forked from PAWPAW-Mirror/lib_xua
Merge pull request #3 from michaelb/pendragon_hid_add_requests
Pendragon hid add requests
This commit is contained in:
@@ -5,6 +5,7 @@ lib_xua Change Log
|
||||
----------
|
||||
* ADDED: UAC1 HID support with simulated Voice Command detection reported
|
||||
every 10 seconds
|
||||
* ADDED: Support for USB HID Set Idle request
|
||||
|
||||
0.2.0
|
||||
-----
|
||||
|
||||
@@ -3,6 +3,11 @@
|
||||
#ifndef __DESCRIPTOR_DEFS_H__
|
||||
#define __DESCRIPTOR_DEFS_H__
|
||||
|
||||
/*
|
||||
Include xua.h to pick up the #defines of NUM_USB_CHAN_IN and NUM_USB_CHAN_OUT.
|
||||
*/
|
||||
#include "xua.h"
|
||||
|
||||
#if (NUM_USB_CHAN_IN > 0) && (NUM_USB_CHAN_OUT > 0)
|
||||
#define AUDIO_INTERFACE_COUNT 3
|
||||
#elif (NUM_USB_CHAN_IN > 0) || (NUM_USB_CHAN_OUT > 0)
|
||||
@@ -60,4 +65,8 @@ enum USBInterfaceNumber
|
||||
INTERFACE_COUNT /* End marker */
|
||||
};
|
||||
|
||||
#if( 0 < HID_CONTROLS )
|
||||
#define ENDPOINT_INT_INTERVAL_IN_HID 0x08
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
@@ -60,7 +60,7 @@
|
||||
extern void device_reboot(void);
|
||||
#endif
|
||||
|
||||
#if HID_CONTROLS
|
||||
#if( 0 < HID_CONTROLS )
|
||||
#include "xua_hid.h"
|
||||
#endif
|
||||
|
||||
@@ -993,7 +993,7 @@ void XUA_Endpoint0_lite_loop(XUD_Result_t result, USB_SetupPacket_t sp, chanend
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#if HID_CONTROLS
|
||||
#if( 0 < HID_CONTROLS )
|
||||
if (interfaceNum == INTERFACE_NUMBER_HID)
|
||||
{
|
||||
result = HidInterfaceClassRequests(ep0_out, ep0_in, &sp);
|
||||
|
||||
@@ -2184,7 +2184,7 @@ USB_Config_Descriptor_Audio2_t cfgDesc_Audio2=
|
||||
ENDPOINT_ADDRESS_IN_HID, /* 2 bEndpointAddress */
|
||||
3, /* 3 bmAttributes (INTERRUPT) */
|
||||
64, /* 4 wMaxPacketSize */
|
||||
8, /* 6 bInterval */
|
||||
ENDPOINT_INT_INTERVAL_IN_HID, /* 6 bInterval */
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -2862,7 +2862,7 @@ unsigned char cfgDesc_Audio1[] =
|
||||
0x03, /* 3 bmAttributes (INTERRUPT) */
|
||||
0x40, /* 4 wMaxPacketSize */
|
||||
0x00, /* 5 wMaxPacketSize */
|
||||
0x08, /* 6 bInterval */
|
||||
ENDPOINT_INT_INTERVAL_IN_HID, /* 6 bInterval */
|
||||
#endif
|
||||
|
||||
};
|
||||
|
||||
@@ -1,26 +1,221 @@
|
||||
#include <xs1.h>
|
||||
#include "xud.h"
|
||||
#include "descriptor_defs.h"
|
||||
#include "hid.h"
|
||||
#include "xud.h"
|
||||
#include "xud_std_requests.h"
|
||||
#include "xua_hid.h"
|
||||
|
||||
static unsigned hidSetIdle = 0;
|
||||
#if( 0 < HID_CONTROLS )
|
||||
#define MS_IN_TICKS 100000U
|
||||
|
||||
unsigned HidIsSetIdleSilenced(void)
|
||||
static unsigned s_hidIdleActive = 0U;
|
||||
static unsigned s_hidCurrentPeriod = ENDPOINT_INT_INTERVAL_IN_HID * MS_IN_TICKS;
|
||||
static unsigned s_hidIndefiniteDuration = 0U;
|
||||
static unsigned s_hidNextReportTime = 0U;
|
||||
static unsigned s_hidReportTime = 0U;
|
||||
|
||||
static unsigned HidCalcNewReportTime( const unsigned currentPeriod, const unsigned reportTime, const unsigned reportToSetIdleInterval, const unsigned newPeriod );
|
||||
static unsigned HidCalcReportToSetIdleInterval( const unsigned reportTime );
|
||||
static unsigned HidFindSetIdleActivationPoint( const unsigned currentPeriod, const unsigned timeWithinPeriod );
|
||||
static XUD_Result_t HidProcessSetIdleRequest( XUD_ep c_ep0_out, XUD_ep c_ep0_in, USB_SetupPacket_t &sp );
|
||||
static unsigned HidTimeDiff( const unsigned earlierTime, const unsigned laterTime );
|
||||
|
||||
void HidCalcNextReportTime( void )
|
||||
{
|
||||
return hidSetIdle;
|
||||
s_hidNextReportTime = s_hidReportTime + s_hidCurrentPeriod;
|
||||
}
|
||||
|
||||
XUD_Result_t HidInterfaceClassRequests(XUD_ep c_ep0_out, XUD_ep c_ep0_in,
|
||||
USB_SetupPacket_t &sp)
|
||||
void HidCaptureReportTime( void )
|
||||
{
|
||||
switch (sp.bRequest) {
|
||||
case HID_SET_IDLE:
|
||||
printstr("HID_SET_IDLE\n");
|
||||
hidSetIdle = 1; // TODO implement duration
|
||||
return XUD_DoSetRequestStatus(c_ep0_in);
|
||||
default:
|
||||
break;
|
||||
timer tmr;
|
||||
tmr :> s_hidReportTime;
|
||||
}
|
||||
|
||||
XUD_Result_t HidInterfaceClassRequests(
|
||||
XUD_ep c_ep0_out,
|
||||
XUD_ep c_ep0_in,
|
||||
USB_SetupPacket_t &sp )
|
||||
{
|
||||
XUD_Result_t result = XUD_RES_ERR;
|
||||
|
||||
switch ( sp.bRequest ) {
|
||||
case HID_SET_IDLE:
|
||||
result = HidProcessSetIdleRequest( c_ep0_out, c_ep0_in, sp );
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
unsigned HidIsSetIdleSilenced( void )
|
||||
{
|
||||
unsigned isSilenced = s_hidIdleActive;
|
||||
|
||||
if( s_hidIdleActive ) {
|
||||
unsigned currentTime;
|
||||
asm volatile( "gettime %0" : "=r" ( currentTime )); // Use inline assembly to access the time without creating a side-effect
|
||||
isSilenced = ( s_hidIndefiniteDuration || ( timeafter( s_hidNextReportTime, currentTime )));
|
||||
}
|
||||
|
||||
return isSilenced;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Calculate the timer value for sending the next HID Report.
|
||||
*
|
||||
* With regard to Section 7.2.4 Set_Idle Request of the USB Device Class Definition for Human
|
||||
* Interface Devices (HID) Version 1.11, I've interpreted 'currently executing period' and
|
||||
* 'current period' to mean the previously established Set Idle duration if one has been
|
||||
* established or the polling interval from the HID Report Descriptor if a Set Idle duration
|
||||
* has not been established.
|
||||
*
|
||||
* \param[in] currentPeriod -- The duration of the current period in timer ticks
|
||||
* \param[in] reportTime -- The time at which the last HID Report was sent
|
||||
* \param[in] reportToSetIdleInterval -- The time interval between receiving the Set Idle Request
|
||||
* and sending the most recent HID Report
|
||||
* \param[in] newPeriod -- The new period value in timer ticks
|
||||
*
|
||||
* \return The time at which the next HID Report should be sent
|
||||
*/
|
||||
static unsigned HidCalcNewReportTime( const unsigned currentPeriod, const unsigned reportTime, const unsigned reportToSetIdleInterval, const unsigned newPeriod )
|
||||
{
|
||||
unsigned nextReportTime = 0;
|
||||
|
||||
if( HidFindSetIdleActivationPoint( currentPeriod, reportToSetIdleInterval )) {
|
||||
/* Activate immediately after sending the next HID Report */
|
||||
nextReportTime = reportTime + currentPeriod;
|
||||
} else {
|
||||
/* Activate immediately after sending the most recent HID Report */
|
||||
nextReportTime = reportTime + newPeriod;
|
||||
}
|
||||
|
||||
return nextReportTime;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Calculate the time interval between the most recent HID Report and a subsequent Set Idle Request
|
||||
*
|
||||
* \warning For this function to produce an accurate interval measument, it must be called without delay
|
||||
* upon receiving a Set Idle Request from the USB Host.
|
||||
*
|
||||
* \param[in] reportTime -- The time at which the last HID Report was sent
|
||||
*
|
||||
* \return The time interval between receiving the Set Idle Request and sending the most recent HID Report
|
||||
*/
|
||||
static unsigned HidCalcReportToSetIdleInterval( const unsigned reportTime )
|
||||
{
|
||||
timer tmr;
|
||||
unsigned setIdleTime;
|
||||
|
||||
tmr :> setIdleTime;
|
||||
unsigned result = HidTimeDiff( reportTime, setIdleTime );
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Indicate if activation of the Set Idle Request happens at the previous or next HID Report
|
||||
*
|
||||
* Section 7.2.4 Set_Idle Request of the USB Device Class Definition for Human Interface
|
||||
* Devices (HID) Version 1.11 makes two statements about the activation point for starting the
|
||||
* duration of the request:
|
||||
* - 'A new request will be executed as if it were issued immediately after the last report, if
|
||||
* the new request is received at least 4 milliseconds before the end of the currently executing
|
||||
* period.'
|
||||
* - 'If the new request is received within 4 milliseconds of the end of the current period, then
|
||||
* the new request will have no effect until after the report.'
|
||||
*
|
||||
* \param[in] currentPeriod -- The duration of the current period
|
||||
* \param[in] timeWithinPeriod -- The current point in time relative to the current period
|
||||
*
|
||||
* \return A Boolean indicating where the activation of the Set Idle Request Duration occurs.
|
||||
* \retval 1 -- Activate immediately after the next HID Report
|
||||
* \retval 0 -- Activate immediately after the previous HID Report
|
||||
*/
|
||||
static unsigned HidFindSetIdleActivationPoint( const unsigned currentPeriod, const unsigned timeWithinPeriod )
|
||||
{
|
||||
unsigned result = (( currentPeriod - timeWithinPeriod ) < ( 4U * MS_IN_TICKS )) ? 1 : 0;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Process a Set Idle request
|
||||
*
|
||||
* \param[in] c_ep0_out -- the channel that carries data from Endpoint 0
|
||||
* \param[in] c_ep0_in -- the channel that carries data for Endpoint 0
|
||||
* \param[in] sp -- a structure containing the Set Idle data
|
||||
*
|
||||
* \return An XUD status value
|
||||
*/
|
||||
static XUD_Result_t HidProcessSetIdleRequest( XUD_ep c_ep0_out, XUD_ep c_ep0_in, USB_SetupPacket_t &sp )
|
||||
{
|
||||
XUD_Result_t result = XUD_RES_ERR;
|
||||
|
||||
/*
|
||||
The Set Idle request wValue field contains two sub-fields:
|
||||
- Duration in the MSB; and
|
||||
- Report ID in the LSB.
|
||||
|
||||
The Duration field specifies how long the USB Device responds with NAK provided the HID data hasn't changed.
|
||||
Zero means indefinitely.
|
||||
The value is in units of 4ms.
|
||||
|
||||
The Report ID identifies the HID report that the USB Host wishes to silence.
|
||||
|
||||
The Set Idle request xIndex field contains the interface number.
|
||||
*/
|
||||
uint16_t duration = ( sp.wValue & 0xFF00 ) >> 6; // Transform from units of 4ms into units of 1ms.
|
||||
uint8_t reportId = sp.wValue & 0x00FF;
|
||||
uint16_t interfaceNum = sp.wIndex;
|
||||
|
||||
/*
|
||||
As long as our HID Report Descriptor does not include a Report ID, any Report ID value other than zero
|
||||
indicates an error by the USB Host (see xua_ep0_descriptors.h for the definition of the HID
|
||||
Report Descriptor).
|
||||
|
||||
Any Interface value other than INTERFACE_NUMBER_HID indicates an error by the USB Host.
|
||||
*/
|
||||
if(( 0U == reportId ) && ( INTERFACE_NUMBER_HID == interfaceNum )) {
|
||||
s_hidIdleActive = (( 0U == duration ) || ( ENDPOINT_INT_INTERVAL_IN_HID < duration ));
|
||||
|
||||
if( s_hidIdleActive ) {
|
||||
unsigned reportToSetIdleInterval = HidCalcReportToSetIdleInterval( s_hidReportTime );
|
||||
s_hidNextReportTime = HidCalcNewReportTime( s_hidCurrentPeriod, s_hidReportTime, reportToSetIdleInterval, duration * MS_IN_TICKS );
|
||||
s_hidCurrentPeriod = duration * MS_IN_TICKS;
|
||||
s_hidIndefiniteDuration = ( 0U == duration );
|
||||
} else {
|
||||
s_hidCurrentPeriod = ENDPOINT_INT_INTERVAL_IN_HID * MS_IN_TICKS;
|
||||
s_hidIndefiniteDuration = 0U;
|
||||
}
|
||||
return XUD_RES_ERR;
|
||||
|
||||
result = XUD_DoSetRequestStatus( c_ep0_in );
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Calculate the difference between two points in time
|
||||
*
|
||||
* This function calculates the difference between two two points in time.
|
||||
* It always returns a positive value even if the timer used to obtain the two
|
||||
* time measurements has wrapped around.
|
||||
*
|
||||
* \warning If time values have been obtained from a timer that has wrapped
|
||||
* more than once in between the two measurements, this function returns an
|
||||
* incorrect value.
|
||||
*
|
||||
* \param[in] earlierTime -- A value from a timer
|
||||
* \param[in] laterTime -- A value from a timer taken after \a earlierTime
|
||||
*
|
||||
* \return The interval between the two points in time
|
||||
*/
|
||||
static unsigned HidTimeDiff( const unsigned earlierTime, const unsigned laterTime )
|
||||
{
|
||||
return ( earlierTime < laterTime ) ? laterTime - earlierTime : UINT_MAX - earlierTime + laterTime;
|
||||
}
|
||||
|
||||
#endif /* ( 0 < HID_CONTROLS ) */
|
||||
|
||||
@@ -3,7 +3,52 @@
|
||||
#include "xud.h"
|
||||
#include "xud_std_requests.h"
|
||||
|
||||
XUD_Result_t HidInterfaceClassRequests(XUD_ep c_ep0_out, XUD_ep c_ep0_in,
|
||||
REFERENCE_PARAM(USB_SetupPacket_t, sp));
|
||||
/**
|
||||
* \brief Calculate the next time to respond with a HID Report.
|
||||
*
|
||||
* If the USB Host has previously sent a valid HID Set_Idle request with
|
||||
* a duration of zero or greater than the default reporting interval,
|
||||
* the device sends HID Reports periodically or when the value of the
|
||||
* payload has changed.
|
||||
*
|
||||
* This function calculates the time for sending the next periodic
|
||||
* HID Report.
|
||||
*/
|
||||
void HidCalcNextReportTime( void );
|
||||
|
||||
unsigned HidIsSetIdleSilenced(void);
|
||||
/**
|
||||
* \brief Capture the time of sending the current HID Report.
|
||||
*
|
||||
* If the USB Host has previously sent a valid HID Set_Idle request with
|
||||
* a duration of zero or greater than the default reporting interval,
|
||||
* the device sends HID Reports periodically or when the value of the
|
||||
* payload has changed.
|
||||
*
|
||||
* This function captures the time when the HID Report was sent so that
|
||||
* a subsequent call to HidCalNextReportTime() can calculate the time
|
||||
* to send the next periodic HID Report.
|
||||
*/
|
||||
void HidCaptureReportTime( void );
|
||||
|
||||
XUD_Result_t HidInterfaceClassRequests(
|
||||
XUD_ep c_ep0_out,
|
||||
XUD_ep c_ep0_in,
|
||||
REFERENCE_PARAM( USB_SetupPacket_t, sp ));
|
||||
|
||||
/**
|
||||
* \brief Indicate whether to send a HID Report based on elapsed time.
|
||||
*
|
||||
* If the USB Host has previously sent a valid HID Set_Idle request with
|
||||
* a duration of zero or greater than the default reporting interval,
|
||||
* the device sends HID Reports periodically or when the value of the
|
||||
* payload has changed.
|
||||
*
|
||||
* This function monitors the passage of time and reports to the caller
|
||||
* whether or not the time to send the next periodic HID Report has
|
||||
* elapsed.
|
||||
*
|
||||
* \return A Boolean value indicating whether or not to send the HID Report.
|
||||
* \retval 1 -- Do not send the HID Report
|
||||
* \retval 0 -- Send the HID Report
|
||||
*/
|
||||
unsigned HidIsSetIdleSilenced( void );
|
||||
|
||||
Reference in New Issue
Block a user