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:   BLENano_HID BLE_HID_MouseScrollDemo BLE_HID_KeyboardStreamDemo Shervs_TestKeyboard_TinyBLE ... more

The development repository is currently hosted on github. It contains examples and documentation. This is a snapshot of the library. The documentation can be read on github, or on docs.mbed.com.

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())