rcbench
Servo and ESC test bench: panel, IOmcu and shared C
Loading...
Searching...
No Matches
heartbeat.c File Reference

SPDX-License-Identifier: MIT. More...

#include "heartbeat.h"
#include <string.h>

Functions

static bool elapsed_at_least (uint32_t now, uint32_t then, uint32_t ms)
 Every comparison is an unsigned difference against a timeout, never a comparison of two timestamps.
void heartbeat_gen_init (heartbeat_gen_t *g)
 Start held low: nothing downstream may run until this loop asks for it.
bool heartbeat_gen_step (heartbeat_gen_t *g, uint32_t now_ms, bool alive)
 Advance the generator; returns the level the pin should be driven to.
void heartbeat_mon_init (heartbeat_mon_t *m)
 Start not alive, with no edge seen.
void heartbeat_mon_edge (heartbeat_mon_t *m, uint32_t now_ms)
 Record an edge on the safety line.
bool heartbeat_mon_alive (heartbeat_mon_t *m, uint32_t now_ms)
 Whether the line may be believed now.

Detailed Description

SPDX-License-Identifier: MIT.

Function Documentation

◆ elapsed_at_least()

bool elapsed_at_least ( uint32_t now,
uint32_t then,
uint32_t ms )
inlinestatic

Every comparison is an unsigned difference against a timeout, never a comparison of two timestamps.

A 32-bit millisecond counter wraps after 49.7 days, and now < then is wrong for about 1ms either side of the wrap; the subtraction wraps with the counter and stays correct.

◆ heartbeat_gen_init()

void heartbeat_gen_init ( heartbeat_gen_t * g)

Start held low: nothing downstream may run until this loop asks for it.

Parameters
gGenerator state to initialise.

◆ heartbeat_gen_step()

bool heartbeat_gen_step ( heartbeat_gen_t * g,
uint32_t now_ms,
bool alive )

Advance the generator; returns the level the pin should be driven to.

alive is the caller's own judgement of whether it is fit to keep the bench running – touch answering, link up, no latched stop. When it is false the line goes low immediately rather than merely stopping: waiting for the monostable to time out would spend its whole period still enabled, and the fastest correct thing to do with a stop is all of it at once.

Call it as often as you like; it edges no faster than HEARTBEAT_PERIOD_MS.

Parameters
gGenerator state.
now_msCurrent time, in milliseconds.
alivetrue when the caller judges the bench fit to run.
Returns
The level the pin is driven to.

◆ heartbeat_mon_alive()

bool heartbeat_mon_alive ( heartbeat_mon_t * m,
uint32_t now_ms )

Whether the line may be believed now.

Must be called even when no edges are arriving: silence is the failure this exists to catch, and silence generates no events. Calling it is what notices that nothing has happened.

Parameters
mMonitor state.
now_msCurrent time, in milliseconds.
Returns
true when the line may be believed now.

◆ heartbeat_mon_edge()

void heartbeat_mon_edge ( heartbeat_mon_t * m,
uint32_t now_ms )

Record an edge on the safety line.

Called from wherever edges are noticed – an interrupt, or a poll that samples faster than HEARTBEAT_MIN_GAP_MS. It only ever costs a subtraction and a compare, so an ISR is a fine place for it.

Parameters
mMonitor state.
now_msTime of the edge, in milliseconds.

◆ heartbeat_mon_init()

void heartbeat_mon_init ( heartbeat_mon_t * m)

Start not alive, with no edge seen.

Parameters
mMonitor state to initialise.