BLE mouse with uBit ( still some issues to resolve )

Dependencies:   BLE_API microbit_ble_mouse mbed nRF51822

Fork of microbit_mouse_BLE by Shahariar Hossain

Revision:
0:cb1939018833
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/BLE_HID/MouseService.h	Mon Nov 02 18:25:58 2015 +0000
@@ -0,0 +1,220 @@
+/* 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 "mbed.h"
+
+#include "HIDServiceBase.h"
+
+enum ButtonState
+{
+    BUTTON_UP,
+    BUTTON_DOWN
+};
+
+enum MouseButton
+{
+    MOUSE_BUTTON_LEFT    = 0x1,
+    MOUSE_BUTTON_RIGHT   = 0x2,
+    MOUSE_BUTTON_MIDDLE  = 0x4,
+};
+
+/**
+ * Report descriptor for a standard 3 buttons + wheel mouse with relative X/Y
+ * moves
+ */
+report_map_t MOUSE_REPORT_MAP = {
+    USAGE_PAGE(1),      0x01,         // Generic Desktop
+    USAGE(1),           0x02,         // Mouse
+    COLLECTION(1),      0x01,         // Application
+    USAGE(1),           0x01,         //  Pointer
+    COLLECTION(1),      0x00,         //  Physical
+    USAGE_PAGE(1),      0x09,         //   Buttons
+    USAGE_MINIMUM(1),   0x01,
+    USAGE_MAXIMUM(1),   0x03,
+    LOGICAL_MINIMUM(1), 0x00,
+    LOGICAL_MAXIMUM(1), 0x01,
+    REPORT_COUNT(1),    0x03,         //   3 bits (Buttons)
+    REPORT_SIZE(1),     0x01,
+    INPUT(1),           0x02,         //   Data, Variable, Absolute
+    REPORT_COUNT(1),    0x01,         //   5 bits (Padding)
+    REPORT_SIZE(1),     0x05,
+    INPUT(1),           0x01,         //   Constant
+    USAGE_PAGE(1),      0x01,         //   Generic Desktop
+    USAGE(1),           0x30,         //   X
+    USAGE(1),           0x31,         //   Y
+    USAGE(1),           0x38,         //   Wheel
+    LOGICAL_MINIMUM(1), 0x81,         //   -127
+    LOGICAL_MAXIMUM(1), 0x7f,         //   127
+    REPORT_SIZE(1),     0x08,         //   Three bytes
+    REPORT_COUNT(1),    0x03,
+    INPUT(1),           0x06,         //   Data, Variable, Relative
+    END_COLLECTION(0),
+    END_COLLECTION(0),
+};
+
+uint8_t report[] = { 0, 0, 0, 0 };
+
+/**
+ * @class MouseService
+ * @brief HID-over-Gatt mouse service.
+ *
+ * Send mouse moves and button informations over BLE.
+ *
+ * @code
+ * BLE ble;
+ * MouseService mouse(ble);
+ *
+ * Timeout timeout;
+ *
+ * void stop_mouse_move(void)
+ * {
+ *      // Set mouse state to immobile
+ *      mouse.setButton(MOUSE_BUTTON_LEFT, MOUSE_UP);
+ *      mouse.setSpeed(0, 0, 0);
+ * }
+ *
+ * void start_mouse_move(void)
+ * {
+ *      // Move left with a left button down. If the focus is on a drawing
+ *      // software, for instance, this should draw a line.
+ *      mouse.setButton(MOUSE_BUTTON_LEFT, MOUSE_DOWN);
+ *      mouse.setSpeed(1, 0, 0);
+ *
+ *      timeout.attach(stop_mouse_move, 0.2);
+ * }
+ * @endcode
+ */
+class MouseService: public HIDServiceBase
+{
+public:
+    MouseService(BLE &_ble) :
+        HIDServiceBase(_ble,
+                       MOUSE_REPORT_MAP, sizeof(MOUSE_REPORT_MAP),
+                       inputReport          = report,
+                       outputReport         = NULL,
+                       featureReport        = NULL,
+                       inputReportLength    = sizeof(inputReport),
+                       outputReportLength   = 0,
+                       featureReportLength  = 0,
+                       reportTickerDelay    = 20),
+        buttonsState (0),
+        failedReports (0)
+    {
+        speed[0] = 0;
+        speed[1] = 0;
+        speed[2] = 0;
+
+        startReportTicker();
+    }
+
+    void onConnection(const Gap::ConnectionCallbackParams_t *params)
+    {
+        HIDServiceBase::onConnection(params);
+        startReportTicker();
+    }
+
+    void onDisconnection(const Gap::DisconnectionCallbackParams_t *params)
+    {
+        stopReportTicker();
+        HIDServiceBase::onDisconnection(params);
+    }
+
+    /**
+     * Set X, Y, Z speed of the mouse. Parameters are sticky and will be
+     * transmitted on every tick. Users should therefore reset them to 0 when
+     * the device is immobile.
+     *
+     * @param x     Speed on hoizontal axis
+     * @param y     Speed on vertical axis
+     * @param wheel Scroll speed
+     *
+     * @returns A status code
+     *
+     * @note Directions depend on the operating system's configuration. It is
+     * customary to increase values on the X axis from left to right, and on the
+     * Y axis from top to bottom.
+     * Wheel is less standard, although positive values will usually scroll up.
+     */
+    int setSpeed(int8_t x, int8_t y, int8_t wheel)
+    {
+        speed[0] = x;
+        speed[1] = y;
+        speed[2] = wheel;
+
+        startReportTicker();
+
+        return 0;
+    }
+
+    /**
+     * Toggle the state of one button
+     *
+     * @returns A status code
+     */
+    int setButton(MouseButton button, ButtonState state)
+    {
+        if (state == BUTTON_UP)
+            buttonsState &= ~(button);
+        else
+            buttonsState |= button;
+
+        startReportTicker();
+
+        return 0;
+    }
+
+    /**
+     * Called by the report ticker
+     */
+    virtual void sendCallback(void) {
+        uint8_t buttons = buttonsState & 0x7;
+
+        if (!connected)
+            return;
+
+        bool can_sleep = (report[0] == 0
+                       && report[1] == 0
+                       && report[2] == 0
+                       && report[3] == 0
+                       && report[0] == buttons
+                       && report[1] == speed[0]
+                       && report[2] == speed[1]
+                       && report[3] == speed[2]);
+
+        if (can_sleep) {
+            /* TODO: find out why there always is two more calls to sendCallback after this
+             * stopReportTicker(). */
+            stopReportTicker();
+            return;
+        }
+
+        report[0] = buttons;
+        report[1] = speed[0];
+        report[2] = speed[1];
+        report[3] = speed[2];
+
+        if (send(report))
+            failedReports++;
+    }
+
+protected:
+    uint8_t buttonsState;
+    uint8_t speed[3];
+
+public:
+    uint32_t failedReports;
+};
+