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
custom_helper.cpp
00001 /* mbed Microcontroller Library 00002 * Copyright (c) 2006-2013 ARM Limited 00003 * 00004 * Licensed under the Apache License, Version 2.0 (the "License"); 00005 * you may not use this file except in compliance with the License. 00006 * You may obtain a copy of the License at 00007 * 00008 * http://www.apache.org/licenses/LICENSE-2.0 00009 * 00010 * Unless required by applicable law or agreed to in writing, software 00011 * distributed under the License is distributed on an "AS IS" BASIS, 00012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 00013 * See the License for the specific language governing permissions and 00014 * limitations under the License. 00015 */ 00016 00017 #include "custom_helper.h" 00018 00019 /* 00020 * The current version of the soft-device doesn't handle duplicate 128-bit UUIDs 00021 * very well. It is therefore necessary to filter away duplicates before 00022 * passing long UUIDs to sd_ble_uuid_vs_add(). The following types and data 00023 * structures involved in maintaining a local cache of 128-bit UUIDs. 00024 */ 00025 typedef struct { 00026 UUID::LongUUIDBytes_t uuid; 00027 uint8_t type; 00028 } converted_uuid_table_entry_t; 00029 static const unsigned UUID_TABLE_MAX_ENTRIES = 4; /* This is the maximum number of 128-bit UUIDs with distinct bases that 00030 * we expect to be in use; increase this limit if needed. */ 00031 static unsigned uuidTableEntries = 0; /* current usage of the table */ 00032 converted_uuid_table_entry_t convertedUUIDTable[UUID_TABLE_MAX_ENTRIES]; 00033 00034 /** 00035 * lookup the cache of previously converted 128-bit UUIDs to find a type value. 00036 * @param uuid base 128-bit UUID 00037 * @param recoveredType the type field of the 3-byte nRF's uuid. 00038 * @return true if a match is found. 00039 */ 00040 static bool 00041 lookupConvertedUUIDTable(const UUID::LongUUIDBytes_t uuid, uint8_t *recoveredType) 00042 { 00043 unsigned i; 00044 for (i = 0; i < uuidTableEntries; i++) { 00045 unsigned byteIndex; 00046 for (byteIndex = 0; byteIndex < UUID::LENGTH_OF_LONG_UUID; byteIndex++) { 00047 /* Skip bytes 2 and 3, because they contain the shortUUID (16-bit) version of the 00048 * long UUID; and we're comparing against the remainder. */ 00049 if ((byteIndex == 2) || (byteIndex == 3)) { 00050 continue; 00051 } 00052 00053 if (convertedUUIDTable[i].uuid[byteIndex] != uuid[byteIndex]) { 00054 break; 00055 } 00056 } 00057 00058 if (byteIndex == UUID::LENGTH_OF_LONG_UUID) { 00059 *recoveredType = convertedUUIDTable[i].type; 00060 return true; 00061 } 00062 } 00063 00064 return false; 00065 } 00066 00067 static void 00068 addToConvertedUUIDTable(const UUID::LongUUIDBytes_t uuid, uint8_t type) 00069 { 00070 if (uuidTableEntries == UUID_TABLE_MAX_ENTRIES) { 00071 return; /* recovery needed; or at least the user should be warned about this fact.*/ 00072 } 00073 00074 memcpy(convertedUUIDTable[uuidTableEntries].uuid, uuid, UUID::LENGTH_OF_LONG_UUID); 00075 convertedUUIDTable[uuidTableEntries].uuid[2] = 0; 00076 convertedUUIDTable[uuidTableEntries].uuid[3] = 0; 00077 convertedUUIDTable[uuidTableEntries].type = type; 00078 uuidTableEntries++; 00079 } 00080 00081 /** 00082 * The nRF transport has its own 3-byte representation of a UUID. If the user- 00083 * specified UUID is 128-bits wide, then the UUID base needs to be added to the 00084 * soft-device and converted to a 3-byte handle before being used further. This 00085 * function is responsible for this translation of user-specified UUIDs into 00086 * nRF's representation. 00087 * 00088 * @param[in] uuid 00089 * user-specified UUID 00090 * @return nRF 00091 * 3-byte UUID (containing a type and 16-bit UUID) representation 00092 * to be used with SVC calls. 00093 */ 00094 ble_uuid_t custom_convert_to_nordic_uuid(const UUID &uuid) 00095 { 00096 ble_uuid_t nordicUUID; 00097 nordicUUID.uuid = uuid.getShortUUID(); 00098 nordicUUID.type = BLE_UUID_TYPE_UNKNOWN; /* to be set below */ 00099 00100 if (uuid.shortOrLong() == UUID::UUID_TYPE_SHORT) { 00101 nordicUUID.type = BLE_UUID_TYPE_BLE; 00102 } else { 00103 if (!lookupConvertedUUIDTable(uuid.getBaseUUID(), &nordicUUID.type)) { 00104 nordicUUID.type = custom_add_uuid_base(uuid.getBaseUUID()); 00105 addToConvertedUUIDTable(uuid.getBaseUUID(), nordicUUID.type); 00106 } 00107 } 00108 00109 return nordicUUID; 00110 } 00111 00112 /**************************************************************************/ 00113 /*! 00114 @brief Adds the base UUID to the custom service. All UUIDs used 00115 by this service are based on this 128-bit UUID. 00116 00117 @note This UUID needs to be added to the SoftDevice stack before 00118 adding the service's primary service via 00119 'sd_ble_gatts_service_add' 00120 00121 @param[in] p_uuid_base A pointer to the 128-bit UUID array (8*16) 00122 00123 @returns The UUID type. 00124 A return value of 0 should be considered an error. 00125 00126 @retval 0x00 BLE_UUID_TYPE_UNKNOWN 00127 @retval 0x01 BLE_UUID_TYPE_BLE 00128 @retval 0x02 BLE_UUID_TYPE_VENDOR_BEGIN 00129 00130 @section EXAMPLE 00131 @code 00132 00133 // Take note that bytes 2/3 are blank since these are used to identify 00134 // the primary service and individual characteristics 00135 #define CFG_CUSTOM_UUID_BASE "\x6E\x40\x00\x00\xB5\xA3\xF3\x93\xE0\xA9\xE5\x0E\x24\xDC\xCA\x9E" 00136 00137 uint8_t uuid_type = custom_add_uuid_base(CFG_CUSTOM_UUID_BASE); 00138 ASSERT(uuid_type > 0, ERROR_NOT_FOUND); 00139 00140 // We can now safely add the primary service and any characteristics 00141 // for our custom service ... 00142 00143 @endcode 00144 */ 00145 /**************************************************************************/ 00146 uint8_t custom_add_uuid_base(uint8_t const *const p_uuid_base) 00147 { 00148 ble_uuid128_t base_uuid; 00149 uint8_t uuid_type = 0; 00150 00151 for (unsigned i = 0; i < UUID::LENGTH_OF_LONG_UUID; i++) { 00152 base_uuid.uuid128[i] = p_uuid_base[i]; 00153 } 00154 00155 ASSERT_INT( ERROR_NONE, sd_ble_uuid_vs_add( &base_uuid, &uuid_type ), 0); 00156 00157 return uuid_type; 00158 } 00159 00160 /**************************************************************************/ 00161 /*! 00162 00163 */ 00164 /**************************************************************************/ 00165 error_t custom_decode_uuid_base(uint8_t const *const p_uuid_base, 00166 ble_uuid_t *p_uuid) 00167 { 00168 UUID::LongUUIDBytes_t uuid_base_le; 00169 00170 for (uint8_t i = 0; i < UUID::LENGTH_OF_LONG_UUID; i++) { 00171 uuid_base_le[i] = p_uuid_base[i]; 00172 } 00173 00174 ASSERT_STATUS( sd_ble_uuid_decode(UUID::LENGTH_OF_LONG_UUID, uuid_base_le, p_uuid)); 00175 00176 return ERROR_NONE; 00177 } 00178 00179 /**************************************************************************/ 00180 /*! 00181 @brief Adds a new characteristic to the custom service, assigning 00182 properties, a UUID add-on value, etc. 00183 00184 @param[in] service_handle 00185 @param[in] p_uuid The 16-bit value to add to the base UUID 00186 for this characteristic (normally >1 00187 since 1 is typically used by the primary 00188 service). 00189 @param[in] char_props The characteristic properties, as 00190 defined by ble_gatt_char_props_t 00191 @param[in] max_length The maximum length of this characeristic 00192 @param[in] has_variable_len Whether the characteristic data has 00193 variable length. 00194 @param[out] p_char_handle 00195 00196 @returns 00197 @retval ERROR_NONE Everything executed normally 00198 */ 00199 /**************************************************************************/ 00200 error_t custom_add_in_characteristic(uint16_t service_handle, 00201 ble_uuid_t *p_uuid, 00202 uint8_t properties, 00203 SecurityManager::SecurityMode_t requiredSecurity, 00204 uint8_t *p_data, 00205 uint16_t length, 00206 uint16_t max_length, 00207 bool has_variable_len, 00208 const uint8_t *userDescriptionDescriptorValuePtr, 00209 uint16_t userDescriptionDescriptorValueLen, 00210 bool readAuthorization, 00211 bool writeAuthorization, 00212 ble_gatts_char_handles_t *p_char_handle) 00213 { 00214 /* Characteristic metadata */ 00215 ble_gatts_attr_md_t cccd_md; 00216 ble_gatt_char_props_t char_props; 00217 00218 memcpy(&char_props, &properties, 1); 00219 00220 if (char_props.notify || char_props.indicate) { 00221 /* Notification requires cccd */ 00222 memclr_( &cccd_md, sizeof(ble_gatts_attr_md_t)); 00223 cccd_md.vloc = BLE_GATTS_VLOC_STACK; 00224 BLE_GAP_CONN_SEC_MODE_SET_OPEN(&cccd_md.read_perm); 00225 switch (requiredSecurity) { 00226 case SecurityManager::SECURITY_MODE_ENCRYPTION_OPEN_LINK : 00227 BLE_GAP_CONN_SEC_MODE_SET_OPEN(&cccd_md.write_perm); 00228 break; 00229 case SecurityManager::SECURITY_MODE_ENCRYPTION_NO_MITM : 00230 BLE_GAP_CONN_SEC_MODE_SET_ENC_NO_MITM(&cccd_md.write_perm); 00231 break; 00232 case SecurityManager::SECURITY_MODE_ENCRYPTION_WITH_MITM : 00233 BLE_GAP_CONN_SEC_MODE_SET_ENC_WITH_MITM(&cccd_md.write_perm); 00234 break; 00235 case SecurityManager::SECURITY_MODE_SIGNED_NO_MITM : 00236 BLE_GAP_CONN_SEC_MODE_SET_SIGNED_NO_MITM(&cccd_md.write_perm); 00237 break; 00238 case SecurityManager::SECURITY_MODE_SIGNED_WITH_MITM : 00239 BLE_GAP_CONN_SEC_MODE_SET_SIGNED_WITH_MITM(&cccd_md.write_perm); 00240 break; 00241 default: 00242 BLE_GAP_CONN_SEC_MODE_SET_OPEN(&cccd_md.write_perm); 00243 break; 00244 } 00245 } 00246 00247 ble_gatts_char_md_t char_md = {0}; 00248 00249 char_md.char_props = char_props; 00250 char_md.p_cccd_md = 00251 (char_props.notify || char_props.indicate) ? &cccd_md : NULL; 00252 if ((userDescriptionDescriptorValueLen > 0) && (userDescriptionDescriptorValuePtr != NULL)) { 00253 char_md.p_char_user_desc = const_cast<uint8_t *>(userDescriptionDescriptorValuePtr); 00254 char_md.char_user_desc_max_size = userDescriptionDescriptorValueLen; 00255 char_md.char_user_desc_size = userDescriptionDescriptorValueLen; 00256 } 00257 00258 /* Attribute declaration */ 00259 ble_gatts_attr_md_t attr_md = {0}; 00260 00261 attr_md.rd_auth = readAuthorization; 00262 attr_md.wr_auth = writeAuthorization; 00263 00264 attr_md.vloc = BLE_GATTS_VLOC_STACK; 00265 /* Always set variable size */ 00266 attr_md.vlen = has_variable_len; 00267 00268 if (char_props.read || char_props.notify || char_props.indicate) { 00269 switch (requiredSecurity) { 00270 case SecurityManager::SECURITY_MODE_ENCRYPTION_OPEN_LINK : 00271 BLE_GAP_CONN_SEC_MODE_SET_OPEN(&attr_md.read_perm); 00272 break; 00273 case SecurityManager::SECURITY_MODE_ENCRYPTION_NO_MITM : 00274 BLE_GAP_CONN_SEC_MODE_SET_ENC_NO_MITM(&attr_md.read_perm); 00275 break; 00276 case SecurityManager::SECURITY_MODE_ENCRYPTION_WITH_MITM : 00277 BLE_GAP_CONN_SEC_MODE_SET_ENC_WITH_MITM(&attr_md.read_perm); 00278 break; 00279 case SecurityManager::SECURITY_MODE_SIGNED_NO_MITM : 00280 BLE_GAP_CONN_SEC_MODE_SET_SIGNED_NO_MITM(&attr_md.read_perm); 00281 break; 00282 case SecurityManager::SECURITY_MODE_SIGNED_WITH_MITM : 00283 BLE_GAP_CONN_SEC_MODE_SET_SIGNED_WITH_MITM(&attr_md.read_perm); 00284 break; 00285 default: 00286 break; 00287 }; 00288 } 00289 00290 if (char_props.write || char_props.write_wo_resp) { 00291 switch (requiredSecurity) { 00292 case SecurityManager::SECURITY_MODE_ENCRYPTION_OPEN_LINK : 00293 BLE_GAP_CONN_SEC_MODE_SET_OPEN(&attr_md.write_perm); 00294 break; 00295 case SecurityManager::SECURITY_MODE_ENCRYPTION_NO_MITM : 00296 BLE_GAP_CONN_SEC_MODE_SET_ENC_NO_MITM(&attr_md.write_perm); 00297 break; 00298 case SecurityManager::SECURITY_MODE_ENCRYPTION_WITH_MITM : 00299 BLE_GAP_CONN_SEC_MODE_SET_ENC_WITH_MITM(&attr_md.write_perm); 00300 break; 00301 case SecurityManager::SECURITY_MODE_SIGNED_NO_MITM : 00302 BLE_GAP_CONN_SEC_MODE_SET_SIGNED_NO_MITM(&attr_md.write_perm); 00303 break; 00304 case SecurityManager::SECURITY_MODE_SIGNED_WITH_MITM : 00305 BLE_GAP_CONN_SEC_MODE_SET_SIGNED_WITH_MITM(&attr_md.write_perm); 00306 break; 00307 default: 00308 break; 00309 }; 00310 } 00311 00312 ble_gatts_attr_t attr_char_value = {0}; 00313 00314 attr_char_value.p_uuid = p_uuid; 00315 attr_char_value.p_attr_md = &attr_md; 00316 attr_char_value.init_len = length; 00317 attr_char_value.max_len = max_length; 00318 attr_char_value.p_value = p_data; 00319 00320 ASSERT_STATUS ( sd_ble_gatts_characteristic_add(service_handle, 00321 &char_md, 00322 &attr_char_value, 00323 p_char_handle)); 00324 00325 return ERROR_NONE; 00326 } 00327 00328 00329 00330 /**************************************************************************/ 00331 /*! 00332 @brief Adds a new descriptor to the custom service, assigning 00333 value, a UUID add-on value, etc. 00334 00335 @param[in] char_handle 00336 @param[in] p_uuid The 16-bit value to add to the base UUID 00337 for this descriptor (normally >1 00338 since 1 is typically used by the primary 00339 service). 00340 @param[in] max_length The maximum length of this descriptor 00341 @param[in] has_variable_len Whether the characteristic data has 00342 variable length. 00343 00344 @returns 00345 @retval ERROR_NONE Everything executed normally 00346 */ 00347 /**************************************************************************/ 00348 error_t custom_add_in_descriptor(uint16_t char_handle, 00349 ble_uuid_t *p_uuid, 00350 uint8_t *p_data, 00351 uint16_t length, 00352 uint16_t max_length, 00353 bool has_variable_len, 00354 uint16_t *p_desc_handle) 00355 { 00356 /* Descriptor metadata */ 00357 ble_gatts_attr_md_t desc_md = {0}; 00358 00359 desc_md.vloc = BLE_GATTS_VLOC_STACK; 00360 /* Always set variable size */ 00361 desc_md.vlen = has_variable_len; 00362 00363 /* Make it readable and writable */ 00364 BLE_GAP_CONN_SEC_MODE_SET_OPEN(&desc_md.read_perm); 00365 BLE_GAP_CONN_SEC_MODE_SET_OPEN(&desc_md.write_perm); 00366 00367 ble_gatts_attr_t attr_desc = {0}; 00368 00369 attr_desc.p_uuid = p_uuid; 00370 attr_desc.p_attr_md = &desc_md; 00371 attr_desc.init_len = length; 00372 attr_desc.max_len = max_length; 00373 attr_desc.p_value = p_data; 00374 00375 ASSERT_STATUS ( sd_ble_gatts_descriptor_add(char_handle, 00376 &attr_desc, 00377 p_desc_handle)); 00378 00379 return ERROR_NONE; 00380 }
Generated on Fri Jul 15 2022 12:51:28 by
