3 Copyright (C) Dean Camera, 2010.
5 dean [at] fourwalledcubicle [dot] com
6 www.fourwalledcubicle.com
10 Copyright 2010 Dean Camera (dean [at] fourwalledcubicle [dot] com)
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.
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
31 #define INCLUDE_FROM_SERVICEDISCOVERYPROTOCOL_C
32 #include "ServiceDiscoveryProtocol.h"
34 /** Service Discovery Protocol attribute, indicationg the service's name. */
40 } PROGMEM SDP_Attribute_Name
= {(SDP_DATATYPE_String
| 5), sizeof("SDP"), "SDP"};
42 /** Service Discovery Protocol attribute, indicationg the service's description. */
48 } PROGMEM SDP_Attribute_Description
= {(SDP_DATATYPE_String
| 5), sizeof("BT Service Discovery"), "BT Service Discovery"};
50 /** Service Discovery Protocol attribute, indicationg the service's availability. */
55 } PROGMEM SDP_Attribute_Availability
= {(SDP_DATATYPE_UnsignedInt
| 0), 0xFF};
61 } PROGMEM SDP_Attribute_LanguageOffset
= {(SDP_DATATYPE_UnsignedInt
| 1), 0x0100};
67 } PROGMEM SDP_Attribute_ServiceHandle
= {(SDP_DATATYPE_UnsignedInt
| 1), 0x0001};
73 ClassUUID_t UUIDList
[];
74 } PROGMEM SDP_Attribute_ServiceClassIDs
=
76 (SDP_DATATYPE_Sequence
| 5), (sizeof(ClassUUID_t
) * 1),
78 {.Header
= (SDP_DATATYPE_UUID
| 5), .Size
= UUID_SIZE_BYTES
, .UUID
= {BASE_96BIT_UUID
, 0x01, 0x00, 0x00, 0x00}}
82 /** Service Discovery Protocol attribute table, listing all supported attributes of the service. */
83 const ServiceAttributeTable_t SDP_Attribute_Table
[] PROGMEM
=
85 {.AttributeID
= SDP_ATTRIBUTE_ID_SERVICERECORDHANDLE
, .Data
= &SDP_Attribute_ServiceHandle
},
86 {.AttributeID
= SDP_ATTRIBUTE_ID_SERVICECLASSIDS
, .Data
= &SDP_Attribute_ServiceClassIDs
},
87 {.AttributeID
= SDP_ATTRIBUTE_ID_LANGIDOFFSET
, .Data
= &SDP_Attribute_LanguageOffset
},
88 {.AttributeID
= SDP_ATTRIBUTE_IDO_PROVIDER
| 0x0100, .Data
= &SDP_Attribute_Name
},
89 {.AttributeID
= SDP_ATTRIBUTE_IDO_DESCRIPTION
| 0x0100, .Data
= &SDP_Attribute_Description
},
91 SERVICE_ATTRIBUTE_TABLE_TERMINATOR
94 /** Master service table, listing all supported services (and their attribute tables) of the device, including
95 * each service's UUID.
97 const ServiceTable_t SDP_Services_Table
[] PROGMEM
=
99 { // 128-bit UUID for the SDP service
100 .UUID
= {BASE_96BIT_UUID
, 0x01, 0x00, 0x00, 0x00},
101 .AttributeTable
= SDP_Attribute_Table
,
104 { // 128-bit UUID for the RFCOMM service
105 .UUID
= {BASE_96BIT_UUID
, 0x03, 0x00, 0x00, 0x00},
106 .AttributeTable
= RFCOMM_Attribute_Table
,
111 /** Base UUID value common to all standardized Bluetooth services */
112 const uint8_t BaseUUID
[] PROGMEM
= {BASE_96BIT_UUID
, 0x00, 0x00, 0x00, 0x00};
115 /** Main Service Discovery Protocol packet processing routine. This function processes incomming SDP packets from
116 * a connected Bluetooth device, and sends back appropriate responses to allow other devices to determine the
117 * services the local device exposes.
119 * \param[in] Data Incomming packet data containing the SDP request
120 * \param[in] Channel Channel the request was issued to by the remote device
122 void ServiceDiscovery_ProcessPacket(void* Data
, Bluetooth_Channel_t
* Channel
)
124 SDP_PDUHeader_t
* SDPHeader
= (SDP_PDUHeader_t
*)Data
;
125 SDPHeader
->ParameterLength
= SwapEndian_16(SDPHeader
->ParameterLength
);
127 BT_SDP_DEBUG(1, "SDP Packet Received");
128 BT_SDP_DEBUG(2, "-- PDU ID: 0x%02X", SDPHeader
->PDU
);
129 BT_SDP_DEBUG(2, "-- Param Length: 0x%04X", SDPHeader
->ParameterLength
);
131 switch (SDPHeader
->PDU
)
133 case SDP_PDU_SERVICESEARCHREQUEST
:
134 ServiceDiscovery_ProcessServiceSearch(SDPHeader
, Channel
);
136 case SDP_PDU_SERVICEATTRIBUTEREQUEST
:
137 ServiceDiscovery_ProcessServiceAttribute(SDPHeader
, Channel
);
139 case SDP_PDU_SERVICESEARCHATTRIBUTEREQUEST
:
140 ServiceDiscovery_ProcessServiceSearchAttribute(SDPHeader
, Channel
);
145 static void ServiceDiscovery_ProcessServiceSearch(SDP_PDUHeader_t
* SDPHeader
, Bluetooth_Channel_t
* Channel
)
147 BT_SDP_DEBUG(1, "<< Service Search");
150 static void ServiceDiscovery_ProcessServiceAttribute(SDP_PDUHeader_t
* SDPHeader
, Bluetooth_Channel_t
* Channel
)
152 BT_SDP_DEBUG(1, "<< Service Attribute");
155 static void ServiceDiscovery_ProcessServiceSearchAttribute(SDP_PDUHeader_t
* SDPHeader
, Bluetooth_Channel_t
* Channel
)
157 const void* CurrentParameter
= ((void*)SDPHeader
+ sizeof(SDP_PDUHeader_t
));
159 BT_SDP_DEBUG(1, "<< Service Search Attribute");
161 uint8_t UUIDList
[12][UUID_SIZE_BYTES
];
162 uint8_t TotalUUIDs
= ServiceDiscovery_GetUUIDList(UUIDList
, &CurrentParameter
);
163 BT_SDP_DEBUG(2, "-- Total UUIDs: %d", TotalUUIDs
);
165 uint16_t MaxAttributeSize
= ServiceDiscovery_Read16BitParameter(&CurrentParameter
);
166 BT_SDP_DEBUG(2, "-- Max Return Attribute Bytes: 0x%04X", MaxAttributeSize
);
168 uint16_t AttributeList
[15][2];
169 uint8_t TotalAttributes
= ServiceDiscovery_GetAttributeList(AttributeList
, &CurrentParameter
);
170 BT_SDP_DEBUG(2, "-- Total Attributes: %d", TotalAttributes
);
174 SDP_PDUHeader_t SDPHeader
;
175 uint16_t AttributeListByteCount
;
176 uint8_t ResponseData
[100];
179 uint8_t* CurrResponsePos
= ResponsePacket
.ResponseData
;
181 if (MaxAttributeSize
> sizeof(ResponsePacket
.ResponseData
))
182 MaxAttributeSize
= sizeof(ResponsePacket
.ResponseData
);
184 uint16_t* TotalResponseSize
= ServiceDiscovery_AddDataElementHeader(&CurrResponsePos
, SDP_DATATYPE_Sequence
);
185 for (uint8_t CurrUUIDItem
= 0; CurrUUIDItem
< TotalUUIDs
; CurrUUIDItem
++)
187 ServiceAttributeTable_t
* AttributeTable
= ServiceDiscovery_GetAttributeTable(UUIDList
[CurrUUIDItem
]);
189 if (AttributeTable
== NULL
)
192 uint16_t* CurrentUUIDResponseSize
= ServiceDiscovery_AddDataElementHeader(&CurrResponsePos
, SDP_DATATYPE_Sequence
);
193 for (uint8_t CurrAttribute
= 0; CurrAttribute
< TotalAttributes
; CurrAttribute
++)
195 uint16_t* AttributeIDRange
= AttributeList
[CurrAttribute
];
197 for (uint32_t CurrAttributeID
= AttributeIDRange
[0]; CurrAttributeID
<= AttributeIDRange
[1]; CurrAttributeID
++)
199 const void* AttributeValue
= ServiceDiscovery_GetAttributeValue(AttributeTable
, CurrAttributeID
);
201 if (AttributeValue
== NULL
)
204 uint32_t AttributeValueLength
= ServiceDiscovery_GetLocalAttributeSize(AttributeValue
);
206 BT_SDP_DEBUG(2, " -- Add Attribute 0x%04X", CurrAttributeID
);
208 *((uint8_t*)CurrResponsePos
) = (1 | SDP_DATATYPE_UnsignedInt
);
209 CurrResponsePos
+= sizeof(uint8_t);
210 *((uint16_t*)CurrResponsePos
) = CurrAttributeID
;
211 CurrResponsePos
+= sizeof(uint16_t);
212 memcpy_P(CurrResponsePos
, AttributeValue
, AttributeValueLength
);
213 CurrResponsePos
+= AttributeValueLength
;
215 *CurrentUUIDResponseSize
+= sizeof(uint8_t) + sizeof(uint16_t) + AttributeValueLength
;
218 *TotalResponseSize
+= 3 + *CurrentUUIDResponseSize
;
222 ResponsePacket
.AttributeListByteCount
= (*TotalResponseSize
+ 3);
223 ResponsePacket
.SDPHeader
.PDU
= SDP_PDU_SERVICESEARCHATTRIBUTERESPONSE
;
224 ResponsePacket
.SDPHeader
.TransactionID
= SDPHeader
->TransactionID
;
225 ResponsePacket
.SDPHeader
.ParameterLength
= (ResponsePacket
.AttributeListByteCount
+ sizeof(ResponsePacket
.AttributeListByteCount
));
227 BT_SDP_DEBUG(1, ">> Service Search Attribute Response");
228 BT_SDP_DEBUG(2, "-- Total Parameter Length: 0x%04X", ResponsePacket
.SDPHeader
.ParameterLength
);
230 Bluetooth_SendPacket(&ResponsePacket
, (sizeof(ResponsePacket
.SDPHeader
) + ResponsePacket
.SDPHeader
.ParameterLength
),
234 static void* ServiceDiscovery_GetAttributeValue(ServiceAttributeTable_t
* AttributeTable
, uint16_t AttributeID
)
236 void* CurrTableItemData
;
237 while ((CurrTableItemData
= (void*)pgm_read_word(&AttributeTable
->Data
)) != NULL
)
239 if (pgm_read_word(&AttributeTable
->AttributeID
) == AttributeID
)
240 return CurrTableItemData
;
248 static ServiceAttributeTable_t
* ServiceDiscovery_GetAttributeTable(uint8_t* UUID
)
250 for (uint8_t CurrTableItem
= 0; CurrTableItem
< (sizeof(SDP_Services_Table
) / sizeof(ServiceTable_t
)); CurrTableItem
++)
252 if (!(memcmp_P(UUID
, SDP_Services_Table
[CurrTableItem
].UUID
, UUID_SIZE_BYTES
)))
253 return (ServiceAttributeTable_t
*)pgm_read_word(&SDP_Services_Table
[CurrTableItem
].AttributeTable
);
259 static uint8_t ServiceDiscovery_GetAttributeList(uint16_t AttributeList
[][2], const void** CurrentParameter
)
261 uint8_t ElementHeaderSize
;
262 uint8_t TotalAttributes
= 0;
264 uint16_t AttributeIDListLength
= ServiceDiscovery_GetDataElementSize(CurrentParameter
, &ElementHeaderSize
);
265 BT_SDP_DEBUG(2, "-- Total Attribute Length: 0x%04X", AttributeIDListLength
);
266 while (AttributeIDListLength
)
268 uint8_t AttributeLength
= ServiceDiscovery_GetDataElementSize(CurrentParameter
, &ElementHeaderSize
);
270 memcpy(&AttributeList
[TotalAttributes
][0], *CurrentParameter
, AttributeLength
);
272 if (AttributeLength
== 2)
273 memcpy(&AttributeList
[TotalAttributes
][1], *CurrentParameter
, 2);
275 BT_SDP_DEBUG(2, "-- Attribute: 0x%04X-0x%04X", AttributeList
[TotalAttributes
][0], AttributeList
[TotalAttributes
][1]);
279 AttributeIDListLength
-= (AttributeLength
+ ElementHeaderSize
);
280 *CurrentParameter
+= AttributeLength
;
283 return TotalAttributes
;
286 static uint8_t ServiceDiscovery_GetUUIDList(uint8_t UUIDList
[][UUID_SIZE_BYTES
], const void** CurrentParameter
)
288 uint8_t ElementHeaderSize
;
289 uint8_t TotalUUIDs
= 0;
291 uint16_t ServicePatternLength
= ServiceDiscovery_GetDataElementSize(CurrentParameter
, &ElementHeaderSize
);
292 BT_SDP_DEBUG(2, "-- Total UUID Length: 0x%04X", ServicePatternLength
);
293 while (ServicePatternLength
)
295 uint8_t* CurrentUUID
= UUIDList
[TotalUUIDs
++];
296 uint8_t UUIDLength
= ServiceDiscovery_GetDataElementSize(CurrentParameter
, &ElementHeaderSize
);
298 memcpy_P(CurrentUUID
, BaseUUID
, sizeof(BaseUUID
));
299 memcpy(&CurrentUUID
[(UUIDLength
<= 4) ?
(UUID_SIZE_BYTES
- 4) : 0], *CurrentParameter
, UUIDLength
);
301 BT_SDP_DEBUG(2, "-- UUID (%d): 0x%02X%02X%02X%02X-%02X%02X-%02X%02X-%02X%02X-%02X%02X%02X%02X%02X%02X",
303 CurrentUUID
[15], CurrentUUID
[14], CurrentUUID
[13], CurrentUUID
[12],
304 CurrentUUID
[11], CurrentUUID
[10], CurrentUUID
[9], CurrentUUID
[8],
305 CurrentUUID
[7], CurrentUUID
[6], CurrentUUID
[5], CurrentUUID
[4],
306 CurrentUUID
[3], CurrentUUID
[2], CurrentUUID
[1], CurrentUUID
[0]);
308 ServicePatternLength
-= (UUIDLength
+ ElementHeaderSize
);
309 *CurrentParameter
+= UUIDLength
;
315 static uint32_t ServiceDiscovery_GetLocalAttributeSize(const void* AttributeData
)
317 /* Fetch the size of the Data Element structure from the header */
318 uint8_t SizeIndex
= (pgm_read_byte(AttributeData
) & 0x07);
320 /* Convert the Data Element size index into a size in bytes */
324 return (1 + sizeof(uint8_t)) + pgm_read_byte(AttributeData
+ 1);
326 return (1 + sizeof(uint16_t)) + pgm_read_word(AttributeData
+ 1);
328 return (1 + sizeof(uint32_t)) + pgm_read_dword(AttributeData
+ 1);
330 return (1 + (1 << SizeIndex
));
336 static uint32_t ServiceDiscovery_GetDataElementSize(const void** DataElementHeader
, uint8_t* ElementHeaderSize
)
338 /* Fetch the size of the Data Element structure from the header, increment the current buffer pos */
339 uint8_t SizeIndex
= (*((uint8_t*)*DataElementHeader
) & 0x07);
340 *DataElementHeader
+= sizeof(uint8_t);
342 uint32_t ElementValue
;
344 /* Convert the Data Element size index into a size in bytes */
348 ElementValue
= *((uint8_t*)*DataElementHeader
);
349 *DataElementHeader
+= sizeof(uint8_t);
350 *ElementHeaderSize
= (1 + sizeof(uint8_t));
353 ElementValue
= *((uint16_t*)*DataElementHeader
);
354 *DataElementHeader
+= sizeof(uint16_t);
355 *ElementHeaderSize
= (1 + sizeof(uint16_t));
358 ElementValue
= *((uint32_t*)*DataElementHeader
);
359 *DataElementHeader
+= sizeof(uint32_t);
360 *ElementHeaderSize
= (1 + sizeof(uint32_t));
363 ElementValue
= (1 << SizeIndex
);
364 *ElementHeaderSize
= 1;