Fix the handling of setidle requests

This commit is contained in:
Ciaran Woodward
2021-12-22 15:41:06 +00:00
parent d5d5bd0637
commit 466cc0abbb
6 changed files with 111 additions and 20 deletions

View File

@@ -374,15 +374,15 @@ void XUA_Buffer_Ep(register chanend c_aud_out,
#if( 0 < HID_CONTROLS )
UserHIDInit();
{
while (!hidIsReportDescriptorPrepared())
;
/* Get the last report - we don't really care which it is, so long as there's some data we can grab. */
int hidReportLength = (int) UserHIDGetData(hidGetReportIdLimit() - 1, g_hidData);
while (!hidIsReportDescriptorPrepared())
;
/* Get the a report - we don't really care which it is, so long as there's some data we can grab. */
int hidReportLength = (int) UserHIDGetData(hidGetNextValidReportId(0), g_hidData);
XUD_SetReady_In(ep_hid, g_hidData, hidReportLength);
XUD_SetReady_In(ep_hid, g_hidData, hidReportLength);
}
#endif
#if (AUDIO_CLASS == 1)

View File

@@ -129,6 +129,31 @@ static unsigned HidFindSetIdleActivationPoint( const unsigned currentPeriod, con
return result;
}
/**
* \brief Configure a hid report's next report time and idle status based on a setidle request
*
* \param[in] reportId -- The report ID to modify
* \param[in] reportDuration -- The duration of the setidle request
*
*/
static void HidUpdateReportPeriod( unsigned reportId, unsigned reportDuration ) {
unsigned currentPeriod = hidGetReportPeriod( reportId );
hidSetIdle( reportId, ( 0U == duration ) || ( ENDPOINT_INT_INTERVAL_IN_HID < duration ));
if( hidIsIdleActive( reportId )) {
unsigned reportTime = hidGetReportTime( reportId );
unsigned reportToSetIdleInterval = HidCalcReportToSetIdleInterval( reportTime );
unsigned nextReportTime = HidCalcNewReportTime( currentPeriod, reportTime, reportToSetIdleInterval, reportDuration * MS_IN_TICKS );
hidSetNextReportTime( reportId, nextReportTime );
currentPeriod = reportDuration * MS_IN_TICKS;
} else {
currentPeriod = ENDPOINT_INT_INTERVAL_IN_HID * MS_IN_TICKS;
}
hidSetReportPeriod( reportId, currentPeriod );
}
/**
* \brief Process a Set Idle request
*
@@ -166,22 +191,24 @@ static XUD_Result_t HidProcessSetIdleRequest( XUD_ep c_ep0_out, XUD_ep c_ep0_in,
Any Interface value other than INTERFACE_NUMBER_HID indicates an error by the USB Host.
*/
if(( 0U == reportId ) && ( INTERFACE_NUMBER_HID == interfaceNum )) {
hidSetIdle( reportId, ( 0U == duration ) || ( ENDPOINT_INT_INTERVAL_IN_HID < duration ));
if( INTERFACE_NUMBER_HID == interfaceNum ) {
if( hidIsReportIdValid( reportId ) ) {
HidUpdateReportPeriod( reportId, duration );
unsigned currentPeriod = hidGetReportPeriod( reportId );
if( hidIsIdleActive( reportId )) {
unsigned reportTime = hidGetReportTime( reportId );
unsigned reportToSetIdleInterval = HidCalcReportToSetIdleInterval( reportTime );
unsigned nextReportTime = HidCalcNewReportTime( currentPeriod, reportTime, reportToSetIdleInterval, duration * MS_IN_TICKS );
hidSetNextReportTime( reportId, nextReportTime );
currentPeriod = duration * MS_IN_TICKS;
} else {
currentPeriod = ENDPOINT_INT_INTERVAL_IN_HID * MS_IN_TICKS;
result = XUD_DoSetRequestStatus( c_ep0_in );
}
else if ( reportId == 0U ) {
// Wildcard request - set all report IDs to idle
unsigned startReportId = hidGetNextValidReportId(reportId);
hidSetReportPeriod( reportId, currentPeriod );
result = XUD_DoSetRequestStatus( c_ep0_in );
reportId = startReportId;
do {
HidUpdateReportPeriod( reportId, duration );
reportId = hidGetNextValidReportId( reportId );
} while( reportId != startReportId);
result = XUD_DoSetRequestStatus( c_ep0_in );
}
}
return result;

View File

@@ -254,6 +254,20 @@ unsigned hidIsReportIdInUse ( void ) {
return 0;
}
unsigned hidIsReportIdValid ( unsigned id ) {
size_t retVal = 0;
for( size_t idx = 0U; idx < HID_REPORT_COUNT; ++idx ) {
unsigned reportId = hidGetElementReportId( hidReports[ idx ]->location );
if( reportId == id ) {
retVal = 1;
break;
}
}
return retVal;
}
unsigned hidGetNextValidReportId ( unsigned idPrev ) {
size_t retIndex = 0;

View File

@@ -203,6 +203,20 @@ unsigned hidGetReportIdLimit ( void );
*/
unsigned hidIsReportIdInUse ( void );
/**
* @brief Is the provided report ID valid for passing to other functions.
*
* e.g If Report IDs are not in use, then only 0 will return true.
* e.g If Report IDs are in use, then 0 will return false and the report IDs that
* are in use will return true when passed to thsi function.
*
* @param id The ID to check
* @return boolean
* @retval 0 The report ID is not valid, other functions may fail silently
* @retval 1 The report ID is valid and can be used as the argument to other functions
*/
unsigned hidIsReportIdValid ( unsigned id );
/**
* @brief Get the next valid report ID - iterator style.
*

View File

@@ -79,6 +79,30 @@ void test_get_next_valid_report_id( void ) {
TEST_ASSERT_EQUAL_UINT( 1, reportId );
}
void test_is_report_id_valid( void ) {
unsigned isValid = 0;
unsigned reportId = 0;
isValid = hidIsReportIdValid( reportId );
TEST_ASSERT_EQUAL_UINT( 0, isValid );
reportId = 1;
isValid = hidIsReportIdValid( reportId );
TEST_ASSERT_EQUAL_UINT( 1, isValid );
reportId = 2;
isValid = hidIsReportIdValid( reportId );
TEST_ASSERT_EQUAL_UINT( 1, isValid );
reportId = 3;
isValid = hidIsReportIdValid( reportId );
TEST_ASSERT_EQUAL_UINT( 1, isValid );
reportId = 4;
isValid = hidIsReportIdValid( reportId );
TEST_ASSERT_EQUAL_UINT( 0, isValid );
}
// Basic report descriptor tests
void test_unprepared_hidGetReportDescriptor( void )
{

View File

@@ -60,6 +60,18 @@ void test_get_next_valid_report_id( void ) {
TEST_ASSERT_EQUAL_UINT( 0, reportId );
}
void test_is_report_id_valid( void ) {
unsigned isValid = 0;
unsigned reportId = 0;
isValid = hidIsReportIdValid( reportId );
TEST_ASSERT_EQUAL_UINT( 1, isValid );
reportId = 1;
isValid = hidIsReportIdValid( reportId );
TEST_ASSERT_EQUAL_UINT( 0, isValid );
}
// Basic report descriptor tests
void test_unprepared_hidGetReportDescriptor( void )
{