Implemented HID report parser. Untested!

pull/7/head
Robert Fisk 8 years ago
parent 7fb0a7e7ad
commit 35d54056c4

@ -18,10 +18,30 @@
#define HID_ITEM_LONG 0xFE
#define HID_ITEM_LENGTH_MASK 0x03
#define HID_ITEM_USAGE_PAGE 0x05 //'global' usage page
#define HID_ITEM_USAGE_PAGE_BUTTON 0x09
#define HID_ITEM_USAGE_PAGE_DESKTOP 0x01
#define HID_ITEM_USAGE 0x09 //'local' usage
#define HID_ITEM_USAGE_X 0x30
#define HID_ITEM_USAGE_Y 0x31
#define HID_ITEM_USAGE_WHEEL 0x38
#define HID_ITEM_REPORT_SIZE 0x75 //'global' report size
#define HID_ITEM_REPORT_COUNT 0x95 //'global' report count
#define HID_ITEM_INPUT 0x81 //'main' input
#define HID_ITEM_INPUT_ABS 0x02
#define HID_ITEM_INPUT_REL 0x06
InterfaceCommandClassTypeDef Downstream_HID_ApproveConnectedDevice(void); InterfaceCommandClassTypeDef Downstream_HID_ApproveConnectedDevice(void);
void Downstream_HID_PacketProcessor(DownstreamPacketTypeDef* receivedPacket); void Downstream_HID_PacketProcessor(DownstreamPacketTypeDef* receivedPacket);
void Downstream_HID_InterruptReportCallback(DownstreamPacketTypeDef* packetToSend); void Downstream_HID_InterruptReportCallback(uint8_t* reportBuffer);

@ -71,7 +71,6 @@ typedef void (*SpiPacketReceivedCallbackTypeDef)(DownstreamPacketTypeDef* receiv
void Downstream_InitSPI(void); void Downstream_InitSPI(void);
HAL_StatusTypeDef Downstream_GetFreePacket(FreePacketCallbackTypeDef callback); HAL_StatusTypeDef Downstream_GetFreePacket(FreePacketCallbackTypeDef callback);
DownstreamPacketTypeDef* Downstream_GetFreePacketImmediately(void);
void Downstream_ReleasePacket(DownstreamPacketTypeDef* packetToRelease); void Downstream_ReleasePacket(DownstreamPacketTypeDef* packetToRelease);
HAL_StatusTypeDef Downstream_ReceivePacket(SpiPacketReceivedCallbackTypeDef callback); HAL_StatusTypeDef Downstream_ReceivePacket(SpiPacketReceivedCallbackTypeDef callback);
HAL_StatusTypeDef Downstream_TransmitPacket(DownstreamPacketTypeDef* packetToWrite); HAL_StatusTypeDef Downstream_TransmitPacket(DownstreamPacketTypeDef* packetToWrite);

@ -59,7 +59,7 @@
#define USBH_MAX_NUM_CONFIGURATION 1 #define USBH_MAX_NUM_CONFIGURATION 1
/*---------- -----------*/ /*---------- -----------*/
#define USBH_KEEP_CFG_DESCRIPTOR 1 #define USBH_KEEP_CFG_DESCRIPTOR 0
/*---------- -----------*/ /*---------- -----------*/
#define USBH_MAX_NUM_SUPPORTED_CLASS 2 #define USBH_MAX_NUM_SUPPORTED_CLASS 2

@ -61,7 +61,7 @@
*/ */
#define HID_MIN_POLL 10 #define HID_MIN_POLL 10
#define HID_REPORT_SIZE 16 #define HID_MAX_REPORT_SIZE 8
#define HID_MAX_USAGE 10 #define HID_MAX_USAGE 10
#define HID_MAX_NBR_REPORT_FMT 10 #define HID_MAX_NBR_REPORT_FMT 10
#define HID_QUEUE_SIZE 10 #define HID_QUEUE_SIZE 10
@ -211,7 +211,7 @@ typedef struct
typedef void (*HID_InterruptReportCallback)(DownstreamPacketTypeDef* packetToSend); typedef void (*HID_InterruptReportCallback)(uint8_t* reportBuffer);
/* Structure for HID process */ /* Structure for HID process */
@ -230,8 +230,7 @@ typedef struct _HID_Process
uint8_t Protocol; uint8_t Protocol;
HID_DescTypeDef HID_Desc; HID_DescTypeDef HID_Desc;
HID_InterruptReportCallback ReportCallback; HID_InterruptReportCallback ReportCallback;
DownstreamPacketTypeDef* hid_packet; uint8_t Data[HID_MAX_REPORT_SIZE];
uint8_t* hid_packet_pbuf;
} }
HID_HandleTypeDef; HID_HandleTypeDef;
@ -325,8 +324,7 @@ uint16_t fifo_read(FIFO_TypeDef * f, void * buf, uint16_t nbytes);
uint16_t fifo_write(FIFO_TypeDef * f, const void * buf, uint16_t nbytes); uint16_t fifo_write(FIFO_TypeDef * f, const void * buf, uint16_t nbytes);
HAL_StatusTypeDef USBH_HID_GetInterruptReport(USBH_HandleTypeDef *phost, HAL_StatusTypeDef USBH_HID_GetInterruptReport(USBH_HandleTypeDef *phost,
HID_InterruptReportCallback callback, HID_InterruptReportCallback callback);
DownstreamPacketTypeDef* packetToUse);
/** /**

@ -184,6 +184,11 @@ static USBH_StatusTypeDef USBH_HID_InterfaceInit (USBH_HandleTypeDef *phost)
HID_Handle->poll = HID_MIN_POLL; HID_Handle->poll = HID_MIN_POLL;
} }
if (HID_Handle->length > HID_MAX_REPORT_SIZE)
{
return USBH_FAIL;
}
/* Check fo available number of endpoints */ /* Check fo available number of endpoints */
/* Find the number of EPs in the Interface Descriptor */ /* Find the number of EPs in the Interface Descriptor */
/* Choose the lower number in order not to overrun the buffer allocated */ /* Choose the lower number in order not to overrun the buffer allocated */
@ -294,25 +299,20 @@ static USBH_StatusTypeDef USBH_HID_ClassRequest(USBH_HandleTypeDef *phost)
{ {
USBH_HID_ParseHIDDesc(&HID_Handle->HID_Desc, phost->device.Data); USBH_HID_ParseHIDDesc(&HID_Handle->HID_Desc, phost->device.Data);
HID_Handle->ctl_state = HID_REQ_SET_IDLE; HID_Handle->ctl_state = HID_REQ_GET_REPORT_DESC;
} }
break; break;
// case HID_REQ_GET_REPORT_DESC: case HID_REQ_GET_REPORT_DESC:
// /* Get Report Desc */
// if (USBH_HID_GetHIDReportDescriptor(phost, HID_Handle->HID_Desc.wItemLength) == USBH_OK)
// /* Get Report Desc */ {
// if (USBH_HID_GetHIDReportDescriptor(phost, HID_Handle->HID_Desc.wItemLength) == USBH_OK) /* The descriptor is available in phost->device.Data */
// { HID_Handle->ctl_state = HID_REQ_SET_IDLE;
// /* The descriptor is available in phost->device.Data */ }
// break;
// HID_Handle->ctl_state = HID_REQ_SET_IDLE;
// }
//
// break;
case HID_REQ_SET_IDLE: case HID_REQ_SET_IDLE:
classReqStatus = USBH_HID_SetIdle (phost, 0, 0); classReqStatus = USBH_HID_SetIdle (phost, 0, 0);
/* set Idle */ /* set Idle */
@ -328,7 +328,7 @@ static USBH_StatusTypeDef USBH_HID_ClassRequest(USBH_HandleTypeDef *phost)
case HID_REQ_SET_PROTOCOL: case HID_REQ_SET_PROTOCOL:
/* set protocol */ /* set protocol */
if (USBH_HID_SetProtocol (phost, 0) == USBH_OK) if (USBH_HID_SetProtocol (phost, 1) == USBH_OK)
{ {
HID_Handle->ctl_state = HID_REQ_IDLE; HID_Handle->ctl_state = HID_REQ_IDLE;
@ -368,7 +368,7 @@ static USBH_StatusTypeDef USBH_HID_Process(USBH_HandleTypeDef *phost)
if ((int32_t)(phost->Timer - HID_Handle->timer) >= HID_Handle->poll) if ((int32_t)(phost->Timer - HID_Handle->timer) >= HID_Handle->poll)
{ {
USBH_InterruptReceiveData(phost, USBH_InterruptReceiveData(phost,
HID_Handle->hid_packet_pbuf, HID_Handle->Data,
HID_Handle->length, HID_Handle->length,
HID_Handle->InPipe); HID_Handle->InPipe);
@ -382,7 +382,7 @@ static USBH_StatusTypeDef USBH_HID_Process(USBH_HandleTypeDef *phost)
if (urbStatus == USBH_URB_DONE) if (urbStatus == USBH_URB_DONE)
{ {
HID_Handle->ReportCallback(HID_Handle->hid_packet); HID_Handle->ReportCallback(HID_Handle->Data);
HID_Handle->state = HID_IDLE; HID_Handle->state = HID_IDLE;
break; break;
} }
@ -431,16 +431,13 @@ static USBH_StatusTypeDef USBH_HID_SOFProcess(USBH_HandleTypeDef *phost)
//Downstream_HID calls into here at main() priority, //Downstream_HID calls into here at main() priority,
//to request a new report for Upstream. //to request a new report for Upstream.
HAL_StatusTypeDef USBH_HID_GetInterruptReport(USBH_HandleTypeDef *phost, HAL_StatusTypeDef USBH_HID_GetInterruptReport(USBH_HandleTypeDef *phost,
HID_InterruptReportCallback callback, HID_InterruptReportCallback callback)
DownstreamPacketTypeDef* packetToUse)
{ {
HID_HandleTypeDef *HID_Handle = (HID_HandleTypeDef *) phost->pActiveClass->pData; HID_HandleTypeDef *HID_Handle = (HID_HandleTypeDef *) phost->pActiveClass->pData;
if (HID_Handle->state == HID_IDLE) if (HID_Handle->state == HID_IDLE)
{ {
HID_Handle->ReportCallback = callback; HID_Handle->ReportCallback = callback;
HID_Handle->hid_packet = packetToUse;
HID_Handle->hid_packet_pbuf = packetToUse->Data;
HID_Handle->state = HID_GET_DATA; HID_Handle->state = HID_GET_DATA;
return HAL_OK; return HAL_OK;
} }
@ -465,6 +462,11 @@ USBH_StatusTypeDef USBH_HID_GetHIDReportDescriptor (USBH_HandleTypeDef *phost,
USBH_StatusTypeDef status; USBH_StatusTypeDef status;
if (length > USBH_MAX_DATA_BUFFER)
{
length = USBH_MAX_DATA_BUFFER;
}
status = USBH_GetDescriptor(phost, status = USBH_GetDescriptor(phost,
USB_REQ_RECIPIENT_INTERFACE | USB_REQ_TYPE_STANDARD, USB_REQ_RECIPIENT_INTERFACE | USB_REQ_TYPE_STANDARD,
USB_DESC_HID_REPORT, USB_DESC_HID_REPORT,
@ -495,6 +497,11 @@ USBH_StatusTypeDef USBH_HID_GetHIDDescriptor (USBH_HandleTypeDef *phost,
USBH_StatusTypeDef status; USBH_StatusTypeDef status;
if (length > USBH_MAX_DATA_BUFFER)
{
length = USBH_MAX_DATA_BUFFER;
}
status = USBH_GetDescriptor( phost, status = USBH_GetDescriptor( phost,
USB_REQ_RECIPIENT_INTERFACE | USB_REQ_TYPE_STANDARD, USB_REQ_RECIPIENT_INTERFACE | USB_REQ_TYPE_STANDARD,
USB_DESC_HID, USB_DESC_HID,

@ -116,6 +116,11 @@ USBH_StatusTypeDef USBH_Get_DevDesc(USBH_HandleTypeDef *phost, uint8_t length)
{ {
USBH_StatusTypeDef status; USBH_StatusTypeDef status;
if (length > USBH_MAX_DATA_BUFFER)
{
length = USBH_MAX_DATA_BUFFER;
}
if((status = USBH_GetDescriptor(phost, if((status = USBH_GetDescriptor(phost,
USB_REQ_RECIPIENT_DEVICE | USB_REQ_TYPE_STANDARD, USB_REQ_RECIPIENT_DEVICE | USB_REQ_TYPE_STANDARD,
USB_DESC_DEVICE, USB_DESC_DEVICE,
@ -191,6 +196,12 @@ USBH_StatusTypeDef USBH_Get_StringDesc(USBH_HandleTypeDef *phost,
uint16_t length) uint16_t length)
{ {
USBH_StatusTypeDef status; USBH_StatusTypeDef status;
if (length > USBH_MAX_DATA_BUFFER)
{
length = USBH_MAX_DATA_BUFFER;
}
if((status = USBH_GetDescriptor(phost, if((status = USBH_GetDescriptor(phost,
USB_REQ_RECIPIENT_DEVICE | USB_REQ_TYPE_STANDARD, USB_REQ_RECIPIENT_DEVICE | USB_REQ_TYPE_STANDARD,
USB_DESC_STRING | string_index, USB_DESC_STRING | string_index,

@ -14,32 +14,222 @@
#include "downstream_hid.h" #include "downstream_hid.h"
#include "downstream_statemachine.h" #include "downstream_statemachine.h"
#include "usbh_hid.h" #include "usbh_hid.h"
#include "stm32f4xx_hal.h"
#define HID_MAX_REPORT_LEN 8 #define HID_MAX_REPORT_LEN 8
#define HID_MOUSE_DATA_LEN 3 #define HID_MOUSE_DATA_LEN 4
#define HID_KEYBOARD_DATA_LEN 0 #define HID_KEYBOARD_DATA_LEN 0
#define HID_MOUSE_MAX_BUTTONS 4
DownstreamPacketTypeDef* SavedPacket;
extern USBH_HandleTypeDef hUsbHostFS; //Hard-link ourselves to usb_host.c extern USBH_HandleTypeDef hUsbHostFS; //Hard-link ourselves to usb_host.c
extern InterfaceCommandClassTypeDef ConfiguredDeviceClass; //Do a cheap hard-link to downstream_statemachine.c, rather than keep a duplicate here extern InterfaceCommandClassTypeDef ConfiguredDeviceClass; //Do a cheap hard-link to downstream_statemachine.c, rather than keep a duplicate here
//Information required to extract the data we need from incoming device reports.
uint8_t ReportButtonBitOffset;
uint8_t ReportButtonBitLength;
uint8_t ReportXBitOffset;
uint8_t ReportXBitLength;
uint8_t ReportYBitOffset;
uint8_t ReportYBitLength;
uint8_t ReportWheelBitOffset;
uint8_t ReportWheelBitLength;
//Stuff used while parsing HID report
uint8_t* ReportDataPointer;
uint8_t ItemHeader;
uint8_t ItemData;
static HAL_StatusTypeDef Downstream_HID_Mouse_ParseReportDescriptor(void);
static HAL_StatusTypeDef Downstream_HID_GetNextReportItem(void);
static void Downstream_HID_Mouse_ExtractDataFromReport(uint8_t* reportBuffer);
InterfaceCommandClassTypeDef Downstream_HID_ApproveConnectedDevice(void) InterfaceCommandClassTypeDef Downstream_HID_ApproveConnectedDevice(void)
{ {
HID_HandleTypeDef* HID_Handle = (HID_HandleTypeDef*)hUsbHostFS.pActiveClass->pData; HID_HandleTypeDef* HID_Handle = (HID_HandleTypeDef*)hUsbHostFS.pActiveClass->pData;
if (HID_Handle->Protocol == HID_MOUSE_BOOT_CODE) if (HID_Handle->Protocol != HID_MOUSE_BOOT_CODE)
{ {
if ((HID_Handle->length >= HID_MOUSE_DATA_LEN) && (HID_Handle->length <= HID_MAX_REPORT_LEN)) return COMMAND_CLASS_INTERFACE; //fail
}
if (Downstream_HID_Mouse_ParseReportDescriptor() != HAL_OK)
{
return COMMAND_CLASS_INTERFACE; //fail
}
return COMMAND_CLASS_HID_MOUSE; //success!
}
HAL_StatusTypeDef Downstream_HID_Mouse_ParseReportDescriptor(void)
{
uint32_t currentReportBitIndex = 0;
uint8_t currentUsagePage = 0;
uint8_t currentUsageIndex = 0;
uint8_t xUsageIndex = 0xFF;
uint8_t yUsageIndex = 0xFF;
uint8_t wheelUsageIndex = 0xFF;
uint8_t currentReportSize = 0;
uint8_t currentReportCount = 0;
ReportDataPointer = hUsbHostFS.device.Data;
ReportButtonBitLength = 0;
ReportXBitLength = 0;
ReportYBitLength = 0;
ReportWheelBitLength = 0;
while ((Downstream_HID_GetNextReportItem() == HAL_OK) && ((ReportButtonBitLength == 0) ||
(ReportXBitLength == 0) ||
(ReportYBitLength == 0) ||
(ReportWheelBitLength == 0)))
{
switch (ItemHeader)
{ {
return COMMAND_CLASS_HID_MOUSE; case HID_ITEM_USAGE_PAGE:
currentUsagePage = ItemData;
currentUsageIndex = 0;
xUsageIndex = 0xFF;
yUsageIndex = 0xFF;
wheelUsageIndex = 0xFF;
break;
case HID_ITEM_USAGE:
switch (ItemData)
{
case HID_ITEM_USAGE_X:
xUsageIndex = currentUsageIndex;
break;
case HID_ITEM_USAGE_Y:
yUsageIndex = currentUsageIndex;
break;
case HID_ITEM_USAGE_WHEEL:
wheelUsageIndex = currentUsageIndex;
break;
}
currentUsageIndex++;
break;
case HID_ITEM_REPORT_SIZE:
currentReportSize = ItemData;
break;
case HID_ITEM_REPORT_COUNT:
currentReportCount = ItemData;
break;
case HID_ITEM_INPUT:
switch (currentUsagePage)
{
case HID_ITEM_USAGE_PAGE_BUTTON:
if (ItemData == HID_ITEM_INPUT_ABS)
{
//Buttons found!
if (currentReportSize != 1)
{
return HAL_ERROR;
}
ReportButtonBitOffset = currentReportBitIndex;
ReportButtonBitLength = currentReportCount;
if (ReportButtonBitLength > HID_MOUSE_MAX_BUTTONS)
{
ReportButtonBitLength = HID_MOUSE_MAX_BUTTONS;
}
}
break;
case HID_ITEM_USAGE_PAGE_DESKTOP:
if (ItemData == HID_ITEM_INPUT_REL)
{
//Movement data found!
if ((currentReportSize < 8) || (currentReportSize > 16))
{
return HAL_ERROR;
}
if (xUsageIndex != 0xFF)
{
ReportXBitOffset = currentReportBitIndex + (currentReportSize * xUsageIndex);
ReportXBitLength = currentReportSize;
}
if (yUsageIndex != 0xFF)
{
ReportYBitOffset = currentReportBitIndex + (currentReportSize * yUsageIndex);
ReportYBitLength = currentReportSize;
}
if (xUsageIndex != 0xFF)
{
ReportWheelBitOffset = currentReportBitIndex + (currentReportSize * wheelUsageIndex);
ReportWheelBitLength = currentReportSize;
}
}
break;
}
currentReportBitIndex += (currentReportSize * currentReportCount);
if (currentReportBitIndex < (HID_MAX_REPORT_LEN * 8))
{
return HAL_ERROR;
}
break;
} }
} }
return COMMAND_CLASS_INTERFACE; //fail //We don't mind if we didn't find a scrollwheel item.
if ((ReportButtonBitLength == 0) ||
(ReportXBitLength == 0) ||
(ReportYBitLength == 0))
{
return HAL_ERROR;
}
return HAL_OK;
}
//Retrieves the next item in the HID report, and at most one of its associated data bytes.
//Then it updates ReportDataPointer based on the actual length of the retrieved item.
HAL_StatusTypeDef Downstream_HID_GetNextReportItem(void)
{
HID_HandleTypeDef* HID_Handle = (HID_HandleTypeDef*)hUsbHostFS.pActiveClass->pData;
uint32_t itemLength;
if ((ReportDataPointer >= &hUsbHostFS.device.Data[USBH_MAX_DATA_BUFFER]) ||
((ReportDataPointer - &hUsbHostFS.device.Data[0]) >= HID_Handle->HID_Desc.wItemLength))
{
return HAL_ERROR;
}
ItemHeader = *ReportDataPointer++;
itemLength = ItemHeader & HID_ITEM_LENGTH_MASK;
if (ItemHeader == HID_ITEM_LONG)
{
itemLength += *ReportDataPointer; //Long items have another length byte
}
else
{
if (itemLength > 0)
{
ItemData = *ReportDataPointer; //If it is a short item, grab its first data byte
}
}
ReportDataPointer += itemLength;
return HAL_OK;
} }
@ -52,9 +242,10 @@ void Downstream_HID_PacketProcessor(DownstreamPacketTypeDef* receivedPacket)
return; return;
} }
SavedPacket = receivedPacket;
if (USBH_HID_GetInterruptReport(&hUsbHostFS, if (USBH_HID_GetInterruptReport(&hUsbHostFS,
Downstream_HID_InterruptReportCallback, Downstream_HID_InterruptReportCallback) != HAL_OK)
receivedPacket) != HAL_OK) //Don't free the packet, USBH_HID will use it then return it to InterruptReportCallback below
{ {
Downstream_PacketProcessor_FreakOut(); Downstream_PacketProcessor_FreakOut();
} }
@ -62,11 +253,12 @@ void Downstream_HID_PacketProcessor(DownstreamPacketTypeDef* receivedPacket)
} }
void Downstream_HID_InterruptReportCallback(DownstreamPacketTypeDef* packetToSend) void Downstream_HID_InterruptReportCallback(uint8_t* reportBuffer)
{ {
if (ConfiguredDeviceClass == COMMAND_CLASS_HID_MOUSE) if (ConfiguredDeviceClass == COMMAND_CLASS_HID_MOUSE)
{ {
packetToSend->Length16 = ((HID_MOUSE_DATA_LEN + 1) / 2) + DOWNSTREAM_PACKET_HEADER_LEN_16; Downstream_HID_Mouse_ExtractDataFromReport(reportBuffer);
SavedPacket->Length16 = ((HID_MOUSE_DATA_LEN + 1) / 2) + DOWNSTREAM_PACKET_HEADER_LEN_16;
} }
//else if... //else if...
else else
@ -75,7 +267,35 @@ void Downstream_HID_InterruptReportCallback(DownstreamPacketTypeDef* packetToSen
return; return;
} }
Downstream_PacketProcessor_ClassReply(packetToSend); Downstream_PacketProcessor_ClassReply(SavedPacket);
}
void Downstream_HID_Mouse_ExtractDataFromReport(uint8_t* reportBuffer)
{
uint16_t readData;
//Grab the buttons
readData = *(uint16_t*)&(reportBuffer[(ReportButtonBitOffset / 8)]);
readData >>= (ReportButtonBitOffset % 8);
readData &= ((1 << ReportButtonBitLength) - 1);
SavedPacket->Data[0] = readData;
//Grab X
readData = *(uint16_t*)&(reportBuffer[(ReportXBitOffset / 8)]);
readData >>= (ReportXBitOffset % 8);
SavedPacket->Data[1] = (uint8_t)readData;
//Grab Y
readData = *(uint16_t*)&(reportBuffer[(ReportYBitOffset / 8)]);
readData >>= (ReportYBitOffset % 8);
SavedPacket->Data[2] = (uint8_t)readData;
//Grab wheel
readData = *(uint16_t*)&(reportBuffer[(ReportWheelBitOffset / 8)]);
readData >>= (ReportWheelBitOffset % 8);
SavedPacket->Data[3] = (uint8_t)readData;
} }

@ -57,7 +57,7 @@ InterfaceCommandClassTypeDef Downstream_MSC_ApproveConnectedDevice(void)
return COMMAND_CLASS_INTERFACE; //fail return COMMAND_CLASS_INTERFACE; //fail
} }
return COMMAND_CLASS_MASS_STORAGE; return COMMAND_CLASS_MASS_STORAGE; //success!
} }

Loading…
Cancel
Save