| /****************************************************************************** |
| * |
| * Copyright (C) 2015, The linux Foundation. All rights reserved. |
| * |
| * Not a Contribution. |
| * |
| * Copyright (C) 2009-2012 Broadcom Corporation |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at: |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| * |
| ******************************************************************************/ |
| |
| /************************************************************************************ |
| * |
| * Filename: mcap_tool.cc |
| * |
| * Description: Fluoride MCAP Test Tool application |
| * |
| ***********************************************************************************/ |
| #include <pthread.h> |
| #include <signal.h> |
| #include <stdarg.h> |
| #include <stdint.h> |
| #include <stdio.h> |
| #include <stdlib.h> |
| #include <string.h> |
| #ifndef OS_GENERIC |
| #include <sys/capability.h> |
| #endif |
| #include <sys/prctl.h> |
| #include <time.h> |
| #include <unistd.h> |
| |
| #include <hardware/bluetooth.h> |
| #include <hardware/hardware.h> |
| #ifndef OS_GENERIC |
| #include <private/android_filesystem_config.h> |
| #endif |
| #include <base/logging.h> |
| |
| #include "bdaddr.h" |
| #include "bt_types.h" |
| #include "l2c_api.h" |
| #include "mca_api.h" |
| #include "mca_defs.h" |
| #include "osi/include/compat.h" |
| #if defined(OS_GENERIC) |
| #include "hal_util.h" |
| #endif |
| #include "mcap_test_app.h" |
| #include "mcap_test_mcl.h" |
| #include "mcap_test_mdep.h" |
| #include "mcap_test_mdl.h" |
| |
| using SYSTEM_BT_TOOLS_MCAP_TOOL::McapTestApp; |
| using SYSTEM_BT_TOOLS_MCAP_TOOL::McapMcl; |
| using SYSTEM_BT_TOOLS_MCAP_TOOL::McapMdep; |
| using SYSTEM_BT_TOOLS_MCAP_TOOL::McapMdl; |
| |
| /****************************************************************************** |
| * Constants & Macros |
| *****************************************************************************/ |
| #define PID_FILE "/data/.bdt_pid" |
| |
| #ifndef MAX |
| #define MAX(x, y) ((x) > (y) ? (x) : (y)) |
| #endif |
| |
| #ifndef MIN |
| #define MIN(x, y) ((x) < (y) ? (x) : (y)) |
| #endif |
| |
| #define CASE_RETURN_STR(const) \ |
| case const: \ |
| return #const; |
| |
| #ifndef OS_GENERIC |
| /* Permission Groups */ |
| static gid_t groups[] = {AID_NET_BT, AID_INET, AID_NET_BT_ADMIN, |
| AID_SYSTEM, AID_MISC, AID_SDCARD_RW, |
| AID_NET_ADMIN, AID_VPN}; |
| #endif |
| /****************************************************************************** |
| * Static variables |
| *****************************************************************************/ |
| /* Console loop states */ |
| static bool global_main_done = false; |
| static bt_status_t global_status; |
| static bool global_strict_mode = false; |
| |
| /* Device and Profile Interfaces */ |
| static bluetooth_device_t* sBtDevice = nullptr; |
| const bt_interface_t* sBtInterface = nullptr; |
| static btmcap_test_interface_t* sMcapTestInterface = nullptr; |
| static McapTestApp* sMcapTestApp = nullptr; |
| |
| /* Bluetooth stack states */ |
| static bool global_bt_enabled = false; |
| static int global_adapter_state = BT_STATE_OFF; |
| static int global_pair_state = BT_BOND_STATE_NONE; |
| /************************************************************************************ |
| ** Static functions |
| ************************************************************************************/ |
| static void process_cmd(char* p, bool is_job); |
| |
| /******************************************************************************* |
| ** Misc helper functions |
| *******************************************************************************/ |
| static const char* dump_bt_status(const bt_status_t status) { |
| switch (status) { |
| CASE_RETURN_STR(BT_STATUS_SUCCESS) |
| CASE_RETURN_STR(BT_STATUS_FAIL) |
| CASE_RETURN_STR(BT_STATUS_NOT_READY) |
| CASE_RETURN_STR(BT_STATUS_NOMEM) |
| CASE_RETURN_STR(BT_STATUS_BUSY) |
| CASE_RETURN_STR(BT_STATUS_UNSUPPORTED) |
| default: |
| return "unknown status code"; |
| } |
| } |
| |
| /************************************************************************************ |
| ** MCAP Callbacks |
| ************************************************************************************/ |
| static void mcap_ctrl_callback(tMCA_HANDLE handle, tMCA_CL mcl, uint8_t event, |
| tMCA_CTRL* p_data) { |
| sMcapTestApp->ControlCallback(handle, mcl, event, p_data); |
| } |
| |
| static void mcap_data_cb(tMCA_DL mdl, BT_HDR* p_pkt) { |
| printf("%s: mdl=%d, event=%d, len=%d, offset=%d, layer_specific=%d\n", |
| __func__, mdl, p_pkt->event, p_pkt->len, p_pkt->offset, |
| p_pkt->layer_specific); |
| printf("%s: HEXDUMP OF DATA LENGTH %u:\n", __func__, p_pkt->len); |
| printf("=========================Begin=========================\n"); |
| bool newline = false; |
| for (int i = 0; i < p_pkt->len; ++i) { |
| printf("%02x", p_pkt->data[i]); |
| if (i > 0 && (i % 25) == 0) { |
| printf("\n"); |
| newline = true; |
| } else { |
| printf(" "); |
| newline = false; |
| } |
| } |
| if (!newline) printf("\n"); |
| printf("=========================End===========================\n"); |
| } |
| |
| /************************************************************************************ |
| ** Shutdown helper functions |
| ************************************************************************************/ |
| |
| static void console_shutdown(void) { |
| LOG(INFO) << __func__ << ": Shutdown Fluoride MCAP test app"; |
| global_main_done = true; |
| } |
| |
| /***************************************************************************** |
| ** Android's init.rc does not yet support applying linux capabilities |
| *****************************************************************************/ |
| |
| #ifndef OS_GENERIC |
| static void config_permissions(void) { |
| struct __user_cap_header_struct header; |
| struct __user_cap_data_struct cap[2]; |
| |
| printf("set_aid_and_cap : pid %d, uid %d gid %d", getpid(), getuid(), |
| getgid()); |
| |
| header.pid = 0; |
| |
| prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0); |
| |
| setuid(AID_BLUETOOTH); |
| setgid(AID_BLUETOOTH); |
| |
| header.version = _LINUX_CAPABILITY_VERSION_3; |
| |
| cap[CAP_TO_INDEX(CAP_NET_RAW)].permitted |= CAP_TO_MASK(CAP_NET_RAW); |
| cap[CAP_TO_INDEX(CAP_NET_ADMIN)].permitted |= CAP_TO_MASK(CAP_NET_ADMIN); |
| cap[CAP_TO_INDEX(CAP_NET_BIND_SERVICE)].permitted |= |
| CAP_TO_MASK(CAP_NET_BIND_SERVICE); |
| cap[CAP_TO_INDEX(CAP_SYS_RAWIO)].permitted |= CAP_TO_MASK(CAP_SYS_RAWIO); |
| cap[CAP_TO_INDEX(CAP_SYS_NICE)].permitted |= CAP_TO_MASK(CAP_SYS_NICE); |
| cap[CAP_TO_INDEX(CAP_SETGID)].permitted |= CAP_TO_MASK(CAP_SETGID); |
| cap[CAP_TO_INDEX(CAP_WAKE_ALARM)].permitted |= CAP_TO_MASK(CAP_WAKE_ALARM); |
| |
| cap[CAP_TO_INDEX(CAP_NET_RAW)].effective |= CAP_TO_MASK(CAP_NET_RAW); |
| cap[CAP_TO_INDEX(CAP_NET_ADMIN)].effective |= CAP_TO_MASK(CAP_NET_ADMIN); |
| cap[CAP_TO_INDEX(CAP_NET_BIND_SERVICE)].effective |= |
| CAP_TO_MASK(CAP_NET_BIND_SERVICE); |
| cap[CAP_TO_INDEX(CAP_SYS_RAWIO)].effective |= CAP_TO_MASK(CAP_SYS_RAWIO); |
| cap[CAP_TO_INDEX(CAP_SYS_NICE)].effective |= CAP_TO_MASK(CAP_SYS_NICE); |
| cap[CAP_TO_INDEX(CAP_SETGID)].effective |= CAP_TO_MASK(CAP_SETGID); |
| cap[CAP_TO_INDEX(CAP_WAKE_ALARM)].effective |= CAP_TO_MASK(CAP_WAKE_ALARM); |
| |
| capset(&header, &cap[0]); |
| setgroups(sizeof(groups) / sizeof(groups[0]), groups); |
| } |
| #endif |
| |
| /******************************************************************************* |
| ** Console helper functions |
| *******************************************************************************/ |
| |
| void skip_blanks(char** p) { |
| while (**p == ' ') (*p)++; |
| } |
| |
| uint32_t get_int(char** p, int DefaultValue) { |
| uint32_t Value = 0; |
| unsigned char UseDefault; |
| |
| UseDefault = 1; |
| skip_blanks(p); |
| |
| while (((**p) <= '9' && (**p) >= '0')) { |
| Value = Value * 10 + (**p) - '0'; |
| UseDefault = 0; |
| (*p)++; |
| } |
| |
| if (UseDefault) |
| return DefaultValue; |
| else |
| return Value; |
| } |
| |
| int get_signed_int(char** p, int DefaultValue) { |
| int Value = 0; |
| unsigned char UseDefault; |
| unsigned char NegativeNum = 0; |
| |
| UseDefault = 1; |
| skip_blanks(p); |
| |
| if ((**p) == '-') { |
| NegativeNum = 1; |
| (*p)++; |
| } |
| while (((**p) <= '9' && (**p) >= '0')) { |
| Value = Value * 10 + (**p) - '0'; |
| UseDefault = 0; |
| (*p)++; |
| } |
| |
| if (UseDefault) |
| return DefaultValue; |
| else |
| return ((NegativeNum == 0) ? Value : -Value); |
| } |
| |
| void get_str(char** p, char* Buffer) { |
| skip_blanks(p); |
| |
| while (**p != 0 && **p != ' ') { |
| *Buffer = **p; |
| (*p)++; |
| Buffer++; |
| } |
| |
| *Buffer = 0; |
| } |
| |
| uint32_t get_hex_any(char** p, int DefaultValue, unsigned int NumOfNibble) { |
| uint32_t Value = 0; |
| unsigned char UseDefault; |
| // unsigned char NumOfNibble = 8; //Since we are returning uint32, max |
| // allowed is 4 bytes(8 nibbles). |
| |
| UseDefault = 1; |
| skip_blanks(p); |
| |
| while ((NumOfNibble) && |
| (((**p) <= '9' && (**p) >= '0') || ((**p) <= 'f' && (**p) >= 'a') || |
| ((**p) <= 'F' && (**p) >= 'A'))) { |
| if (**p >= 'a') |
| Value = Value * 16 + (**p) - 'a' + 10; |
| else if (**p >= 'A') |
| Value = Value * 16 + (**p) - 'A' + 10; |
| else |
| Value = Value * 16 + (**p) - '0'; |
| UseDefault = 0; |
| (*p)++; |
| NumOfNibble--; |
| } |
| |
| if (UseDefault) |
| return DefaultValue; |
| else |
| return Value; |
| } |
| uint32_t get_hex(char** p, int DefaultValue) { |
| return get_hex_any(p, DefaultValue, 8); |
| } |
| uint8_t get_hex_byte(char** p, int DefaultValue) { |
| return get_hex_any(p, DefaultValue, 2); |
| } |
| |
| bool is_cmd(const char* cmd, const char* str) { |
| return (strlen(str) == strlen(cmd)) && (strncmp(cmd, str, strlen(str)) == 0); |
| } |
| |
| typedef void(console_cmd_handler_t)(char* p); |
| |
| typedef struct { |
| const char* name; |
| console_cmd_handler_t* handler; |
| const char* help; |
| bool is_job; |
| } cmd_t; |
| |
| extern const cmd_t console_cmd_list[]; |
| static int console_cmd_maxlen = 0; |
| |
| static void* cmdjob_handler(void* param) { |
| char* job_cmd = (char*)param; |
| LOG(INFO) << "cmdjob starting: " << job_cmd; |
| process_cmd(job_cmd, true); |
| LOG(INFO) << "cmdjob terminating"; |
| free(job_cmd); |
| return nullptr; |
| } |
| |
| static int create_cmdjob(char* cmd) { |
| CHECK(cmd); |
| char* job_cmd = (char*)calloc(1, strlen(cmd) + 1); /* freed in job handler */ |
| if (job_cmd) { |
| strlcpy(job_cmd, cmd, strlen(job_cmd) + 1); |
| pthread_t thread_id; |
| int ret = |
| pthread_create(&thread_id, nullptr, cmdjob_handler, (void*)job_cmd); |
| LOG_IF(ERROR, ret != 0) << "Error during pthread_create"; |
| } else { |
| LOG(INFO) << "Cannot Allocate memory for cmdjob: " << cmd; |
| } |
| return 0; |
| } |
| |
| /******************************************************************************* |
| ** Load stack lib |
| *******************************************************************************/ |
| |
| int HAL_load(void) { |
| int err = 0; |
| hw_module_t* module; |
| hw_device_t* device; |
| LOG(INFO) << "Loading HAL library and extensions"; |
| #if defined(OS_GENERIC) |
| err = hal_util_load_bt_library((hw_module_t const**)&module); |
| #else |
| err = hw_get_module(BT_HARDWARE_MODULE_ID, (hw_module_t const**)&module); |
| #endif |
| if (!err) { |
| err = module->methods->open(module, BT_HARDWARE_MODULE_ID, &device); |
| if (!err) { |
| sBtDevice = (bluetooth_device_t*)device; |
| sBtInterface = sBtDevice->get_bluetooth_interface(); |
| } |
| } |
| LOG(INFO) << "HAL library loaded, status: " << strerror(err); |
| return err; |
| } |
| |
| int HAL_unload(void) { |
| int err = 0; |
| LOG(INFO) << "Unloading HAL lib"; |
| sBtInterface = nullptr; |
| LOG(INFO) << "HAL library unloaded, status: " << strerror(err); |
| return err; |
| } |
| |
| /******************************************************************************* |
| ** HAL test functions & callbacks |
| *******************************************************************************/ |
| |
| void setup_test_env(void) { |
| int i = 0; |
| while (console_cmd_list[i].name) { |
| console_cmd_maxlen = |
| MAX(console_cmd_maxlen, (int)strlen(console_cmd_list[i].name)); |
| i++; |
| } |
| } |
| |
| void check_return_status(bt_status_t status) { |
| if (status != BT_STATUS_SUCCESS) { |
| LOG(INFO) << "HAL REQUEST FAILED status : " << status << " (" |
| << dump_bt_status(status) << ")"; |
| } else { |
| LOG(INFO) << "HAL REQUEST SUCCESS"; |
| } |
| } |
| |
| static void adapter_state_changed(bt_state_t state) { |
| int V1 = 1000, V2 = 2; |
| bt_property_t property = {BT_PROPERTY_ADAPTER_DISCOVERY_TIMEOUT, 4, &V1}; |
| bt_property_t property1 = {BT_PROPERTY_ADAPTER_SCAN_MODE, 2, &V2}; |
| bt_property_t property2 = {BT_PROPERTY_BDNAME, 6, (void*)"Fluoride_Test"}; |
| |
| global_adapter_state = state; |
| |
| if (state == BT_STATE_ON) { |
| global_bt_enabled = true; |
| global_status = (bt_status_t)sBtInterface->set_adapter_property(&property1); |
| global_status = (bt_status_t)sBtInterface->set_adapter_property(&property); |
| global_status = (bt_status_t)sBtInterface->set_adapter_property(&property2); |
| } else { |
| global_bt_enabled = false; |
| } |
| } |
| |
| static void adapter_properties_changed(bt_status_t status, int num_properties, |
| bt_property_t* properties) { |
| RawAddress bd_addr; |
| bdstr_t bd_addr_str; |
| if (!properties) { |
| printf("properties is null\n"); |
| return; |
| } |
| switch (properties->type) { |
| case BT_PROPERTY_BDADDR: |
| memcpy(bd_addr.address, properties->val, |
| MIN((size_t)properties->len, sizeof(bd_addr))); |
| bdaddr_to_string(&bd_addr, bd_addr_str, sizeof(bd_addr_str)); |
| LOG(INFO) << "Local Bd Addr = " << bd_addr_str; |
| break; |
| default: |
| break; |
| } |
| return; |
| } |
| |
| static void discovery_state_changed(bt_discovery_state_t state) { |
| LOG(INFO) << "Discovery State Updated: " |
| << (state == BT_DISCOVERY_STOPPED ? "STOPPED" : "STARTED"); |
| } |
| |
| static void pin_request_cb(RawAddress* remote_bd_addr, bt_bdname_t* bd_name, |
| uint32_t cod, bool min_16_digit) { |
| bt_pin_code_t pincode = {{0x31, 0x32, 0x33, 0x34}}; |
| |
| if (BT_STATUS_SUCCESS != |
| sBtInterface->pin_reply(remote_bd_addr, true, 4, &pincode)) { |
| LOG(INFO) << "Pin Reply failed"; |
| } |
| } |
| |
| static void ssp_request_cb(RawAddress* remote_bd_addr, bt_bdname_t* bd_name, |
| uint32_t cod, bt_ssp_variant_t pairing_variant, |
| uint32_t pass_key) { |
| LOG(INFO) << __func__ << ": device_name:" << bd_name->name |
| << ", pairing_variant: " << (int)pairing_variant |
| << ", passkey: " << unsigned(pass_key); |
| if (BT_STATUS_SUCCESS != |
| sBtInterface->ssp_reply(remote_bd_addr, pairing_variant, true, |
| pass_key)) { |
| LOG(ERROR) << "SSP Reply failed"; |
| } |
| } |
| |
| static void bond_state_changed_cb(bt_status_t status, |
| RawAddress* remote_bd_addr, |
| bt_bond_state_t state) { |
| LOG(INFO) << "Bond State Changed = " << state; |
| global_pair_state = state; |
| } |
| |
| static void acl_state_changed(bt_status_t status, RawAddress* remote_bd_addr, |
| bt_acl_state_t state) { |
| bdstr_t bd_addr_str; |
| bdaddr_to_string(remote_bd_addr, bd_addr_str, sizeof(bd_addr_str)); |
| LOG(INFO) << __func__ << ": remote_bd_addr=" << bd_addr_str << ", acl status=" |
| << (state == BT_ACL_STATE_CONNECTED ? "ACL Connected" |
| : "ACL Disconnected"); |
| } |
| |
| static void dut_mode_recv(uint16_t opcode, uint8_t* buf, uint8_t len) { |
| LOG(INFO) << "DUT MODE RECV : NOT IMPLEMENTED"; |
| } |
| |
| static bt_callbacks_t bt_callbacks = { |
| sizeof(bt_callbacks_t), |
| adapter_state_changed, |
| adapter_properties_changed, /*adapter_properties_cb */ |
| nullptr, /* remote_device_properties_cb */ |
| nullptr, /* device_found_cb */ |
| discovery_state_changed, /* discovery_state_changed_cb */ |
| pin_request_cb, /* pin_request_cb */ |
| ssp_request_cb, /* ssp_request_cb */ |
| bond_state_changed_cb, /*bond_state_changed_cb */ |
| acl_state_changed, /* acl_state_changed_cb */ |
| nullptr, /* thread_evt_cb */ |
| dut_mode_recv, /*dut_mode_recv_cb */ |
| nullptr, /* le_test_mode_cb */ |
| nullptr /* energy_info_cb */ |
| }; |
| |
| static bool set_wake_alarm(uint64_t delay_millis, bool should_wake, alarm_cb cb, |
| void* data) { |
| static timer_t timer; |
| static bool timer_created; |
| |
| if (!timer_created) { |
| struct sigevent sigevent; |
| memset(&sigevent, 0, sizeof(sigevent)); |
| sigevent.sigev_notify = SIGEV_THREAD; |
| sigevent.sigev_notify_function = (void (*)(union sigval))cb; |
| sigevent.sigev_value.sival_ptr = data; |
| timer_create(CLOCK_MONOTONIC, &sigevent, &timer); |
| timer_created = true; |
| } |
| |
| struct itimerspec new_value; |
| new_value.it_value.tv_sec = delay_millis / 1000; |
| new_value.it_value.tv_nsec = (delay_millis % 1000) * 1000 * 1000; |
| new_value.it_interval.tv_sec = 0; |
| new_value.it_interval.tv_nsec = 0; |
| timer_settime(timer, 0, &new_value, nullptr); |
| |
| return true; |
| } |
| |
| static int acquire_wake_lock(const char* lock_name) { |
| return BT_STATUS_SUCCESS; |
| } |
| |
| static int release_wake_lock(const char* lock_name) { |
| return BT_STATUS_SUCCESS; |
| } |
| |
| static bt_os_callouts_t callouts = { |
| sizeof(bt_os_callouts_t), set_wake_alarm, acquire_wake_lock, |
| release_wake_lock, |
| }; |
| |
| void adapter_init(void) { |
| LOG(INFO) << __func__; |
| global_status = (bt_status_t)sBtInterface->init(&bt_callbacks); |
| if (global_status == BT_STATUS_SUCCESS) { |
| global_status = (bt_status_t)sBtInterface->set_os_callouts(&callouts); |
| } |
| check_return_status(global_status); |
| } |
| |
| void adapter_enable(void) { |
| LOG(INFO) << __func__; |
| if (global_bt_enabled) { |
| LOG(INFO) << __func__ << ": Bluetooth is already enabled"; |
| return; |
| } |
| global_status = (bt_status_t)sBtInterface->enable(global_strict_mode); |
| check_return_status(global_status); |
| } |
| |
| void adapter_disable(void) { |
| LOG(INFO) << __func__; |
| if (!global_bt_enabled) { |
| LOG(INFO) << __func__ << ": Bluetooth is already disabled"; |
| return; |
| } |
| global_status = (bt_status_t)sBtInterface->disable(); |
| check_return_status(global_status); |
| } |
| void adapter_dut_mode_configure(char* p) { |
| LOG(INFO) << __func__; |
| if (!global_bt_enabled) { |
| LOG(INFO) << __func__ |
| << ": Bluetooth must be enabled for test_mode to work."; |
| return; |
| } |
| int32_t mode = get_signed_int(&p, -1); // arg1 |
| if ((mode != 0) && (mode != 1)) { |
| LOG(INFO) << __func__ << "Please specify mode: 1 to enter, 0 to exit"; |
| return; |
| } |
| global_status = (bt_status_t)sBtInterface->dut_mode_configure(mode); |
| check_return_status(global_status); |
| } |
| |
| void adapter_cleanup(void) { |
| LOG(INFO) << __func__; |
| sBtInterface->cleanup(); |
| } |
| |
| /******************************************************************************* |
| ** Console commands |
| *******************************************************************************/ |
| |
| void do_help(char* p) { |
| int i = 0; |
| char line[128]; |
| int pos = 0; |
| |
| while (console_cmd_list[i].name != nullptr) { |
| pos = snprintf(line, sizeof(line), "%s", (char*)console_cmd_list[i].name); |
| printf("%s %s\n", (char*)line, (char*)console_cmd_list[i].help); |
| i++; |
| } |
| } |
| |
| void do_quit(char* p) { console_shutdown(); } |
| |
| /******************************************************************* |
| * |
| * BT TEST CONSOLE COMMANDS |
| * |
| * Parses argument lists and passes to API test function |
| * |
| */ |
| |
| void do_init(char* p) { adapter_init(); } |
| |
| void do_enable(char* p) { adapter_enable(); } |
| |
| void do_disable(char* p) { adapter_disable(); } |
| |
| void do_cleanup(char* p) { adapter_cleanup(); } |
| |
| /** |
| * MCAP API commands |
| */ |
| void do_mcap_register(char* p) { |
| uint16_t ctrl_psm = get_hex(&p, 0); // arg1 |
| uint16_t data_psm = get_hex(&p, 0); // arg2 |
| uint16_t sec_mask = get_int(&p, 0); // arg3 |
| printf("%s: ctrl_psm=0x%04x, data_psm=0x%04x, sec_mask=0x%04x\n", __func__, |
| ctrl_psm, data_psm, sec_mask); |
| if (!ctrl_psm || !data_psm) { |
| printf("%s: Invalid Parameters\n", __func__); |
| return; |
| } |
| sMcapTestApp->Register(ctrl_psm, data_psm, sec_mask, mcap_ctrl_callback); |
| printf("%s: mcap_handle=%d\n", __func__, sMcapTestApp->GetHandle()); |
| } |
| |
| void do_mcap_deregister(char* p) { |
| printf("%s: mcap_handle=%d\n", __func__, sMcapTestApp->GetHandle()); |
| sMcapTestApp->Deregister(); |
| printf("%s: handle=%d\n", __func__, sMcapTestApp->GetHandle()); |
| } |
| |
| void do_mcap_create_mdep(char* p) { |
| int type = get_int(&p, -1); // arg1 |
| printf("%s: mcap_handle=%d, type=%d\n", __func__, sMcapTestApp->GetHandle(), |
| type); |
| bool ret = sMcapTestApp->CreateMdep(type, MCA_NUM_MDLS, mcap_data_cb); |
| printf("%s: %s\n", __func__, ret ? "SUCCESS" : "FAIL"); |
| } |
| |
| static void do_mcap_delete_mdep(char* p) { |
| uint8_t mdep_handle = get_int(&p, 0); |
| printf("%s: mcap_handle=%d, mdep_handle=%d\n", __func__, |
| sMcapTestApp->GetHandle(), mdep_handle); |
| if (!mdep_handle) { |
| printf("%s: Invalid Parameters\n", __func__); |
| return; |
| } |
| McapMdep* mcap_mdep = sMcapTestApp->FindMdepByHandle(mdep_handle); |
| if (!mcap_mdep) { |
| LOG(ERROR) << "No MDEP for handle " << (int)mdep_handle; |
| return; |
| } |
| bool ret = mcap_mdep->Delete(); |
| printf("%s: %s\n", __func__, ret ? "SUCCESS" : "FAIL"); |
| } |
| |
| static void do_mcap_connect_mcl(char* p) { |
| char buf[64]; |
| get_str(&p, buf); // arg1 |
| RawAddress bd_addr; |
| bool valid_bd_addr = string_to_bdaddr(buf, &bd_addr); |
| uint16_t ctrl_psm = get_hex(&p, 0); // arg2 |
| uint16_t sec_mask = get_int(&p, 0); // arg3 |
| printf("%s: mcap_handle=%d, ctrl_psm=0x%04x, secMask=0x%04x, bd_addr=%s\n", |
| __func__, sMcapTestApp->GetHandle(), ctrl_psm, sec_mask, buf); |
| if (!ctrl_psm || !valid_bd_addr) { |
| printf("%s: Invalid Parameters\n", __func__); |
| return; |
| } |
| bool ret = sMcapTestApp->ConnectMcl(bd_addr, ctrl_psm, sec_mask); |
| printf("%s: %s\n", __func__, ret ? "SUCCESS" : "FAIL"); |
| } |
| |
| static void do_mcap_disconnect_mcl(char* p) { |
| char buf[64]; |
| get_str(&p, buf); // arg1 |
| RawAddress bd_addr; |
| bool valid_bd_addr = string_to_bdaddr(buf, &bd_addr); |
| printf("%s: bd_addr=%s\n", __func__, buf); |
| if (!valid_bd_addr) { |
| printf("%s: Invalid Parameters\n", __func__); |
| return; |
| } |
| McapMcl* mcap_mcl = sMcapTestApp->FindMclByPeerAddress(bd_addr); |
| if (!mcap_mcl) { |
| LOG(ERROR) << "No MCL for bd_addr " << buf; |
| return; |
| } |
| bool ret = mcap_mcl->Disconnect(); |
| printf("%s: %s\n", __func__, ret ? "SUCCESS" : "FAIL"); |
| } |
| |
| static void do_mcap_create_mdl(char* p) { |
| char buf[64]; |
| get_str(&p, buf); // arg1 |
| RawAddress bd_addr; |
| bool valid_bd_addr = string_to_bdaddr(buf, &bd_addr); |
| uint16_t mdep_handle = get_int(&p, 0); // arg2 |
| uint16_t data_psm = get_hex(&p, 0); // arg3 |
| uint16_t mdl_id = get_int(&p, 0); // arg4 |
| uint8_t peer_dep_id = get_int(&p, 0); // arg5 |
| uint8_t cfg = get_hex(&p, 0); // arg6 |
| int do_not_connect = get_int(&p, 0); // arg7 |
| printf( |
| "%s: bd_addr=%s, mdep_handle=%d, data_psm=0x%04x, mdl_id=%d," |
| " peer_dep_id=%d, cfg=0x%02x, do_not_connect=%d\n", |
| __func__, buf, mdep_handle, data_psm, mdl_id, peer_dep_id, cfg, |
| do_not_connect); |
| if (!data_psm || !peer_dep_id || !valid_bd_addr || !mdep_handle) { |
| printf("%s: Invalid Parameters\n", __func__); |
| return; |
| } |
| McapMcl* mcap_mcl = sMcapTestApp->FindMclByPeerAddress(bd_addr); |
| if (!mcap_mcl) { |
| LOG(ERROR) << "No MCL for bd_addr " << buf; |
| return; |
| } |
| bool ret = mcap_mcl->CreateMdl(mdep_handle, data_psm, mdl_id, peer_dep_id, |
| cfg, !do_not_connect); |
| printf("%s: %s\n", __func__, ret ? "SUCCESS" : "FAIL"); |
| } |
| |
| static void do_mcap_data_channel_config(char* p) { |
| char buf[64]; |
| get_str(&p, buf); // arg1 |
| RawAddress bd_addr; |
| bool valid_bd_addr = string_to_bdaddr(buf, &bd_addr); |
| printf("%s: bd_addr=%s\n", __func__, buf); |
| if (!valid_bd_addr) { |
| printf("%s: Invalid Parameters\n", __func__); |
| return; |
| } |
| McapMcl* mcap_mcl = sMcapTestApp->FindMclByPeerAddress(bd_addr); |
| if (!mcap_mcl) { |
| LOG(ERROR) << "No MCL for bd_addr " << buf; |
| return; |
| } |
| bool ret = mcap_mcl->DataChannelConfig(); |
| printf("%s: %s\n", __func__, ret ? "SUCCESS" : "FAIL"); |
| } |
| |
| static void do_mcap_abort_mdl(char* p) { |
| char buf[64]; |
| get_str(&p, buf); // arg1 |
| RawAddress bd_addr; |
| bool valid_bd_addr = string_to_bdaddr(buf, &bd_addr); |
| printf("%s: bd_addr=%s\n", __func__, buf); |
| if (!valid_bd_addr) { |
| printf("%s: Invalid Parameters\n", __func__); |
| return; |
| } |
| McapMcl* mcap_mcl = sMcapTestApp->FindMclByPeerAddress(bd_addr); |
| if (!mcap_mcl) { |
| LOG(ERROR) << "No MCL for bd_addr " << buf; |
| return; |
| } |
| bool ret = mcap_mcl->AbortMdl(); |
| printf("%s: %s\n", __func__, ret ? "SUCCESS" : "FAIL"); |
| } |
| |
| static void do_mcap_delete_mdl(char* p) { |
| char buf[64]; |
| get_str(&p, buf); // arg1 |
| RawAddress bd_addr; |
| bool valid_bd_addr = string_to_bdaddr(buf, &bd_addr); |
| uint16_t mdl_id = get_int(&p, 0); // arg2 |
| printf("%s: bd_addr=%s, mdl_id=%d\n", __func__, buf, mdl_id); |
| if (!valid_bd_addr) { |
| printf("%s: Invalid Parameters\n", __func__); |
| return; |
| } |
| McapMcl* mcap_mcl = sMcapTestApp->FindMclByPeerAddress(bd_addr); |
| if (!mcap_mcl) { |
| LOG(ERROR) << "No MCL for bd_addr " << buf; |
| return; |
| } |
| bool ret = mcap_mcl->DeleteMdl(mdl_id); |
| printf("%s: %s\n", __func__, ret ? "SUCCESS" : "FAIL"); |
| } |
| |
| static void do_mcap_close_mdl(char* p) { |
| char buf[64]; |
| get_str(&p, buf); // arg1 |
| RawAddress bd_addr; |
| bool valid_bd_addr = string_to_bdaddr(buf, &bd_addr); |
| uint16_t mdl_id = get_int(&p, 0); // arg2 |
| printf("%s: bd_addr=%s, mdl_id=%d\n", __func__, buf, mdl_id); |
| if (!valid_bd_addr || !mdl_id) { |
| printf("%s: Invalid Parameters\n", __func__); |
| return; |
| } |
| McapMcl* mcap_mcl = sMcapTestApp->FindMclByPeerAddress(bd_addr); |
| if (!mcap_mcl) { |
| LOG(ERROR) << "No MCL for bd_addr " << buf; |
| return; |
| } |
| McapMdl* mcap_mdl = mcap_mcl->FindMdlById(mdl_id); |
| if (!mcap_mdl) { |
| LOG(ERROR) << "No MDL for ID " << (int)mdl_id; |
| return; |
| } |
| bool ret = mcap_mdl->Close(); |
| printf("%s: %s\n", __func__, ret ? "SUCCESS" : "FAIL"); |
| } |
| |
| static void do_mcap_reconnect_mdl(char* p) { |
| char buf[64]; |
| get_str(&p, buf); // arg1 |
| RawAddress bd_addr; |
| bool valid_bd_addr = string_to_bdaddr(buf, &bd_addr); |
| uint16_t data_psm = get_hex(&p, 0); // arg1 |
| uint16_t mdl_id = get_int(&p, 0); // arg2 |
| printf("%s: data_psm=0x%04x, mdl_id=%d\n", __func__, data_psm, mdl_id); |
| if (!valid_bd_addr) { |
| printf("%s: Invalid Parameters\n", __func__); |
| return; |
| } |
| McapMcl* mcap_mcl = sMcapTestApp->FindMclByPeerAddress(bd_addr); |
| if (!mcap_mcl) { |
| LOG(ERROR) << "No MCL for bd_addr " << buf; |
| return; |
| } |
| McapMdl* mcap_mdl = mcap_mcl->FindMdlById(mdl_id); |
| if (!mcap_mdl) { |
| LOG(ERROR) << "No MDL for ID " << (int)mdl_id; |
| return; |
| } |
| bool ret = mcap_mdl->Reconnect(data_psm); |
| printf("%s: %s\n", __func__, ret ? "SUCCESS" : "FAIL"); |
| } |
| |
| static void do_pairing(char* p) { |
| RawAddress bd_addr; |
| if (!string_to_bdaddr(p, &bd_addr)) { |
| LOG(ERROR) << "Invalid Bluetooth address " << p; |
| return; |
| } |
| if (BT_STATUS_SUCCESS != |
| sBtInterface->create_bond(&bd_addr, BT_TRANSPORT_BR_EDR)) { |
| LOG(ERROR) << "Failed to Initiate Pairing"; |
| return; |
| } |
| } |
| |
| /** CONSOLE COMMAND TABLE */ |
| |
| const cmd_t console_cmd_list[] = { |
| /* INTERNAL */ |
| {"help", do_help, "", 0}, |
| {"quit", do_quit, "", 0}, |
| /* API CONSOLE COMMANDS */ |
| /* Init and Cleanup shall be called automatically */ |
| {"enable_bluetooth", do_enable, "", 0}, |
| {"disable_bluetooth", do_disable, "", 0}, |
| {"pair", do_pairing, "BD_ADDR<xx:xx:xx:xx:xx:xx>", 0}, |
| {"register", do_mcap_register, |
| "ctrl_psm<hex> data_psm<hex> security_mask<0-10>", 0}, |
| {"deregister", do_mcap_deregister, "", 0}, |
| {"create_mdep", do_mcap_create_mdep, "type<0-Echo, 1-Normal>", 0}, |
| {"delete_mdep", do_mcap_delete_mdep, "mdep_handle<int>", 0}, |
| {"connect_mcl", do_mcap_connect_mcl, |
| "BD_ADDR<xx:xx:xx:xx:xx:xx> ctrl_psm<hex> security_mask<0-10>", 0}, |
| {"disconnect_mcl", do_mcap_disconnect_mcl, "BD_ADDR<xx:xx:xx:xx:xx:xx>", 0}, |
| {"create_mdl", do_mcap_create_mdl, |
| "BD_ADDR<xx:xx:xx:xx:xx:xx> mdep_handle<int> data_psm<hex> mdl_id<int> " |
| "peer_dep_id<int> cfg<hex> " |
| "do_not_connect<0-connect,1-wait_for_data_channel_config>", |
| 0}, |
| {"data_channel_config", do_mcap_data_channel_config, |
| "BD_ADDR<xx:xx:xx:xx:xx:xx>", 0}, |
| {"abort_mdl", do_mcap_abort_mdl, "BD_ADDR<xx:xx:xx:xx:xx:xx>", 0}, |
| {"close_mdl", do_mcap_close_mdl, "BD_ADDR<xx:xx:xx:xx:xx:xx> mdl_id<int>", |
| 0}, |
| {"delete_mdl", do_mcap_delete_mdl, "BD_ADDR<xx:xx:xx:xx:xx:xx> mdl_id<int>", |
| 0}, |
| {"reconnect_mdl", do_mcap_reconnect_mdl, |
| "BD_ADDR<xx:xx:xx:xx:xx:xx> data_psm<hex> mdl_id<int>", 0}, |
| /* last entry */ |
| {nullptr, nullptr, "", 0}, |
| }; |
| |
| /** Main console command handler */ |
| |
| static void process_cmd(char* p, bool is_job) { |
| char cmd[2048]; |
| int i = 0; |
| char* p_saved = p; |
| |
| get_str(&p, cmd); // arg1 |
| |
| /* table commands */ |
| while (console_cmd_list[i].name != nullptr) { |
| if (is_cmd(cmd, console_cmd_list[i].name)) { |
| if (!is_job && console_cmd_list[i].is_job) |
| create_cmdjob(p_saved); |
| else { |
| console_cmd_list[i].handler(p); |
| } |
| return; |
| } |
| i++; |
| } |
| LOG(ERROR) << "Unknown command: " << p_saved; |
| do_help(nullptr); |
| } |
| |
| int main(int argc, char* argv[]) { |
| setbuf(stdout, NULL); |
| #if !defined(OS_GENERIC) |
| config_permissions(); |
| #endif |
| LOG(INFO) << "Fluoride MCAP test app is starting"; |
| |
| if (HAL_load() < 0) { |
| fprintf(stderr, "%s: HAL failed to initialize, exit\n", __func__); |
| unlink(PID_FILE); |
| exit(0); |
| } |
| |
| setup_test_env(); |
| |
| /* Automatically perform the init */ |
| adapter_init(); |
| sleep(2); |
| adapter_enable(); |
| sleep(2); |
| sMcapTestInterface = |
| (btmcap_test_interface_t*)sBtInterface->get_profile_interface( |
| BT_TEST_INTERFACE_MCAP_ID); |
| sMcapTestInterface->init(); |
| sMcapTestApp = new McapTestApp(sMcapTestInterface); |
| |
| /* Main loop */ |
| char line[2048]; |
| while (!global_main_done) { |
| memset(line, '\0', sizeof(line)); |
| /* command prompt */ |
| printf(">"); |
| fflush(stdout); |
| fgets(line, sizeof(line), stdin); |
| if (line[0] != '\0') { |
| /* Remove line feed */ |
| line[strlen(line) - 1] = 0; |
| if (strlen(line) != 0) process_cmd(line, false); |
| } |
| } |
| adapter_cleanup(); |
| HAL_unload(); |
| LOG(INFO) << "Fluoride MCAP test app is terminating"; |
| |
| return 0; |
| } |