Gestione Bluetooth per il progetto Tarallo

Committer:
fdalforno
Date:
Thu Jan 16 14:48:30 2020 +0000
Revision:
82:443323e7d4c9
Parent:
76:652c2be531c7
Gestione client Bluetooth per scheda F401RE

Who changed what in which revision?

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