ble nano hid over gatt

Dependencies:   BLE_API mbed-dev nRF51822

Committer:
cho45
Date:
Sat Sep 03 20:36:40 2016 +0900
Revision:
79:0095bfb18c57
Parent:
75:351d7ffe81d1
Child:
82:af52d37b1946
implement boot keyboard interface

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 79:0095bfb18c57 18 #include "config.h"
cho45 54:899fc2b0a76b 19 #include "HIDServiceBase.h"
cho45 54:899fc2b0a76b 20
cho45 75:351d7ffe81d1 21 static const report_reference_t inputReportReferenceData = { 0, INPUT_REPORT };
cho45 75:351d7ffe81d1 22 static const GattAttribute inputReportReferenceDescriptor(BLE_UUID_DESCRIPTOR_REPORT_REFERENCE, (uint8_t *)&inputReportReferenceData, 2, 2, false);
cho45 75:351d7ffe81d1 23 static const GattAttribute * inputReportDescriptors[] = {
cho45 75:351d7ffe81d1 24 &inputReportReferenceDescriptor,
cho45 75:351d7ffe81d1 25 };
cho45 75:351d7ffe81d1 26
cho45 75:351d7ffe81d1 27 static const report_reference_t outputReportReferenceData = { 0, OUTPUT_REPORT };
cho45 75:351d7ffe81d1 28 static const GattAttribute outputReportReferenceDescriptor(BLE_UUID_DESCRIPTOR_REPORT_REFERENCE, (uint8_t *)&outputReportReferenceData, 2, 2, false);
cho45 75:351d7ffe81d1 29 static const GattAttribute * outputReportDescriptors[] = {
cho45 75:351d7ffe81d1 30 &outputReportReferenceDescriptor,
cho45 75:351d7ffe81d1 31 };
cho45 75:351d7ffe81d1 32
cho45 75:351d7ffe81d1 33
cho45 75:351d7ffe81d1 34 static const report_reference_t featureReportReferenceData = { 0, FEATURE_REPORT };
cho45 75:351d7ffe81d1 35 static const GattAttribute featureReportReferenceDescriptor(BLE_UUID_DESCRIPTOR_REPORT_REFERENCE, (uint8_t *)&featureReportReferenceData, 2, 2, false);
cho45 75:351d7ffe81d1 36 static const GattAttribute * featureReportDescriptors[] = {
cho45 75:351d7ffe81d1 37 &featureReportReferenceDescriptor,
cho45 75:351d7ffe81d1 38 };
cho45 75:351d7ffe81d1 39
cho45 75:351d7ffe81d1 40 static const HID_information_t HID_information = {HID_VERSION_1_11, 0x00, 0x03};
cho45 75:351d7ffe81d1 41
cho45 54:899fc2b0a76b 42 HIDServiceBase::HIDServiceBase(BLE &_ble,
cho45 54:899fc2b0a76b 43 report_map_t reportMap,
cho45 54:899fc2b0a76b 44 uint8_t reportMapSize,
cho45 54:899fc2b0a76b 45 report_t inputReport,
cho45 54:899fc2b0a76b 46 report_t outputReport,
cho45 54:899fc2b0a76b 47 report_t featureReport,
cho45 54:899fc2b0a76b 48 uint8_t inputReportLength,
cho45 54:899fc2b0a76b 49 uint8_t outputReportLength,
cho45 54:899fc2b0a76b 50 uint8_t featureReportLength,
cho45 54:899fc2b0a76b 51 uint8_t inputReportTickerDelay) :
cho45 54:899fc2b0a76b 52 ble(_ble),
cho45 54:899fc2b0a76b 53 connected (false),
cho45 54:899fc2b0a76b 54 reportMapLength(reportMapSize),
cho45 54:899fc2b0a76b 55
cho45 54:899fc2b0a76b 56 inputReport(inputReport),
cho45 54:899fc2b0a76b 57 outputReport(outputReport),
cho45 54:899fc2b0a76b 58 featureReport(featureReport),
cho45 54:899fc2b0a76b 59
cho45 54:899fc2b0a76b 60 inputReportLength(inputReportLength),
cho45 54:899fc2b0a76b 61 outputReportLength(outputReportLength),
cho45 54:899fc2b0a76b 62 featureReportLength(featureReportLength),
cho45 54:899fc2b0a76b 63
cho45 54:899fc2b0a76b 64 protocolMode(REPORT_PROTOCOL),
cho45 54:899fc2b0a76b 65
cho45 54:899fc2b0a76b 66 protocolModeCharacteristic(GattCharacteristic::UUID_PROTOCOL_MODE_CHAR, &protocolMode, 1, 1,
cho45 54:899fc2b0a76b 67 GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_READ
cho45 54:899fc2b0a76b 68 | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_WRITE_WITHOUT_RESPONSE),
cho45 54:899fc2b0a76b 69
cho45 54:899fc2b0a76b 70 inputReportCharacteristic(GattCharacteristic::UUID_REPORT_CHAR,
cho45 54:899fc2b0a76b 71 (uint8_t *)inputReport, inputReportLength, inputReportLength,
cho45 54:899fc2b0a76b 72 GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_READ
cho45 54:899fc2b0a76b 73 | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_NOTIFY
cho45 54:899fc2b0a76b 74 | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_WRITE,
cho45 75:351d7ffe81d1 75 const_cast<GattAttribute**>(inputReportDescriptors), 1),
cho45 54:899fc2b0a76b 76
cho45 54:899fc2b0a76b 77 outputReportCharacteristic(GattCharacteristic::UUID_REPORT_CHAR,
cho45 54:899fc2b0a76b 78 (uint8_t *)outputReport, outputReportLength, outputReportLength,
cho45 54:899fc2b0a76b 79 GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_READ
cho45 54:899fc2b0a76b 80 | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_WRITE_WITHOUT_RESPONSE
cho45 54:899fc2b0a76b 81 | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_WRITE,
cho45 75:351d7ffe81d1 82 const_cast<GattAttribute**>(outputReportDescriptors), 1),
cho45 54:899fc2b0a76b 83
cho45 54:899fc2b0a76b 84 featureReportCharacteristic(GattCharacteristic::UUID_REPORT_CHAR,
cho45 54:899fc2b0a76b 85 (uint8_t *)featureReport, featureReportLength, featureReportLength,
cho45 54:899fc2b0a76b 86 GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_READ
cho45 54:899fc2b0a76b 87 | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_WRITE,
cho45 75:351d7ffe81d1 88 const_cast<GattAttribute**>(featureReportDescriptors), 1),
cho45 54:899fc2b0a76b 89
cho45 54:899fc2b0a76b 90 /*
cho45 54:899fc2b0a76b 91 * We need to set reportMap content as const, in order to let the compiler put it into flash
cho45 54:899fc2b0a76b 92 * instead of RAM. The characteristic is read-only so it won't be written, but
cho45 54:899fc2b0a76b 93 * GattCharacteristic constructor takes non-const arguments only. Hence the cast.
cho45 54:899fc2b0a76b 94 */
cho45 54:899fc2b0a76b 95 reportMapCharacteristic(GattCharacteristic::UUID_REPORT_MAP_CHAR,
cho45 54:899fc2b0a76b 96 const_cast<uint8_t*>(reportMap), reportMapLength, reportMapLength,
cho45 54:899fc2b0a76b 97 GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_READ,
cho45 59:2d6c0bff2151 98 NULL, 0),
cho45 54:899fc2b0a76b 99
cho45 75:351d7ffe81d1 100 HIDInformationCharacteristic(GattCharacteristic::UUID_HID_INFORMATION_CHAR, const_cast<HID_information_t*>(&HID_information)),
cho45 54:899fc2b0a76b 101 HIDControlPointCharacteristic(GattCharacteristic::UUID_HID_CONTROL_POINT_CHAR,
cho45 54:899fc2b0a76b 102 &controlPointCommand, 1, 1,
cho45 54:899fc2b0a76b 103 GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_WRITE_WITHOUT_RESPONSE),
cho45 54:899fc2b0a76b 104
cho45 54:899fc2b0a76b 105 reportTickerDelay(inputReportTickerDelay),
cho45 54:899fc2b0a76b 106 reportTickerIsActive(false)
cho45 54:899fc2b0a76b 107 {
cho45 79:0095bfb18c57 108 }
cho45 54:899fc2b0a76b 109
cho45 79:0095bfb18c57 110 void HIDServiceBase::init(void) {
cho45 79:0095bfb18c57 111 static GattCharacteristic *characteristics[] = {
cho45 79:0095bfb18c57 112 &HIDInformationCharacteristic,
cho45 79:0095bfb18c57 113 &reportMapCharacteristic,
cho45 79:0095bfb18c57 114 &protocolModeCharacteristic,
cho45 79:0095bfb18c57 115 &HIDControlPointCharacteristic,
cho45 79:0095bfb18c57 116 NULL,
cho45 79:0095bfb18c57 117 NULL,
cho45 79:0095bfb18c57 118 NULL,
cho45 79:0095bfb18c57 119 NULL,
cho45 79:0095bfb18c57 120 NULL
cho45 79:0095bfb18c57 121 };
cho45 54:899fc2b0a76b 122
cho45 79:0095bfb18c57 123 uint8_t charIndex = 4;
cho45 79:0095bfb18c57 124 /*
cho45 79:0095bfb18c57 125 * Report characteristics are optional, and depend on the reportMap descriptor
cho45 79:0095bfb18c57 126 * Note: at least one should be present, but we don't check that at the moment.
cho45 79:0095bfb18c57 127 */
cho45 79:0095bfb18c57 128 if (inputReportLength)
cho45 79:0095bfb18c57 129 characteristics[charIndex++] = &inputReportCharacteristic;
cho45 79:0095bfb18c57 130 if (outputReportLength)
cho45 79:0095bfb18c57 131 characteristics[charIndex++] = &outputReportCharacteristic;
cho45 79:0095bfb18c57 132 if (featureReportLength)
cho45 79:0095bfb18c57 133 characteristics[charIndex++] = &featureReportCharacteristic;
cho45 79:0095bfb18c57 134
cho45 79:0095bfb18c57 135 addExtraCharacteristics(characteristics, charIndex);
cho45 54:899fc2b0a76b 136
cho45 79:0095bfb18c57 137 DEBUG_PRINTF_BLE("new GattService %d\r\n", charIndex);
cho45 79:0095bfb18c57 138 GattService service(GattService::UUID_HUMAN_INTERFACE_DEVICE_SERVICE, characteristics, charIndex);
cho45 54:899fc2b0a76b 139
cho45 79:0095bfb18c57 140 ble.gattServer().addService(service);
cho45 54:899fc2b0a76b 141
cho45 79:0095bfb18c57 142 ble.gap().onConnection(this, &HIDServiceBase::onConnection);
cho45 79:0095bfb18c57 143 ble.gap().onDisconnection(this, &HIDServiceBase::onDisconnection);
cho45 54:899fc2b0a76b 144
cho45 79:0095bfb18c57 145 ble.gattServer().onDataSent(this, &HIDServiceBase::onDataSent);
cho45 79:0095bfb18c57 146 ble.gattServer().onDataWritten(this, &HIDServiceBase::onDataWritten);
cho45 54:899fc2b0a76b 147
cho45 79:0095bfb18c57 148 /*
cho45 79:0095bfb18c57 149 * Change preferred connection params, in order to optimize the notification frequency. Most
cho45 79:0095bfb18c57 150 * OSes seem to respect this, even though they are not required to.
cho45 79:0095bfb18c57 151 *
cho45 79:0095bfb18c57 152 * Some OSes don't handle reconnection well, at the moment, so we set the maximum possible
cho45 79:0095bfb18c57 153 * timeout, 32 seconds
cho45 79:0095bfb18c57 154 */
cho45 79:0095bfb18c57 155 uint16_t minInterval = Gap::MSEC_TO_GAP_DURATION_UNITS(reportTickerDelay / 2);
cho45 79:0095bfb18c57 156 if (minInterval < 6)
cho45 79:0095bfb18c57 157 minInterval = 6;
cho45 79:0095bfb18c57 158 uint16_t maxInterval = minInterval * 2;
cho45 79:0095bfb18c57 159 Gap::ConnectionParams_t params = {minInterval, maxInterval, 0, 3200};
cho45 54:899fc2b0a76b 160
cho45 79:0095bfb18c57 161 ble.gap().setPreferredConnectionParams(&params);
cho45 54:899fc2b0a76b 162
cho45 79:0095bfb18c57 163 SecurityManager::SecurityMode_t securityMode = SecurityManager::SECURITY_MODE_ENCRYPTION_NO_MITM;
cho45 79:0095bfb18c57 164 protocolModeCharacteristic.requireSecurity(securityMode);
cho45 79:0095bfb18c57 165 reportMapCharacteristic.requireSecurity(securityMode);
cho45 79:0095bfb18c57 166 inputReportCharacteristic.requireSecurity(securityMode);
cho45 79:0095bfb18c57 167 outputReportCharacteristic.requireSecurity(securityMode);
cho45 79:0095bfb18c57 168 featureReportCharacteristic.requireSecurity(securityMode);
cho45 54:899fc2b0a76b 169 }
cho45 54:899fc2b0a76b 170
cho45 54:899fc2b0a76b 171 void HIDServiceBase::startReportTicker(void) {
cho45 54:899fc2b0a76b 172 if (reportTickerIsActive)
cho45 54:899fc2b0a76b 173 return;
cho45 54:899fc2b0a76b 174 reportTicker.attach_us(this, &HIDServiceBase::sendCallback, reportTickerDelay * 1000);
cho45 54:899fc2b0a76b 175 reportTickerIsActive = true;
cho45 54:899fc2b0a76b 176 }
cho45 54:899fc2b0a76b 177
cho45 54:899fc2b0a76b 178 void HIDServiceBase::stopReportTicker(void) {
cho45 54:899fc2b0a76b 179 reportTicker.detach();
cho45 54:899fc2b0a76b 180 reportTickerIsActive = false;
cho45 54:899fc2b0a76b 181 }
cho45 54:899fc2b0a76b 182
cho45 54:899fc2b0a76b 183 void HIDServiceBase::onDataSent(unsigned count) {
cho45 54:899fc2b0a76b 184 startReportTicker();
cho45 54:899fc2b0a76b 185 }
cho45 54:899fc2b0a76b 186
cho45 79:0095bfb18c57 187 void HIDServiceBase::onDataWritten(const GattWriteCallbackParams *params) {
cho45 79:0095bfb18c57 188 }
cho45 79:0095bfb18c57 189
cho45 79:0095bfb18c57 190 void HIDServiceBase::addExtraCharacteristics(GattCharacteristic** characteristics, uint8_t& charIndex) {
cho45 79:0095bfb18c57 191 }
cho45 54:899fc2b0a76b 192
cho45 54:899fc2b0a76b 193 ble_error_t HIDServiceBase::send(const report_t report) {
cho45 54:899fc2b0a76b 194 return ble.gattServer().write(inputReportCharacteristic.getValueHandle(),
cho45 54:899fc2b0a76b 195 report,
cho45 54:899fc2b0a76b 196 inputReportLength);
cho45 54:899fc2b0a76b 197 }
cho45 54:899fc2b0a76b 198
cho45 54:899fc2b0a76b 199 ble_error_t HIDServiceBase::read(report_t report) {
cho45 54:899fc2b0a76b 200 // TODO. For the time being, we'll just have HID input reports...
cho45 54:899fc2b0a76b 201 return BLE_ERROR_NOT_IMPLEMENTED;
cho45 54:899fc2b0a76b 202 }
cho45 54:899fc2b0a76b 203
cho45 54:899fc2b0a76b 204 void HIDServiceBase::onConnection(const Gap::ConnectionCallbackParams_t *params)
cho45 54:899fc2b0a76b 205 {
cho45 54:899fc2b0a76b 206 this->connected = true;
cho45 54:899fc2b0a76b 207 }
cho45 54:899fc2b0a76b 208
cho45 54:899fc2b0a76b 209 void HIDServiceBase::onDisconnection(const Gap::DisconnectionCallbackParams_t *params)
cho45 54:899fc2b0a76b 210 {
cho45 54:899fc2b0a76b 211 this->connected = false;
cho45 75:351d7ffe81d1 212 }