xref: /btstack/example/gatt_device_information_query.c (revision 77aad1258144cabf71d1ac0fca4f95457933190e)
1*77aad125SMilanka Ringwald /*
2*77aad125SMilanka Ringwald  * Copyright (C) 2014 BlueKitchen GmbH
3*77aad125SMilanka Ringwald  *
4*77aad125SMilanka Ringwald  * Redistribution and use in source and binary forms, with or without
5*77aad125SMilanka Ringwald  * modification, are permitted provided that the following conditions
6*77aad125SMilanka Ringwald  * are met:
7*77aad125SMilanka Ringwald  *
8*77aad125SMilanka Ringwald  * 1. Redistributions of source code must retain the above copyright
9*77aad125SMilanka Ringwald  *    notice, this list of conditions and the following disclaimer.
10*77aad125SMilanka Ringwald  * 2. Redistributions in binary form must reproduce the above copyright
11*77aad125SMilanka Ringwald  *    notice, this list of conditions and the following disclaimer in the
12*77aad125SMilanka Ringwald  *    documentation and/or other materials provided with the distribution.
13*77aad125SMilanka Ringwald  * 3. Neither the name of the copyright holders nor the names of
14*77aad125SMilanka Ringwald  *    contributors may be used to endorse or promote products derived
15*77aad125SMilanka Ringwald  *    from this software without specific prior written permission.
16*77aad125SMilanka Ringwald  * 4. Any redistribution, use, or modification is done solely for
17*77aad125SMilanka Ringwald  *    personal benefit and not for any commercial purpose or for
18*77aad125SMilanka Ringwald  *    monetary gain.
19*77aad125SMilanka Ringwald  *
20*77aad125SMilanka Ringwald  * THIS SOFTWARE IS PROVIDED BY BLUEKITCHEN GMBH AND CONTRIBUTORS
21*77aad125SMilanka Ringwald  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22*77aad125SMilanka Ringwald  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23*77aad125SMilanka Ringwald  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MATTHIAS
24*77aad125SMilanka Ringwald  * RINGWALD OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25*77aad125SMilanka Ringwald  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26*77aad125SMilanka Ringwald  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
27*77aad125SMilanka Ringwald  * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
28*77aad125SMilanka Ringwald  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
29*77aad125SMilanka Ringwald  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
30*77aad125SMilanka Ringwald  * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31*77aad125SMilanka Ringwald  * SUCH DAMAGE.
32*77aad125SMilanka Ringwald  *
33*77aad125SMilanka Ringwald  * Please inquire about commercial licensing options at
34*77aad125SMilanka Ringwald  * [email protected]
35*77aad125SMilanka Ringwald  *
36*77aad125SMilanka Ringwald  */
37*77aad125SMilanka Ringwald 
38*77aad125SMilanka Ringwald #define BTSTACK_FILE__ "gatt_device_information_query.c"
39*77aad125SMilanka Ringwald 
40*77aad125SMilanka Ringwald // *****************************************************************************
41*77aad125SMilanka Ringwald /* EXAMPLE_START(gatt_device_information_query): GATT Device Information Client
42*77aad125SMilanka Ringwald  *
43*77aad125SMilanka Ringwald  */
44*77aad125SMilanka Ringwald 
45*77aad125SMilanka Ringwald #include <stdint.h>
46*77aad125SMilanka Ringwald #include <stdio.h>
47*77aad125SMilanka Ringwald #include <stdlib.h>
48*77aad125SMilanka Ringwald #include <string.h>
49*77aad125SMilanka Ringwald 
50*77aad125SMilanka Ringwald #include "btstack.h"
51*77aad125SMilanka Ringwald 
52*77aad125SMilanka Ringwald // gatt_device_information_query.gatt contains the declaration of the provided GATT Services + Characteristics
53*77aad125SMilanka Ringwald // gatt_device_information_query.h    contains the binary representation of gatt_device_information_query.gatt
54*77aad125SMilanka Ringwald // it is generated by the build system by calling: $BTSTACK_ROOT/tool/compile_gatt.py gatt_device_information_query.gatt gatt_device_information_query.h
55*77aad125SMilanka Ringwald // it needs to be regenerated when the GATT Database declared in gatt_device_information_query.gatt file is modified
56*77aad125SMilanka Ringwald #include "gatt_device_information_query.h"
57*77aad125SMilanka Ringwald 
58*77aad125SMilanka Ringwald typedef struct advertising_report {
59*77aad125SMilanka Ringwald     uint8_t   type;
60*77aad125SMilanka Ringwald     uint8_t   event_type;
61*77aad125SMilanka Ringwald     uint8_t   address_type;
62*77aad125SMilanka Ringwald     bd_addr_t address;
63*77aad125SMilanka Ringwald     uint8_t   rssi;
64*77aad125SMilanka Ringwald     uint8_t   length;
65*77aad125SMilanka Ringwald     const uint8_t * data;
66*77aad125SMilanka Ringwald } advertising_report_t;
67*77aad125SMilanka Ringwald 
68*77aad125SMilanka Ringwald static enum {
69*77aad125SMilanka Ringwald     APP_STATE_IDLE,
70*77aad125SMilanka Ringwald     APP_STATE_W4_SCAN_RESULT,
71*77aad125SMilanka Ringwald     APP_STATE_W4_CONNECT,
72*77aad125SMilanka Ringwald     APP_STATE_CONNECTED
73*77aad125SMilanka Ringwald } app_state;
74*77aad125SMilanka Ringwald 
75*77aad125SMilanka Ringwald static int blacklist_index = 0;
76*77aad125SMilanka Ringwald static bd_addr_t blacklist[20];
77*77aad125SMilanka Ringwald static advertising_report_t report;
78*77aad125SMilanka Ringwald 
79*77aad125SMilanka Ringwald static hci_con_handle_t connection_handle;
80*77aad125SMilanka Ringwald 
81*77aad125SMilanka Ringwald static bd_addr_t cmdline_addr;
82*77aad125SMilanka Ringwald static int cmdline_addr_found = 0;
83*77aad125SMilanka Ringwald 
84*77aad125SMilanka Ringwald static btstack_packet_callback_registration_t hci_event_callback_registration;
85*77aad125SMilanka Ringwald 
86*77aad125SMilanka Ringwald static int blacklist_size(void){
87*77aad125SMilanka Ringwald     return sizeof(blacklist) / sizeof(bd_addr_t);
88*77aad125SMilanka Ringwald }
89*77aad125SMilanka Ringwald 
90*77aad125SMilanka Ringwald static int blacklist_contains(bd_addr_t addr){
91*77aad125SMilanka Ringwald     int i;
92*77aad125SMilanka Ringwald     for (i=0; i<blacklist_size(); i++){
93*77aad125SMilanka Ringwald         if (bd_addr_cmp(addr, blacklist[i]) == 0) return 1;
94*77aad125SMilanka Ringwald     }
95*77aad125SMilanka Ringwald     return 0;
96*77aad125SMilanka Ringwald }
97*77aad125SMilanka Ringwald 
98*77aad125SMilanka Ringwald static void add_to_blacklist(bd_addr_t addr){
99*77aad125SMilanka Ringwald     printf("%s added to blacklist (no device information service found).\n", bd_addr_to_str(addr));
100*77aad125SMilanka Ringwald     bd_addr_copy(blacklist[blacklist_index], addr);
101*77aad125SMilanka Ringwald     blacklist_index = (blacklist_index + 1) % blacklist_size();
102*77aad125SMilanka Ringwald }
103*77aad125SMilanka Ringwald 
104*77aad125SMilanka Ringwald static void dump_advertising_report(uint8_t *packet){
105*77aad125SMilanka Ringwald     bd_addr_t address;
106*77aad125SMilanka Ringwald     gap_event_advertising_report_get_address(packet, address);
107*77aad125SMilanka Ringwald 
108*77aad125SMilanka Ringwald     printf("    * adv. event: evt-type %u, addr-type %u, addr %s, rssi %u, length adv %u, data: ",
109*77aad125SMilanka Ringwald         gap_event_advertising_report_get_advertising_event_type(packet),
110*77aad125SMilanka Ringwald         gap_event_advertising_report_get_address_type(packet),
111*77aad125SMilanka Ringwald         bd_addr_to_str(address),
112*77aad125SMilanka Ringwald         gap_event_advertising_report_get_rssi(packet),
113*77aad125SMilanka Ringwald         gap_event_advertising_report_get_data_length(packet));
114*77aad125SMilanka Ringwald     printf_hexdump(gap_event_advertising_report_get_data(packet), gap_event_advertising_report_get_data_length(packet));
115*77aad125SMilanka Ringwald 
116*77aad125SMilanka Ringwald }
117*77aad125SMilanka Ringwald 
118*77aad125SMilanka Ringwald static void handle_gatt_client_event(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){
119*77aad125SMilanka Ringwald     UNUSED(packet_type);
120*77aad125SMilanka Ringwald     UNUSED(channel);
121*77aad125SMilanka Ringwald     UNUSED(size);
122*77aad125SMilanka Ringwald 
123*77aad125SMilanka Ringwald 
124*77aad125SMilanka Ringwald     if (hci_event_packet_get_type(packet) != HCI_EVENT_GATTSERVICE_META){
125*77aad125SMilanka Ringwald         return;
126*77aad125SMilanka Ringwald     }
127*77aad125SMilanka Ringwald 
128*77aad125SMilanka Ringwald     switch (hci_event_gattservice_meta_get_subevent_code(packet)){
129*77aad125SMilanka Ringwald 
130*77aad125SMilanka Ringwald         default:
131*77aad125SMilanka Ringwald             break;
132*77aad125SMilanka Ringwald     }
133*77aad125SMilanka Ringwald }
134*77aad125SMilanka Ringwald 
135*77aad125SMilanka Ringwald static void hci_event_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){
136*77aad125SMilanka Ringwald     UNUSED(channel);
137*77aad125SMilanka Ringwald     UNUSED(size);
138*77aad125SMilanka Ringwald 
139*77aad125SMilanka Ringwald     uint8_t status;
140*77aad125SMilanka Ringwald     bd_addr_t address;
141*77aad125SMilanka Ringwald 
142*77aad125SMilanka Ringwald     if (packet_type != HCI_EVENT_PACKET){
143*77aad125SMilanka Ringwald         return;
144*77aad125SMilanka Ringwald     }
145*77aad125SMilanka Ringwald 
146*77aad125SMilanka Ringwald     switch (hci_event_packet_get_type(packet)) {
147*77aad125SMilanka Ringwald         case BTSTACK_EVENT_STATE:
148*77aad125SMilanka Ringwald             // BTstack activated, get started
149*77aad125SMilanka Ringwald             if (btstack_event_state_get_state(packet) != HCI_STATE_WORKING) break;
150*77aad125SMilanka Ringwald             if (cmdline_addr_found){
151*77aad125SMilanka Ringwald                 printf("Connect to %s\n", bd_addr_to_str(cmdline_addr));
152*77aad125SMilanka Ringwald                 app_state = APP_STATE_W4_CONNECT;
153*77aad125SMilanka Ringwald                 gap_connect(cmdline_addr, 0);
154*77aad125SMilanka Ringwald                 break;
155*77aad125SMilanka Ringwald             }
156*77aad125SMilanka Ringwald             printf("Start scanning!\n");
157*77aad125SMilanka Ringwald             app_state = APP_STATE_W4_SCAN_RESULT;
158*77aad125SMilanka Ringwald             gap_set_scan_parameters(0,0x0030, 0x0030);
159*77aad125SMilanka Ringwald             gap_start_scan();
160*77aad125SMilanka Ringwald             break;
161*77aad125SMilanka Ringwald 
162*77aad125SMilanka Ringwald         case GAP_EVENT_ADVERTISING_REPORT:
163*77aad125SMilanka Ringwald             if (app_state != APP_STATE_W4_SCAN_RESULT) return;
164*77aad125SMilanka Ringwald 
165*77aad125SMilanka Ringwald             gap_event_advertising_report_get_address(packet, address);
166*77aad125SMilanka Ringwald             if (blacklist_contains(address)) {
167*77aad125SMilanka Ringwald                 break;
168*77aad125SMilanka Ringwald             }
169*77aad125SMilanka Ringwald             dump_advertising_report(packet);
170*77aad125SMilanka Ringwald 
171*77aad125SMilanka Ringwald             // stop scanning, and connect to the device
172*77aad125SMilanka Ringwald             app_state = APP_STATE_W4_CONNECT;
173*77aad125SMilanka Ringwald             gap_stop_scan();
174*77aad125SMilanka Ringwald             printf("Stop scan. Connect to device with addr %s.\n", bd_addr_to_str(report.address));
175*77aad125SMilanka Ringwald             gap_connect(report.address,report.address_type);
176*77aad125SMilanka Ringwald             break;
177*77aad125SMilanka Ringwald 
178*77aad125SMilanka Ringwald         case HCI_EVENT_LE_META:
179*77aad125SMilanka Ringwald             // wait for connection complete
180*77aad125SMilanka Ringwald             if (hci_event_le_meta_get_subevent_code(packet) !=  HCI_SUBEVENT_LE_CONNECTION_COMPLETE) break;
181*77aad125SMilanka Ringwald             if (app_state != APP_STATE_W4_CONNECT) return;
182*77aad125SMilanka Ringwald             connection_handle = hci_subevent_le_connection_complete_get_connection_handle(packet);
183*77aad125SMilanka Ringwald 
184*77aad125SMilanka Ringwald             status = device_information_service_client_query(connection_handle, handle_gatt_client_event);
185*77aad125SMilanka Ringwald             btstack_assert(status == ERROR_CODE_SUCCESS);
186*77aad125SMilanka Ringwald 
187*77aad125SMilanka Ringwald             app_state = APP_STATE_CONNECTED;
188*77aad125SMilanka Ringwald             printf("Device Information service queried.\n");
189*77aad125SMilanka Ringwald             break;
190*77aad125SMilanka Ringwald 
191*77aad125SMilanka Ringwald         case HCI_EVENT_DISCONNECTION_COMPLETE:
192*77aad125SMilanka Ringwald             connection_handle = HCI_CON_HANDLE_INVALID;
193*77aad125SMilanka Ringwald 
194*77aad125SMilanka Ringwald             if (cmdline_addr_found){
195*77aad125SMilanka Ringwald                 printf("Disconnected %s\n", bd_addr_to_str(cmdline_addr));
196*77aad125SMilanka Ringwald                 return;
197*77aad125SMilanka Ringwald             }
198*77aad125SMilanka Ringwald 
199*77aad125SMilanka Ringwald             printf("Disconnected %s\n", bd_addr_to_str(report.address));
200*77aad125SMilanka Ringwald             printf("Restart scan.\n");
201*77aad125SMilanka Ringwald             app_state = APP_STATE_W4_SCAN_RESULT;
202*77aad125SMilanka Ringwald             gap_start_scan();
203*77aad125SMilanka Ringwald             break;
204*77aad125SMilanka Ringwald         default:
205*77aad125SMilanka Ringwald             break;
206*77aad125SMilanka Ringwald     }
207*77aad125SMilanka Ringwald }
208*77aad125SMilanka Ringwald 
209*77aad125SMilanka Ringwald int btstack_main(int argc, const char * argv[]);
210*77aad125SMilanka Ringwald int btstack_main(int argc, const char * argv[]){
211*77aad125SMilanka Ringwald 
212*77aad125SMilanka Ringwald     // parse address if command line arguments are provided
213*77aad125SMilanka Ringwald     int arg = 1;
214*77aad125SMilanka Ringwald     cmdline_addr_found = 0;
215*77aad125SMilanka Ringwald 
216*77aad125SMilanka Ringwald     while (arg < argc) {
217*77aad125SMilanka Ringwald         if(!strcmp(argv[arg], "-a") || !strcmp(argv[arg], "--address")){
218*77aad125SMilanka Ringwald             arg++;
219*77aad125SMilanka Ringwald             cmdline_addr_found = sscanf_bd_addr(argv[arg], cmdline_addr);
220*77aad125SMilanka Ringwald             arg++;
221*77aad125SMilanka Ringwald             if (!cmdline_addr_found) exit(1);
222*77aad125SMilanka Ringwald             continue;
223*77aad125SMilanka Ringwald         }
224*77aad125SMilanka Ringwald         fprintf(stderr, "\nUsage: %s [-a|--address aa:bb:cc:dd:ee:ff]\n", argv[0]);
225*77aad125SMilanka Ringwald         fprintf(stderr, "If no argument is provided, GATT browser will start scanning and connect to the first found device.\nTo connect to a specific device use argument [-a].\n\n");
226*77aad125SMilanka Ringwald         return 0;
227*77aad125SMilanka Ringwald     }
228*77aad125SMilanka Ringwald     (void)argv;
229*77aad125SMilanka Ringwald 
230*77aad125SMilanka Ringwald     l2cap_init();
231*77aad125SMilanka Ringwald 
232*77aad125SMilanka Ringwald     // setup ATT server - only needed if LE Peripheral does ATT queries on its own, e.g. Android phones
233*77aad125SMilanka Ringwald     att_server_init(profile_data, NULL, NULL);
234*77aad125SMilanka Ringwald 
235*77aad125SMilanka Ringwald     // GATT Client setup
236*77aad125SMilanka Ringwald     gatt_client_init();
237*77aad125SMilanka Ringwald     device_information_service_client_init();
238*77aad125SMilanka Ringwald 
239*77aad125SMilanka Ringwald     sm_init();
240*77aad125SMilanka Ringwald     sm_set_io_capabilities(IO_CAPABILITY_NO_INPUT_NO_OUTPUT);
241*77aad125SMilanka Ringwald 
242*77aad125SMilanka Ringwald     hci_event_callback_registration.callback = &hci_event_handler;
243*77aad125SMilanka Ringwald     hci_add_event_handler(&hci_event_callback_registration);
244*77aad125SMilanka Ringwald 
245*77aad125SMilanka Ringwald     app_state = APP_STATE_IDLE;
246*77aad125SMilanka Ringwald 
247*77aad125SMilanka Ringwald     // turn on!
248*77aad125SMilanka Ringwald     hci_power_control(HCI_POWER_ON);
249*77aad125SMilanka Ringwald 
250*77aad125SMilanka Ringwald     return 0;
251*77aad125SMilanka Ringwald }
252*77aad125SMilanka Ringwald 
253*77aad125SMilanka Ringwald /* EXAMPLE_END */
254*77aad125SMilanka Ringwald 
255*77aad125SMilanka Ringwald 
256