xref: /btstack/src/ble/gatt-service/device_information_service_client.c (revision eb4dccece89f38c3fa8fb13197f36188f58d954a)
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 #ifdef ENABLE_TESTING_SUPPORT
46 #include <stdio.h>
47 #endif
48 
49 #include "ble/gatt-service/device_information_service_client.h"
50 
51 #include "ble/att_db.h"
52 #include "ble/core.h"
53 #include "ble/gatt_client.h"
54 #include "bluetooth_gatt.h"
55 #include "btstack_debug.h"
56 #include "btstack_event.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 #ifdef ENABLE_TESTING_SUPPORT
67     DEVICE_INFORMATION_SERVICE_CLIENT_STATE_W2_QUERY_CHARACTERISTICS,
68     DEVICE_INFORMATION_SERVICE_CLIENT_STATE_W4_CHARACTERISTIC_RESULT,
69 #endif
70     DEVICE_INFORMATION_SERVICE_CLIENT_STATE_W2_READ_VALUE_OF_CHARACTERISTIC,
71     DEVICE_INFORMATION_SERVICE_CLIENT_STATE_W4_CHARACTERISTIC_VALUE
72 } device_information_service_client_state_t;
73 
74 typedef struct {
75     hci_con_handle_t con_handle;
76     device_information_service_client_state_t  state;
77     btstack_packet_handler_t client_handler;
78 
79     // service
80     uint16_t start_handle;
81     uint16_t end_handle;
82     uint8_t  num_instances;
83 
84     // index of next characteristic to query
85     uint8_t characteristic_index;
86 } device_information_service_client_t;
87 
88 static device_information_service_client_t device_information_service_client;
89 
90 static void handle_gatt_client_event(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size);
91 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);
92 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);
93 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);
94 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);
95 
96 // list of uuids and how they are reported as events
97 static const struct device_information_characteristic {
98     uint16_t uuid;
99     uint8_t  subevent;
100     void (*handle_value)(device_information_service_client_t * client, uint8_t subevent, uint8_t att_status, const uint8_t * value, uint16_t value_len);
101 } device_information_characteristics[] = {
102     {ORG_BLUETOOTH_CHARACTERISTIC_MANUFACTURER_NAME_STRING, GATTSERVICE_SUBEVENT_DEVICE_INFORMATION_MANUFACTURER_NAME, device_information_service_emit_string_value},
103     {ORG_BLUETOOTH_CHARACTERISTIC_MODEL_NUMBER_STRING, GATTSERVICE_SUBEVENT_DEVICE_INFORMATION_MODEL_NUMBER, device_information_service_emit_string_value},
104     {ORG_BLUETOOTH_CHARACTERISTIC_SERIAL_NUMBER_STRING, GATTSERVICE_SUBEVENT_DEVICE_INFORMATION_SERIAL_NUMBER, device_information_service_emit_string_value},
105     {ORG_BLUETOOTH_CHARACTERISTIC_HARDWARE_REVISION_STRING, GATTSERVICE_SUBEVENT_DEVICE_INFORMATION_HARDWARE_REVISION, device_information_service_emit_system_id},
106     {ORG_BLUETOOTH_CHARACTERISTIC_FIRMWARE_REVISION_STRING, GATTSERVICE_SUBEVENT_DEVICE_INFORMATION_FIRMWARE_REVISION, device_information_service_emit_string_value},
107     {ORG_BLUETOOTH_CHARACTERISTIC_SOFTWARE_REVISION_STRING, GATTSERVICE_SUBEVENT_DEVICE_INFORMATION_SOFTWARE_REVISION, device_information_service_emit_string_value},
108 
109     {ORG_BLUETOOTH_CHARACTERISTIC_SYSTEM_ID, GATTSERVICE_SUBEVENT_DEVICE_INFORMATION_SYSTEM_ID, device_information_service_emit_string_value},
110     {ORG_BLUETOOTH_CHARACTERISTIC_IEEE_11073_20601_REGULATORY_CERTIFICATION_DATA_LIST, GATTSERVICE_SUBEVENT_DEVICE_INFORMATION_IEEE_REGULATORY_CERTIFICATION, device_information_service_emit_certification_data_list},
111     {ORG_BLUETOOTH_CHARACTERISTIC_PNP_ID, GATTSERVICE_SUBEVENT_DEVICE_INFORMATION_PNP_ID, device_information_service_emit_pnp_id}
112 };
113 
114 #ifdef ENABLE_TESTING_SUPPORT
115 static struct device_information_characteristic_handles{
116     uint16_t uuid;
117     uint16_t value_handle;
118 } device_information_characteristic_handles[] = {
119     {ORG_BLUETOOTH_CHARACTERISTIC_MANUFACTURER_NAME_STRING, 0},
120     {ORG_BLUETOOTH_CHARACTERISTIC_MODEL_NUMBER_STRING, 0},
121     {ORG_BLUETOOTH_CHARACTERISTIC_SERIAL_NUMBER_STRING, 0},
122     {ORG_BLUETOOTH_CHARACTERISTIC_HARDWARE_REVISION_STRING, 0},
123     {ORG_BLUETOOTH_CHARACTERISTIC_FIRMWARE_REVISION_STRING, 0},
124     {ORG_BLUETOOTH_CHARACTERISTIC_SOFTWARE_REVISION_STRING, 0},
125     {ORG_BLUETOOTH_CHARACTERISTIC_SYSTEM_ID, 0},
126     {ORG_BLUETOOTH_CHARACTERISTIC_IEEE_11073_20601_REGULATORY_CERTIFICATION_DATA_LIST, 0},
127     {ORG_BLUETOOTH_CHARACTERISTIC_PNP_ID, 0}
128 };
129 
130 static void device_information_service_update_handle_for_uuid(uint16_t uuid, uint16_t value_handle){
131     uint8_t i;
132     for (i = 0; i < 9; i++){
133         if (device_information_characteristic_handles[i].uuid == uuid){
134             device_information_characteristic_handles[i].value_handle = value_handle;
135             return;
136         }
137     }
138 }
139 #endif
140 
141 
142 static const uint8_t num_information_fields = sizeof(device_information_characteristics)/sizeof(struct device_information_characteristic);
143 
144 #ifdef ENABLE_TESTING_SUPPORT
145 static char * device_information_characteristic_name(uint16_t uuid){
146     switch (uuid){
147         case ORG_BLUETOOTH_CHARACTERISTIC_MANUFACTURER_NAME_STRING:
148             return "MANUFACTURER_NAME_STRING";
149 
150         case ORG_BLUETOOTH_CHARACTERISTIC_MODEL_NUMBER_STRING:
151             return "MODEL_NUMBER_STRING";
152 
153         case ORG_BLUETOOTH_CHARACTERISTIC_SERIAL_NUMBER_STRING:
154             return "SERIAL_NUMBER_STRING";
155 
156         case ORG_BLUETOOTH_CHARACTERISTIC_HARDWARE_REVISION_STRING:
157             return "HARDWARE_REVISION_STRING";
158 
159         case ORG_BLUETOOTH_CHARACTERISTIC_FIRMWARE_REVISION_STRING:
160             return "FIRMWARE_REVISION_STRING";
161 
162         case ORG_BLUETOOTH_CHARACTERISTIC_SOFTWARE_REVISION_STRING:
163             return "SOFTWARE_REVISION_STRING";
164 
165         case ORG_BLUETOOTH_CHARACTERISTIC_SYSTEM_ID:
166             return "SYSTEM_ID";
167 
168         case ORG_BLUETOOTH_CHARACTERISTIC_IEEE_11073_20601_REGULATORY_CERTIFICATION_DATA_LIST:
169             return "IEEE_11073_20601_REGULATORY_CERTIFICATION_DATA_LIST";
170 
171         case ORG_BLUETOOTH_CHARACTERISTIC_PNP_ID:
172             return "PNP_ID";
173         default:
174             return "UKNOWN";
175     }
176 }
177 #endif
178 static device_information_service_client_t * device_information_service_client_get_client(void){
179     return &device_information_service_client;
180 }
181 
182 static device_information_service_client_t * device_information_service_get_client_for_con_handle(hci_con_handle_t con_handle){
183     if (device_information_service_client.con_handle == con_handle){
184         return &device_information_service_client;
185     }
186     return NULL;
187 }
188 
189 static void device_information_service_finalize_client(device_information_service_client_t * client){
190     client->state = DEVICE_INFORMATION_SERVICE_CLIENT_STATE_IDLE;
191     client->con_handle = HCI_CON_HANDLE_INVALID;
192 }
193 
194 static void device_information_service_emit_query_done(device_information_service_client_t * client, uint8_t att_status){
195     uint8_t event[6];
196     int pos = 0;
197     event[pos++] = HCI_EVENT_GATTSERVICE_META;
198     event[pos++] = sizeof(event) - 2;
199     event[pos++] = GATTSERVICE_SUBEVENT_DEVICE_INFORMATION_DONE;
200     little_endian_store_16(event, pos, client->con_handle);
201     pos += 2;
202     event[pos++] = att_status;
203     (*client->client_handler)(HCI_EVENT_PACKET, 0, event, pos);
204 }
205 
206 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){
207     uint8_t event[6 + DEVICE_INFORMATION_MAX_STRING_LEN + 1];
208     int pos = 0;
209 
210     event[pos++] = HCI_EVENT_GATTSERVICE_META;
211     pos++;
212     event[pos++] = subevent;
213     little_endian_store_16(event, pos, client->con_handle);
214     pos += 2;
215     event[pos++] = att_status;
216 
217     uint16_t bytes_to_copy = btstack_min(value_len, DEVICE_INFORMATION_MAX_STRING_LEN);
218     memcpy((char*)&event[pos], value, bytes_to_copy);
219     pos += bytes_to_copy;
220     event[pos++] = 0;
221 
222     event[1] = pos - 2;
223     (*client->client_handler)(HCI_EVENT_PACKET, 0, event, pos);
224 }
225 
226 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){
227     if (value_len != 8) return;
228 
229     uint8_t event[14];
230     uint16_t pos = 0;
231     event[pos++] = HCI_EVENT_GATTSERVICE_META;
232     event[pos++] = sizeof(event) - 2;
233     event[pos++] = subevent;
234     little_endian_store_16(event, pos, client->con_handle);
235     pos += 2;
236     event[pos++] = att_status;
237     memcpy(event+pos, value, 8);
238     pos += 8;
239 
240     (*client->client_handler)(HCI_EVENT_PACKET, 0, event, pos);
241 }
242 
243 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){
244     if (value_len != 4) return;
245 
246     uint8_t event[10];
247     int pos = 0;
248     event[pos++] = HCI_EVENT_GATTSERVICE_META;
249     event[pos++] = sizeof(event) - 2;
250     event[pos++] = subevent;
251     little_endian_store_16(event, pos, client->con_handle);
252     pos += 2;
253     event[pos++] = att_status;
254     memcpy(event + pos, value, 4);
255     pos += 4;
256 
257     (*client->client_handler)(HCI_EVENT_PACKET, 0, event, pos);
258 }
259 
260 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){
261     if (value_len != 7) return;
262 
263     uint8_t event[13];
264     uint16_t pos = 0;
265     event[pos++] = HCI_EVENT_GATTSERVICE_META;
266     event[pos++] = sizeof(event) - 2;
267     event[pos++] = subevent;
268     little_endian_store_16(event, pos, client->con_handle);
269     pos += 2;
270     event[pos++] = att_status;
271     memcpy(event + pos, value, 7);
272     pos += 7;
273 
274     (*client->client_handler)(HCI_EVENT_PACKET, 0, event, pos);
275 }
276 
277 
278 static void device_information_service_run_for_client(device_information_service_client_t * client){
279     uint8_t att_status;
280 
281     switch (client->state){
282         case DEVICE_INFORMATION_SERVICE_CLIENT_STATE_W2_QUERY_SERVICE:
283             client->state = DEVICE_INFORMATION_SERVICE_CLIENT_STATE_W4_SERVICE_RESULT;
284             att_status = gatt_client_discover_primary_services_by_uuid16(handle_gatt_client_event, client->con_handle, ORG_BLUETOOTH_SERVICE_DEVICE_INFORMATION);
285             // TODO handle status
286             UNUSED(att_status);
287             break;
288 #ifdef ENABLE_TESTING_SUPPORT
289         case DEVICE_INFORMATION_SERVICE_CLIENT_STATE_W2_QUERY_CHARACTERISTICS:
290             client->state = DEVICE_INFORMATION_SERVICE_CLIENT_STATE_W4_CHARACTERISTIC_RESULT;
291             gatt_client_discover_characteristics_for_handle_range_by_uuid16(
292                 &handle_gatt_client_event,
293                 client->con_handle, client->start_handle, client->end_handle,
294                 device_information_characteristics[client->characteristic_index].uuid);
295             break;
296 #endif
297 
298         case DEVICE_INFORMATION_SERVICE_CLIENT_STATE_W2_READ_VALUE_OF_CHARACTERISTIC:
299             client->state = DEVICE_INFORMATION_SERVICE_CLIENT_STATE_W4_CHARACTERISTIC_VALUE;
300 
301  #ifdef ENABLE_TESTING_SUPPORT
302             att_status = gatt_client_read_value_of_characteristic_using_value_handle(
303                 handle_gatt_client_event,
304                 client->con_handle,
305                 device_information_characteristic_handles[client->characteristic_index].value_handle);
306  #else
307             att_status = gatt_client_read_value_of_characteristics_by_uuid16(
308                 handle_gatt_client_event,
309                 client->con_handle, client->start_handle, client->end_handle,
310                 device_information_characteristics[client->characteristic_index].uuid);
311 #endif
312             // TODO handle status
313             UNUSED(att_status);
314             break;
315 
316         default:
317             break;
318     }
319 }
320 
321 static void handle_gatt_client_event(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){
322     UNUSED(packet_type);
323     UNUSED(channel);
324     UNUSED(size);
325 
326     uint8_t att_status;
327     device_information_service_client_t * client = NULL;
328     gatt_client_service_t service;
329 
330 #ifdef ENABLE_TESTING_SUPPORT
331     gatt_client_characteristic_t characteristic;
332 #endif
333 
334     switch(hci_event_packet_get_type(packet)){
335 
336         case GATT_EVENT_SERVICE_QUERY_RESULT:
337             client = device_information_service_get_client_for_con_handle(gatt_event_service_query_result_get_handle(packet));
338             btstack_assert(client != NULL);
339 
340             if (client->state != DEVICE_INFORMATION_SERVICE_CLIENT_STATE_W4_SERVICE_RESULT) {
341                 device_information_service_emit_query_done(client, GATT_CLIENT_IN_WRONG_STATE);
342                 device_information_service_finalize_client(client);
343                 break;
344             }
345 
346             gatt_event_service_query_result_get_service(packet, &service);
347             client->start_handle = service.start_group_handle;
348             client->end_handle = service.end_group_handle;
349 #ifdef ENABLE_TESTING_SUPPORT
350             printf("Device Information Service: start handle 0x%04X, end handle 0x%04X\n", client->start_handle, client->end_handle);
351 #endif
352             client->num_instances++;
353             client->characteristic_index = 0;
354             break;
355 
356 #ifdef ENABLE_TESTING_SUPPORT
357         case GATT_EVENT_CHARACTERISTIC_QUERY_RESULT:
358             client = device_information_service_get_client_for_con_handle(gatt_event_characteristic_query_result_get_handle(packet));
359             btstack_assert(client != NULL);
360             gatt_event_characteristic_query_result_get_characteristic(packet, &characteristic);
361 
362             device_information_service_update_handle_for_uuid(characteristic.uuid16, characteristic.value_handle);
363             printf("Device Information Characteristic %s:  \n    Attribute Handle 0x%04X, Properties 0x%02X, Handle 0x%04X, UUID 0x%04X\n",
364                 device_information_characteristic_name(characteristic.uuid16),
365                 characteristic.start_handle,
366                 characteristic.properties,
367                 characteristic.value_handle, characteristic.uuid16);
368             break;
369 #endif
370         case GATT_EVENT_CHARACTERISTIC_VALUE_QUERY_RESULT:
371             client = device_information_service_get_client_for_con_handle(gatt_event_characteristic_value_query_result_get_handle(packet));
372             btstack_assert(client != NULL);
373 
374 
375             (device_information_characteristics[client->characteristic_index].handle_value(
376                 client, device_information_characteristics[client->characteristic_index].subevent,
377                 ATT_ERROR_SUCCESS,
378                 gatt_event_characteristic_value_query_result_get_value(packet),
379                 gatt_event_characteristic_value_query_result_get_value_length(packet)));
380             break;
381 
382         case GATT_EVENT_QUERY_COMPLETE:
383             client = device_information_service_get_client_for_con_handle(gatt_event_query_complete_get_handle(packet));
384             btstack_assert(client != NULL);
385 
386             att_status = gatt_event_query_complete_get_att_status(packet);
387             switch (client->state){
388                 case DEVICE_INFORMATION_SERVICE_CLIENT_STATE_W4_SERVICE_RESULT:
389                     if (att_status != ATT_ERROR_SUCCESS){
390                         device_information_service_emit_query_done(client, att_status);
391                         device_information_service_finalize_client(client);
392                         break;
393                     }
394 
395                     if (client->num_instances != 1){
396                         device_information_service_emit_query_done(client, ERROR_CODE_UNSUPPORTED_FEATURE_OR_PARAMETER_VALUE);
397                         device_information_service_finalize_client(client);
398                         break;
399                     }
400                     client->characteristic_index = 0;
401 #ifdef ENABLE_TESTING_SUPPORT
402                     client->state = DEVICE_INFORMATION_SERVICE_CLIENT_STATE_W2_QUERY_CHARACTERISTICS;
403 #else
404                     client->state = DEVICE_INFORMATION_SERVICE_CLIENT_STATE_W2_READ_VALUE_OF_CHARACTERISTIC;
405 #endif
406                     break;
407 
408 #ifdef ENABLE_TESTING_SUPPORT
409                     case DEVICE_INFORMATION_SERVICE_CLIENT_STATE_W4_CHARACTERISTIC_RESULT:
410                         // check if there is another characteristic to query
411                         if ((client->characteristic_index + 1) < num_information_fields){
412                             client->characteristic_index++;
413                             client->state = DEVICE_INFORMATION_SERVICE_CLIENT_STATE_W2_QUERY_CHARACTERISTICS;
414                             break;
415                         }
416                         client->characteristic_index = 0;
417                         client->state = DEVICE_INFORMATION_SERVICE_CLIENT_STATE_W2_READ_VALUE_OF_CHARACTERISTIC;
418                         break;
419 #endif
420                 case DEVICE_INFORMATION_SERVICE_CLIENT_STATE_W4_CHARACTERISTIC_VALUE:
421                     if (att_status != ATT_ERROR_SUCCESS){
422                         (device_information_characteristics[client->characteristic_index].handle_value(
423                             client, device_information_characteristics[client->characteristic_index].subevent,
424                             att_status,
425                             gatt_event_characteristic_value_query_result_get_value(packet),
426                             gatt_event_characteristic_value_query_result_get_value_length(packet)));
427                     }
428 
429                     // check if there is another characteristic to query
430                     if ((client->characteristic_index + 1) < num_information_fields){
431                         client->characteristic_index++;
432                         client->state = DEVICE_INFORMATION_SERVICE_CLIENT_STATE_W2_READ_VALUE_OF_CHARACTERISTIC;
433                         break;
434                     }
435                     // we are done with quering all characteristics
436                     device_information_service_emit_query_done(client, ERROR_CODE_SUCCESS);
437                     device_information_service_finalize_client(client);
438                     break;
439 
440                 default:
441                     break;
442             }
443             break;
444         default:
445             break;
446     }
447 
448     if (client != NULL){
449         device_information_service_run_for_client(client);
450     }
451 
452 }
453 
454 uint8_t device_information_service_client_query(hci_con_handle_t con_handle, btstack_packet_handler_t packet_handler){
455     btstack_assert(packet_handler != NULL);
456     device_information_service_client_t * client = device_information_service_client_get_client();
457 
458     if (client->state != DEVICE_INFORMATION_SERVICE_CLIENT_STATE_IDLE){
459         return GATT_CLIENT_IN_WRONG_STATE;
460     }
461 
462     client->con_handle = con_handle;
463     client->client_handler = packet_handler;
464     client->state = DEVICE_INFORMATION_SERVICE_CLIENT_STATE_W2_QUERY_SERVICE;
465     device_information_service_run_for_client(client);
466     return ERROR_CODE_SUCCESS;
467 }
468 
469 
470 void device_information_service_client_init(void){}
471 
472 void device_information_service_client_deinit(void){}
473 
474