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.
Dependents: mbed-os-example-ble-GattServer_ECG
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 }
Generated on Tue Jul 12 2022 11:26:30 by
