BLE HID keyboard with gesture

Dependencies:   BLE_API BLE_HID PAJ7620U2 mbed nRF51822

https://mtmtechblog.files.wordpress.com/2017/01/mtsense04-pi-on-mbed.jpeg We have full tutorial, please visit our blog

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?

UserRevisionLine numberNew 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 }