mirror of
https://github.com/MikaylaFischler/cc-mek-scada.git
synced 2024-08-30 18:22:34 +00:00
#123 RTU startup without devices, fixed repeat RTU advert handling, added PPM virtual devices, fixed log out of space detection, updated RTU type conversion functions in comms
This commit is contained in:
parent
f940c136bf
commit
1a01bec7e4
@ -16,7 +16,7 @@ local config = require("coordinator.config")
|
|||||||
local coordinator = require("coordinator.coordinator")
|
local coordinator = require("coordinator.coordinator")
|
||||||
local renderer = require("coordinator.renderer")
|
local renderer = require("coordinator.renderer")
|
||||||
|
|
||||||
local COORDINATOR_VERSION = "alpha-v0.6.9"
|
local COORDINATOR_VERSION = "alpha-v0.6.10"
|
||||||
|
|
||||||
local print = util.print
|
local print = util.print
|
||||||
local println = util.println
|
local println = util.println
|
||||||
|
@ -13,7 +13,7 @@ local config = require("reactor-plc.config")
|
|||||||
local plc = require("reactor-plc.plc")
|
local plc = require("reactor-plc.plc")
|
||||||
local threads = require("reactor-plc.threads")
|
local threads = require("reactor-plc.threads")
|
||||||
|
|
||||||
local R_PLC_VERSION = "beta-v0.9.4"
|
local R_PLC_VERSION = "beta-v0.9.5"
|
||||||
|
|
||||||
local print = util.print
|
local print = util.print
|
||||||
local println = util.println
|
local println = util.println
|
||||||
|
172
rtu/startup.lua
172
rtu/startup.lua
@ -24,7 +24,7 @@ local sna_rtu = require("rtu.dev.sna_rtu")
|
|||||||
local sps_rtu = require("rtu.dev.sps_rtu")
|
local sps_rtu = require("rtu.dev.sps_rtu")
|
||||||
local turbinev_rtu = require("rtu.dev.turbinev_rtu")
|
local turbinev_rtu = require("rtu.dev.turbinev_rtu")
|
||||||
|
|
||||||
local RTU_VERSION = "beta-v0.9.1"
|
local RTU_VERSION = "beta-v0.9.2"
|
||||||
|
|
||||||
local rtu_t = types.rtu_t
|
local rtu_t = types.rtu_t
|
||||||
|
|
||||||
@ -257,98 +257,104 @@ local function configure()
|
|||||||
|
|
||||||
local device = ppm.get_periph(name)
|
local device = ppm.get_periph(name)
|
||||||
|
|
||||||
|
local type = nil
|
||||||
|
local rtu_iface = nil ---@type rtu_device
|
||||||
|
local rtu_type = ""
|
||||||
|
local formed = nil ---@type boolean|nil
|
||||||
|
|
||||||
if device == nil then
|
if device == nil then
|
||||||
local message = util.c("configure> '", name, "' not found")
|
local message = util.c("configure> '", name, "' not found, using placeholder")
|
||||||
println(message)
|
println(message)
|
||||||
log.fatal(message)
|
log.warning(message)
|
||||||
return false
|
|
||||||
|
-- mount a virtual (placeholder) device
|
||||||
|
type, device = ppm.mount_virtual()
|
||||||
else
|
else
|
||||||
local type = ppm.get_type(name)
|
type = ppm.get_type(name)
|
||||||
local rtu_iface = nil ---@type rtu_device
|
end
|
||||||
local rtu_type = ""
|
|
||||||
local formed = nil ---@type boolean|nil
|
|
||||||
|
|
||||||
if type == "boilerValve" then
|
if type == "boilerValve" then
|
||||||
-- boiler multiblock
|
-- boiler multiblock
|
||||||
rtu_type = rtu_t.boiler_valve
|
rtu_type = rtu_t.boiler_valve
|
||||||
rtu_iface = boilerv_rtu.new(device)
|
rtu_iface = boilerv_rtu.new(device)
|
||||||
formed = device.isFormed()
|
formed = device.isFormed()
|
||||||
|
|
||||||
if formed == ppm.UNDEFINED_FIELD or formed == ppm.ACCESS_FAULT then
|
if formed == ppm.UNDEFINED_FIELD or formed == ppm.ACCESS_FAULT then
|
||||||
println_ts(util.c("configure> failed to check if '", name, "' is formed"))
|
println_ts(util.c("configure> failed to check if '", name, "' is formed"))
|
||||||
log.fatal(util.c("configure> failed to check if '", name, "' is a formed boiler multiblock"))
|
log.fatal(util.c("configure> failed to check if '", name, "' is a formed boiler multiblock"))
|
||||||
return false
|
|
||||||
end
|
|
||||||
elseif type == "turbineValve" then
|
|
||||||
-- turbine multiblock
|
|
||||||
rtu_type = rtu_t.turbine_valve
|
|
||||||
rtu_iface = turbinev_rtu.new(device)
|
|
||||||
formed = device.isFormed()
|
|
||||||
|
|
||||||
if formed == ppm.UNDEFINED_FIELD or formed == ppm.ACCESS_FAULT then
|
|
||||||
println_ts(util.c("configure> failed to check if '", name, "' is formed"))
|
|
||||||
log.fatal(util.c("configure> failed to check if '", name, "' is a formed turbine multiblock"))
|
|
||||||
return false
|
|
||||||
end
|
|
||||||
elseif type == "inductionPort" then
|
|
||||||
-- induction matrix multiblock
|
|
||||||
rtu_type = rtu_t.induction_matrix
|
|
||||||
rtu_iface = imatrix_rtu.new(device)
|
|
||||||
formed = device.isFormed()
|
|
||||||
|
|
||||||
if formed == ppm.UNDEFINED_FIELD or formed == ppm.ACCESS_FAULT then
|
|
||||||
println_ts(util.c("configure> failed to check if '", name, "' is formed"))
|
|
||||||
log.fatal(util.c("configure> failed to check if '", name, "' is a formed induction matrix multiblock"))
|
|
||||||
return false
|
|
||||||
end
|
|
||||||
elseif type == "spsPort" then
|
|
||||||
-- SPS multiblock
|
|
||||||
rtu_type = rtu_t.sps
|
|
||||||
rtu_iface = sps_rtu.new(device)
|
|
||||||
formed = device.isFormed()
|
|
||||||
|
|
||||||
if formed == ppm.UNDEFINED_FIELD or formed == ppm.ACCESS_FAULT then
|
|
||||||
println_ts(util.c("configure> failed to check if '", name, "' is formed"))
|
|
||||||
log.fatal(util.c("configure> failed to check if '", name, "' is a formed SPS multiblock"))
|
|
||||||
return false
|
|
||||||
end
|
|
||||||
elseif type == "solarNeutronActivator" then
|
|
||||||
-- SNA
|
|
||||||
rtu_type = rtu_t.sna
|
|
||||||
rtu_iface = sna_rtu.new(device)
|
|
||||||
elseif type == "environmentDetector" then
|
|
||||||
-- advanced peripherals environment detector
|
|
||||||
rtu_type = rtu_t.env_detector
|
|
||||||
rtu_iface = envd_rtu.new(device)
|
|
||||||
else
|
|
||||||
local message = util.c("configure> device '", name, "' is not a known type (", type, ")")
|
|
||||||
println_ts(message)
|
|
||||||
log.fatal(message)
|
|
||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
|
elseif type == "turbineValve" then
|
||||||
|
-- turbine multiblock
|
||||||
|
rtu_type = rtu_t.turbine_valve
|
||||||
|
rtu_iface = turbinev_rtu.new(device)
|
||||||
|
formed = device.isFormed()
|
||||||
|
|
||||||
if rtu_iface ~= nil then
|
if formed == ppm.UNDEFINED_FIELD or formed == ppm.ACCESS_FAULT then
|
||||||
---@class rtu_unit_registry_entry
|
println_ts(util.c("configure> failed to check if '", name, "' is formed"))
|
||||||
local rtu_unit = {
|
log.fatal(util.c("configure> failed to check if '", name, "' is a formed turbine multiblock"))
|
||||||
name = name,
|
return false
|
||||||
type = rtu_type,
|
|
||||||
index = index,
|
|
||||||
reactor = for_reactor,
|
|
||||||
device = device,
|
|
||||||
formed = formed,
|
|
||||||
rtu = rtu_iface, ---@type rtu_device|rtu_rs_device
|
|
||||||
modbus_io = modbus.new(rtu_iface, true),
|
|
||||||
pkt_queue = mqueue.new(), ---@type mqueue|nil
|
|
||||||
thread = nil
|
|
||||||
}
|
|
||||||
|
|
||||||
rtu_unit.thread = threads.thread__unit_comms(__shared_memory, rtu_unit)
|
|
||||||
|
|
||||||
table.insert(units, rtu_unit)
|
|
||||||
|
|
||||||
log.debug(util.c("configure> initialized RTU unit #", #units, ": ", name, " (", rtu_type, ") [", index, "] for reactor ", for_reactor))
|
|
||||||
end
|
end
|
||||||
|
elseif type == "inductionPort" then
|
||||||
|
-- induction matrix multiblock
|
||||||
|
rtu_type = rtu_t.induction_matrix
|
||||||
|
rtu_iface = imatrix_rtu.new(device)
|
||||||
|
formed = device.isFormed()
|
||||||
|
|
||||||
|
if formed == ppm.UNDEFINED_FIELD or formed == ppm.ACCESS_FAULT then
|
||||||
|
println_ts(util.c("configure> failed to check if '", name, "' is formed"))
|
||||||
|
log.fatal(util.c("configure> failed to check if '", name, "' is a formed induction matrix multiblock"))
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
elseif type == "spsPort" then
|
||||||
|
-- SPS multiblock
|
||||||
|
rtu_type = rtu_t.sps
|
||||||
|
rtu_iface = sps_rtu.new(device)
|
||||||
|
formed = device.isFormed()
|
||||||
|
|
||||||
|
if formed == ppm.UNDEFINED_FIELD or formed == ppm.ACCESS_FAULT then
|
||||||
|
println_ts(util.c("configure> failed to check if '", name, "' is formed"))
|
||||||
|
log.fatal(util.c("configure> failed to check if '", name, "' is a formed SPS multiblock"))
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
elseif type == "solarNeutronActivator" then
|
||||||
|
-- SNA
|
||||||
|
rtu_type = rtu_t.sna
|
||||||
|
rtu_iface = sna_rtu.new(device)
|
||||||
|
elseif type == "environmentDetector" then
|
||||||
|
-- advanced peripherals environment detector
|
||||||
|
rtu_type = rtu_t.env_detector
|
||||||
|
rtu_iface = envd_rtu.new(device)
|
||||||
|
elseif type == ppm.VIRTUAL_DEVICE_TYPE then
|
||||||
|
-- placeholder device
|
||||||
|
rtu_type = "virtual"
|
||||||
|
rtu_iface = rtu.init_unit().interface()
|
||||||
|
else
|
||||||
|
local message = util.c("configure> device '", name, "' is not a known type (", type, ")")
|
||||||
|
println_ts(message)
|
||||||
|
log.fatal(message)
|
||||||
|
return false
|
||||||
end
|
end
|
||||||
|
|
||||||
|
---@class rtu_unit_registry_entry
|
||||||
|
local rtu_unit = {
|
||||||
|
name = name,
|
||||||
|
type = rtu_type,
|
||||||
|
index = index,
|
||||||
|
reactor = for_reactor,
|
||||||
|
device = device,
|
||||||
|
formed = formed,
|
||||||
|
rtu = rtu_iface, ---@type rtu_device|rtu_rs_device
|
||||||
|
modbus_io = modbus.new(rtu_iface, true),
|
||||||
|
pkt_queue = mqueue.new(), ---@type mqueue|nil
|
||||||
|
thread = nil
|
||||||
|
}
|
||||||
|
|
||||||
|
rtu_unit.thread = threads.thread__unit_comms(__shared_memory, rtu_unit)
|
||||||
|
|
||||||
|
table.insert(units, rtu_unit)
|
||||||
|
|
||||||
|
log.debug(util.c("configure> initialized RTU unit #", #units, ": ", name, " (", rtu_type, ") [", index, "] for reactor ", for_reactor))
|
||||||
end
|
end
|
||||||
|
|
||||||
-- we made it through all that trusting-user-to-write-a-config-file chaos
|
-- we made it through all that trusting-user-to-write-a-config-file chaos
|
||||||
|
@ -122,9 +122,37 @@ function threads.thread__main(smem)
|
|||||||
-- find disconnected device to reconnect
|
-- find disconnected device to reconnect
|
||||||
-- note: cannot check isFormed as that would yield this coroutine and consume events
|
-- note: cannot check isFormed as that would yield this coroutine and consume events
|
||||||
if unit.name == param1 then
|
if unit.name == param1 then
|
||||||
|
local resend_advert = false
|
||||||
|
|
||||||
-- found, re-link
|
-- found, re-link
|
||||||
unit.device = device
|
unit.device = device
|
||||||
|
|
||||||
|
if unit.type == "virtual" then
|
||||||
|
resend_advert = true
|
||||||
|
if type == "boilerValve" then
|
||||||
|
-- boiler multiblock
|
||||||
|
unit.type = rtu_t.boiler_valve
|
||||||
|
elseif type == "turbineValve" then
|
||||||
|
-- turbine multiblock
|
||||||
|
unit.type = rtu_t.turbine_valve
|
||||||
|
elseif type == "inductionPort" then
|
||||||
|
-- induction matrix multiblock
|
||||||
|
unit.type = rtu_t.induction_matrix
|
||||||
|
elseif type == "spsPort" then
|
||||||
|
-- SPS multiblock
|
||||||
|
unit.type = rtu_t.sps
|
||||||
|
elseif type == "solarNeutronActivator" then
|
||||||
|
-- SNA
|
||||||
|
unit.type = rtu_t.sna
|
||||||
|
elseif type == "environmentDetector" then
|
||||||
|
-- advanced peripherals environment detector
|
||||||
|
unit.type = rtu_t.env_detector
|
||||||
|
else
|
||||||
|
resend_advert = false
|
||||||
|
log.error(util.c("virtual device '", unit.name, "' cannot init to an unknown type (", type, ")"))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
if unit.type == rtu_t.boiler_valve then
|
if unit.type == rtu_t.boiler_valve then
|
||||||
unit.rtu = boilerv_rtu.new(device)
|
unit.rtu = boilerv_rtu.new(device)
|
||||||
unit.formed = true
|
unit.formed = true
|
||||||
@ -142,14 +170,19 @@ function threads.thread__main(smem)
|
|||||||
elseif unit.type == rtu_t.env_detector then
|
elseif unit.type == rtu_t.env_detector then
|
||||||
unit.rtu = envd_rtu.new(device)
|
unit.rtu = envd_rtu.new(device)
|
||||||
else
|
else
|
||||||
log.error(util.c("unreachable case occured trying to identify reconnected RTU unit type (", unit.name, ")"), true)
|
log.error(util.c("failed to identify reconnected RTU unit type (", unit.name, ")"), true)
|
||||||
end
|
end
|
||||||
|
|
||||||
unit.modbus_io = modbus.new(unit.rtu, true)
|
unit.modbus_io = modbus.new(unit.rtu, true)
|
||||||
|
|
||||||
rtu_comms.send_remounted(unit.index)
|
|
||||||
|
|
||||||
println_ts("reconnected the " .. unit.type .. " on interface " .. unit.name)
|
println_ts("reconnected the " .. unit.type .. " on interface " .. unit.name)
|
||||||
|
log.info("reconnected the " .. unit.type .. " on interface " .. unit.name)
|
||||||
|
|
||||||
|
if resend_advert then
|
||||||
|
rtu_comms.send_advertisement(units)
|
||||||
|
else
|
||||||
|
rtu_comms.send_remounted(unit.index)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@ -274,7 +307,6 @@ function threads.thread__unit_comms(smem, unit)
|
|||||||
|
|
||||||
local last_update = util.time()
|
local last_update = util.time()
|
||||||
|
|
||||||
local check_formed = type(unit.formed) == "boolean"
|
|
||||||
local last_f_check = 0
|
local last_f_check = 0
|
||||||
|
|
||||||
local detail_name = util.c(unit.type, " (", unit.name, ") [", unit.index, "] for reactor ", unit.reactor)
|
local detail_name = util.c(unit.type, " (", unit.name, ") [", unit.index, "] for reactor ", unit.reactor)
|
||||||
@ -308,8 +340,8 @@ function threads.thread__unit_comms(smem, unit)
|
|||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
-- check if multiblocks is still formed
|
-- check if multiblock is still formed if this is a multiblock
|
||||||
if check_formed and (util.time() - last_f_check > 1000) then
|
if (type(unit.formed) == "boolean") and (util.time() - last_f_check > 1000) then
|
||||||
if (not unit.formed) and unit.device.isFormed() then
|
if (not unit.formed) and unit.device.isFormed() then
|
||||||
-- newly re-formed
|
-- newly re-formed
|
||||||
local iface = ppm.get_iface(unit.device)
|
local iface = ppm.get_iface(unit.device)
|
||||||
|
@ -642,6 +642,12 @@ function comms.rtu_t_to_unit_type(type)
|
|||||||
return RTU_UNIT_TYPES.TURBINE_VALVE
|
return RTU_UNIT_TYPES.TURBINE_VALVE
|
||||||
elseif type == rtu_t.induction_matrix then
|
elseif type == rtu_t.induction_matrix then
|
||||||
return RTU_UNIT_TYPES.IMATRIX
|
return RTU_UNIT_TYPES.IMATRIX
|
||||||
|
elseif type == rtu_t.sps then
|
||||||
|
return RTU_UNIT_TYPES.SPS
|
||||||
|
elseif type == rtu_t.sna then
|
||||||
|
return RTU_UNIT_TYPES.SNA
|
||||||
|
elseif type == rtu_t.env_detector then
|
||||||
|
return RTU_UNIT_TYPES.ENV_DETECTOR
|
||||||
end
|
end
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
@ -659,6 +665,12 @@ function comms.advert_type_to_rtu_t(utype)
|
|||||||
return rtu_t.turbine_valve
|
return rtu_t.turbine_valve
|
||||||
elseif utype == RTU_UNIT_TYPES.IMATRIX then
|
elseif utype == RTU_UNIT_TYPES.IMATRIX then
|
||||||
return rtu_t.induction_matrix
|
return rtu_t.induction_matrix
|
||||||
|
elseif utype == RTU_UNIT_TYPES.SPS then
|
||||||
|
return rtu_t.sps
|
||||||
|
elseif utype == RTU_UNIT_TYPES.SNA then
|
||||||
|
return rtu_t.sna
|
||||||
|
elseif utype == RTU_UNIT_TYPES.ENV_DETECTOR then
|
||||||
|
return rtu_t.env_detector
|
||||||
end
|
end
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
@ -58,6 +58,7 @@ end
|
|||||||
-- private log write function
|
-- private log write function
|
||||||
---@param msg string
|
---@param msg string
|
||||||
local function _log(msg)
|
local function _log(msg)
|
||||||
|
local out_of_space = false
|
||||||
local time_stamp = os.date("[%c] ")
|
local time_stamp = os.date("[%c] ")
|
||||||
local stamped = time_stamp .. util.strval(msg)
|
local stamped = time_stamp .. util.strval(msg)
|
||||||
|
|
||||||
@ -69,15 +70,17 @@ local function _log(msg)
|
|||||||
|
|
||||||
-- if we don't have space, we need to create a new log file
|
-- if we don't have space, we need to create a new log file
|
||||||
|
|
||||||
if not status then
|
if (not status) and (result ~= nil) then
|
||||||
if result == "Out of space" then
|
out_of_space = string.find(result, "Out of space") ~= nil
|
||||||
|
|
||||||
|
if out_of_space then
|
||||||
-- will delete log file
|
-- will delete log file
|
||||||
elseif result ~= nil then
|
else
|
||||||
util.println("unknown error writing to logfile: " .. result)
|
util.println("unknown error writing to logfile: " .. result)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
if (result == "Out of space") or (free_space(_log_sys.path) < 100) then
|
if out_of_space or (free_space(_log_sys.path) < 100) then
|
||||||
-- delete the old log file and open a new one
|
-- delete the old log file and open a new one
|
||||||
_log_sys.file.close()
|
_log_sys.file.close()
|
||||||
fs.delete(_log_sys.path)
|
fs.delete(_log_sys.path)
|
||||||
|
@ -12,8 +12,11 @@ local ACCESS_FAULT = nil ---@type nil
|
|||||||
|
|
||||||
local UNDEFINED_FIELD = "undefined field"
|
local UNDEFINED_FIELD = "undefined field"
|
||||||
|
|
||||||
|
local VIRTUAL_DEVICE_TYPE = "ppm_vdev"
|
||||||
|
|
||||||
ppm.ACCESS_FAULT = ACCESS_FAULT
|
ppm.ACCESS_FAULT = ACCESS_FAULT
|
||||||
ppm.UNDEFINED_FIELD = UNDEFINED_FIELD
|
ppm.UNDEFINED_FIELD = UNDEFINED_FIELD
|
||||||
|
ppm.VIRTUAL_DEVICE_TYPE = VIRTUAL_DEVICE_TYPE
|
||||||
|
|
||||||
----------------------------
|
----------------------------
|
||||||
-- PRIVATE DATA/FUNCTIONS --
|
-- PRIVATE DATA/FUNCTIONS --
|
||||||
@ -23,6 +26,7 @@ local REPORT_FREQUENCY = 20 -- log every 20 faults per function
|
|||||||
|
|
||||||
local _ppm_sys = {
|
local _ppm_sys = {
|
||||||
mounts = {},
|
mounts = {},
|
||||||
|
next_vid = 0,
|
||||||
auto_cf = false,
|
auto_cf = false,
|
||||||
faulted = false,
|
faulted = false,
|
||||||
last_fault = "",
|
last_fault = "",
|
||||||
@ -42,10 +46,15 @@ local function peri_init(iface)
|
|||||||
last_fault = "",
|
last_fault = "",
|
||||||
fault_counts = {},
|
fault_counts = {},
|
||||||
auto_cf = true,
|
auto_cf = true,
|
||||||
type = peripheral.getType(iface),
|
type = VIRTUAL_DEVICE_TYPE,
|
||||||
device = peripheral.wrap(iface)
|
device = {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if iface ~= "__virtual__" then
|
||||||
|
self.type = peripheral.getType(iface)
|
||||||
|
self.device = peripheral.wrap(iface)
|
||||||
|
end
|
||||||
|
|
||||||
-- initialization process (re-map)
|
-- initialization process (re-map)
|
||||||
|
|
||||||
for key, func in pairs(self.device) do
|
for key, func in pairs(self.device) do
|
||||||
@ -245,6 +254,19 @@ function ppm.mount(iface)
|
|||||||
return pm_type, pm_dev
|
return pm_type, pm_dev
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- mount a virtual, placeholder device (specifically designed for RTU startup with missing devices)
|
||||||
|
---@return string type, table device
|
||||||
|
function ppm.mount_virtual()
|
||||||
|
local iface = "ppm_vdev_" .. _ppm_sys.next_vid
|
||||||
|
|
||||||
|
_ppm_sys.mounts[iface] = peri_init("__virtual__")
|
||||||
|
_ppm_sys.next_vid = _ppm_sys.next_vid + 1
|
||||||
|
|
||||||
|
log.info(util.c("PPM: mount_virtual() -> allocated new virtual device ", iface))
|
||||||
|
|
||||||
|
return _ppm_sys.mounts[iface].type, _ppm_sys.mounts[iface].dev
|
||||||
|
end
|
||||||
|
|
||||||
-- manually unmount a peripheral from the PPM
|
-- manually unmount a peripheral from the PPM
|
||||||
---@param device table device table
|
---@param device table device table
|
||||||
function ppm.unmount(device)
|
function ppm.unmount(device)
|
||||||
|
@ -89,8 +89,12 @@ function rtu.new_session(id, in_queue, out_queue, advertisement, facility_units)
|
|||||||
|
|
||||||
-- parse the recorded advertisement and create unit sub-sessions
|
-- parse the recorded advertisement and create unit sub-sessions
|
||||||
local function _handle_advertisement()
|
local function _handle_advertisement()
|
||||||
self.units = {}
|
_reset_config()
|
||||||
self.rs_io_q = {}
|
|
||||||
|
for i = 1, #self.f_units do
|
||||||
|
local unit = self.f_units[i] ---@type reactor_unit
|
||||||
|
unit.purge_rtu_devices(self.id)
|
||||||
|
end
|
||||||
|
|
||||||
for i = 1, #self.advert do
|
for i = 1, #self.advert do
|
||||||
local unit = nil ---@type unit_session|nil
|
local unit = nil ---@type unit_session|nil
|
||||||
@ -130,6 +134,7 @@ function rtu.new_session(id, in_queue, out_queue, advertisement, facility_units)
|
|||||||
|
|
||||||
if u_type == false then
|
if u_type == false then
|
||||||
-- validation fail
|
-- validation fail
|
||||||
|
log.debug(log_header .. "advertisement unit validation failure")
|
||||||
else
|
else
|
||||||
local target_unit = self.f_units[unit_advert.reactor] ---@type reactor_unit
|
local target_unit = self.f_units[unit_advert.reactor] ---@type reactor_unit
|
||||||
|
|
||||||
@ -285,8 +290,13 @@ function rtu.new_session(id, in_queue, out_queue, advertisement, facility_units)
|
|||||||
_close()
|
_close()
|
||||||
elseif pkt.type == SCADA_MGMT_TYPES.RTU_ADVERT then
|
elseif pkt.type == SCADA_MGMT_TYPES.RTU_ADVERT then
|
||||||
-- RTU unit advertisement
|
-- RTU unit advertisement
|
||||||
-- handle advertisement; this will re-create all unit sub-sessions
|
log.debug(log_header .. "received updated advertisement")
|
||||||
|
|
||||||
|
-- copy advertisement and remove version tag
|
||||||
self.advert = pkt.data
|
self.advert = pkt.data
|
||||||
|
table.remove(self.advert, 1)
|
||||||
|
|
||||||
|
-- handle advertisement; this will re-create all unit sub-sessions
|
||||||
_handle_advertisement()
|
_handle_advertisement()
|
||||||
elseif pkt.type == SCADA_MGMT_TYPES.RTU_DEV_REMOUNT then
|
elseif pkt.type == SCADA_MGMT_TYPES.RTU_DEV_REMOUNT then
|
||||||
if pkt.length == 1 then
|
if pkt.length == 1 then
|
||||||
|
@ -46,7 +46,7 @@ function boilerv.new(session_id, unit_id, advert, out_queue)
|
|||||||
local log_tag = "session.rtu(" .. session_id .. ").boilerv(" .. advert.index .. "): "
|
local log_tag = "session.rtu(" .. session_id .. ").boilerv(" .. advert.index .. "): "
|
||||||
|
|
||||||
local self = {
|
local self = {
|
||||||
session = unit_session.new(unit_id, advert, out_queue, log_tag, TXN_TAGS),
|
session = unit_session.new(session_id, unit_id, advert, out_queue, log_tag, TXN_TAGS),
|
||||||
has_build = false,
|
has_build = false,
|
||||||
periodics = {
|
periodics = {
|
||||||
next_formed_req = 0,
|
next_formed_req = 0,
|
||||||
|
@ -37,7 +37,7 @@ function envd.new(session_id, unit_id, advert, out_queue)
|
|||||||
local log_tag = "session.rtu(" .. session_id .. ").envd(" .. advert.index .. "): "
|
local log_tag = "session.rtu(" .. session_id .. ").envd(" .. advert.index .. "): "
|
||||||
|
|
||||||
local self = {
|
local self = {
|
||||||
session = unit_session.new(unit_id, advert, out_queue, log_tag, TXN_TAGS),
|
session = unit_session.new(session_id, unit_id, advert, out_queue, log_tag, TXN_TAGS),
|
||||||
periodics = {
|
periodics = {
|
||||||
next_rad_req = 0
|
next_rad_req = 0
|
||||||
},
|
},
|
||||||
|
@ -46,7 +46,7 @@ function imatrix.new(session_id, unit_id, advert, out_queue)
|
|||||||
local log_tag = "session.rtu(" .. session_id .. ").imatrix(" .. advert.index .. "): "
|
local log_tag = "session.rtu(" .. session_id .. ").imatrix(" .. advert.index .. "): "
|
||||||
|
|
||||||
local self = {
|
local self = {
|
||||||
session = unit_session.new(unit_id, advert, out_queue, log_tag, TXN_TAGS),
|
session = unit_session.new(session_id, unit_id, advert, out_queue, log_tag, TXN_TAGS),
|
||||||
has_build = false,
|
has_build = false,
|
||||||
periodics = {
|
periodics = {
|
||||||
next_formed_req = 0,
|
next_formed_req = 0,
|
||||||
|
@ -61,7 +61,7 @@ function redstone.new(session_id, unit_id, advert, out_queue)
|
|||||||
local log_tag = "session.rtu(" .. session_id .. ").redstone(" .. unit_id .. "): "
|
local log_tag = "session.rtu(" .. session_id .. ").redstone(" .. unit_id .. "): "
|
||||||
|
|
||||||
local self = {
|
local self = {
|
||||||
session = unit_session.new(unit_id, advert, out_queue, log_tag, TXN_TAGS),
|
session = unit_session.new(session_id, unit_id, advert, out_queue, log_tag, TXN_TAGS),
|
||||||
in_q = mqueue.new(),
|
in_q = mqueue.new(),
|
||||||
has_di = false,
|
has_di = false,
|
||||||
has_ai = false,
|
has_ai = false,
|
||||||
|
@ -43,7 +43,7 @@ function sna.new(session_id, unit_id, advert, out_queue)
|
|||||||
local log_tag = "session.rtu(" .. session_id .. ").sna(" .. advert.index .. "): "
|
local log_tag = "session.rtu(" .. session_id .. ").sna(" .. advert.index .. "): "
|
||||||
|
|
||||||
local self = {
|
local self = {
|
||||||
session = unit_session.new(unit_id, advert, out_queue, log_tag, TXN_TAGS),
|
session = unit_session.new(session_id, unit_id, advert, out_queue, log_tag, TXN_TAGS),
|
||||||
has_build = false,
|
has_build = false,
|
||||||
periodics = {
|
periodics = {
|
||||||
next_build_req = 0,
|
next_build_req = 0,
|
||||||
|
@ -46,7 +46,7 @@ function sps.new(session_id, unit_id, advert, out_queue)
|
|||||||
local log_tag = "session.rtu(" .. session_id .. ").sps(" .. advert.index .. "): "
|
local log_tag = "session.rtu(" .. session_id .. ").sps(" .. advert.index .. "): "
|
||||||
|
|
||||||
local self = {
|
local self = {
|
||||||
session = unit_session.new(unit_id, advert, out_queue, log_tag, TXN_TAGS),
|
session = unit_session.new(session_id, unit_id, advert, out_queue, log_tag, TXN_TAGS),
|
||||||
has_build = false,
|
has_build = false,
|
||||||
periodics = {
|
periodics = {
|
||||||
next_formed_req = 0,
|
next_formed_req = 0,
|
||||||
|
@ -66,7 +66,7 @@ function turbinev.new(session_id, unit_id, advert, out_queue)
|
|||||||
local log_tag = "session.rtu(" .. session_id .. ").turbinev(" .. advert.index .. "): "
|
local log_tag = "session.rtu(" .. session_id .. ").turbinev(" .. advert.index .. "): "
|
||||||
|
|
||||||
local self = {
|
local self = {
|
||||||
session = unit_session.new(unit_id, advert, out_queue, log_tag, TXN_TAGS),
|
session = unit_session.new(session_id, unit_id, advert, out_queue, log_tag, TXN_TAGS),
|
||||||
in_q = mqueue.new(),
|
in_q = mqueue.new(),
|
||||||
has_build = false,
|
has_build = false,
|
||||||
periodics = {
|
periodics = {
|
||||||
|
@ -22,12 +22,13 @@ unit_session.RTU_US_CMDS = RTU_US_CMDS
|
|||||||
unit_session.RTU_US_DATA = RTU_US_DATA
|
unit_session.RTU_US_DATA = RTU_US_DATA
|
||||||
|
|
||||||
-- create a new unit session runner
|
-- create a new unit session runner
|
||||||
|
---@param session_id integer RTU session ID
|
||||||
---@param unit_id integer MODBUS unit ID
|
---@param unit_id integer MODBUS unit ID
|
||||||
---@param advert rtu_advertisement RTU advertisement for this unit
|
---@param advert rtu_advertisement RTU advertisement for this unit
|
||||||
---@param out_queue mqueue send queue
|
---@param out_queue mqueue send queue
|
||||||
---@param log_tag string logging tag
|
---@param log_tag string logging tag
|
||||||
---@param txn_tags table transaction log tags
|
---@param txn_tags table transaction log tags
|
||||||
function unit_session.new(unit_id, advert, out_queue, log_tag, txn_tags)
|
function unit_session.new(session_id, unit_id, advert, out_queue, log_tag, txn_tags)
|
||||||
local self = {
|
local self = {
|
||||||
log_tag = log_tag,
|
log_tag = log_tag,
|
||||||
txn_tags = txn_tags,
|
txn_tags = txn_tags,
|
||||||
@ -132,6 +133,8 @@ function unit_session.new(unit_id, advert, out_queue, log_tag, txn_tags)
|
|||||||
|
|
||||||
-- PUBLIC FUNCTIONS --
|
-- PUBLIC FUNCTIONS --
|
||||||
|
|
||||||
|
-- get the unit ID
|
||||||
|
function public.get_session_id() return session_id end
|
||||||
-- get the unit ID
|
-- get the unit ID
|
||||||
function public.get_unit_id() return self.unit_id end
|
function public.get_unit_id() return self.unit_id end
|
||||||
-- get the device index
|
-- get the device index
|
||||||
|
@ -401,6 +401,14 @@ function unit.new(for_reactor, num_boilers, num_turbines)
|
|||||||
table.insert(self.redstone[field], accessor)
|
table.insert(self.redstone[field], accessor)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- purge devices associated with the given RTU session ID
|
||||||
|
---@param session integer RTU session ID
|
||||||
|
function public.purge_rtu_devices(session)
|
||||||
|
util.filter_table(self.turbines, function (s) return s.get_session_id() ~= session end)
|
||||||
|
util.filter_table(self.boilers, function (s) return s.get_session_id() ~= session end)
|
||||||
|
util.filter_table(self.redstone, function (s) return s.get_session_id() ~= session end)
|
||||||
|
end
|
||||||
|
|
||||||
-- UPDATE SESSION --
|
-- UPDATE SESSION --
|
||||||
|
|
||||||
-- update (iterate) this unit
|
-- update (iterate) this unit
|
||||||
|
@ -13,7 +13,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.7.3"
|
local SUPERVISOR_VERSION = "beta-v0.7.4"
|
||||||
|
|
||||||
local print = util.print
|
local print = util.print
|
||||||
local println = util.println
|
local println = util.println
|
||||||
|
Loading…
Reference in New Issue
Block a user