// Generated by STruC++ - IEC 61131-3 Structured Text to C++ Compiler
// Do not edit this file manually.

#include "generated.hpp"

namespace strucpp {

Program_SIMULATION::Program_SIMULATION(GlobalVar<IEC_INT>* G_SIMCMD_INFLOW_ref, GlobalVar<IEC_INT>* G_SIMCMD_MODE_ref, GlobalVar<IEC_INT>* G_SIMCMD_RESET_ref, GlobalVar<IEC_INT>* G_SIMCMD_TIMESCALE_ref, GlobalVar<Array1D<IEC_BOOL, 1, 3>>* G_O_RUNCMD_ref, GlobalVar<IEC_INT>* G_O_SPEED_X10_ref, GlobalVar<IEC_BOOL>* G_SIMACTIVE_ref, GlobalVar<IEC_BOOL>* G_SIM_CLEARRESET_ref, GlobalVar<IEC_INT>* G_SIM_LEVEL_MM_ref, GlobalVar<IEC_INT>* G_SIM_INFLOW_X10_ref, GlobalVar<IEC_INT>* G_SIM_DISCH_X10_ref, GlobalVar<IEC_INT>* G_SIM_MANIFOLDP_ref, GlobalVar<Array1D<IEC_INT, 1, 3>>* G_SIM_PUMPP_ref, GlobalVar<Array1D<IEC_INT, 1, 3>>* G_SIM_VIB_X10_ref, GlobalVar<IEC_BOOL>* G_SIM_LSHH_ref, GlobalVar<IEC_BOOL>* G_SIM_LSLL_WET_ref, GlobalVar<IEC_BOOL>* G_SIM_SPILL_ref, GlobalVar<Array1D<IEC_BOOL, 1, 3>>* G_SIM_THERMALOK_ref, GlobalVar<Array1D<IEC_BOOL, 1, 3>>* G_SIM_SEALLEAK_ref, GlobalVar<IEC_BOOL>* G_SIM_MAINSOK_ref)
    : SCAN_S(0.1), AREA_M2(120.0), SPILL_M(6.0), LSHH_M(5.5), LSLL_M(0.30), START_DLY_S(3.0), HZ_LO(38.0), HZ_HI(50.0), Q_LO(65.0), Q_HI(120.0), P_IDLE(80.0), P_BASE(220.0), P_PER_LPS(1.4), VIB_IDLE(0.2), VIB_BASE(1.5), VIB_PER_LPS(0.02), INIT(false), VOLUME_M3(0.0), LEVEL_M(0.0), INFLOW_LPS(0.0), SUMFLOW_LPS(0.0), SIMCLOCK_S(0.0), TIMESCALE(0.0), DT_S(0.0), SPEED_HZ(0.0), UNITQ_LPS(0.0), DERATE(0.0), NDELIVERING(0), I(0), RND(12345), NOISE(0.0), G_SIMCMD_INFLOW(G_SIMCMD_INFLOW_ref), G_SIMCMD_MODE(G_SIMCMD_MODE_ref), G_SIMCMD_RESET(G_SIMCMD_RESET_ref), G_SIMCMD_TIMESCALE(G_SIMCMD_TIMESCALE_ref), G_O_RUNCMD(G_O_RUNCMD_ref), G_O_SPEED_X10(G_O_SPEED_X10_ref), G_SIMACTIVE(G_SIMACTIVE_ref), G_SIM_CLEARRESET(G_SIM_CLEARRESET_ref), G_SIM_LEVEL_MM(G_SIM_LEVEL_MM_ref), G_SIM_INFLOW_X10(G_SIM_INFLOW_X10_ref), G_SIM_DISCH_X10(G_SIM_DISCH_X10_ref), G_SIM_MANIFOLDP(G_SIM_MANIFOLDP_ref), G_SIM_PUMPP(G_SIM_PUMPP_ref), G_SIM_VIB_X10(G_SIM_VIB_X10_ref), G_SIM_LSHH(G_SIM_LSHH_ref), G_SIM_LSLL_WET(G_SIM_LSLL_WET_ref), G_SIM_SPILL(G_SIM_SPILL_ref), G_SIM_THERMALOK(G_SIM_THERMALOK_ref), G_SIM_SEALLEAK(G_SIM_SEALLEAK_ref), G_SIM_MAINSOK(G_SIM_MAINSOK_ref)
{
}

void Program_SIMULATION::run() {
    G_SIM_CLEARRESET->write(false);
    if (((!INIT)) | ((G_SIMCMD_RESET->read() == 1))) {
        INIT = true;
        G_SIM_CLEARRESET->write(true);
        SIMCLOCK_S = 0.0;
        if (G_SIMCMD_MODE->read() == 3) {
            LEVEL_M = 4.0;
        } else {
            LEVEL_M = 3.5;
        }
        VOLUME_M3 = LEVEL_M * AREA_M2;
        for (I = 1; I <= 3; I++) {
            STARTDLY_S.at(I) = 0.0;
            DELIVERING.at(I) = false;
            FLOW_LPS.at(I) = 0.0;
            PRESS_KPA.at(I) = P_IDLE;
            VIB_MMS.at(I) = VIB_IDLE;
        }
    }
    if (((G_SIMCMD_TIMESCALE->read() >= 1)) & ((G_SIMCMD_TIMESCALE->read() <= 120))) {
        TIMESCALE = TO_REAL(G_SIMCMD_TIMESCALE->read());
    } else {
        TIMESCALE = 1.0;
    }
    DT_S = SCAN_S * TIMESCALE;
    SIMCLOCK_S = SIMCLOCK_S + DT_S;
    switch (G_SIMCMD_MODE->read()) {
        case 1:
            INFLOW_LPS = 75.0 + 35.0 * SIN(6.283185 * SIMCLOCK_S / 86400.0);
            break;
        case 2:
            if (SIMCLOCK_S < 1200.0) {
                INFLOW_LPS = 75.0 + (300.0 - 75.0) * SIMCLOCK_S / 1200.0;
            } else if (SIMCLOCK_S < 3600.0) {
                INFLOW_LPS = 300.0;
            } else if (SIMCLOCK_S < 9000.0) {
                INFLOW_LPS = 300.0 - (300.0 - 75.0) * (SIMCLOCK_S - 3600.0) / 5400.0;
            } else {
                INFLOW_LPS = 75.0;
            }
            break;
        case 3:
            INFLOW_LPS = 165.0;
            break;
        default:
            INFLOW_LPS = TO_REAL(G_SIMCMD_INFLOW->read()) / 10.0;
            break;
    }
    if (INFLOW_LPS < 0.0) {
        INFLOW_LPS = 0.0;
    }
    SPEED_HZ = TO_REAL(G_O_SPEED_X10->read()) / 10.0;
    if (SPEED_HZ < HZ_LO) {
        UNITQ_LPS = 0.0;
    } else {
        if (SPEED_HZ > HZ_HI) {
            SPEED_HZ = HZ_HI;
        }
        UNITQ_LPS = Q_LO + (SPEED_HZ - HZ_LO) * (Q_HI - Q_LO) / (HZ_HI - HZ_LO);
    }
    NDELIVERING = 0;
    for (I = 1; I <= 3; I++) {
        if (G_O_RUNCMD->with_lock([&](auto* __glk){ return (*__glk).at(I); })) {
            if (STARTDLY_S.at(I) < START_DLY_S) {
                STARTDLY_S.at(I) = STARTDLY_S.at(I) + SCAN_S;
            }
            DELIVERING.at(I) = ((STARTDLY_S.at(I) >= START_DLY_S)) & ((UNITQ_LPS > 0.0));
        } else {
            STARTDLY_S.at(I) = 0.0;
            DELIVERING.at(I) = false;
        }
        if (DELIVERING.at(I)) {
            NDELIVERING = NDELIVERING + 1;
        }
    }
    switch (NDELIVERING) {
        case 1:
            DERATE = 1.0;
            break;
        case 2:
            DERATE = 0.94;
            break;
        case 3:
            DERATE = 0.88;
            break;
        default:
            DERATE = 1.0;
            break;
    }
    SUMFLOW_LPS = 0.0;
    for (I = 1; I <= 3; I++) {
        if (DELIVERING.at(I)) {
            FLOW_LPS.at(I) = UNITQ_LPS * DERATE;
            PRESS_KPA.at(I) = P_BASE + P_PER_LPS * FLOW_LPS.at(I);
            VIB_MMS.at(I) = VIB_BASE + VIB_PER_LPS * FLOW_LPS.at(I);
            SUMFLOW_LPS = SUMFLOW_LPS + FLOW_LPS.at(I);
        } else {
            FLOW_LPS.at(I) = 0.0;
            PRESS_KPA.at(I) = P_IDLE;
            if (G_O_RUNCMD->with_lock([&](auto* __glk){ return (*__glk).at(I); })) {
                VIB_MMS.at(I) = VIB_BASE;
            } else {
                VIB_MMS.at(I) = VIB_IDLE;
            }
        }
    }
    VOLUME_M3 = VOLUME_M3 + (INFLOW_LPS - SUMFLOW_LPS) * DT_S / 1000.0;
    if (VOLUME_M3 < 0.0) {
        VOLUME_M3 = 0.0;
    }
    if (VOLUME_M3 > SPILL_M * AREA_M2) {
        VOLUME_M3 = SPILL_M * AREA_M2;
    }
    LEVEL_M = VOLUME_M3 / AREA_M2;
    RND = (RND * 75 + 74) % 65537;
    NOISE = (TO_REAL(RND) / 65536.0 - 0.5) * 0.01;
    G_SIM_LEVEL_MM->write(TO_INT(LEVEL_M * 1000.0 * (1.0 + NOISE)));
    RND = (RND * 75 + 74) % 65537;
    NOISE = (TO_REAL(RND) / 65536.0 - 0.5) * 0.04;
    G_SIM_INFLOW_X10->write(TO_INT(INFLOW_LPS * 10.0 * (1.0 + NOISE)));
    RND = (RND * 75 + 74) % 65537;
    NOISE = (TO_REAL(RND) / 65536.0 - 0.5) * 0.04;
    G_SIM_DISCH_X10->write(TO_INT(SUMFLOW_LPS * 10.0 * (1.0 + NOISE)));
    for (I = 1; I <= 3; I++) {
        auto __gwv_18 = TO_INT(PRESS_KPA.at(I));
        G_SIM_PUMPP->with_lock([&](auto* __glk){ (*__glk).at(I) = __gwv_18; });
        auto __gwv_19 = TO_INT(VIB_MMS.at(I) * 10.0);
        G_SIM_VIB_X10->with_lock([&](auto* __glk){ (*__glk).at(I) = __gwv_19; });
    }
    G_SIM_MANIFOLDP->write(TO_INT(P_IDLE));
    if (NDELIVERING > 0) {
        G_SIM_MANIFOLDP->write(TO_INT(P_BASE + P_PER_LPS * UNITQ_LPS * DERATE));
    }
    G_SIM_LSHH->write(LEVEL_M >= LSHH_M);
    G_SIM_LSLL_WET->write(LEVEL_M > LSLL_M);
    G_SIM_SPILL->write(LEVEL_M >= (SPILL_M - 0.001));
    for (I = 1; I <= 3; I++) {
        auto __gwv_20 = true;
        G_SIM_THERMALOK->with_lock([&](auto* __glk){ (*__glk).at(I) = __gwv_20; });
        auto __gwv_21 = false;
        G_SIM_SEALLEAK->with_lock([&](auto* __glk){ (*__glk).at(I) = __gwv_21; });
    }
    G_SIM_MAINSOK->write(true);
    G_SIMACTIVE->write(true);
}

}  // namespace strucpp