Zoltan Hudak / UsbHostMAX3421E

Dependents:   UsbHostMAX3421E_Hello

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers BTHID.cpp Source File

BTHID.cpp

00001 /* Copyright (C) 2013 Kristian Lauszus, TKJ Electronics. All rights reserved.
00002 
00003  This software may be distributed and modified under the terms of the GNU
00004  General Public License version 2 (GPL2) as published by the Free Software
00005  Foundation and appearing in the file GPL2.TXT included in the packaging of
00006  this file. Please note that GPL2 Section 2[b] requires that all works based
00007  on this software must also be made publicly available under the terms of
00008  the GPL2 ("Copyleft").
00009 
00010  Contact information
00011  -------------------
00012 
00013  Kristian Lauszus, TKJ Electronics
00014  Web      :  http://www.tkjelectronics.com
00015  e-mail   :  kristianl@tkjelectronics.com
00016  */
00017 
00018 #include "BTHID.h"
00019 // To enable serial debugging see "settings.h"
00020 //#define EXTRADEBUG // Uncomment to get even more debugging data
00021 //#define PRINTREPORT // Uncomment to print the report send by the HID device
00022 
00023 BTHID::BTHID(BTD *p, bool pair, const char *pin) :
00024 BluetoothService(p), // Pointer to USB class instance - mandatory
00025 protocolMode(USB_HID_BOOT_PROTOCOL) {
00026         for(uint8_t i = 0; i < NUM_PARSERS; i++)
00027                 pRptParser[i] = NULL;
00028 
00029         pBtd->pairWithHIDDevice = pair;
00030         pBtd->btdPin = pin;
00031 
00032         /* Set device cid for the control and intterrupt channelse - LSB */
00033         control_dcid[0] = 0x70; // 0x0070
00034         control_dcid[1] = 0x00;
00035         interrupt_dcid[0] = 0x71; // 0x0071
00036         interrupt_dcid[1] = 0x00;
00037 
00038         Reset();
00039 }
00040 
00041 void BTHID::Reset() {
00042         connected = false;
00043         activeConnection = false;
00044         l2cap_event_flag = 0; // Reset flags
00045         l2cap_state = L2CAP_WAIT;
00046         ResetBTHID();
00047 }
00048 
00049 void BTHID::disconnect() { // Use this void to disconnect the device
00050         // First the HID interrupt channel has to be disconnected, then the HID control channel and finally the HCI connection
00051         pBtd->l2cap_disconnection_request(hci_handle, ++identifier, interrupt_scid, interrupt_dcid);
00052         Reset();
00053         l2cap_state = L2CAP_INTERRUPT_DISCONNECT;
00054 }
00055 
00056 void BTHID::ACLData(uint8_t* l2capinbuf) {
00057         if(!pBtd->l2capConnectionClaimed && pBtd->incomingHIDDevice && !connected && !activeConnection) {
00058                 if(l2capinbuf[8] == L2CAP_CMD_CONNECTION_REQUEST) {
00059                         if((l2capinbuf[12] | (l2capinbuf[13] << 8)) == HID_CTRL_PSM) {
00060                                 pBtd->incomingHIDDevice = false;
00061                                 pBtd->l2capConnectionClaimed = true; // Claim that the incoming connection belongs to this service
00062                                 activeConnection = true;
00063                                 hci_handle = pBtd->hci_handle; // Store the HCI Handle for the connection
00064                                 l2cap_state = L2CAP_WAIT;
00065                         }
00066                 }
00067         }
00068 
00069         if(checkHciHandle(l2capinbuf, hci_handle)) { // acl_handle_ok
00070                 if((l2capinbuf[6] | (l2capinbuf[7] << 8)) == 0x0001U) { // l2cap_control - Channel ID for ACL-U
00071                         if(l2capinbuf[8] == L2CAP_CMD_COMMAND_REJECT) {
00072 #ifdef DEBUG_USB_HOST
00073                                 Notify(PSTR("\r\nL2CAP Command Rejected - Reason: "), 0x80);
00074                                 D_PrintHex<uint8_t > (l2capinbuf[13], 0x80);
00075                                 Notify(PSTR(" "), 0x80);
00076                                 D_PrintHex<uint8_t > (l2capinbuf[12], 0x80);
00077                                 Notify(PSTR(" "), 0x80);
00078                                 D_PrintHex<uint8_t > (l2capinbuf[17], 0x80);
00079                                 Notify(PSTR(" "), 0x80);
00080                                 D_PrintHex<uint8_t > (l2capinbuf[16], 0x80);
00081                                 Notify(PSTR(" "), 0x80);
00082                                 D_PrintHex<uint8_t > (l2capinbuf[15], 0x80);
00083                                 Notify(PSTR(" "), 0x80);
00084                                 D_PrintHex<uint8_t > (l2capinbuf[14], 0x80);
00085 #endif
00086                         } else if(l2capinbuf[8] == L2CAP_CMD_CONNECTION_RESPONSE) {
00087                                 if(((l2capinbuf[16] | (l2capinbuf[17] << 8)) == 0x0000) && ((l2capinbuf[18] | (l2capinbuf[19] << 8)) == SUCCESSFUL)) { // Success
00088                                         if(l2capinbuf[14] == control_dcid[0] && l2capinbuf[15] == control_dcid[1]) {
00089                                                 //Notify(PSTR("\r\nHID Control Connection Complete"), 0x80);
00090                                                 identifier = l2capinbuf[9];
00091                                                 control_scid[0] = l2capinbuf[12];
00092                                                 control_scid[1] = l2capinbuf[13];
00093                                                 l2cap_set_flag(L2CAP_FLAG_CONTROL_CONNECTED);
00094                                         } else if(l2capinbuf[14] == interrupt_dcid[0] && l2capinbuf[15] == interrupt_dcid[1]) {
00095                                                 //Notify(PSTR("\r\nHID Interrupt Connection Complete"), 0x80);
00096                                                 identifier = l2capinbuf[9];
00097                                                 interrupt_scid[0] = l2capinbuf[12];
00098                                                 interrupt_scid[1] = l2capinbuf[13];
00099                                                 l2cap_set_flag(L2CAP_FLAG_INTERRUPT_CONNECTED);
00100                                         }
00101                                 }
00102                         } else if(l2capinbuf[8] == L2CAP_CMD_CONNECTION_REQUEST) {
00103 #ifdef EXTRADEBUG
00104                                 Notify(PSTR("\r\nL2CAP Connection Request - PSM: "), 0x80);
00105                                 D_PrintHex<uint8_t > (l2capinbuf[13], 0x80);
00106                                 Notify(PSTR(" "), 0x80);
00107                                 D_PrintHex<uint8_t > (l2capinbuf[12], 0x80);
00108                                 Notify(PSTR(" SCID: "), 0x80);
00109                                 D_PrintHex<uint8_t > (l2capinbuf[15], 0x80);
00110                                 Notify(PSTR(" "), 0x80);
00111                                 D_PrintHex<uint8_t > (l2capinbuf[14], 0x80);
00112                                 Notify(PSTR(" Identifier: "), 0x80);
00113                                 D_PrintHex<uint8_t > (l2capinbuf[9], 0x80);
00114 #endif
00115                                 if((l2capinbuf[12] | (l2capinbuf[13] << 8)) == HID_CTRL_PSM) {
00116                                         identifier = l2capinbuf[9];
00117                                         control_scid[0] = l2capinbuf[14];
00118                                         control_scid[1] = l2capinbuf[15];
00119                                         l2cap_set_flag(L2CAP_FLAG_CONNECTION_CONTROL_REQUEST);
00120                                 } else if((l2capinbuf[12] | (l2capinbuf[13] << 8)) == HID_INTR_PSM) {
00121                                         identifier = l2capinbuf[9];
00122                                         interrupt_scid[0] = l2capinbuf[14];
00123                                         interrupt_scid[1] = l2capinbuf[15];
00124                                         l2cap_set_flag(L2CAP_FLAG_CONNECTION_INTERRUPT_REQUEST);
00125                                 }
00126                         } else if(l2capinbuf[8] == L2CAP_CMD_CONFIG_RESPONSE) {
00127                                 if((l2capinbuf[16] | (l2capinbuf[17] << 8)) == 0x0000) { // Success
00128                                         if(l2capinbuf[12] == control_dcid[0] && l2capinbuf[13] == control_dcid[1]) {
00129                                                 //Notify(PSTR("\r\nHID Control Configuration Complete"), 0x80);
00130                                                 identifier = l2capinbuf[9];
00131                                                 l2cap_set_flag(L2CAP_FLAG_CONFIG_CONTROL_SUCCESS);
00132                                         } else if(l2capinbuf[12] == interrupt_dcid[0] && l2capinbuf[13] == interrupt_dcid[1]) {
00133                                                 //Notify(PSTR("\r\nHID Interrupt Configuration Complete"), 0x80);
00134                                                 identifier = l2capinbuf[9];
00135                                                 l2cap_set_flag(L2CAP_FLAG_CONFIG_INTERRUPT_SUCCESS);
00136                                         }
00137                                 }
00138                         } else if(l2capinbuf[8] == L2CAP_CMD_CONFIG_REQUEST) {
00139                                 if(l2capinbuf[12] == control_dcid[0] && l2capinbuf[13] == control_dcid[1]) {
00140                                         //Notify(PSTR("\r\nHID Control Configuration Request"), 0x80);
00141                                         pBtd->l2cap_config_response(hci_handle, l2capinbuf[9], control_scid);
00142                                 } else if(l2capinbuf[12] == interrupt_dcid[0] && l2capinbuf[13] == interrupt_dcid[1]) {
00143                                         //Notify(PSTR("\r\nHID Interrupt Configuration Request"), 0x80);
00144                                         pBtd->l2cap_config_response(hci_handle, l2capinbuf[9], interrupt_scid);
00145                                 }
00146                         } else if(l2capinbuf[8] == L2CAP_CMD_DISCONNECT_REQUEST) {
00147                                 if(l2capinbuf[12] == control_dcid[0] && l2capinbuf[13] == control_dcid[1]) {
00148 #ifdef DEBUG_USB_HOST
00149                                         Notify(PSTR("\r\nDisconnect Request: Control Channel"), 0x80);
00150 #endif
00151                                         identifier = l2capinbuf[9];
00152                                         pBtd->l2cap_disconnection_response(hci_handle, identifier, control_dcid, control_scid);
00153                                         Reset();
00154                                 } else if(l2capinbuf[12] == interrupt_dcid[0] && l2capinbuf[13] == interrupt_dcid[1]) {
00155 #ifdef DEBUG_USB_HOST
00156                                         Notify(PSTR("\r\nDisconnect Request: Interrupt Channel"), 0x80);
00157 #endif
00158                                         identifier = l2capinbuf[9];
00159                                         pBtd->l2cap_disconnection_response(hci_handle, identifier, interrupt_dcid, interrupt_scid);
00160                                         Reset();
00161                                 }
00162                         } else if(l2capinbuf[8] == L2CAP_CMD_DISCONNECT_RESPONSE) {
00163                                 if(l2capinbuf[12] == control_scid[0] && l2capinbuf[13] == control_scid[1]) {
00164                                         //Notify(PSTR("\r\nDisconnect Response: Control Channel"), 0x80);
00165                                         identifier = l2capinbuf[9];
00166                                         l2cap_set_flag(L2CAP_FLAG_DISCONNECT_CONTROL_RESPONSE);
00167                                 } else if(l2capinbuf[12] == interrupt_scid[0] && l2capinbuf[13] == interrupt_scid[1]) {
00168                                         //Notify(PSTR("\r\nDisconnect Response: Interrupt Channel"), 0x80);
00169                                         identifier = l2capinbuf[9];
00170                                         l2cap_set_flag(L2CAP_FLAG_DISCONNECT_INTERRUPT_RESPONSE);
00171                                 }
00172                         }
00173 #ifdef EXTRADEBUG
00174                         else {
00175                                 identifier = l2capinbuf[9];
00176                                 Notify(PSTR("\r\nL2CAP Unknown Signaling Command: "), 0x80);
00177                                 D_PrintHex<uint8_t > (l2capinbuf[8], 0x80);
00178                         }
00179 #endif
00180                 } else if(l2capinbuf[6] == interrupt_dcid[0] && l2capinbuf[7] == interrupt_dcid[1]) { // l2cap_interrupt
00181 #ifdef PRINTREPORT
00182                         Notify(PSTR("\r\nL2CAP Interrupt: "), 0x80);
00183                         for(uint16_t i = 0; i < ((uint16_t)l2capinbuf[5] << 8 | l2capinbuf[4]); i++) {
00184                                 D_PrintHex<uint8_t > (l2capinbuf[i + 8], 0x80);
00185                                 Notify(PSTR(" "), 0x80);
00186                         }
00187 #endif
00188                         if(l2capinbuf[8] == 0xA1) { // HID_THDR_DATA_INPUT
00189                                 uint16_t length = ((uint16_t)l2capinbuf[5] << 8 | l2capinbuf[4]);
00190                                 ParseBTHIDData((uint8_t)(length - 1), &l2capinbuf[9]);
00191 
00192                                 switch(l2capinbuf[9]) {
00193                                         case 0x01: // Keyboard or Joystick events
00194                                                 if(pRptParser[KEYBOARD_PARSER_ID])
00195                                                         pRptParser[KEYBOARD_PARSER_ID]->Parse(reinterpret_cast<USBHID *>(this), 0, (uint8_t)(length - 2), &l2capinbuf[10]); // Use reinterpret_cast again to extract the instance
00196                                                 break;
00197 
00198                                         case 0x02: // Mouse events
00199                                                 if(pRptParser[MOUSE_PARSER_ID])
00200                                                         pRptParser[MOUSE_PARSER_ID]->Parse(reinterpret_cast<USBHID *>(this), 0, (uint8_t)(length - 2), &l2capinbuf[10]); // Use reinterpret_cast again to extract the instance
00201                                                 break;
00202 #ifdef EXTRADEBUG
00203                                         default:
00204                                                 Notify(PSTR("\r\nUnknown Report type: "), 0x80);
00205                                                 D_PrintHex<uint8_t > (l2capinbuf[9], 0x80);
00206                                                 break;
00207 #endif
00208                                 }
00209                         }
00210                 } else if(l2capinbuf[6] == control_dcid[0] && l2capinbuf[7] == control_dcid[1]) { // l2cap_control
00211 #ifdef PRINTREPORT
00212                         Notify(PSTR("\r\nL2CAP Control: "), 0x80);
00213                         for(uint16_t i = 0; i < ((uint16_t)l2capinbuf[5] << 8 | l2capinbuf[4]); i++) {
00214                                 D_PrintHex<uint8_t > (l2capinbuf[i + 8], 0x80);
00215                                 Notify(PSTR(" "), 0x80);
00216                         }
00217 #endif
00218                 }
00219 #ifdef EXTRADEBUG
00220                 else {
00221                         Notify(PSTR("\r\nUnsupported L2CAP Data - Channel ID: "), 0x80);
00222                         D_PrintHex<uint8_t > (l2capinbuf[7], 0x80);
00223                         Notify(PSTR(" "), 0x80);
00224                         D_PrintHex<uint8_t > (l2capinbuf[6], 0x80);
00225 
00226                         Notify(PSTR("\r\nData: "), 0x80);
00227                         Notify(PSTR("\r\n"), 0x80);
00228                         for(uint16_t i = 0; i < ((uint16_t)l2capinbuf[5] << 8 | l2capinbuf[4]); i++) {
00229                                 D_PrintHex<uint8_t > (l2capinbuf[i + 8], 0x80);
00230                                 Notify(PSTR(" "), 0x80);
00231                         }
00232                 }
00233 #endif
00234                 L2CAP_task();
00235         }
00236 }
00237 
00238 void BTHID::L2CAP_task() {
00239         switch(l2cap_state) {
00240                         /* These states are used if the HID device is the host */
00241                 case L2CAP_CONTROL_SUCCESS:
00242                         if(l2cap_check_flag(L2CAP_FLAG_CONFIG_CONTROL_SUCCESS)) {
00243 #ifdef DEBUG_USB_HOST
00244                                 Notify(PSTR("\r\nHID Control Successfully Configured"), 0x80);
00245 #endif
00246                                 setProtocol(); // Set protocol before establishing HID interrupt channel
00247                                 l2cap_state = L2CAP_INTERRUPT_SETUP;
00248                         }
00249                         break;
00250 
00251                 case L2CAP_INTERRUPT_SETUP:
00252                         if(l2cap_check_flag(L2CAP_FLAG_CONNECTION_INTERRUPT_REQUEST)) {
00253 #ifdef DEBUG_USB_HOST
00254                                 Notify(PSTR("\r\nHID Interrupt Incoming Connection Request"), 0x80);
00255 #endif
00256                                 pBtd->l2cap_connection_response(hci_handle, identifier, interrupt_dcid, interrupt_scid, PENDING);
00257                                 wait_ms(1);
00258                                 pBtd->l2cap_connection_response(hci_handle, identifier, interrupt_dcid, interrupt_scid, SUCCESSFUL);
00259                                 identifier++;
00260                                 wait_ms(1);
00261                                 pBtd->l2cap_config_request(hci_handle, identifier, interrupt_scid);
00262 
00263                                 l2cap_state = L2CAP_INTERRUPT_CONFIG_REQUEST;
00264                         }
00265                         break;
00266 
00267                         /* These states are used if the Arduino is the host */
00268                 case L2CAP_CONTROL_CONNECT_REQUEST:
00269                         if(l2cap_check_flag(L2CAP_FLAG_CONTROL_CONNECTED)) {
00270 #ifdef DEBUG_USB_HOST
00271                                 Notify(PSTR("\r\nSend HID Control Config Request"), 0x80);
00272 #endif
00273                                 identifier++;
00274                                 pBtd->l2cap_config_request(hci_handle, identifier, control_scid);
00275                                 l2cap_state = L2CAP_CONTROL_CONFIG_REQUEST;
00276                         }
00277                         break;
00278 
00279                 case L2CAP_CONTROL_CONFIG_REQUEST:
00280                         if(l2cap_check_flag(L2CAP_FLAG_CONFIG_CONTROL_SUCCESS)) {
00281                                 setProtocol(); // Set protocol before establishing HID interrupt channel
00282                                 wait_ms(1); // Short delay between commands - just to be sure
00283 #ifdef DEBUG_USB_HOST
00284                                 Notify(PSTR("\r\nSend HID Interrupt Connection Request"), 0x80);
00285 #endif
00286                                 identifier++;
00287                                 pBtd->l2cap_connection_request(hci_handle, identifier, interrupt_dcid, HID_INTR_PSM);
00288                                 l2cap_state = L2CAP_INTERRUPT_CONNECT_REQUEST;
00289                         }
00290                         break;
00291 
00292                 case L2CAP_INTERRUPT_CONNECT_REQUEST:
00293                         if(l2cap_check_flag(L2CAP_FLAG_INTERRUPT_CONNECTED)) {
00294 #ifdef DEBUG_USB_HOST
00295                                 Notify(PSTR("\r\nSend HID Interrupt Config Request"), 0x80);
00296 #endif
00297                                 identifier++;
00298                                 pBtd->l2cap_config_request(hci_handle, identifier, interrupt_scid);
00299                                 l2cap_state = L2CAP_INTERRUPT_CONFIG_REQUEST;
00300                         }
00301                         break;
00302 
00303                 case L2CAP_INTERRUPT_CONFIG_REQUEST:
00304                         if(l2cap_check_flag(L2CAP_FLAG_CONFIG_INTERRUPT_SUCCESS)) { // Now the HID channels is established
00305 #ifdef DEBUG_USB_HOST
00306                                 Notify(PSTR("\r\nHID Channels Established"), 0x80);
00307 #endif
00308                                 pBtd->connectToHIDDevice = false;
00309                                 pBtd->pairWithHIDDevice = false;
00310                                 connected = true;
00311                                 onInit();
00312                                 l2cap_state = L2CAP_DONE;
00313                         }
00314                         break;
00315 
00316                 case L2CAP_DONE:
00317                         break;
00318 
00319                 case L2CAP_INTERRUPT_DISCONNECT:
00320                         if(l2cap_check_flag(L2CAP_FLAG_DISCONNECT_INTERRUPT_RESPONSE)) {
00321 #ifdef DEBUG_USB_HOST
00322                                 Notify(PSTR("\r\nDisconnected Interrupt Channel"), 0x80);
00323 #endif
00324                                 identifier++;
00325                                 pBtd->l2cap_disconnection_request(hci_handle, identifier, control_scid, control_dcid);
00326                                 l2cap_state = L2CAP_CONTROL_DISCONNECT;
00327                         }
00328                         break;
00329 
00330                 case L2CAP_CONTROL_DISCONNECT:
00331                         if(l2cap_check_flag(L2CAP_FLAG_DISCONNECT_CONTROL_RESPONSE)) {
00332 #ifdef DEBUG_USB_HOST
00333                                 Notify(PSTR("\r\nDisconnected Control Channel"), 0x80);
00334 #endif
00335                                 pBtd->hci_disconnect(hci_handle);
00336                                 hci_handle = -1; // Reset handle
00337                                 l2cap_event_flag = 0; // Reset flags
00338                                 l2cap_state = L2CAP_WAIT;
00339                         }
00340                         break;
00341         }
00342 }
00343 
00344 void BTHID::Run() {
00345         switch(l2cap_state) {
00346                 case L2CAP_WAIT:
00347                         if(pBtd->connectToHIDDevice && !pBtd->l2capConnectionClaimed && !connected && !activeConnection) {
00348                                 pBtd->l2capConnectionClaimed = true;
00349                                 activeConnection = true;
00350 #ifdef DEBUG_USB_HOST
00351                                 Notify(PSTR("\r\nSend HID Control Connection Request"), 0x80);
00352 #endif
00353                                 hci_handle = pBtd->hci_handle; // Store the HCI Handle for the connection
00354                                 l2cap_event_flag = 0; // Reset flags
00355                                 identifier = 0;
00356                                 pBtd->l2cap_connection_request(hci_handle, identifier, control_dcid, HID_CTRL_PSM);
00357                                 l2cap_state = L2CAP_CONTROL_CONNECT_REQUEST;
00358                         } else if(l2cap_check_flag(L2CAP_FLAG_CONNECTION_CONTROL_REQUEST)) {
00359 #ifdef DEBUG_USB_HOST
00360                                 Notify(PSTR("\r\nHID Control Incoming Connection Request"), 0x80);
00361 #endif
00362                                 pBtd->l2cap_connection_response(hci_handle, identifier, control_dcid, control_scid, PENDING);
00363                                 wait_ms(1);
00364                                 pBtd->l2cap_connection_response(hci_handle, identifier, control_dcid, control_scid, SUCCESSFUL);
00365                                 identifier++;
00366                                 wait_ms(1);
00367                                 pBtd->l2cap_config_request(hci_handle, identifier, control_scid);
00368                                 l2cap_state = L2CAP_CONTROL_SUCCESS;
00369                         }
00370                         break;
00371         }
00372 }
00373 
00374 /************************************************************/
00375 /*                    HID Commands                          */
00376 
00377 /************************************************************/
00378 void BTHID::setProtocol() {
00379 #ifdef DEBUG_USB_HOST
00380         Notify(PSTR("\r\nSet protocol mode: "), 0x80);
00381         D_PrintHex<uint8_t > (protocolMode, 0x80);
00382 #endif
00383         if (protocolMode != USB_HID_BOOT_PROTOCOL && protocolMode != HID_RPT_PROTOCOL) {
00384 #ifdef DEBUG_USB_HOST
00385                 Notify(PSTR("\r\nNot a valid protocol mode. Using Boot protocol instead."), 0x80);
00386 #endif
00387                 protocolMode = USB_HID_BOOT_PROTOCOL; // Use Boot Protocol by default
00388         }
00389         uint8_t command = 0x70 | protocolMode; // Set Protocol, see Bluetooth HID specs page 33
00390         pBtd->L2CAP_Command(hci_handle, &command, 1, control_scid[0], control_scid[1]);
00391 }
00392 
00393 void BTHID::setLeds(uint8_t data) {
00394         uint8_t buf[3];
00395         buf[0] = 0xA2; // HID BT DATA_request (0xA0) | Report Type (Output 0x02)
00396         buf[1] = 0x01; // Report ID
00397         buf[2] = data;
00398         pBtd->L2CAP_Command(hci_handle, buf, 3, interrupt_scid[0], interrupt_scid[1]);
00399 }