This application demonstrates detailed uses of the GattClient APIs.

Committer:
mbed_official
Date:
Tue Jul 23 12:02:37 2019 +0100
Revision:
5:331ef6ec71f5
Parent:
2:32be19c07874
Merge pull request #245 from paul-szczepanek-arm/master

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