mirror of
https://github.com/MikaylaFischler/cc-mek-scada.git
synced 2024-08-30 18:22:34 +00:00
#24 coordinator/supervisor setting process groups and unit burn rate limits
This commit is contained in:
@ -2,6 +2,7 @@ local comms = require("scada-common.comms")
|
|||||||
local log = require("scada-common.log")
|
local log = require("scada-common.log")
|
||||||
local ppm = require("scada-common.ppm")
|
local ppm = require("scada-common.ppm")
|
||||||
local util = require("scada-common.util")
|
local util = require("scada-common.util")
|
||||||
|
local process = require("coordinator.process")
|
||||||
|
|
||||||
local apisessions = require("coordinator.apisessions")
|
local apisessions = require("coordinator.apisessions")
|
||||||
local iocontrol = require("coordinator.iocontrol")
|
local iocontrol = require("coordinator.iocontrol")
|
||||||
@ -442,6 +443,10 @@ function coordinator.comms(version, modem, sv_port, sv_listen, api_listen, sv_wa
|
|||||||
unit.set_waste_ack(ack)
|
unit.set_waste_ack(ack)
|
||||||
elseif cmd == UNIT_COMMANDS.ACK_ALL_ALARMS then
|
elseif cmd == UNIT_COMMANDS.ACK_ALL_ALARMS then
|
||||||
unit.ack_alarms_ack(ack)
|
unit.ack_alarms_ack(ack)
|
||||||
|
elseif cmd == UNIT_COMMANDS.SET_GROUP then
|
||||||
|
process.sv_assign(unit_id, ack)
|
||||||
|
elseif cmd == UNIT_COMMANDS.SET_LIMIT then
|
||||||
|
process.sv_limit(unit_id, ack)
|
||||||
else
|
else
|
||||||
log.debug(util.c("received command ack with unknown command ", cmd))
|
log.debug(util.c("received command ack with unknown command ", cmd))
|
||||||
end
|
end
|
||||||
|
@ -4,6 +4,7 @@ local psil = require("scada-common.psil")
|
|||||||
local types = require("scada-common.types")
|
local types = require("scada-common.types")
|
||||||
local util = require("scada-common.util")
|
local util = require("scada-common.util")
|
||||||
|
|
||||||
|
local process = require("coordinator.process")
|
||||||
local sounder = require("coordinator.sounder")
|
local sounder = require("coordinator.sounder")
|
||||||
|
|
||||||
local UNIT_COMMANDS = comms.UNIT_COMMANDS
|
local UNIT_COMMANDS = comms.UNIT_COMMANDS
|
||||||
@ -20,13 +21,21 @@ local io = {}
|
|||||||
---@param comms coord_comms comms reference
|
---@param comms coord_comms comms reference
|
||||||
---@diagnostic disable-next-line: redefined-local
|
---@diagnostic disable-next-line: redefined-local
|
||||||
function iocontrol.init(conf, comms)
|
function iocontrol.init(conf, comms)
|
||||||
|
-- pass IO control here since it can't be require'd due to a require loop
|
||||||
|
process.init(iocontrol, comms)
|
||||||
|
|
||||||
io.facility = {
|
io.facility = {
|
||||||
|
auto_active = false,
|
||||||
scram = false,
|
scram = false,
|
||||||
|
|
||||||
num_units = conf.num_units, ---@type integer
|
num_units = conf.num_units, ---@type integer
|
||||||
ps = psil.create(),
|
ps = psil.create(),
|
||||||
|
|
||||||
induction_ps_tbl = {},
|
induction_ps_tbl = {},
|
||||||
induction_data_tbl = {}
|
induction_data_tbl = {},
|
||||||
|
|
||||||
|
env_d_ps = psil.create(),
|
||||||
|
env_d_data = {}
|
||||||
}
|
}
|
||||||
|
|
||||||
-- create induction tables (max 1 per unit, preferably 1 total)
|
-- create induction tables (max 1 per unit, preferably 1 total)
|
||||||
@ -38,20 +47,12 @@ function iocontrol.init(conf, comms)
|
|||||||
|
|
||||||
io.units = {}
|
io.units = {}
|
||||||
for i = 1, conf.num_units do
|
for i = 1, conf.num_units do
|
||||||
local function ack(alarm)
|
local function ack(alarm) process.ack_alarm(i, alarm) end
|
||||||
comms.send_command(UNIT_COMMANDS.ACK_ALARM, i, alarm)
|
local function reset(alarm) process.reset_alarm(i, alarm) end
|
||||||
log.debug(util.c("UNIT[", i, "]: ACK ALARM ", alarm))
|
|
||||||
end
|
|
||||||
|
|
||||||
local function reset(alarm)
|
|
||||||
comms.send_command(UNIT_COMMANDS.RESET_ALARM, i, alarm)
|
|
||||||
log.debug(util.c("UNIT[", i, "]: RESET ALARM ", alarm))
|
|
||||||
end
|
|
||||||
|
|
||||||
---@class ioctl_entry
|
---@class ioctl_entry
|
||||||
local entry = {
|
local entry = {
|
||||||
unit_id = i, ---@type integer
|
unit_id = i, ---@type integer
|
||||||
initialized = false,
|
|
||||||
|
|
||||||
num_boilers = 0,
|
num_boilers = 0,
|
||||||
num_turbines = 0,
|
num_turbines = 0,
|
||||||
@ -60,12 +61,17 @@ function iocontrol.init(conf, comms)
|
|||||||
burn_rate_cmd = 0.0,
|
burn_rate_cmd = 0.0,
|
||||||
waste_control = 0,
|
waste_control = 0,
|
||||||
|
|
||||||
start = function () end,
|
a_group = 0, -- auto control group
|
||||||
scram = function () end,
|
a_limit = 0.0, -- auto control limit
|
||||||
reset_rps = function () end,
|
|
||||||
ack_alarms = function () end,
|
start = function () process.start(i) end,
|
||||||
set_burn = function (rate) end, ---@param rate number
|
scram = function () process.scram(i) end,
|
||||||
set_waste = function (mode) end, ---@param mode integer
|
reset_rps = function () process.reset_rps(i) end,
|
||||||
|
ack_alarms = function () process.ack_all_alarms(i) end,
|
||||||
|
set_burn = function (rate) process.set_rate(i, rate) end, ---@param rate number burn rate
|
||||||
|
set_waste = function (mode) process.set_waste(i, mode) end, ---@param mode integer waste processing mode
|
||||||
|
|
||||||
|
set_group = function (g) process.set_group(i, g) end, ---@param g integer|0 group ID or 0
|
||||||
|
|
||||||
start_ack = function (success) end, ---@param success boolean
|
start_ack = function (success) end, ---@param success boolean
|
||||||
scram_ack = function (success) end, ---@param success boolean
|
scram_ack = function (success) end, ---@param success boolean
|
||||||
@ -91,18 +97,18 @@ function iocontrol.init(conf, comms)
|
|||||||
|
|
||||||
---@type alarms
|
---@type alarms
|
||||||
alarms = {
|
alarms = {
|
||||||
ALARM_STATE.INACTIVE,
|
ALARM_STATE.INACTIVE, -- containment breach
|
||||||
ALARM_STATE.INACTIVE,
|
ALARM_STATE.INACTIVE, -- containment radiation
|
||||||
ALARM_STATE.INACTIVE,
|
ALARM_STATE.INACTIVE, -- reactor lost
|
||||||
ALARM_STATE.INACTIVE,
|
ALARM_STATE.INACTIVE, -- damage critical
|
||||||
ALARM_STATE.INACTIVE,
|
ALARM_STATE.INACTIVE, -- reactor taking damage
|
||||||
ALARM_STATE.INACTIVE,
|
ALARM_STATE.INACTIVE, -- reactor over temperature
|
||||||
ALARM_STATE.INACTIVE,
|
ALARM_STATE.INACTIVE, -- reactor high temperature
|
||||||
ALARM_STATE.INACTIVE,
|
ALARM_STATE.INACTIVE, -- waste leak
|
||||||
ALARM_STATE.INACTIVE,
|
ALARM_STATE.INACTIVE, -- waste level high
|
||||||
ALARM_STATE.INACTIVE,
|
ALARM_STATE.INACTIVE, -- RPS transient
|
||||||
ALARM_STATE.INACTIVE,
|
ALARM_STATE.INACTIVE, -- RCS transient
|
||||||
ALARM_STATE.INACTIVE
|
ALARM_STATE.INACTIVE -- turbine trip
|
||||||
},
|
},
|
||||||
|
|
||||||
reactor_ps = psil.create(),
|
reactor_ps = psil.create(),
|
||||||
@ -115,38 +121,6 @@ function iocontrol.init(conf, comms)
|
|||||||
turbine_data_tbl = {}
|
turbine_data_tbl = {}
|
||||||
}
|
}
|
||||||
|
|
||||||
function entry.start()
|
|
||||||
entry.control_state = true
|
|
||||||
comms.send_command(UNIT_COMMANDS.START, i)
|
|
||||||
log.debug(util.c("UNIT[", i, "]: START"))
|
|
||||||
end
|
|
||||||
|
|
||||||
function entry.scram()
|
|
||||||
entry.control_state = false
|
|
||||||
comms.send_command(UNIT_COMMANDS.SCRAM, i)
|
|
||||||
log.debug(util.c("UNIT[", i, "]: SCRAM"))
|
|
||||||
end
|
|
||||||
|
|
||||||
function entry.reset_rps()
|
|
||||||
comms.send_command(UNIT_COMMANDS.RESET_RPS, i)
|
|
||||||
log.debug(util.c("UNIT[", i, "]: RESET_RPS"))
|
|
||||||
end
|
|
||||||
|
|
||||||
function entry.ack_alarms()
|
|
||||||
comms.send_command(UNIT_COMMANDS.ACK_ALL_ALARMS, i)
|
|
||||||
log.debug(util.c("UNIT[", i, "]: ACK_ALL_ALARMS"))
|
|
||||||
end
|
|
||||||
|
|
||||||
function entry.set_burn(rate)
|
|
||||||
comms.send_command(UNIT_COMMANDS.SET_BURN, i, rate)
|
|
||||||
log.debug(util.c("UNIT[", i, "]: SET_BURN = ", rate))
|
|
||||||
end
|
|
||||||
|
|
||||||
function entry.set_waste(mode)
|
|
||||||
comms.send_command(UNIT_COMMANDS.SET_WASTE, i, mode)
|
|
||||||
log.debug(util.c("UNIT[", i, "]: SET_WASTE = ", mode))
|
|
||||||
end
|
|
||||||
|
|
||||||
-- create boiler tables
|
-- create boiler tables
|
||||||
for _ = 1, conf.defs[(i * 2) - 1] do
|
for _ = 1, conf.defs[(i * 2) - 1] do
|
||||||
local data = {} ---@type boilerv_session_db
|
local data = {} ---@type boilerv_session_db
|
||||||
|
117
coordinator/process.lua
Normal file
117
coordinator/process.lua
Normal file
@ -0,0 +1,117 @@
|
|||||||
|
|
||||||
|
local comms = require("scada-common.comms")
|
||||||
|
local log = require("scada-common.log")
|
||||||
|
local util = require("scada-common.util")
|
||||||
|
|
||||||
|
local UNIT_COMMANDS = comms.UNIT_COMMANDS
|
||||||
|
|
||||||
|
---@class process_controller
|
||||||
|
local process = {}
|
||||||
|
|
||||||
|
local self = {
|
||||||
|
io = nil, ---@type ioctl
|
||||||
|
comms = nil ---@type coord_comms
|
||||||
|
}
|
||||||
|
|
||||||
|
--------------------------
|
||||||
|
-- UNIT COMMAND CONTROL --
|
||||||
|
--------------------------
|
||||||
|
|
||||||
|
-- initialize the process controller
|
||||||
|
---@param iocontrol ioctl
|
||||||
|
---@diagnostic disable-next-line: redefined-local
|
||||||
|
function process.init(iocontrol, comms)
|
||||||
|
self.io = iocontrol
|
||||||
|
self.comms = comms
|
||||||
|
end
|
||||||
|
|
||||||
|
-- start reactor
|
||||||
|
---@param id integer unit ID
|
||||||
|
function process.start(id)
|
||||||
|
self.io.units[id].control_state = true
|
||||||
|
self.comms.send_command(UNIT_COMMANDS.START, id)
|
||||||
|
log.debug(util.c("UNIT[", id, "]: START"))
|
||||||
|
end
|
||||||
|
|
||||||
|
-- SCRAM reactor
|
||||||
|
---@param id integer unit ID
|
||||||
|
function process.scram(id)
|
||||||
|
self.io.units[id].control_state = false
|
||||||
|
self.comms.send_command(UNIT_COMMANDS.SCRAM, id)
|
||||||
|
log.debug(util.c("UNIT[", id, "]: SCRAM"))
|
||||||
|
end
|
||||||
|
|
||||||
|
-- reset reactor protection system
|
||||||
|
---@param id integer unit ID
|
||||||
|
function process.reset_rps(id)
|
||||||
|
self.comms.send_command(UNIT_COMMANDS.RESET_RPS, id)
|
||||||
|
log.debug(util.c("UNIT[", id, "]: RESET RPS"))
|
||||||
|
end
|
||||||
|
|
||||||
|
-- set burn rate or burn limit if part of a group
|
||||||
|
---@param id integer unit ID
|
||||||
|
---@param rate number burn rate
|
||||||
|
function process.set_rate(id, rate)
|
||||||
|
if self.io.units[id].group == 0 then
|
||||||
|
self.comms.send_command(UNIT_COMMANDS.SET_BURN, id, rate)
|
||||||
|
log.debug(util.c("UNIT[", id, "]: SET BURN = ", rate))
|
||||||
|
else
|
||||||
|
self.comms.send_command(UNIT_COMMANDS.SET_LIMIT, id, rate)
|
||||||
|
log.debug(util.c("UNIT[", id, "]: SET LIMIT = ", rate))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- set waste mode
|
||||||
|
---@param id integer unit ID
|
||||||
|
---@param mode integer waste mode
|
||||||
|
function process.set_waste(id, mode)
|
||||||
|
self.comms.send_command(UNIT_COMMANDS.SET_WASTE, id, mode)
|
||||||
|
log.debug(util.c("UNIT[", id, "]: SET WASTE = ", mode))
|
||||||
|
end
|
||||||
|
|
||||||
|
-- acknowledge all alarms
|
||||||
|
---@param id integer unit ID
|
||||||
|
function process.ack_all_alarms(id)
|
||||||
|
self.comms.send_command(UNIT_COMMANDS.ACK_ALL_ALARMS, id)
|
||||||
|
log.debug(util.c("UNIT[", id, "]: ACK ALL ALARMS"))
|
||||||
|
end
|
||||||
|
|
||||||
|
-- acknowledge an alarm
|
||||||
|
---@param id integer unit ID
|
||||||
|
---@param alarm integer alarm ID
|
||||||
|
function process.ack_alarm(id, alarm)
|
||||||
|
self.comms.send_command(UNIT_COMMANDS.ACK_ALARM, id, alarm)
|
||||||
|
log.debug(util.c("UNIT[", id, "]: ACK ALARM ", alarm))
|
||||||
|
end
|
||||||
|
|
||||||
|
-- reset an alarm
|
||||||
|
---@param id integer unit ID
|
||||||
|
---@param alarm integer alarm ID
|
||||||
|
function process.reset_alarm(id, alarm)
|
||||||
|
self.comms.send_command(UNIT_COMMANDS.RESET_ALARM, id, alarm)
|
||||||
|
log.debug(util.c("UNIT[", id, "]: RESET ALARM ", alarm))
|
||||||
|
end
|
||||||
|
|
||||||
|
-- assign a unit to a group
|
||||||
|
---@param unit_id integer unit ID
|
||||||
|
---@param group_id integer|0 group ID or 0 for independent
|
||||||
|
function process.set_group(unit_id, group_id)
|
||||||
|
self.comms.send_command(UNIT_COMMANDS.SET_GROUP, unit_id, group_id)
|
||||||
|
log.debug(util.c("UNIT[", unit_id, "]: SET GROUP ", group_id))
|
||||||
|
end
|
||||||
|
|
||||||
|
--------------------------
|
||||||
|
-- SUPERVISOR RESPONSES --
|
||||||
|
--------------------------
|
||||||
|
|
||||||
|
-- acknowledgement from the supervisor to assign a unit to a group
|
||||||
|
function process.sv_assign(unit_id, group_id)
|
||||||
|
self.io.units[unit_id].group = group_id
|
||||||
|
end
|
||||||
|
|
||||||
|
-- acknowledgement from the supervisor to assign a unit a burn rate limit
|
||||||
|
function process.sv_limit(unit_id, limit)
|
||||||
|
self.io.units[unit_id].limit = limit
|
||||||
|
end
|
||||||
|
|
||||||
|
return process
|
@ -19,7 +19,7 @@ local iocontrol = require("coordinator.iocontrol")
|
|||||||
local renderer = require("coordinator.renderer")
|
local renderer = require("coordinator.renderer")
|
||||||
local sounder = require("coordinator.sounder")
|
local sounder = require("coordinator.sounder")
|
||||||
|
|
||||||
local COORDINATOR_VERSION = "beta-v0.8.4"
|
local COORDINATOR_VERSION = "beta-v0.8.5"
|
||||||
|
|
||||||
local print = util.print
|
local print = util.print
|
||||||
local println = util.println
|
local println = util.println
|
||||||
|
@ -12,7 +12,7 @@ local rtu_t = types.rtu_t
|
|||||||
|
|
||||||
local insert = table.insert
|
local insert = table.insert
|
||||||
|
|
||||||
comms.version = "1.1.0"
|
comms.version = "1.1.1"
|
||||||
|
|
||||||
---@alias PROTOCOLS integer
|
---@alias PROTOCOLS integer
|
||||||
local PROTOCOLS = {
|
local PROTOCOLS = {
|
||||||
@ -79,7 +79,9 @@ local UNIT_COMMANDS = {
|
|||||||
SET_WASTE = 4, -- set the waste processing mode
|
SET_WASTE = 4, -- set the waste processing mode
|
||||||
ACK_ALL_ALARMS = 5, -- ack all active alarms
|
ACK_ALL_ALARMS = 5, -- ack all active alarms
|
||||||
ACK_ALARM = 6, -- ack a particular alarm
|
ACK_ALARM = 6, -- ack a particular alarm
|
||||||
RESET_ALARM = 7 -- reset a particular alarm
|
RESET_ALARM = 7, -- reset a particular alarm
|
||||||
|
SET_GROUP = 8, -- assign this unit to a group
|
||||||
|
SET_LIMIT = 9 -- set this unit maximum auto burn rate
|
||||||
}
|
}
|
||||||
|
|
||||||
---@alias CAPI_TYPES integer
|
---@alias CAPI_TYPES integer
|
||||||
|
@ -45,13 +45,13 @@ local PERIODICS = {
|
|||||||
---@param in_queue mqueue
|
---@param in_queue mqueue
|
||||||
---@param out_queue mqueue
|
---@param out_queue mqueue
|
||||||
---@param facility facility
|
---@param facility facility
|
||||||
---@param units table
|
function coordinator.new_session(id, in_queue, out_queue, facility)
|
||||||
function coordinator.new_session(id, in_queue, out_queue, facility, units)
|
|
||||||
local log_header = "crdn_session(" .. id .. "): "
|
local log_header = "crdn_session(" .. id .. "): "
|
||||||
|
|
||||||
local self = {
|
local self = {
|
||||||
in_q = in_queue,
|
in_q = in_queue,
|
||||||
out_q = out_queue,
|
out_q = out_queue,
|
||||||
|
units = facility.get_units(),
|
||||||
-- connection properties
|
-- connection properties
|
||||||
seq_num = 0,
|
seq_num = 0,
|
||||||
r_seq_num = nil,
|
r_seq_num = nil,
|
||||||
@ -122,8 +122,8 @@ function coordinator.new_session(id, in_queue, out_queue, facility, units)
|
|||||||
|
|
||||||
local builds = {}
|
local builds = {}
|
||||||
|
|
||||||
for i = 1, #units do
|
for i = 1, #self.units do
|
||||||
local unit = units[i] ---@type reactor_unit
|
local unit = self.units[i] ---@type reactor_unit
|
||||||
builds[unit.get_id()] = unit.get_build()
|
builds[unit.get_id()] = unit.get_build()
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -143,8 +143,8 @@ function coordinator.new_session(id, in_queue, out_queue, facility, units)
|
|||||||
local function _send_unit_statuses()
|
local function _send_unit_statuses()
|
||||||
local status = {}
|
local status = {}
|
||||||
|
|
||||||
for i = 1, #units do
|
for i = 1, #self.units do
|
||||||
local unit = units[i] ---@type reactor_unit
|
local unit = self.units[i] ---@type reactor_unit
|
||||||
status[unit.get_id()] = {
|
status[unit.get_id()] = {
|
||||||
unit.get_reactor_status(),
|
unit.get_reactor_status(),
|
||||||
unit.get_rtu_statuses(),
|
unit.get_rtu_statuses(),
|
||||||
@ -215,8 +215,8 @@ function coordinator.new_session(id, in_queue, out_queue, facility, units)
|
|||||||
local data = { uid, pkt.data[3] }
|
local data = { uid, pkt.data[3] }
|
||||||
|
|
||||||
-- continue if valid unit id
|
-- continue if valid unit id
|
||||||
if util.is_int(uid) and uid > 0 and uid <= #units then
|
if util.is_int(uid) and uid > 0 and uid <= #self.units then
|
||||||
local unit = units[uid] ---@type reactor_unit
|
local unit = self.units[uid] ---@type reactor_unit
|
||||||
|
|
||||||
if cmd == UNIT_COMMANDS.START then
|
if cmd == UNIT_COMMANDS.START then
|
||||||
self.out_q.push_data(SV_Q_DATA.START, data)
|
self.out_q.push_data(SV_Q_DATA.START, data)
|
||||||
@ -243,13 +243,27 @@ function coordinator.new_session(id, in_queue, out_queue, facility, units)
|
|||||||
if pkt.length == 3 then
|
if pkt.length == 3 then
|
||||||
unit.ack_alarm(pkt.data[3])
|
unit.ack_alarm(pkt.data[3])
|
||||||
else
|
else
|
||||||
log.debug(log_header .. "CRDN command unit ack alarm missing id")
|
log.debug(log_header .. "CRDN command unit ack alarm missing alarm id")
|
||||||
end
|
end
|
||||||
elseif cmd == UNIT_COMMANDS.RESET_ALARM then
|
elseif cmd == UNIT_COMMANDS.RESET_ALARM then
|
||||||
if pkt.length == 3 then
|
if pkt.length == 3 then
|
||||||
unit.reset_alarm(pkt.data[3])
|
unit.reset_alarm(pkt.data[3])
|
||||||
else
|
else
|
||||||
log.debug(log_header .. "CRDN command unit reset alarm missing id")
|
log.debug(log_header .. "CRDN command unit reset alarm missing alarm id")
|
||||||
|
end
|
||||||
|
elseif cmd == UNIT_COMMANDS.SET_GROUP then
|
||||||
|
if pkt.length == 3 then
|
||||||
|
unit.set_group(pkt.data[3])
|
||||||
|
_send(SCADA_CRDN_TYPES.UNIT_CMD, { cmd, uid, pkt.data[3] })
|
||||||
|
else
|
||||||
|
log.debug(log_header .. "CRDN command unit set group missing group id")
|
||||||
|
end
|
||||||
|
elseif cmd == UNIT_COMMANDS.SET_LIMIT then
|
||||||
|
if pkt.length == 3 then
|
||||||
|
unit.set_burn_limit(pkt.data[3])
|
||||||
|
_send(SCADA_CRDN_TYPES.UNIT_CMD, { cmd, uid, pkt.data[3] })
|
||||||
|
else
|
||||||
|
log.debug(log_header .. "CRDN command unit set limit missing group id")
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
log.debug(log_header .. "CRDN command unknown")
|
log.debug(log_header .. "CRDN command unknown")
|
||||||
|
@ -3,17 +3,102 @@ local rsio = require("scada-common.rsio")
|
|||||||
local util = require("scada-common.util")
|
local util = require("scada-common.util")
|
||||||
|
|
||||||
local rsctl = require("supervisor.session.rsctl")
|
local rsctl = require("supervisor.session.rsctl")
|
||||||
|
local unit = require("supervisor.session.unit")
|
||||||
|
|
||||||
|
local HEATING_WATER = 20000
|
||||||
|
local HEATING_SODIUM = 200000
|
||||||
|
|
||||||
|
-- 7.14 kJ per blade for 1 mB of fissile fuel
|
||||||
|
local POWER_PER_BLADE = util.joules_to_fe(7140)
|
||||||
|
|
||||||
|
local function m_avg(length, default)
|
||||||
|
local data = {}
|
||||||
|
local index = 1
|
||||||
|
local last_t = 0 ---@type number|nil
|
||||||
|
|
||||||
|
---@class moving_average
|
||||||
|
local public = {}
|
||||||
|
|
||||||
|
-- reset all to a given value
|
||||||
|
---@param x number value
|
||||||
|
function public.reset(x)
|
||||||
|
data = {}
|
||||||
|
for _ = 1, length do table.insert(data, x) end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- record a new value
|
||||||
|
---@param x number new value
|
||||||
|
---@param t number? optional last update time to prevent duplicated entries
|
||||||
|
function public.record(x, t)
|
||||||
|
if type(t) == "number" and last_t == t then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
data[index] = x
|
||||||
|
last_t = t
|
||||||
|
|
||||||
|
index = index + 1
|
||||||
|
if index > length then index = 1 end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- compute the moving average
|
||||||
|
---@return number average
|
||||||
|
function public.compute()
|
||||||
|
local sum = 0
|
||||||
|
for i = 1, length do sum = sum + data[i] end
|
||||||
|
return sum
|
||||||
|
end
|
||||||
|
|
||||||
|
public.reset(default)
|
||||||
|
|
||||||
|
return public
|
||||||
|
end
|
||||||
|
|
||||||
|
---@alias PROCESS integer
|
||||||
|
local PROCESS = {
|
||||||
|
INACTIVE = 1,
|
||||||
|
SIMPLE = 2,
|
||||||
|
CHARGE = 3,
|
||||||
|
GEN_RATE = 4,
|
||||||
|
BURN_RATE = 5
|
||||||
|
}
|
||||||
|
|
||||||
---@class facility_management
|
---@class facility_management
|
||||||
local facility = {}
|
local facility = {}
|
||||||
|
|
||||||
|
facility.PROCESS_MODES = PROCESS
|
||||||
|
|
||||||
-- create a new facility management object
|
-- create a new facility management object
|
||||||
function facility.new()
|
---@param num_reactors integer number of reactor units
|
||||||
|
---@param cooling_conf table cooling configurations of reactor units
|
||||||
|
function facility.new(num_reactors, cooling_conf)
|
||||||
local self = {
|
local self = {
|
||||||
|
-- components
|
||||||
|
units = {},
|
||||||
induction = {},
|
induction = {},
|
||||||
redstone = {}
|
redstone = {},
|
||||||
|
-- process control
|
||||||
|
mode = PROCESS.INACTIVE,
|
||||||
|
charge_target = 0, -- FE
|
||||||
|
charge_rate = 0, -- FE/t
|
||||||
|
charge_limit = 0.99, -- percentage
|
||||||
|
burn_rate_set = 0,
|
||||||
|
unit_limits = {},
|
||||||
|
-- statistics
|
||||||
|
im_stat_init = false,
|
||||||
|
avg_charge = m_avg(10, 0.0),
|
||||||
|
avg_inflow = m_avg(10, 0.0),
|
||||||
|
avg_outflow = m_avg(10, 0.0)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
-- create units
|
||||||
|
for i = 1, num_reactors do
|
||||||
|
table.insert(self.units, unit.new(i, cooling_conf[i].BOILERS, cooling_conf[i].TURBINES))
|
||||||
|
|
||||||
|
local u_lim = { burn_rate = -1.0, temp = 1100 } ---@class unit_limit
|
||||||
|
table.insert(self.unit_limits, u_lim)
|
||||||
|
end
|
||||||
|
|
||||||
-- init redstone RTU I/O controller
|
-- init redstone RTU I/O controller
|
||||||
local rs_rtu_io_ctl = rsctl.new(self.redstone)
|
local rs_rtu_io_ctl = rsctl.new(self.redstone)
|
||||||
|
|
||||||
@ -58,6 +143,13 @@ function facility.new()
|
|||||||
_unlink_disconnected_units(self.redstone)
|
_unlink_disconnected_units(self.redstone)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function public.update_units()
|
||||||
|
for i = 1, #self.units do
|
||||||
|
local u = self.units[i] ---@type reactor_unit
|
||||||
|
u.update()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
-- READ STATES/PROPERTIES --
|
-- READ STATES/PROPERTIES --
|
||||||
|
|
||||||
-- get build properties of all machines
|
-- get build properties of all machines
|
||||||
@ -94,6 +186,10 @@ function facility.new()
|
|||||||
return status
|
return status
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function public.get_units()
|
||||||
|
return self.units
|
||||||
|
end
|
||||||
|
|
||||||
return public
|
return public
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -37,8 +37,7 @@ local PERIODICS = {
|
|||||||
---@param out_queue mqueue
|
---@param out_queue mqueue
|
||||||
---@param advertisement table
|
---@param advertisement table
|
||||||
---@param facility facility
|
---@param facility facility
|
||||||
---@param facility_units table
|
function rtu.new_session(id, in_queue, out_queue, advertisement, facility)
|
||||||
function rtu.new_session(id, in_queue, out_queue, advertisement, facility, facility_units)
|
|
||||||
local log_header = "rtu_session(" .. id .. "): "
|
local log_header = "rtu_session(" .. id .. "): "
|
||||||
|
|
||||||
local self = {
|
local self = {
|
||||||
@ -46,6 +45,7 @@ function rtu.new_session(id, in_queue, out_queue, advertisement, facility, facil
|
|||||||
out_q = out_queue,
|
out_q = out_queue,
|
||||||
modbus_q = mqueue.new(),
|
modbus_q = mqueue.new(),
|
||||||
advert = advertisement,
|
advert = advertisement,
|
||||||
|
fac_units = facility.get_units(),
|
||||||
-- connection properties
|
-- connection properties
|
||||||
seq_num = 0,
|
seq_num = 0,
|
||||||
r_seq_num = nil,
|
r_seq_num = nil,
|
||||||
@ -71,8 +71,8 @@ function rtu.new_session(id, in_queue, out_queue, advertisement, facility, facil
|
|||||||
local function _handle_advertisement()
|
local function _handle_advertisement()
|
||||||
_reset_config()
|
_reset_config()
|
||||||
|
|
||||||
for i = 1, #facility_units do
|
for i = 1, #self.fac_units do
|
||||||
local unit = facility_units[i] ---@type reactor_unit
|
local unit = self.fac_units[i] ---@type reactor_unit
|
||||||
unit.purge_rtu_devices(id)
|
unit.purge_rtu_devices(id)
|
||||||
facility.purge_rtu_devices(id)
|
facility.purge_rtu_devices(id)
|
||||||
end
|
end
|
||||||
@ -105,7 +105,7 @@ function rtu.new_session(id, in_queue, out_queue, advertisement, facility, facil
|
|||||||
if advert_validator.valid() then
|
if advert_validator.valid() then
|
||||||
advert_validator.assert_min(unit_advert.index, 1)
|
advert_validator.assert_min(unit_advert.index, 1)
|
||||||
advert_validator.assert_min(unit_advert.reactor, 0)
|
advert_validator.assert_min(unit_advert.reactor, 0)
|
||||||
advert_validator.assert_max(unit_advert.reactor, #facility_units)
|
advert_validator.assert_max(unit_advert.reactor, #self.fac_units)
|
||||||
if not advert_validator.valid() then u_type = false end
|
if not advert_validator.valid() then u_type = false end
|
||||||
else
|
else
|
||||||
u_type = false
|
u_type = false
|
||||||
@ -121,7 +121,7 @@ function rtu.new_session(id, in_queue, out_queue, advertisement, facility, facil
|
|||||||
log.debug(log_header .. "advertisement unit validation failure")
|
log.debug(log_header .. "advertisement unit validation failure")
|
||||||
else
|
else
|
||||||
if unit_advert.reactor > 0 then
|
if unit_advert.reactor > 0 then
|
||||||
local target_unit = facility_units[unit_advert.reactor] ---@type reactor_unit
|
local target_unit = self.fac_units[unit_advert.reactor] ---@type reactor_unit
|
||||||
|
|
||||||
if u_type == RTU_UNIT_TYPES.REDSTONE then
|
if u_type == RTU_UNIT_TYPES.REDSTONE then
|
||||||
-- redstone
|
-- redstone
|
||||||
|
@ -4,7 +4,6 @@ local util = require("scada-common.util")
|
|||||||
|
|
||||||
local facility = require("supervisor.session.facility")
|
local facility = require("supervisor.session.facility")
|
||||||
local svqtypes = require("supervisor.session.svqtypes")
|
local svqtypes = require("supervisor.session.svqtypes")
|
||||||
local unit = require("supervisor.session.unit")
|
|
||||||
|
|
||||||
local coordinator = require("supervisor.session.coordinator")
|
local coordinator = require("supervisor.session.coordinator")
|
||||||
local plc = require("supervisor.session.plc")
|
local plc = require("supervisor.session.plc")
|
||||||
@ -33,8 +32,7 @@ svsessions.SESSION_TYPE = SESSION_TYPE
|
|||||||
local self = {
|
local self = {
|
||||||
modem = nil,
|
modem = nil,
|
||||||
num_reactors = 0,
|
num_reactors = 0,
|
||||||
facility = facility.new(),
|
facility = nil, ---@type facility
|
||||||
units = {},
|
|
||||||
rtu_sessions = {},
|
rtu_sessions = {},
|
||||||
plc_sessions = {},
|
plc_sessions = {},
|
||||||
coord_sessions = {},
|
coord_sessions = {},
|
||||||
@ -199,11 +197,7 @@ end
|
|||||||
function svsessions.init(modem, num_reactors, cooling_conf)
|
function svsessions.init(modem, num_reactors, cooling_conf)
|
||||||
self.modem = modem
|
self.modem = modem
|
||||||
self.num_reactors = num_reactors
|
self.num_reactors = num_reactors
|
||||||
self.units = {}
|
self.facility = facility.new(num_reactors, cooling_conf)
|
||||||
|
|
||||||
for i = 1, self.num_reactors do
|
|
||||||
table.insert(self.units, unit.new(i, cooling_conf[i].BOILERS, cooling_conf[i].TURBINES))
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
-- re-link the modem
|
-- re-link the modem
|
||||||
@ -299,7 +293,8 @@ function svsessions.establish_plc_session(local_port, remote_port, for_reactor,
|
|||||||
plc_s.instance = plc.new_session(self.next_plc_id, for_reactor, plc_s.in_queue, plc_s.out_queue)
|
plc_s.instance = plc.new_session(self.next_plc_id, for_reactor, plc_s.in_queue, plc_s.out_queue)
|
||||||
table.insert(self.plc_sessions, plc_s)
|
table.insert(self.plc_sessions, plc_s)
|
||||||
|
|
||||||
self.units[for_reactor].link_plc_session(plc_s)
|
local units = self.facility.get_units()
|
||||||
|
units[for_reactor].link_plc_session(plc_s)
|
||||||
|
|
||||||
log.debug("established new PLC session to " .. remote_port .. " with ID " .. self.next_plc_id)
|
log.debug("established new PLC session to " .. remote_port .. " with ID " .. self.next_plc_id)
|
||||||
|
|
||||||
@ -332,7 +327,7 @@ function svsessions.establish_rtu_session(local_port, remote_port, advertisement
|
|||||||
instance = nil ---@type rtu_session
|
instance = nil ---@type rtu_session
|
||||||
}
|
}
|
||||||
|
|
||||||
rtu_s.instance = rtu.new_session(self.next_rtu_id, rtu_s.in_queue, rtu_s.out_queue, advertisement, self.facility, self.units)
|
rtu_s.instance = rtu.new_session(self.next_rtu_id, rtu_s.in_queue, rtu_s.out_queue, advertisement, self.facility)
|
||||||
table.insert(self.rtu_sessions, rtu_s)
|
table.insert(self.rtu_sessions, rtu_s)
|
||||||
|
|
||||||
log.debug("established new RTU session to " .. remote_port .. " with ID " .. self.next_rtu_id)
|
log.debug("established new RTU session to " .. remote_port .. " with ID " .. self.next_rtu_id)
|
||||||
@ -362,7 +357,7 @@ function svsessions.establish_coord_session(local_port, remote_port, version)
|
|||||||
instance = nil ---@type coord_session
|
instance = nil ---@type coord_session
|
||||||
}
|
}
|
||||||
|
|
||||||
coord_s.instance = coordinator.new_session(self.next_coord_id, coord_s.in_queue, coord_s.out_queue, self.facility, self.units)
|
coord_s.instance = coordinator.new_session(self.next_coord_id, coord_s.in_queue, coord_s.out_queue, self.facility)
|
||||||
table.insert(self.coord_sessions, coord_s)
|
table.insert(self.coord_sessions, coord_s)
|
||||||
|
|
||||||
log.debug("established new coordinator session to " .. remote_port .. " with ID " .. self.next_coord_id)
|
log.debug("established new coordinator session to " .. remote_port .. " with ID " .. self.next_coord_id)
|
||||||
@ -405,10 +400,7 @@ function svsessions.iterate_all()
|
|||||||
self.facility.update()
|
self.facility.update()
|
||||||
|
|
||||||
-- iterate units
|
-- iterate units
|
||||||
for i = 1, #self.units do
|
self.facility.update_units()
|
||||||
local u = self.units[i] ---@type reactor_unit
|
|
||||||
u.update()
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
-- delete all closed sessions
|
-- delete all closed sessions
|
||||||
|
@ -88,7 +88,10 @@ function unit.new(for_reactor, num_boilers, num_turbines)
|
|||||||
damage_last = 0,
|
damage_last = 0,
|
||||||
damage_est_last = 0,
|
damage_est_last = 0,
|
||||||
waste_mode = WASTE_MODE.AUTO,
|
waste_mode = WASTE_MODE.AUTO,
|
||||||
status_text = { "Unknown", "Awaiting Connection..." },
|
status_text = { "UNKNOWN", "awaiting connection..." },
|
||||||
|
-- auto control
|
||||||
|
group = 0,
|
||||||
|
limit = 0.0,
|
||||||
-- logic for alarms
|
-- logic for alarms
|
||||||
had_reactor = false,
|
had_reactor = false,
|
||||||
start_ms = 0,
|
start_ms = 0,
|
||||||
@ -947,6 +950,28 @@ function unit.new(for_reactor, num_boilers, num_turbines)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- set the automatic control group of this unit
|
||||||
|
---@param group integer group ID or 0 for independent
|
||||||
|
function public.set_group(group)
|
||||||
|
if group >= 0 and group <= 4 then
|
||||||
|
self.group = group
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- set the automatic control max burn rate for this unit
|
||||||
|
---@param limit number burn rate limit for auto control
|
||||||
|
function public.set_burn_limit(limit)
|
||||||
|
if limit >= 0 then
|
||||||
|
self.limit = limit
|
||||||
|
|
||||||
|
if self.plc_i ~= nil then
|
||||||
|
if limit > self.plc_i.get_struct().max_burn then
|
||||||
|
self.limit = self.plc_i.get_struct().max_burn
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
-- READ STATES/PROPERTIES --
|
-- READ STATES/PROPERTIES --
|
||||||
|
|
||||||
-- get build properties of all machines
|
-- get build properties of all machines
|
||||||
|
@ -14,7 +14,7 @@ local svsessions = require("supervisor.session.svsessions")
|
|||||||
local config = require("supervisor.config")
|
local config = require("supervisor.config")
|
||||||
local supervisor = require("supervisor.supervisor")
|
local supervisor = require("supervisor.supervisor")
|
||||||
|
|
||||||
local SUPERVISOR_VERSION = "beta-v0.9.1"
|
local SUPERVISOR_VERSION = "beta-v0.9.2"
|
||||||
|
|
||||||
local print = util.print
|
local print = util.print
|
||||||
local println = util.println
|
local println = util.println
|
||||||
|
Reference in New Issue
Block a user