Qi Yao / LinkNode---test123

Dependencies:   mbed

Fork of LinkNode-Test by Qi Yao

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 #include "mbed.h"
00021 #include "ble/blecommon.h"
00022 #include "ble.h"
00023 #include "ble/GapAdvertisingParams.h"
00024 #include "ble/GapAdvertisingData.h"
00025 #include "ble/Gap.h"
00026 #include "ble/GapScanningParams.h"
00027 
00028 #include "nrf_soc.h"
00029 
00030 extern "C" {
00031 #include "ble_radio_notification.h "
00032 }
00033 
00034 #include "btle_security.h"
00035 
00036 void radioNotificationStaticCallback(bool param);
00037 
00038 /**************************************************************************/
00039 /*!
00040     \brief
00041 
00042 */
00043 /**************************************************************************/
00044 class nRF5xGap : public Gap
00045 {
00046 public:
00047     static nRF5xGap &getInstance();
00048 
00049     /* Functions that must be implemented from Gap */
00050     virtual ble_error_t setAddress(AddressType_t  type,  const Address_t address);
00051     virtual ble_error_t getAddress(AddressType_t *typeP, Address_t address);
00052     virtual ble_error_t setAdvertisingData(const GapAdvertisingData &, const GapAdvertisingData &);
00053 
00054     virtual uint16_t    getMinAdvertisingInterval(void) const {return GapAdvertisingParams::ADVERTISEMENT_DURATION_UNITS_TO_MS(BLE_GAP_ADV_INTERVAL_MIN);}
00055     virtual uint16_t    getMinNonConnectableAdvertisingInterval(void) const {return GapAdvertisingParams::ADVERTISEMENT_DURATION_UNITS_TO_MS(BLE_GAP_ADV_NONCON_INTERVAL_MIN);}
00056     virtual uint16_t    getMaxAdvertisingInterval(void) const {return GapAdvertisingParams::ADVERTISEMENT_DURATION_UNITS_TO_MS(BLE_GAP_ADV_INTERVAL_MAX);}
00057 
00058     virtual ble_error_t startAdvertising(const GapAdvertisingParams &);
00059     virtual ble_error_t stopAdvertising(void);
00060     virtual ble_error_t connect(const Address_t, Gap::AddressType_t peerAddrType, const ConnectionParams_t *connectionParams, const GapScanningParams *scanParams);
00061     virtual ble_error_t disconnect(Handle_t connectionHandle, DisconnectionReason_t reason);
00062     virtual ble_error_t disconnect(DisconnectionReason_t reason);
00063 
00064     virtual ble_error_t setDeviceName(const uint8_t *deviceName);
00065     virtual ble_error_t getDeviceName(uint8_t *deviceName, unsigned *lengthP);
00066     virtual ble_error_t setAppearance(GapAdvertisingData::Appearance appearance);
00067     virtual ble_error_t getAppearance(GapAdvertisingData::Appearance *appearanceP);
00068 
00069     virtual ble_error_t setTxPower(int8_t txPower);
00070     virtual void        getPermittedTxPowerValues(const int8_t **valueArrayPP, size_t *countP);
00071 
00072     void     setConnectionHandle(uint16_t con_handle);
00073     uint16_t getConnectionHandle(void);
00074 
00075     virtual ble_error_t getPreferredConnectionParams(ConnectionParams_t *params);
00076     virtual ble_error_t setPreferredConnectionParams(const ConnectionParams_t *params);
00077     virtual ble_error_t updateConnectionParams(Handle_t handle, const ConnectionParams_t *params);
00078 
00079     virtual ble_error_t initRadioNotification(void) {
00080         if (ble_radio_notification_init(NRF_APP_PRIORITY_HIGH, NRF_RADIO_NOTIFICATION_DISTANCE_800US, radioNotificationStaticCallback) == NRF_SUCCESS) {
00081             return BLE_ERROR_NONE;
00082         }
00083 
00084         return BLE_ERROR_UNSPECIFIED;
00085     }
00086 
00087 /* Observer role is not supported by S110, return BLE_ERROR_NOT_IMPLEMENTED */
00088 #if !defined(TARGET_MCU_NRF51_16K_S110) && !defined(TARGET_MCU_NRF51_32K_S110)
00089     virtual ble_error_t startRadioScan(const GapScanningParams &scanningParams) {
00090         ble_gap_scan_params_t scanParams = {
00091             .active      = scanningParams.getActiveScanning(), /**< If 1, perform active scanning (scan requests). */
00092             .selective   = 0,    /**< If 1, ignore unknown devices (non whitelisted). */
00093             .p_whitelist = NULL, /**< Pointer to whitelist, NULL if none is given. */
00094             .interval    = scanningParams.getInterval(),  /**< Scan interval between 0x0004 and 0x4000 in 0.625ms units (2.5ms to 10.24s). */
00095             .window      = scanningParams.getWindow(),    /**< Scan window between 0x0004 and 0x4000 in 0.625ms units (2.5ms to 10.24s). */
00096             .timeout     = scanningParams.getTimeout(),   /**< Scan timeout between 0x0001 and 0xFFFF in seconds, 0x0000 disables timeout. */
00097         };
00098 
00099         if (sd_ble_gap_scan_start(&scanParams) != NRF_SUCCESS) {
00100             return BLE_ERROR_PARAM_OUT_OF_RANGE;
00101         }
00102 
00103         return BLE_ERROR_NONE;
00104     }
00105 
00106     virtual ble_error_t stopScan(void) {
00107         if (sd_ble_gap_scan_stop() == NRF_SUCCESS) {
00108             return BLE_ERROR_NONE;
00109         }
00110 
00111         return BLE_STACK_BUSY;
00112     }
00113 #endif
00114 
00115 private:
00116     bool    radioNotificationCallbackParam; /* parameter to be passed into the Timeout-generated radio notification callback. */
00117     Timeout radioNotificationTimeout;
00118 
00119     /*
00120      * A helper function to post radio notification callbacks with low interrupt priority.
00121      */
00122     void postRadioNotificationCallback(void) {
00123 #ifdef YOTTA_CFG_MBED_OS
00124         /*
00125          * In mbed OS, all user-facing BLE events (interrupts) are posted to the
00126          * MINAR scheduler to be executed as callbacks in thread mode. MINAR guards
00127          * its critical sections from interrupts by acquiring CriticalSectionLock,
00128          * which results in a call to sd_nvic_critical_region_enter(). Thus, it is
00129          * safe to invoke MINAR APIs from interrupt context as long as those
00130          * interrupts are blocked by sd_nvic_critical_region_enter().
00131          *
00132          * Radio notifications are a special case for the above. The Radio
00133          * Notification IRQ is handled at a very high priority--higher than the
00134          * level blocked by sd_nvic_critical_region_enter(). Thus Radio Notification
00135          * events can preempt MINAR's critical sections. Using MINAR APIs (such as
00136          * posting an event) directly in processRadioNotification() may result in a
00137          * race condition ending in a hard-fault.
00138          *
00139          * The solution is to *not* call MINAR APIs directly from the Radio
00140          * Notification handling; i.e. to do the bulk of RadioNotification
00141          * processing at a reduced priority which respects MINAR's critical
00142          * sections. Unfortunately, on a cortex-M0, there is no clean way to demote
00143          * priority for the currently executing interrupt--we wouldn't want to
00144          * demote the radio notification handling anyway because it is sensitive to
00145          * timing, and the system expects to finish this handling very quickly. The
00146          * workaround is to employ a Timeout to trigger
00147          * postRadioNotificationCallback() after a very short delay (~0 us) and post
00148          * the MINAR callback that context.
00149          *
00150          * !!!WARNING!!! Radio notifications are very time critical events. The
00151          * current solution is expected to work under the assumption that
00152          * postRadioNotificationCalback() will be executed BEFORE the next radio
00153          * notification event is generated.
00154          */
00155         minar::Scheduler::postCallback(
00156             mbed::util::FunctionPointer1<void, bool>(&radioNotificationCallback, &FunctionPointerWithContext<bool>::call).bind(radioNotificationCallbackParam)
00157         );
00158 #else
00159         /*
00160          * In mbed classic, all user-facing BLE events execute callbacks in interrupt
00161          * mode. Radio Notifications are a special case because its IRQ is handled at
00162          * a very high priority. Thus Radio Notification events can preempt other
00163          * operations that require interaction with the SoftDevice such as advertising
00164          * payload updates and changing the Gap state. Therefore, executing a Radio
00165          * Notification callback directly from processRadioNotification() may result
00166          * in a race condition ending in a hard-fault.
00167          *
00168          * The solution is to *not* execute the Radio Notification callback directly
00169          * from the Radio Notification handling; i.e. to do the bulk of the
00170          * Radio Notification processing at a reduced priority. Unfortunately, on a
00171          * cortex-M0, there is no clean way to demote priority for the currently
00172          * executing interrupt--we wouldn't want to demote the radio notification
00173          * handling anyway because it is sensitive to timing, and the system expects
00174          * to finish this handling very quickly. The workaround is to employ a Timeout
00175          * to trigger postRadioNotificationCallback() after a very short delay (~0 us)
00176          * and execute the callback in that context.
00177          *
00178          * !!!WARNING!!! Radio notifications are very time critical events. The
00179          * current solution is expected to work under the assumption that
00180          * postRadioNotificationCalback() will be executed BEFORE the next radio
00181          * notification event is generated.
00182          */
00183         radioNotificationCallback.call(radioNotificationCallbackParam);
00184 #endif /* #ifdef YOTTA_CFG_MBED_OS */
00185     }
00186 
00187     /**
00188      * A helper function to process radio-notification events; to be called internally.
00189      * @param param [description]
00190      */
00191     void processRadioNotificationEvent(bool param) {
00192         radioNotificationCallbackParam = param;
00193         radioNotificationTimeout.attach_us(this, &nRF5xGap::postRadioNotificationCallback, 0);
00194     }
00195     friend void radioNotificationStaticCallback(bool param); /* allow invocations of processRadioNotificationEvent() */
00196 
00197 private:
00198     uint16_t m_connectionHandle;
00199     nRF5xGap() {
00200         m_connectionHandle = BLE_CONN_HANDLE_INVALID;
00201     }
00202 
00203     nRF5xGap(nRF5xGap const &);
00204     void operator=(nRF5xGap const &);
00205 };
00206 
00207 #endif // ifndef __NRF5x_GAP_H__