Initial release

Dependencies:   microbit

Committer:
masakjm
Date:
Mon Sep 17 02:48:51 2018 +0000
Revision:
0:28fb3e9ef81a
first release

Who changed what in which revision?

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