#147 possible fix for MODBUS failures on server startup

This commit is contained in:
Mikayla Fischler
2023-04-06 12:52:25 -04:00
parent 40b11dbfd3
commit c2132ea7eb
10 changed files with 92 additions and 23 deletions

View File

@@ -5,9 +5,13 @@ local boilerv_rtu = {}
-- create new boiler (mek 10.1+) device
---@nodiscard
---@param boiler table
---@return rtu_device interface, boolean faulted
function boilerv_rtu.new(boiler)
local unit = rtu.init_unit()
-- disable auto fault clearing
boiler.__p_disable_afc()
-- discrete inputs --
unit.connect_di(boiler.isFormed)
@@ -50,7 +54,12 @@ function boilerv_rtu.new(boiler)
-- holding registers --
-- none
return unit.interface()
-- check if any calls faulted
local faulted = boiler.__p_is_faulted()
boiler.__p_clear_fault()
boiler.__p_enable_afc()
return unit.interface(), faulted
end
return boilerv_rtu

View File

@@ -5,9 +5,13 @@ local envd_rtu = {}
-- create new environment detector device
---@nodiscard
---@param envd table
---@return rtu_device interface, boolean faulted
function envd_rtu.new(envd)
local unit = rtu.init_unit()
-- disable auto fault clearing
envd.__p_disable_afc()
-- discrete inputs --
-- none
@@ -21,7 +25,12 @@ function envd_rtu.new(envd)
-- holding registers --
-- none
return unit.interface()
-- check if any calls faulted
local faulted = envd.__p_is_faulted()
envd.__p_clear_fault()
envd.__p_enable_afc()
return unit.interface(), faulted
end
return envd_rtu

View File

@@ -5,9 +5,13 @@ local imatrix_rtu = {}
-- create new induction matrix (mek 10.1+) device
---@nodiscard
---@param imatrix table
---@return rtu_device interface, boolean faulted
function imatrix_rtu.new(imatrix)
local unit = rtu.init_unit()
-- disable auto fault clearing
imatrix.__p_disable_afc()
-- discrete inputs --
unit.connect_di(imatrix.isFormed)
@@ -37,7 +41,12 @@ function imatrix_rtu.new(imatrix)
-- holding registers --
-- none
return unit.interface()
-- check if any calls faulted
local faulted = imatrix.__p_is_faulted()
imatrix.__p_clear_fault()
imatrix.__p_enable_afc()
return unit.interface(), faulted
end
return imatrix_rtu

View File

@@ -11,6 +11,7 @@ local digital_write = rsio.digital_write
-- create new redstone device
---@nodiscard
---@return rtu_rs_device interface, boolean faulted
function redstone_rtu.new()
local unit = rtu.init_unit()
@@ -111,7 +112,7 @@ function redstone_rtu.new()
)
end
return public
return public, false
end
return redstone_rtu

View File

@@ -5,9 +5,13 @@ local sna_rtu = {}
-- create new solar neutron activator (SNA) device
---@nodiscard
---@param sna table
---@return rtu_device interface, boolean faulted
function sna_rtu.new(sna)
local unit = rtu.init_unit()
-- disable auto fault clearing
sna.__p_disable_afc()
-- discrete inputs --
-- none
@@ -32,7 +36,12 @@ function sna_rtu.new(sna)
-- holding registers --
-- none
return unit.interface()
-- check if any calls faulted
local faulted = sna.__p_is_faulted()
sna.__p_clear_fault()
sna.__p_enable_afc()
return unit.interface(), faulted
end
return sna_rtu

View File

@@ -5,9 +5,13 @@ local sps_rtu = {}
-- create new super-critical phase shifter (SPS) device
---@nodiscard
---@param sps table
---@return rtu_device interface, boolean faulted
function sps_rtu.new(sps)
local unit = rtu.init_unit()
-- disable auto fault clearing
sps.__p_disable_afc()
-- discrete inputs --
unit.connect_di(sps.isFormed)
@@ -42,7 +46,12 @@ function sps_rtu.new(sps)
-- holding registers --
-- none
return unit.interface()
-- check if any calls faulted
local faulted = sps.__p_is_faulted()
sps.__p_clear_fault()
sps.__p_enable_afc()
return unit.interface(), faulted
end
return sps_rtu

View File

@@ -5,9 +5,13 @@ local turbinev_rtu = {}
-- create new turbine (mek 10.1+) device
---@nodiscard
---@param turbine table
---@return rtu_device interface, boolean faulted
function turbinev_rtu.new(turbine)
local unit = rtu.init_unit()
-- disable auto fault clearing
turbine.__p_disable_afc()
-- discrete inputs --
unit.connect_di(turbine.isFormed)
@@ -49,7 +53,12 @@ function turbinev_rtu.new(turbine)
-- holding registers --
unit.connect_holding_reg(turbine.getDumpingMode, turbine.setDumpingMode)
return unit.interface()
-- check if any calls faulted
local faulted = turbine.__p_is_faulted()
turbine.__p_clear_fault()
turbine.__p_enable_afc()
return unit.interface(), faulted
end
return turbinev_rtu

View File

@@ -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 = "v0.13.0"
local RTU_VERSION = "v0.13.1"
local RTU_UNIT_TYPE = types.RTU_UNIT_TYPE
@@ -290,8 +290,9 @@ local function main()
local type = nil ---@type string|nil
local rtu_iface = nil ---@type rtu_device
local rtu_type = nil ---@type RTU_UNIT_TYPE
local is_multiblock = false
local is_multiblock = false ---@type boolean
local formed = nil ---@type boolean|nil
local faulted = nil ---@type boolean|nil
if device == nil then
local message = util.c("configure> '", name, "' not found, using placeholder")
@@ -307,7 +308,7 @@ local function main()
if type == "boilerValve" then
-- boiler multiblock
rtu_type = RTU_UNIT_TYPE.BOILER_VALVE
rtu_iface = boilerv_rtu.new(device)
rtu_iface, faulted = boilerv_rtu.new(device)
is_multiblock = true
formed = device.isFormed()
@@ -319,7 +320,7 @@ local function main()
elseif type == "turbineValve" then
-- turbine multiblock
rtu_type = RTU_UNIT_TYPE.TURBINE_VALVE
rtu_iface = turbinev_rtu.new(device)
rtu_iface, faulted = turbinev_rtu.new(device)
is_multiblock = true
formed = device.isFormed()
@@ -331,7 +332,7 @@ local function main()
elseif type == "inductionPort" then
-- induction matrix multiblock
rtu_type = RTU_UNIT_TYPE.IMATRIX
rtu_iface = imatrix_rtu.new(device)
rtu_iface, faulted = imatrix_rtu.new(device)
is_multiblock = true
formed = device.isFormed()
@@ -343,7 +344,7 @@ local function main()
elseif type == "spsPort" then
-- SPS multiblock
rtu_type = RTU_UNIT_TYPE.SPS
rtu_iface = sps_rtu.new(device)
rtu_iface, faulted = sps_rtu.new(device)
is_multiblock = true
formed = device.isFormed()
@@ -355,11 +356,11 @@ local function main()
elseif type == "solarNeutronActivator" then
-- SNA
rtu_type = RTU_UNIT_TYPE.SNA
rtu_iface = sna_rtu.new(device)
rtu_iface, _ = sna_rtu.new(device)
elseif type == "environmentDetector" then
-- advanced peripherals environment detector
rtu_type = RTU_UNIT_TYPE.ENV_DETECTOR
rtu_iface = envd_rtu.new(device)
rtu_iface, _ = envd_rtu.new(device)
elseif type == ppm.VIRTUAL_DEVICE_TYPE then
-- placeholder device
rtu_type = RTU_UNIT_TYPE.VIRTUAL
@@ -391,8 +392,15 @@ local function main()
table.insert(units, rtu_unit)
if is_multiblock and not formed then
log.info(util.c("configure> device '", name, "' is not formed"))
if is_multiblock then
if not formed then
log.info(util.c("configure> device '", name, "' is not formed"))
elseif faulted then
-- sometimes there is a race condition on server boot where it reports formed, but
-- the other functions are not yet defined (that's the theory at least). mark as unformed to attempt connection later
formed = false
log.warning(util.c("configure> device '", name, "' is formed, but initialization had one or more faults: marked as unformed"))
end
end
local for_message = "facility"

View File

@@ -375,37 +375,43 @@ function threads.thread__unit_comms(smem, unit)
ppm.unmount(unit.device)
local type, device = ppm.mount(iface)
local faulted = false
if device ~= nil then
if type == "boilerValve" and unit.type == RTU_UNIT_TYPE.BOILER_VALVE then
-- boiler multiblock
unit.device = device
unit.rtu = boilerv_rtu.new(device)
unit.rtu, faulted = boilerv_rtu.new(device)
unit.formed = device.isFormed()
unit.modbus_io = modbus.new(unit.rtu, true)
elseif type == "turbineValve" and unit.type == RTU_UNIT_TYPE.TURBINE_VALVE then
-- turbine multiblock
unit.device = device
unit.rtu = turbinev_rtu.new(device)
unit.rtu, faulted = turbinev_rtu.new(device)
unit.formed = device.isFormed()
unit.modbus_io = modbus.new(unit.rtu, true)
elseif type == "inductionPort" and unit.type == RTU_UNIT_TYPE.IMATRIX then
-- induction matrix multiblock
unit.device = device
unit.rtu = imatrix_rtu.new(device)
unit.rtu, faulted = imatrix_rtu.new(device)
unit.formed = device.isFormed()
unit.modbus_io = modbus.new(unit.rtu, true)
elseif type == "spsPort" and unit.type == RTU_UNIT_TYPE.SPS then
-- SPS multiblock
unit.device = device
unit.rtu = sps_rtu.new(device)
unit.rtu, faulted = sps_rtu.new(device)
unit.formed = device.isFormed()
unit.modbus_io = modbus.new(unit.rtu, true)
else
log.error("illegal remount of non-multiblock RTU attempted for " .. short_name, true)
end
rtu_comms.send_remounted(unit.uid)
if unit.formed and faulted then
-- something is still wrong = can't mark as formed yet
unit.formed = false
else
rtu_comms.send_remounted(unit.uid)
end
else
-- fully lost the peripheral now :(
log.error(util.c(unit.name, " lost (failed reconnect)"))