This application demonstrates detailed uses of the GattClient APIs.

Committer:
mbed_official
Date:
Wed Feb 27 13:01:37 2019 +0000
Revision:
4:38639a71a0f1
Parent:
2:32be19c07874
Child:
5:331ef6ec71f5
Updating mbed-os to mbed-os-5.11.5

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

Who changed what in which revision?

UserRevisionLine numberNew contents of line
mbed_official 2:32be19c07874 1
mbed_official 2:32be19c07874 2 /* mbed Microcontroller Library
mbed_official 2:32be19c07874 3 * Copyright (c) 2006-2018 ARM Limited
mbed_official 2:32be19c07874 4 *
mbed_official 2:32be19c07874 5 * Licensed under the Apache License, Version 2.0 (the "License");
mbed_official 2:32be19c07874 6 * you may not use this file except in compliance with the License.
mbed_official 2:32be19c07874 7 * You may obtain a copy of the License at
mbed_official 2:32be19c07874 8 *
mbed_official 2:32be19c07874 9 * http://www.apache.org/licenses/LICENSE-2.0
mbed_official 2:32be19c07874 10 *
mbed_official 2:32be19c07874 11 * Unless required by applicable law or agreed to in writing, software
mbed_official 2:32be19c07874 12 * distributed under the License is distributed on an "AS IS" BASIS,
mbed_official 2:32be19c07874 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
mbed_official 2:32be19c07874 14 * See the License for the specific language governing permissions and
mbed_official 2:32be19c07874 15 * limitations under the License.
mbed_official 2:32be19c07874 16 */
mbed_official 2:32be19c07874 17
mbed_official 2:32be19c07874 18 #include <memory>
mbed_official 2:32be19c07874 19 #include <new>
mbed_official 2:32be19c07874 20 #include <stdio.h>
mbed_official 2:32be19c07874 21
mbed_official 2:32be19c07874 22 #include "events/EventQueue.h"
mbed_official 2:32be19c07874 23 #include "platform/NonCopyable.h"
mbed_official 2:32be19c07874 24
mbed_official 2:32be19c07874 25 #include "ble/BLE.h"
mbed_official 2:32be19c07874 26 #include "ble/Gap.h"
mbed_official 2:32be19c07874 27 #include "ble/GattClient.h"
mbed_official 2:32be19c07874 28 #include "ble/GapAdvertisingParams.h"
mbed_official 2:32be19c07874 29 #include "ble/GapAdvertisingData.h"
mbed_official 2:32be19c07874 30 #include "ble/GattClient.h"
mbed_official 2:32be19c07874 31 #include "ble/DiscoveredService.h"
mbed_official 2:32be19c07874 32 #include "ble/DiscoveredCharacteristic.h"
mbed_official 2:32be19c07874 33 #include "ble/CharacteristicDescriptorDiscovery.h"
mbed_official 2:32be19c07874 34
mbed_official 2:32be19c07874 35 #include "BLEProcess.h"
mbed_official 2:32be19c07874 36
mbed_official 2:32be19c07874 37 /**
mbed_official 2:32be19c07874 38 * Handle discovery of the GATT server.
mbed_official 2:32be19c07874 39 *
mbed_official 2:32be19c07874 40 * First the GATT server is discovered in its entirety then each readable
mbed_official 2:32be19c07874 41 * characteristic is read and the client register to characteristic
mbed_official 2:32be19c07874 42 * notifications or indication when available. The client report server
mbed_official 2:32be19c07874 43 * indications and notification until the connection end.
mbed_official 2:32be19c07874 44 */
mbed_official 2:32be19c07874 45 class GattClientProcess : private mbed::NonCopyable<GattClientProcess>,
mbed_official 2:32be19c07874 46 public ble::Gap::EventHandler {
mbed_official 2:32be19c07874 47
mbed_official 2:32be19c07874 48 // Internal typedef to this class type.
mbed_official 2:32be19c07874 49 // It is used as a shorthand to pass member function as callbacks.
mbed_official 2:32be19c07874 50 typedef GattClientProcess Self;
mbed_official 2:32be19c07874 51
mbed_official 2:32be19c07874 52 typedef CharacteristicDescriptorDiscovery::DiscoveryCallbackParams_t
mbed_official 2:32be19c07874 53 DiscoveryCallbackParams_t;
mbed_official 2:32be19c07874 54
mbed_official 2:32be19c07874 55 typedef CharacteristicDescriptorDiscovery::TerminationCallbackParams_t
mbed_official 2:32be19c07874 56 TerminationCallbackParams_t;
mbed_official 2:32be19c07874 57
mbed_official 2:32be19c07874 58 typedef DiscoveredCharacteristic::Properties_t Properties_t;
mbed_official 2:32be19c07874 59
mbed_official 2:32be19c07874 60 public:
mbed_official 2:32be19c07874 61
mbed_official 2:32be19c07874 62 /**
mbed_official 2:32be19c07874 63 * Construct an empty client process.
mbed_official 2:32be19c07874 64 *
mbed_official 2:32be19c07874 65 * The function start() shall be called to initiate the discovery process.
mbed_official 2:32be19c07874 66 */
mbed_official 2:32be19c07874 67 GattClientProcess() :
mbed_official 2:32be19c07874 68 _client(NULL),
mbed_official 2:32be19c07874 69 _connection_handle(),
mbed_official 2:32be19c07874 70 _characteristics(NULL),
mbed_official 2:32be19c07874 71 _it(NULL),
mbed_official 2:32be19c07874 72 _descriptor_handle(0),
mbed_official 2:32be19c07874 73 _ble_interface(NULL),
mbed_official 2:32be19c07874 74 _event_queue(NULL) {
mbed_official 2:32be19c07874 75 }
mbed_official 2:32be19c07874 76
mbed_official 2:32be19c07874 77 ~GattClientProcess()
mbed_official 2:32be19c07874 78 {
mbed_official 2:32be19c07874 79 stop();
mbed_official 2:32be19c07874 80 }
mbed_official 2:32be19c07874 81
mbed_official 2:32be19c07874 82 void init(BLE &ble_interface, events::EventQueue &event_queue)
mbed_official 2:32be19c07874 83 {
mbed_official 2:32be19c07874 84 _ble_interface = &ble_interface;
mbed_official 2:32be19c07874 85 _event_queue = &event_queue;
mbed_official 2:32be19c07874 86 _client = &_ble_interface->gattClient();
mbed_official 2:32be19c07874 87
mbed_official 2:32be19c07874 88 _ble_interface->gap().setEventHandler(this);
mbed_official 2:32be19c07874 89 }
mbed_official 2:32be19c07874 90
mbed_official 2:32be19c07874 91 /**
mbed_official 2:32be19c07874 92 * Start the discovery process.
mbed_official 2:32be19c07874 93 *
mbed_official 2:32be19c07874 94 * @param[in] client The GattClient instance which will discover the distant
mbed_official 2:32be19c07874 95 * GATT server.
mbed_official 2:32be19c07874 96 * @param[in] connection_handle Reference of the connection to the GATT
mbed_official 2:32be19c07874 97 * server which will be discovered.
mbed_official 2:32be19c07874 98 */
mbed_official 2:32be19c07874 99 void start()
mbed_official 2:32be19c07874 100 {
mbed_official 2:32be19c07874 101 // setup the event handlers called during the process
mbed_official 2:32be19c07874 102 _client->onDataWritten().add(as_cb(&Self::when_descriptor_written));
mbed_official 2:32be19c07874 103 _client->onHVX().add(as_cb(&Self::when_characteristic_changed));
mbed_official 2:32be19c07874 104
mbed_official 2:32be19c07874 105 // The discovery process will invoke when_service_discovered when a
mbed_official 2:32be19c07874 106 // service is discovered, when_characteristic_discovered when a
mbed_official 2:32be19c07874 107 // characteristic is discovered and when_service_discovery_ends once the
mbed_official 2:32be19c07874 108 // discovery process has ended.
mbed_official 2:32be19c07874 109 _client->onServiceDiscoveryTermination(as_cb(&Self::when_service_discovery_ends));
mbed_official 2:32be19c07874 110 ble_error_t error = _client->launchServiceDiscovery(
mbed_official 2:32be19c07874 111 _connection_handle,
mbed_official 2:32be19c07874 112 as_cb(&Self::when_service_discovered),
mbed_official 2:32be19c07874 113 as_cb(&Self::when_characteristic_discovered)
mbed_official 2:32be19c07874 114 );
mbed_official 2:32be19c07874 115
mbed_official 2:32be19c07874 116 if (error) {
mbed_official 2:32be19c07874 117 printf("Error %u returned by _client->launchServiceDiscovery.\r\n", error);
mbed_official 2:32be19c07874 118 return;
mbed_official 2:32be19c07874 119 }
mbed_official 2:32be19c07874 120
mbed_official 2:32be19c07874 121 printf("Client process started: initiate service discovery.\r\n");
mbed_official 2:32be19c07874 122 }
mbed_official 2:32be19c07874 123
mbed_official 2:32be19c07874 124 /**
mbed_official 2:32be19c07874 125 * Stop the discovery process and clean the instance.
mbed_official 2:32be19c07874 126 */
mbed_official 2:32be19c07874 127 void stop()
mbed_official 2:32be19c07874 128 {
mbed_official 2:32be19c07874 129 if (!_client) {
mbed_official 2:32be19c07874 130 return;
mbed_official 2:32be19c07874 131 }
mbed_official 2:32be19c07874 132
mbed_official 2:32be19c07874 133 // unregister event handlers
mbed_official 2:32be19c07874 134 _client->onDataWritten().detach(as_cb(&Self::when_descriptor_written));
mbed_official 2:32be19c07874 135 _client->onHVX().detach(as_cb(&Self::when_characteristic_changed));
mbed_official 2:32be19c07874 136 _client->onServiceDiscoveryTermination(NULL);
mbed_official 2:32be19c07874 137
mbed_official 2:32be19c07874 138 // remove discovered characteristics
mbed_official 2:32be19c07874 139 clear_characteristics();
mbed_official 2:32be19c07874 140
mbed_official 2:32be19c07874 141 // clean up the instance
mbed_official 2:32be19c07874 142 _connection_handle = 0;
mbed_official 2:32be19c07874 143 _characteristics = NULL;
mbed_official 2:32be19c07874 144 _it = NULL;
mbed_official 2:32be19c07874 145 _descriptor_handle = 0;
mbed_official 2:32be19c07874 146
mbed_official 2:32be19c07874 147 printf("Client process stopped.\r\n");
mbed_official 2:32be19c07874 148 }
mbed_official 2:32be19c07874 149
mbed_official 2:32be19c07874 150 private:
mbed_official 2:32be19c07874 151 /**
mbed_official 2:32be19c07874 152 * Event handler invoked when a connection is established.
mbed_official 2:32be19c07874 153 *
mbed_official 2:32be19c07874 154 * This function setup the connection handle to operate on then start the
mbed_official 2:32be19c07874 155 * discovery process.
mbed_official 2:32be19c07874 156 */
mbed_official 2:32be19c07874 157 virtual void onConnectionComplete(const ble::ConnectionCompleteEvent &event)
mbed_official 2:32be19c07874 158 {
mbed_official 2:32be19c07874 159 _connection_handle = event.getConnectionHandle();
mbed_official 2:32be19c07874 160 _event_queue->call(mbed::callback(this, &Self::start));
mbed_official 2:32be19c07874 161 }
mbed_official 2:32be19c07874 162
mbed_official 2:32be19c07874 163 /**
mbed_official 2:32be19c07874 164 * Stop the discovery process and clean the instance.
mbed_official 2:32be19c07874 165 */
mbed_official 2:32be19c07874 166 virtual void onDisconnectionComplete(const ble::DisconnectionCompleteEvent &event)
mbed_official 2:32be19c07874 167 {
mbed_official 2:32be19c07874 168 if (_client && event.getConnectionHandle() == _connection_handle) {
mbed_official 2:32be19c07874 169 stop();
mbed_official 2:32be19c07874 170 }
mbed_official 2:32be19c07874 171 }
mbed_official 2:32be19c07874 172
mbed_official 2:32be19c07874 173 private:
mbed_official 2:32be19c07874 174 ////////////////////////////////////////////////////////////////////////////////
mbed_official 2:32be19c07874 175 // Service and characteristic discovery process.
mbed_official 2:32be19c07874 176
mbed_official 2:32be19c07874 177 /**
mbed_official 2:32be19c07874 178 * Handle services discovered.
mbed_official 2:32be19c07874 179 *
mbed_official 2:32be19c07874 180 * The GattClient invokes this function when a service has been discovered.
mbed_official 2:32be19c07874 181 *
mbed_official 2:32be19c07874 182 * @see GattClient::launchServiceDiscovery
mbed_official 2:32be19c07874 183 */
mbed_official 2:32be19c07874 184 void when_service_discovered(const DiscoveredService *discovered_service)
mbed_official 2:32be19c07874 185 {
mbed_official 2:32be19c07874 186 // print information of the service discovered
mbed_official 2:32be19c07874 187 printf("Service discovered: value = ");
mbed_official 2:32be19c07874 188 print_uuid(discovered_service->getUUID());
mbed_official 2:32be19c07874 189 printf(", start = %u, end = %u.\r\n",
mbed_official 2:32be19c07874 190 discovered_service->getStartHandle(),
mbed_official 2:32be19c07874 191 discovered_service->getEndHandle()
mbed_official 2:32be19c07874 192 );
mbed_official 2:32be19c07874 193 }
mbed_official 2:32be19c07874 194
mbed_official 2:32be19c07874 195 /**
mbed_official 2:32be19c07874 196 * Handle characteristics discovered.
mbed_official 2:32be19c07874 197 *
mbed_official 2:32be19c07874 198 * The GattClient invoke this function when a characteristic has been
mbed_official 2:32be19c07874 199 * discovered.
mbed_official 2:32be19c07874 200 *
mbed_official 2:32be19c07874 201 * @see GattClient::launchServiceDiscovery
mbed_official 2:32be19c07874 202 */
mbed_official 2:32be19c07874 203 void when_characteristic_discovered(const DiscoveredCharacteristic *discovered_characteristic)
mbed_official 2:32be19c07874 204 {
mbed_official 2:32be19c07874 205 // print characteristics properties
mbed_official 2:32be19c07874 206 printf("\tCharacteristic discovered: uuid = ");
mbed_official 2:32be19c07874 207 print_uuid(discovered_characteristic->getUUID());
mbed_official 2:32be19c07874 208 printf(", properties = ");
mbed_official 2:32be19c07874 209 print_properties(discovered_characteristic->getProperties());
mbed_official 2:32be19c07874 210 printf(
mbed_official 2:32be19c07874 211 ", decl handle = %u, value handle = %u, last handle = %u.\r\n",
mbed_official 2:32be19c07874 212 discovered_characteristic->getDeclHandle(),
mbed_official 2:32be19c07874 213 discovered_characteristic->getValueHandle(),
mbed_official 2:32be19c07874 214 discovered_characteristic->getLastHandle()
mbed_official 2:32be19c07874 215 );
mbed_official 2:32be19c07874 216
mbed_official 2:32be19c07874 217 // add the characteristic into the list of discovered characteristics
mbed_official 2:32be19c07874 218 bool success = add_characteristic(discovered_characteristic);
mbed_official 2:32be19c07874 219 if (!success) {
mbed_official 2:32be19c07874 220 printf("Error: memory allocation failure while adding the discovered characteristic.\r\n");
mbed_official 2:32be19c07874 221 _client->terminateServiceDiscovery();
mbed_official 2:32be19c07874 222 stop();
mbed_official 2:32be19c07874 223 return;
mbed_official 2:32be19c07874 224 }
mbed_official 2:32be19c07874 225 }
mbed_official 2:32be19c07874 226
mbed_official 2:32be19c07874 227 /**
mbed_official 2:32be19c07874 228 * Handle termination of the service and characteristic discovery process.
mbed_official 2:32be19c07874 229 *
mbed_official 2:32be19c07874 230 * The GattClient invokes this function when the service and characteristic
mbed_official 2:32be19c07874 231 * discovery process ends.
mbed_official 2:32be19c07874 232 *
mbed_official 2:32be19c07874 233 * @see GattClient::onServiceDiscoveryTermination
mbed_official 2:32be19c07874 234 */
mbed_official 2:32be19c07874 235 void when_service_discovery_ends(Gap::Handle_t connection_handle)
mbed_official 2:32be19c07874 236 {
mbed_official 2:32be19c07874 237 if (!_characteristics) {
mbed_official 2:32be19c07874 238 printf("No characteristics discovered, end of the process.\r\n");
mbed_official 2:32be19c07874 239 return;
mbed_official 2:32be19c07874 240 }
mbed_official 2:32be19c07874 241
mbed_official 2:32be19c07874 242 printf("All services and characteristics discovered, process them.\r\n");
mbed_official 2:32be19c07874 243
mbed_official 2:32be19c07874 244 // reset iterator and start processing characteristics in order
mbed_official 2:32be19c07874 245 _it = NULL;
mbed_official 2:32be19c07874 246 _event_queue->call(mbed::callback(this, &Self::process_next_characteristic));
mbed_official 2:32be19c07874 247 }
mbed_official 2:32be19c07874 248
mbed_official 2:32be19c07874 249 ////////////////////////////////////////////////////////////////////////////////
mbed_official 2:32be19c07874 250 // Processing of characteristics based on their properties.
mbed_official 2:32be19c07874 251
mbed_official 2:32be19c07874 252 /**
mbed_official 2:32be19c07874 253 * Process the characteristics discovered.
mbed_official 2:32be19c07874 254 *
mbed_official 2:32be19c07874 255 * - If the characteristic is readable then read its value and print it. Then
mbed_official 2:32be19c07874 256 * - If the characteristic can emit notification or indication then discover
mbed_official 2:32be19c07874 257 * the characteristic CCCD and subscribe to the server initiated event.
mbed_official 2:32be19c07874 258 * - Otherwise skip the characteristic processing.
mbed_official 2:32be19c07874 259 */
mbed_official 2:32be19c07874 260 void process_next_characteristic(void)
mbed_official 2:32be19c07874 261 {
mbed_official 2:32be19c07874 262 if (!_it) {
mbed_official 2:32be19c07874 263 _it = _characteristics;
mbed_official 2:32be19c07874 264 } else {
mbed_official 2:32be19c07874 265 _it = _it->next;
mbed_official 2:32be19c07874 266 }
mbed_official 2:32be19c07874 267
mbed_official 2:32be19c07874 268 while (_it) {
mbed_official 2:32be19c07874 269 Properties_t properties = _it->value.getProperties();
mbed_official 2:32be19c07874 270
mbed_official 2:32be19c07874 271 if (properties.read()) {
mbed_official 2:32be19c07874 272 read_characteristic(_it->value);
mbed_official 2:32be19c07874 273 return;
mbed_official 2:32be19c07874 274 } else if(properties.notify() || properties.indicate()) {
mbed_official 2:32be19c07874 275 discover_descriptors(_it->value);
mbed_official 2:32be19c07874 276 return;
mbed_official 2:32be19c07874 277 } else {
mbed_official 2:32be19c07874 278 printf(
mbed_official 2:32be19c07874 279 "Skip processing of characteristic %u\r\n",
mbed_official 2:32be19c07874 280 _it->value.getValueHandle()
mbed_official 2:32be19c07874 281 );
mbed_official 2:32be19c07874 282 _it = _it->next;
mbed_official 2:32be19c07874 283 }
mbed_official 2:32be19c07874 284 }
mbed_official 2:32be19c07874 285
mbed_official 2:32be19c07874 286 printf("All characteristics discovered have been processed.\r\n");
mbed_official 2:32be19c07874 287 }
mbed_official 2:32be19c07874 288
mbed_official 2:32be19c07874 289 /**
mbed_official 2:32be19c07874 290 * Initate the read of the characteristic in input.
mbed_official 2:32be19c07874 291 *
mbed_official 2:32be19c07874 292 * The completion of the operation will happens in when_characteristic_read()
mbed_official 2:32be19c07874 293 */
mbed_official 2:32be19c07874 294 void read_characteristic(const DiscoveredCharacteristic &characteristic)
mbed_official 2:32be19c07874 295 {
mbed_official 2:32be19c07874 296 printf("Initiating read at %u.\r\n", characteristic.getValueHandle());
mbed_official 2:32be19c07874 297 ble_error_t error = characteristic.read(
mbed_official 2:32be19c07874 298 0, as_cb(&Self::when_characteristic_read)
mbed_official 2:32be19c07874 299 );
mbed_official 2:32be19c07874 300
mbed_official 2:32be19c07874 301 if (error) {
mbed_official 2:32be19c07874 302 printf(
mbed_official 2:32be19c07874 303 "Error: cannot initiate read at %u due to %u\r\n",
mbed_official 2:32be19c07874 304 characteristic.getValueHandle(), error
mbed_official 2:32be19c07874 305 );
mbed_official 2:32be19c07874 306 stop();
mbed_official 2:32be19c07874 307 }
mbed_official 2:32be19c07874 308 }
mbed_official 2:32be19c07874 309
mbed_official 2:32be19c07874 310 /**
mbed_official 2:32be19c07874 311 * Handle the reception of a read response.
mbed_official 2:32be19c07874 312 *
mbed_official 2:32be19c07874 313 * If the characteristic can emit notification or indication then start the
mbed_official 2:32be19c07874 314 * discovery of the the characteristic descriptors then subscribe to the
mbed_official 2:32be19c07874 315 * server initiated event by writing the CCCD discovered. Otherwise start
mbed_official 2:32be19c07874 316 * the processing of the next characteristic discovered in the server.
mbed_official 2:32be19c07874 317 */
mbed_official 2:32be19c07874 318 void when_characteristic_read(const GattReadCallbackParams *read_event)
mbed_official 2:32be19c07874 319 {
mbed_official 2:32be19c07874 320 printf("\tCharacteristic value at %u equal to: ", read_event->handle);
mbed_official 2:32be19c07874 321 for (size_t i = 0; i < read_event->len; ++i) {
mbed_official 2:32be19c07874 322 printf("0x%02X ", read_event->data[i]);
mbed_official 2:32be19c07874 323 }
mbed_official 2:32be19c07874 324 printf(".\r\n");
mbed_official 2:32be19c07874 325
mbed_official 2:32be19c07874 326 Properties_t properties = _it->value.getProperties();
mbed_official 2:32be19c07874 327
mbed_official 2:32be19c07874 328 if(properties.notify() || properties.indicate()) {
mbed_official 2:32be19c07874 329 discover_descriptors(_it->value);
mbed_official 2:32be19c07874 330 } else {
mbed_official 2:32be19c07874 331 process_next_characteristic();
mbed_official 2:32be19c07874 332 }
mbed_official 2:32be19c07874 333 }
mbed_official 2:32be19c07874 334
mbed_official 2:32be19c07874 335 /**
mbed_official 2:32be19c07874 336 * Initiate the discovery of the descriptors of the characteristic in input.
mbed_official 2:32be19c07874 337 *
mbed_official 2:32be19c07874 338 * When a descriptor is discovered, the function when_descriptor_discovered
mbed_official 2:32be19c07874 339 * is invoked.
mbed_official 2:32be19c07874 340 */
mbed_official 2:32be19c07874 341 void discover_descriptors(const DiscoveredCharacteristic &characteristic)
mbed_official 2:32be19c07874 342 {
mbed_official 2:32be19c07874 343 printf("Initiating descriptor discovery of %u.\r\n", characteristic.getValueHandle());
mbed_official 2:32be19c07874 344
mbed_official 2:32be19c07874 345 _descriptor_handle = 0;
mbed_official 2:32be19c07874 346 ble_error_t error = characteristic.discoverDescriptors(
mbed_official 2:32be19c07874 347 as_cb(&Self::when_descriptor_discovered),
mbed_official 2:32be19c07874 348 as_cb(&Self::when_descriptor_discovery_ends)
mbed_official 2:32be19c07874 349 );
mbed_official 2:32be19c07874 350
mbed_official 2:32be19c07874 351 if (error) {
mbed_official 2:32be19c07874 352 printf(
mbed_official 2:32be19c07874 353 "Error: cannot initiate discovery of %04X due to %u.\r\n",
mbed_official 2:32be19c07874 354 characteristic.getValueHandle(), error
mbed_official 2:32be19c07874 355 );
mbed_official 2:32be19c07874 356 stop();
mbed_official 2:32be19c07874 357 }
mbed_official 2:32be19c07874 358 }
mbed_official 2:32be19c07874 359
mbed_official 2:32be19c07874 360 /**
mbed_official 2:32be19c07874 361 * Handle the discovery of the characteristic descriptors.
mbed_official 2:32be19c07874 362 *
mbed_official 2:32be19c07874 363 * If the descriptor found is a CCCD then stop the discovery. Once the
mbed_official 2:32be19c07874 364 * process has ended subscribe to server initiated events by writing the
mbed_official 2:32be19c07874 365 * value of the CCCD.
mbed_official 2:32be19c07874 366 */
mbed_official 2:32be19c07874 367 void when_descriptor_discovered(const DiscoveryCallbackParams_t* event)
mbed_official 2:32be19c07874 368 {
mbed_official 2:32be19c07874 369 printf("\tDescriptor discovered at %u, UUID: ", event->descriptor.getAttributeHandle());
mbed_official 2:32be19c07874 370 print_uuid(event->descriptor.getUUID());
mbed_official 2:32be19c07874 371 printf(".\r\n");
mbed_official 2:32be19c07874 372
mbed_official 2:32be19c07874 373 if (event->descriptor.getUUID() == BLE_UUID_DESCRIPTOR_CLIENT_CHAR_CONFIG) {
mbed_official 2:32be19c07874 374 _descriptor_handle = event->descriptor.getAttributeHandle();
mbed_official 2:32be19c07874 375 _client->terminateCharacteristicDescriptorDiscovery(
mbed_official 2:32be19c07874 376 event->characteristic
mbed_official 2:32be19c07874 377 );
mbed_official 2:32be19c07874 378 }
mbed_official 2:32be19c07874 379 }
mbed_official 2:32be19c07874 380
mbed_official 2:32be19c07874 381 /**
mbed_official 2:32be19c07874 382 * If a CCCD has been found subscribe to server initiated events by writing
mbed_official 2:32be19c07874 383 * its value.
mbed_official 2:32be19c07874 384 */
mbed_official 2:32be19c07874 385 void when_descriptor_discovery_ends(const TerminationCallbackParams_t *event) {
mbed_official 2:32be19c07874 386 // shall never happen but happen with android devices ...
mbed_official 2:32be19c07874 387 // process the next charateristic
mbed_official 2:32be19c07874 388 if (!_descriptor_handle) {
mbed_official 2:32be19c07874 389 printf("\tWarning: characteristic with notify or indicate attribute without CCCD.\r\n");
mbed_official 2:32be19c07874 390 process_next_characteristic();
mbed_official 2:32be19c07874 391 return;
mbed_official 2:32be19c07874 392 }
mbed_official 2:32be19c07874 393
mbed_official 2:32be19c07874 394 Properties_t properties = _it->value.getProperties();
mbed_official 2:32be19c07874 395
mbed_official 2:32be19c07874 396 uint16_t cccd_value =
mbed_official 2:32be19c07874 397 (properties.notify() << 0) | (properties.indicate() << 1);
mbed_official 2:32be19c07874 398
mbed_official 2:32be19c07874 399 ble_error_t error = _client->write(
mbed_official 2:32be19c07874 400 GattClient::GATT_OP_WRITE_REQ,
mbed_official 2:32be19c07874 401 _connection_handle,
mbed_official 2:32be19c07874 402 _descriptor_handle,
mbed_official 2:32be19c07874 403 sizeof(cccd_value),
mbed_official 2:32be19c07874 404 reinterpret_cast<uint8_t*>(&cccd_value)
mbed_official 2:32be19c07874 405 );
mbed_official 2:32be19c07874 406
mbed_official 2:32be19c07874 407 if (error) {
mbed_official 2:32be19c07874 408 printf(
mbed_official 2:32be19c07874 409 "Error: cannot initiate write of CCCD %u due to %u.\r\n",
mbed_official 2:32be19c07874 410 _descriptor_handle, error
mbed_official 2:32be19c07874 411 );
mbed_official 2:32be19c07874 412 stop();
mbed_official 2:32be19c07874 413 }
mbed_official 2:32be19c07874 414 }
mbed_official 2:32be19c07874 415
mbed_official 2:32be19c07874 416 /**
mbed_official 2:32be19c07874 417 * Called when the CCCD has been written.
mbed_official 2:32be19c07874 418 */
mbed_official 2:32be19c07874 419 void when_descriptor_written(const GattWriteCallbackParams* event)
mbed_official 2:32be19c07874 420 {
mbed_official 2:32be19c07874 421 // should never happen
mbed_official 2:32be19c07874 422 if (!_descriptor_handle) {
mbed_official 2:32be19c07874 423 printf("\tError: received write response to unsolicited request.\r\n");
mbed_official 2:32be19c07874 424 stop();
mbed_official 2:32be19c07874 425 return;
mbed_official 2:32be19c07874 426 }
mbed_official 2:32be19c07874 427
mbed_official 2:32be19c07874 428 printf("\tCCCD at %u written.\r\n", _descriptor_handle);
mbed_official 2:32be19c07874 429 _descriptor_handle = 0;
mbed_official 2:32be19c07874 430 process_next_characteristic();
mbed_official 2:32be19c07874 431 }
mbed_official 2:32be19c07874 432
mbed_official 2:32be19c07874 433 /**
mbed_official 2:32be19c07874 434 * Print the updated value of the characteristic.
mbed_official 2:32be19c07874 435 *
mbed_official 2:32be19c07874 436 * This function is called when the server emits a notification or an
mbed_official 2:32be19c07874 437 * indication of a characteristic value the client has subscribed to.
mbed_official 2:32be19c07874 438 *
mbed_official 2:32be19c07874 439 * @see GattClient::onHVX()
mbed_official 2:32be19c07874 440 */
mbed_official 2:32be19c07874 441 void when_characteristic_changed(const GattHVXCallbackParams* event)
mbed_official 2:32be19c07874 442 {
mbed_official 2:32be19c07874 443 printf("Change on attribute %u: new value = ", event->handle);
mbed_official 2:32be19c07874 444 for (size_t i = 0; i < event->len; ++i) {
mbed_official 2:32be19c07874 445 printf("0x%02X ", event->data[i]);
mbed_official 2:32be19c07874 446 }
mbed_official 2:32be19c07874 447 printf(".\r\n");
mbed_official 2:32be19c07874 448 }
mbed_official 2:32be19c07874 449
mbed_official 2:32be19c07874 450 struct DiscoveredCharacteristicNode {
mbed_official 2:32be19c07874 451 DiscoveredCharacteristicNode(const DiscoveredCharacteristic &c) :
mbed_official 2:32be19c07874 452 value(c), next(NULL) { }
mbed_official 2:32be19c07874 453
mbed_official 2:32be19c07874 454 DiscoveredCharacteristic value;
mbed_official 2:32be19c07874 455 DiscoveredCharacteristicNode *next;
mbed_official 2:32be19c07874 456 };
mbed_official 2:32be19c07874 457
mbed_official 2:32be19c07874 458 /**
mbed_official 2:32be19c07874 459 * Add a discovered characteristic into the list of discovered characteristics.
mbed_official 2:32be19c07874 460 */
mbed_official 2:32be19c07874 461 bool add_characteristic(const DiscoveredCharacteristic *characteristic)
mbed_official 2:32be19c07874 462 {
mbed_official 2:32be19c07874 463 DiscoveredCharacteristicNode* new_node =
mbed_official 2:32be19c07874 464 new(std::nothrow) DiscoveredCharacteristicNode(*characteristic);
mbed_official 2:32be19c07874 465
mbed_official 2:32be19c07874 466 if (new_node == false) {
mbed_official 2:32be19c07874 467 printf("Error while allocating a new characteristic.\r\n");
mbed_official 2:32be19c07874 468 return false;
mbed_official 2:32be19c07874 469 }
mbed_official 2:32be19c07874 470
mbed_official 2:32be19c07874 471 if (_characteristics == NULL) {
mbed_official 2:32be19c07874 472 _characteristics = new_node;
mbed_official 2:32be19c07874 473 } else {
mbed_official 2:32be19c07874 474 DiscoveredCharacteristicNode* c = _characteristics;
mbed_official 2:32be19c07874 475 while(c->next) {
mbed_official 2:32be19c07874 476 c = c->next;
mbed_official 2:32be19c07874 477 }
mbed_official 2:32be19c07874 478 c->next = new_node;
mbed_official 2:32be19c07874 479 }
mbed_official 2:32be19c07874 480
mbed_official 2:32be19c07874 481 return true;
mbed_official 2:32be19c07874 482 }
mbed_official 2:32be19c07874 483
mbed_official 2:32be19c07874 484 /**
mbed_official 2:32be19c07874 485 * Clear the list of discovered characteristics.
mbed_official 2:32be19c07874 486 */
mbed_official 2:32be19c07874 487 void clear_characteristics(void)
mbed_official 2:32be19c07874 488 {
mbed_official 2:32be19c07874 489 DiscoveredCharacteristicNode *c= _characteristics;
mbed_official 2:32be19c07874 490
mbed_official 2:32be19c07874 491 while (c) {
mbed_official 2:32be19c07874 492 DiscoveredCharacteristicNode *n = c->next;
mbed_official 2:32be19c07874 493 delete c;
mbed_official 2:32be19c07874 494 c = n;
mbed_official 2:32be19c07874 495 }
mbed_official 2:32be19c07874 496 }
mbed_official 2:32be19c07874 497
mbed_official 2:32be19c07874 498 /**
mbed_official 2:32be19c07874 499 * Helper to construct an event handler from a member function of this
mbed_official 2:32be19c07874 500 * instance.
mbed_official 2:32be19c07874 501 */
mbed_official 2:32be19c07874 502 template<typename ContextType>
mbed_official 2:32be19c07874 503 FunctionPointerWithContext<ContextType> as_cb(
mbed_official 2:32be19c07874 504 void (Self::*member)(ContextType context)
mbed_official 2:32be19c07874 505 ) {
mbed_official 2:32be19c07874 506 return makeFunctionPointer(this, member);
mbed_official 2:32be19c07874 507 }
mbed_official 2:32be19c07874 508
mbed_official 2:32be19c07874 509 /**
mbed_official 2:32be19c07874 510 * Print the value of a UUID.
mbed_official 2:32be19c07874 511 */
mbed_official 2:32be19c07874 512 static void print_uuid(const UUID &uuid)
mbed_official 2:32be19c07874 513 {
mbed_official 2:32be19c07874 514 const uint8_t *uuid_value = uuid.getBaseUUID();
mbed_official 2:32be19c07874 515
mbed_official 2:32be19c07874 516 // UUIDs are in little endian, print them in big endian
mbed_official 2:32be19c07874 517 for (size_t i = 0; i < uuid.getLen(); ++i) {
mbed_official 2:32be19c07874 518 printf("%02X", uuid_value[(uuid.getLen() - 1) - i]);
mbed_official 2:32be19c07874 519 }
mbed_official 2:32be19c07874 520 }
mbed_official 2:32be19c07874 521
mbed_official 2:32be19c07874 522 /**
mbed_official 2:32be19c07874 523 * Print the value of a characteristic properties.
mbed_official 2:32be19c07874 524 */
mbed_official 2:32be19c07874 525 static void print_properties(const Properties_t &properties)
mbed_official 2:32be19c07874 526 {
mbed_official 2:32be19c07874 527 const struct {
mbed_official 2:32be19c07874 528 bool (Properties_t::*fn)() const;
mbed_official 2:32be19c07874 529 const char* str;
mbed_official 2:32be19c07874 530 } prop_to_str[] = {
mbed_official 2:32be19c07874 531 { &Properties_t::broadcast, "broadcast" },
mbed_official 2:32be19c07874 532 { &Properties_t::read, "read" },
mbed_official 2:32be19c07874 533 { &Properties_t::writeWoResp, "writeWoResp" },
mbed_official 2:32be19c07874 534 { &Properties_t::write, "write" },
mbed_official 2:32be19c07874 535 { &Properties_t::notify, "notify" },
mbed_official 2:32be19c07874 536 { &Properties_t::indicate, "indicate" },
mbed_official 2:32be19c07874 537 { &Properties_t::authSignedWrite, "authSignedWrite" }
mbed_official 2:32be19c07874 538 };
mbed_official 2:32be19c07874 539
mbed_official 2:32be19c07874 540 printf("[");
mbed_official 2:32be19c07874 541 for (size_t i = 0; i < (sizeof(prop_to_str) / sizeof(prop_to_str[0])); ++i) {
mbed_official 2:32be19c07874 542 if ((properties.*(prop_to_str[i].fn))()) {
mbed_official 2:32be19c07874 543 printf(" %s", prop_to_str[i].str);
mbed_official 2:32be19c07874 544 }
mbed_official 2:32be19c07874 545 }
mbed_official 2:32be19c07874 546 printf(" ]");
mbed_official 2:32be19c07874 547 }
mbed_official 2:32be19c07874 548
mbed_official 2:32be19c07874 549 GattClient *_client;
mbed_official 2:32be19c07874 550 Gap::Handle_t _connection_handle;
mbed_official 2:32be19c07874 551 DiscoveredCharacteristicNode *_characteristics;
mbed_official 2:32be19c07874 552 DiscoveredCharacteristicNode *_it;
mbed_official 2:32be19c07874 553 GattAttribute::Handle_t _descriptor_handle;
mbed_official 2:32be19c07874 554 BLE *_ble_interface;
mbed_official 2:32be19c07874 555 events::EventQueue *_event_queue;
mbed_official 2:32be19c07874 556 };
mbed_official 2:32be19c07874 557
mbed_official 2:32be19c07874 558
mbed_official 2:32be19c07874 559 int main() {
mbed_official 2:32be19c07874 560
mbed_official 2:32be19c07874 561 BLE &ble_interface = BLE::Instance();
mbed_official 2:32be19c07874 562 events::EventQueue event_queue;
mbed_official 2:32be19c07874 563 BLEProcess ble_process(event_queue, ble_interface);
mbed_official 2:32be19c07874 564 GattClientProcess gatt_client_process;
mbed_official 2:32be19c07874 565
mbed_official 2:32be19c07874 566 // Register GattClientProcess::init in the ble_process; this function will
mbed_official 2:32be19c07874 567 // be called once the ble_interface is initialized.
mbed_official 2:32be19c07874 568 ble_process.on_init(
mbed_official 2:32be19c07874 569 mbed::callback(&gatt_client_process, &GattClientProcess::init)
mbed_official 2:32be19c07874 570 );
mbed_official 2:32be19c07874 571
mbed_official 2:32be19c07874 572 // bind the event queue to the ble interface, initialize the interface
mbed_official 2:32be19c07874 573 // and start advertising
mbed_official 2:32be19c07874 574 ble_process.start();
mbed_official 2:32be19c07874 575
mbed_official 2:32be19c07874 576 // Process the event queue.
mbed_official 2:32be19c07874 577 event_queue.dispatch_forever();
mbed_official 2:32be19c07874 578
mbed_official 2:32be19c07874 579 return 0;
mbed_official 2:32be19c07874 580 }