USB Host Shield 2.0
BTHID.cpp
Go to the documentation of this file.
1 /* Copyright (C) 2013 Kristian Lauszus, TKJ Electronics. All rights reserved.
2 
3  This software may be distributed and modified under the terms of the GNU
4  General Public License version 2 (GPL2) as published by the Free Software
5  Foundation and appearing in the file GPL2.TXT included in the packaging of
6  this file. Please note that GPL2 Section 2[b] requires that all works based
7  on this software must also be made publicly available under the terms of
8  the GPL2 ("Copyleft").
9 
10  Contact information
11  -------------------
12 
13  Kristian Lauszus, TKJ Electronics
14  Web : http://www.tkjelectronics.com
15  e-mail : kristianl@tkjelectronics.com
16  */
17 
18 #include "BTHID.h"
19 // To enable serial debugging see "settings.h"
20 //#define EXTRADEBUG // Uncomment to get even more debugging data
21 //#define PRINTREPORT // Uncomment to print the report send by the HID device
22 
23 BTHID::BTHID(BTD *p, bool pair, const char *pin) :
24 BluetoothService(p), // Pointer to USB class instance - mandatory
25 protocolMode(USB_HID_BOOT_PROTOCOL) {
26  for(uint8_t i = 0; i < NUM_PARSERS; i++)
27  pRptParser[i] = NULL;
28 
30  pBtd->btdPin = pin;
31 
32  /* Set device cid for the control and intterrupt channelse - LSB */
33  sdp_dcid[0] = 0x50; // 0x0050
34  sdp_dcid[1] = 0x00;
35  control_dcid[0] = 0x70; // 0x0070
36  control_dcid[1] = 0x00;
37  interrupt_dcid[0] = 0x71; // 0x0071
38  interrupt_dcid[1] = 0x00;
39 
40  Reset();
41 }
42 
43 void BTHID::Reset() {
44  connected = false;
45  activeConnection = false;
46  SDPConnected = false;
47  l2cap_event_flag = 0; // Reset flags
49  l2cap_state = L2CAP_WAIT;
50  ResetBTHID();
51 }
52 
53 void BTHID::disconnect() { // Use this void to disconnect the device
54  if(SDPConnected)
56  // First the HID interrupt channel has to be disconnected, then the HID control channel and finally the HCI connection
58  Reset();
60  l2cap_state = L2CAP_INTERRUPT_DISCONNECT;
61 }
62 
63 void BTHID::ACLData(uint8_t* l2capinbuf) {
64  if(!connected) {
65  if(l2capinbuf[8] == L2CAP_CMD_CONNECTION_REQUEST) {
66  if((l2capinbuf[12] | (l2capinbuf[13] << 8)) == SDP_PSM && !pBtd->sdpConnectionClaimed) {
67  pBtd->sdpConnectionClaimed = true;
68  hci_handle = pBtd->hci_handle; // Store the HCI Handle for the connection
69  l2cap_sdp_state = L2CAP_SDP_WAIT; // Reset state
70  }
71  }
72  }
73 
74  if(!pBtd->l2capConnectionClaimed && pBtd->incomingHIDDevice && !connected && !activeConnection) {
75  if(l2capinbuf[8] == L2CAP_CMD_CONNECTION_REQUEST) {
76  if((l2capinbuf[12] | (l2capinbuf[13] << 8)) == HID_CTRL_PSM) {
77  pBtd->incomingHIDDevice = false;
78  pBtd->l2capConnectionClaimed = true; // Claim that the incoming connection belongs to this service
79  activeConnection = true;
80  hci_handle = pBtd->hci_handle; // Store the HCI Handle for the connection
81  l2cap_state = L2CAP_WAIT;
82  }
83  }
84  }
85 
86  if(checkHciHandle(l2capinbuf, hci_handle)) { // acl_handle_ok
87  if((l2capinbuf[6] | (l2capinbuf[7] << 8)) == 0x0001U) { // l2cap_control - Channel ID for ACL-U
88  if(l2capinbuf[8] == L2CAP_CMD_COMMAND_REJECT) {
89 #ifdef DEBUG_USB_HOST
90  Notify(PSTR("\r\nL2CAP Command Rejected - Reason: "), 0x80);
91  D_PrintHex<uint8_t > (l2capinbuf[13], 0x80);
92  Notify(PSTR(" "), 0x80);
93  D_PrintHex<uint8_t > (l2capinbuf[12], 0x80);
94  Notify(PSTR(" "), 0x80);
95  D_PrintHex<uint8_t > (l2capinbuf[17], 0x80);
96  Notify(PSTR(" "), 0x80);
97  D_PrintHex<uint8_t > (l2capinbuf[16], 0x80);
98  Notify(PSTR(" "), 0x80);
99  D_PrintHex<uint8_t > (l2capinbuf[15], 0x80);
100  Notify(PSTR(" "), 0x80);
101  D_PrintHex<uint8_t > (l2capinbuf[14], 0x80);
102 #endif
103  } else if(l2capinbuf[8] == L2CAP_CMD_CONNECTION_RESPONSE) {
104  if(((l2capinbuf[16] | (l2capinbuf[17] << 8)) == 0x0000) && ((l2capinbuf[18] | (l2capinbuf[19] << 8)) == SUCCESSFUL)) { // Success
105  if(l2capinbuf[14] == sdp_dcid[0] && l2capinbuf[15] == sdp_dcid[1]) {
106 #ifdef EXTRADEBUG
107  Notify(PSTR("\r\nSDP Connection Complete"), 0x80);
108 #endif
109  identifier = l2capinbuf[9];
110  sdp_scid[0] = l2capinbuf[12];
111  sdp_scid[1] = l2capinbuf[13];
112 #ifdef DEBUG_USB_HOST
113  Notify(PSTR("\r\nSend SDP Config Request"), 0x80);
114 #endif
115  identifier++;
117  } else if(l2capinbuf[14] == control_dcid[0] && l2capinbuf[15] == control_dcid[1]) {
118 #ifdef EXTRADEBUG
119  Notify(PSTR("\r\nHID Control Connection Complete"), 0x80);
120 #endif
121  identifier = l2capinbuf[9];
122  control_scid[0] = l2capinbuf[12];
123  control_scid[1] = l2capinbuf[13];
125  } else if(l2capinbuf[14] == interrupt_dcid[0] && l2capinbuf[15] == interrupt_dcid[1]) {
126 #ifdef EXTRADEBUG
127  Notify(PSTR("\r\nHID Interrupt Connection Complete"), 0x80);
128 #endif
129  identifier = l2capinbuf[9];
130  interrupt_scid[0] = l2capinbuf[12];
131  interrupt_scid[1] = l2capinbuf[13];
133  }
134  }
135  } else if(l2capinbuf[8] == L2CAP_CMD_CONNECTION_REQUEST) {
136 #ifdef EXTRADEBUG
137  Notify(PSTR("\r\nL2CAP Connection Request - PSM: "), 0x80);
138  D_PrintHex<uint8_t > (l2capinbuf[13], 0x80);
139  Notify(PSTR(" "), 0x80);
140  D_PrintHex<uint8_t > (l2capinbuf[12], 0x80);
141  Notify(PSTR(" SCID: "), 0x80);
142  D_PrintHex<uint8_t > (l2capinbuf[15], 0x80);
143  Notify(PSTR(" "), 0x80);
144  D_PrintHex<uint8_t > (l2capinbuf[14], 0x80);
145  Notify(PSTR(" Identifier: "), 0x80);
146  D_PrintHex<uint8_t > (l2capinbuf[9], 0x80);
147 #endif
148  if((l2capinbuf[12] | (l2capinbuf[13] << 8)) == SDP_PSM) {
149  identifier = l2capinbuf[9];
150  sdp_scid[0] = l2capinbuf[14];
151  sdp_scid[1] = l2capinbuf[15];
153  } else if((l2capinbuf[12] | (l2capinbuf[13] << 8)) == HID_CTRL_PSM) {
154  identifier = l2capinbuf[9];
155  control_scid[0] = l2capinbuf[14];
156  control_scid[1] = l2capinbuf[15];
158  } else if((l2capinbuf[12] | (l2capinbuf[13] << 8)) == HID_INTR_PSM) {
159  identifier = l2capinbuf[9];
160  interrupt_scid[0] = l2capinbuf[14];
161  interrupt_scid[1] = l2capinbuf[15];
163  }
164  } else if(l2capinbuf[8] == L2CAP_CMD_CONFIG_RESPONSE) {
165  if((l2capinbuf[16] | (l2capinbuf[17] << 8)) == 0x0000) { // Success
166  if(l2capinbuf[12] == sdp_dcid[0] && l2capinbuf[13] == sdp_dcid[1]) {
167 #ifdef EXTRADEBUG
168  Notify(PSTR("\r\nSDP Configuration Complete"), 0x80);
169 #endif
170  identifier = l2capinbuf[9];
172  } else if(l2capinbuf[12] == control_dcid[0] && l2capinbuf[13] == control_dcid[1]) {
173 #ifdef EXTRADEBUG
174  Notify(PSTR("\r\nHID Control Configuration Complete"), 0x80);
175 #endif
176  identifier = l2capinbuf[9];
178  } else if(l2capinbuf[12] == interrupt_dcid[0] && l2capinbuf[13] == interrupt_dcid[1]) {
179 #ifdef EXTRADEBUG
180  Notify(PSTR("\r\nHID Interrupt Configuration Complete"), 0x80);
181 #endif
182  identifier = l2capinbuf[9];
184  }
185  }
186  } else if(l2capinbuf[8] == L2CAP_CMD_CONFIG_REQUEST) {
187  if(l2capinbuf[12] == sdp_dcid[0] && l2capinbuf[13] == sdp_dcid[1]) {
188 #ifdef EXTRADEBUG
189  Notify(PSTR("\r\nSDP Configuration Request"), 0x80);
190 #endif
191  pBtd->l2cap_config_response(hci_handle, l2capinbuf[9], sdp_scid);
192  } else if(l2capinbuf[12] == control_dcid[0] && l2capinbuf[13] == control_dcid[1]) {
193 #ifdef EXTRADEBUG
194  Notify(PSTR("\r\nHID Control Configuration Request"), 0x80);
195 #endif
197  } else if(l2capinbuf[12] == interrupt_dcid[0] && l2capinbuf[13] == interrupt_dcid[1]) {
198 #ifdef EXTRADEBUG
199  Notify(PSTR("\r\nHID Interrupt Configuration Request"), 0x80);
200 #endif
202  }
203  } else if(l2capinbuf[8] == L2CAP_CMD_DISCONNECT_REQUEST) {
204  if(l2capinbuf[12] == sdp_dcid[0] && l2capinbuf[13] == sdp_dcid[1]) {
205 #ifdef DEBUG_USB_HOST
206  Notify(PSTR("\r\nDisconnect Request: SDP Channel"), 0x80);
207 #endif
208  identifier = l2capinbuf[9];
210  } else if(l2capinbuf[12] == control_dcid[0] && l2capinbuf[13] == control_dcid[1]) {
211 #ifdef DEBUG_USB_HOST
212  Notify(PSTR("\r\nDisconnect Request: Control Channel"), 0x80);
213 #endif
214  identifier = l2capinbuf[9];
216  Reset();
217  } else if(l2capinbuf[12] == interrupt_dcid[0] && l2capinbuf[13] == interrupt_dcid[1]) {
218 #ifdef DEBUG_USB_HOST
219  Notify(PSTR("\r\nDisconnect Request: Interrupt Channel"), 0x80);
220 #endif
221  identifier = l2capinbuf[9];
223  Reset();
224  }
225  } else if(l2capinbuf[8] == L2CAP_CMD_DISCONNECT_RESPONSE) {
226  if(l2capinbuf[12] == sdp_scid[0] && l2capinbuf[13] == sdp_scid[1]) {
227 #ifdef EXTRADEBUG
228  Notify(PSTR("\r\nDisconnect Response: SDP Channel"), 0x80);
229 #endif
230  identifier = l2capinbuf[9];
232  } else if(l2capinbuf[12] == control_scid[0] && l2capinbuf[13] == control_scid[1]) {
233 #ifdef EXTRADEBUG
234  Notify(PSTR("\r\nDisconnect Response: Control Channel"), 0x80);
235 #endif
236  identifier = l2capinbuf[9];
238  } else if(l2capinbuf[12] == interrupt_scid[0] && l2capinbuf[13] == interrupt_scid[1]) {
239 #ifdef EXTRADEBUG
240  Notify(PSTR("\r\nDisconnect Response: Interrupt Channel"), 0x80);
241 #endif
242  identifier = l2capinbuf[9];
244  }
245  } else if(l2capinbuf[8] == L2CAP_CMD_INFORMATION_REQUEST) {
246 #ifdef DEBUG_USB_HOST
247  Notify(PSTR("\r\nInformation request"), 0x80);
248 #endif
249  identifier = l2capinbuf[9];
250  pBtd->l2cap_information_response(hci_handle, identifier, l2capinbuf[12], l2capinbuf[13]);
251  }
252 #ifdef EXTRADEBUG
253  else {
254  identifier = l2capinbuf[9];
255  Notify(PSTR("\r\nL2CAP Unknown Signaling Command: "), 0x80);
256  D_PrintHex<uint8_t > (l2capinbuf[8], 0x80);
257  }
258 #endif
259  } else if(l2capinbuf[6] == sdp_dcid[0] && l2capinbuf[7] == sdp_dcid[1]) { // SDP
260  if(l2capinbuf[8] == SDP_SERVICE_SEARCH_REQUEST) {
261 #ifdef EXTRADEBUG
262  Notify(PSTR("\r\nSDP_SERVICE_SEARCH_REQUEST"), 0x80);
263 #endif
264  // Send response
265  l2capoutbuf[0] = SDP_SERVICE_SEARCH_RESPONSE;
266  l2capoutbuf[1] = l2capinbuf[9];//transactionIDHigh;
267  l2capoutbuf[2] = l2capinbuf[10];//transactionIDLow;
268 
269  l2capoutbuf[3] = 0x00; // MSB Parameter Length
270  l2capoutbuf[4] = 0x05; // LSB Parameter Length = 5
271 
272  l2capoutbuf[5] = 0x00; // MSB TotalServiceRecordCount
273  l2capoutbuf[6] = 0x00; // LSB TotalServiceRecordCount = 0
274 
275  l2capoutbuf[7] = 0x00; // MSB CurrentServiceRecordCount
276  l2capoutbuf[8] = 0x00; // LSB CurrentServiceRecordCount = 0
277 
278  l2capoutbuf[9] = 0x00; // No continuation state
279 
280  SDP_Command(l2capoutbuf, 10);
281  } else if(l2capinbuf[8] == SDP_SERVICE_ATTRIBUTE_REQUEST) {
282 #ifdef EXTRADEBUG
283  Notify(PSTR("\r\nSDP_SERVICE_ATTRIBUTE_REQUEST"), 0x80);
284 #endif
285  // Send response
286  l2capoutbuf[0] = SDP_SERVICE_ATTRIBUTE_RESPONSE;
287  l2capoutbuf[1] = l2capinbuf[9];//transactionIDHigh;
288  l2capoutbuf[2] = l2capinbuf[10];//transactionIDLow;
289 
290  l2capoutbuf[3] = 0x00; // MSB Parameter Length
291  l2capoutbuf[4] = 0x05; // LSB Parameter Length = 5
292 
293  l2capoutbuf[5] = 0x00; // MSB AttributeListByteCount
294  l2capoutbuf[6] = 0x02; // LSB AttributeListByteCount = 2
295 
296  // TODO: What to send?
297  l2capoutbuf[7] = 0x35; // Data element sequence - length in next byte
298  l2capoutbuf[8] = 0x00; // Length = 0
299 
300  l2capoutbuf[9] = 0x00; // No continuation state
301 
302  SDP_Command(l2capoutbuf, 10);
303  } else if(l2capinbuf[8] == SDP_SERVICE_SEARCH_ATTRIBUTE_REQUEST) {
304 #ifdef EXTRADEBUG
305  Notify(PSTR("\r\nSDP_SERVICE_SEARCH_ATTRIBUTE_REQUEST"), 0x80);
306  Notify(PSTR("\r\nUUID: "), 0x80);
307  uint16_t uuid;
308  if((l2capinbuf[16] << 8 | l2capinbuf[17]) == 0x0000) // Check if it's sending the UUID as a 128-bit UUID
309  uuid = (l2capinbuf[18] << 8 | l2capinbuf[19]);
310  else // Short UUID
311  uuid = (l2capinbuf[16] << 8 | l2capinbuf[17]);
312  D_PrintHex<uint16_t > (uuid, 0x80);
313 
314  Notify(PSTR("\r\nLength: "), 0x80);
315  uint16_t length = l2capinbuf[11] << 8 | l2capinbuf[12];
316  D_PrintHex<uint16_t > (length, 0x80);
317  Notify(PSTR("\r\nData: "), 0x80);
318  for(uint8_t i = 0; i < length; i++) {
319  D_PrintHex<uint8_t > (l2capinbuf[13 + i], 0x80);
320  Notify(PSTR(" "), 0x80);
321  }
322 #endif
323  serviceNotSupported(l2capinbuf[9], l2capinbuf[10]); // The service is not supported
324  }
325 #ifdef EXTRADEBUG
326  else {
327  Notify(PSTR("\r\nUnknown PDU: "), 0x80);
328  D_PrintHex<uint8_t > (l2capinbuf[8], 0x80);
329  }
330 #endif
331  } else if(l2capinbuf[6] == interrupt_dcid[0] && l2capinbuf[7] == interrupt_dcid[1]) { // l2cap_interrupt
332 #ifdef PRINTREPORT
333  Notify(PSTR("\r\nL2CAP Interrupt: "), 0x80);
334  for(uint16_t i = 0; i < ((uint16_t)l2capinbuf[5] << 8 | l2capinbuf[4]); i++) {
335  D_PrintHex<uint8_t > (l2capinbuf[i + 8], 0x80);
336  Notify(PSTR(" "), 0x80);
337  }
338 #endif
339  if(l2capinbuf[8] == 0xA1) { // HID BT DATA (0xA0) | Report Type (Input 0x01)
340  lastBtDataInputIntMillis = (uint32_t)millis(); // Store the timestamp of the report
341 
342  uint16_t length = ((uint16_t)l2capinbuf[5] << 8 | l2capinbuf[4]);
343  ParseBTHIDData((uint8_t)(length - 1), &l2capinbuf[9]); // First byte will be the report ID
344 
345  switch(l2capinbuf[9]) { // Report ID
346  case 0x01: // Keyboard or Joystick events
347  if(pRptParser[KEYBOARD_PARSER_ID])
348  pRptParser[KEYBOARD_PARSER_ID]->Parse(reinterpret_cast<USBHID *>(this), 0, (uint8_t)(length - 2), &l2capinbuf[10]); // Use reinterpret_cast again to extract the instance
349  break;
350 
351  case 0x02: // Mouse events
352  if(pRptParser[MOUSE_PARSER_ID])
353  pRptParser[MOUSE_PARSER_ID]->Parse(reinterpret_cast<USBHID *>(this), 0, (uint8_t)(length - 2), &l2capinbuf[10]); // Use reinterpret_cast again to extract the instance
354  break;
355 #ifdef EXTRADEBUG
356  default:
357  Notify(PSTR("\r\nUnknown Report type: "), 0x80);
358  D_PrintHex<uint8_t > (l2capinbuf[9], 0x80);
359  break;
360 #endif
361  }
362  } else {
363 #ifdef EXTRADEBUG
364  Notify(PSTR("\r\nUnhandled L2CAP interrupt report: "), 0x80);
365  D_PrintHex<uint8_t > (l2capinbuf[8], 0x80);
366 #endif
367  }
368  } else if(l2capinbuf[6] == control_dcid[0] && l2capinbuf[7] == control_dcid[1]) { // l2cap_control
369 #ifdef PRINTREPORT
370  Notify(PSTR("\r\nL2CAP Control: "), 0x80);
371  for(uint16_t i = 0; i < ((uint16_t)l2capinbuf[5] << 8 | l2capinbuf[4]); i++) {
372  D_PrintHex<uint8_t > (l2capinbuf[i + 8], 0x80);
373  Notify(PSTR(" "), 0x80);
374  }
375 #endif
376  if(l2capinbuf[8] == 0xA3) { // HID BT DATA (0xA0) | Report Type (Feature 0x03)
377  uint16_t length = ((uint16_t)l2capinbuf[5] << 8 | l2capinbuf[4]);
378  ParseBTHIDControlData((uint8_t)(length - 1), &l2capinbuf[9]); // First byte will be the report ID
379  } else {
380 #ifdef EXTRADEBUG
381  Notify(PSTR("\r\nUnhandled L2CAP control report: "), 0x80);
382  D_PrintHex<uint8_t > (l2capinbuf[8], 0x80);
383 #endif
384  }
385  }
386 #ifdef EXTRADEBUG
387  else {
388  Notify(PSTR("\r\nUnsupported L2CAP Data - Channel ID: "), 0x80);
389  D_PrintHex<uint8_t > (l2capinbuf[7], 0x80);
390  Notify(PSTR(" "), 0x80);
391  D_PrintHex<uint8_t > (l2capinbuf[6], 0x80);
392 
393  Notify(PSTR("\r\nData: "), 0x80);
394  Notify(PSTR("\r\n"), 0x80);
395  for(uint16_t i = 0; i < ((uint16_t)l2capinbuf[5] << 8 | l2capinbuf[4]); i++) {
396  D_PrintHex<uint8_t > (l2capinbuf[i + 8], 0x80);
397  Notify(PSTR(" "), 0x80);
398  }
399  }
400 #endif
401  SDP_task();
402  L2CAP_task();
403  }
404 }
405 
406 void BTHID::SDP_task() {
407  switch(l2cap_sdp_state) {
408  case L2CAP_SDP_WAIT:
411 #ifdef DEBUG_USB_HOST
412  Notify(PSTR("\r\nSDP Incoming Connection Request"), 0x80);
413 #endif
415  delay(1);
417  identifier++;
418  delay(1);
423  SDPConnected = false;
424 #ifdef DEBUG_USB_HOST
425  Notify(PSTR("\r\nDisconnected SDP Channel"), 0x80);
426 #endif
428  }
429  break;
430  case L2CAP_SDP_SUCCESS:
433 #ifdef DEBUG_USB_HOST
434  Notify(PSTR("\r\nSDP Successfully Configured"), 0x80);
435 #endif
436  SDPConnected = true;
438  }
439  break;
440 
441  case L2CAP_DISCONNECT_RESPONSE: // This is for both disconnection response from the RFCOMM and SDP channel if they were connected
443 #ifdef DEBUG_USB_HOST
444  Notify(PSTR("\r\nDisconnected L2CAP Connection"), 0x80);
445 #endif
447  hci_handle = -1; // Reset handle
448  Reset();
449  }
450  break;
451  }
452 }
453 
454 void BTHID::L2CAP_task() {
455  switch(l2cap_state) {
456  /* These states are used if the HID device is the host */
459 #ifdef DEBUG_USB_HOST
460  Notify(PSTR("\r\nHID Control Successfully Configured"), 0x80);
461 #endif
462  setProtocol(); // Set protocol before establishing HID interrupt channel
463  l2cap_state = L2CAP_INTERRUPT_SETUP;
464  }
465  break;
466 
469 #ifdef DEBUG_USB_HOST
470  Notify(PSTR("\r\nHID Interrupt Incoming Connection Request"), 0x80);
471 #endif
473  delay(1);
475  identifier++;
476  delay(1);
478 
479  l2cap_state = L2CAP_INTERRUPT_CONFIG_REQUEST;
480  }
481  break;
482 
483  /* These states are used if the Arduino is the host */
486 #ifdef DEBUG_USB_HOST
487  Notify(PSTR("\r\nSend HID Control Config Request"), 0x80);
488 #endif
489  identifier++;
491  l2cap_state = L2CAP_CONTROL_CONFIG_REQUEST;
492  }
493  break;
494 
497  setProtocol(); // Set protocol before establishing HID interrupt channel
498  delay(1); // Short delay between commands - just to be sure
499 #ifdef DEBUG_USB_HOST
500  Notify(PSTR("\r\nSend HID Interrupt Connection Request"), 0x80);
501 #endif
502  identifier++;
504  l2cap_state = L2CAP_INTERRUPT_CONNECT_REQUEST;
505  }
506  break;
507 
510 #ifdef DEBUG_USB_HOST
511  Notify(PSTR("\r\nSend HID Interrupt Config Request"), 0x80);
512 #endif
513  identifier++;
515  l2cap_state = L2CAP_INTERRUPT_CONFIG_REQUEST;
516  }
517  break;
518 
520  if(l2cap_check_flag(L2CAP_FLAG_CONFIG_INTERRUPT_SUCCESS)) { // Now the HID channels is established
521 #ifdef DEBUG_USB_HOST
522  Notify(PSTR("\r\nHID Channels Established"), 0x80);
523 #endif
524  pBtd->connectToHIDDevice = false;
525  pBtd->pairWithHIDDevice = false;
526  connected = true;
527  onInit();
528  l2cap_state = L2CAP_DONE;
529  }
530  break;
531 
532  case L2CAP_DONE:
533  break;
534 
537 #ifdef DEBUG_USB_HOST
538  Notify(PSTR("\r\nDisconnected Interrupt Channel"), 0x80);
539 #endif
540  identifier++;
542  l2cap_state = L2CAP_CONTROL_DISCONNECT;
543  }
544  break;
545 
548 #ifdef DEBUG_USB_HOST
549  Notify(PSTR("\r\nDisconnected Control Channel"), 0x80);
550 #endif
552  hci_handle = -1; // Reset handle
553  l2cap_event_flag = 0; // Reset flags
554  l2cap_state = L2CAP_WAIT;
555  }
556  break;
557  }
558 }
559 
560 void BTHID::Run() {
561  switch(l2cap_state) {
562  case L2CAP_WAIT:
563  if(pBtd->connectToHIDDevice && !pBtd->l2capConnectionClaimed && !connected && !activeConnection) {
565  activeConnection = true;
566 #ifdef DEBUG_USB_HOST
567  Notify(PSTR("\r\nSend HID Control Connection Request"), 0x80);
568 #endif
569  hci_handle = pBtd->hci_handle; // Store the HCI Handle for the connection
570  l2cap_event_flag = 0; // Reset flags
571  identifier = 0;
573  l2cap_state = L2CAP_CONTROL_CONNECT_REQUEST;
575 #ifdef DEBUG_USB_HOST
576  Notify(PSTR("\r\nHID Control Incoming Connection Request"), 0x80);
577 #endif
579  delay(1);
581  identifier++;
582  delay(1);
584  l2cap_state = L2CAP_CONTROL_SUCCESS;
585  }
586  break;
587  }
588 }
589 
590 void BTHID::SDP_Command(uint8_t* data, uint8_t nbytes) { // See page 223 in the Bluetooth specs
591  pBtd->L2CAP_Command(hci_handle, data, nbytes, sdp_scid[0], sdp_scid[1]);
592 }
593 
594 void BTHID::serviceNotSupported(uint8_t transactionIDHigh, uint8_t transactionIDLow) { // See page 235 in the Bluetooth specs
595  l2capoutbuf[0] = SDP_SERVICE_SEARCH_ATTRIBUTE_RESPONSE;
596  l2capoutbuf[1] = transactionIDHigh;
597  l2capoutbuf[2] = transactionIDLow;
598  l2capoutbuf[3] = 0x00; // MSB Parameter Length
599  l2capoutbuf[4] = 0x05; // LSB Parameter Length = 5
600  l2capoutbuf[5] = 0x00; // MSB AttributeListsByteCount
601  l2capoutbuf[6] = 0x02; // LSB AttributeListsByteCount = 2
602 
603  /* Attribute ID/Value Sequence: */
604  l2capoutbuf[7] = 0x35; // Data element sequence - length in next byte
605  l2capoutbuf[8] = 0x00; // Length = 0
606  l2capoutbuf[9] = 0x00; // No continuation state
607 
608  SDP_Command(l2capoutbuf, 10);
609 }
610 
611 /************************************************************/
612 /* HID Commands */
613 
614 /************************************************************/
615 void BTHID::setProtocol() {
616 #ifdef DEBUG_USB_HOST
617  Notify(PSTR("\r\nSet protocol mode: "), 0x80);
618  D_PrintHex<uint8_t > (protocolMode, 0x80);
619 #endif
620  if (protocolMode != USB_HID_BOOT_PROTOCOL && protocolMode != HID_RPT_PROTOCOL) {
621 #ifdef DEBUG_USB_HOST
622  Notify(PSTR("\r\nNot a valid protocol mode. Using Boot protocol instead."), 0x80);
623 #endif
624  protocolMode = USB_HID_BOOT_PROTOCOL; // Use Boot Protocol by default
625  }
626  uint8_t command = 0x70 | protocolMode; // Set Protocol, see Bluetooth HID specs page 33
627  pBtd->L2CAP_Command(hci_handle, &command, 1, control_scid[0], control_scid[1]);
628 }
629 
630 void BTHID::setLeds(uint8_t data) {
631  uint8_t buf[3];
632  buf[0] = 0xA2; // HID BT DATA_request (0xA0) | Report Type (Output 0x02)
633  buf[1] = 0x01; // Report ID
634  buf[2] = data;
636 }
#define L2CAP_FLAG_CONNECTION_INTERRUPT_REQUEST
Definition: BTD.h:153
#define L2CAP_FLAG_CONFIG_CONTROL_SUCCESS
Definition: BTD.h:148
#define L2CAP_FLAG_CONNECTION_SDP_REQUEST
Definition: BTD.h:159
#define HID_CTRL_PSM
Definition: BTD.h:193
#define L2CAP_WAIT
Definition: BTD.h:114
#define L2CAP_SDP_SUCCESS
Definition: BTD.h:131
#define SUCCESSFUL
Definition: BTD.h:188
#define SDP_SERVICE_ATTRIBUTE_RESPONSE
Definition: BTD.h:200
#define L2CAP_CMD_INFORMATION_REQUEST
Definition: BTD.h:183
#define SDP_PSM
Definition: BTD.h:191
#define L2CAP_FLAG_DISCONNECT_CONTROL_RESPONSE
Definition: BTD.h:150
#define SDP_SERVICE_ATTRIBUTE_REQUEST
Definition: BTD.h:199
#define L2CAP_FLAG_CONFIG_INTERRUPT_SUCCESS
Definition: BTD.h:154
#define L2CAP_FLAG_CONTROL_CONNECTED
Definition: BTD.h:149
#define L2CAP_CMD_DISCONNECT_REQUEST
Definition: BTD.h:181
#define L2CAP_CMD_CONFIG_REQUEST
Definition: BTD.h:179
#define HID_INTR_PSM
Definition: BTD.h:194
#define L2CAP_CMD_DISCONNECT_RESPONSE
Definition: BTD.h:182
#define l2cap_check_flag(flag)
Definition: BTD.h:171
#define l2cap_set_flag(flag)
Definition: BTD.h:172
#define SDP_SERVICE_SEARCH_REQUEST
Definition: BTD.h:197
#define L2CAP_CONTROL_CONNECT_REQUEST
Definition: BTD.h:118
#define L2CAP_CMD_COMMAND_REJECT
Definition: BTD.h:176
#define L2CAP_SDP_WAIT
Definition: BTD.h:130
#define L2CAP_INTERRUPT_CONFIG_REQUEST
Definition: BTD.h:126
#define L2CAP_FLAG_CONFIG_SDP_SUCCESS
Definition: BTD.h:160
#define L2CAP_CMD_CONFIG_RESPONSE
Definition: BTD.h:180
#define SDP_SERVICE_SEARCH_ATTRIBUTE_REQUEST
Definition: BTD.h:201
#define L2CAP_FLAG_CONNECTION_CONTROL_REQUEST
Definition: BTD.h:147
#define PENDING
Definition: BTD.h:187
#define L2CAP_CONTROL_DISCONNECT
Definition: BTD.h:121
#define L2CAP_CONTROL_CONFIG_REQUEST
Definition: BTD.h:119
#define L2CAP_FLAG_DISCONNECT_SDP_REQUEST
Definition: BTD.h:161
#define L2CAP_FLAG_INTERRUPT_CONNECTED
Definition: BTD.h:155
#define L2CAP_INTERRUPT_DISCONNECT
Definition: BTD.h:127
#define l2cap_clear_flag(flag)
Definition: BTD.h:173
#define L2CAP_CONTROL_SUCCESS
Definition: BTD.h:120
#define L2CAP_CMD_CONNECTION_REQUEST
Definition: BTD.h:177
#define L2CAP_INTERRUPT_SETUP
Definition: BTD.h:124
#define L2CAP_FLAG_DISCONNECT_INTERRUPT_RESPONSE
Definition: BTD.h:156
#define SDP_SERVICE_SEARCH_ATTRIBUTE_RESPONSE
Definition: BTD.h:202
#define L2CAP_DISCONNECT_RESPONSE
Definition: BTD.h:137
#define L2CAP_FLAG_DISCONNECT_RESPONSE
Definition: BTD.h:168
#define L2CAP_DONE
Definition: BTD.h:115
#define SDP_SERVICE_SEARCH_RESPONSE
Definition: BTD.h:198
#define L2CAP_CMD_CONNECTION_RESPONSE
Definition: BTD.h:178
#define L2CAP_INTERRUPT_CONNECT_REQUEST
Definition: BTD.h:125
#define MOUSE_PARSER_ID
Definition: BTHID.h:25
#define KEYBOARD_PARSER_ID
Definition: BTHID.h:24
#define NUM_PARSERS
Definition: BTHID.h:26
Definition: BTD.h:222
bool l2capConnectionClaimed
Definition: BTD.h:471
void hci_disconnect(uint16_t handle)
Definition: BTD.cpp:1404
const char * btdPin
Definition: BTD.h:480
void l2cap_disconnection_response(uint16_t handle, uint8_t rxid, uint8_t *dcid, uint8_t *scid)
Definition: BTD.cpp:1559
bool pairWithHIDDevice
Definition: BTD.h:524
void l2cap_connection_request(uint16_t handle, uint8_t rxid, uint8_t *scid, uint16_t psm)
Definition: BTD.cpp:1480
bool incomingHIDDevice
Definition: BTD.h:522
void l2cap_config_response(uint16_t handle, uint8_t rxid, uint8_t *scid)
Definition: BTD.cpp:1527
void l2cap_connection_response(uint16_t handle, uint8_t rxid, uint8_t *dcid, uint8_t *scid, uint8_t result)
Definition: BTD.cpp:1493
void l2cap_information_response(uint16_t handle, uint8_t rxid, uint8_t infoTypeLow, uint8_t infoTypeHigh)
Definition: BTD.cpp:1572
uint16_t hci_handle
Definition: BTD.h:485
void L2CAP_Command(uint16_t handle, uint8_t *data, uint8_t nbytes, uint8_t channelLow=0x01, uint8_t channelHigh=0x00)
Definition: BTD.cpp:1452
void l2cap_config_request(uint16_t handle, uint8_t rxid, uint8_t *dcid)
Definition: BTD.cpp:1510
void l2cap_disconnection_request(uint16_t handle, uint8_t rxid, uint8_t *dcid, uint8_t *scid)
Definition: BTD.cpp:1546
bool connectToHIDDevice
Definition: BTD.h:518
bool sdpConnectionClaimed
Definition: BTD.h:473
uint8_t sdp_scid[2]
Definition: BTHID.h:161
uint8_t interrupt_scid[2]
Definition: BTHID.h:158
virtual void ParseBTHIDData(uint8_t len, uint8_t *buf)
Definition: BTHID.h:134
BTHID(BTD *p, bool pair=false, const char *pin="0000")
Definition: BTHID.cpp:23
void ACLData(uint8_t *ACLData)
Definition: BTHID.cpp:63
void Run()
Definition: BTHID.cpp:560
void onInit()
Definition: BTHID.h:121
bool connected
Definition: BTHID.h:88
virtual void ResetBTHID()
Definition: BTHID.h:149
uint8_t control_scid[2]
Definition: BTHID.h:155
virtual void ParseBTHIDControlData(uint8_t len, uint8_t *buf)
Definition: BTHID.h:141
void setLeds(struct KBDLEDS data)
Definition: BTHID.h:81
void disconnect()
Definition: BTHID.cpp:53
uint8_t l2cap_sdp_state
Definition: BTHID.h:160
void Reset()
Definition: BTHID.cpp:43
void pair(void)
Definition: BTHID.h:91
bool checkHciHandle(uint8_t *buf, uint16_t handle)
Definition: BTD.h:639
uint16_t hci_handle
Definition: BTD.h:650
uint32_t l2cap_event_flag
Definition: BTD.h:653
BTD * pBtd
Definition: BTD.h:647
uint8_t identifier
Definition: BTD.h:656
virtual void Parse(USBHID *hid, bool is_rpt_id, uint8_t len, uint8_t *buf)=0
Definition: usbhid.h:143
#define Notify(...)
Definition: message.h:51
#define HID_RPT_PROTOCOL
Definition: usbhid.h:83
#define USB_HID_BOOT_PROTOCOL
Definition: usbhid.h:82
#define PSTR(str)