Revision 1:c840c2b6f490, committed 2019-05-31
- 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
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(¶ms);
+
+ 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