diff --git a/rtu/dev/boilerv_rtu.lua b/rtu/dev/boilerv_rtu.lua index 0197421..cb4f701 100644 --- a/rtu/dev/boilerv_rtu.lua +++ b/rtu/dev/boilerv_rtu.lua @@ -7,7 +7,7 @@ local boilerv_rtu = {} ---@param boiler table ---@return rtu_device interface, boolean faulted function boilerv_rtu.new(boiler) - local unit = rtu.init_unit() + local unit = rtu.init_unit(boiler) -- disable auto fault clearing boiler.__p_clear_fault() diff --git a/rtu/dev/dynamicv_rtu.lua b/rtu/dev/dynamicv_rtu.lua index 75540a3..987e366 100644 --- a/rtu/dev/dynamicv_rtu.lua +++ b/rtu/dev/dynamicv_rtu.lua @@ -7,7 +7,7 @@ local dynamicv_rtu = {} ---@param dynamic_tank table ---@return rtu_device interface, boolean faulted function dynamicv_rtu.new(dynamic_tank) - local unit = rtu.init_unit() + local unit = rtu.init_unit(dynamic_tank) -- disable auto fault clearing dynamic_tank.__p_clear_fault() diff --git a/rtu/dev/envd_rtu.lua b/rtu/dev/envd_rtu.lua index 2d576bc..f6dfa09 100644 --- a/rtu/dev/envd_rtu.lua +++ b/rtu/dev/envd_rtu.lua @@ -7,7 +7,7 @@ local envd_rtu = {} ---@param envd table ---@return rtu_device interface, boolean faulted function envd_rtu.new(envd) - local unit = rtu.init_unit() + local unit = rtu.init_unit(envd) -- disable auto fault clearing envd.__p_clear_fault() diff --git a/rtu/dev/imatrix_rtu.lua b/rtu/dev/imatrix_rtu.lua index a20d1a5..f3b7f5c 100644 --- a/rtu/dev/imatrix_rtu.lua +++ b/rtu/dev/imatrix_rtu.lua @@ -7,7 +7,7 @@ local imatrix_rtu = {} ---@param imatrix table ---@return rtu_device interface, boolean faulted function imatrix_rtu.new(imatrix) - local unit = rtu.init_unit() + local unit = rtu.init_unit(imatrix) -- disable auto fault clearing imatrix.__p_clear_fault() diff --git a/rtu/dev/sna_rtu.lua b/rtu/dev/sna_rtu.lua index a3e678e..209ebb2 100644 --- a/rtu/dev/sna_rtu.lua +++ b/rtu/dev/sna_rtu.lua @@ -7,7 +7,7 @@ local sna_rtu = {} ---@param sna table ---@return rtu_device interface, boolean faulted function sna_rtu.new(sna) - local unit = rtu.init_unit() + local unit = rtu.init_unit(sna) -- disable auto fault clearing sna.__p_clear_fault() diff --git a/rtu/dev/sps_rtu.lua b/rtu/dev/sps_rtu.lua index 428f7bb..448dc48 100644 --- a/rtu/dev/sps_rtu.lua +++ b/rtu/dev/sps_rtu.lua @@ -7,7 +7,7 @@ local sps_rtu = {} ---@param sps table ---@return rtu_device interface, boolean faulted function sps_rtu.new(sps) - local unit = rtu.init_unit() + local unit = rtu.init_unit(sps) -- disable auto fault clearing sps.__p_clear_fault() diff --git a/rtu/dev/turbinev_rtu.lua b/rtu/dev/turbinev_rtu.lua index 17e6675..4bfad81 100644 --- a/rtu/dev/turbinev_rtu.lua +++ b/rtu/dev/turbinev_rtu.lua @@ -7,7 +7,7 @@ local turbinev_rtu = {} ---@param turbine table ---@return rtu_device interface, boolean faulted function turbinev_rtu.new(turbine) - local unit = rtu.init_unit() + local unit = rtu.init_unit(turbine) -- disable auto fault clearing turbine.__p_clear_fault() diff --git a/rtu/modbus.lua b/rtu/modbus.lua index 44900a0..d55907f 100644 --- a/rtu/modbus.lua +++ b/rtu/modbus.lua @@ -37,12 +37,7 @@ function modbus.new(rtu_dev, use_parallel_read) end) else readings[i], access_fault = rtu_dev.read_coil(addr) - - if access_fault then - return_ok = false - readings = MODBUS_EXCODE.SERVER_DEVICE_FAIL - break - end + if access_fault then break end end end @@ -86,12 +81,7 @@ function modbus.new(rtu_dev, use_parallel_read) end) else readings[i], access_fault = rtu_dev.read_di(addr) - - if access_fault then - return_ok = false - readings = MODBUS_EXCODE.SERVER_DEVICE_FAIL - break - end + if access_fault then break end end end @@ -135,12 +125,7 @@ function modbus.new(rtu_dev, use_parallel_read) end) else readings[i], access_fault = rtu_dev.read_holding_reg(addr) - - if access_fault then - return_ok = false - readings = MODBUS_EXCODE.SERVER_DEVICE_FAIL - break - end + if access_fault then break end end end @@ -184,12 +169,7 @@ function modbus.new(rtu_dev, use_parallel_read) end) else readings[i], access_fault = rtu_dev.read_input_reg(addr) - - if access_fault then - return_ok = false - readings = MODBUS_EXCODE.SERVER_DEVICE_FAIL - break - end + if access_fault then break end end end diff --git a/rtu/rtu.lua b/rtu/rtu.lua index 6c2b01f..bac230f 100644 --- a/rtu/rtu.lua +++ b/rtu/rtu.lua @@ -67,9 +67,11 @@ function rtu.load_config() return cfv.valid() end --- create a new RTU unit +-- create a new RTU unit
+-- if this is for a PPM peripheral, auto fault clearing MUST stay enabled once access begins ---@nodiscard -function rtu.init_unit() +---@param device table|nil peripheral device, if applicable +function rtu.init_unit(device) local self = { discrete_inputs = {}, coils = {}, @@ -86,6 +88,10 @@ function rtu.init_unit() ---@class rtu local protected = {} + -- function to check if the peripheral (if exists) is faulted + local function _is_faulted() return false end + if device then _is_faulted = device.__p_is_faulted end + -- refresh IO count local function _count_io() self.io_count_cache = { #self.discrete_inputs, #self.coils, #self.input_regs, #self.holding_regs } @@ -112,9 +118,8 @@ function rtu.init_unit() ---@param di_addr integer ---@return any value, boolean access_fault function public.read_di(di_addr) - ppm.clear_fault() local value = self.discrete_inputs[di_addr].read() - return value, ppm.is_faulted() + return value, _is_faulted() end -- coils: single bit read-write @@ -133,9 +138,8 @@ function rtu.init_unit() ---@param coil_addr integer ---@return any value, boolean access_fault function public.read_coil(coil_addr) - ppm.clear_fault() local value = self.coils[coil_addr].read() - return value, ppm.is_faulted() + return value, _is_faulted() end -- write coil @@ -143,9 +147,8 @@ function rtu.init_unit() ---@param value any ---@return boolean access_fault function public.write_coil(coil_addr, value) - ppm.clear_fault() self.coils[coil_addr].write(value) - return ppm.is_faulted() + return _is_faulted() end -- input registers: multi-bit read-only @@ -163,9 +166,8 @@ function rtu.init_unit() ---@param reg_addr integer ---@return any value, boolean access_fault function public.read_input_reg(reg_addr) - ppm.clear_fault() local value = self.input_regs[reg_addr].read() - return value, ppm.is_faulted() + return value, _is_faulted() end -- holding registers: multi-bit read-write @@ -184,9 +186,8 @@ function rtu.init_unit() ---@param reg_addr integer ---@return any value, boolean access_fault function public.read_holding_reg(reg_addr) - ppm.clear_fault() local value = self.holding_regs[reg_addr].read() - return value, ppm.is_faulted() + return value, _is_faulted() end -- write holding register @@ -194,9 +195,8 @@ function rtu.init_unit() ---@param value any ---@return boolean access_fault function public.write_holding_reg(reg_addr, value) - ppm.clear_fault() self.holding_regs[reg_addr].write(value) - return ppm.is_faulted() + return _is_faulted() end -- public RTU device access diff --git a/rtu/startup.lua b/rtu/startup.lua index 1c5a4a2..90b81a0 100644 --- a/rtu/startup.lua +++ b/rtu/startup.lua @@ -31,7 +31,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 = "v1.7.14" +local RTU_VERSION = "v1.7.15" local RTU_UNIT_TYPE = types.RTU_UNIT_TYPE local RTU_UNIT_HW_STATE = databus.RTU_UNIT_HW_STATE diff --git a/scada-common/ppm.lua b/scada-common/ppm.lua index fb98161..0d02663 100644 --- a/scada-common/ppm.lua +++ b/scada-common/ppm.lua @@ -131,31 +131,33 @@ local function peri_init(iface) local mt = { __index = function (_, key) - -- this will continuously be counting calls here as faults - -- unlike other functions, faults here can't be cleared as it is just not defined - if self.fault_counts[key] == nil then - self.fault_counts[key] = 0 - end - - -- function failed - self.faulted = true - self.last_fault = UNDEFINED_FIELD - - ppm_sys.faulted = true - ppm_sys.last_fault = UNDEFINED_FIELD - - if not ppm_sys.mute and (self.fault_counts[key] % REPORT_FREQUENCY == 0) then - local count_str = "" - if self.fault_counts[key] > 0 then - count_str = " [" .. self.fault_counts[key] .. " total calls]" + return (function () + -- this will continuously be counting calls here as faults + -- unlike other functions, faults here can't be cleared as it is just not defined + if self.fault_counts[key] == nil then + self.fault_counts[key] = 0 end - log.error(util.c("PPM: caught undefined function ", key, "()", count_str)) - end + -- function failed + self.faulted = true + self.last_fault = UNDEFINED_FIELD - self.fault_counts[key] = self.fault_counts[key] + 1 + ppm_sys.faulted = true + ppm_sys.last_fault = UNDEFINED_FIELD - return (function () return UNDEFINED_FIELD end) + if not ppm_sys.mute and (self.fault_counts[key] % REPORT_FREQUENCY == 0) then + local count_str = "" + if self.fault_counts[key] > 0 then + count_str = " [" .. self.fault_counts[key] .. " total calls]" + end + + log.error(util.c("PPM: caught undefined function ", key, "()", count_str)) + end + + self.fault_counts[key] = self.fault_counts[key] + 1 + + return UNDEFINED_FIELD + end) end }