├── CHANGELOG.md ├── LICENSE ├── apache-2.0.txt ├── bootloader ├── s110_nrf51822_8.0.0_bootloader.hex ├── s130_nrf51_1.0.0_bootloader.hex └── softdevice_nrf51822_licence_agreement.txt ├── module.json ├── softdevice_nrf51822_licence_agreement.txt └── source ├── btle ├── btle.cpp ├── btle.h ├── btle_advertising.cpp ├── btle_advertising.h ├── btle_discovery.cpp ├── btle_discovery.h ├── btle_gap.cpp ├── btle_gap.h ├── btle_security.cpp ├── btle_security.h └── custom │ ├── custom_helper.cpp │ └── custom_helper.h ├── common ├── ansi_escape.h ├── assertion.h ├── binary.h ├── ble_error.h ├── common.h └── compiler.h ├── nRF5xCharacteristicDescriptorDiscoverer.cpp ├── nRF5xCharacteristicDescriptorDiscoverer.h ├── nRF5xDiscoveredCharacteristic.cpp ├── nRF5xDiscoveredCharacteristic.h ├── nRF5xGap.cpp ├── nRF5xGap.h ├── nRF5xGattClient.cpp ├── nRF5xGattClient.h ├── nRF5xGattServer.cpp ├── nRF5xGattServer.h ├── nRF5xSecurityManager.h ├── nRF5xServiceDiscovery.cpp ├── nRF5xServiceDiscovery.h ├── nRF5xn.cpp ├── nRF5xn.h ├── projectconfig.h └── supress-warnings.cmake /LICENSE: -------------------------------------------------------------------------------- 1 | This module contains softdevice which comes with The Nordic Softdevice License Agreement, 2 | a BSD-like licence for binary distributions, offered by Nordic for use in mbed. Some 3 | other files come from the mbed SDK, and are licensed under Apache-2.0. Unless 4 | specifically indicated otherwise in a file, files are licensed under the 5 | Apache 2.0 license, as can be found in: apache-2.0.txt. The Nordic Semiconductor Softdevice 6 | License Agreement can be found in softdevice_nrf51822_licence_agreement.txt. 7 | -------------------------------------------------------------------------------- /apache-2.0.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2015 ARM Limited 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License. 14 | -------------------------------------------------------------------------------- /bootloader/softdevice_nrf51822_licence_agreement.txt: -------------------------------------------------------------------------------- 1 | /* 2 | * S110/S120/S130 License Agreement 3 | * 4 | * Copyright (c) 2015, Nordic Semiconductor ASA, All rights reserved. 5 | * 6 | * Redistribution. Redistribution and use in binary form, without modification, 7 | * are permitted provided that the following conditions are met: 8 | * 9 | * • Redistributions must reproduce the above copyright notice and the following 10 | * disclaimer in the documentation and/or other materials provided with the 11 | * distribution. 12 | * • Neither the name of the copyright holder nor the names of its contributors 13 | * may be used to endorse or promote products derived from this software 14 | * without specific prior written permission. 15 | * • No reverse engineering, decompilation, or disassembly of this software is 16 | * permitted. 17 | * 18 | * DISCLAIMER. 19 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 20 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 21 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 22 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR 23 | * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 24 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 25 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 26 | * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 28 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | * 30 | * / 31 | -------------------------------------------------------------------------------- /module.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ble-nrf51822", 3 | "version": "2.8.0", 4 | "description": "Nordic stack and drivers for the mbed BLE API.", 5 | "keywords": [ 6 | "Bluetooth", 7 | "BLE", 8 | "mbed", 9 | "mbed-official" 10 | ], 11 | "author": "Rohit Grover", 12 | "repository": { 13 | "url": "git@github.com:ARMmbed/ble-nRF51822.git", 14 | "type": "git" 15 | }, 16 | "homepage": "https://developer.mbed.org/teams/Nordic-Semiconductor/", 17 | "licenses": [ 18 | { 19 | "url": "https://spdx.org/licenses/Apache-2.0", 20 | "type": "Apache-2.0" 21 | }, 22 | { 23 | "type": "LicenseRef-softdevice_nrf51822_licence_agreement.txt" 24 | } 25 | ], 26 | "dependencies": { 27 | "ble": "^2.7.0", 28 | "nrf51-sdk": "^2.4.0" 29 | }, 30 | "extraIncludes": [ 31 | "source/btle", 32 | "source/btle/custom", 33 | "source/common" 34 | ], 35 | "targetDependencies": {} 36 | } 37 | -------------------------------------------------------------------------------- /softdevice_nrf51822_licence_agreement.txt: -------------------------------------------------------------------------------- 1 | /* 2 | * S110/S120/S130 License Agreement 3 | * 4 | * Copyright (c) 2015, Nordic Semiconductor ASA, All rights reserved. 5 | * 6 | * Redistribution. Redistribution and use in binary form, without modification, 7 | * are permitted provided that the following conditions are met: 8 | * 9 | * • Redistributions must reproduce the above copyright notice and the following 10 | * disclaimer in the documentation and/or other materials provided with the 11 | * distribution. 12 | * • Neither the name of the copyright holder nor the names of its contributors 13 | * may be used to endorse or promote products derived from this software 14 | * without specific prior written permission. 15 | * • No reverse engineering, decompilation, or disassembly of this software is 16 | * permitted. 17 | * 18 | * DISCLAIMER. 19 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 20 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 21 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 22 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR 23 | * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 24 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 25 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 26 | * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 28 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | * 30 | * / 31 | -------------------------------------------------------------------------------- /source/btle/btle.cpp: -------------------------------------------------------------------------------- 1 | /* mbed Microcontroller Library 2 | * Copyright (c) 2006-2013 ARM Limited 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #include "common/common.h" 18 | #include "nordic_common.h" 19 | 20 | #include "btle.h" 21 | 22 | #include "ble_flash.h" 23 | #include "ble_conn_params.h" 24 | 25 | #include "btle_gap.h" 26 | #include "btle_advertising.h" 27 | #include "custom/custom_helper.h" 28 | 29 | #include "ble/GapEvents.h" 30 | #include "nRF5xn.h" 31 | 32 | extern "C" { 33 | #include "pstorage.h" 34 | #include "device_manager.h" 35 | #include "softdevice_handler.h" 36 | #include "ble_stack_handler_types.h" 37 | } 38 | 39 | #include "ble_hci.h" 40 | #include "btle_discovery.h" 41 | 42 | #include "nRF5xGattClient.h" 43 | #include "nRF5xServiceDiscovery.h" 44 | #include "nRF5xCharacteristicDescriptorDiscoverer.h" 45 | 46 | bool isEventsSignaled = false; 47 | 48 | extern "C" void assert_nrf_callback(uint16_t line_num, const uint8_t *p_file_name); 49 | void app_error_handler(uint32_t error_code, uint32_t line_num, const uint8_t *p_file_name); 50 | 51 | static void btle_handler(ble_evt_t *p_ble_evt); 52 | 53 | static void sys_evt_dispatch(uint32_t sys_evt) 54 | { 55 | pstorage_sys_event_handler(sys_evt); 56 | } 57 | 58 | /** 59 | * This function is called in interrupt context to handle BLE events; i.e. pull 60 | * system and user events out of the pending events-queue of the BLE stack. The 61 | * BLE stack signals the availability of events by the triggering the SWI2 62 | * interrupt, which forwards the handling to this function. 63 | * 64 | * The event processing loop is implemented in intern_softdevice_events_execute(). 65 | * 66 | * This function will signal to the user code by calling signalEventsToProcess 67 | * that their is events to process and BLE::processEvents should be called. 68 | */ 69 | static uint32_t signalEvent() 70 | { 71 | if(isEventsSignaled == false) { 72 | isEventsSignaled = true; 73 | nRF5xn::Instance(BLE::DEFAULT_INSTANCE).signalEventsToProcess(BLE::DEFAULT_INSTANCE); 74 | } 75 | return NRF_SUCCESS; 76 | } 77 | 78 | error_t btle_init(void) 79 | { 80 | nrf_clock_lfclksrc_t clockSource; 81 | if (NRF_CLOCK->LFCLKSRC & (CLOCK_LFCLKSRC_SRC_Xtal << CLOCK_LFCLKSRC_SRC_Pos)) { 82 | clockSource = NRF_CLOCK_LFCLKSRC_XTAL_20_PPM; 83 | } else { 84 | clockSource = NRF_CLOCK_LFCLKSRC_RC_250_PPM_4000MS_CALIBRATION; 85 | } 86 | SOFTDEVICE_HANDLER_INIT(clockSource, signalEvent); 87 | 88 | // Enable BLE stack 89 | /** 90 | * Using this call, the application can select whether to include the 91 | * Service Changed characteristic in the GATT Server. The default in all 92 | * previous releases has been to include the Service Changed characteristic, 93 | * but this affects how GATT clients behave. Specifically, it requires 94 | * clients to subscribe to this attribute and not to cache attribute handles 95 | * between connections unless the devices are bonded. If the application 96 | * does not need to change the structure of the GATT server attributes at 97 | * runtime this adds unnecessary complexity to the interaction with peer 98 | * clients. If the SoftDevice is enabled with the Service Changed 99 | * Characteristics turned off, then clients are allowed to cache attribute 100 | * handles making applications simpler on both sides. 101 | */ 102 | static const bool IS_SRVC_CHANGED_CHARACT_PRESENT = true; 103 | ble_enable_params_t enableParams = { 104 | .gatts_enable_params = { 105 | .service_changed = IS_SRVC_CHANGED_CHARACT_PRESENT 106 | } 107 | }; 108 | if (sd_ble_enable(&enableParams) != NRF_SUCCESS) { 109 | return ERROR_INVALID_PARAM; 110 | } 111 | 112 | ble_gap_addr_t addr; 113 | if (sd_ble_gap_address_get(&addr) != NRF_SUCCESS) { 114 | return ERROR_INVALID_PARAM; 115 | } 116 | if (sd_ble_gap_address_set(BLE_GAP_ADDR_CYCLE_MODE_NONE, &addr) != NRF_SUCCESS) { 117 | return ERROR_INVALID_PARAM; 118 | } 119 | 120 | ASSERT_STATUS( softdevice_ble_evt_handler_set(btle_handler)); 121 | ASSERT_STATUS( softdevice_sys_evt_handler_set(sys_evt_dispatch)); 122 | 123 | return btle_gap_init(); 124 | } 125 | 126 | static void btle_handler(ble_evt_t *p_ble_evt) 127 | { 128 | /* Library service handlers */ 129 | #if SDK_CONN_PARAMS_MODULE_ENABLE 130 | ble_conn_params_on_ble_evt(p_ble_evt); 131 | #endif 132 | 133 | dm_ble_evt_handler(p_ble_evt); 134 | 135 | #if !defined(TARGET_MCU_NRF51_16K_S110) && !defined(TARGET_MCU_NRF51_32K_S110) 136 | bleGattcEventHandler(p_ble_evt); 137 | #endif 138 | 139 | nRF5xn &ble = nRF5xn::Instance(BLE::DEFAULT_INSTANCE); 140 | nRF5xGap &gap = (nRF5xGap &) ble.getGap(); 141 | nRF5xGattServer &gattServer = (nRF5xGattServer &) ble.getGattServer(); 142 | nRF5xSecurityManager &securityManager = (nRF5xSecurityManager &) ble.getSecurityManager(); 143 | 144 | /* Custom event handler */ 145 | switch (p_ble_evt->header.evt_id) { 146 | case BLE_GAP_EVT_CONNECTED: { 147 | Gap::Handle_t handle = p_ble_evt->evt.gap_evt.conn_handle; 148 | #if defined(TARGET_MCU_NRF51_16K_S110) || defined(TARGET_MCU_NRF51_32K_S110) 149 | /* Only peripheral role is supported by S110 */ 150 | Gap::Role_t role = Gap::PERIPHERAL; 151 | #else 152 | Gap::Role_t role = static_cast(p_ble_evt->evt.gap_evt.params.connected.role); 153 | #endif 154 | gap.setConnectionHandle(handle); 155 | const Gap::ConnectionParams_t *params = reinterpret_cast(&(p_ble_evt->evt.gap_evt.params.connected.conn_params)); 156 | const ble_gap_addr_t *peer = &p_ble_evt->evt.gap_evt.params.connected.peer_addr; 157 | const ble_gap_addr_t *own = &p_ble_evt->evt.gap_evt.params.connected.own_addr; 158 | gap.processConnectionEvent(handle, 159 | role, 160 | static_cast(peer->addr_type), peer->addr, 161 | static_cast(own->addr_type), own->addr, 162 | params); 163 | break; 164 | } 165 | 166 | case BLE_GAP_EVT_DISCONNECTED: { 167 | Gap::Handle_t handle = p_ble_evt->evt.gap_evt.conn_handle; 168 | // Since we are not in a connection and have not started advertising, 169 | // store bonds 170 | gap.setConnectionHandle (BLE_CONN_HANDLE_INVALID); 171 | 172 | Gap::DisconnectionReason_t reason; 173 | switch (p_ble_evt->evt.gap_evt.params.disconnected.reason) { 174 | case BLE_HCI_LOCAL_HOST_TERMINATED_CONNECTION: 175 | reason = Gap::LOCAL_HOST_TERMINATED_CONNECTION; 176 | break; 177 | case BLE_HCI_REMOTE_USER_TERMINATED_CONNECTION: 178 | reason = Gap::REMOTE_USER_TERMINATED_CONNECTION; 179 | break; 180 | case BLE_HCI_CONN_INTERVAL_UNACCEPTABLE: 181 | reason = Gap::CONN_INTERVAL_UNACCEPTABLE; 182 | break; 183 | default: 184 | /* Please refer to the underlying transport library for an 185 | * interpretion of this reason's value. */ 186 | reason = static_cast(p_ble_evt->evt.gap_evt.params.disconnected.reason); 187 | break; 188 | } 189 | 190 | #if !defined(TARGET_MCU_NRF51_16K_S110) && !defined(TARGET_MCU_NRF51_32K_S110) 191 | // Close all pending discoveries for this connection 192 | nRF5xGattClient& gattClient = ble.getGattClient(); 193 | gattClient.characteristicDescriptorDiscoverer().terminate(handle, BLE_ERROR_INVALID_STATE); 194 | gattClient.discovery().terminate(handle); 195 | #endif 196 | 197 | gap.processDisconnectionEvent(handle, reason); 198 | break; 199 | } 200 | 201 | case BLE_GAP_EVT_PASSKEY_DISPLAY: 202 | securityManager.processPasskeyDisplayEvent(p_ble_evt->evt.gap_evt.conn_handle, p_ble_evt->evt.gap_evt.params.passkey_display.passkey); 203 | break; 204 | 205 | case BLE_GAP_EVT_TIMEOUT: 206 | gap.processTimeoutEvent(static_cast(p_ble_evt->evt.gap_evt.params.timeout.src)); 207 | break; 208 | 209 | case BLE_GATTC_EVT_TIMEOUT: 210 | case BLE_GATTS_EVT_TIMEOUT: 211 | // Disconnect on GATT Server and Client timeout events. 212 | // ASSERT_STATUS_RET_VOID (sd_ble_gap_disconnect(m_conn_handle, 213 | // BLE_HCI_REMOTE_USER_TERMINATED_CONNECTION)); 214 | break; 215 | 216 | case BLE_GAP_EVT_ADV_REPORT: { 217 | const ble_gap_evt_adv_report_t *advReport = &p_ble_evt->evt.gap_evt.params.adv_report; 218 | gap.processAdvertisementReport(advReport->peer_addr.addr, 219 | advReport->rssi, 220 | advReport->scan_rsp, 221 | static_cast(advReport->type), 222 | advReport->dlen, 223 | advReport->data); 224 | break; 225 | } 226 | 227 | default: 228 | break; 229 | } 230 | 231 | gattServer.hwCallback(p_ble_evt); 232 | } 233 | 234 | /*! @brief Callback when an error occurs inside the SoftDevice */ 235 | void assert_nrf_callback(uint16_t line_num, const uint8_t *p_file_name) 236 | { 237 | ASSERT(false, (void) 0); 238 | } 239 | 240 | /*! 241 | @brief Handler for general errors above the SoftDevice layer. 242 | Typically we can' recover from this so we do a reset. 243 | */ 244 | void app_error_handler(uint32_t error_code, uint32_t line_num, const uint8_t *p_file_name) 245 | { 246 | ASSERT_STATUS_RET_VOID( error_code ); 247 | NVIC_SystemReset(); 248 | } 249 | -------------------------------------------------------------------------------- /source/btle/btle.h: -------------------------------------------------------------------------------- 1 | /* mbed Microcontroller Library 2 | * Copyright (c) 2006-2013 ARM Limited 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #ifndef _BTLE_H_ 18 | #define _BTLE_H_ 19 | 20 | #ifdef __cplusplus 21 | extern "C" { 22 | #endif 23 | 24 | #include "common/common.h" 25 | 26 | #include "ble_srv_common.h" 27 | #include "nrf_ble.h" 28 | 29 | error_t btle_init(void); 30 | 31 | // flag indicating if events have been signaled or not 32 | // It is used by processEvents and signalEventsToProcess 33 | // signalEventsToProcess raise the flag and processEvents 34 | // clears it. 35 | extern bool isEventsSignaled; 36 | 37 | #ifdef __cplusplus 38 | } 39 | #endif 40 | 41 | #endif // ifndef _BTLE_H_ 42 | -------------------------------------------------------------------------------- /source/btle/btle_advertising.cpp: -------------------------------------------------------------------------------- 1 | /* mbed Microcontroller Library 2 | * Copyright (c) 2006-2013 ARM Limited 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | #include "common/common.h" 17 | 18 | #include "ble_advdata.h" 19 | #include "btle.h" 20 | 21 | /**************************************************************************/ 22 | /*! 23 | @brief Starts the advertising process 24 | 25 | @returns 26 | */ 27 | /**************************************************************************/ 28 | error_t btle_advertising_start(void) 29 | { 30 | ble_gap_adv_params_t adv_para = {0}; 31 | 32 | /* Set the default advertising parameters */ 33 | adv_para.type = BLE_GAP_ADV_TYPE_ADV_IND; 34 | adv_para.p_peer_addr = NULL; /* Undirected advertising */ 35 | adv_para.fp = BLE_GAP_ADV_FP_ANY; 36 | adv_para.p_whitelist = NULL; 37 | adv_para.interval = (CFG_GAP_ADV_INTERVAL_MS * 8) / 5; /* Advertising 38 | * interval in 39 | * units of 0.625 40 | * ms */ 41 | adv_para.timeout = CFG_GAP_ADV_TIMEOUT_S; 42 | 43 | ASSERT_STATUS( sd_ble_gap_adv_start(&adv_para)); 44 | 45 | return ERROR_NONE; 46 | } 47 | -------------------------------------------------------------------------------- /source/btle/btle_advertising.h: -------------------------------------------------------------------------------- 1 | /* mbed Microcontroller Library 2 | * Copyright (c) 2006-2013 ARM Limited 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #ifndef _BTLE_ADVERTISING_H_ 18 | #define _BTLE_ADVERTISING_H_ 19 | 20 | #include "common/common.h" 21 | 22 | error_t btle_advertising_start(void); 23 | 24 | #endif // ifndef _BTLE_ADVERTISING_H_ 25 | -------------------------------------------------------------------------------- /source/btle/btle_discovery.cpp: -------------------------------------------------------------------------------- 1 | /* mbed Microcontroller Library 2 | * Copyright (c) 2006-2013 ARM Limited 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #include "nRF5xServiceDiscovery.h" 18 | #include "nRF5xCharacteristicDescriptorDiscoverer.h" 19 | #include "nRF5xGattClient.h" 20 | #include "nRF5xn.h" 21 | 22 | #if !defined(TARGET_MCU_NRF51_16K_S110) && !defined(TARGET_MCU_NRF51_32K_S110) 23 | void bleGattcEventHandler(const ble_evt_t *p_ble_evt) 24 | { 25 | nRF5xn &ble = nRF5xn::Instance(BLE::DEFAULT_INSTANCE); 26 | nRF5xGap &gap = (nRF5xGap &) ble.getGap(); 27 | nRF5xGattClient &gattClient = (nRF5xGattClient &) ble.getGattClient(); 28 | nRF5xServiceDiscovery &sdSingleton = gattClient.discovery(); 29 | nRF5xCharacteristicDescriptorDiscoverer &characteristicDescriptorDiscoverer = 30 | gattClient.characteristicDescriptorDiscoverer(); 31 | 32 | switch (p_ble_evt->header.evt_id) { 33 | case BLE_GATTC_EVT_PRIM_SRVC_DISC_RSP: 34 | switch (p_ble_evt->evt.gattc_evt.gatt_status) { 35 | case BLE_GATT_STATUS_SUCCESS: 36 | sdSingleton.setupDiscoveredServices(&p_ble_evt->evt.gattc_evt.params.prim_srvc_disc_rsp); 37 | break; 38 | 39 | case BLE_GATT_STATUS_ATTERR_ATTRIBUTE_NOT_FOUND: 40 | default: 41 | sdSingleton.terminate(); 42 | break; 43 | } 44 | break; 45 | 46 | case BLE_GATTC_EVT_CHAR_DISC_RSP: 47 | switch (p_ble_evt->evt.gattc_evt.gatt_status) { 48 | case BLE_GATT_STATUS_SUCCESS: 49 | sdSingleton.setupDiscoveredCharacteristics(&p_ble_evt->evt.gattc_evt.params.char_disc_rsp); 50 | break; 51 | 52 | case BLE_GATT_STATUS_ATTERR_ATTRIBUTE_NOT_FOUND: 53 | default: 54 | sdSingleton.terminateCharacteristicDiscovery(BLE_ERROR_NONE); 55 | break; 56 | } 57 | break; 58 | 59 | case BLE_GATTC_EVT_CHAR_VAL_BY_UUID_READ_RSP: 60 | if (sdSingleton.isActive()) { 61 | sdSingleton.processDiscoverUUIDResponse(&p_ble_evt->evt.gattc_evt.params.char_val_by_uuid_read_rsp); 62 | } 63 | break; 64 | 65 | case BLE_GATTC_EVT_READ_RSP: { 66 | GattReadCallbackParams response = { 67 | .connHandle = p_ble_evt->evt.gattc_evt.conn_handle, 68 | .handle = p_ble_evt->evt.gattc_evt.params.read_rsp.handle, 69 | .offset = p_ble_evt->evt.gattc_evt.params.read_rsp.offset, 70 | .len = p_ble_evt->evt.gattc_evt.params.read_rsp.len, 71 | .data = p_ble_evt->evt.gattc_evt.params.read_rsp.data, 72 | }; 73 | gattClient.processReadResponse(&response); 74 | } 75 | break; 76 | 77 | case BLE_GATTC_EVT_WRITE_RSP: { 78 | GattWriteCallbackParams response = { 79 | .connHandle = p_ble_evt->evt.gattc_evt.conn_handle, 80 | .handle = p_ble_evt->evt.gattc_evt.params.write_rsp.handle, 81 | .writeOp = (GattWriteCallbackParams::WriteOp_t)(p_ble_evt->evt.gattc_evt.params.write_rsp.write_op), 82 | .offset = p_ble_evt->evt.gattc_evt.params.write_rsp.offset, 83 | .len = p_ble_evt->evt.gattc_evt.params.write_rsp.len, 84 | .data = p_ble_evt->evt.gattc_evt.params.write_rsp.data, 85 | }; 86 | gattClient.processWriteResponse(&response); 87 | } 88 | break; 89 | 90 | case BLE_GATTC_EVT_HVX: { 91 | GattHVXCallbackParams params; 92 | params.connHandle = p_ble_evt->evt.gattc_evt.conn_handle; 93 | params.handle = p_ble_evt->evt.gattc_evt.params.hvx.handle; 94 | params.type = static_cast(p_ble_evt->evt.gattc_evt.params.hvx.type); 95 | params.len = p_ble_evt->evt.gattc_evt.params.hvx.len; 96 | params.data = p_ble_evt->evt.gattc_evt.params.hvx.data; 97 | 98 | gattClient.processHVXEvent(¶ms); 99 | } 100 | break; 101 | 102 | case BLE_GATTC_EVT_DESC_DISC_RSP: { 103 | uint16_t conn_handle = p_ble_evt->evt.gattc_evt.conn_handle; 104 | uint16_t status = p_ble_evt->evt.gattc_evt.gatt_status; 105 | const ble_gattc_evt_desc_disc_rsp_t& discovered_descriptors = p_ble_evt->evt.gattc_evt.params.desc_disc_rsp; 106 | 107 | switch(status) { 108 | case BLE_GATT_STATUS_SUCCESS: 109 | characteristicDescriptorDiscoverer.process( 110 | conn_handle, 111 | discovered_descriptors 112 | ); 113 | break; 114 | case BLE_GATT_STATUS_ATTERR_ATTRIBUTE_NOT_FOUND: 115 | // end of discovery 116 | characteristicDescriptorDiscoverer.terminate(conn_handle, BLE_ERROR_NONE); 117 | break; 118 | default: 119 | characteristicDescriptorDiscoverer.terminate(conn_handle, BLE_ERROR_UNSPECIFIED); 120 | break; 121 | } 122 | } break; 123 | } 124 | 125 | sdSingleton.progressCharacteristicDiscovery(); 126 | sdSingleton.progressServiceDiscovery(); 127 | } 128 | #endif 129 | 130 | -------------------------------------------------------------------------------- /source/btle/btle_discovery.h: -------------------------------------------------------------------------------- 1 | /* mbed Microcontroller Library 2 | * Copyright (c) 2006-2013 ARM Limited 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #ifndef _BTLE_DISCOVERY_H_ 18 | #define _BTLE_DISCOVERY_H_ 19 | 20 | void bleGattcEventHandler(const ble_evt_t *p_ble_evt); 21 | 22 | #endif /*_BTLE_DISCOVERY_H_*/ 23 | -------------------------------------------------------------------------------- /source/btle/btle_gap.cpp: -------------------------------------------------------------------------------- 1 | /* mbed Microcontroller Library 2 | * Copyright (c) 2006-2013 ARM Limited 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | #include "common/common.h" 17 | 18 | #include "ble_gap.h" 19 | #include "ble_conn_params.h" 20 | 21 | static inline uint32_t msec_to_1_25msec(uint32_t interval_ms) ATTR_ALWAYS_INLINE ATTR_CONST; 22 | #if SDK_CONN_PARAMS_MODULE_ENABLE 23 | static void error_callback(uint32_t nrf_error); 24 | #endif // SDK_CONN_PARAMS_MODULE_ENABLE 25 | 26 | /**************************************************************************/ 27 | /*! 28 | @brief Initialise GAP in the underlying SoftDevice 29 | 30 | @returns 31 | */ 32 | /**************************************************************************/ 33 | error_t btle_gap_init(void) 34 | { 35 | ble_gap_conn_params_t gap_conn_params = {0}; 36 | 37 | gap_conn_params.min_conn_interval = msec_to_1_25msec(CFG_GAP_CONNECTION_MIN_INTERVAL_MS); // in 1.25ms units 38 | gap_conn_params.max_conn_interval = msec_to_1_25msec(CFG_GAP_CONNECTION_MAX_INTERVAL_MS); // in 1.25ms unit 39 | gap_conn_params.slave_latency = CFG_GAP_CONNECTION_SLAVE_LATENCY; 40 | gap_conn_params.conn_sup_timeout = CFG_GAP_CONNECTION_SUPERVISION_TIMEOUT_MS / 10; // in 10ms unit 41 | 42 | ble_gap_conn_sec_mode_t sec_mode; 43 | BLE_GAP_CONN_SEC_MODE_SET_OPEN(&sec_mode); // no security is needed 44 | 45 | ASSERT_STATUS( sd_ble_gap_device_name_set(&sec_mode, (const uint8_t *) CFG_GAP_LOCAL_NAME, strlen(CFG_GAP_LOCAL_NAME))); 46 | ASSERT_STATUS( sd_ble_gap_appearance_set(CFG_GAP_APPEARANCE)); 47 | ASSERT_STATUS( sd_ble_gap_ppcp_set(&gap_conn_params)); 48 | ASSERT_STATUS( sd_ble_gap_tx_power_set(CFG_BLE_TX_POWER_LEVEL)); 49 | 50 | /** 51 | * Call to conn_params_init() is not necessary; and so is disabled by default. 52 | * This API should be exposed to the user to be invoked when necessary. 53 | */ 54 | #if SDK_CONN_PARAMS_MODULE_ENABLE 55 | /* Connection Parameters */ 56 | enum { 57 | FIRST_UPDATE_DELAY = APP_TIMER_TICKS(5000, CFG_TIMER_PRESCALER), 58 | NEXT_UPDATE_DELAY = APP_TIMER_TICKS(5000, CFG_TIMER_PRESCALER), 59 | MAX_UPDATE_COUNT = 3 60 | }; 61 | 62 | ble_conn_params_init_t cp_init = {0}; 63 | 64 | cp_init.p_conn_params = NULL; 65 | cp_init.first_conn_params_update_delay = FIRST_UPDATE_DELAY; 66 | cp_init.next_conn_params_update_delay = NEXT_UPDATE_DELAY; 67 | cp_init.max_conn_params_update_count = MAX_UPDATE_COUNT; 68 | cp_init.start_on_notify_cccd_handle = BLE_GATT_HANDLE_INVALID; 69 | cp_init.disconnect_on_fail = true; 70 | cp_init.evt_handler = NULL; 71 | cp_init.error_handler = error_callback; 72 | 73 | ASSERT_STATUS ( ble_conn_params_init(&cp_init)); 74 | #endif // SDK_CONN_PARAMS_MODULE_ENABLE 75 | 76 | return ERROR_NONE; 77 | } 78 | 79 | /**************************************************************************/ 80 | /*! 81 | @brief Converts msecs to an integer representing 1.25ms units 82 | 83 | @param[in] ms 84 | The number of milliseconds to conver to 1.25ms units 85 | 86 | @returns The number of 1.25ms units in the supplied number of ms 87 | */ 88 | /**************************************************************************/ 89 | static inline uint32_t msec_to_1_25msec(uint32_t interval_ms) 90 | { 91 | return (interval_ms * 4) / 5; 92 | } 93 | 94 | #if SDK_CONN_PARAMS_MODULE_ENABLE 95 | static void error_callback(uint32_t nrf_error) 96 | { 97 | ASSERT_STATUS_RET_VOID( nrf_error ); 98 | } 99 | #endif // SDK_CONN_PARAMS_MODULE_ENABLE 100 | -------------------------------------------------------------------------------- /source/btle/btle_gap.h: -------------------------------------------------------------------------------- 1 | /* mbed Microcontroller Library 2 | * Copyright (c) 2006-2013 ARM Limited 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #ifndef _BTLE_GAP_H_ 18 | #define _BTLE_GAP_H_ 19 | 20 | #include "common/common.h" 21 | 22 | error_t btle_gap_init(void); 23 | 24 | #endif // ifndef _BTLE_GAP_H_ 25 | -------------------------------------------------------------------------------- /source/btle/btle_security.cpp: -------------------------------------------------------------------------------- 1 | /* mbed Microcontroller Library 2 | * Copyright (c) 2006-2013 ARM Limited 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #include "btle.h" 18 | 19 | #include "nRF5xn.h" 20 | 21 | extern "C" { 22 | #include "pstorage.h" 23 | #include "device_manager.h" 24 | #include "id_manager.h" 25 | } 26 | 27 | #include "btle_security.h" 28 | 29 | static dm_application_instance_t applicationInstance; 30 | static bool initialized = false; 31 | static ret_code_t dm_handler(dm_handle_t const *p_handle, dm_event_t const *p_event, ret_code_t event_result); 32 | 33 | // default security parameters 34 | static ble_gap_sec_params_t securityParameters = { 35 | .bond = true, /**< Perform bonding. */ 36 | .mitm = true, /**< Man In The Middle protection required. */ 37 | .io_caps = SecurityManager::IO_CAPS_NONE, /**< IO capabilities, see @ref BLE_GAP_IO_CAPS. */ 38 | .oob = 0, /**< Out Of Band data available. */ 39 | .min_key_size = 16, /**< Minimum encryption key size in octets between 7 and 16. If 0 then not applicable in this instance. */ 40 | .max_key_size = 16, /**< Maximum encryption key size in octets between min_key_size and 16. */ 41 | .kdist_periph = { 42 | .enc = 1, /**< Long Term Key and Master Identification. */ 43 | .id = 1, /**< Identity Resolving Key and Identity Address Information. */ 44 | .sign = 1, /**< Connection Signature Resolving Key. */ 45 | }, /**< Key distribution bitmap: keys that the peripheral device will distribute. */ 46 | }; 47 | 48 | bool 49 | btle_hasInitializedSecurity(void) 50 | { 51 | return initialized; 52 | } 53 | 54 | ble_error_t 55 | btle_initializeSecurity(bool enableBonding, 56 | bool requireMITM, 57 | SecurityManager::SecurityIOCapabilities_t iocaps, 58 | const SecurityManager::Passkey_t passkey) 59 | { 60 | /* guard against multiple initializations */ 61 | if (initialized) { 62 | return BLE_ERROR_NONE; 63 | } 64 | 65 | if (pstorage_init() != NRF_SUCCESS) { 66 | return BLE_ERROR_UNSPECIFIED; 67 | } 68 | 69 | ret_code_t rc; 70 | if (passkey) { 71 | ble_opt_t opts; 72 | opts.gap_opt.passkey.p_passkey = const_cast(passkey); 73 | if ((rc = sd_ble_opt_set(BLE_GAP_OPT_PASSKEY, &opts)) != NRF_SUCCESS) { 74 | switch (rc) { 75 | case BLE_ERROR_INVALID_CONN_HANDLE: 76 | case NRF_ERROR_INVALID_ADDR: 77 | case NRF_ERROR_INVALID_PARAM: 78 | default: 79 | return BLE_ERROR_INVALID_PARAM; 80 | case NRF_ERROR_INVALID_STATE: 81 | return BLE_ERROR_INVALID_STATE; 82 | case NRF_ERROR_BUSY: 83 | return BLE_STACK_BUSY; 84 | } 85 | } 86 | } 87 | 88 | dm_init_param_t dm_init_param = { 89 | .clear_persistent_data = false /* Set to true in case the module should clear all persistent data. */ 90 | }; 91 | if (dm_init(&dm_init_param) != NRF_SUCCESS) { 92 | return BLE_ERROR_UNSPECIFIED; 93 | } 94 | 95 | // update default security parameters with function call parameters 96 | securityParameters.bond = enableBonding; 97 | securityParameters.mitm = requireMITM; 98 | securityParameters.io_caps = iocaps; 99 | 100 | const dm_application_param_t dm_param = { 101 | .evt_handler = dm_handler, 102 | .service_type = DM_PROTOCOL_CNTXT_GATT_CLI_ID, 103 | .sec_param = securityParameters 104 | }; 105 | 106 | if ((rc = dm_register(&applicationInstance, &dm_param)) != NRF_SUCCESS) { 107 | switch (rc) { 108 | case NRF_ERROR_INVALID_STATE: 109 | return BLE_ERROR_INVALID_STATE; 110 | case NRF_ERROR_NO_MEM: 111 | return BLE_ERROR_NO_MEM; 112 | default: 113 | return BLE_ERROR_UNSPECIFIED; 114 | } 115 | } 116 | 117 | initialized = true; 118 | return BLE_ERROR_NONE; 119 | } 120 | 121 | ble_error_t 122 | btle_purgeAllBondingState(void) 123 | { 124 | ret_code_t rc; 125 | if ((rc = dm_device_delete_all(&applicationInstance)) == NRF_SUCCESS) { 126 | return BLE_ERROR_NONE; 127 | } 128 | 129 | switch (rc) { 130 | case NRF_ERROR_INVALID_STATE: 131 | return BLE_ERROR_INVALID_STATE; 132 | case NRF_ERROR_NO_MEM: 133 | return BLE_ERROR_NO_MEM; 134 | default: 135 | return BLE_ERROR_UNSPECIFIED; 136 | } 137 | } 138 | 139 | ble_error_t 140 | btle_getLinkSecurity(Gap::Handle_t connectionHandle, SecurityManager::LinkSecurityStatus_t *securityStatusP) 141 | { 142 | ret_code_t rc; 143 | dm_handle_t dmHandle = { 144 | .appl_id = applicationInstance, 145 | }; 146 | if ((rc = dm_handle_get(connectionHandle, &dmHandle)) != NRF_SUCCESS) { 147 | if (rc == NRF_ERROR_NOT_FOUND) { 148 | return BLE_ERROR_INVALID_PARAM; 149 | } else { 150 | return BLE_ERROR_UNSPECIFIED; 151 | } 152 | } 153 | 154 | if ((rc = dm_security_status_req(&dmHandle, reinterpret_cast(securityStatusP))) != NRF_SUCCESS) { 155 | switch (rc) { 156 | case NRF_ERROR_INVALID_STATE: 157 | return BLE_ERROR_INVALID_STATE; 158 | case NRF_ERROR_NO_MEM: 159 | return BLE_ERROR_NO_MEM; 160 | default: 161 | return BLE_ERROR_UNSPECIFIED; 162 | } 163 | } 164 | 165 | return BLE_ERROR_NONE; 166 | } 167 | 168 | ble_error_t 169 | btle_setLinkSecurity(Gap::Handle_t connectionHandle, SecurityManager::SecurityMode_t securityMode) 170 | { 171 | // use default and updated parameters as starting point 172 | // and modify structure based on security mode. 173 | ble_gap_sec_params_t params = securityParameters; 174 | 175 | switch (securityMode) { 176 | case SecurityManager::SECURITY_MODE_ENCRYPTION_OPEN_LINK: 177 | /**< Require no protection, open link. */ 178 | securityParameters.bond = false; 179 | securityParameters.mitm = false; 180 | break; 181 | 182 | case SecurityManager::SECURITY_MODE_ENCRYPTION_NO_MITM: 183 | /**< Require encryption, but no MITM protection. */ 184 | securityParameters.bond = true; 185 | securityParameters.mitm = false; 186 | break; 187 | 188 | // not yet implemented security modes 189 | case SecurityManager::SECURITY_MODE_NO_ACCESS: 190 | case SecurityManager::SECURITY_MODE_ENCRYPTION_WITH_MITM: 191 | /**< Require encryption and MITM protection. */ 192 | case SecurityManager::SECURITY_MODE_SIGNED_NO_MITM: 193 | /**< Require signing or encryption, but no MITM protection. */ 194 | case SecurityManager::SECURITY_MODE_SIGNED_WITH_MITM: 195 | /**< Require signing or encryption, and MITM protection. */ 196 | default: 197 | return BLE_ERROR_NOT_IMPLEMENTED; 198 | } 199 | 200 | // update security settings for given connection 201 | uint32_t result = sd_ble_gap_authenticate(connectionHandle, ¶ms); 202 | 203 | if (result == NRF_SUCCESS) { 204 | return BLE_ERROR_NONE; 205 | } else { 206 | return BLE_ERROR_UNSPECIFIED; 207 | } 208 | } 209 | 210 | ret_code_t 211 | dm_handler(dm_handle_t const *p_handle, dm_event_t const *p_event, ret_code_t event_result) 212 | { 213 | nRF5xn &ble = nRF5xn::Instance(BLE::DEFAULT_INSTANCE); 214 | nRF5xSecurityManager &securityManager = (nRF5xSecurityManager &) ble.getSecurityManager(); 215 | 216 | switch (p_event->event_id) { 217 | case DM_EVT_SECURITY_SETUP: /* started */ { 218 | const ble_gap_sec_params_t *peerParams = &p_event->event_param.p_gap_param->params.sec_params_request.peer_params; 219 | securityManager.processSecuritySetupInitiatedEvent(p_event->event_param.p_gap_param->conn_handle, 220 | peerParams->bond, 221 | peerParams->mitm, 222 | (SecurityManager::SecurityIOCapabilities_t)peerParams->io_caps); 223 | break; 224 | } 225 | case DM_EVT_SECURITY_SETUP_COMPLETE: 226 | securityManager. 227 | processSecuritySetupCompletedEvent(p_event->event_param.p_gap_param->conn_handle, 228 | (SecurityManager::SecurityCompletionStatus_t)(p_event->event_param.p_gap_param->params.auth_status.auth_status)); 229 | break; 230 | case DM_EVT_LINK_SECURED: { 231 | unsigned securityMode = p_event->event_param.p_gap_param->params.conn_sec_update.conn_sec.sec_mode.sm; 232 | unsigned level = p_event->event_param.p_gap_param->params.conn_sec_update.conn_sec.sec_mode.lv; 233 | SecurityManager::SecurityMode_t resolvedSecurityMode = SecurityManager::SECURITY_MODE_NO_ACCESS; 234 | switch (securityMode) { 235 | case 1: 236 | switch (level) { 237 | case 1: 238 | resolvedSecurityMode = SecurityManager::SECURITY_MODE_ENCRYPTION_OPEN_LINK; 239 | break; 240 | case 2: 241 | resolvedSecurityMode = SecurityManager::SECURITY_MODE_ENCRYPTION_NO_MITM; 242 | break; 243 | case 3: 244 | resolvedSecurityMode = SecurityManager::SECURITY_MODE_ENCRYPTION_WITH_MITM; 245 | break; 246 | } 247 | break; 248 | case 2: 249 | switch (level) { 250 | case 1: 251 | resolvedSecurityMode = SecurityManager::SECURITY_MODE_SIGNED_NO_MITM; 252 | break; 253 | case 2: 254 | resolvedSecurityMode = SecurityManager::SECURITY_MODE_SIGNED_WITH_MITM; 255 | break; 256 | } 257 | break; 258 | } 259 | 260 | securityManager.processLinkSecuredEvent(p_event->event_param.p_gap_param->conn_handle, resolvedSecurityMode); 261 | break; 262 | } 263 | case DM_EVT_DEVICE_CONTEXT_STORED: 264 | securityManager.processSecurityContextStoredEvent(p_event->event_param.p_gap_param->conn_handle); 265 | break; 266 | default: 267 | break; 268 | } 269 | 270 | return NRF_SUCCESS; 271 | } 272 | 273 | ble_error_t 274 | btle_createWhitelistFromBondTable(ble_gap_whitelist_t *p_whitelist) 275 | { 276 | if (!btle_hasInitializedSecurity()) { 277 | return BLE_ERROR_INITIALIZATION_INCOMPLETE; 278 | } 279 | ret_code_t err = dm_whitelist_create(&applicationInstance, p_whitelist); 280 | if (err == NRF_SUCCESS) { 281 | return BLE_ERROR_NONE; 282 | } else if (err == NRF_ERROR_NULL) { 283 | return BLE_ERROR_PARAM_OUT_OF_RANGE; 284 | } else { 285 | return BLE_ERROR_INVALID_STATE; 286 | } 287 | } 288 | 289 | 290 | bool 291 | btle_matchAddressAndIrk(ble_gap_addr_t const * p_addr, ble_gap_irk_t const * p_irk) 292 | { 293 | /* 294 | * Use a helper function from the Nordic SDK to test whether the BLE 295 | * address can be generated using the IRK. 296 | */ 297 | return im_address_resolve(p_addr, p_irk); 298 | } 299 | 300 | void 301 | btle_generateResolvableAddress(const ble_gap_irk_t &irk, ble_gap_addr_t &address) 302 | { 303 | /* Set type to resolvable */ 304 | address.addr_type = BLE_GAP_ADDR_TYPE_RANDOM_PRIVATE_RESOLVABLE; 305 | 306 | /* 307 | * Assign a random number to the most significant 3 bytes 308 | * of the address. 309 | */ 310 | address.addr[BLE_GAP_ADDR_LEN - 3] = 0x8E; 311 | address.addr[BLE_GAP_ADDR_LEN - 2] = 0x4F; 312 | address.addr[BLE_GAP_ADDR_LEN - 1] = 0x7C; 313 | 314 | /* Calculate the hash and store it in the top half of the address */ 315 | ah(irk.irk, &address.addr[BLE_GAP_ADDR_LEN - 3], address.addr); 316 | } 317 | -------------------------------------------------------------------------------- /source/btle/btle_security.h: -------------------------------------------------------------------------------- 1 | /* mbed Microcontroller Library 2 | * Copyright (c) 2006-2013 ARM Limited 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #ifndef _BTLE_SECURITY_H_ 18 | #define _BTLE_SECURITY_H_ 19 | 20 | #include "ble/Gap.h" 21 | #include "ble/SecurityManager.h" 22 | 23 | /** 24 | * Function to test whether the SecurityManager has been initialized. 25 | * Possible by a call to @ref btle_initializeSecurity(). 26 | * 27 | * @return True if the SecurityManager was previously initialized, false 28 | * otherwise. 29 | */ 30 | bool btle_hasInitializedSecurity(void); 31 | 32 | /** 33 | * Enable Nordic's Device Manager, which brings in functionality from the 34 | * stack's Security Manager. The Security Manager implements the actual 35 | * cryptographic algorithms and protocol exchanges that allow two devices to 36 | * securely exchange data and privately detect each other. 37 | * 38 | * @param[in] enableBonding Allow for bonding. 39 | * @param[in] requireMITM Require protection for man-in-the-middle attacks. 40 | * @param[in] iocaps To specify IO capabilities of this peripheral, 41 | * such as availability of a display or keyboard to 42 | * support out-of-band exchanges of security data. 43 | * @param[in] passkey To specify a static passkey. 44 | * 45 | * @return BLE_ERROR_NONE on success. 46 | */ 47 | ble_error_t btle_initializeSecurity(bool enableBonding = true, 48 | bool requireMITM = true, 49 | SecurityManager::SecurityIOCapabilities_t iocaps = SecurityManager::IO_CAPS_NONE, 50 | const SecurityManager::Passkey_t passkey = NULL); 51 | 52 | /** 53 | * Get the security status of a link. 54 | * 55 | * @param[in] connectionHandle 56 | * Handle to identify the connection. 57 | * @param[out] securityStatusP 58 | * security status. 59 | * 60 | * @return BLE_ERROR_NONE Or appropriate error code indicating reason for failure. 61 | */ 62 | ble_error_t btle_getLinkSecurity(Gap::Handle_t connectionHandle, SecurityManager::LinkSecurityStatus_t *securityStatusP); 63 | 64 | /** 65 | * Set the security mode on a connection. Useful for elevating the security mode 66 | * once certain conditions are met, e.g., a particular service is found. 67 | * 68 | * @param[in] connectionHandle 69 | * Handle to identify the connection. 70 | * @param[in] securityMode 71 | * security mode. 72 | * 73 | * @return BLE_ERROR_NONE Or appropriate error code indicating reason for failure. 74 | */ 75 | ble_error_t btle_setLinkSecurity(Gap::Handle_t connectionHandle, SecurityManager::SecurityMode_t securityMode); 76 | 77 | /** 78 | * Function for deleting all peer device context and all related bonding 79 | * information from the database. 80 | * 81 | * @retval BLE_ERROR_NONE On success, else an error code indicating reason for failure. 82 | * @retval BLE_ERROR_INVALID_STATE If the API is called without module initialization and/or 83 | * application registration. 84 | */ 85 | ble_error_t btle_purgeAllBondingState(void); 86 | 87 | /** 88 | * Query the SoftDevice bond table to extract a whitelist containing the BLE 89 | * addresses and IRKs of bonded devices. 90 | * 91 | * @param[in/out] p_whitelist 92 | * (on input) p_whitelist->addr_count and 93 | * p_whitelist->irk_count specify the maximum number of 94 | * addresses and IRKs added to the whitelist structure. 95 | * (on output) *p_whitelist is a whitelist containing the 96 | * addresses and IRKs of the bonded devices. 97 | * 98 | * @return BLE_ERROR_NONE Or appropriate error code indicating reason for failure. 99 | */ 100 | ble_error_t btle_createWhitelistFromBondTable(ble_gap_whitelist_t *p_whitelist); 101 | 102 | /** 103 | * Function to test whether a BLE address is generated using an IRK. 104 | * 105 | * @param[in] p_addr 106 | * Pointer to a BLE address. 107 | * @param[in] p_irk 108 | * Pointer to an IRK. 109 | * 110 | * @return True if p_addr can be generated using p_irk, false otherwise. 111 | */ 112 | bool btle_matchAddressAndIrk(ble_gap_addr_t const * p_addr, ble_gap_irk_t const * p_irk); 113 | 114 | /** 115 | * Function to generate a private resolvable BLE address. 116 | * 117 | * @param[out] p_addr 118 | * The output address. 119 | * @param[in] p_irk 120 | * A reference to a IRK. 121 | * 122 | * @note This function does not generate a secure address since the prand number in the 123 | * resolvable address is not truly random. Therefore, the output of this function 124 | * is only meant to be used by the application internally but never exported. 125 | */ 126 | void btle_generateResolvableAddress(const ble_gap_irk_t &irk, ble_gap_addr_t &address); 127 | 128 | #endif /* _BTLE_SECURITY_H_ */ 129 | -------------------------------------------------------------------------------- /source/btle/custom/custom_helper.cpp: -------------------------------------------------------------------------------- 1 | /* mbed Microcontroller Library 2 | * Copyright (c) 2006-2013 ARM Limited 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #include "custom_helper.h" 18 | 19 | /* 20 | * The current version of the soft-device doesn't handle duplicate 128-bit UUIDs 21 | * very well. It is therefore necessary to filter away duplicates before 22 | * passing long UUIDs to sd_ble_uuid_vs_add(). The following types and data 23 | * structures involved in maintaining a local cache of 128-bit UUIDs. 24 | */ 25 | typedef struct { 26 | UUID::LongUUIDBytes_t uuid; 27 | uint8_t type; 28 | } converted_uuid_table_entry_t; 29 | static const unsigned UUID_TABLE_MAX_ENTRIES = 4; /* This is the maximum number of 128-bit UUIDs with distinct bases that 30 | * we expect to be in use; increase this limit if needed. */ 31 | static unsigned uuidTableEntries = 0; /* current usage of the table */ 32 | converted_uuid_table_entry_t convertedUUIDTable[UUID_TABLE_MAX_ENTRIES]; 33 | 34 | /** 35 | * lookup the cache of previously converted 128-bit UUIDs to find a type value. 36 | * @param uuid base 128-bit UUID 37 | * @param recoveredType the type field of the 3-byte nRF's uuid. 38 | * @return true if a match is found. 39 | */ 40 | static bool 41 | lookupConvertedUUIDTable(const UUID::LongUUIDBytes_t uuid, uint8_t *recoveredType) 42 | { 43 | unsigned i; 44 | for (i = 0; i < uuidTableEntries; i++) { 45 | unsigned byteIndex; 46 | for (byteIndex = 0; byteIndex < UUID::LENGTH_OF_LONG_UUID; byteIndex++) { 47 | /* Skip bytes 2 and 3, because they contain the shortUUID (16-bit) version of the 48 | * long UUID; and we're comparing against the remainder. */ 49 | if ((byteIndex == 2) || (byteIndex == 3)) { 50 | continue; 51 | } 52 | 53 | if (convertedUUIDTable[i].uuid[byteIndex] != uuid[byteIndex]) { 54 | break; 55 | } 56 | } 57 | 58 | if (byteIndex == UUID::LENGTH_OF_LONG_UUID) { 59 | *recoveredType = convertedUUIDTable[i].type; 60 | return true; 61 | } 62 | } 63 | 64 | return false; 65 | } 66 | 67 | static void 68 | addToConvertedUUIDTable(const UUID::LongUUIDBytes_t uuid, uint8_t type) 69 | { 70 | if (uuidTableEntries == UUID_TABLE_MAX_ENTRIES) { 71 | return; /* recovery needed; or at least the user should be warned about this fact.*/ 72 | } 73 | 74 | memcpy(convertedUUIDTable[uuidTableEntries].uuid, uuid, UUID::LENGTH_OF_LONG_UUID); 75 | convertedUUIDTable[uuidTableEntries].uuid[2] = 0; 76 | convertedUUIDTable[uuidTableEntries].uuid[3] = 0; 77 | convertedUUIDTable[uuidTableEntries].type = type; 78 | uuidTableEntries++; 79 | } 80 | 81 | /** 82 | * The nRF transport has its own 3-byte representation of a UUID. If the user- 83 | * specified UUID is 128-bits wide, then the UUID base needs to be added to the 84 | * soft-device and converted to a 3-byte handle before being used further. This 85 | * function is responsible for this translation of user-specified UUIDs into 86 | * nRF's representation. 87 | * 88 | * @param[in] uuid 89 | * user-specified UUID 90 | * @return nRF 91 | * 3-byte UUID (containing a type and 16-bit UUID) representation 92 | * to be used with SVC calls. 93 | */ 94 | ble_uuid_t custom_convert_to_nordic_uuid(const UUID &uuid) 95 | { 96 | ble_uuid_t nordicUUID; 97 | nordicUUID.uuid = uuid.getShortUUID(); 98 | nordicUUID.type = BLE_UUID_TYPE_UNKNOWN; /* to be set below */ 99 | 100 | if (uuid.shortOrLong() == UUID::UUID_TYPE_SHORT) { 101 | nordicUUID.type = BLE_UUID_TYPE_BLE; 102 | } else { 103 | if (!lookupConvertedUUIDTable(uuid.getBaseUUID(), &nordicUUID.type)) { 104 | nordicUUID.type = custom_add_uuid_base(uuid.getBaseUUID()); 105 | addToConvertedUUIDTable(uuid.getBaseUUID(), nordicUUID.type); 106 | } 107 | } 108 | 109 | return nordicUUID; 110 | } 111 | 112 | /**************************************************************************/ 113 | /*! 114 | @brief Adds the base UUID to the custom service. All UUIDs used 115 | by this service are based on this 128-bit UUID. 116 | 117 | @note This UUID needs to be added to the SoftDevice stack before 118 | adding the service's primary service via 119 | 'sd_ble_gatts_service_add' 120 | 121 | @param[in] p_uuid_base A pointer to the 128-bit UUID array (8*16) 122 | 123 | @returns The UUID type. 124 | A return value of 0 should be considered an error. 125 | 126 | @retval 0x00 BLE_UUID_TYPE_UNKNOWN 127 | @retval 0x01 BLE_UUID_TYPE_BLE 128 | @retval 0x02 BLE_UUID_TYPE_VENDOR_BEGIN 129 | 130 | @section EXAMPLE 131 | @code 132 | 133 | // Take note that bytes 2/3 are blank since these are used to identify 134 | // the primary service and individual characteristics 135 | #define CFG_CUSTOM_UUID_BASE "\x6E\x40\x00\x00\xB5\xA3\xF3\x93\xE0\xA9\xE5\x0E\x24\xDC\xCA\x9E" 136 | 137 | uint8_t uuid_type = custom_add_uuid_base(CFG_CUSTOM_UUID_BASE); 138 | ASSERT(uuid_type > 0, ERROR_NOT_FOUND); 139 | 140 | // We can now safely add the primary service and any characteristics 141 | // for our custom service ... 142 | 143 | @endcode 144 | */ 145 | /**************************************************************************/ 146 | uint8_t custom_add_uuid_base(uint8_t const *const p_uuid_base) 147 | { 148 | ble_uuid128_t base_uuid; 149 | uint8_t uuid_type = 0; 150 | 151 | for (unsigned i = 0; i < UUID::LENGTH_OF_LONG_UUID; i++) { 152 | base_uuid.uuid128[i] = p_uuid_base[i]; 153 | } 154 | 155 | ASSERT_INT( ERROR_NONE, sd_ble_uuid_vs_add( &base_uuid, &uuid_type ), 0); 156 | 157 | return uuid_type; 158 | } 159 | 160 | /**************************************************************************/ 161 | /*! 162 | 163 | */ 164 | /**************************************************************************/ 165 | error_t custom_decode_uuid_base(uint8_t const *const p_uuid_base, 166 | ble_uuid_t *p_uuid) 167 | { 168 | UUID::LongUUIDBytes_t uuid_base_le; 169 | 170 | for (uint8_t i = 0; i < UUID::LENGTH_OF_LONG_UUID; i++) { 171 | uuid_base_le[i] = p_uuid_base[i]; 172 | } 173 | 174 | ASSERT_STATUS( sd_ble_uuid_decode(UUID::LENGTH_OF_LONG_UUID, uuid_base_le, p_uuid)); 175 | 176 | return ERROR_NONE; 177 | } 178 | 179 | /**************************************************************************/ 180 | /*! 181 | @brief Adds a new characteristic to the custom service, assigning 182 | properties, a UUID add-on value, etc. 183 | 184 | @param[in] service_handle 185 | @param[in] p_uuid The 16-bit value to add to the base UUID 186 | for this characteristic (normally >1 187 | since 1 is typically used by the primary 188 | service). 189 | @param[in] char_props The characteristic properties, as 190 | defined by ble_gatt_char_props_t 191 | @param[in] max_length The maximum length of this characeristic 192 | @param[in] has_variable_len Whether the characteristic data has 193 | variable length. 194 | @param[out] p_char_handle 195 | 196 | @returns 197 | @retval ERROR_NONE Everything executed normally 198 | */ 199 | /**************************************************************************/ 200 | error_t custom_add_in_characteristic(uint16_t service_handle, 201 | ble_uuid_t *p_uuid, 202 | uint8_t properties, 203 | SecurityManager::SecurityMode_t requiredSecurity, 204 | uint8_t *p_data, 205 | uint16_t length, 206 | uint16_t max_length, 207 | bool has_variable_len, 208 | const uint8_t *userDescriptionDescriptorValuePtr, 209 | uint16_t userDescriptionDescriptorValueLen, 210 | bool readAuthorization, 211 | bool writeAuthorization, 212 | ble_gatts_char_handles_t *p_char_handle) 213 | { 214 | /* Characteristic metadata */ 215 | ble_gatts_attr_md_t cccd_md; 216 | ble_gatt_char_props_t char_props; 217 | 218 | memcpy(&char_props, &properties, 1); 219 | 220 | if (char_props.notify || char_props.indicate) { 221 | /* Notification requires cccd */ 222 | memclr_( &cccd_md, sizeof(ble_gatts_attr_md_t)); 223 | cccd_md.vloc = BLE_GATTS_VLOC_STACK; 224 | BLE_GAP_CONN_SEC_MODE_SET_OPEN(&cccd_md.read_perm); 225 | BLE_GAP_CONN_SEC_MODE_SET_OPEN(&cccd_md.write_perm); 226 | } 227 | 228 | ble_gatts_char_md_t char_md = {0}; 229 | 230 | char_md.char_props = char_props; 231 | char_md.p_cccd_md = 232 | (char_props.notify || char_props.indicate) ? &cccd_md : NULL; 233 | if ((userDescriptionDescriptorValueLen > 0) && (userDescriptionDescriptorValuePtr != NULL)) { 234 | char_md.p_char_user_desc = const_cast(userDescriptionDescriptorValuePtr); 235 | char_md.char_user_desc_max_size = userDescriptionDescriptorValueLen; 236 | char_md.char_user_desc_size = userDescriptionDescriptorValueLen; 237 | } 238 | 239 | /* Attribute declaration */ 240 | ble_gatts_attr_md_t attr_md = {0}; 241 | 242 | attr_md.rd_auth = readAuthorization; 243 | attr_md.wr_auth = writeAuthorization; 244 | 245 | attr_md.vloc = BLE_GATTS_VLOC_STACK; 246 | /* Always set variable size */ 247 | attr_md.vlen = has_variable_len; 248 | 249 | if (char_props.read || char_props.notify || char_props.indicate) { 250 | switch (requiredSecurity) { 251 | case SecurityManager::SECURITY_MODE_ENCRYPTION_OPEN_LINK : 252 | BLE_GAP_CONN_SEC_MODE_SET_OPEN(&attr_md.read_perm); 253 | break; 254 | case SecurityManager::SECURITY_MODE_ENCRYPTION_NO_MITM : 255 | BLE_GAP_CONN_SEC_MODE_SET_ENC_NO_MITM(&attr_md.read_perm); 256 | break; 257 | case SecurityManager::SECURITY_MODE_ENCRYPTION_WITH_MITM : 258 | BLE_GAP_CONN_SEC_MODE_SET_ENC_WITH_MITM(&attr_md.read_perm); 259 | break; 260 | case SecurityManager::SECURITY_MODE_SIGNED_NO_MITM : 261 | BLE_GAP_CONN_SEC_MODE_SET_SIGNED_NO_MITM(&attr_md.read_perm); 262 | break; 263 | case SecurityManager::SECURITY_MODE_SIGNED_WITH_MITM : 264 | BLE_GAP_CONN_SEC_MODE_SET_SIGNED_WITH_MITM(&attr_md.read_perm); 265 | break; 266 | default: 267 | break; 268 | }; 269 | } 270 | 271 | if (char_props.write || char_props.write_wo_resp) { 272 | switch (requiredSecurity) { 273 | case SecurityManager::SECURITY_MODE_ENCRYPTION_OPEN_LINK : 274 | BLE_GAP_CONN_SEC_MODE_SET_OPEN(&attr_md.write_perm); 275 | break; 276 | case SecurityManager::SECURITY_MODE_ENCRYPTION_NO_MITM : 277 | BLE_GAP_CONN_SEC_MODE_SET_ENC_NO_MITM(&attr_md.write_perm); 278 | break; 279 | case SecurityManager::SECURITY_MODE_ENCRYPTION_WITH_MITM : 280 | BLE_GAP_CONN_SEC_MODE_SET_ENC_WITH_MITM(&attr_md.write_perm); 281 | break; 282 | case SecurityManager::SECURITY_MODE_SIGNED_NO_MITM : 283 | BLE_GAP_CONN_SEC_MODE_SET_SIGNED_NO_MITM(&attr_md.write_perm); 284 | break; 285 | case SecurityManager::SECURITY_MODE_SIGNED_WITH_MITM : 286 | BLE_GAP_CONN_SEC_MODE_SET_SIGNED_WITH_MITM(&attr_md.write_perm); 287 | break; 288 | default: 289 | break; 290 | }; 291 | } 292 | 293 | ble_gatts_attr_t attr_char_value = {0}; 294 | 295 | attr_char_value.p_uuid = p_uuid; 296 | attr_char_value.p_attr_md = &attr_md; 297 | attr_char_value.init_len = length; 298 | attr_char_value.max_len = max_length; 299 | attr_char_value.p_value = p_data; 300 | 301 | ASSERT_STATUS ( sd_ble_gatts_characteristic_add(service_handle, 302 | &char_md, 303 | &attr_char_value, 304 | p_char_handle)); 305 | 306 | return ERROR_NONE; 307 | } 308 | 309 | 310 | 311 | /**************************************************************************/ 312 | /*! 313 | @brief Adds a new descriptor to the custom service, assigning 314 | value, a UUID add-on value, etc. 315 | 316 | @param[in] char_handle 317 | @param[in] p_uuid The 16-bit value to add to the base UUID 318 | for this descriptor (normally >1 319 | since 1 is typically used by the primary 320 | service). 321 | @param[in] max_length The maximum length of this descriptor 322 | @param[in] has_variable_len Whether the characteristic data has 323 | variable length. 324 | 325 | @returns 326 | @retval ERROR_NONE Everything executed normally 327 | */ 328 | /**************************************************************************/ 329 | error_t custom_add_in_descriptor(uint16_t char_handle, 330 | ble_uuid_t *p_uuid, 331 | uint8_t *p_data, 332 | uint16_t length, 333 | uint16_t max_length, 334 | bool has_variable_len, 335 | uint16_t *p_desc_handle) 336 | { 337 | /* Descriptor metadata */ 338 | ble_gatts_attr_md_t desc_md = {0}; 339 | 340 | desc_md.vloc = BLE_GATTS_VLOC_STACK; 341 | /* Always set variable size */ 342 | desc_md.vlen = has_variable_len; 343 | 344 | /* Make it readable and writable */ 345 | BLE_GAP_CONN_SEC_MODE_SET_OPEN(&desc_md.read_perm); 346 | BLE_GAP_CONN_SEC_MODE_SET_OPEN(&desc_md.write_perm); 347 | 348 | ble_gatts_attr_t attr_desc = {0}; 349 | 350 | attr_desc.p_uuid = p_uuid; 351 | attr_desc.p_attr_md = &desc_md; 352 | attr_desc.init_len = length; 353 | attr_desc.max_len = max_length; 354 | attr_desc.p_value = p_data; 355 | 356 | ASSERT_STATUS ( sd_ble_gatts_descriptor_add(char_handle, 357 | &attr_desc, 358 | p_desc_handle)); 359 | 360 | return ERROR_NONE; 361 | } 362 | -------------------------------------------------------------------------------- /source/btle/custom/custom_helper.h: -------------------------------------------------------------------------------- 1 | /* mbed Microcontroller Library 2 | * Copyright (c) 2006-2013 ARM Limited 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #ifndef _CUSTOM_HELPER_H_ 18 | #define _CUSTOM_HELPER_H_ 19 | 20 | #include "common/common.h" 21 | #include "nrf_ble.h" 22 | #include "ble/UUID.h" 23 | #include "ble/GattCharacteristic.h" 24 | 25 | #ifdef __cplusplus 26 | extern "C" { 27 | #endif 28 | 29 | uint8_t custom_add_uuid_base(uint8_t const *const p_uuid_base); 30 | error_t custom_decode_uuid(uint8_t const *const p_uuid_base, 31 | ble_uuid_t *p_uuid); 32 | ble_uuid_t custom_convert_to_nordic_uuid(const UUID &uuid); 33 | 34 | error_t custom_add_in_characteristic(uint16_t service_handle, 35 | ble_uuid_t *p_uuid, 36 | uint8_t properties, 37 | SecurityManager::SecurityMode_t requiredSecurity, 38 | uint8_t *p_data, 39 | uint16_t length, 40 | uint16_t max_length, 41 | bool has_variable_len, 42 | const uint8_t *userDescriptionDescriptorValuePtr, 43 | uint16_t userDescriptionDescriptorValueLen, 44 | bool readAuthorization, 45 | bool writeAuthorization, 46 | ble_gatts_char_handles_t *p_char_handle); 47 | 48 | error_t custom_add_in_descriptor(uint16_t char_handle, 49 | ble_uuid_t *p_uuid, 50 | uint8_t *p_data, 51 | uint16_t length, 52 | uint16_t max_length, 53 | bool has_variable_len, 54 | uint16_t *p_desc_handle); 55 | 56 | #ifdef __cplusplus 57 | } 58 | #endif 59 | 60 | #endif // ifndef _CUSTOM_HELPER_H_ 61 | -------------------------------------------------------------------------------- /source/common/ansi_escape.h: -------------------------------------------------------------------------------- 1 | /**************************************************************************/ 2 | /*! 3 | @file ansi_esc_code.h 4 | @author hathach (tinyusb.org) 5 | 6 | @section LICENSE 7 | 8 | Software License Agreement (BSD License) 9 | 10 | Copyright (c) 2013, hathach (tinyusb.org) 11 | All rights reserved. 12 | 13 | Redistribution and use in source and binary forms, with or without 14 | modification, are permitted provided that the following conditions are met: 15 | 1. Redistributions of source code must retain the above copyright 16 | notice, this list of conditions and the following disclaimer. 17 | 2. Redistributions in binary form must reproduce the above copyright 18 | notice, this list of conditions and the following disclaimer in the 19 | documentation and/or other materials provided with the distribution. 20 | 3. Neither the name of the copyright holders nor the 21 | names of its contributors may be used to endorse or promote products 22 | derived from this software without specific prior written permission. 23 | 24 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY 25 | EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 26 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 27 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY 28 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 29 | INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 30 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION HOWEVER CAUSED AND 31 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 32 | INCLUDING NEGLIGENCE OR OTHERWISE ARISING IN ANY WAY OUT OF THE USE OF THIS 33 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 34 | 35 | This file is part of the tinyusb stack. 36 | */ 37 | /**************************************************************************/ 38 | 39 | /** \file 40 | * \brief TBD 41 | * 42 | * \note TBD 43 | */ 44 | 45 | /** \ingroup TBD 46 | * \defgroup TBD 47 | * \brief TBD 48 | * 49 | * @{ 50 | */ 51 | 52 | #ifndef _ANSI_ESC_CODE_H_ 53 | #define _ANSI_ESC_CODE_H_ 54 | 55 | 56 | #ifdef __cplusplus 57 | extern "C" { 58 | #endif 59 | 60 | #define CSI_CODE(seq) "\33[" seq 61 | #define CSI_SGR(x) CSI_CODE(#x) "m" 62 | 63 | //------------- Cursor movement -------------// 64 | #define ANSI_CURSOR_UP(n) CSI_CODE(#n "A") 65 | #define ANSI_CURSOR_DOWN(n) CSI_CODE(#n "B") 66 | #define ANSI_CURSOR_FORWARD(n) CSI_CODE(#n "C") 67 | #define ANSI_CURSOR_BACKWARD(n) CSI_CODE(#n "D") 68 | #define ANSI_CURSOR_LINE_DOWN(n) CSI_CODE(#n "E") 69 | #define ANSI_CURSOR_LINE_UP(n) CSI_CODE(#n "F") 70 | #define ANSI_CURSOR_POSITION(n, m) CSI_CODE(#n ";" #m "H") 71 | 72 | #define ANSI_ERASE_SCREEN(n) CSI_CODE(#n "J") 73 | #define ANSI_ERASE_LINE(n) CSI_CODE(#n "K") 74 | 75 | /** text color */ 76 | #define ANSI_TEXT_BLACK CSI_SGR(30) 77 | #define ANSI_TEXT_RED CSI_SGR(31) 78 | #define ANSI_TEXT_GREEN CSI_SGR(32) 79 | #define ANSI_TEXT_YELLOW CSI_SGR(33) 80 | #define ANSI_TEXT_BLUE CSI_SGR(34) 81 | #define ANSI_TEXT_MAGENTA CSI_SGR(35) 82 | #define ANSI_TEXT_CYAN CSI_SGR(36) 83 | #define ANSI_TEXT_WHITE CSI_SGR(37) 84 | #define ANSI_TEXT_DEFAULT CSI_SGR(39) 85 | 86 | /** background color */ 87 | #define ANSI_BG_BLACK CSI_SGR(40) 88 | #define ANSI_BG_RED CSI_SGR(41) 89 | #define ANSI_BG_GREEN CSI_SGR(42) 90 | #define ANSI_BG_YELLOW CSI_SGR(43) 91 | #define ANSI_BG_BLUE CSI_SGR(44) 92 | #define ANSI_BG_MAGENTA CSI_SGR(45) 93 | #define ANSI_BG_CYAN CSI_SGR(46) 94 | #define ANSI_BG_WHITE CSI_SGR(47) 95 | #define ANSI_BG_DEFAULT CSI_SGR(49) 96 | 97 | #ifdef __cplusplus 98 | } 99 | #endif 100 | 101 | #endif /* _TUSB_ANSI_ESC_CODE_H_ */ 102 | 103 | /** @} */ 104 | -------------------------------------------------------------------------------- /source/common/assertion.h: -------------------------------------------------------------------------------- 1 | /**************************************************************************/ 2 | /*! 3 | @file assertion.h 4 | @author hathach (tinyusb.org) 5 | 6 | @section LICENSE 7 | 8 | Software License Agreement (BSD License) 9 | 10 | Copyright (c) 2013, K. Townsend (microBuilder.eu) 11 | All rights reserved. 12 | 13 | Redistribution and use in source and binary forms, with or without 14 | modification, are permitted provided that the following conditions are met: 15 | 1. Redistributions of source code must retain the above copyright 16 | notice, this list of conditions and the following disclaimer. 17 | 2. Redistributions in binary form must reproduce the above copyright 18 | notice, this list of conditions and the following disclaimer in the 19 | documentation and/or other materials provided with the distribution. 20 | 3. Neither the name of the copyright holders nor the 21 | names of its contributors may be used to endorse or promote products 22 | derived from this software without specific prior written permission. 23 | 24 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY 25 | EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 26 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 27 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY 28 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 29 | INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 30 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION HOWEVER CAUSED AND 31 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 32 | INCLUDING NEGLIGENCE OR OTHERWISE ARISING IN ANY WAY OUT OF THE USE OF THIS 33 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 34 | */ 35 | /**************************************************************************/ 36 | 37 | /** \file 38 | * \brief TBD 39 | * 40 | * \note TBD 41 | */ 42 | 43 | /** \ingroup TBD 44 | * \defgroup TBD 45 | * \brief TBD 46 | * 47 | * @{ 48 | */ 49 | 50 | #ifndef _ASSERTION_H_ 51 | #define _ASSERTION_H_ 52 | 53 | #include "projectconfig.h" 54 | 55 | #ifdef __cplusplus 56 | extern "C" 57 | { 58 | #endif 59 | 60 | static inline void debugger_breakpoint(void) ATTR_ALWAYS_INLINE; 61 | static inline void debugger_breakpoint(void) 62 | { 63 | #ifndef _TEST_ 64 | __asm("BKPT #0\n"); 65 | #endif 66 | } 67 | 68 | //--------------------------------------------------------------------+ 69 | // Compile-time Assert 70 | //--------------------------------------------------------------------+ 71 | #if defined __COUNTER__ && __COUNTER__ != __COUNTER__ 72 | #define _ASSERT_COUNTER __COUNTER__ 73 | #else 74 | #define _ASSERT_COUNTER __LINE__ 75 | #endif 76 | 77 | #define ASSERT_STATIC(const_expr, message) enum { XSTRING_CONCAT_(static_assert_, _ASSERT_COUNTER) = 1/(!!(const_expr)) } 78 | 79 | //--------------------------------------------------------------------+ 80 | // Assert Helper 81 | //--------------------------------------------------------------------+ 82 | //#ifndef _TEST_ 83 | // #define ASSERT_MESSAGE(format, ...) _PRINTF("Assert at %s: %s: %d: " format "\n", __BASE_FILE__, __PRETTY_FUNCTION__, __LINE__, __VA_ARGS__) 84 | //#else 85 | // #define ASSERT_MESSAGE(format, ...) _PRINTF("%d:note: Assert " format "\n", __LINE__, __VA_ARGS__) 86 | //#endif 87 | 88 | #if CFG_DEBUG == 3 89 | #define ASSERT_MESSAGE(format, ...) debugger_breakpoint() 90 | #elif CFG_DEBUG == 2 91 | #define ASSERT_MESSAGE(format, ...) printf("Assert at %s: %s: %d: " format "\n", __BASE_FILE__, __PRETTY_FUNCTION__, __LINE__, __VA_ARGS__) 92 | #else 93 | #define ASSERT_MESSAGE(format, ...) 94 | #endif 95 | 96 | #define ASSERT_ERROR_HANDLER(x, para) \ 97 | return (x) 98 | 99 | #define ASSERT_DEFINE_WITH_HANDLER(error_handler, handler_para, setup_statement, condition, error, format, ...) \ 100 | do{\ 101 | setup_statement;\ 102 | if (!(condition)) {\ 103 | ASSERT_MESSAGE(format, __VA_ARGS__);\ 104 | error_handler(error, handler_para);\ 105 | }\ 106 | }while(0) 107 | 108 | #define ASSERT_DEFINE(...) ASSERT_DEFINE_WITH_HANDLER(ASSERT_ERROR_HANDLER, NULL, __VA_ARGS__) 109 | 110 | //--------------------------------------------------------------------+ 111 | // error_t Status Assert TODO use ASSERT_DEFINE 112 | //--------------------------------------------------------------------+ 113 | #define ASSERT_STATUS_MESSAGE(sts, message) \ 114 | ASSERT_DEFINE(error_t status = (error_t)(sts),\ 115 | ERROR_NONE == status, status, "%s: %s", ErrorStr[status], message) 116 | 117 | #define ASSERT_STATUS(sts) \ 118 | ASSERT_DEFINE(error_t status = (error_t)(sts),\ 119 | ERROR_NONE == status, status, "error = %d", status) 120 | 121 | #define ASSERT_STATUS_RET_VOID(sts) \ 122 | ASSERT_DEFINE(error_t status = (error_t)(sts),\ 123 | ERROR_NONE == status, (void) 0, "error = %d", status) 124 | 125 | //--------------------------------------------------------------------+ 126 | // Logical Assert 127 | //--------------------------------------------------------------------+ 128 | #define ASSERT(...) ASSERT_TRUE(__VA_ARGS__) 129 | #define ASSERT_TRUE(condition , error) ASSERT_DEFINE( , (condition), error, "%s", "evaluated to false") 130 | #define ASSERT_FALSE(condition , error) ASSERT_DEFINE( ,!(condition), error, "%s", "evaluated to true") 131 | 132 | //--------------------------------------------------------------------+ 133 | // Pointer Assert 134 | //--------------------------------------------------------------------+ 135 | #define ASSERT_PTR(...) ASSERT_PTR_NOT_NULL(__VA_ARGS__) 136 | #define ASSERT_PTR_NOT_NULL(pointer, error) ASSERT_DEFINE( , NULL != (pointer), error, "%s", "pointer is NULL") 137 | #define ASSERT_PTR_NULL(pointer, error) ASSERT_DEFINE( , NULL == (pointer), error, "%s", "pointer is not NULL") 138 | 139 | //--------------------------------------------------------------------+ 140 | // Integral Assert 141 | //--------------------------------------------------------------------+ 142 | #define ASSERT_XXX_EQUAL(type_format, expected, actual, error) \ 143 | ASSERT_DEFINE(\ 144 | uint32_t exp = (expected); uint32_t act = (actual),\ 145 | exp==act,\ 146 | error,\ 147 | "expected " type_format ", actual " type_format, exp, act) 148 | 149 | #define ASSERT_XXX_WITHIN(type_format, lower, upper, actual, error) \ 150 | ASSERT_DEFINE(\ 151 | uint32_t low = (lower); uint32_t up = (upper); uint32_t act = (actual),\ 152 | (low <= act) && (act <= up),\ 153 | error,\ 154 | "expected within " type_format " - " type_format ", actual " type_format, low, up, act) 155 | 156 | //--------------------------------------------------------------------+ 157 | // Integer Assert 158 | //--------------------------------------------------------------------+ 159 | #define ASSERT_INT(...) ASSERT_INT_EQUAL(__VA_ARGS__) 160 | #define ASSERT_INT_EQUAL(...) ASSERT_XXX_EQUAL("%d", __VA_ARGS__) 161 | #define ASSERT_INT_WITHIN(...) ASSERT_XXX_WITHIN("%d", __VA_ARGS__) 162 | 163 | //--------------------------------------------------------------------+ 164 | // Hex Assert 165 | //--------------------------------------------------------------------+ 166 | #define ASSERT_HEX(...) ASSERT_HEX_EQUAL(__VA_ARGS__) 167 | #define ASSERT_HEX_EQUAL(...) ASSERT_XXX_EQUAL("0x%x", __VA_ARGS__) 168 | #define ASSERT_HEX_WITHIN(...) ASSERT_XXX_WITHIN("0x%x", __VA_ARGS__) 169 | 170 | //--------------------------------------------------------------------+ 171 | // Bin Assert 172 | //--------------------------------------------------------------------+ 173 | #define BIN8_PRINTF_PATTERN "%d%d%d%d%d%d%d%d" 174 | #define BIN8_PRINTF_CONVERT(byte) \ 175 | ((byte) & 0x80 ? 1 : 0), \ 176 | ((byte) & 0x40 ? 1 : 0), \ 177 | ((byte) & 0x20 ? 1 : 0), \ 178 | ((byte) & 0x10 ? 1 : 0), \ 179 | ((byte) & 0x08 ? 1 : 0), \ 180 | ((byte) & 0x04 ? 1 : 0), \ 181 | ((byte) & 0x02 ? 1 : 0), \ 182 | ((byte) & 0x01 ? 1 : 0) 183 | 184 | #define ASSERT_BIN8(...) ASSERT_BIN8_EQUAL(__VA_ARGS__) 185 | #define ASSERT_BIN8_EQUAL(expected, actual, error)\ 186 | ASSERT_DEFINE(\ 187 | uint8_t exp = (expected); uint8_t act = (actual),\ 188 | exp==act,\ 189 | error,\ 190 | "expected " BIN8_PRINTF_PATTERN ", actual " BIN8_PRINTF_PATTERN, BIN8_PRINTF_CONVERT(exp), BIN8_PRINTF_CONVERT(act) ) 191 | 192 | #ifdef __cplusplus 193 | } 194 | #endif 195 | 196 | #endif /* _ASSERTION_H_ */ 197 | 198 | /** @} */ 199 | -------------------------------------------------------------------------------- /source/common/binary.h: -------------------------------------------------------------------------------- 1 | /**************************************************************************/ 2 | /*! 3 | @file binary.h 4 | @author hathach (tinyusb.org) 5 | 6 | @section LICENSE 7 | 8 | Software License Agreement (BSD License) 9 | 10 | Copyright (c) 2013, K. Townsend (microBuilder.eu) 11 | All rights reserved. 12 | 13 | Redistribution and use in source and binary forms, with or without 14 | modification, are permitted provided that the following conditions are met: 15 | 1. Redistributions of source code must retain the above copyright 16 | notice, this list of conditions and the following disclaimer. 17 | 2. Redistributions in binary form must reproduce the above copyright 18 | notice, this list of conditions and the following disclaimer in the 19 | documentation and/or other materials provided with the distribution. 20 | 3. Neither the name of the copyright holders nor the 21 | names of its contributors may be used to endorse or promote products 22 | derived from this software without specific prior written permission. 23 | 24 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY 25 | EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 26 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 27 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY 28 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 29 | INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 30 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION HOWEVER CAUSED AND 31 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 32 | INCLUDING NEGLIGENCE OR OTHERWISE ARISING IN ANY WAY OUT OF THE USE OF THIS 33 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 34 | */ 35 | /**************************************************************************/ 36 | 37 | /** \ingroup TBD 38 | * \defgroup TBD 39 | * \brief TBD 40 | * 41 | * @{ 42 | */ 43 | 44 | #ifndef _BINARY_H_ 45 | #define _BINARY_H_ 46 | 47 | #ifdef __cplusplus 48 | extern "C" { 49 | #endif 50 | 51 | /// n-th Bit 52 | #define BIT(n) (1 << (n)) 53 | 54 | /// set n-th bit of x to 1 55 | #define BIT_SET(x, n) ( (x) | BIT(n) ) 56 | 57 | /// clear n-th bit of x 58 | #define BIT_CLR(x, n) ( (x) & (~BIT(n)) ) 59 | 60 | /// test n-th bit of x 61 | #define BIT_TEST(x, n) ( (x) & BIT(n) ) 62 | 63 | #if defined(__GNUC__) && !defined(__CC_ARM) // keil does not support binary format 64 | 65 | #define BIN8(x) ((uint8_t) (0b##x)) 66 | #define BIN16(b1, b2) ((uint16_t) (0b##b1##b2)) 67 | #define BIN32(b1, b2, b3, b4) ((uint32_t) (0b##b1##b2##b3##b4)) 68 | 69 | #else 70 | 71 | // internal macro of B8, B16, B32 72 | #define _B8__(x) (((x&0x0000000FUL)?1:0) \ 73 | +((x&0x000000F0UL)?2:0) \ 74 | +((x&0x00000F00UL)?4:0) \ 75 | +((x&0x0000F000UL)?8:0) \ 76 | +((x&0x000F0000UL)?16:0) \ 77 | +((x&0x00F00000UL)?32:0) \ 78 | +((x&0x0F000000UL)?64:0) \ 79 | +((x&0xF0000000UL)?128:0)) 80 | 81 | #define BIN8(d) ((uint8_t) _B8__(0x##d##UL)) 82 | #define BIN16(dmsb,dlsb) (((uint16_t)BIN8(dmsb)<<8) + BIN8(dlsb)) 83 | #define BIN32(dmsb,db2,db3,dlsb) \ 84 | (((uint32_t)BIN8(dmsb)<<24) \ 85 | + ((uint32_t)BIN8(db2)<<16) \ 86 | + ((uint32_t)BIN8(db3)<<8) \ 87 | + BIN8(dlsb)) 88 | #endif 89 | 90 | #ifdef __cplusplus 91 | } 92 | #endif 93 | 94 | #endif /* _BINARY_H_ */ 95 | 96 | /** @} */ 97 | -------------------------------------------------------------------------------- /source/common/ble_error.h: -------------------------------------------------------------------------------- 1 | /**************************************************************************/ 2 | /*! 3 | @file ble_error.h 4 | @author hathach (tinyusb.org) 5 | 6 | @section LICENSE 7 | 8 | Software License Agreement (BSD License) 9 | 10 | Copyright (c) 2013, K. Townsend (microBuilder.eu) 11 | All rights reserved. 12 | 13 | Redistribution and use in source and binary forms, with or without 14 | modification, are permitted provided that the following conditions are met: 15 | 1. Redistributions of source code must retain the above copyright 16 | notice, this list of conditions and the following disclaimer. 17 | 2. Redistributions in binary form must reproduce the above copyright 18 | notice, this list of conditions and the following disclaimer in the 19 | documentation and/or other materials provided with the distribution. 20 | 3. Neither the name of the copyright holders nor the 21 | names of its contributors may be used to endorse or promote products 22 | derived from this software without specific prior written permission. 23 | 24 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY 25 | EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 26 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 27 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY 28 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 29 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 30 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 31 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 32 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 33 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 34 | */ 35 | /**************************************************************************/ 36 | 37 | /** \file 38 | * \brief Error Header 39 | * 40 | * \note TBD 41 | */ 42 | 43 | /** \ingroup Group_Common 44 | * \defgroup Group_Error Error Codes 45 | * @{ 46 | */ 47 | 48 | #ifndef _BLE_ERROR_H_ 49 | #define _BLE_ERROR_H_ 50 | 51 | #include "projectconfig.h" 52 | 53 | #ifdef __cplusplus 54 | extern "C" { 55 | #endif 56 | 57 | typedef enum 58 | { 59 | /*======================================================================= 60 | NORDIC GLOBAL ERRORS 0x0000 .. 0x00FF 61 | ----------------------------------------------------------------------- 62 | Errors mapped from nrf_error.h 63 | -----------------------------------------------------------------------*/ 64 | ERROR_NONE = 0x0000 , ///< Successful command 65 | ERROR_SVC_HANDLER_MISSING = 0x0001 , ///< SVC handler is missing 66 | ERROR_SOFTDEVICE_NOT_ENABLED = 0x0002 , ///< SoftDevice has not been enabled 67 | ERROR_INTERNAL = 0x0003 , ///< Internal Error 68 | ERROR_NO_MEM = 0x0004 , ///< No Memory for operation 69 | ERROR_NOT_FOUND = 0x0005 , ///< Not found 70 | ERROR_NOT_SUPPORTED = 0x0006 , ///< Not supported 71 | ERROR_INVALID_PARAM = 0x0007 , ///< Invalid Parameter 72 | ERROR_INVALID_STATE = 0x0008 , ///< Invalid state, operation disallowed in this state 73 | ERROR_INVALID_LENGTH = 0x0009 , ///< Invalid Length 74 | ERROR_INVALID_FLAGS = 0x000A , ///< Invalid Flags 75 | ERROR_INVALID_DATA = 0x000B , ///< Invalid Data 76 | ERROR_DATA_SIZE = 0x000C , ///< Data size exceeds limit 77 | ERROR_TIMEOUT = 0x000D , ///< Operation timed out 78 | ERROR_NULL = 0x000E , ///< Null Pointer 79 | ERROR_FORBIDDEN = 0x000F , ///< Forbidden Operation 80 | ERROR_INVALID_ADDR = 0x0010 , ///< Bad Memory Address 81 | ERROR_BUSY = 0x0011 , ///< Busy 82 | /*=======================================================================*/ 83 | 84 | ERROR_INVALIDPARAMETER = 0x0100 , /**< An invalid parameter value was provided */ 85 | ERROR_I2C_XFER_FAILED = 0x0101 , /**< an failed attempt to make I2C transfer */ 86 | 87 | /*======================================================================= 88 | SIMPLE BINARY PROTOCOL ERRORS 0x0120 .. 0x013F 89 | ----------------------------------------------------------------------- 90 | Errors relating to the simple binary protocol (/src//protocol) 91 | -----------------------------------------------------------------------*/ 92 | ERROR_PROT_INVALIDMSGTYPE = 0x121, /**< Unexpected msg type encountered */ 93 | ERROR_PROT_INVALIDCOMMANDID = 0x122, /**< Unknown or out of range command ID */ 94 | ERROR_PROT_INVALIDPAYLOAD = 0x123, /**< Message payload has a problem (invalid len, etc.) */ 95 | /*=======================================================================*/ 96 | 97 | //------------- based on Nordic SDM nrf_error_sdm.h -------------// 98 | ERROR_SDM_LFCLK_SOURCE_UNKNOWN = 0x1000 , ///< Unknown lfclk source 99 | ERROR_SDM_INCORRECT_INTERRUPT_CONFIGURATION = 0x1001 , ///< Incorrect interrupt configuration (can be caused by using illegal priority levels, or having enabled SoftDevice interrupts) 100 | ERROR_SDM_INCORRECT_CLENR0 = 0x1002 , ///< Incorrect CLENR0 (can be caused by erronous SoftDevice flashing) 101 | 102 | //------------- based on Nordic SOC nrf_error_soc.h -------------// 103 | /* Mutex Errors */ 104 | ERROR_SOC_MUTEX_ALREADY_TAKEN = 0x2000 , ///< Mutex already taken 105 | 106 | /* NVIC errors */ 107 | ERROR_SOC_NVIC_INTERRUPT_NOT_AVAILABLE = 0x2001 , ///< NVIC interrupt not available 108 | ERROR_SOC_NVIC_INTERRUPT_PRIORITY_NOT_ALLOWED = 0x2002 , ///< NVIC interrupt priority not allowed 109 | ERROR_SOC_NVIC_SHOULD_NOT_RETURN = 0x2003 , ///< NVIC should not return 110 | 111 | /* Power errors */ 112 | ERROR_SOC_POWER_MODE_UNKNOWN = 0x2004 , ///< Power mode unknown 113 | ERROR_SOC_POWER_POF_THRESHOLD_UNKNOWN = 0x2005 , ///< Power POF threshold unknown 114 | ERROR_SOC_POWER_OFF_SHOULD_NOT_RETURN = 0x2006 , ///< Power off should not return 115 | 116 | /* Rand errors */ 117 | ERROR_SOC_RAND_NOT_ENOUGH_VALUES = 0x2007 , ///< RAND not enough values 118 | 119 | /* PPI errors */ 120 | ERROR_SOC_PPI_INVALID_CHANNEL = 0x2008 , ///< Invalid PPI Channel 121 | ERROR_SOC_PPI_INVALID_GROUP = 0x2009 , ///< Invalid PPI Group 122 | 123 | //------------- based on Nordic STK (ble) ble_err.h -------------// 124 | ERROR_BLE_INVALID_CONN_HANDLE = 0x3001 , /**< Invalid connection handle. */ 125 | ERROR_BLE_INVALID_ATTR_HANDLE = 0x3002 , /**< Invalid attribute handle. */ 126 | ERROR_BLE_NO_TX_BUFFERS = 0x3003 , /**< Buffer capacity exceeded. */ 127 | 128 | // L2CAP 129 | ERROR_BLE_L2CAP_CID_IN_USE = 0x3100 , /**< CID already in use. */ 130 | 131 | // GAP 132 | ERROR_BLE_GAP_UUID_LIST_MISMATCH = 0x3200 , /**< UUID list does not contain an integral number of UUIDs. */ 133 | ERROR_BLE_GAP_DISCOVERABLE_WITH_WHITELIST = 0x3201 , /**< Use of Whitelist not permitted with discoverable advertising. */ 134 | ERROR_BLE_GAP_INVALID_BLE_ADDR = 0x3202 , /**< The upper two bits of the address do not correspond to the specified address type. */ 135 | 136 | // GATTC 137 | ERROR_BLE_GATTC_PROC_NOT_PERMITTED = 0x3300 , 138 | 139 | // GATTS 140 | ERROR_BLEGATTS_INVALID_ATTR_TYPE = 0x3400 , /**< Invalid attribute type. */ 141 | ERROR_BLEGATTS_SYS_ATTR_MISSING = 0x3401 , /**< System Attributes missing. */ 142 | 143 | }error_t; 144 | 145 | #ifdef __cplusplus 146 | } 147 | #endif 148 | 149 | #endif /* _BLE_ERROR_H_ */ 150 | 151 | /** @} */ 152 | -------------------------------------------------------------------------------- /source/common/common.h: -------------------------------------------------------------------------------- 1 | /**************************************************************************/ 2 | /*! 3 | @file common.h 4 | @author hathach (tinyusb.org) 5 | 6 | @section LICENSE 7 | 8 | Software License Agreement (BSD License) 9 | 10 | Copyright (c) 2013, K. Townsend (microBuilder.eu) 11 | All rights reserved. 12 | 13 | Redistribution and use in source and binary forms, with or without 14 | modification, are permitted provided that the following conditions are met: 15 | 1. Redistributions of source code must retain the above copyright 16 | notice, this list of conditions and the following disclaimer. 17 | 2. Redistributions in binary form must reproduce the above copyright 18 | notice, this list of conditions and the following disclaimer in the 19 | documentation and/or other materials provided with the distribution. 20 | 3. Neither the name of the copyright holders nor the 21 | names of its contributors may be used to endorse or promote products 22 | derived from this software without specific prior written permission. 23 | 24 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY 25 | EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 26 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 27 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY 28 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 29 | INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 30 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION HOWEVER CAUSED AND 31 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 32 | INCLUDING NEGLIGENCE OR OTHERWISE ARISING IN ANY WAY OUT OF THE USE OF THIS 33 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 34 | */ 35 | /**************************************************************************/ 36 | 37 | /** \defgroup Group_Common Common Files 38 | * @{ 39 | * 40 | * \defgroup Group_CommonH common.h 41 | * 42 | * @{ 43 | */ 44 | 45 | #ifndef _COMMON_H_ 46 | #define _COMMON_H_ 47 | 48 | #ifdef __cplusplus 49 | extern "C" { 50 | #endif 51 | 52 | //--------------------------------------------------------------------+ 53 | // INCLUDES 54 | //--------------------------------------------------------------------+ 55 | 56 | //------------- Standard Header -------------// 57 | #include 58 | #include 59 | #include 60 | #include 61 | #include 62 | 63 | //------------- General Header -------------// 64 | #include "projectconfig.h" 65 | #include "compiler.h" 66 | #include "assertion.h" 67 | #include "binary.h" 68 | #include "ble_error.h" 69 | 70 | //------------- MCU header -------------// 71 | //#include "nrf.h" 72 | 73 | //--------------------------------------------------------------------+ 74 | // TYPEDEFS 75 | //--------------------------------------------------------------------+ 76 | typedef unsigned char byte_t; 77 | typedef float float32_t; 78 | typedef double float64_t; 79 | 80 | //--------------------------------------------------------------------+ 81 | // MACROS 82 | //--------------------------------------------------------------------+ 83 | #define STRING_(x) #x // stringify without expand 84 | #define XSTRING_(x) STRING_(x) // expand then stringify 85 | #define STRING_CONCAT_(a, b) a##b // concat without expand 86 | #define XSTRING_CONCAT_(a, b) STRING_CONCAT_(a, b) // expand then concat 87 | 88 | #define U16_HIGH_U8(u16) ((uint8_t) (((u16) >> 8) & 0x00ff)) 89 | #define U16_LOW_U8(u16) ((uint8_t) ((u16) & 0x00ff)) 90 | #define U16_TO_U8S_BE(u16) U16_HIGH_U8(u16), U16_LOW_U8(u16) 91 | #define U16_TO_U8S_LE(u16) U16_LOW_U8(u16), U16_HIGH_U8(u16) 92 | 93 | #define U32_B1_U8(u32) ((uint8_t) (((u32) >> 24) & 0x000000ff)) // MSB 94 | #define U32_B2_U8(u32) ((uint8_t) (((u32) >> 16) & 0x000000ff)) 95 | #define U32_B3_U8(u32) ((uint8_t) (((u32) >> 8) & 0x000000ff)) 96 | #define U32_B4_U8(u32) ((uint8_t) ((u32) & 0x000000ff)) // LSB 97 | 98 | #define U32_TO_U8S_BE(u32) U32_B1_U8(u32), U32_B2_U8(u32), U32_B3_U8(u32), U32_B4_U8(u32) 99 | #define U32_TO_U8S_LE(u32) U32_B4_U8(u32), U32_B3_U8(u32), U32_B2_U8(u32), U32_B1_U8(u32) 100 | 101 | //--------------------------------------------------------------------+ 102 | // INLINE FUNCTION 103 | //--------------------------------------------------------------------+ 104 | #define memclr_(buffer, size) memset(buffer, 0, size) 105 | 106 | //------------- Conversion -------------// 107 | /// form an uint32_t from 4 x uint8_t 108 | static inline uint32_t u32_from_u8(uint8_t b1, uint8_t b2, uint8_t b3, uint8_t b4) ATTR_ALWAYS_INLINE ATTR_CONST; 109 | static inline uint32_t u32_from_u8(uint8_t b1, uint8_t b2, uint8_t b3, uint8_t b4) 110 | { 111 | return (b1 << 24) + (b2 << 16) + (b3 << 8) + b4; 112 | } 113 | 114 | static inline uint8_t u16_high_u8(uint16_t u16) ATTR_CONST ATTR_ALWAYS_INLINE; 115 | static inline uint8_t u16_high_u8(uint16_t u16) 116 | { 117 | return (uint8_t) ((u16 >> 8) & 0x00ff); 118 | } 119 | 120 | static inline uint8_t u16_low_u8(uint16_t u16) ATTR_CONST ATTR_ALWAYS_INLINE; 121 | static inline uint8_t u16_low_u8(uint16_t u16) 122 | { 123 | return (uint8_t) (u16 & 0x00ff); 124 | } 125 | 126 | //------------- Min -------------// 127 | static inline uint8_t min8_of(uint8_t x, uint8_t y) ATTR_ALWAYS_INLINE ATTR_CONST; 128 | static inline uint8_t min8_of(uint8_t x, uint8_t y) 129 | { 130 | return (x < y) ? x : y; 131 | } 132 | 133 | static inline uint16_t min16_of(uint16_t x, uint16_t y) ATTR_ALWAYS_INLINE ATTR_CONST; 134 | static inline uint16_t min16_of(uint16_t x, uint16_t y) 135 | { 136 | return (x < y) ? x : y; 137 | } 138 | 139 | static inline uint32_t min32_of(uint32_t x, uint32_t y) ATTR_ALWAYS_INLINE ATTR_CONST; 140 | static inline uint32_t min32_of(uint32_t x, uint32_t y) 141 | { 142 | return (x < y) ? x : y; 143 | } 144 | 145 | //------------- Max -------------// 146 | static inline uint32_t max32_of(uint32_t x, uint32_t y) ATTR_ALWAYS_INLINE ATTR_CONST; 147 | static inline uint32_t max32_of(uint32_t x, uint32_t y) 148 | { 149 | return (x > y) ? x : y; 150 | } 151 | 152 | //------------- Align -------------// 153 | static inline uint32_t align32 (uint32_t value) ATTR_ALWAYS_INLINE ATTR_CONST; 154 | static inline uint32_t align32 (uint32_t value) 155 | { 156 | return (value & 0xFFFFFFE0UL); 157 | } 158 | 159 | static inline uint32_t align16 (uint32_t value) ATTR_ALWAYS_INLINE ATTR_CONST; 160 | static inline uint32_t align16 (uint32_t value) 161 | { 162 | return (value & 0xFFFFFFF0UL); 163 | } 164 | 165 | static inline uint32_t align_n (uint32_t alignment, uint32_t value) ATTR_ALWAYS_INLINE ATTR_CONST; 166 | static inline uint32_t align_n (uint32_t alignment, uint32_t value) 167 | { 168 | return value & (~(alignment-1)); 169 | } 170 | 171 | static inline uint32_t align4k (uint32_t value) ATTR_ALWAYS_INLINE ATTR_CONST; 172 | static inline uint32_t align4k (uint32_t value) 173 | { 174 | return (value & 0xFFFFF000UL); 175 | } 176 | 177 | static inline uint32_t offset4k(uint32_t value) ATTR_ALWAYS_INLINE ATTR_CONST; 178 | static inline uint32_t offset4k(uint32_t value) 179 | { 180 | return (value & 0xFFFUL); 181 | } 182 | 183 | //------------- Mathematics -------------// 184 | /// inclusive range checking 185 | static inline bool is_in_range(uint32_t lower, uint32_t value, uint32_t upper) ATTR_ALWAYS_INLINE ATTR_CONST; 186 | static inline bool is_in_range(uint32_t lower, uint32_t value, uint32_t upper) 187 | { 188 | return (lower <= value) && (value <= upper); 189 | } 190 | 191 | /// exclusive range checking 192 | static inline bool is_in_range_exclusive(uint32_t lower, uint32_t value, uint32_t upper) ATTR_ALWAYS_INLINE ATTR_CONST; 193 | static inline bool is_in_range_exclusive(uint32_t lower, uint32_t value, uint32_t upper) 194 | { 195 | return (lower < value) && (value < upper); 196 | } 197 | 198 | static inline uint8_t log2_of(uint32_t value) ATTR_ALWAYS_INLINE ATTR_CONST; 199 | static inline uint8_t log2_of(uint32_t value) 200 | { 201 | uint8_t result = 0; // log2 of a value is its MSB's position 202 | 203 | while (value >>= 1) 204 | { 205 | result++; 206 | } 207 | return result; 208 | } 209 | 210 | // return the number of set bits in value 211 | static inline uint8_t cardinality_of(uint32_t value) ATTR_ALWAYS_INLINE ATTR_CONST; 212 | static inline uint8_t cardinality_of(uint32_t value) 213 | { 214 | // Brian Kernighan's method goes through as many iterations as there are set bits. So if we have a 32-bit word with only 215 | // the high bit set, then it will only go once through the loop 216 | // Published in 1988, the C Programming Language 2nd Ed. (by Brian W. Kernighan and Dennis M. Ritchie) 217 | // mentions this in exercise 2-9. On April 19, 2006 Don Knuth pointed out to me that this method 218 | // "was first published by Peter Wegner in CACM 3 (1960), 322. (Also discovered independently by Derrick Lehmer and 219 | // published in 1964 in a book edited by Beckenbach.)" 220 | uint8_t count; 221 | for (count = 0; value; count++) 222 | { 223 | value &= value - 1; // clear the least significant bit set 224 | } 225 | 226 | return count; 227 | } 228 | 229 | #ifdef __cplusplus 230 | } 231 | #endif 232 | 233 | #endif /* _COMMON_H_ */ 234 | 235 | /** @} */ 236 | /** @} */ 237 | -------------------------------------------------------------------------------- /source/common/compiler.h: -------------------------------------------------------------------------------- 1 | /**************************************************************************/ 2 | /*! 3 | @file compiler.h 4 | @author hathach (tinyusb.org) 5 | 6 | @section LICENSE 7 | 8 | Software License Agreement (BSD License) 9 | 10 | Copyright (c) 2013, K. Townsend (microBuilder.eu) 11 | All rights reserved. 12 | 13 | Redistribution and use in source and binary forms, with or without 14 | modification, are permitted provided that the following conditions are met: 15 | 1. Redistributions of source code must retain the above copyright 16 | notice, this list of conditions and the following disclaimer. 17 | 2. Redistributions in binary form must reproduce the above copyright 18 | notice, this list of conditions and the following disclaimer in the 19 | documentation and/or other materials provided with the distribution. 20 | 3. Neither the name of the copyright holders nor the 21 | names of its contributors may be used to endorse or promote products 22 | derived from this software without specific prior written permission. 23 | 24 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY 25 | EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 26 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 27 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY 28 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 29 | INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 30 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION HOWEVER CAUSED AND 31 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 32 | INCLUDING NEGLIGENCE OR OTHERWISE ARISING IN ANY WAY OUT OF THE USE OF THIS 33 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 34 | */ 35 | /**************************************************************************/ 36 | 37 | /** \file 38 | * \brief GCC Header 39 | */ 40 | 41 | /** \ingroup Group_Compiler 42 | * \defgroup Group_GCC GNU GCC 43 | * @{ 44 | */ 45 | 46 | #ifndef _COMPILER_GCC_H_ 47 | #define _COMPILER_GCC_H_ 48 | 49 | #ifdef __cplusplus 50 | extern "C" { 51 | #endif 52 | 53 | #include "projectconfig.h" 54 | 55 | //#ifndef __GNUC__ 56 | // #define ATTR_ALWAYS_INLINE 57 | // #define ATTR_CONST 58 | //#else 59 | 60 | #ifdef _TEST_ 61 | #define ATTR_ALWAYS_INLINE 62 | #define STATIC_ 63 | #define INLINE_ 64 | #else 65 | #define STATIC_ static 66 | #define INLINE_ inline 67 | 68 | #if CFG_DEBUG == 3 69 | #define ATTR_ALWAYS_INLINE // no inline for debug = 3 70 | #endif 71 | #endif 72 | 73 | #define ALIGN_OF(x) __alignof__(x) 74 | 75 | /// Normally, the compiler places the objects it generates in sections like data or bss & function in text. Sometimes, however, you need additional sections, or you need certain particular variables to appear in special sections, for example to map to special hardware. The section attribute specifies that a variable (or function) lives in a particular section 76 | #define ATTR_SECTION(section) __attribute__ ((#section)) 77 | 78 | /// If this attribute is used on a function declaration and a call to such a function is not eliminated through dead code elimination or other optimizations, an error that includes message is diagnosed. This is useful for compile-time checking 79 | #define ATTR_ERROR(Message) __attribute__ ((error(Message))) 80 | 81 | /// If this attribute is used on a function declaration and a call to such a function is not eliminated through dead code elimination or other optimizations, a warning that includes message is diagnosed. This is useful for compile-time checking 82 | #define ATTR_WARNING(Message) __attribute__ ((warning(Message))) 83 | 84 | /** 85 | * \defgroup Group_VariableAttr Variable Attributes 86 | * @{ 87 | */ 88 | 89 | /// This attribute specifies a minimum alignment for the variable or structure field, measured in bytes 90 | #define ATTR_ALIGNED(Bytes) __attribute__ ((aligned(Bytes))) 91 | 92 | /// The packed attribute specifies that a variable or structure field should have the smallest possible alignment—one byte for a variable, and one bit for a field, unless you specify a larger value with the aligned attribute 93 | #define ATTR_PACKED __attribute__ ((packed)) 94 | 95 | #define ATTR_PREPACKED 96 | 97 | #define ATTR_PACKED_STRUCT(x) x __attribute__ ((packed)) 98 | /** @} */ 99 | 100 | /** 101 | * \defgroup Group_FuncAttr Function Attributes 102 | * @{ 103 | */ 104 | 105 | #ifndef ATTR_ALWAYS_INLINE 106 | /// Generally, functions are not inlined unless optimization is specified. For functions declared inline, this attribute inlines the function even if no optimization level is specified 107 | #define ATTR_ALWAYS_INLINE __attribute__ ((always_inline)) 108 | #endif 109 | 110 | /// The nonnull attribute specifies that some function parameters should be non-null pointers. f the compiler determines that a null pointer is passed in an argument slot marked as non-null, and the -Wnonnull option is enabled, a warning is issued. All pointer arguments are marked as non-null 111 | #define ATTR_NON_NULL __attribute__ ((nonull)) 112 | 113 | /// Many functions have no effects except the return value and their return value depends only on the parameters and/or global variables. Such a function can be subject to common subexpression elimination and loop optimization just as an arithmetic operator would be. These functions should be declared with the attribute pure 114 | #define ATTR_PURE __attribute__ ((pure)) 115 | 116 | /// Many functions do not examine any values except their arguments, and have no effects except the return value. Basically this is just slightly more strict class than the pure attribute below, since function is not allowed to read global memory. 117 | /// Note that a function that has pointer arguments and examines the data pointed to must not be declared const. Likewise, a function that calls a non-const function usually must not be const. It does not make sense for a const function to return void 118 | #define ATTR_CONST __attribute__ ((const)) 119 | 120 | /// The deprecated attribute results in a warning if the function is used anywhere in the source file. This is useful when identifying functions that are expected to be removed in a future version of a program. The warning also includes the location of the declaration of the deprecated function, to enable users to easily find further information about why the function is deprecated, or what they should do instead. Note that the warnings only occurs for uses 121 | #define ATTR_DEPRECATED __attribute__ ((deprecated)) 122 | 123 | /// Same as the deprecated attribute with optional message in the warning 124 | #define ATTR_DEPRECATED_MESS(mess) __attribute__ ((deprecated(mess))) 125 | 126 | /// The weak attribute causes the declaration to be emitted as a weak symbol rather than a global. This is primarily useful in defining library functions that can be overridden in user code 127 | #define ATTR_WEAK __attribute__ ((weak)) 128 | 129 | /// The alias attribute causes the declaration to be emitted as an alias for another symbol, which must be specified 130 | #define ATTR_ALIAS(func) __attribute__ ((alias(#func))) 131 | 132 | /// The weakref attribute marks a declaration as a weak reference. It is equivalent with weak + alias attribute, but require function is static 133 | #define ATTR_WEAKREF(func) __attribute__ ((weakref(#func))) 134 | 135 | /// The warn_unused_result attribute causes a warning to be emitted if a caller of the function with this attribute does not use its return value. This is useful for functions where not checking the result is either a security problem or always a bug 136 | #define ATTR_WARN_UNUSED_RESULT __attribute__ ((warn_unused_result)) 137 | 138 | /// This attribute, attached to a function, means that code must be emitted for the function even if it appears that the function is not referenced. This is useful, for example, when the function is referenced only in inline assembly. 139 | #define ATTR_USED __attribute__ ((used)) 140 | 141 | /// This attribute, attached to a function, means that the function is meant to be possibly unused. GCC does not produce a warning for this function. 142 | #define ATTR_UNUSED __attribute__ ((unused)) 143 | 144 | /** @} */ 145 | 146 | #ifdef __cplusplus 147 | } 148 | #endif 149 | 150 | #endif /* _COMPILER_GCC_H_ */ 151 | 152 | /// @} 153 | -------------------------------------------------------------------------------- /source/nRF5xCharacteristicDescriptorDiscoverer.cpp: -------------------------------------------------------------------------------- 1 | /* mbed Microcontroller Library 2 | * Copyright (c) 2006-2015 ARM Limited 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | #include "nRF5xCharacteristicDescriptorDiscoverer.h" 17 | #include "ble_err.h" 18 | #include "ble/DiscoveredCharacteristicDescriptor.h" 19 | 20 | nRF5xCharacteristicDescriptorDiscoverer::nRF5xCharacteristicDescriptorDiscoverer() : 21 | discoveryRunning() { 22 | // nothing to do 23 | } 24 | 25 | nRF5xCharacteristicDescriptorDiscoverer::~nRF5xCharacteristicDescriptorDiscoverer() { 26 | // nothing to do 27 | } 28 | 29 | ble_error_t nRF5xCharacteristicDescriptorDiscoverer::launch( 30 | const DiscoveredCharacteristic& characteristic, 31 | const CharacteristicDescriptorDiscovery::DiscoveryCallback_t& discoveryCallback, 32 | const CharacteristicDescriptorDiscovery::TerminationCallback_t& terminationCallback 33 | ) { 34 | Gap::Handle_t connHandle = characteristic.getConnectionHandle(); 35 | // it is ok to deduce that the start handle for descriptors is after 36 | // the characteristic declaration and the characteristic value declaration 37 | // see BLUETOOTH SPECIFICATION Version 4.2 [Vol 3, Part G] (3.3) 38 | Gap::Handle_t descriptorStartHandle = characteristic.getDeclHandle() + 2; 39 | Gap::Handle_t descriptorEndHandle = characteristic.getLastHandle(); 40 | 41 | // check if there is any descriptor to discover 42 | if (descriptorEndHandle < descriptorStartHandle) { 43 | CharacteristicDescriptorDiscovery::TerminationCallbackParams_t termParams = { 44 | characteristic, 45 | BLE_ERROR_NONE 46 | }; 47 | terminationCallback.call(&termParams); 48 | return BLE_ERROR_NONE; 49 | } 50 | 51 | // check if we can run this discovery 52 | if (isConnectionInUse(connHandle)) { 53 | return BLE_STACK_BUSY; 54 | } 55 | 56 | // get a new discovery slot, if none are available, just return 57 | Discovery* discovery = getAvailableDiscoverySlot(); 58 | if(discovery == NULL) { 59 | return BLE_STACK_BUSY; 60 | } 61 | 62 | // try to launch the discovery 63 | ble_error_t err = gattc_descriptors_discover(connHandle, descriptorStartHandle, descriptorEndHandle); 64 | if(!err) { 65 | // commit the new discovery to its slot 66 | *discovery = Discovery(characteristic, discoveryCallback, terminationCallback); 67 | } 68 | 69 | return err; 70 | } 71 | 72 | bool nRF5xCharacteristicDescriptorDiscoverer::isActive(const DiscoveredCharacteristic& characteristic) const { 73 | for(size_t i = 0; i < MAXIMUM_CONCURRENT_CONNECTIONS_COUNT; ++i) { 74 | if(discoveryRunning[i].getCharacteristic() == characteristic) { 75 | return true; 76 | } 77 | } 78 | return false; 79 | } 80 | 81 | void nRF5xCharacteristicDescriptorDiscoverer::requestTerminate(const DiscoveredCharacteristic& characteristic) { 82 | Discovery* discovery = findRunningDiscovery(characteristic); 83 | if(discovery) { 84 | // call terminate anyway 85 | terminate(discovery, BLE_ERROR_NONE); 86 | } 87 | } 88 | 89 | void nRF5xCharacteristicDescriptorDiscoverer::process(uint16_t connectionHandle, const ble_gattc_evt_desc_disc_rsp_t& descriptors) { 90 | Discovery* discovery = findRunningDiscovery(connectionHandle); 91 | // the discovery has been removed 92 | if(!discovery) { 93 | return; 94 | } 95 | 96 | for (uint16_t i = 0; i < descriptors.count; ++i) { 97 | discovery->process( 98 | descriptors.descs[i].handle, UUID(descriptors.descs[i].uuid.uuid) 99 | ); 100 | } 101 | 102 | // prepare the next discovery request (if needed) 103 | uint16_t startHandle = descriptors.descs[descriptors.count - 1].handle + 1; 104 | uint16_t endHandle = discovery->getCharacteristic().getLastHandle(); 105 | 106 | if(startHandle > endHandle) { 107 | terminate(discovery, BLE_ERROR_NONE); 108 | return; 109 | } 110 | 111 | ble_error_t err = gattc_descriptors_discover(connectionHandle, startHandle, endHandle); 112 | if(err) { 113 | terminate(discovery, err); 114 | return; 115 | } 116 | } 117 | 118 | void nRF5xCharacteristicDescriptorDiscoverer::terminate(uint16_t handle, ble_error_t err) { 119 | Discovery* discovery = findRunningDiscovery(handle); 120 | // the discovery has already been terminated 121 | if(!discovery) { 122 | return; 123 | } 124 | 125 | terminate(discovery, err); 126 | } 127 | 128 | void nRF5xCharacteristicDescriptorDiscoverer::terminate(Discovery* discovery, ble_error_t err) { 129 | // temporary copy, user code can try to launch a new discovery in the onTerminate 130 | // callback. So, this discovery should not appear in such case. 131 | Discovery tmp = *discovery; 132 | *discovery = Discovery(); 133 | tmp.terminate(err); 134 | } 135 | 136 | nRF5xCharacteristicDescriptorDiscoverer::Discovery* 137 | nRF5xCharacteristicDescriptorDiscoverer::findRunningDiscovery(const DiscoveredCharacteristic& characteristic) { 138 | for(size_t i = 0; i < MAXIMUM_CONCURRENT_CONNECTIONS_COUNT; ++i) { 139 | if((discoveryRunning[i].getCharacteristic() == characteristic) && 140 | (discoveryRunning[i].isEmpty() == false)) { 141 | return &discoveryRunning[i]; 142 | } 143 | } 144 | return NULL; 145 | } 146 | 147 | nRF5xCharacteristicDescriptorDiscoverer::Discovery* 148 | nRF5xCharacteristicDescriptorDiscoverer::findRunningDiscovery(uint16_t handle) { 149 | for(size_t i = 0; i < MAXIMUM_CONCURRENT_CONNECTIONS_COUNT; ++i) { 150 | if((discoveryRunning[i].getCharacteristic().getConnectionHandle() == handle) && 151 | (discoveryRunning[i].isEmpty() == false)) { 152 | return &discoveryRunning[i]; 153 | } 154 | } 155 | return NULL; 156 | } 157 | 158 | nRF5xCharacteristicDescriptorDiscoverer::Discovery* 159 | nRF5xCharacteristicDescriptorDiscoverer::getAvailableDiscoverySlot() { 160 | for(size_t i = 0; i < MAXIMUM_CONCURRENT_CONNECTIONS_COUNT; ++i) { 161 | if(discoveryRunning[i].isEmpty()) { 162 | return &discoveryRunning[i]; 163 | } 164 | } 165 | return NULL; 166 | } 167 | 168 | bool nRF5xCharacteristicDescriptorDiscoverer::isConnectionInUse(uint16_t connHandle) { 169 | return findRunningDiscovery(connHandle) != NULL; 170 | } 171 | 172 | ble_error_t nRF5xCharacteristicDescriptorDiscoverer::gattc_descriptors_discover( 173 | uint16_t connection_handle, uint16_t start_handle, uint16_t end_handle) { 174 | 175 | ble_gattc_handle_range_t discoveryRange = { 176 | start_handle, 177 | end_handle 178 | }; 179 | uint32_t err = sd_ble_gattc_descriptors_discover(connection_handle, &discoveryRange); 180 | 181 | switch(err) { 182 | case NRF_SUCCESS: 183 | return BLE_ERROR_NONE; 184 | case BLE_ERROR_INVALID_CONN_HANDLE: 185 | return BLE_ERROR_INVALID_PARAM; 186 | case NRF_ERROR_INVALID_ADDR: 187 | return BLE_ERROR_PARAM_OUT_OF_RANGE; 188 | case NRF_ERROR_BUSY: 189 | return BLE_STACK_BUSY; 190 | default: 191 | return BLE_ERROR_UNSPECIFIED; 192 | } 193 | } 194 | 195 | // implementation of nRF5xCharacteristicDescriptorDiscoverer::Discovery 196 | 197 | nRF5xCharacteristicDescriptorDiscoverer::Discovery::Discovery() : 198 | characteristic(), onDiscovery(), onTerminate() { 199 | } 200 | 201 | nRF5xCharacteristicDescriptorDiscoverer::Discovery::Discovery( 202 | const DiscoveredCharacteristic& c, const DiscoveryCallback_t& dCb, const TerminationCallback_t& tCb) : 203 | characteristic(c), onDiscovery(dCb), onTerminate(tCb) { 204 | } 205 | 206 | void nRF5xCharacteristicDescriptorDiscoverer::Discovery::process( 207 | GattAttribute::Handle_t handle, const UUID& uuid) { 208 | CharacteristicDescriptorDiscovery::DiscoveryCallbackParams_t params = { 209 | characteristic, 210 | DiscoveredCharacteristicDescriptor( 211 | characteristic.getGattClient(), 212 | characteristic.getConnectionHandle(), 213 | handle, 214 | uuid 215 | ) 216 | }; 217 | onDiscovery.call(¶ms); 218 | } 219 | 220 | void nRF5xCharacteristicDescriptorDiscoverer::Discovery::terminate(ble_error_t err) { 221 | CharacteristicDescriptorDiscovery::TerminationCallbackParams_t params = { 222 | characteristic, 223 | err 224 | }; 225 | 226 | onTerminate.call(¶ms); 227 | } 228 | 229 | bool nRF5xCharacteristicDescriptorDiscoverer::Discovery::isEmpty() const { 230 | return *this == Discovery(); 231 | } 232 | 233 | const DiscoveredCharacteristic& nRF5xCharacteristicDescriptorDiscoverer::Discovery::getCharacteristic() const { 234 | return characteristic; 235 | } 236 | -------------------------------------------------------------------------------- /source/nRF5xCharacteristicDescriptorDiscoverer.h: -------------------------------------------------------------------------------- 1 | /* mbed Microcontroller Library 2 | * Copyright (c) 2006-2015 ARM Limited 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #ifndef __NRF_CHARACTERISTIC_DESCRIPTOR_DISCOVERY_H__ 18 | #define __NRF_CHARACTERISTIC_DESCRIPTOR_DISCOVERY_H__ 19 | 20 | #include "ble/Gap.h" 21 | #include "ble/DiscoveredCharacteristic.h" 22 | #include "ble/CharacteristicDescriptorDiscovery.h" 23 | #include "ble/GattClient.h" 24 | #include "ble_gattc.h" 25 | 26 | /** 27 | * @brief Manage the discovery of Characteristic descriptors 28 | * @details is a bridge between BLE API and Nordic stack regarding Characteristic 29 | * Descriptor discovery. The BLE API can launch, monitor and ask for termination 30 | * of a discovery. The Nordic stack will provide new descriptors and indicate when 31 | * the discovery is done. 32 | */ 33 | class nRF5xCharacteristicDescriptorDiscoverer 34 | { 35 | typedef CharacteristicDescriptorDiscovery::DiscoveryCallback_t DiscoveryCallback_t; 36 | typedef CharacteristicDescriptorDiscovery::TerminationCallback_t TerminationCallback_t; 37 | 38 | public: 39 | /** 40 | * @brief Construct a new characteristic descriptor discoverer. 41 | */ 42 | nRF5xCharacteristicDescriptorDiscoverer(); 43 | 44 | /** 45 | * @brief Destroy a characteristic descriptor discoverer. 46 | */ 47 | ~nRF5xCharacteristicDescriptorDiscoverer(); 48 | 49 | /** 50 | * Launch a new characteristic descriptor discovery for a given DiscoveredCharacteristic. 51 | * @param characteristic The characteristic owning the descriptors to discover. 52 | * @param discoveryCallback The callback called when a descriptor is discovered. 53 | * @param terminationCallback The callback called when the discovery process end. 54 | * @return BLE_ERROR_NONE if characteristic descriptor discovery is launched successfully; 55 | * else an appropriate error. 56 | * @note: this will be called by BLE API side. 57 | */ 58 | ble_error_t launch( 59 | const DiscoveredCharacteristic& characteristic, 60 | const DiscoveryCallback_t& discoveryCallback, 61 | const TerminationCallback_t& terminationCallback 62 | ); 63 | 64 | /** 65 | * @brief indicate if a characteristic descriptor discovery is active for a 66 | * given DiscoveredCharacteristic. 67 | * @param characteristic The characteristic for whom the descriptor might be 68 | * currently discovered. 69 | * @return true if descriptors of characteristic are discovered, false otherwise. 70 | * @note: this will be called by BLE API side. 71 | */ 72 | bool isActive(const DiscoveredCharacteristic& characteristic) const; 73 | 74 | /** 75 | * @brief request the termination of characteristic descriptor discovery 76 | * for a give DiscoveredCharacteristic 77 | * @param characteristic The characteristic for whom the descriptor discovery 78 | * should be stopped. 79 | * @note: this will be called by BLE API side. 80 | */ 81 | void requestTerminate(const DiscoveredCharacteristic& characteristic); 82 | 83 | /** 84 | * @brief process descriptors discovered from the Nordic stack. 85 | * @param connectionHandle The connection handle upon which descriptors has been 86 | * discovered. 87 | * @param descriptors Discovered descriptors. 88 | * @note This will be called by the Nordic stack. 89 | */ 90 | void process(uint16_t connectionHandle, const ble_gattc_evt_desc_disc_rsp_t& descriptors); 91 | 92 | /** 93 | * @brief Called by the Nordic stack when the discovery is over. 94 | * @param The connection handle upon which the discovery process is done. 95 | * @param err An error if the termination is due to an error. 96 | */ 97 | void terminate(uint16_t connectionHandle, ble_error_t err); 98 | 99 | private: 100 | // protection against copy construction and assignment 101 | nRF5xCharacteristicDescriptorDiscoverer(const nRF5xCharacteristicDescriptorDiscoverer&); 102 | nRF5xCharacteristicDescriptorDiscoverer& operator=(const nRF5xCharacteristicDescriptorDiscoverer&); 103 | 104 | /** 105 | * @brief Discovery process, it store the DiscoveredCharacteristic, the 106 | * discovery callback and the termination callback. 107 | */ 108 | class Discovery { 109 | public: 110 | /** 111 | * @brief Construct an empty discovery, such can be considerate as a not running discovery. 112 | * @note #isEmpty function will return true 113 | */ 114 | Discovery(); 115 | 116 | /** 117 | * @brief Construct a valid discovery process. 118 | * 119 | * @param c the characteristic from whom descriptors will be discovered. 120 | * @param dCb The discovery callback called each time a descriptor is discovered. 121 | * @param tCb The termination callback called when the discovery terminate. 122 | * 123 | * @note #isEmpty function will return false 124 | */ 125 | Discovery(const DiscoveredCharacteristic& c, const DiscoveryCallback_t& dCb, const TerminationCallback_t& tCb); 126 | 127 | /** 128 | * @brief Process the discovery of a descriptor. 129 | * 130 | * @param handle The attribute handle of the descriptor found 131 | * @param uuid The UUID of the descriptor found. 132 | */ 133 | void process(GattAttribute::Handle_t handle, const UUID& uuid); 134 | 135 | /** 136 | * @brief Terminate the discovery process. 137 | * 138 | * @param err Error associate with the termination 139 | * @note after this call #isEmpty function will return true. 140 | */ 141 | void terminate(ble_error_t err); 142 | 143 | /** 144 | * @brief check if the discovery process is empty or not. Empty discovery are 145 | * not running. 146 | * 147 | * @detail Discovery are empty after: 148 | * - a default construction 149 | * - a copy construction form a default constructed 150 | * - an assignment from a default constructed Discovery 151 | * @return true if the Discovery is empty and false otherwise. 152 | */ 153 | bool isEmpty() const; 154 | 155 | /** 156 | * @brief return the characteristic from whom descriptors are discovered. 157 | * @return the characteristic from whom descriptors are discovered. 158 | */ 159 | const DiscoveredCharacteristic& getCharacteristic() const; 160 | 161 | /** 162 | * @brief equal to operator, test if two discovery process are equal 163 | * 164 | * @param lhs left hand side of the expression 165 | * @param rhs right hand side of the expression 166 | * @return true if lhs == rhs 167 | */ 168 | friend bool operator==(const Discovery& lhs, const Discovery& rhs) { 169 | return lhs.characteristic == rhs.characteristic && 170 | lhs.onDiscovery == rhs.onDiscovery && 171 | lhs.onTerminate == rhs.onTerminate; 172 | } 173 | 174 | /** 175 | * @brief not equal to operator, test if two discovery process are not equal 176 | * 177 | * @param lhs left hand side of the expression 178 | * @param rhs right hand side of the expression 179 | * @return true if lhs != rhs 180 | */ 181 | friend bool operator!=(const Discovery& lhs, const Discovery& rhs) { 182 | return !(lhs == rhs); 183 | } 184 | 185 | private: 186 | DiscoveredCharacteristic characteristic; 187 | DiscoveryCallback_t onDiscovery; 188 | TerminationCallback_t onTerminate; 189 | }; 190 | 191 | // find a running discovery process 192 | Discovery* findRunningDiscovery(const DiscoveredCharacteristic& characteristic); 193 | Discovery* findRunningDiscovery(uint16_t handle); 194 | 195 | // Called to terminate a discovery is over. 196 | void terminate(Discovery* discovery, ble_error_t err); 197 | 198 | // get one slot for a discovery process 199 | Discovery* getAvailableDiscoverySlot(); 200 | 201 | // indicate if a connection is already running a discovery 202 | bool isConnectionInUse(uint16_t connHandle); 203 | 204 | // low level start of a discovery 205 | static ble_error_t gattc_descriptors_discover(uint16_t connection_handle, uint16_t start_handle, uint16_t end_handle); 206 | 207 | // count of concurrent connections which can run a descriptor discovery process 208 | static const size_t MAXIMUM_CONCURRENT_CONNECTIONS_COUNT = 3; 209 | 210 | // array of running discoveries 211 | Discovery discoveryRunning[MAXIMUM_CONCURRENT_CONNECTIONS_COUNT]; 212 | }; 213 | 214 | #endif /*__NRF_CHARACTERISTIC_DESCRIPTOR_DISCOVERY_H__*/ 215 | -------------------------------------------------------------------------------- /source/nRF5xDiscoveredCharacteristic.cpp: -------------------------------------------------------------------------------- 1 | /* mbed Microcontroller Library 2 | * Copyright (c) 2006-2013 ARM Limited 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #include "nRF5xDiscoveredCharacteristic.h" 18 | #include "nRF5xGattClient.h" 19 | #include "ble_gatt.h" 20 | 21 | void 22 | nRF5xDiscoveredCharacteristic::setup(nRF5xGattClient *gattcIn, 23 | Gap::Handle_t connectionHandleIn, 24 | ble_gatt_char_props_t propsIn, 25 | GattAttribute::Handle_t declHandleIn, 26 | GattAttribute::Handle_t valueHandleIn) 27 | { 28 | gattc = gattcIn; 29 | connHandle = connectionHandleIn; 30 | declHandle = declHandleIn; 31 | valueHandle = valueHandleIn; 32 | 33 | props._broadcast = propsIn.broadcast; 34 | props._read = propsIn.read; 35 | props._writeWoResp = propsIn.write_wo_resp; 36 | props._write = propsIn.write; 37 | props._notify = propsIn.notify; 38 | props._indicate = propsIn.indicate; 39 | props._authSignedWrite = propsIn.auth_signed_wr; 40 | } 41 | 42 | void 43 | nRF5xDiscoveredCharacteristic::setup(nRF5xGattClient *gattcIn, 44 | Gap::Handle_t connectionHandleIn, 45 | UUID::ShortUUIDBytes_t uuidIn, 46 | ble_gatt_char_props_t propsIn, 47 | GattAttribute::Handle_t declHandleIn, 48 | GattAttribute::Handle_t valueHandleIn) 49 | { 50 | gattc = gattcIn; 51 | connHandle = connectionHandleIn; 52 | uuid = uuidIn; 53 | declHandle = declHandleIn; 54 | valueHandle = valueHandleIn; 55 | 56 | props._broadcast = propsIn.broadcast; 57 | props._read = propsIn.read; 58 | props._writeWoResp = propsIn.write_wo_resp; 59 | props._write = propsIn.write; 60 | props._notify = propsIn.notify; 61 | props._indicate = propsIn.indicate; 62 | props._authSignedWrite = propsIn.auth_signed_wr; 63 | } 64 | -------------------------------------------------------------------------------- /source/nRF5xDiscoveredCharacteristic.h: -------------------------------------------------------------------------------- 1 | /* mbed Microcontroller Library 2 | * Copyright (c) 2006-2013 ARM Limited 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #ifndef __NRF_DISCOVERED_CHARACTERISTIC_H__ 18 | #define __NRF_DISCOVERED_CHARACTERISTIC_H__ 19 | 20 | #include "ble/DiscoveredCharacteristic.h" 21 | #include "ble_gatt.h" 22 | 23 | class nRF5xGattClient; /* forward declaration */ 24 | 25 | class nRF5xDiscoveredCharacteristic : public DiscoveredCharacteristic { 26 | public: 27 | void setup(nRF5xGattClient *gattcIn, 28 | Gap::Handle_t connectionHandleIn, 29 | ble_gatt_char_props_t propsIn, 30 | GattAttribute::Handle_t declHandleIn, 31 | GattAttribute::Handle_t valueHandleIn); 32 | 33 | void setup(nRF5xGattClient *gattcIn, 34 | Gap::Handle_t connectionHandleIn, 35 | UUID::ShortUUIDBytes_t uuidIn, 36 | ble_gatt_char_props_t propsIn, 37 | GattAttribute::Handle_t declHandleIn, 38 | GattAttribute::Handle_t valueHandleIn); 39 | 40 | void setLastHandle(GattAttribute::Handle_t last) { 41 | lastHandle = last; 42 | } 43 | }; 44 | 45 | #endif /* __NRF_DISCOVERED_CHARACTERISTIC_H__ */ 46 | -------------------------------------------------------------------------------- /source/nRF5xGap.h: -------------------------------------------------------------------------------- 1 | /* mbed Microcontroller Library 2 | * Copyright (c) 2006-2013 ARM Limited 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #ifndef __NRF5x_GAP_H__ 18 | #define __NRF5x_GAP_H__ 19 | 20 | #ifdef YOTTA_CFG_MBED_OS 21 | #include "mbed-drivers/mbed.h" 22 | #else 23 | #include "mbed.h" 24 | #endif 25 | #ifndef YOTTA_CFG_WHITELIST_MAX_SIZE 26 | #define YOTTA_CFG_WHITELIST_MAX_SIZE BLE_GAP_WHITELIST_ADDR_MAX_COUNT 27 | #elif YOTTA_CFG_WHITELIST_MAX_SIZE > BLE_GAP_WHITELIST_ADDR_MAX_COUNT 28 | #undef YOTTA_CFG_WHITELIST_MAX_SIZE 29 | #define YOTTA_CFG_WHITELIST_MAX_SIZE BLE_GAP_WHITELIST_ADDR_MAX_COUNT 30 | #endif 31 | #ifndef YOTTA_CFG_IRK_TABLE_MAX_SIZE 32 | #define YOTTA_CFG_IRK_TABLE_MAX_SIZE BLE_GAP_WHITELIST_IRK_MAX_COUNT 33 | #elif YOTTA_CFG_IRK_TABLE_MAX_SIZE > BLE_GAP_WHITELIST_IRK_MAX_COUNT 34 | #undef YOTTA_CFG_IRK_TABLE_MAX_SIZE 35 | #define YOTTA_CFG_IRK_TABLE_MAX_SIZE BLE_GAP_WHITELIST_IRK_MAX_COUNT 36 | #endif 37 | #include "ble/blecommon.h" 38 | #include "nrf_ble.h" 39 | #include "ble/GapAdvertisingParams.h" 40 | #include "ble/GapAdvertisingData.h" 41 | #include "ble/Gap.h" 42 | #include "ble/GapScanningParams.h" 43 | 44 | #include "nrf_soc.h" 45 | 46 | extern "C" { 47 | #include "ble_radio_notification.h" 48 | } 49 | 50 | #include "btle_security.h" 51 | 52 | void radioNotificationStaticCallback(bool param); 53 | 54 | /**************************************************************************/ 55 | /*! 56 | \brief 57 | 58 | */ 59 | /**************************************************************************/ 60 | class nRF5xGap : public Gap 61 | { 62 | public: 63 | /* Functions that must be implemented from Gap */ 64 | virtual ble_error_t setAddress(AddressType_t type, const Address_t address); 65 | virtual ble_error_t getAddress(AddressType_t *typeP, Address_t address); 66 | virtual ble_error_t setAdvertisingData(const GapAdvertisingData &, const GapAdvertisingData &); 67 | 68 | virtual uint16_t getMinAdvertisingInterval(void) const {return GapAdvertisingParams::ADVERTISEMENT_DURATION_UNITS_TO_MS(BLE_GAP_ADV_INTERVAL_MIN);} 69 | virtual uint16_t getMinNonConnectableAdvertisingInterval(void) const {return GapAdvertisingParams::ADVERTISEMENT_DURATION_UNITS_TO_MS(BLE_GAP_ADV_NONCON_INTERVAL_MIN);} 70 | virtual uint16_t getMaxAdvertisingInterval(void) const {return GapAdvertisingParams::ADVERTISEMENT_DURATION_UNITS_TO_MS(BLE_GAP_ADV_INTERVAL_MAX);} 71 | 72 | virtual ble_error_t startAdvertising(const GapAdvertisingParams &); 73 | virtual ble_error_t stopAdvertising(void); 74 | virtual ble_error_t connect(const Address_t, BLEProtocol::AddressType_t peerAddrType, const ConnectionParams_t *connectionParams, const GapScanningParams *scanParams); 75 | virtual ble_error_t disconnect(Handle_t connectionHandle, DisconnectionReason_t reason); 76 | virtual ble_error_t disconnect(DisconnectionReason_t reason); 77 | 78 | virtual ble_error_t setDeviceName(const uint8_t *deviceName); 79 | virtual ble_error_t getDeviceName(uint8_t *deviceName, unsigned *lengthP); 80 | virtual ble_error_t setAppearance(GapAdvertisingData::Appearance appearance); 81 | virtual ble_error_t getAppearance(GapAdvertisingData::Appearance *appearanceP); 82 | 83 | virtual ble_error_t setTxPower(int8_t txPower); 84 | virtual void getPermittedTxPowerValues(const int8_t **valueArrayPP, size_t *countP); 85 | 86 | void setConnectionHandle(uint16_t con_handle); 87 | uint16_t getConnectionHandle(void); 88 | 89 | virtual ble_error_t getPreferredConnectionParams(ConnectionParams_t *params); 90 | virtual ble_error_t setPreferredConnectionParams(const ConnectionParams_t *params); 91 | virtual ble_error_t updateConnectionParams(Handle_t handle, const ConnectionParams_t *params); 92 | 93 | virtual ble_error_t reset(void); 94 | 95 | /* 96 | * The following functions are part of the whitelisting experimental API. 97 | * Therefore, this functionality can change in the near future. 98 | */ 99 | virtual uint8_t getMaxWhitelistSize(void) const; 100 | virtual ble_error_t getWhitelist(Gap::Whitelist_t &whitelistOut) const; 101 | virtual ble_error_t setWhitelist(const Gap::Whitelist_t &whitelistIn); 102 | 103 | virtual ble_error_t setAdvertisingPolicyMode(AdvertisingPolicyMode_t mode); 104 | virtual ble_error_t setScanningPolicyMode(ScanningPolicyMode_t mode); 105 | virtual ble_error_t setInitiatorPolicyMode(InitiatorPolicyMode_t mode); 106 | virtual Gap::AdvertisingPolicyMode_t getAdvertisingPolicyMode(void) const; 107 | virtual Gap::ScanningPolicyMode_t getScanningPolicyMode(void) const; 108 | virtual Gap::InitiatorPolicyMode_t getInitiatorPolicyMode(void) const; 109 | 110 | virtual ble_error_t initRadioNotification(void) { 111 | if (ble_radio_notification_init(NRF_APP_PRIORITY_HIGH, NRF_RADIO_NOTIFICATION_DISTANCE_800US, radioNotificationStaticCallback) == NRF_SUCCESS) { 112 | return BLE_ERROR_NONE; 113 | } 114 | 115 | return BLE_ERROR_UNSPECIFIED; 116 | } 117 | 118 | /* Observer role is not supported by S110, return BLE_ERROR_NOT_IMPLEMENTED */ 119 | #if !defined(TARGET_MCU_NRF51_16K_S110) && !defined(TARGET_MCU_NRF51_32K_S110) 120 | virtual ble_error_t startRadioScan(const GapScanningParams &scanningParams); 121 | virtual ble_error_t stopScan(void); 122 | #endif 123 | 124 | private: 125 | /* 126 | * Whitelisting API related structures and helper functions. 127 | */ 128 | 129 | /* Policy modes set by the user. By default these are set to ignore the whitelist */ 130 | Gap::AdvertisingPolicyMode_t advertisingPolicyMode; 131 | Gap::ScanningPolicyMode_t scanningPolicyMode; 132 | 133 | /* Internal representation of a whitelist */ 134 | uint8_t whitelistAddressesSize; 135 | ble_gap_addr_t whitelistAddresses[YOTTA_CFG_WHITELIST_MAX_SIZE]; 136 | 137 | /* 138 | * An internal function used to populate the ble_gap_whitelist_t that will be used by 139 | * the SoftDevice for filtering requests. This function is needed because for the BLE 140 | * API the whitelist is just a collection of keys, but for the stack it also includes 141 | * the IRK table. 142 | */ 143 | ble_error_t generateStackWhitelist(ble_gap_whitelist_t &whitelist); 144 | 145 | private: 146 | bool radioNotificationCallbackParam; /* parameter to be passed into the Timeout-generated radio notification callback. */ 147 | Timeout radioNotificationTimeout; 148 | 149 | /* 150 | * A helper function to post radio notification callbacks with low interrupt priority. 151 | */ 152 | void postRadioNotificationCallback(void) { 153 | #ifdef YOTTA_CFG_MBED_OS 154 | /* 155 | * In mbed OS, all user-facing BLE events (interrupts) are posted to the 156 | * MINAR scheduler to be executed as callbacks in thread mode. MINAR guards 157 | * its critical sections from interrupts by acquiring CriticalSectionLock, 158 | * which results in a call to sd_nvic_critical_region_enter(). Thus, it is 159 | * safe to invoke MINAR APIs from interrupt context as long as those 160 | * interrupts are blocked by sd_nvic_critical_region_enter(). 161 | * 162 | * Radio notifications are a special case for the above. The Radio 163 | * Notification IRQ is handled at a very high priority--higher than the 164 | * level blocked by sd_nvic_critical_region_enter(). Thus Radio Notification 165 | * events can preempt MINAR's critical sections. Using MINAR APIs (such as 166 | * posting an event) directly in processRadioNotification() may result in a 167 | * race condition ending in a hard-fault. 168 | * 169 | * The solution is to *not* call MINAR APIs directly from the Radio 170 | * Notification handling; i.e. to do the bulk of RadioNotification 171 | * processing at a reduced priority which respects MINAR's critical 172 | * sections. Unfortunately, on a cortex-M0, there is no clean way to demote 173 | * priority for the currently executing interrupt--we wouldn't want to 174 | * demote the radio notification handling anyway because it is sensitive to 175 | * timing, and the system expects to finish this handling very quickly. The 176 | * workaround is to employ a Timeout to trigger 177 | * postRadioNotificationCallback() after a very short delay (~0 us) and post 178 | * the MINAR callback that context. 179 | * 180 | * !!!WARNING!!! Radio notifications are very time critical events. The 181 | * current solution is expected to work under the assumption that 182 | * postRadioNotificationCalback() will be executed BEFORE the next radio 183 | * notification event is generated. 184 | */ 185 | minar::Scheduler::postCallback( 186 | mbed::util::FunctionPointer1(&radioNotificationCallback, &FunctionPointerWithContext::call).bind(radioNotificationCallbackParam) 187 | ); 188 | #else 189 | /* 190 | * In mbed classic, all user-facing BLE events execute callbacks in interrupt 191 | * mode. Radio Notifications are a special case because its IRQ is handled at 192 | * a very high priority. Thus Radio Notification events can preempt other 193 | * operations that require interaction with the SoftDevice such as advertising 194 | * payload updates and changing the Gap state. Therefore, executing a Radio 195 | * Notification callback directly from processRadioNotification() may result 196 | * in a race condition ending in a hard-fault. 197 | * 198 | * The solution is to *not* execute the Radio Notification callback directly 199 | * from the Radio Notification handling; i.e. to do the bulk of the 200 | * Radio Notification processing at a reduced priority. Unfortunately, on a 201 | * cortex-M0, there is no clean way to demote priority for the currently 202 | * executing interrupt--we wouldn't want to demote the radio notification 203 | * handling anyway because it is sensitive to timing, and the system expects 204 | * to finish this handling very quickly. The workaround is to employ a Timeout 205 | * to trigger postRadioNotificationCallback() after a very short delay (~0 us) 206 | * and execute the callback in that context. 207 | * 208 | * !!!WARNING!!! Radio notifications are very time critical events. The 209 | * current solution is expected to work under the assumption that 210 | * postRadioNotificationCalback() will be executed BEFORE the next radio 211 | * notification event is generated. 212 | */ 213 | radioNotificationCallback.call(radioNotificationCallbackParam); 214 | #endif /* #ifdef YOTTA_CFG_MBED_OS */ 215 | } 216 | 217 | /** 218 | * A helper function to process radio-notification events; to be called internally. 219 | * @param param [description] 220 | */ 221 | void processRadioNotificationEvent(bool param) { 222 | radioNotificationCallbackParam = param; 223 | radioNotificationTimeout.attach_us(this, &nRF5xGap::postRadioNotificationCallback, 0); 224 | } 225 | friend void radioNotificationStaticCallback(bool param); /* allow invocations of processRadioNotificationEvent() */ 226 | 227 | private: 228 | uint16_t m_connectionHandle; 229 | 230 | /* 231 | * Allow instantiation from nRF5xn when required. 232 | */ 233 | friend class nRF5xn; 234 | 235 | nRF5xGap() : 236 | advertisingPolicyMode(Gap::ADV_POLICY_IGNORE_WHITELIST), 237 | scanningPolicyMode(Gap::SCAN_POLICY_IGNORE_WHITELIST), 238 | whitelistAddressesSize(0) { 239 | m_connectionHandle = BLE_CONN_HANDLE_INVALID; 240 | } 241 | 242 | nRF5xGap(nRF5xGap const &); 243 | void operator=(nRF5xGap const &); 244 | }; 245 | 246 | #endif // ifndef __NRF5x_GAP_H__ 247 | -------------------------------------------------------------------------------- /source/nRF5xGattClient.cpp: -------------------------------------------------------------------------------- 1 | /* mbed Microcontroller Library 2 | * Copyright (c) 2006-2013 ARM Limited 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #include "nRF5xGattClient.h" 18 | 19 | #if !defined(TARGET_MCU_NRF51_16K_S110) && !defined(TARGET_MCU_NRF51_32K_S110) 20 | ble_error_t 21 | nRF5xGattClient::launchServiceDiscovery(Gap::Handle_t connectionHandle, 22 | ServiceDiscovery::ServiceCallback_t sc, 23 | ServiceDiscovery::CharacteristicCallback_t cc, 24 | const UUID &matchingServiceUUIDIn, 25 | const UUID &matchingCharacteristicUUIDIn) 26 | { 27 | return _discovery.launch(connectionHandle, sc, cc, matchingServiceUUIDIn, matchingCharacteristicUUIDIn); 28 | } 29 | 30 | ble_error_t nRF5xGattClient::discoverCharacteristicDescriptors( 31 | const DiscoveredCharacteristic& characteristic, 32 | const CharacteristicDescriptorDiscovery::DiscoveryCallback_t& discoveryCallback, 33 | const CharacteristicDescriptorDiscovery::TerminationCallback_t& terminationCallback) 34 | { 35 | return _characteristicDescriptorDiscoverer.launch( 36 | characteristic, 37 | discoveryCallback, 38 | terminationCallback 39 | ); 40 | } 41 | 42 | bool nRF5xGattClient::isCharacteristicDescriptorsDiscoveryActive(const DiscoveredCharacteristic& characteristic) const { 43 | return _characteristicDescriptorDiscoverer.isActive(characteristic); 44 | } 45 | 46 | void nRF5xGattClient::terminateCharacteristicDescriptorsDiscovery(const DiscoveredCharacteristic& characteristic) { 47 | return _characteristicDescriptorDiscoverer.requestTerminate(characteristic); 48 | } 49 | 50 | #endif 51 | -------------------------------------------------------------------------------- /source/nRF5xGattClient.h: -------------------------------------------------------------------------------- 1 | /* mbed Microcontroller Library 2 | * Copyright (c) 2006-2013 ARM Limited 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #ifndef __NRF51822_GATT_CLIENT_H__ 18 | #define __NRF51822_GATT_CLIENT_H__ 19 | 20 | #include "ble/GattClient.h" 21 | #include "nRF5xServiceDiscovery.h" 22 | #include "nRF5xCharacteristicDescriptorDiscoverer.h" 23 | 24 | class nRF5xGattClient : public GattClient 25 | { 26 | public: 27 | /** 28 | * When using S110, all Gatt client features will return 29 | * BLE_ERROR_NOT_IMPLEMENTED 30 | */ 31 | #if !defined(TARGET_MCU_NRF51_16K_S110) && !defined(TARGET_MCU_NRF51_32K_S110) 32 | 33 | /** 34 | * Launch service discovery. Once launched, service discovery will remain 35 | * active with callbacks being issued back into the application for matching 36 | * services/characteristics. isActive() can be used to determine status; and 37 | * a termination callback (if setup) will be invoked at the end. Service 38 | * discovery can be terminated prematurely if needed using terminate(). 39 | * 40 | * @param connectionHandle 41 | * Handle for the connection with the peer. 42 | * @param sc 43 | * This is the application callback for matching service. Taken as 44 | * NULL by default. Note: service discovery may still be active 45 | * when this callback is issued; calling asynchronous BLE-stack 46 | * APIs from within this application callback might cause the 47 | * stack to abort service discovery. If this becomes an issue, it 48 | * may be better to make local copy of the discoveredService and 49 | * wait for service discovery to terminate before operating on the 50 | * service. 51 | * @param cc 52 | * This is the application callback for matching characteristic. 53 | * Taken as NULL by default. Note: service discovery may still be 54 | * active when this callback is issued; calling asynchronous 55 | * BLE-stack APIs from within this application callback might cause 56 | * the stack to abort service discovery. If this becomes an issue, 57 | * it may be better to make local copy of the discoveredCharacteristic 58 | * and wait for service discovery to terminate before operating on the 59 | * characteristic. 60 | * @param matchingServiceUUID 61 | * UUID based filter for specifying a service in which the application is 62 | * interested. By default it is set as the wildcard UUID_UNKNOWN, 63 | * in which case it matches all services. If characteristic-UUID 64 | * filter (below) is set to the wildcard value, then a service 65 | * callback will be invoked for the matching service (or for every 66 | * service if the service filter is a wildcard). 67 | * @param matchingCharacteristicUUIDIn 68 | * UUID based filter for specifying characteristic in which the application 69 | * is interested. By default it is set as the wildcard UUID_UKNOWN 70 | * to match against any characteristic. If both service-UUID 71 | * filter and characteristic-UUID filter are used with non- wildcard 72 | * values, then only a single characteristic callback is 73 | * invoked for the matching characteristic. 74 | * 75 | * @Note Using wildcard values for both service-UUID and characteristic- 76 | * UUID will result in complete service discovery--callbacks being 77 | * called for every service and characteristic. 78 | * 79 | * @return 80 | * BLE_ERROR_NONE if service discovery is launched successfully; else an appropriate error. 81 | */ 82 | virtual ble_error_t launchServiceDiscovery(Gap::Handle_t connectionHandle, 83 | ServiceDiscovery::ServiceCallback_t sc = NULL, 84 | ServiceDiscovery::CharacteristicCallback_t cc = NULL, 85 | const UUID &matchingServiceUUID = UUID::ShortUUIDBytes_t(BLE_UUID_UNKNOWN), 86 | const UUID &matchingCharacteristicUUIDIn = UUID::ShortUUIDBytes_t(BLE_UUID_UNKNOWN)); 87 | 88 | virtual void onServiceDiscoveryTermination(ServiceDiscovery::TerminationCallback_t callback) { 89 | _discovery.onTermination(callback); 90 | } 91 | 92 | /** 93 | * Is service-discovery currently active? 94 | */ 95 | virtual bool isServiceDiscoveryActive(void) const { 96 | return _discovery.isActive(); 97 | } 98 | 99 | /** 100 | * Terminate an ongoing service-discovery. This should result in an 101 | * invocation of the TerminationCallback if service-discovery is active. 102 | */ 103 | virtual void terminateServiceDiscovery(void) { 104 | _discovery.terminate(); 105 | } 106 | 107 | /** 108 | * @brief Implementation of GattClient::discoverCharacteristicDescriptors 109 | * @see GattClient::discoverCharacteristicDescriptors 110 | */ 111 | virtual ble_error_t discoverCharacteristicDescriptors( 112 | const DiscoveredCharacteristic& characteristic, 113 | const CharacteristicDescriptorDiscovery::DiscoveryCallback_t& discoveryCallback, 114 | const CharacteristicDescriptorDiscovery::TerminationCallback_t& terminationCallback 115 | ); 116 | 117 | /** 118 | * @brief Implementation of GattClient::isCharacteristicDiscoveryActive 119 | * @see GattClient::isCharacteristicDiscoveryActive 120 | */ 121 | virtual bool isCharacteristicDescriptorsDiscoveryActive(const DiscoveredCharacteristic& characteristic) const; 122 | 123 | /** 124 | * @brief Implementation of GattClient::terminateCharacteristicDiscovery 125 | * @see GattClient::terminateCharacteristicDiscovery 126 | */ 127 | virtual void terminateCharacteristicDescriptorsDiscovery(const DiscoveredCharacteristic& characteristic); 128 | 129 | virtual ble_error_t read(Gap::Handle_t connHandle, GattAttribute::Handle_t attributeHandle, uint16_t offset) const { 130 | uint32_t rc = sd_ble_gattc_read(connHandle, attributeHandle, offset); 131 | if (rc == NRF_SUCCESS) { 132 | return BLE_ERROR_NONE; 133 | } 134 | switch (rc) { 135 | case NRF_ERROR_BUSY: 136 | return BLE_STACK_BUSY; 137 | case BLE_ERROR_INVALID_CONN_HANDLE: 138 | case NRF_ERROR_INVALID_STATE: 139 | case NRF_ERROR_INVALID_ADDR: 140 | default: 141 | return BLE_ERROR_INVALID_STATE; 142 | } 143 | } 144 | 145 | virtual ble_error_t write(GattClient::WriteOp_t cmd, Gap::Handle_t connHandle, GattAttribute::Handle_t attributeHandle, size_t length, const uint8_t *value) const { 146 | ble_gattc_write_params_t writeParams; 147 | writeParams.write_op = cmd; 148 | writeParams.flags = 0; /* this is inconsequential */ 149 | writeParams.handle = attributeHandle; 150 | writeParams.offset = 0; 151 | writeParams.len = length; 152 | writeParams.p_value = const_cast(value); 153 | 154 | uint32_t rc = sd_ble_gattc_write(connHandle, &writeParams); 155 | if (rc == NRF_SUCCESS) { 156 | return BLE_ERROR_NONE; 157 | } 158 | switch (rc) { 159 | case NRF_ERROR_BUSY: 160 | return BLE_STACK_BUSY; 161 | case BLE_ERROR_NO_TX_BUFFERS: 162 | return BLE_ERROR_NO_MEM; 163 | case BLE_ERROR_INVALID_CONN_HANDLE: 164 | case NRF_ERROR_INVALID_STATE: 165 | case NRF_ERROR_INVALID_ADDR: 166 | default: 167 | return BLE_ERROR_INVALID_STATE; 168 | } 169 | } 170 | 171 | /** 172 | * @brief Clear nRF5xGattClient's state. 173 | * 174 | * @return 175 | * BLE_ERROR_NONE if successful. 176 | */ 177 | virtual ble_error_t reset(void) { 178 | /* Clear all state that is from the parent, including private members */ 179 | if (GattClient::reset() != BLE_ERROR_NONE) { 180 | return BLE_ERROR_INVALID_STATE; 181 | } 182 | 183 | /* Clear derived class members */ 184 | _discovery.reset(); 185 | 186 | return BLE_ERROR_NONE; 187 | } 188 | 189 | public: 190 | /* 191 | * Allow instantiation from nRF5xn when required. 192 | */ 193 | friend class nRF5xn; 194 | 195 | nRF5xGattClient() : _discovery(this) { 196 | /* empty */ 197 | } 198 | 199 | nRF5xServiceDiscovery& discovery() { 200 | return _discovery; 201 | } 202 | 203 | nRF5xCharacteristicDescriptorDiscoverer& characteristicDescriptorDiscoverer() { 204 | return _characteristicDescriptorDiscoverer; 205 | } 206 | 207 | private: 208 | nRF5xGattClient(const nRF5xGattClient &); 209 | const nRF5xGattClient& operator=(const nRF5xGattClient &); 210 | 211 | private: 212 | nRF5xServiceDiscovery _discovery; 213 | nRF5xCharacteristicDescriptorDiscoverer _characteristicDescriptorDiscoverer; 214 | 215 | #endif // if !S110 216 | }; 217 | 218 | #endif // ifndef __NRF51822_GATT_CLIENT_H__ 219 | -------------------------------------------------------------------------------- /source/nRF5xGattServer.h: -------------------------------------------------------------------------------- 1 | /* mbed Microcontroller Library 2 | * Copyright (c) 2006-2013 ARM Limited 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #ifndef __NRF51822_GATT_SERVER_H__ 18 | #define __NRF51822_GATT_SERVER_H__ 19 | 20 | #include 21 | 22 | #include "ble/blecommon.h" 23 | #include "nrf_ble.h" /* nordic ble */ 24 | #include "ble/Gap.h" 25 | #include "ble/GattServer.h" 26 | 27 | class nRF5xGattServer : public GattServer 28 | { 29 | public: 30 | /* Functions that must be implemented from GattServer */ 31 | virtual ble_error_t addService(GattService &); 32 | virtual ble_error_t read(GattAttribute::Handle_t attributeHandle, uint8_t buffer[], uint16_t *lengthP); 33 | virtual ble_error_t read(Gap::Handle_t connectionHandle, GattAttribute::Handle_t attributeHandle, uint8_t buffer[], uint16_t *lengthP); 34 | virtual ble_error_t write(GattAttribute::Handle_t, const uint8_t[], uint16_t, bool localOnly = false); 35 | virtual ble_error_t write(Gap::Handle_t connectionHandle, GattAttribute::Handle_t, const uint8_t[], uint16_t, bool localOnly = false); 36 | virtual ble_error_t areUpdatesEnabled(const GattCharacteristic &characteristic, bool *enabledP); 37 | virtual ble_error_t areUpdatesEnabled(Gap::Handle_t connectionHandle, const GattCharacteristic &characteristic, bool *enabledP); 38 | virtual ble_error_t reset(void); 39 | 40 | /* nRF51 Functions */ 41 | void eventCallback(void); 42 | void hwCallback(ble_evt_t *p_ble_evt); 43 | 44 | 45 | private: 46 | const static unsigned BLE_TOTAL_CHARACTERISTICS = 20; 47 | const static unsigned BLE_TOTAL_DESCRIPTORS = 8; 48 | 49 | private: 50 | /** 51 | * resolve a value attribute to its owning characteristic. 52 | * @param valueHandle the value handle to be resolved. 53 | * @return characteristic index if a resolution is found, else -1. 54 | */ 55 | int resolveValueHandleToCharIndex(GattAttribute::Handle_t valueHandle) const { 56 | unsigned charIndex; 57 | for (charIndex = 0; charIndex < characteristicCount; charIndex++) { 58 | if (nrfCharacteristicHandles[charIndex].value_handle == valueHandle) { 59 | return charIndex; 60 | } 61 | } 62 | 63 | return -1; 64 | } 65 | 66 | /** 67 | * resolve a CCCD attribute handle to its owning characteristic. 68 | * @param cccdHandle the CCCD handle to be resolved. 69 | * @return characteristic index if a resolution is found, else -1. 70 | */ 71 | int resolveCCCDHandleToCharIndex(GattAttribute::Handle_t cccdHandle) const { 72 | unsigned charIndex; 73 | for (charIndex = 0; charIndex < characteristicCount; charIndex++) { 74 | if (nrfCharacteristicHandles[charIndex].cccd_handle == cccdHandle) { 75 | return charIndex; 76 | } 77 | } 78 | 79 | return -1; 80 | } 81 | 82 | private: 83 | GattCharacteristic *p_characteristics[BLE_TOTAL_CHARACTERISTICS]; 84 | ble_gatts_char_handles_t nrfCharacteristicHandles[BLE_TOTAL_CHARACTERISTICS]; 85 | GattAttribute *p_descriptors[BLE_TOTAL_DESCRIPTORS]; 86 | uint8_t descriptorCount; 87 | uint16_t nrfDescriptorHandles[BLE_TOTAL_DESCRIPTORS]; 88 | 89 | /* 90 | * Allow instantiation from nRF5xn when required. 91 | */ 92 | friend class nRF5xn; 93 | 94 | nRF5xGattServer() : GattServer(), p_characteristics(), nrfCharacteristicHandles(), p_descriptors(), descriptorCount(0), nrfDescriptorHandles() { 95 | /* empty */ 96 | } 97 | 98 | private: 99 | nRF5xGattServer(const nRF5xGattServer &); 100 | const nRF5xGattServer& operator=(const nRF5xGattServer &); 101 | }; 102 | 103 | #endif // ifndef __NRF51822_GATT_SERVER_H__ 104 | -------------------------------------------------------------------------------- /source/nRF5xSecurityManager.h: -------------------------------------------------------------------------------- 1 | /* mbed Microcontroller Library 2 | * Copyright (c) 2006-2013 ARM Limited 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #ifndef __NRF51822_SECURITY_MANAGER_H__ 18 | #define __NRF51822_SECURITY_MANAGER_H__ 19 | 20 | #include 21 | 22 | #include "nRF5xGap.h" 23 | #include "ble/SecurityManager.h" 24 | #include "btle_security.h" 25 | 26 | class nRF5xSecurityManager : public SecurityManager 27 | { 28 | public: 29 | /* Functions that must be implemented from SecurityManager */ 30 | virtual ble_error_t init(bool enableBonding, 31 | bool requireMITM, 32 | SecurityIOCapabilities_t iocaps, 33 | const Passkey_t passkey) { 34 | return btle_initializeSecurity(enableBonding, requireMITM, iocaps, passkey); 35 | } 36 | 37 | virtual ble_error_t getLinkSecurity(Gap::Handle_t connectionHandle, LinkSecurityStatus_t *securityStatusP) { 38 | return btle_getLinkSecurity(connectionHandle, securityStatusP); 39 | } 40 | 41 | virtual ble_error_t setLinkSecurity(Gap::Handle_t connectionHandle, SecurityMode_t securityMode) { 42 | return btle_setLinkSecurity(connectionHandle, securityMode); 43 | } 44 | 45 | virtual ble_error_t purgeAllBondingState(void) { 46 | return btle_purgeAllBondingState(); 47 | } 48 | 49 | /** 50 | * @brief Returns a list of addresses from peers in the stacks bond table. 51 | * 52 | * @param[in/out] addresses 53 | * (on input) @ref Gap::Whitelist_t structure where at 54 | * most addresses.capacity addresses from bonded peers will 55 | * be stored. 56 | * (on output) A copy of the addresses from bonded peers. 57 | * 58 | * @return 59 | * BLE_ERROR_NONE if successful. 60 | */ 61 | virtual ble_error_t getAddressesFromBondTable(Gap::Whitelist_t &addresses) const { 62 | uint8_t i; 63 | 64 | ble_gap_whitelist_t whitelistFromBondTable; 65 | ble_gap_addr_t *addressPtr[YOTTA_CFG_WHITELIST_MAX_SIZE]; 66 | ble_gap_irk_t *irkPtr[YOTTA_CFG_IRK_TABLE_MAX_SIZE]; 67 | 68 | /* Initialize the structure so that we get as many addreses as the whitelist can hold */ 69 | whitelistFromBondTable.addr_count = YOTTA_CFG_IRK_TABLE_MAX_SIZE; 70 | whitelistFromBondTable.pp_addrs = addressPtr; 71 | whitelistFromBondTable.irk_count = YOTTA_CFG_IRK_TABLE_MAX_SIZE; 72 | whitelistFromBondTable.pp_irks = irkPtr; 73 | 74 | ble_error_t error = createWhitelistFromBondTable(whitelistFromBondTable); 75 | if (error != BLE_ERROR_NONE) { 76 | addresses.size = 0; 77 | return error; 78 | } 79 | 80 | /* Put all the addresses in the structure */ 81 | for (i = 0; i < whitelistFromBondTable.addr_count; ++i) { 82 | if (i >= addresses.capacity) { 83 | /* Ran out of space in the output Gap::Whitelist_t */ 84 | addresses.size = i; 85 | return BLE_ERROR_NONE; 86 | } 87 | memcpy(&addresses.addresses[i], whitelistFromBondTable.pp_addrs[i], sizeof(BLEProtocol::Address_t)); 88 | } 89 | 90 | /* Update the current address count */ 91 | addresses.size = i; 92 | 93 | /* The assumption here is that the underlying implementation of 94 | * createWhitelistFromBondTable() will not return the private resolvable 95 | * addresses (which is the case in the SoftDevice). Rather it returns the 96 | * IRKs, so we need to generate the private resolvable address by ourselves. 97 | */ 98 | for (i = 0; i < whitelistFromBondTable.irk_count; ++i) { 99 | if (i + addresses.size >= addresses.capacity) { 100 | /* Ran out of space in the output Gap::Whitelist_t */ 101 | addresses.size += i; 102 | return BLE_ERROR_NONE; 103 | } 104 | btle_generateResolvableAddress( 105 | *whitelistFromBondTable.pp_irks[i], 106 | (ble_gap_addr_t &) addresses.addresses[i + addresses.size] 107 | ); 108 | } 109 | 110 | /* Update the current address count */ 111 | addresses.size += i; 112 | 113 | return BLE_ERROR_NONE; 114 | } 115 | 116 | /** 117 | * @brief Clear nRF5xSecurityManager's state. 118 | * 119 | * @return 120 | * BLE_ERROR_NONE if successful. 121 | */ 122 | virtual ble_error_t reset(void) 123 | { 124 | if (SecurityManager::reset() != BLE_ERROR_NONE) { 125 | return BLE_ERROR_INVALID_STATE; 126 | } 127 | 128 | return BLE_ERROR_NONE; 129 | } 130 | 131 | bool hasInitialized(void) const { 132 | return btle_hasInitializedSecurity(); 133 | } 134 | 135 | public: 136 | /* 137 | * Allow instantiation from nRF5xn when required. 138 | */ 139 | friend class nRF5xn; 140 | 141 | nRF5xSecurityManager() { 142 | /* empty */ 143 | } 144 | 145 | private: 146 | nRF5xSecurityManager(const nRF5xSecurityManager &); 147 | const nRF5xSecurityManager& operator=(const nRF5xSecurityManager &); 148 | 149 | /* 150 | * Expose an interface that allows us to query the SoftDevice bond table 151 | * and extract a whitelist. 152 | */ 153 | ble_error_t createWhitelistFromBondTable(ble_gap_whitelist_t &whitelistFromBondTable) const { 154 | return btle_createWhitelistFromBondTable(&whitelistFromBondTable); 155 | } 156 | 157 | /* 158 | * Given a BLE address and a IRK this function check whether the address 159 | * can be generated from the IRK. To do so, this function uses the hash 160 | * function and algorithm described in the Bluetooth low Energy 161 | * Specification. Internally, Nordic SDK functions are used. 162 | */ 163 | bool matchAddressAndIrk(ble_gap_addr_t *address, ble_gap_irk_t *irk) const { 164 | return btle_matchAddressAndIrk(address, irk); 165 | } 166 | 167 | /* 168 | * Give nRF5xGap access to createWhitelistFromBondTable() and 169 | * matchAddressAndIrk() 170 | */ 171 | friend class nRF5xGap; 172 | }; 173 | 174 | #endif // ifndef __NRF51822_SECURITY_MANAGER_H__ 175 | -------------------------------------------------------------------------------- /source/nRF5xServiceDiscovery.cpp: -------------------------------------------------------------------------------- 1 | /* mbed Microcontroller Library 2 | * Copyright (c) 2006-2013 ARM Limited 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #include "nRF5xServiceDiscovery.h" 18 | 19 | ble_error_t 20 | nRF5xServiceDiscovery::launchCharacteristicDiscovery(Gap::Handle_t connectionHandle, 21 | Gap::Handle_t startHandle, 22 | Gap::Handle_t endHandle) 23 | { 24 | characteristicDiscoveryStarted(connectionHandle); 25 | 26 | ble_gattc_handle_range_t handleRange = { 27 | .start_handle = startHandle, 28 | .end_handle = endHandle 29 | }; 30 | uint32_t rc = sd_ble_gattc_characteristics_discover(connectionHandle, &handleRange); 31 | ble_error_t err = BLE_ERROR_NONE; 32 | 33 | switch (rc) { 34 | case NRF_SUCCESS: 35 | err = BLE_ERROR_NONE; 36 | break; 37 | case BLE_ERROR_INVALID_CONN_HANDLE: 38 | case NRF_ERROR_INVALID_ADDR: 39 | err = BLE_ERROR_INVALID_PARAM; 40 | break; 41 | case NRF_ERROR_BUSY: 42 | err = BLE_STACK_BUSY; 43 | break; 44 | case NRF_ERROR_INVALID_STATE: 45 | err = BLE_ERROR_INVALID_STATE; 46 | break; 47 | default: 48 | err = BLE_ERROR_UNSPECIFIED; 49 | break; 50 | } 51 | 52 | if (err) { 53 | terminateCharacteristicDiscovery(err); 54 | } 55 | return err; 56 | } 57 | 58 | void 59 | nRF5xServiceDiscovery::setupDiscoveredServices(const ble_gattc_evt_prim_srvc_disc_rsp_t *response) 60 | { 61 | serviceIndex = 0; 62 | numServices = response->count; 63 | 64 | /* Account for the limitation on the number of discovered services we can handle at a time. */ 65 | if (numServices > BLE_DB_DISCOVERY_MAX_SRV) { 66 | numServices = BLE_DB_DISCOVERY_MAX_SRV; 67 | } 68 | 69 | serviceUUIDDiscoveryQueue.reset(); 70 | for (unsigned serviceIndex = 0; serviceIndex < numServices; serviceIndex++) { 71 | if (response->services[serviceIndex].uuid.type == BLE_UUID_TYPE_UNKNOWN) { 72 | serviceUUIDDiscoveryQueue.enqueue(serviceIndex); 73 | services[serviceIndex].setup(response->services[serviceIndex].handle_range.start_handle, 74 | response->services[serviceIndex].handle_range.end_handle); 75 | } else { 76 | services[serviceIndex].setup(response->services[serviceIndex].uuid.uuid, 77 | response->services[serviceIndex].handle_range.start_handle, 78 | response->services[serviceIndex].handle_range.end_handle); 79 | } 80 | } 81 | 82 | /* Trigger discovery of service UUID if necessary. */ 83 | if (serviceUUIDDiscoveryQueue.getCount()) { 84 | serviceUUIDDiscoveryQueue.triggerFirst(); 85 | } 86 | } 87 | 88 | void 89 | nRF5xServiceDiscovery::setupDiscoveredCharacteristics(const ble_gattc_evt_char_disc_rsp_t *response) 90 | { 91 | numCharacteristics = response->count; 92 | 93 | /* Account for the limitation on the number of discovered characteristics we can handle at a time. */ 94 | if (numCharacteristics > BLE_DB_DISCOVERY_MAX_CHAR_PER_SRV) { 95 | numCharacteristics = BLE_DB_DISCOVERY_MAX_CHAR_PER_SRV; 96 | } 97 | 98 | charUUIDDiscoveryQueue.reset(); 99 | for (unsigned charIndex = 0; charIndex < numCharacteristics; charIndex++) { 100 | if (response->chars[charIndex].uuid.type == BLE_UUID_TYPE_UNKNOWN) { 101 | charUUIDDiscoveryQueue.enqueue(charIndex); 102 | characteristics[charIndex].setup(gattc, 103 | connHandle, 104 | response->chars[charIndex].char_props, 105 | response->chars[charIndex].handle_decl, 106 | response->chars[charIndex].handle_value); 107 | } else { 108 | characteristics[charIndex].setup(gattc, 109 | connHandle, 110 | response->chars[charIndex].uuid.uuid, 111 | response->chars[charIndex].char_props, 112 | response->chars[charIndex].handle_decl, 113 | response->chars[charIndex].handle_value); 114 | } 115 | } 116 | 117 | /* Trigger discovery of char UUID if necessary. */ 118 | if (charUUIDDiscoveryQueue.getCount()) { 119 | charUUIDDiscoveryQueue.triggerFirst(); 120 | } 121 | } 122 | 123 | void 124 | nRF5xServiceDiscovery::progressCharacteristicDiscovery(void) 125 | { 126 | if (state != CHARACTERISTIC_DISCOVERY_ACTIVE) { 127 | return; 128 | } 129 | 130 | if ((discoveredCharacteristic != nRF5xDiscoveredCharacteristic()) && (numCharacteristics > 0)) { 131 | discoveredCharacteristic.setLastHandle(characteristics[0].getDeclHandle() - 1); 132 | 133 | if ((matchingCharacteristicUUID == UUID::ShortUUIDBytes_t(BLE_UUID_UNKNOWN)) || 134 | ((matchingCharacteristicUUID == discoveredCharacteristic.getUUID()) && 135 | (matchingServiceUUID != UUID::ShortUUIDBytes_t(BLE_UUID_UNKNOWN)))) { 136 | if (characteristicCallback) { 137 | characteristicCallback(&discoveredCharacteristic); 138 | } 139 | } 140 | } 141 | 142 | for (uint8_t i = 0; i < numCharacteristics; ++i) { 143 | if (state != CHARACTERISTIC_DISCOVERY_ACTIVE) { 144 | return; 145 | } 146 | 147 | if (i == (numCharacteristics - 1)) { 148 | discoveredCharacteristic = characteristics[i]; 149 | break; 150 | } else { 151 | characteristics[i].setLastHandle(characteristics[i + 1].getDeclHandle() - 1); 152 | } 153 | 154 | if ((matchingCharacteristicUUID == UUID::ShortUUIDBytes_t(BLE_UUID_UNKNOWN)) || 155 | ((matchingCharacteristicUUID == characteristics[i].getUUID()) && 156 | (matchingServiceUUID != UUID::ShortUUIDBytes_t(BLE_UUID_UNKNOWN)))) { 157 | if (characteristicCallback) { 158 | characteristicCallback(&characteristics[i]); 159 | } 160 | } 161 | } 162 | 163 | if (state != CHARACTERISTIC_DISCOVERY_ACTIVE) { 164 | return; 165 | } 166 | 167 | Gap::Handle_t startHandle = (numCharacteristics > 0) ? characteristics[numCharacteristics - 1].getValueHandle() + 1 : SRV_DISC_END_HANDLE; 168 | Gap::Handle_t endHandle = services[serviceIndex].getEndHandle(); 169 | resetDiscoveredCharacteristics(); /* Note: resetDiscoveredCharacteristics() must come after fetching start and end Handles. */ 170 | 171 | if (startHandle < endHandle) { 172 | ble_gattc_handle_range_t handleRange = { 173 | .start_handle = startHandle, 174 | .end_handle = endHandle 175 | }; 176 | if (sd_ble_gattc_characteristics_discover(connHandle, &handleRange) != NRF_SUCCESS) { 177 | terminateCharacteristicDiscovery(BLE_ERROR_UNSPECIFIED); 178 | } 179 | } else { 180 | terminateCharacteristicDiscovery(BLE_ERROR_NONE); 181 | } 182 | } 183 | 184 | void 185 | nRF5xServiceDiscovery::progressServiceDiscovery(void) 186 | { 187 | /* Iterate through the previously discovered services cached in services[]. */ 188 | while ((state == SERVICE_DISCOVERY_ACTIVE) && (serviceIndex < numServices)) { 189 | if ((matchingServiceUUID == UUID::ShortUUIDBytes_t(BLE_UUID_UNKNOWN)) || 190 | (matchingServiceUUID == services[serviceIndex].getUUID())) { 191 | 192 | if (serviceCallback && (matchingCharacteristicUUID == UUID::ShortUUIDBytes_t(BLE_UUID_UNKNOWN))) { 193 | serviceCallback(&services[serviceIndex]); 194 | } 195 | 196 | if ((state == SERVICE_DISCOVERY_ACTIVE) && characteristicCallback) { 197 | launchCharacteristicDiscovery(connHandle, services[serviceIndex].getStartHandle(), services[serviceIndex].getEndHandle()); 198 | } else { 199 | serviceIndex++; 200 | } 201 | } else { 202 | serviceIndex++; 203 | } 204 | } 205 | 206 | /* Relaunch discovery of new services beyond the last entry cached in services[]. */ 207 | if ((state == SERVICE_DISCOVERY_ACTIVE) && (numServices > 0) && (serviceIndex > 0)) { 208 | /* Determine the ending handle of the last cached service. */ 209 | Gap::Handle_t endHandle = services[serviceIndex - 1].getEndHandle(); 210 | resetDiscoveredServices(); /* Note: resetDiscoveredServices() must come after fetching endHandle. */ 211 | 212 | if (endHandle == SRV_DISC_END_HANDLE) { 213 | terminateServiceDiscovery(); 214 | } else { 215 | if (sd_ble_gattc_primary_services_discover(connHandle, endHandle, NULL) != NRF_SUCCESS) { 216 | terminateServiceDiscovery(); 217 | } 218 | } 219 | } 220 | } 221 | 222 | void 223 | nRF5xServiceDiscovery::ServiceUUIDDiscoveryQueue::triggerFirst(void) 224 | { 225 | while (numIndices) { /* loop until a call to char_value_by_uuid_read() succeeds or we run out of pending indices. */ 226 | parentDiscoveryObject->state = DISCOVER_SERVICE_UUIDS; 227 | 228 | unsigned serviceIndex = getFirst(); 229 | ble_uuid_t uuid = { 230 | .uuid = BLE_UUID_SERVICE_PRIMARY, 231 | .type = BLE_UUID_TYPE_BLE, 232 | }; 233 | ble_gattc_handle_range_t handleRange = { 234 | .start_handle = parentDiscoveryObject->services[serviceIndex].getStartHandle(), 235 | .end_handle = parentDiscoveryObject->services[serviceIndex].getEndHandle(), 236 | }; 237 | if (sd_ble_gattc_char_value_by_uuid_read(parentDiscoveryObject->connHandle, &uuid, &handleRange) == NRF_SUCCESS) { 238 | return; 239 | } 240 | 241 | /* Skip this service if we fail to launch a read for its service-declaration 242 | * attribute. Its UUID will remain INVALID, and it may not match any filters. */ 243 | dequeue(); 244 | } 245 | 246 | /* Switch back to service discovery upon exhausting the service-indices pending UUID discovery. */ 247 | if (parentDiscoveryObject->state == DISCOVER_SERVICE_UUIDS) { 248 | parentDiscoveryObject->state = SERVICE_DISCOVERY_ACTIVE; 249 | } 250 | } 251 | 252 | void 253 | nRF5xServiceDiscovery::CharUUIDDiscoveryQueue::triggerFirst(void) 254 | { 255 | while (numIndices) { /* loop until a call to char_value_by_uuid_read() succeeds or we run out of pending indices. */ 256 | parentDiscoveryObject->state = DISCOVER_CHARACTERISTIC_UUIDS; 257 | 258 | unsigned charIndex = getFirst(); 259 | ble_uuid_t uuid = { 260 | .uuid = BLE_UUID_CHARACTERISTIC, 261 | .type = BLE_UUID_TYPE_BLE, 262 | }; 263 | ble_gattc_handle_range_t handleRange = { }; 264 | handleRange.start_handle = parentDiscoveryObject->characteristics[charIndex].getDeclHandle(); 265 | handleRange.end_handle = parentDiscoveryObject->characteristics[charIndex].getDeclHandle() + 1; 266 | if (sd_ble_gattc_char_value_by_uuid_read(parentDiscoveryObject->connHandle, &uuid, &handleRange) == NRF_SUCCESS) { 267 | return; 268 | } 269 | 270 | /* Skip this service if we fail to launch a read for its service-declaration 271 | * attribute. Its UUID will remain INVALID, and it may not match any filters. */ 272 | dequeue(); 273 | } 274 | 275 | /* Switch back to service discovery upon exhausting the service-indices pending UUID discovery. */ 276 | if (parentDiscoveryObject->state == DISCOVER_CHARACTERISTIC_UUIDS) { 277 | parentDiscoveryObject->state = CHARACTERISTIC_DISCOVERY_ACTIVE; 278 | } 279 | } 280 | 281 | void 282 | nRF5xServiceDiscovery::processDiscoverUUIDResponse(const ble_gattc_evt_char_val_by_uuid_read_rsp_t *response) 283 | { 284 | if (state == DISCOVER_SERVICE_UUIDS) { 285 | if ((response->count == 1) && (response->value_len == UUID::LENGTH_OF_LONG_UUID)) { 286 | UUID::LongUUIDBytes_t uuid; 287 | memcpy(uuid, response->handle_value[0].p_value, UUID::LENGTH_OF_LONG_UUID); 288 | 289 | unsigned serviceIndex = serviceUUIDDiscoveryQueue.dequeue(); 290 | services[serviceIndex].setupLongUUID(uuid, UUID::LSB); 291 | 292 | serviceUUIDDiscoveryQueue.triggerFirst(); 293 | } else { 294 | serviceUUIDDiscoveryQueue.dequeue(); 295 | } 296 | } else if (state == DISCOVER_CHARACTERISTIC_UUIDS) { 297 | if ((response->count == 1) && (response->value_len == UUID::LENGTH_OF_LONG_UUID + 1 /* props */ + 2 /* value handle */)) { 298 | UUID::LongUUIDBytes_t uuid; 299 | 300 | memcpy(uuid, &(response->handle_value[0].p_value[3]), UUID::LENGTH_OF_LONG_UUID); 301 | 302 | unsigned charIndex = charUUIDDiscoveryQueue.dequeue(); 303 | characteristics[charIndex].setupLongUUID(uuid, UUID::LSB); 304 | 305 | charUUIDDiscoveryQueue.triggerFirst(); 306 | } else { 307 | charUUIDDiscoveryQueue.dequeue(); 308 | } 309 | } 310 | } 311 | -------------------------------------------------------------------------------- /source/nRF5xServiceDiscovery.h: -------------------------------------------------------------------------------- 1 | /* mbed Microcontroller Library 2 | * Copyright (c) 2006-2013 ARM Limited 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #ifndef __NRF_SERVICE_DISCOVERY_H__ 18 | #define __NRF_SERVICE_DISCOVERY_H__ 19 | 20 | #include "ble/ServiceDiscovery.h" 21 | #include "ble/DiscoveredService.h" 22 | #include "nRF5xDiscoveredCharacteristic.h" 23 | 24 | #include "nrf_ble.h" 25 | #include "ble_gattc.h" 26 | 27 | class nRF5xGattClient; /* forward declaration */ 28 | 29 | class nRF5xServiceDiscovery : public ServiceDiscovery 30 | { 31 | public: 32 | static const uint16_t SRV_DISC_START_HANDLE = 0x0001; /**< The start handle value used during service discovery. */ 33 | static const uint16_t SRV_DISC_END_HANDLE = 0xFFFF; /**< The end handle value used during service discovery. */ 34 | 35 | public: 36 | static const unsigned BLE_DB_DISCOVERY_MAX_SRV = 4; /**< Maximum number of services we can retain information for after a single discovery. */ 37 | static const unsigned BLE_DB_DISCOVERY_MAX_CHAR_PER_SRV = 4; /**< Maximum number of characteristics per service we can retain information for. */ 38 | 39 | public: 40 | nRF5xServiceDiscovery(nRF5xGattClient *gattcIn) : 41 | gattc(gattcIn), 42 | serviceIndex(0), 43 | numServices(0), 44 | numCharacteristics(0), 45 | state(INACTIVE), 46 | services(), 47 | characteristics(), 48 | serviceUUIDDiscoveryQueue(this), 49 | charUUIDDiscoveryQueue(this), 50 | onTerminationCallback(NULL) { 51 | /* empty */ 52 | } 53 | 54 | virtual ble_error_t launch(Gap::Handle_t connectionHandle, 55 | ServiceDiscovery::ServiceCallback_t sc, 56 | ServiceDiscovery::CharacteristicCallback_t cc, 57 | const UUID &matchingServiceUUIDIn, 58 | const UUID &matchingCharacteristicUUIDIn) 59 | { 60 | if (isActive()) { 61 | return BLE_ERROR_INVALID_STATE; 62 | } 63 | 64 | serviceCallback = sc; 65 | characteristicCallback = cc; 66 | matchingServiceUUID = matchingServiceUUIDIn; 67 | matchingCharacteristicUUID = matchingCharacteristicUUIDIn; 68 | 69 | serviceDiscoveryStarted(connectionHandle); 70 | 71 | uint32_t rc; 72 | if ((rc = sd_ble_gattc_primary_services_discover(connectionHandle, SRV_DISC_START_HANDLE, NULL)) != NRF_SUCCESS) { 73 | terminate(); 74 | switch (rc) { 75 | case NRF_ERROR_INVALID_PARAM: 76 | case BLE_ERROR_INVALID_CONN_HANDLE: 77 | return BLE_ERROR_INVALID_PARAM; 78 | case NRF_ERROR_BUSY: 79 | return BLE_STACK_BUSY; 80 | default: 81 | case NRF_ERROR_INVALID_STATE: 82 | return BLE_ERROR_INVALID_STATE; 83 | } 84 | } 85 | 86 | return BLE_ERROR_NONE; 87 | } 88 | 89 | virtual bool isActive(void) const { 90 | return state != INACTIVE; 91 | } 92 | 93 | virtual void terminate(void) { 94 | terminateServiceDiscovery(); 95 | } 96 | 97 | void terminate(Gap::Handle_t connectionHandle) { 98 | if(connHandle == connectionHandle) { 99 | terminate(); 100 | } 101 | } 102 | 103 | virtual void onTermination(ServiceDiscovery::TerminationCallback_t callback) { 104 | onTerminationCallback = callback; 105 | } 106 | 107 | /** 108 | * @brief Clear nRF5xServiceDiscovery's state. 109 | * 110 | * @return 111 | * BLE_ERROR_NONE if successful. 112 | */ 113 | virtual ble_error_t reset(void) { 114 | /* Clear all state that is from the parent, including private members */ 115 | if (ServiceDiscovery::reset() != BLE_ERROR_NONE) { 116 | return BLE_ERROR_INVALID_STATE; 117 | } 118 | 119 | /* Clear derived class members */ 120 | serviceIndex = 0; 121 | numServices = 0; 122 | numCharacteristics = 0; 123 | 124 | state = INACTIVE; 125 | 126 | serviceUUIDDiscoveryQueue.reset(); 127 | charUUIDDiscoveryQueue.reset(); 128 | 129 | onTerminationCallback = NULL; 130 | 131 | return BLE_ERROR_NONE; 132 | } 133 | 134 | private: 135 | ble_error_t launchCharacteristicDiscovery(Gap::Handle_t connectionHandle, Gap::Handle_t startHandle, Gap::Handle_t endHandle); 136 | 137 | private: 138 | void setupDiscoveredServices(const ble_gattc_evt_prim_srvc_disc_rsp_t *response); 139 | void setupDiscoveredCharacteristics(const ble_gattc_evt_char_disc_rsp_t *response); 140 | 141 | void triggerServiceUUIDDiscovery(void); 142 | void processDiscoverUUIDResponse(const ble_gattc_evt_char_val_by_uuid_read_rsp_t *response); 143 | void removeFirstServiceNeedingUUIDDiscovery(void); 144 | 145 | void terminateServiceDiscovery(void) { 146 | discoveredCharacteristic = nRF5xDiscoveredCharacteristic(); 147 | 148 | bool wasActive = isActive(); 149 | state = INACTIVE; 150 | 151 | if (wasActive && onTerminationCallback) { 152 | onTerminationCallback(connHandle); 153 | } 154 | } 155 | 156 | void terminateCharacteristicDiscovery(ble_error_t err) { 157 | if (state == CHARACTERISTIC_DISCOVERY_ACTIVE) { 158 | if(discoveredCharacteristic != nRF5xDiscoveredCharacteristic()) { 159 | if(err == BLE_ERROR_NONE) { 160 | // fullfill the last characteristic 161 | discoveredCharacteristic.setLastHandle(services[serviceIndex].getEndHandle()); 162 | 163 | if ((matchingCharacteristicUUID == UUID::ShortUUIDBytes_t(BLE_UUID_UNKNOWN)) || 164 | ((matchingCharacteristicUUID == discoveredCharacteristic.getUUID()) && 165 | (matchingServiceUUID != UUID::ShortUUIDBytes_t(BLE_UUID_UNKNOWN)))) { 166 | if (characteristicCallback) { 167 | characteristicCallback(&discoveredCharacteristic); 168 | } 169 | } 170 | } 171 | discoveredCharacteristic = nRF5xDiscoveredCharacteristic(); 172 | } 173 | 174 | state = SERVICE_DISCOVERY_ACTIVE; 175 | } 176 | serviceIndex++; /* Progress service index to keep discovery alive. */ 177 | } 178 | 179 | private: 180 | void resetDiscoveredServices(void) { 181 | numServices = 0; 182 | serviceIndex = 0; 183 | } 184 | 185 | void resetDiscoveredCharacteristics(void) { 186 | numCharacteristics = 0; 187 | } 188 | 189 | private: 190 | void serviceDiscoveryStarted(Gap::Handle_t connectionHandle) { 191 | connHandle = connectionHandle; 192 | resetDiscoveredServices(); 193 | state = SERVICE_DISCOVERY_ACTIVE; 194 | } 195 | 196 | private: 197 | void characteristicDiscoveryStarted(Gap::Handle_t connectionHandle) { 198 | connHandle = connectionHandle; 199 | resetDiscoveredCharacteristics(); 200 | state = CHARACTERISTIC_DISCOVERY_ACTIVE; 201 | } 202 | 203 | private: 204 | /** 205 | * A datatype to contain service-indices for which long UUIDs need to be 206 | * discovered using read_val_by_uuid(). 207 | */ 208 | class ServiceUUIDDiscoveryQueue { 209 | public: 210 | ServiceUUIDDiscoveryQueue(nRF5xServiceDiscovery *parent) : 211 | numIndices(0), 212 | serviceIndices(), 213 | parentDiscoveryObject(parent) { 214 | /* empty */ 215 | } 216 | 217 | public: 218 | void reset(void) { 219 | numIndices = 0; 220 | for (unsigned i = 0; i < BLE_DB_DISCOVERY_MAX_SRV; i++) { 221 | serviceIndices[i] = INVALID_INDEX; 222 | } 223 | } 224 | void enqueue(int serviceIndex) { 225 | serviceIndices[numIndices++] = serviceIndex; 226 | } 227 | int dequeue(void) { 228 | if (numIndices == 0) { 229 | return INVALID_INDEX; 230 | } 231 | 232 | unsigned valueToReturn = serviceIndices[0]; 233 | numIndices--; 234 | for (unsigned i = 0; i < numIndices; i++) { 235 | serviceIndices[i] = serviceIndices[i + 1]; 236 | } 237 | 238 | return valueToReturn; 239 | } 240 | unsigned getFirst(void) const { 241 | return serviceIndices[0]; 242 | } 243 | size_t getCount(void) const { 244 | return numIndices; 245 | } 246 | 247 | /** 248 | * Trigger UUID discovery for the first of the enqueued ServiceIndices. 249 | */ 250 | void triggerFirst(void); 251 | 252 | private: 253 | static const int INVALID_INDEX = -1; 254 | 255 | private: 256 | size_t numIndices; 257 | int serviceIndices[BLE_DB_DISCOVERY_MAX_SRV]; 258 | 259 | nRF5xServiceDiscovery *parentDiscoveryObject; 260 | }; 261 | friend class ServiceUUIDDiscoveryQueue; 262 | 263 | /** 264 | * A datatype to contain characteristic-indices for which long UUIDs need to 265 | * be discovered using read_val_by_uuid(). 266 | */ 267 | class CharUUIDDiscoveryQueue { 268 | public: 269 | CharUUIDDiscoveryQueue(nRF5xServiceDiscovery *parent) : 270 | numIndices(0), 271 | charIndices(), 272 | parentDiscoveryObject(parent) { 273 | /* empty */ 274 | } 275 | 276 | public: 277 | void reset(void) { 278 | numIndices = 0; 279 | for (unsigned i = 0; i < BLE_DB_DISCOVERY_MAX_SRV; i++) { 280 | charIndices[i] = INVALID_INDEX; 281 | } 282 | } 283 | void enqueue(int serviceIndex) { 284 | charIndices[numIndices++] = serviceIndex; 285 | } 286 | int dequeue(void) { 287 | if (numIndices == 0) { 288 | return INVALID_INDEX; 289 | } 290 | 291 | unsigned valueToReturn = charIndices[0]; 292 | numIndices--; 293 | for (unsigned i = 0; i < numIndices; i++) { 294 | charIndices[i] = charIndices[i + 1]; 295 | } 296 | 297 | return valueToReturn; 298 | } 299 | unsigned getFirst(void) const { 300 | return charIndices[0]; 301 | } 302 | size_t getCount(void) const { 303 | return numIndices; 304 | } 305 | 306 | /** 307 | * Trigger UUID discovery for the first of the enqueued charIndices. 308 | */ 309 | void triggerFirst(void); 310 | 311 | private: 312 | static const int INVALID_INDEX = -1; 313 | 314 | private: 315 | size_t numIndices; 316 | int charIndices[BLE_DB_DISCOVERY_MAX_CHAR_PER_SRV]; 317 | 318 | nRF5xServiceDiscovery *parentDiscoveryObject; 319 | }; 320 | friend class CharUUIDDiscoveryQueue; 321 | 322 | private: 323 | friend void bleGattcEventHandler(const ble_evt_t *p_ble_evt); 324 | void progressCharacteristicDiscovery(void); 325 | void progressServiceDiscovery(void); 326 | 327 | private: 328 | nRF5xGattClient *gattc; 329 | 330 | private: 331 | uint8_t serviceIndex; /**< Index of the current service being discovered. This is intended for internal use during service discovery.*/ 332 | uint8_t numServices; /**< Number of services at the peers GATT database.*/ 333 | uint8_t numCharacteristics; /**< Number of characteristics within the service.*/ 334 | 335 | enum State_t { 336 | INACTIVE, 337 | SERVICE_DISCOVERY_ACTIVE, 338 | CHARACTERISTIC_DISCOVERY_ACTIVE, 339 | DISCOVER_SERVICE_UUIDS, 340 | DISCOVER_CHARACTERISTIC_UUIDS, 341 | } state; 342 | 343 | DiscoveredService services[BLE_DB_DISCOVERY_MAX_SRV]; /**< Information related to the current service being discovered. 344 | * This is intended for internal use during service discovery. */ 345 | nRF5xDiscoveredCharacteristic characteristics[BLE_DB_DISCOVERY_MAX_CHAR_PER_SRV]; 346 | 347 | ServiceUUIDDiscoveryQueue serviceUUIDDiscoveryQueue; 348 | CharUUIDDiscoveryQueue charUUIDDiscoveryQueue; 349 | 350 | TerminationCallback_t onTerminationCallback; 351 | 352 | /* 353 | * The currently discovered characteristic. Discovery of a characteristic 354 | * is a two phase process. 355 | * First, declaration handle is fetched, it provide the UUID, the value handle and 356 | * the properties of a characteristic. 357 | * Second, the next declaration handle is fetched, with its declaration handle, it is 358 | * possible to compute the last handle of the discovered characteristic and fill the 359 | * missing part of the object. 360 | * If there is no remaining characteristic to discover, the last handle of the 361 | * discovered characteristic will be set to the last handle of its enclosing service. 362 | */ 363 | nRF5xDiscoveredCharacteristic discoveredCharacteristic; 364 | }; 365 | 366 | #endif /*__NRF_SERVICE_DISCOVERY_H__*/ 367 | -------------------------------------------------------------------------------- /source/nRF5xn.cpp: -------------------------------------------------------------------------------- 1 | /* mbed Microcontroller Library 2 | * Copyright (c) 2006-2013 ARM Limited 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #ifdef YOTTA_CFG_MBED_OS 18 | #include "mbed-drivers/mbed.h" 19 | #else 20 | #include "mbed.h" 21 | #endif 22 | #include "nRF5xn.h" 23 | #include "ble/blecommon.h" 24 | #include "nrf_soc.h" 25 | 26 | #include "btle/btle.h" 27 | #include "nrf_delay.h" 28 | 29 | extern "C" { 30 | #include "softdevice_handler.h" 31 | } 32 | 33 | /** 34 | * The singleton which represents the nRF51822 transport for the BLE. 35 | */ 36 | static nRF5xn deviceInstance; 37 | 38 | /** 39 | * BLE-API requires an implementation of the following function in order to 40 | * obtain its transport handle. 41 | */ 42 | BLEInstanceBase * 43 | createBLEInstance(void) 44 | { 45 | return &nRF5xn::Instance(BLE::DEFAULT_INSTANCE); 46 | } 47 | 48 | nRF5xn& nRF5xn::Instance(BLE::InstanceID_t instanceId) 49 | { 50 | return deviceInstance; 51 | } 52 | 53 | nRF5xn::nRF5xn(void) : 54 | initialized(false), 55 | instanceID(BLE::DEFAULT_INSTANCE), 56 | gapInstance(), 57 | gattServerInstance(NULL), 58 | gattClientInstance(NULL), 59 | securityManagerInstance(NULL) 60 | { 61 | } 62 | 63 | nRF5xn::~nRF5xn(void) 64 | { 65 | } 66 | 67 | const char *nRF5xn::getVersion(void) 68 | { 69 | if (!initialized) { 70 | return "INITIALIZATION_INCOMPLETE"; 71 | } 72 | 73 | static char versionString[32]; 74 | static bool versionFetched = false; 75 | 76 | if (!versionFetched) { 77 | ble_version_t version; 78 | if ((sd_ble_version_get(&version) == NRF_SUCCESS) && (version.company_id == 0x0059)) { 79 | switch (version.version_number) { 80 | case 0x07: 81 | case 0x08: 82 | snprintf(versionString, sizeof(versionString), "Nordic BLE4.1 ver:%u fw:%04x", version.version_number, version.subversion_number); 83 | break; 84 | default: 85 | snprintf(versionString, sizeof(versionString), "Nordic (spec unknown) ver:%u fw:%04x", version.version_number, version.subversion_number); 86 | break; 87 | } 88 | versionFetched = true; 89 | } else { 90 | strncpy(versionString, "unknown", sizeof(versionString)); 91 | } 92 | } 93 | 94 | return versionString; 95 | } 96 | 97 | /**************************************************************************/ 98 | /*! 99 | @brief Initialize the BLE stack. 100 | 101 | @returns ble_error_t 102 | 103 | @retval BLE_ERROR_NONE if everything executed properly and 104 | BLE_ERROR_ALREADY_INITIALIZED if the stack has already 105 | been initialized (possibly through a call to nRF5xn::init()). 106 | BLE_ERROR_INTERNAL_STACK_FAILURE is returned if initialization 107 | of the internal stack (SoftDevice) failed. 108 | 109 | */ 110 | /**************************************************************************/ 111 | ble_error_t nRF5xn::init(BLE::InstanceID_t instanceID, FunctionPointerWithContext callback) 112 | { 113 | if (initialized) { 114 | BLE::InitializationCompleteCallbackContext context = { 115 | BLE::Instance(instanceID), 116 | BLE_ERROR_ALREADY_INITIALIZED 117 | }; 118 | callback.call(&context); 119 | return BLE_ERROR_ALREADY_INITIALIZED; 120 | } 121 | 122 | instanceID = instanceID; 123 | 124 | /* ToDo: Clear memory contents, reset the SD, etc. */ 125 | if (btle_init() != ERROR_NONE) { 126 | return BLE_ERROR_INTERNAL_STACK_FAILURE; 127 | } 128 | 129 | initialized = true; 130 | BLE::InitializationCompleteCallbackContext context = { 131 | BLE::Instance(instanceID), 132 | BLE_ERROR_NONE 133 | }; 134 | callback.call(&context); 135 | return BLE_ERROR_NONE; 136 | } 137 | 138 | /**************************************************************************/ 139 | /*! 140 | @brief Purge the BLE stack of GATT and GAP state. 141 | 142 | @returns ble_error_t 143 | 144 | @retval BLE_ERROR_NONE 145 | Everything executed properly 146 | 147 | @note When using S110, GattClient::shutdown() will not be called 148 | since Gatt client features are not supported. 149 | */ 150 | /**************************************************************************/ 151 | ble_error_t nRF5xn::shutdown(void) 152 | { 153 | if (!initialized) { 154 | return BLE_ERROR_INITIALIZATION_INCOMPLETE; 155 | } 156 | 157 | /* 158 | * Shutdown the SoftDevice first. This is because we need to disable all 159 | * interrupts. Otherwise if we clear the BLE API and glue code first there 160 | * will be many NULL references and no config information which could lead 161 | * to errors if the shutdown process is interrupted. 162 | */ 163 | if (softdevice_handler_sd_disable() != NRF_SUCCESS) { 164 | return BLE_STACK_BUSY; 165 | } 166 | 167 | 168 | /* Shutdown the BLE API and nRF51 glue code */ 169 | ble_error_t error; 170 | 171 | if (gattServerInstance != NULL) { 172 | error = gattServerInstance->reset(); 173 | if (error != BLE_ERROR_NONE) { 174 | return error; 175 | } 176 | } 177 | 178 | if (securityManagerInstance != NULL) { 179 | error = securityManagerInstance->reset(); 180 | if (error != BLE_ERROR_NONE) { 181 | return error; 182 | } 183 | } 184 | 185 | /* S110 does not support BLE client features, nothing to reset. */ 186 | #if !defined(TARGET_MCU_NRF51_16K_S110) && !defined(TARGET_MCU_NRF51_32K_S110) 187 | if (gattClientInstance != NULL) { 188 | error = gattClientInstance->reset(); 189 | if (error != BLE_ERROR_NONE) { 190 | return error; 191 | } 192 | } 193 | #endif 194 | 195 | /* Gap instance is always present */ 196 | error = gapInstance.reset(); 197 | if (error != BLE_ERROR_NONE) { 198 | return error; 199 | } 200 | 201 | initialized = false; 202 | return BLE_ERROR_NONE; 203 | } 204 | 205 | void 206 | nRF5xn::waitForEvent(void) 207 | { 208 | processEvents(); 209 | sd_app_evt_wait(); 210 | } 211 | 212 | void nRF5xn::processEvents() { 213 | if (isEventsSignaled) { 214 | isEventsSignaled = false; 215 | intern_softdevice_events_execute(); 216 | } 217 | } 218 | -------------------------------------------------------------------------------- /source/nRF5xn.h: -------------------------------------------------------------------------------- 1 | /* mbed Microcontroller Library 2 | * Copyright (c) 2006-2013 ARM Limited 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #ifndef __NRF51822_H__ 18 | #define __NRF51822_H__ 19 | 20 | #include "ble/BLE.h" 21 | #include "ble/blecommon.h" 22 | #include "ble/BLEInstanceBase.h" 23 | 24 | #include "nRF5xGap.h" 25 | #include "nRF5xGattServer.h" 26 | #include "nRF5xGattClient.h" 27 | #include "nRF5xSecurityManager.h" 28 | 29 | #include "btle.h" 30 | 31 | class nRF5xn : public BLEInstanceBase 32 | { 33 | public: 34 | nRF5xn(void); 35 | virtual ~nRF5xn(void); 36 | 37 | virtual ble_error_t init(BLE::InstanceID_t instanceID, FunctionPointerWithContext callback); 38 | virtual bool hasInitialized(void) const { 39 | return initialized; 40 | } 41 | virtual ble_error_t shutdown(void); 42 | virtual const char *getVersion(void); 43 | 44 | /** 45 | * Accessors to GAP. This function checks whether gapInstance points to an 46 | * object. If if does not, then the gapInstance is updated to 47 | * &_getInstance before returning. 48 | * 49 | * @return A reference to GattServer. 50 | * 51 | * @note Unlike the GattClient, GattServer and SecurityManager, Gap is 52 | * always needed in a BLE application. Therefore it is allocated 53 | * statically. 54 | */ 55 | virtual Gap &getGap() { 56 | return gapInstance; 57 | }; 58 | 59 | /** 60 | * Accessors to GATT Server. This function checks whether a GattServer 61 | * object was previously instantiated. If such object does not exist, then 62 | * it is created before returning. 63 | * 64 | * @return A reference to GattServer. 65 | */ 66 | virtual GattServer &getGattServer() { 67 | if (gattServerInstance == NULL) { 68 | gattServerInstance = new nRF5xGattServer(); 69 | } 70 | return *gattServerInstance; 71 | }; 72 | 73 | /** 74 | * Accessors to GATT Client. This function checks whether a GattClient 75 | * object was previously instantiated. If such object does not exist, then 76 | * it is created before returning. 77 | * 78 | * @return A reference to GattClient. 79 | */ 80 | virtual nRF5xGattClient &getGattClient() { 81 | if (gattClientInstance == NULL) { 82 | gattClientInstance = new nRF5xGattClient(); 83 | } 84 | return *gattClientInstance; 85 | } 86 | 87 | /** 88 | * Accessors to Security Manager. This function checks whether a SecurityManager 89 | * object was previously instantiated. If such object does not exist, then 90 | * it is created before returning. 91 | * 92 | * @return A reference to GattServer. 93 | */ 94 | virtual nRF5xSecurityManager &getSecurityManager() { 95 | if (securityManagerInstance == NULL) { 96 | securityManagerInstance = new nRF5xSecurityManager(); 97 | } 98 | return *securityManagerInstance; 99 | } 100 | 101 | /** 102 | * Accessors to GAP. This function checks whether gapInstance points to an 103 | * object. If if does not, then the gapInstance is updated to 104 | * &_getInstance before returning. 105 | * 106 | * @return A const reference to GattServer. 107 | * 108 | * @note Unlike the GattClient, GattServer and SecurityManager, Gap is 109 | * always needed in a BLE application. Therefore it is allocated 110 | * statically. 111 | * 112 | * @note The accessor is able to modify the object's state because the 113 | * internal pointer has been declared mutable. 114 | */ 115 | virtual const nRF5xGap &getGap() const { 116 | return gapInstance; 117 | }; 118 | 119 | /** 120 | * Accessors to GATT Server. This function checks whether a GattServer 121 | * object was previously instantiated. If such object does not exist, then 122 | * it is created before returning. 123 | * 124 | * @return A const reference to GattServer. 125 | * 126 | * @note The accessor is able to modify the object's state because the 127 | * internal pointer has been declared mutable. 128 | */ 129 | virtual const nRF5xGattServer &getGattServer() const { 130 | if (gattServerInstance == NULL) { 131 | gattServerInstance = new nRF5xGattServer(); 132 | } 133 | return *gattServerInstance; 134 | }; 135 | 136 | /** 137 | * Accessors to Security Manager. This function checks whether a SecurityManager 138 | * object was previously instantiated. If such object does not exist, then 139 | * it is created before returning. 140 | * 141 | * @return A const reference to GattServer. 142 | * 143 | * @note The accessor is able to modify the object's state because the 144 | * internal pointer has been declared mutable. 145 | */ 146 | virtual const nRF5xSecurityManager &getSecurityManager() const { 147 | if (securityManagerInstance == NULL) { 148 | securityManagerInstance = new nRF5xSecurityManager(); 149 | } 150 | return *securityManagerInstance; 151 | } 152 | 153 | virtual void waitForEvent(void); 154 | 155 | virtual void processEvents(); 156 | 157 | public: 158 | static nRF5xn& Instance(BLE::InstanceID_t instanceId); 159 | 160 | private: 161 | bool initialized; 162 | BLE::InstanceID_t instanceID; 163 | 164 | private: 165 | mutable nRF5xGap gapInstance; /**< Gap instance whose reference is returned from a call to 166 | * getGap(). Unlike the GattClient, GattServer and 167 | * SecurityManager, Gap is always needed in a BLE application. */ 168 | 169 | private: 170 | mutable nRF5xGattServer *gattServerInstance; /**< Pointer to the GattServer object instance. 171 | * If NULL, then GattServer has not been initialized. 172 | * The pointer has been declared as 'mutable' so that 173 | * it can be assigned inside a 'const' function. */ 174 | mutable nRF5xGattClient *gattClientInstance; /**< Pointer to the GattClient object instance. 175 | * If NULL, then GattClient has not been initialized. 176 | * The pointer has been declared as 'mutable' so that 177 | * it can be assigned inside a 'const' function. */ 178 | mutable nRF5xSecurityManager *securityManagerInstance; /**< Pointer to the SecurityManager object instance. 179 | * If NULL, then SecurityManager has not been initialized. 180 | * The pointer has been declared as 'mutable' so that 181 | * it can be assigned inside a 'const' function. */ 182 | }; 183 | 184 | #endif 185 | -------------------------------------------------------------------------------- /source/projectconfig.h: -------------------------------------------------------------------------------- 1 | /* mbed Microcontroller Library 2 | * Copyright (c) 2006-2013 ARM Limited 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #ifndef _PROJECTCONFIG_H_ 18 | #define _PROJECTCONFIG_H_ 19 | 20 | #include "ble/GapAdvertisingData.h" 21 | 22 | /*========================================================================= 23 | MCU & BOARD SELCTION 24 | 25 | CFG_BOARD is one of the value defined in board.h 26 | -----------------------------------------------------------------------*/ 27 | #define CFG_BOARD BOARD_PCA10001 28 | #define CFG_MCU_STRING "nRF51822" 29 | /*=========================================================================*/ 30 | 31 | 32 | /*========================================================================= 33 | CODE BASE VERSION SETTINGS 34 | 35 | Please do not modify this version number. To set a version number 36 | for your project or firmware, change the values in your 'boards/' 37 | config file. 38 | -----------------------------------------------------------------------*/ 39 | #define CFG_CODEBASE_VERSION_MAJOR 0 40 | #define CFG_CODEBASE_VERSION_MINOR 1 41 | #define CFG_CODEBASE_VERSION_REVISION 0 42 | /*=========================================================================*/ 43 | 44 | 45 | /*========================================================================= 46 | FIRMWARE VERSION SETTINGS 47 | -----------------------------------------------------------------------*/ 48 | #define CFG_FIRMWARE_VERSION_MAJOR 0 49 | #define CFG_FIRMWARE_VERSION_MINOR 0 50 | #define CFG_FIRMWARE_VERSION_REVISION 0 51 | /*=========================================================================*/ 52 | 53 | 54 | /*========================================================================= 55 | DEBUG LEVEL 56 | ----------------------------------------------------------------------- 57 | 58 | CFG_DEBUG Level 3: Full debug output, any failed assert 59 | will produce a breakpoint for the 60 | debugger 61 | Level 2: ATTR_ALWAYS_INLINE is null, ASSERT 62 | has text 63 | Level 1: ATTR_ALWAYS_INLINE is an attribute, 64 | ASSERT has no text 65 | Level 0: No debug information generated 66 | 67 | -----------------------------------------------------------------------*/ 68 | #define CFG_DEBUG (1) 69 | 70 | #if (CFG_DEBUG > 3) || (CFG_DEBUG < 0) 71 | #error "CFG_DEBUG must be a value between 0 (no debug) and 3" 72 | #endif 73 | /*=========================================================================*/ 74 | 75 | 76 | /*========================================================================= 77 | GENERAL NRF51 PERIPHERAL SETTINGS 78 | ----------------------------------------------------------------------- 79 | 80 | CFG_SCHEDULER_ENABLE Set this to 'true' or 'false' depending on 81 | if you use the event scheduler or not 82 | 83 | -----------------------------------------------------------------------*/ 84 | #define CFG_SCHEDULER_ENABLE false 85 | 86 | /*------------------------------- GPIOTE ------------------------------*/ 87 | #define CFG_GPIOTE_MAX_USERS 1 /**< Maximum number of users of the GPIOTE handler. */ 88 | 89 | /*-------------------------------- TIMER ------------------------------*/ 90 | #define CFG_TIMER_PRESCALER 0 /**< Value of the RTC1 PRESCALER register. freq = (32768/(PRESCALER+1)) */ 91 | #define CFG_TIMER_MAX_INSTANCE 1 /**< Maximum number of simultaneously created timers. */ 92 | #define CFG_TIMER_OPERATION_QUEUE_SIZE 2 /**< Size of timer operation queues. */ 93 | /*=========================================================================*/ 94 | 95 | 96 | /*========================================================================= 97 | BTLE SETTINGS 98 | -----------------------------------------------------------------------*/ 99 | 100 | #define CFG_BLE_TX_POWER_LEVEL 0 /**< in dBm (Valid values are -40, -20, -16, -12, -8, -4, 0, 4) */ 101 | 102 | /*---------------------------- BOND MANAGER ---------------------------*/ 103 | #define CFG_BLE_BOND_FLASH_PAGE_BOND (BLE_FLASH_PAGE_END-1) /**< Flash page used for bond manager bonding information.*/ 104 | #define CFG_BLE_BOND_FLASH_PAGE_SYS_ATTR (BLE_FLASH_PAGE_END-3) /**< Flash page used for bond manager system attribute information. TODO check if we can use BLE_FLASH_PAGE_END-2*/ 105 | #define CFG_BLE_BOND_DELETE_BUTTON_NUM 0 /**< Button to press to delete bond details during init */ 106 | 107 | /*------------------------------ SECURITY -----------------------------*/ 108 | #define CFG_BLE_SEC_PARAM_MITM 0 /**< Man In The Middle protection not required. */ 109 | #define CFG_BLE_SEC_PARAM_IO_CAPABILITIES BLE_GAP_IO_CAPS_NONE /**< No I/O capabilities. */ 110 | #define CFG_BLE_SEC_PARAM_OOB 0 /**< Out Of Band data not available. */ 111 | #define CFG_BLE_SEC_PARAM_MIN_KEY_SIZE 7 /**< Minimum encryption key size. */ 112 | #define CFG_BLE_SEC_PARAM_MAX_KEY_SIZE 16 113 | 114 | /*--------------------------------- GAP -------------------------------*/ 115 | #define CFG_GAP_APPEARANCE GapAdvertisingData::GENERIC_TAG 116 | #define CFG_GAP_LOCAL_NAME "nRF5x" 117 | 118 | #define CFG_GAP_CONNECTION_MIN_INTERVAL_MS 50 /**< Minimum acceptable connection interval */ 119 | #define CFG_GAP_CONNECTION_MAX_INTERVAL_MS 500 /**< Maximum acceptable connection interval */ 120 | #define CFG_GAP_CONNECTION_SUPERVISION_TIMEOUT_MS 4000 /**< Connection supervisory timeout */ 121 | #define CFG_GAP_CONNECTION_SLAVE_LATENCY 0 /**< Slave Latency in number of connection events. */ 122 | 123 | #define CFG_GAP_ADV_INTERVAL_MS 25 /**< The advertising interval in miliseconds, should be multiply of 0.625 */ 124 | #define CFG_GAP_ADV_TIMEOUT_S 180 /**< The advertising timeout in units of seconds. */ 125 | /*=========================================================================*/ 126 | 127 | 128 | /*========================================================================= 129 | VALIDATION 130 | -----------------------------------------------------------------------*/ 131 | #if CFG_BLE_TX_POWER_LEVEL != -40 && CFG_BLE_TX_POWER_LEVEL != -20 && CFG_BLE_TX_POWER_LEVEL != -16 && CFG_BLE_TX_POWER_LEVEL != -12 && CFG_BLE_TX_POWER_LEVEL != -8 && CFG_BLE_TX_POWER_LEVEL != -4 && CFG_BLE_TX_POWER_LEVEL != 0 && CFG_BLE_TX_POWER_LEVEL != 4 132 | #error "CFG_BLE_TX_POWER_LEVEL must be -40, -20, -16, -12, -8, -4, 0 or 4" 133 | #endif 134 | /*=========================================================================*/ 135 | 136 | #endif /* _PROJECTCONFIG_H_ */ 137 | -------------------------------------------------------------------------------- /source/supress-warnings.cmake: -------------------------------------------------------------------------------- 1 | # Copyright 2015 ARM Limited 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | message("suppressing warnings from ble-nrf51822") 16 | 17 | if(CMAKE_C_COMPILER_ID STREQUAL "GNU") 18 | set_target_properties(ble-nrf51822 19 | PROPERTIES COMPILE_FLAGS "-Wno-sign-compare -Wno-unused-variable -Wno-unused-parameter -Wno-unused-function -Wno-missing-field-initializers" 20 | ) 21 | endif() 22 | --------------------------------------------------------------------------------