Dependencies:   mbed BLE_API nRF51822

Committer:
weisimin
Date:
Tue Jul 20 09:23:54 2021 +0000
Revision:
0:706cf6936c11
BLE GATT GAMEPAD NO TEST

Who changed what in which revision?

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