Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
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 delay(1); 00258 pBtd->l2cap_connection_response(hci_handle, identifier, interrupt_dcid, interrupt_scid, SUCCESSFUL); 00259 identifier++; 00260 delay(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 delay(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 delay(1); 00364 pBtd->l2cap_connection_response(hci_handle, identifier, control_dcid, control_scid, SUCCESSFUL); 00365 identifier++; 00366 delay(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 } 00400
Generated on Thu Jul 14 2022 08:33:40 by
1.7.2