xref: /btstack/test/mock/mock_gatt_client.c (revision ec1a0dae0a3dfeeea3c9f966337cee08a13aa827)
10f7fd6c1SMilanka Ringwald #include <stdint.h>
20f7fd6c1SMilanka Ringwald #include <stdio.h>
30f7fd6c1SMilanka Ringwald #include <string.h>
40f7fd6c1SMilanka Ringwald 
5af770404SMilanka Ringwald #include "btstack_debug.h"
60f7fd6c1SMilanka Ringwald #include "mock_gatt_client.h"
70f7fd6c1SMilanka Ringwald 
80f7fd6c1SMilanka Ringwald #include "CppUTest/TestHarness.h"
90f7fd6c1SMilanka Ringwald #include "CppUTestExt/MockSupport.h"
100f7fd6c1SMilanka Ringwald 
11af770404SMilanka Ringwald static enum {
12af770404SMilanka Ringwald     MOCK_QUERY_IDLE = 0,
13d41a8f51SMilanka Ringwald     MOCK_QUERY_DISCOVER_PRIMARY_SERVICES_BY_UUID16,
14d41a8f51SMilanka Ringwald     MOCK_QUERY_DISCOVER_CHARACTERISTICS_BY_UUID16,
1576cdba3eSMilanka Ringwald     MOCK_QUERY_DISCOVER_CHARACTERISTIC_DESCRIPTORS,
1676cdba3eSMilanka Ringwald     MOCK_WRITE_CLIENT_CHARACTERISTIC_CONFIGURATION,
1776cdba3eSMilanka Ringwald     MOCK_READ_VALUE_OF_CHARACTERISTIC_USING_VALUE_HANDLE
18af770404SMilanka Ringwald } mock_gatt_client_state;
19af770404SMilanka Ringwald 
2076cdba3eSMilanka Ringwald static uint16_t mock_gatt_client_att_handle_generator;
2176cdba3eSMilanka Ringwald 
22af770404SMilanka Ringwald static uint8_t mock_gatt_client_att_error;
23af770404SMilanka Ringwald static uint16_t mock_gatt_client_uuid;
2476cdba3eSMilanka Ringwald static uint16_t mock_gatt_client_value_handle;
2576cdba3eSMilanka Ringwald static uint16_t mock_gatt_client_start_handle;
2676cdba3eSMilanka Ringwald static uint16_t mock_gatt_client_end_handle;
2776cdba3eSMilanka Ringwald 
28af770404SMilanka Ringwald static gatt_client_t gatt_client;
290f7fd6c1SMilanka Ringwald 
307da2c1baSMilanka Ringwald static btstack_linked_list_t mock_gatt_client_services;
317da2c1baSMilanka Ringwald 
327da2c1baSMilanka Ringwald static mock_gatt_client_service_t * mock_gatt_client_last_service;
337da2c1baSMilanka Ringwald static mock_gatt_client_characteristic_t * mock_gatt_client_last_characteristic;
347da2c1baSMilanka Ringwald 
35*ec1a0daeSMilanka Ringwald static uint8_t moc_att_error_code_discover_services;
36*ec1a0daeSMilanka Ringwald static uint8_t moc_att_error_code_discover_characteristics;
37*ec1a0daeSMilanka Ringwald static uint8_t moc_att_error_code_discover_characteristic_descriptors;
38*ec1a0daeSMilanka Ringwald 
39*ec1a0daeSMilanka Ringwald static void mock_gatt_client_reset_att_errors(void){
40*ec1a0daeSMilanka Ringwald     moc_att_error_code_discover_services = ATT_ERROR_SUCCESS;
41*ec1a0daeSMilanka Ringwald     moc_att_error_code_discover_characteristics = ATT_ERROR_SUCCESS;
42*ec1a0daeSMilanka Ringwald     moc_att_error_code_discover_characteristic_descriptors = ATT_ERROR_SUCCESS;
43*ec1a0daeSMilanka Ringwald }
44*ec1a0daeSMilanka Ringwald 
450f7fd6c1SMilanka Ringwald void mock_gatt_client_reset(void){
46af770404SMilanka Ringwald     mock_gatt_client_att_error = 0;
47af770404SMilanka Ringwald     mock_gatt_client_state = MOCK_QUERY_IDLE;
4876cdba3eSMilanka Ringwald     mock_gatt_client_att_handle_generator = 0;
4976cdba3eSMilanka Ringwald     mock_gatt_client_last_service = NULL;
507da2c1baSMilanka Ringwald 
51*ec1a0daeSMilanka Ringwald     mock_gatt_client_reset_att_errors();
52*ec1a0daeSMilanka Ringwald 
537da2c1baSMilanka Ringwald     btstack_linked_list_iterator_t service_it;
547da2c1baSMilanka Ringwald     btstack_linked_list_iterator_init(&service_it, &mock_gatt_client_services);
557da2c1baSMilanka Ringwald     while (btstack_linked_list_iterator_has_next(&service_it)){
567da2c1baSMilanka Ringwald         mock_gatt_client_service_t * service = (mock_gatt_client_service_t *) btstack_linked_list_iterator_next(&service_it);
577da2c1baSMilanka Ringwald         btstack_linked_list_remove(&mock_gatt_client_services, (btstack_linked_item_t *) service);
587da2c1baSMilanka Ringwald 
597da2c1baSMilanka Ringwald         btstack_linked_list_iterator_t characteristic_it;
607da2c1baSMilanka Ringwald         btstack_linked_list_iterator_init(&characteristic_it, &service->characteristics);
617da2c1baSMilanka Ringwald         while (btstack_linked_list_iterator_has_next(&characteristic_it)){
627da2c1baSMilanka Ringwald             mock_gatt_client_characteristic_t * characteristic = (mock_gatt_client_characteristic_t *) btstack_linked_list_iterator_next(&characteristic_it);
637da2c1baSMilanka Ringwald             btstack_linked_list_remove(&service->characteristics, (btstack_linked_item_t *) characteristic);
647da2c1baSMilanka Ringwald 
657da2c1baSMilanka Ringwald             btstack_linked_list_iterator_t desc_it;
667da2c1baSMilanka Ringwald             btstack_linked_list_iterator_init(&desc_it, &characteristic->descriptors);
677da2c1baSMilanka Ringwald             while (btstack_linked_list_iterator_has_next(&desc_it)){
687da2c1baSMilanka Ringwald                 mock_gatt_client_characteristic_descriptor_t * desc = (mock_gatt_client_characteristic_descriptor_t *) btstack_linked_list_iterator_next(&desc_it);
697da2c1baSMilanka Ringwald                 btstack_linked_list_remove(&characteristic->descriptors, (btstack_linked_item_t *) desc);
707da2c1baSMilanka Ringwald                 free(desc);
717da2c1baSMilanka Ringwald             }
727da2c1baSMilanka Ringwald             free(characteristic);
737da2c1baSMilanka Ringwald         }
747da2c1baSMilanka Ringwald         free(service);
757da2c1baSMilanka Ringwald     }
760f7fd6c1SMilanka Ringwald }
77af770404SMilanka Ringwald 
78*ec1a0daeSMilanka Ringwald void mock_gatt_client_set_att_error_discover_primary_services(void){
79*ec1a0daeSMilanka Ringwald     moc_att_error_code_discover_services = ATT_ERROR_REQUEST_NOT_SUPPORTED;
80*ec1a0daeSMilanka Ringwald }
81*ec1a0daeSMilanka Ringwald void mock_gatt_client_set_att_error_discover_characteristics(void){
82*ec1a0daeSMilanka Ringwald     moc_att_error_code_discover_characteristics = ATT_ERROR_REQUEST_NOT_SUPPORTED;
83*ec1a0daeSMilanka Ringwald }
84*ec1a0daeSMilanka Ringwald void mock_gatt_client_set_att_error_discover_characteristic_descriptors(void){
85*ec1a0daeSMilanka Ringwald     moc_att_error_code_discover_characteristic_descriptors = ATT_ERROR_REQUEST_NOT_SUPPORTED;
86*ec1a0daeSMilanka Ringwald }
87*ec1a0daeSMilanka Ringwald 
8876cdba3eSMilanka Ringwald void mock_gatt_client_dump_services(void){
8976cdba3eSMilanka Ringwald     btstack_linked_list_iterator_t service_it;
9076cdba3eSMilanka Ringwald     btstack_linked_list_iterator_init(&service_it, &mock_gatt_client_services);
9176cdba3eSMilanka Ringwald     while (btstack_linked_list_iterator_has_next(&service_it)){
9276cdba3eSMilanka Ringwald         mock_gatt_client_service_t * service = (mock_gatt_client_service_t *) btstack_linked_list_iterator_next(&service_it);
9376cdba3eSMilanka Ringwald         printf("0x%02x: START SERVICE 0%02x\n", service->start_group_handle, service->uuid16);
9476cdba3eSMilanka Ringwald 
9576cdba3eSMilanka Ringwald         btstack_linked_list_iterator_t characteristic_it;
9676cdba3eSMilanka Ringwald         btstack_linked_list_iterator_init(&characteristic_it, &service->characteristics);
9776cdba3eSMilanka Ringwald         while (btstack_linked_list_iterator_has_next(&characteristic_it)){
9876cdba3eSMilanka Ringwald             mock_gatt_client_characteristic_t * characteristic = (mock_gatt_client_characteristic_t *) btstack_linked_list_iterator_next(&characteristic_it);
9976cdba3eSMilanka Ringwald             printf("0x%02x:   START CHR 0%02x\n", characteristic->start_handle, characteristic->uuid16);
10076cdba3eSMilanka Ringwald             printf("0x%02x:   VALUE HANDLE CHR 0%02x\n", characteristic->value_handle, characteristic->uuid16);
10176cdba3eSMilanka Ringwald 
10276cdba3eSMilanka Ringwald             btstack_linked_list_iterator_t desc_it;
10376cdba3eSMilanka Ringwald             btstack_linked_list_iterator_init(&desc_it, &characteristic->descriptors);
10476cdba3eSMilanka Ringwald             while (btstack_linked_list_iterator_has_next(&desc_it)){
10576cdba3eSMilanka Ringwald                 mock_gatt_client_characteristic_descriptor_t * desc = (mock_gatt_client_characteristic_descriptor_t *) btstack_linked_list_iterator_next(&desc_it);
10676cdba3eSMilanka Ringwald                 printf("0x%02x:     DESC 0x%02x\n", desc->handle, desc->uuid16);
10776cdba3eSMilanka Ringwald             }
10876cdba3eSMilanka Ringwald 
10976cdba3eSMilanka Ringwald             printf("0x%02x:   END CHR 0%02x\n", characteristic->end_handle, characteristic->uuid16);
11076cdba3eSMilanka Ringwald 
11176cdba3eSMilanka Ringwald         }
11276cdba3eSMilanka Ringwald         printf("0x%02x: END SERVICE 0%02x\n", service->end_group_handle, service->uuid16);
11376cdba3eSMilanka Ringwald 
11476cdba3eSMilanka Ringwald     }
11576cdba3eSMilanka Ringwald }
11676cdba3eSMilanka Ringwald 
11776cdba3eSMilanka Ringwald mock_gatt_client_service_t * mock_gatt_client_add_primary_service_uuid16(uint16_t service_uuid){
11876cdba3eSMilanka Ringwald     // set lsat group handle
11976cdba3eSMilanka Ringwald     // create new service
1207da2c1baSMilanka Ringwald     mock_gatt_client_last_service = (mock_gatt_client_service_t * )malloc(sizeof(mock_gatt_client_service_t));
1217da2c1baSMilanka Ringwald     memset(mock_gatt_client_last_service, 0, sizeof(mock_gatt_client_service_t));
1227da2c1baSMilanka Ringwald     mock_gatt_client_last_service->uuid16 = service_uuid;
12376cdba3eSMilanka Ringwald     mock_gatt_client_last_service->start_group_handle = mock_gatt_client_att_handle_generator++;
1246ad61799SMilanka Ringwald     mock_gatt_client_last_service->end_group_handle = mock_gatt_client_last_service->start_group_handle;
1255b92fca9SMilanka Ringwald     btstack_linked_list_add_tail(&mock_gatt_client_services, (btstack_linked_item_t*)mock_gatt_client_last_service);
12676cdba3eSMilanka Ringwald     mock_gatt_client_last_characteristic = NULL;
12776cdba3eSMilanka Ringwald     return mock_gatt_client_last_service;
1280f7fd6c1SMilanka Ringwald }
129af770404SMilanka Ringwald 
13076cdba3eSMilanka Ringwald mock_gatt_client_characteristic_t * mock_gatt_client_add_characteristic_uuid16(uint16_t characteristic_uuid, uint16_t properties){
1317da2c1baSMilanka Ringwald     btstack_assert(mock_gatt_client_last_service != NULL);
1327da2c1baSMilanka Ringwald     mock_gatt_client_last_characteristic = (mock_gatt_client_characteristic_t * )malloc(sizeof(mock_gatt_client_characteristic_t));
1337da2c1baSMilanka Ringwald     memset(mock_gatt_client_last_characteristic, 0, sizeof(mock_gatt_client_characteristic_t));
1347da2c1baSMilanka Ringwald     mock_gatt_client_last_characteristic->uuid16 = characteristic_uuid;
13576cdba3eSMilanka Ringwald     mock_gatt_client_last_characteristic->properties = properties;
13676cdba3eSMilanka Ringwald     mock_gatt_client_last_characteristic->start_handle = mock_gatt_client_att_handle_generator++;
13776cdba3eSMilanka Ringwald     mock_gatt_client_last_characteristic->value_handle = mock_gatt_client_att_handle_generator++;
13876cdba3eSMilanka Ringwald     mock_gatt_client_last_characteristic->end_handle = mock_gatt_client_last_characteristic->value_handle;
1395b92fca9SMilanka Ringwald     btstack_linked_list_add_tail(&mock_gatt_client_last_service->characteristics, (btstack_linked_item_t*)mock_gatt_client_last_characteristic);
14076cdba3eSMilanka Ringwald     mock_gatt_client_last_service->end_group_handle = mock_gatt_client_att_handle_generator - 1;
14176cdba3eSMilanka Ringwald     return mock_gatt_client_last_characteristic;
1420f7fd6c1SMilanka Ringwald }
143af770404SMilanka Ringwald 
14476cdba3eSMilanka Ringwald mock_gatt_client_characteristic_descriptor_t * mock_gatt_client_add_characteristic_descriptor_uuid16(uint16_t descriptor_uuid){
14576cdba3eSMilanka Ringwald     btstack_assert(mock_gatt_client_last_characteristic != NULL);
1467da2c1baSMilanka Ringwald     mock_gatt_client_characteristic_descriptor_t * desc = (mock_gatt_client_characteristic_descriptor_t * )malloc(sizeof(mock_gatt_client_characteristic_descriptor_t));
1477da2c1baSMilanka Ringwald     memset(desc, 0, sizeof(mock_gatt_client_characteristic_descriptor_t));
1487da2c1baSMilanka Ringwald     desc->uuid16 = descriptor_uuid;
14976cdba3eSMilanka Ringwald     desc->handle = mock_gatt_client_att_handle_generator++;
1505b92fca9SMilanka Ringwald     btstack_linked_list_add_tail(&mock_gatt_client_last_characteristic->descriptors, (btstack_linked_item_t*)desc);
15176cdba3eSMilanka Ringwald     mock_gatt_client_last_characteristic->end_handle = mock_gatt_client_att_handle_generator - 1;
15276cdba3eSMilanka Ringwald     mock_gatt_client_last_service->end_group_handle = mock_gatt_client_att_handle_generator - 1;
15376cdba3eSMilanka Ringwald     return desc;
1540f7fd6c1SMilanka Ringwald }
1550f7fd6c1SMilanka Ringwald 
15676cdba3eSMilanka Ringwald static mock_gatt_client_characteristic_t * mock_gatt_client_get_characteristic_for_value_handle(uint16_t value_handle){
15776cdba3eSMilanka Ringwald     btstack_linked_list_iterator_t service_it;
15876cdba3eSMilanka Ringwald     btstack_linked_list_iterator_t characteristic_it;
15976cdba3eSMilanka Ringwald 
16076cdba3eSMilanka Ringwald     btstack_linked_list_iterator_init(&service_it, &mock_gatt_client_services);
16176cdba3eSMilanka Ringwald     while (btstack_linked_list_iterator_has_next(&service_it)){
16276cdba3eSMilanka Ringwald         mock_gatt_client_service_t * service = (mock_gatt_client_service_t *) btstack_linked_list_iterator_next(&service_it);
16376cdba3eSMilanka Ringwald 
16476cdba3eSMilanka Ringwald         btstack_linked_list_iterator_init(&characteristic_it, &service->characteristics);
16576cdba3eSMilanka Ringwald         while (btstack_linked_list_iterator_has_next(&characteristic_it)){
16676cdba3eSMilanka Ringwald             mock_gatt_client_characteristic_t * characteristic = (mock_gatt_client_characteristic_t *) btstack_linked_list_iterator_next(&characteristic_it);
16776cdba3eSMilanka Ringwald             if (characteristic->value_handle != value_handle) continue;
16876cdba3eSMilanka Ringwald             return characteristic;
16976cdba3eSMilanka Ringwald         }
17076cdba3eSMilanka Ringwald     }
17176cdba3eSMilanka Ringwald     return NULL;
17276cdba3eSMilanka Ringwald }
17376cdba3eSMilanka Ringwald 
17476cdba3eSMilanka Ringwald static mock_gatt_client_characteristic_descriptor_t * mock_gatt_client_get_characteristic_descriptor_for_handle(uint16_t handle){
17576cdba3eSMilanka Ringwald     btstack_linked_list_iterator_t service_it;
17676cdba3eSMilanka Ringwald     btstack_linked_list_iterator_t characteristic_it;
17776cdba3eSMilanka Ringwald 
17876cdba3eSMilanka Ringwald     btstack_linked_list_iterator_init(&service_it, &mock_gatt_client_services);
17976cdba3eSMilanka Ringwald     while (btstack_linked_list_iterator_has_next(&service_it)){
18076cdba3eSMilanka Ringwald         mock_gatt_client_service_t * service = (mock_gatt_client_service_t *) btstack_linked_list_iterator_next(&service_it);
18176cdba3eSMilanka Ringwald 
18276cdba3eSMilanka Ringwald         btstack_linked_list_iterator_init(&characteristic_it, &service->characteristics);
18376cdba3eSMilanka Ringwald         while (btstack_linked_list_iterator_has_next(&characteristic_it)){
18476cdba3eSMilanka Ringwald             mock_gatt_client_characteristic_t * characteristic = (mock_gatt_client_characteristic_t *) btstack_linked_list_iterator_next(&characteristic_it);
18576cdba3eSMilanka Ringwald 
18676cdba3eSMilanka Ringwald             btstack_linked_list_iterator_t desc_it;
18776cdba3eSMilanka Ringwald             btstack_linked_list_iterator_init(&desc_it, &characteristic->descriptors);
18876cdba3eSMilanka Ringwald             while (btstack_linked_list_iterator_has_next(&desc_it)){
18976cdba3eSMilanka Ringwald                 mock_gatt_client_characteristic_descriptor_t * desc = (mock_gatt_client_characteristic_descriptor_t *) btstack_linked_list_iterator_next(&desc_it);
19076cdba3eSMilanka Ringwald                 if (desc->handle != handle) continue;
19176cdba3eSMilanka Ringwald                 return desc;
19276cdba3eSMilanka Ringwald             }
19376cdba3eSMilanka Ringwald         }
19476cdba3eSMilanka Ringwald     }
19576cdba3eSMilanka Ringwald     return NULL;
19676cdba3eSMilanka Ringwald }
19776cdba3eSMilanka Ringwald 
19876cdba3eSMilanka Ringwald 
19976cdba3eSMilanka Ringwald void mock_gatt_client_set_characteristic_value(mock_gatt_client_characteristic_descriptor_t * descriptor, uint8_t * value_buffer, uint16_t value_len){
20076cdba3eSMilanka Ringwald     btstack_assert(descriptor != NULL);
20176cdba3eSMilanka Ringwald     descriptor->value_buffer = value_buffer;
20276cdba3eSMilanka Ringwald     descriptor->value_len = value_len;
20376cdba3eSMilanka Ringwald }
2047da2c1baSMilanka Ringwald 
205af770404SMilanka Ringwald // simulate erro
206af770404SMilanka Ringwald void mock_gatt_client_simulate_att_error(uint8_t att_error){
207af770404SMilanka Ringwald     mock_gatt_client_att_error = att_error;
2080f7fd6c1SMilanka Ringwald }
2090f7fd6c1SMilanka Ringwald 
2100f7fd6c1SMilanka Ringwald uint8_t gatt_client_discover_primary_services_by_uuid16(btstack_packet_handler_t callback, hci_con_handle_t con_handle, uint16_t uuid16){
211d41a8f51SMilanka Ringwald     mock_gatt_client_state = MOCK_QUERY_DISCOVER_PRIMARY_SERVICES_BY_UUID16;
212af770404SMilanka Ringwald     mock_gatt_client_uuid = uuid16;
213af770404SMilanka Ringwald 
214af770404SMilanka Ringwald     gatt_client.callback = callback;
215af770404SMilanka Ringwald     gatt_client.con_handle = con_handle;
2160f7fd6c1SMilanka Ringwald     return ERROR_CODE_SUCCESS;
2170f7fd6c1SMilanka Ringwald }
2180f7fd6c1SMilanka Ringwald 
2190f7fd6c1SMilanka Ringwald uint8_t gatt_client_discover_characteristics_for_handle_range_by_uuid16(btstack_packet_handler_t callback, hci_con_handle_t con_handle, uint16_t start_handle, uint16_t end_handle, uint16_t uuid16){
220d41a8f51SMilanka Ringwald     mock_gatt_client_state = MOCK_QUERY_DISCOVER_CHARACTERISTICS_BY_UUID16;
2217da2c1baSMilanka Ringwald     mock_gatt_client_uuid = uuid16;
22276cdba3eSMilanka Ringwald     mock_gatt_client_start_handle = start_handle;
22376cdba3eSMilanka Ringwald     mock_gatt_client_end_handle = end_handle;
2247da2c1baSMilanka Ringwald 
2257da2c1baSMilanka Ringwald     gatt_client.callback = callback;
2267da2c1baSMilanka Ringwald     gatt_client.con_handle = con_handle;
2270f7fd6c1SMilanka Ringwald     return ERROR_CODE_SUCCESS;
2280f7fd6c1SMilanka Ringwald }
2290f7fd6c1SMilanka Ringwald 
2300f7fd6c1SMilanka Ringwald uint8_t gatt_client_discover_characteristic_descriptors(btstack_packet_handler_t callback, hci_con_handle_t con_handle, gatt_client_characteristic_t * characteristic){
23176cdba3eSMilanka Ringwald     mock_gatt_client_state = MOCK_QUERY_DISCOVER_CHARACTERISTIC_DESCRIPTORS;
23276cdba3eSMilanka Ringwald     mock_gatt_client_value_handle = characteristic->value_handle;
23376cdba3eSMilanka Ringwald 
23476cdba3eSMilanka Ringwald     gatt_client.callback = callback;
23576cdba3eSMilanka Ringwald     gatt_client.con_handle = con_handle;
23676cdba3eSMilanka Ringwald     return ERROR_CODE_SUCCESS;
23776cdba3eSMilanka Ringwald }
23876cdba3eSMilanka Ringwald 
23976cdba3eSMilanka Ringwald uint8_t gatt_client_write_client_characteristic_configuration(btstack_packet_handler_t callback, hci_con_handle_t con_handle, gatt_client_characteristic_t * characteristic, uint16_t configuration){
24076cdba3eSMilanka Ringwald     mock_gatt_client_state = MOCK_WRITE_CLIENT_CHARACTERISTIC_CONFIGURATION;
24176cdba3eSMilanka Ringwald     mock_gatt_client_uuid = characteristic->uuid16;
24276cdba3eSMilanka Ringwald 
24376cdba3eSMilanka Ringwald     gatt_client.callback = callback;
24476cdba3eSMilanka Ringwald     gatt_client.con_handle = con_handle;
24576cdba3eSMilanka Ringwald     return ERROR_CODE_SUCCESS;
24676cdba3eSMilanka Ringwald }
24776cdba3eSMilanka Ringwald 
24876cdba3eSMilanka Ringwald void gatt_client_listen_for_characteristic_value_updates(gatt_client_notification_t * notification, btstack_packet_handler_t callback, hci_con_handle_t con_handle, gatt_client_characteristic_t * characteristic){
24976cdba3eSMilanka Ringwald     notification->callback = callback;
25076cdba3eSMilanka Ringwald     notification->con_handle = con_handle;
25176cdba3eSMilanka Ringwald 
25276cdba3eSMilanka Ringwald     if (characteristic == NULL){
25376cdba3eSMilanka Ringwald         // 'all characteristics': not used yet
254af770404SMilanka Ringwald         btstack_assert(false);
25576cdba3eSMilanka Ringwald     } else {
25676cdba3eSMilanka Ringwald         notification->attribute_handle = characteristic->value_handle;
25776cdba3eSMilanka Ringwald     }
25876cdba3eSMilanka Ringwald 
25976cdba3eSMilanka Ringwald     // finc our characteristic and set point to notification
26076cdba3eSMilanka Ringwald }
26176cdba3eSMilanka Ringwald 
26276cdba3eSMilanka Ringwald 
26376cdba3eSMilanka Ringwald uint8_t gatt_client_read_value_of_characteristic_using_value_handle(btstack_packet_handler_t callback, hci_con_handle_t con_handle, uint16_t value_handle){
26476cdba3eSMilanka Ringwald     mock_gatt_client_state = MOCK_READ_VALUE_OF_CHARACTERISTIC_USING_VALUE_HANDLE;
26576cdba3eSMilanka Ringwald     mock_gatt_client_value_handle = value_handle;
266af770404SMilanka Ringwald     return ERROR_CODE_SUCCESS;
267af770404SMilanka Ringwald }
268af770404SMilanka Ringwald 
269af770404SMilanka Ringwald uint8_t gatt_client_read_value_of_characteristic(btstack_packet_handler_t callback, hci_con_handle_t con_handle, gatt_client_characteristic_t * characteristic){
27024152f08SMilanka Ringwald     btstack_assert(characteristic != NULL);
27124152f08SMilanka Ringwald     mock_gatt_client_state = MOCK_READ_VALUE_OF_CHARACTERISTIC_USING_VALUE_HANDLE;
27224152f08SMilanka Ringwald     mock_gatt_client_characteristic_t * mock_characteristic = mock_gatt_client_get_characteristic_for_value_handle(characteristic->value_handle);
27324152f08SMilanka Ringwald 
27424152f08SMilanka Ringwald     btstack_assert(mock_characteristic != NULL);
27524152f08SMilanka Ringwald 
27624152f08SMilanka Ringwald     mock_gatt_client_value_handle = mock_characteristic->value_handle;
2770f7fd6c1SMilanka Ringwald     return ERROR_CODE_SUCCESS;
2780f7fd6c1SMilanka Ringwald }
2790f7fd6c1SMilanka Ringwald 
280af770404SMilanka Ringwald void gatt_client_stop_listening_for_characteristic_value_updates(gatt_client_notification_t * notification){
281af770404SMilanka Ringwald }
282af770404SMilanka Ringwald 
283af770404SMilanka Ringwald /**
284af770404SMilanka Ringwald  * copied from gatt_client.c - START
285af770404SMilanka Ringwald  */
2860f7fd6c1SMilanka Ringwald void gatt_client_deserialize_service(const uint8_t *packet, int offset, gatt_client_service_t * service){
2870f7fd6c1SMilanka Ringwald     service->start_group_handle = little_endian_read_16(packet, offset);
2880f7fd6c1SMilanka Ringwald     service->end_group_handle = little_endian_read_16(packet, offset + 2);
2890f7fd6c1SMilanka Ringwald     reverse_128(&packet[offset + 4], service->uuid128);
2900f7fd6c1SMilanka Ringwald     if (uuid_has_bluetooth_prefix(service->uuid128)){
2910f7fd6c1SMilanka Ringwald         service->uuid16 = big_endian_read_32(service->uuid128, 0);
2920f7fd6c1SMilanka Ringwald     } else {
2930f7fd6c1SMilanka Ringwald         service->uuid16 = 0;
2940f7fd6c1SMilanka Ringwald     }
2950f7fd6c1SMilanka Ringwald }
2960f7fd6c1SMilanka Ringwald 
2970f7fd6c1SMilanka Ringwald void gatt_client_deserialize_characteristic(const uint8_t * packet, int offset, gatt_client_characteristic_t * characteristic){
2980f7fd6c1SMilanka Ringwald     characteristic->start_handle = little_endian_read_16(packet, offset);
2990f7fd6c1SMilanka Ringwald     characteristic->value_handle = little_endian_read_16(packet, offset + 2);
3000f7fd6c1SMilanka Ringwald     characteristic->end_handle = little_endian_read_16(packet, offset + 4);
3010f7fd6c1SMilanka Ringwald     characteristic->properties = little_endian_read_16(packet, offset + 6);
3020f7fd6c1SMilanka Ringwald     reverse_128(&packet[offset+8], characteristic->uuid128);
3030f7fd6c1SMilanka Ringwald     if (uuid_has_bluetooth_prefix(characteristic->uuid128)){
3040f7fd6c1SMilanka Ringwald         characteristic->uuid16 = big_endian_read_32(characteristic->uuid128, 0);
3050f7fd6c1SMilanka Ringwald     } else {
3060f7fd6c1SMilanka Ringwald         characteristic->uuid16 = 0;
3070f7fd6c1SMilanka Ringwald     }
3080f7fd6c1SMilanka Ringwald }
3090f7fd6c1SMilanka Ringwald 
3100f7fd6c1SMilanka Ringwald void gatt_client_deserialize_characteristic_descriptor(const uint8_t * packet, int offset, gatt_client_characteristic_descriptor_t * descriptor){
3110f7fd6c1SMilanka Ringwald     descriptor->handle = little_endian_read_16(packet, offset);
3120f7fd6c1SMilanka Ringwald     reverse_128(&packet[offset+2], descriptor->uuid128);
3130f7fd6c1SMilanka Ringwald     if (uuid_has_bluetooth_prefix(descriptor->uuid128)){
3140f7fd6c1SMilanka Ringwald         descriptor->uuid16 = big_endian_read_32(descriptor->uuid128, 0);
3150f7fd6c1SMilanka Ringwald     } else {
3160f7fd6c1SMilanka Ringwald         descriptor->uuid16 = 0;
3170f7fd6c1SMilanka Ringwald     }
3180f7fd6c1SMilanka Ringwald }
3190f7fd6c1SMilanka Ringwald 
320af770404SMilanka Ringwald static void emit_event_new(btstack_packet_handler_t callback, uint8_t * packet, uint16_t size){
321af770404SMilanka Ringwald     if (!callback) return;
322af770404SMilanka Ringwald     (*callback)(HCI_EVENT_PACKET, 0, packet, size);
3230f7fd6c1SMilanka Ringwald }
3240f7fd6c1SMilanka Ringwald 
325af770404SMilanka Ringwald static void emit_gatt_complete_event(gatt_client_t * gatt_client, uint8_t att_status){
326af770404SMilanka Ringwald     // @format H1
327af770404SMilanka Ringwald     uint8_t packet[5];
328af770404SMilanka Ringwald     packet[0] = GATT_EVENT_QUERY_COMPLETE;
329af770404SMilanka Ringwald     packet[1] = 3;
330af770404SMilanka Ringwald     little_endian_store_16(packet, 2, gatt_client->con_handle);
331af770404SMilanka Ringwald     packet[4] = att_status;
332af770404SMilanka Ringwald     emit_event_new(gatt_client->callback, packet, sizeof(packet));
3330f7fd6c1SMilanka Ringwald }
3340f7fd6c1SMilanka Ringwald 
3357da2c1baSMilanka Ringwald static void emit_gatt_service_query_result_event(gatt_client_t * gatt_client, uint16_t start_group_handle, uint16_t end_group_handle, const uint8_t * uuid128){
3367da2c1baSMilanka Ringwald     // @format HX
3377da2c1baSMilanka Ringwald     uint8_t packet[24];
3387da2c1baSMilanka Ringwald     packet[0] = GATT_EVENT_SERVICE_QUERY_RESULT;
3397da2c1baSMilanka Ringwald     packet[1] = sizeof(packet) - 2u;
3407da2c1baSMilanka Ringwald     little_endian_store_16(packet, 2, gatt_client->con_handle);
3417da2c1baSMilanka Ringwald     ///
3427da2c1baSMilanka Ringwald     little_endian_store_16(packet, 4, start_group_handle);
3437da2c1baSMilanka Ringwald     little_endian_store_16(packet, 6, end_group_handle);
3447da2c1baSMilanka Ringwald     reverse_128(uuid128, &packet[8]);
3457da2c1baSMilanka Ringwald     emit_event_new(gatt_client->callback, packet, sizeof(packet));
3467da2c1baSMilanka Ringwald }
3477da2c1baSMilanka Ringwald 
3487da2c1baSMilanka Ringwald static void emit_gatt_characteristic_query_result_event(gatt_client_t * gatt_client, uint16_t start_handle, uint16_t value_handle, uint16_t end_handle,
3497da2c1baSMilanka Ringwald                                                         uint16_t properties, const uint8_t * uuid128){
3507da2c1baSMilanka Ringwald     // @format HY
3517da2c1baSMilanka Ringwald     uint8_t packet[28];
3527da2c1baSMilanka Ringwald     packet[0] = GATT_EVENT_CHARACTERISTIC_QUERY_RESULT;
3537da2c1baSMilanka Ringwald     packet[1] = sizeof(packet) - 2u;
3547da2c1baSMilanka Ringwald     little_endian_store_16(packet, 2, gatt_client->con_handle);
3557da2c1baSMilanka Ringwald     ///
3567da2c1baSMilanka Ringwald     little_endian_store_16(packet, 4,  start_handle);
3577da2c1baSMilanka Ringwald     little_endian_store_16(packet, 6,  value_handle);
3587da2c1baSMilanka Ringwald     little_endian_store_16(packet, 8,  end_handle);
3597da2c1baSMilanka Ringwald     little_endian_store_16(packet, 10, properties);
3607da2c1baSMilanka Ringwald     reverse_128(uuid128, &packet[12]);
3617da2c1baSMilanka Ringwald     emit_event_new(gatt_client->callback, packet, sizeof(packet));
3627da2c1baSMilanka Ringwald }
3637da2c1baSMilanka Ringwald 
36476cdba3eSMilanka Ringwald static void emit_gatt_all_characteristic_descriptors_result_event(
36576cdba3eSMilanka Ringwald         gatt_client_t * gatt_client, uint16_t descriptor_handle, const uint8_t * uuid128){
36676cdba3eSMilanka Ringwald     // @format HZ
36776cdba3eSMilanka Ringwald     uint8_t packet[22];
36876cdba3eSMilanka Ringwald     packet[0] = GATT_EVENT_ALL_CHARACTERISTIC_DESCRIPTORS_QUERY_RESULT;
36976cdba3eSMilanka Ringwald     packet[1] = sizeof(packet) - 2u;
37076cdba3eSMilanka Ringwald     little_endian_store_16(packet, 2, gatt_client->con_handle);
37176cdba3eSMilanka Ringwald     ///
37276cdba3eSMilanka Ringwald     little_endian_store_16(packet, 4,  descriptor_handle);
37376cdba3eSMilanka Ringwald     reverse_128(uuid128, &packet[6]);
37476cdba3eSMilanka Ringwald     emit_event_new(gatt_client->callback, packet, sizeof(packet));
37576cdba3eSMilanka Ringwald }
37676cdba3eSMilanka Ringwald 
37776cdba3eSMilanka Ringwald 
37876cdba3eSMilanka Ringwald static const int characteristic_value_event_header_size = 8;
37976cdba3eSMilanka Ringwald static uint8_t * setup_characteristic_value_packet(uint8_t type, hci_con_handle_t con_handle, uint16_t attribute_handle, uint8_t * value, uint16_t length){
38076cdba3eSMilanka Ringwald     // before the value inside the ATT PDU
38176cdba3eSMilanka Ringwald     uint8_t * packet = value - characteristic_value_event_header_size;
38276cdba3eSMilanka Ringwald     packet[0] = type;
38376cdba3eSMilanka Ringwald     packet[1] = characteristic_value_event_header_size - 2 + length;
38476cdba3eSMilanka Ringwald     little_endian_store_16(packet, 2, con_handle);
38576cdba3eSMilanka Ringwald     little_endian_store_16(packet, 4, attribute_handle);
38676cdba3eSMilanka Ringwald     little_endian_store_16(packet, 6, length);
38776cdba3eSMilanka Ringwald     return packet;
38876cdba3eSMilanka Ringwald }
38976cdba3eSMilanka Ringwald 
39076cdba3eSMilanka Ringwald // @note assume that value is part of an l2cap buffer - overwrite parts of the HCI/L2CAP/ATT packet (4/4/3) bytes
39176cdba3eSMilanka Ringwald static void report_gatt_characteristic_value(gatt_client_t * gatt_client, uint16_t attribute_handle, uint8_t * value, uint16_t length){
39276cdba3eSMilanka Ringwald     uint8_t * packet = setup_characteristic_value_packet(GATT_EVENT_CHARACTERISTIC_VALUE_QUERY_RESULT, gatt_client->con_handle, attribute_handle, value, length);
39376cdba3eSMilanka Ringwald     emit_event_new(gatt_client->callback, packet, characteristic_value_event_header_size + length);
39476cdba3eSMilanka Ringwald }
39576cdba3eSMilanka Ringwald 
396af770404SMilanka Ringwald /**
397af770404SMilanka Ringwald  * copied from gatt_client.c - END
398af770404SMilanka Ringwald  */
3990f7fd6c1SMilanka Ringwald 
4007da2c1baSMilanka Ringwald static void mock_gatt_client_emit_complete(uint8_t status){
4017da2c1baSMilanka Ringwald     mock_gatt_client_state = MOCK_QUERY_IDLE;
4027da2c1baSMilanka Ringwald     emit_gatt_complete_event(&gatt_client, status);
4037da2c1baSMilanka Ringwald }
4040f7fd6c1SMilanka Ringwald 
405af770404SMilanka Ringwald void mock_gatt_client_run(void){
406af770404SMilanka Ringwald     btstack_assert(mock_gatt_client_state != MOCK_QUERY_IDLE);
40776cdba3eSMilanka Ringwald     mock_gatt_client_characteristic_t * characteristic;
40876cdba3eSMilanka Ringwald     mock_gatt_client_characteristic_descriptor_t * descriptor;
40976cdba3eSMilanka Ringwald 
4107da2c1baSMilanka Ringwald     btstack_linked_list_iterator_t service_it;
4117da2c1baSMilanka Ringwald     btstack_linked_list_iterator_t characteristic_it;
41276cdba3eSMilanka Ringwald     btstack_linked_list_iterator_t descriptor_it;
41376cdba3eSMilanka Ringwald 
4147da2c1baSMilanka Ringwald     uint8_t uuid128[16];
4157da2c1baSMilanka Ringwald 
4167da2c1baSMilanka Ringwald     while (mock_gatt_client_state != MOCK_QUERY_IDLE){
417af770404SMilanka Ringwald         switch (mock_gatt_client_state){
418d41a8f51SMilanka Ringwald             case MOCK_QUERY_DISCOVER_PRIMARY_SERVICES_BY_UUID16:
419af770404SMilanka Ringwald                 // emit GATT_EVENT_SERVICE_QUERY_RESULT for each matching service
420*ec1a0daeSMilanka Ringwald                 if (moc_att_error_code_discover_services != ATT_ERROR_SUCCESS){
421*ec1a0daeSMilanka Ringwald                     mock_gatt_client_emit_complete(moc_att_error_code_discover_services);
422*ec1a0daeSMilanka Ringwald                     return;
423*ec1a0daeSMilanka Ringwald                 }
424*ec1a0daeSMilanka Ringwald 
4257da2c1baSMilanka Ringwald                 btstack_linked_list_iterator_init(&service_it, &mock_gatt_client_services);
4267da2c1baSMilanka Ringwald                 while (btstack_linked_list_iterator_has_next(&service_it)){
4277da2c1baSMilanka Ringwald                     mock_gatt_client_service_t * service = (mock_gatt_client_service_t *) btstack_linked_list_iterator_next(&service_it);
4287da2c1baSMilanka Ringwald                     if (service->uuid16 != mock_gatt_client_uuid) continue;
4297da2c1baSMilanka Ringwald                     mock_gatt_client_last_service = service;
4307da2c1baSMilanka Ringwald                     uuid_add_bluetooth_prefix(uuid128, service->uuid16);
43176cdba3eSMilanka Ringwald                     emit_gatt_service_query_result_event(&gatt_client, service->start_group_handle, service->end_group_handle, uuid128);
4327da2c1baSMilanka Ringwald                 }
4337da2c1baSMilanka Ringwald                 // emit GATT_EVENT_QUERY_COMPLETE
4347da2c1baSMilanka Ringwald                 mock_gatt_client_emit_complete(ATT_ERROR_SUCCESS);
4357da2c1baSMilanka Ringwald                 break;
4367da2c1baSMilanka Ringwald 
437d41a8f51SMilanka Ringwald             case MOCK_QUERY_DISCOVER_CHARACTERISTICS_BY_UUID16:
4387da2c1baSMilanka Ringwald                 // emit GATT_EVENT_CHARACTERISTIC_QUERY_RESULT for each matching characteristic
439*ec1a0daeSMilanka Ringwald                 if (moc_att_error_code_discover_characteristics != ATT_ERROR_SUCCESS){
440*ec1a0daeSMilanka Ringwald                     mock_gatt_client_emit_complete(moc_att_error_code_discover_characteristics);
441*ec1a0daeSMilanka Ringwald                     return;
442*ec1a0daeSMilanka Ringwald                 }
443*ec1a0daeSMilanka Ringwald 
4447da2c1baSMilanka Ringwald                 btstack_linked_list_iterator_init(&service_it, &mock_gatt_client_services);
4457da2c1baSMilanka Ringwald                 while (btstack_linked_list_iterator_has_next(&service_it)){
4467da2c1baSMilanka Ringwald                     mock_gatt_client_service_t * service = (mock_gatt_client_service_t *) btstack_linked_list_iterator_next(&service_it);
4477da2c1baSMilanka Ringwald 
4487da2c1baSMilanka Ringwald                     btstack_linked_list_iterator_init(&characteristic_it, &service->characteristics);
4497da2c1baSMilanka Ringwald                     while (btstack_linked_list_iterator_has_next(&characteristic_it)){
4507da2c1baSMilanka Ringwald                         mock_gatt_client_characteristic_t * characteristic = (mock_gatt_client_characteristic_t *) btstack_linked_list_iterator_next(&characteristic_it);
4517da2c1baSMilanka Ringwald                         if (characteristic->uuid16 != mock_gatt_client_uuid) continue;
45276cdba3eSMilanka Ringwald                         if (characteristic->start_handle < mock_gatt_client_start_handle) continue;
45376cdba3eSMilanka Ringwald                         if (characteristic->end_handle > mock_gatt_client_end_handle) continue;
45476cdba3eSMilanka Ringwald 
4557da2c1baSMilanka Ringwald                         uuid_add_bluetooth_prefix(uuid128, characteristic->uuid16);
45676cdba3eSMilanka Ringwald                         emit_gatt_characteristic_query_result_event(&gatt_client,
45776cdba3eSMilanka Ringwald                             characteristic->start_handle, characteristic->value_handle, characteristic->end_handle,
45876cdba3eSMilanka Ringwald                             characteristic->properties, uuid128);
4597da2c1baSMilanka Ringwald                     }
4607da2c1baSMilanka Ringwald                 }
4617da2c1baSMilanka Ringwald 
4627da2c1baSMilanka Ringwald                 // emit GATT_EVENT_QUERY_COMPLETE
4637da2c1baSMilanka Ringwald                 mock_gatt_client_emit_complete(ERROR_CODE_SUCCESS);
464af770404SMilanka Ringwald                 break;
46576cdba3eSMilanka Ringwald 
46676cdba3eSMilanka Ringwald             case MOCK_QUERY_DISCOVER_CHARACTERISTIC_DESCRIPTORS:
46776cdba3eSMilanka Ringwald                 characteristic = mock_gatt_client_get_characteristic_for_value_handle(mock_gatt_client_value_handle);
46876cdba3eSMilanka Ringwald                 btstack_assert(characteristic != NULL);
46976cdba3eSMilanka Ringwald 
470*ec1a0daeSMilanka Ringwald                 if (moc_att_error_code_discover_characteristic_descriptors != ATT_ERROR_SUCCESS){
471*ec1a0daeSMilanka Ringwald                     mock_gatt_client_emit_complete(moc_att_error_code_discover_characteristic_descriptors);
472*ec1a0daeSMilanka Ringwald                     return;
473*ec1a0daeSMilanka Ringwald                 }
474*ec1a0daeSMilanka Ringwald 
47576cdba3eSMilanka Ringwald                 btstack_linked_list_iterator_init(&descriptor_it, &characteristic->descriptors);
47676cdba3eSMilanka Ringwald                 while (btstack_linked_list_iterator_has_next(&descriptor_it)){
47776cdba3eSMilanka Ringwald                     mock_gatt_client_characteristic_descriptor_t * desc = (mock_gatt_client_characteristic_descriptor_t *) btstack_linked_list_iterator_next(&descriptor_it);
47876cdba3eSMilanka Ringwald 
47976cdba3eSMilanka Ringwald                     uuid_add_bluetooth_prefix(uuid128, desc->uuid16);
48076cdba3eSMilanka Ringwald                     emit_gatt_all_characteristic_descriptors_result_event(&gatt_client, desc->handle, uuid128);
48176cdba3eSMilanka Ringwald                 }
48276cdba3eSMilanka Ringwald 
48376cdba3eSMilanka Ringwald                 // emit GATT_EVENT_QUERY_COMPLETE
48476cdba3eSMilanka Ringwald                 mock_gatt_client_emit_complete(ERROR_CODE_SUCCESS);
48576cdba3eSMilanka Ringwald                 break;
48676cdba3eSMilanka Ringwald 
48776cdba3eSMilanka Ringwald             case MOCK_WRITE_CLIENT_CHARACTERISTIC_CONFIGURATION:
48876cdba3eSMilanka Ringwald                 mock_gatt_client_emit_complete(ERROR_CODE_SUCCESS);
48976cdba3eSMilanka Ringwald                 break;
49076cdba3eSMilanka Ringwald 
49176cdba3eSMilanka Ringwald             case MOCK_READ_VALUE_OF_CHARACTERISTIC_USING_VALUE_HANDLE:
49276cdba3eSMilanka Ringwald                 descriptor = mock_gatt_client_get_characteristic_descriptor_for_handle(mock_gatt_client_value_handle);
49376cdba3eSMilanka Ringwald                 btstack_assert(descriptor != NULL);
49476cdba3eSMilanka Ringwald                 btstack_assert(descriptor->value_buffer != NULL);
49576cdba3eSMilanka Ringwald 
49676cdba3eSMilanka Ringwald                 report_gatt_characteristic_value(&gatt_client, descriptor->handle, descriptor->value_buffer, descriptor->value_len);
49776cdba3eSMilanka Ringwald                 mock_gatt_client_emit_complete(ERROR_CODE_SUCCESS);
49876cdba3eSMilanka Ringwald                 break;
49976cdba3eSMilanka Ringwald 
500af770404SMilanka Ringwald             default:
501af770404SMilanka Ringwald                 btstack_assert(false);
502af770404SMilanka Ringwald                 break;
5030f7fd6c1SMilanka Ringwald         }
5047da2c1baSMilanka Ringwald     }
5057da2c1baSMilanka Ringwald     mock_gatt_client_att_error = ERROR_CODE_SUCCESS;
506af770404SMilanka Ringwald     mock_gatt_client_state = MOCK_QUERY_IDLE;
5070f7fd6c1SMilanka Ringwald }