MicroBit as BLE gamepad

Dependencies:   BLE_API mbed-dev-bin nRF51822

Dependents:   microbit

Fork of microbit-dal by Lancaster University

Committer:
rengro01
Date:
Mon Jan 30 08:29:06 2017 +0000
Revision:
75:df904445f561
Parent:
74:1b9850e39cd1
MicroBit as BLE gamepad

Who changed what in which revision?

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