blob: 6834de43633bfce66a09ee72cc7e6d5a8040f630 [file] [log] [blame]
/*
* 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;
}