Home | History | Annotate | Download | only in bluedroidtest
      1 /******************************************************************************
      2  *
      3  *  Copyright (C) 2009-2012 Broadcom Corporation
      4  *
      5  *  Licensed under the Apache License, Version 2.0 (the "License");
      6  *  you may not use this file except in compliance with the License.
      7  *  You may obtain a copy of the License at:
      8  *
      9  *  http://www.apache.org/licenses/LICENSE-2.0
     10  *
     11  *  Unless required by applicable law or agreed to in writing, software
     12  *  distributed under the License is distributed on an "AS IS" BASIS,
     13  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     14  *  See the License for the specific language governing permissions and
     15  *  limitations under the License.
     16  *
     17  ******************************************************************************/
     18 
     19 /************************************************************************************
     20  *
     21  *  Filename:      bluedroidtest.c
     22  *
     23  *  Description:   Bluedroid Test application
     24  *
     25  ***********************************************************************************/
     26 
     27 #include <stdio.h>
     28 #include <dlfcn.h>
     29 #include <stdlib.h>
     30 #include <errno.h>
     31 #include <string.h>
     32 #include <pthread.h>
     33 #include <unistd.h>
     34 #include <ctype.h>
     35 #include <fcntl.h>
     36 #include <sys/prctl.h>
     37 #include <sys/capability.h>
     38 
     39 #include <arpa/inet.h>
     40 #include <netinet/in.h>
     41 #include <netdb.h>
     42 
     43 #include <private/android_filesystem_config.h>
     44 #include <android/log.h>
     45 
     46 #include <hardware/hardware.h>
     47 #include <hardware/bluetooth.h>
     48 
     49 /************************************************************************************
     50 **  Constants & Macros
     51 ************************************************************************************/
     52 
     53 #define PID_FILE "/data/.bdt_pid"
     54 
     55 #ifndef MAX
     56 #define MAX(x, y) ((x) > (y) ? (x) : (y))
     57 #endif
     58 
     59 #define CASE_RETURN_STR(const) case const: return #const;
     60 
     61 #define UNUSED __attribute__((unused))
     62 
     63 /************************************************************************************
     64 **  Local type definitions
     65 ************************************************************************************/
     66 
     67 /************************************************************************************
     68 **  Static variables
     69 ************************************************************************************/
     70 
     71 static unsigned char main_done = 0;
     72 static bt_status_t status;
     73 
     74 /* Main API */
     75 static bluetooth_device_t* bt_device;
     76 
     77 const bt_interface_t* sBtInterface = NULL;
     78 
     79 static gid_t groups[] = { AID_NET_BT, AID_INET, AID_NET_BT_ADMIN,
     80                           AID_SYSTEM, AID_MISC, AID_SDCARD_RW,
     81                           AID_NET_ADMIN, AID_VPN};
     82 
     83 /* Set to 1 when the Bluedroid stack is enabled */
     84 static unsigned char bt_enabled = 0;
     85 
     86 /************************************************************************************
     87 **  Static functions
     88 ************************************************************************************/
     89 
     90 static void process_cmd(char *p, unsigned char is_job);
     91 static void job_handler(void *param);
     92 static void bdt_log(const char *fmt_str, ...);
     93 
     94 
     95 /************************************************************************************
     96 **  Externs
     97 ************************************************************************************/
     98 
     99 /************************************************************************************
    100 **  Functions
    101 ************************************************************************************/
    102 
    103 
    104 /************************************************************************************
    105 **  Shutdown helper functions
    106 ************************************************************************************/
    107 
    108 static void bdt_shutdown(void)
    109 {
    110     bdt_log("shutdown bdroid test app\n");
    111     main_done = 1;
    112 }
    113 
    114 
    115 /*****************************************************************************
    116 ** Android's init.rc does not yet support applying linux capabilities
    117 *****************************************************************************/
    118 
    119 static void config_permissions(void)
    120 {
    121     struct __user_cap_header_struct header;
    122     struct __user_cap_data_struct cap;
    123 
    124     bdt_log("set_aid_and_cap : pid %d, uid %d gid %d", getpid(), getuid(), getgid());
    125 
    126     header.pid = 0;
    127 
    128     prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0);
    129 
    130     setuid(AID_BLUETOOTH);
    131     setgid(AID_BLUETOOTH);
    132 
    133     header.version = _LINUX_CAPABILITY_VERSION;
    134 
    135     cap.effective = cap.permitted =  cap.inheritable =
    136                     1 << CAP_NET_RAW |
    137                     1 << CAP_NET_ADMIN |
    138                     1 << CAP_NET_BIND_SERVICE |
    139                     1 << CAP_SYS_RAWIO |
    140                     1 << CAP_SYS_NICE |
    141                     1 << CAP_SETGID;
    142 
    143     capset(&header, &cap);
    144     setgroups(sizeof(groups)/sizeof(groups[0]), groups);
    145 }
    146 
    147 
    148 
    149 /*****************************************************************************
    150 **   Logger API
    151 *****************************************************************************/
    152 
    153 void bdt_log(const char *fmt_str, ...)
    154 {
    155     static char buffer[1024];
    156     va_list ap;
    157 
    158     va_start(ap, fmt_str);
    159     vsnprintf(buffer, 1024, fmt_str, ap);
    160     va_end(ap);
    161 
    162     fprintf(stdout, "%s\n", buffer);
    163 }
    164 
    165 /*******************************************************************************
    166  ** Misc helper functions
    167  *******************************************************************************/
    168 static const char* dump_bt_status(bt_status_t status)
    169 {
    170     switch(status)
    171     {
    172         CASE_RETURN_STR(BT_STATUS_SUCCESS)
    173         CASE_RETURN_STR(BT_STATUS_FAIL)
    174         CASE_RETURN_STR(BT_STATUS_NOT_READY)
    175         CASE_RETURN_STR(BT_STATUS_NOMEM)
    176         CASE_RETURN_STR(BT_STATUS_BUSY)
    177         CASE_RETURN_STR(BT_STATUS_UNSUPPORTED)
    178 
    179         default:
    180             return "unknown status code";
    181     }
    182 }
    183 
    184 static void hex_dump(char *msg, void *data, int size, int trunc)
    185 {
    186     unsigned char *p = data;
    187     unsigned char c;
    188     int n;
    189     char bytestr[4] = {0};
    190     char addrstr[10] = {0};
    191     char hexstr[ 16*3 + 5] = {0};
    192     char charstr[16*1 + 5] = {0};
    193 
    194     bdt_log("%s  \n", msg);
    195 
    196     /* truncate */
    197     if(trunc && (size>32))
    198         size = 32;
    199 
    200     for(n=1;n<=size;n++) {
    201         if (n%16 == 1) {
    202             /* store address for this line */
    203             snprintf(addrstr, sizeof(addrstr), "%.4x",
    204                (unsigned int)((uintptr_t)p-(uintptr_t)data) );
    205         }
    206 
    207         c = *p;
    208         if (isalnum(c) == 0) {
    209             c = '.';
    210         }
    211 
    212         /* store hex str (for left side) */
    213         snprintf(bytestr, sizeof(bytestr), "%02X ", *p);
    214         strncat(hexstr, bytestr, sizeof(hexstr)-strlen(hexstr)-1);
    215 
    216         /* store char str (for right side) */
    217         snprintf(bytestr, sizeof(bytestr), "%c", c);
    218         strncat(charstr, bytestr, sizeof(charstr)-strlen(charstr)-1);
    219 
    220         if(n%16 == 0) {
    221             /* line completed */
    222             bdt_log("[%4.4s]   %-50.50s  %s\n", addrstr, hexstr, charstr);
    223             hexstr[0] = 0;
    224             charstr[0] = 0;
    225         } else if(n%8 == 0) {
    226             /* half line: add whitespaces */
    227             strncat(hexstr, "  ", sizeof(hexstr)-strlen(hexstr)-1);
    228             strncat(charstr, " ", sizeof(charstr)-strlen(charstr)-1);
    229         }
    230         p++; /* next byte */
    231     }
    232 
    233     if (strlen(hexstr) > 0) {
    234         /* print rest of buffer if not empty */
    235         bdt_log("[%4.4s]   %-50.50s  %s\n", addrstr, hexstr, charstr);
    236     }
    237 }
    238 
    239 /*******************************************************************************
    240  ** Console helper functions
    241  *******************************************************************************/
    242 
    243 void skip_blanks(char **p)
    244 {
    245   while (**p == ' ')
    246     (*p)++;
    247 }
    248 
    249 uint32_t get_int(char **p, int DefaultValue)
    250 {
    251   uint32_t Value = 0;
    252   unsigned char   UseDefault;
    253 
    254   UseDefault = 1;
    255   skip_blanks(p);
    256 
    257   while ( ((**p)<= '9' && (**p)>= '0') )
    258     {
    259       Value = Value * 10 + (**p) - '0';
    260       UseDefault = 0;
    261       (*p)++;
    262     }
    263 
    264   if (UseDefault)
    265     return DefaultValue;
    266   else
    267     return Value;
    268 }
    269 
    270 int get_signed_int(char **p, int DefaultValue)
    271 {
    272   int    Value = 0;
    273   unsigned char   UseDefault;
    274   unsigned char  NegativeNum = 0;
    275 
    276   UseDefault = 1;
    277   skip_blanks(p);
    278 
    279   if ( (**p) == '-')
    280     {
    281       NegativeNum = 1;
    282       (*p)++;
    283     }
    284   while ( ((**p)<= '9' && (**p)>= '0') )
    285     {
    286       Value = Value * 10 + (**p) - '0';
    287       UseDefault = 0;
    288       (*p)++;
    289     }
    290 
    291   if (UseDefault)
    292     return DefaultValue;
    293   else
    294     return ((NegativeNum == 0)? Value : -Value);
    295 }
    296 
    297 void get_str(char **p, char *Buffer)
    298 {
    299   skip_blanks(p);
    300 
    301   while (**p != 0 && **p != ' ')
    302     {
    303       *Buffer = **p;
    304       (*p)++;
    305       Buffer++;
    306     }
    307 
    308   *Buffer = 0;
    309 }
    310 
    311 uint32_t get_hex(char **p, int DefaultValue)
    312 {
    313   uint32_t Value = 0;
    314   unsigned char   UseDefault;
    315 
    316   UseDefault = 1;
    317   skip_blanks(p);
    318 
    319   while ( ((**p)<= '9' && (**p)>= '0') ||
    320           ((**p)<= 'f' && (**p)>= 'a') ||
    321           ((**p)<= 'F' && (**p)>= 'A') )
    322     {
    323       if (**p >= 'a')
    324         Value = Value * 16 + (**p) - 'a' + 10;
    325       else if (**p >= 'A')
    326         Value = Value * 16 + (**p) - 'A' + 10;
    327       else
    328         Value = Value * 16 + (**p) - '0';
    329       UseDefault = 0;
    330       (*p)++;
    331     }
    332 
    333   if (UseDefault)
    334     return DefaultValue;
    335   else
    336     return Value;
    337 }
    338 
    339 void get_bdaddr(const char *str, bt_bdaddr_t *bd) {
    340     char *d = ((char *)bd), *endp;
    341     int i;
    342     for(i = 0; i < 6; i++) {
    343         *d++ = strtol(str, &endp, 16);
    344         if (*endp != ':' && i != 5) {
    345             memset(bd, 0, sizeof(bt_bdaddr_t));
    346             return;
    347         }
    348         str = endp + 1;
    349     }
    350 }
    351 
    352 #define is_cmd(str) ((strlen(str) == strlen(cmd)) && strncmp((const char *)&cmd, str, strlen(str)) == 0)
    353 #define if_cmd(str)  if (is_cmd(str))
    354 
    355 typedef void (t_console_cmd_handler) (char *p);
    356 
    357 typedef struct {
    358     const char *name;
    359     t_console_cmd_handler *handler;
    360     const char *help;
    361     unsigned char is_job;
    362 } t_cmd;
    363 
    364 
    365 const t_cmd console_cmd_list[];
    366 static int console_cmd_maxlen = 0;
    367 
    368 static void cmdjob_handler(void *param)
    369 {
    370     char *job_cmd = (char*)param;
    371 
    372     bdt_log("cmdjob starting (%s)", job_cmd);
    373 
    374     process_cmd(job_cmd, 1);
    375 
    376     bdt_log("cmdjob terminating");
    377 
    378     free(job_cmd);
    379 }
    380 
    381 static int create_cmdjob(char *cmd)
    382 {
    383     pthread_t thread_id;
    384     char *job_cmd;
    385 
    386     job_cmd = malloc(strlen(cmd)+1); /* freed in job handler */
    387     strcpy(job_cmd, cmd);
    388 
    389     if (pthread_create(&thread_id, NULL,
    390                        (void*)cmdjob_handler, (void*)job_cmd)!=0)
    391       perror("pthread_create");
    392 
    393     return 0;
    394 }
    395 
    396 /*******************************************************************************
    397  ** Load stack lib
    398  *******************************************************************************/
    399 
    400 int HAL_load(void)
    401 {
    402     int err = 0;
    403 
    404     hw_module_t* module;
    405     hw_device_t* device;
    406 
    407     bdt_log("Loading HAL lib + extensions");
    408 
    409     err = hw_get_module(BT_HARDWARE_MODULE_ID, (hw_module_t const**)&module);
    410     if (err == 0)
    411     {
    412         err = module->methods->open(module, BT_HARDWARE_MODULE_ID, &device);
    413         if (err == 0) {
    414             bt_device = (bluetooth_device_t *)device;
    415             sBtInterface = bt_device->get_bluetooth_interface();
    416         }
    417     }
    418 
    419     bdt_log("HAL library loaded (%s)", strerror(err));
    420 
    421     return err;
    422 }
    423 
    424 int HAL_unload(void)
    425 {
    426     int err = 0;
    427 
    428     bdt_log("Unloading HAL lib");
    429 
    430     sBtInterface = NULL;
    431 
    432     bdt_log("HAL library unloaded (%s)", strerror(err));
    433 
    434     return err;
    435 }
    436 
    437 /*******************************************************************************
    438  ** HAL test functions & callbacks
    439  *******************************************************************************/
    440 
    441 void setup_test_env(void)
    442 {
    443     int i = 0;
    444 
    445     while (console_cmd_list[i].name != NULL)
    446     {
    447         console_cmd_maxlen = MAX(console_cmd_maxlen, (int)strlen(console_cmd_list[i].name));
    448         i++;
    449     }
    450 }
    451 
    452 void check_return_status(bt_status_t status)
    453 {
    454     if (status != BT_STATUS_SUCCESS)
    455     {
    456         bdt_log("HAL REQUEST FAILED status : %d (%s)", status, dump_bt_status(status));
    457     }
    458     else
    459     {
    460         bdt_log("HAL REQUEST SUCCESS");
    461     }
    462 }
    463 
    464 static void adapter_state_changed(bt_state_t state)
    465 {
    466     bdt_log("ADAPTER STATE UPDATED : %s", (state == BT_STATE_OFF)?"OFF":"ON");
    467     if (state == BT_STATE_ON) {
    468         bt_enabled = 1;
    469     } else {
    470         bt_enabled = 0;
    471     }
    472 }
    473 
    474 static void dut_mode_recv(uint16_t UNUSED opcode, uint8_t UNUSED *buf, uint8_t UNUSED len)
    475 {
    476     bdt_log("DUT MODE RECV : NOT IMPLEMENTED");
    477 }
    478 
    479 static void le_test_mode(bt_status_t status, uint16_t packet_count)
    480 {
    481     bdt_log("LE TEST MODE END status:%s number_of_packets:%d", dump_bt_status(status), packet_count);
    482 }
    483 
    484 static bt_callbacks_t bt_callbacks = {
    485     sizeof(bt_callbacks_t),
    486     adapter_state_changed,
    487     NULL, /* adapter_properties_cb */
    488     NULL, /* remote_device_properties_cb */
    489     NULL, /* device_found_cb */
    490     NULL, /* discovery_state_changed_cb */
    491     NULL, /* pin_request_cb  */
    492     NULL, /* ssp_request_cb  */
    493     NULL, /* bond_state_changed_cb */
    494     NULL, /* acl_state_changed_cb */
    495     NULL, /* thread_evt_cb */
    496     dut_mode_recv, /* dut_mode_recv_cb */
    497 #if BLE_INCLUDED == TRUE
    498     le_test_mode, /* le_test_mode_cb */
    499 #else
    500     NULL, /* le_test_mode_cb */
    501 #endif
    502     NULL /* energy_info_cb */
    503 };
    504 
    505 static bool set_wake_alarm(uint64_t delay_millis, bool should_wake, alarm_cb cb, void *data) {
    506   static timer_t timer;
    507   static bool timer_created;
    508 
    509   if (!timer_created) {
    510     struct sigevent sigevent;
    511     memset(&sigevent, 0, sizeof(sigevent));
    512     sigevent.sigev_notify = SIGEV_THREAD;
    513     sigevent.sigev_notify_function = (void (*)(union sigval))cb;
    514     sigevent.sigev_value.sival_ptr = data;
    515     timer_create(CLOCK_MONOTONIC, &sigevent, &timer);
    516     timer_created = true;
    517   }
    518 
    519   struct itimerspec new_value;
    520   new_value.it_value.tv_sec = delay_millis / 1000;
    521   new_value.it_value.tv_nsec = (delay_millis % 1000) * 1000 * 1000;
    522   new_value.it_interval.tv_sec = 0;
    523   new_value.it_interval.tv_nsec = 0;
    524   timer_settime(timer, 0, &new_value, NULL);
    525 
    526   return true;
    527 }
    528 
    529 static int acquire_wake_lock(const char *lock_name) {
    530   return BT_STATUS_SUCCESS;
    531 }
    532 
    533 static int release_wake_lock(const char *lock_name) {
    534   return BT_STATUS_SUCCESS;
    535 }
    536 
    537 static bt_os_callouts_t callouts = {
    538     sizeof(bt_os_callouts_t),
    539     set_wake_alarm,
    540     acquire_wake_lock,
    541     release_wake_lock,
    542 };
    543 
    544 void bdt_init(void)
    545 {
    546     bdt_log("INIT BT ");
    547     status = sBtInterface->init(&bt_callbacks);
    548 
    549     if (status == BT_STATUS_SUCCESS) {
    550         status = sBtInterface->set_os_callouts(&callouts);
    551     }
    552 
    553     check_return_status(status);
    554 }
    555 
    556 void bdt_enable(void)
    557 {
    558     bdt_log("ENABLE BT");
    559     if (bt_enabled) {
    560         bdt_log("Bluetooth is already enabled");
    561         return;
    562     }
    563     status = sBtInterface->enable();
    564 
    565     check_return_status(status);
    566 }
    567 
    568 void bdt_disable(void)
    569 {
    570     bdt_log("DISABLE BT");
    571     if (!bt_enabled) {
    572         bdt_log("Bluetooth is already disabled");
    573         return;
    574     }
    575     status = sBtInterface->disable();
    576 
    577     check_return_status(status);
    578 }
    579 void bdt_dut_mode_configure(char *p)
    580 {
    581     int32_t mode = -1;
    582 
    583     bdt_log("BT DUT MODE CONFIGURE");
    584     if (!bt_enabled) {
    585         bdt_log("Bluetooth must be enabled for test_mode to work.");
    586         return;
    587     }
    588     mode = get_signed_int(&p, mode);
    589     if ((mode != 0) && (mode != 1)) {
    590         bdt_log("Please specify mode: 1 to enter, 0 to exit");
    591         return;
    592     }
    593     status = sBtInterface->dut_mode_configure(mode);
    594 
    595     check_return_status(status);
    596 }
    597 
    598 #define HCI_LE_RECEIVER_TEST_OPCODE 0x201D
    599 #define HCI_LE_TRANSMITTER_TEST_OPCODE 0x201E
    600 #define HCI_LE_END_TEST_OPCODE 0x201F
    601 
    602 void bdt_le_test_mode(char *p)
    603 {
    604     int cmd;
    605     unsigned char buf[3];
    606     int arg1, arg2, arg3;
    607 
    608     bdt_log("BT LE TEST MODE");
    609     if (!bt_enabled) {
    610         bdt_log("Bluetooth must be enabled for le_test to work.");
    611         return;
    612     }
    613 
    614     memset(buf, 0, sizeof(buf));
    615     cmd = get_int(&p, 0);
    616     switch (cmd)
    617     {
    618         case 0x1: /* RX TEST */
    619            arg1 = get_int(&p, -1);
    620            if (arg1 < 0) bdt_log("%s Invalid arguments", __FUNCTION__);
    621            buf[0] = arg1;
    622            status = sBtInterface->le_test_mode(HCI_LE_RECEIVER_TEST_OPCODE, buf, 1);
    623            break;
    624         case 0x2: /* TX TEST */
    625             arg1 = get_int(&p, -1);
    626             arg2 = get_int(&p, -1);
    627             arg3 = get_int(&p, -1);
    628             if ((arg1 < 0) || (arg2 < 0) || (arg3 < 0))
    629                 bdt_log("%s Invalid arguments", __FUNCTION__);
    630             buf[0] = arg1;
    631             buf[1] = arg2;
    632             buf[2] = arg3;
    633             status = sBtInterface->le_test_mode(HCI_LE_TRANSMITTER_TEST_OPCODE, buf, 3);
    634            break;
    635         case 0x3: /* END TEST */
    636             status = sBtInterface->le_test_mode(HCI_LE_END_TEST_OPCODE, buf, 0);
    637            break;
    638         default:
    639             bdt_log("Unsupported command");
    640             return;
    641             break;
    642     }
    643     if (status != BT_STATUS_SUCCESS)
    644     {
    645         bdt_log("%s Test 0x%x Failed with status:0x%x", __FUNCTION__, cmd, status);
    646     }
    647     return;
    648 }
    649 
    650 void bdt_cleanup(void)
    651 {
    652     bdt_log("CLEANUP");
    653     sBtInterface->cleanup();
    654 }
    655 
    656 /*******************************************************************************
    657  ** Console commands
    658  *******************************************************************************/
    659 
    660 void do_help(char UNUSED *p)
    661 {
    662     int i = 0;
    663     int max = 0;
    664     char line[128];
    665     int pos = 0;
    666 
    667     while (console_cmd_list[i].name != NULL)
    668     {
    669         pos = sprintf(line, "%s", (char*)console_cmd_list[i].name);
    670         bdt_log("%s %s\n", (char*)line, (char*)console_cmd_list[i].help);
    671         i++;
    672     }
    673 }
    674 
    675 void do_quit(char UNUSED *p)
    676 {
    677     bdt_shutdown();
    678 }
    679 
    680 /*******************************************************************
    681  *
    682  *  BT TEST  CONSOLE COMMANDS
    683  *
    684  *  Parses argument lists and passes to API test function
    685  *
    686 */
    687 
    688 void do_init(char UNUSED *p)
    689 {
    690     bdt_init();
    691 }
    692 
    693 void do_enable(char UNUSED *p)
    694 {
    695     bdt_enable();
    696 }
    697 
    698 void do_disable(char UNUSED *p)
    699 {
    700     bdt_disable();
    701 }
    702 void do_dut_mode_configure(char *p)
    703 {
    704     bdt_dut_mode_configure(p);
    705 }
    706 
    707 void do_le_test_mode(char *p)
    708 {
    709     bdt_le_test_mode(p);
    710 }
    711 
    712 void do_cleanup(char UNUSED *p)
    713 {
    714     bdt_cleanup();
    715 }
    716 
    717 /*******************************************************************
    718  *
    719  *  CONSOLE COMMAND TABLE
    720  *
    721 */
    722 
    723 const t_cmd console_cmd_list[] =
    724 {
    725     /*
    726      * INTERNAL
    727      */
    728 
    729     { "help", do_help, "lists all available console commands", 0 },
    730     { "quit", do_quit, "", 0},
    731 
    732     /*
    733      * API CONSOLE COMMANDS
    734      */
    735 
    736      /* Init and Cleanup shall be called automatically */
    737     { "enable", do_enable, ":: enables bluetooth", 0 },
    738     { "disable", do_disable, ":: disables bluetooth", 0 },
    739     { "dut_mode_configure", do_dut_mode_configure, ":: DUT mode - 1 to enter,0 to exit", 0 },
    740     { "le_test_mode", do_le_test_mode, ":: LE Test Mode - RxTest - 1 <rx_freq>, \n\t \
    741                       TxTest - 2 <tx_freq> <test_data_len> <payload_pattern>, \n\t \
    742                       End Test - 3 <no_args>", 0 },
    743     /* add here */
    744 
    745     /* last entry */
    746     {NULL, NULL, "", 0},
    747 };
    748 
    749 /*
    750  * Main console command handler
    751 */
    752 
    753 static void process_cmd(char *p, unsigned char is_job)
    754 {
    755     char cmd[64];
    756     int i = 0;
    757     char *p_saved = p;
    758 
    759     get_str(&p, cmd);
    760 
    761     /* table commands */
    762     while (console_cmd_list[i].name != NULL)
    763     {
    764         if (is_cmd(console_cmd_list[i].name))
    765         {
    766             if (!is_job && console_cmd_list[i].is_job)
    767                 create_cmdjob(p_saved);
    768             else
    769             {
    770                 console_cmd_list[i].handler(p);
    771             }
    772             return;
    773         }
    774         i++;
    775     }
    776     bdt_log("%s : unknown command\n", p_saved);
    777     do_help(NULL);
    778 }
    779 
    780 int main (int UNUSED argc, char UNUSED *argv[])
    781 {
    782     int opt;
    783     char cmd[128];
    784     int args_processed = 0;
    785     int pid = -1;
    786 
    787     config_permissions();
    788     bdt_log("\n:::::::::::::::::::::::::::::::::::::::::::::::::::");
    789     bdt_log(":: Bluedroid test app starting");
    790 
    791     if ( HAL_load() < 0 ) {
    792         perror("HAL failed to initialize, exit\n");
    793         unlink(PID_FILE);
    794         exit(0);
    795     }
    796 
    797     setup_test_env();
    798 
    799     /* Automatically perform the init */
    800     bdt_init();
    801 
    802     while(!main_done)
    803     {
    804         char line[128];
    805 
    806         /* command prompt */
    807         printf( ">" );
    808         fflush(stdout);
    809 
    810         fgets (line, 128, stdin);
    811 
    812         if (line[0]!= '\0')
    813         {
    814             /* remove linefeed */
    815             line[strlen(line)-1] = 0;
    816 
    817             process_cmd(line, 0);
    818             memset(line, '\0', 128);
    819         }
    820     }
    821 
    822     /* FIXME: Commenting this out as for some reason, the application does not exit otherwise*/
    823     //bdt_cleanup();
    824 
    825     HAL_unload();
    826 
    827     bdt_log(":: Bluedroid test app terminating");
    828 
    829     return 0;
    830 }
    831