mbed-os-examples / Mbed OS mbed-os-example-ble-GattServer

Dependents:   mbed-os-example-ble-GattServer_ECG

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers main.cpp Source File

main.cpp

00001 /* mbed Microcontroller Library
00002  * Copyright (c) 2017 ARM Limited
00003  *
00004  * Licensed under the Apache License, Version 2.0 (the "License");
00005  * you may not use this file except in compliance with the License.
00006  * You may obtain a copy of the License at
00007  *
00008  *     http://www.apache.org/licenses/LICENSE-2.0
00009  *
00010  * Unless required by applicable law or agreed to in writing, software
00011  * distributed under the License is distributed on an "AS IS" BASIS,
00012  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00013  * See the License for the specific language governing permissions and
00014  * limitations under the License.
00015  */
00016 
00017 #include <stdio.h>
00018 
00019 #include "platform/Callback.h"
00020 #include "events/EventQueue.h"
00021 #include "platform/NonCopyable.h"
00022 
00023 #include "ble/BLE.h"
00024 #include "ble/Gap.h"
00025 #include "ble/GattClient.h"
00026 #include "ble/GapAdvertisingParams.h"
00027 #include "ble/GapAdvertisingData.h"
00028 #include "ble/GattServer.h"
00029 #include "BLEProcess.h"
00030 
00031 using mbed::callback;
00032 
00033 /**
00034  * A Clock service that demonstrate the GattServer features.
00035  *
00036  * The clock service host three characteristics that model the current hour,
00037  * minute and second of the clock. The value of the second characteristic is
00038  * incremented automatically by the system.
00039  *
00040  * A client can subscribe to updates of the clock characteristics and get
00041  * notified when one of the value is changed. Clients can also change value of
00042  * the second, minute and hour characteristric.
00043  */
00044 class ClockService {
00045     typedef ClockService Self;
00046 
00047 public:
00048     ClockService() :
00049         _hour_char("485f4145-52b9-4644-af1f-7a6b9322490f", 0),
00050         _minute_char("0a924ca7-87cd-4699-a3bd-abdcd9cf126a", 0),
00051         _second_char("8dd6a1b7-bc75-4741-8a26-264af75807de", 0),
00052         _clock_service(
00053             /* uuid */ "51311102-030e-485f-b122-f8f381aa84ed",
00054             /* characteristics */ _clock_characteristics,
00055             /* numCharacteristics */ sizeof(_clock_characteristics) /
00056                                      sizeof(_clock_characteristics[0])
00057         ),
00058         _server(NULL),
00059         _event_queue(NULL)
00060     {
00061         // update internal pointers (value, descriptors and characteristics array)
00062         _clock_characteristics[0] = &_hour_char;
00063         _clock_characteristics[1] = &_minute_char;
00064         _clock_characteristics[2] = &_second_char;
00065 
00066         // setup authorization handlers
00067         _hour_char.setWriteAuthorizationCallback(this, &Self::authorize_client_write);
00068         _minute_char.setWriteAuthorizationCallback(this, &Self::authorize_client_write);
00069         _second_char.setWriteAuthorizationCallback(this, &Self::authorize_client_write);
00070     }
00071 
00072 
00073 
00074     void start(BLE &ble_interface, events::EventQueue &event_queue)
00075     {
00076          if (_event_queue) {
00077             return;
00078         }
00079 
00080         _server = &ble_interface.gattServer();
00081         _event_queue = &event_queue;
00082 
00083         // register the service
00084         printf("Adding demo service\r\n");
00085         ble_error_t err = _server->addService(_clock_service);
00086 
00087         if (err) {
00088             printf("Error %u during demo service registration.\r\n", err);
00089             return;
00090         }
00091 
00092         // read write handler
00093         _server->onDataSent(as_cb(&Self::when_data_sent));
00094         _server->onDataWritten(as_cb(&Self::when_data_written));
00095         _server->onDataRead(as_cb(&Self::when_data_read));
00096 
00097         // updates subscribtion handlers
00098         _server->onUpdatesEnabled(as_cb(&Self::when_update_enabled));
00099         _server->onUpdatesDisabled(as_cb(&Self::when_update_disabled));
00100         _server->onConfirmationReceived(as_cb(&Self::when_confirmation_received));
00101 
00102         // print the handles
00103         printf("clock service registered\r\n");
00104         printf("service handle: %u\r\n", _clock_service.getHandle());
00105         printf("\thour characteristic value handle %u\r\n", _hour_char.getValueHandle());
00106         printf("\tminute characteristic value handle %u\r\n", _minute_char.getValueHandle());
00107         printf("\tsecond characteristic value handle %u\r\n", _second_char.getValueHandle());
00108 
00109         _event_queue->call_every(1000 /* ms */, callback(this, &Self::increment_second));
00110     }
00111 
00112 private:
00113 
00114     /**
00115      * Handler called when a notification or an indication has been sent.
00116      */
00117     void when_data_sent(unsigned count)
00118     {
00119         printf("sent %u updates\r\n", count);
00120     }
00121 
00122     /**
00123      * Handler called after an attribute has been written.
00124      */
00125     void when_data_written(const GattWriteCallbackParams *e)
00126     {
00127         printf("data written:\r\n");
00128         printf("\tconnection handle: %u\r\n", e->connHandle);
00129         printf("\tattribute handle: %u", e->handle);
00130         if (e->handle == _hour_char.getValueHandle()) {
00131             printf(" (hour characteristic)\r\n");
00132         } else if (e->handle == _minute_char.getValueHandle()) {
00133             printf(" (minute characteristic)\r\n");
00134         } else if (e->handle == _second_char.getValueHandle()) {
00135             printf(" (second characteristic)\r\n");
00136         } else {
00137             printf("\r\n");
00138         }
00139         printf("\twrite operation: %u\r\n", e->writeOp);
00140         printf("\toffset: %u\r\n", e->offset);
00141         printf("\tlength: %u\r\n", e->len);
00142         printf("\t data: ");
00143 
00144         for (size_t i = 0; i < e->len; ++i) {
00145             printf("%02X", e->data[i]);
00146         }
00147 
00148         printf("\r\n");
00149     }
00150 
00151     /**
00152      * Handler called after an attribute has been read.
00153      */
00154     void when_data_read(const GattReadCallbackParams *e)
00155     {
00156         printf("data read:\r\n");
00157         printf("\tconnection handle: %u\r\n", e->connHandle);
00158         printf("\tattribute handle: %u", e->handle);
00159         if (e->handle == _hour_char.getValueHandle()) {
00160             printf(" (hour characteristic)\r\n");
00161         } else if (e->handle == _minute_char.getValueHandle()) {
00162             printf(" (minute characteristic)\r\n");
00163         } else if (e->handle == _second_char.getValueHandle()) {
00164             printf(" (second characteristic)\r\n");
00165         } else {
00166             printf("\r\n");
00167         }
00168     }
00169 
00170     /**
00171      * Handler called after a client has subscribed to notification or indication.
00172      *
00173      * @param handle Handle of the characteristic value affected by the change.
00174      */
00175     void when_update_enabled(GattAttribute::Handle_t handle)
00176     {
00177         printf("update enabled on handle %d\r\n", handle);
00178     }
00179 
00180     /**
00181      * Handler called after a client has cancelled his subscription from
00182      * notification or indication.
00183      *
00184      * @param handle Handle of the characteristic value affected by the change.
00185      */
00186     void when_update_disabled(GattAttribute::Handle_t handle)
00187     {
00188         printf("update disabled on handle %d\r\n", handle);
00189     }
00190 
00191     /**
00192      * Handler called when an indication confirmation has been received.
00193      *
00194      * @param handle Handle of the characteristic value that has emitted the
00195      * indication.
00196      */
00197     void when_confirmation_received(GattAttribute::Handle_t handle)
00198     {
00199         printf("confirmation received on handle %d\r\n", handle);
00200     }
00201 
00202     /**
00203      * Handler called when a write request is received.
00204      *
00205      * This handler verify that the value submitted by the client is valid before
00206      * authorizing the operation.
00207      */
00208     void authorize_client_write(GattWriteAuthCallbackParams *e)
00209     {
00210         printf("characteristic %u write authorization\r\n", e->handle);
00211 
00212         if (e->offset != 0) {
00213             printf("Error invalid offset\r\n");
00214             e->authorizationReply = AUTH_CALLBACK_REPLY_ATTERR_INVALID_OFFSET;
00215             return;
00216         }
00217 
00218         if (e->len != 1) {
00219             printf("Error invalid len\r\n");
00220             e->authorizationReply = AUTH_CALLBACK_REPLY_ATTERR_INVALID_ATT_VAL_LENGTH;
00221             return;
00222         }
00223 
00224         if ((e->data[0] >= 60) ||
00225             ((e->data[0] >= 24) && (e->handle == _hour_char.getValueHandle()))) {
00226             printf("Error invalid data\r\n");
00227             e->authorizationReply = AUTH_CALLBACK_REPLY_ATTERR_WRITE_NOT_PERMITTED;
00228             return;
00229         }
00230 
00231         e->authorizationReply = AUTH_CALLBACK_REPLY_SUCCESS;
00232     }
00233 
00234     /**
00235      * Increment the second counter.
00236      */
00237     void increment_second(void)
00238     {
00239         uint8_t second = 0;
00240         ble_error_t err = _second_char.get(*_server, second);
00241         if (err) {
00242             printf("read of the second value returned error %u\r\n", err);
00243             return;
00244         }
00245 
00246         second = (second + 1) % 60;
00247 
00248         err = _second_char.set(*_server, second);
00249         if (err) {
00250             printf("write of the second value returned error %u\r\n", err);
00251             return;
00252         }
00253 
00254         if (second == 0) {
00255             increment_minute();
00256         }
00257     }
00258 
00259     /**
00260      * Increment the minute counter.
00261      */
00262     void increment_minute(void)
00263     {
00264         uint8_t minute = 0;
00265         ble_error_t err = _minute_char.get(*_server, minute);
00266         if (err) {
00267             printf("read of the minute value returned error %u\r\n", err);
00268             return;
00269         }
00270 
00271         minute = (minute + 1) % 60;
00272 
00273         err = _minute_char.set(*_server, minute);
00274         if (err) {
00275             printf("write of the minute value returned error %u\r\n", err);
00276             return;
00277         }
00278 
00279         if (minute == 0) {
00280             increment_hour();
00281         }
00282     }
00283 
00284     /**
00285      * Increment the hour counter.
00286      */
00287     void increment_hour(void)
00288     {
00289         uint8_t hour = 0;
00290         ble_error_t err = _hour_char.get(*_server, hour);
00291         if (err) {
00292             printf("read of the hour value returned error %u\r\n", err);
00293             return;
00294         }
00295 
00296         hour = (hour + 1) % 24;
00297 
00298         err = _hour_char.set(*_server, hour);
00299         if (err) {
00300             printf("write of the hour value returned error %u\r\n", err);
00301             return;
00302         }
00303     }
00304 
00305 private:
00306     /**
00307      * Helper that construct an event handler from a member function of this
00308      * instance.
00309      */
00310     template<typename Arg>
00311     FunctionPointerWithContext<Arg> as_cb(void (Self::*member)(Arg))
00312     {
00313         return makeFunctionPointer(this, member);
00314     }
00315 
00316     /**
00317      * Read, Write, Notify, Indicate  Characteristic declaration helper.
00318      *
00319      * @tparam T type of data held by the characteristic.
00320      */
00321     template<typename T>
00322     class ReadWriteNotifyIndicateCharacteristic : public GattCharacteristic {
00323     public:
00324         /**
00325          * Construct a characteristic that can be read or written and emit
00326          * notification or indication.
00327          *
00328          * @param[in] uuid The UUID of the characteristic.
00329          * @param[in] initial_value Initial value contained by the characteristic.
00330          */
00331         ReadWriteNotifyIndicateCharacteristic(const UUID & uuid, const T& initial_value) :
00332             GattCharacteristic(
00333                 /* UUID */ uuid,
00334                 /* Initial value */ &_value,
00335                 /* Value size */ sizeof(_value),
00336                 /* Value capacity */ sizeof(_value),
00337                 /* Properties */ GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_READ |
00338                                 GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_WRITE |
00339                                 GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_NOTIFY |
00340                                 GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_INDICATE,
00341                 /* Descriptors */ NULL,
00342                 /* Num descriptors */ 0,
00343                 /* variable len */ false
00344             ),
00345             _value(initial_value) {
00346         }
00347 
00348         /**
00349          * Get the value of this characteristic.
00350          *
00351          * @param[in] server GattServer instance that contain the characteristic
00352          * value.
00353          * @param[in] dst Variable that will receive the characteristic value.
00354          *
00355          * @return BLE_ERROR_NONE in case of success or an appropriate error code.
00356          */
00357         ble_error_t get(GattServer &server, T& dst) const
00358         {
00359             uint16_t value_length = sizeof(dst);
00360             return server.read(getValueHandle(), &dst, &value_length);
00361         }
00362 
00363         /**
00364          * Assign a new value to this characteristic.
00365          *
00366          * @param[in] server GattServer instance that will receive the new value.
00367          * @param[in] value The new value to set.
00368          * @param[in] local_only Flag that determine if the change should be kept
00369          * locally or forwarded to subscribed clients.
00370          */
00371         ble_error_t set(
00372             GattServer &server, const uint8_t &value, bool local_only = false
00373         ) const {
00374             return server.write(getValueHandle(), &value, sizeof(value), local_only);
00375         }
00376 
00377     private:
00378         uint8_t _value;
00379     };
00380 
00381     ReadWriteNotifyIndicateCharacteristic<uint8_t> _hour_char;
00382     ReadWriteNotifyIndicateCharacteristic<uint8_t> _minute_char;
00383     ReadWriteNotifyIndicateCharacteristic<uint8_t> _second_char;
00384 
00385     // list of the characteristics of the clock service
00386     GattCharacteristic* _clock_characteristics[3];
00387 
00388     // demo service
00389     GattService _clock_service;
00390 
00391     GattServer* _server;
00392     events::EventQueue *_event_queue;
00393 };
00394 
00395 int main() {
00396     BLE &ble_interface = BLE::Instance();
00397     events::EventQueue event_queue;
00398     ClockService demo_service;
00399     BLEProcess ble_process(event_queue, ble_interface);
00400 
00401     ble_process.on_init(callback(&demo_service, &ClockService::start));
00402 
00403     // bind the event queue to the ble interface, initialize the interface
00404     // and start advertising
00405     ble_process.start();
00406 
00407     // Process the event queue.
00408     event_queue.dispatch_forever();
00409 
00410     return 0;
00411 }