init
Dependencies: BLE_API mbed nRF51822
main.cpp@3:88f7aa6c2a75, 2015-08-17 (annotated)
- Committer:
- jslater8
- Date:
- Mon Aug 17 09:50:14 2015 +0000
- Revision:
- 3:88f7aa6c2a75
- Parent:
- 2:2a2b4781cd8a
initial
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
jslater8 | 0:ef5229893eb9 | 1 | /* mbed Microcontroller Library |
jslater8 | 0:ef5229893eb9 | 2 | * Copyright (c) 2006-2015 ARM Limited |
jslater8 | 0:ef5229893eb9 | 3 | * |
jslater8 | 0:ef5229893eb9 | 4 | * Licensed under the Apache License, Version 2.0 (the "License"); |
jslater8 | 0:ef5229893eb9 | 5 | * you may not use this file except in compliance with the License. |
jslater8 | 0:ef5229893eb9 | 6 | * You may obtain a copy of the License at |
jslater8 | 0:ef5229893eb9 | 7 | * |
jslater8 | 0:ef5229893eb9 | 8 | * http://www.apache.org/licenses/LICENSE-2.0 |
jslater8 | 0:ef5229893eb9 | 9 | * |
jslater8 | 0:ef5229893eb9 | 10 | * Unless required by applicable law or agreed to in writing, software |
jslater8 | 0:ef5229893eb9 | 11 | * distributed under the License is distributed on an "AS IS" BASIS, |
jslater8 | 0:ef5229893eb9 | 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
jslater8 | 0:ef5229893eb9 | 13 | * See the License for the specific language governing permissions and |
jslater8 | 0:ef5229893eb9 | 14 | * limitations under the License. |
jslater8 | 0:ef5229893eb9 | 15 | */ |
jslater8 | 3:88f7aa6c2a75 | 16 | |
jslater8 | 0:ef5229893eb9 | 17 | #include "mbed.h" |
jslater8 | 0:ef5229893eb9 | 18 | #include "BLE.h" |
jslater8 | 0:ef5229893eb9 | 19 | #include "ble/DiscoveredCharacteristic.h" |
jslater8 | 0:ef5229893eb9 | 20 | #include "ble/DiscoveredService.h" |
jslater8 | 0:ef5229893eb9 | 21 | #define DUMP_ADV_DATA 0 |
jslater8 | 0:ef5229893eb9 | 22 | |
jslater8 | 3:88f7aa6c2a75 | 23 | #define ASSERT_NO_FAILURE(CMD) do { \ |
jslater8 | 3:88f7aa6c2a75 | 24 | ble_error_t error = (CMD); \ |
jslater8 | 3:88f7aa6c2a75 | 25 | if (error == BLE_ERROR_NONE){ \ |
jslater8 | 3:88f7aa6c2a75 | 26 | printf("{{success}}\r\n"); \ |
jslater8 | 3:88f7aa6c2a75 | 27 | } else{ \ |
jslater8 | 3:88f7aa6c2a75 | 28 | printf("{{failure}} %s at line %u ERROR CODE: %u\r\n", #CMD, __LINE__, (error)); \ |
jslater8 | 3:88f7aa6c2a75 | 29 | return; \ |
jslater8 | 3:88f7aa6c2a75 | 30 | } \ |
jslater8 | 3:88f7aa6c2a75 | 31 | }while (0) |
jslater8 | 3:88f7aa6c2a75 | 32 | #define CHECK_EQUALS(X,Y) ((X)==(Y)) ? (printf("{{success}}\r\n")) : printf("{{failure}}\r\n"); |
jslater8 | 0:ef5229893eb9 | 33 | |
jslater8 | 3:88f7aa6c2a75 | 34 | BLE ble; |
jslater8 | 3:88f7aa6c2a75 | 35 | Gap::Address_t address; |
jslater8 | 2:2a2b4781cd8a | 36 | |
jslater8 | 0:ef5229893eb9 | 37 | DiscoveredCharacteristic HRMCharacteristic; |
jslater8 | 3:88f7aa6c2a75 | 38 | bool HRMFound = false; |
jslater8 | 1:30f1232e4c17 | 39 | DiscoveredCharacteristic LEDCharacteristic; |
jslater8 | 3:88f7aa6c2a75 | 40 | bool LEDFound = false; |
jslater8 | 3:88f7aa6c2a75 | 41 | DiscoveredCharacteristic BTNCharacteristic; |
jslater8 | 3:88f7aa6c2a75 | 42 | bool BTNFound = false; |
jslater8 | 2:2a2b4781cd8a | 43 | Gap::Handle_t deviceAHandle; |
jslater8 | 0:ef5229893eb9 | 44 | |
jslater8 | 0:ef5229893eb9 | 45 | |
jslater8 | 3:88f7aa6c2a75 | 46 | /* |
jslater8 | 3:88f7aa6c2a75 | 47 | * Call back when a service is discovered |
jslater8 | 3:88f7aa6c2a75 | 48 | */ |
jslater8 | 3:88f7aa6c2a75 | 49 | void serviceDiscoveryCallback(const DiscoveredService *service) |
jslater8 | 3:88f7aa6c2a75 | 50 | { |
jslater8 | 0:ef5229893eb9 | 51 | if (service->getUUID().shortOrLong() == UUID::UUID_TYPE_SHORT) { |
jslater8 | 0:ef5229893eb9 | 52 | printf("S UUID-%x attrs[%u %u]\r\n", service->getUUID().getShortUUID(), service->getStartHandle(), service->getEndHandle()); |
jslater8 | 0:ef5229893eb9 | 53 | } else { |
jslater8 | 0:ef5229893eb9 | 54 | printf("S UUID-"); |
jslater8 | 0:ef5229893eb9 | 55 | const uint8_t *longUUIDBytes = service->getUUID().getBaseUUID(); |
jslater8 | 0:ef5229893eb9 | 56 | for (unsigned i = 0; i < UUID::LENGTH_OF_LONG_UUID; i++) { |
jslater8 | 0:ef5229893eb9 | 57 | printf("%02x", longUUIDBytes[i]); |
jslater8 | 0:ef5229893eb9 | 58 | } |
jslater8 | 0:ef5229893eb9 | 59 | printf("attrs[%u %u]\r\n", service->getStartHandle(), service->getEndHandle()); |
jslater8 | 0:ef5229893eb9 | 60 | } |
jslater8 | 0:ef5229893eb9 | 61 | } |
jslater8 | 0:ef5229893eb9 | 62 | |
jslater8 | 3:88f7aa6c2a75 | 63 | /* |
jslater8 | 3:88f7aa6c2a75 | 64 | * Call back when a characteristic is discovered |
jslater8 | 3:88f7aa6c2a75 | 65 | */ |
jslater8 | 3:88f7aa6c2a75 | 66 | void characteristicDiscoveryCallback(const DiscoveredCharacteristic *characteristicP) |
jslater8 | 3:88f7aa6c2a75 | 67 | { |
jslater8 | 3:88f7aa6c2a75 | 68 | if (characteristicP->getUUID().getShortUUID() == 0x2a37) { /* Searches for HRM Characteristic*/ |
jslater8 | 3:88f7aa6c2a75 | 69 | HRMCharacteristic = *characteristicP; |
jslater8 | 3:88f7aa6c2a75 | 70 | HRMFound = true; |
jslater8 | 1:30f1232e4c17 | 71 | } |
jslater8 | 3:88f7aa6c2a75 | 72 | if (characteristicP->getUUID().getShortUUID() == 0xA001) { /* Searches for LED Characteristic*/ |
jslater8 | 1:30f1232e4c17 | 73 | LEDCharacteristic = *characteristicP; |
jslater8 | 3:88f7aa6c2a75 | 74 | LEDFound = true; |
jslater8 | 3:88f7aa6c2a75 | 75 | } |
jslater8 | 3:88f7aa6c2a75 | 76 | if (characteristicP->getUUID().getShortUUID() == 0xA003) { |
jslater8 | 3:88f7aa6c2a75 | 77 | BTNCharacteristic = *characteristicP; |
jslater8 | 3:88f7aa6c2a75 | 78 | BTNFound = true; |
jslater8 | 0:ef5229893eb9 | 79 | } |
jslater8 | 0:ef5229893eb9 | 80 | } |
jslater8 | 0:ef5229893eb9 | 81 | |
jslater8 | 3:88f7aa6c2a75 | 82 | /* |
jslater8 | 3:88f7aa6c2a75 | 83 | * Call back when device is connected |
jslater8 | 3:88f7aa6c2a75 | 84 | */ |
jslater8 | 3:88f7aa6c2a75 | 85 | void connectionCallback(const Gap::ConnectionCallbackParams_t *params) |
jslater8 | 3:88f7aa6c2a75 | 86 | { |
jslater8 | 3:88f7aa6c2a75 | 87 | printf("Connected to: %d:%d:%d:%d:%d:%d\n", |
jslater8 | 3:88f7aa6c2a75 | 88 | params->peerAddr[0], params->peerAddr[1], params->peerAddr[2], params->peerAddr[3], params->peerAddr[4], params->peerAddr[5]); |
jslater8 | 0:ef5229893eb9 | 89 | if (params->role == Gap::CENTRAL) { |
jslater8 | 3:88f7aa6c2a75 | 90 | deviceAHandle = params->handle; /* Handle for device A so it is it possible to disconnect*/ |
jslater8 | 3:88f7aa6c2a75 | 91 | ASSERT_NO_FAILURE(ble.gattClient().launchServiceDiscovery(params->handle, serviceDiscoveryCallback, characteristicDiscoveryCallback)); |
jslater8 | 0:ef5229893eb9 | 92 | } |
jslater8 | 0:ef5229893eb9 | 93 | } |
jslater8 | 0:ef5229893eb9 | 94 | |
jslater8 | 3:88f7aa6c2a75 | 95 | /* |
jslater8 | 3:88f7aa6c2a75 | 96 | * The callback for reading a characteristic, print depends on what characteristic is read |
jslater8 | 3:88f7aa6c2a75 | 97 | */ |
jslater8 | 3:88f7aa6c2a75 | 98 | void readCharacteristic(const GattReadCallbackParams *response) |
jslater8 | 3:88f7aa6c2a75 | 99 | { |
jslater8 | 0:ef5229893eb9 | 100 | if (response->handle == HRMCharacteristic.getValueHandle()) { |
jslater8 | 1:30f1232e4c17 | 101 | printf("HRMCounter: %d\n", response->data[1]); |
jslater8 | 1:30f1232e4c17 | 102 | } |
jslater8 | 1:30f1232e4c17 | 103 | if (response->handle == LEDCharacteristic.getValueHandle()) { |
jslater8 | 1:30f1232e4c17 | 104 | printf("LED: %d\n", response->data[0]); |
jslater8 | 3:88f7aa6c2a75 | 105 | } |
jslater8 | 3:88f7aa6c2a75 | 106 | if (response->handle == BTNCharacteristic.getValueHandle()) { |
jslater8 | 3:88f7aa6c2a75 | 107 | printf("BTN: %d\n", response->data[0]); |
jslater8 | 3:88f7aa6c2a75 | 108 | } |
jslater8 | 3:88f7aa6c2a75 | 109 | } |
jslater8 | 3:88f7aa6c2a75 | 110 | |
jslater8 | 3:88f7aa6c2a75 | 111 | /* |
jslater8 | 3:88f7aa6c2a75 | 112 | * Tests connecting devices. Devices must be disconnected for this test |
jslater8 | 3:88f7aa6c2a75 | 113 | */ |
jslater8 | 3:88f7aa6c2a75 | 114 | void connectTest() |
jslater8 | 3:88f7aa6c2a75 | 115 | { |
jslater8 | 3:88f7aa6c2a75 | 116 | if (!(ble.gap().getState().connected)) { |
jslater8 | 3:88f7aa6c2a75 | 117 | ASSERT_NO_FAILURE(ble.gap().connect(address, Gap::ADDR_TYPE_RANDOM_STATIC, NULL, NULL)); |
jslater8 | 3:88f7aa6c2a75 | 118 | } else { |
jslater8 | 3:88f7aa6c2a75 | 119 | printf("Devices already connected\n"); |
jslater8 | 0:ef5229893eb9 | 120 | } |
jslater8 | 0:ef5229893eb9 | 121 | } |
jslater8 | 0:ef5229893eb9 | 122 | |
jslater8 | 3:88f7aa6c2a75 | 123 | /* |
jslater8 | 3:88f7aa6c2a75 | 124 | * Tests reading from to the heart rate characteristic. Devices need to be connected for this test. |
jslater8 | 3:88f7aa6c2a75 | 125 | */ |
jslater8 | 3:88f7aa6c2a75 | 126 | void readTest(){ |
jslater8 | 3:88f7aa6c2a75 | 127 | if (!(ble.gap().getState().connected)) { |
jslater8 | 3:88f7aa6c2a75 | 128 | printf("Devices must be connected before this test can be run\n"); |
jslater8 | 3:88f7aa6c2a75 | 129 | return; |
jslater8 | 1:30f1232e4c17 | 130 | } |
jslater8 | 3:88f7aa6c2a75 | 131 | if (HRMFound) { |
jslater8 | 3:88f7aa6c2a75 | 132 | ASSERT_NO_FAILURE(HRMCharacteristic.read()); |
jslater8 | 3:88f7aa6c2a75 | 133 | } else { |
jslater8 | 3:88f7aa6c2a75 | 134 | printf("Characteristic not found\r\n"); |
jslater8 | 3:88f7aa6c2a75 | 135 | } |
jslater8 | 0:ef5229893eb9 | 136 | } |
jslater8 | 0:ef5229893eb9 | 137 | |
jslater8 | 3:88f7aa6c2a75 | 138 | /** |
jslater8 | 3:88f7aa6c2a75 | 139 | * Tests writing to the LED Characteristic. Then reads from the callback to verify that the write is correct. |
jslater8 | 3:88f7aa6c2a75 | 140 | * Devices need to be connected for this test. |
jslater8 | 3:88f7aa6c2a75 | 141 | */ |
jslater8 | 3:88f7aa6c2a75 | 142 | void writeTest() |
jslater8 | 3:88f7aa6c2a75 | 143 | { |
jslater8 | 3:88f7aa6c2a75 | 144 | if (!(ble.gap().getState().connected)) { |
jslater8 | 1:30f1232e4c17 | 145 | printf("Devices must be connected before this test can be run\n"); |
jslater8 | 1:30f1232e4c17 | 146 | return; |
jslater8 | 1:30f1232e4c17 | 147 | } |
jslater8 | 3:88f7aa6c2a75 | 148 | if (LEDFound) { |
jslater8 | 3:88f7aa6c2a75 | 149 | uint8_t write_value = 1; |
jslater8 | 3:88f7aa6c2a75 | 150 | ASSERT_NO_FAILURE(LEDCharacteristic.write(sizeof(write_value), &write_value)); /* When write finishes, writeCallback is called */ |
jslater8 | 3:88f7aa6c2a75 | 151 | } else { |
jslater8 | 3:88f7aa6c2a75 | 152 | printf("Characeristic not found\r\n"); |
jslater8 | 1:30f1232e4c17 | 153 | } |
jslater8 | 1:30f1232e4c17 | 154 | } |
jslater8 | 3:88f7aa6c2a75 | 155 | |
jslater8 | 3:88f7aa6c2a75 | 156 | /** |
jslater8 | 3:88f7aa6c2a75 | 157 | * Tests disconnecting devices. If it is already connected it prints a message |
jslater8 | 3:88f7aa6c2a75 | 158 | */ |
jslater8 | 3:88f7aa6c2a75 | 159 | void disconnectTest() |
jslater8 | 3:88f7aa6c2a75 | 160 | { |
jslater8 | 3:88f7aa6c2a75 | 161 | if ((ble.gap().getState().connected)) { |
jslater8 | 3:88f7aa6c2a75 | 162 | ASSERT_NO_FAILURE(ble.gap().disconnect(deviceAHandle, Gap::REMOTE_USER_TERMINATED_CONNECTION)); |
jslater8 | 3:88f7aa6c2a75 | 163 | } else { |
jslater8 | 3:88f7aa6c2a75 | 164 | printf("Devices not connected\n"); |
jslater8 | 3:88f7aa6c2a75 | 165 | } |
jslater8 | 3:88f7aa6c2a75 | 166 | } |
jslater8 | 3:88f7aa6c2a75 | 167 | |
jslater8 | 3:88f7aa6c2a75 | 168 | void notificationTest() |
jslater8 | 3:88f7aa6c2a75 | 169 | { |
jslater8 | 3:88f7aa6c2a75 | 170 | if (!ble.gap().getState().connected) { |
jslater8 | 1:30f1232e4c17 | 171 | printf("Devices must be connected before this test can be run\n"); |
jslater8 | 1:30f1232e4c17 | 172 | return; |
jslater8 | 1:30f1232e4c17 | 173 | } |
jslater8 | 3:88f7aa6c2a75 | 174 | if (BTNFound) { |
jslater8 | 3:88f7aa6c2a75 | 175 | uint16_t value = BLE_HVX_NOTIFICATION; |
jslater8 | 3:88f7aa6c2a75 | 176 | ASSERT_NO_FAILURE(ble.gattClient().write(GattClient::GATT_OP_WRITE_REQ, |
jslater8 | 3:88f7aa6c2a75 | 177 | deviceAHandle, |
jslater8 | 3:88f7aa6c2a75 | 178 | BTNCharacteristic.getValueHandle() + 1, /* HACK Alert. We're assuming that CCCD descriptor immediately follows the value attribute. */ |
jslater8 | 3:88f7aa6c2a75 | 179 | sizeof(uint16_t), /* HACK Alert! size should be made into a BLE_API constant. */ |
jslater8 | 3:88f7aa6c2a75 | 180 | reinterpret_cast<const uint8_t *>(&value))); |
jslater8 | 3:88f7aa6c2a75 | 181 | } else { |
jslater8 | 3:88f7aa6c2a75 | 182 | printf("Characteristic not found\r\r"); |
jslater8 | 1:30f1232e4c17 | 183 | } |
jslater8 | 1:30f1232e4c17 | 184 | } |
jslater8 | 1:30f1232e4c17 | 185 | |
jslater8 | 3:88f7aa6c2a75 | 186 | /** |
jslater8 | 3:88f7aa6c2a75 | 187 | * Controls which tests are run from input from PC |
jslater8 | 3:88f7aa6c2a75 | 188 | */ |
jslater8 | 3:88f7aa6c2a75 | 189 | void commandInterpreter() |
jslater8 | 3:88f7aa6c2a75 | 190 | { |
jslater8 | 3:88f7aa6c2a75 | 191 | char command[50]; |
jslater8 | 3:88f7aa6c2a75 | 192 | while (true) { |
jslater8 | 3:88f7aa6c2a75 | 193 | scanf("%s", command); /* Takes a string from the host test and decides what test to use. */ |
jslater8 | 3:88f7aa6c2a75 | 194 | if (!strcmp(command, "connect")) { |
jslater8 | 3:88f7aa6c2a75 | 195 | connectTest(); |
jslater8 | 3:88f7aa6c2a75 | 196 | } else if (!strcmp(command, "disconnect")) { |
jslater8 | 3:88f7aa6c2a75 | 197 | disconnectTest(); |
jslater8 | 3:88f7aa6c2a75 | 198 | } else if (!strcmp(command, "read")) { |
jslater8 | 3:88f7aa6c2a75 | 199 | readTest(); |
jslater8 | 3:88f7aa6c2a75 | 200 | } else if (!strcmp(command, "write")) { |
jslater8 | 3:88f7aa6c2a75 | 201 | writeTest(); |
jslater8 | 3:88f7aa6c2a75 | 202 | } else if (!strcmp(command, "notification")) { |
jslater8 | 3:88f7aa6c2a75 | 203 | notificationTest(); |
jslater8 | 3:88f7aa6c2a75 | 204 | } |
jslater8 | 1:30f1232e4c17 | 205 | } |
jslater8 | 1:30f1232e4c17 | 206 | } |
jslater8 | 1:30f1232e4c17 | 207 | |
jslater8 | 3:88f7aa6c2a75 | 208 | /** |
jslater8 | 3:88f7aa6c2a75 | 209 | * Call back for writing to LED characteristic. |
jslater8 | 3:88f7aa6c2a75 | 210 | */ |
jslater8 | 3:88f7aa6c2a75 | 211 | void writeCallback(const GattWriteCallbackParams *params) |
jslater8 | 3:88f7aa6c2a75 | 212 | { |
jslater8 | 3:88f7aa6c2a75 | 213 | if (params->handle == LEDCharacteristic.getValueHandle()) { |
jslater8 | 3:88f7aa6c2a75 | 214 | ASSERT_NO_FAILURE(LEDCharacteristic.read()); |
jslater8 | 3:88f7aa6c2a75 | 215 | } else if (params->handle == BTNCharacteristic.getValueHandle() + 1) { |
jslater8 | 3:88f7aa6c2a75 | 216 | printf("Sync\r\n"); |
jslater8 | 3:88f7aa6c2a75 | 217 | } |
jslater8 | 3:88f7aa6c2a75 | 218 | } |
jslater8 | 3:88f7aa6c2a75 | 219 | |
jslater8 | 3:88f7aa6c2a75 | 220 | void hvxCallback(const GattHVXCallbackParams *params) { |
jslater8 | 3:88f7aa6c2a75 | 221 | printf("Button: "); |
jslater8 | 3:88f7aa6c2a75 | 222 | for (unsigned index = 0; index < params->len; index++) { |
jslater8 | 3:88f7aa6c2a75 | 223 | printf("%02x", params->data[index]); |
jslater8 | 3:88f7aa6c2a75 | 224 | } |
jslater8 | 3:88f7aa6c2a75 | 225 | printf("\r\n"); |
jslater8 | 0:ef5229893eb9 | 226 | } |
jslater8 | 0:ef5229893eb9 | 227 | |
jslater8 | 0:ef5229893eb9 | 228 | int main(void) |
jslater8 | 0:ef5229893eb9 | 229 | { |
jslater8 | 3:88f7aa6c2a75 | 230 | printf("{{end}}\n"); /* Hands control over to Python script */ |
jslater8 | 3:88f7aa6c2a75 | 231 | scanf("%hhu", &address[0]); |
jslater8 | 3:88f7aa6c2a75 | 232 | scanf("%hhu", &address[1]); |
jslater8 | 3:88f7aa6c2a75 | 233 | scanf("%hhu", &address[2]); |
jslater8 | 3:88f7aa6c2a75 | 234 | scanf("%hhu", &address[3]); |
jslater8 | 3:88f7aa6c2a75 | 235 | scanf("%hhu", &address[4]); |
jslater8 | 3:88f7aa6c2a75 | 236 | scanf("%hhu", &address[5]); |
jslater8 | 3:88f7aa6c2a75 | 237 | |
jslater8 | 3:88f7aa6c2a75 | 238 | ASSERT_NO_FAILURE(ble.init()); |
jslater8 | 3:88f7aa6c2a75 | 239 | ASSERT_NO_FAILURE(ble.gap().setScanParams(500 /* scan interval */, 200 /* scan window */)); |
jslater8 | 3:88f7aa6c2a75 | 240 | printf("ASSERTIONS DONE\r\n"); |
jslater8 | 0:ef5229893eb9 | 241 | ble.gap().onConnection(connectionCallback); |
jslater8 | 3:88f7aa6c2a75 | 242 | ble.gattClient().onDataRead(readCharacteristic); |
jslater8 | 3:88f7aa6c2a75 | 243 | ble.gattClient().onDataWrite(writeCallback); |
jslater8 | 3:88f7aa6c2a75 | 244 | ble.gattClient().onHVX(hvxCallback); |
jslater8 | 1:30f1232e4c17 | 245 | commandInterpreter(); |
jslater8 | 0:ef5229893eb9 | 246 | } |