// ============================================================================= // nmea2000_consumer.h -- NMEA 2000 backbone consumer // ============================================================================= // // Sprint 1 subscribes to PGN 127250 (Vessel Heading) and PGN 127251 // (Rate of Turn) from the boat's NMEA 2000 backbone. The latest values // are stashed in a thread-safe snapshot that the Modbus slave (and later // the PID outer loop) read from. // // Later sprints will also subscribe to PGN 129025/129029 (Position), // 129026 (COG/SOG), 129284 (Navigation Data), 127257 (Attitude). // // This module owns the NMEA2000 instance and its dedicated FreeRTOS task // pinned to Core 0. // ============================================================================= #pragma once #include namespace arautopilot::protocols::nmea2000 { struct HeadingSnapshot { float heading_deg; ///< 0..360, magnetic or true depending on source bool is_true; ///< true if reference is "true north", false if magnetic float rate_of_turn_dps; ///< signed deg/s; positive = turning to starboard uint32_t heading_age_ms; ///< millis() at the last 127250 update uint32_t rot_age_ms; ///< millis() at the last 127251 update bool heading_valid; ///< true if the heading is fresh (<5 s old) bool rot_valid; ///< true if the ROT is fresh (<5 s old) }; /// Initialise the NMEA2000 stack with our PGN handlers. void nmea2000_consumer_init(); /// Spawn the FreeRTOS task that pumps NMEA2000.ParseMessages() forever. void nmea2000_consumer_start_task(); /// Thread-safe read of the latest heading + ROT snapshot. HeadingSnapshot nmea2000_latest(); /// True if either heading_age_ms or rot_age_ms exceeds the stale-threshold /// (default 5 s, brief section 7). bool nmea2000_is_stale(); } // namespace arautopilot::protocols::nmea2000