xref: /btstack/example/gatt_heart_rate_client.c (revision 6104991b22e7d660422a4977956ff1b8a4ee8626)
1*6104991bSMatthias Ringwald /*
2*6104991bSMatthias Ringwald  * Copyright (C) 2018 BlueKitchen GmbH
3*6104991bSMatthias Ringwald  *
4*6104991bSMatthias Ringwald  * Redistribution and use in source and binary forms, with or without
5*6104991bSMatthias Ringwald  * modification, are permitted provided that the following conditions
6*6104991bSMatthias Ringwald  * are met:
7*6104991bSMatthias Ringwald  *
8*6104991bSMatthias Ringwald  * 1. Redistributions of source code must retain the above copyright
9*6104991bSMatthias Ringwald  *    notice, this list of conditions and the following disclaimer.
10*6104991bSMatthias Ringwald  * 2. Redistributions in binary form must reproduce the above copyright
11*6104991bSMatthias Ringwald  *    notice, this list of conditions and the following disclaimer in the
12*6104991bSMatthias Ringwald  *    documentation and/or other materials provided with the distribution.
13*6104991bSMatthias Ringwald  * 3. Neither the name of the copyright holders nor the names of
14*6104991bSMatthias Ringwald  *    contributors may be used to endorse or promote products derived
15*6104991bSMatthias Ringwald  *    from this software without specific prior written permission.
16*6104991bSMatthias Ringwald  * 4. Any redistribution, use, or modification is done solely for
17*6104991bSMatthias Ringwald  *    personal benefit and not for any commercial purpose or for
18*6104991bSMatthias Ringwald  *    monetary gain.
19*6104991bSMatthias Ringwald  *
20*6104991bSMatthias Ringwald  * THIS SOFTWARE IS PROVIDED BY BLUEKITCHEN GMBH AND CONTRIBUTORS
21*6104991bSMatthias Ringwald  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22*6104991bSMatthias Ringwald  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23*6104991bSMatthias Ringwald  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MATTHIAS
24*6104991bSMatthias Ringwald  * RINGWALD OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25*6104991bSMatthias Ringwald  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26*6104991bSMatthias Ringwald  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
27*6104991bSMatthias Ringwald  * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
28*6104991bSMatthias Ringwald  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
29*6104991bSMatthias Ringwald  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
30*6104991bSMatthias Ringwald  * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31*6104991bSMatthias Ringwald  * SUCH DAMAGE.
32*6104991bSMatthias Ringwald  *
33*6104991bSMatthias Ringwald  * Please inquire about commercial licensing options at
34*6104991bSMatthias Ringwald  * [email protected]
35*6104991bSMatthias Ringwald  *
36*6104991bSMatthias Ringwald  */
37*6104991bSMatthias Ringwald 
38*6104991bSMatthias Ringwald #define __BTSTACK_FILE__ "gatt_heart_rate_client.c"
39*6104991bSMatthias Ringwald 
40*6104991bSMatthias Ringwald // *****************************************************************************
41*6104991bSMatthias Ringwald /* EXAMPLE_START(gatt_heart_rate_client): Connects for Heart Rate Sensor and reports measurements */
42*6104991bSMatthias Ringwald // *****************************************************************************
43*6104991bSMatthias Ringwald 
44*6104991bSMatthias Ringwald #include <inttypes.h>
45*6104991bSMatthias Ringwald #include <stdint.h>
46*6104991bSMatthias Ringwald #include <stdio.h>
47*6104991bSMatthias Ringwald #include <stdlib.h>
48*6104991bSMatthias Ringwald #include <string.h>
49*6104991bSMatthias Ringwald 
50*6104991bSMatthias Ringwald #include "btstack.h"
51*6104991bSMatthias Ringwald 
52*6104991bSMatthias Ringwald // prototypes
53*6104991bSMatthias Ringwald static void handle_gatt_client_event(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size);
54*6104991bSMatthias Ringwald 
55*6104991bSMatthias Ringwald typedef enum {
56*6104991bSMatthias Ringwald     TC_OFF,
57*6104991bSMatthias Ringwald     TC_IDLE,
58*6104991bSMatthias Ringwald     TC_W4_SCAN_RESULT,
59*6104991bSMatthias Ringwald     TC_W4_CONNECT,
60*6104991bSMatthias Ringwald     TC_W4_SERVICE_RESULT,
61*6104991bSMatthias Ringwald     TC_W4_HEART_RATE_MEASUREMENT_CHARACTERISTIC,
62*6104991bSMatthias Ringwald     TC_W4_ENABLE_NOTIFICATIONS_COMPLETE,
63*6104991bSMatthias Ringwald     TC_W4_SENSOR_LOCATION_CHARACTERISTIC,
64*6104991bSMatthias Ringwald     TC_W4_SENSOR_LOCATION,
65*6104991bSMatthias Ringwald     TC_CONNECTED
66*6104991bSMatthias Ringwald } gc_state_t;
67*6104991bSMatthias Ringwald 
68*6104991bSMatthias Ringwald static const char * sensor_contact_string[] = {
69*6104991bSMatthias Ringwald     "not supported",
70*6104991bSMatthias Ringwald     "not supported",
71*6104991bSMatthias Ringwald     "no/poor contact",
72*6104991bSMatthias Ringwald     "good contact"
73*6104991bSMatthias Ringwald };
74*6104991bSMatthias Ringwald 
75*6104991bSMatthias Ringwald static bd_addr_t cmdline_addr = { };
76*6104991bSMatthias Ringwald static int cmdline_addr_found = 0;
77*6104991bSMatthias Ringwald 
78*6104991bSMatthias Ringwald // addr and type of device with correct name
79*6104991bSMatthias Ringwald static bd_addr_t      le_streamer_addr;
80*6104991bSMatthias Ringwald static bd_addr_type_t le_streamer_addr_type;
81*6104991bSMatthias Ringwald 
82*6104991bSMatthias Ringwald static hci_con_handle_t connection_handle;
83*6104991bSMatthias Ringwald 
84*6104991bSMatthias Ringwald static gatt_client_service_t        heart_rate_service;
85*6104991bSMatthias Ringwald static gatt_client_characteristic_t body_sensor_location_characteristic;
86*6104991bSMatthias Ringwald static gatt_client_characteristic_t heart_rate_measurement_characteristic;
87*6104991bSMatthias Ringwald 
88*6104991bSMatthias Ringwald static uint8_t body_sensor_location;
89*6104991bSMatthias Ringwald 
90*6104991bSMatthias Ringwald static gatt_client_notification_t notification_listener;
91*6104991bSMatthias Ringwald static int listener_registered;
92*6104991bSMatthias Ringwald 
93*6104991bSMatthias Ringwald static gc_state_t state = TC_OFF;
94*6104991bSMatthias Ringwald static btstack_packet_callback_registration_t hci_event_callback_registration;
95*6104991bSMatthias Ringwald 
96*6104991bSMatthias Ringwald 
97*6104991bSMatthias Ringwald // returns 1 if name is found in advertisement
98*6104991bSMatthias Ringwald static int advertisement_report_contains_uuid16(uint16_t uuid16, uint8_t * advertisement_report){
99*6104991bSMatthias Ringwald     // get advertisement from report event
100*6104991bSMatthias Ringwald     const uint8_t * adv_data = gap_event_advertising_report_get_data(advertisement_report);
101*6104991bSMatthias Ringwald     uint16_t        adv_len  = gap_event_advertising_report_get_data_length(advertisement_report);
102*6104991bSMatthias Ringwald 
103*6104991bSMatthias Ringwald     // iterate over advertisement data
104*6104991bSMatthias Ringwald     ad_context_t context;
105*6104991bSMatthias Ringwald     int found = 0;
106*6104991bSMatthias Ringwald     for (ad_iterator_init(&context, adv_len, adv_data) ; ad_iterator_has_more(&context) ; ad_iterator_next(&context)){
107*6104991bSMatthias Ringwald         uint8_t data_type    = ad_iterator_get_data_type(&context);
108*6104991bSMatthias Ringwald         uint8_t data_size    = ad_iterator_get_data_len(&context);
109*6104991bSMatthias Ringwald         const uint8_t * data = ad_iterator_get_data(&context);
110*6104991bSMatthias Ringwald         int i;
111*6104991bSMatthias Ringwald         switch (data_type){
112*6104991bSMatthias Ringwald             case BLUETOOTH_DATA_TYPE_INCOMPLETE_LIST_OF_16_BIT_SERVICE_CLASS_UUIDS:
113*6104991bSMatthias Ringwald             case BLUETOOTH_DATA_TYPE_COMPLETE_LIST_OF_16_BIT_SERVICE_CLASS_UUIDS:
114*6104991bSMatthias Ringwald                 // compare common prefix
115*6104991bSMatthias Ringwald                 for (i=0; i<data_size;i+=2){
116*6104991bSMatthias Ringwald                     if (little_endian_read_16(data, i) == uuid16) {
117*6104991bSMatthias Ringwald                         found = 1;
118*6104991bSMatthias Ringwald                         break;
119*6104991bSMatthias Ringwald                     }
120*6104991bSMatthias Ringwald                 }
121*6104991bSMatthias Ringwald                 break;
122*6104991bSMatthias Ringwald             default:
123*6104991bSMatthias Ringwald                 break;
124*6104991bSMatthias Ringwald         }
125*6104991bSMatthias Ringwald     }
126*6104991bSMatthias Ringwald     return found;
127*6104991bSMatthias Ringwald }
128*6104991bSMatthias Ringwald 
129*6104991bSMatthias Ringwald static void handle_gatt_client_event(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){
130*6104991bSMatthias Ringwald     UNUSED(packet_type);
131*6104991bSMatthias Ringwald     UNUSED(channel);
132*6104991bSMatthias Ringwald     UNUSED(size);
133*6104991bSMatthias Ringwald 
134*6104991bSMatthias Ringwald     uint16_t heart_rate;
135*6104991bSMatthias Ringwald     uint8_t  sensor_contact;
136*6104991bSMatthias Ringwald 
137*6104991bSMatthias Ringwald     switch(state){
138*6104991bSMatthias Ringwald         case TC_W4_SERVICE_RESULT:
139*6104991bSMatthias Ringwald             switch(hci_event_packet_get_type(packet)){
140*6104991bSMatthias Ringwald                 case GATT_EVENT_SERVICE_QUERY_RESULT:
141*6104991bSMatthias Ringwald                     // store service (we expect only one)
142*6104991bSMatthias Ringwald                     gatt_event_service_query_result_get_service(packet, &heart_rate_service);
143*6104991bSMatthias Ringwald                     break;
144*6104991bSMatthias Ringwald                 case GATT_EVENT_QUERY_COMPLETE:
145*6104991bSMatthias Ringwald                     if (packet[4] != 0){
146*6104991bSMatthias Ringwald                         printf("SERVICE_QUERY_RESULT - Error status %x.\n", packet[4]);
147*6104991bSMatthias Ringwald                         gap_disconnect(connection_handle);
148*6104991bSMatthias Ringwald                         break;
149*6104991bSMatthias Ringwald                     }
150*6104991bSMatthias Ringwald                     state = TC_W4_HEART_RATE_MEASUREMENT_CHARACTERISTIC;
151*6104991bSMatthias Ringwald                     printf("Search for Heart Rate Measurement characteristic.\n");
152*6104991bSMatthias Ringwald                     gatt_client_discover_characteristics_for_service_by_uuid16(handle_gatt_client_event, connection_handle, &heart_rate_service, ORG_BLUETOOTH_CHARACTERISTIC_HEART_RATE_MEASUREMENT);
153*6104991bSMatthias Ringwald                     break;
154*6104991bSMatthias Ringwald                 default:
155*6104991bSMatthias Ringwald                     break;
156*6104991bSMatthias Ringwald             }
157*6104991bSMatthias Ringwald             break;
158*6104991bSMatthias Ringwald 
159*6104991bSMatthias Ringwald         case TC_W4_HEART_RATE_MEASUREMENT_CHARACTERISTIC:
160*6104991bSMatthias Ringwald             switch(hci_event_packet_get_type(packet)){
161*6104991bSMatthias Ringwald                 case GATT_EVENT_CHARACTERISTIC_QUERY_RESULT:
162*6104991bSMatthias Ringwald                     gatt_event_characteristic_query_result_get_characteristic(packet, &heart_rate_measurement_characteristic);
163*6104991bSMatthias Ringwald                     break;
164*6104991bSMatthias Ringwald                 case GATT_EVENT_QUERY_COMPLETE:
165*6104991bSMatthias Ringwald                     if (packet[4] != 0){
166*6104991bSMatthias Ringwald                         printf("CHARACTERISTIC_QUERY_RESULT - Error status %x.\n", packet[4]);
167*6104991bSMatthias Ringwald                         gap_disconnect(connection_handle);
168*6104991bSMatthias Ringwald                         break;
169*6104991bSMatthias Ringwald                     }
170*6104991bSMatthias Ringwald                     // register handler for notifications
171*6104991bSMatthias Ringwald                     listener_registered = 1;
172*6104991bSMatthias Ringwald                     gatt_client_listen_for_characteristic_value_updates(&notification_listener, handle_gatt_client_event, connection_handle, &heart_rate_measurement_characteristic);
173*6104991bSMatthias Ringwald                     // enable notifications
174*6104991bSMatthias Ringwald                     printf("Enable Notify on Heart Rate Measurements characteristic.\n");
175*6104991bSMatthias Ringwald                     state = TC_W4_ENABLE_NOTIFICATIONS_COMPLETE;
176*6104991bSMatthias Ringwald                     gatt_client_write_client_characteristic_configuration(handle_gatt_client_event, connection_handle,
177*6104991bSMatthias Ringwald                         &heart_rate_measurement_characteristic, GATT_CLIENT_CHARACTERISTICS_CONFIGURATION_NOTIFICATION);
178*6104991bSMatthias Ringwald                     break;
179*6104991bSMatthias Ringwald                 default:
180*6104991bSMatthias Ringwald                     break;
181*6104991bSMatthias Ringwald             }
182*6104991bSMatthias Ringwald             break;
183*6104991bSMatthias Ringwald 
184*6104991bSMatthias Ringwald         case TC_W4_ENABLE_NOTIFICATIONS_COMPLETE:
185*6104991bSMatthias Ringwald             switch(hci_event_packet_get_type(packet)){
186*6104991bSMatthias Ringwald                 case GATT_EVENT_QUERY_COMPLETE:
187*6104991bSMatthias Ringwald                     printf("Notifications enabled, status %02x\n", gatt_event_query_complete_get_status(packet));
188*6104991bSMatthias Ringwald 
189*6104991bSMatthias Ringwald                     state = TC_W4_SENSOR_LOCATION_CHARACTERISTIC;
190*6104991bSMatthias Ringwald                     printf("Search for Sensor Location characteristic.\n");
191*6104991bSMatthias Ringwald                     gatt_client_discover_characteristics_for_service_by_uuid16(handle_gatt_client_event, connection_handle, &heart_rate_service, ORG_BLUETOOTH_CHARACTERISTIC_BODY_SENSOR_LOCATION);
192*6104991bSMatthias Ringwald                     break;
193*6104991bSMatthias Ringwald                 default:
194*6104991bSMatthias Ringwald                     break;
195*6104991bSMatthias Ringwald             }
196*6104991bSMatthias Ringwald             break;
197*6104991bSMatthias Ringwald 
198*6104991bSMatthias Ringwald 
199*6104991bSMatthias Ringwald         case TC_W4_SENSOR_LOCATION_CHARACTERISTIC:
200*6104991bSMatthias Ringwald             switch(hci_event_packet_get_type(packet)){
201*6104991bSMatthias Ringwald                 case GATT_EVENT_CHARACTERISTIC_QUERY_RESULT:
202*6104991bSMatthias Ringwald                     gatt_event_characteristic_query_result_get_characteristic(packet, &body_sensor_location_characteristic);
203*6104991bSMatthias Ringwald                     break;
204*6104991bSMatthias Ringwald                 case GATT_EVENT_QUERY_COMPLETE:
205*6104991bSMatthias Ringwald                     if (packet[4] != 0){
206*6104991bSMatthias Ringwald                         printf("CHARACTERISTIC_QUERY_RESULT - Error status %x.\n", packet[4]);
207*6104991bSMatthias Ringwald                         state = TC_CONNECTED;
208*6104991bSMatthias Ringwald                         break;
209*6104991bSMatthias Ringwald                     }
210*6104991bSMatthias Ringwald                     state = TC_W4_HEART_RATE_MEASUREMENT_CHARACTERISTIC;
211*6104991bSMatthias Ringwald                     printf("Read Body Sensor Location.\n");
212*6104991bSMatthias Ringwald                     state = TC_W4_SENSOR_LOCATION;
213*6104991bSMatthias Ringwald                     gatt_client_read_value_of_characteristic(handle_gatt_client_event, connection_handle, &body_sensor_location_characteristic);
214*6104991bSMatthias Ringwald                     break;
215*6104991bSMatthias Ringwald                 default:
216*6104991bSMatthias Ringwald                     break;
217*6104991bSMatthias Ringwald             }
218*6104991bSMatthias Ringwald             break;
219*6104991bSMatthias Ringwald 
220*6104991bSMatthias Ringwald 
221*6104991bSMatthias Ringwald         case TC_W4_SENSOR_LOCATION:
222*6104991bSMatthias Ringwald             switch(hci_event_packet_get_type(packet)){
223*6104991bSMatthias Ringwald                 case GATT_EVENT_CHARACTERISTIC_VALUE_QUERY_RESULT:
224*6104991bSMatthias Ringwald                     body_sensor_location = gatt_event_characteristic_value_query_result_get_value(packet)[0];
225*6104991bSMatthias Ringwald                     printf("Sensor Location: %u\n", body_sensor_location);
226*6104991bSMatthias Ringwald                     state = TC_CONNECTED;
227*6104991bSMatthias Ringwald                     break;
228*6104991bSMatthias Ringwald                 default:
229*6104991bSMatthias Ringwald                     break;
230*6104991bSMatthias Ringwald             }
231*6104991bSMatthias Ringwald             break;
232*6104991bSMatthias Ringwald 
233*6104991bSMatthias Ringwald         case TC_CONNECTED:
234*6104991bSMatthias Ringwald             switch(hci_event_packet_get_type(packet)){
235*6104991bSMatthias Ringwald                 case GATT_EVENT_NOTIFICATION:
236*6104991bSMatthias Ringwald                     if (gatt_event_notification_get_value(packet)[0] & 1){
237*6104991bSMatthias Ringwald                         heart_rate = little_endian_read_16(gatt_event_notification_get_value(packet), 1);
238*6104991bSMatthias Ringwald                     } else {
239*6104991bSMatthias Ringwald                         heart_rate = gatt_event_notification_get_value(packet)[1];
240*6104991bSMatthias Ringwald                     }
241*6104991bSMatthias Ringwald                     sensor_contact = (gatt_event_notification_get_value(packet)[0] >> 1) & 3;
242*6104991bSMatthias Ringwald                     printf("Heart Rate: %3u, Sensor Contact: %s\n", heart_rate, sensor_contact_string[sensor_contact]);
243*6104991bSMatthias Ringwald                     break;
244*6104991bSMatthias Ringwald                 case GATT_EVENT_QUERY_COMPLETE:
245*6104991bSMatthias Ringwald                     break;
246*6104991bSMatthias Ringwald                 case GATT_EVENT_CAN_WRITE_WITHOUT_RESPONSE:
247*6104991bSMatthias Ringwald                     break;
248*6104991bSMatthias Ringwald                 default:
249*6104991bSMatthias Ringwald                     break;
250*6104991bSMatthias Ringwald             }
251*6104991bSMatthias Ringwald             break;
252*6104991bSMatthias Ringwald 
253*6104991bSMatthias Ringwald         default:
254*6104991bSMatthias Ringwald             break;
255*6104991bSMatthias Ringwald     }
256*6104991bSMatthias Ringwald }
257*6104991bSMatthias Ringwald 
258*6104991bSMatthias Ringwald // Either connect to remote specified on command line or start scan for device with Hear Rate Service in advertisement
259*6104991bSMatthias Ringwald static void gatt_heart_rate_client_start(void){
260*6104991bSMatthias Ringwald     if (cmdline_addr_found){
261*6104991bSMatthias Ringwald         printf("Connect to %s\n", bd_addr_to_str(cmdline_addr));
262*6104991bSMatthias Ringwald         state = TC_W4_CONNECT;
263*6104991bSMatthias Ringwald         gap_connect(cmdline_addr, 0);
264*6104991bSMatthias Ringwald     } else {
265*6104991bSMatthias Ringwald         printf("Start scanning!\n");
266*6104991bSMatthias Ringwald         state = TC_W4_SCAN_RESULT;
267*6104991bSMatthias Ringwald         gap_set_scan_parameters(0,0x0030, 0x0030);
268*6104991bSMatthias Ringwald         gap_start_scan();
269*6104991bSMatthias Ringwald     }
270*6104991bSMatthias Ringwald }
271*6104991bSMatthias Ringwald 
272*6104991bSMatthias Ringwald static void hci_event_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){
273*6104991bSMatthias Ringwald     UNUSED(channel);
274*6104991bSMatthias Ringwald     UNUSED(size);
275*6104991bSMatthias Ringwald 
276*6104991bSMatthias Ringwald     if (packet_type != HCI_EVENT_PACKET) return;
277*6104991bSMatthias Ringwald 
278*6104991bSMatthias Ringwald     uint16_t conn_interval;
279*6104991bSMatthias Ringwald     uint8_t event = hci_event_packet_get_type(packet);
280*6104991bSMatthias Ringwald     switch (event) {
281*6104991bSMatthias Ringwald         case BTSTACK_EVENT_STATE:
282*6104991bSMatthias Ringwald             // BTstack activated, get started
283*6104991bSMatthias Ringwald             if (btstack_event_state_get_state(packet) == HCI_STATE_WORKING) {
284*6104991bSMatthias Ringwald                 gatt_heart_rate_client_start();
285*6104991bSMatthias Ringwald             } else {
286*6104991bSMatthias Ringwald                 state = TC_OFF;
287*6104991bSMatthias Ringwald             }
288*6104991bSMatthias Ringwald             break;
289*6104991bSMatthias Ringwald         case GAP_EVENT_ADVERTISING_REPORT:
290*6104991bSMatthias Ringwald             if (state != TC_W4_SCAN_RESULT) return;
291*6104991bSMatthias Ringwald             // check name in advertisement
292*6104991bSMatthias Ringwald             if (!advertisement_report_contains_uuid16(ORG_BLUETOOTH_SERVICE_HEART_RATE, packet)) return;
293*6104991bSMatthias Ringwald             // store address and type
294*6104991bSMatthias Ringwald             gap_event_advertising_report_get_address(packet, le_streamer_addr);
295*6104991bSMatthias Ringwald             le_streamer_addr_type = gap_event_advertising_report_get_address_type(packet);
296*6104991bSMatthias Ringwald             // stop scanning, and connect to the device
297*6104991bSMatthias Ringwald             state = TC_W4_CONNECT;
298*6104991bSMatthias Ringwald             gap_stop_scan();
299*6104991bSMatthias Ringwald             printf("Stop scan. Connect to device with addr %s.\n", bd_addr_to_str(le_streamer_addr));
300*6104991bSMatthias Ringwald             gap_connect(le_streamer_addr,le_streamer_addr_type);
301*6104991bSMatthias Ringwald             break;
302*6104991bSMatthias Ringwald         case HCI_EVENT_LE_META:
303*6104991bSMatthias Ringwald             // wait for connection complete
304*6104991bSMatthias Ringwald             if (hci_event_le_meta_get_subevent_code(packet) !=  HCI_SUBEVENT_LE_CONNECTION_COMPLETE) break;
305*6104991bSMatthias Ringwald             if (state != TC_W4_CONNECT) return;
306*6104991bSMatthias Ringwald             connection_handle = hci_subevent_le_connection_complete_get_connection_handle(packet);
307*6104991bSMatthias Ringwald             // print connection parameters (without using float operations)
308*6104991bSMatthias Ringwald             conn_interval = hci_subevent_le_connection_complete_get_conn_interval(packet);
309*6104991bSMatthias Ringwald             printf("Connection Interval: %u.%02u ms\n", conn_interval * 125 / 100, 25 * (conn_interval & 3));
310*6104991bSMatthias Ringwald             printf("Connection Latency: %u\n", hci_subevent_le_connection_complete_get_conn_latency(packet));
311*6104991bSMatthias Ringwald             // initialize gatt client context with handle, and add it to the list of active clients
312*6104991bSMatthias Ringwald             // query primary services
313*6104991bSMatthias Ringwald             printf("Search for Heart Rate service.\n");
314*6104991bSMatthias Ringwald             state = TC_W4_SERVICE_RESULT;
315*6104991bSMatthias Ringwald             gatt_client_discover_primary_services_by_uuid16(handle_gatt_client_event, connection_handle, ORG_BLUETOOTH_SERVICE_HEART_RATE);
316*6104991bSMatthias Ringwald             break;
317*6104991bSMatthias Ringwald         case HCI_EVENT_DISCONNECTION_COMPLETE:
318*6104991bSMatthias Ringwald             // unregister listener
319*6104991bSMatthias Ringwald             connection_handle = HCI_CON_HANDLE_INVALID;
320*6104991bSMatthias Ringwald             if (listener_registered){
321*6104991bSMatthias Ringwald                 listener_registered = 0;
322*6104991bSMatthias Ringwald                 gatt_client_stop_listening_for_characteristic_value_updates(&notification_listener);
323*6104991bSMatthias Ringwald             }
324*6104991bSMatthias Ringwald             if (cmdline_addr_found){
325*6104991bSMatthias Ringwald                 printf("Disconnected %s\n", bd_addr_to_str(cmdline_addr));
326*6104991bSMatthias Ringwald                 return;
327*6104991bSMatthias Ringwald             }
328*6104991bSMatthias Ringwald             printf("Disconnected %s\n", bd_addr_to_str(le_streamer_addr));
329*6104991bSMatthias Ringwald             if (state == TC_OFF) break;
330*6104991bSMatthias Ringwald             gatt_heart_rate_client_start();
331*6104991bSMatthias Ringwald             break;
332*6104991bSMatthias Ringwald         default:
333*6104991bSMatthias Ringwald             break;
334*6104991bSMatthias Ringwald     }
335*6104991bSMatthias Ringwald }
336*6104991bSMatthias Ringwald 
337*6104991bSMatthias Ringwald #ifdef HAVE_BTSTACK_STDIN
338*6104991bSMatthias Ringwald static void usage(const char *name){
339*6104991bSMatthias Ringwald     fprintf(stderr, "Usage: %s [-a|--address aa:bb:cc:dd:ee:ff]\n", name);
340*6104991bSMatthias Ringwald     fprintf(stderr, "If no argument is provided, GATT Heart Rate Client will start scanning and connect to the first device named 'LE Streamer'.\n");
341*6104991bSMatthias Ringwald     fprintf(stderr, "To connect to a specific device use argument [-a].\n\n");
342*6104991bSMatthias Ringwald }
343*6104991bSMatthias Ringwald #endif
344*6104991bSMatthias Ringwald 
345*6104991bSMatthias Ringwald int btstack_main(int argc, const char * argv[]);
346*6104991bSMatthias Ringwald int btstack_main(int argc, const char * argv[]){
347*6104991bSMatthias Ringwald 
348*6104991bSMatthias Ringwald #ifdef HAVE_BTSTACK_STDIN
349*6104991bSMatthias Ringwald     int arg = 1;
350*6104991bSMatthias Ringwald     cmdline_addr_found = 0;
351*6104991bSMatthias Ringwald 
352*6104991bSMatthias Ringwald     while (arg < argc) {
353*6104991bSMatthias Ringwald         if(!strcmp(argv[arg], "-a") || !strcmp(argv[arg], "--address")){
354*6104991bSMatthias Ringwald             arg++;
355*6104991bSMatthias Ringwald             cmdline_addr_found = sscanf_bd_addr(argv[arg], cmdline_addr);
356*6104991bSMatthias Ringwald             arg++;
357*6104991bSMatthias Ringwald             if (!cmdline_addr_found) exit(1);
358*6104991bSMatthias Ringwald             continue;
359*6104991bSMatthias Ringwald         }
360*6104991bSMatthias Ringwald         usage(argv[0]);
361*6104991bSMatthias Ringwald         return 0;
362*6104991bSMatthias Ringwald     }
363*6104991bSMatthias Ringwald #else
364*6104991bSMatthias Ringwald     (void)argc;
365*6104991bSMatthias Ringwald     (void)argv;
366*6104991bSMatthias Ringwald #endif
367*6104991bSMatthias Ringwald 
368*6104991bSMatthias Ringwald     hci_event_callback_registration.callback = &hci_event_handler;
369*6104991bSMatthias Ringwald     hci_add_event_handler(&hci_event_callback_registration);
370*6104991bSMatthias Ringwald 
371*6104991bSMatthias Ringwald     l2cap_init();
372*6104991bSMatthias Ringwald 
373*6104991bSMatthias Ringwald     gatt_client_init();
374*6104991bSMatthias Ringwald 
375*6104991bSMatthias Ringwald     sm_init();
376*6104991bSMatthias Ringwald     sm_set_io_capabilities(IO_CAPABILITY_NO_INPUT_NO_OUTPUT);
377*6104991bSMatthias Ringwald 
378*6104991bSMatthias Ringwald     // turn on!
379*6104991bSMatthias Ringwald     hci_power_control(HCI_POWER_ON);
380*6104991bSMatthias Ringwald 
381*6104991bSMatthias Ringwald     return 0;
382*6104991bSMatthias Ringwald }
383*6104991bSMatthias Ringwald /* EXAMPLE_END */
384