From d61082c585e39f35ed4fce57484e3a9b80c8b799 Mon Sep 17 00:00:00 2001 From: "Deployment Bot (from Travis CI)" Date: Mon, 16 Nov 2020 08:40:37 +0000 Subject: [PATCH] Deploy felis/USB_Host_Shield_2.0 to github.com/felis/USB_Host_Shield_2.0.git:gh-pages --- _b_t_d_8cpp_source.html | 226 +++--- _b_t_d_8h.html | 691 +++++++++++++----- _b_t_d_8h__dep__incl.map | 17 +- _b_t_d_8h__dep__incl.md5 | 2 +- _b_t_d_8h__dep__incl.png | Bin 13917 -> 15916 bytes _b_t_d_8h_source.html | 168 +++-- _b_t_h_i_d_8cpp_source.html | 132 ++-- _b_t_h_i_d_8h.html | 1 + _b_t_h_i_d_8h__dep__incl.map | 1 + _b_t_h_i_d_8h__dep__incl.md5 | 2 +- _b_t_h_i_d_8h__dep__incl.png | Bin 4157 -> 4933 bytes _b_t_h_i_d_8h_source.html | 23 +- _p_s3_b_t_8cpp_source.html | 136 ++-- _p_s3_b_t_8h_source.html | 12 +- _p_s3_u_s_b_8cpp_source.html | 14 +- _p_s3_u_s_b_8h_source.html | 6 +- _p_s4_b_t_8h_source.html | 10 +- _p_s4_parser_8cpp.html | 31 +- _p_s4_parser_8cpp_source.html | 2 +- _p_s4_parser_8h_source.html | 20 +- _r_e_a_d_m_e_8md_source.html | 2 +- _s_p_p_8cpp_source.html | 128 ++-- _s_p_p_8h.html | 86 +-- _s_p_p_8h_source.html | 12 +- _usb_8h.html | 98 +-- _usb_8h__dep__incl.map | 98 +-- _usb_8h__dep__incl.md5 | 2 +- _usb_8h__dep__incl.png | Bin 133098 -> 145423 bytes _wii_8cpp_source.html | 126 ++-- _wii_8h_source.html | 10 +- _x_b_o_x_o_l_d_8cpp_source.html | 10 +- _x_b_o_x_o_l_d_8h_source.html | 2 +- _x_b_o_x_o_n_e_8cpp_source.html | 10 +- _x_b_o_x_o_n_e_8h_source.html | 2 +- _x_b_o_x_o_n_e_s_b_t_8h.html | 124 ++++ _x_b_o_x_o_n_e_s_b_t_8h__incl.map | 10 + _x_b_o_x_o_n_e_s_b_t_8h__incl.md5 | 1 + _x_b_o_x_o_n_e_s_b_t_8h__incl.png | Bin 0 -> 25487 bytes _x_b_o_x_o_n_e_s_b_t_8h_source.html | 120 +++ _x_b_o_x_o_n_e_s_parser_8cpp.html | 221 ++++++ _x_b_o_x_o_n_e_s_parser_8cpp__incl.map | 5 + _x_b_o_x_o_n_e_s_parser_8cpp__incl.md5 | 1 + _x_b_o_x_o_n_e_s_parser_8cpp__incl.png | Bin 0 -> 8153 bytes _x_b_o_x_o_n_e_s_parser_8cpp_source.html | 132 ++++ _x_b_o_x_o_n_e_s_parser_8h.html | 131 ++++ _x_b_o_x_o_n_e_s_parser_8h__dep__incl.map | 4 + _x_b_o_x_o_n_e_s_parser_8h__dep__incl.md5 | 1 + _x_b_o_x_o_n_e_s_parser_8h__dep__incl.png | Bin 0 -> 6137 bytes _x_b_o_x_o_n_e_s_parser_8h__incl.map | 4 + _x_b_o_x_o_n_e_s_parser_8h__incl.md5 | 1 + _x_b_o_x_o_n_e_s_parser_8h__incl.png | Bin 0 -> 5161 bytes _x_b_o_x_o_n_e_s_parser_8h_source.html | 120 +++ _x_b_o_x_r_e_c_v_8cpp_source.html | 10 +- _x_b_o_x_r_e_c_v_8h_source.html | 2 +- _x_b_o_x_u_s_b_8cpp_source.html | 10 +- _x_b_o_x_u_s_b_8h_source.html | 2 +- annotated.html | 10 +- class_b_t_d-members.html | 80 +- class_b_t_d.html | 271 +++++-- class_b_t_h_i_d-members.html | 20 +- class_b_t_h_i_d.html | 69 +- class_b_t_h_i_d__inherit__graph.map | 5 +- class_b_t_h_i_d__inherit__graph.md5 | 2 +- class_b_t_h_i_d__inherit__graph.png | Bin 3749 -> 6311 bytes class_bluetooth_service.html | 29 +- class_bluetooth_service__inherit__graph.map | 9 +- class_bluetooth_service__inherit__graph.md5 | 2 +- class_bluetooth_service__inherit__graph.png | Bin 9021 -> 11719 bytes class_p_s4_b_t-members.html | 28 +- class_p_s4_b_t.html | 4 + class_p_t_p_list_parser.html | 8 +- class_report_desc_parser2.html | 2 +- class_report_desc_parser_base.html | 32 +- class_s_p_p.html | 8 +- class_u_s_b_device_config.html | 4 +- class_u_s_b_h___m_i_d_i.html | 4 +- class_universal_report_parser.html | 2 +- class_x_b_o_x_o_n_e_s_b_t-members.html | 138 ++++ class_x_b_o_x_o_n_e_s_b_t.html | 401 ++++++++++ class_x_b_o_x_o_n_e_s_b_t__coll__graph.map | 11 + class_x_b_o_x_o_n_e_s_b_t__coll__graph.md5 | 1 + class_x_b_o_x_o_n_e_s_b_t__coll__graph.png | Bin 0 -> 20814 bytes class_x_b_o_x_o_n_e_s_b_t__inherit__graph.map | 5 + class_x_b_o_x_o_n_e_s_b_t__inherit__graph.md5 | 1 + class_x_b_o_x_o_n_e_s_b_t__inherit__graph.png | Bin 0 -> 7233 bytes class_x_b_o_x_o_n_e_s_parser-members.html | 108 +++ class_x_b_o_x_o_n_e_s_parser.html | 321 ++++++++ ...x_b_o_x_o_n_e_s_parser__inherit__graph.map | 3 + ...x_b_o_x_o_n_e_s_parser__inherit__graph.md5 | 1 + ...x_b_o_x_o_n_e_s_parser__inherit__graph.png | Bin 0 -> 3576 bytes classes.html | 77 +- confdescparser_8h_source.html | 2 +- controller_enums_8h.html | 32 +- controller_enums_8h__dep__incl.map | 9 +- controller_enums_8h__dep__incl.md5 | 2 +- controller_enums_8h__dep__incl.png | Bin 33187 -> 38705 bytes controller_enums_8h_source.html | 64 +- files.html | 11 +- functions_a.html | 3 + functions_b.html | 2 + functions_c.html | 1 + functions_d.html | 1 + functions_func_c.html | 1 + functions_func_g.html | 3 + functions_func_h.html | 19 +- functions_func_o.html | 1 + functions_func_p.html | 2 + functions_func_r.html | 2 + functions_func_w.html | 2 +- functions_func_x.html | 6 + functions_g.html | 3 + functions_h.html | 20 +- functions_l.html | 5 + functions_m.html | 7 +- functions_o.html | 1 + functions_p.html | 2 + functions_r.html | 12 +- functions_s.html | 7 +- functions_t.html | 1 + functions_u.html | 3 + functions_v.html | 4 + functions_vars_a.html | 3 + functions_vars_b.html | 2 + functions_vars_d.html | 1 + functions_vars_h.html | 1 + functions_vars_l.html | 5 + functions_vars_m.html | 3 + functions_vars_r.html | 8 + functions_vars_s.html | 3 + functions_vars_t.html | 1 + functions_vars_u.html | 3 + functions_vars_v.html | 4 + functions_vars_x.html | 1 + functions_vars_y.html | 1 + functions_w.html | 2 +- functions_x.html | 7 + functions_y.html | 1 + globals_d.html | 20 +- globals_defs_e.html | 15 + globals_defs_h.html | 16 +- globals_defs_l.html | 2 +- globals_defs_p.html | 7 +- globals_defs_s.html | 22 +- globals_e.html | 15 + globals_enum.html | 1 + globals_eval.html | 21 +- globals_h.html | 16 +- globals_l.html | 2 +- globals_m.html | 3 + globals_p.html | 3 + globals_s.html | 22 +- globals_v.html | 3 + globals_vars_x.html | 3 + globals_w.html | 6 +- globals_x.html | 3 + hidboot_8h.html | 5 +- hidboot_8h__dep__incl.map | 5 +- hidboot_8h__dep__incl.md5 | 2 +- hidboot_8h__dep__incl.png | Bin 7823 -> 9325 bytes hidescriptorparser_8cpp_source.html | 38 +- hidescriptorparser_8h_source.html | 32 +- hidusagestr_8h.html | 63 +- hidusagestr_8h__dep__incl.map | 63 +- hidusagestr_8h__dep__incl.md5 | 2 +- hidusagestr_8h__dep__incl.png | Bin 52063 -> 54252 bytes hierarchy.html | 159 ++-- index.html | 12 +- inherit_graph_54.map | 34 +- inherit_graph_54.md5 | 2 +- inherit_graph_54.png | Bin 99847 -> 14648 bytes inherit_graph_55.map | 6 +- inherit_graph_55.md5 | 2 +- inherit_graph_55.png | Bin 14648 -> 1655 bytes inherit_graph_56.map | 3 + inherit_graph_56.md5 | 1 + inherit_graph_56.png | Bin 0 -> 1606 bytes inherit_graph_57.map | 33 + inherit_graph_57.md5 | 1 + inherit_graph_57.png | Bin 0 -> 95605 bytes inherits.html | 80 +- parsetools_8cpp_source.html | 2 +- parsetools_8h.html | 2 +- parsetools_8h_source.html | 10 +- search/all_1.js | 2 +- search/all_10.js | 5 +- search/all_12.js | 13 +- search/all_13.js | 11 +- search/all_14.js | 2 +- search/all_15.js | 3 +- search/all_16.js | 5 +- search/all_17.js | 4 +- search/all_18.js | 10 +- search/all_19.js | 2 +- search/all_2.js | 4 +- search/all_3.js | 2 +- search/all_4.js | 22 +- search/all_5.js | 5 + search/all_7.js | 6 +- search/all_8.js | 15 +- search/all_c.js | 7 +- search/all_d.js | 1 + search/all_f.js | 2 +- search/classes_10.js | 4 + search/defines_10.js | 1 + search/defines_12.js | 10 +- search/defines_5.js | 5 + search/defines_8.js | 6 +- search/defines_c.js | 2 +- search/enums_3.js | 2 +- search/enumvalues_12.js | 3 +- search/enumvalues_13.js | 2 +- search/enumvalues_3.js | 18 +- search/enumvalues_a.js | 1 + search/files_b.js | 3 + search/functions_14.js | 2 +- search/functions_15.js | 2 + search/functions_2.js | 2 +- search/functions_6.js | 6 +- search/functions_7.js | 7 +- search/functions_d.js | 2 +- search/functions_e.js | 4 +- search/functions_f.js | 4 +- search/variables_1.js | 1 + search/variables_11.js | 9 +- search/variables_12.js | 1 + search/variables_13.js | 2 +- search/variables_14.js | 3 +- search/variables_15.js | 5 +- search/variables_17.js | 3 +- search/variables_18.js | 2 +- search/variables_2.js | 4 +- search/variables_4.js | 2 +- search/variables_8.js | 2 +- search/variables_b.js | 5 +- search/variables_c.js | 1 + struct_xbox_one_s_data-members.html | 105 +++ struct_xbox_one_s_data.html | 171 +++++ struct_xbox_one_s_data__coll__graph.map | 3 + struct_xbox_one_s_data__coll__graph.md5 | 1 + struct_xbox_one_s_data__coll__graph.png | Bin 0 -> 4609 bytes union_xbox_one_s_buttons-members.html | 116 +++ union_xbox_one_s_buttons.html | 354 +++++++++ usbh__midi_8cpp_source.html | 6 +- usbh__midi_8h_source.html | 4 +- usbhid_8h.html | 59 +- usbhid_8h__dep__incl.map | 59 +- usbhid_8h__dep__incl.md5 | 2 +- usbhid_8h__dep__incl.png | Bin 46636 -> 48980 bytes 248 files changed, 5129 insertions(+), 1644 deletions(-) create mode 100644 _x_b_o_x_o_n_e_s_b_t_8h.html create mode 100644 _x_b_o_x_o_n_e_s_b_t_8h__incl.map create mode 100644 _x_b_o_x_o_n_e_s_b_t_8h__incl.md5 create mode 100644 _x_b_o_x_o_n_e_s_b_t_8h__incl.png create mode 100644 _x_b_o_x_o_n_e_s_b_t_8h_source.html create mode 100644 _x_b_o_x_o_n_e_s_parser_8cpp.html create mode 100644 _x_b_o_x_o_n_e_s_parser_8cpp__incl.map create mode 100644 _x_b_o_x_o_n_e_s_parser_8cpp__incl.md5 create mode 100644 _x_b_o_x_o_n_e_s_parser_8cpp__incl.png create mode 100644 _x_b_o_x_o_n_e_s_parser_8cpp_source.html create mode 100644 _x_b_o_x_o_n_e_s_parser_8h.html create mode 100644 _x_b_o_x_o_n_e_s_parser_8h__dep__incl.map create mode 100644 _x_b_o_x_o_n_e_s_parser_8h__dep__incl.md5 create mode 100644 _x_b_o_x_o_n_e_s_parser_8h__dep__incl.png create mode 100644 _x_b_o_x_o_n_e_s_parser_8h__incl.map create mode 100644 _x_b_o_x_o_n_e_s_parser_8h__incl.md5 create mode 100644 _x_b_o_x_o_n_e_s_parser_8h__incl.png create mode 100644 _x_b_o_x_o_n_e_s_parser_8h_source.html create mode 100644 class_x_b_o_x_o_n_e_s_b_t-members.html create mode 100644 class_x_b_o_x_o_n_e_s_b_t.html create mode 100644 class_x_b_o_x_o_n_e_s_b_t__coll__graph.map create mode 100644 class_x_b_o_x_o_n_e_s_b_t__coll__graph.md5 create mode 100644 class_x_b_o_x_o_n_e_s_b_t__coll__graph.png create mode 100644 class_x_b_o_x_o_n_e_s_b_t__inherit__graph.map create mode 100644 class_x_b_o_x_o_n_e_s_b_t__inherit__graph.md5 create mode 100644 class_x_b_o_x_o_n_e_s_b_t__inherit__graph.png create mode 100644 class_x_b_o_x_o_n_e_s_parser-members.html create mode 100644 class_x_b_o_x_o_n_e_s_parser.html create mode 100644 class_x_b_o_x_o_n_e_s_parser__inherit__graph.map create mode 100644 class_x_b_o_x_o_n_e_s_parser__inherit__graph.md5 create mode 100644 class_x_b_o_x_o_n_e_s_parser__inherit__graph.png create mode 100644 inherit_graph_56.map create mode 100644 inherit_graph_56.md5 create mode 100644 inherit_graph_56.png create mode 100644 inherit_graph_57.map create mode 100644 inherit_graph_57.md5 create mode 100644 inherit_graph_57.png create mode 100644 struct_xbox_one_s_data-members.html create mode 100644 struct_xbox_one_s_data.html create mode 100644 struct_xbox_one_s_data__coll__graph.map create mode 100644 struct_xbox_one_s_data__coll__graph.md5 create mode 100644 struct_xbox_one_s_data__coll__graph.png create mode 100644 union_xbox_one_s_buttons-members.html create mode 100644 union_xbox_one_s_buttons.html diff --git a/_b_t_d_8cpp_source.html b/_b_t_d_8cpp_source.html index 9c94b9d3..f4569c38 100644 --- a/_b_t_d_8cpp_source.html +++ b/_b_t_d_8cpp_source.html @@ -86,205 +86,219 @@ var searchBox = new SearchBox("searchBox", "search",false,'Search');
BTD.cpp
-Go to the documentation of this file.
1 /* Copyright (C) 2012 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 "BTD.h"
19 // To enable serial debugging see "settings.h"
20 //#define EXTRADEBUG // Uncomment to get even more debugging data
21 
22 const uint8_t BTD::BTD_CONTROL_PIPE = 0;
23 const uint8_t BTD::BTD_EVENT_PIPE = 1;
24 const uint8_t BTD::BTD_DATAIN_PIPE = 2;
25 const uint8_t BTD::BTD_DATAOUT_PIPE = 3;
26 
28 connectToWii(false),
29 pairWithWii(false),
30 connectToHIDDevice(false),
31 pairWithHIDDevice(false),
32 pUsb(p), // Pointer to USB class instance - mandatory
33 bAddress(0), // Device address - mandatory
34 bNumEP(1), // If config descriptor needs to be parsed
35 qNextPollTime(0), // Reset NextPollTime
36 pollInterval(0),
37 bPollEnable(false) // Don't start polling before dongle is connected
38 {
39  for(uint8_t i = 0; i < BTD_NUM_SERVICES; i++)
40  btService[i] = NULL;
41 
42  Initialize(); // Set all variables, endpoint structs etc. to default values
43 
44  if(pUsb) // Register in USB subsystem
45  pUsb->RegisterDeviceClass(this); // Set devConfig[] entry
46 }
47 
48 uint8_t BTD::ConfigureDevice(uint8_t parent, uint8_t port, bool lowspeed) {
49  const uint8_t constBufSize = sizeof (USB_DEVICE_DESCRIPTOR);
50  uint8_t buf[constBufSize];
51  USB_DEVICE_DESCRIPTOR * udd = reinterpret_cast<USB_DEVICE_DESCRIPTOR*>(buf);
52  uint8_t rcode;
53  UsbDevice *p = NULL;
54  EpInfo *oldep_ptr = NULL;
55 
56  Initialize(); // Set all variables, endpoint structs etc. to default values
57 
58  AddressPool &addrPool = pUsb->GetAddressPool(); // Get memory address of USB device address pool
59 #ifdef EXTRADEBUG
60  Notify(PSTR("\r\nBTD ConfigureDevice"), 0x80);
61 #endif
62 
63  if(bAddress) { // Check if address has already been assigned to an instance
64 #ifdef DEBUG_USB_HOST
65  Notify(PSTR("\r\nAddress in use"), 0x80);
66 #endif
68  }
69 
70  p = addrPool.GetUsbDevicePtr(0); // Get pointer to pseudo device with address 0 assigned
71  if(!p) {
72 #ifdef DEBUG_USB_HOST
73  Notify(PSTR("\r\nAddress not found"), 0x80);
74 #endif
76  }
77 
78  if(!p->epinfo) {
79 #ifdef DEBUG_USB_HOST
80  Notify(PSTR("\r\nepinfo is null"), 0x80);
81 #endif
83  }
84 
85  oldep_ptr = p->epinfo; // Save old pointer to EP_RECORD of address 0
86  p->epinfo = epInfo; // Temporary assign new pointer to epInfo to p->epinfo in order to avoid toggle inconsistence
87  p->lowspeed = lowspeed;
88  rcode = pUsb->getDevDescr(0, 0, constBufSize, (uint8_t*)buf); // Get device descriptor - addr, ep, nbytes, data
89 
90  p->epinfo = oldep_ptr; // Restore p->epinfo
91 
92  if(rcode)
93  goto FailGetDevDescr;
94 
95  bAddress = addrPool.AllocAddress(parent, false, port); // Allocate new address according to device class
96 
97  if(!bAddress) {
98 #ifdef DEBUG_USB_HOST
99  Notify(PSTR("\r\nOut of address space"), 0x80);
100 #endif
102  }
103 
104  if (udd->bDeviceClass == 0x09) // Some dongles have an USB hub inside
105  goto FailHub;
106 
107  epInfo[0].maxPktSize = udd->bMaxPacketSize0; // Extract Max Packet Size from device descriptor
108  epInfo[1].epAddr = udd->bNumConfigurations; // Steal and abuse from epInfo structure to save memory
109 
110  VID = udd->idVendor;
111  PID = udd->idProduct;
112 
114 
115 FailHub:
116 #ifdef DEBUG_USB_HOST
117  Notify(PSTR("\r\nPlease create a hub instance in your code: \"USBHub Hub1(&Usb);\""), 0x80);
118 #endif
119  pUsb->setAddr(bAddress, 0, 0); // Reset address
121  Release();
122  return rcode;
123 
124 FailGetDevDescr:
125 #ifdef DEBUG_USB_HOST
126  NotifyFailGetDevDescr(rcode);
127 #endif
128  if(rcode != hrJERR)
130  Release();
131  return rcode;
132 };
133 
134 uint8_t BTD::Init(uint8_t parent __attribute__((unused)), uint8_t port __attribute__((unused)), bool lowspeed) {
135  uint8_t rcode;
136  uint8_t num_of_conf = epInfo[1].epAddr; // Number of configurations
137  epInfo[1].epAddr = 0;
138 
139  AddressPool &addrPool = pUsb->GetAddressPool();
140 #ifdef EXTRADEBUG
141  Notify(PSTR("\r\nBTD Init"), 0x80);
142 #endif
143  UsbDevice *p = addrPool.GetUsbDevicePtr(bAddress); // Get pointer to assigned address record
144 
145  if(!p) {
146 #ifdef DEBUG_USB_HOST
147  Notify(PSTR("\r\nAddress not found"), 0x80);
148 #endif
150  }
151 
152  delay(300); // Assign new address to the device
153 
154  rcode = pUsb->setAddr(0, 0, bAddress); // Assign new address to the device
155  if(rcode) {
156 #ifdef DEBUG_USB_HOST
157  Notify(PSTR("\r\nsetAddr: "), 0x80);
158  D_PrintHex<uint8_t > (rcode, 0x80);
159 #endif
160  p->lowspeed = false;
161  goto Fail;
162  }
163 #ifdef EXTRADEBUG
164  Notify(PSTR("\r\nAddr: "), 0x80);
165  D_PrintHex<uint8_t > (bAddress, 0x80);
166 #endif
167 
168  p->lowspeed = false;
169 
170  p = addrPool.GetUsbDevicePtr(bAddress); // Get pointer to assigned address record
171  if(!p) {
172 #ifdef DEBUG_USB_HOST
173  Notify(PSTR("\r\nAddress not found"), 0x80);
174 #endif
176  }
177 
178  p->lowspeed = lowspeed;
179 
180  rcode = pUsb->setEpInfoEntry(bAddress, 1, epInfo); // Assign epInfo to epinfo pointer - only EP0 is known
181  if(rcode)
182  goto FailSetDevTblEntry;
183 
184  if(VID == PS3_VID && (PID == PS3_PID || PID == PS3NAVIGATION_PID || PID == PS3MOVE_PID)) {
185  delay(100);
186  rcode = pUsb->setConf(bAddress, epInfo[ BTD_CONTROL_PIPE ].epAddr, 1); // We only need the Control endpoint, so we don't have to initialize the other endpoints of device
187  if(rcode)
188  goto FailSetConfDescr;
189 
190 #ifdef DEBUG_USB_HOST
191  if(PID == PS3_PID || PID == PS3NAVIGATION_PID) {
192  if(PID == PS3_PID)
193  Notify(PSTR("\r\nDualshock 3 Controller Connected"), 0x80);
194  else // It must be a navigation controller
195  Notify(PSTR("\r\nNavigation Controller Connected"), 0x80);
196  } else // It must be a Motion controller
197  Notify(PSTR("\r\nMotion Controller Connected"), 0x80);
198 #endif
199 
200  if(my_bdaddr[0] == 0x00 && my_bdaddr[1] == 0x00 && my_bdaddr[2] == 0x00 && my_bdaddr[3] == 0x00 && my_bdaddr[4] == 0x00 && my_bdaddr[5] == 0x00) {
201 #ifdef DEBUG_USB_HOST
202  Notify(PSTR("\r\nPlease plug in the dongle before trying to pair with the PS3 Controller\r\nor set the Bluetooth address in the constructor of the PS3BT class"), 0x80);
203 #endif
204  } else {
205  if(PID == PS3_PID || PID == PS3NAVIGATION_PID)
206  setBdaddr(my_bdaddr); // Set internal Bluetooth address
207  else
208  setMoveBdaddr(my_bdaddr); // Set internal Bluetooth address
209 #ifdef DEBUG_USB_HOST
210  Notify(PSTR("\r\nBluetooth Address was set to: "), 0x80);
211  for(int8_t i = 5; i > 0; i--) {
212  D_PrintHex<uint8_t > (my_bdaddr[i], 0x80);
213  Notify(PSTR(":"), 0x80);
214  }
215  D_PrintHex<uint8_t > (my_bdaddr[0], 0x80);
216 #endif
217  }
218 
219  pUsb->setConf(bAddress, epInfo[ BTD_CONTROL_PIPE ].epAddr, 0); // Reset configuration value
220  pUsb->setAddr(bAddress, 0, 0); // Reset address
221  Release(); // Release device
223  } else {
224  // Check if attached device is a Bluetooth dongle and fill endpoint data structure
225  // First interface in the configuration must have Bluetooth assigned Class/Subclass/Protocol
226  // And 3 endpoints - interrupt-IN, bulk-IN, bulk-OUT, not necessarily in this order
227  for(uint8_t i = 0; i < num_of_conf; i++) {
228  if((VID == IOGEAR_GBU521_VID && PID == IOGEAR_GBU521_PID) || (VID == BELKIN_F8T065BF_VID && PID == BELKIN_F8T065BF_PID)) {
229  ConfigDescParser<USB_CLASS_VENDOR_SPECIFIC, WI_SUBCLASS_RF, WI_PROTOCOL_BT, CP_MASK_COMPARE_ALL> confDescrParser(this); // Workaround issue with some dongles
230  rcode = pUsb->getConfDescr(bAddress, 0, i, &confDescrParser);
231  } else {
232  ConfigDescParser<USB_CLASS_WIRELESS_CTRL, WI_SUBCLASS_RF, WI_PROTOCOL_BT, CP_MASK_COMPARE_ALL> confDescrParser(this); // Set class id according to the specification
233  rcode = pUsb->getConfDescr(bAddress, 0, i, &confDescrParser);
234  }
235  if(rcode) // Check error code
236  goto FailGetConfDescr;
237  if(bNumEP >= BTD_MAX_ENDPOINTS) // All endpoints extracted
238  break;
239  }
240 
242  goto FailUnknownDevice;
243 
244  // Assign epInfo to epinfo pointer - this time all 3 endpoins
245  rcode = pUsb->setEpInfoEntry(bAddress, bNumEP, epInfo);
246  if(rcode)
247  goto FailSetDevTblEntry;
248 
249  // Set Configuration Value
250  rcode = pUsb->setConf(bAddress, epInfo[ BTD_CONTROL_PIPE ].epAddr, bConfNum);
251  if(rcode)
252  goto FailSetConfDescr;
253 
254  hci_num_reset_loops = 100; // only loop 100 times before trying to send the hci reset command
255  hci_counter = 0;
256  hci_state = HCI_INIT_STATE;
257  waitingForConnection = false;
258  bPollEnable = true;
259 
260 #ifdef DEBUG_USB_HOST
261  Notify(PSTR("\r\nBluetooth Dongle Initialized"), 0x80);
262 #endif
263  }
264  return 0; // Successful configuration
265 
266  /* Diagnostic messages */
267 FailSetDevTblEntry:
268 #ifdef DEBUG_USB_HOST
270  goto Fail;
271 #endif
272 
273 FailGetConfDescr:
274 #ifdef DEBUG_USB_HOST
276  goto Fail;
277 #endif
278 
279 FailSetConfDescr:
280 #ifdef DEBUG_USB_HOST
282 #endif
283  goto Fail;
284 
285 FailUnknownDevice:
286 #ifdef DEBUG_USB_HOST
287  NotifyFailUnknownDevice(VID, PID);
288 #endif
289  pUsb->setAddr(bAddress, 0, 0); // Reset address
291 Fail:
292 #ifdef DEBUG_USB_HOST
293  Notify(PSTR("\r\nBTD Init Failed, error code: "), 0x80);
294  NotifyFail(rcode);
295 #endif
296  Release();
297  return rcode;
298 }
299 
300 void BTD::Initialize() {
301  uint8_t i;
302  for(i = 0; i < BTD_MAX_ENDPOINTS; i++) {
303  epInfo[i].epAddr = 0;
304  epInfo[i].maxPktSize = (i) ? 0 : 8;
305  epInfo[i].bmSndToggle = 0;
306  epInfo[i].bmRcvToggle = 0;
308  }
309  for(i = 0; i < BTD_NUM_SERVICES; i++) {
310  if(btService[i])
311  btService[i]->Reset(); // Reset all Bluetooth services
312  }
313 
314  connectToWii = false;
315  incomingWii = false;
316  connectToHIDDevice = false;
317  incomingHIDDevice = false;
318  incomingPS4 = false;
319  bAddress = 0; // Clear device address
320  bNumEP = 1; // Must have to be reset to 1
321  qNextPollTime = 0; // Reset next poll time
322  pollInterval = 0;
323  bPollEnable = false; // Don't start polling before dongle is connected
324 }
325 
326 /* Extracts interrupt-IN, bulk-IN, bulk-OUT endpoint information from config descriptor */
327 void BTD::EndpointXtract(uint8_t conf, uint8_t iface __attribute__((unused)), uint8_t alt, uint8_t proto __attribute__((unused)), const USB_ENDPOINT_DESCRIPTOR *pep) {
328  //ErrorMessage<uint8_t>(PSTR("Conf.Val"),conf);
329  //ErrorMessage<uint8_t>(PSTR("Iface Num"),iface);
330  //ErrorMessage<uint8_t>(PSTR("Alt.Set"),alt);
331 
332  if(alt) // Wrong interface - by BT spec, no alt setting
333  return;
334 
335  bConfNum = conf;
336  uint8_t index;
337 
338  if((pep->bmAttributes & bmUSB_TRANSFER_TYPE) == USB_TRANSFER_TYPE_INTERRUPT && (pep->bEndpointAddress & 0x80) == 0x80) { // Interrupt In endpoint found
339  index = BTD_EVENT_PIPE;
341  } else if((pep->bmAttributes & bmUSB_TRANSFER_TYPE) == USB_TRANSFER_TYPE_BULK) // Bulk endpoint found
342  index = ((pep->bEndpointAddress & 0x80) == 0x80) ? BTD_DATAIN_PIPE : BTD_DATAOUT_PIPE;
343  else
344  return;
345 
346  // Fill the rest of endpoint data structure
347  epInfo[index].epAddr = (pep->bEndpointAddress & 0x0F);
348  epInfo[index].maxPktSize = (uint8_t)pep->wMaxPacketSize;
349 #ifdef EXTRADEBUG
351 #endif
352  if(pollInterval < pep->bInterval) // Set the polling interval as the largest polling interval obtained from endpoints
353  pollInterval = pep->bInterval;
354  bNumEP++;
355 }
356 
357 void BTD::PrintEndpointDescriptor(const USB_ENDPOINT_DESCRIPTOR* ep_ptr __attribute__((unused))) {
358 #ifdef EXTRADEBUG
359  Notify(PSTR("\r\nEndpoint descriptor:"), 0x80);
360  Notify(PSTR("\r\nLength:\t\t"), 0x80);
361  D_PrintHex<uint8_t > (ep_ptr->bLength, 0x80);
362  Notify(PSTR("\r\nType:\t\t"), 0x80);
363  D_PrintHex<uint8_t > (ep_ptr->bDescriptorType, 0x80);
364  Notify(PSTR("\r\nAddress:\t"), 0x80);
365  D_PrintHex<uint8_t > (ep_ptr->bEndpointAddress, 0x80);
366  Notify(PSTR("\r\nAttributes:\t"), 0x80);
367  D_PrintHex<uint8_t > (ep_ptr->bmAttributes, 0x80);
368  Notify(PSTR("\r\nMaxPktSize:\t"), 0x80);
369  D_PrintHex<uint16_t > (ep_ptr->wMaxPacketSize, 0x80);
370  Notify(PSTR("\r\nPoll Intrv:\t"), 0x80);
371  D_PrintHex<uint8_t > (ep_ptr->bInterval, 0x80);
372 #endif
373 }
374 
375 /* Performs a cleanup after failed Init() attempt */
376 uint8_t BTD::Release() {
377  Initialize(); // Set all variables, endpoint structs etc. to default values
379  return 0;
380 }
381 
382 uint8_t BTD::Poll() {
383  if(!bPollEnable)
384  return 0;
385  if((int32_t)((uint32_t)millis() - qNextPollTime) >= 0L) { // Don't poll if shorter than polling interval
386  qNextPollTime = (uint32_t)millis() + pollInterval; // Set new poll time
387  HCI_event_task(); // Poll the HCI event pipe
388  HCI_task(); // HCI state machine
389  ACL_event_task(); // Poll the ACL input pipe too
390  }
391  return 0;
392 }
393 
395  for(uint8_t i = 0; i < BTD_NUM_SERVICES; i++)
396  if(btService[i])
397  btService[i]->disconnect();
398 };
399 
400 void BTD::HCI_event_task() {
401  uint16_t length = BULK_MAXPKTSIZE; // Request more than 16 bytes anyway, the inTransfer routine will take care of this
402  uint8_t rcode = pUsb->inTransfer(bAddress, epInfo[ BTD_EVENT_PIPE ].epAddr, &length, hcibuf, pollInterval); // Input on endpoint 1
403 
404  if(!rcode || rcode == hrNAK) { // Check for errors
405  switch(hcibuf[0]) { // Switch on event type
406  case EV_COMMAND_COMPLETE:
407  if(!hcibuf[5]) { // Check if command succeeded
408  hci_set_flag(HCI_FLAG_CMD_COMPLETE); // Set command complete flag
409  if((hcibuf[3] == 0x01) && (hcibuf[4] == 0x10)) { // Parameters from read local version information
410  hci_version = hcibuf[6]; // Used to check if it supports 2.0+EDR - see http://www.bluetooth.org/Technical/AssignedNumbers/hci.htm
412  } else if((hcibuf[3] == 0x09) && (hcibuf[4] == 0x10)) { // Parameters from read local bluetooth address
413  for(uint8_t i = 0; i < 6; i++)
414  my_bdaddr[i] = hcibuf[6 + i];
416  }
417  }
418  break;
419 
420  case EV_COMMAND_STATUS:
421  if(hcibuf[2]) { // Show status on serial if not OK
422 #ifdef DEBUG_USB_HOST
423  Notify(PSTR("\r\nHCI Command Failed: "), 0x80);
424  D_PrintHex<uint8_t > (hcibuf[2], 0x80);
425 #endif
426  }
427  break;
428 
429  case EV_INQUIRY_COMPLETE:
430  if(inquiry_counter >= 5 && (pairWithWii || pairWithHIDDevice)) {
431  inquiry_counter = 0;
432 #ifdef DEBUG_USB_HOST
433  if(pairWithWii)
434  Notify(PSTR("\r\nCouldn't find Wiimote"), 0x80);
435  else
436  Notify(PSTR("\r\nCouldn't find HID device"), 0x80);
437 #endif
438  connectToWii = false;
439  pairWithWii = false;
440  connectToHIDDevice = false;
441  pairWithHIDDevice = false;
442  hci_state = HCI_SCANNING_STATE;
443  }
444  inquiry_counter++;
445  break;
446 
447  case EV_INQUIRY_RESULT:
448  if(hcibuf[2]) { // Check that there is more than zero responses
449 #ifdef EXTRADEBUG
450  Notify(PSTR("\r\nNumber of responses: "), 0x80);
451  Notify(hcibuf[2], 0x80);
452 #endif
453  for(uint8_t i = 0; i < hcibuf[2]; i++) {
454  uint8_t offset = 8 * hcibuf[2] + 3 * i;
455 
456  for(uint8_t j = 0; j < 3; j++)
457  classOfDevice[j] = hcibuf[j + 4 + offset];
458 
459 #ifdef EXTRADEBUG
460  Notify(PSTR("\r\nClass of device: "), 0x80);
461  D_PrintHex<uint8_t > (classOfDevice[2], 0x80);
462  Notify(PSTR(" "), 0x80);
463  D_PrintHex<uint8_t > (classOfDevice[1], 0x80);
464  Notify(PSTR(" "), 0x80);
465  D_PrintHex<uint8_t > (classOfDevice[0], 0x80);
466 #endif
467 
468  if(pairWithWii && classOfDevice[2] == 0x00 && (classOfDevice[1] & 0x05) && (classOfDevice[0] & 0x0C)) { // See http://wiibrew.org/wiki/Wiimote#SDP_information
469  checkRemoteName = true; // Check remote name to distinguish between the different controllers
470 
471  for(uint8_t j = 0; j < 6; j++)
472  disc_bdaddr[j] = hcibuf[j + 3 + 6 * i];
473 
475  break;
476  } else if(pairWithHIDDevice && (classOfDevice[1] & 0x05) && (classOfDevice[0] & 0xC8)) { // Check if it is a mouse, keyboard or a gamepad - see: http://bluetooth-pentest.narod.ru/software/bluetooth_class_of_device-service_generator.html
477 #ifdef DEBUG_USB_HOST
478  if(classOfDevice[0] & 0x80)
479  Notify(PSTR("\r\nMouse found"), 0x80);
480  if(classOfDevice[0] & 0x40)
481  Notify(PSTR("\r\nKeyboard found"), 0x80);
482  if(classOfDevice[0] & 0x08)
483  Notify(PSTR("\r\nGamepad found"), 0x80);
484 #endif
485 
486  for(uint8_t j = 0; j < 6; j++)
487  disc_bdaddr[j] = hcibuf[j + 3 + 6 * i];
488 
490  break;
491  }
492  }
493  }
494  break;
495 
496  case EV_CONNECT_COMPLETE:
498  if(!hcibuf[2]) { // Check if connected OK
499 #ifdef EXTRADEBUG
500  Notify(PSTR("\r\nConnection established"), 0x80);
501 #endif
502  hci_handle = hcibuf[3] | ((hcibuf[4] & 0x0F) << 8); // Store the handle for the ACL connection
503  hci_set_flag(HCI_FLAG_CONNECT_COMPLETE); // Set connection complete flag
504  } else {
505  hci_state = HCI_CHECK_DEVICE_SERVICE;
506 #ifdef DEBUG_USB_HOST
507  Notify(PSTR("\r\nConnection Failed: "), 0x80);
508  D_PrintHex<uint8_t > (hcibuf[2], 0x80);
509 #endif
510  }
511  break;
512 
514  if(!hcibuf[2]) { // Check if disconnected OK
515  hci_set_flag(HCI_FLAG_DISCONNECT_COMPLETE); // Set disconnect command complete flag
516  hci_clear_flag(HCI_FLAG_CONNECT_COMPLETE); // Clear connection complete flag
517  }
518  break;
519 
521  if(!hcibuf[2]) { // Check if reading is OK
522  for(uint8_t i = 0; i < min(sizeof (remote_name), sizeof (hcibuf) - 9); i++) {
523  remote_name[i] = hcibuf[9 + i];
524  if(remote_name[i] == '\0') // End of string
525  break;
526  }
527  // TODO: Altid sæt '\0' i remote name!
529  }
530  break;
531 
532  case EV_INCOMING_CONNECT:
533  for(uint8_t i = 0; i < 6; i++)
534  disc_bdaddr[i] = hcibuf[i + 2];
535 
536  for(uint8_t i = 0; i < 3; i++)
537  classOfDevice[i] = hcibuf[i + 8];
538 
539  if((classOfDevice[1] & 0x05) && (classOfDevice[0] & 0xC8)) { // Check if it is a mouse, keyboard or a gamepad
540 #ifdef DEBUG_USB_HOST
541  if(classOfDevice[0] & 0x80)
542  Notify(PSTR("\r\nMouse is connecting"), 0x80);
543  if(classOfDevice[0] & 0x40)
544  Notify(PSTR("\r\nKeyboard is connecting"), 0x80);
545  if(classOfDevice[0] & 0x08)
546  Notify(PSTR("\r\nGamepad is connecting"), 0x80);
547 #endif
548  incomingHIDDevice = true;
549  }
550 
551 #ifdef EXTRADEBUG
552  Notify(PSTR("\r\nClass of device: "), 0x80);
553  D_PrintHex<uint8_t > (classOfDevice[2], 0x80);
554  Notify(PSTR(" "), 0x80);
555  D_PrintHex<uint8_t > (classOfDevice[1], 0x80);
556  Notify(PSTR(" "), 0x80);
557  D_PrintHex<uint8_t > (classOfDevice[0], 0x80);
558 #endif
560  break;
561 
562  case EV_PIN_CODE_REQUEST:
563  if(pairWithWii) {
564 #ifdef DEBUG_USB_HOST
565  Notify(PSTR("\r\nPairing with Wiimote"), 0x80);
566 #endif
568  } else if(btdPin != NULL) {
569 #ifdef DEBUG_USB_HOST
570  Notify(PSTR("\r\nBluetooth pin is set too: "), 0x80);
571  NotifyStr(btdPin, 0x80);
572 #endif
574  } else {
575 #ifdef DEBUG_USB_HOST
576  Notify(PSTR("\r\nNo pin was set"), 0x80);
577 #endif
579  }
580  break;
581 
582  case EV_LINK_KEY_REQUEST:
583 #ifdef DEBUG_USB_HOST
584  Notify(PSTR("\r\nReceived Key Request"), 0x80);
585 #endif
587  break;
588 
590  if(!hcibuf[2]) { // Check if pairing was successful
591  if(pairWithWii && !connectToWii) {
592 #ifdef DEBUG_USB_HOST
593  Notify(PSTR("\r\nPairing successful with Wiimote"), 0x80);
594 #endif
595  connectToWii = true; // Used to indicate to the Wii service, that it should connect to this device
596  } else if(pairWithHIDDevice && !connectToHIDDevice) {
597 #ifdef DEBUG_USB_HOST
598  Notify(PSTR("\r\nPairing successful with HID device"), 0x80);
599 #endif
600  connectToHIDDevice = true; // Used to indicate to the BTHID service, that it should connect to this device
601  }
602  } else {
603 #ifdef DEBUG_USB_HOST
604  Notify(PSTR("\r\nPairing Failed: "), 0x80);
605  D_PrintHex<uint8_t > (hcibuf[2], 0x80);
606 #endif
608  hci_state = HCI_DISCONNECT_STATE;
609  }
610  break;
611  /* We will just ignore the following events */
612  case EV_NUM_COMPLETE_PKT:
613  case EV_ROLE_CHANGED:
615  case EV_LOOPBACK_COMMAND:
618  case EV_MAX_SLOTS_CHANGE:
623  break;
624 #ifdef EXTRADEBUG
625  default:
626  if(hcibuf[0] != 0x00) {
627  Notify(PSTR("\r\nUnmanaged HCI Event: "), 0x80);
628  D_PrintHex<uint8_t > (hcibuf[0], 0x80);
629  }
630  break;
631 #endif
632  } // Switch
633  }
634 #ifdef EXTRADEBUG
635  else {
636  Notify(PSTR("\r\nHCI event error: "), 0x80);
637  D_PrintHex<uint8_t > (rcode, 0x80);
638  }
639 #endif
640 }
641 
642 /* Poll Bluetooth and print result */
643 void BTD::HCI_task() {
644  switch(hci_state) {
645  case HCI_INIT_STATE:
646  hci_counter++;
647  if(hci_counter > hci_num_reset_loops) { // wait until we have looped x times to clear any old events
648  hci_reset();
649  hci_state = HCI_RESET_STATE;
650  hci_counter = 0;
651  }
652  break;
653 
654  case HCI_RESET_STATE:
655  hci_counter++;
657  hci_counter = 0;
658 #ifdef DEBUG_USB_HOST
659  Notify(PSTR("\r\nHCI Reset complete"), 0x80);
660 #endif
661  hci_state = HCI_CLASS_STATE;
663  } else if(hci_counter > hci_num_reset_loops) {
664  hci_num_reset_loops *= 10;
665  if(hci_num_reset_loops > 2000)
666  hci_num_reset_loops = 2000;
667 #ifdef DEBUG_USB_HOST
668  Notify(PSTR("\r\nNo response to HCI Reset"), 0x80);
669 #endif
670  hci_state = HCI_INIT_STATE;
671  hci_counter = 0;
672  }
673  break;
674 
675  case HCI_CLASS_STATE:
677 #ifdef DEBUG_USB_HOST
678  Notify(PSTR("\r\nWrite class of device"), 0x80);
679 #endif
680  hci_state = HCI_BDADDR_STATE;
681  hci_read_bdaddr();
682  }
683  break;
684 
685  case HCI_BDADDR_STATE:
687 #ifdef DEBUG_USB_HOST
688  Notify(PSTR("\r\nLocal Bluetooth Address: "), 0x80);
689  for(int8_t i = 5; i > 0; i--) {
690  D_PrintHex<uint8_t > (my_bdaddr[i], 0x80);
691  Notify(PSTR(":"), 0x80);
692  }
693  D_PrintHex<uint8_t > (my_bdaddr[0], 0x80);
694 #endif
696  hci_state = HCI_LOCAL_VERSION_STATE;
697  }
698  break;
699 
700  case HCI_LOCAL_VERSION_STATE: // The local version is used by the PS3BT class
702  if(btdName != NULL) {
704  hci_state = HCI_SET_NAME_STATE;
705  } else
706  hci_state = HCI_CHECK_DEVICE_SERVICE;
707  }
708  break;
709 
710  case HCI_SET_NAME_STATE:
712 #ifdef DEBUG_USB_HOST
713  Notify(PSTR("\r\nThe name is set to: "), 0x80);
714  NotifyStr(btdName, 0x80);
715 #endif
716  hci_state = HCI_CHECK_DEVICE_SERVICE;
717  }
718  break;
719 
721  if(pairWithHIDDevice || pairWithWii) { // Check if it should try to connect to a Wiimote
722 #ifdef DEBUG_USB_HOST
723  if(pairWithWii)
724  Notify(PSTR("\r\nStarting inquiry\r\nPress 1 & 2 on the Wiimote\r\nOr press the SYNC button if you are using a Wii U Pro Controller or a Wii Balance Board"), 0x80);
725  else
726  Notify(PSTR("\r\nPlease enable discovery of your device"), 0x80);
727 #endif
728  hci_inquiry();
729  hci_state = HCI_INQUIRY_STATE;
730  } else
731  hci_state = HCI_SCANNING_STATE; // Don't try to connect to a Wiimote
732  break;
733 
734  case HCI_INQUIRY_STATE:
736  hci_inquiry_cancel(); // Stop inquiry
737 #ifdef DEBUG_USB_HOST
738  if(pairWithWii)
739  Notify(PSTR("\r\nWiimote found"), 0x80);
740  else
741  Notify(PSTR("\r\nHID device found"), 0x80);
742 
743  Notify(PSTR("\r\nNow just create the instance like so:"), 0x80);
744  if(pairWithWii)
745  Notify(PSTR("\r\nWII Wii(&Btd);"), 0x80);
746  else
747  Notify(PSTR("\r\nBTHID bthid(&Btd);"), 0x80);
748 
749  Notify(PSTR("\r\nAnd then press any button on the "), 0x80);
750  if(pairWithWii)
751  Notify(PSTR("Wiimote"), 0x80);
752  else
753  Notify(PSTR("device"), 0x80);
754 #endif
755  if(checkRemoteName) {
756  hci_remote_name(); // We need to know the name to distinguish between the Wiimote, the new Wiimote with Motion Plus inside, a Wii U Pro Controller and a Wii Balance Board
757  hci_state = HCI_REMOTE_NAME_STATE;
758  } else
759  hci_state = HCI_CONNECT_DEVICE_STATE;
760  }
761  break;
762 
765 #ifdef DEBUG_USB_HOST
766  if(pairWithWii)
767  Notify(PSTR("\r\nConnecting to Wiimote"), 0x80);
768  else
769  Notify(PSTR("\r\nConnecting to HID device"), 0x80);
770 #endif
771  checkRemoteName = false;
772  hci_connect();
773  hci_state = HCI_CONNECTED_DEVICE_STATE;
774  }
775  break;
776 
780 #ifdef DEBUG_USB_HOST
781  if(pairWithWii)
782  Notify(PSTR("\r\nConnected to Wiimote"), 0x80);
783  else
784  Notify(PSTR("\r\nConnected to HID device"), 0x80);
785 #endif
786  hci_authentication_request(); // This will start the pairing with the Wiimote
787  hci_state = HCI_SCANNING_STATE;
788  } else {
789 #ifdef DEBUG_USB_HOST
790  Notify(PSTR("\r\nTrying to connect one more time..."), 0x80);
791 #endif
792  hci_connect(); // Try to connect one more time
793  }
794  }
795  break;
796 
797  case HCI_SCANNING_STATE:
799 #ifdef DEBUG_USB_HOST
800  Notify(PSTR("\r\nWait For Incoming Connection Request"), 0x80);
801 #endif
803  waitingForConnection = true;
804  hci_state = HCI_CONNECT_IN_STATE;
805  }
806  break;
807 
810  waitingForConnection = false;
811 #ifdef DEBUG_USB_HOST
812  Notify(PSTR("\r\nIncoming Connection Request"), 0x80);
813 #endif
814  hci_remote_name();
815  hci_state = HCI_REMOTE_NAME_STATE;
817  hci_state = HCI_DISCONNECT_STATE;
818  break;
819 
822 #ifdef DEBUG_USB_HOST
823  Notify(PSTR("\r\nRemote Name: "), 0x80);
824  for(uint8_t i = 0; i < strlen(remote_name); i++)
825  Notifyc(remote_name[i], 0x80);
826 #endif
827  if(strncmp((const char*)remote_name, "Nintendo", 8) == 0) {
828  incomingWii = true;
829  motionPlusInside = false;
830  wiiUProController = false;
831  pairWiiUsingSync = false;
832 #ifdef DEBUG_USB_HOST
833  Notify(PSTR("\r\nWiimote is connecting"), 0x80);
834 #endif
835  if(strncmp((const char*)remote_name, "Nintendo RVL-CNT-01-TR", 22) == 0) {
836 #ifdef DEBUG_USB_HOST
837  Notify(PSTR(" with Motion Plus Inside"), 0x80);
838 #endif
839  motionPlusInside = true;
840  } else if(strncmp((const char*)remote_name, "Nintendo RVL-CNT-01-UC", 22) == 0) {
841 #ifdef DEBUG_USB_HOST
842  Notify(PSTR(" - Wii U Pro Controller"), 0x80);
843 #endif
844  wiiUProController = motionPlusInside = pairWiiUsingSync = true;
845  } else if(strncmp((const char*)remote_name, "Nintendo RVL-WBC-01", 19) == 0) {
846 #ifdef DEBUG_USB_HOST
847  Notify(PSTR(" - Wii Balance Board"), 0x80);
848 #endif
849  pairWiiUsingSync = true;
850  }
851  }
852  if(classOfDevice[2] == 0 && classOfDevice[1] == 0x25 && classOfDevice[0] == 0x08 && strncmp((const char*)remote_name, "Wireless Controller", 19) == 0) {
853 #ifdef DEBUG_USB_HOST
854  Notify(PSTR("\r\nPS4 controller is connecting"), 0x80);
855 #endif
856  incomingPS4 = true;
857  }
858  if(pairWithWii && checkRemoteName)
859  hci_state = HCI_CONNECT_DEVICE_STATE;
860  else {
862  hci_state = HCI_CONNECTED_STATE;
863  }
864  }
865  break;
866 
867  case HCI_CONNECTED_STATE:
869 #ifdef DEBUG_USB_HOST
870  Notify(PSTR("\r\nConnected to Device: "), 0x80);
871  for(int8_t i = 5; i > 0; i--) {
872  D_PrintHex<uint8_t > (disc_bdaddr[i], 0x80);
873  Notify(PSTR(":"), 0x80);
874  }
875  D_PrintHex<uint8_t > (disc_bdaddr[0], 0x80);
876 #endif
877  if(incomingPS4)
878  connectToHIDDevice = true; // We should always connect to the PS4 controller
879 
880  // Clear these flags for a new connection
881  l2capConnectionClaimed = false;
882  sdpConnectionClaimed = false;
883  rfcommConnectionClaimed = false;
884 
885  hci_event_flag = 0;
886  hci_state = HCI_DONE_STATE;
887  }
888  break;
889 
890  case HCI_DONE_STATE:
891  hci_counter++;
892  if(hci_counter > 1000) { // Wait until we have looped 1000 times to make sure that the L2CAP connection has been started
893  hci_counter = 0;
894  hci_state = HCI_SCANNING_STATE;
895  }
896  break;
897 
900 #ifdef DEBUG_USB_HOST
901  Notify(PSTR("\r\nHCI Disconnected from Device"), 0x80);
902 #endif
903  hci_event_flag = 0; // Clear all flags
904 
905  // Reset all buffers
906  memset(hcibuf, 0, BULK_MAXPKTSIZE);
907  memset(l2capinbuf, 0, BULK_MAXPKTSIZE);
908 
910  connectToHIDDevice = incomingHIDDevice = pairWithHIDDevice = checkRemoteName = false;
911  incomingPS4 = false;
912 
913  hci_state = HCI_SCANNING_STATE;
914  }
915  break;
916  default:
917  break;
918  }
919 }
920 
921 void BTD::ACL_event_task() {
922  uint16_t length = BULK_MAXPKTSIZE;
923  uint8_t rcode = pUsb->inTransfer(bAddress, epInfo[ BTD_DATAIN_PIPE ].epAddr, &length, l2capinbuf, pollInterval); // Input on endpoint 2
924 
925  if(!rcode) { // Check for errors
926  if(length > 0) { // Check if any data was read
927  for(uint8_t i = 0; i < BTD_NUM_SERVICES; i++) {
928  if(btService[i])
929  btService[i]->ACLData(l2capinbuf);
930  }
931  }
932  }
933 #ifdef EXTRADEBUG
934  else if(rcode != hrNAK) {
935  Notify(PSTR("\r\nACL data in error: "), 0x80);
936  D_PrintHex<uint8_t > (rcode, 0x80);
937  }
938 #endif
939  for(uint8_t i = 0; i < BTD_NUM_SERVICES; i++)
940  if(btService[i])
941  btService[i]->Run();
942 }
943 
944 /************************************************************/
945 /* HCI Commands */
946 
947 /************************************************************/
948 void BTD::HCI_Command(uint8_t* data, uint16_t nbytes) {
950  pUsb->ctrlReq(bAddress, epInfo[ BTD_CONTROL_PIPE ].epAddr, bmREQ_HCI_OUT, 0x00, 0x00, 0x00, 0x00, nbytes, nbytes, data, NULL);
951 }
952 
954  hci_event_flag = 0; // Clear all the flags
955  hcibuf[0] = 0x03; // HCI OCF = 3
956  hcibuf[1] = 0x03 << 2; // HCI OGF = 3
957  hcibuf[2] = 0x00;
958 
959  HCI_Command(hcibuf, 3);
960 }
961 
964  hcibuf[0] = 0x1A; // HCI OCF = 1A
965  hcibuf[1] = 0x03 << 2; // HCI OGF = 3
966  hcibuf[2] = 0x01; // parameter length = 1
967  if(btdName != NULL)
968  hcibuf[3] = 0x03; // Inquiry Scan enabled. Page Scan enabled.
969  else
970  hcibuf[3] = 0x02; // Inquiry Scan disabled. Page Scan enabled.
971 
972  HCI_Command(hcibuf, 4);
973 }
974 
976  hcibuf[0] = 0x1A; // HCI OCF = 1A
977  hcibuf[1] = 0x03 << 2; // HCI OGF = 3
978  hcibuf[2] = 0x01; // parameter length = 1
979  hcibuf[3] = 0x00; // Inquiry Scan disabled. Page Scan disabled.
980 
981  HCI_Command(hcibuf, 4);
982 }
983 
986  hcibuf[0] = 0x09; // HCI OCF = 9
987  hcibuf[1] = 0x04 << 2; // HCI OGF = 4
988  hcibuf[2] = 0x00;
989 
990  HCI_Command(hcibuf, 3);
991 }
992 
995  hcibuf[0] = 0x01; // HCI OCF = 1
996  hcibuf[1] = 0x04 << 2; // HCI OGF = 4
997  hcibuf[2] = 0x00;
998 
999  HCI_Command(hcibuf, 3);
1000 }
1001 
1004  hcibuf[0] = 0x09; // HCI OCF = 9
1005  hcibuf[1] = 0x01 << 2; // HCI OGF = 1
1006  hcibuf[2] = 0x07; // parameter length 7
1007  hcibuf[3] = disc_bdaddr[0]; // 6 octet bdaddr
1008  hcibuf[4] = disc_bdaddr[1];
1009  hcibuf[5] = disc_bdaddr[2];
1010  hcibuf[6] = disc_bdaddr[3];
1011  hcibuf[7] = disc_bdaddr[4];
1012  hcibuf[8] = disc_bdaddr[5];
1013  hcibuf[9] = 0x00; // Switch role to master
1014 
1015  HCI_Command(hcibuf, 10);
1016 }
1017 
1020  hcibuf[0] = 0x19; // HCI OCF = 19
1021  hcibuf[1] = 0x01 << 2; // HCI OGF = 1
1022  hcibuf[2] = 0x0A; // parameter length = 10
1023  hcibuf[3] = disc_bdaddr[0]; // 6 octet bdaddr
1024  hcibuf[4] = disc_bdaddr[1];
1025  hcibuf[5] = disc_bdaddr[2];
1026  hcibuf[6] = disc_bdaddr[3];
1027  hcibuf[7] = disc_bdaddr[4];
1028  hcibuf[8] = disc_bdaddr[5];
1029  hcibuf[9] = 0x01; // Page Scan Repetition Mode
1030  hcibuf[10] = 0x00; // Reserved
1031  hcibuf[11] = 0x00; // Clock offset - low byte
1032  hcibuf[12] = 0x00; // Clock offset - high byte
1033 
1034  HCI_Command(hcibuf, 13);
1035 }
1036 
1037 void BTD::hci_set_local_name(const char* name) {
1038  hcibuf[0] = 0x13; // HCI OCF = 13
1039  hcibuf[1] = 0x03 << 2; // HCI OGF = 3
1040  hcibuf[2] = strlen(name) + 1; // parameter length = the length of the string + end byte
1041  uint8_t i;
1042  for(i = 0; i < strlen(name); i++)
1043  hcibuf[i + 3] = name[i];
1044  hcibuf[i + 3] = 0x00; // End of string
1045 
1046  HCI_Command(hcibuf, 4 + strlen(name));
1047 }
1048 
1051  hcibuf[0] = 0x01;
1052  hcibuf[1] = 0x01 << 2; // HCI OGF = 1
1053  hcibuf[2] = 0x05; // Parameter Total Length = 5
1054  hcibuf[3] = 0x33; // LAP: Genera/Unlimited Inquiry Access Code (GIAC = 0x9E8B33) - see https://www.bluetooth.org/Technical/AssignedNumbers/baseband.htm
1055  hcibuf[4] = 0x8B;
1056  hcibuf[5] = 0x9E;
1057  hcibuf[6] = 0x30; // Inquiry time = 61.44 sec (maximum)
1058  hcibuf[7] = 0x0A; // 10 number of responses
1059 
1060  HCI_Command(hcibuf, 8);
1061 }
1062 
1064  hcibuf[0] = 0x02;
1065  hcibuf[1] = 0x01 << 2; // HCI OGF = 1
1066  hcibuf[2] = 0x00; // Parameter Total Length = 0
1067 
1068  HCI_Command(hcibuf, 3);
1069 }
1070 
1072  hci_connect(disc_bdaddr); // Use last discovered device
1073 }
1074 
1075 void BTD::hci_connect(uint8_t *bdaddr) {
1077  hcibuf[0] = 0x05;
1078  hcibuf[1] = 0x01 << 2; // HCI OGF = 1
1079  hcibuf[2] = 0x0D; // parameter Total Length = 13
1080  hcibuf[3] = bdaddr[0]; // 6 octet bdaddr (LSB)
1081  hcibuf[4] = bdaddr[1];
1082  hcibuf[5] = bdaddr[2];
1083  hcibuf[6] = bdaddr[3];
1084  hcibuf[7] = bdaddr[4];
1085  hcibuf[8] = bdaddr[5];
1086  hcibuf[9] = 0x18; // DM1 or DH1 may be used
1087  hcibuf[10] = 0xCC; // DM3, DH3, DM5, DH5 may be used
1088  hcibuf[11] = 0x01; // Page repetition mode R1
1089  hcibuf[12] = 0x00; // Reserved
1090  hcibuf[13] = 0x00; // Clock offset
1091  hcibuf[14] = 0x00; // Invalid clock offset
1092  hcibuf[15] = 0x00; // Do not allow role switch
1093 
1094  HCI_Command(hcibuf, 16);
1095 }
1096 
1098  hcibuf[0] = 0x0D; // HCI OCF = 0D
1099  hcibuf[1] = 0x01 << 2; // HCI OGF = 1
1100  hcibuf[2] = 0x17; // parameter length 23
1101  hcibuf[3] = disc_bdaddr[0]; // 6 octet bdaddr
1102  hcibuf[4] = disc_bdaddr[1];
1103  hcibuf[5] = disc_bdaddr[2];
1104  hcibuf[6] = disc_bdaddr[3];
1105  hcibuf[7] = disc_bdaddr[4];
1106  hcibuf[8] = disc_bdaddr[5];
1107  if(pairWithWii) {
1108  hcibuf[9] = 6; // Pin length is the length of the Bluetooth address
1109  if(pairWiiUsingSync) {
1110 #ifdef DEBUG_USB_HOST
1111  Notify(PSTR("\r\nPairing with Wii controller via SYNC"), 0x80);
1112 #endif
1113  for(uint8_t i = 0; i < 6; i++)
1114  hcibuf[10 + i] = my_bdaddr[i]; // The pin is the Bluetooth dongles Bluetooth address backwards
1115  } else {
1116  for(uint8_t i = 0; i < 6; i++)
1117  hcibuf[10 + i] = disc_bdaddr[i]; // The pin is the Wiimote's Bluetooth address backwards
1118  }
1119  for(uint8_t i = 16; i < 26; i++)
1120  hcibuf[i] = 0x00; // The rest should be 0
1121  } else {
1122  hcibuf[9] = strlen(btdPin); // Length of pin
1123  uint8_t i;
1124  for(i = 0; i < strlen(btdPin); i++) // The maximum size of the pin is 16
1125  hcibuf[i + 10] = btdPin[i];
1126  for(; i < 16; i++)
1127  hcibuf[i + 10] = 0x00; // The rest should be 0
1128  }
1129 
1130  HCI_Command(hcibuf, 26);
1131 }
1132 
1134  hcibuf[0] = 0x0E; // HCI OCF = 0E
1135  hcibuf[1] = 0x01 << 2; // HCI OGF = 1
1136  hcibuf[2] = 0x06; // parameter length 6
1137  hcibuf[3] = disc_bdaddr[0]; // 6 octet bdaddr
1138  hcibuf[4] = disc_bdaddr[1];
1139  hcibuf[5] = disc_bdaddr[2];
1140  hcibuf[6] = disc_bdaddr[3];
1141  hcibuf[7] = disc_bdaddr[4];
1142  hcibuf[8] = disc_bdaddr[5];
1143 
1144  HCI_Command(hcibuf, 9);
1145 }
1146 
1148  hcibuf[0] = 0x0C; // HCI OCF = 0C
1149  hcibuf[1] = 0x01 << 2; // HCI OGF = 1
1150  hcibuf[2] = 0x06; // parameter length 6
1151  hcibuf[3] = disc_bdaddr[0]; // 6 octet bdaddr
1152  hcibuf[4] = disc_bdaddr[1];
1153  hcibuf[5] = disc_bdaddr[2];
1154  hcibuf[6] = disc_bdaddr[3];
1155  hcibuf[7] = disc_bdaddr[4];
1156  hcibuf[8] = disc_bdaddr[5];
1157 
1158  HCI_Command(hcibuf, 9);
1159 }
1160 
1162  hcibuf[0] = 0x11; // HCI OCF = 11
1163  hcibuf[1] = 0x01 << 2; // HCI OGF = 1
1164  hcibuf[2] = 0x02; // parameter length = 2
1165  hcibuf[3] = (uint8_t)(hci_handle & 0xFF); //connection handle - low byte
1166  hcibuf[4] = (uint8_t)((hci_handle >> 8) & 0x0F); //connection handle - high byte
1167 
1168  HCI_Command(hcibuf, 5);
1169 }
1170 
1171 void BTD::hci_disconnect(uint16_t handle) { // This is called by the different services
1173  hcibuf[0] = 0x06; // HCI OCF = 6
1174  hcibuf[1] = 0x01 << 2; // HCI OGF = 1
1175  hcibuf[2] = 0x03; // parameter length = 3
1176  hcibuf[3] = (uint8_t)(handle & 0xFF); //connection handle - low byte
1177  hcibuf[4] = (uint8_t)((handle >> 8) & 0x0F); //connection handle - high byte
1178  hcibuf[5] = 0x13; // reason
1179 
1180  HCI_Command(hcibuf, 6);
1181 }
1182 
1183 void BTD::hci_write_class_of_device() { // See http://bluetooth-pentest.narod.ru/software/bluetooth_class_of_device-service_generator.html
1184  hcibuf[0] = 0x24; // HCI OCF = 24
1185  hcibuf[1] = 0x03 << 2; // HCI OGF = 3
1186  hcibuf[2] = 0x03; // parameter length = 3
1187  hcibuf[3] = 0x04; // Robot
1188  hcibuf[4] = 0x08; // Toy
1189  hcibuf[5] = 0x00;
1190 
1191  HCI_Command(hcibuf, 6);
1192 }
1193 /*******************************************************************
1194  * *
1195  * HCI ACL Data Packet *
1196  * *
1197  * buf[0] buf[1] buf[2] buf[3]
1198  * 0 4 8 11 12 16 24 31 MSB
1199  * .-+-+-+-+-+-+-+-|-+-+-+-|-+-|-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-.
1200  * | HCI Handle |PB |BC | Data Total Length | HCI ACL Data Packet
1201  * .-+-+-+-+-+-+-+-|-+-+-+-|-+-|-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-.
1202  *
1203  * buf[4] buf[5] buf[6] buf[7]
1204  * 0 8 16 31 MSB
1205  * .-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-.
1206  * | Length | Channel ID | Basic L2CAP header
1207  * .-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-.
1208  *
1209  * buf[8] buf[9] buf[10] buf[11]
1210  * 0 8 16 31 MSB
1211  * .-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-.
1212  * | Code | Identifier | Length | Control frame (C-frame)
1213  * .-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-. (signaling packet format)
1214  */
1215 /************************************************************/
1216 /* L2CAP Commands */
1217 
1218 /************************************************************/
1219 void BTD::L2CAP_Command(uint16_t handle, uint8_t* data, uint8_t nbytes, uint8_t channelLow, uint8_t channelHigh) {
1220  uint8_t buf[8 + nbytes];
1221  buf[0] = (uint8_t)(handle & 0xff); // HCI handle with PB,BC flag
1222  buf[1] = (uint8_t)(((handle >> 8) & 0x0f) | 0x20);
1223  buf[2] = (uint8_t)((4 + nbytes) & 0xff); // HCI ACL total data length
1224  buf[3] = (uint8_t)((4 + nbytes) >> 8);
1225  buf[4] = (uint8_t)(nbytes & 0xff); // L2CAP header: Length
1226  buf[5] = (uint8_t)(nbytes >> 8);
1227  buf[6] = channelLow;
1228  buf[7] = channelHigh;
1229 
1230  for(uint16_t i = 0; i < nbytes; i++) // L2CAP C-frame
1231  buf[8 + i] = data[i];
1232 
1233  uint8_t rcode = pUsb->outTransfer(bAddress, epInfo[ BTD_DATAOUT_PIPE ].epAddr, (8 + nbytes), buf);
1234  if(rcode) {
1235  delay(100); // This small delay prevents it from overflowing if it fails
1236 #ifdef DEBUG_USB_HOST
1237  Notify(PSTR("\r\nError sending L2CAP message: 0x"), 0x80);
1238  D_PrintHex<uint8_t > (rcode, 0x80);
1239  Notify(PSTR(" - Channel ID: "), 0x80);
1240  D_PrintHex<uint8_t > (channelHigh, 0x80);
1241  Notify(PSTR(" "), 0x80);
1242  D_PrintHex<uint8_t > (channelLow, 0x80);
1243 #endif
1244  }
1245 }
1246 
1247 void BTD::l2cap_connection_request(uint16_t handle, uint8_t rxid, uint8_t* scid, uint16_t psm) {
1248  l2capoutbuf[0] = L2CAP_CMD_CONNECTION_REQUEST; // Code
1249  l2capoutbuf[1] = rxid; // Identifier
1250  l2capoutbuf[2] = 0x04; // Length
1251  l2capoutbuf[3] = 0x00;
1252  l2capoutbuf[4] = (uint8_t)(psm & 0xff); // PSM
1253  l2capoutbuf[5] = (uint8_t)(psm >> 8);
1254  l2capoutbuf[6] = scid[0]; // Source CID
1255  l2capoutbuf[7] = scid[1];
1256 
1257  L2CAP_Command(handle, l2capoutbuf, 8);
1258 }
1259 
1260 void BTD::l2cap_connection_response(uint16_t handle, uint8_t rxid, uint8_t* dcid, uint8_t* scid, uint8_t result) {
1261  l2capoutbuf[0] = L2CAP_CMD_CONNECTION_RESPONSE; // Code
1262  l2capoutbuf[1] = rxid; // Identifier
1263  l2capoutbuf[2] = 0x08; // Length
1264  l2capoutbuf[3] = 0x00;
1265  l2capoutbuf[4] = dcid[0]; // Destination CID
1266  l2capoutbuf[5] = dcid[1];
1267  l2capoutbuf[6] = scid[0]; // Source CID
1268  l2capoutbuf[7] = scid[1];
1269  l2capoutbuf[8] = result; // Result: Pending or Success
1270  l2capoutbuf[9] = 0x00;
1271  l2capoutbuf[10] = 0x00; // No further information
1272  l2capoutbuf[11] = 0x00;
1273 
1274  L2CAP_Command(handle, l2capoutbuf, 12);
1275 }
1276 
1277 void BTD::l2cap_config_request(uint16_t handle, uint8_t rxid, uint8_t* dcid) {
1278  l2capoutbuf[0] = L2CAP_CMD_CONFIG_REQUEST; // Code
1279  l2capoutbuf[1] = rxid; // Identifier
1280  l2capoutbuf[2] = 0x08; // Length
1281  l2capoutbuf[3] = 0x00;
1282  l2capoutbuf[4] = dcid[0]; // Destination CID
1283  l2capoutbuf[5] = dcid[1];
1284  l2capoutbuf[6] = 0x00; // Flags
1285  l2capoutbuf[7] = 0x00;
1286  l2capoutbuf[8] = 0x01; // Config Opt: type = MTU (Maximum Transmission Unit) - Hint
1287  l2capoutbuf[9] = 0x02; // Config Opt: length
1288  l2capoutbuf[10] = 0xFF; // MTU
1289  l2capoutbuf[11] = 0xFF;
1290 
1291  L2CAP_Command(handle, l2capoutbuf, 12);
1292 }
1293 
1294 void BTD::l2cap_config_response(uint16_t handle, uint8_t rxid, uint8_t* scid) {
1295  l2capoutbuf[0] = L2CAP_CMD_CONFIG_RESPONSE; // Code
1296  l2capoutbuf[1] = rxid; // Identifier
1297  l2capoutbuf[2] = 0x0A; // Length
1298  l2capoutbuf[3] = 0x00;
1299  l2capoutbuf[4] = scid[0]; // Source CID
1300  l2capoutbuf[5] = scid[1];
1301  l2capoutbuf[6] = 0x00; // Flag
1302  l2capoutbuf[7] = 0x00;
1303  l2capoutbuf[8] = 0x00; // Result
1304  l2capoutbuf[9] = 0x00;
1305  l2capoutbuf[10] = 0x01; // Config
1306  l2capoutbuf[11] = 0x02;
1307  l2capoutbuf[12] = 0xA0;
1308  l2capoutbuf[13] = 0x02;
1309 
1310  L2CAP_Command(handle, l2capoutbuf, 14);
1311 }
1312 
1313 void BTD::l2cap_disconnection_request(uint16_t handle, uint8_t rxid, uint8_t* dcid, uint8_t* scid) {
1314  l2capoutbuf[0] = L2CAP_CMD_DISCONNECT_REQUEST; // Code
1315  l2capoutbuf[1] = rxid; // Identifier
1316  l2capoutbuf[2] = 0x04; // Length
1317  l2capoutbuf[3] = 0x00;
1318  l2capoutbuf[4] = dcid[0];
1319  l2capoutbuf[5] = dcid[1];
1320  l2capoutbuf[6] = scid[0];
1321  l2capoutbuf[7] = scid[1];
1322 
1323  L2CAP_Command(handle, l2capoutbuf, 8);
1324 }
1325 
1326 void BTD::l2cap_disconnection_response(uint16_t handle, uint8_t rxid, uint8_t* dcid, uint8_t* scid) {
1327  l2capoutbuf[0] = L2CAP_CMD_DISCONNECT_RESPONSE; // Code
1328  l2capoutbuf[1] = rxid; // Identifier
1329  l2capoutbuf[2] = 0x04; // Length
1330  l2capoutbuf[3] = 0x00;
1331  l2capoutbuf[4] = dcid[0];
1332  l2capoutbuf[5] = dcid[1];
1333  l2capoutbuf[6] = scid[0];
1334  l2capoutbuf[7] = scid[1];
1335 
1336  L2CAP_Command(handle, l2capoutbuf, 8);
1337 }
1338 
1339 void BTD::l2cap_information_response(uint16_t handle, uint8_t rxid, uint8_t infoTypeLow, uint8_t infoTypeHigh) {
1340  l2capoutbuf[0] = L2CAP_CMD_INFORMATION_RESPONSE; // Code
1341  l2capoutbuf[1] = rxid; // Identifier
1342  l2capoutbuf[2] = 0x08; // Length
1343  l2capoutbuf[3] = 0x00;
1344  l2capoutbuf[4] = infoTypeLow;
1345  l2capoutbuf[5] = infoTypeHigh;
1346  l2capoutbuf[6] = 0x00; // Result = success
1347  l2capoutbuf[7] = 0x00; // Result = success
1348  l2capoutbuf[8] = 0x00;
1349  l2capoutbuf[9] = 0x00;
1350  l2capoutbuf[10] = 0x00;
1351  l2capoutbuf[11] = 0x00;
1352 
1353  L2CAP_Command(handle, l2capoutbuf, 12);
1354 }
1355 
1356 /* PS3 Commands - only set Bluetooth address is implemented in this library */
1357 void BTD::setBdaddr(uint8_t* bdaddr) {
1358  /* Set the internal Bluetooth address */
1359  uint8_t buf[8];
1360  buf[0] = 0x01;
1361  buf[1] = 0x00;
1362 
1363  for(uint8_t i = 0; i < 6; i++)
1364  buf[i + 2] = bdaddr[5 - i]; // Copy into buffer, has to be written reversed, so it is MSB first
1365 
1366  // bmRequest = Host to device (0x00) | Class (0x20) | Interface (0x01) = 0x21, bRequest = Set Report (0x09), Report ID (0xF5), Report Type (Feature 0x03), interface (0x00), datalength, datalength, data
1367  pUsb->ctrlReq(bAddress, epInfo[BTD_CONTROL_PIPE].epAddr, bmREQ_HID_OUT, HID_REQUEST_SET_REPORT, 0xF5, 0x03, 0x00, 8, 8, buf, NULL);
1368 }
1369 
1370 void BTD::setMoveBdaddr(uint8_t* bdaddr) {
1371  /* Set the internal Bluetooth address */
1372  uint8_t buf[11];
1373  buf[0] = 0x05;
1374  buf[7] = 0x10;
1375  buf[8] = 0x01;
1376  buf[9] = 0x02;
1377  buf[10] = 0x12;
1378 
1379  for(uint8_t i = 0; i < 6; i++)
1380  buf[i + 1] = bdaddr[i];
1381 
1382  // bmRequest = Host to device (0x00) | Class (0x20) | Interface (0x01) = 0x21, bRequest = Set Report (0x09), Report ID (0x05), Report Type (Feature 0x03), interface (0x00), datalength, datalength, data
1383  pUsb->ctrlReq(bAddress, epInfo[BTD_CONTROL_PIPE].epAddr, bmREQ_HID_OUT, HID_REQUEST_SET_REPORT, 0x05, 0x03, 0x00, 11, 11, buf, NULL);
1384 }
static const uint8_t BTD_DATAOUT_PIPE
Definition: BTD.h:525
+Go to the documentation of this file.
1 /* Copyright (C) 2012 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 "BTD.h"
19 // To enable serial debugging see "settings.h"
20 //#define EXTRADEBUG // Uncomment to get even more debugging data
21 
22 const uint8_t BTD::BTD_CONTROL_PIPE = 0;
23 const uint8_t BTD::BTD_EVENT_PIPE = 1;
24 const uint8_t BTD::BTD_DATAIN_PIPE = 2;
25 const uint8_t BTD::BTD_DATAOUT_PIPE = 3;
26 
28 connectToWii(false),
29 pairWithWii(false),
30 connectToHIDDevice(false),
31 pairWithHIDDevice(false),
32 useSimplePairing(false),
33 pUsb(p), // Pointer to USB class instance - mandatory
34 bAddress(0), // Device address - mandatory
35 bNumEP(1), // If config descriptor needs to be parsed
36 qNextPollTime(0), // Reset NextPollTime
37 pollInterval(0),
38 simple_pairing_supported(false),
39 bPollEnable(false) // Don't start polling before dongle is connected
40 {
41  for(uint8_t i = 0; i < BTD_NUM_SERVICES; i++)
42  btService[i] = NULL;
43 
44  Initialize(); // Set all variables, endpoint structs etc. to default values
45 
46  if(pUsb) // Register in USB subsystem
47  pUsb->RegisterDeviceClass(this); // Set devConfig[] entry
48 }
49 
50 uint8_t BTD::ConfigureDevice(uint8_t parent, uint8_t port, bool lowspeed) {
51  const uint8_t constBufSize = sizeof (USB_DEVICE_DESCRIPTOR);
52  uint8_t buf[constBufSize];
53  USB_DEVICE_DESCRIPTOR * udd = reinterpret_cast<USB_DEVICE_DESCRIPTOR*>(buf);
54  uint8_t rcode;
55  UsbDevice *p = NULL;
56  EpInfo *oldep_ptr = NULL;
57 
58  Initialize(); // Set all variables, endpoint structs etc. to default values
59 
60  AddressPool &addrPool = pUsb->GetAddressPool(); // Get memory address of USB device address pool
61 #ifdef EXTRADEBUG
62  Notify(PSTR("\r\nBTD ConfigureDevice"), 0x80);
63 #endif
64 
65  if(bAddress) { // Check if address has already been assigned to an instance
66 #ifdef DEBUG_USB_HOST
67  Notify(PSTR("\r\nAddress in use"), 0x80);
68 #endif
70  }
71 
72  p = addrPool.GetUsbDevicePtr(0); // Get pointer to pseudo device with address 0 assigned
73  if(!p) {
74 #ifdef DEBUG_USB_HOST
75  Notify(PSTR("\r\nAddress not found"), 0x80);
76 #endif
78  }
79 
80  if(!p->epinfo) {
81 #ifdef DEBUG_USB_HOST
82  Notify(PSTR("\r\nepinfo is null"), 0x80);
83 #endif
85  }
86 
87  oldep_ptr = p->epinfo; // Save old pointer to EP_RECORD of address 0
88  p->epinfo = epInfo; // Temporary assign new pointer to epInfo to p->epinfo in order to avoid toggle inconsistence
89  p->lowspeed = lowspeed;
90  rcode = pUsb->getDevDescr(0, 0, constBufSize, (uint8_t*)buf); // Get device descriptor - addr, ep, nbytes, data
91 
92  p->epinfo = oldep_ptr; // Restore p->epinfo
93 
94  if(rcode)
95  goto FailGetDevDescr;
96 
97  bAddress = addrPool.AllocAddress(parent, false, port); // Allocate new address according to device class
98 
99  if(!bAddress) {
100 #ifdef DEBUG_USB_HOST
101  Notify(PSTR("\r\nOut of address space"), 0x80);
102 #endif
104  }
105 
106  if (udd->bDeviceClass == 0x09) // Some dongles have an USB hub inside
107  goto FailHub;
108 
109  epInfo[0].maxPktSize = udd->bMaxPacketSize0; // Extract Max Packet Size from device descriptor
110  epInfo[1].epAddr = udd->bNumConfigurations; // Steal and abuse from epInfo structure to save memory
111 
112  VID = udd->idVendor;
113  PID = udd->idProduct;
114 
116 
117 FailHub:
118 #ifdef DEBUG_USB_HOST
119  Notify(PSTR("\r\nPlease create a hub instance in your code: \"USBHub Hub1(&Usb);\""), 0x80);
120 #endif
121  pUsb->setAddr(bAddress, 0, 0); // Reset address
123  Release();
124  return rcode;
125 
126 FailGetDevDescr:
127 #ifdef DEBUG_USB_HOST
128  NotifyFailGetDevDescr(rcode);
129 #endif
130  if(rcode != hrJERR)
132  Release();
133  return rcode;
134 };
135 
136 uint8_t BTD::Init(uint8_t parent __attribute__((unused)), uint8_t port __attribute__((unused)), bool lowspeed) {
137  uint8_t rcode;
138  uint8_t num_of_conf = epInfo[1].epAddr; // Number of configurations
139  epInfo[1].epAddr = 0;
140 
141  AddressPool &addrPool = pUsb->GetAddressPool();
142 #ifdef EXTRADEBUG
143  Notify(PSTR("\r\nBTD Init"), 0x80);
144 #endif
145  UsbDevice *p = addrPool.GetUsbDevicePtr(bAddress); // Get pointer to assigned address record
146 
147  if(!p) {
148 #ifdef DEBUG_USB_HOST
149  Notify(PSTR("\r\nAddress not found"), 0x80);
150 #endif
152  }
153 
154  delay(300); // Assign new address to the device
155 
156  rcode = pUsb->setAddr(0, 0, bAddress); // Assign new address to the device
157  if(rcode) {
158 #ifdef DEBUG_USB_HOST
159  Notify(PSTR("\r\nsetAddr: "), 0x80);
160  D_PrintHex<uint8_t > (rcode, 0x80);
161 #endif
162  p->lowspeed = false;
163  goto Fail;
164  }
165 #ifdef EXTRADEBUG
166  Notify(PSTR("\r\nAddr: "), 0x80);
167  D_PrintHex<uint8_t > (bAddress, 0x80);
168 #endif
169 
170  p->lowspeed = false;
171 
172  p = addrPool.GetUsbDevicePtr(bAddress); // Get pointer to assigned address record
173  if(!p) {
174 #ifdef DEBUG_USB_HOST
175  Notify(PSTR("\r\nAddress not found"), 0x80);
176 #endif
178  }
179 
180  p->lowspeed = lowspeed;
181 
182  rcode = pUsb->setEpInfoEntry(bAddress, 1, epInfo); // Assign epInfo to epinfo pointer - only EP0 is known
183  if(rcode)
184  goto FailSetDevTblEntry;
185 
186  if(VID == PS3_VID && (PID == PS3_PID || PID == PS3NAVIGATION_PID || PID == PS3MOVE_PID)) {
187  delay(100);
188  rcode = pUsb->setConf(bAddress, epInfo[ BTD_CONTROL_PIPE ].epAddr, 1); // We only need the Control endpoint, so we don't have to initialize the other endpoints of device
189  if(rcode)
190  goto FailSetConfDescr;
191 
192 #ifdef DEBUG_USB_HOST
193  if(PID == PS3_PID || PID == PS3NAVIGATION_PID) {
194  if(PID == PS3_PID)
195  Notify(PSTR("\r\nDualshock 3 Controller Connected"), 0x80);
196  else // It must be a navigation controller
197  Notify(PSTR("\r\nNavigation Controller Connected"), 0x80);
198  } else // It must be a Motion controller
199  Notify(PSTR("\r\nMotion Controller Connected"), 0x80);
200 #endif
201 
202  if(my_bdaddr[0] == 0x00 && my_bdaddr[1] == 0x00 && my_bdaddr[2] == 0x00 && my_bdaddr[3] == 0x00 && my_bdaddr[4] == 0x00 && my_bdaddr[5] == 0x00) {
203 #ifdef DEBUG_USB_HOST
204  Notify(PSTR("\r\nPlease plug in the dongle before trying to pair with the PS3 Controller\r\nor set the Bluetooth address in the constructor of the PS3BT class"), 0x80);
205 #endif
206  } else {
207  if(PID == PS3_PID || PID == PS3NAVIGATION_PID)
208  setBdaddr(my_bdaddr); // Set internal Bluetooth address
209  else
210  setMoveBdaddr(my_bdaddr); // Set internal Bluetooth address
211 #ifdef DEBUG_USB_HOST
212  Notify(PSTR("\r\nBluetooth Address was set to: "), 0x80);
213  for(int8_t i = 5; i > 0; i--) {
214  D_PrintHex<uint8_t > (my_bdaddr[i], 0x80);
215  Notify(PSTR(":"), 0x80);
216  }
217  D_PrintHex<uint8_t > (my_bdaddr[0], 0x80);
218 #endif
219  }
220 
221  pUsb->setConf(bAddress, epInfo[ BTD_CONTROL_PIPE ].epAddr, 0); // Reset configuration value
222  pUsb->setAddr(bAddress, 0, 0); // Reset address
223  Release(); // Release device
225  } else {
226  // Check if attached device is a Bluetooth dongle and fill endpoint data structure
227  // First interface in the configuration must have Bluetooth assigned Class/Subclass/Protocol
228  // And 3 endpoints - interrupt-IN, bulk-IN, bulk-OUT, not necessarily in this order
229  for(uint8_t i = 0; i < num_of_conf; i++) {
230  if((VID == IOGEAR_GBU521_VID && PID == IOGEAR_GBU521_PID) || (VID == BELKIN_F8T065BF_VID && PID == BELKIN_F8T065BF_PID)) {
231  ConfigDescParser<USB_CLASS_VENDOR_SPECIFIC, WI_SUBCLASS_RF, WI_PROTOCOL_BT, CP_MASK_COMPARE_ALL> confDescrParser(this); // Workaround issue with some dongles
232  rcode = pUsb->getConfDescr(bAddress, 0, i, &confDescrParser);
233  } else {
234  ConfigDescParser<USB_CLASS_WIRELESS_CTRL, WI_SUBCLASS_RF, WI_PROTOCOL_BT, CP_MASK_COMPARE_ALL> confDescrParser(this); // Set class id according to the specification
235  rcode = pUsb->getConfDescr(bAddress, 0, i, &confDescrParser);
236  }
237  if(rcode) // Check error code
238  goto FailGetConfDescr;
239  if(bNumEP >= BTD_MAX_ENDPOINTS) // All endpoints extracted
240  break;
241  }
242 
244  goto FailUnknownDevice;
245 
246  // Assign epInfo to epinfo pointer - this time all 3 endpoins
247  rcode = pUsb->setEpInfoEntry(bAddress, bNumEP, epInfo);
248  if(rcode)
249  goto FailSetDevTblEntry;
250 
251  // Set Configuration Value
252  rcode = pUsb->setConf(bAddress, epInfo[ BTD_CONTROL_PIPE ].epAddr, bConfNum);
253  if(rcode)
254  goto FailSetConfDescr;
255 
256  hci_num_reset_loops = 100; // only loop 100 times before trying to send the hci reset command
257  hci_counter = 0;
258  hci_state = HCI_INIT_STATE;
259  waitingForConnection = false;
260  bPollEnable = true;
261 
262 #ifdef DEBUG_USB_HOST
263  Notify(PSTR("\r\nBluetooth Dongle Initialized"), 0x80);
264 #endif
265  }
266  return 0; // Successful configuration
267 
268  /* Diagnostic messages */
269 FailSetDevTblEntry:
270 #ifdef DEBUG_USB_HOST
272  goto Fail;
273 #endif
274 
275 FailGetConfDescr:
276 #ifdef DEBUG_USB_HOST
278  goto Fail;
279 #endif
280 
281 FailSetConfDescr:
282 #ifdef DEBUG_USB_HOST
284 #endif
285  goto Fail;
286 
287 FailUnknownDevice:
288 #ifdef DEBUG_USB_HOST
289  NotifyFailUnknownDevice(VID, PID);
290 #endif
291  pUsb->setAddr(bAddress, 0, 0); // Reset address
293 Fail:
294 #ifdef DEBUG_USB_HOST
295  Notify(PSTR("\r\nBTD Init Failed, error code: "), 0x80);
296  NotifyFail(rcode);
297 #endif
298  Release();
299  return rcode;
300 }
301 
302 void BTD::Initialize() {
303  uint8_t i;
304  for(i = 0; i < BTD_MAX_ENDPOINTS; i++) {
305  epInfo[i].epAddr = 0;
306  epInfo[i].maxPktSize = (i) ? 0 : 8;
307  epInfo[i].bmSndToggle = 0;
308  epInfo[i].bmRcvToggle = 0;
310  }
311  for(i = 0; i < BTD_NUM_SERVICES; i++) {
312  if(btService[i])
313  btService[i]->Reset(); // Reset all Bluetooth services
314  }
315 
316  connectToWii = false;
317  incomingWii = false;
318  connectToHIDDevice = false;
319  incomingHIDDevice = false;
320  incomingPS4 = false;
321  bAddress = 0; // Clear device address
322  bNumEP = 1; // Must have to be reset to 1
323  qNextPollTime = 0; // Reset next poll time
324  pollInterval = 0;
325  bPollEnable = false; // Don't start polling before dongle is connected
326  simple_pairing_supported = false;
327 }
328 
329 /* Extracts interrupt-IN, bulk-IN, bulk-OUT endpoint information from config descriptor */
330 void BTD::EndpointXtract(uint8_t conf, uint8_t iface __attribute__((unused)), uint8_t alt, uint8_t proto __attribute__((unused)), const USB_ENDPOINT_DESCRIPTOR *pep) {
331  //ErrorMessage<uint8_t>(PSTR("Conf.Val"),conf);
332  //ErrorMessage<uint8_t>(PSTR("Iface Num"),iface);
333  //ErrorMessage<uint8_t>(PSTR("Alt.Set"),alt);
334 
335  if(alt) // Wrong interface - by BT spec, no alt setting
336  return;
337 
338  bConfNum = conf;
339  uint8_t index;
340 
341  if((pep->bmAttributes & bmUSB_TRANSFER_TYPE) == USB_TRANSFER_TYPE_INTERRUPT && (pep->bEndpointAddress & 0x80) == 0x80) { // Interrupt In endpoint found
342  index = BTD_EVENT_PIPE;
344  } else if((pep->bmAttributes & bmUSB_TRANSFER_TYPE) == USB_TRANSFER_TYPE_BULK) // Bulk endpoint found
345  index = ((pep->bEndpointAddress & 0x80) == 0x80) ? BTD_DATAIN_PIPE : BTD_DATAOUT_PIPE;
346  else
347  return;
348 
349  // Fill the rest of endpoint data structure
350  epInfo[index].epAddr = (pep->bEndpointAddress & 0x0F);
351  epInfo[index].maxPktSize = (uint8_t)pep->wMaxPacketSize;
352 #ifdef EXTRADEBUG
354 #endif
355  if(pollInterval < pep->bInterval) // Set the polling interval as the largest polling interval obtained from endpoints
356  pollInterval = pep->bInterval;
357  bNumEP++;
358 }
359 
360 void BTD::PrintEndpointDescriptor(const USB_ENDPOINT_DESCRIPTOR* ep_ptr __attribute__((unused))) {
361 #ifdef EXTRADEBUG
362  Notify(PSTR("\r\nEndpoint descriptor:"), 0x80);
363  Notify(PSTR("\r\nLength:\t\t"), 0x80);
364  D_PrintHex<uint8_t > (ep_ptr->bLength, 0x80);
365  Notify(PSTR("\r\nType:\t\t"), 0x80);
366  D_PrintHex<uint8_t > (ep_ptr->bDescriptorType, 0x80);
367  Notify(PSTR("\r\nAddress:\t"), 0x80);
368  D_PrintHex<uint8_t > (ep_ptr->bEndpointAddress, 0x80);
369  Notify(PSTR("\r\nAttributes:\t"), 0x80);
370  D_PrintHex<uint8_t > (ep_ptr->bmAttributes, 0x80);
371  Notify(PSTR("\r\nMaxPktSize:\t"), 0x80);
372  D_PrintHex<uint16_t > (ep_ptr->wMaxPacketSize, 0x80);
373  Notify(PSTR("\r\nPoll Intrv:\t"), 0x80);
374  D_PrintHex<uint8_t > (ep_ptr->bInterval, 0x80);
375 #endif
376 }
377 
378 /* Performs a cleanup after failed Init() attempt */
379 uint8_t BTD::Release() {
380  Initialize(); // Set all variables, endpoint structs etc. to default values
382  return 0;
383 }
384 
385 uint8_t BTD::Poll() {
386  if(!bPollEnable)
387  return 0;
388  if((int32_t)((uint32_t)millis() - qNextPollTime) >= 0L) { // Don't poll if shorter than polling interval
389  qNextPollTime = (uint32_t)millis() + pollInterval; // Set new poll time
390  HCI_event_task(); // Poll the HCI event pipe
391  HCI_task(); // HCI state machine
392  ACL_event_task(); // Poll the ACL input pipe too
393  }
394  return 0;
395 }
396 
398  for(uint8_t i = 0; i < BTD_NUM_SERVICES; i++)
399  if(btService[i])
400  btService[i]->disconnect();
401 };
402 
403 void BTD::HCI_event_task() {
404  uint16_t length = BULK_MAXPKTSIZE; // Request more than 16 bytes anyway, the inTransfer routine will take care of this
405  uint8_t rcode = pUsb->inTransfer(bAddress, epInfo[ BTD_EVENT_PIPE ].epAddr, &length, hcibuf, pollInterval); // Input on endpoint 1
406 
407  if(!rcode || rcode == hrNAK) { // Check for errors
408  switch(hcibuf[0]) { // Switch on event type
409  case EV_COMMAND_COMPLETE:
410  if(!hcibuf[5]) { // Check if command succeeded
411  hci_set_flag(HCI_FLAG_CMD_COMPLETE); // Set command complete flag
412  if((hcibuf[3] == 0x01) && (hcibuf[4] == 0x10)) { // Parameters from read local version information
413  hci_version = hcibuf[6]; // Used to check if it supports 2.0+EDR - see http://www.bluetooth.org/Technical/AssignedNumbers/hci.htm
414 #ifdef EXTRADEBUG
416  Notify(PSTR("\r\nHCI version: "), 0x80);
417  D_PrintHex<uint8_t > (hci_version, 0x80);
418  }
419 #endif
421  } else if((hcibuf[3] == 0x04) && (hcibuf[4] == 0x10)) { // Parameters from read local extended features
423 #ifdef EXTRADEBUG
424  Notify(PSTR("\r\nPage number: "), 0x80);
425  D_PrintHex<uint8_t > (hcibuf[6], 0x80);
426  Notify(PSTR("\r\nMaximum page number: "), 0x80);
427  D_PrintHex<uint8_t > (hcibuf[7], 0x80);
428  Notify(PSTR("\r\nExtended LMP features:"), 0x80);
429  for(uint8_t i = 0; i < 8; i++) {
430  Notify(PSTR(" "), 0x80);
431  D_PrintHex<uint8_t > (hcibuf[8 + i], 0x80);
432  }
433 #endif
434  if(hcibuf[6] == 0) { // Page 0
435 #ifdef DEBUG_USB_HOST
436  Notify(PSTR("\r\nDongle "), 0x80);
437 #endif
438  if(hcibuf[8 + 6] & (1U << 3)) {
439  simple_pairing_supported = true;
440 #ifdef DEBUG_USB_HOST
441  Notify(PSTR("supports"), 0x80);
442 #endif
443  } else {
444  simple_pairing_supported = false;
445 #ifdef DEBUG_USB_HOST
446  Notify(PSTR("does NOT support"), 0x80);
447 #endif
448  }
449 #ifdef DEBUG_USB_HOST
450  Notify(PSTR(" secure simple pairing (controller support)"), 0x80);
451 #endif
452  } else if(hcibuf[6] == 1) { // Page 1
453 #ifdef DEBUG_USB_HOST
454  Notify(PSTR("\r\nDongle "), 0x80);
455  if(hcibuf[8 + 0] & (1U << 0))
456  Notify(PSTR("supports"), 0x80);
457  else
458  Notify(PSTR("does NOT support"), 0x80);
459  Notify(PSTR(" secure simple pairing (host support)"), 0x80);
460 #endif
461  }
462  }
463 
465  } else if((hcibuf[3] == 0x09) && (hcibuf[4] == 0x10)) { // Parameters from read local bluetooth address
466  for(uint8_t i = 0; i < 6; i++)
467  my_bdaddr[i] = hcibuf[6 + i];
469  }
470  }
471  break;
472 
473  case EV_COMMAND_STATUS:
474  if(hcibuf[2]) { // Show status on serial if not OK
475 #ifdef DEBUG_USB_HOST
476  Notify(PSTR("\r\nHCI Command Failed: "), 0x80);
477  D_PrintHex<uint8_t > (hcibuf[2], 0x80);
478  Notify(PSTR("\r\nNum HCI Command Packets: "), 0x80);
479  D_PrintHex<uint8_t > (hcibuf[3], 0x80);
480  Notify(PSTR("\r\nCommand Opcode: "), 0x80);
481  D_PrintHex<uint8_t > (hcibuf[4], 0x80);
482  Notify(PSTR(" "), 0x80);
483  D_PrintHex<uint8_t > (hcibuf[5], 0x80);
484 #endif
485  }
486  break;
487 
488  case EV_INQUIRY_COMPLETE:
489  if(inquiry_counter >= 5 && (pairWithWii || pairWithHIDDevice)) {
490  inquiry_counter = 0;
491 #ifdef DEBUG_USB_HOST
492  if(pairWithWii)
493  Notify(PSTR("\r\nCouldn't find Wiimote"), 0x80);
494  else
495  Notify(PSTR("\r\nCouldn't find HID device"), 0x80);
496 #endif
497  connectToWii = false;
498  pairWithWii = false;
499  connectToHIDDevice = false;
500  pairWithHIDDevice = false;
501  hci_state = HCI_SCANNING_STATE;
502  }
503  inquiry_counter++;
504  break;
505 
506  case EV_INQUIRY_RESULT:
507  if(hcibuf[2]) { // Check that there is more than zero responses
508 #ifdef EXTRADEBUG
509  Notify(PSTR("\r\nNumber of responses: "), 0x80);
510  Notify(hcibuf[2], 0x80);
511 #endif
512  for(uint8_t i = 0; i < hcibuf[2]; i++) {
513  uint8_t offset = 8 * hcibuf[2] + 3 * i;
514 
515  for(uint8_t j = 0; j < 3; j++)
516  classOfDevice[j] = hcibuf[j + 4 + offset];
517 
518 #ifdef EXTRADEBUG
519  Notify(PSTR("\r\nClass of device: "), 0x80);
520  D_PrintHex<uint8_t > (classOfDevice[2], 0x80);
521  Notify(PSTR(" "), 0x80);
522  D_PrintHex<uint8_t > (classOfDevice[1], 0x80);
523  Notify(PSTR(" "), 0x80);
524  D_PrintHex<uint8_t > (classOfDevice[0], 0x80);
525 #endif
526 
527  if(pairWithWii && classOfDevice[2] == 0x00 && (classOfDevice[1] == 0x05) && (classOfDevice[0] & 0x0C)) { // See http://wiibrew.org/wiki/Wiimote#SDP_information
528  checkRemoteName = true; // Check remote name to distinguish between the different controllers
529 
530  for(uint8_t j = 0; j < 6; j++)
531  disc_bdaddr[j] = hcibuf[j + 3 + 6 * i];
532 
534  break;
535  } else if(pairWithHIDDevice && (classOfDevice[1] & 0x0F) == 0x05 && (classOfDevice[0] & 0xC8)) { // Check if it is a mouse, keyboard or a gamepad - see: http://bluetooth-pentest.narod.ru/software/bluetooth_class_of_device-service_generator.html
536 #ifdef DEBUG_USB_HOST
537  checkRemoteName = true; // Used to print name in the serial monitor if serial debugging is enabled
538 
539  if(classOfDevice[0] & 0x80)
540  Notify(PSTR("\r\nMouse found"), 0x80);
541  if(classOfDevice[0] & 0x40)
542  Notify(PSTR("\r\nKeyboard found"), 0x80);
543  if(classOfDevice[0] & 0x08)
544  Notify(PSTR("\r\nGamepad found"), 0x80);
545 #endif
546  for(uint8_t j = 0; j < 6; j++)
547  disc_bdaddr[j] = hcibuf[j + 3 + 6 * i];
548 
550  break;
551  }
552  }
553  }
554  break;
555 
556  case EV_CONNECT_COMPLETE:
558  if(!hcibuf[2]) { // Check if connected OK
559 #ifdef EXTRADEBUG
560  Notify(PSTR("\r\nConnection established"), 0x80);
561 #endif
562  hci_handle = hcibuf[3] | ((hcibuf[4] & 0x0F) << 8); // Store the handle for the ACL connection
563  hci_set_flag(HCI_FLAG_CONNECT_COMPLETE); // Set connection complete flag
564  } else {
565  hci_state = HCI_CHECK_DEVICE_SERVICE;
566 #ifdef DEBUG_USB_HOST
567  Notify(PSTR("\r\nConnection Failed: "), 0x80);
568  D_PrintHex<uint8_t > (hcibuf[2], 0x80);
569 #endif
570  }
571  break;
572 
574  if(!hcibuf[2]) { // Check if disconnected OK
575  hci_set_flag(HCI_FLAG_DISCONNECT_COMPLETE); // Set disconnect command complete flag
576  hci_clear_flag(HCI_FLAG_CONNECT_COMPLETE); // Clear connection complete flag
577  }
578  break;
579 
581  if(!hcibuf[2]) { // Check if reading is OK
582  for(uint8_t i = 0; i < min(sizeof (remote_name), sizeof (hcibuf) - 9); i++) {
583  remote_name[i] = hcibuf[9 + i];
584  if(remote_name[i] == '\0') // End of string
585  break;
586  }
587  // TODO: Always set '\0' in remote name!
589  }
590  break;
591 
592  case EV_INCOMING_CONNECT:
593  for(uint8_t i = 0; i < 6; i++)
594  disc_bdaddr[i] = hcibuf[i + 2];
595 
596  for(uint8_t i = 0; i < 3; i++)
597  classOfDevice[i] = hcibuf[i + 8];
598 
599  if((classOfDevice[1] & 0x0F) == 0x05 && (classOfDevice[0] & 0xC8)) { // Check if it is a mouse, keyboard or a gamepad
600 #ifdef DEBUG_USB_HOST
601  if(classOfDevice[0] & 0x80)
602  Notify(PSTR("\r\nMouse is connecting"), 0x80);
603  if(classOfDevice[0] & 0x40)
604  Notify(PSTR("\r\nKeyboard is connecting"), 0x80);
605  if(classOfDevice[0] & 0x08)
606  Notify(PSTR("\r\nGamepad is connecting"), 0x80);
607 #endif
608  incomingHIDDevice = true;
609  }
610 
611 #ifdef EXTRADEBUG
612  Notify(PSTR("\r\nClass of device: "), 0x80);
613  D_PrintHex<uint8_t > (classOfDevice[2], 0x80);
614  Notify(PSTR(" "), 0x80);
615  D_PrintHex<uint8_t > (classOfDevice[1], 0x80);
616  Notify(PSTR(" "), 0x80);
617  D_PrintHex<uint8_t > (classOfDevice[0], 0x80);
618 #endif
620  break;
621 
622  case EV_PIN_CODE_REQUEST:
623  if(pairWithWii) {
624 #ifdef DEBUG_USB_HOST
625  Notify(PSTR("\r\nPairing with Wiimote"), 0x80);
626 #endif
628  } else if(btdPin != NULL) {
629 #ifdef DEBUG_USB_HOST
630  Notify(PSTR("\r\nBluetooth pin is set too: "), 0x80);
631  NotifyStr(btdPin, 0x80);
632 #endif
634  } else {
635 #ifdef DEBUG_USB_HOST
636  Notify(PSTR("\r\nNo pin was set"), 0x80);
637 #endif
639  }
640  break;
641 
642  case EV_LINK_KEY_REQUEST:
643 #ifdef DEBUG_USB_HOST
644  Notify(PSTR("\r\nReceived Key Request"), 0x80);
645 #endif
647  break;
648 
650  if(!hcibuf[2]) { // Check if pairing was successful
651  if(pairWithWii && !connectToWii) {
652 #ifdef DEBUG_USB_HOST
653  Notify(PSTR("\r\nPairing successful with Wiimote"), 0x80);
654 #endif
655  connectToWii = true; // Used to indicate to the Wii service, that it should connect to this device
656  } else if(pairWithHIDDevice && !connectToHIDDevice) {
657 #ifdef DEBUG_USB_HOST
658  Notify(PSTR("\r\nPairing successful with HID device"), 0x80);
659 #endif
660  connectToHIDDevice = true; // Used to indicate to the BTHID service, that it should connect to this device
661  } else {
662 #ifdef EXTRADEBUG
663  Notify(PSTR("\r\nPairing was successful"), 0x80);
664 #endif
665  }
666  } else {
667 #ifdef DEBUG_USB_HOST
668  Notify(PSTR("\r\nPairing Failed: "), 0x80);
669  D_PrintHex<uint8_t > (hcibuf[2], 0x80);
670 #endif
672  hci_state = HCI_DISCONNECT_STATE;
673  }
674  break;
675 
677 #ifdef DEBUG_USB_HOST
678  Notify(PSTR("\r\nReceived IO Capability Request"), 0x80);
679 #endif
681  break;
682 
684 #ifdef EXTRADEBUG
685  Notify(PSTR("\r\nReceived IO Capability Response: "), 0x80);
686  Notify(PSTR("\r\nIO capability: "), 0x80);
687  D_PrintHex<uint8_t > (hcibuf[8], 0x80);
688  Notify(PSTR("\r\nOOB data present: "), 0x80);
689  D_PrintHex<uint8_t > (hcibuf[9], 0x80);
690  Notify(PSTR("\r\nAuthentication request: "), 0x80);
691  D_PrintHex<uint8_t > (hcibuf[10], 0x80);
692 #endif
693  break;
694 
696 #ifdef DEBUG_USB_HOST
697  Notify(PSTR("\r\nUser confirmation Request"), 0x80);
698 #ifdef EXTRADEBUG
699  Notify(PSTR(": \r\nNumeric value: "), 0x80);
700  for(uint8_t i = 0; i < 4; i++) {
701  Notify(PSTR(" "), 0x80);
702  D_PrintHex<uint8_t > (hcibuf[8 + i], 0x80);
703  }
704 #endif
705 #endif
706  // Simply confirm the connection, as the host has no "NoInputNoOutput" capabilities
708  break;
709 
711 #ifdef EXTRADEBUG
712  if(!hcibuf[2]) { // Check if connected OK
713  Notify(PSTR("\r\nSimple Pairing succeeded"), 0x80);
714  } else {
715  Notify(PSTR("\r\nSimple Pairing failed: "), 0x80);
716  D_PrintHex<uint8_t > (hcibuf[2], 0x80);
717  }
718 #endif
719  break;
720 
721  /* We will just ignore the following events */
722  case EV_MAX_SLOTS_CHANGE:
723  case EV_NUM_COMPLETE_PKT:
724  break;
725  case EV_ROLE_CHANGED:
727  case EV_LOOPBACK_COMMAND:
734 #ifdef EXTRADEBUG
735  if(hcibuf[0] != 0x00) {
736  Notify(PSTR("\r\nIgnore HCI Event: "), 0x80);
737  D_PrintHex<uint8_t > (hcibuf[0], 0x80);
738  }
739 #endif
740  break;
741 #ifdef EXTRADEBUG
742  default:
743  if(hcibuf[0] != 0x00) {
744  Notify(PSTR("\r\nUnmanaged HCI Event: "), 0x80);
745  D_PrintHex<uint8_t > (hcibuf[0], 0x80);
746  Notify(PSTR(", data: "), 0x80);
747  for(uint16_t i = 0; i < hcibuf[1]; i++) {
748  D_PrintHex<uint8_t > (hcibuf[2 + i], 0x80);
749  Notify(PSTR(" "), 0x80);
750  }
751  }
752  break;
753 #endif
754  } // Switch
755  }
756 #ifdef EXTRADEBUG
757  else {
758  Notify(PSTR("\r\nHCI event error: "), 0x80);
759  D_PrintHex<uint8_t > (rcode, 0x80);
760  }
761 #endif
762 }
763 
764 /* Poll Bluetooth and print result */
765 void BTD::HCI_task() {
766  switch(hci_state) {
767  case HCI_INIT_STATE:
768  hci_counter++;
769  if(hci_counter > hci_num_reset_loops) { // wait until we have looped x times to clear any old events
770  hci_reset();
771  hci_state = HCI_RESET_STATE;
772  hci_counter = 0;
773  }
774  break;
775 
776  case HCI_RESET_STATE:
777  hci_counter++;
779  hci_counter = 0;
780 #ifdef DEBUG_USB_HOST
781  Notify(PSTR("\r\nHCI Reset complete"), 0x80);
782 #endif
783  hci_state = HCI_CLASS_STATE;
785  } else if(hci_counter > hci_num_reset_loops) {
786  hci_num_reset_loops *= 10;
787  if(hci_num_reset_loops > 2000)
788  hci_num_reset_loops = 2000;
789 #ifdef DEBUG_USB_HOST
790  Notify(PSTR("\r\nNo response to HCI Reset"), 0x80);
791 #endif
792  hci_state = HCI_INIT_STATE;
793  hci_counter = 0;
794  }
795  break;
796 
797  case HCI_CLASS_STATE:
799 #ifdef DEBUG_USB_HOST
800  Notify(PSTR("\r\nWrite class of device"), 0x80);
801 #endif
802  hci_state = HCI_BDADDR_STATE;
803  hci_read_bdaddr();
804  }
805  break;
806 
807  case HCI_BDADDR_STATE:
809 #ifdef DEBUG_USB_HOST
810  Notify(PSTR("\r\nLocal Bluetooth Address: "), 0x80);
811  for(int8_t i = 5; i > 0; i--) {
812  D_PrintHex<uint8_t > (my_bdaddr[i], 0x80);
813  Notify(PSTR(":"), 0x80);
814  }
815  D_PrintHex<uint8_t > (my_bdaddr[0], 0x80);
816 #endif
818  hci_state = HCI_LOCAL_VERSION_STATE;
819  }
820  break;
821 
822  case HCI_LOCAL_VERSION_STATE: // The local version is used by the PS3BT class
824  if(btdName != NULL) {
826  hci_state = HCI_WRITE_NAME_STATE;
827  } else if(useSimplePairing) {
828  hci_read_local_extended_features(0); // "Requests the normal LMP features as returned by Read_Local_Supported_Features"
829  //hci_read_local_extended_features(1); // Read page 1
831  } else
832  hci_state = HCI_CHECK_DEVICE_SERVICE;
833  }
834  break;
835 
838 #ifdef DEBUG_USB_HOST
839  Notify(PSTR("\r\nThe name was set to: "), 0x80);
840  NotifyStr(btdName, 0x80);
841 #endif
842  if(useSimplePairing) {
843  hci_read_local_extended_features(0); // "Requests the normal LMP features as returned by Read_Local_Supported_Features"
844  //hci_read_local_extended_features(1); // Read page 1
846  } else
847  hci_state = HCI_CHECK_DEVICE_SERVICE;
848  }
849  break;
850 
853  if(simple_pairing_supported) {
855  hci_state = HCI_WRITE_SIMPLE_PAIRING_STATE;
856  } else
857  hci_state = HCI_CHECK_DEVICE_SERVICE;
858  }
859  break;
860 
863 #ifdef DEBUG_USB_HOST
864  Notify(PSTR("\r\nSimple pairing was enabled"), 0x80);
865 #endif
867  hci_state = HCI_SET_EVENT_MASK_STATE;
868  }
869  break;
870 
873 #ifdef DEBUG_USB_HOST
874  Notify(PSTR("\r\nSet event mask completed"), 0x80);
875 #endif
876  hci_state = HCI_CHECK_DEVICE_SERVICE;
877  }
878  break;
879 
881  if(pairWithHIDDevice || pairWithWii) { // Check if it should try to connect to a Wiimote
882 #ifdef DEBUG_USB_HOST
883  if(pairWithWii)
884  Notify(PSTR("\r\nStarting inquiry\r\nPress 1 & 2 on the Wiimote\r\nOr press the SYNC button if you are using a Wii U Pro Controller or a Wii Balance Board"), 0x80);
885  else
886  Notify(PSTR("\r\nPlease enable discovery of your device"), 0x80);
887 #endif
888  hci_inquiry();
889  hci_state = HCI_INQUIRY_STATE;
890  } else
891  hci_state = HCI_SCANNING_STATE; // Don't try to connect to a Wiimote
892  break;
893 
894  case HCI_INQUIRY_STATE:
896  hci_inquiry_cancel(); // Stop inquiry
897 #ifdef DEBUG_USB_HOST
898  if(pairWithWii)
899  Notify(PSTR("\r\nWiimote found"), 0x80);
900  else
901  Notify(PSTR("\r\nHID device found"), 0x80);
902 
903  Notify(PSTR("\r\nNow just create the instance like so:"), 0x80);
904  if(pairWithWii)
905  Notify(PSTR("\r\nWII Wii(&Btd);"), 0x80);
906  else
907  Notify(PSTR("\r\nBTHID bthid(&Btd);"), 0x80);
908 
909  Notify(PSTR("\r\nAnd then press any button on the "), 0x80);
910  if(pairWithWii)
911  Notify(PSTR("Wiimote"), 0x80);
912  else
913  Notify(PSTR("device"), 0x80);
914 #endif
915  if(checkRemoteName) {
916  hci_remote_name(); // We need to know the name to distinguish between the Wiimote, the new Wiimote with Motion Plus inside, a Wii U Pro Controller and a Wii Balance Board
917  hci_state = HCI_REMOTE_NAME_STATE;
918  } else
919  hci_state = HCI_CONNECT_DEVICE_STATE;
920  }
921  break;
922 
925 #ifdef DEBUG_USB_HOST
926  if(pairWithWii)
927  Notify(PSTR("\r\nConnecting to Wiimote"), 0x80);
928  else
929  Notify(PSTR("\r\nConnecting to HID device"), 0x80);
930 #endif
931  checkRemoteName = false;
932  hci_connect();
933  hci_state = HCI_CONNECTED_DEVICE_STATE;
934  }
935  break;
936 
940 #ifdef DEBUG_USB_HOST
941  if(pairWithWii)
942  Notify(PSTR("\r\nConnected to Wiimote"), 0x80);
943  else
944  Notify(PSTR("\r\nConnected to HID device"), 0x80);
945 #endif
946  hci_authentication_request(); // This will start the pairing with the device
947  hci_state = HCI_SCANNING_STATE;
948  } else {
949 #ifdef DEBUG_USB_HOST
950  Notify(PSTR("\r\nTrying to connect one more time..."), 0x80);
951 #endif
952  hci_connect(); // Try to connect one more time
953  }
954  }
955  break;
956 
957  case HCI_SCANNING_STATE:
959 #ifdef DEBUG_USB_HOST
960  Notify(PSTR("\r\nWait For Incoming Connection Request"), 0x80);
961 #endif
963  waitingForConnection = true;
964  hci_state = HCI_CONNECT_IN_STATE;
965  }
966  break;
967 
970  waitingForConnection = false;
971 #ifdef DEBUG_USB_HOST
972  Notify(PSTR("\r\nIncoming Connection Request"), 0x80);
973 #endif
974  hci_remote_name();
975  hci_state = HCI_REMOTE_NAME_STATE;
977  hci_state = HCI_DISCONNECT_STATE;
978  break;
979 
982 #ifdef DEBUG_USB_HOST
983  Notify(PSTR("\r\nRemote Name: "), 0x80);
984  for(uint8_t i = 0; i < strlen(remote_name); i++)
985  Notifyc(remote_name[i], 0x80);
986 #endif
987  if(strncmp((const char*)remote_name, "Nintendo", 8) == 0) {
988  incomingWii = true;
989  motionPlusInside = false;
990  wiiUProController = false;
991  pairWiiUsingSync = false;
992 #ifdef DEBUG_USB_HOST
993  Notify(PSTR("\r\nWiimote is connecting"), 0x80);
994 #endif
995  if(strncmp((const char*)remote_name, "Nintendo RVL-CNT-01-TR", 22) == 0) {
996 #ifdef DEBUG_USB_HOST
997  Notify(PSTR(" with Motion Plus Inside"), 0x80);
998 #endif
999  motionPlusInside = true;
1000  } else if(strncmp((const char*)remote_name, "Nintendo RVL-CNT-01-UC", 22) == 0) {
1001 #ifdef DEBUG_USB_HOST
1002  Notify(PSTR(" - Wii U Pro Controller"), 0x80);
1003 #endif
1004  wiiUProController = motionPlusInside = pairWiiUsingSync = true;
1005  } else if(strncmp((const char*)remote_name, "Nintendo RVL-WBC-01", 19) == 0) {
1006 #ifdef DEBUG_USB_HOST
1007  Notify(PSTR(" - Wii Balance Board"), 0x80);
1008 #endif
1009  pairWiiUsingSync = true;
1010  }
1011  }
1012  if(classOfDevice[2] == 0 && classOfDevice[1] == 0x25 && classOfDevice[0] == 0x08 && strncmp((const char*)remote_name, "Wireless Controller", 19) == 0) {
1013 #ifdef DEBUG_USB_HOST
1014  Notify(PSTR("\r\nPS4 controller is connecting"), 0x80);
1015 #endif
1016  incomingPS4 = true;
1017  }
1018  if((pairWithWii || pairWithHIDDevice) && checkRemoteName)
1019  hci_state = HCI_CONNECT_DEVICE_STATE;
1020  else {
1022  hci_state = HCI_CONNECTED_STATE;
1023  }
1024  }
1025  break;
1026 
1027  case HCI_CONNECTED_STATE:
1029 #ifdef DEBUG_USB_HOST
1030  Notify(PSTR("\r\nConnected to Device: "), 0x80);
1031  for(int8_t i = 5; i > 0; i--) {
1032  D_PrintHex<uint8_t > (disc_bdaddr[i], 0x80);
1033  Notify(PSTR(":"), 0x80);
1034  }
1035  D_PrintHex<uint8_t > (disc_bdaddr[0], 0x80);
1036 #endif
1037  if(incomingPS4)
1038  connectToHIDDevice = true; // We should always connect to the PS4 controller
1039 
1040  // Clear these flags for a new connection
1041  l2capConnectionClaimed = false;
1042  sdpConnectionClaimed = false;
1043  rfcommConnectionClaimed = false;
1044 
1045  hci_event_flag = 0;
1046  hci_state = HCI_DONE_STATE;
1047  }
1048  break;
1049 
1050  case HCI_DONE_STATE:
1051  hci_counter++;
1052  if(hci_counter > 1000) { // Wait until we have looped 1000 times to make sure that the L2CAP connection has been started
1053  hci_counter = 0;
1054  hci_state = HCI_SCANNING_STATE;
1055  }
1056  break;
1057 
1058  case HCI_DISCONNECT_STATE:
1060 #ifdef DEBUG_USB_HOST
1061  Notify(PSTR("\r\nHCI Disconnected from Device"), 0x80);
1062 #endif
1063  hci_event_flag = 0; // Clear all flags
1064 
1065  // Reset all buffers
1066  memset(hcibuf, 0, BULK_MAXPKTSIZE);
1067  memset(l2capinbuf, 0, BULK_MAXPKTSIZE);
1068 
1069  connectToWii = incomingWii = pairWithWii = false;
1070  connectToHIDDevice = incomingHIDDevice = pairWithHIDDevice = checkRemoteName = false;
1071  incomingPS4 = false;
1072 
1073  hci_state = HCI_SCANNING_STATE;
1074  }
1075  break;
1076  default:
1077  break;
1078  }
1079 }
1080 
1081 void BTD::ACL_event_task() {
1082  uint16_t length = BULK_MAXPKTSIZE;
1083  uint8_t rcode = pUsb->inTransfer(bAddress, epInfo[ BTD_DATAIN_PIPE ].epAddr, &length, l2capinbuf, pollInterval); // Input on endpoint 2
1084 
1085  if(!rcode) { // Check for errors
1086  if(length > 0) { // Check if any data was read
1087  for(uint8_t i = 0; i < BTD_NUM_SERVICES; i++) {
1088  if(btService[i])
1089  btService[i]->ACLData(l2capinbuf);
1090  }
1091  }
1092  }
1093 #ifdef EXTRADEBUG
1094  else if(rcode != hrNAK) {
1095  Notify(PSTR("\r\nACL data in error: "), 0x80);
1096  D_PrintHex<uint8_t > (rcode, 0x80);
1097  }
1098 #endif
1099  for(uint8_t i = 0; i < BTD_NUM_SERVICES; i++)
1100  if(btService[i])
1101  btService[i]->Run();
1102 }
1103 
1104 /************************************************************/
1105 /* HCI Commands */
1106 
1107 /************************************************************/
1108 void BTD::HCI_Command(uint8_t* data, uint16_t nbytes) {
1110  pUsb->ctrlReq(bAddress, epInfo[ BTD_CONTROL_PIPE ].epAddr, bmREQ_HCI_OUT, 0x00, 0x00, 0x00, 0x00, nbytes, nbytes, data, NULL);
1111 }
1112 
1114  hci_event_flag = 0; // Clear all the flags
1115  hcibuf[0] = 0x03; // HCI OCF = 3
1116  hcibuf[1] = 0x03 << 2; // HCI OGF = 3
1117  hcibuf[2] = 0x00;
1118 
1119  HCI_Command(hcibuf, 3);
1120 }
1121 
1124  hcibuf[0] = 0x1A; // HCI OCF = 1A
1125  hcibuf[1] = 0x03 << 2; // HCI OGF = 3
1126  hcibuf[2] = 0x01; // parameter length = 1
1127  if(btdName != NULL)
1128  hcibuf[3] = 0x03; // Inquiry Scan enabled. Page Scan enabled.
1129  else
1130  hcibuf[3] = 0x02; // Inquiry Scan disabled. Page Scan enabled.
1131 
1132  HCI_Command(hcibuf, 4);
1133 }
1134 
1136  hcibuf[0] = 0x1A; // HCI OCF = 1A
1137  hcibuf[1] = 0x03 << 2; // HCI OGF = 3
1138  hcibuf[2] = 0x01; // parameter length = 1
1139  hcibuf[3] = 0x00; // Inquiry Scan disabled. Page Scan disabled.
1140 
1141  HCI_Command(hcibuf, 4);
1142 }
1143 
1146  hcibuf[0] = 0x09; // HCI OCF = 9
1147  hcibuf[1] = 0x04 << 2; // HCI OGF = 4
1148  hcibuf[2] = 0x00;
1149 
1150  HCI_Command(hcibuf, 3);
1151 }
1152 
1155  hcibuf[0] = 0x01; // HCI OCF = 1
1156  hcibuf[1] = 0x04 << 2; // HCI OGF = 4
1157  hcibuf[2] = 0x00;
1158 
1159  HCI_Command(hcibuf, 3);
1160 }
1161 
1162 void BTD::hci_read_local_extended_features(uint8_t page_number) {
1164  hcibuf[0] = 0x04; // HCI OCF = 4
1165  hcibuf[1] = 0x04 << 2; // HCI OGF = 4
1166  hcibuf[2] = 0x01; // parameter length = 1
1167  hcibuf[3] = page_number;
1168 
1169  HCI_Command(hcibuf, 4);
1170 }
1171 
1174  hcibuf[0] = 0x09; // HCI OCF = 9
1175  hcibuf[1] = 0x01 << 2; // HCI OGF = 1
1176  hcibuf[2] = 0x07; // parameter length 7
1177  hcibuf[3] = disc_bdaddr[0]; // 6 octet bdaddr
1178  hcibuf[4] = disc_bdaddr[1];
1179  hcibuf[5] = disc_bdaddr[2];
1180  hcibuf[6] = disc_bdaddr[3];
1181  hcibuf[7] = disc_bdaddr[4];
1182  hcibuf[8] = disc_bdaddr[5];
1183  hcibuf[9] = 0x00; // Switch role to master
1184 
1185  HCI_Command(hcibuf, 10);
1186 }
1187 
1190  hcibuf[0] = 0x19; // HCI OCF = 19
1191  hcibuf[1] = 0x01 << 2; // HCI OGF = 1
1192  hcibuf[2] = 0x0A; // parameter length = 10
1193  hcibuf[3] = disc_bdaddr[0]; // 6 octet bdaddr
1194  hcibuf[4] = disc_bdaddr[1];
1195  hcibuf[5] = disc_bdaddr[2];
1196  hcibuf[6] = disc_bdaddr[3];
1197  hcibuf[7] = disc_bdaddr[4];
1198  hcibuf[8] = disc_bdaddr[5];
1199  hcibuf[9] = 0x01; // Page Scan Repetition Mode
1200  hcibuf[10] = 0x00; // Reserved
1201  hcibuf[11] = 0x00; // Clock offset - low byte
1202  hcibuf[12] = 0x00; // Clock offset - high byte
1203 
1204  HCI_Command(hcibuf, 13);
1205 }
1206 
1207 void BTD::hci_write_local_name(const char* name) {
1208  hcibuf[0] = 0x13; // HCI OCF = 13
1209  hcibuf[1] = 0x03 << 2; // HCI OGF = 3
1210  hcibuf[2] = strlen(name) + 1; // parameter length = the length of the string + end byte
1211  uint8_t i;
1212  for(i = 0; i < strlen(name); i++)
1213  hcibuf[i + 3] = name[i];
1214  hcibuf[i + 3] = 0x00; // End of string
1215 
1216  HCI_Command(hcibuf, 4 + strlen(name));
1217 }
1218 
1220  hcibuf[0] = 0x01; // HCI OCF = 01
1221  hcibuf[1] = 0x03 << 2; // HCI OGF = 3
1222  hcibuf[2] = 0x08;
1223  // The first 6 bytes are the default of 1FFF FFFF FFFF
1224  // However we need to set bits 48-55 for simple pairing to work
1225  hcibuf[3] = 0xFF;
1226  hcibuf[4] = 0xFF;
1227  hcibuf[5] = 0xFF;
1228  hcibuf[6] = 0xFF;
1229  hcibuf[7] = 0xFF;
1230  hcibuf[8] = 0x1F;
1231  hcibuf[9] = 0xFF; // Enable bits 48-55 used for simple pairing
1232  hcibuf[10] = 0x00;
1233 
1234  HCI_Command(hcibuf, 11);
1235 }
1236 
1238  hcibuf[0] = 0x56; // HCI OCF = 56
1239  hcibuf[1] = 0x03 << 2; // HCI OGF = 3
1240  hcibuf[2] = 1; // parameter length = 1
1241  hcibuf[3] = enable ? 1 : 0;
1242 
1243  HCI_Command(hcibuf, 4);
1244 }
1245 
1248  hcibuf[0] = 0x01;
1249  hcibuf[1] = 0x01 << 2; // HCI OGF = 1
1250  hcibuf[2] = 0x05; // Parameter Total Length = 5
1251  hcibuf[3] = 0x33; // LAP: Genera/Unlimited Inquiry Access Code (GIAC = 0x9E8B33) - see https://www.bluetooth.org/Technical/AssignedNumbers/baseband.htm
1252  hcibuf[4] = 0x8B;
1253  hcibuf[5] = 0x9E;
1254  hcibuf[6] = 0x30; // Inquiry time = 61.44 sec (maximum)
1255  hcibuf[7] = 0x0A; // 10 number of responses
1256 
1257  HCI_Command(hcibuf, 8);
1258 }
1259 
1261  hcibuf[0] = 0x02;
1262  hcibuf[1] = 0x01 << 2; // HCI OGF = 1
1263  hcibuf[2] = 0x00; // Parameter Total Length = 0
1264 
1265  HCI_Command(hcibuf, 3);
1266 }
1267 
1269  hci_connect(disc_bdaddr); // Use last discovered device
1270 }
1271 
1272 void BTD::hci_connect(uint8_t *bdaddr) {
1274  hcibuf[0] = 0x05; // HCI OCF = 5
1275  hcibuf[1] = 0x01 << 2; // HCI OGF = 1
1276  hcibuf[2] = 0x0D; // parameter Total Length = 13
1277  hcibuf[3] = bdaddr[0]; // 6 octet bdaddr (LSB)
1278  hcibuf[4] = bdaddr[1];
1279  hcibuf[5] = bdaddr[2];
1280  hcibuf[6] = bdaddr[3];
1281  hcibuf[7] = bdaddr[4];
1282  hcibuf[8] = bdaddr[5];
1283  hcibuf[9] = 0x18; // DM1 or DH1 may be used
1284  hcibuf[10] = 0xCC; // DM3, DH3, DM5, DH5 may be used
1285  hcibuf[11] = 0x01; // Page repetition mode R1
1286  hcibuf[12] = 0x00; // Reserved
1287  hcibuf[13] = 0x00; // Clock offset
1288  hcibuf[14] = 0x00; // Invalid clock offset
1289  hcibuf[15] = 0x00; // Do not allow role switch
1290 
1291  HCI_Command(hcibuf, 16);
1292 }
1293 
1295  hcibuf[0] = 0x0D; // HCI OCF = 0D
1296  hcibuf[1] = 0x01 << 2; // HCI OGF = 1
1297  hcibuf[2] = 0x17; // parameter length 23
1298  hcibuf[3] = disc_bdaddr[0]; // 6 octet bdaddr
1299  hcibuf[4] = disc_bdaddr[1];
1300  hcibuf[5] = disc_bdaddr[2];
1301  hcibuf[6] = disc_bdaddr[3];
1302  hcibuf[7] = disc_bdaddr[4];
1303  hcibuf[8] = disc_bdaddr[5];
1304  if(pairWithWii) {
1305  hcibuf[9] = 6; // Pin length is the length of the Bluetooth address
1306  if(pairWiiUsingSync) {
1307 #ifdef DEBUG_USB_HOST
1308  Notify(PSTR("\r\nPairing with Wii controller via SYNC"), 0x80);
1309 #endif
1310  for(uint8_t i = 0; i < 6; i++)
1311  hcibuf[10 + i] = my_bdaddr[i]; // The pin is the Bluetooth dongles Bluetooth address backwards
1312  } else {
1313  for(uint8_t i = 0; i < 6; i++)
1314  hcibuf[10 + i] = disc_bdaddr[i]; // The pin is the Wiimote's Bluetooth address backwards
1315  }
1316  for(uint8_t i = 16; i < 26; i++)
1317  hcibuf[i] = 0x00; // The rest should be 0
1318  } else {
1319  hcibuf[9] = strlen(btdPin); // Length of pin
1320  uint8_t i;
1321  for(i = 0; i < strlen(btdPin); i++) // The maximum size of the pin is 16
1322  hcibuf[i + 10] = btdPin[i];
1323  for(; i < 16; i++)
1324  hcibuf[i + 10] = 0x00; // The rest should be 0
1325  }
1326 
1327  HCI_Command(hcibuf, 26);
1328 }
1329 
1331  hcibuf[0] = 0x0E; // HCI OCF = 0E
1332  hcibuf[1] = 0x01 << 2; // HCI OGF = 1
1333  hcibuf[2] = 0x06; // parameter length 6
1334  hcibuf[3] = disc_bdaddr[0]; // 6 octet bdaddr
1335  hcibuf[4] = disc_bdaddr[1];
1336  hcibuf[5] = disc_bdaddr[2];
1337  hcibuf[6] = disc_bdaddr[3];
1338  hcibuf[7] = disc_bdaddr[4];
1339  hcibuf[8] = disc_bdaddr[5];
1340 
1341  HCI_Command(hcibuf, 9);
1342 }
1343 
1345  hcibuf[0] = 0x0C; // HCI OCF = 0C
1346  hcibuf[1] = 0x01 << 2; // HCI OGF = 1
1347  hcibuf[2] = 0x06; // parameter length 6
1348  hcibuf[3] = disc_bdaddr[0]; // 6 octet bdaddr
1349  hcibuf[4] = disc_bdaddr[1];
1350  hcibuf[5] = disc_bdaddr[2];
1351  hcibuf[6] = disc_bdaddr[3];
1352  hcibuf[7] = disc_bdaddr[4];
1353  hcibuf[8] = disc_bdaddr[5];
1354 
1355  HCI_Command(hcibuf, 9);
1356 }
1357 
1359  hcibuf[0] = 0x2B; // HCI OCF = 2B
1360  hcibuf[1] = 0x01 << 2; // HCI OGF = 1
1361  hcibuf[2] = 0x09;
1362  hcibuf[3] = disc_bdaddr[0]; // 6 octet bdaddr
1363  hcibuf[4] = disc_bdaddr[1];
1364  hcibuf[5] = disc_bdaddr[2];
1365  hcibuf[6] = disc_bdaddr[3];
1366  hcibuf[7] = disc_bdaddr[4];
1367  hcibuf[8] = disc_bdaddr[5];
1368  hcibuf[9] = 0x03; // NoInputNoOutput
1369  hcibuf[10] = 0x00; // OOB authentication data not present
1370  hcibuf[11] = 0x00; // MITM Protection Not Required – No Bonding. Numeric comparison with automatic accept allowed
1371 
1372  HCI_Command(hcibuf, 12);
1373 }
1374 
1376  hcibuf[0] = 0x2C; // HCI OCF = 2C
1377  hcibuf[1] = 0x01 << 2; // HCI OGF = 1
1378  hcibuf[2] = 0x06; // parameter length 6
1379  hcibuf[3] = disc_bdaddr[0]; // 6 octet bdaddr
1380  hcibuf[4] = disc_bdaddr[1];
1381  hcibuf[5] = disc_bdaddr[2];
1382  hcibuf[6] = disc_bdaddr[3];
1383  hcibuf[7] = disc_bdaddr[4];
1384  hcibuf[8] = disc_bdaddr[5];
1385 
1386  HCI_Command(hcibuf, 9);
1387 }
1388 
1390  hcibuf[0] = 0x11; // HCI OCF = 11
1391  hcibuf[1] = 0x01 << 2; // HCI OGF = 1
1392  hcibuf[2] = 0x02; // parameter length = 2
1393  hcibuf[3] = (uint8_t)(hci_handle & 0xFF); //connection handle - low byte
1394  hcibuf[4] = (uint8_t)((hci_handle >> 8) & 0x0F); //connection handle - high byte
1395 
1396  HCI_Command(hcibuf, 5);
1397 }
1398 
1399 void BTD::hci_disconnect(uint16_t handle) { // This is called by the different services
1401  hcibuf[0] = 0x06; // HCI OCF = 6
1402  hcibuf[1] = 0x01 << 2; // HCI OGF = 1
1403  hcibuf[2] = 0x03; // parameter length = 3
1404  hcibuf[3] = (uint8_t)(handle & 0xFF); //connection handle - low byte
1405  hcibuf[4] = (uint8_t)((handle >> 8) & 0x0F); //connection handle - high byte
1406  hcibuf[5] = 0x13; // reason
1407 
1408  HCI_Command(hcibuf, 6);
1409 }
1410 
1411 void BTD::hci_write_class_of_device() { // See http://bluetooth-pentest.narod.ru/software/bluetooth_class_of_device-service_generator.html
1412  hcibuf[0] = 0x24; // HCI OCF = 24
1413  hcibuf[1] = 0x03 << 2; // HCI OGF = 3
1414  hcibuf[2] = 0x03; // parameter length = 3
1415  hcibuf[3] = 0x04; // Robot
1416  hcibuf[4] = 0x08; // Toy
1417  hcibuf[5] = 0x00;
1418 
1419  HCI_Command(hcibuf, 6);
1420 }
1421 /*******************************************************************
1422  * *
1423  * HCI ACL Data Packet *
1424  * *
1425  * buf[0] buf[1] buf[2] buf[3]
1426  * 0 4 8 11 12 16 24 31 MSB
1427  * .-+-+-+-+-+-+-+-|-+-+-+-|-+-|-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-.
1428  * | HCI Handle |PB |BC | Data Total Length | HCI ACL Data Packet
1429  * .-+-+-+-+-+-+-+-|-+-+-+-|-+-|-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-.
1430  *
1431  * buf[4] buf[5] buf[6] buf[7]
1432  * 0 8 16 31 MSB
1433  * .-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-.
1434  * | Length | Channel ID | Basic L2CAP header
1435  * .-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-.
1436  *
1437  * buf[8] buf[9] buf[10] buf[11]
1438  * 0 8 16 31 MSB
1439  * .-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-.
1440  * | Code | Identifier | Length | Control frame (C-frame)
1441  * .-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-. (signaling packet format)
1442  */
1443 /************************************************************/
1444 /* L2CAP Commands */
1445 
1446 /************************************************************/
1447 void BTD::L2CAP_Command(uint16_t handle, uint8_t* data, uint8_t nbytes, uint8_t channelLow, uint8_t channelHigh) {
1448  uint8_t buf[8 + nbytes];
1449  buf[0] = (uint8_t)(handle & 0xff); // HCI handle with PB,BC flag
1450  buf[1] = (uint8_t)(((handle >> 8) & 0x0f) | 0x20);
1451  buf[2] = (uint8_t)((4 + nbytes) & 0xff); // HCI ACL total data length
1452  buf[3] = (uint8_t)((4 + nbytes) >> 8);
1453  buf[4] = (uint8_t)(nbytes & 0xff); // L2CAP header: Length
1454  buf[5] = (uint8_t)(nbytes >> 8);
1455  buf[6] = channelLow;
1456  buf[7] = channelHigh;
1457 
1458  for(uint16_t i = 0; i < nbytes; i++) // L2CAP C-frame
1459  buf[8 + i] = data[i];
1460 
1461  uint8_t rcode = pUsb->outTransfer(bAddress, epInfo[ BTD_DATAOUT_PIPE ].epAddr, (8 + nbytes), buf);
1462  if(rcode) {
1463  delay(100); // This small delay prevents it from overflowing if it fails
1464 #ifdef DEBUG_USB_HOST
1465  Notify(PSTR("\r\nError sending L2CAP message: 0x"), 0x80);
1466  D_PrintHex<uint8_t > (rcode, 0x80);
1467  Notify(PSTR(" - Channel ID: "), 0x80);
1468  D_PrintHex<uint8_t > (channelHigh, 0x80);
1469  Notify(PSTR(" "), 0x80);
1470  D_PrintHex<uint8_t > (channelLow, 0x80);
1471 #endif
1472  }
1473 }
1474 
1475 void BTD::l2cap_connection_request(uint16_t handle, uint8_t rxid, uint8_t* scid, uint16_t psm) {
1476  l2capoutbuf[0] = L2CAP_CMD_CONNECTION_REQUEST; // Code
1477  l2capoutbuf[1] = rxid; // Identifier
1478  l2capoutbuf[2] = 0x04; // Length
1479  l2capoutbuf[3] = 0x00;
1480  l2capoutbuf[4] = (uint8_t)(psm & 0xff); // PSM
1481  l2capoutbuf[5] = (uint8_t)(psm >> 8);
1482  l2capoutbuf[6] = scid[0]; // Source CID
1483  l2capoutbuf[7] = scid[1];
1484 
1485  L2CAP_Command(handle, l2capoutbuf, 8);
1486 }
1487 
1488 void BTD::l2cap_connection_response(uint16_t handle, uint8_t rxid, uint8_t* dcid, uint8_t* scid, uint8_t result) {
1489  l2capoutbuf[0] = L2CAP_CMD_CONNECTION_RESPONSE; // Code
1490  l2capoutbuf[1] = rxid; // Identifier
1491  l2capoutbuf[2] = 0x08; // Length
1492  l2capoutbuf[3] = 0x00;
1493  l2capoutbuf[4] = dcid[0]; // Destination CID
1494  l2capoutbuf[5] = dcid[1];
1495  l2capoutbuf[6] = scid[0]; // Source CID
1496  l2capoutbuf[7] = scid[1];
1497  l2capoutbuf[8] = result; // Result: Pending or Success
1498  l2capoutbuf[9] = 0x00;
1499  l2capoutbuf[10] = 0x00; // No further information
1500  l2capoutbuf[11] = 0x00;
1501 
1502  L2CAP_Command(handle, l2capoutbuf, 12);
1503 }
1504 
1505 void BTD::l2cap_config_request(uint16_t handle, uint8_t rxid, uint8_t* dcid) {
1506  l2capoutbuf[0] = L2CAP_CMD_CONFIG_REQUEST; // Code
1507  l2capoutbuf[1] = rxid; // Identifier
1508  l2capoutbuf[2] = 0x08; // Length
1509  l2capoutbuf[3] = 0x00;
1510  l2capoutbuf[4] = dcid[0]; // Destination CID
1511  l2capoutbuf[5] = dcid[1];
1512  l2capoutbuf[6] = 0x00; // Flags
1513  l2capoutbuf[7] = 0x00;
1514  l2capoutbuf[8] = 0x01; // Config Opt: type = MTU (Maximum Transmission Unit) - Hint
1515  l2capoutbuf[9] = 0x02; // Config Opt: length
1516  l2capoutbuf[10] = 0xFF; // MTU
1517  l2capoutbuf[11] = 0xFF;
1518 
1519  L2CAP_Command(handle, l2capoutbuf, 12);
1520 }
1521 
1522 void BTD::l2cap_config_response(uint16_t handle, uint8_t rxid, uint8_t* scid) {
1523  l2capoutbuf[0] = L2CAP_CMD_CONFIG_RESPONSE; // Code
1524  l2capoutbuf[1] = rxid; // Identifier
1525  l2capoutbuf[2] = 0x0A; // Length
1526  l2capoutbuf[3] = 0x00;
1527  l2capoutbuf[4] = scid[0]; // Source CID
1528  l2capoutbuf[5] = scid[1];
1529  l2capoutbuf[6] = 0x00; // Flag
1530  l2capoutbuf[7] = 0x00;
1531  l2capoutbuf[8] = 0x00; // Result
1532  l2capoutbuf[9] = 0x00;
1533  l2capoutbuf[10] = 0x01; // Config
1534  l2capoutbuf[11] = 0x02;
1535  l2capoutbuf[12] = 0xA0;
1536  l2capoutbuf[13] = 0x02;
1537 
1538  L2CAP_Command(handle, l2capoutbuf, 14);
1539 }
1540 
1541 void BTD::l2cap_disconnection_request(uint16_t handle, uint8_t rxid, uint8_t* dcid, uint8_t* scid) {
1542  l2capoutbuf[0] = L2CAP_CMD_DISCONNECT_REQUEST; // Code
1543  l2capoutbuf[1] = rxid; // Identifier
1544  l2capoutbuf[2] = 0x04; // Length
1545  l2capoutbuf[3] = 0x00;
1546  l2capoutbuf[4] = dcid[0];
1547  l2capoutbuf[5] = dcid[1];
1548  l2capoutbuf[6] = scid[0];
1549  l2capoutbuf[7] = scid[1];
1550 
1551  L2CAP_Command(handle, l2capoutbuf, 8);
1552 }
1553 
1554 void BTD::l2cap_disconnection_response(uint16_t handle, uint8_t rxid, uint8_t* dcid, uint8_t* scid) {
1555  l2capoutbuf[0] = L2CAP_CMD_DISCONNECT_RESPONSE; // Code
1556  l2capoutbuf[1] = rxid; // Identifier
1557  l2capoutbuf[2] = 0x04; // Length
1558  l2capoutbuf[3] = 0x00;
1559  l2capoutbuf[4] = dcid[0];
1560  l2capoutbuf[5] = dcid[1];
1561  l2capoutbuf[6] = scid[0];
1562  l2capoutbuf[7] = scid[1];
1563 
1564  L2CAP_Command(handle, l2capoutbuf, 8);
1565 }
1566 
1567 void BTD::l2cap_information_response(uint16_t handle, uint8_t rxid, uint8_t infoTypeLow, uint8_t infoTypeHigh) {
1568  l2capoutbuf[0] = L2CAP_CMD_INFORMATION_RESPONSE; // Code
1569  l2capoutbuf[1] = rxid; // Identifier
1570  l2capoutbuf[2] = 0x08; // Length
1571  l2capoutbuf[3] = 0x00;
1572  l2capoutbuf[4] = infoTypeLow;
1573  l2capoutbuf[5] = infoTypeHigh;
1574  l2capoutbuf[6] = 0x00; // Result = success
1575  l2capoutbuf[7] = 0x00; // Result = success
1576  l2capoutbuf[8] = 0x00;
1577  l2capoutbuf[9] = 0x00;
1578  l2capoutbuf[10] = 0x00;
1579  l2capoutbuf[11] = 0x00;
1580 
1581  L2CAP_Command(handle, l2capoutbuf, 12);
1582 }
1583 
1584 /* PS3 Commands - only set Bluetooth address is implemented in this library */
1585 void BTD::setBdaddr(uint8_t* bdaddr) {
1586  /* Set the internal Bluetooth address */
1587  uint8_t buf[8];
1588  buf[0] = 0x01;
1589  buf[1] = 0x00;
1590 
1591  for(uint8_t i = 0; i < 6; i++)
1592  buf[i + 2] = bdaddr[5 - i]; // Copy into buffer, has to be written reversed, so it is MSB first
1593 
1594  // bmRequest = Host to device (0x00) | Class (0x20) | Interface (0x01) = 0x21, bRequest = Set Report (0x09), Report ID (0xF5), Report Type (Feature 0x03), interface (0x00), datalength, datalength, data
1595  pUsb->ctrlReq(bAddress, epInfo[BTD_CONTROL_PIPE].epAddr, bmREQ_HID_OUT, HID_REQUEST_SET_REPORT, 0xF5, 0x03, 0x00, 8, 8, buf, NULL);
1596 }
1597 
1598 void BTD::setMoveBdaddr(uint8_t* bdaddr) {
1599  /* Set the internal Bluetooth address */
1600  uint8_t buf[11];
1601  buf[0] = 0x05;
1602  buf[7] = 0x10;
1603  buf[8] = 0x01;
1604  buf[9] = 0x02;
1605  buf[10] = 0x12;
1606 
1607  for(uint8_t i = 0; i < 6; i++)
1608  buf[i + 1] = bdaddr[i];
1609 
1610  // bmRequest = Host to device (0x00) | Class (0x20) | Interface (0x01) = 0x21, bRequest = Set Report (0x09), Report ID (0x05), Report Type (Feature 0x03), interface (0x00), datalength, datalength, data
1611  pUsb->ctrlReq(bAddress, epInfo[BTD_CONTROL_PIPE].epAddr, bmREQ_HID_OUT, HID_REQUEST_SET_REPORT, 0x05, 0x03, 0x00, 11, 11, buf, NULL);
1612 }
static const uint8_t BTD_DATAOUT_PIPE
Definition: BTD.h:558
uint8_t getConfDescr(uint8_t addr, uint8_t ep, uint16_t nbytes, uint8_t conf, uint8_t *dataptr)
Definition: Usb.cpp:801
uint8_t bmRcvToggle
Definition: address.h:48
-
bool incomingWii
Definition: BTD.h:474
+
bool incomingWii
Definition: BTD.h:504
+
bool useSimplePairing
Definition: BTD.h:531
-
void hci_connect()
Definition: BTD.cpp:1071
-
uint8_t bNumEP
Definition: BTD.h:514
+
void hci_connect()
Definition: BTD.cpp:1268
+
void hci_write_simple_pairing_mode(bool enable)
Definition: BTD.cpp:1237
+
uint8_t bNumEP
Definition: BTD.h:547
EpInfo * epinfo
Definition: address.h:83
-
const char * btdName
Definition: BTD.h:447
-
void hci_reset()
Definition: BTD.cpp:953
-
void l2cap_connection_response(uint16_t handle, uint8_t rxid, uint8_t *dcid, uint8_t *scid, uint8_t result)
Definition: BTD.cpp:1260
+
const char * btdName
Definition: BTD.h:477
+
void hci_reset()
Definition: BTD.cpp:1113
+
void l2cap_connection_response(uint16_t handle, uint8_t rxid, uint8_t *dcid, uint8_t *scid, uint8_t result)
Definition: BTD.cpp:1488
#define HCI_SCANNING_STATE
Definition: BTD.h:55
bool lowspeed
Definition: address.h:86
#define USB_ERROR_EPINFO_IS_NULL
Definition: UsbCore.h:96
-
void l2cap_connection_request(uint16_t handle, uint8_t rxid, uint8_t *scid, uint16_t psm)
Definition: BTD.cpp:1247
-
#define EV_COMMAND_STATUS
Definition: BTD.h:99
-
#define EV_REMOTE_NAME_COMPLETE
Definition: BTD.h:86
+
void l2cap_connection_request(uint16_t handle, uint8_t rxid, uint8_t *scid, uint16_t psm)
Definition: BTD.cpp:1475
+
#define EV_COMMAND_STATUS
Definition: BTD.h:96
+
#define EV_REMOTE_NAME_COMPLETE
Definition: BTD.h:90
uint8_t bmNakPower
Definition: address.h:49
-
bool sdpConnectionClaimed
Definition: BTD.h:442
+
bool sdpConnectionClaimed
Definition: BTD.h:472
#define bmREQ_HCI_OUT
Definition: BTD.h:40
-
void l2cap_disconnection_request(uint16_t handle, uint8_t rxid, uint8_t *dcid, uint8_t *scid)
Definition: BTD.cpp:1313
+
void l2cap_disconnection_request(uint16_t handle, uint8_t rxid, uint8_t *dcid, uint8_t *scid)
Definition: BTD.cpp:1541
+
#define EV_SIMPLE_PAIRING_COMPLETE
Definition: BTD.h:110
-
bool rfcommConnectionClaimed
Definition: BTD.h:444
-
uint8_t hci_version
Definition: BTD.h:464
-
bool waitingForConnection
Definition: BTD.h:438
+
bool rfcommConnectionClaimed
Definition: BTD.h:474
+
uint8_t hci_version
Definition: BTD.h:494
+
bool waitingForConnection
Definition: BTD.h:468
-
#define EV_INQUIRY_COMPLETE
Definition: BTD.h:80
-
void hci_inquiry()
Definition: BTD.cpp:1049
-
static const uint8_t BTD_EVENT_PIPE
Definition: BTD.h:521
+
#define EV_INQUIRY_COMPLETE
Definition: BTD.h:84
+
void hci_inquiry()
Definition: BTD.cpp:1246
+
static const uint8_t BTD_EVENT_PIPE
Definition: BTD.h:554
#define PS3MOVE_PID
Definition: BTD.h:28
-
bool pairWithWii
Definition: BTD.h:476
+
bool pairWithWii
Definition: BTD.h:506
uint8_t bMaxPacketSize0
Definition: usb_ch9.h:112
-
void hci_write_scan_disable()
Definition: BTD.cpp:975
+
#define HCI_WRITE_SIMPLE_PAIRING_STATE
Definition: BTD.h:63
+
void hci_write_scan_disable()
Definition: BTD.cpp:1135
#define NotifyFail(...)
Definition: message.h:62
#define BELKIN_F8T065BF_PID
Definition: BTD.h:34
-
#define HCI_SET_NAME_STATE
Definition: BTD.h:48
-
void EndpointXtract(uint8_t conf, uint8_t iface, uint8_t alt, uint8_t proto, const USB_ENDPOINT_DESCRIPTOR *ep)
Definition: BTD.cpp:327
-
#define EV_LINK_KEY_REQUEST
Definition: BTD.h:92
+
void EndpointXtract(uint8_t conf, uint8_t iface, uint8_t alt, uint8_t proto, const USB_ENDPOINT_DESCRIPTOR *ep)
Definition: BTD.cpp:330
+
#define EV_LINK_KEY_REQUEST
Definition: BTD.h:100
#define HCI_DONE_STATE
Definition: BTD.h:60
-
#define BTD_NUM_SERVICES
Definition: BTD.h:191
-
#define EV_DATA_BUFFER_OVERFLOW
Definition: BTD.h:94
+
#define BTD_NUM_SERVICES
Definition: BTD.h:211
+
#define EV_DATA_BUFFER_OVERFLOW
Definition: BTD.h:102
+
#define HCI_LOCAL_EXTENDED_FEATURES_STATE
Definition: BTD.h:62
#define HCI_DISCONNECT_STATE
Definition: BTD.h:61
-
#define HCI_FLAG_CONNECT_COMPLETE
Definition: BTD.h:65
-
#define EV_PIN_CODE_REQUEST
Definition: BTD.h:91
+
#define HCI_FLAG_CONNECT_COMPLETE
Definition: BTD.h:68
+
#define EV_IO_CAPABILITY_REQUEST
Definition: BTD.h:107
+
#define EV_PIN_CODE_REQUEST
Definition: BTD.h:99
uint8_t setConf(uint8_t addr, uint8_t ep, uint8_t conf_value)
Definition: Usb.cpp:840
-
const char * btdPin
Definition: BTD.h:449
-
bool motionPlusInside
Definition: BTD.h:478
-
#define EV_AUTHENTICATION_COMPLETE
Definition: BTD.h:85
-
void hci_remote_name()
Definition: BTD.cpp:1018
+
const char * btdPin
Definition: BTD.h:479
+
bool motionPlusInside
Definition: BTD.h:508
+
#define EV_AUTHENTICATION_COMPLETE
Definition: BTD.h:89
+
void hci_remote_name()
Definition: BTD.cpp:1188
#define USB_TRANSFER_TYPE_INTERRUPT
Definition: usb_ch9.h:93
-
#define HCI_FLAG_CONNECT_EVENT
Definition: BTD.h:72
+
#define HCI_FLAG_CONNECT_EVENT
Definition: BTD.h:75
#define bmREQ_HID_OUT
Definition: usbhid.h:63
-
#define HCI_FLAG_DISCONNECT_COMPLETE
Definition: BTD.h:66
+
#define HCI_FLAG_DISCONNECT_COMPLETE
Definition: BTD.h:69
#define BELKIN_F8T065BF_VID
Definition: BTD.h:33
#define HCI_REMOTE_NAME_STATE
Definition: BTD.h:57
#define USB_ERROR_FailGetDevDescr
Definition: UsbCore.h:102
-
#define HCI_FLAG_CMD_COMPLETE
Definition: BTD.h:64
+
#define HCI_FLAG_CMD_COMPLETE
Definition: BTD.h:67
#define PS3_VID
Definition: BTD.h:25
#define NotifyFailGetDevDescr(...)
Definition: message.h:57
BTD(USB *p)
Definition: BTD.cpp:27
-
char remote_name[30]
Definition: BTD.h:458
+
char remote_name[30]
Definition: BTD.h:488
#define hrJERR
Definition: max3421e.h:227
uint8_t setEpInfoEntry(uint8_t addr, uint8_t epcount, EpInfo *eprecord_ptr)
Definition: Usb.cpp:64
virtual void Reset()=0
-
#define EV_MAX_SLOTS_CHANGE
Definition: BTD.h:95
-
static const uint8_t BTD_DATAIN_PIPE
Definition: BTD.h:523
-
void hci_set_local_name(const char *name)
Definition: BTD.cpp:1037
-
#define EV_QOS_SETUP_COMPLETE
Definition: BTD.h:97
-
void hci_write_scan_enable()
Definition: BTD.cpp:962
-
uint8_t Release()
Definition: BTD.cpp:376
+
#define EV_MAX_SLOTS_CHANGE
Definition: BTD.h:103
+
static const uint8_t BTD_DATAIN_PIPE
Definition: BTD.h:556
+
#define EV_QOS_SETUP_COMPLETE
Definition: BTD.h:94
+
void hci_write_scan_enable()
Definition: BTD.cpp:1122
+
uint8_t Release()
Definition: BTD.cpp:379
virtual void FreeAddress(uint8_t addr)=0
-
void l2cap_disconnection_response(uint16_t handle, uint8_t rxid, uint8_t *dcid, uint8_t *scid)
Definition: BTD.cpp:1326
+
void l2cap_disconnection_response(uint16_t handle, uint8_t rxid, uint8_t *dcid, uint8_t *scid)
Definition: BTD.cpp:1554
uint8_t ctrlReq(uint8_t addr, uint8_t ep, uint8_t bmReqType, uint8_t bRequest, uint8_t wValLo, uint8_t wValHi, uint16_t wInd, uint16_t total, uint16_t nbytes, uint8_t *dataptr, USBReadParser *p)
Definition: Usb.cpp:126
virtual UsbDevice * GetUsbDevicePtr(uint8_t addr)=0
#define HCI_BDADDR_STATE
Definition: BTD.h:46
#define HCI_CONNECT_DEVICE_STATE
Definition: BTD.h:52
#define Notify(...)
Definition: message.h:51
-
bool connectToHIDDevice
Definition: BTD.h:487
+
bool connectToHIDDevice
Definition: BTD.h:517
uint8_t setAddr(uint8_t oldaddr, uint8_t ep, uint8_t newaddr)
Definition: Usb.cpp:831
-
uint8_t bAddress
Definition: BTD.h:507
+
uint8_t bAddress
Definition: BTD.h:540
#define NotifyFailGetConfDescr(...)
Definition: message.h:59
uint8_t epAddr
Definition: address.h:40
-
bool incomingHIDDevice
Definition: BTD.h:491
+
bool incomingHIDDevice
Definition: BTD.h:521
#define NotifyFailUnknownDevice(...)
Definition: message.h:61
-
bool pairWithHIDDevice
Definition: BTD.h:493
-
uint32_t qNextPollTime
Definition: BTD.h:516
+
bool pairWithHIDDevice
Definition: BTD.h:523
+
uint32_t qNextPollTime
Definition: BTD.h:549
#define USB_NAK_MAX_POWER
Definition: address.h:34
-
#define EV_CONNECT_COMPLETE
Definition: BTD.h:82
-
void PrintEndpointDescriptor(const USB_ENDPOINT_DESCRIPTOR *ep_ptr)
Definition: BTD.cpp:357
-
#define EV_DISCONNECT_COMPLETE
Definition: BTD.h:84
-
#define HCI_FLAG_READ_BDADDR
Definition: BTD.h:69
+
#define EV_CONNECT_COMPLETE
Definition: BTD.h:86
+
void PrintEndpointDescriptor(const USB_ENDPOINT_DESCRIPTOR *ep_ptr)
Definition: BTD.cpp:360
+
#define EV_DISCONNECT_COMPLETE
Definition: BTD.h:88
+
#define HCI_FLAG_READ_BDADDR
Definition: BTD.h:72
#define IOGEAR_GBU521_PID
Definition: BTD.h:32
-
bool connectToWii
Definition: BTD.h:470
-
uint8_t ConfigureDevice(uint8_t parent, uint8_t port, bool lowspeed)
Definition: BTD.cpp:48
+
bool connectToWii
Definition: BTD.h:500
+
uint8_t ConfigureDevice(uint8_t parent, uint8_t port, bool lowspeed)
Definition: BTD.cpp:50
#define HCI_LOCAL_VERSION_STATE
Definition: BTD.h:47
virtual void disconnect()=0
-
bool wiiUProController
Definition: BTD.h:480
-
uint16_t hci_handle
Definition: BTD.h:454
-
uint8_t Init(uint8_t parent, uint8_t port, bool lowspeed)
Definition: BTD.cpp:134
+
bool wiiUProController
Definition: BTD.h:510
+
uint16_t hci_handle
Definition: BTD.h:484
+
uint8_t Init(uint8_t parent, uint8_t port, bool lowspeed)
Definition: BTD.cpp:136
#define Notifyc(...)
Definition: message.h:53
Definition: address.h:39
-
void hci_disconnect(uint16_t handle)
Definition: BTD.cpp:1171
+
void hci_disconnect(uint16_t handle)
Definition: BTD.cpp:1399
#define HCI_RESET_STATE
Definition: BTD.h:44
uint8_t outTransfer(uint8_t addr, uint8_t ep, uint16_t nbytes, uint8_t *data)
Definition: Usb.cpp:303
+
#define EV_IO_CAPABILITY_RESPONSE
Definition: BTD.h:108
#define hrNAK
Definition: max3421e.h:218
-
void hci_read_bdaddr()
Definition: BTD.cpp:984
-
void hci_inquiry_cancel()
Definition: BTD.cpp:1063
-
#define L2CAP_CMD_INFORMATION_RESPONSE
Definition: BTD.h:174
+
void hci_read_bdaddr()
Definition: BTD.cpp:1144
+
void hci_inquiry_cancel()
Definition: BTD.cpp:1260
+
#define L2CAP_CMD_INFORMATION_RESPONSE
Definition: BTD.h:183
uint16_t wMaxPacketSize
Definition: usb_ch9.h:153
#define bmUSB_TRANSFER_TYPE
Definition: usb_ch9.h:94
virtual void Run()=0
-
uint8_t my_bdaddr[6]
Definition: BTD.h:452
-
#define EV_INCOMING_CONNECT
Definition: BTD.h:83
+
uint8_t my_bdaddr[6]
Definition: BTD.h:482
+
#define EV_INCOMING_CONNECT
Definition: BTD.h:87
+
#define HCI_WRITE_NAME_STATE
Definition: BTD.h:48
#define HCI_CONNECT_IN_STATE
Definition: BTD.h:56
#define HCI_INQUIRY_STATE
Definition: BTD.h:51
+
void hci_read_local_extended_features(uint8_t page_number)
Definition: BTD.cpp:1162
virtual uint8_t AllocAddress(uint8_t parent, bool is_hub=false, uint8_t port=0)=0
uint8_t bEndpointAddress
Definition: usb_ch9.h:151
#define HCI_CONNECTED_STATE
Definition: BTD.h:58
-
#define EV_INQUIRY_RESULT
Definition: BTD.h:81
+
#define EV_INQUIRY_RESULT
Definition: BTD.h:85
uint8_t bmSndToggle
Definition: address.h:47
#define USB_ERROR_CLASS_INSTANCE_ALREADY_IN_USE
Definition: UsbCore.h:98
-
#define L2CAP_CMD_CONFIG_REQUEST
Definition: BTD.h:169
+
#define L2CAP_CMD_CONFIG_REQUEST
Definition: BTD.h:178
#define PSTR(str)
-
uint8_t Poll()
Definition: BTD.cpp:382
+
uint8_t Poll()
Definition: BTD.cpp:385
uint8_t bDeviceClass
Definition: usb_ch9.h:109
-
#define L2CAP_CMD_DISCONNECT_REQUEST
Definition: BTD.h:171
-
static const uint8_t BTD_CONTROL_PIPE
Definition: BTD.h:519
+
#define L2CAP_CMD_DISCONNECT_REQUEST
Definition: BTD.h:180
+
static const uint8_t BTD_CONTROL_PIPE
Definition: BTD.h:552
+
void hci_write_local_name(const char *name)
Definition: BTD.cpp:1207
#define BULK_MAXPKTSIZE
Definition: BTD.h:37
-
void disconnect()
Definition: BTD.cpp:394
-
#define HCI_FLAG_READ_VERSION
Definition: BTD.h:70
-
uint8_t disc_bdaddr[6]
Definition: BTD.h:456
-
bool l2capConnectionClaimed
Definition: BTD.h:440
+
void disconnect()
Definition: BTD.cpp:397
+
#define HCI_FLAG_READ_VERSION
Definition: BTD.h:73
+
uint8_t disc_bdaddr[6]
Definition: BTD.h:486
+
bool l2capConnectionClaimed
Definition: BTD.h:470
#define USB_NAK_NOWAIT
Definition: address.h:36
-
#define HCI_FLAG_INCOMING_REQUEST
Definition: BTD.h:68
-
#define EV_NUM_COMPLETE_PKT
Definition: BTD.h:90
+
#define HCI_FLAG_INCOMING_REQUEST
Definition: BTD.h:71
+
#define EV_NUM_COMPLETE_PKT
Definition: BTD.h:98
#define USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL
Definition: UsbCore.h:95
-
EpInfo epInfo[BTD_MAX_ENDPOINTS]
Definition: BTD.h:509
+
EpInfo epInfo[BTD_MAX_ENDPOINTS]
Definition: BTD.h:542
#define IOGEAR_GBU521_VID
Definition: BTD.h:31
#define PS3_PID
Definition: BTD.h:26
-
#define BTD_MAX_ENDPOINTS
Definition: BTD.h:190
+
#define BTD_MAX_ENDPOINTS
Definition: BTD.h:210
#define PS3NAVIGATION_PID
Definition: BTD.h:27
#define USB_DEV_CONFIG_ERROR_DEVICE_NOT_SUPPORTED
Definition: UsbCore.h:90
-
#define L2CAP_CMD_DISCONNECT_RESPONSE
Definition: BTD.h:172
-
#define EV_READ_REMOTE_VERSION_INFORMATION_COMPLETE
Definition: BTD.h:96
-
#define EV_COMMAND_COMPLETE
Definition: BTD.h:98
-
void l2cap_information_response(uint16_t handle, uint8_t rxid, uint8_t infoTypeLow, uint8_t infoTypeHigh)
Definition: BTD.cpp:1339
+
#define L2CAP_CMD_DISCONNECT_RESPONSE
Definition: BTD.h:181
+
#define EV_READ_REMOTE_VERSION_INFORMATION_COMPLETE
Definition: BTD.h:93
+
#define EV_COMMAND_COMPLETE
Definition: BTD.h:95
+
void l2cap_information_response(uint16_t handle, uint8_t rxid, uint8_t infoTypeLow, uint8_t infoTypeHigh)
Definition: BTD.cpp:1567
uint16_t idProduct
Definition: usb_ch9.h:114
-
#define L2CAP_CMD_CONNECTION_RESPONSE
Definition: BTD.h:168
-
#define L2CAP_CMD_CONFIG_RESPONSE
Definition: BTD.h:170
-
#define hci_set_flag(flag)
Definition: BTD.h:76
-
void hci_write_class_of_device()
Definition: BTD.cpp:1183
+
#define L2CAP_CMD_CONNECTION_RESPONSE
Definition: BTD.h:177
+
#define L2CAP_CMD_CONFIG_RESPONSE
Definition: BTD.h:179
+
#define hci_set_flag(flag)
Definition: BTD.h:80
+
void hci_write_class_of_device()
Definition: BTD.cpp:1411
#define HCI_CONNECTED_DEVICE_STATE
Definition: BTD.h:53
uint8_t inTransfer(uint8_t addr, uint8_t ep, uint16_t *nbytesptr, uint8_t *data, uint8_t bInterval=0)
Definition: Usb.cpp:209
#define HCI_INIT_STATE
Definition: BTD.h:43
-
void hci_pin_code_negative_request_reply()
Definition: BTD.cpp:1133
-
#define EV_CHANGE_CONNECTION_LINK
Definition: BTD.h:88
+
#define HCI_FLAG_LOCAL_EXTENDED_FEATURES
Definition: BTD.h:76
+
void hci_pin_code_negative_request_reply()
Definition: BTD.cpp:1330
+
#define EV_CHANGE_CONNECTION_LINK
Definition: BTD.h:92
virtual void ACLData(uint8_t *ACLData)=0
uint8_t bNumConfigurations
Definition: usb_ch9.h:119
#define USB_ERROR_OUT_OF_ADDRESS_SPACE_IN_POOL
Definition: UsbCore.h:93
-
#define hci_check_flag(flag)
Definition: BTD.h:75
-
#define EV_ROLE_CHANGED
Definition: BTD.h:89
+
#define hci_check_flag(flag)
Definition: BTD.h:79
+
#define EV_ROLE_CHANGED
Definition: BTD.h:97
uint8_t maxPktSize
Definition: address.h:41
AddressPool & GetAddressPool()
Definition: UsbCore.h:226
#define HCI_CHECK_DEVICE_SERVICE
Definition: BTD.h:49
Definition: UsbCore.h:210
#define USB_TRANSFER_TYPE_BULK
Definition: usb_ch9.h:92
-
uint8_t bConfNum
Definition: BTD.h:512
-
void hci_link_key_request_negative_reply()
Definition: BTD.cpp:1147
-
#define EV_LOOPBACK_COMMAND
Definition: BTD.h:100
-
void L2CAP_Command(uint16_t handle, uint8_t *data, uint8_t nbytes, uint8_t channelLow=0x01, uint8_t channelHigh=0x00)
Definition: BTD.cpp:1219
-
#define EV_LINK_KEY_NOTIFICATION
Definition: BTD.h:93
-
void l2cap_config_response(uint16_t handle, uint8_t rxid, uint8_t *scid)
Definition: BTD.cpp:1294
-
void l2cap_config_request(uint16_t handle, uint8_t rxid, uint8_t *dcid)
Definition: BTD.cpp:1277
-
void hci_pin_code_request_reply()
Definition: BTD.cpp:1097
+
uint8_t bConfNum
Definition: BTD.h:545
+
void hci_link_key_request_negative_reply()
Definition: BTD.cpp:1344
+
#define EV_LOOPBACK_COMMAND
Definition: BTD.h:104
+
void L2CAP_Command(uint16_t handle, uint8_t *data, uint8_t nbytes, uint8_t channelLow=0x01, uint8_t channelHigh=0x00)
Definition: BTD.cpp:1447
+
#define EV_LINK_KEY_NOTIFICATION
Definition: BTD.h:101
+
void l2cap_config_response(uint16_t handle, uint8_t rxid, uint8_t *scid)
Definition: BTD.cpp:1522
+
void l2cap_config_request(uint16_t handle, uint8_t rxid, uint8_t *dcid)
Definition: BTD.cpp:1505
+
void hci_pin_code_request_reply()
Definition: BTD.cpp:1294
#define HID_REQUEST_SET_REPORT
Definition: usbhid.h:72
-
#define L2CAP_CMD_CONNECTION_REQUEST
Definition: BTD.h:167
+
#define L2CAP_CMD_CONNECTION_REQUEST
Definition: BTD.h:176
uint8_t RegisterDeviceClass(USBDeviceConfig *pdev)
Definition: UsbCore.h:230
-
#define EV_ENCRYPTION_CHANGE
Definition: BTD.h:87
+
#define EV_ENCRYPTION_CHANGE
Definition: BTD.h:91
#define NotifyFailSetConfDescr(...)
Definition: message.h:60
-
#define hci_clear_flag(flag)
Definition: BTD.h:77
-
USB * pUsb
Definition: BTD.h:501
+
#define hci_clear_flag(flag)
Definition: BTD.h:81
+
USB * pUsb
Definition: BTD.h:538
#define NotifyStr(...)
Definition: message.h:52
-
void hci_authentication_request()
Definition: BTD.cpp:1161
-
void hci_read_local_version_information()
Definition: BTD.cpp:993
-
#define HCI_FLAG_REMOTE_NAME_COMPLETE
Definition: BTD.h:67
-
void hci_accept_connection()
Definition: BTD.cpp:1002
-
#define EV_PAGE_SCAN_REP_MODE
Definition: BTD.h:101
-
#define HCI_FLAG_DEVICE_FOUND
Definition: BTD.h:71
+
void hci_authentication_request()
Definition: BTD.cpp:1389
+
void hci_read_local_version_information()
Definition: BTD.cpp:1153
+
#define HCI_FLAG_REMOTE_NAME_COMPLETE
Definition: BTD.h:70
+
void hci_accept_connection()
Definition: BTD.cpp:1172
+
#define EV_PAGE_SCAN_REP_MODE
Definition: BTD.h:105
+
#define EV_USER_CONFIRMATION_REQUEST
Definition: BTD.h:109
+
#define HCI_FLAG_DEVICE_FOUND
Definition: BTD.h:74
+
void hci_set_event_mask()
Definition: BTD.cpp:1219
#define HCI_CLASS_STATE
Definition: BTD.h:45
uint8_t getDevDescr(uint8_t addr, uint8_t ep, uint16_t nbytes, uint8_t *dataptr)
defined(USB_METHODS_INLINE)
Definition: Usb.cpp:796
#define NotifyFailSetDevTblEntry(...)
Definition: message.h:58
+
void hci_io_capability_request_reply()
Definition: BTD.cpp:1358
+
#define HCI_SET_EVENT_MASK_STATE
Definition: BTD.h:64
#define USB_ERROR_CONFIG_REQUIRES_ADDITIONAL_RESET
Definition: UsbCore.h:101
-
void HCI_Command(uint8_t *data, uint16_t nbytes)
Definition: BTD.cpp:948
+
void hci_user_confirmation_request_reply()
Definition: BTD.cpp:1375
+
void HCI_Command(uint8_t *data, uint16_t nbytes)
Definition: BTD.cpp:1108
diff --git a/_b_t_d_8h.html b/_b_t_d_8h.html index 93cb8f0c..77e77993 100644 --- a/_b_t_d_8h.html +++ b/_b_t_d_8h.html @@ -106,16 +106,17 @@ This graph shows which files directly or indirectly include this file:
- - - - - + + + + + - - - + + + +
@@ -160,8 +161,8 @@ Macros   #define HCI_LOCAL_VERSION_STATE   4   -#define HCI_SET_NAME_STATE   5 -  +#define HCI_WRITE_NAME_STATE   5 +  #define HCI_CHECK_DEVICE_SERVICE   6   #define HCI_INQUIRY_STATE   7 @@ -184,6 +185,12 @@ Macros   #define HCI_DISCONNECT_STATE   16   +#define HCI_LOCAL_EXTENDED_FEATURES_STATE   17 +  +#define HCI_WRITE_SIMPLE_PAIRING_STATE   18 +  +#define HCI_SET_EVENT_MASK_STATE   19 +  #define HCI_FLAG_CMD_COMPLETE   (1UL << 0)   #define HCI_FLAG_CONNECT_COMPLETE   (1UL << 1) @@ -202,6 +209,8 @@ Macros   #define HCI_FLAG_CONNECT_EVENT   (1UL << 8)   +#define HCI_FLAG_LOCAL_EXTENDED_FEATURES   (1UL << 9) +  #define hci_check_flag(flag)   (hci_event_flag & (flag))   #define hci_set_flag(flag)   (hci_event_flag |= (flag)) @@ -226,6 +235,14 @@ Macros   #define EV_CHANGE_CONNECTION_LINK   0x09   +#define EV_READ_REMOTE_VERSION_INFORMATION_COMPLETE   0x0C +  +#define EV_QOS_SETUP_COMPLETE   0x0D +  +#define EV_COMMAND_COMPLETE   0x0E +  +#define EV_COMMAND_STATUS   0x0F +  #define EV_ROLE_CHANGED   0x12   #define EV_NUM_COMPLETE_PKT   0x13 @@ -240,18 +257,20 @@ Macros   #define EV_MAX_SLOTS_CHANGE   0x1B   -#define EV_READ_REMOTE_VERSION_INFORMATION_COMPLETE   0x0C -  -#define EV_QOS_SETUP_COMPLETE   0x0D -  -#define EV_COMMAND_COMPLETE   0x0E -  -#define EV_COMMAND_STATUS   0x0F -  #define EV_LOOPBACK_COMMAND   0x19   #define EV_PAGE_SCAN_REP_MODE   0x20   +#define EV_READ_REMOTE_EXTENDED_FEATURES_COMPLETE   0x23 +  +#define EV_IO_CAPABILITY_REQUEST   0x31 +  +#define EV_IO_CAPABILITY_RESPONSE   0x32 +  +#define EV_USER_CONFIRMATION_REQUEST   0x33 +  +#define EV_SIMPLE_PAIRING_COMPLETE   0x36 +  #define L2CAP_WAIT   0   #define L2CAP_DONE   1 @@ -358,6 +377,24 @@ Macros   #define HID_INTR_PSM   0x13   +#define SDP_SERVICE_SEARCH_REQUEST   0x02 +  +#define SDP_SERVICE_SEARCH_RESPONSE   0x03 +  +#define SDP_SERVICE_ATTRIBUTE_REQUEST   0x04 +  +#define SDP_SERVICE_ATTRIBUTE_RESPONSE   0x05 +  +#define SDP_SERVICE_SEARCH_ATTRIBUTE_REQUEST   0x06 +  +#define SDP_SERVICE_SEARCH_ATTRIBUTE_RESPONSE   0x07 +  +#define PNP_INFORMATION_UUID   0x1200 +  +#define SERIALPORT_UUID   0x1101 +  +#define L2CAP_UUID   0x0100 +  #define WI_SUBCLASS_RF   0x01   #define WI_PROTOCOL_BT   0x01 @@ -580,12 +617,12 @@ Macros - +
- +
#define HCI_SET_NAME_STATE   5#define HCI_WRITE_NAME_STATE   5
@@ -746,6 +783,48 @@ Macros

Definition at line 61 of file BTD.h.

+
+
+ +
+
+ + + + +
#define HCI_LOCAL_EXTENDED_FEATURES_STATE   17
+
+ +

Definition at line 62 of file BTD.h.

+ +
+
+ +
+
+ + + + +
#define HCI_WRITE_SIMPLE_PAIRING_STATE   18
+
+ +

Definition at line 63 of file BTD.h.

+ +
+
+ +
+
+ + + + +
#define HCI_SET_EVENT_MASK_STATE   19
+
+ +

Definition at line 64 of file BTD.h.

+
@@ -758,7 +837,7 @@ Macros
-

Definition at line 64 of file BTD.h.

+

Definition at line 67 of file BTD.h.

@@ -772,7 +851,7 @@ Macros
-

Definition at line 65 of file BTD.h.

+

Definition at line 68 of file BTD.h.

@@ -786,7 +865,7 @@ Macros
-

Definition at line 66 of file BTD.h.

+

Definition at line 69 of file BTD.h.

@@ -800,7 +879,7 @@ Macros
-

Definition at line 67 of file BTD.h.

+

Definition at line 70 of file BTD.h.

@@ -814,7 +893,7 @@ Macros
-

Definition at line 68 of file BTD.h.

+

Definition at line 71 of file BTD.h.

@@ -828,7 +907,7 @@ Macros
-

Definition at line 69 of file BTD.h.

+

Definition at line 72 of file BTD.h.

@@ -842,7 +921,7 @@ Macros
-

Definition at line 70 of file BTD.h.

+

Definition at line 73 of file BTD.h.

@@ -856,7 +935,7 @@ Macros
-

Definition at line 71 of file BTD.h.

+

Definition at line 74 of file BTD.h.

@@ -870,7 +949,21 @@ Macros
-

Definition at line 72 of file BTD.h.

+

Definition at line 75 of file BTD.h.

+ +
+ + +
+
+ + + + +
#define HCI_FLAG_LOCAL_EXTENDED_FEATURES   (1UL << 9)
+
+ +

Definition at line 76 of file BTD.h.

@@ -888,7 +981,7 @@ Macros
-

Definition at line 75 of file BTD.h.

+

Definition at line 79 of file BTD.h.

@@ -906,7 +999,7 @@ Macros
-

Definition at line 76 of file BTD.h.

+

Definition at line 80 of file BTD.h.

@@ -924,7 +1017,7 @@ Macros
-

Definition at line 77 of file BTD.h.

+

Definition at line 81 of file BTD.h.

@@ -938,7 +1031,7 @@ Macros
-

Definition at line 80 of file BTD.h.

+

Definition at line 84 of file BTD.h.

@@ -952,7 +1045,7 @@ Macros
-

Definition at line 81 of file BTD.h.

+

Definition at line 85 of file BTD.h.

@@ -966,7 +1059,7 @@ Macros
-

Definition at line 82 of file BTD.h.

+

Definition at line 86 of file BTD.h.

@@ -980,7 +1073,7 @@ Macros
-

Definition at line 83 of file BTD.h.

+

Definition at line 87 of file BTD.h.

@@ -994,7 +1087,7 @@ Macros
-

Definition at line 84 of file BTD.h.

+

Definition at line 88 of file BTD.h.

@@ -1008,7 +1101,7 @@ Macros
-

Definition at line 85 of file BTD.h.

+

Definition at line 89 of file BTD.h.

@@ -1022,7 +1115,7 @@ Macros
-

Definition at line 86 of file BTD.h.

+

Definition at line 90 of file BTD.h.

@@ -1036,7 +1129,7 @@ Macros
-

Definition at line 87 of file BTD.h.

+

Definition at line 91 of file BTD.h.

@@ -1050,106 +1143,8 @@ Macros
-

Definition at line 88 of file BTD.h.

- -
- - -
-
- - - - -
#define EV_ROLE_CHANGED   0x12
-
- -

Definition at line 89 of file BTD.h.

- -
-
- -
-
- - - - -
#define EV_NUM_COMPLETE_PKT   0x13
-
- -

Definition at line 90 of file BTD.h.

- -
-
- -
-
- - - - -
#define EV_PIN_CODE_REQUEST   0x16
-
- -

Definition at line 91 of file BTD.h.

- -
-
- -
-
- - - - -
#define EV_LINK_KEY_REQUEST   0x17
-
-

Definition at line 92 of file BTD.h.

-
-
- -
-
- - - - -
#define EV_LINK_KEY_NOTIFICATION   0x18
-
- -

Definition at line 93 of file BTD.h.

- -
-
- -
-
- - - - -
#define EV_DATA_BUFFER_OVERFLOW   0x1A
-
- -

Definition at line 94 of file BTD.h.

- -
-
- -
-
- - - - -
#define EV_MAX_SLOTS_CHANGE   0x1B
-
- -

Definition at line 95 of file BTD.h.

-
@@ -1162,7 +1157,7 @@ Macros
-

Definition at line 96 of file BTD.h.

+

Definition at line 93 of file BTD.h.

@@ -1176,7 +1171,7 @@ Macros
-

Definition at line 97 of file BTD.h.

+

Definition at line 94 of file BTD.h.

@@ -1190,7 +1185,7 @@ Macros
-

Definition at line 98 of file BTD.h.

+

Definition at line 95 of file BTD.h.

@@ -1204,8 +1199,106 @@ Macros
+

Definition at line 96 of file BTD.h.

+ +
+ + +
+
+ + + + +
#define EV_ROLE_CHANGED   0x12
+
+ +

Definition at line 97 of file BTD.h.

+ +
+
+ +
+
+ + + + +
#define EV_NUM_COMPLETE_PKT   0x13
+
+ +

Definition at line 98 of file BTD.h.

+ +
+
+ +
+
+ + + + +
#define EV_PIN_CODE_REQUEST   0x16
+
+

Definition at line 99 of file BTD.h.

+
+
+ +
+
+ + + + +
#define EV_LINK_KEY_REQUEST   0x17
+
+ +

Definition at line 100 of file BTD.h.

+ +
+
+ +
+
+ + + + +
#define EV_LINK_KEY_NOTIFICATION   0x18
+
+ +

Definition at line 101 of file BTD.h.

+ +
+
+ +
+
+ + + + +
#define EV_DATA_BUFFER_OVERFLOW   0x1A
+
+ +

Definition at line 102 of file BTD.h.

+ +
+
+ +
+
+ + + + +
#define EV_MAX_SLOTS_CHANGE   0x1B
+
+ +

Definition at line 103 of file BTD.h.

+
@@ -1218,7 +1311,7 @@ Macros
-

Definition at line 100 of file BTD.h.

+

Definition at line 104 of file BTD.h.

@@ -1232,7 +1325,77 @@ Macros
-

Definition at line 101 of file BTD.h.

+

Definition at line 105 of file BTD.h.

+ +
+ + +
+
+ + + + +
#define EV_READ_REMOTE_EXTENDED_FEATURES_COMPLETE   0x23
+
+ +

Definition at line 106 of file BTD.h.

+ +
+
+ +
+
+ + + + +
#define EV_IO_CAPABILITY_REQUEST   0x31
+
+ +

Definition at line 107 of file BTD.h.

+ +
+
+ +
+
+ + + + +
#define EV_IO_CAPABILITY_RESPONSE   0x32
+
+ +

Definition at line 108 of file BTD.h.

+ +
+
+ +
+
+ + + + +
#define EV_USER_CONFIRMATION_REQUEST   0x33
+
+ +

Definition at line 109 of file BTD.h.

+ +
+
+ +
+
+ + + + +
#define EV_SIMPLE_PAIRING_COMPLETE   0x36
+
+ +

Definition at line 110 of file BTD.h.

@@ -1246,7 +1409,7 @@ Macros
-

Definition at line 104 of file BTD.h.

+

Definition at line 113 of file BTD.h.

@@ -1260,7 +1423,7 @@ Macros
-

Definition at line 105 of file BTD.h.

+

Definition at line 114 of file BTD.h.

@@ -1274,7 +1437,7 @@ Macros
-

Definition at line 108 of file BTD.h.

+

Definition at line 117 of file BTD.h.

@@ -1288,7 +1451,7 @@ Macros
-

Definition at line 109 of file BTD.h.

+

Definition at line 118 of file BTD.h.

@@ -1302,7 +1465,7 @@ Macros
-

Definition at line 110 of file BTD.h.

+

Definition at line 119 of file BTD.h.

@@ -1316,7 +1479,7 @@ Macros
-

Definition at line 111 of file BTD.h.

+

Definition at line 120 of file BTD.h.

@@ -1330,7 +1493,7 @@ Macros
-

Definition at line 114 of file BTD.h.

+

Definition at line 123 of file BTD.h.

@@ -1344,7 +1507,7 @@ Macros
-

Definition at line 115 of file BTD.h.

+

Definition at line 124 of file BTD.h.

@@ -1358,7 +1521,7 @@ Macros
-

Definition at line 116 of file BTD.h.

+

Definition at line 125 of file BTD.h.

@@ -1372,7 +1535,7 @@ Macros
-

Definition at line 117 of file BTD.h.

+

Definition at line 126 of file BTD.h.

@@ -1386,7 +1549,7 @@ Macros
-

Definition at line 120 of file BTD.h.

+

Definition at line 129 of file BTD.h.

@@ -1400,7 +1563,7 @@ Macros
-

Definition at line 121 of file BTD.h.

+

Definition at line 130 of file BTD.h.

@@ -1414,7 +1577,7 @@ Macros
-

Definition at line 124 of file BTD.h.

+

Definition at line 133 of file BTD.h.

@@ -1428,7 +1591,7 @@ Macros
-

Definition at line 125 of file BTD.h.

+

Definition at line 134 of file BTD.h.

@@ -1442,7 +1605,7 @@ Macros
-

Definition at line 127 of file BTD.h.

+

Definition at line 136 of file BTD.h.

@@ -1456,7 +1619,7 @@ Macros
-

Definition at line 130 of file BTD.h.

+

Definition at line 139 of file BTD.h.

@@ -1470,7 +1633,7 @@ Macros
-

Definition at line 131 of file BTD.h.

+

Definition at line 140 of file BTD.h.

@@ -1484,7 +1647,7 @@ Macros
-

Definition at line 132 of file BTD.h.

+

Definition at line 141 of file BTD.h.

@@ -1498,7 +1661,7 @@ Macros
-

Definition at line 133 of file BTD.h.

+

Definition at line 142 of file BTD.h.

@@ -1512,7 +1675,7 @@ Macros
-

Definition at line 134 of file BTD.h.

+

Definition at line 143 of file BTD.h.

@@ -1526,7 +1689,7 @@ Macros
-

Definition at line 137 of file BTD.h.

+

Definition at line 146 of file BTD.h.

@@ -1540,7 +1703,7 @@ Macros
-

Definition at line 138 of file BTD.h.

+

Definition at line 147 of file BTD.h.

@@ -1554,7 +1717,7 @@ Macros
-

Definition at line 139 of file BTD.h.

+

Definition at line 148 of file BTD.h.

@@ -1568,7 +1731,7 @@ Macros
-

Definition at line 140 of file BTD.h.

+

Definition at line 149 of file BTD.h.

@@ -1582,7 +1745,7 @@ Macros
-

Definition at line 143 of file BTD.h.

+

Definition at line 152 of file BTD.h.

@@ -1596,7 +1759,7 @@ Macros
-

Definition at line 144 of file BTD.h.

+

Definition at line 153 of file BTD.h.

@@ -1610,7 +1773,7 @@ Macros
-

Definition at line 145 of file BTD.h.

+

Definition at line 154 of file BTD.h.

@@ -1624,7 +1787,7 @@ Macros
-

Definition at line 146 of file BTD.h.

+

Definition at line 155 of file BTD.h.

@@ -1638,7 +1801,7 @@ Macros
-

Definition at line 149 of file BTD.h.

+

Definition at line 158 of file BTD.h.

@@ -1652,7 +1815,7 @@ Macros
-

Definition at line 150 of file BTD.h.

+

Definition at line 159 of file BTD.h.

@@ -1666,7 +1829,7 @@ Macros
-

Definition at line 151 of file BTD.h.

+

Definition at line 160 of file BTD.h.

@@ -1680,7 +1843,7 @@ Macros
-

Definition at line 154 of file BTD.h.

+

Definition at line 163 of file BTD.h.

@@ -1694,7 +1857,7 @@ Macros
-

Definition at line 155 of file BTD.h.

+

Definition at line 164 of file BTD.h.

@@ -1708,7 +1871,7 @@ Macros
-

Definition at line 156 of file BTD.h.

+

Definition at line 165 of file BTD.h.

@@ -1722,7 +1885,7 @@ Macros
-

Definition at line 158 of file BTD.h.

+

Definition at line 167 of file BTD.h.

@@ -1740,7 +1903,7 @@ Macros
-

Definition at line 161 of file BTD.h.

+

Definition at line 170 of file BTD.h.

@@ -1758,7 +1921,7 @@ Macros
-

Definition at line 162 of file BTD.h.

+

Definition at line 171 of file BTD.h.

@@ -1776,7 +1939,7 @@ Macros
-

Definition at line 163 of file BTD.h.

+

Definition at line 172 of file BTD.h.

@@ -1790,7 +1953,7 @@ Macros
-

Definition at line 166 of file BTD.h.

+

Definition at line 175 of file BTD.h.

@@ -1804,7 +1967,7 @@ Macros
-

Definition at line 167 of file BTD.h.

+

Definition at line 176 of file BTD.h.

@@ -1818,7 +1981,7 @@ Macros
-

Definition at line 168 of file BTD.h.

+

Definition at line 177 of file BTD.h.

@@ -1832,7 +1995,7 @@ Macros
-

Definition at line 169 of file BTD.h.

+

Definition at line 178 of file BTD.h.

@@ -1846,7 +2009,7 @@ Macros
-

Definition at line 170 of file BTD.h.

+

Definition at line 179 of file BTD.h.

@@ -1860,7 +2023,7 @@ Macros
-

Definition at line 171 of file BTD.h.

+

Definition at line 180 of file BTD.h.

@@ -1874,7 +2037,7 @@ Macros
-

Definition at line 172 of file BTD.h.

+

Definition at line 181 of file BTD.h.

@@ -1888,7 +2051,7 @@ Macros
-

Definition at line 173 of file BTD.h.

+

Definition at line 182 of file BTD.h.

@@ -1902,7 +2065,7 @@ Macros
-

Definition at line 174 of file BTD.h.

+

Definition at line 183 of file BTD.h.

@@ -1916,7 +2079,7 @@ Macros
-

Definition at line 177 of file BTD.h.

+

Definition at line 186 of file BTD.h.

@@ -1930,7 +2093,7 @@ Macros
-

Definition at line 178 of file BTD.h.

+

Definition at line 187 of file BTD.h.

@@ -1944,7 +2107,7 @@ Macros
-

Definition at line 181 of file BTD.h.

+

Definition at line 190 of file BTD.h.

@@ -1958,7 +2121,7 @@ Macros
-

Definition at line 182 of file BTD.h.

+

Definition at line 191 of file BTD.h.

@@ -1972,7 +2135,7 @@ Macros
-

Definition at line 183 of file BTD.h.

+

Definition at line 192 of file BTD.h.

@@ -1986,7 +2149,133 @@ Macros
-

Definition at line 184 of file BTD.h.

+

Definition at line 193 of file BTD.h.

+ +
+ + +
+
+ + + + +
#define SDP_SERVICE_SEARCH_REQUEST   0x02
+
+ +

Definition at line 196 of file BTD.h.

+ +
+
+ +
+
+ + + + +
#define SDP_SERVICE_SEARCH_RESPONSE   0x03
+
+ +

Definition at line 197 of file BTD.h.

+ +
+
+ +
+
+ + + + +
#define SDP_SERVICE_ATTRIBUTE_REQUEST   0x04
+
+ +

Definition at line 198 of file BTD.h.

+ +
+
+ +
+
+ + + + +
#define SDP_SERVICE_ATTRIBUTE_RESPONSE   0x05
+
+ +

Definition at line 199 of file BTD.h.

+ +
+
+ +
+
+ + + + +
#define SDP_SERVICE_SEARCH_ATTRIBUTE_REQUEST   0x06
+
+ +

Definition at line 200 of file BTD.h.

+ +
+
+ +
+
+ + + + +
#define SDP_SERVICE_SEARCH_ATTRIBUTE_RESPONSE   0x07
+
+ +

Definition at line 201 of file BTD.h.

+ +
+
+ +
+
+ + + + +
#define PNP_INFORMATION_UUID   0x1200
+
+ +

Definition at line 202 of file BTD.h.

+ +
+
+ +
+
+ + + + +
#define SERIALPORT_UUID   0x1101
+
+ +

Definition at line 203 of file BTD.h.

+ +
+
+ +
+
+ + + + +
#define L2CAP_UUID   0x0100
+
+ +

Definition at line 204 of file BTD.h.

@@ -2000,7 +2289,7 @@ Macros
-

Definition at line 187 of file BTD.h.

+

Definition at line 207 of file BTD.h.

@@ -2014,7 +2303,7 @@ Macros
-

Definition at line 188 of file BTD.h.

+

Definition at line 208 of file BTD.h.

@@ -2028,7 +2317,7 @@ Macros
-

Definition at line 190 of file BTD.h.

+

Definition at line 210 of file BTD.h.

@@ -2042,7 +2331,7 @@ Macros
-

Definition at line 191 of file BTD.h.

+

Definition at line 211 of file BTD.h.

@@ -2056,7 +2345,7 @@ Macros
-

Definition at line 193 of file BTD.h.

+

Definition at line 213 of file BTD.h.

diff --git a/_b_t_d_8h__dep__incl.map b/_b_t_d_8h__dep__incl.map index d582d1ce..f1f02286 100644 --- a/_b_t_d_8h__dep__incl.map +++ b/_b_t_d_8h__dep__incl.map @@ -1,12 +1,13 @@ - - - - - + + + + + - - - + + + + diff --git a/_b_t_d_8h__dep__incl.md5 b/_b_t_d_8h__dep__incl.md5 index 3f896a89..bbea866d 100644 --- a/_b_t_d_8h__dep__incl.md5 +++ b/_b_t_d_8h__dep__incl.md5 @@ -1 +1 @@ -1cf25c5527b32b2a9e530f3758fe7f24 \ No newline at end of file +9039e772c47944b11e9bf0a098808b93 \ No newline at end of file diff --git a/_b_t_d_8h__dep__incl.png b/_b_t_d_8h__dep__incl.png index a69a37b7bf936e071f5475c56e668f7e8b83514d..e8438b44d78fe6f3fbda4b2eaa01ef50ddc92f0e 100644 GIT binary patch literal 15916 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 literal 13917 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 c3Eq1=+0Y!Ta@wBTD.h
-Go to the documentation of this file.
1 /* Copyright (C) 2012 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 _btd_h_
19 #define _btd_h_
20 
21 #include "Usb.h"
22 #include "usbhid.h"
23 
24 //PID and VID of the Sony PS3 devices
25 #define PS3_VID 0x054C // Sony Corporation
26 #define PS3_PID 0x0268 // PS3 Controller DualShock 3
27 #define PS3NAVIGATION_PID 0x042F // Navigation controller
28 #define PS3MOVE_PID 0x03D5 // Motion controller
29 
30 // These dongles do not present themselves correctly, so we have to check for them manually
31 #define IOGEAR_GBU521_VID 0x0A5C
32 #define IOGEAR_GBU521_PID 0x21E8
33 #define BELKIN_F8T065BF_VID 0x050D
34 #define BELKIN_F8T065BF_PID 0x065A
35 
36 /* Bluetooth dongle data taken from descriptors */
37 #define BULK_MAXPKTSIZE 64 // Max size for ACL data
38 
39 // Used in control endpoint header for HCI Commands
40 #define bmREQ_HCI_OUT USB_SETUP_HOST_TO_DEVICE|USB_SETUP_TYPE_CLASS|USB_SETUP_RECIPIENT_DEVICE
41 
42 /* Bluetooth HCI states for hci_task() */
43 #define HCI_INIT_STATE 0
44 #define HCI_RESET_STATE 1
45 #define HCI_CLASS_STATE 2
46 #define HCI_BDADDR_STATE 3
47 #define HCI_LOCAL_VERSION_STATE 4
48 #define HCI_SET_NAME_STATE 5
49 #define HCI_CHECK_DEVICE_SERVICE 6
50 
51 #define HCI_INQUIRY_STATE 7 // These three states are only used if it should pair and connect to a device
52 #define HCI_CONNECT_DEVICE_STATE 8
53 #define HCI_CONNECTED_DEVICE_STATE 9
54 
55 #define HCI_SCANNING_STATE 10
56 #define HCI_CONNECT_IN_STATE 11
57 #define HCI_REMOTE_NAME_STATE 12
58 #define HCI_CONNECTED_STATE 13
59 #define HCI_DISABLE_SCAN_STATE 14
60 #define HCI_DONE_STATE 15
61 #define HCI_DISCONNECT_STATE 16
62 
63 /* HCI event flags*/
64 #define HCI_FLAG_CMD_COMPLETE (1UL << 0)
65 #define HCI_FLAG_CONNECT_COMPLETE (1UL << 1)
66 #define HCI_FLAG_DISCONNECT_COMPLETE (1UL << 2)
67 #define HCI_FLAG_REMOTE_NAME_COMPLETE (1UL << 3)
68 #define HCI_FLAG_INCOMING_REQUEST (1UL << 4)
69 #define HCI_FLAG_READ_BDADDR (1UL << 5)
70 #define HCI_FLAG_READ_VERSION (1UL << 6)
71 #define HCI_FLAG_DEVICE_FOUND (1UL << 7)
72 #define HCI_FLAG_CONNECT_EVENT (1UL << 8)
73 
74 /* Macros for HCI event flag tests */
75 #define hci_check_flag(flag) (hci_event_flag & (flag))
76 #define hci_set_flag(flag) (hci_event_flag |= (flag))
77 #define hci_clear_flag(flag) (hci_event_flag &= ~(flag))
78 
79 /* HCI Events managed */
80 #define EV_INQUIRY_COMPLETE 0x01
81 #define EV_INQUIRY_RESULT 0x02
82 #define EV_CONNECT_COMPLETE 0x03
83 #define EV_INCOMING_CONNECT 0x04
84 #define EV_DISCONNECT_COMPLETE 0x05
85 #define EV_AUTHENTICATION_COMPLETE 0x06
86 #define EV_REMOTE_NAME_COMPLETE 0x07
87 #define EV_ENCRYPTION_CHANGE 0x08
88 #define EV_CHANGE_CONNECTION_LINK 0x09
89 #define EV_ROLE_CHANGED 0x12
90 #define EV_NUM_COMPLETE_PKT 0x13
91 #define EV_PIN_CODE_REQUEST 0x16
92 #define EV_LINK_KEY_REQUEST 0x17
93 #define EV_LINK_KEY_NOTIFICATION 0x18
94 #define EV_DATA_BUFFER_OVERFLOW 0x1A
95 #define EV_MAX_SLOTS_CHANGE 0x1B
96 #define EV_READ_REMOTE_VERSION_INFORMATION_COMPLETE 0x0C
97 #define EV_QOS_SETUP_COMPLETE 0x0D
98 #define EV_COMMAND_COMPLETE 0x0E
99 #define EV_COMMAND_STATUS 0x0F
100 #define EV_LOOPBACK_COMMAND 0x19
101 #define EV_PAGE_SCAN_REP_MODE 0x20
102 
103 /* Bluetooth states for the different Bluetooth drivers */
104 #define L2CAP_WAIT 0
105 #define L2CAP_DONE 1
106 
107 /* Used for HID Control channel */
108 #define L2CAP_CONTROL_CONNECT_REQUEST 2
109 #define L2CAP_CONTROL_CONFIG_REQUEST 3
110 #define L2CAP_CONTROL_SUCCESS 4
111 #define L2CAP_CONTROL_DISCONNECT 5
112 
113 /* Used for HID Interrupt channel */
114 #define L2CAP_INTERRUPT_SETUP 6
115 #define L2CAP_INTERRUPT_CONNECT_REQUEST 7
116 #define L2CAP_INTERRUPT_CONFIG_REQUEST 8
117 #define L2CAP_INTERRUPT_DISCONNECT 9
118 
119 /* Used for SDP channel */
120 #define L2CAP_SDP_WAIT 10
121 #define L2CAP_SDP_SUCCESS 11
122 
123 /* Used for RFCOMM channel */
124 #define L2CAP_RFCOMM_WAIT 12
125 #define L2CAP_RFCOMM_SUCCESS 13
126 
127 #define L2CAP_DISCONNECT_RESPONSE 14 // Used for both SDP and RFCOMM channel
128 
129 /* Bluetooth states used by some drivers */
130 #define TURN_ON_LED 17
131 #define PS3_ENABLE_SIXAXIS 18
132 #define WII_CHECK_MOTION_PLUS_STATE 19
133 #define WII_CHECK_EXTENSION_STATE 20
134 #define WII_INIT_MOTION_PLUS_STATE 21
135 
136 /* L2CAP event flags for HID Control channel */
137 #define L2CAP_FLAG_CONNECTION_CONTROL_REQUEST (1UL << 0)
138 #define L2CAP_FLAG_CONFIG_CONTROL_SUCCESS (1UL << 1)
139 #define L2CAP_FLAG_CONTROL_CONNECTED (1UL << 2)
140 #define L2CAP_FLAG_DISCONNECT_CONTROL_RESPONSE (1UL << 3)
141 
142 /* L2CAP event flags for HID Interrupt channel */
143 #define L2CAP_FLAG_CONNECTION_INTERRUPT_REQUEST (1UL << 4)
144 #define L2CAP_FLAG_CONFIG_INTERRUPT_SUCCESS (1UL << 5)
145 #define L2CAP_FLAG_INTERRUPT_CONNECTED (1UL << 6)
146 #define L2CAP_FLAG_DISCONNECT_INTERRUPT_RESPONSE (1UL << 7)
147 
148 /* L2CAP event flags for SDP channel */
149 #define L2CAP_FLAG_CONNECTION_SDP_REQUEST (1UL << 8)
150 #define L2CAP_FLAG_CONFIG_SDP_SUCCESS (1UL << 9)
151 #define L2CAP_FLAG_DISCONNECT_SDP_REQUEST (1UL << 10)
152 
153 /* L2CAP event flags for RFCOMM channel */
154 #define L2CAP_FLAG_CONNECTION_RFCOMM_REQUEST (1UL << 11)
155 #define L2CAP_FLAG_CONFIG_RFCOMM_SUCCESS (1UL << 12)
156 #define L2CAP_FLAG_DISCONNECT_RFCOMM_REQUEST (1UL << 13)
157 
158 #define L2CAP_FLAG_DISCONNECT_RESPONSE (1UL << 14)
159 
160 /* Macros for L2CAP event flag tests */
161 #define l2cap_check_flag(flag) (l2cap_event_flag & (flag))
162 #define l2cap_set_flag(flag) (l2cap_event_flag |= (flag))
163 #define l2cap_clear_flag(flag) (l2cap_event_flag &= ~(flag))
164 
165 /* L2CAP signaling commands */
166 #define L2CAP_CMD_COMMAND_REJECT 0x01
167 #define L2CAP_CMD_CONNECTION_REQUEST 0x02
168 #define L2CAP_CMD_CONNECTION_RESPONSE 0x03
169 #define L2CAP_CMD_CONFIG_REQUEST 0x04
170 #define L2CAP_CMD_CONFIG_RESPONSE 0x05
171 #define L2CAP_CMD_DISCONNECT_REQUEST 0x06
172 #define L2CAP_CMD_DISCONNECT_RESPONSE 0x07
173 #define L2CAP_CMD_INFORMATION_REQUEST 0x0A
174 #define L2CAP_CMD_INFORMATION_RESPONSE 0x0B
175 
176 // Used For Connection Response - Remember to Include High Byte
177 #define PENDING 0x01
178 #define SUCCESSFUL 0x00
179 
180 /* Bluetooth L2CAP PSM - see http://www.bluetooth.org/Technical/AssignedNumbers/logical_link.htm */
181 #define SDP_PSM 0x01 // Service Discovery Protocol PSM Value
182 #define RFCOMM_PSM 0x03 // RFCOMM PSM Value
183 #define HID_CTRL_PSM 0x11 // HID_Control PSM Value
184 #define HID_INTR_PSM 0x13 // HID_Interrupt PSM Value
185 
186 // Used to determine if it is a Bluetooth dongle
187 #define WI_SUBCLASS_RF 0x01 // RF Controller
188 #define WI_PROTOCOL_BT 0x01 // Bluetooth Programming Interface
189 
190 #define BTD_MAX_ENDPOINTS 4
191 #define BTD_NUM_SERVICES 4 // Max number of Bluetooth services - if you need more than 4 simply increase this number
192 
193 #define PAIR 1
194 
195 class BluetoothService;
196 
201 class BTD : public USBDeviceConfig, public UsbConfigXtracter {
202 public:
207  BTD(USB *p);
208 
217  uint8_t ConfigureDevice(uint8_t parent, uint8_t port, bool lowspeed);
225  uint8_t Init(uint8_t parent, uint8_t port, bool lowspeed);
230  uint8_t Release();
235  uint8_t Poll();
236 
241  virtual uint8_t GetAddress() {
242  return bAddress;
243  };
244 
249  virtual bool isReady() {
250  return bPollEnable;
251  };
252 
258  virtual bool DEVCLASSOK(uint8_t klass) {
259  return (klass == USB_CLASS_WIRELESS_CTRL);
260  };
261 
269  virtual bool VIDPIDOK(uint16_t vid, uint16_t pid) {
270  if((vid == IOGEAR_GBU521_VID && pid == IOGEAR_GBU521_PID) || (vid == BELKIN_F8T065BF_VID && pid == BELKIN_F8T065BF_PID))
271  return true;
272  if(my_bdaddr[0] != 0x00 || my_bdaddr[1] != 0x00 || my_bdaddr[2] != 0x00 || my_bdaddr[3] != 0x00 || my_bdaddr[4] != 0x00 || my_bdaddr[5] != 0x00) { // Check if Bluetooth address is set
273  if(vid == PS3_VID && (pid == PS3_PID || pid == PS3NAVIGATION_PID || pid == PS3MOVE_PID))
274  return true;
275  }
276  return false;
277  };
289  void EndpointXtract(uint8_t conf, uint8_t iface, uint8_t alt, uint8_t proto, const USB_ENDPOINT_DESCRIPTOR *ep);
293  void disconnect();
294 
301  for(uint8_t i = 0; i < BTD_NUM_SERVICES; i++) {
302  if(!btService[i]) {
303  btService[i] = pService;
304  return i; // Return ID
305  }
306  }
307  return -1; // Error registering BluetoothService
308  };
309 
316  void HCI_Command(uint8_t* data, uint16_t nbytes);
318  void hci_reset();
320  void hci_read_bdaddr();
327  void hci_set_local_name(const char* name);
329  void hci_write_scan_enable();
331  void hci_write_scan_disable();
333  void hci_remote_name();
335  void hci_accept_connection();
340  void hci_disconnect(uint16_t handle);
357  void hci_inquiry();
359  void hci_inquiry_cancel();
361  void hci_connect();
366  void hci_connect(uint8_t *bdaddr);
380  void L2CAP_Command(uint16_t handle, uint8_t* data, uint8_t nbytes, uint8_t channelLow = 0x01, uint8_t channelHigh = 0x00);
388  void l2cap_connection_request(uint16_t handle, uint8_t rxid, uint8_t* scid, uint16_t psm);
397  void l2cap_connection_response(uint16_t handle, uint8_t rxid, uint8_t* dcid, uint8_t* scid, uint8_t result);
404  void l2cap_config_request(uint16_t handle, uint8_t rxid, uint8_t* dcid);
411  void l2cap_config_response(uint16_t handle, uint8_t rxid, uint8_t* scid);
419  void l2cap_disconnection_request(uint16_t handle, uint8_t rxid, uint8_t* dcid, uint8_t* scid);
427  void l2cap_disconnection_response(uint16_t handle, uint8_t rxid, uint8_t* dcid, uint8_t* scid);
434  void l2cap_information_response(uint16_t handle, uint8_t rxid, uint8_t infoTypeLow, uint8_t infoTypeHigh);
445 
447  const char* btdName;
449  const char* btdPin;
450 
452  uint8_t my_bdaddr[6];
454  uint16_t hci_handle;
456  uint8_t disc_bdaddr[6];
458  char remote_name[30];
464  uint8_t hci_version;
465 
468  pairWithWii = true;
469  hci_state = HCI_CHECK_DEVICE_SERVICE;
470  };
472  bool connectToWii;
481 
483  void pairWithHID() {
484  waitingForConnection = false;
485  pairWithHIDDevice = true;
486  hci_state = HCI_CHECK_DEVICE_SERVICE;
487  };
489  bool connectToHIDDevice;
494 
499  uint8_t readPollInterval() {
500  return pollInterval;
501  };
502 
503 protected:
505  USB *pUsb;
507  uint8_t bAddress;
510 
512  uint8_t bConfNum;
514  uint8_t bNumEP;
516  uint32_t qNextPollTime;
517 
519  static const uint8_t BTD_CONTROL_PIPE;
521  static const uint8_t BTD_EVENT_PIPE;
523  static const uint8_t BTD_DATAIN_PIPE;
525  static const uint8_t BTD_DATAOUT_PIPE;
526 
532 
533 private:
534  void Initialize(); // Set all variables, endpoint structs etc. to default values
536 
537  uint16_t PID, VID; // PID and VID of device connected
538 
539  uint8_t pollInterval;
540  bool bPollEnable;
541 
542  bool pairWiiUsingSync; // True if pairing was done using the Wii SYNC button.
543  bool checkRemoteName; // Used to check remote device's name before connecting.
544  bool incomingPS4; // True if a PS4 controller is connecting
545  uint8_t classOfDevice[3]; // Class of device of last device
546 
547  /* Variables used by high level HCI task */
548  uint8_t hci_state; // Current state of Bluetooth HCI connection
549  uint16_t hci_counter; // Counter used for Bluetooth HCI reset loops
550  uint16_t hci_num_reset_loops; // This value indicate how many times it should read before trying to reset
551  uint16_t hci_event_flag; // HCI flags of received Bluetooth events
552  uint8_t inquiry_counter;
553 
554  uint8_t hcibuf[BULK_MAXPKTSIZE]; // General purpose buffer for HCI data
555  uint8_t l2capinbuf[BULK_MAXPKTSIZE]; // General purpose buffer for L2CAP in data
556  uint8_t l2capoutbuf[14]; // General purpose buffer for L2CAP out data
557 
558  /* State machines */
559  void HCI_event_task(); // Poll the HCI event pipe
560  void HCI_task(); // HCI state machine
561  void ACL_event_task(); // ACL input pipe
562 
563  /* Used to set the Bluetooth Address internally to the PS3 Controllers */
564  void setBdaddr(uint8_t* BDADDR);
565  void setMoveBdaddr(uint8_t* BDADDR);
566 };
567 
570 public:
571  BluetoothService(BTD *p) : pBtd(p) {
572  if(pBtd)
573  pBtd->registerBluetoothService(this); // Register it as a Bluetooth service
574  };
579  virtual void ACLData(uint8_t* ACLData) = 0;
581  virtual void Run() = 0;
583  virtual void Reset() = 0;
585  virtual void disconnect() = 0;
586 
591  void attachOnInit(void (*funcOnInit)(void)) {
592  pFuncOnInit = funcOnInit; // TODO: This really belong in a class of it's own as it is repeated several times
593  };
594 
595 protected:
601  virtual void onInit() = 0;
602 
604  bool checkHciHandle(uint8_t *buf, uint16_t handle) {
605  return (buf[0] == (handle & 0xFF)) && (buf[1] == ((handle >> 8) | 0x20));
606  }
607 
609  void (*pFuncOnInit)(void);
610 
613 
615  uint16_t hci_handle;
616 
619 
621  uint8_t identifier;
622 };
623 
624 #endif
static const uint8_t BTD_DATAOUT_PIPE
Definition: BTD.h:525
-
bool incomingWii
Definition: BTD.h:474
-
void hci_connect()
Definition: BTD.cpp:1071
-
uint8_t bNumEP
Definition: BTD.h:514
-
const char * btdName
Definition: BTD.h:447
-
void hci_reset()
Definition: BTD.cpp:953
-
void l2cap_connection_response(uint16_t handle, uint8_t rxid, uint8_t *dcid, uint8_t *scid, uint8_t result)
Definition: BTD.cpp:1260
-
void l2cap_connection_request(uint16_t handle, uint8_t rxid, uint8_t *scid, uint16_t psm)
Definition: BTD.cpp:1247
-
bool sdpConnectionClaimed
Definition: BTD.h:442
-
Definition: BTD.h:201
-
int8_t registerBluetoothService(BluetoothService *pService)
Definition: BTD.h:300
-
void l2cap_disconnection_request(uint16_t handle, uint8_t rxid, uint8_t *dcid, uint8_t *scid)
Definition: BTD.cpp:1313
-
bool rfcommConnectionClaimed
Definition: BTD.h:444
-
uint8_t hci_version
Definition: BTD.h:464
-
bool waitingForConnection
Definition: BTD.h:438
-
void hci_inquiry()
Definition: BTD.cpp:1049
-
static const uint8_t BTD_EVENT_PIPE
Definition: BTD.h:521
+Go to the documentation of this file.
1 /* Copyright (C) 2012 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 _btd_h_
19 #define _btd_h_
20 
21 #include "Usb.h"
22 #include "usbhid.h"
23 
24 //PID and VID of the Sony PS3 devices
25 #define PS3_VID 0x054C // Sony Corporation
26 #define PS3_PID 0x0268 // PS3 Controller DualShock 3
27 #define PS3NAVIGATION_PID 0x042F // Navigation controller
28 #define PS3MOVE_PID 0x03D5 // Motion controller
29 
30 // These dongles do not present themselves correctly, so we have to check for them manually
31 #define IOGEAR_GBU521_VID 0x0A5C
32 #define IOGEAR_GBU521_PID 0x21E8
33 #define BELKIN_F8T065BF_VID 0x050D
34 #define BELKIN_F8T065BF_PID 0x065A
35 
36 /* Bluetooth dongle data taken from descriptors */
37 #define BULK_MAXPKTSIZE 64 // Max size for ACL data
38 
39 // Used in control endpoint header for HCI Commands
40 #define bmREQ_HCI_OUT USB_SETUP_HOST_TO_DEVICE|USB_SETUP_TYPE_CLASS|USB_SETUP_RECIPIENT_DEVICE
41 
42 /* Bluetooth HCI states for hci_task() */
43 #define HCI_INIT_STATE 0
44 #define HCI_RESET_STATE 1
45 #define HCI_CLASS_STATE 2
46 #define HCI_BDADDR_STATE 3
47 #define HCI_LOCAL_VERSION_STATE 4
48 #define HCI_WRITE_NAME_STATE 5
49 #define HCI_CHECK_DEVICE_SERVICE 6
50 
51 #define HCI_INQUIRY_STATE 7 // These three states are only used if it should pair and connect to a device
52 #define HCI_CONNECT_DEVICE_STATE 8
53 #define HCI_CONNECTED_DEVICE_STATE 9
54 
55 #define HCI_SCANNING_STATE 10
56 #define HCI_CONNECT_IN_STATE 11
57 #define HCI_REMOTE_NAME_STATE 12
58 #define HCI_CONNECTED_STATE 13
59 #define HCI_DISABLE_SCAN_STATE 14
60 #define HCI_DONE_STATE 15
61 #define HCI_DISCONNECT_STATE 16
62 #define HCI_LOCAL_EXTENDED_FEATURES_STATE 17
63 #define HCI_WRITE_SIMPLE_PAIRING_STATE 18
64 #define HCI_SET_EVENT_MASK_STATE 19
65 
66 /* HCI event flags*/
67 #define HCI_FLAG_CMD_COMPLETE (1UL << 0)
68 #define HCI_FLAG_CONNECT_COMPLETE (1UL << 1)
69 #define HCI_FLAG_DISCONNECT_COMPLETE (1UL << 2)
70 #define HCI_FLAG_REMOTE_NAME_COMPLETE (1UL << 3)
71 #define HCI_FLAG_INCOMING_REQUEST (1UL << 4)
72 #define HCI_FLAG_READ_BDADDR (1UL << 5)
73 #define HCI_FLAG_READ_VERSION (1UL << 6)
74 #define HCI_FLAG_DEVICE_FOUND (1UL << 7)
75 #define HCI_FLAG_CONNECT_EVENT (1UL << 8)
76 #define HCI_FLAG_LOCAL_EXTENDED_FEATURES (1UL << 9)
77 
78 /* Macros for HCI event flag tests */
79 #define hci_check_flag(flag) (hci_event_flag & (flag))
80 #define hci_set_flag(flag) (hci_event_flag |= (flag))
81 #define hci_clear_flag(flag) (hci_event_flag &= ~(flag))
82 
83 /* HCI Events managed */
84 #define EV_INQUIRY_COMPLETE 0x01
85 #define EV_INQUIRY_RESULT 0x02
86 #define EV_CONNECT_COMPLETE 0x03
87 #define EV_INCOMING_CONNECT 0x04
88 #define EV_DISCONNECT_COMPLETE 0x05
89 #define EV_AUTHENTICATION_COMPLETE 0x06
90 #define EV_REMOTE_NAME_COMPLETE 0x07
91 #define EV_ENCRYPTION_CHANGE 0x08
92 #define EV_CHANGE_CONNECTION_LINK 0x09
93 #define EV_READ_REMOTE_VERSION_INFORMATION_COMPLETE 0x0C
94 #define EV_QOS_SETUP_COMPLETE 0x0D
95 #define EV_COMMAND_COMPLETE 0x0E
96 #define EV_COMMAND_STATUS 0x0F
97 #define EV_ROLE_CHANGED 0x12
98 #define EV_NUM_COMPLETE_PKT 0x13
99 #define EV_PIN_CODE_REQUEST 0x16
100 #define EV_LINK_KEY_REQUEST 0x17
101 #define EV_LINK_KEY_NOTIFICATION 0x18
102 #define EV_DATA_BUFFER_OVERFLOW 0x1A
103 #define EV_MAX_SLOTS_CHANGE 0x1B
104 #define EV_LOOPBACK_COMMAND 0x19
105 #define EV_PAGE_SCAN_REP_MODE 0x20
106 #define EV_READ_REMOTE_EXTENDED_FEATURES_COMPLETE 0x23
107 #define EV_IO_CAPABILITY_REQUEST 0x31
108 #define EV_IO_CAPABILITY_RESPONSE 0x32
109 #define EV_USER_CONFIRMATION_REQUEST 0x33
110 #define EV_SIMPLE_PAIRING_COMPLETE 0x36
111 
112 /* Bluetooth states for the different Bluetooth drivers */
113 #define L2CAP_WAIT 0
114 #define L2CAP_DONE 1
115 
116 /* Used for HID Control channel */
117 #define L2CAP_CONTROL_CONNECT_REQUEST 2
118 #define L2CAP_CONTROL_CONFIG_REQUEST 3
119 #define L2CAP_CONTROL_SUCCESS 4
120 #define L2CAP_CONTROL_DISCONNECT 5
121 
122 /* Used for HID Interrupt channel */
123 #define L2CAP_INTERRUPT_SETUP 6
124 #define L2CAP_INTERRUPT_CONNECT_REQUEST 7
125 #define L2CAP_INTERRUPT_CONFIG_REQUEST 8
126 #define L2CAP_INTERRUPT_DISCONNECT 9
127 
128 /* Used for SDP channel */
129 #define L2CAP_SDP_WAIT 10
130 #define L2CAP_SDP_SUCCESS 11
131 
132 /* Used for RFCOMM channel */
133 #define L2CAP_RFCOMM_WAIT 12
134 #define L2CAP_RFCOMM_SUCCESS 13
135 
136 #define L2CAP_DISCONNECT_RESPONSE 14 // Used for both SDP and RFCOMM channel
137 
138 /* Bluetooth states used by some drivers */
139 #define TURN_ON_LED 17
140 #define PS3_ENABLE_SIXAXIS 18
141 #define WII_CHECK_MOTION_PLUS_STATE 19
142 #define WII_CHECK_EXTENSION_STATE 20
143 #define WII_INIT_MOTION_PLUS_STATE 21
144 
145 /* L2CAP event flags for HID Control channel */
146 #define L2CAP_FLAG_CONNECTION_CONTROL_REQUEST (1UL << 0)
147 #define L2CAP_FLAG_CONFIG_CONTROL_SUCCESS (1UL << 1)
148 #define L2CAP_FLAG_CONTROL_CONNECTED (1UL << 2)
149 #define L2CAP_FLAG_DISCONNECT_CONTROL_RESPONSE (1UL << 3)
150 
151 /* L2CAP event flags for HID Interrupt channel */
152 #define L2CAP_FLAG_CONNECTION_INTERRUPT_REQUEST (1UL << 4)
153 #define L2CAP_FLAG_CONFIG_INTERRUPT_SUCCESS (1UL << 5)
154 #define L2CAP_FLAG_INTERRUPT_CONNECTED (1UL << 6)
155 #define L2CAP_FLAG_DISCONNECT_INTERRUPT_RESPONSE (1UL << 7)
156 
157 /* L2CAP event flags for SDP channel */
158 #define L2CAP_FLAG_CONNECTION_SDP_REQUEST (1UL << 8)
159 #define L2CAP_FLAG_CONFIG_SDP_SUCCESS (1UL << 9)
160 #define L2CAP_FLAG_DISCONNECT_SDP_REQUEST (1UL << 10)
161 
162 /* L2CAP event flags for RFCOMM channel */
163 #define L2CAP_FLAG_CONNECTION_RFCOMM_REQUEST (1UL << 11)
164 #define L2CAP_FLAG_CONFIG_RFCOMM_SUCCESS (1UL << 12)
165 #define L2CAP_FLAG_DISCONNECT_RFCOMM_REQUEST (1UL << 13)
166 
167 #define L2CAP_FLAG_DISCONNECT_RESPONSE (1UL << 14)
168 
169 /* Macros for L2CAP event flag tests */
170 #define l2cap_check_flag(flag) (l2cap_event_flag & (flag))
171 #define l2cap_set_flag(flag) (l2cap_event_flag |= (flag))
172 #define l2cap_clear_flag(flag) (l2cap_event_flag &= ~(flag))
173 
174 /* L2CAP signaling commands */
175 #define L2CAP_CMD_COMMAND_REJECT 0x01
176 #define L2CAP_CMD_CONNECTION_REQUEST 0x02
177 #define L2CAP_CMD_CONNECTION_RESPONSE 0x03
178 #define L2CAP_CMD_CONFIG_REQUEST 0x04
179 #define L2CAP_CMD_CONFIG_RESPONSE 0x05
180 #define L2CAP_CMD_DISCONNECT_REQUEST 0x06
181 #define L2CAP_CMD_DISCONNECT_RESPONSE 0x07
182 #define L2CAP_CMD_INFORMATION_REQUEST 0x0A
183 #define L2CAP_CMD_INFORMATION_RESPONSE 0x0B
184 
185 // Used For Connection Response - Remember to Include High Byte
186 #define PENDING 0x01
187 #define SUCCESSFUL 0x00
188 
189 /* Bluetooth L2CAP PSM - see http://www.bluetooth.org/Technical/AssignedNumbers/logical_link.htm */
190 #define SDP_PSM 0x01 // Service Discovery Protocol PSM Value
191 #define RFCOMM_PSM 0x03 // RFCOMM PSM Value
192 #define HID_CTRL_PSM 0x11 // HID_Control PSM Value
193 #define HID_INTR_PSM 0x13 // HID_Interrupt PSM Value
194 
195 /* Used for SDP */
196 #define SDP_SERVICE_SEARCH_REQUEST 0x02
197 #define SDP_SERVICE_SEARCH_RESPONSE 0x03
198 #define SDP_SERVICE_ATTRIBUTE_REQUEST 0x04
199 #define SDP_SERVICE_ATTRIBUTE_RESPONSE 0x05
200 #define SDP_SERVICE_SEARCH_ATTRIBUTE_REQUEST 0x06 // See the RFCOMM specs
201 #define SDP_SERVICE_SEARCH_ATTRIBUTE_RESPONSE 0x07 // See the RFCOMM specs
202 #define PNP_INFORMATION_UUID 0x1200
203 #define SERIALPORT_UUID 0x1101 // See http://www.bluetooth.org/Technical/AssignedNumbers/service_discovery.htm
204 #define L2CAP_UUID 0x0100
205 
206 // Used to determine if it is a Bluetooth dongle
207 #define WI_SUBCLASS_RF 0x01 // RF Controller
208 #define WI_PROTOCOL_BT 0x01 // Bluetooth Programming Interface
209 
210 #define BTD_MAX_ENDPOINTS 4
211 #define BTD_NUM_SERVICES 4 // Max number of Bluetooth services - if you need more than 4 simply increase this number
212 
213 #define PAIR 1
214 
215 class BluetoothService;
216 
221 class BTD : public USBDeviceConfig, public UsbConfigXtracter {
222 public:
227  BTD(USB *p);
228 
237  uint8_t ConfigureDevice(uint8_t parent, uint8_t port, bool lowspeed);
245  uint8_t Init(uint8_t parent, uint8_t port, bool lowspeed);
250  uint8_t Release();
255  uint8_t Poll();
256 
261  virtual uint8_t GetAddress() {
262  return bAddress;
263  };
264 
269  virtual bool isReady() {
270  return bPollEnable;
271  };
272 
278  virtual bool DEVCLASSOK(uint8_t klass) {
279  return (klass == USB_CLASS_WIRELESS_CTRL);
280  };
281 
289  virtual bool VIDPIDOK(uint16_t vid, uint16_t pid) {
290  if((vid == IOGEAR_GBU521_VID && pid == IOGEAR_GBU521_PID) || (vid == BELKIN_F8T065BF_VID && pid == BELKIN_F8T065BF_PID))
291  return true;
292  if(my_bdaddr[0] != 0x00 || my_bdaddr[1] != 0x00 || my_bdaddr[2] != 0x00 || my_bdaddr[3] != 0x00 || my_bdaddr[4] != 0x00 || my_bdaddr[5] != 0x00) { // Check if Bluetooth address is set
293  if(vid == PS3_VID && (pid == PS3_PID || pid == PS3NAVIGATION_PID || pid == PS3MOVE_PID))
294  return true;
295  }
296  return false;
297  };
309  void EndpointXtract(uint8_t conf, uint8_t iface, uint8_t alt, uint8_t proto, const USB_ENDPOINT_DESCRIPTOR *ep);
313  void disconnect();
314 
321  for(uint8_t i = 0; i < BTD_NUM_SERVICES; i++) {
322  if(!btService[i]) {
323  btService[i] = pService;
324  return i; // Return ID
325  }
326  }
327  return -1; // Error registering BluetoothService
328  };
329 
336  void HCI_Command(uint8_t* data, uint16_t nbytes);
338  void hci_reset();
340  void hci_read_bdaddr();
344  void hci_read_local_extended_features(uint8_t page_number);
349  void hci_write_local_name(const char* name);
351  void hci_write_simple_pairing_mode(bool enable);
353  void hci_set_event_mask();
355  void hci_write_scan_enable();
357  void hci_write_scan_disable();
359  void hci_remote_name();
361  void hci_accept_connection();
366  void hci_disconnect(uint16_t handle);
385  void hci_inquiry();
387  void hci_inquiry_cancel();
389  void hci_connect();
396  void hci_connect(uint8_t *bdaddr);
410  void L2CAP_Command(uint16_t handle, uint8_t* data, uint8_t nbytes, uint8_t channelLow = 0x01, uint8_t channelHigh = 0x00);
418  void l2cap_connection_request(uint16_t handle, uint8_t rxid, uint8_t* scid, uint16_t psm);
427  void l2cap_connection_response(uint16_t handle, uint8_t rxid, uint8_t* dcid, uint8_t* scid, uint8_t result);
434  void l2cap_config_request(uint16_t handle, uint8_t rxid, uint8_t* dcid);
441  void l2cap_config_response(uint16_t handle, uint8_t rxid, uint8_t* scid);
449  void l2cap_disconnection_request(uint16_t handle, uint8_t rxid, uint8_t* dcid, uint8_t* scid);
457  void l2cap_disconnection_response(uint16_t handle, uint8_t rxid, uint8_t* dcid, uint8_t* scid);
464  void l2cap_information_response(uint16_t handle, uint8_t rxid, uint8_t infoTypeLow, uint8_t infoTypeHigh);
475 
477  const char* btdName;
479  const char* btdPin;
480 
482  uint8_t my_bdaddr[6];
484  uint16_t hci_handle;
486  uint8_t disc_bdaddr[6];
488  char remote_name[30];
494  uint8_t hci_version;
495 
498  pairWithWii = true;
499  hci_state = HCI_CHECK_DEVICE_SERVICE;
500  };
502  bool connectToWii;
511 
513  void pairWithHID() {
514  waitingForConnection = false;
515  pairWithHIDDevice = true;
516  hci_state = HCI_CHECK_DEVICE_SERVICE;
517  };
519  bool connectToHIDDevice;
524 
529  uint8_t readPollInterval() {
530  return pollInterval;
531  };
532 
534  bool useSimplePairing;
535 
536 protected:
540  uint8_t bAddress;
543 
545  uint8_t bConfNum;
547  uint8_t bNumEP;
549  uint32_t qNextPollTime;
550 
552  static const uint8_t BTD_CONTROL_PIPE;
554  static const uint8_t BTD_EVENT_PIPE;
556  static const uint8_t BTD_DATAIN_PIPE;
558  static const uint8_t BTD_DATAOUT_PIPE;
559 
565 
566 private:
567  void Initialize(); // Set all variables, endpoint structs etc. to default values
569 
570  uint16_t PID, VID; // PID and VID of device connected
571 
572  uint8_t pollInterval;
573  bool simple_pairing_supported;
574  bool bPollEnable;
575 
576  bool pairWiiUsingSync; // True if pairing was done using the Wii SYNC button.
577  bool checkRemoteName; // Used to check remote device's name before connecting.
578  bool incomingPS4; // True if a PS4 controller is connecting
579  uint8_t classOfDevice[3]; // Class of device of last device
580 
581  /* Variables used by high level HCI task */
582  uint8_t hci_state; // Current state of Bluetooth HCI connection
583  uint16_t hci_counter; // Counter used for Bluetooth HCI reset loops
584  uint16_t hci_num_reset_loops; // This value indicate how many times it should read before trying to reset
585  uint16_t hci_event_flag; // HCI flags of received Bluetooth events
586  uint8_t inquiry_counter;
587 
588  uint8_t hcibuf[BULK_MAXPKTSIZE]; // General purpose buffer for HCI data
589  uint8_t l2capinbuf[BULK_MAXPKTSIZE]; // General purpose buffer for L2CAP in data
590  uint8_t l2capoutbuf[14]; // General purpose buffer for L2CAP out data
591 
592  /* State machines */
593  void HCI_event_task(); // Poll the HCI event pipe
594  void HCI_task(); // HCI state machine
595  void ACL_event_task(); // ACL input pipe
596 
597  /* Used to set the Bluetooth Address internally to the PS3 Controllers */
598  void setBdaddr(uint8_t* BDADDR);
599  void setMoveBdaddr(uint8_t* BDADDR);
600 };
601 
604 public:
605  BluetoothService(BTD *p) : pBtd(p) {
606  if(pBtd)
607  pBtd->registerBluetoothService(this); // Register it as a Bluetooth service
608  };
613  virtual void ACLData(uint8_t* ACLData) = 0;
615  virtual void Run() = 0;
617  virtual void Reset() = 0;
619  virtual void disconnect() = 0;
620 
625  void attachOnInit(void (*funcOnInit)(void)) {
626  pFuncOnInit = funcOnInit; // TODO: This really belong in a class of it's own as it is repeated several times
627  };
628 
629 protected:
635  virtual void onInit() = 0;
636 
638  bool checkHciHandle(uint8_t *buf, uint16_t handle) {
639  return (buf[0] == (handle & 0xFF)) && (buf[1] == ((handle >> 8) | 0x20));
640  }
641 
643  void (*pFuncOnInit)(void);
644 
647 
649  uint16_t hci_handle;
650 
653 
655  uint8_t identifier;
656 };
657 
658 #endif
static const uint8_t BTD_DATAOUT_PIPE
Definition: BTD.h:558
+
bool incomingWii
Definition: BTD.h:504
+
bool useSimplePairing
Definition: BTD.h:531
+
void hci_connect()
Definition: BTD.cpp:1268
+
void hci_write_simple_pairing_mode(bool enable)
Definition: BTD.cpp:1237
+
uint8_t bNumEP
Definition: BTD.h:547
+
const char * btdName
Definition: BTD.h:477
+
void hci_reset()
Definition: BTD.cpp:1113
+
void l2cap_connection_response(uint16_t handle, uint8_t rxid, uint8_t *dcid, uint8_t *scid, uint8_t result)
Definition: BTD.cpp:1488
+
void l2cap_connection_request(uint16_t handle, uint8_t rxid, uint8_t *scid, uint16_t psm)
Definition: BTD.cpp:1475
+
bool sdpConnectionClaimed
Definition: BTD.h:472
+
Definition: BTD.h:221
+
int8_t registerBluetoothService(BluetoothService *pService)
Definition: BTD.h:320
+
void l2cap_disconnection_request(uint16_t handle, uint8_t rxid, uint8_t *dcid, uint8_t *scid)
Definition: BTD.cpp:1541
+
bool rfcommConnectionClaimed
Definition: BTD.h:474
+
uint8_t hci_version
Definition: BTD.h:494
+
bool waitingForConnection
Definition: BTD.h:468
+
void hci_inquiry()
Definition: BTD.cpp:1246
+
static const uint8_t BTD_EVENT_PIPE
Definition: BTD.h:554
#define PS3MOVE_PID
Definition: BTD.h:28
-
bool pairWithWii
Definition: BTD.h:476
-
uint8_t identifier
Definition: BTD.h:621
-
void hci_write_scan_disable()
Definition: BTD.cpp:975
+
bool pairWithWii
Definition: BTD.h:506
+
uint8_t identifier
Definition: BTD.h:655
+
void hci_write_scan_disable()
Definition: BTD.cpp:1135
#define BELKIN_F8T065BF_PID
Definition: BTD.h:34
-
void EndpointXtract(uint8_t conf, uint8_t iface, uint8_t alt, uint8_t proto, const USB_ENDPOINT_DESCRIPTOR *ep)
Definition: BTD.cpp:327
-
virtual bool VIDPIDOK(uint16_t vid, uint16_t pid)
Definition: BTD.h:269
-
virtual uint8_t GetAddress()
Definition: BTD.h:241
-
#define BTD_NUM_SERVICES
Definition: BTD.h:191
-
const char * btdPin
Definition: BTD.h:449
-
bool motionPlusInside
Definition: BTD.h:478
-
void hci_remote_name()
Definition: BTD.cpp:1018
+
void EndpointXtract(uint8_t conf, uint8_t iface, uint8_t alt, uint8_t proto, const USB_ENDPOINT_DESCRIPTOR *ep)
Definition: BTD.cpp:330
+
virtual bool VIDPIDOK(uint16_t vid, uint16_t pid)
Definition: BTD.h:289
+
virtual uint8_t GetAddress()
Definition: BTD.h:261
+
#define BTD_NUM_SERVICES
Definition: BTD.h:211
+
const char * btdPin
Definition: BTD.h:479
+
bool motionPlusInside
Definition: BTD.h:508
+
void hci_remote_name()
Definition: BTD.cpp:1188
#define BELKIN_F8T065BF_VID
Definition: BTD.h:33
#define PS3_VID
Definition: BTD.h:25
BTD(USB *p)
Definition: BTD.cpp:27
-
char remote_name[30]
Definition: BTD.h:458
-
uint8_t readPollInterval()
Definition: BTD.h:499
-
static const uint8_t BTD_DATAIN_PIPE
Definition: BTD.h:523
-
void hci_set_local_name(const char *name)
Definition: BTD.cpp:1037
-
void hci_write_scan_enable()
Definition: BTD.cpp:962
-
uint8_t Release()
Definition: BTD.cpp:376
-
void l2cap_disconnection_response(uint16_t handle, uint8_t rxid, uint8_t *dcid, uint8_t *scid)
Definition: BTD.cpp:1326
+
char remote_name[30]
Definition: BTD.h:488
+
uint8_t readPollInterval()
Definition: BTD.h:529
+
static const uint8_t BTD_DATAIN_PIPE
Definition: BTD.h:556
+
void hci_write_scan_enable()
Definition: BTD.cpp:1122
+
uint8_t Release()
Definition: BTD.cpp:379
+
void l2cap_disconnection_response(uint16_t handle, uint8_t rxid, uint8_t *dcid, uint8_t *scid)
Definition: BTD.cpp:1554
#define USB_CLASS_WIRELESS_CTRL
Definition: UsbCore.h:84
-
bool connectToHIDDevice
Definition: BTD.h:487
-
uint8_t bAddress
Definition: BTD.h:507
-
bool incomingHIDDevice
Definition: BTD.h:491
-
bool pairWithHIDDevice
Definition: BTD.h:493
-
uint32_t qNextPollTime
Definition: BTD.h:516
-
void PrintEndpointDescriptor(const USB_ENDPOINT_DESCRIPTOR *ep_ptr)
Definition: BTD.cpp:357
+
bool connectToHIDDevice
Definition: BTD.h:517
+
uint8_t bAddress
Definition: BTD.h:540
+
bool incomingHIDDevice
Definition: BTD.h:521
+
bool pairWithHIDDevice
Definition: BTD.h:523
+
uint32_t qNextPollTime
Definition: BTD.h:549
+
void PrintEndpointDescriptor(const USB_ENDPOINT_DESCRIPTOR *ep_ptr)
Definition: BTD.cpp:360
#define IOGEAR_GBU521_PID
Definition: BTD.h:32
-
bool connectToWii
Definition: BTD.h:470
-
uint8_t ConfigureDevice(uint8_t parent, uint8_t port, bool lowspeed)
Definition: BTD.cpp:48
-
bool wiiUProController
Definition: BTD.h:480
-
uint16_t hci_handle
Definition: BTD.h:454
-
uint8_t Init(uint8_t parent, uint8_t port, bool lowspeed)
Definition: BTD.cpp:134
+
bool connectToWii
Definition: BTD.h:500
+
uint8_t ConfigureDevice(uint8_t parent, uint8_t port, bool lowspeed)
Definition: BTD.cpp:50
+
bool wiiUProController
Definition: BTD.h:510
+
uint16_t hci_handle
Definition: BTD.h:484
+
uint8_t Init(uint8_t parent, uint8_t port, bool lowspeed)
Definition: BTD.cpp:136
Definition: address.h:39
-
void pairWithHID()
Definition: BTD.h:483
-
void hci_disconnect(uint16_t handle)
Definition: BTD.cpp:1171
- -
void hci_read_bdaddr()
Definition: BTD.cpp:984
-
void hci_inquiry_cancel()
Definition: BTD.cpp:1063
-
uint8_t my_bdaddr[6]
Definition: BTD.h:452
-
void attachOnInit(void(*funcOnInit)(void))
Definition: BTD.h:591
-
uint8_t Poll()
Definition: BTD.cpp:382
-
static const uint8_t BTD_CONTROL_PIPE
Definition: BTD.h:519
+
void pairWithHID()
Definition: BTD.h:513
+
void hci_disconnect(uint16_t handle)
Definition: BTD.cpp:1399
+ +
void hci_read_bdaddr()
Definition: BTD.cpp:1144
+
void hci_inquiry_cancel()
Definition: BTD.cpp:1260
+
uint8_t my_bdaddr[6]
Definition: BTD.h:482
+
void attachOnInit(void(*funcOnInit)(void))
Definition: BTD.h:625
+
void hci_read_local_extended_features(uint8_t page_number)
Definition: BTD.cpp:1162
+
uint8_t Poll()
Definition: BTD.cpp:385
+
static const uint8_t BTD_CONTROL_PIPE
Definition: BTD.h:552
+
void hci_write_local_name(const char *name)
Definition: BTD.cpp:1207
-
BTD * pBtd
Definition: BTD.h:612
+
BTD * pBtd
Definition: BTD.h:646
#define BULK_MAXPKTSIZE
Definition: BTD.h:37
-
void disconnect()
Definition: BTD.cpp:394
-
uint8_t disc_bdaddr[6]
Definition: BTD.h:456
-
bool l2capConnectionClaimed
Definition: BTD.h:440
-
EpInfo epInfo[BTD_MAX_ENDPOINTS]
Definition: BTD.h:509
+
void disconnect()
Definition: BTD.cpp:397
+
uint8_t disc_bdaddr[6]
Definition: BTD.h:486
+
bool l2capConnectionClaimed
Definition: BTD.h:470
+
EpInfo epInfo[BTD_MAX_ENDPOINTS]
Definition: BTD.h:542
#define IOGEAR_GBU521_VID
Definition: BTD.h:31
#define PS3_PID
Definition: BTD.h:26
-
#define BTD_MAX_ENDPOINTS
Definition: BTD.h:190
+
#define BTD_MAX_ENDPOINTS
Definition: BTD.h:210
#define PS3NAVIGATION_PID
Definition: BTD.h:27
-
void l2cap_information_response(uint16_t handle, uint8_t rxid, uint8_t infoTypeLow, uint8_t infoTypeHigh)
Definition: BTD.cpp:1339
-
BluetoothService(BTD *p)
Definition: BTD.h:571
+
void l2cap_information_response(uint16_t handle, uint8_t rxid, uint8_t infoTypeLow, uint8_t infoTypeHigh)
Definition: BTD.cpp:1567
+
BluetoothService(BTD *p)
Definition: BTD.h:605
-
void hci_write_class_of_device()
Definition: BTD.cpp:1183
-
uint16_t hci_handle
Definition: BTD.h:615
-
void hci_pin_code_negative_request_reply()
Definition: BTD.cpp:1133
-
virtual bool DEVCLASSOK(uint8_t klass)
Definition: BTD.h:258
-
uint32_t l2cap_event_flag
Definition: BTD.h:618
+
void hci_write_class_of_device()
Definition: BTD.cpp:1411
+
uint16_t hci_handle
Definition: BTD.h:649
+
void hci_pin_code_negative_request_reply()
Definition: BTD.cpp:1330
+
virtual bool DEVCLASSOK(uint8_t klass)
Definition: BTD.h:278
+
uint32_t l2cap_event_flag
Definition: BTD.h:652
#define HCI_CHECK_DEVICE_SERVICE
Definition: BTD.h:49
Definition: UsbCore.h:210
-
uint8_t bConfNum
Definition: BTD.h:512
-
void hci_link_key_request_negative_reply()
Definition: BTD.cpp:1147
-
void pairWithWiimote()
Definition: BTD.h:467
-
virtual bool isReady()
Definition: BTD.h:249
-
void L2CAP_Command(uint16_t handle, uint8_t *data, uint8_t nbytes, uint8_t channelLow=0x01, uint8_t channelHigh=0x00)
Definition: BTD.cpp:1219
-
void l2cap_config_response(uint16_t handle, uint8_t rxid, uint8_t *scid)
Definition: BTD.cpp:1294
-
void l2cap_config_request(uint16_t handle, uint8_t rxid, uint8_t *dcid)
Definition: BTD.cpp:1277
-
void hci_pin_code_request_reply()
Definition: BTD.cpp:1097
-
USB * pUsb
Definition: BTD.h:501
-
void hci_authentication_request()
Definition: BTD.cpp:1161
-
void hci_read_local_version_information()
Definition: BTD.cpp:993
-
void hci_accept_connection()
Definition: BTD.cpp:1002
-
bool checkHciHandle(uint8_t *buf, uint16_t handle)
Definition: BTD.h:604
-
void HCI_Command(uint8_t *data, uint16_t nbytes)
Definition: BTD.cpp:948
+
uint8_t bConfNum
Definition: BTD.h:545
+
void hci_link_key_request_negative_reply()
Definition: BTD.cpp:1344
+
void pairWithWiimote()
Definition: BTD.h:497
+
virtual bool isReady()
Definition: BTD.h:269
+
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
+
void l2cap_config_request(uint16_t handle, uint8_t rxid, uint8_t *dcid)
Definition: BTD.cpp:1505
+
void hci_pin_code_request_reply()
Definition: BTD.cpp:1294
+
USB * pUsb
Definition: BTD.h:538
+
void hci_authentication_request()
Definition: BTD.cpp:1389
+
void hci_read_local_version_information()
Definition: BTD.cpp:1153
+
void hci_accept_connection()
Definition: BTD.cpp:1172
+
bool checkHciHandle(uint8_t *buf, uint16_t handle)
Definition: BTD.h:638
+
void hci_set_event_mask()
Definition: BTD.cpp:1219
+
void hci_io_capability_request_reply()
Definition: BTD.cpp:1358
+
void hci_user_confirmation_request_reply()
Definition: BTD.cpp:1375
+
void HCI_Command(uint8_t *data, uint16_t nbytes)
Definition: BTD.cpp:1108
-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  control_dcid[0] = 0x70; // 0x0070
34  control_dcid[1] = 0x00;
35  interrupt_dcid[0] = 0x71; // 0x0071
36  interrupt_dcid[1] = 0x00;
37 
38  Reset();
39 }
40 
41 void BTHID::Reset() {
42  connected = false;
43  activeConnection = false;
44  l2cap_event_flag = 0; // Reset flags
45  l2cap_state = L2CAP_WAIT;
46  ResetBTHID();
47 }
48 
49 void BTHID::disconnect() { // Use this void to disconnect the device
50  // First the HID interrupt channel has to be disconnected, then the HID control channel and finally the HCI connection
52  Reset();
53  l2cap_state = L2CAP_INTERRUPT_DISCONNECT;
54 }
55 
56 void BTHID::ACLData(uint8_t* l2capinbuf) {
57  if(!pBtd->l2capConnectionClaimed && pBtd->incomingHIDDevice && !connected && !activeConnection) {
58  if(l2capinbuf[8] == L2CAP_CMD_CONNECTION_REQUEST) {
59  if((l2capinbuf[12] | (l2capinbuf[13] << 8)) == HID_CTRL_PSM) {
60  pBtd->incomingHIDDevice = false;
61  pBtd->l2capConnectionClaimed = true; // Claim that the incoming connection belongs to this service
62  activeConnection = true;
63  hci_handle = pBtd->hci_handle; // Store the HCI Handle for the connection
64  l2cap_state = L2CAP_WAIT;
65  }
66  }
67  }
68 
69  if(checkHciHandle(l2capinbuf, hci_handle)) { // acl_handle_ok
70  if((l2capinbuf[6] | (l2capinbuf[7] << 8)) == 0x0001U) { // l2cap_control - Channel ID for ACL-U
71  if(l2capinbuf[8] == L2CAP_CMD_COMMAND_REJECT) {
72 #ifdef DEBUG_USB_HOST
73  Notify(PSTR("\r\nL2CAP Command Rejected - Reason: "), 0x80);
74  D_PrintHex<uint8_t > (l2capinbuf[13], 0x80);
75  Notify(PSTR(" "), 0x80);
76  D_PrintHex<uint8_t > (l2capinbuf[12], 0x80);
77  Notify(PSTR(" "), 0x80);
78  D_PrintHex<uint8_t > (l2capinbuf[17], 0x80);
79  Notify(PSTR(" "), 0x80);
80  D_PrintHex<uint8_t > (l2capinbuf[16], 0x80);
81  Notify(PSTR(" "), 0x80);
82  D_PrintHex<uint8_t > (l2capinbuf[15], 0x80);
83  Notify(PSTR(" "), 0x80);
84  D_PrintHex<uint8_t > (l2capinbuf[14], 0x80);
85 #endif
86  } else if(l2capinbuf[8] == L2CAP_CMD_CONNECTION_RESPONSE) {
87  if(((l2capinbuf[16] | (l2capinbuf[17] << 8)) == 0x0000) && ((l2capinbuf[18] | (l2capinbuf[19] << 8)) == SUCCESSFUL)) { // Success
88  if(l2capinbuf[14] == control_dcid[0] && l2capinbuf[15] == control_dcid[1]) {
89  //Notify(PSTR("\r\nHID Control Connection Complete"), 0x80);
90  identifier = l2capinbuf[9];
91  control_scid[0] = l2capinbuf[12];
92  control_scid[1] = l2capinbuf[13];
94  } else if(l2capinbuf[14] == interrupt_dcid[0] && l2capinbuf[15] == interrupt_dcid[1]) {
95  //Notify(PSTR("\r\nHID Interrupt Connection Complete"), 0x80);
96  identifier = l2capinbuf[9];
97  interrupt_scid[0] = l2capinbuf[12];
98  interrupt_scid[1] = l2capinbuf[13];
100  }
101  }
102  } else if(l2capinbuf[8] == L2CAP_CMD_CONNECTION_REQUEST) {
103 #ifdef EXTRADEBUG
104  Notify(PSTR("\r\nL2CAP Connection Request - PSM: "), 0x80);
105  D_PrintHex<uint8_t > (l2capinbuf[13], 0x80);
106  Notify(PSTR(" "), 0x80);
107  D_PrintHex<uint8_t > (l2capinbuf[12], 0x80);
108  Notify(PSTR(" SCID: "), 0x80);
109  D_PrintHex<uint8_t > (l2capinbuf[15], 0x80);
110  Notify(PSTR(" "), 0x80);
111  D_PrintHex<uint8_t > (l2capinbuf[14], 0x80);
112  Notify(PSTR(" Identifier: "), 0x80);
113  D_PrintHex<uint8_t > (l2capinbuf[9], 0x80);
114 #endif
115  if((l2capinbuf[12] | (l2capinbuf[13] << 8)) == HID_CTRL_PSM) {
116  identifier = l2capinbuf[9];
117  control_scid[0] = l2capinbuf[14];
118  control_scid[1] = l2capinbuf[15];
120  } else if((l2capinbuf[12] | (l2capinbuf[13] << 8)) == HID_INTR_PSM) {
121  identifier = l2capinbuf[9];
122  interrupt_scid[0] = l2capinbuf[14];
123  interrupt_scid[1] = l2capinbuf[15];
125  }
126  } else if(l2capinbuf[8] == L2CAP_CMD_CONFIG_RESPONSE) {
127  if((l2capinbuf[16] | (l2capinbuf[17] << 8)) == 0x0000) { // Success
128  if(l2capinbuf[12] == control_dcid[0] && l2capinbuf[13] == control_dcid[1]) {
129  //Notify(PSTR("\r\nHID Control Configuration Complete"), 0x80);
130  identifier = l2capinbuf[9];
132  } else if(l2capinbuf[12] == interrupt_dcid[0] && l2capinbuf[13] == interrupt_dcid[1]) {
133  //Notify(PSTR("\r\nHID Interrupt Configuration Complete"), 0x80);
134  identifier = l2capinbuf[9];
136  }
137  }
138  } else if(l2capinbuf[8] == L2CAP_CMD_CONFIG_REQUEST) {
139  if(l2capinbuf[12] == control_dcid[0] && l2capinbuf[13] == control_dcid[1]) {
140  //Notify(PSTR("\r\nHID Control Configuration Request"), 0x80);
142  } else if(l2capinbuf[12] == interrupt_dcid[0] && l2capinbuf[13] == interrupt_dcid[1]) {
143  //Notify(PSTR("\r\nHID Interrupt Configuration Request"), 0x80);
145  }
146  } else if(l2capinbuf[8] == L2CAP_CMD_DISCONNECT_REQUEST) {
147  if(l2capinbuf[12] == control_dcid[0] && l2capinbuf[13] == control_dcid[1]) {
148 #ifdef DEBUG_USB_HOST
149  Notify(PSTR("\r\nDisconnect Request: Control Channel"), 0x80);
150 #endif
151  identifier = l2capinbuf[9];
153  Reset();
154  } else if(l2capinbuf[12] == interrupt_dcid[0] && l2capinbuf[13] == interrupt_dcid[1]) {
155 #ifdef DEBUG_USB_HOST
156  Notify(PSTR("\r\nDisconnect Request: Interrupt Channel"), 0x80);
157 #endif
158  identifier = l2capinbuf[9];
160  Reset();
161  }
162  } else if(l2capinbuf[8] == L2CAP_CMD_DISCONNECT_RESPONSE) {
163  if(l2capinbuf[12] == control_scid[0] && l2capinbuf[13] == control_scid[1]) {
164  //Notify(PSTR("\r\nDisconnect Response: Control Channel"), 0x80);
165  identifier = l2capinbuf[9];
167  } else if(l2capinbuf[12] == interrupt_scid[0] && l2capinbuf[13] == interrupt_scid[1]) {
168  //Notify(PSTR("\r\nDisconnect Response: Interrupt Channel"), 0x80);
169  identifier = l2capinbuf[9];
171  }
172  }
173 #ifdef EXTRADEBUG
174  else {
175  identifier = l2capinbuf[9];
176  Notify(PSTR("\r\nL2CAP Unknown Signaling Command: "), 0x80);
177  D_PrintHex<uint8_t > (l2capinbuf[8], 0x80);
178  }
179 #endif
180  } else if(l2capinbuf[6] == interrupt_dcid[0] && l2capinbuf[7] == interrupt_dcid[1]) { // l2cap_interrupt
181 #ifdef PRINTREPORT
182  Notify(PSTR("\r\nL2CAP Interrupt: "), 0x80);
183  for(uint16_t i = 0; i < ((uint16_t)l2capinbuf[5] << 8 | l2capinbuf[4]); i++) {
184  D_PrintHex<uint8_t > (l2capinbuf[i + 8], 0x80);
185  Notify(PSTR(" "), 0x80);
186  }
187 #endif
188  if(l2capinbuf[8] == 0xA1) { // HID_THDR_DATA_INPUT
189  uint16_t length = ((uint16_t)l2capinbuf[5] << 8 | l2capinbuf[4]);
190  ParseBTHIDData((uint8_t)(length - 1), &l2capinbuf[9]);
191 
192  switch(l2capinbuf[9]) {
193  case 0x01: // Keyboard or Joystick events
194  if(pRptParser[KEYBOARD_PARSER_ID])
195  pRptParser[KEYBOARD_PARSER_ID]->Parse(reinterpret_cast<USBHID *>(this), 0, (uint8_t)(length - 2), &l2capinbuf[10]); // Use reinterpret_cast again to extract the instance
196  break;
197 
198  case 0x02: // Mouse events
199  if(pRptParser[MOUSE_PARSER_ID])
200  pRptParser[MOUSE_PARSER_ID]->Parse(reinterpret_cast<USBHID *>(this), 0, (uint8_t)(length - 2), &l2capinbuf[10]); // Use reinterpret_cast again to extract the instance
201  break;
202 #ifdef EXTRADEBUG
203  default:
204  Notify(PSTR("\r\nUnknown Report type: "), 0x80);
205  D_PrintHex<uint8_t > (l2capinbuf[9], 0x80);
206  break;
207 #endif
208  }
209  }
210  } else if(l2capinbuf[6] == control_dcid[0] && l2capinbuf[7] == control_dcid[1]) { // l2cap_control
211 #ifdef PRINTREPORT
212  Notify(PSTR("\r\nL2CAP Control: "), 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 #endif
218  }
219 #ifdef EXTRADEBUG
220  else {
221  Notify(PSTR("\r\nUnsupported L2CAP Data - Channel ID: "), 0x80);
222  D_PrintHex<uint8_t > (l2capinbuf[7], 0x80);
223  Notify(PSTR(" "), 0x80);
224  D_PrintHex<uint8_t > (l2capinbuf[6], 0x80);
225 
226  Notify(PSTR("\r\nData: "), 0x80);
227  Notify(PSTR("\r\n"), 0x80);
228  for(uint16_t i = 0; i < ((uint16_t)l2capinbuf[5] << 8 | l2capinbuf[4]); i++) {
229  D_PrintHex<uint8_t > (l2capinbuf[i + 8], 0x80);
230  Notify(PSTR(" "), 0x80);
231  }
232  }
233 #endif
234  L2CAP_task();
235  }
236 }
237 
238 void BTHID::L2CAP_task() {
239  switch(l2cap_state) {
240  /* These states are used if the HID device is the host */
243 #ifdef DEBUG_USB_HOST
244  Notify(PSTR("\r\nHID Control Successfully Configured"), 0x80);
245 #endif
246  setProtocol(); // Set protocol before establishing HID interrupt channel
247  l2cap_state = L2CAP_INTERRUPT_SETUP;
248  }
249  break;
250 
253 #ifdef DEBUG_USB_HOST
254  Notify(PSTR("\r\nHID Interrupt Incoming Connection Request"), 0x80);
255 #endif
257  delay(1);
259  identifier++;
260  delay(1);
262 
263  l2cap_state = L2CAP_INTERRUPT_CONFIG_REQUEST;
264  }
265  break;
266 
267  /* These states are used if the Arduino is the host */
270 #ifdef DEBUG_USB_HOST
271  Notify(PSTR("\r\nSend HID Control Config Request"), 0x80);
272 #endif
273  identifier++;
275  l2cap_state = L2CAP_CONTROL_CONFIG_REQUEST;
276  }
277  break;
278 
281  setProtocol(); // Set protocol before establishing HID interrupt channel
282  delay(1); // Short delay between commands - just to be sure
283 #ifdef DEBUG_USB_HOST
284  Notify(PSTR("\r\nSend HID Interrupt Connection Request"), 0x80);
285 #endif
286  identifier++;
288  l2cap_state = L2CAP_INTERRUPT_CONNECT_REQUEST;
289  }
290  break;
291 
294 #ifdef DEBUG_USB_HOST
295  Notify(PSTR("\r\nSend HID Interrupt Config Request"), 0x80);
296 #endif
297  identifier++;
299  l2cap_state = L2CAP_INTERRUPT_CONFIG_REQUEST;
300  }
301  break;
302 
304  if(l2cap_check_flag(L2CAP_FLAG_CONFIG_INTERRUPT_SUCCESS)) { // Now the HID channels is established
305 #ifdef DEBUG_USB_HOST
306  Notify(PSTR("\r\nHID Channels Established"), 0x80);
307 #endif
308  pBtd->connectToHIDDevice = false;
309  pBtd->pairWithHIDDevice = false;
310  connected = true;
311  onInit();
312  l2cap_state = L2CAP_DONE;
313  }
314  break;
315 
316  case L2CAP_DONE:
317  break;
318 
321 #ifdef DEBUG_USB_HOST
322  Notify(PSTR("\r\nDisconnected Interrupt Channel"), 0x80);
323 #endif
324  identifier++;
326  l2cap_state = L2CAP_CONTROL_DISCONNECT;
327  }
328  break;
329 
332 #ifdef DEBUG_USB_HOST
333  Notify(PSTR("\r\nDisconnected Control Channel"), 0x80);
334 #endif
336  hci_handle = -1; // Reset handle
337  l2cap_event_flag = 0; // Reset flags
338  l2cap_state = L2CAP_WAIT;
339  }
340  break;
341  }
342 }
343 
344 void BTHID::Run() {
345  switch(l2cap_state) {
346  case L2CAP_WAIT:
347  if(pBtd->connectToHIDDevice && !pBtd->l2capConnectionClaimed && !connected && !activeConnection) {
349  activeConnection = true;
350 #ifdef DEBUG_USB_HOST
351  Notify(PSTR("\r\nSend HID Control Connection Request"), 0x80);
352 #endif
353  hci_handle = pBtd->hci_handle; // Store the HCI Handle for the connection
354  l2cap_event_flag = 0; // Reset flags
355  identifier = 0;
357  l2cap_state = L2CAP_CONTROL_CONNECT_REQUEST;
359 #ifdef DEBUG_USB_HOST
360  Notify(PSTR("\r\nHID Control Incoming Connection Request"), 0x80);
361 #endif
363  delay(1);
365  identifier++;
366  delay(1);
368  l2cap_state = L2CAP_CONTROL_SUCCESS;
369  }
370  break;
371  }
372 }
373 
374 /************************************************************/
375 /* HID Commands */
376 
377 /************************************************************/
378 void BTHID::setProtocol() {
379 #ifdef DEBUG_USB_HOST
380  Notify(PSTR("\r\nSet protocol mode: "), 0x80);
381  D_PrintHex<uint8_t > (protocolMode, 0x80);
382 #endif
383  if (protocolMode != USB_HID_BOOT_PROTOCOL && protocolMode != HID_RPT_PROTOCOL) {
384 #ifdef DEBUG_USB_HOST
385  Notify(PSTR("\r\nNot a valid protocol mode. Using Boot protocol instead."), 0x80);
386 #endif
387  protocolMode = USB_HID_BOOT_PROTOCOL; // Use Boot Protocol by default
388  }
389  uint8_t command = 0x70 | protocolMode; // Set Protocol, see Bluetooth HID specs page 33
390  pBtd->L2CAP_Command(hci_handle, &command, 1, control_scid[0], control_scid[1]);
391 }
392 
393 void BTHID::setLeds(uint8_t data) {
394  uint8_t buf[3];
395  buf[0] = 0xA2; // HID BT DATA_request (0xA0) | Report Type (Output 0x02)
396  buf[1] = 0x01; // Report ID
397  buf[2] = data;
399 }
#define L2CAP_FLAG_DISCONNECT_CONTROL_RESPONSE
Definition: BTD.h:140
-
#define L2CAP_FLAG_CONFIG_INTERRUPT_SUCCESS
Definition: BTD.h:144
-
#define L2CAP_INTERRUPT_CONFIG_REQUEST
Definition: BTD.h:116
-
#define L2CAP_INTERRUPT_SETUP
Definition: BTD.h:114
-
void l2cap_connection_response(uint16_t handle, uint8_t rxid, uint8_t *dcid, uint8_t *scid, uint8_t result)
Definition: BTD.cpp:1260
-
#define SUCCESSFUL
Definition: BTD.h:178
-
void ACLData(uint8_t *ACLData)
Definition: BTHID.cpp:56
-
void l2cap_connection_request(uint16_t handle, uint8_t rxid, uint8_t *scid, uint16_t psm)
Definition: BTD.cpp:1247
-
#define L2CAP_FLAG_CONNECTION_INTERRUPT_REQUEST
Definition: BTD.h:143
-
Definition: BTD.h:201
-
void l2cap_disconnection_request(uint16_t handle, uint8_t rxid, uint8_t *dcid, uint8_t *scid)
Definition: BTD.cpp:1313
+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:621
+
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
-
void Run()
Definition: BTHID.cpp:344
-
const char * btdPin
Definition: BTD.h:449
-
#define L2CAP_DONE
Definition: BTD.h:105
-
#define L2CAP_CONTROL_SUCCESS
Definition: BTD.h:110
-
#define L2CAP_WAIT
Definition: BTD.h:104
+
#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
-
void Reset()
Definition: BTHID.cpp:41
-
#define L2CAP_CONTROL_CONFIG_REQUEST
Definition: BTD.h:109
-
void l2cap_disconnection_response(uint16_t handle, uint8_t rxid, uint8_t *dcid, uint8_t *scid)
Definition: BTD.cpp:1326
+
#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:487
-
#define L2CAP_CONTROL_CONNECT_REQUEST
Definition: BTD.h:108
-
#define HID_CTRL_PSM
Definition: BTD.h:183
-
bool incomingHIDDevice
Definition: BTD.h:491
-
bool pairWithHIDDevice
Definition: BTD.h:493
+
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:454
+
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:1171
- -
#define L2CAP_FLAG_DISCONNECT_INTERRUPT_RESPONSE
Definition: BTD.h:146
-
void disconnect()
Definition: BTHID.cpp:49
+
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_check_flag(flag)
Definition: BTD.h:161
-
#define L2CAP_CMD_CONFIG_REQUEST
Definition: BTD.h:169
-
#define L2CAP_FLAG_CONTROL_CONNECTED
Definition: BTD.h:139
+
#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:171
-
#define L2CAP_CONTROL_DISCONNECT
Definition: BTD.h:111
-
#define L2CAP_FLAG_CONNECTION_CONTROL_REQUEST
Definition: BTD.h:137
-
BTD * pBtd
Definition: BTD.h:612
-
#define HID_INTR_PSM
Definition: BTD.h:184
-
bool l2capConnectionClaimed
Definition: BTD.h:440
-
#define L2CAP_CMD_DISCONNECT_RESPONSE
Definition: BTD.h:172
-
#define L2CAP_CMD_CONNECTION_RESPONSE
Definition: BTD.h:168
-
#define L2CAP_CMD_CONFIG_RESPONSE
Definition: BTD.h:170
+
#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:615
+
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:618
+
uint32_t l2cap_event_flag
Definition: BTD.h:652
void onInit()
Definition: BTHID.h:112
-
void L2CAP_Command(uint16_t handle, uint8_t *data, uint8_t nbytes, uint8_t channelLow=0x01, uint8_t channelHigh=0x00)
Definition: BTD.cpp:1219
-
void l2cap_config_response(uint16_t handle, uint8_t rxid, uint8_t *scid)
Definition: BTD.cpp:1294
-
#define PENDING
Definition: BTD.h:177
-
#define L2CAP_FLAG_INTERRUPT_CONNECTED
Definition: BTD.h:145
-
#define l2cap_set_flag(flag)
Definition: BTD.h:162
-
void l2cap_config_request(uint16_t handle, uint8_t rxid, uint8_t *dcid)
Definition: BTD.cpp:1277
-
#define L2CAP_FLAG_CONFIG_CONTROL_SUCCESS
Definition: BTD.h:138
-
#define L2CAP_CMD_CONNECTION_REQUEST
Definition: BTD.h:167
+
#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
-
bool checkHciHandle(uint8_t *buf, uint16_t handle)
Definition: BTD.h:604
-
#define L2CAP_INTERRUPT_CONNECT_REQUEST
Definition: BTD.h:115
+
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:117
-
#define L2CAP_CMD_COMMAND_REJECT
Definition: BTD.h:166
+
#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
+ diff --git a/_b_t_h_i_d_8h__dep__incl.map b/_b_t_h_i_d_8h__dep__incl.map index 1b72a609..953e5981 100644 --- a/_b_t_h_i_d_8h__dep__incl.map +++ b/_b_t_h_i_d_8h__dep__incl.map @@ -1,4 +1,5 @@ + diff --git a/_b_t_h_i_d_8h__dep__incl.md5 b/_b_t_h_i_d_8h__dep__incl.md5 index 053bda1f..33bd7539 100644 --- a/_b_t_h_i_d_8h__dep__incl.md5 +++ b/_b_t_h_i_d_8h__dep__incl.md5 @@ -1 +1 @@ -0205aeed5db75f7b218ba6ecd920ddcd \ No newline at end of file +f1f4d069fb346aadbae9c219f4a36799 \ No newline at end of file diff --git a/_b_t_h_i_d_8h__dep__incl.png b/_b_t_h_i_d_8h__dep__incl.png index 6ad24e96bab3916ba9ff116b6291672d8f8d4b22..7db4b80b92ff3c9a1c06dce51b62a74570ceb5bc 100644 GIT binary patch literal 4933 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 diff --git a/_b_t_h_i_d_8h_source.html b/_b_t_h_i_d_8h_source.html index fe0e0279..c05d80c1 100644 --- a/_b_t_h_i_d_8h_source.html +++ b/_b_t_h_i_d_8h_source.html @@ -86,25 +86,27 @@ var searchBox = new SearchBox("searchBox", "search",false,'Search');
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  };
129  virtual void OnInitBTHID() {
130  return;
131  };
133  virtual void ResetBTHID() {
134  return;
135  }
139  uint8_t control_scid[2];
140 
142  uint8_t interrupt_scid[2];
143 
144 private:
145  HIDReportParser *pRptParser[NUM_PARSERS]; // Pointer to HIDReportParsers.
146 
148  void setProtocol();
149  uint8_t protocolMode;
150 
151  void L2CAP_task(); // L2CAP state machine
152 
153  bool activeConnection; // Used to indicate if it already has established a connection
154 
155  /* Variables used for L2CAP communication */
156  uint8_t control_dcid[2]; // L2CAP device CID for HID_Control - Always 0x0070
157  uint8_t interrupt_dcid[2]; // L2CAP device CID for HID_Interrupt - Always 0x0071
158  uint8_t l2cap_state;
159 };
160 #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 
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  };
129  virtual void OnInitBTHID() {
130  return;
131  };
133  virtual void ResetBTHID() {
134  return;
135  }
139  uint8_t control_scid[2];
140 
142  uint8_t interrupt_scid[2];
143 
145  uint8_t sdp_scid[2]; // L2CAP source CID for SDP
146 
147 private:
148  HIDReportParser *pRptParser[NUM_PARSERS]; // Pointer to HIDReportParsers.
149 
150  uint8_t l2capoutbuf[BULK_MAXPKTSIZE]; // General purpose buffer for l2cap out data
151  void SDP_Command(uint8_t* data, uint8_t nbytes);
152  void serviceNotSupported(uint8_t transactionIDHigh, uint8_t transactionIDLow);
153 
155  void setProtocol();
156  uint8_t protocolMode;
157 
158  void SDP_task();
159  void L2CAP_task(); // L2CAP state machine
160 
161  bool activeConnection; // Used to indicate if it already has established a connection
162  bool SDPConnected;
163 
164  /* Variables used for L2CAP communication */
165  uint8_t control_dcid[2]; // L2CAP device CID for HID_Control - Always 0x0070
166  uint8_t interrupt_dcid[2]; // L2CAP device CID for HID_Interrupt - Always 0x0071
167  uint8_t sdp_dcid[2];
168  uint8_t l2cap_state;
169 };
170 #endif
virtual void OnInitBTHID()
Definition: BTHID.h:129
-
void ACLData(uint8_t *ACLData)
Definition: BTHID.cpp:56
-
Definition: BTD.h:201
+
void ACLData(uint8_t *ACLData)
Definition: BTHID.cpp:63
+
Definition: BTD.h:221
uint8_t interrupt_scid[2]
Definition: BTHID.h:142
bool connected
Definition: BTHID.h:88
-
void Run()
Definition: BTHID.cpp:344
+
void Run()
Definition: BTHID.cpp:544
virtual void ResetBTHID()
Definition: BTHID.h:133
-
void Reset()
Definition: BTHID.cpp:41
+
void Reset()
Definition: BTHID.cpp:43
uint8_t control_scid[2]
Definition: BTHID.h:139
-
void pairWithHID()
Definition: BTD.h:483
- -
void disconnect()
Definition: BTHID.cpp:49
+
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
-
void(* pFuncOnInit)(void)
Definition: BTD.h:609
-
BTD * pBtd
Definition: BTD.h:612
+
void(* pFuncOnInit)(void)
Definition: BTD.h:643
+
BTD * pBtd
Definition: BTD.h:646
+
#define BULK_MAXPKTSIZE
Definition: BTD.h:37
void setLeds(struct KBDLEDS data)
Definition: BTHID.h:81
+
uint8_t sdp_scid[2]
Definition: BTHID.h:145
#define NUM_PARSERS
Definition: BTHID.h:26
void onInit()
Definition: BTHID.h:112
@@ -112,6 +114,7 @@ var searchBox = new SearchBox("searchBox", "search",false,'Search');
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:144
void pair(void)
Definition: BTHID.h:91
bool SetReportParser(uint8_t id, HIDReportParser *prs)
Definition: BTHID.h:61
diff --git a/_p_s3_b_t_8cpp_source.html b/_p_s3_b_t_8cpp_source.html index a155fb5b..e076c6f9 100644 --- a/_p_s3_b_t_8cpp_source.html +++ b/_p_s3_b_t_8cpp_source.html @@ -86,146 +86,146 @@ var searchBox = new SearchBox("searchBox", "search",false,'Search');
PS3BT.cpp
-Go to the documentation of this file.
1 /* Copyright (C) 2012 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 "PS3BT.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 PS3 Controllers
22 
23 PS3BT::PS3BT(BTD *p, uint8_t btadr5, uint8_t btadr4, uint8_t btadr3, uint8_t btadr2, uint8_t btadr1, uint8_t btadr0) :
24 BluetoothService(p) // Pointer to USB class instance - mandatory
25 {
26  pBtd->my_bdaddr[5] = btadr5; // Change to your dongle's Bluetooth address instead
27  pBtd->my_bdaddr[4] = btadr4;
28  pBtd->my_bdaddr[3] = btadr3;
29  pBtd->my_bdaddr[2] = btadr2;
30  pBtd->my_bdaddr[1] = btadr1;
31  pBtd->my_bdaddr[0] = btadr0;
32 
33  HIDBuffer[0] = 0x52; // HID BT Set_report (0x50) | Report Type (Output 0x02)
34  HIDBuffer[1] = 0x01; // Report ID
35 
36  // Needed for PS3 Move Controller commands to work via bluetooth
37  HIDMoveBuffer[0] = 0xA2; // HID BT DATA_request (0xA0) | Report Type (Output 0x02)
38  HIDMoveBuffer[1] = 0x02; // Report ID
39 
40  /* Set device cid for the control and intterrupt channelse - LSB */
41  control_dcid[0] = 0x40; // 0x0040
42  control_dcid[1] = 0x00;
43  interrupt_dcid[0] = 0x41; // 0x0041
44  interrupt_dcid[1] = 0x00;
45 
46  Reset();
47 }
48 
50  return (ButtonState & pgm_read_dword(&PS3_BUTTONS[(uint8_t)b]));
51 }
52 
54  uint32_t button = pgm_read_dword(&PS3_BUTTONS[(uint8_t)b]);
55  bool click = (ButtonClickState & button);
56  ButtonClickState &= ~button; // Clear "click" event
57  return click;
58 }
59 
61  return (uint8_t)(l2capinbuf[pgm_read_byte(&PS3_ANALOG_BUTTONS[(uint8_t)a])]);
62 }
63 
65  return (uint8_t)(l2capinbuf[(uint8_t)a + 15]);
66 }
67 
69  if(PS3Connected) {
70  if(a == aX || a == aY || a == aZ || a == gZ)
71  return ((l2capinbuf[(uint16_t)a] << 8) | l2capinbuf[(uint16_t)a + 1]);
72  else
73  return 0;
74  } else if(PS3MoveConnected) {
75  if(a == mXmove || a == mYmove) // These are all 12-bits long
76  return (((l2capinbuf[(uint16_t)a] & 0x0F) << 8) | (l2capinbuf[(uint16_t)a + 1]));
77  else if(a == mZmove || a == tempMove) // The tempearature is also 12 bits long
78  return ((l2capinbuf[(uint16_t)a] << 4) | ((l2capinbuf[(uint16_t)a + 1] & 0xF0) >> 4));
79  else // aXmove, aYmove, aZmove, gXmove, gYmove and gZmove
80  return (l2capinbuf[(uint16_t)a] | (l2capinbuf[(uint16_t)a + 1] << 8));
81  } else
82  return 0;
83 }
84 
86  float accXval, accYval, accZval;
87 
88  if(PS3Connected) {
89  // Data for the Kionix KXPC4 used in the DualShock 3
90  const float zeroG = 511.5f; // 1.65/3.3*1023 (1.65V)
91  accXval = -((float)getSensor(aX) - zeroG);
92  accYval = -((float)getSensor(aY) - zeroG);
93  accZval = -((float)getSensor(aZ) - zeroG);
94  } else if(PS3MoveConnected) {
95  // It's a Kionix KXSC4 inside the Motion controller
96  const uint16_t zeroG = 0x8000;
97  accXval = -(int16_t)(getSensor(aXmove) - zeroG);
98  accYval = (int16_t)(getSensor(aYmove) - zeroG);
99  accZval = (int16_t)(getSensor(aZmove) - zeroG);
100  } else
101  return 0;
102 
103  // Convert to 360 degrees resolution
104  // atan2 outputs the value of -Ï€ to Ï€ (radians)
105  // We are then converting it to 0 to 2Ï€ and then to degrees
106  if(a == Pitch)
107  return (atan2f(accYval, accZval) + PI) * RAD_TO_DEG;
108  else
109  return (atan2f(accXval, accZval) + PI) * RAD_TO_DEG;
110 }
111 
112 float PS3BT::get9DOFValues(SensorEnum a) { // Thanks to Manfred Piendl
113  if(!PS3MoveConnected)
114  return 0;
115  int16_t value = getSensor(a);
116  if(a == mXmove || a == mYmove || a == mZmove) {
117  if(value > 2047)
118  value -= 0x1000;
119  return (float)value / 3.2f; // unit: muT = 10^(-6) Tesla
120  } else if(a == aXmove || a == aYmove || a == aZmove) {
121  if(value < 0)
122  value += 0x8000;
123  else
124  value -= 0x8000;
125  return (float)value / 442.0f; // unit: m/(s^2)
126  } else if(a == gXmove || a == gYmove || a == gZmove) {
127  if(value < 0)
128  value += 0x8000;
129  else
130  value -= 0x8000;
131  if(a == gXmove)
132  return (float)value / 11.6f; // unit: deg/s
133  else if(a == gYmove)
134  return (float)value / 11.2f; // unit: deg/s
135  else // gZmove
136  return (float)value / 9.6f; // unit: deg/s
137  } else
138  return 0;
139 }
140 
142  if(PS3MoveConnected) {
143  int16_t input = getSensor(tempMove);
144 
145  String output = String(input / 100);
146  output += ".";
147  if(input % 100 < 10)
148  output += "0";
149  output += String(input % 100);
150 
151  return output;
152  } else
153  return "Error";
154 }
155 
157  return (l2capinbuf[(uint16_t)c >> 8] == ((uint8_t)c & 0xff));
158 }
159 
161  char statusOutput[102]; // Max string length plus null character
163  strcpy_P(statusOutput, PSTR("\r\nConnectionStatus: "));
164 
165  if(getStatus(Plugged)) strcat_P(statusOutput, PSTR("Plugged"));
166  else if(getStatus(Unplugged)) strcat_P(statusOutput, PSTR("Unplugged"));
167  else strcat_P(statusOutput, PSTR("Error"));
168 
169  strcat_P(statusOutput, PSTR(" - PowerRating: "));
170 
171  if(getStatus(Charging)) strcat_P(statusOutput, PSTR("Charging"));
172  else if(getStatus(NotCharging)) strcat_P(statusOutput, PSTR("Not Charging"));
173  else if(getStatus(Shutdown)) strcat_P(statusOutput, PSTR("Shutdown"));
174  else if(getStatus(Dying)) strcat_P(statusOutput, PSTR("Dying"));
175  else if(getStatus(Low)) strcat_P(statusOutput, PSTR("Low"));
176  else if(getStatus(High)) strcat_P(statusOutput, PSTR("High"));
177  else if(getStatus(Full)) strcat_P(statusOutput, PSTR("Full"));
178  else strcat_P(statusOutput, PSTR("Error"));
179 
180  strcat_P(statusOutput, PSTR(" - WirelessStatus: "));
181 
182  if(getStatus(CableRumble)) strcat_P(statusOutput, PSTR("Cable - Rumble is on"));
183  else if(getStatus(Cable)) strcat_P(statusOutput, PSTR("Cable - Rumble is off"));
184  else if(getStatus(BluetoothRumble)) strcat_P(statusOutput, PSTR("Bluetooth - Rumble is on"));
185  else if(getStatus(Bluetooth)) strcat_P(statusOutput, PSTR("Bluetooth - Rumble is off"));
186  else strcat_P(statusOutput, PSTR("Error"));
187  } else if(PS3MoveConnected) {
188  strcpy_P(statusOutput, PSTR("\r\nPowerRating: "));
189 
190  if(getStatus(MoveCharging)) strcat_P(statusOutput, PSTR("Charging"));
191  else if(getStatus(MoveNotCharging)) strcat_P(statusOutput, PSTR("Not Charging"));
192  else if(getStatus(MoveShutdown)) strcat_P(statusOutput, PSTR("Shutdown"));
193  else if(getStatus(MoveDying)) strcat_P(statusOutput, PSTR("Dying"));
194  else if(getStatus(MoveLow)) strcat_P(statusOutput, PSTR("Low"));
195  else if(getStatus(MoveHigh)) strcat_P(statusOutput, PSTR("High"));
196  else if(getStatus(MoveFull)) strcat_P(statusOutput, PSTR("Full"));
197  else strcat_P(statusOutput, PSTR("Error"));
198  } else
199  strcpy_P(statusOutput, PSTR("\r\nError"));
200 
201  USB_HOST_SERIAL.write(statusOutput);
202 }
203 
204 void PS3BT::Reset() {
205  PS3Connected = false;
206  PS3MoveConnected = false;
207  PS3NavigationConnected = false;
208  activeConnection = false;
209  l2cap_event_flag = 0; // Reset flags
210  l2cap_state = L2CAP_WAIT;
211 
212  // Needed for PS3 Dualshock Controller commands to work via Bluetooth
213  for(uint8_t i = 0; i < PS3_REPORT_BUFFER_SIZE; i++)
214  HIDBuffer[i + 2] = pgm_read_byte(&PS3_REPORT_BUFFER[i]); // First two bytes reserved for report type and ID
215 }
216 
217 void PS3BT::disconnect() { // Use this void to disconnect any of the controllers
218  // First the HID interrupt channel has to be disconnected, then the HID control channel and finally the HCI connection
219  pBtd->l2cap_disconnection_request(hci_handle, ++identifier, interrupt_scid, interrupt_dcid);
220  Reset();
221  l2cap_state = L2CAP_INTERRUPT_DISCONNECT;
222 }
223 
224 void PS3BT::ACLData(uint8_t* ACLData) {
226  if(ACLData[8] == L2CAP_CMD_CONNECTION_REQUEST) {
227  if((ACLData[12] | (ACLData[13] << 8)) == HID_CTRL_PSM) {
228  pBtd->l2capConnectionClaimed = true; // Claim that the incoming connection belongs to this service
229  activeConnection = true;
230  hci_handle = pBtd->hci_handle; // Store the HCI Handle for the connection
231  l2cap_state = L2CAP_WAIT;
232  remote_name_first = pBtd->remote_name[0]; // Store the first letter in remote name for the connection
233 #ifdef DEBUG_USB_HOST
234  if(pBtd->hci_version < 3) { // Check the HCI Version of the Bluetooth dongle
235  Notify(PSTR("\r\nYour dongle may not support reading the analog buttons, sensors and status\r\nYour HCI Version is: "), 0x80);
236  Notify(pBtd->hci_version, 0x80);
237  Notify(PSTR("\r\nBut should be at least 3\r\nThis means that it doesn't support Bluetooth Version 2.0+EDR"), 0x80);
238  }
239 #endif
240  }
241  }
242  }
243 
244  if(checkHciHandle(ACLData, hci_handle)) { // acl_handle_ok
245  memcpy(l2capinbuf, ACLData, BULK_MAXPKTSIZE);
246  if((l2capinbuf[6] | (l2capinbuf[7] << 8)) == 0x0001U) { // l2cap_control - Channel ID for ACL-U
247  if(l2capinbuf[8] == L2CAP_CMD_COMMAND_REJECT) {
248 #ifdef DEBUG_USB_HOST
249  Notify(PSTR("\r\nL2CAP Command Rejected - Reason: "), 0x80);
250  D_PrintHex<uint8_t > (l2capinbuf[13], 0x80);
251  Notify(PSTR(" "), 0x80);
252  D_PrintHex<uint8_t > (l2capinbuf[12], 0x80);
253  Notify(PSTR(" Data: "), 0x80);
254  D_PrintHex<uint8_t > (l2capinbuf[17], 0x80);
255  Notify(PSTR(" "), 0x80);
256  D_PrintHex<uint8_t > (l2capinbuf[16], 0x80);
257  Notify(PSTR(" "), 0x80);
258  D_PrintHex<uint8_t > (l2capinbuf[15], 0x80);
259  Notify(PSTR(" "), 0x80);
260  D_PrintHex<uint8_t > (l2capinbuf[14], 0x80);
261 #endif
262  } else if(l2capinbuf[8] == L2CAP_CMD_CONNECTION_REQUEST) {
263 #ifdef EXTRADEBUG
264  Notify(PSTR("\r\nL2CAP Connection Request - PSM: "), 0x80);
265  D_PrintHex<uint8_t > (l2capinbuf[13], 0x80);
266  Notify(PSTR(" "), 0x80);
267  D_PrintHex<uint8_t > (l2capinbuf[12], 0x80);
268  Notify(PSTR(" SCID: "), 0x80);
269  D_PrintHex<uint8_t > (l2capinbuf[15], 0x80);
270  Notify(PSTR(" "), 0x80);
271  D_PrintHex<uint8_t > (l2capinbuf[14], 0x80);
272  Notify(PSTR(" Identifier: "), 0x80);
273  D_PrintHex<uint8_t > (l2capinbuf[9], 0x80);
274 #endif
275  if((l2capinbuf[12] | (l2capinbuf[13] << 8)) == HID_CTRL_PSM) {
276  identifier = l2capinbuf[9];
277  control_scid[0] = l2capinbuf[14];
278  control_scid[1] = l2capinbuf[15];
280  } else if((l2capinbuf[12] | (l2capinbuf[13] << 8)) == HID_INTR_PSM) {
281  identifier = l2capinbuf[9];
282  interrupt_scid[0] = l2capinbuf[14];
283  interrupt_scid[1] = l2capinbuf[15];
285  }
286  } else if(l2capinbuf[8] == L2CAP_CMD_CONFIG_RESPONSE) {
287  if((l2capinbuf[16] | (l2capinbuf[17] << 8)) == 0x0000) { // Success
288  if(l2capinbuf[12] == control_dcid[0] && l2capinbuf[13] == control_dcid[1]) {
289  //Notify(PSTR("\r\nHID Control Configuration Complete"), 0x80);
291  } else if(l2capinbuf[12] == interrupt_dcid[0] && l2capinbuf[13] == interrupt_dcid[1]) {
292  //Notify(PSTR("\r\nHID Interrupt Configuration Complete"), 0x80);
294  }
295  }
296  } else if(l2capinbuf[8] == L2CAP_CMD_CONFIG_REQUEST) {
297  if(l2capinbuf[12] == control_dcid[0] && l2capinbuf[13] == control_dcid[1]) {
298  //Notify(PSTR("\r\nHID Control Configuration Request"), 0x80);
299  pBtd->l2cap_config_response(hci_handle, l2capinbuf[9], control_scid);
300  } else if(l2capinbuf[12] == interrupt_dcid[0] && l2capinbuf[13] == interrupt_dcid[1]) {
301  //Notify(PSTR("\r\nHID Interrupt Configuration Request"), 0x80);
302  pBtd->l2cap_config_response(hci_handle, l2capinbuf[9], interrupt_scid);
303  }
304  } else if(l2capinbuf[8] == L2CAP_CMD_DISCONNECT_REQUEST) {
305  if(l2capinbuf[12] == control_dcid[0] && l2capinbuf[13] == control_dcid[1]) {
306 #ifdef DEBUG_USB_HOST
307  Notify(PSTR("\r\nDisconnect Request: Control Channel"), 0x80);
308 #endif
309  identifier = l2capinbuf[9];
310  pBtd->l2cap_disconnection_response(hci_handle, identifier, control_dcid, control_scid);
311  Reset();
312  } else if(l2capinbuf[12] == interrupt_dcid[0] && l2capinbuf[13] == interrupt_dcid[1]) {
313 #ifdef DEBUG_USB_HOST
314  Notify(PSTR("\r\nDisconnect Request: Interrupt Channel"), 0x80);
315 #endif
316  identifier = l2capinbuf[9];
317  pBtd->l2cap_disconnection_response(hci_handle, identifier, interrupt_dcid, interrupt_scid);
318  Reset();
319  }
320  } else if(l2capinbuf[8] == L2CAP_CMD_DISCONNECT_RESPONSE) {
321  if(l2capinbuf[12] == control_scid[0] && l2capinbuf[13] == control_scid[1]) {
322  //Notify(PSTR("\r\nDisconnect Response: Control Channel"), 0x80);
323  identifier = l2capinbuf[9];
325  } else if(l2capinbuf[12] == interrupt_scid[0] && l2capinbuf[13] == interrupt_scid[1]) {
326  //Notify(PSTR("\r\nDisconnect Response: Interrupt Channel"), 0x80);
327  identifier = l2capinbuf[9];
329  }
330  }
331 #ifdef EXTRADEBUG
332  else {
333  Notify(PSTR("\r\nL2CAP Unknown Signaling Command: "), 0x80);
334  D_PrintHex<uint8_t > (l2capinbuf[8], 0x80);
335  }
336 #endif
337  } else if(l2capinbuf[6] == interrupt_dcid[0] && l2capinbuf[7] == interrupt_dcid[1]) { // l2cap_interrupt
338  //Notify(PSTR("\r\nL2CAP Interrupt"), 0x80);
340  /* Read Report */
341  if(l2capinbuf[8] == 0xA1) { // HID_THDR_DATA_INPUT
342  lastMessageTime = (uint32_t)millis(); // Store the last message time
343 
345  ButtonState = (uint32_t)(l2capinbuf[11] | ((uint16_t)l2capinbuf[12] << 8) | ((uint32_t)l2capinbuf[13] << 16));
346  else if(PS3MoveConnected)
347  ButtonState = (uint32_t)(l2capinbuf[10] | ((uint16_t)l2capinbuf[11] << 8) | ((uint32_t)l2capinbuf[12] << 16));
348 
349  //Notify(PSTR("\r\nButtonState", 0x80);
350  //PrintHex<uint32_t>(ButtonState, 0x80);
351 
352  if(ButtonState != OldButtonState) {
353  ButtonClickState = ButtonState & ~OldButtonState; // Update click state variable
354  OldButtonState = ButtonState;
355  }
356 
357 #ifdef PRINTREPORT // Uncomment "#define PRINTREPORT" to print the report send by the PS3 Controllers
358  for(uint8_t i = 10; i < 58; i++) {
359  D_PrintHex<uint8_t > (l2capinbuf[i], 0x80);
360  Notify(PSTR(" "), 0x80);
361  }
362  Notify(PSTR("\r\n"), 0x80);
363 #endif
364  }
365  }
366  }
367  L2CAP_task();
368  }
369 }
370 
371 void PS3BT::L2CAP_task() {
372  switch(l2cap_state) {
373  case L2CAP_WAIT:
375 #ifdef DEBUG_USB_HOST
376  Notify(PSTR("\r\nHID Control Incoming Connection Request"), 0x80);
377 #endif
378  pBtd->l2cap_connection_response(hci_handle, identifier, control_dcid, control_scid, PENDING);
379  delay(1);
380  pBtd->l2cap_connection_response(hci_handle, identifier, control_dcid, control_scid, SUCCESSFUL);
381  identifier++;
382  delay(1);
384  l2cap_state = L2CAP_CONTROL_SUCCESS;
385  }
386  break;
387 
390 #ifdef DEBUG_USB_HOST
391  Notify(PSTR("\r\nHID Control Successfully Configured"), 0x80);
392 #endif
393  l2cap_state = L2CAP_INTERRUPT_SETUP;
394  }
395  break;
396 
399 #ifdef DEBUG_USB_HOST
400  Notify(PSTR("\r\nHID Interrupt Incoming Connection Request"), 0x80);
401 #endif
402  pBtd->l2cap_connection_response(hci_handle, identifier, interrupt_dcid, interrupt_scid, PENDING);
403  delay(1);
404  pBtd->l2cap_connection_response(hci_handle, identifier, interrupt_dcid, interrupt_scid, SUCCESSFUL);
405  identifier++;
406  delay(1);
407  pBtd->l2cap_config_request(hci_handle, identifier, interrupt_scid);
408 
409  l2cap_state = L2CAP_INTERRUPT_CONFIG_REQUEST;
410  }
411  break;
412 
414  if(l2cap_check_flag(L2CAP_FLAG_CONFIG_INTERRUPT_SUCCESS)) { // Now the HID channels is established
415 #ifdef DEBUG_USB_HOST
416  Notify(PSTR("\r\nHID Interrupt Successfully Configured"), 0x80);
417 #endif
418  if(remote_name_first == 'M') { // First letter in Motion Controller ('M')
419  memset(l2capinbuf, 0, BULK_MAXPKTSIZE); // Reset l2cap in buffer as it sometimes read it as a button has been pressed
420  l2cap_state = TURN_ON_LED;
421  } else
422  l2cap_state = PS3_ENABLE_SIXAXIS;
423  timer = (uint32_t)millis();
424  }
425  break;
426 
427  /* These states are handled in Run() */
428 
431 #ifdef DEBUG_USB_HOST
432  Notify(PSTR("\r\nDisconnected Interrupt Channel"), 0x80);
433 #endif
434  identifier++;
435  pBtd->l2cap_disconnection_request(hci_handle, identifier, control_scid, control_dcid);
436  l2cap_state = L2CAP_CONTROL_DISCONNECT;
437  }
438  break;
439 
442 #ifdef DEBUG_USB_HOST
443  Notify(PSTR("\r\nDisconnected Control Channel"), 0x80);
444 #endif
446  hci_handle = -1; // Reset handle
447  l2cap_event_flag = 0; // Reset flags
448  l2cap_state = L2CAP_WAIT;
449  }
450  break;
451  }
452 }
453 
454 void PS3BT::Run() {
455  switch(l2cap_state) {
456  case PS3_ENABLE_SIXAXIS:
457  if((int32_t)((uint32_t)millis() - timer) > 1000) { // loop 1 second before sending the command
458  memset(l2capinbuf, 0, BULK_MAXPKTSIZE); // Reset l2cap in buffer as it sometimes read it as a button has been pressed
459  for(uint8_t i = 15; i < 19; i++)
460  l2capinbuf[i] = 0x7F; // Set the analog joystick values to center position
461  enable_sixaxis();
462  l2cap_state = TURN_ON_LED;
463  timer = (uint32_t)millis();
464  }
465  break;
466 
467  case TURN_ON_LED:
468  if((int32_t)((uint32_t)millis() - timer) > 1000) { // loop 1 second before sending the command
469  if(remote_name_first == 'P') { // First letter in PLAYSTATION(R)3 Controller ('P')
470 #ifdef DEBUG_USB_HOST
471  Notify(PSTR("\r\nDualshock 3 Controller Enabled\r\n"), 0x80);
472 #endif
473  PS3Connected = true;
474  } else if(remote_name_first == 'N') { // First letter in Navigation Controller ('N')
475 #ifdef DEBUG_USB_HOST
476  Notify(PSTR("\r\nNavigation Controller Enabled\r\n"), 0x80);
477 #endif
478  PS3NavigationConnected = true;
479  } else if(remote_name_first == 'M') { // First letter in Motion Controller ('M')
480  timer = (uint32_t)millis();
481 #ifdef DEBUG_USB_HOST
482  Notify(PSTR("\r\nMotion Controller Enabled\r\n"), 0x80);
483 #endif
484  PS3MoveConnected = true;
485  }
486  ButtonState = 0; // Clear all values
487  OldButtonState = 0;
488  ButtonClickState = 0;
489 
490  onInit(); // Turn on the LED on the controller
491  l2cap_state = L2CAP_DONE;
492  }
493  break;
494 
495  case L2CAP_DONE:
496  if(PS3MoveConnected) { // The Bulb and rumble values, has to be send at approximately every 5th second for it to stay on
497  if((int32_t)((uint32_t)millis() - timer) > 4000) { // Send at least every 4th second
498  HIDMove_Command(HIDMoveBuffer, HID_BUFFERSIZE); // The Bulb and rumble values, has to be written again and again, for it to stay turned on
499  timer = (uint32_t)millis();
500  }
501  }
502  break;
503  }
504 }
505 
506 /************************************************************/
507 /* HID Commands */
508 /************************************************************/
509 
510 // Playstation Sixaxis Dualshock and Navigation Controller commands
511 
512 void PS3BT::HID_Command(uint8_t* data, uint8_t nbytes) {
513  if((int32_t)((uint32_t)millis() - timerHID) <= 150) // Check if is has been more than 150ms since last command
514  delay((uint32_t)(150 - ((uint32_t)millis() - timerHID))); // There have to be a delay between commands
515  pBtd->L2CAP_Command(hci_handle, data, nbytes, control_scid[0], control_scid[1]); // Both the Navigation and Dualshock controller sends data via the control channel
516  timerHID = (uint32_t)millis();
517 }
518 
520  HIDBuffer[3] = 0x00; // Rumble bytes
521  HIDBuffer[4] = 0x00;
522  HIDBuffer[5] = 0x00;
523  HIDBuffer[6] = 0x00;
524 
525  HIDBuffer[11] = 0x00; // LED byte
526 
527  HID_Command(HIDBuffer, HID_BUFFERSIZE);
528 }
529 
531  uint8_t rumbleBuf[HID_BUFFERSIZE];
532  memcpy(rumbleBuf, HIDBuffer, HID_BUFFERSIZE);
533  rumbleBuf[3] = 0x00;
534  rumbleBuf[4] = 0x00;
535  rumbleBuf[5] = 0x00;
536  rumbleBuf[6] = 0x00;
537  HID_Command(rumbleBuf, HID_BUFFERSIZE);
538 }
539 
541  uint8_t power[2] = {0xff, 0x00}; // Defaults to RumbleLow
542  if(mode == RumbleHigh) {
543  power[0] = 0x00;
544  power[1] = 0xff;
545  }
546  setRumbleOn(0xfe, power[0], 0xfe, power[1]);
547 }
548 
549 void PS3BT::setRumbleOn(uint8_t rightDuration, uint8_t rightPower, uint8_t leftDuration, uint8_t leftPower) {
550  uint8_t rumbleBuf[HID_BUFFERSIZE];
551  memcpy(rumbleBuf, HIDBuffer, HID_BUFFERSIZE);
552  rumbleBuf[3] = rightDuration;
553  rumbleBuf[4] = rightPower;
554  rumbleBuf[5] = leftDuration;
555  rumbleBuf[6] = leftPower;
556  HID_Command(rumbleBuf, HID_BUFFERSIZE);
557 }
558 
559 void PS3BT::setLedRaw(uint8_t value) {
560  HIDBuffer[11] = value << 1;
561  HID_Command(HIDBuffer, HID_BUFFERSIZE);
562 }
563 
565  HIDBuffer[11] &= ~((uint8_t)((pgm_read_byte(&PS3_LEDS[(uint8_t)a]) & 0x0f) << 1));
566  HID_Command(HIDBuffer, HID_BUFFERSIZE);
567 }
568 
570  if(a == OFF)
571  setLedRaw(0);
572  else {
573  HIDBuffer[11] |= (uint8_t)((pgm_read_byte(&PS3_LEDS[(uint8_t)a]) & 0x0f) << 1);
574  HID_Command(HIDBuffer, HID_BUFFERSIZE);
575  }
576 }
577 
579  HIDBuffer[11] ^= (uint8_t)((pgm_read_byte(&PS3_LEDS[(uint8_t)a]) & 0x0f) << 1);
580  HID_Command(HIDBuffer, HID_BUFFERSIZE);
581 }
582 
583 void PS3BT::enable_sixaxis() { // Command used to enable the Dualshock 3 and Navigation controller to send data via Bluetooth
584  uint8_t cmd_buf[6];
585  cmd_buf[0] = 0x53; // HID BT Set_report (0x50) | Report Type (Feature 0x03)
586  cmd_buf[1] = 0xF4; // Report ID
587  cmd_buf[2] = 0x42; // Special PS3 Controller enable commands
588  cmd_buf[3] = 0x03;
589  cmd_buf[4] = 0x00;
590  cmd_buf[5] = 0x00;
591 
592  HID_Command(cmd_buf, 6);
593 }
594 
595 // Playstation Move Controller commands
596 
597 void PS3BT::HIDMove_Command(uint8_t* data, uint8_t nbytes) {
598  if((int32_t)((uint32_t)millis() - timerHID) <= 150)// Check if is has been less than 150ms since last command
599  delay((uint32_t)(150 - ((uint32_t)millis() - timerHID))); // There have to be a delay between commands
600  pBtd->L2CAP_Command(hci_handle, data, nbytes, interrupt_scid[0], interrupt_scid[1]); // The Move controller sends it's data via the intterrupt channel
601  timerHID = (uint32_t)millis();
602 }
603 
604 void PS3BT::moveSetBulb(uint8_t r, uint8_t g, uint8_t b) { // Use this to set the Color using RGB values
605  // Set the Bulb's values into the write buffer
606  HIDMoveBuffer[3] = r;
607  HIDMoveBuffer[4] = g;
608  HIDMoveBuffer[5] = b;
609 
610  HIDMove_Command(HIDMoveBuffer, HID_BUFFERSIZE);
611 }
612 
613 void PS3BT::moveSetBulb(ColorsEnum color) { // Use this to set the Color using the predefined colors in enum
614  moveSetBulb((uint8_t)(color >> 16), (uint8_t)(color >> 8), (uint8_t)(color));
615 }
616 
617 void PS3BT::moveSetRumble(uint8_t rumble) {
618 #ifdef DEBUG_USB_HOST
619  if(rumble < 64 && rumble != 0) // The rumble value has to at least 64, or approximately 25% (64/255*100)
620  Notify(PSTR("\r\nThe rumble value has to at least 64, or approximately 25%"), 0x80);
621 #endif
622  // Set the rumble value into the write buffer
623  HIDMoveBuffer[7] = rumble;
624 
625  HIDMove_Command(HIDMoveBuffer, HID_BUFFERSIZE);
626 }
627 
629  if(pFuncOnInit)
630  pFuncOnInit(); // Call the user function
631  else {
632  if(PS3MoveConnected)
633  moveSetBulb(Red);
634  else // Dualshock 3 or Navigation controller
635  setLedOn(static_cast<LEDEnum>(LED1));
636  }
637 }
#define L2CAP_FLAG_DISCONNECT_CONTROL_RESPONSE
Definition: BTD.h:140
-
bool incomingWii
Definition: BTD.h:474
+Go to the documentation of this file.
1 /* Copyright (C) 2012 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 "PS3BT.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 PS3 Controllers
22 
23 PS3BT::PS3BT(BTD *p, uint8_t btadr5, uint8_t btadr4, uint8_t btadr3, uint8_t btadr2, uint8_t btadr1, uint8_t btadr0) :
24 BluetoothService(p) // Pointer to USB class instance - mandatory
25 {
26  pBtd->my_bdaddr[5] = btadr5; // Change to your dongle's Bluetooth address instead
27  pBtd->my_bdaddr[4] = btadr4;
28  pBtd->my_bdaddr[3] = btadr3;
29  pBtd->my_bdaddr[2] = btadr2;
30  pBtd->my_bdaddr[1] = btadr1;
31  pBtd->my_bdaddr[0] = btadr0;
32 
33  HIDBuffer[0] = 0x52; // HID BT Set_report (0x50) | Report Type (Output 0x02)
34  HIDBuffer[1] = 0x01; // Report ID
35 
36  // Needed for PS3 Move Controller commands to work via bluetooth
37  HIDMoveBuffer[0] = 0xA2; // HID BT DATA_request (0xA0) | Report Type (Output 0x02)
38  HIDMoveBuffer[1] = 0x02; // Report ID
39 
40  /* Set device cid for the control and intterrupt channelse - LSB */
41  control_dcid[0] = 0x40; // 0x0040
42  control_dcid[1] = 0x00;
43  interrupt_dcid[0] = 0x41; // 0x0041
44  interrupt_dcid[1] = 0x00;
45 
46  Reset();
47 }
48 
50  return (ButtonState & pgm_read_dword(&PS3_BUTTONS[(uint8_t)b]));
51 }
52 
54  uint32_t button = pgm_read_dword(&PS3_BUTTONS[(uint8_t)b]);
55  bool click = (ButtonClickState & button);
56  ButtonClickState &= ~button; // Clear "click" event
57  return click;
58 }
59 
61  return (uint8_t)(l2capinbuf[pgm_read_byte(&PS3_ANALOG_BUTTONS[(uint8_t)a])]);
62 }
63 
65  return (uint8_t)(l2capinbuf[(uint8_t)a + 15]);
66 }
67 
69  if(PS3Connected) {
70  if(a == aX || a == aY || a == aZ || a == gZ)
71  return ((l2capinbuf[(uint16_t)a] << 8) | l2capinbuf[(uint16_t)a + 1]);
72  else
73  return 0;
74  } else if(PS3MoveConnected) {
75  if(a == mXmove || a == mYmove) // These are all 12-bits long
76  return (((l2capinbuf[(uint16_t)a] & 0x0F) << 8) | (l2capinbuf[(uint16_t)a + 1]));
77  else if(a == mZmove || a == tempMove) // The tempearature is also 12 bits long
78  return ((l2capinbuf[(uint16_t)a] << 4) | ((l2capinbuf[(uint16_t)a + 1] & 0xF0) >> 4));
79  else // aXmove, aYmove, aZmove, gXmove, gYmove and gZmove
80  return (l2capinbuf[(uint16_t)a] | (l2capinbuf[(uint16_t)a + 1] << 8));
81  } else
82  return 0;
83 }
84 
86  float accXval, accYval, accZval;
87 
88  if(PS3Connected) {
89  // Data for the Kionix KXPC4 used in the DualShock 3
90  const float zeroG = 511.5f; // 1.65/3.3*1023 (1.65V)
91  accXval = -((float)getSensor(aX) - zeroG);
92  accYval = -((float)getSensor(aY) - zeroG);
93  accZval = -((float)getSensor(aZ) - zeroG);
94  } else if(PS3MoveConnected) {
95  // It's a Kionix KXSC4 inside the Motion controller
96  const uint16_t zeroG = 0x8000;
97  accXval = -(int16_t)(getSensor(aXmove) - zeroG);
98  accYval = (int16_t)(getSensor(aYmove) - zeroG);
99  accZval = (int16_t)(getSensor(aZmove) - zeroG);
100  } else
101  return 0;
102 
103  // Convert to 360 degrees resolution
104  // atan2 outputs the value of -Ï€ to Ï€ (radians)
105  // We are then converting it to 0 to 2Ï€ and then to degrees
106  if(a == Pitch)
107  return (atan2f(accYval, accZval) + PI) * RAD_TO_DEG;
108  else
109  return (atan2f(accXval, accZval) + PI) * RAD_TO_DEG;
110 }
111 
112 float PS3BT::get9DOFValues(SensorEnum a) { // Thanks to Manfred Piendl
113  if(!PS3MoveConnected)
114  return 0;
115  int16_t value = getSensor(a);
116  if(a == mXmove || a == mYmove || a == mZmove) {
117  if(value > 2047)
118  value -= 0x1000;
119  return (float)value / 3.2f; // unit: muT = 10^(-6) Tesla
120  } else if(a == aXmove || a == aYmove || a == aZmove) {
121  if(value < 0)
122  value += 0x8000;
123  else
124  value -= 0x8000;
125  return (float)value / 442.0f; // unit: m/(s^2)
126  } else if(a == gXmove || a == gYmove || a == gZmove) {
127  if(value < 0)
128  value += 0x8000;
129  else
130  value -= 0x8000;
131  if(a == gXmove)
132  return (float)value / 11.6f; // unit: deg/s
133  else if(a == gYmove)
134  return (float)value / 11.2f; // unit: deg/s
135  else // gZmove
136  return (float)value / 9.6f; // unit: deg/s
137  } else
138  return 0;
139 }
140 
142  if(PS3MoveConnected) {
143  int16_t input = getSensor(tempMove);
144 
145  String output = String(input / 100);
146  output += ".";
147  if(input % 100 < 10)
148  output += "0";
149  output += String(input % 100);
150 
151  return output;
152  } else
153  return "Error";
154 }
155 
157  return (l2capinbuf[(uint16_t)c >> 8] == ((uint8_t)c & 0xff));
158 }
159 
161  char statusOutput[102]; // Max string length plus null character
163  strcpy_P(statusOutput, PSTR("\r\nConnectionStatus: "));
164 
165  if(getStatus(Plugged)) strcat_P(statusOutput, PSTR("Plugged"));
166  else if(getStatus(Unplugged)) strcat_P(statusOutput, PSTR("Unplugged"));
167  else strcat_P(statusOutput, PSTR("Error"));
168 
169  strcat_P(statusOutput, PSTR(" - PowerRating: "));
170 
171  if(getStatus(Charging)) strcat_P(statusOutput, PSTR("Charging"));
172  else if(getStatus(NotCharging)) strcat_P(statusOutput, PSTR("Not Charging"));
173  else if(getStatus(Shutdown)) strcat_P(statusOutput, PSTR("Shutdown"));
174  else if(getStatus(Dying)) strcat_P(statusOutput, PSTR("Dying"));
175  else if(getStatus(Low)) strcat_P(statusOutput, PSTR("Low"));
176  else if(getStatus(High)) strcat_P(statusOutput, PSTR("High"));
177  else if(getStatus(Full)) strcat_P(statusOutput, PSTR("Full"));
178  else strcat_P(statusOutput, PSTR("Error"));
179 
180  strcat_P(statusOutput, PSTR(" - WirelessStatus: "));
181 
182  if(getStatus(CableRumble)) strcat_P(statusOutput, PSTR("Cable - Rumble is on"));
183  else if(getStatus(Cable)) strcat_P(statusOutput, PSTR("Cable - Rumble is off"));
184  else if(getStatus(BluetoothRumble)) strcat_P(statusOutput, PSTR("Bluetooth - Rumble is on"));
185  else if(getStatus(Bluetooth)) strcat_P(statusOutput, PSTR("Bluetooth - Rumble is off"));
186  else strcat_P(statusOutput, PSTR("Error"));
187  } else if(PS3MoveConnected) {
188  strcpy_P(statusOutput, PSTR("\r\nPowerRating: "));
189 
190  if(getStatus(MoveCharging)) strcat_P(statusOutput, PSTR("Charging"));
191  else if(getStatus(MoveNotCharging)) strcat_P(statusOutput, PSTR("Not Charging"));
192  else if(getStatus(MoveShutdown)) strcat_P(statusOutput, PSTR("Shutdown"));
193  else if(getStatus(MoveDying)) strcat_P(statusOutput, PSTR("Dying"));
194  else if(getStatus(MoveLow)) strcat_P(statusOutput, PSTR("Low"));
195  else if(getStatus(MoveHigh)) strcat_P(statusOutput, PSTR("High"));
196  else if(getStatus(MoveFull)) strcat_P(statusOutput, PSTR("Full"));
197  else strcat_P(statusOutput, PSTR("Error"));
198  } else
199  strcpy_P(statusOutput, PSTR("\r\nError"));
200 
201  USB_HOST_SERIAL.write(statusOutput);
202 }
203 
204 void PS3BT::Reset() {
205  PS3Connected = false;
206  PS3MoveConnected = false;
207  PS3NavigationConnected = false;
208  activeConnection = false;
209  l2cap_event_flag = 0; // Reset flags
210  l2cap_state = L2CAP_WAIT;
211 
212  // Needed for PS3 Dualshock Controller commands to work via Bluetooth
213  for(uint8_t i = 0; i < PS3_REPORT_BUFFER_SIZE; i++)
214  HIDBuffer[i + 2] = pgm_read_byte(&PS3_REPORT_BUFFER[i]); // First two bytes reserved for report type and ID
215 }
216 
217 void PS3BT::disconnect() { // Use this void to disconnect any of the controllers
218  // First the HID interrupt channel has to be disconnected, then the HID control channel and finally the HCI connection
219  pBtd->l2cap_disconnection_request(hci_handle, ++identifier, interrupt_scid, interrupt_dcid);
220  Reset();
221  l2cap_state = L2CAP_INTERRUPT_DISCONNECT;
222 }
223 
224 void PS3BT::ACLData(uint8_t* ACLData) {
226  if(ACLData[8] == L2CAP_CMD_CONNECTION_REQUEST) {
227  if((ACLData[12] | (ACLData[13] << 8)) == HID_CTRL_PSM) {
228  pBtd->l2capConnectionClaimed = true; // Claim that the incoming connection belongs to this service
229  activeConnection = true;
230  hci_handle = pBtd->hci_handle; // Store the HCI Handle for the connection
231  l2cap_state = L2CAP_WAIT;
232  remote_name_first = pBtd->remote_name[0]; // Store the first letter in remote name for the connection
233 #ifdef DEBUG_USB_HOST
234  if(pBtd->hci_version < 3) { // Check the HCI Version of the Bluetooth dongle
235  Notify(PSTR("\r\nYour dongle may not support reading the analog buttons, sensors and status\r\nYour HCI Version is: "), 0x80);
236  Notify(pBtd->hci_version, 0x80);
237  Notify(PSTR("\r\nBut should be at least 3\r\nThis means that it doesn't support Bluetooth Version 2.0+EDR"), 0x80);
238  }
239 #endif
240  }
241  }
242  }
243 
244  if(checkHciHandle(ACLData, hci_handle)) { // acl_handle_ok
245  memcpy(l2capinbuf, ACLData, BULK_MAXPKTSIZE);
246  if((l2capinbuf[6] | (l2capinbuf[7] << 8)) == 0x0001U) { // l2cap_control - Channel ID for ACL-U
247  if(l2capinbuf[8] == L2CAP_CMD_COMMAND_REJECT) {
248 #ifdef DEBUG_USB_HOST
249  Notify(PSTR("\r\nL2CAP Command Rejected - Reason: "), 0x80);
250  D_PrintHex<uint8_t > (l2capinbuf[13], 0x80);
251  Notify(PSTR(" "), 0x80);
252  D_PrintHex<uint8_t > (l2capinbuf[12], 0x80);
253  Notify(PSTR(" Data: "), 0x80);
254  D_PrintHex<uint8_t > (l2capinbuf[17], 0x80);
255  Notify(PSTR(" "), 0x80);
256  D_PrintHex<uint8_t > (l2capinbuf[16], 0x80);
257  Notify(PSTR(" "), 0x80);
258  D_PrintHex<uint8_t > (l2capinbuf[15], 0x80);
259  Notify(PSTR(" "), 0x80);
260  D_PrintHex<uint8_t > (l2capinbuf[14], 0x80);
261 #endif
262  } else if(l2capinbuf[8] == L2CAP_CMD_CONNECTION_REQUEST) {
263 #ifdef EXTRADEBUG
264  Notify(PSTR("\r\nL2CAP Connection Request - PSM: "), 0x80);
265  D_PrintHex<uint8_t > (l2capinbuf[13], 0x80);
266  Notify(PSTR(" "), 0x80);
267  D_PrintHex<uint8_t > (l2capinbuf[12], 0x80);
268  Notify(PSTR(" SCID: "), 0x80);
269  D_PrintHex<uint8_t > (l2capinbuf[15], 0x80);
270  Notify(PSTR(" "), 0x80);
271  D_PrintHex<uint8_t > (l2capinbuf[14], 0x80);
272  Notify(PSTR(" Identifier: "), 0x80);
273  D_PrintHex<uint8_t > (l2capinbuf[9], 0x80);
274 #endif
275  if((l2capinbuf[12] | (l2capinbuf[13] << 8)) == HID_CTRL_PSM) {
276  identifier = l2capinbuf[9];
277  control_scid[0] = l2capinbuf[14];
278  control_scid[1] = l2capinbuf[15];
280  } else if((l2capinbuf[12] | (l2capinbuf[13] << 8)) == HID_INTR_PSM) {
281  identifier = l2capinbuf[9];
282  interrupt_scid[0] = l2capinbuf[14];
283  interrupt_scid[1] = l2capinbuf[15];
285  }
286  } else if(l2capinbuf[8] == L2CAP_CMD_CONFIG_RESPONSE) {
287  if((l2capinbuf[16] | (l2capinbuf[17] << 8)) == 0x0000) { // Success
288  if(l2capinbuf[12] == control_dcid[0] && l2capinbuf[13] == control_dcid[1]) {
289  //Notify(PSTR("\r\nHID Control Configuration Complete"), 0x80);
291  } else if(l2capinbuf[12] == interrupt_dcid[0] && l2capinbuf[13] == interrupt_dcid[1]) {
292  //Notify(PSTR("\r\nHID Interrupt Configuration Complete"), 0x80);
294  }
295  }
296  } else if(l2capinbuf[8] == L2CAP_CMD_CONFIG_REQUEST) {
297  if(l2capinbuf[12] == control_dcid[0] && l2capinbuf[13] == control_dcid[1]) {
298  //Notify(PSTR("\r\nHID Control Configuration Request"), 0x80);
299  pBtd->l2cap_config_response(hci_handle, l2capinbuf[9], control_scid);
300  } else if(l2capinbuf[12] == interrupt_dcid[0] && l2capinbuf[13] == interrupt_dcid[1]) {
301  //Notify(PSTR("\r\nHID Interrupt Configuration Request"), 0x80);
302  pBtd->l2cap_config_response(hci_handle, l2capinbuf[9], interrupt_scid);
303  }
304  } else if(l2capinbuf[8] == L2CAP_CMD_DISCONNECT_REQUEST) {
305  if(l2capinbuf[12] == control_dcid[0] && l2capinbuf[13] == control_dcid[1]) {
306 #ifdef DEBUG_USB_HOST
307  Notify(PSTR("\r\nDisconnect Request: Control Channel"), 0x80);
308 #endif
309  identifier = l2capinbuf[9];
310  pBtd->l2cap_disconnection_response(hci_handle, identifier, control_dcid, control_scid);
311  Reset();
312  } else if(l2capinbuf[12] == interrupt_dcid[0] && l2capinbuf[13] == interrupt_dcid[1]) {
313 #ifdef DEBUG_USB_HOST
314  Notify(PSTR("\r\nDisconnect Request: Interrupt Channel"), 0x80);
315 #endif
316  identifier = l2capinbuf[9];
317  pBtd->l2cap_disconnection_response(hci_handle, identifier, interrupt_dcid, interrupt_scid);
318  Reset();
319  }
320  } else if(l2capinbuf[8] == L2CAP_CMD_DISCONNECT_RESPONSE) {
321  if(l2capinbuf[12] == control_scid[0] && l2capinbuf[13] == control_scid[1]) {
322  //Notify(PSTR("\r\nDisconnect Response: Control Channel"), 0x80);
323  identifier = l2capinbuf[9];
325  } else if(l2capinbuf[12] == interrupt_scid[0] && l2capinbuf[13] == interrupt_scid[1]) {
326  //Notify(PSTR("\r\nDisconnect Response: Interrupt Channel"), 0x80);
327  identifier = l2capinbuf[9];
329  }
330  }
331 #ifdef EXTRADEBUG
332  else {
333  Notify(PSTR("\r\nL2CAP Unknown Signaling Command: "), 0x80);
334  D_PrintHex<uint8_t > (l2capinbuf[8], 0x80);
335  }
336 #endif
337  } else if(l2capinbuf[6] == interrupt_dcid[0] && l2capinbuf[7] == interrupt_dcid[1]) { // l2cap_interrupt
338  //Notify(PSTR("\r\nL2CAP Interrupt"), 0x80);
340  /* Read Report */
341  if(l2capinbuf[8] == 0xA1) { // HID_THDR_DATA_INPUT
342  lastMessageTime = (uint32_t)millis(); // Store the last message time
343 
345  ButtonState = (uint32_t)(l2capinbuf[11] | ((uint16_t)l2capinbuf[12] << 8) | ((uint32_t)l2capinbuf[13] << 16));
346  else if(PS3MoveConnected)
347  ButtonState = (uint32_t)(l2capinbuf[10] | ((uint16_t)l2capinbuf[11] << 8) | ((uint32_t)l2capinbuf[12] << 16));
348 
349  //Notify(PSTR("\r\nButtonState", 0x80);
350  //PrintHex<uint32_t>(ButtonState, 0x80);
351 
352  if(ButtonState != OldButtonState) {
353  ButtonClickState = ButtonState & ~OldButtonState; // Update click state variable
354  OldButtonState = ButtonState;
355  }
356 
357 #ifdef PRINTREPORT // Uncomment "#define PRINTREPORT" to print the report send by the PS3 Controllers
358  for(uint8_t i = 10; i < 58; i++) {
359  D_PrintHex<uint8_t > (l2capinbuf[i], 0x80);
360  Notify(PSTR(" "), 0x80);
361  }
362  Notify(PSTR("\r\n"), 0x80);
363 #endif
364  }
365  }
366  }
367  L2CAP_task();
368  }
369 }
370 
371 void PS3BT::L2CAP_task() {
372  switch(l2cap_state) {
373  case L2CAP_WAIT:
375 #ifdef DEBUG_USB_HOST
376  Notify(PSTR("\r\nHID Control Incoming Connection Request"), 0x80);
377 #endif
378  pBtd->l2cap_connection_response(hci_handle, identifier, control_dcid, control_scid, PENDING);
379  delay(1);
380  pBtd->l2cap_connection_response(hci_handle, identifier, control_dcid, control_scid, SUCCESSFUL);
381  identifier++;
382  delay(1);
384  l2cap_state = L2CAP_CONTROL_SUCCESS;
385  }
386  break;
387 
390 #ifdef DEBUG_USB_HOST
391  Notify(PSTR("\r\nHID Control Successfully Configured"), 0x80);
392 #endif
393  l2cap_state = L2CAP_INTERRUPT_SETUP;
394  }
395  break;
396 
399 #ifdef DEBUG_USB_HOST
400  Notify(PSTR("\r\nHID Interrupt Incoming Connection Request"), 0x80);
401 #endif
402  pBtd->l2cap_connection_response(hci_handle, identifier, interrupt_dcid, interrupt_scid, PENDING);
403  delay(1);
404  pBtd->l2cap_connection_response(hci_handle, identifier, interrupt_dcid, interrupt_scid, SUCCESSFUL);
405  identifier++;
406  delay(1);
407  pBtd->l2cap_config_request(hci_handle, identifier, interrupt_scid);
408 
409  l2cap_state = L2CAP_INTERRUPT_CONFIG_REQUEST;
410  }
411  break;
412 
414  if(l2cap_check_flag(L2CAP_FLAG_CONFIG_INTERRUPT_SUCCESS)) { // Now the HID channels is established
415 #ifdef DEBUG_USB_HOST
416  Notify(PSTR("\r\nHID Interrupt Successfully Configured"), 0x80);
417 #endif
418  if(remote_name_first == 'M') { // First letter in Motion Controller ('M')
419  memset(l2capinbuf, 0, BULK_MAXPKTSIZE); // Reset l2cap in buffer as it sometimes read it as a button has been pressed
420  l2cap_state = TURN_ON_LED;
421  } else
422  l2cap_state = PS3_ENABLE_SIXAXIS;
423  timer = (uint32_t)millis();
424  }
425  break;
426 
427  /* These states are handled in Run() */
428 
431 #ifdef DEBUG_USB_HOST
432  Notify(PSTR("\r\nDisconnected Interrupt Channel"), 0x80);
433 #endif
434  identifier++;
435  pBtd->l2cap_disconnection_request(hci_handle, identifier, control_scid, control_dcid);
436  l2cap_state = L2CAP_CONTROL_DISCONNECT;
437  }
438  break;
439 
442 #ifdef DEBUG_USB_HOST
443  Notify(PSTR("\r\nDisconnected Control Channel"), 0x80);
444 #endif
446  hci_handle = -1; // Reset handle
447  l2cap_event_flag = 0; // Reset flags
448  l2cap_state = L2CAP_WAIT;
449  }
450  break;
451  }
452 }
453 
454 void PS3BT::Run() {
455  switch(l2cap_state) {
456  case PS3_ENABLE_SIXAXIS:
457  if((int32_t)((uint32_t)millis() - timer) > 1000) { // loop 1 second before sending the command
458  memset(l2capinbuf, 0, BULK_MAXPKTSIZE); // Reset l2cap in buffer as it sometimes read it as a button has been pressed
459  for(uint8_t i = 15; i < 19; i++)
460  l2capinbuf[i] = 0x7F; // Set the analog joystick values to center position
461  enable_sixaxis();
462  l2cap_state = TURN_ON_LED;
463  timer = (uint32_t)millis();
464  }
465  break;
466 
467  case TURN_ON_LED:
468  if((int32_t)((uint32_t)millis() - timer) > 1000) { // loop 1 second before sending the command
469  if(remote_name_first == 'P') { // First letter in PLAYSTATION(R)3 Controller ('P')
470 #ifdef DEBUG_USB_HOST
471  Notify(PSTR("\r\nDualshock 3 Controller Enabled\r\n"), 0x80);
472 #endif
473  PS3Connected = true;
474  } else if(remote_name_first == 'N') { // First letter in Navigation Controller ('N')
475 #ifdef DEBUG_USB_HOST
476  Notify(PSTR("\r\nNavigation Controller Enabled\r\n"), 0x80);
477 #endif
478  PS3NavigationConnected = true;
479  } else if(remote_name_first == 'M') { // First letter in Motion Controller ('M')
480  timer = (uint32_t)millis();
481 #ifdef DEBUG_USB_HOST
482  Notify(PSTR("\r\nMotion Controller Enabled\r\n"), 0x80);
483 #endif
484  PS3MoveConnected = true;
485  }
486  ButtonState = 0; // Clear all values
487  OldButtonState = 0;
488  ButtonClickState = 0;
489 
490  onInit(); // Turn on the LED on the controller
491  l2cap_state = L2CAP_DONE;
492  }
493  break;
494 
495  case L2CAP_DONE:
496  if(PS3MoveConnected) { // The Bulb and rumble values, has to be send at approximately every 5th second for it to stay on
497  if((int32_t)((uint32_t)millis() - timer) > 4000) { // Send at least every 4th second
498  HIDMove_Command(HIDMoveBuffer, HID_BUFFERSIZE); // The Bulb and rumble values, has to be written again and again, for it to stay turned on
499  timer = (uint32_t)millis();
500  }
501  }
502  break;
503  }
504 }
505 
506 /************************************************************/
507 /* HID Commands */
508 /************************************************************/
509 
510 // Playstation Sixaxis Dualshock and Navigation Controller commands
511 
512 void PS3BT::HID_Command(uint8_t* data, uint8_t nbytes) {
513  if((int32_t)((uint32_t)millis() - timerHID) <= 150) // Check if is has been more than 150ms since last command
514  delay((uint32_t)(150 - ((uint32_t)millis() - timerHID))); // There have to be a delay between commands
515  pBtd->L2CAP_Command(hci_handle, data, nbytes, control_scid[0], control_scid[1]); // Both the Navigation and Dualshock controller sends data via the control channel
516  timerHID = (uint32_t)millis();
517 }
518 
520  HIDBuffer[3] = 0x00; // Rumble bytes
521  HIDBuffer[4] = 0x00;
522  HIDBuffer[5] = 0x00;
523  HIDBuffer[6] = 0x00;
524 
525  HIDBuffer[11] = 0x00; // LED byte
526 
527  HID_Command(HIDBuffer, HID_BUFFERSIZE);
528 }
529 
531  uint8_t rumbleBuf[HID_BUFFERSIZE];
532  memcpy(rumbleBuf, HIDBuffer, HID_BUFFERSIZE);
533  rumbleBuf[3] = 0x00;
534  rumbleBuf[4] = 0x00;
535  rumbleBuf[5] = 0x00;
536  rumbleBuf[6] = 0x00;
537  HID_Command(rumbleBuf, HID_BUFFERSIZE);
538 }
539 
541  uint8_t power[2] = {0xff, 0x00}; // Defaults to RumbleLow
542  if(mode == RumbleHigh) {
543  power[0] = 0x00;
544  power[1] = 0xff;
545  }
546  setRumbleOn(0xfe, power[0], 0xfe, power[1]);
547 }
548 
549 void PS3BT::setRumbleOn(uint8_t rightDuration, uint8_t rightPower, uint8_t leftDuration, uint8_t leftPower) {
550  uint8_t rumbleBuf[HID_BUFFERSIZE];
551  memcpy(rumbleBuf, HIDBuffer, HID_BUFFERSIZE);
552  rumbleBuf[3] = rightDuration;
553  rumbleBuf[4] = rightPower;
554  rumbleBuf[5] = leftDuration;
555  rumbleBuf[6] = leftPower;
556  HID_Command(rumbleBuf, HID_BUFFERSIZE);
557 }
558 
559 void PS3BT::setLedRaw(uint8_t value) {
560  HIDBuffer[11] = value << 1;
561  HID_Command(HIDBuffer, HID_BUFFERSIZE);
562 }
563 
565  HIDBuffer[11] &= ~((uint8_t)((pgm_read_byte(&PS3_LEDS[(uint8_t)a]) & 0x0f) << 1));
566  HID_Command(HIDBuffer, HID_BUFFERSIZE);
567 }
568 
570  if(a == OFF)
571  setLedRaw(0);
572  else {
573  HIDBuffer[11] |= (uint8_t)((pgm_read_byte(&PS3_LEDS[(uint8_t)a]) & 0x0f) << 1);
574  HID_Command(HIDBuffer, HID_BUFFERSIZE);
575  }
576 }
577 
579  HIDBuffer[11] ^= (uint8_t)((pgm_read_byte(&PS3_LEDS[(uint8_t)a]) & 0x0f) << 1);
580  HID_Command(HIDBuffer, HID_BUFFERSIZE);
581 }
582 
583 void PS3BT::enable_sixaxis() { // Command used to enable the Dualshock 3 and Navigation controller to send data via Bluetooth
584  uint8_t cmd_buf[6];
585  cmd_buf[0] = 0x53; // HID BT Set_report (0x50) | Report Type (Feature 0x03)
586  cmd_buf[1] = 0xF4; // Report ID
587  cmd_buf[2] = 0x42; // Special PS3 Controller enable commands
588  cmd_buf[3] = 0x03;
589  cmd_buf[4] = 0x00;
590  cmd_buf[5] = 0x00;
591 
592  HID_Command(cmd_buf, 6);
593 }
594 
595 // Playstation Move Controller commands
596 
597 void PS3BT::HIDMove_Command(uint8_t* data, uint8_t nbytes) {
598  if((int32_t)((uint32_t)millis() - timerHID) <= 150)// Check if is has been less than 150ms since last command
599  delay((uint32_t)(150 - ((uint32_t)millis() - timerHID))); // There have to be a delay between commands
600  pBtd->L2CAP_Command(hci_handle, data, nbytes, interrupt_scid[0], interrupt_scid[1]); // The Move controller sends it's data via the intterrupt channel
601  timerHID = (uint32_t)millis();
602 }
603 
604 void PS3BT::moveSetBulb(uint8_t r, uint8_t g, uint8_t b) { // Use this to set the Color using RGB values
605  // Set the Bulb's values into the write buffer
606  HIDMoveBuffer[3] = r;
607  HIDMoveBuffer[4] = g;
608  HIDMoveBuffer[5] = b;
609 
610  HIDMove_Command(HIDMoveBuffer, HID_BUFFERSIZE);
611 }
612 
613 void PS3BT::moveSetBulb(ColorsEnum color) { // Use this to set the Color using the predefined colors in enum
614  moveSetBulb((uint8_t)(color >> 16), (uint8_t)(color >> 8), (uint8_t)(color));
615 }
616 
617 void PS3BT::moveSetRumble(uint8_t rumble) {
618 #ifdef DEBUG_USB_HOST
619  if(rumble < 64 && rumble != 0) // The rumble value has to at least 64, or approximately 25% (64/255*100)
620  Notify(PSTR("\r\nThe rumble value has to at least 64, or approximately 25%"), 0x80);
621 #endif
622  // Set the rumble value into the write buffer
623  HIDMoveBuffer[7] = rumble;
624 
625  HIDMove_Command(HIDMoveBuffer, HID_BUFFERSIZE);
626 }
627 
629  if(pFuncOnInit)
630  pFuncOnInit(); // Call the user function
631  else {
632  if(PS3MoveConnected)
633  moveSetBulb(Red);
634  else // Dualshock 3 or Navigation controller
635  setLedOn(static_cast<LEDEnum>(LED1));
636  }
637 }
#define L2CAP_FLAG_DISCONNECT_CONTROL_RESPONSE
Definition: BTD.h:149
+
bool incomingWii
Definition: BTD.h:504
Definition: PS3Enums.h:124
#define pgm_read_dword(addr)
bool PS3NavigationConnected
Definition: PS3BT.h:184
-
#define L2CAP_FLAG_CONFIG_INTERRUPT_SUCCESS
Definition: BTD.h:144
-
#define L2CAP_INTERRUPT_CONFIG_REQUEST
Definition: BTD.h:116
-
#define L2CAP_INTERRUPT_SETUP
Definition: BTD.h:114
+
#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
bool getStatus(StatusEnum c)
Definition: PS3BT.cpp:156
-
void l2cap_connection_response(uint16_t handle, uint8_t rxid, uint8_t *dcid, uint8_t *scid, uint8_t result)
Definition: BTD.cpp:1260
+
void l2cap_connection_response(uint16_t handle, uint8_t rxid, uint8_t *dcid, uint8_t *scid, uint8_t result)
Definition: BTD.cpp:1488
void Run()
Definition: PS3BT.cpp:454
-
#define SUCCESSFUL
Definition: BTD.h:178
+
#define SUCCESSFUL
Definition: BTD.h:187
#define strcpy_P(dest, src)
-
#define L2CAP_FLAG_CONNECTION_INTERRUPT_REQUEST
Definition: BTD.h:143
-
Definition: BTD.h:201
+
#define L2CAP_FLAG_CONNECTION_INTERRUPT_REQUEST
Definition: BTD.h:152
+
Definition: BTD.h:221
void setLedOn(LEDEnum a)
Definition: PS3BT.cpp:569
-
void l2cap_disconnection_request(uint16_t handle, uint8_t rxid, uint8_t *dcid, uint8_t *scid)
Definition: BTD.cpp:1313
+
void l2cap_disconnection_request(uint16_t handle, uint8_t rxid, uint8_t *dcid, uint8_t *scid)
Definition: BTD.cpp:1541
-
uint8_t hci_version
Definition: BTD.h:464
- - -
bool pairWithWii
Definition: BTD.h:476
-
uint8_t identifier
Definition: BTD.h:621
+
uint8_t hci_version
Definition: BTD.h:494
+ + +
bool pairWithWii
Definition: BTD.h:506
+
uint8_t identifier
Definition: BTD.h:655
String getTemperature()
Definition: PS3BT.cpp:141
-
AnalogHatEnum
+
AnalogHatEnum
void moveSetRumble(uint8_t rumble)
Definition: PS3BT.cpp:617
-
#define TURN_ON_LED
Definition: BTD.h:130
- - +
#define TURN_ON_LED
Definition: BTD.h:139
+ +
void printStatusString()
Definition: PS3BT.cpp:160
void setAllOff()
Definition: PS3BT.cpp:519
- -
#define L2CAP_DONE
Definition: BTD.h:105
+ +
#define L2CAP_DONE
Definition: BTD.h:114
-
#define L2CAP_CONTROL_SUCCESS
Definition: BTD.h:110
-
#define L2CAP_WAIT
Definition: BTD.h:104
+
#define L2CAP_CONTROL_SUCCESS
Definition: BTD.h:119
+
#define L2CAP_WAIT
Definition: BTD.h:113
StatusEnum
Definition: PS3Enums.h:113
#define HID_BUFFERSIZE
Definition: PS3BT.h:24
void Reset()
Definition: PS3BT.cpp:204
#define pgm_read_byte(addr)
- -
char remote_name[30]
Definition: BTD.h:458
- + +
char remote_name[30]
Definition: BTD.h:488
+
const uint32_t PS3_BUTTONS[]
Definition: PS3Enums.h:62
bool getButtonPress(ButtonEnum b)
Definition: PS3BT.cpp:49
LEDEnum
int16_t getSensor(SensorEnum a)
Definition: PS3BT.cpp:68
-
void l2cap_disconnection_response(uint16_t handle, uint8_t rxid, uint8_t *dcid, uint8_t *scid)
Definition: BTD.cpp:1326
+
void l2cap_disconnection_response(uint16_t handle, uint8_t rxid, uint8_t *dcid, uint8_t *scid)
Definition: BTD.cpp:1554
#define Notify(...)
Definition: message.h:51
RumbleEnum
#define USB_HOST_SERIAL
Definition: settings.h:49
-
#define HID_CTRL_PSM
Definition: BTD.h:183
- +
#define HID_CTRL_PSM
Definition: BTD.h:192
+
Definition: PS3Enums.h:123
- -
bool connectToWii
Definition: BTD.h:470
+ +
bool connectToWii
Definition: BTD.h:500
uint8_t getAnalogHat(AnalogHatEnum a)
Definition: PS3BT.cpp:64
-
uint16_t hci_handle
Definition: BTD.h:454
+
uint16_t hci_handle
Definition: BTD.h:484
bool PS3Connected
Definition: PS3BT.h:176
-
void hci_disconnect(uint16_t handle)
Definition: BTD.cpp:1171
- -
#define L2CAP_FLAG_DISCONNECT_INTERRUPT_RESPONSE
Definition: BTD.h:146
- +
void hci_disconnect(uint16_t handle)
Definition: BTD.cpp:1399
+ +
#define L2CAP_FLAG_DISCONNECT_INTERRUPT_RESPONSE
Definition: BTD.h:155
+
ButtonEnum
void moveSetBulb(uint8_t r, uint8_t g, uint8_t b)
Definition: PS3BT.cpp:604
bool PS3MoveConnected
Definition: PS3BT.h:182
-
uint8_t my_bdaddr[6]
Definition: BTD.h:452
- +
uint8_t my_bdaddr[6]
Definition: BTD.h:482
+
void setRumbleOn(RumbleEnum mode)
Definition: PS3BT.cpp:540
-
void(* pFuncOnInit)(void)
Definition: BTD.h:609
+
void(* pFuncOnInit)(void)
Definition: BTD.h:643
float get9DOFValues(SensorEnum a)
Definition: PS3BT.cpp:112
const uint8_t PS3_LEDS[]
Definition: PS3Enums.h:43
-
#define l2cap_check_flag(flag)
Definition: BTD.h:161
+
#define l2cap_check_flag(flag)
Definition: BTD.h:170
-
#define L2CAP_CMD_CONFIG_REQUEST
Definition: BTD.h:169
+
#define L2CAP_CMD_CONFIG_REQUEST
Definition: BTD.h:178
#define PSTR(str)
-
#define L2CAP_CMD_DISCONNECT_REQUEST
Definition: BTD.h:171
-
#define L2CAP_CONTROL_DISCONNECT
Definition: BTD.h:111
-
#define L2CAP_FLAG_CONNECTION_CONTROL_REQUEST
Definition: BTD.h:137
+
#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
ColorsEnum
-
BTD * pBtd
Definition: BTD.h:612
+
BTD * pBtd
Definition: BTD.h:646
#define BULK_MAXPKTSIZE
Definition: BTD.h:37
- -
#define HID_INTR_PSM
Definition: BTD.h:184
+ +
#define HID_INTR_PSM
Definition: BTD.h:193
const uint8_t PS3_ANALOG_BUTTONS[]
Definition: PS3Enums.h:92
- -
bool l2capConnectionClaimed
Definition: BTD.h:440
-
AngleEnum
-
#define PS3_ENABLE_SIXAXIS
Definition: BTD.h:131
+ +
bool l2capConnectionClaimed
Definition: BTD.h:470
+
AngleEnum
+
#define PS3_ENABLE_SIXAXIS
Definition: BTD.h:140
-
#define L2CAP_CMD_DISCONNECT_RESPONSE
Definition: BTD.h:172
+
#define L2CAP_CMD_DISCONNECT_RESPONSE
Definition: BTD.h:181
void ACLData(uint8_t *ACLData)
Definition: PS3BT.cpp:224
-
#define L2CAP_CMD_CONFIG_RESPONSE
Definition: BTD.h:170
+
#define L2CAP_CMD_CONFIG_RESPONSE
Definition: BTD.h:179
-
uint16_t hci_handle
Definition: BTD.h:615
+
uint16_t hci_handle
Definition: BTD.h:649
void setLedOff()
Definition: PS3BT.h:138
#define strcat_P(dest, src)
void setLedToggle(LEDEnum a)
Definition: PS3BT.cpp:578
-
uint32_t l2cap_event_flag
Definition: BTD.h:618
+
uint32_t l2cap_event_flag
Definition: BTD.h:652
#define PS3_REPORT_BUFFER_SIZE
Definition: PS3Enums.h:24
void disconnect()
Definition: PS3BT.cpp:217
-
void L2CAP_Command(uint16_t handle, uint8_t *data, uint8_t nbytes, uint8_t channelLow=0x01, uint8_t channelHigh=0x00)
Definition: BTD.cpp:1219
-
void l2cap_config_response(uint16_t handle, uint8_t rxid, uint8_t *scid)
Definition: BTD.cpp:1294
-
#define PENDING
Definition: BTD.h:177
-
#define l2cap_set_flag(flag)
Definition: BTD.h:162
-
void l2cap_config_request(uint16_t handle, uint8_t rxid, uint8_t *dcid)
Definition: BTD.cpp:1277
-
#define L2CAP_FLAG_CONFIG_CONTROL_SUCCESS
Definition: BTD.h:138
-
SensorEnum
+
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_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
+
SensorEnum
-
#define L2CAP_CMD_CONNECTION_REQUEST
Definition: BTD.h:167
+
#define L2CAP_CMD_CONNECTION_REQUEST
Definition: BTD.h:176
uint8_t getAnalogButton(ButtonEnum a)
Definition: PS3BT.cpp:60
- +
float getAngle(AngleEnum a)
Definition: PS3BT.cpp:85
void setLedRaw(uint8_t value)
Definition: PS3BT.cpp:559
PS3BT(BTD *pBtd, uint8_t btadr5=0, uint8_t btadr4=0, uint8_t btadr3=0, uint8_t btadr2=0, uint8_t btadr1=0, uint8_t btadr0=0)
Definition: PS3BT.cpp:23
- -
bool checkHciHandle(uint8_t *buf, uint16_t handle)
Definition: BTD.h:604
+ +
bool checkHciHandle(uint8_t *buf, uint16_t handle)
Definition: BTD.h:638
void onInit()
Definition: PS3BT.cpp:628
Definition: PS3Enums.h:125
-
#define L2CAP_INTERRUPT_DISCONNECT
Definition: BTD.h:117
+
#define L2CAP_INTERRUPT_DISCONNECT
Definition: BTD.h:126
void setRumbleOff()
Definition: PS3BT.cpp:530
bool getButtonClick(ButtonEnum b)
Definition: PS3BT.cpp:53
const uint8_t PS3_REPORT_BUFFER[PS3_REPORT_BUFFER_SIZE]
Definition: PS3Enums.h:27
-
#define L2CAP_CMD_COMMAND_REJECT
Definition: BTD.h:166
+
#define L2CAP_CMD_COMMAND_REJECT
Definition: BTD.h:175
-Go to the documentation of this file.
1 /* Copyright (C) 2012 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 "SPP.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 sent to the Arduino
22 
23 /*
24  * CRC (reversed crc) lookup table as calculated by the table generator in ETSI TS 101 369 V6.3.0.
25  */
26 const uint8_t rfcomm_crc_table[256] PROGMEM = {/* reversed, 8-bit, poly=0x07 */
27  0x00, 0x91, 0xE3, 0x72, 0x07, 0x96, 0xE4, 0x75, 0x0E, 0x9F, 0xED, 0x7C, 0x09, 0x98, 0xEA, 0x7B,
28  0x1C, 0x8D, 0xFF, 0x6E, 0x1B, 0x8A, 0xF8, 0x69, 0x12, 0x83, 0xF1, 0x60, 0x15, 0x84, 0xF6, 0x67,
29  0x38, 0xA9, 0xDB, 0x4A, 0x3F, 0xAE, 0xDC, 0x4D, 0x36, 0xA7, 0xD5, 0x44, 0x31, 0xA0, 0xD2, 0x43,
30  0x24, 0xB5, 0xC7, 0x56, 0x23, 0xB2, 0xC0, 0x51, 0x2A, 0xBB, 0xC9, 0x58, 0x2D, 0xBC, 0xCE, 0x5F,
31  0x70, 0xE1, 0x93, 0x02, 0x77, 0xE6, 0x94, 0x05, 0x7E, 0xEF, 0x9D, 0x0C, 0x79, 0xE8, 0x9A, 0x0B,
32  0x6C, 0xFD, 0x8F, 0x1E, 0x6B, 0xFA, 0x88, 0x19, 0x62, 0xF3, 0x81, 0x10, 0x65, 0xF4, 0x86, 0x17,
33  0x48, 0xD9, 0xAB, 0x3A, 0x4F, 0xDE, 0xAC, 0x3D, 0x46, 0xD7, 0xA5, 0x34, 0x41, 0xD0, 0xA2, 0x33,
34  0x54, 0xC5, 0xB7, 0x26, 0x53, 0xC2, 0xB0, 0x21, 0x5A, 0xCB, 0xB9, 0x28, 0x5D, 0xCC, 0xBE, 0x2F,
35  0xE0, 0x71, 0x03, 0x92, 0xE7, 0x76, 0x04, 0x95, 0xEE, 0x7F, 0x0D, 0x9C, 0xE9, 0x78, 0x0A, 0x9B,
36  0xFC, 0x6D, 0x1F, 0x8E, 0xFB, 0x6A, 0x18, 0x89, 0xF2, 0x63, 0x11, 0x80, 0xF5, 0x64, 0x16, 0x87,
37  0xD8, 0x49, 0x3B, 0xAA, 0xDF, 0x4E, 0x3C, 0xAD, 0xD6, 0x47, 0x35, 0xA4, 0xD1, 0x40, 0x32, 0xA3,
38  0xC4, 0x55, 0x27, 0xB6, 0xC3, 0x52, 0x20, 0xB1, 0xCA, 0x5B, 0x29, 0xB8, 0xCD, 0x5C, 0x2E, 0xBF,
39  0x90, 0x01, 0x73, 0xE2, 0x97, 0x06, 0x74, 0xE5, 0x9E, 0x0F, 0x7D, 0xEC, 0x99, 0x08, 0x7A, 0xEB,
40  0x8C, 0x1D, 0x6F, 0xFE, 0x8B, 0x1A, 0x68, 0xF9, 0x82, 0x13, 0x61, 0xF0, 0x85, 0x14, 0x66, 0xF7,
41  0xA8, 0x39, 0x4B, 0xDA, 0xAF, 0x3E, 0x4C, 0xDD, 0xA6, 0x37, 0x45, 0xD4, 0xA1, 0x30, 0x42, 0xD3,
42  0xB4, 0x25, 0x57, 0xC6, 0xB3, 0x22, 0x50, 0xC1, 0xBA, 0x2B, 0x59, 0xC8, 0xBD, 0x2C, 0x5E, 0xCF
43 };
44 
45 SPP::SPP(BTD *p, const char* name, const char* pin) :
46 BluetoothService(p) // Pointer to BTD class instance - mandatory
47 {
48  pBtd->btdName = name;
49  pBtd->btdPin = pin;
50 
51  /* Set device cid for the SDP and RFCOMM channelse */
52  sdp_dcid[0] = 0x50; // 0x0050
53  sdp_dcid[1] = 0x00;
54  rfcomm_dcid[0] = 0x51; // 0x0051
55  rfcomm_dcid[1] = 0x00;
56 
57  Reset();
58 }
59 
60 void SPP::Reset() {
61  connected = false;
62  RFCOMMConnected = false;
63  SDPConnected = false;
64  waitForLastCommand = false;
65  l2cap_sdp_state = L2CAP_SDP_WAIT;
66  l2cap_rfcomm_state = L2CAP_RFCOMM_WAIT;
67  l2cap_event_flag = 0;
68  sppIndex = 0;
69  creditSent = false;
70 }
71 
73  connected = false;
74  // First the two L2CAP channels has to be disconnected and then the HCI connection
75  if(RFCOMMConnected)
76  pBtd->l2cap_disconnection_request(hci_handle, ++identifier, rfcomm_scid, rfcomm_dcid);
77  if(RFCOMMConnected && SDPConnected)
78  delay(1); // Add delay between commands
79  if(SDPConnected)
80  pBtd->l2cap_disconnection_request(hci_handle, ++identifier, sdp_scid, sdp_dcid);
81  l2cap_sdp_state = L2CAP_DISCONNECT_RESPONSE;
82 }
83 
84 void SPP::ACLData(uint8_t* l2capinbuf) {
85  if(!connected) {
86  if(l2capinbuf[8] == L2CAP_CMD_CONNECTION_REQUEST) {
87  if((l2capinbuf[12] | (l2capinbuf[13] << 8)) == SDP_PSM && !pBtd->sdpConnectionClaimed) {
88  pBtd->sdpConnectionClaimed = true;
89  hci_handle = pBtd->hci_handle; // Store the HCI Handle for the connection
90  l2cap_sdp_state = L2CAP_SDP_WAIT; // Reset state
91  } else if((l2capinbuf[12] | (l2capinbuf[13] << 8)) == RFCOMM_PSM && !pBtd->rfcommConnectionClaimed) {
93  hci_handle = pBtd->hci_handle; // Store the HCI Handle for the connection
94  l2cap_rfcomm_state = L2CAP_RFCOMM_WAIT; // Reset state
95  }
96  }
97  }
98 
99  if(checkHciHandle(l2capinbuf, hci_handle)) { // acl_handle_ok
100  if((l2capinbuf[6] | (l2capinbuf[7] << 8)) == 0x0001U) { // l2cap_control - Channel ID for ACL-U
101  if(l2capinbuf[8] == L2CAP_CMD_COMMAND_REJECT) {
102 #ifdef DEBUG_USB_HOST
103  Notify(PSTR("\r\nL2CAP Command Rejected - Reason: "), 0x80);
104  D_PrintHex<uint8_t > (l2capinbuf[13], 0x80);
105  Notify(PSTR(" "), 0x80);
106  D_PrintHex<uint8_t > (l2capinbuf[12], 0x80);
107  Notify(PSTR(" Data: "), 0x80);
108  D_PrintHex<uint8_t > (l2capinbuf[17], 0x80);
109  Notify(PSTR(" "), 0x80);
110  D_PrintHex<uint8_t > (l2capinbuf[16], 0x80);
111  Notify(PSTR(" "), 0x80);
112  D_PrintHex<uint8_t > (l2capinbuf[15], 0x80);
113  Notify(PSTR(" "), 0x80);
114  D_PrintHex<uint8_t > (l2capinbuf[14], 0x80);
115 #endif
116  } else if(l2capinbuf[8] == L2CAP_CMD_CONNECTION_REQUEST) {
117 #ifdef EXTRADEBUG
118  Notify(PSTR("\r\nL2CAP Connection Request - PSM: "), 0x80);
119  D_PrintHex<uint8_t > (l2capinbuf[13], 0x80);
120  Notify(PSTR(" "), 0x80);
121  D_PrintHex<uint8_t > (l2capinbuf[12], 0x80);
122  Notify(PSTR(" SCID: "), 0x80);
123  D_PrintHex<uint8_t > (l2capinbuf[15], 0x80);
124  Notify(PSTR(" "), 0x80);
125  D_PrintHex<uint8_t > (l2capinbuf[14], 0x80);
126  Notify(PSTR(" Identifier: "), 0x80);
127  D_PrintHex<uint8_t > (l2capinbuf[9], 0x80);
128 #endif
129  if((l2capinbuf[12] | (l2capinbuf[13] << 8)) == SDP_PSM) { // It doesn't matter if it receives another reqeust, since it waits for the channel to disconnect in the L2CAP_SDP_DONE state, and the l2cap_event_flag will be cleared if so
130  identifier = l2capinbuf[9];
131  sdp_scid[0] = l2capinbuf[14];
132  sdp_scid[1] = l2capinbuf[15];
134  } else if((l2capinbuf[12] | (l2capinbuf[13] << 8)) == RFCOMM_PSM) { // ----- || -----
135  identifier = l2capinbuf[9];
136  rfcomm_scid[0] = l2capinbuf[14];
137  rfcomm_scid[1] = l2capinbuf[15];
139  }
140  } else if(l2capinbuf[8] == L2CAP_CMD_CONFIG_RESPONSE) {
141  if((l2capinbuf[16] | (l2capinbuf[17] << 8)) == 0x0000) { // Success
142  if(l2capinbuf[12] == sdp_dcid[0] && l2capinbuf[13] == sdp_dcid[1]) {
143  //Notify(PSTR("\r\nSDP Configuration Complete"), 0x80);
145  } else if(l2capinbuf[12] == rfcomm_dcid[0] && l2capinbuf[13] == rfcomm_dcid[1]) {
146  //Notify(PSTR("\r\nRFCOMM Configuration Complete"), 0x80);
148  }
149  }
150  } else if(l2capinbuf[8] == L2CAP_CMD_CONFIG_REQUEST) {
151  if(l2capinbuf[12] == sdp_dcid[0] && l2capinbuf[13] == sdp_dcid[1]) {
152  //Notify(PSTR("\r\nSDP Configuration Request"), 0x80);
153  pBtd->l2cap_config_response(hci_handle, l2capinbuf[9], sdp_scid);
154  } else if(l2capinbuf[12] == rfcomm_dcid[0] && l2capinbuf[13] == rfcomm_dcid[1]) {
155  //Notify(PSTR("\r\nRFCOMM Configuration Request"), 0x80);
156  pBtd->l2cap_config_response(hci_handle, l2capinbuf[9], rfcomm_scid);
157  }
158  } else if(l2capinbuf[8] == L2CAP_CMD_DISCONNECT_REQUEST) {
159  if(l2capinbuf[12] == sdp_dcid[0] && l2capinbuf[13] == sdp_dcid[1]) {
160  //Notify(PSTR("\r\nDisconnect Request: SDP Channel"), 0x80);
161  identifier = l2capinbuf[9];
163  } else if(l2capinbuf[12] == rfcomm_dcid[0] && l2capinbuf[13] == rfcomm_dcid[1]) {
164  //Notify(PSTR("\r\nDisconnect Request: RFCOMM Channel"), 0x80);
165  identifier = l2capinbuf[9];
167  }
168  } else if(l2capinbuf[8] == L2CAP_CMD_DISCONNECT_RESPONSE) {
169  if(l2capinbuf[12] == sdp_scid[0] && l2capinbuf[13] == sdp_scid[1]) {
170  //Notify(PSTR("\r\nDisconnect Response: SDP Channel"), 0x80);
171  identifier = l2capinbuf[9];
173  } else if(l2capinbuf[12] == rfcomm_scid[0] && l2capinbuf[13] == rfcomm_scid[1]) {
174  //Notify(PSTR("\r\nDisconnect Response: RFCOMM Channel"), 0x80);
175  identifier = l2capinbuf[9];
177  }
178  } else if(l2capinbuf[8] == L2CAP_CMD_INFORMATION_REQUEST) {
179 #ifdef DEBUG_USB_HOST
180  Notify(PSTR("\r\nInformation request"), 0x80);
181 #endif
182  identifier = l2capinbuf[9];
183  pBtd->l2cap_information_response(hci_handle, identifier, l2capinbuf[12], l2capinbuf[13]);
184  }
185 #ifdef EXTRADEBUG
186  else {
187  Notify(PSTR("\r\nL2CAP Unknown Signaling Command: "), 0x80);
188  D_PrintHex<uint8_t > (l2capinbuf[8], 0x80);
189  }
190 #endif
191  } else if(l2capinbuf[6] == sdp_dcid[0] && l2capinbuf[7] == sdp_dcid[1]) { // SDP
192  if(l2capinbuf[8] == SDP_SERVICE_SEARCH_ATTRIBUTE_REQUEST_PDU) {
193  if(((l2capinbuf[16] << 8 | l2capinbuf[17]) == SERIALPORT_UUID) || ((l2capinbuf[16] << 8 | l2capinbuf[17]) == 0x0000 && (l2capinbuf[18] << 8 | l2capinbuf[19]) == SERIALPORT_UUID)) { // Check if it's sending the full UUID, see: https://www.bluetooth.org/Technical/AssignedNumbers/service_discovery.htm, we will just check the first four bytes
194  if(firstMessage) {
195  serialPortResponse1(l2capinbuf[9], l2capinbuf[10]);
196  firstMessage = false;
197  } else {
198  serialPortResponse2(l2capinbuf[9], l2capinbuf[10]); // Serialport continuation state
199  firstMessage = true;
200  }
201  } else if(((l2capinbuf[16] << 8 | l2capinbuf[17]) == L2CAP_UUID) || ((l2capinbuf[16] << 8 | l2capinbuf[17]) == 0x0000 && (l2capinbuf[18] << 8 | l2capinbuf[19]) == L2CAP_UUID)) {
202  if(firstMessage) {
203  l2capResponse1(l2capinbuf[9], l2capinbuf[10]);
204  firstMessage = false;
205  } else {
206  l2capResponse2(l2capinbuf[9], l2capinbuf[10]); // L2CAP continuation state
207  firstMessage = true;
208  }
209  } else
210  serviceNotSupported(l2capinbuf[9], l2capinbuf[10]); // The service is not supported
211 #ifdef EXTRADEBUG
212  Notify(PSTR("\r\nUUID: "), 0x80);
213  uint16_t uuid;
214  if((l2capinbuf[16] << 8 | l2capinbuf[17]) == 0x0000) // Check if it's sending the UUID as a 128-bit UUID
215  uuid = (l2capinbuf[18] << 8 | l2capinbuf[19]);
216  else // Short UUID
217  uuid = (l2capinbuf[16] << 8 | l2capinbuf[17]);
218  D_PrintHex<uint16_t > (uuid, 0x80);
219 
220  Notify(PSTR("\r\nLength: "), 0x80);
221  uint16_t length = l2capinbuf[11] << 8 | l2capinbuf[12];
222  D_PrintHex<uint16_t > (length, 0x80);
223  Notify(PSTR("\r\nData: "), 0x80);
224  for(uint8_t i = 0; i < length; i++) {
225  D_PrintHex<uint8_t > (l2capinbuf[13 + i], 0x80);
226  Notify(PSTR(" "), 0x80);
227  }
228 #endif
229  }
230 #ifdef EXTRADEBUG
231  else {
232  Notify(PSTR("\r\nUnknown PDU: "), 0x80);
233  D_PrintHex<uint8_t > (l2capinbuf[8], 0x80);
234  }
235 #endif
236  } else if(l2capinbuf[6] == rfcomm_dcid[0] && l2capinbuf[7] == rfcomm_dcid[1]) { // RFCOMM
237  rfcommChannel = l2capinbuf[8] & 0xF8;
238  rfcommDirection = l2capinbuf[8] & 0x04;
239  rfcommCommandResponse = l2capinbuf[8] & 0x02;
240  rfcommChannelType = l2capinbuf[9] & 0xEF;
241  rfcommPfBit = l2capinbuf[9] & 0x10;
242 
243  if(rfcommChannel >> 3 != 0x00)
244  rfcommChannelConnection = rfcommChannel;
245 
246 #ifdef EXTRADEBUG
247  Notify(PSTR("\r\nRFCOMM Channel: "), 0x80);
248  D_PrintHex<uint8_t > (rfcommChannel >> 3, 0x80);
249  Notify(PSTR(" Direction: "), 0x80);
250  D_PrintHex<uint8_t > (rfcommDirection >> 2, 0x80);
251  Notify(PSTR(" CommandResponse: "), 0x80);
252  D_PrintHex<uint8_t > (rfcommCommandResponse >> 1, 0x80);
253  Notify(PSTR(" ChannelType: "), 0x80);
254  D_PrintHex<uint8_t > (rfcommChannelType, 0x80);
255  Notify(PSTR(" PF_BIT: "), 0x80);
256  D_PrintHex<uint8_t > (rfcommPfBit, 0x80);
257 #endif
258  if(rfcommChannelType == RFCOMM_DISC) {
259 #ifdef DEBUG_USB_HOST
260  Notify(PSTR("\r\nReceived Disconnect RFCOMM Command on channel: "), 0x80);
261  D_PrintHex<uint8_t > (rfcommChannel >> 3, 0x80);
262 #endif
263  connected = false;
264  sendRfcomm(rfcommChannel, rfcommDirection, rfcommCommandResponse, RFCOMM_UA, rfcommPfBit, rfcommbuf, 0x00); // UA Command
265  }
266  if(connected) {
267  /* Read the incoming message */
268  if(rfcommChannelType == RFCOMM_UIH && rfcommChannel == rfcommChannelConnection) {
269  uint8_t length = l2capinbuf[10] >> 1; // Get length
270  uint8_t offset = l2capinbuf[4] - length - 4; // Check if there is credit
271  if(checkFcs(&l2capinbuf[8], l2capinbuf[11 + length + offset])) {
272  uint8_t i = 0;
273  for(; i < length; i++) {
274  if(rfcommAvailable + i >= sizeof (rfcommDataBuffer)) {
275 #ifdef DEBUG_USB_HOST
276  Notify(PSTR("\r\nWarning: Buffer is full!"), 0x80);
277 #endif
278  break;
279  }
280  rfcommDataBuffer[rfcommAvailable + i] = l2capinbuf[11 + i + offset];
281  }
282  rfcommAvailable += i;
283 #ifdef EXTRADEBUG
284  Notify(PSTR("\r\nRFCOMM Data Available: "), 0x80);
285  Notify(rfcommAvailable, 0x80);
286  if(offset) {
287  Notify(PSTR(" - Credit: 0x"), 0x80);
288  D_PrintHex<uint8_t > (l2capinbuf[11], 0x80);
289  }
290 #endif
291  }
292 #ifdef DEBUG_USB_HOST
293  else
294  Notify(PSTR("\r\nError in FCS checksum!"), 0x80);
295 #endif
296 #ifdef PRINTREPORT // Uncomment "#define PRINTREPORT" to print the report send to the Arduino via Bluetooth
297  for(uint8_t i = 0; i < length; i++)
298  Notifyc(l2capinbuf[i + 11 + offset], 0x80);
299 #endif
300  } else if(rfcommChannelType == RFCOMM_UIH && l2capinbuf[11] == BT_RFCOMM_RPN_CMD) { // UIH Remote Port Negotiation Command
301 #ifdef DEBUG_USB_HOST
302  Notify(PSTR("\r\nReceived UIH Remote Port Negotiation Command"), 0x80);
303 #endif
304  rfcommbuf[0] = BT_RFCOMM_RPN_RSP; // Command
305  rfcommbuf[1] = l2capinbuf[12]; // Length and shiftet like so: length << 1 | 1
306  rfcommbuf[2] = l2capinbuf[13]; // Channel: channel << 1 | 1
307  rfcommbuf[3] = l2capinbuf[14]; // Pre difined for Bluetooth, see 5.5.3 of TS 07.10 Adaption for RFCOMM
308  rfcommbuf[4] = l2capinbuf[15]; // Priority
309  rfcommbuf[5] = l2capinbuf[16]; // Timer
310  rfcommbuf[6] = l2capinbuf[17]; // Max Fram Size LSB
311  rfcommbuf[7] = l2capinbuf[18]; // Max Fram Size MSB
312  rfcommbuf[8] = l2capinbuf[19]; // MaxRatransm.
313  rfcommbuf[9] = l2capinbuf[20]; // Number of Frames
314  sendRfcomm(rfcommChannel, rfcommDirection, 0, RFCOMM_UIH, rfcommPfBit, rfcommbuf, 0x0A); // UIH Remote Port Negotiation Response
315  } else if(rfcommChannelType == RFCOMM_UIH && l2capinbuf[11] == BT_RFCOMM_MSC_CMD) { // UIH Modem Status Command
316 #ifdef DEBUG_USB_HOST
317  Notify(PSTR("\r\nSend UIH Modem Status Response"), 0x80);
318 #endif
319  rfcommbuf[0] = BT_RFCOMM_MSC_RSP; // UIH Modem Status Response
320  rfcommbuf[1] = 2 << 1 | 1; // Length and shiftet like so: length << 1 | 1
321  rfcommbuf[2] = l2capinbuf[13]; // Channel: (1 << 0) | (1 << 1) | (0 << 2) | (channel << 3)
322  rfcommbuf[3] = l2capinbuf[14];
323  sendRfcomm(rfcommChannel, rfcommDirection, 0, RFCOMM_UIH, rfcommPfBit, rfcommbuf, 0x04);
324  }
325  } else {
326  if(rfcommChannelType == RFCOMM_SABM) { // SABM Command - this is sent twice: once for channel 0 and then for the channel to establish
327 #ifdef DEBUG_USB_HOST
328  Notify(PSTR("\r\nReceived SABM Command"), 0x80);
329 #endif
330  sendRfcomm(rfcommChannel, rfcommDirection, rfcommCommandResponse, RFCOMM_UA, rfcommPfBit, rfcommbuf, 0x00); // UA Command
331  } else if(rfcommChannelType == RFCOMM_UIH && l2capinbuf[11] == BT_RFCOMM_PN_CMD) { // UIH Parameter Negotiation Command
332 #ifdef DEBUG_USB_HOST
333  Notify(PSTR("\r\nReceived UIH Parameter Negotiation Command"), 0x80);
334 #endif
335  rfcommbuf[0] = BT_RFCOMM_PN_RSP; // UIH Parameter Negotiation Response
336  rfcommbuf[1] = l2capinbuf[12]; // Length and shiftet like so: length << 1 | 1
337  rfcommbuf[2] = l2capinbuf[13]; // Channel: channel << 1 | 1
338  rfcommbuf[3] = 0xE0; // Pre difined for Bluetooth, see 5.5.3 of TS 07.10 Adaption for RFCOMM
339  rfcommbuf[4] = 0x00; // Priority
340  rfcommbuf[5] = 0x00; // Timer
341  rfcommbuf[6] = BULK_MAXPKTSIZE - 14; // Max Fram Size LSB - set to the size of received data (50)
342  rfcommbuf[7] = 0x00; // Max Fram Size MSB
343  rfcommbuf[8] = 0x00; // MaxRatransm.
344  rfcommbuf[9] = 0x00; // Number of Frames
345  sendRfcomm(rfcommChannel, rfcommDirection, 0, RFCOMM_UIH, rfcommPfBit, rfcommbuf, 0x0A);
346  } else if(rfcommChannelType == RFCOMM_UIH && l2capinbuf[11] == BT_RFCOMM_MSC_CMD) { // UIH Modem Status Command
347 #ifdef DEBUG_USB_HOST
348  Notify(PSTR("\r\nSend UIH Modem Status Response"), 0x80);
349 #endif
350  rfcommbuf[0] = BT_RFCOMM_MSC_RSP; // UIH Modem Status Response
351  rfcommbuf[1] = 2 << 1 | 1; // Length and shiftet like so: length << 1 | 1
352  rfcommbuf[2] = l2capinbuf[13]; // Channel: (1 << 0) | (1 << 1) | (0 << 2) | (channel << 3)
353  rfcommbuf[3] = l2capinbuf[14];
354  sendRfcomm(rfcommChannel, rfcommDirection, 0, RFCOMM_UIH, rfcommPfBit, rfcommbuf, 0x04);
355 
356  delay(1);
357 #ifdef DEBUG_USB_HOST
358  Notify(PSTR("\r\nSend UIH Modem Status Command"), 0x80);
359 #endif
360  rfcommbuf[0] = BT_RFCOMM_MSC_CMD; // UIH Modem Status Command
361  rfcommbuf[1] = 2 << 1 | 1; // Length and shiftet like so: length << 1 | 1
362  rfcommbuf[2] = l2capinbuf[13]; // Channel: (1 << 0) | (1 << 1) | (0 << 2) | (channel << 3)
363  rfcommbuf[3] = 0x8D; // Can receive frames (YES), Ready to Communicate (YES), Ready to Receive (YES), Incomig Call (NO), Data is Value (YES)
364 
365  sendRfcomm(rfcommChannel, rfcommDirection, 0, RFCOMM_UIH, rfcommPfBit, rfcommbuf, 0x04);
366  } else if(rfcommChannelType == RFCOMM_UIH && l2capinbuf[11] == BT_RFCOMM_MSC_RSP) { // UIH Modem Status Response
367  if(!creditSent) {
368 #ifdef DEBUG_USB_HOST
369  Notify(PSTR("\r\nSend UIH Command with credit"), 0x80);
370 #endif
371  sendRfcommCredit(rfcommChannelConnection, rfcommDirection, 0, RFCOMM_UIH, 0x10, sizeof (rfcommDataBuffer)); // Send credit
372  creditSent = true;
373  timer = (uint32_t)millis();
374  waitForLastCommand = true;
375  }
376  } else if(rfcommChannelType == RFCOMM_UIH && l2capinbuf[10] == 0x01) { // UIH Command with credit
377 #ifdef DEBUG_USB_HOST
378  Notify(PSTR("\r\nReceived UIH Command with credit"), 0x80);
379 #endif
380  } else if(rfcommChannelType == RFCOMM_UIH && l2capinbuf[11] == BT_RFCOMM_RPN_CMD) { // UIH Remote Port Negotiation Command
381 #ifdef DEBUG_USB_HOST
382  Notify(PSTR("\r\nReceived UIH Remote Port Negotiation Command"), 0x80);
383 #endif
384  rfcommbuf[0] = BT_RFCOMM_RPN_RSP; // Command
385  rfcommbuf[1] = l2capinbuf[12]; // Length and shiftet like so: length << 1 | 1
386  rfcommbuf[2] = l2capinbuf[13]; // Channel: channel << 1 | 1
387  rfcommbuf[3] = l2capinbuf[14]; // Pre difined for Bluetooth, see 5.5.3 of TS 07.10 Adaption for RFCOMM
388  rfcommbuf[4] = l2capinbuf[15]; // Priority
389  rfcommbuf[5] = l2capinbuf[16]; // Timer
390  rfcommbuf[6] = l2capinbuf[17]; // Max Fram Size LSB
391  rfcommbuf[7] = l2capinbuf[18]; // Max Fram Size MSB
392  rfcommbuf[8] = l2capinbuf[19]; // MaxRatransm.
393  rfcommbuf[9] = l2capinbuf[20]; // Number of Frames
394  sendRfcomm(rfcommChannel, rfcommDirection, 0, RFCOMM_UIH, rfcommPfBit, rfcommbuf, 0x0A); // UIH Remote Port Negotiation Response
395 #ifdef DEBUG_USB_HOST
396  Notify(PSTR("\r\nRFCOMM Connection is now established\r\n"), 0x80);
397 #endif
398  onInit();
399  }
400 #ifdef EXTRADEBUG
401  else if(rfcommChannelType != RFCOMM_DISC) {
402  Notify(PSTR("\r\nUnsupported RFCOMM Data - ChannelType: "), 0x80);
403  D_PrintHex<uint8_t > (rfcommChannelType, 0x80);
404  Notify(PSTR(" Command: "), 0x80);
405  D_PrintHex<uint8_t > (l2capinbuf[11], 0x80);
406  }
407 #endif
408  }
409  }
410 #ifdef EXTRADEBUG
411  else {
412  Notify(PSTR("\r\nUnsupported L2CAP Data - Channel ID: "), 0x80);
413  D_PrintHex<uint8_t > (l2capinbuf[7], 0x80);
414  Notify(PSTR(" "), 0x80);
415  D_PrintHex<uint8_t > (l2capinbuf[6], 0x80);
416  }
417 #endif
418  SDP_task();
419  RFCOMM_task();
420  }
421 }
422 
423 void SPP::Run() {
424  if(waitForLastCommand && (int32_t)((uint32_t)millis() - timer) > 100) { // We will only wait 100ms and see if the UIH Remote Port Negotiation Command is send, as some deviced don't send it
425 #ifdef DEBUG_USB_HOST
426  Notify(PSTR("\r\nRFCOMM Connection is now established - Automatic\r\n"), 0x80);
427 #endif
428  onInit();
429  }
430  send(); // Send all bytes currently in the buffer
431 }
432 
433 void SPP::onInit() {
434  creditSent = false;
435  waitForLastCommand = false;
436  connected = true; // The RFCOMM channel is now established
437  sppIndex = 0;
438  if(pFuncOnInit)
439  pFuncOnInit(); // Call the user function
440 };
441 
442 void SPP::SDP_task() {
443  switch(l2cap_sdp_state) {
444  case L2CAP_SDP_WAIT:
447 #ifdef DEBUG_USB_HOST
448  Notify(PSTR("\r\nSDP Incoming Connection Request"), 0x80);
449 #endif
451  delay(1);
453  identifier++;
454  delay(1);
456  l2cap_sdp_state = L2CAP_SDP_SUCCESS;
459  SDPConnected = false;
460 #ifdef DEBUG_USB_HOST
461  Notify(PSTR("\r\nDisconnected SDP Channel"), 0x80);
462 #endif
464  }
465  break;
466  case L2CAP_SDP_SUCCESS:
469 #ifdef DEBUG_USB_HOST
470  Notify(PSTR("\r\nSDP Successfully Configured"), 0x80);
471 #endif
472  firstMessage = true; // Reset bool
473  SDPConnected = true;
474  l2cap_sdp_state = L2CAP_SDP_WAIT;
475  }
476  break;
477 
478  case L2CAP_DISCONNECT_RESPONSE: // This is for both disconnection response from the RFCOMM and SDP channel if they were connected
480 #ifdef DEBUG_USB_HOST
481  Notify(PSTR("\r\nDisconnected L2CAP Connection"), 0x80);
482 #endif
484  hci_handle = -1; // Reset handle
485  Reset();
486  }
487  break;
488  }
489 }
490 
491 void SPP::RFCOMM_task() {
492  switch(l2cap_rfcomm_state) {
493  case L2CAP_RFCOMM_WAIT:
496 #ifdef DEBUG_USB_HOST
497  Notify(PSTR("\r\nRFCOMM Incoming Connection Request"), 0x80);
498 #endif
499  pBtd->l2cap_connection_response(hci_handle, identifier, rfcomm_dcid, rfcomm_scid, PENDING);
500  delay(1);
501  pBtd->l2cap_connection_response(hci_handle, identifier, rfcomm_dcid, rfcomm_scid, SUCCESSFUL);
502  identifier++;
503  delay(1);
505  l2cap_rfcomm_state = L2CAP_RFCOMM_SUCCESS;
508  RFCOMMConnected = false;
509  connected = false;
510 #ifdef DEBUG_USB_HOST
511  Notify(PSTR("\r\nDisconnected RFCOMM Channel"), 0x80);
512 #endif
513  pBtd->l2cap_disconnection_response(hci_handle, identifier, rfcomm_dcid, rfcomm_scid);
514  }
515  break;
519 #ifdef DEBUG_USB_HOST
520  Notify(PSTR("\r\nRFCOMM Successfully Configured"), 0x80);
521 #endif
522  rfcommAvailable = 0; // Reset number of bytes available
523  bytesRead = 0; // Reset number of bytes received
524  RFCOMMConnected = true;
525  l2cap_rfcomm_state = L2CAP_RFCOMM_WAIT;
526  }
527  break;
528  }
529 }
530 /************************************************************/
531 /* SDP Commands */
532 
533 /************************************************************/
534 void SPP::SDP_Command(uint8_t* data, uint8_t nbytes) { // See page 223 in the Bluetooth specs
535  pBtd->L2CAP_Command(hci_handle, data, nbytes, sdp_scid[0], sdp_scid[1]);
536 }
537 
538 void SPP::serviceNotSupported(uint8_t transactionIDHigh, uint8_t transactionIDLow) { // See page 235 in the Bluetooth specs
540  l2capoutbuf[1] = transactionIDHigh;
541  l2capoutbuf[2] = transactionIDLow;
542  l2capoutbuf[3] = 0x00; // MSB Parameter Length
543  l2capoutbuf[4] = 0x05; // LSB Parameter Length = 5
544  l2capoutbuf[5] = 0x00; // MSB AttributeListsByteCount
545  l2capoutbuf[6] = 0x02; // LSB AttributeListsByteCount = 2
546 
547  /* Attribute ID/Value Sequence: */
548  l2capoutbuf[7] = 0x35; // Data element sequence - length in next byte
549  l2capoutbuf[8] = 0x00; // Length = 0
550  l2capoutbuf[9] = 0x00; // No continuation state
551 
552  SDP_Command(l2capoutbuf, 10);
553 }
554 
555 void SPP::serialPortResponse1(uint8_t transactionIDHigh, uint8_t transactionIDLow) {
557  l2capoutbuf[1] = transactionIDHigh;
558  l2capoutbuf[2] = transactionIDLow;
559  l2capoutbuf[3] = 0x00; // MSB Parameter Length
560  l2capoutbuf[4] = 0x2B; // LSB Parameter Length = 43
561  l2capoutbuf[5] = 0x00; // MSB AttributeListsByteCount
562  l2capoutbuf[6] = 0x26; // LSB AttributeListsByteCount = 38
563 
564  /* Attribute ID/Value Sequence: */
565  l2capoutbuf[7] = 0x36; // Data element sequence - length in next two bytes
566  l2capoutbuf[8] = 0x00; // MSB Length
567  l2capoutbuf[9] = 0x3C; // LSB Length = 60
568 
569  l2capoutbuf[10] = 0x36; // Data element sequence - length in next two bytes
570  l2capoutbuf[11] = 0x00; // MSB Length
571  l2capoutbuf[12] = 0x39; // LSB Length = 57
572 
573  l2capoutbuf[13] = 0x09; // Unsigned Integer - length 2 bytes
574  l2capoutbuf[14] = 0x00; // MSB ServiceRecordHandle
575  l2capoutbuf[15] = 0x00; // LSB ServiceRecordHandle
576  l2capoutbuf[16] = 0x0A; // Unsigned int - length 4 bytes
577  l2capoutbuf[17] = 0x00; // ServiceRecordHandle value - TODO: Is this related to HCI_Handle?
578  l2capoutbuf[18] = 0x01;
579  l2capoutbuf[19] = 0x00;
580  l2capoutbuf[20] = 0x06;
581 
582  l2capoutbuf[21] = 0x09; // Unsigned Integer - length 2 bytes
583  l2capoutbuf[22] = 0x00; // MSB ServiceClassIDList
584  l2capoutbuf[23] = 0x01; // LSB ServiceClassIDList
585  l2capoutbuf[24] = 0x35; // Data element sequence - length in next byte
586  l2capoutbuf[25] = 0x03; // Length = 3
587  l2capoutbuf[26] = 0x19; // UUID (universally unique identifier) - length = 2 bytes
588  l2capoutbuf[27] = 0x11; // MSB SerialPort
589  l2capoutbuf[28] = 0x01; // LSB SerialPort
590 
591  l2capoutbuf[29] = 0x09; // Unsigned Integer - length 2 bytes
592  l2capoutbuf[30] = 0x00; // MSB ProtocolDescriptorList
593  l2capoutbuf[31] = 0x04; // LSB ProtocolDescriptorList
594  l2capoutbuf[32] = 0x35; // Data element sequence - length in next byte
595  l2capoutbuf[33] = 0x0C; // Length = 12
596 
597  l2capoutbuf[34] = 0x35; // Data element sequence - length in next byte
598  l2capoutbuf[35] = 0x03; // Length = 3
599  l2capoutbuf[36] = 0x19; // UUID (universally unique identifier) - length = 2 bytes
600  l2capoutbuf[37] = 0x01; // MSB L2CAP
601  l2capoutbuf[38] = 0x00; // LSB L2CAP
602 
603  l2capoutbuf[39] = 0x35; // Data element sequence - length in next byte
604  l2capoutbuf[40] = 0x05; // Length = 5
605  l2capoutbuf[41] = 0x19; // UUID (universally unique identifier) - length = 2 bytes
606  l2capoutbuf[42] = 0x00; // MSB RFCOMM
607  l2capoutbuf[43] = 0x03; // LSB RFCOMM
608  l2capoutbuf[44] = 0x08; // Unsigned Integer - length 1 byte
609 
610  l2capoutbuf[45] = 0x02; // ContinuationState - Two more bytes
611  l2capoutbuf[46] = 0x00; // MSB length
612  l2capoutbuf[47] = 0x19; // LSB length = 25 more bytes to come
613 
614  SDP_Command(l2capoutbuf, 48);
615 }
616 
617 void SPP::serialPortResponse2(uint8_t transactionIDHigh, uint8_t transactionIDLow) {
619  l2capoutbuf[1] = transactionIDHigh;
620  l2capoutbuf[2] = transactionIDLow;
621  l2capoutbuf[3] = 0x00; // MSB Parameter Length
622  l2capoutbuf[4] = 0x1C; // LSB Parameter Length = 28
623  l2capoutbuf[5] = 0x00; // MSB AttributeListsByteCount
624  l2capoutbuf[6] = 0x19; // LSB AttributeListsByteCount = 25
625 
626  /* Attribute ID/Value Sequence: */
627  l2capoutbuf[7] = 0x01; // Channel 1 - TODO: Try different values, so multiple servers can be used at once
628 
629  l2capoutbuf[8] = 0x09; // Unsigned Integer - length 2 bytes
630  l2capoutbuf[9] = 0x00; // MSB LanguageBaseAttributeIDList
631  l2capoutbuf[10] = 0x06; // LSB LanguageBaseAttributeIDList
632  l2capoutbuf[11] = 0x35; // Data element sequence - length in next byte
633  l2capoutbuf[12] = 0x09; // Length = 9
634 
635  // Identifier representing the natural language = en = English - see: "ISO 639:1988"
636  l2capoutbuf[13] = 0x09; // Unsigned Integer - length 2 bytes
637  l2capoutbuf[14] = 0x65; // 'e'
638  l2capoutbuf[15] = 0x6E; // 'n'
639 
640  // "The second element of each triplet contains an identifier that specifies a character encoding used for the language"
641  // Encoding is set to 106 (UTF-8) - see: http://www.iana.org/assignments/character-sets/character-sets.xhtml
642  l2capoutbuf[16] = 0x09; // Unsigned Integer - length 2 bytes
643  l2capoutbuf[17] = 0x00; // MSB of character encoding
644  l2capoutbuf[18] = 0x6A; // LSB of character encoding (106)
645 
646  // Attribute ID that serves as the base attribute ID for the natural language in the service record
647  // "To facilitate the retrieval of human-readable universal attributes in a principal language, the base attribute ID value for the primary language supported by a service record shall be 0x0100"
648  l2capoutbuf[19] = 0x09; // Unsigned Integer - length 2 bytes
649  l2capoutbuf[20] = 0x01;
650  l2capoutbuf[21] = 0x00;
651 
652  l2capoutbuf[22] = 0x09; // Unsigned Integer - length 2 bytes
653  l2capoutbuf[23] = 0x01; // MSB ServiceDescription
654  l2capoutbuf[24] = 0x00; // LSB ServiceDescription
655 
656  l2capoutbuf[25] = 0x25; // Text string - length in next byte
657  l2capoutbuf[26] = 0x05; // Name length
658  l2capoutbuf[27] = 'T';
659  l2capoutbuf[28] = 'K';
660  l2capoutbuf[29] = 'J';
661  l2capoutbuf[30] = 'S';
662  l2capoutbuf[31] = 'P';
663  l2capoutbuf[32] = 0x00; // No continuation state
664 
665  SDP_Command(l2capoutbuf, 33);
666 }
667 
668 void SPP::l2capResponse1(uint8_t transactionIDHigh, uint8_t transactionIDLow) {
669  serialPortResponse1(transactionIDHigh, transactionIDLow); // These has to send all the supported functions, since it only supports virtual serialport it just sends the message again
670 }
671 
672 void SPP::l2capResponse2(uint8_t transactionIDHigh, uint8_t transactionIDLow) {
673  serialPortResponse2(transactionIDHigh, transactionIDLow); // Same data as serialPortResponse2
674 }
675 /************************************************************/
676 /* RFCOMM Commands */
677 
678 /************************************************************/
679 void SPP::RFCOMM_Command(uint8_t* data, uint8_t nbytes) {
680  pBtd->L2CAP_Command(hci_handle, data, nbytes, rfcomm_scid[0], rfcomm_scid[1]);
681 }
682 
683 void SPP::sendRfcomm(uint8_t channel, uint8_t direction, uint8_t CR, uint8_t channelType, uint8_t pfBit, uint8_t* data, uint8_t length) {
684  l2capoutbuf[0] = channel | direction | CR | extendAddress; // RFCOMM Address
685  l2capoutbuf[1] = channelType | pfBit; // RFCOMM Control
686  l2capoutbuf[2] = length << 1 | 0x01; // Length and format (always 0x01 bytes format)
687  uint8_t i = 0;
688  for(; i < length; i++)
689  l2capoutbuf[i + 3] = data[i];
690  l2capoutbuf[i + 3] = calcFcs(l2capoutbuf);
691 #ifdef EXTRADEBUG
692  Notify(PSTR(" - RFCOMM Data: "), 0x80);
693  for(i = 0; i < length + 4; i++) {
694  D_PrintHex<uint8_t > (l2capoutbuf[i], 0x80);
695  Notify(PSTR(" "), 0x80);
696  }
697 #endif
698  RFCOMM_Command(l2capoutbuf, length + 4);
699 }
700 
701 void SPP::sendRfcommCredit(uint8_t channel, uint8_t direction, uint8_t CR, uint8_t channelType, uint8_t pfBit, uint8_t credit) {
702  l2capoutbuf[0] = channel | direction | CR | extendAddress; // RFCOMM Address
703  l2capoutbuf[1] = channelType | pfBit; // RFCOMM Control
704  l2capoutbuf[2] = 0x01; // Length = 0
705  l2capoutbuf[3] = credit; // Credit
706  l2capoutbuf[4] = calcFcs(l2capoutbuf);
707 #ifdef EXTRADEBUG
708  Notify(PSTR(" - RFCOMM Credit Data: "), 0x80);
709  for(uint8_t i = 0; i < 5; i++) {
710  D_PrintHex<uint8_t > (l2capoutbuf[i], 0x80);
711  Notify(PSTR(" "), 0x80);
712  }
713 #endif
714  RFCOMM_Command(l2capoutbuf, 5);
715 }
716 
717 /* CRC on 2 bytes */
718 uint8_t SPP::crc(uint8_t *data) {
719  return (pgm_read_byte(&rfcomm_crc_table[pgm_read_byte(&rfcomm_crc_table[0xFF ^ data[0]]) ^ data[1]]));
720 }
721 
722 /* Calculate FCS */
723 uint8_t SPP::calcFcs(uint8_t *data) {
724  uint8_t temp = crc(data);
725  if((data[1] & 0xEF) == RFCOMM_UIH)
726  return (0xFF - temp); // FCS on 2 bytes
727  else
728  return (0xFF - pgm_read_byte(&rfcomm_crc_table[temp ^ data[2]])); // FCS on 3 bytes
729 }
730 
731 /* Check FCS */
732 bool SPP::checkFcs(uint8_t *data, uint8_t fcs) {
733  uint8_t temp = crc(data);
734  if((data[1] & 0xEF) != RFCOMM_UIH)
735  temp = pgm_read_byte(&rfcomm_crc_table[temp ^ data[2]]); // FCS on 3 bytes
736  return (pgm_read_byte(&rfcomm_crc_table[temp ^ fcs]) == 0xCF);
737 }
738 
739 /* Serial commands */
740 #if defined(ARDUINO) && ARDUINO >=100
741 
742 size_t SPP::write(uint8_t data) {
743  return write(&data, 1);
744 }
745 #else
746 
747 void SPP::write(uint8_t data) {
748  write(&data, 1);
749 }
750 #endif
751 
752 #if defined(ARDUINO) && ARDUINO >=100
753 
754 size_t SPP::write(const uint8_t *data, size_t size) {
755 #else
756 
757 void SPP::write(const uint8_t *data, size_t size) {
758 #endif
759  for(uint8_t i = 0; i < size; i++) {
760  if(sppIndex >= sizeof (sppOutputBuffer) / sizeof (sppOutputBuffer[0]))
761  send(); // Send the current data in the buffer
762  sppOutputBuffer[sppIndex++] = data[i]; // All the bytes are put into a buffer and then send using the send() function
763  }
764 #if defined(ARDUINO) && ARDUINO >=100
765  return size;
766 #endif
767 }
768 
769 void SPP::send() {
770  if(!connected || !sppIndex)
771  return;
772  uint8_t length; // This is the length of the string we are sending
773  uint8_t offset = 0; // This is used to keep track of where we are in the string
774 
775  l2capoutbuf[0] = rfcommChannelConnection | 0 | 0 | extendAddress; // RFCOMM Address
776  l2capoutbuf[1] = RFCOMM_UIH; // RFCOMM Control
777 
778  while(sppIndex) { // We will run this while loop until this variable is 0
779  if(sppIndex > (sizeof (l2capoutbuf) - 4)) // Check if the string is larger than the outgoing buffer
780  length = sizeof (l2capoutbuf) - 4;
781  else
782  length = sppIndex;
783 
784  l2capoutbuf[2] = length << 1 | 1; // Length
785  uint8_t i = 0;
786  for(; i < length; i++)
787  l2capoutbuf[i + 3] = sppOutputBuffer[i + offset];
788  l2capoutbuf[i + 3] = calcFcs(l2capoutbuf); // Calculate checksum
789 
790  RFCOMM_Command(l2capoutbuf, length + 4);
791 
792  sppIndex -= length;
793  offset += length; // Increment the offset
794  }
795 }
796 
797 int SPP::available(void) {
798  return rfcommAvailable;
799 };
800 
801 void SPP::discard(void) {
802  rfcommAvailable = 0;
803 }
804 
805 int SPP::peek(void) {
806  if(rfcommAvailable == 0) // Don't read if there is nothing in the buffer
807  return -1;
808  return rfcommDataBuffer[0];
809 }
810 
811 int SPP::read(void) {
812  if(rfcommAvailable == 0) // Don't read if there is nothing in the buffer
813  return -1;
814  uint8_t output = rfcommDataBuffer[0];
815  for(uint8_t i = 1; i < rfcommAvailable; i++)
816  rfcommDataBuffer[i - 1] = rfcommDataBuffer[i]; // Shift the buffer one left
817  rfcommAvailable--;
818  bytesRead++;
819  if(bytesRead > (sizeof (rfcommDataBuffer) - 5)) { // We will send the command just before it runs out of credit
820  bytesRead = 0;
821  sendRfcommCredit(rfcommChannelConnection, rfcommDirection, 0, RFCOMM_UIH, 0x10, sizeof (rfcommDataBuffer)); // Send more credit
822 #ifdef EXTRADEBUG
823  Notify(PSTR("\r\nSent "), 0x80);
824  Notify((uint8_t)sizeof (rfcommDataBuffer), 0x80);
825  Notify(PSTR(" more credit"), 0x80);
826 #endif
827  }
828  return output;
829 }
size_t write(uint8_t data)
Definition: SPP.cpp:742
+Go to the documentation of this file.
1 /* Copyright (C) 2012 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 "SPP.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 sent to the Arduino
22 
23 /*
24  * CRC (reversed crc) lookup table as calculated by the table generator in ETSI TS 101 369 V6.3.0.
25  */
26 const uint8_t rfcomm_crc_table[256] PROGMEM = {/* reversed, 8-bit, poly=0x07 */
27  0x00, 0x91, 0xE3, 0x72, 0x07, 0x96, 0xE4, 0x75, 0x0E, 0x9F, 0xED, 0x7C, 0x09, 0x98, 0xEA, 0x7B,
28  0x1C, 0x8D, 0xFF, 0x6E, 0x1B, 0x8A, 0xF8, 0x69, 0x12, 0x83, 0xF1, 0x60, 0x15, 0x84, 0xF6, 0x67,
29  0x38, 0xA9, 0xDB, 0x4A, 0x3F, 0xAE, 0xDC, 0x4D, 0x36, 0xA7, 0xD5, 0x44, 0x31, 0xA0, 0xD2, 0x43,
30  0x24, 0xB5, 0xC7, 0x56, 0x23, 0xB2, 0xC0, 0x51, 0x2A, 0xBB, 0xC9, 0x58, 0x2D, 0xBC, 0xCE, 0x5F,
31  0x70, 0xE1, 0x93, 0x02, 0x77, 0xE6, 0x94, 0x05, 0x7E, 0xEF, 0x9D, 0x0C, 0x79, 0xE8, 0x9A, 0x0B,
32  0x6C, 0xFD, 0x8F, 0x1E, 0x6B, 0xFA, 0x88, 0x19, 0x62, 0xF3, 0x81, 0x10, 0x65, 0xF4, 0x86, 0x17,
33  0x48, 0xD9, 0xAB, 0x3A, 0x4F, 0xDE, 0xAC, 0x3D, 0x46, 0xD7, 0xA5, 0x34, 0x41, 0xD0, 0xA2, 0x33,
34  0x54, 0xC5, 0xB7, 0x26, 0x53, 0xC2, 0xB0, 0x21, 0x5A, 0xCB, 0xB9, 0x28, 0x5D, 0xCC, 0xBE, 0x2F,
35  0xE0, 0x71, 0x03, 0x92, 0xE7, 0x76, 0x04, 0x95, 0xEE, 0x7F, 0x0D, 0x9C, 0xE9, 0x78, 0x0A, 0x9B,
36  0xFC, 0x6D, 0x1F, 0x8E, 0xFB, 0x6A, 0x18, 0x89, 0xF2, 0x63, 0x11, 0x80, 0xF5, 0x64, 0x16, 0x87,
37  0xD8, 0x49, 0x3B, 0xAA, 0xDF, 0x4E, 0x3C, 0xAD, 0xD6, 0x47, 0x35, 0xA4, 0xD1, 0x40, 0x32, 0xA3,
38  0xC4, 0x55, 0x27, 0xB6, 0xC3, 0x52, 0x20, 0xB1, 0xCA, 0x5B, 0x29, 0xB8, 0xCD, 0x5C, 0x2E, 0xBF,
39  0x90, 0x01, 0x73, 0xE2, 0x97, 0x06, 0x74, 0xE5, 0x9E, 0x0F, 0x7D, 0xEC, 0x99, 0x08, 0x7A, 0xEB,
40  0x8C, 0x1D, 0x6F, 0xFE, 0x8B, 0x1A, 0x68, 0xF9, 0x82, 0x13, 0x61, 0xF0, 0x85, 0x14, 0x66, 0xF7,
41  0xA8, 0x39, 0x4B, 0xDA, 0xAF, 0x3E, 0x4C, 0xDD, 0xA6, 0x37, 0x45, 0xD4, 0xA1, 0x30, 0x42, 0xD3,
42  0xB4, 0x25, 0x57, 0xC6, 0xB3, 0x22, 0x50, 0xC1, 0xBA, 0x2B, 0x59, 0xC8, 0xBD, 0x2C, 0x5E, 0xCF
43 };
44 
45 SPP::SPP(BTD *p, const char* name, const char* pin) :
46 BluetoothService(p) // Pointer to BTD class instance - mandatory
47 {
48  pBtd->btdName = name;
49  pBtd->btdPin = pin;
50 
51  /* Set device cid for the SDP and RFCOMM channelse */
52  sdp_dcid[0] = 0x50; // 0x0050
53  sdp_dcid[1] = 0x00;
54  rfcomm_dcid[0] = 0x51; // 0x0051
55  rfcomm_dcid[1] = 0x00;
56 
57  Reset();
58 }
59 
60 void SPP::Reset() {
61  connected = false;
62  RFCOMMConnected = false;
63  SDPConnected = false;
64  waitForLastCommand = false;
65  l2cap_sdp_state = L2CAP_SDP_WAIT;
66  l2cap_rfcomm_state = L2CAP_RFCOMM_WAIT;
67  l2cap_event_flag = 0;
68  sppIndex = 0;
69  creditSent = false;
70 }
71 
73  connected = false;
74  // First the two L2CAP channels has to be disconnected and then the HCI connection
75  if(RFCOMMConnected)
76  pBtd->l2cap_disconnection_request(hci_handle, ++identifier, rfcomm_scid, rfcomm_dcid);
77  if(RFCOMMConnected && SDPConnected)
78  delay(1); // Add delay between commands
79  if(SDPConnected)
80  pBtd->l2cap_disconnection_request(hci_handle, ++identifier, sdp_scid, sdp_dcid);
81  l2cap_sdp_state = L2CAP_DISCONNECT_RESPONSE;
82 }
83 
84 void SPP::ACLData(uint8_t* l2capinbuf) {
85  if(!connected) {
86  if(l2capinbuf[8] == L2CAP_CMD_CONNECTION_REQUEST) {
87  if((l2capinbuf[12] | (l2capinbuf[13] << 8)) == SDP_PSM && !pBtd->sdpConnectionClaimed) {
88  pBtd->sdpConnectionClaimed = true;
89  hci_handle = pBtd->hci_handle; // Store the HCI Handle for the connection
90  l2cap_sdp_state = L2CAP_SDP_WAIT; // Reset state
91  } else if((l2capinbuf[12] | (l2capinbuf[13] << 8)) == RFCOMM_PSM && !pBtd->rfcommConnectionClaimed) {
93  hci_handle = pBtd->hci_handle; // Store the HCI Handle for the connection
94  l2cap_rfcomm_state = L2CAP_RFCOMM_WAIT; // Reset state
95  }
96  }
97  }
98 
99  if(checkHciHandle(l2capinbuf, hci_handle)) { // acl_handle_ok
100  if((l2capinbuf[6] | (l2capinbuf[7] << 8)) == 0x0001U) { // l2cap_control - Channel ID for ACL-U
101  if(l2capinbuf[8] == L2CAP_CMD_COMMAND_REJECT) {
102 #ifdef DEBUG_USB_HOST
103  Notify(PSTR("\r\nL2CAP Command Rejected - Reason: "), 0x80);
104  D_PrintHex<uint8_t > (l2capinbuf[13], 0x80);
105  Notify(PSTR(" "), 0x80);
106  D_PrintHex<uint8_t > (l2capinbuf[12], 0x80);
107  Notify(PSTR(" Data: "), 0x80);
108  D_PrintHex<uint8_t > (l2capinbuf[17], 0x80);
109  Notify(PSTR(" "), 0x80);
110  D_PrintHex<uint8_t > (l2capinbuf[16], 0x80);
111  Notify(PSTR(" "), 0x80);
112  D_PrintHex<uint8_t > (l2capinbuf[15], 0x80);
113  Notify(PSTR(" "), 0x80);
114  D_PrintHex<uint8_t > (l2capinbuf[14], 0x80);
115 #endif
116  } else if(l2capinbuf[8] == L2CAP_CMD_CONNECTION_REQUEST) {
117 #ifdef EXTRADEBUG
118  Notify(PSTR("\r\nL2CAP Connection Request - PSM: "), 0x80);
119  D_PrintHex<uint8_t > (l2capinbuf[13], 0x80);
120  Notify(PSTR(" "), 0x80);
121  D_PrintHex<uint8_t > (l2capinbuf[12], 0x80);
122  Notify(PSTR(" SCID: "), 0x80);
123  D_PrintHex<uint8_t > (l2capinbuf[15], 0x80);
124  Notify(PSTR(" "), 0x80);
125  D_PrintHex<uint8_t > (l2capinbuf[14], 0x80);
126  Notify(PSTR(" Identifier: "), 0x80);
127  D_PrintHex<uint8_t > (l2capinbuf[9], 0x80);
128 #endif
129  if((l2capinbuf[12] | (l2capinbuf[13] << 8)) == SDP_PSM) { // It doesn't matter if it receives another reqeust, since it waits for the channel to disconnect in the L2CAP_SDP_DONE state, and the l2cap_event_flag will be cleared if so
130  identifier = l2capinbuf[9];
131  sdp_scid[0] = l2capinbuf[14];
132  sdp_scid[1] = l2capinbuf[15];
134  } else if((l2capinbuf[12] | (l2capinbuf[13] << 8)) == RFCOMM_PSM) { // ----- || -----
135  identifier = l2capinbuf[9];
136  rfcomm_scid[0] = l2capinbuf[14];
137  rfcomm_scid[1] = l2capinbuf[15];
139  }
140  } else if(l2capinbuf[8] == L2CAP_CMD_CONFIG_RESPONSE) {
141  if((l2capinbuf[16] | (l2capinbuf[17] << 8)) == 0x0000) { // Success
142  if(l2capinbuf[12] == sdp_dcid[0] && l2capinbuf[13] == sdp_dcid[1]) {
143  //Notify(PSTR("\r\nSDP Configuration Complete"), 0x80);
145  } else if(l2capinbuf[12] == rfcomm_dcid[0] && l2capinbuf[13] == rfcomm_dcid[1]) {
146  //Notify(PSTR("\r\nRFCOMM Configuration Complete"), 0x80);
148  }
149  }
150  } else if(l2capinbuf[8] == L2CAP_CMD_CONFIG_REQUEST) {
151  if(l2capinbuf[12] == sdp_dcid[0] && l2capinbuf[13] == sdp_dcid[1]) {
152  //Notify(PSTR("\r\nSDP Configuration Request"), 0x80);
153  pBtd->l2cap_config_response(hci_handle, l2capinbuf[9], sdp_scid);
154  } else if(l2capinbuf[12] == rfcomm_dcid[0] && l2capinbuf[13] == rfcomm_dcid[1]) {
155  //Notify(PSTR("\r\nRFCOMM Configuration Request"), 0x80);
156  pBtd->l2cap_config_response(hci_handle, l2capinbuf[9], rfcomm_scid);
157  }
158  } else if(l2capinbuf[8] == L2CAP_CMD_DISCONNECT_REQUEST) {
159  if(l2capinbuf[12] == sdp_dcid[0] && l2capinbuf[13] == sdp_dcid[1]) {
160  //Notify(PSTR("\r\nDisconnect Request: SDP Channel"), 0x80);
161  identifier = l2capinbuf[9];
163  } else if(l2capinbuf[12] == rfcomm_dcid[0] && l2capinbuf[13] == rfcomm_dcid[1]) {
164  //Notify(PSTR("\r\nDisconnect Request: RFCOMM Channel"), 0x80);
165  identifier = l2capinbuf[9];
167  }
168  } else if(l2capinbuf[8] == L2CAP_CMD_DISCONNECT_RESPONSE) {
169  if(l2capinbuf[12] == sdp_scid[0] && l2capinbuf[13] == sdp_scid[1]) {
170  //Notify(PSTR("\r\nDisconnect Response: SDP Channel"), 0x80);
171  identifier = l2capinbuf[9];
173  } else if(l2capinbuf[12] == rfcomm_scid[0] && l2capinbuf[13] == rfcomm_scid[1]) {
174  //Notify(PSTR("\r\nDisconnect Response: RFCOMM Channel"), 0x80);
175  identifier = l2capinbuf[9];
177  }
178  } else if(l2capinbuf[8] == L2CAP_CMD_INFORMATION_REQUEST) {
179 #ifdef DEBUG_USB_HOST
180  Notify(PSTR("\r\nInformation request"), 0x80);
181 #endif
182  identifier = l2capinbuf[9];
183  pBtd->l2cap_information_response(hci_handle, identifier, l2capinbuf[12], l2capinbuf[13]);
184  }
185 #ifdef EXTRADEBUG
186  else {
187  Notify(PSTR("\r\nL2CAP Unknown Signaling Command: "), 0x80);
188  D_PrintHex<uint8_t > (l2capinbuf[8], 0x80);
189  }
190 #endif
191  } else if(l2capinbuf[6] == sdp_dcid[0] && l2capinbuf[7] == sdp_dcid[1]) { // SDP
192  if(l2capinbuf[8] == SDP_SERVICE_SEARCH_ATTRIBUTE_REQUEST) {
193  if(((l2capinbuf[16] << 8 | l2capinbuf[17]) == SERIALPORT_UUID) || ((l2capinbuf[16] << 8 | l2capinbuf[17]) == 0x0000 && (l2capinbuf[18] << 8 | l2capinbuf[19]) == SERIALPORT_UUID)) { // Check if it's sending the full UUID, see: https://www.bluetooth.org/Technical/AssignedNumbers/service_discovery.htm, we will just check the first four bytes
194  if(firstMessage) {
195  serialPortResponse1(l2capinbuf[9], l2capinbuf[10]);
196  firstMessage = false;
197  } else {
198  serialPortResponse2(l2capinbuf[9], l2capinbuf[10]); // Serialport continuation state
199  firstMessage = true;
200  }
201  } else if(((l2capinbuf[16] << 8 | l2capinbuf[17]) == L2CAP_UUID) || ((l2capinbuf[16] << 8 | l2capinbuf[17]) == 0x0000 && (l2capinbuf[18] << 8 | l2capinbuf[19]) == L2CAP_UUID)) {
202  if(firstMessage) {
203  l2capResponse1(l2capinbuf[9], l2capinbuf[10]);
204  firstMessage = false;
205  } else {
206  l2capResponse2(l2capinbuf[9], l2capinbuf[10]); // L2CAP continuation state
207  firstMessage = true;
208  }
209  } else
210  serviceNotSupported(l2capinbuf[9], l2capinbuf[10]); // The service is not supported
211 #ifdef EXTRADEBUG
212  Notify(PSTR("\r\nUUID: "), 0x80);
213  uint16_t uuid;
214  if((l2capinbuf[16] << 8 | l2capinbuf[17]) == 0x0000) // Check if it's sending the UUID as a 128-bit UUID
215  uuid = (l2capinbuf[18] << 8 | l2capinbuf[19]);
216  else // Short UUID
217  uuid = (l2capinbuf[16] << 8 | l2capinbuf[17]);
218  D_PrintHex<uint16_t > (uuid, 0x80);
219 
220  Notify(PSTR("\r\nLength: "), 0x80);
221  uint16_t length = l2capinbuf[11] << 8 | l2capinbuf[12];
222  D_PrintHex<uint16_t > (length, 0x80);
223  Notify(PSTR("\r\nData: "), 0x80);
224  for(uint8_t i = 0; i < length; i++) {
225  D_PrintHex<uint8_t > (l2capinbuf[13 + i], 0x80);
226  Notify(PSTR(" "), 0x80);
227  }
228 #endif
229  }
230 #ifdef EXTRADEBUG
231  else {
232  Notify(PSTR("\r\nUnknown PDU: "), 0x80);
233  D_PrintHex<uint8_t > (l2capinbuf[8], 0x80);
234  }
235 #endif
236  } else if(l2capinbuf[6] == rfcomm_dcid[0] && l2capinbuf[7] == rfcomm_dcid[1]) { // RFCOMM
237  rfcommChannel = l2capinbuf[8] & 0xF8;
238  rfcommDirection = l2capinbuf[8] & 0x04;
239  rfcommCommandResponse = l2capinbuf[8] & 0x02;
240  rfcommChannelType = l2capinbuf[9] & 0xEF;
241  rfcommPfBit = l2capinbuf[9] & 0x10;
242 
243  if(rfcommChannel >> 3 != 0x00)
244  rfcommChannelConnection = rfcommChannel;
245 
246 #ifdef EXTRADEBUG
247  Notify(PSTR("\r\nRFCOMM Channel: "), 0x80);
248  D_PrintHex<uint8_t > (rfcommChannel >> 3, 0x80);
249  Notify(PSTR(" Direction: "), 0x80);
250  D_PrintHex<uint8_t > (rfcommDirection >> 2, 0x80);
251  Notify(PSTR(" CommandResponse: "), 0x80);
252  D_PrintHex<uint8_t > (rfcommCommandResponse >> 1, 0x80);
253  Notify(PSTR(" ChannelType: "), 0x80);
254  D_PrintHex<uint8_t > (rfcommChannelType, 0x80);
255  Notify(PSTR(" PF_BIT: "), 0x80);
256  D_PrintHex<uint8_t > (rfcommPfBit, 0x80);
257 #endif
258  if(rfcommChannelType == RFCOMM_DISC) {
259 #ifdef DEBUG_USB_HOST
260  Notify(PSTR("\r\nReceived Disconnect RFCOMM Command on channel: "), 0x80);
261  D_PrintHex<uint8_t > (rfcommChannel >> 3, 0x80);
262 #endif
263  connected = false;
264  sendRfcomm(rfcommChannel, rfcommDirection, rfcommCommandResponse, RFCOMM_UA, rfcommPfBit, rfcommbuf, 0x00); // UA Command
265  }
266  if(connected) {
267  /* Read the incoming message */
268  if(rfcommChannelType == RFCOMM_UIH && rfcommChannel == rfcommChannelConnection) {
269  uint8_t length = l2capinbuf[10] >> 1; // Get length
270  uint8_t offset = l2capinbuf[4] - length - 4; // Check if there is credit
271  if(checkFcs(&l2capinbuf[8], l2capinbuf[11 + length + offset])) {
272  uint8_t i = 0;
273  for(; i < length; i++) {
274  if(rfcommAvailable + i >= sizeof (rfcommDataBuffer)) {
275 #ifdef DEBUG_USB_HOST
276  Notify(PSTR("\r\nWarning: Buffer is full!"), 0x80);
277 #endif
278  break;
279  }
280  rfcommDataBuffer[rfcommAvailable + i] = l2capinbuf[11 + i + offset];
281  }
282  rfcommAvailable += i;
283 #ifdef EXTRADEBUG
284  Notify(PSTR("\r\nRFCOMM Data Available: "), 0x80);
285  Notify(rfcommAvailable, 0x80);
286  if(offset) {
287  Notify(PSTR(" - Credit: 0x"), 0x80);
288  D_PrintHex<uint8_t > (l2capinbuf[11], 0x80);
289  }
290 #endif
291  }
292 #ifdef DEBUG_USB_HOST
293  else
294  Notify(PSTR("\r\nError in FCS checksum!"), 0x80);
295 #endif
296 #ifdef PRINTREPORT // Uncomment "#define PRINTREPORT" to print the report send to the Arduino via Bluetooth
297  for(uint8_t i = 0; i < length; i++)
298  Notifyc(l2capinbuf[i + 11 + offset], 0x80);
299 #endif
300  } else if(rfcommChannelType == RFCOMM_UIH && l2capinbuf[11] == BT_RFCOMM_RPN_CMD) { // UIH Remote Port Negotiation Command
301 #ifdef DEBUG_USB_HOST
302  Notify(PSTR("\r\nReceived UIH Remote Port Negotiation Command"), 0x80);
303 #endif
304  rfcommbuf[0] = BT_RFCOMM_RPN_RSP; // Command
305  rfcommbuf[1] = l2capinbuf[12]; // Length and shiftet like so: length << 1 | 1
306  rfcommbuf[2] = l2capinbuf[13]; // Channel: channel << 1 | 1
307  rfcommbuf[3] = l2capinbuf[14]; // Pre difined for Bluetooth, see 5.5.3 of TS 07.10 Adaption for RFCOMM
308  rfcommbuf[4] = l2capinbuf[15]; // Priority
309  rfcommbuf[5] = l2capinbuf[16]; // Timer
310  rfcommbuf[6] = l2capinbuf[17]; // Max Fram Size LSB
311  rfcommbuf[7] = l2capinbuf[18]; // Max Fram Size MSB
312  rfcommbuf[8] = l2capinbuf[19]; // MaxRatransm.
313  rfcommbuf[9] = l2capinbuf[20]; // Number of Frames
314  sendRfcomm(rfcommChannel, rfcommDirection, 0, RFCOMM_UIH, rfcommPfBit, rfcommbuf, 0x0A); // UIH Remote Port Negotiation Response
315  } else if(rfcommChannelType == RFCOMM_UIH && l2capinbuf[11] == BT_RFCOMM_MSC_CMD) { // UIH Modem Status Command
316 #ifdef DEBUG_USB_HOST
317  Notify(PSTR("\r\nSend UIH Modem Status Response"), 0x80);
318 #endif
319  rfcommbuf[0] = BT_RFCOMM_MSC_RSP; // UIH Modem Status Response
320  rfcommbuf[1] = 2 << 1 | 1; // Length and shiftet like so: length << 1 | 1
321  rfcommbuf[2] = l2capinbuf[13]; // Channel: (1 << 0) | (1 << 1) | (0 << 2) | (channel << 3)
322  rfcommbuf[3] = l2capinbuf[14];
323  sendRfcomm(rfcommChannel, rfcommDirection, 0, RFCOMM_UIH, rfcommPfBit, rfcommbuf, 0x04);
324  }
325  } else {
326  if(rfcommChannelType == RFCOMM_SABM) { // SABM Command - this is sent twice: once for channel 0 and then for the channel to establish
327 #ifdef DEBUG_USB_HOST
328  Notify(PSTR("\r\nReceived SABM Command"), 0x80);
329 #endif
330  sendRfcomm(rfcommChannel, rfcommDirection, rfcommCommandResponse, RFCOMM_UA, rfcommPfBit, rfcommbuf, 0x00); // UA Command
331  } else if(rfcommChannelType == RFCOMM_UIH && l2capinbuf[11] == BT_RFCOMM_PN_CMD) { // UIH Parameter Negotiation Command
332 #ifdef DEBUG_USB_HOST
333  Notify(PSTR("\r\nReceived UIH Parameter Negotiation Command"), 0x80);
334 #endif
335  rfcommbuf[0] = BT_RFCOMM_PN_RSP; // UIH Parameter Negotiation Response
336  rfcommbuf[1] = l2capinbuf[12]; // Length and shiftet like so: length << 1 | 1
337  rfcommbuf[2] = l2capinbuf[13]; // Channel: channel << 1 | 1
338  rfcommbuf[3] = 0xE0; // Pre difined for Bluetooth, see 5.5.3 of TS 07.10 Adaption for RFCOMM
339  rfcommbuf[4] = 0x00; // Priority
340  rfcommbuf[5] = 0x00; // Timer
341  rfcommbuf[6] = BULK_MAXPKTSIZE - 14; // Max Fram Size LSB - set to the size of received data (50)
342  rfcommbuf[7] = 0x00; // Max Fram Size MSB
343  rfcommbuf[8] = 0x00; // MaxRatransm.
344  rfcommbuf[9] = 0x00; // Number of Frames
345  sendRfcomm(rfcommChannel, rfcommDirection, 0, RFCOMM_UIH, rfcommPfBit, rfcommbuf, 0x0A);
346  } else if(rfcommChannelType == RFCOMM_UIH && l2capinbuf[11] == BT_RFCOMM_MSC_CMD) { // UIH Modem Status Command
347 #ifdef DEBUG_USB_HOST
348  Notify(PSTR("\r\nSend UIH Modem Status Response"), 0x80);
349 #endif
350  rfcommbuf[0] = BT_RFCOMM_MSC_RSP; // UIH Modem Status Response
351  rfcommbuf[1] = 2 << 1 | 1; // Length and shiftet like so: length << 1 | 1
352  rfcommbuf[2] = l2capinbuf[13]; // Channel: (1 << 0) | (1 << 1) | (0 << 2) | (channel << 3)
353  rfcommbuf[3] = l2capinbuf[14];
354  sendRfcomm(rfcommChannel, rfcommDirection, 0, RFCOMM_UIH, rfcommPfBit, rfcommbuf, 0x04);
355 
356  delay(1);
357 #ifdef DEBUG_USB_HOST
358  Notify(PSTR("\r\nSend UIH Modem Status Command"), 0x80);
359 #endif
360  rfcommbuf[0] = BT_RFCOMM_MSC_CMD; // UIH Modem Status Command
361  rfcommbuf[1] = 2 << 1 | 1; // Length and shiftet like so: length << 1 | 1
362  rfcommbuf[2] = l2capinbuf[13]; // Channel: (1 << 0) | (1 << 1) | (0 << 2) | (channel << 3)
363  rfcommbuf[3] = 0x8D; // Can receive frames (YES), Ready to Communicate (YES), Ready to Receive (YES), Incomig Call (NO), Data is Value (YES)
364 
365  sendRfcomm(rfcommChannel, rfcommDirection, 0, RFCOMM_UIH, rfcommPfBit, rfcommbuf, 0x04);
366  } else if(rfcommChannelType == RFCOMM_UIH && l2capinbuf[11] == BT_RFCOMM_MSC_RSP) { // UIH Modem Status Response
367  if(!creditSent) {
368 #ifdef DEBUG_USB_HOST
369  Notify(PSTR("\r\nSend UIH Command with credit"), 0x80);
370 #endif
371  sendRfcommCredit(rfcommChannelConnection, rfcommDirection, 0, RFCOMM_UIH, 0x10, sizeof (rfcommDataBuffer)); // Send credit
372  creditSent = true;
373  timer = (uint32_t)millis();
374  waitForLastCommand = true;
375  }
376  } else if(rfcommChannelType == RFCOMM_UIH && l2capinbuf[10] == 0x01) { // UIH Command with credit
377 #ifdef DEBUG_USB_HOST
378  Notify(PSTR("\r\nReceived UIH Command with credit"), 0x80);
379 #endif
380  } else if(rfcommChannelType == RFCOMM_UIH && l2capinbuf[11] == BT_RFCOMM_RPN_CMD) { // UIH Remote Port Negotiation Command
381 #ifdef DEBUG_USB_HOST
382  Notify(PSTR("\r\nReceived UIH Remote Port Negotiation Command"), 0x80);
383 #endif
384  rfcommbuf[0] = BT_RFCOMM_RPN_RSP; // Command
385  rfcommbuf[1] = l2capinbuf[12]; // Length and shiftet like so: length << 1 | 1
386  rfcommbuf[2] = l2capinbuf[13]; // Channel: channel << 1 | 1
387  rfcommbuf[3] = l2capinbuf[14]; // Pre difined for Bluetooth, see 5.5.3 of TS 07.10 Adaption for RFCOMM
388  rfcommbuf[4] = l2capinbuf[15]; // Priority
389  rfcommbuf[5] = l2capinbuf[16]; // Timer
390  rfcommbuf[6] = l2capinbuf[17]; // Max Fram Size LSB
391  rfcommbuf[7] = l2capinbuf[18]; // Max Fram Size MSB
392  rfcommbuf[8] = l2capinbuf[19]; // MaxRatransm.
393  rfcommbuf[9] = l2capinbuf[20]; // Number of Frames
394  sendRfcomm(rfcommChannel, rfcommDirection, 0, RFCOMM_UIH, rfcommPfBit, rfcommbuf, 0x0A); // UIH Remote Port Negotiation Response
395 #ifdef DEBUG_USB_HOST
396  Notify(PSTR("\r\nRFCOMM Connection is now established\r\n"), 0x80);
397 #endif
398  onInit();
399  }
400 #ifdef EXTRADEBUG
401  else if(rfcommChannelType != RFCOMM_DISC) {
402  Notify(PSTR("\r\nUnsupported RFCOMM Data - ChannelType: "), 0x80);
403  D_PrintHex<uint8_t > (rfcommChannelType, 0x80);
404  Notify(PSTR(" Command: "), 0x80);
405  D_PrintHex<uint8_t > (l2capinbuf[11], 0x80);
406  }
407 #endif
408  }
409  }
410 #ifdef EXTRADEBUG
411  else {
412  Notify(PSTR("\r\nUnsupported L2CAP Data - Channel ID: "), 0x80);
413  D_PrintHex<uint8_t > (l2capinbuf[7], 0x80);
414  Notify(PSTR(" "), 0x80);
415  D_PrintHex<uint8_t > (l2capinbuf[6], 0x80);
416  }
417 #endif
418  SDP_task();
419  RFCOMM_task();
420  }
421 }
422 
423 void SPP::Run() {
424  if(waitForLastCommand && (int32_t)((uint32_t)millis() - timer) > 100) { // We will only wait 100ms and see if the UIH Remote Port Negotiation Command is send, as some deviced don't send it
425 #ifdef DEBUG_USB_HOST
426  Notify(PSTR("\r\nRFCOMM Connection is now established - Automatic\r\n"), 0x80);
427 #endif
428  onInit();
429  }
430  send(); // Send all bytes currently in the buffer
431 }
432 
433 void SPP::onInit() {
434  creditSent = false;
435  waitForLastCommand = false;
436  connected = true; // The RFCOMM channel is now established
437  sppIndex = 0;
438  if(pFuncOnInit)
439  pFuncOnInit(); // Call the user function
440 };
441 
442 void SPP::SDP_task() {
443  switch(l2cap_sdp_state) {
444  case L2CAP_SDP_WAIT:
447 #ifdef DEBUG_USB_HOST
448  Notify(PSTR("\r\nSDP Incoming Connection Request"), 0x80);
449 #endif
451  delay(1);
453  identifier++;
454  delay(1);
456  l2cap_sdp_state = L2CAP_SDP_SUCCESS;
459  SDPConnected = false;
460 #ifdef DEBUG_USB_HOST
461  Notify(PSTR("\r\nDisconnected SDP Channel"), 0x80);
462 #endif
464  }
465  break;
466  case L2CAP_SDP_SUCCESS:
469 #ifdef DEBUG_USB_HOST
470  Notify(PSTR("\r\nSDP Successfully Configured"), 0x80);
471 #endif
472  firstMessage = true; // Reset bool
473  SDPConnected = true;
474  l2cap_sdp_state = L2CAP_SDP_WAIT;
475  }
476  break;
477 
478  case L2CAP_DISCONNECT_RESPONSE: // This is for both disconnection response from the RFCOMM and SDP channel if they were connected
480 #ifdef DEBUG_USB_HOST
481  Notify(PSTR("\r\nDisconnected L2CAP Connection"), 0x80);
482 #endif
484  hci_handle = -1; // Reset handle
485  Reset();
486  }
487  break;
488  }
489 }
490 
491 void SPP::RFCOMM_task() {
492  switch(l2cap_rfcomm_state) {
493  case L2CAP_RFCOMM_WAIT:
496 #ifdef DEBUG_USB_HOST
497  Notify(PSTR("\r\nRFCOMM Incoming Connection Request"), 0x80);
498 #endif
499  pBtd->l2cap_connection_response(hci_handle, identifier, rfcomm_dcid, rfcomm_scid, PENDING);
500  delay(1);
501  pBtd->l2cap_connection_response(hci_handle, identifier, rfcomm_dcid, rfcomm_scid, SUCCESSFUL);
502  identifier++;
503  delay(1);
505  l2cap_rfcomm_state = L2CAP_RFCOMM_SUCCESS;
508  RFCOMMConnected = false;
509  connected = false;
510 #ifdef DEBUG_USB_HOST
511  Notify(PSTR("\r\nDisconnected RFCOMM Channel"), 0x80);
512 #endif
513  pBtd->l2cap_disconnection_response(hci_handle, identifier, rfcomm_dcid, rfcomm_scid);
514  }
515  break;
519 #ifdef DEBUG_USB_HOST
520  Notify(PSTR("\r\nRFCOMM Successfully Configured"), 0x80);
521 #endif
522  rfcommAvailable = 0; // Reset number of bytes available
523  bytesRead = 0; // Reset number of bytes received
524  RFCOMMConnected = true;
525  l2cap_rfcomm_state = L2CAP_RFCOMM_WAIT;
526  }
527  break;
528  }
529 }
530 /************************************************************/
531 /* SDP Commands */
532 
533 /************************************************************/
534 void SPP::SDP_Command(uint8_t* data, uint8_t nbytes) { // See page 223 in the Bluetooth specs
535  pBtd->L2CAP_Command(hci_handle, data, nbytes, sdp_scid[0], sdp_scid[1]);
536 }
537 
538 void SPP::serviceNotSupported(uint8_t transactionIDHigh, uint8_t transactionIDLow) { // See page 235 in the Bluetooth specs
539  l2capoutbuf[0] = SDP_SERVICE_SEARCH_ATTRIBUTE_RESPONSE;
540  l2capoutbuf[1] = transactionIDHigh;
541  l2capoutbuf[2] = transactionIDLow;
542  l2capoutbuf[3] = 0x00; // MSB Parameter Length
543  l2capoutbuf[4] = 0x05; // LSB Parameter Length = 5
544  l2capoutbuf[5] = 0x00; // MSB AttributeListsByteCount
545  l2capoutbuf[6] = 0x02; // LSB AttributeListsByteCount = 2
546 
547  /* Attribute ID/Value Sequence: */
548  l2capoutbuf[7] = 0x35; // Data element sequence - length in next byte
549  l2capoutbuf[8] = 0x00; // Length = 0
550  l2capoutbuf[9] = 0x00; // No continuation state
551 
552  SDP_Command(l2capoutbuf, 10);
553 }
554 
555 void SPP::serialPortResponse1(uint8_t transactionIDHigh, uint8_t transactionIDLow) {
556  l2capoutbuf[0] = SDP_SERVICE_SEARCH_ATTRIBUTE_RESPONSE;
557  l2capoutbuf[1] = transactionIDHigh;
558  l2capoutbuf[2] = transactionIDLow;
559  l2capoutbuf[3] = 0x00; // MSB Parameter Length
560  l2capoutbuf[4] = 0x2B; // LSB Parameter Length = 43
561  l2capoutbuf[5] = 0x00; // MSB AttributeListsByteCount
562  l2capoutbuf[6] = 0x26; // LSB AttributeListsByteCount = 38
563 
564  /* Attribute ID/Value Sequence: */
565  l2capoutbuf[7] = 0x36; // Data element sequence - length in next two bytes
566  l2capoutbuf[8] = 0x00; // MSB Length
567  l2capoutbuf[9] = 0x3C; // LSB Length = 60
568 
569  l2capoutbuf[10] = 0x36; // Data element sequence - length in next two bytes
570  l2capoutbuf[11] = 0x00; // MSB Length
571  l2capoutbuf[12] = 0x39; // LSB Length = 57
572 
573  l2capoutbuf[13] = 0x09; // Unsigned Integer - length 2 bytes
574  l2capoutbuf[14] = 0x00; // MSB ServiceRecordHandle
575  l2capoutbuf[15] = 0x00; // LSB ServiceRecordHandle
576  l2capoutbuf[16] = 0x0A; // Unsigned int - length 4 bytes
577  l2capoutbuf[17] = 0x00; // ServiceRecordHandle value - TODO: Is this related to HCI_Handle?
578  l2capoutbuf[18] = 0x01;
579  l2capoutbuf[19] = 0x00;
580  l2capoutbuf[20] = 0x06;
581 
582  l2capoutbuf[21] = 0x09; // Unsigned Integer - length 2 bytes
583  l2capoutbuf[22] = 0x00; // MSB ServiceClassIDList
584  l2capoutbuf[23] = 0x01; // LSB ServiceClassIDList
585  l2capoutbuf[24] = 0x35; // Data element sequence - length in next byte
586  l2capoutbuf[25] = 0x03; // Length = 3
587  l2capoutbuf[26] = 0x19; // UUID (universally unique identifier) - length = 2 bytes
588  l2capoutbuf[27] = 0x11; // MSB SerialPort
589  l2capoutbuf[28] = 0x01; // LSB SerialPort
590 
591  l2capoutbuf[29] = 0x09; // Unsigned Integer - length 2 bytes
592  l2capoutbuf[30] = 0x00; // MSB ProtocolDescriptorList
593  l2capoutbuf[31] = 0x04; // LSB ProtocolDescriptorList
594  l2capoutbuf[32] = 0x35; // Data element sequence - length in next byte
595  l2capoutbuf[33] = 0x0C; // Length = 12
596 
597  l2capoutbuf[34] = 0x35; // Data element sequence - length in next byte
598  l2capoutbuf[35] = 0x03; // Length = 3
599  l2capoutbuf[36] = 0x19; // UUID (universally unique identifier) - length = 2 bytes
600  l2capoutbuf[37] = 0x01; // MSB L2CAP
601  l2capoutbuf[38] = 0x00; // LSB L2CAP
602 
603  l2capoutbuf[39] = 0x35; // Data element sequence - length in next byte
604  l2capoutbuf[40] = 0x05; // Length = 5
605  l2capoutbuf[41] = 0x19; // UUID (universally unique identifier) - length = 2 bytes
606  l2capoutbuf[42] = 0x00; // MSB RFCOMM
607  l2capoutbuf[43] = 0x03; // LSB RFCOMM
608  l2capoutbuf[44] = 0x08; // Unsigned Integer - length 1 byte
609 
610  l2capoutbuf[45] = 0x02; // ContinuationState - Two more bytes
611  l2capoutbuf[46] = 0x00; // MSB length
612  l2capoutbuf[47] = 0x19; // LSB length = 25 more bytes to come
613 
614  SDP_Command(l2capoutbuf, 48);
615 }
616 
617 void SPP::serialPortResponse2(uint8_t transactionIDHigh, uint8_t transactionIDLow) {
618  l2capoutbuf[0] = SDP_SERVICE_SEARCH_ATTRIBUTE_RESPONSE;
619  l2capoutbuf[1] = transactionIDHigh;
620  l2capoutbuf[2] = transactionIDLow;
621  l2capoutbuf[3] = 0x00; // MSB Parameter Length
622  l2capoutbuf[4] = 0x1C; // LSB Parameter Length = 28
623  l2capoutbuf[5] = 0x00; // MSB AttributeListsByteCount
624  l2capoutbuf[6] = 0x19; // LSB AttributeListsByteCount = 25
625 
626  /* Attribute ID/Value Sequence: */
627  l2capoutbuf[7] = 0x01; // Channel 1 - TODO: Try different values, so multiple servers can be used at once
628 
629  l2capoutbuf[8] = 0x09; // Unsigned Integer - length 2 bytes
630  l2capoutbuf[9] = 0x00; // MSB LanguageBaseAttributeIDList
631  l2capoutbuf[10] = 0x06; // LSB LanguageBaseAttributeIDList
632  l2capoutbuf[11] = 0x35; // Data element sequence - length in next byte
633  l2capoutbuf[12] = 0x09; // Length = 9
634 
635  // Identifier representing the natural language = en = English - see: "ISO 639:1988"
636  l2capoutbuf[13] = 0x09; // Unsigned Integer - length 2 bytes
637  l2capoutbuf[14] = 0x65; // 'e'
638  l2capoutbuf[15] = 0x6E; // 'n'
639 
640  // "The second element of each triplet contains an identifier that specifies a character encoding used for the language"
641  // Encoding is set to 106 (UTF-8) - see: http://www.iana.org/assignments/character-sets/character-sets.xhtml
642  l2capoutbuf[16] = 0x09; // Unsigned Integer - length 2 bytes
643  l2capoutbuf[17] = 0x00; // MSB of character encoding
644  l2capoutbuf[18] = 0x6A; // LSB of character encoding (106)
645 
646  // Attribute ID that serves as the base attribute ID for the natural language in the service record
647  // "To facilitate the retrieval of human-readable universal attributes in a principal language, the base attribute ID value for the primary language supported by a service record shall be 0x0100"
648  l2capoutbuf[19] = 0x09; // Unsigned Integer - length 2 bytes
649  l2capoutbuf[20] = 0x01;
650  l2capoutbuf[21] = 0x00;
651 
652  l2capoutbuf[22] = 0x09; // Unsigned Integer - length 2 bytes
653  l2capoutbuf[23] = 0x01; // MSB ServiceDescription
654  l2capoutbuf[24] = 0x00; // LSB ServiceDescription
655 
656  l2capoutbuf[25] = 0x25; // Text string - length in next byte
657  l2capoutbuf[26] = 0x05; // Name length
658  l2capoutbuf[27] = 'T';
659  l2capoutbuf[28] = 'K';
660  l2capoutbuf[29] = 'J';
661  l2capoutbuf[30] = 'S';
662  l2capoutbuf[31] = 'P';
663  l2capoutbuf[32] = 0x00; // No continuation state
664 
665  SDP_Command(l2capoutbuf, 33);
666 }
667 
668 void SPP::l2capResponse1(uint8_t transactionIDHigh, uint8_t transactionIDLow) {
669  serialPortResponse1(transactionIDHigh, transactionIDLow); // These has to send all the supported functions, since it only supports virtual serialport it just sends the message again
670 }
671 
672 void SPP::l2capResponse2(uint8_t transactionIDHigh, uint8_t transactionIDLow) {
673  serialPortResponse2(transactionIDHigh, transactionIDLow); // Same data as serialPortResponse2
674 }
675 /************************************************************/
676 /* RFCOMM Commands */
677 
678 /************************************************************/
679 void SPP::RFCOMM_Command(uint8_t* data, uint8_t nbytes) {
680  pBtd->L2CAP_Command(hci_handle, data, nbytes, rfcomm_scid[0], rfcomm_scid[1]);
681 }
682 
683 void SPP::sendRfcomm(uint8_t channel, uint8_t direction, uint8_t CR, uint8_t channelType, uint8_t pfBit, uint8_t* data, uint8_t length) {
684  l2capoutbuf[0] = channel | direction | CR | extendAddress; // RFCOMM Address
685  l2capoutbuf[1] = channelType | pfBit; // RFCOMM Control
686  l2capoutbuf[2] = length << 1 | 0x01; // Length and format (always 0x01 bytes format)
687  uint8_t i = 0;
688  for(; i < length; i++)
689  l2capoutbuf[i + 3] = data[i];
690  l2capoutbuf[i + 3] = calcFcs(l2capoutbuf);
691 #ifdef EXTRADEBUG
692  Notify(PSTR(" - RFCOMM Data: "), 0x80);
693  for(i = 0; i < length + 4; i++) {
694  D_PrintHex<uint8_t > (l2capoutbuf[i], 0x80);
695  Notify(PSTR(" "), 0x80);
696  }
697 #endif
698  RFCOMM_Command(l2capoutbuf, length + 4);
699 }
700 
701 void SPP::sendRfcommCredit(uint8_t channel, uint8_t direction, uint8_t CR, uint8_t channelType, uint8_t pfBit, uint8_t credit) {
702  l2capoutbuf[0] = channel | direction | CR | extendAddress; // RFCOMM Address
703  l2capoutbuf[1] = channelType | pfBit; // RFCOMM Control
704  l2capoutbuf[2] = 0x01; // Length = 0
705  l2capoutbuf[3] = credit; // Credit
706  l2capoutbuf[4] = calcFcs(l2capoutbuf);
707 #ifdef EXTRADEBUG
708  Notify(PSTR(" - RFCOMM Credit Data: "), 0x80);
709  for(uint8_t i = 0; i < 5; i++) {
710  D_PrintHex<uint8_t > (l2capoutbuf[i], 0x80);
711  Notify(PSTR(" "), 0x80);
712  }
713 #endif
714  RFCOMM_Command(l2capoutbuf, 5);
715 }
716 
717 /* CRC on 2 bytes */
718 uint8_t SPP::crc(uint8_t *data) {
719  return (pgm_read_byte(&rfcomm_crc_table[pgm_read_byte(&rfcomm_crc_table[0xFF ^ data[0]]) ^ data[1]]));
720 }
721 
722 /* Calculate FCS */
723 uint8_t SPP::calcFcs(uint8_t *data) {
724  uint8_t temp = crc(data);
725  if((data[1] & 0xEF) == RFCOMM_UIH)
726  return (0xFF - temp); // FCS on 2 bytes
727  else
728  return (0xFF - pgm_read_byte(&rfcomm_crc_table[temp ^ data[2]])); // FCS on 3 bytes
729 }
730 
731 /* Check FCS */
732 bool SPP::checkFcs(uint8_t *data, uint8_t fcs) {
733  uint8_t temp = crc(data);
734  if((data[1] & 0xEF) != RFCOMM_UIH)
735  temp = pgm_read_byte(&rfcomm_crc_table[temp ^ data[2]]); // FCS on 3 bytes
736  return (pgm_read_byte(&rfcomm_crc_table[temp ^ fcs]) == 0xCF);
737 }
738 
739 /* Serial commands */
740 #if defined(ARDUINO) && ARDUINO >=100
741 
742 size_t SPP::write(uint8_t data) {
743  return write(&data, 1);
744 }
745 #else
746 
747 void SPP::write(uint8_t data) {
748  write(&data, 1);
749 }
750 #endif
751 
752 #if defined(ARDUINO) && ARDUINO >=100
753 
754 size_t SPP::write(const uint8_t *data, size_t size) {
755 #else
756 
757 void SPP::write(const uint8_t *data, size_t size) {
758 #endif
759  for(uint8_t i = 0; i < size; i++) {
760  if(sppIndex >= sizeof (sppOutputBuffer) / sizeof (sppOutputBuffer[0]))
761  send(); // Send the current data in the buffer
762  sppOutputBuffer[sppIndex++] = data[i]; // All the bytes are put into a buffer and then send using the send() function
763  }
764 #if defined(ARDUINO) && ARDUINO >=100
765  return size;
766 #endif
767 }
768 
769 void SPP::send() {
770  if(!connected || !sppIndex)
771  return;
772  uint8_t length; // This is the length of the string we are sending
773  uint8_t offset = 0; // This is used to keep track of where we are in the string
774 
775  l2capoutbuf[0] = rfcommChannelConnection | 0 | 0 | extendAddress; // RFCOMM Address
776  l2capoutbuf[1] = RFCOMM_UIH; // RFCOMM Control
777 
778  while(sppIndex) { // We will run this while loop until this variable is 0
779  if(sppIndex > (sizeof (l2capoutbuf) - 4)) // Check if the string is larger than the outgoing buffer
780  length = sizeof (l2capoutbuf) - 4;
781  else
782  length = sppIndex;
783 
784  l2capoutbuf[2] = length << 1 | 1; // Length
785  uint8_t i = 0;
786  for(; i < length; i++)
787  l2capoutbuf[i + 3] = sppOutputBuffer[i + offset];
788  l2capoutbuf[i + 3] = calcFcs(l2capoutbuf); // Calculate checksum
789 
790  RFCOMM_Command(l2capoutbuf, length + 4);
791 
792  sppIndex -= length;
793  offset += length; // Increment the offset
794  }
795 }
796 
797 int SPP::available(void) {
798  return rfcommAvailable;
799 };
800 
801 void SPP::discard(void) {
802  rfcommAvailable = 0;
803 }
804 
805 int SPP::peek(void) {
806  if(rfcommAvailable == 0) // Don't read if there is nothing in the buffer
807  return -1;
808  return rfcommDataBuffer[0];
809 }
810 
811 int SPP::read(void) {
812  if(rfcommAvailable == 0) // Don't read if there is nothing in the buffer
813  return -1;
814  uint8_t output = rfcommDataBuffer[0];
815  for(uint8_t i = 1; i < rfcommAvailable; i++)
816  rfcommDataBuffer[i - 1] = rfcommDataBuffer[i]; // Shift the buffer one left
817  rfcommAvailable--;
818  bytesRead++;
819  if(bytesRead > (sizeof (rfcommDataBuffer) - 5)) { // We will send the command just before it runs out of credit
820  bytesRead = 0;
821  sendRfcommCredit(rfcommChannelConnection, rfcommDirection, 0, RFCOMM_UIH, 0x10, sizeof (rfcommDataBuffer)); // Send more credit
822 #ifdef EXTRADEBUG
823  Notify(PSTR("\r\nSent "), 0x80);
824  Notify((uint8_t)sizeof (rfcommDataBuffer), 0x80);
825  Notify(PSTR(" more credit"), 0x80);
826 #endif
827  }
828  return output;
829 }
size_t write(uint8_t data)
Definition: SPP.cpp:742
void onInit()
Definition: SPP.cpp:433
-
const char * btdName
Definition: BTD.h:447
-
#define BT_RFCOMM_RPN_RSP
Definition: SPP.h:44
-
void l2cap_connection_response(uint16_t handle, uint8_t rxid, uint8_t *dcid, uint8_t *scid, uint8_t result)
Definition: BTD.cpp:1260
-
#define SUCCESSFUL
Definition: BTD.h:178
-
bool sdpConnectionClaimed
Definition: BTD.h:442
-
#define RFCOMM_PSM
Definition: BTD.h:182
+
const char * btdName
Definition: BTD.h:477
+
#define BT_RFCOMM_RPN_RSP
Definition: SPP.h:38
+
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
+
bool sdpConnectionClaimed
Definition: BTD.h:472
+
#define RFCOMM_PSM
Definition: BTD.h:191
SPP(BTD *p, const char *name="Arduino", const char *pin="0000")
Definition: SPP.cpp:45
-
Definition: BTD.h:201
-
void l2cap_disconnection_request(uint16_t handle, uint8_t rxid, uint8_t *dcid, uint8_t *scid)
Definition: BTD.cpp:1313
-
#define RFCOMM_SABM
Definition: SPP.h:30
-
#define L2CAP_UUID
Definition: SPP.h:27
+
Definition: BTD.h:221
+
void l2cap_disconnection_request(uint16_t handle, uint8_t rxid, uint8_t *dcid, uint8_t *scid)
Definition: BTD.cpp:1541
+
#define RFCOMM_SABM
Definition: SPP.h:24
const uint8_t rfcomm_crc_table[256]
Definition: SPP.cpp:26
-
bool rfcommConnectionClaimed
Definition: BTD.h:444
-
#define SDP_SERVICE_SEARCH_ATTRIBUTE_RESPONSE_PDU
Definition: SPP.h:25
-
uint8_t identifier
Definition: BTD.h:621
-
#define L2CAP_FLAG_CONFIG_SDP_SUCCESS
Definition: BTD.h:150
-
#define RFCOMM_DISC
Definition: SPP.h:34
-
#define SERIALPORT_UUID
Definition: SPP.h:26
-
#define L2CAP_SDP_SUCCESS
Definition: BTD.h:121
-
const char * btdPin
Definition: BTD.h:449
-
bool connected
Definition: SPP.h:84
+
bool rfcommConnectionClaimed
Definition: BTD.h:474
+
#define SERIALPORT_UUID
Definition: BTD.h:203
+
uint8_t identifier
Definition: BTD.h:655
+
#define L2CAP_FLAG_CONFIG_SDP_SUCCESS
Definition: BTD.h:159
+
#define RFCOMM_DISC
Definition: SPP.h:28
+
#define L2CAP_SDP_SUCCESS
Definition: BTD.h:130
+
const char * btdPin
Definition: BTD.h:479
+
bool connected
Definition: SPP.h:78
+
#define SDP_SERVICE_SEARCH_ATTRIBUTE_REQUEST
Definition: BTD.h:200
#define pgm_read_byte(addr)
-
#define L2CAP_CMD_INFORMATION_REQUEST
Definition: BTD.h:173
-
#define SDP_PSM
Definition: BTD.h:181
+
#define L2CAP_CMD_INFORMATION_REQUEST
Definition: BTD.h:182
+
#define SDP_PSM
Definition: BTD.h:190
int read(void)
Definition: SPP.cpp:811
-
void l2cap_disconnection_response(uint16_t handle, uint8_t rxid, uint8_t *dcid, uint8_t *scid)
Definition: BTD.cpp:1326
-
#define extendAddress
Definition: SPP.h:36
-
#define L2CAP_RFCOMM_WAIT
Definition: BTD.h:124
+
void l2cap_disconnection_response(uint16_t handle, uint8_t rxid, uint8_t *dcid, uint8_t *scid)
Definition: BTD.cpp:1554
+
#define extendAddress
Definition: SPP.h:30
+
#define L2CAP_RFCOMM_WAIT
Definition: BTD.h:133
#define Notify(...)
Definition: message.h:51
void Run()
Definition: SPP.cpp:423
-
#define L2CAP_FLAG_CONNECTION_RFCOMM_REQUEST
Definition: BTD.h:154
-
uint16_t hci_handle
Definition: BTD.h:454
+
#define L2CAP_FLAG_CONNECTION_RFCOMM_REQUEST
Definition: BTD.h:163
+
uint16_t hci_handle
Definition: BTD.h:484
#define Notifyc(...)
Definition: message.h:53
-
void hci_disconnect(uint16_t handle)
Definition: BTD.cpp:1171
- +
void hci_disconnect(uint16_t handle)
Definition: BTD.cpp:1399
+
void Reset()
Definition: SPP.cpp:60
-
void(* pFuncOnInit)(void)
Definition: BTD.h:609
-
#define L2CAP_FLAG_DISCONNECT_SDP_REQUEST
Definition: BTD.h:151
-
#define RFCOMM_UIH
Definition: SPP.h:32
+
void(* pFuncOnInit)(void)
Definition: BTD.h:643
+
#define L2CAP_FLAG_DISCONNECT_SDP_REQUEST
Definition: BTD.h:160
+
#define RFCOMM_UIH
Definition: SPP.h:26
int available(void)
Definition: SPP.cpp:797
-
#define l2cap_check_flag(flag)
Definition: BTD.h:161
-
#define L2CAP_CMD_CONFIG_REQUEST
Definition: BTD.h:169
+
#define l2cap_check_flag(flag)
Definition: BTD.h:170
+
#define L2CAP_CMD_CONFIG_REQUEST
Definition: BTD.h:178
#define PSTR(str)
-
#define L2CAP_CMD_DISCONNECT_REQUEST
Definition: BTD.h:171
+
#define L2CAP_CMD_DISCONNECT_REQUEST
Definition: BTD.h:180
void discard(void)
Definition: SPP.cpp:801
-
#define L2CAP_SDP_WAIT
Definition: BTD.h:120
-
BTD * pBtd
Definition: BTD.h:612
+
#define L2CAP_SDP_WAIT
Definition: BTD.h:129
+
BTD * pBtd
Definition: BTD.h:646
#define BULK_MAXPKTSIZE
Definition: BTD.h:37
-
#define L2CAP_RFCOMM_SUCCESS
Definition: BTD.h:125
-
#define BT_RFCOMM_RPN_CMD
Definition: SPP.h:43
-
#define L2CAP_FLAG_DISCONNECT_RESPONSE
Definition: BTD.h:158
-
#define L2CAP_FLAG_CONFIG_RFCOMM_SUCCESS
Definition: BTD.h:155
+
#define L2CAP_RFCOMM_SUCCESS
Definition: BTD.h:134
+
#define BT_RFCOMM_RPN_CMD
Definition: SPP.h:37
+
#define L2CAP_FLAG_DISCONNECT_RESPONSE
Definition: BTD.h:167
+
#define L2CAP_UUID
Definition: BTD.h:204
+
#define L2CAP_FLAG_CONFIG_RFCOMM_SUCCESS
Definition: BTD.h:164
void disconnect()
Definition: SPP.cpp:72
-
#define BT_RFCOMM_MSC_CMD
Definition: SPP.h:41
-
#define SDP_SERVICE_SEARCH_ATTRIBUTE_REQUEST_PDU
Definition: SPP.h:24
-
#define L2CAP_CMD_DISCONNECT_RESPONSE
Definition: BTD.h:172
-
#define RFCOMM_UA
Definition: SPP.h:31
-
void l2cap_information_response(uint16_t handle, uint8_t rxid, uint8_t infoTypeLow, uint8_t infoTypeHigh)
Definition: BTD.cpp:1339
-
#define L2CAP_CMD_CONFIG_RESPONSE
Definition: BTD.h:170
-
uint16_t hci_handle
Definition: BTD.h:615
-
#define BT_RFCOMM_PN_CMD
Definition: SPP.h:39
-
#define BT_RFCOMM_MSC_RSP
Definition: SPP.h:42
-
#define L2CAP_FLAG_CONNECTION_SDP_REQUEST
Definition: BTD.h:149
-
uint32_t l2cap_event_flag
Definition: BTD.h:618
-
#define l2cap_clear_flag(flag)
Definition: BTD.h:163
-
#define L2CAP_FLAG_DISCONNECT_RFCOMM_REQUEST
Definition: BTD.h:156
-
#define L2CAP_DISCONNECT_RESPONSE
Definition: BTD.h:127
+
#define BT_RFCOMM_MSC_CMD
Definition: SPP.h:35
+
#define L2CAP_CMD_DISCONNECT_RESPONSE
Definition: BTD.h:181
+
#define RFCOMM_UA
Definition: SPP.h:25
+
void l2cap_information_response(uint16_t handle, uint8_t rxid, uint8_t infoTypeLow, uint8_t infoTypeHigh)
Definition: BTD.cpp:1567
+
#define L2CAP_CMD_CONFIG_RESPONSE
Definition: BTD.h:179
+
#define SDP_SERVICE_SEARCH_ATTRIBUTE_RESPONSE
Definition: BTD.h:201
+
uint16_t hci_handle
Definition: BTD.h:649
+
#define BT_RFCOMM_PN_CMD
Definition: SPP.h:33
+
#define BT_RFCOMM_MSC_RSP
Definition: SPP.h:36
+
#define L2CAP_FLAG_CONNECTION_SDP_REQUEST
Definition: BTD.h:158
+
uint32_t l2cap_event_flag
Definition: BTD.h:652
+
#define l2cap_clear_flag(flag)
Definition: BTD.h:172
+
#define L2CAP_FLAG_DISCONNECT_RFCOMM_REQUEST
Definition: BTD.h:165
+
#define L2CAP_DISCONNECT_RESPONSE
Definition: BTD.h:136
void send(void)
Definition: SPP.cpp:769
-
void L2CAP_Command(uint16_t handle, uint8_t *data, uint8_t nbytes, uint8_t channelLow=0x01, uint8_t channelHigh=0x00)
Definition: BTD.cpp:1219
-
void l2cap_config_response(uint16_t handle, uint8_t rxid, uint8_t *scid)
Definition: BTD.cpp:1294
-
#define PENDING
Definition: BTD.h:177
-
#define l2cap_set_flag(flag)
Definition: BTD.h:162
-
void l2cap_config_request(uint16_t handle, uint8_t rxid, uint8_t *dcid)
Definition: BTD.cpp:1277
-
#define L2CAP_CMD_CONNECTION_REQUEST
Definition: BTD.h:167
-
#define BT_RFCOMM_PN_RSP
Definition: SPP.h:40
-
bool checkHciHandle(uint8_t *buf, uint16_t handle)
Definition: BTD.h:604
+
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_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_CMD_CONNECTION_REQUEST
Definition: BTD.h:176
+
#define BT_RFCOMM_PN_RSP
Definition: SPP.h:34
+
bool checkHciHandle(uint8_t *buf, uint16_t handle)
Definition: BTD.h:638
void ACLData(uint8_t *ACLData)
Definition: SPP.cpp:84
int peek(void)
Definition: SPP.cpp:805
-
#define L2CAP_CMD_COMMAND_REJECT
Definition: BTD.h:166
+
#define L2CAP_CMD_COMMAND_REJECT
Definition: BTD.h:175
-

Definition at line 31 of file SPP.h.

+

Definition at line 25 of file SPP.h.

@@ -245,7 +181,7 @@ Macros
-

Definition at line 32 of file SPP.h.

+

Definition at line 26 of file SPP.h.

@@ -259,7 +195,7 @@ Macros
-

Definition at line 34 of file SPP.h.

+

Definition at line 28 of file SPP.h.

@@ -273,7 +209,7 @@ Macros
-

Definition at line 36 of file SPP.h.

+

Definition at line 30 of file SPP.h.

@@ -287,7 +223,7 @@ Macros
-

Definition at line 39 of file SPP.h.

+

Definition at line 33 of file SPP.h.

@@ -301,7 +237,7 @@ Macros
-

Definition at line 40 of file SPP.h.

+

Definition at line 34 of file SPP.h.

@@ -315,7 +251,7 @@ Macros
-

Definition at line 41 of file SPP.h.

+

Definition at line 35 of file SPP.h.

@@ -329,7 +265,7 @@ Macros
-

Definition at line 42 of file SPP.h.

+

Definition at line 36 of file SPP.h.

@@ -343,7 +279,7 @@ Macros
-

Definition at line 43 of file SPP.h.

+

Definition at line 37 of file SPP.h.

@@ -357,7 +293,7 @@ Macros
-

Definition at line 44 of file SPP.h.

+

Definition at line 38 of file SPP.h.

diff --git a/_s_p_p_8h_source.html b/_s_p_p_8h_source.html index a9c4d76c..c3abcec8 100644 --- a/_s_p_p_8h_source.html +++ b/_s_p_p_8h_source.html @@ -86,21 +86,21 @@ var searchBox = new SearchBox("searchBox", "search",false,'Search');
SPP.h
-Go to the documentation of this file.
1 /* Copyright (C) 2012 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 _spp_h_
19 #define _spp_h_
20 
21 #include "BTD.h"
22 
23 /* Used for SDP */
24 #define SDP_SERVICE_SEARCH_ATTRIBUTE_REQUEST_PDU 0x06 // See the RFCOMM specs
25 #define SDP_SERVICE_SEARCH_ATTRIBUTE_RESPONSE_PDU 0x07 // See the RFCOMM specs
26 #define SERIALPORT_UUID 0x1101 // See http://www.bluetooth.org/Technical/AssignedNumbers/service_discovery.htm
27 #define L2CAP_UUID 0x0100
28 
29 /* Used for RFCOMM */
30 #define RFCOMM_SABM 0x2F
31 #define RFCOMM_UA 0x63
32 #define RFCOMM_UIH 0xEF
33 //#define RFCOMM_DM 0x0F
34 #define RFCOMM_DISC 0x43
35 
36 #define extendAddress 0x01 // Always 1
37 
38 // Multiplexer message types
39 #define BT_RFCOMM_PN_CMD 0x83
40 #define BT_RFCOMM_PN_RSP 0x81
41 #define BT_RFCOMM_MSC_CMD 0xE3
42 #define BT_RFCOMM_MSC_RSP 0xE1
43 #define BT_RFCOMM_RPN_CMD 0x93
44 #define BT_RFCOMM_RPN_RSP 0x91
45 /*
46 #define BT_RFCOMM_TEST_CMD 0x23
47 #define BT_RFCOMM_TEST_RSP 0x21
48 #define BT_RFCOMM_FCON_CMD 0xA3
49 #define BT_RFCOMM_FCON_RSP 0xA1
50 #define BT_RFCOMM_FCOFF_CMD 0x63
51 #define BT_RFCOMM_FCOFF_RSP 0x61
52 #define BT_RFCOMM_RLS_CMD 0x53
53 #define BT_RFCOMM_RLS_RSP 0x51
54 #define BT_RFCOMM_NSC_RSP 0x11
55  */
56 
61 class SPP : public BluetoothService, public Stream {
62 public:
69  SPP(BTD *p, const char *name = "Arduino", const char *pin = "0000");
70 
73  void disconnect();
80  operator bool() {
81  return connected;
82  }
84  bool connected;
85 
91  int available(void);
92 
94  void flush(void) {
95  send();
96  };
101  int peek(void);
106  int read(void);
107 
108 #if defined(ARDUINO) && ARDUINO >=100
109 
114  size_t write(uint8_t data);
121  size_t write(const uint8_t* data, size_t size);
123 #if !defined(RBL_NRF51822)
124  using Print::write;
125 #endif
126 #else
127 
131  void write(uint8_t data);
137  void write(const uint8_t* data, size_t size);
138 #endif
139 
141  void discard(void);
147  void send(void);
150 protected:
156  void ACLData(uint8_t* ACLData);
158  void Run();
160  void Reset();
166  void onInit();
169 private:
170  /* Set true when a channel is created */
171  bool SDPConnected;
172  bool RFCOMMConnected;
173 
174  /* Variables used by L2CAP state machines */
175  uint8_t l2cap_sdp_state;
176  uint8_t l2cap_rfcomm_state;
177 
178  uint8_t l2capoutbuf[BULK_MAXPKTSIZE]; // General purpose buffer for l2cap out data
179  uint8_t rfcommbuf[10]; // Buffer for RFCOMM Commands
180 
181  /* L2CAP Channels */
182  uint8_t sdp_scid[2]; // L2CAP source CID for SDP
183  uint8_t sdp_dcid[2]; // 0x0050
184  uint8_t rfcomm_scid[2]; // L2CAP source CID for RFCOMM
185  uint8_t rfcomm_dcid[2]; // 0x0051
186 
187  /* RFCOMM Variables */
188  uint8_t rfcommChannel;
189  uint8_t rfcommChannelConnection; // This is the channel the SPP channel will be running at
190  uint8_t rfcommDirection;
191  uint8_t rfcommCommandResponse;
192  uint8_t rfcommChannelType;
193  uint8_t rfcommPfBit;
194 
195  uint32_t timer;
196  bool waitForLastCommand;
197  bool creditSent;
198 
199  uint8_t rfcommDataBuffer[100]; // Create a 100 sized buffer for incoming data
200  uint8_t sppOutputBuffer[100]; // Create a 100 sized buffer for outgoing SPP data
201  uint8_t sppIndex;
202  uint8_t rfcommAvailable;
203 
204  bool firstMessage; // Used to see if it's the first SDP request received
205  uint8_t bytesRead; // Counter to see when it's time to send more credit
206 
207  /* State machines */
208  void SDP_task(); // SDP state machine
209  void RFCOMM_task(); // RFCOMM state machine
210 
211  /* SDP Commands */
212  void SDP_Command(uint8_t *data, uint8_t nbytes);
213  void serviceNotSupported(uint8_t transactionIDHigh, uint8_t transactionIDLow);
214  void serialPortResponse1(uint8_t transactionIDHigh, uint8_t transactionIDLow);
215  void serialPortResponse2(uint8_t transactionIDHigh, uint8_t transactionIDLow);
216  void l2capResponse1(uint8_t transactionIDHigh, uint8_t transactionIDLow);
217  void l2capResponse2(uint8_t transactionIDHigh, uint8_t transactionIDLow);
218 
219  /* RFCOMM Commands */
220  void RFCOMM_Command(uint8_t *data, uint8_t nbytes);
221  void sendRfcomm(uint8_t channel, uint8_t direction, uint8_t CR, uint8_t channelType, uint8_t pfBit, uint8_t *data, uint8_t length);
222  void sendRfcommCredit(uint8_t channel, uint8_t direction, uint8_t CR, uint8_t channelType, uint8_t pfBit, uint8_t credit);
223  uint8_t calcFcs(uint8_t *data);
224  bool checkFcs(uint8_t *data, uint8_t fcs);
225  uint8_t crc(uint8_t *data);
226 };
227 #endif
size_t write(uint8_t data)
Definition: SPP.cpp:742
+Go to the documentation of this file.
1 /* Copyright (C) 2012 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 _spp_h_
19 #define _spp_h_
20 
21 #include "BTD.h"
22 
23 /* Used for RFCOMM */
24 #define RFCOMM_SABM 0x2F
25 #define RFCOMM_UA 0x63
26 #define RFCOMM_UIH 0xEF
27 //#define RFCOMM_DM 0x0F
28 #define RFCOMM_DISC 0x43
29 
30 #define extendAddress 0x01 // Always 1
31 
32 // Multiplexer message types
33 #define BT_RFCOMM_PN_CMD 0x83
34 #define BT_RFCOMM_PN_RSP 0x81
35 #define BT_RFCOMM_MSC_CMD 0xE3
36 #define BT_RFCOMM_MSC_RSP 0xE1
37 #define BT_RFCOMM_RPN_CMD 0x93
38 #define BT_RFCOMM_RPN_RSP 0x91
39 /*
40 #define BT_RFCOMM_TEST_CMD 0x23
41 #define BT_RFCOMM_TEST_RSP 0x21
42 #define BT_RFCOMM_FCON_CMD 0xA3
43 #define BT_RFCOMM_FCON_RSP 0xA1
44 #define BT_RFCOMM_FCOFF_CMD 0x63
45 #define BT_RFCOMM_FCOFF_RSP 0x61
46 #define BT_RFCOMM_RLS_CMD 0x53
47 #define BT_RFCOMM_RLS_RSP 0x51
48 #define BT_RFCOMM_NSC_RSP 0x11
49  */
50 
55 class SPP : public BluetoothService, public Stream {
56 public:
63  SPP(BTD *p, const char *name = "Arduino", const char *pin = "0000");
64 
67  void disconnect();
74  operator bool() {
75  return connected;
76  }
78  bool connected;
79 
85  int available(void);
86 
88  void flush(void) {
89  send();
90  };
95  int peek(void);
100  int read(void);
101 
102 #if defined(ARDUINO) && ARDUINO >=100
103 
108  size_t write(uint8_t data);
115  size_t write(const uint8_t* data, size_t size);
117 #if !defined(RBL_NRF51822)
118  using Print::write;
119 #endif
120 #else
121 
125  void write(uint8_t data);
131  void write(const uint8_t* data, size_t size);
132 #endif
133 
135  void discard(void);
141  void send(void);
144 protected:
150  void ACLData(uint8_t* ACLData);
152  void Run();
154  void Reset();
160  void onInit();
163 private:
164  /* Set true when a channel is created */
165  bool SDPConnected;
166  bool RFCOMMConnected;
167 
168  /* Variables used by L2CAP state machines */
169  uint8_t l2cap_sdp_state;
170  uint8_t l2cap_rfcomm_state;
171 
172  uint8_t l2capoutbuf[BULK_MAXPKTSIZE]; // General purpose buffer for l2cap out data
173  uint8_t rfcommbuf[10]; // Buffer for RFCOMM Commands
174 
175  /* L2CAP Channels */
176  uint8_t sdp_scid[2]; // L2CAP source CID for SDP
177  uint8_t sdp_dcid[2]; // 0x0050
178  uint8_t rfcomm_scid[2]; // L2CAP source CID for RFCOMM
179  uint8_t rfcomm_dcid[2]; // 0x0051
180 
181  /* RFCOMM Variables */
182  uint8_t rfcommChannel;
183  uint8_t rfcommChannelConnection; // This is the channel the SPP channel will be running at
184  uint8_t rfcommDirection;
185  uint8_t rfcommCommandResponse;
186  uint8_t rfcommChannelType;
187  uint8_t rfcommPfBit;
188 
189  uint32_t timer;
190  bool waitForLastCommand;
191  bool creditSent;
192 
193  uint8_t rfcommDataBuffer[100]; // Create a 100 sized buffer for incoming data
194  uint8_t sppOutputBuffer[100]; // Create a 100 sized buffer for outgoing SPP data
195  uint8_t sppIndex;
196  uint8_t rfcommAvailable;
197 
198  bool firstMessage; // Used to see if it's the first SDP request received
199  uint8_t bytesRead; // Counter to see when it's time to send more credit
200 
201  /* State machines */
202  void SDP_task(); // SDP state machine
203  void RFCOMM_task(); // RFCOMM state machine
204 
205  /* SDP Commands */
206  void SDP_Command(uint8_t *data, uint8_t nbytes);
207  void serviceNotSupported(uint8_t transactionIDHigh, uint8_t transactionIDLow);
208  void serialPortResponse1(uint8_t transactionIDHigh, uint8_t transactionIDLow);
209  void serialPortResponse2(uint8_t transactionIDHigh, uint8_t transactionIDLow);
210  void l2capResponse1(uint8_t transactionIDHigh, uint8_t transactionIDLow);
211  void l2capResponse2(uint8_t transactionIDHigh, uint8_t transactionIDLow);
212 
213  /* RFCOMM Commands */
214  void RFCOMM_Command(uint8_t *data, uint8_t nbytes);
215  void sendRfcomm(uint8_t channel, uint8_t direction, uint8_t CR, uint8_t channelType, uint8_t pfBit, uint8_t *data, uint8_t length);
216  void sendRfcommCredit(uint8_t channel, uint8_t direction, uint8_t CR, uint8_t channelType, uint8_t pfBit, uint8_t credit);
217  uint8_t calcFcs(uint8_t *data);
218  bool checkFcs(uint8_t *data, uint8_t fcs);
219  uint8_t crc(uint8_t *data);
220 };
221 #endif
size_t write(uint8_t data)
Definition: SPP.cpp:742
void onInit()
Definition: SPP.cpp:433
SPP(BTD *p, const char *name="Arduino", const char *pin="0000")
Definition: SPP.cpp:45
-
Definition: BTD.h:201
-
void flush(void)
Definition: SPP.h:94
-
bool connected
Definition: SPP.h:84
+
Definition: BTD.h:221
+
void flush(void)
Definition: SPP.h:88
+
bool connected
Definition: SPP.h:78
int read(void)
Definition: SPP.cpp:811
void Run()
Definition: SPP.cpp:423
- +
void Reset()
Definition: SPP.cpp:60
int available(void)
Definition: SPP.cpp:797
void discard(void)
Definition: SPP.cpp:801
#define BULK_MAXPKTSIZE
Definition: BTD.h:37
void disconnect()
Definition: SPP.cpp:72
-
Definition: SPP.h:61
+
Definition: SPP.h:55
void send(void)
Definition: SPP.cpp:769
void ACLData(uint8_t *ACLData)
Definition: SPP.cpp:84
diff --git a/_usb_8h.html b/_usb_8h.html index 7f13d5b2..cb136e17 100644 --- a/_usb_8h.html +++ b/_usb_8h.html @@ -91,55 +91,55 @@ This graph shows which files directly or indirectly include this file:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
diff --git a/_usb_8h__dep__incl.map b/_usb_8h__dep__incl.map index 0318b392..a317b165 100644 --- a/_usb_8h__dep__incl.map +++ b/_usb_8h__dep__incl.map @@ -1,51 +1,51 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/_usb_8h__dep__incl.md5 b/_usb_8h__dep__incl.md5 index d05d3dae..6a821aa3 100644 --- a/_usb_8h__dep__incl.md5 +++ b/_usb_8h__dep__incl.md5 @@ -1 +1 @@ -02dd4b5bb74a4b06471e56603cb1a320 \ No newline at end of file +7c643f23ca87656d0de4bb0b970d686b \ No newline at end of file diff --git a/_usb_8h__dep__incl.png b/_usb_8h__dep__incl.png index fb2d7566f181b9ff48a932d197b397cca9c3cf75..7a2bd06b538d02d0833bee1677e25894105989f3 100644 GIT binary patch literal 145423 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%0D#p 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 z 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 literal 133098 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 z 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

vg+FBOiHQcuG9`7_k*v&4@% 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

Go to the documentation of this file.
1 /* Copyright (C) 2012 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  IR camera support added by Allan Glover (adglover9.81@gmail.com) and Kristian Lauszus
18  */
19 
20 #include "Wii.h"
21 // To enable serial debugging see "settings.h"
22 //#define EXTRADEBUG // Uncomment to get even more debugging data
23 //#define PRINTREPORT // Uncomment to print the report send by the Wii controllers
24 
25 const uint8_t WII_LEDS[] PROGMEM = {
26  0x00, // OFF
27  0x10, // LED1
28  0x20, // LED2
29  0x40, // LED3
30  0x80, // LED4
31 
32  0x90, // LED5
33  0xA0, // LED6
34  0xC0, // LED7
35  0xD0, // LED8
36  0xE0, // LED9
37  0xF0, // LED10
38 };
39 
40 const uint32_t WII_BUTTONS[] PROGMEM = {
41  0x00008, // UP
42  0x00002, // RIGHT
43  0x00004, // DOWN
44  0x00001, // LEFT
45 
46  0, // Skip
47  0x00010, // PLUS
48  0x00100, // TWO
49  0x00200, // ONE
50 
51  0x01000, // MINUS
52  0x08000, // HOME
53  0x10000, // Z
54  0x20000, // C
55 
56  0x00400, // B
57  0x00800, // A
58 };
59 const uint32_t WII_PROCONTROLLER_BUTTONS[] PROGMEM = {
60  0x00100, // UP
61  0x00080, // RIGHT
62  0x00040, // DOWN
63  0x00200, // LEFT
64 
65  0, // Skip
66  0x00004, // PLUS
67  0x20000, // L3
68  0x10000, // R3
69 
70  0x00010, // MINUS
71  0x00008, // HOME
72  0, 0, // Skip
73 
74  0x04000, // B
75  0x01000, // A
76  0x00800, // X
77  0x02000, // Y
78 
79  0x00020, // L
80  0x00002, // R
81  0x08000, // ZL
82  0x00400, // ZR
83 };
84 
85 WII::WII(BTD *p, bool pair) :
86 BluetoothService(p) // Pointer to USB class instance - mandatory
87 {
89 
90  HIDBuffer[0] = 0xA2; // HID BT DATA_request (0xA0) | Report Type (Output 0x02)
91 
92  /* Set device cid for the control and intterrupt channelse - LSB */
93  control_dcid[0] = 0x60; // 0x0060
94  control_dcid[1] = 0x00;
95  interrupt_dcid[0] = 0x61; // 0x0061
96  interrupt_dcid[1] = 0x00;
97 
98  Reset();
99 }
100 
101 void WII::Reset() {
102  wiimoteConnected = false;
103  nunchuckConnected = false;
104  motionPlusConnected = false;
105  activateNunchuck = false;
106  motionValuesReset = false;
107  activeConnection = false;
108  motionPlusInside = false;
109  pBtd->wiiUProController = false;
111  wiiBalanceBoardConnected = false;
112  l2cap_event_flag = 0; // Reset flags
113  l2cap_state = L2CAP_WAIT;
114 }
115 
116 void WII::disconnect() { // Use this void to disconnect any of the controllers
117  if(!motionPlusInside) { // The old Wiimote needs a delay after the first command or it will automatically reconnect
118  if(motionPlusConnected) {
119 #ifdef DEBUG_USB_HOST
120  Notify(PSTR("\r\nDeactivating Motion Plus"), 0x80);
121 #endif
122  initExtension1(); // This will disable the Motion Plus extension
123  }
124  timer = (uint32_t)millis() + 1000; // We have to wait for the message before the rest of the channels can be deactivated
125  } else
126  timer = (uint32_t)millis(); // Don't wait
127  // First the HID interrupt channel has to be disconnected, then the HID control channel and finally the HCI connection
128  pBtd->l2cap_disconnection_request(hci_handle, ++identifier, interrupt_scid, interrupt_dcid);
129  Reset();
130  l2cap_state = L2CAP_INTERRUPT_DISCONNECT;
131 }
132 
133 void WII::ACLData(uint8_t* l2capinbuf) {
134  if(!pBtd->l2capConnectionClaimed && pBtd->incomingWii && !wiimoteConnected && !activeConnection) {
135  if(l2capinbuf[8] == L2CAP_CMD_CONNECTION_REQUEST) {
136  if((l2capinbuf[12] | (l2capinbuf[13] << 8)) == HID_CTRL_PSM) {
137  motionPlusInside = pBtd->motionPlusInside;
138  pBtd->incomingWii = false;
139  pBtd->l2capConnectionClaimed = true; // Claim that the incoming connection belongs to this service
140  activeConnection = true;
141  hci_handle = pBtd->hci_handle; // Store the HCI Handle for the connection
142  l2cap_state = L2CAP_WAIT;
143  }
144  }
145  }
146 
147  if(checkHciHandle(l2capinbuf, hci_handle)) { // acl_handle_ok
148  if((l2capinbuf[6] | (l2capinbuf[7] << 8)) == 0x0001U) { // l2cap_control - Channel ID for ACL-U
149  if(l2capinbuf[8] == L2CAP_CMD_COMMAND_REJECT) {
150 #ifdef DEBUG_USB_HOST
151  Notify(PSTR("\r\nL2CAP Command Rejected - Reason: "), 0x80);
152  D_PrintHex<uint8_t > (l2capinbuf[13], 0x80);
153  Notify(PSTR(" "), 0x80);
154  D_PrintHex<uint8_t > (l2capinbuf[12], 0x80);
155  Notify(PSTR(" "), 0x80);
156  D_PrintHex<uint8_t > (l2capinbuf[17], 0x80);
157  Notify(PSTR(" "), 0x80);
158  D_PrintHex<uint8_t > (l2capinbuf[16], 0x80);
159  Notify(PSTR(" "), 0x80);
160  D_PrintHex<uint8_t > (l2capinbuf[15], 0x80);
161  Notify(PSTR(" "), 0x80);
162  D_PrintHex<uint8_t > (l2capinbuf[14], 0x80);
163 #endif
164  } else if(l2capinbuf[8] == L2CAP_CMD_CONNECTION_RESPONSE) {
165  if(((l2capinbuf[16] | (l2capinbuf[17] << 8)) == 0x0000) && ((l2capinbuf[18] | (l2capinbuf[19] << 8)) == SUCCESSFUL)) { // Success
166  if(l2capinbuf[14] == control_dcid[0] && l2capinbuf[15] == control_dcid[1]) {
167  //Notify(PSTR("\r\nHID Control Connection Complete"), 0x80);
168  identifier = l2capinbuf[9];
169  control_scid[0] = l2capinbuf[12];
170  control_scid[1] = l2capinbuf[13];
172  } else if(l2capinbuf[14] == interrupt_dcid[0] && l2capinbuf[15] == interrupt_dcid[1]) {
173  //Notify(PSTR("\r\nHID Interrupt Connection Complete"), 0x80);
174  identifier = l2capinbuf[9];
175  interrupt_scid[0] = l2capinbuf[12];
176  interrupt_scid[1] = l2capinbuf[13];
178  }
179  }
180  } else if(l2capinbuf[8] == L2CAP_CMD_CONNECTION_REQUEST) {
181 #ifdef EXTRADEBUG
182  Notify(PSTR("\r\nL2CAP Connection Request - PSM: "), 0x80);
183  D_PrintHex<uint8_t > (l2capinbuf[13], 0x80);
184  Notify(PSTR(" "), 0x80);
185  D_PrintHex<uint8_t > (l2capinbuf[12], 0x80);
186  Notify(PSTR(" SCID: "), 0x80);
187  D_PrintHex<uint8_t > (l2capinbuf[15], 0x80);
188  Notify(PSTR(" "), 0x80);
189  D_PrintHex<uint8_t > (l2capinbuf[14], 0x80);
190  Notify(PSTR(" Identifier: "), 0x80);
191  D_PrintHex<uint8_t > (l2capinbuf[9], 0x80);
192 #endif
193  if((l2capinbuf[12] | (l2capinbuf[13] << 8)) == HID_CTRL_PSM) {
194  identifier = l2capinbuf[9];
195  control_scid[0] = l2capinbuf[14];
196  control_scid[1] = l2capinbuf[15];
198  } else if((l2capinbuf[12] | (l2capinbuf[13] << 8)) == HID_INTR_PSM) {
199  identifier = l2capinbuf[9];
200  interrupt_scid[0] = l2capinbuf[14];
201  interrupt_scid[1] = l2capinbuf[15];
203  }
204  } else if(l2capinbuf[8] == L2CAP_CMD_CONFIG_RESPONSE) {
205  if((l2capinbuf[16] | (l2capinbuf[17] << 8)) == 0x0000) { // Success
206  if(l2capinbuf[12] == control_dcid[0] && l2capinbuf[13] == control_dcid[1]) {
207  //Notify(PSTR("\r\nHID Control Configuration Complete"), 0x80);
208  identifier = l2capinbuf[9];
210  } else if(l2capinbuf[12] == interrupt_dcid[0] && l2capinbuf[13] == interrupt_dcid[1]) {
211  //Notify(PSTR("\r\nHID Interrupt Configuration Complete"), 0x80);
212  identifier = l2capinbuf[9];
214  }
215  }
216  } else if(l2capinbuf[8] == L2CAP_CMD_CONFIG_REQUEST) {
217  if(l2capinbuf[12] == control_dcid[0] && l2capinbuf[13] == control_dcid[1]) {
218  //Notify(PSTR("\r\nHID Control Configuration Request"), 0x80);
219  pBtd->l2cap_config_response(hci_handle, l2capinbuf[9], control_scid);
220  } else if(l2capinbuf[12] == interrupt_dcid[0] && l2capinbuf[13] == interrupt_dcid[1]) {
221  //Notify(PSTR("\r\nHID Interrupt Configuration Request"), 0x80);
222  pBtd->l2cap_config_response(hci_handle, l2capinbuf[9], interrupt_scid);
223  }
224  } else if(l2capinbuf[8] == L2CAP_CMD_DISCONNECT_REQUEST) {
225  if(l2capinbuf[12] == control_dcid[0] && l2capinbuf[13] == control_dcid[1]) {
226 #ifdef DEBUG_USB_HOST
227  Notify(PSTR("\r\nDisconnect Request: Control Channel"), 0x80);
228 #endif
229  identifier = l2capinbuf[9];
230  pBtd->l2cap_disconnection_response(hci_handle, identifier, control_dcid, control_scid);
231  Reset();
232  } else if(l2capinbuf[12] == interrupt_dcid[0] && l2capinbuf[13] == interrupt_dcid[1]) {
233 #ifdef DEBUG_USB_HOST
234  Notify(PSTR("\r\nDisconnect Request: Interrupt Channel"), 0x80);
235 #endif
236  identifier = l2capinbuf[9];
237  pBtd->l2cap_disconnection_response(hci_handle, identifier, interrupt_dcid, interrupt_scid);
238  Reset();
239  }
240  } else if(l2capinbuf[8] == L2CAP_CMD_DISCONNECT_RESPONSE) {
241  if(l2capinbuf[12] == control_scid[0] && l2capinbuf[13] == control_scid[1]) {
242  //Notify(PSTR("\r\nDisconnect Response: Control Channel"), 0x80);
243  identifier = l2capinbuf[9];
245  } else if(l2capinbuf[12] == interrupt_scid[0] && l2capinbuf[13] == interrupt_scid[1]) {
246  //Notify(PSTR("\r\nDisconnect Response: Interrupt Channel"), 0x80);
247  identifier = l2capinbuf[9];
249  }
250  }
251 #ifdef EXTRADEBUG
252  else {
253  identifier = l2capinbuf[9];
254  Notify(PSTR("\r\nL2CAP Unknown Signaling Command: "), 0x80);
255  D_PrintHex<uint8_t > (l2capinbuf[8], 0x80);
256  }
257 #endif
258  } else if(l2capinbuf[6] == interrupt_dcid[0] && l2capinbuf[7] == interrupt_dcid[1]) { // l2cap_interrupt
259  //Notify(PSTR("\r\nL2CAP Interrupt"), 0x80);
260  if(l2capinbuf[8] == 0xA1) { // HID_THDR_DATA_INPUT
261  if((l2capinbuf[9] >= 0x20 && l2capinbuf[9] <= 0x22) || (l2capinbuf[9] >= 0x30 && l2capinbuf[9] <= 0x37) || l2capinbuf[9] == 0x3e || l2capinbuf[9] == 0x3f) { // These reports include the buttons
262  if((l2capinbuf[9] >= 0x20 && l2capinbuf[9] <= 0x22) || l2capinbuf[9] == 0x31 || l2capinbuf[9] == 0x33) // These reports have no extensions bytes
263  ButtonState = (uint32_t)((l2capinbuf[10] & 0x1F) | ((uint16_t)(l2capinbuf[11] & 0x9F) << 8));
265  ButtonState = (uint32_t)(((~l2capinbuf[23]) & 0xFE) | ((uint16_t)(~l2capinbuf[24]) << 8) | ((uint32_t)((~l2capinbuf[25]) & 0x03) << 16));
266  else if(motionPlusConnected) {
267  if(l2capinbuf[20] & 0x02) // Only update the Wiimote buttons, since the extension bytes are from the Motion Plus
268  ButtonState = (uint32_t)((l2capinbuf[10] & 0x1F) | ((uint16_t)(l2capinbuf[11] & 0x9F) << 8) | ((uint32_t)(ButtonState & 0xFFFF0000)));
269  else if(nunchuckConnected) // Update if it's a report from the Nunchuck
270  ButtonState = (uint32_t)((l2capinbuf[10] & 0x1F) | ((uint16_t)(l2capinbuf[11] & 0x9F) << 8) | ((uint32_t)((~l2capinbuf[20]) & 0x0C) << 14));
271  //else if(classicControllerConnected) // Update if it's a report from the Classic Controller
272  } else if(nunchuckConnected) // The Nunchuck is directly connected
273  ButtonState = (uint32_t)((l2capinbuf[10] & 0x1F) | ((uint16_t)(l2capinbuf[11] & 0x9F) << 8) | ((uint32_t)((~l2capinbuf[20]) & 0x03) << 16));
274  //else if(classicControllerConnected) // The Classic Controller is directly connected
275  else if(!unknownExtensionConnected)
276  ButtonState = (uint32_t)((l2capinbuf[10] & 0x1F) | ((uint16_t)(l2capinbuf[11] & 0x9F) << 8));
277 #ifdef PRINTREPORT
278  Notify(PSTR("ButtonState: "), 0x80);
279  D_PrintHex<uint32_t > (ButtonState, 0x80);
280  Notify(PSTR("\r\n"), 0x80);
281 #endif
282  if(ButtonState != OldButtonState) {
283  ButtonClickState = ButtonState & ~OldButtonState; // Update click state variable
284  OldButtonState = ButtonState;
285  }
286  }
287  if(l2capinbuf[9] == 0x31 || l2capinbuf[9] == 0x33 || l2capinbuf[9] == 0x35 || l2capinbuf[9] == 0x37) { // Read the accelerometer
288  accXwiimote = ((l2capinbuf[12] << 2) | (l2capinbuf[10] & 0x60 >> 5)) - 500;
289  accYwiimote = ((l2capinbuf[13] << 2) | (l2capinbuf[11] & 0x20 >> 4)) - 500;
290  accZwiimote = ((l2capinbuf[14] << 2) | (l2capinbuf[11] & 0x40 >> 5)) - 500;
291  }
292  switch(l2capinbuf[9]) {
293  case 0x20: // Status Information - (a1) 20 BB BB LF 00 00 VV
294 #ifdef EXTRADEBUG
295  Notify(PSTR("\r\nStatus report was received"), 0x80);
296 #endif
297  wiiState = l2capinbuf[12]; // (0x01: Battery is nearly empty), (0x02: An Extension Controller is connected), (0x04: Speaker enabled), (0x08: IR enabled), (0x10: LED1, 0x20: LED2, 0x40: LED3, 0x80: LED4)
298  batteryLevel = l2capinbuf[15]; // Update battery level
299 
300  if(!checkBatteryLevel) { // If this is true it means that the user must have called getBatteryLevel()
301  if(l2capinbuf[12] & 0x02) { // Check if a extension is connected
302 #ifdef DEBUG_USB_HOST
303  if(!unknownExtensionConnected)
304  Notify(PSTR("\r\nExtension connected"), 0x80);
305 #endif
306  unknownExtensionConnected = true;
307 #ifdef WIICAMERA
308  if(!isIRCameraEnabled()) // Don't activate the Motion Plus if we are trying to initialize the IR camera
309 #endif
310  setReportMode(false, 0x35); // Also read the extension
311  } else {
312 #ifdef DEBUG_USB_HOST
313  Notify(PSTR("\r\nExtension disconnected"), 0x80);
314 #endif
315  if(motionPlusConnected) {
316 #ifdef DEBUG_USB_HOST
317  Notify(PSTR(" - from Motion Plus"), 0x80);
318 #endif
320  if(!activateNunchuck) // If it's already trying to initialize the Nunchuck don't set it to false
321  nunchuckConnected = false;
322  //else if(classicControllerConnected)
323  } else if(nunchuckConnected) {
324 #ifdef DEBUG_USB_HOST
325  Notify(PSTR(" - Nunchuck"), 0x80);
326 #endif
327  nunchuckConnected = false; // It must be the Nunchuck controller then
329  onInit();
330 #ifdef WIICAMERA
331  if(!isIRCameraEnabled()) // We still want to read from the IR camera, so do not change the report mode
332 #endif
333  setReportMode(false, 0x31); // If there is no extension connected we will read the buttons and accelerometer
334  } else {
335 #ifdef WIICAMERA
336  if(!isIRCameraEnabled()) // We still want to read from the IR camera, so do not change the report mode
337 #endif
338  setReportMode(false, 0x31); // If there is no extension connected we will read the buttons and accelerometer
339  }
340  }
341  }
342  else {
343 #ifdef EXTRADEBUG
344  Notify(PSTR("\r\nChecking battery level"), 0x80);
345 #endif
346  checkBatteryLevel = false; // Check for extensions by default
347  }
348 #ifdef DEBUG_USB_HOST
349  if(l2capinbuf[12] & 0x01)
350  Notify(PSTR("\r\nWARNING: Battery is nearly empty"), 0x80);
351 #endif
352 
353  break;
354  case 0x21: // Read Memory Data
355  if((l2capinbuf[12] & 0x0F) == 0) { // No error
356  uint8_t reportLength = (l2capinbuf[12] >> 4) + 1; // // Bit 4-7 is the length - 1
357  // See: http://wiibrew.org/wiki/Wiimote/Extension_Controllers
358  if(l2capinbuf[16] == 0x00 && l2capinbuf[17] == 0xA4 && l2capinbuf[18] == 0x20 && l2capinbuf[19] == 0x00 && l2capinbuf[20] == 0x00) {
359 #ifdef DEBUG_USB_HOST
360  Notify(PSTR("\r\nNunchuck connected"), 0x80);
361 #endif
363  } else if(l2capinbuf[16] == 0x00 && (l2capinbuf[17] == 0xA6 || l2capinbuf[17] == 0xA4) && l2capinbuf[18] == 0x20 && l2capinbuf[19] == 0x00 && l2capinbuf[20] == 0x05) {
364 #ifdef DEBUG_USB_HOST
365  Notify(PSTR("\r\nMotion Plus connected"), 0x80);
366 #endif
368  } else if(l2capinbuf[16] == 0x00 && l2capinbuf[17] == 0xA4 && l2capinbuf[18] == 0x20 && l2capinbuf[19] == 0x04 && l2capinbuf[20] == 0x05) {
369 #ifdef DEBUG_USB_HOST
370  Notify(PSTR("\r\nMotion Plus activated in normal mode"), 0x80);
371 #endif
372  motionPlusConnected = true;
373 #ifdef WIICAMERA
374  if(!isIRCameraEnabled()) // Don't activate the Motion Plus if we are trying to initialize the IR camera
375 #endif
376  setReportMode(false, 0x35); // Also read the extension
377  } else if(l2capinbuf[16] == 0x00 && l2capinbuf[17] == 0xA4 && l2capinbuf[18] == 0x20 && l2capinbuf[19] == 0x05 && l2capinbuf[20] == 0x05) {
378 #ifdef DEBUG_USB_HOST
379  Notify(PSTR("\r\nMotion Plus activated in Nunchuck pass-through mode"), 0x80);
380 #endif
381  activateNunchuck = false;
382  motionPlusConnected = true;
383  nunchuckConnected = true;
384 #ifdef WIICAMERA
385  if(!isIRCameraEnabled()) // Don't activate the Motion Plus if we are trying to initialize the IR camera
386 #endif
387  setReportMode(false, 0x35); // Also read the extension
388  } else if(l2capinbuf[16] == 0x00 && l2capinbuf[17] == 0xA6 && l2capinbuf[18] == 0x20 && (l2capinbuf[19] == 0x00 || l2capinbuf[19] == 0x04 || l2capinbuf[19] == 0x05 || l2capinbuf[19] == 0x07) && l2capinbuf[20] == 0x05) {
389 #ifdef DEBUG_USB_HOST
390  Notify(PSTR("\r\nInactive Wii Motion Plus"), 0x80);
391  Notify(PSTR("\r\nPlease unplug the Motion Plus, disconnect the Wiimote and then replug the Motion Plus Extension"), 0x80);
392 #endif
393  stateCounter = 300; // Skip the rest in "WII_CHECK_MOTION_PLUS_STATE"
394  } else if(l2capinbuf[16] == 0x00 && l2capinbuf[17] == 0xA4 && l2capinbuf[18] == 0x20 && l2capinbuf[19] == 0x01 && l2capinbuf[20] == 0x20) {
395 #ifdef DEBUG_USB_HOST
396  Notify(PSTR("\r\nWii U Pro Controller connected"), 0x80);
397 #endif
399  } else if(l2capinbuf[16] == 0x00 && l2capinbuf[17] == 0xA4 && l2capinbuf[18] == 0x20 && l2capinbuf[19] == 0x04 && l2capinbuf[20] == 0x02) {
400 #ifdef DEBUG_USB_HOST
401  Notify(PSTR("\r\nWii Balance Board connected"), 0x80);
402 #endif
403  setReportMode(false, 0x32); // Read the Wii Balance Board extension
405  }
406  // Wii Balance Board calibration reports (24 bits in total)
407  else if(l2capinbuf[13] == 0x00 && l2capinbuf[14] == 0x24 && reportLength == 16) { // First 16-bit
408  for(uint8_t i = 0; i < 2; i++) {
409  for(uint8_t j = 0; j < 4; j++)
410  wiiBalanceBoardCal[i][j] = l2capinbuf[16 + 8 * i + 2 * j] | l2capinbuf[15 + 8 * i + 2 * j] << 8;
411  }
412  } else if(l2capinbuf[13] == 0x00 && l2capinbuf[14] == 0x34 && reportLength == 8) { // Last 8-bit
413  for(uint8_t j = 0; j < 4; j++)
414  wiiBalanceBoardCal[2][j] = l2capinbuf[16 + 2 * j] | l2capinbuf[15 + 2 * j] << 8;
415 #ifdef DEBUG_USB_HOST
416  Notify(PSTR("\r\nWii Balance Board calibration values read successfully"), 0x80);
417 #endif
420  }
421 #ifdef DEBUG_USB_HOST
422  else {
423  Notify(PSTR("\r\nUnknown Device: "), 0x80);
424  D_PrintHex<uint8_t > (l2capinbuf[13], 0x80);
425  D_PrintHex<uint8_t > (l2capinbuf[14], 0x80);
426  Notify(PSTR("\r\nData: "), 0x80);
427  for(uint8_t i = 0; i < reportLength; i++) {
428  D_PrintHex<uint8_t > (l2capinbuf[15 + i], 0x80);
429  Notify(PSTR(" "), 0x80);
430  }
431  }
432 #endif
433  }
434 #ifdef EXTRADEBUG
435  else {
436  Notify(PSTR("\r\nReport Error: "), 0x80);
437  D_PrintHex<uint8_t > (l2capinbuf[13], 0x80);
438  D_PrintHex<uint8_t > (l2capinbuf[14], 0x80);
439  }
440 #endif
441  break;
442  case 0x22: // Acknowledge output report, return function result
443 #ifdef DEBUG_USB_HOST
444  if(l2capinbuf[13] != 0x00) { // Check if there is an error
445  Notify(PSTR("\r\nCommand failed: "), 0x80);
446  D_PrintHex<uint8_t > (l2capinbuf[12], 0x80);
447  }
448 #endif
449  break;
450  case 0x30: // Core buttons - (a1) 30 BB BB
451  break;
452  case 0x31: // Core Buttons and Accelerometer - (a1) 31 BB BB AA AA AA
453  break;
454  case 0x32: // Core Buttons with 8 Extension bytes - (a1) 32 BB BB EE EE EE EE EE EE EE EE
455  // See: http://wiibrew.org/wiki/Wii_Balance_Board#Data_Format
456  wiiBalanceBoardRaw[TopRight] = l2capinbuf[13] | l2capinbuf[12] << 8; // Top right
457  wiiBalanceBoardRaw[BotRight] = l2capinbuf[15] | l2capinbuf[14] << 8; // Bottom right
458  wiiBalanceBoardRaw[TopLeft] = l2capinbuf[17] | l2capinbuf[16] << 8; // Top left
459  wiiBalanceBoardRaw[BotLeft] = l2capinbuf[19] | l2capinbuf[18] << 8; // Bottom left
460  break;
461  case 0x33: // Core Buttons with Accelerometer and 12 IR bytes - (a1) 33 BB BB AA AA AA II II II II II II II II II II II II
462 #ifdef WIICAMERA
463  // Read the IR data
464  IR_object_x1 = (l2capinbuf[15] | ((uint16_t)(l2capinbuf[17] & 0x30) << 4)); // x position
465  IR_object_y1 = (l2capinbuf[16] | ((uint16_t)(l2capinbuf[17] & 0xC0) << 2)); // y position
466  IR_object_s1 = (l2capinbuf[17] & 0x0F); // Size value, 0-15
467 
468  IR_object_x2 = (l2capinbuf[18] | ((uint16_t)(l2capinbuf[20] & 0x30) << 4));
469  IR_object_y2 = (l2capinbuf[19] | ((uint16_t)(l2capinbuf[20] & 0xC0) << 2));
470  IR_object_s2 = (l2capinbuf[20] & 0x0F);
471 
472  IR_object_x3 = (l2capinbuf[21] | ((uint16_t)(l2capinbuf[23] & 0x30) << 4));
473  IR_object_y3 = (l2capinbuf[22] | ((uint16_t)(l2capinbuf[23] & 0xC0) << 2));
474  IR_object_s3 = (l2capinbuf[23] & 0x0F);
475 
476  IR_object_x4 = (l2capinbuf[24] | ((uint16_t)(l2capinbuf[26] & 0x30) << 4));
477  IR_object_y4 = (l2capinbuf[25] | ((uint16_t)(l2capinbuf[26] & 0xC0) << 2));
478  IR_object_s4 = (l2capinbuf[26] & 0x0F);
479 #endif
480  break;
481  case 0x34: // Core Buttons with 19 Extension bytes - (a1) 34 BB BB EE EE EE EE EE EE EE EE EE EE EE EE EE EE EE EE EE EE EE
482  break;
483  /* 0x3e and 0x3f both give unknown report types when report mode is 0x3e or 0x3f with mode number 0x05 */
484  case 0x3E: // Core Buttons with Accelerometer and 32 IR bytes
485  // (a1) 31 BB BB AA AA AA II II II II II II II II II II II II II II II II II II II II II II II II II II II II II II II II
486  // corresponds to output report mode 0x3e
487 
488  /**** for reading in full mode: DOES NOT WORK YET ****/
489  /* When it works it will also have intensity and bounding box data */
490  /*
491  IR_object_x1 = (l2capinbuf[13] | ((uint16_t)(l2capinbuf[15] & 0x30) << 4));
492  IR_object_y1 = (l2capinbuf[14] | ((uint16_t)(l2capinbuf[15] & 0xC0) << 2));
493  IR_object_s1 = (l2capinbuf[15] & 0x0F);
494  */
495  break;
496  case 0x3F:
497  /*
498  IR_object_x1 = (l2capinbuf[13] | ((uint16_t)(l2capinbuf[15] & 0x30) << 4));
499  IR_object_y1 = (l2capinbuf[14] | ((uint16_t)(l2capinbuf[15] & 0xC0) << 2));
500  IR_object_s1 = (l2capinbuf[15] & 0x0F);
501  */
502  break;
503  case 0x35: // Core Buttons and Accelerometer with 16 Extension Bytes
504  // (a1) 35 BB BB AA AA AA EE EE EE EE EE EE EE EE EE EE EE EE EE EE EE EE
505 #if 1 // Set this to 0 if you don't want to use an extension, this reduceds the size of the library a lot!
506  if(motionPlusConnected) {
507  if(l2capinbuf[20] & 0x02) { // Check if it's a report from the Motion controller or the extension
508  if(motionValuesReset) { // We will only use the values when the gyro value has been set
509  gyroYawRaw = ((l2capinbuf[15] | ((l2capinbuf[18] & 0xFC) << 6)) - gyroYawZero);
510  gyroRollRaw = ((l2capinbuf[16] | ((l2capinbuf[19] & 0xFC) << 6)) - gyroRollZero);
511  gyroPitchRaw = ((l2capinbuf[17] | ((l2capinbuf[20] & 0xFC) << 6)) - gyroPitchZero);
512 
513  yawGyroSpeed = (float)gyroYawRaw / ((float)gyroYawZero / yawGyroScale);
514  rollGyroSpeed = -(float)gyroRollRaw / ((float)gyroRollZero / rollGyroScale); // We invert these values so they will fit the acc values
516 
517  /* The onboard gyro has two ranges for slow and fast mode */
518  if(!(l2capinbuf[18] & 0x02)) // Check if fast mode is used
519  yawGyroSpeed *= 4.545;
520  if(!(l2capinbuf[18] & 0x01)) // Check if fast mode is used
521  pitchGyroSpeed *= 4.545;
522  if(!(l2capinbuf[19] & 0x02)) // Check if fast mode is used
523  rollGyroSpeed *= 4.545;
524 
525  compPitch = (0.93f * (compPitch + (pitchGyroSpeed * (float)((uint32_t)micros() - timer) / 1000000.0f)))+(0.07f * getWiimotePitch()); // Use a complimentary filter to calculate the angle
526  compRoll = (0.93f * (compRoll + (rollGyroSpeed * (float)((uint32_t)micros() - timer) / 1000000.0f)))+(0.07f * getWiimoteRoll());
527 
528  gyroYaw += (yawGyroSpeed * ((float)((uint32_t)micros() - timer) / 1000000.0f));
529  gyroRoll += (rollGyroSpeed * ((float)((uint32_t)micros() - timer) / 1000000.0f));
530  gyroPitch += (pitchGyroSpeed * ((float)((uint32_t)micros() - timer) / 1000000.0f));
531  timer = (uint32_t)micros();
532  /*
533  // Uncomment these lines to tune the gyro scale variabels
534  Notify(PSTR("\r\ngyroYaw: "), 0x80);
535  Notify(gyroYaw, 0x80);
536  Notify(PSTR("\tgyroRoll: "), 0x80);
537  Notify(gyroRoll, 0x80);
538  Notify(PSTR("\tgyroPitch: "), 0x80);
539  Notify(gyroPitch, 0x80);
540  */
541  /*
542  Notify(PSTR("\twiimoteRoll: "), 0x80);
543  Notify(wiimoteRoll, 0x80);
544  Notify(PSTR("\twiimotePitch: "), 0x80);
545  Notify(wiimotePitch, 0x80);
546  */
547  } else {
548  if((int32_t)((uint32_t)micros() - timer) > 1000000) { // Loop for 1 sec before resetting the values
549 #ifdef DEBUG_USB_HOST
550  Notify(PSTR("\r\nThe gyro values has been reset"), 0x80);
551 #endif
552  gyroYawZero = (l2capinbuf[15] | ((l2capinbuf[18] & 0xFC) << 6));
553  gyroRollZero = (l2capinbuf[16] | ((l2capinbuf[19] & 0xFC) << 6));
554  gyroPitchZero = (l2capinbuf[17] | ((l2capinbuf[20] & 0xFC) << 6));
555 
556  rollGyroScale = 500; // You might need to adjust these
557  pitchGyroScale = 400;
558  yawGyroScale = 415;
559 
560  gyroYaw = 0;
561  gyroRoll = 0;
562  gyroPitch = 0;
563 
564  motionValuesReset = true;
565  timer = (uint32_t)micros();
566  }
567  }
568  } else {
569  if(nunchuckConnected) {
570  hatValues[HatX] = l2capinbuf[15];
571  hatValues[HatY] = l2capinbuf[16];
572  accXnunchuck = ((l2capinbuf[17] << 2) | (l2capinbuf[20] & 0x10 >> 3)) - 416;
573  accYnunchuck = ((l2capinbuf[18] << 2) | (l2capinbuf[20] & 0x20 >> 4)) - 416;
574  accZnunchuck = (((l2capinbuf[19] & 0xFE) << 2) | (l2capinbuf[20] & 0xC0 >> 5)) - 416;
575  }
576  //else if(classicControllerConnected) { }
577  }
578  if(l2capinbuf[19] & 0x01) {
579  if(!extensionConnected) {
580  extensionConnected = true;
581  unknownExtensionConnected = true;
582 #ifdef DEBUG_USB_HOST
583  Notify(PSTR("\r\nExtension connected to Motion Plus"), 0x80);
584 #endif
585  }
586  } else {
587  if(extensionConnected && !unknownExtensionConnected) {
588  extensionConnected = false;
589  unknownExtensionConnected = true;
590 #ifdef DEBUG_USB_HOST
591  Notify(PSTR("\r\nExtension disconnected from Motion Plus"), 0x80);
592 #endif
593  nunchuckConnected = false; // There is no extension connected to the Motion Plus if this report is sent
594  }
595  }
596 
597  } else if(nunchuckConnected) {
598  hatValues[HatX] = l2capinbuf[15];
599  hatValues[HatY] = l2capinbuf[16];
600  accXnunchuck = ((l2capinbuf[17] << 2) | (l2capinbuf[20] & 0x0C >> 2)) - 416;
601  accYnunchuck = ((l2capinbuf[18] << 2) | (l2capinbuf[20] & 0x30 >> 4)) - 416;
602  accZnunchuck = ((l2capinbuf[19] << 2) | (l2capinbuf[20] & 0xC0 >> 6)) - 416;
603  } else if(wiiUProControllerConnected) {
604  hatValues[LeftHatX] = (l2capinbuf[15] | l2capinbuf[16] << 8);
605  hatValues[RightHatX] = (l2capinbuf[17] | l2capinbuf[18] << 8);
606  hatValues[LeftHatY] = (l2capinbuf[19] | l2capinbuf[20] << 8);
607  hatValues[RightHatY] = (l2capinbuf[21] | l2capinbuf[22] << 8);
608  }
609 #endif
610  break;
611 #ifdef DEBUG_USB_HOST
612  default:
613  Notify(PSTR("\r\nUnknown Report type: "), 0x80);
614  D_PrintHex<uint8_t > (l2capinbuf[9], 0x80);
615  break;
616 #endif
617  }
618  }
619  }
620  L2CAP_task();
621  }
622 }
623 
624 void WII::L2CAP_task() {
625  switch(l2cap_state) {
626  /* These states are used if the Wiimote is the host */
629 #ifdef DEBUG_USB_HOST
630  Notify(PSTR("\r\nHID Control Successfully Configured"), 0x80);
631 #endif
632  l2cap_state = L2CAP_INTERRUPT_SETUP;
633  }
634  break;
635 
638 #ifdef DEBUG_USB_HOST
639  Notify(PSTR("\r\nHID Interrupt Incoming Connection Request"), 0x80);
640 #endif
641  pBtd->l2cap_connection_response(hci_handle, identifier, interrupt_dcid, interrupt_scid, PENDING);
642  delay(1);
643  pBtd->l2cap_connection_response(hci_handle, identifier, interrupt_dcid, interrupt_scid, SUCCESSFUL);
644  identifier++;
645  delay(1);
646  pBtd->l2cap_config_request(hci_handle, identifier, interrupt_scid);
647 
648  l2cap_state = L2CAP_INTERRUPT_CONFIG_REQUEST;
649  }
650  break;
651 
652  /* These states are used if the Arduino is the host */
655 #ifdef DEBUG_USB_HOST
656  Notify(PSTR("\r\nSend HID Control Config Request"), 0x80);
657 #endif
658  identifier++;
660  l2cap_state = L2CAP_CONTROL_CONFIG_REQUEST;
661  }
662  break;
663 
666 #ifdef DEBUG_USB_HOST
667  Notify(PSTR("\r\nSend HID Interrupt Connection Request"), 0x80);
668 #endif
669  identifier++;
671  l2cap_state = L2CAP_INTERRUPT_CONNECT_REQUEST;
672  }
673  break;
674 
677 #ifdef DEBUG_USB_HOST
678  Notify(PSTR("\r\nSend HID Interrupt Config Request"), 0x80);
679 #endif
680  identifier++;
681  pBtd->l2cap_config_request(hci_handle, identifier, interrupt_scid);
682  l2cap_state = L2CAP_INTERRUPT_CONFIG_REQUEST;
683  }
684  break;
685 
687  if(l2cap_check_flag(L2CAP_FLAG_CONFIG_INTERRUPT_SUCCESS)) { // Now the HID channels is established
688 #ifdef DEBUG_USB_HOST
689  Notify(PSTR("\r\nHID Channels Established"), 0x80);
690 #endif
691  pBtd->connectToWii = false;
692  pBtd->pairWithWii = false;
693  stateCounter = 0;
694  l2cap_state = WII_CHECK_MOTION_PLUS_STATE;
695  }
696  break;
697 
698  /* The next states are in run() */
699 
701  if(l2cap_check_flag(L2CAP_FLAG_DISCONNECT_INTERRUPT_RESPONSE) && ((int32_t)((uint32_t)millis() - timer) >= 0L)) {
702 #ifdef DEBUG_USB_HOST
703  Notify(PSTR("\r\nDisconnected Interrupt Channel"), 0x80);
704 #endif
705  identifier++;
706  pBtd->l2cap_disconnection_request(hci_handle, identifier, control_scid, control_dcid);
707  l2cap_state = L2CAP_CONTROL_DISCONNECT;
708  }
709  break;
710 
713 #ifdef DEBUG_USB_HOST
714  Notify(PSTR("\r\nDisconnected Control Channel"), 0x80);
715 #endif
717  hci_handle = -1; // Reset handle
718  l2cap_event_flag = 0; // Reset flags
719  l2cap_state = L2CAP_WAIT;
720  }
721  break;
722  }
723 }
724 
725 void WII::Run() {
726  if(l2cap_state == L2CAP_INTERRUPT_DISCONNECT && ((int32_t)((uint32_t)millis() - timer) >= 0L))
727  L2CAP_task(); // Call the rest of the disconnection routine after we have waited long enough
728 
729  switch(l2cap_state) {
730  case L2CAP_WAIT:
731  if(pBtd->connectToWii && !pBtd->l2capConnectionClaimed && !wiimoteConnected && !activeConnection) {
733  activeConnection = true;
734  motionPlusInside = pBtd->motionPlusInside;
735 #ifdef DEBUG_USB_HOST
736  Notify(PSTR("\r\nSend HID Control Connection Request"), 0x80);
737 #endif
738  hci_handle = pBtd->hci_handle; // Store the HCI Handle for the connection
739  l2cap_event_flag = 0; // Reset flags
740  identifier = 0;
742  l2cap_state = L2CAP_CONTROL_CONNECT_REQUEST;
744 #ifdef DEBUG_USB_HOST
745  Notify(PSTR("\r\nHID Control Incoming Connection Request"), 0x80);
746 #endif
747  pBtd->l2cap_connection_response(hci_handle, identifier, control_dcid, control_scid, PENDING);
748  delay(1);
749  pBtd->l2cap_connection_response(hci_handle, identifier, control_dcid, control_scid, SUCCESSFUL);
750  identifier++;
751  delay(1);
753  l2cap_state = L2CAP_CONTROL_SUCCESS;
754  }
755  break;
756 
758 #ifdef DEBUG_USB_HOST
759  if(stateCounter == 0) // Only print onnce
760  Notify(PSTR("\r\nChecking if a Motion Plus is connected"), 0x80);
761 #endif
762  stateCounter++;
763  if(stateCounter % 200 == 0)
764  checkMotionPresent(); // Check if there is a motion plus connected
766  stateCounter = 0;
767  l2cap_state = WII_INIT_MOTION_PLUS_STATE;
768  timer = (uint32_t)micros();
769 
770  if(unknownExtensionConnected) {
771 #ifdef DEBUG_USB_HOST
772  Notify(PSTR("\r\nA extension is also connected"), 0x80);
773 #endif
774  activateNunchuck = true; // For we will just set this to true as this the only extension supported so far
775  }
776 
777  } else if(stateCounter == 601) { // We will try three times to check for the motion plus
778 #ifdef DEBUG_USB_HOST
779  Notify(PSTR("\r\nNo Motion Plus was detected"), 0x80);
780 #endif
781  stateCounter = 0;
782  l2cap_state = WII_CHECK_EXTENSION_STATE;
783  }
784  break;
785 
786  case WII_CHECK_EXTENSION_STATE: // This is used to check if there is anything plugged in to the extension port
787 #ifdef DEBUG_USB_HOST
788  if(stateCounter == 0) // Only print onnce
789  Notify(PSTR("\r\nChecking if there is any extension connected"), 0x80);
790 #endif
791  stateCounter++; // We use this counter as there has to be a short delay between the commands
792  if(stateCounter == 1)
793  statusRequest(); // See if a new device has connected
794  if(stateCounter == 100) {
795  if(unknownExtensionConnected) // Check if there is a extension is connected to the port
796  initExtension1();
797  else
798  stateCounter = 499;
799  } else if(stateCounter == 200)
800  initExtension2();
801  else if(stateCounter == 300) {
802  readExtensionType();
803  unknownExtensionConnected = false;
804  } else if(stateCounter == 400) {
806 #ifdef DEBUG_USB_HOST
807  Notify(PSTR("\r\nReading Wii Balance Board calibration values"), 0x80);
808 #endif
809  readWiiBalanceBoardCalibration();
810  } else
811  stateCounter = 499;
812  } else if(stateCounter == 500) {
813  stateCounter = 0;
814  l2cap_state = TURN_ON_LED;
815  }
816  break;
817 
819  stateCounter++;
820  if(stateCounter == 1)
821  initMotionPlus();
822  else if(stateCounter == 100)
823  activateMotionPlus();
824  else if(stateCounter == 200)
825  readExtensionType(); // Check if it has been activated
826  else if(stateCounter == 300) {
827  stateCounter = 0;
828  unknownExtensionConnected = false; // The motion plus will send a status report when it's activated, we will set this to false so it doesn't reinitialize the Motion Plus
829  l2cap_state = TURN_ON_LED;
830  }
831  break;
832 
833  case TURN_ON_LED:
835  nunchuckConnected = true;
836  wiimoteConnected = true;
837  onInit();
838  l2cap_state = L2CAP_DONE;
839  break;
840 
841  case L2CAP_DONE:
842  if(unknownExtensionConnected) {
843 #ifdef DEBUG_USB_HOST
844  if(stateCounter == 0) // Only print once
845  Notify(PSTR("\r\nChecking extension port"), 0x80);
846 #endif
847  stateCounter++; // We will use this counter as there has to be a short delay between the commands
848  if(stateCounter == 50)
849  statusRequest();
850  else if(stateCounter == 100)
851  initExtension1();
852  else if(stateCounter == 150)
853  if((extensionConnected && motionPlusConnected) || (unknownExtensionConnected && !motionPlusConnected))
854  initExtension2();
855  else
856  stateCounter = 299; // There is no extension connected
857  else if(stateCounter == 200)
858  readExtensionType();
859  else if(stateCounter == 250) {
861 #ifdef DEBUG_USB_HOST
862  Notify(PSTR("\r\nNunchuck was reconnected"), 0x80);
863 #endif
864  activateNunchuck = true;
865  nunchuckConnected = true;
866  }
868  stateCounter = 449;
869  } else if(stateCounter == 300) {
870  if(motionPlusConnected) {
871 #ifdef DEBUG_USB_HOST
872  Notify(PSTR("\r\nReactivating the Motion Plus"), 0x80);
873 #endif
874  initMotionPlus();
875  } else
876  stateCounter = 449;
877  } else if(stateCounter == 350)
878  activateMotionPlus();
879  else if(stateCounter == 400)
880  readExtensionType(); // Check if it has been activated
881  else if(stateCounter == 450) {
882  onInit();
883  stateCounter = 0;
884  unknownExtensionConnected = false;
885  }
886  } else
887  stateCounter = 0;
888  break;
889  }
890 }
891 
892 /************************************************************/
893 /* HID Commands */
894 /************************************************************/
895 
896 void WII::HID_Command(uint8_t* data, uint8_t nbytes) {
897  if(motionPlusInside)
898  pBtd->L2CAP_Command(hci_handle, data, nbytes, interrupt_scid[0], interrupt_scid[1]); // It's the new Wiimote with the Motion Plus Inside or Wii U Pro controller
899  else
900  pBtd->L2CAP_Command(hci_handle, data, nbytes, control_scid[0], control_scid[1]);
901 }
902 
904  HIDBuffer[1] = 0x11;
905  HIDBuffer[2] = 0x00;
906  HID_Command(HIDBuffer, 3);
907 }
908 
910  HIDBuffer[1] = 0x11;
911  HIDBuffer[2] &= ~0x01; // Bit 0 control the rumble
912  HID_Command(HIDBuffer, 3);
913 }
914 
916  HIDBuffer[1] = 0x11;
917  HIDBuffer[2] |= 0x01; // Bit 0 control the rumble
918  HID_Command(HIDBuffer, 3);
919 }
920 
922  HIDBuffer[1] = 0x11;
923  HIDBuffer[2] ^= 0x01; // Bit 0 control the rumble
924  HID_Command(HIDBuffer, 3);
925 }
926 
927 void WII::setLedRaw(uint8_t value) {
928  HIDBuffer[1] = 0x11;
929  HIDBuffer[2] = value | (HIDBuffer[2] & 0x01); // Keep the rumble bit
930  HID_Command(HIDBuffer, 3);
931 }
932 
934  HIDBuffer[1] = 0x11;
935  HIDBuffer[2] &= ~(pgm_read_byte(&WII_LEDS[(uint8_t)a]));
936  HID_Command(HIDBuffer, 3);
937 }
938 
940  if(a == OFF)
941  setLedRaw(0);
942  else {
943  HIDBuffer[1] = 0x11;
944  HIDBuffer[2] |= pgm_read_byte(&WII_LEDS[(uint8_t)a]);
945  HID_Command(HIDBuffer, 3);
946  }
947 }
948 
950  HIDBuffer[1] = 0x11;
951  HIDBuffer[2] ^= pgm_read_byte(&WII_LEDS[(uint8_t)a]);
952  HID_Command(HIDBuffer, 3);
953 }
954 
956  HIDBuffer[1] = 0x11;
957  HIDBuffer[2] = (HIDBuffer[2] & 0x01); // Keep the rumble bit
958  if(wiimoteConnected)
959  HIDBuffer[2] |= 0x10; // If it's connected LED1 will light up
961  HIDBuffer[2] |= 0x20; // If it's connected LED2 will light up
963  HIDBuffer[2] |= 0x40; // If it's connected LED3 will light up
964 
965  HID_Command(HIDBuffer, 3);
966 }
967 
969  checkBatteryLevel = true; // This is needed so the library knows that the status response is a response to this function
970  statusRequest(); // This will update the battery level
971  return batteryLevel;
972 };
973 
974 void WII::setReportMode(bool continuous, uint8_t mode) {
975 #ifdef EXTRADEBUG
976  Notify(PSTR("\r\nReport mode was changed to: "), 0x80);
977  D_PrintHex<uint8_t > (mode, 0x80);
978 #endif
979  uint8_t cmd_buf[4];
980  cmd_buf[0] = 0xA2; // HID BT DATA_request (0xA0) | Report Type (Output 0x02)
981  cmd_buf[1] = 0x12;
982  if(continuous)
983  cmd_buf[2] = 0x04 | (HIDBuffer[2] & 0x01); // Keep the rumble bit
984  else
985  cmd_buf[2] = 0x00 | (HIDBuffer[2] & 0x01); // Keep the rumble bit
986  cmd_buf[3] = mode;
987  HID_Command(cmd_buf, 4);
988 }
989 
990 void WII::statusRequest() {
991  uint8_t cmd_buf[3];
992  cmd_buf[0] = 0xA2; // HID BT DATA_request (0xA0) | Report Type (Output 0x02)
993  cmd_buf[1] = 0x15;
994  cmd_buf[2] = (HIDBuffer[2] & 0x01); // Keep the rumble bit
995  HID_Command(cmd_buf, 3);
996 }
997 
998 /************************************************************/
999 /* Memmory Commands */
1000 /************************************************************/
1001 
1002 void WII::writeData(uint32_t offset, uint8_t size, uint8_t* data) {
1003  uint8_t cmd_buf[23];
1004  cmd_buf[0] = 0xA2; // HID BT DATA_request (0xA0) | Report Type (Output 0x02)
1005  cmd_buf[1] = 0x16; // Write data
1006  cmd_buf[2] = 0x04 | (HIDBuffer[2] & 0x01); // Write to memory, clear bit 2 to write to EEPROM
1007  cmd_buf[3] = (uint8_t)((offset & 0xFF0000) >> 16);
1008  cmd_buf[4] = (uint8_t)((offset & 0xFF00) >> 8);
1009  cmd_buf[5] = (uint8_t)(offset & 0xFF);
1010  cmd_buf[6] = size;
1011  uint8_t i = 0;
1012  for(; i < size; i++)
1013  cmd_buf[7 + i] = data[i];
1014  for(; i < 16; i++) // Set the rest to zero
1015  cmd_buf[7 + i] = 0x00;
1016  HID_Command(cmd_buf, 23);
1017 }
1018 
1019 void WII::initExtension1() {
1020  uint8_t buf[1];
1021  buf[0] = 0x55;
1022  writeData(0xA400F0, 1, buf);
1023 }
1024 
1025 void WII::initExtension2() {
1026  uint8_t buf[1];
1027  buf[0] = 0x00;
1028  writeData(0xA400FB, 1, buf);
1029 }
1030 
1031 void WII::initMotionPlus() {
1032  uint8_t buf[1];
1033  buf[0] = 0x55;
1034  writeData(0xA600F0, 1, buf);
1035 }
1036 
1037 void WII::activateMotionPlus() {
1038  uint8_t buf[1];
1039  if(pBtd->wiiUProController) {
1040 #ifdef DEBUG_USB_HOST
1041  Notify(PSTR("\r\nActivating Wii U Pro Controller"), 0x80);
1042 #endif
1043  buf[0] = 0x00; // It seems like you can send anything but 0x04, 0x05, and 0x07
1044  } else if(activateNunchuck) {
1045 #ifdef DEBUG_USB_HOST
1046  Notify(PSTR("\r\nActivating Motion Plus in pass-through mode"), 0x80);
1047 #endif
1048  buf[0] = 0x05; // Activate nunchuck pass-through mode
1049  }//else if(classicControllerConnected && extensionConnected)
1050  //buf[0] = 0x07;
1051  else {
1052 #ifdef DEBUG_USB_HOST
1053  Notify(PSTR("\r\nActivating Motion Plus in normal mode"), 0x80);
1054 #endif
1055  buf[0] = 0x04; // Don't use any extension
1056  }
1057  writeData(0xA600FE, 1, buf);
1058 }
1059 
1060 void WII::readData(uint32_t offset, uint16_t size, bool EEPROM) {
1061  uint8_t cmd_buf[8];
1062  cmd_buf[0] = 0xA2; // HID BT DATA_request (0xA0) | Report Type (Output 0x02)
1063  cmd_buf[1] = 0x17; // Read data
1064  if(EEPROM)
1065  cmd_buf[2] = 0x00 | (HIDBuffer[2] & 0x01); // Read from EEPROM
1066  else
1067  cmd_buf[2] = 0x04 | (HIDBuffer[2] & 0x01); // Read from memory
1068  cmd_buf[3] = (uint8_t)((offset & 0xFF0000) >> 16);
1069  cmd_buf[4] = (uint8_t)((offset & 0xFF00) >> 8);
1070  cmd_buf[5] = (uint8_t)(offset & 0xFF);
1071  cmd_buf[6] = (uint8_t)((size & 0xFF00) >> 8);
1072  cmd_buf[7] = (uint8_t)(size & 0xFF);
1073 
1074  HID_Command(cmd_buf, 8);
1075 }
1076 
1077 void WII::readExtensionType() {
1078  readData(0xA400FA, 6, false);
1079 }
1080 
1081 void WII::readCalData() {
1082  readData(0x0016, 8, true);
1083 }
1084 
1085 void WII::checkMotionPresent() {
1086  readData(0xA600FA, 6, false);
1087 }
1088 
1089 void WII::readWiiBalanceBoardCalibration() {
1090  readData(0xA40024, 24, false);
1091 }
1092 
1093 /************************************************************/
1094 /* WII Commands */
1095 /************************************************************/
1096 
1097 bool WII::getButtonPress(ButtonEnum b) { // Return true when a button is pressed
1099  return (ButtonState & pgm_read_dword(&WII_PROCONTROLLER_BUTTONS[(uint8_t)b]));
1100  else
1101  return (ButtonState & pgm_read_dword(&WII_BUTTONS[(uint8_t)b]));
1102 }
1103 
1104 bool WII::getButtonClick(ButtonEnum b) { // Only return true when a button is clicked
1105  uint32_t button;
1107  button = pgm_read_dword(&WII_PROCONTROLLER_BUTTONS[(uint8_t)b]);
1108  else
1109  button = pgm_read_dword(&WII_BUTTONS[(uint8_t)b]);
1110  bool click = (ButtonClickState & button);
1111  ButtonClickState &= ~button; // clear "click" event
1112  return click;
1113 }
1114 
1116  if(!nunchuckConnected)
1117  return 127; // Return center position
1118  else {
1119  uint8_t output = hatValues[(uint8_t)a];
1120  if(output == 0xFF || output == 0x00) // The joystick will only read 255 or 0 when the cable is unplugged or initializing, so we will just return the center position
1121  return 127;
1122  else
1123  return output;
1124  }
1125 }
1126 
1129  return 2000;
1130  else {
1131  uint16_t output = hatValues[(uint8_t)a];
1132  if(output == 0x00) // The joystick will only read 0 when it is first initializing, so we will just return the center position
1133  return 2000;
1134  else
1135  return output;
1136  }
1137 }
1138 
1139 void WII::onInit() {
1140  if(pFuncOnInit)
1141  pFuncOnInit(); // Call the user function
1142  else
1143  setLedStatus();
1144 }
1145 
1146 /************************************************************/
1147 /* Wii Balance Board Commands */
1148 /************************************************************/
1149 
1151  // Use interpolating between two points - based on: https://github.com/skorokithakis/gr8w8upd8m8/blob/master/gr8w8upd8m8.py
1152  // wiiBalanceBoardCal[pos][0] is calibration values for 0 kg
1153  // wiiBalanceBoardCal[pos][1] is calibration values for 17 kg
1154  // wiiBalanceBoardCal[pos][2] is calibration values for 34 kg
1155  if(wiiBalanceBoardRaw[pos] < wiiBalanceBoardCal[0][pos])
1156  return 0.0f; // Below 0 kg
1157  else if(wiiBalanceBoardRaw[pos] < wiiBalanceBoardCal[1][pos]) // Between 0 and 17 kg
1158  return 17.0f * (float)(wiiBalanceBoardRaw[pos] - wiiBalanceBoardCal[0][pos]) / (float)(wiiBalanceBoardCal[1][pos] - wiiBalanceBoardCal[0][pos]);
1159  else // More than 17 kg
1160  return 17.0f + 17.0f * (float)(wiiBalanceBoardRaw[pos] - wiiBalanceBoardCal[1][pos]) / (float)(wiiBalanceBoardCal[2][pos] - wiiBalanceBoardCal[1][pos]);
1161 };
1162 
1165 };
1166 
1167 /************************************************************/
1168 /* The following functions are for the IR camera */
1169 /************************************************************/
1170 
1171 #ifdef WIICAMERA
1172 
1173 void WII::IRinitialize() { // Turns on and initialises the IR camera
1174 
1175  enableIRCamera1();
1176 #ifdef DEBUG_USB_HOST
1177  Notify(PSTR("\r\nEnable IR Camera1 Complete"), 0x80);
1178 #endif
1179  delay(80);
1180 
1181  enableIRCamera2();
1182 #ifdef DEBUG_USB_HOST
1183  Notify(PSTR("\r\nEnable IR Camera2 Complete"), 0x80);
1184 #endif
1185  delay(80);
1186 
1187  write0x08Value();
1188 #ifdef DEBUG_USB_HOST
1189  Notify(PSTR("\r\nWrote hex number 0x08"), 0x80);
1190 #endif
1191  delay(80);
1192 
1193  writeSensitivityBlock1();
1194 #ifdef DEBUG_USB_HOST
1195  Notify(PSTR("\r\nWrote Sensitivity Block 1"), 0x80);
1196 #endif
1197  delay(80);
1198 
1199  writeSensitivityBlock2();
1200 #ifdef DEBUG_USB_HOST
1201  Notify(PSTR("\r\nWrote Sensitivity Block 2"), 0x80);
1202 #endif
1203  delay(80);
1204 
1205  uint8_t mode_num = 0x03;
1206  setWiiModeNumber(mode_num); // Change input for whatever mode you want i.e. 0x01, 0x03, or 0x05
1207 #ifdef DEBUG_USB_HOST
1208  Notify(PSTR("\r\nSet Wii Mode Number To 0x"), 0x80);
1209  D_PrintHex<uint8_t > (mode_num, 0x80);
1210 #endif
1211  delay(80);
1212 
1213  write0x08Value();
1214 #ifdef DEBUG_USB_HOST
1215  Notify(PSTR("\r\nWrote Hex Number 0x08"), 0x80);
1216 #endif
1217  delay(80);
1218 
1219  setReportMode(false, 0x33);
1220  //setReportMode(false, 0x3f); // For full reporting mode, doesn't work yet
1221 #ifdef DEBUG_USB_HOST
1222  Notify(PSTR("\r\nSet Report Mode to 0x33"), 0x80);
1223 #endif
1224  delay(80);
1225 
1226  statusRequest(); // Used to update wiiState - call isIRCameraEnabled() afterwards to check if it actually worked
1227 #ifdef DEBUG_USB_HOST
1228  Notify(PSTR("\r\nIR Initialized"), 0x80);
1229 #endif
1230 }
1231 
1232 void WII::enableIRCamera1() {
1233  uint8_t cmd_buf[3];
1234  cmd_buf[0] = 0xA2; // HID BT DATA_request (0xA0) | Report Type (Output 0x02)
1235  cmd_buf[1] = 0x13; // Output report 13
1236  cmd_buf[2] = 0x04 | (HIDBuffer[2] & 0x01); // Keep the rumble bit and sets bit 2
1237  HID_Command(cmd_buf, 3);
1238 }
1239 
1240 void WII::enableIRCamera2() {
1241  uint8_t cmd_buf[3];
1242  cmd_buf[0] = 0xA2; // HID BT DATA_request (0xA0) | Report Type (Output 0x02)
1243  cmd_buf[1] = 0x1A; // Output report 1A
1244  cmd_buf[2] = 0x04 | (HIDBuffer[2] & 0x01); // Keep the rumble bit and sets bit 2
1245  HID_Command(cmd_buf, 3);
1246 }
1247 
1248 void WII::writeSensitivityBlock1() {
1249  uint8_t buf[9];
1250  buf[0] = 0x00;
1251  buf[1] = 0x00;
1252  buf[2] = 0x00;
1253  buf[3] = 0x00;
1254  buf[4] = 0x00;
1255  buf[5] = 0x00;
1256  buf[6] = 0x90;
1257  buf[7] = 0x00;
1258  buf[8] = 0x41;
1259 
1260  writeData(0xB00000, 9, buf);
1261 }
1262 
1263 void WII::writeSensitivityBlock2() {
1264  uint8_t buf[2];
1265  buf[0] = 0x40;
1266  buf[1] = 0x00;
1267 
1268  writeData(0xB0001A, 2, buf);
1269 }
1270 
1271 void WII::write0x08Value() {
1272  uint8_t cmd = 0x08;
1273  writeData(0xb00030, 1, &cmd);
1274 }
1275 
1276 void WII::setWiiModeNumber(uint8_t mode_number) { // mode_number in hex i.e. 0x03 for extended mode
1277  writeData(0xb00033, 1, &mode_number);
1278 }
1279 #endif
bool wiimoteConnected
Definition: Wii.h:191
-
#define L2CAP_FLAG_DISCONNECT_CONTROL_RESPONSE
Definition: BTD.h:140
-
bool incomingWii
Definition: BTD.h:474
+
#define L2CAP_FLAG_DISCONNECT_CONTROL_RESPONSE
Definition: BTD.h:149
+
bool incomingWii
Definition: BTD.h:504
void onInit()
Definition: Wii.cpp:1139
- +
int16_t gyroPitchRaw
Definition: Wii.h:265
#define pgm_read_dword(addr)
#define wii_clear_flag(flag)
Definition: Wii.h:33
-
#define L2CAP_FLAG_CONFIG_INTERRUPT_SUCCESS
Definition: BTD.h:144
-
#define L2CAP_INTERRUPT_CONFIG_REQUEST
Definition: BTD.h:116
-
#define L2CAP_INTERRUPT_SETUP
Definition: BTD.h:114
+
#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
uint16_t rollGyroScale
Definition: Wii.h:257
-
void l2cap_connection_response(uint16_t handle, uint8_t rxid, uint8_t *dcid, uint8_t *scid, uint8_t result)
Definition: BTD.cpp:1260
-
#define SUCCESSFUL
Definition: BTD.h:178
-
void l2cap_connection_request(uint16_t handle, uint8_t rxid, uint8_t *scid, uint16_t psm)
Definition: BTD.cpp:1247
-
#define L2CAP_FLAG_CONNECTION_INTERRUPT_REQUEST
Definition: BTD.h:143
+
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 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
void setLedToggle(LEDEnum a)
Definition: Wii.cpp:949
void setLedRaw(uint8_t value)
Definition: Wii.cpp:927
uint8_t getAnalogHat(HatEnum a)
Definition: Wii.cpp:1115
uint16_t yawGyroScale
Definition: Wii.h:258
Definition: Wii.h:40
-
Definition: BTD.h:201
+
Definition: BTD.h:221
#define WII_FLAG_NUNCHUCK_CONNECTED
Definition: Wii.h:28
-
void l2cap_disconnection_request(uint16_t handle, uint8_t rxid, uint8_t *dcid, uint8_t *scid)
Definition: BTD.cpp:1313
+
void l2cap_disconnection_request(uint16_t handle, uint8_t rxid, uint8_t *dcid, uint8_t *scid)
Definition: BTD.cpp:1541
void ACLData(uint8_t *ACLData)
Definition: Wii.cpp:133
-
bool pairWithWii
Definition: BTD.h:476
-
uint8_t identifier
Definition: BTD.h:621
+
bool pairWithWii
Definition: BTD.h:506
+
uint8_t identifier
Definition: BTD.h:655
float pitchGyroSpeed
Definition: Wii.h:249
void setRumbleOn()
Definition: Wii.cpp:915
void Reset()
Definition: Wii.cpp:101
-
AnalogHatEnum
-
#define TURN_ON_LED
Definition: BTD.h:130
+
AnalogHatEnum
+
#define TURN_ON_LED
Definition: BTD.h:139
int16_t accZnunchuck
Definition: Wii.h:236
Definition: Wii.h:48
uint8_t getBatteryLevel()
Definition: Wii.cpp:968
void disconnect()
Definition: Wii.cpp:116
-
bool motionPlusInside
Definition: BTD.h:478
-
#define L2CAP_DONE
Definition: BTD.h:105
+
bool motionPlusInside
Definition: BTD.h:508
+
#define L2CAP_DONE
Definition: BTD.h:114
#define wii_set_flag(flag)
Definition: Wii.h:32
-
#define L2CAP_CONTROL_SUCCESS
Definition: BTD.h:110
-
#define L2CAP_WAIT
Definition: BTD.h:104
+
#define L2CAP_CONTROL_SUCCESS
Definition: BTD.h:119
+
#define L2CAP_WAIT
Definition: BTD.h:113
Definition: Wii.h:47
int16_t accXnunchuck
Definition: Wii.h:236
#define pgm_read_byte(addr)
-
#define L2CAP_CONTROL_CONFIG_REQUEST
Definition: BTD.h:109
+
#define L2CAP_CONTROL_CONFIG_REQUEST
Definition: BTD.h:118
int16_t gyroRollRaw
Definition: Wii.h:264
LEDEnum
-
void l2cap_disconnection_response(uint16_t handle, uint8_t rxid, uint8_t *dcid, uint8_t *scid)
Definition: BTD.cpp:1326
+
void l2cap_disconnection_response(uint16_t handle, uint8_t rxid, uint8_t *dcid, uint8_t *scid)
Definition: BTD.cpp:1554
void IRinitialize()
Definition: Wii.cpp:1173
Definition: Wii.h:38
#define Notify(...)
Definition: message.h:51
void setRumbleToggle()
Definition: Wii.cpp:921
int16_t gyroPitchZero
Definition: Wii.h:272
uint16_t pitchGyroScale
Definition: Wii.h:256
-
#define L2CAP_CONTROL_CONNECT_REQUEST
Definition: BTD.h:108
-
#define HID_CTRL_PSM
Definition: BTD.h:183
+
#define L2CAP_CONTROL_CONNECT_REQUEST
Definition: BTD.h:117
+
#define HID_CTRL_PSM
Definition: BTD.h:192
WII(BTD *p, bool pair=false)
Definition: Wii.cpp:85
-
#define WII_CHECK_EXTENSION_STATE
Definition: BTD.h:133
- +
#define WII_CHECK_EXTENSION_STATE
Definition: BTD.h:142
+
float rollGyroSpeed
Definition: Wii.h:250
-
bool connectToWii
Definition: BTD.h:470
-
bool wiiUProController
Definition: BTD.h:480
-
uint16_t hci_handle
Definition: BTD.h:454
-
void hci_disconnect(uint16_t handle)
Definition: BTD.cpp:1171
- +
bool connectToWii
Definition: BTD.h:500
+
bool wiiUProController
Definition: BTD.h:510
+
uint16_t hci_handle
Definition: BTD.h:484
+
void hci_disconnect(uint16_t handle)
Definition: BTD.cpp:1399
+
void setLedStatus()
Definition: Wii.cpp:955
-
#define L2CAP_FLAG_DISCONNECT_INTERRUPT_RESPONSE
Definition: BTD.h:146
+
#define L2CAP_FLAG_DISCONNECT_INTERRUPT_RESPONSE
Definition: BTD.h:155
BalanceBoardEnum
Definition: Wii.h:44
#define WII_FLAG_MOTION_PLUS_CONNECTED
Definition: Wii.h:27
const uint8_t WII_LEDS[]
Definition: Wii.cpp:25
@@ -161,29 +161,29 @@ var searchBox = new SearchBox("searchBox", "search",false,'Search');
bool getButtonClick(ButtonEnum b)
Definition: Wii.cpp:1104
int16_t accYwiimote
Definition: Wii.h:230
bool wiiUProControllerConnected
Definition: Wii.h:202
-
void(* pFuncOnInit)(void)
Definition: BTD.h:609
+
void(* pFuncOnInit)(void)
Definition: BTD.h:643
#define WII_FLAG_CALIBRATE_BALANCE_BOARD
Definition: Wii.h:29
-
#define l2cap_check_flag(flag)
Definition: BTD.h:161
+
#define l2cap_check_flag(flag)
Definition: BTD.h:170
void setRumbleOff()
Definition: Wii.cpp:909
bool wiiBalanceBoardConnected
Definition: Wii.h:204
-
#define L2CAP_CMD_CONFIG_REQUEST
Definition: BTD.h:169
-
#define L2CAP_FLAG_CONTROL_CONNECTED
Definition: BTD.h:139
+
#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:171
+
#define L2CAP_CMD_DISCONNECT_REQUEST
Definition: BTD.h:180
float gyroRoll
Definition: Wii.h:243
void setAllOff()
Definition: Wii.cpp:903
-
#define L2CAP_CONTROL_DISCONNECT
Definition: BTD.h:111
+
#define L2CAP_CONTROL_DISCONNECT
Definition: BTD.h:120
const uint32_t WII_BUTTONS[]
Definition: Wii.cpp:40
-
#define L2CAP_FLAG_CONNECTION_CONTROL_REQUEST
Definition: BTD.h:137
+
#define L2CAP_FLAG_CONNECTION_CONTROL_REQUEST
Definition: BTD.h:146
void setLedOff()
Definition: Wii.h:152
float getWiimoteRoll()
Definition: Wii.h:216
-
#define WII_CHECK_MOTION_PLUS_STATE
Definition: BTD.h:132
-
BTD * pBtd
Definition: BTD.h:612
-
#define HID_INTR_PSM
Definition: BTD.h:184
+
#define WII_CHECK_MOTION_PLUS_STATE
Definition: BTD.h:141
+
BTD * pBtd
Definition: BTD.h:646
+
#define HID_INTR_PSM
Definition: BTD.h:193
bool nunchuckConnected
Definition: Wii.h:198
-
bool l2capConnectionClaimed
Definition: BTD.h:440
+
bool l2capConnectionClaimed
Definition: BTD.h:470
float gyroPitch
Definition: Wii.h:241
Definition: Wii.h:45
int16_t gyroYawRaw
Definition: Wii.h:263
@@ -191,42 +191,42 @@ var searchBox = new SearchBox("searchBox", "search",false,'Search');
bool isIRCameraEnabled()
Definition: Wii.h:408
const uint32_t WII_PROCONTROLLER_BUTTONS[]
Definition: Wii.cpp:59
float yawGyroSpeed
Definition: Wii.h:251
-
#define L2CAP_CMD_DISCONNECT_RESPONSE
Definition: BTD.h:172
-
#define L2CAP_CMD_CONNECTION_RESPONSE
Definition: BTD.h:168
-
#define L2CAP_CMD_CONFIG_RESPONSE
Definition: BTD.h:170
+
#define L2CAP_CMD_DISCONNECT_RESPONSE
Definition: BTD.h:181
+
#define L2CAP_CMD_CONNECTION_RESPONSE
Definition: BTD.h:177
+
#define L2CAP_CMD_CONFIG_RESPONSE
Definition: BTD.h:179
void pair(void)
Definition: Wii.h:89
-
uint16_t hci_handle
Definition: BTD.h:615
+
uint16_t hci_handle
Definition: BTD.h:649
void setLedOn(LEDEnum a)
Definition: Wii.cpp:939
HatEnum
Definition: Wii.h:36
int16_t accYnunchuck
Definition: Wii.h:236
int16_t gyroYawZero
Definition: Wii.h:270
-
uint32_t l2cap_event_flag
Definition: BTD.h:618
+
uint32_t l2cap_event_flag
Definition: BTD.h:652
#define wii_check_flag(flag)
Definition: Wii.h:31
Definition: Wii.h:46
-
#define WII_INIT_MOTION_PLUS_STATE
Definition: BTD.h:134
-
void L2CAP_Command(uint16_t handle, uint8_t *data, uint8_t nbytes, uint8_t channelLow=0x01, uint8_t channelHigh=0x00)
Definition: BTD.cpp:1219
-
void l2cap_config_response(uint16_t handle, uint8_t rxid, uint8_t *scid)
Definition: BTD.cpp:1294
-
#define PENDING
Definition: BTD.h:177
-
#define L2CAP_FLAG_INTERRUPT_CONNECTED
Definition: BTD.h:145
-
#define l2cap_set_flag(flag)
Definition: BTD.h:162
-
void l2cap_config_request(uint16_t handle, uint8_t rxid, uint8_t *dcid)
Definition: BTD.cpp:1277
- +
#define WII_INIT_MOTION_PLUS_STATE
Definition: BTD.h:143
+
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
+
bool getButtonPress(ButtonEnum b)
Definition: Wii.cpp:1097
-
#define L2CAP_FLAG_CONFIG_CONTROL_SUCCESS
Definition: BTD.h:138
- -
#define L2CAP_CMD_CONNECTION_REQUEST
Definition: BTD.h:167
+
#define L2CAP_FLAG_CONFIG_CONTROL_SUCCESS
Definition: BTD.h:147
+ +
#define L2CAP_CMD_CONNECTION_REQUEST
Definition: BTD.h:176
float getWiimotePitch()
Definition: Wii.h:212
bool motionPlusConnected
Definition: Wii.h:200
int16_t gyroRollZero
Definition: Wii.h:271
float getTotalWeight()
Definition: Wii.cpp:1163
-
bool checkHciHandle(uint8_t *buf, uint16_t handle)
Definition: BTD.h:604
-
#define L2CAP_INTERRUPT_CONNECT_REQUEST
Definition: BTD.h:115
+
bool checkHciHandle(uint8_t *buf, uint16_t handle)
Definition: BTD.h:638
+
#define L2CAP_INTERRUPT_CONNECT_REQUEST
Definition: BTD.h:124
void Run()
Definition: Wii.cpp:725
-
#define L2CAP_INTERRUPT_DISCONNECT
Definition: BTD.h:117
+
#define L2CAP_INTERRUPT_DISCONNECT
Definition: BTD.h:126
int16_t accXwiimote
Definition: Wii.h:230
float getWeight(BalanceBoardEnum pos)
Definition: Wii.cpp:1150
int16_t accZwiimote
Definition: Wii.h:230
-
#define L2CAP_CMD_COMMAND_REJECT
Definition: BTD.h:166
+
#define L2CAP_CMD_COMMAND_REJECT
Definition: BTD.h:175

Enable visibility to other Bluetooth devices.

-

Definition at line 962 of file BTD.cpp.

+

Definition at line 1122 of file BTD.cpp.

@@ -876,7 +944,7 @@ Static Protected Attributes

Disable visibility to other Bluetooth devices.

-

Definition at line 975 of file BTD.cpp.

+

Definition at line 1135 of file BTD.cpp.

@@ -894,7 +962,7 @@ Static Protected Attributes

Read the remote devices name.

-

Definition at line 1018 of file BTD.cpp.

+

Definition at line 1188 of file BTD.cpp.

@@ -912,7 +980,7 @@ Static Protected Attributes

Accept the connection with the Bluetooth device.

-

Definition at line 1002 of file BTD.cpp.

+

Definition at line 1172 of file BTD.cpp.

@@ -936,7 +1004,7 @@ Static Protected Attributes -

Definition at line 1171 of file BTD.cpp.

+

Definition at line 1399 of file BTD.cpp.

@@ -954,7 +1022,7 @@ Static Protected Attributes

Respond with the pin for the connection. The pin is automatically set for the Wii library, but can be customized for the SPP library.

-

Definition at line 1097 of file BTD.cpp.

+

Definition at line 1294 of file BTD.cpp.

@@ -972,7 +1040,7 @@ Static Protected Attributes

Respons when no pin was set.

-

Definition at line 1133 of file BTD.cpp.

+

Definition at line 1330 of file BTD.cpp.

@@ -990,7 +1058,25 @@ Static Protected Attributes

Command is used to reply to a Link Key Request event from the BR/EDR Controller if the Host does not have a stored Link Key for the connection.

-

Definition at line 1147 of file BTD.cpp.

+

Definition at line 1344 of file BTD.cpp.

+ +
+ + +
+
+ + + + + + + +
void BTD::hci_user_confirmation_request_reply ()
+
+

Used to during simple paring to confirm that the we want to connect

+ +

Definition at line 1375 of file BTD.cpp.

@@ -1008,7 +1094,7 @@ Static Protected Attributes

Used to try to authenticate with the remote device.

-

Definition at line 1161 of file BTD.cpp.

+

Definition at line 1389 of file BTD.cpp.

@@ -1026,7 +1112,7 @@ Static Protected Attributes

Start a HCI inquiry.

-

Definition at line 1049 of file BTD.cpp.

+

Definition at line 1246 of file BTD.cpp.

@@ -1044,7 +1130,7 @@ Static Protected Attributes

Cancel a HCI inquiry.

-

Definition at line 1063 of file BTD.cpp.

+

Definition at line 1260 of file BTD.cpp.

@@ -1062,7 +1148,25 @@ Static Protected Attributes

Connect to last device communicated with.

-

Definition at line 1071 of file BTD.cpp.

+

Definition at line 1268 of file BTD.cpp.

+ +
+ + +
+
+ + + + + + + +
void BTD::hci_io_capability_request_reply ()
+
+

Used during simple paring to reply to a IO capability request

+ +

Definition at line 1358 of file BTD.cpp.

@@ -1086,7 +1190,7 @@ Static Protected Attributes -

Definition at line 1075 of file BTD.cpp.

+

Definition at line 1272 of file BTD.cpp.

@@ -1104,7 +1208,7 @@ Static Protected Attributes

Used to a set the class of the device.

-

Definition at line 1183 of file BTD.cpp.

+

Definition at line 1411 of file BTD.cpp.

@@ -1159,7 +1263,7 @@ Static Protected Attributes -

Definition at line 1219 of file BTD.cpp.

+

Definition at line 1447 of file BTD.cpp.

@@ -1208,7 +1312,7 @@ Static Protected Attributes -

Definition at line 1247 of file BTD.cpp.

+

Definition at line 1475 of file BTD.cpp.

@@ -1264,7 +1368,7 @@ Static Protected Attributes -

Definition at line 1260 of file BTD.cpp.

+

Definition at line 1488 of file BTD.cpp.

@@ -1306,7 +1410,7 @@ Static Protected Attributes -

Definition at line 1277 of file BTD.cpp.

+

Definition at line 1505 of file BTD.cpp.

@@ -1348,7 +1452,7 @@ Static Protected Attributes -

Definition at line 1294 of file BTD.cpp.

+

Definition at line 1522 of file BTD.cpp.

@@ -1397,7 +1501,7 @@ Static Protected Attributes -

Definition at line 1313 of file BTD.cpp.

+

Definition at line 1541 of file BTD.cpp.

@@ -1446,7 +1550,7 @@ Static Protected Attributes -

Definition at line 1326 of file BTD.cpp.

+

Definition at line 1554 of file BTD.cpp.

@@ -1494,7 +1598,7 @@ Static Protected Attributes -

Definition at line 1339 of file BTD.cpp.

+

Definition at line 1567 of file BTD.cpp.

@@ -1520,7 +1624,7 @@ Static Protected Attributes

Call this function to pair with a Wiimote

-

Definition at line 467 of file BTD.h.

+

Definition at line 497 of file BTD.h.

@@ -1546,7 +1650,7 @@ Static Protected Attributes

Call this function to pair with a HID device

-

Definition at line 483 of file BTD.h.

+

Definition at line 513 of file BTD.h.

@@ -1572,7 +1676,7 @@ Static Protected Attributes

Read the poll interval taken from the endpoint descriptors.

Returns
The poll interval in ms.
-

Definition at line 499 of file BTD.h.

+

Definition at line 529 of file BTD.h.

@@ -1604,7 +1708,7 @@ Static Protected Attributes -

Definition at line 357 of file BTD.cpp.

+

Definition at line 360 of file BTD.cpp.

@@ -1620,7 +1724,7 @@ Static Protected Attributes

Use this to see if it is waiting for a incoming connection.

-

Definition at line 438 of file BTD.h.

+

Definition at line 468 of file BTD.h.

@@ -1635,7 +1739,7 @@ Static Protected Attributes

This is used by the service to know when to store the device information.

-

Definition at line 440 of file BTD.h.

+

Definition at line 470 of file BTD.h.

@@ -1650,7 +1754,7 @@ Static Protected Attributes

This is used by the SPP library to claim the current SDP incoming request.

-

Definition at line 442 of file BTD.h.

+

Definition at line 472 of file BTD.h.

@@ -1665,7 +1769,7 @@ Static Protected Attributes

This is used by the SPP library to claim the current RFCOMM incoming request.

-

Definition at line 444 of file BTD.h.

+

Definition at line 474 of file BTD.h.

@@ -1680,7 +1784,7 @@ Static Protected Attributes

The name you wish to make the dongle show up as. It is set automatically by the SPP library.

-

Definition at line 447 of file BTD.h.

+

Definition at line 477 of file BTD.h.

@@ -1695,7 +1799,7 @@ Static Protected Attributes

The pin you wish to make the dongle use for authentication. It is set automatically by the SPP and BTHID library.

-

Definition at line 449 of file BTD.h.

+

Definition at line 479 of file BTD.h.

@@ -1710,7 +1814,7 @@ Static Protected Attributes

The bluetooth dongles Bluetooth address.

-

Definition at line 452 of file BTD.h.

+

Definition at line 482 of file BTD.h.

@@ -1725,7 +1829,7 @@ Static Protected Attributes

HCI handle for the last connection.

-

Definition at line 454 of file BTD.h.

+

Definition at line 484 of file BTD.h.

@@ -1740,7 +1844,7 @@ Static Protected Attributes

Last incoming devices Bluetooth address.

-

Definition at line 456 of file BTD.h.

+

Definition at line 486 of file BTD.h.

@@ -1755,7 +1859,7 @@ Static Protected Attributes

First 30 chars of last remote name.

-

Definition at line 458 of file BTD.h.

+

Definition at line 488 of file BTD.h.

@@ -1770,7 +1874,7 @@ Static Protected Attributes

The supported HCI Version read from the Bluetooth dongle. Used by the PS3BT library to check the HCI Version of the Bluetooth dongle, it should be at least 3 to work properly with the library.

-

Definition at line 464 of file BTD.h.

+

Definition at line 494 of file BTD.h.

@@ -1785,7 +1889,7 @@ Static Protected Attributes

Used to only send the ACL data to the Wiimote.

-

Definition at line 470 of file BTD.h.

+

Definition at line 500 of file BTD.h.

@@ -1800,7 +1904,7 @@ Static Protected Attributes

True if a Wiimote is connecting.

-

Definition at line 474 of file BTD.h.

+

Definition at line 504 of file BTD.h.

@@ -1815,7 +1919,7 @@ Static Protected Attributes

True when it should pair with a Wiimote.

-

Definition at line 476 of file BTD.h.

+

Definition at line 506 of file BTD.h.

@@ -1830,7 +1934,7 @@ Static Protected Attributes

True if it's the new Wiimote with the Motion Plus Inside or a Wii U Pro Controller.

-

Definition at line 478 of file BTD.h.

+

Definition at line 508 of file BTD.h.

@@ -1845,7 +1949,7 @@ Static Protected Attributes

True if it's a Wii U Pro Controller.

-

Definition at line 480 of file BTD.h.

+

Definition at line 510 of file BTD.h.

@@ -1860,7 +1964,7 @@ Static Protected Attributes

Used to only send the ACL data to the HID device.

-

Definition at line 487 of file BTD.h.

+

Definition at line 517 of file BTD.h.

@@ -1875,7 +1979,7 @@ Static Protected Attributes

True if a HID device is connecting.

-

Definition at line 491 of file BTD.h.

+

Definition at line 521 of file BTD.h.

@@ -1890,7 +1994,22 @@ Static Protected Attributes

True when it should pair with a device like a mouse or keyboard.

-

Definition at line 493 of file BTD.h.

+

Definition at line 523 of file BTD.h.

+ +
+ + +
+
+ + + + +
bool BTD::useSimplePairing
+
+

Used by the drivers to enable simple pairing

+ +

Definition at line 531 of file BTD.h.

@@ -1913,7 +2032,7 @@ Static Protected Attributes

Pointer to USB class instance.

-

Definition at line 501 of file BTD.h.

+

Definition at line 538 of file BTD.h.

@@ -1936,7 +2055,7 @@ Static Protected Attributes

Device address.

-

Definition at line 507 of file BTD.h.

+

Definition at line 540 of file BTD.h.

@@ -1959,7 +2078,7 @@ Static Protected Attributes

Endpoint info structure.

-

Definition at line 509 of file BTD.h.

+

Definition at line 542 of file BTD.h.

@@ -1982,7 +2101,7 @@ Static Protected Attributes

Configuration number.

-

Definition at line 512 of file BTD.h.

+

Definition at line 545 of file BTD.h.

@@ -2005,7 +2124,7 @@ Static Protected Attributes

Total number of endpoints in the configuration.

-

Definition at line 514 of file BTD.h.

+

Definition at line 547 of file BTD.h.

@@ -2028,7 +2147,7 @@ Static Protected Attributes

Next poll time based on poll interval taken from the USB descriptor.

-

Definition at line 516 of file BTD.h.

+

Definition at line 549 of file BTD.h.

@@ -2051,7 +2170,7 @@ Static Protected Attributes

Bluetooth dongle control endpoint.

-

Definition at line 519 of file BTD.h.

+

Definition at line 552 of file BTD.h.

@@ -2074,7 +2193,7 @@ Static Protected Attributes

HCI event endpoint index.

-

Definition at line 521 of file BTD.h.

+

Definition at line 554 of file BTD.h.

@@ -2097,7 +2216,7 @@ Static Protected Attributes

ACL In endpoint index.

-

Definition at line 523 of file BTD.h.

+

Definition at line 556 of file BTD.h.

@@ -2120,7 +2239,7 @@ Static Protected Attributes

ACL Out endpoint index.

-

Definition at line 525 of file BTD.h.

+

Definition at line 558 of file BTD.h.

diff --git a/class_b_t_h_i_d-members.html b/class_b_t_h_i_d-members.html index d2b57a60..bd5387f4 100644 --- a/class_b_t_h_i_d-members.html +++ b/class_b_t_h_i_d-members.html @@ -104,15 +104,17 @@ var searchBox = new SearchBox("searchBox", "search",false,'Search'); identifierBluetoothServiceprotected interrupt_scidBTHIDprotected l2cap_event_flagBluetoothServiceprotected - onInit()BTHIDinlineprotectedvirtual - OnInitBTHID()BTHIDinlineprotectedvirtual - pair(void)BTHIDinline - ParseBTHIDData(uint8_t len, uint8_t *buf)BTHIDinlineprotectedvirtual - pBtdBluetoothServiceprotected - pFuncOnInitBluetoothServiceprotected - Reset()BTHIDprotectedvirtual - ResetBTHID()BTHIDinlineprotectedvirtual - Run()BTHIDprotectedvirtual + l2cap_sdp_stateBTHIDprotected + onInit()BTHIDinlineprotectedvirtual + OnInitBTHID()BTHIDinlineprotectedvirtual + pair(void)BTHIDinline + 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 diff --git a/class_b_t_h_i_d.html b/class_b_t_h_i_d.html index df129a2a..5b2ab120 100644 --- a/class_b_t_h_i_d.html +++ b/class_b_t_h_i_d.html @@ -100,8 +100,9 @@ Inheritance diagram for BTHID:
Inheritance graph
- - + + +
[legend]
@@ -166,6 +167,10 @@ Protected Attributes   uint8_t interrupt_scid [2]   +uint8_t l2cap_sdp_state +  +uint8_t sdp_scid [2] +  - Protected Attributes inherited from BluetoothService void(* pFuncOnInit )(void)   @@ -263,7 +268,7 @@ BluetoothService implementation

Implements BluetoothService.

-

Definition at line 49 of file BTHID.cpp.

+

Definition at line 53 of file BTHID.cpp.

@@ -428,7 +433,7 @@ BluetoothService implementation -

Definition at line 393 of file BTHID.cpp.

+

Definition at line 614 of file BTHID.cpp.

@@ -489,7 +494,7 @@ BluetoothService implementation

Implements BluetoothService.

-

Definition at line 56 of file BTHID.cpp.

+

Definition at line 63 of file BTHID.cpp.

@@ -517,7 +522,7 @@ BluetoothService implementation

Implements BluetoothService.

-

Definition at line 344 of file BTHID.cpp.

+

Definition at line 544 of file BTHID.cpp.

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

Implements BluetoothService.

-

Definition at line 41 of file BTHID.cpp.

+

Definition at line 43 of file BTHID.cpp.

@@ -616,7 +621,7 @@ BluetoothService implementation -

Reimplemented in PS4BT.

+

Reimplemented in PS4BT, and XBOXONESBT.

Definition at line 125 of file BTHID.h.

@@ -644,7 +649,7 @@ BluetoothService implementation

Called when a device is connected

-

Reimplemented in PS4BT.

+

Reimplemented in PS4BT, and XBOXONESBT.

Definition at line 129 of file BTHID.h.

@@ -672,7 +677,7 @@ BluetoothService implementation

Used to reset any buffers in the class that inherits this

-

Reimplemented in PS4BT.

+

Reimplemented in PS4BT, and XBOXONESBT.

Definition at line 133 of file BTHID.h.

@@ -738,6 +743,50 @@ BluetoothService implementation

Definition at line 142 of file BTHID.h.

+
+ + +
+
+ + + + + +
+ + + + +
uint8_t BTHID::l2cap_sdp_state
+
+protected
+
+ +

Definition at line 144 of file BTHID.h.

+ +
+
+ +
+
+ + + + + +
+ + + + +
uint8_t BTHID::sdp_scid[2]
+
+protected
+
+ +

Definition at line 145 of file BTHID.h.

+

The documentation for this class was generated from the following files: