mbed base bard check program for BlueTooth USB dongle module (3 switches, 6 leds, I2C LCD, A/D)
Fork of BTstack by
BTstack/sdp_util.c@3:7b7d1273e2d5, 2016-10-17 (annotated)
- Committer:
- tamaki
- Date:
- Mon Oct 17 00:25:18 2016 +0000
- Revision:
- 3:7b7d1273e2d5
- Parent:
- 0:1ed23ab1345f
mbed base bard check program
; for BlueTooth USB dongle module
; (3 switches, 6 leds, I2C LCD, A/D)
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
va009039 | 0:1ed23ab1345f | 1 | /* |
va009039 | 0:1ed23ab1345f | 2 | * Copyright (C) 2009-2012 by Matthias Ringwald |
va009039 | 0:1ed23ab1345f | 3 | * |
va009039 | 0:1ed23ab1345f | 4 | * Redistribution and use in source and binary forms, with or without |
va009039 | 0:1ed23ab1345f | 5 | * modification, are permitted provided that the following conditions |
va009039 | 0:1ed23ab1345f | 6 | * are met: |
va009039 | 0:1ed23ab1345f | 7 | * |
va009039 | 0:1ed23ab1345f | 8 | * 1. Redistributions of source code must retain the above copyright |
va009039 | 0:1ed23ab1345f | 9 | * notice, this list of conditions and the following disclaimer. |
va009039 | 0:1ed23ab1345f | 10 | * 2. Redistributions in binary form must reproduce the above copyright |
va009039 | 0:1ed23ab1345f | 11 | * notice, this list of conditions and the following disclaimer in the |
va009039 | 0:1ed23ab1345f | 12 | * documentation and/or other materials provided with the distribution. |
va009039 | 0:1ed23ab1345f | 13 | * 3. Neither the name of the copyright holders nor the names of |
va009039 | 0:1ed23ab1345f | 14 | * contributors may be used to endorse or promote products derived |
va009039 | 0:1ed23ab1345f | 15 | * from this software without specific prior written permission. |
va009039 | 0:1ed23ab1345f | 16 | * 4. Any redistribution, use, or modification is done solely for |
va009039 | 0:1ed23ab1345f | 17 | * personal benefit and not for any commercial purpose or for |
va009039 | 0:1ed23ab1345f | 18 | * monetary gain. |
va009039 | 0:1ed23ab1345f | 19 | * |
va009039 | 0:1ed23ab1345f | 20 | * THIS SOFTWARE IS PROVIDED BY MATTHIAS RINGWALD AND CONTRIBUTORS |
va009039 | 0:1ed23ab1345f | 21 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
va009039 | 0:1ed23ab1345f | 22 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS |
va009039 | 0:1ed23ab1345f | 23 | * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MATTHIAS |
va009039 | 0:1ed23ab1345f | 24 | * RINGWALD OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, |
va009039 | 0:1ed23ab1345f | 25 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, |
va009039 | 0:1ed23ab1345f | 26 | * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS |
va009039 | 0:1ed23ab1345f | 27 | * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED |
va009039 | 0:1ed23ab1345f | 28 | * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, |
va009039 | 0:1ed23ab1345f | 29 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF |
va009039 | 0:1ed23ab1345f | 30 | * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
va009039 | 0:1ed23ab1345f | 31 | * SUCH DAMAGE. |
va009039 | 0:1ed23ab1345f | 32 | * |
va009039 | 0:1ed23ab1345f | 33 | * Please inquire about commercial licensing options at btstack@ringwald.ch |
va009039 | 0:1ed23ab1345f | 34 | * |
va009039 | 0:1ed23ab1345f | 35 | */ |
va009039 | 0:1ed23ab1345f | 36 | |
va009039 | 0:1ed23ab1345f | 37 | /* |
va009039 | 0:1ed23ab1345f | 38 | * sdp_util.c |
va009039 | 0:1ed23ab1345f | 39 | */ |
va009039 | 0:1ed23ab1345f | 40 | |
va009039 | 0:1ed23ab1345f | 41 | #include <btstack/sdp_util.h> |
va009039 | 0:1ed23ab1345f | 42 | #include <btstack/utils.h> |
va009039 | 0:1ed23ab1345f | 43 | |
va009039 | 0:1ed23ab1345f | 44 | #include <stdio.h> |
va009039 | 0:1ed23ab1345f | 45 | #include <stdlib.h> |
va009039 | 0:1ed23ab1345f | 46 | #include <string.h> |
va009039 | 0:1ed23ab1345f | 47 | #include <stdint.h> |
va009039 | 0:1ed23ab1345f | 48 | #include <inttypes.h> // PRIx32 |
va009039 | 0:1ed23ab1345f | 49 | |
va009039 | 0:1ed23ab1345f | 50 | // workaround for missing PRIx32 on mspgcc (16-bit MCU) |
va009039 | 0:1ed23ab1345f | 51 | #ifndef PRIx32 |
va009039 | 0:1ed23ab1345f | 52 | #warning Using own: #define PRIx32 "lx" |
va009039 | 0:1ed23ab1345f | 53 | #define PRIx32 "lx" |
va009039 | 0:1ed23ab1345f | 54 | #endif |
va009039 | 0:1ed23ab1345f | 55 | |
va009039 | 0:1ed23ab1345f | 56 | // date element type names |
va009039 | 0:1ed23ab1345f | 57 | const char * const type_names[] = { "NIL", "UINT", "INT", "UUID", "STRING", "BOOL", "DES", "DEA", "URL"}; |
va009039 | 0:1ed23ab1345f | 58 | |
va009039 | 0:1ed23ab1345f | 59 | // Bluetooth Base UUID: 00000000-0000-1000-8000- 00805F9B34FB |
va009039 | 0:1ed23ab1345f | 60 | const uint8_t sdp_bluetooth_base_uuid[] = { 0x00, 0x00, 0x00, 0x00, /* - */ 0x00, 0x00, /* - */ 0x10, 0x00, /* - */ |
va009039 | 0:1ed23ab1345f | 61 | 0x80, 0x00, /* - */ 0x00, 0x80, 0x5F, 0x9B, 0x34, 0xFB }; |
va009039 | 0:1ed23ab1345f | 62 | |
va009039 | 0:1ed23ab1345f | 63 | void sdp_normalize_uuid(uint8_t *uuid, uint32_t shortUUID){ |
va009039 | 0:1ed23ab1345f | 64 | memcpy(uuid, sdp_bluetooth_base_uuid, 16); |
va009039 | 0:1ed23ab1345f | 65 | net_store_32(uuid, 0, shortUUID); |
va009039 | 0:1ed23ab1345f | 66 | } |
va009039 | 0:1ed23ab1345f | 67 | |
va009039 | 0:1ed23ab1345f | 68 | // MARK: DataElement getter |
va009039 | 0:1ed23ab1345f | 69 | de_size_t de_get_size_type(uint8_t *header){ |
va009039 | 0:1ed23ab1345f | 70 | return (de_size_t) (header[0] & 7); |
va009039 | 0:1ed23ab1345f | 71 | } |
va009039 | 0:1ed23ab1345f | 72 | |
va009039 | 0:1ed23ab1345f | 73 | de_type_t de_get_element_type(uint8_t *header){ |
va009039 | 0:1ed23ab1345f | 74 | return (de_type_t) (header[0] >> 3); |
va009039 | 0:1ed23ab1345f | 75 | } |
va009039 | 0:1ed23ab1345f | 76 | |
va009039 | 0:1ed23ab1345f | 77 | int de_get_header_size(uint8_t * header){ |
va009039 | 0:1ed23ab1345f | 78 | de_size_t de_size = de_get_size_type(header); |
va009039 | 0:1ed23ab1345f | 79 | if (de_size <= DE_SIZE_128) { |
va009039 | 0:1ed23ab1345f | 80 | return 1; |
va009039 | 0:1ed23ab1345f | 81 | } |
va009039 | 0:1ed23ab1345f | 82 | return 1 + (1 << (de_size-DE_SIZE_VAR_8)); |
va009039 | 0:1ed23ab1345f | 83 | } |
va009039 | 0:1ed23ab1345f | 84 | |
va009039 | 0:1ed23ab1345f | 85 | int de_get_data_size(uint8_t * header){ |
va009039 | 0:1ed23ab1345f | 86 | uint32_t result = 0; |
va009039 | 0:1ed23ab1345f | 87 | de_type_t de_type = de_get_element_type(header); |
va009039 | 0:1ed23ab1345f | 88 | de_size_t de_size = de_get_size_type(header); |
va009039 | 0:1ed23ab1345f | 89 | switch (de_size){ |
va009039 | 0:1ed23ab1345f | 90 | case DE_SIZE_VAR_8: |
va009039 | 0:1ed23ab1345f | 91 | result = header[1]; |
va009039 | 0:1ed23ab1345f | 92 | break; |
va009039 | 0:1ed23ab1345f | 93 | case DE_SIZE_VAR_16: |
va009039 | 0:1ed23ab1345f | 94 | result = READ_NET_16(header,1); |
va009039 | 0:1ed23ab1345f | 95 | break; |
va009039 | 0:1ed23ab1345f | 96 | case DE_SIZE_VAR_32: |
va009039 | 0:1ed23ab1345f | 97 | result = READ_NET_32(header,1); |
va009039 | 0:1ed23ab1345f | 98 | break; |
va009039 | 0:1ed23ab1345f | 99 | default: |
va009039 | 0:1ed23ab1345f | 100 | // case DE_SIZE_8: |
va009039 | 0:1ed23ab1345f | 101 | // case DE_SIZE_16: |
va009039 | 0:1ed23ab1345f | 102 | // case DE_SIZE_32: |
va009039 | 0:1ed23ab1345f | 103 | // case DE_SIZE_64: |
va009039 | 0:1ed23ab1345f | 104 | // case DE_SIZE_128: |
va009039 | 0:1ed23ab1345f | 105 | if (de_type == DE_NIL) return 0; |
va009039 | 0:1ed23ab1345f | 106 | return 1 << de_size; |
va009039 | 0:1ed23ab1345f | 107 | } |
va009039 | 0:1ed23ab1345f | 108 | return result; |
va009039 | 0:1ed23ab1345f | 109 | } |
va009039 | 0:1ed23ab1345f | 110 | |
va009039 | 0:1ed23ab1345f | 111 | int de_get_len(uint8_t *header){ |
va009039 | 0:1ed23ab1345f | 112 | return de_get_header_size(header) + de_get_data_size(header); |
va009039 | 0:1ed23ab1345f | 113 | } |
va009039 | 0:1ed23ab1345f | 114 | |
va009039 | 0:1ed23ab1345f | 115 | // @returns: element is valid UUID |
va009039 | 0:1ed23ab1345f | 116 | int de_get_normalized_uuid(uint8_t *uuid128, uint8_t *element){ |
va009039 | 0:1ed23ab1345f | 117 | de_type_t uuidType = de_get_element_type(element); |
va009039 | 0:1ed23ab1345f | 118 | de_size_t uuidSize = de_get_size_type(element); |
va009039 | 0:1ed23ab1345f | 119 | if (uuidType != DE_UUID) return 0; |
va009039 | 0:1ed23ab1345f | 120 | uint32_t shortUUID; |
va009039 | 0:1ed23ab1345f | 121 | switch (uuidSize){ |
va009039 | 0:1ed23ab1345f | 122 | case DE_SIZE_16: |
va009039 | 0:1ed23ab1345f | 123 | shortUUID = READ_NET_16(element, 1); |
va009039 | 0:1ed23ab1345f | 124 | break; |
va009039 | 0:1ed23ab1345f | 125 | case DE_SIZE_32: |
va009039 | 0:1ed23ab1345f | 126 | shortUUID = READ_NET_32(element, 1); |
va009039 | 0:1ed23ab1345f | 127 | break; |
va009039 | 0:1ed23ab1345f | 128 | case DE_SIZE_128: |
va009039 | 0:1ed23ab1345f | 129 | memcpy(uuid128, element+1, 16); |
va009039 | 0:1ed23ab1345f | 130 | return 1; |
va009039 | 0:1ed23ab1345f | 131 | default: |
va009039 | 0:1ed23ab1345f | 132 | return 0; |
va009039 | 0:1ed23ab1345f | 133 | } |
va009039 | 0:1ed23ab1345f | 134 | sdp_normalize_uuid(uuid128, shortUUID); |
va009039 | 0:1ed23ab1345f | 135 | return 1; |
va009039 | 0:1ed23ab1345f | 136 | } |
va009039 | 0:1ed23ab1345f | 137 | |
va009039 | 0:1ed23ab1345f | 138 | // functions to create record |
va009039 | 0:1ed23ab1345f | 139 | static void de_store_descriptor(uint8_t * header, de_type_t type, de_size_t size){ |
va009039 | 0:1ed23ab1345f | 140 | header[0] = (type << 3) | size; |
va009039 | 0:1ed23ab1345f | 141 | } |
va009039 | 0:1ed23ab1345f | 142 | |
va009039 | 0:1ed23ab1345f | 143 | void de_store_descriptor_with_len(uint8_t * header, de_type_t type, de_size_t size, uint32_t len){ |
va009039 | 0:1ed23ab1345f | 144 | header[0] = (type << 3) | size; |
va009039 | 0:1ed23ab1345f | 145 | switch (size){ |
va009039 | 0:1ed23ab1345f | 146 | case DE_SIZE_VAR_8: |
va009039 | 0:1ed23ab1345f | 147 | header[1] = len; |
va009039 | 0:1ed23ab1345f | 148 | break; |
va009039 | 0:1ed23ab1345f | 149 | case DE_SIZE_VAR_16: |
va009039 | 0:1ed23ab1345f | 150 | net_store_16(header, 1, len); |
va009039 | 0:1ed23ab1345f | 151 | break; |
va009039 | 0:1ed23ab1345f | 152 | case DE_SIZE_VAR_32: |
va009039 | 0:1ed23ab1345f | 153 | net_store_32(header, 1, len); |
va009039 | 0:1ed23ab1345f | 154 | break; |
va009039 | 0:1ed23ab1345f | 155 | default: |
va009039 | 0:1ed23ab1345f | 156 | break; |
va009039 | 0:1ed23ab1345f | 157 | } |
va009039 | 0:1ed23ab1345f | 158 | } |
va009039 | 0:1ed23ab1345f | 159 | |
va009039 | 0:1ed23ab1345f | 160 | // MARK: DataElement creation |
va009039 | 0:1ed23ab1345f | 161 | |
va009039 | 0:1ed23ab1345f | 162 | /* starts a new sequence in empty buffer - first call */ |
va009039 | 0:1ed23ab1345f | 163 | void de_create_sequence(uint8_t *header){ |
va009039 | 0:1ed23ab1345f | 164 | de_store_descriptor_with_len( header, DE_DES, DE_SIZE_VAR_16, 0); // DES, 2 Byte Length |
va009039 | 0:1ed23ab1345f | 165 | }; |
va009039 | 0:1ed23ab1345f | 166 | |
va009039 | 0:1ed23ab1345f | 167 | /* starts a sub-sequence, @returns handle for sub-sequence */ |
va009039 | 0:1ed23ab1345f | 168 | uint8_t * de_push_sequence(uint8_t *header){ |
va009039 | 0:1ed23ab1345f | 169 | int element_len = de_get_len(header); |
va009039 | 0:1ed23ab1345f | 170 | de_store_descriptor_with_len(header+element_len, DE_DES, DE_SIZE_VAR_16, 0); // DES, 2 Byte Length |
va009039 | 0:1ed23ab1345f | 171 | return header + element_len; |
va009039 | 0:1ed23ab1345f | 172 | } |
va009039 | 0:1ed23ab1345f | 173 | |
va009039 | 0:1ed23ab1345f | 174 | /* closes the current sequence and updates the parent sequence */ |
va009039 | 0:1ed23ab1345f | 175 | void de_pop_sequence(uint8_t * parent, uint8_t * child){ |
va009039 | 0:1ed23ab1345f | 176 | int child_len = de_get_len(child); |
va009039 | 0:1ed23ab1345f | 177 | int data_size_parent = READ_NET_16(parent,1); |
va009039 | 0:1ed23ab1345f | 178 | net_store_16(parent, 1, data_size_parent + child_len); |
va009039 | 0:1ed23ab1345f | 179 | } |
va009039 | 0:1ed23ab1345f | 180 | |
va009039 | 0:1ed23ab1345f | 181 | /* adds a single number value and 16+32 bit UUID to the sequence */ |
va009039 | 0:1ed23ab1345f | 182 | void de_add_number(uint8_t *seq, de_type_t type, de_size_t size, uint32_t value){ |
va009039 | 0:1ed23ab1345f | 183 | int data_size = READ_NET_16(seq,1); |
va009039 | 0:1ed23ab1345f | 184 | int element_size = 1; // e.g. for DE_TYPE_NIL |
va009039 | 0:1ed23ab1345f | 185 | de_store_descriptor(seq+3+data_size, type, size); |
va009039 | 0:1ed23ab1345f | 186 | switch (size){ |
va009039 | 0:1ed23ab1345f | 187 | case DE_SIZE_8: |
va009039 | 0:1ed23ab1345f | 188 | if (type != DE_NIL){ |
va009039 | 0:1ed23ab1345f | 189 | seq[4+data_size] = value; |
va009039 | 0:1ed23ab1345f | 190 | element_size = 2; |
va009039 | 0:1ed23ab1345f | 191 | } |
va009039 | 0:1ed23ab1345f | 192 | break; |
va009039 | 0:1ed23ab1345f | 193 | case DE_SIZE_16: |
va009039 | 0:1ed23ab1345f | 194 | net_store_16(seq, 4+data_size, value); |
va009039 | 0:1ed23ab1345f | 195 | element_size = 3; |
va009039 | 0:1ed23ab1345f | 196 | break; |
va009039 | 0:1ed23ab1345f | 197 | case DE_SIZE_32: |
va009039 | 0:1ed23ab1345f | 198 | net_store_32(seq, 4+data_size, value); |
va009039 | 0:1ed23ab1345f | 199 | element_size = 5; |
va009039 | 0:1ed23ab1345f | 200 | break; |
va009039 | 0:1ed23ab1345f | 201 | default: |
va009039 | 0:1ed23ab1345f | 202 | break; |
va009039 | 0:1ed23ab1345f | 203 | } |
va009039 | 0:1ed23ab1345f | 204 | net_store_16(seq, 1, data_size+element_size); |
va009039 | 0:1ed23ab1345f | 205 | } |
va009039 | 0:1ed23ab1345f | 206 | |
va009039 | 0:1ed23ab1345f | 207 | /* add a single block of data, e.g. as DE_STRING, DE_URL */ |
va009039 | 0:1ed23ab1345f | 208 | void de_add_data( uint8_t *seq, de_type_t type, uint16_t size, uint8_t *data){ |
va009039 | 0:1ed23ab1345f | 209 | int data_size = READ_NET_16(seq,1); |
va009039 | 0:1ed23ab1345f | 210 | if (size > 0xff) { |
va009039 | 0:1ed23ab1345f | 211 | // use 16-bit lengh information (3 byte header) |
va009039 | 0:1ed23ab1345f | 212 | de_store_descriptor_with_len(seq+3+data_size, type, DE_SIZE_VAR_16, size); |
va009039 | 0:1ed23ab1345f | 213 | data_size += 3; |
va009039 | 0:1ed23ab1345f | 214 | } else { |
va009039 | 0:1ed23ab1345f | 215 | // use 8-bit lengh information (2 byte header) |
va009039 | 0:1ed23ab1345f | 216 | de_store_descriptor_with_len(seq+3+data_size, type, DE_SIZE_VAR_8, size); |
va009039 | 0:1ed23ab1345f | 217 | data_size += 2; |
va009039 | 0:1ed23ab1345f | 218 | } |
va009039 | 0:1ed23ab1345f | 219 | memcpy( seq + 3 + data_size, data, size); |
va009039 | 0:1ed23ab1345f | 220 | data_size += size; |
va009039 | 0:1ed23ab1345f | 221 | net_store_16(seq, 1, data_size); |
va009039 | 0:1ed23ab1345f | 222 | } |
va009039 | 0:1ed23ab1345f | 223 | |
va009039 | 0:1ed23ab1345f | 224 | void de_add_uuid128(uint8_t * seq, uint8_t * uuid){ |
va009039 | 0:1ed23ab1345f | 225 | int data_size = READ_NET_16(seq,1); |
va009039 | 0:1ed23ab1345f | 226 | de_store_descriptor(seq+3+data_size, DE_UUID, DE_SIZE_128); |
va009039 | 0:1ed23ab1345f | 227 | memcpy( seq + 4 + data_size, uuid, 16); |
va009039 | 0:1ed23ab1345f | 228 | net_store_16(seq, 1, data_size+1+16); |
va009039 | 0:1ed23ab1345f | 229 | } |
va009039 | 0:1ed23ab1345f | 230 | |
va009039 | 0:1ed23ab1345f | 231 | void sdp_add_attribute(uint8_t *seq, uint16_t attributeID, uint8_t attributeValue){ |
va009039 | 0:1ed23ab1345f | 232 | } |
va009039 | 0:1ed23ab1345f | 233 | |
va009039 | 0:1ed23ab1345f | 234 | // MARK: DataElementSequence traversal |
va009039 | 0:1ed23ab1345f | 235 | typedef int (*de_traversal_callback_t)(uint8_t * element, de_type_t type, de_size_t size, void *context); |
va009039 | 0:1ed23ab1345f | 236 | static void de_traverse_sequence(uint8_t * element, de_traversal_callback_t handler, void *context){ |
va009039 | 0:1ed23ab1345f | 237 | de_type_t type = de_get_element_type(element); |
va009039 | 0:1ed23ab1345f | 238 | if (type != DE_DES) return; |
va009039 | 0:1ed23ab1345f | 239 | int pos = de_get_header_size(element); |
va009039 | 0:1ed23ab1345f | 240 | int end_pos = de_get_len(element); |
va009039 | 0:1ed23ab1345f | 241 | while (pos < end_pos){ |
va009039 | 0:1ed23ab1345f | 242 | de_type_t elemType = de_get_element_type(element + pos); |
va009039 | 0:1ed23ab1345f | 243 | de_size_t elemSize = de_get_size_type(element + pos); |
va009039 | 0:1ed23ab1345f | 244 | uint8_t done = (*handler)(element + pos, elemType, elemSize, context); |
va009039 | 0:1ed23ab1345f | 245 | if (done) break; |
va009039 | 0:1ed23ab1345f | 246 | pos += de_get_len(element + pos); |
va009039 | 0:1ed23ab1345f | 247 | } |
va009039 | 0:1ed23ab1345f | 248 | } |
va009039 | 0:1ed23ab1345f | 249 | |
va009039 | 0:1ed23ab1345f | 250 | // MARK: AttributeList traversal |
va009039 | 0:1ed23ab1345f | 251 | typedef int (*sdp_attribute_list_traversal_callback_t)(uint16_t attributeID, uint8_t * attributeValue, de_type_t type, de_size_t size, void *context); |
va009039 | 0:1ed23ab1345f | 252 | static void sdp_attribute_list_traverse_sequence(uint8_t * element, sdp_attribute_list_traversal_callback_t handler, void *context){ |
va009039 | 0:1ed23ab1345f | 253 | de_type_t type = de_get_element_type(element); |
va009039 | 0:1ed23ab1345f | 254 | if (type != DE_DES) return; |
va009039 | 0:1ed23ab1345f | 255 | int pos = de_get_header_size(element); |
va009039 | 0:1ed23ab1345f | 256 | int end_pos = de_get_len(element); |
va009039 | 0:1ed23ab1345f | 257 | while (pos < end_pos){ |
va009039 | 0:1ed23ab1345f | 258 | de_type_t idType = de_get_element_type(element + pos); |
va009039 | 0:1ed23ab1345f | 259 | de_size_t idSize = de_get_size_type(element + pos); |
va009039 | 0:1ed23ab1345f | 260 | if (idType != DE_UINT || idSize != DE_SIZE_16) break; // wrong type |
va009039 | 0:1ed23ab1345f | 261 | uint16_t attribute_id = READ_NET_16(element, pos + 1); |
va009039 | 0:1ed23ab1345f | 262 | pos += 3; |
va009039 | 0:1ed23ab1345f | 263 | if (pos >= end_pos) break; // array out of bounds |
va009039 | 0:1ed23ab1345f | 264 | de_type_t valueType = de_get_element_type(element + pos); |
va009039 | 0:1ed23ab1345f | 265 | de_size_t valueSize = de_get_size_type(element + pos); |
va009039 | 0:1ed23ab1345f | 266 | uint8_t done = (*handler)(attribute_id, element + pos, valueType, valueSize, context); |
va009039 | 0:1ed23ab1345f | 267 | if (done) break; |
va009039 | 0:1ed23ab1345f | 268 | pos += de_get_len(element + pos); |
va009039 | 0:1ed23ab1345f | 269 | } |
va009039 | 0:1ed23ab1345f | 270 | } |
va009039 | 0:1ed23ab1345f | 271 | |
va009039 | 0:1ed23ab1345f | 272 | // MARK: AttributeID in AttributeIDList |
va009039 | 0:1ed23ab1345f | 273 | // attribute ID in AttributeIDList |
va009039 | 0:1ed23ab1345f | 274 | // context { result, attributeID } |
va009039 | 0:1ed23ab1345f | 275 | struct sdp_context_attributeID_search { |
va009039 | 0:1ed23ab1345f | 276 | int result; |
va009039 | 0:1ed23ab1345f | 277 | uint16_t attributeID; |
va009039 | 0:1ed23ab1345f | 278 | }; |
va009039 | 0:1ed23ab1345f | 279 | static int sdp_traversal_attributeID_search(uint8_t * element, de_type_t type, de_size_t size, void *my_context){ |
va009039 | 0:1ed23ab1345f | 280 | struct sdp_context_attributeID_search * context = (struct sdp_context_attributeID_search *) my_context; |
va009039 | 0:1ed23ab1345f | 281 | if (type != DE_UINT) return 0; |
va009039 | 0:1ed23ab1345f | 282 | switch (size) { |
va009039 | 0:1ed23ab1345f | 283 | case DE_SIZE_16: |
va009039 | 0:1ed23ab1345f | 284 | if (READ_NET_16(element, 1) == context->attributeID) { |
va009039 | 0:1ed23ab1345f | 285 | context->result = 1; |
va009039 | 0:1ed23ab1345f | 286 | return 1; |
va009039 | 0:1ed23ab1345f | 287 | } |
va009039 | 0:1ed23ab1345f | 288 | break; |
va009039 | 0:1ed23ab1345f | 289 | case DE_SIZE_32: |
va009039 | 0:1ed23ab1345f | 290 | if (READ_NET_16(element, 1) <= context->attributeID |
va009039 | 0:1ed23ab1345f | 291 | && context->attributeID <= READ_NET_16(element, 3)) { |
va009039 | 0:1ed23ab1345f | 292 | context->result = 1; |
va009039 | 0:1ed23ab1345f | 293 | return 1; |
va009039 | 0:1ed23ab1345f | 294 | } |
va009039 | 0:1ed23ab1345f | 295 | break; |
va009039 | 0:1ed23ab1345f | 296 | default: |
va009039 | 0:1ed23ab1345f | 297 | break; |
va009039 | 0:1ed23ab1345f | 298 | } |
va009039 | 0:1ed23ab1345f | 299 | return 0; |
va009039 | 0:1ed23ab1345f | 300 | } |
va009039 | 0:1ed23ab1345f | 301 | int sdp_attribute_list_constains_id(uint8_t *attributeIDList, uint16_t attributeID){ |
va009039 | 0:1ed23ab1345f | 302 | struct sdp_context_attributeID_search attributeID_search; |
va009039 | 0:1ed23ab1345f | 303 | attributeID_search.result = 0; |
va009039 | 0:1ed23ab1345f | 304 | attributeID_search.attributeID = attributeID; |
va009039 | 0:1ed23ab1345f | 305 | de_traverse_sequence(attributeIDList, sdp_traversal_attributeID_search, &attributeID_search); |
va009039 | 0:1ed23ab1345f | 306 | return attributeID_search.result; |
va009039 | 0:1ed23ab1345f | 307 | } |
va009039 | 0:1ed23ab1345f | 308 | |
va009039 | 0:1ed23ab1345f | 309 | // MARK: Append Attributes for AttributeIDList |
va009039 | 0:1ed23ab1345f | 310 | // pre: buffer contains DES with 2 byte length field |
va009039 | 0:1ed23ab1345f | 311 | struct sdp_context_append_attributes { |
va009039 | 0:1ed23ab1345f | 312 | uint8_t * buffer; |
va009039 | 0:1ed23ab1345f | 313 | uint16_t startOffset; // offset of when to start copying |
va009039 | 0:1ed23ab1345f | 314 | uint16_t maxBytes; |
va009039 | 0:1ed23ab1345f | 315 | uint16_t usedBytes; |
va009039 | 0:1ed23ab1345f | 316 | uint8_t *attributeIDList; |
va009039 | 0:1ed23ab1345f | 317 | }; |
va009039 | 0:1ed23ab1345f | 318 | |
va009039 | 0:1ed23ab1345f | 319 | static int sdp_traversal_append_attributes(uint16_t attributeID, uint8_t * attributeValue, de_type_t type, de_size_t size, void *my_context){ |
va009039 | 0:1ed23ab1345f | 320 | struct sdp_context_append_attributes * context = (struct sdp_context_append_attributes *) my_context; |
va009039 | 0:1ed23ab1345f | 321 | if (sdp_attribute_list_constains_id(context->attributeIDList, attributeID)) { |
va009039 | 0:1ed23ab1345f | 322 | // DES_HEADER(3) + DES_DATA + (UINT16(3) + attribute) |
va009039 | 0:1ed23ab1345f | 323 | uint16_t data_size = READ_NET_16(context->buffer, 1); |
va009039 | 0:1ed23ab1345f | 324 | int attribute_len = de_get_len(attributeValue); |
va009039 | 0:1ed23ab1345f | 325 | if (3 + data_size + (3 + attribute_len) <= context->maxBytes) { |
va009039 | 0:1ed23ab1345f | 326 | // copy Attribute |
va009039 | 0:1ed23ab1345f | 327 | de_add_number(context->buffer, DE_UINT, DE_SIZE_16, attributeID); |
va009039 | 0:1ed23ab1345f | 328 | data_size += 3; // 3 bytes |
va009039 | 0:1ed23ab1345f | 329 | memcpy(context->buffer + 3 + data_size, attributeValue, attribute_len); |
va009039 | 0:1ed23ab1345f | 330 | net_store_16(context->buffer,1,data_size+attribute_len); |
va009039 | 0:1ed23ab1345f | 331 | } else { |
va009039 | 0:1ed23ab1345f | 332 | // not enought space left -> continue with previous element |
va009039 | 0:1ed23ab1345f | 333 | return 1; |
va009039 | 0:1ed23ab1345f | 334 | } |
va009039 | 0:1ed23ab1345f | 335 | } |
va009039 | 0:1ed23ab1345f | 336 | return 0; |
va009039 | 0:1ed23ab1345f | 337 | } |
va009039 | 0:1ed23ab1345f | 338 | |
va009039 | 0:1ed23ab1345f | 339 | // maxBytes: maximal size of data element sequence |
va009039 | 0:1ed23ab1345f | 340 | uint16_t sdp_append_attributes_in_attributeIDList(uint8_t *record, uint8_t *attributeIDList, uint16_t startOffset, uint16_t maxBytes, uint8_t *buffer){ |
va009039 | 0:1ed23ab1345f | 341 | struct sdp_context_append_attributes context; |
va009039 | 0:1ed23ab1345f | 342 | context.buffer = buffer; |
va009039 | 0:1ed23ab1345f | 343 | context.maxBytes = maxBytes; |
va009039 | 0:1ed23ab1345f | 344 | context.usedBytes = 0; |
va009039 | 0:1ed23ab1345f | 345 | context.startOffset = startOffset; |
va009039 | 0:1ed23ab1345f | 346 | context.attributeIDList = attributeIDList; |
va009039 | 0:1ed23ab1345f | 347 | sdp_attribute_list_traverse_sequence(record, sdp_traversal_append_attributes, &context); |
va009039 | 0:1ed23ab1345f | 348 | return context.usedBytes; |
va009039 | 0:1ed23ab1345f | 349 | } |
va009039 | 0:1ed23ab1345f | 350 | |
va009039 | 0:1ed23ab1345f | 351 | // MARK: Filter attributes that match attribute list from startOffset and a max nr bytes |
va009039 | 0:1ed23ab1345f | 352 | struct sdp_context_filter_attributes { |
va009039 | 0:1ed23ab1345f | 353 | uint8_t * buffer; |
va009039 | 0:1ed23ab1345f | 354 | uint16_t startOffset; // offset of when to start copying |
va009039 | 0:1ed23ab1345f | 355 | uint16_t maxBytes; |
va009039 | 0:1ed23ab1345f | 356 | uint16_t usedBytes; |
va009039 | 0:1ed23ab1345f | 357 | uint8_t *attributeIDList; |
va009039 | 0:1ed23ab1345f | 358 | int complete; |
va009039 | 0:1ed23ab1345f | 359 | }; |
va009039 | 0:1ed23ab1345f | 360 | |
va009039 | 0:1ed23ab1345f | 361 | // copy data with given start offset and max bytes, returns OK if all data has been copied |
va009039 | 0:1ed23ab1345f | 362 | static int spd_append_range(struct sdp_context_filter_attributes* context, uint16_t len, uint8_t *data){ |
va009039 | 0:1ed23ab1345f | 363 | int ok = 1; |
va009039 | 0:1ed23ab1345f | 364 | uint16_t remainder_len = len - context->startOffset; |
va009039 | 0:1ed23ab1345f | 365 | if (context->maxBytes < remainder_len){ |
va009039 | 0:1ed23ab1345f | 366 | remainder_len = context->maxBytes; |
va009039 | 0:1ed23ab1345f | 367 | ok = 0; |
va009039 | 0:1ed23ab1345f | 368 | } |
va009039 | 0:1ed23ab1345f | 369 | memcpy(context->buffer, &data[context->startOffset], remainder_len); |
va009039 | 0:1ed23ab1345f | 370 | context->usedBytes += remainder_len; |
va009039 | 0:1ed23ab1345f | 371 | context->buffer += remainder_len; |
va009039 | 0:1ed23ab1345f | 372 | context->maxBytes -= remainder_len; |
va009039 | 0:1ed23ab1345f | 373 | context->startOffset = 0; |
va009039 | 0:1ed23ab1345f | 374 | return ok; |
va009039 | 0:1ed23ab1345f | 375 | } |
va009039 | 0:1ed23ab1345f | 376 | |
va009039 | 0:1ed23ab1345f | 377 | static int sdp_traversal_filter_attributes(uint16_t attributeID, uint8_t * attributeValue, de_type_t type, de_size_t size, void *my_context){ |
va009039 | 0:1ed23ab1345f | 378 | struct sdp_context_filter_attributes * context = (struct sdp_context_filter_attributes *) my_context; |
va009039 | 0:1ed23ab1345f | 379 | |
va009039 | 0:1ed23ab1345f | 380 | if (!sdp_attribute_list_constains_id(context->attributeIDList, attributeID)) return 0; |
va009039 | 0:1ed23ab1345f | 381 | |
va009039 | 0:1ed23ab1345f | 382 | // { Attribute ID (Descriptor, big endian 16-bit ID), AttributeValue (data)} |
va009039 | 0:1ed23ab1345f | 383 | |
va009039 | 0:1ed23ab1345f | 384 | // handle Attribute ID |
va009039 | 0:1ed23ab1345f | 385 | if (context->startOffset >= 3){ |
va009039 | 0:1ed23ab1345f | 386 | context->startOffset -= 3; |
va009039 | 0:1ed23ab1345f | 387 | } else { |
va009039 | 0:1ed23ab1345f | 388 | uint8_t idBuffer[3]; |
va009039 | 0:1ed23ab1345f | 389 | de_store_descriptor(idBuffer, DE_UINT, DE_SIZE_16); |
va009039 | 0:1ed23ab1345f | 390 | net_store_16(idBuffer,1,attributeID); |
va009039 | 0:1ed23ab1345f | 391 | |
va009039 | 0:1ed23ab1345f | 392 | int ok = spd_append_range(context, 3, idBuffer); |
va009039 | 0:1ed23ab1345f | 393 | if (!ok) { |
va009039 | 0:1ed23ab1345f | 394 | context->complete = 0; |
va009039 | 0:1ed23ab1345f | 395 | return 1; |
va009039 | 0:1ed23ab1345f | 396 | } |
va009039 | 0:1ed23ab1345f | 397 | } |
va009039 | 0:1ed23ab1345f | 398 | |
va009039 | 0:1ed23ab1345f | 399 | // handle Attribute Value |
va009039 | 0:1ed23ab1345f | 400 | int attribute_len = de_get_len(attributeValue); |
va009039 | 0:1ed23ab1345f | 401 | if (context->startOffset >= attribute_len) { |
va009039 | 0:1ed23ab1345f | 402 | context->startOffset -= attribute_len; |
va009039 | 0:1ed23ab1345f | 403 | return 0; |
va009039 | 0:1ed23ab1345f | 404 | } |
va009039 | 0:1ed23ab1345f | 405 | |
va009039 | 0:1ed23ab1345f | 406 | int ok = spd_append_range(context, attribute_len, attributeValue); |
va009039 | 0:1ed23ab1345f | 407 | if (!ok) { |
va009039 | 0:1ed23ab1345f | 408 | context->complete = 0; |
va009039 | 0:1ed23ab1345f | 409 | return 1; |
va009039 | 0:1ed23ab1345f | 410 | } |
va009039 | 0:1ed23ab1345f | 411 | return 0; |
va009039 | 0:1ed23ab1345f | 412 | } |
va009039 | 0:1ed23ab1345f | 413 | |
va009039 | 0:1ed23ab1345f | 414 | int sdp_filter_attributes_in_attributeIDList(uint8_t *record, uint8_t *attributeIDList, uint16_t startOffset, uint16_t maxBytes, uint16_t *usedBytes, uint8_t *buffer){ |
va009039 | 0:1ed23ab1345f | 415 | |
va009039 | 0:1ed23ab1345f | 416 | struct sdp_context_filter_attributes context; |
va009039 | 0:1ed23ab1345f | 417 | context.buffer = buffer; |
va009039 | 0:1ed23ab1345f | 418 | context.maxBytes = maxBytes; |
va009039 | 0:1ed23ab1345f | 419 | context.usedBytes = 0; |
va009039 | 0:1ed23ab1345f | 420 | context.startOffset = startOffset; |
va009039 | 0:1ed23ab1345f | 421 | context.attributeIDList = attributeIDList; |
va009039 | 0:1ed23ab1345f | 422 | context.complete = 1; |
va009039 | 0:1ed23ab1345f | 423 | |
va009039 | 0:1ed23ab1345f | 424 | sdp_attribute_list_traverse_sequence(record, sdp_traversal_filter_attributes, &context); |
va009039 | 0:1ed23ab1345f | 425 | |
va009039 | 0:1ed23ab1345f | 426 | *usedBytes = context.usedBytes; |
va009039 | 0:1ed23ab1345f | 427 | return context.complete; |
va009039 | 0:1ed23ab1345f | 428 | } |
va009039 | 0:1ed23ab1345f | 429 | |
va009039 | 0:1ed23ab1345f | 430 | // MARK: Get sum of attributes matching attribute list |
va009039 | 0:1ed23ab1345f | 431 | struct sdp_context_get_filtered_size { |
va009039 | 0:1ed23ab1345f | 432 | uint8_t *attributeIDList; |
va009039 | 0:1ed23ab1345f | 433 | uint16_t size; |
va009039 | 0:1ed23ab1345f | 434 | }; |
va009039 | 0:1ed23ab1345f | 435 | |
va009039 | 0:1ed23ab1345f | 436 | static int sdp_traversal_get_filtered_size(uint16_t attributeID, uint8_t * attributeValue, de_type_t type, de_size_t size, void *my_context){ |
va009039 | 0:1ed23ab1345f | 437 | struct sdp_context_get_filtered_size * context = (struct sdp_context_get_filtered_size *) my_context; |
va009039 | 0:1ed23ab1345f | 438 | if (sdp_attribute_list_constains_id(context->attributeIDList, attributeID)) { |
va009039 | 0:1ed23ab1345f | 439 | context->size += 3 + de_get_len(attributeValue); |
va009039 | 0:1ed23ab1345f | 440 | } |
va009039 | 0:1ed23ab1345f | 441 | return 0; |
va009039 | 0:1ed23ab1345f | 442 | } |
va009039 | 0:1ed23ab1345f | 443 | |
va009039 | 0:1ed23ab1345f | 444 | int spd_get_filtered_size(uint8_t *record, uint8_t *attributeIDList){ |
va009039 | 0:1ed23ab1345f | 445 | struct sdp_context_get_filtered_size context; |
va009039 | 0:1ed23ab1345f | 446 | context.size = 0; |
va009039 | 0:1ed23ab1345f | 447 | context.attributeIDList = attributeIDList; |
va009039 | 0:1ed23ab1345f | 448 | sdp_attribute_list_traverse_sequence(record, sdp_traversal_get_filtered_size, &context); |
va009039 | 0:1ed23ab1345f | 449 | return context.size; |
va009039 | 0:1ed23ab1345f | 450 | } |
va009039 | 0:1ed23ab1345f | 451 | |
va009039 | 0:1ed23ab1345f | 452 | // MARK: Get AttributeValue for AttributeID |
va009039 | 0:1ed23ab1345f | 453 | // find attribute (ELEMENT) by ID |
va009039 | 0:1ed23ab1345f | 454 | struct sdp_context_attribute_by_id { |
va009039 | 0:1ed23ab1345f | 455 | uint16_t attributeID; |
va009039 | 0:1ed23ab1345f | 456 | uint8_t * attributeValue; |
va009039 | 0:1ed23ab1345f | 457 | }; |
va009039 | 0:1ed23ab1345f | 458 | static int sdp_traversal_attribute_by_id(uint16_t attributeID, uint8_t * attributeValue, de_type_t attributeType, de_size_t size, void *my_context){ |
va009039 | 0:1ed23ab1345f | 459 | struct sdp_context_attribute_by_id * context = (struct sdp_context_attribute_by_id *) my_context; |
va009039 | 0:1ed23ab1345f | 460 | if (attributeID == context->attributeID) { |
va009039 | 0:1ed23ab1345f | 461 | context->attributeValue = attributeValue; |
va009039 | 0:1ed23ab1345f | 462 | return 1; |
va009039 | 0:1ed23ab1345f | 463 | } |
va009039 | 0:1ed23ab1345f | 464 | return 0; |
va009039 | 0:1ed23ab1345f | 465 | } |
va009039 | 0:1ed23ab1345f | 466 | |
va009039 | 0:1ed23ab1345f | 467 | uint8_t * sdp_get_attribute_value_for_attribute_id(uint8_t * record, uint16_t attributeID){ |
va009039 | 0:1ed23ab1345f | 468 | struct sdp_context_attribute_by_id context; |
va009039 | 0:1ed23ab1345f | 469 | context.attributeValue = NULL; |
va009039 | 0:1ed23ab1345f | 470 | context.attributeID = attributeID; |
va009039 | 0:1ed23ab1345f | 471 | sdp_attribute_list_traverse_sequence(record, sdp_traversal_attribute_by_id, &context); |
va009039 | 0:1ed23ab1345f | 472 | return context.attributeValue; |
va009039 | 0:1ed23ab1345f | 473 | } |
va009039 | 0:1ed23ab1345f | 474 | |
va009039 | 0:1ed23ab1345f | 475 | // MARK: Set AttributeValue for AttributeID |
va009039 | 0:1ed23ab1345f | 476 | struct sdp_context_set_attribute_for_id { |
va009039 | 0:1ed23ab1345f | 477 | uint16_t attributeID; |
va009039 | 0:1ed23ab1345f | 478 | uint32_t attributeValue; |
va009039 | 0:1ed23ab1345f | 479 | uint8_t attributeFound; |
va009039 | 0:1ed23ab1345f | 480 | }; |
va009039 | 0:1ed23ab1345f | 481 | static int sdp_traversal_set_attribute_for_id(uint16_t attributeID, uint8_t * attributeValue, de_type_t attributeType, de_size_t size, void *my_context){ |
va009039 | 0:1ed23ab1345f | 482 | struct sdp_context_set_attribute_for_id * context = (struct sdp_context_set_attribute_for_id *) my_context; |
va009039 | 0:1ed23ab1345f | 483 | if (attributeID == context->attributeID) { |
va009039 | 0:1ed23ab1345f | 484 | context->attributeFound = 1; |
va009039 | 0:1ed23ab1345f | 485 | switch (size){ |
va009039 | 0:1ed23ab1345f | 486 | case DE_SIZE_8: |
va009039 | 0:1ed23ab1345f | 487 | if (attributeType != DE_NIL){ |
va009039 | 0:1ed23ab1345f | 488 | attributeValue[1] = context->attributeValue; |
va009039 | 0:1ed23ab1345f | 489 | } |
va009039 | 0:1ed23ab1345f | 490 | break; |
va009039 | 0:1ed23ab1345f | 491 | case DE_SIZE_16: |
va009039 | 0:1ed23ab1345f | 492 | net_store_16(attributeValue, 1, context->attributeValue); |
va009039 | 0:1ed23ab1345f | 493 | break; |
va009039 | 0:1ed23ab1345f | 494 | case DE_SIZE_32: |
va009039 | 0:1ed23ab1345f | 495 | net_store_32(attributeValue, 1, context->attributeValue); |
va009039 | 0:1ed23ab1345f | 496 | break; |
va009039 | 0:1ed23ab1345f | 497 | // Might want to support STRINGS to, copy upto original length |
va009039 | 0:1ed23ab1345f | 498 | default: |
va009039 | 0:1ed23ab1345f | 499 | break; |
va009039 | 0:1ed23ab1345f | 500 | } |
va009039 | 0:1ed23ab1345f | 501 | return 1; |
va009039 | 0:1ed23ab1345f | 502 | } |
va009039 | 0:1ed23ab1345f | 503 | return 0; |
va009039 | 0:1ed23ab1345f | 504 | } |
va009039 | 0:1ed23ab1345f | 505 | uint8_t sdp_set_attribute_value_for_attribute_id(uint8_t * record, uint16_t attributeID, uint32_t value){ |
va009039 | 0:1ed23ab1345f | 506 | struct sdp_context_set_attribute_for_id context; |
va009039 | 0:1ed23ab1345f | 507 | context.attributeID = attributeID; |
va009039 | 0:1ed23ab1345f | 508 | context.attributeValue = value; |
va009039 | 0:1ed23ab1345f | 509 | context.attributeFound = 0; |
va009039 | 0:1ed23ab1345f | 510 | sdp_attribute_list_traverse_sequence(record, sdp_traversal_set_attribute_for_id, &context); |
va009039 | 0:1ed23ab1345f | 511 | return context.attributeFound; |
va009039 | 0:1ed23ab1345f | 512 | } |
va009039 | 0:1ed23ab1345f | 513 | |
va009039 | 0:1ed23ab1345f | 514 | // MARK: ServiceRecord contains UUID |
va009039 | 0:1ed23ab1345f | 515 | // service record contains UUID |
va009039 | 0:1ed23ab1345f | 516 | // context { normalizedUUID } |
va009039 | 0:1ed23ab1345f | 517 | struct sdp_context_contains_uuid128 { |
va009039 | 0:1ed23ab1345f | 518 | uint8_t * uuid128; |
va009039 | 0:1ed23ab1345f | 519 | int result; |
va009039 | 0:1ed23ab1345f | 520 | }; |
va009039 | 0:1ed23ab1345f | 521 | int sdp_record_contains_UUID128(uint8_t *record, uint8_t *uuid128); |
va009039 | 0:1ed23ab1345f | 522 | static int sdp_traversal_contains_UUID128(uint8_t * element, de_type_t type, de_size_t size, void *my_context){ |
va009039 | 0:1ed23ab1345f | 523 | struct sdp_context_contains_uuid128 * context = (struct sdp_context_contains_uuid128 *) my_context; |
va009039 | 0:1ed23ab1345f | 524 | uint8_t normalizedUUID[16]; |
va009039 | 0:1ed23ab1345f | 525 | if (type == DE_UUID){ |
va009039 | 0:1ed23ab1345f | 526 | uint8_t uuidOK = de_get_normalized_uuid(normalizedUUID, element); |
va009039 | 0:1ed23ab1345f | 527 | context->result = uuidOK && memcmp(context->uuid128, normalizedUUID, 16) == 0; |
va009039 | 0:1ed23ab1345f | 528 | } |
va009039 | 0:1ed23ab1345f | 529 | if (type == DE_DES){ |
va009039 | 0:1ed23ab1345f | 530 | context->result = sdp_record_contains_UUID128(element, context->uuid128); |
va009039 | 0:1ed23ab1345f | 531 | } |
va009039 | 0:1ed23ab1345f | 532 | return context->result; |
va009039 | 0:1ed23ab1345f | 533 | } |
va009039 | 0:1ed23ab1345f | 534 | int sdp_record_contains_UUID128(uint8_t *record, uint8_t *uuid128){ |
va009039 | 0:1ed23ab1345f | 535 | struct sdp_context_contains_uuid128 context; |
va009039 | 0:1ed23ab1345f | 536 | context.uuid128 = uuid128; |
va009039 | 0:1ed23ab1345f | 537 | context.result = 0; |
va009039 | 0:1ed23ab1345f | 538 | de_traverse_sequence(record, sdp_traversal_contains_UUID128, &context); |
va009039 | 0:1ed23ab1345f | 539 | return context.result; |
va009039 | 0:1ed23ab1345f | 540 | } |
va009039 | 0:1ed23ab1345f | 541 | |
va009039 | 0:1ed23ab1345f | 542 | // MARK: ServiceRecord matches SearchServicePattern |
va009039 | 0:1ed23ab1345f | 543 | // if UUID in searchServicePattern is not found in record => false |
va009039 | 0:1ed23ab1345f | 544 | // context { result, record } |
va009039 | 0:1ed23ab1345f | 545 | struct sdp_context_match_pattern { |
va009039 | 0:1ed23ab1345f | 546 | uint8_t * record; |
va009039 | 0:1ed23ab1345f | 547 | int result; |
va009039 | 0:1ed23ab1345f | 548 | }; |
va009039 | 0:1ed23ab1345f | 549 | int sdp_traversal_match_pattern(uint8_t * element, de_type_t attributeType, de_size_t size, void *my_context){ |
va009039 | 0:1ed23ab1345f | 550 | struct sdp_context_match_pattern * context = (struct sdp_context_match_pattern *) my_context; |
va009039 | 0:1ed23ab1345f | 551 | uint8_t normalizedUUID[16]; |
va009039 | 0:1ed23ab1345f | 552 | uint8_t uuidOK = de_get_normalized_uuid(normalizedUUID, element); |
va009039 | 0:1ed23ab1345f | 553 | if (!uuidOK || !sdp_record_contains_UUID128(context->record, normalizedUUID)){ |
va009039 | 0:1ed23ab1345f | 554 | context->result = 0; |
va009039 | 0:1ed23ab1345f | 555 | return 1; |
va009039 | 0:1ed23ab1345f | 556 | } |
va009039 | 0:1ed23ab1345f | 557 | return 0; |
va009039 | 0:1ed23ab1345f | 558 | } |
va009039 | 0:1ed23ab1345f | 559 | int sdp_record_matches_service_search_pattern(uint8_t *record, uint8_t *serviceSearchPattern){ |
va009039 | 0:1ed23ab1345f | 560 | struct sdp_context_match_pattern context; |
va009039 | 0:1ed23ab1345f | 561 | context.record = record; |
va009039 | 0:1ed23ab1345f | 562 | context.result = 1; |
va009039 | 0:1ed23ab1345f | 563 | de_traverse_sequence(serviceSearchPattern, sdp_traversal_match_pattern, &context); |
va009039 | 0:1ed23ab1345f | 564 | return context.result; |
va009039 | 0:1ed23ab1345f | 565 | } |
va009039 | 0:1ed23ab1345f | 566 | |
va009039 | 0:1ed23ab1345f | 567 | // MARK: Dump DataElement |
va009039 | 0:1ed23ab1345f | 568 | // context { indent } |
va009039 | 0:1ed23ab1345f | 569 | static int de_traversal_dump_data(uint8_t * element, de_type_t de_type, de_size_t de_size, void *my_context){ |
va009039 | 0:1ed23ab1345f | 570 | int indent = *(int*) my_context; |
va009039 | 0:1ed23ab1345f | 571 | int i; |
va009039 | 0:1ed23ab1345f | 572 | for (i=0; i<indent;i++) printf(" "); |
va009039 | 0:1ed23ab1345f | 573 | int pos = de_get_header_size(element); |
va009039 | 0:1ed23ab1345f | 574 | int end_pos = de_get_len(element); |
va009039 | 0:1ed23ab1345f | 575 | printf("type %5s (%u), element len %2u ", type_names[de_type], de_type, end_pos); |
va009039 | 0:1ed23ab1345f | 576 | if (de_type == DE_DES) { |
va009039 | 0:1ed23ab1345f | 577 | printf("\n"); |
va009039 | 0:1ed23ab1345f | 578 | indent++; |
va009039 | 0:1ed23ab1345f | 579 | de_traverse_sequence(element, de_traversal_dump_data, (void *)&indent); |
va009039 | 0:1ed23ab1345f | 580 | } else if (de_type == DE_UUID && de_size == DE_SIZE_128) { |
va009039 | 0:1ed23ab1345f | 581 | printf(", value: "); |
va009039 | 0:1ed23ab1345f | 582 | printUUID(element+1); |
va009039 | 0:1ed23ab1345f | 583 | printf("\n"); |
va009039 | 0:1ed23ab1345f | 584 | } else if (de_type == DE_STRING) { |
va009039 | 0:1ed23ab1345f | 585 | int len = 0; |
va009039 | 0:1ed23ab1345f | 586 | switch (de_size){ |
va009039 | 0:1ed23ab1345f | 587 | case DE_SIZE_VAR_8: |
va009039 | 0:1ed23ab1345f | 588 | len = element[1]; |
va009039 | 0:1ed23ab1345f | 589 | break; |
va009039 | 0:1ed23ab1345f | 590 | case DE_SIZE_VAR_16: |
va009039 | 0:1ed23ab1345f | 591 | len = READ_NET_16(element, 1); |
va009039 | 0:1ed23ab1345f | 592 | break; |
va009039 | 0:1ed23ab1345f | 593 | default: |
va009039 | 0:1ed23ab1345f | 594 | break; |
va009039 | 0:1ed23ab1345f | 595 | } |
va009039 | 0:1ed23ab1345f | 596 | printf("len %u (0x%02x)\n", len, len); |
va009039 | 0:1ed23ab1345f | 597 | hexdump(&element[pos], len); |
va009039 | 0:1ed23ab1345f | 598 | } else { |
va009039 | 0:1ed23ab1345f | 599 | uint32_t value = 0; |
va009039 | 0:1ed23ab1345f | 600 | switch (de_size) { |
va009039 | 0:1ed23ab1345f | 601 | case DE_SIZE_8: |
va009039 | 0:1ed23ab1345f | 602 | if (de_type != DE_NIL){ |
va009039 | 0:1ed23ab1345f | 603 | value = element[pos]; |
va009039 | 0:1ed23ab1345f | 604 | } |
va009039 | 0:1ed23ab1345f | 605 | break; |
va009039 | 0:1ed23ab1345f | 606 | case DE_SIZE_16: |
va009039 | 0:1ed23ab1345f | 607 | value = READ_NET_16(element,pos); |
va009039 | 0:1ed23ab1345f | 608 | break; |
va009039 | 0:1ed23ab1345f | 609 | case DE_SIZE_32: |
va009039 | 0:1ed23ab1345f | 610 | value = READ_NET_32(element,pos); |
va009039 | 0:1ed23ab1345f | 611 | break; |
va009039 | 0:1ed23ab1345f | 612 | default: |
va009039 | 0:1ed23ab1345f | 613 | break; |
va009039 | 0:1ed23ab1345f | 614 | } |
va009039 | 0:1ed23ab1345f | 615 | printf(", value: 0x%08" PRIx32 "\n", value); |
va009039 | 0:1ed23ab1345f | 616 | } |
va009039 | 0:1ed23ab1345f | 617 | return 0; |
va009039 | 0:1ed23ab1345f | 618 | } |
va009039 | 0:1ed23ab1345f | 619 | |
va009039 | 0:1ed23ab1345f | 620 | void de_dump_data_element(uint8_t * record){ |
va009039 | 0:1ed23ab1345f | 621 | int indent = 0; |
va009039 | 0:1ed23ab1345f | 622 | // hack to get root DES, too. |
va009039 | 0:1ed23ab1345f | 623 | de_type_t type = de_get_element_type(record); |
va009039 | 0:1ed23ab1345f | 624 | de_size_t size = de_get_size_type(record); |
va009039 | 0:1ed23ab1345f | 625 | de_traversal_dump_data(record, type, size, (void*) &indent); |
va009039 | 0:1ed23ab1345f | 626 | } |
va009039 | 0:1ed23ab1345f | 627 | |
va009039 | 0:1ed23ab1345f | 628 | void sdp_create_spp_service(uint8_t *service, int service_id, const char *name){ |
va009039 | 0:1ed23ab1345f | 629 | |
va009039 | 0:1ed23ab1345f | 630 | uint8_t* attribute; |
va009039 | 0:1ed23ab1345f | 631 | de_create_sequence(service); |
va009039 | 0:1ed23ab1345f | 632 | |
va009039 | 0:1ed23ab1345f | 633 | // 0x0000 "Service Record Handle" |
va009039 | 0:1ed23ab1345f | 634 | de_add_number(service, DE_UINT, DE_SIZE_16, SDP_ServiceRecordHandle); |
va009039 | 0:1ed23ab1345f | 635 | de_add_number(service, DE_UINT, DE_SIZE_32, 0x10001); |
va009039 | 0:1ed23ab1345f | 636 | |
va009039 | 0:1ed23ab1345f | 637 | // 0x0001 "Service Class ID List" |
va009039 | 0:1ed23ab1345f | 638 | de_add_number(service, DE_UINT, DE_SIZE_16, SDP_ServiceClassIDList); |
va009039 | 0:1ed23ab1345f | 639 | attribute = de_push_sequence(service); |
va009039 | 0:1ed23ab1345f | 640 | { |
va009039 | 0:1ed23ab1345f | 641 | de_add_number(attribute, DE_UUID, DE_SIZE_16, 0x1101 ); |
va009039 | 0:1ed23ab1345f | 642 | } |
va009039 | 0:1ed23ab1345f | 643 | de_pop_sequence(service, attribute); |
va009039 | 0:1ed23ab1345f | 644 | |
va009039 | 0:1ed23ab1345f | 645 | // 0x0004 "Protocol Descriptor List" |
va009039 | 0:1ed23ab1345f | 646 | de_add_number(service, DE_UINT, DE_SIZE_16, SDP_ProtocolDescriptorList); |
va009039 | 0:1ed23ab1345f | 647 | attribute = de_push_sequence(service); |
va009039 | 0:1ed23ab1345f | 648 | { |
va009039 | 0:1ed23ab1345f | 649 | uint8_t* l2cpProtocol = de_push_sequence(attribute); |
va009039 | 0:1ed23ab1345f | 650 | { |
va009039 | 0:1ed23ab1345f | 651 | de_add_number(l2cpProtocol, DE_UUID, DE_SIZE_16, 0x0100); |
va009039 | 0:1ed23ab1345f | 652 | } |
va009039 | 0:1ed23ab1345f | 653 | de_pop_sequence(attribute, l2cpProtocol); |
va009039 | 0:1ed23ab1345f | 654 | |
va009039 | 0:1ed23ab1345f | 655 | uint8_t* rfcomm = de_push_sequence(attribute); |
va009039 | 0:1ed23ab1345f | 656 | { |
va009039 | 0:1ed23ab1345f | 657 | de_add_number(rfcomm, DE_UUID, DE_SIZE_16, 0x0003); // rfcomm_service |
va009039 | 0:1ed23ab1345f | 658 | de_add_number(rfcomm, DE_UINT, DE_SIZE_8, service_id); // rfcomm channel |
va009039 | 0:1ed23ab1345f | 659 | } |
va009039 | 0:1ed23ab1345f | 660 | de_pop_sequence(attribute, rfcomm); |
va009039 | 0:1ed23ab1345f | 661 | } |
va009039 | 0:1ed23ab1345f | 662 | de_pop_sequence(service, attribute); |
va009039 | 0:1ed23ab1345f | 663 | |
va009039 | 0:1ed23ab1345f | 664 | // 0x0005 "Public Browse Group" |
va009039 | 0:1ed23ab1345f | 665 | de_add_number(service, DE_UINT, DE_SIZE_16, SDP_BrowseGroupList); // public browse group |
va009039 | 0:1ed23ab1345f | 666 | attribute = de_push_sequence(service); |
va009039 | 0:1ed23ab1345f | 667 | { |
va009039 | 0:1ed23ab1345f | 668 | de_add_number(attribute, DE_UUID, DE_SIZE_16, 0x1002 ); |
va009039 | 0:1ed23ab1345f | 669 | } |
va009039 | 0:1ed23ab1345f | 670 | de_pop_sequence(service, attribute); |
va009039 | 0:1ed23ab1345f | 671 | |
va009039 | 0:1ed23ab1345f | 672 | // 0x0006 |
va009039 | 0:1ed23ab1345f | 673 | de_add_number(service, DE_UINT, DE_SIZE_16, SDP_LanguageBaseAttributeIDList); |
va009039 | 0:1ed23ab1345f | 674 | attribute = de_push_sequence(service); |
va009039 | 0:1ed23ab1345f | 675 | { |
va009039 | 0:1ed23ab1345f | 676 | de_add_number(attribute, DE_UINT, DE_SIZE_16, 0x656e); |
va009039 | 0:1ed23ab1345f | 677 | de_add_number(attribute, DE_UINT, DE_SIZE_16, 0x006a); |
va009039 | 0:1ed23ab1345f | 678 | de_add_number(attribute, DE_UINT, DE_SIZE_16, 0x0100); |
va009039 | 0:1ed23ab1345f | 679 | } |
va009039 | 0:1ed23ab1345f | 680 | de_pop_sequence(service, attribute); |
va009039 | 0:1ed23ab1345f | 681 | |
va009039 | 0:1ed23ab1345f | 682 | // 0x0009 "Bluetooth Profile Descriptor List" |
va009039 | 0:1ed23ab1345f | 683 | de_add_number(service, DE_UINT, DE_SIZE_16, SDP_BluetoothProfileDescriptorList); |
va009039 | 0:1ed23ab1345f | 684 | attribute = de_push_sequence(service); |
va009039 | 0:1ed23ab1345f | 685 | { |
va009039 | 0:1ed23ab1345f | 686 | uint8_t *sppProfile = de_push_sequence(attribute); |
va009039 | 0:1ed23ab1345f | 687 | { |
va009039 | 0:1ed23ab1345f | 688 | de_add_number(sppProfile, DE_UUID, DE_SIZE_16, 0x1101); |
va009039 | 0:1ed23ab1345f | 689 | de_add_number(sppProfile, DE_UINT, DE_SIZE_16, 0x0100); |
va009039 | 0:1ed23ab1345f | 690 | } |
va009039 | 0:1ed23ab1345f | 691 | de_pop_sequence(attribute, sppProfile); |
va009039 | 0:1ed23ab1345f | 692 | } |
va009039 | 0:1ed23ab1345f | 693 | de_pop_sequence(service, attribute); |
va009039 | 0:1ed23ab1345f | 694 | |
va009039 | 0:1ed23ab1345f | 695 | // 0x0100 "ServiceName" |
va009039 | 0:1ed23ab1345f | 696 | de_add_number(service, DE_UINT, DE_SIZE_16, 0x0100); |
va009039 | 0:1ed23ab1345f | 697 | de_add_data(service, DE_STRING, strlen(name), (uint8_t *) name); |
va009039 | 0:1ed23ab1345f | 698 | } |