HID-over-GATT implementation with the BLE API. This library allows to create devices such as mouse, keyboard or joystick, over Bluetooth Low Energy.
Dependents: Seeed_Tiny_BLE_FTHR_Peripheral
Fork of BLE_HID by
Diff: KeyboardService.h
- Revision:
- 1:7a6c2e2c9371
- Parent:
- 0:cfd70fa91663
- Child:
- 2:3d9adb26bdc5
--- a/KeyboardService.h Tue Sep 15 20:16:58 2015 +0100 +++ b/KeyboardService.h Wed Oct 07 11:29:52 2015 +0100 @@ -1,3 +1,19 @@ +/* mbed Microcontroller Library + * Copyright (c) 2015 ARM Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + #include <errno.h> #include "mbed.h" #include "CircularBuffer.h" @@ -11,6 +27,11 @@ #define KEYBUFFER_SIZE 512 #endif +/** + * Report descriptor for a standard 101 keys keyboard, following the HID specification example: + * - 8 bytes input report (1 byte for modifiers and 6 for keys) + * - 1 byte output report (LEDs) + */ report_map_t KEYBOARD_REPORT_MAP = { USAGE_PAGE(1), 0x01, // Generic Desktop Ctrls USAGE(1), 0x06, // Keyboard @@ -46,10 +67,14 @@ END_COLLECTION(0), }; +/// "keys pressed" report static uint8_t inputReportData[] = { 0, 0, 0, 0, 0, 0, 0, 0 }; +/// "keys released" report static const uint8_t emptyInputReportData[] = { 0, 0, 0, 0, 0, 0, 0, 0 }; +/// LEDs report static uint8_t outputReportData[] = { 0 }; + /** * @class KeyBuffer * @@ -135,6 +160,26 @@ bool keyUpIsPending; }; + +/** + * @class KeyboardService + * @brief HID-over-Gatt keyboard service + * + * Send keyboard reports over BLE. Users should rely on the high-level functions provided by the + * Stream API. Because we can't send batches of HID reports, we store pending keys in a circular + * buffer and rely on the report ticker to spread them over time. + * + * @code + * BLE ble; + * KeyboardService kbd(ble); + * + * void once_connected_and_paired_callback(void) + * { + * // Sequentially send keys 'Shift'+'h', 'e', 'l', 'l', 'o', '!' and <enter> + * kbd.printf("Hello!\n"); + * } + * @endcode + */ class KeyboardService : public HIDServiceBase, public Stream { public: @@ -152,6 +197,24 @@ { } + virtual void onConnection(const Gap::ConnectionCallbackParams_t *params) + { + HIDServiceBase::onConnection(params); + + /* Drain buffer, in case we've been disconnected while transmitting */ + if (!reportTickerIsActive && keyBuffer.isSomethingPending()) + startReportTicker(); + } + + virtual void onDisconnection(const Gap::DisconnectionCallbackParams_t *params) + { + stopReportTicker(); + HIDServiceBase::onDisconnection(params); + } + + /** + * Send raw report. Should only be called by sendCallback. + */ virtual ble_error_t send(const report_t report) { static unsigned int consecutiveFailures = 0; @@ -172,7 +235,7 @@ if (consecutiveFailures > 20) { /* - * We're not tranmitting anything anymore. Might as well avoid overloading the + * We're not transmitting anything anymore. Might as well avoid overloading the * system in case it can magically fix itself. Ticker will start again on next _putc * call. It could also be started on next connection, but we can't register a callback * for that, currently. @@ -192,6 +255,14 @@ return send(emptyInputReportData); } + /** + * Send a character, defined by a modifier (CTRL, SHIFT, ALT) and the key + * + * @param key Character to send (as defined in USB HID Usage Tables) + * @param modifier Optional modifiers (logical OR of enum MODIFIER_KEY) + * + * @returns BLE_ERROR_NONE on success, or an error code otherwise. + */ ble_error_t keyDownCode(uint8_t key, uint8_t modifier) { inputReportData[0] = modifier; @@ -200,6 +271,13 @@ return send(inputReportData); } + /** + * Push a key on the internal FIFO + * + * @param c ASCII character to send + * + * @returns 0 on success, or ENOMEM when the FIFO is full. + */ virtual int _putc(int c) { if (keyBuffer.full()) { return ENOMEM; @@ -218,6 +296,9 @@ return 0; } + /** + * Pop a key from the internal FIFO, and attempt to send it over BLE + */ virtual void sendCallback(void) { ble_error_t ret; uint8_t c; @@ -256,6 +337,13 @@ } } + /** + * Restart report ticker if it was disabled, after too many consecutive failures. + * + * This is called by the BLE stack. + * + * @param count Number of reports (notifications) sent + */ virtual void onDataSent(unsigned count) { if (!reportTickerIsActive && keyBuffer.isSomethingPending())