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

Revision:
0:55c7f79a524c
Child:
2:6109e375f9a7
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/main.cpp	Fri Dec 16 09:04:08 2016 +0000
@@ -0,0 +1,225 @@
+#include "mbed.h"
+#include "ble/BLE.h"
+#include "ble/services/BatteryService.h"
+#include "ble/services/DeviceInformationService.h"
+
+#include "PAJ7620.h"
+
+#include "HIDServiceBase.h"
+//#include "MouseService.h"
+//#include "JoystickService.h"
+#include "KeyboardService.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
+
+
+/* UART printf */
+Serial pc(p5, p4);
+
+/* Sensor */
+PAJ7620 gesture(p3, p2, p0);
+volatile bool gestureHasIntEvent = false;
+
+/* HID service */
+//MouseService    *msService = NULL;
+//JoystickService *jsService = NULL;
+KeyboardService *kbService = NULL;
+
+/* Device name */
+static const char DEVICE_NAME[] = "MtM_gHID";
+static const char SHORT_DEVICE_NAME[] = "gHID";
+
+
+void connectionCallback(const Gap::ConnectionCallbackParams_t *params)
+{
+    pc.printf("connection\n");
+}
+
+void disconnectionCallback(const Gap::DisconnectionCallbackParams_t *params)
+{    
+    BLE::Instance().gap().startAdvertising(); // restart advertising
+    
+    pc.printf("disconnection\n");
+}
+
+static void passkeyDisplayCallback(Gap::Handle_t handle, const SecurityManager::Passkey_t passkey)
+{
+    pc.printf("Input passKey: ");
+    for (unsigned i = 0; i < Gap::ADDR_LEN; i++) {
+        pc.printf("%c", passkey[i]);
+    }
+    pc.printf("\r\n");
+}
+
+static void securitySetupCompletedCallback(Gap::Handle_t handle, SecurityManager::SecurityCompletionStatus_t status)
+{
+    if (status == SecurityManager::SEC_STATUS_SUCCESS) {
+        pc.printf("Security success %d\r\n", status);
+    } else {
+        pc.printf("Security failed %d\r\n", status);
+    }
+}
+
+static void securitySetupInitiatedCallback(Gap::Handle_t, bool allowBonding, bool requireMITM, SecurityManager::SecurityIOCapabilities_t iocaps)
+{
+    pc.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};
+
+    DeviceInformationService deviceInfo(ble, "ARM", "m1", "abc", "def", "ghi", "jkl");
+
+    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);
+}
+
+void bleInitComplete(BLE::InitializationCompleteCallbackContext *params)
+{
+    BLE &ble          = params->ble;
+    ble_error_t error = params->error;
+
+    if (error != BLE_ERROR_NONE) {
+        return;
+    }
+
+    ble.gap().onConnection(connectionCallback);
+    ble.gap().onDisconnection(disconnectionCallback);
+
+    /* Setup primary service. */
+    initializeSecurity(ble);
+//  msService = new MouseService(ble);
+//  jsService = new JoystickService(ble);
+    kbService = new KeyboardService(ble);
+    initializeHOGP(ble);
+
+    /* Setup advertising. */
+    ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::KEYBOARD/*MOUSE*/);
+    ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LOCAL_NAME, (const uint8_t *)DEVICE_NAME, sizeof(DEVICE_NAME));
+    ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::SHORTENED_LOCAL_NAME, (const uint8_t *)SHORT_DEVICE_NAME, sizeof(SHORT_DEVICE_NAME));
+    ble.gap().setDeviceName((const uint8_t *)DEVICE_NAME);
+    ble.gap().startAdvertising();
+}
+
+void gestureIntEventCallback()
+{
+    pc.printf("gestureIntEventCallback\n");
+    gestureHasIntEvent = true;
+}
+
+int main(void)
+{
+    /* Force to disable the hardware flow control of Serial */
+    *((uint32_t *)(0x40002000+0x56C)) = 0;
+    pc.printf("~ Hell World ~\n");
+
+    /* Init BLE */
+    BLE& ble = BLE::Instance();
+    ble.init(bleInitComplete);
+    while(ble.hasInitialized() == false) { /* spin loop */ }
+
+    /* Config sensor */
+    pc.printf("PID(0x%04X), VID(0x%02X)\n", gesture.PID, gesture.VID);
+    gesture.IntEvent(&gestureIntEventCallback);
+
+    /* Main loop */
+    while(1){
+        /* Process interrupt event */
+        if(gestureHasIntEvent && ble.getGapState().connected){
+            gestureHasIntEvent = false;
+
+            /* Get sensor data */
+            uint16_t int_flag = gesture.ReadIntFlag();
+            pc.printf("(0x%04X)\n", int_flag);
+
+            /* Send HID code */
+            if(kbService!=NULL && kbService->isConnected()){
+                switch(int_flag){
+                case 0x0001:    // Up
+                    pc.printf("UpArrow\n");
+                    kbService->printf("%c", UP_ARROW);
+                    break;
+                case 0x0002:    // Down
+                    pc.printf("DownArrow\n");
+                    kbService->printf("%c", DOWN_ARROW);
+                    break;
+                case 0x0004:    // Left
+                    pc.printf("LeftArrow\n");
+                    kbService->printf("%c", LEFT_ARROW);
+                    break;
+                case 0x0008:    // Right
+                    pc.printf("RightArrow\n");
+                    kbService->printf("%c", RIGHT_ARROW);
+                    break;
+                case 0x0010:    // Forward
+                    pc.printf("PageDown\n");
+                    kbService->printf("%c", KEY_PAGE_DOWN);
+                    break;
+                case 0x0020:    // Backword
+                    pc.printf("PageUp\n");
+                    kbService->printf("%c", KEY_PAGE_UP);
+                    break;
+                case 0x0040:    // Clockwise
+                    pc.printf("F5\n");
+                    kbService->printf("%c", KEY_F5);
+                    break;
+                case 0x0080:    // Counter-Clockwise
+                    pc.printf("ESC\n");
+                    kbService->printf("%c", 27);
+                    break;
+                case 0x0100:    // Wave
+                    pc.printf("Bye Bye\n");
+                    kbService->printf("Bye Bye\n");
+                    break;
+                }// End of switch
+            }
+        }
+
+        /* low power wait for event */
+//      pc.printf("sleep\n");
+        ble.waitForEvent();
+//      pc.printf("wakeup\n");
+
+    }// End of while
+}