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.

Committer:
Jean-Philippe Brucker
Date:
Wed Oct 07 11:29:52 2015 +0100
Revision:
1:7a6c2e2c9371
Parent:
0:cfd70fa91663
Child:
2:3d9adb26bdc5
Publish version 0.1 of the BLE HID lib

This version number is completely arbitrary, and probably won't stick: once the
service is stable, we'll merge it with BLE API.
It is simply used to keep examples in sync with the lib and the github
repository during development.

Who changed what in which revision?

UserRevisionLine numberNew contents of line
Jean-Philippe Brucker 1:7a6c2e2c9371 1 /* mbed Microcontroller Library
Jean-Philippe Brucker 1:7a6c2e2c9371 2 * Copyright (c) 2015 ARM Limited
Jean-Philippe Brucker 1:7a6c2e2c9371 3 *
Jean-Philippe Brucker 1:7a6c2e2c9371 4 * Licensed under the Apache License, Version 2.0 (the "License");
Jean-Philippe Brucker 1:7a6c2e2c9371 5 * you may not use this file except in compliance with the License.
Jean-Philippe Brucker 1:7a6c2e2c9371 6 * You may obtain a copy of the License at
Jean-Philippe Brucker 1:7a6c2e2c9371 7 *
Jean-Philippe Brucker 1:7a6c2e2c9371 8 * http://www.apache.org/licenses/LICENSE-2.0
Jean-Philippe Brucker 1:7a6c2e2c9371 9 *
Jean-Philippe Brucker 1:7a6c2e2c9371 10 * Unless required by applicable law or agreed to in writing, software
Jean-Philippe Brucker 1:7a6c2e2c9371 11 * distributed under the License is distributed on an "AS IS" BASIS,
Jean-Philippe Brucker 1:7a6c2e2c9371 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
Jean-Philippe Brucker 1:7a6c2e2c9371 13 * See the License for the specific language governing permissions and
Jean-Philippe Brucker 1:7a6c2e2c9371 14 * limitations under the License.
Jean-Philippe Brucker 1:7a6c2e2c9371 15 */
Jean-Philippe Brucker 1:7a6c2e2c9371 16
Jean-Philippe Brucker 0:cfd70fa91663 17 #include "mbed.h"
Jean-Philippe Brucker 0:cfd70fa91663 18
Jean-Philippe Brucker 0:cfd70fa91663 19 #include "HIDServiceBase.h"
Jean-Philippe Brucker 0:cfd70fa91663 20
Jean-Philippe Brucker 0:cfd70fa91663 21 enum ButtonState
Jean-Philippe Brucker 0:cfd70fa91663 22 {
Jean-Philippe Brucker 0:cfd70fa91663 23 BUTTON_UP,
Jean-Philippe Brucker 0:cfd70fa91663 24 BUTTON_DOWN
Jean-Philippe Brucker 0:cfd70fa91663 25 };
Jean-Philippe Brucker 0:cfd70fa91663 26
Jean-Philippe Brucker 0:cfd70fa91663 27 enum MouseButton
Jean-Philippe Brucker 0:cfd70fa91663 28 {
Jean-Philippe Brucker 0:cfd70fa91663 29 MOUSE_BUTTON_LEFT = 0x1,
Jean-Philippe Brucker 0:cfd70fa91663 30 MOUSE_BUTTON_RIGHT = 0x2,
Jean-Philippe Brucker 0:cfd70fa91663 31 MOUSE_BUTTON_MIDDLE = 0x4,
Jean-Philippe Brucker 0:cfd70fa91663 32 };
Jean-Philippe Brucker 0:cfd70fa91663 33
Jean-Philippe Brucker 1:7a6c2e2c9371 34 /**
Jean-Philippe Brucker 1:7a6c2e2c9371 35 * Report descriptor for a standard 3 buttons + wheel mouse with relative X/Y
Jean-Philippe Brucker 1:7a6c2e2c9371 36 * moves
Jean-Philippe Brucker 1:7a6c2e2c9371 37 */
Jean-Philippe Brucker 0:cfd70fa91663 38 report_map_t MOUSE_REPORT_MAP = {
Jean-Philippe Brucker 0:cfd70fa91663 39 USAGE_PAGE(1), 0x01, // Generic Desktop
Jean-Philippe Brucker 0:cfd70fa91663 40 USAGE(1), 0x02, // Mouse
Jean-Philippe Brucker 0:cfd70fa91663 41 COLLECTION(1), 0x01, // Application
Jean-Philippe Brucker 0:cfd70fa91663 42 USAGE(1), 0x01, // Pointer
Jean-Philippe Brucker 0:cfd70fa91663 43 COLLECTION(1), 0x00, // Physical
Jean-Philippe Brucker 0:cfd70fa91663 44 USAGE_PAGE(1), 0x09, // Buttons
Jean-Philippe Brucker 0:cfd70fa91663 45 USAGE_MINIMUM(1), 0x01,
Jean-Philippe Brucker 0:cfd70fa91663 46 USAGE_MAXIMUM(1), 0x03,
Jean-Philippe Brucker 0:cfd70fa91663 47 LOGICAL_MINIMUM(1), 0x00,
Jean-Philippe Brucker 0:cfd70fa91663 48 LOGICAL_MAXIMUM(1), 0x01,
Jean-Philippe Brucker 0:cfd70fa91663 49 REPORT_COUNT(1), 0x03, // 3 bits (Buttons)
Jean-Philippe Brucker 0:cfd70fa91663 50 REPORT_SIZE(1), 0x01,
Jean-Philippe Brucker 0:cfd70fa91663 51 INPUT(1), 0x02, // Data, Variable, Absolute
Jean-Philippe Brucker 0:cfd70fa91663 52 REPORT_COUNT(1), 0x01, // 5 bits (Padding)
Jean-Philippe Brucker 0:cfd70fa91663 53 REPORT_SIZE(1), 0x05,
Jean-Philippe Brucker 0:cfd70fa91663 54 INPUT(1), 0x01, // Constant
Jean-Philippe Brucker 0:cfd70fa91663 55 USAGE_PAGE(1), 0x01, // Generic Desktop
Jean-Philippe Brucker 0:cfd70fa91663 56 USAGE(1), 0x30, // X
Jean-Philippe Brucker 0:cfd70fa91663 57 USAGE(1), 0x31, // Y
Jean-Philippe Brucker 0:cfd70fa91663 58 USAGE(1), 0x38, // Wheel
Jean-Philippe Brucker 0:cfd70fa91663 59 LOGICAL_MINIMUM(1), 0x81, // -127
Jean-Philippe Brucker 0:cfd70fa91663 60 LOGICAL_MAXIMUM(1), 0x7f, // 127
Jean-Philippe Brucker 0:cfd70fa91663 61 REPORT_SIZE(1), 0x08, // Three bytes
Jean-Philippe Brucker 0:cfd70fa91663 62 REPORT_COUNT(1), 0x03,
Jean-Philippe Brucker 0:cfd70fa91663 63 INPUT(1), 0x06, // Data, Variable, Relative
Jean-Philippe Brucker 0:cfd70fa91663 64 END_COLLECTION(0),
Jean-Philippe Brucker 0:cfd70fa91663 65 END_COLLECTION(0),
Jean-Philippe Brucker 0:cfd70fa91663 66 };
Jean-Philippe Brucker 0:cfd70fa91663 67
Jean-Philippe Brucker 0:cfd70fa91663 68 uint8_t report[] = { 0, 0, 0, 0 };
Jean-Philippe Brucker 0:cfd70fa91663 69
Jean-Philippe Brucker 1:7a6c2e2c9371 70 /**
Jean-Philippe Brucker 1:7a6c2e2c9371 71 * @class MouseService
Jean-Philippe Brucker 1:7a6c2e2c9371 72 * @brief HID-over-Gatt mouse service.
Jean-Philippe Brucker 1:7a6c2e2c9371 73 *
Jean-Philippe Brucker 1:7a6c2e2c9371 74 * Send mouse moves and button informations over BLE.
Jean-Philippe Brucker 1:7a6c2e2c9371 75 *
Jean-Philippe Brucker 1:7a6c2e2c9371 76 * @code
Jean-Philippe Brucker 1:7a6c2e2c9371 77 * BLE ble;
Jean-Philippe Brucker 1:7a6c2e2c9371 78 * MouseService mouse(ble);
Jean-Philippe Brucker 1:7a6c2e2c9371 79 *
Jean-Philippe Brucker 1:7a6c2e2c9371 80 * Timeout timeout;
Jean-Philippe Brucker 1:7a6c2e2c9371 81 *
Jean-Philippe Brucker 1:7a6c2e2c9371 82 * void stop_mouse_move(void)
Jean-Philippe Brucker 1:7a6c2e2c9371 83 * {
Jean-Philippe Brucker 1:7a6c2e2c9371 84 * // Set mouse state to immobile
Jean-Philippe Brucker 1:7a6c2e2c9371 85 * mouse.setButton(MOUSE_BUTTON_LEFT, MOUSE_UP);
Jean-Philippe Brucker 1:7a6c2e2c9371 86 * mouse.setSpeed(0, 0, 0);
Jean-Philippe Brucker 1:7a6c2e2c9371 87 * }
Jean-Philippe Brucker 1:7a6c2e2c9371 88 *
Jean-Philippe Brucker 1:7a6c2e2c9371 89 * void start_mouse_move(void)
Jean-Philippe Brucker 1:7a6c2e2c9371 90 * {
Jean-Philippe Brucker 1:7a6c2e2c9371 91 * // Move left with a left button down. If the focus is on a drawing
Jean-Philippe Brucker 1:7a6c2e2c9371 92 * // software, for instance, this should draw a line.
Jean-Philippe Brucker 1:7a6c2e2c9371 93 * mouse.setButton(MOUSE_BUTTON_LEFT, MOUSE_DOWN);
Jean-Philippe Brucker 1:7a6c2e2c9371 94 * mouse.setSpeed(1, 0, 0);
Jean-Philippe Brucker 1:7a6c2e2c9371 95 *
Jean-Philippe Brucker 1:7a6c2e2c9371 96 * timeout.attach(stop_mouse_move, 0.2);
Jean-Philippe Brucker 1:7a6c2e2c9371 97 * }
Jean-Philippe Brucker 1:7a6c2e2c9371 98 * @endcode
Jean-Philippe Brucker 1:7a6c2e2c9371 99 */
Jean-Philippe Brucker 0:cfd70fa91663 100 class MouseService: public HIDServiceBase
Jean-Philippe Brucker 0:cfd70fa91663 101 {
Jean-Philippe Brucker 0:cfd70fa91663 102 public:
Jean-Philippe Brucker 0:cfd70fa91663 103 MouseService(BLE &_ble) :
Jean-Philippe Brucker 0:cfd70fa91663 104 HIDServiceBase(_ble,
Jean-Philippe Brucker 0:cfd70fa91663 105 MOUSE_REPORT_MAP, sizeof(MOUSE_REPORT_MAP),
Jean-Philippe Brucker 0:cfd70fa91663 106 inputReport = report,
Jean-Philippe Brucker 0:cfd70fa91663 107 outputReport = NULL,
Jean-Philippe Brucker 0:cfd70fa91663 108 featureReport = NULL,
Jean-Philippe Brucker 0:cfd70fa91663 109 inputReportLength = sizeof(inputReport),
Jean-Philippe Brucker 0:cfd70fa91663 110 outputReportLength = 0,
Jean-Philippe Brucker 0:cfd70fa91663 111 featureReportLength = 0,
Jean-Philippe Brucker 0:cfd70fa91663 112 reportTickerDelay = 20),
Jean-Philippe Brucker 0:cfd70fa91663 113 buttonsState (0),
Jean-Philippe Brucker 0:cfd70fa91663 114 failedReports (0)
Jean-Philippe Brucker 0:cfd70fa91663 115 {
Jean-Philippe Brucker 0:cfd70fa91663 116 speed[0] = 0;
Jean-Philippe Brucker 0:cfd70fa91663 117 speed[1] = 0;
Jean-Philippe Brucker 0:cfd70fa91663 118 speed[2] = 0;
Jean-Philippe Brucker 0:cfd70fa91663 119
Jean-Philippe Brucker 0:cfd70fa91663 120 startReportTicker();
Jean-Philippe Brucker 0:cfd70fa91663 121 }
Jean-Philippe Brucker 0:cfd70fa91663 122
Jean-Philippe Brucker 1:7a6c2e2c9371 123 void onConnection(const Gap::ConnectionCallbackParams_t *params)
Jean-Philippe Brucker 1:7a6c2e2c9371 124 {
Jean-Philippe Brucker 1:7a6c2e2c9371 125 HIDServiceBase::onConnection(params);
Jean-Philippe Brucker 1:7a6c2e2c9371 126 startReportTicker();
Jean-Philippe Brucker 1:7a6c2e2c9371 127 }
Jean-Philippe Brucker 1:7a6c2e2c9371 128
Jean-Philippe Brucker 1:7a6c2e2c9371 129 void onDisconnection(const Gap::DisconnectionCallbackParams_t *params)
Jean-Philippe Brucker 1:7a6c2e2c9371 130 {
Jean-Philippe Brucker 1:7a6c2e2c9371 131 stopReportTicker();
Jean-Philippe Brucker 1:7a6c2e2c9371 132 HIDServiceBase::onDisconnection(params);
Jean-Philippe Brucker 1:7a6c2e2c9371 133 }
Jean-Philippe Brucker 1:7a6c2e2c9371 134
Jean-Philippe Brucker 1:7a6c2e2c9371 135 /**
Jean-Philippe Brucker 1:7a6c2e2c9371 136 * Set X, Y, Z speed of the mouse. Parameters are sticky and will be
Jean-Philippe Brucker 1:7a6c2e2c9371 137 * transmitted on every tick. Users should therefore reset them to 0 when
Jean-Philippe Brucker 1:7a6c2e2c9371 138 * the device is immobile.
Jean-Philippe Brucker 1:7a6c2e2c9371 139 *
Jean-Philippe Brucker 1:7a6c2e2c9371 140 * @param x Speed on hoizontal axis
Jean-Philippe Brucker 1:7a6c2e2c9371 141 * @param y Speed on vertical axis
Jean-Philippe Brucker 1:7a6c2e2c9371 142 * @param wheel Scroll speed
Jean-Philippe Brucker 1:7a6c2e2c9371 143 *
Jean-Philippe Brucker 1:7a6c2e2c9371 144 * @returns A status code
Jean-Philippe Brucker 1:7a6c2e2c9371 145 *
Jean-Philippe Brucker 1:7a6c2e2c9371 146 * @note Directions depend on the operating system's configuration. It is
Jean-Philippe Brucker 1:7a6c2e2c9371 147 * customary to increase values on the X axis from left to right, and on the
Jean-Philippe Brucker 1:7a6c2e2c9371 148 * Y axis from top to bottom.
Jean-Philippe Brucker 1:7a6c2e2c9371 149 * Wheel is less standard, although positive values will usually scroll up.
Jean-Philippe Brucker 1:7a6c2e2c9371 150 */
Jean-Philippe Brucker 0:cfd70fa91663 151 int setSpeed(int8_t x, int8_t y, int8_t wheel)
Jean-Philippe Brucker 0:cfd70fa91663 152 {
Jean-Philippe Brucker 0:cfd70fa91663 153 speed[0] = x;
Jean-Philippe Brucker 0:cfd70fa91663 154 speed[1] = y;
Jean-Philippe Brucker 0:cfd70fa91663 155 speed[2] = wheel;
Jean-Philippe Brucker 0:cfd70fa91663 156
Jean-Philippe Brucker 1:7a6c2e2c9371 157 startReportTicker();
Jean-Philippe Brucker 1:7a6c2e2c9371 158
Jean-Philippe Brucker 0:cfd70fa91663 159 return 0;
Jean-Philippe Brucker 0:cfd70fa91663 160 }
Jean-Philippe Brucker 0:cfd70fa91663 161
Jean-Philippe Brucker 1:7a6c2e2c9371 162 /**
Jean-Philippe Brucker 1:7a6c2e2c9371 163 * Toggle the state of one button
Jean-Philippe Brucker 1:7a6c2e2c9371 164 *
Jean-Philippe Brucker 1:7a6c2e2c9371 165 * @returns A status code
Jean-Philippe Brucker 1:7a6c2e2c9371 166 */
Jean-Philippe Brucker 0:cfd70fa91663 167 int setButton(MouseButton button, ButtonState state)
Jean-Philippe Brucker 0:cfd70fa91663 168 {
Jean-Philippe Brucker 0:cfd70fa91663 169 if (state == BUTTON_UP)
Jean-Philippe Brucker 0:cfd70fa91663 170 buttonsState &= ~(button);
Jean-Philippe Brucker 0:cfd70fa91663 171 else
Jean-Philippe Brucker 0:cfd70fa91663 172 buttonsState |= button;
Jean-Philippe Brucker 0:cfd70fa91663 173
Jean-Philippe Brucker 1:7a6c2e2c9371 174 startReportTicker();
Jean-Philippe Brucker 1:7a6c2e2c9371 175
Jean-Philippe Brucker 0:cfd70fa91663 176 return 0;
Jean-Philippe Brucker 0:cfd70fa91663 177 }
Jean-Philippe Brucker 0:cfd70fa91663 178
Jean-Philippe Brucker 1:7a6c2e2c9371 179 /**
Jean-Philippe Brucker 1:7a6c2e2c9371 180 * Called by the report ticker
Jean-Philippe Brucker 1:7a6c2e2c9371 181 */
Jean-Philippe Brucker 0:cfd70fa91663 182 virtual void sendCallback(void) {
Jean-Philippe Brucker 1:7a6c2e2c9371 183 uint8_t buttons = buttonsState & 0x7;
Jean-Philippe Brucker 1:7a6c2e2c9371 184
Jean-Philippe Brucker 0:cfd70fa91663 185 if (!connected)
Jean-Philippe Brucker 0:cfd70fa91663 186 return;
Jean-Philippe Brucker 0:cfd70fa91663 187
Jean-Philippe Brucker 1:7a6c2e2c9371 188 bool can_sleep = (report[0] == 0
Jean-Philippe Brucker 1:7a6c2e2c9371 189 && report[1] == 0
Jean-Philippe Brucker 1:7a6c2e2c9371 190 && report[2] == 0
Jean-Philippe Brucker 1:7a6c2e2c9371 191 && report[3] == 0
Jean-Philippe Brucker 1:7a6c2e2c9371 192 && report[0] == buttons
Jean-Philippe Brucker 1:7a6c2e2c9371 193 && report[1] == speed[0]
Jean-Philippe Brucker 1:7a6c2e2c9371 194 && report[2] == speed[1]
Jean-Philippe Brucker 1:7a6c2e2c9371 195 && report[3] == speed[2]);
Jean-Philippe Brucker 1:7a6c2e2c9371 196
Jean-Philippe Brucker 1:7a6c2e2c9371 197 if (can_sleep) {
Jean-Philippe Brucker 1:7a6c2e2c9371 198 /* TODO: find out why there always is two more calls to sendCallback after this
Jean-Philippe Brucker 1:7a6c2e2c9371 199 * stopReportTicker(). */
Jean-Philippe Brucker 1:7a6c2e2c9371 200 stopReportTicker();
Jean-Philippe Brucker 1:7a6c2e2c9371 201 return;
Jean-Philippe Brucker 1:7a6c2e2c9371 202 }
Jean-Philippe Brucker 1:7a6c2e2c9371 203
Jean-Philippe Brucker 1:7a6c2e2c9371 204 report[0] = buttons;
Jean-Philippe Brucker 0:cfd70fa91663 205 report[1] = speed[0];
Jean-Philippe Brucker 0:cfd70fa91663 206 report[2] = speed[1];
Jean-Philippe Brucker 0:cfd70fa91663 207 report[3] = speed[2];
Jean-Philippe Brucker 0:cfd70fa91663 208
Jean-Philippe Brucker 0:cfd70fa91663 209 if (send(report))
Jean-Philippe Brucker 0:cfd70fa91663 210 failedReports++;
Jean-Philippe Brucker 0:cfd70fa91663 211 }
Jean-Philippe Brucker 0:cfd70fa91663 212
Jean-Philippe Brucker 0:cfd70fa91663 213 protected:
Jean-Philippe Brucker 0:cfd70fa91663 214 uint8_t buttonsState;
Jean-Philippe Brucker 0:cfd70fa91663 215 uint8_t speed[3];
Jean-Philippe Brucker 0:cfd70fa91663 216
Jean-Philippe Brucker 0:cfd70fa91663 217 public:
Jean-Philippe Brucker 0:cfd70fa91663 218 uint32_t failedReports;
Jean-Philippe Brucker 0:cfd70fa91663 219 };