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 Sep 16 10:46:07 2016 +0000
Revision:
6:8b46e5e8e572
Parent:
3:b2bf47485f85
Sync w/ mbed (rev125) BLE_API (rev1208) and X_NUCLEO_IDB0XA1 (rev307) libs

Who changed what in which revision?

UserRevisionLine numberNew contents of line
apalmieri 0:2e972e7d3f64 1 /* mbed Microcontroller Library
apalmieri 0:2e972e7d3f64 2 * Copyright (c) 2006-2013 ARM Limited
apalmieri 0:2e972e7d3f64 3 *
apalmieri 0:2e972e7d3f64 4 * Licensed under the Apache License, Version 2.0 (the "License");
apalmieri 0:2e972e7d3f64 5 * you may not use this file except in compliance with the License.
apalmieri 0:2e972e7d3f64 6 * You may obtain a copy of the License at
apalmieri 0:2e972e7d3f64 7 *
apalmieri 0:2e972e7d3f64 8 * http://www.apache.org/licenses/LICENSE-2.0
apalmieri 0:2e972e7d3f64 9 *
apalmieri 0:2e972e7d3f64 10 * Unless required by applicable law or agreed to in writing, software
apalmieri 0:2e972e7d3f64 11 * distributed under the License is distributed on an "AS IS" BASIS,
apalmieri 0:2e972e7d3f64 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
apalmieri 0:2e972e7d3f64 13 * See the License for the specific language governing permissions and
apalmieri 0:2e972e7d3f64 14 * limitations under the License.
apalmieri 0:2e972e7d3f64 15 */
apalmieri 0:2e972e7d3f64 16
apalmieri 0:2e972e7d3f64 17 #include "mbed.h"
apalmieri 0:2e972e7d3f64 18 #include "ble/BLE.h"
apalmieri 0:2e972e7d3f64 19 #include "ble/DiscoveredCharacteristic.h"
apalmieri 0:2e972e7d3f64 20 #include "ble/DiscoveredService.h"
apalmieri 0:2e972e7d3f64 21
apalmieri 0:2e972e7d3f64 22 #define SCAN_INT 0x30 // 30 ms = 48 * 0.625 ms
apalmieri 0:2e972e7d3f64 23 #define SCAN_WIND 0x30 // 30 ms = 48 * 0.625 ms
apalmieri 0:2e972e7d3f64 24
apalmieri 0:2e972e7d3f64 25
apalmieri 0:2e972e7d3f64 26 const Gap::Address_t BLE_address_BE = {0xCC, 0x00, 0x00, 0xE1, 0x80, 0x02};
apalmieri 0:2e972e7d3f64 27 const Gap::Address_t BLE_peer_address_BE = {0xFD, 0x66, 0x05, 0x13, 0xBE, 0xBA};
apalmieri 0:2e972e7d3f64 28
apalmieri 0:2e972e7d3f64 29 DiscoveredCharacteristic ledCharacteristic;
apalmieri 0:2e972e7d3f64 30
apalmieri 0:2e972e7d3f64 31 uint8_t toggledValue = 0;
apalmieri 0:2e972e7d3f64 32 enum {
apalmieri 0:2e972e7d3f64 33 READ = 0,
apalmieri 0:2e972e7d3f64 34 WRITE,
apalmieri 0:2e972e7d3f64 35 IDLE
apalmieri 0:2e972e7d3f64 36 };
apalmieri 0:2e972e7d3f64 37 static volatile unsigned int triggerOp = IDLE;
apalmieri 0:2e972e7d3f64 38
apalmieri 0:2e972e7d3f64 39 void disconnectionCallback(const Gap::DisconnectionCallbackParams_t *params)
apalmieri 0:2e972e7d3f64 40 {
apalmieri 0:2e972e7d3f64 41 (void)params;
apalmieri 0:2e972e7d3f64 42 printf("disconnected\n\r");
apalmieri 0:2e972e7d3f64 43 }
apalmieri 0:2e972e7d3f64 44
apalmieri 0:2e972e7d3f64 45 void advertisementCallback(const Gap::AdvertisementCallbackParams_t *params) {
apalmieri 0:2e972e7d3f64 46 if (params->peerAddr[0] != BLE_peer_address_BE[0]) {
apalmieri 0:2e972e7d3f64 47 return;
apalmieri 0:2e972e7d3f64 48 }
apalmieri 0:2e972e7d3f64 49
apalmieri 0:2e972e7d3f64 50 printf("adv peerAddr[%02x %02x %02x %02x %02x %02x] rssi %d, isScanResponse %u, AdvertisementType %u\r\n",
apalmieri 0:2e972e7d3f64 51 params->peerAddr[5], params->peerAddr[4], params->peerAddr[3], params->peerAddr[2], params->peerAddr[1], params->peerAddr[0],
apalmieri 0:2e972e7d3f64 52 params->rssi, params->isScanResponse, params->type);
apalmieri 0:2e972e7d3f64 53
apalmieri 0:2e972e7d3f64 54 if(!params->isScanResponse) {
apalmieri 0:2e972e7d3f64 55 BLE::Instance().gap().connect(params->peerAddr, Gap::ADDR_TYPE_PUBLIC, NULL, NULL);
apalmieri 0:2e972e7d3f64 56 }
apalmieri 0:2e972e7d3f64 57 }
apalmieri 0:2e972e7d3f64 58
apalmieri 0:2e972e7d3f64 59 void discoveryTerminationCallback(Gap::Handle_t connectionHandle) {
apalmieri 0:2e972e7d3f64 60 printf("terminated SD for handle %u\r\n", connectionHandle);
apalmieri 0:2e972e7d3f64 61 }
apalmieri 0:2e972e7d3f64 62
apalmieri 0:2e972e7d3f64 63 void serviceDiscoveryCallback(const DiscoveredService *service) {
apalmieri 0:2e972e7d3f64 64 if (service->getUUID().shortOrLong() == UUID::UUID_TYPE_SHORT) {
apalmieri 0:2e972e7d3f64 65 printf("S UUID-%x attrs[%u %u]\r\n", service->getUUID().getShortUUID(), service->getStartHandle(), service->getEndHandle());
apalmieri 0:2e972e7d3f64 66 } else {
apalmieri 0:2e972e7d3f64 67 printf("S UUID-");
apalmieri 0:2e972e7d3f64 68 const uint8_t *longUUIDBytes = service->getUUID().getBaseUUID();
apalmieri 0:2e972e7d3f64 69 for (unsigned i = 0; i < UUID::LENGTH_OF_LONG_UUID; i++) {
apalmieri 0:2e972e7d3f64 70 printf("%02X", longUUIDBytes[i]);
apalmieri 0:2e972e7d3f64 71 }
apalmieri 0:2e972e7d3f64 72 printf(" attrs[%u %u]\r\n", service->getStartHandle(), service->getEndHandle());
apalmieri 0:2e972e7d3f64 73 }
apalmieri 0:2e972e7d3f64 74 }
apalmieri 0:2e972e7d3f64 75
apalmieri 0:2e972e7d3f64 76 void characteristicDiscoveryCallback(const DiscoveredCharacteristic *characteristicP) {
apalmieri 0:2e972e7d3f64 77 //printf(" C UUID-%x valueAttr[%u] props[%x]\r\n", characteristicP->getShortUUID(), characteristicP->getValueHandle(), (uint8_t)characteristicP->getProperties().broadcast());
apalmieri 0:2e972e7d3f64 78 if (characteristicP->getUUID().getShortUUID() == 0xa001) { /* !ALERT! Alter this filter to suit your device. */
apalmieri 0:2e972e7d3f64 79 //printf(" C UUID-%x valueAttr[%u] props[%x]\r\n", characteristicP->getShortUUID(), characteristicP->getValueHandle(), (uint8_t)characteristicP->getProperties().broadcast());
apalmieri 0:2e972e7d3f64 80 ledCharacteristic = *characteristicP;
apalmieri 0:2e972e7d3f64 81 triggerOp = READ;
apalmieri 0:2e972e7d3f64 82 }
apalmieri 0:2e972e7d3f64 83 }
apalmieri 0:2e972e7d3f64 84
apalmieri 0:2e972e7d3f64 85 void connectionCallback(const Gap::ConnectionCallbackParams_t *params) {
apalmieri 0:2e972e7d3f64 86 uint16_t LED_SERVICE_UUID = 0xA000;
apalmieri 0:2e972e7d3f64 87 uint16_t LED_STATE_CHARACTERISTIC_UUID = 0xA001;
apalmieri 0:2e972e7d3f64 88
apalmieri 0:2e972e7d3f64 89 if (params->role == Gap::CENTRAL) {
apalmieri 0:2e972e7d3f64 90 BLE &ble = BLE::Instance();
apalmieri 0:2e972e7d3f64 91 ble.gattClient().onServiceDiscoveryTermination(discoveryTerminationCallback);
apalmieri 0:2e972e7d3f64 92 ble.gattClient().launchServiceDiscovery(params->handle, serviceDiscoveryCallback, characteristicDiscoveryCallback, LED_SERVICE_UUID, LED_STATE_CHARACTERISTIC_UUID);
apalmieri 0:2e972e7d3f64 93 }
apalmieri 0:2e972e7d3f64 94 }
apalmieri 0:2e972e7d3f64 95
apalmieri 0:2e972e7d3f64 96 void triggerToggledWrite(const GattReadCallbackParams *response) {
apalmieri 0:2e972e7d3f64 97 if (response->handle == ledCharacteristic.getValueHandle()) {
apalmieri 0:2e972e7d3f64 98 #if 0
apalmieri 0:2e972e7d3f64 99 printf("triggerToggledWrite: handle %u, offset %u, len %u\r\n", response->handle, response->offset, response->len);
apalmieri 0:2e972e7d3f64 100 for (unsigned index = 0; index < response->len; index++) {
apalmieri 0:2e972e7d3f64 101 printf("%c[%02x]", response->data[index], response->data[index]);
apalmieri 0:2e972e7d3f64 102 }
apalmieri 0:2e972e7d3f64 103 printf("\r\n");
apalmieri 0:2e972e7d3f64 104 #endif
apalmieri 0:2e972e7d3f64 105
apalmieri 0:2e972e7d3f64 106 toggledValue = response->data[0] ^ 0x1;
apalmieri 0:2e972e7d3f64 107 triggerOp = WRITE;
apalmieri 0:2e972e7d3f64 108 }
apalmieri 0:2e972e7d3f64 109 }
apalmieri 0:2e972e7d3f64 110
apalmieri 0:2e972e7d3f64 111 void triggerRead(const GattWriteCallbackParams *response) {
apalmieri 0:2e972e7d3f64 112 if (response->handle == ledCharacteristic.getValueHandle()) {
apalmieri 0:2e972e7d3f64 113 triggerOp = READ;
apalmieri 0:2e972e7d3f64 114 }
apalmieri 0:2e972e7d3f64 115 }
apalmieri 0:2e972e7d3f64 116
apalmieri 0:2e972e7d3f64 117 /**
apalmieri 0:2e972e7d3f64 118 * This function is called when the ble initialization process has failled
apalmieri 0:2e972e7d3f64 119 */
apalmieri 0:2e972e7d3f64 120 void onBleInitError(BLE &ble, ble_error_t error)
apalmieri 0:2e972e7d3f64 121 {
apalmieri 0:2e972e7d3f64 122 /* Initialization error handling should go here */
apalmieri 0:2e972e7d3f64 123 }
apalmieri 0:2e972e7d3f64 124
apalmieri 0:2e972e7d3f64 125 /**
apalmieri 0:2e972e7d3f64 126 * Callback triggered when the ble initialization process has finished
apalmieri 0:2e972e7d3f64 127 */
apalmieri 0:2e972e7d3f64 128 void bleInitComplete(BLE::InitializationCompleteCallbackContext *params)
apalmieri 0:2e972e7d3f64 129 {
apalmieri 0:2e972e7d3f64 130 BLE& ble = params->ble;
apalmieri 0:2e972e7d3f64 131 ble_error_t error = params->error;
apalmieri 0:2e972e7d3f64 132
apalmieri 0:2e972e7d3f64 133 if (error != BLE_ERROR_NONE) {
apalmieri 0:2e972e7d3f64 134 /* In case of error, forward the error handling to onBleInitError */
apalmieri 0:2e972e7d3f64 135 onBleInitError(ble, error);
apalmieri 0:2e972e7d3f64 136 return;
apalmieri 0:2e972e7d3f64 137 }
apalmieri 0:2e972e7d3f64 138
apalmieri 0:2e972e7d3f64 139 /* Ensure that it is the default instance of BLE */
apalmieri 0:2e972e7d3f64 140 if(ble.getInstanceID() != BLE::DEFAULT_INSTANCE) {
apalmieri 0:2e972e7d3f64 141 return;
apalmieri 0:2e972e7d3f64 142 }
apalmieri 0:2e972e7d3f64 143
apalmieri 0:2e972e7d3f64 144 // Set BT Address
apalmieri 1:e0f4bcce540c 145 ble.gap().setAddress(BLEProtocol::AddressType::PUBLIC, BLE_address_BE);
apalmieri 0:2e972e7d3f64 146
apalmieri 0:2e972e7d3f64 147 ble.gap().onConnection(connectionCallback);
apalmieri 0:2e972e7d3f64 148 ble.onDisconnection(disconnectionCallback);
apalmieri 0:2e972e7d3f64 149
apalmieri 0:2e972e7d3f64 150 ble.gattClient().onDataRead(triggerToggledWrite);
apalmieri 0:2e972e7d3f64 151 ble.gattClient().onDataWrite(triggerRead);
apalmieri 0:2e972e7d3f64 152
apalmieri 0:2e972e7d3f64 153 ble.gap().setScanParams(SCAN_INT, SCAN_WIND);
apalmieri 0:2e972e7d3f64 154 ble.gap().startScan(advertisementCallback);
apalmieri 0:2e972e7d3f64 155
apalmieri 0:2e972e7d3f64 156 // infinite loop
apalmieri 0:2e972e7d3f64 157 while (1) {
apalmieri 0:2e972e7d3f64 158 if (!ble.gattClient().isServiceDiscoveryActive()) {
apalmieri 0:2e972e7d3f64 159 switch(triggerOp) {
apalmieri 0:2e972e7d3f64 160 case READ:
apalmieri 0:2e972e7d3f64 161 triggerOp = IDLE;
apalmieri 0:2e972e7d3f64 162 ledCharacteristic.read();
apalmieri 0:2e972e7d3f64 163 break;
apalmieri 0:2e972e7d3f64 164 case WRITE:
apalmieri 0:2e972e7d3f64 165 triggerOp = IDLE;
apalmieri 0:2e972e7d3f64 166 ledCharacteristic.write(1, &toggledValue);
apalmieri 0:2e972e7d3f64 167 break;
apalmieri 0:2e972e7d3f64 168 }
apalmieri 0:2e972e7d3f64 169 }
apalmieri 0:2e972e7d3f64 170 ble.waitForEvent();
apalmieri 0:2e972e7d3f64 171 }
apalmieri 0:2e972e7d3f64 172 }
apalmieri 0:2e972e7d3f64 173
apalmieri 0:2e972e7d3f64 174 int main(void)
apalmieri 0:2e972e7d3f64 175 {
apalmieri 0:2e972e7d3f64 176 BLE::Instance().init(bleInitComplete);
apalmieri 2:c944cfe08e79 177 }