3      Copyright (C) Dean Camera, 2012. 
   5   dean [at] fourwalledcubicle [dot] com 
  10   Copyright 2012  Dean Camera (dean [at] fourwalledcubicle [dot] com) 
  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. 
  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 
  33  *  Bluetooth HCI layer management code. This module manages the overall 
  34  *  Bluetooth stack connection state to and from other devices, processes 
  35  *  received events from the Bluetooth controller, and issues commands to 
  36  *  modify the controller's configuration, such as the broadcast name of the 
  41         TODO: Add local to remote device connections 
  44 #define  INCLUDE_FROM_BLUETOOTHHCICOMMANDS_C 
  45 #include "BluetoothHCICommands.h" 
  47 /** Temporary Bluetooth Device Address, for HCI responses which must include the destination address */ 
  48 static uint8_t Bluetooth_TempDeviceAddress
[6]; 
  50 /** Bluetooth HCI processing task. This task should be called repeatedly the main Bluetooth 
  51  *  stack task to manage the HCI processing state. 
  53 void Bluetooth_HCITask(void) 
  55         BT_HCICommand_Header_t HCICommandHeader
; 
  57         switch (Bluetooth_State
.CurrentHCIState
) 
  59                 case Bluetooth_ProcessEvents
: 
  60                         Pipe_SelectPipe(BLUETOOTH_EVENTS_PIPE
); 
  63                         if (Pipe_IsReadWriteAllowed()) 
  65                                 BT_HCIEvent_Header_t HCIEventHeader
; 
  67                                 /* Read in the event header to fetch the event code and payload length */ 
  68                                 Pipe_Read_Stream_LE(&HCIEventHeader
, sizeof(HCIEventHeader
), NULL
); 
  70                                 /* Create a temporary buffer for the event parameters */ 
  71                                 uint8_t EventParams
[HCIEventHeader
.ParameterLength
]; 
  73                                 /* Read in the event parameters into the temporary buffer */ 
  74                                 Pipe_Read_Stream_LE(&EventParams
, HCIEventHeader
.ParameterLength
, NULL
); 
  77                                 BT_HCI_DEBUG(1, "Event Received (0x%02X)", HCIEventHeader
.EventCode
); 
  79                                 switch (HCIEventHeader
.EventCode
) 
  81                                         case EVENT_COMMAND_COMPLETE
: 
  82                                                 BT_HCI_DEBUG(1, "<< Command Complete"); 
  84                                                 /* Check which operation was completed in case we need to process the even parameters */ 
  85                                                 switch (((BT_HCIEvent_CommandComplete_t
*)&EventParams
)->Opcode
) 
  87                                                         case (OGF_CTRLR_INFORMATIONAL 
| OCF_CTRLR_INFORMATIONAL_READBDADDR
): 
  88                                                                 /* A READ BDADDR command completed, copy over the local device's BDADDR from the response */ 
  89                                                                 memcpy(Bluetooth_State
.LocalBDADDR
, 
  90                                                                        &((BT_HCIEvent_CommandComplete_t
*)&EventParams
)->ReturnParams
[1], 
  91                                                                        sizeof(Bluetooth_State
.LocalBDADDR
)); 
  95                                                 Bluetooth_State
.CurrentHCIState 
= Bluetooth_State
.NextHCIState
; 
  97                                         case EVENT_COMMAND_STATUS
: 
  98                                                 BT_HCI_DEBUG(1, "<< Command Status"); 
  99                                                 BT_HCI_DEBUG(2, "-- Status Code: 0x%02X", (((BT_HCIEvent_CommandStatus_t
*)&EventParams
)->Status
)); 
 101                                                 /* If the execution of a command failed, reset the stack */ 
 102                                                 if (((BT_HCIEvent_CommandStatus_t
*)&EventParams
)->Status
) 
 103                                                   Bluetooth_State
.CurrentHCIState 
= Bluetooth_Init
; 
 105                                         case EVENT_CONNECTION_REQUEST
: 
 106                                                 BT_HCI_DEBUG(1, "<< Connection Request"); 
 107                                                 BT_HCI_DEBUG(2, "-- Link Type: 0x%02X", (((BT_HCIEvent_ConnectionRequest_t
*)&EventParams
)->LinkType
)); 
 109                                                 /* Need to store the remote device's BT address in a temporary buffer for later use */ 
 110                                                 memcpy(Bluetooth_TempDeviceAddress
, 
 111                                                        &((BT_HCIEvent_ConnectionRequest_t
*)&EventParams
)->RemoteAddress
, 
 112                                                        sizeof(Bluetooth_TempDeviceAddress
)); 
 114                                                 bool IsACLConnection 
= (((BT_HCIEvent_ConnectionRequest_t
*)&EventParams
)->LinkType 
== 0x01); 
 116                                                 /* Only accept the connection if it is a ACL (data) connection, a device is not already connected 
 117                                                    and the user application has indicated that the connection should be allowed */ 
 118                                                 Bluetooth_State
.CurrentHCIState 
= (Bluetooth_Connection
.IsConnected 
|| !(IsACLConnection
) || 
 119                                                                                                               !(Bluetooth_ConnectionRequest(Bluetooth_TempDeviceAddress
))) ?
 
 120                                                                                                               Bluetooth_Conn_RejectConnection 
: Bluetooth_Conn_AcceptConnection
; 
 122                                                 BT_HCI_DEBUG(2, "-- Connection %S", (Bluetooth_State
.CurrentHCIState 
== Bluetooth_Conn_RejectConnection
) ?
 
 123                                                                                      PSTR("REJECTED") : PSTR("ACCEPTED")); 
 126                                         case EVENT_PIN_CODE_REQUEST
: 
 127                                                 BT_HCI_DEBUG(1, "<< Pin Code Request"); 
 129                                                 /* Need to store the remote device's BT address in a temporary buffer for later use */ 
 130                                                 memcpy(Bluetooth_TempDeviceAddress
, 
 131                                                        &((BT_HCIEvent_PinCodeReq_t
*)&EventParams
)->RemoteAddress
, 
 132                                                        sizeof(Bluetooth_TempDeviceAddress
)); 
 134                                                 Bluetooth_State
.CurrentHCIState 
= Bluetooth_Conn_SendPINCode
; 
 136                                         case EVENT_LINK_KEY_REQUEST
: 
 137                                                 BT_HCI_DEBUG(1, "<< Link Key Request"); 
 139                                                 /* Need to store the remote device's BT address in a temporary buffer for later use */ 
 140                                                 memcpy(Bluetooth_TempDeviceAddress
, 
 141                                                        &((BT_HCIEvent_LinkKeyReq_t
*)&EventParams
)->RemoteAddress
, 
 142                                                        sizeof(Bluetooth_TempDeviceAddress
)); 
 144                                                 Bluetooth_State
.CurrentHCIState 
= Bluetooth_Conn_SendLinkKeyNAK
; 
 146                                         case EVENT_CONNECTION_COMPLETE
: 
 147                                                 BT_HCI_DEBUG(1, "<< Connection Complete"); 
 148                                                 BT_HCI_DEBUG(2, "-- Handle: 0x%04X", ((BT_HCIEvent_ConnectionComplete_t
*)&EventParams
)->ConnectionHandle
); 
 150                                                 /* Need to store the remote device's BT address in a temporary buffer for later use */ 
 151                                                 memcpy(Bluetooth_Connection
.RemoteAddress
, 
 152                                                        &((BT_HCIEvent_ConnectionComplete_t
*)&EventParams
)->RemoteAddress
, 
 153                                                        sizeof(Bluetooth_TempDeviceAddress
)); 
 155                                                 /* Store the created connection handle and indicate that the connection has been established */ 
 156                                                 Bluetooth_Connection
.ConnectionHandle 
= ((BT_HCIEvent_ConnectionComplete_t
*)&EventParams
)->ConnectionHandle
; 
 157                                                 Bluetooth_Connection
.IsConnected      
= true; 
 159                                                 Bluetooth_ConnectionComplete(); 
 161                                         case EVENT_DISCONNECTION_COMPLETE
: 
 162                                                 BT_HCI_DEBUG(1, "<< Disconnection Complete"); 
 164                                                 /* Device disconnected, indicate connection information no longer valid */ 
 165                                                 Bluetooth_Connection
.IsConnected 
= false; 
 167                                                 Bluetooth_DisconnectionComplete(); 
 176                         BT_HCI_DEBUG(1, "# Init"); 
 178                         Bluetooth_State
.IsInitialized 
= false; 
 180                         /* Reset the connection information structure to destroy any previous connection state */ 
 181                         memset(&Bluetooth_Connection
, 0x00, sizeof(Bluetooth_Connection
)); 
 183                         Bluetooth_State
.CurrentHCIState 
= Bluetooth_Init_Reset
; 
 185                 case Bluetooth_Init_Reset
: 
 186                         BT_HCI_DEBUG(1, "# Reset"); 
 188                         HCICommandHeader 
= (BT_HCICommand_Header_t
) 
 190                                 OpCode
: (OGF_CTRLR_BASEBAND 
| OCF_CTRLR_BASEBAND_RESET
), 
 194                         /* Send the command to reset the Bluetooth dongle controller */ 
 195                         Bluetooth_SendHCICommand(&HCICommandHeader
, NULL
, 0); 
 197                         Bluetooth_State
.NextHCIState    
= Bluetooth_Init_ReadBufferSize
; 
 198                         Bluetooth_State
.CurrentHCIState 
= Bluetooth_ProcessEvents
; 
 200                 case Bluetooth_Init_ReadBufferSize
: 
 201                         BT_HCI_DEBUG(1, "# Read Buffer Size"); 
 203                         HCICommandHeader 
= (BT_HCICommand_Header_t
) 
 205                                 OpCode
: (OGF_CTRLR_INFORMATIONAL 
| OCF_CTRLR_INFORMATIONAL_READBUFFERSIZE
), 
 209                         /* Send the command to read the Bluetooth buffer size (mandatory before device sends any data) */ 
 210                         Bluetooth_SendHCICommand(&HCICommandHeader
, NULL
, 0); 
 212                         Bluetooth_State
.NextHCIState    
= Bluetooth_Init_GetBDADDR
; 
 213                         Bluetooth_State
.CurrentHCIState 
= Bluetooth_ProcessEvents
; 
 215                 case Bluetooth_Init_GetBDADDR
: 
 216                         BT_HCI_DEBUG(1, "# Get BDADDR"); 
 218                         HCICommandHeader 
= (BT_HCICommand_Header_t
) 
 220                                 OpCode
: (OGF_CTRLR_INFORMATIONAL 
| OCF_CTRLR_INFORMATIONAL_READBDADDR
), 
 224                         /* Send the command to retrieve the BDADDR of the inserted Bluetooth dongle */ 
 225                         Bluetooth_SendHCICommand(&HCICommandHeader
, NULL
, 0); 
 227                         Bluetooth_State
.NextHCIState    
= Bluetooth_Init_SetLocalName
; 
 228                         Bluetooth_State
.CurrentHCIState 
= Bluetooth_ProcessEvents
; 
 230                 case Bluetooth_Init_SetLocalName
: 
 231                         BT_HCI_DEBUG(1, "# Set Local Name"); 
 233                         HCICommandHeader 
= (BT_HCICommand_Header_t
) 
 235                                         OpCode
: (OGF_CTRLR_BASEBAND 
| OCF_CTRLR_BASEBAND_WRITE_LOCAL_NAME
), 
 236                                         ParameterLength
: 248, 
 239                         /* Send the command to set the Bluetooth dongle's name for other devices to see */ 
 240                         Bluetooth_SendHCICommand(&HCICommandHeader
, Bluetooth_DeviceConfiguration
.Name
, strlen(Bluetooth_DeviceConfiguration
.Name
)); 
 242                         Bluetooth_State
.NextHCIState    
= Bluetooth_Init_SetDeviceClass
; 
 243                         Bluetooth_State
.CurrentHCIState 
= Bluetooth_ProcessEvents
; 
 245                 case Bluetooth_Init_SetDeviceClass
: 
 246                         BT_HCI_DEBUG(1, "# Set Device Class"); 
 248                         HCICommandHeader 
= (BT_HCICommand_Header_t
) 
 250                                         OpCode
: (OGF_CTRLR_BASEBAND 
| OCF_CTRLR_BASEBAND_WRITE_CLASS_OF_DEVICE
), 
 254                         /* Send the command to set the class of the device for other devices to see */ 
 255                         Bluetooth_SendHCICommand(&HCICommandHeader
, &Bluetooth_DeviceConfiguration
.Class
, 3); 
 257                         Bluetooth_State
.NextHCIState    
= Bluetooth_Init_WriteScanEnable
; 
 258                         Bluetooth_State
.CurrentHCIState 
= Bluetooth_ProcessEvents
; 
 260                 case Bluetooth_Init_WriteScanEnable
: 
 261                         BT_HCI_DEBUG(1, "# Write Scan Enable"); 
 263                         HCICommandHeader 
= (BT_HCICommand_Header_t
) 
 265                                 OpCode
: (OGF_CTRLR_BASEBAND 
| OCF_CTRLR_BASEBAND_WRITE_SCAN_ENABLE
), 
 269                         uint8_t Interval 
= BT_SCANMODE_InquiryAndPageScans
; 
 271                         /* Send the command to set the remote device scanning mode */ 
 272                         Bluetooth_SendHCICommand(&HCICommandHeader
, &Interval
, 1); 
 274                         Bluetooth_State
.NextHCIState    
= Bluetooth_Init_FinalizeInit
; 
 275                         Bluetooth_State
.CurrentHCIState 
= Bluetooth_ProcessEvents
; 
 277                 case Bluetooth_Init_FinalizeInit
: 
 278                         Bluetooth_State
.IsInitialized 
= true; 
 280                         /* Fire the user application callback to indicate that the stack is now fully initialized */ 
 281                         Bluetooth_StackInitialized(); 
 283                         Bluetooth_State
.NextHCIState    
= Bluetooth_ProcessEvents
; 
 284                         Bluetooth_State
.CurrentHCIState 
= Bluetooth_ProcessEvents
; 
 286                 case Bluetooth_Conn_AcceptConnection
: 
 287                         BT_HCI_DEBUG(1, "# Accept Connection"); 
 289                         HCICommandHeader 
= (BT_HCICommand_Header_t
) 
 291                                         OpCode
: (OGF_LINK_CONTROL 
| OCF_LINK_CONTROL_ACCEPT_CONNECTION_REQUEST
), 
 292                                         ParameterLength
: sizeof(BT_HCICommand_AcceptConnectionReq_t
), 
 295                         /* Copy over the temporary BT device address saved from the Connection Request event, indicate slave 
 297                         BT_HCICommand_AcceptConnectionReq_t AcceptConnectionParams
; 
 298                         memcpy(AcceptConnectionParams
.RemoteAddress
, Bluetooth_TempDeviceAddress
, 
 299                                sizeof(AcceptConnectionParams
.RemoteAddress
)); 
 300                         AcceptConnectionParams
.SlaveRole 
= true; 
 302                         /* Send the command to accept the remote connection request */ 
 303                         Bluetooth_SendHCICommand(&HCICommandHeader
, &AcceptConnectionParams
, sizeof(BT_HCICommand_AcceptConnectionReq_t
)); 
 305                         Bluetooth_State
.CurrentHCIState 
= Bluetooth_ProcessEvents
; 
 307                 case Bluetooth_Conn_RejectConnection
: 
 308                         BT_HCI_DEBUG(1, "# Reject Connection"); 
 310                         HCICommandHeader 
= (BT_HCICommand_Header_t
) 
 312                                         OpCode
: (OGF_LINK_CONTROL 
| OCF_LINK_CONTROL_REJECT_CONNECTION_REQUEST
), 
 313                                         ParameterLength
: sizeof(BT_HCICommand_RejectConnectionReq_t
), 
 316                         /* Copy over the temporary BT device address saved from the Connection Request event, indicate failure 
 317                            to accept the connection due to limited device resources or incorrect device address */ 
 318                         BT_HCICommand_RejectConnectionReq_t RejectConnectionParams
; 
 319                         memcpy(RejectConnectionParams
.RemoteAddress
, Bluetooth_TempDeviceAddress
, sizeof(RejectConnectionParams
.RemoteAddress
)); 
 320                         RejectConnectionParams
.Reason 
= Bluetooth_Connection
.IsConnected ? ERROR_LIMITED_RESOURCES 
: ERROR_UNACCEPTABLE_BDADDR
; 
 322                         /* Send the command to reject the remote connection request */ 
 323                         Bluetooth_SendHCICommand(&HCICommandHeader
, &RejectConnectionParams
, sizeof(BT_HCICommand_RejectConnectionReq_t
)); 
 325                         Bluetooth_State
.CurrentHCIState 
= Bluetooth_ProcessEvents
; 
 327                 case Bluetooth_Conn_SendPINCode
: 
 328                         BT_HCI_DEBUG(1, "# Send Pin Code"); 
 330                         HCICommandHeader 
= (BT_HCICommand_Header_t
) 
 332                                         OpCode
: (OGF_LINK_CONTROL 
| OCF_LINK_CONTROL_PIN_CODE_REQUEST_REPLY
), 
 333                                         ParameterLength
: sizeof(BT_HCICommand_PinCodeResp_t
), 
 336                         /* Copy over the temporary BT device address saved from the PIN Code Request event, copy over the 
 337                            local PIN authentication code to the response */ 
 338                         BT_HCICommand_PinCodeResp_t PINCodeRequestParams
; 
 339                         memcpy(PINCodeRequestParams
.RemoteAddress
, Bluetooth_TempDeviceAddress
, sizeof(PINCodeRequestParams
.RemoteAddress
)); 
 340                         PINCodeRequestParams
.PINCodeLength 
= strlen(Bluetooth_DeviceConfiguration
.PINCode
); 
 341                         memcpy(PINCodeRequestParams
.PINCode
, Bluetooth_DeviceConfiguration
.PINCode
, sizeof(PINCodeRequestParams
.PINCode
)); 
 343                         /* Send the command to transmit the device's local PIN number for authentication */ 
 344                         Bluetooth_SendHCICommand(&HCICommandHeader
, &PINCodeRequestParams
, sizeof(BT_HCICommand_PinCodeResp_t
)); 
 346                         Bluetooth_State
.CurrentHCIState 
= Bluetooth_ProcessEvents
; 
 348                 case Bluetooth_Conn_SendLinkKeyNAK
: 
 349                         BT_HCI_DEBUG(1, "# Send Link Key NAK"); 
 351                         HCICommandHeader 
= (BT_HCICommand_Header_t
) 
 353                                         OpCode
: (OGF_LINK_CONTROL 
| OCF_LINK_CONTROL_LINK_KEY_REQUEST_NEG_REPLY
), 
 354                                         ParameterLength
: sizeof(BT_HCICommand_LinkKeyNAKResp_t
), 
 357                         /* Copy over the temporary BT device address saved from the Link Key Request event */ 
 358                         BT_HCICommand_LinkKeyNAKResp_t LinkKeyNAKParams
; 
 359                         memcpy(LinkKeyNAKParams
.RemoteAddress
, Bluetooth_TempDeviceAddress
, sizeof(LinkKeyNAKParams
.RemoteAddress
)); 
 361                         /* Send the command to transmit the link key NAK to the receiver */ 
 362                         Bluetooth_SendHCICommand(&HCICommandHeader
, &LinkKeyNAKParams
, sizeof(BT_HCICommand_LinkKeyNAKResp_t
)); 
 364                         Bluetooth_State
.CurrentHCIState 
= Bluetooth_ProcessEvents
; 
 369 /** Sends a Bluetooth HCI control command to the attached Bluetooth device. 
 371  *  \param[in] HCICommandHeader  HCI command header to send to the attached device 
 372  *  \param[in] Parameters        Pointer to the source of the control parameters (if any) 
 373  *  \param[in] ParameterLength   Length of the parameters to send in bytes 
 375  *  \return A value from the USB_Host_SendControlErrorCodes_t enum. 
 377 static uint8_t Bluetooth_SendHCICommand(const BT_HCICommand_Header_t
* const HCICommandHeader
, 
 378                                         const void* Parameters
, 
 379                                         const uint16_t ParameterLength
) 
 381         /* Need to reserve the amount of bytes given in the header for the complete payload */ 
 382         uint8_t CommandBuffer
[sizeof(BT_HCICommand_Header_t
) + HCICommandHeader
->ParameterLength
]; 
 384         USB_ControlRequest 
= (USB_Request_Header_t
) 
 386                         .bmRequestType 
= (REQDIR_HOSTTODEVICE 
| REQTYPE_CLASS 
| REQREC_DEVICE
), 
 390                         .wLength       
= sizeof(CommandBuffer
) 
 393         /* Copy over the HCI command header to the allocated buffer */ 
 394         memcpy(CommandBuffer
, HCICommandHeader
, sizeof(BT_HCICommand_Header_t
)); 
 396         /* Zero out the parameter section of the response so that all padding bytes are known to be zero */ 
 397         memset(&CommandBuffer
[sizeof(BT_HCICommand_Header_t
)], 0x00, HCICommandHeader
->ParameterLength
); 
 399         /* Copy over the command parameters (if any) to the command buffer - note, the number of actual source parameter bytes 
 400            may differ to those in the header; any difference in length is filled with 0x00 padding bytes */ 
 401         memcpy(&CommandBuffer
[sizeof(BT_HCICommand_Header_t
)], Parameters
, ParameterLength
); 
 403         Pipe_SelectPipe(PIPE_CONTROLPIPE
); 
 404         return USB_Host_SendControlRequest(CommandBuffer
);