BLE HID Keyboard example for Delta BLE platform
Fork of BLE_HeartRate_DELTA by
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
Diff: main.cpp
- Revision:
- 1:8bca989a70be
- Parent:
- 0:c7bcc0b36b5e
- Child:
- 2:9f46fa6237dd
--- a/main.cpp Thu Oct 13 07:34:53 2016 +0000 +++ b/main.cpp Tue Feb 07 02:51:56 2017 +0000 @@ -16,30 +16,81 @@ #include "mbed.h" #include "ble/BLE.h" -#include "ble/services/HeartRateService.h" #include "ble/services/BatteryService.h" #include "ble/services/DeviceInformationService.h" +#include "HIDService.h" -DigitalOut led1(LED1); +//DigitalOut led1(LED1); +Serial uart(USBTX, USBRX); -const static char DEVICE_NAME[] = "DELTA_HRM1"; -static const uint16_t uuid16_list[] = {GattService::UUID_HEART_RATE_SERVICE, +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; -uint8_t hrmCounter = 100; // init HRM to 100bps +DeviceInformationService *deviceInfo; -HeartRateService *hrService; -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 */ + //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. */ @@ -54,11 +105,22 @@ 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. */ - hrService = new HeartRateService(ble, hrmCounter, HeartRateService::LOCATION_FINGER); + hidService = new HIDService(ble); /* Setup auxiliary service. */ deviceInfo = new DeviceInformationService(ble, "DELTA", "NQ620", "SN1", "hw-rev1", "fw-rev1", "soft-rev1"); @@ -66,18 +128,28 @@ /* 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::GENERIC_HEART_RATE_SENSOR); + 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(1000); /* 1000ms */ + 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, 1); // blink LED every second + //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); @@ -88,20 +160,63 @@ // infinite loop while (1) { - // check for trigger from periodicCallback() - if (triggerSensorPolling && ble.getGapState().connected) { - triggerSensorPolling = false; - - // Do blocking calls or whatever is necessary for sensor polling. - // In our case, we simply update the HRM measurement. - hrmCounter++; - if (hrmCounter == 175) { // 100 <= HRM bps <=175 - hrmCounter = 100; + 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); + } } - - hrService->updateHeartRate(hrmCounter); } else { ble.waitForEvent(); // low power wait for event + wait(1); } + } }