Merge branch 'develop' of https://github.com/bluekitchen/btstack into develop

This commit is contained in:
Matthias Ringwald 2017-02-03 13:53:47 +01:00
commit ca19fe361e
15 changed files with 321 additions and 30 deletions

View File

@ -73,6 +73,8 @@ ENABLE_LOG_DEBUG | Enable log_debug messages
ENABLE_LOG_ERROR | Enable log_error messages
ENABLE_LOG_INFO | Enable log_info messages
ENABLE_SCO_OVER_HCI | Enable SCO over HCI for chipsets (only CC256x/WL18xx and USB CSR controllers)
ENBALE_LE_PERIPHERAL | Enable support for LE Peripheral Role in HCI and Security Manager
ENBALE_LE_CENTRAL | Enable support for LE Central Role in HCI and Security Manager
ENABLE_LE_SECURE_CONNECTIONS | Enable LE Secure Connections using [mbed TLS library](https://tls.mbed.org)
ENABLE_LE_DATA_CHANNELS | Enable LE Data Channels in credit-based flow control mode
ENABLE_LE_SIGNED_WRITE | Enable LE Signed Writes in ATT/GATT
@ -193,10 +195,11 @@ BTstack provides different run loop implementations that implement the *btstack_
- Embedded: the main implementation for embedded systems, especially without an RTOS.
- POSIX: implementation for POSIX systems based on the select() call.
- CoreFoundation: implementation for iOS and OS X applications
- WICED: implementation for the Broadcom WICED SDK RTOS abstraction that warps FreeRTOS or ThreadX.
- WICED: implementation for the Broadcom WICED SDK RTOS abstraction that wraps FreeRTOS or ThreadX.
- Windows: implementation for Windows based on Event objects and WaitForMultipleObjects() call.
Depending on the platform, data sources are either polled (embedded), or the platform provides a way
to wait for a data source to become ready for read or write (POSIX, CoreFoundation), or,
to wait for a data source to become ready for read or write (POSIX, CoreFoundation, Windows), or,
are not used as the HCI transport driver and the run loop is implemented in a different way (WICED).
In any case, the callbacks must be to explicitly enabled with the *btstack_run_loop_enable_data_source_callbacks(..)* function.
@ -254,8 +257,13 @@ It supports ready to read and write similar to the POSIX implementation. The cal
To enable the use of timers, make sure that you defined HAVE_POSIX_TIME in the config file.
### Run loop WICED
### Run loop Windows
The data sources are Event objects. In the run loop implementation WaitForMultipleObjects() call
is all is used to wait for the Event object to become ready while waiting for the next timeout.
### Run loop WICED
WICED SDK API does not provide asynchronous read and write to the UART and no direct way to wait for
one or more peripherals to become ready. Therefore, BTstack does not provide direct support for data sources.

View File

@ -30,16 +30,20 @@ system.
Currently, we have two examples for this:
- *btstack_run_loop_posix.c* is an implementation for POSIX compliant
systems. The data sources are modeled as file descriptors and
managed in a linked list. Then, the *select* function is used to wait
for the next file descriptor to become ready or timer to expire.
- *btstack_run_loop_cocoa.c* is an implementation for the CoreFoundation
Framework used in OS X and iOS. All run loop functions are
implemented in terms of CoreFoundation calls, data sources and
timers are modeled as CFSockets and CFRunLoopTimer respectively.
- *btstack_run_loop_posix.c* is an implementation for POSIX compliant
systems. The data sources are modeled as file descriptors and
managed in a linked list. Then, the*select* function is used to wait
for the next file descriptor to become ready or timer to expire.
- *btstack_run_loop_windows* is an implementation for Windows environment.
The data sources are modeled with Event objects and managed in a linked list.
Then, the *WaitForMultipleObjects* is used to wait for the next Event to
becomre ready or timer to expire.
## Adapting BTstack for Multi-Threaded Environments {#sec:multithreadingIntegration}

View File

@ -10,9 +10,9 @@ On Windows, there is no packet manager, but it's easy to download and install al
- [Python](http://www.python.org/getit/) for Windows. When using the official installer, please confirm adding Python to the Windows Path.
- [MSYS2](https://msys2.github.io) is used to provide the bash shell and most standard POSIX command line tools.
- [MinGW64](https://mingw-w64.org/doku.php) GCC for Windows 64 & 32 bits incl. make. To install with MYS2: pacman -S mingw-w64-x86_64-gcc
- [git](https://git-scm.com) is used to download BTstack source code. To install with MYS2: pacman -S git
- [winpty](https://github.com/rprichard/winpty) a wrapper to allow for console input when running in msys2: To install with MYS2: pacman -S winpty
- [MinGW64](https://mingw-w64.org/doku.php) GCC for Windows 64 & 32 bits incl. make. To install with MSYS2: pacman -S mingw-w64-x86_64-gcc
- [git](https://git-scm.com) is used to download BTstack source code. To install with MSYS2: pacman -S git
- [winpty](https://github.com/rprichard/winpty) a wrapper to allow for console input when running in MSYS2: To install with MSYS2: pacman -S winpty
## Getting BTstack from GitHub
@ -68,7 +68,7 @@ Bluetooth. For this, execute:
## Windows-WinUSB
While libusb basically also works on Windows, we recommend to use the Windows-WinUSB port that uses a native run loop and the native WinUSB API to access the USB Bluetooth dongle.
Although libusb basically works with the POSIX Run Loop on Windows, we recommend to use the Windows-WinUSB port that uses a native run loop and the native WinUSB API to access a USB Bluetooth dongle.
For libusb or WinUSB, you need to install a special device driver to make the USB dongle accessible to user space. It works like this:
@ -78,8 +78,7 @@ For libusb or WinUSB, you need to install a special device driver to make the US
- Select WinUSB (libusb) in the right pull pull down list
- Select “Replace Driver”
When running the examples in the MSYS2, the console input (via btstack_stdin_support) doesn't work. It works in the older MSYS and also the regular
CMD.exe environment. Another option is to install WinPTY and then start the example via WinPTY like this:
When running the examples in the MSYS2 shell, the console input (via btstack_stdin_support) doesn't work. It works in the older MSYS and also the regular CMD.exe environment. Another option is to install WinPTY and then start the example via WinPTY like this:
$ winpty ./hfp_hf_demo.exe

View File

@ -96,6 +96,7 @@ EXAMPLES = \
gatt_browser \
le_counter \
le_streamer \
le_streamer_client \
led_counter \
sdp_bnep_query \
sdp_general_query \
@ -117,6 +118,7 @@ EXAMPLES_USING_LE = \
gatt_browser \
le_counter \
le_streamer \
le_streamer_client \
spp_and_le_counter \
gap_le_advertisements \
sm_pairing_peripheral \
@ -176,6 +178,9 @@ sm_pairing_central: ${CORE_OBJ} ${COMMON_OBJ} ${SM_OBJ} ad_parser.o sm_pairing_c
le_streamer: le_streamer.h ${CORE_OBJ} ${COMMON_OBJ} ${ATT_OBJ} ${GATT_SERVER_OBJ} ${SM_OBJ} le_streamer.c
${CC} $(filter-out le_streamer.h,$^) ${CFLAGS} ${LDFLAGS} -o $@
le_streamer_client: ${CORE_OBJ} ${COMMON_OBJ} ${ATT_OBJ} ${GATT_CLIENT_OBJ} ${SM_OBJ} le_streamer_client.c
${CC} $^ ${CFLAGS} ${LDFLAGS} -o $@
spp_and_le_counter: spp_and_le_counter.h ${CORE_OBJ} ${COMMON_OBJ} ${CLASSIC_OBJ} ${ATT_OBJ} ${GATT_SERVER_OBJ} ${SM_OBJ} spp_and_le_counter.c
${CC} $(filter-out spp_and_le_counter.h,$^) ${CFLAGS} ${LDFLAGS} -o $@

View File

@ -0,0 +1,283 @@
/*
* Copyright (C) 2014 BlueKitchen GmbH
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holders nor the names of
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
* 4. Any redistribution, use, or modification is done solely for
* personal benefit and not for any commercial purpose or for
* monetary gain.
*
* THIS SOFTWARE IS PROVIDED BY BLUEKITCHEN GMBH AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MATTHIAS
* RINGWALD OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
* THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* Please inquire about commercial licensing options at
* contact@bluekitchen-gmbh.com
*
*/
// *****************************************************************************
//
// LE Streamer Client - connects to 'LE Streamer' and subscribes to test characteristic
//
// *****************************************************************************
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "btstack.h"
typedef enum {
TC_IDLE,
TC_W4_SCAN_RESULT,
TC_W4_CONNECT,
TC_W4_SERVICE_RESULT,
TC_W4_CHARACTERISTIC_RESULT,
TC_W4_TEST_DATA
} gc_state_t;
static bd_addr_t cmdline_addr = { };
static int cmdline_addr_found = 0;
// addr and type of device with correct name
static bd_addr_t le_streamer_addr;
static bd_addr_type_t le_streamer_addr_type;
static hci_con_handle_t connection_handle;
static uint8_t le_streamer_service_uuid[16] = { 0x00, 0x00, 0xFF, 0x10, 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0x80, 0x5F, 0x9B, 0x34, 0xFB};
static uint8_t le_streamer_characteristic_uuid[16] = { 0x00, 0x00, 0xFF, 0x11, 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0x80, 0x5F, 0x9B, 0x34, 0xFB};
static gatt_client_service_t le_streamer_service;
static gatt_client_characteristic_t le_streamer_characteristic;
static gatt_client_notification_t notification_registration;
static gc_state_t state = TC_IDLE;
static btstack_packet_callback_registration_t hci_event_callback_registration;
// returns 1 if name is found in advertisement
static int advertisement_report_contains_name(const char * name, uint8_t * advertisement_report){
// get advertisement from report event
const uint8_t * adv_data = gap_event_advertising_report_get_data(advertisement_report);
uint16_t adv_len = gap_event_advertising_report_get_data_length(advertisement_report);
int name_len = strlen(name);
// iterate over advertisement data
ad_context_t context;
for (ad_iterator_init(&context, adv_len, adv_data) ; ad_iterator_has_more(&context) ; ad_iterator_next(&context)){
uint8_t data_type = ad_iterator_get_data_type(&context);
uint8_t data_size = ad_iterator_get_data_len(&context);
const uint8_t * data = ad_iterator_get_data(&context);
int i;
switch (data_type){
case BLUETOOTH_DATA_TYPE_SHORTENED_LOCAL_NAME:
case BLUETOOTH_DATA_TYPE_COMPLETE_LOCAL_NAME:
// compare common prefix
for (i=0; i<data_size && i<name_len;i++){
if (data[i] != name[i]) break;
}
// prefix match
return 1;
default:
break;
}
}
return 0;
}
static void handle_gatt_client_event(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){
UNUSED(packet_type);
UNUSED(channel);
UNUSED(size);
switch(state){
case TC_W4_SERVICE_RESULT:
switch(hci_event_packet_get_type(packet)){
case GATT_EVENT_SERVICE_QUERY_RESULT:
// store service (we expect only one)
gatt_event_service_query_result_get_service(packet, &le_streamer_service);
break;
case GATT_EVENT_QUERY_COMPLETE:
if (packet[4] != 0){
printf("SERVICE_QUERY_RESULT - Error status %x.\n", packet[4]);
gap_disconnect(connection_handle);
break;
}
// service query complete, look for characteristic
state = TC_W4_CHARACTERISTIC_RESULT;
printf("Search for LE Streamer test characteristic.\n");
gatt_client_discover_characteristics_for_service_by_uuid128(handle_gatt_client_event, connection_handle, &le_streamer_service, le_streamer_characteristic_uuid);
break;
default:
break;
}
break;
case TC_W4_CHARACTERISTIC_RESULT:
switch(hci_event_packet_get_type(packet)){
case GATT_EVENT_CHARACTERISTIC_QUERY_RESULT:
gatt_event_characteristic_query_result_get_characteristic(packet, &le_streamer_characteristic);
break;
case GATT_EVENT_QUERY_COMPLETE:
if (packet[4] != 0){
printf("CHARACTERISTIC_QUERY_RESULT - Error status %x.\n", packet[4]);
gap_disconnect(connection_handle);
break;
}
// register handler for notifications
gatt_client_listen_for_characteristic_value_updates(&notification_registration, handle_gatt_client_event, connection_handle, &le_streamer_characteristic);
// enable notifications
state = TC_W4_TEST_DATA;
printf("Start streaming - enable notify on test characteristic.\n");
gatt_client_write_client_characteristic_configuration(handle_gatt_client_event, connection_handle, &le_streamer_characteristic, GATT_CLIENT_CHARACTERISTICS_CONFIGURATION_NOTIFICATION);
break;
default:
break;
}
break;
case TC_W4_TEST_DATA:
switch(hci_event_packet_get_type(packet)){
case GATT_EVENT_NOTIFICATION:
printf("Data: ");
printf_hexdump( gatt_event_notification_get_value(packet), gatt_event_notification_get_value_length(packet));
case GATT_EVENT_QUERY_COMPLETE:
break;
default:
printf("Unknown packet type %x\n", hci_event_packet_get_type(packet));
break;
}
break;
default:
printf("error\n");
break;
}
}
static void hci_event_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){
UNUSED(channel);
UNUSED(size);
if (packet_type != HCI_EVENT_PACKET) return;
uint8_t event = hci_event_packet_get_type(packet);
switch (event) {
case BTSTACK_EVENT_STATE:
// BTstack activated, get started
if (btstack_event_state_get_state(packet) != HCI_STATE_WORKING) break;
if (cmdline_addr_found){
printf("Connect to %s\n", bd_addr_to_str(cmdline_addr));
state = TC_W4_CONNECT;
gap_connect(cmdline_addr, 0);
break;
}
printf("Start scanning!\n");
state = TC_W4_SCAN_RESULT;
gap_set_scan_parameters(0,0x0030, 0x0030);
gap_start_scan();
break;
case GAP_EVENT_ADVERTISING_REPORT:
if (state != TC_W4_SCAN_RESULT) return;
// check name in advertisement
if (!advertisement_report_contains_name("LE Streamer", packet)) return;
// store address and type
gap_event_advertising_report_get_address(packet, le_streamer_addr);
le_streamer_addr_type = gap_event_advertising_report_get_address_type(packet);
// stop scanning, and connect to the device
state = TC_W4_CONNECT;
gap_stop_scan();
printf("Stop scan. Connect to device with addr %s.\n", bd_addr_to_str(le_streamer_addr));
gap_connect(le_streamer_addr,le_streamer_addr_type);
break;
case HCI_EVENT_LE_META:
// wait for connection complete
if (hci_event_le_meta_get_subevent_code(packet) != HCI_SUBEVENT_LE_CONNECTION_COMPLETE) break;
if (state != TC_W4_CONNECT) return;
connection_handle = hci_subevent_le_connection_complete_get_connection_handle(packet);
// initialize gatt client context with handle, and add it to the list of active clients
// query primary services
printf("Search for LE Streamer service.\n");
state = TC_W4_SERVICE_RESULT;
gatt_client_discover_primary_services_by_uuid128(handle_gatt_client_event, connection_handle, le_streamer_service_uuid);
break;
case HCI_EVENT_DISCONNECTION_COMPLETE:
if (cmdline_addr_found){
printf("Disconnected %s\n", bd_addr_to_str(cmdline_addr));
return;
}
printf("Disconnected %s\n", bd_addr_to_str(le_streamer_addr));
break;
default:
break;
}
}
#ifdef HAVE_POSIX_STDIN
static void usage(const char *name){
fprintf(stderr, "Usage: %s [-a|--address aa:bb:cc:dd:ee:ff]\n", name);
fprintf(stderr, "If no argument is provided, LE Streamer Client will start scanning and connect to the first device named 'LE Streamer'.\n");
fprintf(stderr, "To connect to a specific device use argument [-a].\n\n");
}
#endif
int btstack_main(int argc, const char * argv[]);
int btstack_main(int argc, const char * argv[]){
#ifdef HAVE_POSIX_STDIN
int arg = 1;
cmdline_addr_found = 0;
while (arg < argc) {
if(!strcmp(argv[arg], "-a") || !strcmp(argv[arg], "--address")){
arg++;
cmdline_addr_found = sscanf_bd_addr(argv[arg], cmdline_addr);
arg++;
if (!cmdline_addr_found) exit(1);
continue;
}
usage(argv[0]);
return 0;
}
#else
UNUSED(argc);
UNUSED(argv);
#endif
hci_event_callback_registration.callback = &hci_event_handler;
hci_add_event_handler(&hci_event_callback_registration);
l2cap_init();
gatt_client_init();
sm_init();
sm_set_io_capabilities(IO_CAPABILITY_NO_INPUT_NO_OUTPUT);
// turn on!
hci_power_control(HCI_POWER_ON);
return 0;
}

View File

@ -19,7 +19,6 @@
#define HCI_ACL_PAYLOAD_SIZE 200
#define MAX_NR_BNEP_SERVICES 0
#define MAX_NR_BNEP_CHANNELS 0
#define MAX_NR_GATT_SUBCLIENTS 2
#define MAX_NR_HCI_CONNECTIONS 1
#define MAX_NR_L2CAP_SERVICES 0
#define MAX_NR_L2CAP_CHANNELS 0

View File

@ -21,8 +21,7 @@
#define HCI_ACL_PAYLOAD_SIZE 52
#define MAX_SPP_CONNECTIONS 1
#define MAX_NR_HCI_CONNECTIONS MAX_SPP_CONNECTIONS
#define MAX_NR_GATT_CLIENTS 0
#define MAX_NR_GATT_SUBCLIENTS 0
#define MAX_NR_GATT_CLIENTS 1
#define MAX_NR_L2CAP_SERVICES 2
#define MAX_NR_L2CAP_CHANNELS (1+MAX_SPP_CONNECTIONS)
#define MAX_NR_RFCOMM_MULTIPLEXERS MAX_SPP_CONNECTIONS

View File

@ -22,8 +22,7 @@
#define MAX_NR_BNEP_CHANNELS MAX_SPP_CONNECTIONS
#define MAX_NR_BNEP_SERVICES 1
#define MAX_NR_BTSTACK_LINK_KEY_DB_MEMORY_ENTRIES 2
#define MAX_NR_GATT_CLIENTS 0
#define MAX_NR_GATT_SUBCLIENTS 0
#define MAX_NR_GATT_CLIENTS 1
#define MAX_NR_HCI_CONNECTIONS MAX_SPP_CONNECTIONS
#define MAX_NR_HFP_CONNECTIONS 0
#define MAX_NR_L2CAP_CHANNELS (1+MAX_SPP_CONNECTIONS)

View File

@ -21,8 +21,7 @@
#define HCI_ACL_PAYLOAD_SIZE 52
#define MAX_SPP_CONNECTIONS 1
#define MAX_NR_HCI_CONNECTIONS MAX_SPP_CONNECTIONS
#define MAX_NR_GATT_CLIENTS 0
#define MAX_NR_GATT_SUBCLIENTS 0
#define MAX_NR_GATT_CLIENTS 1
#define MAX_NR_HFP_CONNECTIONS 0
#define MAX_NR_L2CAP_SERVICES 2
#define MAX_NR_L2CAP_CHANNELS (1+MAX_SPP_CONNECTIONS)

View File

@ -22,7 +22,6 @@
#define MAX_NR_L2CAP_SERVICES 1
#define MAX_NR_L2CAP_CHANNELS 1
#define MAX_NR_GATT_CLIENTS 1
#define MAX_NR_GATT_SUBCLIENTS 1
#define MAX_NR_RFCOMM_MULTIPLEXERS 0
#define MAX_NR_RFCOMM_SERVICES 0

View File

@ -19,8 +19,7 @@
// BTstack configuration. buffers, sizes, ...
#define HCI_ACL_PAYLOAD_SIZE 52
#define MAX_SPP_CONNECTIONS 1
#define MAX_NR_GATT_CLIENTS 0
#define MAX_NR_GATT_SUBCLIENTS 0
#define MAX_NR_GATT_CLIENTS 1
#define MAX_NR_HCI_CONNECTIONS MAX_SPP_CONNECTIONS
#define MAX_NR_L2CAP_SERVICES 2
#define MAX_NR_L2CAP_CHANNELS (1+MAX_SPP_CONNECTIONS)

View File

@ -20,8 +20,7 @@
// BTstack configuration. buffers, sizes, ...
#define HCI_ACL_PAYLOAD_SIZE 52
#define MAX_SPP_CONNECTIONS 1
#define MAX_NR_GATT_CLIENTS 0
#define MAX_NR_GATT_SUBCLIENTS 0
#define MAX_NR_GATT_CLIENTS 1
#define MAX_NR_HCI_CONNECTIONS MAX_SPP_CONNECTIONS
#define MAX_NR_L2CAP_SERVICES 2
#define MAX_NR_L2CAP_CHANNELS (1+MAX_SPP_CONNECTIONS)

View File

@ -20,8 +20,7 @@
// BTstack configuration. buffers, sizes, ...
#define HCI_ACL_PAYLOAD_SIZE 52
#define MAX_SPP_CONNECTIONS 1
#define MAX_NR_GATT_CLIENTS 0
#define MAX_NR_GATT_SUBCLIENTS 0
#define MAX_NR_GATT_CLIENTS 1
#define MAX_NR_HCI_CONNECTIONS MAX_SPP_CONNECTIONS
#define MAX_NR_L2CAP_SERVICES 2
#define MAX_NR_L2CAP_CHANNELS (1+MAX_SPP_CONNECTIONS)

View File

@ -21,8 +21,7 @@
// BTstack configuration. buffers, sizes, ...
#define HCI_ACL_PAYLOAD_SIZE 52
#define MAX_SPP_CONNECTIONS 1
#define MAX_NR_GATT_CLIENTS 0
#define MAX_NR_GATT_SUBCLIENTS 0
#define MAX_NR_GATT_CLIENTS 1
#define MAX_NR_HCI_CONNECTIONS MAX_SPP_CONNECTIONS
#define MAX_NR_L2CAP_SERVICES 2
#define MAX_NR_L2CAP_CHANNELS (1+MAX_SPP_CONNECTIONS)

View File

@ -16,6 +16,7 @@ $(NAME)_SOURCES += \
../../src/ble/att_db.c \
../../src/ble/att_dispatch.c \
../../src/ble/att_server.c \
../../src/ble/gatt_client.c \
../../src/ble/le_device_db_memory.c \
../../src/ble/gatt-service/battery_service_server.c \
../../src/ble/sm.c \