From a5f4e52e022c5757443ac2be40942c0411b3bc94 Mon Sep 17 00:00:00 2001 From: Robert Fisk Date: Tue, 26 Apr 2016 11:30:47 +1200 Subject: [PATCH] More work on enumerating cheap POS mice, arrrrgh. Added timeout checks and retry functionality to control transaction state machine. But some times the device just won't talk, so we flash the fault LED slowly to give the user some clue about what happened. --- .../Core/Inc/usbh_def.h | 4 +- .../Core/Src/usbh_core.c | 5 +- .../Core/Src/usbh_ctlreq.c | 125 +++++++----------- Downstream/Src/downstream_statemachine.c | 11 +- Downstream/Src/usbh_config.c | 2 +- 5 files changed, 59 insertions(+), 88 deletions(-) diff --git a/Downstream/Middlewares/ST/STM32_USB_Host_Library/Core/Inc/usbh_def.h b/Downstream/Middlewares/ST/STM32_USB_Host_Library/Core/Inc/usbh_def.h index 48dd3f4..0b74acd 100644 --- a/Downstream/Middlewares/ST/STM32_USB_Host_Library/Core/Inc/usbh_def.h +++ b/Downstream/Middlewares/ST/STM32_USB_Host_Library/Core/Inc/usbh_def.h @@ -190,6 +190,8 @@ #define USBH_MAX_ERROR_COUNT 2 #define USBH_DEVICE_ADDRESS 1 +#define USBH_CTRL_TRANSACTION_TIMEOUT_MS 100 + /** * @} @@ -413,8 +415,8 @@ typedef struct uint8_t pipe_out; uint8_t pipe_size; uint8_t *buff; + uint32_t timer; uint16_t length; - uint16_t timer; USB_Setup_TypeDef setup; CTRL_StateTypeDef state; uint8_t errorcount; diff --git a/Downstream/Middlewares/ST/STM32_USB_Host_Library/Core/Src/usbh_core.c b/Downstream/Middlewares/ST/STM32_USB_Host_Library/Core/Src/usbh_core.c index 4eb2709..2f0e71a 100644 --- a/Downstream/Middlewares/ST/STM32_USB_Host_Library/Core/Src/usbh_core.c +++ b/Downstream/Middlewares/ST/STM32_USB_Host_Library/Core/Src/usbh_core.c @@ -152,6 +152,8 @@ USBH_StatusTypeDef USBH_DeInit(USBH_HandleTypeDef *phost) USBH_LL_Stop(phost); } + USBH_LL_DeInit(phost); + return USBH_OK; } @@ -187,6 +189,7 @@ static USBH_StatusTypeDef DeInitStateMachine(USBH_HandleTypeDef *phost) phost->device.address = USBH_ADDRESS_DEFAULT; phost->device.speed = USBH_SPEED_FULL; + phost->device.is_connected = 0; return USBH_OK; } @@ -840,7 +843,7 @@ USBH_StatusTypeDef USBH_LL_Connect (USBH_HandleTypeDef *phost) } else if (phost->gState == HOST_DEV_WAIT_FOR_ATTACHMENT) { - //On the first boot after a power cycle with a low-speed device pre-attached, + //On a cold boot with a low-speed device pre-attached, //we get a second port-connected interrupt!??? //So go back and do the port reset again... phost->gState = HOST_IDLE; diff --git a/Downstream/Middlewares/ST/STM32_USB_Host_Library/Core/Src/usbh_ctlreq.c b/Downstream/Middlewares/ST/STM32_USB_Host_Library/Core/Src/usbh_ctlreq.c index df7f7d5..b853762 100644 --- a/Downstream/Middlewares/ST/STM32_USB_Host_Library/Core/Src/usbh_ctlreq.c +++ b/Downstream/Middlewares/ST/STM32_USB_Host_Library/Core/Src/usbh_ctlreq.c @@ -603,15 +603,14 @@ static USBH_StatusTypeDef USBH_HandleControl (USBH_HandleTypeDef *phost) { case CTRL_SETUP: /* send a SETUP packet */ - USBH_CtlSendSetup (phost, + phost->Control.timer = phost->Timer; + USBH_CtlSendSetup(phost, (uint8_t *)phost->Control.setup.d8 , phost->Control.pipe_out); - phost->Control.state = CTRL_SETUP_WAIT; break; case CTRL_SETUP_WAIT: - URB_Status = USBH_LL_GetURBState(phost, phost->Control.pipe_out); /* case SETUP packet sent successfully */ if(URB_Status == USBH_URB_DONE) @@ -647,22 +646,24 @@ static USBH_StatusTypeDef USBH_HandleControl (USBH_HandleTypeDef *phost) phost->Control.state = CTRL_STATUS_IN; } } -#if (USBH_USE_OS == 1) - osMessagePut ( phost->os_event, USBH_CONTROL_EVENT, 0); -#endif } else if(URB_Status == USBH_URB_ERROR) { phost->Control.state = CTRL_ERROR; -#if (USBH_USE_OS == 1) - osMessagePut ( phost->os_event, USBH_CONTROL_EVENT, 0); -#endif } else if (URB_Status == USBH_URB_NOTREADY) { - //Some mice cause a transaction error interrupt (HCINT_TXERR) at this point, - //so we retry and hope for the best! - phost->Control.state = CTRL_SETUP; + //Some mice cause a transaction error interrupt (HCINT_TXERR) at this point. + //Other mice just NAK our transaction. + //Either way we need to retry, but keep our original timeout so we don't wait forever. + USBH_CtlSendSetup(phost, + (uint8_t *)phost->Control.setup.d8 , + phost->Control.pipe_out); + } + + if ((int32_t)(phost->Timer - phost->Control.timer) >= USBH_CTRL_TRANSACTION_TIMEOUT_MS) + { + phost->Control.state = CTRL_ERROR; } break; @@ -678,171 +679,139 @@ static USBH_StatusTypeDef USBH_HandleControl (USBH_HandleTypeDef *phost) break; case CTRL_DATA_IN_WAIT: - URB_Status = USBH_LL_GetURBState(phost , phost->Control.pipe_in); /* check is DATA packet transferred successfully */ if (URB_Status == USBH_URB_DONE) { phost->Control.state = CTRL_STATUS_OUT; -#if (USBH_USE_OS == 1) - osMessagePut ( phost->os_event, USBH_CONTROL_EVENT, 0); -#endif } /* manage error cases*/ if (URB_Status == USBH_URB_STALL) { - /* In stall case, return to previous machine state*/ - status = USBH_NOT_SUPPORTED; -#if (USBH_USE_OS == 1) - osMessagePut ( phost->os_event, USBH_CONTROL_EVENT, 0); -#endif + //Retry transaction + phost->Control.state = CTRL_ERROR; } else if (URB_Status == USBH_URB_ERROR) { /* Device error */ - phost->Control.state = CTRL_ERROR; -#if (USBH_USE_OS == 1) - osMessagePut ( phost->os_event, USBH_CONTROL_EVENT, 0); -#endif + phost->Control.state = CTRL_ERROR; + } + + if ((int32_t)(phost->Timer - phost->Control.timer) >= USBH_CTRL_TRANSACTION_TIMEOUT_MS) + { + phost->Control.state = CTRL_ERROR; } break; case CTRL_DATA_OUT: - + phost->Control.timer = phost->Timer; USBH_CtlSendData (phost, phost->Control.buff, phost->Control.length , phost->Control.pipe_out, 1); - phost->Control.timer = phost->Timer; phost->Control.state = CTRL_DATA_OUT_WAIT; break; case CTRL_DATA_OUT_WAIT: - - URB_Status = USBH_LL_GetURBState(phost , phost->Control.pipe_out); + URB_Status = USBH_LL_GetURBState(phost, phost->Control.pipe_out); if (URB_Status == USBH_URB_DONE) { /* If the Setup Pkt is sent successful, then change the state */ phost->Control.state = CTRL_STATUS_IN; -#if (USBH_USE_OS == 1) - osMessagePut ( phost->os_event, USBH_CONTROL_EVENT, 0); -#endif } /* handle error cases */ else if (URB_Status == USBH_URB_STALL) { - /* In stall case, return to previous machine state*/ - phost->Control.state = CTRL_STALLED; - status = USBH_NOT_SUPPORTED; -#if (USBH_USE_OS == 1) - osMessagePut ( phost->os_event, USBH_CONTROL_EVENT, 0); -#endif + //Retry transaction + phost->Control.state = CTRL_ERROR; } else if (URB_Status == USBH_URB_NOTREADY) { /* Nack received from device */ phost->Control.state = CTRL_DATA_OUT; - -#if (USBH_USE_OS == 1) - osMessagePut ( phost->os_event, USBH_CONTROL_EVENT, 0); -#endif } else if (URB_Status == USBH_URB_ERROR) { /* device error */ phost->Control.state = CTRL_ERROR; status = USBH_FAIL; - -#if (USBH_USE_OS == 1) - osMessagePut ( phost->os_event, USBH_CONTROL_EVENT, 0); -#endif - } + } + + if ((int32_t)(phost->Timer - phost->Control.timer) >= USBH_CTRL_TRANSACTION_TIMEOUT_MS) + { + phost->Control.state = CTRL_ERROR; + } break; case CTRL_STATUS_IN: /* Send 0 bytes out packet */ + phost->Control.timer = phost->Timer; USBH_CtlReceiveData (phost, 0, 0, phost->Control.pipe_in); - phost->Control.timer = phost->Timer; phost->Control.state = CTRL_STATUS_IN_WAIT; - break; case CTRL_STATUS_IN_WAIT: - URB_Status = USBH_LL_GetURBState(phost , phost->Control.pipe_in); if ( URB_Status == USBH_URB_DONE) { /* Control transfers completed, Exit the State Machine */ phost->Control.state = CTRL_COMPLETE; status = USBH_OK; -#if (USBH_USE_OS == 1) - osMessagePut ( phost->os_event, USBH_CONTROL_EVENT, 0); -#endif } else if (URB_Status == USBH_URB_ERROR) { phost->Control.state = CTRL_ERROR; -#if (USBH_USE_OS == 1) - osMessagePut ( phost->os_event, USBH_CONTROL_EVENT, 0); -#endif } else if(URB_Status == USBH_URB_STALL) { - /* Control transfers completed, Exit the State Machine */ - status = USBH_NOT_SUPPORTED; - -#if (USBH_USE_OS == 1) - osMessagePut ( phost->os_event, USBH_CONTROL_EVENT, 0); -#endif + //Retry transaction + phost->Control.state = CTRL_ERROR; + } + + if ((int32_t)(phost->Timer - phost->Control.timer) >= USBH_CTRL_TRANSACTION_TIMEOUT_MS) + { + phost->Control.state = CTRL_ERROR; } break; case CTRL_STATUS_OUT: + phost->Control.timer = phost->Timer; USBH_CtlSendData (phost, 0, 0, phost->Control.pipe_out, 1); - phost->Control.timer = phost->Timer; phost->Control.state = CTRL_STATUS_OUT_WAIT; break; case CTRL_STATUS_OUT_WAIT: - URB_Status = USBH_LL_GetURBState(phost , phost->Control.pipe_out); if (URB_Status == USBH_URB_DONE) { status = USBH_OK; - phost->Control.state = CTRL_COMPLETE; - -#if (USBH_USE_OS == 1) - osMessagePut ( phost->os_event, USBH_CONTROL_EVENT, 0); -#endif + phost->Control.state = CTRL_COMPLETE; } else if (URB_Status == USBH_URB_NOTREADY) { phost->Control.state = CTRL_STATUS_OUT; - -#if (USBH_USE_OS == 1) - osMessagePut ( phost->os_event, USBH_CONTROL_EVENT, 0); -#endif } else if (URB_Status == USBH_URB_ERROR) { - phost->Control.state = CTRL_ERROR; - -#if (USBH_USE_OS == 1) - osMessagePut ( phost->os_event, USBH_CONTROL_EVENT, 0); -#endif + phost->Control.state = CTRL_ERROR; + } + + if ((int32_t)(phost->Timer - phost->Control.timer) >= USBH_CTRL_TRANSACTION_TIMEOUT_MS) + { + phost->Control.state = CTRL_ERROR; } break; diff --git a/Downstream/Src/downstream_statemachine.c b/Downstream/Src/downstream_statemachine.c index 347c415..0a65f83 100644 --- a/Downstream/Src/downstream_statemachine.c +++ b/Downstream/Src/downstream_statemachine.c @@ -201,12 +201,6 @@ void Downstream_HostUserCallback(USBH_HandleTypeDef *phost, uint8_t id) return; } - //Called from main() - if (id == HOST_USER_UNRECOVERED_ERROR) - { - DOWNSTREAM_STATEMACHINE_FREAKOUT; - return; - } //Called from main() if (id == HOST_USER_CLASS_ACTIVE) @@ -263,8 +257,10 @@ void Downstream_HostUserCallback(USBH_HandleTypeDef *phost, uint8_t id) return; } + //Called from main(): - if (id == HOST_USER_CLASS_FAILED) + if ((id == HOST_USER_CLASS_FAILED) || + (id == HOST_USER_UNRECOVERED_ERROR)) //Probably due to a crappy device that won't enumerate! { //Unsupported device classes will cause a slow fault flash. //This is distinct from the fast freakout flash caused by internal errors or attacks. @@ -273,5 +269,6 @@ void Downstream_HostUserCallback(USBH_HandleTypeDef *phost, uint8_t id) DownstreamState = STATE_ERROR; return; } + } diff --git a/Downstream/Src/usbh_config.c b/Downstream/Src/usbh_config.c index af812dc..439da85 100644 --- a/Downstream/Src/usbh_config.c +++ b/Downstream/Src/usbh_config.c @@ -85,7 +85,7 @@ void HAL_HCD_MspDeInit(HCD_HandleTypeDef* hhcd) PA11 ------> USB_OTG_FS_DM PA12 ------> USB_OTG_FS_DP */ - HAL_GPIO_DeInit(GPIOA, GPIO_PIN_11|GPIO_PIN_12); + //HAL_GPIO_DeInit(GPIOA, GPIO_PIN_11|GPIO_PIN_12); /* Peripheral interrupt Deinit*/ HAL_NVIC_DisableIRQ(OTG_FS_IRQn);