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  uint16_t length = ((uint16_t)l2capinbuf[5] << 8 | l2capinbuf[4]);
341  ParseBTHIDData((uint8_t)(length - 1), &l2capinbuf[9]); // First byte will be the report ID
342 
343  switch(l2capinbuf[9]) { // Report ID
344  case 0x01: // Keyboard or Joystick events
345  if(pRptParser[KEYBOARD_PARSER_ID])
346  pRptParser[KEYBOARD_PARSER_ID]->Parse(reinterpret_cast<USBHID *>(this), 0, (uint8_t)(length - 2), &l2capinbuf[10]); // Use reinterpret_cast again to extract the instance
347  break;
348 
349  case 0x02: // Mouse events
350  if(pRptParser[MOUSE_PARSER_ID])
351  pRptParser[MOUSE_PARSER_ID]->Parse(reinterpret_cast<USBHID *>(this), 0, (uint8_t)(length - 2), &l2capinbuf[10]); // Use reinterpret_cast again to extract the instance
352  break;
353 #ifdef EXTRADEBUG
354  default:
355  Notify(PSTR("\r\nUnknown Report type: "), 0x80);
356  D_PrintHex<uint8_t > (l2capinbuf[9], 0x80);
357  break;
358 #endif
359  }
360  } else {
361 #ifdef EXTRADEBUG
362  Notify(PSTR("\r\nUnhandled L2CAP interrupt report: "), 0x80);
363  D_PrintHex<uint8_t > (l2capinbuf[8], 0x80);
364 #endif
365  }
366  } else if(l2capinbuf[6] == control_dcid[0] && l2capinbuf[7] == control_dcid[1]) { // l2cap_control
367 #ifdef PRINTREPORT
368  Notify(PSTR("\r\nL2CAP Control: "), 0x80);
369  for(uint16_t i = 0; i < ((uint16_t)l2capinbuf[5] << 8 | l2capinbuf[4]); i++) {
370  D_PrintHex<uint8_t > (l2capinbuf[i + 8], 0x80);
371  Notify(PSTR(" "), 0x80);
372  }
373 #endif
374  if(l2capinbuf[8] == 0xA3) { // HID BT DATA (0xA0) | Report Type (Feature 0x03)
375  uint16_t length = ((uint16_t)l2capinbuf[5] << 8 | l2capinbuf[4]);
376  ParseBTHIDControlData((uint8_t)(length - 1), &l2capinbuf[9]); // First byte will be the report ID
377  } else {
378 #ifdef EXTRADEBUG
379  Notify(PSTR("\r\nUnhandled L2CAP control report: "), 0x80);
380  D_PrintHex<uint8_t > (l2capinbuf[8], 0x80);
381 #endif
382  }
383  }
384 #ifdef EXTRADEBUG
385  else {
386  Notify(PSTR("\r\nUnsupported L2CAP Data - Channel ID: "), 0x80);
387  D_PrintHex<uint8_t > (l2capinbuf[7], 0x80);
388  Notify(PSTR(" "), 0x80);
389  D_PrintHex<uint8_t > (l2capinbuf[6], 0x80);
390 
391  Notify(PSTR("\r\nData: "), 0x80);
392  Notify(PSTR("\r\n"), 0x80);
393  for(uint16_t i = 0; i < ((uint16_t)l2capinbuf[5] << 8 | l2capinbuf[4]); i++) {
394  D_PrintHex<uint8_t > (l2capinbuf[i + 8], 0x80);
395  Notify(PSTR(" "), 0x80);
396  }
397  }
398 #endif
399  SDP_task();
400  L2CAP_task();
401  }
402 }
403 
404 void BTHID::SDP_task() {
405  switch(l2cap_sdp_state) {
406  case L2CAP_SDP_WAIT:
409 #ifdef DEBUG_USB_HOST
410  Notify(PSTR("\r\nSDP Incoming Connection Request"), 0x80);
411 #endif
413  delay(1);
415  identifier++;
416  delay(1);
421  SDPConnected = false;
422 #ifdef DEBUG_USB_HOST
423  Notify(PSTR("\r\nDisconnected SDP Channel"), 0x80);
424 #endif
426  }
427  break;
428  case L2CAP_SDP_SUCCESS:
431 #ifdef DEBUG_USB_HOST
432  Notify(PSTR("\r\nSDP Successfully Configured"), 0x80);
433 #endif
434  SDPConnected = true;
436  }
437  break;
438 
439  case L2CAP_DISCONNECT_RESPONSE: // This is for both disconnection response from the RFCOMM and SDP channel if they were connected
441 #ifdef DEBUG_USB_HOST
442  Notify(PSTR("\r\nDisconnected L2CAP Connection"), 0x80);
443 #endif
445  hci_handle = -1; // Reset handle
446  Reset();
447  }
448  break;
449  }
450 }
451 
452 void BTHID::L2CAP_task() {
453  switch(l2cap_state) {
454  /* These states are used if the HID device is the host */
457 #ifdef DEBUG_USB_HOST
458  Notify(PSTR("\r\nHID Control Successfully Configured"), 0x80);
459 #endif
460  setProtocol(); // Set protocol before establishing HID interrupt channel
461  l2cap_state = L2CAP_INTERRUPT_SETUP;
462  }
463  break;
464 
467 #ifdef DEBUG_USB_HOST
468  Notify(PSTR("\r\nHID Interrupt Incoming Connection Request"), 0x80);
469 #endif
471  delay(1);
473  identifier++;
474  delay(1);
476 
477  l2cap_state = L2CAP_INTERRUPT_CONFIG_REQUEST;
478  }
479  break;
480 
481  /* These states are used if the Arduino is the host */
484 #ifdef DEBUG_USB_HOST
485  Notify(PSTR("\r\nSend HID Control Config Request"), 0x80);
486 #endif
487  identifier++;
489  l2cap_state = L2CAP_CONTROL_CONFIG_REQUEST;
490  }
491  break;
492 
495  setProtocol(); // Set protocol before establishing HID interrupt channel
496  delay(1); // Short delay between commands - just to be sure
497 #ifdef DEBUG_USB_HOST
498  Notify(PSTR("\r\nSend HID Interrupt Connection Request"), 0x80);
499 #endif
500  identifier++;
502  l2cap_state = L2CAP_INTERRUPT_CONNECT_REQUEST;
503  }
504  break;
505 
508 #ifdef DEBUG_USB_HOST
509  Notify(PSTR("\r\nSend HID Interrupt Config Request"), 0x80);
510 #endif
511  identifier++;
513  l2cap_state = L2CAP_INTERRUPT_CONFIG_REQUEST;
514  }
515  break;
516 
518  if(l2cap_check_flag(L2CAP_FLAG_CONFIG_INTERRUPT_SUCCESS)) { // Now the HID channels is established
519 #ifdef DEBUG_USB_HOST
520  Notify(PSTR("\r\nHID Channels Established"), 0x80);
521 #endif
522  pBtd->connectToHIDDevice = false;
523  pBtd->pairWithHIDDevice = false;
524  connected = true;
525  onInit();
526  l2cap_state = L2CAP_DONE;
527  }
528  break;
529 
530  case L2CAP_DONE:
531  break;
532 
535 #ifdef DEBUG_USB_HOST
536  Notify(PSTR("\r\nDisconnected Interrupt Channel"), 0x80);
537 #endif
538  identifier++;
540  l2cap_state = L2CAP_CONTROL_DISCONNECT;
541  }
542  break;
543 
546 #ifdef DEBUG_USB_HOST
547  Notify(PSTR("\r\nDisconnected Control Channel"), 0x80);
548 #endif
550  hci_handle = -1; // Reset handle
551  l2cap_event_flag = 0; // Reset flags
552  l2cap_state = L2CAP_WAIT;
553  }
554  break;
555  }
556 }
557 
558 void BTHID::Run() {
559  switch(l2cap_state) {
560  case L2CAP_WAIT:
561  if(pBtd->connectToHIDDevice && !pBtd->l2capConnectionClaimed && !connected && !activeConnection) {
563  activeConnection = true;
564 #ifdef DEBUG_USB_HOST
565  Notify(PSTR("\r\nSend HID Control Connection Request"), 0x80);
566 #endif
567  hci_handle = pBtd->hci_handle; // Store the HCI Handle for the connection
568  l2cap_event_flag = 0; // Reset flags
569  identifier = 0;
571  l2cap_state = L2CAP_CONTROL_CONNECT_REQUEST;
573 #ifdef DEBUG_USB_HOST
574  Notify(PSTR("\r\nHID Control Incoming Connection Request"), 0x80);
575 #endif
577  delay(1);
579  identifier++;
580  delay(1);
582  l2cap_state = L2CAP_CONTROL_SUCCESS;
583  }
584  break;
585  }
586 }
587 
588 void BTHID::SDP_Command(uint8_t* data, uint8_t nbytes) { // See page 223 in the Bluetooth specs
589  pBtd->L2CAP_Command(hci_handle, data, nbytes, sdp_scid[0], sdp_scid[1]);
590 }
591 
592 void BTHID::serviceNotSupported(uint8_t transactionIDHigh, uint8_t transactionIDLow) { // See page 235 in the Bluetooth specs
593  l2capoutbuf[0] = SDP_SERVICE_SEARCH_ATTRIBUTE_RESPONSE;
594  l2capoutbuf[1] = transactionIDHigh;
595  l2capoutbuf[2] = transactionIDLow;
596  l2capoutbuf[3] = 0x00; // MSB Parameter Length
597  l2capoutbuf[4] = 0x05; // LSB Parameter Length = 5
598  l2capoutbuf[5] = 0x00; // MSB AttributeListsByteCount
599  l2capoutbuf[6] = 0x02; // LSB AttributeListsByteCount = 2
600 
601  /* Attribute ID/Value Sequence: */
602  l2capoutbuf[7] = 0x35; // Data element sequence - length in next byte
603  l2capoutbuf[8] = 0x00; // Length = 0
604  l2capoutbuf[9] = 0x00; // No continuation state
605 
606  SDP_Command(l2capoutbuf, 10);
607 }
608 
609 /************************************************************/
610 /* HID Commands */
611 
612 /************************************************************/
613 void BTHID::setProtocol() {
614 #ifdef DEBUG_USB_HOST
615  Notify(PSTR("\r\nSet protocol mode: "), 0x80);
616  D_PrintHex<uint8_t > (protocolMode, 0x80);
617 #endif
618  if (protocolMode != USB_HID_BOOT_PROTOCOL && protocolMode != HID_RPT_PROTOCOL) {
619 #ifdef DEBUG_USB_HOST
620  Notify(PSTR("\r\nNot a valid protocol mode. Using Boot protocol instead."), 0x80);
621 #endif
622  protocolMode = USB_HID_BOOT_PROTOCOL; // Use Boot Protocol by default
623  }
624  uint8_t command = 0x70 | protocolMode; // Set Protocol, see Bluetooth HID specs page 33
625  pBtd->L2CAP_Command(hci_handle, &command, 1, control_scid[0], control_scid[1]);
626 }
627 
628 void BTHID::setLeds(uint8_t data) {
629  uint8_t buf[3];
630  buf[0] = 0xA2; // HID BT DATA_request (0xA0) | Report Type (Output 0x02)
631  buf[1] = 0x01; // Report ID
632  buf[2] = data;
634 }
#define L2CAP_FLAG_DISCONNECT_CONTROL_RESPONSE
Definition: BTD.h:149
#define L2CAP_FLAG_CONFIG_INTERRUPT_SUCCESS
Definition: BTD.h:153
#define L2CAP_INTERRUPT_CONFIG_REQUEST
Definition: BTD.h:125
#define L2CAP_INTERRUPT_SETUP
Definition: BTD.h:123
void l2cap_connection_response(uint16_t handle, uint8_t rxid, uint8_t *dcid, uint8_t *scid, uint8_t result)
Definition: BTD.cpp:1488
#define SUCCESSFUL
Definition: BTD.h:187
void ACLData(uint8_t *ACLData)
Definition: BTHID.cpp:63
void l2cap_connection_request(uint16_t handle, uint8_t rxid, uint8_t *scid, uint16_t psm)
Definition: BTD.cpp:1475
#define L2CAP_FLAG_CONNECTION_INTERRUPT_REQUEST
Definition: BTD.h:152
bool sdpConnectionClaimed
Definition: BTD.h:472
Definition: BTD.h:221
void l2cap_disconnection_request(uint16_t handle, uint8_t rxid, uint8_t *dcid, uint8_t *scid)
Definition: BTD.cpp:1541
uint8_t interrupt_scid[2]
Definition: BTHID.h:149
uint8_t identifier
Definition: BTD.h:655
#define L2CAP_FLAG_CONFIG_SDP_SUCCESS
Definition: BTD.h:159
#define SDP_SERVICE_ATTRIBUTE_REQUEST
Definition: BTD.h:198
bool connected
Definition: BTHID.h:88
#define L2CAP_SDP_SUCCESS
Definition: BTD.h:130
void Run()
Definition: BTHID.cpp:558
const char * btdPin
Definition: BTD.h:479
#define L2CAP_DONE
Definition: BTD.h:114
#define L2CAP_CONTROL_SUCCESS
Definition: BTD.h:119
#define SDP_SERVICE_SEARCH_ATTRIBUTE_REQUEST
Definition: BTD.h:200
#define L2CAP_WAIT
Definition: BTD.h:113
virtual void ResetBTHID()
Definition: BTHID.h:140
#define L2CAP_CMD_INFORMATION_REQUEST
Definition: BTD.h:182
void Reset()
Definition: BTHID.cpp:43
#define SDP_SERVICE_SEARCH_RESPONSE
Definition: BTD.h:197
#define L2CAP_CONTROL_CONFIG_REQUEST
Definition: BTD.h:118
#define SDP_PSM
Definition: BTD.h:190
void l2cap_disconnection_response(uint16_t handle, uint8_t rxid, uint8_t *dcid, uint8_t *scid)
Definition: BTD.cpp:1554
uint8_t control_scid[2]
Definition: BTHID.h:146
#define Notify(...)
Definition: message.h:51
bool connectToHIDDevice
Definition: BTD.h:517
#define L2CAP_CONTROL_CONNECT_REQUEST
Definition: BTD.h:117
#define HID_CTRL_PSM
Definition: BTD.h:192
bool incomingHIDDevice
Definition: BTD.h:521
bool pairWithHIDDevice
Definition: BTD.h:523
#define MOUSE_PARSER_ID
Definition: BTHID.h:25
virtual void ParseBTHIDControlData(uint8_t len, uint8_t *buf)
Definition: BTHID.h:132
uint16_t hci_handle
Definition: BTD.h:484
#define SDP_SERVICE_SEARCH_REQUEST
Definition: BTD.h:196
void hci_disconnect(uint16_t handle)
Definition: BTD.cpp:1399
#define L2CAP_FLAG_DISCONNECT_INTERRUPT_RESPONSE
Definition: BTD.h:155
void disconnect()
Definition: BTHID.cpp:53
virtual void ParseBTHIDData(uint8_t len, uint8_t *buf)
Definition: BTHID.h:125
#define L2CAP_FLAG_DISCONNECT_SDP_REQUEST
Definition: BTD.h:160
#define l2cap_check_flag(flag)
Definition: BTD.h:170
#define L2CAP_CMD_CONFIG_REQUEST
Definition: BTD.h:178
#define L2CAP_FLAG_CONTROL_CONNECTED
Definition: BTD.h:148
#define PSTR(str)
#define L2CAP_CMD_DISCONNECT_REQUEST
Definition: BTD.h:180
#define L2CAP_CONTROL_DISCONNECT
Definition: BTD.h:120
#define L2CAP_FLAG_CONNECTION_CONTROL_REQUEST
Definition: BTD.h:146
#define L2CAP_SDP_WAIT
Definition: BTD.h:129
BTD * pBtd
Definition: BTD.h:646
#define HID_INTR_PSM
Definition: BTD.h:193
bool l2capConnectionClaimed
Definition: BTD.h:470
#define L2CAP_FLAG_DISCONNECT_RESPONSE
Definition: BTD.h:167
#define L2CAP_CMD_DISCONNECT_RESPONSE
Definition: BTD.h:181
void l2cap_information_response(uint16_t handle, uint8_t rxid, uint8_t infoTypeLow, uint8_t infoTypeHigh)
Definition: BTD.cpp:1567
#define L2CAP_CMD_CONNECTION_RESPONSE
Definition: BTD.h:177
#define L2CAP_CMD_CONFIG_RESPONSE
Definition: BTD.h:179
#define SDP_SERVICE_SEARCH_ATTRIBUTE_RESPONSE
Definition: BTD.h:201
void setLeds(struct KBDLEDS data)
Definition: BTHID.h:81
uint16_t hci_handle
Definition: BTD.h:649
uint8_t sdp_scid[2]
Definition: BTHID.h:152
#define NUM_PARSERS
Definition: BTHID.h:26
#define KEYBOARD_PARSER_ID
Definition: BTHID.h:24
#define L2CAP_FLAG_CONNECTION_SDP_REQUEST
Definition: BTD.h:158
#define USB_HID_BOOT_PROTOCOL
Definition: usbhid.h:82
uint32_t l2cap_event_flag
Definition: BTD.h:652
void onInit()
Definition: BTHID.h:112
#define l2cap_clear_flag(flag)
Definition: BTD.h:172
#define L2CAP_DISCONNECT_RESPONSE
Definition: BTD.h:136
void L2CAP_Command(uint16_t handle, uint8_t *data, uint8_t nbytes, uint8_t channelLow=0x01, uint8_t channelHigh=0x00)
Definition: BTD.cpp:1447
void l2cap_config_response(uint16_t handle, uint8_t rxid, uint8_t *scid)
Definition: BTD.cpp:1522
#define PENDING
Definition: BTD.h:186
#define L2CAP_FLAG_INTERRUPT_CONNECTED
Definition: BTD.h:154
#define l2cap_set_flag(flag)
Definition: BTD.h:171
void l2cap_config_request(uint16_t handle, uint8_t rxid, uint8_t *dcid)
Definition: BTD.cpp:1505
#define L2CAP_FLAG_CONFIG_CONTROL_SUCCESS
Definition: BTD.h:147
#define L2CAP_CMD_CONNECTION_REQUEST
Definition: BTD.h:176
virtual void Parse(USBHID *hid, bool is_rpt_id, uint8_t len, uint8_t *buf)=0
BTHID(BTD *p, bool pair=false, const char *pin="0000")
Definition: BTHID.cpp:23
uint8_t l2cap_sdp_state
Definition: BTHID.h:151
bool checkHciHandle(uint8_t *buf, uint16_t handle)
Definition: BTD.h:638
#define L2CAP_INTERRUPT_CONNECT_REQUEST
Definition: BTD.h:124
#define HID_RPT_PROTOCOL
Definition: usbhid.h:83
void pair(void)
Definition: BTHID.h:91
#define L2CAP_INTERRUPT_DISCONNECT
Definition: BTD.h:126
#define SDP_SERVICE_ATTRIBUTE_RESPONSE
Definition: BTD.h:199
#define L2CAP_CMD_COMMAND_REJECT
Definition: BTD.h:175