A GattClient example based on ST BlueNRG driving an LED service exported by a BLE_LED peripheral. Shows scanning, connections, service-discovery, and reads/writes.

Dependencies:   BLE_API X_NUCLEO_IDB0XA1 mbed

Committer:
apalmieri
Date:
Fri Feb 19 15:32:04 2016 +0000
Revision:
2:c944cfe08e79
Parent:
1:e0f4bcce540c
Child:
3:b2bf47485f85
Sync w/ rev114 of mbed lib

Who changed what in which revision?

UserRevisionLine numberNew contents of line
apalmieri 2:c944cfe08e79 1 #if 0
apalmieri 0:2e972e7d3f64 2 /* mbed Microcontroller Library
apalmieri 0:2e972e7d3f64 3 * Copyright (c) 2006-2013 ARM Limited
apalmieri 0:2e972e7d3f64 4 *
apalmieri 0:2e972e7d3f64 5 * Licensed under the Apache License, Version 2.0 (the "License");
apalmieri 0:2e972e7d3f64 6 * you may not use this file except in compliance with the License.
apalmieri 0:2e972e7d3f64 7 * You may obtain a copy of the License at
apalmieri 0:2e972e7d3f64 8 *
apalmieri 0:2e972e7d3f64 9 * http://www.apache.org/licenses/LICENSE-2.0
apalmieri 0:2e972e7d3f64 10 *
apalmieri 0:2e972e7d3f64 11 * Unless required by applicable law or agreed to in writing, software
apalmieri 0:2e972e7d3f64 12 * distributed under the License is distributed on an "AS IS" BASIS,
apalmieri 0:2e972e7d3f64 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
apalmieri 0:2e972e7d3f64 14 * See the License for the specific language governing permissions and
apalmieri 0:2e972e7d3f64 15 * limitations under the License.
apalmieri 0:2e972e7d3f64 16 */
apalmieri 0:2e972e7d3f64 17
apalmieri 0:2e972e7d3f64 18 #include "mbed.h"
apalmieri 0:2e972e7d3f64 19 #include "ble/BLE.h"
apalmieri 0:2e972e7d3f64 20 #include "ble/DiscoveredCharacteristic.h"
apalmieri 0:2e972e7d3f64 21 #include "ble/DiscoveredService.h"
apalmieri 0:2e972e7d3f64 22
apalmieri 0:2e972e7d3f64 23 #define SCAN_INT 0x30 // 30 ms = 48 * 0.625 ms
apalmieri 0:2e972e7d3f64 24 #define SCAN_WIND 0x30 // 30 ms = 48 * 0.625 ms
apalmieri 0:2e972e7d3f64 25
apalmieri 0:2e972e7d3f64 26
apalmieri 0:2e972e7d3f64 27 const Gap::Address_t BLE_address_BE = {0xCC, 0x00, 0x00, 0xE1, 0x80, 0x02};
apalmieri 0:2e972e7d3f64 28 const Gap::Address_t BLE_peer_address_BE = {0xFD, 0x66, 0x05, 0x13, 0xBE, 0xBA};
apalmieri 0:2e972e7d3f64 29
apalmieri 0:2e972e7d3f64 30 DiscoveredCharacteristic ledCharacteristic;
apalmieri 0:2e972e7d3f64 31
apalmieri 0:2e972e7d3f64 32 uint8_t toggledValue = 0;
apalmieri 0:2e972e7d3f64 33 enum {
apalmieri 0:2e972e7d3f64 34 READ = 0,
apalmieri 0:2e972e7d3f64 35 WRITE,
apalmieri 0:2e972e7d3f64 36 IDLE
apalmieri 0:2e972e7d3f64 37 };
apalmieri 0:2e972e7d3f64 38 static volatile unsigned int triggerOp = IDLE;
apalmieri 0:2e972e7d3f64 39
apalmieri 0:2e972e7d3f64 40 void disconnectionCallback(const Gap::DisconnectionCallbackParams_t *params)
apalmieri 0:2e972e7d3f64 41 {
apalmieri 0:2e972e7d3f64 42 (void)params;
apalmieri 0:2e972e7d3f64 43 printf("disconnected\n\r");
apalmieri 0:2e972e7d3f64 44 }
apalmieri 0:2e972e7d3f64 45
apalmieri 0:2e972e7d3f64 46 void advertisementCallback(const Gap::AdvertisementCallbackParams_t *params) {
apalmieri 0:2e972e7d3f64 47 if (params->peerAddr[0] != BLE_peer_address_BE[0]) {
apalmieri 0:2e972e7d3f64 48 return;
apalmieri 0:2e972e7d3f64 49 }
apalmieri 0:2e972e7d3f64 50
apalmieri 0:2e972e7d3f64 51 printf("adv peerAddr[%02x %02x %02x %02x %02x %02x] rssi %d, isScanResponse %u, AdvertisementType %u\r\n",
apalmieri 0:2e972e7d3f64 52 params->peerAddr[5], params->peerAddr[4], params->peerAddr[3], params->peerAddr[2], params->peerAddr[1], params->peerAddr[0],
apalmieri 0:2e972e7d3f64 53 params->rssi, params->isScanResponse, params->type);
apalmieri 0:2e972e7d3f64 54
apalmieri 0:2e972e7d3f64 55 if(!params->isScanResponse) {
apalmieri 0:2e972e7d3f64 56 BLE::Instance().gap().connect(params->peerAddr, Gap::ADDR_TYPE_PUBLIC, NULL, NULL);
apalmieri 0:2e972e7d3f64 57 }
apalmieri 0:2e972e7d3f64 58 }
apalmieri 0:2e972e7d3f64 59
apalmieri 0:2e972e7d3f64 60 void discoveryTerminationCallback(Gap::Handle_t connectionHandle) {
apalmieri 0:2e972e7d3f64 61 printf("terminated SD for handle %u\r\n", connectionHandle);
apalmieri 0:2e972e7d3f64 62 }
apalmieri 0:2e972e7d3f64 63
apalmieri 0:2e972e7d3f64 64 void serviceDiscoveryCallback(const DiscoveredService *service) {
apalmieri 0:2e972e7d3f64 65 if (service->getUUID().shortOrLong() == UUID::UUID_TYPE_SHORT) {
apalmieri 0:2e972e7d3f64 66 printf("S UUID-%x attrs[%u %u]\r\n", service->getUUID().getShortUUID(), service->getStartHandle(), service->getEndHandle());
apalmieri 0:2e972e7d3f64 67 } else {
apalmieri 0:2e972e7d3f64 68 printf("S UUID-");
apalmieri 0:2e972e7d3f64 69 const uint8_t *longUUIDBytes = service->getUUID().getBaseUUID();
apalmieri 0:2e972e7d3f64 70 for (unsigned i = 0; i < UUID::LENGTH_OF_LONG_UUID; i++) {
apalmieri 0:2e972e7d3f64 71 printf("%02X", longUUIDBytes[i]);
apalmieri 0:2e972e7d3f64 72 }
apalmieri 0:2e972e7d3f64 73 printf(" attrs[%u %u]\r\n", service->getStartHandle(), service->getEndHandle());
apalmieri 0:2e972e7d3f64 74 }
apalmieri 0:2e972e7d3f64 75 }
apalmieri 0:2e972e7d3f64 76
apalmieri 0:2e972e7d3f64 77 void characteristicDiscoveryCallback(const DiscoveredCharacteristic *characteristicP) {
apalmieri 0:2e972e7d3f64 78 //printf(" C UUID-%x valueAttr[%u] props[%x]\r\n", characteristicP->getShortUUID(), characteristicP->getValueHandle(), (uint8_t)characteristicP->getProperties().broadcast());
apalmieri 0:2e972e7d3f64 79 if (characteristicP->getUUID().getShortUUID() == 0xa001) { /* !ALERT! Alter this filter to suit your device. */
apalmieri 0:2e972e7d3f64 80 //printf(" C UUID-%x valueAttr[%u] props[%x]\r\n", characteristicP->getShortUUID(), characteristicP->getValueHandle(), (uint8_t)characteristicP->getProperties().broadcast());
apalmieri 0:2e972e7d3f64 81 ledCharacteristic = *characteristicP;
apalmieri 0:2e972e7d3f64 82 triggerOp = READ;
apalmieri 0:2e972e7d3f64 83 }
apalmieri 0:2e972e7d3f64 84 }
apalmieri 0:2e972e7d3f64 85
apalmieri 0:2e972e7d3f64 86 void connectionCallback(const Gap::ConnectionCallbackParams_t *params) {
apalmieri 0:2e972e7d3f64 87 uint16_t LED_SERVICE_UUID = 0xA000;
apalmieri 0:2e972e7d3f64 88 uint16_t LED_STATE_CHARACTERISTIC_UUID = 0xA001;
apalmieri 0:2e972e7d3f64 89
apalmieri 0:2e972e7d3f64 90 if (params->role == Gap::CENTRAL) {
apalmieri 0:2e972e7d3f64 91 BLE &ble = BLE::Instance();
apalmieri 0:2e972e7d3f64 92 ble.gattClient().onServiceDiscoveryTermination(discoveryTerminationCallback);
apalmieri 0:2e972e7d3f64 93 ble.gattClient().launchServiceDiscovery(params->handle, serviceDiscoveryCallback, characteristicDiscoveryCallback, LED_SERVICE_UUID, LED_STATE_CHARACTERISTIC_UUID);
apalmieri 0:2e972e7d3f64 94 }
apalmieri 0:2e972e7d3f64 95 }
apalmieri 0:2e972e7d3f64 96
apalmieri 0:2e972e7d3f64 97 void triggerToggledWrite(const GattReadCallbackParams *response) {
apalmieri 0:2e972e7d3f64 98 if (response->handle == ledCharacteristic.getValueHandle()) {
apalmieri 0:2e972e7d3f64 99 #if 0
apalmieri 0:2e972e7d3f64 100 printf("triggerToggledWrite: handle %u, offset %u, len %u\r\n", response->handle, response->offset, response->len);
apalmieri 0:2e972e7d3f64 101 for (unsigned index = 0; index < response->len; index++) {
apalmieri 0:2e972e7d3f64 102 printf("%c[%02x]", response->data[index], response->data[index]);
apalmieri 0:2e972e7d3f64 103 }
apalmieri 0:2e972e7d3f64 104 printf("\r\n");
apalmieri 0:2e972e7d3f64 105 #endif
apalmieri 0:2e972e7d3f64 106
apalmieri 0:2e972e7d3f64 107 toggledValue = response->data[0] ^ 0x1;
apalmieri 0:2e972e7d3f64 108 triggerOp = WRITE;
apalmieri 0:2e972e7d3f64 109 }
apalmieri 0:2e972e7d3f64 110 }
apalmieri 0:2e972e7d3f64 111
apalmieri 0:2e972e7d3f64 112 void triggerRead(const GattWriteCallbackParams *response) {
apalmieri 0:2e972e7d3f64 113 if (response->handle == ledCharacteristic.getValueHandle()) {
apalmieri 0:2e972e7d3f64 114 triggerOp = READ;
apalmieri 0:2e972e7d3f64 115 }
apalmieri 0:2e972e7d3f64 116 }
apalmieri 0:2e972e7d3f64 117
apalmieri 0:2e972e7d3f64 118 /**
apalmieri 0:2e972e7d3f64 119 * This function is called when the ble initialization process has failled
apalmieri 0:2e972e7d3f64 120 */
apalmieri 0:2e972e7d3f64 121 void onBleInitError(BLE &ble, ble_error_t error)
apalmieri 0:2e972e7d3f64 122 {
apalmieri 0:2e972e7d3f64 123 /* Initialization error handling should go here */
apalmieri 0:2e972e7d3f64 124 }
apalmieri 0:2e972e7d3f64 125
apalmieri 0:2e972e7d3f64 126 /**
apalmieri 0:2e972e7d3f64 127 * Callback triggered when the ble initialization process has finished
apalmieri 0:2e972e7d3f64 128 */
apalmieri 0:2e972e7d3f64 129 void bleInitComplete(BLE::InitializationCompleteCallbackContext *params)
apalmieri 0:2e972e7d3f64 130 {
apalmieri 0:2e972e7d3f64 131 BLE& ble = params->ble;
apalmieri 0:2e972e7d3f64 132 ble_error_t error = params->error;
apalmieri 0:2e972e7d3f64 133
apalmieri 0:2e972e7d3f64 134 if (error != BLE_ERROR_NONE) {
apalmieri 0:2e972e7d3f64 135 /* In case of error, forward the error handling to onBleInitError */
apalmieri 0:2e972e7d3f64 136 onBleInitError(ble, error);
apalmieri 0:2e972e7d3f64 137 return;
apalmieri 0:2e972e7d3f64 138 }
apalmieri 0:2e972e7d3f64 139
apalmieri 0:2e972e7d3f64 140 /* Ensure that it is the default instance of BLE */
apalmieri 0:2e972e7d3f64 141 if(ble.getInstanceID() != BLE::DEFAULT_INSTANCE) {
apalmieri 0:2e972e7d3f64 142 return;
apalmieri 0:2e972e7d3f64 143 }
apalmieri 0:2e972e7d3f64 144
apalmieri 0:2e972e7d3f64 145 // Set BT Address
apalmieri 1:e0f4bcce540c 146 ble.gap().setAddress(BLEProtocol::AddressType::PUBLIC, BLE_address_BE);
apalmieri 0:2e972e7d3f64 147
apalmieri 0:2e972e7d3f64 148 ble.gap().onConnection(connectionCallback);
apalmieri 0:2e972e7d3f64 149 ble.onDisconnection(disconnectionCallback);
apalmieri 0:2e972e7d3f64 150
apalmieri 0:2e972e7d3f64 151 ble.gattClient().onDataRead(triggerToggledWrite);
apalmieri 0:2e972e7d3f64 152 ble.gattClient().onDataWrite(triggerRead);
apalmieri 0:2e972e7d3f64 153
apalmieri 0:2e972e7d3f64 154 ble.gap().setScanParams(SCAN_INT, SCAN_WIND);
apalmieri 0:2e972e7d3f64 155 ble.gap().startScan(advertisementCallback);
apalmieri 0:2e972e7d3f64 156
apalmieri 0:2e972e7d3f64 157 // infinite loop
apalmieri 0:2e972e7d3f64 158 while (1) {
apalmieri 0:2e972e7d3f64 159 if (!ble.gattClient().isServiceDiscoveryActive()) {
apalmieri 0:2e972e7d3f64 160 switch(triggerOp) {
apalmieri 0:2e972e7d3f64 161 case READ:
apalmieri 0:2e972e7d3f64 162 triggerOp = IDLE;
apalmieri 0:2e972e7d3f64 163 ledCharacteristic.read();
apalmieri 0:2e972e7d3f64 164 break;
apalmieri 0:2e972e7d3f64 165 case WRITE:
apalmieri 0:2e972e7d3f64 166 triggerOp = IDLE;
apalmieri 0:2e972e7d3f64 167 ledCharacteristic.write(1, &toggledValue);
apalmieri 0:2e972e7d3f64 168 break;
apalmieri 0:2e972e7d3f64 169 }
apalmieri 0:2e972e7d3f64 170 }
apalmieri 0:2e972e7d3f64 171 ble.waitForEvent();
apalmieri 0:2e972e7d3f64 172 }
apalmieri 0:2e972e7d3f64 173 }
apalmieri 0:2e972e7d3f64 174
apalmieri 0:2e972e7d3f64 175 int main(void)
apalmieri 0:2e972e7d3f64 176 {
apalmieri 0:2e972e7d3f64 177 BLE::Instance().init(bleInitComplete);
apalmieri 0:2e972e7d3f64 178 }
apalmieri 0:2e972e7d3f64 179
apalmieri 2:c944cfe08e79 180 #endif
apalmieri 2:c944cfe08e79 181
apalmieri 2:c944cfe08e79 182
apalmieri 2:c944cfe08e79 183
apalmieri 2:c944cfe08e79 184
apalmieri 2:c944cfe08e79 185
apalmieri 2:c944cfe08e79 186 /* mbed Microcontroller Library
apalmieri 2:c944cfe08e79 187 * Copyright (c) 2006-2015 ARM Limited
apalmieri 2:c944cfe08e79 188 *
apalmieri 2:c944cfe08e79 189 * Licensed under the Apache License, Version 2.0 (the "License");
apalmieri 2:c944cfe08e79 190 * you may not use this file except in compliance with the License.
apalmieri 2:c944cfe08e79 191 * You may obtain a copy of the License at
apalmieri 2:c944cfe08e79 192 *
apalmieri 2:c944cfe08e79 193 * http://www.apache.org/licenses/LICENSE-2.0
apalmieri 2:c944cfe08e79 194 *
apalmieri 2:c944cfe08e79 195 * Unless required by applicable law or agreed to in writing, software
apalmieri 2:c944cfe08e79 196 * distributed under the License is distributed on an "AS IS" BASIS,
apalmieri 2:c944cfe08e79 197 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
apalmieri 2:c944cfe08e79 198 * See the License for the specific language governing permissions and
apalmieri 2:c944cfe08e79 199 * limitations under the License.
apalmieri 2:c944cfe08e79 200 */
apalmieri 2:c944cfe08e79 201
apalmieri 2:c944cfe08e79 202 #include "mbed.h"
apalmieri 2:c944cfe08e79 203 #include "ble/Gap.h"
apalmieri 2:c944cfe08e79 204 #include "ble/BLE.h"
apalmieri 2:c944cfe08e79 205 #include "ble/DiscoveredCharacteristic.h"
apalmieri 2:c944cfe08e79 206 #include "ble/DiscoveredService.h"
apalmieri 2:c944cfe08e79 207 #include "ble/GapAdvertisingParams.h"
apalmieri 2:c944cfe08e79 208
apalmieri 2:c944cfe08e79 209
apalmieri 2:c944cfe08e79 210 #define PRINTF(...) printf(__VA_ARGS__)
apalmieri 2:c944cfe08e79 211
apalmieri 2:c944cfe08e79 212 BLE ble;
apalmieri 2:c944cfe08e79 213 DigitalOut led1(LED1);
apalmieri 2:c944cfe08e79 214
apalmieri 2:c944cfe08e79 215
apalmieri 2:c944cfe08e79 216 bool _connected = false;
apalmieri 2:c944cfe08e79 217
apalmieri 2:c944cfe08e79 218 DiscoveredCharacteristic hrmCharacteristic;
apalmieri 2:c944cfe08e79 219 static volatile bool triggerHrmCharacteristic = false;
apalmieri 2:c944cfe08e79 220 //PROTOTYPES
apalmieri 2:c944cfe08e79 221 void PrintScanResult(const Gap::AdvertisementCallbackParams_t *params);
apalmieri 2:c944cfe08e79 222 void periodicCallback(void);
apalmieri 2:c944cfe08e79 223 void connectToDevice(const Gap::Address_t peerAddr);
apalmieri 2:c944cfe08e79 224
apalmieri 2:c944cfe08e79 225 void serviceDiscoveryCallback(const DiscoveredService *service);
apalmieri 2:c944cfe08e79 226 void characteristicDiscoveryCallback(const DiscoveredCharacteristic *characteristicP);
apalmieri 2:c944cfe08e79 227 void discoveryTerminationCallback(Gap::Handle_t connectionHandle);
apalmieri 2:c944cfe08e79 228
apalmieri 2:c944cfe08e79 229
apalmieri 2:c944cfe08e79 230 void disconnectionCallback(const Gap::DisconnectionCallbackParams_t *params) {
apalmieri 2:c944cfe08e79 231 _connected = false;
apalmieri 2:c944cfe08e79 232 PRINTF("disconnected\r\n");
apalmieri 2:c944cfe08e79 233 }
apalmieri 2:c944cfe08e79 234
apalmieri 2:c944cfe08e79 235 void periodicCallback(void)
apalmieri 2:c944cfe08e79 236 {
apalmieri 2:c944cfe08e79 237 led1 = !led1; /* Do blinky on LED1 while we're waiting for BLE events */
apalmieri 2:c944cfe08e79 238 /* Note that the periodicCallback() executes in interrupt context, so it is safer to do
apalmieri 2:c944cfe08e79 239 * heavy-weight sensor polling from the main thread. */
apalmieri 2:c944cfe08e79 240 triggerHrmCharacteristic = true;
apalmieri 2:c944cfe08e79 241 }
apalmieri 2:c944cfe08e79 242
apalmieri 2:c944cfe08e79 243 void PrintScanResult(const Gap::AdvertisementCallbackParams_t *params)
apalmieri 2:c944cfe08e79 244 {
apalmieri 2:c944cfe08e79 245 for(int8_t i = 5; i>=0; i--)
apalmieri 2:c944cfe08e79 246 {
apalmieri 2:c944cfe08e79 247 PRINTF("%02x",params->peerAddr[i] );
apalmieri 2:c944cfe08e79 248 if(i != 0)PRINTF("-");
apalmieri 2:c944cfe08e79 249 }
apalmieri 2:c944cfe08e79 250 PRINTF("\r\n");
apalmieri 2:c944cfe08e79 251
apalmieri 2:c944cfe08e79 252 PRINTF("RSSI: %d\r\n",params->rssi );
apalmieri 2:c944cfe08e79 253
apalmieri 2:c944cfe08e79 254 if(params->isScanResponse){
apalmieri 2:c944cfe08e79 255 PRINTF("isScanResponse=true\r\n");
apalmieri 2:c944cfe08e79 256 } else {
apalmieri 2:c944cfe08e79 257 PRINTF("isScanResponse=false\r\n");
apalmieri 2:c944cfe08e79 258 }
apalmieri 2:c944cfe08e79 259
apalmieri 2:c944cfe08e79 260 switch(params->type)
apalmieri 2:c944cfe08e79 261 {
apalmieri 2:c944cfe08e79 262 case GapAdvertisingParams::ADV_CONNECTABLE_UNDIRECTED:
apalmieri 2:c944cfe08e79 263 PRINTF("ADV_CONNECTABLE_UNDIRECTED\r\n");
apalmieri 2:c944cfe08e79 264 break;
apalmieri 2:c944cfe08e79 265 case GapAdvertisingParams::ADV_CONNECTABLE_DIRECTED:
apalmieri 2:c944cfe08e79 266 PRINTF("ADV_CONNECTABLE_DIRECTED\r\n");
apalmieri 2:c944cfe08e79 267 break;
apalmieri 2:c944cfe08e79 268 case GapAdvertisingParams::ADV_SCANNABLE_UNDIRECTED:
apalmieri 2:c944cfe08e79 269 PRINTF("ADV_SCANNABLE_UNDIRECTED\r\n");
apalmieri 2:c944cfe08e79 270 break;
apalmieri 2:c944cfe08e79 271 case GapAdvertisingParams::ADV_NON_CONNECTABLE_UNDIRECTED:
apalmieri 2:c944cfe08e79 272 PRINTF("ADV_NON_CONNECTABLE_UNDIRECTED\r\n");
apalmieri 2:c944cfe08e79 273 break;
apalmieri 2:c944cfe08e79 274
apalmieri 2:c944cfe08e79 275 }
apalmieri 2:c944cfe08e79 276
apalmieri 2:c944cfe08e79 277 PRINTF("advertisingDataLen: %d\r\n",params->advertisingDataLen );
apalmieri 2:c944cfe08e79 278
apalmieri 2:c944cfe08e79 279 PRINTF("advertisingData: ");
apalmieri 2:c944cfe08e79 280 for(int i=0; i < params->advertisingDataLen; i++)
apalmieri 2:c944cfe08e79 281 {
apalmieri 2:c944cfe08e79 282 PRINTF("%02x",params->advertisingData[i]);
apalmieri 2:c944cfe08e79 283 if(i != params->advertisingDataLen - 1)PRINTF("-");
apalmieri 2:c944cfe08e79 284 }
apalmieri 2:c944cfe08e79 285 PRINTF("\r\n");
apalmieri 2:c944cfe08e79 286 }
apalmieri 2:c944cfe08e79 287
apalmieri 2:c944cfe08e79 288
apalmieri 2:c944cfe08e79 289 void scanResultReceived(const Gap::AdvertisementCallbackParams_t *params)
apalmieri 2:c944cfe08e79 290 {
apalmieri 2:c944cfe08e79 291 PRINTF("\r\nscanResultReceived\r\n");
apalmieri 2:c944cfe08e79 292
apalmieri 2:c944cfe08e79 293 //print advertsing values
apalmieri 2:c944cfe08e79 294 PrintScanResult(params);
apalmieri 2:c944cfe08e79 295
apalmieri 2:c944cfe08e79 296 PRINTF("scan result ... try connect\r\n");
apalmieri 2:c944cfe08e79 297 connectToDevice(params->peerAddr);
apalmieri 2:c944cfe08e79 298 }
apalmieri 2:c944cfe08e79 299
apalmieri 2:c944cfe08e79 300 void connectToDevice(const Gap::Address_t peerAddr)
apalmieri 2:c944cfe08e79 301 {
apalmieri 2:c944cfe08e79 302 ble_error_t ret = ble.gap().connect(peerAddr, Gap::ADDR_TYPE_PUBLIC, NULL, NULL);
apalmieri 2:c944cfe08e79 303
apalmieri 2:c944cfe08e79 304 if(ret == BLE_ERROR_NONE) {
apalmieri 2:c944cfe08e79 305 PRINTF("SUCCESS: connect\r\n");
apalmieri 2:c944cfe08e79 306 } else {
apalmieri 2:c944cfe08e79 307 PRINTF("ERROR : connect\r\n");
apalmieri 2:c944cfe08e79 308 }
apalmieri 2:c944cfe08e79 309 }
apalmieri 2:c944cfe08e79 310
apalmieri 2:c944cfe08e79 311 void serviceDiscoveryCallback(const DiscoveredService *service) {
apalmieri 2:c944cfe08e79 312 PRINTF("Service discovery callback\r\n");
apalmieri 2:c944cfe08e79 313
apalmieri 2:c944cfe08e79 314 if (service->getUUID().shortOrLong() == UUID::UUID_TYPE_SHORT) {
apalmieri 2:c944cfe08e79 315 PRINTF("S UUID-%x attrs[%u %u]\r\n", service->getUUID().getShortUUID(), service->getStartHandle(), service->getEndHandle());
apalmieri 2:c944cfe08e79 316 } else {
apalmieri 2:c944cfe08e79 317 printf("S UUID-");
apalmieri 2:c944cfe08e79 318 const uint8_t *longUUIDBytes = service->getUUID().getBaseUUID();
apalmieri 2:c944cfe08e79 319 for (unsigned i = 0; i < UUID::LENGTH_OF_LONG_UUID; i++) {
apalmieri 2:c944cfe08e79 320 printf("%02x", longUUIDBytes[i]);
apalmieri 2:c944cfe08e79 321 }
apalmieri 2:c944cfe08e79 322 PRINTF(" attrs[%u %u]\r\n", service->getStartHandle(), service->getEndHandle());
apalmieri 2:c944cfe08e79 323 }
apalmieri 2:c944cfe08e79 324 }
apalmieri 2:c944cfe08e79 325
apalmieri 2:c944cfe08e79 326 void characteristicDiscoveryCallback(const DiscoveredCharacteristic *characteristicP) {
apalmieri 2:c944cfe08e79 327 PRINTF("Characteristic discovery callback\r\n");
apalmieri 2:c944cfe08e79 328
apalmieri 2:c944cfe08e79 329 PRINTF(" C UUID-%x valueAttr[%u] props[%x]\r\n", characteristicP->getUUID().getShortUUID(), characteristicP->getValueHandle(), (uint8_t)characteristicP->getProperties().broadcast());
apalmieri 2:c944cfe08e79 330 //TODO: use hear rate characteristic
apalmieri 2:c944cfe08e79 331 if (characteristicP->getUUID().getShortUUID() == 0x2A00) {
apalmieri 2:c944cfe08e79 332 hrmCharacteristic = *characteristicP;
apalmieri 2:c944cfe08e79 333 triggerHrmCharacteristic = true;
apalmieri 2:c944cfe08e79 334 PRINTF("device name characteristic found\r\n");
apalmieri 2:c944cfe08e79 335 }
apalmieri 2:c944cfe08e79 336 }
apalmieri 2:c944cfe08e79 337
apalmieri 2:c944cfe08e79 338 void discoveryTerminationCallback(Gap::Handle_t connectionHandle) {
apalmieri 2:c944cfe08e79 339 PRINTF("terminated SD for handle %u\r\n", connectionHandle);
apalmieri 2:c944cfe08e79 340 }
apalmieri 2:c944cfe08e79 341
apalmieri 2:c944cfe08e79 342 void timeoutCallback(Gap::TimeoutSource_t param) {
apalmieri 2:c944cfe08e79 343
apalmieri 2:c944cfe08e79 344 switch(param)
apalmieri 2:c944cfe08e79 345 {
apalmieri 2:c944cfe08e79 346 case Gap::TIMEOUT_SRC_ADVERTISING:
apalmieri 2:c944cfe08e79 347 PRINTF("Timeout: Advertising\r\n");
apalmieri 2:c944cfe08e79 348 break;
apalmieri 2:c944cfe08e79 349 case Gap::TIMEOUT_SRC_SECURITY_REQUEST:
apalmieri 2:c944cfe08e79 350 PRINTF("Timeout: Security access\r\n");
apalmieri 2:c944cfe08e79 351 break;
apalmieri 2:c944cfe08e79 352 case Gap::TIMEOUT_SRC_SCAN:
apalmieri 2:c944cfe08e79 353 PRINTF("Timeout: Scan\r\n");
apalmieri 2:c944cfe08e79 354 break;
apalmieri 2:c944cfe08e79 355 case Gap::TIMEOUT_SRC_CONN:
apalmieri 2:c944cfe08e79 356 PRINTF("Timeout: Conn\r\n");
apalmieri 2:c944cfe08e79 357 break;
apalmieri 2:c944cfe08e79 358 }
apalmieri 2:c944cfe08e79 359 }
apalmieri 2:c944cfe08e79 360
apalmieri 2:c944cfe08e79 361 void connectionCallback(const Gap::ConnectionCallbackParams_t *params) {
apalmieri 2:c944cfe08e79 362 if (params->role == Gap::CENTRAL) {
apalmieri 2:c944cfe08e79 363 PRINTF("Launch service discovery\r\n");
apalmieri 2:c944cfe08e79 364 //TODO: use heart rate service
apalmieri 2:c944cfe08e79 365 ble.gattClient().onServiceDiscoveryTermination(discoveryTerminationCallback);
apalmieri 2:c944cfe08e79 366 ble.gattClient().launchServiceDiscovery(params->handle, serviceDiscoveryCallback, characteristicDiscoveryCallback, 0x1800, 0x2A00);
apalmieri 2:c944cfe08e79 367 _connected = true;
apalmieri 2:c944cfe08e79 368 // ble.gattClient().launchServiceDiscovery(params->handle, serviceDiscoveryCallback, characteristicDiscoveryCallback, GattService::UUID_HEART_RATE_SERVICE, GattCharacteristic::UUID_HEART_RATE_MEASUREMENT_CHAR); //BLE_UUID_UNKNOWN
apalmieri 2:c944cfe08e79 369 }
apalmieri 2:c944cfe08e79 370 else {
apalmieri 2:c944cfe08e79 371 PRINTF("No central role\r\n");
apalmieri 2:c944cfe08e79 372 }
apalmieri 2:c944cfe08e79 373 }
apalmieri 2:c944cfe08e79 374
apalmieri 2:c944cfe08e79 375
apalmieri 2:c944cfe08e79 376 void readCallback(const GattReadCallbackParams *response)
apalmieri 2:c944cfe08e79 377 {
apalmieri 2:c944cfe08e79 378 PRINTF("readCallback\r\n");
apalmieri 2:c944cfe08e79 379
apalmieri 2:c944cfe08e79 380 if (response->handle == hrmCharacteristic.getValueHandle()) {
apalmieri 2:c944cfe08e79 381 PRINTF("readCallback: handle %u, offset %u, len %u\r\n", response->handle, response->offset, response->len);
apalmieri 2:c944cfe08e79 382 for (unsigned index = 0; index < response->len; index++) {
apalmieri 2:c944cfe08e79 383 PRINTF("%c[%02x]", response->data[index], response->data[index]);
apalmieri 2:c944cfe08e79 384 }
apalmieri 2:c944cfe08e79 385 PRINTF("\r\n");
apalmieri 2:c944cfe08e79 386 }
apalmieri 2:c944cfe08e79 387 }
apalmieri 2:c944cfe08e79 388
apalmieri 2:c944cfe08e79 389 /**
apalmieri 2:c944cfe08e79 390 * This function is called when the ble initialization process has failled
apalmieri 2:c944cfe08e79 391 */
apalmieri 2:c944cfe08e79 392 void onBleInitError(BLE &ble, ble_error_t error)
apalmieri 2:c944cfe08e79 393 {
apalmieri 2:c944cfe08e79 394 PRINTF("BLE init error");
apalmieri 2:c944cfe08e79 395 }
apalmieri 2:c944cfe08e79 396
apalmieri 2:c944cfe08e79 397 /**
apalmieri 2:c944cfe08e79 398 * Callback triggered when the ble initialization process has finished
apalmieri 2:c944cfe08e79 399 */
apalmieri 2:c944cfe08e79 400 void bleInitComplete(BLE::InitializationCompleteCallbackContext *params)
apalmieri 2:c944cfe08e79 401 {
apalmieri 2:c944cfe08e79 402
apalmieri 2:c944cfe08e79 403 PRINTF("init complete\r\n");
apalmieri 2:c944cfe08e79 404
apalmieri 2:c944cfe08e79 405 BLE& ble = params->ble;
apalmieri 2:c944cfe08e79 406 ble_error_t error = params->error;
apalmieri 2:c944cfe08e79 407
apalmieri 2:c944cfe08e79 408 if (error != BLE_ERROR_NONE) {
apalmieri 2:c944cfe08e79 409 /* In case of error, forward the error handling to onBleInitError */
apalmieri 2:c944cfe08e79 410 PRINTF("Error init\r\n");
apalmieri 2:c944cfe08e79 411 onBleInitError(ble, error);
apalmieri 2:c944cfe08e79 412 return;
apalmieri 2:c944cfe08e79 413 }
apalmieri 2:c944cfe08e79 414
apalmieri 2:c944cfe08e79 415 /* Ensure that it is the default instance of BLE */
apalmieri 2:c944cfe08e79 416 if(ble.getInstanceID() != BLE::DEFAULT_INSTANCE) {
apalmieri 2:c944cfe08e79 417 PRINTF("Error default instance\r\n");
apalmieri 2:c944cfe08e79 418 return;
apalmieri 2:c944cfe08e79 419 }
apalmieri 2:c944cfe08e79 420
apalmieri 2:c944cfe08e79 421 ble.onTimeout(timeoutCallback);
apalmieri 2:c944cfe08e79 422 ble.onConnection(connectionCallback);
apalmieri 2:c944cfe08e79 423 ble.onDisconnection(disconnectionCallback);
apalmieri 2:c944cfe08e79 424 ble.gattClient().onDataRead(readCallback);
apalmieri 2:c944cfe08e79 425
apalmieri 2:c944cfe08e79 426 ble.gap().setScanParams(300, 300);
apalmieri 2:c944cfe08e79 427 ble.gap().startScan(scanResultReceived);
apalmieri 2:c944cfe08e79 428 PRINTF("scan started...\r\n");
apalmieri 2:c944cfe08e79 429
apalmieri 2:c944cfe08e79 430
apalmieri 2:c944cfe08e79 431 // infinite loop
apalmieri 2:c944cfe08e79 432 while (1) {
apalmieri 2:c944cfe08e79 433 // check for trigger from periodicCallback()
apalmieri 2:c944cfe08e79 434 if (triggerHrmCharacteristic && !ble.gattClient().isServiceDiscoveryActive() && _connected) {
apalmieri 2:c944cfe08e79 435
apalmieri 2:c944cfe08e79 436 triggerHrmCharacteristic = false;
apalmieri 2:c944cfe08e79 437 PRINTF("START READ\r\n");
apalmieri 2:c944cfe08e79 438 hrmCharacteristic.read();
apalmieri 2:c944cfe08e79 439
apalmieri 2:c944cfe08e79 440 } else {
apalmieri 2:c944cfe08e79 441 ble.waitForEvent(); // low power wait for event
apalmieri 2:c944cfe08e79 442 }
apalmieri 2:c944cfe08e79 443 }
apalmieri 2:c944cfe08e79 444
apalmieri 2:c944cfe08e79 445
apalmieri 2:c944cfe08e79 446
apalmieri 2:c944cfe08e79 447
apalmieri 2:c944cfe08e79 448 }
apalmieri 2:c944cfe08e79 449
apalmieri 2:c944cfe08e79 450 int main(void)
apalmieri 2:c944cfe08e79 451 {
apalmieri 2:c944cfe08e79 452 PRINTF("started...\r\n");
apalmieri 2:c944cfe08e79 453
apalmieri 2:c944cfe08e79 454 led1 = 1;
apalmieri 2:c944cfe08e79 455 Ticker ticker;
apalmieri 2:c944cfe08e79 456 ticker.attach(periodicCallback, 1); // blink LED every second
apalmieri 2:c944cfe08e79 457
apalmieri 2:c944cfe08e79 458 _connected = false;
apalmieri 2:c944cfe08e79 459
apalmieri 2:c944cfe08e79 460 PRINTF("start init...\r\n");
apalmieri 2:c944cfe08e79 461
apalmieri 2:c944cfe08e79 462 ble.init(bleInitComplete);
apalmieri 2:c944cfe08e79 463 }