Utility¶
Small helpers: wait for a condition with a timeout, read time and sleep, start a group of threads together, and turn FreeRTOS codes into text.
TestLogicWithTimeout¶
TestLogicWithTimeout(func, expected, timeoutMsec, checkIntervalMs) calls func() until it returns expected
or timeoutMsec passes, sleeping checkIntervalMs between calls. It returns true when the value arrived.
BaseThread uses it to verify starts and stops.
#include <atomic>
#include "Utility.h"
static std::atomic<bool> link_up{false};
bool WaitForLink() {
return TestLogicWithTimeout([] { return link_up.load(); }, true,
/*timeoutMsec=*/2000, /*checkIntervalMs=*/10);
}
The check interval is passed to os_delay_msec() as a uint16_t. On the no-RTOS backend without an external
clock, time does not move, so the loop never times out: define HF_RTOS_NONE_EXTERNAL_CLOCK in host builds that
call it (see Backends).
Time¶
| Call | Header | Returns |
|---|---|---|
RtosTime::GetCurrentTimeUs() |
RtosMutex.h |
Microseconds since start, from the kernel tick (tick resolution) or the external clock |
RtosTime::MsToTicks(ms) |
RtosMutex.h |
Ticks, at least 1 for a non-zero ms |
os_get_elapsed_time_msec() |
OsUtility.h |
Milliseconds since start, as uint32_t (wraps after 49.7 days) |
os_delay_msec(ms) |
OsUtility.h |
Sleeps ms (a uint16_t, at most 65 535), converted with os_convert_msec_to_delay_ticks(): at least one tick for a non-zero ms, so 1 ms on a 100 Hz tick sleeps 10 ms, never 0 |
os_convert_msec_to_delay_ticks(ms) |
OsUtility.h |
Ticks, rounded down, at least 1 for a non-zero ms; 0 for 0 |
os_convert_hz_to_delay_ticks(hz) |
OsUtility.h |
Period in ticks, rounded down, at least 1 for a non-zero hz; 0 for 0 |
os_delay_time(t, unit) |
OsUtility.h |
Sleeps t in TIME_UNIT_US, TIME_UNIT_MS or TIME_UNIT_S |
#include <cstdint>
#include "OsUtility.h"
#include "RtosMutex.h"
uint64_t MeasureUs() {
const uint64_t t0 = RtosTime::GetCurrentTimeUs();
os_delay_msec(5);
return RtosTime::GetCurrentTimeUs() - t0;
}
BaseThreadsManager¶
Starts and stops a set of BaseThread objects together, named by an enum, with or without
waiting for each to confirm. The enum must be unscoped (enum, not enum class) because its count also sizes a
std::bitset.
#include <map>
#include "BaseThread.h"
#include "BaseThreadsManager.h"
enum AppThread : int { kControl, kTelemetry, kAppThreadCount }; // unscoped: also the bitset size
static const char* AppThreadName(AppThread t) {
return t == kControl ? "control" : "telemetry";
}
class AppThreads : public BaseThreadsManager<AppThread, kAppThreadCount> {
public:
using BaseThreadsManager::BaseThreadsManager;
};
bool StartApp(BaseThread& control, BaseThread& telemetry) {
static AppThreads threads({{kControl, &control}, {kTelemetry, &telemetry}}, AppThreadName);
return threads.EnsureInitialized() && threads.StartAllAndWaitToVerify(/*waitToVerifyTimeoutMsec=*/1000);
}
| Group | Calls |
|---|---|
| Start | StartAll(), StartSelected(list), StartAllExceptSelected(list), and each ...AndWaitToVerify(..., ms) |
| Stop | StopAll(), StopSelected(list), StopAllExceptSelected(list), and each ...AndWaitToVerify(..., ms) |
| Resume | ResumeAll(), ResumeSelected(list) |
| Hooks | PreThreadInitializationActions(), PostThreadInitializationActions() (virtual, override in a subclass) |
The registry is a std::map copied from the constructor argument, so it allocates on the heap once; an internal
Mutex guards it.
FreeRTOSUtils¶
freertos_ret_to_string(BaseType_t) and freertos_task_state_to_string(eTaskState) return a name for a FreeRTOS
return code or task state, for logs. Without FreeRTOS they return "N/A (no RTOS)". Compile
src/FreeRTOSUtils.c with the FreeRTOS backend.
Next: API reference.