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