Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Fork of nRF51822 by
Revision 592:f9574772b816, committed 2016-01-11
- Comitter:
- vcoubard
- Date:
- Mon Jan 11 10:19:33 2016 +0000
- Parent:
- 591:266079a50c20
- Child:
- 593:aa1bbbf1de4f
- Commit message:
- Synchronized with git rev 05763f78
Author: Vincent Coubard
Merge pull request #74 from pan-/characteristicDescriptorDiscovery
Implementation of Characteristic descriptor discovery
Changed in this revision
--- a/source/btle/btle.cpp Mon Jan 11 10:19:32 2016 +0000 +++ b/source/btle/btle.cpp Mon Jan 11 10:19:33 2016 +0000 @@ -39,6 +39,10 @@ #include "ble_hci.h" #include "btle_discovery.h" +#include "nRF5xGattClient.h" +#include "nRF5xServiceDiscovery.h" +#include "nRF5xCharacteristicDescriptorDiscoverer.h" + extern "C" void assert_nrf_callback(uint16_t line_num, const uint8_t *p_file_name); void app_error_handler(uint32_t error_code, uint32_t line_num, const uint8_t *p_file_name); @@ -184,6 +188,12 @@ reason = static_cast<Gap::DisconnectionReason_t>(p_ble_evt->evt.gap_evt.params.disconnected.reason); break; } + + // Close all pending discoveries for this connection + nRF5xGattClient& gattClient = ble.getGattClient(); + gattClient.characteristicDescriptorDiscoverer().terminate(handle, BLE_ERROR_INVALID_STATE); + gattClient.discovery().terminate(handle); + gap.processDisconnectionEvent(handle, reason); break; }
--- a/source/btle/btle_discovery.cpp Mon Jan 11 10:19:32 2016 +0000 +++ b/source/btle/btle_discovery.cpp Mon Jan 11 10:19:33 2016 +0000 @@ -14,6 +14,9 @@ * limitations under the License. */ +#include "nRF5xServiceDiscovery.h" +#include "nRF5xCharacteristicDescriptorDiscoverer.h" +#include "nRF5xGattClient.h" #include "nRF5xn.h" #if !defined(TARGET_MCU_NRF51_16K_S110) && !defined(TARGET_MCU_NRF51_32K_S110) @@ -22,7 +25,9 @@ nRF5xn &ble = nRF5xn::Instance(BLE::DEFAULT_INSTANCE); nRF5xGap &gap = (nRF5xGap &) ble.getGap(); nRF5xGattClient &gattClient = (nRF5xGattClient &) ble.getGattClient(); - nRF5xServiceDiscovery &sdSingleton = gattClient.discovery; + nRF5xServiceDiscovery &sdSingleton = gattClient.discovery(); + nRF5xCharacteristicDescriptorDiscoverer &characteristicDescriptorDiscoverer = + gattClient.characteristicDescriptorDiscoverer(); switch (p_ble_evt->header.evt_id) { case BLE_GATTC_EVT_PRIM_SRVC_DISC_RSP: @@ -46,7 +51,7 @@ case BLE_GATT_STATUS_ATTERR_ATTRIBUTE_NOT_FOUND: default: - sdSingleton.terminateCharacteristicDiscovery(); + sdSingleton.terminateCharacteristicDiscovery(BLE_ERROR_NONE); break; } break; @@ -93,6 +98,28 @@ gattClient.processHVXEvent(¶ms); } break; + + case BLE_GATTC_EVT_DESC_DISC_RSP: { + uint16_t conn_handle = p_ble_evt->evt.gattc_evt.conn_handle; + uint16_t status = p_ble_evt->evt.gattc_evt.gatt_status; + const ble_gattc_evt_desc_disc_rsp_t& discovered_descriptors = p_ble_evt->evt.gattc_evt.params.desc_disc_rsp; + + switch(status) { + case BLE_GATT_STATUS_SUCCESS: + characteristicDescriptorDiscoverer.process( + conn_handle, + discovered_descriptors + ); + break; + case BLE_GATT_STATUS_ATTERR_ATTRIBUTE_NOT_FOUND: + // end of discovery + characteristicDescriptorDiscoverer.terminate(conn_handle, BLE_ERROR_NONE); + break; + default: + characteristicDescriptorDiscoverer.terminate(conn_handle, BLE_ERROR_UNSPECIFIED); + break; + } + } break; } sdSingleton.progressCharacteristicDiscovery();
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/source/nRF5xCharacteristicDescriptorDiscoverer.cpp Mon Jan 11 10:19:33 2016 +0000 @@ -0,0 +1,236 @@ +/* mbed Microcontroller Library + * Copyright (c) 2006-2015 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. + */ +#include "nRF5xCharacteristicDescriptorDiscoverer.h" +#include "ble_err.h" +#include "mbed-drivers/mbed_error.h" +#include "ble/DiscoveredCharacteristicDescriptor.h" + +nRF5xCharacteristicDescriptorDiscoverer::nRF5xCharacteristicDescriptorDiscoverer() : + discoveryRunning() { + // nothing to do +} + +nRF5xCharacteristicDescriptorDiscoverer::~nRF5xCharacteristicDescriptorDiscoverer() { + // nothing to do +} + +ble_error_t nRF5xCharacteristicDescriptorDiscoverer::launch( + const DiscoveredCharacteristic& characteristic, + const CharacteristicDescriptorDiscovery::DiscoveryCallback_t& discoveryCallback, + const CharacteristicDescriptorDiscovery::TerminationCallback_t& terminationCallback +) { + Gap::Handle_t connHandle = characteristic.getConnectionHandle(); + // it is ok to deduce that the start handle for descriptors is after + // the characteristic declaration and the characteristic value declaration + // see BLUETOOTH SPECIFICATION Version 4.2 [Vol 3, Part G] (3.3) + Gap::Handle_t descriptorStartHandle = characteristic.getDeclHandle() + 2; + Gap::Handle_t descriptorEndHandle = characteristic.getLastHandle(); + + // check if there is any descriptor to discover + if (descriptorEndHandle < descriptorStartHandle) { + CharacteristicDescriptorDiscovery::TerminationCallbackParams_t termParams = { + characteristic, + BLE_ERROR_NONE + }; + terminationCallback.call(&termParams); + return BLE_ERROR_NONE; + } + + // check if we can run this discovery + if (isConnectionInUse(connHandle)) { + return BLE_STACK_BUSY; + } + + // get a new discovery slot, if none are available, just return + Discovery* discovery = getAvailableDiscoverySlot(); + if(discovery == NULL) { + return BLE_STACK_BUSY; + } + + // try to launch the discovery + ble_error_t err = gattc_descriptors_discover(connHandle, descriptorStartHandle, descriptorEndHandle); + if(!err) { + // commit the new discovery to its slot + *discovery = Discovery(characteristic, discoveryCallback, terminationCallback); + } + + return err; +} + +bool nRF5xCharacteristicDescriptorDiscoverer::isActive(const DiscoveredCharacteristic& characteristic) const { + for(size_t i = 0; i < MAXIMUM_CONCURRENT_CONNECTIONS_COUNT; ++i) { + if(discoveryRunning[i].getCharacteristic() == characteristic) { + return true; + } + } + return false; +} + +void nRF5xCharacteristicDescriptorDiscoverer::requestTerminate(const DiscoveredCharacteristic& characteristic) { + Discovery* discovery = findRunningDiscovery(characteristic); + if(discovery) { + // call terminate anyway + terminate(discovery, BLE_ERROR_NONE); + } +} + +void nRF5xCharacteristicDescriptorDiscoverer::process(uint16_t connectionHandle, const ble_gattc_evt_desc_disc_rsp_t& descriptors) { + Discovery* discovery = findRunningDiscovery(connectionHandle); + // the discovery has been removed + if(!discovery) { + return; + } + + for (uint16_t i = 0; i < descriptors.count; ++i) { + discovery->process( + descriptors.descs[i].handle, UUID(descriptors.descs[i].uuid.uuid) + ); + } + + // prepare the next discovery request (if needed) + uint16_t startHandle = descriptors.descs[descriptors.count - 1].handle + 1; + uint16_t endHandle = discovery->getCharacteristic().getLastHandle(); + + if(startHandle > endHandle) { + terminate(discovery, BLE_ERROR_NONE); + return; + } + + ble_error_t err = gattc_descriptors_discover(connectionHandle, startHandle, endHandle); + if(err) { + terminate(discovery, err); + return; + } +} + +void nRF5xCharacteristicDescriptorDiscoverer::terminate(uint16_t handle, ble_error_t err) { + Discovery* discovery = findRunningDiscovery(handle); + // the discovery has already been terminated + if(!discovery) { + return; + } + + terminate(discovery, err); +} + +void nRF5xCharacteristicDescriptorDiscoverer::terminate(Discovery* discovery, ble_error_t err) { + // temporary copy, user code can try to launch a new discovery in the onTerminate + // callback. So, this discovery should not appear in such case. + Discovery tmp = *discovery; + *discovery = Discovery(); + tmp.terminate(err); +} + +nRF5xCharacteristicDescriptorDiscoverer::Discovery* +nRF5xCharacteristicDescriptorDiscoverer::findRunningDiscovery(const DiscoveredCharacteristic& characteristic) { + for(size_t i = 0; i < MAXIMUM_CONCURRENT_CONNECTIONS_COUNT; ++i) { + if((discoveryRunning[i].getCharacteristic() == characteristic) && + (discoveryRunning[i].isEmpty() == false)) { + return &discoveryRunning[i]; + } + } + return NULL; +} + +nRF5xCharacteristicDescriptorDiscoverer::Discovery* +nRF5xCharacteristicDescriptorDiscoverer::findRunningDiscovery(uint16_t handle) { + for(size_t i = 0; i < MAXIMUM_CONCURRENT_CONNECTIONS_COUNT; ++i) { + if((discoveryRunning[i].getCharacteristic().getConnectionHandle() == handle) && + (discoveryRunning[i].isEmpty() == false)) { + return &discoveryRunning[i]; + } + } + return NULL; +} + +nRF5xCharacteristicDescriptorDiscoverer::Discovery* +nRF5xCharacteristicDescriptorDiscoverer::getAvailableDiscoverySlot() { + for(size_t i = 0; i < MAXIMUM_CONCURRENT_CONNECTIONS_COUNT; ++i) { + if(discoveryRunning[i].isEmpty()) { + return &discoveryRunning[i]; + } + } + return NULL; +} + +bool nRF5xCharacteristicDescriptorDiscoverer::isConnectionInUse(uint16_t connHandle) { + return findRunningDiscovery(connHandle) != NULL; +} + +ble_error_t nRF5xCharacteristicDescriptorDiscoverer::gattc_descriptors_discover( + uint16_t connection_handle, uint16_t start_handle, uint16_t end_handle) { + + ble_gattc_handle_range_t discoveryRange = { + start_handle, + end_handle + }; + uint32_t err = sd_ble_gattc_descriptors_discover(connection_handle, &discoveryRange); + + switch(err) { + case NRF_SUCCESS: + return BLE_ERROR_NONE; + case BLE_ERROR_INVALID_CONN_HANDLE: + return BLE_ERROR_INVALID_PARAM; + case NRF_ERROR_INVALID_ADDR: + return BLE_ERROR_PARAM_OUT_OF_RANGE; + case NRF_ERROR_BUSY: + return BLE_STACK_BUSY; + default: + return BLE_ERROR_UNSPECIFIED; + } +} + +// implementation of nRF5xCharacteristicDescriptorDiscoverer::Discovery + +nRF5xCharacteristicDescriptorDiscoverer::Discovery::Discovery() : + characteristic(), onDiscovery(), onTerminate() { +} + +nRF5xCharacteristicDescriptorDiscoverer::Discovery::Discovery( + const DiscoveredCharacteristic& c, const DiscoveryCallback_t& dCb, const TerminationCallback_t& tCb) : + characteristic(c), onDiscovery(dCb), onTerminate(tCb) { +} + +void nRF5xCharacteristicDescriptorDiscoverer::Discovery::process( + GattAttribute::Handle_t handle, const UUID& uuid) { + CharacteristicDescriptorDiscovery::DiscoveryCallbackParams_t params = { + characteristic, + DiscoveredCharacteristicDescriptor( + characteristic.getGattClient(), + characteristic.getConnectionHandle(), + handle, + uuid + ) + }; + onDiscovery.call(¶ms); +} + +void nRF5xCharacteristicDescriptorDiscoverer::Discovery::terminate(ble_error_t err) { + CharacteristicDescriptorDiscovery::TerminationCallbackParams_t params = { + characteristic, + err + }; + + onTerminate.call(¶ms); +} + +bool nRF5xCharacteristicDescriptorDiscoverer::Discovery::isEmpty() const { + return *this == Discovery(); +} + +const DiscoveredCharacteristic& nRF5xCharacteristicDescriptorDiscoverer::Discovery::getCharacteristic() const { + return characteristic; +} \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/source/nRF5xCharacteristicDescriptorDiscoverer.h Mon Jan 11 10:19:33 2016 +0000 @@ -0,0 +1,214 @@ +/* mbed Microcontroller Library + * Copyright (c) 2006-2015 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_CHARACTERISTIC_DESCRIPTOR_DISCOVERY_H__ +#define __NRF_CHARACTERISTIC_DESCRIPTOR_DISCOVERY_H__ + +#include "ble/Gap.h" +#include "ble/DiscoveredCharacteristic.h" +#include "ble/CharacteristicDescriptorDiscovery.h" +#include "ble/GattClient.h" +#include "ble_gattc.h" + +/** + * @brief Manage the discovery of Characteristic descriptors + * @details is a bridge between BLE API and Nordic stack regarding Characteristic + * Descriptor discovery. The BLE API can launch, monitor and ask for termination + * of a discovery. The Nordic stack will provide new descriptors and indicate when + * the discovery is done. + */ +class nRF5xCharacteristicDescriptorDiscoverer +{ + typedef CharacteristicDescriptorDiscovery::DiscoveryCallback_t DiscoveryCallback_t; + typedef CharacteristicDescriptorDiscovery::TerminationCallback_t TerminationCallback_t; + +public: + /** + * @brief Construct a new characteristic descriptor discoverer. + */ + nRF5xCharacteristicDescriptorDiscoverer(); + + /** + * @brief Destroy a characteristic descriptor discoverer. + */ + ~nRF5xCharacteristicDescriptorDiscoverer(); + + /** + * Launch a new characteristic descriptor discovery for a given DiscoveredCharacteristic. + * @param characteristic The characteristic owning the descriptors to discover. + * @param discoveryCallback The callback called when a descriptor is discovered. + * @param terminationCallback The callback called when the discovery process end. + * @return BLE_ERROR_NONE if characteristic descriptor discovery is launched successfully; + * else an appropriate error. + * @note: this will be called by BLE API side. + */ + ble_error_t launch( + const DiscoveredCharacteristic& characteristic, + const DiscoveryCallback_t& discoveryCallback, + const TerminationCallback_t& terminationCallback + ); + + /** + * @brief indicate if a characteristic descriptor discovery is active for a + * given DiscoveredCharacteristic. + * @param characteristic The characteristic for whom the descriptor might be + * currently discovered. + * @return true if descriptors of characteristic are discovered, false otherwise. + * @note: this will be called by BLE API side. + */ + bool isActive(const DiscoveredCharacteristic& characteristic) const; + + /** + * @brief request the termination of characteristic descriptor discovery + * for a give DiscoveredCharacteristic + * @param characteristic The characteristic for whom the descriptor discovery + * should be stopped. + * @note: this will be called by BLE API side. + */ + void requestTerminate(const DiscoveredCharacteristic& characteristic); + + /** + * @brief process descriptors discovered from the Nordic stack. + * @param connectionHandle The connection handle upon which descriptors has been + * discovered. + * @param descriptors Discovered descriptors. + * @note This will be called by the Nordic stack. + */ + void process(uint16_t connectionHandle, const ble_gattc_evt_desc_disc_rsp_t& descriptors); + + /** + * @brief Called by the Nordic stack when the discovery is over. + * @param The connection handle upon which the discovery process is done. + * @param err An error if the termination is due to an error. + */ + void terminate(uint16_t connectionHandle, ble_error_t err); + +private: + // protection against copy construction and assignment + nRF5xCharacteristicDescriptorDiscoverer(const nRF5xCharacteristicDescriptorDiscoverer&); + nRF5xCharacteristicDescriptorDiscoverer& operator=(const nRF5xCharacteristicDescriptorDiscoverer&); + + /** + * @brief Discovery process, it store the DiscoveredCharacteristic, the + * discovery callback and the termination callback. + */ + class Discovery { + public: + /** + * @brief Construct an empty discovery, such can be considerate as a not running discovery. + * @note #isEmpty function will return true + */ + Discovery(); + + /** + * @brief Construct a valid discovery process. + * + * @param c the characteristic from whom descriptors will be discovered. + * @param dCb The discovery callback called each time a descriptor is discovered. + * @param tCb The termination callback called when the discovery terminate. + * + * @note #isEmpty function will return false + */ + Discovery(const DiscoveredCharacteristic& c, const DiscoveryCallback_t& dCb, const TerminationCallback_t& tCb); + + /** + * @brief Process the discovery of a descriptor. + * + * @param handle The attribute handle of the descriptor found + * @param uuid The UUID of the descriptor found. + */ + void process(GattAttribute::Handle_t handle, const UUID& uuid); + + /** + * @brief Terminate the discovery process. + * + * @param err Error associate with the termination + * @note after this call #isEmpty function will return true. + */ + void terminate(ble_error_t err); + + /** + * @brief check if the discovery process is empty or not. Empty discovery are + * not running. + * + * @detail Discovery are empty after: + * - a default construction + * - a copy construction form a default constructed + * - an assignment from a default constructed Discovery + * @return true if the Discovery is empty and false otherwise. + */ + bool isEmpty() const; + + /** + * @brief return the characteristic from whom descriptors are discovered. + * @return the characteristic from whom descriptors are discovered. + */ + const DiscoveredCharacteristic& getCharacteristic() const; + + /** + * @brief equal to operator, test if two discovery process are equal + * + * @param lhs left hand side of the expression + * @param rhs right hand side of the expression + * @return true if lhs == rhs + */ + friend bool operator==(const Discovery& lhs, const Discovery& rhs) { + return lhs.characteristic == rhs.characteristic && + lhs.onDiscovery == rhs.onDiscovery && + lhs.onTerminate == rhs.onTerminate; + } + + /** + * @brief not equal to operator, test if two discovery process are not equal + * + * @param lhs left hand side of the expression + * @param rhs right hand side of the expression + * @return true if lhs != rhs + */ + friend bool operator!=(const Discovery& lhs, const Discovery& rhs) { + return !(lhs == rhs); + } + + private: + DiscoveredCharacteristic characteristic; + DiscoveryCallback_t onDiscovery; + TerminationCallback_t onTerminate; + }; + + // find a running discovery process + Discovery* findRunningDiscovery(const DiscoveredCharacteristic& characteristic); + Discovery* findRunningDiscovery(uint16_t handle); + + // Called to terminate a discovery is over. + void terminate(Discovery* discovery, ble_error_t err); + + // get one slot for a discovery process + Discovery* getAvailableDiscoverySlot(); + + // indicate if a connection is already running a discovery + bool isConnectionInUse(uint16_t connHandle); + + // low level start of a discovery + static ble_error_t gattc_descriptors_discover(uint16_t connection_handle, uint16_t start_handle, uint16_t end_handle); + + // count of concurrent connections which can run a descriptor discovery process + static const size_t MAXIMUM_CONCURRENT_CONNECTIONS_COUNT = 3; + + // array of running discoveries + Discovery discoveryRunning[MAXIMUM_CONCURRENT_CONNECTIONS_COUNT]; +}; + +#endif /*__NRF_CHARACTERISTIC_DESCRIPTOR_DISCOVERY_H__*/ \ No newline at end of file
--- a/source/nRF5xDiscoveredCharacteristic.h Mon Jan 11 10:19:32 2016 +0000 +++ b/source/nRF5xDiscoveredCharacteristic.h Mon Jan 11 10:19:33 2016 +0000 @@ -36,6 +36,10 @@ ble_gatt_char_props_t propsIn, GattAttribute::Handle_t declHandleIn, GattAttribute::Handle_t valueHandleIn); + + void setLastHandle(GattAttribute::Handle_t last) { + lastHandle = last; + } }; #endif /* __NRF_DISCOVERED_CHARACTERISTIC_H__ */ \ No newline at end of file
--- a/source/nRF5xGattClient.cpp Mon Jan 11 10:19:32 2016 +0000 +++ b/source/nRF5xGattClient.cpp Mon Jan 11 10:19:33 2016 +0000 @@ -24,6 +24,27 @@ const UUID &matchingServiceUUIDIn, const UUID &matchingCharacteristicUUIDIn) { - return discovery.launch(connectionHandle, sc, cc, matchingServiceUUIDIn, matchingCharacteristicUUIDIn); + return _discovery.launch(connectionHandle, sc, cc, matchingServiceUUIDIn, matchingCharacteristicUUIDIn); } + +ble_error_t nRF5xGattClient::discoverCharacteristicDescriptors( + const DiscoveredCharacteristic& characteristic, + const CharacteristicDescriptorDiscovery::DiscoveryCallback_t& discoveryCallback, + const CharacteristicDescriptorDiscovery::TerminationCallback_t& terminationCallback) +{ + return _characteristicDescriptorDiscoverer.launch( + characteristic, + discoveryCallback, + terminationCallback + ); +} + +bool nRF5xGattClient::isCharacteristicDescriptorsDiscoveryActive(const DiscoveredCharacteristic& characteristic) const { + return _characteristicDescriptorDiscoverer.isActive(characteristic); +} + +void nRF5xGattClient::terminateCharacteristicDescriptorsDiscovery(const DiscoveredCharacteristic& characteristic) { + return _characteristicDescriptorDiscoverer.requestTerminate(characteristic); +} + #endif \ No newline at end of file
--- a/source/nRF5xGattClient.h Mon Jan 11 10:19:32 2016 +0000 +++ b/source/nRF5xGattClient.h Mon Jan 11 10:19:33 2016 +0000 @@ -19,6 +19,7 @@ #include "ble/GattClient.h" #include "nRF5xServiceDiscovery.h" +#include "nRF5xCharacteristicDescriptorDiscoverer.h" class nRF5xGattClient : public GattClient { @@ -85,14 +86,14 @@ const UUID &matchingCharacteristicUUIDIn = UUID::ShortUUIDBytes_t(BLE_UUID_UNKNOWN)); virtual void onServiceDiscoveryTermination(ServiceDiscovery::TerminationCallback_t callback) { - discovery.onTermination(callback); + _discovery.onTermination(callback); } /** * Is service-discovery currently active? */ virtual bool isServiceDiscoveryActive(void) const { - return discovery.isActive(); + return _discovery.isActive(); } /** @@ -100,9 +101,31 @@ * invocation of the TerminationCallback if service-discovery is active. */ virtual void terminateServiceDiscovery(void) { - discovery.terminate(); + _discovery.terminate(); } + /** + * @brief Implementation of GattClient::discoverCharacteristicDescriptors + * @see GattClient::discoverCharacteristicDescriptors + */ + virtual ble_error_t discoverCharacteristicDescriptors( + const DiscoveredCharacteristic& characteristic, + const CharacteristicDescriptorDiscovery::DiscoveryCallback_t& discoveryCallback, + const CharacteristicDescriptorDiscovery::TerminationCallback_t& terminationCallback + ); + + /** + * @brief Implementation of GattClient::isCharacteristicDiscoveryActive + * @see GattClient::isCharacteristicDiscoveryActive + */ + virtual bool isCharacteristicDescriptorsDiscoveryActive(const DiscoveredCharacteristic& characteristic) const; + + /** + * @brief Implementation of GattClient::terminateCharacteristicDiscovery + * @see GattClient::terminateCharacteristicDiscovery + */ + virtual void terminateCharacteristicDescriptorsDiscovery(const DiscoveredCharacteristic& characteristic); + virtual ble_error_t read(Gap::Handle_t connHandle, GattAttribute::Handle_t attributeHandle, uint16_t offset) const { uint32_t rc = sd_ble_gattc_read(connHandle, attributeHandle, offset); if (rc == NRF_SUCCESS) { @@ -158,7 +181,7 @@ } /* Clear derived class members */ - discovery.reset(); + _discovery.reset(); return BLE_ERROR_NONE; } @@ -169,18 +192,25 @@ */ friend class nRF5xn; - nRF5xGattClient() : discovery(this) { + nRF5xGattClient() : _discovery(this) { /* empty */ } - friend void bleGattcEventHandler(const ble_evt_t *p_ble_evt); + nRF5xServiceDiscovery& discovery() { + return _discovery; + } + + nRF5xCharacteristicDescriptorDiscoverer& characteristicDescriptorDiscoverer() { + return _characteristicDescriptorDiscoverer; + } private: nRF5xGattClient(const nRF5xGattClient &); const nRF5xGattClient& operator=(const nRF5xGattClient &); private: - nRF5xServiceDiscovery discovery; + nRF5xServiceDiscovery _discovery; + nRF5xCharacteristicDescriptorDiscoverer _characteristicDescriptorDiscoverer; #endif // if !S110 };
--- a/source/nRF5xServiceDiscovery.cpp Mon Jan 11 10:19:32 2016 +0000 +++ b/source/nRF5xServiceDiscovery.cpp Mon Jan 11 10:19:33 2016 +0000 @@ -27,22 +27,32 @@ .start_handle = startHandle, .end_handle = endHandle }; - uint32_t rc; - if ((rc = sd_ble_gattc_characteristics_discover(connectionHandle, &handleRange)) != NRF_SUCCESS) { - terminateCharacteristicDiscovery(); - switch (rc) { - case BLE_ERROR_INVALID_CONN_HANDLE: - case NRF_ERROR_INVALID_ADDR: - return BLE_ERROR_INVALID_PARAM; - case NRF_ERROR_BUSY: - return BLE_STACK_BUSY; - default: - case NRF_ERROR_INVALID_STATE: - return BLE_ERROR_INVALID_STATE; - } + uint32_t rc = sd_ble_gattc_characteristics_discover(connectionHandle, &handleRange); + ble_error_t err = BLE_ERROR_NONE; + + switch (rc) { + case NRF_SUCCESS: + err = BLE_ERROR_NONE; + break; + case BLE_ERROR_INVALID_CONN_HANDLE: + case NRF_ERROR_INVALID_ADDR: + err = BLE_ERROR_INVALID_PARAM; + break; + case NRF_ERROR_BUSY: + err = BLE_STACK_BUSY; + break; + case NRF_ERROR_INVALID_STATE: + err = BLE_ERROR_INVALID_STATE; + break; + default: + err = BLE_ERROR_UNSPECIFIED; + break; } - return BLE_ERROR_NONE; + if (err) { + terminateCharacteristicDiscovery(err); + } + return err; } void @@ -78,7 +88,6 @@ void nRF5xServiceDiscovery::setupDiscoveredCharacteristics(const ble_gattc_evt_char_disc_rsp_t *response) { - characteristicIndex = 0; numCharacteristics = response->count; /* Account for the limitation on the number of discovered characteristics we can handle at a time. */ @@ -114,38 +123,62 @@ void nRF5xServiceDiscovery::progressCharacteristicDiscovery(void) { - /* Iterate through the previously discovered characteristics cached in characteristics[]. */ - while ((state == CHARACTERISTIC_DISCOVERY_ACTIVE) && (characteristicIndex < numCharacteristics)) { + if (state != CHARACTERISTIC_DISCOVERY_ACTIVE) { + return; + } + + if ((discoveredCharacteristic != nRF5xDiscoveredCharacteristic()) && (numCharacteristics > 0)) { + discoveredCharacteristic.setLastHandle(characteristics[0].getDeclHandle() - 1); + if ((matchingCharacteristicUUID == UUID::ShortUUIDBytes_t(BLE_UUID_UNKNOWN)) || - ((matchingCharacteristicUUID == characteristics[characteristicIndex].getUUID()) && + ((matchingCharacteristicUUID == discoveredCharacteristic.getUUID()) && (matchingServiceUUID != UUID::ShortUUIDBytes_t(BLE_UUID_UNKNOWN)))) { if (characteristicCallback) { - characteristicCallback(&characteristics[characteristicIndex]); + characteristicCallback(&discoveredCharacteristic); } } - - characteristicIndex++; } - /* Relaunch discovery of new characteristics beyond the last entry cached in characteristics[]. */ - if (state == CHARACTERISTIC_DISCOVERY_ACTIVE) { - /* Determine the ending handle of the last cached characteristic. */ - Gap::Handle_t startHandle = characteristics[characteristicIndex - 1].getValueHandle() + 1; - Gap::Handle_t endHandle = services[serviceIndex].getEndHandle(); - resetDiscoveredCharacteristics(); /* Note: resetDiscoveredCharacteristics() must come after fetching start and end Handles. */ + for (uint8_t i = 0; i < numCharacteristics; ++i) { + if (state != CHARACTERISTIC_DISCOVERY_ACTIVE) { + return; + } + + if (i == (numCharacteristics - 1)) { + discoveredCharacteristic = characteristics[i]; + break; + } else { + characteristics[i].setLastHandle(characteristics[i + 1].getDeclHandle() - 1); + } - if (startHandle < endHandle) { - ble_gattc_handle_range_t handleRange = { - .start_handle = startHandle, - .end_handle = endHandle - }; - if (sd_ble_gattc_characteristics_discover(connHandle, &handleRange) != NRF_SUCCESS) { - terminateCharacteristicDiscovery(); + if ((matchingCharacteristicUUID == UUID::ShortUUIDBytes_t(BLE_UUID_UNKNOWN)) || + ((matchingCharacteristicUUID == characteristics[i].getUUID()) && + (matchingServiceUUID != UUID::ShortUUIDBytes_t(BLE_UUID_UNKNOWN)))) { + if (characteristicCallback) { + characteristicCallback(&characteristics[i]); } - } else { - terminateCharacteristicDiscovery(); } } + + if (state != CHARACTERISTIC_DISCOVERY_ACTIVE) { + return; + } + + Gap::Handle_t startHandle = (numCharacteristics > 0) ? characteristics[numCharacteristics - 1].getValueHandle() + 1 : SRV_DISC_END_HANDLE; + Gap::Handle_t endHandle = services[serviceIndex].getEndHandle(); + resetDiscoveredCharacteristics(); /* Note: resetDiscoveredCharacteristics() must come after fetching start and end Handles. */ + + if (startHandle < endHandle) { + ble_gattc_handle_range_t handleRange = { + .start_handle = startHandle, + .end_handle = endHandle + }; + if (sd_ble_gattc_characteristics_discover(connHandle, &handleRange) != NRF_SUCCESS) { + terminateCharacteristicDiscovery(BLE_ERROR_UNSPECIFIED); + } + } else { + terminateCharacteristicDiscovery(BLE_ERROR_NONE); + } } void
--- a/source/nRF5xServiceDiscovery.h Mon Jan 11 10:19:32 2016 +0000 +++ b/source/nRF5xServiceDiscovery.h Mon Jan 11 10:19:33 2016 +0000 @@ -41,7 +41,6 @@ gattc(gattcIn), serviceIndex(0), numServices(0), - characteristicIndex(0), numCharacteristics(0), state(INACTIVE), services(), @@ -95,6 +94,12 @@ terminateServiceDiscovery(); } + void terminate(Gap::Handle_t connectionHandle) { + if(connHandle == connectionHandle) { + terminate(); + } + } + virtual void onTermination(ServiceDiscovery::TerminationCallback_t callback) { onTerminationCallback = callback; } @@ -114,7 +119,6 @@ /* Clear derived class members */ serviceIndex = 0; numServices = 0; - characteristicIndex = 0; numCharacteristics = 0; state = INACTIVE; @@ -139,6 +143,8 @@ void removeFirstServiceNeedingUUIDDiscovery(void); void terminateServiceDiscovery(void) { + discoveredCharacteristic = nRF5xDiscoveredCharacteristic(); + bool wasActive = isActive(); state = INACTIVE; @@ -147,8 +153,24 @@ } } - void terminateCharacteristicDiscovery(void) { + 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. */ @@ -162,7 +184,6 @@ void resetDiscoveredCharacteristics(void) { numCharacteristics = 0; - characteristicIndex = 0; } private: @@ -309,7 +330,6 @@ 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 characteristicIndex; /**< Index of the current characteristic being discovered. This is intended for internal use during service discovery.*/ uint8_t numCharacteristics; /**< Number of characteristics within the service.*/ enum State_t { @@ -328,6 +348,19 @@ 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
--- a/source/nRF5xn.h Mon Jan 11 10:19:32 2016 +0000 +++ b/source/nRF5xn.h Mon Jan 11 10:19:33 2016 +0000 @@ -77,7 +77,7 @@ * * @return A reference to GattClient. */ - virtual GattClient &getGattClient() { + virtual nRF5xGattClient &getGattClient() { if (gattClientInstance == NULL) { gattClientInstance = new nRF5xGattClient(); } @@ -91,7 +91,7 @@ * * @return A reference to GattServer. */ - virtual SecurityManager &getSecurityManager() { + virtual nRF5xSecurityManager &getSecurityManager() { if (securityManagerInstance == NULL) { securityManagerInstance = new nRF5xSecurityManager(); } @@ -112,7 +112,7 @@ * @note The accessor is able to modify the object's state because the * internal pointer has been declared mutable. */ - virtual const Gap &getGap() const { + virtual const nRF5xGap &getGap() const { return gapInstance; }; @@ -126,7 +126,7 @@ * @note The accessor is able to modify the object's state because the * internal pointer has been declared mutable. */ - virtual const GattServer &getGattServer() const { + virtual const nRF5xGattServer &getGattServer() const { if (gattServerInstance == NULL) { gattServerInstance = new nRF5xGattServer(); } @@ -143,7 +143,7 @@ * @note The accessor is able to modify the object's state because the * internal pointer has been declared mutable. */ - virtual const SecurityManager &getSecurityManager() const { + virtual const nRF5xSecurityManager &getSecurityManager() const { if (securityManagerInstance == NULL) { securityManagerInstance = new nRF5xSecurityManager(); }