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.
Revision 82:443323e7d4c9, committed 2020-01-16
- Comitter:
- fdalforno
- Date:
- Thu Jan 16 14:48:30 2020 +0000
- Parent:
- 81:796f36bfa718
- Commit message:
- Gestione client Bluetooth per scheda F401RE
Changed in this revision
source/BLEProcess.h | Show annotated file Show diff for this revision Revisions of this file |
source/main.cpp | Show annotated file Show diff for this revision Revisions of this file |
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/source/BLEProcess.h Thu Jan 16 14:48:30 2020 +0000 @@ -0,0 +1,231 @@ +/* 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 GATT_EXAMPLE_BLE_PROCESS_H_ +#define GATT_EXAMPLE_BLE_PROCESS_H_ + +#include <stdint.h> +#include <stdio.h> + +#include "events/EventQueue.h" +#include "platform/Callback.h" +#include "platform/NonCopyable.h" + +#include "ble/BLE.h" +#include "ble/Gap.h" +#include "ble/GapAdvertisingParams.h" +#include "ble/GapAdvertisingData.h" +#include "ble/FunctionPointerWithContext.h" + +/** + * Handle initialization and shutdown of the BLE Instance. + * + * Setup advertising payload and manage advertising state. + * Delegate to GattClientProcess once the connection is established. + */ +class BLEProcess : private mbed::NonCopyable<BLEProcess> { +public: + /** + * Construct a BLEProcess from an event queue and a ble interface. + * + * Call start() to initiate ble processing. + */ + BLEProcess(events::EventQueue &event_queue, BLE &ble_interface) : + _event_queue(event_queue), + _ble_interface(ble_interface), + _post_init_cb() { + } + + ~BLEProcess() + { + stop(); + } + + /** + * Initialize the ble interface, configure it and start advertising. + */ + bool start() + { + printf("Ble process started.\r\n"); + + if (_ble_interface.hasInitialized()) { + printf("Error: the ble instance has already been initialized.\r\n"); + return false; + } + + _ble_interface.onEventsToProcess( + makeFunctionPointer(this, &BLEProcess::schedule_ble_events) + ); + + ble_error_t error = _ble_interface.init( + this, &BLEProcess::when_init_complete + ); + + if (error) { + printf("Error: %u returned by BLE::init.\r\n", error); + return false; + } + + return true; + } + + /** + * Close existing connections and stop the process. + */ + void stop() + { + if (_ble_interface.hasInitialized()) { + _ble_interface.shutdown(); + printf("Ble process stopped."); + } + } + + /** + * Subscription to the ble interface initialization event. + * + * @param[in] cb The callback object that will be called when the ble + * interface is initialized. + */ + void on_init(mbed::Callback<void(BLE&, events::EventQueue&)> cb) + { + _post_init_cb = cb; + } + +private: + /** + * Sets up adverting payload and start advertising. + * + * This function is invoked when the ble interface is initialized. + */ + void when_init_complete(BLE::InitializationCompleteCallbackContext *event) + { + if (event->error) { + printf("Error %u during the initialization\r\n", event->error); + return; + } + printf("Ble instance initialized\r\n"); + + Gap &gap = _ble_interface.gap(); + ble_error_t error = gap.setAdvertisingPayload(make_advertising_data()); + if (error) { + printf("Error %u during gap.setAdvertisingPayload\r\n", error); + return; + } + + gap.setAdvertisingParams(make_advertising_params()); + + gap.onConnection(this, &BLEProcess::when_connection); + gap.onDisconnection(this, &BLEProcess::when_disconnection); + + start_advertising(); + + if (_post_init_cb) { + _post_init_cb(_ble_interface, _event_queue); + } + } + + /** + * Start the gatt client process when a connection event is received. + */ + void when_connection(const Gap::ConnectionCallbackParams_t *connection_event) + { + printf("Connected.\r\n"); + } + + /** + * Stop the gatt client process when the device is disconnected then restart + * advertising. + */ + void when_disconnection(const Gap::DisconnectionCallbackParams_t *event) + { + printf("Disconnected.\r\n"); + start_advertising(); + } + + /** + * Setup the advertising parameters. + */ + void setup_advertising() + { + Gap &gap = _ble_interface.gap(); + gap.setAdvertisingPayload(make_advertising_data()); + gap.setAdvertisingParams(make_advertising_params()); + } + + /** + * Start the advertising process; it ends when a device connects. + */ + void start_advertising() + { + ble_error_t error = _ble_interface.gap().startAdvertising(); + if (error) { + printf("Error %u during gap.startAdvertising.\r\n", error); + } else { + printf("Advertising started.\r\n"); + } + } + + /** + * Schedule processing of events from the BLE middleware in the event queue. + */ + void schedule_ble_events(BLE::OnEventsToProcessCallbackContext *event) + { + _event_queue.call(mbed::callback(&event->ble, &BLE::processEvents)); + } + + /** + * Build data advertised by the BLE interface. + */ + static GapAdvertisingData make_advertising_data(void) + { + static const uint8_t device_name[] = "GattClient"; + GapAdvertisingData advertising_data; + + // add advertising flags + advertising_data.addFlags( + GapAdvertisingData::LE_GENERAL_DISCOVERABLE | + GapAdvertisingData::BREDR_NOT_SUPPORTED + ); + + // add device name + advertising_data.addData( + GapAdvertisingData::COMPLETE_LOCAL_NAME, + device_name, + sizeof(device_name) + ); + + return advertising_data; + } + + /** + * Build advertising parameters used by the BLE interface. + */ + static GapAdvertisingParams make_advertising_params(void) + { + return GapAdvertisingParams( + /* type */ GapAdvertisingParams::ADV_CONNECTABLE_UNDIRECTED, + /* interval */ GapAdvertisingParams::MSEC_TO_ADVERTISEMENT_DURATION_UNITS(500), + /* timeout */ 0 + ); + } + + events::EventQueue &_event_queue; + BLE &_ble_interface; + mbed::Callback<void(BLE&, events::EventQueue&)> _post_init_cb; +}; + + +#endif /* GATT_EXAMPLE_BLE_PROCESS_H_ */ \ No newline at end of file
--- a/source/main.cpp Thu Aug 15 17:00:47 2019 +0100 +++ b/source/main.cpp Thu Jan 16 14:48:30 2020 +0000 @@ -1,5 +1,5 @@ /* mbed Microcontroller Library - * Copyright (c) 2006-2015 ARM Limited + * Copyright (c) 2006-2018 ARM Limited * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,221 +14,566 @@ * limitations under the License. */ -#include <events/mbed_events.h> -#include <mbed.h> +#include <memory> +#include <new> +#include <stdio.h> + +#include "events/EventQueue.h" +#include "platform/NonCopyable.h" + #include "ble/BLE.h" -#include "pretty_printer.h" +#include "ble/Gap.h" +#include "ble/GattClient.h" +#include "ble/GapAdvertisingParams.h" +#include "ble/GapAdvertisingData.h" +#include "ble/GattClient.h" +#include "ble/DiscoveredService.h" +#include "ble/DiscoveredCharacteristic.h" +#include "ble/CharacteristicDescriptorDiscovery.h" -static events::EventQueue event_queue(/* event count */ 16 * EVENTS_EVENT_SIZE); +#include "BLEProcess.h" -/** @deprecated This demo is deprecated and no replacement is currently available. +/** + * Handle discovery of the GATT server. + * + * First the GATT server is discovered in its entirety then each readable + * characteristic is read and the client register to characteristic + * notifications or indication when available. The client report server + * indications and notification until the connection end. */ -MBED_DEPRECATED_SINCE( - "mbed-os-5.11", - "This demo is deprecated and no replacement is currently available." -) -class BeaconDemo : ble::Gap::EventHandler { +class GattClientProcess : private mbed::NonCopyable<GattClientProcess>, + public ble::Gap::EventHandler { + + // Internal typedef to this class type. + // It is used as a shorthand to pass member function as callbacks. + typedef GattClientProcess Self; + + typedef CharacteristicDescriptorDiscovery::DiscoveryCallbackParams_t + DiscoveryCallbackParams_t; + + typedef CharacteristicDescriptorDiscovery::TerminationCallbackParams_t + TerminationCallbackParams_t; + + typedef DiscoveredCharacteristic::Properties_t Properties_t; + public: - BeaconDemo(BLE &ble, events::EventQueue &event_queue) : - _ble(ble), - _event_queue(event_queue), - _adv_data_builder(_adv_buffer) { } + + /** + * Construct an empty client process. + * + * The function start() shall be called to initiate the discovery process. + */ + GattClientProcess() : + _client(NULL), + _connection_handle(), + _characteristics(NULL), + _it(NULL), + _descriptor_handle(0), + _ble_interface(NULL), + _event_queue(NULL) { + } + + ~GattClientProcess() + { + stop(); + } + + void init(BLE &ble_interface, events::EventQueue &event_queue) + { + _ble_interface = &ble_interface; + _event_queue = &event_queue; + _client = &_ble_interface->gattClient(); + + _ble_interface->gap().setEventHandler(this); + } + + /** + * Start the discovery process. + * + * @param[in] client The GattClient instance which will discover the distant + * GATT server. + * @param[in] connection_handle Reference of the connection to the GATT + * server which will be discovered. + */ + void start() + { + // setup the event handlers called during the process + _client->onDataWritten().add(as_cb(&Self::when_descriptor_written)); + _client->onHVX().add(as_cb(&Self::when_characteristic_changed)); - void start() { - _ble.gap().setEventHandler(this); + // The discovery process will invoke when_service_discovered when a + // service is discovered, when_characteristic_discovered when a + // characteristic is discovered and when_service_discovery_ends once the + // discovery process has ended. + _client->onServiceDiscoveryTermination(as_cb(&Self::when_service_discovery_ends)); + ble_error_t error = _client->launchServiceDiscovery( + _connection_handle, + as_cb(&Self::when_service_discovered), + as_cb(&Self::when_characteristic_discovered) + ); + + if (error) { + printf("Error %u returned by _client->launchServiceDiscovery.\r\n", error); + return; + } + + printf("Client process started: initiate service discovery.\r\n"); + } - _ble.init(this, &BeaconDemo::on_init_complete); + /** + * Stop the discovery process and clean the instance. + */ + void stop() + { + if (!_client) { + return; + } - _event_queue.dispatch_forever(); + // unregister event handlers + _client->onDataWritten().detach(as_cb(&Self::when_descriptor_written)); + _client->onHVX().detach(as_cb(&Self::when_characteristic_changed)); + _client->onServiceDiscoveryTermination(NULL); + + // remove discovered characteristics + clear_characteristics(); + + // clean up the instance + _connection_handle = 0; + _characteristics = NULL; + _it = NULL; + _descriptor_handle = 0; + + printf("Client process stopped.\r\n"); } private: /** - * iBeacon payload builder. + * Event handler invoked when a connection is established. * - * This data structure contains the payload of an iBeacon. The payload is - * built at construction time and application code can set up an iBeacon by - * injecting the raw field into the GAP advertising payload as a - * GapAdvertisingData::MANUFACTURER_SPECIFIC_DATA. + * This function setup the connection handle to operate on then start the + * discovery process. */ - union Payload { - /** - * Raw data of the payload. - */ - uint8_t raw[25]; - struct { - /** - * Beacon manufacturer identifier. - */ - uint16_t companyID; - - /** - * Packet ID; Equal to 2 for an iBeacon. - */ - uint8_t ID; - - /** - * Length of the remaining data presents in the payload. - */ - uint8_t len; - - /** - * Beacon UUID. - */ - uint8_t proximityUUID[16]; - - /** - * Beacon Major group ID. - */ - uint16_t majorNumber; - - /** - * Beacon minor ID. - */ - uint16_t minorNumber; + virtual void onConnectionComplete(const ble::ConnectionCompleteEvent &event) + { + _connection_handle = event.getConnectionHandle(); + _event_queue->call(mbed::callback(this, &Self::start)); + } - /** - * Tx power received at 1 meter; in dBm. - */ - uint8_t txPower; - }; - - /** - * Assemble an iBeacon payload. - * - * @param[in] uuid Beacon network ID. iBeacon operators use this value - * to group their iBeacons into a single network, a single region and - * identify their organization among others. - * - * @param[in] majNum Beacon major group ID. iBeacon exploitants may use - * this field to divide the region into subregions, their network into - * subnetworks. - * - * @param[in] minNum Identifier of the Beacon in its subregion. - * - * @param[in] transmitPower Measured transmit power of the beacon at 1 - * meter. Scanners use this parameter to approximate the distance - * to the beacon. - * - * @param[in] companyIDIn ID of the beacon manufacturer. - */ - Payload( - const uint8_t *uuid, - uint16_t majNum, - uint16_t minNum, - uint8_t transmitPower, - uint16_t companyIDIn - ) : companyID(companyIDIn), - ID(0x02), - len(0x15), - majorNumber(__REV16(majNum)), - minorNumber(__REV16(minNum)), - txPower(transmitPower) - { - memcpy(proximityUUID, uuid, 16); + /** + * Stop the discovery process and clean the instance. + */ + virtual void onDisconnectionComplete(const ble::DisconnectionCompleteEvent &event) + { + if (_client && event.getConnectionHandle() == _connection_handle) { + stop(); } - }; - - /** Callback triggered when the ble initialization process has finished */ - void on_init_complete(BLE::InitializationCompleteCallbackContext *params) { - if (params->error != BLE_ERROR_NONE) { - printf("Ble initialization failed."); - return; - } - - print_mac_address(); - - start_advertising(); } - void start_advertising() { - /* Create advertising parameters and payload */ +private: +//////////////////////////////////////////////////////////////////////////////// +// Service and characteristic discovery process. - ble::AdvertisingParameters adv_parameters( - ble::advertising_type_t::CONNECTABLE_UNDIRECTED, - ble::adv_interval_t(ble::millisecond_t(1000)) + /** + * Handle services discovered. + * + * The GattClient invokes this function when a service has been discovered. + * + * @see GattClient::launchServiceDiscovery + */ + void when_service_discovered(const DiscoveredService *discovered_service) + { + // print information of the service discovered + printf("Service discovered: value = "); + print_uuid(discovered_service->getUUID()); + printf(", start = %u, end = %u.\r\n", + discovered_service->getStartHandle(), + discovered_service->getEndHandle() + ); + } + + /** + * Handle characteristics discovered. + * + * The GattClient invoke this function when a characteristic has been + * discovered. + * + * @see GattClient::launchServiceDiscovery + */ + void when_characteristic_discovered(const DiscoveredCharacteristic *discovered_characteristic) + { + // print characteristics properties + printf("\tCharacteristic discovered: uuid = "); + print_uuid(discovered_characteristic->getUUID()); + printf(", properties = "); + print_properties(discovered_characteristic->getProperties()); + printf( + ", decl handle = %u, value handle = %u, last handle = %u.\r\n", + discovered_characteristic->getDeclHandle(), + discovered_characteristic->getValueHandle(), + discovered_characteristic->getLastHandle() ); - _adv_data_builder.setFlags(); - - /** - * The Beacon payload has the following composition: - * 128-Bit / 16byte UUID = E2 0A 39 F4 73 F5 4B C4 A1 2F 17 D1 AD 07 A9 61 - * Major/Minor = 0x1122 / 0x3344 - * Tx Power = 0xC8 = 200, 2's compliment is 256-200 = (-56dB) - * - * Note: please remember to calibrate your beacons TX Power for more accurate results. - */ - static const uint8_t uuid[] = { 0xE2, 0x0A, 0x39, 0xF4, 0x73, 0xF5, 0x4B, 0xC4, - 0xA1, 0x2F, 0x17, 0xD1, 0xAD, 0x07, 0xA9, 0x61 }; - uint16_t major_number = 1122; - uint16_t minor_number = 3344; - uint16_t tx_power = 0xC8; - uint16_t comp_id = 0x004C; - - Payload ibeacon(uuid, major_number, minor_number, tx_power, comp_id); - - _adv_data_builder.setManufacturerSpecificData(ibeacon.raw); - - /* Setup advertising */ - - ble_error_t error = _ble.gap().setAdvertisingParameters( - ble::LEGACY_ADVERTISING_HANDLE, - adv_parameters - ); - - if (error) { - print_error(error, "_ble.gap().setAdvertisingParameters() failed"); - return; - } - - error = _ble.gap().setAdvertisingPayload( - ble::LEGACY_ADVERTISING_HANDLE, - _adv_data_builder.getAdvertisingData() - ); - - if (error) { - print_error(error, "_ble.gap().setAdvertisingPayload() failed"); - return; - } - - /* Start advertising */ - - error = _ble.gap().startAdvertising(ble::LEGACY_ADVERTISING_HANDLE); - - if (error) { - print_error(error, "_ble.gap().startAdvertising() failed"); + // add the characteristic into the list of discovered characteristics + bool success = add_characteristic(discovered_characteristic); + if (!success) { + printf("Error: memory allocation failure while adding the discovered characteristic.\r\n"); + _client->terminateServiceDiscovery(); + stop(); return; } } -private: - /* Event handler */ + /** + * Handle termination of the service and characteristic discovery process. + * + * The GattClient invokes this function when the service and characteristic + * discovery process ends. + * + * @see GattClient::onServiceDiscoveryTermination + */ + void when_service_discovery_ends(Gap::Handle_t connection_handle) + { + if (!_characteristics) { + printf("No characteristics discovered, end of the process.\r\n"); + return; + } + + printf("All services and characteristics discovered, process them.\r\n"); + + // reset iterator and start processing characteristics in order + _it = NULL; + _event_queue->call(mbed::callback(this, &Self::process_next_characteristic)); + } + +//////////////////////////////////////////////////////////////////////////////// +// Processing of characteristics based on their properties. + + /** + * Process the characteristics discovered. + * + * - If the characteristic is readable then read its value and print it. Then + * - If the characteristic can emit notification or indication then discover + * the characteristic CCCD and subscribe to the server initiated event. + * - Otherwise skip the characteristic processing. + */ + void process_next_characteristic(void) + { + if (!_it) { + _it = _characteristics; + } else { + _it = _it->next; + } + + while (_it) { + Properties_t properties = _it->value.getProperties(); + + if (properties.read()) { + read_characteristic(_it->value); + return; + } else if(properties.notify() || properties.indicate()) { + discover_descriptors(_it->value); + return; + } else { + printf( + "Skip processing of characteristic %u\r\n", + _it->value.getValueHandle() + ); + _it = _it->next; + } + } + + printf("All characteristics discovered have been processed.\r\n"); + } + + /** + * Initate the read of the characteristic in input. + * + * The completion of the operation will happens in when_characteristic_read() + */ + void read_characteristic(const DiscoveredCharacteristic &characteristic) + { + printf("Initiating read at %u.\r\n", characteristic.getValueHandle()); + ble_error_t error = characteristic.read( + 0, as_cb(&Self::when_characteristic_read) + ); - void onDisconnectionComplete(const ble::DisconnectionCompleteEvent&) { - _ble.gap().startAdvertising(ble::LEGACY_ADVERTISING_HANDLE); + if (error) { + printf( + "Error: cannot initiate read at %u due to %u\r\n", + characteristic.getValueHandle(), error + ); + stop(); + } + } + + /** + * Handle the reception of a read response. + * + * If the characteristic can emit notification or indication then start the + * discovery of the the characteristic descriptors then subscribe to the + * server initiated event by writing the CCCD discovered. Otherwise start + * the processing of the next characteristic discovered in the server. + */ + void when_characteristic_read(const GattReadCallbackParams *read_event) + { + printf("\tCharacteristic value at %u equal to: ", read_event->handle); + for (size_t i = 0; i < read_event->len; ++i) { + printf("0x%02X ", read_event->data[i]); + } + printf(".\r\n"); + + Properties_t properties = _it->value.getProperties(); + + if(properties.notify() || properties.indicate()) { + discover_descriptors(_it->value); + } else { + process_next_characteristic(); + } + } + + /** + * Initiate the discovery of the descriptors of the characteristic in input. + * + * When a descriptor is discovered, the function when_descriptor_discovered + * is invoked. + */ + void discover_descriptors(const DiscoveredCharacteristic &characteristic) + { + printf("Initiating descriptor discovery of %u.\r\n", characteristic.getValueHandle()); + + _descriptor_handle = 0; + ble_error_t error = characteristic.discoverDescriptors( + as_cb(&Self::when_descriptor_discovered), + as_cb(&Self::when_descriptor_discovery_ends) + ); + + if (error) { + printf( + "Error: cannot initiate discovery of %04X due to %u.\r\n", + characteristic.getValueHandle(), error + ); + stop(); + } + } + + /** + * Handle the discovery of the characteristic descriptors. + * + * If the descriptor found is a CCCD then stop the discovery. Once the + * process has ended subscribe to server initiated events by writing the + * value of the CCCD. + */ + void when_descriptor_discovered(const DiscoveryCallbackParams_t* event) + { + printf("\tDescriptor discovered at %u, UUID: ", event->descriptor.getAttributeHandle()); + print_uuid(event->descriptor.getUUID()); + printf(".\r\n"); + + if (event->descriptor.getUUID() == BLE_UUID_DESCRIPTOR_CLIENT_CHAR_CONFIG) { + _descriptor_handle = event->descriptor.getAttributeHandle(); + _client->terminateCharacteristicDescriptorDiscovery( + event->characteristic + ); + } } -private: - BLE &_ble; - events::EventQueue &_event_queue; + /** + * If a CCCD has been found subscribe to server initiated events by writing + * its value. + */ + void when_descriptor_discovery_ends(const TerminationCallbackParams_t *event) { + // shall never happen but happen with android devices ... + // process the next charateristic + if (!_descriptor_handle) { + printf("\tWarning: characteristic with notify or indicate attribute without CCCD.\r\n"); + process_next_characteristic(); + return; + } + + Properties_t properties = _it->value.getProperties(); + + uint16_t cccd_value = + (properties.notify() << 0) | (properties.indicate() << 1); + + ble_error_t error = _client->write( + GattClient::GATT_OP_WRITE_REQ, + _connection_handle, + _descriptor_handle, + sizeof(cccd_value), + reinterpret_cast<uint8_t*>(&cccd_value) + ); + + if (error) { + printf( + "Error: cannot initiate write of CCCD %u due to %u.\r\n", + _descriptor_handle, error + ); + stop(); + } + } + + /** + * Called when the CCCD has been written. + */ + void when_descriptor_written(const GattWriteCallbackParams* event) + { + // should never happen + if (!_descriptor_handle) { + printf("\tError: received write response to unsolicited request.\r\n"); + stop(); + return; + } + + printf("\tCCCD at %u written.\r\n", _descriptor_handle); + _descriptor_handle = 0; + process_next_characteristic(); + } + + /** + * Print the updated value of the characteristic. + * + * This function is called when the server emits a notification or an + * indication of a characteristic value the client has subscribed to. + * + * @see GattClient::onHVX() + */ + void when_characteristic_changed(const GattHVXCallbackParams* event) + { + printf("Change on attribute %u: new value = ", event->handle); + for (size_t i = 0; i < event->len; ++i) { + printf("0x%02X ", event->data[i]); + } + printf(".\r\n"); + } + + struct DiscoveredCharacteristicNode { + DiscoveredCharacteristicNode(const DiscoveredCharacteristic &c) : + value(c), next(NULL) { } + + DiscoveredCharacteristic value; + DiscoveredCharacteristicNode *next; + }; + + /** + * Add a discovered characteristic into the list of discovered characteristics. + */ + bool add_characteristic(const DiscoveredCharacteristic *characteristic) + { + DiscoveredCharacteristicNode* new_node = + new(std::nothrow) DiscoveredCharacteristicNode(*characteristic); - uint8_t _adv_buffer[ble::LEGACY_ADVERTISING_MAX_SIZE]; - ble::AdvertisingDataBuilder _adv_data_builder; + if (new_node == NULL) { + printf("Error while allocating a new characteristic.\r\n"); + return false; + } + + if (_characteristics == NULL) { + _characteristics = new_node; + } else { + DiscoveredCharacteristicNode* c = _characteristics; + while(c->next) { + c = c->next; + } + c->next = new_node; + } + + return true; + } + + /** + * Clear the list of discovered characteristics. + */ + void clear_characteristics(void) + { + DiscoveredCharacteristicNode *c= _characteristics; + + while (c) { + DiscoveredCharacteristicNode *n = c->next; + delete c; + c = n; + } + } + + /** + * Helper to construct an event handler from a member function of this + * instance. + */ + template<typename ContextType> + FunctionPointerWithContext<ContextType> as_cb( + void (Self::*member)(ContextType context) + ) { + return makeFunctionPointer(this, member); + } + + /** + * Print the value of a UUID. + */ + static void print_uuid(const UUID &uuid) + { + const uint8_t *uuid_value = uuid.getBaseUUID(); + + // UUIDs are in little endian, print them in big endian + for (size_t i = 0; i < uuid.getLen(); ++i) { + printf("%02X", uuid_value[(uuid.getLen() - 1) - i]); + } + } + + /** + * Print the value of a characteristic properties. + */ + static void print_properties(const Properties_t &properties) + { + const struct { + bool (Properties_t::*fn)() const; + const char* str; + } prop_to_str[] = { + { &Properties_t::broadcast, "broadcast" }, + { &Properties_t::read, "read" }, + { &Properties_t::writeWoResp, "writeWoResp" }, + { &Properties_t::write, "write" }, + { &Properties_t::notify, "notify" }, + { &Properties_t::indicate, "indicate" }, + { &Properties_t::authSignedWrite, "authSignedWrite" } + }; + + printf("["); + for (size_t i = 0; i < (sizeof(prop_to_str) / sizeof(prop_to_str[0])); ++i) { + if ((properties.*(prop_to_str[i].fn))()) { + printf(" %s", prop_to_str[i].str); + } + } + printf(" ]"); + } + + GattClient *_client; + Gap::Handle_t _connection_handle; + DiscoveredCharacteristicNode *_characteristics; + DiscoveredCharacteristicNode *_it; + GattAttribute::Handle_t _descriptor_handle; + BLE *_ble_interface; + events::EventQueue *_event_queue; }; -/** Schedule processing of events from the BLE middleware in the event queue. */ -void schedule_ble_events(BLE::OnEventsToProcessCallbackContext *context) { - event_queue.call(Callback<void()>(&context->ble, &BLE::processEvents)); -} + +int main() { + + BLE &ble_interface = BLE::Instance(); + events::EventQueue event_queue; + BLEProcess ble_process(event_queue, ble_interface); + GattClientProcess gatt_client_process; -int main() -{ - BLE &ble = BLE::Instance(); - ble.onEventsToProcess(schedule_ble_events); + // Register GattClientProcess::init in the ble_process; this function will + // be called once the ble_interface is initialized. + ble_process.on_init( + mbed::callback(&gatt_client_process, &GattClientProcess::init) + ); - BeaconDemo demo(ble, event_queue); - demo.start(); + // bind the event queue to the ble interface, initialize the interface + // and start advertising + ble_process.start(); + + // Process the event queue. + event_queue.dispatch_forever(); return 0; -} +} \ No newline at end of file