No changes
Fork of nRF51822 by
source/nRF5xGap.h@565:cf03471a4ec4, 2016-01-11 (annotated)
- Committer:
- vcoubard
- Date:
- Mon Jan 11 10:19:18 2016 +0000
- Revision:
- 565:cf03471a4ec4
- Parent:
- 563:9c4b96f7be8d
- Child:
- 566:e425ad9e5d6e
Synchronized with git rev 0bcc2e96
Author: Andres Amaya Garcia
Modify shutdown due to BLE API change
The module is updated to comply with the changes to BLE API regarding correct
shutdown functionality. The following changes are introduced to ble-nrf51822:
* Calls to the old static function shutdown in Gap, GattClient, GattServer and
SecurityManager are removed.
* The cleanup function in Gap, GattClient, GattServer and SecurityManager is
renamed to `reset()` and made public.
* The static references inside nRF5xGap, nRF5xGattClient, nRF5xGattServer and
nRF5xSecurityManager to objects of their own class are moved to nRF5xn.
* The static getInstance accessors in nRF5xGap, nRF5xGattClient,
nRF5xGattServer and nRF5xSecurityManager are removed and their functionality is
moved to the implemented virtual accessors in nRF5xn i.e. getGap(),
getGattClient, etc.
* A static function Instance is added to nRF5xn class to make the transport
object accessible across the module.
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
vcoubard | 541:884f95bf5351 | 1 | /* mbed Microcontroller Library |
vcoubard | 541:884f95bf5351 | 2 | * Copyright (c) 2006-2013 ARM Limited |
vcoubard | 541:884f95bf5351 | 3 | * |
vcoubard | 541:884f95bf5351 | 4 | * Licensed under the Apache License, Version 2.0 (the "License"); |
vcoubard | 541:884f95bf5351 | 5 | * you may not use this file except in compliance with the License. |
vcoubard | 541:884f95bf5351 | 6 | * You may obtain a copy of the License at |
vcoubard | 541:884f95bf5351 | 7 | * |
vcoubard | 541:884f95bf5351 | 8 | * http://www.apache.org/licenses/LICENSE-2.0 |
vcoubard | 541:884f95bf5351 | 9 | * |
vcoubard | 541:884f95bf5351 | 10 | * Unless required by applicable law or agreed to in writing, software |
vcoubard | 541:884f95bf5351 | 11 | * distributed under the License is distributed on an "AS IS" BASIS, |
vcoubard | 541:884f95bf5351 | 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
vcoubard | 541:884f95bf5351 | 13 | * See the License for the specific language governing permissions and |
vcoubard | 541:884f95bf5351 | 14 | * limitations under the License. |
vcoubard | 541:884f95bf5351 | 15 | */ |
vcoubard | 541:884f95bf5351 | 16 | |
vcoubard | 541:884f95bf5351 | 17 | #ifndef __NRF5x_GAP_H__ |
vcoubard | 541:884f95bf5351 | 18 | #define __NRF5x_GAP_H__ |
vcoubard | 541:884f95bf5351 | 19 | |
vcoubard | 541:884f95bf5351 | 20 | #include "mbed.h" |
vcoubard | 541:884f95bf5351 | 21 | #include "ble/blecommon.h" |
vcoubard | 541:884f95bf5351 | 22 | #include "ble.h" |
vcoubard | 541:884f95bf5351 | 23 | #include "ble/GapAdvertisingParams.h" |
vcoubard | 541:884f95bf5351 | 24 | #include "ble/GapAdvertisingData.h" |
vcoubard | 541:884f95bf5351 | 25 | #include "ble/Gap.h" |
vcoubard | 541:884f95bf5351 | 26 | #include "ble/GapScanningParams.h" |
vcoubard | 541:884f95bf5351 | 27 | |
vcoubard | 541:884f95bf5351 | 28 | #include "nrf_soc.h" |
vcoubard | 549:3f782c64d014 | 29 | |
vcoubard | 549:3f782c64d014 | 30 | extern "C" { |
vcoubard | 541:884f95bf5351 | 31 | #include "ble_radio_notification.h" |
vcoubard | 549:3f782c64d014 | 32 | } |
vcoubard | 549:3f782c64d014 | 33 | |
vcoubard | 541:884f95bf5351 | 34 | #include "btle_security.h" |
vcoubard | 541:884f95bf5351 | 35 | |
vcoubard | 541:884f95bf5351 | 36 | void radioNotificationStaticCallback(bool param); |
vcoubard | 541:884f95bf5351 | 37 | |
vcoubard | 541:884f95bf5351 | 38 | /**************************************************************************/ |
vcoubard | 541:884f95bf5351 | 39 | /*! |
vcoubard | 541:884f95bf5351 | 40 | \brief |
vcoubard | 541:884f95bf5351 | 41 | |
vcoubard | 541:884f95bf5351 | 42 | */ |
vcoubard | 541:884f95bf5351 | 43 | /**************************************************************************/ |
vcoubard | 541:884f95bf5351 | 44 | class nRF5xGap : public Gap |
vcoubard | 541:884f95bf5351 | 45 | { |
vcoubard | 541:884f95bf5351 | 46 | public: |
vcoubard | 541:884f95bf5351 | 47 | /* Functions that must be implemented from Gap */ |
vcoubard | 541:884f95bf5351 | 48 | virtual ble_error_t setAddress(AddressType_t type, const Address_t address); |
vcoubard | 541:884f95bf5351 | 49 | virtual ble_error_t getAddress(AddressType_t *typeP, Address_t address); |
vcoubard | 541:884f95bf5351 | 50 | virtual ble_error_t setAdvertisingData(const GapAdvertisingData &, const GapAdvertisingData &); |
vcoubard | 541:884f95bf5351 | 51 | |
vcoubard | 541:884f95bf5351 | 52 | virtual uint16_t getMinAdvertisingInterval(void) const {return GapAdvertisingParams::ADVERTISEMENT_DURATION_UNITS_TO_MS(BLE_GAP_ADV_INTERVAL_MIN);} |
vcoubard | 541:884f95bf5351 | 53 | virtual uint16_t getMinNonConnectableAdvertisingInterval(void) const {return GapAdvertisingParams::ADVERTISEMENT_DURATION_UNITS_TO_MS(BLE_GAP_ADV_NONCON_INTERVAL_MIN);} |
vcoubard | 541:884f95bf5351 | 54 | virtual uint16_t getMaxAdvertisingInterval(void) const {return GapAdvertisingParams::ADVERTISEMENT_DURATION_UNITS_TO_MS(BLE_GAP_ADV_INTERVAL_MAX);} |
vcoubard | 541:884f95bf5351 | 55 | |
vcoubard | 541:884f95bf5351 | 56 | virtual ble_error_t startAdvertising(const GapAdvertisingParams &); |
vcoubard | 541:884f95bf5351 | 57 | virtual ble_error_t stopAdvertising(void); |
vcoubard | 541:884f95bf5351 | 58 | virtual ble_error_t connect(const Address_t, Gap::AddressType_t peerAddrType, const ConnectionParams_t *connectionParams, const GapScanningParams *scanParams); |
vcoubard | 541:884f95bf5351 | 59 | virtual ble_error_t disconnect(Handle_t connectionHandle, DisconnectionReason_t reason); |
vcoubard | 541:884f95bf5351 | 60 | virtual ble_error_t disconnect(DisconnectionReason_t reason); |
vcoubard | 541:884f95bf5351 | 61 | |
vcoubard | 541:884f95bf5351 | 62 | virtual ble_error_t setDeviceName(const uint8_t *deviceName); |
vcoubard | 541:884f95bf5351 | 63 | virtual ble_error_t getDeviceName(uint8_t *deviceName, unsigned *lengthP); |
vcoubard | 541:884f95bf5351 | 64 | virtual ble_error_t setAppearance(GapAdvertisingData::Appearance appearance); |
vcoubard | 541:884f95bf5351 | 65 | virtual ble_error_t getAppearance(GapAdvertisingData::Appearance *appearanceP); |
vcoubard | 541:884f95bf5351 | 66 | |
vcoubard | 541:884f95bf5351 | 67 | virtual ble_error_t setTxPower(int8_t txPower); |
vcoubard | 541:884f95bf5351 | 68 | virtual void getPermittedTxPowerValues(const int8_t **valueArrayPP, size_t *countP); |
vcoubard | 541:884f95bf5351 | 69 | |
vcoubard | 541:884f95bf5351 | 70 | void setConnectionHandle(uint16_t con_handle); |
vcoubard | 541:884f95bf5351 | 71 | uint16_t getConnectionHandle(void); |
vcoubard | 541:884f95bf5351 | 72 | |
vcoubard | 541:884f95bf5351 | 73 | virtual ble_error_t getPreferredConnectionParams(ConnectionParams_t *params); |
vcoubard | 541:884f95bf5351 | 74 | virtual ble_error_t setPreferredConnectionParams(const ConnectionParams_t *params); |
vcoubard | 541:884f95bf5351 | 75 | virtual ble_error_t updateConnectionParams(Handle_t handle, const ConnectionParams_t *params); |
vcoubard | 541:884f95bf5351 | 76 | |
vcoubard | 565:cf03471a4ec4 | 77 | virtual ble_error_t reset(void); |
vcoubard | 565:cf03471a4ec4 | 78 | |
vcoubard | 541:884f95bf5351 | 79 | virtual ble_error_t initRadioNotification(void) { |
vcoubard | 541:884f95bf5351 | 80 | if (ble_radio_notification_init(NRF_APP_PRIORITY_HIGH, NRF_RADIO_NOTIFICATION_DISTANCE_800US, radioNotificationStaticCallback) == NRF_SUCCESS) { |
vcoubard | 541:884f95bf5351 | 81 | return BLE_ERROR_NONE; |
vcoubard | 541:884f95bf5351 | 82 | } |
vcoubard | 541:884f95bf5351 | 83 | |
vcoubard | 541:884f95bf5351 | 84 | return BLE_ERROR_UNSPECIFIED; |
vcoubard | 541:884f95bf5351 | 85 | } |
vcoubard | 541:884f95bf5351 | 86 | |
vcoubard | 541:884f95bf5351 | 87 | /* Observer role is not supported by S110, return BLE_ERROR_NOT_IMPLEMENTED */ |
vcoubard | 541:884f95bf5351 | 88 | #if !defined(TARGET_MCU_NRF51_16K_S110) && !defined(TARGET_MCU_NRF51_32K_S110) |
vcoubard | 541:884f95bf5351 | 89 | virtual ble_error_t startRadioScan(const GapScanningParams &scanningParams) { |
vcoubard | 541:884f95bf5351 | 90 | ble_gap_scan_params_t scanParams = { |
vcoubard | 541:884f95bf5351 | 91 | .active = scanningParams.getActiveScanning(), /**< If 1, perform active scanning (scan requests). */ |
vcoubard | 541:884f95bf5351 | 92 | .selective = 0, /**< If 1, ignore unknown devices (non whitelisted). */ |
vcoubard | 541:884f95bf5351 | 93 | .p_whitelist = NULL, /**< Pointer to whitelist, NULL if none is given. */ |
vcoubard | 541:884f95bf5351 | 94 | .interval = scanningParams.getInterval(), /**< Scan interval between 0x0004 and 0x4000 in 0.625ms units (2.5ms to 10.24s). */ |
vcoubard | 541:884f95bf5351 | 95 | .window = scanningParams.getWindow(), /**< Scan window between 0x0004 and 0x4000 in 0.625ms units (2.5ms to 10.24s). */ |
vcoubard | 541:884f95bf5351 | 96 | .timeout = scanningParams.getTimeout(), /**< Scan timeout between 0x0001 and 0xFFFF in seconds, 0x0000 disables timeout. */ |
vcoubard | 541:884f95bf5351 | 97 | }; |
vcoubard | 541:884f95bf5351 | 98 | |
vcoubard | 541:884f95bf5351 | 99 | if (sd_ble_gap_scan_start(&scanParams) != NRF_SUCCESS) { |
vcoubard | 541:884f95bf5351 | 100 | return BLE_ERROR_PARAM_OUT_OF_RANGE; |
vcoubard | 541:884f95bf5351 | 101 | } |
vcoubard | 541:884f95bf5351 | 102 | |
vcoubard | 541:884f95bf5351 | 103 | return BLE_ERROR_NONE; |
vcoubard | 541:884f95bf5351 | 104 | } |
vcoubard | 541:884f95bf5351 | 105 | |
vcoubard | 541:884f95bf5351 | 106 | virtual ble_error_t stopScan(void) { |
vcoubard | 541:884f95bf5351 | 107 | if (sd_ble_gap_scan_stop() == NRF_SUCCESS) { |
vcoubard | 541:884f95bf5351 | 108 | return BLE_ERROR_NONE; |
vcoubard | 541:884f95bf5351 | 109 | } |
vcoubard | 541:884f95bf5351 | 110 | |
vcoubard | 541:884f95bf5351 | 111 | return BLE_STACK_BUSY; |
vcoubard | 541:884f95bf5351 | 112 | } |
vcoubard | 541:884f95bf5351 | 113 | #endif |
vcoubard | 541:884f95bf5351 | 114 | |
vcoubard | 541:884f95bf5351 | 115 | private: |
vcoubard | 546:1e147322b2b5 | 116 | bool radioNotificationCallbackParam; /* parameter to be passed into the Timeout-generated radio notification callback. */ |
vcoubard | 546:1e147322b2b5 | 117 | Timeout radioNotificationTimeout; |
vcoubard | 546:1e147322b2b5 | 118 | |
vcoubard | 546:1e147322b2b5 | 119 | /* |
vcoubard | 550:bcb632fc92df | 120 | * A helper function to post radio notification callbacks with low interrupt priority. |
vcoubard | 546:1e147322b2b5 | 121 | */ |
vcoubard | 546:1e147322b2b5 | 122 | void postRadioNotificationCallback(void) { |
vcoubard | 550:bcb632fc92df | 123 | #ifdef YOTTA_CFG_MBED_OS |
vcoubard | 550:bcb632fc92df | 124 | /* |
vcoubard | 550:bcb632fc92df | 125 | * In mbed OS, all user-facing BLE events (interrupts) are posted to the |
vcoubard | 550:bcb632fc92df | 126 | * MINAR scheduler to be executed as callbacks in thread mode. MINAR guards |
vcoubard | 550:bcb632fc92df | 127 | * its critical sections from interrupts by acquiring CriticalSectionLock, |
vcoubard | 550:bcb632fc92df | 128 | * which results in a call to sd_nvic_critical_region_enter(). Thus, it is |
vcoubard | 550:bcb632fc92df | 129 | * safe to invoke MINAR APIs from interrupt context as long as those |
vcoubard | 550:bcb632fc92df | 130 | * interrupts are blocked by sd_nvic_critical_region_enter(). |
vcoubard | 550:bcb632fc92df | 131 | * |
vcoubard | 550:bcb632fc92df | 132 | * Radio notifications are a special case for the above. The Radio |
vcoubard | 550:bcb632fc92df | 133 | * Notification IRQ is handled at a very high priority--higher than the |
vcoubard | 550:bcb632fc92df | 134 | * level blocked by sd_nvic_critical_region_enter(). Thus Radio Notification |
vcoubard | 550:bcb632fc92df | 135 | * events can preempt MINAR's critical sections. Using MINAR APIs (such as |
vcoubard | 550:bcb632fc92df | 136 | * posting an event) directly in processRadioNotification() may result in a |
vcoubard | 550:bcb632fc92df | 137 | * race condition ending in a hard-fault. |
vcoubard | 550:bcb632fc92df | 138 | * |
vcoubard | 550:bcb632fc92df | 139 | * The solution is to *not* call MINAR APIs directly from the Radio |
vcoubard | 550:bcb632fc92df | 140 | * Notification handling; i.e. to do the bulk of RadioNotification |
vcoubard | 550:bcb632fc92df | 141 | * processing at a reduced priority which respects MINAR's critical |
vcoubard | 550:bcb632fc92df | 142 | * sections. Unfortunately, on a cortex-M0, there is no clean way to demote |
vcoubard | 550:bcb632fc92df | 143 | * priority for the currently executing interrupt--we wouldn't want to |
vcoubard | 550:bcb632fc92df | 144 | * demote the radio notification handling anyway because it is sensitive to |
vcoubard | 550:bcb632fc92df | 145 | * timing, and the system expects to finish this handling very quickly. The |
vcoubard | 550:bcb632fc92df | 146 | * workaround is to employ a Timeout to trigger |
vcoubard | 550:bcb632fc92df | 147 | * postRadioNotificationCallback() after a very short delay (~0 us) and post |
vcoubard | 550:bcb632fc92df | 148 | * the MINAR callback that context. |
vcoubard | 550:bcb632fc92df | 149 | * |
vcoubard | 550:bcb632fc92df | 150 | * !!!WARNING!!! Radio notifications are very time critical events. The |
vcoubard | 550:bcb632fc92df | 151 | * current solution is expected to work under the assumption that |
vcoubard | 550:bcb632fc92df | 152 | * postRadioNotificationCalback() will be executed BEFORE the next radio |
vcoubard | 550:bcb632fc92df | 153 | * notification event is generated. |
vcoubard | 550:bcb632fc92df | 154 | */ |
vcoubard | 546:1e147322b2b5 | 155 | minar::Scheduler::postCallback( |
vcoubard | 546:1e147322b2b5 | 156 | mbed::util::FunctionPointer1<void, bool>(&radioNotificationCallback, &FunctionPointerWithContext<bool>::call).bind(radioNotificationCallbackParam) |
vcoubard | 546:1e147322b2b5 | 157 | ); |
vcoubard | 550:bcb632fc92df | 158 | #else |
vcoubard | 550:bcb632fc92df | 159 | /* |
vcoubard | 550:bcb632fc92df | 160 | * In mbed classic, all user-facing BLE events execute callbacks in interrupt |
vcoubard | 550:bcb632fc92df | 161 | * mode. Radio Notifications are a special case because its IRQ is handled at |
vcoubard | 550:bcb632fc92df | 162 | * a very high priority. Thus Radio Notification events can preempt other |
vcoubard | 550:bcb632fc92df | 163 | * operations that require interaction with the SoftDevice such as advertising |
vcoubard | 550:bcb632fc92df | 164 | * payload updates and changing the Gap state. Therefore, executing a Radio |
vcoubard | 550:bcb632fc92df | 165 | * Notification callback directly from processRadioNotification() may result |
vcoubard | 550:bcb632fc92df | 166 | * in a race condition ending in a hard-fault. |
vcoubard | 550:bcb632fc92df | 167 | * |
vcoubard | 550:bcb632fc92df | 168 | * The solution is to *not* execute the Radio Notification callback directly |
vcoubard | 550:bcb632fc92df | 169 | * from the Radio Notification handling; i.e. to do the bulk of the |
vcoubard | 550:bcb632fc92df | 170 | * Radio Notification processing at a reduced priority. Unfortunately, on a |
vcoubard | 550:bcb632fc92df | 171 | * cortex-M0, there is no clean way to demote priority for the currently |
vcoubard | 550:bcb632fc92df | 172 | * executing interrupt--we wouldn't want to demote the radio notification |
vcoubard | 550:bcb632fc92df | 173 | * handling anyway because it is sensitive to timing, and the system expects |
vcoubard | 550:bcb632fc92df | 174 | * to finish this handling very quickly. The workaround is to employ a Timeout |
vcoubard | 550:bcb632fc92df | 175 | * to trigger postRadioNotificationCallback() after a very short delay (~0 us) |
vcoubard | 550:bcb632fc92df | 176 | * and execute the callback in that context. |
vcoubard | 550:bcb632fc92df | 177 | * |
vcoubard | 550:bcb632fc92df | 178 | * !!!WARNING!!! Radio notifications are very time critical events. The |
vcoubard | 550:bcb632fc92df | 179 | * current solution is expected to work under the assumption that |
vcoubard | 550:bcb632fc92df | 180 | * postRadioNotificationCalback() will be executed BEFORE the next radio |
vcoubard | 550:bcb632fc92df | 181 | * notification event is generated. |
vcoubard | 550:bcb632fc92df | 182 | */ |
vcoubard | 550:bcb632fc92df | 183 | radioNotificationCallback.call(radioNotificationCallbackParam); |
vcoubard | 550:bcb632fc92df | 184 | #endif /* #ifdef YOTTA_CFG_MBED_OS */ |
vcoubard | 546:1e147322b2b5 | 185 | } |
vcoubard | 546:1e147322b2b5 | 186 | |
vcoubard | 541:884f95bf5351 | 187 | /** |
vcoubard | 541:884f95bf5351 | 188 | * A helper function to process radio-notification events; to be called internally. |
vcoubard | 541:884f95bf5351 | 189 | * @param param [description] |
vcoubard | 541:884f95bf5351 | 190 | */ |
vcoubard | 541:884f95bf5351 | 191 | void processRadioNotificationEvent(bool param) { |
vcoubard | 546:1e147322b2b5 | 192 | radioNotificationCallbackParam = param; |
vcoubard | 546:1e147322b2b5 | 193 | radioNotificationTimeout.attach_us(this, &nRF5xGap::postRadioNotificationCallback, 0); |
vcoubard | 541:884f95bf5351 | 194 | } |
vcoubard | 541:884f95bf5351 | 195 | friend void radioNotificationStaticCallback(bool param); /* allow invocations of processRadioNotificationEvent() */ |
vcoubard | 541:884f95bf5351 | 196 | |
vcoubard | 541:884f95bf5351 | 197 | private: |
vcoubard | 541:884f95bf5351 | 198 | uint16_t m_connectionHandle; |
vcoubard | 565:cf03471a4ec4 | 199 | |
vcoubard | 565:cf03471a4ec4 | 200 | /* |
vcoubard | 565:cf03471a4ec4 | 201 | * Allow instantiation from nRF5xn when required. |
vcoubard | 565:cf03471a4ec4 | 202 | */ |
vcoubard | 565:cf03471a4ec4 | 203 | friend class nRF5xn; |
vcoubard | 565:cf03471a4ec4 | 204 | |
vcoubard | 541:884f95bf5351 | 205 | nRF5xGap() { |
vcoubard | 541:884f95bf5351 | 206 | m_connectionHandle = BLE_CONN_HANDLE_INVALID; |
vcoubard | 541:884f95bf5351 | 207 | } |
vcoubard | 541:884f95bf5351 | 208 | |
vcoubard | 541:884f95bf5351 | 209 | nRF5xGap(nRF5xGap const &); |
vcoubard | 541:884f95bf5351 | 210 | void operator=(nRF5xGap const &); |
vcoubard | 541:884f95bf5351 | 211 | }; |
vcoubard | 541:884f95bf5351 | 212 | |
rgrover1 | 388:db85a09c27ef | 213 | #endif // ifndef __NRF5x_GAP_H__ |