• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
bdt_shutdown(void)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 
config_permissions(void)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 
bdt_log(const char * fmt_str,...)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  *******************************************************************************/
dump_bt_status(bt_status_t status)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 
hex_dump(char * msg,void * data,int size,int trunc)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 
skip_blanks(char ** p)243 void skip_blanks(char **p)
244 {
245   while (**p == ' ')
246     (*p)++;
247 }
248 
get_int(char ** p,int DefaultValue)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 
get_signed_int(char ** p,int DefaultValue)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 
get_str(char ** p,char * Buffer)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 
get_hex(char ** p,int DefaultValue)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 
get_bdaddr(const char * str,bt_bdaddr_t * bd)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 
cmdjob_handler(void * param)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 
create_cmdjob(char * cmd)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 
HAL_load(void)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 
HAL_unload(void)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 
setup_test_env(void)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 
check_return_status(bt_status_t status)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 
adapter_state_changed(bt_state_t state)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 
dut_mode_recv(uint16_t UNUSED opcode,uint8_t UNUSED * buf,uint8_t UNUSED len)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 
le_test_mode(bt_status_t status,uint16_t packet_count)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 
set_wake_alarm(uint64_t delay_millis,bool should_wake,alarm_cb cb,void * data)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 
acquire_wake_lock(const char * lock_name)529 static int acquire_wake_lock(const char *lock_name) {
530   return BT_STATUS_SUCCESS;
531 }
532 
release_wake_lock(const char * lock_name)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 
bdt_init(void)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 
bdt_enable(void)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(false);
564 
565     check_return_status(status);
566 }
567 
bdt_disable(void)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 }
bdt_dut_mode_configure(char * p)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 
bdt_le_test_mode(char * p)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 
bdt_cleanup(void)650 void bdt_cleanup(void)
651 {
652     bdt_log("CLEANUP");
653     sBtInterface->cleanup();
654 }
655 
656 /*******************************************************************************
657  ** Console commands
658  *******************************************************************************/
659 
do_help(char UNUSED * p)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 
do_quit(char UNUSED * p)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 
do_init(char UNUSED * p)688 void do_init(char UNUSED *p)
689 {
690     bdt_init();
691 }
692 
do_enable(char UNUSED * p)693 void do_enable(char UNUSED *p)
694 {
695     bdt_enable();
696 }
697 
do_disable(char UNUSED * p)698 void do_disable(char UNUSED *p)
699 {
700     bdt_disable();
701 }
do_dut_mode_configure(char * p)702 void do_dut_mode_configure(char *p)
703 {
704     bdt_dut_mode_configure(p);
705 }
706 
do_le_test_mode(char * p)707 void do_le_test_mode(char *p)
708 {
709     bdt_le_test_mode(p);
710 }
711 
do_cleanup(char UNUSED * p)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 
process_cmd(char * p,unsigned char is_job)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 
main(int UNUSED argc,char UNUSED * argv[])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