ble nano hid over gatt

Dependencies:   BLE_API mbed-dev nRF51822

Committer:
cho45
Date:
Tue Aug 30 13:18:00 2016 +0000
Revision:
54:899fc2b0a76b
Child:
55:f01a31103685
battery service ???????????????

Who changed what in which revision?

UserRevisionLine numberNew contents of line
cho45 54:899fc2b0a76b 1 /* mbed Microcontroller Library
cho45 54:899fc2b0a76b 2 * Copyright (c) 2015 ARM Limited
cho45 54:899fc2b0a76b 3 *
cho45 54:899fc2b0a76b 4 * Licensed under the Apache License, Version 2.0 (the "License");
cho45 54:899fc2b0a76b 5 * you may not use this file except in compliance with the License.
cho45 54:899fc2b0a76b 6 * You may obtain a copy of the License at
cho45 54:899fc2b0a76b 7 *
cho45 54:899fc2b0a76b 8 * http://www.apache.org/licenses/LICENSE-2.0
cho45 54:899fc2b0a76b 9 *
cho45 54:899fc2b0a76b 10 * Unless required by applicable law or agreed to in writing, software
cho45 54:899fc2b0a76b 11 * distributed under the License is distributed on an "AS IS" BASIS,
cho45 54:899fc2b0a76b 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
cho45 54:899fc2b0a76b 13 * See the License for the specific language governing permissions and
cho45 54:899fc2b0a76b 14 * limitations under the License.
cho45 54:899fc2b0a76b 15 */
cho45 54:899fc2b0a76b 16
cho45 54:899fc2b0a76b 17 #include "mbed.h"
cho45 54:899fc2b0a76b 18 #include "HIDServiceBase.h"
cho45 54:899fc2b0a76b 19
cho45 54:899fc2b0a76b 20 static const uint16_t UUID_BATTERY_LEVEL_CHAR = GattCharacteristic::UUID_BATTERY_LEVEL_CHAR;
cho45 54:899fc2b0a76b 21
cho45 54:899fc2b0a76b 22 HIDServiceBase::HIDServiceBase(BLE &_ble,
cho45 54:899fc2b0a76b 23 report_map_t reportMap,
cho45 54:899fc2b0a76b 24 uint8_t reportMapSize,
cho45 54:899fc2b0a76b 25 report_t inputReport,
cho45 54:899fc2b0a76b 26 report_t outputReport,
cho45 54:899fc2b0a76b 27 report_t featureReport,
cho45 54:899fc2b0a76b 28 uint8_t inputReportLength,
cho45 54:899fc2b0a76b 29 uint8_t outputReportLength,
cho45 54:899fc2b0a76b 30 uint8_t featureReportLength,
cho45 54:899fc2b0a76b 31 uint8_t inputReportTickerDelay) :
cho45 54:899fc2b0a76b 32 ble(_ble),
cho45 54:899fc2b0a76b 33 connected (false),
cho45 54:899fc2b0a76b 34 reportMapLength(reportMapSize),
cho45 54:899fc2b0a76b 35
cho45 54:899fc2b0a76b 36 inputReport(inputReport),
cho45 54:899fc2b0a76b 37 outputReport(outputReport),
cho45 54:899fc2b0a76b 38 featureReport(featureReport),
cho45 54:899fc2b0a76b 39
cho45 54:899fc2b0a76b 40 inputReportLength(inputReportLength),
cho45 54:899fc2b0a76b 41 outputReportLength(outputReportLength),
cho45 54:899fc2b0a76b 42 featureReportLength(featureReportLength),
cho45 54:899fc2b0a76b 43
cho45 54:899fc2b0a76b 44 protocolMode(REPORT_PROTOCOL),
cho45 54:899fc2b0a76b 45
cho45 54:899fc2b0a76b 46 inputReportReferenceDescriptor(BLE_UUID_DESCRIPTOR_REPORT_REFERENCE,
cho45 54:899fc2b0a76b 47 (uint8_t *)&inputReportReferenceData, 2, 2),
cho45 54:899fc2b0a76b 48 outputReportReferenceDescriptor(BLE_UUID_DESCRIPTOR_REPORT_REFERENCE,
cho45 54:899fc2b0a76b 49 (uint8_t *)&outputReportReferenceData, 2, 2),
cho45 54:899fc2b0a76b 50 featureReportReferenceDescriptor(BLE_UUID_DESCRIPTOR_REPORT_REFERENCE,
cho45 54:899fc2b0a76b 51 (uint8_t *)&featureReportReferenceData, 2, 2),
cho45 54:899fc2b0a76b 52 batteryServiceExternalReportReferenceDescriptor(BLE_UUID_DESCRIPTOR_EXTERNAL_REPORT_REFERENCE,
cho45 54:899fc2b0a76b 53 (uint8_t *)&UUID_BATTERY_LEVEL_CHAR, 2, 2, false),
cho45 54:899fc2b0a76b 54
cho45 54:899fc2b0a76b 55 protocolModeCharacteristic(GattCharacteristic::UUID_PROTOCOL_MODE_CHAR, &protocolMode, 1, 1,
cho45 54:899fc2b0a76b 56 GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_READ
cho45 54:899fc2b0a76b 57 | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_WRITE_WITHOUT_RESPONSE),
cho45 54:899fc2b0a76b 58
cho45 54:899fc2b0a76b 59 inputReportCharacteristic(GattCharacteristic::UUID_REPORT_CHAR,
cho45 54:899fc2b0a76b 60 (uint8_t *)inputReport, inputReportLength, inputReportLength,
cho45 54:899fc2b0a76b 61 GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_READ
cho45 54:899fc2b0a76b 62 | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_NOTIFY
cho45 54:899fc2b0a76b 63 | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_WRITE,
cho45 54:899fc2b0a76b 64 inputReportDescriptors(), 1),
cho45 54:899fc2b0a76b 65
cho45 54:899fc2b0a76b 66 outputReportCharacteristic(GattCharacteristic::UUID_REPORT_CHAR,
cho45 54:899fc2b0a76b 67 (uint8_t *)outputReport, outputReportLength, outputReportLength,
cho45 54:899fc2b0a76b 68 GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_READ
cho45 54:899fc2b0a76b 69 | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_WRITE_WITHOUT_RESPONSE
cho45 54:899fc2b0a76b 70 | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_WRITE,
cho45 54:899fc2b0a76b 71 outputReportDescriptors(), 1),
cho45 54:899fc2b0a76b 72
cho45 54:899fc2b0a76b 73 featureReportCharacteristic(GattCharacteristic::UUID_REPORT_CHAR,
cho45 54:899fc2b0a76b 74 (uint8_t *)featureReport, featureReportLength, featureReportLength,
cho45 54:899fc2b0a76b 75 GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_READ
cho45 54:899fc2b0a76b 76 | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_WRITE,
cho45 54:899fc2b0a76b 77 featureReportDescriptors(), 1),
cho45 54:899fc2b0a76b 78
cho45 54:899fc2b0a76b 79 /*
cho45 54:899fc2b0a76b 80 * We need to set reportMap content as const, in order to let the compiler put it into flash
cho45 54:899fc2b0a76b 81 * instead of RAM. The characteristic is read-only so it won't be written, but
cho45 54:899fc2b0a76b 82 * GattCharacteristic constructor takes non-const arguments only. Hence the cast.
cho45 54:899fc2b0a76b 83 */
cho45 54:899fc2b0a76b 84 reportMapCharacteristic(GattCharacteristic::UUID_REPORT_MAP_CHAR,
cho45 54:899fc2b0a76b 85 const_cast<uint8_t*>(reportMap), reportMapLength, reportMapLength,
cho45 54:899fc2b0a76b 86 GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_READ,
cho45 54:899fc2b0a76b 87 reportMapDescriptors(), 1),
cho45 54:899fc2b0a76b 88
cho45 54:899fc2b0a76b 89 HIDInformationCharacteristic(GattCharacteristic::UUID_HID_INFORMATION_CHAR, HIDInformation()),
cho45 54:899fc2b0a76b 90 HIDControlPointCharacteristic(GattCharacteristic::UUID_HID_CONTROL_POINT_CHAR,
cho45 54:899fc2b0a76b 91 &controlPointCommand, 1, 1,
cho45 54:899fc2b0a76b 92 GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_WRITE_WITHOUT_RESPONSE),
cho45 54:899fc2b0a76b 93
cho45 54:899fc2b0a76b 94 reportTickerDelay(inputReportTickerDelay),
cho45 54:899fc2b0a76b 95 reportTickerIsActive(false)
cho45 54:899fc2b0a76b 96 {
cho45 54:899fc2b0a76b 97 static GattCharacteristic *characteristics[] = {
cho45 54:899fc2b0a76b 98 &HIDInformationCharacteristic,
cho45 54:899fc2b0a76b 99 &reportMapCharacteristic,
cho45 54:899fc2b0a76b 100 &protocolModeCharacteristic,
cho45 54:899fc2b0a76b 101 &HIDControlPointCharacteristic,
cho45 54:899fc2b0a76b 102 NULL,
cho45 54:899fc2b0a76b 103 NULL,
cho45 54:899fc2b0a76b 104 NULL,
cho45 54:899fc2b0a76b 105 NULL,
cho45 54:899fc2b0a76b 106 NULL
cho45 54:899fc2b0a76b 107 };
cho45 54:899fc2b0a76b 108
cho45 54:899fc2b0a76b 109 unsigned int charIndex = 4;
cho45 54:899fc2b0a76b 110 /*
cho45 54:899fc2b0a76b 111 * Report characteristics are optional, and depend on the reportMap descriptor
cho45 54:899fc2b0a76b 112 * Note: at least one should be present, but we don't check that at the moment.
cho45 54:899fc2b0a76b 113 */
cho45 54:899fc2b0a76b 114 if (inputReportLength)
cho45 54:899fc2b0a76b 115 characteristics[charIndex++] = &inputReportCharacteristic;
cho45 54:899fc2b0a76b 116 if (outputReportLength)
cho45 54:899fc2b0a76b 117 characteristics[charIndex++] = &outputReportCharacteristic;
cho45 54:899fc2b0a76b 118 if (featureReportLength)
cho45 54:899fc2b0a76b 119 characteristics[charIndex++] = &featureReportCharacteristic;
cho45 54:899fc2b0a76b 120
cho45 54:899fc2b0a76b 121 /* TODO: let children add some more characteristics, namely boot keyboard and mouse (They are
cho45 54:899fc2b0a76b 122 * mandatory as per HIDS spec.) Ex:
cho45 54:899fc2b0a76b 123 *
cho45 54:899fc2b0a76b 124 * addExtraCharacteristics(characteristics, int& charIndex);
cho45 54:899fc2b0a76b 125 */
cho45 54:899fc2b0a76b 126
cho45 54:899fc2b0a76b 127 GattService service(GattService::UUID_HUMAN_INTERFACE_DEVICE_SERVICE,
cho45 54:899fc2b0a76b 128 characteristics, charIndex);
cho45 54:899fc2b0a76b 129
cho45 54:899fc2b0a76b 130 ble.gattServer().addService(service);
cho45 54:899fc2b0a76b 131
cho45 54:899fc2b0a76b 132 ble.gap().onConnection(this, &HIDServiceBase::onConnection);
cho45 54:899fc2b0a76b 133 ble.gap().onDisconnection(this, &HIDServiceBase::onDisconnection);
cho45 54:899fc2b0a76b 134
cho45 54:899fc2b0a76b 135 ble.gattServer().onDataSent(this, &HIDServiceBase::onDataSent);
cho45 54:899fc2b0a76b 136
cho45 54:899fc2b0a76b 137 /*
cho45 54:899fc2b0a76b 138 * Change preferred connection params, in order to optimize the notification frequency. Most
cho45 54:899fc2b0a76b 139 * OSes seem to respect this, even though they are not required to.
cho45 54:899fc2b0a76b 140 *
cho45 54:899fc2b0a76b 141 * Some OSes don't handle reconnection well, at the moment, so we set the maximum possible
cho45 54:899fc2b0a76b 142 * timeout, 32 seconds
cho45 54:899fc2b0a76b 143 */
cho45 54:899fc2b0a76b 144 uint16_t minInterval = Gap::MSEC_TO_GAP_DURATION_UNITS(reportTickerDelay / 2);
cho45 54:899fc2b0a76b 145 if (minInterval < 6)
cho45 54:899fc2b0a76b 146 minInterval = 6;
cho45 54:899fc2b0a76b 147 uint16_t maxInterval = minInterval * 2;
cho45 54:899fc2b0a76b 148 Gap::ConnectionParams_t params = {minInterval, maxInterval, 0, 3200};
cho45 54:899fc2b0a76b 149
cho45 54:899fc2b0a76b 150 ble.gap().setPreferredConnectionParams(&params);
cho45 54:899fc2b0a76b 151
cho45 54:899fc2b0a76b 152 SecurityManager::SecurityMode_t securityMode = SecurityManager::SECURITY_MODE_ENCRYPTION_NO_MITM;
cho45 54:899fc2b0a76b 153 protocolModeCharacteristic.requireSecurity(securityMode);
cho45 54:899fc2b0a76b 154 reportMapCharacteristic.requireSecurity(securityMode);
cho45 54:899fc2b0a76b 155 inputReportCharacteristic.requireSecurity(securityMode);
cho45 54:899fc2b0a76b 156 outputReportCharacteristic.requireSecurity(securityMode);
cho45 54:899fc2b0a76b 157 featureReportCharacteristic.requireSecurity(securityMode);
cho45 54:899fc2b0a76b 158 }
cho45 54:899fc2b0a76b 159
cho45 54:899fc2b0a76b 160 void HIDServiceBase::startReportTicker(void) {
cho45 54:899fc2b0a76b 161 if (reportTickerIsActive)
cho45 54:899fc2b0a76b 162 return;
cho45 54:899fc2b0a76b 163 reportTicker.attach_us(this, &HIDServiceBase::sendCallback, reportTickerDelay * 1000);
cho45 54:899fc2b0a76b 164 reportTickerIsActive = true;
cho45 54:899fc2b0a76b 165 }
cho45 54:899fc2b0a76b 166
cho45 54:899fc2b0a76b 167 void HIDServiceBase::stopReportTicker(void) {
cho45 54:899fc2b0a76b 168 reportTicker.detach();
cho45 54:899fc2b0a76b 169 reportTickerIsActive = false;
cho45 54:899fc2b0a76b 170 }
cho45 54:899fc2b0a76b 171
cho45 54:899fc2b0a76b 172 void HIDServiceBase::onDataSent(unsigned count) {
cho45 54:899fc2b0a76b 173 startReportTicker();
cho45 54:899fc2b0a76b 174 }
cho45 54:899fc2b0a76b 175
cho45 54:899fc2b0a76b 176 GattAttribute** HIDServiceBase::inputReportDescriptors() {
cho45 54:899fc2b0a76b 177 inputReportReferenceData.ID = 0;
cho45 54:899fc2b0a76b 178 inputReportReferenceData.type = INPUT_REPORT;
cho45 54:899fc2b0a76b 179
cho45 54:899fc2b0a76b 180 static GattAttribute * descs[] = {
cho45 54:899fc2b0a76b 181 &inputReportReferenceDescriptor,
cho45 54:899fc2b0a76b 182 };
cho45 54:899fc2b0a76b 183 return descs;
cho45 54:899fc2b0a76b 184 }
cho45 54:899fc2b0a76b 185
cho45 54:899fc2b0a76b 186 GattAttribute** HIDServiceBase::outputReportDescriptors() {
cho45 54:899fc2b0a76b 187 outputReportReferenceData.ID = 0;
cho45 54:899fc2b0a76b 188 outputReportReferenceData.type = OUTPUT_REPORT;
cho45 54:899fc2b0a76b 189
cho45 54:899fc2b0a76b 190 static GattAttribute * descs[] = {
cho45 54:899fc2b0a76b 191 &outputReportReferenceDescriptor,
cho45 54:899fc2b0a76b 192 };
cho45 54:899fc2b0a76b 193 return descs;
cho45 54:899fc2b0a76b 194 }
cho45 54:899fc2b0a76b 195
cho45 54:899fc2b0a76b 196 GattAttribute** HIDServiceBase::featureReportDescriptors() {
cho45 54:899fc2b0a76b 197 featureReportReferenceData.ID = 0;
cho45 54:899fc2b0a76b 198 featureReportReferenceData.type = FEATURE_REPORT;
cho45 54:899fc2b0a76b 199
cho45 54:899fc2b0a76b 200 static GattAttribute * descs[] = {
cho45 54:899fc2b0a76b 201 &featureReportReferenceDescriptor,
cho45 54:899fc2b0a76b 202 };
cho45 54:899fc2b0a76b 203 return descs;
cho45 54:899fc2b0a76b 204 }
cho45 54:899fc2b0a76b 205
cho45 54:899fc2b0a76b 206 GattAttribute** HIDServiceBase::reportMapDescriptors() {
cho45 54:899fc2b0a76b 207 static GattAttribute * descs[] = {
cho45 54:899fc2b0a76b 208 &batteryServiceExternalReportReferenceDescriptor,
cho45 54:899fc2b0a76b 209 };
cho45 54:899fc2b0a76b 210 return descs;
cho45 54:899fc2b0a76b 211 }
cho45 54:899fc2b0a76b 212
cho45 54:899fc2b0a76b 213 HID_information_t* HIDServiceBase::HIDInformation() {
cho45 54:899fc2b0a76b 214 static HID_information_t info = {HID_VERSION_1_11, 0x00, 0x03};
cho45 54:899fc2b0a76b 215
cho45 54:899fc2b0a76b 216 return &info;
cho45 54:899fc2b0a76b 217 }
cho45 54:899fc2b0a76b 218
cho45 54:899fc2b0a76b 219 ble_error_t HIDServiceBase::send(const report_t report) {
cho45 54:899fc2b0a76b 220 return ble.gattServer().write(inputReportCharacteristic.getValueHandle(),
cho45 54:899fc2b0a76b 221 report,
cho45 54:899fc2b0a76b 222 inputReportLength);
cho45 54:899fc2b0a76b 223 }
cho45 54:899fc2b0a76b 224
cho45 54:899fc2b0a76b 225 ble_error_t HIDServiceBase::read(report_t report) {
cho45 54:899fc2b0a76b 226 // TODO. For the time being, we'll just have HID input reports...
cho45 54:899fc2b0a76b 227 return BLE_ERROR_NOT_IMPLEMENTED;
cho45 54:899fc2b0a76b 228 }
cho45 54:899fc2b0a76b 229
cho45 54:899fc2b0a76b 230 void HIDServiceBase::onConnection(const Gap::ConnectionCallbackParams_t *params)
cho45 54:899fc2b0a76b 231 {
cho45 54:899fc2b0a76b 232 this->connected = true;
cho45 54:899fc2b0a76b 233 }
cho45 54:899fc2b0a76b 234
cho45 54:899fc2b0a76b 235 void HIDServiceBase::onDisconnection(const Gap::DisconnectionCallbackParams_t *params)
cho45 54:899fc2b0a76b 236 {
cho45 54:899fc2b0a76b 237 this->connected = false;
cho45 54:899fc2b0a76b 238 }