16bdecec7SMatthias Ringwald /*
26bdecec7SMatthias Ringwald * Copyright (C) 2021 BlueKitchen GmbH
36bdecec7SMatthias Ringwald *
46bdecec7SMatthias Ringwald * Redistribution and use in source and binary forms, with or without
56bdecec7SMatthias Ringwald * modification, are permitted provided that the following conditions
66bdecec7SMatthias Ringwald * are met:
76bdecec7SMatthias Ringwald *
86bdecec7SMatthias Ringwald * 1. Redistributions of source code must retain the above copyright
96bdecec7SMatthias Ringwald * notice, this list of conditions and the following disclaimer.
106bdecec7SMatthias Ringwald * 2. Redistributions in binary form must reproduce the above copyright
116bdecec7SMatthias Ringwald * notice, this list of conditions and the following disclaimer in the
126bdecec7SMatthias Ringwald * documentation and/or other materials provided with the distribution.
136bdecec7SMatthias Ringwald * 3. Neither the name of the copyright holders nor the names of
146bdecec7SMatthias Ringwald * contributors may be used to endorse or promote products derived
156bdecec7SMatthias Ringwald * from this software without specific prior written permission.
166bdecec7SMatthias Ringwald * 4. Any redistribution, use, or modification is done solely for
176bdecec7SMatthias Ringwald * personal benefit and not for any commercial purpose or for
186bdecec7SMatthias Ringwald * monetary gain.
196bdecec7SMatthias Ringwald *
206bdecec7SMatthias Ringwald * THIS SOFTWARE IS PROVIDED BY BLUEKITCHEN GMBH AND CONTRIBUTORS
216bdecec7SMatthias Ringwald * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
226bdecec7SMatthias Ringwald * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
232fca4dadSMilanka Ringwald * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BLUEKITCHEN
242fca4dadSMilanka Ringwald * GMBH OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
256bdecec7SMatthias Ringwald * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
266bdecec7SMatthias Ringwald * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
276bdecec7SMatthias Ringwald * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
286bdecec7SMatthias Ringwald * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
296bdecec7SMatthias Ringwald * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
306bdecec7SMatthias Ringwald * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
316bdecec7SMatthias Ringwald * SUCH DAMAGE.
326bdecec7SMatthias Ringwald *
336bdecec7SMatthias Ringwald * Please inquire about commercial licensing options at
346bdecec7SMatthias Ringwald * [email protected]
356bdecec7SMatthias Ringwald *
366bdecec7SMatthias Ringwald */
376bdecec7SMatthias Ringwald
386bdecec7SMatthias Ringwald #define BTSTACK_FILE__ "device_information_service_client.c"
396bdecec7SMatthias Ringwald
406bdecec7SMatthias Ringwald #include "btstack_config.h"
416bdecec7SMatthias Ringwald
426bdecec7SMatthias Ringwald #include <stdint.h>
436bdecec7SMatthias Ringwald #include <string.h>
446bdecec7SMatthias Ringwald
4509fa6397SMilanka Ringwald #ifdef ENABLE_TESTING_SUPPORT
4609fa6397SMilanka Ringwald #include <stdio.h>
4709fa6397SMilanka Ringwald #endif
486bdecec7SMatthias Ringwald
496bdecec7SMatthias Ringwald #include "ble/gatt-service/device_information_service_client.h"
506bdecec7SMatthias Ringwald
516bdecec7SMatthias Ringwald #include "ble/core.h"
526bdecec7SMatthias Ringwald #include "ble/gatt_client.h"
536bdecec7SMatthias Ringwald #include "bluetooth_gatt.h"
546bdecec7SMatthias Ringwald #include "btstack_debug.h"
556bdecec7SMatthias Ringwald #include "btstack_event.h"
566bdecec7SMatthias Ringwald #include "gap.h"
576bdecec7SMatthias Ringwald
586bdecec7SMatthias Ringwald #define DEVICE_INFORMATION_MAX_STRING_LEN 32
596bdecec7SMatthias Ringwald
606bdecec7SMatthias Ringwald
616bdecec7SMatthias Ringwald typedef enum {
626bdecec7SMatthias Ringwald DEVICE_INFORMATION_SERVICE_CLIENT_STATE_IDLE,
636bdecec7SMatthias Ringwald DEVICE_INFORMATION_SERVICE_CLIENT_STATE_W2_QUERY_SERVICE,
646bdecec7SMatthias Ringwald DEVICE_INFORMATION_SERVICE_CLIENT_STATE_W4_SERVICE_RESULT,
65c5b041aaSMilanka Ringwald #ifdef ENABLE_TESTING_SUPPORT
66c5b041aaSMilanka Ringwald DEVICE_INFORMATION_SERVICE_CLIENT_STATE_W2_QUERY_CHARACTERISTICS,
67c5b041aaSMilanka Ringwald DEVICE_INFORMATION_SERVICE_CLIENT_STATE_W4_CHARACTERISTIC_RESULT,
68c5b041aaSMilanka Ringwald #endif
69c5b041aaSMilanka Ringwald DEVICE_INFORMATION_SERVICE_CLIENT_STATE_W2_READ_VALUE_OF_CHARACTERISTIC,
70c5b041aaSMilanka Ringwald DEVICE_INFORMATION_SERVICE_CLIENT_STATE_W4_CHARACTERISTIC_VALUE
716bdecec7SMatthias Ringwald } device_information_service_client_state_t;
726bdecec7SMatthias Ringwald
736bdecec7SMatthias Ringwald typedef struct {
746bdecec7SMatthias Ringwald hci_con_handle_t con_handle;
756bdecec7SMatthias Ringwald device_information_service_client_state_t state;
766bdecec7SMatthias Ringwald btstack_packet_handler_t client_handler;
776bdecec7SMatthias Ringwald
786bdecec7SMatthias Ringwald // service
796bdecec7SMatthias Ringwald uint16_t start_handle;
806bdecec7SMatthias Ringwald uint16_t end_handle;
816bdecec7SMatthias Ringwald uint8_t num_instances;
826bdecec7SMatthias Ringwald
836bdecec7SMatthias Ringwald // index of next characteristic to query
846bdecec7SMatthias Ringwald uint8_t characteristic_index;
856bdecec7SMatthias Ringwald } device_information_service_client_t;
866bdecec7SMatthias Ringwald
871d3c1f7fSMatthias Ringwald
881d3c1f7fSMatthias Ringwald static btstack_context_callback_registration_t device_information_service_handle_can_send_now;
891d3c1f7fSMatthias Ringwald
906bdecec7SMatthias Ringwald static device_information_service_client_t device_information_service_client;
916bdecec7SMatthias Ringwald
926bdecec7SMatthias Ringwald static void handle_gatt_client_event(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size);
936bdecec7SMatthias Ringwald 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);
946bdecec7SMatthias Ringwald 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);
956bdecec7SMatthias Ringwald 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);
966bdecec7SMatthias Ringwald 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);
971d3c1f7fSMatthias Ringwald static void device_information_service_emit_udi_for_medical_devices(device_information_service_client_t * client, uint8_t subevent, uint8_t att_status, const uint8_t * value, uint16_t value_len);
986bdecec7SMatthias Ringwald
996bdecec7SMatthias Ringwald // list of uuids and how they are reported as events
1002e39b0f0SMilanka Ringwald static const struct device_information_characteristic {
1016bdecec7SMatthias Ringwald uint16_t uuid;
1026bdecec7SMatthias Ringwald uint8_t subevent;
1036bdecec7SMatthias Ringwald void (*handle_value)(device_information_service_client_t * client, uint8_t subevent, uint8_t att_status, const uint8_t * value, uint16_t value_len);
1046bdecec7SMatthias Ringwald } device_information_characteristics[] = {
1056bdecec7SMatthias Ringwald {ORG_BLUETOOTH_CHARACTERISTIC_MANUFACTURER_NAME_STRING, GATTSERVICE_SUBEVENT_DEVICE_INFORMATION_MANUFACTURER_NAME, device_information_service_emit_string_value},
1066bdecec7SMatthias Ringwald {ORG_BLUETOOTH_CHARACTERISTIC_MODEL_NUMBER_STRING, GATTSERVICE_SUBEVENT_DEVICE_INFORMATION_MODEL_NUMBER, device_information_service_emit_string_value},
1076bdecec7SMatthias Ringwald {ORG_BLUETOOTH_CHARACTERISTIC_SERIAL_NUMBER_STRING, GATTSERVICE_SUBEVENT_DEVICE_INFORMATION_SERIAL_NUMBER, device_information_service_emit_string_value},
10826dcf835SMilanka Ringwald {ORG_BLUETOOTH_CHARACTERISTIC_HARDWARE_REVISION_STRING, GATTSERVICE_SUBEVENT_DEVICE_INFORMATION_HARDWARE_REVISION, device_information_service_emit_string_value},
1096bdecec7SMatthias Ringwald {ORG_BLUETOOTH_CHARACTERISTIC_FIRMWARE_REVISION_STRING, GATTSERVICE_SUBEVENT_DEVICE_INFORMATION_FIRMWARE_REVISION, device_information_service_emit_string_value},
1106bdecec7SMatthias Ringwald {ORG_BLUETOOTH_CHARACTERISTIC_SOFTWARE_REVISION_STRING, GATTSERVICE_SUBEVENT_DEVICE_INFORMATION_SOFTWARE_REVISION, device_information_service_emit_string_value},
1116bdecec7SMatthias Ringwald
11226dcf835SMilanka Ringwald {ORG_BLUETOOTH_CHARACTERISTIC_SYSTEM_ID, GATTSERVICE_SUBEVENT_DEVICE_INFORMATION_SYSTEM_ID, device_information_service_emit_system_id},
1136bdecec7SMatthias Ringwald {ORG_BLUETOOTH_CHARACTERISTIC_IEEE_11073_20601_REGULATORY_CERTIFICATION_DATA_LIST, GATTSERVICE_SUBEVENT_DEVICE_INFORMATION_IEEE_REGULATORY_CERTIFICATION, device_information_service_emit_certification_data_list},
1141d3c1f7fSMatthias Ringwald {ORG_BLUETOOTH_CHARACTERISTIC_PNP_ID, GATTSERVICE_SUBEVENT_DEVICE_INFORMATION_PNP_ID, device_information_service_emit_pnp_id},
1151d3c1f7fSMatthias Ringwald {ORG_BLUETOOTH_CHARACTERISTIC_UDI_FOR_MEDICAL_DEVICES, GATTSERVICE_SUBEVENT_DEVICE_INFORMATION_UDI_FOR_MEDICAL_DEVICES, device_information_service_emit_udi_for_medical_devices}
1166bdecec7SMatthias Ringwald };
1176bdecec7SMatthias Ringwald
device_informatiom_client_request_send_gatt_query(device_information_service_client_t * client)1181d3c1f7fSMatthias Ringwald static uint8_t device_informatiom_client_request_send_gatt_query(device_information_service_client_t * client){
1191d3c1f7fSMatthias Ringwald uint8_t status = gatt_client_request_to_send_gatt_query(&device_information_service_handle_can_send_now, client->con_handle);
1201d3c1f7fSMatthias Ringwald if (status != ERROR_CODE_SUCCESS){
1211d3c1f7fSMatthias Ringwald if (client->state >= DEVICE_INFORMATION_SERVICE_CLIENT_STATE_W2_QUERY_SERVICE){
1221d3c1f7fSMatthias Ringwald client->state = DEVICE_INFORMATION_SERVICE_CLIENT_STATE_IDLE;
1231d3c1f7fSMatthias Ringwald }
1241d3c1f7fSMatthias Ringwald
1251d3c1f7fSMatthias Ringwald }
1261d3c1f7fSMatthias Ringwald return status;
1271d3c1f7fSMatthias Ringwald }
1281d3c1f7fSMatthias Ringwald
1292e39b0f0SMilanka Ringwald #ifdef ENABLE_TESTING_SUPPORT
1302e39b0f0SMilanka Ringwald static struct device_information_characteristic_handles{
1312e39b0f0SMilanka Ringwald uint16_t uuid;
1322e39b0f0SMilanka Ringwald uint16_t value_handle;
1332e39b0f0SMilanka Ringwald } device_information_characteristic_handles[] = {
1342e39b0f0SMilanka Ringwald {ORG_BLUETOOTH_CHARACTERISTIC_MANUFACTURER_NAME_STRING, 0},
1352e39b0f0SMilanka Ringwald {ORG_BLUETOOTH_CHARACTERISTIC_MODEL_NUMBER_STRING, 0},
1362e39b0f0SMilanka Ringwald {ORG_BLUETOOTH_CHARACTERISTIC_SERIAL_NUMBER_STRING, 0},
1372e39b0f0SMilanka Ringwald {ORG_BLUETOOTH_CHARACTERISTIC_HARDWARE_REVISION_STRING, 0},
1382e39b0f0SMilanka Ringwald {ORG_BLUETOOTH_CHARACTERISTIC_FIRMWARE_REVISION_STRING, 0},
1392e39b0f0SMilanka Ringwald {ORG_BLUETOOTH_CHARACTERISTIC_SOFTWARE_REVISION_STRING, 0},
1402e39b0f0SMilanka Ringwald {ORG_BLUETOOTH_CHARACTERISTIC_SYSTEM_ID, 0},
1412e39b0f0SMilanka Ringwald {ORG_BLUETOOTH_CHARACTERISTIC_IEEE_11073_20601_REGULATORY_CERTIFICATION_DATA_LIST, 0},
142*3a82c685SMatthias Ringwald {ORG_BLUETOOTH_CHARACTERISTIC_PNP_ID, 0},
143*3a82c685SMatthias Ringwald {ORG_BLUETOOTH_CHARACTERISTIC_UDI_FOR_MEDICAL_DEVICES, 0}
1442e39b0f0SMilanka Ringwald };
1452e39b0f0SMilanka Ringwald
device_information_service_update_handle_for_uuid(uint16_t uuid,uint16_t value_handle)1462e39b0f0SMilanka Ringwald static void device_information_service_update_handle_for_uuid(uint16_t uuid, uint16_t value_handle){
1472e39b0f0SMilanka Ringwald uint8_t i;
1482e39b0f0SMilanka Ringwald for (i = 0; i < 9; i++){
1492e39b0f0SMilanka Ringwald if (device_information_characteristic_handles[i].uuid == uuid){
1502e39b0f0SMilanka Ringwald device_information_characteristic_handles[i].value_handle = value_handle;
1512e39b0f0SMilanka Ringwald return;
1522e39b0f0SMilanka Ringwald }
1532e39b0f0SMilanka Ringwald }
1542e39b0f0SMilanka Ringwald }
1552e39b0f0SMilanka Ringwald #endif
1562e39b0f0SMilanka Ringwald
1572e39b0f0SMilanka Ringwald
1586bdecec7SMatthias Ringwald static const uint8_t num_information_fields = sizeof(device_information_characteristics)/sizeof(struct device_information_characteristic);
1596bdecec7SMatthias Ringwald
160c5b041aaSMilanka Ringwald #ifdef ENABLE_TESTING_SUPPORT
device_information_characteristic_name(uint16_t uuid)161c5b041aaSMilanka Ringwald static char * device_information_characteristic_name(uint16_t uuid){
162c5b041aaSMilanka Ringwald switch (uuid){
163c5b041aaSMilanka Ringwald case ORG_BLUETOOTH_CHARACTERISTIC_MANUFACTURER_NAME_STRING:
164c5b041aaSMilanka Ringwald return "MANUFACTURER_NAME_STRING";
165c5b041aaSMilanka Ringwald
166c5b041aaSMilanka Ringwald case ORG_BLUETOOTH_CHARACTERISTIC_MODEL_NUMBER_STRING:
167c5b041aaSMilanka Ringwald return "MODEL_NUMBER_STRING";
168c5b041aaSMilanka Ringwald
169c5b041aaSMilanka Ringwald case ORG_BLUETOOTH_CHARACTERISTIC_SERIAL_NUMBER_STRING:
170c5b041aaSMilanka Ringwald return "SERIAL_NUMBER_STRING";
171c5b041aaSMilanka Ringwald
172c5b041aaSMilanka Ringwald case ORG_BLUETOOTH_CHARACTERISTIC_HARDWARE_REVISION_STRING:
173c5b041aaSMilanka Ringwald return "HARDWARE_REVISION_STRING";
174c5b041aaSMilanka Ringwald
175c5b041aaSMilanka Ringwald case ORG_BLUETOOTH_CHARACTERISTIC_FIRMWARE_REVISION_STRING:
176c5b041aaSMilanka Ringwald return "FIRMWARE_REVISION_STRING";
177c5b041aaSMilanka Ringwald
178c5b041aaSMilanka Ringwald case ORG_BLUETOOTH_CHARACTERISTIC_SOFTWARE_REVISION_STRING:
179c5b041aaSMilanka Ringwald return "SOFTWARE_REVISION_STRING";
180c5b041aaSMilanka Ringwald
181c5b041aaSMilanka Ringwald case ORG_BLUETOOTH_CHARACTERISTIC_SYSTEM_ID:
182c5b041aaSMilanka Ringwald return "SYSTEM_ID";
183c5b041aaSMilanka Ringwald
184c5b041aaSMilanka Ringwald case ORG_BLUETOOTH_CHARACTERISTIC_IEEE_11073_20601_REGULATORY_CERTIFICATION_DATA_LIST:
185c5b041aaSMilanka Ringwald return "IEEE_11073_20601_REGULATORY_CERTIFICATION_DATA_LIST";
186c5b041aaSMilanka Ringwald
187c5b041aaSMilanka Ringwald case ORG_BLUETOOTH_CHARACTERISTIC_PNP_ID:
188c5b041aaSMilanka Ringwald return "PNP_ID";
1891d3c1f7fSMatthias Ringwald
1901d3c1f7fSMatthias Ringwald case ORG_BLUETOOTH_CHARACTERISTIC_UDI_FOR_MEDICAL_DEVICES:
1911d3c1f7fSMatthias Ringwald return "ORG_BLUETOOTH_CHARACTERISTIC_UDI_FOR_MEDICAL_DEVICES";
1921d3c1f7fSMatthias Ringwald
193c5b041aaSMilanka Ringwald default:
194c5b041aaSMilanka Ringwald return "UKNOWN";
195c5b041aaSMilanka Ringwald }
196c5b041aaSMilanka Ringwald }
197c5b041aaSMilanka Ringwald #endif
device_information_service_client_get_client(void)1986bdecec7SMatthias Ringwald static device_information_service_client_t * device_information_service_client_get_client(void){
1996bdecec7SMatthias Ringwald return &device_information_service_client;
2006bdecec7SMatthias Ringwald }
2016bdecec7SMatthias Ringwald
device_information_service_get_client_for_con_handle(hci_con_handle_t con_handle)2026bdecec7SMatthias Ringwald static device_information_service_client_t * device_information_service_get_client_for_con_handle(hci_con_handle_t con_handle){
2036bdecec7SMatthias Ringwald if (device_information_service_client.con_handle == con_handle){
2046bdecec7SMatthias Ringwald return &device_information_service_client;
2056bdecec7SMatthias Ringwald }
2066bdecec7SMatthias Ringwald return NULL;
2076bdecec7SMatthias Ringwald }
2086bdecec7SMatthias Ringwald
device_information_service_finalize_client(device_information_service_client_t * client)2096bdecec7SMatthias Ringwald static void device_information_service_finalize_client(device_information_service_client_t * client){
2106bdecec7SMatthias Ringwald client->state = DEVICE_INFORMATION_SERVICE_CLIENT_STATE_IDLE;
2116bdecec7SMatthias Ringwald client->con_handle = HCI_CON_HANDLE_INVALID;
21226dcf835SMilanka Ringwald client->client_handler = NULL;
21326dcf835SMilanka Ringwald client->num_instances = 0;
21426dcf835SMilanka Ringwald client->start_handle = 0;
21526dcf835SMilanka Ringwald client->end_handle = 0;
2166bdecec7SMatthias Ringwald }
2176bdecec7SMatthias Ringwald
device_information_service_emit_query_done_and_finalize_client(device_information_service_client_t * client,uint8_t status)218a58af5a9SMilanka Ringwald static void device_information_service_emit_query_done_and_finalize_client(device_information_service_client_t * client, uint8_t status){
219a58af5a9SMilanka Ringwald hci_con_handle_t con_handle = client->con_handle;
220a58af5a9SMilanka Ringwald btstack_packet_handler_t callback = client->client_handler;
221a58af5a9SMilanka Ringwald
222a58af5a9SMilanka Ringwald device_information_service_finalize_client(client);
223a58af5a9SMilanka Ringwald
2246bdecec7SMatthias Ringwald uint8_t event[6];
2256bdecec7SMatthias Ringwald int pos = 0;
2266bdecec7SMatthias Ringwald event[pos++] = HCI_EVENT_GATTSERVICE_META;
2276bdecec7SMatthias Ringwald event[pos++] = sizeof(event) - 2;
2286bdecec7SMatthias Ringwald event[pos++] = GATTSERVICE_SUBEVENT_DEVICE_INFORMATION_DONE;
229a58af5a9SMilanka Ringwald little_endian_store_16(event, pos, con_handle);
2306bdecec7SMatthias Ringwald pos += 2;
231a58af5a9SMilanka Ringwald event[pos++] = status;
232a58af5a9SMilanka Ringwald (*callback)(HCI_EVENT_PACKET, 0, event, pos);
2336bdecec7SMatthias Ringwald }
2346bdecec7SMatthias Ringwald
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)2356bdecec7SMatthias Ringwald 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){
2366bdecec7SMatthias Ringwald uint8_t event[6 + DEVICE_INFORMATION_MAX_STRING_LEN + 1];
2376bdecec7SMatthias Ringwald int pos = 0;
2386bdecec7SMatthias Ringwald
2396bdecec7SMatthias Ringwald event[pos++] = HCI_EVENT_GATTSERVICE_META;
2406bdecec7SMatthias Ringwald pos++;
2416bdecec7SMatthias Ringwald event[pos++] = subevent;
2426bdecec7SMatthias Ringwald little_endian_store_16(event, pos, client->con_handle);
2436bdecec7SMatthias Ringwald pos += 2;
2446bdecec7SMatthias Ringwald event[pos++] = att_status;
2456bdecec7SMatthias Ringwald
2466bdecec7SMatthias Ringwald uint16_t bytes_to_copy = btstack_min(value_len, DEVICE_INFORMATION_MAX_STRING_LEN);
2476bdecec7SMatthias Ringwald memcpy((char*)&event[pos], value, bytes_to_copy);
2486bdecec7SMatthias Ringwald pos += bytes_to_copy;
2496bdecec7SMatthias Ringwald event[pos++] = 0;
2506bdecec7SMatthias Ringwald
251ff666f0bSMilanka Ringwald event[1] = pos - 2;
2526bdecec7SMatthias Ringwald (*client->client_handler)(HCI_EVENT_PACKET, 0, event, pos);
2536bdecec7SMatthias Ringwald }
2546bdecec7SMatthias Ringwald
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)2556bdecec7SMatthias Ringwald 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){
2566bdecec7SMatthias Ringwald if (value_len != 8) return;
2576bdecec7SMatthias Ringwald
2586bdecec7SMatthias Ringwald uint8_t event[14];
2596bdecec7SMatthias Ringwald uint16_t pos = 0;
2606bdecec7SMatthias Ringwald event[pos++] = HCI_EVENT_GATTSERVICE_META;
2616bdecec7SMatthias Ringwald event[pos++] = sizeof(event) - 2;
2626bdecec7SMatthias Ringwald event[pos++] = subevent;
2636bdecec7SMatthias Ringwald little_endian_store_16(event, pos, client->con_handle);
2646bdecec7SMatthias Ringwald pos += 2;
2656bdecec7SMatthias Ringwald event[pos++] = att_status;
2666bdecec7SMatthias Ringwald memcpy(event+pos, value, 8);
2676bdecec7SMatthias Ringwald pos += 8;
2686bdecec7SMatthias Ringwald
2696bdecec7SMatthias Ringwald (*client->client_handler)(HCI_EVENT_PACKET, 0, event, pos);
2706bdecec7SMatthias Ringwald }
2716bdecec7SMatthias Ringwald
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)2726bdecec7SMatthias Ringwald 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){
2736bdecec7SMatthias Ringwald if (value_len != 4) return;
2746bdecec7SMatthias Ringwald
2756bdecec7SMatthias Ringwald uint8_t event[10];
2766bdecec7SMatthias Ringwald int pos = 0;
2776bdecec7SMatthias Ringwald event[pos++] = HCI_EVENT_GATTSERVICE_META;
2786bdecec7SMatthias Ringwald event[pos++] = sizeof(event) - 2;
2796bdecec7SMatthias Ringwald event[pos++] = subevent;
2806bdecec7SMatthias Ringwald little_endian_store_16(event, pos, client->con_handle);
2816bdecec7SMatthias Ringwald pos += 2;
2826bdecec7SMatthias Ringwald event[pos++] = att_status;
2836bdecec7SMatthias Ringwald memcpy(event + pos, value, 4);
2846bdecec7SMatthias Ringwald pos += 4;
2856bdecec7SMatthias Ringwald
2866bdecec7SMatthias Ringwald (*client->client_handler)(HCI_EVENT_PACKET, 0, event, pos);
2876bdecec7SMatthias Ringwald }
2886bdecec7SMatthias Ringwald
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)2896bdecec7SMatthias Ringwald 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){
2906bdecec7SMatthias Ringwald if (value_len != 7) return;
2916bdecec7SMatthias Ringwald
2926bdecec7SMatthias Ringwald uint8_t event[13];
2936bdecec7SMatthias Ringwald uint16_t pos = 0;
2946bdecec7SMatthias Ringwald event[pos++] = HCI_EVENT_GATTSERVICE_META;
2956bdecec7SMatthias Ringwald event[pos++] = sizeof(event) - 2;
2966bdecec7SMatthias Ringwald event[pos++] = subevent;
2976bdecec7SMatthias Ringwald little_endian_store_16(event, pos, client->con_handle);
2986bdecec7SMatthias Ringwald pos += 2;
2996bdecec7SMatthias Ringwald event[pos++] = att_status;
3006bdecec7SMatthias Ringwald memcpy(event + pos, value, 7);
3016bdecec7SMatthias Ringwald pos += 7;
3026bdecec7SMatthias Ringwald
3036bdecec7SMatthias Ringwald (*client->client_handler)(HCI_EVENT_PACKET, 0, event, pos);
3046bdecec7SMatthias Ringwald }
3056bdecec7SMatthias Ringwald
device_information_service_emit_udi_for_medical_devices(device_information_service_client_t * client,uint8_t subevent,uint8_t att_status,const uint8_t * value,uint16_t value_len)3061d3c1f7fSMatthias Ringwald static void device_information_service_emit_udi_for_medical_devices(device_information_service_client_t * client, uint8_t subevent, uint8_t att_status, const uint8_t * value, uint16_t value_len){
3071d3c1f7fSMatthias Ringwald uint16_t max_udi_length = 1 + 4 * DEVICE_INFORMATION_MAX_STRING_LEN;
3086bdecec7SMatthias Ringwald
3091d3c1f7fSMatthias Ringwald if (value_len > max_udi_length) return;
3101d3c1f7fSMatthias Ringwald
3111d3c1f7fSMatthias Ringwald uint8_t event[6 + 1 + 4 * DEVICE_INFORMATION_MAX_STRING_LEN];
3121d3c1f7fSMatthias Ringwald uint16_t pos = 0;
3131d3c1f7fSMatthias Ringwald event[pos++] = HCI_EVENT_GATTSERVICE_META;
3141d3c1f7fSMatthias Ringwald event[pos++] = sizeof(event) - 2;
3151d3c1f7fSMatthias Ringwald event[pos++] = subevent;
3161d3c1f7fSMatthias Ringwald little_endian_store_16(event, pos, client->con_handle);
3171d3c1f7fSMatthias Ringwald pos += 2;
3181d3c1f7fSMatthias Ringwald event[pos++] = att_status;
3191d3c1f7fSMatthias Ringwald memcpy(event + pos, value, value_len);
3201d3c1f7fSMatthias Ringwald pos += value_len;
3211d3c1f7fSMatthias Ringwald
3221d3c1f7fSMatthias Ringwald (*client->client_handler)(HCI_EVENT_PACKET, 0, event, pos);
3231d3c1f7fSMatthias Ringwald }
3241d3c1f7fSMatthias Ringwald
3251d3c1f7fSMatthias Ringwald
device_information_service_send_next_query(void * context)3261d3c1f7fSMatthias Ringwald static void device_information_service_send_next_query(void * context){
3271d3c1f7fSMatthias Ringwald UNUSED(context);
3281d3c1f7fSMatthias Ringwald device_information_service_client_t * client = device_information_service_client_get_client();
3291d3c1f7fSMatthias Ringwald
3301d3c1f7fSMatthias Ringwald if (client == NULL){
3311d3c1f7fSMatthias Ringwald return;
3321d3c1f7fSMatthias Ringwald }
3331d3c1f7fSMatthias Ringwald
3346bdecec7SMatthias Ringwald uint8_t att_status;
3356bdecec7SMatthias Ringwald
3366bdecec7SMatthias Ringwald switch (client->state){
3376bdecec7SMatthias Ringwald case DEVICE_INFORMATION_SERVICE_CLIENT_STATE_W2_QUERY_SERVICE:
3386bdecec7SMatthias Ringwald client->state = DEVICE_INFORMATION_SERVICE_CLIENT_STATE_W4_SERVICE_RESULT;
3396bdecec7SMatthias Ringwald att_status = gatt_client_discover_primary_services_by_uuid16(handle_gatt_client_event, client->con_handle, ORG_BLUETOOTH_SERVICE_DEVICE_INFORMATION);
3406bdecec7SMatthias Ringwald // TODO handle status
3416bdecec7SMatthias Ringwald UNUSED(att_status);
3426bdecec7SMatthias Ringwald break;
343c5b041aaSMilanka Ringwald #ifdef ENABLE_TESTING_SUPPORT
344c5b041aaSMilanka Ringwald case DEVICE_INFORMATION_SERVICE_CLIENT_STATE_W2_QUERY_CHARACTERISTICS:
345c5b041aaSMilanka Ringwald client->state = DEVICE_INFORMATION_SERVICE_CLIENT_STATE_W4_CHARACTERISTIC_RESULT;
346c5b041aaSMilanka Ringwald gatt_client_discover_characteristics_for_handle_range_by_uuid16(
347c5b041aaSMilanka Ringwald &handle_gatt_client_event,
348c5b041aaSMilanka Ringwald client->con_handle, client->start_handle, client->end_handle,
349c5b041aaSMilanka Ringwald device_information_characteristics[client->characteristic_index].uuid);
350c5b041aaSMilanka Ringwald break;
351c5b041aaSMilanka Ringwald #endif
3526bdecec7SMatthias Ringwald
353c5b041aaSMilanka Ringwald case DEVICE_INFORMATION_SERVICE_CLIENT_STATE_W2_READ_VALUE_OF_CHARACTERISTIC:
354c5b041aaSMilanka Ringwald client->state = DEVICE_INFORMATION_SERVICE_CLIENT_STATE_W4_CHARACTERISTIC_VALUE;
3552e39b0f0SMilanka Ringwald
3562e39b0f0SMilanka Ringwald #ifdef ENABLE_TESTING_SUPPORT
3572e39b0f0SMilanka Ringwald att_status = gatt_client_read_value_of_characteristic_using_value_handle(
3582e39b0f0SMilanka Ringwald handle_gatt_client_event,
3592e39b0f0SMilanka Ringwald client->con_handle,
3602e39b0f0SMilanka Ringwald device_information_characteristic_handles[client->characteristic_index].value_handle);
3612e39b0f0SMilanka Ringwald #else
3626bdecec7SMatthias Ringwald att_status = gatt_client_read_value_of_characteristics_by_uuid16(
3636bdecec7SMatthias Ringwald handle_gatt_client_event,
3646bdecec7SMatthias Ringwald client->con_handle, client->start_handle, client->end_handle,
3656bdecec7SMatthias Ringwald device_information_characteristics[client->characteristic_index].uuid);
3662e39b0f0SMilanka Ringwald #endif
3676bdecec7SMatthias Ringwald // TODO handle status
3686bdecec7SMatthias Ringwald UNUSED(att_status);
3696bdecec7SMatthias Ringwald break;
3706bdecec7SMatthias Ringwald
3716bdecec7SMatthias Ringwald default:
3726bdecec7SMatthias Ringwald break;
3736bdecec7SMatthias Ringwald }
3746bdecec7SMatthias Ringwald }
3756bdecec7SMatthias Ringwald
handle_gatt_client_event(uint8_t packet_type,uint16_t channel,uint8_t * packet,uint16_t size)3766bdecec7SMatthias Ringwald static void handle_gatt_client_event(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){
3776bdecec7SMatthias Ringwald UNUSED(packet_type);
3786bdecec7SMatthias Ringwald UNUSED(channel);
3796bdecec7SMatthias Ringwald UNUSED(size);
3806bdecec7SMatthias Ringwald
3816bdecec7SMatthias Ringwald uint8_t att_status;
382c5b041aaSMilanka Ringwald device_information_service_client_t * client = NULL;
3836bdecec7SMatthias Ringwald gatt_client_service_t service;
384*3a82c685SMatthias Ringwald bool trigger_next_query = false;
385c5b041aaSMilanka Ringwald #ifdef ENABLE_TESTING_SUPPORT
386c5b041aaSMilanka Ringwald gatt_client_characteristic_t characteristic;
387c5b041aaSMilanka Ringwald #endif
388c5b041aaSMilanka Ringwald
3896bdecec7SMatthias Ringwald switch(hci_event_packet_get_type(packet)){
3906bdecec7SMatthias Ringwald
3916bdecec7SMatthias Ringwald case GATT_EVENT_SERVICE_QUERY_RESULT:
3926bdecec7SMatthias Ringwald client = device_information_service_get_client_for_con_handle(gatt_event_service_query_result_get_handle(packet));
3936bdecec7SMatthias Ringwald btstack_assert(client != NULL);
3946bdecec7SMatthias Ringwald
3956bdecec7SMatthias Ringwald gatt_event_service_query_result_get_service(packet, &service);
3966bdecec7SMatthias Ringwald client->start_handle = service.start_group_handle;
3976bdecec7SMatthias Ringwald client->end_handle = service.end_group_handle;
398498fd4baSMilanka Ringwald
399498fd4baSMilanka Ringwald client->characteristic_index = 0;
400498fd4baSMilanka Ringwald if (client->start_handle < client->end_handle){
401498fd4baSMilanka Ringwald client->num_instances++;
402498fd4baSMilanka Ringwald }
40309fa6397SMilanka Ringwald #ifdef ENABLE_TESTING_SUPPORT
40426dcf835SMilanka Ringwald 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);
40509fa6397SMilanka Ringwald #endif
4066bdecec7SMatthias Ringwald break;
4076bdecec7SMatthias Ringwald
408c5b041aaSMilanka Ringwald #ifdef ENABLE_TESTING_SUPPORT
409c5b041aaSMilanka Ringwald case GATT_EVENT_CHARACTERISTIC_QUERY_RESULT:
410c5b041aaSMilanka Ringwald client = device_information_service_get_client_for_con_handle(gatt_event_characteristic_query_result_get_handle(packet));
411c5b041aaSMilanka Ringwald btstack_assert(client != NULL);
412c5b041aaSMilanka Ringwald gatt_event_characteristic_query_result_get_characteristic(packet, &characteristic);
413c5b041aaSMilanka Ringwald
4142e39b0f0SMilanka Ringwald device_information_service_update_handle_for_uuid(characteristic.uuid16, characteristic.value_handle);
415c5b041aaSMilanka Ringwald printf("Device Information Characteristic %s: \n Attribute Handle 0x%04X, Properties 0x%02X, Handle 0x%04X, UUID 0x%04X\n",
416c5b041aaSMilanka Ringwald device_information_characteristic_name(characteristic.uuid16),
417c5b041aaSMilanka Ringwald characteristic.start_handle,
418c5b041aaSMilanka Ringwald characteristic.properties,
419c5b041aaSMilanka Ringwald characteristic.value_handle, characteristic.uuid16);
420c5b041aaSMilanka Ringwald break;
421c5b041aaSMilanka Ringwald #endif
4226bdecec7SMatthias Ringwald case GATT_EVENT_CHARACTERISTIC_VALUE_QUERY_RESULT:
4236bdecec7SMatthias Ringwald client = device_information_service_get_client_for_con_handle(gatt_event_characteristic_value_query_result_get_handle(packet));
4246bdecec7SMatthias Ringwald btstack_assert(client != NULL);
4256bdecec7SMatthias Ringwald
426c5b041aaSMilanka Ringwald
4276bdecec7SMatthias Ringwald (device_information_characteristics[client->characteristic_index].handle_value(
4286bdecec7SMatthias Ringwald client, device_information_characteristics[client->characteristic_index].subevent,
4296bdecec7SMatthias Ringwald ATT_ERROR_SUCCESS,
4306bdecec7SMatthias Ringwald gatt_event_characteristic_value_query_result_get_value(packet),
4316bdecec7SMatthias Ringwald gatt_event_characteristic_value_query_result_get_value_length(packet)));
4326bdecec7SMatthias Ringwald break;
4336bdecec7SMatthias Ringwald
4346bdecec7SMatthias Ringwald case GATT_EVENT_QUERY_COMPLETE:
4356bdecec7SMatthias Ringwald client = device_information_service_get_client_for_con_handle(gatt_event_query_complete_get_handle(packet));
4366bdecec7SMatthias Ringwald btstack_assert(client != NULL);
4376bdecec7SMatthias Ringwald
4386bdecec7SMatthias Ringwald att_status = gatt_event_query_complete_get_att_status(packet);
4396bdecec7SMatthias Ringwald switch (client->state){
4406bdecec7SMatthias Ringwald case DEVICE_INFORMATION_SERVICE_CLIENT_STATE_W4_SERVICE_RESULT:
4416bdecec7SMatthias Ringwald if (att_status != ATT_ERROR_SUCCESS){
442a58af5a9SMilanka Ringwald device_information_service_emit_query_done_and_finalize_client(client, att_status);
4435fa2c39aSMilanka Ringwald return;
4446bdecec7SMatthias Ringwald }
4456bdecec7SMatthias Ringwald
4466bdecec7SMatthias Ringwald if (client->num_instances != 1){
447a58af5a9SMilanka Ringwald device_information_service_emit_query_done_and_finalize_client(client, ERROR_CODE_UNSUPPORTED_FEATURE_OR_PARAMETER_VALUE);
4485fa2c39aSMilanka Ringwald return;
4496bdecec7SMatthias Ringwald }
450c5b041aaSMilanka Ringwald client->characteristic_index = 0;
451a58af5a9SMilanka Ringwald
452c5b041aaSMilanka Ringwald #ifdef ENABLE_TESTING_SUPPORT
453c5b041aaSMilanka Ringwald client->state = DEVICE_INFORMATION_SERVICE_CLIENT_STATE_W2_QUERY_CHARACTERISTICS;
454c5b041aaSMilanka Ringwald #else
455c5b041aaSMilanka Ringwald client->state = DEVICE_INFORMATION_SERVICE_CLIENT_STATE_W2_READ_VALUE_OF_CHARACTERISTIC;
456c5b041aaSMilanka Ringwald #endif
457*3a82c685SMatthias Ringwald trigger_next_query = true;
4586bdecec7SMatthias Ringwald break;
4596bdecec7SMatthias Ringwald
460c5b041aaSMilanka Ringwald #ifdef ENABLE_TESTING_SUPPORT
461c5b041aaSMilanka Ringwald case DEVICE_INFORMATION_SERVICE_CLIENT_STATE_W4_CHARACTERISTIC_RESULT:
462c5b041aaSMilanka Ringwald // check if there is another characteristic to query
463c5b041aaSMilanka Ringwald if ((client->characteristic_index + 1) < num_information_fields){
464c5b041aaSMilanka Ringwald client->characteristic_index++;
465c5b041aaSMilanka Ringwald client->state = DEVICE_INFORMATION_SERVICE_CLIENT_STATE_W2_QUERY_CHARACTERISTICS;
466*3a82c685SMatthias Ringwald trigger_next_query = true;
467c5b041aaSMilanka Ringwald break;
468c5b041aaSMilanka Ringwald }
469c5b041aaSMilanka Ringwald client->characteristic_index = 0;
470c5b041aaSMilanka Ringwald client->state = DEVICE_INFORMATION_SERVICE_CLIENT_STATE_W2_READ_VALUE_OF_CHARACTERISTIC;
471*3a82c685SMatthias Ringwald trigger_next_query = true;
472c5b041aaSMilanka Ringwald break;
473c5b041aaSMilanka Ringwald #endif
474c5b041aaSMilanka Ringwald case DEVICE_INFORMATION_SERVICE_CLIENT_STATE_W4_CHARACTERISTIC_VALUE:
4756bdecec7SMatthias Ringwald // check if there is another characteristic to query
476c5b041aaSMilanka Ringwald if ((client->characteristic_index + 1) < num_information_fields){
4776bdecec7SMatthias Ringwald client->characteristic_index++;
478c5b041aaSMilanka Ringwald client->state = DEVICE_INFORMATION_SERVICE_CLIENT_STATE_W2_READ_VALUE_OF_CHARACTERISTIC;
479*3a82c685SMatthias Ringwald trigger_next_query = true;
4806bdecec7SMatthias Ringwald break;
4816bdecec7SMatthias Ringwald }
4826bdecec7SMatthias Ringwald // we are done with quering all characteristics
483a58af5a9SMilanka Ringwald device_information_service_emit_query_done_and_finalize_client(client, ERROR_CODE_SUCCESS);
4845fa2c39aSMilanka Ringwald return;
4856bdecec7SMatthias Ringwald
4866bdecec7SMatthias Ringwald default:
4876bdecec7SMatthias Ringwald break;
4886bdecec7SMatthias Ringwald }
4896bdecec7SMatthias Ringwald break;
4906bdecec7SMatthias Ringwald default:
4916bdecec7SMatthias Ringwald break;
4926bdecec7SMatthias Ringwald }
4936bdecec7SMatthias Ringwald
494*3a82c685SMatthias Ringwald if (trigger_next_query){
4951d3c1f7fSMatthias Ringwald device_informatiom_client_request_send_gatt_query(client);
496c5b041aaSMilanka Ringwald }
4976bdecec7SMatthias Ringwald }
4986bdecec7SMatthias Ringwald
device_information_service_client_query(hci_con_handle_t con_handle,btstack_packet_handler_t packet_handler)4996bdecec7SMatthias Ringwald uint8_t device_information_service_client_query(hci_con_handle_t con_handle, btstack_packet_handler_t packet_handler){
5006bdecec7SMatthias Ringwald btstack_assert(packet_handler != NULL);
50166881873SMilanka Ringwald device_information_service_client_t * client = device_information_service_get_client_for_con_handle(con_handle);
5026bdecec7SMatthias Ringwald
50366881873SMilanka Ringwald if (client != NULL){
50466881873SMilanka Ringwald return ERROR_CODE_COMMAND_DISALLOWED;
5056bdecec7SMatthias Ringwald }
5066bdecec7SMatthias Ringwald
50766881873SMilanka Ringwald client = device_information_service_client_get_client();
508f6a72c8fSWeigang Wang
509f6a72c8fSWeigang Wang if (client->con_handle != HCI_CON_HANDLE_INVALID) {
510f6a72c8fSWeigang Wang return ERROR_CODE_COMMAND_DISALLOWED;
511f6a72c8fSWeigang Wang }
51266881873SMilanka Ringwald
5136bdecec7SMatthias Ringwald client->con_handle = con_handle;
5146bdecec7SMatthias Ringwald client->client_handler = packet_handler;
5156bdecec7SMatthias Ringwald client->state = DEVICE_INFORMATION_SERVICE_CLIENT_STATE_W2_QUERY_SERVICE;
51666881873SMilanka Ringwald
5171d3c1f7fSMatthias Ringwald device_informatiom_client_request_send_gatt_query(client);
5186bdecec7SMatthias Ringwald return ERROR_CODE_SUCCESS;
5196bdecec7SMatthias Ringwald }
5206bdecec7SMatthias Ringwald
5216bdecec7SMatthias Ringwald
device_information_service_client_init(void)52226dcf835SMilanka Ringwald void device_information_service_client_init(void){
52326dcf835SMilanka Ringwald device_information_service_client_t * client = device_information_service_client_get_client();
52426dcf835SMilanka Ringwald device_information_service_finalize_client(client);
5251d3c1f7fSMatthias Ringwald device_information_service_handle_can_send_now.callback = &device_information_service_send_next_query;
52626dcf835SMilanka Ringwald }
5276bdecec7SMatthias Ringwald
device_information_service_client_deinit(void)5286bdecec7SMatthias Ringwald void device_information_service_client_deinit(void){}
5296bdecec7SMatthias Ringwald
53071be2750SMilanka Ringwald // unit test only
53171be2750SMilanka Ringwald #if defined __cplusplus
53271be2750SMilanka Ringwald extern "C"
53371be2750SMilanka Ringwald #endif
53471be2750SMilanka Ringwald void device_information_service_client_set_invalid_state(void);
device_information_service_client_set_invalid_state(void)53571be2750SMilanka Ringwald void device_information_service_client_set_invalid_state(void){
53671be2750SMilanka Ringwald device_information_service_client_t * client = device_information_service_client_get_client();
53771be2750SMilanka Ringwald client->state = DEVICE_INFORMATION_SERVICE_CLIENT_STATE_IDLE;
53871be2750SMilanka Ringwald }
539