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:
2:9f46fa6237dd
Parent:
1:8bca989a70be
--- a/main.cpp	Tue Feb 07 02:51:56 2017 +0000
+++ b/main.cpp	Mon Mar 27 09:58:38 2017 +0000
@@ -21,17 +21,28 @@
 #include "HIDService.h"
 
 //DigitalOut led1(LED1);
-Serial uart(USBTX, USBRX);
+Serial uart(USBTX, USBRX, 115200);
 
+BLE deltaBLE;
 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_BATTERY_SERVICE,
                                               GattService::UUID_DEVICE_INFORMATION_SERVICE};
 static volatile bool  triggerSensorPolling = false;
 bool isConnectionSecured = false;
+bool isSecuritySetup = false;
+static uint8_t key_press_scan_buff[50];
+static uint8_t modifyKey[50];
+char msg[25] = "";
+int index_b = 0;
+int index_w = 0;
+unsigned char uart_buf[64];
+unsigned int i = 0;
 
 DeviceInformationService *deviceInfo;
+BatteryService *batteryService;
 
 void passkeyDisplayCallback(Gap::Handle_t handle, const SecurityManager::Passkey_t passkey)
 {
@@ -41,12 +52,18 @@
     }
     uart.printf("\r\n");
 }
+
+void securitySetupInitiatedCallback(Gap::Handle_t, bool allowBonding, bool requireMITM, SecurityManager::SecurityIOCapabilities_t iocaps)
+{
+    uart.printf("securitySetupInitiatedCallback\r\n");
+    isSecuritySetup = true;
+}
  
 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;
+        //isConnectionSecured = true;
     } else {
         uart.printf("Security failed\r\n", status);
     }
@@ -55,7 +72,15 @@
 void linkSecuredCallback(Gap::Handle_t handle, SecurityManager::SecurityMode_t securityMode)
 {
     uart.printf("linkSecuredCallback\r\n");
+    if (!isSecuritySetup) {
+        isConnectionSecured = true;
+    }
+}
+
+void securityContextStoredCallback(Gap::Handle_t handle) {
+    uart.printf("securityContextStoredCallback\r\n");
     isConnectionSecured = true;
+    isSecuritySetup = false;
 }
 
 void onConnectionCallback(const Gap::ConnectionCallbackParams_t *params)
@@ -67,7 +92,7 @@
 {
     uart.printf("Disconnected\r\n");
     isConnectionSecured = false;
-    BLE::Instance(BLE::DEFAULT_INSTANCE).gap().startAdvertising(); // restart advertising
+    deltaBLE.gap().startAdvertising(); // restart advertising
 }
 
 void onTimeoutCallback(Gap::TimeoutSource_t source)
@@ -94,77 +119,18 @@
 
     /* Note that the periodicCallback() executes in interrupt context, so it is safer to do
      * heavy-weight sensor polling from the main thread. */
-    triggerSensorPolling = true;
+    //triggerSensorPolling = true;
 }
 
-void bleInitComplete(BLE::InitializationCompleteCallbackContext *params)
-{
-    BLE &ble          = params->ble;
-    ble_error_t error = params->error;
-
-    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. */
-    hidService = new HIDService(ble);
-
-    /* Setup auxiliary service. */
-    deviceInfo = new DeviceInformationService(ble, "DELTA", "NQ620", "SN1", "hw-rev1", "fw-rev1", "soft-rev1");
-
-    /* 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::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(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, 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);
-
-    /* SpinWait for initialization to complete. This is necessary because the
-     * BLE object is used in the main loop below. */
-    while (ble.hasInitialized()  == false) { /* spin loop */ }
-
-    // infinite loop
-    while (1) {
+void CLI_execute() {
+//    if (i>=2)
+//    if (uart_buf[i-2] == 0x0D && uart_buf[i-1] == 0x0A){//detecting CR LF
+        if (uart.readable()) return;//retrun if it is not the end of packet
+        
         if (isConnectionSecured) {
-            if (uart.readable() == 1) {
-                keyData = uart.getc();
-                uart.putc(keyData);
-                msg[index_w++] = keyData;
+            for (int j=0; j<i; j++) {
+                keyData = uart_buf[j];
+                
                 if(keyData <= 0x39 && keyData >= 0x30){             //number
                     if(keyData == 0x30){
                         modifyKey[index_b] = 0x00;
@@ -192,31 +158,110 @@
                     key_press_scan_buff[index_b] = 0x2c;
                     index_b++;
                     key_press_scan_buff[index_b] = 0x73;
+                } else if (keyData == 0x08) {                   //backspace
+                    modifyKey[index_b] = 0x00;
+                    key_press_scan_buff[index_b] = 0x2a;
+                    index_b++;
+                    key_press_scan_buff[index_b] = 0x73;
+                } else if (keyData == 0x0d) {                   //return
+                    modifyKey[index_b] = 0x00;
+                    key_press_scan_buff[index_b] = 0x28;
+                    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);
-                    }
+            }
+            
+            i=0;
             
-                    index_b = 0;
-                    index_w = 0;
-                    memset(modifyKey, 0, 50);
-                    memset(msg, 0, 25);
-                    memset(key_press_scan_buff, 0, 50);
-                }
+            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::Instance(BLE::DEFAULT_INSTANCE).waitForEvent();
+                //wait(0.03);
             }
-        } else {
-            ble.waitForEvent(); // low power wait for event
-            wait(1);
+            
+            index_b = 0;
+            index_w = 0;
+            memset(modifyKey, 0, 50);
+            memset(msg, 0, 25);
+            memset(key_press_scan_buff, 0, 50);
+            
         }
         
+//    }    
+}
+
+void uart_interrupt() {
+    uart.printf("uart_interrupt\r\n");
+    uart_buf[i++] = uart.getc();
+    CLI_execute();
+}
+
+void bleInitComplete(BLE::InitializationCompleteCallbackContext *params)
+{
+    BLE &ble          = params->ble;
+    ble_error_t error = params->error;
+
+    if (error != BLE_ERROR_NONE) {
+        return;
+    }
+    
+    bool enableBonding = true;
+    bool requireMITM   = false;
+
+    //uint8_t pKey[6] = {'1', '1', '1', '1', '1', '1'}; //set the passkey
+    ble.securityManager().init(enableBonding, requireMITM, SecurityManager::IO_CAPS_NONE);
+    ble.securityManager().onPasskeyDisplay(passkeyDisplayCallback);
+    ble.securityManager().onSecuritySetupInitiated(securitySetupInitiatedCallback);
+    ble.securityManager().onSecuritySetupCompleted(securitySetupCompletedCallback);
+    ble.securityManager().onLinkSecured(linkSecuredCallback);
+    ble.securityManager().onSecurityContextStored(securityContextStoredCallback);
+    ble.gap().onDisconnection(disconnectionCallback);
+    ble.gap().onConnection(onConnectionCallback);
+    ble.gap().onTimeout(onTimeoutCallback);
+    //ble.gattServer().onDataRead(onDataReadCallback);
+
+    /* Setup primary service. */
+    hidService = new HIDService(ble);
+
+    /* Setup auxiliary service. */
+    batteryService = new BatteryService(ble, 100);
+    deviceInfo = new DeviceInformationService(ble, "DELTA", "NQ620", "SN1", "hw-rev1", "fw-rev1", "soft-rev1");
+
+    /* 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::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(50); /* 50ms */
+    ble.gap().startAdvertising();
+    uart.printf("Start advertising\r\n");
+}
+
+int main(void)
+{
+    //led1 = 1;
+    //Ticker ticker;
+    //ticker.attach(periodicCallback, 1); // blink LED every second
+    
+    uart.attach(&uart_interrupt);
+    uart.printf("Srarting HID Service\r\n");
+
+    BLE &deltaBLE = BLE::Instance(BLE::DEFAULT_INSTANCE);
+    deltaBLE.init(bleInitComplete);
+
+    /* SpinWait for initialization to complete. This is necessary because the
+     * BLE object is used in the main loop below. */
+    while (deltaBLE.hasInitialized()  == false) { /* spin loop */ }
+
+    // infinite loop
+    while (1) {
+        deltaBLE.waitForEvent();
     }
 }