MicroBit as BLE gamepad

Dependencies:   BLE_API mbed-dev-bin nRF51822

Dependents:   microbit

Fork of microbit-dal by Lancaster University

Committer:
rengro01
Date:
Mon Jan 30 08:29:06 2017 +0000
Revision:
75:df904445f561
Parent:
74:1b9850e39cd1
MicroBit as BLE gamepad

Who changed what in which revision?

UserRevisionLine numberNew contents of line
rengro01 74:1b9850e39cd1 1 /* mbed Microcontroller Library
rengro01 74:1b9850e39cd1 2 * Copyright (c) 2015 ARM Limited
rengro01 74:1b9850e39cd1 3 *
rengro01 74:1b9850e39cd1 4 * Licensed under the Apache License, Version 2.0 (the "License");
rengro01 74:1b9850e39cd1 5 * you may not use this file except in compliance with the License.
rengro01 74:1b9850e39cd1 6 * You may obtain a copy of the License at
rengro01 74:1b9850e39cd1 7 *
rengro01 74:1b9850e39cd1 8 * http://www.apache.org/licenses/LICENSE-2.0
rengro01 74:1b9850e39cd1 9 *
rengro01 74:1b9850e39cd1 10 * Unless required by applicable law or agreed to in writing, software
rengro01 74:1b9850e39cd1 11 * distributed under the License is distributed on an "AS IS" BASIS,
rengro01 74:1b9850e39cd1 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
rengro01 74:1b9850e39cd1 13 * See the License for the specific language governing permissions and
rengro01 74:1b9850e39cd1 14 * limitations under the License.
rengro01 74:1b9850e39cd1 15 */
rengro01 74:1b9850e39cd1 16
rengro01 74:1b9850e39cd1 17 #include <errno.h>
rengro01 74:1b9850e39cd1 18 #include "mbed.h"
rengro01 74:1b9850e39cd1 19 #include "CircularBuffer.h"
rengro01 74:1b9850e39cd1 20
rengro01 74:1b9850e39cd1 21 #include "HIDServiceBase.h"
rengro01 74:1b9850e39cd1 22 #include "Keyboard_types.h"
rengro01 74:1b9850e39cd1 23
rengro01 74:1b9850e39cd1 24 /* TODO: make this easier to configure by application (e.g. as a template parameter for
rengro01 74:1b9850e39cd1 25 * KeyboardService) */
rengro01 74:1b9850e39cd1 26 #ifndef KEYBUFFER_SIZE
rengro01 74:1b9850e39cd1 27 #define KEYBUFFER_SIZE 512
rengro01 74:1b9850e39cd1 28 #endif
rengro01 74:1b9850e39cd1 29
rengro01 74:1b9850e39cd1 30 /**
rengro01 74:1b9850e39cd1 31 * Report descriptor for a standard 101 keys keyboard, following the HID specification example:
rengro01 74:1b9850e39cd1 32 * - 8 bytes input report (1 byte for modifiers and 6 for keys)
rengro01 74:1b9850e39cd1 33 * - 1 byte output report (LEDs)
rengro01 74:1b9850e39cd1 34 */
rengro01 74:1b9850e39cd1 35 report_map_t KEYBOARD_REPORT_MAP = {
rengro01 74:1b9850e39cd1 36 USAGE_PAGE(1), 0x01, // Generic Desktop Ctrls
rengro01 74:1b9850e39cd1 37 USAGE(1), 0x06, // Keyboard
rengro01 74:1b9850e39cd1 38 COLLECTION(1), 0x01, // Application
rengro01 74:1b9850e39cd1 39 USAGE_PAGE(1), 0x07, // Kbrd/Keypad
rengro01 74:1b9850e39cd1 40 USAGE_MINIMUM(1), 0xE0,
rengro01 74:1b9850e39cd1 41 USAGE_MAXIMUM(1), 0xE7,
rengro01 74:1b9850e39cd1 42 LOGICAL_MINIMUM(1), 0x00,
rengro01 74:1b9850e39cd1 43 LOGICAL_MAXIMUM(1), 0x01,
rengro01 74:1b9850e39cd1 44 REPORT_SIZE(1), 0x01, // 1 byte (Modifier)
rengro01 74:1b9850e39cd1 45 REPORT_COUNT(1), 0x08,
rengro01 74:1b9850e39cd1 46 INPUT(1), 0x02, // Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position
rengro01 74:1b9850e39cd1 47 REPORT_COUNT(1), 0x01, // 1 byte (Reserved)
rengro01 74:1b9850e39cd1 48 REPORT_SIZE(1), 0x08,
rengro01 74:1b9850e39cd1 49 INPUT(1), 0x01, // Const,Array,Abs,No Wrap,Linear,Preferred State,No Null Position
rengro01 74:1b9850e39cd1 50 REPORT_COUNT(1), 0x05, // 5 bits (Num lock, Caps lock, Scroll lock, Compose, Kana)
rengro01 74:1b9850e39cd1 51 REPORT_SIZE(1), 0x01,
rengro01 74:1b9850e39cd1 52 USAGE_PAGE(1), 0x08, // LEDs
rengro01 74:1b9850e39cd1 53 USAGE_MINIMUM(1), 0x01, // Num Lock
rengro01 74:1b9850e39cd1 54 USAGE_MAXIMUM(1), 0x05, // Kana
rengro01 74:1b9850e39cd1 55 OUTPUT(1), 0x02, // Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile
rengro01 74:1b9850e39cd1 56 REPORT_COUNT(1), 0x01, // 3 bits (Padding)
rengro01 74:1b9850e39cd1 57 REPORT_SIZE(1), 0x03,
rengro01 74:1b9850e39cd1 58 OUTPUT(1), 0x01, // Const,Array,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile
rengro01 74:1b9850e39cd1 59 REPORT_COUNT(1), 0x06, // 6 bytes (Keys)
rengro01 74:1b9850e39cd1 60 REPORT_SIZE(1), 0x08,
rengro01 74:1b9850e39cd1 61 LOGICAL_MINIMUM(1), 0x00,
rengro01 74:1b9850e39cd1 62 LOGICAL_MAXIMUM(1), 0x65, // 101 keys
rengro01 74:1b9850e39cd1 63 USAGE_PAGE(1), 0x07, // Kbrd/Keypad
rengro01 74:1b9850e39cd1 64 USAGE_MINIMUM(1), 0x00,
rengro01 74:1b9850e39cd1 65 USAGE_MAXIMUM(1), 0x65,
rengro01 74:1b9850e39cd1 66 INPUT(1), 0x00, // Data,Array,Abs,No Wrap,Linear,Preferred State,No Null Position
rengro01 74:1b9850e39cd1 67 END_COLLECTION(0),
rengro01 74:1b9850e39cd1 68 };
rengro01 74:1b9850e39cd1 69
rengro01 74:1b9850e39cd1 70 /// "keys pressed" report
rengro01 74:1b9850e39cd1 71 static uint8_t inputReportData[] = { 0, 0, 0, 0, 0, 0, 0, 0 };
rengro01 74:1b9850e39cd1 72 /// "keys released" report
rengro01 74:1b9850e39cd1 73 static const uint8_t emptyInputReportData[] = { 0, 0, 0, 0, 0, 0, 0, 0 };
rengro01 74:1b9850e39cd1 74 /// LEDs report
rengro01 74:1b9850e39cd1 75 static uint8_t outputReportData[] = { 0 };
rengro01 74:1b9850e39cd1 76
rengro01 74:1b9850e39cd1 77
rengro01 74:1b9850e39cd1 78 /**
rengro01 74:1b9850e39cd1 79 * @class KeyBuffer
rengro01 74:1b9850e39cd1 80 *
rengro01 74:1b9850e39cd1 81 * Buffer used to store keys to send.
rengro01 74:1b9850e39cd1 82 * Internally, it is a CircularBuffer, with the added capability of putting the last char back in,
rengro01 74:1b9850e39cd1 83 * when we're unable to send it (ie. when BLE stack is busy)
rengro01 74:1b9850e39cd1 84 */
rengro01 74:1b9850e39cd1 85 class KeyBuffer: public CircularBuffer<uint8_t, KEYBUFFER_SIZE>
rengro01 74:1b9850e39cd1 86 {
rengro01 74:1b9850e39cd1 87 public:
rengro01 74:1b9850e39cd1 88 KeyBuffer() :
rengro01 74:1b9850e39cd1 89 CircularBuffer(),
rengro01 74:1b9850e39cd1 90 dataIsPending (false),
rengro01 74:1b9850e39cd1 91 keyUpIsPending (false)
rengro01 74:1b9850e39cd1 92 {
rengro01 74:1b9850e39cd1 93 }
rengro01 74:1b9850e39cd1 94
rengro01 74:1b9850e39cd1 95 /**
rengro01 74:1b9850e39cd1 96 * Mark a character as pending. When a freshly popped character cannot be sent, because the
rengro01 74:1b9850e39cd1 97 * underlying stack is busy, we set it as pending, and it will get popped in priority by @ref
rengro01 74:1b9850e39cd1 98 * getPending once reports can be sent again.
rengro01 74:1b9850e39cd1 99 *
rengro01 74:1b9850e39cd1 100 * @param data The character to send in priority. The second keyUp report is implied.
rengro01 74:1b9850e39cd1 101 */
rengro01 74:1b9850e39cd1 102 void setPending(uint8_t data)
rengro01 74:1b9850e39cd1 103 {
rengro01 74:1b9850e39cd1 104 MBED_ASSERT(dataIsPending == false);
rengro01 74:1b9850e39cd1 105
rengro01 74:1b9850e39cd1 106 dataIsPending = true;
rengro01 74:1b9850e39cd1 107 pendingData = data;
rengro01 74:1b9850e39cd1 108 keyUpIsPending = true;
rengro01 74:1b9850e39cd1 109 }
rengro01 74:1b9850e39cd1 110
rengro01 74:1b9850e39cd1 111 /**
rengro01 74:1b9850e39cd1 112 * Get pending char. Either from the high priority buffer (set with setPending), or from the
rengro01 74:1b9850e39cd1 113 * circular buffer.
rengro01 74:1b9850e39cd1 114 *
rengro01 74:1b9850e39cd1 115 * @param data Filled with the pending data, when present
rengro01 74:1b9850e39cd1 116 * @return true if data was filled
rengro01 74:1b9850e39cd1 117 */
rengro01 74:1b9850e39cd1 118 bool getPending(uint8_t &data)
rengro01 74:1b9850e39cd1 119 {
rengro01 74:1b9850e39cd1 120 if (dataIsPending) {
rengro01 74:1b9850e39cd1 121 dataIsPending = false;
rengro01 74:1b9850e39cd1 122 data = pendingData;
rengro01 74:1b9850e39cd1 123 return true;
rengro01 74:1b9850e39cd1 124 }
rengro01 74:1b9850e39cd1 125
rengro01 74:1b9850e39cd1 126 return pop(data);
rengro01 74:1b9850e39cd1 127 }
rengro01 74:1b9850e39cd1 128
rengro01 74:1b9850e39cd1 129 bool isSomethingPending(void)
rengro01 74:1b9850e39cd1 130 {
rengro01 74:1b9850e39cd1 131 return dataIsPending || keyUpIsPending || !empty();
rengro01 74:1b9850e39cd1 132 }
rengro01 74:1b9850e39cd1 133
rengro01 74:1b9850e39cd1 134 /**
rengro01 74:1b9850e39cd1 135 * Signal that a keyUp report is pending. This means that a character has successfully been
rengro01 74:1b9850e39cd1 136 * sent, but the subsequent keyUp report failed. This report is of highest priority than the
rengro01 74:1b9850e39cd1 137 * next character.
rengro01 74:1b9850e39cd1 138 */
rengro01 74:1b9850e39cd1 139 void setKeyUpPending(void)
rengro01 74:1b9850e39cd1 140 {
rengro01 74:1b9850e39cd1 141 keyUpIsPending = true;
rengro01 74:1b9850e39cd1 142 }
rengro01 74:1b9850e39cd1 143
rengro01 74:1b9850e39cd1 144 /**
rengro01 74:1b9850e39cd1 145 * Signal that no high-priority report is pending anymore, we can go back to the normal queue.
rengro01 74:1b9850e39cd1 146 */
rengro01 74:1b9850e39cd1 147 void clearKeyUpPending(void)
rengro01 74:1b9850e39cd1 148 {
rengro01 74:1b9850e39cd1 149 keyUpIsPending = false;
rengro01 74:1b9850e39cd1 150 }
rengro01 74:1b9850e39cd1 151
rengro01 74:1b9850e39cd1 152 bool isKeyUpPending(void)
rengro01 74:1b9850e39cd1 153 {
rengro01 74:1b9850e39cd1 154 return keyUpIsPending;
rengro01 74:1b9850e39cd1 155 }
rengro01 74:1b9850e39cd1 156
rengro01 74:1b9850e39cd1 157 protected:
rengro01 74:1b9850e39cd1 158 bool dataIsPending;
rengro01 74:1b9850e39cd1 159 uint8_t pendingData;
rengro01 74:1b9850e39cd1 160 bool keyUpIsPending;
rengro01 74:1b9850e39cd1 161 };
rengro01 74:1b9850e39cd1 162
rengro01 74:1b9850e39cd1 163
rengro01 74:1b9850e39cd1 164 /**
rengro01 74:1b9850e39cd1 165 * @class KeyboardService
rengro01 74:1b9850e39cd1 166 * @brief HID-over-Gatt keyboard service
rengro01 74:1b9850e39cd1 167 *
rengro01 74:1b9850e39cd1 168 * Send keyboard reports over BLE. Users should rely on the high-level functions provided by the
rengro01 74:1b9850e39cd1 169 * Stream API. Because we can't send batches of HID reports, we store pending keys in a circular
rengro01 74:1b9850e39cd1 170 * buffer and rely on the report ticker to spread them over time.
rengro01 74:1b9850e39cd1 171 *
rengro01 74:1b9850e39cd1 172 * @code
rengro01 74:1b9850e39cd1 173 * BLE ble;
rengro01 74:1b9850e39cd1 174 * KeyboardService kbd(ble);
rengro01 74:1b9850e39cd1 175 *
rengro01 74:1b9850e39cd1 176 * void once_connected_and_paired_callback(void)
rengro01 74:1b9850e39cd1 177 * {
rengro01 74:1b9850e39cd1 178 * // Sequentially send keys 'Shift'+'h', 'e', 'l', 'l', 'o', '!' and <enter>
rengro01 74:1b9850e39cd1 179 * kbd.printf("Hello!\n");
rengro01 74:1b9850e39cd1 180 * }
rengro01 74:1b9850e39cd1 181 * @endcode
rengro01 74:1b9850e39cd1 182 */
rengro01 74:1b9850e39cd1 183 class KeyboardService : public HIDServiceBase, public Stream
rengro01 74:1b9850e39cd1 184 {
rengro01 74:1b9850e39cd1 185 public:
rengro01 74:1b9850e39cd1 186 KeyboardService(BLE &_ble) :
rengro01 74:1b9850e39cd1 187 HIDServiceBase(_ble,
rengro01 74:1b9850e39cd1 188 KEYBOARD_REPORT_MAP, sizeof(KEYBOARD_REPORT_MAP),
rengro01 74:1b9850e39cd1 189 inputReport = emptyInputReportData,
rengro01 74:1b9850e39cd1 190 outputReport = outputReportData,
rengro01 74:1b9850e39cd1 191 featureReport = NULL,
rengro01 74:1b9850e39cd1 192 inputReportLength = sizeof(inputReportData),
rengro01 74:1b9850e39cd1 193 outputReportLength = sizeof(outputReportData),
rengro01 74:1b9850e39cd1 194 featureReportLength = 0,
rengro01 74:1b9850e39cd1 195 reportTickerDelay = 24),
rengro01 74:1b9850e39cd1 196 failedReports(0)
rengro01 74:1b9850e39cd1 197 {
rengro01 74:1b9850e39cd1 198 }
rengro01 74:1b9850e39cd1 199
rengro01 74:1b9850e39cd1 200 virtual void onConnection(const Gap::ConnectionCallbackParams_t *params)
rengro01 74:1b9850e39cd1 201 {
rengro01 74:1b9850e39cd1 202 HIDServiceBase::onConnection(params);
rengro01 74:1b9850e39cd1 203
rengro01 74:1b9850e39cd1 204 /* Drain buffer, in case we've been disconnected while transmitting */
rengro01 74:1b9850e39cd1 205 if (!reportTickerIsActive && keyBuffer.isSomethingPending())
rengro01 74:1b9850e39cd1 206 startReportTicker();
rengro01 74:1b9850e39cd1 207 }
rengro01 74:1b9850e39cd1 208
rengro01 74:1b9850e39cd1 209 virtual void onDisconnection(const Gap::DisconnectionCallbackParams_t *params)
rengro01 74:1b9850e39cd1 210 {
rengro01 74:1b9850e39cd1 211 stopReportTicker();
rengro01 74:1b9850e39cd1 212 HIDServiceBase::onDisconnection(params);
rengro01 74:1b9850e39cd1 213 }
rengro01 74:1b9850e39cd1 214
rengro01 74:1b9850e39cd1 215 /**
rengro01 74:1b9850e39cd1 216 * Send raw report. Should only be called by sendCallback.
rengro01 74:1b9850e39cd1 217 */
rengro01 74:1b9850e39cd1 218 virtual ble_error_t send(const report_t report)
rengro01 74:1b9850e39cd1 219 {
rengro01 74:1b9850e39cd1 220 static unsigned int consecutiveFailures = 0;
rengro01 74:1b9850e39cd1 221 ble_error_t ret = HIDServiceBase::send(report);
rengro01 74:1b9850e39cd1 222
rengro01 74:1b9850e39cd1 223 /*
rengro01 74:1b9850e39cd1 224 * Wait until a buffer is available (onDataSent)
rengro01 74:1b9850e39cd1 225 * TODO. This won't work, because BUSY error is not only returned when we're short of
rengro01 74:1b9850e39cd1 226 * notification buffers, but in other cases as well (e.g. when disconnected). We need to
rengro01 74:1b9850e39cd1 227 * find a reliable way of knowing when we actually need to wait for onDataSent to be called.
rengro01 74:1b9850e39cd1 228 if (ret == BLE_STACK_BUSY)
rengro01 74:1b9850e39cd1 229 stopReportTicker();
rengro01 74:1b9850e39cd1 230 */
rengro01 74:1b9850e39cd1 231 if (ret == BLE_STACK_BUSY)
rengro01 74:1b9850e39cd1 232 consecutiveFailures++;
rengro01 74:1b9850e39cd1 233 else
rengro01 74:1b9850e39cd1 234 consecutiveFailures = 0;
rengro01 74:1b9850e39cd1 235
rengro01 74:1b9850e39cd1 236 if (consecutiveFailures > 20) {
rengro01 74:1b9850e39cd1 237 /*
rengro01 74:1b9850e39cd1 238 * We're not transmitting anything anymore. Might as well avoid overloading the
rengro01 74:1b9850e39cd1 239 * system in case it can magically fix itself. Ticker will start again on next _putc
rengro01 74:1b9850e39cd1 240 * call. It could also be started on next connection, but we can't register a callback
rengro01 74:1b9850e39cd1 241 * for that, currently.
rengro01 74:1b9850e39cd1 242 */
rengro01 74:1b9850e39cd1 243 stopReportTicker();
rengro01 74:1b9850e39cd1 244 consecutiveFailures = 0;
rengro01 74:1b9850e39cd1 245 }
rengro01 74:1b9850e39cd1 246
rengro01 74:1b9850e39cd1 247 return ret;
rengro01 74:1b9850e39cd1 248 }
rengro01 74:1b9850e39cd1 249
rengro01 74:1b9850e39cd1 250 /**
rengro01 74:1b9850e39cd1 251 * Send an empty report, representing keyUp event
rengro01 74:1b9850e39cd1 252 */
rengro01 74:1b9850e39cd1 253 ble_error_t keyUpCode(void)
rengro01 74:1b9850e39cd1 254 {
rengro01 74:1b9850e39cd1 255 return send(emptyInputReportData);
rengro01 74:1b9850e39cd1 256 }
rengro01 74:1b9850e39cd1 257
rengro01 74:1b9850e39cd1 258 /**
rengro01 74:1b9850e39cd1 259 * Send a character, defined by a modifier (CTRL, SHIFT, ALT) and the key
rengro01 74:1b9850e39cd1 260 *
rengro01 74:1b9850e39cd1 261 * @param key Character to send (as defined in USB HID Usage Tables)
rengro01 74:1b9850e39cd1 262 * @param modifier Optional modifiers (logical OR of enum MODIFIER_KEY)
rengro01 74:1b9850e39cd1 263 *
rengro01 74:1b9850e39cd1 264 * @returns BLE_ERROR_NONE on success, or an error code otherwise.
rengro01 74:1b9850e39cd1 265 */
rengro01 74:1b9850e39cd1 266 ble_error_t keyDownCode(uint8_t key, uint8_t modifier)
rengro01 74:1b9850e39cd1 267 {
rengro01 74:1b9850e39cd1 268 inputReportData[0] = modifier;
rengro01 74:1b9850e39cd1 269 inputReportData[2] = keymap[key].usage;
rengro01 74:1b9850e39cd1 270
rengro01 74:1b9850e39cd1 271 return send(inputReportData);
rengro01 74:1b9850e39cd1 272 }
rengro01 74:1b9850e39cd1 273
rengro01 74:1b9850e39cd1 274 /**
rengro01 74:1b9850e39cd1 275 * Push a key on the internal FIFO
rengro01 74:1b9850e39cd1 276 *
rengro01 74:1b9850e39cd1 277 * @param c ASCII character to send
rengro01 74:1b9850e39cd1 278 *
rengro01 74:1b9850e39cd1 279 * @returns 0 on success, or ENOMEM when the FIFO is full.
rengro01 74:1b9850e39cd1 280 */
rengro01 74:1b9850e39cd1 281 virtual int _putc(int c) {
rengro01 74:1b9850e39cd1 282 if (keyBuffer.full()) {
rengro01 74:1b9850e39cd1 283 return ENOMEM;
rengro01 74:1b9850e39cd1 284 }
rengro01 74:1b9850e39cd1 285
rengro01 74:1b9850e39cd1 286 keyBuffer.push((unsigned char)c);
rengro01 74:1b9850e39cd1 287
rengro01 74:1b9850e39cd1 288 if (!reportTickerIsActive)
rengro01 74:1b9850e39cd1 289 startReportTicker();
rengro01 74:1b9850e39cd1 290
rengro01 74:1b9850e39cd1 291 return 0;
rengro01 74:1b9850e39cd1 292 }
rengro01 74:1b9850e39cd1 293
rengro01 74:1b9850e39cd1 294 uint8_t lockStatus() {
rengro01 74:1b9850e39cd1 295 // TODO: implement numlock/capslock/scrolllock
rengro01 74:1b9850e39cd1 296 return 0;
rengro01 74:1b9850e39cd1 297 }
rengro01 74:1b9850e39cd1 298
rengro01 74:1b9850e39cd1 299 /**
rengro01 74:1b9850e39cd1 300 * Pop a key from the internal FIFO, and attempt to send it over BLE
rengro01 74:1b9850e39cd1 301 */
rengro01 74:1b9850e39cd1 302 virtual void sendCallback(void) {
rengro01 74:1b9850e39cd1 303 ble_error_t ret;
rengro01 74:1b9850e39cd1 304 uint8_t c;
rengro01 74:1b9850e39cd1 305
rengro01 74:1b9850e39cd1 306 if (!keyBuffer.isSomethingPending()) {
rengro01 74:1b9850e39cd1 307 /* Stop until the next call to putc */
rengro01 74:1b9850e39cd1 308 stopReportTicker();
rengro01 74:1b9850e39cd1 309 return;
rengro01 74:1b9850e39cd1 310 }
rengro01 74:1b9850e39cd1 311
rengro01 74:1b9850e39cd1 312 if (!keyBuffer.isKeyUpPending()) {
rengro01 74:1b9850e39cd1 313 bool hasData = keyBuffer.getPending(c);
rengro01 74:1b9850e39cd1 314
rengro01 74:1b9850e39cd1 315 /*
rengro01 74:1b9850e39cd1 316 * If something is pending and is not a keyUp, getPending *must* return something. The
rengro01 74:1b9850e39cd1 317 * following is only a sanity check.
rengro01 74:1b9850e39cd1 318 */
rengro01 74:1b9850e39cd1 319 MBED_ASSERT(hasData);
rengro01 74:1b9850e39cd1 320
rengro01 74:1b9850e39cd1 321 if (hasData) {
rengro01 74:1b9850e39cd1 322 ret = keyDownCode(c, keymap[c].modifier);
rengro01 74:1b9850e39cd1 323 if (ret) {
rengro01 74:1b9850e39cd1 324 keyBuffer.setPending(c);
rengro01 74:1b9850e39cd1 325 failedReports++;
rengro01 74:1b9850e39cd1 326 return;
rengro01 74:1b9850e39cd1 327 }
rengro01 74:1b9850e39cd1 328 }
rengro01 74:1b9850e39cd1 329 }
rengro01 74:1b9850e39cd1 330
rengro01 74:1b9850e39cd1 331 ret = keyUpCode();
rengro01 74:1b9850e39cd1 332 if (ret) {
rengro01 74:1b9850e39cd1 333 keyBuffer.setKeyUpPending();
rengro01 74:1b9850e39cd1 334 failedReports++;
rengro01 74:1b9850e39cd1 335 } else {
rengro01 74:1b9850e39cd1 336 keyBuffer.clearKeyUpPending();
rengro01 74:1b9850e39cd1 337 }
rengro01 74:1b9850e39cd1 338 }
rengro01 74:1b9850e39cd1 339
rengro01 74:1b9850e39cd1 340 /**
rengro01 74:1b9850e39cd1 341 * Restart report ticker if it was disabled, after too many consecutive failures.
rengro01 74:1b9850e39cd1 342 *
rengro01 74:1b9850e39cd1 343 * This is called by the BLE stack.
rengro01 74:1b9850e39cd1 344 *
rengro01 74:1b9850e39cd1 345 * @param count Number of reports (notifications) sent
rengro01 74:1b9850e39cd1 346 */
rengro01 74:1b9850e39cd1 347 virtual void onDataSent(unsigned count)
rengro01 74:1b9850e39cd1 348 {
rengro01 74:1b9850e39cd1 349 if (!reportTickerIsActive && keyBuffer.isSomethingPending())
rengro01 74:1b9850e39cd1 350 startReportTicker();
rengro01 74:1b9850e39cd1 351 }
rengro01 74:1b9850e39cd1 352
rengro01 74:1b9850e39cd1 353 unsigned long failedReports;
rengro01 74:1b9850e39cd1 354
rengro01 74:1b9850e39cd1 355 protected:
rengro01 74:1b9850e39cd1 356 virtual int _getc() {
rengro01 74:1b9850e39cd1 357 return 0;
rengro01 74:1b9850e39cd1 358 }
rengro01 74:1b9850e39cd1 359
rengro01 74:1b9850e39cd1 360 protected:
rengro01 74:1b9850e39cd1 361 KeyBuffer keyBuffer;
rengro01 74:1b9850e39cd1 362
rengro01 74:1b9850e39cd1 363 //GattCharacteristic boot_keyboard_input_report;
rengro01 74:1b9850e39cd1 364 //GattCharacteristic boot_keyboard_output_report;
rengro01 74:1b9850e39cd1 365 };
rengro01 74:1b9850e39cd1 366
rengro01 74:1b9850e39cd1 367