// =============================================================================
//  modbus_registers.h -- AR-Autopilot Modbus RTU register map
// =============================================================================
//
//  AUTO-GENERATED. Do not edit by hand.
//  Source: firmware/ar_autopilot_v1/modbus_registers.yaml
//  Regenerate with: python tools/gen_modbus_registers.py
// =============================================================================

#pragma once

#include <cstdint>

namespace arautopilot::protocols::modbus {

constexpr const char* MAP_SCHEMA_VERSION = "0.1.0";
constexpr uint8_t  SLAVE_ID  = 1;
constexpr uint32_t BAUDRATE  = 38400;
constexpr char     PARITY    = 'N';
constexpr uint8_t  DATA_BITS = 8;
constexpr uint8_t  STOP_BITS = 1;

// ----- Discrete inputs (read-only bits) -----
constexpr uint16_t DISCRETE_COUNT = 19;
constexpr uint16_t DISCRETE_MAX_ADDR = 25;

// 1 if the pilot is currently engaged (any mode other than STANDBY)
constexpr uint16_t DISCRETE_PILOT_ENGAGED = 0;
// Live state of the physical Engage/Disengage push-button
constexpr uint16_t DISCRETE_DI_DISENGAGE_BUTTON = 1;
// Port-side rudder mechanical end-stop reached
constexpr uint16_t DISCRETE_DI_LIMIT_PORT = 2;
// Starboard-side rudder mechanical end-stop reached
constexpr uint16_t DISCRETE_DI_LIMIT_STBD = 3;
// External critical alarm (VMS / genset) asserted
constexpr uint16_t DISCRETE_DI_EXTERNAL_ALARM = 4;
// Manual confirmation switch asserted (emergency override)
constexpr uint16_t DISCRETE_DI_MANUAL_CONFIRM = 5;
// Master actuator power relay (DO3) commanded ON
constexpr uint16_t DISCRETE_ACTUATOR_POWER = 8;
// Actuator direction output: driving to port
constexpr uint16_t DISCRETE_ACTUATOR_DRIVING_PORT = 9;
// Actuator direction output: driving to starboard
constexpr uint16_t DISCRETE_ACTUATOR_DRIVING_STBD = 10;
// Off-course warning active
constexpr uint16_t DISCRETE_ALARM_OFF_COURSE = 16;
// Severe off-course alarm (auto-disengage)
constexpr uint16_t DISCRETE_ALARM_OFF_COURSE_SEVERE = 17;
// Rudder command sent but no feedback motion
constexpr uint16_t DISCRETE_ALARM_RUDDER_NOT_RESP = 18;
// NMEA 2000 heading PGN not received >5 s
constexpr uint16_t DISCRETE_ALARM_HEADING_LOST = 19;
// Actuator current over threshold
constexpr uint16_t DISCRETE_ALARM_ACTUATOR_OVERCURR = 20;
// Supply voltage below safe threshold
constexpr uint16_t DISCRETE_ALARM_VOLTAGE_LOW = 21;
// Rudder reached mechanical end-stop
constexpr uint16_t DISCRETE_ALARM_LIMIT_REACHED = 22;
// Firmware watchdog fired -- controller reset
constexpr uint16_t DISCRETE_ALARM_WATCHDOG_TRIPPED = 23;
// VMS reported blackout or electrical fault
constexpr uint16_t DISCRETE_ALARM_VMS_CRITICAL = 24;
// OR of all alarm bits (convenience)
constexpr uint16_t DISCRETE_ANY_ALARM_ACTIVE = 25;

// ----- Coils (read-write bits) -----
constexpr uint16_t COIL_COUNT = 4;
constexpr uint16_t COIL_MAX_ADDR = 3;

// Rising edge requests pilot engagement (subject to interlocks)
constexpr uint16_t COIL_CMD_ENGAGE_REQUEST = 0;
// Rising edge forces pilot to STANDBY
constexpr uint16_t COIL_CMD_DISENGAGE_REQUEST = 1;
// Rising edge acknowledges every active alarm
constexpr uint16_t COIL_CMD_ACK_ALL_ALARMS = 2;
// Knob arming request (Sprint 7+)
constexpr uint16_t COIL_CMD_KNOB_ARM = 3;

// ----- Input registers (read-only words) -----
constexpr uint16_t INPUT_COUNT = 39;
constexpr uint16_t INPUT_MAX_ADDR = 65;

// Firmware major version
constexpr uint16_t INPUT_FW_VERSION_MAJOR = 0;
// Firmware minor version
constexpr uint16_t INPUT_FW_VERSION_MINOR = 1;
// Firmware patch version
constexpr uint16_t INPUT_FW_VERSION_PATCH = 2;
// Modbus map schema version (0=v0.1.0)
constexpr uint16_t INPUT_SCHEMA_VERSION = 3;
// Uptime seconds, low 16 bits
// unit=s
constexpr uint16_t INPUT_UPTIME_SECONDS_LO = 4;
// Uptime seconds, high 16 bits
// unit=s
constexpr uint16_t INPUT_UPTIME_SECONDS_HI = 5;
// Current AutopilotMode (0=STANDBY,1=HH,2=TC,3=TK,4=DODGE)
constexpr uint16_t INPUT_CURRENT_MODE = 6;
// Current free heap, KiB
// unit=KiB
constexpr uint16_t INPUT_FREE_HEAP_KB = 7;
// Minimum free heap since boot
// unit=KiB
constexpr uint16_t INPUT_MIN_FREE_HEAP_KB = 8;
// Hardware ID bytes [0..1] (MAC eFuse high word)
constexpr uint16_t INPUT_HWID_MAC_01 = 9;
// Hardware ID bytes [2..3] (MAC eFuse mid word)
constexpr uint16_t INPUT_HWID_MAC_23 = 10;
// Hardware ID bytes [4..5] (MAC eFuse low word)
constexpr uint16_t INPUT_HWID_MAC_45 = 11;
// Filtered rudder angle, deg * 100 (-3500..+3500)
// unit=deg, scale=0.01
constexpr uint16_t INPUT_RUDDER_ANGLE_DEG_X100 = 16;
// Raw ADC reading after median filter (0..4095)
// unit=counts
constexpr uint16_t INPUT_RUDDER_RAW_ADC = 17;
// 1 if median filter has filled (>=5 samples)
constexpr uint16_t INPUT_RUDDER_VALID = 18;
// Current heading from NMEA 2000 PGN 127250, deg*100 (0..35999)
// unit=deg, scale=0.01
constexpr uint16_t INPUT_HEADING_DEG_X100 = 24;
// Rate of turn from PGN 127251, deg/s*100 (signed int16)
// unit=deg/s, scale=0.01
constexpr uint16_t INPUT_ROT_DPS_X100 = 25;
// Milliseconds since the last heading update (0..60000)
// unit=ms
constexpr uint16_t INPUT_HEADING_AGE_MS = 26;
// System battery voltage, V*100
// unit=V, scale=0.01
constexpr uint16_t INPUT_BATTERY_VOLTAGE_X100 = 32;
// Actuator current, A*100
// unit=A, scale=0.01
constexpr uint16_t INPUT_ACTUATOR_CURRENT_X100 = 33;
// Inner-loop rudder setpoint, deg*100 (signed int16)
// unit=deg, scale=0.01
constexpr uint16_t INPUT_PID_INNER_SETPOINT_X100 = 40;
// Last PID command, %*100 (signed int16, -10000..+10000)
// unit=%, scale=0.01
constexpr uint16_t INPUT_PID_INNER_OUTPUT_X100 = 41;
// Last PID error, deg*100 (signed int16)
// unit=deg, scale=0.01
constexpr uint16_t INPUT_PID_INNER_ERROR_X100 = 42;
// Inner-loop kp * 1000 (unsigned)
// scale=0.001
constexpr uint16_t INPUT_PID_INNER_KP_X1000 = 43;
// Inner-loop ki * 1000 (unsigned)
// scale=0.001
constexpr uint16_t INPUT_PID_INNER_KI_X1000 = 44;
// Inner-loop kd * 1000 (unsigned)
// scale=0.001
constexpr uint16_t INPUT_PID_INNER_KD_X1000 = 45;
// Outer-loop heading setpoint, deg*100 (0..35999)
// unit=deg, scale=0.01
constexpr uint16_t INPUT_PID_OUTER_HEADING_SP_X100 = 50;
// Rudder setpoint produced by outer loop, deg*100 (signed int16)
// unit=deg, scale=0.01
constexpr uint16_t INPUT_PID_OUTER_RUDDER_SP_X100 = 51;
// Outer-loop heading error, deg*100 (signed int16)
// unit=deg, scale=0.01
constexpr uint16_t INPUT_PID_OUTER_ERROR_X100 = 52;
// SOG currently used for gain scheduling, knots*10
// unit=kn, scale=0.1
constexpr uint16_t INPUT_PID_OUTER_SPEED_KN_X10 = 53;
// Outer-loop active kp * 1000
// scale=0.001
constexpr uint16_t INPUT_PID_OUTER_KP_X1000 = 54;
// Outer-loop active ki * 1000
// scale=0.001
constexpr uint16_t INPUT_PID_OUTER_KI_X1000 = 55;
// Outer-loop active kd * 1000
// scale=0.001
constexpr uint16_t INPUT_PID_OUTER_KD_X1000 = 56;
// Course Over Ground (true) from PGN 129026, deg*100 (0..35999)
// unit=deg, scale=0.01
constexpr uint16_t INPUT_COG_DEG_X100 = 60;
// Speed Over Ground from PGN 129026, knots*10 (unsigned)
// unit=kn, scale=0.1
constexpr uint16_t INPUT_SOG_KN_X10 = 61;
// Milliseconds since last COG/SOG update (0..60000)
// unit=ms
constexpr uint16_t INPUT_COG_AGE_MS = 62;
// Cross Track Error from PGN 129284, decimetres (signed int16, +stbd/-port)
// unit=dm, scale=0.1
constexpr uint16_t INPUT_XTE_DM_SIGNED = 63;
// Milliseconds since last XTE update (0..60000)
// unit=ms
constexpr uint16_t INPUT_XTE_AGE_MS = 64;
// Distance to next waypoint, metres (unsigned int16, 0..65535)
// unit=m
constexpr uint16_t INPUT_DTW_M = 65;

// ----- Holding registers (read-write words) -----
constexpr uint16_t HOLDING_COUNT = 17;
constexpr uint16_t HOLDING_MAX_ADDR = 34;

// Mode requested by operator (0=STANDBY,1=HH,2=TC,3=TK,4=DODGE)
constexpr uint16_t HOLDING_MODE_REQUEST = 0;
// Desired heading, deg*100
// unit=deg, scale=0.01
constexpr uint16_t HOLDING_HEADING_SETPOINT_X100 = 1;
// Display brightness 0..100
// unit=%
constexpr uint16_t HOLDING_BRIGHTNESS_PCT = 2;
// Alarm volume 0..100
// unit=%
constexpr uint16_t HOLDING_ALARM_VOLUME_PCT = 3;
// Dodge mode heading offset, deg*100 (signed int16)
// unit=deg, scale=0.01
constexpr uint16_t HOLDING_DODGE_OFFSET_DEG_X100 = 8;
// Requested inner-loop rudder setpoint, deg*100 (signed int16)
// unit=deg, scale=0.01
constexpr uint16_t HOLDING_PID_INNER_SETPOINT_REQ_X100 = 16;
// Requested inner-loop kp * 1000 (unsigned)
// scale=0.001
constexpr uint16_t HOLDING_PID_INNER_KP_REQ_X1000 = 17;
// Requested inner-loop ki * 1000 (unsigned)
// scale=0.001
constexpr uint16_t HOLDING_PID_INNER_KI_REQ_X1000 = 18;
// Requested inner-loop kd * 1000 (unsigned)
// scale=0.001
constexpr uint16_t HOLDING_PID_INNER_KD_REQ_X1000 = 19;
// Requested outer-loop heading setpoint, deg*100 (0..35999)
// unit=deg, scale=0.01
constexpr uint16_t HOLDING_PID_OUTER_HEADING_SP_REQ_X100 = 24;
// Requested SOG for gain scheduling, knots*10
// unit=kn, scale=0.1
constexpr uint16_t HOLDING_PID_OUTER_SPEED_KN_REQ_X10 = 25;
// Requested outer-loop base kp * 1000
// scale=0.001
constexpr uint16_t HOLDING_PID_OUTER_KP_REQ_X1000 = 26;
// Requested outer-loop base ki * 1000
// scale=0.001
constexpr uint16_t HOLDING_PID_OUTER_KI_REQ_X1000 = 27;
// Requested outer-loop base kd * 1000
// scale=0.001
constexpr uint16_t HOLDING_PID_OUTER_KD_REQ_X1000 = 28;
// Desired COG setpoint for TRUE_COURSE / TRACK_KEEPING, deg*100 (0..35999)
// unit=deg, scale=0.01
constexpr uint16_t HOLDING_TRUE_COURSE_SP_X100 = 32;
// XTE correction gain * 1000 (deg of heading correction per metre of XTE)
// scale=0.001
constexpr uint16_t HOLDING_XTE_GAIN_X1000 = 33;
// Maximum XTE heading correction, deg*100 (default 2000 = 20 deg)
// unit=deg, scale=0.01
constexpr uint16_t HOLDING_XTE_MAX_CORRECTION_X100 = 34;

}  // namespace arautopilot::protocols::modbus
