(* =====================================================================
   WRPS-CTL-003  Waterloo Road Pump Station
   10_globals.st - constants, located I/O, process image globals

   This file and 50_prog_io_mux.st are the ONLY files permitted to
   reference located variables (%I*, %Q*, %M*).  See brief section 10.
   ===================================================================== *)

VAR_GLOBAL CONSTANT
    (* Plant geometry - WRPS-PRO-001 *)
    CFG_AREA_M2     : REAL := 120.0;    (* wet well plan area, m2        *)
    CFG_SPILL_M     : REAL := 6.000;    (* spill weir level, m           *)
    CFG_LSHH_M      : REAL := 5.500;    (* LSHH level, m                 *)

    (* Drive limits - hard physical limits, section 4.3 *)
    CFG_MIN_HZ      : REAL := 38.0;
    CFG_MAX_HZ      : REAL := 50.0;

    (* Setpoint defaults, section 2.3.  Seeded into %MW at first scan. *)
    DEF_MODE        : INT := 1;         (* 1 = auto, 2 = off             *)
    DEF_SP_LEVEL    : INT := 4200;      (* mm                            *)
    DEF_START_DUTY  : INT := 4000;
    DEF_START_P2    : INT := 4500;
    DEF_START_P3    : INT := 5000;
    DEF_STOP_ALL    : INT := 1000;
    DEF_HIGH_ALARM  : INT := 5200;
    DEF_MIN_SPEED   : INT := 380;       (* Hz x 10                       *)
    DEF_SERVICE_HRS : INT := 4000;

    (* Published "meaningless / drawing down" sentinel, section 4.4 *)
    CFG_NO_TIME     : INT := 32767;
END_VAR


(* ---------------------------------------------------------------------
   2.1  Field inputs - %IW / %IX
   --------------------------------------------------------------------- *)
VAR_GLOBAL
    IW_LIT101       AT %IW0  : INT;     (* wet well level, mm 0-7000     *)
    IW_FIT201       AT %IW1  : INT;     (* inlet flow, L/s x 10          *)
    IW_FIT301       AT %IW2  : INT;     (* discharge flow, L/s x 10      *)
    IW_PIT302       AT %IW3  : INT;     (* manifold pressure, kPa        *)
    IW_PIT311       AT %IW4  : INT;     (* pump discharge pressure, kPa  *)
    IW_PIT321       AT %IW5  : INT;
    IW_PIT331       AT %IW6  : INT;
    IW_VE314        AT %IW7  : INT;     (* bearing vibration, mm/s x 10  *)
    IW_VE324        AT %IW8  : INT;
    IW_VE334        AT %IW9  : INT;

    IX_LSHH102      AT %IX0.0 : BOOL;   (* TRUE = wet                    *)
    IX_LSLL103      AT %IX0.1 : BOOL;   (* TRUE = wet, FALSE = dry       *)
    IX_LSH104       AT %IX0.2 : BOOL;   (* TRUE = spilling               *)
    IX_TE312        AT %IX0.3 : BOOL;   (* TRUE = healthy                *)
    IX_TE322        AT %IX0.4 : BOOL;
    IX_TE332        AT %IX0.5 : BOOL;
    IX_MSE313       AT %IX0.6 : BOOL;   (* TRUE = seal leak              *)
    IX_MSE323       AT %IX0.7 : BOOL;
    IX_MSE333       AT %IX1.0 : BOOL;
    IX_XA502        AT %IX1.1 : BOOL;   (* TRUE = mains healthy          *)
END_VAR


(* ---------------------------------------------------------------------
   2.2  PLC outputs - %QX / %QW, read by CI Server
   --------------------------------------------------------------------- *)
VAR_GLOBAL
    QX_RunCmd1      AT %QX0.0 : BOOL;
    QX_RunCmd2      AT %QX0.1 : BOOL;
    QX_RunCmd3      AT %QX0.2 : BOOL;
    QX_Running1     AT %QX0.3 : BOOL;
    QX_Running2     AT %QX0.4 : BOOL;
    QX_Running3     AT %QX0.5 : BOOL;
    QX_Avail1       AT %QX0.6 : BOOL;
    QX_Avail2       AT %QX0.7 : BOOL;
    QX_Avail3       AT %QX1.0 : BOOL;
    QX_InAuto       AT %QX1.1 : BOOL;
    QX_HighLevel    AT %QX1.2 : BOOL;
    QX_SpillActive  AT %QX1.3 : BOOL;
    QX_Tripped1     AT %QX1.4 : BOOL;
    QX_Tripped2     AT %QX1.5 : BOOL;
    QX_Tripped3     AT %QX1.6 : BOOL;

    QW_Level        AT %QW0  : INT;     (* mm                            *)
    QW_Inflow       AT %QW1  : INT;     (* L/s x 10                      *)
    QW_Discharge    AT %QW2  : INT;     (* L/s x 10                      *)
    QW_PumpsRunning AT %QW3  : INT;
    QW_Speed        AT %QW4  : INT;     (* Hz x 10                       *)
    QW_TimeToSpill  AT %QW5  : INT;     (* s, 32767 = drawing down       *)
    QW_TimeToLSHH   AT %QW6  : INT;     (* s, 32767 = drawing down       *)
    QW_NetAccum     AT %QW7  : INT;     (* L/s x 10, signed              *)
    QW_RunHours1    AT %QW8  : INT;     (* hours                         *)
    QW_RunHours2    AT %QW9  : INT;
    QW_RunHours3    AT %QW10 : INT;
    QW_VolToSpill   AT %QW11 : INT;     (* m3                            *)
    QW_StationState AT %QW12 : INT;     (* enum, section 3.1             *)
    QW_PumpState1   AT %QW13 : INT;     (* enum, section 3.2             *)
    QW_PumpState2   AT %QW14 : INT;
    QW_PumpState3   AT %QW15 : INT;
    QW_DutyPump     AT %QW16 : INT;     (* 0 = none, 1-3                 *)
    QW_AlarmWord    AT %QW17 : INT;     (* bitmask, section 6, unsigned  *)
    QW_CmdAck       AT %QW20 : INT;     (* echoes %MW1 when executed     *)
END_VAR


(* ---------------------------------------------------------------------
   2.3  Commands and setpoints - %MW, written by CI Server

   NOTE: on this runtime %MW is NOT Modbus holding register 0.  The
   v4 Modbus slave segments holding registers: %QW occupies HR 0-1023
   and %MW starts at HR 1024.  %MW0 is therefore HR 1024.  See
   docs/register-map.csv, which carries the offset.
   --------------------------------------------------------------------- *)
VAR_GLOBAL
    MW_Mode         AT %MW0  : INT;     (* 1 = auto, 2 = off             *)
    MW_CmdWord      AT %MW1  : INT;     (* section 3.3                   *)
    MW_CmdParam     AT %MW2  : INT;     (* pump number, etc.             *)
    MW_SpLevel      AT %MW3  : INT;     (* level control setpoint, mm    *)
    MW_StartDuty    AT %MW4  : INT;
    MW_StartP2      AT %MW5  : INT;
    MW_StartP3      AT %MW6  : INT;
    MW_StopAll      AT %MW7  : INT;
    MW_HighAlarm    AT %MW8  : INT;
    MW_MinSpeed     AT %MW9  : INT;     (* Hz x 10                       *)
    MW_ServiceHrs   AT %MW10 : INT;     (* hours                         *)
END_VAR


(* ---------------------------------------------------------------------
   2.4  Simulation control - %MW20-23, section 8.2

   Section 2 calls this block "simulation build only".  It is declared
   here in both builds instead, because located variables may only be
   declared in this file and splitting it would need a second file with
   located-variable permission.  In the field build these registers are
   simply unused: nothing reads them, since PROGRAM SIMULATION is not
   part of that build.  register-map.csv marks them sim-only.
   --------------------------------------------------------------------- *)
VAR_GLOBAL
    MW_SimInflow    AT %MW20 : INT;     (* manual inflow, L/s x 10       *)
    MW_SimMode      AT %MW21 : INT;     (* 0 man, 1 diurnal, 2 wet, 3 ref *)
    MW_SimReset     AT %MW22 : INT;     (* write 1 to reset; self-clears *)
    MW_SimTimeScale AT %MW23 : INT;     (* 1-120, default 1              *)
END_VAR


(* ---------------------------------------------------------------------
   Process image globals.

   IO_MUX writes these from the located variables above; CONTROL reads
   only these.  In the pass 2 simulation build the same globals are
   written from PROGRAM SIMULATION instead, and no control POU changes.
   --------------------------------------------------------------------- *)
VAR_GLOBAL
    g_LevelRaw_mm   : INT;              (* unconditioned, for fault test *)
    g_Level_mm      : INT;
    g_Level_m       : REAL;
    g_Inflow_Lps    : REAL;
    g_Disch_Lps     : REAL;
    g_ManifoldP_kPa : REAL;
    g_PumpP_kPa     : ARRAY[1..3] OF REAL;
    g_Vib_mms       : ARRAY[1..3] OF REAL;

    g_LSHH          : BOOL;             (* TRUE = high high, wet         *)
    g_LSLL_Wet      : BOOL;             (* TRUE = wet; FALSE = dry       *)
    g_SpillDetected : BOOL;
    g_ThermalOK     : ARRAY[1..3] OF BOOL;
    g_SealLeak      : ARRAY[1..3] OF BOOL;
    g_MainsOK       : BOOL;
END_VAR

(* Raw command / setpoint image, copied from %MW by IO_MUX.
   CONTROL validates and clamps these before use. *)
VAR_GLOBAL
    g_cmd_Mode      : INT;
    g_cmd_Word      : INT;
    g_cmd_Param     : INT;
    g_sp_Level      : INT;
    g_sp_StartDuty  : INT;
    g_sp_StartP2    : INT;
    g_sp_StartP3    : INT;
    g_sp_StopAll    : INT;
    g_sp_HighAlarm  : INT;
    g_sp_MinSpeed   : INT;
    g_sp_ServiceHrs : INT;
END_VAR

(* Published values, written by CONTROL, copied to %QW / %QX by IO_MUX. *)
VAR_GLOBAL
    g_o_RunCmd      : ARRAY[1..3] OF BOOL;
    g_o_Running     : ARRAY[1..3] OF BOOL;
    g_o_Available   : ARRAY[1..3] OF BOOL;
    g_o_Tripped     : ARRAY[1..3] OF BOOL;
    g_o_InAuto      : BOOL;
    g_o_HighLevel   : BOOL;
    g_o_SpillActive : BOOL;

    g_o_Level_mm    : INT;
    g_o_Inflow_x10  : INT;
    g_o_Disch_x10   : INT;
    g_o_PumpsRun    : INT;
    g_o_Speed_x10   : INT;
    g_o_TimeToSpill : INT;
    g_o_TimeToLSHH  : INT;
    g_o_NetAccum    : INT;
    g_o_RunHours    : ARRAY[1..3] OF INT;
    g_o_VolToSpill  : INT;
    g_o_StationState: INT;
    g_o_PumpState   : ARRAY[1..3] OF INT;
    g_o_DutyPump    : INT;
    g_o_AlarmWord   : INT;
    g_o_CmdAck      : INT;
END_VAR


(* ---------------------------------------------------------------------
   Simulation image, section 8.

   PROGRAM SIMULATION writes these; IO_MUX copies them into the process
   image above when g_SimActive is TRUE, in place of %IW / %IX.  In the
   field build SIMULATION is absent, g_SimActive stays FALSE, and none
   of these are ever written.

   g_SimActive is set by SIMULATION every scan rather than declared
   TRUE here, so the field build cannot accidentally mux in an
   all-zero simulation image.  In the simulation build SIMULATION is
   scheduled before IO_MUX, so it is already TRUE - and the simulated
   image already populated - on the first scan.  That ordering is not
   cosmetic: see 91_config_sim.st.
   --------------------------------------------------------------------- *)
VAR_GLOBAL
    g_SimActive     : BOOL;             (* FALSE in the field build      *)
    g_sim_ClearReset : BOOL;            (* SIMULATION -> IO_MUX, clears %MW22 *)

    g_simcmd_Inflow    : INT;           (* copies of %MW20-23 for SIMULATION *)
    g_simcmd_Mode      : INT;
    g_simcmd_Reset     : INT;
    g_simcmd_TimeScale : INT;

    g_sim_Level_mm  : INT;
    g_sim_Inflow_x10 : INT;
    g_sim_Disch_x10 : INT;
    g_sim_ManifoldP : INT;
    g_sim_PumpP     : ARRAY[1..3] OF INT;
    g_sim_Vib_x10   : ARRAY[1..3] OF INT;

    g_sim_LSHH      : BOOL;
    g_sim_LSLL_Wet  : BOOL;
    g_sim_Spill     : BOOL;
    g_sim_ThermalOK : ARRAY[1..3] OF BOOL;
    g_sim_SealLeak  : ARRAY[1..3] OF BOOL;
    g_sim_MainsOK   : BOOL;
END_VAR
