1 /* 2 * Copyright 2008 Oliver Ruiz Dorantes, oliver.ruiz.dorantes_at_gmail.com 3 * Copyright 2008 Mika Lindqvist 4 * All rights reserved. Distributed under the terms of the MIT License. 5 */ 6 7 #include "CommandManager.h" 8 9 10 #include <bluetooth/bluetooth_error.h> 11 #include <bluetooth/debug.h> 12 13 inline void* buildCommand(uint8 ogf, uint8 ocf, void** param, size_t psize, 14 size_t* outsize) 15 { 16 CALLED(); 17 struct hci_command_header* header; 18 19 header = (struct hci_command_header*) malloc(psize 20 + sizeof(struct hci_command_header)); 21 *outsize = psize + sizeof(struct hci_command_header); 22 23 if (header != NULL) { 24 header->opcode = B_HOST_TO_LENDIAN_INT16(PACK_OPCODE(ogf, ocf)); 25 header->clen = psize; 26 27 if (param != NULL && psize != 0) { 28 *param = ((uint8*)header) + sizeof(struct hci_command_header); 29 } 30 } 31 return header; 32 } 33 34 35 // This is for request that only require a Command complete in reply. 36 37 // Propagate to ReadBufferSize => reply stored in server side 38 // ReadLocalVersion => reply stored in server side 39 // Reset => no reply 40 41 // Request that do not need any input parameter 42 // Output reply can be fit in 32 bits field without talking status into account 43 status_t 44 NonParameterCommandRequest(uint8 ofg, uint8 ocf, int32* result, hci_id hId, 45 BMessenger* messenger) 46 { 47 CALLED(); 48 int8 bt_status = BT_ERROR; 49 50 BluetoothCommand<> simpleCommand(ofg, ocf); 51 52 BMessage request(BT_MSG_HANDLE_SIMPLE_REQUEST); 53 BMessage reply; 54 55 request.AddInt32("hci_id", hId); 56 request.AddData("raw command", B_ANY_TYPE, 57 simpleCommand.Data(), simpleCommand.Size()); 58 request.AddInt16("eventExpected", HCI_EVENT_CMD_COMPLETE); 59 request.AddInt16("opcodeExpected", PACK_OPCODE(ofg, ocf)); 60 61 if (messenger->SendMessage(&request, &reply) == B_OK) { 62 reply.FindInt8("status", &bt_status); 63 if (result != NULL) 64 reply.FindInt32("result", result); 65 } 66 67 return bt_status; 68 } 69 70 71 #if 0 72 #pragma mark - CONTROL BASEBAND - 73 #endif 74 75 76 void* buildReset(size_t* outsize) 77 { 78 CALLED(); 79 return buildCommand(OGF_CONTROL_BASEBAND, OCF_RESET, 80 NULL, 0, outsize); 81 } 82 83 84 void* buildReadLocalName(size_t* outsize) 85 { 86 CALLED(); 87 return buildCommand(OGF_CONTROL_BASEBAND, OCF_READ_LOCAL_NAME, 88 NULL, 0, outsize); 89 } 90 91 92 void* buildReadClassOfDevice(size_t* outsize) 93 { 94 CALLED(); 95 return buildCommand(OGF_CONTROL_BASEBAND, OCF_READ_CLASS_OF_DEV, 96 NULL, 0, outsize); 97 } 98 99 100 void* buildReadScan(size_t* outsize) 101 { 102 CALLED(); 103 return buildCommand(OGF_CONTROL_BASEBAND, OCF_READ_SCAN_ENABLE, 104 NULL, 0, outsize); 105 } 106 107 108 void* buildWriteScan(uint8 scanmode, size_t* outsize) 109 { 110 CALLED(); 111 struct hci_write_scan_enable* param; 112 void* command = buildCommand(OGF_CONTROL_BASEBAND, OCF_WRITE_SCAN_ENABLE, 113 (void**) ¶m, sizeof(struct hci_write_scan_enable), outsize); 114 115 116 if (command != NULL) { 117 param->scan = scanmode; 118 } 119 120 return command; 121 } 122 123 124 #if 0 125 #pragma mark - LINK CONTROL - 126 #endif 127 128 129 void* buildRemoteNameRequest(bdaddr_t bdaddr, uint8 pscan_rep_mode, 130 uint16 clock_offset, size_t* outsize) 131 { 132 CALLED(); 133 struct hci_remote_name_request* param; 134 void* command = buildCommand(OGF_LINK_CONTROL, OCF_REMOTE_NAME_REQUEST, 135 (void**)¶m, sizeof(struct hci_remote_name_request), outsize); 136 137 if (command != NULL) { 138 param->bdaddr = bdaddr; 139 param->pscan_rep_mode = pscan_rep_mode; 140 param->clock_offset = clock_offset; 141 } 142 143 return command; 144 } 145 146 147 void* buildInquiry(uint32 lap, uint8 length, uint8 num_rsp, size_t* outsize) 148 { 149 CALLED(); 150 struct hci_cp_inquiry* param; 151 void* command = buildCommand(OGF_LINK_CONTROL, OCF_INQUIRY, 152 (void**) ¶m, sizeof(struct hci_cp_inquiry), outsize); 153 154 if (command != NULL) { 155 156 param->lap[2] = (lap >> 16) & 0xFF; 157 param->lap[1] = (lap >> 8) & 0xFF; 158 param->lap[0] = (lap >> 0) & 0xFF; 159 param->length = length; 160 param->num_rsp = num_rsp; 161 } 162 163 return command; 164 } 165 166 167 void* buildInquiryCancel(size_t* outsize) 168 { 169 CALLED(); 170 return buildCommand(OGF_LINK_CONTROL, OCF_INQUIRY_CANCEL, NULL, 0, outsize); 171 } 172 173 174 void* buildPinCodeRequestReply(bdaddr_t bdaddr, uint8 length, char pincode[16], 175 size_t* outsize) 176 { 177 CALLED(); 178 struct hci_cp_pin_code_reply* param; 179 180 if (length > HCI_PIN_SIZE) // PinCode cannot be longer than 16 181 return NULL; 182 183 void* command = buildCommand(OGF_LINK_CONTROL, OCF_PIN_CODE_REPLY, 184 (void**)¶m, sizeof(struct hci_cp_pin_code_reply), outsize); 185 186 if (command != NULL) { 187 param->bdaddr = bdaddr; 188 param->pin_len = length; 189 memcpy(¶m->pin_code, pincode, length); 190 } 191 192 return command; 193 } 194 195 196 void* buildPinCodeRequestNegativeReply(bdaddr_t bdaddr, size_t* outsize) 197 { 198 CALLED(); 199 struct hci_cp_pin_code_neg_reply* param; 200 201 void* command = buildCommand(OGF_LINK_CONTROL, OCF_PIN_CODE_NEG_REPLY, 202 (void**) ¶m, sizeof(struct hci_cp_pin_code_neg_reply), outsize); 203 204 if (command != NULL) { 205 206 param->bdaddr = bdaddr; 207 208 } 209 210 return command; 211 } 212 213 214 void* buildAcceptConnectionRequest(bdaddr_t bdaddr, uint8 role, size_t* outsize) 215 { 216 CALLED(); 217 struct hci_cp_accept_conn_req* param; 218 219 void* command = buildCommand(OGF_LINK_CONTROL, OCF_ACCEPT_CONN_REQ, 220 (void**) ¶m, sizeof(struct hci_cp_accept_conn_req), outsize); 221 222 if (command != NULL) { 223 param->bdaddr = bdaddr; 224 param->role = role; 225 } 226 227 return command; 228 } 229 230 231 void* buildRejectConnectionRequest(bdaddr_t bdaddr, size_t* outsize) 232 { 233 CALLED(); 234 struct hci_cp_reject_conn_req* param; 235 236 void* command = buildCommand(OGF_LINK_CONTROL, OCF_REJECT_CONN_REQ, 237 (void**)¶m, sizeof(struct hci_cp_reject_conn_req), 238 outsize); 239 240 if (command != NULL) { 241 param->bdaddr = bdaddr; 242 } 243 244 return command; 245 } 246 247 248 #if 0 249 #pragma mark - INFORMATIONAL_PARAM - 250 #endif 251 252 void* buildReadLocalVersionInformation(size_t* outsize) 253 { 254 CALLED(); 255 return buildCommand(OGF_INFORMATIONAL_PARAM, OCF_READ_LOCAL_VERSION, 256 NULL, 0, outsize); 257 } 258 259 260 void* buildReadBufferSize(size_t* outsize) 261 { 262 CALLED(); 263 return buildCommand(OGF_INFORMATIONAL_PARAM, OCF_READ_BUFFER_SIZE, 264 NULL, 0, outsize); 265 } 266 267 268 void* buildReadBdAddr(size_t* outsize) 269 { 270 CALLED(); 271 return buildCommand(OGF_INFORMATIONAL_PARAM, OCF_READ_BD_ADDR, 272 NULL, 0, outsize); 273 } 274 275 276 const char* bluetoothManufacturers[] = { 277 "Ericsson Technology Licensing", 278 "Nokia Mobile Phones", 279 "Intel Corp.", 280 "IBM Corp.", 281 "Toshiba Corp.", 282 "3Com", 283 "Microsoft", 284 "Lucent", 285 "Motorola", 286 "Infineon Technologies AG", 287 "Cambridge Silicon Radio", 288 "Silicon Wave", 289 "Digianswer A/S", 290 "Texas Instruments Inc.", 291 "Parthus Technologies Inc.", 292 "Broadcom Corporation", 293 "Mitel Semiconductor", 294 "Widcomm, Inc.", 295 "Zeevo, Inc.", 296 "Atmel Corporation", 297 "Mitsubishi Electric Corporation", 298 "RTX Telecom A/S", 299 "KC Technology Inc.", 300 "Newlogic", 301 "Transilica, Inc.", 302 "Rohde & Schwartz GmbH & Co. KG", 303 "TTPCom Limited", 304 "Signia Technologies, Inc.", 305 "Conexant Systems Inc.", 306 "Qualcomm", 307 "Inventel", 308 "AVM Berlin", 309 "BandSpeed, Inc.", 310 "Mansella Ltd", 311 "NEC Corporation", 312 "WavePlus Technology Co., Ltd.", 313 "Alcatel", 314 "Philips Semiconductors", 315 "C Technologies", 316 "Open Interface", 317 "R F Micro Devices", 318 "Hitachi Ltd", 319 "Symbol Technologies, Inc.", 320 "Tenovis", 321 "Macronix International Co. Ltd.", 322 "GCT Semiconductor", 323 "Norwood Systems", 324 "MewTel Technology Inc.", 325 "ST Microelectronics", 326 "Synopsys", 327 "Red-M (Communications) Ltd", 328 "Commil Ltd", 329 "Computer Access Technology Corporation (CATC)", 330 "Eclipse (HQ España) S.L.", 331 "Renesas Technology Corp.", 332 "Mobilian Corporation", 333 "Terax", 334 "Integrated System Solution Corp.", 335 "Matsushita Electric Industrial Co., Ltd.", 336 "Gennum Corporation", 337 "Research In Motion", 338 "IPextreme, Inc.", 339 "Systems and Chips, Inc", 340 "Bluetooth SIG, Inc", 341 "Seiko Epson Corporation", 342 "Integrated Silicon Solution Taiwain, Inc.", 343 "CONWISE Technology Corporation Ltd", 344 "PARROT SA", 345 "Socket Communications", 346 "Atheros Communications, Inc.", 347 "MediaTek, Inc.", 348 "Bluegiga", /* (tentative) */ 349 "Marvell Technology Group Ltd.", 350 "3DSP Corporation", 351 "Accel Semiconductor Ltd.", 352 "Continental Automotive Systems", 353 "Apple, Inc.", 354 "Staccato Communications, Inc." 355 }; 356 357 358 const char* linkControlCommands[] = { 359 "Inquiry", 360 "Inquiry Cancel", 361 "Periodic Inquiry Mode", 362 "Exit Periodic Inquiry Mode", 363 "Create Connection", 364 "Disconnect", 365 "Add SCO Connection", // not on 2.1 366 "Cancel Create Connection", 367 "Accept Connection Request", 368 "Reject Connection Request", 369 "Link Key Request Reply", 370 "Link Key Request Negative Reply", 371 "PIN Code Request Reply", 372 "PIN Code Request Negative Reply", 373 "Change Connection Packet Type", 374 "Reserved", // not on 2.1", 375 "Authentication Requested", 376 "Reserved", // not on 2.1", 377 "Set Connection Encryption", 378 "Reserved", // not on 2.1", 379 "Change Connection Link Key", 380 "Reserved", // not on 2.1", 381 "Master Link Key", 382 "Reserved", // not on 2.1", 383 "Remote Name Request", 384 "Cancel Remote Name Request", 385 "Read Remote Supported Features", 386 "Read Remote Extended Features", 387 "Read Remote Version Information", 388 "Reserved", // not on 2.1", 389 "Read Clock Offset", 390 "Read LMP Handle", 391 "Reserved", 392 "Reserved", 393 "Reserved", 394 "Reserved", 395 "Reserved", 396 "Reserved", 397 "Reserved", 398 "Setup Synchronous Connection", 399 "Accept Synchronous Connection", 400 "Reject Synchronous Connection", 401 "IO Capability Request Reply", 402 "User Confirmation Request Reply", 403 "User Confirmation Request Negative Reply", 404 "User Passkey Request Reply", 405 "User Passkey Request Negative Reply", 406 "Remote OOB Data Request Reply", 407 "Reserved", 408 "Reserved", 409 "Remote OOB Data Request Negative Reply", 410 "IO Capabilities Response Negative Reply" 411 }; 412 413 414 const char* linkPolicyCommands[] = { 415 "Hold Mode", 416 "Reserved", 417 "Sniff Mode", 418 "Exit Sniff Mode", 419 "Park State", 420 "Exit Park State", 421 "QoS Setup", 422 "Reserved", 423 "Role Discovery", 424 "Reserved", 425 "Switch Role", 426 "Read Link Policy Settings", 427 "Write Link Policy Settings", 428 "Read Default Link Policy Settings", 429 "Write Default Link Policy Settings", 430 "Flow Specification", 431 "Sniff Subrating" 432 }; 433 434 435 const char* controllerBasebandCommands[] = { 436 "Set Event Mask", 437 "Reserved", 438 "Reset", 439 "Reserved", 440 "Set Event Filter", 441 "Reserved", 442 "Reserved", 443 "Flush", 444 "Read PIN Type", 445 "Write PIN Type", 446 "Create New Unit Key", 447 "Reserved", 448 "Read Stored Link Key", 449 "Reserved", 450 "Reserved", 451 "Reserved", 452 "Write Stored Link Key", 453 "Delete Stored Link Key", 454 "Write Local Name", 455 "Read Local Name", 456 "Read Connection Accept Timeout", 457 "Write Connection Accept Timeout", 458 "Read Page Timeout", 459 "Write Page Timeout", 460 "Read Scan Enable", 461 "Write Scan Enable", 462 "Read Page Scan Activity", 463 "Write Page Scan Activity", 464 "Read Inquiry Scan Activity", 465 "Write Inquiry Scan Activity", 466 "Read Authentication Enable", 467 "Write Authentication Enable", 468 "Read Encryption Mode", // not 2.1 469 "Write Encryption Mode",// not 2.1 470 "Read Class Of Device", 471 "Write Class Of Device", 472 "Read Voice Setting", 473 "Write Voice Setting", 474 "Read Automatic Flush Timeout", 475 "Write Automatic Flush Timeout", 476 "Read Num Broadcast Retransmissions", 477 "Write Num Broadcast Retransmissions", 478 "Read Hold Mode Activity", 479 "Write Hold Mode Activity", 480 "Read Transmit Power Level", 481 "Read Synchronous Flow Control Enable", 482 "Write Synchronous Flow Control Enable", 483 "Reserved", 484 "Set Host Controller To Host Flow Control", 485 "Reserved", 486 "Host Buffer Size", 487 "Reserved", 488 "Host Number Of Completed Packets", 489 "Read Link Supervision Timeout", 490 "Write Link Supervision Timeout", 491 "Read Number of Supported IAC", 492 "Read Current IAC LAP", 493 "Write Current IAC LAP", 494 "Read Page Scan Period Mode", // not 2.1 495 "Write Page Scan Period Mode", // not 2.1 496 "Read Page Scan Mode", // not 2.1 497 "Write Page Scan Mode", // not 2.1 498 "Set AFH Channel Classification", 499 "Reserved", 500 "Reserved", 501 "Read Inquiry Scan Type", 502 "Write Inquiry Scan Type", 503 "Read Inquiry Mode", 504 "Write Inquiry Mode", 505 "Read Page Scan Type", 506 "Write Page Scan Type", 507 "Read AFH Channel Assessment Mode", 508 "Write AFH Channel Assessment Mode", 509 "Reserved", 510 "Reserved", 511 "Reserved", 512 "Reserved", 513 "Reserved", 514 "Reserved", 515 "Reserved", 516 "Read Extended Inquiry Response", 517 "Write Extended Inquiry Response", 518 "Refresh Encryption Key", 519 "Reserved", 520 "Read Simple Pairing Mode", 521 "Write Simple Pairing Mode", 522 "Read Local OOB Data", 523 "Read Inquiry Transmit Power Level", 524 "Write Inquiry Transmit Power Level", 525 "Read Default Erroneous Data Reporting", 526 "Write Default Erroneous Data Reporting", 527 "Reserved", 528 "Reserved", 529 "Reserved", 530 "Enhanced Flush", 531 "Send Keypress Notification" 532 }; 533 534 535 const char* informationalParametersCommands[] = { 536 "Read Local Version Information", 537 "Read Local Supported Commands", 538 "Read Local Supported Features", 539 "Read Local Extended Features", 540 "Read Buffer Size", 541 "Reserved", 542 "Read Country Code", // not 2.1 543 "Reserved", 544 "Read BD ADDR" 545 }; 546 547 548 const char* statusParametersCommands[] = { 549 "Read Failed Contact Counter", 550 "Reset Failed Contact Counter", 551 "Read Link Quality", 552 "Reserved", 553 "Read RSSI", 554 "Read AFH Channel Map", 555 "Read Clock", 556 }; 557 558 559 const char* testingCommands[] = { 560 "Read Loopback Mode", 561 "Write Loopback Mode", 562 "Enable Device Under Test Mode", 563 "Write Simple Pairing Debug Mode", 564 }; 565 566 567 const char* bluetoothEvents[] = { 568 "Inquiry Complete", 569 "Inquiry Result", 570 "Conn Complete", 571 "Conn Request", 572 "Disconnection Complete", 573 "Auth Complete", 574 "Remote Name Request Complete", 575 "Encrypt Change", 576 "Change Conn Link Key Complete", 577 "Master Link Key Compl", 578 "Rmt Features", 579 "Rmt Version", 580 "Qos Setup Complete", 581 "Command Complete", 582 "Command Status", 583 "Hardware Error", 584 "Flush Occur", 585 "Role Change", 586 "Num Comp Pkts", 587 "Mode Change", 588 "Return Link Keys", 589 "Pin Code Req", 590 "Link Key Req", 591 "Link Key Notify", 592 "Loopback Command", 593 "Data Buffer Overflow", 594 "Max Slot Change", 595 "Read Clock Offset Compl", 596 "Con Pkt Type Changed", 597 "Qos Violation", 598 "Reserved", 599 "Page Scan Rep Mode Change", 600 "Flow Specification", 601 "Inquiry Result With Rssi", 602 "Remote Extended Features", 603 "Reserved", 604 "Reserved", 605 "Reserved", 606 "Reserved", 607 "Reserved", 608 "Reserved", 609 "Reserved", 610 "Reserved", 611 "Synchronous Connection Completed", 612 "Synchronous Connection Changed", 613 "Reserved", 614 "Extended Inquiry Result", 615 "Encryption Key Refresh Complete", 616 "Io Capability Request", 617 "Io Capability Response", 618 "User Confirmation Request", 619 "User Passkey Request", 620 "Oob Data Request", 621 "Simple Pairing Complete", 622 "Reserved", 623 "Link Supervision Timeout Changed", 624 "Enhanced Flush Complete", 625 "Reserved", 626 "Reserved", 627 "Keypress Notification", 628 "Remote Host Supported Features Notification" 629 }; 630 631 632 const char* bluetoothErrors[] = { 633 "No Error", 634 "Unknown Command", 635 "No Connection", 636 "Hardware Failure", 637 "Page Timeout", 638 "Authentication Failure", 639 "Pin Or Key Missing", 640 "Memory Full", 641 "Connection Timeout", 642 "Max Number Of Connections", 643 "Max Number Of Sco Connections", 644 "Acl Connection Exists", 645 "Command Disallowed", 646 "Rejected Limited Resources", 647 "Rejected Security", 648 "Rejected Personal", 649 "Host Timeout", 650 "Unsupported Feature", 651 "Invalid Parameters", 652 "Remote User Ended Connection", 653 "Remote Low Resources", 654 "Remote Power Off", 655 "Connection Terminated", 656 "Repeated Attempts", 657 "Pairing Not Allowed", 658 "Unknown Lmp Pdu", 659 "Unsupported Remote Feature", 660 "Sco Offset Rejected", 661 "Sco Interval Rejected", 662 "Air Mode Rejected", 663 "Invalid Lmp Parameters", 664 "Unspecified Error", 665 "Unsupported Lmp Parameter Value", 666 "Role Change Not Allowed", 667 "Lmp Response Timeout", 668 "Lmp Error Transaction Collision", 669 "Lmp Pdu Not Allowed", 670 "Encryption Mode Not Accepted", 671 "Unit Link Key Used", 672 "Qos Not Supported", 673 "Instant Passed", 674 "Pairing With Unit Key Not Supported", 675 "Different Transaction Collision", 676 "Qos Unacceptable Parameter", 677 "Qos Rejected", 678 "Classification Not Supported", 679 "Insufficient Security", 680 "Parameter Out Of Range", 681 "Reserved", 682 "Role Switch Pending", 683 "Reserved", 684 "Slot Violation", 685 "Role Switch Failed", 686 "Extended Inquiry Response Too Large", 687 "Simple Pairing Not Supported By Host", 688 "Host Busy Pairing" 689 }; 690 691 692 const char* hciVersion[] = { "1.0B" , "1.1 " , "1.2 " , "2.0 " , "2.1 "}; 693 const char* lmpVersion[] = { "1.0 " , "1.1 " , "1.2 " , "2.0 " , "2.1 "}; 694 695 696 #if 0 697 #pragma mark - 698 #endif 699 700 701 const char* 702 BluetoothHciVersion(uint16 ver) 703 { 704 CALLED(); 705 return hciVersion[ver]; 706 } 707 708 709 const char* 710 BluetoothLmpVersion(uint16 ver) 711 { 712 CALLED(); 713 return lmpVersion[ver]; 714 } 715 716 717 const char* 718 BluetoothCommandOpcode(uint16 opcode) 719 { 720 CALLED(); 721 // NOTE: BT implementations beyond 2.1 722 // could specify new commands with OCF numbers 723 // beyond the boundaries of the arrays and crash. 724 // But only our stack could issue them so its under 725 // our control. 726 switch (GET_OPCODE_OGF(opcode)) { 727 case OGF_LINK_CONTROL: 728 return linkControlCommands[GET_OPCODE_OCF(opcode) - 1]; 729 break; 730 731 case OGF_LINK_POLICY: 732 return linkPolicyCommands[GET_OPCODE_OCF(opcode) - 1]; 733 break; 734 735 case OGF_CONTROL_BASEBAND: 736 return controllerBasebandCommands[GET_OPCODE_OCF(opcode) - 1]; 737 break; 738 739 case OGF_INFORMATIONAL_PARAM: 740 return informationalParametersCommands[GET_OPCODE_OCF(opcode) - 1]; 741 break; 742 743 case OGF_STATUS_PARAM: 744 return statusParametersCommands[GET_OPCODE_OCF(opcode) - 1]; 745 break; 746 747 case OGF_TESTING_CMD: 748 return testingCommands[GET_OPCODE_OCF(opcode) - 1]; 749 break; 750 case OGF_VENDOR_CMD: 751 return "Vendor specific command"; 752 break; 753 default: 754 return "Unknown command"; 755 break; 756 } 757 758 } 759 760 761 const char* 762 BluetoothEvent(uint8 event) 763 { 764 CALLED(); 765 if (event < sizeof(bluetoothEvents) / sizeof(const char*)) 766 return bluetoothEvents[event - 1]; 767 else 768 return "Event out of Range!"; 769 } 770 771 772 const char* 773 BluetoothManufacturer(uint16 manufacturer) 774 { 775 CALLED(); 776 if (manufacturer < sizeof(bluetoothManufacturers) / sizeof(const char*)) 777 return bluetoothManufacturers[manufacturer]; 778 else if (manufacturer == 0xFFFF) 779 return "internal use"; 780 else 781 return "not assigned"; 782 } 783 784 785 const char* 786 BluetoothError(uint8 error) 787 { 788 CALLED(); 789 if (error < sizeof(bluetoothErrors) / sizeof(const char*)) 790 return bluetoothErrors[error]; 791 else 792 return "not specified"; 793 } 794