@@ -436,49 +436,46 @@ async def write_encrypted_payload(self, ctrl_byte: int, payload: AnyBytes) -> No
436436
437437 header = PacketHeader (ctrl_byte , self .get_channel_id_int (), payload_len )
438438
439+ ack_latency_ms = self .channel_cache .get_int (CHANNEL_ACK_LATENCY_MS ) or 0
440+
441+ # ACK is needed before sending more data
442+ ABP .set_sending_allowed (self .channel_cache , False )
443+
444+ # allows preempting this channel, if another channel becomes active
445+ self .last_write_ms = utime .ticks_ms ()
446+
439447 async def _write_loop () -> None :
440448 """Send the payload and wait for an ACK with retransmissions."""
449+ from trezor .loop import sleep
441450
442- ack_latency_ms = self .channel_cache .get_int (CHANNEL_ACK_LATENCY_MS ) or 0
443451 if __debug__ :
444452 self ._log (f"Sending { len (payload )} bytes, latency: { ack_latency_ms } ms" )
445453
446- # ACK is needed before sending more data
447- ABP .set_sending_allowed (self .channel_cache , False )
448-
449- # allows preempting this channel, if another channel becomes active
450- self .last_write_ms = utime .ticks_ms ()
451-
452454 for i in range (_MAX_RETRANSMISSION_COUNT ):
453455 await self ._write_payload_once (header , payload )
454-
455456 # Channel's estimated latency + a variable delay (from 200ms till ~3.52s)
456457 timeout_ms = ack_latency_ms + round (10300 - 1010000 / (100 + i ))
457- try :
458- # wait and return after receiving an ACK, or raise in case of an unexpected message.
459- await self .recv_payload (
460- expected_ctrl_byte = None , timeout_ms = timeout_ms
461- )
462- except Timeout :
463- if __debug__ :
464- log .warning (__name__ , "Retransmit after %d ms" , timeout_ms )
465- continue
466-
467- ack_latency_ms = utime .ticks_diff (utime .ticks_ms (), self .last_write_ms )
468- # Limit estimated latency to avoid integer overflows and too long delays
469- ack_latency_ms = max (0 , min (800 , ack_latency_ms ))
470- self .channel_cache .set_int (CHANNEL_ACK_LATENCY_MS , ack_latency_ms )
471-
472- # `ABP.set_sending_allowed()` will be called after a valid ACK
473- if ABP .is_sending_allowed (self .channel_cache ):
474- return
458+ await sleep (timeout_ms )
459+ if __debug__ :
460+ log .warning (__name__ , "Retransmit after %d ms" , timeout_ms )
475461
476462 # restart event loop due to unresponsive channel
477463 raise Timeout ("THP retransmission timeout" )
478464
465+ async def _wait_for_ack () -> None :
466+ while not ABP .is_sending_allowed (self .channel_cache ):
467+ # `ABP.set_sending_allowed()` will be called after a valid ACK
468+ await self .recv_payload (expected_ctrl_byte = None )
469+
470+ # wait and return after receiving an ACK, or raise in case of an unexpected message / retransmission timeout.
479471 try :
480- return await _write_loop ()
472+ await race ( _wait_for_ack (), _write_loop () )
481473 finally :
474+ ack_latency_ms = utime .ticks_diff (utime .ticks_ms (), self .last_write_ms )
475+ # Limit estimated latency to avoid integer overflows and too long delays
476+ ack_latency_ms = max (0 , min (800 , ack_latency_ms ))
477+ self .channel_cache .set_int (CHANNEL_ACK_LATENCY_MS , ack_latency_ms )
478+
482479 # Make sure to use the next `seq_bit` for the next payload
483480 ABP .set_send_seq_bit_to_opposite (self .channel_cache )
484481
0 commit comments