BLE HID keyboard with gesture
Dependencies: BLE_API BLE_HID PAJ7620U2 mbed nRF51822
We have full tutorial, please visit our blog
main.cpp@2:6109e375f9a7, 2016-12-30 (annotated)
- Committer:
- mtmkimi
- Date:
- Fri Dec 30 08:36:50 2016 +0000
- Revision:
- 2:6109e375f9a7
- Parent:
- 0:55c7f79a524c
- Child:
- 3:656f8fb89f05
Pack PAJ7620 to library and rename device.
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
mtmkimi | 2:6109e375f9a7 | 1 | /* Copyright (c) 2016 MtM Technology Corporation, MIT License |
mtmkimi | 2:6109e375f9a7 | 2 | * |
mtmkimi | 2:6109e375f9a7 | 3 | * Permission is hereby granted, free of charge, to any person obtaining a copy of this software |
mtmkimi | 2:6109e375f9a7 | 4 | * and associated documentation files (the "Software"), to deal in the Software without restriction, |
mtmkimi | 2:6109e375f9a7 | 5 | * including without limitation the rights to use, copy, modify, merge, publish, distribute, |
mtmkimi | 2:6109e375f9a7 | 6 | * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is |
mtmkimi | 2:6109e375f9a7 | 7 | * furnished to do so, subject to the following conditions: |
mtmkimi | 2:6109e375f9a7 | 8 | * |
mtmkimi | 2:6109e375f9a7 | 9 | * The above copyright notice and this permission notice shall be included in all copies or |
mtmkimi | 2:6109e375f9a7 | 10 | * substantial portions of the Software. |
mtmkimi | 2:6109e375f9a7 | 11 | * |
mtmkimi | 2:6109e375f9a7 | 12 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING |
mtmkimi | 2:6109e375f9a7 | 13 | * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND |
mtmkimi | 2:6109e375f9a7 | 14 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, |
mtmkimi | 2:6109e375f9a7 | 15 | * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
mtmkimi | 2:6109e375f9a7 | 16 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
mtmkimi | 2:6109e375f9a7 | 17 | */ |
bcc6 | 0:55c7f79a524c | 18 | #include "mbed.h" |
bcc6 | 0:55c7f79a524c | 19 | #include "ble/BLE.h" |
bcc6 | 0:55c7f79a524c | 20 | #include "ble/services/BatteryService.h" |
bcc6 | 0:55c7f79a524c | 21 | #include "ble/services/DeviceInformationService.h" |
bcc6 | 0:55c7f79a524c | 22 | |
mtmkimi | 2:6109e375f9a7 | 23 | #include "PAJ7620U2.h" |
bcc6 | 0:55c7f79a524c | 24 | |
bcc6 | 0:55c7f79a524c | 25 | #include "HIDServiceBase.h" |
bcc6 | 0:55c7f79a524c | 26 | //#include "MouseService.h" |
bcc6 | 0:55c7f79a524c | 27 | //#include "JoystickService.h" |
bcc6 | 0:55c7f79a524c | 28 | #include "KeyboardService.h" |
bcc6 | 0:55c7f79a524c | 29 | |
bcc6 | 0:55c7f79a524c | 30 | |
bcc6 | 0:55c7f79a524c | 31 | /** |
bcc6 | 0:55c7f79a524c | 32 | * IO capabilities of the device. During development, you most likely want "JustWorks", which means |
bcc6 | 0:55c7f79a524c | 33 | * no IO capabilities. |
bcc6 | 0:55c7f79a524c | 34 | * It is also possible to use IO_CAPS_DISPLAY_ONLY to generate and show a pincode on the serial |
bcc6 | 0:55c7f79a524c | 35 | * output. |
bcc6 | 0:55c7f79a524c | 36 | */ |
bcc6 | 0:55c7f79a524c | 37 | #ifndef HID_SECURITY_IOCAPS |
bcc6 | 0:55c7f79a524c | 38 | #define HID_SECURITY_IOCAPS (SecurityManager::IO_CAPS_NONE) |
bcc6 | 0:55c7f79a524c | 39 | #endif |
bcc6 | 0:55c7f79a524c | 40 | |
bcc6 | 0:55c7f79a524c | 41 | /** |
bcc6 | 0:55c7f79a524c | 42 | * Security level. MITM disabled forces "Just Works". If you require MITM, HID_SECURITY_IOCAPS must |
bcc6 | 0:55c7f79a524c | 43 | * be at least IO_CAPS_DISPLAY_ONLY. |
bcc6 | 0:55c7f79a524c | 44 | */ |
bcc6 | 0:55c7f79a524c | 45 | #ifndef HID_SECURITY_REQUIRE_MITM |
bcc6 | 0:55c7f79a524c | 46 | #define HID_SECURITY_REQUIRE_MITM false |
bcc6 | 0:55c7f79a524c | 47 | #endif |
bcc6 | 0:55c7f79a524c | 48 | |
bcc6 | 0:55c7f79a524c | 49 | |
bcc6 | 0:55c7f79a524c | 50 | /* UART printf */ |
bcc6 | 0:55c7f79a524c | 51 | Serial pc(p5, p4); |
bcc6 | 0:55c7f79a524c | 52 | |
bcc6 | 0:55c7f79a524c | 53 | /* Sensor */ |
mtmkimi | 2:6109e375f9a7 | 54 | PAJ7620U2 gesture(p3, p2, p0); |
bcc6 | 0:55c7f79a524c | 55 | volatile bool gestureHasIntEvent = false; |
bcc6 | 0:55c7f79a524c | 56 | |
bcc6 | 0:55c7f79a524c | 57 | /* HID service */ |
bcc6 | 0:55c7f79a524c | 58 | //MouseService *msService = NULL; |
bcc6 | 0:55c7f79a524c | 59 | //JoystickService *jsService = NULL; |
bcc6 | 0:55c7f79a524c | 60 | KeyboardService *kbService = NULL; |
bcc6 | 0:55c7f79a524c | 61 | |
bcc6 | 0:55c7f79a524c | 62 | /* Device name */ |
mtmkimi | 2:6109e375f9a7 | 63 | static const char DEVICE_NAME[] = "MtM Gesture"; |
bcc6 | 0:55c7f79a524c | 64 | static const char SHORT_DEVICE_NAME[] = "gHID"; |
bcc6 | 0:55c7f79a524c | 65 | |
bcc6 | 0:55c7f79a524c | 66 | |
bcc6 | 0:55c7f79a524c | 67 | void connectionCallback(const Gap::ConnectionCallbackParams_t *params) |
bcc6 | 0:55c7f79a524c | 68 | { |
bcc6 | 0:55c7f79a524c | 69 | pc.printf("connection\n"); |
bcc6 | 0:55c7f79a524c | 70 | } |
bcc6 | 0:55c7f79a524c | 71 | |
bcc6 | 0:55c7f79a524c | 72 | void disconnectionCallback(const Gap::DisconnectionCallbackParams_t *params) |
bcc6 | 0:55c7f79a524c | 73 | { |
bcc6 | 0:55c7f79a524c | 74 | BLE::Instance().gap().startAdvertising(); // restart advertising |
bcc6 | 0:55c7f79a524c | 75 | |
bcc6 | 0:55c7f79a524c | 76 | pc.printf("disconnection\n"); |
bcc6 | 0:55c7f79a524c | 77 | } |
bcc6 | 0:55c7f79a524c | 78 | |
bcc6 | 0:55c7f79a524c | 79 | static void passkeyDisplayCallback(Gap::Handle_t handle, const SecurityManager::Passkey_t passkey) |
bcc6 | 0:55c7f79a524c | 80 | { |
bcc6 | 0:55c7f79a524c | 81 | pc.printf("Input passKey: "); |
bcc6 | 0:55c7f79a524c | 82 | for (unsigned i = 0; i < Gap::ADDR_LEN; i++) { |
bcc6 | 0:55c7f79a524c | 83 | pc.printf("%c", passkey[i]); |
bcc6 | 0:55c7f79a524c | 84 | } |
bcc6 | 0:55c7f79a524c | 85 | pc.printf("\r\n"); |
bcc6 | 0:55c7f79a524c | 86 | } |
bcc6 | 0:55c7f79a524c | 87 | |
bcc6 | 0:55c7f79a524c | 88 | static void securitySetupCompletedCallback(Gap::Handle_t handle, SecurityManager::SecurityCompletionStatus_t status) |
bcc6 | 0:55c7f79a524c | 89 | { |
bcc6 | 0:55c7f79a524c | 90 | if (status == SecurityManager::SEC_STATUS_SUCCESS) { |
bcc6 | 0:55c7f79a524c | 91 | pc.printf("Security success %d\r\n", status); |
bcc6 | 0:55c7f79a524c | 92 | } else { |
bcc6 | 0:55c7f79a524c | 93 | pc.printf("Security failed %d\r\n", status); |
bcc6 | 0:55c7f79a524c | 94 | } |
bcc6 | 0:55c7f79a524c | 95 | } |
bcc6 | 0:55c7f79a524c | 96 | |
bcc6 | 0:55c7f79a524c | 97 | static void securitySetupInitiatedCallback(Gap::Handle_t, bool allowBonding, bool requireMITM, SecurityManager::SecurityIOCapabilities_t iocaps) |
bcc6 | 0:55c7f79a524c | 98 | { |
bcc6 | 0:55c7f79a524c | 99 | pc.printf("Security setup initiated\r\n"); |
bcc6 | 0:55c7f79a524c | 100 | } |
bcc6 | 0:55c7f79a524c | 101 | |
bcc6 | 0:55c7f79a524c | 102 | void initializeSecurity(BLE &ble) |
bcc6 | 0:55c7f79a524c | 103 | { |
bcc6 | 0:55c7f79a524c | 104 | bool enableBonding = true; |
bcc6 | 0:55c7f79a524c | 105 | bool requireMITM = HID_SECURITY_REQUIRE_MITM; |
bcc6 | 0:55c7f79a524c | 106 | |
bcc6 | 0:55c7f79a524c | 107 | ble.securityManager().onSecuritySetupInitiated(securitySetupInitiatedCallback); |
bcc6 | 0:55c7f79a524c | 108 | ble.securityManager().onPasskeyDisplay(passkeyDisplayCallback); |
bcc6 | 0:55c7f79a524c | 109 | ble.securityManager().onSecuritySetupCompleted(securitySetupCompletedCallback); |
bcc6 | 0:55c7f79a524c | 110 | |
bcc6 | 0:55c7f79a524c | 111 | ble.securityManager().init(enableBonding, requireMITM, HID_SECURITY_IOCAPS); |
bcc6 | 0:55c7f79a524c | 112 | } |
bcc6 | 0:55c7f79a524c | 113 | |
bcc6 | 0:55c7f79a524c | 114 | void initializeHOGP(BLE &ble) |
bcc6 | 0:55c7f79a524c | 115 | { |
bcc6 | 0:55c7f79a524c | 116 | static const uint16_t uuid16_list[] = {GattService::UUID_HUMAN_INTERFACE_DEVICE_SERVICE, |
bcc6 | 0:55c7f79a524c | 117 | GattService::UUID_DEVICE_INFORMATION_SERVICE, |
bcc6 | 0:55c7f79a524c | 118 | GattService::UUID_BATTERY_SERVICE}; |
bcc6 | 0:55c7f79a524c | 119 | |
bcc6 | 0:55c7f79a524c | 120 | DeviceInformationService deviceInfo(ble, "ARM", "m1", "abc", "def", "ghi", "jkl"); |
bcc6 | 0:55c7f79a524c | 121 | |
bcc6 | 0:55c7f79a524c | 122 | BatteryService batteryInfo(ble, 80); |
bcc6 | 0:55c7f79a524c | 123 | |
bcc6 | 0:55c7f79a524c | 124 | ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::BREDR_NOT_SUPPORTED | |
bcc6 | 0:55c7f79a524c | 125 | GapAdvertisingData::LE_GENERAL_DISCOVERABLE); |
bcc6 | 0:55c7f79a524c | 126 | ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LIST_16BIT_SERVICE_IDS, |
bcc6 | 0:55c7f79a524c | 127 | (uint8_t *)uuid16_list, sizeof(uuid16_list)); |
bcc6 | 0:55c7f79a524c | 128 | |
bcc6 | 0:55c7f79a524c | 129 | // see 5.1.2: HID over GATT Specification (pg. 25) |
bcc6 | 0:55c7f79a524c | 130 | ble.gap().setAdvertisingType(GapAdvertisingParams::ADV_CONNECTABLE_UNDIRECTED); |
bcc6 | 0:55c7f79a524c | 131 | // 30ms to 50ms is recommended (5.1.2) |
bcc6 | 0:55c7f79a524c | 132 | ble.gap().setAdvertisingInterval(50); |
bcc6 | 0:55c7f79a524c | 133 | } |
bcc6 | 0:55c7f79a524c | 134 | |
bcc6 | 0:55c7f79a524c | 135 | void bleInitComplete(BLE::InitializationCompleteCallbackContext *params) |
bcc6 | 0:55c7f79a524c | 136 | { |
bcc6 | 0:55c7f79a524c | 137 | BLE &ble = params->ble; |
bcc6 | 0:55c7f79a524c | 138 | ble_error_t error = params->error; |
bcc6 | 0:55c7f79a524c | 139 | |
bcc6 | 0:55c7f79a524c | 140 | if (error != BLE_ERROR_NONE) { |
bcc6 | 0:55c7f79a524c | 141 | return; |
bcc6 | 0:55c7f79a524c | 142 | } |
bcc6 | 0:55c7f79a524c | 143 | |
bcc6 | 0:55c7f79a524c | 144 | ble.gap().onConnection(connectionCallback); |
bcc6 | 0:55c7f79a524c | 145 | ble.gap().onDisconnection(disconnectionCallback); |
bcc6 | 0:55c7f79a524c | 146 | |
bcc6 | 0:55c7f79a524c | 147 | /* Setup primary service. */ |
bcc6 | 0:55c7f79a524c | 148 | initializeSecurity(ble); |
bcc6 | 0:55c7f79a524c | 149 | // msService = new MouseService(ble); |
bcc6 | 0:55c7f79a524c | 150 | // jsService = new JoystickService(ble); |
bcc6 | 0:55c7f79a524c | 151 | kbService = new KeyboardService(ble); |
bcc6 | 0:55c7f79a524c | 152 | initializeHOGP(ble); |
bcc6 | 0:55c7f79a524c | 153 | |
bcc6 | 0:55c7f79a524c | 154 | /* Setup advertising. */ |
bcc6 | 0:55c7f79a524c | 155 | ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::KEYBOARD/*MOUSE*/); |
bcc6 | 0:55c7f79a524c | 156 | ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LOCAL_NAME, (const uint8_t *)DEVICE_NAME, sizeof(DEVICE_NAME)); |
bcc6 | 0:55c7f79a524c | 157 | ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::SHORTENED_LOCAL_NAME, (const uint8_t *)SHORT_DEVICE_NAME, sizeof(SHORT_DEVICE_NAME)); |
bcc6 | 0:55c7f79a524c | 158 | ble.gap().setDeviceName((const uint8_t *)DEVICE_NAME); |
bcc6 | 0:55c7f79a524c | 159 | ble.gap().startAdvertising(); |
bcc6 | 0:55c7f79a524c | 160 | } |
bcc6 | 0:55c7f79a524c | 161 | |
bcc6 | 0:55c7f79a524c | 162 | void gestureIntEventCallback() |
bcc6 | 0:55c7f79a524c | 163 | { |
bcc6 | 0:55c7f79a524c | 164 | pc.printf("gestureIntEventCallback\n"); |
bcc6 | 0:55c7f79a524c | 165 | gestureHasIntEvent = true; |
bcc6 | 0:55c7f79a524c | 166 | } |
bcc6 | 0:55c7f79a524c | 167 | |
bcc6 | 0:55c7f79a524c | 168 | int main(void) |
bcc6 | 0:55c7f79a524c | 169 | { |
bcc6 | 0:55c7f79a524c | 170 | /* Force to disable the hardware flow control of Serial */ |
bcc6 | 0:55c7f79a524c | 171 | *((uint32_t *)(0x40002000+0x56C)) = 0; |
bcc6 | 0:55c7f79a524c | 172 | pc.printf("~ Hell World ~\n"); |
bcc6 | 0:55c7f79a524c | 173 | |
bcc6 | 0:55c7f79a524c | 174 | /* Init BLE */ |
bcc6 | 0:55c7f79a524c | 175 | BLE& ble = BLE::Instance(); |
bcc6 | 0:55c7f79a524c | 176 | ble.init(bleInitComplete); |
bcc6 | 0:55c7f79a524c | 177 | while(ble.hasInitialized() == false) { /* spin loop */ } |
bcc6 | 0:55c7f79a524c | 178 | |
bcc6 | 0:55c7f79a524c | 179 | /* Config sensor */ |
bcc6 | 0:55c7f79a524c | 180 | pc.printf("PID(0x%04X), VID(0x%02X)\n", gesture.PID, gesture.VID); |
bcc6 | 0:55c7f79a524c | 181 | gesture.IntEvent(&gestureIntEventCallback); |
bcc6 | 0:55c7f79a524c | 182 | |
bcc6 | 0:55c7f79a524c | 183 | /* Main loop */ |
bcc6 | 0:55c7f79a524c | 184 | while(1){ |
bcc6 | 0:55c7f79a524c | 185 | /* Process interrupt event */ |
bcc6 | 0:55c7f79a524c | 186 | if(gestureHasIntEvent && ble.getGapState().connected){ |
bcc6 | 0:55c7f79a524c | 187 | gestureHasIntEvent = false; |
bcc6 | 0:55c7f79a524c | 188 | |
bcc6 | 0:55c7f79a524c | 189 | /* Get sensor data */ |
bcc6 | 0:55c7f79a524c | 190 | uint16_t int_flag = gesture.ReadIntFlag(); |
bcc6 | 0:55c7f79a524c | 191 | pc.printf("(0x%04X)\n", int_flag); |
bcc6 | 0:55c7f79a524c | 192 | |
bcc6 | 0:55c7f79a524c | 193 | /* Send HID code */ |
bcc6 | 0:55c7f79a524c | 194 | if(kbService!=NULL && kbService->isConnected()){ |
bcc6 | 0:55c7f79a524c | 195 | switch(int_flag){ |
bcc6 | 0:55c7f79a524c | 196 | case 0x0001: // Up |
bcc6 | 0:55c7f79a524c | 197 | pc.printf("UpArrow\n"); |
bcc6 | 0:55c7f79a524c | 198 | kbService->printf("%c", UP_ARROW); |
bcc6 | 0:55c7f79a524c | 199 | break; |
bcc6 | 0:55c7f79a524c | 200 | case 0x0002: // Down |
bcc6 | 0:55c7f79a524c | 201 | pc.printf("DownArrow\n"); |
bcc6 | 0:55c7f79a524c | 202 | kbService->printf("%c", DOWN_ARROW); |
bcc6 | 0:55c7f79a524c | 203 | break; |
bcc6 | 0:55c7f79a524c | 204 | case 0x0004: // Left |
bcc6 | 0:55c7f79a524c | 205 | pc.printf("LeftArrow\n"); |
bcc6 | 0:55c7f79a524c | 206 | kbService->printf("%c", LEFT_ARROW); |
bcc6 | 0:55c7f79a524c | 207 | break; |
bcc6 | 0:55c7f79a524c | 208 | case 0x0008: // Right |
bcc6 | 0:55c7f79a524c | 209 | pc.printf("RightArrow\n"); |
bcc6 | 0:55c7f79a524c | 210 | kbService->printf("%c", RIGHT_ARROW); |
bcc6 | 0:55c7f79a524c | 211 | break; |
bcc6 | 0:55c7f79a524c | 212 | case 0x0010: // Forward |
bcc6 | 0:55c7f79a524c | 213 | pc.printf("PageDown\n"); |
bcc6 | 0:55c7f79a524c | 214 | kbService->printf("%c", KEY_PAGE_DOWN); |
bcc6 | 0:55c7f79a524c | 215 | break; |
bcc6 | 0:55c7f79a524c | 216 | case 0x0020: // Backword |
bcc6 | 0:55c7f79a524c | 217 | pc.printf("PageUp\n"); |
bcc6 | 0:55c7f79a524c | 218 | kbService->printf("%c", KEY_PAGE_UP); |
bcc6 | 0:55c7f79a524c | 219 | break; |
bcc6 | 0:55c7f79a524c | 220 | case 0x0040: // Clockwise |
bcc6 | 0:55c7f79a524c | 221 | pc.printf("F5\n"); |
bcc6 | 0:55c7f79a524c | 222 | kbService->printf("%c", KEY_F5); |
bcc6 | 0:55c7f79a524c | 223 | break; |
bcc6 | 0:55c7f79a524c | 224 | case 0x0080: // Counter-Clockwise |
bcc6 | 0:55c7f79a524c | 225 | pc.printf("ESC\n"); |
bcc6 | 0:55c7f79a524c | 226 | kbService->printf("%c", 27); |
bcc6 | 0:55c7f79a524c | 227 | break; |
bcc6 | 0:55c7f79a524c | 228 | case 0x0100: // Wave |
bcc6 | 0:55c7f79a524c | 229 | pc.printf("Bye Bye\n"); |
bcc6 | 0:55c7f79a524c | 230 | kbService->printf("Bye Bye\n"); |
bcc6 | 0:55c7f79a524c | 231 | break; |
bcc6 | 0:55c7f79a524c | 232 | }// End of switch |
bcc6 | 0:55c7f79a524c | 233 | } |
bcc6 | 0:55c7f79a524c | 234 | } |
bcc6 | 0:55c7f79a524c | 235 | |
bcc6 | 0:55c7f79a524c | 236 | /* low power wait for event */ |
bcc6 | 0:55c7f79a524c | 237 | // pc.printf("sleep\n"); |
bcc6 | 0:55c7f79a524c | 238 | ble.waitForEvent(); |
bcc6 | 0:55c7f79a524c | 239 | // pc.printf("wakeup\n"); |
bcc6 | 0:55c7f79a524c | 240 | |
bcc6 | 0:55c7f79a524c | 241 | }// End of while |
bcc6 | 0:55c7f79a524c | 242 | } |