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.
Dependents: UsbHostMAX3421E_Hello
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 }
Generated on Tue Jul 12 2022 18:12:04 by
