BluetoothHCICommands.c 11.2 KB
Newer Older
1
2
/*
             LUFA Library
Dean Camera's avatar
Dean Camera committed
3
     Copyright (C) Dean Camera, 2010.
4
5
6
7
8
9
              
  dean [at] fourwalledcubicle [dot] com
      www.fourwalledcubicle.com
*/

/*
Dean Camera's avatar
Dean Camera committed
10
  Copyright 2010  Dean Camera (dean [at] fourwalledcubicle [dot] com)
11

12
13
14
15
16
17
18
  Permission to use, copy, modify, distribute, and sell this 
  software and its documentation for any purpose is hereby granted
  without fee, provided that the above copyright notice appear in 
  all copies and that both that the copyright notice and this
  permission notice and warranty disclaimer appear in supporting 
  documentation, and that the name of the author not be used in 
  advertising or publicity pertaining to distribution of the 
19
20
21
22
23
24
25
26
27
28
29
30
  software without specific, written prior permission.

  The author disclaim all warranties with regard to this
  software, including all implied warranties of merchantability
  and fitness.  In no event shall the author be liable for any
  special, indirect or consequential damages or any damages
  whatsoever resulting from loss of use, data or profits, whether
  in an action of contract, negligence or other tortious action,
  arising out of or in connection with the use or performance of
  this software.
*/

31
#define  INCLUDE_FROM_BLUETOOTHHCICOMMANDS_C
32
33
#include "BluetoothHCICommands.h"

34
static BT_HCICommand_Header_t HCICommandHeader;
35

36
37
38
       uint8_t                       Bluetooth_HCIProcessingState;
static uint8_t                       Bluetooth_HCINextState;
static uint8_t                       Bluetooth_TempDeviceAddress[6];
39

40
void Bluetooth_HCITask(void)
41
42
43
{
	switch (Bluetooth_HCIProcessingState)
	{
44
		case Bluetooth_ProcessEvents:
45
			Pipe_SelectPipe(BLUETOOTH_EVENTS_PIPE);
46
47
48
49
			Pipe_Unfreeze();
			
			if (Pipe_IsReadWriteAllowed())
			{
50
				BT_HCIEvent_Header_t HCIEventHeader;
51
52

				/* Read in the event header to fetch the event code and payload length */
53
54
				Pipe_Read_Stream_LE(&HCIEventHeader, sizeof(HCIEventHeader));
				
55
				/* Create a temporary buffer for the event parameters */
56
57
				uint8_t EventParams[HCIEventHeader.ParameterLength];

58
				/* Read in the event parameters into the temporary buffer */
59
60
61
62
63
64
65
66
67
				Pipe_Read_Stream_LE(&EventParams, HCIEventHeader.ParameterLength);
				Pipe_ClearIN();

				switch (HCIEventHeader.EventCode)
				{
					case EVENT_COMMAND_COMPLETE:
						Bluetooth_HCIProcessingState = Bluetooth_HCINextState;
						break;
					case EVENT_COMMAND_STATUS:
68
						/* If the execution of a command failed, reset the stack */
69
						if (((BT_HCIEvent_CommandStatus_t*)&EventParams)->Status)
70
71
72
						  Bluetooth_HCIProcessingState = Bluetooth_Init;
						break;
					case EVENT_CONNECTION_REQUEST:
73
						/* Need to store the remote device's BT address in a temporary buffer for later use */
74
						memcpy(Bluetooth_TempDeviceAddress,
75
						       &((BT_HCIEvent_ConnectionRequest_t*)&EventParams)->RemoteAddress,
76
						       sizeof(Bluetooth_TempDeviceAddress));
77
							   
78
						bool IsACLConnection = (((BT_HCIEvent_ConnectionRequest_t*)&EventParams)->LinkType == 0x01);
79
80
81
82

						/* Only accept the connection if it is a ACL (data) connection, a device is not already connected
						   and the user application has indicated that the connection should be allowed */
						Bluetooth_HCIProcessingState = (Bluetooth_Connection.IsConnected || !(IsACLConnection) ||
83
													    !(Bluetooth_ConnectionRequest(Bluetooth_TempDeviceAddress))) ?
84
85
86
													   Bluetooth_Conn_RejectConnection : Bluetooth_Conn_AcceptConnection;
						break;
					case EVENT_PIN_CODE_REQUEST:
87
						/* Need to store the remote device's BT address in a temporary buffer for later use */
88
						memcpy(Bluetooth_TempDeviceAddress,
89
						       &((BT_HCIEvent_PinCodeReq_t*)&EventParams)->RemoteAddress,
90
91
92
93
94
						       sizeof(Bluetooth_TempDeviceAddress));

						Bluetooth_HCIProcessingState = Bluetooth_Conn_SendPINCode;
						break;
					case EVENT_CONNECTION_COMPLETE:
95
						/* Need to store the remote device's BT address in a temporary buffer for later use */
96
						memcpy(Bluetooth_Connection.RemoteAddress,
97
						       &((BT_HCIEvent_ConnectionComplete_t*)&EventParams)->RemoteAddress,
98
99
						       sizeof(Bluetooth_TempDeviceAddress));

100
						/* Store the created connection handle and indicate that the connection has been established */
101
						Bluetooth_Connection.ConnectionHandle = ((BT_HCIEvent_ConnectionComplete_t*)&EventParams)->ConnectionHandle;
102
						Bluetooth_Connection.IsConnected      = true;
103
104
						
						Bluetooth_ConnectionComplete();						
105
						break;
106
107
108
109
					case EVENT_DISCONNECTION_COMPLETE:
						/* Device disconnected, indicate connection information no longer valid */
						Bluetooth_Connection.IsConnected = false;
						
110
111
						Bluetooth_DisconnectionComplete();
						
112
113
						Bluetooth_HCIProcessingState = Bluetooth_Init;
						break;					
114
115
116
117
				}
			}
			
			Pipe_Freeze();
118
			
119
120
			break;
		case Bluetooth_Init:
121
			/* Reset the connection information structure to destroy any previous connection state */
122
			memset(&Bluetooth_Connection, 0x00, sizeof(Bluetooth_Connection));
123

124
125
126
			Bluetooth_HCIProcessingState = Bluetooth_Init_Reset; 
			break;
		case Bluetooth_Init_Reset:
127
			HCICommandHeader = (BT_HCICommand_Header_t)
128
129
130
131
132
			{
				OpCode: {OGF: OGF_CTRLR_BASEBAND, OCF: OCF_CTRLR_BASEBAND_RESET},
				ParameterLength: 0,
			};

133
134
			/* Send the command to reset the bluetooth dongle controller */
			Bluetooth_SendHCICommand(NULL, 0);
135
136
137
			
			Bluetooth_HCINextState       = Bluetooth_Init_SetLocalName;
			Bluetooth_HCIProcessingState = Bluetooth_ProcessEvents;
138
139
			break;
		case Bluetooth_Init_SetLocalName:
140
			HCICommandHeader = (BT_HCICommand_Header_t)
141
142
143
144
145
				{
					OpCode: {OGF: OGF_CTRLR_BASEBAND, OCF: OCF_CTRLR_BASEBAND_WRITE_LOCAL_NAME},
					ParameterLength: 248,
				};

146
147
			/* Send the command to set the bluetooth dongle's name for other devices to see */
			Bluetooth_SendHCICommand(Bluetooth_DeviceConfiguration.Name, strlen(Bluetooth_DeviceConfiguration.Name));
148

149
150
			Bluetooth_HCINextState       = Bluetooth_Init_SetDeviceClass;
			Bluetooth_HCIProcessingState = Bluetooth_ProcessEvents;
151
152
			break;
		case Bluetooth_Init_SetDeviceClass:
153
			HCICommandHeader = (BT_HCICommand_Header_t)
154
155
156
157
158
				{
					OpCode: {OGF: OGF_CTRLR_BASEBAND, OCF: OCF_CTRLR_BASEBAND_WRITE_CLASS_OF_DEVICE},
					ParameterLength: 3,
				};

159
160
			/* Send the command to set the class of the device for other devices to see */
			Bluetooth_SendHCICommand(&Bluetooth_DeviceConfiguration.Class, 3);
161

162
163
			Bluetooth_HCINextState       = Bluetooth_Init_WriteScanEnable;
			Bluetooth_HCIProcessingState = Bluetooth_ProcessEvents;
164
165
			break;
		case Bluetooth_Init_WriteScanEnable:
166
			HCICommandHeader = (BT_HCICommand_Header_t)
167
168
169
170
171
			{
				OpCode: {OGF: OGF_CTRLR_BASEBAND, OCF: OCF_CTRLR_BASEBAND_WRITE_SCAN_ENABLE},
				ParameterLength: 1,
			};

172
173
174
175
			uint8_t Interval = BT_SCANMODE_InquiryAndPageScans;
			
			/* Send the command to set the remote device scanning mode */
			Bluetooth_SendHCICommand(&Interval, 1);
176
			
177
178
			Bluetooth_HCINextState       = Bluetooth_ProcessEvents;
			Bluetooth_HCIProcessingState = Bluetooth_ProcessEvents;
179
180
			break;
		case Bluetooth_Conn_AcceptConnection:
181
			HCICommandHeader = (BT_HCICommand_Header_t)
182
183
				{
					OpCode: {OGF: OGF_LINK_CONTROL, OCF: OCF_LINK_CONTROL_ACCEPT_CONNECTION_REQUEST},
184
					ParameterLength: sizeof(BT_HCICommand_AcceptConnectionReq_t),
185
186
				};

187
188
			/* Copy over the temporary BT device address saved from the Connection Request event, indicate slave
			   connection role */
189
			BT_HCICommand_AcceptConnectionReq_t AcceptConnectionParams;
190
191
			memcpy(AcceptConnectionParams.RemoteAddress, Bluetooth_TempDeviceAddress,
			       sizeof(AcceptConnectionParams.RemoteAddress));
192
193
			AcceptConnectionParams.SlaveRole = true;

194
			/* Send the command to accept the remote connection request */
195
			Bluetooth_SendHCICommand(&AcceptConnectionParams, sizeof(BT_HCICommand_AcceptConnectionReq_t));
196
			
197
			Bluetooth_HCIProcessingState = Bluetooth_ProcessEvents;
198
199
			break;
		case Bluetooth_Conn_RejectConnection:
200
			HCICommandHeader = (BT_HCICommand_Header_t)
201
				{
202
					OpCode: {OGF: OGF_LINK_CONTROL, OCF: OCF_LINK_CONTROL_REJECT_CONNECTION_REQUEST},
203
					ParameterLength: sizeof(BT_HCICommand_RejectConnectionReq_t),
204
205
				};

206
			/* Copy over the temporary BT device address saved from the Connection Request event, indicate failure
207
			   to accept the connection due to limited device resources or incorrect device address */
208
			BT_HCICommand_RejectConnectionReq_t RejectConnectionParams;
209
			memcpy(RejectConnectionParams.RemoteAddress, Bluetooth_TempDeviceAddress, sizeof(RejectConnectionParams.RemoteAddress));
210
			RejectConnectionParams.Reason = Bluetooth_Connection.IsConnected ? ERROR_LIMITED_RESOURCES : ERROR_UNACCEPTABLE_BDADDR;
211

212
			/* Send the command to reject the remote connection request */
213
			Bluetooth_SendHCICommand(&RejectConnectionParams, sizeof(BT_HCICommand_RejectConnectionReq_t));
214
		
215
			Bluetooth_HCIProcessingState = Bluetooth_ProcessEvents;
216
217
			break;
		case Bluetooth_Conn_SendPINCode:
218
			HCICommandHeader = (BT_HCICommand_Header_t)
219
220
				{
					OpCode: {OGF: OGF_LINK_CONTROL, OCF: OCF_LINK_CONTROL_PIN_CODE_REQUEST_REPLY},
221
					ParameterLength: sizeof(BT_HCICommand_PinCodeResp_t),
222
223
				};

224
225
			/* Copy over the temporary BT device address saved from the PIN Code Request event, copy over the
			   local PIN authentication code to the response */
226
			BT_HCICommand_PinCodeResp_t PINCodeRequestParams;
227
			memcpy(PINCodeRequestParams.RemoteAddress, Bluetooth_TempDeviceAddress, sizeof(PINCodeRequestParams.RemoteAddress));
228
			PINCodeRequestParams.PINCodeLength = strlen(Bluetooth_DeviceConfiguration.PINCode);
229
			memcpy(PINCodeRequestParams.PINCode, Bluetooth_DeviceConfiguration.PINCode, sizeof(PINCodeRequestParams.PINCode));
230
			
231
			/* Send the command to transmit the device's local PIN number for authentication */
232
			Bluetooth_SendHCICommand(&PINCodeRequestParams, sizeof(BT_HCICommand_PinCodeResp_t));
233

234
			Bluetooth_HCIProcessingState = Bluetooth_ProcessEvents;
235
236
237
			break;
	}
}
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265

static uint8_t Bluetooth_SendHCICommand(void* Parameters, uint16_t ParameterLength)
{
	/* Need to reserve the amount of bytes given in the header for the complete payload */
	uint8_t CommandBuffer[sizeof(HCICommandHeader) + HCICommandHeader.ParameterLength];

	USB_ControlRequest = (USB_Request_Header_t)
		{
			.bmRequestType = (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_DEVICE),
			.bRequest      = 0,
			.wValue        = 0,
			.wIndex        = 0,
			.wLength       = sizeof(CommandBuffer)
		};

	/* Copy over the HCI command header to the allocated buffer */
	memcpy(CommandBuffer, &HCICommandHeader, sizeof(HCICommandHeader));
	
	/* Zero out the parameter section of the response to ensure that any padding bytes do not expose private RAM contents */
	memset(&CommandBuffer[sizeof(HCICommandHeader)], 0x00, HCICommandHeader.ParameterLength);

	/* Copy over the command parameters (if any) to the command buffer - note, the number of actual source parameter bytes
	   may differ to those in the header; any difference in length is filled with 0x00 padding bytes */
	memcpy(&CommandBuffer[sizeof(HCICommandHeader)], Parameters, ParameterLength);
	
	Pipe_SelectPipe(PIPE_CONTROLPIPE);
	return USB_Host_SendControlRequest(CommandBuffer);
}