Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Fork of nRF51822 by
btle/custom/custom_helper.cpp@10:68c0e6cabe07, 2014-05-29 (annotated)
- Committer:
- Rohit Grover
- Date:
- Thu May 29 08:07:04 2014 +0100
- Revision:
- 10:68c0e6cabe07
- Parent:
- 9:3794dc9540f0
- Child:
- 12:e151f55035b8
add a functional UUID cache
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
bogdanm | 0:eff01767de02 | 1 | /* mbed Microcontroller Library |
bogdanm | 0:eff01767de02 | 2 | * Copyright (c) 2006-2013 ARM Limited |
bogdanm | 0:eff01767de02 | 3 | * |
bogdanm | 0:eff01767de02 | 4 | * Licensed under the Apache License, Version 2.0 (the "License"); |
bogdanm | 0:eff01767de02 | 5 | * you may not use this file except in compliance with the License. |
bogdanm | 0:eff01767de02 | 6 | * You may obtain a copy of the License at |
bogdanm | 0:eff01767de02 | 7 | * |
bogdanm | 0:eff01767de02 | 8 | * http://www.apache.org/licenses/LICENSE-2.0 |
bogdanm | 0:eff01767de02 | 9 | * |
bogdanm | 0:eff01767de02 | 10 | * Unless required by applicable law or agreed to in writing, software |
bogdanm | 0:eff01767de02 | 11 | * distributed under the License is distributed on an "AS IS" BASIS, |
bogdanm | 0:eff01767de02 | 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
bogdanm | 0:eff01767de02 | 13 | * See the License for the specific language governing permissions and |
bogdanm | 0:eff01767de02 | 14 | * limitations under the License. |
bogdanm | 0:eff01767de02 | 15 | */ |
bogdanm | 0:eff01767de02 | 16 | |
bogdanm | 0:eff01767de02 | 17 | #include "custom_helper.h" |
bogdanm | 0:eff01767de02 | 18 | |
Rohit Grover |
8:2214f1df6a6a | 19 | /** |
Rohit Grover |
10:68c0e6cabe07 | 20 | * Types and data structures involved in maintaining a local cache of 128-bit |
Rohit Grover |
10:68c0e6cabe07 | 21 | * UUIDs which have been added to the nRF using SVC calls previously. |
Rohit Grover |
10:68c0e6cabe07 | 22 | */ |
Rohit Grover |
10:68c0e6cabe07 | 23 | typedef struct { |
Rohit Grover |
10:68c0e6cabe07 | 24 | uint8_t uuid[UUID::LENGTH_OF_LONG_UUID]; |
Rohit Grover |
10:68c0e6cabe07 | 25 | uint8_t type; |
Rohit Grover |
10:68c0e6cabe07 | 26 | } converted_uuid_table_entry_t; |
Rohit Grover |
10:68c0e6cabe07 | 27 | static const unsigned UUID_TABLE_MAX_ENTRIES = 8; /* This is the maximum number |
Rohit Grover |
10:68c0e6cabe07 | 28 | * of 128-bit UUIDs with distinct bases that |
Rohit Grover |
10:68c0e6cabe07 | 29 | * we expect to be in use; increase this |
Rohit Grover |
10:68c0e6cabe07 | 30 | * limit if needed. */ |
Rohit Grover |
10:68c0e6cabe07 | 31 | static unsigned uuidTableEntries = 0; /* current usage of the table */ |
Rohit Grover |
10:68c0e6cabe07 | 32 | converted_uuid_table_entry_t convertedUUIDTable[UUID_TABLE_MAX_ENTRIES]; |
Rohit Grover |
10:68c0e6cabe07 | 33 | |
Rohit Grover |
10:68c0e6cabe07 | 34 | /** |
Rohit Grover |
9:3794dc9540f0 | 35 | * lookup the cache of previously converted 128-bit UUIDs to find a type value. |
Rohit Grover |
9:3794dc9540f0 | 36 | * @param uuid long UUID |
Rohit Grover |
9:3794dc9540f0 | 37 | * @param recoveredType the type field of the 3-byte nRF's uuid. |
Rohit Grover |
9:3794dc9540f0 | 38 | * @return true if a match is found. |
Rohit Grover |
9:3794dc9540f0 | 39 | */ |
Rohit Grover |
9:3794dc9540f0 | 40 | static bool |
Rohit Grover |
9:3794dc9540f0 | 41 | lookupConvertedUUIDTable(const uint8_t uuid[UUID::LENGTH_OF_LONG_UUID], |
Rohit Grover |
10:68c0e6cabe07 | 42 | uint8_t *recoveredType) |
Rohit Grover |
9:3794dc9540f0 | 43 | { |
Rohit Grover |
10:68c0e6cabe07 | 44 | unsigned i; |
Rohit Grover |
10:68c0e6cabe07 | 45 | for (i = 0; i < uuidTableEntries; i++) { |
Rohit Grover |
10:68c0e6cabe07 | 46 | if (memcmp(convertedUUIDTable[i].uuid, |
Rohit Grover |
10:68c0e6cabe07 | 47 | uuid, |
Rohit Grover |
10:68c0e6cabe07 | 48 | UUID::LENGTH_OF_LONG_UUID) == 0) { |
Rohit Grover |
10:68c0e6cabe07 | 49 | *recoveredType = convertedUUIDTable[i].type; |
Rohit Grover |
10:68c0e6cabe07 | 50 | return true; |
Rohit Grover |
10:68c0e6cabe07 | 51 | } |
Rohit Grover |
10:68c0e6cabe07 | 52 | } |
Rohit Grover |
10:68c0e6cabe07 | 53 | |
Rohit Grover |
9:3794dc9540f0 | 54 | return false; |
Rohit Grover |
9:3794dc9540f0 | 55 | } |
Rohit Grover |
9:3794dc9540f0 | 56 | |
Rohit Grover |
9:3794dc9540f0 | 57 | static void |
Rohit Grover |
9:3794dc9540f0 | 58 | addToConvertedUUIDTable(const uint8_t uuid[UUID::LENGTH_OF_LONG_UUID], |
Rohit Grover |
10:68c0e6cabe07 | 59 | uint8_t type) |
Rohit Grover |
9:3794dc9540f0 | 60 | { |
Rohit Grover |
10:68c0e6cabe07 | 61 | if (uuidTableEntries == UUID_TABLE_MAX_ENTRIES) { |
Rohit Grover |
10:68c0e6cabe07 | 62 | return; /* recovery needed; or at least the user should be |
Rohit Grover |
10:68c0e6cabe07 | 63 | * warned about this fact.*/ |
Rohit Grover |
10:68c0e6cabe07 | 64 | } |
Rohit Grover |
10:68c0e6cabe07 | 65 | |
Rohit Grover |
10:68c0e6cabe07 | 66 | memcpy(convertedUUIDTable[uuidTableEntries].uuid, |
Rohit Grover |
10:68c0e6cabe07 | 67 | uuid, |
Rohit Grover |
10:68c0e6cabe07 | 68 | UUID::LENGTH_OF_LONG_UUID); |
Rohit Grover |
10:68c0e6cabe07 | 69 | convertedUUIDTable[uuidTableEntries].type = type; |
Rohit Grover |
10:68c0e6cabe07 | 70 | uuidTableEntries++; |
Rohit Grover |
9:3794dc9540f0 | 71 | } |
Rohit Grover |
9:3794dc9540f0 | 72 | |
Rohit Grover |
9:3794dc9540f0 | 73 | /** |
Rohit Grover |
8:2214f1df6a6a | 74 | * The nRF transport has its own 3-byte representation of a UUID. If the user- |
Rohit Grover |
8:2214f1df6a6a | 75 | * specified UUID is 128-bits wide, then the UUID base needs to be added to the |
Rohit Grover |
8:2214f1df6a6a | 76 | * soft-device and converted to a 3-byte handle before being used further. This |
Rohit Grover |
8:2214f1df6a6a | 77 | * function is responsible for this translation of user-specified UUIDs into |
Rohit Grover |
8:2214f1df6a6a | 78 | * nRF's representation. |
Rohit Grover |
8:2214f1df6a6a | 79 | * |
Rohit Grover |
8:2214f1df6a6a | 80 | * @param[in] uuid |
Rohit Grover |
8:2214f1df6a6a | 81 | * user-specified UUID |
Rohit Grover |
8:2214f1df6a6a | 82 | * @return nRF |
Rohit Grover |
8:2214f1df6a6a | 83 | * 3-byte UUID (containing a type and 16-bit UUID) representation |
Rohit Grover |
8:2214f1df6a6a | 84 | * to be used with SVC calls. |
Rohit Grover |
8:2214f1df6a6a | 85 | */ |
Rohit Grover |
8:2214f1df6a6a | 86 | ble_uuid_t custom_convert_to_transport_uuid(const UUID &uuid) |
Rohit Grover |
8:2214f1df6a6a | 87 | { |
Rohit Grover |
10:68c0e6cabe07 | 88 | ble_uuid_t nordicUUID = { |
Rohit Grover |
8:2214f1df6a6a | 89 | .uuid = uuid.value, |
Rohit Grover |
8:2214f1df6a6a | 90 | .type = BLE_UUID_TYPE_UNKNOWN /* to be set below */ |
Rohit Grover |
8:2214f1df6a6a | 91 | }; |
Rohit Grover |
8:2214f1df6a6a | 92 | |
Rohit Grover |
8:2214f1df6a6a | 93 | if (uuid.type == UUID::UUID_TYPE_SHORT) { |
Rohit Grover |
10:68c0e6cabe07 | 94 | nordicUUID.type = BLE_UUID_TYPE_BLE; |
Rohit Grover |
8:2214f1df6a6a | 95 | } else { |
Rohit Grover |
10:68c0e6cabe07 | 96 | if (!lookupConvertedUUIDTable(uuid.base, &nordicUUID.type)) { |
Rohit Grover |
10:68c0e6cabe07 | 97 | nordicUUID.type = custom_add_uuid_base(uuid.base); |
Rohit Grover |
10:68c0e6cabe07 | 98 | addToConvertedUUIDTable(uuid.base, nordicUUID.type); |
Rohit Grover |
9:3794dc9540f0 | 99 | } |
Rohit Grover |
8:2214f1df6a6a | 100 | } |
Rohit Grover |
8:2214f1df6a6a | 101 | |
Rohit Grover |
10:68c0e6cabe07 | 102 | return nordicUUID; |
Rohit Grover |
8:2214f1df6a6a | 103 | } |
Rohit Grover |
8:2214f1df6a6a | 104 | |
bogdanm | 0:eff01767de02 | 105 | /**************************************************************************/ |
bogdanm | 0:eff01767de02 | 106 | /*! |
bogdanm | 0:eff01767de02 | 107 | @brief Adds the base UUID to the custom service. All UUIDs used |
bogdanm | 0:eff01767de02 | 108 | by this service are based on this 128-bit UUID. |
Rohit Grover |
6:bbb4357dc135 | 109 | |
bogdanm | 0:eff01767de02 | 110 | @note This UUID needs to be added to the SoftDevice stack before |
bogdanm | 0:eff01767de02 | 111 | adding the service's primary service via |
bogdanm | 0:eff01767de02 | 112 | 'sd_ble_gatts_service_add' |
bogdanm | 0:eff01767de02 | 113 | |
bogdanm | 0:eff01767de02 | 114 | @param[in] p_uuid_base A pointer to the 128-bit UUID array (8*16) |
Rohit Grover |
6:bbb4357dc135 | 115 | |
bogdanm | 0:eff01767de02 | 116 | @returns The UUID type. |
bogdanm | 0:eff01767de02 | 117 | A return value of 0 should be considered an error. |
Rohit Grover |
6:bbb4357dc135 | 118 | |
bogdanm | 0:eff01767de02 | 119 | @retval 0x00 BLE_UUID_TYPE_UNKNOWN |
bogdanm | 0:eff01767de02 | 120 | @retval 0x01 BLE_UUID_TYPE_BLE |
bogdanm | 0:eff01767de02 | 121 | @retval 0x02 BLE_UUID_TYPE_VENDOR_BEGIN |
Rohit Grover |
6:bbb4357dc135 | 122 | |
bogdanm | 0:eff01767de02 | 123 | @section EXAMPLE |
bogdanm | 0:eff01767de02 | 124 | @code |
bogdanm | 0:eff01767de02 | 125 | |
bogdanm | 0:eff01767de02 | 126 | // Take note that bytes 2/3 are blank since these are used to identify |
bogdanm | 0:eff01767de02 | 127 | // the primary service and individual characteristics |
bogdanm | 0:eff01767de02 | 128 | #define CFG_CUSTOM_UUID_BASE "\x6E\x40\x00\x00\xB5\xA3\xF3\x93\xE0\xA9\xE5\x0E\x24\xDC\xCA\x9E" |
Rohit Grover |
6:bbb4357dc135 | 129 | |
bogdanm | 0:eff01767de02 | 130 | uint8_t uuid_type = custom_add_uuid_base(CFG_CUSTOM_UUID_BASE); |
bogdanm | 0:eff01767de02 | 131 | ASSERT(uuid_type > 0, ERROR_NOT_FOUND); |
Rohit Grover |
6:bbb4357dc135 | 132 | |
bogdanm | 0:eff01767de02 | 133 | // We can now safely add the primary service and any characteristics |
bogdanm | 0:eff01767de02 | 134 | // for our custom service ... |
Rohit Grover |
6:bbb4357dc135 | 135 | |
bogdanm | 0:eff01767de02 | 136 | @endcode |
bogdanm | 0:eff01767de02 | 137 | */ |
bogdanm | 0:eff01767de02 | 138 | /**************************************************************************/ |
Rohit Grover |
6:bbb4357dc135 | 139 | uint8_t custom_add_uuid_base(uint8_t const *const p_uuid_base) |
bogdanm | 0:eff01767de02 | 140 | { |
Rohit Grover |
6:bbb4357dc135 | 141 | ble_uuid128_t base_uuid; |
Rohit Grover |
6:bbb4357dc135 | 142 | uint8_t uuid_type = 0; |
bogdanm | 0:eff01767de02 | 143 | |
Rohit Grover |
6:bbb4357dc135 | 144 | /* Reverse the bytes since ble_uuid128_t is LSB */ |
Rohit Grover |
6:bbb4357dc135 | 145 | for (uint8_t i = 0; i<16; i++) { |
Rohit Grover |
6:bbb4357dc135 | 146 | base_uuid.uuid128[i] = p_uuid_base[15 - i]; |
Rohit Grover |
6:bbb4357dc135 | 147 | } |
bogdanm | 0:eff01767de02 | 148 | |
Rohit Grover |
6:bbb4357dc135 | 149 | ASSERT_INT( ERROR_NONE, sd_ble_uuid_vs_add( &base_uuid, &uuid_type ), 0); |
bogdanm | 0:eff01767de02 | 150 | |
Rohit Grover |
6:bbb4357dc135 | 151 | return uuid_type; |
bogdanm | 0:eff01767de02 | 152 | } |
bogdanm | 0:eff01767de02 | 153 | |
bogdanm | 0:eff01767de02 | 154 | /**************************************************************************/ |
bogdanm | 0:eff01767de02 | 155 | /*! |
bogdanm | 0:eff01767de02 | 156 | |
bogdanm | 0:eff01767de02 | 157 | */ |
bogdanm | 0:eff01767de02 | 158 | /**************************************************************************/ |
Rohit Grover |
6:bbb4357dc135 | 159 | error_t custom_decode_uuid_base(uint8_t const *const p_uuid_base, |
Rohit Grover |
6:bbb4357dc135 | 160 | ble_uuid_t *p_uuid) |
bogdanm | 0:eff01767de02 | 161 | { |
Rohit Grover |
6:bbb4357dc135 | 162 | uint8_t uuid_base_le[16]; |
bogdanm | 0:eff01767de02 | 163 | |
Rohit Grover |
6:bbb4357dc135 | 164 | /* Reverse the bytes since ble_uuid128_t is LSB */ |
Rohit Grover |
6:bbb4357dc135 | 165 | for (uint8_t i = 0; i<16; i++) { |
Rohit Grover |
6:bbb4357dc135 | 166 | uuid_base_le[i] = p_uuid_base[15 - i]; |
Rohit Grover |
6:bbb4357dc135 | 167 | } |
bogdanm | 0:eff01767de02 | 168 | |
Rohit Grover |
6:bbb4357dc135 | 169 | ASSERT_STATUS( sd_ble_uuid_decode(16, uuid_base_le, p_uuid)); |
bogdanm | 0:eff01767de02 | 170 | |
Rohit Grover |
6:bbb4357dc135 | 171 | return ERROR_NONE; |
bogdanm | 0:eff01767de02 | 172 | } |
bogdanm | 0:eff01767de02 | 173 | |
bogdanm | 0:eff01767de02 | 174 | /**************************************************************************/ |
bogdanm | 0:eff01767de02 | 175 | /*! |
bogdanm | 0:eff01767de02 | 176 | @brief Adds a new characteristic to the custom service, assigning |
bogdanm | 0:eff01767de02 | 177 | properties, a UUID add-on value, etc. |
bogdanm | 0:eff01767de02 | 178 | |
bogdanm | 0:eff01767de02 | 179 | @param[in] service_handle |
bogdanm | 0:eff01767de02 | 180 | @param[in] p_uuid The 16-bit value to add to the base UUID |
bogdanm | 0:eff01767de02 | 181 | for this characteristic (normally >1 |
bogdanm | 0:eff01767de02 | 182 | since 1 is typically used by the primary |
bogdanm | 0:eff01767de02 | 183 | service). |
bogdanm | 0:eff01767de02 | 184 | @param[in] char_props The characteristic properties, as |
bogdanm | 0:eff01767de02 | 185 | defined by ble_gatt_char_props_t |
bogdanm | 0:eff01767de02 | 186 | @param[in] max_length The maximum length of this characeristic |
bogdanm | 0:eff01767de02 | 187 | @param[in] p_char_handle |
Rohit Grover |
6:bbb4357dc135 | 188 | |
bogdanm | 0:eff01767de02 | 189 | @returns |
bogdanm | 0:eff01767de02 | 190 | @retval ERROR_NONE Everything executed normally |
bogdanm | 0:eff01767de02 | 191 | */ |
bogdanm | 0:eff01767de02 | 192 | /**************************************************************************/ |
Rohit Grover |
6:bbb4357dc135 | 193 | error_t custom_add_in_characteristic(uint16_t service_handle, |
Rohit Grover |
6:bbb4357dc135 | 194 | ble_uuid_t *p_uuid, |
Rohit Grover |
6:bbb4357dc135 | 195 | uint8_t properties, |
Rohit Grover |
6:bbb4357dc135 | 196 | uint8_t *p_data, |
Rohit Grover |
6:bbb4357dc135 | 197 | uint16_t min_length, |
Rohit Grover |
6:bbb4357dc135 | 198 | uint16_t max_length, |
Rohit Grover |
6:bbb4357dc135 | 199 | ble_gatts_char_handles_t *p_char_handle) |
bogdanm | 0:eff01767de02 | 200 | { |
Rohit Grover |
6:bbb4357dc135 | 201 | /* Characteristic metadata */ |
Rohit Grover |
6:bbb4357dc135 | 202 | ble_gatts_attr_md_t cccd_md; |
Rohit Grover |
6:bbb4357dc135 | 203 | ble_gatt_char_props_t char_props; |
bogdanm | 0:eff01767de02 | 204 | |
Rohit Grover |
6:bbb4357dc135 | 205 | memcpy(&char_props, &properties, 1); |
bogdanm | 0:eff01767de02 | 206 | |
Rohit Grover |
6:bbb4357dc135 | 207 | if (char_props.notify || char_props.indicate) { |
Rohit Grover |
6:bbb4357dc135 | 208 | /* Notification requires cccd */ |
Rohit Grover |
6:bbb4357dc135 | 209 | memclr_( &cccd_md, sizeof(ble_gatts_attr_md_t)); |
Rohit Grover |
6:bbb4357dc135 | 210 | cccd_md.vloc = BLE_GATTS_VLOC_STACK; |
Rohit Grover |
6:bbb4357dc135 | 211 | BLE_GAP_CONN_SEC_MODE_SET_OPEN(&cccd_md.read_perm); |
Rohit Grover |
6:bbb4357dc135 | 212 | BLE_GAP_CONN_SEC_MODE_SET_OPEN(&cccd_md.write_perm); |
Rohit Grover |
6:bbb4357dc135 | 213 | } |
bogdanm | 0:eff01767de02 | 214 | |
Rohit Grover |
6:bbb4357dc135 | 215 | ble_gatts_char_md_t char_md = {0}; |
bogdanm | 0:eff01767de02 | 216 | |
Rohit Grover |
6:bbb4357dc135 | 217 | char_md.char_props = char_props; |
Rohit Grover |
6:bbb4357dc135 | 218 | char_md.p_cccd_md = |
Rohit Grover |
6:bbb4357dc135 | 219 | (char_props.notify || char_props.indicate) ? &cccd_md : NULL; |
bogdanm | 0:eff01767de02 | 220 | |
Rohit Grover |
6:bbb4357dc135 | 221 | /* Attribute declaration */ |
Rohit Grover |
6:bbb4357dc135 | 222 | ble_gatts_attr_md_t attr_md = {0}; |
bogdanm | 0:eff01767de02 | 223 | |
Rohit Grover |
6:bbb4357dc135 | 224 | attr_md.vloc = BLE_GATTS_VLOC_STACK; |
Rohit Grover |
6:bbb4357dc135 | 225 | attr_md.vlen = (min_length == max_length) ? 0 : 1; |
bogdanm | 0:eff01767de02 | 226 | |
Rohit Grover |
6:bbb4357dc135 | 227 | if (char_props.read || char_props.notify || char_props.indicate) { |
Rohit Grover |
6:bbb4357dc135 | 228 | BLE_GAP_CONN_SEC_MODE_SET_OPEN(&attr_md.read_perm); |
Rohit Grover |
6:bbb4357dc135 | 229 | } |
Rohit Grover |
6:bbb4357dc135 | 230 | |
Rohit Grover |
6:bbb4357dc135 | 231 | if (char_props.write) { |
Rohit Grover |
6:bbb4357dc135 | 232 | BLE_GAP_CONN_SEC_MODE_SET_OPEN(&attr_md.write_perm); |
Rohit Grover |
6:bbb4357dc135 | 233 | } |
bogdanm | 0:eff01767de02 | 234 | |
Rohit Grover |
6:bbb4357dc135 | 235 | ble_gatts_attr_t attr_char_value = {0}; |
bogdanm | 0:eff01767de02 | 236 | |
Rohit Grover |
6:bbb4357dc135 | 237 | attr_char_value.p_uuid = p_uuid; |
Rohit Grover |
6:bbb4357dc135 | 238 | attr_char_value.p_attr_md = &attr_md; |
Rohit Grover |
6:bbb4357dc135 | 239 | attr_char_value.init_len = min_length; |
Rohit Grover |
6:bbb4357dc135 | 240 | attr_char_value.max_len = max_length; |
Rohit Grover |
6:bbb4357dc135 | 241 | attr_char_value.p_value = p_data; |
bogdanm | 0:eff01767de02 | 242 | |
bogdanm | 0:eff01767de02 | 243 | |
Rohit Grover |
6:bbb4357dc135 | 244 | ASSERT_STATUS ( sd_ble_gatts_characteristic_add(service_handle, |
Rohit Grover |
6:bbb4357dc135 | 245 | &char_md, |
Rohit Grover |
6:bbb4357dc135 | 246 | &attr_char_value, |
Rohit Grover |
6:bbb4357dc135 | 247 | p_char_handle)); |
bogdanm | 0:eff01767de02 | 248 | |
Rohit Grover |
6:bbb4357dc135 | 249 | return ERROR_NONE; |
bogdanm | 0:eff01767de02 | 250 | } |