blob: 861aaf696c8d2dcddbe953f25f8a468b837038f8 [file] [log] [blame]
/******************************************************************************
*
* 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.c
*
* Description: Bluedroid MCAP TOOL application
*
***********************************************************************************/
#include <stdio.h>
#include <dlfcn.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <pthread.h>
#include <unistd.h>
#include <ctype.h>
#include <fcntl.h>
#include <sys/prctl.h>
#include <sys/capability.h>
#include "l2c_api.h"
#include <arpa/inet.h>
#include <netinet/in.h>
#include <netdb.h>
#include <private/android_filesystem_config.h>
#include <android/log.h>
#include <hardware/hardware.h>
#include <hardware/bluetooth.h>
#include "bt_testapp.h"
#include "mca_defs.h"
#include "mca_api.h"
/************************************************************************************
** Constants & Macros
************************************************************************************/
//#define TRUE 1
//#define FALSE 0
#define PID_FILE "/data/.bdt_pid"
#ifndef MAX
#define MAX(x, y) ((x) > (y) ? (x) : (y))
#endif
#define CASE_RETURN_STR(const) case const: return #const;
#define TRANSPORT_BREDR 1 //Add tranport parameter to create bond
/************************************************************************************
** Local type definitions
************************************************************************************/
/************************************************************************************
** Static variables
************************************************************************************/
static unsigned char main_done = 0;
static bt_status_t status;
static bool strict_mode = FALSE;
/* 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;
enum {
DISCONNECT,
CONNECTING,
CONNECTED,
DISCONNECTING
};
static int g_AdapterState = BT_STATE_OFF;
static int g_PairState = BT_BOND_STATE_NONE;
btmcap_interface_t *sMcapIface = NULL;
tMCA_HANDLE g_Mcap_Handle = 0;
tMCA_DEP g_Mcap_Dep = 0;
tL2CAP_FCR_OPTS g_fcr_opts = {
L2CAP_FCR_ERTM_MODE,
MCA_FCR_OPT_TX_WINDOW_SIZE, /* Tx window size */
MCA_FCR_OPT_MAX_TX_B4_DISCNT, /* Maximum transmissions before disconnecting */
MCA_FCR_OPT_RETX_TOUT, /* Retransmission timeout (2 secs) */
MCA_FCR_OPT_MONITOR_TOUT, /* Monitor timeout (12 secs) */
MCA_FCR_OPT_MPS_SIZE /* MPS segment size */
};
tMCA_CHNL_CFG g_chnl_cfg = {
{
L2CAP_FCR_ERTM_MODE,
MCA_FCR_OPT_TX_WINDOW_SIZE, /* Tx window size */
MCA_FCR_OPT_MAX_TX_B4_DISCNT, /* Maximum transmissions before disconnecting */
MCA_FCR_OPT_RETX_TOUT, /* Retransmission timeout (2 secs) */
MCA_FCR_OPT_MONITOR_TOUT, /* Monitor timeout (12 secs) */
MCA_FCR_OPT_MPS_SIZE /* MPS segment size */
},
BT_DEFAULT_BUFFER_SIZE,
BT_DEFAULT_BUFFER_SIZE,
BT_DEFAULT_BUFFER_SIZE,
BT_DEFAULT_BUFFER_SIZE,
MCA_FCS_NONE,
572
};
UINT16 g_Peer_Mtu = 0;
UINT16 g_Mdl_Id = 0;
tMCA_DL g_Mdl = 0;
tMCA_CL g_Mcl = 0;
/************************************************************************************
** Static functions
************************************************************************************/
static void process_cmd(char *p, unsigned char is_job);
static void bdt_log(const char *fmt_str, ...);
int GetBdAddr(char *p, bt_bdaddr_t *pbd_addr);
static int str2bd(char *str, bt_bdaddr_t *addr)
{
int32_t i = 0;
for (i = 0; i < 6; i++)
{
addr->address[i] = (uint8_t) strtoul(str, (char **)&str, 16);
str++;
}
return 0;
}
/************************************************************************************
** Externs
************************************************************************************/
/************************************************************************************
** MCAP Callbacks
************************************************************************************/
static void mcap_ctrl_cb(tMCA_HANDLE handle, tMCA_CL mcl, UINT8 event, tMCA_CTRL *p_data)
{
tMCA_RESULT Ret;
//printf("%s:: handle=%d, mcl=%d, event=0x%x, g_Mdl=%d, g_Mdl_Id=%d \n", __FUNCTION__, handle, mcl, event, g_Mdl, g_Mdl_Id);
switch(event)
{
case MCA_CREATE_IND_EVT:
//printf("%s::Create_ind::Mdl_Id=%d, OpCode=%d, dep_id=%d, cfg=%d \n", __FUNCTION__, p_data->create_ind.mdl_id,
//p_data->create_ind.op_code, p_data->create_ind.dep_id, p_data->create_ind.cfg);
g_Mdl = p_data->create_ind.mdl_id;
Ret = sMcapIface->CreateMdlRsp(mcl, p_data->create_ind.dep_id,
g_Mdl, p_data->create_ind.cfg, MCA_SUCCESS, &g_chnl_cfg);
break;
case MCA_CONNECT_IND_EVT:
//printf("%s::Connect_Ind:: peer_mtu=%d \n", __FUNCTION__, p_data->connect_ind.mtu);
g_Mcl = mcl;
break;
case MCA_DISCONNECT_IND_EVT:
g_Mcl = 0;
break;
case MCA_OPEN_IND_EVT:
case MCA_OPEN_CFM_EVT:
g_Mdl_Id = p_data->open_ind.mdl_id;
g_Mdl = p_data->open_ind.mdl;
g_Peer_Mtu = p_data->open_ind.mtu;
break;
case MCA_RECONNECT_IND_EVT:
//printf("%s::Reconnect Ind:: Mdl_Id=%d, g_Mdl_Id=%d\n", __FUNCTION__, p_data->reconnect_ind.mdl_id, g_Mdl_Id);
Ret = sMcapIface->ReconnectMdlRsp(mcl, g_Mcap_Dep, p_data->reconnect_ind.mdl_id, (g_Mdl_Id==p_data->reconnect_ind.mdl_id) ?MCA_RSP_SUCCESS :MCA_RSP_BAD_MDL, &g_chnl_cfg);
break;
case MCA_DELETE_IND_EVT:
//printf("%s::Delete Ind:: Mdl_Id=%d\n", __FUNCTION__, p_data->delete_ind.mdl_id);
if((0xffff==p_data->delete_ind.mdl_id)||(g_Mdl_Id == p_data->delete_ind.mdl_id)) g_Mdl_Id = 0;
break;
case MCA_SYNC_CAP_IND_EVT:
//printf("%s::Sync Cap Ind::\n", __FUNCTION__);
break;
case MCA_ABORT_IND_EVT:
//printf("%s::Abort_Ind::Mdl_Id=%d, opCode=%d \n", __FUNCTION__, p_data->abort_ind.mdl_id, p_data->abort_ind.op_code);
break;
}
}
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", __FUNCTION__, mdl, p_pkt->event, p_pkt->len, p_pkt->offset, p_pkt->layer_specific);
}
/************************************************************************************
** Shutdown helper functions
************************************************************************************/
static void bdt_shutdown(void)
{
bdt_log("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[2];
bdt_log("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);
}
/*****************************************************************************
** Logger API
*****************************************************************************/
void bdt_log(const char *fmt_str, ...)
{
static char buffer[1024];
va_list ap;
va_start(ap, fmt_str);
vsnprintf(buffer, 1024, fmt_str, ap);
va_end(ap);
fprintf(stdout, "%s\n", buffer);
}
/*******************************************************************************
** Misc helper functions
*******************************************************************************/
static const char* dump_bt_status(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";
}
}
#if 0
static void hex_dump(char *msg, void *data, int size, int trunc)
{
unsigned char *p = data;
unsigned char c;
int n;
char bytestr[4] = {0};
char addrstr[10] = {0};
char hexstr[ 16*3 + 5] = {0};
char charstr[16*1 + 5] = {0};
bdt_log("%s \n", msg);
/* truncate */
if(trunc && (size>32))
size = 32;
for(n=1;n<=size;n++) {
if (n%16 == 1) {
/* store address for this line */
snprintf(addrstr, sizeof(addrstr), "%.4x",
((unsigned int)p-(unsigned int)data) );
}
c = *p;
if (isalnum(c) == 0) {
c = '.';
}
/* store hex str (for left side) */
snprintf(bytestr, sizeof(bytestr), "%02X ", *p);
strlcat(hexstr, bytestr, sizeof(hexstr)-strlen(hexstr)-1);
/* store char str (for right side) */
snprintf(bytestr, sizeof(bytestr), "%c", c);
strlcat(charstr, bytestr, sizeof(charstr)-strlen(charstr)-1);
if(n%16 == 0) {
/* line completed */
bdt_log("[%4.4s] %-50.50s %s\n", addrstr, hexstr, charstr);
hexstr[0] = 0;
charstr[0] = 0;
} else if(n%8 == 0) {
/* half line: add whitespaces */
strlcat(hexstr, " ", sizeof(hexstr)-strlen(hexstr)-1);
strlcat(charstr, " ", sizeof(charstr)-strlen(charstr)-1);
}
p++; /* next byte */
}
if (strlen(hexstr) > 0) {
/* print rest of buffer if not empty */
bdt_log("[%4.4s] %-50.50s %s\n", addrstr, hexstr, charstr);
}
}
#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)
{
//unsigned char NumOfNibble = 8; //Since we are returning uint32, max allowed is 4 bytes(8 nibbles).
return (get_hex_any(p, DefaultValue, 8));
}
uint32_t get_hex_byte(char **p, int DefaultValue)
{
return (get_hex_any(p, DefaultValue, 2));
}
void get_bdaddr(const char *str, bt_bdaddr_t *bd) {
char *d = ((char *)bd), *endp;
int i;
for(i = 0; i < 6; i++) {
*d++ = strtol(str, &endp, 16);
if (*endp != ':' && i != 5) {
memset(bd, 0, sizeof(bt_bdaddr_t));
return;
}
str = endp + 1;
}
}
#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;
bdt_log("cmdjob starting (%s)", job_cmd);
process_cmd(job_cmd, 1);
bdt_log("cmdjob terminating");
free(job_cmd);
}
static int create_cmdjob(char *cmd)
{
pthread_t thread_id;
char *job_cmd;
job_cmd = (char*)calloc(1, strlen(cmd)+1); /* freed in job handler */
if(job_cmd)
{
strlcpy(job_cmd, cmd, strlen(job_cmd)+1);
if (pthread_create(&thread_id, NULL,
(void*)cmdjob_handler, (void*)job_cmd)!=0)
perror("pthread_create");
}
else
bdt_log("Mecap_test: Cannot Allocate memory for cmdjob");
return 0;
}
/*******************************************************************************
** Load stack lib
*******************************************************************************/
int HAL_load(void)
{
int err = 0;
hw_module_t* module;
hw_device_t* device;
bdt_log("Loading HAL lib + extensions");
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();
}
}
bdt_log("HAL library loaded (%s)", strerror(err));
return err;
}
int HAL_unload(void)
{
int err = 0;
bdt_log("Unloading HAL lib");
sBtInterface = NULL;
bdt_log("HAL library unloaded (%s)", strerror(err));
return err;
}
/*******************************************************************************
** HAL test functions & callbacks
*******************************************************************************/
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++;
}
}
void check_return_status(bt_status_t status)
{
if (status != BT_STATUS_SUCCESS)
{
bdt_log("HAL REQUEST FAILED status : %d (%s)", status, dump_bt_status(status));
}
else
{
bdt_log("HAL 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,"Bluedroid"};
g_AdapterState = state;
if (state == BT_STATE_ON) {
bt_enabled = 1;
status = sBtInterface->set_adapter_property(&property1);
status = sBtInterface->set_adapter_property(&property);
status = sBtInterface->set_adapter_property(&property2);
}
else {
bt_enabled = 0;
}
}
static void adapter_properties_changed(bt_status_t status, int num_properties, bt_property_t *properties)
{
char Bd_addr[15] = {0};
if(NULL == properties)
{
printf("properties is null\n");
return;
}
switch(properties->type)
{
case BT_PROPERTY_BDADDR:
memcpy(Bd_addr, properties->val, properties->len);
printf("Local Bd Addr = %02x:%02x:%02x:%02x:%02x:%02x\n", Bd_addr[0], Bd_addr[1], Bd_addr[2], Bd_addr[3], Bd_addr[4], Bd_addr[5]);
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, 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))
{
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)
{
printf("ssp_request_cb : %s %d %u\n", bd_name->name, pairing_variant, 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)
{
printf("Bond State Changed = %d\n", state);
g_PairState = state;
}
static void acl_state_changed(bt_status_t status, bt_bdaddr_t *remote_bd_addr, bt_acl_state_t state)
{
printf("acl_state_changed : remote_bd_addr=%02x:%02x:%02x:%02x:%02x:%02x, acl status=%s \n",
remote_bd_addr->address[0], remote_bd_addr->address[1], remote_bd_addr->address[2],
remote_bd_addr->address[3], remote_bd_addr->address[4], remote_bd_addr->address[5],
(state == BT_ACL_STATE_CONNECTED)?"ACL Connected" :"ACL Disconnected"
);
}
static void dut_mode_recv(uint16_t opcode, uint8_t *buf, uint8_t len)
{
bdt_log("DUT MODE RECV : NOT IMPLEMENTED");
}
static void le_test_mode(bt_status_t status, uint16_t packet_count)
{
bdt_log("LE TEST MODE END status:%s number_of_packets:%d", dump_bt_status(status), packet_count);
}
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 */
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 */
NULL, /* thread_evt_cb */
dut_mode_recv, /*dut_mode_recv_cb */
// NULL, /*authorize_request_cb */
#if BLE_INCLUDED == TRUE
le_test_mode, /* le_test_mode_cb */
#else
NULL,
#endif
NULL,
NULL
};
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)
{
bdt_log("INIT BT ");
status = sBtInterface->init(&bt_callbacks);
if (status == BT_STATUS_SUCCESS) {
status = sBtInterface->set_os_callouts(&callouts);
}
check_return_status(status);
}
void bdt_enable(void)
{
bdt_log("ENABLE BT");
if (bt_enabled) {
bdt_log("Bluetooth is already enabled");
return;
}
status = sBtInterface->enable(strict_mode);
check_return_status(status);
}
void bdt_disable(void)
{
bdt_log("DISABLE BT");
if (!bt_enabled) {
bdt_log("Bluetooth is already disabled");
return;
}
status = sBtInterface->disable();
check_return_status(status);
}
void bdt_dut_mode_configure(char *p)
{
int32_t mode = -1;
bdt_log("BT DUT MODE CONFIGURE");
if (!bt_enabled) {
bdt_log("Bluetooth must be enabled for test_mode to work.");
return;
}
mode = get_signed_int(&p, mode);
if ((mode != 0) && (mode != 1)) {
bdt_log("Please specify mode: 1 to enter, 0 to exit");
return;
}
status = sBtInterface->dut_mode_configure(mode);
check_return_status(status);
}
#define HCI_LE_RECEIVER_TEST_OPCODE 0x201D
#define HCI_LE_TRANSMITTER_TEST_OPCODE 0x201E
#define HCI_LE_END_TEST_OPCODE 0x201F
void bdt_le_test_mode(char *p)
{
int cmd;
unsigned char buf[3];
int arg1, arg2, arg3;
bdt_log("BT LE TEST MODE");
if (!bt_enabled) {
bdt_log("Bluetooth must be enabled for le_test to work.");
return;
}
memset(buf, 0, sizeof(buf));
cmd = get_int(&p, 0);
switch (cmd)
{
case 0x1: /* RX TEST */
arg1 = get_int(&p, -1);
if (arg1 < 0) bdt_log("%s Invalid arguments", __FUNCTION__);
buf[0] = arg1;
status = sBtInterface->le_test_mode(HCI_LE_RECEIVER_TEST_OPCODE, buf, 1);
break;
case 0x2: /* TX TEST */
arg1 = get_int(&p, -1);
arg2 = get_int(&p, -1);
arg3 = get_int(&p, -1);
if ((arg1 < 0) || (arg2 < 0) || (arg3 < 0))
bdt_log("%s Invalid arguments", __FUNCTION__);
buf[0] = arg1;
buf[1] = arg2;
buf[2] = arg3;
status = sBtInterface->le_test_mode(HCI_LE_TRANSMITTER_TEST_OPCODE, buf, 3);
break;
case 0x3: /* END TEST */
status = sBtInterface->le_test_mode(HCI_LE_END_TEST_OPCODE, buf, 0);
break;
default:
bdt_log("Unsupported command");
return;
break;
}
if (status != BT_STATUS_SUCCESS)
{
bdt_log("%s Test 0x%x Failed with status:0x%x", __FUNCTION__, cmd, status);
}
return;
}
void bdt_cleanup(void)
{
bdt_log("CLEANUP");
sBtInterface->cleanup();
}
/*******************************************************************************
** Console commands
*******************************************************************************/
void do_help(char *p)
{
int i = 0;
char line[128];
int pos = 0;
while (console_cmd_list[i].name != NULL)
{
pos = snprintf(line, sizeof(line), "%s", (char*)console_cmd_list[i].name);
bdt_log("%s %s\n", (char*)line, (char*)console_cmd_list[i].help);
i++;
}
}
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();
}
void do_enable(char *p)
{
bdt_enable();
}
void do_disable(char *p)
{
bdt_disable();
}
void do_cleanup(char *p)
{
bdt_cleanup();
}
/*******************************************************************************
** MCAP API commands
*******************************************************************************/
void do_mcap_register(char *p)
{
tMCA_REG Mca_Reg;
Mca_Reg.rsp_tout = 5000; //Need to check if we have to give in msec or seconds
Mca_Reg.ctrl_psm = get_hex(&p, -1); // arg1
Mca_Reg.data_psm = get_hex(&p, -1); // arg2
Mca_Reg.sec_mask = get_int(&p, -1); // arg3
g_Mcap_Handle = sMcapIface->Register(&Mca_Reg, mcap_ctrl_cb);
printf("%s:: Ret=%d \n", __FUNCTION__, g_Mcap_Handle);
}
void do_mcap_deregister(char *p)
{
sMcapIface->Deregister(g_Mcap_Handle);
printf("%s:: Handle=%d \n", __FUNCTION__, g_Mcap_Handle);
}
void do_mcap_create_dep(char *p)
{
tMCA_RESULT Ret = 0;
int type = 0;
tMCA_CS Mca_cs ;
type = get_int(&p, -1); // arg1
memset ((void*)&Mca_cs ,0 ,sizeof(tMCA_CS));
Mca_cs.type = (0 == type) ? MCA_TDEP_ECHO :MCA_TDEP_DATA;
Mca_cs.max_mdl = MCA_NUM_MDLS;
Mca_cs.p_data_cback = mcap_data_cb;
Ret = sMcapIface->CreateDep(g_Mcap_Handle, &g_Mcap_Dep, &Mca_cs);
printf("%s:: Ret=%d \n", __FUNCTION__, Ret);
}
static void do_mcap_delete_dep(char *p)
{
tMCA_RESULT Ret = 0;
Ret = sMcapIface->DeleteDep(g_Mcap_Handle, g_Mcap_Dep);
printf("%s:: Ret=%d \n", __FUNCTION__, Ret);
}
static void do_mcap_connect(char *p)
{
tMCA_RESULT Ret = 0;
bt_bdaddr_t bd_addr = {{0}};
UINT16 ctrl_psm = 0;
UINT16 sec_mask = 0;
char buf[64];
get_str(&p, buf);
str2bd(buf, &bd_addr);
ctrl_psm = get_hex(&p, -1);// arg2
sec_mask = get_int(&p, -1);// arg3
printf("ctrl_psm=%d, secMask=%d \n", ctrl_psm, sec_mask);
Ret = sMcapIface->ConnectReq(g_Mcap_Handle, bd_addr.address, ctrl_psm, sec_mask);
printf("%s:: Ret=%d \n", __FUNCTION__, Ret);
}
static void do_mcap_disconnect(char *p)
{
tMCA_RESULT Ret = 0;
Ret = sMcapIface->DisconnectReq(g_Mcl);
printf("%s:: Ret=%d \n", __FUNCTION__, Ret);
}
static void do_mcap_create_mdl(char *p)
{
tMCA_RESULT Ret = 0;
UINT16 data_psm = 0;
data_psm = get_hex(&p, -1); // arg1
Ret = sMcapIface->CreateMdl(g_Mcl, g_Mcap_Dep, data_psm, 1, 1, 1, &g_chnl_cfg);
printf("%s:: Ret=%d \n", __FUNCTION__, Ret);
}
static void do_mcap_close(char *p)
{
tMCA_RESULT Ret = 0;
Ret = sMcapIface->CloseReq(g_Mdl);
printf("%s:: Ret=%d \n", __FUNCTION__, Ret);
}
static void do_pairing(char *p)
{
bt_bdaddr_t bd_addr = {{0}};
if(FALSE == GetBdAddr(p, &bd_addr))
return; // arg1
if(BT_STATUS_SUCCESS != sBtInterface->create_bond(&bd_addr, TRANSPORT_BREDR))
{
printf("Failed to Initiate Pairing \n");
return;
}
}
/*******************************************************************
*
* CONSOLE COMMAND TABLE
*
*/
const t_cmd console_cmd_list[] =
{
/*
* INTERNAL
*/
{ "help", do_help, "lists all available console commands", 0 },
{ "quit", do_quit, "", 0},
/*
* API CONSOLE COMMANDS
*/
/* Init and Cleanup shall be called automatically */
{ "enable", do_enable, ":: enables bluetooth", 0 },
{ "disable", do_disable, ":: disables bluetooth", 0 },
{ "pair", do_pairing, ":: BdAddr<00112233445566>", 0 },
{ "register", do_mcap_register, "::Ctrl_Psm<hex>, Data_Psm<hex>, Security<0-10>", 0 },
{ "deregister", do_mcap_deregister, "::", 0 },
{ "create_data_endpoint", do_mcap_create_dep, "::Type<0-Echo, 1-NormalData>", 0 },
{ "delete_data_endpoint", do_mcap_delete_dep, "::", 0 },
{ "connect", do_mcap_connect, ":: BdAddr<00112233445566>, Ctrl_Psm<hex>, SecMask<int>", 0 },
{ "disconnect", do_mcap_disconnect, ":: BdAddr<00112233445566>", 0 },
{ "create_mdl", do_mcap_create_mdl, ":: Data_Psm<hex>", 0 },
{ "close_data_channel", do_mcap_close, "::", 0 },
/* last entry */
{NULL, NULL, "", 0},
};
/*
* Main console command handler
*/
static void process_cmd(char *p, unsigned char is_job)
{
char cmd[2048];
int i = 0;
char *p_saved = p;
get_str(&p, cmd);
/* table commands */
while (console_cmd_list[i].name != NULL)
{
if (is_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++;
}
bdt_log("%s : unknown command\n", p_saved);
do_help(NULL);
}
int main (int argc, char * argv[])
{
config_permissions();
bdt_log("\n:::::::::::::::::::::::::::::::::::::::::::::::::::");
bdt_log(":: Bluedroid test app starting");
if ( HAL_load() < 0 ) {
perror("HAL failed to initialize, exit\n");
unlink(PID_FILE);
exit(0);
}
setup_test_env();
/* Automatically perform the init */
bdt_init();
sleep(5);
bdt_enable();
sleep(5);
sMcapIface = (btmcap_interface_t *)sBtInterface->get_testapp_interface(TEST_APP_MCAP);
//sSmpIface = sBtInterface->get_testapp_interface(TEST_APP_SMP);
sleep(1);
sMcapIface->Init();
while(!main_done)
{
char line[2048];
/* command prompt */
printf( ">" );
fflush(stdout);
fgets (line, 2048, stdin);
if (line[0]!= '\0')
{
/* remove linefeed */
line[strlen(line)-1] = 0;
process_cmd(line, 0);
memset(line, '\0', 2048);
}
}
/* FIXME: Commenting this out as for some reason, the application does not exit otherwise*/
//bdt_cleanup();
HAL_unload();
bdt_log(":: Bluedroid test app terminating");
return 0;
}
int GetBdAddr(char *p, bt_bdaddr_t *pbd_addr)
{
char Arr[13] = {0};
UINT8 k1 = 0;
UINT8 k2 = 0;
int i;
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;
}