1*6bdecec7SMatthias Ringwald /* 2*6bdecec7SMatthias Ringwald * Copyright (C) 2014 BlueKitchen GmbH 3*6bdecec7SMatthias Ringwald * 4*6bdecec7SMatthias Ringwald * Redistribution and use in source and binary forms, with or without 5*6bdecec7SMatthias Ringwald * modification, are permitted provided that the following conditions 6*6bdecec7SMatthias Ringwald * are met: 7*6bdecec7SMatthias Ringwald * 8*6bdecec7SMatthias Ringwald * 1. Redistributions of source code must retain the above copyright 9*6bdecec7SMatthias Ringwald * notice, this list of conditions and the following disclaimer. 10*6bdecec7SMatthias Ringwald * 2. Redistributions in binary form must reproduce the above copyright 11*6bdecec7SMatthias Ringwald * notice, this list of conditions and the following disclaimer in the 12*6bdecec7SMatthias Ringwald * documentation and/or other materials provided with the distribution. 13*6bdecec7SMatthias Ringwald * 3. Neither the name of the copyright holders nor the names of 14*6bdecec7SMatthias Ringwald * contributors may be used to endorse or promote products derived 15*6bdecec7SMatthias Ringwald * from this software without specific prior written permission. 16*6bdecec7SMatthias Ringwald * 4. Any redistribution, use, or modification is done solely for 17*6bdecec7SMatthias Ringwald * personal benefit and not for any commercial purpose or for 18*6bdecec7SMatthias Ringwald * monetary gain. 19*6bdecec7SMatthias Ringwald * 20*6bdecec7SMatthias Ringwald * THIS SOFTWARE IS PROVIDED BY BLUEKITCHEN GMBH AND CONTRIBUTORS 21*6bdecec7SMatthias Ringwald * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 22*6bdecec7SMatthias Ringwald * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 23*6bdecec7SMatthias Ringwald * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MATTHIAS 24*6bdecec7SMatthias Ringwald * RINGWALD OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 25*6bdecec7SMatthias Ringwald * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 26*6bdecec7SMatthias Ringwald * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS 27*6bdecec7SMatthias Ringwald * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 28*6bdecec7SMatthias Ringwald * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 29*6bdecec7SMatthias Ringwald * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 30*6bdecec7SMatthias Ringwald * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31*6bdecec7SMatthias Ringwald * SUCH DAMAGE. 32*6bdecec7SMatthias Ringwald * 33*6bdecec7SMatthias Ringwald * Please inquire about commercial licensing options at 34*6bdecec7SMatthias Ringwald * [email protected] 35*6bdecec7SMatthias Ringwald * 36*6bdecec7SMatthias Ringwald */ 37*6bdecec7SMatthias Ringwald 38*6bdecec7SMatthias Ringwald #define BTSTACK_FILE__ "ancs_client.c" 39*6bdecec7SMatthias Ringwald 40*6bdecec7SMatthias Ringwald #include "btstack_config.h" 41*6bdecec7SMatthias Ringwald 42*6bdecec7SMatthias Ringwald #include <stdint.h> 43*6bdecec7SMatthias Ringwald #include <string.h> 44*6bdecec7SMatthias Ringwald 45*6bdecec7SMatthias Ringwald #include "ble/gatt-service/ancs_client.h" 46*6bdecec7SMatthias Ringwald 47*6bdecec7SMatthias Ringwald #include "ble/att_db.h" 48*6bdecec7SMatthias Ringwald #include "ble/core.h" 49*6bdecec7SMatthias Ringwald #include "ble/gatt_client.h" 50*6bdecec7SMatthias Ringwald #include "ble/sm.h" 51*6bdecec7SMatthias Ringwald #include "btstack_debug.h" 52*6bdecec7SMatthias Ringwald #include "btstack_event.h" 53*6bdecec7SMatthias Ringwald #include "btstack_run_loop.h" 54*6bdecec7SMatthias Ringwald #include "gap.h" 55*6bdecec7SMatthias Ringwald 56*6bdecec7SMatthias Ringwald // ancs_client.h Start 57*6bdecec7SMatthias Ringwald typedef enum ancs_chunk_parser_state { 58*6bdecec7SMatthias Ringwald W4_ATTRIBUTE_ID, 59*6bdecec7SMatthias Ringwald W4_ATTRIBUTE_LEN, 60*6bdecec7SMatthias Ringwald W4_ATTRIBUTE_COMPLETE, 61*6bdecec7SMatthias Ringwald } ancs_chunk_parser_state_t; 62*6bdecec7SMatthias Ringwald 63*6bdecec7SMatthias Ringwald typedef enum { 64*6bdecec7SMatthias Ringwald TC_IDLE, 65*6bdecec7SMatthias Ringwald TC_W4_ENCRYPTED_CONNECTION, 66*6bdecec7SMatthias Ringwald TC_W4_SERVICE_RESULT, 67*6bdecec7SMatthias Ringwald TC_W4_CHARACTERISTIC_RESULT, 68*6bdecec7SMatthias Ringwald TC_W4_DATA_SOURCE_SUBSCRIBED, 69*6bdecec7SMatthias Ringwald TC_W4_NOTIFICATION_SOURCE_SUBSCRIBED, 70*6bdecec7SMatthias Ringwald TC_SUBSCRIBED, 71*6bdecec7SMatthias Ringwald TC_W4_DISCONNECT 72*6bdecec7SMatthias Ringwald } tc_state_t; 73*6bdecec7SMatthias Ringwald 74*6bdecec7SMatthias Ringwald static uint32_t ancs_notification_uid; 75*6bdecec7SMatthias Ringwald static uint16_t gc_handle; 76*6bdecec7SMatthias Ringwald static gatt_client_notification_t ancs_notification_source_notification; 77*6bdecec7SMatthias Ringwald static gatt_client_notification_t ancs_data_source_notification; 78*6bdecec7SMatthias Ringwald static int ancs_service_found; 79*6bdecec7SMatthias Ringwald static gatt_client_service_t ancs_service; 80*6bdecec7SMatthias Ringwald static gatt_client_characteristic_t ancs_notification_source_characteristic; 81*6bdecec7SMatthias Ringwald static gatt_client_characteristic_t ancs_control_point_characteristic; 82*6bdecec7SMatthias Ringwald static gatt_client_characteristic_t ancs_data_source_characteristic; 83*6bdecec7SMatthias Ringwald static int ancs_characteristcs; 84*6bdecec7SMatthias Ringwald static tc_state_t tc_state = TC_IDLE; 85*6bdecec7SMatthias Ringwald 86*6bdecec7SMatthias Ringwald static ancs_chunk_parser_state_t chunk_parser_state; 87*6bdecec7SMatthias Ringwald static uint8_t ancs_notification_buffer[50]; 88*6bdecec7SMatthias Ringwald static uint16_t ancs_bytes_received; 89*6bdecec7SMatthias Ringwald static uint16_t ancs_bytes_needed; 90*6bdecec7SMatthias Ringwald static uint8_t ancs_attribute_id; 91*6bdecec7SMatthias Ringwald static uint16_t ancs_attribute_len; 92*6bdecec7SMatthias Ringwald 93*6bdecec7SMatthias Ringwald static btstack_packet_handler_t client_handler; 94*6bdecec7SMatthias Ringwald static btstack_packet_callback_registration_t hci_event_callback_registration; 95*6bdecec7SMatthias Ringwald 96*6bdecec7SMatthias Ringwald void ancs_client_register_callback(btstack_packet_handler_t handler){ 97*6bdecec7SMatthias Ringwald client_handler = handler; 98*6bdecec7SMatthias Ringwald } 99*6bdecec7SMatthias Ringwald 100*6bdecec7SMatthias Ringwald static void notify_client_text(int event_type){ 101*6bdecec7SMatthias Ringwald if (!client_handler) return; 102*6bdecec7SMatthias Ringwald uint8_t event[7 + sizeof(ancs_notification_buffer) + 1]; 103*6bdecec7SMatthias Ringwald event[0] = HCI_EVENT_ANCS_META; 104*6bdecec7SMatthias Ringwald event[1] = 5u + ancs_attribute_len; 105*6bdecec7SMatthias Ringwald event[2] = event_type; 106*6bdecec7SMatthias Ringwald little_endian_store_16(event, 3, gc_handle); 107*6bdecec7SMatthias Ringwald little_endian_store_16(event, 5, ancs_attribute_id); 108*6bdecec7SMatthias Ringwald (void)memcpy(&event[7], ancs_notification_buffer, ancs_attribute_len); 109*6bdecec7SMatthias Ringwald // we're nice 110*6bdecec7SMatthias Ringwald event[7u+ancs_attribute_len] = 0u; 111*6bdecec7SMatthias Ringwald (*client_handler)(HCI_EVENT_PACKET, 0u, event, event[1u] + 2u); 112*6bdecec7SMatthias Ringwald } 113*6bdecec7SMatthias Ringwald 114*6bdecec7SMatthias Ringwald static void notify_client_simple(int event_type){ 115*6bdecec7SMatthias Ringwald if (!client_handler) return; 116*6bdecec7SMatthias Ringwald uint8_t event[5]; 117*6bdecec7SMatthias Ringwald event[0] = HCI_EVENT_ANCS_META; 118*6bdecec7SMatthias Ringwald event[1] = 3; 119*6bdecec7SMatthias Ringwald event[2] = event_type; 120*6bdecec7SMatthias Ringwald little_endian_store_16(event, 3, gc_handle); 121*6bdecec7SMatthias Ringwald (*client_handler)(HCI_EVENT_PACKET, 0, event, sizeof(event)); 122*6bdecec7SMatthias Ringwald } 123*6bdecec7SMatthias Ringwald 124*6bdecec7SMatthias Ringwald static void ancs_chunk_parser_init(void){ 125*6bdecec7SMatthias Ringwald chunk_parser_state = W4_ATTRIBUTE_ID; 126*6bdecec7SMatthias Ringwald ancs_bytes_received = 0; 127*6bdecec7SMatthias Ringwald ancs_bytes_needed = 6; 128*6bdecec7SMatthias Ringwald } 129*6bdecec7SMatthias Ringwald 130*6bdecec7SMatthias Ringwald const char * ancs_client_attribute_name_for_id(int id){ 131*6bdecec7SMatthias Ringwald static const char * ancs_attribute_names[] = { 132*6bdecec7SMatthias Ringwald "AppIdentifier", 133*6bdecec7SMatthias Ringwald "IDTitle", 134*6bdecec7SMatthias Ringwald "IDSubtitle", 135*6bdecec7SMatthias Ringwald "IDMessage", 136*6bdecec7SMatthias Ringwald "IDMessageSize", 137*6bdecec7SMatthias Ringwald "IDDate" 138*6bdecec7SMatthias Ringwald }; 139*6bdecec7SMatthias Ringwald 140*6bdecec7SMatthias Ringwald static const uint16_t ANCS_ATTRBUTE_NAMES_COUNT = sizeof(ancs_attribute_names) / sizeof(char *); 141*6bdecec7SMatthias Ringwald 142*6bdecec7SMatthias Ringwald if (id >= ANCS_ATTRBUTE_NAMES_COUNT) return NULL; 143*6bdecec7SMatthias Ringwald return ancs_attribute_names[id]; 144*6bdecec7SMatthias Ringwald } 145*6bdecec7SMatthias Ringwald 146*6bdecec7SMatthias Ringwald static void ancs_chunk_parser_handle_byte(uint8_t data){ 147*6bdecec7SMatthias Ringwald ancs_notification_buffer[ancs_bytes_received++] = data; 148*6bdecec7SMatthias Ringwald if (ancs_bytes_received < ancs_bytes_needed) return; 149*6bdecec7SMatthias Ringwald switch (chunk_parser_state){ 150*6bdecec7SMatthias Ringwald case W4_ATTRIBUTE_ID: 151*6bdecec7SMatthias Ringwald ancs_attribute_id = ancs_notification_buffer[ancs_bytes_received-1u]; 152*6bdecec7SMatthias Ringwald ancs_bytes_received = 0; 153*6bdecec7SMatthias Ringwald ancs_bytes_needed = 2; 154*6bdecec7SMatthias Ringwald chunk_parser_state = W4_ATTRIBUTE_LEN; 155*6bdecec7SMatthias Ringwald break; 156*6bdecec7SMatthias Ringwald case W4_ATTRIBUTE_LEN: 157*6bdecec7SMatthias Ringwald ancs_attribute_len = little_endian_read_16(ancs_notification_buffer, ancs_bytes_received-2u); 158*6bdecec7SMatthias Ringwald ancs_bytes_received = 0; 159*6bdecec7SMatthias Ringwald ancs_bytes_needed = ancs_attribute_len; 160*6bdecec7SMatthias Ringwald if (ancs_attribute_len == 0u) { 161*6bdecec7SMatthias Ringwald ancs_bytes_needed = 1; 162*6bdecec7SMatthias Ringwald chunk_parser_state = W4_ATTRIBUTE_ID; 163*6bdecec7SMatthias Ringwald break; 164*6bdecec7SMatthias Ringwald } 165*6bdecec7SMatthias Ringwald chunk_parser_state = W4_ATTRIBUTE_COMPLETE; 166*6bdecec7SMatthias Ringwald break; 167*6bdecec7SMatthias Ringwald case W4_ATTRIBUTE_COMPLETE: 168*6bdecec7SMatthias Ringwald ancs_notification_buffer[ancs_bytes_received] = 0; 169*6bdecec7SMatthias Ringwald notify_client_text(ANCS_SUBEVENT_CLIENT_NOTIFICATION); 170*6bdecec7SMatthias Ringwald ancs_bytes_received = 0; 171*6bdecec7SMatthias Ringwald ancs_bytes_needed = 1; 172*6bdecec7SMatthias Ringwald chunk_parser_state = W4_ATTRIBUTE_ID; 173*6bdecec7SMatthias Ringwald break; 174*6bdecec7SMatthias Ringwald default: 175*6bdecec7SMatthias Ringwald btstack_assert(false); 176*6bdecec7SMatthias Ringwald break; 177*6bdecec7SMatthias Ringwald } 178*6bdecec7SMatthias Ringwald } 179*6bdecec7SMatthias Ringwald 180*6bdecec7SMatthias Ringwald static void handle_hci_event(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){ 181*6bdecec7SMatthias Ringwald 182*6bdecec7SMatthias Ringwald UNUSED(packet_type); // ok: only hci events 183*6bdecec7SMatthias Ringwald UNUSED(channel); // ok: there is no channel 184*6bdecec7SMatthias Ringwald UNUSED(size); // ok: fixed format events read from HCI buffer 185*6bdecec7SMatthias Ringwald 186*6bdecec7SMatthias Ringwald static const uint8_t ancs_service_uuid[] = {0x79,0x05,0xF4,0x31,0xB5,0xCE,0x4E,0x99,0xA4,0x0F,0x4B,0x1E,0x12,0x2D,0x00,0xD0}; 187*6bdecec7SMatthias Ringwald static const uint8_t ancs_notification_source_uuid[] = {0x9F,0xBF,0x12,0x0D,0x63,0x01,0x42,0xD9,0x8C,0x58,0x25,0xE6,0x99,0xA2,0x1D,0xBD}; 188*6bdecec7SMatthias Ringwald static const uint8_t ancs_control_point_uuid[] = {0x69,0xD1,0xD8,0xF3,0x45,0xE1,0x49,0xA8,0x98,0x21,0x9B,0xBD,0xFD,0xAA,0xD9,0xD9}; 189*6bdecec7SMatthias Ringwald static const uint8_t ancs_data_source_uuid[] = {0x22,0xEA,0xC6,0xE9,0x24,0xD6,0x4B,0xB5,0xBE,0x44,0xB3,0x6A,0xCE,0x7C,0x7B,0xFB}; 190*6bdecec7SMatthias Ringwald 191*6bdecec7SMatthias Ringwald 192*6bdecec7SMatthias Ringwald int connection_encrypted; 193*6bdecec7SMatthias Ringwald 194*6bdecec7SMatthias Ringwald // handle connect / disconncet events first 195*6bdecec7SMatthias Ringwald switch (hci_event_packet_get_type(packet)) { 196*6bdecec7SMatthias Ringwald case HCI_EVENT_LE_META: 197*6bdecec7SMatthias Ringwald switch (packet[2]) { 198*6bdecec7SMatthias Ringwald case HCI_SUBEVENT_LE_CONNECTION_COMPLETE: 199*6bdecec7SMatthias Ringwald gc_handle = little_endian_read_16(packet, 4); 200*6bdecec7SMatthias Ringwald log_info("Connection handle 0x%04x, request encryption", gc_handle); 201*6bdecec7SMatthias Ringwald 202*6bdecec7SMatthias Ringwald // we need to be paired to enable notifications 203*6bdecec7SMatthias Ringwald tc_state = TC_W4_ENCRYPTED_CONNECTION; 204*6bdecec7SMatthias Ringwald sm_request_pairing(gc_handle); 205*6bdecec7SMatthias Ringwald break; 206*6bdecec7SMatthias Ringwald default: 207*6bdecec7SMatthias Ringwald break; 208*6bdecec7SMatthias Ringwald } 209*6bdecec7SMatthias Ringwald return; 210*6bdecec7SMatthias Ringwald 211*6bdecec7SMatthias Ringwald case HCI_EVENT_ENCRYPTION_CHANGE: 212*6bdecec7SMatthias Ringwald if (gc_handle != little_endian_read_16(packet, 3)) return; 213*6bdecec7SMatthias Ringwald connection_encrypted = packet[5]; 214*6bdecec7SMatthias Ringwald log_info("Encryption state change: %u", connection_encrypted); 215*6bdecec7SMatthias Ringwald if (!connection_encrypted) return; 216*6bdecec7SMatthias Ringwald if (tc_state != TC_W4_ENCRYPTED_CONNECTION) return; 217*6bdecec7SMatthias Ringwald 218*6bdecec7SMatthias Ringwald // let's start 219*6bdecec7SMatthias Ringwald log_info("\nANCS Client - CONNECTED, discover ANCS service"); 220*6bdecec7SMatthias Ringwald tc_state = TC_W4_SERVICE_RESULT; 221*6bdecec7SMatthias Ringwald gatt_client_discover_primary_services_by_uuid128(handle_hci_event, gc_handle, ancs_service_uuid); 222*6bdecec7SMatthias Ringwald return; 223*6bdecec7SMatthias Ringwald 224*6bdecec7SMatthias Ringwald case HCI_EVENT_DISCONNECTION_COMPLETE: 225*6bdecec7SMatthias Ringwald if (hci_event_disconnection_complete_get_connection_handle(packet) != gc_handle) break; 226*6bdecec7SMatthias Ringwald if (tc_state == TC_SUBSCRIBED){ 227*6bdecec7SMatthias Ringwald notify_client_simple(ANCS_SUBEVENT_CLIENT_DISCONNECTED); 228*6bdecec7SMatthias Ringwald } 229*6bdecec7SMatthias Ringwald tc_state = TC_IDLE; 230*6bdecec7SMatthias Ringwald gc_handle = 0; 231*6bdecec7SMatthias Ringwald return; 232*6bdecec7SMatthias Ringwald 233*6bdecec7SMatthias Ringwald default: 234*6bdecec7SMatthias Ringwald break; 235*6bdecec7SMatthias Ringwald } 236*6bdecec7SMatthias Ringwald 237*6bdecec7SMatthias Ringwald gatt_client_characteristic_t characteristic; 238*6bdecec7SMatthias Ringwald uint8_t * value; 239*6bdecec7SMatthias Ringwald uint16_t value_handle; 240*6bdecec7SMatthias Ringwald uint16_t value_length; 241*6bdecec7SMatthias Ringwald 242*6bdecec7SMatthias Ringwald switch(tc_state){ 243*6bdecec7SMatthias Ringwald case TC_W4_SERVICE_RESULT: 244*6bdecec7SMatthias Ringwald switch(hci_event_packet_get_type(packet)){ 245*6bdecec7SMatthias Ringwald case GATT_EVENT_SERVICE_QUERY_RESULT: 246*6bdecec7SMatthias Ringwald gatt_event_service_query_result_get_service(packet, &ancs_service); 247*6bdecec7SMatthias Ringwald ancs_service_found = 1; 248*6bdecec7SMatthias Ringwald break; 249*6bdecec7SMatthias Ringwald case GATT_EVENT_QUERY_COMPLETE: 250*6bdecec7SMatthias Ringwald if (!ancs_service_found){ 251*6bdecec7SMatthias Ringwald log_info("ANCS Service not found"); 252*6bdecec7SMatthias Ringwald tc_state = TC_IDLE; 253*6bdecec7SMatthias Ringwald break; 254*6bdecec7SMatthias Ringwald } 255*6bdecec7SMatthias Ringwald tc_state = TC_W4_CHARACTERISTIC_RESULT; 256*6bdecec7SMatthias Ringwald log_info("ANCS Client - Discover characteristics for ANCS SERVICE "); 257*6bdecec7SMatthias Ringwald gatt_client_discover_characteristics_for_service(handle_hci_event, gc_handle, &ancs_service); 258*6bdecec7SMatthias Ringwald break; 259*6bdecec7SMatthias Ringwald default: 260*6bdecec7SMatthias Ringwald break; 261*6bdecec7SMatthias Ringwald } 262*6bdecec7SMatthias Ringwald break; 263*6bdecec7SMatthias Ringwald 264*6bdecec7SMatthias Ringwald case TC_W4_CHARACTERISTIC_RESULT: 265*6bdecec7SMatthias Ringwald switch(hci_event_packet_get_type(packet)){ 266*6bdecec7SMatthias Ringwald case GATT_EVENT_CHARACTERISTIC_QUERY_RESULT: 267*6bdecec7SMatthias Ringwald gatt_event_characteristic_query_result_get_characteristic(packet, &characteristic); 268*6bdecec7SMatthias Ringwald if (memcmp(characteristic.uuid128, ancs_notification_source_uuid, 16) == 0){ 269*6bdecec7SMatthias Ringwald log_info("ANCS Notification Source found, attribute handle %u", characteristic.value_handle); 270*6bdecec7SMatthias Ringwald ancs_notification_source_characteristic = characteristic; 271*6bdecec7SMatthias Ringwald ancs_characteristcs++; 272*6bdecec7SMatthias Ringwald break; 273*6bdecec7SMatthias Ringwald } 274*6bdecec7SMatthias Ringwald if (memcmp(characteristic.uuid128, ancs_control_point_uuid, 16) == 0){ 275*6bdecec7SMatthias Ringwald log_info("ANCS Control Point found, attribute handle %u", characteristic.value_handle); 276*6bdecec7SMatthias Ringwald ancs_control_point_characteristic = characteristic; 277*6bdecec7SMatthias Ringwald ancs_characteristcs++; 278*6bdecec7SMatthias Ringwald break; 279*6bdecec7SMatthias Ringwald } 280*6bdecec7SMatthias Ringwald if (memcmp(characteristic.uuid128, ancs_data_source_uuid, 16) == 0){ 281*6bdecec7SMatthias Ringwald log_info("ANCS Data Source found, attribute handle %u", characteristic.value_handle); 282*6bdecec7SMatthias Ringwald ancs_data_source_characteristic = characteristic; 283*6bdecec7SMatthias Ringwald ancs_characteristcs++; 284*6bdecec7SMatthias Ringwald break; 285*6bdecec7SMatthias Ringwald } 286*6bdecec7SMatthias Ringwald break; 287*6bdecec7SMatthias Ringwald case GATT_EVENT_QUERY_COMPLETE: 288*6bdecec7SMatthias Ringwald log_info("ANCS Characteristcs count %u", ancs_characteristcs); 289*6bdecec7SMatthias Ringwald tc_state = TC_W4_NOTIFICATION_SOURCE_SUBSCRIBED; 290*6bdecec7SMatthias Ringwald gatt_client_listen_for_characteristic_value_updates(&ancs_notification_source_notification, &handle_hci_event, gc_handle, &ancs_notification_source_characteristic); 291*6bdecec7SMatthias Ringwald gatt_client_write_client_characteristic_configuration(handle_hci_event, gc_handle, &ancs_notification_source_characteristic, 292*6bdecec7SMatthias Ringwald GATT_CLIENT_CHARACTERISTICS_CONFIGURATION_NOTIFICATION); 293*6bdecec7SMatthias Ringwald break; 294*6bdecec7SMatthias Ringwald default: 295*6bdecec7SMatthias Ringwald break; 296*6bdecec7SMatthias Ringwald } 297*6bdecec7SMatthias Ringwald break; 298*6bdecec7SMatthias Ringwald case TC_W4_NOTIFICATION_SOURCE_SUBSCRIBED: 299*6bdecec7SMatthias Ringwald switch(hci_event_packet_get_type(packet)){ 300*6bdecec7SMatthias Ringwald case GATT_EVENT_QUERY_COMPLETE: 301*6bdecec7SMatthias Ringwald log_info("ANCS Notification Source subscribed"); 302*6bdecec7SMatthias Ringwald tc_state = TC_W4_DATA_SOURCE_SUBSCRIBED; 303*6bdecec7SMatthias Ringwald gatt_client_listen_for_characteristic_value_updates(&ancs_data_source_notification, &handle_hci_event, gc_handle, &ancs_data_source_characteristic); 304*6bdecec7SMatthias Ringwald gatt_client_write_client_characteristic_configuration(handle_hci_event, gc_handle, &ancs_data_source_characteristic, 305*6bdecec7SMatthias Ringwald GATT_CLIENT_CHARACTERISTICS_CONFIGURATION_NOTIFICATION); 306*6bdecec7SMatthias Ringwald break; 307*6bdecec7SMatthias Ringwald default: 308*6bdecec7SMatthias Ringwald break; 309*6bdecec7SMatthias Ringwald } 310*6bdecec7SMatthias Ringwald break; 311*6bdecec7SMatthias Ringwald case TC_W4_DATA_SOURCE_SUBSCRIBED: 312*6bdecec7SMatthias Ringwald switch(hci_event_packet_get_type(packet)){ 313*6bdecec7SMatthias Ringwald case GATT_EVENT_QUERY_COMPLETE: 314*6bdecec7SMatthias Ringwald log_info("ANCS Data Source subscribed"); 315*6bdecec7SMatthias Ringwald tc_state = TC_SUBSCRIBED; 316*6bdecec7SMatthias Ringwald notify_client_simple(ANCS_SUBEVENT_CLIENT_CONNECTED); 317*6bdecec7SMatthias Ringwald break; 318*6bdecec7SMatthias Ringwald default: 319*6bdecec7SMatthias Ringwald break; 320*6bdecec7SMatthias Ringwald } 321*6bdecec7SMatthias Ringwald break; 322*6bdecec7SMatthias Ringwald case TC_SUBSCRIBED: 323*6bdecec7SMatthias Ringwald if ((hci_event_packet_get_type(packet) != GATT_EVENT_NOTIFICATION) && (hci_event_packet_get_type(packet) != GATT_EVENT_INDICATION) ) break; 324*6bdecec7SMatthias Ringwald 325*6bdecec7SMatthias Ringwald value_handle = little_endian_read_16(packet, 4); 326*6bdecec7SMatthias Ringwald value_length = little_endian_read_16(packet, 6); 327*6bdecec7SMatthias Ringwald value = &packet[8]; 328*6bdecec7SMatthias Ringwald 329*6bdecec7SMatthias Ringwald log_info("ANCS Notification, value handle %u", value_handle); 330*6bdecec7SMatthias Ringwald 331*6bdecec7SMatthias Ringwald if (value_handle == ancs_data_source_characteristic.value_handle){ 332*6bdecec7SMatthias Ringwald int i; 333*6bdecec7SMatthias Ringwald for (i=0;i<value_length;i++) { 334*6bdecec7SMatthias Ringwald ancs_chunk_parser_handle_byte(value[i]); 335*6bdecec7SMatthias Ringwald } 336*6bdecec7SMatthias Ringwald } else if (value_handle == ancs_notification_source_characteristic.value_handle){ 337*6bdecec7SMatthias Ringwald ancs_notification_uid = little_endian_read_32(value, 4); 338*6bdecec7SMatthias Ringwald log_info("Notification received: EventID %02x, EventFlags %02x, CategoryID %02x, CategoryCount %u, UID %04x", 339*6bdecec7SMatthias Ringwald value[0], value[1], value[2], value[3], (int) ancs_notification_uid); 340*6bdecec7SMatthias Ringwald static uint8_t get_notification_attributes[] = {0, 0,0,0,0, 0, 1,32,0, 2,32,0, 3,32,0, 4, 5}; 341*6bdecec7SMatthias Ringwald little_endian_store_32(get_notification_attributes, 1, ancs_notification_uid); 342*6bdecec7SMatthias Ringwald ancs_notification_uid = 0; 343*6bdecec7SMatthias Ringwald ancs_chunk_parser_init(); 344*6bdecec7SMatthias Ringwald gatt_client_write_value_of_characteristic(handle_hci_event, gc_handle, ancs_control_point_characteristic.value_handle, 345*6bdecec7SMatthias Ringwald sizeof(get_notification_attributes), get_notification_attributes); 346*6bdecec7SMatthias Ringwald } else { 347*6bdecec7SMatthias Ringwald log_info("Unknown Source: "); 348*6bdecec7SMatthias Ringwald log_info_hexdump(value , value_length); 349*6bdecec7SMatthias Ringwald } 350*6bdecec7SMatthias Ringwald break; 351*6bdecec7SMatthias Ringwald default: 352*6bdecec7SMatthias Ringwald break; 353*6bdecec7SMatthias Ringwald } 354*6bdecec7SMatthias Ringwald // app_run(); 355*6bdecec7SMatthias Ringwald } 356*6bdecec7SMatthias Ringwald 357*6bdecec7SMatthias Ringwald void ancs_client_init(void){ 358*6bdecec7SMatthias Ringwald hci_event_callback_registration.callback = &handle_hci_event; 359*6bdecec7SMatthias Ringwald hci_add_event_handler(&hci_event_callback_registration); 360*6bdecec7SMatthias Ringwald } 361