Test; try to make a personal repository

Dependencies:   microbit

Files at this revision

API Documentation at this revision

Comitter:
xx316
Date:
Fri May 31 20:53:51 2019 +0000
Parent:
0:0041f35b0c4c
Commit message:
This is the program for bit_board, an accessory developed by a group of Imperial EEE students for MicroBit. This is the first commit to backup the work in May 2019.

Changed in this revision

BLE_HID/HIDDeviceInformationService.h Show annotated file Show diff for this revision Revisions of this file
BLE_HID/HIDServiceBase.cpp Show annotated file Show diff for this revision Revisions of this file
BLE_HID/HIDServiceBase.h Show annotated file Show diff for this revision Revisions of this file
BLE_HID/HID_types.h Show annotated file Show diff for this revision Revisions of this file
BLE_HID/JoystickService.h Show annotated file Show diff for this revision Revisions of this file
BLE_HID/KeyboardService.h Show annotated file Show diff for this revision Revisions of this file
BLE_HID/Keyboard_types.h Show annotated file Show diff for this revision Revisions of this file
BLE_HID/MouseService.h Show annotated file Show diff for this revision Revisions of this file
BLE_HID/examples_common.cpp Show annotated file Show diff for this revision Revisions of this file
BLE_HID/examples_common.h Show annotated file Show diff for this revision Revisions of this file
bit_board.cpp Show annotated file Show diff for this revision Revisions of this file
main.cpp Show diff for this revision Revisions of this file
test.txt Show annotated file Show diff for this revision Revisions of this file
diff -r 0041f35b0c4c -r c840c2b6f490 BLE_HID/HIDDeviceInformationService.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/BLE_HID/HIDDeviceInformationService.h	Fri May 31 20:53:51 2019 +0000
@@ -0,0 +1,144 @@
+/* mbed Microcontroller Library
+ * Copyright (c) 2006-2013 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.
+ */
+
+#ifndef __BLE_HID_DEVICE_INFORMATION_SERVICE_H__
+#define __BLE_HID_DEVICE_INFORMATION_SERVICE_H__
+
+#include "ble/BLE.h"
+
+#include "HID_types.h"
+
+/**
+* @class HIDDeviceInformationService
+* @brief BLE Device Information Service <br>
+* Service: https://developer.bluetooth.org/gatt/services/Pages/ServiceViewer.aspx?u=org.bluetooth.service.device_information.xml <br>
+* Manufacturer Name String Char: https://developer.bluetooth.org/gatt/characteristics/Pages/CharacteristicViewer.aspx?u=org.bluetooth.characteristic.manufacturer_name_string.xml
+*/
+class HIDDeviceInformationService {
+public:
+    /**
+     * @brief Device Information Service Constructor.
+     *
+     * @param[ref] _ble
+     *                BLE object for the underlying controller.
+     * @param[in] manufacturersName
+     *                This characteristic represents the name of the
+     *                manufacturer of the device. The name is copied into the
+     *                BLE stack during this constructor.
+     * @param[in] modelNumber
+     *                This characteristic represents the model number that is
+     *                assigned by the device vendor. The value is copied into
+     *                the BLE stack during this constructor.
+     * @param[in] serialNumber
+     *                This characteristic represents the serial number for a
+     *                particular instance of the device.  The value is copied
+     *                into the BLE stack during this constructor.
+     * @param[in] hardwareRevision
+     *                This characteristic represents the hardware revision for
+     *                the hardware within the device. The value is copied
+     *                into the BLE stack during this constructor.
+     * @param[in] firmwareRevision
+     *                This characteristic represents the firmware revision for
+     *                the firmware within the device. The value is copied
+     *                into the BLE stack during this constructor.
+     * @param[in] softwareRevision
+     *                This characteristic represents the software revision for
+     *                the software within the device. The value is copied
+     *                into the BLE stack during this constructor.
+     * @param[in] pnpID
+     *                This characteristic represents HID-specific information,
+     *                such as vendor id, product id and version.
+     */
+    HIDDeviceInformationService(BLE            &_ble,
+                             const char     *manufacturersName = NULL,
+                             const char     *modelNumber       = NULL,
+                             const char     *serialNumber      = NULL,
+                             const char     *hardwareRevision  = NULL,
+                             const char     *firmwareRevision  = NULL,
+                             const char     *softwareRevision  = NULL,
+                             PnPID_t        *PnPID             = NULL) :
+        ble(_ble),
+        manufacturersNameStringCharacteristic(GattCharacteristic::UUID_MANUFACTURER_NAME_STRING_CHAR,
+                                              (uint8_t *)manufacturersName,
+                                              (manufacturersName != NULL) ? strlen(manufacturersName) : 0, /* minLength */
+                                              (manufacturersName != NULL) ? strlen(manufacturersName) : 0, /* maxLength */
+                                              GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_READ),
+        modelNumberStringCharacteristic(GattCharacteristic::UUID_MODEL_NUMBER_STRING_CHAR,
+                                        (uint8_t *)modelNumber,
+                                        (modelNumber != NULL) ? strlen(modelNumber) : 0, /* minLength */
+                                        (modelNumber != NULL) ? strlen(modelNumber) : 0, /* maxLength */
+                                        GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_READ),
+        serialNumberStringCharacteristic(GattCharacteristic::UUID_SERIAL_NUMBER_STRING_CHAR,
+                                         (uint8_t *)serialNumber,
+                                         (serialNumber != NULL) ? strlen(serialNumber) : 0, /* minLength */
+                                         (serialNumber != NULL) ? strlen(serialNumber) : 0, /* maxLength */
+                                         GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_READ),
+        hardwareRevisionStringCharacteristic(GattCharacteristic::UUID_HARDWARE_REVISION_STRING_CHAR,
+                                             (uint8_t *)hardwareRevision,
+                                             (hardwareRevision != NULL) ? strlen(hardwareRevision) : 0, /* minLength */
+                                             (hardwareRevision != NULL) ? strlen(hardwareRevision) : 0, /* maxLength */
+                                             GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_READ),
+        firmwareRevisionStringCharacteristic(GattCharacteristic::UUID_FIRMWARE_REVISION_STRING_CHAR,
+                                             (uint8_t *)firmwareRevision,
+                                             (firmwareRevision != NULL) ? strlen(firmwareRevision) : 0, /* minLength */
+                                             (firmwareRevision != NULL) ? strlen(firmwareRevision) : 0, /* maxLength */
+                                             GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_READ),
+        softwareRevisionStringCharacteristic(GattCharacteristic::UUID_SOFTWARE_REVISION_STRING_CHAR,
+                                             (uint8_t *)softwareRevision,
+                                             (softwareRevision != NULL) ? strlen(softwareRevision) : 0, /* minLength */
+                                             (softwareRevision != NULL) ? strlen(softwareRevision) : 0, /* maxLength */
+                                             GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_READ),
+        pnpIDCharacteristic(GattCharacteristic::UUID_PNP_ID_CHAR,
+                            PnPID)
+    {
+        static bool serviceAdded = false; /* We should only ever need to add the heart rate service once. */
+        if (serviceAdded) {
+            return;
+        }
+
+        GattCharacteristic *charTable[] = {&manufacturersNameStringCharacteristic,
+                                           &modelNumberStringCharacteristic,
+                                           &serialNumberStringCharacteristic,
+                                           &hardwareRevisionStringCharacteristic,
+                                           &firmwareRevisionStringCharacteristic,
+                                           &softwareRevisionStringCharacteristic,
+                                           &pnpIDCharacteristic};
+        GattService         deviceInformationService(GattService::UUID_DEVICE_INFORMATION_SERVICE, charTable,
+                                                     sizeof(charTable) / sizeof(GattCharacteristic *));
+
+        /*
+         * This is a hack to make things work on MacOSX 10.10. I don't have the details, but MacOSX
+         * 10.10 gets confused when only characteristics from HID Service require security...
+         */
+        pnpIDCharacteristic.requireSecurity(SecurityManager::SECURITY_MODE_ENCRYPTION_NO_MITM);
+        ble.addService(deviceInformationService);
+        serviceAdded = true;
+    }
+
+protected:
+    BLE                 &ble;
+    GattCharacteristic  manufacturersNameStringCharacteristic;
+    GattCharacteristic  modelNumberStringCharacteristic;
+    GattCharacteristic  serialNumberStringCharacteristic;
+    GattCharacteristic  hardwareRevisionStringCharacteristic;
+    GattCharacteristic  firmwareRevisionStringCharacteristic;
+    GattCharacteristic  softwareRevisionStringCharacteristic;
+    ReadOnlyGattCharacteristic<PnPID_t>  pnpIDCharacteristic;
+};
+
+#endif /* #ifndef __BLE_HID_DEVICE_INFORMATION_SERVICE_H__*/
+
+
diff -r 0041f35b0c4c -r c840c2b6f490 BLE_HID/HIDServiceBase.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/BLE_HID/HIDServiceBase.cpp	Fri May 31 20:53:51 2019 +0000
@@ -0,0 +1,230 @@
+/* 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"
+
+HIDServiceBase::HIDServiceBase(BLE          &_ble,
+                               report_map_t reportMap,
+                               uint8_t      reportMapSize,
+                               report_t     inputReport,
+                               report_t     outputReport,
+                               report_t     featureReport,
+                               uint8_t      inputReportLength,
+                               uint8_t      outputReportLength,
+                               uint8_t      featureReportLength,
+                               uint8_t      inputReportTickerDelay) :
+    ble(_ble),
+    connected (false),
+    reportMapLength(reportMapSize),
+
+    inputReport(inputReport),
+    outputReport(outputReport),
+    featureReport(featureReport),
+
+    inputReportLength(inputReportLength),
+    outputReportLength(outputReportLength),
+    featureReportLength(featureReportLength),
+
+    protocolMode(REPORT_PROTOCOL),
+
+    inputReportReferenceDescriptor(BLE_UUID_DESCRIPTOR_REPORT_REFERENCE,
+            (uint8_t *)&inputReportReferenceData, 2, 2),
+    outputReportReferenceDescriptor(BLE_UUID_DESCRIPTOR_REPORT_REFERENCE,
+            (uint8_t *)&outputReportReferenceData, 2, 2),
+    featureReportReferenceDescriptor(BLE_UUID_DESCRIPTOR_REPORT_REFERENCE,
+            (uint8_t *)&featureReportReferenceData, 2, 2),
+
+    protocolModeCharacteristic(GattCharacteristic::UUID_PROTOCOL_MODE_CHAR, &protocolMode, 1, 1,
+              GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_READ
+            | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_WRITE_WITHOUT_RESPONSE),
+
+    inputReportCharacteristic(GattCharacteristic::UUID_REPORT_CHAR,
+            (uint8_t *)inputReport, inputReportLength, inputReportLength,
+              GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_READ
+            | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_NOTIFY
+            | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_WRITE,
+            inputReportDescriptors(), 1),
+
+    outputReportCharacteristic(GattCharacteristic::UUID_REPORT_CHAR,
+            (uint8_t *)outputReport, outputReportLength, outputReportLength,
+              GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_READ
+            | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_WRITE_WITHOUT_RESPONSE
+            | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_WRITE,
+            outputReportDescriptors(), 1),
+
+    featureReportCharacteristic(GattCharacteristic::UUID_REPORT_CHAR,
+            (uint8_t *)featureReport, featureReportLength, featureReportLength,
+              GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_READ
+            | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_WRITE,
+            featureReportDescriptors(), 1),
+
+    /*
+     * We need to set reportMap content as const, in order to let the compiler put it into flash
+     * instead of RAM. The characteristic is read-only so it won't be written, but
+     * GattCharacteristic constructor takes non-const arguments only. Hence the cast.
+     */
+    reportMapCharacteristic(GattCharacteristic::UUID_REPORT_MAP_CHAR,
+            const_cast<uint8_t*>(reportMap), reportMapLength, reportMapLength,
+            GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_READ),
+
+    HIDInformationCharacteristic(GattCharacteristic::UUID_HID_INFORMATION_CHAR, HIDInformation()),
+    HIDControlPointCharacteristic(GattCharacteristic::UUID_HID_CONTROL_POINT_CHAR,
+            &controlPointCommand, 1, 1,
+            GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_WRITE_WITHOUT_RESPONSE),
+
+    reportTickerDelay(inputReportTickerDelay),
+    reportTickerIsActive(false)
+{
+    static GattCharacteristic *characteristics[] = {
+        &HIDInformationCharacteristic,
+        &reportMapCharacteristic,
+        &protocolModeCharacteristic,
+        &HIDControlPointCharacteristic,
+        NULL,
+        NULL,
+        NULL,
+        NULL,
+        NULL
+    };
+
+    unsigned int charIndex = 4;
+    /*
+     * Report characteristics are optional, and depend on the reportMap descriptor
+     * Note: at least one should be present, but we don't check that at the moment.
+     */
+    if (inputReportLength)
+        characteristics[charIndex++] = &inputReportCharacteristic;
+    if (outputReportLength)
+        characteristics[charIndex++] = &outputReportCharacteristic;
+    if (featureReportLength)
+        characteristics[charIndex++] = &featureReportCharacteristic;
+
+    /* TODO: let children add some more characteristics, namely boot keyboard and mouse (They are
+     * mandatory as per HIDS spec.) Ex:
+     *
+     * addExtraCharacteristics(characteristics, int& charIndex);
+     */
+
+    GattService service(GattService::UUID_HUMAN_INTERFACE_DEVICE_SERVICE,
+                        characteristics, charIndex);
+
+    ble.gattServer().addService(service);
+
+    ble.gap().onConnection(this, &HIDServiceBase::onConnection);
+    ble.gap().onDisconnection(this, &HIDServiceBase::onDisconnection);
+
+    ble.gattServer().onDataSent(this, &HIDServiceBase::onDataSent);
+
+    /*
+     * Change preferred connection params, in order to optimize the notification frequency. Most
+     * OSes seem to respect this, even though they are not required to.
+     *
+     * Some OSes don't handle reconnection well, at the moment, so we set the maximum possible
+     * timeout, 32 seconds
+     */
+    uint16_t minInterval = Gap::MSEC_TO_GAP_DURATION_UNITS(reportTickerDelay / 2);
+    if (minInterval < 6)
+        minInterval = 6;
+    uint16_t maxInterval = minInterval * 2;
+    Gap::ConnectionParams_t params = {minInterval, maxInterval, 0, 3200};
+
+    ble.gap().setPreferredConnectionParams(&params);
+
+    SecurityManager::SecurityMode_t securityMode = SecurityManager::SECURITY_MODE_ENCRYPTION_NO_MITM;
+    protocolModeCharacteristic.requireSecurity(securityMode);
+    reportMapCharacteristic.requireSecurity(securityMode);
+    inputReportCharacteristic.requireSecurity(securityMode);
+    outputReportCharacteristic.requireSecurity(securityMode);
+    featureReportCharacteristic.requireSecurity(securityMode);
+}
+
+void HIDServiceBase::startReportTicker(void) {
+    if (reportTickerIsActive)
+        return;
+    reportTicker.attach_us(this, &HIDServiceBase::sendCallback, reportTickerDelay * 1000);
+    reportTickerIsActive = true;
+}
+
+void HIDServiceBase::stopReportTicker(void) {
+    reportTicker.detach();
+    reportTickerIsActive = false;
+}
+
+void HIDServiceBase::onDataSent(unsigned count) {
+    startReportTicker();
+}
+
+GattAttribute** HIDServiceBase::inputReportDescriptors() {
+    inputReportReferenceData.ID = 0;
+    inputReportReferenceData.type = INPUT_REPORT;
+
+    static GattAttribute * descs[] = {
+        &inputReportReferenceDescriptor,
+    };
+    return descs;
+}
+
+GattAttribute** HIDServiceBase::outputReportDescriptors() {
+    outputReportReferenceData.ID = 0;
+    outputReportReferenceData.type = OUTPUT_REPORT;
+
+    static GattAttribute * descs[] = {
+        &outputReportReferenceDescriptor,
+    };
+    return descs;
+}
+
+GattAttribute** HIDServiceBase::featureReportDescriptors() {
+    featureReportReferenceData.ID = 0;
+    featureReportReferenceData.type = FEATURE_REPORT;
+
+    static GattAttribute * descs[] = {
+        &featureReportReferenceDescriptor,
+    };
+    return descs;
+}
+
+
+HID_information_t* HIDServiceBase::HIDInformation() {
+    static HID_information_t info = {HID_VERSION_1_11, 0x00, 0x03};
+    printf("read hid information\n");
+
+    return &info;
+}
+
+ble_error_t HIDServiceBase::send(const report_t report) {
+    return ble.gattServer().write(inputReportCharacteristic.getValueHandle(),
+                                  report,
+                                  inputReportLength);
+}
+
+ble_error_t HIDServiceBase::read(report_t report) {
+    // TODO. For the time being, we'll just have HID input reports...
+    printf("read not implemented\n");
+    return BLE_ERROR_NOT_IMPLEMENTED;
+}
+
+void HIDServiceBase::onConnection(const Gap::ConnectionCallbackParams_t *params)
+{
+    this->connected = true;
+}
+
+void HIDServiceBase::onDisconnection(const Gap::DisconnectionCallbackParams_t *params)
+{
+    this->connected = false;
+}
+
diff -r 0041f35b0c4c -r c840c2b6f490 BLE_HID/HIDServiceBase.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/BLE_HID/HIDServiceBase.h	Fri May 31 20:53:51 2019 +0000
@@ -0,0 +1,200 @@
+/* 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.
+ */
+
+#ifndef HID_SERVICE_BASE_H_
+#define HID_SERVICE_BASE_H_
+
+#include "mbed.h"
+
+#include "ble/BLE.h"
+#include "HID_types.h"
+
+#define BLE_UUID_DESCRIPTOR_REPORT_REFERENCE 0x2908
+
+typedef const uint8_t report_map_t[];
+typedef const uint8_t * report_t;
+
+typedef struct {
+    uint16_t bcdHID;
+    uint8_t  bCountryCode;
+    uint8_t  flags;
+} HID_information_t;
+
+enum ReportType {
+    INPUT_REPORT    = 0x1,
+    OUTPUT_REPORT   = 0x2,
+    FEATURE_REPORT  = 0x3,
+};
+
+enum ProtocolMode {
+    BOOT_PROTOCOL   = 0x0,
+    REPORT_PROTOCOL = 0x1,
+};
+
+typedef struct {
+    uint8_t ID;
+    uint8_t type;
+} report_reference_t;
+
+
+class HIDServiceBase {
+public:
+    /**
+     *  Constructor
+     *
+     *  @param _ble
+     *         BLE object to add this service to
+     *  @param reportMap
+     *         Byte array representing the input/output report formats. In USB HID jargon, it
+     *         is called "HID report descriptor".
+     *  @param reportMapLength 
+     *         Size of the reportMap array
+     *  @param outputReportLength
+     *         Maximum length of a sent report (up to 64 bytes) (default: 64 bytes)
+     *  @param inputReportLength
+     *         Maximum length of a received report (up to 64 bytes) (default: 64 bytes)
+     *  @param inputReportTickerDelay
+     *         Delay between input report notifications, in ms. Acceptable values depend directly on
+     *         GAP's connInterval parameter, so it shouldn't be less than 12ms
+     *         Preferred GAP connection interval is set after this value, in order to send
+     *         notifications as quick as possible: minimum connection interval will be set to
+     *         (inputReportTickerDelay / 2)
+     */
+    HIDServiceBase(BLE &_ble,
+                   report_map_t reportMap,
+                   uint8_t reportMapLength,
+                   report_t inputReport,
+                   report_t outputReport,
+                   report_t featureReport,
+                   uint8_t inputReportLength = 0,
+                   uint8_t outputReportLength = 0,
+                   uint8_t featureReportLength = 0,
+                   uint8_t inputReportTickerDelay = 50);
+
+    /**
+     *  Send Report
+     *
+     *  @param report   Report to send. Must be of size @ref inputReportLength
+     *  @return         The write status
+     *
+     *  @note Don't call send() directly for multiple reports! Use reportTicker for that, in order
+     *  to avoid overloading the BLE stack, and let it handle events between each report.
+     */
+    virtual ble_error_t send(const report_t report);
+
+    /**
+     *  Read Report
+     *
+     *  @param report   Report to fill. Must be of size @ref outputReportLength
+     *  @return         The read status
+     */
+    virtual ble_error_t read(report_t report);
+
+    virtual void onConnection(const Gap::ConnectionCallbackParams_t *params);
+    virtual void onDisconnection(const Gap::DisconnectionCallbackParams_t *params);
+
+    virtual bool isConnected(void)
+    {
+        return connected;
+    }
+
+protected:
+    /**
+     * Called by BLE API when data has been successfully sent.
+     *
+     * @param count     Number of reports sent
+     *
+     * @note Subclasses can override this to avoid starting the report ticker when there is nothing
+     * to send
+     */
+    virtual void onDataSent(unsigned count);
+
+    /**
+     * Start the ticker that sends input reports at regular interval
+     *
+     * @note reportTickerIsActive describes the state of the ticker and can be used by HIDS
+     * implementations.
+     */
+    virtual void startReportTicker(void);
+
+    /**
+     * Stop the input report ticker
+     */
+    virtual void stopReportTicker(void);
+
+    /**
+     * Called by input report ticker at regular interval (reportTickerDelay). This must be
+     * overriden by HIDS implementations to call the @ref send() with a report, if necessary.
+     */
+    virtual void sendCallback(void) = 0;
+
+    /**
+     * Create the Gatt descriptor for a report characteristic
+     */
+    GattAttribute** inputReportDescriptors();
+    GattAttribute** outputReportDescriptors();
+    GattAttribute** featureReportDescriptors();
+
+    /**
+     * Create the HID information structure
+     */
+    HID_information_t* HIDInformation();
+
+protected:
+    BLE &ble;
+    bool connected;
+
+    int reportMapLength;
+
+    report_t inputReport;
+    report_t outputReport;
+    report_t featureReport;
+
+    uint8_t inputReportLength;
+    uint8_t outputReportLength;
+    uint8_t featureReportLength;
+
+    uint8_t controlPointCommand;
+    uint8_t protocolMode;
+
+    report_reference_t inputReportReferenceData;
+    report_reference_t outputReportReferenceData;
+    report_reference_t featureReportReferenceData;
+
+    GattAttribute inputReportReferenceDescriptor;
+    GattAttribute outputReportReferenceDescriptor;
+    GattAttribute featureReportReferenceDescriptor;
+
+    // Optional gatt characteristics:
+    GattCharacteristic protocolModeCharacteristic;
+
+    // Report characteristics (each sort of optional)
+    GattCharacteristic inputReportCharacteristic;
+    GattCharacteristic outputReportCharacteristic;
+    GattCharacteristic featureReportCharacteristic;
+
+    // Required gatt characteristics: Report Map, Information, Control Point
+    GattCharacteristic reportMapCharacteristic;
+    ReadOnlyGattCharacteristic<HID_information_t> HIDInformationCharacteristic;
+    GattCharacteristic HIDControlPointCharacteristic;
+
+    Ticker reportTicker;
+    uint32_t reportTickerDelay;
+    bool reportTickerIsActive;
+};
+
+#endif /* !HID_SERVICE_BASE_H_ */
+
diff -r 0041f35b0c4c -r c840c2b6f490 BLE_HID/HID_types.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/BLE_HID/HID_types.h	Fri May 31 20:53:51 2019 +0000
@@ -0,0 +1,104 @@
+/* Copyright (c) 2015 mbed.org, MIT License
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this software
+ * and associated documentation files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or
+ * substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
+ * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Note: this file was pulled from the USBHID library, in mbed SDK
+ */
+
+#ifndef USBCLASS_HID_TYPES
+#define USBCLASS_HID_TYPES
+
+#include <stdint.h>
+
+#pragma pack(push, 1)
+typedef struct {
+    uint8_t vendorID_source;
+    uint16_t vendorID;
+    uint16_t productID;
+    uint16_t productVersion;
+} PnPID_t;
+#pragma pack(pop)
+
+/* */
+#define HID_VERSION_1_11    (0x0111)
+
+/* HID Class */
+#define HID_CLASS           (3)
+#define HID_SUBCLASS_NONE   (0)
+#define HID_PROTOCOL_NONE   (0)
+
+/* Descriptors */
+#define HID_DESCRIPTOR          (33)
+#define HID_DESCRIPTOR_LENGTH   (0x09)
+#define REPORT_DESCRIPTOR       (34)
+
+/* Class requests */
+#define GET_REPORT (0x1)
+#define GET_IDLE   (0x2)
+#define SET_REPORT (0x9)
+#define SET_IDLE   (0xa)
+
+/* HID Class Report Descriptor */
+/* Short items: size is 0, 1, 2 or 3 specifying 0, 1, 2 or 4 (four) bytes */
+/* of data as per HID Class standard */
+
+/* Main items */
+#define INPUT(size)             (0x80 | size)
+#define OUTPUT(size)            (0x90 | size)
+#define FEATURE(size)           (0xb0 | size)
+#define COLLECTION(size)        (0xa0 | size)
+#define END_COLLECTION(size)    (0xc0 | size)
+
+/* Global items */
+#define USAGE_PAGE(size)        (0x04 | size)
+#define LOGICAL_MINIMUM(size)   (0x14 | size)
+#define LOGICAL_MAXIMUM(size)   (0x24 | size)
+#define PHYSICAL_MINIMUM(size)  (0x34 | size)
+#define PHYSICAL_MAXIMUM(size)  (0x44 | size)
+#define UNIT_EXPONENT(size)     (0x54 | size)
+#define UNIT(size)              (0x64 | size)
+#define REPORT_SIZE(size)       (0x74 | size)
+#define REPORT_ID(size)         (0x84 | size)
+#define REPORT_COUNT(size)      (0x94 | size)
+#define PUSH(size)              (0xa4 | size)
+#define POP(size)               (0xb4 | size)
+
+/* Local items */
+#define USAGE(size)                 (0x08 | size)
+#define USAGE_MINIMUM(size)         (0x18 | size)
+#define USAGE_MAXIMUM(size)         (0x28 | size)
+#define DESIGNATOR_INDEX(size)      (0x38 | size)
+#define DESIGNATOR_MINIMUM(size)    (0x48 | size)
+#define DESIGNATOR_MAXIMUM(size)    (0x58 | size)
+#define STRING_INDEX(size)          (0x78 | size)
+#define STRING_MINIMUM(size)        (0x88 | size)
+#define STRING_MAXIMUM(size)        (0x98 | size)
+#define DELIMITER(size)             (0xa8 | size)
+
+/* HID Report */
+/* Where report IDs are used the first byte of 'data' will be the */
+/* report ID and 'length' will include this report ID byte. */
+
+#define MAX_HID_REPORT_SIZE (64)
+
+typedef struct {
+    uint32_t length;
+    uint8_t data[MAX_HID_REPORT_SIZE];
+} HID_REPORT;
+
+#endif
+
+
diff -r 0041f35b0c4c -r c840c2b6f490 BLE_HID/JoystickService.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/BLE_HID/JoystickService.h	Fri May 31 20:53:51 2019 +0000
@@ -0,0 +1,129 @@
+/* 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 JoystickButton
+{
+    JOYSTICK_BUTTON_1       = 0x1,
+    JOYSTICK_BUTTON_2       = 0x2,
+};
+
+report_map_t JOYSTICK_REPORT_MAP = {
+    USAGE_PAGE(1),      0x01,         // Generic Desktop
+    USAGE(1),           0x04,         // Joystick
+    COLLECTION(1),      0x01,         // Application
+    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,         //   2 bits (Buttons)
+    REPORT_SIZE(1),     0x01,
+    INPUT(1),           0x02,         //   Data, Variable, Absolute
+    REPORT_COUNT(1),    0x01,         //   6 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),           0x32,         //   Z
+    USAGE(1),           0x33,         //   Rx
+    LOGICAL_MINIMUM(1), 0x81,         //   -127
+    LOGICAL_MAXIMUM(1), 0x7f,         //   127
+    REPORT_SIZE(1),     0x08,         //   Three bytes
+    REPORT_COUNT(1),    0x04,
+    INPUT(1),           0x02,         //   Data, Variable, Absolute (unlike mouse)
+    END_COLLECTION(0),
+    END_COLLECTION(0),
+};
+
+uint8_t report[] = { 0, 0, 0, 0, 0 };
+
+class JoystickService: public HIDServiceBase
+{
+public:
+    JoystickService(BLE &_ble) :
+        HIDServiceBase(_ble,
+                       JOYSTICK_REPORT_MAP, sizeof(JOYSTICK_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;
+        speed[3] = 0;
+
+        startReportTicker();
+    }
+
+    int setSpeed(int8_t x, int8_t y, int8_t z)
+    {
+        speed[0] = x;
+        speed[1] = y;
+        speed[2] = z;
+
+        return 0;
+    }
+
+    int setButton(JoystickButton button, ButtonState state)
+    {
+        if (state == BUTTON_UP)
+            buttonsState &= ~(button);
+        else
+            buttonsState |= button;
+
+        return 0;
+    }
+
+    virtual void sendCallback(void) {
+        if (!connected)
+            return;
+
+        report[0] = buttonsState & 0x7;
+        report[1] = speed[0];
+        report[2] = speed[1];
+        report[3] = speed[2];
+        report[4] = speed[3];
+
+        if (send(report))
+            failedReports++;
+    }
+
+protected:
+    uint8_t buttonsState;
+    uint8_t speed[4];
+
+public:
+    uint32_t failedReports;
+};
+
diff -r 0041f35b0c4c -r c840c2b6f490 BLE_HID/KeyboardService.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/BLE_HID/KeyboardService.h	Fri May 31 20:53:51 2019 +0000
@@ -0,0 +1,367 @@
+/* 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"
+
+#include "HIDServiceBase.h"
+#include "Keyboard_types.h"
+
+/* TODO: make this easier to configure by application (e.g. as a template parameter for
+ * KeyboardService) */
+#ifndef KEYBUFFER_SIZE
+#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
+    COLLECTION(1),      0x01,       // Application
+    USAGE_PAGE(1),      0x07,       //   Kbrd/Keypad
+    USAGE_MINIMUM(1),   0xE0,
+    USAGE_MAXIMUM(1),   0xE7,
+    LOGICAL_MINIMUM(1), 0x00,
+    LOGICAL_MAXIMUM(1), 0x01,
+    REPORT_SIZE(1),     0x01,       //   1 byte (Modifier)
+    REPORT_COUNT(1),    0x08,
+    INPUT(1),           0x02,       //   Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position
+    REPORT_COUNT(1),    0x01,       //   1 byte (Reserved)
+    REPORT_SIZE(1),     0x08,
+    INPUT(1),           0x01,       //   Const,Array,Abs,No Wrap,Linear,Preferred State,No Null Position
+    REPORT_COUNT(1),    0x05,       //   5 bits (Num lock, Caps lock, Scroll lock, Compose, Kana)
+    REPORT_SIZE(1),     0x01,
+    USAGE_PAGE(1),      0x08,       //   LEDs
+    USAGE_MINIMUM(1),   0x01,       //   Num Lock
+    USAGE_MAXIMUM(1),   0x05,       //   Kana
+    OUTPUT(1),          0x02,       //   Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile
+    REPORT_COUNT(1),    0x01,       //   3 bits (Padding)
+    REPORT_SIZE(1),     0x03,
+    OUTPUT(1),          0x01,       //   Const,Array,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile
+    REPORT_COUNT(1),    0x06,       //   6 bytes (Keys)
+    REPORT_SIZE(1),     0x08,
+    LOGICAL_MINIMUM(1), 0x00,
+    LOGICAL_MAXIMUM(1), 0x65,       //   101 keys
+    USAGE_PAGE(1),      0x07,       //   Kbrd/Keypad
+    USAGE_MINIMUM(1),   0x00,
+    USAGE_MAXIMUM(1),   0x65,
+    INPUT(1),           0x00,       //   Data,Array,Abs,No Wrap,Linear,Preferred State,No Null Position
+    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
+ *
+ * Buffer used to store keys to send.
+ * Internally, it is a CircularBuffer, with the added capability of putting the last char back in,
+ * when we're unable to send it (ie. when BLE stack is busy)
+ */
+class KeyBuffer: public CircularBuffer<uint8_t, KEYBUFFER_SIZE>
+{
+public:
+    KeyBuffer() :
+        CircularBuffer(),
+        dataIsPending (false),
+        keyUpIsPending (false)
+    {
+    }
+
+    /**
+     * Mark a character as pending. When a freshly popped character cannot be sent, because the
+     * underlying stack is busy, we set it as pending, and it will get popped in priority by @ref
+     * getPending once reports can be sent again.
+     *
+     * @param data  The character to send in priority. The second keyUp report is implied.
+     */
+    void setPending(uint8_t data)
+    {
+        MBED_ASSERT(dataIsPending == false);
+
+        dataIsPending = true;
+        pendingData = data;
+        keyUpIsPending = true;
+    }
+
+    /**
+     * Get pending char. Either from the high priority buffer (set with setPending), or from the
+     * circular buffer.
+     *
+     * @param   data Filled with the pending data, when present
+     * @return  true if data was filled
+     */
+    bool getPending(uint8_t &data)
+    {
+        if (dataIsPending) {
+            dataIsPending = false;
+            data = pendingData;
+            return true;
+        }
+
+        return pop(data);
+    }
+
+    bool isSomethingPending(void)
+    {
+        return dataIsPending || keyUpIsPending || !empty();
+    }
+
+    /**
+     * Signal that a keyUp report is pending. This means that a character has successfully been
+     * sent, but the subsequent keyUp report failed. This report is of highest priority than the
+     * next character.
+     */
+    void setKeyUpPending(void)
+    {
+        keyUpIsPending = true;
+    }
+
+    /**
+     * Signal that no high-priority report is pending anymore, we can go back to the normal queue.
+     */
+    void clearKeyUpPending(void)
+    {
+        keyUpIsPending = false;
+    }
+
+    bool isKeyUpPending(void)
+    {
+        return keyUpIsPending;
+    }
+
+protected:
+    bool dataIsPending;
+    uint8_t pendingData;
+    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:
+    KeyboardService(BLE &_ble) :
+        HIDServiceBase(_ble,
+                KEYBOARD_REPORT_MAP, sizeof(KEYBOARD_REPORT_MAP),
+                inputReport         = emptyInputReportData,
+                outputReport        = outputReportData,
+                featureReport       = NULL,
+                inputReportLength   = sizeof(inputReportData),
+                outputReportLength  = sizeof(outputReportData),
+                featureReportLength = 0,
+                reportTickerDelay   = 24),
+        failedReports(0)
+    {
+    }
+
+    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;
+        ble_error_t ret = HIDServiceBase::send(report);
+
+        /*
+         * Wait until a buffer is available (onDataSent)
+         * TODO. This won't work, because BUSY error is not only returned when we're short of
+         * notification buffers, but in other cases as well (e.g. when disconnected). We need to
+         * find a reliable way of knowing when we actually need to wait for onDataSent to be called.
+        if (ret == BLE_STACK_BUSY)
+            stopReportTicker();
+         */
+        if (ret == BLE_STACK_BUSY)
+            consecutiveFailures++;
+        else
+            consecutiveFailures = 0;
+
+        if (consecutiveFailures > 20) {
+            /*
+             * 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.
+             */
+            stopReportTicker();
+            consecutiveFailures = 0;
+        }
+
+        return ret;
+    }
+
+    /**
+     * Send an empty report, representing keyUp event
+     */
+    ble_error_t keyUpCode(void)
+    {
+        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;
+        inputReportData[2] = keymap[key].usage;
+
+        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;
+        }
+
+        keyBuffer.push((unsigned char)c);
+
+        if (!reportTickerIsActive)
+            startReportTicker();
+
+        return 0;
+    }
+
+    uint8_t lockStatus() {
+        // TODO: implement numlock/capslock/scrolllock
+        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;
+
+        if (!keyBuffer.isSomethingPending()) {
+            /* Stop until the next call to putc */
+            stopReportTicker();
+            return;
+        }
+
+        if (!keyBuffer.isKeyUpPending()) {
+            bool hasData = keyBuffer.getPending(c);
+
+            /*
+             * If something is pending and is not a keyUp, getPending *must* return something. The
+             * following is only a sanity check.
+             */
+            MBED_ASSERT(hasData);
+
+            if (hasData) {
+                ret = keyDownCode(c, keymap[c].modifier);
+                if (ret) {
+                    keyBuffer.setPending(c);
+                    failedReports++;
+                    return;
+                }
+            }
+        }
+
+        ret = keyUpCode();
+        if (ret) {
+            keyBuffer.setKeyUpPending();
+            failedReports++;
+        } else {
+            keyBuffer.clearKeyUpPending();
+        }
+    }
+
+    /**
+     * 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())
+            startReportTicker();
+    }
+
+    unsigned long failedReports;
+
+protected:
+    virtual int _getc() {
+        return 0;
+    }
+
+protected:
+    KeyBuffer keyBuffer;
+
+    //GattCharacteristic boot_keyboard_input_report;
+    //GattCharacteristic boot_keyboard_output_report;
+};
+
+
diff -r 0041f35b0c4c -r c840c2b6f490 BLE_HID/Keyboard_types.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/BLE_HID/Keyboard_types.h	Fri May 31 20:53:51 2019 +0000
@@ -0,0 +1,404 @@
+/* Copyright (c) 2015 mbed.org, MIT License
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this software
+ * and associated documentation files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or
+ * substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
+ * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Note: this file was pulled from different parts of the USBHID library, in mbed SDK
+ */
+
+#ifndef KEYBOARD_DEFS_H
+#define KEYBOARD_DEFS_H
+
+#define REPORT_ID_KEYBOARD 1
+#define REPORT_ID_VOLUME   3
+ 
+/* Modifiers */
+enum MODIFIER_KEY {
+    KEY_CTRL = 1,
+    KEY_SHIFT = 2,
+    KEY_ALT = 4,
+};
+ 
+ 
+enum MEDIA_KEY {
+    KEY_NEXT_TRACK,     /*!< next Track Button */
+    KEY_PREVIOUS_TRACK, /*!< Previous track Button */
+    KEY_STOP,           /*!< Stop Button */
+    KEY_PLAY_PAUSE,     /*!< Play/Pause Button */
+    KEY_MUTE,           /*!< Mute Button */
+    KEY_VOLUME_UP,      /*!< Volume Up Button */
+    KEY_VOLUME_DOWN,    /*!< Volume Down Button */
+};
+ 
+enum FUNCTION_KEY {
+    KEY_F1 = 128,   /* F1 key */
+    KEY_F2,         /* F2 key */
+    KEY_F3,         /* F3 key */
+    KEY_F4,         /* F4 key */
+    KEY_F5,         /* F5 key */
+    KEY_F6,         /* F6 key */
+    KEY_F7,         /* F7 key */
+    KEY_F8,         /* F8 key */
+    KEY_F9,         /* F9 key */
+    KEY_F10,        /* F10 key */
+    KEY_F11,        /* F11 key */
+    KEY_F12,        /* F12 key */
+ 
+    KEY_PRINT_SCREEN,   /* Print Screen key */
+    KEY_SCROLL_LOCK,    /* Scroll lock */
+    KEY_CAPS_LOCK,      /* caps lock */
+    KEY_NUM_LOCK,       /* num lock */
+    KEY_INSERT,         /* Insert key */
+    KEY_HOME,           /* Home key */
+    KEY_PAGE_UP,        /* Page Up key */
+    KEY_PAGE_DOWN,      /* Page Down key */
+ 
+    RIGHT_ARROW,        /* Right arrow */
+    LEFT_ARROW,         /* Left arrow */
+    DOWN_ARROW,         /* Down arrow */
+    UP_ARROW,           /* Up arrow */
+};
+ 
+typedef struct {
+    unsigned char usage;
+    unsigned char modifier;
+} KEYMAP;
+ 
+#ifdef US_KEYBOARD
+/* US keyboard (as HID standard) */
+#define KEYMAP_SIZE (152)
+const KEYMAP keymap[KEYMAP_SIZE] = {
+    {0, 0},             /* NUL */
+    {0, 0},             /* SOH */
+    {0, 0},             /* STX */
+    {0, 0},             /* ETX */
+    {0, 0},             /* EOT */
+    {0, 0},             /* ENQ */
+    {0, 0},             /* ACK */
+    {0, 0},             /* BEL */
+    {0x2a, 0},          /* BS  */  /* Keyboard Delete (Backspace) */
+    {0x2b, 0},          /* TAB */  /* Keyboard Tab */
+    {0x28, 0},          /* LF  */  /* Keyboard Return (Enter) */
+    {0, 0},             /* VT  */
+    {0, 0},             /* FF  */
+    {0, 0},             /* CR  */
+    {0, 0},             /* SO  */
+    {0, 0},             /* SI  */
+    {0, 0},             /* DEL */
+    {0, 0},             /* DC1 */
+    {0, 0},             /* DC2 */
+    {0, 0},             /* DC3 */
+    {0, 0},             /* DC4 */
+    {0, 0},             /* NAK */
+    {0, 0},             /* SYN */
+    {0, 0},             /* ETB */
+    {0, 0},             /* CAN */
+    {0, 0},             /* EM  */
+    {0, 0},             /* SUB */
+    {0, 0},             /* ESC */
+    {0, 0},             /* FS  */
+    {0, 0},             /* GS  */
+    {0, 0},             /* RS  */
+    {0, 0},             /* US  */
+    {0x2c, 0},          /*   */
+    {0x1e, KEY_SHIFT},      /* ! */
+    {0x34, KEY_SHIFT},      /* " */
+    {0x20, KEY_SHIFT},      /* # */
+    {0x21, KEY_SHIFT},      /* $ */
+    {0x22, KEY_SHIFT},      /* % */
+    {0x24, KEY_SHIFT},      /* & */
+    {0x34, 0},          /* ' */
+    {0x26, KEY_SHIFT},      /* ( */
+    {0x27, KEY_SHIFT},      /* ) */
+    {0x25, KEY_SHIFT},      /* * */
+    {0x2e, KEY_SHIFT},      /* + */
+    {0x36, 0},          /* , */
+    {0x2d, 0},          /* - */
+    {0x37, 0},          /* . */
+    {0x38, 0},          /* / */
+    {0x27, 0},          /* 0 */
+    {0x1e, 0},          /* 1 */
+    {0x1f, 0},          /* 2 */
+    {0x20, 0},          /* 3 */
+    {0x21, 0},          /* 4 */
+    {0x22, 0},          /* 5 */
+    {0x23, 0},          /* 6 */
+    {0x24, 0},          /* 7 */
+    {0x25, 0},          /* 8 */
+    {0x26, 0},          /* 9 */
+    {0x33, KEY_SHIFT},      /* : */
+    {0x33, 0},          /* ; */
+    {0x36, KEY_SHIFT},      /* < */
+    {0x2e, 0},          /* = */
+    {0x37, KEY_SHIFT},      /* > */
+    {0x38, KEY_SHIFT},      /* ? */
+    {0x1f, KEY_SHIFT},      /* @ */
+    {0x04, KEY_SHIFT},      /* A */
+    {0x05, KEY_SHIFT},      /* B */
+    {0x06, KEY_SHIFT},      /* C */
+    {0x07, KEY_SHIFT},      /* D */
+    {0x08, KEY_SHIFT},      /* E */
+    {0x09, KEY_SHIFT},      /* F */
+    {0x0a, KEY_SHIFT},      /* G */
+    {0x0b, KEY_SHIFT},      /* H */
+    {0x0c, KEY_SHIFT},      /* I */
+    {0x0d, KEY_SHIFT},      /* J */
+    {0x0e, KEY_SHIFT},      /* K */
+    {0x0f, KEY_SHIFT},      /* L */
+    {0x10, KEY_SHIFT},      /* M */
+    {0x11, KEY_SHIFT},      /* N */
+    {0x12, KEY_SHIFT},      /* O */
+    {0x13, KEY_SHIFT},      /* P */
+    {0x14, KEY_SHIFT},      /* Q */
+    {0x15, KEY_SHIFT},      /* R */
+    {0x16, KEY_SHIFT},      /* S */
+    {0x17, KEY_SHIFT},      /* T */
+    {0x18, KEY_SHIFT},      /* U */
+    {0x19, KEY_SHIFT},      /* V */
+    {0x1a, KEY_SHIFT},      /* W */
+    {0x1b, KEY_SHIFT},      /* X */
+    {0x1c, KEY_SHIFT},      /* Y */
+    {0x1d, KEY_SHIFT},      /* Z */
+    {0x2f, 0},          /* [ */
+    {0x31, 0},          /* \ */
+    {0x30, 0},          /* ] */
+    {0x23, KEY_SHIFT},      /* ^ */
+    {0x2d, KEY_SHIFT},      /* _ */
+    {0x35, 0},          /* ` */
+    {0x04, 0},          /* a */
+    {0x05, 0},          /* b */
+    {0x06, 0},          /* c */
+    {0x07, 0},          /* d */
+    {0x08, 0},          /* e */
+    {0x09, 0},          /* f */
+    {0x0a, 0},          /* g */
+    {0x0b, 0},          /* h */
+    {0x0c, 0},          /* i */
+    {0x0d, 0},          /* j */
+    {0x0e, 0},          /* k */
+    {0x0f, 0},          /* l */
+    {0x10, 0},          /* m */
+    {0x11, 0},          /* n */
+    {0x12, 0},          /* o */
+    {0x13, 0},          /* p */
+    {0x14, 0},          /* q */
+    {0x15, 0},          /* r */
+    {0x16, 0},          /* s */
+    {0x17, 0},          /* t */
+    {0x18, 0},          /* u */
+    {0x19, 0},          /* v */
+    {0x1a, 0},          /* w */
+    {0x1b, 0},          /* x */
+    {0x1c, 0},          /* y */
+    {0x1d, 0},          /* z */
+    {0x2f, KEY_SHIFT},      /* { */
+    {0x31, KEY_SHIFT},      /* | */
+    {0x30, KEY_SHIFT},      /* } */
+    {0x35, KEY_SHIFT},      /* ~ */
+    {0,0},              /* DEL */
+ 
+    {0x3a, 0},          /* F1 */
+    {0x3b, 0},          /* F2 */
+    {0x3c, 0},          /* F3 */
+    {0x3d, 0},          /* F4 */
+    {0x3e, 0},          /* F5 */
+    {0x3f, 0},          /* F6 */
+    {0x40, 0},          /* F7 */
+    {0x41, 0},          /* F8 */
+    {0x42, 0},          /* F9 */
+    {0x43, 0},          /* F10 */
+    {0x44, 0},          /* F11 */
+    {0x45, 0},          /* F12 */
+ 
+    {0x46, 0},          /* PRINT_SCREEN */
+    {0x47, 0},          /* SCROLL_LOCK */
+    {0x39, 0},          /* CAPS_LOCK */
+    {0x53, 0},          /* NUM_LOCK */
+    {0x49, 0},          /* INSERT */
+    {0x4a, 0},          /* HOME */
+    {0x4b, 0},          /* PAGE_UP */
+    {0x4e, 0},          /* PAGE_DOWN */
+ 
+    {0x4f, 0},          /* RIGHT_ARROW */
+    {0x50, 0},          /* LEFT_ARROW */
+    {0x51, 0},          /* DOWN_ARROW */
+    {0x52, 0},          /* UP_ARROW */
+};
+ 
+#else
+/* UK keyboard */
+#define KEYMAP_SIZE (152)
+const KEYMAP keymap[KEYMAP_SIZE] = {
+    {0, 0},             /* NUL */
+    {0, 0},             /* SOH */
+    {0, 0},             /* STX */
+    {0, 0},             /* ETX */
+    {0, 0},             /* EOT */
+    {0, 0},             /* ENQ */
+    {0, 0},             /* ACK */
+    {0, 0},             /* BEL */
+    {0x2a, 0},          /* BS  */  /* Keyboard Delete (Backspace) */
+    {0x2b, 0},          /* TAB */  /* Keyboard Tab */
+    {0x28, 0},          /* LF  */  /* Keyboard Return (Enter) */
+    {0, 0},             /* VT  */
+    {0, 0},             /* FF  */
+    {0, 0},             /* CR  */
+    {0, 0},             /* SO  */
+    {0, 0},             /* SI  */
+    {0, 0},             /* DEL */
+    {0, 0},             /* DC1 */
+    {0, 0},             /* DC2 */
+    {0, 0},             /* DC3 */
+    {0, 0},             /* DC4 */
+    {0, 0},             /* NAK */
+    {0, 0},             /* SYN */
+    {0, 0},             /* ETB */
+    {0, 0},             /* CAN */
+    {0, 0},             /* EM  */
+    {0, 0},             /* SUB */
+    {0, 0},             /* ESC */
+    {0, 0},             /* FS  */
+    {0, 0},             /* GS  */
+    {0, 0},             /* RS  */
+    {0, 0},             /* US  */
+    {0x2c, 0},          /*   */
+    {0x1e, KEY_SHIFT},      /* ! */
+    {0x1f, KEY_SHIFT},      /* " */
+    {0x32, 0},          /* # */
+    {0x21, KEY_SHIFT},      /* $ */
+    {0x22, KEY_SHIFT},      /* % */
+    {0x24, KEY_SHIFT},      /* & */
+    {0x34, 0},          /* ' */
+    {0x26, KEY_SHIFT},      /* ( */
+    {0x27, KEY_SHIFT},      /* ) */
+    {0x25, KEY_SHIFT},      /* * */
+    {0x2e, KEY_SHIFT},      /* + */
+    {0x36, 0},          /* , */
+    {0x2d, 0},          /* - */
+    {0x37, 0},          /* . */
+    {0x38, 0},          /* / */
+    {0x27, 0},          /* 0 */
+    {0x1e, 0},          /* 1 */
+    {0x1f, 0},          /* 2 */
+    {0x20, 0},          /* 3 */
+    {0x21, 0},          /* 4 */
+    {0x22, 0},          /* 5 */
+    {0x23, 0},          /* 6 */
+    {0x24, 0},          /* 7 */
+    {0x25, 0},          /* 8 */
+    {0x26, 0},          /* 9 */
+    {0x33, KEY_SHIFT},      /* : */
+    {0x33, 0},          /* ; */
+    {0x36, KEY_SHIFT},      /* < */
+    {0x2e, 0},          /* = */
+    {0x37, KEY_SHIFT},      /* > */
+    {0x38, KEY_SHIFT},      /* ? */
+    {0x34, KEY_SHIFT},      /* @ */
+    {0x04, KEY_SHIFT},      /* A */
+    {0x05, KEY_SHIFT},      /* B */
+    {0x06, KEY_SHIFT},      /* C */
+    {0x07, KEY_SHIFT},      /* D */
+    {0x08, KEY_SHIFT},      /* E */
+    {0x09, KEY_SHIFT},      /* F */
+    {0x0a, KEY_SHIFT},      /* G */
+    {0x0b, KEY_SHIFT},      /* H */
+    {0x0c, KEY_SHIFT},      /* I */
+    {0x0d, KEY_SHIFT},      /* J */
+    {0x0e, KEY_SHIFT},      /* K */
+    {0x0f, KEY_SHIFT},      /* L */
+    {0x10, KEY_SHIFT},      /* M */
+    {0x11, KEY_SHIFT},      /* N */
+    {0x12, KEY_SHIFT},      /* O */
+    {0x13, KEY_SHIFT},      /* P */
+    {0x14, KEY_SHIFT},      /* Q */
+    {0x15, KEY_SHIFT},      /* R */
+    {0x16, KEY_SHIFT},      /* S */
+    {0x17, KEY_SHIFT},      /* T */
+    {0x18, KEY_SHIFT},      /* U */
+    {0x19, KEY_SHIFT},      /* V */
+    {0x1a, KEY_SHIFT},      /* W */
+    {0x1b, KEY_SHIFT},      /* X */
+    {0x1c, KEY_SHIFT},      /* Y */
+    {0x1d, KEY_SHIFT},      /* Z */
+    {0x2f, 0},          /* [ */
+    {0x64, 0},          /* \ */
+    {0x30, 0},          /* ] */
+    {0x23, KEY_SHIFT},      /* ^ */
+    {0x2d, KEY_SHIFT},      /* _ */
+    {0x35, 0},          /* ` */
+    {0x04, 0},          /* a */
+    {0x05, 0},          /* b */
+    {0x06, 0},          /* c */
+    {0x07, 0},          /* d */
+    {0x08, 0},          /* e */
+    {0x09, 0},          /* f */
+    {0x0a, 0},          /* g */
+    {0x0b, 0},          /* h */
+    {0x0c, 0},          /* i */
+    {0x0d, 0},          /* j */
+    {0x0e, 0},          /* k */
+    {0x0f, 0},          /* l */
+    {0x10, 0},          /* m */
+    {0x11, 0},          /* n */
+    {0x12, 0},          /* o */
+    {0x13, 0},          /* p */
+    {0x14, 0},          /* q */
+    {0x15, 0},          /* r */
+    {0x16, 0},          /* s */
+    {0x17, 0},          /* t */
+    {0x18, 0},          /* u */
+    {0x19, 0},          /* v */
+    {0x1a, 0},          /* w */
+    {0x1b, 0},          /* x */
+    {0x1c, 0},          /* y */
+    {0x1d, 0},          /* z */
+    {0x2f, KEY_SHIFT},      /* { */
+    {0x64, KEY_SHIFT},      /* | */
+    {0x30, KEY_SHIFT},      /* } */
+    {0x32, KEY_SHIFT},      /* ~ */
+    {0,0},             /* DEL */
+ 
+    {0x3a, 0},          /* F1 */
+    {0x3b, 0},          /* F2 */
+    {0x3c, 0},          /* F3 */
+    {0x3d, 0},          /* F4 */
+    {0x3e, 0},          /* F5 */
+    {0x3f, 0},          /* F6 */
+    {0x40, 0},          /* F7 */
+    {0x41, 0},          /* F8 */
+    {0x42, 0},          /* F9 */
+    {0x43, 0},          /* F10 */
+    {0x44, 0},          /* F11 */
+    {0x45, 0},          /* F12 */
+ 
+    {0x46, 0},          /* PRINT_SCREEN */
+    {0x47, 0},          /* SCROLL_LOCK */
+    {0x39, 0},          /* CAPS_LOCK */
+    {0x53, 0},          /* NUM_LOCK */
+    {0x49, 0},          /* INSERT */
+    {0x4a, 0},          /* HOME */
+    {0x4b, 0},          /* PAGE_UP */
+    {0x4e, 0},          /* PAGE_DOWN */
+ 
+    {0x4f, 0},          /* RIGHT_ARROW */
+    {0x50, 0},          /* LEFT_ARROW */
+    {0x51, 0},          /* DOWN_ARROW */
+    {0x52, 0},          /* UP_ARROW */
+};
+#endif
+
+#endif
+
+
diff -r 0041f35b0c4c -r c840c2b6f490 BLE_HID/MouseService.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/BLE_HID/MouseService.h	Fri May 31 20:53:51 2019 +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;
+};
+
diff -r 0041f35b0c4c -r c840c2b6f490 BLE_HID/examples_common.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/BLE_HID/examples_common.cpp	Fri May 31 20:53:51 2019 +0000
@@ -0,0 +1,83 @@
+/* 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 "ble/services/BatteryService.h"
+
+#include "HIDDeviceInformationService.h"
+
+#include "examples_common.h"
+
+static void passkeyDisplayCallback(Gap::Handle_t handle, const SecurityManager::Passkey_t passkey)
+{
+    printf("Input passKey: ");
+    for (unsigned i = 0; i < Gap::ADDR_LEN; i++) {
+        printf("%c", passkey[i]);
+    }
+    printf("\r\n");
+}
+
+static void securitySetupCompletedCallback(Gap::Handle_t handle, SecurityManager::SecurityCompletionStatus_t status)
+{
+    if (status == SecurityManager::SEC_STATUS_SUCCESS) {
+        printf("Security success %d\r\n", status);
+    } else {
+        printf("Security failed %d\r\n", status);
+    }
+}
+
+static void securitySetupInitiatedCallback(Gap::Handle_t, bool allowBonding, bool requireMITM, SecurityManager::SecurityIOCapabilities_t iocaps)
+{
+    printf("Security setup initiated\r\n");
+}
+
+void initializeSecurity(BLE &ble)
+{
+    bool enableBonding = true;
+    bool requireMITM = HID_SECURITY_REQUIRE_MITM;
+
+    ble.securityManager().onSecuritySetupInitiated(securitySetupInitiatedCallback);
+    ble.securityManager().onPasskeyDisplay(passkeyDisplayCallback);
+    ble.securityManager().onSecuritySetupCompleted(securitySetupCompletedCallback);
+
+    ble.securityManager().init(enableBonding, requireMITM, HID_SECURITY_IOCAPS);
+}
+
+void initializeHOGP(BLE &ble)
+{
+    static const uint16_t uuid16_list[] =  {GattService::UUID_HUMAN_INTERFACE_DEVICE_SERVICE,
+        GattService::UUID_DEVICE_INFORMATION_SERVICE,
+        GattService::UUID_BATTERY_SERVICE};
+
+    PnPID_t pnpID;
+    pnpID.vendorID_source = 0x2; // from the USB Implementer's Forum
+    pnpID.vendorID = 0x0D28; // NXP
+    pnpID.productID = 0x0204; // CMSIS-DAP (well, it's a keyboard but oh well)
+    pnpID.productVersion = 0x0100; // v1.0
+    HIDDeviceInformationService deviceInfo(ble, "ARM", "m1", "abc", "def", "ghi", "jkl", &pnpID);
+
+    BatteryService batteryInfo(ble, 80);
+
+    ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::BREDR_NOT_SUPPORTED |
+            GapAdvertisingData::LE_GENERAL_DISCOVERABLE);
+    ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LIST_16BIT_SERVICE_IDS,
+            (uint8_t *)uuid16_list, sizeof(uuid16_list));
+
+    // see 5.1.2: HID over GATT Specification (pg. 25)
+    ble.gap().setAdvertisingType(GapAdvertisingParams::ADV_CONNECTABLE_UNDIRECTED);
+    // 30ms to 50ms is recommended (5.1.2)
+    ble.gap().setAdvertisingInterval(50);
+}
+
diff -r 0041f35b0c4c -r c840c2b6f490 BLE_HID/examples_common.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/BLE_HID/examples_common.h	Fri May 31 20:53:51 2019 +0000
@@ -0,0 +1,70 @@
+/* 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.
+ */
+
+#ifndef HID_EXAMPLES_COMMON_H_
+#define HID_EXAMPLES_COMMON_H_
+
+/**
+ * Functions and configuration common to all HID demos
+ */
+
+#include "ble/BLE.h"
+
+#include "HIDServiceBase.h"
+
+/**
+ * IO capabilities of the device. During development, you most likely want "JustWorks", which means
+ * no IO capabilities.
+ * It is also possible to use IO_CAPS_DISPLAY_ONLY to generate and show a pincode on the serial
+ * output.
+ */
+#ifndef HID_SECURITY_IOCAPS
+#define HID_SECURITY_IOCAPS (SecurityManager::IO_CAPS_NONE)
+#endif
+
+/**
+ * Security level. MITM disabled forces "Just Works". If you require MITM, HID_SECURITY_IOCAPS must
+ * be at least IO_CAPS_DISPLAY_ONLY.
+ */
+#ifndef HID_SECURITY_REQUIRE_MITM
+#define HID_SECURITY_REQUIRE_MITM false
+#endif
+
+/**
+ * Disable debug messages by setting NDEBUG
+ */
+#ifndef NDEBUG
+#define HID_DEBUG(...) printf(__VA_ARGS__)
+#else
+#define HID_DEBUG(...)
+#endif
+
+/**
+ * Initialize security manager: set callback functions and required security level
+ */
+void initializeSecurity(BLE &ble);
+
+/**
+ * - Initialize auxiliary services required by the HID-over-GATT Profile.
+ * - Initialize common Gap advertisement.
+ *
+ * Demos only have to set a custom device name and appearance, and their HID
+ * service.
+ */
+void initializeHOGP(BLE &ble);
+
+#endif /* !BLE_HID_COMMON_H_ */
+
diff -r 0041f35b0c4c -r c840c2b6f490 bit_board.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/bit_board.cpp	Fri May 31 20:53:51 2019 +0000
@@ -0,0 +1,246 @@
+/* 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 "ble/BLE.h"
+#include "KeyboardService.h"
+#include "MicroBitPin.h"
+#include "examples_common.h"
+#include "MicroBit.h"
+/**
+ * This program implements a complete HID-over-Gatt Profile:
+ *  - HID is provided by KeyboardService
+ *  - Battery Service
+ *  - Device Information Service
+ *
+ * Complete strings can be sent over BLE using printf. Please note, however, than a 12char string
+ * will take about 500ms to transmit, principally because of the limited notification rate in BLE.
+ * KeyboardService uses a circular buffer to store the strings to send, and calls to putc will fail
+ * once this buffer is full. This will result in partial strings being sent to the client.
+ */
+ 
+ //The micro:bit has a matrixed display, this is a simple way to use some LEDs on it
+DigitalOut col9(P0_12, 0);
+
+DigitalOut waiting_led(P0_13);
+DigitalOut connected_led(P0_15);
+
+InterruptIn button1(BUTTON_A);
+InterruptIn button2(BUTTON_B);
+
+//InterruptIn key1(MICROBIT_PIN_P0);
+// Try to use external signal, rather than button a&b as keys
+
+BLE ble;
+KeyboardService *kbdServicePtr;
+
+static const char DEVICE_NAME[] = "micro:bit xx316";
+static const char SHORT_DEVICE_NAME[] = "kbd1";
+
+static void onDisconnect(const Gap::DisconnectionCallbackParams_t *params)
+{
+    HID_DEBUG("disconnected\r\n");
+    connected_led = 0;
+
+    ble.gap().startAdvertising(); // restart advertising
+}
+
+static void onConnect(const Gap::ConnectionCallbackParams_t *params)
+{
+    HID_DEBUG("connected\r\n");
+    waiting_led = false;
+}
+
+static void waiting() {
+    if (!kbdServicePtr->isConnected())
+        waiting_led = !waiting_led;
+    else
+        connected_led = !connected_led;
+}
+
+void send_string(const char * c) {
+    if (!kbdServicePtr)
+        return;
+
+    if (!kbdServicePtr->isConnected()) {
+        HID_DEBUG("we haven't connected yet...");
+    } else {
+        int len = strlen(c);
+        kbdServicePtr->printf(c);
+        HID_DEBUG("sending %d chars\r\n", len);
+    }
+}
+
+void send_stuff() {
+    send_string("n");
+    wait(0.1);
+}
+
+void send_more_stuff() {
+    send_string("p");
+    wait(0.1);
+}
+
+
+void send_one(){
+    inputReportData[0] = 0;
+    inputReportData[2] = 0x1e;
+    kbdServicePtr->send(inputReportData); //key down event?
+    kbdServicePtr->send(emptyInputReportData); // key up event?
+    wait(0.1);
+}
+
+void send_zero(){// testing input from pins
+    inputReportData[0] = 0;
+    inputReportData[2] = 0x27;
+    kbdServicePtr->send(inputReportData); //key down event?
+    kbdServicePtr->send(emptyInputReportData); // key up event?
+    wait(0.1);
+}
+
+void send_up(){// testing input from pins
+    inputReportData[0] = 0;
+    inputReportData[2] = 0x52;
+    kbdServicePtr->send(inputReportData); //key down event?
+    kbdServicePtr->send(emptyInputReportData); // key up event?
+    wait(0.1);
+}
+
+void send_down(){// testing input from pins
+   // kbdServicePtr->putc(DownArrow);
+    inputReportData[0] = 0;
+    inputReportData[2] = 0x51;
+    kbdServicePtr->send(inputReportData);
+    kbdServicePtr->send(emptyInputReportData);
+    wait(0.1);
+}
+
+void send_left(){// testing input from pins
+    inputReportData[0] = 0;
+    inputReportData[2] = 0x50;
+    kbdServicePtr->send(inputReportData);
+    kbdServicePtr->send(emptyInputReportData);
+    wait(0.1);
+}
+
+void send_right(){// testing input from pins
+    inputReportData[0] = 0;
+    inputReportData[2] = 0x4f;
+    kbdServicePtr->send(inputReportData);
+    kbdServicePtr->send(emptyInputReportData);
+    wait(0.1);
+}
+
+void send_space(){// testing input from pins
+    inputReportData[0] = 0;
+    inputReportData[2] = 0x2c;
+    kbdServicePtr->send(inputReportData);
+    kbdServicePtr->send(emptyInputReportData);
+    wait(0.1);
+}
+
+void send_release(){
+    kbdServicePtr->send(emptyInputReportData);
+    wait(0.1);
+}
+    
+
+//#define MICROBIT_PIN_P13                    P0_23       //SCK
+//InterruptIn key2(MICROBIT_PIN_P13);
+DigitalIn touch1(MICROBIT_PIN_P13);
+//#define MICROBIT_PIN_P0                     P0_3  
+AnalogIn x_axis(MICROBIT_PIN_P0);
+//#define MICROBIT_PIN_P1                     P0_2
+AnalogIn y_axis(MICROBIT_PIN_P1);
+
+//Thread joystick_control_thread; // "Identifier "Thread" is undefined"???
+
+void JoystickControl(){
+    float x,y;
+//    
+//    if (touch1 == 1) send_one();
+//        if (touch1 == 0) send_zero();
+
+    x = x_axis.read();
+    if (x < 0.05f) send_left();
+    if (x > 0.95f) send_right();
+    
+    y = y_axis.read();
+    if (y < 0.05f) send_down();
+    if (y > 0.95f) send_up();
+    
+    wait(0.05);
+}
+
+void touch_control(){
+    if (touch1 == 1) send_space();
+    wait(0.05);
+}
+
+//void BLE_fiber(){
+//    while (true) {
+//        ble.waitForEvent();     
+//    }
+//}
+
+int main(){
+    //create_fiber(JoystickControl);
+//    create_fiber(BLE_fiber);
+    Ticker heartbeat;
+
+    button1.rise(send_one);
+    button2.rise(send_zero);
+
+    HID_DEBUG("initialising ticker\r\n");
+
+    heartbeat.attach(waiting, 1);
+
+    HID_DEBUG("initialising ble\r\n");
+    ble.init();
+
+    ble.gap().onDisconnection(onDisconnect);
+    ble.gap().onConnection(onConnect);
+
+    initializeSecurity(ble);
+
+    HID_DEBUG("adding hid service\r\n");
+    KeyboardService kbdService(ble);
+    kbdServicePtr = &kbdService;
+
+    HID_DEBUG("adding device info and battery service\r\n");
+    initializeHOGP(ble);
+
+    HID_DEBUG("setting up gap\r\n");
+    ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::KEYBOARD);
+    ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LOCAL_NAME,
+                                           (uint8_t *)DEVICE_NAME, sizeof(DEVICE_NAME));
+    ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::SHORTENED_LOCAL_NAME,
+                                           (uint8_t *)SHORT_DEVICE_NAME, sizeof(SHORT_DEVICE_NAME));
+    ble.gap().setDeviceName((const uint8_t *)DEVICE_NAME);
+
+    HID_DEBUG("advertising\r\n");
+    ble.gap().startAdvertising();
+    
+    float x,y;
+    
+    while (true) {
+        ble.waitForEvent();  
+        
+        JoystickControl();  
+        touch_control();
+    }
+//    release_fiber();
+}
\ No newline at end of file
diff -r 0041f35b0c4c -r c840c2b6f490 main.cpp
--- a/main.cpp	Wed Jul 13 16:03:21 2016 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,43 +0,0 @@
-/*
-The MIT License (MIT)
-
-Copyright (c) 2016 British Broadcasting Corporation.
-This software is provided by Lancaster University by arrangement with the BBC.
-
-Permission is hereby granted, free of charge, to any person obtaining a
-copy of this software and associated documentation files (the "Software"),
-to deal in the Software without restriction, including without limitation
-the rights to use, copy, modify, merge, publish, distribute, sublicense,
-and/or sell copies of the Software, and to permit persons to whom the
-Software is furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in
-all copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
-THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
-DEALINGS IN THE SOFTWARE.
-*/
-
-#include "MicroBit.h"
-
-MicroBit uBit;
-
-int main()
-{
-    // Initialise the micro:bit runtime.
-    uBit.init();
-
-    // Insert your code here!
-    uBit.display.scroll("HELLO WORLD! :)");
-
-    // If main exits, there may still be other fibers running or registered event handlers etc.
-    // Simply release this fiber, which will mean we enter the scheduler. Worse case, we then
-    // sit in the idle task forever, in a power efficient sleep.
-    release_fiber();
-}
-
diff -r 0041f35b0c4c -r c840c2b6f490 test.txt
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test.txt	Fri May 31 20:53:51 2019 +0000
@@ -0,0 +1,12 @@
+110101011111111
+1110011111001
+10101101010101010100101110
+101001001010000101010010100
+1010000101000110011001100011100011100011100
+10
+11
+11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111
+111111111111111111111111111111111111111111111111111
+111111111111111111111111111111111111
+0
+1010101010100010000111000
\ No newline at end of file