xref: /btstack/test/gatt-service-client/ancs_client_test.cpp (revision 77bf845768a9c39a5561c69033c0112e62f08947)
1 // *****************************************************************************
2 //
3 // test ANCS Client
4 //
5 // *****************************************************************************
6 
7 
8 #include <stdint.h>
9 #include <stdio.h>
10 #include <stdlib.h>
11 #include <string.h>
12 
13 #include "CppUTest/TestHarness.h"
14 #include "CppUTest/CommandLineTestRunner.h"
15 #include "CppUTestExt/MockSupport.h"
16 
17 #include "bluetooth.h"
18 #include "bluetooth_gatt.h"
19 #include "btstack_debug.h"
20 #include "btstack_event.h"
21 #include "btstack_memory.h"
22 #include "btstack_util.h"
23 #include "hci.h"
24 
25 #include "ble/gatt-service/ancs_client.h"
26 #include "mock_gatt_client.h"
27 
28 extern "C" void ancs_client_set_invalid_parser_state(void);
29 
30 // mock hci
31 
32 static const uint8_t ancs_service_uuid[] =             {0x79,0x05,0xF4,0x31,0xB5,0xCE,0x4E,0x99,0xA4,0x0F,0x4B,0x1E,0x12,0x2D,0x00,0xD0};
33 static const uint8_t ancs_notification_source_uuid[] = {0x9F,0xBF,0x12,0x0D,0x63,0x01,0x42,0xD9,0x8C,0x58,0x25,0xE6,0x99,0xA2,0x1D,0xBD};
34 static const uint8_t ancs_control_point_uuid[] =       {0x69,0xD1,0xD8,0xF3,0x45,0xE1,0x49,0xA8,0x98,0x21,0x9B,0xBD,0xFD,0xAA,0xD9,0xD9};
35 static const uint8_t ancs_data_source_uuid[] =         {0x22,0xEA,0xC6,0xE9,0x24,0xD6,0x4B,0xB5,0xBE,0x44,0xB3,0x6A,0xCE,0x7C,0x7B,0xFB};
36 
37 static btstack_packet_callback_registration_t * ancs_callback_registration;
38 static const hci_con_handle_t ancs_con_handle = 0x001;
39 static bool ancs_connected;
40 
41 void hci_add_event_handler(btstack_packet_callback_registration_t * callback_handler){
42     ancs_callback_registration = callback_handler;
43 }
44 
45 static void hci_emit_event(uint8_t * event, uint16_t size, int dump){
46     btstack_assert(ancs_callback_registration != NULL);
47     (*ancs_callback_registration->callback)(HCI_EVENT_PACKET, 0, event, size);
48 }
49 
50 static void hci_create_gap_connection_complete_event(const uint8_t * hci_event, uint8_t * gap_event) {
51     gap_event[0] = HCI_EVENT_META_GAP;
52     gap_event[1] = 36 - 2;
53     gap_event[2] = GAP_SUBEVENT_LE_CONNECTION_COMPLETE;
54     switch (hci_event[2]){
55         case HCI_SUBEVENT_LE_CONNECTION_COMPLETE:
56             memcpy(&gap_event[3], &hci_event[3], 11);
57         memset(&gap_event[14], 0, 12);
58         memcpy(&gap_event[26], &hci_event[14], 7);
59         memset(&gap_event[33], 0xff, 3);
60         break;
61         case HCI_SUBEVENT_LE_ENHANCED_CONNECTION_COMPLETE_V1:
62             memcpy(&gap_event[3], &hci_event[3], 30);
63         memset(&gap_event[33], 0xff, 3);
64         break;
65         case HCI_SUBEVENT_LE_ENHANCED_CONNECTION_COMPLETE_V2:
66             memcpy(&gap_event[3], &hci_event[3], 33);
67         break;
68         default:
69             btstack_unreachable();
70         break;
71     }
72 }
73 
74 static void hci_emit_le_connection_complete(uint8_t address_type, const bd_addr_t address, hci_con_handle_t con_handle, uint8_t status){
75     uint8_t hci_event[21];
76     hci_event[0] = HCI_EVENT_LE_META;
77     hci_event[1] = sizeof(hci_event) - 2u;
78     hci_event[2] = HCI_SUBEVENT_LE_CONNECTION_COMPLETE;
79     hci_event[3] = status;
80     little_endian_store_16(hci_event, 4, con_handle);
81     hci_event[6] = 0; // TODO: role
82     hci_event[7] = address_type;
83     reverse_bd_addr(address, &hci_event[8]);
84     little_endian_store_16(hci_event, 14, 0); // interval
85     little_endian_store_16(hci_event, 16, 0); // latency
86     little_endian_store_16(hci_event, 18, 0); // supervision timeout
87     hci_event[20] = 0; // master clock accuracy
88     // emit GAP event, too
89     uint8_t gap_event[36];
90     hci_create_gap_connection_complete_event(hci_event, gap_event);
91     hci_emit_event(gap_event, sizeof(gap_event), 1);
92 }
93 
94 static void hci_emit_connection_encrypted(hci_con_handle_t con_handle, uint8_t encrypted){
95     uint8_t encryption_complete_event[6] = { HCI_EVENT_ENCRYPTION_CHANGE, 4, 0, 0, 0, 0};
96     little_endian_store_16(encryption_complete_event, 3, con_handle);
97     encryption_complete_event[5] = encrypted;
98     hci_emit_event(encryption_complete_event, sizeof(encryption_complete_event), 0);
99 }
100 
101 static void hci_emit_disconnection_complete(hci_con_handle_t con_handle, uint8_t reason){
102     uint8_t event[6];
103     event[0] = HCI_EVENT_DISCONNECTION_COMPLETE;
104     event[1] = sizeof(event) - 2u;
105     event[2] = 0; // status = OK
106     little_endian_store_16(event, 3, con_handle);
107     event[5] = reason;
108     hci_emit_event(event, sizeof(event), 1);
109 }
110 
111 // mock sm
112 void sm_request_pairing(hci_con_handle_t con_handle){
113 }
114 
115 
116 // temp btstack run loop mock
117 
118 static btstack_timer_source_t * btstack_timer = NULL;
119 
120 void btstack_run_lopo_deinit(void){
121     btstack_timer = NULL;
122 }
123 
124 void btstack_run_loop_add_timer(btstack_timer_source_t * timer){
125     btstack_timer = timer;
126 }
127 
128 int btstack_run_loop_remove_timer(btstack_timer_source_t * timer){
129     btstack_timer = NULL;
130     return 1;
131 }
132 
133 void btstack_run_loop_set_timer(btstack_timer_source_t * timer, uint32_t timeout_in_ms){
134 }
135 
136 void btstack_run_loop_set_timer_handler(btstack_timer_source_t * timer, void (*process)(btstack_timer_source_t * _timer)){
137     timer->process = process;
138 }
139 
140 void btstack_run_loop_set_timer_context(btstack_timer_source_t * timer, void * context){
141     timer->context = context;
142 }
143 
144 void * btstack_run_loop_get_timer_context(btstack_timer_source_t * timer){
145     return timer->context;
146 }
147 
148 void mock_btstack_run_loop_trigger_timer(void){
149     btstack_assert(btstack_timer != NULL);
150     (*btstack_timer->process)(btstack_timer);
151 }
152 
153 static void ancs_client_event_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){
154     UNUSED(packet_type);
155     UNUSED(channel);
156     UNUSED(size);
157 
158     switch (hci_event_gattservice_meta_get_subevent_code(packet)){
159         case ANCS_SUBEVENT_CLIENT_CONNECTED:
160             ancs_connected = true;
161             break;
162         default:
163             break;
164     }
165 }
166 
167 TEST_GROUP(ANCS_CLIENT){
168     mock_gatt_client_service_t * service;
169     mock_gatt_client_characteristic_t * ancs_data_source_characteristic;
170     mock_gatt_client_characteristic_t * ancs_notification_source_characteristic;
171     mock_gatt_client_characteristic_t * ancs_control_point_characteristic;
172     mock_gatt_client_characteristic_descriptor_t * descriptor;
173 
174     uint8_t  value_buffer[3];
175 
176     void setup(void){
177         ancs_connected = false;
178         mock_gatt_client_reset();
179         ancs_client_init();
180         ancs_client_register_callback(&ancs_client_event_handler);
181     }
182 
183     void setup_service(bool add_characteristics, bool add_descriptors){
184         // TODO: setup ANCS Service
185         service = mock_gatt_client_add_primary_service_uuid128(ancs_service_uuid);
186 
187         if (!add_characteristics) return;
188         ancs_control_point_characteristic = mock_gatt_client_add_characteristic_uuid128(ancs_control_point_uuid, ATT_PROPERTY_NOTIFY);
189         if (add_descriptors) {
190             descriptor = mock_gatt_client_add_characteristic_descriptor_uuid16(ORG_BLUETOOTH_DESCRIPTOR_GATT_CLIENT_CHARACTERISTIC_CONFIGURATION);
191         }
192         ancs_data_source_characteristic = mock_gatt_client_add_characteristic_uuid128(ancs_data_source_uuid, ATT_PROPERTY_NOTIFY);
193         if (add_descriptors) {
194             descriptor = mock_gatt_client_add_characteristic_descriptor_uuid16(ORG_BLUETOOTH_DESCRIPTOR_GATT_CLIENT_CHARACTERISTIC_CONFIGURATION);
195         }
196         ancs_notification_source_characteristic = mock_gatt_client_add_characteristic_uuid128(ancs_notification_source_uuid, ATT_PROPERTY_NOTIFY);
197         if (add_descriptors) {
198             descriptor = mock_gatt_client_add_characteristic_descriptor_uuid16(ORG_BLUETOOTH_DESCRIPTOR_GATT_CLIENT_CHARACTERISTIC_CONFIGURATION);
199         }
200         // mock_gatt_client_dump_services();
201 
202     }
203 
204     void connect(void){
205         // simulated connected
206         bd_addr_t some_address;
207         hci_emit_le_connection_complete(0, some_address, ancs_con_handle, ERROR_CODE_SUCCESS);
208         hci_emit_connection_encrypted(ancs_con_handle, 1);
209     }
210 
211     void teardown(void){
212     }
213 };
214 
215 
216 TEST(ANCS_CLIENT, resolve_ids){
217     for (int i = 0; i<6; i++){
218         const char * name = ancs_client_attribute_name_for_id(i);
219         CHECK_TRUE(name != NULL);
220     }
221     CHECK_EQUAL(NULL, ancs_client_attribute_name_for_id(6));
222 }
223 
224 TEST(ANCS_CLIENT, ignored_events){
225     // default hci event
226     uint8_t some_other_event[] = { 0, 0};
227     hci_emit_event(some_other_event, sizeof(some_other_event), 0);
228     // default hci le subevent
229     uint8_t some_le_event[] = { HCI_EVENT_LE_META, 1, 0};
230     hci_emit_event(some_le_event, sizeof(some_le_event), 0);
231     // encypted but different con handle
232     hci_emit_connection_encrypted(ancs_con_handle+1, 1);
233     // encypted but different state
234     hci_emit_connection_encrypted(ancs_con_handle, 1);
235     // non-encypted
236     hci_emit_connection_encrypted(ancs_con_handle, 0);
237     // disconnected different handle
238     hci_emit_disconnection_complete(ancs_con_handle+1,0);
239     // disconnected different handle
240     hci_emit_disconnection_complete(ancs_con_handle,0);
241 }
242 
243 TEST(ANCS_CLIENT, connect_no_service){
244     connect();
245     mock_gatt_client_run();
246 }
247 
248 TEST(ANCS_CLIENT, connect_unexpected_event_during_service_disc){
249     connect();
250     mock_gatt_client_emit_dummy_event();
251 }
252 
253 TEST(ANCS_CLIENT, connect_unexpected_events){
254     setup_service(true, true);
255     connect();
256     mock_gatt_client_run_once();
257     mock_gatt_client_emit_dummy_event();
258     mock_gatt_client_run_once();
259     mock_gatt_client_emit_dummy_event();
260     mock_gatt_client_run_once();
261     mock_gatt_client_emit_dummy_event();
262     mock_gatt_client_run_once();
263     mock_gatt_client_emit_dummy_event();
264 }
265 
266 TEST(ANCS_CLIENT, connect){
267     setup_service(true, true);
268     connect();
269     mock_gatt_client_run();
270     CHECK_TRUE(ancs_connected);
271 }
272 
273 TEST(ANCS_CLIENT, connect_extra_characteristic){
274     setup_service(true, true);
275     mock_gatt_client_add_characteristic_uuid16(ORG_BLUETOOTH_CHARACTERISTIC_BATTERY_LEVEL, 0);
276     connect();
277     mock_gatt_client_run();
278 }
279 
280 TEST(ANCS_CLIENT, disconnect){
281     setup_service(true, true);
282     connect();
283     mock_gatt_client_run();
284     hci_emit_disconnection_complete(ancs_con_handle,0);
285 }
286 
287 TEST(ANCS_CLIENT, notification_characteristic){
288     setup_service(true, true);
289     connect();
290     mock_gatt_client_run();
291     const uint8_t data[] = {};
292     mock_gatt_client_send_notification(ancs_notification_source_characteristic, data, sizeof(data));
293 }
294 
295 TEST(ANCS_CLIENT, data_source_characteristic){
296     setup_service(true, true);
297     connect();
298     mock_gatt_client_run();
299     // simulate notification
300     const uint8_t notification_data[] = {0,0,0,0,0,0,0,0};
301     mock_gatt_client_send_notification(ancs_notification_source_characteristic, notification_data, sizeof(notification_data));
302     // command id = 0 / CommandIDGetNotificationAttributes
303     // notification uid 0x1111
304     // attribute id 1
305     // len 1
306     // attribute id 2
307     // len 0
308     const uint8_t data[] = { 0, 0,0,0,0, 1, 1, 0, 'a', 2, 0, 0};
309     mock_gatt_client_send_notification(ancs_data_source_characteristic, data, sizeof(data));
310 }
311 
312 TEST(ANCS_CLIENT, data_source_characteristic_no_handler){
313     ancs_client_register_callback(NULL);
314     setup_service(true, true);
315     connect();
316     mock_gatt_client_run();
317     // simulate notification
318     const uint8_t notification_data[] = {0,0,0,0,0,0,0,0};
319     mock_gatt_client_send_notification(ancs_notification_source_characteristic, notification_data, sizeof(notification_data));
320     // command id = 0 / CommandIDGetNotificationAttributes
321     // notification uid 0x1111
322     // attribute id 1
323     // len 1
324     // attribute id 2
325     // len 0
326     const uint8_t data[] = { 0, 0,0,0,0, 1, 1, 0, 'a', 2, 0, 0};
327     mock_gatt_client_send_notification(ancs_data_source_characteristic, data, sizeof(data));
328 }
329 
330 TEST(ANCS_CLIENT, notifications_other){
331     setup_service(true, true);
332     connect();
333     mock_gatt_client_run();
334     const uint8_t data[] = {};
335     mock_gatt_client_send_notification_with_handle(ancs_notification_source_characteristic, 0x0001, data, sizeof(data));
336 }
337 
338 TEST(ANCS_CLIENT, indications_other){
339     setup_service(true, true);
340     connect();
341     mock_gatt_client_run();
342     const uint8_t data[] = {};
343     mock_gatt_client_send_indication_with_handle(ancs_notification_source_characteristic, 0x0001, data, sizeof(data));
344 }
345 
346 TEST(ANCS_CLIENT, notifications_invalid_parser){
347     setup_service(true, true);
348     ancs_client_set_invalid_parser_state();
349     connect();
350     mock_gatt_client_run();
351     const uint8_t data[] = {1,2,3,4,5,6};
352     mock_gatt_client_send_notification(ancs_data_source_characteristic, data, sizeof(data));
353 }
354 
355 int main (int argc, const char * argv[]){
356     return CommandLineTestRunner::RunAllTests(argc, argv);
357 }
358