xref: /btstack/src/ble/gatt-service/device_information_service_client.c (revision 09fa6397dc3c85798acbc6200f06f2a2a3ff29c0)
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 "btstack_memory.h"
52 #include "ble/att_db.h"
53 #include "ble/core.h"
54 #include "ble/gatt_client.h"
55 #include "ble/sm.h"
56 #include "bluetooth_gatt.h"
57 #include "btstack_debug.h"
58 #include "btstack_event.h"
59 #include "btstack_run_loop.h"
60 #include "gap.h"
61 
62 #define DEVICE_INFORMATION_MAX_STRING_LEN 32
63 
64 
65 typedef enum {
66     DEVICE_INFORMATION_SERVICE_CLIENT_STATE_IDLE,
67     DEVICE_INFORMATION_SERVICE_CLIENT_STATE_W2_QUERY_SERVICE,
68     DEVICE_INFORMATION_SERVICE_CLIENT_STATE_W4_SERVICE_RESULT,
69     DEVICE_INFORMATION_CLIENT_STATE_W4_CHARACTERISTIC_RESULT
70 } device_information_service_client_state_t;
71 
72 typedef struct {
73     hci_con_handle_t con_handle;
74     device_information_service_client_state_t  state;
75     btstack_packet_handler_t client_handler;
76 
77     // service
78     uint16_t start_handle;
79     uint16_t end_handle;
80     uint8_t  num_instances;
81 
82     // index of next characteristic to query
83     uint8_t characteristic_index;
84 } device_information_service_client_t;
85 
86 static device_information_service_client_t device_information_service_client;
87 
88 static void handle_gatt_client_event(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size);
89 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);
90 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);
91 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);
92 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);
93 
94 // list of uuids and how they are reported as events
95 static struct device_information_characteristic {
96     uint16_t uuid;
97     uint8_t  subevent;
98     void (*handle_value)(device_information_service_client_t * client, uint8_t subevent, uint8_t att_status, const uint8_t * value, uint16_t value_len);
99 } device_information_characteristics[] = {
100     {ORG_BLUETOOTH_CHARACTERISTIC_MANUFACTURER_NAME_STRING, GATTSERVICE_SUBEVENT_DEVICE_INFORMATION_MANUFACTURER_NAME, device_information_service_emit_string_value},
101     {ORG_BLUETOOTH_CHARACTERISTIC_MODEL_NUMBER_STRING, GATTSERVICE_SUBEVENT_DEVICE_INFORMATION_MODEL_NUMBER, device_information_service_emit_string_value},
102     {ORG_BLUETOOTH_CHARACTERISTIC_SERIAL_NUMBER_STRING, GATTSERVICE_SUBEVENT_DEVICE_INFORMATION_SERIAL_NUMBER, device_information_service_emit_string_value},
103     {ORG_BLUETOOTH_CHARACTERISTIC_HARDWARE_REVISION_STRING, GATTSERVICE_SUBEVENT_DEVICE_INFORMATION_HARDWARE_REVISION, device_information_service_emit_system_id},
104     {ORG_BLUETOOTH_CHARACTERISTIC_FIRMWARE_REVISION_STRING, GATTSERVICE_SUBEVENT_DEVICE_INFORMATION_FIRMWARE_REVISION, device_information_service_emit_string_value},
105     {ORG_BLUETOOTH_CHARACTERISTIC_SOFTWARE_REVISION_STRING, GATTSERVICE_SUBEVENT_DEVICE_INFORMATION_SOFTWARE_REVISION, device_information_service_emit_string_value},
106 
107     {ORG_BLUETOOTH_CHARACTERISTIC_SYSTEM_ID, GATTSERVICE_SUBEVENT_DEVICE_INFORMATION_SYSTEM_ID, device_information_service_emit_string_value},
108     {ORG_BLUETOOTH_CHARACTERISTIC_IEEE_11073_20601_REGULATORY_CERTIFICATION_DATA_LIST, GATTSERVICE_SUBEVENT_DEVICE_INFORMATION_IEEE_REGULATORY_CERTIFICATION, device_information_service_emit_certification_data_list},
109     {ORG_BLUETOOTH_CHARACTERISTIC_PNP_ID, GATTSERVICE_SUBEVENT_DEVICE_INFORMATION_PNP_ID, device_information_service_emit_pnp_id}
110 };
111 
112 static const uint8_t num_information_fields = sizeof(device_information_characteristics)/sizeof(struct device_information_characteristic);
113 
114 static device_information_service_client_t * device_information_service_client_get_client(void){
115     return &device_information_service_client;
116 }
117 
118 static device_information_service_client_t * device_information_service_get_client_for_con_handle(hci_con_handle_t con_handle){
119     if (device_information_service_client.con_handle == con_handle){
120         return &device_information_service_client;
121     }
122     return NULL;
123 }
124 
125 static void device_information_service_finalize_client(device_information_service_client_t * client){
126     client->state = DEVICE_INFORMATION_SERVICE_CLIENT_STATE_IDLE;
127     client->con_handle = HCI_CON_HANDLE_INVALID;
128 }
129 
130 static void device_information_service_emit_query_done(device_information_service_client_t * client, uint8_t att_status){
131     uint8_t event[6];
132     int pos = 0;
133     event[pos++] = HCI_EVENT_GATTSERVICE_META;
134     event[pos++] = sizeof(event) - 2;
135     event[pos++] = GATTSERVICE_SUBEVENT_DEVICE_INFORMATION_DONE;
136     little_endian_store_16(event, pos, client->con_handle);
137     pos += 2;
138     event[pos++] = att_status;
139     (*client->client_handler)(HCI_EVENT_PACKET, 0, event, pos);
140 }
141 
142 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){
143     uint8_t event[6 + DEVICE_INFORMATION_MAX_STRING_LEN + 1];
144     int pos = 0;
145 
146     event[pos++] = HCI_EVENT_GATTSERVICE_META;
147     pos++;
148     event[pos++] = subevent;
149     little_endian_store_16(event, pos, client->con_handle);
150     pos += 2;
151     event[pos++] = att_status;
152 
153     uint16_t bytes_to_copy = btstack_min(value_len, DEVICE_INFORMATION_MAX_STRING_LEN);
154     memcpy((char*)&event[pos], value, bytes_to_copy);
155     pos += bytes_to_copy;
156     event[pos++] = 0;
157 
158     event[2] = pos - 2;
159     (*client->client_handler)(HCI_EVENT_PACKET, 0, event, pos);
160 }
161 
162 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){
163     if (value_len != 8) return;
164 
165     uint8_t event[14];
166     uint16_t pos = 0;
167     event[pos++] = HCI_EVENT_GATTSERVICE_META;
168     event[pos++] = sizeof(event) - 2;
169     event[pos++] = subevent;
170     little_endian_store_16(event, pos, client->con_handle);
171     pos += 2;
172     event[pos++] = att_status;
173     memcpy(event+pos, value, 8);
174     pos += 8;
175 
176     (*client->client_handler)(HCI_EVENT_PACKET, 0, event, pos);
177 }
178 
179 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){
180     if (value_len != 4) return;
181 
182     uint8_t event[10];
183     int pos = 0;
184     event[pos++] = HCI_EVENT_GATTSERVICE_META;
185     event[pos++] = sizeof(event) - 2;
186     event[pos++] = subevent;
187     little_endian_store_16(event, pos, client->con_handle);
188     pos += 2;
189     event[pos++] = att_status;
190     memcpy(event + pos, value, 4);
191     pos += 4;
192 
193     (*client->client_handler)(HCI_EVENT_PACKET, 0, event, pos);
194 }
195 
196 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){
197     if (value_len != 7) return;
198 
199     uint8_t event[13];
200     uint16_t pos = 0;
201     event[pos++] = HCI_EVENT_GATTSERVICE_META;
202     event[pos++] = sizeof(event) - 2;
203     event[pos++] = subevent;
204     little_endian_store_16(event, pos, client->con_handle);
205     pos += 2;
206     event[pos++] = att_status;
207     memcpy(event + pos, value, 7);
208     pos += 7;
209 
210     (*client->client_handler)(HCI_EVENT_PACKET, 0, event, pos);
211 }
212 
213 
214 static void device_information_service_run_for_client(device_information_service_client_t * client){
215     uint8_t att_status;
216 
217     switch (client->state){
218         case DEVICE_INFORMATION_SERVICE_CLIENT_STATE_W2_QUERY_SERVICE:
219             client->state = DEVICE_INFORMATION_SERVICE_CLIENT_STATE_W4_SERVICE_RESULT;
220             att_status = gatt_client_discover_primary_services_by_uuid16(handle_gatt_client_event, client->con_handle, ORG_BLUETOOTH_SERVICE_DEVICE_INFORMATION);
221             // TODO handle status
222             UNUSED(att_status);
223             break;
224 
225         case DEVICE_INFORMATION_CLIENT_STATE_W4_CHARACTERISTIC_RESULT:
226             if (client->characteristic_index < num_information_fields){
227                 att_status = gatt_client_read_value_of_characteristics_by_uuid16(
228                     handle_gatt_client_event,
229                     client->con_handle, client->start_handle, client->end_handle,
230                     device_information_characteristics[client->characteristic_index].uuid);
231                 // TODO handle status
232                 UNUSED(att_status);
233             }
234             break;
235 
236         default:
237             break;
238     }
239 }
240 
241 static void handle_gatt_client_event(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){
242     UNUSED(packet_type);
243     UNUSED(channel);
244     UNUSED(size);
245 
246     uint8_t att_status;
247     device_information_service_client_t * client;
248     gatt_client_service_t service;
249 
250     switch(hci_event_packet_get_type(packet)){
251 
252         case GATT_EVENT_SERVICE_QUERY_RESULT:
253             client = device_information_service_get_client_for_con_handle(gatt_event_service_query_result_get_handle(packet));
254             btstack_assert(client != NULL);
255 
256             if (client->state != DEVICE_INFORMATION_SERVICE_CLIENT_STATE_W4_SERVICE_RESULT) {
257                 device_information_service_emit_query_done(client, GATT_CLIENT_IN_WRONG_STATE);
258                 device_information_service_finalize_client(client);
259                 break;
260             }
261 
262             gatt_event_service_query_result_get_service(packet, &service);
263             client->start_handle = service.start_group_handle;
264             client->end_handle = service.end_group_handle;
265 #ifdef ENABLE_TESTING_SUPPORT
266             printf("Device Information Service: start handle 0x%04X, end handle 0x%04X\n", client->start_handle, client->end_handle);
267 #endif
268             client->num_instances++;
269             client->characteristic_index = 0;
270             break;
271 
272         case GATT_EVENT_CHARACTERISTIC_VALUE_QUERY_RESULT:
273             client = device_information_service_get_client_for_con_handle(gatt_event_characteristic_value_query_result_get_handle(packet));
274             btstack_assert(client != NULL);
275 
276             (device_information_characteristics[client->characteristic_index].handle_value(
277                 client, device_information_characteristics[client->characteristic_index].subevent,
278                 ATT_ERROR_SUCCESS,
279                 gatt_event_characteristic_value_query_result_get_value(packet),
280                 gatt_event_characteristic_value_query_result_get_value_length(packet)));
281             break;
282 
283         case GATT_EVENT_QUERY_COMPLETE:
284             client = device_information_service_get_client_for_con_handle(gatt_event_query_complete_get_handle(packet));
285             btstack_assert(client != NULL);
286 
287             att_status = gatt_event_query_complete_get_att_status(packet);
288             switch (client->state){
289                 case DEVICE_INFORMATION_SERVICE_CLIENT_STATE_W4_SERVICE_RESULT:
290                     if (att_status != ATT_ERROR_SUCCESS){
291                         device_information_service_emit_query_done(client, att_status);
292                         device_information_service_finalize_client(client);
293                         break;
294                     }
295 
296                     if (client->num_instances != 1){
297                         device_information_service_emit_query_done(client, ERROR_CODE_UNSUPPORTED_FEATURE_OR_PARAMETER_VALUE);
298                         device_information_service_finalize_client(client);
299                         break;
300                     }
301 
302                     client->state = DEVICE_INFORMATION_CLIENT_STATE_W4_CHARACTERISTIC_RESULT;
303                     device_information_service_run_for_client(client);
304                     break;
305 
306                 case DEVICE_INFORMATION_CLIENT_STATE_W4_CHARACTERISTIC_RESULT:
307                     if (att_status != ATT_ERROR_SUCCESS){
308                         (device_information_characteristics[client->characteristic_index].handle_value(
309                             client, device_information_characteristics[client->characteristic_index].subevent,
310                             att_status,
311                             gatt_event_characteristic_value_query_result_get_value(packet),
312                             gatt_event_characteristic_value_query_result_get_value_length(packet)));
313                     }
314 
315                     // check if there is another characteristic to query
316                     if (client->characteristic_index < num_information_fields){
317                         client->characteristic_index++;
318                         device_information_service_run_for_client(client);
319                         break;
320                     }
321                     // we are done with quering all characteristics
322                     device_information_service_emit_query_done(client, ERROR_CODE_SUCCESS);
323                     device_information_service_finalize_client(client);
324                     break;
325 
326                 default:
327                     break;
328             }
329             break;
330         default:
331             break;
332     }
333 
334 }
335 
336 uint8_t device_information_service_client_query(hci_con_handle_t con_handle, btstack_packet_handler_t packet_handler){
337     btstack_assert(packet_handler != NULL);
338     device_information_service_client_t * client = device_information_service_client_get_client();
339 
340     if (client->state != DEVICE_INFORMATION_SERVICE_CLIENT_STATE_IDLE){
341         return GATT_CLIENT_IN_WRONG_STATE;
342     }
343 
344     client->con_handle = con_handle;
345     client->client_handler = packet_handler;
346     client->state = DEVICE_INFORMATION_SERVICE_CLIENT_STATE_W2_QUERY_SERVICE;
347     device_information_service_run_for_client(client);
348     return ERROR_CODE_SUCCESS;
349 }
350 
351 
352 void device_information_service_client_init(void){}
353 
354 void device_information_service_client_deinit(void){}
355 
356