Use the microbit as a foot paddle Send Shift-Ctrl-Alt F11 and F12 for the buttons, you can use those a global hotkeys for actions, e.g. mute/unmute microphone

Dependencies:   mbed BLE_API nRF51822

Committer:
JonnyA
Date:
Mon Nov 02 18:25:58 2015 +0000
Revision:
0:cb1939018833
Child:
1:9e174f8fd9e9
Rename the keyboard

Who changed what in which revision?

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