diff --git a/Demos/Host/Incomplete/BluetoothHost/Lib/BluetoothACLPackets.c b/Demos/Host/Incomplete/BluetoothHost/Lib/BluetoothACLPackets.c index 03d0f2acae..df8dfc5c1d 100644 --- a/Demos/Host/Incomplete/BluetoothHost/Lib/BluetoothACLPackets.c +++ b/Demos/Host/Incomplete/BluetoothHost/Lib/BluetoothACLPackets.c @@ -28,6 +28,13 @@ this software. */ +/** \file + * + * Bluetooth L2CAP layer management code. This module managed the creation, + * configuration and teardown of L2CAP channels, and manages packet reception + * and sending to and from other Bluetooth devices. + */ + /* TODO: Make SendPacket respect receiver's MTU TODO: Make ReceivePacket stitch together MTU fragments (?) diff --git a/Demos/Host/Incomplete/BluetoothHost/Lib/BluetoothHCICommands.c b/Demos/Host/Incomplete/BluetoothHost/Lib/BluetoothHCICommands.c index 57b74e089b..d718752127 100644 --- a/Demos/Host/Incomplete/BluetoothHost/Lib/BluetoothHCICommands.c +++ b/Demos/Host/Incomplete/BluetoothHost/Lib/BluetoothHCICommands.c @@ -28,6 +28,15 @@ this software. */ +/** \file + * + * Bluetooth HCI layer management code. This module manages the overall + * Bluetooth stack connection state to and from other devices, processes + * received events from the Bluetooth controller, and issues commands to + * modify the controller's configuration, such as the broadcast name of the + * device. + */ + /* TODO: Add local to remote device connections */ diff --git a/Demos/Host/Incomplete/BluetoothHost/Lib/BluetoothStack.c b/Demos/Host/Incomplete/BluetoothHost/Lib/BluetoothStack.c index d78a9efa19..1a667987b3 100644 --- a/Demos/Host/Incomplete/BluetoothHost/Lib/BluetoothStack.c +++ b/Demos/Host/Incomplete/BluetoothHost/Lib/BluetoothStack.c @@ -28,6 +28,12 @@ this software. */ +/** \file + * + * Main module for the Bluetooth stack. This module contains the overall Bluetooth + * stack state variables and the main Bluetooth stack management functions. + */ + #include "BluetoothStack.h" /** Bluetooth device connection information structure. Once connected to a remote device, this structure tracks the diff --git a/Demos/Host/Incomplete/BluetoothHost/Lib/RFCOMM.c b/Demos/Host/Incomplete/BluetoothHost/Lib/RFCOMM.c index a441ae1564..510160629d 100644 --- a/Demos/Host/Incomplete/BluetoothHost/Lib/RFCOMM.c +++ b/Demos/Host/Incomplete/BluetoothHost/Lib/RFCOMM.c @@ -28,6 +28,13 @@ this software. */ +/** \file + * + * RFCOMM layer module. This module manages the RFCOMM layer of the + * stack, providing virtual serial port channels on top of the lower + * L2CAP layer. + */ + #define INCLUDE_FROM_RFCOMM_C #include "RFCOMM.h" @@ -62,10 +69,10 @@ void RFCOMM_Initialize(void) void RFCOMM_ProcessPacket(void* Data, Bluetooth_Channel_t* const Channel) { - RFCOMM_Header_t* FrameHeader = (RFCOMM_Header_t*)Data; + const RFCOMM_Header_t* FrameHeader = (const RFCOMM_Header_t*)Data; /* Decode the RFCOMM frame type from the header */ - switch (FrameHeader->FrameType & ~FRAME_POLL_FINAL) + switch (FrameHeader->Control & ~FRAME_POLL_FINAL) { case RFCOMM_Frame_SABM: RFCOMM_ProcessSABM(FrameHeader, Channel); @@ -82,54 +89,94 @@ void RFCOMM_ProcessPacket(void* Data, Bluetooth_Channel_t* const Channel) case RFCOMM_Frame_UIH: RFCOMM_ProcessUIH(FrameHeader, Channel); break; + default: + BT_RFCOMM_DEBUG(1, "<< Unknown Frame Type"); + break; } } static void RFCOMM_ProcessSABM(const RFCOMM_Header_t* const FrameHeader, Bluetooth_Channel_t* const Channel) { - uint8_t* CurrBufferPos = ((uint8_t*)FrameHeader + sizeof(RFCOMM_Header_t)); - uint16_t DataLen = RFCOMM_GetFrameDataLength(&CurrBufferPos); - BT_RFCOMM_DEBUG(1, "<< SABM Received"); - BT_RFCOMM_DEBUG(2, "-- Data Length 0x%04X", DataLen); + BT_RFCOMM_DEBUG(2, "-- Address 0x%02X", FrameHeader->Address); + + // TODO: Reset channel send/receive state here + + struct + { + RFCOMM_Header_t FrameHeader; + uint8_t FrameLength; + uint8_t FCS; + } ResponsePacket; + + /* Copy over the same frame header as the sent packet to copy the logical RFCOMM channel address */ + ResponsePacket.FrameHeader.Address = FrameHeader->Address; + + /* Set the frame type to an Unnumbered Acknowledgement to acknowledge the SABM request */ + ResponsePacket.FrameHeader.Control = RFCOMM_Frame_UA; + + /* Set the length to 0 (LSB indicates end of 8-bit length field) */ + ResponsePacket.FrameLength = 0x01; + + /* Calculate the frame checksum from all fields except the FCS field itself */ + ResponsePacket.FCS = RFCOMM_GetFCSValue(&ResponsePacket, sizeof(ResponsePacket) - sizeof(ResponsePacket.FCS)); + + BT_RFCOMM_DEBUG(1, ">> UA Sent"); - for (uint16_t i = 0; i < DataLen; i++) - printf("0x%02X ", CurrBufferPos[i]); - printf("\r\n"); + /* Send the completed response packet to the sender */ + Bluetooth_SendPacket(&ResponsePacket, sizeof(ResponsePacket), Channel); } static void RFCOMM_ProcessUA(const RFCOMM_Header_t* const FrameHeader, Bluetooth_Channel_t* const Channel) { + const uint8_t* CurrBufferPos = ((const uint8_t*)FrameHeader + sizeof(RFCOMM_Header_t)); + BT_RFCOMM_DEBUG(1, "<< UA Received"); + BT_RFCOMM_DEBUG(2, "-- Address 0x%02X", FrameHeader->Address); } static void RFCOMM_ProcessDM(const RFCOMM_Header_t* const FrameHeader, Bluetooth_Channel_t* const Channel) { + const uint8_t* CurrBufferPos = ((const uint8_t*)FrameHeader + sizeof(RFCOMM_Header_t)); + BT_RFCOMM_DEBUG(1, "<< DM Received"); + BT_RFCOMM_DEBUG(2, "-- Address 0x%02X", FrameHeader->Address); } static void RFCOMM_ProcessDISC(const RFCOMM_Header_t* const FrameHeader, Bluetooth_Channel_t* const Channel) { + const uint8_t* CurrBufferPos = ((const uint8_t*)FrameHeader + sizeof(RFCOMM_Header_t)); + BT_RFCOMM_DEBUG(1, "<< DISC Received"); + BT_RFCOMM_DEBUG(2, "-- Address 0x%02X", FrameHeader->Address); } static void RFCOMM_ProcessUIH(const RFCOMM_Header_t* const FrameHeader, Bluetooth_Channel_t* const Channel) { + const uint8_t* CurrBufferPos = ((const uint8_t*)FrameHeader + sizeof(RFCOMM_Header_t)); + BT_RFCOMM_DEBUG(1, "<< UIH Received"); + BT_RFCOMM_DEBUG(2, "-- Address 0x%02X", FrameHeader->Address); } -static uint16_t RFCOMM_GetFrameDataLength(void** BufferPos) +static uint8_t RFCOMM_GetFCSValue(const void* FrameStart, uint16_t Length) { - uint8_t FirstOctet = *((uint8_t*)*BufferPos); - (*BufferPos)++; + const uint8_t* CurrPos = FrameStart; + uint8_t FCS = 0xFF; + + while (Length--) + FCS = pgm_read_byte(CRC8_Table[FCS ^ *(CurrPos++)]); + return ~FCS; +} + +static uint16_t RFCOMM_GetFrameDataLength(const uint8_t** BufferPos) +{ + uint8_t FirstOctet = *((*BufferPos)++); uint8_t SecondOctet = 0; if (!(FirstOctet & 0x01)) - { - SecondOctet = *((uint8_t*)*BufferPos); - (*BufferPos)++; - } + SecondOctet = *((*BufferPos)++); return (((uint16_t)SecondOctet << 7) | (FirstOctet >> 1)); } diff --git a/Demos/Host/Incomplete/BluetoothHost/Lib/RFCOMM.h b/Demos/Host/Incomplete/BluetoothHost/Lib/RFCOMM.h index 45f29ac21f..194551d03a 100644 --- a/Demos/Host/Incomplete/BluetoothHost/Lib/RFCOMM.h +++ b/Demos/Host/Incomplete/BluetoothHost/Lib/RFCOMM.h @@ -52,7 +52,7 @@ #define BT_RFCOMM_DEBUG(l, s, ...) do { if (RFCOMM_DEBUG_LEVEL >= l) printf_P(PSTR("(RFCOMM) " s "\r\n"), ##__VA_ARGS__); } while (0) #define RFCOMM_DEBUG_LEVEL 2 - #define FRAME_POLL_FINAL (1 << 5) + #define FRAME_POLL_FINAL (1 << 4) /* Enums: */ /** Enum for the types of RFCOMM frames which can be exchanged on a Bluetooth channel. */ @@ -73,9 +73,9 @@ unsigned char LogicalChannel : 6; unsigned char PollResponse : 1; unsigned char LastAddressOctet : 1; - } Header; + } Address; - uint8_t FrameType; + uint8_t Control; } RFCOMM_Header_t; /* Function Prototypes: */ @@ -89,7 +89,8 @@ static void RFCOMM_ProcessDISC(const RFCOMM_Header_t* const FrameHeader, Bluetooth_Channel_t* const Channel); static void RFCOMM_ProcessUIH(const RFCOMM_Header_t* const FrameHeader, Bluetooth_Channel_t* const Channel); - static uint16_t RFCOMM_GetFrameDataLength(void** BufferPos); + static uint8_t RFCOMM_GetFCSValue(const void* FrameStart, uint16_t Length); + static uint16_t RFCOMM_GetFrameDataLength(const uint8_t** BufferPos); #endif #endif diff --git a/Demos/Host/Incomplete/BluetoothHost/Lib/SDPServices.c b/Demos/Host/Incomplete/BluetoothHost/Lib/SDPServices.c index ca47f9084a..16317e787a 100644 --- a/Demos/Host/Incomplete/BluetoothHost/Lib/SDPServices.c +++ b/Demos/Host/Incomplete/BluetoothHost/Lib/SDPServices.c @@ -28,8 +28,19 @@ this software. */ +/** \file + * + * SDP Service Attribute definitions. This file contains the attributes + * and attribute tables of all the services the device supports, which can + * then be retrieved by a connected Bluetooth device via the SDP server. + */ + #include "SDPServices.h" +/** Serial Port Profile attribute, listing the unique service handle of the Serial Port service + * within the device. This handle can then be requested by the SDP client in future transactions + * in lieu of a search UUID list. + */ const struct { uint8_t Header; @@ -40,6 +51,10 @@ const struct SWAPENDIAN_32(0x00010001), }; +/** Serial Port Profile attribute, listing the implemented Service Class UUIDs of the Serial Port service + * within the device. This list indicates all the class UUIDs that apply to the Serial Port service, so that + * a SDP client can search by a generalized class rather than a specific UUID to determine supported services. + */ const struct { uint8_t Header; @@ -54,6 +69,10 @@ const struct }, }; +/** Serial Port Profile attribute, listing the Protocols (and their attributes) of the Serial Port service + * within the device. This list indicates what protocols the service is layered on top of, as well as any + * configuration information for each layer. + */ const struct { uint8_t Header; @@ -77,11 +96,15 @@ const struct (sizeof(ItemUUID_t) + sizeof(Item8Bit_t)), { {(SDP_DATATYPE_UUID | SDP_DATASIZE_128Bit), RFCOMM_UUID}, - {(SDP_DATATYPE_UnsignedInt | SDP_DATASIZE_8Bit), 0x00}, + {(SDP_DATATYPE_UnsignedInt | SDP_DATASIZE_8Bit), 0x03}, }, }, }; +/** Serial Port Profile attribute, listing the Browse Group List UUIDs which this service is a member of. + * Browse Group UUIDs give a way to group together services within a device in a simple heirachy, so that + * a SDP client can progressively narrow down an general browse to a specific service which it requires. + */ const struct { uint8_t Header; @@ -95,7 +118,10 @@ const struct {(SDP_DATATYPE_UUID | SDP_DATASIZE_128Bit), PUBLICBROWSEGROUP_CLASS_UUID}, }, }; - + +/** Serial Port Profile attribute, listing the languages (and their encodings) supported + * by the Serial Port service in its text string attributes. + */ const struct { uint8_t Header; @@ -113,7 +139,8 @@ const struct }, }, }; - + +/** Serial Port Profile attribute, listing a human readable name of the service. */ const struct { uint8_t Header; @@ -126,6 +153,7 @@ const struct "Wireless Serial Port", }; +/** Serial Port Profile attribute, listing a human readable description of the service. */ const struct { uint8_t Header; @@ -138,6 +166,9 @@ const struct "Wireless Serial Port Service", }; +/** Service Attribute Table for the Serial Port service, linking each supported attribute ID to its data, so that + * the SDP server can retrieve it for transmission back to a SDP client upon request. + */ const ServiceAttributeTable_t PROGMEM SerialPort_Attribute_Table[] = { {.AttributeID = SDP_ATTRIBUTE_ID_SERVICERECORDHANDLE, .Data = &SerialPort_Attribute_ServiceHandle }, diff --git a/Demos/Host/Incomplete/BluetoothHost/Lib/ServiceDiscoveryProtocol.c b/Demos/Host/Incomplete/BluetoothHost/Lib/ServiceDiscoveryProtocol.c index c07718e78c..6d8f27036a 100644 --- a/Demos/Host/Incomplete/BluetoothHost/Lib/ServiceDiscoveryProtocol.c +++ b/Demos/Host/Incomplete/BluetoothHost/Lib/ServiceDiscoveryProtocol.c @@ -28,6 +28,14 @@ this software. */ +/** \file + * + * SDP layer module. This module implements a simple Service Discovery + * Protocol server, which can broadcast the device's supported services + * to other Bluetooth devices upon request, so that they can determine + * what services are available. + */ + #define INCLUDE_FROM_SERVICEDISCOVERYPROTOCOL_C #include "ServiceDiscoveryProtocol.h" @@ -62,6 +70,7 @@ void SDP_ProcessPacket(void* Data, Bluetooth_Channel_t* const Channel) BT_SDP_DEBUG(2, "-- PDU ID: 0x%02X", SDPHeader->PDU); BT_SDP_DEBUG(2, "-- Param Length: 0x%04X", SDPHeader->ParameterLength); + /* Dispatch to the correct processing routine for the given SDP packet type */ switch (SDPHeader->PDU) { case SDP_PDU_SERVICESEARCHREQUEST: