xref: /btstack/src/ble/gatt-service/device_information_service_client.c (revision 98451c7b102094e15e0a72ca2f7098d91aed2017)
1 /*
2  * Copyright (C) 2021 BlueKitchen GmbH
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  *
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  * 3. Neither the name of the copyright holders nor the names of
14  *    contributors may be used to endorse or promote products derived
15  *    from this software without specific prior written permission.
16  * 4. Any redistribution, use, or modification is done solely for
17  *    personal benefit and not for any commercial purpose or for
18  *    monetary gain.
19  *
20  * THIS SOFTWARE IS PROVIDED BY BLUEKITCHEN GMBH AND CONTRIBUTORS
21  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MATTHIAS
24  * RINGWALD OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
27  * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
28  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
29  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
30  * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31  * SUCH DAMAGE.
32  *
33  * Please inquire about commercial licensing options at
34  * [email protected]
35  *
36  */
37 
38 #define BTSTACK_FILE__ "device_information_service_client.c"
39 
40 #include "btstack_config.h"
41 
42 #include <stdint.h>
43 #include <string.h>
44 
45 
46 #include "ble/gatt-service/device_information_service_client.h"
47 
48 #include "btstack_memory.h"
49 #include "ble/att_db.h"
50 #include "ble/core.h"
51 #include "ble/gatt_client.h"
52 #include "ble/sm.h"
53 #include "bluetooth_gatt.h"
54 #include "btstack_debug.h"
55 #include "btstack_event.h"
56 #include "btstack_run_loop.h"
57 #include "gap.h"
58 
59 #define DEVICE_INFORMATION_MAX_STRING_LEN 32
60 
61 
62 typedef enum {
63     DEVICE_INFORMATION_SERVICE_CLIENT_STATE_IDLE,
64     DEVICE_INFORMATION_SERVICE_CLIENT_STATE_W2_QUERY_SERVICE,
65     DEVICE_INFORMATION_SERVICE_CLIENT_STATE_W4_SERVICE_RESULT,
66     DEVICE_INFORMATION_CLIENT_STATE_W4_CHARACTERISTIC_RESULT
67 } device_information_service_client_state_t;
68 
69 typedef struct {
70     hci_con_handle_t con_handle;
71     device_information_service_client_state_t  state;
72     btstack_packet_handler_t client_handler;
73 
74     // service
75     uint16_t start_handle;
76     uint16_t end_handle;
77     uint8_t  num_instances;
78 
79     // index of next characteristic to query
80     uint8_t characteristic_index;
81 } device_information_service_client_t;
82 
83 static device_information_service_client_t device_information_service_client;
84 
85 static void handle_gatt_client_event(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size);
86 static void device_information_service_emit_string_value(device_information_service_client_t * client, uint8_t subevent, uint8_t att_status, const uint8_t * value, uint16_t value_len);
87 static void device_information_service_emit_system_id(device_information_service_client_t * client, uint8_t subevent, uint8_t att_status, const uint8_t * value, uint16_t value_len);
88 static void device_information_service_emit_certification_data_list(device_information_service_client_t * client, uint8_t subevent, uint8_t att_status, const uint8_t * value, uint16_t value_len);
89 static void device_information_service_emit_pnp_id(device_information_service_client_t * client, uint8_t subevent, uint8_t att_status, const uint8_t * value, uint16_t value_len);
90 
91 // list of uuids and how they are reported as events
92 static struct device_information_characteristic {
93     uint16_t uuid;
94     uint8_t  subevent;
95     void (*handle_value)(device_information_service_client_t * client, uint8_t subevent, uint8_t att_status, const uint8_t * value, uint16_t value_len);
96 } device_information_characteristics[] = {
97     {ORG_BLUETOOTH_CHARACTERISTIC_MANUFACTURER_NAME_STRING, GATTSERVICE_SUBEVENT_DEVICE_INFORMATION_MANUFACTURER_NAME, device_information_service_emit_string_value},
98     {ORG_BLUETOOTH_CHARACTERISTIC_MODEL_NUMBER_STRING, GATTSERVICE_SUBEVENT_DEVICE_INFORMATION_MODEL_NUMBER, device_information_service_emit_string_value},
99     {ORG_BLUETOOTH_CHARACTERISTIC_SERIAL_NUMBER_STRING, GATTSERVICE_SUBEVENT_DEVICE_INFORMATION_SERIAL_NUMBER, device_information_service_emit_string_value},
100     {ORG_BLUETOOTH_CHARACTERISTIC_HARDWARE_REVISION_STRING, GATTSERVICE_SUBEVENT_DEVICE_INFORMATION_HARDWARE_REVISION, device_information_service_emit_system_id},
101     {ORG_BLUETOOTH_CHARACTERISTIC_FIRMWARE_REVISION_STRING, GATTSERVICE_SUBEVENT_DEVICE_INFORMATION_FIRMWARE_REVISION, device_information_service_emit_string_value},
102     {ORG_BLUETOOTH_CHARACTERISTIC_SOFTWARE_REVISION_STRING, GATTSERVICE_SUBEVENT_DEVICE_INFORMATION_SOFTWARE_REVISION, device_information_service_emit_string_value},
103 
104     {ORG_BLUETOOTH_CHARACTERISTIC_SYSTEM_ID, GATTSERVICE_SUBEVENT_DEVICE_INFORMATION_SYSTEM_ID, device_information_service_emit_string_value},
105     {ORG_BLUETOOTH_CHARACTERISTIC_IEEE_11073_20601_REGULATORY_CERTIFICATION_DATA_LIST, GATTSERVICE_SUBEVENT_DEVICE_INFORMATION_IEEE_REGULATORY_CERTIFICATION, device_information_service_emit_certification_data_list},
106     {ORG_BLUETOOTH_CHARACTERISTIC_PNP_ID, GATTSERVICE_SUBEVENT_DEVICE_INFORMATION_PNP_ID, device_information_service_emit_pnp_id}
107 };
108 
109 static const uint8_t num_information_fields = sizeof(device_information_characteristics)/sizeof(struct device_information_characteristic);
110 
111 static device_information_service_client_t * device_information_service_client_get_client(void){
112     return &device_information_service_client;
113 }
114 
115 static device_information_service_client_t * device_information_service_get_client_for_con_handle(hci_con_handle_t con_handle){
116     if (device_information_service_client.con_handle == con_handle){
117         return &device_information_service_client;
118     }
119     return NULL;
120 }
121 
122 static void device_information_service_finalize_client(device_information_service_client_t * client){
123     client->state = DEVICE_INFORMATION_SERVICE_CLIENT_STATE_IDLE;
124     client->con_handle = HCI_CON_HANDLE_INVALID;
125 }
126 
127 static void device_information_service_emit_query_done(device_information_service_client_t * client, uint8_t att_status){
128     uint8_t event[6];
129     int pos = 0;
130     event[pos++] = HCI_EVENT_GATTSERVICE_META;
131     event[pos++] = sizeof(event) - 2;
132     event[pos++] = GATTSERVICE_SUBEVENT_DEVICE_INFORMATION_DONE;
133     little_endian_store_16(event, pos, client->con_handle);
134     pos += 2;
135     event[pos++] = att_status;
136     (*client->client_handler)(HCI_EVENT_PACKET, 0, event, pos);
137 }
138 
139 static void device_information_service_emit_string_value(device_information_service_client_t * client, uint8_t subevent, uint8_t att_status, const uint8_t * value, uint16_t value_len){
140     uint8_t event[6 + DEVICE_INFORMATION_MAX_STRING_LEN + 1];
141     int pos = 0;
142 
143     event[pos++] = HCI_EVENT_GATTSERVICE_META;
144     pos++;
145     event[pos++] = subevent;
146     little_endian_store_16(event, pos, client->con_handle);
147     pos += 2;
148     event[pos++] = att_status;
149 
150     uint16_t bytes_to_copy = btstack_min(value_len, DEVICE_INFORMATION_MAX_STRING_LEN);
151     memcpy((char*)&event[pos], value, bytes_to_copy);
152     pos += bytes_to_copy;
153     event[pos++] = 0;
154 
155     event[2] = pos - 2;
156     (*client->client_handler)(HCI_EVENT_PACKET, 0, event, pos);
157 }
158 
159 static void device_information_service_emit_system_id(device_information_service_client_t * client, uint8_t subevent, uint8_t att_status, const uint8_t * value, uint16_t value_len){
160     if (value_len != 8) return;
161 
162     uint8_t event[14];
163     uint16_t pos = 0;
164     event[pos++] = HCI_EVENT_GATTSERVICE_META;
165     event[pos++] = sizeof(event) - 2;
166     event[pos++] = subevent;
167     little_endian_store_16(event, pos, client->con_handle);
168     pos += 2;
169     event[pos++] = att_status;
170     memcpy(event+pos, value, 8);
171     pos += 8;
172 
173     (*client->client_handler)(HCI_EVENT_PACKET, 0, event, pos);
174 }
175 
176 static void device_information_service_emit_certification_data_list(device_information_service_client_t * client, uint8_t subevent, uint8_t att_status, const uint8_t * value, uint16_t value_len){
177     if (value_len != 4) return;
178 
179     uint8_t event[10];
180     int pos = 0;
181     event[pos++] = HCI_EVENT_GATTSERVICE_META;
182     event[pos++] = sizeof(event) - 2;
183     event[pos++] = subevent;
184     little_endian_store_16(event, pos, client->con_handle);
185     pos += 2;
186     event[pos++] = att_status;
187     memcpy(event + pos, value, 4);
188     pos += 4;
189 
190     (*client->client_handler)(HCI_EVENT_PACKET, 0, event, pos);
191 }
192 
193 static void device_information_service_emit_pnp_id(device_information_service_client_t * client, uint8_t subevent, uint8_t att_status, const uint8_t * value, uint16_t value_len){
194     if (value_len != 7) return;
195 
196     uint8_t event[13];
197     uint16_t pos = 0;
198     event[pos++] = HCI_EVENT_GATTSERVICE_META;
199     event[pos++] = sizeof(event) - 2;
200     event[pos++] = subevent;
201     little_endian_store_16(event, pos, client->con_handle);
202     pos += 2;
203     event[pos++] = att_status;
204     memcpy(event + pos, value, 7);
205     pos += 7;
206 
207     (*client->client_handler)(HCI_EVENT_PACKET, 0, event, pos);
208 }
209 
210 
211 static void device_information_service_run_for_client(device_information_service_client_t * client){
212     uint8_t att_status;
213 
214     switch (client->state){
215         case DEVICE_INFORMATION_SERVICE_CLIENT_STATE_W2_QUERY_SERVICE:
216             client->state = DEVICE_INFORMATION_SERVICE_CLIENT_STATE_W4_SERVICE_RESULT;
217             att_status = gatt_client_discover_primary_services_by_uuid16(handle_gatt_client_event, client->con_handle, ORG_BLUETOOTH_SERVICE_DEVICE_INFORMATION);
218             // TODO handle status
219             UNUSED(att_status);
220             break;
221 
222         case DEVICE_INFORMATION_CLIENT_STATE_W4_CHARACTERISTIC_RESULT:
223             if (client->characteristic_index < num_information_fields){
224                 att_status = gatt_client_read_value_of_characteristics_by_uuid16(
225                     handle_gatt_client_event,
226                     client->con_handle, client->start_handle, client->end_handle,
227                     device_information_characteristics[client->characteristic_index].uuid);
228                 // TODO handle status
229                 UNUSED(att_status);
230             }
231             break;
232 
233         default:
234             break;
235     }
236 }
237 
238 static void handle_gatt_client_event(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){
239     UNUSED(packet_type);
240     UNUSED(channel);
241     UNUSED(size);
242 
243     uint8_t att_status;
244     device_information_service_client_t * client;
245     gatt_client_service_t service;
246 
247     switch(hci_event_packet_get_type(packet)){
248 
249         case GATT_EVENT_SERVICE_QUERY_RESULT:
250             client = device_information_service_get_client_for_con_handle(gatt_event_service_query_result_get_handle(packet));
251             btstack_assert(client != NULL);
252 
253             if (client->state != DEVICE_INFORMATION_SERVICE_CLIENT_STATE_W4_SERVICE_RESULT) {
254                 device_information_service_emit_query_done(client, GATT_CLIENT_IN_WRONG_STATE);
255                 device_information_service_finalize_client(client);
256                 break;
257             }
258 
259             gatt_event_service_query_result_get_service(packet, &service);
260             client->start_handle = service.start_group_handle;
261             client->end_handle = service.end_group_handle;
262             client->num_instances++;
263             client->characteristic_index = 0;
264             break;
265 
266         case GATT_EVENT_CHARACTERISTIC_VALUE_QUERY_RESULT:
267             client = device_information_service_get_client_for_con_handle(gatt_event_characteristic_value_query_result_get_handle(packet));
268             btstack_assert(client != NULL);
269 
270             (device_information_characteristics[client->characteristic_index].handle_value(
271                 client, device_information_characteristics[client->characteristic_index].subevent,
272                 ATT_ERROR_SUCCESS,
273                 gatt_event_characteristic_value_query_result_get_value(packet),
274                 gatt_event_characteristic_value_query_result_get_value_length(packet)));
275             break;
276 
277         case GATT_EVENT_QUERY_COMPLETE:
278             client = device_information_service_get_client_for_con_handle(gatt_event_query_complete_get_handle(packet));
279             btstack_assert(client != NULL);
280 
281             att_status = gatt_event_query_complete_get_att_status(packet);
282             switch (client->state){
283                 case DEVICE_INFORMATION_SERVICE_CLIENT_STATE_W4_SERVICE_RESULT:
284                     if (att_status != ATT_ERROR_SUCCESS){
285                         device_information_service_emit_query_done(client, att_status);
286                         device_information_service_finalize_client(client);
287                         break;
288                     }
289 
290                     if (client->num_instances != 1){
291                         device_information_service_emit_query_done(client, ERROR_CODE_UNSUPPORTED_FEATURE_OR_PARAMETER_VALUE);
292                         device_information_service_finalize_client(client);
293                         break;
294                     }
295 
296                     client->state = DEVICE_INFORMATION_CLIENT_STATE_W4_CHARACTERISTIC_RESULT;
297                     device_information_service_run_for_client(client);
298                     break;
299 
300                 case DEVICE_INFORMATION_CLIENT_STATE_W4_CHARACTERISTIC_RESULT:
301                     if (att_status != ATT_ERROR_SUCCESS){
302                         (device_information_characteristics[client->characteristic_index].handle_value(
303                             client, device_information_characteristics[client->characteristic_index].subevent,
304                             att_status,
305                             gatt_event_characteristic_value_query_result_get_value(packet),
306                             gatt_event_characteristic_value_query_result_get_value_length(packet)));
307                     }
308 
309                     // check if there is another characteristic to query
310                     if (client->characteristic_index < num_information_fields){
311                         client->characteristic_index++;
312                         device_information_service_run_for_client(client);
313                         break;
314                     }
315                     // we are done with quering all characteristics
316                     device_information_service_emit_query_done(client, ERROR_CODE_SUCCESS);
317                     device_information_service_finalize_client(client);
318                     break;
319 
320                 default:
321                     break;
322             }
323             break;
324         default:
325             break;
326     }
327 
328 }
329 
330 uint8_t device_information_service_client_query(hci_con_handle_t con_handle, btstack_packet_handler_t packet_handler){
331     btstack_assert(packet_handler != NULL);
332     device_information_service_client_t * client = device_information_service_client_get_client();
333 
334     if (client->state != DEVICE_INFORMATION_SERVICE_CLIENT_STATE_IDLE){
335         return GATT_CLIENT_IN_WRONG_STATE;
336     }
337 
338     client->con_handle = con_handle;
339     client->client_handler = packet_handler;
340     client->state = DEVICE_INFORMATION_SERVICE_CLIENT_STATE_W2_QUERY_SERVICE;
341     device_information_service_run_for_client(client);
342     return ERROR_CODE_SUCCESS;
343 }
344 
345 
346 void device_information_service_client_init(void){}
347 
348 void device_information_service_client_deinit(void){}
349 
350