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:
mtmkimi
Date:
2016-12-30
Revision:
2:6109e375f9a7
Parent:
0:55c7f79a524c
Child:
3:656f8fb89f05

File content as of revision 2:6109e375f9a7:

/* Copyright (c) 2016 MtM Technology Corporation, MIT License
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy of this software 
 * and associated documentation files (the "Software"), to deal in the Software without restriction, 
 * including without limitation the rights to use, copy, modify, merge, publish, distribute, 
 * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is 
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or 
 * substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 
 * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 
 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */
#include "mbed.h"
#include "ble/BLE.h"
#include "ble/services/BatteryService.h"
#include "ble/services/DeviceInformationService.h"

#include "PAJ7620U2.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 */
PAJ7620U2 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 Gesture";
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
}