ra8-firmware 0.1.0
Bare-metal firmware for the Renesas RA8 family (RA8D2 / RA8P1)
Loading...
Searching...
No Matches
ra8_wdt_supervisor.h File Reference

ThreadX-aware watchdog supervisor (per-thread check-in registry). More...

#include <stdint.h>
#include "ra8_err.h"
Include dependency graph for ra8_wdt_supervisor.h:
This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Data Structures

struct  ra8_wdt_sup_cfg_t
 One-shot supervisor configuration block. More...

Typedefs

typedef uint32_t(* ra8_wdt_sup_now_fn_t) (void)
 Hook used by tests to inject monotonic-time readings.
typedef void(* ra8_wdt_sup_refresh_fn_t) (void)
 Hook used to call into ra8_wdt_refresh_deferred.

Enumerations

enum  ra8_wdt_sup_limits_t : uint8_t {
  k_ra8_wdt_sup_max_threads = 8U ,
  k_ra8_wdt_sup_name_max = 16U
}
 Compile-time limits on the supervisor registry. More...
enum  ra8_wdt_sup_handle_t : uint8_t { k_ra8_wdt_sup_handle_invalid = 0xFFU }
 Opaque handle returned by ra8_wdt_supervisor_register_thread. More...

Functions

ra8_err_t ra8_wdt_supervisor_init (const ra8_wdt_sup_cfg_t *cfg)
 Initialise the supervisor registry and runtime hooks.
ra8_err_t ra8_wdt_supervisor_deinit (void)
 Reset the supervisor to its uninitialized state (test helper).
ra8_err_t ra8_wdt_supervisor_register_thread (const char *name, uint32_t deadline_ms, uint8_t *out_handle)
 Register a worker thread with the supervisor.
ra8_err_t ra8_wdt_supervisor_checkin (uint8_t handle)
 Record a thread check-in, resetting its deadline window.
ra8_err_t ra8_wdt_supervisor_start (void)
 Spawn the supervisor thread.
ra8_err_t ra8_wdt_supervisor_tick (bool *out_did_refresh)
 Run one supervisor tick synchronously (test / introspection hook).
ra8_err_t ra8_wdt_supervisor_set_now_hook (ra8_wdt_sup_now_fn_t now)
 Override the monotonic-time hook (test injection point).
ra8_err_t ra8_wdt_supervisor_set_refresh_hook (ra8_wdt_sup_refresh_fn_t refresh)
 Override the WDT-refresh hook (test injection point).
uint8_t ra8_wdt_supervisor_thread_count (void)
 Read the number of currently-registered worker threads.

Detailed Description

ThreadX-aware watchdog supervisor (per-thread check-in registry).

Tag
[Ring 4 / Service] {World: NS}

The hardware Watchdog Timer (ra8_wdt) demands a refresh inside the configured window or it resets the chip. In a multi-threaded build blindly refreshing from one place defeats the purpose – if the refreshing thread is alive but every other worker has wedged, the WDT still gets kicked and the wedge goes undetected.

This module implements the canonical "per-thread check-in" pattern:

  1. Each long-running ThreadX thread registers itself with a deadline_ms budget that bounds how often it must check in.
  2. The thread calls ra8_wdt_supervisor_checkin at safe points in its loop (typically once per iteration).
  3. A dedicated supervisor thread wakes every refresh_period_ms and only calls ra8_wdt_refresh_deferred if every registered thread has checked in within its deadline. If any thread is overdue the supervisor stops kicking, the WDT eventually underflows, and the chip reboots into the failure handler.

The registry is statically allocated and protected by a TX_MUTEX, so registration must happen during boot before secondary threads start running.

State Machine:

Definition in file ra8_wdt_supervisor.h.

Typedef Documentation

◆ ra8_wdt_sup_now_fn_t

typedef uint32_t(* ra8_wdt_sup_now_fn_t) (void)

Hook used by tests to inject monotonic-time readings.

Production builds default to a hook that wraps tx_time_get and scales it by the kernel tick. Unit tests override this with a deterministic counter so deadline arithmetic is reproducible. NASA Rule 9 deviation: function pointer used for Dependency Inversion.

Returns
Monotonic time in milliseconds. Wraps mod 2^32.

Definition at line 144 of file ra8_wdt_supervisor.h.

◆ ra8_wdt_sup_refresh_fn_t

typedef void(* ra8_wdt_sup_refresh_fn_t) (void)

Hook used to call into ra8_wdt_refresh_deferred.

Default points at ra8_wdt_refresh_deferred. Tests override this so the test body can count refresh calls without mmapping fake WDT registers.

Definition at line 155 of file ra8_wdt_supervisor.h.

Enumeration Type Documentation

◆ ra8_wdt_sup_handle_t

enum ra8_wdt_sup_handle_t : uint8_t

Opaque handle returned by ra8_wdt_supervisor_register_thread.

Handles are small integers in [0, k_ra8_wdt_sup_max_threads). The sentinel k_ra8_wdt_sup_handle_invalid is returned in out_handle if registration fails.

Enumerator
k_ra8_wdt_sup_handle_invalid 

Invalid / unregistered handle.

Definition at line 96 of file ra8_wdt_supervisor.h.

◆ ra8_wdt_sup_limits_t

enum ra8_wdt_sup_limits_t : uint8_t

Compile-time limits on the supervisor registry.

The maximum number of registered worker threads is capped to keep the registry walk bounded (NASA Rule 2). All slots are statically allocated – no malloc per CLAUDE.md.

Enumerator
k_ra8_wdt_sup_max_threads 

Max simultaneously registered threads.

k_ra8_wdt_sup_name_max 

Max bytes (incl.

NUL) in a thread name.

Definition at line 82 of file ra8_wdt_supervisor.h.

Function Documentation

◆ ra8_wdt_supervisor_checkin()

ra8_err_t ra8_wdt_supervisor_checkin ( uint8_t handle)
nodiscard

Record a thread check-in, resetting its deadline window.

Called by registered worker threads at known points in their loops (typically once per iteration, before any blocking call). Updates the slot's last_checkin_ms to the current monotonic time so the supervisor sees the thread as alive on its next tick.

Parameters
[in]handleHandle returned by ra8_wdt_supervisor_register_thread.
Returns
ra8_err_t
Return values
k_ra8_okCheck-in recorded.
k_ra8_err_invalid_arghandle is out of range.
k_ra8_err_not_foundhandle refers to a free slot.
k_ra8_err_not_initializedra8_wdt_supervisor_init not called.
Precondition
handle < k_ra8_wdt_sup_max_threads.
Slot was previously registered.
Postcondition
Slot's last_checkin_ms equals current monotonic time.
Note
Thread-safe via TX_MUTEX.
Since
0.1.0

Definition at line 342 of file ra8_wdt_supervisor.c.

References k_ra8_err_invalid_arg, k_ra8_err_not_found, k_ra8_err_not_initialized, k_ra8_err_rtos_error, k_ra8_ok, k_ra8_wdt_sup_max_threads, k_ra8_wdt_sup_slot_used, s_state, tx_mutex_get, tx_mutex_put, TX_SUCCESS, and TX_WAIT_FOREVER.

Referenced by internal_sys_thread_entry(), internal_ui_thread_entry(), worker_a_entry(), and worker_b_entry().

◆ ra8_wdt_supervisor_deinit()

ra8_err_t ra8_wdt_supervisor_deinit ( void )
nodiscard

Reset the supervisor to its uninitialized state (test helper).

Tears down the registry, deletes the mutex, and clears module state. Intended for unit tests that need a fresh slate between cases. Safe to call when never initialized.

Returns
ra8_err_t
Return values
k_ra8_okAlways succeeds.
Precondition
None.
Postcondition
Module state is identical to its pre-init posture.
Note
Not thread-safe.
Since
0.1.0

Definition at line 254 of file ra8_wdt_supervisor.c.

References k_ra8_ok, memset(), s_state, tx_mutex_delete, tx_thread_delete, and tx_thread_terminate.

◆ ra8_wdt_supervisor_init()

ra8_err_t ra8_wdt_supervisor_init ( const ra8_wdt_sup_cfg_t * cfg)
nodiscard

Initialise the supervisor registry and runtime hooks.

Validates cfg, zeroes the static registry, creates the registry mutex, and stores cfg for later use by ..._start. Does not spawn the supervisor thread yet – callers register their workers first, then call ra8_wdt_supervisor_start.

Algorithm:

  1. Reject null cfg and out-of-range fields.
  2. Clear every registry slot to free.
  3. Create the TX_MUTEX guarding the registry.
  4. Stash cfg in module state.
Parameters
[in]cfgPointer to a populated configuration block.
Returns
ra8_err_t
Return values
k_ra8_okSupervisor initialized, ready for register / start.
k_ra8_err_null_ptrcfg was null or cfg->stack was null.
k_ra8_err_invalid_argStack too small / period zero / bad priority.
k_ra8_err_busyra8_wdt_supervisor_init was already called.
Precondition
cfg is non-null and points to a populated block.
Caller is in single-threaded init context.
Postcondition
Registry is empty (every slot free).
Internal mutex is created and unlocked.
Note
Not thread-safe; call once during boot.
Example:
static uint8_t sup_stack[1024];
const ra8_wdt_sup_cfg_t cfg = {
.stack = sup_stack, .stack_size_bytes = sizeof sup_stack,
.priority = 4, .refresh_period_ms = 50,
};
ra8_err_t ra8_wdt_supervisor_init(const ra8_wdt_sup_cfg_t *cfg)
Initialise the supervisor registry and runtime hooks.
One-shot supervisor configuration block.
See also
ra8_wdt_supervisor_register_thread
ra8_wdt_supervisor_start
Since
0.1.0

Definition at line 229 of file ra8_wdt_supervisor.c.

References internal_default_now(), internal_default_refresh(), internal_validate_cfg(), k_ra8_err_busy, k_ra8_err_rtos_error, k_ra8_ok, memset(), s_state, tx_mutex_create, TX_NO_INHERIT, and TX_SUCCESS.

Referenced by internal_wdt_setup(), and wdt_sup_demo_bring_up().

◆ ra8_wdt_supervisor_register_thread()

ra8_err_t ra8_wdt_supervisor_register_thread ( const char * name,
uint32_t deadline_ms,
uint8_t * out_handle )
nodiscard

Register a worker thread with the supervisor.

Allocates one of the k_ra8_wdt_sup_max_threads static slots, copies up to k_ra8_wdt_sup_name_max - 1 bytes of name for diagnostics, stamps the deadline budget, and primes last_checkin_ms to "now" so the first tick does not count the thread as overdue before it has had a chance to run.

Parameters
[in]nameShort diagnostic name (must be NUL-terminated).
[in]deadline_msMaximum allowed gap between consecutive check-ins, in milliseconds. Must be > 0.
[out]out_handleReceives the registered handle on success.
Returns
ra8_err_t
Return values
k_ra8_okSlot allocated, *out_handle populated.
k_ra8_err_null_ptrname or out_handle was null.
k_ra8_err_invalid_argdeadline_ms was zero.
k_ra8_err_no_memAll slots are taken.
k_ra8_err_not_initializedra8_wdt_supervisor_init not called.
Precondition
name is NUL-terminated and non-null.
deadline_ms > 0.
Postcondition
On success, registry holds one more populated slot.
On failure, *out_handle is set to k_ra8_wdt_sup_handle_invalid.
Note
Thread-safe via TX_MUTEX.
See also
ra8_wdt_supervisor_checkin
Since
0.1.0

Definition at line 306 of file ra8_wdt_supervisor.c.

References internal_fill_slot(), k_ra8_err_invalid_arg, k_ra8_err_no_mem, k_ra8_err_not_initialized, k_ra8_err_null_ptr, k_ra8_err_rtos_error, k_ra8_ok, k_ra8_wdt_sup_handle_invalid, k_ra8_wdt_sup_max_threads, k_ra8_wdt_sup_slot_free, s_state, tx_mutex_get, tx_mutex_put, TX_SUCCESS, and TX_WAIT_FOREVER.

Referenced by internal_wdt_setup(), and wdt_sup_demo_bring_up().

◆ ra8_wdt_supervisor_set_now_hook()

ra8_err_t ra8_wdt_supervisor_set_now_hook ( ra8_wdt_sup_now_fn_t now)
nodiscard

Override the monotonic-time hook (test injection point).

Pass nullptr to restore the default ThreadX-tick reader. NASA Rule 9 deviation: function pointer used for Dependency Inversion.

Parameters
[in]nowReplacement hook or nullptr.
Returns
Always k_ra8_ok.
Precondition
Caller is in single-writer init context.
Postcondition
Subsequent supervisor logic uses now.
Since
0.1.0

Definition at line 444 of file ra8_wdt_supervisor.c.

References internal_default_now(), k_ra8_ok, and s_state.

◆ ra8_wdt_supervisor_set_refresh_hook()

ra8_err_t ra8_wdt_supervisor_set_refresh_hook ( ra8_wdt_sup_refresh_fn_t refresh)
nodiscard

Override the WDT-refresh hook (test injection point).

Pass nullptr to restore the default that calls ra8_wdt_refresh_deferred. NASA Rule 9 deviation: function pointer used for Dependency Inversion.

Parameters
[in]refreshReplacement hook or nullptr.
Returns
Always k_ra8_ok.
Precondition
Caller is in single-writer init context.
Postcondition
Subsequent supervisor ticks call refresh in place of the WDT.
Since
0.1.0

Definition at line 450 of file ra8_wdt_supervisor.c.

References internal_default_refresh(), k_ra8_ok, and s_state.

Referenced by internal_wdt_setup().

◆ ra8_wdt_supervisor_start()

ra8_err_t ra8_wdt_supervisor_start ( void )
nodiscard

Spawn the supervisor thread.

Creates the supervisor's TX_THREAD with the stack region from cfg, then returns. The supervisor's loop:

  1. tx_thread_sleep(refresh_period_ms) worth of ticks.
  2. Snapshot every populated slot under the mutex.
  3. For each slot, evaluate now - last_checkin_ms <= deadline_ms.
  4. If every slot passes, call the refresh hook -> ra8_wdt_refresh_deferred. Otherwise skip the refresh and let the WDT do its job.
Returns
ra8_err_t
Return values
k_ra8_okSupervisor thread created.
k_ra8_err_not_initializedra8_wdt_supervisor_init not called.
k_ra8_err_busyAlready started.
k_ra8_err_rtos_thread_createUnderlying tx_thread_create failed.
Precondition
ra8_wdt_supervisor_init returned k_ra8_ok.
At least one worker has been registered.
Postcondition
Supervisor thread is runnable.
First refresh occurs at t = refresh_period_ms.
Note
Not thread-safe; call once after registration.
Since
0.1.0

Definition at line 366 of file ra8_wdt_supervisor.c.

References internal_thread_entry(), k_ra8_err_busy, k_ra8_err_not_initialized, k_ra8_err_rtos_error, k_ra8_ok, s_state, TX_AUTO_START, TX_NO_TIME_SLICE, TX_SUCCESS, and tx_thread_create.

Referenced by internal_wdt_setup(), and wdt_sup_demo_bring_up().

◆ ra8_wdt_supervisor_thread_count()

uint8_t ra8_wdt_supervisor_thread_count ( void )

Read the number of currently-registered worker threads.

Diagnostic accessor for tests and dump helpers.

Returns
Count in [0, k_ra8_wdt_sup_max_threads].
Precondition
None.
Postcondition
No state is mutated.
Since
0.1.0
Return values
k_ra8_okOperation succeeded.
Precondition
Module state is consistent.
Postcondition
Caller-visible state matches the documented contract.
Note
Not thread-safe unless documented otherwise.

Definition at line 456 of file ra8_wdt_supervisor.c.

References k_ra8_wdt_sup_max_threads, k_ra8_wdt_sup_slot_used, and s_state.

◆ ra8_wdt_supervisor_tick()

ra8_err_t ra8_wdt_supervisor_tick ( bool * out_did_refresh)
nodiscard

Run one supervisor tick synchronously (test / introspection hook).

Production builds run the same logic from the supervisor thread's loop. Exposing it as a callable function lets unit tests drive the supervisor without spinning a real ThreadX kernel and lets a host application probe "would I refresh right now?" out-of-band.

Parameters
[out]out_did_refreshOptional. Receives true if every registered thread was within deadline and the refresh hook was therefore called.
Returns
ra8_err_t
Return values
k_ra8_okTick complete.
k_ra8_err_not_initializedra8_wdt_supervisor_init not called.
Precondition
ra8_wdt_supervisor_init returned k_ra8_ok.
Postcondition
*out_did_refresh reflects whether the refresh hook ran.
Module state is otherwise unchanged.
Note
Thread-safe via TX_MUTEX.
Since
0.1.0

Definition at line 393 of file ra8_wdt_supervisor.c.

References internal_is_overdue(), k_ra8_err_not_initialized, k_ra8_err_rtos_error, k_ra8_ok, k_ra8_wdt_sup_max_threads, k_ra8_wdt_sup_slot_used, s_state, tx_mutex_get, tx_mutex_put, TX_SUCCESS, and TX_WAIT_FOREVER.

Referenced by internal_thread_entry().