diff --git a/_b_t_h_i_d_8cpp_source.html b/_b_t_h_i_d_8cpp_source.html index 08e7cbc7..2d5eacab 100644 --- a/_b_t_h_i_d_8cpp_source.html +++ b/_b_t_h_i_d_8cpp_source.html @@ -63,7 +63,7 @@ $(function() {
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
+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_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
@@ -75,26 +75,26 @@ $(function() {
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 interrupt_scid[2]
Definition: BTHID.h:158
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
+
void Run()
Definition: BTHID.cpp:560
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
+
virtual void ResetBTHID()
Definition: BTHID.h:149
#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
+
uint8_t control_scid[2]
Definition: BTHID.h:155
#define Notify(...)
Definition: message.h:51
bool connectToHIDDevice
Definition: BTD.h:517
#define L2CAP_CONTROL_CONNECT_REQUEST
Definition: BTD.h:117
@@ -102,7 +102,7 @@ $(function() {
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
+
virtual void ParseBTHIDControlData(uint8_t len, uint8_t *buf)
Definition: BTHID.h:141
uint16_t hci_handle
Definition: BTD.h:484
#define SDP_SERVICE_SEARCH_REQUEST
Definition: BTD.h:196
@@ -110,7 +110,7 @@ $(function() {
#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
+
virtual void ParseBTHIDData(uint8_t len, uint8_t *buf)
Definition: BTHID.h:134
#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
@@ -131,13 +131,13 @@ $(function() {
#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
+
uint8_t sdp_scid[2]
Definition: BTHID.h:161
#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
+
void onInit()
Definition: BTHID.h:121
#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
@@ -150,7 +150,7 @@ $(function() {
#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
+
uint8_t l2cap_sdp_state
Definition: BTHID.h:160
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
diff --git a/_b_t_h_i_d_8h_source.html b/_b_t_h_i_d_8h_source.html index 7bbc038c..365ebdf8 100644 --- a/_b_t_h_i_d_8h_source.html +++ b/_b_t_h_i_d_8h_source.html @@ -63,36 +63,37 @@ $(function() {
BTHID.h
-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 #ifndef _bthid_h_
19 #define _bthid_h_
20 
21 #include "BTD.h"
22 #include "hidboot.h"
23 
24 #define KEYBOARD_PARSER_ID 0
25 #define MOUSE_PARSER_ID 1
26 #define NUM_PARSERS 2
27 
29 class BTHID : public BluetoothService {
30 public:
37  BTHID(BTD *p, bool pair = false, const char *pin = "0000");
38 
41  void disconnect();
50  if (id >= NUM_PARSERS)
51  return NULL;
52  return pRptParser[id];
53  };
54 
61  bool SetReportParser(uint8_t id, HIDReportParser *prs) {
62  if (id >= NUM_PARSERS)
63  return false;
64  pRptParser[id] = prs;
65  return true;
66  };
67 
72  void setProtocolMode(uint8_t mode) {
73  protocolMode = mode;
74  };
75 
81  void setLeds(struct KBDLEDS data) {
82  setLeds(*((uint8_t*)&data));
83  };
84  void setLeds(uint8_t data);
88  bool connected;
89 
91  void pair(void) {
92  if(pBtd)
93  pBtd->pairWithHID();
94  };
95 
96 protected:
102  void ACLData(uint8_t* ACLData);
104  void Run();
106  void Reset();
112  void onInit() {
113  if(pFuncOnInit)
114  pFuncOnInit(); // Call the user function
115  OnInitBTHID();
116  };
125  virtual void ParseBTHIDData(uint8_t len __attribute__((unused)), uint8_t *buf __attribute__((unused))) {
126  return;
127  };
132  virtual void ParseBTHIDControlData(uint8_t len __attribute__((unused)), uint8_t *buf __attribute__((unused))) {
133  return;
134  }
136  virtual void OnInitBTHID() {
137  return;
138  };
140  virtual void ResetBTHID() {
141  return;
142  }
146  uint8_t control_scid[2];
147 
149  uint8_t interrupt_scid[2];
150 
152  uint8_t sdp_scid[2]; // L2CAP source CID for SDP
153 
154 private:
155  HIDReportParser *pRptParser[NUM_PARSERS]; // Pointer to HIDReportParsers.
156 
157  uint8_t l2capoutbuf[BULK_MAXPKTSIZE]; // General purpose buffer for l2cap out data
158  void SDP_Command(uint8_t* data, uint8_t nbytes);
159  void serviceNotSupported(uint8_t transactionIDHigh, uint8_t transactionIDLow);
160 
162  void setProtocol();
163  uint8_t protocolMode;
164 
165  void SDP_task();
166  void L2CAP_task(); // L2CAP state machine
167 
168  bool activeConnection; // Used to indicate if it already has established a connection
169  bool SDPConnected;
170 
171  /* Variables used for L2CAP communication */
172  uint8_t control_dcid[2]; // L2CAP device CID for HID_Control - Always 0x0070
173  uint8_t interrupt_dcid[2]; // L2CAP device CID for HID_Interrupt - Always 0x0071
174  uint8_t sdp_dcid[2];
175  uint8_t l2cap_state;
176 };
177 #endif
+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 #ifndef _bthid_h_
19 #define _bthid_h_
20 
21 #include "BTD.h"
22 #include "hidboot.h"
23 
24 #define KEYBOARD_PARSER_ID 0
25 #define MOUSE_PARSER_ID 1
26 #define NUM_PARSERS 2
27 
29 class BTHID : public BluetoothService {
30 public:
37  BTHID(BTD *p, bool pair = false, const char *pin = "0000");
38 
41  void disconnect();
50  if (id >= NUM_PARSERS)
51  return NULL;
52  return pRptParser[id];
53  };
54 
61  bool SetReportParser(uint8_t id, HIDReportParser *prs) {
62  if (id >= NUM_PARSERS)
63  return false;
64  pRptParser[id] = prs;
65  return true;
66  };
67 
72  void setProtocolMode(uint8_t mode) {
73  protocolMode = mode;
74  };
75 
81  void setLeds(struct KBDLEDS data) {
82  setLeds(*((uint8_t*)&data));
83  };
84  void setLeds(uint8_t data);
88  bool connected;
89 
91  void pair(void) {
92  if(pBtd)
93  pBtd->pairWithHID();
94  };
95 
101  uint32_t getLastMessageTime() {
102  return lastBtDataInputIntMillis;
103  };
104 
105 protected:
111  void ACLData(uint8_t* ACLData);
113  void Run();
115  void Reset();
121  void onInit() {
122  if(pFuncOnInit)
123  pFuncOnInit(); // Call the user function
124  OnInitBTHID();
125  };
134  virtual void ParseBTHIDData(uint8_t len __attribute__((unused)), uint8_t *buf __attribute__((unused))) {
135  return;
136  };
141  virtual void ParseBTHIDControlData(uint8_t len __attribute__((unused)), uint8_t *buf __attribute__((unused))) {
142  return;
143  }
145  virtual void OnInitBTHID() {
146  return;
147  };
149  virtual void ResetBTHID() {
150  return;
151  }
155  uint8_t control_scid[2];
156 
158  uint8_t interrupt_scid[2];
159 
161  uint8_t sdp_scid[2]; // L2CAP source CID for SDP
162 
163 private:
164  HIDReportParser *pRptParser[NUM_PARSERS]; // Pointer to HIDReportParsers.
165 
166  uint8_t l2capoutbuf[BULK_MAXPKTSIZE]; // General purpose buffer for l2cap out data
167  void SDP_Command(uint8_t* data, uint8_t nbytes);
168  void serviceNotSupported(uint8_t transactionIDHigh, uint8_t transactionIDLow);
169 
171  void setProtocol();
172  uint8_t protocolMode;
173 
174  void SDP_task();
175  void L2CAP_task(); // L2CAP state machine
176 
177  bool activeConnection; // Used to indicate if it already has established a connection
178  bool SDPConnected;
179 
180  /* Variables used for L2CAP communication */
181  uint8_t control_dcid[2]; // L2CAP device CID for HID_Control - Always 0x0070
182  uint8_t interrupt_dcid[2]; // L2CAP device CID for HID_Interrupt - Always 0x0071
183  uint8_t sdp_dcid[2];
184  uint8_t l2cap_state;
185 
186  uint32_t lastBtDataInputIntMillis; // Variable used to store the millis value of the last Bluetooth DATA input report received on the interrupt channel
187 };
188 #endif
-
virtual void OnInitBTHID()
Definition: BTHID.h:136
+
virtual void OnInitBTHID()
Definition: BTHID.h:145
void ACLData(uint8_t *ACLData)
Definition: BTHID.cpp:63
Definition: BTD.h:221
-
uint8_t interrupt_scid[2]
Definition: BTHID.h:149
+
uint8_t interrupt_scid[2]
Definition: BTHID.h:158
bool connected
Definition: BTHID.h:88
-
void Run()
Definition: BTHID.cpp:558
-
virtual void ResetBTHID()
Definition: BTHID.h:140
+
void Run()
Definition: BTHID.cpp:560
+
virtual void ResetBTHID()
Definition: BTHID.h:149
void Reset()
Definition: BTHID.cpp:43
-
uint8_t control_scid[2]
Definition: BTHID.h:146
-
virtual void ParseBTHIDControlData(uint8_t len, uint8_t *buf)
Definition: BTHID.h:132
+
uint8_t control_scid[2]
Definition: BTHID.h:155
+
virtual void ParseBTHIDControlData(uint8_t len, uint8_t *buf)
Definition: BTHID.h:141
void pairWithHID()
Definition: BTD.h:513
void disconnect()
Definition: BTHID.cpp:53
HIDReportParser * GetReportParser(uint8_t id)
Definition: BTHID.h:49
-
virtual void ParseBTHIDData(uint8_t len, uint8_t *buf)
Definition: BTHID.h:125
+
virtual void ParseBTHIDData(uint8_t len, uint8_t *buf)
Definition: BTHID.h:134
void(* pFuncOnInit)(void)
Definition: BTD.h:643
BTD * pBtd
Definition: BTD.h:646
#define BULK_MAXPKTSIZE
Definition: BTD.h:37
+
uint32_t getLastMessageTime()
Definition: BTHID.h:101
void setLeds(struct KBDLEDS data)
Definition: BTHID.h:81
-
uint8_t sdp_scid[2]
Definition: BTHID.h:152
+
uint8_t sdp_scid[2]
Definition: BTHID.h:161
#define NUM_PARSERS
Definition: BTHID.h:26
-
void onInit()
Definition: BTHID.h:112
+
void onInit()
Definition: BTHID.h:121
Definition: BTHID.h:29
void setProtocolMode(uint8_t mode)
Definition: BTHID.h:72
BTHID(BTD *p, bool pair=false, const char *pin="0000")
Definition: BTHID.cpp:23
-
uint8_t l2cap_sdp_state
Definition: BTHID.h:151
+
uint8_t l2cap_sdp_state
Definition: BTHID.h:160
void pair(void)
Definition: BTHID.h:91
bool SetReportParser(uint8_t id, HIDReportParser *prs)
Definition: BTHID.h:61
diff --git a/_p_s4_b_t_8h_source.html b/_p_s4_b_t_8h_source.html index 74121431..ca263fc7 100644 --- a/_p_s4_b_t_8h_source.html +++ b/_p_s4_b_t_8h_source.html @@ -71,7 +71,7 @@ $(function() {
bool connected
Definition: BTHID.h:88
uint8_t flashOn
Definition: PS4Parser.h:119
-
uint8_t control_scid[2]
Definition: BTHID.h:146
+
uint8_t control_scid[2]
Definition: BTHID.h:155
uint8_t g
Definition: PS4Parser.h:118
bool reportChanged
Definition: PS4Parser.h:120
void Parse(uint8_t len, uint8_t *buf)
Definition: PS4Parser.cpp:76
diff --git a/_p_s5_b_t_8h_source.html b/_p_s5_b_t_8h_source.html index c17e9016..d55ecf2f 100644 --- a/_p_s5_b_t_8h_source.html +++ b/_p_s5_b_t_8h_source.html @@ -69,7 +69,7 @@ $(function() {
Definition: BTD.h:221
uint8_t disableLeds
Definition: PS5Parser.h:142
uint8_t playerLeds
Definition: PS5Parser.h:143
-
uint8_t interrupt_scid[2]
Definition: BTHID.h:149
+
uint8_t interrupt_scid[2]
Definition: BTHID.h:158
bool connected()
Definition: PS5BT.h:126
bool connected
Definition: BTHID.h:88
@@ -78,7 +78,7 @@ $(function() {
#define CRC32_POLY_LE
Definition: PS5BT.h:80
uint8_t r
Definition: PS5Parser.h:144
-
uint8_t control_scid[2]
Definition: BTHID.h:146
+
uint8_t control_scid[2]
Definition: BTHID.h:155
virtual void OnInitBTHID()
Definition: PS5BT.h:146
void Parse(uint8_t len, uint8_t *buf)
Definition: PS5Parser.cpp:80
PS5Trigger leftTrigger
Definition: PS5Parser.h:154
diff --git a/_x_b_o_x_o_n_e_s_b_t_8h_source.html b/_x_b_o_x_o_n_e_s_b_t_8h_source.html index 2d22ce99..44033dd8 100644 --- a/_x_b_o_x_o_n_e_s_b_t_8h_source.html +++ b/_x_b_o_x_o_n_e_s_b_t_8h_source.html @@ -68,7 +68,7 @@ $(function() {
Definition: BTD.h:221
virtual void ParseBTHIDData(uint8_t len, uint8_t *buf)
Definition: XBOXONESBT.h:56
-
uint8_t interrupt_scid[2]
Definition: BTHID.h:149
+
uint8_t interrupt_scid[2]
Definition: BTHID.h:158
bool connected
Definition: BTHID.h:88
virtual void sendOutputReport(uint8_t *data, uint8_t nbytes)
Definition: XBOXONESBT.h:76
virtual void ResetBTHID()
Definition: XBOXONESBT.h:70
diff --git a/class_b_t_h_i_d-members.html b/class_b_t_h_i_d-members.html index 929e90b5..73241b22 100644 --- a/class_b_t_h_i_d-members.html +++ b/class_b_t_h_i_d-members.html @@ -74,27 +74,28 @@ $(function() { connectedBTHID control_scidBTHIDprotected disconnect()BTHIDvirtual - GetReportParser(uint8_t id)BTHIDinline - hci_handleBluetoothServiceprotected - identifierBluetoothServiceprotected - interrupt_scidBTHIDprotected - l2cap_event_flagBluetoothServiceprotected - l2cap_sdp_stateBTHIDprotected - onInit()BTHIDinlineprotectedvirtual - OnInitBTHID()BTHIDinlineprotectedvirtual - pair(void)BTHIDinline - ParseBTHIDControlData(uint8_t len, uint8_t *buf)BTHIDinlineprotectedvirtual - ParseBTHIDData(uint8_t len, uint8_t *buf)BTHIDinlineprotectedvirtual - pBtdBluetoothServiceprotected - pFuncOnInitBluetoothServiceprotected - Reset()BTHIDprotectedvirtual - ResetBTHID()BTHIDinlineprotectedvirtual - Run()BTHIDprotectedvirtual - sdp_scidBTHIDprotected - setLeds(struct KBDLEDS data)BTHIDinline - setLeds(uint8_t data)BTHID - setProtocolMode(uint8_t mode)BTHIDinline - SetReportParser(uint8_t id, HIDReportParser *prs)BTHIDinline + getLastMessageTime()BTHIDinline + GetReportParser(uint8_t id)BTHIDinline + hci_handleBluetoothServiceprotected + identifierBluetoothServiceprotected + interrupt_scidBTHIDprotected + l2cap_event_flagBluetoothServiceprotected + l2cap_sdp_stateBTHIDprotected + onInit()BTHIDinlineprotectedvirtual + OnInitBTHID()BTHIDinlineprotectedvirtual + pair(void)BTHIDinline + ParseBTHIDControlData(uint8_t len, uint8_t *buf)BTHIDinlineprotectedvirtual + ParseBTHIDData(uint8_t len, uint8_t *buf)BTHIDinlineprotectedvirtual + pBtdBluetoothServiceprotected + pFuncOnInitBluetoothServiceprotected + Reset()BTHIDprotectedvirtual + ResetBTHID()BTHIDinlineprotectedvirtual + Run()BTHIDprotectedvirtual + sdp_scidBTHIDprotected + setLeds(struct KBDLEDS data)BTHIDinline + setLeds(uint8_t data)BTHID + setProtocolMode(uint8_t mode)BTHIDinline + SetReportParser(uint8_t id, HIDReportParser *prs)BTHIDinline
@@ -456,6 +458,34 @@ BluetoothService implementation

Definition at line 91 of file BTHID.h.

+ + + +

◆ getLastMessageTime()

+ +
+
+ + + + + +
+ + + + + + + +
uint32_t BTHID::getLastMessageTime ()
+
+inline
+
+

Used to get the millis() of the last Bluetooth DATA input report received on the interrupt channel. This can be used detect if the connection to a Bluetooth device is lost fx if the battery runs out or if it gets out of range.

Returns
Timestamp in milliseconds of the last Bluetooth DATA input report received on the interrupt channel.
+ +

Definition at line 101 of file BTHID.h.

+
@@ -520,7 +550,7 @@ BluetoothService implementation

Implements BluetoothService.

-

Definition at line 558 of file BTHID.cpp.

+

Definition at line 560 of file BTHID.cpp.

@@ -580,7 +610,7 @@ BluetoothService implementation

Implements BluetoothService.

-

Definition at line 112 of file BTHID.h.

+

Definition at line 121 of file BTHID.h.

@@ -627,7 +657,7 @@ BluetoothService implementation

Reimplemented in PS5BT, PS4BT, and XBOXONESBT.

-

Definition at line 125 of file BTHID.h.

+

Definition at line 134 of file BTHID.h.

@@ -666,7 +696,7 @@ BluetoothService implementation

Same as ParseBTHIDData for reports that are sent through the interrupt pipe (in response to a GET_REPORT).

-

Definition at line 132 of file BTHID.h.

+

Definition at line 141 of file BTHID.h.

@@ -696,7 +726,7 @@ BluetoothService implementation

Reimplemented in PS5BT, PS4BT, and XBOXONESBT.

-

Definition at line 136 of file BTHID.h.

+

Definition at line 145 of file BTHID.h.

@@ -726,7 +756,7 @@ BluetoothService implementation

Reimplemented in PS5BT, PS4BT, and XBOXONESBT.

-

Definition at line 140 of file BTHID.h.

+

Definition at line 149 of file BTHID.h.

@@ -769,7 +799,7 @@ BluetoothService implementation

L2CAP source CID for HID_Control

-

Definition at line 146 of file BTHID.h.

+

Definition at line 155 of file BTHID.h.

@@ -794,7 +824,7 @@ BluetoothService implementation

L2CAP source CID for HID_Interrupt

-

Definition at line 149 of file BTHID.h.

+

Definition at line 158 of file BTHID.h.

@@ -818,7 +848,7 @@ BluetoothService implementation
-

Definition at line 151 of file BTHID.h.

+

Definition at line 160 of file BTHID.h.

@@ -842,7 +872,7 @@ BluetoothService implementation
-

Definition at line 152 of file BTHID.h.

+

Definition at line 161 of file BTHID.h.

diff --git a/class_p_s4_b_t-members.html b/class_p_s4_b_t-members.html index fb6f7f6c..968ee5a3 100644 --- a/class_p_s4_b_t-members.html +++ b/class_p_s4_b_t-members.html @@ -82,47 +82,48 @@ $(function() { getBatteryLevel()PS4Parserinline getButtonClick(ButtonEnum b)PS4Parser getButtonPress(ButtonEnum b)PS4Parser - getMicStatus()PS4Parserinline - GetReportParser(uint8_t id)BTHIDinline - getSensor(SensorEnum s)PS4Parserinline - getTouchCounter(uint8_t finger=0, uint8_t xyId=0)PS4Parserinline - getUsbStatus()PS4Parserinline - getX(uint8_t finger=0, uint8_t xyId=0)PS4Parserinline - getY(uint8_t finger=0, uint8_t xyId=0)PS4Parserinline - hci_handleBluetoothServiceprotected - identifierBluetoothServiceprotected - interrupt_scidBTHIDprotected - isTouching(uint8_t finger=0, uint8_t xyId=0)PS4Parserinline - l2cap_event_flagBluetoothServiceprotected - l2cap_sdp_stateBTHIDprotected - onInit()BTHIDinlineprotectedvirtual - OnInitBTHID()PS4BTinlineprotectedvirtual - pair(void)BTHIDinline - Parse(uint8_t len, uint8_t *buf)PS4Parserprotected - ParseBTHIDControlData(uint8_t len, uint8_t *buf)BTHIDinlineprotectedvirtual - ParseBTHIDData(uint8_t len, uint8_t *buf)PS4BTinlineprotectedvirtual - pBtdBluetoothServiceprotected - pFuncOnInitBluetoothServiceprotected - PS4BT(BTD *p, bool pair=false, const char *pin="0000")PS4BTinline - PS4Parser()PS4Parserinline - BTHID::Reset()BTHIDprotectedvirtual - PS4Parser::Reset()PS4Parserprotected - ResetBTHID()PS4BTinlineprotectedvirtual - Run()BTHIDprotectedvirtual - sdp_scidBTHIDprotected - sendOutputReport(PS4Output *output)PS4BTinlineprotectedvirtual - setAllOff()PS4Parserinline - setLed(uint8_t r, uint8_t g, uint8_t b)PS4Parserinline - setLed(ColorsEnum color)PS4Parserinline - setLedFlash(uint8_t flashOn, uint8_t flashOff)PS4Parserinline - setLedOff()PS4Parserinline - setLeds(struct KBDLEDS data)BTHIDinline - setLeds(uint8_t data)BTHID - setProtocolMode(uint8_t mode)BTHIDinline - SetReportParser(uint8_t id, HIDReportParser *prs)BTHIDinline - setRumbleOff()PS4Parserinline - setRumbleOn(RumbleEnum mode)PS4Parserinline - setRumbleOn(uint8_t bigRumble, uint8_t smallRumble)PS4Parserinline + getLastMessageTime()BTHIDinline + getMicStatus()PS4Parserinline + GetReportParser(uint8_t id)BTHIDinline + getSensor(SensorEnum s)PS4Parserinline + getTouchCounter(uint8_t finger=0, uint8_t xyId=0)PS4Parserinline + getUsbStatus()PS4Parserinline + getX(uint8_t finger=0, uint8_t xyId=0)PS4Parserinline + getY(uint8_t finger=0, uint8_t xyId=0)PS4Parserinline + hci_handleBluetoothServiceprotected + identifierBluetoothServiceprotected + interrupt_scidBTHIDprotected + isTouching(uint8_t finger=0, uint8_t xyId=0)PS4Parserinline + l2cap_event_flagBluetoothServiceprotected + l2cap_sdp_stateBTHIDprotected + onInit()BTHIDinlineprotectedvirtual + OnInitBTHID()PS4BTinlineprotectedvirtual + pair(void)BTHIDinline + Parse(uint8_t len, uint8_t *buf)PS4Parserprotected + ParseBTHIDControlData(uint8_t len, uint8_t *buf)BTHIDinlineprotectedvirtual + ParseBTHIDData(uint8_t len, uint8_t *buf)PS4BTinlineprotectedvirtual + pBtdBluetoothServiceprotected + pFuncOnInitBluetoothServiceprotected + PS4BT(BTD *p, bool pair=false, const char *pin="0000")PS4BTinline + PS4Parser()PS4Parserinline + BTHID::Reset()BTHIDprotectedvirtual + PS4Parser::Reset()PS4Parserprotected + ResetBTHID()PS4BTinlineprotectedvirtual + Run()BTHIDprotectedvirtual + sdp_scidBTHIDprotected + sendOutputReport(PS4Output *output)PS4BTinlineprotectedvirtual + setAllOff()PS4Parserinline + setLed(uint8_t r, uint8_t g, uint8_t b)PS4Parserinline + setLed(ColorsEnum color)PS4Parserinline + setLedFlash(uint8_t flashOn, uint8_t flashOff)PS4Parserinline + setLedOff()PS4Parserinline + setLeds(struct KBDLEDS data)BTHIDinline + setLeds(uint8_t data)BTHID + setProtocolMode(uint8_t mode)BTHIDinline + SetReportParser(uint8_t id, HIDReportParser *prs)BTHIDinline + setRumbleOff()PS4Parserinline + setRumbleOn(RumbleEnum mode)PS4Parserinline + setRumbleOn(uint8_t bigRumble, uint8_t smallRumble)PS4Parserinline