From 466cc0abbbde4ea16e19638885baebb9fb306a23 Mon Sep 17 00:00:00 2001 From: Ciaran Woodward Date: Wed, 22 Dec 2021 15:41:06 +0000 Subject: [PATCH] Fix the handling of setidle requests --- lib_xua/src/core/buffer/ep/ep_buffer.xc | 14 ++--- lib_xua/src/hid/hid.xc | 53 ++++++++++++++----- lib_xua/src/hid/hid_report.c | 14 +++++ lib_xua/src/hid/xua_hid_report.h | 14 +++++ .../test_multi_report/test_hid_multi_report.c | 24 +++++++++ .../xua_unit_tests/src/test_simple/test_hid.c | 12 +++++ 6 files changed, 111 insertions(+), 20 deletions(-) diff --git a/lib_xua/src/core/buffer/ep/ep_buffer.xc b/lib_xua/src/core/buffer/ep/ep_buffer.xc index cfacd9b9..d87db99b 100644 --- a/lib_xua/src/core/buffer/ep/ep_buffer.xc +++ b/lib_xua/src/core/buffer/ep/ep_buffer.xc @@ -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) diff --git a/lib_xua/src/hid/hid.xc b/lib_xua/src/hid/hid.xc index d9a0d500..cd59d6a5 100644 --- a/lib_xua/src/hid/hid.xc +++ b/lib_xua/src/hid/hid.xc @@ -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; diff --git a/lib_xua/src/hid/hid_report.c b/lib_xua/src/hid/hid_report.c index 97d7f014..a647204e 100644 --- a/lib_xua/src/hid/hid_report.c +++ b/lib_xua/src/hid/hid_report.c @@ -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; diff --git a/lib_xua/src/hid/xua_hid_report.h b/lib_xua/src/hid/xua_hid_report.h index c5574441..e05810da 100644 --- a/lib_xua/src/hid/xua_hid_report.h +++ b/lib_xua/src/hid/xua_hid_report.h @@ -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. * diff --git a/tests/xua_unit_tests/src/test_multi_report/test_hid_multi_report.c b/tests/xua_unit_tests/src/test_multi_report/test_hid_multi_report.c index a78e7fcf..bad4c699 100644 --- a/tests/xua_unit_tests/src/test_multi_report/test_hid_multi_report.c +++ b/tests/xua_unit_tests/src/test_multi_report/test_hid_multi_report.c @@ -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 ) { diff --git a/tests/xua_unit_tests/src/test_simple/test_hid.c b/tests/xua_unit_tests/src/test_simple/test_hid.c index 29d96021..856edd79 100644 --- a/tests/xua_unit_tests/src/test_simple/test_hid.c +++ b/tests/xua_unit_tests/src/test_simple/test_hid.c @@ -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 ) {