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