sl-controls e181dcc786 feat(safety): IWDG watchdog, arm hold interlock, tilt alert (bd-3qh)
Safety systems implementation:

IWDG Hardware Watchdog (50ms timeout, config.h WATCHDOG_TIMEOUT_MS):
- safety_init() configures IWDG at PSC/32 (0.8ms tick), reload=62
- safety_refresh() must be called every loop iteration
- Cannot be disabled once started — MCU resets if loop hangs
- Started after 3s USB init delay (avoids spurious startup reset)

Arm Hold Interlock (3s, config.h ARMING_HOLD_MS):
- Arm command starts a hold timer, not immediate motor enable
- Motors only enable after ARMING_HOLD_MS consecutive hold
- Disarm or tilt > 10° cancels pending arm
- Prevents accidental arm from single keypress

Tilt Fault Alert:
- safety_alert_tilt_fault() fires one-shot buzzer on TILT_FAULT edge
- Rider hears alarm when tilt cutoff triggers
- Edge-detected (buzzer only fires once per fault event)

RC Timeout (infrastructure):
- safety_rc_alive() checks crsf_state.last_rx_ms vs RC_TIMEOUT_MS
- RC disarm wired but guarded (no CRSF yet) — remove guard when wired
- Compatible with future CRSF implementation

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-28 12:33:15 -05:00

52 lines
1.4 KiB
C

#ifndef SAFETY_H
#define SAFETY_H
#include <stdint.h>
#include <stdbool.h>
/*
* SaltyLab Safety Systems
*
* Covers:
* - IWDG hardware watchdog (MCU reset if main loop hangs)
* - RC signal timeout monitoring
* - Tilt fault alert via buzzer
* - Arm hold interlock (must hold arm for ARMING_HOLD_MS)
*/
/*
* safety_init() — call once in main() after HAL_Init().
* Starts IWDG with WATCHDOG_TIMEOUT_MS timeout from config.h.
* Starts ARMING_HOLD_MS countdown from config.h.
*/
void safety_init(void);
/*
* safety_refresh() — call every main loop iteration.
* Resets IWDG counter. If not called within WATCHDOG_TIMEOUT_MS,
* the MCU will reset (independent of software — cannot be disabled).
*/
void safety_refresh(void);
/*
* safety_rc_alive() — returns true if RC receiver has sent a frame
* within RC_TIMEOUT_MS. Call from the balance loop.
*/
bool safety_rc_alive(uint32_t now);
/*
* safety_alert_tilt_fault() — one-shot buzzer beep for tilt fault.
* Safe to call repeatedly; only fires once per fault.
*/
void safety_alert_tilt_fault(bool faulted);
/*
* safety_arm_interlock() — returns true once arm button has been
* held for ARMING_HOLD_MS from the moment safety_arm_start() was called.
*/
void safety_arm_start(uint32_t now); /* Call when arm requested */
bool safety_arm_ready(uint32_t now); /* Poll until true, then arm */
void safety_arm_cancel(void); /* Cancel pending arm */
#endif /* SAFETY_H */