Change matching algorithm so that it recursively searches through the entire attribute table, and not just pre-specified sequence attributes.
Add browse lists and proper descriptions to the Serial Port service.
\r
#include "SDPServices.h"\r
\r
-/* ------------------------------ SDP SERVICE ATTRIBUTES ------------------------------ */\r
-\r
-const struct\r
-{\r
- uint8_t Header;\r
- uint32_t Data;\r
-} PROGMEM SDP_Attribute_ServiceHandle =\r
- {\r
- (SDP_DATATYPE_UnsignedInt | SDP_DATASIZE_32Bit),\r
- SWAPENDIAN_32(0x00010000),\r
- };\r
-\r
-const struct\r
-{\r
- uint8_t Header;\r
- uint16_t Size;\r
- ItemUUID_t UUIDList[];\r
-} PROGMEM SDP_Attribute_ServiceClassIDs =\r
- {\r
- (SDP_DATATYPE_Sequence | SDP_DATASIZE_Variable16Bit),\r
- SWAPENDIAN_16(sizeof(ItemUUID_t) * 1),\r
- {\r
- {(SDP_DATATYPE_UUID | SDP_DATASIZE_128Bit), SDP_CLASS_UUID}\r
- }\r
- };\r
-\r
-const struct\r
-{\r
- uint8_t Header;\r
- uint8_t Size;\r
- Item16Bit_t VersionList[];\r
-} PROGMEM SDP_Attribute_Version =\r
- {\r
- (SDP_DATATYPE_Sequence | SDP_DATASIZE_Variable8Bit),\r
- (sizeof(Item16Bit_t) * 1),\r
- {\r
- {(SDP_DATATYPE_UnsignedInt | SDP_DATASIZE_16Bit), SWAPENDIAN_16(0x0100)}\r
- }\r
- };\r
-\r
-const struct\r
-{\r
- uint8_t Header;\r
- uint8_t Size;\r
- char Text[];\r
-} PROGMEM SDP_Attribute_ServiceName =\r
- {\r
- (SDP_DATATYPE_String | SDP_DATASIZE_Variable8Bit),\r
- (sizeof("SDP") - 1),\r
- "SDP",\r
- };\r
-\r
-const struct\r
-{\r
- uint8_t Header;\r
- uint8_t Size;\r
- char Text[];\r
-} PROGMEM SDP_Attribute_ServiceDescription =\r
- {\r
- (SDP_DATATYPE_String | SDP_DATASIZE_Variable8Bit),\r
- (sizeof("Service Discovery Protocol Server") - 1),\r
- "Service Discovery Protocol Server",\r
- };\r
-\r
-/** Service Discovery Protocol attribute table, listing all supported attributes of the service. */\r
-const ServiceAttributeTable_t SDP_Attribute_Table[] PROGMEM =\r
- {\r
- {.AttributeID = SDP_ATTRIBUTE_ID_SERVICERECORDHANDLE, .Data = &SDP_Attribute_ServiceHandle },\r
- {.AttributeID = SDP_ATTRIBUTE_ID_SERVICECLASSIDS, .Data = &SDP_Attribute_ServiceClassIDs },\r
- {.AttributeID = SDP_ATTRIBUTE_ID_VERSION, .Data = &SDP_Attribute_Version },\r
- {.AttributeID = SDP_ATTRIBUTE_ID_SERVICENAME, .Data = &SDP_Attribute_ServiceName },\r
- {.AttributeID = SDP_ATTRIBUTE_ID_SERVICEDESCRIPTION, .Data = &SDP_Attribute_ServiceDescription },\r
-\r
- SERVICE_ATTRIBUTE_TABLE_TERMINATOR\r
- };\r
-\r
-\r
-/* ------------------------------ RFCOMM SERVICE ATTRIBUTES ------------------------------ */\r
-\r
-\r
const struct\r
{\r
uint8_t Header;\r
{\r
{\r
(SDP_DATATYPE_Sequence | SDP_DATASIZE_Variable8Bit),\r
- sizeof(UUID_t),\r
+ sizeof(ItemUUID_t),\r
{\r
{(SDP_DATATYPE_UUID | SDP_DATASIZE_128Bit), L2CAP_UUID},\r
}\r
},\r
{\r
(SDP_DATATYPE_Sequence | SDP_DATASIZE_Variable8Bit),\r
- sizeof(UUID_t),\r
+ sizeof(ItemUUID_t),\r
{\r
{(SDP_DATATYPE_UUID | SDP_DATASIZE_128Bit), RFCOMM_UUID},\r
}\r
- }\r
+ },\r
}\r
};\r
\r
const struct\r
{\r
- uint8_t Header;\r
- uint8_t Size;\r
- char Text[];\r
-} PROGMEM RFCOMM_Attribute_ServiceName =\r
- {\r
- (SDP_DATATYPE_String | SDP_DATASIZE_Variable8Bit),\r
- sizeof("Serial Port") - 1,\r
- "Serial Port",\r
- };\r
-\r
-const struct\r
-{\r
- uint8_t Header;\r
- uint8_t Size;\r
- char Text[];\r
-} PROGMEM RFCOMM_Attribute_ServiceDescription =\r
- {\r
- (SDP_DATATYPE_String | SDP_DATASIZE_Variable8Bit),\r
- sizeof("Wireless Serial Port Service") - 1,\r
- "Wireless Serial Port Service",\r
- };\r
-\r
-const ServiceAttributeTable_t RFCOMM_Attribute_Table[] PROGMEM =\r
- {\r
- {.AttributeID = SDP_ATTRIBUTE_ID_SERVICERECORDHANDLE, .Data = &RFCOMM_Attribute_ServiceHandle },\r
- {.AttributeID = SDP_ATTRIBUTE_ID_SERVICECLASSIDS, .Data = &RFCOMM_Attribute_ServiceClassIDs },\r
- {.AttributeID = SDP_ATTRIBUTE_ID_PROTOCOLDESCRIPTORLIST, .Data = &RFCOMM_Attribute_ProtocolDescriptor },\r
- {.AttributeID = SDP_ATTRIBUTE_ID_SERVICENAME, .Data = &RFCOMM_Attribute_ServiceName },\r
- {.AttributeID = SDP_ATTRIBUTE_ID_SERVICEDESCRIPTION, .Data = &RFCOMM_Attribute_ServiceDescription },\r
-\r
- SERVICE_ATTRIBUTE_TABLE_TERMINATOR\r
- };\r
-\r
-\r
-/* ------------------------------ L2CAP SERVICE ATTRIBUTES ------------------------------ */\r
-\r
-\r
-const struct\r
-{\r
- uint8_t Header;\r
- uint32_t Data;\r
-} PROGMEM L2CAP_Attribute_ServiceHandle =\r
- {\r
- (SDP_DATATYPE_UnsignedInt | SDP_DATASIZE_32Bit),\r
- SWAPENDIAN_32(0x00010002),\r
- };\r
-\r
-const struct\r
-{\r
uint8_t Header;\r
uint16_t Size;\r
ItemUUID_t UUIDList[];\r
-} PROGMEM L2CAP_Attribute_ServiceClassIDs =\r
+} PROGMEM RFCOMM_Attribute_BrowseGroupList =\r
{\r
(SDP_DATATYPE_Sequence | SDP_DATASIZE_Variable16Bit),\r
- SWAPENDIAN_16(sizeof(ItemUUID_t) * 2),\r
+ SWAPENDIAN_16(sizeof(ItemUUID_t) * 1),\r
{\r
- {(SDP_DATATYPE_UUID | SDP_DATASIZE_128Bit), SDP_CLASS_UUID },\r
- {(SDP_DATATYPE_UUID | SDP_DATASIZE_128Bit), SP_CLASS_UUID },\r
+ {(SDP_DATATYPE_UUID | SDP_DATASIZE_128Bit), PUBLICBROWSEGROUP_CLASS_UUID}\r
}\r
};\r
-\r
+ \r
const struct\r
{\r
- uint8_t Header;\r
- uint16_t Size;\r
-\r
- ItemProtocol_t ProtocolList[];\r
-} PROGMEM L2CAP_Attribute_ProtocolDescriptor =\r
- {\r
- (SDP_DATATYPE_Sequence | SDP_DATASIZE_Variable16Bit),\r
- SWAPENDIAN_16(sizeof(ItemProtocol_t) * 2),\r
- {\r
+ uint8_t Header;\r
+ uint8_t Size;\r
+ ItemLangID_t OffsetList[];\r
+} PROGMEM RFCOMM_Attribute_LanguageBaseIDOffset =\r
+ {\r
+ .Header = (SDP_DATATYPE_Sequence | SDP_DATASIZE_Variable8Bit),\r
+ .Size = (sizeof(ItemLangID_t) * 1),\r
+ .OffsetList =\r
{\r
- (SDP_DATATYPE_Sequence | SDP_DATASIZE_Variable8Bit),\r
- sizeof(UUID_t),\r
{\r
- {(SDP_DATATYPE_UUID | SDP_DATASIZE_128Bit), L2CAP_UUID},\r
- }\r
- },\r
- {\r
- (SDP_DATATYPE_Sequence | SDP_DATASIZE_Variable8Bit),\r
- sizeof(UUID_t),\r
- {\r
- {(SDP_DATATYPE_UUID | SDP_DATASIZE_128Bit), RFCOMM_UUID},\r
+ {(SDP_DATATYPE_UnsignedInt | SDP_DATASIZE_16Bit), SWAPENDIAN_16(0x454E)},\r
+ {(SDP_DATATYPE_UnsignedInt | SDP_DATASIZE_16Bit), SWAPENDIAN_16(0x006A)},\r
+ {(SDP_DATATYPE_UnsignedInt | SDP_DATASIZE_16Bit), SWAPENDIAN_16(0x0100)},\r
}\r
}\r
- }\r
- };\r
+ }; \r
\r
const struct\r
{\r
uint8_t Header;\r
uint8_t Size;\r
char Text[];\r
-} PROGMEM L2CAP_Attribute_ServiceName =\r
+} PROGMEM RFCOMM_Attribute_ServiceName =\r
{\r
(SDP_DATATYPE_String | SDP_DATASIZE_Variable8Bit),\r
- sizeof("L2CAP") - 1,\r
- "L2CAP",\r
+ sizeof("Serial Port") - 1,\r
+ "Serial Port",\r
};\r
\r
const struct\r
uint8_t Header;\r
uint8_t Size;\r
char Text[];\r
-} PROGMEM L2CAP_Attribute_ServiceDescription =\r
+} PROGMEM RFCOMM_Attribute_ServiceDescription =\r
{\r
(SDP_DATATYPE_String | SDP_DATASIZE_Variable8Bit),\r
- sizeof("Logical Link Layer") - 1,\r
- "Logical Link Layer",\r
+ sizeof("Wireless Serial Port Service") - 1,\r
+ "Wireless Serial Port Service",\r
};\r
\r
-const ServiceAttributeTable_t L2CAP_Attribute_Table[] PROGMEM =\r
+const ServiceAttributeTable_t PROGMEM RFCOMM_Attribute_Table[] =\r
{\r
- {.AttributeID = SDP_ATTRIBUTE_ID_SERVICERECORDHANDLE, .Data = &L2CAP_Attribute_ServiceHandle },\r
- {.AttributeID = SDP_ATTRIBUTE_ID_SERVICECLASSIDS, .Data = &L2CAP_Attribute_ServiceClassIDs },\r
- {.AttributeID = SDP_ATTRIBUTE_ID_PROTOCOLDESCRIPTORLIST, .Data = &L2CAP_Attribute_ProtocolDescriptor },\r
- {.AttributeID = SDP_ATTRIBUTE_ID_SERVICENAME, .Data = &L2CAP_Attribute_ServiceName },\r
- {.AttributeID = SDP_ATTRIBUTE_ID_SERVICEDESCRIPTION, .Data = &L2CAP_Attribute_ServiceDescription },\r
- \r
+ {.AttributeID = SDP_ATTRIBUTE_ID_SERVICERECORDHANDLE, .Data = &RFCOMM_Attribute_ServiceHandle },\r
+ {.AttributeID = SDP_ATTRIBUTE_ID_SERVICECLASSIDS, .Data = &RFCOMM_Attribute_ServiceClassIDs },\r
+ {.AttributeID = SDP_ATTRIBUTE_ID_PROTOCOLDESCRIPTORLIST, .Data = &RFCOMM_Attribute_ProtocolDescriptor },\r
+ {.AttributeID = SDP_ATTRIBUTE_ID_BROWSEGROUPLIST, .Data = &RFCOMM_Attribute_BrowseGroupList },\r
+ {.AttributeID = SDP_ATTRIBUTE_ID_LANGUAGEBASEATTROFFSET, .Data = &RFCOMM_Attribute_LanguageBaseIDOffset},\r
+ {.AttributeID = SDP_ATTRIBUTE_ID_SERVICENAME, .Data = &RFCOMM_Attribute_ServiceName },\r
+ {.AttributeID = SDP_ATTRIBUTE_ID_SERVICEDESCRIPTION, .Data = &RFCOMM_Attribute_ServiceDescription },\r
+\r
SERVICE_ATTRIBUTE_TABLE_TERMINATOR\r
};\r
#define SDP_UUID {BASE_80BIT_UUID, {0x00, 0x00, 0x00, 0x00, 0x00, 0x01}}\r
#define RFCOMM_UUID {BASE_80BIT_UUID, {0x00, 0x00, 0x00, 0x00, 0x00, 0x03}}\r
#define L2CAP_UUID {BASE_80BIT_UUID, {0x00, 0x00, 0x00, 0x00, 0x01, 0x00}}\r
- #define UPNP_UUID {BASE_80BIT_UUID, {0x00, 0x00, 0x00, 0x00, 0x00, 0x10}}\r
#define SDP_CLASS_UUID {BASE_80BIT_UUID, {0x00, 0x00, 0x00, 0x00, 0x10, 0x00}}\r
#define SP_CLASS_UUID {BASE_80BIT_UUID, {0x00, 0x00, 0x00, 0x00, 0x11, 0x01}}\r
- #define UPNP_CLASS_UUID {BASE_80BIT_UUID, {0x00, 0x00, 0x00, 0x00, 0x12, 0x00}}\r
+ #define PUBLICBROWSEGROUP_CLASS_UUID {BASE_80BIT_UUID, {0x00, 0x00, 0x00, 0x00, 0x10, 0x02}}\r
\r
#define SDP_ATTRIBUTE_ID_SERVICERECORDHANDLE 0x0000\r
#define SDP_ATTRIBUTE_ID_SERVICECLASSIDS 0x0001\r
#define SDP_ATTRIBUTE_ID_PROTOCOLDESCRIPTORLIST 0x0004\r
+ #define SDP_ATTRIBUTE_ID_BROWSEGROUPLIST 0x0005\r
+ #define SDP_ATTRIBUTE_ID_LANGUAGEBASEATTROFFSET 0x0006\r
#define SDP_ATTRIBUTE_ID_VERSION 0x0200\r
#define SDP_ATTRIBUTE_ID_SERVICENAME 0x0100\r
#define SDP_ATTRIBUTE_ID_SERVICEDESCRIPTION 0x0101\r
const void* Data; /**< Pointer to the attribute data, located in PROGMEM memory space */\r
} ServiceAttributeTable_t;\r
\r
- /** Structure for the association of service UUID values to attribute tables stored in FLASH. A table of these\r
- * structures can then be built up for each supported UUID service within the device.\r
- */\r
- typedef struct\r
- {\r
- UUID_t UUID; /**< UUID of a service supported by the device */\r
- const void* AttributeTable; /**< Pointer to the UUID's attribute table, located in PROGMEM memory space */\r
- } ServiceTable_t;\r
-\r
/** Structure for a list of Data Elements containing 8-bit integers, for service attributes requiring such lists. */\r
typedef struct\r
{\r
} Protocol;\r
} ItemProtocol_t;\r
\r
+ typedef struct\r
+ {\r
+ Item16Bit_t LanguageID;\r
+ Item16Bit_t EncodingID;\r
+ Item16Bit_t OffsetID;\r
+ } ItemLangID_t;\r
+ \r
/* External Variables: */\r
- extern const ServiceAttributeTable_t SDP_Attribute_Table[];\r
extern const ServiceAttributeTable_t RFCOMM_Attribute_Table[];\r
- extern const ServiceAttributeTable_t L2CAP_Attribute_Table[];\r
\r
#endif\r
#define INCLUDE_FROM_SERVICEDISCOVERYPROTOCOL_C
#include "ServiceDiscoveryProtocol.h"
-/** Master service table, listing all supported services (and their attribute tables) of the device, including
- * each service's UUID.
- */
-const ServiceTable_t SDP_Services_Table[] PROGMEM =
+/** Service attribute table list, containing a pointer to each service attribute table the device contains */
+const ServiceAttributeTable_t* SDP_Services_Table[] PROGMEM =
{
- { .UUID = SDP_UUID , .AttributeTable = SDP_Attribute_Table },
- { .UUID = RFCOMM_UUID, .AttributeTable = RFCOMM_Attribute_Table },
- { .UUID = L2CAP_UUID , .AttributeTable = L2CAP_Attribute_Table },
+ RFCOMM_Attribute_Table,
};
/** Base UUID value common to all standardized Bluetooth services */
uint16_t CurrentServiceRecordCount;
uint8_t ResponseData[100];
} ResponsePacket;
+
+ uint8_t AddedServiceHandles = 0;
/* Create a pointer to the buffer to indicate the current location for response data to be added */
void* CurrResponsePos = ResponsePacket.ResponseData;
-
- uint8_t AddedServiceHandles = 0;
- /* Search through the list of UUIDs one at a time looking for matching search Attributes */
- for (uint8_t CurrUUIDItem = 0; CurrUUIDItem < TotalUUIDs; CurrUUIDItem++)
+ /* Search through the global service list an item at a time */
+ for (uint8_t CurrTableItem = 0; CurrTableItem < (sizeof(SDP_Services_Table) / sizeof(void*)); CurrTableItem++)
{
- ServiceAttributeTable_t* AttributeTable;
+ /* Read in a pointer to the current UUID table entry's Attribute table */
+ ServiceAttributeTable_t* CurrAttributeTable = pgm_read_ptr(&SDP_Services_Table[CurrTableItem]);
- /* Retrieve the attribute table of the current search UUID from the global UUID table if it exists */
- if ((AttributeTable = SDP_GetAttributeTable(UUIDList[CurrUUIDItem])) == NULL)
+ if (!(SDP_SearchServiceTable(UUIDList, TotalUUIDs, CurrAttributeTable)))
continue;
-
- BT_SDP_DEBUG(2, " -- Found UUID %d in table", CurrUUIDItem);
+
+ BT_SDP_DEBUG(2, " -- Found search match in table");
/* Retrieve a PROGMEM pointer to the value of the service's record handle */
- const void* AttributeValue = SDP_GetAttributeValue(AttributeTable, SDP_ATTRIBUTE_ID_SERVICERECORDHANDLE);
+ const void* AttributeValue = SDP_GetAttributeValue(CurrAttributeTable, SDP_ATTRIBUTE_ID_SERVICERECORDHANDLE);
/* Copy over the service record handle to the response list */
uint8_t AttrHeaderSize;
uint16_t TotalResponseSize = 0;
/* Search through the global UUID list an item at a time */
- for (uint8_t CurrTableItem = 0; CurrTableItem < (sizeof(SDP_Services_Table) / sizeof(ServiceTable_t)); CurrTableItem++)
+ for (uint8_t CurrTableItem = 0; CurrTableItem < (sizeof(SDP_Services_Table) / sizeof(void*)); CurrTableItem++)
{
/* Read in a pointer to the current UUID table entry's Attribute table */
- ServiceAttributeTable_t* CurrAttributeTable = (ServiceAttributeTable_t*)pgm_read_word(&SDP_Services_Table[CurrTableItem].AttributeTable);
+ ServiceAttributeTable_t* CurrAttributeTable = pgm_read_ptr(&SDP_Services_Table[CurrTableItem]);
/* Retrieve a PROGMEM pointer to the value of the Service Record Handle */
const void* ServiceRecord = SDP_GetAttributeValue(CurrAttributeTable, SDP_ATTRIBUTE_ID_SERVICERECORDHANDLE);
/* Add the outer Data Element Sequence header for all of the retrieved Attributes */
uint16_t* TotalResponseSize = SDP_AddSequence16(&CurrResponsePos);
- /* Search through the list of UUIDs one at a time looking for matching search Attributes */
- for (uint8_t CurrUUIDItem = 0; CurrUUIDItem < TotalUUIDs; CurrUUIDItem++)
+ /* Search through the global service list an item at a time */
+ for (uint8_t CurrTableItem = 0; CurrTableItem < (sizeof(SDP_Services_Table) / sizeof(void*)); CurrTableItem++)
{
- ServiceAttributeTable_t* AttributeTable;
+ /* Read in a pointer to the current UUID table entry's Attribute table */
+ ServiceAttributeTable_t* CurrAttributeTable = pgm_read_ptr(&SDP_Services_Table[CurrTableItem]);
- /* Retrieve the attribute table of the current search UUID from the global UUID table if it exists */
- if ((AttributeTable = SDP_GetAttributeTable(UUIDList[CurrUUIDItem])) == NULL)
+ if (!(SDP_SearchServiceTable(UUIDList, TotalUUIDs, CurrAttributeTable)))
continue;
- BT_SDP_DEBUG(2, " -- Found UUID %d in table", CurrUUIDItem);
+ BT_SDP_DEBUG(2, " -- Found search match in table");
/* Add the listed attributes for the found UUID to the response */
- *TotalResponseSize += SDP_AddListedAttributesToResponse(AttributeTable, AttributeList, TotalAttributes,
+ *TotalResponseSize += SDP_AddListedAttributesToResponse(CurrAttributeTable, AttributeList, TotalAttributes,
&CurrResponsePos);
}
void* AttributeValue;
/* Look through the current service's attribute list, examining all the attributes */
- while ((AttributeValue = (void*)pgm_read_word(&AttributeTable->Data)) != NULL)
+ while ((AttributeValue = pgm_read_ptr(&AttributeTable->Data)) != NULL)
{
/* Get the current Attribute's ID from the current attribute table entry */
uint16_t CurrAttributeID = pgm_read_word(&AttributeTable->AttributeID);
void* CurrTableItemData;
/* Search through the current Attribute table, abort when the terminator item has been reached */
- while ((CurrTableItemData = (void*)pgm_read_word(&AttributeTable->Data)) != NULL)
+ while ((CurrTableItemData = pgm_read_ptr(&AttributeTable->Data)) != NULL)
{
/* Check if the current Attribute ID matches the search ID - if so return a pointer to it */
if (pgm_read_word(&AttributeTable->AttributeID) == AttributeID)
return NULL;
}
-/** Retrieves the Attribute table for the given UUID if it exists.
+/** Retrieves the Attribute table for the given UUID list if it exists.
*
- * \param[in] UUID UUID to search for
+ * \param[in] UUIDList List of UUIDs which must be matched within the service attribute table
+ * \param[in] TotalUUIDs Total number of UUIDs stored in the UUID list
+ * \param[in] CurrAttributeTable Pointer to the service attribute table to search through
*
- * \return Pointer to the UUID's associated Attribute table if found in the global UUID table, NULL otherwise
+ * \return True if all the UUIDs given in the UUID list appear in the given attribute table, false otherwise
*/
-static ServiceAttributeTable_t* SDP_GetAttributeTable(const uint8_t* const UUID)
+static bool SDP_SearchServiceTable(uint8_t UUIDList[][UUID_SIZE_BYTES], const uint8_t TotalUUIDs,
+ const ServiceAttributeTable_t* CurrAttributeTable)
{
- /* Search through the global UUID list an item at a time */
- for (uint8_t CurrTableItem = 0; CurrTableItem < (sizeof(SDP_Services_Table) / sizeof(ServiceTable_t)); CurrTableItem++)
+ bool UUIDMatch[TotalUUIDs];
+
+ /* Set all the match flags to false (not matched) before starting the search */
+ memset(UUIDMatch, false, sizeof(UUIDMatch));
+
+ const void* CurrAttribute;
+
+ /* Search through the current attribute table, checking each attribute value for UUID matches */
+ while ((CurrAttribute = pgm_read_ptr(&CurrAttributeTable->Data)) != NULL)
{
- /* Read in a pointer to the current UUID table entry's Attribute table */
- ServiceAttributeTable_t* CurrAttributeTable = (ServiceAttributeTable_t*)pgm_read_word(&SDP_Services_Table[CurrTableItem].AttributeTable);
+ SDP_CheckUUIDMatch(UUIDList, TotalUUIDs, UUIDMatch, CurrAttribute);
+ CurrAttributeTable++;
+ }
+
+ /* Determine how many UUID matches in the list we have found */
+ uint8_t UUIDMatches = 0;
+ for (uint8_t i = 0; i < TotalUUIDs; i++)
+ {
+ if (UUIDMatch[i])
+ UUIDMatches++;
+ }
- /* If the current table item's UUID matches the search UUID, return a pointer the table item's Attribute table */
- if (!(memcmp_P(UUID, &SDP_Services_Table[CurrTableItem].UUID, UUID_SIZE_BYTES)))
- return CurrAttributeTable;
-
- /* Retrieve the list of the service's Class UUIDs from its Attribute table */
- void* ClassUUIDs = SDP_GetAttributeValue(CurrAttributeTable, SDP_ATTRIBUTE_ID_SERVICECLASSIDS);
+ /* If all UUIDs have been matched to the current service, return true */
+ return (UUIDMatches == TotalUUIDs);
+}
+
+/** Recursively upwraps the given locally stored attribute (in PROGMEM space), searching for UUIDs to match against
+ * the given UUID list. As matches are found, they are indicated in the UUIDMatch flag list.
+ *
+ * \param[in] UUIDList List of UUIDs which must be matched within the service attribute table
+ * \param[in] TotalUUIDs Total number of UUIDs stored in the UUID list
+ * \param[in, out] UUIDMatch Array of flags indicating which UUIDs in the list have already been matched
+ * \param[in] CurrAttribute Pointer to the current attribute to search through
+ *
+ * \return True if all the UUIDs given in the UUID list appear in the given attribute table, false otherwise
+ */
+static void SDP_CheckUUIDMatch(uint8_t UUIDList[][UUID_SIZE_BYTES], const uint8_t TotalUUIDs, bool UUIDMatch[],
+ const void* CurrAttribute)
+{
+ uint8_t CurrAttributeType = (pgm_read_byte(CurrAttribute) & ~0x07);
+
+ /* Check the data type of the current attribute value - if UUID, compare, if Sequence, unwrap and recurse */
+ if (CurrAttributeType == SDP_DATATYPE_UUID)
+ {
+ /* Look for matches in the UUID list against the current attribute UUID value */
+ for (uint8_t i = 0; i < TotalUUIDs; i++)
+ {
+ if (!(UUIDMatch[i]) && !(memcmp_P(UUIDList[i], (CurrAttribute + 1), UUID_SIZE_BYTES)))
+ {
+ /* Indicate match found for the current attribute UUID and early-abort */
+ UUIDMatch[i] = true;
+ break;
+ }
+ }
+ }
+ else if (CurrAttributeType == SDP_DATATYPE_Sequence)
+ {
+ uint8_t SequenceHeaderSize;
+ uint16_t SequenceSize = SDP_GetLocalAttributeContainerSize(CurrAttribute, &SequenceHeaderSize);
- /* Go to the next UUID in the table if the current item does not have a list of Class UUIDs */
- if (ClassUUIDs == NULL)
- continue;
-
- /* Retrieve the size of the Class UUID list and skip past the header to the first Class UUID in the list */
- uint8_t ClassUUIDListHeaderSize;
- uint16_t ClassUUIDListSize = SDP_GetLocalAttributeContainerSize(ClassUUIDs, &ClassUUIDListHeaderSize);
- ClassUUIDs += ClassUUIDListHeaderSize;
+ CurrAttribute += SequenceHeaderSize;
- /* Check each class UUID in turn for a match */
- while (ClassUUIDListSize)
+ /* Recursively unwrap the sequence container, and re-search its contents for UUIDs */
+ while (SequenceSize)
{
- /* Current Service UUID's Class UUID list has a matching entry, return the Attribute table */
- if (!(memcmp_P(UUID, &((ItemUUID_t*)ClassUUIDs)->UUID, UUID_SIZE_BYTES)))
- return CurrAttributeTable;
-
- ClassUUIDListSize -= sizeof(ItemUUID_t);
- ClassUUIDs += sizeof(ItemUUID_t);
- }
- }
-
- return NULL;
+ uint8_t InnerHeaderSize;
+ uint16_t InnerSize = SDP_GetLocalAttributeContainerSize(CurrAttribute, &InnerHeaderSize);
+
+ SDP_CheckUUIDMatch(UUIDList, TotalUUIDs, UUIDMatch, CurrAttribute);
+
+ SequenceSize -= InnerHeaderSize + InnerSize;
+ CurrAttribute += InnerHeaderSize + InnerSize;
+ }
+ }
}
/** Reads in the collection of Attribute ranges from the input buffer's Data Element Sequence container, into the given
switch (SizeIndex)
{
case SDP_DATASIZE_Variable8Bit:
- ElementValueSize = SDP_ReadData8(DataElementHeader);
*ElementHeaderSize = (1 + sizeof(uint8_t));
+ ElementValueSize = SDP_ReadData8(DataElementHeader);
break;
case SDP_DATASIZE_Variable16Bit:
- ElementValueSize = SDP_ReadData16(DataElementHeader);
*ElementHeaderSize = (1 + sizeof(uint16_t));
+ ElementValueSize = SDP_ReadData16(DataElementHeader);
break;
case SDP_DATASIZE_Variable32Bit:
- ElementValueSize = SDP_ReadData32(DataElementHeader);
*ElementHeaderSize = (1 + sizeof(uint32_t));
+ ElementValueSize = SDP_ReadData32(DataElementHeader);
break;
default:
- ElementValueSize = (1 << SizeIndex);
*ElementHeaderSize = 1;
+ ElementValueSize = (1 << SizeIndex);
break;
}
/* 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_DEBUG_LEVEL 1
#define SDP_PDU_ERRORRESPONSE 0x01
#define SDP_PDU_SERVICESEARCHREQUEST 0x02
#define SDP_PDU_SERVICEATTRIBUTERESPONSE 0x05
#define SDP_PDU_SERVICESEARCHATTRIBUTEREQUEST 0x06
#define SDP_PDU_SERVICESEARCHATTRIBUTERESPONSE 0x07
+
+ #define pgm_read_ptr(x) (void*)pgm_read_word(x)
/* Enums: */
/** Data sizes for SDP Data Element headers, to indicate the size of the data contained in the element. When creating
const uint8_t TotalAttributes, void** const BufferPos);
static uint16_t SDP_AddAttributeToResponse(const uint16_t AttributeID, const void* AttributeValue, void** ResponseBuffer);
static void* SDP_GetAttributeValue(const ServiceAttributeTable_t* AttributeTable, const uint16_t AttributeID);
- static ServiceAttributeTable_t* SDP_GetAttributeTable(const uint8_t* const UUID);
+
+ static bool SDP_SearchServiceTable(uint8_t UUIDList[][UUID_SIZE_BYTES], const uint8_t TotalUUIDs,
+ const ServiceAttributeTable_t* CurrAttributeTable);
+ static void SDP_CheckUUIDMatch(uint8_t UUIDList[][UUID_SIZE_BYTES], const uint8_t TotalUUIDs, bool UUIDMatch[],
+ const void* CurrAttribute);
+
static uint8_t SDP_GetAttributeList(uint16_t AttributeList[][2], const void** const CurrentParameter);
static uint8_t SDP_GetUUIDList(uint8_t UUIDList[][UUID_SIZE_BYTES], const void** const CurrentParameter);
+
static uint32_t SDP_GetLocalAttributeContainerSize(const void* const AttributeData, uint8_t* const HeaderSize);
static uint32_t SDP_GetDataElementSize(const void** const AttributeHeader, uint8_t* const ElementHeaderSize);
#endif
"Assertion \"%s\" failed.\r\n"), \
__FILE__, __func__, __LINE__, #x); } \
}MACROE
-
+
/* Inline Functions: */
/** Function to reverse the individual bits in a byte - i.e. bit 7 is moved to bit 0, bit 6 to bit 1,
* etc.