From 4d40d08a7a96f17e2a333dccc62e70c9a886f980 Mon Sep 17 00:00:00 2001 From: Mikayla Fischler Date: Sun, 12 Feb 2023 13:06:44 -0500 Subject: [PATCH] #157 fixed bug with RTU remount messages --- rtu/startup.lua | 25 +++++++++++++++++++------ rtu/threads.lua | 28 ++++++++++++++++++++-------- supervisor/session/rtu.lua | 2 +- supervisor/session/rtu/boilerv.lua | 2 ++ supervisor/session/rtu/imatrix.lua | 2 ++ supervisor/session/rtu/sps.lua | 2 ++ supervisor/session/rtu/turbinev.lua | 2 ++ supervisor/startup.lua | 2 +- 8 files changed, 49 insertions(+), 16 deletions(-) diff --git a/rtu/startup.lua b/rtu/startup.lua index 19c201b..22f6f2d 100644 --- a/rtu/startup.lua +++ b/rtu/startup.lua @@ -25,7 +25,7 @@ local sna_rtu = require("rtu.dev.sna_rtu") local sps_rtu = require("rtu.dev.sps_rtu") local turbinev_rtu = require("rtu.dev.turbinev_rtu") -local RTU_VERSION = "beta-v0.10.2" +local RTU_VERSION = "beta-v0.10.3" local rtu_t = types.rtu_t @@ -222,11 +222,13 @@ local function main() ---@class rtu_unit_registry_entry local unit = { + uid = 0, name = "redstone_io", type = rtu_t.redstone, index = entry_idx, reactor = io_reactor, device = capabilities, -- use device field for redstone ports + is_multiblock = false, formed = nil, ---@type boolean|nil rtu = rs_rtu, ---@type rtu_device|rtu_rs_device modbus_io = modbus.new(rs_rtu, false), @@ -237,6 +239,8 @@ local function main() table.insert(units, unit) log.debug(util.c("init> initialized RTU unit #", #units, ": redstone_io (redstone) [1] for reactor ", io_reactor)) + + unit.uid = #units end end @@ -267,9 +271,10 @@ local function main() local device = ppm.get_periph(name) local type = nil - local rtu_iface = nil ---@type rtu_device + local rtu_iface = nil ---@type rtu_device local rtu_type = "" - local formed = nil ---@type boolean|nil + local is_multiblock = false + local formed = nil ---@type boolean|nil if device == nil then local message = util.c("configure> '", name, "' not found, using placeholder") @@ -286,6 +291,7 @@ local function main() -- boiler multiblock rtu_type = rtu_t.boiler_valve rtu_iface = boilerv_rtu.new(device) + is_multiblock = true formed = device.isFormed() if formed == ppm.UNDEFINED_FIELD or formed == ppm.ACCESS_FAULT then @@ -297,6 +303,7 @@ local function main() -- turbine multiblock rtu_type = rtu_t.turbine_valve rtu_iface = turbinev_rtu.new(device) + is_multiblock = true formed = device.isFormed() if formed == ppm.UNDEFINED_FIELD or formed == ppm.ACCESS_FAULT then @@ -308,6 +315,7 @@ local function main() -- induction matrix multiblock rtu_type = rtu_t.induction_matrix rtu_iface = imatrix_rtu.new(device) + is_multiblock = true formed = device.isFormed() if formed == ppm.UNDEFINED_FIELD or formed == ppm.ACCESS_FAULT then @@ -319,6 +327,7 @@ local function main() -- SPS multiblock rtu_type = rtu_t.sps rtu_iface = sps_rtu.new(device) + is_multiblock = true formed = device.isFormed() if formed == ppm.UNDEFINED_FIELD or formed == ppm.ACCESS_FAULT then @@ -347,15 +356,17 @@ local function main() ---@class rtu_unit_registry_entry local rtu_unit = { + uid = 0, name = name, type = rtu_type, index = index, reactor = for_reactor, device = device, - formed = formed, - rtu = rtu_iface, ---@type rtu_device|rtu_rs_device + is_multiblock = is_multiblock, + formed = formed, ---@type boolean|nil + rtu = rtu_iface, ---@type rtu_device|rtu_rs_device modbus_io = modbus.new(rtu_iface, true), - pkt_queue = mqueue.new(), ---@type mqueue|nil + pkt_queue = mqueue.new(), ---@type mqueue|nil thread = nil } @@ -373,6 +384,8 @@ local function main() end log.debug(util.c("configure> initialized RTU unit #", #units, ": ", name, " (", rtu_type, ") [", index, "] for ", for_message)) + + rtu_unit.uid = #units end -- we made it through all that trusting-user-to-write-a-config-file chaos diff --git a/rtu/threads.lua b/rtu/threads.lua index 8027f34..7af184e 100644 --- a/rtu/threads.lua +++ b/rtu/threads.lua @@ -157,16 +157,20 @@ function threads.thread__main(smem) if unit.type == rtu_t.boiler_valve then unit.rtu = boilerv_rtu.new(device) - unit.formed = true + -- if not formed, indexing the multiblock functions would have resulted in a PPM fault + unit.formed = util.trinary(device.__p_is_faulted(), false, nil) elseif unit.type == rtu_t.turbine_valve then unit.rtu = turbinev_rtu.new(device) - unit.formed = true + -- if not formed, indexing the multiblock functions would have resulted in a PPM fault + unit.formed = util.trinary(device.__p_is_faulted(), false, nil) elseif unit.type == rtu_t.induction_matrix then unit.rtu = imatrix_rtu.new(device) - unit.formed = true + -- if not formed, indexing the multiblock functions would have resulted in a PPM fault + unit.formed = util.trinary(device.__p_is_faulted(), false, nil) elseif unit.type == rtu_t.sps then unit.rtu = sps_rtu.new(device) - unit.formed = true + -- if not formed, indexing the multiblock functions would have resulted in a PPM fault + unit.formed = util.trinary(device.__p_is_faulted(), false, nil) elseif unit.type == rtu_t.sna then unit.rtu = sna_rtu.new(device) elseif unit.type == rtu_t.env_detector then @@ -175,6 +179,10 @@ function threads.thread__main(smem) log.error(util.c("failed to identify reconnected RTU unit type (", unit.name, ")"), true) end + if unit.is_multiblock and (unit.formed == false) then + log.info(util.c("assuming ", unit.name, " is not formed due to PPM faults while initializing")) + end + unit.modbus_io = modbus.new(unit.rtu, true) println_ts("reconnected the " .. unit.type .. " on interface " .. unit.name) @@ -183,7 +191,7 @@ function threads.thread__main(smem) if resend_advert then rtu_comms.send_advertisement(units) else - rtu_comms.send_remounted(unit.index) + rtu_comms.send_remounted(unit.uid) end end end @@ -342,9 +350,13 @@ function threads.thread__unit_comms(smem, unit) end -- check if multiblock is still formed if this is a multiblock - if (type(unit.formed) == "boolean") and (util.time() - last_f_check > 1000) then + if unit.is_multiblock and (util.time_ms() - last_f_check > 250) then local is_formed = unit.device.isFormed() + last_f_check = util.time_ms() + + if unit.formed == nil then unit.formed = is_formed end + if (not unit.formed) and is_formed then -- newly re-formed local iface = ppm.get_iface(unit.device) @@ -384,13 +396,13 @@ function threads.thread__unit_comms(smem, unit) log.error("illegal remount of non-multiblock RTU attempted for " .. short_name, true) end - rtu_comms.send_remounted(unit.index) + rtu_comms.send_remounted(unit.uid) else -- fully lost the peripheral now :( log.error(util.c(unit.name, " lost (failed reconnect)")) end - log.info("reconnected the " .. unit.type .. " on interface " .. unit.name) + log.info(util.c("reconnected the ", unit.type, " on interface ", unit.name)) else log.error("failed to get interface of previously connected RTU unit " .. detail_name, true) end diff --git a/supervisor/session/rtu.lua b/supervisor/session/rtu.lua index 01a32c3..607f4f6 100644 --- a/supervisor/session/rtu.lua +++ b/supervisor/session/rtu.lua @@ -265,7 +265,7 @@ function rtu.new_session(id, in_queue, out_queue, advertisement, facility) _handle_advertisement() elseif pkt.type == SCADA_MGMT_TYPES.RTU_DEV_REMOUNT then if pkt.length == 1 then - local unit_id = pkt[1] + local unit_id = pkt.data[1] if self.units[unit_id] ~= nil then local unit = self.units[unit_id] ---@type unit_session unit.invalidate_cache() diff --git a/supervisor/session/rtu/boilerv.lua b/supervisor/session/rtu/boilerv.lua index d35517d..fe61372 100644 --- a/supervisor/session/rtu/boilerv.lua +++ b/supervisor/session/rtu/boilerv.lua @@ -137,6 +137,8 @@ function boilerv.new(session_id, unit_id, advert, out_queue) -- load in data if correct length if m_pkt.length == 1 then self.db.formed = m_pkt.data[1] + + if not self.db.formed then self.has_build = false end else log.debug(log_tag .. "MODBUS transaction reply length mismatch (" .. TXN_TAGS[txn_type] .. ")") end diff --git a/supervisor/session/rtu/imatrix.lua b/supervisor/session/rtu/imatrix.lua index ab5704c..00e14f7 100644 --- a/supervisor/session/rtu/imatrix.lua +++ b/supervisor/session/rtu/imatrix.lua @@ -124,6 +124,8 @@ function imatrix.new(session_id, unit_id, advert, out_queue) -- load in data if correct length if m_pkt.length == 1 then self.db.formed = m_pkt.data[1] + + if not self.db.formed then self.has_build = false end else log.debug(log_tag .. "MODBUS transaction reply length mismatch (" .. TXN_TAGS[txn_type] .. ")") end diff --git a/supervisor/session/rtu/sps.lua b/supervisor/session/rtu/sps.lua index f389049..4cd7fb1 100644 --- a/supervisor/session/rtu/sps.lua +++ b/supervisor/session/rtu/sps.lua @@ -129,6 +129,8 @@ function sps.new(session_id, unit_id, advert, out_queue) -- load in data if correct length if m_pkt.length == 1 then self.db.formed = m_pkt.data[1] + + if not self.db.formed then self.has_build = false end else log.debug(log_tag .. "MODBUS transaction reply length mismatch (" .. TXN_TAGS[txn_type] .. ")") end diff --git a/supervisor/session/rtu/turbinev.lua b/supervisor/session/rtu/turbinev.lua index d1bba6b..5662b70 100644 --- a/supervisor/session/rtu/turbinev.lua +++ b/supervisor/session/rtu/turbinev.lua @@ -166,6 +166,8 @@ function turbinev.new(session_id, unit_id, advert, out_queue) -- load in data if correct length if m_pkt.length == 1 then self.db.formed = m_pkt.data[1] + + if not self.db.formed then self.has_build = false end else log.debug(log_tag .. "MODBUS transaction reply length mismatch (" .. TXN_TAGS[txn_type] .. ")") end diff --git a/supervisor/startup.lua b/supervisor/startup.lua index 348151b..2ae0df3 100644 --- a/supervisor/startup.lua +++ b/supervisor/startup.lua @@ -14,7 +14,7 @@ local svsessions = require("supervisor.session.svsessions") local config = require("supervisor.config") local supervisor = require("supervisor.supervisor") -local SUPERVISOR_VERSION = "beta-v0.11.0" +local SUPERVISOR_VERSION = "beta-v0.11.1" local print = util.print local println = util.println