From d923b261a6ed4a91956cd6aac6bf9bee145ad597 Mon Sep 17 00:00:00 2001 From: schneider <schneider@blinkenlichts.net> Date: Fri, 26 Jun 2020 19:06:24 +0200 Subject: [PATCH] feat(ble): Basic HID support in epicardium --- epicardium/ble/ble_main.c | 18 +- epicardium/ble/cccd.h | 5 + epicardium/ble/hid.c | 217 +++++++++++++++ epicardium/ble/hid.h | 14 + epicardium/ble/hid_work.c | 423 +++++++++++++++++++++++++++++ epicardium/ble/meson.build | 2 + epicardium/epicardium.h | 17 ++ lib/sdk/Libraries/BTLE/meson.build | 2 +- 8 files changed, 694 insertions(+), 4 deletions(-) create mode 100644 epicardium/ble/hid.c create mode 100644 epicardium/ble/hid.h create mode 100644 epicardium/ble/hid_work.c diff --git a/epicardium/ble/ble_main.c b/epicardium/ble/ble_main.c index 431b4310a..12c62f2a9 100644 --- a/epicardium/ble/ble_main.c +++ b/epicardium/ble/ble_main.c @@ -34,6 +34,7 @@ #include "svc_hrs.h" #include "svc_dis.h" #include "svc_batt.h" +#include "svc_hid.h" #include "svc_rscs.h" #include "bas/bas_api.h" #include "hrps/hrps_api.h" @@ -182,9 +183,9 @@ static const uint8_t bleAdvDataDisc[] = DM_ADV_TYPE_128_UUID_PART, CARD10_UUID_SUFFIX, 0x0, CARD10_UUID_PREFIX, - 2, /*! length */ - DM_ADV_TYPE_TX_POWER, /*! AD type */ - 0, /*! tx power */ + 3, /*! length */ + DM_ADV_TYPE_16_UUID_PART, /*! AD type */ + UINT16_TO_BYTES(ATT_UUID_HID_SERVICE) }; /*! scan data, discoverable mode */ @@ -232,6 +233,11 @@ static const attsCccSet_t bleCccSet[BLE_NUM_CCC_IDX] = {ESS_TEMP_CH_CCC_HDL, ATT_CLIENT_CFG_NOTIFY, DM_SEC_LEVEL_NONE}, /* BLE_ESS_TEMP_CCC_IDX */ {ESS_HUMI_CH_CCC_HDL, ATT_CLIENT_CFG_NOTIFY, DM_SEC_LEVEL_NONE}, /* BLE_ESS_HUMI_CCC_IDX */ {ESS_PRES_CH_CCC_HDL, ATT_CLIENT_CFG_NOTIFY, DM_SEC_LEVEL_NONE}, /* BLE_ESS_PRES_CCC_IDX */ + {HID_MOUSE_BOOT_IN_CH_CCC_HDL, ATT_CLIENT_CFG_NOTIFY, DM_SEC_LEVEL_NONE}, /* HIDAPP_MBI_CCC_HDL */ + {HID_KEYBOARD_BOOT_IN_CH_CCC_HDL, ATT_CLIENT_CFG_NOTIFY, DM_SEC_LEVEL_NONE}, /* HIDAPP_KBI_CCC_HDL */ + {HID_INPUT_REPORT_1_CH_CCC_HDL, ATT_CLIENT_CFG_NOTIFY, DM_SEC_LEVEL_NONE}, /* HIDAPP_IN_REMOTE_CCC_HDL */ + {HID_INPUT_REPORT_2_CH_CCC_HDL, ATT_CLIENT_CFG_NOTIFY, DM_SEC_LEVEL_NONE}, /* HIDAPP_IN_KEYBOARD_CCC_HDL */ + {HID_INPUT_REPORT_3_CH_CCC_HDL, ATT_CLIENT_CFG_NOTIFY, DM_SEC_LEVEL_NONE}, /* HIDAPP_IN_MOUSE_CCC_HDL */ }; /************************************************************************************************** @@ -720,6 +726,7 @@ static void scannerScanReport(dmEvt_t *pMsg) * \return None. */ /*************************************************************************************************/ +void HidProcMsg(wsfMsgHdr_t *pMsg); static void bleProcMsg(bleMsg_t *pMsg) { hciLeConnCmplEvt_t *connOpen; @@ -737,6 +744,7 @@ static void bleProcMsg(bleMsg_t *pMsg) case ATTS_HANDLE_VALUE_CNF: BasProcMsg(&pMsg->hdr); + HidProcMsg(&pMsg->hdr); break; case ATTS_CCC_STATE_IND: @@ -771,6 +779,7 @@ static void bleProcMsg(bleMsg_t *pMsg) connOpen->peerAddr[1], connOpen->peerAddr[0]); BasProcMsg(&pMsg->hdr); bleESS_ccc_update(); + HidProcMsg(&pMsg->hdr); break; case DM_CONN_CLOSE_IND: @@ -964,6 +973,8 @@ static void BleHandler(wsfEventMask_t event, wsfMsgHdr_t *pMsg) } } +void hid_init(void); + /*************************************************************************************************/ /*! * \brief Start the application. @@ -992,6 +1003,7 @@ void BleStart(void) SvcBattCbackRegister(BasReadCback, NULL); SvcBattAddGroup(); + hid_init(); /* Reset the device */ DmDevReset(); } diff --git a/epicardium/ble/cccd.h b/epicardium/ble/cccd.h index 2715f6ebb..1f75bc640 100644 --- a/epicardium/ble/cccd.h +++ b/epicardium/ble/cccd.h @@ -7,6 +7,11 @@ enum BLE_ESS_TEMP_CCC_IDX, /*! Environmental sensing service, temperature characteristic */ BLE_ESS_HUMI_CCC_IDX, /*! Environmental sensing service, humidity characteristic */ BLE_ESS_PRES_CCC_IDX, /*! Environmental sensing service, pressure characteristic */ + HIDAPP_MBI_CCC_HDL, /*! HID Boot Mouse Input characteristic */ + HIDAPP_KBI_CCC_HDL, /*! HID Boot Keyboard Input characteristic */ + HIDAPP_IN_REMOTE_CCC_HDL, /*! HID Input Report characteristic for remote inputs */ + HIDAPP_IN_KEYBOARD_CCC_HDL, /*! HID Input Report characteristic for keyboard inputs */ + HIDAPP_IN_MOUSE_CCC_HDL, /*! HID Input Report characteristic for mouse inputs */ BLE_NUM_CCC_IDX }; diff --git a/epicardium/ble/hid.c b/epicardium/ble/hid.c new file mode 100644 index 000000000..c5fedf45e --- /dev/null +++ b/epicardium/ble/hid.c @@ -0,0 +1,217 @@ +/* + * Based on ble-profiles/sources/apps/hidapp/hidapp_main.c + */ +#include "cccd.h" +#include "hid.h" + +#include "wsf_types.h" +#include "dm_api.h" +#include "att_api.h" +#include "svc_hid.h" +#include "hid/hid_api.h" +//#include "hidapp/hidapp_api.h" + +#include "modules/log.h" + +#include <stdio.h> +#include <string.h> +#include <stdint.h> + +/*! HidApp Report Map (Descriptor) */ +/* clang-format off */ +const uint8_t hidReportMap[] = +{ + 0x05, 0x0c, /* Usage Page (Consumer Devices) */ + 0x09, 0x01, /* Usage (Consumer Control) */ + 0xa1, 0x01, /* Collection (Application) */ + 0x85, HIDAPP_REMOTE_REPORT_ID, /* report ID (HIDAPP_REMOTE_REPORT_ID) */ + 0x15, 0x00, /* Logical Minimum (0) */ + 0x25, 0x01, /* Logical Maximum (1) */ + 0x09, 0xe9, /* Usage (Volume Up) */ + 0x09, 0xea, /* Usage (Volume Down) */ + 0x75, 0x01, /* Report Size (1) */ + 0x95, 0x02, /* Report Count (2) */ + 0x81, 0x06, /* Input (Data, Variable, Relative) */ + 0x09, 0xe2, /* Usage (Mute) */ + 0x95, 0x01, /* Report Count (1) */ + 0x81, 0x06, /* Input (Data, Variable, Relative) */ + 0x09, 0xb0, /* Usage (Play) */ + 0x95, 0x01, /* Report Count (1) */ + 0x81, 0x06, /* Input (Data, Variable, Relative) */ + 0x09, 0xb1, /* Usage (Pause) */ + 0x95, 0x01, /* Report Count (1) */ + 0x81, 0x06, /* Input (Data, Variable, Relative) */ + 0x09, 0xb7, /* Usage (Stop) */ + 0x95, 0x01, /* Report Count (1) */ + 0x81, 0x06, /* Input (Data, Variable, Relative) */ + 0x09, 0xb5, /* Usage (Next) */ + 0x95, 0x01, /* Report Count (1) */ + 0x81, 0x06, /* Input (Data, Variable, Relative) */ + 0x09, 0xb6, /* Usage (Previous) */ + 0x95, 0x01, /* Report Count (1) */ + 0x81, 0x06, /* Input (Data, Variable, Relative) */ + 0xc0, /* End Collection */ + 0x05, 0x01, /* Usage Page (Generic Desktop) */ + 0x09, 0x06, /* Usage (Keyboard) */ + 0xA1, 0x01, /* Collection (Application) */ + 0x85, HIDAPP_KEYBOARD_REPORT_ID, /* report ID (HIDAPP_KEYBOARD_REPORT_ID) */ + 0x75, 0x01, /* Report Size (1) */ + 0x95, 0x08, /* Report Count (8) */ + 0x05, 0x07, /* Usage Page (Key Codes) */ + 0x19, 0xe0, /* Usage Minimum (224) */ + 0x29, 0xe7, /* Usage Maximum (231) */ + 0x15, 0x00, /* Logical Minimum (0) */ + 0x25, 0x01, /* Logical Maximum (1) */ + 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 (Constant), 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) */ + 0xC0, /* End Collection (Application) */ + 0x05, 0x01, /* USAGE_PAGE (Generic Desktop) */ + 0x09, 0x02, /* USAGE (Mouse) */ + 0xa1, 0x01, /* COLLECTION (Application) */ + 0x85, HIDAPP_MOUSE_REPORT_ID, /* report ID (HIDAPP_MOUSE_REPORT_ID) */ + 0x09, 0x01, /* USAGE (Pointer) */ + 0xa1, 0x00, /* COLLECTION (Physical) */ + 0x95, 0x03, /* REPORT_COUNT (3) */ + 0x75, 0x01, /* REPORT_SIZE (1) */ + 0x05, 0x09, /* USAGE_PAGE (Button) */ + 0x19, 0x01, /* USAGE_MINIMUM (Button 1) */ + 0x29, 0x03, /* USAGE_MAXIMUM (Button 3) */ + 0x15, 0x00, /* LOGICAL_MINIMUM (0) */ + 0x25, 0x01, /* LOGICAL_MAXIMUM (1) */ + 0x81, 0x02, /* INPUT (Data, Variable, Absolute) */ + 0x95, 0x01, /* REPORT_COUNT (1) */ + 0x75, 0x05, /* REPORT_SIZE (5) */ + 0x81, 0x01, /* INPUT (Constant) */ + 0x75, 0x08, /* REPORT_SIZE (8) */ + 0x95, 0x02, /* REPORT_COUNT (2) */ + 0x05, 0x01, /* USAGE_PAGE (Generic Desktop) */ + 0x09, 0x30, /* USAGE (X) */ + 0x09, 0x31, /* USAGE (Y) */ + 0x15, 0x81, /* LOGICAL_MINIMUM (-127) */ + 0x25, 0x7f, /* LOGICAL_MAXIMUM (127) */ + 0x81, 0x06, /* INPUT (Data, Variable, Relative) */ + 0xc0, /* End Collection (Physical) */ + 0xc0 /* End Collection (Application) */ +}; +/* clang-format on */ + +const uint16_t hidReportMapLen = sizeof(hidReportMap); + +/*! HID Report Type/ID and attribute handle map */ +/* clang-format off */ +static const hidReportIdMap_t hidAppReportIdSet[] = +{ + /* type ID handle */ + {HID_REPORT_TYPE_INPUT, HIDAPP_REMOTE_REPORT_ID, HID_INPUT_REPORT_1_HDL}, /* Remote Input Report */ + {HID_REPORT_TYPE_INPUT, HIDAPP_KEYBOARD_REPORT_ID, HID_INPUT_REPORT_2_HDL}, /* Keyboard Input Report */ + {HID_REPORT_TYPE_OUTPUT, HIDAPP_KEYBOARD_REPORT_ID, HID_OUTPUT_REPORT_HDL}, /* Keyboard Output Report */ + {HID_REPORT_TYPE_FEATURE, HIDAPP_KEYBOARD_REPORT_ID, HID_FEATURE_REPORT_HDL}, /* Keyboard Feature Report */ + {HID_REPORT_TYPE_INPUT, HIDAPP_MOUSE_REPORT_ID, HID_INPUT_REPORT_3_HDL}, /* Mouse Input Report */ + {HID_REPORT_TYPE_INPUT, HID_KEYBOARD_BOOT_ID, HID_KEYBOARD_BOOT_IN_HDL}, /* Boot Keyboard Input Report */ + {HID_REPORT_TYPE_OUTPUT, HID_KEYBOARD_BOOT_ID, HID_KEYBOARD_BOOT_OUT_HDL}, /* Boot Keyboard Output Report */ + {HID_REPORT_TYPE_INPUT, HID_MOUSE_BOOT_ID, HID_MOUSE_BOOT_IN_HDL}, /* Boot Mouse Input Report */ +}; +/* clang-format on */ + +void hidAppOutputCback( + dmConnId_t connId, uint8_t id, uint16_t len, uint8_t *pReport +); +void hidAppFeatureCback( + dmConnId_t connId, uint8_t id, uint16_t len, uint8_t *pReport +); +void hidAppInfoCback(dmConnId_t connId, uint8_t type, uint8_t value); + +/*! HID Profile Configuration */ +/* clang-format off */ +static const hidConfig_t hidAppHidConfig = +{ + (hidReportIdMap_t*) hidAppReportIdSet, /* Report ID to Attribute Handle map */ + sizeof(hidAppReportIdSet)/sizeof(hidReportIdMap_t), /* Size of Report ID to Attribute Handle map */ + &hidAppOutputCback, /* Output Report Callback */ + &hidAppFeatureCback, /* Feature Report Callback */ + &hidAppInfoCback /* Info Callback */ +}; +/* clang-format on */ + +static void hidAppReportInit(void) +{ + uint8_t iKeyboardBuffer[HIDAPP_KEYBOARD_INPUT_REPORT_LEN]; + uint8_t iMouseBuffer[HIDAPP_MOUSE_INPUT_REPORT_LEN]; + uint8_t iRemoteBuffer[HIDAPP_REMOTE_INPUT_REPORT_LEN]; + uint8_t oBuffer[HIDAPP_OUTPUT_REPORT_LEN]; + uint8_t fBuffer[HIDAPP_FEATURE_REPORT_LEN]; + + /* Remote Input report */ + memset(iRemoteBuffer, 0, HIDAPP_REMOTE_INPUT_REPORT_LEN); + AttsSetAttr( + HID_INPUT_REPORT_1_HDL, + HIDAPP_REMOTE_INPUT_REPORT_LEN, + iRemoteBuffer + ); + + /* Keyboard Input report */ + memset(iKeyboardBuffer, 0, HIDAPP_KEYBOARD_INPUT_REPORT_LEN); + AttsSetAttr( + HID_INPUT_REPORT_2_HDL, + HIDAPP_KEYBOARD_INPUT_REPORT_LEN, + iKeyboardBuffer + ); + + /* Mouse Input report */ + memset(iMouseBuffer, 0, HIDAPP_MOUSE_INPUT_REPORT_LEN); + AttsSetAttr( + HID_INPUT_REPORT_3_HDL, + HIDAPP_MOUSE_INPUT_REPORT_LEN, + iMouseBuffer + ); + + /* Output report */ + memset(oBuffer, 0, HIDAPP_OUTPUT_REPORT_LEN); + AttsSetAttr(HID_OUTPUT_REPORT_HDL, HIDAPP_OUTPUT_REPORT_LEN, oBuffer); + + /* Feature report */ + memset(fBuffer, 0, HIDAPP_FEATURE_REPORT_LEN); + AttsSetAttr(HID_FEATURE_REPORT_HDL, HIDAPP_FEATURE_REPORT_LEN, fBuffer); +} + +void hid_work_init(void); +void hid_init(void) +{ +#ifdef HID_ATT_DYNAMIC + /* Initialize the dynamic service system */ + AttsDynInit(); + /* Add the HID service dynamically */ + pSHdl = SvcHidAddGroupDyn(); + AttsDynRegister(pSHdl, NULL, HidAttsWriteCback); +#else + /* Add the HID service statically */ + SvcHidAddGroup(); + SvcHidRegister(HidAttsWriteCback, NULL); +#endif /* HID_ATT_DYNAMIC */ + /* Initialize the HID profile */ + HidInit(&hidAppHidConfig); + + /* Initialize the report attributes */ + hidAppReportInit(); + + hid_work_init(); +} diff --git a/epicardium/ble/hid.h b/epicardium/ble/hid.h new file mode 100644 index 000000000..da489fcbb --- /dev/null +++ b/epicardium/ble/hid.h @@ -0,0 +1,14 @@ +#pragma once + +/* The input report fits in one byte */ +#define HIDAPP_KEYBOARD_INPUT_REPORT_LEN 8 +#define HIDAPP_MOUSE_INPUT_REPORT_LEN 3 +#define HIDAPP_REMOTE_INPUT_REPORT_LEN 1 +#define HIDAPP_OUTPUT_REPORT_LEN 1 +#define HIDAPP_FEATURE_REPORT_LEN 1 + + +/* HID Report IDs */ +#define HIDAPP_REMOTE_REPORT_ID 1 +#define HIDAPP_KEYBOARD_REPORT_ID 2 +#define HIDAPP_MOUSE_REPORT_ID 3 diff --git a/epicardium/ble/hid_work.c b/epicardium/ble/hid_work.c new file mode 100644 index 000000000..b63236d4e --- /dev/null +++ b/epicardium/ble/hid_work.c @@ -0,0 +1,423 @@ +#include "hid.h" +#include "cccd.h" + +#include "modules/log.h" + +#include "dm_api.h" +#include "att_api.h" +#include "app_api.h" +#include "hid/hid_api.h" +#include "svc_hid.h" + +#include <stdint.h> +#include <stdio.h> +#include <string.h> + +/* Remote Button Identifier bits */ +/* clang-format off */ +#define REMOTE_USAGE_NONE (0<<0) +#define REMOTE_VOLUME_UP (1<<0) +#define REMOTE_VOLUME_DOWN (1<<1) +#define REMOTE_MUTE (1<<2) +#define REMOTE_PLAY (1<<3) +#define REMOTE_PAUSE (1<<4) +#define REMOTE_STOP (1<<5) +#define REMOTE_NEXT (1<<6) +#define REMOTE_PREVIOUS (1<<7) + +/* Keyboard input record message format */ +#define KEYBOARD_IR_MODIFIER_POS 0 +#define KEYBOARD_IR_RESERVED_POS 1 +#define KEYBOARD_IR_KEY_POS 2 +#define KEYBOARD_IR_MAX_KEYS 6 + +/* Keyboard LED Identifier bits */ +#define KEYBOARD_LED_NUM_LOCK (1<<0) +#define KEYBOARD_LED_CAPS_LOCK (1<<1) +#define KEYBOARD_LED_SCROLL_LOCK (1<<2) +#define KEYBOARD_LED_COMPOSE (1<<3) +#define KEYBOARD_LED_KANA (1<<4) + +/* Mouse button bit mask */ +#define MOUSE_BUTTON_LEFT (1<<0) +#define MOUSE_BUTTON_RIGHT (1<<1) +#define MOUSE_BUTTON_MIDDLE (1<<2) + +/* Mouse input record message format */ +#define MOUSE_BUTTON_POS 0 +#define MOUSE_X_POS 1 +#define MOUSE_Y_POS 2 + + +/* HidApp TX path flags */ +#define HIDAPP_TX_FLAGS_READY 0x01 +#define HIDAPP_TX_FLAGS_PENDING 0x02 +/* clang-format on */ + +/*! application control block */ +/* clang-format off */ +struct +{ + /* Mouse pending event data */ + uint8_t buttonMask; /* pending button mask */ + uint8_t xDisplacement; /* pending X Displacement */ + uint8_t yDisplacement; /* pending Y Displacement */ + uint8_t devSpecific; /* pending Device Specific */ + + /* Keyboard pending event data */ + uint8_t modifier; /* pending key modifiers */ + uint8_t keys[KEYBOARD_IR_MAX_KEYS]; /* pending keys */ + + /* Remote pending event data */ + uint8_t btnData; /* pending remote button data */ + + uint8_t reportId; /* pending reportId button data */ + uint8_t txFlags; /* transmit flags */ + uint8_t protocolMode; /* current protocol mode */ + uint8_t hostSuspended; /* TRUE if host suspended */ +} hidAppCb; +/* clang-format on */ + +/*************************************************************************************************/ +/*! + * \brief Send example data. + * + * \param connId Connection identifier. + * + * \return None. + */ +/*************************************************************************************************/ +static void hidAppMouseSendData(dmConnId_t connId) +{ + uint8_t cccHandle = HIDAPP_IN_MOUSE_CCC_HDL; + uint8_t protocolMode; + + protocolMode = HidGetProtocolMode(); + + if (protocolMode == HID_PROTOCOL_MODE_BOOT) { + cccHandle = HIDAPP_MBI_CCC_HDL; + } + + if (AttsCccEnabled(connId, cccHandle)) { + if (hidAppCb.txFlags & HIDAPP_TX_FLAGS_PENDING) { + if (hidAppCb.txFlags & HIDAPP_TX_FLAGS_READY) { + uint8_t buffer[HIDAPP_MOUSE_INPUT_REPORT_LEN]; + uint8_t reportId = HIDAPP_MOUSE_REPORT_ID; + + /* mouse record: button mask, x displacement, y displacement, device specific */ + buffer[MOUSE_BUTTON_POS] = hidAppCb.buttonMask; + buffer[MOUSE_X_POS] = hidAppCb.xDisplacement; + buffer[MOUSE_Y_POS] = hidAppCb.yDisplacement; + + hidAppCb.txFlags &= + ~(HIDAPP_TX_FLAGS_READY | + HIDAPP_TX_FLAGS_PENDING); + + if (protocolMode == HID_PROTOCOL_MODE_BOOT) { + reportId = HID_MOUSE_BOOT_ID; + } + + /* Send the message */ + HidSendInputReport( + connId, + reportId, + HIDAPP_MOUSE_INPUT_REPORT_LEN, + buffer + ); + } + } + } else { + hidAppCb.txFlags &= ~HIDAPP_TX_FLAGS_PENDING; + } +} + +/*************************************************************************************************/ +/*! + * \brief Send example data. + * + * \param connId Connection identifier. + * + * \return None. + */ +/*************************************************************************************************/ +static void hidAppkeyboardSendData(dmConnId_t connId) +{ + uint8_t cccHandle = HIDAPP_IN_KEYBOARD_CCC_HDL; + uint8_t protocolMode; + + protocolMode = HidGetProtocolMode(); + + if (protocolMode == HID_PROTOCOL_MODE_BOOT) { + cccHandle = HIDAPP_KBI_CCC_HDL; + } + + if (AttsCccEnabled(connId, cccHandle)) { + if (hidAppCb.txFlags & HIDAPP_TX_FLAGS_PENDING) { + if (hidAppCb.txFlags & HIDAPP_TX_FLAGS_READY) { + uint8_t buffer[HIDAPP_KEYBOARD_INPUT_REPORT_LEN]; + uint8_t reportId = HIDAPP_KEYBOARD_REPORT_ID; + + /* modifier, reserved, keys[6] */ + buffer[KEYBOARD_IR_MODIFIER_POS] = + hidAppCb.modifier; + buffer[KEYBOARD_IR_RESERVED_POS] = 0; + memcpy(buffer + KEYBOARD_IR_KEY_POS, + hidAppCb.keys, + sizeof(hidAppCb.keys)); + + hidAppCb.txFlags &= + ~(HIDAPP_TX_FLAGS_READY | + HIDAPP_TX_FLAGS_PENDING); + + if (protocolMode == HID_PROTOCOL_MODE_BOOT) { + reportId = HID_KEYBOARD_BOOT_ID; + } + + /* Send the message */ + HidSendInputReport( + connId, + reportId, + HIDAPP_KEYBOARD_INPUT_REPORT_LEN, + buffer + ); + } + } + } else { + hidAppCb.txFlags &= ~HIDAPP_TX_FLAGS_PENDING; + } +} +/*************************************************************************************************/ +/*! + * \brief Send example data. + * + * \param connId Connection identifier. + * + * \return None. + */ +/*************************************************************************************************/ +static void hidAppRemoteSendData(dmConnId_t connId) +{ + if (AttsCccEnabled(connId, HIDAPP_IN_REMOTE_CCC_HDL)) { + if (hidAppCb.txFlags & HIDAPP_TX_FLAGS_PENDING) { + if (hidAppCb.txFlags & HIDAPP_TX_FLAGS_READY) { + uint8_t buffer; + + /* bitmask of remote buttons */ + buffer = hidAppCb.btnData; + + hidAppCb.txFlags &= + ~(HIDAPP_TX_FLAGS_READY | + HIDAPP_TX_FLAGS_PENDING); + + /* Send the message */ + HidSendInputReport( + connId, + hidAppCb.reportId, + HIDAPP_REMOTE_INPUT_REPORT_LEN, + &buffer + ); + } + } + } else { + hidAppCb.txFlags &= ~HIDAPP_TX_FLAGS_PENDING; + } +} + +/*************************************************************************************************/ +/*! + * \brief Send example data. + * + * \param connId Connection identifier. + * + * \return None. + */ +/*************************************************************************************************/ +static void hidAppSendData(dmConnId_t connId) +{ + /* Send the report based on report ID */ + switch (hidAppCb.reportId) { + case HIDAPP_REMOTE_REPORT_ID: + hidAppRemoteSendData(connId); + break; + case HIDAPP_KEYBOARD_REPORT_ID: + hidAppkeyboardSendData(connId); + break; + case HIDAPP_MOUSE_REPORT_ID: + hidAppMouseSendData(connId); + break; + default: + break; + } +} + +/*************************************************************************************************/ +/*! + * \brief Send or queue a remote event to the host + * + * \param button Remote control depressed button + * + * \return None. + */ +/*************************************************************************************************/ +void epic_hid_remote_report_event(uint8_t button) +{ + dmConnId_t connId; + + if ((connId = AppConnIsOpen()) != DM_CONN_ID_NONE) { + LOG_INFO("hid", "send button %d\n", button); + /* record key data */ + hidAppCb.btnData = button; + hidAppCb.reportId = HIDAPP_REMOTE_REPORT_ID; + + /* Indicate new data is pending */ + hidAppCb.txFlags |= HIDAPP_TX_FLAGS_PENDING; + + /* send the data */ + hidAppSendData(connId); + } +} + +/*************************************************************************************************/ +/*! + * \brief Send or queue a keyboard event to the host + * + * \param modifiers Keyboard modifiers. + * \param keys Keyboard depressed keys. + * \param numKeys Size of keys parameters in bytes + * + * \return None. + */ +/*************************************************************************************************/ +void epic_hid_keyboard_report_event( + uint8_t modifiers, uint8_t keys[], uint8_t numKeys +) { + dmConnId_t connId; + + if ((connId = AppConnIsOpen()) != DM_CONN_ID_NONE) { + /* max 6 keys in report map */ + if (numKeys > KEYBOARD_IR_MAX_KEYS) { + numKeys = KEYBOARD_IR_MAX_KEYS; + } + + /* record key data */ + hidAppCb.modifier = modifiers; + memset(hidAppCb.keys, 0, sizeof(hidAppCb.keys)); + memcpy(hidAppCb.keys, keys, numKeys); + hidAppCb.reportId = HIDAPP_KEYBOARD_REPORT_ID; + + /* indicate new data is pending */ + hidAppCb.txFlags |= HIDAPP_TX_FLAGS_PENDING; + + /* send the data */ + hidAppSendData(connId); + } +} + +/*************************************************************************************************/ +/*! + * \brief Report or queue a mouse event to the host. + * + * \param buttonMask Mouse button mask. + * \param xDisplacement Mouse displacement in the x direction. + * \param yDisplacement Mouse displacement in the y direction. + * + * \return None. + */ +/*************************************************************************************************/ +void epic_hid_mouse_report_event( + uint8_t buttonMask, uint8_t xDisplacement, uint8_t yDisplacement +) { + dmConnId_t connId; + + if ((connId = AppConnIsOpen()) != DM_CONN_ID_NONE) { + /* record mouse data */ + hidAppCb.buttonMask = buttonMask; + hidAppCb.xDisplacement = xDisplacement; + hidAppCb.yDisplacement = yDisplacement; + hidAppCb.devSpecific = 0; + hidAppCb.reportId = HIDAPP_MOUSE_REPORT_ID; + + /* Indicate new data is pending */ + hidAppCb.txFlags |= HIDAPP_TX_FLAGS_PENDING; + + /* send the data */ + hidAppSendData(connId); + } +} + +/*************************************************************************************************/ +/*! + * \brief Callback to handle an output report from the host. + * + * \param connId The connection identifier. + * \param id The ID of the report. + * \param len The length of the report data in pReport. + * \param pReport A buffer containing the report. + * + * \return None. + */ +/*************************************************************************************************/ +void hidAppOutputCback( + dmConnId_t connId, uint8_t id, uint16_t len, uint8_t *pReport +) { + /* TODO: process output reports */ +} + +/*************************************************************************************************/ +/*! + * \brief Callback to handle a feature report from the host. + * + * \param connId The connection identifier. + * \param id The ID of the report. + * \param len The length of the report data in pReport. + * \param pReport A buffer containing the report. + * + * \return None. + */ +/*************************************************************************************************/ +void hidAppFeatureCback( + dmConnId_t connId, uint8_t id, uint16_t len, uint8_t *pReport +) { + /* TODO: process feature reports */ +} + +/*************************************************************************************************/ +/*! + * \brief Callback to handle a change in protocol mode or control point from the host. + * + * \param connId The connection identifier. + * \param mode The type of information (HID_INFO_CONTROL_POINT or HID_INFO_PROTOCOL_MODE) + * \param value The value of the information + * + * \return None. + */ +/*************************************************************************************************/ +void hidAppInfoCback(dmConnId_t connId, uint8_t type, uint8_t value) +{ + if (type == HID_INFO_PROTOCOL_MODE) { + LOG_INFO("hid", "protocol mode: %u\n", value); + hidAppCb.protocolMode = value; + } else if (type == HID_INFO_CONTROL_POINT) { + LOG_INFO("hid", "host suspended: %u\n", value); + hidAppCb.hostSuspended = + (value == HID_CONTROL_POINT_SUSPEND) ? TRUE : FALSE; + } +} + +void HidProcMsg(wsfMsgHdr_t *pMsg) +{ + if (pMsg->event == ATTS_HANDLE_VALUE_CNF) { + if (pMsg->status == ATT_SUCCESS) { + hidAppCb.txFlags |= HIDAPP_TX_FLAGS_READY; + hidAppSendData((dmConnId_t)pMsg->param); + } + } + if (pMsg->event == DM_CONN_OPEN_IND) { + hidAppCb.txFlags = HIDAPP_TX_FLAGS_READY; + } +} + +void hid_work_init(void) +{ + hidAppCb.txFlags = HIDAPP_TX_FLAGS_READY; +} diff --git a/epicardium/ble/meson.build b/epicardium/ble/meson.build index c2f10a12a..341ad2257 100644 --- a/epicardium/ble/meson.build +++ b/epicardium/ble/meson.build @@ -12,4 +12,6 @@ ble_sources = files( 'card10.c', 'ess.c', 'filetransfer.c', + 'hid.c', + 'hid_work.c', ) diff --git a/epicardium/epicardium.h b/epicardium/epicardium.h index 842714028..80102ee44 100644 --- a/epicardium/epicardium.h +++ b/epicardium/epicardium.h @@ -159,6 +159,10 @@ typedef _Bool bool; #define API_BLE_GET_PEER_DEVICE_NAME 0x146 +#define API_HID_REMOTE_REPORT 0x150 +#define API_HID_KEYBOARD_REPORT 0x151 +#define API_HID_MOUSE_REPORT 0x152 + /* clang-format on */ typedef uint32_t api_int_id_t; @@ -2320,5 +2324,18 @@ API(API_BLE_SET_MODE, void epic_ble_set_mode(bool bondable, bool scanner)); * */ API(API_BLE_GET_SCAN_REPORT, int epic_ble_get_scan_report(struct epic_scan_report *rpt)); + +API(API_HID_REMOTE_REPORT, void epic_hid_remote_report_event(uint8_t button)); + +API(API_HID_KEYBOARD_REPORT, void epic_hid_keyboard_report_event( + uint8_t modifiers, + uint8_t *keys, + uint8_t numKeys +)); +API(API_HID_MOUSE_REPORT, void epic_hid_mouse_report_event( + uint8_t buttonMask, + uint8_t xDisplacement, + uint8_t yDisplacement +)); #endif /* _EPICARDIUM_H */ diff --git a/lib/sdk/Libraries/BTLE/meson.build b/lib/sdk/Libraries/BTLE/meson.build index 1314ad583..2bf03dbb6 100644 --- a/lib/sdk/Libraries/BTLE/meson.build +++ b/lib/sdk/Libraries/BTLE/meson.build @@ -48,7 +48,7 @@ sources = files( 'stack/ble-profiles/sources/apps/meds/meds_htp.c', 'stack/ble-profiles/sources/apps/meds/meds_plx.c', 'stack/ble-profiles/sources/apps/meds/meds_glp.c', -'stack/ble-profiles/sources/apps/hidapp/hidapp_main.c', +#'stack/ble-profiles/sources/apps/hidapp/hidapp_main.c', 'stack/ble-profiles/sources/apps/watch/watch_main.c', 'stack/ble-profiles/sources/apps/datc/datc_main.c', 'stack/ble-profiles/sources/apps/gluc/gluc_main.c', -- GitLab