Service Discovery ServiceSearchAttribute requests require the response to be grouped...
[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 /** Service Discovery Protocol attribute, indicationg the service's name. */
35 SERVICE_ATTRIBUTE_TEXT(SDP_Attribute_Name, "SDP");
36 /** Service Discovery Protocol attribute, indicationg the service's description. */
37 SERVICE_ATTRIBUTE_TEXT(SDP_Attribute_Description, "BT Service Discovery");
38 /** Service Discovery Protocol attribute, indicationg the service's availability. */
39 SERVICE_ATTRIBUTE_LEN8(SDP_Attribute_Availability, SDP_DATATYPE_UnsignedInt, 1, {0xFF});
40 /** Service Discovery Protocol attribute table, listing all supported attributes of the service. */
41 const ServiceAttributeTable_t SDP_Attribute_Table[] PROGMEM =
42 {
43 {.AttributeID = SDP_ATTRIBUTE_NAME , .Data = &SDP_Attribute_Name},
44 {.AttributeID = SDP_ATTRIBUTE_DESCRIPTION , .Data = &SDP_Attribute_Description},
45 {.AttributeID = SDP_ATTRIBUTE_AVAILABILITY, .Data = &SDP_Attribute_Availability},
46 SERVICE_ATTRIBUTE_TABLE_TERMINATOR
47 };
48
49 /** RFCOMM Service attribute, indicationg the service's name. */
50 SERVICE_ATTRIBUTE_TEXT(RFCOMM_Attribute_Name, "RFCOMM");
51 /** RFCOMM Service attribute, indicationg the service's description. */
52 SERVICE_ATTRIBUTE_TEXT(RFCOMM_Attribute_Description, "Virtual Serial");
53 /** RFCOMM Service attribute, indicationg the service's availability. */
54 SERVICE_ATTRIBUTE_LEN8(RFCOMM_Attribute_Availability, SDP_DATATYPE_UnsignedInt, 1, {0xFF});
55 /** RFCOMM Service attribute table, listing all supported attributes of the service. */
56 const ServiceAttributeTable_t RFCOMM_Attribute_Table[] PROGMEM =
57 {
58 {.AttributeID = SDP_ATTRIBUTE_NAME , .Data = &RFCOMM_Attribute_Name},
59 {.AttributeID = SDP_ATTRIBUTE_DESCRIPTION , .Data = &RFCOMM_Attribute_Description},
60 {.AttributeID = SDP_ATTRIBUTE_AVAILABILITY, .Data = &RFCOMM_Attribute_Availability},
61 SERVICE_ATTRIBUTE_TABLE_TERMINATOR
62 };
63
64 /** Master service table, listing all supported services (and their attribute tables) of the device, including
65 * each service's UUID.
66 */
67 const ServiceTable_t SDP_Services_Table[] PROGMEM =
68 {
69 { // 128-bit UUID for the SDP service
70 .UUID = {BASE_96BIT_UUID, 0x01, 0x00, 0x00, 0x00},
71 .AttributeTable = &SDP_Attribute_Table,
72 },
73 { // 128-bit UUID for the RFCOMM service
74 .UUID = {BASE_96BIT_UUID, 0x03, 0x00, 0x00, 0x00},
75 .AttributeTable = &RFCOMM_Attribute_Table,
76 },
77 };
78
79 /** Base UUID value common to all standardized Bluetooth services */
80 const uint8_t BaseUUID[] PROGMEM = {BASE_96BIT_UUID, 0x00, 0x00, 0x00, 0x00};
81
82
83 /** Main Service Discovery Protocol packet processing routine. This function processes incomming SDP packets from
84 * a connected Bluetooth device, and sends back appropriate responses to allow other devices to determine the
85 * services the local device exposes.
86 *
87 * \param[in] Data Incomming packet data containing the SDP request
88 * \param[in] Channel Channel the request was issued to by the remote device
89 */
90 void ServiceDiscovery_ProcessPacket(void* Data, Bluetooth_Channel_t* Channel)
91 {
92 SDP_PDUHeader_t* SDPHeader = (SDP_PDUHeader_t*)Data;
93 SDPHeader->ParameterLength = SwapEndian_16(SDPHeader->ParameterLength);
94
95 BT_SDP_DEBUG(1, "SDP Packet Received");
96 BT_SDP_DEBUG(2, "-- PDU ID: 0x%02X", SDPHeader->PDU);
97 BT_SDP_DEBUG(2, "-- Param Length: 0x%04X", SDPHeader->ParameterLength);
98
99 switch (SDPHeader->PDU)
100 {
101 case SDP_PDU_SERVICESEARCHREQUEST:
102 ServiceDiscovery_ProcessServiceSearch(SDPHeader, Channel);
103 break;
104 case SDP_PDU_SERVICEATTRIBUTEREQUEST:
105 ServiceDiscovery_ProcessServiceAttribute(SDPHeader, Channel);
106 break;
107 case SDP_PDU_SERVICESEARCHATTRIBUTEREQUEST:
108 ServiceDiscovery_ProcessServiceSearchAttribute(SDPHeader, Channel);
109 break;
110 }
111 }
112
113 static void ServiceDiscovery_ProcessServiceSearch(SDP_PDUHeader_t* SDPHeader, Bluetooth_Channel_t* Channel)
114 {
115 BT_SDP_DEBUG(1, "<< Service Search");
116 }
117
118 static void ServiceDiscovery_ProcessServiceAttribute(SDP_PDUHeader_t* SDPHeader, Bluetooth_Channel_t* Channel)
119 {
120 BT_SDP_DEBUG(1, "<< Service Attribute");
121 }
122
123 static void ServiceDiscovery_ProcessServiceSearchAttribute(SDP_PDUHeader_t* SDPHeader, Bluetooth_Channel_t* Channel)
124 {
125 const void* CurrentParameter = ((void*)SDPHeader + sizeof(SDP_PDUHeader_t));
126
127 BT_SDP_DEBUG(1, "<< Service Search Attribute");
128
129 uint8_t UUIDList[12][UUID_SIZE_BYTES];
130 uint8_t TotalUUIDs = ServiceDiscovery_GetUUIDList(UUIDList, &CurrentParameter);
131 BT_SDP_DEBUG(2, "-- Total UUIDs: %d", TotalUUIDs);
132
133 uint16_t MaxAttributeSize = ServiceDiscovery_Read16BitParameter(&CurrentParameter);
134 BT_SDP_DEBUG(2, "-- Max Return Attribute Bytes: 0x%04X", MaxAttributeSize);
135
136 uint16_t AttributeList[20][2];
137 uint8_t TotalAttributes = ServiceDiscovery_GetAttributeList(AttributeList, &CurrentParameter);
138 BT_SDP_DEBUG(2, "-- Total Attributes: %d", TotalAttributes);
139
140 struct
141 {
142 SDP_PDUHeader_t SDPHeader;
143 uint16_t AttributeListByteCount;
144 uint8_t ResponseData[100];
145 } ResponsePacket;
146
147 uint8_t* CurrResponsePos = ResponsePacket.ResponseData;
148
149 if (MaxAttributeSize > sizeof(ResponsePacket.ResponseData))
150 MaxAttributeSize = sizeof(ResponsePacket.ResponseData);
151
152 uint16_t* TotalResponseSize = ServiceDiscovery_AddDataElementHeader(&CurrResponsePos, SDP_DATATYPE_Sequence);
153 for (uint8_t CurrUUIDItem = 0; CurrUUIDItem < TotalUUIDs; CurrUUIDItem++)
154 {
155 ServiceAttributeTable_t* AttributeTable = ServiceDiscovery_GetAttributeTable(UUIDList[CurrUUIDItem]);
156
157 if (AttributeTable == NULL)
158 continue;
159
160 uint16_t* CurrentUUIDResponseSize = ServiceDiscovery_AddDataElementHeader(&CurrResponsePos, SDP_DATATYPE_Sequence);
161 *TotalResponseSize += sizeof(ServiceAttributeData16Bit_t);
162 for (uint8_t CurrAttribute = 0; CurrAttribute < TotalAttributes; CurrAttribute++)
163 {
164 uint16_t* AttributeIDRange = AttributeList[CurrAttribute];
165
166 for (uint16_t CurrAttributeID = AttributeIDRange[0]; CurrAttributeID < AttributeIDRange[1]; CurrAttributeID++)
167 {
168 void* AttributeValue = ServiceDiscovery_GetAttributeValue(AttributeTable, CurrAttributeID);
169
170 if (AttributeValue == NULL)
171 continue;
172
173 BT_SDP_DEBUG(2, "GUID + ATTRIBUTE FOUND");
174 }
175 }
176 }
177
178 ResponsePacket.AttributeListByteCount = (*TotalResponseSize + sizeof(ServiceAttributeData16Bit_t));
179 ResponsePacket.SDPHeader.PDU = SDP_PDU_SERVICESEARCHATTRIBUTERESPONSE;
180 ResponsePacket.SDPHeader.TransactionID = SDPHeader->TransactionID;
181 ResponsePacket.SDPHeader.ParameterLength = (ResponsePacket.AttributeListByteCount + sizeof(ResponsePacket.AttributeListByteCount));
182
183 Bluetooth_SendPacket(&ResponsePacket, (sizeof(ResponsePacket.SDPHeader) + ResponsePacket.SDPHeader.ParameterLength),
184 Channel);
185 }
186
187 static void* ServiceDiscovery_GetAttributeValue(ServiceAttributeTable_t* AttributeTable, uint16_t AttributeID)
188 {
189 while ((void*)pgm_read_word(&AttributeTable->Data) != NULL)
190 {
191 if (pgm_read_word(&AttributeTable->AttributeID) == AttributeID)
192 return &AttributeTable->Data;
193
194 AttributeTable++;
195 }
196
197 return NULL;
198 }
199
200 static ServiceAttributeTable_t* ServiceDiscovery_GetAttributeTable(uint8_t* UUID)
201 {
202 for (uint8_t CurrTableItem = 0; CurrTableItem < (sizeof(SDP_Services_Table) / sizeof(ServiceTable_t)); CurrTableItem++)
203 {
204 if (!(memcmp_P(UUID, SDP_Services_Table[CurrTableItem].UUID, UUID_SIZE_BYTES)))
205 return (ServiceAttributeTable_t*)pgm_read_word(&SDP_Services_Table[CurrTableItem].AttributeTable);
206 }
207
208 return NULL;
209 }
210
211 static uint8_t ServiceDiscovery_GetAttributeList(uint16_t AttributeList[][2], const void** CurrentParameter)
212 {
213 uint8_t ElementHeaderSize;
214 uint8_t TotalAttributes = 0;
215
216 uint16_t AttributeIDListLength = ServiceDiscovery_GetDataElementSize(CurrentParameter, &ElementHeaderSize);
217 BT_SDP_DEBUG(2, "-- Total Attribute Length: 0x%04X", AttributeIDListLength);
218 while (AttributeIDListLength)
219 {
220 uint8_t AttributeLength = ServiceDiscovery_GetDataElementSize(CurrentParameter, &ElementHeaderSize);
221
222 memcpy(&AttributeList[TotalAttributes][0], *CurrentParameter, AttributeLength);
223
224 if (AttributeLength == 2)
225 memcpy(&AttributeList[TotalAttributes][1], *CurrentParameter, 2);
226
227 BT_SDP_DEBUG(2, "-- Attribute: 0x%04X-0x%04X", AttributeList[TotalAttributes][0], AttributeList[TotalAttributes][1]);
228
229 TotalAttributes++;
230
231 AttributeIDListLength -= (AttributeLength + ElementHeaderSize);
232 *CurrentParameter += AttributeLength;
233 }
234
235 return TotalAttributes;
236 }
237
238 static uint8_t ServiceDiscovery_GetUUIDList(uint8_t UUIDList[][UUID_SIZE_BYTES], const void** CurrentParameter)
239 {
240 uint8_t ElementHeaderSize;
241 uint8_t TotalUUIDs = 0;
242
243 uint16_t ServicePatternLength = ServiceDiscovery_GetDataElementSize(CurrentParameter, &ElementHeaderSize);
244 BT_SDP_DEBUG(2, "-- Total UUID Length: 0x%04X", ServicePatternLength);
245 while (ServicePatternLength)
246 {
247 uint8_t* CurrentUUID = UUIDList[TotalUUIDs++];
248 uint8_t UUIDLength = ServiceDiscovery_GetDataElementSize(CurrentParameter, &ElementHeaderSize);
249
250 memcpy_P(CurrentUUID, BaseUUID, sizeof(BaseUUID));
251 memcpy(&CurrentUUID[(UUIDLength <= 4) ? (UUID_SIZE_BYTES - 4) : 0], *CurrentParameter, UUIDLength);
252
253 BT_SDP_DEBUG(2, "-- UUID (%d): 0x%02X%02X%02X%02X-%02X%02X-%02X%02X-%02X%02X-%02X%02X%02X%02X%02X%02X",
254 UUIDLength,
255 CurrentUUID[15], CurrentUUID[14], CurrentUUID[13], CurrentUUID[12],
256 CurrentUUID[11], CurrentUUID[10], CurrentUUID[9], CurrentUUID[8],
257 CurrentUUID[7], CurrentUUID[6], CurrentUUID[5], CurrentUUID[4],
258 CurrentUUID[3], CurrentUUID[2], CurrentUUID[1], CurrentUUID[0]);
259
260 ServicePatternLength -= (UUIDLength + ElementHeaderSize);
261 *CurrentParameter += UUIDLength;
262 }
263
264 return TotalUUIDs;
265 }
266
267 static uint32_t ServiceDiscovery_GetDataElementSize(const void** DataElementHeader, uint8_t* ElementHeaderSize)
268 {
269 /* Fetch the size of the Data Element structure from the header, increment the current buffer pos */
270 uint8_t SizeIndex = (*((uint8_t*)*DataElementHeader) & 0x07);
271 *DataElementHeader += sizeof(uint8_t);
272
273 uint32_t ElementValue;
274
275 /* Convert the Data Element size index into a size in bytes */
276 switch (SizeIndex)
277 {
278 case 5:
279 ElementValue = *((uint8_t*)*DataElementHeader);
280 *DataElementHeader += sizeof(uint8_t);
281 *ElementHeaderSize = (1 + sizeof(uint8_t));
282 break;
283 case 6:
284 ElementValue = *((uint16_t*)*DataElementHeader);
285 *DataElementHeader += sizeof(uint16_t);
286 *ElementHeaderSize = (1 + sizeof(uint16_t));
287 break;
288 case 7:
289 ElementValue = *((uint32_t*)*DataElementHeader);
290 *DataElementHeader += sizeof(uint32_t);
291 *ElementHeaderSize = (1 + sizeof(uint32_t));
292 break;
293 default:
294 ElementValue = (1 << SizeIndex);
295 *ElementHeaderSize = 1;
296 break;
297 }
298
299 return ElementValue;
300 }