BLE switch interface using micro:bit with 3 tact switches or 3 Makey Makey sensors

Dependencies:   microbit

Committer:
masakjm
Date:
Tue Jun 11 18:08:53 2019 +0000
Revision:
3:d8fd4efb63cc
Parent:
1:9d0e2e5b5d25
Change the usage of timer.

Who changed what in which revision?

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