Example for BLE HID scanner
Fork of BLE_HIDScanner_DELTA by
Revision 1:8bca989a70be, committed 2017-02-07
- Comitter:
- silviaChen
- Date:
- Tue Feb 07 02:51:56 2017 +0000
- Parent:
- 0:c7bcc0b36b5e
- Child:
- 2:9f46fa6237dd
- Commit message:
- BLE HID Keyboard demo
Changed in this revision
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/HIDService.cpp Tue Feb 07 02:51:56 2017 +0000
@@ -0,0 +1,46 @@
+#include "HIDService.h"
+
+const uint8_t KeyboardReportMap[] =
+ { 0x05, 0x01, // Usage Page (Generic Desktop)
+ 0x09, 0x06, // Usage (Keyboard)
+ 0xA1, 0x01, // Collection (Application)
+ 0x05, 0x07, // Usage Page (Key Codes)
+ 0x19, 0xe0, // Usage Minimum (224)
+ 0x29, 0xe7, // Usage Maximum (231)
+ 0x15, 0x00, // Logicagl Minimum (0)
+ 0x25, 0x01, // Logical Maximum (1)
+ 0x75, 0x01, // Report Size (1)
+ 0x95, 0x08, // Report Count (8)
+ 0x81, 0x02, // Input (Data, Variable, Absolute)
+
+ 0x95, 0x01, // Report Count (1)
+ 0x75, 0x08, // Report Size (8)
+ 0x81, 0x01, // Input (Constant) reserved byte(1)
+
+ 0x95, 0x05, // Report Count (5)
+ 0x75, 0x01, // Report Size (1)
+ 0x05, 0x08, // Usage Page (Page# for LEDs)
+ 0x19, 0x01, // Usage Minimum (1)
+ 0x29, 0x05, // Usage Maximum (5)
+ 0x91, 0x02, // Output (Data, Variable, Absolute), Led report
+ 0x95, 0x01, // Report Count (1)
+ 0x75, 0x03, // Report Size (3)
+ 0x91, 0x01, // Output (Data, Variable, Absolute), Led report padding
+
+ 0x95, 0x06, // Report Count (6)
+ 0x75, 0x08, // Report Size (8)
+ 0x15, 0x00, // Logical Minimum (0)
+ 0x25, 0x65, // Logical Maximum (101)
+ 0x05, 0x07, // Usage Page (Key codes)
+ 0x19, 0x00, // Usage Minimum (0)
+ 0x29, 0x65, // Usage Maximum (101)
+ 0x81, 0x00, // Input (Data, Array) Key array(6 bytes)
+
+ 0x09, 0x05, // Usage (Vendor Defined)
+ 0x15, 0x00, // Logical Minimum (0)
+ 0x26, 0xFF, 0x00, // Logical Maximum (255)
+ 0x75, 0x08, // Report Count (2)
+ 0x95, 0x02, // Report Size (8 bit)
+ 0xB1, 0x02, // Feature (Data, Variable, Absolute)
+ 0xC0 // End Collection (Application)
+ };
\ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/HIDService.h Tue Feb 07 02:51:56 2017 +0000
@@ -0,0 +1,132 @@
+#ifndef __BLE_HID_SERVICE_H__
+#define __BLE_HID_SERVICE_H__
+
+#include "BLE.h"
+/**
+* @class Human Interface Device Service
+* @brief BLE Human Interface Device Service. This service displays the Glucose measurement value represented as a 16bit Float format.<br>
+* @Author: Marco.Hsu
+* @Email: marco.missyou@gmail.com
+*/
+
+extern const uint8_t KeyboardReportMap[76];
+
+class HIDService {
+public:
+ HIDService(BLEDevice &_ble, const uint8_t* key = &KeyboardReportMap[0]):
+ ble(_ble),
+ protocol_modeValue(1), // Report Protocol Mode(1), Boot Protocol Mode(0)
+ KeyboardMap(key),
+ Protocol_Mode(GattCharacteristic::UUID_PROTOCOL_MODE_CHAR, &protocol_modeValue, 1, 1, GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_WRITE_WITHOUT_RESPONSE|GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_READ),
+ ReportMap(GattCharacteristic::UUID_REPORT_MAP_CHAR, KeyboardMap.getPointer(), 76, sizeof(KeyboardMap), GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_READ |GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_NOTIFY),
+ Report(GattCharacteristic::UUID_REPORT_CHAR, reportValue.getPointer(), 8, 8, GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_NOTIFY|GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_READ),
+ HID_Information(GattCharacteristic::UUID_HID_INFORMATION_CHAR, hidInformation.getPointer(), 4, 4, GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_READ),
+ HID_Control_Point(GattCharacteristic::UUID_HID_CONTROL_POINT_CHAR, &hidcontrolPointer, 1, 1, GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_WRITE_WITHOUT_RESPONSE)
+ {
+ static bool serviceAdded = false; /* We should only ever need to add the heart rate service once. */
+ if (serviceAdded) {
+ return;
+ }
+
+ //SecurityManager::SecurityMode_t securityMode = SecurityManager::SECURITY_MODE_ENCRYPTION_NO_MITM;
+ Protocol_Mode.requireSecurity(SecurityManager::SECURITY_MODE_ENCRYPTION_NO_MITM);
+ ReportMap.requireSecurity(SecurityManager::SECURITY_MODE_ENCRYPTION_NO_MITM);
+ Report.requireSecurity(SecurityManager::SECURITY_MODE_ENCRYPTION_NO_MITM);
+ HID_Information.requireSecurity(SecurityManager::SECURITY_MODE_ENCRYPTION_NO_MITM);
+ HID_Control_Point.requireSecurity(SecurityManager::SECURITY_MODE_ENCRYPTION_NO_MITM);
+ GattCharacteristic *charTable[] = {&Protocol_Mode, &ReportMap, &Report, &HID_Information, &HID_Control_Point};
+ GattService HIDGattService(GattService::UUID_HUMAN_INTERFACE_DEVICE_SERVICE, charTable, sizeof(charTable) / sizeof(GattCharacteristic *));
+ ble.addService(HIDGattService);
+ serviceAdded = true;
+ ble.onDataWritten(this, &HIDService::onDataWritten);
+ }
+public:
+ void updateReport(uint8_t modifydata, uint8_t data) {
+ reportValue.updateReportValue(modifydata, data);
+
+ //ble.updateCharacteristicValue(Report.getValueAttribute().getHandle(), reportValue.getPointer(), 8);
+ ble.gattServer().write(Report.getValueAttribute().getHandle(), reportValue.getPointer(), 8);
+ }
+
+ virtual void onDataWritten(const GattWriteCallbackParams *params) {
+ if (params->handle == HID_Control_Point.getValueAttribute().getHandle()) {
+ uint16_t bytesRead = params->len;
+ if (bytesRead == 1) {
+ memcpy(&hidcontrolPointer, params->data, bytesRead);
+ }
+ }
+ if (params->handle == Report.getValueAttribute().getHandle()) {
+ uint16_t bytesRead = params->len;
+ if (bytesRead <= 4) {
+ memcpy(&reportValue, params->data, bytesRead);
+ }
+ }
+ }
+
+private:
+ struct ReportMapStructure{
+ uint8_t KeyboardMap[76];
+ ReportMapStructure(const uint8_t* data): KeyboardMap() {
+ memcpy(&KeyboardMap[0], data, 76);
+ }
+ uint8_t *getPointer(void) {
+ return KeyboardMap;
+ }
+ };
+
+private:
+ struct ReportStructure {
+ // Initial setting report value
+ ReportStructure(): reportValue() {
+ uint8_t data= 0x00;
+ updateReportValue(data, data);
+ }
+
+ void updateReportValue(uint8_t modifyKey, uint8_t data){
+ memset(&reportValue[0], 0 ,8);
+ memcpy(&reportValue[0], &modifyKey, 1);
+ memcpy(&reportValue[2], &data, 1);
+ }
+
+ uint8_t *getPointer(void) {
+ return reportValue;
+ }
+
+ uint8_t reportValue[8];
+ };
+
+private:
+ struct HIDInforStructure{
+ uint16_t bcdHID;
+ uint8_t bCountryCode;
+ uint8_t Flags;
+
+ HIDInforStructure():bcdHID(0),bCountryCode(0),Flags(0){
+ memcpy(&hidInformation[0], &bcdHID, 2);
+ memcpy(&hidInformation[2], &bCountryCode, 1);
+ memcpy(&hidInformation[3], &Flags, 1);
+ }
+ uint8_t *getPointer(void) {
+ return hidInformation;
+ }
+
+ uint8_t hidInformation[4];
+ };
+
+private:
+ BLEDevice &ble;
+ uint8_t protocol_modeValue;
+ ReportStructure reportValue;
+ uint8_t hidcontrolPointer;
+ ReportMapStructure KeyboardMap;
+ HIDInforStructure hidInformation;
+ GattCharacteristic Protocol_Mode;
+ GattCharacteristic ReportMap;
+ GattCharacteristic Report;
+// ReadOnlyGattCharacteristic Boot_Keyboard_Input_Report;
+// ReadWriteGattCharacteristic Boot_Keyboard_Output_Report;
+// ReadOnlyGattCharacteristic Boot_Mouse_Input_Report;
+ GattCharacteristic HID_Information;
+ GattCharacteristic HID_Control_Point;
+};
+#endif /* #ifndef __BLE_GLUCOSE_SERVICE_H__*/
\ No newline at end of file
--- 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);
}
+
}
}
