BLE HID Keyboard example for Delta BLE platform

Fork of BLE_HeartRate_DELTA by Delta

This example demonstrates the HID over GATT profile for keyboard.

1. Running this application on Delta BLE platform 2. To connect and pair with device named "HID_Keyboard" in your mobile (iOS/Android) Settings>Bluetooth page 3. Open a text editing application on your mobile phone 4. On the PC, open the terminal tool (Putty or TeraTerm) and choose the correct COM/BaudRate 5. Enter any character from your PC, and it will be displayed in your mobile phone

Revision:
1:8bca989a70be
Parent:
0:c7bcc0b36b5e
Child:
2:9f46fa6237dd
--- a/main.cpp	Thu Oct 13 07:34:53 2016 +0000
+++ b/main.cpp	Tue Feb 07 02:51:56 2017 +0000
@@ -16,30 +16,81 @@
 
 #include "mbed.h"
 #include "ble/BLE.h"
-#include "ble/services/HeartRateService.h"
 #include "ble/services/BatteryService.h"
 #include "ble/services/DeviceInformationService.h"
+#include "HIDService.h"
 
-DigitalOut led1(LED1);
+//DigitalOut led1(LED1);
+Serial uart(USBTX, USBRX);
 
-const static char     DEVICE_NAME[]        = "DELTA_HRM1";
-static const uint16_t uuid16_list[]        = {GattService::UUID_HEART_RATE_SERVICE,
+HIDService *hidService;
+unsigned char keyData;
+const static char     DEVICE_NAME[]        = "HID_Keyboard";
+static const uint16_t uuid16_list[]        = {GattService::UUID_HUMAN_INTERFACE_DEVICE_SERVICE,
                                               GattService::UUID_DEVICE_INFORMATION_SERVICE};
 static volatile bool  triggerSensorPolling = false;
+bool isConnectionSecured = false;
 
-uint8_t hrmCounter = 100; // init HRM to 100bps
+DeviceInformationService *deviceInfo;
 
-HeartRateService         *hrService;
-DeviceInformationService *deviceInfo;
+void passkeyDisplayCallback(Gap::Handle_t handle, const SecurityManager::Passkey_t passkey)
+{
+    uart.printf("Input passKey: ");
+    for (unsigned i = 0; i < Gap::ADDR_LEN; i++) {
+        uart.printf("%c ", passkey[i]);
+    }
+    uart.printf("\r\n");
+}
+ 
+void securitySetupCompletedCallback(Gap::Handle_t handle, SecurityManager::SecurityCompletionStatus_t status)
+{
+    if (status == SecurityManager::SEC_STATUS_SUCCESS) {
+        uart.printf("Security success\r\n", status);
+        isConnectionSecured = true;
+    } else {
+        uart.printf("Security failed\r\n", status);
+    }
+}
+
+void linkSecuredCallback(Gap::Handle_t handle, SecurityManager::SecurityMode_t securityMode)
+{
+    uart.printf("linkSecuredCallback\r\n");
+    isConnectionSecured = true;
+}
+
+void onConnectionCallback(const Gap::ConnectionCallbackParams_t *params)
+{
+    uart.printf("Connected\r\n");
+}
 
 void disconnectionCallback(const Gap::DisconnectionCallbackParams_t *params)
 {
+    uart.printf("Disconnected\r\n");
+    isConnectionSecured = false;
     BLE::Instance(BLE::DEFAULT_INSTANCE).gap().startAdvertising(); // restart advertising
 }
 
+void onTimeoutCallback(Gap::TimeoutSource_t source)
+{
+    switch (source) {
+        case Gap::TIMEOUT_SRC_ADVERTISING:
+            uart.printf("Advertising timeout\r\n");
+            break;  
+        case Gap::TIMEOUT_SRC_SECURITY_REQUEST:
+            uart.printf("Security request timeout\r\n");
+            break;
+        case Gap::TIMEOUT_SRC_SCAN:
+            uart.printf("Scanning timeout\r\n");
+            break;
+        case Gap::TIMEOUT_SRC_CONN:
+            uart.printf("Connection timeout\r\n");
+            break;
+    }
+}
+
 void periodicCallback(void)
 {
-    led1 = !led1; /* Do blinky on LED1 while we're waiting for BLE events */
+    //led1 = !led1; /* Do blinky on LED1 while we're waiting for BLE events */
 
     /* Note that the periodicCallback() executes in interrupt context, so it is safer to do
      * heavy-weight sensor polling from the main thread. */
@@ -54,11 +105,22 @@
     if (error != BLE_ERROR_NONE) {
         return;
     }
+    
+    bool enableBonding = true;
+    bool requireMITM   = false;
 
+    //const uint8_t passkeyValue[6] = {0x00,0x00,0x00,0x00,0x00,0x00};
+    ble.securityManager().init(enableBonding, requireMITM, SecurityManager::IO_CAPS_NONE);
+    ble.securityManager().onPasskeyDisplay(passkeyDisplayCallback);
+    ble.securityManager().onSecuritySetupCompleted(securitySetupCompletedCallback);
+    ble.securityManager().onLinkSecured(linkSecuredCallback);
     ble.gap().onDisconnection(disconnectionCallback);
+    ble.gap().onConnection(onConnectionCallback);
+    ble.gap().onTimeout(onTimeoutCallback);
+    //ble.gattServer().onDataRead(onDataReadCallback);
 
     /* Setup primary service. */
-    hrService = new HeartRateService(ble, hrmCounter, HeartRateService::LOCATION_FINGER);
+    hidService = new HIDService(ble);
 
     /* Setup auxiliary service. */
     deviceInfo = new DeviceInformationService(ble, "DELTA", "NQ620", "SN1", "hw-rev1", "fw-rev1", "soft-rev1");
@@ -66,18 +128,28 @@
     /* Setup advertising. */
     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));
-    ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::GENERIC_HEART_RATE_SENSOR);
+    ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::KEYBOARD);
     ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LOCAL_NAME, (uint8_t *)DEVICE_NAME, sizeof(DEVICE_NAME));
     ble.gap().setAdvertisingType(GapAdvertisingParams::ADV_CONNECTABLE_UNDIRECTED);
-    ble.gap().setAdvertisingInterval(1000); /* 1000ms */
+    ble.gap().setAdvertisingInterval(50); /* 50ms */
     ble.gap().startAdvertising();
+    uart.printf("Start advertising\r\n");
 }
 
+static uint8_t key_press_scan_buff[50];
+static uint8_t modifyKey[50];
+char msg[25] = "";
+int index_b = 0;
+int index_w = 0;
+
 int main(void)
 {
-    led1 = 1;
-    Ticker ticker;
-    ticker.attach(periodicCallback, 1); // blink LED every second
+    //led1 = 1;
+   // Ticker ticker;
+//    ticker.attach(periodicCallback, 0.1); // blink LED every second
+    
+    uart.baud(115200);
+    uart.printf("Srarting HID Service\r\n");
 
     BLE& ble = BLE::Instance(BLE::DEFAULT_INSTANCE);
     ble.init(bleInitComplete);
@@ -88,20 +160,63 @@
 
     // infinite loop
     while (1) {
-        // check for trigger from periodicCallback()
-        if (triggerSensorPolling && ble.getGapState().connected) {
-            triggerSensorPolling = false;
-
-            // Do blocking calls or whatever is necessary for sensor polling.
-            // In our case, we simply update the HRM measurement.
-            hrmCounter++;
-            if (hrmCounter == 175) { //  100 <= HRM bps <=175
-                hrmCounter = 100;
+        if (isConnectionSecured) {
+            if (uart.readable() == 1) {
+                keyData = uart.getc();
+                uart.putc(keyData);
+                msg[index_w++] = keyData;
+                if(keyData <= 0x39 && keyData >= 0x30){             //number
+                    if(keyData == 0x30){
+                        modifyKey[index_b] = 0x00;
+                        key_press_scan_buff[index_b] = 0x27;
+                        index_b++;
+                        key_press_scan_buff[index_b] = 0x73;
+                    } else {
+                        modifyKey[index_b] = 0x00;
+                        key_press_scan_buff[index_b] = keyData-0x13;
+                        index_b++;
+                        key_press_scan_buff[index_b] = 0x73;
+                        }
+                } else if(keyData <= 0x7a && keyData >= 0x61 ){ //lowercase letters
+                    modifyKey[index_b] = 0x00;
+                    key_press_scan_buff[index_b] = keyData-0x5d;
+                    index_b++;
+                    key_press_scan_buff[index_b] = 0x73;
+                } else if(keyData <= 0x5a && keyData >= 0x41){  //uppercase letters
+                    modifyKey[index_b] = 0x02;
+                    key_press_scan_buff[index_b] = keyData-0x3d;
+                    index_b++;
+                    key_press_scan_buff[index_b] = 0x73;
+                } else if (keyData == 0x20) {                   //space
+                    modifyKey[index_b] = 0x00;
+                    key_press_scan_buff[index_b] = 0x2c;
+                    index_b++;
+                    key_press_scan_buff[index_b] = 0x73;
+                } else {
+                    modifyKey[index_b] = 0x00;
+                    //key_press_scan_buff[index_b] = 0x73;          //this is dummy data.
+                    //msg[index_w+1] = '\0';
+                }
+                index_b++;
+                if(keyData == 0x0a && ble.getGapState().connected){
+                    for(int i = 0; i < index_b ; i++){
+                        uart.printf("m[%x] k[%x] ", modifyKey[i], key_press_scan_buff[i]);
+                        hidService->updateReport(modifyKey[i], key_press_scan_buff[i]);
+                        ble.waitForEvent();
+                        wait(0.03);
+                    }
+            
+                    index_b = 0;
+                    index_w = 0;
+                    memset(modifyKey, 0, 50);
+                    memset(msg, 0, 25);
+                    memset(key_press_scan_buff, 0, 50);
+                }
             }
-
-            hrService->updateHeartRate(hrmCounter);
         } else {
             ble.waitForEvent(); // low power wait for event
+            wait(1);
         }
+        
     }
 }