Based on the example USB HID keyboard https://developer.mbed.org/users/jbru/code/BLE_HID_KeyboardStreamDemo/

Dependencies:   BLE_API mbed nRF51822

Fork of HID-kb by Microbug

Committer:
JonnyA
Date:
Wed Nov 14 09:46:45 2018 +0000
Revision:
3:7d7822143a2d
Parent:
0:cb1939018833
Add simple debounce wait on interrupts for buttons

Who changed what in which revision?

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