back up of work during May 2019

Dependencies:   microbit

Committer:
xx316
Date:
Fri May 31 20:53:51 2019 +0000
Revision:
1:c840c2b6f490
This is the program for bit_board, an accessory developed by a group of Imperial EEE students for MicroBit. This is the first commit to backup the work in May 2019.

Who changed what in which revision?

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