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

main.cpp

Committer:
bcc6
Date:
2016-12-16
Revision:
0:55c7f79a524c
Child:
2:6109e375f9a7

File content as of revision 0:55c7f79a524c:

#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
}