#445 fixed PPM undefined field logic and improved RTU unit fault handling

This commit is contained in:
Mikayla Fischler 2024-03-09 13:24:06 -05:00
parent d1e4ea586e
commit 79c93f1562
11 changed files with 49 additions and 67 deletions

View File

@ -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()

View File

@ -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()

View File

@ -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()

View File

@ -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()

View File

@ -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()

View File

@ -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()

View File

@ -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()

View File

@ -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

View File

@ -67,9 +67,11 @@ function rtu.load_config()
return cfv.valid()
end
-- create a new RTU unit
-- create a new RTU unit<br>
-- 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

View File

@ -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

View File

@ -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
}