xref: /btstack/test/gatt-service-client/ancs_client_test.cpp (revision a64cbea79fa5fb9daa58e135a19c6cce10f3e642)
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_emit_le_connection_complete(uint8_t address_type, const bd_addr_t address, hci_con_handle_t con_handle, uint8_t status){
51     uint8_t event[21];
52     event[0] = HCI_EVENT_LE_META;
53     event[1] = sizeof(event) - 2u;
54     event[2] = HCI_SUBEVENT_LE_CONNECTION_COMPLETE;
55     event[3] = status;
56     little_endian_store_16(event, 4, con_handle);
57     event[6] = 0; // TODO: role
58     event[7] = address_type;
59     reverse_bd_addr(address, &event[8]);
60     little_endian_store_16(event, 14, 0); // interval
61     little_endian_store_16(event, 16, 0); // latency
62     little_endian_store_16(event, 18, 0); // supervision timeout
63     event[20] = 0; // master clock accuracy
64     hci_emit_event(event, sizeof(event), 1);
65 }
66 
67 static void hci_emit_connection_encrypted(hci_con_handle_t con_handle, uint8_t encrypted){
68     uint8_t encryption_complete_event[6] = { HCI_EVENT_ENCRYPTION_CHANGE, 4, 0, 0, 0, 0};
69     little_endian_store_16(encryption_complete_event, 3, con_handle);
70     encryption_complete_event[5] = encrypted;
71     hci_emit_event(encryption_complete_event, sizeof(encryption_complete_event), 0);
72 }
73 
74 static void hci_emit_disconnection_complete(hci_con_handle_t con_handle, uint8_t reason){
75     uint8_t event[6];
76     event[0] = HCI_EVENT_DISCONNECTION_COMPLETE;
77     event[1] = sizeof(event) - 2u;
78     event[2] = 0; // status = OK
79     little_endian_store_16(event, 3, con_handle);
80     event[5] = reason;
81     hci_emit_event(event, sizeof(event), 1);
82 }
83 
84 // mock sm
85 void sm_request_pairing(hci_con_handle_t con_handle){
86 }
87 
88 
89 // temp btstack run loop mock
90 
91 static btstack_timer_source_t * btstack_timer = NULL;
92 
93 void btstack_run_lopo_deinit(void){
94     btstack_timer = NULL;
95 }
96 
97 void btstack_run_loop_add_timer(btstack_timer_source_t * timer){
98     btstack_timer = timer;
99 }
100 
101 int btstack_run_loop_remove_timer(btstack_timer_source_t * timer){
102     btstack_timer = NULL;
103     return 1;
104 }
105 
106 void btstack_run_loop_set_timer(btstack_timer_source_t * timer, uint32_t timeout_in_ms){
107 }
108 
109 void btstack_run_loop_set_timer_handler(btstack_timer_source_t * timer, void (*process)(btstack_timer_source_t * _timer)){
110     timer->process = process;
111 }
112 
113 void btstack_run_loop_set_timer_context(btstack_timer_source_t * timer, void * context){
114     timer->context = context;
115 }
116 
117 void * btstack_run_loop_get_timer_context(btstack_timer_source_t * timer){
118     return timer->context;
119 }
120 
121 void mock_btstack_run_loop_trigger_timer(void){
122     btstack_assert(btstack_timer != NULL);
123     (*btstack_timer->process)(btstack_timer);
124 }
125 
126 static void ancs_client_event_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){
127     UNUSED(packet_type);
128     UNUSED(channel);
129     UNUSED(size);
130 
131     switch (hci_event_gattservice_meta_get_subevent_code(packet)){
132         case ANCS_SUBEVENT_CLIENT_CONNECTED:
133             ancs_connected = true;
134             break;
135         default:
136             break;
137     }
138 }
139 
140 TEST_GROUP(ANCS_CLIENT){
141     mock_gatt_client_service_t * service;
142     mock_gatt_client_characteristic_t * ancs_data_source_characteristic;
143     mock_gatt_client_characteristic_t * ancs_notification_source_characteristic;
144     mock_gatt_client_characteristic_t * ancs_control_point_characteristic;
145     mock_gatt_client_characteristic_descriptor_t * descriptor;
146 
147     uint8_t  value_buffer[3];
148 
149     void setup(void){
150         ancs_connected = false;
151         mock_gatt_client_reset();
152         ancs_client_init();
153         ancs_client_register_callback(&ancs_client_event_handler);
154     }
155 
156     void setup_service(bool add_characteristics, bool add_descriptors){
157         // TODO: setup ANCS Service
158         service = mock_gatt_client_add_primary_service_uuid128(ancs_service_uuid);
159 
160         if (!add_characteristics) return;
161         ancs_control_point_characteristic = mock_gatt_client_add_characteristic_uuid128(ancs_control_point_uuid, ATT_PROPERTY_NOTIFY);
162         if (add_descriptors) {
163             descriptor = mock_gatt_client_add_characteristic_descriptor_uuid16(ORG_BLUETOOTH_DESCRIPTOR_GATT_CLIENT_CHARACTERISTIC_CONFIGURATION);
164         }
165         ancs_data_source_characteristic = mock_gatt_client_add_characteristic_uuid128(ancs_data_source_uuid, ATT_PROPERTY_NOTIFY);
166         if (add_descriptors) {
167             descriptor = mock_gatt_client_add_characteristic_descriptor_uuid16(ORG_BLUETOOTH_DESCRIPTOR_GATT_CLIENT_CHARACTERISTIC_CONFIGURATION);
168         }
169         ancs_notification_source_characteristic = mock_gatt_client_add_characteristic_uuid128(ancs_notification_source_uuid, ATT_PROPERTY_NOTIFY);
170         if (add_descriptors) {
171             descriptor = mock_gatt_client_add_characteristic_descriptor_uuid16(ORG_BLUETOOTH_DESCRIPTOR_GATT_CLIENT_CHARACTERISTIC_CONFIGURATION);
172         }
173         // mock_gatt_client_dump_services();
174 
175     }
176 
177     void connect(void){
178         // simulated connected
179         bd_addr_t some_address;
180         hci_emit_le_connection_complete(0, some_address, ancs_con_handle, ERROR_CODE_SUCCESS);
181         hci_emit_connection_encrypted(ancs_con_handle, 1);
182     }
183 
184     void teardown(void){
185     }
186 };
187 
188 
189 TEST(ANCS_CLIENT, resolve_ids){
190     for (int i = 0; i<6; i++){
191         const char * name = ancs_client_attribute_name_for_id(i);
192         CHECK_TRUE(name != NULL);
193     }
194     CHECK_EQUAL(NULL, ancs_client_attribute_name_for_id(6));
195 }
196 
197 TEST(ANCS_CLIENT, ignored_events){
198     // default hci event
199     uint8_t some_other_event[] = { 0, 0};
200     hci_emit_event(some_other_event, sizeof(some_other_event), 0);
201     // default hci le subevent
202     uint8_t some_le_event[] = { HCI_EVENT_LE_META, 1, 0};
203     hci_emit_event(some_le_event, sizeof(some_le_event), 0);
204     // encypted but different con handle
205     hci_emit_connection_encrypted(ancs_con_handle+1, 1);
206     // encypted but different state
207     hci_emit_connection_encrypted(ancs_con_handle, 1);
208     // non-encypted
209     hci_emit_connection_encrypted(ancs_con_handle, 0);
210     // disconnected different handle
211     hci_emit_disconnection_complete(ancs_con_handle+1,0);
212     // disconnected different handle
213     hci_emit_disconnection_complete(ancs_con_handle,0);
214 }
215 
216 TEST(ANCS_CLIENT, connect_no_service){
217     connect();
218     mock_gatt_client_run();
219 }
220 
221 TEST(ANCS_CLIENT, connect_unexpected_event_during_service_disc){
222     connect();
223     mock_gatt_client_emit_dummy_event();
224 }
225 
226 TEST(ANCS_CLIENT, connect_unexpected_events){
227     setup_service(true, true);
228     connect();
229     mock_gatt_client_run_once();
230     mock_gatt_client_emit_dummy_event();
231     mock_gatt_client_run_once();
232     mock_gatt_client_emit_dummy_event();
233     mock_gatt_client_run_once();
234     mock_gatt_client_emit_dummy_event();
235     mock_gatt_client_run_once();
236     mock_gatt_client_emit_dummy_event();
237 }
238 
239 TEST(ANCS_CLIENT, connect){
240     setup_service(true, true);
241     connect();
242     mock_gatt_client_run();
243     CHECK_TRUE(ancs_connected);
244 }
245 
246 TEST(ANCS_CLIENT, connect_extra_characteristic){
247     setup_service(true, true);
248     mock_gatt_client_add_characteristic_uuid16(ORG_BLUETOOTH_CHARACTERISTIC_BATTERY_LEVEL, 0);
249     connect();
250     mock_gatt_client_run();
251 }
252 
253 TEST(ANCS_CLIENT, disconnect){
254     setup_service(true, true);
255     connect();
256     mock_gatt_client_run();
257     hci_emit_disconnection_complete(ancs_con_handle,0);
258 }
259 
260 TEST(ANCS_CLIENT, notification_characteristic){
261     setup_service(true, true);
262     connect();
263     mock_gatt_client_run();
264     const uint8_t data[] = {};
265     mock_gatt_client_send_notification(ancs_notification_source_characteristic, data, sizeof(data));
266 }
267 
268 TEST(ANCS_CLIENT, data_source_characteristic){
269     setup_service(true, true);
270     connect();
271     mock_gatt_client_run();
272     // simulate notification
273     const uint8_t notification_data[] = {0,0,0,0,0,0,0,0};
274     mock_gatt_client_send_notification(ancs_notification_source_characteristic, notification_data, sizeof(notification_data));
275     // command id = 0 / CommandIDGetNotificationAttributes
276     // notification uid 0x1111
277     // attribute id 1
278     // len 1
279     // attribute id 2
280     // len 0
281     const uint8_t data[] = { 0, 0,0,0,0, 1, 1, 0, 'a', 2, 0, 0};
282     mock_gatt_client_send_notification(ancs_data_source_characteristic, data, sizeof(data));
283 }
284 
285 TEST(ANCS_CLIENT, data_source_characteristic_no_handler){
286     ancs_client_register_callback(NULL);
287     setup_service(true, true);
288     connect();
289     mock_gatt_client_run();
290     // simulate notification
291     const uint8_t notification_data[] = {0,0,0,0,0,0,0,0};
292     mock_gatt_client_send_notification(ancs_notification_source_characteristic, notification_data, sizeof(notification_data));
293     // command id = 0 / CommandIDGetNotificationAttributes
294     // notification uid 0x1111
295     // attribute id 1
296     // len 1
297     // attribute id 2
298     // len 0
299     const uint8_t data[] = { 0, 0,0,0,0, 1, 1, 0, 'a', 2, 0, 0};
300     mock_gatt_client_send_notification(ancs_data_source_characteristic, data, sizeof(data));
301 }
302 
303 TEST(ANCS_CLIENT, notifications_other){
304     setup_service(true, true);
305     connect();
306     mock_gatt_client_run();
307     const uint8_t data[] = {};
308     mock_gatt_client_send_notification_with_handle(ancs_notification_source_characteristic, 0x0001, data, sizeof(data));
309 }
310 
311 TEST(ANCS_CLIENT, indications_other){
312     setup_service(true, true);
313     connect();
314     mock_gatt_client_run();
315     const uint8_t data[] = {};
316     mock_gatt_client_send_indication_with_handle(ancs_notification_source_characteristic, 0x0001, data, sizeof(data));
317 }
318 
319 TEST(ANCS_CLIENT, notifications_invalid_parser){
320     setup_service(true, true);
321     ancs_client_set_invalid_parser_state();
322     connect();
323     mock_gatt_client_run();
324     const uint8_t data[] = {1,2,3,4,5,6};
325     mock_gatt_client_send_notification(ancs_data_source_characteristic, data, sizeof(data));
326 }
327 
328 int main (int argc, const char * argv[]){
329     return CommandLineTestRunner::RunAllTests(argc, argv);
330 }
331