From 2c1de250062713102c5e65dba96aabc884de2cd5 Mon Sep 17 00:00:00 2001 From: lihuanhuan Date: Thu, 15 Jan 2026 16:50:06 +0800 Subject: [PATCH 1/3] feat: add deferred sleep after action cancel. --- core/src/trezor/uart.py | 6 ++++++ core/src/trezor/utils.py | 36 ++++++++++++++++++++++++++++++++ core/src/trezor/wire/__init__.py | 27 ++++++++++++++++++++++++ 3 files changed, 69 insertions(+) diff --git a/core/src/trezor/uart.py b/core/src/trezor/uart.py index 968693cc1..b5c2c9db0 100644 --- a/core/src/trezor/uart.py +++ b/core/src/trezor/uart.py @@ -421,9 +421,14 @@ async def _deal_button_press(value: bytes) -> None: return if res == _PRESS_SHORT: if display.backlight(): + utils.request_sleep_after_cancel() + if utils.is_wire_busy(): + workflow.close_others() + return display.backlight(0) if storage_device.is_initialized(): if utils.is_initialization_processing(): + utils.clear_sleep_after_cancel() return utils.AUTO_POWER_OFF = True utils.RESTART_MAIN_LOOP = True @@ -444,6 +449,7 @@ async def _deal_button_press(value: bytes) -> None: workflow.spawn(utils.internal_reloop()) base.set_homescreen() return + utils.clear_sleep_after_cancel() else: utils.turn_on_lcd_if_possible() diff --git a/core/src/trezor/utils.py b/core/src/trezor/utils.py index 255a077cd..692d51365 100644 --- a/core/src/trezor/utils.py +++ b/core/src/trezor/utils.py @@ -89,6 +89,8 @@ def board_version() -> str: CHARGING = False USB_STATE_CHANGED = False RESTART_MAIN_LOOP = False +_WIRE_BUSY = False +_PENDING_SLEEP_AFTER_CANCEL = False if __debug__: MAX_FP_ATTEMPTS = 50 @@ -200,6 +202,7 @@ def lcd_resume(timeouts_ms: int | None = None) -> bool: async def internal_reloop(): from trezor import loop + clear_sleep_after_cancel() loop.clear() @@ -219,6 +222,39 @@ async def turn_off_lcd(): loop.clear() +def set_wire_busy(is_busy: bool) -> None: + global _WIRE_BUSY + _WIRE_BUSY = is_busy + + +def is_wire_busy() -> bool: + return _WIRE_BUSY + + +def request_sleep_after_cancel() -> None: + global _PENDING_SLEEP_AFTER_CANCEL + _PENDING_SLEEP_AFTER_CANCEL = True + + +def clear_sleep_after_cancel() -> None: + global _PENDING_SLEEP_AFTER_CANCEL + _PENDING_SLEEP_AFTER_CANCEL = False + + +def has_pending_sleep_after_cancel() -> bool: + return _PENDING_SLEEP_AFTER_CANCEL + + +async def sleep_after_action_cancel() -> None: + from apps import base + + if is_initialization_processing(): + await turn_off_lcd() + return + base.lock_device() + await turn_off_lcd() + + def play_dead(): from trezor import io, loop import usb diff --git a/core/src/trezor/wire/__init__.py b/core/src/trezor/wire/__init__.py index 8c974e79f..0fe53eadd 100644 --- a/core/src/trezor/wire/__init__.py +++ b/core/src/trezor/wire/__init__.py @@ -430,6 +430,11 @@ async def _handle_single_message( ) res_msg: protobuf.MessageType | None = None + if use_workflow and utils.has_pending_sleep_after_cancel(): + res_msg = failure(loop.TASK_CLOSED) + await ctx.write(res_msg) + await _handle_pending_sleep_after_cancel(res_msg) + return None # We need to find a handler for this message type. Should not raise. handler = find_handler(ctx.iface, msg.type) # pylint: disable=assignment-from-none @@ -506,6 +511,8 @@ async def _handle_single_message( # perform the write outside the big try-except block, so that usb write # problem bubbles up await ctx.write(res_msg) + if use_workflow: + await _handle_pending_sleep_after_cancel(res_msg) return None @@ -537,6 +544,7 @@ async def handle_session( # wait for a new one coming from the wire. try: msg = await ctx.read_from_wire() + utils.set_wire_busy(True) change_state(is_busy=True) except codec_v1.CodecError as exc: if __debug__: @@ -567,6 +575,7 @@ async def handle_session( utils.unimport_end(modules) if next_msg is None and msg.type not in AVOID_RESTARTING_FOR: + utils.set_wire_busy(False) # Shut down the loop if there is no next message waiting. # Let the session be restarted from `main`. change_state() @@ -580,6 +589,24 @@ async def handle_session( log.exception(__name__, exc) +async def _handle_pending_sleep_after_cancel( + res_msg: protobuf.MessageType | None, +) -> None: + + if not utils.has_pending_sleep_after_cancel(): + return + + try: + if ( + res_msg is not None + and Failure.is_type_of(res_msg) + and res_msg.code == FailureType.ActionCancelled + ): + await utils.sleep_after_action_cancel() + finally: + utils.clear_sleep_after_cancel() + + def _find_handler_placeholder(iface: WireInterface, msg_type: int) -> Handler | None: """Placeholder handler lookup before a proper one is registered.""" return None From c08a3221e433697e450377e386d522475aa3644b Mon Sep 17 00:00:00 2001 From: lihuanhuan Date: Tue, 3 Feb 2026 14:58:20 +0800 Subject: [PATCH 2/3] fix: improve UART DMA RX circular buffer handling. --- core/embed/trezorhal/usart.c | 157 +++++++++++++++++++++-------------- 1 file changed, 94 insertions(+), 63 deletions(-) diff --git a/core/embed/trezorhal/usart.c b/core/embed/trezorhal/usart.c index 91f851003..2221d7359 100644 --- a/core/embed/trezorhal/usart.c +++ b/core/embed/trezorhal/usart.c @@ -22,12 +22,12 @@ static DMA_HandleTypeDef hdma_rx; static bool uart_tx_done = false; -#define UART_PACKET_MAX_LEN 128 +#define UART_PACKET_MAX_LEN 256 static uint8_t dma_uart_rev_buf[UART_PACKET_MAX_LEN] __attribute__((section(".sram3"))); static uint8_t dma_uart_send_buf[UART_PACKET_MAX_LEN] __attribute__((section(".sram3"))); -uint32_t usart_fifo_len = 0; +static uint32_t usart_dma_rx_read_pos = 0; uint8_t uart_data_in[UART_BUF_MAX_LEN]; @@ -103,7 +103,7 @@ void ble_usart_init(void) { hdma_rx.Init.MemInc = DMA_MINC_ENABLE; hdma_rx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE; hdma_rx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE; - hdma_rx.Init.Mode = DMA_NORMAL; + hdma_rx.Init.Mode = DMA_CIRCULAR; hdma_rx.Init.Priority = DMA_PRIORITY_MEDIUM; HAL_DMA_Init(&hdma_rx); @@ -129,6 +129,7 @@ void ble_usart_init(void) { HAL_UART_ReceiverTimeout_Config( huart, (UART_TIMEOUT_MS * 1000) / UART_ONE_BIT_TIME_US); __HAL_UART_ENABLE_IT(huart, UART_IT_RTO); + usart_dma_rx_read_pos = 0; HAL_UART_Receive_DMA(huart, dma_uart_rev_buf, sizeof(dma_uart_rev_buf)); } @@ -189,6 +190,7 @@ void ble_usart_irq_ctrl(bool enable) { if (enable) { HAL_NVIC_EnableIRQ(UART4_IRQn); HAL_UART_Abort(huart); + usart_dma_rx_read_pos = 0; HAL_UART_Receive_DMA(huart, dma_uart_rev_buf, sizeof(dma_uart_rev_buf)); } else { HAL_UART_Abort(huart); @@ -206,74 +208,110 @@ uint32_t ble_usart_read(uint8_t *buf, uint32_t lenth) { return len + 3; } -static uint8_t calXor(uint8_t *buf, uint32_t len) { - uint8_t tmp = 0; - uint32_t i; - for (i = 0; i < len; i++) { - tmp ^= buf[i]; +static void usart_rx_dma_process(void) { + uint32_t write_pos = + sizeof(dma_uart_rev_buf) - __HAL_DMA_GET_COUNTER(huart->hdmarx); + if (write_pos == usart_dma_rx_read_pos) { + return; } - return tmp; -} -static void usart_rev_package_dma(uint8_t *buf, uint32_t len) { - if (len < 5) { - return; + uint32_t available_len; + if (write_pos > usart_dma_rx_read_pos) { + available_len = write_pos - usart_dma_rx_read_pos; + } else { + available_len = + sizeof(dma_uart_rev_buf) - usart_dma_rx_read_pos + write_pos; } - uint32_t index = 0; - uint8_t *p_header; - while (len > 0) { - if (buf[index] != 0xA5 || buf[index + 1] != 0x5A) { - index++; - len--; + + uint32_t processed_len = 0; + uint32_t current_read_pos = usart_dma_rx_read_pos; + const uint32_t buf_len = sizeof(dma_uart_rev_buf); + + while (processed_len < available_len) { + uint32_t remaining = available_len - processed_len; + + if (remaining < 2) { + break; + } + + uint8_t b0 = dma_uart_rev_buf[current_read_pos % buf_len]; + uint8_t b1 = dma_uart_rev_buf[(current_read_pos + 1) % buf_len]; + if (b0 != 0xA5 || b1 != 0x5A) { + current_read_pos = (current_read_pos + 1) % buf_len; + processed_len += 1; continue; } - p_header = buf + index; - index += 2; - len -= 2; - if (len < 2) { - return; + + if (remaining < 4) { + break; } - // length include xor byte - uint16_t data_len = (buf[index] << 8) + buf[index + 1]; - index += 2; - len -= 2; - if (len < data_len) { - return; + + uint16_t data_len = + (dma_uart_rev_buf[(current_read_pos + 2) % buf_len] << 8) + + dma_uart_rev_buf[(current_read_pos + 3) % buf_len]; + + // Packet format: [0xA5][0x5A][LH][LL][payload...][XOR] + // data_len = len(payload) + len(XOR) + uint32_t packet_total_len = data_len + 4; // Including header + uint32_t packet_store_len = data_len + 3; // Excluding XOR byte + + // Validate packet length + if (packet_total_len < 5 || packet_total_len > buf_len) { + current_read_pos = (current_read_pos + 1) % buf_len; + processed_len += 1; + continue; } - index += data_len; - len -= data_len; - uint8_t xor = calXor(p_header, data_len + 3); - if (buf[index - 1] != xor) { - return; + if (remaining < packet_total_len) { + break; + } + + uint8_t xor = 0; + uint32_t first_part_len = buf_len - current_read_pos; + if (first_part_len > packet_store_len) { + first_part_len = packet_store_len; + } + uint32_t second_part_len = packet_store_len - first_part_len; + for (uint32_t i = 0; i < first_part_len; i++) { + xor ^= dma_uart_rev_buf[current_read_pos + i]; + } + for (uint32_t i = 0; i < second_part_len; i++) { + xor ^= dma_uart_rev_buf[i]; + } + if (xor != + dma_uart_rev_buf[(current_read_pos + packet_total_len - 1) % buf_len]) { + current_read_pos = (current_read_pos + 1) % buf_len; + processed_len += 1; + continue; } - fifo_write_no_overflow(&uart_fifo_in, p_header, data_len + 3); + + for (uint32_t i = 0; i < first_part_len; i++) { + fifo_put_no_overflow(&uart_fifo_in, + dma_uart_rev_buf[current_read_pos + i]); + } + for (uint32_t i = 0; i < second_part_len; i++) { + fifo_put_no_overflow(&uart_fifo_in, dma_uart_rev_buf[i]); + } + + fifo_lockpos_set(&uart_fifo_in); + + current_read_pos = (current_read_pos + packet_total_len) % buf_len; + processed_len += packet_total_len; } -} -// void UART4_IRQHandler(void) { -// volatile uint8_t data = 0; -// (void)data; -// if (__HAL_UART_GET_FLAG(huart, UART_FLAG_WUF)) { -// __HAL_UART_CLEAR_FLAG(huart, UART_CLEAR_WUF); -// } -// if (__HAL_UART_GET_FLAG(huart, UART_FLAG_ORE) != 0) { -// data = (uint8_t)(huart->Instance->RDR); -// __HAL_UART_CLEAR_FLAG(huart, UART_CLEAR_OREF); -// } -// if (__HAL_UART_GET_FLAG(huart, UART_FLAG_RXFNE) != 0) { -// memset(dma_uart_rev_buf, 0x00, sizeof(dma_uart_rev_buf)); -// usart_rev_package(dma_uart_rev_buf); -// } -// } + usart_dma_rx_read_pos = current_read_pos; +} void UARTx_DMA_TX_IRQHandler(void) { HAL_DMA_IRQHandler(huart->hdmatx); } void UARTx_DMA_RX_IRQHandler(void) { HAL_DMA_IRQHandler(huart->hdmarx); } void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart) { - usart_rev_package_dma(dma_uart_rev_buf, sizeof(dma_uart_rev_buf)); - HAL_UART_Receive_DMA(huart, dma_uart_rev_buf, sizeof(dma_uart_rev_buf)); + usart_rx_dma_process(); +} + +void HAL_UART_RxHalfCpltCallback(UART_HandleTypeDef *huart) { + usart_rx_dma_process(); } void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart) { uart_tx_done = true; } @@ -284,16 +322,9 @@ void UART4_IRQHandler(void) { } if (__HAL_UART_GET_FLAG(huart, UART_FLAG_RTOF)) { __HAL_UART_CLEAR_FLAG(huart, UART_CLEAR_RTOF); - HAL_UART_Abort(huart); - usart_fifo_len = - sizeof(dma_uart_rev_buf) - __HAL_DMA_GET_COUNTER(huart->hdmarx); - if (usart_fifo_len > 0) { - usart_rev_package_dma(dma_uart_rev_buf, usart_fifo_len); - } - HAL_UART_Receive_DMA(huart, dma_uart_rev_buf, sizeof(dma_uart_rev_buf)); - } else { - HAL_UART_IRQHandler(huart); + usart_rx_dma_process(); } + HAL_UART_IRQHandler(huart); } void usart_print(const char *text, int text_len) { From 551a6b31cebc6d389861545874d20729405d26c1 Mon Sep 17 00:00:00 2001 From: lihuanhuan Date: Tue, 3 Feb 2026 14:58:30 +0800 Subject: [PATCH 3/3] chore: update workflow trigger branch to main. --- .github/workflows/build-pro.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build-pro.yml b/.github/workflows/build-pro.yml index b4cae140a..880e1bb48 100644 --- a/.github/workflows/build-pro.yml +++ b/.github/workflows/build-pro.yml @@ -2,7 +2,7 @@ name: "build-pro" on: push: - branches: [master] + branches: [main] workflow_dispatch: jobs: