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