From f0946845ff44651cb8bb7f44ad3a572df40c8341 Mon Sep 17 00:00:00 2001 From: Matthias Ringwald Date: Mon, 4 Nov 2019 16:28:55 +0100 Subject: [PATCH] auto-pts: some gap commands --- test/auto-pts/btpclient.c | 242 +++++++++++++++++++++++++++++++++++--- 1 file changed, 225 insertions(+), 17 deletions(-) diff --git a/test/auto-pts/btpclient.c b/test/auto-pts/btpclient.c index ed6c16778..efe3b1d33 100644 --- a/test/auto-pts/btpclient.c +++ b/test/auto-pts/btpclient.c @@ -57,6 +57,19 @@ int btstack_main(int argc, const char * argv[]); static btstack_packet_callback_registration_t hci_event_callback_registration; +static bool gap_send_powered_state; +static char gap_name[249]; +static char gap_short_name[11]; +static uint32_t gap_cod; + +static uint32_t current_settings; + + +static void btp_send_gap_settings(uint8_t opcode){ + uint8_t buffer[4]; + little_endian_store_32(buffer, 0, current_settings); + btp_socket_send_packet(BTP_SERVICE_ID_GAP, opcode, 0, 4, buffer); +} static void btstack_packet_handler (uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){ UNUSED(channel); @@ -66,9 +79,18 @@ static void btstack_packet_handler (uint8_t packet_type, uint16_t channel, uint8 case BTSTACK_EVENT_STATE: switch (btstack_event_state_get_state(packet)){ case HCI_STATE_WORKING: - btp_socket_open_unix(AUTOPTS_SOCKET_NAME); - log_info("BTP_CORE_SERVICE/BTP_EV_CORE_READY/BTP_INDEX_NON_CONTROLLER()"); - btp_socket_send_packet(BTP_SERVICE_ID_CORE, BTP_CORE_EV_READY, BTP_INDEX_NON_CONTROLLER, 0, NULL); + if (gap_send_powered_state){ + gap_send_powered_state = false; + current_settings |= BTP_GAP_SETTING_POWERED; + btp_send_gap_settings(BTP_GAP_OP_SET_POWERED); + } + break; + case HCI_STATE_OFF: + if (gap_send_powered_state){ + gap_send_powered_state = false; + current_settings &= ~BTP_GAP_SETTING_POWERED; + btp_send_gap_settings(BTP_GAP_OP_SET_POWERED); + } break; default: break; @@ -83,23 +105,184 @@ static void btstack_packet_handler (uint8_t packet_type, uint16_t channel, uint8 } } -static void btp_packet_handler(uint8_t service_id, uint8_t opcode, uint8_t controller_index, uint16_t length, const uint8_t *data){ +static void btp_core_handler(uint8_t opcode, uint8_t controller_index, uint16_t length, const uint8_t *data){ uint8_t status; + switch (opcode){ + case BTP_OP_ERROR: + log_info("BTP_OP_ERROR"); + status = data[0]; + if (status == BTP_ERROR_NOT_READY){ + // connection stopped, abort + exit(10); + } + break; + case BTP_CORE_OP_READ_SUPPORTED_COMMANDS: + log_info("BTP_CORE_OP_READ_SUPPORTED_COMMANDS"); + if (controller_index == BTP_INDEX_NON_CONTROLLER){ + uint8_t commands = 0; + commands |= (1U << BTP_CORE_OP_READ_SUPPORTED_COMMANDS); + commands |= (1U << BTP_CORE_OP_READ_SUPPORTED_SERVICES); + commands |= (1U << BTP_CORE_OP_REGISTER); + commands |= (1U << BTP_CORE_OP_UNREGISTER); + btp_socket_send_packet(BTP_SERVICE_ID_CORE, opcode, controller_index, 1, &commands); + } + break; + case BTP_CORE_OP_READ_SUPPORTED_SERVICES: + log_info("BTP_CORE_OP_READ_SUPPORTED_SERVICES"); + if (controller_index == BTP_INDEX_NON_CONTROLLER){ + uint8_t services = 0; + services |= (1U << BTP_SERVICE_ID_CORE); + services |= (1U << BTP_SERVICE_ID_GAP); + services |= (1U << BTP_SERVICE_ID_GATT ); + services |= (1U << BTP_SERVICE_ID_L2CAP); + services |= (1U << BTP_SERVICE_ID_MESH ); + btp_socket_send_packet(BTP_SERVICE_ID_CORE, opcode, controller_index, 1, &services); + } + break; + case BTP_CORE_OP_REGISTER: + log_info("BTP_CORE_OP_REGISTER"); + if (controller_index == BTP_INDEX_NON_CONTROLLER){ + btp_socket_send_packet(BTP_SERVICE_ID_CORE, opcode, controller_index, 0, NULL); + } + break; + case BTP_CORE_OP_UNREGISTER: + log_info("BTP_CORE_OP_UNREGISTER"); + if (controller_index == BTP_INDEX_NON_CONTROLLER){ + btp_socket_send_packet(BTP_SERVICE_ID_CORE, opcode, controller_index, 0, NULL); + } + break; + default: + break; + } +} + +static void btp_gap_handler(uint8_t opcode, uint8_t controller_index, uint16_t length, const uint8_t *data){ + switch (opcode){ + case BTP_OP_ERROR: + log_info("BTP_OP_ERROR"); + break; + case BTP_GAP_OP_READ_SUPPORTED_COMMANDS: + log_info("BTP_GAP_OP_READ_SUPPORTED_COMMANDS"); + if (controller_index == BTP_INDEX_NON_CONTROLLER){ + uint8_t commands = 0; + btp_socket_send_packet(BTP_SERVICE_ID_GAP, opcode, controller_index, 1, &commands); + } + break; + case BTP_GAP_OP_READ_CONTROLLER_INDEX_LIST: + log_info("BTP_GAP_OP_READ_CONTROLLER_INDEX_LIST - not implemented"); + break; + case BTP_GAP_OP_READ_COTROLLER_INFO: + log_info("BTP_GAP_OP_READ_COTROLLER_INFO"); + if (controller_index == 0){ + uint8_t buffer[277]; + bd_addr_t local_addr; + gap_local_bd_addr( local_addr); + reverse_bd_addr(local_addr, &buffer[0]); + uint32_t supported_settings = 0; + supported_settings |= BTP_GAP_SETTING_POWERED; + supported_settings |= BTP_GAP_SETTING_CONNECTABLE; + supported_settings |= BTP_GAP_SETTING_DISCOVERABLE; + supported_settings |= BTP_GAP_SETTING_BONDABLE; + supported_settings |= BTP_GAP_SETTING_SSP; + #ifdef ENABLE_CLASSIC + supported_settings |= BTP_GAP_SETTING_BREDR; + #endif + #ifdef ENABLE_BLE + supported_settings |= BTP_GAP_SETTING_LE; + #endif + supported_settings |= BTP_GAP_SETTING_ADVERTISING; + #ifdef ENABLE_LE_SECURE_CONNECTIONS + supported_settings |= BTP_GAP_SETTING_SC; + #endif + supported_settings |= BTP_GAP_SETTING_PRIVACY; + // supported_settings |= BTP_GAP_SETTING_STATIC_ADDRESS; + little_endian_store_32(buffer, 6, supported_settings); + little_endian_store_32(buffer,10, current_settings); + little_endian_store_24(buffer, 14, gap_cod); + strncpy((char *) &buffer[17], &gap_name[0], 249); + strncpy((char *) &buffer[266], &gap_short_name[0], 11 ); + btp_socket_send_packet(BTP_SERVICE_ID_GAP, opcode, controller_index, 277, buffer); + } + break; + case BTP_GAP_OP_RESET: + log_info("BTP_GAP_OP_RESET - NOP"); + // ignore + btp_send_gap_settings(opcode); + break; + case BTP_GAP_OP_SET_POWERED: + log_info("BTP_GAP_OP_SET_POWERED"); + if (controller_index == 0){ + uint8_t powered = data[0]; + if (powered){ + hci_power_control(HCI_POWER_ON); + } else { + hci_power_control(HCI_POWER_OFF); + } + gap_send_powered_state = true; + } + break; + case BTP_GAP_OP_SET_CONNECTABLE: + log_info("BTP_GAP_OP_SET_POWERED"); + if (controller_index == 0){ + uint8_t connectable = data[0]; + if (connectable) { + current_settings |= BTP_GAP_SETTING_CONNECTABLE; + } else { + current_settings &= ~BTP_GAP_SETTING_CONNECTABLE; + + } + btp_send_gap_settings(opcode); + } + break; + case BTP_GAP_OP_START_ADVERTISING: + log_info("BTP_GAP_OP_START_ADVERTISING"); + if (controller_index == 0){ + uint8_t adv_data_len = data[0]; + uint8_t scan_response_len = data[1]; + const uint8_t * adv_data = &data[2]; + const uint8_t * scan_response = &data[2 + adv_data_len]; + // uint32_t duration = little_endian_read_32(data, 2 + adv_data_len + scan_response_len); + bool use_own_id_address = (bool) &data[6 + adv_data_len + scan_response_len]; + // configure controller + if (use_own_id_address){ + gap_random_address_set_mode(GAP_RANDOM_ADDRESS_TYPE_OFF); + } else { + gap_random_address_set_mode(GAP_RANDOM_ADDRESS_RESOLVABLE); + } + uint16_t adv_int_min = 0x0030; + uint16_t adv_int_max = 0x0030; + uint8_t adv_type; + bd_addr_t null_addr; + memset(null_addr, 0, 6); + if (current_settings & BTP_GAP_SETTING_CONNECTABLE){ + adv_type = 0; // ADV_IND + } else { + adv_type = 3; // ADV_NONCONN_IND + } + gap_advertisements_set_params(adv_int_min, adv_int_max, adv_type, 0, null_addr, 0x07, 0x00); + gap_advertisements_set_data(adv_data_len, (uint8_t *) adv_data); + gap_scan_response_set_data(scan_response_len, (uint8_t *) scan_response); + gap_advertisements_enable(1); + // update settings + current_settings |= BTP_GAP_SETTING_ADVERTISING; + btp_send_gap_settings(opcode); + } + break; + default: + break; + } +} + +static void btp_packet_handler(uint8_t service_id, uint8_t opcode, uint8_t controller_index, uint16_t length, const uint8_t *data){ log_info("service id 0x%02x, opcode 0x%02x, controller_index 0x%0x, len %u", service_id, opcode, controller_index, length); log_info_hexdump(data, length); switch (service_id){ case BTP_SERVICE_ID_CORE: - switch (opcode){ - case BTP_OP_ERROR: - status = data[0]; - if (status == BTP_ERROR_NOT_READY){ - // connection stopped, abort - exit(10); - } - break; - } + btp_core_handler(opcode, controller_index, length, data); break; + case BTP_SERVICE_ID_GAP: + btp_gap_handler(opcode, controller_index, length, data); default: break; } @@ -114,19 +297,44 @@ int btstack_main(int argc, const char * argv[]) rfcomm_init(); sdp_init(); + le_device_db_init(); + sm_init(); + // register for HCI events hci_event_callback_registration.callback = &btstack_packet_handler; hci_add_event_handler(&hci_event_callback_registration); + // configure GAP gap_ssp_set_io_capability(SSP_IO_CAPABILITY_DISPLAY_YES_NO); - gap_set_local_name("iut 00:00:00:00:00:00"); - gap_discoverable_control(1); + + strcpy(gap_name, "iut 00:00:00:00:00:00"); + gap_set_local_name(gap_name); + + strcpy(gap_short_name, "iut"); + + gap_cod = 0x007a020c; // smartphone + gap_set_class_of_device(gap_cod); btp_socket_register_packet_handler(&btp_packet_handler); printf("auto-pts iut-btp-client started\n"); - // turn on! - hci_power_control(HCI_POWER_ON); + // current settings + current_settings |= BTP_GAP_SETTING_SSP; + current_settings |= BTP_GAP_SETTING_LE; + current_settings |= BTP_GAP_SETTING_PRIVACY; +#ifdef ENABLE_CLASSIC + current_settings |= BTP_GAP_SETTING_BREDR; +#endif +#ifdef ENABLE_BLE +#endif +#ifdef ENABLE_LE_SECURE_CONNECTIONS + current_settings |= BTP_GAP_SETTING_SC; +#endif + + // connect to auto-pts client + btp_socket_open_unix(AUTOPTS_SOCKET_NAME); + log_info("BTP_CORE_SERVICE/BTP_EV_CORE_READY/BTP_INDEX_NON_CONTROLLER()"); + btp_socket_send_packet(BTP_SERVICE_ID_CORE, BTP_CORE_EV_READY, BTP_INDEX_NON_CONTROLLER, 0, NULL); return 0; }