Vous ne pouvez pas sélectionner plus de 25 sujets Les noms de sujets doivent commencer par une lettre ou un nombre, peuvent contenir des tirets ('-') et peuvent comporter jusqu'à 35 caractères.
Ce dépôt est archivé. Vous pouvez voir les fichiers et le cloner, mais vous ne pouvez pas pousser ni ouvrir de ticket/demande d'ajout.

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399
  1. /* Copyright (C) 2013 Kristian Lauszus, TKJ Electronics. All rights reserved.
  2. This software may be distributed and modified under the terms of the GNU
  3. General Public License version 2 (GPL2) as published by the Free Software
  4. Foundation and appearing in the file GPL2.TXT included in the packaging of
  5. this file. Please note that GPL2 Section 2[b] requires that all works based
  6. on this software must also be made publicly available under the terms of
  7. the GPL2 ("Copyleft").
  8. Contact information
  9. -------------------
  10. Kristian Lauszus, TKJ Electronics
  11. Web : http://www.tkjelectronics.com
  12. e-mail : [email protected]
  13. */
  14. #include "BTHID.h"
  15. // To enable serial debugging see "settings.h"
  16. //#define EXTRADEBUG // Uncomment to get even more debugging data
  17. //#define PRINTREPORT // Uncomment to print the report send by the HID device
  18. BTHID::BTHID(BTD *p, bool pair, const char *pin) :
  19. BluetoothService(p), // Pointer to USB class instance - mandatory
  20. protocolMode(HID_BOOT_PROTOCOL) {
  21. for(uint8_t i = 0; i < NUM_PARSERS; i++)
  22. pRptParser[i] = NULL;
  23. pBtd->pairWithHIDDevice = pair;
  24. pBtd->btdPin = pin;
  25. /* Set device cid for the control and intterrupt channelse - LSB */
  26. control_dcid[0] = 0x70; // 0x0070
  27. control_dcid[1] = 0x00;
  28. interrupt_dcid[0] = 0x71; // 0x0071
  29. interrupt_dcid[1] = 0x00;
  30. Reset();
  31. }
  32. void BTHID::Reset() {
  33. connected = false;
  34. activeConnection = false;
  35. l2cap_event_flag = 0; // Reset flags
  36. l2cap_state = L2CAP_WAIT;
  37. ResetBTHID();
  38. }
  39. void BTHID::disconnect() { // Use this void to disconnect the device
  40. // First the HID interrupt channel has to be disconnected, then the HID control channel and finally the HCI connection
  41. pBtd->l2cap_disconnection_request(hci_handle, ++identifier, interrupt_scid, interrupt_dcid);
  42. Reset();
  43. l2cap_state = L2CAP_INTERRUPT_DISCONNECT;
  44. }
  45. void BTHID::ACLData(uint8_t* l2capinbuf) {
  46. if(!pBtd->l2capConnectionClaimed && pBtd->incomingHIDDevice && !connected && !activeConnection) {
  47. if(l2capinbuf[8] == L2CAP_CMD_CONNECTION_REQUEST) {
  48. if((l2capinbuf[12] | (l2capinbuf[13] << 8)) == HID_CTRL_PSM) {
  49. pBtd->incomingHIDDevice = false;
  50. pBtd->l2capConnectionClaimed = true; // Claim that the incoming connection belongs to this service
  51. activeConnection = true;
  52. hci_handle = pBtd->hci_handle; // Store the HCI Handle for the connection
  53. l2cap_state = L2CAP_WAIT;
  54. }
  55. }
  56. }
  57. if(checkHciHandle(l2capinbuf, hci_handle)) { // acl_handle_ok
  58. if((l2capinbuf[6] | (l2capinbuf[7] << 8)) == 0x0001U) { // l2cap_control - Channel ID for ACL-U
  59. if(l2capinbuf[8] == L2CAP_CMD_COMMAND_REJECT) {
  60. #ifdef DEBUG_USB_HOST
  61. Notify(PSTR("\r\nL2CAP Command Rejected - Reason: "), 0x80);
  62. D_PrintHex<uint8_t > (l2capinbuf[13], 0x80);
  63. Notify(PSTR(" "), 0x80);
  64. D_PrintHex<uint8_t > (l2capinbuf[12], 0x80);
  65. Notify(PSTR(" "), 0x80);
  66. D_PrintHex<uint8_t > (l2capinbuf[17], 0x80);
  67. Notify(PSTR(" "), 0x80);
  68. D_PrintHex<uint8_t > (l2capinbuf[16], 0x80);
  69. Notify(PSTR(" "), 0x80);
  70. D_PrintHex<uint8_t > (l2capinbuf[15], 0x80);
  71. Notify(PSTR(" "), 0x80);
  72. D_PrintHex<uint8_t > (l2capinbuf[14], 0x80);
  73. #endif
  74. } else if(l2capinbuf[8] == L2CAP_CMD_CONNECTION_RESPONSE) {
  75. if(((l2capinbuf[16] | (l2capinbuf[17] << 8)) == 0x0000) && ((l2capinbuf[18] | (l2capinbuf[19] << 8)) == SUCCESSFUL)) { // Success
  76. if(l2capinbuf[14] == control_dcid[0] && l2capinbuf[15] == control_dcid[1]) {
  77. //Notify(PSTR("\r\nHID Control Connection Complete"), 0x80);
  78. identifier = l2capinbuf[9];
  79. control_scid[0] = l2capinbuf[12];
  80. control_scid[1] = l2capinbuf[13];
  81. l2cap_set_flag(L2CAP_FLAG_CONTROL_CONNECTED);
  82. } else if(l2capinbuf[14] == interrupt_dcid[0] && l2capinbuf[15] == interrupt_dcid[1]) {
  83. //Notify(PSTR("\r\nHID Interrupt Connection Complete"), 0x80);
  84. identifier = l2capinbuf[9];
  85. interrupt_scid[0] = l2capinbuf[12];
  86. interrupt_scid[1] = l2capinbuf[13];
  87. l2cap_set_flag(L2CAP_FLAG_INTERRUPT_CONNECTED);
  88. }
  89. }
  90. } else if(l2capinbuf[8] == L2CAP_CMD_CONNECTION_REQUEST) {
  91. #ifdef EXTRADEBUG
  92. Notify(PSTR("\r\nL2CAP Connection Request - PSM: "), 0x80);
  93. D_PrintHex<uint8_t > (l2capinbuf[13], 0x80);
  94. Notify(PSTR(" "), 0x80);
  95. D_PrintHex<uint8_t > (l2capinbuf[12], 0x80);
  96. Notify(PSTR(" SCID: "), 0x80);
  97. D_PrintHex<uint8_t > (l2capinbuf[15], 0x80);
  98. Notify(PSTR(" "), 0x80);
  99. D_PrintHex<uint8_t > (l2capinbuf[14], 0x80);
  100. Notify(PSTR(" Identifier: "), 0x80);
  101. D_PrintHex<uint8_t > (l2capinbuf[9], 0x80);
  102. #endif
  103. if((l2capinbuf[12] | (l2capinbuf[13] << 8)) == HID_CTRL_PSM) {
  104. identifier = l2capinbuf[9];
  105. control_scid[0] = l2capinbuf[14];
  106. control_scid[1] = l2capinbuf[15];
  107. l2cap_set_flag(L2CAP_FLAG_CONNECTION_CONTROL_REQUEST);
  108. } else if((l2capinbuf[12] | (l2capinbuf[13] << 8)) == HID_INTR_PSM) {
  109. identifier = l2capinbuf[9];
  110. interrupt_scid[0] = l2capinbuf[14];
  111. interrupt_scid[1] = l2capinbuf[15];
  112. l2cap_set_flag(L2CAP_FLAG_CONNECTION_INTERRUPT_REQUEST);
  113. }
  114. } else if(l2capinbuf[8] == L2CAP_CMD_CONFIG_RESPONSE) {
  115. if((l2capinbuf[16] | (l2capinbuf[17] << 8)) == 0x0000) { // Success
  116. if(l2capinbuf[12] == control_dcid[0] && l2capinbuf[13] == control_dcid[1]) {
  117. //Notify(PSTR("\r\nHID Control Configuration Complete"), 0x80);
  118. identifier = l2capinbuf[9];
  119. l2cap_set_flag(L2CAP_FLAG_CONFIG_CONTROL_SUCCESS);
  120. } else if(l2capinbuf[12] == interrupt_dcid[0] && l2capinbuf[13] == interrupt_dcid[1]) {
  121. //Notify(PSTR("\r\nHID Interrupt Configuration Complete"), 0x80);
  122. identifier = l2capinbuf[9];
  123. l2cap_set_flag(L2CAP_FLAG_CONFIG_INTERRUPT_SUCCESS);
  124. }
  125. }
  126. } else if(l2capinbuf[8] == L2CAP_CMD_CONFIG_REQUEST) {
  127. if(l2capinbuf[12] == control_dcid[0] && l2capinbuf[13] == control_dcid[1]) {
  128. //Notify(PSTR("\r\nHID Control Configuration Request"), 0x80);
  129. pBtd->l2cap_config_response(hci_handle, l2capinbuf[9], control_scid);
  130. } else if(l2capinbuf[12] == interrupt_dcid[0] && l2capinbuf[13] == interrupt_dcid[1]) {
  131. //Notify(PSTR("\r\nHID Interrupt Configuration Request"), 0x80);
  132. pBtd->l2cap_config_response(hci_handle, l2capinbuf[9], interrupt_scid);
  133. }
  134. } else if(l2capinbuf[8] == L2CAP_CMD_DISCONNECT_REQUEST) {
  135. if(l2capinbuf[12] == control_dcid[0] && l2capinbuf[13] == control_dcid[1]) {
  136. #ifdef DEBUG_USB_HOST
  137. Notify(PSTR("\r\nDisconnect Request: Control Channel"), 0x80);
  138. #endif
  139. identifier = l2capinbuf[9];
  140. pBtd->l2cap_disconnection_response(hci_handle, identifier, control_dcid, control_scid);
  141. Reset();
  142. } else if(l2capinbuf[12] == interrupt_dcid[0] && l2capinbuf[13] == interrupt_dcid[1]) {
  143. #ifdef DEBUG_USB_HOST
  144. Notify(PSTR("\r\nDisconnect Request: Interrupt Channel"), 0x80);
  145. #endif
  146. identifier = l2capinbuf[9];
  147. pBtd->l2cap_disconnection_response(hci_handle, identifier, interrupt_dcid, interrupt_scid);
  148. Reset();
  149. }
  150. } else if(l2capinbuf[8] == L2CAP_CMD_DISCONNECT_RESPONSE) {
  151. if(l2capinbuf[12] == control_scid[0] && l2capinbuf[13] == control_scid[1]) {
  152. //Notify(PSTR("\r\nDisconnect Response: Control Channel"), 0x80);
  153. identifier = l2capinbuf[9];
  154. l2cap_set_flag(L2CAP_FLAG_DISCONNECT_CONTROL_RESPONSE);
  155. } else if(l2capinbuf[12] == interrupt_scid[0] && l2capinbuf[13] == interrupt_scid[1]) {
  156. //Notify(PSTR("\r\nDisconnect Response: Interrupt Channel"), 0x80);
  157. identifier = l2capinbuf[9];
  158. l2cap_set_flag(L2CAP_FLAG_DISCONNECT_INTERRUPT_RESPONSE);
  159. }
  160. }
  161. #ifdef EXTRADEBUG
  162. else {
  163. identifier = l2capinbuf[9];
  164. Notify(PSTR("\r\nL2CAP Unknown Signaling Command: "), 0x80);
  165. D_PrintHex<uint8_t > (l2capinbuf[8], 0x80);
  166. }
  167. #endif
  168. } else if(l2capinbuf[6] == interrupt_dcid[0] && l2capinbuf[7] == interrupt_dcid[1]) { // l2cap_interrupt
  169. #ifdef PRINTREPORT
  170. Notify(PSTR("\r\nL2CAP Interrupt: "), 0x80);
  171. for(uint16_t i = 0; i < ((uint16_t)l2capinbuf[5] << 8 | l2capinbuf[4]); i++) {
  172. D_PrintHex<uint8_t > (l2capinbuf[i + 8], 0x80);
  173. Notify(PSTR(" "), 0x80);
  174. }
  175. #endif
  176. if(l2capinbuf[8] == 0xA1) { // HID_THDR_DATA_INPUT
  177. uint16_t length = ((uint16_t)l2capinbuf[5] << 8 | l2capinbuf[4]);
  178. ParseBTHIDData((uint8_t)(length - 1), &l2capinbuf[9]);
  179. switch(l2capinbuf[9]) {
  180. case 0x01: // Keyboard or Joystick events
  181. if(pRptParser[KEYBOARD_PARSER_ID])
  182. pRptParser[KEYBOARD_PARSER_ID]->Parse(reinterpret_cast<HID *>(this), 0, (uint8_t)(length - 2), &l2capinbuf[10]); // Use reinterpret_cast again to extract the instance
  183. break;
  184. case 0x02: // Mouse events
  185. if(pRptParser[MOUSE_PARSER_ID])
  186. pRptParser[MOUSE_PARSER_ID]->Parse(reinterpret_cast<HID *>(this), 0, (uint8_t)(length - 2), &l2capinbuf[10]); // Use reinterpret_cast again to extract the instance
  187. break;
  188. #ifdef EXTRADEBUG
  189. default:
  190. Notify(PSTR("\r\nUnknown Report type: "), 0x80);
  191. D_PrintHex<uint8_t > (l2capinbuf[9], 0x80);
  192. break;
  193. #endif
  194. }
  195. }
  196. } else if(l2capinbuf[6] == control_dcid[0] && l2capinbuf[7] == control_dcid[1]) { // l2cap_control
  197. #ifdef PRINTREPORT
  198. Notify(PSTR("\r\nL2CAP Control: "), 0x80);
  199. for(uint16_t i = 0; i < ((uint16_t)l2capinbuf[5] << 8 | l2capinbuf[4]); i++) {
  200. D_PrintHex<uint8_t > (l2capinbuf[i + 8], 0x80);
  201. Notify(PSTR(" "), 0x80);
  202. }
  203. #endif
  204. }
  205. #ifdef EXTRADEBUG
  206. else {
  207. Notify(PSTR("\r\nUnsupported L2CAP Data - Channel ID: "), 0x80);
  208. D_PrintHex<uint8_t > (l2capinbuf[7], 0x80);
  209. Notify(PSTR(" "), 0x80);
  210. D_PrintHex<uint8_t > (l2capinbuf[6], 0x80);
  211. Notify(PSTR("\r\nData: "), 0x80);
  212. Notify(PSTR("\r\n"), 0x80);
  213. for(uint16_t i = 0; i < ((uint16_t)l2capinbuf[5] << 8 | l2capinbuf[4]); i++) {
  214. D_PrintHex<uint8_t > (l2capinbuf[i + 8], 0x80);
  215. Notify(PSTR(" "), 0x80);
  216. }
  217. }
  218. #endif
  219. L2CAP_task();
  220. }
  221. }
  222. void BTHID::L2CAP_task() {
  223. switch(l2cap_state) {
  224. /* These states are used if the HID device is the host */
  225. case L2CAP_CONTROL_SUCCESS:
  226. if(l2cap_check_flag(L2CAP_FLAG_CONFIG_CONTROL_SUCCESS)) {
  227. #ifdef DEBUG_USB_HOST
  228. Notify(PSTR("\r\nHID Control Successfully Configured"), 0x80);
  229. #endif
  230. setProtocol(); // Set protocol before establishing HID interrupt channel
  231. l2cap_state = L2CAP_INTERRUPT_SETUP;
  232. }
  233. break;
  234. case L2CAP_INTERRUPT_SETUP:
  235. if(l2cap_check_flag(L2CAP_FLAG_CONNECTION_INTERRUPT_REQUEST)) {
  236. #ifdef DEBUG_USB_HOST
  237. Notify(PSTR("\r\nHID Interrupt Incoming Connection Request"), 0x80);
  238. #endif
  239. pBtd->l2cap_connection_response(hci_handle, identifier, interrupt_dcid, interrupt_scid, PENDING);
  240. delay(1);
  241. pBtd->l2cap_connection_response(hci_handle, identifier, interrupt_dcid, interrupt_scid, SUCCESSFUL);
  242. identifier++;
  243. delay(1);
  244. pBtd->l2cap_config_request(hci_handle, identifier, interrupt_scid);
  245. l2cap_state = L2CAP_INTERRUPT_CONFIG_REQUEST;
  246. }
  247. break;
  248. /* These states are used if the Arduino is the host */
  249. case L2CAP_CONTROL_CONNECT_REQUEST:
  250. if(l2cap_check_flag(L2CAP_FLAG_CONTROL_CONNECTED)) {
  251. #ifdef DEBUG_USB_HOST
  252. Notify(PSTR("\r\nSend HID Control Config Request"), 0x80);
  253. #endif
  254. identifier++;
  255. pBtd->l2cap_config_request(hci_handle, identifier, control_scid);
  256. l2cap_state = L2CAP_CONTROL_CONFIG_REQUEST;
  257. }
  258. break;
  259. case L2CAP_CONTROL_CONFIG_REQUEST:
  260. if(l2cap_check_flag(L2CAP_FLAG_CONFIG_CONTROL_SUCCESS)) {
  261. setProtocol(); // Set protocol before establishing HID interrupt channel
  262. delay(1); // Short delay between commands - just to be sure
  263. #ifdef DEBUG_USB_HOST
  264. Notify(PSTR("\r\nSend HID Interrupt Connection Request"), 0x80);
  265. #endif
  266. identifier++;
  267. pBtd->l2cap_connection_request(hci_handle, identifier, interrupt_dcid, HID_INTR_PSM);
  268. l2cap_state = L2CAP_INTERRUPT_CONNECT_REQUEST;
  269. }
  270. break;
  271. case L2CAP_INTERRUPT_CONNECT_REQUEST:
  272. if(l2cap_check_flag(L2CAP_FLAG_INTERRUPT_CONNECTED)) {
  273. #ifdef DEBUG_USB_HOST
  274. Notify(PSTR("\r\nSend HID Interrupt Config Request"), 0x80);
  275. #endif
  276. identifier++;
  277. pBtd->l2cap_config_request(hci_handle, identifier, interrupt_scid);
  278. l2cap_state = L2CAP_INTERRUPT_CONFIG_REQUEST;
  279. }
  280. break;
  281. case L2CAP_INTERRUPT_CONFIG_REQUEST:
  282. if(l2cap_check_flag(L2CAP_FLAG_CONFIG_INTERRUPT_SUCCESS)) { // Now the HID channels is established
  283. #ifdef DEBUG_USB_HOST
  284. Notify(PSTR("\r\nHID Channels Established"), 0x80);
  285. #endif
  286. pBtd->connectToHIDDevice = false;
  287. pBtd->pairWithHIDDevice = false;
  288. connected = true;
  289. onInit();
  290. l2cap_state = L2CAP_DONE;
  291. }
  292. break;
  293. case L2CAP_DONE:
  294. break;
  295. case L2CAP_INTERRUPT_DISCONNECT:
  296. if(l2cap_check_flag(L2CAP_FLAG_DISCONNECT_INTERRUPT_RESPONSE)) {
  297. #ifdef DEBUG_USB_HOST
  298. Notify(PSTR("\r\nDisconnected Interrupt Channel"), 0x80);
  299. #endif
  300. identifier++;
  301. pBtd->l2cap_disconnection_request(hci_handle, identifier, control_scid, control_dcid);
  302. l2cap_state = L2CAP_CONTROL_DISCONNECT;
  303. }
  304. break;
  305. case L2CAP_CONTROL_DISCONNECT:
  306. if(l2cap_check_flag(L2CAP_FLAG_DISCONNECT_CONTROL_RESPONSE)) {
  307. #ifdef DEBUG_USB_HOST
  308. Notify(PSTR("\r\nDisconnected Control Channel"), 0x80);
  309. #endif
  310. pBtd->hci_disconnect(hci_handle);
  311. hci_handle = -1; // Reset handle
  312. l2cap_event_flag = 0; // Reset flags
  313. l2cap_state = L2CAP_WAIT;
  314. }
  315. break;
  316. }
  317. }
  318. void BTHID::Run() {
  319. switch(l2cap_state) {
  320. case L2CAP_WAIT:
  321. if(pBtd->connectToHIDDevice && !pBtd->l2capConnectionClaimed && !connected && !activeConnection) {
  322. pBtd->l2capConnectionClaimed = true;
  323. activeConnection = true;
  324. #ifdef DEBUG_USB_HOST
  325. Notify(PSTR("\r\nSend HID Control Connection Request"), 0x80);
  326. #endif
  327. hci_handle = pBtd->hci_handle; // Store the HCI Handle for the connection
  328. l2cap_event_flag = 0; // Reset flags
  329. identifier = 0;
  330. pBtd->l2cap_connection_request(hci_handle, identifier, control_dcid, HID_CTRL_PSM);
  331. l2cap_state = L2CAP_CONTROL_CONNECT_REQUEST;
  332. } else if(l2cap_check_flag(L2CAP_FLAG_CONNECTION_CONTROL_REQUEST)) {
  333. #ifdef DEBUG_USB_HOST
  334. Notify(PSTR("\r\nHID Control Incoming Connection Request"), 0x80);
  335. #endif
  336. pBtd->l2cap_connection_response(hci_handle, identifier, control_dcid, control_scid, PENDING);
  337. delay(1);
  338. pBtd->l2cap_connection_response(hci_handle, identifier, control_dcid, control_scid, SUCCESSFUL);
  339. identifier++;
  340. delay(1);
  341. pBtd->l2cap_config_request(hci_handle, identifier, control_scid);
  342. l2cap_state = L2CAP_CONTROL_SUCCESS;
  343. }
  344. break;
  345. }
  346. }
  347. /************************************************************/
  348. /* HID Commands */
  349. /************************************************************/
  350. void BTHID::setProtocol() {
  351. #ifdef DEBUG_USB_HOST
  352. Notify(PSTR("\r\nSet protocol mode: "), 0x80);
  353. D_PrintHex<uint8_t > (protocolMode, 0x80);
  354. #endif
  355. if (protocolMode != HID_BOOT_PROTOCOL && protocolMode != HID_RPT_PROTOCOL) {
  356. #ifdef DEBUG_USB_HOST
  357. Notify(PSTR("\r\nNot a valid protocol mode. Using Boot protocol instead."), 0x80);
  358. #endif
  359. protocolMode = HID_BOOT_PROTOCOL; // Use Boot Protocol by default
  360. }
  361. uint8_t command = 0x70 | protocolMode; // Set Protocol, see Bluetooth HID specs page 33
  362. pBtd->L2CAP_Command(hci_handle, &command, 1, control_scid[0], control_scid[1]);
  363. }
  364. void BTHID::setLeds(uint8_t data) {
  365. uint8_t buf[3];
  366. buf[0] = 0xA2; // HID BT DATA_request (0xA0) | Report Type (Output 0x02)
  367. buf[1] = 0x01; // Report ID
  368. buf[2] = data;
  369. pBtd->L2CAP_Command(hci_handle, buf, 3, interrupt_scid[0], interrupt_scid[1]);
  370. }