| /* |
| * Copyright (c) 2013, The Linux Foundation. All rights reserved. |
| * |
| * Redistribution and use in source and binary forms, with or without |
| * modification, are permitted provided that the following conditions are met: |
| * * Redistributions of source code must retain the above copyright |
| * notice, this list of conditions and the following disclaimer. |
| * * Redistributions in binary form must reproduce the above copyright |
| * notice, this list of conditions and the following disclaimer in the |
| * documentation and/or other materials provided with the distribution. |
| * * Neither the name of The Linux Foundation nor |
| * the names of its contributors may be used to endorse or promote |
| * products derived from this software without specific prior written |
| * permission. |
| * |
| * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" |
| * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
| * IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND |
| * NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR |
| * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, |
| * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
| * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; |
| * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, |
| * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR |
| * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF |
| * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| */ |
| |
| /************************************************************************************ |
| * |
| * Filename: l2test_ertm.c |
| * |
| * Description: Bluedroid Test application |
| * |
| ***********************************************************************************/ |
| |
| #include <stdio.h> |
| #include <stdlib.h> |
| #include "l2c_api.h" |
| #include <bt_testapp.h> |
| #include <sys/capability.h> |
| |
| /************************************************************************************ |
| ** Constants & Macros |
| ************************************************************************************/ |
| |
| #define PID_FILE "/data/.bdt_pid" |
| |
| #ifndef MAX |
| #define MAX(x, y) ((x) > (y) ? (x) : (y)) |
| #endif |
| |
| #define TRANSPORT_BREDR 1 //Add tranport parameter to create bond |
| |
| /************************************************************************************ |
| ** Local type definitions |
| ************************************************************************************/ |
| |
| enum { |
| DISCONNECT, |
| CONNECTING, |
| CONNECTED, |
| DISCONNECTING |
| }; |
| |
| static int g_ConnectionState = DISCONNECT; |
| static int g_AdapterState = BT_STATE_OFF; |
| static int g_PairState = BT_BOND_STATE_NONE; |
| static UINT16 g_SecLevel = 0; |
| static BOOLEAN g_ConnType = TRUE;//DUT is initiating connection |
| static BOOLEAN g_Fcr_Present = FALSE; |
| static UINT8 g_Fcr_Mode = L2CAP_FCR_BASIC_MODE; |
| static UINT8 g_Ertm_AllowedMode = (L2CAP_FCR_CHAN_OPT_BASIC | L2CAP_FCR_CHAN_OPT_ERTM | L2CAP_FCR_CHAN_OPT_STREAM); |
| static int g_LocalBusy = 0; |
| |
| enum { |
| BT_TURNON_CMD, |
| BT_TURNOFF_CMD, |
| I_CONNECT_CMD, |
| O_CONNECT_CMD, |
| DISCONNECT_CMD, |
| SEND_DATA_CMD, |
| O_PAIR_CMD |
| }; |
| |
| enum { |
| SEND, |
| RECEIVE, |
| WAITANDSEND, |
| PAIR, |
| PING, |
| CONNECT, |
| }; |
| |
| static unsigned char *buf; |
| /* Default mtu */ |
| static int g_imtu = 672; |
| static int g_omtu = 0; |
| |
| /* Default FCS option */ |
| static int g_fcs = 0x01; |
| |
| /* Default data size */ |
| static long data_size = -1; |
| static long buffer_size = 2048; |
| static unsigned short cid = 0; |
| |
| static int master = 0; |
| static int auth = 0; |
| static int encrypt = 0; |
| static int secure = 0; |
| /* Default number of frames */ |
| static int num_frames = 1; |
| static int count = 1; |
| |
| /* Default delay before data transfer */ |
| static unsigned long g_delay = 1; |
| |
| static char *filename = NULL; |
| |
| |
| /* Control channel eL2CAP default options */ |
| tL2CAP_FCR_OPTS ertm_fcr_opts_def = { |
| L2CAP_FCR_ERTM_MODE, |
| 3, /* Tx window size */ |
| MCA_FCR_OPT_MAX_TX_B4_DISCNT, /* Maximum transmissions before disconnecting */ |
| 2000, /* Retransmission timeout (2 secs) */ |
| MCA_FCR_OPT_MONITOR_TOUT, /* Monitor timeout (12 secs) */ |
| 100 /* MPS segment size */ |
| }; |
| |
| tL2CAP_FCR_OPTS stream_fcr_opts_def = { |
| L2CAP_FCR_STREAM_MODE, |
| 3,/* Tx window size */ |
| MCA_FCR_OPT_MAX_TX_B4_DISCNT, /* Maximum transmissions before disconnecting */ |
| 2000, /* Retransmission timeout (2 secs) */ |
| MCA_FCR_OPT_MONITOR_TOUT, /* Monitor timeout (12 secs) */ |
| 100 /* MPS segment size */ |
| }; |
| static tL2CAP_ERTM_INFO t_ertm_info = {0}; |
| |
| UINT8 do_l2cap_DataWrite(char *p , UINT32 len); |
| |
| |
| /************************************************************************************ |
| ** Static variables |
| ************************************************************************************/ |
| |
| static unsigned char main_done = 0; |
| static bt_status_t status; |
| |
| /* Main API */ |
| static bluetooth_device_t* bt_device; |
| |
| const bt_interface_t* sBtInterface = NULL; |
| |
| 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}; |
| |
| /* Set to 1 when the Bluedroid stack is enabled */ |
| static unsigned char bt_enabled = 0; |
| |
| const btl2cap_interface_t *sL2capInterface = NULL; |
| |
| enum { |
| L2CAP_NOT_CONNECTED, |
| L2CAP_CONN_SETUP, |
| L2CAP_CONNECTED |
| }; |
| |
| static int L2cap_conn_state = L2CAP_NOT_CONNECTED; |
| static tL2CAP_CFG_INFO tl2cap_cfg_info = {0}; |
| static UINT16 g_PSM = 0; |
| static UINT16 g_lcid = 0; |
| |
| |
| /************************************************************************************ |
| ** Static functions |
| ************************************************************************************/ |
| |
| //static void process_cmd(char *p, unsigned char is_job); |
| static void job_handler(void *param); |
| //static void printf(const char *fmt_str, ...); |
| |
| |
| static int Send_Data(); |
| static int WaitForCompletion(int Cmd, int Timeout); |
| |
| |
| /************************************************************************************ |
| ** Externs |
| ************************************************************************************/ |
| |
| /************************************************************************************ |
| ** Functions |
| ************************************************************************************/ |
| |
| |
| //--------------------l2test---------------------------------------------------- |
| btl2cap_interface_t* get_l2cap_interface(void); |
| |
| |
| |
| static void l2test_l2c_connect_ind_cb(BD_ADDR bd_addr, UINT16 lcid, UINT16 psm, UINT8 id) |
| { |
| |
| if((L2CAP_FCR_ERTM_MODE == g_Fcr_Mode) || (L2CAP_FCR_STREAM_MODE == g_Fcr_Mode)) { |
| sL2capInterface->ErtmConnectRsp(bd_addr, id, lcid, L2CAP_CONN_OK, L2CAP_CONN_OK, &t_ertm_info); |
| } else { |
| sL2capInterface->ConnectRsp(bd_addr, id, lcid, L2CAP_CONN_OK, L2CAP_CONN_OK); |
| } |
| { |
| tL2CAP_CFG_INFO cfg = tl2cap_cfg_info; |
| if ((!sL2capInterface->ConfigReq (lcid, &cfg)) && cfg.fcr_present |
| && cfg.fcr.mode != L2CAP_FCR_BASIC_MODE) { |
| cfg.fcr.mode = L2CAP_FCR_BASIC_MODE; |
| cfg.fcr_present = FALSE; |
| sL2capInterface->ConfigReq (lcid, &cfg); |
| } |
| } |
| g_ConnectionState = CONNECT; |
| g_lcid = lcid; |
| } |
| |
| static void l2test_l2c_connect_cfm_cb(UINT16 lcid, UINT16 result) |
| { |
| |
| if ((result == L2CAP_CONN_OK) ) { |
| L2cap_conn_state = L2CAP_CONN_SETUP; |
| tL2CAP_CFG_INFO cfg = tl2cap_cfg_info; |
| sL2capInterface->ConfigReq (lcid, &cfg); |
| g_imtu = cfg.mtu; |
| g_ConnectionState = CONNECT; |
| g_lcid = lcid; |
| } |
| } |
| |
| static void l2test_l2c_connect_pnd_cb(UINT16 lcid) |
| { |
| g_ConnectionState = CONNECTING; |
| } |
| static void l2test_l2c_config_ind_cb(UINT16 lcid, tL2CAP_CFG_INFO *p_cfg) |
| { |
| p_cfg->result = L2CAP_CFG_OK; |
| p_cfg->fcr_present = FALSE; |
| if(p_cfg->mtu_present) g_omtu = p_cfg->mtu; |
| else g_omtu = L2CAP_DEFAULT_MTU; |
| sL2capInterface->ConfigRsp (lcid, p_cfg); |
| return; |
| } |
| |
| static void l2test_l2c_config_cfm_cb(UINT16 lcid, tL2CAP_CFG_INFO *p_cfg) |
| { |
| |
| /* For now, always accept configuration from the other side */ |
| if (p_cfg->result == L2CAP_CFG_OK) { |
| printf("\nl2test_l2c_config_cfm_cb Success\n"); |
| } else { |
| |
| /* If peer has rejected FCR and suggested basic then try basic */ |
| if (p_cfg->fcr_present) { |
| tL2CAP_CFG_INFO cfg = tl2cap_cfg_info; |
| cfg.fcr_present = FALSE; |
| sL2capInterface->ConfigReq (lcid, &cfg); |
| // Remain in configure state |
| return; |
| } |
| sL2capInterface->DisconnectReq(lcid); |
| } |
| if(0 == g_omtu) g_omtu = L2CAP_DEFAULT_MTU; |
| } |
| |
| static void l2test_l2c_disconnect_ind_cb(UINT16 lcid, BOOLEAN ack_needed) |
| { |
| if (ack_needed) |
| { |
| /* send L2CAP disconnect response */ |
| sL2capInterface->DisconnectRsp(lcid); |
| } |
| g_ConnectionState = DISCONNECTING; |
| g_lcid = 0; |
| } |
| static void l2test_l2c_disconnect_cfm_cb(UINT16 lcid, UINT16 result) |
| { |
| g_ConnectionState = DISCONNECT; |
| g_lcid = 0; |
| } |
| static void l2test_l2c_QoSViolationInd(BD_ADDR bd_addr) |
| { |
| printf("l2test_l2c_QoSViolationInd\n"); |
| } |
| static void l2test_l2c_data_ind_cb(UINT16 lcid, BT_HDR *p_buf) |
| { |
| printf("l2test_l2c_data_ind_cb:: event=%u, len=%u, offset=%u, layer_specific=%u\n", p_buf->event, p_buf->len, p_buf->offset, p_buf->layer_specific); |
| } |
| static void l2test_l2c_congestion_ind_cb(UINT16 lcid, BOOLEAN is_congested) |
| { |
| printf("l2test_l2c_congestion_ind_cb\n"); |
| } |
| |
| static void l2test_l2c_tx_complete_cb (UINT16 lcid, UINT16 NoOfSDU) |
| { |
| printf("l2test_l2c_tx_complete_cb, cid=0x%x, SDUs=%u\n", lcid, NoOfSDU); |
| } |
| |
| static void l2c_echo_rsp_cb(UINT16 p) |
| { |
| printf("Ping Response = %s\n", (L2CAP_PING_RESULT_OK==p) ?"Ping Reply OK" :(L2CAP_PING_RESULT_NO_LINK==p) ?"Link Could Not be setup" :"Remote L2cap did not reply"); |
| } |
| |
| /* L2CAP callback function structure */ |
| static tL2CAP_APPL_INFO l2test_l2c_appl = { |
| // sizeof(l2test_l2c_appl), |
| l2test_l2c_connect_ind_cb, |
| l2test_l2c_connect_cfm_cb, |
| l2test_l2c_connect_pnd_cb, |
| l2test_l2c_config_ind_cb, |
| l2test_l2c_config_cfm_cb, |
| l2test_l2c_disconnect_ind_cb, |
| l2test_l2c_disconnect_cfm_cb, |
| l2test_l2c_QoSViolationInd, |
| l2test_l2c_data_ind_cb, |
| l2test_l2c_congestion_ind_cb, |
| l2test_l2c_tx_complete_cb |
| }; |
| |
| |
| /************************************************************************************ |
| ** Shutdown helper functions |
| ************************************************************************************/ |
| |
| static void bdt_shutdown(void) |
| { |
| printf("shutdown bdroid test app\n"); |
| main_done = 1; |
| } |
| |
| |
| /***************************************************************************** |
| ** Android's init.rc does not yet support applying linux capabilities |
| *****************************************************************************/ |
| |
| static void config_permissions(void) |
| { |
| struct __user_cap_header_struct header; |
| struct __user_cap_data_struct cap; |
| |
| 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; |
| |
| cap.effective = cap.permitted = cap.inheritable = |
| 1 << CAP_NET_RAW | |
| 1 << CAP_NET_ADMIN | |
| 1 << CAP_NET_BIND_SERVICE | |
| 1 << CAP_SYS_RAWIO | |
| 1 << CAP_SYS_NICE | |
| 1 << CAP_SETGID; |
| |
| capset(&header, &cap); |
| setgroups(sizeof(groups)/sizeof(groups[0]), groups); |
| } |
| |
| |
| |
| /***************************************************************************** |
| ** Logger API |
| *****************************************************************************/ |
| |
| |
| /******************************************************************************* |
| ** Console helper functions |
| *******************************************************************************/ |
| |
| void skip_blanks(char **p) |
| { |
| while (**p == ' ') |
| (*p)++; |
| } |
| |
| #define is_cmd(str) ((strlen(str) == strlen(cmd)) && strncmp((const char *)&cmd, str, strlen(str)) == 0) |
| #define if_cmd(str) if (is_cmd(str)) |
| |
| typedef void (t_console_cmd_handler) (char *p); |
| |
| typedef struct { |
| const char *name; |
| t_console_cmd_handler *handler; |
| const char *help; |
| unsigned char is_job; |
| } t_cmd; |
| |
| |
| //const t_cmd console_cmd_list[]; |
| static int console_cmd_maxlen = 0; |
| |
| static void cmdjob_handler(void *param) |
| { |
| char *job_cmd = (char*)param; |
| |
| // process_cmd(job_cmd, 1); |
| free(job_cmd); |
| } |
| |
| static int create_cmdjob(char *cmd) |
| { |
| pthread_t thread_id; |
| char *job_cmd; |
| |
| job_cmd = malloc(strlen(cmd)+1); /* freed in job handler */ |
| if (job_cmd) { |
| strlcpy(job_cmd, cmd, sizeof(job_cmd)); |
| |
| if (pthread_create(&thread_id, NULL, |
| (void*)cmdjob_handler, (void*)job_cmd)!=0) |
| perror("pthread_create"); |
| } |
| |
| return 0; |
| } |
| |
| /******************************************************************************* |
| ** Load stack lib |
| *******************************************************************************/ |
| |
| int HAL_load(void) |
| { |
| int err = 0; |
| |
| hw_module_t* module; |
| hw_device_t* device; |
| |
| err = hw_get_module(BT_HARDWARE_MODULE_ID, (hw_module_t const**)&module); |
| if (err == 0) |
| { |
| err = module->methods->open(module, BT_HARDWARE_MODULE_ID, &device); |
| if (err == 0) { |
| bt_device = (bluetooth_device_t *)device; |
| sBtInterface = bt_device->get_bluetooth_interface(); |
| } |
| } |
| |
| return err; |
| } |
| |
| int HAL_unload(void) |
| { |
| int err = 0; |
| |
| sBtInterface = NULL; |
| |
| return err; |
| } |
| |
| /******************************************************************************* |
| ** HAL test functions & callbacks |
| *******************************************************************************/ |
| #if 0 |
| void setup_test_env(void) |
| { |
| int i = 0; |
| |
| while (console_cmd_list[i].name != NULL) |
| { |
| console_cmd_maxlen = MAX(console_cmd_maxlen, (int)strlen(console_cmd_list[i].name)); |
| i++; |
| } |
| } |
| #endif |
| |
| void check_return_status(bt_status_t status) |
| { |
| if (status != BT_STATUS_SUCCESS) |
| { |
| printf("HAL REQUEST FAILED\n"); |
| } |
| else |
| { |
| printf("\nHAL REQUEST SUCCESS"); |
| } |
| } |
| |
| static void adapter_state_changed(bt_state_t state) |
| { |
| |
| int V1 = 1000, V2=2; |
| bt_property_t property = {9 /*BT_PROPERTY_DISCOVERY_TIMEOUT*/, 4, &V1}; |
| bt_property_t property1 = {7 /*SCAN*/, 2, &V2}; |
| bt_property_t property2 ={1,6,"Amith"}; |
| g_AdapterState = state; |
| |
| if (state == BT_STATE_ON) { |
| status = sBtInterface->set_adapter_property(&property1); |
| status = sBtInterface->set_adapter_property(&property); |
| status = sBtInterface->set_adapter_property(&property2); |
| } |
| } |
| |
| static void adapter_properties_changed(bt_status_t status, int num_properties, bt_property_t *properties) |
| { |
| |
| char Bd_addr[15] = {0}; |
| if(NULL == properties) { |
| return; |
| } |
| switch(properties->type) |
| { |
| case BT_PROPERTY_BDADDR: |
| memcpy(Bd_addr, properties->val, properties->len); |
| break; |
| default: |
| break; |
| } |
| return; |
| } |
| |
| static void discovery_state_changed(bt_discovery_state_t state) |
| { |
| printf("Discovery State Updated : %s\n", (state == BT_DISCOVERY_STOPPED)?"STOPPED":"STARTED"); |
| } |
| |
| |
| static void pin_request_cb(bt_bdaddr_t *remote_bd_addr, bt_bdname_t *bd_name, uint32_t cod) |
| { |
| |
| int ret = 0; |
| bt_pin_code_t pincode = {{ 0x31, 0x32, 0x33, 0x34}}; |
| |
| if(BT_STATUS_SUCCESS != sBtInterface->pin_reply(remote_bd_addr, TRUE, 4, &pincode)) { |
| printf("Pin Reply failed\n"); |
| } |
| } |
| |
| static void ssp_request_cb(bt_bdaddr_t *remote_bd_addr, bt_bdname_t *bd_name, |
| uint32_t cod, bt_ssp_variant_t pairing_variant, uint32_t pass_key) |
| { |
| if(BT_STATUS_SUCCESS != sBtInterface->ssp_reply(remote_bd_addr, pairing_variant, TRUE, pass_key)) { |
| printf("SSP Reply failed\n"); |
| } |
| } |
| |
| static void bond_state_changed_cb(bt_status_t status, bt_bdaddr_t *remote_bd_addr, bt_bond_state_t state) |
| { |
| |
| g_PairState = state; |
| } |
| |
| static void acl_state_changed(bt_status_t status, bt_bdaddr_t *remote_bd_addr, bt_acl_state_t state) |
| { |
| } |
| |
| |
| static void dut_mode_recv(uint16_t opcode, uint8_t *buf, uint8_t len) |
| { |
| printf("DUT MODE RECEIVE : NOT IMPLEMENTED\n"); |
| } |
| |
| static bt_callbacks_t bt_callbacks = { |
| sizeof(bt_callbacks_t), |
| adapter_state_changed, |
| adapter_properties_changed, /*adapter_properties_cb */ |
| NULL, /* remote_device_properties_cb */ |
| NULL, /* device_found_cb */ |
| discovery_state_changed, /* discovery_state_changed_cb */ |
| NULL, /* pin_request_cb */ |
| ssp_request_cb, /* ssp_request_cb */ |
| bond_state_changed_cb, /*bond_state_changed_cb */ |
| acl_state_changed, /* acl_state_changed_cb */ |
| NULL, /* thread_evt_cb */ |
| dut_mode_recv, /*dut_mode_recv_cb */ |
| NULL, /*le_test_mode_cb*/ |
| NULL, /*energy_info_cb */ |
| NULL, /*le_lpp_write_rssi_thresh_cb*/ |
| NULL, /*le_lpp_read_rssi_thresh_cb*/ |
| NULL, /*le_lpp_enable_rssi_monitor_cb*/ |
| NULL /*le_lpp_rssi_threshold_evt_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, NULL); |
| |
| 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 bdt_init(void) |
| { |
| printf("INIT BT \n"); |
| status = sBtInterface->init(&bt_callbacks); |
| if (status == BT_STATUS_SUCCESS) { |
| status = sBtInterface->set_os_callouts(&callouts); |
| } |
| check_return_status(status); |
| } |
| |
| void bdt_enable(void) |
| { |
| //int status = 0; |
| printf("ENABLE BT\n"); |
| if (BT_STATE_ON == g_AdapterState) { |
| printf("Bluetooth is already enabled\n"); |
| return; |
| } |
| status = sBtInterface->enable(false); |
| return; |
| } |
| |
| void bdt_disable(void) |
| { |
| if (BT_STATE_ON != g_AdapterState) |
| { |
| return; |
| } |
| status = sBtInterface->disable(); |
| check_return_status(status); |
| return; |
| } |
| |
| void bdt_cleanup(void) |
| { |
| sBtInterface->cleanup(); |
| } |
| |
| btl2cap_interface_t* get_l2cap_interface(void) |
| { |
| if ((sBtInterface)&&(sBtInterface->get_testapp_interface)) { |
| return (btl2cap_interface_t *) sBtInterface->get_testapp_interface(TEST_APP_L2CAP); |
| } |
| return NULL; |
| } |
| |
| /******************************************************************************* |
| ** Console commands |
| *******************************************************************************/ |
| |
| void do_quit(char *p) |
| { |
| bdt_shutdown(); |
| } |
| |
| /******************************************************************* |
| * |
| * BT TEST CONSOLE COMMANDS |
| * |
| * Parses argument lists and passes to API test function |
| * |
| */ |
| |
| void do_init(char *p) |
| { |
| bdt_init(); |
| } |
| |
| BOOLEAN do_enable(char *p) |
| { |
| bdt_enable(); |
| if(0 != WaitForCompletion(BT_TURNON_CMD, 10)) |
| { |
| printf("BT Turn ON Failed... Exiting...\n"); |
| return FALSE; |
| } |
| return TRUE; |
| } |
| |
| BOOLEAN do_disable(char *p) |
| { |
| bdt_disable(); |
| if(0 != WaitForCompletion(BT_TURNOFF_CMD, 10)) |
| { |
| printf("BT Turn OFF Failed... Exiting...\n"); |
| return FALSE; |
| } |
| return TRUE; |
| } |
| |
| void do_cleanup(char *p) |
| { |
| // bdt_cleanup(); |
| } |
| |
| int GetBdAddr(char *p, bt_bdaddr_t *pbd_addr) |
| { |
| char Arr[13] = {0}; |
| UINT8 k1 = 0; |
| UINT8 k2 = 0; |
| int i; |
| char *t = NULL; |
| |
| if(12 != strlen(p)) |
| { |
| printf("\nInvalid Bd Address. Format[112233445566]\n"); |
| return FALSE; |
| } |
| strlcpy(Arr, p, sizeof(Arr)); |
| for(i=0; i<12; i++) |
| { |
| Arr[i] = tolower(Arr[i]); |
| } |
| for(i=0; i<6; i++) |
| { |
| k1 = (UINT8) ( (Arr[i*2] >= 'a') ? ( 10 + (UINT8)( Arr[i*2] - 'a' )) : (Arr[i*2] - '0') ); |
| k2 = (UINT8) ( (Arr[i*2+1] >= 'a') ? ( 10 + (UINT8)( Arr[i*2+1] - 'a' )) : (Arr[i*2+1] - '0') ); |
| if ( (k1>15)||(k2>15) ) |
| { |
| return FALSE; |
| } |
| pbd_addr->address[i] = (k1<<4 | k2); |
| } |
| return TRUE; |
| } |
| |
| void do_l2cap_init(char *p) |
| { |
| |
| char *value = NULL; |
| |
| memset(&tl2cap_cfg_info, 0, sizeof(tl2cap_cfg_info)); |
| //Use macros for the constants |
| tl2cap_cfg_info.mtu_present = TRUE; |
| tl2cap_cfg_info.mtu = g_imtu; |
| tl2cap_cfg_info.flush_to_present = TRUE; |
| tl2cap_cfg_info.flush_to = 0xffff; |
| //use other param if needed |
| tl2cap_cfg_info.fcr_present = g_Fcr_Present; |
| tl2cap_cfg_info.fcr.mode = g_Fcr_Mode; |
| tl2cap_cfg_info.fcs = 0; |
| tl2cap_cfg_info.fcs_present = 1; |
| |
| if(L2CAP_FCR_ERTM_MODE == tl2cap_cfg_info.fcr.mode) |
| { |
| tl2cap_cfg_info.fcr = ertm_fcr_opts_def; |
| } |
| else if(L2CAP_FCR_STREAM_MODE == tl2cap_cfg_info.fcr.mode) |
| { |
| tl2cap_cfg_info.fcr = stream_fcr_opts_def; |
| } |
| tl2cap_cfg_info.fcr.tx_win_sz = 3; |
| //Initialize ERTM Parameters |
| t_ertm_info.preferred_mode = g_Fcr_Mode; |
| t_ertm_info.allowed_modes = g_Ertm_AllowedMode; |
| t_ertm_info.user_rx_pool_id = HCI_ACL_POOL_ID; |
| t_ertm_info.user_tx_pool_id = HCI_ACL_POOL_ID; |
| t_ertm_info.fcr_rx_pool_id = L2CAP_FCR_RX_POOL_ID; |
| t_ertm_info.fcr_tx_pool_id = L2CAP_FCR_TX_POOL_ID; |
| //Load L2cap Interface |
| if(NULL == sL2capInterface) |
| { |
| sL2capInterface = get_l2cap_interface(); |
| } |
| if (sL2capInterface) |
| sL2capInterface->Init(&l2test_l2c_appl); |
| } |
| |
| void do_l2cap_deregister(char *p) |
| { |
| |
| sL2capInterface->Deregister(g_PSM); |
| } |
| |
| UINT16 do_l2cap_connect(char *p) |
| { |
| |
| bt_bdaddr_t bd_addr = {{0}}; |
| GetBdAddr(p, &bd_addr); |
| |
| if((L2CAP_FCR_STREAM_MODE == g_Fcr_Mode) || (L2CAP_FCR_ERTM_MODE == g_Fcr_Mode)) { |
| return sL2capInterface->ErtmConnectReq(g_PSM,(uint8_t *)&bd_addr.address, &t_ertm_info); |
| } else { |
| return sL2capInterface->Connect(g_PSM, &bd_addr); |
| } |
| } |
| |
| BOOLEAN do_l2cap_ping(char *p) |
| { |
| |
| bt_bdaddr_t bd_addr = {{0}}; |
| GetBdAddr(p, &bd_addr); |
| if(FALSE == sL2capInterface->Ping(bd_addr.address, l2c_echo_rsp_cb)) { |
| printf("Failed to send Ping Request \n"); |
| return FALSE; |
| } |
| return TRUE; |
| } |
| |
| |
| BOOLEAN do_l2cap_disconnect(char *p) |
| { |
| return sL2capInterface->DisconnectReq(g_lcid); |
| } |
| |
| UINT8 do_l2cap_DataWrite(char *p , UINT32 len) |
| { |
| return sL2capInterface->DataWrite(g_lcid, p, len); |
| } |
| |
| static int WaitForCompletion(int Cmd, int Timeout) |
| { |
| int Status = 0xFF; |
| int *pState = NULL; |
| switch(Cmd) |
| { |
| case BT_TURNON_CMD: |
| Status = BT_STATE_ON; |
| pState = &g_AdapterState; |
| break; |
| case BT_TURNOFF_CMD: |
| Status = BT_STATE_OFF; |
| pState = &g_AdapterState; |
| break; |
| case I_CONNECT_CMD: |
| Status = CONNECT; |
| pState = &g_ConnectionState; |
| break; |
| case O_CONNECT_CMD: |
| Status = CONNECT; |
| pState = &g_ConnectionState; |
| break; |
| case DISCONNECT_CMD: |
| Status = DISCONNECT; |
| pState = &g_ConnectionState; |
| break; |
| case SEND_DATA_CMD: |
| // |
| break; |
| case O_PAIR_CMD: |
| Status = BT_BOND_STATE_BONDED; |
| pState = &g_PairState; |
| break; |
| } |
| if(NULL == pState) |
| return 0xFF; |
| while( (Status != *pState) && (Timeout--) ) |
| { |
| sleep(1); |
| } |
| if(Status != *pState) |
| return 1; //Timeout |
| else |
| return 0; //Success |
| } |
| |
| static void l2c_listen(int SendData) |
| { |
| printf("Waiting for Incoming connection... \n"); |
| if(0 != WaitForCompletion(I_CONNECT_CMD, 60)) |
| { |
| printf("No incoming connection... Exiting...\n"); |
| return; |
| } |
| if(TRUE == SendData) |
| { |
| printf(" going to send data...\n"); |
| Send_Data(); |
| } |
| } |
| |
| static int Send_Data() |
| { |
| uint32_t seq =0; |
| int i, fd, len, buflen, size, sent; |
| long buflen_tmp; |
| char *tmpBuf = NULL; |
| |
| if (data_size < 0) |
| data_size = g_omtu; |
| printf("data_size = %ld, g_omtu=%d", data_size, g_omtu); |
| |
| tmpBuf = malloc(data_size); |
| if(NULL == tmpBuf) |
| { |
| printf("Malloc failed \n"); |
| return FALSE; |
| } |
| if (filename) { |
| fd = open(filename, O_RDONLY); |
| printf("Filename for input data = %s \n", filename); |
| if (fd < 0) { |
| printf("Open failed: %s (%d)\n", strerror(errno), errno); |
| exit(1); |
| } |
| while (1) { |
| size = read(fd, tmpBuf, data_size); |
| if(size <= 0) { |
| printf("\n File end "); |
| break; |
| } |
| do_l2cap_DataWrite(tmpBuf, size); |
| } |
| return TRUE; |
| } else { |
| memset(tmpBuf, '\x7f', data_size); |
| } |
| if (num_frames && g_delay && count) { |
| printf("Delay before first send ... %lu msec, size=%ld \n", g_delay/1000, data_size); |
| usleep(g_delay); |
| } |
| printf(" count %d...\n", count); |
| while (count > 0) { |
| char tmpBuffer[] = {0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F}; |
| count--; |
| printf("Before write count is %d...\n", count); |
| sleep(5); |
| do_l2cap_DataWrite(tmpBuffer, 5); |
| if (num_frames && g_delay && count && !(seq % count)) { |
| // printf("Delaying before next send ...%d\n", g_delay); |
| usleep(g_delay); |
| // printf("After Delay before next send ...%d\n", g_delay); |
| } |
| } |
| free(tmpBuf); |
| return TRUE; |
| } |
| |
| static void l2c_connect(char *svr) |
| { |
| |
| printf("In l2c_connect - %s \n", svr); |
| do_l2cap_connect(svr); |
| } |
| |
| static void l2c_send(char *p) |
| { |
| |
| do_l2cap_connect(p); |
| if(0 != WaitForCompletion(I_CONNECT_CMD, 10)) { |
| printf("Connection didnot happen in 10sec... Returning Failure...\n"); |
| return; |
| } |
| sleep(1); //Let Config to complete |
| Send_Data(); |
| } |
| |
| static int l2c_pair(char *p) |
| { |
| bt_bdaddr_t bd_addr = {{0}}; |
| GetBdAddr(p, &bd_addr); |
| if(BT_STATUS_SUCCESS != sBtInterface->create_bond(&bd_addr,TRANSPORT_BREDR)) |
| { |
| printf("Failed to Initiate Pairing \n"); |
| return FALSE; |
| } |
| if(0 != WaitForCompletion(O_PAIR_CMD, 15)) |
| { |
| printf("Pairing didnot happen in 15sec... Returning Failure...\n"); |
| return FALSE; |
| } |
| return TRUE; |
| } |
| |
| static void l2c_ping(char *svr) |
| { |
| |
| printf("In l2c_ping - %s \n", svr); |
| do_l2cap_ping(svr); |
| } |
| |
| static void l2c_disconnect(char *p) |
| { |
| printf("In l2c_disconnect\n"); |
| do_l2cap_disconnect(p); |
| } |
| |
| static void options(void) |
| { |
| printf("Modes:\n" |
| "\t-c connect\n" |
| "\t-r receive\n" |
| "\t-s connect and send\n" |
| "\t-w wait and send\n" |
| "\t-p bonding\n" |
| "\t-a ping\n"); |
| printf("Options:\n" |
| "\t[-b bytes] [-i device] [-P psm] [-J cid]\n" |
| "\t[-I imtu] [-O omtu]\n" |
| "\t[-L localBusy status] 1-localbusy, 0-otherwise (default=0)\n" |
| "\t[-N num] send num frames (default = infinite)\n" |
| "\t[-C num] Count(default = 1)\n" |
| "\t[-D milliseconds] delay after sending num frames (default = 0)\n" |
| "\t[-X mode] select retransmission/flow-control mode\n" |
| "\t(ertm, ertm-mandatory, streaming, streaming-mandatory)\n" |
| "\t[-Q num] retransmit each packet up to num times (default = 3)\n" |
| "\t[-A] authentication\n" |
| "\t[-E] encryption\n" |
| "\t[-S] secure connection\n" |
| "\t[-T] timestamps\n"); |
| } |
| |
| int main(int argc, char *argv[]) |
| { |
| struct sigaction sa; |
| int opt, mode = RECEIVE, addr_required = 0; |
| char temp[3] = {0}; |
| int len =0; |
| |
| while ((opt=getopt(argc,argv,"arswcpb:i:P:K:O:F:N:L:C:D:X:Q:I:W:UGATMES")) != EOF) { |
| switch(opt) { |
| case 'a': |
| mode = PING; |
| addr_required = 1; |
| break; |
| case 'r': |
| mode = RECEIVE; |
| g_ConnType = FALSE; |
| break; |
| |
| case 's': |
| mode = SEND; |
| g_ConnType = TRUE; |
| addr_required = 1; |
| break; |
| |
| case 'w': |
| mode = WAITANDSEND; |
| g_ConnType = FALSE; |
| break; |
| |
| case 'c': |
| mode = CONNECT; |
| g_ConnType = TRUE; |
| addr_required = 1; |
| break; |
| |
| case 'p': |
| mode = PAIR; |
| addr_required = 1; |
| break; |
| |
| case 'b': |
| data_size = atoi(optarg); |
| break; |
| |
| case 'A': |
| auth = 1; |
| break; |
| case 'C': |
| count = atoi(optarg); |
| break; |
| case 'D': |
| g_delay = atoi(optarg) * 1000; |
| break; |
| case 'E': |
| encrypt = 1; |
| break; |
| case 'F': |
| filename = strdup(optarg); |
| break; |
| |
| case 'I': |
| g_imtu = atoi(optarg); |
| break; |
| |
| case 'L': |
| g_LocalBusy = atoi(optarg); |
| break; |
| |
| case 'M': |
| master = 1; |
| break; |
| |
| case 'N': |
| num_frames = atoi(optarg); |
| break; |
| |
| case 'O': |
| g_omtu = atoi(optarg); |
| break; |
| |
| case 'P': |
| g_PSM = atoi(optarg); |
| printf("PSM %d",g_PSM); |
| break; |
| case 'S': |
| secure = 1; |
| break; |
| |
| case 'Q': |
| ertm_fcr_opts_def.max_transmit = atoi(optarg); |
| stream_fcr_opts_def.max_transmit = ertm_fcr_opts_def.max_transmit; |
| break; |
| |
| case 'X': |
| if (strcasecmp(optarg, "ertm-mandatory") == 0) { |
| g_Fcr_Present = TRUE; |
| g_Fcr_Mode = L2CAP_FCR_ERTM_MODE; |
| g_Ertm_AllowedMode = L2CAP_FCR_CHAN_OPT_ERTM; |
| printf("in ERTM Mandatory option - 1\n"); |
| } else if (strcasecmp(optarg, "ertm") == 0) { |
| g_Fcr_Present = TRUE; |
| g_Fcr_Mode = L2CAP_FCR_ERTM_MODE; |
| printf("in ERTM option \n"); |
| } else if (strcasecmp(optarg, "streaming-mandatory") == 0) { |
| printf("FCR Mode selected as Streaming Mandatory\n"); |
| g_Fcr_Present = TRUE; |
| g_Fcr_Mode = L2CAP_FCR_STREAM_MODE; |
| g_Ertm_AllowedMode = L2CAP_FCR_CHAN_OPT_STREAM; |
| } else if (strcasecmp(optarg, "streaming") == 0) { |
| g_Fcr_Present = TRUE; |
| printf("FCR Mode selected as Streaming\n"); |
| g_Fcr_Mode = L2CAP_FCR_STREAM_MODE; |
| } else { |
| g_Fcr_Mode = L2CAP_FCR_BASIC_MODE; |
| printf("FCR Mode selected as Basic. String passed matches none\n"); |
| } |
| break; |
| |
| case 'W': |
| ertm_fcr_opts_def.tx_win_sz = atoi(optarg); |
| stream_fcr_opts_def.tx_win_sz = ertm_fcr_opts_def.tx_win_sz; |
| break; |
| default: |
| options(); |
| exit(1); |
| } |
| } |
| if (addr_required && !(argc - optind)) { |
| options(); |
| exit(1); |
| } |
| |
| if (data_size < 0) |
| buffer_size = (g_omtu > g_imtu) ? g_omtu : g_imtu; |
| else |
| buffer_size = data_size; |
| |
| if (!(buf = malloc(buffer_size))) { |
| perror("Can't allocate data buffer"); |
| exit(1); |
| } |
| |
| memset(&sa, 0, sizeof(sa)); |
| sa.sa_handler = SIG_IGN; |
| sa.sa_flags = SA_NOCLDSTOP; |
| sigaction(SIGCHLD, &sa, NULL); |
| |
| config_permissions(); |
| if ( HAL_load() < 0 ) { |
| perror("HAL failed to initialize, exit\n"); |
| unlink(PID_FILE); |
| exit(0); |
| } |
| |
| //setup_test_env(); |
| bdt_init(); |
| sleep(5); |
| if(FALSE == do_enable(NULL)) |
| goto ERR; |
| printf("\n Before l2cap init\n"); |
| do_l2cap_init(NULL); |
| printf("\n after l2cap init\n"); |
| |
| //Outgoing Connection |
| if(TRUE == g_ConnType) |
| { |
| if(1 == auth) g_SecLevel |= BTM_SEC_OUT_AUTHENTICATE; |
| if(1 == encrypt) g_SecLevel |= BTM_SEC_OUT_ENCRYPT ; |
| } else { |
| if(1 == auth) g_SecLevel |= BTM_SEC_IN_AUTHENTICATE; |
| if(1 == encrypt) g_SecLevel |= BTM_SEC_IN_ENCRYPT ; |
| } |
| |
| if(0 != g_PSM) |
| { |
| printf("g_SecLevel = %d \n", g_SecLevel); |
| sL2capInterface->RegisterPsm(g_PSM, g_ConnType, g_SecLevel /*BTM_SEC_IN_AUTHORIZE */); |
| sleep(3); |
| } |
| |
| switch (mode) { |
| case RECEIVE: |
| l2c_listen(FALSE); |
| break; |
| |
| case SEND: |
| l2c_send(argv[optind]); |
| break; |
| |
| case WAITANDSEND: |
| l2c_listen(TRUE); |
| break; |
| |
| case CONNECT: |
| l2c_connect(argv[optind]); |
| break; |
| |
| case PING: |
| l2c_ping(argv[optind]); |
| break; |
| |
| case PAIR: |
| l2c_pair(argv[optind]); |
| if(0 != g_PSM) { |
| sleep(2); |
| l2c_connect(argv[optind]); |
| } |
| break; |
| } |
| |
| if(0 != g_LocalBusy) { |
| sleep(5); |
| printf("To Send Local BusyStatus.... Press any key\n"); |
| read(0, &temp, 2); |
| sL2capInterface->FlowControl(g_lcid, 0); //second param is 'dataEnabled', making it false means localBusy |
| } |
| |
| ERR: |
| while(1) { |
| sleep(5); |
| printf("Enter Y/y to Exit... \n"); |
| len = read(0, &temp, 2); |
| if((temp[0] == 'Y') || (temp[0] == 'y')) |
| break; |
| } |
| //bdt_cleanup(); |
| if(g_ConnectionState == CONNECT) { |
| l2c_disconnect(NULL); |
| sleep(5); |
| } |
| do_disable(NULL); |
| HAL_unload(); |
| return 0; |
| } |