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