for demo on Thursday

Dependencies:   microbit

Files at this revision

API Documentation at this revision

Comitter:
xx316
Date:
Wed Jun 12 15:21:01 2019 +0000
Parent:
0:0041f35b0c4c
Commit message:
for demo on Thursday;

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
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/BLE_HID/HIDDeviceInformationService.h	Wed Jun 12 15:21:01 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__*/
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/BLE_HID/HIDServiceBase.cpp	Wed Jun 12 15:21:01 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;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/BLE_HID/HIDServiceBase.h	Wed Jun 12 15:21:01 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_ */
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/BLE_HID/HID_types.h	Wed Jun 12 15:21:01 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
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/BLE_HID/JoystickService.h	Wed Jun 12 15:21:01 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;
+};
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/BLE_HID/KeyboardService.h	Wed Jun 12 15:21:01 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;
+};
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/BLE_HID/Keyboard_types.h	Wed Jun 12 15:21:01 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
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/BLE_HID/MouseService.h	Wed Jun 12 15:21:01 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;
+};
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/BLE_HID/examples_common.cpp	Wed Jun 12 15:21:01 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);
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/BLE_HID/examples_common.h	Wed Jun 12 15:21:01 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_ */
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/bit_board.cpp	Wed Jun 12 15:21:01 2019 +0000
@@ -0,0 +1,316 @@
+/* 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[] = "bit:board wire loop";
+static const char SHORT_DEVICE_NAME[] = "kbd blue";
+
+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_delete(){// testing input from pins
+    inputReportData[0] = 0;
+    inputReportData[2] = 0x2a;
+    kbdServicePtr->send(inputReportData);
+    kbdServicePtr->send(emptyInputReportData);
+    wait(0.1);
+}
+void send_tab(){// testing input from pins
+    inputReportData[0] = 0;
+    inputReportData[2] = 0x2b;
+    kbdServicePtr->send(inputReportData);
+    kbdServicePtr->send(emptyInputReportData);
+    wait(0.1);
+}
+
+void send_return(){// testing input from pins
+    inputReportData[0] = 0;
+    inputReportData[2] = 0x28;
+    kbdServicePtr->send(inputReportData);
+    kbdServicePtr->send(emptyInputReportData);
+    wait(0.1);
+}
+
+void send_release(){
+    kbdServicePtr->send(emptyInputReportData);
+    wait(0.1);
+}
+    
+
+DigitalIn touch1(MICROBIT_PIN_P13); // for the normal 4
+DigitalIn touch2(MICROBIT_PIN_P14);
+DigitalIn touch3(MICROBIT_PIN_P15);
+DigitalIn touch4(MICROBIT_PIN_P16); // disable for wire loop example?
+InterruptIn touch0(MICROBIT_PIN_P8);//
+//DigitalIn touch0(MICROBIT_PIN_P8); // for wire loop example only
+AnalogIn x_axis(MICROBIT_PIN_P1);
+AnalogIn y_axis(MICROBIT_PIN_P2);
+AnalogIn potentiometer(MICROBIT_PIN_P0);
+
+void JoystickControl(){
+    float x,y;
+
+    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 crossy_road_touch(){
+    if (touch1 == 1) send_space(); 
+    wait(0.05);
+}
+
+enum mode{empty,arithmetic, alphebet, number};
+
+void potentiometer_control(){
+    mode current_mode = empty;
+    float value = potentiometer.read();
+    
+    if (value < (float) 229/1024 ) {current_mode = empty;}
+    else if (value < (float) 307/1024) { current_mode = arithmetic;}
+    else if (value < (float) 522/1024) { current_mode = number;}
+    else {current_mode = alphebet;}
+    
+    // need to update mode, depending on value
+    
+    switch(current_mode){
+        case empty: 
+            if (touch1 == 1) send_space(); 
+            if (touch2 == 1) send_delete(); 
+            if (touch3 == 1) send_tab(); 
+            if (touch4 == 1) send_return(); 
+            wait(0.05);
+            break;
+        case arithmetic: 
+            if (touch1 == 1) {send_string("+");wait(0.1);} 
+            if (touch2 == 1) {send_string("-");wait(0.1);}
+            if (touch3 == 1) {send_string("*");wait(0.1);}
+            if (touch4 == 1) {send_string("/");wait(0.1);}
+            wait(0.05);
+            break;
+        case alphebet: 
+            if (touch1 == 1) {send_string("A");wait(0.1);} 
+            if (touch2 == 1) {send_string("B");wait(0.1);}
+            if (touch3 == 1) {send_string("C");wait(0.1);}
+            if (touch4 == 1) {send_string("D");wait(0.1);}
+            wait(0.05);
+            break;
+        case number: 
+            if (touch1 == 1) {send_string("1");wait(0.1);} 
+            if (touch2 == 1) {send_string("2");wait(0.1);}
+            if (touch3 == 1) {send_string("3");wait(0.1);}
+            if (touch4 == 1) {send_string("4");wait(0.1);}
+            wait(0.05);
+            break;
+    }
+}
+
+void wire_loop_control(){
+//    if (touch0 == 1) {send_string("w");wait(0.1);}  // touch, need to stop timer as well
+    // ???somehow pin8 is active high, need to pull down????
+    if (touch1 == 1) {send_string("x");wait(0.1);}  // start timer
+    if (touch2 == 1) {send_string("y");wait(0.1);}  // stop timer
+    if (touch3 == 1) {send_string("z");wait(0.1);}  // reset timer
+//    if (touch4 == 1) {send_string("w");wait(0.1);} 
+ /// try to use interrup
+}
+
+void touched(){send_string("w");wait(0.1);}
+
+int main(){
+    //create_fiber(JoystickControl);
+//    create_fiber(BLE_fiber);
+    Ticker heartbeat;
+
+    touch0.fall(touched);
+    //button1.rise(send_one);
+//    button2.rise(send_zero);
+    button1.rise(send_stuff);
+    button2.rise(send_more_stuff);
+
+    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();
+    
+    while (true) {
+        ble.waitForEvent();  
+        
+        //JoystickControl();  
+        
+        // normally, only realize one example: crossy road, potentiometer, or wire loop
+//        crossy_road_touch();
+//        potentiometer_control();
+        wire_loop_control();
+    }
+//    release_fiber();
+}
+
+
--- 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();
-}
-