mirror of
https://github.com/MikaylaFischler/cc-mek-scada.git
synced 2024-08-30 18:22:34 +00:00
#445 fixed PPM undefined field logic and improved RTU unit fault handling
This commit is contained in:
parent
d1e4ea586e
commit
79c93f1562
@ -7,7 +7,7 @@ local boilerv_rtu = {}
|
|||||||
---@param boiler table
|
---@param boiler table
|
||||||
---@return rtu_device interface, boolean faulted
|
---@return rtu_device interface, boolean faulted
|
||||||
function boilerv_rtu.new(boiler)
|
function boilerv_rtu.new(boiler)
|
||||||
local unit = rtu.init_unit()
|
local unit = rtu.init_unit(boiler)
|
||||||
|
|
||||||
-- disable auto fault clearing
|
-- disable auto fault clearing
|
||||||
boiler.__p_clear_fault()
|
boiler.__p_clear_fault()
|
||||||
|
@ -7,7 +7,7 @@ local dynamicv_rtu = {}
|
|||||||
---@param dynamic_tank table
|
---@param dynamic_tank table
|
||||||
---@return rtu_device interface, boolean faulted
|
---@return rtu_device interface, boolean faulted
|
||||||
function dynamicv_rtu.new(dynamic_tank)
|
function dynamicv_rtu.new(dynamic_tank)
|
||||||
local unit = rtu.init_unit()
|
local unit = rtu.init_unit(dynamic_tank)
|
||||||
|
|
||||||
-- disable auto fault clearing
|
-- disable auto fault clearing
|
||||||
dynamic_tank.__p_clear_fault()
|
dynamic_tank.__p_clear_fault()
|
||||||
|
@ -7,7 +7,7 @@ local envd_rtu = {}
|
|||||||
---@param envd table
|
---@param envd table
|
||||||
---@return rtu_device interface, boolean faulted
|
---@return rtu_device interface, boolean faulted
|
||||||
function envd_rtu.new(envd)
|
function envd_rtu.new(envd)
|
||||||
local unit = rtu.init_unit()
|
local unit = rtu.init_unit(envd)
|
||||||
|
|
||||||
-- disable auto fault clearing
|
-- disable auto fault clearing
|
||||||
envd.__p_clear_fault()
|
envd.__p_clear_fault()
|
||||||
|
@ -7,7 +7,7 @@ local imatrix_rtu = {}
|
|||||||
---@param imatrix table
|
---@param imatrix table
|
||||||
---@return rtu_device interface, boolean faulted
|
---@return rtu_device interface, boolean faulted
|
||||||
function imatrix_rtu.new(imatrix)
|
function imatrix_rtu.new(imatrix)
|
||||||
local unit = rtu.init_unit()
|
local unit = rtu.init_unit(imatrix)
|
||||||
|
|
||||||
-- disable auto fault clearing
|
-- disable auto fault clearing
|
||||||
imatrix.__p_clear_fault()
|
imatrix.__p_clear_fault()
|
||||||
|
@ -7,7 +7,7 @@ local sna_rtu = {}
|
|||||||
---@param sna table
|
---@param sna table
|
||||||
---@return rtu_device interface, boolean faulted
|
---@return rtu_device interface, boolean faulted
|
||||||
function sna_rtu.new(sna)
|
function sna_rtu.new(sna)
|
||||||
local unit = rtu.init_unit()
|
local unit = rtu.init_unit(sna)
|
||||||
|
|
||||||
-- disable auto fault clearing
|
-- disable auto fault clearing
|
||||||
sna.__p_clear_fault()
|
sna.__p_clear_fault()
|
||||||
|
@ -7,7 +7,7 @@ local sps_rtu = {}
|
|||||||
---@param sps table
|
---@param sps table
|
||||||
---@return rtu_device interface, boolean faulted
|
---@return rtu_device interface, boolean faulted
|
||||||
function sps_rtu.new(sps)
|
function sps_rtu.new(sps)
|
||||||
local unit = rtu.init_unit()
|
local unit = rtu.init_unit(sps)
|
||||||
|
|
||||||
-- disable auto fault clearing
|
-- disable auto fault clearing
|
||||||
sps.__p_clear_fault()
|
sps.__p_clear_fault()
|
||||||
|
@ -7,7 +7,7 @@ local turbinev_rtu = {}
|
|||||||
---@param turbine table
|
---@param turbine table
|
||||||
---@return rtu_device interface, boolean faulted
|
---@return rtu_device interface, boolean faulted
|
||||||
function turbinev_rtu.new(turbine)
|
function turbinev_rtu.new(turbine)
|
||||||
local unit = rtu.init_unit()
|
local unit = rtu.init_unit(turbine)
|
||||||
|
|
||||||
-- disable auto fault clearing
|
-- disable auto fault clearing
|
||||||
turbine.__p_clear_fault()
|
turbine.__p_clear_fault()
|
||||||
|
@ -37,12 +37,7 @@ function modbus.new(rtu_dev, use_parallel_read)
|
|||||||
end)
|
end)
|
||||||
else
|
else
|
||||||
readings[i], access_fault = rtu_dev.read_coil(addr)
|
readings[i], access_fault = rtu_dev.read_coil(addr)
|
||||||
|
if access_fault then break end
|
||||||
if access_fault then
|
|
||||||
return_ok = false
|
|
||||||
readings = MODBUS_EXCODE.SERVER_DEVICE_FAIL
|
|
||||||
break
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -86,12 +81,7 @@ function modbus.new(rtu_dev, use_parallel_read)
|
|||||||
end)
|
end)
|
||||||
else
|
else
|
||||||
readings[i], access_fault = rtu_dev.read_di(addr)
|
readings[i], access_fault = rtu_dev.read_di(addr)
|
||||||
|
if access_fault then break end
|
||||||
if access_fault then
|
|
||||||
return_ok = false
|
|
||||||
readings = MODBUS_EXCODE.SERVER_DEVICE_FAIL
|
|
||||||
break
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -135,12 +125,7 @@ function modbus.new(rtu_dev, use_parallel_read)
|
|||||||
end)
|
end)
|
||||||
else
|
else
|
||||||
readings[i], access_fault = rtu_dev.read_holding_reg(addr)
|
readings[i], access_fault = rtu_dev.read_holding_reg(addr)
|
||||||
|
if access_fault then break end
|
||||||
if access_fault then
|
|
||||||
return_ok = false
|
|
||||||
readings = MODBUS_EXCODE.SERVER_DEVICE_FAIL
|
|
||||||
break
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -184,12 +169,7 @@ function modbus.new(rtu_dev, use_parallel_read)
|
|||||||
end)
|
end)
|
||||||
else
|
else
|
||||||
readings[i], access_fault = rtu_dev.read_input_reg(addr)
|
readings[i], access_fault = rtu_dev.read_input_reg(addr)
|
||||||
|
if access_fault then break end
|
||||||
if access_fault then
|
|
||||||
return_ok = false
|
|
||||||
readings = MODBUS_EXCODE.SERVER_DEVICE_FAIL
|
|
||||||
break
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
28
rtu/rtu.lua
28
rtu/rtu.lua
@ -67,9 +67,11 @@ function rtu.load_config()
|
|||||||
return cfv.valid()
|
return cfv.valid()
|
||||||
end
|
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
|
---@nodiscard
|
||||||
function rtu.init_unit()
|
---@param device table|nil peripheral device, if applicable
|
||||||
|
function rtu.init_unit(device)
|
||||||
local self = {
|
local self = {
|
||||||
discrete_inputs = {},
|
discrete_inputs = {},
|
||||||
coils = {},
|
coils = {},
|
||||||
@ -86,6 +88,10 @@ function rtu.init_unit()
|
|||||||
---@class rtu
|
---@class rtu
|
||||||
local protected = {}
|
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
|
-- refresh IO count
|
||||||
local function _count_io()
|
local function _count_io()
|
||||||
self.io_count_cache = { #self.discrete_inputs, #self.coils, #self.input_regs, #self.holding_regs }
|
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
|
---@param di_addr integer
|
||||||
---@return any value, boolean access_fault
|
---@return any value, boolean access_fault
|
||||||
function public.read_di(di_addr)
|
function public.read_di(di_addr)
|
||||||
ppm.clear_fault()
|
|
||||||
local value = self.discrete_inputs[di_addr].read()
|
local value = self.discrete_inputs[di_addr].read()
|
||||||
return value, ppm.is_faulted()
|
return value, _is_faulted()
|
||||||
end
|
end
|
||||||
|
|
||||||
-- coils: single bit read-write
|
-- coils: single bit read-write
|
||||||
@ -133,9 +138,8 @@ function rtu.init_unit()
|
|||||||
---@param coil_addr integer
|
---@param coil_addr integer
|
||||||
---@return any value, boolean access_fault
|
---@return any value, boolean access_fault
|
||||||
function public.read_coil(coil_addr)
|
function public.read_coil(coil_addr)
|
||||||
ppm.clear_fault()
|
|
||||||
local value = self.coils[coil_addr].read()
|
local value = self.coils[coil_addr].read()
|
||||||
return value, ppm.is_faulted()
|
return value, _is_faulted()
|
||||||
end
|
end
|
||||||
|
|
||||||
-- write coil
|
-- write coil
|
||||||
@ -143,9 +147,8 @@ function rtu.init_unit()
|
|||||||
---@param value any
|
---@param value any
|
||||||
---@return boolean access_fault
|
---@return boolean access_fault
|
||||||
function public.write_coil(coil_addr, value)
|
function public.write_coil(coil_addr, value)
|
||||||
ppm.clear_fault()
|
|
||||||
self.coils[coil_addr].write(value)
|
self.coils[coil_addr].write(value)
|
||||||
return ppm.is_faulted()
|
return _is_faulted()
|
||||||
end
|
end
|
||||||
|
|
||||||
-- input registers: multi-bit read-only
|
-- input registers: multi-bit read-only
|
||||||
@ -163,9 +166,8 @@ function rtu.init_unit()
|
|||||||
---@param reg_addr integer
|
---@param reg_addr integer
|
||||||
---@return any value, boolean access_fault
|
---@return any value, boolean access_fault
|
||||||
function public.read_input_reg(reg_addr)
|
function public.read_input_reg(reg_addr)
|
||||||
ppm.clear_fault()
|
|
||||||
local value = self.input_regs[reg_addr].read()
|
local value = self.input_regs[reg_addr].read()
|
||||||
return value, ppm.is_faulted()
|
return value, _is_faulted()
|
||||||
end
|
end
|
||||||
|
|
||||||
-- holding registers: multi-bit read-write
|
-- holding registers: multi-bit read-write
|
||||||
@ -184,9 +186,8 @@ function rtu.init_unit()
|
|||||||
---@param reg_addr integer
|
---@param reg_addr integer
|
||||||
---@return any value, boolean access_fault
|
---@return any value, boolean access_fault
|
||||||
function public.read_holding_reg(reg_addr)
|
function public.read_holding_reg(reg_addr)
|
||||||
ppm.clear_fault()
|
|
||||||
local value = self.holding_regs[reg_addr].read()
|
local value = self.holding_regs[reg_addr].read()
|
||||||
return value, ppm.is_faulted()
|
return value, _is_faulted()
|
||||||
end
|
end
|
||||||
|
|
||||||
-- write holding register
|
-- write holding register
|
||||||
@ -194,9 +195,8 @@ function rtu.init_unit()
|
|||||||
---@param value any
|
---@param value any
|
||||||
---@return boolean access_fault
|
---@return boolean access_fault
|
||||||
function public.write_holding_reg(reg_addr, value)
|
function public.write_holding_reg(reg_addr, value)
|
||||||
ppm.clear_fault()
|
|
||||||
self.holding_regs[reg_addr].write(value)
|
self.holding_regs[reg_addr].write(value)
|
||||||
return ppm.is_faulted()
|
return _is_faulted()
|
||||||
end
|
end
|
||||||
|
|
||||||
-- public RTU device access
|
-- public RTU device access
|
||||||
|
@ -31,7 +31,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 = "v1.7.14"
|
local RTU_VERSION = "v1.7.15"
|
||||||
|
|
||||||
local RTU_UNIT_TYPE = types.RTU_UNIT_TYPE
|
local RTU_UNIT_TYPE = types.RTU_UNIT_TYPE
|
||||||
local RTU_UNIT_HW_STATE = databus.RTU_UNIT_HW_STATE
|
local RTU_UNIT_HW_STATE = databus.RTU_UNIT_HW_STATE
|
||||||
|
@ -131,31 +131,33 @@ local function peri_init(iface)
|
|||||||
|
|
||||||
local mt = {
|
local mt = {
|
||||||
__index = function (_, key)
|
__index = function (_, key)
|
||||||
-- this will continuously be counting calls here as faults
|
return (function ()
|
||||||
-- unlike other functions, faults here can't be cleared as it is just not defined
|
-- this will continuously be counting calls here as faults
|
||||||
if self.fault_counts[key] == nil then
|
-- unlike other functions, faults here can't be cleared as it is just not defined
|
||||||
self.fault_counts[key] = 0
|
if self.fault_counts[key] == nil then
|
||||||
end
|
self.fault_counts[key] = 0
|
||||||
|
|
||||||
-- 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]"
|
|
||||||
end
|
end
|
||||||
|
|
||||||
log.error(util.c("PPM: caught undefined function ", key, "()", count_str))
|
-- function failed
|
||||||
end
|
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
|
end
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user