hid_work.c 5.70 KiB
#include "hid.h"
#include "cccd.h"
#include "epicardium.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 "FreeRTOS.h"
#include "queue.h"
#include <stdint.h>
#include <stdio.h>
#include <string.h>
/* HidApp TX path flags */
#define HIDAPP_TX_FLAGS_READY 0x01
/*! application control block */
/* clang-format off */
struct
{
uint8_t txFlags; /* transmit flags */
uint8_t protocolMode; /* current protocol mode */
uint8_t hostSuspended; /* TRUE if host suspended */
} hidAppCb;
/* clang-format on */
struct report {
uint8_t report_id;
uint8_t data[8];
uint8_t len;
};
#define QUEUE_SIZE 10
static QueueHandle_t queue;
static uint8_t buffer[sizeof(struct report) * QUEUE_SIZE];
static StaticQueue_t queue_data;
static int hid_queue_data(uint8_t report_id, uint8_t *data, uint8_t len)
{
struct report report;
if (report_id < 1 || report_id > 3) {
return -EINVAL;
}
report.report_id = report_id;
if (len > sizeof(report.data)) {
return -EINVAL;
}
memcpy(report.data, data, len);
report.len = len;
if (xQueueSend(queue, &report, 0) != pdTRUE) {
/* Likely full */
return -EAGAIN;
}
return 0;
}
static bool hid_dequeue_data(dmConnId_t connId)
{
uint8_t cccHandle;
struct report report;
//lock();
if (!(hidAppCb.txFlags & HIDAPP_TX_FLAGS_READY)) {
//unlock();
return false;
}
// Loop until a CCC is enabled or the queue is empty
while (true) {
if (xQueueReceive(queue, &report, 0) != pdTRUE) {
break;
}
if (HidGetProtocolMode() == HID_PROTOCOL_MODE_BOOT) {
if (report.report_id == HIDAPP_KEYBOARD_REPORT_ID) {
report.report_id = HID_KEYBOARD_BOOT_ID;
cccHandle = HIDAPP_KBI_CCC_HDL;
} else if (report.report_id == HIDAPP_MOUSE_REPORT_ID) {
report.report_id = HID_MOUSE_BOOT_ID;
cccHandle = HIDAPP_MBI_CCC_HDL;
} else {
break;
}
} else {
if (report.report_id == HIDAPP_KEYBOARD_REPORT_ID) {
cccHandle = HIDAPP_IN_KEYBOARD_CCC_HDL;
} else if (report.report_id == HIDAPP_MOUSE_REPORT_ID) {
cccHandle = HIDAPP_IN_MOUSE_CCC_HDL;
} else if (report.report_id == HIDAPP_CONSUMER_REPORT_ID) {
cccHandle = HIDAPP_IN_CONSUMER_CCC_HDL;
} else {
break;
};
}
if (AttsCccEnabled(connId, cccHandle) || 1) {
hidAppCb.txFlags &= ~(HIDAPP_TX_FLAGS_READY);
/* Send the message */
HidSendInputReport(
connId,
report.report_id,
report.len,
report.data
);
break;
}
}
//unlock();
return true;
}
/*************************************************************************************************/
/*!
* \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 (!queue) {
/* Not initialized (yet). */
return;
}
if (pMsg->event == ATTS_HANDLE_VALUE_CNF) {
if (pMsg->status == ATT_SUCCESS) {
hidAppCb.txFlags |= HIDAPP_TX_FLAGS_READY;
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. */
}
}
int epic_ble_hid_send_report(uint8_t report_id, uint8_t *data, uint8_t len)
{
dmConnId_t connId = AppConnIsOpen();
if (connId == DM_CONN_ID_NONE) {
return -EIO;
}
int ret;
ret = hid_queue_data(report_id, data, len);
if (ret < 0) {
return ret;
}
if (hid_dequeue_data(connId)) {
return 0;
} else {
return 1;
}
}
void hid_work_init(void)
{
queue = xQueueCreateStatic(
QUEUE_SIZE, sizeof(struct report), buffer, &queue_data
);
hidAppCb.txFlags = HIDAPP_TX_FLAGS_READY;
}