Fork of nRF51822 by
Revision 631:e613866d34ba, committed 2016-04-11
- Comitter:
- vcoubard
- Date:
- Mon Apr 11 15:07:15 2016 +0100
- Parent:
- 630:435a3d9e6456
- Child:
- 632:e29695758978
- Commit message:
- Synchronized with git rev 4e6cc020
Author: Vincent Coubard
Replace inclusion of nordic header ble.h into nrf_ble.h
This change has been introduced in the SDK to mitigate
compilation issues with mbed-classic.
Changed in this revision
--- a/source/btle/btle.h Mon Apr 11 15:07:10 2016 +0100 +++ b/source/btle/btle.h Mon Apr 11 15:07:15 2016 +0100 @@ -24,7 +24,7 @@ #include "common/common.h" #include "ble_srv_common.h" -#include "ble.h" +#include "nrf_ble.h" error_t btle_init(void);
--- a/source/btle/custom/custom_helper.h Mon Apr 11 15:07:10 2016 +0100 +++ b/source/btle/custom/custom_helper.h Mon Apr 11 15:07:15 2016 +0100 @@ -1,60 +1,60 @@ -/* mbed Microcontroller Library - * Copyright (c) 2006-2013 ARM Limited - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef _CUSTOM_HELPER_H_ -#define _CUSTOM_HELPER_H_ - -#include "common/common.h" -#include "ble.h" -#include "ble/UUID.h" -#include "ble/GattCharacteristic.h" - -#ifdef __cplusplus -extern "C" { -#endif - -uint8_t custom_add_uuid_base(uint8_t const *const p_uuid_base); -error_t custom_decode_uuid(uint8_t const *const p_uuid_base, - ble_uuid_t *p_uuid); -ble_uuid_t custom_convert_to_nordic_uuid(const UUID &uuid); - -error_t custom_add_in_characteristic(uint16_t service_handle, - ble_uuid_t *p_uuid, - uint8_t properties, - SecurityManager::SecurityMode_t requiredSecurity, - uint8_t *p_data, - uint16_t length, - uint16_t max_length, - bool has_variable_len, - const uint8_t *userDescriptionDescriptorValuePtr, - uint16_t userDescriptionDescriptorValueLen, - bool readAuthorization, - bool writeAuthorization, - ble_gatts_char_handles_t *p_char_handle); - -error_t custom_add_in_descriptor(uint16_t char_handle, - ble_uuid_t *p_uuid, - uint8_t *p_data, - uint16_t length, - uint16_t max_length, - bool has_variable_len, - uint16_t *p_desc_handle); - -#ifdef __cplusplus -} -#endif - +/* mbed Microcontroller Library + * Copyright (c) 2006-2013 ARM Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _CUSTOM_HELPER_H_ +#define _CUSTOM_HELPER_H_ + +#include "common/common.h" +#include "nrf_ble.h" +#include "ble/UUID.h" +#include "ble/GattCharacteristic.h" + +#ifdef __cplusplus +extern "C" { +#endif + +uint8_t custom_add_uuid_base(uint8_t const *const p_uuid_base); +error_t custom_decode_uuid(uint8_t const *const p_uuid_base, + ble_uuid_t *p_uuid); +ble_uuid_t custom_convert_to_nordic_uuid(const UUID &uuid); + +error_t custom_add_in_characteristic(uint16_t service_handle, + ble_uuid_t *p_uuid, + uint8_t properties, + SecurityManager::SecurityMode_t requiredSecurity, + uint8_t *p_data, + uint16_t length, + uint16_t max_length, + bool has_variable_len, + const uint8_t *userDescriptionDescriptorValuePtr, + uint16_t userDescriptionDescriptorValueLen, + bool readAuthorization, + bool writeAuthorization, + ble_gatts_char_handles_t *p_char_handle); + +error_t custom_add_in_descriptor(uint16_t char_handle, + ble_uuid_t *p_uuid, + uint8_t *p_data, + uint16_t length, + uint16_t max_length, + bool has_variable_len, + uint16_t *p_desc_handle); + +#ifdef __cplusplus +} +#endif + #endif // ifndef _CUSTOM_HELPER_H_ \ No newline at end of file
--- a/source/nRF5xGap.h Mon Apr 11 15:07:10 2016 +0100 +++ b/source/nRF5xGap.h Mon Apr 11 15:07:15 2016 +0100 @@ -1,246 +1,246 @@ -/* mbed Microcontroller Library - * Copyright (c) 2006-2013 ARM Limited - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef __NRF5x_GAP_H__ -#define __NRF5x_GAP_H__ - -#ifdef YOTTA_CFG_MBED_OS - #include "mbed-drivers/mbed.h" -#else - #include "mbed.h" -#endif -#ifndef YOTTA_CFG_WHITELIST_MAX_SIZE - #define YOTTA_CFG_WHITELIST_MAX_SIZE BLE_GAP_WHITELIST_ADDR_MAX_COUNT -#elif YOTTA_CFG_WHITELIST_MAX_SIZE > BLE_GAP_WHITELIST_ADDR_MAX_COUNT - #undef YOTTA_CFG_WHITELIST_MAX_SIZE - #define YOTTA_CFG_WHITELIST_MAX_SIZE BLE_GAP_WHITELIST_ADDR_MAX_COUNT -#endif -#ifndef YOTTA_CFG_IRK_TABLE_MAX_SIZE - #define YOTTA_CFG_IRK_TABLE_MAX_SIZE BLE_GAP_WHITELIST_IRK_MAX_COUNT -#elif YOTTA_CFG_IRK_TABLE_MAX_SIZE > BLE_GAP_WHITELIST_IRK_MAX_COUNT - #undef YOTTA_CFG_IRK_TABLE_MAX_SIZE - #define YOTTA_CFG_IRK_TABLE_MAX_SIZE BLE_GAP_WHITELIST_IRK_MAX_COUNT -#endif -#include "ble/blecommon.h" -#include "ble.h" -#include "ble/GapAdvertisingParams.h" -#include "ble/GapAdvertisingData.h" -#include "ble/Gap.h" -#include "ble/GapScanningParams.h" - -#include "nrf_soc.h" - -extern "C" { -#include "ble_radio_notification.h" -} - -#include "btle_security.h" - -void radioNotificationStaticCallback(bool param); - -/**************************************************************************/ -/*! - \brief - -*/ -/**************************************************************************/ -class nRF5xGap : public Gap -{ -public: - /* Functions that must be implemented from Gap */ - virtual ble_error_t setAddress(AddressType_t type, const Address_t address); - virtual ble_error_t getAddress(AddressType_t *typeP, Address_t address); - virtual ble_error_t setAdvertisingData(const GapAdvertisingData &, const GapAdvertisingData &); - - virtual uint16_t getMinAdvertisingInterval(void) const {return GapAdvertisingParams::ADVERTISEMENT_DURATION_UNITS_TO_MS(BLE_GAP_ADV_INTERVAL_MIN);} - virtual uint16_t getMinNonConnectableAdvertisingInterval(void) const {return GapAdvertisingParams::ADVERTISEMENT_DURATION_UNITS_TO_MS(BLE_GAP_ADV_NONCON_INTERVAL_MIN);} - virtual uint16_t getMaxAdvertisingInterval(void) const {return GapAdvertisingParams::ADVERTISEMENT_DURATION_UNITS_TO_MS(BLE_GAP_ADV_INTERVAL_MAX);} - - virtual ble_error_t startAdvertising(const GapAdvertisingParams &); - virtual ble_error_t stopAdvertising(void); - virtual ble_error_t connect(const Address_t, BLEProtocol::AddressType_t peerAddrType, const ConnectionParams_t *connectionParams, const GapScanningParams *scanParams); - virtual ble_error_t disconnect(Handle_t connectionHandle, DisconnectionReason_t reason); - virtual ble_error_t disconnect(DisconnectionReason_t reason); - - virtual ble_error_t setDeviceName(const uint8_t *deviceName); - virtual ble_error_t getDeviceName(uint8_t *deviceName, unsigned *lengthP); - virtual ble_error_t setAppearance(GapAdvertisingData::Appearance appearance); - virtual ble_error_t getAppearance(GapAdvertisingData::Appearance *appearanceP); - - virtual ble_error_t setTxPower(int8_t txPower); - virtual void getPermittedTxPowerValues(const int8_t **valueArrayPP, size_t *countP); - - void setConnectionHandle(uint16_t con_handle); - uint16_t getConnectionHandle(void); - - virtual ble_error_t getPreferredConnectionParams(ConnectionParams_t *params); - virtual ble_error_t setPreferredConnectionParams(const ConnectionParams_t *params); - virtual ble_error_t updateConnectionParams(Handle_t handle, const ConnectionParams_t *params); - - virtual ble_error_t reset(void); - - /* - * The following functions are part of the whitelisting experimental API. - * Therefore, this functionality can change in the near future. - */ - virtual uint8_t getMaxWhitelistSize(void) const; - virtual ble_error_t getWhitelist(Gap::Whitelist_t &whitelistOut) const; - virtual ble_error_t setWhitelist(const Gap::Whitelist_t &whitelistIn); - - virtual ble_error_t setAdvertisingPolicyMode(AdvertisingPolicyMode_t mode); - virtual ble_error_t setScanningPolicyMode(ScanningPolicyMode_t mode); - virtual ble_error_t setInitiatorPolicyMode(InitiatorPolicyMode_t mode); - virtual Gap::AdvertisingPolicyMode_t getAdvertisingPolicyMode(void) const; - virtual Gap::ScanningPolicyMode_t getScanningPolicyMode(void) const; - virtual Gap::InitiatorPolicyMode_t getInitiatorPolicyMode(void) const; - - virtual ble_error_t initRadioNotification(void) { - if (ble_radio_notification_init(NRF_APP_PRIORITY_HIGH, NRF_RADIO_NOTIFICATION_DISTANCE_800US, radioNotificationStaticCallback) == NRF_SUCCESS) { - return BLE_ERROR_NONE; - } - - return BLE_ERROR_UNSPECIFIED; - } - -/* Observer role is not supported by S110, return BLE_ERROR_NOT_IMPLEMENTED */ -#if !defined(TARGET_MCU_NRF51_16K_S110) && !defined(TARGET_MCU_NRF51_32K_S110) - virtual ble_error_t startRadioScan(const GapScanningParams &scanningParams); - virtual ble_error_t stopScan(void); -#endif - -private: - /* - * Whitelisting API related structures and helper functions. - */ - - /* Policy modes set by the user. By default these are set to ignore the whitelist */ - Gap::AdvertisingPolicyMode_t advertisingPolicyMode; - Gap::ScanningPolicyMode_t scanningPolicyMode; - - /* Internal representation of a whitelist */ - uint8_t whitelistAddressesSize; - ble_gap_addr_t whitelistAddresses[YOTTA_CFG_WHITELIST_MAX_SIZE]; - - /* - * An internal function used to populate the ble_gap_whitelist_t that will be used by - * the SoftDevice for filtering requests. This function is needed because for the BLE - * API the whitelist is just a collection of keys, but for the stack it also includes - * the IRK table. - */ - ble_error_t generateStackWhitelist(ble_gap_whitelist_t &whitelist); - -private: - bool radioNotificationCallbackParam; /* parameter to be passed into the Timeout-generated radio notification callback. */ - Timeout radioNotificationTimeout; - - /* - * A helper function to post radio notification callbacks with low interrupt priority. - */ - void postRadioNotificationCallback(void) { -#ifdef YOTTA_CFG_MBED_OS - /* - * In mbed OS, all user-facing BLE events (interrupts) are posted to the - * MINAR scheduler to be executed as callbacks in thread mode. MINAR guards - * its critical sections from interrupts by acquiring CriticalSectionLock, - * which results in a call to sd_nvic_critical_region_enter(). Thus, it is - * safe to invoke MINAR APIs from interrupt context as long as those - * interrupts are blocked by sd_nvic_critical_region_enter(). - * - * Radio notifications are a special case for the above. The Radio - * Notification IRQ is handled at a very high priority--higher than the - * level blocked by sd_nvic_critical_region_enter(). Thus Radio Notification - * events can preempt MINAR's critical sections. Using MINAR APIs (such as - * posting an event) directly in processRadioNotification() may result in a - * race condition ending in a hard-fault. - * - * The solution is to *not* call MINAR APIs directly from the Radio - * Notification handling; i.e. to do the bulk of RadioNotification - * processing at a reduced priority which respects MINAR's critical - * sections. Unfortunately, on a cortex-M0, there is no clean way to demote - * priority for the currently executing interrupt--we wouldn't want to - * demote the radio notification handling anyway because it is sensitive to - * timing, and the system expects to finish this handling very quickly. The - * workaround is to employ a Timeout to trigger - * postRadioNotificationCallback() after a very short delay (~0 us) and post - * the MINAR callback that context. - * - * !!!WARNING!!! Radio notifications are very time critical events. The - * current solution is expected to work under the assumption that - * postRadioNotificationCalback() will be executed BEFORE the next radio - * notification event is generated. - */ - minar::Scheduler::postCallback( - mbed::util::FunctionPointer1<void, bool>(&radioNotificationCallback, &FunctionPointerWithContext<bool>::call).bind(radioNotificationCallbackParam) - ); -#else - /* - * In mbed classic, all user-facing BLE events execute callbacks in interrupt - * mode. Radio Notifications are a special case because its IRQ is handled at - * a very high priority. Thus Radio Notification events can preempt other - * operations that require interaction with the SoftDevice such as advertising - * payload updates and changing the Gap state. Therefore, executing a Radio - * Notification callback directly from processRadioNotification() may result - * in a race condition ending in a hard-fault. - * - * The solution is to *not* execute the Radio Notification callback directly - * from the Radio Notification handling; i.e. to do the bulk of the - * Radio Notification processing at a reduced priority. Unfortunately, on a - * cortex-M0, there is no clean way to demote priority for the currently - * executing interrupt--we wouldn't want to demote the radio notification - * handling anyway because it is sensitive to timing, and the system expects - * to finish this handling very quickly. The workaround is to employ a Timeout - * to trigger postRadioNotificationCallback() after a very short delay (~0 us) - * and execute the callback in that context. - * - * !!!WARNING!!! Radio notifications are very time critical events. The - * current solution is expected to work under the assumption that - * postRadioNotificationCalback() will be executed BEFORE the next radio - * notification event is generated. - */ - radioNotificationCallback.call(radioNotificationCallbackParam); -#endif /* #ifdef YOTTA_CFG_MBED_OS */ - } - - /** - * A helper function to process radio-notification events; to be called internally. - * @param param [description] - */ - void processRadioNotificationEvent(bool param) { - radioNotificationCallbackParam = param; - radioNotificationTimeout.attach_us(this, &nRF5xGap::postRadioNotificationCallback, 0); - } - friend void radioNotificationStaticCallback(bool param); /* allow invocations of processRadioNotificationEvent() */ - -private: - uint16_t m_connectionHandle; - - /* - * Allow instantiation from nRF5xn when required. - */ - friend class nRF5xn; - - nRF5xGap() : - advertisingPolicyMode(Gap::ADV_POLICY_IGNORE_WHITELIST), - scanningPolicyMode(Gap::SCAN_POLICY_IGNORE_WHITELIST), - whitelistAddressesSize(0) { - m_connectionHandle = BLE_CONN_HANDLE_INVALID; - } - - nRF5xGap(nRF5xGap const &); - void operator=(nRF5xGap const &); -}; - +/* mbed Microcontroller Library + * Copyright (c) 2006-2013 ARM Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __NRF5x_GAP_H__ +#define __NRF5x_GAP_H__ + +#ifdef YOTTA_CFG_MBED_OS + #include "mbed-drivers/mbed.h" +#else + #include "mbed.h" +#endif +#ifndef YOTTA_CFG_WHITELIST_MAX_SIZE + #define YOTTA_CFG_WHITELIST_MAX_SIZE BLE_GAP_WHITELIST_ADDR_MAX_COUNT +#elif YOTTA_CFG_WHITELIST_MAX_SIZE > BLE_GAP_WHITELIST_ADDR_MAX_COUNT + #undef YOTTA_CFG_WHITELIST_MAX_SIZE + #define YOTTA_CFG_WHITELIST_MAX_SIZE BLE_GAP_WHITELIST_ADDR_MAX_COUNT +#endif +#ifndef YOTTA_CFG_IRK_TABLE_MAX_SIZE + #define YOTTA_CFG_IRK_TABLE_MAX_SIZE BLE_GAP_WHITELIST_IRK_MAX_COUNT +#elif YOTTA_CFG_IRK_TABLE_MAX_SIZE > BLE_GAP_WHITELIST_IRK_MAX_COUNT + #undef YOTTA_CFG_IRK_TABLE_MAX_SIZE + #define YOTTA_CFG_IRK_TABLE_MAX_SIZE BLE_GAP_WHITELIST_IRK_MAX_COUNT +#endif +#include "ble/blecommon.h" +#include "nrf_ble.h" +#include "ble/GapAdvertisingParams.h" +#include "ble/GapAdvertisingData.h" +#include "ble/Gap.h" +#include "ble/GapScanningParams.h" + +#include "nrf_soc.h" + +extern "C" { +#include "ble_radio_notification.h" +} + +#include "btle_security.h" + +void radioNotificationStaticCallback(bool param); + +/**************************************************************************/ +/*! + \brief + +*/ +/**************************************************************************/ +class nRF5xGap : public Gap +{ +public: + /* Functions that must be implemented from Gap */ + virtual ble_error_t setAddress(AddressType_t type, const Address_t address); + virtual ble_error_t getAddress(AddressType_t *typeP, Address_t address); + virtual ble_error_t setAdvertisingData(const GapAdvertisingData &, const GapAdvertisingData &); + + virtual uint16_t getMinAdvertisingInterval(void) const {return GapAdvertisingParams::ADVERTISEMENT_DURATION_UNITS_TO_MS(BLE_GAP_ADV_INTERVAL_MIN);} + virtual uint16_t getMinNonConnectableAdvertisingInterval(void) const {return GapAdvertisingParams::ADVERTISEMENT_DURATION_UNITS_TO_MS(BLE_GAP_ADV_NONCON_INTERVAL_MIN);} + virtual uint16_t getMaxAdvertisingInterval(void) const {return GapAdvertisingParams::ADVERTISEMENT_DURATION_UNITS_TO_MS(BLE_GAP_ADV_INTERVAL_MAX);} + + virtual ble_error_t startAdvertising(const GapAdvertisingParams &); + virtual ble_error_t stopAdvertising(void); + virtual ble_error_t connect(const Address_t, BLEProtocol::AddressType_t peerAddrType, const ConnectionParams_t *connectionParams, const GapScanningParams *scanParams); + virtual ble_error_t disconnect(Handle_t connectionHandle, DisconnectionReason_t reason); + virtual ble_error_t disconnect(DisconnectionReason_t reason); + + virtual ble_error_t setDeviceName(const uint8_t *deviceName); + virtual ble_error_t getDeviceName(uint8_t *deviceName, unsigned *lengthP); + virtual ble_error_t setAppearance(GapAdvertisingData::Appearance appearance); + virtual ble_error_t getAppearance(GapAdvertisingData::Appearance *appearanceP); + + virtual ble_error_t setTxPower(int8_t txPower); + virtual void getPermittedTxPowerValues(const int8_t **valueArrayPP, size_t *countP); + + void setConnectionHandle(uint16_t con_handle); + uint16_t getConnectionHandle(void); + + virtual ble_error_t getPreferredConnectionParams(ConnectionParams_t *params); + virtual ble_error_t setPreferredConnectionParams(const ConnectionParams_t *params); + virtual ble_error_t updateConnectionParams(Handle_t handle, const ConnectionParams_t *params); + + virtual ble_error_t reset(void); + + /* + * The following functions are part of the whitelisting experimental API. + * Therefore, this functionality can change in the near future. + */ + virtual uint8_t getMaxWhitelistSize(void) const; + virtual ble_error_t getWhitelist(Gap::Whitelist_t &whitelistOut) const; + virtual ble_error_t setWhitelist(const Gap::Whitelist_t &whitelistIn); + + virtual ble_error_t setAdvertisingPolicyMode(AdvertisingPolicyMode_t mode); + virtual ble_error_t setScanningPolicyMode(ScanningPolicyMode_t mode); + virtual ble_error_t setInitiatorPolicyMode(InitiatorPolicyMode_t mode); + virtual Gap::AdvertisingPolicyMode_t getAdvertisingPolicyMode(void) const; + virtual Gap::ScanningPolicyMode_t getScanningPolicyMode(void) const; + virtual Gap::InitiatorPolicyMode_t getInitiatorPolicyMode(void) const; + + virtual ble_error_t initRadioNotification(void) { + if (ble_radio_notification_init(NRF_APP_PRIORITY_HIGH, NRF_RADIO_NOTIFICATION_DISTANCE_800US, radioNotificationStaticCallback) == NRF_SUCCESS) { + return BLE_ERROR_NONE; + } + + return BLE_ERROR_UNSPECIFIED; + } + +/* Observer role is not supported by S110, return BLE_ERROR_NOT_IMPLEMENTED */ +#if !defined(TARGET_MCU_NRF51_16K_S110) && !defined(TARGET_MCU_NRF51_32K_S110) + virtual ble_error_t startRadioScan(const GapScanningParams &scanningParams); + virtual ble_error_t stopScan(void); +#endif + +private: + /* + * Whitelisting API related structures and helper functions. + */ + + /* Policy modes set by the user. By default these are set to ignore the whitelist */ + Gap::AdvertisingPolicyMode_t advertisingPolicyMode; + Gap::ScanningPolicyMode_t scanningPolicyMode; + + /* Internal representation of a whitelist */ + uint8_t whitelistAddressesSize; + ble_gap_addr_t whitelistAddresses[YOTTA_CFG_WHITELIST_MAX_SIZE]; + + /* + * An internal function used to populate the ble_gap_whitelist_t that will be used by + * the SoftDevice for filtering requests. This function is needed because for the BLE + * API the whitelist is just a collection of keys, but for the stack it also includes + * the IRK table. + */ + ble_error_t generateStackWhitelist(ble_gap_whitelist_t &whitelist); + +private: + bool radioNotificationCallbackParam; /* parameter to be passed into the Timeout-generated radio notification callback. */ + Timeout radioNotificationTimeout; + + /* + * A helper function to post radio notification callbacks with low interrupt priority. + */ + void postRadioNotificationCallback(void) { +#ifdef YOTTA_CFG_MBED_OS + /* + * In mbed OS, all user-facing BLE events (interrupts) are posted to the + * MINAR scheduler to be executed as callbacks in thread mode. MINAR guards + * its critical sections from interrupts by acquiring CriticalSectionLock, + * which results in a call to sd_nvic_critical_region_enter(). Thus, it is + * safe to invoke MINAR APIs from interrupt context as long as those + * interrupts are blocked by sd_nvic_critical_region_enter(). + * + * Radio notifications are a special case for the above. The Radio + * Notification IRQ is handled at a very high priority--higher than the + * level blocked by sd_nvic_critical_region_enter(). Thus Radio Notification + * events can preempt MINAR's critical sections. Using MINAR APIs (such as + * posting an event) directly in processRadioNotification() may result in a + * race condition ending in a hard-fault. + * + * The solution is to *not* call MINAR APIs directly from the Radio + * Notification handling; i.e. to do the bulk of RadioNotification + * processing at a reduced priority which respects MINAR's critical + * sections. Unfortunately, on a cortex-M0, there is no clean way to demote + * priority for the currently executing interrupt--we wouldn't want to + * demote the radio notification handling anyway because it is sensitive to + * timing, and the system expects to finish this handling very quickly. The + * workaround is to employ a Timeout to trigger + * postRadioNotificationCallback() after a very short delay (~0 us) and post + * the MINAR callback that context. + * + * !!!WARNING!!! Radio notifications are very time critical events. The + * current solution is expected to work under the assumption that + * postRadioNotificationCalback() will be executed BEFORE the next radio + * notification event is generated. + */ + minar::Scheduler::postCallback( + mbed::util::FunctionPointer1<void, bool>(&radioNotificationCallback, &FunctionPointerWithContext<bool>::call).bind(radioNotificationCallbackParam) + ); +#else + /* + * In mbed classic, all user-facing BLE events execute callbacks in interrupt + * mode. Radio Notifications are a special case because its IRQ is handled at + * a very high priority. Thus Radio Notification events can preempt other + * operations that require interaction with the SoftDevice such as advertising + * payload updates and changing the Gap state. Therefore, executing a Radio + * Notification callback directly from processRadioNotification() may result + * in a race condition ending in a hard-fault. + * + * The solution is to *not* execute the Radio Notification callback directly + * from the Radio Notification handling; i.e. to do the bulk of the + * Radio Notification processing at a reduced priority. Unfortunately, on a + * cortex-M0, there is no clean way to demote priority for the currently + * executing interrupt--we wouldn't want to demote the radio notification + * handling anyway because it is sensitive to timing, and the system expects + * to finish this handling very quickly. The workaround is to employ a Timeout + * to trigger postRadioNotificationCallback() after a very short delay (~0 us) + * and execute the callback in that context. + * + * !!!WARNING!!! Radio notifications are very time critical events. The + * current solution is expected to work under the assumption that + * postRadioNotificationCalback() will be executed BEFORE the next radio + * notification event is generated. + */ + radioNotificationCallback.call(radioNotificationCallbackParam); +#endif /* #ifdef YOTTA_CFG_MBED_OS */ + } + + /** + * A helper function to process radio-notification events; to be called internally. + * @param param [description] + */ + void processRadioNotificationEvent(bool param) { + radioNotificationCallbackParam = param; + radioNotificationTimeout.attach_us(this, &nRF5xGap::postRadioNotificationCallback, 0); + } + friend void radioNotificationStaticCallback(bool param); /* allow invocations of processRadioNotificationEvent() */ + +private: + uint16_t m_connectionHandle; + + /* + * Allow instantiation from nRF5xn when required. + */ + friend class nRF5xn; + + nRF5xGap() : + advertisingPolicyMode(Gap::ADV_POLICY_IGNORE_WHITELIST), + scanningPolicyMode(Gap::SCAN_POLICY_IGNORE_WHITELIST), + whitelistAddressesSize(0) { + m_connectionHandle = BLE_CONN_HANDLE_INVALID; + } + + nRF5xGap(nRF5xGap const &); + void operator=(nRF5xGap const &); +}; + #endif // ifndef __NRF5x_GAP_H__ \ No newline at end of file
--- a/source/nRF5xGattServer.h Mon Apr 11 15:07:10 2016 +0100 +++ b/source/nRF5xGattServer.h Mon Apr 11 15:07:15 2016 +0100 @@ -1,103 +1,103 @@ -/* mbed Microcontroller Library - * Copyright (c) 2006-2013 ARM Limited - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef __NRF51822_GATT_SERVER_H__ -#define __NRF51822_GATT_SERVER_H__ - -#include <stddef.h> - -#include "ble/blecommon.h" -#include "ble.h" /* nordic ble */ -#include "ble/Gap.h" -#include "ble/GattServer.h" - -class nRF5xGattServer : public GattServer -{ -public: - /* Functions that must be implemented from GattServer */ - virtual ble_error_t addService(GattService &); - virtual ble_error_t read(GattAttribute::Handle_t attributeHandle, uint8_t buffer[], uint16_t *lengthP); - virtual ble_error_t read(Gap::Handle_t connectionHandle, GattAttribute::Handle_t attributeHandle, uint8_t buffer[], uint16_t *lengthP); - virtual ble_error_t write(GattAttribute::Handle_t, const uint8_t[], uint16_t, bool localOnly = false); - virtual ble_error_t write(Gap::Handle_t connectionHandle, GattAttribute::Handle_t, const uint8_t[], uint16_t, bool localOnly = false); - virtual ble_error_t areUpdatesEnabled(const GattCharacteristic &characteristic, bool *enabledP); - virtual ble_error_t areUpdatesEnabled(Gap::Handle_t connectionHandle, const GattCharacteristic &characteristic, bool *enabledP); - virtual ble_error_t reset(void); - - /* nRF51 Functions */ - void eventCallback(void); - void hwCallback(ble_evt_t *p_ble_evt); - - -private: - const static unsigned BLE_TOTAL_CHARACTERISTICS = 20; - const static unsigned BLE_TOTAL_DESCRIPTORS = 8; - -private: - /** - * resolve a value attribute to its owning characteristic. - * @param valueHandle the value handle to be resolved. - * @return characteristic index if a resolution is found, else -1. - */ - int resolveValueHandleToCharIndex(GattAttribute::Handle_t valueHandle) const { - unsigned charIndex; - for (charIndex = 0; charIndex < characteristicCount; charIndex++) { - if (nrfCharacteristicHandles[charIndex].value_handle == valueHandle) { - return charIndex; - } - } - - return -1; - } - - /** - * resolve a CCCD attribute handle to its owning characteristic. - * @param cccdHandle the CCCD handle to be resolved. - * @return characteristic index if a resolution is found, else -1. - */ - int resolveCCCDHandleToCharIndex(GattAttribute::Handle_t cccdHandle) const { - unsigned charIndex; - for (charIndex = 0; charIndex < characteristicCount; charIndex++) { - if (nrfCharacteristicHandles[charIndex].cccd_handle == cccdHandle) { - return charIndex; - } - } - - return -1; - } - -private: - GattCharacteristic *p_characteristics[BLE_TOTAL_CHARACTERISTICS]; - ble_gatts_char_handles_t nrfCharacteristicHandles[BLE_TOTAL_CHARACTERISTICS]; - GattAttribute *p_descriptors[BLE_TOTAL_DESCRIPTORS]; - uint8_t descriptorCount; - uint16_t nrfDescriptorHandles[BLE_TOTAL_DESCRIPTORS]; - - /* - * Allow instantiation from nRF5xn when required. - */ - friend class nRF5xn; - - nRF5xGattServer() : GattServer(), p_characteristics(), nrfCharacteristicHandles(), p_descriptors(), descriptorCount(0), nrfDescriptorHandles() { - /* empty */ - } - -private: - nRF5xGattServer(const nRF5xGattServer &); - const nRF5xGattServer& operator=(const nRF5xGattServer &); -}; - +/* mbed Microcontroller Library + * Copyright (c) 2006-2013 ARM Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __NRF51822_GATT_SERVER_H__ +#define __NRF51822_GATT_SERVER_H__ + +#include <stddef.h> + +#include "ble/blecommon.h" +#include "nrf_ble.h" /* nordic ble */ +#include "ble/Gap.h" +#include "ble/GattServer.h" + +class nRF5xGattServer : public GattServer +{ +public: + /* Functions that must be implemented from GattServer */ + virtual ble_error_t addService(GattService &); + virtual ble_error_t read(GattAttribute::Handle_t attributeHandle, uint8_t buffer[], uint16_t *lengthP); + virtual ble_error_t read(Gap::Handle_t connectionHandle, GattAttribute::Handle_t attributeHandle, uint8_t buffer[], uint16_t *lengthP); + virtual ble_error_t write(GattAttribute::Handle_t, const uint8_t[], uint16_t, bool localOnly = false); + virtual ble_error_t write(Gap::Handle_t connectionHandle, GattAttribute::Handle_t, const uint8_t[], uint16_t, bool localOnly = false); + virtual ble_error_t areUpdatesEnabled(const GattCharacteristic &characteristic, bool *enabledP); + virtual ble_error_t areUpdatesEnabled(Gap::Handle_t connectionHandle, const GattCharacteristic &characteristic, bool *enabledP); + virtual ble_error_t reset(void); + + /* nRF51 Functions */ + void eventCallback(void); + void hwCallback(ble_evt_t *p_ble_evt); + + +private: + const static unsigned BLE_TOTAL_CHARACTERISTICS = 20; + const static unsigned BLE_TOTAL_DESCRIPTORS = 8; + +private: + /** + * resolve a value attribute to its owning characteristic. + * @param valueHandle the value handle to be resolved. + * @return characteristic index if a resolution is found, else -1. + */ + int resolveValueHandleToCharIndex(GattAttribute::Handle_t valueHandle) const { + unsigned charIndex; + for (charIndex = 0; charIndex < characteristicCount; charIndex++) { + if (nrfCharacteristicHandles[charIndex].value_handle == valueHandle) { + return charIndex; + } + } + + return -1; + } + + /** + * resolve a CCCD attribute handle to its owning characteristic. + * @param cccdHandle the CCCD handle to be resolved. + * @return characteristic index if a resolution is found, else -1. + */ + int resolveCCCDHandleToCharIndex(GattAttribute::Handle_t cccdHandle) const { + unsigned charIndex; + for (charIndex = 0; charIndex < characteristicCount; charIndex++) { + if (nrfCharacteristicHandles[charIndex].cccd_handle == cccdHandle) { + return charIndex; + } + } + + return -1; + } + +private: + GattCharacteristic *p_characteristics[BLE_TOTAL_CHARACTERISTICS]; + ble_gatts_char_handles_t nrfCharacteristicHandles[BLE_TOTAL_CHARACTERISTICS]; + GattAttribute *p_descriptors[BLE_TOTAL_DESCRIPTORS]; + uint8_t descriptorCount; + uint16_t nrfDescriptorHandles[BLE_TOTAL_DESCRIPTORS]; + + /* + * Allow instantiation from nRF5xn when required. + */ + friend class nRF5xn; + + nRF5xGattServer() : GattServer(), p_characteristics(), nrfCharacteristicHandles(), p_descriptors(), descriptorCount(0), nrfDescriptorHandles() { + /* empty */ + } + +private: + nRF5xGattServer(const nRF5xGattServer &); + const nRF5xGattServer& operator=(const nRF5xGattServer &); +}; + #endif // ifndef __NRF51822_GATT_SERVER_H__ \ No newline at end of file
--- a/source/nRF5xServiceDiscovery.h Mon Apr 11 15:07:10 2016 +0100 +++ b/source/nRF5xServiceDiscovery.h Mon Apr 11 15:07:15 2016 +0100 @@ -1,366 +1,366 @@ -/* mbed Microcontroller Library - * Copyright (c) 2006-2013 ARM Limited - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef __NRF_SERVICE_DISCOVERY_H__ -#define __NRF_SERVICE_DISCOVERY_H__ - -#include "ble/ServiceDiscovery.h" -#include "ble/DiscoveredService.h" -#include "nRF5xDiscoveredCharacteristic.h" - -#include "ble.h" -#include "ble_gattc.h" - -class nRF5xGattClient; /* forward declaration */ - -class nRF5xServiceDiscovery : public ServiceDiscovery -{ -public: - static const uint16_t SRV_DISC_START_HANDLE = 0x0001; /**< The start handle value used during service discovery. */ - static const uint16_t SRV_DISC_END_HANDLE = 0xFFFF; /**< The end handle value used during service discovery. */ - -public: - static const unsigned BLE_DB_DISCOVERY_MAX_SRV = 4; /**< Maximum number of services we can retain information for after a single discovery. */ - static const unsigned BLE_DB_DISCOVERY_MAX_CHAR_PER_SRV = 4; /**< Maximum number of characteristics per service we can retain information for. */ - -public: - nRF5xServiceDiscovery(nRF5xGattClient *gattcIn) : - gattc(gattcIn), - serviceIndex(0), - numServices(0), - numCharacteristics(0), - state(INACTIVE), - services(), - characteristics(), - serviceUUIDDiscoveryQueue(this), - charUUIDDiscoveryQueue(this), - onTerminationCallback(NULL) { - /* empty */ - } - - virtual ble_error_t launch(Gap::Handle_t connectionHandle, - ServiceDiscovery::ServiceCallback_t sc, - ServiceDiscovery::CharacteristicCallback_t cc, - const UUID &matchingServiceUUIDIn, - const UUID &matchingCharacteristicUUIDIn) - { - if (isActive()) { - return BLE_ERROR_INVALID_STATE; - } - - serviceCallback = sc; - characteristicCallback = cc; - matchingServiceUUID = matchingServiceUUIDIn; - matchingCharacteristicUUID = matchingCharacteristicUUIDIn; - - serviceDiscoveryStarted(connectionHandle); - - uint32_t rc; - if ((rc = sd_ble_gattc_primary_services_discover(connectionHandle, SRV_DISC_START_HANDLE, NULL)) != NRF_SUCCESS) { - terminate(); - switch (rc) { - case NRF_ERROR_INVALID_PARAM: - case BLE_ERROR_INVALID_CONN_HANDLE: - return BLE_ERROR_INVALID_PARAM; - case NRF_ERROR_BUSY: - return BLE_STACK_BUSY; - default: - case NRF_ERROR_INVALID_STATE: - return BLE_ERROR_INVALID_STATE; - } - } - - return BLE_ERROR_NONE; - } - - virtual bool isActive(void) const { - return state != INACTIVE; - } - - virtual void terminate(void) { - terminateServiceDiscovery(); - } - - void terminate(Gap::Handle_t connectionHandle) { - if(connHandle == connectionHandle) { - terminate(); - } - } - - virtual void onTermination(ServiceDiscovery::TerminationCallback_t callback) { - onTerminationCallback = callback; - } - - /** - * @brief Clear nRF5xServiceDiscovery's state. - * - * @return - * BLE_ERROR_NONE if successful. - */ - virtual ble_error_t reset(void) { - /* Clear all state that is from the parent, including private members */ - if (ServiceDiscovery::reset() != BLE_ERROR_NONE) { - return BLE_ERROR_INVALID_STATE; - } - - /* Clear derived class members */ - serviceIndex = 0; - numServices = 0; - numCharacteristics = 0; - - state = INACTIVE; - - serviceUUIDDiscoveryQueue.reset(); - charUUIDDiscoveryQueue.reset(); - - onTerminationCallback = NULL; - - return BLE_ERROR_NONE; - } - -private: - ble_error_t launchCharacteristicDiscovery(Gap::Handle_t connectionHandle, Gap::Handle_t startHandle, Gap::Handle_t endHandle); - -private: - void setupDiscoveredServices(const ble_gattc_evt_prim_srvc_disc_rsp_t *response); - void setupDiscoveredCharacteristics(const ble_gattc_evt_char_disc_rsp_t *response); - - void triggerServiceUUIDDiscovery(void); - void processDiscoverUUIDResponse(const ble_gattc_evt_char_val_by_uuid_read_rsp_t *response); - void removeFirstServiceNeedingUUIDDiscovery(void); - - void terminateServiceDiscovery(void) { - discoveredCharacteristic = nRF5xDiscoveredCharacteristic(); - - bool wasActive = isActive(); - state = INACTIVE; - - if (wasActive && onTerminationCallback) { - onTerminationCallback(connHandle); - } - } - - void terminateCharacteristicDiscovery(ble_error_t err) { - if (state == CHARACTERISTIC_DISCOVERY_ACTIVE) { - if(discoveredCharacteristic != nRF5xDiscoveredCharacteristic()) { - if(err == BLE_ERROR_NONE) { - // fullfill the last characteristic - discoveredCharacteristic.setLastHandle(services[serviceIndex].getEndHandle()); - - if ((matchingCharacteristicUUID == UUID::ShortUUIDBytes_t(BLE_UUID_UNKNOWN)) || - ((matchingCharacteristicUUID == discoveredCharacteristic.getUUID()) && - (matchingServiceUUID != UUID::ShortUUIDBytes_t(BLE_UUID_UNKNOWN)))) { - if (characteristicCallback) { - characteristicCallback(&discoveredCharacteristic); - } - } - } - discoveredCharacteristic = nRF5xDiscoveredCharacteristic(); - } - - state = SERVICE_DISCOVERY_ACTIVE; - } - serviceIndex++; /* Progress service index to keep discovery alive. */ - } - -private: - void resetDiscoveredServices(void) { - numServices = 0; - serviceIndex = 0; - } - - void resetDiscoveredCharacteristics(void) { - numCharacteristics = 0; - } - -private: - void serviceDiscoveryStarted(Gap::Handle_t connectionHandle) { - connHandle = connectionHandle; - resetDiscoveredServices(); - state = SERVICE_DISCOVERY_ACTIVE; - } - -private: - void characteristicDiscoveryStarted(Gap::Handle_t connectionHandle) { - connHandle = connectionHandle; - resetDiscoveredCharacteristics(); - state = CHARACTERISTIC_DISCOVERY_ACTIVE; - } - -private: - /** - * A datatype to contain service-indices for which long UUIDs need to be - * discovered using read_val_by_uuid(). - */ - class ServiceUUIDDiscoveryQueue { - public: - ServiceUUIDDiscoveryQueue(nRF5xServiceDiscovery *parent) : - numIndices(0), - serviceIndices(), - parentDiscoveryObject(parent) { - /* empty */ - } - - public: - void reset(void) { - numIndices = 0; - for (unsigned i = 0; i < BLE_DB_DISCOVERY_MAX_SRV; i++) { - serviceIndices[i] = INVALID_INDEX; - } - } - void enqueue(int serviceIndex) { - serviceIndices[numIndices++] = serviceIndex; - } - int dequeue(void) { - if (numIndices == 0) { - return INVALID_INDEX; - } - - unsigned valueToReturn = serviceIndices[0]; - numIndices--; - for (unsigned i = 0; i < numIndices; i++) { - serviceIndices[i] = serviceIndices[i + 1]; - } - - return valueToReturn; - } - unsigned getFirst(void) const { - return serviceIndices[0]; - } - size_t getCount(void) const { - return numIndices; - } - - /** - * Trigger UUID discovery for the first of the enqueued ServiceIndices. - */ - void triggerFirst(void); - - private: - static const int INVALID_INDEX = -1; - - private: - size_t numIndices; - int serviceIndices[BLE_DB_DISCOVERY_MAX_SRV]; - - nRF5xServiceDiscovery *parentDiscoveryObject; - }; - friend class ServiceUUIDDiscoveryQueue; - - /** - * A datatype to contain characteristic-indices for which long UUIDs need to - * be discovered using read_val_by_uuid(). - */ - class CharUUIDDiscoveryQueue { - public: - CharUUIDDiscoveryQueue(nRF5xServiceDiscovery *parent) : - numIndices(0), - charIndices(), - parentDiscoveryObject(parent) { - /* empty */ - } - - public: - void reset(void) { - numIndices = 0; - for (unsigned i = 0; i < BLE_DB_DISCOVERY_MAX_SRV; i++) { - charIndices[i] = INVALID_INDEX; - } - } - void enqueue(int serviceIndex) { - charIndices[numIndices++] = serviceIndex; - } - int dequeue(void) { - if (numIndices == 0) { - return INVALID_INDEX; - } - - unsigned valueToReturn = charIndices[0]; - numIndices--; - for (unsigned i = 0; i < numIndices; i++) { - charIndices[i] = charIndices[i + 1]; - } - - return valueToReturn; - } - unsigned getFirst(void) const { - return charIndices[0]; - } - size_t getCount(void) const { - return numIndices; - } - - /** - * Trigger UUID discovery for the first of the enqueued charIndices. - */ - void triggerFirst(void); - - private: - static const int INVALID_INDEX = -1; - - private: - size_t numIndices; - int charIndices[BLE_DB_DISCOVERY_MAX_CHAR_PER_SRV]; - - nRF5xServiceDiscovery *parentDiscoveryObject; - }; - friend class CharUUIDDiscoveryQueue; - -private: - friend void bleGattcEventHandler(const ble_evt_t *p_ble_evt); - void progressCharacteristicDiscovery(void); - void progressServiceDiscovery(void); - -private: - nRF5xGattClient *gattc; - -private: - uint8_t serviceIndex; /**< Index of the current service being discovered. This is intended for internal use during service discovery.*/ - uint8_t numServices; /**< Number of services at the peers GATT database.*/ - uint8_t numCharacteristics; /**< Number of characteristics within the service.*/ - - enum State_t { - INACTIVE, - SERVICE_DISCOVERY_ACTIVE, - CHARACTERISTIC_DISCOVERY_ACTIVE, - DISCOVER_SERVICE_UUIDS, - DISCOVER_CHARACTERISTIC_UUIDS, - } state; - - DiscoveredService services[BLE_DB_DISCOVERY_MAX_SRV]; /**< Information related to the current service being discovered. - * This is intended for internal use during service discovery. */ - nRF5xDiscoveredCharacteristic characteristics[BLE_DB_DISCOVERY_MAX_CHAR_PER_SRV]; - - ServiceUUIDDiscoveryQueue serviceUUIDDiscoveryQueue; - CharUUIDDiscoveryQueue charUUIDDiscoveryQueue; - - TerminationCallback_t onTerminationCallback; - - /* - * The currently discovered characteristic. Discovery of a characteristic - * is a two phase process. - * First, declaration handle is fetched, it provide the UUID, the value handle and - * the properties of a characteristic. - * Second, the next declaration handle is fetched, with its declaration handle, it is - * possible to compute the last handle of the discovered characteristic and fill the - * missing part of the object. - * If there is no remaining characteristic to discover, the last handle of the - * discovered characteristic will be set to the last handle of its enclosing service. - */ - nRF5xDiscoveredCharacteristic discoveredCharacteristic; -}; - +/* mbed Microcontroller Library + * Copyright (c) 2006-2013 ARM Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __NRF_SERVICE_DISCOVERY_H__ +#define __NRF_SERVICE_DISCOVERY_H__ + +#include "ble/ServiceDiscovery.h" +#include "ble/DiscoveredService.h" +#include "nRF5xDiscoveredCharacteristic.h" + +#include "nrf_ble.h" +#include "ble_gattc.h" + +class nRF5xGattClient; /* forward declaration */ + +class nRF5xServiceDiscovery : public ServiceDiscovery +{ +public: + static const uint16_t SRV_DISC_START_HANDLE = 0x0001; /**< The start handle value used during service discovery. */ + static const uint16_t SRV_DISC_END_HANDLE = 0xFFFF; /**< The end handle value used during service discovery. */ + +public: + static const unsigned BLE_DB_DISCOVERY_MAX_SRV = 4; /**< Maximum number of services we can retain information for after a single discovery. */ + static const unsigned BLE_DB_DISCOVERY_MAX_CHAR_PER_SRV = 4; /**< Maximum number of characteristics per service we can retain information for. */ + +public: + nRF5xServiceDiscovery(nRF5xGattClient *gattcIn) : + gattc(gattcIn), + serviceIndex(0), + numServices(0), + numCharacteristics(0), + state(INACTIVE), + services(), + characteristics(), + serviceUUIDDiscoveryQueue(this), + charUUIDDiscoveryQueue(this), + onTerminationCallback(NULL) { + /* empty */ + } + + virtual ble_error_t launch(Gap::Handle_t connectionHandle, + ServiceDiscovery::ServiceCallback_t sc, + ServiceDiscovery::CharacteristicCallback_t cc, + const UUID &matchingServiceUUIDIn, + const UUID &matchingCharacteristicUUIDIn) + { + if (isActive()) { + return BLE_ERROR_INVALID_STATE; + } + + serviceCallback = sc; + characteristicCallback = cc; + matchingServiceUUID = matchingServiceUUIDIn; + matchingCharacteristicUUID = matchingCharacteristicUUIDIn; + + serviceDiscoveryStarted(connectionHandle); + + uint32_t rc; + if ((rc = sd_ble_gattc_primary_services_discover(connectionHandle, SRV_DISC_START_HANDLE, NULL)) != NRF_SUCCESS) { + terminate(); + switch (rc) { + case NRF_ERROR_INVALID_PARAM: + case BLE_ERROR_INVALID_CONN_HANDLE: + return BLE_ERROR_INVALID_PARAM; + case NRF_ERROR_BUSY: + return BLE_STACK_BUSY; + default: + case NRF_ERROR_INVALID_STATE: + return BLE_ERROR_INVALID_STATE; + } + } + + return BLE_ERROR_NONE; + } + + virtual bool isActive(void) const { + return state != INACTIVE; + } + + virtual void terminate(void) { + terminateServiceDiscovery(); + } + + void terminate(Gap::Handle_t connectionHandle) { + if(connHandle == connectionHandle) { + terminate(); + } + } + + virtual void onTermination(ServiceDiscovery::TerminationCallback_t callback) { + onTerminationCallback = callback; + } + + /** + * @brief Clear nRF5xServiceDiscovery's state. + * + * @return + * BLE_ERROR_NONE if successful. + */ + virtual ble_error_t reset(void) { + /* Clear all state that is from the parent, including private members */ + if (ServiceDiscovery::reset() != BLE_ERROR_NONE) { + return BLE_ERROR_INVALID_STATE; + } + + /* Clear derived class members */ + serviceIndex = 0; + numServices = 0; + numCharacteristics = 0; + + state = INACTIVE; + + serviceUUIDDiscoveryQueue.reset(); + charUUIDDiscoveryQueue.reset(); + + onTerminationCallback = NULL; + + return BLE_ERROR_NONE; + } + +private: + ble_error_t launchCharacteristicDiscovery(Gap::Handle_t connectionHandle, Gap::Handle_t startHandle, Gap::Handle_t endHandle); + +private: + void setupDiscoveredServices(const ble_gattc_evt_prim_srvc_disc_rsp_t *response); + void setupDiscoveredCharacteristics(const ble_gattc_evt_char_disc_rsp_t *response); + + void triggerServiceUUIDDiscovery(void); + void processDiscoverUUIDResponse(const ble_gattc_evt_char_val_by_uuid_read_rsp_t *response); + void removeFirstServiceNeedingUUIDDiscovery(void); + + void terminateServiceDiscovery(void) { + discoveredCharacteristic = nRF5xDiscoveredCharacteristic(); + + bool wasActive = isActive(); + state = INACTIVE; + + if (wasActive && onTerminationCallback) { + onTerminationCallback(connHandle); + } + } + + void terminateCharacteristicDiscovery(ble_error_t err) { + if (state == CHARACTERISTIC_DISCOVERY_ACTIVE) { + if(discoveredCharacteristic != nRF5xDiscoveredCharacteristic()) { + if(err == BLE_ERROR_NONE) { + // fullfill the last characteristic + discoveredCharacteristic.setLastHandle(services[serviceIndex].getEndHandle()); + + if ((matchingCharacteristicUUID == UUID::ShortUUIDBytes_t(BLE_UUID_UNKNOWN)) || + ((matchingCharacteristicUUID == discoveredCharacteristic.getUUID()) && + (matchingServiceUUID != UUID::ShortUUIDBytes_t(BLE_UUID_UNKNOWN)))) { + if (characteristicCallback) { + characteristicCallback(&discoveredCharacteristic); + } + } + } + discoveredCharacteristic = nRF5xDiscoveredCharacteristic(); + } + + state = SERVICE_DISCOVERY_ACTIVE; + } + serviceIndex++; /* Progress service index to keep discovery alive. */ + } + +private: + void resetDiscoveredServices(void) { + numServices = 0; + serviceIndex = 0; + } + + void resetDiscoveredCharacteristics(void) { + numCharacteristics = 0; + } + +private: + void serviceDiscoveryStarted(Gap::Handle_t connectionHandle) { + connHandle = connectionHandle; + resetDiscoveredServices(); + state = SERVICE_DISCOVERY_ACTIVE; + } + +private: + void characteristicDiscoveryStarted(Gap::Handle_t connectionHandle) { + connHandle = connectionHandle; + resetDiscoveredCharacteristics(); + state = CHARACTERISTIC_DISCOVERY_ACTIVE; + } + +private: + /** + * A datatype to contain service-indices for which long UUIDs need to be + * discovered using read_val_by_uuid(). + */ + class ServiceUUIDDiscoveryQueue { + public: + ServiceUUIDDiscoveryQueue(nRF5xServiceDiscovery *parent) : + numIndices(0), + serviceIndices(), + parentDiscoveryObject(parent) { + /* empty */ + } + + public: + void reset(void) { + numIndices = 0; + for (unsigned i = 0; i < BLE_DB_DISCOVERY_MAX_SRV; i++) { + serviceIndices[i] = INVALID_INDEX; + } + } + void enqueue(int serviceIndex) { + serviceIndices[numIndices++] = serviceIndex; + } + int dequeue(void) { + if (numIndices == 0) { + return INVALID_INDEX; + } + + unsigned valueToReturn = serviceIndices[0]; + numIndices--; + for (unsigned i = 0; i < numIndices; i++) { + serviceIndices[i] = serviceIndices[i + 1]; + } + + return valueToReturn; + } + unsigned getFirst(void) const { + return serviceIndices[0]; + } + size_t getCount(void) const { + return numIndices; + } + + /** + * Trigger UUID discovery for the first of the enqueued ServiceIndices. + */ + void triggerFirst(void); + + private: + static const int INVALID_INDEX = -1; + + private: + size_t numIndices; + int serviceIndices[BLE_DB_DISCOVERY_MAX_SRV]; + + nRF5xServiceDiscovery *parentDiscoveryObject; + }; + friend class ServiceUUIDDiscoveryQueue; + + /** + * A datatype to contain characteristic-indices for which long UUIDs need to + * be discovered using read_val_by_uuid(). + */ + class CharUUIDDiscoveryQueue { + public: + CharUUIDDiscoveryQueue(nRF5xServiceDiscovery *parent) : + numIndices(0), + charIndices(), + parentDiscoveryObject(parent) { + /* empty */ + } + + public: + void reset(void) { + numIndices = 0; + for (unsigned i = 0; i < BLE_DB_DISCOVERY_MAX_SRV; i++) { + charIndices[i] = INVALID_INDEX; + } + } + void enqueue(int serviceIndex) { + charIndices[numIndices++] = serviceIndex; + } + int dequeue(void) { + if (numIndices == 0) { + return INVALID_INDEX; + } + + unsigned valueToReturn = charIndices[0]; + numIndices--; + for (unsigned i = 0; i < numIndices; i++) { + charIndices[i] = charIndices[i + 1]; + } + + return valueToReturn; + } + unsigned getFirst(void) const { + return charIndices[0]; + } + size_t getCount(void) const { + return numIndices; + } + + /** + * Trigger UUID discovery for the first of the enqueued charIndices. + */ + void triggerFirst(void); + + private: + static const int INVALID_INDEX = -1; + + private: + size_t numIndices; + int charIndices[BLE_DB_DISCOVERY_MAX_CHAR_PER_SRV]; + + nRF5xServiceDiscovery *parentDiscoveryObject; + }; + friend class CharUUIDDiscoveryQueue; + +private: + friend void bleGattcEventHandler(const ble_evt_t *p_ble_evt); + void progressCharacteristicDiscovery(void); + void progressServiceDiscovery(void); + +private: + nRF5xGattClient *gattc; + +private: + uint8_t serviceIndex; /**< Index of the current service being discovered. This is intended for internal use during service discovery.*/ + uint8_t numServices; /**< Number of services at the peers GATT database.*/ + uint8_t numCharacteristics; /**< Number of characteristics within the service.*/ + + enum State_t { + INACTIVE, + SERVICE_DISCOVERY_ACTIVE, + CHARACTERISTIC_DISCOVERY_ACTIVE, + DISCOVER_SERVICE_UUIDS, + DISCOVER_CHARACTERISTIC_UUIDS, + } state; + + DiscoveredService services[BLE_DB_DISCOVERY_MAX_SRV]; /**< Information related to the current service being discovered. + * This is intended for internal use during service discovery. */ + nRF5xDiscoveredCharacteristic characteristics[BLE_DB_DISCOVERY_MAX_CHAR_PER_SRV]; + + ServiceUUIDDiscoveryQueue serviceUUIDDiscoveryQueue; + CharUUIDDiscoveryQueue charUUIDDiscoveryQueue; + + TerminationCallback_t onTerminationCallback; + + /* + * The currently discovered characteristic. Discovery of a characteristic + * is a two phase process. + * First, declaration handle is fetched, it provide the UUID, the value handle and + * the properties of a characteristic. + * Second, the next declaration handle is fetched, with its declaration handle, it is + * possible to compute the last handle of the discovered characteristic and fill the + * missing part of the object. + * If there is no remaining characteristic to discover, the last handle of the + * discovered characteristic will be set to the last handle of its enclosing service. + */ + nRF5xDiscoveredCharacteristic discoveredCharacteristic; +}; + #endif /*__NRF_SERVICE_DISCOVERY_H__*/ \ No newline at end of file