├── LICENSE-2.0.txt ├── README.md ├── examples ├── moveAndScroll │ └── moveAndScroll.ino └── moveUsingIMU │ └── moveUsingIMU.ino ├── keywords.txt ├── library.properties └── src ├── BLE_HID ├── HIDDeviceInformationService.h ├── HIDServiceBase.cpp ├── HIDServiceBase.h ├── HID_types.h ├── mouse.cpp └── mouse.h ├── HIDMouse.cpp ├── HIDMouse.h └── mbed_pins.txt /LICENSE-2.0.txt: -------------------------------------------------------------------------------- 1 | 2 | Apache License 3 | Version 2.0, January 2004 4 | http://www.apache.org/licenses/ 5 | 6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 7 | 8 | 1. Definitions. 9 | 10 | "License" shall mean the terms and conditions for use, reproduction, 11 | and distribution as defined by Sections 1 through 9 of this document. 12 | 13 | "Licensor" shall mean the copyright owner or entity authorized by 14 | the copyright owner that is granting the License. 15 | 16 | "Legal Entity" shall mean the union of the acting entity and all 17 | other entities that control, are controlled by, or are under common 18 | control with that entity. For the purposes of this definition, 19 | "control" means (i) the power, direct or indirect, to cause the 20 | direction or management of such entity, whether by contract or 21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 22 | outstanding shares, or (iii) beneficial ownership of such entity. 23 | 24 | "You" (or "Your") shall mean an individual or Legal Entity 25 | exercising permissions granted by this License. 26 | 27 | "Source" form shall mean the preferred form for making modifications, 28 | including but not limited to software source code, documentation 29 | source, and configuration files. 30 | 31 | "Object" form shall mean any form resulting from mechanical 32 | transformation or translation of a Source form, including but 33 | not limited to compiled object code, generated documentation, 34 | and conversions to other media types. 35 | 36 | "Work" shall mean the work of authorship, whether in Source or 37 | Object form, made available under the License, as indicated by a 38 | copyright notice that is included in or attached to the work 39 | (an example is provided in the Appendix below). 40 | 41 | "Derivative Works" shall mean any work, whether in Source or Object 42 | form, that is based on (or derived from) the Work and for which the 43 | editorial revisions, annotations, elaborations, or other modifications 44 | represent, as a whole, an original work of authorship. For the purposes 45 | of this License, Derivative Works shall not include works that remain 46 | separable from, or merely link (or bind by name) to the interfaces of, 47 | the Work and Derivative Works thereof. 48 | 49 | "Contribution" shall mean any work of authorship, including 50 | the original version of the Work and any modifications or additions 51 | to that Work or Derivative Works thereof, that is intentionally 52 | submitted to Licensor for inclusion in the Work by the copyright owner 53 | or by an individual or Legal Entity authorized to submit on behalf of 54 | the copyright owner. For the purposes of this definition, "submitted" 55 | means any form of electronic, verbal, or written communication sent 56 | to the Licensor or its representatives, including but not limited to 57 | communication on electronic mailing lists, source code control systems, 58 | and issue tracking systems that are managed by, or on behalf of, the 59 | Licensor for the purpose of discussing and improving the Work, but 60 | excluding communication that is conspicuously marked or otherwise 61 | designated in writing by the copyright owner as "Not a Contribution." 62 | 63 | "Contributor" shall mean Licensor and any individual or Legal Entity 64 | on behalf of whom a Contribution has been received by Licensor and 65 | subsequently incorporated within the Work. 66 | 67 | 2. Grant of Copyright License. Subject to the terms and conditions of 68 | this License, each Contributor hereby grants to You a perpetual, 69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 70 | copyright license to reproduce, prepare Derivative Works of, 71 | publicly display, publicly perform, sublicense, and distribute the 72 | Work and such Derivative Works in Source or Object form. 73 | 74 | 3. Grant of Patent License. Subject to the terms and conditions of 75 | this License, each Contributor hereby grants to You a perpetual, 76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 77 | (except as stated in this section) patent license to make, have made, 78 | use, offer to sell, sell, import, and otherwise transfer the Work, 79 | where such license applies only to those patent claims licensable 80 | by such Contributor that are necessarily infringed by their 81 | Contribution(s) alone or by combination of their Contribution(s) 82 | with the Work to which such Contribution(s) was submitted. If You 83 | institute patent litigation against any entity (including a 84 | cross-claim or counterclaim in a lawsuit) alleging that the Work 85 | or a Contribution incorporated within the Work constitutes direct 86 | or contributory patent infringement, then any patent licenses 87 | granted to You under this License for that Work shall terminate 88 | as of the date such litigation is filed. 89 | 90 | 4. Redistribution. You may reproduce and distribute copies of the 91 | Work or Derivative Works thereof in any medium, with or without 92 | modifications, and in Source or Object form, provided that You 93 | meet the following conditions: 94 | 95 | (a) You must give any other recipients of the Work or 96 | Derivative Works a copy of this License; and 97 | 98 | (b) You must cause any modified files to carry prominent notices 99 | stating that You changed the files; and 100 | 101 | (c) You must retain, in the Source form of any Derivative Works 102 | that You distribute, all copyright, patent, trademark, and 103 | attribution notices from the Source form of the Work, 104 | excluding those notices that do not pertain to any part of 105 | the Derivative Works; and 106 | 107 | (d) If the Work includes a "NOTICE" text file as part of its 108 | distribution, then any Derivative Works that You distribute must 109 | include a readable copy of the attribution notices contained 110 | within such NOTICE file, excluding those notices that do not 111 | pertain to any part of the Derivative Works, in at least one 112 | of the following places: within a NOTICE text file distributed 113 | as part of the Derivative Works; within the Source form or 114 | documentation, if provided along with the Derivative Works; or, 115 | within a display generated by the Derivative Works, if and 116 | wherever such third-party notices normally appear. The contents 117 | of the NOTICE file are for informational purposes only and 118 | do not modify the License. You may add Your own attribution 119 | notices within Derivative Works that You distribute, alongside 120 | or as an addendum to the NOTICE text from the Work, provided 121 | that such additional attribution notices cannot be construed 122 | as modifying the License. 123 | 124 | You may add Your own copyright statement to Your modifications and 125 | may provide additional or different license terms and conditions 126 | for use, reproduction, or distribution of Your modifications, or 127 | for any such Derivative Works as a whole, provided Your use, 128 | reproduction, and distribution of the Work otherwise complies with 129 | the conditions stated in this License. 130 | 131 | 5. Submission of Contributions. Unless You explicitly state otherwise, 132 | any Contribution intentionally submitted for inclusion in the Work 133 | by You to the Licensor shall be under the terms and conditions of 134 | this License, without any additional terms or conditions. 135 | Notwithstanding the above, nothing herein shall supersede or modify 136 | the terms of any separate license agreement you may have executed 137 | with Licensor regarding such Contributions. 138 | 139 | 6. Trademarks. This License does not grant permission to use the trade 140 | names, trademarks, service marks, or product names of the Licensor, 141 | except as required for reasonable and customary use in describing the 142 | origin of the Work and reproducing the content of the NOTICE file. 143 | 144 | 7. Disclaimer of Warranty. Unless required by applicable law or 145 | agreed to in writing, Licensor provides the Work (and each 146 | Contributor provides its Contributions) on an "AS IS" BASIS, 147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 148 | implied, including, without limitation, any warranties or conditions 149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 150 | PARTICULAR PURPOSE. You are solely responsible for determining the 151 | appropriateness of using or redistributing the Work and assume any 152 | risks associated with Your exercise of permissions under this License. 153 | 154 | 8. Limitation of Liability. In no event and under no legal theory, 155 | whether in tort (including negligence), contract, or otherwise, 156 | unless required by applicable law (such as deliberate and grossly 157 | negligent acts) or agreed to in writing, shall any Contributor be 158 | liable to You for damages, including any direct, indirect, special, 159 | incidental, or consequential damages of any character arising as a 160 | result of this License or out of the use or inability to use the 161 | Work (including but not limited to damages for loss of goodwill, 162 | work stoppage, computer failure or malfunction, or any and all 163 | other commercial damages or losses), even if such Contributor 164 | has been advised of the possibility of such damages. 165 | 166 | 9. Accepting Warranty or Additional Liability. While redistributing 167 | the Work or Derivative Works thereof, You may choose to offer, 168 | and charge a fee for, acceptance of support, warranty, indemnity, 169 | or other liability obligations and/or rights consistent with this 170 | License. However, in accepting such obligations, You may act only 171 | on Your own behalf and on Your sole responsibility, not on behalf 172 | of any other Contributor, and only if You agree to indemnify, 173 | defend, and hold each Contributor harmless for any liability 174 | incurred by, or claims asserted against, such Contributor by reason 175 | of your accepting any such warranty or additional liability. 176 | 177 | END OF TERMS AND CONDITIONS 178 | 179 | APPENDIX: How to apply the Apache License to your work. 180 | 181 | To apply the Apache License to your work, attach the following 182 | boilerplate notice, with the fields enclosed by brackets "[]" 183 | replaced with your own identifying information. (Don't include 184 | the brackets!) The text should be enclosed in the appropriate 185 | comment syntax for the file format. We also recommend that a 186 | file or class name and description of purpose be included on the 187 | same "printed page" as the copyright notice for easier 188 | identification within third-party archives. 189 | 190 | Copyright [yyyy] [name of copyright owner] 191 | 192 | Licensed under the Apache License, Version 2.0 (the "License"); 193 | you may not use this file except in compliance with the License. 194 | You may obtain a copy of the License at 195 | 196 | http://www.apache.org/licenses/LICENSE-2.0 197 | 198 | Unless required by applicable law or agreed to in writing, software 199 | distributed under the License is distributed on an "AS IS" BASIS, 200 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 201 | See the License for the specific language governing permissions and 202 | limitations under the License. 203 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # mbed-BLE-Mouse 2 | ### BLE Mouse library for Arduino boards with BLE support and mbed OS. 3 | This library turns Arduino Board into a BLE Mouse which can be connected to devices such as Windows PC, android phones etc. 4 | This library is completely written using Mbed OS's BLE API and also supports pairing with the Central device. 5 | 6 | ## Usage 7 | This library is similar to the Arduino's Mouse library and supports all the functions which are in the mouse library. 8 | It also has additional features such as setDeviceName, setManufacturerName and setBatteryLevel. 9 | ``` 10 | #include 11 | 12 | HIDMouse bleMouse; 13 | 14 | void setup() { 15 | 16 | pinMode(LED_BUILTIN, OUTPUT); 17 | bleMouse.setDeviceName("Device"); 18 | bleMouse.setManufacturerName("Manufacturer"); 19 | bleMouse.setBatteryLevel(75); 20 | bleMouse.begin(); 21 | } 22 | 23 | void loop() { 24 | while(bleMouse.isConnected()) { 25 | digitalWrite(LED_BUILTIN, HIGH); 26 | bleMouse.move(0,0,1); 27 | delay(1000); 28 | } 29 | 30 | digitalWrite(LED_BUILTIN, LOW); 31 | } 32 | ``` 33 | 34 | ## Compatible Hardware 35 | - Arduino Nano BLE 36 | - Arduino Nano BLE Sense 37 | - Any board with Mbed OS and BLE support. 38 | 39 | ## Installation 40 | ### Using the Arduino IDE Library Manager 41 | 42 | 1. Choose `Tools` -> `Manage Libraries` -> `Mbed BLE Mouse` 43 | 44 | ### Using Git 45 | 46 | ```sh 47 | cd ~/Documents/Arduino/libraries/ 48 | git clone https://github.com/csash7/mbed-BLE-Mouse 49 | ``` 50 | 51 | ## Examples 52 | 53 | See [examples](examples) folder. 54 | 55 | ## License 56 | 57 | This library is [licensed](LICENSE-2.0.txt) under the [APACHE Licence](http://www.apache.org/licenses/LICENSE-2.0). 58 | -------------------------------------------------------------------------------- /examples/moveAndScroll/moveAndScroll.ino: -------------------------------------------------------------------------------- 1 | /** 2 | * This example turns the nano 33 BLE into a Bluetooth LE mouse that continuously moves the mouse. 3 | */ 4 | #include 5 | 6 | HIDMouse bleMouse; 7 | 8 | void setup() { 9 | 10 | pinMode(LED_BUILTIN, OUTPUT); 11 | bleMouse.setDeviceName("Device"); 12 | bleMouse.setManufacturerName("Manufacturer"); 13 | bleMouse.setBatteryLevel(75); 14 | bleMouse.begin(); 15 | } 16 | 17 | void loop() { 18 | if(bleMouse.isConnected()) { 19 | 20 | digitalWrite(LED_BUILTIN, HIGH); 21 | unsigned long startTime; 22 | 23 | startTime = millis(); 24 | while(millis() 7 | #include 8 | 9 | HIDMouse bleMouse; 10 | 11 | void setup() { 12 | 13 | if (!IMU.begin()) { 14 | while (1); 15 | } 16 | 17 | pinMode(LED_BUILTIN, OUTPUT); 18 | bleMouse.setDeviceName("Device"); 19 | bleMouse.setManufacturerName("Manufacturer"); 20 | bleMouse.setBatteryLevel(75); 21 | bleMouse.begin(); 22 | 23 | } 24 | 25 | void loop() { 26 | float ax, ay, az; 27 | float prevxValue = 0, prevyValue = 0; 28 | int xAcc = 0, yAcc = 0, maxPosAcc = 5, maxNegAcc = -5; 29 | 30 | while(bleMouse.isConnected()) { 31 | 32 | digitalWrite(LED_BUILTIN, HIGH); 33 | 34 | if (IMU.accelerationAvailable ()) { 35 | IMU.readAcceleration(ax, ay, az); 36 | 37 | if(ax < -0.3){ 38 | if(prevxValue < -0.3){ 39 | if(yAcc < maxPosAcc){ 40 | yAcc += 1; 41 | } 42 | } 43 | else { 44 | prevxValue = ax; 45 | yAcc = 1; 46 | } 47 | bleMouse.move(0,yAcc); // y-Axis down 48 | } 49 | else if(ax > 0.3){ 50 | if(prevxValue > 0.3){ 51 | if(yAcc > maxNegAcc){ 52 | yAcc -= 1; 53 | } 54 | } 55 | else { 56 | prevxValue = ax; 57 | yAcc = -1; 58 | } 59 | bleMouse.move(0,yAcc); // y-axis up 60 | } 61 | if(ay < -0.3){ 62 | if(prevyValue < -0.3){ 63 | if(xAcc > maxNegAcc){ 64 | xAcc -= 1; 65 | } 66 | } 67 | else { 68 | prevyValue = ay; 69 | xAcc = -1; 70 | } 71 | bleMouse.move(xAcc,0); // x-axis right 72 | } 73 | else if(ay > 0.3){ 74 | if(prevyValue > 0.3){ 75 | if(xAcc < maxPosAcc){ 76 | xAcc += 1; 77 | } 78 | } 79 | else { 80 | prevyValue = ay; 81 | xAcc = 1; 82 | } 83 | bleMouse.move(xAcc,0); // x-axis left 84 | } 85 | } 86 | //delay(100); 87 | 88 | } 89 | digitalWrite(LED_BUILTIN, LOW); 90 | } 91 | -------------------------------------------------------------------------------- /keywords.txt: -------------------------------------------------------------------------------- 1 | ####################################### 2 | # Syntax Coloring Map For mbed BLE Mouse 3 | ####################################### 4 | # Class 5 | ####################################### 6 | 7 | HIDMouse KEYWORD1 8 | 9 | ####################################### 10 | # Methods and Functions 11 | ####################################### 12 | 13 | begin KEYWORD2 14 | click KEYWORD2 15 | move KEYWORD2 16 | press KEYWORD2 17 | release KEYWORD2 18 | isPressed KEYWORD2 19 | isConnected KEYWORD2 20 | setManufacturerName KEYWORD2 21 | setDeviceName KEYWORD2 22 | setBatteryLevel KEYWORD2 23 | 24 | ####################################### 25 | # Constants 26 | ####################################### 27 | 28 | MOUSE_BUTTON_LEFT LITERAL1 29 | MOUSE_BUTTON_RIGHT LITERAL1 30 | MOUSE_BUTTON_MIDDLE LITERAL1 31 | MOUSE_BUTTON_BACK LITERAL1 32 | MOUSE_BUTTON_FORWARD LITERAL1 -------------------------------------------------------------------------------- /library.properties: -------------------------------------------------------------------------------- 1 | name=Mbed BLE Mouse 2 | version=1.3.0 3 | author=Harsha 4 | maintainer=csash7 5 | sentence=Bluetooth LE Mouse library for the Arduino Boards with BLE support and running mbed OS. 6 | paragraph=Bluetooth LE Mouse library for the Arduino Boards with BLE support and running mbed OS. 7 | category=Communication 8 | url=https://github.com/csash7/mbed-BLE-Mouse 9 | architectures=mbed,mbed_nano,mbed_portenta 10 | includes=HIDMouse.h 11 | -------------------------------------------------------------------------------- /src/BLE_HID/HIDDeviceInformationService.h: -------------------------------------------------------------------------------- 1 | /* mbed Microcontroller Library 2 | * Copyright (c) 2006-2013 ARM Limited 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #ifndef __BLE_HID_DEVICE_INFORMATION_SERVICE_H__ 18 | #define __BLE_HID_DEVICE_INFORMATION_SERVICE_H__ 19 | 20 | #include "ble/BLE.h" 21 | 22 | #include "HID_types.h" 23 | 24 | 25 | class HIDDeviceInformationService { 26 | public: 27 | /** 28 | * @brief Device Information Service Constructor. 29 | * 30 | * @param[ref] _ble 31 | * BLE object for the underlying controller. 32 | * @param[in] manufacturersName 33 | * This characteristic represents the name of the 34 | * manufacturer of the device. The name is copied into the 35 | * BLE stack during this constructor. 36 | * @param[in] modelNumber 37 | * This characteristic represents the model number that is 38 | * assigned by the device vendor. The value is copied into 39 | * the BLE stack during this constructor. 40 | * @param[in] serialNumber 41 | * This characteristic represents the serial number for a 42 | * particular instance of the device. The value is copied 43 | * into the BLE stack during this constructor. 44 | * @param[in] hardwareRevision 45 | * This characteristic represents the hardware revision for 46 | * the hardware within the device. The value is copied 47 | * into the BLE stack during this constructor. 48 | * @param[in] firmwareRevision 49 | * This characteristic represents the firmware revision for 50 | * the firmware within the device. The value is copied 51 | * into the BLE stack during this constructor. 52 | * @param[in] softwareRevision 53 | * This characteristic represents the software revision for 54 | * the software within the device. The value is copied 55 | * into the BLE stack during this constructor. 56 | * @param[in] pnpID 57 | * This characteristic represents HID-specific information, 58 | * such as vendor id, product id and version. 59 | */ 60 | HIDDeviceInformationService(BLE &_ble, 61 | const char *manufacturersName = NULL, 62 | const char *modelNumber = NULL, 63 | const char *serialNumber = NULL, 64 | const char *hardwareRevision = NULL, 65 | const char *firmwareRevision = NULL, 66 | const char *softwareRevision = NULL, 67 | PnPID_t *PnPID = NULL) : 68 | ble(_ble), 69 | manufacturersNameStringCharacteristic(GattCharacteristic::UUID_MANUFACTURER_NAME_STRING_CHAR, 70 | (uint8_t *)manufacturersName, 71 | (manufacturersName != NULL) ? strlen(manufacturersName) : 0, /* minLength */ 72 | (manufacturersName != NULL) ? strlen(manufacturersName) : 0, /* maxLength */ 73 | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_READ), 74 | modelNumberStringCharacteristic(GattCharacteristic::UUID_MODEL_NUMBER_STRING_CHAR, 75 | (uint8_t *)modelNumber, 76 | (modelNumber != NULL) ? strlen(modelNumber) : 0, /* minLength */ 77 | (modelNumber != NULL) ? strlen(modelNumber) : 0, /* maxLength */ 78 | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_READ), 79 | serialNumberStringCharacteristic(GattCharacteristic::UUID_SERIAL_NUMBER_STRING_CHAR, 80 | (uint8_t *)serialNumber, 81 | (serialNumber != NULL) ? strlen(serialNumber) : 0, /* minLength */ 82 | (serialNumber != NULL) ? strlen(serialNumber) : 0, /* maxLength */ 83 | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_READ), 84 | hardwareRevisionStringCharacteristic(GattCharacteristic::UUID_HARDWARE_REVISION_STRING_CHAR, 85 | (uint8_t *)hardwareRevision, 86 | (hardwareRevision != NULL) ? strlen(hardwareRevision) : 0, /* minLength */ 87 | (hardwareRevision != NULL) ? strlen(hardwareRevision) : 0, /* maxLength */ 88 | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_READ), 89 | firmwareRevisionStringCharacteristic(GattCharacteristic::UUID_FIRMWARE_REVISION_STRING_CHAR, 90 | (uint8_t *)firmwareRevision, 91 | (firmwareRevision != NULL) ? strlen(firmwareRevision) : 0, /* minLength */ 92 | (firmwareRevision != NULL) ? strlen(firmwareRevision) : 0, /* maxLength */ 93 | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_READ), 94 | softwareRevisionStringCharacteristic(GattCharacteristic::UUID_SOFTWARE_REVISION_STRING_CHAR, 95 | (uint8_t *)softwareRevision, 96 | (softwareRevision != NULL) ? strlen(softwareRevision) : 0, /* minLength */ 97 | (softwareRevision != NULL) ? strlen(softwareRevision) : 0, /* maxLength */ 98 | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_READ), 99 | pnpIDCharacteristic(GattCharacteristic::UUID_PNP_ID_CHAR, 100 | PnPID) 101 | { 102 | static bool serviceAdded = false; 103 | if (serviceAdded) { 104 | return; 105 | } 106 | 107 | GattCharacteristic *charTable[] = {&manufacturersNameStringCharacteristic, 108 | &modelNumberStringCharacteristic, 109 | &serialNumberStringCharacteristic, 110 | &hardwareRevisionStringCharacteristic, 111 | &firmwareRevisionStringCharacteristic, 112 | &softwareRevisionStringCharacteristic, 113 | &pnpIDCharacteristic}; 114 | GattService deviceInformationService(GattService::UUID_DEVICE_INFORMATION_SERVICE, charTable, 115 | sizeof(charTable) / sizeof(GattCharacteristic *)); 116 | 117 | ble.gattServer().addService(deviceInformationService); 118 | serviceAdded = true; 119 | } 120 | 121 | protected: 122 | BLE &ble; 123 | GattCharacteristic manufacturersNameStringCharacteristic; 124 | GattCharacteristic modelNumberStringCharacteristic; 125 | GattCharacteristic serialNumberStringCharacteristic; 126 | GattCharacteristic hardwareRevisionStringCharacteristic; 127 | GattCharacteristic firmwareRevisionStringCharacteristic; 128 | GattCharacteristic softwareRevisionStringCharacteristic; 129 | ReadOnlyGattCharacteristic pnpIDCharacteristic; 130 | }; 131 | 132 | #endif /* #ifndef __BLE_HID_DEVICE_INFORMATION_SERVICE_H__*/ 133 | 134 | 135 | -------------------------------------------------------------------------------- /src/BLE_HID/HIDServiceBase.cpp: -------------------------------------------------------------------------------- 1 | #include "mbed.h" 2 | #include "HIDServiceBase.h" 3 | 4 | HIDServiceBase::HIDServiceBase(BLE &_ble, 5 | report_map_t reportMap, 6 | uint8_t reportMapSize, 7 | report_t inputReport, 8 | report_t outputReport, 9 | report_t featureReport, 10 | uint8_t inputReportLength, 11 | uint8_t outputReportLength, 12 | uint8_t featureReportLength) : 13 | ble(_ble), 14 | reportMapLength(reportMapSize), 15 | 16 | inputReport(inputReport), 17 | outputReport(outputReport), 18 | featureReport(featureReport), 19 | 20 | inputReportLength(inputReportLength), 21 | outputReportLength(outputReportLength), 22 | featureReportLength(featureReportLength), 23 | 24 | protocolMode(REPORT_PROTOCOL), 25 | 26 | inputReportReferenceDescriptor(BLE_UUID_DESCRIPTOR_REPORT_REFERENCE, 27 | (uint8_t *)&inputReportReferenceData, 2, 2), 28 | outputReportReferenceDescriptor(BLE_UUID_DESCRIPTOR_REPORT_REFERENCE, 29 | (uint8_t *)&outputReportReferenceData, 2, 2), 30 | featureReportReferenceDescriptor(BLE_UUID_DESCRIPTOR_REPORT_REFERENCE, 31 | (uint8_t *)&featureReportReferenceData, 2, 2), 32 | 33 | protocolModeCharacteristic(GattCharacteristic::UUID_PROTOCOL_MODE_CHAR, &protocolMode, 1, 1, 34 | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_READ 35 | | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_WRITE_WITHOUT_RESPONSE), 36 | 37 | inputReportCharacteristic(GattCharacteristic::UUID_REPORT_CHAR, 38 | (uint8_t *)inputReport, inputReportLength, inputReportLength, 39 | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_READ 40 | | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_NOTIFY 41 | | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_WRITE, 42 | inputReportDescriptors(), 1), 43 | 44 | outputReportCharacteristic(GattCharacteristic::UUID_REPORT_CHAR, 45 | (uint8_t *)outputReport, outputReportLength, outputReportLength, 46 | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_READ 47 | | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_WRITE_WITHOUT_RESPONSE 48 | | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_WRITE, 49 | outputReportDescriptors(), 1), 50 | 51 | featureReportCharacteristic(GattCharacteristic::UUID_REPORT_CHAR, 52 | (uint8_t *)featureReport, featureReportLength, featureReportLength, 53 | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_READ 54 | | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_WRITE, 55 | featureReportDescriptors(), 1), 56 | 57 | /* 58 | * We need to set reportMap content as const, in order to let the compiler put it into flash 59 | * instead of RAM. The characteristic is read-only so it won't be written, but 60 | * GattCharacteristic constructor takes non-const arguments only. Hence the cast. 61 | */ 62 | reportMapCharacteristic(GattCharacteristic::UUID_REPORT_MAP_CHAR, 63 | const_cast(reportMap), reportMapLength, reportMapLength, 64 | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_READ), 65 | 66 | HIDInformationCharacteristic(GattCharacteristic::UUID_HID_INFORMATION_CHAR, HIDInformation()), 67 | HIDControlPointCharacteristic(GattCharacteristic::UUID_HID_CONTROL_POINT_CHAR, 68 | &controlPointCommand, 1, 1, 69 | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_WRITE_WITHOUT_RESPONSE) 70 | 71 | { 72 | static GattCharacteristic *characteristics[] = { 73 | &HIDInformationCharacteristic, 74 | &reportMapCharacteristic, 75 | &protocolModeCharacteristic, 76 | &HIDControlPointCharacteristic, 77 | NULL, 78 | NULL, 79 | NULL, 80 | NULL, 81 | NULL 82 | }; 83 | 84 | unsigned int charIndex = 4; 85 | /* 86 | * Report characteristics are optional, and depend on the reportMap descriptor 87 | * Note: at least one should be present, but we don't check that at the moment. 88 | */ 89 | if (inputReportLength) 90 | characteristics[charIndex++] = &inputReportCharacteristic; 91 | if (outputReportLength) 92 | characteristics[charIndex++] = &outputReportCharacteristic; 93 | if (featureReportLength) 94 | characteristics[charIndex++] = &featureReportCharacteristic; 95 | 96 | /* TODO: let children add some more characteristics, namely boot keyboard and mouse (They are 97 | * mandatory as per HIDS spec.) Ex: 98 | * 99 | * addExtraCharacteristics(characteristics, int& charIndex); 100 | */ 101 | 102 | GattService service(GattService::UUID_HUMAN_INTERFACE_DEVICE_SERVICE, 103 | characteristics, charIndex); 104 | 105 | ble.gattServer().addService(service); 106 | 107 | /* 108 | * Change preferred connection params, in order to optimize the notification frequency. Most 109 | * OSes seem to respect this, even though they are not required to. 110 | * 111 | * Some OSes don't handle reconnection well, at the moment, so we set the maximum possible 112 | * timeout, 32 seconds 113 | */ 114 | 115 | /* 116 | uint16_t minInterval = Gap::MSEC_TO_GAP_DURATION_UNITS(reportTickerDelay / 2); 117 | if (minInterval < 6) 118 | minInterval = 6; 119 | uint16_t maxInterval = minInterval * 2; 120 | Gap::ConnectionParams_t params = {minInterval, maxInterval, 0, 3200}; 121 | 122 | ble.gap().setPreferredConnectionParams(¶ms); 123 | */ 124 | 125 | 126 | //protocolModeCharacteristic.setReadSecurityRequirement(ble::att_security_requirement_t::UNAUTHENTICATED); 127 | //reportMapCharacteristic.setReadSecurityRequirement(ble::att_security_requirement_t::UNAUTHENTICATED); 128 | //inputReportCharacteristic.setReadSecurityRequirement(ble::att_security_requirement_t::UNAUTHENTICATED); 129 | //outputReportCharacteristic.setReadSecurityRequirement(ble::att_security_requirement_t::UNAUTHENTICATED); 130 | //featureReportCharacteristic.setReadSecurityRequirement(ble::att_security_requirement_t::UNAUTHENTICATED); 131 | } 132 | 133 | 134 | GattAttribute** HIDServiceBase::inputReportDescriptors() { 135 | inputReportReferenceData.ID = 0; 136 | inputReportReferenceData.type = INPUT_REPORT; 137 | 138 | static GattAttribute * descs[] = { 139 | &inputReportReferenceDescriptor, 140 | }; 141 | return descs; 142 | } 143 | 144 | GattAttribute** HIDServiceBase::outputReportDescriptors() { 145 | outputReportReferenceData.ID = 0; 146 | outputReportReferenceData.type = OUTPUT_REPORT; 147 | 148 | static GattAttribute * descs[] = { 149 | &outputReportReferenceDescriptor, 150 | }; 151 | return descs; 152 | } 153 | 154 | GattAttribute** HIDServiceBase::featureReportDescriptors() { 155 | featureReportReferenceData.ID = 0; 156 | featureReportReferenceData.type = FEATURE_REPORT; 157 | 158 | static GattAttribute * descs[] = { 159 | &featureReportReferenceDescriptor, 160 | }; 161 | return descs; 162 | } 163 | 164 | 165 | HID_information_t* HIDServiceBase::HIDInformation() { 166 | static HID_information_t info = {HID_VERSION_1_11, 0x00, 0x03}; 167 | //printf("read hid information\n"); 168 | 169 | return &info; 170 | } 171 | 172 | ble_error_t HIDServiceBase::send(const report_t report) { 173 | return ble.gattServer().write(inputReportCharacteristic.getValueHandle(), 174 | report, 175 | inputReportLength); 176 | } 177 | 178 | ble_error_t HIDServiceBase::read(report_t report) { 179 | // TODO. For the time being, we'll just have HID input reports... 180 | //printf("read not implemented\n"); 181 | return BLE_ERROR_NOT_IMPLEMENTED; 182 | } 183 | 184 | 185 | -------------------------------------------------------------------------------- /src/BLE_HID/HIDServiceBase.h: -------------------------------------------------------------------------------- 1 | #ifndef HID_SERVICE_BASE_H_ 2 | #define HID_SERVICE_BASE_H_ 3 | 4 | #include "mbed.h" 5 | 6 | #include "ble/BLE.h" 7 | #include "HID_types.h" 8 | 9 | #define BLE_UUID_DESCRIPTOR_REPORT_REFERENCE 0x2908 10 | 11 | typedef const uint8_t report_map_t[]; 12 | typedef const uint8_t * report_t; 13 | 14 | typedef struct { 15 | uint16_t bcdHID; 16 | uint8_t bCountryCode; 17 | uint8_t flags; 18 | } HID_information_t; 19 | 20 | enum ReportType { 21 | INPUT_REPORT = 0x1, 22 | OUTPUT_REPORT = 0x2, 23 | FEATURE_REPORT = 0x3, 24 | }; 25 | 26 | enum ProtocolMode { 27 | BOOT_PROTOCOL = 0x0, 28 | REPORT_PROTOCOL = 0x1, 29 | }; 30 | 31 | typedef struct { 32 | uint8_t ID; 33 | uint8_t type; 34 | } report_reference_t; 35 | 36 | 37 | class HIDServiceBase { 38 | public: 39 | /** 40 | * Constructor 41 | * 42 | * @param _ble 43 | * BLE object to add this service to 44 | * @param reportMap 45 | * Byte array representing the input/output report formats. In USB HID jargon, it 46 | * is called "HID report descriptor". 47 | * @param reportMapLength 48 | * Size of the reportMap array 49 | * @param outputReportLength 50 | * Maximum length of a sent report (up to 64 bytes) (default: 64 bytes) 51 | * @param inputReportLength 52 | * Maximum length of a received report (up to 64 bytes) (default: 64 bytes) 53 | * @param inputReportTickerDelay 54 | * Delay between input report notifications, in ms. Acceptable values depend directly on 55 | * GAP's connInterval parameter, so it shouldn't be less than 12ms 56 | * Preferred GAP connection interval is set after this value, in order to send 57 | * notifications as quick as possible: minimum connection interval will be set to 58 | * (inputReportTickerDelay / 2) 59 | */ 60 | HIDServiceBase(BLE &_ble, 61 | report_map_t reportMap, 62 | uint8_t reportMapLength, 63 | report_t inputReport, 64 | report_t outputReport, 65 | report_t featureReport, 66 | uint8_t inputReportLength = 0, 67 | uint8_t outputReportLength = 0, 68 | uint8_t featureReportLength = 0); 69 | 70 | /** 71 | * Send Report 72 | * 73 | * @param report Report to send. Must be of size @ref inputReportLength 74 | * @return The write status 75 | * 76 | * @note Don't call send() directly for multiple reports! Use reportTicker for that, in order 77 | * to avoid overloading the BLE stack, and let it handle events between each report. 78 | */ 79 | virtual ble_error_t send(const report_t report); 80 | 81 | /** 82 | * Read Report 83 | * 84 | * @param report Report to fill. Must be of size @ref outputReportLength 85 | * @return The read status 86 | */ 87 | virtual ble_error_t read(report_t report); 88 | 89 | 90 | protected: 91 | /** 92 | * Called by BLE API when data has been successfully sent. 93 | * 94 | * @param count Number of reports sent 95 | * 96 | * @note Subclasses can override this to avoid starting the report ticker when there is nothing 97 | * to send 98 | */ 99 | 100 | /** 101 | * Create the Gatt descriptor for a report characteristic 102 | */ 103 | GattAttribute** inputReportDescriptors(); 104 | GattAttribute** outputReportDescriptors(); 105 | GattAttribute** featureReportDescriptors(); 106 | 107 | /** 108 | * Create the HID information structure 109 | */ 110 | HID_information_t* HIDInformation(); 111 | 112 | protected: 113 | BLE &ble; 114 | 115 | int reportMapLength; 116 | 117 | report_t inputReport; 118 | report_t outputReport; 119 | report_t featureReport; 120 | 121 | uint8_t inputReportLength; 122 | uint8_t outputReportLength; 123 | uint8_t featureReportLength; 124 | 125 | uint8_t controlPointCommand; 126 | uint8_t protocolMode; 127 | 128 | report_reference_t inputReportReferenceData; 129 | report_reference_t outputReportReferenceData; 130 | report_reference_t featureReportReferenceData; 131 | 132 | GattAttribute inputReportReferenceDescriptor; 133 | GattAttribute outputReportReferenceDescriptor; 134 | GattAttribute featureReportReferenceDescriptor; 135 | 136 | // Optional gatt characteristics: 137 | GattCharacteristic protocolModeCharacteristic; 138 | 139 | // Report characteristics (each sort of optional) 140 | GattCharacteristic inputReportCharacteristic; 141 | GattCharacteristic outputReportCharacteristic; 142 | GattCharacteristic featureReportCharacteristic; 143 | 144 | // Required gatt characteristics: Report Map, Information, Control Point 145 | GattCharacteristic reportMapCharacteristic; 146 | ReadOnlyGattCharacteristic HIDInformationCharacteristic; 147 | GattCharacteristic HIDControlPointCharacteristic; 148 | 149 | }; 150 | 151 | #endif /* !HID_SERVICE_BASE_H_ */ 152 | 153 | -------------------------------------------------------------------------------- /src/BLE_HID/HID_types.h: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2015 mbed.org, MIT License 2 | * 3 | * Permission is hereby granted, free of charge, to any person obtaining a copy of this software 4 | * and associated documentation files (the "Software"), to deal in the Software without 5 | * restriction, including without limitation the rights to use, copy, modify, merge, publish, 6 | * distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the 7 | * Software is furnished to do so, subject to the following conditions: 8 | * 9 | * The above copyright notice and this permission notice shall be included in all copies or 10 | * substantial portions of the Software. 11 | * 12 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 13 | * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 14 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 15 | * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 16 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 17 | * 18 | * Note: this file was pulled from the USBHID library, in mbed SDK 19 | */ 20 | 21 | #ifndef USBCLASS_HID_TYPES 22 | #define USBCLASS_HID_TYPES 23 | 24 | #include 25 | 26 | 27 | typedef struct { 28 | uint8_t vendorID_source; 29 | uint16_t vendorID; 30 | uint16_t productID; 31 | uint16_t productVersion; 32 | } PnPID_t; 33 | 34 | 35 | /* */ 36 | #define HID_VERSION_1_11 (0x0111) 37 | 38 | /* HID Class */ 39 | #define HID_CLASS (3) 40 | #define HID_SUBCLASS_NONE (0) 41 | #define HID_PROTOCOL_NONE (0) 42 | #define HID_PROTOCOL_KEYBOARD (1) 43 | #define HID_PROTOCOL_MOUSE (2) 44 | 45 | /* Descriptors */ 46 | #define HID_DESCRIPTOR (33) 47 | #define HID_DESCRIPTOR_LENGTH (0x09) 48 | #define REPORT_DESCRIPTOR (34) 49 | 50 | /* Class requests */ 51 | #define GET_REPORT (0x1) 52 | #define GET_IDLE (0x2) 53 | #define SET_REPORT (0x9) 54 | #define SET_IDLE (0xa) 55 | 56 | /* HID Class Report Descriptor */ 57 | /* Short items: size is 0, 1, 2 or 3 specifying 0, 1, 2 or 4 (four) bytes */ 58 | /* of data as per HID Class standard */ 59 | 60 | /* Main items */ 61 | #define INPUT(size) (0x80 | size) 62 | #define OUTPUT(size) (0x90 | size) 63 | #define FEATURE(size) (0xb0 | size) 64 | #define COLLECTION(size) (0xa0 | size) 65 | #define END_COLLECTION(size) (0xc0 | size) 66 | 67 | /* Global items */ 68 | #define USAGE_PAGE(size) (0x04 | size) 69 | #define LOGICAL_MINIMUM(size) (0x14 | size) 70 | #define LOGICAL_MAXIMUM(size) (0x24 | size) 71 | #define PHYSICAL_MINIMUM(size) (0x34 | size) 72 | #define PHYSICAL_MAXIMUM(size) (0x44 | size) 73 | #define UNIT_EXPONENT(size) (0x54 | size) 74 | #define UNIT(size) (0x64 | size) 75 | #define REPORT_SIZE(size) (0x74 | size) 76 | #define REPORT_ID(size) (0x84 | size) 77 | #define REPORT_COUNT(size) (0x94 | size) 78 | #define PUSH(size) (0xa4 | size) 79 | #define POP(size) (0xb4 | size) 80 | 81 | /* Local items */ 82 | #define USAGE(size) (0x08 | size) 83 | #define USAGE_MINIMUM(size) (0x18 | size) 84 | #define USAGE_MAXIMUM(size) (0x28 | size) 85 | #define DESIGNATOR_INDEX(size) (0x38 | size) 86 | #define DESIGNATOR_MINIMUM(size) (0x48 | size) 87 | #define DESIGNATOR_MAXIMUM(size) (0x58 | size) 88 | #define STRING_INDEX(size) (0x78 | size) 89 | #define STRING_MINIMUM(size) (0x88 | size) 90 | #define STRING_MAXIMUM(size) (0x98 | size) 91 | #define DELIMITER(size) (0xa8 | size) 92 | 93 | /* HID Report */ 94 | /* Where report IDs are used the first byte of 'data' will be the */ 95 | /* report ID and 'length' will include this report ID byte. */ 96 | 97 | #define MAX_HID_REPORT_SIZE (64) 98 | 99 | typedef struct { 100 | uint32_t length; 101 | uint8_t data[MAX_HID_REPORT_SIZE]; 102 | } HID_REPORT; 103 | 104 | #endif 105 | 106 | 107 | -------------------------------------------------------------------------------- /src/BLE_HID/mouse.cpp: -------------------------------------------------------------------------------- 1 | #include "mouse.h" 2 | 3 | uint8_t report[] = { 0, 0, 0, 0 }; 4 | 5 | BLEMouse::BLEMouse(BLE &ble) : HIDServiceBase(ble, 6 | MOUSE_REPORT_MAP, 7 | sizeof(MOUSE_REPORT_MAP), 8 | report, 9 | NULL, 10 | NULL, 11 | sizeof(inputReport)), 12 | _button(0) 13 | { 14 | } 15 | 16 | void BLEMouse::click(uint8_t b) { 17 | this->press(b); 18 | this->release(b); 19 | } 20 | 21 | void BLEMouse::move(signed char x, signed char y, signed char wheel) { 22 | unsigned char mouseMove[4]= { 0x00, 0x00, 0x00, 0x00 }; 23 | 24 | // send key code 25 | mouseMove[0] = this->_button; 26 | mouseMove[1] = x; 27 | mouseMove[2] = y; 28 | mouseMove[3] = wheel; 29 | 30 | this->send(mouseMove); 31 | } 32 | 33 | void BLEMouse::press(uint8_t b) { 34 | this->_button |= b; 35 | 36 | this->move(0, 0, 0); 37 | } 38 | 39 | void BLEMouse::release(uint8_t b) { 40 | this->_button &= ~b; 41 | 42 | this->move(0, 0, 0); 43 | } 44 | 45 | bool BLEMouse::isPressed(uint8_t b) { 46 | return ((this->_button & b) != 0); 47 | } 48 | 49 | -------------------------------------------------------------------------------- /src/BLE_HID/mouse.h: -------------------------------------------------------------------------------- 1 | #include "mbed.h" 2 | 3 | #include "HIDServiceBase.h" 4 | 5 | #define MOUSE_BUTTON_LEFT 0x01 6 | #define MOUSE_BUTTON_RIGHT 0x02 7 | #define MOUSE_BUTTON_MIDDLE 0x04 8 | 9 | report_map_t MOUSE_REPORT_MAP = { 10 | USAGE_PAGE(1), 0x01, // Generic Desktop 11 | USAGE(1), 0x02, // Mouse 12 | COLLECTION(1), 0x01, // Application 13 | USAGE(1), 0x01, // Pointer 14 | COLLECTION(1), 0x00, // Physical 15 | USAGE_PAGE(1), 0x09, // Buttons 16 | USAGE_MINIMUM(1), 0x01, 17 | USAGE_MAXIMUM(1), 0x03, 18 | LOGICAL_MINIMUM(1), 0x00, 19 | LOGICAL_MAXIMUM(1), 0x01, 20 | REPORT_COUNT(1), 0x03, // 3 bits (Buttons) 21 | REPORT_SIZE(1), 0x01, 22 | INPUT(1), 0x02, // Data, Variable, Absolute 23 | REPORT_COUNT(1), 0x01, // 5 bits (Padding) 24 | REPORT_SIZE(1), 0x05, 25 | INPUT(1), 0x01, // Constant 26 | USAGE_PAGE(1), 0x01, // Generic Desktop 27 | USAGE(1), 0x30, // X 28 | USAGE(1), 0x31, // Y 29 | USAGE(1), 0x38, // Wheel 30 | LOGICAL_MINIMUM(1), 0x81, // -127 31 | LOGICAL_MAXIMUM(1), 0x7f, // 127 32 | REPORT_SIZE(1), 0x08, // Three bytes 33 | REPORT_COUNT(1), 0x03, 34 | INPUT(1), 0x06, // Data, Variable, Relative 35 | END_COLLECTION(0), 36 | END_COLLECTION(0), 37 | }; 38 | 39 | class BLEMouse : public HIDServiceBase 40 | { 41 | public: 42 | BLEMouse(BLE &ble); 43 | 44 | void click(uint8_t b = MOUSE_BUTTON_LEFT); 45 | void move(signed char x, signed char y, signed char wheel = 0); 46 | void press(uint8_t b = MOUSE_BUTTON_LEFT); 47 | void release(uint8_t b = MOUSE_BUTTON_LEFT); 48 | bool isPressed(uint8_t b = MOUSE_BUTTON_LEFT); 49 | 50 | private: 51 | unsigned char _button; 52 | }; -------------------------------------------------------------------------------- /src/HIDMouse.cpp: -------------------------------------------------------------------------------- 1 | #include "mbed.h" 2 | #include "rtos.h" 3 | #include "ble/BLE.h" 4 | #include "ble/Gap.h" 5 | #include "SecurityManager.h" 6 | #include "events/mbed_events.h" 7 | #include "BLE_HID/HIDServiceBase.h" 8 | #include "ble/services/BatteryService.h" 9 | #include "BLE_HID/HIDDeviceInformationService.h" 10 | #include "HIDMouse.h" 11 | 12 | /** 13 | * This program implements a complete HID-over-Gatt Profile: 14 | * - HID is provided by MouseService 15 | * - Battery Service 16 | * - Device Information Service 17 | * 18 | * Complete strings can be sent over BLE using printf. Please note, however, than a 12char string 19 | * will take about 500ms to transmit, principally because of the limited notification rate in BLE. 20 | * KeyboardService uses a circular buffer to store the strings to send, and calls to putc will fail 21 | * once this buffer is full. This will result in partial strings being sent to the client. 22 | */ 23 | 24 | rtos::Thread t; 25 | 26 | typedef ble_error_t (Gap::*disconnect_call_t)(ble::connection_handle_t, ble::local_disconnection_reason_t); 27 | const static disconnect_call_t disconnect_call = &Gap::disconnect; 28 | 29 | void HIDMouse::schedule_ble_events(BLE::OnEventsToProcessCallbackContext *context) { 30 | _event_queue.call(mbed::Callback(&context->ble, &BLE::processEvents)); 31 | } 32 | 33 | HIDMouse::HIDMouse(BLE &ble): BLEMouse(ble), 34 | _battery_level(50), 35 | device_name("Example"), 36 | manufacturersName("ARM"), 37 | _ble(ble), 38 | _event_queue(event_queue), 39 | _battery_uuid(GattService::UUID_BATTERY_SERVICE), 40 | _battery_service(_ble, _battery_level), 41 | batteryService(false), 42 | _handle(0), 43 | _adv_data_builder(_adv_buffer), 44 | ifconnected(false){ 45 | } 46 | 47 | void HIDMouse::start(){ 48 | _ble.onEventsToProcess( 49 | makeFunctionPointer(this, &HIDMouse::schedule_ble_events) 50 | ); 51 | 52 | _ble.securityManager().setSecurityManagerEventHandler(this); 53 | _ble.gap().setEventHandler(this); 54 | _ble.init(this, &HIDMouse::on_init_complete); 55 | t.start(mbed::callback(&_event_queue, &events::EventQueue::dispatch_forever)); 56 | 57 | } 58 | 59 | void HIDMouse::click(uint8_t b){ 60 | BLEMouse::click(b); 61 | } 62 | 63 | void HIDMouse::move(signed char x, signed char y, signed char wheel ){ 64 | BLEMouse::move(x, y, wheel); 65 | } 66 | 67 | void HIDMouse::press(uint8_t b){ 68 | BLEMouse::press(b); 69 | } 70 | 71 | void HIDMouse::release(uint8_t b){ 72 | BLEMouse::release(b); 73 | } 74 | 75 | bool HIDMouse::isPressed(uint8_t b){ 76 | BLEMouse::isPressed(b); 77 | } 78 | 79 | bool HIDMouse::isConnected(){ 80 | return ifconnected; 81 | } 82 | 83 | 84 | void HIDMouse::setManufacturerName(const char *manufacturersName2){ 85 | manufacturersName = manufacturersName2; 86 | } 87 | 88 | void HIDMouse::setDeviceName(const char *device_name2){ 89 | device_name = device_name2; 90 | } 91 | 92 | void HIDMouse::setBatteryLevel(uint8_t _battery_level){ 93 | batteryService = true; 94 | _battery_service.updateBatteryLevel(_battery_level); 95 | } 96 | 97 | void HIDMouse::on_init_complete(BLE::InitializationCompleteCallbackContext *params){ 98 | if (params->error != BLE_ERROR_NONE) { 99 | return; 100 | } 101 | 102 | ble_error_t error; 103 | /* If the security manager is required this needs to be called before any 104 | * calls to the Security manager happen. */ 105 | error = _ble.securityManager().init( 106 | true, 107 | false, 108 | SecurityManager::IO_CAPS_NONE, 109 | NULL, 110 | false, 111 | NULL 112 | ); 113 | 114 | if (error) { 115 | //printf("Error during init %d\r\n", error); 116 | return; 117 | } 118 | 119 | error = _ble.securityManager().preserveBondingStateOnReset(true); 120 | 121 | if (error) { 122 | //printf("Error during preserveBondingStateOnReset %d\r\n", error); 123 | } 124 | 125 | 126 | start_advertising(); 127 | } 128 | 129 | void setManufacturerInfo(BLE &ble, const char *manufacturersName) 130 | { 131 | 132 | PnPID_t pnpID; 133 | pnpID.vendorID_source = 0x2; // from the USB Implementer's Forum 134 | pnpID.vendorID = 0x0D28; // NXP 135 | pnpID.productID = 0x0204; // CMSIS-DAP (well, it's a keyboard but oh well) 136 | pnpID.productVersion = 0x0100; // v1.0 137 | HIDDeviceInformationService deviceInfo(ble, manufacturersName, "m1", "abc", "def", "ghi", "jkl", &pnpID); 138 | 139 | } 140 | 141 | void HIDMouse::start_advertising(){ 142 | 143 | ble::AdvertisingParameters adv_parameters( 144 | ble::advertising_type_t::CONNECTABLE_UNDIRECTED, 145 | ble::adv_interval_t(ble::millisecond_t(100)) 146 | ); 147 | adv_parameters.setTxPower(ble::advertising_power_t(-10)); 148 | 149 | setManufacturerInfo(_ble, manufacturersName); 150 | 151 | _adv_data_builder.setFlags(); 152 | _adv_data_builder.setName(device_name); 153 | _adv_data_builder.setAppearance(ble::adv_data_appearance_t::MOUSE); 154 | if(batteryService){ 155 | _adv_data_builder.setLocalServiceList(mbed::make_Span(&_battery_uuid, 1)); 156 | } 157 | 158 | 159 | ble_error_t error = _ble.gap().setAdvertisingParameters( 160 | ble::advertising_type_t::CONNECTABLE_UNDIRECTED, 161 | adv_parameters 162 | ); 163 | 164 | if (error) { 165 | // print_error(error, "_ble.gap().setAdvertisingParameters() failed"); 166 | return; 167 | } 168 | 169 | error = _ble.gap().setAdvertisingPayload( 170 | ble::LEGACY_ADVERTISING_HANDLE, 171 | _adv_data_builder.getAdvertisingData() 172 | ); 173 | 174 | if (error) { 175 | //print_error(error, "_ble.gap().setAdvertisingPayload() failed"); 176 | return; 177 | } 178 | 179 | /* Start advertising */ 180 | 181 | error = _ble.gap().startAdvertising(ble::LEGACY_ADVERTISING_HANDLE); 182 | 183 | if (error) { 184 | //print_error(error, "_ble.gap().startAdvertising() failed"); 185 | return; 186 | } 187 | 188 | _ble.securityManager().setPairingRequestAuthorisation(false); 189 | } 190 | 191 | 192 | void HIDMouse::onDisconnectionComplete(const ble::DisconnectionCompleteEvent&) { 193 | ifconnected = false; 194 | _ble.gap().startAdvertising(ble::LEGACY_ADVERTISING_HANDLE); 195 | _ble.securityManager().setPairingRequestAuthorisation(false); 196 | } 197 | 198 | void HIDMouse::onConnectionComplete(const ble::ConnectionCompleteEvent &event) { 199 | ifconnected = true; 200 | 201 | ble_error_t error; 202 | 203 | _handle = event.getConnectionHandle(); 204 | 205 | error = _ble.securityManager().setLinkSecurity( 206 | _handle, 207 | SecurityManager::SECURITY_MODE_ENCRYPTION_NO_MITM 208 | ); 209 | 210 | if (error) { 211 | //printf("Error during SM::setLinkSecurity %d\r\n", error); 212 | return; 213 | } 214 | 215 | } 216 | 217 | 218 | 219 | void HIDMouse::pairingRequest( 220 | ble::connection_handle_t connectionHandle 221 | ) { 222 | //printf("Pairing requested - authorising\r\n"); 223 | _ble.securityManager().acceptPairingRequest(connectionHandle); 224 | } 225 | 226 | void HIDMouse::pairingResult( 227 | ble::connection_handle_t connectionHandle, 228 | SecurityManager::SecurityCompletionStatus_t result 229 | ) { 230 | if (result == SecurityManager::SEC_STATUS_SUCCESS) { 231 | //printf("Pairing successful\r\n"); 232 | } else { 233 | //printf("Pairing failed\r\n"); 234 | } 235 | } 236 | 237 | 238 | void HIDMouse::begin() 239 | { 240 | HIDMouse::start(); 241 | } 242 | 243 | -------------------------------------------------------------------------------- /src/HIDMouse.h: -------------------------------------------------------------------------------- 1 | #include "mbed.h" 2 | #include "ble/BLE.h" 3 | #include "ble/services/BatteryService.h" 4 | #include "events/mbed_events.h" 5 | #include "BLE_HID/mouse.h" 6 | 7 | static events::EventQueue event_queue(/* event count */ 16 * EVENTS_EVENT_SIZE); 8 | 9 | 10 | class HIDMouse : public ble::Gap::EventHandler, 11 | public SecurityManager::EventHandler, 12 | public BLEMouse{ 13 | 14 | 15 | public: 16 | BLE &_ble; 17 | HIDMouse(BLE &ble = BLE::Instance()); 18 | void begin(); 19 | 20 | void click(uint8_t b = MOUSE_BUTTON_LEFT); 21 | void move(signed char x, signed char y, signed char wheel = 0); 22 | void press(uint8_t b = MOUSE_BUTTON_LEFT); 23 | void release(uint8_t b = MOUSE_BUTTON_LEFT); 24 | bool isPressed(uint8_t b = MOUSE_BUTTON_LEFT); 25 | 26 | bool isConnected(void); 27 | void setManufacturerName(const char *manufacturersName2); 28 | void setDeviceName(const char *device_name2); 29 | void setBatteryLevel(uint8_t _battery_level); 30 | 31 | private: 32 | 33 | void schedule_ble_events(BLE::OnEventsToProcessCallbackContext *context); 34 | events::EventQueue &_event_queue = event_queue; 35 | 36 | uint8_t _battery_level; 37 | const char *manufacturersName; 38 | const char *device_name; 39 | 40 | UUID _battery_uuid; 41 | BatteryService _battery_service; 42 | 43 | bool batteryService; 44 | uint8_t _adv_buffer[ble::LEGACY_ADVERTISING_MAX_SIZE]; 45 | ble::AdvertisingDataBuilder _adv_data_builder; 46 | ble::connection_handle_t _handle; 47 | bool ifconnected; 48 | 49 | private: 50 | void start(void); 51 | void on_init_complete(BLE::InitializationCompleteCallbackContext *params); 52 | void start_advertising(); 53 | virtual void onDisconnectionComplete(const ble::DisconnectionCompleteEvent&); 54 | virtual void onConnectionComplete(const ble::ConnectionCompleteEvent &event); 55 | virtual void pairingResult( 56 | ble::connection_handle_t connectionHandle, 57 | SecurityManager::SecurityCompletionStatus_t result 58 | ); 59 | int _dispatch_event; 60 | virtual void pairingRequest( 61 | ble::connection_handle_t connectionHandle 62 | ); 63 | 64 | }; 65 | -------------------------------------------------------------------------------- /src/mbed_pins.txt: -------------------------------------------------------------------------------- 1 | Arduino Pins Corresponding Mbed name 2 | D0/TX P1_3 (not recommended for use) 3 | D1/RX P1_10 (not recommended for use) 4 | D2 P1_11 5 | D3 P1_12 6 | D4 P1_15 7 | D5 P1_13 8 | D6 P1_14 9 | D7 P1_23 10 | D8 P1_21 11 | D9 P1_27 12 | D10 P1_2 13 | D11 P1_1 14 | D12 P1_8 15 | D13/Built in LED P0_13 16 | A0 P0_4 17 | A1 P0_5 18 | A2 P0_30 19 | A3 P0_29 20 | A4 P0_31 21 | A5 P0_2 22 | A6 P0_28 23 | A7 P0_3 24 | Power LED P1_9 --------------------------------------------------------------------------------