BLE HID keyboard with gesture
Dependencies: BLE_API BLE_HID PAJ7620U2 mbed nRF51822
We have full tutorial, please visit our blog
Revision 3:656f8fb89f05, committed 2017-01-17
- Comitter:
- bcc6
- Date:
- Tue Jan 17 03:53:35 2017 +0000
- Parent:
- 2:6109e375f9a7
- Commit message:
- After reset, purge all bonding state.
Changed in this revision
diff -r 6109e375f9a7 -r 656f8fb89f05 BLE_HID.lib --- a/BLE_HID.lib Fri Dec 30 08:36:50 2016 +0000 +++ b/BLE_HID.lib Tue Jan 17 03:53:35 2017 +0000 @@ -1,1 +1,1 @@ -https://developer.mbed.org/users/bcc6/code/BLE_HID/#c02f0fe0db5f +https://developer.mbed.org/users/bcc6/code/BLE_HID/#dc4e6dbcb79b
diff -r 6109e375f9a7 -r 656f8fb89f05 debug.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/debug.h Tue Jan 17 03:53:35 2017 +0000 @@ -0,0 +1,32 @@ +#ifndef __DEBUG_H__ +#define __DEBUG_H__ + +#include "Serial.h" + + +#define ENABLE_LOG 1 +#define ENABLE_ASSERT 1 + +extern Serial dbg; + + +#if ENABLE_LOG +#define log(...) dbg.printf(__VA_ARGS__) +#else +#define log(...) +#endif + +#if ENABLE_ASSERT +#define assert(expr) { \ + if (!(expr)) { \ + dbg.printf("ASSERT: %s, file %s, line %d\n", #expr, __FILE__, __LINE__); \ + while(1); \ + } \ +} +#else +#define assert(expr) +#endif + + +#endif +
diff -r 6109e375f9a7 -r 656f8fb89f05 main.cpp --- a/main.cpp Fri Dec 30 08:36:50 2016 +0000 +++ b/main.cpp Tue Jan 17 03:53:35 2017 +0000 @@ -17,159 +17,220 @@ */ #include "mbed.h" #include "ble/BLE.h" -#include "ble/services/BatteryService.h" -#include "ble/services/DeviceInformationService.h" +#include "debug.h" #include "PAJ7620U2.h" -#include "HIDServiceBase.h" -//#include "MouseService.h" -//#include "JoystickService.h" -#include "KeyboardService.h" +#include "BLE_HID/DeviceInformationService.h" +#include "BLE_HID/BatteryService.h" +#include "BLE_HID/HIDServiceBase.h" +#include "BLE_HID/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) +#define DEVICE_NAME ("MtM_gHID") + +#define TX_POWER_dBm (0) // -40, -20, -16, -12, -8, -4, 0, 4 + +#define BD_ADDRESS_TYPE (BLEProtocol::AddressType::RANDOM_STATIC) +#define BD_ADDRESS ((Gap::Address_t){0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC}) + +#define ENABLE_BONDING (true) +#define REQUIRE_MITM (false) +#define IOCAPS (SecurityManager::IO_CAPS_NONE) +#define PASSKEY ((SecurityManager::Passkey_t){'1', '2', '3', '4', '5', '6'}) + +#define MANUFACTURERS_NAME ("MtM") +#define MODEL_NAME (NULL) +#define SERIAL_NUMBER (NULL) +#define HW_VERSION (NULL) +#define FW_VERSION (NULL) +#define SW_VERSION (NULL) +#if 0 +#define PNP_ID &((PnPID_t){0x01, 0xFFFE, 0x0001, 0x0001}) // From Bluetooth SIG +#else +#define PNP_ID &((PnPID_t){0x02, 0x1915, 0xEEEE, 0x0001}) // From USB-IF #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 +#define MIN_CONN_INTERVAL (Gap::MSEC_TO_GAP_DURATION_UNITS(10)); // 10ms +#define MAX_CONN_INTERVAL (Gap::MSEC_TO_GAP_DURATION_UNITS(30)); // 30ms +#define SLAVE_LATENCY (6) +#define CONN_SUP_TIMEOUT (43) // 430ms + +#define ADV_INTERVAL (50) // 50ms +#define ADV_TIMEOUT (60) // 60sec -/* UART printf */ -Serial pc(p5, p4); +/* UART for debug (log, assert) */ +Serial dbg(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"; + +static void connectionCallback(const Gap::ConnectionCallbackParams_t *params) +{ + log("connection\n"); + log("role(%d)\n", params->role); + log("peerAddrType(%d), peerAddr(%02X:%02X:%02X:%02X:%02X:%02X)\n", + params->peerAddrType, + params->peerAddr[5], params->peerAddr[4], params->peerAddr[3], params->peerAddr[2], params->peerAddr[1], params->peerAddr[0]); + log("ownAddrType(%d), ownAddr(%02X:%02X:%02X:%02X:%02X:%02X)\n", + params->ownAddrType, + params->ownAddr[5], params->ownAddr[4], params->ownAddr[3], params->ownAddr[2], params->ownAddr[1], params->ownAddr[0]); -void connectionCallback(const Gap::ConnectionCallbackParams_t *params) -{ - pc.printf("connection\n"); + log("connectionParams(%d, %d, %d, %d)\n", + params->connectionParams->minConnectionInterval, + params->connectionParams->maxConnectionInterval, + params->connectionParams->slaveLatency, + params->connectionParams->connectionSupervisionTimeout); } -void disconnectionCallback(const Gap::DisconnectionCallbackParams_t *params) +static void disconnectionCallback(const Gap::DisconnectionCallbackParams_t *params) { BLE::Instance().gap().startAdvertising(); // restart advertising - pc.printf("disconnection\n"); + log("disconnection\n"); } -static void passkeyDisplayCallback(Gap::Handle_t handle, const SecurityManager::Passkey_t passkey) +static void timeoutCallback(const Gap::TimeoutSource_t source) { - pc.printf("Input passKey: "); - for (unsigned i = 0; i < Gap::ADDR_LEN; i++) { - pc.printf("%c", passkey[i]); - } - pc.printf("\r\n"); + log("timeout(%d)\n", source); +} + +static void securitySetupInitiatedCallback(Gap::Handle_t, bool allowBonding, bool requireMITM, SecurityManager::SecurityIOCapabilities_t iocaps) +{ + log("Security setup initiated\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); + log("Security success %d\r\n", status); } else { - pc.printf("Security failed %d\r\n", status); + log("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) +static void passkeyDisplayCallback(Gap::Handle_t handle, const SecurityManager::Passkey_t passkey) { - 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); + log("Input passKey: "); + for (unsigned i = 0; i < Gap::ADDR_LEN; i++) { + log("%c", passkey[i]); + } + log("\r\n"); } -void initializeHOGP(BLE &ble) +static void bleInitComplete(BLE::InitializationCompleteCallbackContext *params) { - 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); + log("InitComplete\n"); - 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; + assert(error == BLE_ERROR_NONE); + + + /* Set Tx power */ + error = ble.gap().setTxPower(TX_POWER_dBm); + assert(error == BLE_ERROR_NONE); + + /* Set address */ + error = ble.gap().setAddress(BD_ADDRESS_TYPE, BD_ADDRESS); + assert(error == BLE_ERROR_NONE); + + /* Initialize BLE security */ + error = ble.securityManager().init(ENABLE_BONDING, REQUIRE_MITM, IOCAPS, PASSKEY); + assert(error == BLE_ERROR_NONE); + +#if 1 // After reset, clear bonding state + /* Purge all bonding state */ + error = ble.securityManager().purgeAllBondingState(); + assert(error == BLE_ERROR_NONE); +#endif + +#if 0 // Disable white-list + /* Set white-list */ + BLEProtocol::Address_t addresses[2]; + Gap::Whitelist_t whitelist; + whitelist.addresses = addresses; + whitelist.size = 0; + whitelist.capacity = 2; + error = ble.securityManager().getAddressesFromBondTable(whitelist); + assert(error == BLE_ERROR_NONE); + + log("getAddressesFromBondTable (%d)\n", whitelist.size); + for(int i=0; i<whitelist.size; i++) { + int type = (int)whitelist.addresses[i].type; + uint8_t *addr = (uint8_t *)whitelist.addresses[i].address; + log("type(%d), addr(%02X:%02X:%02X:%02X:%02X:%02X)\n", + type, addr[5], addr[4], addr[3], addr[2], addr[1], addr[0]); } + error = ble.gap().setWhitelist(whitelist); + assert(error == BLE_ERROR_NONE); + error = ble.gap().setAdvertisingPolicyMode(Gap::ADV_POLICY_IGNORE_WHITELIST); // Allow scan requests and connect requests from any device + assert(error == BLE_ERROR_NONE); +#endif + /* Set callback functions */ ble.gap().onConnection(connectionCallback); ble.gap().onDisconnection(disconnectionCallback); + ble.gap().onTimeout(timeoutCallback); + ble.securityManager().onSecuritySetupInitiated(securitySetupInitiatedCallback); + ble.securityManager().onSecuritySetupCompleted(securitySetupCompletedCallback); + ble.securityManager().onPasskeyDisplay(passkeyDisplayCallback); - /* Setup primary service. */ - initializeSecurity(ble); -// msService = new MouseService(ble); -// jsService = new JoystickService(ble); + /* Setup primary service */ + DeviceInformationService deviceInfo(ble, MANUFACTURERS_NAME, MODEL_NAME, SERIAL_NUMBER, HW_VERSION, FW_VERSION, SW_VERSION, PNP_ID); + BatteryService batteryInfo(ble, 80); kbService = new KeyboardService(ble); - initializeHOGP(ble); + + /* Connection parameters */ + Gap::ConnectionParams_t conn_params; + conn_params.minConnectionInterval = MIN_CONN_INTERVAL; + conn_params.maxConnectionInterval = MAX_CONN_INTERVAL; + conn_params.slaveLatency = SLAVE_LATENCY; + conn_params.connectionSupervisionTimeout = CONN_SUP_TIMEOUT; + ble.gap().setPreferredConnectionParams(&conn_params); /* 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(); + static const uint16_t uuid16_list[] = { + GattService::UUID_HUMAN_INTERFACE_DEVICE_SERVICE + }; + ble.gap().setAdvertisingType(GapAdvertisingParams::ADV_CONNECTABLE_UNDIRECTED); + ble.gap().setAdvertisingInterval(ADV_INTERVAL); + ble.gap().setAdvertisingTimeout(ADV_TIMEOUT); + error = ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::BREDR_NOT_SUPPORTED | GapAdvertisingData::LE_LIMITED_DISCOVERABLE); + assert(error == BLE_ERROR_NONE); + error = ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LIST_16BIT_SERVICE_IDS, (uint8_t *)uuid16_list, sizeof(uuid16_list)); + assert(error == BLE_ERROR_NONE); + error = ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::KEYBOARD); + assert(error == BLE_ERROR_NONE); + error = ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LOCAL_NAME, (const uint8_t *)DEVICE_NAME, sizeof(DEVICE_NAME)); + assert(error == BLE_ERROR_NONE); + error = ble.gap().setDeviceName((const uint8_t *)DEVICE_NAME); + assert(error == BLE_ERROR_NONE); + error = ble.gap().startAdvertising(); + assert(error == BLE_ERROR_NONE); } -void gestureIntEventCallback() +static void gestureIntEventCallback() { - pc.printf("gestureIntEventCallback\n"); + log("gestureIntEventCallback\n"); gestureHasIntEvent = true; } int main(void) { - /* Force to disable the hardware flow control of Serial */ + /* Disable the hardware flow control of Serial */ *((uint32_t *)(0x40002000+0x56C)) = 0; - pc.printf("~ Hell World ~\n"); + log("\n"); + log("~ Hell World ~\n"); + log("\n"); /* Init BLE */ BLE& ble = BLE::Instance(); @@ -177,7 +238,7 @@ while(ble.hasInitialized() == false) { /* spin loop */ } /* Config sensor */ - pc.printf("PID(0x%04X), VID(0x%02X)\n", gesture.PID, gesture.VID); + log("PID(0x%04X), VID(0x%02X)\n", gesture.PID, gesture.VID); gesture.IntEvent(&gestureIntEventCallback); /* Main loop */ @@ -188,45 +249,45 @@ /* Get sensor data */ uint16_t int_flag = gesture.ReadIntFlag(); - pc.printf("(0x%04X)\n", int_flag); + log("(0x%04X)\n", int_flag); /* Send HID code */ if(kbService!=NULL && kbService->isConnected()){ switch(int_flag){ case 0x0001: // Up - pc.printf("UpArrow\n"); + log("UpArrow\n"); kbService->printf("%c", UP_ARROW); break; case 0x0002: // Down - pc.printf("DownArrow\n"); + log("DownArrow\n"); kbService->printf("%c", DOWN_ARROW); break; case 0x0004: // Left - pc.printf("LeftArrow\n"); + log("LeftArrow\n"); kbService->printf("%c", LEFT_ARROW); break; case 0x0008: // Right - pc.printf("RightArrow\n"); + log("RightArrow\n"); kbService->printf("%c", RIGHT_ARROW); break; case 0x0010: // Forward - pc.printf("PageDown\n"); + log("PageDown\n"); kbService->printf("%c", KEY_PAGE_DOWN); break; case 0x0020: // Backword - pc.printf("PageUp\n"); + log("PageUp\n"); kbService->printf("%c", KEY_PAGE_UP); break; case 0x0040: // Clockwise - pc.printf("F5\n"); + log("F5\n"); kbService->printf("%c", KEY_F5); break; case 0x0080: // Counter-Clockwise - pc.printf("ESC\n"); + log("ESC\n"); kbService->printf("%c", 27); break; case 0x0100: // Wave - pc.printf("Bye Bye\n"); + log("Bye Bye\n"); kbService->printf("Bye Bye\n"); break; }// End of switch @@ -234,9 +295,10 @@ } /* low power wait for event */ -// pc.printf("sleep\n"); +// log("sleep\n"); ble.waitForEvent(); -// pc.printf("wakeup\n"); +// log("wakeup\n"); }// End of while } +