mirror of
https://github.com/MikaylaFischler/cc-mek-scada.git
synced 2024-08-30 18:22:34 +00:00
parent
eb8aab175f
commit
2e78aa895d
@ -23,9 +23,11 @@ local io = {}
|
||||
function iocontrol.init(conf, comms)
|
||||
---@class ioctl_facility
|
||||
io.facility = {
|
||||
auto_ready = false,
|
||||
auto_active = false,
|
||||
auto_ramping = false,
|
||||
auto_scram = false,
|
||||
---@todo not currently used or set
|
||||
auto_scram_cause = "ok", ---@type auto_scram_cause
|
||||
|
||||
num_units = conf.num_units, ---@type integer
|
||||
@ -271,19 +273,21 @@ function iocontrol.update_facility_status(status)
|
||||
local ctl_status = status[1]
|
||||
|
||||
if type(ctl_status) == "table" then
|
||||
fac.auto_active = ctl_status[1] > 0
|
||||
fac.auto_ramping = ctl_status[2]
|
||||
fac.auto_scram = ctl_status[3]
|
||||
fac.status_line_1 = ctl_status[4]
|
||||
fac.status_line_2 = ctl_status[5]
|
||||
fac.auto_ready = ctl_status[1]
|
||||
fac.auto_active = ctl_status[2] > 0
|
||||
fac.auto_ramping = ctl_status[3]
|
||||
fac.auto_scram = ctl_status[4]
|
||||
fac.status_line_1 = ctl_status[5]
|
||||
fac.status_line_2 = ctl_status[6]
|
||||
|
||||
fac.ps.publish("auto_ready", fac.auto_ready)
|
||||
fac.ps.publish("auto_active", fac.auto_active)
|
||||
fac.ps.publish("auto_ramping", fac.auto_ramping)
|
||||
fac.ps.publish("auto_scram", fac.auto_scram)
|
||||
fac.ps.publish("status_line_1", fac.status_line_1)
|
||||
fac.ps.publish("status_line_2", fac.status_line_2)
|
||||
|
||||
local group_map = ctl_status[6]
|
||||
local group_map = ctl_status[7]
|
||||
|
||||
if (type(group_map) == "table") and (#group_map == fac.num_units) then
|
||||
local names = { "Manual", "Primary", "Secondary", "Tertiary", "Backup" }
|
||||
@ -634,10 +638,12 @@ function iocontrol.update_unit_statuses(statuses)
|
||||
local unit_state = status[5]
|
||||
|
||||
if type(unit_state) == "table" then
|
||||
if #unit_state == 3 then
|
||||
if #unit_state == 5 then
|
||||
unit.reactor_ps.publish("U_StatusLine1", unit_state[1])
|
||||
unit.reactor_ps.publish("U_StatusLine2", unit_state[2])
|
||||
unit.reactor_ps.publish("U_WasteMode", unit_state[3])
|
||||
unit.reactor_ps.publish("U_WasteMode", unit_state[3])
|
||||
unit.reactor_ps.publish("U_AutoReady", unit_state[4])
|
||||
unit.reactor_ps.publish("U_AutoDegraded", unit_state[5])
|
||||
else
|
||||
log.debug(log_header .. "unit state length mismatch")
|
||||
end
|
||||
|
@ -19,7 +19,7 @@ local iocontrol = require("coordinator.iocontrol")
|
||||
local renderer = require("coordinator.renderer")
|
||||
local sounder = require("coordinator.sounder")
|
||||
|
||||
local COORDINATOR_VERSION = "beta-v0.8.11"
|
||||
local COORDINATOR_VERSION = "beta-v0.8.12"
|
||||
|
||||
local print = util.print
|
||||
local println = util.println
|
||||
|
@ -30,6 +30,8 @@ local TEXT_ALIGN = core.graphics.TEXT_ALIGN
|
||||
local cpair = core.graphics.cpair
|
||||
local border = core.graphics.border
|
||||
|
||||
local period = core.flasher.PERIOD
|
||||
|
||||
-- new process control view
|
||||
---@param root graphics_element parent
|
||||
---@param x integer top left x
|
||||
@ -48,6 +50,22 @@ local function new_view(root, x, y)
|
||||
|
||||
facility.scram_ack = scram.on_response
|
||||
|
||||
local auto_act = IndicatorLight{parent=main,y=5,label="Auto Active",colors=cpair(colors.green,colors.gray)}
|
||||
local auto_ramp = IndicatorLight{parent=main,label="Auto Ramping",colors=cpair(colors.white,colors.gray),flash=true,period=period.BLINK_250_MS}
|
||||
local auto_scram = IndicatorLight{parent=main,label="Auto SCRAM",colors=cpair(colors.red,colors.gray),flash=true,period=period.BLINK_250_MS}
|
||||
|
||||
facility.ps.subscribe("auto_active", auto_act.update)
|
||||
facility.ps.subscribe("auto_ramping", auto_ramp.update)
|
||||
facility.ps.subscribe("auto_scram", auto_scram.update)
|
||||
|
||||
main.line_break()
|
||||
|
||||
local _ = IndicatorLight{parent=main,label="Unit Off-line",colors=cpair(colors.yellow,colors.gray),flash=true,period=period.BLINK_1000_MS}
|
||||
local _ = IndicatorLight{parent=main,label="Unit RPS Trip",colors=cpair(colors.red,colors.gray),flash=true,period=period.BLINK_250_MS}
|
||||
local _ = IndicatorLight{parent=main,label="Unit Critical Alarm",colors=cpair(colors.red,colors.gray),flash=true,period=period.BLINK_250_MS}
|
||||
local _ = IndicatorLight{parent=main,label="High Charge Level",colors=cpair(colors.red,colors.gray),flash=true,period=period.BLINK_250_MS}
|
||||
|
||||
|
||||
---------------------
|
||||
-- process control --
|
||||
---------------------
|
||||
@ -134,6 +152,9 @@ local function new_view(root, x, y)
|
||||
local stat_line_1 = TextBox{parent=u_stat,x=1,y=1,text="UNKNOWN",width=31,height=1,alignment=TEXT_ALIGN.CENTER,fg_bg=bw_fg_bg}
|
||||
local stat_line_2 = TextBox{parent=u_stat,x=1,y=2,text="awaiting data",width=31,height=1,alignment=TEXT_ALIGN.CENTER,fg_bg=cpair(colors.gray, colors.white)}
|
||||
|
||||
facility.ps.subscribe("status_line_1", stat_line_1.set_value)
|
||||
facility.ps.subscribe("status_line_2", stat_line_2.set_value)
|
||||
|
||||
local auto_controls = Div{parent=proc,x=1,y=20,width=31,height=5,fg_bg=cpair(colors.gray,colors.white)}
|
||||
|
||||
-- save the automatic process control configuration without starting
|
||||
@ -160,6 +181,36 @@ local function new_view(root, x, y)
|
||||
function facility.save_cfg_ack(ack)
|
||||
tcd.dispatch(0.2, function () save.on_response(ack) end)
|
||||
end
|
||||
|
||||
facility.ps.subscribe("auto_ready", function (ready)
|
||||
if ready and (not facility.auto_active) then start.enable() else start.disable() end
|
||||
end)
|
||||
|
||||
facility.ps.subscribe("auto_active", function (active)
|
||||
if active then
|
||||
b_target.disable()
|
||||
c_target.disable()
|
||||
g_target.disable()
|
||||
|
||||
mode.disable()
|
||||
start.disable()
|
||||
|
||||
for i = 1, #rate_limits do
|
||||
rate_limits[i].disable()
|
||||
end
|
||||
else
|
||||
b_target.enable()
|
||||
c_target.enable()
|
||||
g_target.enable()
|
||||
|
||||
mode.enable()
|
||||
if facility.auto_ready then start.enable() end
|
||||
|
||||
for i = 1, #rate_limits do
|
||||
rate_limits[i].enable()
|
||||
end
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
return new_view
|
||||
|
@ -474,17 +474,14 @@ local function init(parent, id)
|
||||
|
||||
auto_div.line_break()
|
||||
|
||||
local a_act = IndicatorLight{parent=auto_div,label="Active",x=2,colors=cpair(colors.green,colors.gray)}
|
||||
local a_stb = IndicatorLight{parent=auto_div,label="Standby",x=2,colors=cpair(colors.white,colors.gray)}
|
||||
local a_rdy = IndicatorLight{parent=auto_div,label="Ready",x=2,colors=cpair(colors.green,colors.gray)}
|
||||
local a_stb = IndicatorLight{parent=auto_div,label="Standby",x=2,colors=cpair(colors.white,colors.gray),flash=true,period=period.BLINK_1000_MS}
|
||||
|
||||
r_ps.subscribe("U_AutoReady", a_rdy.update)
|
||||
|
||||
-- update standby indicator
|
||||
r_ps.subscribe("status", function (active)
|
||||
if unit.annunciator.AutoControl then
|
||||
a_act.update(active)
|
||||
a_stb.update(not active)
|
||||
else
|
||||
a_act.update(false)
|
||||
a_stb.update(false)
|
||||
end
|
||||
a_stb.update(unit.annunciator.AutoControl and (not active))
|
||||
end)
|
||||
|
||||
-- enable and disable controls based on auto control state (start button is handled separately)
|
||||
@ -495,13 +492,11 @@ local function init(parent, id)
|
||||
burn_rate.disable()
|
||||
set_burn_btn.disable()
|
||||
set_grp_btn.disable()
|
||||
a_act.update(unit.reactor_data.mek_status.status == true)
|
||||
a_stb.update(unit.reactor_data.mek_status.status == false)
|
||||
else
|
||||
burn_rate.enable()
|
||||
set_burn_btn.enable()
|
||||
set_grp_btn.enable()
|
||||
a_act.update(false)
|
||||
a_stb.update(false)
|
||||
end
|
||||
end)
|
||||
|
@ -16,8 +16,6 @@ local TextBox = require("graphics.elements.textbox")
|
||||
|
||||
local TEXT_ALIGN = core.graphics.TEXT_ALIGN
|
||||
|
||||
local cpair = core.graphics.cpair
|
||||
local border = core.graphics.border
|
||||
local pipe = core.graphics.pipe
|
||||
|
||||
-- make a new unit overview window
|
||||
|
@ -49,26 +49,31 @@ local function init(monitor)
|
||||
local uo_1, uo_2, uo_3, uo_4 ---@type graphics_element
|
||||
|
||||
local cnc_y_start = 3
|
||||
local row_1_height = 0
|
||||
|
||||
-- unit overviews
|
||||
if facility.num_units >= 1 then
|
||||
uo_1 = unit_overview(main, 2, 3, units[1])
|
||||
cnc_y_start = cnc_y_start + uo_1.height() + 1
|
||||
row_1_height = uo_1.height()
|
||||
end
|
||||
|
||||
if facility.num_units >= 2 then
|
||||
uo_2 = unit_overview(main, 84, 3, units[2])
|
||||
row_1_height = math.max(row_1_height, uo_2.height())
|
||||
end
|
||||
|
||||
cnc_y_start = cnc_y_start + row_1_height + 1
|
||||
|
||||
if facility.num_units >= 3 then
|
||||
-- base offset 3, spacing 1, max height of units 1 and 2
|
||||
local row_2_offset = 3 + 1 + math.max(uo_1.height(), uo_2.height())
|
||||
local row_2_offset = cnc_y_start
|
||||
|
||||
uo_3 = unit_overview(main, 2, row_2_offset, units[3])
|
||||
cnc_y_start = cnc_y_start + uo_3.height() + 1
|
||||
cnc_y_start = row_2_offset + uo_3.height() + 1
|
||||
|
||||
if facility.num_units == 4 then
|
||||
uo_4 = unit_overview(main, 84, row_2_offset, units[4])
|
||||
cnc_y_start = math.max(cnc_y_start, row_2_offset + uo_4.height() + 1)
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -40,8 +40,9 @@ function facility.new(num_reactors, cooling_conf)
|
||||
units = {},
|
||||
induction = {},
|
||||
redstone = {},
|
||||
status_text = { "IDLE", "control inactive" },
|
||||
status_text = { "START UP", "initializing..." },
|
||||
-- process control
|
||||
units_ready = false,
|
||||
mode = PROCESS.INACTIVE,
|
||||
last_mode = PROCESS.INACTIVE,
|
||||
mode_set = PROCESS.SIMPLE,
|
||||
@ -234,7 +235,10 @@ function facility.new(num_reactors, cooling_conf)
|
||||
log.debug(util.c("FAC: starting auto control: chg_conv = ", self.charge_conversion, ", blade_count = ", blade_count, ", max_burn = ", self.max_burn_combined))
|
||||
elseif self.mode == PROCESS.INACTIVE then
|
||||
for i = 1, #self.prio_defs do
|
||||
-- SCRAM reactors and disengage auto control
|
||||
-- use manual SCRAM since inactive was requested, and automatic SCRAM trips an alarm
|
||||
for _, u in pairs(self.prio_defs[i]) do
|
||||
u.scram()
|
||||
u.a_disengage()
|
||||
end
|
||||
end
|
||||
@ -249,7 +253,21 @@ function facility.new(num_reactors, cooling_conf)
|
||||
self.initial_ramp = false
|
||||
end
|
||||
|
||||
if self.mode == PROCESS.SIMPLE then
|
||||
if self.mode == PROCESS.INACTIVE then
|
||||
-- check if we are ready to start when that time comes
|
||||
self.units_ready = true
|
||||
for i = 1, #self.prio_defs do
|
||||
for _, u in pairs(self.prio_defs[i]) do
|
||||
self.units_ready = self.units_ready and u.get_control_inf().ready
|
||||
end
|
||||
end
|
||||
|
||||
if self.units_ready then
|
||||
self.status_text = { "IDLE", "control disengaged" }
|
||||
else
|
||||
self.status_text = { "NOT READY", "assigned units not ready" }
|
||||
end
|
||||
elseif self.mode == PROCESS.SIMPLE then
|
||||
-- run units at their last configured set point
|
||||
if state_changed then
|
||||
self.time_start = now
|
||||
@ -504,6 +522,8 @@ function facility.new(num_reactors, cooling_conf)
|
||||
ready = false
|
||||
end
|
||||
|
||||
ready = ready and self.units_ready
|
||||
|
||||
if ready then self.mode = self.mode_set end
|
||||
end
|
||||
|
||||
@ -550,6 +570,7 @@ function facility.new(num_reactors, cooling_conf)
|
||||
-- get automatic process control status
|
||||
function public.get_control_status()
|
||||
return {
|
||||
self.units_ready,
|
||||
self.mode,
|
||||
self.waiting_on_ramp,
|
||||
self.ascram,
|
||||
|
@ -448,6 +448,7 @@ function plc.new_session(id, for_reactor, in_queue, out_queue)
|
||||
|
||||
self.acks.burn_rate = ack ~= PLC_AUTO_ACK.FAIL
|
||||
|
||||
---@todo implement error handling here
|
||||
if ack == PLC_AUTO_ACK.FAIL then
|
||||
elseif ack == PLC_AUTO_ACK.DIRECT_SET_OK then
|
||||
elseif ack == PLC_AUTO_ACK.RAMP_SET_OK then
|
||||
|
@ -174,6 +174,8 @@ function unit.new(for_reactor, num_boilers, num_turbines)
|
||||
-- fields for facility control
|
||||
---@class unit_control
|
||||
control = {
|
||||
ready = false,
|
||||
degraded = false,
|
||||
blade_count = 0,
|
||||
br10 = 0,
|
||||
lim_br10 = 0
|
||||
@ -398,7 +400,7 @@ function unit.new(for_reactor, num_boilers, num_turbines)
|
||||
if self.plc_i ~= nil then
|
||||
self.plc_i.auto_set_burn(self.db.control.br10 / 10, ramp)
|
||||
|
||||
if ramp then self.ramp_target_br10 = self.db.control.br10 / 10 end
|
||||
if ramp then self.ramp_target_br10 = self.db.control.br10 end
|
||||
end
|
||||
end
|
||||
end
|
||||
@ -407,8 +409,9 @@ function unit.new(for_reactor, num_boilers, num_turbines)
|
||||
---@return boolean complete
|
||||
function public.a_ramp_complete()
|
||||
if self.plc_i ~= nil then
|
||||
return (math.floor(self.plc_i.get_db().mek_status.burn_rate * 10) == self.ramp_target_br10) or (self.ramp_target_br10 == 0)
|
||||
else return false end
|
||||
local cur_rate = math.floor(self.plc_i.get_db().mek_status.burn_rate * 10)
|
||||
return (cur_rate == self.ramp_target_br10) or (self.ramp_target_br10 == 0)
|
||||
else return true end
|
||||
end
|
||||
|
||||
-- perform an automatic SCRAM
|
||||
@ -428,6 +431,7 @@ function unit.new(for_reactor, num_boilers, num_turbines)
|
||||
if self.plc_s ~= nil and not self.plc_s.open then
|
||||
self.plc_s = nil
|
||||
self.plc_i = nil
|
||||
self.db.control.br10 = 0
|
||||
self.db.control.lim_br10 = 0
|
||||
end
|
||||
|
||||
@ -436,6 +440,9 @@ function unit.new(for_reactor, num_boilers, num_turbines)
|
||||
_unlink_disconnected_units(self.turbines)
|
||||
_unlink_disconnected_units(self.redstone)
|
||||
|
||||
-- update degraded state for auto control
|
||||
self.db.control.degraded = (#self.boilers ~= num_boilers) or (#self.turbines ~= num_turbines) or (self.plc_i == nil)
|
||||
|
||||
-- update deltas
|
||||
_dt__compute_all()
|
||||
|
||||
@ -606,9 +613,9 @@ function unit.new(for_reactor, num_boilers, num_turbines)
|
||||
-- get information required for automatic reactor control
|
||||
function public.get_control_inf() return self.db.control end
|
||||
|
||||
-- get unit state (currently only waste mode)
|
||||
-- get unit state
|
||||
function public.get_state()
|
||||
return { self.status_text[1], self.status_text[2], self.waste_mode }
|
||||
return { self.status_text[1], self.status_text[2], self.waste_mode, self.db.control.ready, self.db.control.degraded }
|
||||
end
|
||||
|
||||
-- get the reactor ID
|
||||
|
@ -38,9 +38,17 @@ function logic.update_annunciator(self)
|
||||
-- check PLC status
|
||||
self.db.annunciator.PLCOnline = self.plc_i ~= nil
|
||||
|
||||
local plc_ready = self.db.annunciator.PLCOnline
|
||||
|
||||
if self.db.annunciator.PLCOnline then
|
||||
local plc_db = self.plc_i.get_db()
|
||||
|
||||
-- update ready state
|
||||
-- - can't be tripped
|
||||
-- - must have received status at least once
|
||||
-- - must have received struct at least once
|
||||
plc_ready = (not plc_db.rps_tripped) and (plc_db.last_status_update > 0) and (plc_db.mek_struct.length > 0)
|
||||
|
||||
-- update auto control limit
|
||||
if (self.db.control.lim_br10 == 0) or ((self.db.control.lim_br10 / 10) > plc_db.mek_struct.max_burn) then
|
||||
self.db.control.lim_br10 = math.floor(plc_db.mek_struct.max_burn * 10)
|
||||
@ -106,6 +114,8 @@ function logic.update_annunciator(self)
|
||||
-- BOILERS --
|
||||
-------------
|
||||
|
||||
local boilers_ready = num_boilers == #self.boilers
|
||||
|
||||
-- clear boiler online flags
|
||||
for i = 1, num_boilers do self.db.annunciator.BoilerOnline[i] = false end
|
||||
|
||||
@ -119,6 +129,14 @@ function logic.update_annunciator(self)
|
||||
local session = self.boilers[i] ---@type unit_session
|
||||
local boiler = session.get_db() ---@type boilerv_session_db
|
||||
|
||||
-- update ready state
|
||||
-- - must be formed
|
||||
-- - must have received build, state, and tanks at least once
|
||||
boilers_ready = boilers_ready and boiler.formed and
|
||||
(boiler.build.last_update > 0) and
|
||||
(boiler.state.last_update > 0) and
|
||||
(boiler.tanks.last_update > 0)
|
||||
|
||||
total_boil_rate = total_boil_rate + boiler.state.boil_rate
|
||||
boiler_steam_dt_sum = _get_dt(DT_KEYS.BoilerSteam .. self.boilers[i].get_device_idx())
|
||||
boiler_water_dt_sum = _get_dt(DT_KEYS.BoilerWater .. self.boilers[i].get_device_idx())
|
||||
@ -185,6 +203,8 @@ function logic.update_annunciator(self)
|
||||
-- TURBINES --
|
||||
--------------
|
||||
|
||||
local turbines_ready = num_turbines == #self.turbines
|
||||
|
||||
-- clear turbine online flags
|
||||
for i = 1, num_turbines do self.db.annunciator.TurbineOnline[i] = false end
|
||||
|
||||
@ -201,6 +221,14 @@ function logic.update_annunciator(self)
|
||||
local session = self.turbines[i] ---@type unit_session
|
||||
local turbine = session.get_db() ---@type turbinev_session_db
|
||||
|
||||
-- update ready state
|
||||
-- - must be formed
|
||||
-- - must have received build, state, and tanks at least once
|
||||
turbines_ready = turbines_ready and turbine.formed and
|
||||
(turbine.build.last_update > 0) and
|
||||
(turbine.state.last_update > 0) and
|
||||
(turbine.tanks.last_update > 0)
|
||||
|
||||
total_flow_rate = total_flow_rate + turbine.state.flow_rate
|
||||
total_input_rate = total_input_rate + turbine.state.steam_input_rate
|
||||
max_water_return_rate = max_water_return_rate + turbine.build.max_water_output
|
||||
@ -257,6 +285,9 @@ function logic.update_annunciator(self)
|
||||
local has_steam = db.state.steam_input_rate > 0 or db.tanks.steam_fill > 0.01
|
||||
self.db.annunciator.TurbineTrip[turbine.get_device_idx()] = has_steam and db.state.flow_rate == 0
|
||||
end
|
||||
|
||||
-- update auto control ready state for this unit
|
||||
self.db.control.ready = plc_ready and boilers_ready and turbines_ready
|
||||
end
|
||||
|
||||
-- update an alarm state given conditions
|
||||
|
@ -14,7 +14,7 @@ local svsessions = require("supervisor.session.svsessions")
|
||||
local config = require("supervisor.config")
|
||||
local supervisor = require("supervisor.supervisor")
|
||||
|
||||
local SUPERVISOR_VERSION = "beta-v0.9.8"
|
||||
local SUPERVISOR_VERSION = "beta-v0.9.9"
|
||||
|
||||
local print = util.print
|
||||
local println = util.println
|
||||
|
Loading…
Reference in New Issue
Block a user