#24 coordinator/supervisor setting process groups and unit burn rate limits
This commit is contained in:
@@ -45,13 +45,13 @@ local PERIODICS = {
|
||||
---@param in_queue mqueue
|
||||
---@param out_queue mqueue
|
||||
---@param facility facility
|
||||
---@param units table
|
||||
function coordinator.new_session(id, in_queue, out_queue, facility, units)
|
||||
function coordinator.new_session(id, in_queue, out_queue, facility)
|
||||
local log_header = "crdn_session(" .. id .. "): "
|
||||
|
||||
local self = {
|
||||
in_q = in_queue,
|
||||
out_q = out_queue,
|
||||
units = facility.get_units(),
|
||||
-- connection properties
|
||||
seq_num = 0,
|
||||
r_seq_num = nil,
|
||||
@@ -122,8 +122,8 @@ function coordinator.new_session(id, in_queue, out_queue, facility, units)
|
||||
|
||||
local builds = {}
|
||||
|
||||
for i = 1, #units do
|
||||
local unit = units[i] ---@type reactor_unit
|
||||
for i = 1, #self.units do
|
||||
local unit = self.units[i] ---@type reactor_unit
|
||||
builds[unit.get_id()] = unit.get_build()
|
||||
end
|
||||
|
||||
@@ -143,8 +143,8 @@ function coordinator.new_session(id, in_queue, out_queue, facility, units)
|
||||
local function _send_unit_statuses()
|
||||
local status = {}
|
||||
|
||||
for i = 1, #units do
|
||||
local unit = units[i] ---@type reactor_unit
|
||||
for i = 1, #self.units do
|
||||
local unit = self.units[i] ---@type reactor_unit
|
||||
status[unit.get_id()] = {
|
||||
unit.get_reactor_status(),
|
||||
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] }
|
||||
|
||||
-- continue if valid unit id
|
||||
if util.is_int(uid) and uid > 0 and uid <= #units then
|
||||
local unit = units[uid] ---@type reactor_unit
|
||||
if util.is_int(uid) and uid > 0 and uid <= #self.units then
|
||||
local unit = self.units[uid] ---@type reactor_unit
|
||||
|
||||
if cmd == UNIT_COMMANDS.START then
|
||||
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
|
||||
unit.ack_alarm(pkt.data[3])
|
||||
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
|
||||
elseif cmd == UNIT_COMMANDS.RESET_ALARM then
|
||||
if pkt.length == 3 then
|
||||
unit.reset_alarm(pkt.data[3])
|
||||
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
|
||||
else
|
||||
log.debug(log_header .. "CRDN command unknown")
|
||||
|
||||
@@ -3,17 +3,102 @@ local rsio = require("scada-common.rsio")
|
||||
local util = require("scada-common.util")
|
||||
|
||||
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
|
||||
local facility = {}
|
||||
|
||||
facility.PROCESS_MODES = PROCESS
|
||||
|
||||
-- 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 = {
|
||||
-- components
|
||||
units = {},
|
||||
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
|
||||
local rs_rtu_io_ctl = rsctl.new(self.redstone)
|
||||
|
||||
@@ -58,6 +143,13 @@ function facility.new()
|
||||
_unlink_disconnected_units(self.redstone)
|
||||
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 --
|
||||
|
||||
-- get build properties of all machines
|
||||
@@ -94,6 +186,10 @@ function facility.new()
|
||||
return status
|
||||
end
|
||||
|
||||
function public.get_units()
|
||||
return self.units
|
||||
end
|
||||
|
||||
return public
|
||||
end
|
||||
|
||||
|
||||
@@ -37,8 +37,7 @@ local PERIODICS = {
|
||||
---@param out_queue mqueue
|
||||
---@param advertisement table
|
||||
---@param facility facility
|
||||
---@param facility_units table
|
||||
function rtu.new_session(id, in_queue, out_queue, advertisement, facility, facility_units)
|
||||
function rtu.new_session(id, in_queue, out_queue, advertisement, facility)
|
||||
local log_header = "rtu_session(" .. id .. "): "
|
||||
|
||||
local self = {
|
||||
@@ -46,6 +45,7 @@ function rtu.new_session(id, in_queue, out_queue, advertisement, facility, facil
|
||||
out_q = out_queue,
|
||||
modbus_q = mqueue.new(),
|
||||
advert = advertisement,
|
||||
fac_units = facility.get_units(),
|
||||
-- connection properties
|
||||
seq_num = 0,
|
||||
r_seq_num = nil,
|
||||
@@ -71,8 +71,8 @@ function rtu.new_session(id, in_queue, out_queue, advertisement, facility, facil
|
||||
local function _handle_advertisement()
|
||||
_reset_config()
|
||||
|
||||
for i = 1, #facility_units do
|
||||
local unit = facility_units[i] ---@type reactor_unit
|
||||
for i = 1, #self.fac_units do
|
||||
local unit = self.fac_units[i] ---@type reactor_unit
|
||||
unit.purge_rtu_devices(id)
|
||||
facility.purge_rtu_devices(id)
|
||||
end
|
||||
@@ -105,7 +105,7 @@ function rtu.new_session(id, in_queue, out_queue, advertisement, facility, facil
|
||||
if advert_validator.valid() then
|
||||
advert_validator.assert_min(unit_advert.index, 1)
|
||||
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
|
||||
else
|
||||
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")
|
||||
else
|
||||
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
|
||||
-- redstone
|
||||
|
||||
@@ -4,7 +4,6 @@ local util = require("scada-common.util")
|
||||
|
||||
local facility = require("supervisor.session.facility")
|
||||
local svqtypes = require("supervisor.session.svqtypes")
|
||||
local unit = require("supervisor.session.unit")
|
||||
|
||||
local coordinator = require("supervisor.session.coordinator")
|
||||
local plc = require("supervisor.session.plc")
|
||||
@@ -33,8 +32,7 @@ svsessions.SESSION_TYPE = SESSION_TYPE
|
||||
local self = {
|
||||
modem = nil,
|
||||
num_reactors = 0,
|
||||
facility = facility.new(),
|
||||
units = {},
|
||||
facility = nil, ---@type facility
|
||||
rtu_sessions = {},
|
||||
plc_sessions = {},
|
||||
coord_sessions = {},
|
||||
@@ -199,11 +197,7 @@ end
|
||||
function svsessions.init(modem, num_reactors, cooling_conf)
|
||||
self.modem = modem
|
||||
self.num_reactors = num_reactors
|
||||
self.units = {}
|
||||
|
||||
for i = 1, self.num_reactors do
|
||||
table.insert(self.units, unit.new(i, cooling_conf[i].BOILERS, cooling_conf[i].TURBINES))
|
||||
end
|
||||
self.facility = facility.new(num_reactors, cooling_conf)
|
||||
end
|
||||
|
||||
-- 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)
|
||||
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)
|
||||
|
||||
@@ -332,7 +327,7 @@ function svsessions.establish_rtu_session(local_port, remote_port, advertisement
|
||||
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)
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
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)
|
||||
|
||||
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()
|
||||
|
||||
-- iterate units
|
||||
for i = 1, #self.units do
|
||||
local u = self.units[i] ---@type reactor_unit
|
||||
u.update()
|
||||
end
|
||||
self.facility.update_units()
|
||||
end
|
||||
|
||||
-- delete all closed sessions
|
||||
|
||||
@@ -88,7 +88,10 @@ function unit.new(for_reactor, num_boilers, num_turbines)
|
||||
damage_last = 0,
|
||||
damage_est_last = 0,
|
||||
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
|
||||
had_reactor = false,
|
||||
start_ms = 0,
|
||||
@@ -947,6 +950,28 @@ function unit.new(for_reactor, num_boilers, num_turbines)
|
||||
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 --
|
||||
|
||||
-- get build properties of all machines
|
||||
|
||||
Reference in New Issue
Block a user