From a576ed4e3426f3b58b740e2643aee33d07bb0e15 Mon Sep 17 00:00:00 2001 From: MMS Date: Fri, 19 Jul 2024 19:25:12 -0400 Subject: [PATCH 1/3] 7.4.0-rc.3 --- ports/posix-qv/qf_port.c | 58 ++++++++++++++++++++++++++++++++-------- ports/posix-qv/qs_port.c | 8 +++--- ports/posix/qf_port.c | 57 +++++++++++++++++++++++++++++++++------ ports/posix/qs_port.c | 6 ++--- ports/win32-qv/qf_port.c | 3 +-- 5 files changed, 104 insertions(+), 28 deletions(-) diff --git a/ports/posix-qv/qf_port.c b/ports/posix-qv/qf_port.c index 14c850ff..eb9fcc37 100644 --- a/ports/posix-qv/qf_port.c +++ b/ports/posix-qv/qf_port.c @@ -22,7 +22,7 @@ // // //============================================================================ -//! @date Last updated on: 2024-06-11 +//! @date Last updated on: 2024-07-19 //! @version Last updated for: @ref qpc_7_4_0 //! //! @file @@ -61,9 +61,47 @@ static struct timespec l_tick; // structure for the clock tick static int_t l_tickPrio; // priority of the ticker thread #define NSEC_PER_SEC 1000000000L -#define DEFAULT_TICKS_PER_SEC 100 +#define DEFAULT_TICKS_PER_SEC 100L -//============================================================================ +//---------------------------------------------------------------------------- +#ifdef __APPLE__ + +#define TIMER_ABSTIME 0 + +// emulate clock_nanosleep() for CLOCK_MONOTONIC and TIMER_ABSTIME +static inline int clock_nanosleep(clockid_t clockid, int flags, + const struct timespec* t, + struct timespec* remain) +{ + Q_UNUSED_PAR(clockid); + Q_UNUSED_PAR(flags); + Q_UNUSED_PAR(remain); + + struct timespec ts_delta; + clock_gettime(CLOCK_MONOTONIC, &ts_delta); + + ts_delta.tv_sec = t->tv_sec - ts_delta.tv_sec; + ts_delta.tv_nsec = t->tv_nsec - ts_delta.tv_nsec; + if (ts_delta.tv_sec < 0) { + ts_delta.tv_sec = 0; + ts_delta.tv_nsec = 0; + } + else if (ts_delta.tv_nsec < 0) { + if (ts_delta.tv_sec == 0) { + ts_delta.tv_sec = 0; + ts_delta.tv_nsec = 0; + } + else { + ts_delta.tv_sec = ts_delta.tv_sec - 1; + ts_delta.tv_nsec = ts_delta.tv_nsec + NSEC_PER_SEC; + } + } + + return nanosleep(&ts_delta, NULL); +} +#endif + +//---------------------------------------------------------------------------- static void *ticker_thread(void *arg); // prototype static void *ticker_thread(void *arg) { // for pthread_create() Q_UNUSED_PAR(arg); @@ -91,7 +129,8 @@ static void *ticker_thread(void *arg) { // for pthread_create() if (clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, &next_tick, NULL) == 0) // success? { - QF_onClockTick(); // must call QTIMEEVT_TICK_X() + // clock tick callback (must call QTIMEEVT_TICK_X()) + QF_onClockTick(); } } return (void *)0; // return success @@ -121,12 +160,12 @@ static int_t l_critSectNest; // critical section nesting up-down counter //............................................................................ void QF_enterCriticalSection_(void) { pthread_mutex_lock(&l_critSectMutex_); - Q_ASSERT_INCRIT(100, l_critSectNest == 0); // NO nesting of crit.sect! + Q_ASSERT_INCRIT(101, l_critSectNest == 0); // NO nesting of crit.sect! ++l_critSectNest; } //............................................................................ void QF_leaveCriticalSection_(void) { - Q_ASSERT_INCRIT(200, l_critSectNest == 1); // crit.sect. must ballace! + Q_ASSERT_INCRIT(102, l_critSectNest == 1); // crit.sect. must balance! if ((--l_critSectNest) == 0) { pthread_mutex_unlock(&l_critSectMutex_); } @@ -166,6 +205,7 @@ void QF_init(void) { //............................................................................ int QF_run(void) { + l_isRunning = true; // QF is running QF_onStartup(); // application-specific startup callback @@ -218,7 +258,6 @@ int QF_run(void) { QS_BEGIN_PRE_(QS_QF_RUN, 0U) QS_END_PRE_() - l_isRunning = true; // QF is running while (l_isRunning) { Q_ASSERT_INCRIT(300, QPSet_verify_(&QF_readySet_, &QF_readySet_dis_)); @@ -233,8 +272,7 @@ int QF_run(void) { QF_CRIT_EXIT(); QEvt const *e = QActive_get_(a); - // dispatch event (virtual call) - (*a->super.vptr->dispatch)(&a->super, e, a->prio); + QASM_DISPATCH(&a->super, e, a->prio); // dispatch to the HSM QF_gc(e); QF_CRIT_ENTRY(); @@ -329,7 +367,6 @@ int QF_consoleWaitForKey(void) { #endif // QActive functions ========================================================= - void QActive_start_(QActive * const me, QPrioSpec const prioSpec, QEvt const * * const qSto, uint_fast16_t const qLen, void * const stkSto, uint_fast16_t const stkSize, @@ -354,7 +391,6 @@ void QActive_start_(QActive * const me, QPrioSpec const prioSpec, (*me->super.vptr->init)(&me->super, par, me->prio); QS_FLUSH(); // flush the QS trace buffer to the host } - //............................................................................ #ifdef QACTIVE_CAN_STOP void QActive_stop(QActive * const me) { diff --git a/ports/posix-qv/qs_port.c b/ports/posix-qv/qs_port.c index 882860f6..e0ef1766 100644 --- a/ports/posix-qv/qs_port.c +++ b/ports/posix-qv/qs_port.c @@ -22,7 +22,7 @@ // // //============================================================================ -//! @date Last updated on: 2024-06-11 +//! @date Last updated on: 2024-07-18 //! @version Last updated for: @ref qpc_7_4_0 //! //! @file @@ -151,7 +151,7 @@ uint8_t QS_onStartup(void const *arg) { if (fcntl(l_sock, F_SETFL, status | O_NONBLOCK) != 0) { FPRINTF_S(stderr, " ERROR Failed to set non-blocking socket " "errno=%d\n", errno); - QS_EXIT(); + QF_stop(); // <== stop and exit the application goto error; } @@ -177,7 +177,7 @@ void QS_onCleanup(void) { close(l_sock); l_sock = INVALID_SOCKET; } - //PRINTF_S(" Disconnected from QSPY\n"); + //PRINTF_S("%s\n", " Disconnected from QSPY"); } //............................................................................ void QS_onReset(void) { @@ -232,7 +232,7 @@ void QS_onFlush(void) { //............................................................................ QSTimeCtr QS_onGetTime(void) { struct timespec tspec; - clock_gettime(CLOCK_MONOTONIC_RAW, &tspec); + clock_gettime(CLOCK_MONOTONIC, &tspec); // convert to units of 0.1 microsecond QSTimeCtr time = (QSTimeCtr)(tspec.tv_sec * 10000000 + tspec.tv_nsec / 100); diff --git a/ports/posix/qf_port.c b/ports/posix/qf_port.c index d947f090..76c32805 100644 --- a/ports/posix/qf_port.c +++ b/ports/posix/qf_port.c @@ -22,7 +22,7 @@ // // //============================================================================ -//! @date Last updated on: 2024-06-11 +//! @date Last updated on: 2024-07-18 //! @version Last updated for: @ref qpc_7_4_0 //! //! @file @@ -72,7 +72,46 @@ static void sigIntHandler(int dummy) { exit(-1); } +//---------------------------------------------------------------------------- +#ifdef __APPLE__ + +#define TIMER_ABSTIME 0 + +// emulate clock_nanosleep() for CLOCK_MONOTONIC and TIMER_ABSTIME +static inline int clock_nanosleep(clockid_t clockid, int flags, + const struct timespec* t, + struct timespec* remain) +{ + Q_UNUSED_PAR(clockid); + Q_UNUSED_PAR(flags); + Q_UNUSED_PAR(remain); + + struct timespec ts_delta; + clock_gettime(CLOCK_MONOTONIC, &ts_delta); + + ts_delta.tv_sec = t->tv_sec - ts_delta.tv_sec; + ts_delta.tv_nsec = t->tv_nsec - ts_delta.tv_nsec; + if (ts_delta.tv_sec < 0) { + ts_delta.tv_sec = 0; + ts_delta.tv_nsec = 0; + } + else if (ts_delta.tv_nsec < 0) { + if (ts_delta.tv_sec == 0) { + ts_delta.tv_sec = 0; + ts_delta.tv_nsec = 0; + } + else { + ts_delta.tv_sec = ts_delta.tv_sec - 1; + ts_delta.tv_nsec = ts_delta.tv_nsec + NSEC_PER_SEC; + } + } + + return nanosleep(&ts_delta, NULL); +} +#endif + //============================================================================ +// QF functions // NOTE: initialize the critical section mutex as non-recursive, // but check that nesting of critical sections never occurs @@ -83,12 +122,12 @@ int_t QF_critSectNest_; //............................................................................ void QF_enterCriticalSection_(void) { pthread_mutex_lock(&QF_critSectMutex_); - Q_ASSERT_INCRIT(100, QF_critSectNest_ == 0); // NO nesting of crit.sect! + Q_ASSERT_INCRIT(101, QF_critSectNest_ == 0); // NO nesting of crit.sect! ++QF_critSectNest_; } //............................................................................ void QF_leaveCriticalSection_(void) { - Q_ASSERT_INCRIT(200, QF_critSectNest_ == 1); // crit.sect. must ballace! + Q_ASSERT_INCRIT(102, QF_critSectNest_ == 1); // crit.sect. must balance! if ((--QF_critSectNest_) == 0) { pthread_mutex_unlock(&QF_critSectMutex_); } @@ -112,7 +151,7 @@ void QF_init(void) { } l_tick.tv_sec = 0; - l_tick.tv_nsec = NSEC_PER_SEC / DEFAULT_TICKS_PER_SEC; // default tick + l_tick.tv_nsec = NSEC_PER_SEC / DEFAULT_TICKS_PER_SEC; // default rate l_tickPrio = sched_get_priority_min(SCHED_FIFO); // default ticker prio // install the SIGINT (Ctrl-C) signal handler @@ -167,10 +206,12 @@ int QF_run(void) { } // sleep without drifting till next_time (absolute), see NOTE03 - (void)clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, - &next_tick, NULL); - // clock tick callback (must call QTIMEEVT_TICK_X() once) - QF_onClockTick(); + if (clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, + &next_tick, NULL) == 0) // success? + { + // clock tick callback (must call QTIMEEVT_TICK_X() once) + QF_onClockTick(); + } } } else { // The provided system clock tick NOT configured diff --git a/ports/posix/qs_port.c b/ports/posix/qs_port.c index 7c5d3f77..e0ef1766 100644 --- a/ports/posix/qs_port.c +++ b/ports/posix/qs_port.c @@ -22,7 +22,7 @@ // // //============================================================================ -//! @date Last updated on: 2024-06-11 +//! @date Last updated on: 2024-07-18 //! @version Last updated for: @ref qpc_7_4_0 //! //! @file @@ -151,7 +151,7 @@ uint8_t QS_onStartup(void const *arg) { if (fcntl(l_sock, F_SETFL, status | O_NONBLOCK) != 0) { FPRINTF_S(stderr, " ERROR Failed to set non-blocking socket " "errno=%d\n", errno); - QS_EXIT(); + QF_stop(); // <== stop and exit the application goto error; } @@ -232,7 +232,7 @@ void QS_onFlush(void) { //............................................................................ QSTimeCtr QS_onGetTime(void) { struct timespec tspec; - clock_gettime(CLOCK_MONOTONIC_RAW, &tspec); + clock_gettime(CLOCK_MONOTONIC, &tspec); // convert to units of 0.1 microsecond QSTimeCtr time = (QSTimeCtr)(tspec.tv_sec * 10000000 + tspec.tv_nsec / 100); diff --git a/ports/win32-qv/qf_port.c b/ports/win32-qv/qf_port.c index 68e097ac..ab5be3b1 100644 --- a/ports/win32-qv/qf_port.c +++ b/ports/win32-qv/qf_port.c @@ -155,8 +155,7 @@ int QF_run(void) { QF_CRIT_EXIT(); QEvt const *e = QActive_get_(a); - // dispatch event (virtual call) - (*a->super.vptr->dispatch)(&a->super, e, a->prio); + QASM_DISPATCH(&a->super, e, a->prio); // dispatch to the HSM QF_gc(e); QF_CRIT_ENTRY(); From cff3516cf53d72c851ffd5cc287a0fe98e752f00 Mon Sep 17 00:00:00 2001 From: Mikael Persson Date: Tue, 30 Jul 2024 17:56:30 -0400 Subject: [PATCH 2/3] Added logic to skip ahead to next intact message after overflowing the QS queue, this removes spammy bad checksum errors --- src/qs/qs.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/qs/qs.c b/src/qs/qs.c index f7200b16..d895aae6 100644 --- a/src/qs/qs.c +++ b/src/qs/qs.c @@ -472,6 +472,13 @@ void QS_endRec_(void) { if (QS_priv_.used > end) { QS_priv_.used = end; // the whole buffer is used QS_priv_.tail = head; // shift the tail to the old data + // Skip ahead to next intact message at the tail. + for (;;) { + uint16_t discarded_b = QS_getByte(); + if (discarded_b == QS_EOD || discarded_b == QS_FRAME) { + break; + } + } } } From cfb4da9ab5122e8124024e11b86a612bb8869a03 Mon Sep 17 00:00:00 2001 From: Mikael Persson Date: Wed, 31 Jul 2024 11:27:55 -0400 Subject: [PATCH 3/3] Improved version of fix --- src/qs/qs.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/qs/qs.c b/src/qs/qs.c index d895aae6..2ff144ca 100644 --- a/src/qs/qs.c +++ b/src/qs/qs.c @@ -471,14 +471,18 @@ void QS_endRec_(void) { // overrun over the old data? if (QS_priv_.used > end) { QS_priv_.used = end; // the whole buffer is used - QS_priv_.tail = head; // shift the tail to the old data - // Skip ahead to next intact message at the tail. for (;;) { - uint16_t discarded_b = QS_getByte(); - if (discarded_b == QS_EOD || discarded_b == QS_FRAME) { + uint8_t discarded_b = buf[head]; + ++head; + if (head == end) { + head = 0U; + } + --QS_priv_.used; + if (discarded_b == QS_FRAME) { break; } } + QS_priv_.tail = head; // shift the tail to start of oldest record } }