library for BLE_GAP_backpack

Dependencies:   nrf51-sdk

Fork of nRF51822 by Nordic Semiconductor

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers nRF5xGap.h Source File

nRF5xGap.h

00001 /* mbed Microcontroller Library
00002  * Copyright (c) 2006-2013 ARM Limited
00003  *
00004  * Licensed under the Apache License, Version 2.0 (the "License");
00005  * you may not use this file except in compliance with the License.
00006  * You may obtain a copy of the License at
00007  *
00008  *     http://www.apache.org/licenses/LICENSE-2.0
00009  *
00010  * Unless required by applicable law or agreed to in writing, software
00011  * distributed under the License is distributed on an "AS IS" BASIS,
00012  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00013  * See the License for the specific language governing permissions and
00014  * limitations under the License.
00015  */
00016 
00017 #ifndef __NRF5x_GAP_H__
00018 #define __NRF5x_GAP_H__
00019 
00020 #ifdef YOTTA_CFG_MBED_OS
00021     #include "mbed-drivers/mbed.h"
00022 #else
00023     #include "mbed.h"
00024 #endif
00025 #ifndef YOTTA_CFG_WHITELIST_MAX_SIZE
00026     #define YOTTA_CFG_WHITELIST_MAX_SIZE BLE_GAP_WHITELIST_ADDR_MAX_COUNT
00027 #elif YOTTA_CFG_WHITELIST_MAX_SIZE > BLE_GAP_WHITELIST_ADDR_MAX_COUNT
00028     #undef YOTTA_CFG_WHITELIST_MAX_SIZE
00029     #define YOTTA_CFG_WHITELIST_MAX_SIZE BLE_GAP_WHITELIST_ADDR_MAX_COUNT
00030 #endif
00031 #ifndef YOTTA_CFG_IRK_TABLE_MAX_SIZE
00032     #define YOTTA_CFG_IRK_TABLE_MAX_SIZE BLE_GAP_WHITELIST_IRK_MAX_COUNT
00033 #elif YOTTA_CFG_IRK_TABLE_MAX_SIZE > BLE_GAP_WHITELIST_IRK_MAX_COUNT
00034     #undef YOTTA_CFG_IRK_TABLE_MAX_SIZE
00035     #define YOTTA_CFG_IRK_TABLE_MAX_SIZE BLE_GAP_WHITELIST_IRK_MAX_COUNT
00036 #endif
00037 #include "ble/blecommon.h"
00038 #include "nrf_ble.h"
00039 #include "ble/GapAdvertisingParams.h"
00040 #include "ble/GapAdvertisingData.h"
00041 #include "ble/Gap.h"
00042 #include "ble/GapScanningParams.h"
00043 
00044 #include "nrf_soc.h"
00045 
00046 extern "C" {
00047 #include "ble_radio_notification.h"
00048 }
00049 
00050 #include "btle_security.h"
00051 
00052 void radioNotificationStaticCallback(bool param);
00053 
00054 /**************************************************************************/
00055 /*!
00056     \brief
00057 
00058 */
00059 /**************************************************************************/
00060 class nRF5xGap : public Gap
00061 {
00062 public:
00063     /* Functions that must be implemented from Gap */
00064     virtual ble_error_t setAddress(AddressType_t  type,  const Address_t address);
00065     virtual ble_error_t getAddress(AddressType_t *typeP, Address_t address);
00066     virtual ble_error_t setAdvertisingData(const GapAdvertisingData &, const GapAdvertisingData &);
00067 
00068     virtual uint16_t    getMinAdvertisingInterval(void) const {return GapAdvertisingParams::ADVERTISEMENT_DURATION_UNITS_TO_MS(BLE_GAP_ADV_INTERVAL_MIN);}
00069     virtual uint16_t    getMinNonConnectableAdvertisingInterval(void) const {return GapAdvertisingParams::ADVERTISEMENT_DURATION_UNITS_TO_MS(BLE_GAP_ADV_NONCON_INTERVAL_MIN);}
00070     virtual uint16_t    getMaxAdvertisingInterval(void) const {return GapAdvertisingParams::ADVERTISEMENT_DURATION_UNITS_TO_MS(BLE_GAP_ADV_INTERVAL_MAX);}
00071 
00072     virtual ble_error_t startAdvertising(const GapAdvertisingParams &);
00073     virtual ble_error_t stopAdvertising(void);
00074     virtual ble_error_t connect(const Address_t, BLEProtocol::AddressType_t peerAddrType, const ConnectionParams_t *connectionParams, const GapScanningParams *scanParams);
00075     virtual ble_error_t disconnect(Handle_t connectionHandle, DisconnectionReason_t reason);
00076     virtual ble_error_t disconnect(DisconnectionReason_t reason);
00077 
00078     virtual ble_error_t setDeviceName(const uint8_t *deviceName);
00079     virtual ble_error_t getDeviceName(uint8_t *deviceName, unsigned *lengthP);
00080     virtual ble_error_t setAppearance(GapAdvertisingData::Appearance appearance);
00081     virtual ble_error_t getAppearance(GapAdvertisingData::Appearance *appearanceP);
00082 
00083     virtual ble_error_t setTxPower(int8_t txPower);
00084     virtual void        getPermittedTxPowerValues(const int8_t **valueArrayPP, size_t *countP);
00085 
00086     void     setConnectionHandle(uint16_t con_handle);
00087     uint16_t getConnectionHandle(void);
00088 
00089     virtual ble_error_t getPreferredConnectionParams(ConnectionParams_t *params);
00090     virtual ble_error_t setPreferredConnectionParams(const ConnectionParams_t *params);
00091     virtual ble_error_t updateConnectionParams(Handle_t handle, const ConnectionParams_t *params);
00092 
00093     virtual ble_error_t reset(void);
00094 
00095     /*
00096      * The following functions are part of the whitelisting experimental API.
00097      * Therefore, this functionality can change in the near future.
00098      */
00099     virtual uint8_t getMaxWhitelistSize(void) const;
00100     virtual ble_error_t getWhitelist(Gap::Whitelist_t &whitelistOut) const;
00101     virtual ble_error_t setWhitelist(const Gap::Whitelist_t &whitelistIn);
00102 
00103     virtual ble_error_t setAdvertisingPolicyMode(AdvertisingPolicyMode_t mode);
00104     virtual ble_error_t setScanningPolicyMode(ScanningPolicyMode_t mode);
00105     virtual ble_error_t setInitiatorPolicyMode(InitiatorPolicyMode_t mode);
00106     virtual Gap::AdvertisingPolicyMode_t getAdvertisingPolicyMode(void) const;
00107     virtual Gap::ScanningPolicyMode_t getScanningPolicyMode(void) const;
00108     virtual Gap::InitiatorPolicyMode_t getInitiatorPolicyMode(void) const;
00109 
00110     virtual ble_error_t initRadioNotification(void) {
00111         if (ble_radio_notification_init(NRF_APP_PRIORITY_HIGH, NRF_RADIO_NOTIFICATION_DISTANCE_800US, radioNotificationStaticCallback) == NRF_SUCCESS) {
00112             return BLE_ERROR_NONE;
00113         }
00114 
00115         return BLE_ERROR_UNSPECIFIED;
00116     }
00117 
00118 /* Observer role is not supported by S110, return BLE_ERROR_NOT_IMPLEMENTED */
00119 #if !defined(TARGET_MCU_NRF51_16K_S110) && !defined(TARGET_MCU_NRF51_32K_S110)
00120     virtual ble_error_t startRadioScan(const GapScanningParams &scanningParams);
00121     virtual ble_error_t stopScan(void);
00122 #endif
00123 
00124 private:
00125     /*
00126      * Whitelisting API related structures and helper functions.
00127      */
00128 
00129     /* Policy modes set by the user. By default these are set to ignore the whitelist */
00130     Gap::AdvertisingPolicyMode_t advertisingPolicyMode;
00131     Gap::ScanningPolicyMode_t    scanningPolicyMode;
00132 
00133     /* Internal representation of a whitelist */
00134     uint8_t         whitelistAddressesSize;
00135     ble_gap_addr_t  whitelistAddresses[YOTTA_CFG_WHITELIST_MAX_SIZE];
00136 
00137     /*
00138      * An internal function used to populate the ble_gap_whitelist_t that will be used by
00139      * the SoftDevice for filtering requests. This function is needed because for the BLE
00140      * API the whitelist is just a collection of keys, but for the stack it also includes
00141      * the IRK table.
00142      */
00143     ble_error_t generateStackWhitelist(ble_gap_whitelist_t &whitelist);
00144 
00145 private:
00146     bool    radioNotificationCallbackParam; /* parameter to be passed into the Timeout-generated radio notification callback. */
00147     Timeout radioNotificationTimeout;
00148 
00149     /*
00150      * A helper function to post radio notification callbacks with low interrupt priority.
00151      */
00152     void postRadioNotificationCallback(void) {
00153 #ifdef YOTTA_CFG_MBED_OS
00154         /*
00155          * In mbed OS, all user-facing BLE events (interrupts) are posted to the
00156          * MINAR scheduler to be executed as callbacks in thread mode. MINAR guards
00157          * its critical sections from interrupts by acquiring CriticalSectionLock,
00158          * which results in a call to sd_nvic_critical_region_enter(). Thus, it is
00159          * safe to invoke MINAR APIs from interrupt context as long as those
00160          * interrupts are blocked by sd_nvic_critical_region_enter().
00161          *
00162          * Radio notifications are a special case for the above. The Radio
00163          * Notification IRQ is handled at a very high priority--higher than the
00164          * level blocked by sd_nvic_critical_region_enter(). Thus Radio Notification
00165          * events can preempt MINAR's critical sections. Using MINAR APIs (such as
00166          * posting an event) directly in processRadioNotification() may result in a
00167          * race condition ending in a hard-fault.
00168          *
00169          * The solution is to *not* call MINAR APIs directly from the Radio
00170          * Notification handling; i.e. to do the bulk of RadioNotification
00171          * processing at a reduced priority which respects MINAR's critical
00172          * sections. Unfortunately, on a cortex-M0, there is no clean way to demote
00173          * priority for the currently executing interrupt--we wouldn't want to
00174          * demote the radio notification handling anyway because it is sensitive to
00175          * timing, and the system expects to finish this handling very quickly. The
00176          * workaround is to employ a Timeout to trigger
00177          * postRadioNotificationCallback() after a very short delay (~0 us) and post
00178          * the MINAR callback that context.
00179          *
00180          * !!!WARNING!!! Radio notifications are very time critical events. The
00181          * current solution is expected to work under the assumption that
00182          * postRadioNotificationCalback() will be executed BEFORE the next radio
00183          * notification event is generated.
00184          */
00185         minar::Scheduler::postCallback(
00186             mbed::util::FunctionPointer1<void, bool>(&radioNotificationCallback, &FunctionPointerWithContext<bool>::call).bind(radioNotificationCallbackParam)
00187         );
00188 #else
00189         /*
00190          * In mbed classic, all user-facing BLE events execute callbacks in interrupt
00191          * mode. Radio Notifications are a special case because its IRQ is handled at
00192          * a very high priority. Thus Radio Notification events can preempt other
00193          * operations that require interaction with the SoftDevice such as advertising
00194          * payload updates and changing the Gap state. Therefore, executing a Radio
00195          * Notification callback directly from processRadioNotification() may result
00196          * in a race condition ending in a hard-fault.
00197          *
00198          * The solution is to *not* execute the Radio Notification callback directly
00199          * from the Radio Notification handling; i.e. to do the bulk of the
00200          * Radio Notification processing at a reduced priority. Unfortunately, on a
00201          * cortex-M0, there is no clean way to demote priority for the currently
00202          * executing interrupt--we wouldn't want to demote the radio notification
00203          * handling anyway because it is sensitive to timing, and the system expects
00204          * to finish this handling very quickly. The workaround is to employ a Timeout
00205          * to trigger postRadioNotificationCallback() after a very short delay (~0 us)
00206          * and execute the callback in that context.
00207          *
00208          * !!!WARNING!!! Radio notifications are very time critical events. The
00209          * current solution is expected to work under the assumption that
00210          * postRadioNotificationCalback() will be executed BEFORE the next radio
00211          * notification event is generated.
00212          */
00213         radioNotificationCallback.call(radioNotificationCallbackParam);
00214 #endif /* #ifdef YOTTA_CFG_MBED_OS */
00215     }
00216 
00217     /**
00218      * A helper function to process radio-notification events; to be called internally.
00219      * @param param [description]
00220      */
00221     void processRadioNotificationEvent(bool param) {
00222         radioNotificationCallbackParam = param;
00223         radioNotificationTimeout.attach_us(this, &nRF5xGap::postRadioNotificationCallback, 0);
00224     }
00225     friend void radioNotificationStaticCallback(bool param); /* allow invocations of processRadioNotificationEvent() */
00226 
00227 private:
00228     uint16_t m_connectionHandle;
00229 
00230     /*
00231      * Allow instantiation from nRF5xn when required.
00232      */
00233     friend class nRF5xn;
00234 
00235     nRF5xGap() :
00236         advertisingPolicyMode(Gap::ADV_POLICY_IGNORE_WHITELIST),
00237         scanningPolicyMode(Gap::SCAN_POLICY_IGNORE_WHITELIST),
00238         whitelistAddressesSize(0) {
00239         m_connectionHandle = BLE_CONN_HANDLE_INVALID;
00240     }
00241 
00242     nRF5xGap(nRF5xGap const &);
00243     void operator=(nRF5xGap const &);
00244 };
00245 
00246 #endif // ifndef __NRF5x_GAP_H__