Demonstration of possible usage of the GattServer

Dependents:   mbed-os-example-ble-GattServer_ECG

Files at this revision

API Documentation at this revision

Comitter:
mbed_official
Date:
Mon Jan 14 10:45:40 2019 +0000
Parent:
13:21b02b0b2cb2
Child:
15:084c8c407889
Commit message:
Merge pull request #208 from ARMmbed/mbed-os-5.11.0-oob

Mbed OS 5.11.0
.
Commit copied from https://github.com/ARMmbed/mbed-os-example-ble

Changed in this revision

BLEProcess.h Show diff for this revision Revisions of this file
main.cpp Show diff for this revision Revisions of this file
mbed-os.lib Show annotated file Show diff for this revision Revisions of this file
mbed_app.json Show annotated file Show diff for this revision Revisions of this file
shields/TARGET_CORDIO_BLUENRG.lib Show annotated file Show diff for this revision Revisions of this file
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
--- a/BLEProcess.h	Fri Dec 14 13:15:33 2018 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,206 +0,0 @@
-/* mbed Microcontroller Library
- * Copyright (c) 2017 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_SERVER_EXAMPLE_BLE_PROCESS_H_
-#define GATT_SERVER_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 adn 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();
-    }
-
-   /**
-     * 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;
-    }
-
-    /**
-     * 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.");
-        }
-    }
-
-private:
-
-    /**
-     * 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));
-    }
-
-    /**
-     * 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);
-        }
-    }
-
-    void when_connection(const Gap::ConnectionCallbackParams_t *connection_event)
-    {
-        printf("Connected.\r\n");
-    }
-
-    void when_disconnection(const Gap::DisconnectionCallbackParams_t *event)
-    {
-        printf("Disconnected.\r\n");
-        start_advertising();
-    }
-
-    void start_advertising(void)
-    {
-        ble_error_t error = _ble_interface.gap().startAdvertising();
-        if (error) {
-            printf("Error %u during gap.startAdvertising.\r\n", error);
-            return;
-        } else {
-            printf("Advertising started.\r\n");
-        }
-    }
-
-    static GapAdvertisingData make_advertising_data(void)
-    {
-        static const uint8_t device_name[] = "GattServer";
-        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;
-    }
-
-    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_SERVER_EXAMPLE_BLE_PROCESS_H_ */
--- a/main.cpp	Fri Dec 14 13:15:33 2018 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,411 +0,0 @@
-/* mbed Microcontroller Library
- * Copyright (c) 2017 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 <stdio.h>
-
-#include "platform/Callback.h"
-#include "events/EventQueue.h"
-#include "platform/NonCopyable.h"
-
-#include "ble/BLE.h"
-#include "ble/Gap.h"
-#include "ble/GattClient.h"
-#include "ble/GapAdvertisingParams.h"
-#include "ble/GapAdvertisingData.h"
-#include "ble/GattServer.h"
-#include "BLEProcess.h"
-
-using mbed::callback;
-
-/**
- * A Clock service that demonstrate the GattServer features.
- *
- * The clock service host three characteristics that model the current hour,
- * minute and second of the clock. The value of the second characteristic is
- * incremented automatically by the system.
- *
- * A client can subscribe to updates of the clock characteristics and get
- * notified when one of the value is changed. Clients can also change value of
- * the second, minute and hour characteristric.
- */
-class ClockService {
-    typedef ClockService Self;
-
-public:
-    ClockService() :
-        _hour_char("485f4145-52b9-4644-af1f-7a6b9322490f", 0),
-        _minute_char("0a924ca7-87cd-4699-a3bd-abdcd9cf126a", 0),
-        _second_char("8dd6a1b7-bc75-4741-8a26-264af75807de", 0),
-        _clock_service(
-            /* uuid */ "51311102-030e-485f-b122-f8f381aa84ed",
-            /* characteristics */ _clock_characteristics,
-            /* numCharacteristics */ sizeof(_clock_characteristics) /
-                                     sizeof(_clock_characteristics[0])
-        ),
-        _server(NULL),
-        _event_queue(NULL)
-    {
-        // update internal pointers (value, descriptors and characteristics array)
-        _clock_characteristics[0] = &_hour_char;
-        _clock_characteristics[1] = &_minute_char;
-        _clock_characteristics[2] = &_second_char;
-
-        // setup authorization handlers
-        _hour_char.setWriteAuthorizationCallback(this, &Self::authorize_client_write);
-        _minute_char.setWriteAuthorizationCallback(this, &Self::authorize_client_write);
-        _second_char.setWriteAuthorizationCallback(this, &Self::authorize_client_write);
-    }
-
-
-
-    void start(BLE &ble_interface, events::EventQueue &event_queue)
-    {
-         if (_event_queue) {
-            return;
-        }
-
-        _server = &ble_interface.gattServer();
-        _event_queue = &event_queue;
-
-        // register the service
-        printf("Adding demo service\r\n");
-        ble_error_t err = _server->addService(_clock_service);
-
-        if (err) {
-            printf("Error %u during demo service registration.\r\n", err);
-            return;
-        }
-
-        // read write handler
-        _server->onDataSent(as_cb(&Self::when_data_sent));
-        _server->onDataWritten(as_cb(&Self::when_data_written));
-        _server->onDataRead(as_cb(&Self::when_data_read));
-
-        // updates subscribtion handlers
-        _server->onUpdatesEnabled(as_cb(&Self::when_update_enabled));
-        _server->onUpdatesDisabled(as_cb(&Self::when_update_disabled));
-        _server->onConfirmationReceived(as_cb(&Self::when_confirmation_received));
-
-        // print the handles
-        printf("clock service registered\r\n");
-        printf("service handle: %u\r\n", _clock_service.getHandle());
-        printf("\thour characteristic value handle %u\r\n", _hour_char.getValueHandle());
-        printf("\tminute characteristic value handle %u\r\n", _minute_char.getValueHandle());
-        printf("\tsecond characteristic value handle %u\r\n", _second_char.getValueHandle());
-
-        _event_queue->call_every(1000 /* ms */, callback(this, &Self::increment_second));
-    }
-
-private:
-
-    /**
-     * Handler called when a notification or an indication has been sent.
-     */
-    void when_data_sent(unsigned count)
-    {
-        printf("sent %u updates\r\n", count);
-    }
-
-    /**
-     * Handler called after an attribute has been written.
-     */
-    void when_data_written(const GattWriteCallbackParams *e)
-    {
-        printf("data written:\r\n");
-        printf("\tconnection handle: %u\r\n", e->connHandle);
-        printf("\tattribute handle: %u", e->handle);
-        if (e->handle == _hour_char.getValueHandle()) {
-            printf(" (hour characteristic)\r\n");
-        } else if (e->handle == _minute_char.getValueHandle()) {
-            printf(" (minute characteristic)\r\n");
-        } else if (e->handle == _second_char.getValueHandle()) {
-            printf(" (second characteristic)\r\n");
-        } else {
-            printf("\r\n");
-        }
-        printf("\twrite operation: %u\r\n", e->writeOp);
-        printf("\toffset: %u\r\n", e->offset);
-        printf("\tlength: %u\r\n", e->len);
-        printf("\t data: ");
-
-        for (size_t i = 0; i < e->len; ++i) {
-            printf("%02X", e->data[i]);
-        }
-
-        printf("\r\n");
-    }
-
-    /**
-     * Handler called after an attribute has been read.
-     */
-    void when_data_read(const GattReadCallbackParams *e)
-    {
-        printf("data read:\r\n");
-        printf("\tconnection handle: %u\r\n", e->connHandle);
-        printf("\tattribute handle: %u", e->handle);
-        if (e->handle == _hour_char.getValueHandle()) {
-            printf(" (hour characteristic)\r\n");
-        } else if (e->handle == _minute_char.getValueHandle()) {
-            printf(" (minute characteristic)\r\n");
-        } else if (e->handle == _second_char.getValueHandle()) {
-            printf(" (second characteristic)\r\n");
-        } else {
-            printf("\r\n");
-        }
-    }
-
-    /**
-     * Handler called after a client has subscribed to notification or indication.
-     *
-     * @param handle Handle of the characteristic value affected by the change.
-     */
-    void when_update_enabled(GattAttribute::Handle_t handle)
-    {
-        printf("update enabled on handle %d\r\n", handle);
-    }
-
-    /**
-     * Handler called after a client has cancelled his subscription from
-     * notification or indication.
-     *
-     * @param handle Handle of the characteristic value affected by the change.
-     */
-    void when_update_disabled(GattAttribute::Handle_t handle)
-    {
-        printf("update disabled on handle %d\r\n", handle);
-    }
-
-    /**
-     * Handler called when an indication confirmation has been received.
-     *
-     * @param handle Handle of the characteristic value that has emitted the
-     * indication.
-     */
-    void when_confirmation_received(GattAttribute::Handle_t handle)
-    {
-        printf("confirmation received on handle %d\r\n", handle);
-    }
-
-    /**
-     * Handler called when a write request is received.
-     *
-     * This handler verify that the value submitted by the client is valid before
-     * authorizing the operation.
-     */
-    void authorize_client_write(GattWriteAuthCallbackParams *e)
-    {
-        printf("characteristic %u write authorization\r\n", e->handle);
-
-        if (e->offset != 0) {
-            printf("Error invalid offset\r\n");
-            e->authorizationReply = AUTH_CALLBACK_REPLY_ATTERR_INVALID_OFFSET;
-            return;
-        }
-
-        if (e->len != 1) {
-            printf("Error invalid len\r\n");
-            e->authorizationReply = AUTH_CALLBACK_REPLY_ATTERR_INVALID_ATT_VAL_LENGTH;
-            return;
-        }
-
-        if ((e->data[0] >= 60) ||
-            ((e->data[0] >= 24) && (e->handle == _hour_char.getValueHandle()))) {
-            printf("Error invalid data\r\n");
-            e->authorizationReply = AUTH_CALLBACK_REPLY_ATTERR_WRITE_NOT_PERMITTED;
-            return;
-        }
-
-        e->authorizationReply = AUTH_CALLBACK_REPLY_SUCCESS;
-    }
-
-    /**
-     * Increment the second counter.
-     */
-    void increment_second(void)
-    {
-        uint8_t second = 0;
-        ble_error_t err = _second_char.get(*_server, second);
-        if (err) {
-            printf("read of the second value returned error %u\r\n", err);
-            return;
-        }
-
-        second = (second + 1) % 60;
-
-        err = _second_char.set(*_server, second);
-        if (err) {
-            printf("write of the second value returned error %u\r\n", err);
-            return;
-        }
-
-        if (second == 0) {
-            increment_minute();
-        }
-    }
-
-    /**
-     * Increment the minute counter.
-     */
-    void increment_minute(void)
-    {
-        uint8_t minute = 0;
-        ble_error_t err = _minute_char.get(*_server, minute);
-        if (err) {
-            printf("read of the minute value returned error %u\r\n", err);
-            return;
-        }
-
-        minute = (minute + 1) % 60;
-
-        err = _minute_char.set(*_server, minute);
-        if (err) {
-            printf("write of the minute value returned error %u\r\n", err);
-            return;
-        }
-
-        if (minute == 0) {
-            increment_hour();
-        }
-    }
-
-    /**
-     * Increment the hour counter.
-     */
-    void increment_hour(void)
-    {
-        uint8_t hour = 0;
-        ble_error_t err = _hour_char.get(*_server, hour);
-        if (err) {
-            printf("read of the hour value returned error %u\r\n", err);
-            return;
-        }
-
-        hour = (hour + 1) % 24;
-
-        err = _hour_char.set(*_server, hour);
-        if (err) {
-            printf("write of the hour value returned error %u\r\n", err);
-            return;
-        }
-    }
-
-private:
-    /**
-     * Helper that construct an event handler from a member function of this
-     * instance.
-     */
-    template<typename Arg>
-    FunctionPointerWithContext<Arg> as_cb(void (Self::*member)(Arg))
-    {
-        return makeFunctionPointer(this, member);
-    }
-
-    /**
-     * Read, Write, Notify, Indicate  Characteristic declaration helper.
-     *
-     * @tparam T type of data held by the characteristic.
-     */
-    template<typename T>
-    class ReadWriteNotifyIndicateCharacteristic : public GattCharacteristic {
-    public:
-        /**
-         * Construct a characteristic that can be read or written and emit
-         * notification or indication.
-         *
-         * @param[in] uuid The UUID of the characteristic.
-         * @param[in] initial_value Initial value contained by the characteristic.
-         */
-        ReadWriteNotifyIndicateCharacteristic(const UUID & uuid, const T& initial_value) :
-            GattCharacteristic(
-                /* UUID */ uuid,
-                /* Initial value */ &_value,
-                /* Value size */ sizeof(_value),
-                /* Value capacity */ sizeof(_value),
-                /* Properties */ GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_READ |
-                                GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_WRITE |
-                                GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_NOTIFY |
-                                GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_INDICATE,
-                /* Descriptors */ NULL,
-                /* Num descriptors */ 0,
-                /* variable len */ false
-            ),
-            _value(initial_value) {
-        }
-
-        /**
-         * Get the value of this characteristic.
-         *
-         * @param[in] server GattServer instance that contain the characteristic
-         * value.
-         * @param[in] dst Variable that will receive the characteristic value.
-         *
-         * @return BLE_ERROR_NONE in case of success or an appropriate error code.
-         */
-        ble_error_t get(GattServer &server, T& dst) const
-        {
-            uint16_t value_length = sizeof(dst);
-            return server.read(getValueHandle(), &dst, &value_length);
-        }
-
-        /**
-         * Assign a new value to this characteristic.
-         *
-         * @param[in] server GattServer instance that will receive the new value.
-         * @param[in] value The new value to set.
-         * @param[in] local_only Flag that determine if the change should be kept
-         * locally or forwarded to subscribed clients.
-         */
-        ble_error_t set(
-            GattServer &server, const uint8_t &value, bool local_only = false
-        ) const {
-            return server.write(getValueHandle(), &value, sizeof(value), local_only);
-        }
-
-    private:
-        uint8_t _value;
-    };
-
-    ReadWriteNotifyIndicateCharacteristic<uint8_t> _hour_char;
-    ReadWriteNotifyIndicateCharacteristic<uint8_t> _minute_char;
-    ReadWriteNotifyIndicateCharacteristic<uint8_t> _second_char;
-
-    // list of the characteristics of the clock service
-    GattCharacteristic* _clock_characteristics[3];
-
-    // demo service
-    GattService _clock_service;
-
-    GattServer* _server;
-    events::EventQueue *_event_queue;
-};
-
-int main() {
-    BLE &ble_interface = BLE::Instance();
-    events::EventQueue event_queue;
-    ClockService demo_service;
-    BLEProcess ble_process(event_queue, ble_interface);
-
-    ble_process.on_init(callback(&demo_service, &ClockService::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;
-}
--- a/mbed-os.lib	Fri Dec 14 13:15:33 2018 +0000
+++ b/mbed-os.lib	Mon Jan 14 10:45:40 2019 +0000
@@ -1,1 +1,1 @@
-https://github.com/ARMmbed/mbed-os/#2fd0c5cfbd83fce62da6308f9d64c0ab64e1f0d6
+https://github.com/ARMmbed/mbed-os/#6a0a86538c0b9b2bfcc4583b1e2b7fea8f4e71e9
--- a/mbed_app.json	Fri Dec 14 13:15:33 2018 +0000
+++ b/mbed_app.json	Mon Jan 14 10:45:40 2019 +0000
@@ -11,6 +11,16 @@
         "DISCO_L475VG_IOT01A": {
             "target.features_add": ["BLE"],
             "target.extra_labels_add": ["CORDIO", "CORDIO_BLUENRG"]
+        },
+        "NRF52840_DK": {
+            "target.features_add": ["BLE"],
+            "target.extra_labels_add": ["CORDIO", "CORDIO_LL", "SOFTDEVICE_NONE", "NORDIC_CORDIO"],
+            "target.extra_labels_remove": ["SOFTDEVICE_COMMON", "SOFTDEVICE_S140_FULL", "NORDIC_SOFTDEVICE"]
+        },
+        "NRF52_DK": {
+            "target.features_add": ["BLE"],
+            "target.extra_labels_add": ["CORDIO", "CORDIO_LL", "SOFTDEVICE_NONE", "NORDIC_CORDIO"],
+            "target.extra_labels_remove": ["SOFTDEVICE_COMMON", "SOFTDEVICE_S132_FULL", "NORDIC_SOFTDEVICE"]
         }
     }
-}
\ No newline at end of file
+}
--- a/shields/TARGET_CORDIO_BLUENRG.lib	Fri Dec 14 13:15:33 2018 +0000
+++ b/shields/TARGET_CORDIO_BLUENRG.lib	Mon Jan 14 10:45:40 2019 +0000
@@ -1,1 +1,1 @@
-https://github.com/ARMmbed/cordio-ble-x-nucleo-idb0xa1/#51f60dfea514e35e5aa13c8e24005ecadc24a9f5
+https://github.com/ARMmbed/cordio-ble-x-nucleo-idb0xa1/#811f3fea7aa8083c0bbf378e1b51a8b131d7efcc
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/source/BLEProcess.h	Mon Jan 14 10:45:40 2019 +0000
@@ -0,0 +1,206 @@
+/* mbed Microcontroller Library
+ * Copyright (c) 2017 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_SERVER_EXAMPLE_BLE_PROCESS_H_
+#define GATT_SERVER_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 adn 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();
+    }
+
+   /**
+     * 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;
+    }
+
+    /**
+     * 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.");
+        }
+    }
+
+private:
+
+    /**
+     * 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));
+    }
+
+    /**
+     * 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);
+        }
+    }
+
+    void when_connection(const Gap::ConnectionCallbackParams_t *connection_event)
+    {
+        printf("Connected.\r\n");
+    }
+
+    void when_disconnection(const Gap::DisconnectionCallbackParams_t *event)
+    {
+        printf("Disconnected.\r\n");
+        start_advertising();
+    }
+
+    void start_advertising(void)
+    {
+        ble_error_t error = _ble_interface.gap().startAdvertising();
+        if (error) {
+            printf("Error %u during gap.startAdvertising.\r\n", error);
+            return;
+        } else {
+            printf("Advertising started.\r\n");
+        }
+    }
+
+    static GapAdvertisingData make_advertising_data(void)
+    {
+        static const uint8_t device_name[] = "GattServer";
+        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;
+    }
+
+    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_SERVER_EXAMPLE_BLE_PROCESS_H_ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/source/main.cpp	Mon Jan 14 10:45:40 2019 +0000
@@ -0,0 +1,411 @@
+/* mbed Microcontroller Library
+ * Copyright (c) 2017 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 <stdio.h>
+
+#include "platform/Callback.h"
+#include "events/EventQueue.h"
+#include "platform/NonCopyable.h"
+
+#include "ble/BLE.h"
+#include "ble/Gap.h"
+#include "ble/GattClient.h"
+#include "ble/GapAdvertisingParams.h"
+#include "ble/GapAdvertisingData.h"
+#include "ble/GattServer.h"
+#include "BLEProcess.h"
+
+using mbed::callback;
+
+/**
+ * A Clock service that demonstrate the GattServer features.
+ *
+ * The clock service host three characteristics that model the current hour,
+ * minute and second of the clock. The value of the second characteristic is
+ * incremented automatically by the system.
+ *
+ * A client can subscribe to updates of the clock characteristics and get
+ * notified when one of the value is changed. Clients can also change value of
+ * the second, minute and hour characteristric.
+ */
+class ClockService {
+    typedef ClockService Self;
+
+public:
+    ClockService() :
+        _hour_char("485f4145-52b9-4644-af1f-7a6b9322490f", 0),
+        _minute_char("0a924ca7-87cd-4699-a3bd-abdcd9cf126a", 0),
+        _second_char("8dd6a1b7-bc75-4741-8a26-264af75807de", 0),
+        _clock_service(
+            /* uuid */ "51311102-030e-485f-b122-f8f381aa84ed",
+            /* characteristics */ _clock_characteristics,
+            /* numCharacteristics */ sizeof(_clock_characteristics) /
+                                     sizeof(_clock_characteristics[0])
+        ),
+        _server(NULL),
+        _event_queue(NULL)
+    {
+        // update internal pointers (value, descriptors and characteristics array)
+        _clock_characteristics[0] = &_hour_char;
+        _clock_characteristics[1] = &_minute_char;
+        _clock_characteristics[2] = &_second_char;
+
+        // setup authorization handlers
+        _hour_char.setWriteAuthorizationCallback(this, &Self::authorize_client_write);
+        _minute_char.setWriteAuthorizationCallback(this, &Self::authorize_client_write);
+        _second_char.setWriteAuthorizationCallback(this, &Self::authorize_client_write);
+    }
+
+
+
+    void start(BLE &ble_interface, events::EventQueue &event_queue)
+    {
+         if (_event_queue) {
+            return;
+        }
+
+        _server = &ble_interface.gattServer();
+        _event_queue = &event_queue;
+
+        // register the service
+        printf("Adding demo service\r\n");
+        ble_error_t err = _server->addService(_clock_service);
+
+        if (err) {
+            printf("Error %u during demo service registration.\r\n", err);
+            return;
+        }
+
+        // read write handler
+        _server->onDataSent(as_cb(&Self::when_data_sent));
+        _server->onDataWritten(as_cb(&Self::when_data_written));
+        _server->onDataRead(as_cb(&Self::when_data_read));
+
+        // updates subscribtion handlers
+        _server->onUpdatesEnabled(as_cb(&Self::when_update_enabled));
+        _server->onUpdatesDisabled(as_cb(&Self::when_update_disabled));
+        _server->onConfirmationReceived(as_cb(&Self::when_confirmation_received));
+
+        // print the handles
+        printf("clock service registered\r\n");
+        printf("service handle: %u\r\n", _clock_service.getHandle());
+        printf("\thour characteristic value handle %u\r\n", _hour_char.getValueHandle());
+        printf("\tminute characteristic value handle %u\r\n", _minute_char.getValueHandle());
+        printf("\tsecond characteristic value handle %u\r\n", _second_char.getValueHandle());
+
+        _event_queue->call_every(1000 /* ms */, callback(this, &Self::increment_second));
+    }
+
+private:
+
+    /**
+     * Handler called when a notification or an indication has been sent.
+     */
+    void when_data_sent(unsigned count)
+    {
+        printf("sent %u updates\r\n", count);
+    }
+
+    /**
+     * Handler called after an attribute has been written.
+     */
+    void when_data_written(const GattWriteCallbackParams *e)
+    {
+        printf("data written:\r\n");
+        printf("\tconnection handle: %u\r\n", e->connHandle);
+        printf("\tattribute handle: %u", e->handle);
+        if (e->handle == _hour_char.getValueHandle()) {
+            printf(" (hour characteristic)\r\n");
+        } else if (e->handle == _minute_char.getValueHandle()) {
+            printf(" (minute characteristic)\r\n");
+        } else if (e->handle == _second_char.getValueHandle()) {
+            printf(" (second characteristic)\r\n");
+        } else {
+            printf("\r\n");
+        }
+        printf("\twrite operation: %u\r\n", e->writeOp);
+        printf("\toffset: %u\r\n", e->offset);
+        printf("\tlength: %u\r\n", e->len);
+        printf("\t data: ");
+
+        for (size_t i = 0; i < e->len; ++i) {
+            printf("%02X", e->data[i]);
+        }
+
+        printf("\r\n");
+    }
+
+    /**
+     * Handler called after an attribute has been read.
+     */
+    void when_data_read(const GattReadCallbackParams *e)
+    {
+        printf("data read:\r\n");
+        printf("\tconnection handle: %u\r\n", e->connHandle);
+        printf("\tattribute handle: %u", e->handle);
+        if (e->handle == _hour_char.getValueHandle()) {
+            printf(" (hour characteristic)\r\n");
+        } else if (e->handle == _minute_char.getValueHandle()) {
+            printf(" (minute characteristic)\r\n");
+        } else if (e->handle == _second_char.getValueHandle()) {
+            printf(" (second characteristic)\r\n");
+        } else {
+            printf("\r\n");
+        }
+    }
+
+    /**
+     * Handler called after a client has subscribed to notification or indication.
+     *
+     * @param handle Handle of the characteristic value affected by the change.
+     */
+    void when_update_enabled(GattAttribute::Handle_t handle)
+    {
+        printf("update enabled on handle %d\r\n", handle);
+    }
+
+    /**
+     * Handler called after a client has cancelled his subscription from
+     * notification or indication.
+     *
+     * @param handle Handle of the characteristic value affected by the change.
+     */
+    void when_update_disabled(GattAttribute::Handle_t handle)
+    {
+        printf("update disabled on handle %d\r\n", handle);
+    }
+
+    /**
+     * Handler called when an indication confirmation has been received.
+     *
+     * @param handle Handle of the characteristic value that has emitted the
+     * indication.
+     */
+    void when_confirmation_received(GattAttribute::Handle_t handle)
+    {
+        printf("confirmation received on handle %d\r\n", handle);
+    }
+
+    /**
+     * Handler called when a write request is received.
+     *
+     * This handler verify that the value submitted by the client is valid before
+     * authorizing the operation.
+     */
+    void authorize_client_write(GattWriteAuthCallbackParams *e)
+    {
+        printf("characteristic %u write authorization\r\n", e->handle);
+
+        if (e->offset != 0) {
+            printf("Error invalid offset\r\n");
+            e->authorizationReply = AUTH_CALLBACK_REPLY_ATTERR_INVALID_OFFSET;
+            return;
+        }
+
+        if (e->len != 1) {
+            printf("Error invalid len\r\n");
+            e->authorizationReply = AUTH_CALLBACK_REPLY_ATTERR_INVALID_ATT_VAL_LENGTH;
+            return;
+        }
+
+        if ((e->data[0] >= 60) ||
+            ((e->data[0] >= 24) && (e->handle == _hour_char.getValueHandle()))) {
+            printf("Error invalid data\r\n");
+            e->authorizationReply = AUTH_CALLBACK_REPLY_ATTERR_WRITE_NOT_PERMITTED;
+            return;
+        }
+
+        e->authorizationReply = AUTH_CALLBACK_REPLY_SUCCESS;
+    }
+
+    /**
+     * Increment the second counter.
+     */
+    void increment_second(void)
+    {
+        uint8_t second = 0;
+        ble_error_t err = _second_char.get(*_server, second);
+        if (err) {
+            printf("read of the second value returned error %u\r\n", err);
+            return;
+        }
+
+        second = (second + 1) % 60;
+
+        err = _second_char.set(*_server, second);
+        if (err) {
+            printf("write of the second value returned error %u\r\n", err);
+            return;
+        }
+
+        if (second == 0) {
+            increment_minute();
+        }
+    }
+
+    /**
+     * Increment the minute counter.
+     */
+    void increment_minute(void)
+    {
+        uint8_t minute = 0;
+        ble_error_t err = _minute_char.get(*_server, minute);
+        if (err) {
+            printf("read of the minute value returned error %u\r\n", err);
+            return;
+        }
+
+        minute = (minute + 1) % 60;
+
+        err = _minute_char.set(*_server, minute);
+        if (err) {
+            printf("write of the minute value returned error %u\r\n", err);
+            return;
+        }
+
+        if (minute == 0) {
+            increment_hour();
+        }
+    }
+
+    /**
+     * Increment the hour counter.
+     */
+    void increment_hour(void)
+    {
+        uint8_t hour = 0;
+        ble_error_t err = _hour_char.get(*_server, hour);
+        if (err) {
+            printf("read of the hour value returned error %u\r\n", err);
+            return;
+        }
+
+        hour = (hour + 1) % 24;
+
+        err = _hour_char.set(*_server, hour);
+        if (err) {
+            printf("write of the hour value returned error %u\r\n", err);
+            return;
+        }
+    }
+
+private:
+    /**
+     * Helper that construct an event handler from a member function of this
+     * instance.
+     */
+    template<typename Arg>
+    FunctionPointerWithContext<Arg> as_cb(void (Self::*member)(Arg))
+    {
+        return makeFunctionPointer(this, member);
+    }
+
+    /**
+     * Read, Write, Notify, Indicate  Characteristic declaration helper.
+     *
+     * @tparam T type of data held by the characteristic.
+     */
+    template<typename T>
+    class ReadWriteNotifyIndicateCharacteristic : public GattCharacteristic {
+    public:
+        /**
+         * Construct a characteristic that can be read or written and emit
+         * notification or indication.
+         *
+         * @param[in] uuid The UUID of the characteristic.
+         * @param[in] initial_value Initial value contained by the characteristic.
+         */
+        ReadWriteNotifyIndicateCharacteristic(const UUID & uuid, const T& initial_value) :
+            GattCharacteristic(
+                /* UUID */ uuid,
+                /* Initial value */ &_value,
+                /* Value size */ sizeof(_value),
+                /* Value capacity */ sizeof(_value),
+                /* Properties */ GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_READ |
+                                GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_WRITE |
+                                GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_NOTIFY |
+                                GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_INDICATE,
+                /* Descriptors */ NULL,
+                /* Num descriptors */ 0,
+                /* variable len */ false
+            ),
+            _value(initial_value) {
+        }
+
+        /**
+         * Get the value of this characteristic.
+         *
+         * @param[in] server GattServer instance that contain the characteristic
+         * value.
+         * @param[in] dst Variable that will receive the characteristic value.
+         *
+         * @return BLE_ERROR_NONE in case of success or an appropriate error code.
+         */
+        ble_error_t get(GattServer &server, T& dst) const
+        {
+            uint16_t value_length = sizeof(dst);
+            return server.read(getValueHandle(), &dst, &value_length);
+        }
+
+        /**
+         * Assign a new value to this characteristic.
+         *
+         * @param[in] server GattServer instance that will receive the new value.
+         * @param[in] value The new value to set.
+         * @param[in] local_only Flag that determine if the change should be kept
+         * locally or forwarded to subscribed clients.
+         */
+        ble_error_t set(
+            GattServer &server, const uint8_t &value, bool local_only = false
+        ) const {
+            return server.write(getValueHandle(), &value, sizeof(value), local_only);
+        }
+
+    private:
+        uint8_t _value;
+    };
+
+    ReadWriteNotifyIndicateCharacteristic<uint8_t> _hour_char;
+    ReadWriteNotifyIndicateCharacteristic<uint8_t> _minute_char;
+    ReadWriteNotifyIndicateCharacteristic<uint8_t> _second_char;
+
+    // list of the characteristics of the clock service
+    GattCharacteristic* _clock_characteristics[3];
+
+    // demo service
+    GattService _clock_service;
+
+    GattServer* _server;
+    events::EventQueue *_event_queue;
+};
+
+int main() {
+    BLE &ble_interface = BLE::Instance();
+    events::EventQueue event_queue;
+    ClockService demo_service;
+    BLEProcess ble_process(event_queue, ble_interface);
+
+    ble_process.on_init(callback(&demo_service, &ClockService::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;
+}