Test; try to make a personal repository
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
--- /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__*/ + +
--- /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; +} +
--- /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_ */ +
--- /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 + +
--- /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; +}; +
--- /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; +}; + +
--- /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 + +
--- /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; +}; +
--- /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); +} +
--- /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_ */ +
--- /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
--- 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(); -} -
--- /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