c6b394819477c5393fd2414f303bf0d9e1851d63
[pub/USBasp.git] / Demos / Host / Incomplete / BluetoothHost / Lib / ServiceDiscoveryProtocol.c
1 /*
2 LUFA Library
3 Copyright (C) Dean Camera, 2010.
4
5 dean [at] fourwalledcubicle [dot] com
6 www.fourwalledcubicle.com
7 */
8
9 /*
10 Copyright 2010 Dean Camera (dean [at] fourwalledcubicle [dot] com)
11
12 Permission to use, copy, modify, distribute, and sell this
13 software and its documentation for any purpose is hereby granted
14 without fee, provided that the above copyright notice appear in
15 all copies and that both that the copyright notice and this
16 permission notice and warranty disclaimer appear in supporting
17 documentation, and that the name of the author not be used in
18 advertising or publicity pertaining to distribution of the
19 software without specific, written prior permission.
20
21 The author disclaim all warranties with regard to this
22 software, including all implied warranties of merchantability
23 and fitness. In no event shall the author be liable for any
24 special, indirect or consequential damages or any damages
25 whatsoever resulting from loss of use, data or profits, whether
26 in an action of contract, negligence or other tortious action,
27 arising out of or in connection with the use or performance of
28 this software.
29 */
30
31 #define INCLUDE_FROM_SERVICEDISCOVERYPROTOCOL_C
32 #include "ServiceDiscoveryProtocol.h"
33
34 /** Master service table, listing all supported services (and their attribute tables) of the device, including
35 * each service's UUID.
36 */
37 const ServiceTable_t SDP_Services_Table[] PROGMEM =
38 {
39 { .UUID = SDP_UUID , .AttributeTable = SDP_Attribute_Table },
40 { .UUID = RFCOMM_UUID, .AttributeTable = RFCOMM_Attribute_Table },
41 { .UUID = L2CAP_UUID , .AttributeTable = L2CAP_Attribute_Table },
42 };
43
44 /** Base UUID value common to all standardized Bluetooth services */
45 const UUID_t BaseUUID PROGMEM = {BASE_80BIT_UUID, {0, 0, 0, 0, 0, 0}};
46
47 /** Main Service Discovery Protocol packet processing routine. This function processes incomming SDP packets from
48 * a connected Bluetooth device, and sends back appropriate responses to allow other devices to determine the
49 * services the local device exposes.
50 *
51 * \param[in] Data Incomming packet data containing the SDP request
52 * \param[in] Channel Channel the request was issued to by the remote device
53 */
54 void SDP_ProcessPacket(void* Data, Bluetooth_Channel_t* const Channel)
55 {
56 SDP_PDUHeader_t* SDPHeader = (SDP_PDUHeader_t*)Data;
57 SDPHeader->ParameterLength = SwapEndian_16(SDPHeader->ParameterLength);
58
59 BT_SDP_DEBUG(1, "SDP Packet Received");
60 BT_SDP_DEBUG(2, "-- PDU ID: 0x%02X", SDPHeader->PDU);
61 BT_SDP_DEBUG(2, "-- Param Length: 0x%04X", SDPHeader->ParameterLength);
62
63 switch (SDPHeader->PDU)
64 {
65 case SDP_PDU_SERVICESEARCHREQUEST:
66 SDP_ProcessServiceSearch(SDPHeader, Channel);
67 break;
68 case SDP_PDU_SERVICEATTRIBUTEREQUEST:
69 SDP_ProcessServiceAttribute(SDPHeader, Channel);
70 break;
71 case SDP_PDU_SERVICESEARCHATTRIBUTEREQUEST:
72 SDP_ProcessServiceSearchAttribute(SDPHeader, Channel);
73 break;
74 }
75 }
76
77 /** Internal processing routine for SDP Service Search Requests.
78 *
79 * \param[in] SDPHeader Pointer to the start of the issued SDP request
80 * \param[in] Channel Pointer to the Bluetooth channel structure the request was issued to
81 */
82 static void SDP_ProcessServiceSearch(const SDP_PDUHeader_t* const SDPHeader, Bluetooth_Channel_t* const Channel)
83 {
84 const void* CurrentParameter = ((void*)SDPHeader + sizeof(SDP_PDUHeader_t));
85
86 BT_SDP_DEBUG(1, "<< Service Search");
87
88 /* Retrieve the list of search UUIDs from the request */
89 uint8_t UUIDList[12][UUID_SIZE_BYTES];
90 uint8_t TotalUUIDs = SDP_GetUUIDList(UUIDList, &CurrentParameter);
91 BT_SDP_DEBUG(2, "-- Total UUIDs: %d", TotalUUIDs);
92
93 /* Retrieve the maximum service record reponse count from the request */
94 uint16_t MaxServiceRecordCount = SDP_ReadData16(&CurrentParameter);
95 BT_SDP_DEBUG(2, "-- Max Return Service Count: 0x%04X", MaxServiceRecordCount);
96
97 struct
98 {
99 SDP_PDUHeader_t SDPHeader;
100 uint16_t TotalServiceRecordCount;
101 uint16_t CurrentServiceRecordCount;
102 uint8_t ResponseData[100];
103 } ResponsePacket;
104
105 /* Create a pointer to the buffer to indicate the current location for response data to be added */
106 void* CurrResponsePos = ResponsePacket.ResponseData;
107
108 uint8_t AddedServiceHandles = 0;
109
110 /* Search through the list of UUIDs one at a time looking for matching search Attributes */
111 for (uint8_t CurrUUIDItem = 0; CurrUUIDItem < TotalUUIDs; CurrUUIDItem++)
112 {
113 ServiceAttributeTable_t* AttributeTable;
114
115 /* Retrieve the attribute table of the current search UUID from the global UUID table if it exists */
116 if ((AttributeTable = SDP_GetAttributeTable(UUIDList[CurrUUIDItem])) == NULL)
117 continue;
118
119 BT_SDP_DEBUG(2, " -- Found UUID %d in table", CurrUUIDItem);
120
121 /* Retrieve a PROGMEM pointer to the value of the service's record handle */
122 const void* AttributeValue = SDP_GetAttributeValue(AttributeTable, SDP_ATTRIBUTE_ID_SERVICERECORDHANDLE);
123
124 /* Copy over the service record handle to the response list */
125 uint8_t AttrHeaderSize;
126 SDP_GetLocalAttributeContainerSize(AttributeValue, &AttrHeaderSize);
127 memcpy_P(CurrResponsePos, AttributeValue + AttrHeaderSize, sizeof(uint32_t));
128 CurrResponsePos += AttrHeaderSize + sizeof(uint32_t);
129
130 /* Increment the total number of service records added to the list */
131 AddedServiceHandles++;
132 }
133
134 /* Continuation state - always zero */
135 SDP_WriteData8(&CurrResponsePos, 0);
136
137 /* Fill out the service record count values in the returned packet */
138 ResponsePacket.TotalServiceRecordCount = SwapEndian_16(AddedServiceHandles);
139 ResponsePacket.CurrentServiceRecordCount = ResponsePacket.TotalServiceRecordCount;
140
141 /* Calculate the total parameter length that is to be sent, including the fixed return parameters, the created service
142 handle list and the SDP continuation state */
143 uint16_t ParamLength = (ResponsePacket.CurrentServiceRecordCount << 2) +
144 sizeof(ResponsePacket.CurrentServiceRecordCount) +
145 sizeof(ResponsePacket.TotalServiceRecordCount) +
146 sizeof(uint8_t);
147
148 /* Fill in the response packet's header */
149 ResponsePacket.SDPHeader.PDU = SDP_PDU_SERVICESEARCHRESPONSE;
150 ResponsePacket.SDPHeader.TransactionID = SDPHeader->TransactionID;
151 ResponsePacket.SDPHeader.ParameterLength = SwapEndian_16(ParamLength);
152
153 BT_SDP_DEBUG(1, ">> Service Search Response");
154
155 /* Send the completed response packet to the sender */
156 Bluetooth_SendPacket(&ResponsePacket, (sizeof(ResponsePacket.SDPHeader) + ParamLength), Channel);
157 }
158
159 /** Internal processing routine for SDP Service Attribute Requests.
160 *
161 * \param[in] SDPHeader Pointer to the start of the issued SDP request
162 * \param[in] Channel Pointer to the Bluetooth channel structure the request was issued to
163 */
164 static void SDP_ProcessServiceAttribute(const SDP_PDUHeader_t* const SDPHeader, Bluetooth_Channel_t* const Channel)
165 {
166 const void* CurrentParameter = ((void*)SDPHeader + sizeof(SDP_PDUHeader_t));
167
168 BT_SDP_DEBUG(1, "<< Service Attribute");
169
170 /* Retrieve the service handle whose attributes are to be examined */
171 uint32_t ServiceHandle = SDP_ReadData32(&CurrentParameter);
172 BT_SDP_DEBUG(2, "-- Service Handle: 0x%08lX", ServiceHandle);
173
174 /* Retrieve the maximum Attribute reponse size from the request */
175 uint16_t MaxAttributeSize = SDP_ReadData16(&CurrentParameter);
176 BT_SDP_DEBUG(2, "-- Max Return Attribute Bytes: 0x%04X", MaxAttributeSize);
177
178 /* Retrieve the list of Attributes from the request */
179 uint16_t AttributeList[15][2];
180 uint8_t TotalAttributes = SDP_GetAttributeList(AttributeList, &CurrentParameter);
181 BT_SDP_DEBUG(2, "-- Total Attributes: %d", TotalAttributes);
182
183 struct
184 {
185 SDP_PDUHeader_t SDPHeader;
186 uint16_t AttributeListByteCount;
187 uint8_t ResponseData[100];
188 } ResponsePacket;
189
190 /* Create a pointer to the buffer to indicate the current location for response data to be added */
191 void* CurrResponsePos = ResponsePacket.ResponseData;
192
193 /* Clamp the maximum attribute size to the size of the allocated buffer */
194 if (MaxAttributeSize > sizeof(ResponsePacket.ResponseData))
195 MaxAttributeSize = sizeof(ResponsePacket.ResponseData);
196
197 uint16_t TotalResponseSize = 0;
198
199 /* Search through the global UUID list an item at a time */
200 for (uint8_t CurrTableItem = 0; CurrTableItem < (sizeof(SDP_Services_Table) / sizeof(ServiceTable_t)); CurrTableItem++)
201 {
202 /* Read in a pointer to the current UUID table entry's Attribute table */
203 ServiceAttributeTable_t* CurrAttributeTable = (ServiceAttributeTable_t*)pgm_read_word(&SDP_Services_Table[CurrTableItem].AttributeTable);
204
205 /* Retrieve a PROGMEM pointer to the value of the Service Record Handle */
206 const void* ServiceRecord = SDP_GetAttributeValue(CurrAttributeTable, SDP_ATTRIBUTE_ID_SERVICERECORDHANDLE);
207
208 /* Get the size of the header for the Service Record Handle */
209 uint8_t AttrHeaderSize;
210 SDP_GetLocalAttributeContainerSize(ServiceRecord, &AttrHeaderSize);
211
212 /* Retrieve the endian-swapped service handle of the current service being examined */
213 uint32_t CurrServiceHandle = SwapEndian_32(pgm_read_dword(ServiceRecord + AttrHeaderSize));
214
215 /* Check if the current service in the service table has the requested service handle */
216 if (ServiceHandle == CurrServiceHandle)
217 {
218 /* Add the listed attributes for the found UUID to the response */
219 TotalResponseSize = SDP_AddListedAttributesToResponse(CurrAttributeTable, AttributeList, TotalAttributes,
220 &CurrResponsePos);
221
222 /* Requested service found, abort the search through the service table */
223 break;
224 }
225 }
226
227 /* Continuation state - always zero */
228 SDP_WriteData8(&CurrResponsePos, 0);
229
230 /* Set the total response list size to the size of the outer container plus its header size and continuation state */
231 ResponsePacket.AttributeListByteCount = SwapEndian_16(TotalResponseSize);
232
233 /* Calculate the total parameter length that is to be sent, including the fixed return parameters, the created attribute
234 value list and the SDP continuation state */
235 uint16_t ParamLength = (sizeof(ResponsePacket.AttributeListByteCount) + TotalResponseSize + sizeof(uint8_t));
236
237 /* Fill in the response packet's header */
238 ResponsePacket.SDPHeader.PDU = SDP_PDU_SERVICEATTRIBUTERESPONSE;
239 ResponsePacket.SDPHeader.TransactionID = SDPHeader->TransactionID;
240 ResponsePacket.SDPHeader.ParameterLength = SwapEndian_16(ParamLength);
241
242 BT_SDP_DEBUG(1, ">> Service Attribute Response");
243 BT_SDP_DEBUG(2, "-- Param Len 0x%04X", ParamLength);
244
245 /* Send the completed response packet to the sender */
246 Bluetooth_SendPacket(&ResponsePacket, (sizeof(ResponsePacket.SDPHeader) + ParamLength), Channel);
247 }
248
249 /** Internal processing routine for SDP Service Search Attribute Requests.
250 *
251 * \param[in] SDPHeader Pointer to the start of the issued SDP request
252 * \param[in] Channel Pointer to the Bluetooth channel structure the request was issued to
253 */
254 static void SDP_ProcessServiceSearchAttribute(const SDP_PDUHeader_t* const SDPHeader, Bluetooth_Channel_t* const Channel)
255 {
256 const void* CurrentParameter = ((void*)SDPHeader + sizeof(SDP_PDUHeader_t));
257
258 BT_SDP_DEBUG(1, "<< Service Search Attribute");
259
260 /* Retrieve the list of search UUIDs from the request */
261 uint8_t UUIDList[12][UUID_SIZE_BYTES];
262 uint8_t TotalUUIDs = SDP_GetUUIDList(UUIDList, &CurrentParameter);
263 BT_SDP_DEBUG(2, "-- Total UUIDs: %d", TotalUUIDs);
264
265 /* Retrieve the maximum Attribute reponse size from the request */
266 uint16_t MaxAttributeSize = SDP_ReadData16(&CurrentParameter);
267 BT_SDP_DEBUG(2, "-- Max Return Attribute Bytes: 0x%04X", MaxAttributeSize);
268
269 /* Retrieve the list of Attributes from the request */
270 uint16_t AttributeList[15][2];
271 uint8_t TotalAttributes = SDP_GetAttributeList(AttributeList, &CurrentParameter);
272 BT_SDP_DEBUG(2, "-- Total Attributes: %d", TotalAttributes);
273
274 struct
275 {
276 SDP_PDUHeader_t SDPHeader;
277 uint16_t AttributeListByteCount;
278 uint8_t ResponseData[100];
279 } ResponsePacket;
280
281 /* Create a pointer to the buffer to indicate the current location for response data to be added */
282 void* CurrResponsePos = ResponsePacket.ResponseData;
283
284 /* Clamp the maximum attribute size to the size of the allocated buffer */
285 if (MaxAttributeSize > sizeof(ResponsePacket.ResponseData))
286 MaxAttributeSize = sizeof(ResponsePacket.ResponseData);
287
288 /* Add the outer Data Element Sequence header for all of the retrieved Attributes */
289 uint16_t* TotalResponseSize = SDP_AddSequence16(&CurrResponsePos);
290
291 /* Search through the list of UUIDs one at a time looking for matching search Attributes */
292 for (uint8_t CurrUUIDItem = 0; CurrUUIDItem < TotalUUIDs; CurrUUIDItem++)
293 {
294 ServiceAttributeTable_t* AttributeTable;
295
296 /* Retrieve the attribute table of the current search UUID from the global UUID table if it exists */
297 if ((AttributeTable = SDP_GetAttributeTable(UUIDList[CurrUUIDItem])) == NULL)
298 continue;
299
300 BT_SDP_DEBUG(2, " -- Found UUID %d in table", CurrUUIDItem);
301
302 /* Add the listed attributes for the found UUID to the response */
303 *TotalResponseSize += SDP_AddListedAttributesToResponse(AttributeTable, AttributeList, TotalAttributes,
304 &CurrResponsePos);
305 }
306
307 /* Continuation state - always zero */
308 SDP_WriteData8(&CurrResponsePos, 0);
309
310 /* Set the total response list size to the size of the outer container plus its header size and continuation state */
311 ResponsePacket.AttributeListByteCount = SwapEndian_16(3 + *TotalResponseSize);
312
313 /* Calculate the total parameter length that is to be sent, including the fixed return parameters, the created attribute
314 value list and the SDP continuation state */
315 uint16_t ParamLength = (sizeof(ResponsePacket.AttributeListByteCount) +
316 (3 + *TotalResponseSize) +
317 sizeof(uint8_t));
318
319 /* Flip the endianness of the container's size */
320 *TotalResponseSize = SwapEndian_16(*TotalResponseSize);
321
322 /* Fill in the response packet's header */
323 ResponsePacket.SDPHeader.PDU = SDP_PDU_SERVICESEARCHATTRIBUTERESPONSE;
324 ResponsePacket.SDPHeader.TransactionID = SDPHeader->TransactionID;
325 ResponsePacket.SDPHeader.ParameterLength = SwapEndian_16(ParamLength);
326
327 BT_SDP_DEBUG(1, ">> Service Search Attribute Response");
328 BT_SDP_DEBUG(2, "-- Param Len 0x%04X", ParamLength);
329
330 /* Send the completed response packet to the sender */
331 Bluetooth_SendPacket(&ResponsePacket, (sizeof(ResponsePacket.SDPHeader) + ParamLength), Channel);
332 }
333
334 /** Adds all the Attributes in the given service table to the response that appear in the Attribute table.
335 *
336 * \param[in] AttributeTable Pointer to an Attribute table for the service to examine
337 * \param[in] AttributeList Pointer to a list of Attribute ranges
338 * \param[in] TotalAttributes Number of Attributes stored in the Attribute list
339 * \param[out] BufferPos Pointer to the output buffer position where the retrieved attributes are to be stored
340 *
341 * \return Number of bytes added to the output buffer
342 */
343 static uint16_t SDP_AddListedAttributesToResponse(const ServiceAttributeTable_t* AttributeTable, uint16_t AttributeList[][2],
344 const uint8_t TotalAttributes, void** const BufferPos)
345 {
346 uint16_t TotalResponseSize;
347
348 /* Add an inner Data Element Sequence header for the current services's found Attributes */
349 uint16_t* AttributeListSize = SDP_AddSequence16(BufferPos);
350
351 /* Search through the list of Attributes one at a time looking for values in the current UUID's Attribute table */
352 for (uint8_t CurrAttribute = 0; CurrAttribute < TotalAttributes; CurrAttribute++)
353 {
354 uint16_t* AttributeIDRange = AttributeList[CurrAttribute];
355 void* AttributeValue;
356
357 /* Look through the current service's attribute list, examining all the attributes */
358 while ((AttributeValue = (void*)pgm_read_word(&AttributeTable->Data)) != NULL)
359 {
360 /* Get the current Attribute's ID from the current attribute table entry */
361 uint16_t CurrAttributeID = pgm_read_word(&AttributeTable->AttributeID);
362
363 /* Check if the current Attribute's ID is within the current Attribute range */
364 if ((CurrAttributeID >= AttributeIDRange[0]) && (CurrAttributeID <= AttributeIDRange[1]))
365 {
366 /* Increment the current UUID's returned Attribute container size by the number of added bytes */
367 *AttributeListSize += SDP_AddAttributeToResponse(CurrAttributeID, AttributeValue, BufferPos);
368 }
369
370 AttributeTable++;
371 }
372 }
373
374 /* Record the total number of added bytes to the buffer */
375 TotalResponseSize = 3 + *AttributeListSize;
376
377 /* Fix endianness of the added attribute data element sequence */
378 *AttributeListSize = SwapEndian_16(*AttributeListSize);
379
380 return TotalResponseSize;
381 }
382
383 /** Adds the given attribute ID and value to the reponse buffer, and advances the response buffer pointer past the added data.
384 *
385 * \param[in] AttributeID Attribute ID to add to the response buffer
386 * \param[in] AttributeValue Pointer to the start of the Attribute's value, located in PROGMEM
387 * \param[in, out] ResponseBuffer Pointer to a buffer where the Attribute and Attribute Value is to be added
388 *
389 * \return Number of bytes added to the response buffer
390 */
391 static uint16_t SDP_AddAttributeToResponse(const uint16_t AttributeID, const void* AttributeValue, void** ResponseBuffer)
392 {
393 /* Retrieve the size of the attribute value from its container header */
394 uint8_t AttributeHeaderLength;
395 uint16_t AttributeValueLength = SDP_GetLocalAttributeContainerSize(AttributeValue, &AttributeHeaderLength);
396
397 BT_SDP_DEBUG(2, " -- Add Attribute (0x%04X) 0x%04X", (AttributeHeaderLength + AttributeValueLength), AttributeID);
398
399 /* Add a Data Element header to the response for the Attribute ID */
400 SDP_WriteData8(ResponseBuffer, (SDP_DATATYPE_UnsignedInt | SDP_DATASIZE_16Bit));
401
402 /* Add the Attribute ID to the created Data Element */
403 SDP_WriteData16(ResponseBuffer, AttributeID);
404
405 /* Copy over the Attribute value Data Element container to the response */
406 memcpy_P(*ResponseBuffer, AttributeValue, AttributeHeaderLength + AttributeValueLength);
407 *ResponseBuffer += AttributeHeaderLength + AttributeValueLength;
408
409 return (sizeof(uint8_t) + sizeof(uint16_t) + AttributeHeaderLength + AttributeValueLength);
410 }
411
412 /** Retrieves a pointer to the value of the given Attribute ID from the given Attribute table.
413 *
414 * \param[in] AttributeTable Pointer to the Attribute table to search in
415 * \param[in] AttributeID Attribute ID to search for within the table
416 *
417 * \return Pointer to the start of the Attribute's value if found within the table, NULL otherwise
418 */
419 static void* SDP_GetAttributeValue(const ServiceAttributeTable_t* AttributeTable, const uint16_t AttributeID)
420 {
421 void* CurrTableItemData;
422
423 /* Search through the current Attribute table, abort when the terminator item has been reached */
424 while ((CurrTableItemData = (void*)pgm_read_word(&AttributeTable->Data)) != NULL)
425 {
426 /* Check if the current Attribute ID matches the search ID - if so return a pointer to it */
427 if (pgm_read_word(&AttributeTable->AttributeID) == AttributeID)
428 return CurrTableItemData;
429
430 AttributeTable++;
431 }
432
433 return NULL;
434 }
435
436 /** Retrieves the Attribute table for the given UUID if it exists.
437 *
438 * \param[in] UUID UUID to search for
439 *
440 * \return Pointer to the UUID's associated Attribute table if found in the global UUID table, NULL otherwise
441 */
442 static ServiceAttributeTable_t* SDP_GetAttributeTable(const uint8_t* const UUID)
443 {
444 /* Search through the global UUID list an item at a time */
445 for (uint8_t CurrTableItem = 0; CurrTableItem < (sizeof(SDP_Services_Table) / sizeof(ServiceTable_t)); CurrTableItem++)
446 {
447 /* Read in a pointer to the current UUID table entry's Attribute table */
448 ServiceAttributeTable_t* CurrAttributeTable = (ServiceAttributeTable_t*)pgm_read_word(&SDP_Services_Table[CurrTableItem].AttributeTable);
449
450 /* If the current table item's UUID matches the search UUID, return a pointer the table item's Attribute table */
451 if (!(memcmp_P(UUID, &SDP_Services_Table[CurrTableItem].UUID, UUID_SIZE_BYTES)))
452 return CurrAttributeTable;
453
454 /* Retrieve the list of the service's Class UUIDs from its Attribute table */
455 void* ClassUUIDs = SDP_GetAttributeValue(CurrAttributeTable, SDP_ATTRIBUTE_ID_SERVICECLASSIDS);
456
457 /* Go to the next UUID in the table if the current item does not have a list of Class UUIDs */
458 if (ClassUUIDs == NULL)
459 continue;
460
461 /* Retrieve the size of the Class UUID list and skip past the header to the first Class UUID in the list */
462 uint8_t ClassUUIDListHeaderSize;
463 uint16_t ClassUUIDListSize = SDP_GetLocalAttributeContainerSize(ClassUUIDs, &ClassUUIDListHeaderSize);
464 ClassUUIDs += ClassUUIDListHeaderSize;
465
466 /* Check each class UUID in turn for a match */
467 while (ClassUUIDListSize)
468 {
469 /* Current Service UUID's Class UUID list has a matching entry, return the Attribute table */
470 if (!(memcmp_P(UUID, &((ItemUUID_t*)ClassUUIDs)->UUID, UUID_SIZE_BYTES)))
471 return CurrAttributeTable;
472
473 ClassUUIDListSize -= sizeof(ItemUUID_t);
474 ClassUUIDs += sizeof(ItemUUID_t);
475 }
476 }
477
478 return NULL;
479 }
480
481 /** Reads in the collection of Attribute ranges from the input buffer's Data Element Sequence container, into the given
482 * Attribute list for later use. Once complete, the input buffer pointer is advanced to the end of the Attribute container.
483 *
484 * \param[out] AttributeList Pointer to a buffer where the list of Attribute ranges are to be stored
485 * \param[in] CurrentParameter Pointer to a Buffer containing a Data Element Sequence of Attribute and Attribute Range elements
486 *
487 * \return Total number of Attribute ranges stored in the Data Element Sequence
488 */
489 static uint8_t SDP_GetAttributeList(uint16_t AttributeList[][2], const void** const CurrentParameter)
490 {
491 uint8_t ElementHeaderSize;
492 uint8_t TotalAttributes = 0;
493
494 /* Retrieve the total size of the Attribute container, and unwrap the outer Data Element Sequence container */
495 uint16_t AttributeIDListLength = SDP_GetDataElementSize(CurrentParameter, &ElementHeaderSize);
496 BT_SDP_DEBUG(2, "-- Total Attribute Length: 0x%04X", AttributeIDListLength);
497 while (AttributeIDListLength)
498 {
499 /* Retrieve the size of the next Attribute in the container and get a pointer to the next free Attribute element in the list */
500 uint16_t* CurrentAttributeRange = AttributeList[TotalAttributes++];
501 uint8_t AttributeLength = SDP_GetDataElementSize(CurrentParameter, &ElementHeaderSize);
502
503 /* Copy over the starting Attribute ID and (if it the current element is a range) the ending Attribute ID */
504 memcpy(&CurrentAttributeRange[0], *CurrentParameter, AttributeLength);
505
506 /* If the element is not an Attribute Range, copy over the starting ID to the ending ID to make a range of 1 */
507 if (AttributeLength == 2)
508 CurrentAttributeRange[1] = CurrentAttributeRange[0];
509
510 /* Swap the endianness of the attribute range values */
511 CurrentAttributeRange[0] = SwapEndian_16(CurrentAttributeRange[0]);
512 CurrentAttributeRange[1] = SwapEndian_16(CurrentAttributeRange[1]);
513
514 BT_SDP_DEBUG(2, "-- Attribute: 0x%04X-0x%04X", CurrentAttributeRange[0], CurrentAttributeRange[1]);
515
516 AttributeIDListLength -= (AttributeLength + ElementHeaderSize);
517 *CurrentParameter += AttributeLength;
518 }
519
520 return TotalAttributes;
521 }
522
523 /** Reads in the collection of UUIDs from the input buffer's Data Element Sequence container, into the given
524 * UUID list for later use. Once complete, the input buffer pointer is advanced to the end of the UUID container.
525 *
526 * \param[out] UUIDList Pointer to a buffer where the list of UUIDs are to be stored
527 * \param[in] CurrentParameter Pointer to a Buffer containing a Data Element Sequence of UUID elements
528 *
529 * \return Total number of UUIDs stored in the Data Element Sequence
530 */
531 static uint8_t SDP_GetUUIDList(uint8_t UUIDList[][UUID_SIZE_BYTES], const void** const CurrentParameter)
532 {
533 uint8_t ElementHeaderSize;
534 uint8_t TotalUUIDs = 0;
535
536 /* Retrieve the total size of the UUID container, and unwrap the outer Data Element Sequence container */
537 uint16_t ServicePatternLength = SDP_GetDataElementSize(CurrentParameter, &ElementHeaderSize);
538 BT_SDP_DEBUG(2, "-- Total UUID Length: 0x%04X", ServicePatternLength);
539 while (ServicePatternLength)
540 {
541 /* Retrieve the size of the next UUID in the container and get a pointer to the next free UUID element in the list */
542 uint8_t* CurrentUUID = UUIDList[TotalUUIDs++];
543 uint8_t UUIDLength = SDP_GetDataElementSize(CurrentParameter, &ElementHeaderSize);
544
545 /* Copy over the base UUID value to the free UUID slot in the list */
546 memcpy_P(CurrentUUID, &BaseUUID, sizeof(BaseUUID));
547
548 /* Copy over UUID from the container to the free slot */
549 memcpy(&CurrentUUID[UUID_SIZE_BYTES - UUIDLength], *CurrentParameter, UUIDLength);
550
551 BT_SDP_DEBUG(2, "-- UUID (%d): %02X%02X%02X%02X-%02X%02X-%02X%02X-%02X%02X-%02X%02X%02X%02X%02X%02X",
552 UUIDLength,
553 CurrentUUID[0], CurrentUUID[1], CurrentUUID[2], CurrentUUID[3],
554 CurrentUUID[4], CurrentUUID[5],
555 CurrentUUID[6], CurrentUUID[7],
556 CurrentUUID[8], CurrentUUID[9],
557 CurrentUUID[10], CurrentUUID[11], CurrentUUID[12], CurrentUUID[13], CurrentUUID[14], CurrentUUID[15]);
558
559 ServicePatternLength -= (UUIDLength + ElementHeaderSize);
560 *CurrentParameter += UUIDLength;
561 }
562
563 return TotalUUIDs;
564 }
565
566 /** Retrieves the total size of the given locally stored (in PROGMEM) attribute Data Element container.
567 *
568 * \param[in] AttributeData Pointer to the start of the Attribute container, located in PROGMEM
569 * \param[out] HeaderSize Pointer to a location where the header size of the data element is to be stored
570 *
571 * \return Size in bytes of the entire attribute container, including the header
572 */
573 static uint32_t SDP_GetLocalAttributeContainerSize(const void* const AttributeData, uint8_t* const HeaderSize)
574 {
575 /* Fetch the size of the Data Element structure from the header */
576 uint8_t SizeIndex = (pgm_read_byte(AttributeData) & 0x07);
577
578 uint32_t ElementValueSize;
579
580 /* Convert the Data Element size index into a size in bytes */
581 switch (SizeIndex)
582 {
583 case SDP_DATASIZE_Variable8Bit:
584 *HeaderSize = (1 + sizeof(uint8_t));
585 ElementValueSize = pgm_read_byte(AttributeData + 1);
586 break;
587 case SDP_DATASIZE_Variable16Bit:
588 *HeaderSize = (1 + sizeof(uint16_t));
589 ElementValueSize = SwapEndian_16(pgm_read_word(AttributeData + 1));
590 break;
591 case SDP_DATASIZE_Variable32Bit:
592 *HeaderSize = (1 + sizeof(uint32_t));
593 ElementValueSize = SwapEndian_32(pgm_read_dword(AttributeData + 1));
594 break;
595 default:
596 *HeaderSize = 1;
597 ElementValueSize = (1 << SizeIndex);
598 break;
599 }
600
601 return ElementValueSize;
602 }
603
604 /** Retrieves the size of a Data Element container from the current input buffer, and advances the input buffer
605 * pointer to the start of the Data Element's contents.
606 *
607 * \param[in, out] DataElementHeader Pointer to the start of a Data Element header
608 * \param[out] ElementHeaderSize Size in bytes of the header that was skipped
609 *
610 * \return Size in bytes of the Data Element container's contents, minus the header
611 */
612 static uint32_t SDP_GetDataElementSize(const void** const DataElementHeader, uint8_t* const ElementHeaderSize)
613 {
614 /* Fetch the size of the Data Element structure from the header, increment the current buffer pos */
615 uint8_t SizeIndex = (SDP_ReadData8(DataElementHeader) & 0x07);
616
617 uint32_t ElementValueSize;
618
619 /* Convert the Data Element size index into a size in bytes */
620 switch (SizeIndex)
621 {
622 case SDP_DATASIZE_Variable8Bit:
623 ElementValueSize = SDP_ReadData8(DataElementHeader);
624 *ElementHeaderSize = (1 + sizeof(uint8_t));
625 break;
626 case SDP_DATASIZE_Variable16Bit:
627 ElementValueSize = SDP_ReadData16(DataElementHeader);
628 *ElementHeaderSize = (1 + sizeof(uint16_t));
629 break;
630 case SDP_DATASIZE_Variable32Bit:
631 ElementValueSize = SDP_ReadData32(DataElementHeader);
632 *ElementHeaderSize = (1 + sizeof(uint32_t));
633 break;
634 default:
635 ElementValueSize = (1 << SizeIndex);
636 *ElementHeaderSize = 1;
637 break;
638 }
639
640 return ElementValueSize;
641 }