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-02-07
Revision:
1:8bca989a70be
Parent:
0:c7bcc0b36b5e
Child:
2:9f46fa6237dd

File content as of revision 1:8bca989a70be:

/* 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);

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;

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 */

    /* 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 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) {
        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);
                }
            }
        } else {
            ble.waitForEvent(); // low power wait for event
            wait(1);
        }
        
    }
}