This commit is contained in:
Matthias Ringwald 2015-04-25 23:39:48 +02:00
commit 8496cdf728

View File

@ -42,9 +42,9 @@
* API to discover primary services and their characteristics of the first found * API to discover primary services and their characteristics of the first found
* device that is advertising its services. * device that is advertising its services.
* *
* @text The logic is divided between the HCI and GATT client packet handlers. * The logic is divided between the HCI and GATT client packet handlers.
* The HCI packet handler with its state machine is responsible for finding and * The HCI packet handler is responsible for finding a remote device,
* connecting to a remote device, and for starting the first GATT client query. * connecting to it, and for starting the first GATT client query.
* Then, the GATT client packet handler receives all primary services and * Then, the GATT client packet handler receives all primary services and
* requests the characteristics of the last one to keep the example short. * requests the characteristics of the last one to keep the example short.
* *
@ -94,26 +94,14 @@ static int service_index = 0;
/* @section Setting up GATT client /* @section Setting up GATT client
* *
* @text In setup phase, a GATT client must register the HCI and GATT client * @text In setup phase, a GATT client must register the HCI and GATT client
* packet handlers, as shown in Listing gattClientSetup. * packet handlers, as shown in Listing GATTClientSetup.
* Additionally, the security manager can be setup, if signed writes, or * Additionally, the security manager can be setup, if signed writes, or
* encrypted or authenticated connection, are required to access the * encrypted or authenticated connection, are required to access the
* characteristics, as explained in Section smp. * characteristics, as explained in Section smp.
*/ */
/* LISTING_START(gattClientSetup): Setting up GATT client */ /* LISTING_START(GATTClientSetup): Setting up GATT client */
typedef enum {
TC_IDLE,
TC_W4_SCAN_RESULT,
TC_W4_CONNECT,
TC_W4_SERVICE_RESULT,
TC_W4_CHARACTERISTIC_RESULT,
TC_W4_DISCONNECT
} gc_state_t;
static gc_state_t state = TC_IDLE;
static uint16_t gc_id; static uint16_t gc_id;
// Handles connect, disconnect, and advertising report events, // Handles connect, disconnect, and advertising report events,
@ -189,24 +177,15 @@ static void fill_advertising_report_from_packet(advertising_report_t * report, u
/* @section Packet handlers /* @section Packet handlers
* *
* @text The GATT browser goes sequentially through the states: * @text The HCI packet handler has to start the scanning,
* IDLE, W4_SCAN_RESULT, W4_CONNECT, W4_SERVICE_RESULT,
* W4_CHARACTERISTIC_RESULT, and W4_DISCONNECT.
*
* @text The W4_SERVICE_RESULT and W4_CHARACTERISTIC_RESULT states
* compose the state machine of the GATT client packet handler,
* as it reacts on GATT client events. The other states compose the
* state machine of the HCI packet handler.
*
* @text In detail, the HCI packet handler has to start the scanning,
* to find the first advertising device, to stop scanning, to connect * to find the first advertising device, to stop scanning, to connect
* to and later to disconnect from it, to start the gatt client upon * to and later to disconnect from it, to start the gatt client upon
* the connection is completed, and to send the first query - in this * the connection is completed, and to send the first query - in this
* case the gatt_client_discover_primary_services() is called, see * case the gatt_client_discover_primary_services() is called, see
* Listing gattBrowserHCIPacketHandler. * Listing GATTBrowserHCIPacketHandler.
*/ */
/* LISTING_START(gattBrowserHCIPacketHandler): Connecting and disconnecting from the GATT client */ /* LISTING_START(GATTBrowserHCIPacketHandler): Connecting and disconnecting from the GATT client */
static void handle_hci_event(void * connection, uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){ static void handle_hci_event(void * connection, uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){
if (packet_type != HCI_EVENT_PACKET) return; if (packet_type != HCI_EVENT_PACKET) return;
advertising_report_t report; advertising_report_t report;
@ -218,34 +197,28 @@ static void handle_hci_event(void * connection, uint8_t packet_type, uint16_t ch
if (packet[2] != HCI_STATE_WORKING) break; if (packet[2] != HCI_STATE_WORKING) break;
if (cmdline_addr_found){ if (cmdline_addr_found){
printf("Trying to connect to %s\n", bd_addr_to_str(cmdline_addr)); printf("Trying to connect to %s\n", bd_addr_to_str(cmdline_addr));
state = TC_W4_CONNECT;
le_central_connect(cmdline_addr, 0); le_central_connect(cmdline_addr, 0);
break; break;
} }
printf("BTstack activated, start scanning!\n"); printf("BTstack activated, start scanning!\n");
state = TC_W4_SCAN_RESULT;
le_central_set_scan_parameters(0,0x0030, 0x0030); le_central_set_scan_parameters(0,0x0030, 0x0030);
le_central_start_scan(); le_central_start_scan();
break; break;
case GAP_LE_ADVERTISING_REPORT: case GAP_LE_ADVERTISING_REPORT:
if (state != TC_W4_SCAN_RESULT) return;
fill_advertising_report_from_packet(&report, packet); fill_advertising_report_from_packet(&report, packet);
// stop scanning, and connect to the device // stop scanning, and connect to the device
state = TC_W4_CONNECT;
le_central_stop_scan(); le_central_stop_scan();
le_central_connect(report.address,report.address_type); le_central_connect(report.address,report.address_type);
break; break;
case HCI_EVENT_LE_META: case HCI_EVENT_LE_META:
// wait for connection complete // wait for connection complete
if (packet[2] != HCI_SUBEVENT_LE_CONNECTION_COMPLETE) break; if (packet[2] != HCI_SUBEVENT_LE_CONNECTION_COMPLETE) break;
if (state != TC_W4_CONNECT) return;
gc_handle = READ_BT_16(packet, 4); gc_handle = READ_BT_16(packet, 4);
// query primary services // query primary services
state = TC_W4_SERVICE_RESULT;
gatt_client_discover_primary_services(gc_id, gc_handle); gatt_client_discover_primary_services(gc_id, gc_handle);
break; break;
case HCI_EVENT_DISCONNECTION_COMPLETE: case HCI_EVENT_DISCONNECTION_COMPLETE:
printf("\ntest client - DISCONNECTED\n"); printf("\nGATT browser - DISCONNECTED\n");
exit(0); exit(0);
break; break;
default: default:
@ -254,65 +227,52 @@ static void handle_hci_event(void * connection, uint8_t packet_type, uint16_t ch
} }
/* LISTING_END */ /* LISTING_END */
/* @text Query results and further queries are handled by the gatt client packet /* @text Query results and further queries are handled by the GATT client packet
* handler, as shown in Listing gattBrowserQueryHandler. Here, upon * handler, as shown in Listing GATTBrowserQueryHandler. Here, upon
* receiving the primary services, the * receiving the primary services, the
* gatt_client_discover_characteristics_for_service() query for the last * gatt_client_discover_characteristics_for_service() query for the last
* received service is sent. After receiving the characteristics for the service, * received service is sent. After receiving the characteristics for the service,
* gap_disconnect is called to terminate the connection. Upon * gap_disconnect is called to terminate the connection. Upon
* disconnect, the HCI packet handler receives the disconnect complete event, and * disconnect, the HCI packet handler receives the disconnect complete event.
* has to call the gatt_client_stop() function to remove the disconnected device
* from the list of active GATT clients.
*/ */
/* LISTING_START(gattBrowserQueryHandler): Handling of the GATT client queries */ /* LISTING_START(GATTBrowserQueryHandler): Handling of the GATT client queries */
static int search_services = 1;
void handle_gatt_client_event(le_event_t * event){ void handle_gatt_client_event(le_event_t * event){
le_service_t service; le_service_t service;
le_characteristic_t characteristic; le_characteristic_t characteristic;
switch(state){ switch(event->type){
case TC_W4_SERVICE_RESULT: case GATT_SERVICE_QUERY_RESULT:
switch(event->type){ service = ((le_service_event_t *) event)->service;
case GATT_SERVICE_QUERY_RESULT: dump_service(&service);
service = ((le_service_event_t *) event)->service; services[service_count++] = service;
dump_service(&service);
services[service_count++] = service;
break;
case GATT_QUERY_COMPLETE:
state = TC_W4_CHARACTERISTIC_RESULT;
service_index = 0;
printf("\ntest client - CHARACTERISTIC for SERVICE ");
printUUID128(service.uuid128); printf("\n");
gatt_client_discover_characteristics_for_service(gc_id, gc_handle, &services[service_index]);
break;
default:
break;
}
break; break;
case GATT_CHARACTERISTIC_QUERY_RESULT:
case TC_W4_CHARACTERISTIC_RESULT: characteristic = ((le_characteristic_event_t *) event)->characteristic;
switch(event->type){ dump_characteristic(&characteristic);
case GATT_CHARACTERISTIC_QUERY_RESULT: break;
characteristic = ((le_characteristic_event_t *) event)->characteristic; case GATT_QUERY_COMPLETE:
dump_characteristic(&characteristic); if (search_services){
break; // GATT_QUERY_COMPLETE of search services
case GATT_QUERY_COMPLETE: service_index = 0;
if (service_index < service_count) { printf("\nGATT browser - CHARACTERISTIC for SERVICE ");
state = TC_W4_CHARACTERISTIC_RESULT; printUUID128(service.uuid128); printf("\n");
service = services[service_index++]; search_services = 0;
printf("\ntest client - CHARACTERISTIC for SERVICE "); gatt_client_discover_characteristics_for_service(gc_id, gc_handle, &services[service_index]);
printUUID128(service.uuid128); } else {
printf(", [0x%04x-0x%04x]\n", service.start_group_handle, service.end_group_handle); // GATT_QUERY_COMPLETE of search characteristics
if (service_index < service_count) {
gatt_client_discover_characteristics_for_service(gc_id, gc_handle, &service); service = services[service_index++];
break; printf("\nGATT browser - CHARACTERISTIC for SERVICE ");
} printUUID128(service.uuid128);
state = TC_W4_DISCONNECT; printf(", [0x%04x-0x%04x]\n", service.start_group_handle, service.end_group_handle);
service_index = 0;
gap_disconnect(gc_handle); gatt_client_discover_characteristics_for_service(gc_id, gc_handle, &service);
break;
default:
break; break;
}
service_index = 0;
gap_disconnect(gc_handle);
} }
break; break;
default: default: