diff --git a/Demos/Host/Incomplete/BluetoothHost/BluetoothHost.c b/Demos/Host/Incomplete/BluetoothHost/BluetoothHost.c index d2bd07589e..df9f663e3d 100644 --- a/Demos/Host/Incomplete/BluetoothHost/BluetoothHost.c +++ b/Demos/Host/Incomplete/BluetoothHost/BluetoothHost.c @@ -241,18 +241,25 @@ void Bluetooth_DisconnectionComplete(void) /** Bluetooth stack callback event for a non-signal ACL packet reception. This callback fires once a connection * to a remote Bluetooth device has been made, and the remote device has sent a non-signalling ACL packet. * - * \param PacketLength Length of the packet data, in bytes - this must be decremented as data is read - * \param Channel Bluetooth ACL data channel information structure for the packet's destination channel + * \param Data Pointer to a buffer where the received data is stored + * \param DataLen Length of the packet data, in bytes + * \param Channel Bluetooth ACL data channel information structure for the packet's destination channel */ -void Bluetooth_PacketReceived(uint16_t* PacketLength, Bluetooth_Channel_t* Channel) +void Bluetooth_PacketReceived(void* Data, uint16_t DataLen, Bluetooth_Channel_t* Channel) { - uint8_t DataPayload[*PacketLength]; - - Pipe_Read_Stream_LE(&DataPayload, *PacketLength); - *PacketLength = 0; - - printf_P(PSTR("Packet Received (Channel 0x%04X, PSM: 0x%02x):\r\n"), Channel->LocalNumber, Channel->PSM); - for (uint16_t Byte = 0; Byte < sizeof(DataPayload); Byte++) - printf_P(PSTR("0x%02X "), DataPayload[Byte]); - puts_P(PSTR("\r\n")); + switch (Channel->PSM) + { + case CHANNEL_PSM_SDP: + /* Service Discovery Protocol packet */ + ServiceDiscovery_ProcessPacket(Data, DataLen, Channel); + break; + default: + /* Unknown Protocol packet */ + printf_P(PSTR("Packet Received (Channel 0x%04X, PSM: 0x%02x):\r\n"), Channel->LocalNumber, Channel->PSM); + for (uint16_t Byte = 0; Byte < DataLen; Byte++) + printf_P(PSTR("0x%02X "), ((uint8_t*)Data)[Byte]); + puts_P(PSTR("\r\n")); + + break; + } } diff --git a/Demos/Host/Incomplete/BluetoothHost/BluetoothHost.h b/Demos/Host/Incomplete/BluetoothHost/BluetoothHost.h index a24b67a20b..62baf06abe 100644 --- a/Demos/Host/Incomplete/BluetoothHost/BluetoothHost.h +++ b/Demos/Host/Incomplete/BluetoothHost/BluetoothHost.h @@ -43,6 +43,7 @@ #include #include + #include "Lib/ServiceDiscoveryProtocol.h" #include "Lib/BluetoothStack.h" #include "DeviceDescriptor.h" diff --git a/Demos/Host/Incomplete/BluetoothHost/Lib/BluetoothACLPackets.c b/Demos/Host/Incomplete/BluetoothHost/Lib/BluetoothACLPackets.c index 10560f9c8a..d18e643b48 100644 --- a/Demos/Host/Incomplete/BluetoothHost/Lib/BluetoothACLPackets.c +++ b/Demos/Host/Incomplete/BluetoothHost/Lib/BluetoothACLPackets.c @@ -31,16 +31,22 @@ #define INCLUDE_FROM_BLUETOOTH_ACLPACKETS_C #include "BluetoothACLPackets.h" +/** Bluetooth ACL processing task. This task should be called repeatedly the main Bluetooth + * stack task to manage the ACL processing state. + */ void Bluetooth_ACLTask(void) { - Bluetooth_ProcessACLPackets(); + /* Process incomming ACL packets, if any */ + Bluetooth_ProcessIncommingACLPackets(); + /* Check for any half-open channels, send configuration details to the remote device if found */ for (uint8_t i = 0; i < BLUETOOTH_MAX_OPEN_CHANNELS; i++) { Bluetooth_Channel_t* ChannelData = &Bluetooth_Connection.Channels[i]; bool MustSendConfigReq = true; + /* Check if we are in a channel state which requires a configuration request to be sent */ switch (ChannelData->State) { case Channel_Config_WaitConfig: @@ -54,6 +60,7 @@ void Bluetooth_ACLTask(void) break; } + /* Only send a configuration request if it the channel was in a state which required it */ if (MustSendConfigReq) { struct @@ -68,10 +75,13 @@ void Bluetooth_ACLTask(void) } Option_LocalMTU; } PacketData; + /* Fill out the Signal Command header in the response packet */ PacketData.SignalCommandHeader.Code = BT_SIGNAL_CONFIGURATION_REQUEST; PacketData.SignalCommandHeader.Identifier = ++Bluetooth_Connection.SignallingIdentifier; PacketData.SignalCommandHeader.Length = sizeof(PacketData.ConfigurationRequest) + sizeof(PacketData.Option_LocalMTU); + + /* Fill out the Configuration Request in the response packet, including local MTU information */ PacketData.ConfigurationRequest.DestinationChannel = ChannelData->RemoteNumber; PacketData.ConfigurationRequest.Flags = 0; PacketData.Option_LocalMTU.Header.Type = BT_CONFIG_OPTION_MTU; @@ -86,7 +96,11 @@ void Bluetooth_ACLTask(void) } } -static void Bluetooth_ProcessACLPackets(void) +/** Incomming ACL packet processing task. This task is called by the main ACL processing task to read in and process + * any incomming ACL packets to the device, handling signal requests as they are received or passing along channel + * data to the user application. + */ +static void Bluetooth_ProcessIncommingACLPackets(void) { BT_ACL_Header_t ACLPacketHeader; BT_DataPacket_Header_t DataHeader; @@ -100,6 +114,7 @@ static void Bluetooth_ProcessACLPackets(void) return; } + /* Read in the received ACL packet headers when it has been discovered that a packet has been received */ Pipe_Read_Stream_LE(&ACLPacketHeader, sizeof(ACLPacketHeader)); Pipe_Read_Stream_LE(&DataHeader, sizeof(DataHeader)); @@ -110,36 +125,39 @@ static void Bluetooth_ProcessACLPackets(void) BT_ACL_DEBUG(2, "-- Destination Channel: 0x%04X", DataHeader.DestinationChannel); BT_ACL_DEBUG(2, "-- Payload Length: 0x%04X", DataHeader.PayloadLength); + /* Check the packet's destination channel - signalling channel should be processed by the stack internally */ if (DataHeader.DestinationChannel == BT_CHANNEL_SIGNALING) { + /* Read in the Signal Command header of the incomming packet */ BT_Signal_Header_t SignalCommandHeader; Pipe_Read_Stream_LE(&SignalCommandHeader, sizeof(SignalCommandHeader)); + /* Dispatch to the appropriate handler function based on the Signal message code */ switch (SignalCommandHeader.Code) { case BT_SIGNAL_CONNECTION_REQUEST: - Bluetooth_Signal_ConnectionReq(&ACLPacketHeader, &DataHeader, &SignalCommandHeader); + Bluetooth_Signal_ConnectionReq(&SignalCommandHeader); break; case BT_SIGNAL_CONNECTION_RESPONSE: - Bluetooth_Signal_ConnectionResp(&ACLPacketHeader, &DataHeader, &SignalCommandHeader); + Bluetooth_Signal_ConnectionResp(&SignalCommandHeader); break; case BT_SIGNAL_CONFIGURATION_REQUEST: - Bluetooth_Signal_ConfigurationReq(&ACLPacketHeader, &DataHeader, &SignalCommandHeader); + Bluetooth_Signal_ConfigurationReq(&SignalCommandHeader); break; case BT_SIGNAL_CONFIGURATION_RESPONSE: - Bluetooth_Signal_ConfigurationResp(&ACLPacketHeader, &DataHeader, &SignalCommandHeader); + Bluetooth_Signal_ConfigurationResp(&SignalCommandHeader); break; case BT_SIGNAL_DISCONNECTION_REQUEST: - Bluetooth_Signal_DisconnectionReq(&ACLPacketHeader, &DataHeader, &SignalCommandHeader); + Bluetooth_Signal_DisconnectionReq(&SignalCommandHeader); break; case BT_SIGNAL_DISCONNECTION_RESPONSE: - Bluetooth_Signal_DisconnectionResp(&ACLPacketHeader, &DataHeader, &SignalCommandHeader); + Bluetooth_Signal_DisconnectionResp(&SignalCommandHeader); break; case BT_SIGNAL_ECHO_REQUEST: - Bluetooth_Signal_EchoReq(&ACLPacketHeader, &DataHeader, &SignalCommandHeader); + Bluetooth_Signal_EchoReq(&SignalCommandHeader); break; case BT_SIGNAL_INFORMATION_REQUEST: - Bluetooth_Signal_InformationReq(&ACLPacketHeader, &DataHeader, &SignalCommandHeader); + Bluetooth_Signal_InformationReq(&SignalCommandHeader); break; case BT_SIGNAL_COMMAND_REJECT: BT_ACL_DEBUG(1, "<< Command Reject", NULL); @@ -163,28 +181,39 @@ static void Bluetooth_ProcessACLPackets(void) } else { - Bluetooth_PacketReceived(&DataHeader.PayloadLength, Bluetooth_GetChannelData(DataHeader.DestinationChannel, false)); - - Pipe_SelectPipe(BLUETOOTH_DATA_IN_PIPE); - Pipe_Discard_Stream(DataHeader.PayloadLength); + /* Non-signalling packet received, read in the packet contents and pass to the user application */ + uint8_t PacketData[DataHeader.PayloadLength]; + Pipe_Read_Stream_LE(PacketData, DataHeader.PayloadLength); Pipe_ClearIN(); Pipe_Freeze(); + + Bluetooth_PacketReceived(PacketData, DataHeader.PayloadLength, Bluetooth_GetChannelData(DataHeader.DestinationChannel, false)); } } +/** Sends a packet to the remote device on the specified channel. + * + * \param Data Pointer to a buffer where the data is to be sourced from + * \param DataLen Length of the data to send + * \param Channel Channel information structure containing the destination channel's information, NULL to send + * to the remote device's signalling channel + * + * \return A value from the \ref BT_SendPacket_ErrorCodes_t enum + */ uint8_t Bluetooth_SendPacket(void* Data, uint16_t DataLen, Bluetooth_Channel_t* Channel) { BT_ACL_Header_t ACLPacketHeader; BT_DataPacket_Header_t DataHeader; + /* A remote device must be connected before a packet transmission is attempted */ if (!(Bluetooth_Connection.IsConnected)) return BT_SENDPACKET_NotConnected; + /* If the destination channel is not the signalling channel and it is not currently fully open, abort */ if ((Channel != NULL) && (Channel->State != Channel_Open)) return BT_SENDPACKET_ChannelNotOpen; - // TODO: Add packet fragmentation here after retrieving the device's signal channel MTU - + /* Fill out the packet's header from the remote device connection information structure */ ACLPacketHeader.ConnectionHandle = (Bluetooth_Connection.ConnectionHandle | BT_ACL_FIRST_AUTOFLUSH); ACLPacketHeader.DataLength = sizeof(DataHeader) + DataLen; DataHeader.PayloadLength = DataLen; @@ -193,6 +222,7 @@ uint8_t Bluetooth_SendPacket(void* Data, uint16_t DataLen, Bluetooth_Channel_t* Pipe_SelectPipe(BLUETOOTH_DATA_OUT_PIPE); Pipe_Unfreeze(); + /* Write the packet contents to the pipe so that it can be sent to the remote device */ Pipe_Write_Stream_LE(&ACLPacketHeader, sizeof(ACLPacketHeader)); Pipe_Write_Stream_LE(&DataHeader, sizeof(DataHeader)); Pipe_Write_Stream_LE(Data, DataLen); @@ -210,23 +240,40 @@ uint8_t Bluetooth_SendPacket(void* Data, uint16_t DataLen, Bluetooth_Channel_t* return BT_SENDPACKET_NoError; } +/** Opens a bluetooth channel to the currently connected remote device, so that data can be exchanged. + * + * \note The channel is not immediately opened when this function returns - it must undergo a two way + * connection and configuration process first as the main Bluetooth stack processing task is + * repeatedly called. The returned channel is unusable by the user application until its State + * element has progressed to the Open state. + * + * \param PSM PSM of the service that the channel is to be opened for + * + * \return Pointer to the channel information structure of the opened channel, or NULL if no free channels + */ Bluetooth_Channel_t* Bluetooth_OpenChannel(uint16_t PSM) { Bluetooth_Channel_t* ChannelData = NULL; + /* Search through the channel information list for a free channel item */ for (uint8_t i = 0; i < BLUETOOTH_MAX_OPEN_CHANNELS; i++) { if (Bluetooth_Connection.Channels[i].State == Channel_Closed) { - ChannelData = &Bluetooth_Connection.Channels[i]; + ChannelData = &Bluetooth_Connection.Channels[i]; + + /* Set the new channel structure's local channel number to a unique value within the connection orientated + channel address space */ ChannelData->LocalNumber = (BT_CHANNELNUMBER_BASEOFFSET + i); break; } } + /* If no free channel item was found in the list, all channels are occupied - abort */ if (ChannelData == NULL) return NULL; + /* Reset and fill out the allocated channel's information structure with defaults */ ChannelData->RemoteNumber = 0; ChannelData->PSM = PSM; ChannelData->LocalMTU = MAXIMUM_CHANNEL_MTU; @@ -238,9 +285,12 @@ Bluetooth_Channel_t* Bluetooth_OpenChannel(uint16_t PSM) BT_Signal_ConnectionReq_t ConnectionRequest; } PacketData; + /* Fill out the Signal Command header in the response packet */ PacketData.SignalCommandHeader.Code = BT_SIGNAL_CONNECTION_REQUEST; PacketData.SignalCommandHeader.Identifier = ++Bluetooth_Connection.SignallingIdentifier; PacketData.SignalCommandHeader.Length = sizeof(PacketData.ConnectionRequest); + + /* Fill out the Connection Request in the response packet */ PacketData.ConnectionRequest.PSM = PSM; PacketData.ConnectionRequest.SourceChannel = ChannelData->LocalNumber; @@ -253,11 +303,23 @@ Bluetooth_Channel_t* Bluetooth_OpenChannel(uint16_t PSM) return ChannelData; } +/** Closes a bluetooth channel that is open to the currently connected remote device, so that no further data + * can be exchanged. + * + * \note The channel is not immediately closed when this function returns - it must undergo an asynchronous + * disconnection process first as the main Bluetooth stack processing task is repeatedly called. The + * returned channel is unusable by the user application upon return however the channel is not completely + * closed until its State element has progressed to the Closed state. + * + * \param Channel Channel information structure of the channel to close + */ void Bluetooth_CloseChannel(Bluetooth_Channel_t* Channel) { + /* Don't try to close a non-existing or already closed channel */ if ((Channel == NULL) || (Channel->State == Channel_Closed)) return; - + + /* Set the channel's state to the start of the teardown process */ Channel->State = Channel_WaitDisconnect; struct @@ -266,9 +328,12 @@ void Bluetooth_CloseChannel(Bluetooth_Channel_t* Channel) BT_Signal_DisconnectionReq_t DisconnectionRequest; } PacketData; + /* Fill out the Signal Command header in the response packet */ PacketData.SignalCommandHeader.Code = BT_SIGNAL_DISCONNECTION_REQUEST; PacketData.SignalCommandHeader.Identifier = ++Bluetooth_Connection.SignallingIdentifier; PacketData.SignalCommandHeader.Length = sizeof(PacketData.DisconnectionRequest); + + /* Fill out the Disconnection Request in the response packet */ PacketData.DisconnectionRequest.DestinationChannel = Channel->RemoteNumber; PacketData.DisconnectionRequest.SourceChannel = Channel->LocalNumber; @@ -279,9 +344,11 @@ void Bluetooth_CloseChannel(Bluetooth_Channel_t* Channel) BT_ACL_DEBUG(2, "-- Source Channel: 0x%04X", PacketData.DisconnectionRequest.SourceChannel); } -static inline void Bluetooth_Signal_ConnectionReq(BT_ACL_Header_t* ACLPacketHeader, - BT_DataPacket_Header_t* DataHeader, - BT_Signal_Header_t* SignalCommandHeader) +/** Internal Bluetooth stack Signal Command processing routine for a Connection Request command. + * + * \param SignalCommandHeader Pointer to the start of the received packet's Signal Command header + */ +static inline void Bluetooth_Signal_ConnectionReq(BT_Signal_Header_t* SignalCommandHeader) { BT_Signal_ConnectionReq_t ConnectionRequest; @@ -294,21 +361,28 @@ static inline void Bluetooth_Signal_ConnectionReq(BT_ACL_Header_t* ACLPac BT_ACL_DEBUG(2, "-- PSM: 0x%04X", ConnectionRequest.PSM); BT_ACL_DEBUG(2, "-- Source Channel: 0x%04X", ConnectionRequest.SourceChannel); + /* Try to retrieve the existing channel's information structure if it exists */ Bluetooth_Channel_t* ChannelData = Bluetooth_GetChannelData(ConnectionRequest.SourceChannel, true); + /* If an existing channel item with the correct remote channel number was not found, find a free channel entry */ if (ChannelData == NULL) { + /* Look through the channel information list for a free entry */ for (uint8_t i = 0; i < BLUETOOTH_MAX_OPEN_CHANNELS; i++) { if (Bluetooth_Connection.Channels[i].State == Channel_Closed) { - ChannelData = &Bluetooth_Connection.Channels[i]; + ChannelData = &Bluetooth_Connection.Channels[i]; + + /* Set the new channel structure's local channel number to a unique value within the connection orientated + channel address space */ ChannelData->LocalNumber = (BT_CHANNELNUMBER_BASEOFFSET + i); break; } } } + /* Reset the channel item contents only if a channel entry was found for it */ if (ChannelData != NULL) { ChannelData->RemoteNumber = ConnectionRequest.SourceChannel; @@ -323,9 +397,12 @@ static inline void Bluetooth_Signal_ConnectionReq(BT_ACL_Header_t* ACLPac BT_Signal_ConnectionResp_t ConnectionResponse; } ResponsePacket; + /* Fill out the Signal Command header in the response packet */ ResponsePacket.SignalCommandHeader.Code = BT_SIGNAL_CONNECTION_RESPONSE; ResponsePacket.SignalCommandHeader.Identifier = SignalCommandHeader->Identifier; ResponsePacket.SignalCommandHeader.Length = sizeof(ResponsePacket.ConnectionResponse); + + /* Fill out the Connection Response in the response packet */ ResponsePacket.ConnectionResponse.DestinationChannel = ChannelData->LocalNumber; ResponsePacket.ConnectionResponse.SourceChannel = ChannelData->RemoteNumber; ResponsePacket.ConnectionResponse.Result = (ChannelData == NULL) ? BT_CONNECTION_REFUSED_RESOURCES : @@ -340,9 +417,11 @@ static inline void Bluetooth_Signal_ConnectionReq(BT_ACL_Header_t* ACLPac BT_ACL_DEBUG(2, "-- Source Channel: 0x%04X", ResponsePacket.ConnectionResponse.SourceChannel); } -static inline void Bluetooth_Signal_ConnectionResp(BT_ACL_Header_t* ACLPacketHeader, - BT_DataPacket_Header_t* DataHeader, - BT_Signal_Header_t* SignalCommandHeader) +/** Internal Bluetooth stack Signal Command processing routine for a Connection Response command. + * + * \param SignalCommandHeader Pointer to the start of the received packet's Signal Command header + */ +static inline void Bluetooth_Signal_ConnectionResp(BT_Signal_Header_t* SignalCommandHeader) { BT_Signal_ConnectionResp_t ConnectionResponse; @@ -356,22 +435,28 @@ static inline void Bluetooth_Signal_ConnectionResp(BT_ACL_Header_t* ACLPacketHea BT_ACL_DEBUG(2, "-- Source Channel: 0x%04X", ConnectionResponse.SourceChannel); BT_ACL_DEBUG(2, "-- Destination Channel: 0x%04X", ConnectionResponse.DestinationChannel); + /* Search for the referenced channel in the channel information list */ Bluetooth_Channel_t* ChannelData = Bluetooth_GetChannelData(ConnectionResponse.SourceChannel, false); + /* Only progress if the referenced channel data was found */ if (ChannelData != NULL) { + /* Set the channel structure's remote channel number to the channel allocated on the remote device */ ChannelData->RemoteNumber = ConnectionResponse.SourceChannel; ChannelData->State = (ConnectionResponse.Result == BT_CONNECTION_SUCCESSFUL) ? Channel_Config_WaitConfig : Channel_Closed; } } - -static inline void Bluetooth_Signal_ConfigurationReq(BT_ACL_Header_t* ACLPacketHeader, - BT_DataPacket_Header_t* DataHeader, - BT_Signal_Header_t* SignalCommandHeader) +/** Internal Bluetooth stack Signal Command processing routine for a Configuration Request command. + * + * \param SignalCommandHeader Pointer to the start of the received packet's Signal Command header + */ +static inline void Bluetooth_Signal_ConfigurationReq(BT_Signal_Header_t* SignalCommandHeader) { BT_Signal_ConfigurationReq_t ConfigurationRequest; + + /* Allocate a buffer large enough to hold the variable number of configuration options in the request */ uint8_t OptionsLen = (SignalCommandHeader->Length - sizeof(ConfigurationRequest)); uint8_t Options[OptionsLen]; @@ -381,6 +466,7 @@ static inline void Bluetooth_Signal_ConfigurationReq(BT_ACL_Header_t* ACL Pipe_ClearIN(); Pipe_Freeze(); + /* Search for the referenced channel in the channel information list */ Bluetooth_Channel_t* ChannelData = Bluetooth_GetChannelData(ConfigurationRequest.DestinationChannel, false); BT_ACL_DEBUG(1, "<< L2CAP Configuration Request", NULL); @@ -388,18 +474,26 @@ static inline void Bluetooth_Signal_ConfigurationReq(BT_ACL_Header_t* ACL BT_ACL_DEBUG(2, "-- Remote MTU: 0x%04X", ChannelData->RemoteMTU); BT_ACL_DEBUG(2, "-- Options Len: 0x%04X", OptionsLen); - uint8_t OptionPos = 0; - while (OptionPos < OptionsLen) + /* Only look at the channel configuration options if a valid channel entry for the local channel number was found */ + if (ChannelData != NULL) { - BT_Config_Option_Header_t* OptionHeader = (BT_Config_Option_Header_t*)&Options[OptionPos]; + /* Iterate through each option in the configuration request to look for ones which can be processed */ + uint8_t OptionPos = 0; + while (OptionPos < OptionsLen) + { + BT_Config_Option_Header_t* OptionHeader = (BT_Config_Option_Header_t*)&Options[OptionPos]; + void* OptionData = &Options[OptionPos + sizeof(*OptionHeader)]; - BT_ACL_DEBUG(2, "-- Option Type: 0x%04X", OptionHeader->Type); - BT_ACL_DEBUG(2, "-- Option Length: 0x%04X", (sizeof(*OptionHeader) + OptionHeader->Length)); - - if ((OptionHeader->Type == BT_CONFIG_OPTION_MTU) && (ChannelData != NULL)) - ChannelData->RemoteMTU = *((uint16_t*)&Options[OptionPos + sizeof(*OptionHeader)]); + BT_ACL_DEBUG(2, "-- Option Type: 0x%04X", OptionHeader->Type); + BT_ACL_DEBUG(2, "-- Option Length: 0x%04X", (sizeof(*OptionHeader) + OptionHeader->Length)); + + /* Store the remote MTU option's value if present */ + if (OptionHeader->Type == BT_CONFIG_OPTION_MTU) + ChannelData->RemoteMTU = *((uint16_t*)OptionData); - OptionPos += (sizeof(*OptionHeader) + OptionHeader->Length); + /* Progress to the next option in the packet */ + OptionPos += (sizeof(*OptionHeader) + OptionHeader->Length); + } } struct @@ -408,9 +502,12 @@ static inline void Bluetooth_Signal_ConfigurationReq(BT_ACL_Header_t* ACL BT_Signal_ConfigurationResp_t ConfigurationResponse; } ResponsePacket; + /* Fill out the Signal Command header in the response packet */ ResponsePacket.SignalCommandHeader.Code = BT_SIGNAL_CONFIGURATION_RESPONSE; ResponsePacket.SignalCommandHeader.Identifier = SignalCommandHeader->Identifier; ResponsePacket.SignalCommandHeader.Length = sizeof(ResponsePacket.ConfigurationResponse); + + /* Fill out the Configuration Response in the response packet */ ResponsePacket.ConfigurationResponse.SourceChannel = ChannelData->RemoteNumber; ResponsePacket.ConfigurationResponse.Flags = 0x00; ResponsePacket.ConfigurationResponse.Result = (ChannelData != NULL) ? BT_CONFIGURATION_SUCCESSFUL : BT_CONFIGURATION_REJECTED; @@ -438,9 +535,11 @@ static inline void Bluetooth_Signal_ConfigurationReq(BT_ACL_Header_t* ACL BT_ACL_DEBUG(2, "-- Result: 0x%02X", ResponsePacket.ConfigurationResponse.Result); } -static inline void Bluetooth_Signal_ConfigurationResp(BT_ACL_Header_t* ACLPacketHeader, - BT_DataPacket_Header_t* DataHeader, - BT_Signal_Header_t* SignalCommandHeader) +/** Internal Bluetooth stack Signal Command processing routine for a Configuration Response command. + * + * \param SignalCommandHeader Pointer to the start of the received packet's Signal Command header + */ +static inline void Bluetooth_Signal_ConfigurationResp(BT_Signal_Header_t* SignalCommandHeader) { BT_Signal_ConfigurationResp_t ConfigurationResponse; @@ -453,11 +552,14 @@ static inline void Bluetooth_Signal_ConfigurationResp(BT_ACL_Header_t* AC BT_ACL_DEBUG(2, "-- Source Channel: 0x%04X", ConfigurationResponse.SourceChannel); BT_ACL_DEBUG(2, "-- Result: 0x%02X", ConfigurationResponse.Result); - if (ConfigurationResponse.Result == BT_CONFIGURATION_SUCCESSFUL) + /* Search for the referenced channel in the channel information list */ + Bluetooth_Channel_t* ChannelData = Bluetooth_GetChannelData(ConfigurationResponse.SourceChannel, true); + + /* Only update the channel's state if it was found in the channel list */ + if (ChannelData != NULL) { - Bluetooth_Channel_t* ChannelData = Bluetooth_GetChannelData(ConfigurationResponse.SourceChannel, true); - - if (ChannelData != NULL) + /* Check if the channel configuration completed successfuly */ + if (ConfigurationResponse.Result == BT_CONFIGURATION_SUCCESSFUL) { switch (ChannelData->State) { @@ -467,14 +569,21 @@ static inline void Bluetooth_Signal_ConfigurationResp(BT_ACL_Header_t* AC case Channel_Config_WaitResp: ChannelData->State = Channel_Open; break; - } - } + } + } + else + { + /* Configuration failed - close the channel */ + ChannelData->State = Channel_Closed; + } } } -static inline void Bluetooth_Signal_DisconnectionReq(BT_ACL_Header_t* ACLPacketHeader, - BT_DataPacket_Header_t* DataHeader, - BT_Signal_Header_t* SignalCommandHeader) +/** Internal Bluetooth stack Signal Command processing routine for a Disconnection Request command. + * + * \param SignalCommandHeader Pointer to the start of the received packet's Signal Command header + */ +static inline void Bluetooth_Signal_DisconnectionReq(BT_Signal_Header_t* SignalCommandHeader) { BT_Signal_DisconnectionReq_t DisconnectionRequest; @@ -487,6 +596,7 @@ static inline void Bluetooth_Signal_DisconnectionReq(BT_ACL_Header_t* ACL Pipe_ClearIN(); Pipe_Freeze(); + /* Search for the referenced channel in the channel information list */ Bluetooth_Channel_t* ChannelData = Bluetooth_GetChannelData(DisconnectionRequest.SourceChannel, true); struct @@ -495,14 +605,18 @@ static inline void Bluetooth_Signal_DisconnectionReq(BT_ACL_Header_t* ACL BT_Signal_DisconnectionResp_t DisconnectionResponse; } ResponsePacket; + /* Fill out the Signal Command header in the response packet */ ResponsePacket.SignalCommandHeader.Code = BT_SIGNAL_DISCONNECTION_RESPONSE; ResponsePacket.SignalCommandHeader.Identifier = SignalCommandHeader->Identifier; ResponsePacket.SignalCommandHeader.Length = sizeof(ResponsePacket.DisconnectionResponse); + + /* Fill out the Disconnection Response in the response packet */ ResponsePacket.DisconnectionResponse.DestinationChannel = ChannelData->RemoteNumber; ResponsePacket.DisconnectionResponse.SourceChannel = ChannelData->LocalNumber; Bluetooth_SendPacket(&ResponsePacket, sizeof(ResponsePacket), NULL); + /* If the channel was found in the channel list, close it */ if (ChannelData != NULL) ChannelData->State = Channel_Closed; @@ -511,9 +625,11 @@ static inline void Bluetooth_Signal_DisconnectionReq(BT_ACL_Header_t* ACL BT_ACL_DEBUG(2, "-- Destination Channel: 0x%04X", ResponsePacket.DisconnectionResponse.DestinationChannel); } -static inline void Bluetooth_Signal_DisconnectionResp(BT_ACL_Header_t* ACLPacketHeader, - BT_DataPacket_Header_t* DataHeader, - BT_Signal_Header_t* SignalCommandHeader) +/** Internal Bluetooth stack Signal Command processing routine for a Disconnection Response command. + * + * \param SignalCommandHeader Pointer to the start of the received packet's Signal Command header + */ +static inline void Bluetooth_Signal_DisconnectionResp(BT_Signal_Header_t* SignalCommandHeader) { BT_Signal_DisconnectionResp_t DisconnectionResponse; @@ -526,15 +642,19 @@ static inline void Bluetooth_Signal_DisconnectionResp(BT_ACL_Header_t* AC Pipe_ClearIN(); Pipe_Freeze(); + /* Search for the referenced channel in the channel information list */ Bluetooth_Channel_t* ChannelData = Bluetooth_GetChannelData(DisconnectionResponse.SourceChannel, true); - if (ChannelData->State == Channel_WaitDisconnect) + /* If the channel was found in the channel list, close it */ + if (ChannelData != NULL) ChannelData->State = Channel_Closed; } -static inline void Bluetooth_Signal_EchoReq(BT_ACL_Header_t* ACLPacketHeader, - BT_DataPacket_Header_t* DataHeader, - BT_Signal_Header_t* SignalCommandHeader) +/** Internal Bluetooth stack Signal Command processing routine for an Echo Request command. + * + * \param SignalCommandHeader Pointer to the start of the received packet's Signal Command header + */ +static inline void Bluetooth_Signal_EchoReq(BT_Signal_Header_t* SignalCommandHeader) { BT_ACL_DEBUG(1, "<< L2CAP Echo Request", NULL); @@ -546,6 +666,7 @@ static inline void Bluetooth_Signal_EchoReq(BT_ACL_Header_t* ACLPacketHeader, BT_Signal_Header_t SignalCommandHeader; } ResponsePacket; + /* Fill out the Signal Command header in the response packet */ ResponsePacket.SignalCommandHeader.Code = BT_SIGNAL_ECHO_RESPONSE; ResponsePacket.SignalCommandHeader.Identifier = SignalCommandHeader->Identifier; ResponsePacket.SignalCommandHeader.Length = 0; @@ -555,9 +676,11 @@ static inline void Bluetooth_Signal_EchoReq(BT_ACL_Header_t* ACLPacketHeader, BT_ACL_DEBUG(1, ">> L2CAP Echo Response", NULL); } -static inline void Bluetooth_Signal_InformationReq(BT_ACL_Header_t* ACLPacketHeader, - BT_DataPacket_Header_t* DataHeader, - BT_Signal_Header_t* SignalCommandHeader) +/** Internal Bluetooth stack Signal Command processing routine for an Information Request command. + * + * \param SignalCommandHeader Pointer to the start of the received packet's Signal Command header + */ +static inline void Bluetooth_Signal_InformationReq(BT_Signal_Header_t* SignalCommandHeader) { BT_Signal_InformationReq_t InformationRequest; @@ -579,6 +702,7 @@ static inline void Bluetooth_Signal_InformationReq(BT_ACL_Header_t* ACLPa uint8_t DataLen = 0; + /* Retrieve the requested information and store it in the outgoing packet, if found */ switch (InformationRequest.InfoType) { case BT_INFOREQ_MTU: @@ -599,10 +723,14 @@ static inline void Bluetooth_Signal_InformationReq(BT_ACL_Header_t* ACLPa break; } + /* Fill out the Signal Command header in the response packet */ ResponsePacket.SignalCommandHeader.Code = BT_SIGNAL_INFORMATION_RESPONSE; ResponsePacket.SignalCommandHeader.Identifier = SignalCommandHeader->Identifier; ResponsePacket.SignalCommandHeader.Length = sizeof(ResponsePacket.InformationResponse) + DataLen; + /* Fill out the Information Response in the response packet */ + ResponsePacket.InformationResponse.InfoType = InformationRequest.InfoType; + Bluetooth_SendPacket(&ResponsePacket, (sizeof(ResponsePacket) - sizeof(ResponsePacket.Data) + DataLen), NULL); BT_ACL_DEBUG(1, ">> L2CAP Information Response", NULL); diff --git a/Demos/Host/Incomplete/BluetoothHost/Lib/BluetoothACLPackets.h b/Demos/Host/Incomplete/BluetoothHost/Lib/BluetoothACLPackets.h index d38721a72c..5bc5c83583 100644 --- a/Demos/Host/Incomplete/BluetoothHost/Lib/BluetoothACLPackets.h +++ b/Demos/Host/Incomplete/BluetoothHost/Lib/BluetoothACLPackets.h @@ -35,14 +35,16 @@ #include #include #include + #include #include + #include #include "BluetoothStack.h" /* Macros: */ #define BT_ACL_DEBUG(l, s, ...) do { if (ACL_DEBUG_LEVEL >= l) printf_P(PSTR("(ACL) " s "\r\n"), __VA_ARGS__); } while (0) - #define ACL_DEBUG_LEVEL 2 + #define ACL_DEBUG_LEVEL 0 #define BT_CHANNELNUMBER_BASEOFFSET 0x0040 @@ -158,32 +160,16 @@ void Bluetooth_ACLTask(void); #if defined(INCLUDE_FROM_BLUETOOTH_ACLPACKETS_C) - static void Bluetooth_ProcessACLPackets(void); - - static inline void Bluetooth_Signal_ConnectionReq(BT_ACL_Header_t* ACLPacketHeader, - BT_DataPacket_Header_t* DataHeader, - BT_Signal_Header_t* SignalCommandHeader); - static inline void Bluetooth_Signal_ConnectionResp(BT_ACL_Header_t* ACLPacketHeader, - BT_DataPacket_Header_t* DataHeader, - BT_Signal_Header_t* SignalCommandHeader); - static inline void Bluetooth_Signal_EchoReq(BT_ACL_Header_t* ACLPacketHeader, - BT_DataPacket_Header_t* DataHeader, - BT_Signal_Header_t* SignalCommandHeader); - static inline void Bluetooth_Signal_ConfigurationReq(BT_ACL_Header_t* ACLPacketHeader, - BT_DataPacket_Header_t* DataHeader, - BT_Signal_Header_t* SignalCommandHeader); - static inline void Bluetooth_Signal_ConfigurationResp(BT_ACL_Header_t* ACLPacketHeader, - BT_DataPacket_Header_t* DataHeader, - BT_Signal_Header_t* SignalCommandHeader); - static inline void Bluetooth_Signal_DisconnectionReq(BT_ACL_Header_t* ACLPacketHeader, - BT_DataPacket_Header_t* DataHeader, - BT_Signal_Header_t* SignalCommandHeader); - static inline void Bluetooth_Signal_DisconnectionResp(BT_ACL_Header_t* ACLPacketHeader, - BT_DataPacket_Header_t* DataHeader, - BT_Signal_Header_t* SignalCommandHeader); - static inline void Bluetooth_Signal_InformationReq(BT_ACL_Header_t* ACLPacketHeader, - BT_DataPacket_Header_t* DataHeader, - BT_Signal_Header_t* SignalCommandHeader); + static void Bluetooth_ProcessIncommingACLPackets(void); + + static inline void Bluetooth_Signal_ConnectionReq(BT_Signal_Header_t* SignalCommandHeader); + static inline void Bluetooth_Signal_ConnectionResp(BT_Signal_Header_t* SignalCommandHeader); + static inline void Bluetooth_Signal_ConfigurationReq(BT_Signal_Header_t* SignalCommandHeader); + static inline void Bluetooth_Signal_ConfigurationResp(BT_Signal_Header_t* SignalCommandHeader); + static inline void Bluetooth_Signal_DisconnectionReq(BT_Signal_Header_t* SignalCommandHeader); + static inline void Bluetooth_Signal_DisconnectionResp(BT_Signal_Header_t* SignalCommandHeader); + static inline void Bluetooth_Signal_EchoReq(BT_Signal_Header_t* SignalCommandHeader); + static inline void Bluetooth_Signal_InformationReq(BT_Signal_Header_t* SignalCommandHeader); #endif #endif diff --git a/Demos/Host/Incomplete/BluetoothHost/Lib/BluetoothHCICommands.h b/Demos/Host/Incomplete/BluetoothHost/Lib/BluetoothHCICommands.h index 6a241eaa33..de1ffe6f4d 100644 --- a/Demos/Host/Incomplete/BluetoothHost/Lib/BluetoothHCICommands.h +++ b/Demos/Host/Incomplete/BluetoothHost/Lib/BluetoothHCICommands.h @@ -35,15 +35,17 @@ #include #include #include + #include #include + #include #include "BluetoothStack.h" #include "BluetoothClassCodes.h" /* Macros: */ #define BT_HCI_DEBUG(l, s, ...) do { if (HCI_DEBUG_LEVEL >= l) printf_P(PSTR("(HCI) " s "\r\n"), __VA_ARGS__); } while (0) - #define HCI_DEBUG_LEVEL 1 + #define HCI_DEBUG_LEVEL 0 #define OGF_LINK_CONTROL 0x01 #define OGF_CTRLR_BASEBAND 0x03 diff --git a/Demos/Host/Incomplete/BluetoothHost/Lib/BluetoothStack.h b/Demos/Host/Incomplete/BluetoothHost/Lib/BluetoothStack.h index 4de49b355b..564a2ba3e6 100644 --- a/Demos/Host/Incomplete/BluetoothHost/Lib/BluetoothStack.h +++ b/Demos/Host/Incomplete/BluetoothHost/Lib/BluetoothStack.h @@ -34,26 +34,24 @@ /* Includes: */ #include - #include "BluetoothHost.h" - /* Macros: */ - #define BLUETOOTH_DATA_IN_PIPE 1 - #define BLUETOOTH_DATA_OUT_PIPE 2 - #define BLUETOOTH_EVENTS_PIPE 3 + #define BLUETOOTH_DATA_IN_PIPE 1 + #define BLUETOOTH_DATA_OUT_PIPE 2 + #define BLUETOOTH_EVENTS_PIPE 3 - #define BLUETOOTH_MAX_OPEN_CHANNELS 6 + #define BLUETOOTH_MAX_OPEN_CHANNELS 6 - #define CHANNEL_PSM_SERVICEDISCOVERY 0x0001 - #define CHANNEL_PSM_UDP 0x0002 - #define CHANNEL_PSM_RFCOMM 0x0003 - #define CHANNEL_PSM_TCP 0x0004 - #define CHANNEL_PSM_IP 0x0009 - #define CHANNEL_PSM_FTP 0x000A - #define CHANNEL_PSM_HTTP 0x000C - #define CHANNEL_PSM_UPNP 0x0010 - #define CHANNEL_PSM_HIDP 0x0011 + #define CHANNEL_PSM_SDP 0x0001 + #define CHANNEL_PSM_UDP 0x0002 + #define CHANNEL_PSM_RFCOMM 0x0003 + #define CHANNEL_PSM_TCP 0x0004 + #define CHANNEL_PSM_IP 0x0009 + #define CHANNEL_PSM_FTP 0x000A + #define CHANNEL_PSM_HTTP 0x000C + #define CHANNEL_PSM_UPNP 0x0010 + #define CHANNEL_PSM_HIDP 0x0011 - #define MAXIMUM_CHANNEL_MTU 255 + #define MAXIMUM_CHANNEL_MTU 255 /* Enums: */ /** Enum for the possible states for a bluetooth ACL channel. */ @@ -101,19 +99,21 @@ */ typedef struct { - bool IsConnected; - uint16_t ConnectionHandle; - uint8_t RemoteAddress[6]; - Bluetooth_Channel_t Channels[BLUETOOTH_MAX_OPEN_CHANNELS]; - uint8_t SignallingIdentifier; + bool IsConnected; /**< Indicates if the stack is currently connected to a remote device - if this value is + * false, the remaining elements are invalid. + */ + uint16_t ConnectionHandle; /**< Connection handle to the remote device, used internally in the stack. */ + uint8_t RemoteAddress[6]; /**< Bluetooth device address of the attached remote device. */ + Bluetooth_Channel_t Channels[BLUETOOTH_MAX_OPEN_CHANNELS]; /**< Channel information structures for the connection. */ + uint8_t SignallingIdentifier; /**< Next Signalling Channel unique command sequence identifier. */ } Bluetooth_Connection_t; /** Local Bluetooth device information structure, for the defining of local device characteristics for the Bluetooth stack. */ typedef struct { - uint32_t Class; - char PINCode[16]; - char Name[]; + uint32_t Class; /**< Class of the local device, a mask of DEVICE_CLASS_* masks. */ + char PINCode[16]; /**< Pin code required to send or receive in order to authenticate with a remote device. */ + char Name[]; /**< Name of the local bluetooth device, up to 248 characters. */ } Bluetooth_Device_t; /* Includes: */ @@ -127,7 +127,7 @@ bool Bluetooth_ConnectionRequest(uint8_t* RemoteAddress); void Bluetooth_ConnectionComplete(void); void Bluetooth_DisconnectionComplete(void); - void Bluetooth_PacketReceived(uint16_t* PacketLength, Bluetooth_Channel_t* Channel); + void Bluetooth_PacketReceived(void* Data, uint16_t DataLen, Bluetooth_Channel_t* Channel); Bluetooth_Channel_t* Bluetooth_GetChannelData(uint16_t ChannelNumber, bool SearchByRemoteChannel); Bluetooth_Channel_t* Bluetooth_OpenChannel(uint16_t PSM); void Bluetooth_CloseChannel(Bluetooth_Channel_t* Channel); diff --git a/Demos/Host/Incomplete/BluetoothHost/Lib/ServiceDiscoveryProtocol.c b/Demos/Host/Incomplete/BluetoothHost/Lib/ServiceDiscoveryProtocol.c new file mode 100644 index 0000000000..1ee4c842e5 --- /dev/null +++ b/Demos/Host/Incomplete/BluetoothHost/Lib/ServiceDiscoveryProtocol.c @@ -0,0 +1,41 @@ +/* + LUFA Library + Copyright (C) Dean Camera, 2010. + + dean [at] fourwalledcubicle [dot] com + www.fourwalledcubicle.com +*/ + +/* + Copyright 2010 Dean Camera (dean [at] fourwalledcubicle [dot] com) + + 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 + 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. +*/ + +#include "ServiceDiscoveryProtocol.h" + +void ServiceDiscovery_ProcessPacket(void* Data, uint16_t Length, Bluetooth_Channel_t* Channel) +{ + SDP_PDUHeader_t* SDPHeader = (SDP_PDUHeader_t*)Data; + SDPHeader->ParameterLength = SwapEndian_16(SDPHeader->ParameterLength); + + BT_SDP_DEBUG(1, "<< Service Discovery Packet", NULL); + BT_SDP_DEBUG(2, "-- PDU ID: 0x%02X", SDPHeader->PDU); + BT_SDP_DEBUG(2, "-- Param Length: 0x%04X", SDPHeader->ParameterLength); +} diff --git a/Demos/Host/Incomplete/BluetoothHost/Lib/ServiceDiscoveryProtocol.h b/Demos/Host/Incomplete/BluetoothHost/Lib/ServiceDiscoveryProtocol.h new file mode 100644 index 0000000000..ed528e93f9 --- /dev/null +++ b/Demos/Host/Incomplete/BluetoothHost/Lib/ServiceDiscoveryProtocol.h @@ -0,0 +1,68 @@ +/* + LUFA Library + Copyright (C) Dean Camera, 2010. + + dean [at] fourwalledcubicle [dot] com + www.fourwalledcubicle.com +*/ + +/* + Copyright 2010 Dean Camera (dean [at] fourwalledcubicle [dot] com) + + 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 + 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. +*/ + +#ifndef _SERVICEDISCOVERYPROTOCOL_H_ +#define _SERVICEDISCOVERYPROTOCOL_H_ + + /* Includes: */ + #include + #include + #include + #include + + #include + #include + + #include "BluetoothStack.h" + + /* Macros: */ + #define BT_SDP_DEBUG(l, s, ...) do { if (SDP_DEBUG_LEVEL >= l) printf_P(PSTR("(SDP) " s "\r\n"), __VA_ARGS__); } while (0) + #define SDP_DEBUG_LEVEL 2 + + #define SDP_PDU_ERRORRESPONSE 0x01 + #define SDP_PDU_SERVICESEARCHREQUEST 0x02 + #define SDP_PDU_SERVICESEARCHRESPONSE 0x03 + #define SDP_PDU_SERVICEATTRIBUTEREQUEST 0x04 + #define SDP_PDU_SERVICEATTRIBUTERESPONSE 0x05 + #define SDP_PDU_SERVICESEARCHATTRIBUTEREQUEST 0x06 + #define SDP_PDU_SERVICESEARCHATTRIBUTERESPONSE 0x07 + + /* Type Defines: */ + typedef struct + { + uint8_t PDU; + uint16_t TransactionID; + uint16_t ParameterLength; + } SDP_PDUHeader_t; + + /* Function Prototypes: */ + void ServiceDiscovery_ProcessPacket(void* Data, uint16_t Length, Bluetooth_Channel_t* Channel); + +#endif diff --git a/Demos/Host/Incomplete/BluetoothHost/makefile b/Demos/Host/Incomplete/BluetoothHost/makefile index e4b3f234cc..1f2f26c938 100644 --- a/Demos/Host/Incomplete/BluetoothHost/makefile +++ b/Demos/Host/Incomplete/BluetoothHost/makefile @@ -135,6 +135,7 @@ SRC = $(TARGET).c \ Lib/BluetoothStack.c \ Lib/BluetoothHCICommands.c \ Lib/BluetoothACLPackets.c \ + Lib/ServiceDiscoveryProtocol.c \ $(LUFA_PATH)/LUFA/Drivers/Peripheral/SerialStream.c \ $(LUFA_PATH)/LUFA/Drivers/Peripheral/Serial.c \ $(LUFA_PATH)/LUFA/Drivers/USB/LowLevel/DevChapter9.c \ diff --git a/LUFA.pnproj b/LUFA.pnproj index 6bcce91bbd..f8a4f22c8f 100644 --- a/LUFA.pnproj +++ b/LUFA.pnproj @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/LUFA/ManPages/DirectorySummaries.txt b/LUFA/ManPages/DirectorySummaries.txt index bf2061970a..3d4995b497 100644 --- a/LUFA/ManPages/DirectorySummaries.txt +++ b/LUFA/ManPages/DirectorySummaries.txt @@ -155,7 +155,7 @@ * Board directory should be included instead. * * \dir LUFA/Drivers/Board/JMDBU2 - * \briefJM-DB-U2 board hardware driver files. + * \brief JM-DB-U2 board hardware driver files. * * This folder contains drivers for hardware on the JM-DB-U2 boards (http://u2.mattair.net/). The header files in this folder * should not be included directly in user applications; the similarly named dispatch header files located in the parent Board diff --git a/Projects/LEDNotifier/LEDNotifier.c b/Projects/LEDNotifier/LEDNotifier.c index 00b6e26985..61d5efcbb5 100644 --- a/Projects/LEDNotifier/LEDNotifier.c +++ b/Projects/LEDNotifier/LEDNotifier.c @@ -113,7 +113,7 @@ int main(void) /* Read in next LED colour command from the host */ uint8_t ColorUpdate = fgetc(&USBSerialStream); - /* Top 3 bits select the LED, bottom three control the brightness */ + /* Top 3 bits select the LED, bottom 5 control the brightness */ uint8_t Channel = (ColorUpdate & 0b11100000); uint8_t Duty = (ColorUpdate & 0b00011111);