mirror of
https://github.com/MikaylaFischler/cc-mek-scada.git
synced 2024-08-30 18:22:34 +00:00
#367 reject and record bad or duplicate RTU IDs
This commit is contained in:
parent
bee96ed12e
commit
ab97f8935d
@ -65,7 +65,8 @@ local facility = {}
|
|||||||
---@nodiscard
|
---@nodiscard
|
||||||
---@param config svr_config supervisor configuration
|
---@param config svr_config supervisor configuration
|
||||||
---@param cooling_conf sv_cooling_conf cooling configurations of reactor units
|
---@param cooling_conf sv_cooling_conf cooling configurations of reactor units
|
||||||
function facility.new(config, cooling_conf)
|
---@param check_rtu_id function ID checking function for RTUs attempting to be linked
|
||||||
|
function facility.new(config, cooling_conf, check_rtu_id)
|
||||||
local self = {
|
local self = {
|
||||||
units = {},
|
units = {},
|
||||||
status_text = { "START UP", "initializing..." },
|
status_text = { "START UP", "initializing..." },
|
||||||
@ -144,7 +145,7 @@ function facility.new(config, cooling_conf)
|
|||||||
|
|
||||||
-- create units
|
-- create units
|
||||||
for i = 1, config.UnitCount do
|
for i = 1, config.UnitCount do
|
||||||
table.insert(self.units, unit.new(i, cooling_conf.r_cool[i].BoilerCount, cooling_conf.r_cool[i].TurbineCount, config.ExtChargeIdling))
|
table.insert(self.units, unit.new(i, cooling_conf.r_cool[i].BoilerCount, cooling_conf.r_cool[i].TurbineCount, check_rtu_id, config.ExtChargeIdling))
|
||||||
table.insert(self.group_map, 0)
|
table.insert(self.group_map, 0)
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -257,20 +258,30 @@ function facility.new(config, cooling_conf)
|
|||||||
---@param imatrix unit_session
|
---@param imatrix unit_session
|
||||||
---@return boolean linked induction matrix accepted (max 1)
|
---@return boolean linked induction matrix accepted (max 1)
|
||||||
function public.add_imatrix(imatrix)
|
function public.add_imatrix(imatrix)
|
||||||
if #self.induction == 0 then
|
local fail_code, fail_str = check_rtu_id(imatrix, self.induction, 1)
|
||||||
|
|
||||||
|
if fail_code == 0 then
|
||||||
table.insert(self.induction, imatrix)
|
table.insert(self.induction, imatrix)
|
||||||
return true
|
else
|
||||||
else return false end
|
log.warning(util.c("FAC: rejected induction matrix linking due to failure code ", fail_code, " (", fail_str, ")"))
|
||||||
|
end
|
||||||
|
|
||||||
|
return fail_code == 0
|
||||||
end
|
end
|
||||||
|
|
||||||
-- link an SPS RTU session
|
-- link an SPS RTU session
|
||||||
---@param sps unit_session
|
---@param sps unit_session
|
||||||
---@return boolean linked SPS accepted (max 1)
|
---@return boolean linked SPS accepted (max 1)
|
||||||
function public.add_sps(sps)
|
function public.add_sps(sps)
|
||||||
if #self.sps == 0 then
|
local fail_code, fail_str = check_rtu_id(sps, self.sps, 1)
|
||||||
|
|
||||||
|
if fail_code == 0 then
|
||||||
table.insert(self.sps, sps)
|
table.insert(self.sps, sps)
|
||||||
return true
|
else
|
||||||
else return false end
|
log.warning(util.c("FAC: rejected SPS linking due to failure code ", fail_code, " (", fail_str, ")"))
|
||||||
|
end
|
||||||
|
|
||||||
|
return fail_code == 0
|
||||||
end
|
end
|
||||||
|
|
||||||
-- link a dynamic tank RTU session
|
-- link a dynamic tank RTU session
|
||||||
@ -293,7 +304,7 @@ function facility.new(config, cooling_conf)
|
|||||||
|
|
||||||
-- update (iterate) the facility management
|
-- update (iterate) the facility management
|
||||||
function public.update()
|
function public.update()
|
||||||
-- unlink RTU unit sessions if they are closed
|
-- unlink RTU sessions if they are closed
|
||||||
for _, v in pairs(self.rtu_list) do util.filter_table(v, function (u) return u.is_connected() end) end
|
for _, v in pairs(self.rtu_list) do util.filter_table(v, function (u) return u.is_connected() end) end
|
||||||
|
|
||||||
-- check if test routines are allowed right now
|
-- check if test routines are allowed right now
|
||||||
|
@ -37,7 +37,8 @@ local self = {
|
|||||||
config = nil, ---@type svr_config
|
config = nil, ---@type svr_config
|
||||||
facility = nil, ---@type facility|nil
|
facility = nil, ---@type facility|nil
|
||||||
sessions = { rtu = {}, plc = {}, crd = {}, pdg = {} },
|
sessions = { rtu = {}, plc = {}, crd = {}, pdg = {} },
|
||||||
next_ids = { rtu = 0, plc = 0, crd = 0, pdg = 0 }
|
next_ids = { rtu = 0, plc = 0, crd = 0, pdg = 0 },
|
||||||
|
dev_dbg = { duplicate = {}, out_of_range = {} }
|
||||||
}
|
}
|
||||||
|
|
||||||
---@alias sv_session_structs plc_session_struct|rtu_session_struct|crd_session_struct|pdg_session_struct
|
---@alias sv_session_structs plc_session_struct|rtu_session_struct|crd_session_struct|pdg_session_struct
|
||||||
@ -190,6 +191,49 @@ local function _find_session(list, s_addr)
|
|||||||
return nil
|
return nil
|
||||||
end
|
end
|
||||||
|
|
||||||
|
local function _update_dev_dbg()
|
||||||
|
local f = function (unit) return unit.is_connected() end
|
||||||
|
|
||||||
|
---@param unit unit_session
|
||||||
|
local on_delete = function (unit)
|
||||||
|
end
|
||||||
|
|
||||||
|
util.filter_table(self.dev_dbg.duplicate, f, on_delete)
|
||||||
|
util.filter_table(self.dev_dbg.out_of_range, f, on_delete)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- SHARED FUNCTIONS --
|
||||||
|
|
||||||
|
---@param unit unit_session RTU session
|
||||||
|
---@param list table table of RTU sessions
|
||||||
|
---@param max integer max of this type of RTU
|
||||||
|
---@return 0|1|2|3 fail_code, string fail_str 0 = success, 1 = out-of-range, 2 = duplicate, 3 = exceeded table max
|
||||||
|
local function check_rtu_id(unit, list, max)
|
||||||
|
local fail_code, fail_str = 0, "OK"
|
||||||
|
|
||||||
|
if (unit.get_device_idx() < 1 and max ~= 1) or unit.get_device_idx() > max then
|
||||||
|
-- out-of-range
|
||||||
|
fail_code, fail_str = 1, "index out of range"
|
||||||
|
table.insert(self.dev_dbg.out_of_range, unit)
|
||||||
|
else
|
||||||
|
for _, u in ipairs(list) do
|
||||||
|
if u.get_device_idx() == unit.get_device_idx() then
|
||||||
|
-- duplicate
|
||||||
|
fail_code, fail_str = 2, "duplicate index"
|
||||||
|
table.insert(self.dev_dbg.duplicate, unit)
|
||||||
|
break
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- make sure this won't exceed the maximum allowable devices
|
||||||
|
if fail_code == 0 and #list >= max then
|
||||||
|
fail_code, fail_str = 3, "too many of this type"
|
||||||
|
end
|
||||||
|
|
||||||
|
return fail_code, fail_str
|
||||||
|
end
|
||||||
|
|
||||||
-- PUBLIC FUNCTIONS --
|
-- PUBLIC FUNCTIONS --
|
||||||
|
|
||||||
-- initialize svsessions
|
-- initialize svsessions
|
||||||
@ -201,7 +245,7 @@ function svsessions.init(nic, fp_ok, config, cooling_conf)
|
|||||||
self.nic = nic
|
self.nic = nic
|
||||||
self.fp_ok = fp_ok
|
self.fp_ok = fp_ok
|
||||||
self.config = config
|
self.config = config
|
||||||
self.facility = facility.new(config, cooling_conf)
|
self.facility = facility.new(config, cooling_conf, check_rtu_id)
|
||||||
end
|
end
|
||||||
|
|
||||||
-- find an RTU session by the computer ID
|
-- find an RTU session by the computer ID
|
||||||
@ -466,6 +510,8 @@ function svsessions.iterate_all()
|
|||||||
|
|
||||||
-- iterate units
|
-- iterate units
|
||||||
self.facility.update_units()
|
self.facility.update_units()
|
||||||
|
|
||||||
|
_update_dev_dbg()
|
||||||
end
|
end
|
||||||
|
|
||||||
-- delete all closed sessions
|
-- delete all closed sessions
|
||||||
|
@ -21,7 +21,7 @@ local supervisor = require("supervisor.supervisor")
|
|||||||
|
|
||||||
local svsessions = require("supervisor.session.svsessions")
|
local svsessions = require("supervisor.session.svsessions")
|
||||||
|
|
||||||
local SUPERVISOR_VERSION = "v1.4.3"
|
local SUPERVISOR_VERSION = "v1.5.0"
|
||||||
|
|
||||||
local println = util.println
|
local println = util.println
|
||||||
local println_ts = util.println_ts
|
local println_ts = util.println_ts
|
||||||
|
@ -63,11 +63,14 @@ local unit = {}
|
|||||||
---@param reactor_id integer reactor unit number
|
---@param reactor_id integer reactor unit number
|
||||||
---@param num_boilers integer number of boilers expected
|
---@param num_boilers integer number of boilers expected
|
||||||
---@param num_turbines integer number of turbines expected
|
---@param num_turbines integer number of turbines expected
|
||||||
|
---@param check_rtu_id function ID checking function for RTUs attempting to be linked
|
||||||
---@param ext_idle boolean extended idling mode
|
---@param ext_idle boolean extended idling mode
|
||||||
function unit.new(reactor_id, num_boilers, num_turbines, ext_idle)
|
function unit.new(reactor_id, num_boilers, num_turbines, check_rtu_id, ext_idle)
|
||||||
-- time (ms) to idle for auto idling
|
-- time (ms) to idle for auto idling
|
||||||
local IDLE_TIME = util.trinary(ext_idle, 60000, 10000)
|
local IDLE_TIME = util.trinary(ext_idle, 60000, 10000)
|
||||||
|
|
||||||
|
local log_tag = "UNIT " .. reactor_id .. ": "
|
||||||
|
|
||||||
---@class _unit_self
|
---@class _unit_self
|
||||||
local self = {
|
local self = {
|
||||||
r_id = reactor_id,
|
r_id = reactor_id,
|
||||||
@ -441,22 +444,28 @@ function unit.new(reactor_id, num_boilers, num_turbines, ext_idle)
|
|||||||
---@param turbine unit_session
|
---@param turbine unit_session
|
||||||
---@return boolean linked turbine accepted to associated device slot
|
---@return boolean linked turbine accepted to associated device slot
|
||||||
function public.add_turbine(turbine)
|
function public.add_turbine(turbine)
|
||||||
if #self.turbines < num_turbines and turbine.get_device_idx() <= num_turbines then
|
local fail_code, fail_str = check_rtu_id(turbine, self.turbines, num_turbines)
|
||||||
|
|
||||||
|
if fail_code == 0 then
|
||||||
table.insert(self.turbines, turbine)
|
table.insert(self.turbines, turbine)
|
||||||
|
|
||||||
-- reset deltas
|
-- reset deltas
|
||||||
_reset_dt(DT_KEYS.TurbineSteam .. turbine.get_device_idx())
|
_reset_dt(DT_KEYS.TurbineSteam .. turbine.get_device_idx())
|
||||||
_reset_dt(DT_KEYS.TurbinePower .. turbine.get_device_idx())
|
_reset_dt(DT_KEYS.TurbinePower .. turbine.get_device_idx())
|
||||||
|
else
|
||||||
|
log.warning(util.c(log_tag, "rejected turbine linking due to failure code ", fail_code, " (", fail_str, ")"))
|
||||||
|
end
|
||||||
|
|
||||||
return true
|
return fail_code == 0
|
||||||
else return false end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
-- link a boiler RTU session
|
-- link a boiler RTU session
|
||||||
---@param boiler unit_session
|
---@param boiler unit_session
|
||||||
---@return boolean linked boiler accepted to associated device slot
|
---@return boolean linked boiler accepted to associated device slot
|
||||||
function public.add_boiler(boiler)
|
function public.add_boiler(boiler)
|
||||||
if #self.boilers < num_boilers and boiler.get_device_idx() <= num_boilers then
|
local fail_code, fail_str = check_rtu_id(boiler, self.boilers, num_boilers)
|
||||||
|
|
||||||
|
if fail_code == 0 then
|
||||||
table.insert(self.boilers, boiler)
|
table.insert(self.boilers, boiler)
|
||||||
|
|
||||||
-- reset deltas
|
-- reset deltas
|
||||||
@ -464,19 +473,26 @@ function unit.new(reactor_id, num_boilers, num_turbines, ext_idle)
|
|||||||
_reset_dt(DT_KEYS.BoilerSteam .. boiler.get_device_idx())
|
_reset_dt(DT_KEYS.BoilerSteam .. boiler.get_device_idx())
|
||||||
_reset_dt(DT_KEYS.BoilerCCool .. boiler.get_device_idx())
|
_reset_dt(DT_KEYS.BoilerCCool .. boiler.get_device_idx())
|
||||||
_reset_dt(DT_KEYS.BoilerHCool .. boiler.get_device_idx())
|
_reset_dt(DT_KEYS.BoilerHCool .. boiler.get_device_idx())
|
||||||
|
else
|
||||||
|
log.warning(util.c(log_tag, "rejected boiler linking due to failure code ", fail_code, " (", fail_str, ")"))
|
||||||
|
end
|
||||||
|
|
||||||
return true
|
return fail_code == 0
|
||||||
else return false end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
-- link a dynamic tank RTU session
|
-- link a dynamic tank RTU session
|
||||||
---@param dynamic_tank unit_session
|
---@param dynamic_tank unit_session
|
||||||
---@return boolean linked dynamic tank accepted (max 1)
|
---@return boolean linked dynamic tank accepted (max 1)
|
||||||
function public.add_tank(dynamic_tank)
|
function public.add_tank(dynamic_tank)
|
||||||
if #self.tanks == 0 then
|
local fail_code, fail_str = check_rtu_id(dynamic_tank, self.tanks, 1)
|
||||||
|
|
||||||
|
if fail_code == 0 then
|
||||||
table.insert(self.tanks, dynamic_tank)
|
table.insert(self.tanks, dynamic_tank)
|
||||||
return true
|
else
|
||||||
else return false end
|
log.warning(util.c(log_tag, "rejected dynamic tank linking due to failure code ", fail_code, " (", fail_str, ")"))
|
||||||
|
end
|
||||||
|
|
||||||
|
return fail_code == 0
|
||||||
end
|
end
|
||||||
|
|
||||||
-- link a solar neutron activator RTU session
|
-- link a solar neutron activator RTU session
|
||||||
@ -487,10 +503,15 @@ function unit.new(reactor_id, num_boilers, num_turbines, ext_idle)
|
|||||||
---@param envd unit_session
|
---@param envd unit_session
|
||||||
---@return boolean linked environment detector accepted (max 1)
|
---@return boolean linked environment detector accepted (max 1)
|
||||||
function public.add_envd(envd)
|
function public.add_envd(envd)
|
||||||
if #self.envd == 0 then
|
local fail_code, fail_str = check_rtu_id(envd, self.envd, 99)
|
||||||
|
|
||||||
|
if fail_code == 0 then
|
||||||
table.insert(self.envd, envd)
|
table.insert(self.envd, envd)
|
||||||
return true
|
else
|
||||||
else return false end
|
log.warning(util.c(log_tag, "rejected environment detector linking due to failure code ", fail_code, " (", fail_str, ")"))
|
||||||
|
end
|
||||||
|
|
||||||
|
return fail_code == 0
|
||||||
end
|
end
|
||||||
|
|
||||||
-- purge devices associated with the given RTU session ID
|
-- purge devices associated with the given RTU session ID
|
||||||
@ -512,7 +533,7 @@ function unit.new(reactor_id, num_boilers, num_turbines, ext_idle)
|
|||||||
self.db.control.br100 = 0
|
self.db.control.br100 = 0
|
||||||
end
|
end
|
||||||
|
|
||||||
-- unlink RTU unit sessions if they are closed
|
-- unlink RTU sessions if they are closed
|
||||||
for _, v in pairs(self.rtu_list) do util.filter_table(v, function (u) return u.is_connected() end) end
|
for _, v in pairs(self.rtu_list) do util.filter_table(v, function (u) return u.is_connected() end) end
|
||||||
|
|
||||||
-- update degraded state for auto control
|
-- update degraded state for auto control
|
||||||
@ -547,7 +568,7 @@ function unit.new(reactor_id, num_boilers, num_turbines, ext_idle)
|
|||||||
|
|
||||||
-- stop idling when completed
|
-- stop idling when completed
|
||||||
if self.auto_idling and (((util.time_ms() - self.auto_idle_start) > IDLE_TIME) or not self.auto_idle) then
|
if self.auto_idling and (((util.time_ms() - self.auto_idle_start) > IDLE_TIME) or not self.auto_idle) then
|
||||||
log.info(util.c("UNIT ", self.r_id, ": completed idling period"))
|
log.info(util.c(log_tag, "completed idling period"))
|
||||||
self.auto_idling = false
|
self.auto_idling = false
|
||||||
self.plc_i.auto_set_burn(0, false)
|
self.plc_i.auto_set_burn(0, false)
|
||||||
end
|
end
|
||||||
@ -584,7 +605,7 @@ function unit.new(reactor_id, num_boilers, num_turbines, ext_idle)
|
|||||||
function public.auto_engage()
|
function public.auto_engage()
|
||||||
self.auto_engaged = true
|
self.auto_engaged = true
|
||||||
if self.plc_i ~= nil then
|
if self.plc_i ~= nil then
|
||||||
log.debug(util.c("UNIT ", self.r_id, ": engaged auto control"))
|
log.debug(util.c(log_tag, "engaged auto control"))
|
||||||
self.plc_i.auto_lock(true)
|
self.plc_i.auto_lock(true)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@ -593,7 +614,7 @@ function unit.new(reactor_id, num_boilers, num_turbines, ext_idle)
|
|||||||
function public.auto_disengage()
|
function public.auto_disengage()
|
||||||
self.auto_engaged = false
|
self.auto_engaged = false
|
||||||
if self.plc_i ~= nil then
|
if self.plc_i ~= nil then
|
||||||
log.debug(util.c("UNIT ", self.r_id, ": disengaged auto control"))
|
log.debug(util.c(log_tag, "disengaged auto control"))
|
||||||
self.plc_i.auto_lock(false)
|
self.plc_i.auto_lock(false)
|
||||||
self.db.control.br100 = 0
|
self.db.control.br100 = 0
|
||||||
end
|
end
|
||||||
@ -610,7 +631,7 @@ function unit.new(reactor_id, num_boilers, num_turbines, ext_idle)
|
|||||||
end
|
end
|
||||||
|
|
||||||
if idle ~= self.auto_idle then
|
if idle ~= self.auto_idle then
|
||||||
log.debug(util.c("UNIT ", self.r_id, ": idling mode changed to ", idle))
|
log.debug(util.c(log_tag, "idling mode changed to ", idle))
|
||||||
end
|
end
|
||||||
|
|
||||||
self.auto_idle = idle
|
self.auto_idle = idle
|
||||||
@ -623,7 +644,7 @@ function unit.new(reactor_id, num_boilers, num_turbines, ext_idle)
|
|||||||
function public.auto_get_effective_limit()
|
function public.auto_get_effective_limit()
|
||||||
local ctrl = self.db.control
|
local ctrl = self.db.control
|
||||||
if (not ctrl.ready) or ctrl.degraded or self.plc_cache.rps_trip then
|
if (not ctrl.ready) or ctrl.degraded or self.plc_cache.rps_trip then
|
||||||
-- log.debug(util.c("UNIT ", self.r_id, ": effective limit is zero! ready[", ctrl.ready, "] degraded[", ctrl.degraded, "] rps_trip[", self.plc_cache.rps_trip, "]"))
|
-- log.debug(util.c(log_tag, "effective limit is zero! ready[", ctrl.ready, "] degraded[", ctrl.degraded, "] rps_trip[", self.plc_cache.rps_trip, "]"))
|
||||||
ctrl.br100 = 0
|
ctrl.br100 = 0
|
||||||
return 0
|
return 0
|
||||||
else return ctrl.lim_br100 end
|
else return ctrl.lim_br100 end
|
||||||
@ -634,7 +655,7 @@ function unit.new(reactor_id, num_boilers, num_turbines, ext_idle)
|
|||||||
function public.auto_commit_br100(ramp)
|
function public.auto_commit_br100(ramp)
|
||||||
if self.auto_engaged then
|
if self.auto_engaged then
|
||||||
if self.plc_i ~= nil then
|
if self.plc_i ~= nil then
|
||||||
log.debug(util.c("UNIT ", self.r_id, ": commit br100 of ", self.db.control.br100, " with ramp set to ", ramp))
|
log.debug(util.c(log_tag, "commit br100 of ", self.db.control.br100, " with ramp set to ", ramp))
|
||||||
|
|
||||||
local rate = self.db.control.br100 / 100
|
local rate = self.db.control.br100 / 100
|
||||||
|
|
||||||
@ -643,16 +664,16 @@ function unit.new(reactor_id, num_boilers, num_turbines, ext_idle)
|
|||||||
if self.auto_idle_start == 0 then
|
if self.auto_idle_start == 0 then
|
||||||
self.auto_idling = true
|
self.auto_idling = true
|
||||||
self.auto_idle_start = util.time_ms()
|
self.auto_idle_start = util.time_ms()
|
||||||
log.info(util.c("UNIT ", self.r_id, ": started idling at ", IDLE_RATE, " mB/t"))
|
log.info(util.c(log_tag, "started idling at ", IDLE_RATE, " mB/t"))
|
||||||
|
|
||||||
rate = IDLE_RATE
|
rate = IDLE_RATE
|
||||||
elseif (util.time_ms() - self.auto_idle_start) > IDLE_TIME then
|
elseif (util.time_ms() - self.auto_idle_start) > IDLE_TIME then
|
||||||
if self.auto_idling then
|
if self.auto_idling then
|
||||||
self.auto_idling = false
|
self.auto_idling = false
|
||||||
log.info(util.c("UNIT ", self.r_id, ": completed idling period"))
|
log.info(util.c(log_tag, "completed idling period"))
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
log.debug(util.c("UNIT ", self.r_id, ": continuing idle at ", IDLE_RATE, " mB/t"))
|
log.debug(util.c(log_tag, "continuing idle at ", IDLE_RATE, " mB/t"))
|
||||||
|
|
||||||
rate = IDLE_RATE
|
rate = IDLE_RATE
|
||||||
end
|
end
|
||||||
|
Loading…
Reference in New Issue
Block a user