From 533c0e8283019d7d71ae2690a956c9bc1110d90c Mon Sep 17 00:00:00 2001 From: "mila@ringwald.ch" Date: Wed, 10 Sep 2014 21:03:38 +0000 Subject: [PATCH] split ancs_client in main app and lib, use pkg-config for libusb --- example/libusb/Makefile | 26 +- example/libusb/ancs_client.c | 269 ++------------- example/libusb/ancs_client_lib.c | 326 ++++++++++++++++++ example/libusb/ancs_client_lib.h | 59 ++++ include/btstack/hci_cmds.h | 4 + platforms/posix/src/hci_transport_h2_libusb.c | 2 +- 6 files changed, 437 insertions(+), 249 deletions(-) create mode 100644 example/libusb/ancs_client_lib.c create mode 100644 example/libusb/ancs_client_lib.h diff --git a/example/libusb/Makefile b/example/libusb/Makefile index bf9063771..458853d98 100644 --- a/example/libusb/Makefile +++ b/example/libusb/Makefile @@ -1,13 +1,18 @@ BTSTACK_ROOT = ../.. POSIX_ROOT= ${BTSTACK_ROOT}/platforms/posix -CFLAGS = -g -Wall -I. -I${BTSTACK_ROOT}/src -I${BTSTACK_ROOT}/include +CFLAGS = -g -Wall -I. +CFLAGS += -I${BTSTACK_ROOT}/ble CFLAGS += -I${BTSTACK_ROOT}/chipset-cc256x CFLAGS += -I${BTSTACK_ROOT}/chipset-csr -CFLAGS += -I/usr/local/include -I../../ble -I../.. -I../.. -LDFLAGS = -L/usr/local/lib -lusb-1.0 +CFLAGS += -I${BTSTACK_ROOT}/include +CFLAGS += -I${BTSTACK_ROOT}/src +CFLAGS += -I${BTSTACK_ROOT} + +CFLAGS += $(shell pkg-config libusb-1.0 --cflags) +LDFLAGS += $(shell pkg-config libusb-1.0 --libs) # needed on OS X with libusb compiled stand alone -LDFLAGS += -framework IOKit -framework CoreFoundation -framework Foundation +# LDFLAGS += -framework IOKit -framework CoreFoundation -framework Foundation CORE = \ ${BTSTACK_ROOT}/src/btstack_memory.c \ @@ -63,7 +68,7 @@ SDP_DES = \ ${BTSTACK_ROOT}/test/des_iterator/des_iterator.c \ CORE_OBJ = $(CORE:.c=.o) -COMMON_OBJ = $(COMMON:.c=.o) +COMMON_OBJ = $(COMMON:.c=.o) CC2564_OBJ = $(CC2564:.c=.o) CSR_OBJ = $(CSR:.c=.o) SM_REAL_OBJ = $(SM_REAL:.c=.o) @@ -74,13 +79,13 @@ GATT_SERVER_OBJ = $(GATT_SERVER:.c=.o) # create firmware image from common objects and example source file -all: ../../include/btstack/version.h gatt_browser sdp_rfcomm_query sdp_general_query spp_counter ble_peripheral \ +all: ${BTSTACK_ROOT}/include/btstack/version.h gatt_browser sdp_rfcomm_query sdp_general_query spp_counter ble_peripheral \ ble_peripheral_sm_minimal gap_inquiry gap_dedicated_bonding gap_inquiry_and_bond l2cap_test spp_streamer \ classic_test ble_peripheral_uart_csr ble_peripheral_uart_cc256x ancs_client spp_and_le_counter \ sdp_bnep_query \ -../../include/btstack/version.h: - ../tools/get_version.sh +${BTSTACK_ROOT}/include/btstack/version.h: + ${BTSTACK_ROOT}/tools/get_version.sh sdp_rfcomm_query: ${CORE_OBJ} ${COMMON_OBJ} sdp_rfcomm_query.c ${CC} $^ ${CFLAGS} ${LDFLAGS} -o $@ @@ -126,8 +131,8 @@ ancs_client.h: ancs_client.gatt spp_and_le_counter.h: spp_and_le_counter.gatt python ${BTSTACK_ROOT}/ble/compile-gatt.py $< $@ -ancs_client: ${CORE_OBJ} ${COMMON_OBJ} ${ATT_OBJ} ${GATT_SERVER_OBJ} ${GATT_CLIENT_OBJ} ${SM_REAL_OBJ} ancs_client.c ancs_client.h - ${CC} ${CORE_OBJ} ${COMMON_OBJ} ${ATT_OBJ} ${GATT_SERVER_OBJ} ${GATT_CLIENT_OBJ} ${SM_REAL_OBJ} ancs_client.c ${CFLAGS} ${LDFLAGS} -o $@ +ancs_client: ${CORE_OBJ} ${COMMON_OBJ} ${ATT_OBJ} ${GATT_SERVER_OBJ} ${GATT_CLIENT_OBJ} ${SM_REAL_OBJ} ancs_client_lib.c ancs_client.c ancs_client.h + ${CC} ${CORE_OBJ} ${COMMON_OBJ} ${ATT_OBJ} ${GATT_SERVER_OBJ} ${GATT_CLIENT_OBJ} ${SM_REAL_OBJ} ancs_client.c ancs_client_lib.c ${CFLAGS} ${LDFLAGS} -o $@ ble_peripheral: ${CORE_OBJ} ${COMMON_OBJ} ${ATT_OBJ} ${GATT_SERVER_OBJ} ${SM_REAL_OBJ} ble_peripheral.c profile.h ${CC} ${CORE_OBJ} ${COMMON_OBJ} ${ATT_OBJ} ${GATT_SERVER_OBJ} ${SM_REAL_OBJ} ble_peripheral.c ${CFLAGS} ${LDFLAGS} -o $@ @@ -155,6 +160,7 @@ clean: rm -f ${BTSTACK_ROOT}/src/*.o rm -f ${BTSTACK_ROOT}/ble/*.o rm -f ${BTSTACK_ROOT}/chipset-cc256x/*.o + rm -f ${BTSTACK_ROOT}/platforms/posix/src/*.o rm -f ${BTSTACK_ROOT}/include/btstack/version.h rm -f ${BTSTACK_ROOT}/example/libusb/ancs_client.h rm -f ${BTSTACK_ROOT}/example/libusb/profile.h diff --git a/example/libusb/ancs_client.c b/example/libusb/ancs_client.c index 2d0028246..a94238200 100644 --- a/example/libusb/ancs_client.c +++ b/example/libusb/ancs_client.c @@ -66,6 +66,7 @@ #include "gap_le.h" #include "gatt_client.h" #include "sm.h" +#include "ancs_client_lib.h" // ancs client profile #include "ancs_client.h" @@ -80,24 +81,6 @@ static hci_uart_config_t hci_uart_config_csr8811 = { }; #endif - -typedef enum ancs_chunk_parser_state { - W4_ATTRIBUTE_ID, - W4_ATTRIBUTE_LEN, - W4_ATTRIBUTE_COMPLETE, -} ancs_chunk_parser_state_t; - -typedef enum { - TC_IDLE, - TC_W4_ENCRYPTED_CONNECTION, - TC_W4_SERVICE_RESULT, - TC_W4_CHARACTERISTIC_RESULT, - TC_W4_DATA_SOURCE_SUBSCRIBED, - TC_W4_NOTIFICATION_SOURCE_SUBSCRIBED, - TC_SUBSCRIBED, - TC_W4_DISCONNECT -} tc_state_t; - typedef enum { SET_ADVERTISEMENT_PARAMS = 1 << 0, SET_ADVERTISEMENT_DATA = 1 << 1, @@ -114,190 +97,7 @@ const uint8_t adv_data[] = { }; uint8_t adv_data_len = sizeof(adv_data); -const char * ancs_attribute_names[] = { - "AppIdentifier", - "IDTitle", - "IDSubtitle", - "IDMessage", - "IDMessageSize", - "IDDate" -}; - -const uint8_t ancs_service_uuid[] = {0x79,0x05,0xF4,0x31,0xB5,0xCE,0x4E,0x99,0xA4,0x0F,0x4B,0x1E,0x12,0x2D,0x00,0xD0}; -const uint8_t ancs_notification_source_uuid[] = {0x9F,0xBF,0x12,0x0D,0x63,0x01,0x42,0xD9,0x8C,0x58,0x25,0xE6,0x99,0xA2,0x1D,0xBD}; -const uint8_t ancs_control_point_uuid[] = {0x69,0xD1,0xD8,0xF3,0x45,0xE1,0x49,0xA8,0x98,0x21,0x9B,0xBD,0xFD,0xAA,0xD9,0xD9}; -const uint8_t ancs_data_source_uuid[] = {0x22,0xEA,0xC6,0xE9,0x24,0xD6,0x4B,0xB5,0xBE,0x44,0xB3,0x6A,0xCE,0x7C,0x7B,0xFB}; - static todo_t todos = 0; -static uint32_t ancs_notification_uid; -static uint16_t handle; -static gatt_client_t ancs_client_context; -static int ancs_service_found; -static le_service_t ancs_service; -static le_characteristic_t ancs_notification_source_characteristic; -static le_characteristic_t ancs_control_point_characteristic; -static le_characteristic_t ancs_data_source_characteristic; -static int ancs_characteristcs; -static tc_state_t tc_state = TC_IDLE; - -static ancs_chunk_parser_state_t chunk_parser_state; -static uint8_t ancs_notification_buffer[50]; -static uint16_t ancs_bytes_received; -static uint16_t ancs_bytes_needed; -static uint8_t ancs_attribute_id; -static uint16_t ancs_attribute_len; - -static void app_run(); - -void print_attribute(){ - ancs_notification_buffer[ancs_bytes_received] = 0; - printf("%14s: %s\n", ancs_attribute_names[ancs_attribute_id], ancs_notification_buffer); -} - -void ancs_chunk_parser_init(){ - chunk_parser_state = W4_ATTRIBUTE_ID; - ancs_bytes_received = 0; - ancs_bytes_needed = 6; -} - -void ancs_chunk_parser_handle_byte(uint8_t data){ - ancs_notification_buffer[ancs_bytes_received++] = data; - if (ancs_bytes_received < ancs_bytes_needed) return; - switch (chunk_parser_state){ - case W4_ATTRIBUTE_ID: - ancs_attribute_id = ancs_notification_buffer[ancs_bytes_received-1]; - ancs_bytes_received = 0; - ancs_bytes_needed = 2; - chunk_parser_state = W4_ATTRIBUTE_LEN; - break; - case W4_ATTRIBUTE_LEN: - ancs_attribute_len = READ_BT_16(ancs_notification_buffer, ancs_bytes_received-2); - ancs_bytes_received = 0; - ancs_bytes_needed = ancs_attribute_len; - if (ancs_attribute_len == 0) { - ancs_bytes_needed = 1; - chunk_parser_state = W4_ATTRIBUTE_ID; - break; - } - chunk_parser_state = W4_ATTRIBUTE_COMPLETE; - break; - case W4_ATTRIBUTE_COMPLETE: - print_attribute(); - ancs_bytes_received = 0; - ancs_bytes_needed = 1; - chunk_parser_state = W4_ATTRIBUTE_ID; - break; - } -} - -void handle_gatt_client_event(le_event_t * event){ - le_characteristic_t characteristic; - le_characteristic_value_event_t * value_event; - switch(tc_state){ - case TC_W4_SERVICE_RESULT: - switch(event->type){ - case GATT_SERVICE_QUERY_RESULT: - ancs_service = ((le_service_event_t *) event)->service; - ancs_service_found = 1; - break; - case GATT_QUERY_COMPLETE: - if (!ancs_service_found){ - printf("ANCS Service not found"); - tc_state = TC_IDLE; - break; - } - tc_state = TC_W4_CHARACTERISTIC_RESULT; - printf("ANCS Client - Discover characteristics for ANCS SERVICE \n"); - gatt_client_discover_characteristics_for_service(&ancs_client_context, &ancs_service); - break; - default: - break; - } - break; - - case TC_W4_CHARACTERISTIC_RESULT: - switch(event->type){ - case GATT_CHARACTERISTIC_QUERY_RESULT: - characteristic = ((le_characteristic_event_t *) event)->characteristic; - if (memcmp(characteristic.uuid128, ancs_notification_source_uuid, 16) == 0){ - printf("ANCS Notification Source Characterisic found\n"); - ancs_notification_source_characteristic = characteristic; - ancs_characteristcs++; - break; - } - if (memcmp(characteristic.uuid128, ancs_control_point_uuid, 16) == 0){ - printf("ANCS Control Point found\n"); - ancs_control_point_characteristic = characteristic; - ancs_characteristcs++; - break; - } - if (memcmp(characteristic.uuid128, ancs_data_source_uuid, 16) == 0){ - printf("ANCS Data Source Characterisic found\n"); - ancs_data_source_characteristic = characteristic; - ancs_characteristcs++; - break; - } - break; - case GATT_QUERY_COMPLETE: - printf("ANCS Characteristcs count %u\n", ancs_characteristcs); - tc_state = TC_W4_NOTIFICATION_SOURCE_SUBSCRIBED; - gatt_client_write_client_characteristic_configuration(&ancs_client_context, &ancs_notification_source_characteristic, - GATT_CLIENT_CHARACTERISTICS_CONFIGURATION_NOTIFICATION); - break; - default: - break; - } - break; - case TC_W4_NOTIFICATION_SOURCE_SUBSCRIBED: - switch(event->type){ - case GATT_QUERY_COMPLETE: - printf("ANCS Notification Source subscribed\n"); - tc_state = TC_W4_DATA_SOURCE_SUBSCRIBED; - gatt_client_write_client_characteristic_configuration(&ancs_client_context, &ancs_data_source_characteristic, - GATT_CLIENT_CHARACTERISTICS_CONFIGURATION_NOTIFICATION); - break; - default: - break; - } - break; - case TC_W4_DATA_SOURCE_SUBSCRIBED: - switch(event->type){ - case GATT_QUERY_COMPLETE: - printf("ANCS Data Source subscribed\n"); - tc_state = TC_SUBSCRIBED; - break; - default: - break; - } - break; - case TC_SUBSCRIBED: - if ( event->type != GATT_NOTIFICATION && event->type != GATT_INDICATION ) break; - value_event = (le_characteristic_value_event_t *) event; - if (value_event->value_handle == ancs_data_source_characteristic.value_handle){ - int i; - for (i=0;iblob_length;i++) { - ancs_chunk_parser_handle_byte(value_event->blob[i]); - } - } else if (value_event->value_handle == ancs_notification_source_characteristic.value_handle){ - ancs_notification_uid = READ_BT_32(value_event->blob, 4); - printf("Notification received: EventID %02x, EventFlags %02x, CategoryID %02x, CategoryCount %u, UID %04x\n", - value_event->blob[0], value_event->blob[1], value_event->blob[2], value_event->blob[3], ancs_notification_uid); - static uint8_t get_notification_attributes[] = {0, 0,0,0,0, 0, 1,32,0, 2,32,0, 3,32,0, 4, 5}; - bt_store_32(get_notification_attributes, 1, ancs_notification_uid); - ancs_notification_uid = 0; - ancs_chunk_parser_init(); - gatt_client_write_value_of_characteristic(&ancs_client_context, ancs_control_point_characteristic.value_handle, - sizeof(get_notification_attributes), get_notification_attributes); - } else { - printf("Unknown Source: "); - printf_hexdump(value_event->blob , value_event->blob_length); - } - break; - default: - break; - } - app_run(); -} static void app_run(){ @@ -330,7 +130,9 @@ static void app_run(){ } static void app_packet_handler (uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){ - int connection_encrypted; + + ancs_client_hci_event_handler(packet_type, channel, packet, size); + switch (packet_type) { case HCI_EVENT_PACKET: @@ -345,45 +147,13 @@ static void app_packet_handler (uint8_t packet_type, uint16_t channel, uint8_t * } break; - case HCI_EVENT_LE_META: - switch (packet[2]) { - case HCI_SUBEVENT_LE_CONNECTION_COMPLETE: - handle = READ_BT_16(packet, 4); - printf("Connection handle 0x%04x\n", handle); - - // we need to be paired to enable notifications - tc_state = TC_W4_ENCRYPTED_CONNECTION; - sm_send_security_request(); - break; - - break; - - default: - break; - } - break; - - case HCI_EVENT_ENCRYPTION_CHANGE: - if (handle != READ_BT_16(packet, 3)) break; - connection_encrypted = packet[5]; - log_info("Encryption state change: %u", connection_encrypted); - if (!connection_encrypted) break; - if (tc_state != TC_W4_ENCRYPTED_CONNECTION) break; - - // let's start - printf("\nANCS Client - CONNECTED, discover ANCS service\n"); - tc_state = TC_W4_SERVICE_RESULT; - gatt_client_start(&ancs_client_context, handle); - gatt_client_discover_primary_services_by_uuid128(&ancs_client_context, ancs_service_uuid); - break; - case HCI_EVENT_DISCONNECTION_COMPLETE: todos = ENABLE_ADVERTISEMENTS; break; - case ATT_HANDLE_VALUE_INDICATION_COMPLETE: - printf("ATT_HANDLE_VALUE_INDICATION_COMPLETE status %u\n", packet[2]); - break; + // case ATT_HANDLE_VALUE_INDICATION_COMPLETE: + // printf("ATT_HANDLE_VALUE_INDICATION_COMPLETE status %u\n", packet[2]); + // break; default: break; @@ -392,6 +162,25 @@ static void app_packet_handler (uint8_t packet_type, uint16_t channel, uint8_t * app_run(); } +void ancs_callback(ancs_event_t * event){ + const char * attribute_name; + switch (event->type){ + case ANCS_CLIENT_CONNECTED: + printf("ANCS Client: Connected\n"); + break; + case ANCS_CLIENT_DISCONNECTED: + printf("ANCS Client: Disconnected\n"); + break; + case ANCS_CLIENT_NOTIFICATION: + attribute_name = ancs_client_attribute_name_for_id(event->attribute_id); + if (!attribute_name) break; + printf("Notification: %s - %s\n", attribute_name, event->text); + break; + default: + break; + } +} + void setup(void){ /// GET STARTED with BTstack /// btstack_memory_init(); @@ -430,7 +219,11 @@ void setup(void){ // setup GATT client gatt_client_init(); - gatt_client_register_packet_handler(&handle_gatt_client_event); + + // setup ANCS Client + ancs_client_init(); + ancs_client_register_callback(&ancs_callback); + } int main(void) diff --git a/example/libusb/ancs_client_lib.c b/example/libusb/ancs_client_lib.c new file mode 100644 index 000000000..e9d0a7a39 --- /dev/null +++ b/example/libusb/ancs_client_lib.c @@ -0,0 +1,326 @@ +/* + * Copyright (C) 2011-2013 by Matthias Ringwald + * + * 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. This software may not be used in a commercial product + * without an explicit license granted by the copyright holder. + * + * THIS SOFTWARE IS PROVIDED BY MATTHIAS RINGWALD 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. + * + */ + +#include "btstack-config.h" + +#include +#include +#include +#include + +#include + +#include "ancs_client_lib.h" + +#include "att.h" +#include "debug.h" +#include "gap_le.h" +#include "gatt_client.h" +#include "sm.h" + +// #include "btstack_memory.h" +// #include "hci.h" +// #include "hci_dump.h" +// #include "l2cap.h" +// #include "att_server.h" +// #include "central_device_db.h" + + +// ancs_client.h Start +typedef enum ancs_chunk_parser_state { + W4_ATTRIBUTE_ID, + W4_ATTRIBUTE_LEN, + W4_ATTRIBUTE_COMPLETE, +} ancs_chunk_parser_state_t; + +typedef enum { + TC_IDLE, + TC_W4_ENCRYPTED_CONNECTION, + TC_W4_SERVICE_RESULT, + TC_W4_CHARACTERISTIC_RESULT, + TC_W4_DATA_SOURCE_SUBSCRIBED, + TC_W4_NOTIFICATION_SOURCE_SUBSCRIBED, + TC_SUBSCRIBED, + TC_W4_DISCONNECT +} tc_state_t; + +static const char * ancs_attribute_names[] = { + "AppIdentifier", + "IDTitle", + "IDSubtitle", + "IDMessage", + "IDMessageSize", + "IDDate" +}; +static const int ANCS_ATTRBUTE_NAMES_COUNT = sizeof(ancs_attribute_names) / sizeof(char *); + +static const uint8_t ancs_service_uuid[] = {0x79,0x05,0xF4,0x31,0xB5,0xCE,0x4E,0x99,0xA4,0x0F,0x4B,0x1E,0x12,0x2D,0x00,0xD0}; +static const uint8_t ancs_notification_source_uuid[] = {0x9F,0xBF,0x12,0x0D,0x63,0x01,0x42,0xD9,0x8C,0x58,0x25,0xE6,0x99,0xA2,0x1D,0xBD}; +static const uint8_t ancs_control_point_uuid[] = {0x69,0xD1,0xD8,0xF3,0x45,0xE1,0x49,0xA8,0x98,0x21,0x9B,0xBD,0xFD,0xAA,0xD9,0xD9}; +static const uint8_t ancs_data_source_uuid[] = {0x22,0xEA,0xC6,0xE9,0x24,0xD6,0x4B,0xB5,0xBE,0x44,0xB3,0x6A,0xCE,0x7C,0x7B,0xFB}; + +static uint32_t ancs_notification_uid; +static uint16_t handle; +static gatt_client_t ancs_client_context; +static int ancs_service_found; +static le_service_t ancs_service; +static le_characteristic_t ancs_notification_source_characteristic; +static le_characteristic_t ancs_control_point_characteristic; +static le_characteristic_t ancs_data_source_characteristic; +static int ancs_characteristcs; +static tc_state_t tc_state = TC_IDLE; + +static ancs_chunk_parser_state_t chunk_parser_state; +static char ancs_notification_buffer[50]; +static uint16_t ancs_bytes_received; +static uint16_t ancs_bytes_needed; +static uint8_t ancs_attribute_id; +static uint16_t ancs_attribute_len; +static void (*client_handler)(ancs_event_t * event); + +void ancs_client_register_callback(void (*handler)(ancs_event_t * event)){ + client_handler = handler; +} + +static void notify_client(int event_type){ + if (!client_handler) return; + ancs_event_t event; + event.type = event_type; + event.handle = handle; + event.attribute_id = ancs_attribute_id; + event.text = ancs_notification_buffer; + (*client_handler)(&event); +} + +static void ancs_chunk_parser_init(){ + chunk_parser_state = W4_ATTRIBUTE_ID; + ancs_bytes_received = 0; + ancs_bytes_needed = 6; +} + +const char * ancs_client_attribute_name_for_id(int id){ + if (id >= ANCS_ATTRBUTE_NAMES_COUNT) return 0; + return ancs_attribute_names[id]; +} + +static void ancs_chunk_parser_handle_byte(uint8_t data){ + ancs_notification_buffer[ancs_bytes_received++] = data; + if (ancs_bytes_received < ancs_bytes_needed) return; + switch (chunk_parser_state){ + case W4_ATTRIBUTE_ID: + ancs_attribute_id = ancs_notification_buffer[ancs_bytes_received-1]; + ancs_bytes_received = 0; + ancs_bytes_needed = 2; + chunk_parser_state = W4_ATTRIBUTE_LEN; + break; + case W4_ATTRIBUTE_LEN: + ancs_attribute_len = READ_BT_16(ancs_notification_buffer, ancs_bytes_received-2); + ancs_bytes_received = 0; + ancs_bytes_needed = ancs_attribute_len; + if (ancs_attribute_len == 0) { + ancs_bytes_needed = 1; + chunk_parser_state = W4_ATTRIBUTE_ID; + break; + } + chunk_parser_state = W4_ATTRIBUTE_COMPLETE; + break; + case W4_ATTRIBUTE_COMPLETE: + ancs_notification_buffer[ancs_bytes_received] = 0; + notify_client(ANCS_CLIENT_NOTIFICATION); + ancs_bytes_received = 0; + ancs_bytes_needed = 1; + chunk_parser_state = W4_ATTRIBUTE_ID; + break; + } +} + +static void handle_gatt_client_event(le_event_t * event){ + le_characteristic_t characteristic; + le_characteristic_value_event_t * value_event; + switch(tc_state){ + case TC_W4_SERVICE_RESULT: + switch(event->type){ + case GATT_SERVICE_QUERY_RESULT: + ancs_service = ((le_service_event_t *) event)->service; + ancs_service_found = 1; + break; + case GATT_QUERY_COMPLETE: + if (!ancs_service_found){ + printf("ANCS Service not found"); + tc_state = TC_IDLE; + break; + } + tc_state = TC_W4_CHARACTERISTIC_RESULT; + printf("ANCS Client - Discover characteristics for ANCS SERVICE \n"); + gatt_client_discover_characteristics_for_service(&ancs_client_context, &ancs_service); + break; + default: + break; + } + break; + + case TC_W4_CHARACTERISTIC_RESULT: + switch(event->type){ + case GATT_CHARACTERISTIC_QUERY_RESULT: + characteristic = ((le_characteristic_event_t *) event)->characteristic; + if (memcmp(characteristic.uuid128, ancs_notification_source_uuid, 16) == 0){ + printf("ANCS Notification Source Characterisic found\n"); + ancs_notification_source_characteristic = characteristic; + ancs_characteristcs++; + break; + } + if (memcmp(characteristic.uuid128, ancs_control_point_uuid, 16) == 0){ + printf("ANCS Control Point found\n"); + ancs_control_point_characteristic = characteristic; + ancs_characteristcs++; + break; + } + if (memcmp(characteristic.uuid128, ancs_data_source_uuid, 16) == 0){ + printf("ANCS Data Source Characterisic found\n"); + ancs_data_source_characteristic = characteristic; + ancs_characteristcs++; + break; + } + break; + case GATT_QUERY_COMPLETE: + printf("ANCS Characteristcs count %u\n", ancs_characteristcs); + tc_state = TC_W4_NOTIFICATION_SOURCE_SUBSCRIBED; + gatt_client_write_client_characteristic_configuration(&ancs_client_context, &ancs_notification_source_characteristic, + GATT_CLIENT_CHARACTERISTICS_CONFIGURATION_NOTIFICATION); + break; + default: + break; + } + break; + case TC_W4_NOTIFICATION_SOURCE_SUBSCRIBED: + switch(event->type){ + case GATT_QUERY_COMPLETE: + printf("ANCS Notification Source subscribed\n"); + tc_state = TC_W4_DATA_SOURCE_SUBSCRIBED; + gatt_client_write_client_characteristic_configuration(&ancs_client_context, &ancs_data_source_characteristic, + GATT_CLIENT_CHARACTERISTICS_CONFIGURATION_NOTIFICATION); + break; + default: + break; + } + break; + case TC_W4_DATA_SOURCE_SUBSCRIBED: + switch(event->type){ + case GATT_QUERY_COMPLETE: + printf("ANCS Data Source subscribed\n"); + tc_state = TC_SUBSCRIBED; + notify_client(ANCS_CLIENT_CONNECTED); + break; + default: + break; + } + break; + case TC_SUBSCRIBED: + if ( event->type != GATT_NOTIFICATION && event->type != GATT_INDICATION ) break; + value_event = (le_characteristic_value_event_t *) event; + if (value_event->value_handle == ancs_data_source_characteristic.value_handle){ + int i; + for (i=0;iblob_length;i++) { + ancs_chunk_parser_handle_byte(value_event->blob[i]); + } + } else if (value_event->value_handle == ancs_notification_source_characteristic.value_handle){ + ancs_notification_uid = READ_BT_32(value_event->blob, 4); + printf("Notification received: EventID %02x, EventFlags %02x, CategoryID %02x, CategoryCount %u, UID %04x\n", + value_event->blob[0], value_event->blob[1], value_event->blob[2], value_event->blob[3], ancs_notification_uid); + static uint8_t get_notification_attributes[] = {0, 0,0,0,0, 0, 1,32,0, 2,32,0, 3,32,0, 4, 5}; + bt_store_32(get_notification_attributes, 1, ancs_notification_uid); + ancs_notification_uid = 0; + ancs_chunk_parser_init(); + gatt_client_write_value_of_characteristic(&ancs_client_context, ancs_control_point_characteristic.value_handle, + sizeof(get_notification_attributes), get_notification_attributes); + } else { + printf("Unknown Source: "); + printf_hexdump(value_event->blob , value_event->blob_length); + } + break; + default: + break; + } + // app_run(); +} + +void ancs_client_hci_event_handler (uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){ + int connection_encrypted; + switch (packet_type) { + + case HCI_EVENT_PACKET: + switch (packet[0]) { + + case HCI_EVENT_LE_META: + switch (packet[2]) { + case HCI_SUBEVENT_LE_CONNECTION_COMPLETE: + handle = READ_BT_16(packet, 4); + printf("Connection handle 0x%04x\n", handle); + + // we need to be paired to enable notifications + tc_state = TC_W4_ENCRYPTED_CONNECTION; + sm_send_security_request(); + break; + + default: + break; + } + break; + + case HCI_EVENT_ENCRYPTION_CHANGE: + if (handle != READ_BT_16(packet, 3)) break; + connection_encrypted = packet[5]; + log_info("Encryption state change: %u", connection_encrypted); + if (!connection_encrypted) break; + if (tc_state != TC_W4_ENCRYPTED_CONNECTION) break; + + // let's start + printf("\nANCS Client - CONNECTED, discover ANCS service\n"); + tc_state = TC_W4_SERVICE_RESULT; + gatt_client_start(&ancs_client_context, handle); + gatt_client_discover_primary_services_by_uuid128(&ancs_client_context, ancs_service_uuid); + break; + + case HCI_EVENT_DISCONNECTION_COMPLETE: + notify_client(ANCS_CLIENT_DISCONNECTED); + break; + + default: + break; + } + } +} + +void ancs_client_init(){ + gatt_client_register_packet_handler(&handle_gatt_client_event); +} diff --git a/example/libusb/ancs_client_lib.h b/example/libusb/ancs_client_lib.h new file mode 100644 index 000000000..cb2fd6e1c --- /dev/null +++ b/example/libusb/ancs_client_lib.h @@ -0,0 +1,59 @@ +/* + * Copyright (C) 2011-2013 by Matthias Ringwald + * + * 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. This software may not be used in a commercial product + * without an explicit license granted by the copyright holder. + * + * THIS SOFTWARE IS PROVIDED BY MATTHIAS RINGWALD 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. + * + */ + +#ifndef __ANCS_CLIENT_LIB_H +#define __ANCS_CLIENT_LIB_H + +#if defined __cplusplus +extern "C" { +#endif + +#include + +typedef struct ancs_event{ + uint8_t type; + uint16_t handle; + uint16_t attribute_id; + const char * text; +} ancs_event_t; + +void ancs_client_init(); +void ancs_client_hci_event_handler (uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size); +void ancs_client_register_callback(void (*handler)(ancs_event_t * event)); +const char * ancs_client_attribute_name_for_id(int id); + +#if defined __cplusplus +} +#endif + +#endif diff --git a/include/btstack/hci_cmds.h b/include/btstack/hci_cmds.h index 4d25b8bb3..970453d6e 100644 --- a/include/btstack/hci_cmds.h +++ b/include/btstack/hci_cmds.h @@ -420,6 +420,10 @@ extern "C" { */ #define GAP_LE_ADVERTISING_REPORT 0xE2 +// ANCS Client +#define ANCS_CLIENT_CONNECTED 0xF0 +#define ANCS_CLIENT_NOTIFICATION 0xF1 +#define ANCS_CLIENT_DISCONNECTED 0xF2 // // Error Codes // diff --git a/platforms/posix/src/hci_transport_h2_libusb.c b/platforms/posix/src/hci_transport_h2_libusb.c index fa5dfe6ac..bede65352 100644 --- a/platforms/posix/src/hci_transport_h2_libusb.c +++ b/platforms/posix/src/hci_transport_h2_libusb.c @@ -54,7 +54,7 @@ #include /* UNIX standard function definitions */ #include -#include +#include #include "btstack-config.h"