Example #1
0
static void handle_gatt_client_event(le_event_t * event) {

    uint8_t * packet = (uint8_t*) event;
    int connection_encrypted;

    // handle connect / disconncet events first
    switch (packet[0]) {
    case HCI_EVENT_LE_META:
        switch (packet[2]) {
        case HCI_SUBEVENT_LE_CONNECTION_COMPLETE:
            gc_handle = READ_BT_16(packet, 4);
            printf("Connection handle 0x%04x, request encryption\n", gc_handle);

            // we need to be paired to enable notifications
            tc_state = TC_W4_ENCRYPTED_CONNECTION;
            sm_send_security_request(gc_handle);
            break;
        default:
            break;
        }
        return;

    case HCI_EVENT_ENCRYPTION_CHANGE:
        if (gc_handle != READ_BT_16(packet, 3)) return;
        connection_encrypted = packet[5];
        log_info("Encryption state change: %u", connection_encrypted);
        if (!connection_encrypted) return;
        if (tc_state != TC_W4_ENCRYPTED_CONNECTION) return;

        // let's start
        printf("\nANCS Client - CONNECTED, discover ANCS service\n");
        tc_state = TC_W4_SERVICE_RESULT;
        gatt_client_discover_primary_services_by_uuid128(gc_id, gc_handle, ancs_service_uuid);
        return;

    case HCI_EVENT_DISCONNECTION_COMPLETE:
        notify_client(ANCS_CLIENT_DISCONNECTED);
        return;

    default:
        break;
    }

    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(gc_id, gc_handle, &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(gc_id, gc_handle, &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(gc_id, gc_handle, &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; i<value_event->blob_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], (int) 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(gc_id, gc_handle, 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();
}
Example #2
0
static void handle_hci_event(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){

    UNUSED(packet_type);
    UNUSED(channel);
    UNUSED(size);

    int connection_encrypted;

    // handle connect / disconncet events first
    switch (hci_event_packet_get_type(packet)) {
        case HCI_EVENT_LE_META:
            switch (packet[2]) {
                case HCI_SUBEVENT_LE_CONNECTION_COMPLETE:
                    gc_handle = little_endian_read_16(packet, 4);
                    log_info("Connection handle 0x%04x, request encryption", gc_handle);

                    // we need to be paired to enable notifications
                    tc_state = TC_W4_ENCRYPTED_CONNECTION;
                    sm_send_security_request(gc_handle);
                    break;
                default:
                    break;
            }
            return;

        case HCI_EVENT_ENCRYPTION_CHANGE: 
            if (gc_handle != little_endian_read_16(packet, 3)) return;
            connection_encrypted = packet[5];
            log_info("Encryption state change: %u", connection_encrypted);
            if (!connection_encrypted) return;
            if (tc_state != TC_W4_ENCRYPTED_CONNECTION) return;

            // let's start
            log_info("\nANCS Client - CONNECTED, discover ANCS service");
            tc_state = TC_W4_SERVICE_RESULT;
            gatt_client_discover_primary_services_by_uuid128(handle_hci_event, gc_handle, ancs_service_uuid);
            return;
            
        case HCI_EVENT_DISCONNECTION_COMPLETE:
            if (hci_event_disconnection_complete_get_connection_handle(packet) != gc_handle) break;
            if (tc_state == TC_SUBSCRIBED){
                notify_client_simple(ANCS_SUBEVENT_CLIENT_DISCONNECTED);
            }
            tc_state = TC_IDLE;
            gc_handle = 0;
            return;

        default:
            break;
    }

    gatt_client_characteristic_t characteristic;
    uint8_t *           value;
    uint16_t            value_handle;
    uint16_t            value_length;

    switch(tc_state){
        case TC_W4_SERVICE_RESULT:
            switch(hci_event_packet_get_type(packet)){
                case GATT_EVENT_SERVICE_QUERY_RESULT:
                    gatt_event_service_query_result_get_service(packet, &ancs_service);
                    ancs_service_found = 1;
                    break;
                case GATT_EVENT_QUERY_COMPLETE:
                    if (!ancs_service_found){
                        log_info("ANCS Service not found");
                        tc_state = TC_IDLE;
                        break;
                    }
                    tc_state = TC_W4_CHARACTERISTIC_RESULT;
                    log_info("ANCS Client - Discover characteristics for ANCS SERVICE ");
                    gatt_client_discover_characteristics_for_service(handle_hci_event, gc_handle, &ancs_service);
                    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, &characteristic);
                    if (memcmp(characteristic.uuid128, ancs_notification_source_uuid, 16) == 0){
                        log_info("ANCS Notification Source found, attribute handle %u", characteristic.value_handle);
                        ancs_notification_source_characteristic = characteristic;
                        ancs_characteristcs++;
                        break;                        
                    }
                    if (memcmp(characteristic.uuid128, ancs_control_point_uuid, 16) == 0){
                        log_info("ANCS Control Point found, attribute handle %u", characteristic.value_handle);
                        ancs_control_point_characteristic = characteristic;
                        ancs_characteristcs++;
                        break;                        
                    }
                    if (memcmp(characteristic.uuid128, ancs_data_source_uuid, 16) == 0){
                        log_info("ANCS Data Source found, attribute handle %u", characteristic.value_handle);
                        ancs_data_source_characteristic = characteristic;
                        ancs_characteristcs++;
                        break;                        
                    }
                    break;
                case GATT_EVENT_QUERY_COMPLETE:
                    log_info("ANCS Characteristcs count %u", ancs_characteristcs);
                    tc_state = TC_W4_NOTIFICATION_SOURCE_SUBSCRIBED;
                    gatt_client_listen_for_characteristic_value_updates(&ancs_notification_source_notification, &handle_hci_event, gc_handle, &ancs_notification_source_characteristic);
                    gatt_client_write_client_characteristic_configuration(handle_hci_event, gc_handle, &ancs_notification_source_characteristic,
                        GATT_CLIENT_CHARACTERISTICS_CONFIGURATION_NOTIFICATION);
                    break;
                default:
                    break;
            }
            break;
        case TC_W4_NOTIFICATION_SOURCE_SUBSCRIBED:
            switch(hci_event_packet_get_type(packet)){
                case GATT_EVENT_QUERY_COMPLETE:
                    log_info("ANCS Notification Source subscribed");
                    tc_state = TC_W4_DATA_SOURCE_SUBSCRIBED;
                    gatt_client_listen_for_characteristic_value_updates(&ancs_data_source_notification, &handle_hci_event, gc_handle, &ancs_data_source_characteristic);
                    gatt_client_write_client_characteristic_configuration(handle_hci_event, gc_handle, &ancs_data_source_characteristic,
                        GATT_CLIENT_CHARACTERISTICS_CONFIGURATION_NOTIFICATION);
                    break;
                default:
                    break;
            }
            break;
        case TC_W4_DATA_SOURCE_SUBSCRIBED:
            switch(hci_event_packet_get_type(packet)){
                case GATT_EVENT_QUERY_COMPLETE:
                    log_info("ANCS Data Source subscribed");
                    tc_state = TC_SUBSCRIBED;
                    notify_client_simple(ANCS_SUBEVENT_CLIENT_CONNECTED);
                    break;
                default:
                    break;
            }
            break;
        case TC_SUBSCRIBED:
            if (hci_event_packet_get_type(packet) != GATT_EVENT_NOTIFICATION && hci_event_packet_get_type(packet) != GATT_EVENT_INDICATION ) break;

            value_handle = little_endian_read_16(packet, 4);
            value_length = little_endian_read_16(packet, 6);
            value = &packet[8];

            log_info("ANCS Notification, value handle %u", value_handle);

            if (value_handle == ancs_data_source_characteristic.value_handle){
                int i;
                for (i=0;i<value_length;i++) {
                    ancs_chunk_parser_handle_byte(value[i]);
                }
            } else if (value_handle == ancs_notification_source_characteristic.value_handle){
                ancs_notification_uid = little_endian_read_32(value, 4);
                log_info("Notification received: EventID %02x, EventFlags %02x, CategoryID %02x, CategoryCount %u, UID %04x",
                    value[0], value[1], value[2], value[3], (int) 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};
                little_endian_store_32(get_notification_attributes, 1, ancs_notification_uid);
                ancs_notification_uid = 0;
                ancs_chunk_parser_init();
                gatt_client_write_value_of_characteristic(handle_hci_event, gc_handle, ancs_control_point_characteristic.value_handle, 
                    sizeof(get_notification_attributes), get_notification_attributes);
            } else {
                log_info("Unknown Source: ");
                log_info_hexdump(value , value_length);
            }
            break;
        default:
            break;
    }    
    // app_run();
}