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

main.cpp

Committer:
silviaChen
Date:
2017-03-27
Revision:
2:9f46fa6237dd
Parent:
1:8bca989a70be

File content as of revision 2:9f46fa6237dd:

/* mbed Microcontroller Library
 * Copyright (c) 2006-2015 ARM Limited
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "mbed.h"
#include "ble/BLE.h"
#include "ble/services/BatteryService.h"
#include "ble/services/DeviceInformationService.h"
#include "HIDService.h"

//DigitalOut led1(LED1);
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)
{
    uart.printf("Input passKey: ");
    for (unsigned i = 0; i < Gap::ADDR_LEN; i++) {
        uart.printf("%c ", passkey[i]);
    }
    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;
    } else {
        uart.printf("Security failed\r\n", status);
    }
}

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)
{
    uart.printf("Connected\r\n");
}

void disconnectionCallback(const Gap::DisconnectionCallbackParams_t *params)
{
    uart.printf("Disconnected\r\n");
    isConnectionSecured = false;
    deltaBLE.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 */

    /* Note that the periodicCallback() executes in interrupt context, so it is safer to do
     * heavy-weight sensor polling from the main thread. */
    //triggerSensorPolling = true;
}

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) {
            for (int j=0; j<i; j++) {
                keyData = uart_buf[j];
                
                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 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++;
            }
            
            i=0;
            
            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);
            }
            
            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();
    }
}