Add HCI debugging with verbosity control to the BluetoothHost demo.
[pub/USBasp.git] / Demos / Host / Incomplete / BluetoothHost / Lib / BluetoothHCICommands.c
1 /*
2 LUFA Library
3 Copyright (C) Dean Camera, 2010.
4
5 dean [at] fourwalledcubicle [dot] com
6 www.fourwalledcubicle.com
7 */
8
9 /*
10 Copyright 2010 Dean Camera (dean [at] fourwalledcubicle [dot] com)
11
12 Permission to use, copy, modify, distribute, and sell this
13 software and its documentation for any purpose is hereby granted
14 without fee, provided that the above copyright notice appear in
15 all copies and that both that the copyright notice and this
16 permission notice and warranty disclaimer appear in supporting
17 documentation, and that the name of the author not be used in
18 advertising or publicity pertaining to distribution of the
19 software without specific, written prior permission.
20
21 The author disclaim all warranties with regard to this
22 software, including all implied warranties of merchantability
23 and fitness. In no event shall the author be liable for any
24 special, indirect or consequential damages or any damages
25 whatsoever resulting from loss of use, data or profits, whether
26 in an action of contract, negligence or other tortious action,
27 arising out of or in connection with the use or performance of
28 this software.
29 */
30
31 #define INCLUDE_FROM_BLUETOOTHHCICOMMANDS_C
32 #include "BluetoothHCICommands.h"
33
34 /** Current processing state of the HCI portion of the Bluetooth stack. */
35 uint8_t Bluetooth_HCIProcessingState;
36
37 /** Next HCI state to enter once the last issued HCI command has completed. */
38 static uint8_t Bluetooth_HCINextState;
39
40 /** Temporary Bluetooth Device Address, for HCI responses which much include the detination address */
41 static uint8_t Bluetooth_TempDeviceAddress[6];
42
43
44 /** Bluetooth HCI processing task. This task should be called repeatedly the main Bluetooth
45 * stack task to manage the HCI processing state.
46 */
47 void Bluetooth_HCITask(void)
48 {
49 BT_HCICommand_Header_t HCICommandHeader;
50
51 switch (Bluetooth_HCIProcessingState)
52 {
53 case Bluetooth_ProcessEvents:
54 Pipe_SelectPipe(BLUETOOTH_EVENTS_PIPE);
55 Pipe_Unfreeze();
56
57 if (Pipe_IsReadWriteAllowed())
58 {
59 BT_HCIEvent_Header_t HCIEventHeader;
60
61 /* Read in the event header to fetch the event code and payload length */
62 Pipe_Read_Stream_LE(&HCIEventHeader, sizeof(HCIEventHeader));
63
64 /* Create a temporary buffer for the event parameters */
65 uint8_t EventParams[HCIEventHeader.ParameterLength];
66
67 /* Read in the event parameters into the temporary buffer */
68 Pipe_Read_Stream_LE(&EventParams, HCIEventHeader.ParameterLength);
69 Pipe_ClearIN();
70
71 BT_HCI_DEBUG(1, "Event Received (0x%02X)", HCIEventHeader.EventCode);
72
73 switch (HCIEventHeader.EventCode)
74 {
75 case EVENT_COMMAND_COMPLETE:
76 BT_HCI_DEBUG(1, "<< Command Complete", NULL);
77 Bluetooth_HCIProcessingState = Bluetooth_HCINextState;
78 break;
79 case EVENT_COMMAND_STATUS:
80 BT_HCI_DEBUG(1, "<< Command Status", NULL);
81 BT_HCI_DEBUG(2, "-- Status Code: 0x%02X", (((BT_HCIEvent_CommandStatus_t*)&EventParams)->Status));
82
83 /* If the execution of a command failed, reset the stack */
84 if (((BT_HCIEvent_CommandStatus_t*)&EventParams)->Status)
85 Bluetooth_HCIProcessingState = Bluetooth_Init;
86 break;
87 case EVENT_CONNECTION_REQUEST:
88 BT_HCI_DEBUG(1, "<< Connection Request", NULL);
89 BT_HCI_DEBUG(2, "-- Link Type: 0x%02X", (((BT_HCIEvent_ConnectionRequest_t*)&EventParams)->LinkType));
90
91 /* Need to store the remote device's BT address in a temporary buffer for later use */
92 memcpy(Bluetooth_TempDeviceAddress,
93 &((BT_HCIEvent_ConnectionRequest_t*)&EventParams)->RemoteAddress,
94 sizeof(Bluetooth_TempDeviceAddress));
95
96 bool IsACLConnection = (((BT_HCIEvent_ConnectionRequest_t*)&EventParams)->LinkType == 0x01);
97
98 /* Only accept the connection if it is a ACL (data) connection, a device is not already connected
99 and the user application has indicated that the connection should be allowed */
100 Bluetooth_HCIProcessingState = (Bluetooth_Connection.IsConnected || !(IsACLConnection) ||
101 !(Bluetooth_ConnectionRequest(Bluetooth_TempDeviceAddress))) ?
102 Bluetooth_Conn_RejectConnection : Bluetooth_Conn_AcceptConnection;
103
104 BT_HCI_DEBUG(2, "-- Connection %S", (Bluetooth_HCIProcessingState == Bluetooth_Conn_RejectConnection) ?
105 PSTR("REJECTED") : PSTR("ACCEPTED"));
106
107 break;
108 case EVENT_PIN_CODE_REQUEST:
109 BT_HCI_DEBUG(1, "<< Pin Code Request", NULL);
110
111 /* Need to store the remote device's BT address in a temporary buffer for later use */
112 memcpy(Bluetooth_TempDeviceAddress,
113 &((BT_HCIEvent_PinCodeReq_t*)&EventParams)->RemoteAddress,
114 sizeof(Bluetooth_TempDeviceAddress));
115
116 Bluetooth_HCIProcessingState = Bluetooth_Conn_SendPINCode;
117 break;
118 case EVENT_LINK_KEY_REQUEST:
119 BT_HCI_DEBUG(1, "<< Link Key Request", NULL);
120
121 /* Need to store the remote device's BT address in a temporary buffer for later use */
122 memcpy(Bluetooth_TempDeviceAddress,
123 &((BT_HCIEvent_LinkKeyReq_t*)&EventParams)->RemoteAddress,
124 sizeof(Bluetooth_TempDeviceAddress));
125
126 Bluetooth_HCIProcessingState = Bluetooth_Conn_SendLinkKeyNAK;
127 break;
128 case EVENT_CONNECTION_COMPLETE:
129 BT_HCI_DEBUG(1, "<< Connection Complete", NULL);
130 BT_HCI_DEBUG(2, "-- Handle: 0x%04X", ((BT_HCIEvent_ConnectionComplete_t*)&EventParams)->ConnectionHandle);
131
132 /* Need to store the remote device's BT address in a temporary buffer for later use */
133 memcpy(Bluetooth_Connection.RemoteAddress,
134 &((BT_HCIEvent_ConnectionComplete_t*)&EventParams)->RemoteAddress,
135 sizeof(Bluetooth_TempDeviceAddress));
136
137 /* Store the created connection handle and indicate that the connection has been established */
138 Bluetooth_Connection.ConnectionHandle = ((BT_HCIEvent_ConnectionComplete_t*)&EventParams)->ConnectionHandle;
139 Bluetooth_Connection.IsConnected = true;
140
141 Bluetooth_ConnectionComplete();
142 break;
143 case EVENT_DISCONNECTION_COMPLETE:
144 BT_HCI_DEBUG(1, "<< Disconnection Complete", NULL);
145
146 /* Device disconnected, indicate connection information no longer valid */
147 Bluetooth_Connection.IsConnected = false;
148
149 Bluetooth_DisconnectionComplete();
150
151 Bluetooth_HCIProcessingState = Bluetooth_Init;
152 break;
153 }
154 }
155
156 Pipe_Freeze();
157
158 break;
159 case Bluetooth_Init:
160 BT_HCI_DEBUG(1, "# Init", NULL);
161
162 /* Reset the connection information structure to destroy any previous connection state */
163 memset(&Bluetooth_Connection, 0x00, sizeof(Bluetooth_Connection));
164
165 Bluetooth_HCIProcessingState = Bluetooth_Init_Reset;
166 break;
167 case Bluetooth_Init_Reset:
168 BT_HCI_DEBUG(1, "# Reset", NULL);
169
170 HCICommandHeader = (BT_HCICommand_Header_t)
171 {
172 OpCode: {OGF: OGF_CTRLR_BASEBAND, OCF: OCF_CTRLR_BASEBAND_RESET},
173 ParameterLength: 0,
174 };
175
176 /* Send the command to reset the bluetooth dongle controller */
177 Bluetooth_SendHCICommand(&HCICommandHeader, NULL, 0);
178
179 Bluetooth_HCINextState = Bluetooth_Init_SetLocalName;
180 Bluetooth_HCIProcessingState = Bluetooth_ProcessEvents;
181 break;
182 case Bluetooth_Init_SetLocalName:
183 BT_HCI_DEBUG(1, "# Set Local Name", NULL);
184
185 HCICommandHeader = (BT_HCICommand_Header_t)
186 {
187 OpCode: {OGF: OGF_CTRLR_BASEBAND, OCF: OCF_CTRLR_BASEBAND_WRITE_LOCAL_NAME},
188 ParameterLength: 248,
189 };
190
191 /* Send the command to set the bluetooth dongle's name for other devices to see */
192 Bluetooth_SendHCICommand(&HCICommandHeader, Bluetooth_DeviceConfiguration.Name, strlen(Bluetooth_DeviceConfiguration.Name));
193
194 Bluetooth_HCINextState = Bluetooth_Init_SetDeviceClass;
195 Bluetooth_HCIProcessingState = Bluetooth_ProcessEvents;
196 break;
197 case Bluetooth_Init_SetDeviceClass:
198 BT_HCI_DEBUG(1, "# Set Device Class", NULL);
199
200 HCICommandHeader = (BT_HCICommand_Header_t)
201 {
202 OpCode: {OGF: OGF_CTRLR_BASEBAND, OCF: OCF_CTRLR_BASEBAND_WRITE_CLASS_OF_DEVICE},
203 ParameterLength: 3,
204 };
205
206 /* Send the command to set the class of the device for other devices to see */
207 Bluetooth_SendHCICommand(&HCICommandHeader, &Bluetooth_DeviceConfiguration.Class, 3);
208
209 Bluetooth_HCINextState = Bluetooth_Init_WriteScanEnable;
210 Bluetooth_HCIProcessingState = Bluetooth_ProcessEvents;
211 break;
212 case Bluetooth_Init_WriteScanEnable:
213 BT_HCI_DEBUG(1, "# Write Scan Enable", NULL);
214
215 HCICommandHeader = (BT_HCICommand_Header_t)
216 {
217 OpCode: {OGF: OGF_CTRLR_BASEBAND, OCF: OCF_CTRLR_BASEBAND_WRITE_SCAN_ENABLE},
218 ParameterLength: 1,
219 };
220
221 uint8_t Interval = BT_SCANMODE_InquiryAndPageScans;
222
223 /* Send the command to set the remote device scanning mode */
224 Bluetooth_SendHCICommand(&HCICommandHeader, &Interval, 1);
225
226 Bluetooth_HCINextState = Bluetooth_ProcessEvents;
227 Bluetooth_HCIProcessingState = Bluetooth_ProcessEvents;
228 break;
229 case Bluetooth_Conn_AcceptConnection:
230 BT_HCI_DEBUG(1, "# Accept Connection", NULL);
231
232 HCICommandHeader = (BT_HCICommand_Header_t)
233 {
234 OpCode: {OGF: OGF_LINK_CONTROL, OCF: OCF_LINK_CONTROL_ACCEPT_CONNECTION_REQUEST},
235 ParameterLength: sizeof(BT_HCICommand_AcceptConnectionReq_t),
236 };
237
238 /* Copy over the temporary BT device address saved from the Connection Request event, indicate slave
239 connection role */
240 BT_HCICommand_AcceptConnectionReq_t AcceptConnectionParams;
241 memcpy(AcceptConnectionParams.RemoteAddress, Bluetooth_TempDeviceAddress,
242 sizeof(AcceptConnectionParams.RemoteAddress));
243 AcceptConnectionParams.SlaveRole = true;
244
245 /* Send the command to accept the remote connection request */
246 Bluetooth_SendHCICommand(&HCICommandHeader, &AcceptConnectionParams, sizeof(BT_HCICommand_AcceptConnectionReq_t));
247
248 Bluetooth_HCIProcessingState = Bluetooth_ProcessEvents;
249 break;
250 case Bluetooth_Conn_RejectConnection:
251 BT_HCI_DEBUG(1, "# Reject Connection", NULL);
252
253 HCICommandHeader = (BT_HCICommand_Header_t)
254 {
255 OpCode: {OGF: OGF_LINK_CONTROL, OCF: OCF_LINK_CONTROL_REJECT_CONNECTION_REQUEST},
256 ParameterLength: sizeof(BT_HCICommand_RejectConnectionReq_t),
257 };
258
259 /* Copy over the temporary BT device address saved from the Connection Request event, indicate failure
260 to accept the connection due to limited device resources or incorrect device address */
261 BT_HCICommand_RejectConnectionReq_t RejectConnectionParams;
262 memcpy(RejectConnectionParams.RemoteAddress, Bluetooth_TempDeviceAddress, sizeof(RejectConnectionParams.RemoteAddress));
263 RejectConnectionParams.Reason = Bluetooth_Connection.IsConnected ? ERROR_LIMITED_RESOURCES : ERROR_UNACCEPTABLE_BDADDR;
264
265 /* Send the command to reject the remote connection request */
266 Bluetooth_SendHCICommand(&HCICommandHeader, &RejectConnectionParams, sizeof(BT_HCICommand_RejectConnectionReq_t));
267
268 Bluetooth_HCIProcessingState = Bluetooth_ProcessEvents;
269 break;
270 case Bluetooth_Conn_SendPINCode:
271 BT_HCI_DEBUG(1, "# Send Pin Code", NULL);
272
273 HCICommandHeader = (BT_HCICommand_Header_t)
274 {
275 OpCode: {OGF: OGF_LINK_CONTROL, OCF: OCF_LINK_CONTROL_PIN_CODE_REQUEST_REPLY},
276 ParameterLength: sizeof(BT_HCICommand_PinCodeResp_t),
277 };
278
279 /* Copy over the temporary BT device address saved from the PIN Code Request event, copy over the
280 local PIN authentication code to the response */
281 BT_HCICommand_PinCodeResp_t PINCodeRequestParams;
282 memcpy(PINCodeRequestParams.RemoteAddress, Bluetooth_TempDeviceAddress, sizeof(PINCodeRequestParams.RemoteAddress));
283 PINCodeRequestParams.PINCodeLength = strlen(Bluetooth_DeviceConfiguration.PINCode);
284 memcpy(PINCodeRequestParams.PINCode, Bluetooth_DeviceConfiguration.PINCode, sizeof(PINCodeRequestParams.PINCode));
285
286 /* Send the command to transmit the device's local PIN number for authentication */
287 Bluetooth_SendHCICommand(&HCICommandHeader, &PINCodeRequestParams, sizeof(BT_HCICommand_PinCodeResp_t));
288
289 Bluetooth_HCIProcessingState = Bluetooth_ProcessEvents;
290 break;
291 case Bluetooth_Conn_SendLinkKeyNAK:
292 BT_HCI_DEBUG(1, "# Send Link Key NAK", NULL);
293
294 HCICommandHeader = (BT_HCICommand_Header_t)
295 {
296 OpCode: {OGF: OGF_LINK_CONTROL, OCF: OCF_LINK_CONTROL_LINK_KEY_REQUEST_NEG_REPLY},
297 ParameterLength: sizeof(BT_HCICommand_LinkKeyNAKResp_t),
298 };
299
300 /* Copy over the temporary BT device address saved from the Link Key Request event */
301 BT_HCICommand_LinkKeyNAKResp_t LinkKeyNAKParams;
302 memcpy(LinkKeyNAKParams.RemoteAddress, Bluetooth_TempDeviceAddress, sizeof(LinkKeyNAKParams.RemoteAddress));
303
304 /* Send the command to transmit the link key NAK to the receiver */
305 Bluetooth_SendHCICommand(&HCICommandHeader, &LinkKeyNAKParams, sizeof(BT_HCICommand_LinkKeyNAKResp_t));
306
307 Bluetooth_HCIProcessingState = Bluetooth_ProcessEvents;
308 break;
309 }
310 }
311
312 /** Sends a Bluetooth HCI control command to the attached Bluetooth device.
313 *
314 * \param HCICommandHeader HCI command header to send to the attached device
315 * \param Parameters Pointer to the source of the control parameters (if any)
316 * \param ParameterLength Length of the parameters to send in bytes
317 *
318 * \return A value from the USB_Host_SendControlErrorCodes_t enum.
319 */
320 static uint8_t Bluetooth_SendHCICommand(BT_HCICommand_Header_t* HCICommandHeader, void* Parameters, uint16_t ParameterLength)
321 {
322 /* Need to reserve the amount of bytes given in the header for the complete payload */
323 uint8_t CommandBuffer[sizeof(BT_HCICommand_Header_t) + HCICommandHeader->ParameterLength];
324
325 USB_ControlRequest = (USB_Request_Header_t)
326 {
327 .bmRequestType = (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_DEVICE),
328 .bRequest = 0,
329 .wValue = 0,
330 .wIndex = 0,
331 .wLength = sizeof(CommandBuffer)
332 };
333
334 /* Copy over the HCI command header to the allocated buffer */
335 memcpy(CommandBuffer, HCICommandHeader, sizeof(BT_HCICommand_Header_t));
336
337 /* Zero out the parameter section of the response so that all padding bytes are known to be zero */
338 memset(&CommandBuffer[sizeof(BT_HCICommand_Header_t)], 0x00, HCICommandHeader->ParameterLength);
339
340 /* Copy over the command parameters (if any) to the command buffer - note, the number of actual source parameter bytes
341 may differ to those in the header; any difference in length is filled with 0x00 padding bytes */
342 memcpy(&CommandBuffer[sizeof(BT_HCICommand_Header_t)], Parameters, ParameterLength);
343
344 Pipe_SelectPipe(PIPE_CONTROLPIPE);
345 return USB_Host_SendControlRequest(CommandBuffer);
346 }