Change in simtrace2[master]: card_emu: Fix USART timer, particularly in re-start situations
laforge has submitted this change. ( https://gerrit.osmocom.org/c/simtrace2/+/23643 ) Change subject: card_emu: Fix USART timer, particularly in re-start situations .. card_emu: Fix USART timer, particularly in re-start situations The existing code started the timer once (and expired once) but didn't properly handle re-starting of the timer. Neither did it handle the 'half time expiration' case. If we want to call a function after half the WT expiring, we must of course program the hardware for half the timeout, and not the full timeout... Change-Id: Ia999d97f835c27597fcd1cf7ac78bac0ab9c98c1 Related: OS#1704 --- M firmware/libcommon/source/mode_cardemu.c 1 file changed, 40 insertions(+), 12 deletions(-) Approvals: laforge: Looks good to me, approved Jenkins Builder: Verified diff --git a/firmware/libcommon/source/mode_cardemu.c b/firmware/libcommon/source/mode_cardemu.c index 8531eb5..14f62a6 100644 --- a/firmware/libcommon/source/mode_cardemu.c +++ b/firmware/libcommon/source/mode_cardemu.c @@ -212,6 +212,23 @@ return 1; } +static uint16_t compute_next_timeout(struct cardem_inst *ci) +{ + uint32_t want_to_expire; + + if (ci->wt.total == 0) + return 0; + + if (!ci->wt.half_time_notified) { + /* we need to make sure to expire after half the total waiting time */ + OSMO_ASSERT(ci->wt.remaining > (ci->wt.total / 2)); + want_to_expire = ci->wt.remaining - (ci->wt.total / 2); + } else + want_to_expire = ci->wt.remaining; + TRACE_INFO("want_to_expire=%u (total=%u, remaining=%u)\r\n", want_to_expire, ci->wt.total, ci->wt.remaining); + /* if value exceeds the USART TO range, use the maximum possible value for one round */ + return OSMO_MIN(want_to_expire, 0x); +} /*! common handler if interrupt was received. * \param[in] inst_num Instance number, range 0..1 (some boards only '0' permitted) */ @@ -254,6 +271,9 @@ * how many etu have expired since we last sent a byte. See section * 33.7.3.11 "Receiver Time-out" of the SAM3S8 Data Sheet */ if (csr & US_CSR_TIMEOUT) { + /* clear timeout flag (and stop timeout until next character is received) */ + usart->US_CR |= US_CR_STTTO; + /* RX has been inactive for some time */ if (ci->wt.remaining <= (usart->US_RTOR & 0x)) { /* waiting time is over; will stop the timer */ @@ -266,17 +286,26 @@ if (ci->wt.remaining == 0) { /* let the FSM know that WT has expired */ card_emu_wtime_expired(ci->ch); - } else if (ci->wt.remaining <= ci->wt.total / 2 && !ci->wt.half_time_notified) { - /* let the FS know that half of the WT has expired */ - card_emu_wtime_half_expired(ci->ch); - ci->wt.half_time_notified = true; + /* don't automatically re-start in this case */ + } else { + bool half_time_just_reached = false; + + if (ci->wt.remaining <= ci->wt.total / 2 && !ci->wt.half_time_notified) { + ci->wt.half_time_notified = true; + /* don't immediately call card_emu_wtime_half_expired(), as that +* in turn may calls card_emu_uart_update_wt() which will change +* the timeout but would be overridden 4 lines below */ + half_time_just_reached = true; + } + + /* update the counter no matter if we reached half time or not */ + usart->US_RTOR = compute_next_timeout(ci); + /* restart the counter (if wt is 0, the timeout is not started) */ + usart->US_CR |= US_CR_RETTO; + + if (half_time_just_reached) + card_emu_wtime_half_expired(ci->ch); } - /* if value exceeds the USART TO range, use the maximum for now */ - usart->US_RTOR = OSMO_MIN(ci->wt.remaining, 0x); - /* clear timeout flag (and stop timeout until next character is received) */ - usart->US_CR |= US_CR_STTTO; - /* restart the counter (it wt is 0, the timeout is not started) */ - usart->US_CR |= US_CR_RETTO; } } @@ -336,8 +365,7 @@ /* FIXME: guard against race with interrupt handler */ ci->wt.remaining = ci->wt.total; ci->wt.half_time_notified = false; - /* if value exceeds the USART TO range, use the maximum for now */ - usart->US_RTOR = OSMO_MIN(ci->wt.remaining, 0x); + usart->US_RTOR = compute_next_timeout(ci);
Change in simtrace2[master]: card_emu: Fix USART timer, particularly in re-start situations
laforge has posted comments on this change. ( https://gerrit.osmocom.org/c/simtrace2/+/23643 ) Change subject: card_emu: Fix USART timer, particularly in re-start situations .. Patch Set 2: Code-Review+2 -- To view, visit https://gerrit.osmocom.org/c/simtrace2/+/23643 To unsubscribe, or for help writing mail filters, visit https://gerrit.osmocom.org/settings Gerrit-Project: simtrace2 Gerrit-Branch: master Gerrit-Change-Id: Ia999d97f835c27597fcd1cf7ac78bac0ab9c98c1 Gerrit-Change-Number: 23643 Gerrit-PatchSet: 2 Gerrit-Owner: laforge Gerrit-Reviewer: Hoernchen Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: laforge Gerrit-Reviewer: tsaitgaist Gerrit-Comment-Date: Thu, 08 Apr 2021 21:28:30 + Gerrit-HasComments: No Gerrit-Has-Labels: Yes Gerrit-MessageType: comment
Change in simtrace2[master]: card_emu: Fix USART timer, particularly in re-start situations
Hello Jenkins Builder, I'd like you to reexamine a change. Please visit https://gerrit.osmocom.org/c/simtrace2/+/23643 to look at the new patch set (#2). Change subject: card_emu: Fix USART timer, particularly in re-start situations .. card_emu: Fix USART timer, particularly in re-start situations The existing code started the timer once (and expired once) but didn't properly handle re-starting of the timer. Neither did it handle the 'half time expiration' case. If we want to call a function after half the WT expiring, we must of course program the hardware for half the timeout, and not the full timeout... Change-Id: Ia999d97f835c27597fcd1cf7ac78bac0ab9c98c1 Related: OS#1704 --- M firmware/libcommon/source/mode_cardemu.c 1 file changed, 40 insertions(+), 12 deletions(-) git pull ssh://gerrit.osmocom.org:29418/simtrace2 refs/changes/43/23643/2 -- To view, visit https://gerrit.osmocom.org/c/simtrace2/+/23643 To unsubscribe, or for help writing mail filters, visit https://gerrit.osmocom.org/settings Gerrit-Project: simtrace2 Gerrit-Branch: master Gerrit-Change-Id: Ia999d97f835c27597fcd1cf7ac78bac0ab9c98c1 Gerrit-Change-Number: 23643 Gerrit-PatchSet: 2 Gerrit-Owner: laforge Gerrit-Reviewer: Jenkins Builder Gerrit-MessageType: newpatchset
Change in simtrace2[master]: card_emu: Fix USART timer, particularly in re-start situations
laforge has uploaded this change for review. ( https://gerrit.osmocom.org/c/simtrace2/+/23643 ) Change subject: card_emu: Fix USART timer, particularly in re-start situations .. card_emu: Fix USART timer, particularly in re-start situations The existing code started the timer once (and expired once) but didn't properly handle re-starting of the timer. Neither did it handle the 'half time expiration' case. If we want to call a function after half the WT expiring, we must of course program the hardware for half the timeout, and not the full timeout... Change-Id: Ia999d97f835c27597fcd1cf7ac78bac0ab9c98c1 --- M firmware/libcommon/source/mode_cardemu.c 1 file changed, 40 insertions(+), 12 deletions(-) git pull ssh://gerrit.osmocom.org:29418/simtrace2 refs/changes/43/23643/1 diff --git a/firmware/libcommon/source/mode_cardemu.c b/firmware/libcommon/source/mode_cardemu.c index 8531eb5..14f62a6 100644 --- a/firmware/libcommon/source/mode_cardemu.c +++ b/firmware/libcommon/source/mode_cardemu.c @@ -212,6 +212,23 @@ return 1; } +static uint16_t compute_next_timeout(struct cardem_inst *ci) +{ + uint32_t want_to_expire; + + if (ci->wt.total == 0) + return 0; + + if (!ci->wt.half_time_notified) { + /* we need to make sure to expire after half the total waiting time */ + OSMO_ASSERT(ci->wt.remaining > (ci->wt.total / 2)); + want_to_expire = ci->wt.remaining - (ci->wt.total / 2); + } else + want_to_expire = ci->wt.remaining; + TRACE_INFO("want_to_expire=%u (total=%u, remaining=%u)\r\n", want_to_expire, ci->wt.total, ci->wt.remaining); + /* if value exceeds the USART TO range, use the maximum possible value for one round */ + return OSMO_MIN(want_to_expire, 0x); +} /*! common handler if interrupt was received. * \param[in] inst_num Instance number, range 0..1 (some boards only '0' permitted) */ @@ -254,6 +271,9 @@ * how many etu have expired since we last sent a byte. See section * 33.7.3.11 "Receiver Time-out" of the SAM3S8 Data Sheet */ if (csr & US_CSR_TIMEOUT) { + /* clear timeout flag (and stop timeout until next character is received) */ + usart->US_CR |= US_CR_STTTO; + /* RX has been inactive for some time */ if (ci->wt.remaining <= (usart->US_RTOR & 0x)) { /* waiting time is over; will stop the timer */ @@ -266,17 +286,26 @@ if (ci->wt.remaining == 0) { /* let the FSM know that WT has expired */ card_emu_wtime_expired(ci->ch); - } else if (ci->wt.remaining <= ci->wt.total / 2 && !ci->wt.half_time_notified) { - /* let the FS know that half of the WT has expired */ - card_emu_wtime_half_expired(ci->ch); - ci->wt.half_time_notified = true; + /* don't automatically re-start in this case */ + } else { + bool half_time_just_reached = false; + + if (ci->wt.remaining <= ci->wt.total / 2 && !ci->wt.half_time_notified) { + ci->wt.half_time_notified = true; + /* don't immediately call card_emu_wtime_half_expired(), as that +* in turn may calls card_emu_uart_update_wt() which will change +* the timeout but would be overridden 4 lines below */ + half_time_just_reached = true; + } + + /* update the counter no matter if we reached half time or not */ + usart->US_RTOR = compute_next_timeout(ci); + /* restart the counter (if wt is 0, the timeout is not started) */ + usart->US_CR |= US_CR_RETTO; + + if (half_time_just_reached) + card_emu_wtime_half_expired(ci->ch); } - /* if value exceeds the USART TO range, use the maximum for now */ - usart->US_RTOR = OSMO_MIN(ci->wt.remaining, 0x); - /* clear timeout flag (and stop timeout until next character is received) */ - usart->US_CR |= US_CR_STTTO; - /* restart the counter (it wt is 0, the timeout is not started) */ - usart->US_CR |= US_CR_RETTO; } } @@ -336,8 +365,7 @@ /* FIXME: guard against race with interrupt handler */ ci->wt.remaining = ci->wt.total; ci->wt.half_time_notified = false; - /* if value exceeds the USART TO range, use the maximum for now */ - usart->US_RTOR = OSMO_MIN(ci->wt.remaining, 0x); + usart->US_RTOR = compute_next_timeout(ci); /*