No changes

Fork of nRF51822 by Nordic Semiconductor

Committer:
vcoubard
Date:
Mon Jan 11 10:19:15 2016 +0000
Revision:
561:613dbbdeed27
Parent:
550:bcb632fc92df
Child:
563:9c4b96f7be8d
Synchronized with git rev 7bf81e7e
Author: Andres Amaya Garcia
Improve shutdown to clear BLE API and not just SD

Improve the shutdown functionality, such that a call to ble.shutdown() from
the user application clears the API and nRF5x state and NOT only the
SoftDevice. To achieve this the following changes are introduced:

* Add a protected member cleanup() to nRF5xGap, nRF5xGattClient,
nRF5xGattServer, nRF5xSecurityManager and nRF5xServiceDiscovery.
* Modify the shutdown() implementation in nRF5xn such that it also calls the
static member shutdown() exposed by the BLE API in Gap.h, SecurityManager.h,
GattClient.h and GattServer.h.
* Modify nRF5xGattClient, nRF5xGattServer and nRF5xSecurityManager
classes so that they dynamically create their respective objects only if
needed. Previously the GattClient, GattServer and SecurityManager objects were
declared as static, which means that they were always present even though they
were not always needed. This increases memory consumption unnecessarily.
Furthermore, pointers to the object instances are stored in static members of
the classes as specified by the BLE API base classes. This ensures that
calls to shutdown do not require calls to getInstance() functions that would
otherwise result in undesired memory allocations.
* nRF5xGap object is always needed, so this remains allocated statically. But
the reference in Gap is pointed to this object.

The shutdown procedure is as follows:

1. The user calls ble.shutdown() which executes the code in nRF5xn::shutdown()
1. The SoftDevice is shutdown
1. The static members of Gap.h, SecurityManager.h, GattClient.h and
GattServer.h are called to clean up their own state.

If at any point an error occur during the last step, BLE_ERROR_INVALID_STATE is
returned.

Who changed what in which revision?

UserRevisionLine numberNew 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 static nRF5xGap &getInstance();
vcoubard 541:884f95bf5351 48
vcoubard 541:884f95bf5351 49 /* Functions that must be implemented from Gap */
vcoubard 541:884f95bf5351 50 virtual ble_error_t setAddress(AddressType_t type, const Address_t address);
vcoubard 541:884f95bf5351 51 virtual ble_error_t getAddress(AddressType_t *typeP, Address_t address);
vcoubard 541:884f95bf5351 52 virtual ble_error_t setAdvertisingData(const GapAdvertisingData &, const GapAdvertisingData &);
vcoubard 541:884f95bf5351 53
vcoubard 541:884f95bf5351 54 virtual uint16_t getMinAdvertisingInterval(void) const {return GapAdvertisingParams::ADVERTISEMENT_DURATION_UNITS_TO_MS(BLE_GAP_ADV_INTERVAL_MIN);}
vcoubard 541:884f95bf5351 55 virtual uint16_t getMinNonConnectableAdvertisingInterval(void) const {return GapAdvertisingParams::ADVERTISEMENT_DURATION_UNITS_TO_MS(BLE_GAP_ADV_NONCON_INTERVAL_MIN);}
vcoubard 541:884f95bf5351 56 virtual uint16_t getMaxAdvertisingInterval(void) const {return GapAdvertisingParams::ADVERTISEMENT_DURATION_UNITS_TO_MS(BLE_GAP_ADV_INTERVAL_MAX);}
vcoubard 541:884f95bf5351 57
vcoubard 541:884f95bf5351 58 virtual ble_error_t startAdvertising(const GapAdvertisingParams &);
vcoubard 541:884f95bf5351 59 virtual ble_error_t stopAdvertising(void);
vcoubard 541:884f95bf5351 60 virtual ble_error_t connect(const Address_t, Gap::AddressType_t peerAddrType, const ConnectionParams_t *connectionParams, const GapScanningParams *scanParams);
vcoubard 541:884f95bf5351 61 virtual ble_error_t disconnect(Handle_t connectionHandle, DisconnectionReason_t reason);
vcoubard 541:884f95bf5351 62 virtual ble_error_t disconnect(DisconnectionReason_t reason);
vcoubard 541:884f95bf5351 63
vcoubard 541:884f95bf5351 64 virtual ble_error_t setDeviceName(const uint8_t *deviceName);
vcoubard 541:884f95bf5351 65 virtual ble_error_t getDeviceName(uint8_t *deviceName, unsigned *lengthP);
vcoubard 541:884f95bf5351 66 virtual ble_error_t setAppearance(GapAdvertisingData::Appearance appearance);
vcoubard 541:884f95bf5351 67 virtual ble_error_t getAppearance(GapAdvertisingData::Appearance *appearanceP);
vcoubard 541:884f95bf5351 68
vcoubard 541:884f95bf5351 69 virtual ble_error_t setTxPower(int8_t txPower);
vcoubard 541:884f95bf5351 70 virtual void getPermittedTxPowerValues(const int8_t **valueArrayPP, size_t *countP);
vcoubard 541:884f95bf5351 71
vcoubard 541:884f95bf5351 72 void setConnectionHandle(uint16_t con_handle);
vcoubard 541:884f95bf5351 73 uint16_t getConnectionHandle(void);
vcoubard 541:884f95bf5351 74
vcoubard 541:884f95bf5351 75 virtual ble_error_t getPreferredConnectionParams(ConnectionParams_t *params);
vcoubard 541:884f95bf5351 76 virtual ble_error_t setPreferredConnectionParams(const ConnectionParams_t *params);
vcoubard 541:884f95bf5351 77 virtual ble_error_t updateConnectionParams(Handle_t handle, const ConnectionParams_t *params);
vcoubard 541:884f95bf5351 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 561:613dbbdeed27 115 protected:
vcoubard 561:613dbbdeed27 116 virtual ble_error_t cleanup(void);
vcoubard 561:613dbbdeed27 117
vcoubard 541:884f95bf5351 118 private:
vcoubard 546:1e147322b2b5 119 bool radioNotificationCallbackParam; /* parameter to be passed into the Timeout-generated radio notification callback. */
vcoubard 546:1e147322b2b5 120 Timeout radioNotificationTimeout;
vcoubard 546:1e147322b2b5 121
vcoubard 546:1e147322b2b5 122 /*
vcoubard 550:bcb632fc92df 123 * A helper function to post radio notification callbacks with low interrupt priority.
vcoubard 546:1e147322b2b5 124 */
vcoubard 546:1e147322b2b5 125 void postRadioNotificationCallback(void) {
vcoubard 550:bcb632fc92df 126 #ifdef YOTTA_CFG_MBED_OS
vcoubard 550:bcb632fc92df 127 /*
vcoubard 550:bcb632fc92df 128 * In mbed OS, all user-facing BLE events (interrupts) are posted to the
vcoubard 550:bcb632fc92df 129 * MINAR scheduler to be executed as callbacks in thread mode. MINAR guards
vcoubard 550:bcb632fc92df 130 * its critical sections from interrupts by acquiring CriticalSectionLock,
vcoubard 550:bcb632fc92df 131 * which results in a call to sd_nvic_critical_region_enter(). Thus, it is
vcoubard 550:bcb632fc92df 132 * safe to invoke MINAR APIs from interrupt context as long as those
vcoubard 550:bcb632fc92df 133 * interrupts are blocked by sd_nvic_critical_region_enter().
vcoubard 550:bcb632fc92df 134 *
vcoubard 550:bcb632fc92df 135 * Radio notifications are a special case for the above. The Radio
vcoubard 550:bcb632fc92df 136 * Notification IRQ is handled at a very high priority--higher than the
vcoubard 550:bcb632fc92df 137 * level blocked by sd_nvic_critical_region_enter(). Thus Radio Notification
vcoubard 550:bcb632fc92df 138 * events can preempt MINAR's critical sections. Using MINAR APIs (such as
vcoubard 550:bcb632fc92df 139 * posting an event) directly in processRadioNotification() may result in a
vcoubard 550:bcb632fc92df 140 * race condition ending in a hard-fault.
vcoubard 550:bcb632fc92df 141 *
vcoubard 550:bcb632fc92df 142 * The solution is to *not* call MINAR APIs directly from the Radio
vcoubard 550:bcb632fc92df 143 * Notification handling; i.e. to do the bulk of RadioNotification
vcoubard 550:bcb632fc92df 144 * processing at a reduced priority which respects MINAR's critical
vcoubard 550:bcb632fc92df 145 * sections. Unfortunately, on a cortex-M0, there is no clean way to demote
vcoubard 550:bcb632fc92df 146 * priority for the currently executing interrupt--we wouldn't want to
vcoubard 550:bcb632fc92df 147 * demote the radio notification handling anyway because it is sensitive to
vcoubard 550:bcb632fc92df 148 * timing, and the system expects to finish this handling very quickly. The
vcoubard 550:bcb632fc92df 149 * workaround is to employ a Timeout to trigger
vcoubard 550:bcb632fc92df 150 * postRadioNotificationCallback() after a very short delay (~0 us) and post
vcoubard 550:bcb632fc92df 151 * the MINAR callback that context.
vcoubard 550:bcb632fc92df 152 *
vcoubard 550:bcb632fc92df 153 * !!!WARNING!!! Radio notifications are very time critical events. The
vcoubard 550:bcb632fc92df 154 * current solution is expected to work under the assumption that
vcoubard 550:bcb632fc92df 155 * postRadioNotificationCalback() will be executed BEFORE the next radio
vcoubard 550:bcb632fc92df 156 * notification event is generated.
vcoubard 550:bcb632fc92df 157 */
vcoubard 546:1e147322b2b5 158 minar::Scheduler::postCallback(
vcoubard 546:1e147322b2b5 159 mbed::util::FunctionPointer1<void, bool>(&radioNotificationCallback, &FunctionPointerWithContext<bool>::call).bind(radioNotificationCallbackParam)
vcoubard 546:1e147322b2b5 160 );
vcoubard 550:bcb632fc92df 161 #else
vcoubard 550:bcb632fc92df 162 /*
vcoubard 550:bcb632fc92df 163 * In mbed classic, all user-facing BLE events execute callbacks in interrupt
vcoubard 550:bcb632fc92df 164 * mode. Radio Notifications are a special case because its IRQ is handled at
vcoubard 550:bcb632fc92df 165 * a very high priority. Thus Radio Notification events can preempt other
vcoubard 550:bcb632fc92df 166 * operations that require interaction with the SoftDevice such as advertising
vcoubard 550:bcb632fc92df 167 * payload updates and changing the Gap state. Therefore, executing a Radio
vcoubard 550:bcb632fc92df 168 * Notification callback directly from processRadioNotification() may result
vcoubard 550:bcb632fc92df 169 * in a race condition ending in a hard-fault.
vcoubard 550:bcb632fc92df 170 *
vcoubard 550:bcb632fc92df 171 * The solution is to *not* execute the Radio Notification callback directly
vcoubard 550:bcb632fc92df 172 * from the Radio Notification handling; i.e. to do the bulk of the
vcoubard 550:bcb632fc92df 173 * Radio Notification processing at a reduced priority. Unfortunately, on a
vcoubard 550:bcb632fc92df 174 * cortex-M0, there is no clean way to demote priority for the currently
vcoubard 550:bcb632fc92df 175 * executing interrupt--we wouldn't want to demote the radio notification
vcoubard 550:bcb632fc92df 176 * handling anyway because it is sensitive to timing, and the system expects
vcoubard 550:bcb632fc92df 177 * to finish this handling very quickly. The workaround is to employ a Timeout
vcoubard 550:bcb632fc92df 178 * to trigger postRadioNotificationCallback() after a very short delay (~0 us)
vcoubard 550:bcb632fc92df 179 * and execute the callback in that context.
vcoubard 550:bcb632fc92df 180 *
vcoubard 550:bcb632fc92df 181 * !!!WARNING!!! Radio notifications are very time critical events. The
vcoubard 550:bcb632fc92df 182 * current solution is expected to work under the assumption that
vcoubard 550:bcb632fc92df 183 * postRadioNotificationCalback() will be executed BEFORE the next radio
vcoubard 550:bcb632fc92df 184 * notification event is generated.
vcoubard 550:bcb632fc92df 185 */
vcoubard 550:bcb632fc92df 186 radioNotificationCallback.call(radioNotificationCallbackParam);
vcoubard 550:bcb632fc92df 187 #endif /* #ifdef YOTTA_CFG_MBED_OS */
vcoubard 546:1e147322b2b5 188 }
vcoubard 546:1e147322b2b5 189
vcoubard 541:884f95bf5351 190 /**
vcoubard 541:884f95bf5351 191 * A helper function to process radio-notification events; to be called internally.
vcoubard 541:884f95bf5351 192 * @param param [description]
vcoubard 541:884f95bf5351 193 */
vcoubard 541:884f95bf5351 194 void processRadioNotificationEvent(bool param) {
vcoubard 546:1e147322b2b5 195 radioNotificationCallbackParam = param;
vcoubard 546:1e147322b2b5 196 radioNotificationTimeout.attach_us(this, &nRF5xGap::postRadioNotificationCallback, 0);
vcoubard 541:884f95bf5351 197 }
vcoubard 541:884f95bf5351 198 friend void radioNotificationStaticCallback(bool param); /* allow invocations of processRadioNotificationEvent() */
vcoubard 541:884f95bf5351 199
vcoubard 541:884f95bf5351 200 private:
vcoubard 541:884f95bf5351 201 uint16_t m_connectionHandle;
vcoubard 541:884f95bf5351 202 nRF5xGap() {
vcoubard 541:884f95bf5351 203 m_connectionHandle = BLE_CONN_HANDLE_INVALID;
vcoubard 541:884f95bf5351 204 }
vcoubard 541:884f95bf5351 205
vcoubard 541:884f95bf5351 206 nRF5xGap(nRF5xGap const &);
vcoubard 541:884f95bf5351 207 void operator=(nRF5xGap const &);
vcoubard 541:884f95bf5351 208 };
vcoubard 541:884f95bf5351 209
rgrover1 388:db85a09c27ef 210 #endif // ifndef __NRF5x_GAP_H__