diff --git a/lib/pbio/drv/usb/usb.c b/lib/pbio/drv/usb/usb.c index fda7e63fd..52b93417c 100644 --- a/lib/pbio/drv/usb/usb.c +++ b/lib/pbio/drv/usb/usb.c @@ -294,14 +294,14 @@ static pbio_error_t pbdrv_usb_process_thread(pbio_os_state_t *state, void *conte pbdrv_usb_respond_soon = false; // Send the response. - PBIO_OS_AWAIT(state, &sub, err = pbdrv_usb_tx_response(&sub, error_code)); + PBIO_OS_AWAIT(state, &sub, err = pbdrv_usb_tx_response(&sub, error_code, pbdrv_usb_process.request == PBIO_OS_PROCESS_REQUEST_TYPE_CANCEL)); if (err != PBIO_SUCCESS) { pbdrv_usb_reset_state(); PBIO_OS_AWAIT(state, &sub, pbdrv_usb_tx_reset(&sub)); } } else if (pbdrv_usb_connection_is_active() && update_and_get_event_buffer(¬i_buf, ¬i_size)) { // Send out pending event if any. - PBIO_OS_AWAIT(state, &sub, err = pbdrv_usb_tx_event(&sub, noti_buf, *noti_size)); + PBIO_OS_AWAIT(state, &sub, err = pbdrv_usb_tx_event(&sub, noti_buf, *noti_size, pbdrv_usb_process.request == PBIO_OS_PROCESS_REQUEST_TYPE_CANCEL)); *noti_size = 0; if (err != PBIO_SUCCESS) { pbdrv_usb_reset_state(); diff --git a/lib/pbio/drv/usb/usb.h b/lib/pbio/drv/usb/usb.h index 81a4863b5..1bf67a440 100644 --- a/lib/pbio/drv/usb/usb.h +++ b/lib/pbio/drv/usb/usb.h @@ -51,7 +51,7 @@ uint32_t pbdrv_usb_get_data_and_start_receive(uint8_t *data); /** * Sends and awaits event message from hub to host via the Pybricks USB interface OUT endpoint. * - * Driver-specific implementation. Must return within ::PBDRV_USB_TRANSMIT_TIMEOUT. + * Driver-specific implementation. Must support being canceled via @p cancel. * * The USB process ensures that only one call is made at once. * @@ -60,31 +60,33 @@ uint32_t pbdrv_usb_get_data_and_start_receive(uint8_t *data); * @param [in] state Protothread state. * @param [in] data Data to send. * @param [in] size Data size. + * @param [in] cancel If true, stop waiting for completion and return error. * @return ::PBIO_SUCCESS on completion. * ::PBIO_ERROR_INVALID_OP if there is no connection. * ::PBIO_ERROR_AGAIN while awaiting. * ::PBIO_ERROR_BUSY if this operation is already ongoing. * ::PBIO_ERROR_INVALID_ARG if @p size is too large. - * ::PBIO_ERROR_TIMEDOUT if the operation was started but could not complete. + * ::PBIO_ERROR_CANCELED if the operation was canceled. */ -pbio_error_t pbdrv_usb_tx_event(pbio_os_state_t *state, const uint8_t *data, uint32_t size); +pbio_error_t pbdrv_usb_tx_event(pbio_os_state_t *state, const uint8_t *data, uint32_t size, bool cancel); /** * Sends and awaits response to an earlier incoming message. * - * Driver-specific implementation. Must return within ::PBDRV_USB_TRANSMIT_TIMEOUT. + * Driver-specific implementation. Must support being canceled via @p cancel. * * The USB process ensures that only one call is made at once. * * @param [in] state Protothread state. * @param [in] code Error code to send. + * @param [in] cancel If true, stop waiting for completion and return error. * @return ::PBIO_SUCCESS on completion. * ::PBIO_ERROR_INVALID_OP if there is no connection. * ::PBIO_ERROR_AGAIN while awaiting. * ::PBIO_ERROR_BUSY if this operation is already ongoing. - * ::PBIO_ERROR_TIMEDOUT if the operation was started but could not complete. + * ::PBIO_ERROR_CANCELED if the operation was canceled. */ -pbio_error_t pbdrv_usb_tx_response(pbio_os_state_t *state, pbio_pybricks_error_t code); +pbio_error_t pbdrv_usb_tx_response(pbio_os_state_t *state, pbio_pybricks_error_t code, bool cancel); /** * Resets the driver transmission state. diff --git a/lib/pbio/drv/usb/usb_ev3.c b/lib/pbio/drv/usb/usb_ev3.c index 868c64531..85c7d8318 100644 --- a/lib/pbio/drv/usb/usb_ev3.c +++ b/lib/pbio/drv/usb/usb_ev3.c @@ -1023,9 +1023,7 @@ pbio_error_t pbdrv_usb_tx_reset(pbio_os_state_t *state) { PBIO_OS_ASYNC_END(PBIO_SUCCESS); } -pbio_error_t pbdrv_usb_tx_event(pbio_os_state_t *state, const uint8_t *data, uint32_t size) { - - static pbio_os_timer_t timer; +pbio_error_t pbdrv_usb_tx_event(pbio_os_state_t *state, const uint8_t *data, uint32_t size, bool cancel) { PBIO_OS_ASYNC_BEGIN(state); @@ -1034,28 +1032,20 @@ pbio_error_t pbdrv_usb_tx_event(pbio_os_state_t *state, const uint8_t *data, uin } transmitting = true; - pbio_os_timer_set(&timer, PBDRV_USB_TRANSMIT_TIMEOUT); // Transmit event. pbdrv_cache_prepare_before_dma(data, size); usb_setup_tx_dma_desc(CPPI_DESC_TX_PYBRICKS_EVENT, (uint8_t *)data, size); - PBIO_OS_AWAIT_UNTIL(state, !transmitting || pbio_os_timer_is_expired(&timer)); - - if (pbio_os_timer_is_expired(&timer)) { - // Transmission has taken too long, so reset the state to allow - // new transmissions. This can happen if the host stops reading - // data for some reason. This need some time to complete, so delegate - // the reset back to the process. - return PBIO_ERROR_TIMEDOUT; + PBIO_OS_AWAIT_UNTIL(state, !transmitting || cancel); + if (transmitting && cancel) { + return PBIO_ERROR_CANCELED; } PBIO_OS_ASYNC_END(PBIO_SUCCESS); } -pbio_error_t pbdrv_usb_tx_response(pbio_os_state_t *state, pbio_pybricks_error_t code) { - - static pbio_os_timer_t timer; +pbio_error_t pbdrv_usb_tx_response(pbio_os_state_t *state, pbio_pybricks_error_t code, bool cancel) { static uint8_t ep1_tx_response_buf[1 + sizeof(uint32_t)] __aligned(4) = { PBIO_PYBRICKS_IN_EP_MSG_RESPONSE }; @@ -1066,7 +1056,6 @@ pbio_error_t pbdrv_usb_tx_response(pbio_os_state_t *state, pbio_pybricks_error_t } transmitting = true; - pbio_os_timer_set(&timer, PBDRV_USB_TRANSMIT_TIMEOUT); // Response is just the error code. pbio_set_uint32_le(&ep1_tx_response_buf[1], code); @@ -1076,9 +1065,9 @@ pbio_error_t pbdrv_usb_tx_response(pbio_os_state_t *state, pbio_pybricks_error_t usb_setup_tx_dma_desc(CPPI_DESC_TX_RESPONSE, ep1_tx_response_buf, sizeof(ep1_tx_response_buf)); // Wait until complete or trigger reset on timeout. - PBIO_OS_AWAIT_UNTIL(state, !transmitting || pbio_os_timer_is_expired(&timer)); - if (pbio_os_timer_is_expired(&timer)) { - return PBIO_ERROR_TIMEDOUT; + PBIO_OS_AWAIT_UNTIL(state, !transmitting || cancel); + if (transmitting && cancel) { + return PBIO_ERROR_CANCELED; } PBIO_OS_ASYNC_END(PBIO_SUCCESS); diff --git a/lib/pbio/drv/usb/usb_nxt.c b/lib/pbio/drv/usb/usb_nxt.c index 6cfe22dfa..b9678900f 100644 --- a/lib/pbio/drv/usb/usb_nxt.c +++ b/lib/pbio/drv/usb/usb_nxt.c @@ -853,9 +853,7 @@ pbdrv_usb_bcd_t pbdrv_usb_get_bcd(void) { return PBDRV_USB_BCD_NONE; } -pbio_error_t pbdrv_usb_tx_event(pbio_os_state_t *state, const uint8_t *data, uint32_t size) { - - static pbio_os_timer_t timer; +pbio_error_t pbdrv_usb_tx_event(pbio_os_state_t *state, const uint8_t *data, uint32_t size, bool cancel) { PBIO_OS_ASYNC_BEGIN(state); @@ -864,20 +862,17 @@ pbio_error_t pbdrv_usb_tx_event(pbio_os_state_t *state, const uint8_t *data, uin // return PBIO_ERROR_BUSY; // } - pbio_os_timer_set(&timer, PBDRV_USB_TRANSMIT_TIMEOUT); pbdrv_usb_nxt_write_data(2, data, size); - PBIO_OS_AWAIT_UNTIL(state, pbdrv_usb_nxt_state.status == USB_READY || pbio_os_timer_is_expired(&timer)); - if (pbio_os_timer_is_expired(&timer)) { - return PBIO_ERROR_TIMEDOUT; + PBIO_OS_AWAIT_UNTIL(state, pbdrv_usb_nxt_state.status == USB_READY || cancel); + if (pbdrv_usb_nxt_state.status != USB_READY && cancel) { + return PBIO_ERROR_CANCELED; } PBIO_OS_ASYNC_END(PBIO_SUCCESS); } -pbio_error_t pbdrv_usb_tx_response(pbio_os_state_t *state, pbio_pybricks_error_t code) { - - static pbio_os_timer_t timer; +pbio_error_t pbdrv_usb_tx_response(pbio_os_state_t *state, pbio_pybricks_error_t code, bool cancel) { static uint8_t usb_response_buf[PBIO_PYBRICKS_USB_MESSAGE_SIZE(sizeof(uint32_t))] __aligned(4) = { PBIO_PYBRICKS_IN_EP_MSG_RESPONSE }; @@ -888,13 +883,12 @@ pbio_error_t pbdrv_usb_tx_response(pbio_os_state_t *state, pbio_pybricks_error_t // return PBIO_ERROR_BUSY; // } - pbio_os_timer_set(&timer, PBDRV_USB_TRANSMIT_TIMEOUT); pbio_set_uint32_le(&usb_response_buf[1], code); pbdrv_usb_nxt_write_data(2, usb_response_buf, sizeof(usb_response_buf)); - PBIO_OS_AWAIT_UNTIL(state, pbdrv_usb_nxt_state.status == USB_READY || pbio_os_timer_is_expired(&timer)); - if (pbio_os_timer_is_expired(&timer)) { - return PBIO_ERROR_TIMEDOUT; + PBIO_OS_AWAIT_UNTIL(state, pbdrv_usb_nxt_state.status == USB_READY || cancel); + if (pbdrv_usb_nxt_state.status != USB_READY && cancel) { + return PBIO_ERROR_CANCELED; } PBIO_OS_ASYNC_END(PBIO_SUCCESS); diff --git a/lib/pbio/drv/usb/usb_simulation.c b/lib/pbio/drv/usb/usb_simulation.c index cc2b2a466..e7f43072b 100644 --- a/lib/pbio/drv/usb/usb_simulation.c +++ b/lib/pbio/drv/usb/usb_simulation.c @@ -29,7 +29,7 @@ pbdrv_usb_bcd_t pbdrv_usb_get_bcd(void) { return PBDRV_USB_BCD_NONE; } -pbio_error_t pbdrv_usb_tx_event(pbio_os_state_t *state, const uint8_t *data, uint32_t size) { +pbio_error_t pbdrv_usb_tx_event(pbio_os_state_t *state, const uint8_t *data, uint32_t size, bool cancel) { static pbio_os_timer_t timer; @@ -53,7 +53,7 @@ pbio_error_t pbdrv_usb_tx_event(pbio_os_state_t *state, const uint8_t *data, uin PBIO_OS_ASYNC_END(PBIO_SUCCESS); } -pbio_error_t pbdrv_usb_tx_response(pbio_os_state_t *state, pbio_pybricks_error_t code) { +pbio_error_t pbdrv_usb_tx_response(pbio_os_state_t *state, pbio_pybricks_error_t code, bool cancel) { static pbio_os_timer_t timer; diff --git a/lib/pbio/drv/usb/usb_simulation_pico.c b/lib/pbio/drv/usb/usb_simulation_pico.c index 0ec579501..d4703f847 100644 --- a/lib/pbio/drv/usb/usb_simulation_pico.c +++ b/lib/pbio/drv/usb/usb_simulation_pico.c @@ -38,7 +38,7 @@ pbdrv_usb_bcd_t pbdrv_usb_get_bcd(void) { return PBDRV_USB_BCD_NONE; } -pbio_error_t pbdrv_usb_tx_event(pbio_os_state_t *state, const uint8_t *data, uint32_t size) { +pbio_error_t pbdrv_usb_tx_event(pbio_os_state_t *state, const uint8_t *data, uint32_t size, bool cancel) { PBIO_OS_ASYNC_BEGIN(state); @@ -54,7 +54,10 @@ pbio_error_t pbdrv_usb_tx_event(pbio_os_state_t *state, const uint8_t *data, uin pbdrv_usb_simulation_tx_ready = false; // Enable TX interrupt to be notified when ready. hw_set_bits(&uart_get_hw(uart_default)->imsc, 1 << UART_UARTIMSC_TXIM_LSB); - PBIO_OS_AWAIT_UNTIL(state, pbdrv_usb_simulation_tx_ready); + PBIO_OS_AWAIT_UNTIL(state, pbdrv_usb_simulation_tx_ready || cancel); + if (!pbdrv_usb_simulation_tx_ready && cancel) { + return PBIO_ERROR_CANCELED; + } } uart_get_hw(uart_default)->dr = data[i]; @@ -63,7 +66,7 @@ pbio_error_t pbdrv_usb_tx_event(pbio_os_state_t *state, const uint8_t *data, uin PBIO_OS_ASYNC_END(PBIO_SUCCESS); } -pbio_error_t pbdrv_usb_tx_response(pbio_os_state_t *state, pbio_pybricks_error_t code) { +pbio_error_t pbdrv_usb_tx_response(pbio_os_state_t *state, pbio_pybricks_error_t code, bool cancel) { PBIO_OS_ASYNC_BEGIN(state); diff --git a/lib/pbio/drv/usb/usb_stm32.c b/lib/pbio/drv/usb/usb_stm32.c index b474d3438..d045ecc71 100644 --- a/lib/pbio/drv/usb/usb_stm32.c +++ b/lib/pbio/drv/usb/usb_stm32.c @@ -292,48 +292,50 @@ pbio_error_t pbdrv_usb_tx_reset(pbio_os_state_t *state) { return PBIO_SUCCESS; } -pbio_error_t pbdrv_usb_tx_event(pbio_os_state_t *state, const uint8_t *data, uint32_t size) { - - static pbio_os_timer_t timer; +pbio_error_t pbdrv_usb_tx_event(pbio_os_state_t *state, const uint8_t *data, uint32_t size, bool cancel) { PBIO_OS_ASYNC_BEGIN(state); + if (cancel) { + return PBIO_ERROR_CANCELED; + } + if (transmitting) { return PBIO_ERROR_BUSY; } transmitting = true; - pbio_os_timer_set(&timer, PBDRV_USB_TRANSMIT_TIMEOUT); USBD_Pybricks_TransmitPacket(&husbd, (uint8_t *)data, size); - PBIO_OS_AWAIT_UNTIL(state, !transmitting || pbio_os_timer_is_expired(&timer)); + PBIO_OS_AWAIT_UNTIL(state, !transmitting || cancel); - if (pbio_os_timer_is_expired(&timer)) { - return PBIO_ERROR_TIMEDOUT; + if (transmitting && cancel) { + return PBIO_ERROR_CANCELED; } PBIO_OS_ASYNC_END(PBIO_SUCCESS); } -pbio_error_t pbdrv_usb_tx_response(pbio_os_state_t *state, pbio_pybricks_error_t code) { - - static pbio_os_timer_t timer; +pbio_error_t pbdrv_usb_tx_response(pbio_os_state_t *state, pbio_pybricks_error_t code, bool cancel) { PBIO_OS_ASYNC_BEGIN(state); + if (cancel) { + return PBIO_ERROR_CANCELED; + } + if (transmitting) { return PBIO_ERROR_BUSY; } transmitting = true; - pbio_os_timer_set(&timer, PBDRV_USB_TRANSMIT_TIMEOUT); pbio_set_uint32_le(&usb_response_buf[1], code); USBD_Pybricks_TransmitPacket(&husbd, usb_response_buf, sizeof(usb_response_buf)); - PBIO_OS_AWAIT_UNTIL(state, !transmitting || pbio_os_timer_is_expired(&timer)); - if (pbio_os_timer_is_expired(&timer)) { - return PBIO_ERROR_TIMEDOUT; + PBIO_OS_AWAIT_UNTIL(state, !transmitting || cancel); + if (transmitting && cancel) { + return PBIO_ERROR_CANCELED; } PBIO_OS_ASYNC_END(PBIO_SUCCESS); diff --git a/lib/pbio/platform/prime_hub/pbdrvconfig.h b/lib/pbio/platform/prime_hub/pbdrvconfig.h index f29a1532d..ea16ea21e 100644 --- a/lib/pbio/platform/prime_hub/pbdrvconfig.h +++ b/lib/pbio/platform/prime_hub/pbdrvconfig.h @@ -128,7 +128,7 @@ #define PBDRV_CONFIG_USB_PROD_STR LEGO_USB_PROD_STR_TECHNIC_LARGE_HUB " + Pybricks" #define PBDRV_CONFIG_USB_STM32F4 (1) #define PBDRV_CONFIG_USB_STM32F4_HUB_VARIANT_ADDR 0x08007d80 -#define PBDRV_CONFIG_USB_CHARGE_ONLY (1) +#define PBDRV_CONFIG_USB_CHARGE_ONLY (0) #define PBDRV_CONFIG_STACK (1) #define PBDRV_CONFIG_STACK_EMBEDDED (1)