Nordic stack and drivers for the mbed BLE API. Version to work around build bug.

Dependents:   microbit_rubber_ducky microbit_mouse_BLE microbit_mouse_BLE_daybreak_version microbit_presenter

Fork of nRF51822 by Nordic Semiconductor

Committer:
rgrover1
Date:
Thu Nov 26 14:33:45 2015 +0000
Revision:
470:2c1d3b1fe249
Parent:
455:e33de7c4574c
Child:
471:945e53179855
Synchronized with git rev f8b3f134
Author: Andres Amaya Garcia
Post radio notification callback through minar

The ble-nrf51822 implementation of the BLE API generated callbacks for radio
notification events without using the minar scheduler and at very high
priority. This functionality is replaced by posting events through minar
when YOTTA_CFG_MBED_OS is defined. Note that minar could not be used directly
to post callbacks because radio notification events are handled at very high
priority, which caused a hard-fault when minar tries to enter a critical
section. Alternatively, a Timeout was used to post the callback in another
context with lower priority.

Who changed what in which revision?

UserRevisionLine numberNew contents of line
rgrover1 388:db85a09c27ef 1 /* mbed Microcontroller Library
rgrover1 388:db85a09c27ef 2 * Copyright (c) 2006-2013 ARM Limited
rgrover1 388:db85a09c27ef 3 *
rgrover1 388:db85a09c27ef 4 * Licensed under the Apache License, Version 2.0 (the "License");
rgrover1 388:db85a09c27ef 5 * you may not use this file except in compliance with the License.
rgrover1 388:db85a09c27ef 6 * You may obtain a copy of the License at
rgrover1 388:db85a09c27ef 7 *
rgrover1 388:db85a09c27ef 8 * http://www.apache.org/licenses/LICENSE-2.0
rgrover1 388:db85a09c27ef 9 *
rgrover1 388:db85a09c27ef 10 * Unless required by applicable law or agreed to in writing, software
rgrover1 388:db85a09c27ef 11 * distributed under the License is distributed on an "AS IS" BASIS,
rgrover1 388:db85a09c27ef 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
rgrover1 388:db85a09c27ef 13 * See the License for the specific language governing permissions and
rgrover1 388:db85a09c27ef 14 * limitations under the License.
rgrover1 388:db85a09c27ef 15 */
rgrover1 388:db85a09c27ef 16
rgrover1 388:db85a09c27ef 17 #ifndef __NRF5x_GAP_H__
rgrover1 388:db85a09c27ef 18 #define __NRF5x_GAP_H__
rgrover1 388:db85a09c27ef 19
rgrover1 388:db85a09c27ef 20 #include "mbed.h"
rgrover1 388:db85a09c27ef 21 #include "ble/blecommon.h"
rgrover1 388:db85a09c27ef 22 #include "ble.h"
rgrover1 388:db85a09c27ef 23 #include "ble/GapAdvertisingParams.h"
rgrover1 388:db85a09c27ef 24 #include "ble/GapAdvertisingData.h"
rgrover1 388:db85a09c27ef 25 #include "ble/Gap.h"
rgrover1 388:db85a09c27ef 26 #include "ble/GapScanningParams.h"
rgrover1 388:db85a09c27ef 27
rgrover1 388:db85a09c27ef 28 #include "nrf_soc.h"
rgrover1 388:db85a09c27ef 29 #include "ble_radio_notification.h"
rgrover1 388:db85a09c27ef 30 #include "btle_security.h"
rgrover1 388:db85a09c27ef 31
rgrover1 396:e5b0385fc6f1 32 void radioNotificationStaticCallback(bool param);
rgrover1 396:e5b0385fc6f1 33
rgrover1 388:db85a09c27ef 34 /**************************************************************************/
rgrover1 388:db85a09c27ef 35 /*!
rgrover1 388:db85a09c27ef 36 \brief
rgrover1 388:db85a09c27ef 37
rgrover1 388:db85a09c27ef 38 */
rgrover1 388:db85a09c27ef 39 /**************************************************************************/
rgrover1 388:db85a09c27ef 40 class nRF5xGap : public Gap
rgrover1 388:db85a09c27ef 41 {
rgrover1 388:db85a09c27ef 42 public:
rgrover1 388:db85a09c27ef 43 static nRF5xGap &getInstance();
rgrover1 388:db85a09c27ef 44
rgrover1 388:db85a09c27ef 45 /* Functions that must be implemented from Gap */
rgrover1 388:db85a09c27ef 46 virtual ble_error_t setAddress(AddressType_t type, const Address_t address);
rgrover1 388:db85a09c27ef 47 virtual ble_error_t getAddress(AddressType_t *typeP, Address_t address);
rgrover1 388:db85a09c27ef 48 virtual ble_error_t setAdvertisingData(const GapAdvertisingData &, const GapAdvertisingData &);
rgrover1 388:db85a09c27ef 49
rgrover1 405:665704963abb 50 virtual uint16_t getMinAdvertisingInterval(void) const {return GapAdvertisingParams::ADVERTISEMENT_DURATION_UNITS_TO_MS(BLE_GAP_ADV_INTERVAL_MIN);}
rgrover1 405:665704963abb 51 virtual uint16_t getMinNonConnectableAdvertisingInterval(void) const {return GapAdvertisingParams::ADVERTISEMENT_DURATION_UNITS_TO_MS(BLE_GAP_ADV_NONCON_INTERVAL_MIN);}
rgrover1 405:665704963abb 52 virtual uint16_t getMaxAdvertisingInterval(void) const {return GapAdvertisingParams::ADVERTISEMENT_DURATION_UNITS_TO_MS(BLE_GAP_ADV_INTERVAL_MAX);}
rgrover1 388:db85a09c27ef 53
rgrover1 388:db85a09c27ef 54 virtual ble_error_t startAdvertising(const GapAdvertisingParams &);
rgrover1 388:db85a09c27ef 55 virtual ble_error_t stopAdvertising(void);
rgrover1 388:db85a09c27ef 56 virtual ble_error_t connect(const Address_t, Gap::AddressType_t peerAddrType, const ConnectionParams_t *connectionParams, const GapScanningParams *scanParams);
rgrover1 388:db85a09c27ef 57 virtual ble_error_t disconnect(Handle_t connectionHandle, DisconnectionReason_t reason);
rgrover1 388:db85a09c27ef 58 virtual ble_error_t disconnect(DisconnectionReason_t reason);
rgrover1 388:db85a09c27ef 59
rgrover1 388:db85a09c27ef 60 virtual ble_error_t setDeviceName(const uint8_t *deviceName);
rgrover1 388:db85a09c27ef 61 virtual ble_error_t getDeviceName(uint8_t *deviceName, unsigned *lengthP);
rgrover1 388:db85a09c27ef 62 virtual ble_error_t setAppearance(GapAdvertisingData::Appearance appearance);
rgrover1 388:db85a09c27ef 63 virtual ble_error_t getAppearance(GapAdvertisingData::Appearance *appearanceP);
rgrover1 388:db85a09c27ef 64
rgrover1 388:db85a09c27ef 65 virtual ble_error_t setTxPower(int8_t txPower);
rgrover1 388:db85a09c27ef 66 virtual void getPermittedTxPowerValues(const int8_t **valueArrayPP, size_t *countP);
rgrover1 388:db85a09c27ef 67
rgrover1 388:db85a09c27ef 68 void setConnectionHandle(uint16_t con_handle);
rgrover1 388:db85a09c27ef 69 uint16_t getConnectionHandle(void);
rgrover1 388:db85a09c27ef 70
rgrover1 388:db85a09c27ef 71 virtual ble_error_t getPreferredConnectionParams(ConnectionParams_t *params);
rgrover1 388:db85a09c27ef 72 virtual ble_error_t setPreferredConnectionParams(const ConnectionParams_t *params);
rgrover1 388:db85a09c27ef 73 virtual ble_error_t updateConnectionParams(Handle_t handle, const ConnectionParams_t *params);
rgrover1 388:db85a09c27ef 74
rgrover1 396:e5b0385fc6f1 75 virtual ble_error_t initRadioNotification(void) {
rgrover1 396:e5b0385fc6f1 76 if (ble_radio_notification_init(NRF_APP_PRIORITY_HIGH, NRF_RADIO_NOTIFICATION_DISTANCE_800US, radioNotificationStaticCallback) == NRF_SUCCESS) {
rgrover1 396:e5b0385fc6f1 77 return BLE_ERROR_NONE;
rgrover1 396:e5b0385fc6f1 78 }
rgrover1 396:e5b0385fc6f1 79
rgrover1 396:e5b0385fc6f1 80 return BLE_ERROR_UNSPECIFIED;
rgrover1 388:db85a09c27ef 81 }
rgrover1 388:db85a09c27ef 82
rgrover1 430:db7edc9ad0bc 83 /* Observer role is not supported by S110, return BLE_ERROR_NOT_IMPLEMENTED */
rgrover1 455:e33de7c4574c 84 #if !defined(TARGET_MCU_NRF51_16K_S110) && !defined(TARGET_MCU_NRF51_32K_S110)
rgrover1 388:db85a09c27ef 85 virtual ble_error_t startRadioScan(const GapScanningParams &scanningParams) {
rgrover1 388:db85a09c27ef 86 ble_gap_scan_params_t scanParams = {
rgrover1 388:db85a09c27ef 87 .active = scanningParams.getActiveScanning(), /**< If 1, perform active scanning (scan requests). */
rgrover1 388:db85a09c27ef 88 .selective = 0, /**< If 1, ignore unknown devices (non whitelisted). */
rgrover1 388:db85a09c27ef 89 .p_whitelist = NULL, /**< Pointer to whitelist, NULL if none is given. */
rgrover1 388:db85a09c27ef 90 .interval = scanningParams.getInterval(), /**< Scan interval between 0x0004 and 0x4000 in 0.625ms units (2.5ms to 10.24s). */
rgrover1 388:db85a09c27ef 91 .window = scanningParams.getWindow(), /**< Scan window between 0x0004 and 0x4000 in 0.625ms units (2.5ms to 10.24s). */
rgrover1 388:db85a09c27ef 92 .timeout = scanningParams.getTimeout(), /**< Scan timeout between 0x0001 and 0xFFFF in seconds, 0x0000 disables timeout. */
rgrover1 388:db85a09c27ef 93 };
rgrover1 388:db85a09c27ef 94
rgrover1 388:db85a09c27ef 95 if (sd_ble_gap_scan_start(&scanParams) != NRF_SUCCESS) {
rgrover1 388:db85a09c27ef 96 return BLE_ERROR_PARAM_OUT_OF_RANGE;
rgrover1 388:db85a09c27ef 97 }
rgrover1 388:db85a09c27ef 98
rgrover1 388:db85a09c27ef 99 return BLE_ERROR_NONE;
rgrover1 388:db85a09c27ef 100 }
rgrover1 388:db85a09c27ef 101
rgrover1 388:db85a09c27ef 102 virtual ble_error_t stopScan(void) {
rgrover1 388:db85a09c27ef 103 if (sd_ble_gap_scan_stop() == NRF_SUCCESS) {
rgrover1 388:db85a09c27ef 104 return BLE_ERROR_NONE;
rgrover1 388:db85a09c27ef 105 }
rgrover1 388:db85a09c27ef 106
rgrover1 388:db85a09c27ef 107 return BLE_STACK_BUSY;
rgrover1 388:db85a09c27ef 108 }
rgrover1 430:db7edc9ad0bc 109 #endif
rgrover1 388:db85a09c27ef 110
rgrover1 388:db85a09c27ef 111 private:
rgrover1 470:2c1d3b1fe249 112 #ifdef YOTTA_CFG_MBED_OS
rgrover1 470:2c1d3b1fe249 113 /* Store the current radio notification value that will be used in the next callback */
rgrover1 470:2c1d3b1fe249 114 bool radioNotificationCallbackParam;
rgrover1 470:2c1d3b1fe249 115
rgrover1 470:2c1d3b1fe249 116 /*
rgrover1 470:2c1d3b1fe249 117 * In mbed OS, the idea is to post all callbacks through minar scheduler. However, the radio notifications
rgrover1 470:2c1d3b1fe249 118 * are handled in IRQs with very high priority. Trying to post a minar callback directly in
rgrover1 470:2c1d3b1fe249 119 * processRadioNotification() will result in a hard-fault. This is because minar asumes that all callbacks
rgrover1 470:2c1d3b1fe249 120 * are posted from low priority context, so when minar schedules the callback it attempts to enter a
rgrover1 470:2c1d3b1fe249 121 * critical section and disable all interrupts. The problem is that minar tries to do this by invoking the
rgrover1 470:2c1d3b1fe249 122 * SoftDevice with a call to sd_nvic_critical_region_enter() while already running in high priority. This
rgrover1 470:2c1d3b1fe249 123 * results in the SoftDevice generating a hard-fault.
rgrover1 470:2c1d3b1fe249 124 * A solution is to reduce the priority from which the callback is posted to minar. Unfortunately, there
rgrover1 470:2c1d3b1fe249 125 * are not clean ways to do this. The solution implemented uses a Timeout to call
rgrover1 470:2c1d3b1fe249 126 * postRadioNotificationCallback() after a very short delay (1 us) and post the minar callback there.
rgrover1 470:2c1d3b1fe249 127 *
rgrover1 470:2c1d3b1fe249 128 * !!!WARNING!!! Radio notifications are very time critical events. The current solution is expected to
rgrover1 470:2c1d3b1fe249 129 * work under the assumption that postRadioNotificationCalback() will be executed BEFORE the next radio
rgrover1 470:2c1d3b1fe249 130 * notification event is generated.
rgrover1 470:2c1d3b1fe249 131 */
rgrover1 470:2c1d3b1fe249 132 Timeout radioNotificationTimeout;
rgrover1 470:2c1d3b1fe249 133
rgrover1 470:2c1d3b1fe249 134 /*
rgrover1 470:2c1d3b1fe249 135 * A helper function to post radio notification callbacks through minar when using mbed OS.
rgrover1 470:2c1d3b1fe249 136 */
rgrover1 470:2c1d3b1fe249 137 void postRadioNotificationCallback(void) {
rgrover1 470:2c1d3b1fe249 138 minar::Scheduler::postCallback(
rgrover1 470:2c1d3b1fe249 139 mbed::util::FunctionPointer1<void, bool>(&radioNotificationCallback, &FunctionPointerWithContext<bool>::call).bind(radioNotificationCallbackParam)
rgrover1 470:2c1d3b1fe249 140 );
rgrover1 470:2c1d3b1fe249 141 }
rgrover1 470:2c1d3b1fe249 142 #endif
rgrover1 470:2c1d3b1fe249 143
rgrover1 396:e5b0385fc6f1 144 /**
rgrover1 396:e5b0385fc6f1 145 * A helper function to process radio-notification events; to be called internally.
rgrover1 396:e5b0385fc6f1 146 * @param param [description]
rgrover1 396:e5b0385fc6f1 147 */
rgrover1 396:e5b0385fc6f1 148 void processRadioNotificationEvent(bool param) {
rgrover1 470:2c1d3b1fe249 149 #ifdef YOTTA_CFG_MBED_OS
rgrover1 470:2c1d3b1fe249 150 /* When using mbed OS the callback to the user-defined function will be posted through minar */
rgrover1 470:2c1d3b1fe249 151 radioNotificationCallbackParam = param;
rgrover1 470:2c1d3b1fe249 152 radioNotificationTimeout.attach_us(this, &nRF5xGap::postRadioNotificationCallback, 0);
rgrover1 470:2c1d3b1fe249 153 #else
rgrover1 396:e5b0385fc6f1 154 radioNotificationCallback.call(param);
rgrover1 470:2c1d3b1fe249 155 #endif
rgrover1 396:e5b0385fc6f1 156 }
rgrover1 396:e5b0385fc6f1 157 friend void radioNotificationStaticCallback(bool param); /* allow invocations of processRadioNotificationEvent() */
rgrover1 396:e5b0385fc6f1 158
rgrover1 396:e5b0385fc6f1 159 private:
rgrover1 388:db85a09c27ef 160 uint16_t m_connectionHandle;
rgrover1 388:db85a09c27ef 161 nRF5xGap() {
rgrover1 388:db85a09c27ef 162 m_connectionHandle = BLE_CONN_HANDLE_INVALID;
rgrover1 388:db85a09c27ef 163 }
rgrover1 388:db85a09c27ef 164
rgrover1 388:db85a09c27ef 165 nRF5xGap(nRF5xGap const &);
rgrover1 388:db85a09c27ef 166 void operator=(nRF5xGap const &);
rgrover1 388:db85a09c27ef 167 };
rgrover1 388:db85a09c27ef 168
rgrover1 388:db85a09c27ef 169 #endif // ifndef __NRF5x_GAP_H__