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_THDR_DATA_INPUT
340  uint16_t length = ((uint16_t)l2capinbuf[5] << 8 | l2capinbuf[4]);
341  ParseBTHIDData((uint8_t)(length - 1), &l2capinbuf[9]);
342 
343  switch(l2capinbuf[9]) {
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  }
361  } else if(l2capinbuf[6] == control_dcid[0] && l2capinbuf[7] == control_dcid[1]) { // l2cap_control
362 #ifdef PRINTREPORT
363  Notify(PSTR("\r\nL2CAP Control: "), 0x80);
364  for(uint16_t i = 0; i < ((uint16_t)l2capinbuf[5] << 8 | l2capinbuf[4]); i++) {
365  D_PrintHex<uint8_t > (l2capinbuf[i + 8], 0x80);
366  Notify(PSTR(" "), 0x80);
367  }
368 #endif
369  }
370 #ifdef EXTRADEBUG
371  else {
372  Notify(PSTR("\r\nUnsupported L2CAP Data - Channel ID: "), 0x80);
373  D_PrintHex<uint8_t > (l2capinbuf[7], 0x80);
374  Notify(PSTR(" "), 0x80);
375  D_PrintHex<uint8_t > (l2capinbuf[6], 0x80);
376 
377  Notify(PSTR("\r\nData: "), 0x80);
378  Notify(PSTR("\r\n"), 0x80);
379  for(uint16_t i = 0; i < ((uint16_t)l2capinbuf[5] << 8 | l2capinbuf[4]); i++) {
380  D_PrintHex<uint8_t > (l2capinbuf[i + 8], 0x80);
381  Notify(PSTR(" "), 0x80);
382  }
383  }
384 #endif
385  SDP_task();
386  L2CAP_task();
387  }
388 }
389 
390 void BTHID::SDP_task() {
391  switch(l2cap_sdp_state) {
392  case L2CAP_SDP_WAIT:
395 #ifdef DEBUG_USB_HOST
396  Notify(PSTR("\r\nSDP Incoming Connection Request"), 0x80);
397 #endif
399  delay(1);
401  identifier++;
402  delay(1);
407  SDPConnected = false;
408 #ifdef DEBUG_USB_HOST
409  Notify(PSTR("\r\nDisconnected SDP Channel"), 0x80);
410 #endif
412  }
413  break;
414  case L2CAP_SDP_SUCCESS:
417 #ifdef DEBUG_USB_HOST
418  Notify(PSTR("\r\nSDP Successfully Configured"), 0x80);
419 #endif
420  SDPConnected = true;
422  }
423  break;
424 
425  case L2CAP_DISCONNECT_RESPONSE: // This is for both disconnection response from the RFCOMM and SDP channel if they were connected
427 #ifdef DEBUG_USB_HOST
428  Notify(PSTR("\r\nDisconnected L2CAP Connection"), 0x80);
429 #endif
431  hci_handle = -1; // Reset handle
432  Reset();
433  }
434  break;
435  }
436 }
437 
438 void BTHID::L2CAP_task() {
439  switch(l2cap_state) {
440  /* These states are used if the HID device is the host */
443 #ifdef DEBUG_USB_HOST
444  Notify(PSTR("\r\nHID Control Successfully Configured"), 0x80);
445 #endif
446  setProtocol(); // Set protocol before establishing HID interrupt channel
447  l2cap_state = L2CAP_INTERRUPT_SETUP;
448  }
449  break;
450 
453 #ifdef DEBUG_USB_HOST
454  Notify(PSTR("\r\nHID Interrupt Incoming Connection Request"), 0x80);
455 #endif
457  delay(1);
459  identifier++;
460  delay(1);
462 
463  l2cap_state = L2CAP_INTERRUPT_CONFIG_REQUEST;
464  }
465  break;
466 
467  /* These states are used if the Arduino is the host */
470 #ifdef DEBUG_USB_HOST
471  Notify(PSTR("\r\nSend HID Control Config Request"), 0x80);
472 #endif
473  identifier++;
475  l2cap_state = L2CAP_CONTROL_CONFIG_REQUEST;
476  }
477  break;
478 
481  setProtocol(); // Set protocol before establishing HID interrupt channel
482  delay(1); // Short delay between commands - just to be sure
483 #ifdef DEBUG_USB_HOST
484  Notify(PSTR("\r\nSend HID Interrupt Connection Request"), 0x80);
485 #endif
486  identifier++;
488  l2cap_state = L2CAP_INTERRUPT_CONNECT_REQUEST;
489  }
490  break;
491 
494 #ifdef DEBUG_USB_HOST
495  Notify(PSTR("\r\nSend HID Interrupt Config Request"), 0x80);
496 #endif
497  identifier++;
499  l2cap_state = L2CAP_INTERRUPT_CONFIG_REQUEST;
500  }
501  break;
502 
504  if(l2cap_check_flag(L2CAP_FLAG_CONFIG_INTERRUPT_SUCCESS)) { // Now the HID channels is established
505 #ifdef DEBUG_USB_HOST
506  Notify(PSTR("\r\nHID Channels Established"), 0x80);
507 #endif
508  pBtd->connectToHIDDevice = false;
509  pBtd->pairWithHIDDevice = false;
510  connected = true;
511  onInit();
512  l2cap_state = L2CAP_DONE;
513  }
514  break;
515 
516  case L2CAP_DONE:
517  break;
518 
521 #ifdef DEBUG_USB_HOST
522  Notify(PSTR("\r\nDisconnected Interrupt Channel"), 0x80);
523 #endif
524  identifier++;
526  l2cap_state = L2CAP_CONTROL_DISCONNECT;
527  }
528  break;
529 
532 #ifdef DEBUG_USB_HOST
533  Notify(PSTR("\r\nDisconnected Control Channel"), 0x80);
534 #endif
536  hci_handle = -1; // Reset handle
537  l2cap_event_flag = 0; // Reset flags
538  l2cap_state = L2CAP_WAIT;
539  }
540  break;
541  }
542 }
543 
544 void BTHID::Run() {
545  switch(l2cap_state) {
546  case L2CAP_WAIT:
547  if(pBtd->connectToHIDDevice && !pBtd->l2capConnectionClaimed && !connected && !activeConnection) {
549  activeConnection = true;
550 #ifdef DEBUG_USB_HOST
551  Notify(PSTR("\r\nSend HID Control Connection Request"), 0x80);
552 #endif
553  hci_handle = pBtd->hci_handle; // Store the HCI Handle for the connection
554  l2cap_event_flag = 0; // Reset flags
555  identifier = 0;
557  l2cap_state = L2CAP_CONTROL_CONNECT_REQUEST;
559 #ifdef DEBUG_USB_HOST
560  Notify(PSTR("\r\nHID Control Incoming Connection Request"), 0x80);
561 #endif
563  delay(1);
565  identifier++;
566  delay(1);
568  l2cap_state = L2CAP_CONTROL_SUCCESS;
569  }
570  break;
571  }
572 }
573 
574 void BTHID::SDP_Command(uint8_t* data, uint8_t nbytes) { // See page 223 in the Bluetooth specs
575  pBtd->L2CAP_Command(hci_handle, data, nbytes, sdp_scid[0], sdp_scid[1]);
576 }
577 
578 void BTHID::serviceNotSupported(uint8_t transactionIDHigh, uint8_t transactionIDLow) { // See page 235 in the Bluetooth specs
579  l2capoutbuf[0] = SDP_SERVICE_SEARCH_ATTRIBUTE_RESPONSE;
580  l2capoutbuf[1] = transactionIDHigh;
581  l2capoutbuf[2] = transactionIDLow;
582  l2capoutbuf[3] = 0x00; // MSB Parameter Length
583  l2capoutbuf[4] = 0x05; // LSB Parameter Length = 5
584  l2capoutbuf[5] = 0x00; // MSB AttributeListsByteCount
585  l2capoutbuf[6] = 0x02; // LSB AttributeListsByteCount = 2
586 
587  /* Attribute ID/Value Sequence: */
588  l2capoutbuf[7] = 0x35; // Data element sequence - length in next byte
589  l2capoutbuf[8] = 0x00; // Length = 0
590  l2capoutbuf[9] = 0x00; // No continuation state
591 
592  SDP_Command(l2capoutbuf, 10);
593 }
594 
595 /************************************************************/
596 /* HID Commands */
597 
598 /************************************************************/
599 void BTHID::setProtocol() {
600 #ifdef DEBUG_USB_HOST
601  Notify(PSTR("\r\nSet protocol mode: "), 0x80);
602  D_PrintHex<uint8_t > (protocolMode, 0x80);
603 #endif
604  if (protocolMode != USB_HID_BOOT_PROTOCOL && protocolMode != HID_RPT_PROTOCOL) {
605 #ifdef DEBUG_USB_HOST
606  Notify(PSTR("\r\nNot a valid protocol mode. Using Boot protocol instead."), 0x80);
607 #endif
608  protocolMode = USB_HID_BOOT_PROTOCOL; // Use Boot Protocol by default
609  }
610  uint8_t command = 0x70 | protocolMode; // Set Protocol, see Bluetooth HID specs page 33
611  pBtd->L2CAP_Command(hci_handle, &command, 1, control_scid[0], control_scid[1]);
612 }
613 
614 void BTHID::setLeds(uint8_t data) {
615  uint8_t buf[3];
616  buf[0] = 0xA2; // HID BT DATA_request (0xA0) | Report Type (Output 0x02)
617  buf[1] = 0x01; // Report ID
618  buf[2] = data;
620 }
#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:142
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:544
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:133
#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:139
#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
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:145
#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:144
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