mirror of
https://github.com/bluekitchen/btstack.git
synced 2025-03-14 01:27:41 +00:00
split ancs_client in main app and lib, use pkg-config for libusb
This commit is contained in:
parent
3e67b70164
commit
533c0e8283
@ -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
|
||||
|
@ -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;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], 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)
|
||||
|
326
example/libusb/ancs_client_lib.c
Normal file
326
example/libusb/ancs_client_lib.c
Normal file
@ -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 <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <btstack/run_loop.h>
|
||||
|
||||
#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;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], 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);
|
||||
}
|
59
example/libusb/ancs_client_lib.h
Normal file
59
example/libusb/ancs_client_lib.h
Normal file
@ -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 <stdint.h>
|
||||
|
||||
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
|
@ -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
|
||||
//
|
||||
|
@ -54,7 +54,7 @@
|
||||
#include <unistd.h> /* UNIX standard function definitions */
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <libusb-1.0/libusb.h>
|
||||
#include <libusb.h>
|
||||
|
||||
#include "btstack-config.h"
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user