diff --git a/epicardium/ble/hid_work.c b/epicardium/ble/hid_work.c index b0158feaa039af9fa2dbe35a6701c47a0ae95058..1d529491efecb0a7a1ef3196bc9d4d343e3449cc 100644 --- a/epicardium/ble/hid_work.c +++ b/epicardium/ble/hid_work.c @@ -1,6 +1,7 @@ #include "hid.h" #include "cccd.h" +#include "epicardium.h" #include "modules/log.h" #include "dm_api.h" @@ -9,339 +10,128 @@ #include "hid/hid_api.h" #include "svc_hid.h" +#include "FreeRTOS.h" +#include "queue.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 */ +#define HIDAPP_TX_FLAGS_READY 0x01 /*! 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) || 1) { - 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; +struct report { + uint8_t reportId; + uint8_t data[8]; + uint8_t len; +}; - hidAppCb.txFlags &= - ~(HIDAPP_TX_FLAGS_READY | - HIDAPP_TX_FLAGS_PENDING); +#define QUEUE_SIZE 10 - if (protocolMode == HID_PROTOCOL_MODE_BOOT) { - reportId = HID_MOUSE_BOOT_ID; - } +static QueueHandle_t queue; +static uint8_t buffer[sizeof(struct report) * QUEUE_SIZE]; +static StaticQueue_t queue_data; - /* Send the message */ - HidSendInputReport( - connId, - reportId, - HIDAPP_MOUSE_INPUT_REPORT_LEN, - buffer - ); - } - } - } else { - hidAppCb.txFlags &= ~HIDAPP_TX_FLAGS_PENDING; +static int hid_queue_data(uint8_t reportId, uint8_t *data, uint8_t len) +{ + struct report report; + report.reportId = reportId; + memcpy(report.data, data, len); + report.len = len; + + if (xQueueSend(queue, &report, 0) != pdTRUE) { + /* Likely full */ + return -EAGAIN; } + + return 0; } -/*************************************************************************************************/ -/*! - * \brief Send example data. - * - * \param connId Connection identifier. - * - * \return None. - */ -/*************************************************************************************************/ -static void hidAppkeyboardSendData(dmConnId_t connId) +static bool hid_dequeue_data(dmConnId_t connId) { - uint8_t cccHandle = HIDAPP_IN_KEYBOARD_CCC_HDL; - uint8_t protocolMode; + uint8_t cccHandle; + struct report report; - protocolMode = HidGetProtocolMode(); + //lock(); - if (protocolMode == HID_PROTOCOL_MODE_BOOT) { - cccHandle = HIDAPP_KBI_CCC_HDL; + if (!(hidAppCb.txFlags & HIDAPP_TX_FLAGS_READY)) { + //unlock(); + return false; } - if (AttsCccEnabled(connId, cccHandle) || 1) { - 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; - } + // Loop until a CCC is enabled or the queue is empty + while (true) { + if (xQueueReceive(queue, &report, 0) != pdTRUE) { + break; + } - /* Send the message */ - HidSendInputReport( - connId, - reportId, - HIDAPP_KEYBOARD_INPUT_REPORT_LEN, - buffer - ); + if (HidGetProtocolMode() == HID_PROTOCOL_MODE_BOOT) { + if (report.reportId == HIDAPP_KEYBOARD_REPORT_ID) { + report.reportId = HID_KEYBOARD_BOOT_ID; + cccHandle = HIDAPP_KBI_CCC_HDL; + } else if (report.reportId == HIDAPP_MOUSE_REPORT_ID) { + report.reportId = HID_MOUSE_BOOT_ID; + cccHandle = HIDAPP_MBI_CCC_HDL; + } else { + break; } + } else { + if (report.reportId == HIDAPP_KEYBOARD_REPORT_ID) { + cccHandle = HIDAPP_IN_KEYBOARD_CCC_HDL; + } else if (report.reportId == HIDAPP_MOUSE_REPORT_ID) { + cccHandle = HIDAPP_IN_MOUSE_CCC_HDL; + } else if (report.reportId == HIDAPP_REMOTE_REPORT_ID) { + cccHandle = HIDAPP_IN_REMOTE_CCC_HDL; + } else { + break; + }; } - } 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) || 1) { - 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 - ); - } + if (AttsCccEnabled(connId, cccHandle) || 1) { + hidAppCb.txFlags &= ~(HIDAPP_TX_FLAGS_READY); + /* Send the message */ + HidSendInputReport( + connId, + report.reportId, + report.len, + report.data + ); + break; } - } 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; - } + //unlock(); + return true; } -/*************************************************************************************************/ -/*! - * \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) +int epic_hid_send_report(uint8_t reportId, uint8_t *data, uint8_t len) { - 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); + dmConnId_t connId = AppConnIsOpen(); + if (connId == DM_CONN_ID_NONE) { + return -EIO; } -} - -/*************************************************************************************************/ -/*! - * \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; + int ret; + ret = hid_queue_data(reportId, data, len); - /* indicate new data is pending */ - hidAppCb.txFlags |= HIDAPP_TX_FLAGS_PENDING; - - /* send the data */ - hidAppSendData(connId); + if (ret < 0) { + return ret; } -} - -/*************************************************************************************************/ -/*! - * \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, int8_t xDisplacement, int8_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); + if (hid_dequeue_data(connId)) { + return 0; + } else { + return 1; } } @@ -409,15 +199,25 @@ 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); + hid_dequeue_data((dmConnId_t)pMsg->param); } } if (pMsg->event == DM_CONN_OPEN_IND) { hidAppCb.txFlags = HIDAPP_TX_FLAGS_READY; + + struct report report; + while (xQueueReceive(queue, &report, 0) == pdTRUE) + ; + + /* Todo: At this point the CCC descriptors are not set up yet + * and things which get sent until then are discarded. */ } } void hid_work_init(void) { + queue = xQueueCreateStatic( + QUEUE_SIZE, sizeof(struct report), buffer, &queue_data + ); hidAppCb.txFlags = HIDAPP_TX_FLAGS_READY; } diff --git a/epicardium/epicardium.h b/epicardium/epicardium.h index 2ca919c196b87a55ea5b7cffa518220fe1fce925..db5369ecb7b162c49a591442bbe07d6cad1ce92d 100644 --- a/epicardium/epicardium.h +++ b/epicardium/epicardium.h @@ -158,10 +158,7 @@ typedef _Bool bool; #define API_BLE_GET_LAST_PAIRING_NAME 0x145 #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 +#define API_HID_SEND_REPORT 0x150 /* clang-format on */ @@ -2325,17 +2322,28 @@ 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, - int8_t xDisplacement, - int8_t yDisplacement -)); + +/** + * Human Interface Device (HID) + * ========================== + */ + +/** + * Send an input report to the host. + * + * :param uint8_t reportId: The id of the report to use. 0: remote, 1: keyboard, 2: mouse + * :param uint8_t *data: Data to be reported. + * :param uint8_t len: Length in bytes of the data to be reported. Maximum length in 8 bytes. + * + * :return: `0` on success, `1` if the report is queued or a negative value if an error occured. Possible + * errors: + * + * - ``-EIO``: There is no host device connected + * - ``-EAGAIN``: There is no space in the queue available. Try again later. + * + */ +API(API_HID_SEND_REPORT, int epic_hid_send_report(uint8_t reportId, uint8_t *data, uint8_t len)); + #endif /* _EPICARDIUM_H */ diff --git a/preload/apps/hid.py b/preload/apps/hid.py index fdf47a52a0c5d860ac0fe43acb3935d81f37c684..53587f739c25a470e7a322c06cbcb8c9498b5b12 100644 --- a/preload/apps/hid.py +++ b/preload/apps/hid.py @@ -24,9 +24,10 @@ while True: b_old = b_new if b_new == buttons.TOP_RIGHT: hid.set_button(BUTTON_VOLUME_UP) + hid.set_button(0) elif b_new == buttons.BOTTOM_RIGHT: hid.set_button(BUTTON_VOLUME_DOWN) + hid.set_button(0) elif b_new == buttons.BOTTOM_LEFT: hid.set_button(BUTTON_PLAY) - else: hid.set_button(0) diff --git a/pycardium/modules/hid.c b/pycardium/modules/hid.c index ba134f6ff19c504504d9277474add8f94a8a634e..25134d5dc9225c2e57d4522a6927e41495be01bf 100644 --- a/pycardium/modules/hid.c +++ b/pycardium/modules/hid.c @@ -6,9 +6,10 @@ static mp_obj_t mp_hid_set_button(mp_obj_t button_id) { - int id = mp_obj_get_int(button_id); - epic_hid_remote_report_event(id); - return mp_const_none; + int id = mp_obj_get_int(button_id); + uint8_t data[] = { id }; + int ret = epic_hid_send_report(1, data, sizeof(data)); + return mp_obj_new_int(ret); } static MP_DEFINE_CONST_FUN_OBJ_1(hid_set_button_obj, mp_hid_set_button);