The SDP UUID lists should be searched and ALL UUIDs matched for a record to be retrie...
authorDean Camera <dean@fourwalledcubicle.com>
Wed, 2 Jun 2010 07:05:34 +0000 (07:05 +0000)
committerDean Camera <dean@fourwalledcubicle.com>
Wed, 2 Jun 2010 07:05:34 +0000 (07:05 +0000)
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.

Demos/Host/Incomplete/BluetoothHost/Lib/SDPServices.c
Demos/Host/Incomplete/BluetoothHost/Lib/SDPServices.h
Demos/Host/Incomplete/BluetoothHost/Lib/ServiceDiscoveryProtocol.c
Demos/Host/Incomplete/BluetoothHost/Lib/ServiceDiscoveryProtocol.h
LUFA/Common/Common.h

index 96401c0..511e0b0 100644 (file)
 \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
@@ -147,123 +67,64 @@ const struct
                {\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
@@ -271,20 +132,22 @@ const struct
        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
index a11850d..654ed94 100644 (file)
                #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
index c6b3948..ffe2be0 100644 (file)
 #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 */
@@ -101,25 +97,25 @@ static void SDP_ProcessServiceSearch(const SDP_PDUHeader_t* const SDPHeader, Blu
                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;
@@ -197,10 +193,10 @@ static void SDP_ProcessServiceAttribute(const SDP_PDUHeader_t* const SDPHeader,
        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);
@@ -288,19 +284,19 @@ static void SDP_ProcessServiceSearchAttribute(const SDP_PDUHeader_t* const SDPHe
        /* 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);
        }
        
@@ -355,7 +351,7 @@ static uint16_t SDP_AddListedAttributesToResponse(const ServiceAttributeTable_t*
                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);
@@ -421,7 +417,7 @@ static void* SDP_GetAttributeValue(const ServiceAttributeTable_t* AttributeTable
        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)
@@ -433,49 +429,91 @@ static void* SDP_GetAttributeValue(const ServiceAttributeTable_t* AttributeTable
        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 
@@ -620,20 +658,20 @@ static uint32_t SDP_GetDataElementSize(const void** const DataElementHeader, uin
        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;
        }
        
index ec55b2f..50f4366 100644 (file)
@@ -50,7 +50,7 @@
                
        /* 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
@@ -59,6 +59,8 @@
                #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
index 76307d7..14473cd 100644 (file)
                                                                                                                                "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.