Files
base/middleware/usb/uC-USBH/Class/HID/usbh_hidparser.c
2025-11-07 09:57:14 +08:00

1232 lines
50 KiB
C

/*
*********************************************************************************************************
* uC/USB-Host
* The Embedded USB Host Stack
*
* Copyright 2004-2021 Silicon Laboratories Inc. www.silabs.com
*
* SPDX-License-Identifier: APACHE-2.0
*
* This software is subject to an open source license and is distributed by
* Silicon Laboratories Inc. pursuant to the terms of the Apache License,
* Version 2.0 available at www.apache.org/licenses/LICENSE-2.0.
*
*********************************************************************************************************
*/
/*
*********************************************************************************************************
*
* HUMAN INTERFACE DEVICE CLASS PARSER
*
* Filename : usbh_hidparser.c
* Version : V3.42.01
*********************************************************************************************************
*/
/*
*********************************************************************************************************
* INCLUDE FILES
*********************************************************************************************************
*/
#define USBH_HIDPARSER_MODULE
#define MICRIUM_SOURCE
#include "usbh_hid.h"
#include "usbh_hidparser.h"
#include "../../Source/usbh_core.h"
/*
*********************************************************************************************************
* LOCAL DEFINES
*********************************************************************************************************
*/
#define USBH_HID_ITEM_SIZE(x) (((x) & 0x03u) == 3u ? 4u : ((x) & 0x03u))
#define USBH_HID_ITEM_TYPE(x) ((((x) & 0x0Cu) >> 2u) & 0x03u)
#define USBH_HID_ITEM_TAG(x) ((((x) & 0xF0u) >> 4u) & 0x0Fu)
#define USBH_HID_SIGNED_DATA(p_parser) (((p_parser)->Size == 1u) ? p_parser->Data.S08 : \
((p_parser)->Size == 2u) ? p_parser->Data.S16 : \
((p_parser)->Size == 4u) ? p_parser->Data.S32 : 0u)
#define USBH_HID_UNSIGNED_DATA(p_parser) (((p_parser)->Size == 1u) ? p_parser->Data.U08 : \
((p_parser)->Size == 2u) ? p_parser->Data.U16 : \
((p_parser)->Size == 4u) ? p_parser->Data.U32 : 0u)
/* ----------------- UNDEFINED VALUES ----------------- */
#define USBH_HID_USAGEPAGE_UNDEFINED 0x00000000u
#define USBH_HID_LOG_MIN_UNDEFINED 0x7FFFFFFFu
#define USBH_HID_LOG_MAX_UNDEFINED 0x80000000u
#define USBH_HID_PHY_MIN_UNDEFINED 0x7FFFFFFFu
#define USBH_HID_PHY_MAX_UNDEFINED 0x80000000u
#define USBH_HID_UNIT_EXP_UNDEFINED 0x7FFFFFFFu
#define USBH_HID_USAGE_MIN_UNDEFINED 0xFFFFFFFFu
#define USBH_HID_USAGE_MAX_UNDEFINED 0xFFFFFFFFu
#define USBH_HID_UNIT_UNDEFINED 0xFFFFFFFFu
#define USBH_HID_REPORT_SIZE_UNDEFINED 0u
#define USBH_HID_REPORT_CNT_UNDEFINED 0u
/*
*********************************************************************************************************
* LOCAL CONSTANTS
*********************************************************************************************************
*/
/*
*********************************************************************************************************
* LOCAL DATA TYPES
*********************************************************************************************************
*/
/* -------------- GLOBAL ITEM DATA TYPE --------------- */
typedef struct usbh_hid_global USBH_HID_GLOBAL;
struct usbh_hid_global {
CPU_INT16U UsagePage; /* Usage Page. */
CPU_INT08U ReportID; /* Report ID. */
CPU_INT32S LogMin; /* Logical Minimun. */
CPU_INT32S LogMax; /* Logical Maximum. */
CPU_INT32S PhyMin; /* Physical Minimum. */
CPU_INT32S PhyMax; /* Physical Maximum. */
CPU_INT32S UnitExp; /* Unit exponent. */
CPU_INT32S Unit; /* Unit. */
CPU_INT32U ReportSize; /* Report Size (bits). */
CPU_INT32U ReportCnt; /* Report Count. */
USBH_HID_GLOBAL *NextPtr; /* Pointer to next global this for global stack. */
};
/* --------------- LOCAL ITEM DATA TYPE --------------- */
typedef struct usbh_hid_local {
CPU_INT32U Usage[USBH_HID_CFG_MAX_NBR_USAGE]; /* Usage array. */
CPU_INT32U NbrUsage; /* Number of usages. */
CPU_INT32U UsageMin; /* Usage Minimum. */
CPU_INT32U UsageMax; /* Usage Maximum. */
} USBH_HID_LOCAL;
/* ---------------------- PARSER ---------------------- */
typedef struct usbh_hid_parser {
USBH_HID_LOCAL Local; /* Local items. */
USBH_HID_GLOBAL Global; /* Global items. */
USBH_HID_GLOBAL *GlobalStkPtr; /* Global items stack for push and pop. */
USBH_HID_COLL *CollStkPtr; /* Collection stack. */
CPU_INT08U AppCollNbr; /* Present Apllication Collection number. */
CPU_INT08U Type; /* Item Type. */
CPU_INT08U Tag; /* Item Tag. */
CPU_INT08U Size; /* Item Size. */
union {
CPU_INT08U U08;
CPU_INT08S S08;
CPU_INT16U U16;
CPU_INT16S S16;
CPU_INT32U U32;
CPU_INT32S S32;
} Data; /* Item Data. */
} USBH_HID_PARSER;
/*
*********************************************************************************************************
* LOCAL TABLES
*********************************************************************************************************
*/
/*
*********************************************************************************************************
* LOCAL GLOBAL VARIABLES
*********************************************************************************************************
*/
static MEM_POOL USBH_HID_CollPool;
static USBH_HID_COLL USBH_HID_CollList[USBH_HID_CFG_MAX_COLL];
static MEM_POOL USBH_HID_GlobalItemPool;
static USBH_HID_GLOBAL USBH_HID_GlobalItemList[USBH_HID_CFG_MAX_GLOBAL];
/*
*********************************************************************************************************
* LOCAL FUNCTION PROTOTYPES
*********************************************************************************************************
*/
static void USBH_HID_InitGlobalItem(USBH_HID_GLOBAL *p_global);
static void USBH_HID_InitLocalItem (USBH_HID_LOCAL *p_local);
static void USBH_HID_InitItemParser(USBH_HID_PARSER *p_parser);
static void USBH_HID_FreeItemParser(USBH_HID_PARSER *p_parser);
static USBH_ERR USBH_HID_ParseMain (USBH_HID_DEV *p_hid_dev,
USBH_HID_PARSER *p_parser);
static USBH_ERR USBH_HID_ParseGlobal (USBH_HID_PARSER *p_parser);
static USBH_ERR USBH_HID_ParseLocal (USBH_HID_PARSER *p_parser);
static USBH_ERR USBH_HID_OpenColl (USBH_HID_DEV *p_hid_dev,
USBH_HID_PARSER *p_parser);
static USBH_ERR USBH_HID_CloseColl (USBH_HID_PARSER *p_parser);
static USBH_ERR USBH_HID_AddReport (USBH_HID_DEV *p_hid_dev,
USBH_HID_PARSER *p_parser);
static USBH_ERR USBH_HID_ValidateReport(USBH_HID_REPORT_FMT *p_report_fmt);
static void USBH_HID_InitReport (USBH_HID_PARSER *p_parser,
USBH_HID_REPORT_FMT *p_report_fmt);
static void USBH_HID_SetData (USBH_HID_PARSER *p_parser,
void *p_buf);
/*
*********************************************************************************************************
* LOCAL CONFIGURATION ERRORS
*********************************************************************************************************
*/
/*
*********************************************************************************************************
*********************************************************************************************************
* GLOBAL FUNCTION
*********************************************************************************************************
*********************************************************************************************************
*/
/*
*********************************************************************************************************
* USBH_HID_ParserGlobalInit()
*
* Description : Initialize global data.
*
* Argument(s) : p_hid_dev Pointer to HID device.
*
* Return(s) : USBH_ERR_NONE, if initialization is succesful.
* USBH_ERR_ALLOC, if global item or collection list allocation failed.
*
* Note(s) : None.
*********************************************************************************************************
*/
USBH_ERR USBH_HID_ParserGlobalInit (void)
{
LIB_ERR err_lib;
CPU_SIZE_T octets_reqd;
Mem_PoolCreate ( &USBH_HID_CollPool, /* POOL for managing collection structures. */
(void *)USBH_HID_CollList,
(sizeof(USBH_HID_COLL) * USBH_HID_CFG_MAX_COLL),
USBH_HID_CFG_MAX_COLL,
sizeof(USBH_HID_COLL),
sizeof(CPU_ALIGN),
&octets_reqd,
&err_lib);
if (err_lib != LIB_MEM_ERR_NONE) {
#if (USBH_CFG_PRINT_LOG == DEF_ENABLED)
USBH_PRINT_LOG("%d octets required\r\n", octets_reqd);
#endif
return (USBH_ERR_ALLOC);
}
Mem_PoolCreate ( &USBH_HID_GlobalItemPool, /* POOL for managing global item structures. */
(void *)USBH_HID_GlobalItemList,
(sizeof(USBH_HID_GLOBAL) * USBH_HID_CFG_MAX_GLOBAL),
USBH_HID_CFG_MAX_GLOBAL,
sizeof(USBH_HID_GLOBAL),
sizeof(CPU_ALIGN),
&octets_reqd,
&err_lib);
if (err_lib != LIB_MEM_ERR_NONE) {
#if (USBH_CFG_PRINT_LOG == DEF_ENABLED)
USBH_PRINT_LOG("%d octets required\r\n", octets_reqd);
#endif
return (USBH_ERR_ALLOC);
}
return (USBH_ERR_NONE);
}
/*
*********************************************************************************************************
* USBH_HID_ItemParser()
*
* Description : Parse report descriptor.
*
* Argument(s) : p_hid_dev Pointer to HID device.
*
* p_report_desc Pointer to report descriptor buffer.
*
* desc_len Length of report descriptor buffer in octets.
*
* Return(s) : USBH_ERR_NONE, if report successfully parsed.
* USBH_ERR_UNKNOWN, if unknown error occurred.
* USBH_ERR_HID_ITEM_LONG, if long item present (not supported).
* USBH_ERR_HID_ITEM_UNKNOWN, if unknown item present.
* USBH_ERR_HID_MISMATCH_COLL, if there is a collection mismatch.
* USBH_ERR_HID_MISMATCH_PUSH_POP, if global stack error occured.
*
* Note(s) : None.
*********************************************************************************************************
*/
USBH_ERR USBH_HID_ItemParser (USBH_HID_DEV *p_hid_dev,
CPU_INT08U *p_report_desc,
CPU_INT32U desc_len)
{
USBH_HID_PARSER parser;
CPU_INT32U pos;
CPU_INT08U item;
USBH_ERR err;
/* ----------------- INITIALIZE DATA ------------------ */
USBH_HID_InitItemParser(&parser);
pos = 0u;
err = USBH_ERR_UNKNOWN;
/* ------------- PARSE REPORT DESCRIPTOR -------------- */
while (pos < desc_len) {
item = p_report_desc[pos++];
parser.Size = USBH_HID_ITEM_SIZE(item);
parser.Type = USBH_HID_ITEM_TYPE(item);
parser.Tag = USBH_HID_ITEM_TAG(item);
USBH_HID_SetData(&parser, (void *)&p_report_desc[pos]);
pos += parser.Size;
if (item == USBH_HID_ITEM_LONG) { /* If item is a long item ... */
#if (USBH_CFG_PRINT_LOG == DEF_ENABLED)
USBH_PRINT_LOG("Long Item found\r\n");
#endif
err = USBH_ERR_HID_ITEM_LONG; /* ... rtn err. */
break;
}
switch (parser.Type) {
case USBH_HID_ITEM_TYPE_MAIN: /* Parse main item. */
err = USBH_HID_ParseMain(p_hid_dev, &parser);
break;
case USBH_HID_ITEM_TYPE_GLOBAL: /* Parse global item. */
err = USBH_HID_ParseGlobal(&parser);
break;
case USBH_HID_ITEM_TYPE_LOCAL: /* Parse local item. */
err = USBH_HID_ParseLocal(&parser);
if (pos <= 6u) { /* Store device usage. */
p_hid_dev->Usage = parser.Local.Usage[0u];
}
break;
default:
#if (USBH_CFG_PRINT_LOG == DEF_ENABLED)
USBH_PRINT_LOG("Unknown item type\r\n");
#endif
err = USBH_ERR_HID_ITEM_UNKNOWN;
break;
}
if (err != USBH_ERR_NONE) {
USBH_PRINT_ERR(err);
break;
}
}
/* --------------- HANDLE PARSER ERRORS --------------- */
if (err != USBH_ERR_NONE) { /* Parsing err. */
USBH_HID_FreeItemParser(&parser);
} else if (parser.CollStkPtr != (USBH_HID_COLL *)0) { /* Collection stack err. */
#if (USBH_CFG_PRINT_LOG == DEF_ENABLED)
USBH_PRINT_LOG("Missmatch in collections desc_len = %d\r\n",desc_len);
#endif
USBH_HID_FreeItemParser(&parser);
err = USBH_ERR_HID_MISMATCH_COLL;
} else if (parser.GlobalStkPtr != (USBH_HID_GLOBAL *)0) { /* Global stack err. */
#if (USBH_CFG_PRINT_LOG == DEF_ENABLED)
USBH_PRINT_LOG("Missmatch in push and pop items\r\n");
#endif
USBH_HID_FreeItemParser(&parser);
err = USBH_ERR_HID_MISMATCH_PUSH_POP;
}
return (err);
}
/*
*********************************************************************************************************
* USBH_HID_CreateReportID()
*
* Description : Creates report id list from pre-parsed data.
*
* Argument(s) : p_hid_dev Pointer to HID device.
*
* Return(s) : USBH_ERR_NONE, if report ID list successfully created.
* USBH_ERR_ALLOC, if report ID cannot be allocated.
*
* Note(s) : None.
*********************************************************************************************************
*/
USBH_ERR USBH_HID_CreateReportID (USBH_HID_DEV *p_hid_dev)
{
CPU_BOOLEAN found;
CPU_INT08U coll_ix;
CPU_INT08U report_fmt_ix;
CPU_INT08U report_id_ix;
USBH_HID_REPORT_FMT *p_report_fmt;
USBH_HID_REPORT_ID *p_report_id;
p_hid_dev->NbrReportID = 0u;
/* For each app collection. */
for (coll_ix = 0u; coll_ix < p_hid_dev->NbrAppColl; coll_ix++) {
for (report_fmt_ix = 0u; report_fmt_ix < p_hid_dev->AppColl[coll_ix].NbrReportFmt; report_fmt_ix++) {
p_report_fmt = &p_hid_dev->AppColl[coll_ix].ReportFmt[report_fmt_ix];
found = DEF_FALSE;
for (report_id_ix = 0u; report_id_ix < p_hid_dev->NbrReportID; report_id_ix++) {
p_report_id = &p_hid_dev->ReportID[report_id_ix];
/* If report ID/type match, increment size. */
if ((p_report_id->ReportID == p_report_fmt->ReportID ) &&
(p_report_id->Type == p_report_fmt->ReportType)) {
p_report_id->Size += (p_report_fmt->ReportCnt * p_report_fmt->ReportSize);
found = DEF_TRUE;
break;
}
}
if (found == DEF_FALSE) { /* No match found, create new report ID. */
if (p_hid_dev->NbrReportID >= USBH_HID_CFG_MAX_NBR_REPORT_ID) {
return (USBH_ERR_ALLOC);
}
p_report_id = &p_hid_dev->ReportID[p_hid_dev->NbrReportID];
p_report_id->ReportID = p_report_fmt->ReportID;
p_report_id->Type = p_report_fmt->ReportType;
p_report_id->Size = (p_report_fmt->ReportCnt * p_report_fmt->ReportSize);
p_hid_dev->NbrReportID++;
}
}
}
return (USBH_ERR_NONE);
}
/*
*********************************************************************************************************
* USBH_HID_MaxReport()
*
* Description : Find report of given type that has the greater size.
*
* Argument(s) : p_hid_dev Pointer to HID device.
*
* type Report Type.
*
* Return(s) : Max report id structure pointer.
*
* Note(s) : None.
*********************************************************************************************************
*/
USBH_HID_REPORT_ID *USBH_HID_MaxReport (USBH_HID_DEV *p_hid_dev,
CPU_INT08U type)
{
USBH_HID_REPORT_ID *p_report_id;
CPU_INT32U size;
CPU_INT08U report_id_ix;
size = 0u;
p_report_id = (USBH_HID_REPORT_ID *)0;
for (report_id_ix = 0u; report_id_ix < p_hid_dev->NbrReportID; report_id_ix++) {
if (p_hid_dev->ReportID[report_id_ix].Type == type) {
if (p_hid_dev->ReportID[report_id_ix].Size > size) {
size = p_hid_dev->ReportID[report_id_ix].Size;
p_report_id = &p_hid_dev->ReportID[report_id_ix];
}
}
}
return (p_report_id);
}
/*
*********************************************************************************************************
*********************************************************************************************************
* LOCAL FUNCTIONS
*********************************************************************************************************
*********************************************************************************************************
*/
/*
*********************************************************************************************************
* USBH_HID_InitItemParser()
*
* Description : Initialize HID parser.
*
* Argument(s) : p_parser Pointer to the parser.
*
* Return(s) : None.
*
* Note(s) : None.
*********************************************************************************************************
*/
static void USBH_HID_InitItemParser (USBH_HID_PARSER *p_parser)
{
Mem_Clr((void *)p_parser,
sizeof(USBH_HID_PARSER));
USBH_HID_InitGlobalItem(&p_parser->Global);
USBH_HID_InitLocalItem(&p_parser->Local);
}
/*
*********************************************************************************************************
* USBH_HID_FreeItemParser()
*
* Description : Free memory allocated for parser structure.
*
* Argument(s) : p_parser Pointer to parser.
*
* Return(s) : None.
*
* Note(s) : None.
*********************************************************************************************************
*/
static void USBH_HID_FreeItemParser (USBH_HID_PARSER *p_parser)
{
USBH_HID_GLOBAL *p_global;
USBH_HID_GLOBAL *p_global_free;
USBH_HID_COLL *p_coll;
USBH_HID_COLL *p_coll_free;
LIB_ERR err_lib;
/* --------------- FREE THE GLOBAL STACK -------------- */
p_global = p_parser->GlobalStkPtr;
while (p_global != (USBH_HID_GLOBAL *)0) {
p_global_free = p_global;
p_global = p_global->NextPtr;
Mem_PoolBlkFree( &USBH_HID_GlobalItemPool,
(void *)p_global_free,
&err_lib);
}
/* ------------- FREE THE COLLECTION STACK ------------ */
p_coll = p_parser->CollStkPtr;
while (p_coll != (USBH_HID_COLL *)0) {
p_coll_free = p_coll;
p_coll = p_coll->NextPtr;
Mem_PoolBlkFree( &USBH_HID_CollPool,
(void *)p_coll_free,
&err_lib);
}
}
/*
*********************************************************************************************************
* USBH_HID_InitGlobalItem()
*
* Description : Initialize global item.
*
* Argument(s) : p_global Pointer to global item.
*
* Return(s) : None.
*
* Note(s) : None.
*********************************************************************************************************
*/
static void USBH_HID_InitGlobalItem (USBH_HID_GLOBAL *p_global)
{
Mem_Clr((void *)p_global,
sizeof(USBH_HID_GLOBAL));
p_global->LogMin = (CPU_INT32S)USBH_HID_LOG_MIN_UNDEFINED;
p_global->LogMax = (CPU_INT32S)USBH_HID_LOG_MAX_UNDEFINED;
p_global->PhyMin = (CPU_INT32S)USBH_HID_PHY_MIN_UNDEFINED;
p_global->PhyMax = (CPU_INT32S)USBH_HID_PHY_MAX_UNDEFINED;
p_global->UnitExp = (CPU_INT32S)USBH_HID_UNIT_EXP_UNDEFINED;
p_global->Unit = (CPU_INT32S)USBH_HID_UNIT_UNDEFINED;
}
/*
*********************************************************************************************************
* USBH_HID_InitLocalItem()
*
* Description : Initialize the local item.
*
* Argument(s) : p_local Pointer to the local item.
*
* Return(s) : None.
*
* Note(s) : None.
*********************************************************************************************************
*/
static void USBH_HID_InitLocalItem (USBH_HID_LOCAL *p_local)
{
Mem_Clr((void *)p_local,
sizeof(USBH_HID_LOCAL));
p_local->UsageMin = USBH_HID_USAGE_MIN_UNDEFINED;
p_local->UsageMax = USBH_HID_USAGE_MAX_UNDEFINED;
}
/*
*********************************************************************************************************
* USBH_HID_ParseMain()
*
* Description : Parse a main item.
*
* Argument(s) : p_hid_dev Pointer to the HID device.
*
* p_parser Pointer to the parser.
*
* Return(s) : USBH_ERR_NONE, if item is successfully parsed.
* USBH_ERR_HID_ITEM_UNKNOWN, if unknown item.
*
* Note(s) : None.
*********************************************************************************************************
*/
static USBH_ERR USBH_HID_ParseMain (USBH_HID_DEV *p_hid_dev,
USBH_HID_PARSER *p_parser)
{
USBH_ERR err;
/* -------------------- PARSE ITEM -------------------- */
switch (p_parser->Tag) {
case USBH_HID_MAIN_ITEM_TAG_FEATURE:
case USBH_HID_MAIN_ITEM_TAG_IN:
case USBH_HID_MAIN_ITEM_TAG_OUT:
err = USBH_HID_AddReport(p_hid_dev, p_parser); /* Add report to report list. */
break;
case USBH_HID_MAIN_ITEM_TAG_COLL:
err = USBH_HID_OpenColl(p_hid_dev, p_parser); /* Open new collection. */
break;
case USBH_HID_MAIN_ITEM_TAG_ENDCOLL:
err = USBH_HID_CloseColl(p_parser); /* Close collection. */
break;
default:
#if (USBH_CFG_PRINT_LOG == DEF_ENABLED)
USBH_PRINT_LOG("Unknown main tag\r\n");
#endif
err = USBH_ERR_HID_ITEM_UNKNOWN;
}
/* ---------------- RE-INIT LOCAL ITEM ---------------- */
USBH_HID_InitLocalItem(&p_parser->Local);
return (err);
}
/*
*********************************************************************************************************
* USBH_HID_ParseGlobal()
*
* Description : Parse a global item.
*
* Argument(s) : p_parser Pointer to parser.
*
* Return(s) : USBH_ERR_NONE, if global item successfully parsed.
* USBH_ERR_HID_USAGE_PAGE_INVALID, if usage page is out of range.
* USBH_ERR_HID_REPORT_ID, if report ID is invalid.
* USBH_ERR_HID_REPORTID_OUTRANGE, if report ID is out of range.
* USBH_ERR_HID_REPORT_CNT, if report count is zero.
* USBH_ERR_HID_PUSH_SIZE, if push item with zero size.
* USBH_ERR_HID_POP_SIZE, if pop item with zero size.
* USBH_ERR_HID_MISMATCH_PUSH_POP, if mismatch in push and pop items.
* USBH_ERR_HID_ITEM_UNKNOWN, if unknown global item.
* USBH_ERR_ALLOC, if global item cannot be allocated.
*
* Note(s) : None.
*********************************************************************************************************
*/
static USBH_ERR USBH_HID_ParseGlobal (USBH_HID_PARSER *p_parser)
{
USBH_HID_GLOBAL *p_global_new;
USBH_HID_GLOBAL *p_global_free;
LIB_ERR err_lib;
switch (p_parser->Tag) {
case USBH_HID_GLOBAL_ITEM_TAG_USAGE_PAGE:
p_parser->Global.UsagePage = USBH_HID_UNSIGNED_DATA(p_parser);
if (p_parser->Size > 2u) { /* Rtn err if parser size is too large. */
#if (USBH_CFG_PRINT_LOG == DEF_ENABLED)
USBH_PRINT_LOG("GLOBAL ITEM USAGE PAGE: OUT OF RANGE\r\n");
#endif
return (USBH_ERR_HID_USAGE_PAGE_INVALID);
}
if ((p_parser->Global.UsagePage >= 0x0092u) && /* Warn if usage page is a reserved value. */
(p_parser->Global.UsagePage < 0xFEFFu)) {
#if (USBH_CFG_PRINT_LOG == DEF_ENABLED)
USBH_PRINT_LOG("GLOBAL ITEM USAGE PAGE: RESERVED VALUE\r\n");
#endif
}
break;
case USBH_HID_GLOBAL_ITEM_TAG_LOG_MIN:
p_parser->Global.LogMin = USBH_HID_SIGNED_DATA(p_parser);
break;
case USBH_HID_GLOBAL_ITEM_TAG_LOG_MAX:
p_parser->Global.LogMax = USBH_HID_SIGNED_DATA(p_parser);
break;
case USBH_HID_GLOBAL_ITEM_TAG_PHY_MIN:
p_parser->Global.PhyMin = USBH_HID_SIGNED_DATA(p_parser);
break;
case USBH_HID_GLOBAL_ITEM_TAG_PHY_MAX:
p_parser->Global.PhyMax = USBH_HID_SIGNED_DATA(p_parser);
break;
case USBH_HID_GLOBAL_ITEM_TAG_UNIT_EXPONENT:
p_parser->Global.UnitExp = USBH_HID_SIGNED_DATA(p_parser);
break;
case USBH_HID_GLOBAL_ITEM_TAG_UNIT:
p_parser->Global.Unit = USBH_HID_SIGNED_DATA(p_parser);
break;
case USBH_HID_GLOBAL_ITEM_TAG_REPORT_SIZE:
p_parser->Global.ReportSize = USBH_HID_UNSIGNED_DATA(p_parser);
break;
case USBH_HID_GLOBAL_ITEM_TAG_REPORT_ID:
p_parser->Global.ReportID = USBH_HID_UNSIGNED_DATA(p_parser);
if (p_parser->Global.ReportID == 0u) { /* Report ID should not be zero. */
#if (USBH_CFG_PRINT_LOG == DEF_ENABLED)
USBH_PRINT_LOG("GLOBAL ITEM REPORT ID: REPORT ID == 0\r\n");
#endif
return (USBH_ERR_HID_REPORT_ID);
}
if (p_parser->Size > 1u) { /* Report ID should be 1-byte value. */
#if (USBH_CFG_PRINT_LOG == DEF_ENABLED)
USBH_PRINT_LOG("GLOBAL ITEM REPORT ID: REPORT ID > 255\r\n");
#endif
return (USBH_ERR_HID_REPORT_ID);
}
break;
case USBH_HID_GLOBAL_ITEM_TAG_REPORT_COUNT:
p_parser->Global.ReportCnt = USBH_HID_UNSIGNED_DATA(p_parser);
if (p_parser->Global.ReportCnt == 0u) { /* Report cnt should not be zero. */
#if (USBH_CFG_PRINT_LOG == DEF_ENABLED)
USBH_PRINT_LOG("GLOBAL ITEM REPORT COUNT: REPORT COUNT ZERO\r\n");
#endif
return (USBH_ERR_HID_REPORT_CNT);
}
break;
case USBH_HID_GLOBAL_ITEM_TAG_PUSH: /* Push item to stack. */
if (p_parser->Size != 0u) {
#if (USBH_CFG_PRINT_LOG == DEF_ENABLED)
USBH_PRINT_LOG("GLOBAL ITEM PUSH: SIZE ZERO\r\n");
#endif
return (USBH_ERR_HID_PUSH_SIZE);
}
/* Allocate memory for new entry. */
p_global_new = (USBH_HID_GLOBAL *)Mem_PoolBlkGet ((MEM_POOL *)&USBH_HID_GlobalItemPool,
sizeof(USBH_HID_GLOBAL),
&err_lib);
if (err_lib != LIB_MEM_ERR_NONE) {
#if (USBH_CFG_PRINT_LOG == DEF_ENABLED)
USBH_PRINT_LOG("GLOBAL ITEM PUSH: OUT OF MEMORY\r\n");
#endif
return (USBH_ERR_ALLOC);
}
*p_global_new = p_parser->Global; /* Copy global to new entry. */
p_global_new->NextPtr = p_parser->GlobalStkPtr;
p_parser->GlobalStkPtr = p_global_new;
break;
case USBH_HID_GLOBAL_ITEM_TAG_POP: /* Pop item from stack. */
if (p_parser->Size != 0u) {
#if (USBH_CFG_PRINT_LOG == DEF_ENABLED)
USBH_PRINT_LOG("GLOBAL ITEM POP: SIZE ZERO\r\n");
#endif
return (USBH_ERR_HID_POP_SIZE);
}
/* Global stack should be not empty. */
if (p_parser->GlobalStkPtr == (USBH_HID_GLOBAL *)0) {
#if (USBH_CFG_PRINT_LOG == DEF_ENABLED)
USBH_PRINT_LOG("GLOBAL ITEM POP: MISMATCHED PUSH/POP\r\n");
#endif
return (USBH_ERR_HID_MISMATCH_PUSH_POP);
}
p_parser->Global = *(p_parser->GlobalStkPtr);/* Copy top element to global. */
p_global_free = p_parser->GlobalStkPtr;
p_parser->GlobalStkPtr = p_global_free->NextPtr;
Mem_PoolBlkFree( &USBH_HID_GlobalItemPool, /* Free top item. */
(void *)p_global_free,
&err_lib);
break;
default:
#if (USBH_CFG_PRINT_LOG == DEF_ENABLED)
USBH_PRINT_LOG("GLOBAL ITEM: UNKNOWN\r\n");
#endif
return (USBH_ERR_HID_ITEM_UNKNOWN);
}
return (USBH_ERR_NONE);
}
/*
*********************************************************************************************************
* USBH_HID_ParseLocal()
*
* Description : Parse a local item.
*
* Argument(s) : p_parser Pointer to the parser.
*
* Return(s) : USBH_ERR_NONE, if local item is successfully parsed.
* USBH_ERR_ALLOC, if usage array would have overflowed.
*
* Note(s) : None.
*********************************************************************************************************
*/
static USBH_ERR USBH_HID_ParseLocal (USBH_HID_PARSER *p_parser)
{
switch (p_parser->Tag) {
case USBH_HID_LOCAL_ITEM_TAG_USAGE:
p_parser->Local.NbrUsage++;
if (p_parser->Local.NbrUsage > USBH_HID_CFG_MAX_NBR_USAGE) {
#if (USBH_CFG_PRINT_LOG == DEF_ENABLED)
USBH_PRINT_LOG("LOCAL ITEM USAGE: ARRAY OVERFLOW\r\n");
#endif
return (USBH_ERR_ALLOC);
}
p_parser->Local.Usage[p_parser->Local.NbrUsage - 1u] = USBH_HID_UNSIGNED_DATA(p_parser);
break;
case USBH_HID_LOCAL_ITEM_TAG_USAGE_MIN:
p_parser->Local.UsageMin = USBH_HID_UNSIGNED_DATA(p_parser);
break;
case USBH_HID_LOCAL_ITEM_TAG_USAGE_MAX:
p_parser->Local.UsageMax = USBH_HID_UNSIGNED_DATA(p_parser);
break;
default:
break;
}
return (USBH_ERR_NONE);
}
/*
*********************************************************************************************************
* USBH_HID_OpenColl()
*
* Description : Add new collection item to collection stack.
*
* Argument(s) : p_hid_dev Pointer to HID device.
*
* p_parser Pointer to parser.
*
* Return(s) : USBH_ERR_NONE, if collection opened successfully.
* USBH_ERR_HID_NOT_APP_COLL, if top level collection not an application collection.
* USBH_ERR_ALLOC, if collection cannot be freed/allocated.
*
* Note(s) : None.
*********************************************************************************************************
*/
static USBH_ERR USBH_HID_OpenColl (USBH_HID_DEV *p_hid_dev,
USBH_HID_PARSER *p_parser)
{
USBH_HID_COLL *p_coll_new;
LIB_ERR err_lib;
/* --------------- INIT NEW COLLECTION ---------------- */
p_coll_new = (USBH_HID_COLL *)Mem_PoolBlkGet(&USBH_HID_CollPool,
sizeof(USBH_HID_COLL),
&err_lib);
if (err_lib != LIB_MEM_ERR_NONE) {
return (USBH_ERR_ALLOC);
}
/* Initialize collection parameters. */
p_coll_new->Usage = (((CPU_INT32U)p_parser->Global.UsagePage << 16u) & 0xFFFF0000u) | (CPU_INT32U)p_parser->Local.Usage[0];
p_coll_new->Type = USBH_HID_UNSIGNED_DATA(p_parser);
if ((p_parser->CollStkPtr == (USBH_HID_COLL *)0) && /* Check if first collection is app. */
(p_coll_new->Type != USBH_HID_COLL_APP)) {
#if (USBH_CFG_PRINT_LOG == DEF_ENABLED)
USBH_PRINT_LOG("OPEN COLLECTION: FIRST COLLECTION NOT APP COLLECTION\r\n");
#endif
Mem_PoolBlkFree( &USBH_HID_CollPool,
(void *)p_coll_new,
&err_lib);
return (USBH_ERR_HID_NOT_APP_COLL);
}
/* --------- PUT COLLECTION IN APP USAGE ARAY --------- */
if (p_coll_new->Type == USBH_HID_COLL_APP) {
if (p_parser->CollStkPtr != (USBH_HID_COLL *)0) {
#if (USBH_CFG_PRINT_LOG == DEF_ENABLED)
USBH_PRINT_LOG("OPEN COLLECTION: NESTED\r\n");
#endif
Mem_PoolBlkFree( &USBH_HID_CollPool,
(void *)p_coll_new,
&err_lib);
return (USBH_ERR_HID_NOT_APP_COLL);
}
/* Max app collections exceeded. */
if (p_hid_dev->NbrAppColl == USBH_HID_CFG_MAX_NBR_APP_COLL) {
#if (USBH_CFG_PRINT_LOG == DEF_ENABLED)
USBH_PRINT_LOG("OPEN COLLECTION: MAX APP COLLECTION EXCEEDED\r\n");
#endif
Mem_PoolBlkFree( &USBH_HID_CollPool,
(void *)p_coll_new,
&err_lib);
return (USBH_ERR_ALLOC);
}
p_hid_dev->AppColl[p_hid_dev->NbrAppColl].Usage = p_coll_new->Usage;
p_hid_dev->AppColl[p_hid_dev->NbrAppColl].Type = p_coll_new->Type;
p_hid_dev->NbrAppColl++;
}
/* ------------- PUT COLLECTION IN STACK -------------- */
p_coll_new->NextPtr = p_parser->CollStkPtr;
p_parser->CollStkPtr = p_coll_new;
return (USBH_ERR_NONE);
}
/*
*********************************************************************************************************
* USBH_HID_CloseColl()
*
* Description : Remove top collection from collection stack.
*
* Argument(s) : p_parser Pointer to the parser.
*
* Return(s) : USBH_ERR_NONE, if collection is successfully closed.
* USBH_ERR_HID_MISMATCH_COLL, if collection stack is empty.
*
* Note(s) : None.
*********************************************************************************************************
*/
static USBH_ERR USBH_HID_CloseColl (USBH_HID_PARSER *p_parser)
{
USBH_HID_COLL *p_coll_free;
LIB_ERR err_lib;
if (p_parser->CollStkPtr == (USBH_HID_COLL *)0) { /* Collection stack should not be empty. */
#if (USBH_CFG_PRINT_LOG == DEF_ENABLED)
USBH_PRINT_LOG("CLOSE COLLECTION: MISMATCH\r\n");
#endif
return (USBH_ERR_HID_MISMATCH_COLL);
}
p_coll_free = p_parser->CollStkPtr; /* Remove top element from collection stack. */
p_parser->CollStkPtr = p_coll_free->NextPtr;
Mem_PoolBlkFree( &USBH_HID_CollPool,
(void *)p_coll_free,
&err_lib);
return (USBH_ERR_NONE);
}
/*
*********************************************************************************************************
* USBH_HID_AddReport()
*
* Description : Add new report to report list in application collection.
*
* Argument(s) : p_hid_dev Pointer to HID device.
*
* p_parser Pointer to parser.
*
* Return(s) : USBH_ERR_NONE, if report is successfully added.
* USBH_ERR_ALLOC, if memory could not be allocated for report format.
* USBH_ERR_HID_REPORT_OUTSIDE_COLL, if no application collection.
*
* ----- RETURNED BY USBH_HID_ValidateReport -----
* USBH_ERR_HID_REPORT_INVALID_VAL, if any of report's value is invalid.
*
* Note(s) : None.
*********************************************************************************************************
*/
static USBH_ERR USBH_HID_AddReport (USBH_HID_DEV *p_hid_dev,
USBH_HID_PARSER *p_parser)
{
USBH_HID_REPORT_FMT *p_report_new;
USBH_HID_APP_COLL *p_app_coll;
USBH_ERR err;
if (p_hid_dev->NbrAppColl == 0u) { /* Rtn error if no app collections exist. */
#if (USBH_CFG_PRINT_LOG == DEF_ENABLED)
USBH_PRINT_LOG("ADD REPORT: NO APP COLLECTION's\r\n");
#endif
return (USBH_ERR_HID_REPORT_OUTSIDE_COLL);
}
/* Current Application Collection */
p_app_coll = &p_hid_dev->AppColl[p_hid_dev->NbrAppColl - 1u];
if (p_app_coll->NbrReportFmt == USBH_HID_CFG_MAX_NBR_REPORT_FMT) {
return (USBH_ERR_ALLOC);
}
/* Get new Report Format */
p_report_new = &p_app_coll->ReportFmt[p_app_coll->NbrReportFmt];
p_app_coll->NbrReportFmt++;
/* ----------------- INITIALIZE REPORT ---------------- */
USBH_HID_InitReport(p_parser, p_report_new);
if (p_report_new->ReportID != 0u) {
p_hid_dev->IsReportID_Present = DEF_TRUE;
}
/* ------------------ VALIDATE REPORT ----------------- */
err = USBH_HID_ValidateReport(p_report_new);
if (err != USBH_ERR_NONE) {
#if (USBH_CFG_PRINT_LOG == DEF_ENABLED)
USBH_PRINT_LOG("HID DEVICE REPORT VALIDATION FAILED, ERR = %d\r\n", err);
#endif
}
return (USBH_ERR_NONE);
}
/*
*********************************************************************************************************
* USBH_HID_ValidateReport()
*
* Description : Validate report by checking report values.
*
* Argument(s) : p_report_fmt Pointer to report.
*
* Return(s) : USBH_ERR_NONE, if report is valid.
* USBH_ERR_HID_REPORT_INVALID_VAL, if any of report's value is invalid.
*
* Note(s) : None.
*********************************************************************************************************
*/
static USBH_ERR USBH_HID_ValidateReport (USBH_HID_REPORT_FMT *p_report_fmt)
{
CPU_BOOLEAN x_def;
CPU_BOOLEAN y_def;
/* --------------- CHK MANDATORY FIELDS --------------- */
if ((p_report_fmt->UsagePage == USBH_HID_USAGE_PAGE_UNDEFINED ) ||
(p_report_fmt->LogMax == USBH_HID_LOG_MIN_UNDEFINED ) ||
(p_report_fmt->LogMin == USBH_HID_LOG_MAX_UNDEFINED ) ||
(p_report_fmt->ReportCnt == USBH_HID_REPORT_CNT_UNDEFINED ) ||
(p_report_fmt->ReportSize == USBH_HID_REPORT_SIZE_UNDEFINED)) {
#if (USBH_CFG_PRINT_LOG == DEF_ENABLED)
USBH_PRINT_LOG("VALIDATE REPORT: MANDATORY FIELD NOT DEFINED\r\n");
#endif
return (USBH_ERR_HID_REPORT_INVALID_VAL);
}
/* -------------- CHK LOGICAL MIN & MAX --------------- */
if (p_report_fmt->LogMin >= p_report_fmt->LogMax) {
#if (USBH_CFG_PRINT_LOG == DEF_ENABLED)
USBH_PRINT_LOG("VALIDATE REPORT: LOG MIN > LOG MAX\r\n");
#endif
return (USBH_ERR_HID_REPORT_INVALID_VAL);
}
/* Chk presence/value of physical min & max. */
x_def = p_report_fmt->PhyMax == USBH_HID_PHY_MAX_UNDEFINED ? DEF_FALSE : DEF_TRUE;
y_def = p_report_fmt->PhyMin == USBH_HID_PHY_MIN_UNDEFINED ? DEF_FALSE : DEF_TRUE;
if (((x_def == DEF_TRUE) && (y_def == DEF_FALSE)) ||
((y_def == DEF_TRUE) && (x_def == DEF_FALSE))) {
#if (USBH_CFG_PRINT_LOG == DEF_ENABLED)
USBH_PRINT_LOG("VALIDATE REPORT: ONLY ONE OF PHY MIN & MAX DEF'd\r\n");
#endif
return (USBH_ERR_HID_REPORT_INVALID_VAL);
} else if ((x_def == DEF_FALSE) && (y_def == DEF_FALSE)) {
p_report_fmt->PhyMin = p_report_fmt->LogMin;
p_report_fmt->PhyMax = p_report_fmt->LogMax;
} else if (p_report_fmt->PhyMax < p_report_fmt->PhyMin) {
#if (USBH_CFG_PRINT_LOG == DEF_ENABLED)
USBH_PRINT_LOG("VALIDATE REPORT: PHY MIN > PHY MAX\r\n");
#endif
return (USBH_ERR_HID_REPORT_INVALID_VAL);
}
return (USBH_ERR_NONE);
}
/*
*********************************************************************************************************
* USBH_HID_InitReport()
*
* Description : Initialize report.
*
* Argument(s) : p_parser Pointer to parser.
*
* p_report_fmt Pointer to report.
*
* Return(s) : None.
*
* Note(s) : None.
*********************************************************************************************************
*/
static void USBH_HID_InitReport (USBH_HID_PARSER *p_parser,
USBH_HID_REPORT_FMT *p_report_fmt)
{
USBH_HID_COLL *p_coll_tmp;
CPU_INT08U usage_ix;
/* Copy usages. */
for (usage_ix = 0u; usage_ix < p_parser->Local.NbrUsage; usage_ix++) {
p_report_fmt->Usage[usage_ix] = ((CPU_INT32U)p_parser->Global.UsagePage << 16u) |
(CPU_INT32U)p_parser->Local.Usage[usage_ix];
}
p_report_fmt->UsagePage = p_parser->Global.UsagePage;
p_report_fmt->NbrUsage = p_parser->Local.NbrUsage;
p_report_fmt->ReportType = p_parser->Tag;
p_report_fmt->Flag = USBH_HID_UNSIGNED_DATA(p_parser);
p_report_fmt->LogMin = p_parser->Global.LogMin;
p_report_fmt->LogMax = p_parser->Global.LogMax;
p_report_fmt->PhyMin = p_parser->Global.PhyMin;
p_report_fmt->PhyMax = p_parser->Global.PhyMax;
p_report_fmt->ReportSize = p_parser->Global.ReportSize;
p_report_fmt->ReportCnt = p_parser->Global.ReportCnt;
p_report_fmt->UnitExp = p_parser->Global.UnitExp;
p_report_fmt->Unit = p_parser->Global.Unit;
p_report_fmt->ReportID = p_parser->Global.ReportID;
p_report_fmt->UsageMin = p_parser->Local.UsageMin;
p_report_fmt->UsageMax = p_parser->Local.UsageMax;
p_report_fmt->PhyUsage = USBH_HID_USAGE_PAGE_UNDEFINED; /* Init collection usage to undefined values. */
p_report_fmt->AppUsage = USBH_HID_USAGE_PAGE_UNDEFINED;
p_report_fmt->LogUsage = USBH_HID_USAGE_PAGE_UNDEFINED;
p_coll_tmp = p_parser->CollStkPtr; /* Find values for collection usage. */
while (p_coll_tmp != (USBH_HID_COLL *)0) {
switch (p_coll_tmp->Type) {
case USBH_HID_COLL_PHYSICAL:
p_report_fmt->PhyUsage = p_coll_tmp->Usage;
break;
case USBH_HID_COLL_APP:
p_report_fmt->AppUsage = p_coll_tmp->Usage;
break;
case USBH_HID_COLL_LOGICAL:
p_report_fmt->LogUsage = p_coll_tmp->Usage;
break;
default:
break;
}
p_coll_tmp = p_coll_tmp->NextPtr;
}
}
/*
*********************************************************************************************************
* USBH_HID_SetData()
*
* Description : Set data in parser.
*
* Argument(s) : p_parser Pointer to parser.
*
* p_buf Pointer to data buffer.
*
* Return(s) : None.
*
* Note(s) : None.
*********************************************************************************************************
*/
static void USBH_HID_SetData (USBH_HID_PARSER *p_parser,
void *p_buf)
{
switch (p_parser->Size) {
case 1:
p_parser->Data.U08 = MEM_VAL_GET_INT08U_LITTLE(p_buf);
p_parser->Data.S08 = (CPU_INT08S)MEM_VAL_GET_INT08U_LITTLE(p_buf);
break;
case 2:
p_parser->Data.U16 = MEM_VAL_GET_INT16U_LITTLE(p_buf);
p_parser->Data.S16 = (CPU_INT16S)MEM_VAL_GET_INT16U_LITTLE(p_buf);
break;
case 4:
p_parser->Data.U32 = MEM_VAL_GET_INT32U_LITTLE(p_buf);
p_parser->Data.S32 = (CPU_INT32S)MEM_VAL_GET_INT32U_LITTLE(p_buf);
break;
default:
break;
}
}