mirror of
https://github.com/MikaylaFischler/cc-mek-scada.git
synced 2024-08-30 18:22:34 +00:00
parent
1c0f61b3e0
commit
19869416af
@ -144,9 +144,9 @@ function plc.rps_init(reactor, is_formed)
|
|||||||
local function _check_and_handle_ppm_call(result)
|
local function _check_and_handle_ppm_call(result)
|
||||||
if result == ppm.ACCESS_FAULT then
|
if result == ppm.ACCESS_FAULT then
|
||||||
_set_fault()
|
_set_fault()
|
||||||
elseif result == ppm.UNDEFINED_FIELD then
|
|
||||||
_set_fault()
|
-- if undefined, then the reactor isn't formed
|
||||||
self.formed = false
|
if reactor.__p_last_fault() == ppm.UNDEFINED_FIELD then self.formed = false end
|
||||||
else return true end
|
else return true end
|
||||||
|
|
||||||
return false
|
return false
|
||||||
|
@ -18,7 +18,7 @@ local plc = require("reactor-plc.plc")
|
|||||||
local renderer = require("reactor-plc.renderer")
|
local renderer = require("reactor-plc.renderer")
|
||||||
local threads = require("reactor-plc.threads")
|
local threads = require("reactor-plc.threads")
|
||||||
|
|
||||||
local R_PLC_VERSION = "v1.7.0"
|
local R_PLC_VERSION = "v1.7.1"
|
||||||
|
|
||||||
local println = util.println
|
local println = util.println
|
||||||
local println_ts = util.println_ts
|
local println_ts = util.println_ts
|
||||||
@ -144,13 +144,6 @@ local function main()
|
|||||||
println("init> fission reactor is not formed")
|
println("init> fission reactor is not formed")
|
||||||
log.warning("init> reactor logic adapter present, but reactor is not formed")
|
log.warning("init> reactor logic adapter present, but reactor is not formed")
|
||||||
|
|
||||||
plc_state.degraded = true
|
|
||||||
plc_state.reactor_formed = false
|
|
||||||
elseif smem_dev.reactor.getStatus() == ppm.UNDEFINED_FIELD then
|
|
||||||
-- reactor formed after ppm.mount_all was called
|
|
||||||
println("init> fission reactor was not formed")
|
|
||||||
log.warning("init> reactor reported formed, but multiblock functions are not available")
|
|
||||||
|
|
||||||
plc_state.degraded = true
|
plc_state.degraded = true
|
||||||
plc_state.reactor_formed = false
|
plc_state.reactor_formed = false
|
||||||
end
|
end
|
||||||
@ -185,6 +178,7 @@ local function main()
|
|||||||
local message
|
local message
|
||||||
plc_state.fp_ok, message = renderer.try_start_ui(config.FrontPanelTheme, config.ColorMode)
|
plc_state.fp_ok, message = renderer.try_start_ui(config.FrontPanelTheme, config.ColorMode)
|
||||||
|
|
||||||
|
-- ...or not
|
||||||
if not plc_state.fp_ok then
|
if not plc_state.fp_ok then
|
||||||
println_ts(util.c("UI error: ", message))
|
println_ts(util.c("UI error: ", message))
|
||||||
println("init> running without front panel")
|
println("init> running without front panel")
|
||||||
|
@ -9,58 +9,49 @@ local boilerv_rtu = {}
|
|||||||
function boilerv_rtu.new(boiler)
|
function boilerv_rtu.new(boiler)
|
||||||
local unit = rtu.init_unit(boiler)
|
local unit = rtu.init_unit(boiler)
|
||||||
|
|
||||||
-- disable auto fault clearing
|
|
||||||
boiler.__p_clear_fault()
|
|
||||||
boiler.__p_disable_afc()
|
|
||||||
|
|
||||||
-- discrete inputs --
|
-- discrete inputs --
|
||||||
unit.connect_di(boiler.isFormed)
|
unit.connect_di("isFormed")
|
||||||
|
|
||||||
-- coils --
|
-- coils --
|
||||||
-- none
|
-- none
|
||||||
|
|
||||||
-- input registers --
|
-- input registers --
|
||||||
-- multiblock properties
|
-- multiblock properties
|
||||||
unit.connect_input_reg(boiler.getLength)
|
unit.connect_input_reg("getLength")
|
||||||
unit.connect_input_reg(boiler.getWidth)
|
unit.connect_input_reg("getWidth")
|
||||||
unit.connect_input_reg(boiler.getHeight)
|
unit.connect_input_reg("getHeight")
|
||||||
unit.connect_input_reg(boiler.getMinPos)
|
unit.connect_input_reg("getMinPos")
|
||||||
unit.connect_input_reg(boiler.getMaxPos)
|
unit.connect_input_reg("getMaxPos")
|
||||||
-- build properties
|
-- build properties
|
||||||
unit.connect_input_reg(boiler.getBoilCapacity)
|
unit.connect_input_reg("getBoilCapacity")
|
||||||
unit.connect_input_reg(boiler.getSteamCapacity)
|
unit.connect_input_reg("getSteamCapacity")
|
||||||
unit.connect_input_reg(boiler.getWaterCapacity)
|
unit.connect_input_reg("getWaterCapacity")
|
||||||
unit.connect_input_reg(boiler.getHeatedCoolantCapacity)
|
unit.connect_input_reg("getHeatedCoolantCapacity")
|
||||||
unit.connect_input_reg(boiler.getCooledCoolantCapacity)
|
unit.connect_input_reg("getCooledCoolantCapacity")
|
||||||
unit.connect_input_reg(boiler.getSuperheaters)
|
unit.connect_input_reg("getSuperheaters")
|
||||||
unit.connect_input_reg(boiler.getMaxBoilRate)
|
unit.connect_input_reg("getMaxBoilRate")
|
||||||
-- current state
|
-- current state
|
||||||
unit.connect_input_reg(boiler.getTemperature)
|
unit.connect_input_reg("getTemperature")
|
||||||
unit.connect_input_reg(boiler.getBoilRate)
|
unit.connect_input_reg("getBoilRate")
|
||||||
unit.connect_input_reg(boiler.getEnvironmentalLoss)
|
unit.connect_input_reg("getEnvironmentalLoss")
|
||||||
-- tanks
|
-- tanks
|
||||||
unit.connect_input_reg(boiler.getSteam)
|
unit.connect_input_reg("getSteam")
|
||||||
unit.connect_input_reg(boiler.getSteamNeeded)
|
unit.connect_input_reg("getSteamNeeded")
|
||||||
unit.connect_input_reg(boiler.getSteamFilledPercentage)
|
unit.connect_input_reg("getSteamFilledPercentage")
|
||||||
unit.connect_input_reg(boiler.getWater)
|
unit.connect_input_reg("getWater")
|
||||||
unit.connect_input_reg(boiler.getWaterNeeded)
|
unit.connect_input_reg("getWaterNeeded")
|
||||||
unit.connect_input_reg(boiler.getWaterFilledPercentage)
|
unit.connect_input_reg("getWaterFilledPercentage")
|
||||||
unit.connect_input_reg(boiler.getHeatedCoolant)
|
unit.connect_input_reg("getHeatedCoolant")
|
||||||
unit.connect_input_reg(boiler.getHeatedCoolantNeeded)
|
unit.connect_input_reg("getHeatedCoolantNeeded")
|
||||||
unit.connect_input_reg(boiler.getHeatedCoolantFilledPercentage)
|
unit.connect_input_reg("getHeatedCoolantFilledPercentage")
|
||||||
unit.connect_input_reg(boiler.getCooledCoolant)
|
unit.connect_input_reg("getCooledCoolant")
|
||||||
unit.connect_input_reg(boiler.getCooledCoolantNeeded)
|
unit.connect_input_reg("getCooledCoolantNeeded")
|
||||||
unit.connect_input_reg(boiler.getCooledCoolantFilledPercentage)
|
unit.connect_input_reg("getCooledCoolantFilledPercentage")
|
||||||
|
|
||||||
-- holding registers --
|
-- holding registers --
|
||||||
-- none
|
-- none
|
||||||
|
|
||||||
-- check if any calls faulted
|
return unit.interface(), false
|
||||||
local faulted = boiler.__p_is_faulted()
|
|
||||||
boiler.__p_clear_fault()
|
|
||||||
boiler.__p_enable_afc()
|
|
||||||
|
|
||||||
return unit.interface(), faulted
|
|
||||||
end
|
end
|
||||||
|
|
||||||
return boilerv_rtu
|
return boilerv_rtu
|
||||||
|
@ -9,12 +9,8 @@ local dynamicv_rtu = {}
|
|||||||
function dynamicv_rtu.new(dynamic_tank)
|
function dynamicv_rtu.new(dynamic_tank)
|
||||||
local unit = rtu.init_unit(dynamic_tank)
|
local unit = rtu.init_unit(dynamic_tank)
|
||||||
|
|
||||||
-- disable auto fault clearing
|
|
||||||
dynamic_tank.__p_clear_fault()
|
|
||||||
dynamic_tank.__p_disable_afc()
|
|
||||||
|
|
||||||
-- discrete inputs --
|
-- discrete inputs --
|
||||||
unit.connect_di(dynamic_tank.isFormed)
|
unit.connect_di("isFormed")
|
||||||
|
|
||||||
-- coils --
|
-- coils --
|
||||||
unit.connect_coil(function () dynamic_tank.incrementContainerEditMode() end, function () end)
|
unit.connect_coil(function () dynamic_tank.incrementContainerEditMode() end, function () end)
|
||||||
@ -22,27 +18,22 @@ function dynamicv_rtu.new(dynamic_tank)
|
|||||||
|
|
||||||
-- input registers --
|
-- input registers --
|
||||||
-- multiblock properties
|
-- multiblock properties
|
||||||
unit.connect_input_reg(dynamic_tank.getLength)
|
unit.connect_input_reg("getLength")
|
||||||
unit.connect_input_reg(dynamic_tank.getWidth)
|
unit.connect_input_reg("getWidth")
|
||||||
unit.connect_input_reg(dynamic_tank.getHeight)
|
unit.connect_input_reg("getHeight")
|
||||||
unit.connect_input_reg(dynamic_tank.getMinPos)
|
unit.connect_input_reg("getMinPos")
|
||||||
unit.connect_input_reg(dynamic_tank.getMaxPos)
|
unit.connect_input_reg("getMaxPos")
|
||||||
-- build properties
|
-- build properties
|
||||||
unit.connect_input_reg(dynamic_tank.getTankCapacity)
|
unit.connect_input_reg("getTankCapacity")
|
||||||
unit.connect_input_reg(dynamic_tank.getChemicalTankCapacity)
|
unit.connect_input_reg("getChemicalTankCapacity")
|
||||||
-- tanks/containers
|
-- tanks/containers
|
||||||
unit.connect_input_reg(dynamic_tank.getStored)
|
unit.connect_input_reg("getStored")
|
||||||
unit.connect_input_reg(dynamic_tank.getFilledPercentage)
|
unit.connect_input_reg("getFilledPercentage")
|
||||||
|
|
||||||
-- holding registers --
|
-- holding registers --
|
||||||
unit.connect_holding_reg(dynamic_tank.getContainerEditMode, dynamic_tank.setContainerEditMode)
|
unit.connect_holding_reg("getContainerEditMode", "setContainerEditMode")
|
||||||
|
|
||||||
-- check if any calls faulted
|
return unit.interface(), false
|
||||||
local faulted = dynamic_tank.__p_is_faulted()
|
|
||||||
dynamic_tank.__p_clear_fault()
|
|
||||||
dynamic_tank.__p_enable_afc()
|
|
||||||
|
|
||||||
return unit.interface(), faulted
|
|
||||||
end
|
end
|
||||||
|
|
||||||
return dynamicv_rtu
|
return dynamicv_rtu
|
||||||
|
@ -9,45 +9,36 @@ local imatrix_rtu = {}
|
|||||||
function imatrix_rtu.new(imatrix)
|
function imatrix_rtu.new(imatrix)
|
||||||
local unit = rtu.init_unit(imatrix)
|
local unit = rtu.init_unit(imatrix)
|
||||||
|
|
||||||
-- disable auto fault clearing
|
|
||||||
imatrix.__p_clear_fault()
|
|
||||||
imatrix.__p_disable_afc()
|
|
||||||
|
|
||||||
-- discrete inputs --
|
-- discrete inputs --
|
||||||
unit.connect_di(imatrix.isFormed)
|
unit.connect_di("isFormed")
|
||||||
|
|
||||||
-- coils --
|
-- coils --
|
||||||
-- none
|
-- none
|
||||||
|
|
||||||
-- input registers --
|
-- input registers --
|
||||||
-- multiblock properties
|
-- multiblock properties
|
||||||
unit.connect_input_reg(imatrix.getLength)
|
unit.connect_input_reg("getLength")
|
||||||
unit.connect_input_reg(imatrix.getWidth)
|
unit.connect_input_reg("getWidth")
|
||||||
unit.connect_input_reg(imatrix.getHeight)
|
unit.connect_input_reg("getHeight")
|
||||||
unit.connect_input_reg(imatrix.getMinPos)
|
unit.connect_input_reg("getMinPos")
|
||||||
unit.connect_input_reg(imatrix.getMaxPos)
|
unit.connect_input_reg("getMaxPos")
|
||||||
-- build properties
|
-- build properties
|
||||||
unit.connect_input_reg(imatrix.getMaxEnergy)
|
unit.connect_input_reg("getMaxEnergy")
|
||||||
unit.connect_input_reg(imatrix.getTransferCap)
|
unit.connect_input_reg("getTransferCap")
|
||||||
unit.connect_input_reg(imatrix.getInstalledCells)
|
unit.connect_input_reg("getInstalledCells")
|
||||||
unit.connect_input_reg(imatrix.getInstalledProviders)
|
unit.connect_input_reg("getInstalledProviders")
|
||||||
-- I/O rates
|
-- I/O rates
|
||||||
unit.connect_input_reg(imatrix.getLastInput)
|
unit.connect_input_reg("getLastInput")
|
||||||
unit.connect_input_reg(imatrix.getLastOutput)
|
unit.connect_input_reg("getLastOutput")
|
||||||
-- tanks
|
-- tanks
|
||||||
unit.connect_input_reg(imatrix.getEnergy)
|
unit.connect_input_reg("getEnergy")
|
||||||
unit.connect_input_reg(imatrix.getEnergyNeeded)
|
unit.connect_input_reg("getEnergyNeeded")
|
||||||
unit.connect_input_reg(imatrix.getEnergyFilledPercentage)
|
unit.connect_input_reg("getEnergyFilledPercentage")
|
||||||
|
|
||||||
-- holding registers --
|
-- holding registers --
|
||||||
-- none
|
-- none
|
||||||
|
|
||||||
-- check if any calls faulted
|
return unit.interface(), false
|
||||||
local faulted = imatrix.__p_is_faulted()
|
|
||||||
imatrix.__p_clear_fault()
|
|
||||||
imatrix.__p_enable_afc()
|
|
||||||
|
|
||||||
return unit.interface(), faulted
|
|
||||||
end
|
end
|
||||||
|
|
||||||
return imatrix_rtu
|
return imatrix_rtu
|
||||||
|
@ -9,50 +9,41 @@ local sps_rtu = {}
|
|||||||
function sps_rtu.new(sps)
|
function sps_rtu.new(sps)
|
||||||
local unit = rtu.init_unit(sps)
|
local unit = rtu.init_unit(sps)
|
||||||
|
|
||||||
-- disable auto fault clearing
|
|
||||||
sps.__p_clear_fault()
|
|
||||||
sps.__p_disable_afc()
|
|
||||||
|
|
||||||
-- discrete inputs --
|
-- discrete inputs --
|
||||||
unit.connect_di(sps.isFormed)
|
unit.connect_di("isFormed")
|
||||||
|
|
||||||
-- coils --
|
-- coils --
|
||||||
-- none
|
-- none
|
||||||
|
|
||||||
-- input registers --
|
-- input registers --
|
||||||
-- multiblock properties
|
-- multiblock properties
|
||||||
unit.connect_input_reg(sps.getLength)
|
unit.connect_input_reg("getLength")
|
||||||
unit.connect_input_reg(sps.getWidth)
|
unit.connect_input_reg("getWidth")
|
||||||
unit.connect_input_reg(sps.getHeight)
|
unit.connect_input_reg("getHeight")
|
||||||
unit.connect_input_reg(sps.getMinPos)
|
unit.connect_input_reg("getMinPos")
|
||||||
unit.connect_input_reg(sps.getMaxPos)
|
unit.connect_input_reg("getMaxPos")
|
||||||
-- build properties
|
-- build properties
|
||||||
unit.connect_input_reg(sps.getCoils)
|
unit.connect_input_reg("getCoils")
|
||||||
unit.connect_input_reg(sps.getInputCapacity)
|
unit.connect_input_reg("getInputCapacity")
|
||||||
unit.connect_input_reg(sps.getOutputCapacity)
|
unit.connect_input_reg("getOutputCapacity")
|
||||||
unit.connect_input_reg(sps.getMaxEnergy)
|
unit.connect_input_reg("getMaxEnergy")
|
||||||
-- current state
|
-- current state
|
||||||
unit.connect_input_reg(sps.getProcessRate)
|
unit.connect_input_reg("getProcessRate")
|
||||||
-- tanks
|
-- tanks
|
||||||
unit.connect_input_reg(sps.getInput)
|
unit.connect_input_reg("getInput")
|
||||||
unit.connect_input_reg(sps.getInputNeeded)
|
unit.connect_input_reg("getInputNeeded")
|
||||||
unit.connect_input_reg(sps.getInputFilledPercentage)
|
unit.connect_input_reg("getInputFilledPercentage")
|
||||||
unit.connect_input_reg(sps.getOutput)
|
unit.connect_input_reg("getOutput")
|
||||||
unit.connect_input_reg(sps.getOutputNeeded)
|
unit.connect_input_reg("getOutputNeeded")
|
||||||
unit.connect_input_reg(sps.getOutputFilledPercentage)
|
unit.connect_input_reg("getOutputFilledPercentage")
|
||||||
unit.connect_input_reg(sps.getEnergy)
|
unit.connect_input_reg("getEnergy")
|
||||||
unit.connect_input_reg(sps.getEnergyNeeded)
|
unit.connect_input_reg("getEnergyNeeded")
|
||||||
unit.connect_input_reg(sps.getEnergyFilledPercentage)
|
unit.connect_input_reg("getEnergyFilledPercentage")
|
||||||
|
|
||||||
-- holding registers --
|
-- holding registers --
|
||||||
-- none
|
-- none
|
||||||
|
|
||||||
-- check if any calls faulted
|
return unit.interface(), false
|
||||||
local faulted = sps.__p_is_faulted()
|
|
||||||
sps.__p_clear_fault()
|
|
||||||
sps.__p_enable_afc()
|
|
||||||
|
|
||||||
return unit.interface(), faulted
|
|
||||||
end
|
end
|
||||||
|
|
||||||
return sps_rtu
|
return sps_rtu
|
||||||
|
@ -9,12 +9,8 @@ local turbinev_rtu = {}
|
|||||||
function turbinev_rtu.new(turbine)
|
function turbinev_rtu.new(turbine)
|
||||||
local unit = rtu.init_unit(turbine)
|
local unit = rtu.init_unit(turbine)
|
||||||
|
|
||||||
-- disable auto fault clearing
|
|
||||||
turbine.__p_clear_fault()
|
|
||||||
turbine.__p_disable_afc()
|
|
||||||
|
|
||||||
-- discrete inputs --
|
-- discrete inputs --
|
||||||
unit.connect_di(turbine.isFormed)
|
unit.connect_di("isFormed")
|
||||||
|
|
||||||
-- coils --
|
-- coils --
|
||||||
unit.connect_coil(function () turbine.incrementDumpingMode() end, function () end)
|
unit.connect_coil(function () turbine.incrementDumpingMode() end, function () end)
|
||||||
@ -22,44 +18,39 @@ function turbinev_rtu.new(turbine)
|
|||||||
|
|
||||||
-- input registers --
|
-- input registers --
|
||||||
-- multiblock properties
|
-- multiblock properties
|
||||||
unit.connect_input_reg(turbine.getLength)
|
unit.connect_input_reg("getLength")
|
||||||
unit.connect_input_reg(turbine.getWidth)
|
unit.connect_input_reg("getWidth")
|
||||||
unit.connect_input_reg(turbine.getHeight)
|
unit.connect_input_reg("getHeight")
|
||||||
unit.connect_input_reg(turbine.getMinPos)
|
unit.connect_input_reg("getMinPos")
|
||||||
unit.connect_input_reg(turbine.getMaxPos)
|
unit.connect_input_reg("getMaxPos")
|
||||||
-- build properties
|
-- build properties
|
||||||
unit.connect_input_reg(turbine.getBlades)
|
unit.connect_input_reg("getBlades")
|
||||||
unit.connect_input_reg(turbine.getCoils)
|
unit.connect_input_reg("getCoils")
|
||||||
unit.connect_input_reg(turbine.getVents)
|
unit.connect_input_reg("getVents")
|
||||||
unit.connect_input_reg(turbine.getDispersers)
|
unit.connect_input_reg("getDispersers")
|
||||||
unit.connect_input_reg(turbine.getCondensers)
|
unit.connect_input_reg("getCondensers")
|
||||||
unit.connect_input_reg(turbine.getSteamCapacity)
|
unit.connect_input_reg("getSteamCapacity")
|
||||||
unit.connect_input_reg(turbine.getMaxEnergy)
|
unit.connect_input_reg("getMaxEnergy")
|
||||||
unit.connect_input_reg(turbine.getMaxFlowRate)
|
unit.connect_input_reg("getMaxFlowRate")
|
||||||
unit.connect_input_reg(turbine.getMaxProduction)
|
unit.connect_input_reg("getMaxProduction")
|
||||||
unit.connect_input_reg(turbine.getMaxWaterOutput)
|
unit.connect_input_reg("getMaxWaterOutput")
|
||||||
-- current state
|
-- current state
|
||||||
unit.connect_input_reg(turbine.getFlowRate)
|
unit.connect_input_reg("getFlowRate")
|
||||||
unit.connect_input_reg(turbine.getProductionRate)
|
unit.connect_input_reg("getProductionRate")
|
||||||
unit.connect_input_reg(turbine.getLastSteamInputRate)
|
unit.connect_input_reg("getLastSteamInputRate")
|
||||||
unit.connect_input_reg(turbine.getDumpingMode)
|
unit.connect_input_reg("getDumpingMode")
|
||||||
-- tanks/containers
|
-- tanks/containers
|
||||||
unit.connect_input_reg(turbine.getSteam)
|
unit.connect_input_reg("getSteam")
|
||||||
unit.connect_input_reg(turbine.getSteamNeeded)
|
unit.connect_input_reg("getSteamNeeded")
|
||||||
unit.connect_input_reg(turbine.getSteamFilledPercentage)
|
unit.connect_input_reg("getSteamFilledPercentage")
|
||||||
unit.connect_input_reg(turbine.getEnergy)
|
unit.connect_input_reg("getEnergy")
|
||||||
unit.connect_input_reg(turbine.getEnergyNeeded)
|
unit.connect_input_reg("getEnergyNeeded")
|
||||||
unit.connect_input_reg(turbine.getEnergyFilledPercentage)
|
unit.connect_input_reg("getEnergyFilledPercentage")
|
||||||
|
|
||||||
-- holding registers --
|
-- holding registers --
|
||||||
unit.connect_holding_reg(turbine.getDumpingMode, turbine.setDumpingMode)
|
unit.connect_holding_reg("getDumpingMode", "setDumpingMode")
|
||||||
|
|
||||||
-- check if any calls faulted
|
return unit.interface(), false
|
||||||
local faulted = turbine.__p_is_faulted()
|
|
||||||
turbine.__p_clear_fault()
|
|
||||||
turbine.__p_enable_afc()
|
|
||||||
|
|
||||||
return unit.interface(), faulted
|
|
||||||
end
|
end
|
||||||
|
|
||||||
return turbinev_rtu
|
return turbinev_rtu
|
||||||
|
35
rtu/rtu.lua
35
rtu/rtu.lua
@ -92,6 +92,8 @@ function rtu.init_unit(device)
|
|||||||
|
|
||||||
local insert = table.insert
|
local insert = table.insert
|
||||||
|
|
||||||
|
local stub = function () log.warning("tried to call an RTU function stub") end
|
||||||
|
|
||||||
---@class rtu_device
|
---@class rtu_device
|
||||||
local public = {}
|
local public = {}
|
||||||
|
|
||||||
@ -113,13 +115,26 @@ function rtu.init_unit(device)
|
|||||||
return self.io_count_cache[1], self.io_count_cache[2], self.io_count_cache[3], self.io_count_cache[4]
|
return self.io_count_cache[1], self.io_count_cache[2], self.io_count_cache[3], self.io_count_cache[4]
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- pass a function through or generate one to call a function by name from the device
|
||||||
|
---@param f function|string function or device function name
|
||||||
|
local function _as_func(f)
|
||||||
|
if type(f) == "string" then
|
||||||
|
local name = f
|
||||||
|
if device then
|
||||||
|
f = function (...) return device[name](...) end
|
||||||
|
else f = stub end
|
||||||
|
end
|
||||||
|
|
||||||
|
return f
|
||||||
|
end
|
||||||
|
|
||||||
-- discrete inputs: single bit read-only
|
-- discrete inputs: single bit read-only
|
||||||
|
|
||||||
-- connect discrete input
|
-- connect discrete input
|
||||||
---@param f function
|
---@param f function|string function or function name
|
||||||
---@return integer count count of discrete inputs
|
---@return integer count count of discrete inputs
|
||||||
function protected.connect_di(f)
|
function protected.connect_di(f)
|
||||||
insert(self.discrete_inputs, { read = f })
|
insert(self.discrete_inputs, { read = _as_func(f) })
|
||||||
_count_io()
|
_count_io()
|
||||||
return #self.discrete_inputs
|
return #self.discrete_inputs
|
||||||
end
|
end
|
||||||
@ -135,11 +150,11 @@ function rtu.init_unit(device)
|
|||||||
-- coils: single bit read-write
|
-- coils: single bit read-write
|
||||||
|
|
||||||
-- connect coil
|
-- connect coil
|
||||||
---@param f_read function
|
---@param f_read function|string function or function name
|
||||||
---@param f_write function
|
---@param f_write function|string function or function name
|
||||||
---@return integer count count of coils
|
---@return integer count count of coils
|
||||||
function protected.connect_coil(f_read, f_write)
|
function protected.connect_coil(f_read, f_write)
|
||||||
insert(self.coils, { read = f_read, write = f_write })
|
insert(self.coils, { read = _as_func(f_read), write = _as_func(f_write) })
|
||||||
_count_io()
|
_count_io()
|
||||||
return #self.coils
|
return #self.coils
|
||||||
end
|
end
|
||||||
@ -164,10 +179,10 @@ function rtu.init_unit(device)
|
|||||||
-- input registers: multi-bit read-only
|
-- input registers: multi-bit read-only
|
||||||
|
|
||||||
-- connect input register
|
-- connect input register
|
||||||
---@param f function
|
---@param f function|string function or function name
|
||||||
---@return integer count count of input registers
|
---@return integer count count of input registers
|
||||||
function protected.connect_input_reg(f)
|
function protected.connect_input_reg(f)
|
||||||
insert(self.input_regs, { read = f })
|
insert(self.input_regs, { read = _as_func(f) })
|
||||||
_count_io()
|
_count_io()
|
||||||
return #self.input_regs
|
return #self.input_regs
|
||||||
end
|
end
|
||||||
@ -183,11 +198,11 @@ function rtu.init_unit(device)
|
|||||||
-- holding registers: multi-bit read-write
|
-- holding registers: multi-bit read-write
|
||||||
|
|
||||||
-- connect holding register
|
-- connect holding register
|
||||||
---@param f_read function
|
---@param f_read function|string function or function name
|
||||||
---@param f_write function
|
---@param f_write function|string function or function name
|
||||||
---@return integer count count of holding registers
|
---@return integer count count of holding registers
|
||||||
function protected.connect_holding_reg(f_read, f_write)
|
function protected.connect_holding_reg(f_read, f_write)
|
||||||
insert(self.holding_regs, { read = f_read, write = f_write })
|
insert(self.holding_regs, { read = _as_func(f_read), write = _as_func(f_write) })
|
||||||
_count_io()
|
_count_io()
|
||||||
return #self.holding_regs
|
return #self.holding_regs
|
||||||
end
|
end
|
||||||
|
@ -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.8.0"
|
local RTU_VERSION = "v1.9.0"
|
||||||
|
|
||||||
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
|
||||||
@ -342,7 +342,7 @@ local function main()
|
|||||||
is_multiblock = true
|
is_multiblock = true
|
||||||
formed = device.isFormed()
|
formed = device.isFormed()
|
||||||
|
|
||||||
if formed == ppm.UNDEFINED_FIELD or formed == ppm.ACCESS_FAULT then
|
if formed == ppm.ACCESS_FAULT then
|
||||||
println_ts(util.c("sys_config> failed to check if '", name, "' is formed"))
|
println_ts(util.c("sys_config> failed to check if '", name, "' is formed"))
|
||||||
log.fatal(util.c("sys_config> failed to check if '", name, "' is a formed boiler multiblock"))
|
log.fatal(util.c("sys_config> failed to check if '", name, "' is a formed boiler multiblock"))
|
||||||
return false
|
return false
|
||||||
@ -357,7 +357,7 @@ local function main()
|
|||||||
is_multiblock = true
|
is_multiblock = true
|
||||||
formed = device.isFormed()
|
formed = device.isFormed()
|
||||||
|
|
||||||
if formed == ppm.UNDEFINED_FIELD or formed == ppm.ACCESS_FAULT then
|
if formed == ppm.ACCESS_FAULT then
|
||||||
println_ts(util.c("sys_config> failed to check if '", name, "' is formed"))
|
println_ts(util.c("sys_config> failed to check if '", name, "' is formed"))
|
||||||
log.fatal(util.c("sys_config> failed to check if '", name, "' is a formed turbine multiblock"))
|
log.fatal(util.c("sys_config> failed to check if '", name, "' is a formed turbine multiblock"))
|
||||||
return false
|
return false
|
||||||
@ -377,7 +377,7 @@ local function main()
|
|||||||
is_multiblock = true
|
is_multiblock = true
|
||||||
formed = device.isFormed()
|
formed = device.isFormed()
|
||||||
|
|
||||||
if formed == ppm.UNDEFINED_FIELD or formed == ppm.ACCESS_FAULT then
|
if formed == ppm.ACCESS_FAULT then
|
||||||
println_ts(util.c("sys_config> failed to check if '", name, "' is formed"))
|
println_ts(util.c("sys_config> failed to check if '", name, "' is formed"))
|
||||||
log.fatal(util.c("sys_config> failed to check if '", name, "' is a formed dynamic tank multiblock"))
|
log.fatal(util.c("sys_config> failed to check if '", name, "' is a formed dynamic tank multiblock"))
|
||||||
return false
|
return false
|
||||||
@ -391,7 +391,7 @@ local function main()
|
|||||||
is_multiblock = true
|
is_multiblock = true
|
||||||
formed = device.isFormed()
|
formed = device.isFormed()
|
||||||
|
|
||||||
if formed == ppm.UNDEFINED_FIELD or formed == ppm.ACCESS_FAULT then
|
if formed == ppm.ACCESS_FAULT then
|
||||||
println_ts(util.c("sys_config> failed to check if '", name, "' is formed"))
|
println_ts(util.c("sys_config> failed to check if '", name, "' is formed"))
|
||||||
log.fatal(util.c("sys_config> failed to check if '", name, "' is a formed induction matrix multiblock"))
|
log.fatal(util.c("sys_config> failed to check if '", name, "' is a formed induction matrix multiblock"))
|
||||||
return false
|
return false
|
||||||
@ -405,7 +405,7 @@ local function main()
|
|||||||
is_multiblock = true
|
is_multiblock = true
|
||||||
formed = device.isFormed()
|
formed = device.isFormed()
|
||||||
|
|
||||||
if formed == ppm.UNDEFINED_FIELD or formed == ppm.ACCESS_FAULT then
|
if formed == ppm.ACCESS_FAULT then
|
||||||
println_ts(util.c("sys_config> failed to check if '", name, "' is formed"))
|
println_ts(util.c("sys_config> failed to check if '", name, "' is formed"))
|
||||||
log.fatal(util.c("sys_config> failed to check if '", name, "' is a formed SPS multiblock"))
|
log.fatal(util.c("sys_config> failed to check if '", name, "' is a formed SPS multiblock"))
|
||||||
return false
|
return false
|
||||||
@ -471,7 +471,8 @@ local function main()
|
|||||||
for_message = util.c("reactor ", for_reactor)
|
for_message = util.c("reactor ", for_reactor)
|
||||||
end
|
end
|
||||||
|
|
||||||
log.info(util.c("sys_config> initialized RTU unit #", #units, ": ", name, " (", types.rtu_type_to_string(rtu_type), ") [", index, "] for ", for_message))
|
local index_str = util.trinary(index ~= nil, util.c(" [", index, "]"), "")
|
||||||
|
log.info(util.c("sys_config> initialized RTU unit #", #units, ": ", name, " (", types.rtu_type_to_string(rtu_type), ")", index_str, " for ", for_message))
|
||||||
|
|
||||||
rtu_unit.uid = #units
|
rtu_unit.uid = #units
|
||||||
|
|
||||||
|
@ -517,82 +517,23 @@ function threads.thread__unit_comms(smem, unit)
|
|||||||
|
|
||||||
-- check if multiblock is still formed if this is a multiblock
|
-- check if multiblock is still formed if this is a multiblock
|
||||||
if unit.is_multiblock and (util.time_ms() - last_f_check > 250) 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()
|
last_f_check = util.time_ms()
|
||||||
|
|
||||||
|
local is_formed = unit.device.isFormed()
|
||||||
|
|
||||||
if unit.formed == nil then
|
if unit.formed == nil then
|
||||||
unit.formed = is_formed
|
unit.formed = is_formed
|
||||||
if is_formed then unit.hw_state = UNIT_HW_STATE.OK end
|
if is_formed then unit.hw_state = UNIT_HW_STATE.OK end
|
||||||
end
|
elseif not unit.formed then
|
||||||
|
|
||||||
if not unit.formed then unit.hw_state = UNIT_HW_STATE.UNFORMED end
|
|
||||||
|
|
||||||
if (not unit.formed) and is_formed then
|
|
||||||
-- newly re-formed
|
|
||||||
local iface = ppm.get_iface(unit.device)
|
|
||||||
if iface then
|
|
||||||
log.info(util.c("unmounting and remounting reformed RTU unit ", detail_name))
|
|
||||||
|
|
||||||
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, 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, faulted = turbinev_rtu.new(device)
|
|
||||||
unit.formed = device.isFormed()
|
|
||||||
unit.modbus_io = modbus.new(unit.rtu, true)
|
|
||||||
elseif type == "dynamicValve" and unit.type == RTU_UNIT_TYPE.DYNAMIC_VALVE then
|
|
||||||
-- dynamic tank multiblock
|
|
||||||
unit.device = device
|
|
||||||
unit.rtu, faulted = dynamicv_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, 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, 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 or type change attempted for " .. short_name, true)
|
|
||||||
end
|
|
||||||
|
|
||||||
if unit.formed and faulted then
|
|
||||||
-- something is still wrong = can't mark as formed yet
|
|
||||||
unit.formed = false
|
|
||||||
unit.hw_state = UNIT_HW_STATE.UNFORMED
|
unit.hw_state = UNIT_HW_STATE.UNFORMED
|
||||||
log.info(util.c("assuming ", unit.name, " is not formed due to PPM faults while initializing"))
|
|
||||||
else
|
|
||||||
unit.hw_state = UNIT_HW_STATE.OK
|
|
||||||
rtu_comms.send_remounted(unit.uid)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
local type_name = types.rtu_type_to_string(unit.type)
|
if (is_formed == true) and not unit.formed then
|
||||||
log.info(util.c("reconnected the ", type_name, " on interface ", unit.name))
|
unit.hw_state = UNIT_HW_STATE.OK
|
||||||
else
|
log.info(util.c(detail_name, " is now formed"))
|
||||||
-- fully lost the peripheral now :(
|
rtu_comms.send_remounted(unit.uid)
|
||||||
log.error(util.c(unit.name, " lost (failed reconnect)"))
|
elseif (is_formed == false) and unit.formed then
|
||||||
end
|
log.warning(util.c(detail_name, " is no longer formed"))
|
||||||
else
|
|
||||||
log.error("failed to get interface of previously connected RTU unit " .. detail_name, true)
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
unit.formed = is_formed
|
unit.formed = is_formed
|
||||||
|
@ -51,11 +51,13 @@ local function peri_init(iface)
|
|||||||
self.device = peripheral.wrap(iface)
|
self.device = peripheral.wrap(iface)
|
||||||
end
|
end
|
||||||
|
|
||||||
-- initialization process (re-map)
|
-- create a protected version of a peripheral function call
|
||||||
|
---@nodiscard
|
||||||
for key, func in pairs(self.device) do
|
---@param key string function name
|
||||||
self.fault_counts[key] = 0
|
---@param func function function
|
||||||
self.device[key] = function (...)
|
---@return function method protected version of the function
|
||||||
|
local function protect_peri_function(key, func)
|
||||||
|
return function (...)
|
||||||
local return_table = table.pack(pcall(func, ...))
|
local return_table = table.pack(pcall(func, ...))
|
||||||
|
|
||||||
local status = return_table[1]
|
local status = return_table[1]
|
||||||
@ -85,18 +87,22 @@ local function peri_init(iface)
|
|||||||
count_str = " [" .. self.fault_counts[key] .. " total faults]"
|
count_str = " [" .. self.fault_counts[key] .. " total faults]"
|
||||||
end
|
end
|
||||||
|
|
||||||
log.error(util.c("PPM: protected ", key, "() -> ", result, count_str))
|
log.error(util.c("PPM: [@", iface, "] protected ", key, "() -> ", result, count_str))
|
||||||
end
|
end
|
||||||
|
|
||||||
self.fault_counts[key] = self.fault_counts[key] + 1
|
self.fault_counts[key] = self.fault_counts[key] + 1
|
||||||
|
|
||||||
if result == "Terminated" then
|
if result == "Terminated" then ppm_sys.terminate = true end
|
||||||
ppm_sys.terminate = true
|
|
||||||
|
return ACCESS_FAULT, result
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
return ACCESS_FAULT
|
-- initialization process (re-map)
|
||||||
end
|
for key, func in pairs(self.device) do
|
||||||
end
|
self.fault_counts[key] = 0
|
||||||
|
self.device[key] = protect_peri_function(key, func)
|
||||||
end
|
end
|
||||||
|
|
||||||
-- fault management & monitoring functions
|
-- fault management & monitoring functions
|
||||||
@ -131,12 +137,21 @@ local function peri_init(iface)
|
|||||||
|
|
||||||
local mt = {
|
local mt = {
|
||||||
__index = function (_, key)
|
__index = function (_, key)
|
||||||
|
-- try to find the function in case it was added (multiblock formed)
|
||||||
|
local funcs = peripheral.wrap(iface)
|
||||||
|
if (type(funcs) == "table") and (type(funcs[key]) == "function") then
|
||||||
|
-- add this function then return it
|
||||||
|
self.device[key] = protect_peri_function(key, funcs[key])
|
||||||
|
log.info(util.c("PPM: [@", iface, "] initialized previously undefined field ", key, "()"))
|
||||||
|
|
||||||
|
return self.device[key]
|
||||||
|
end
|
||||||
|
|
||||||
|
-- function still missing, return an undefined function handler
|
||||||
|
-- note: code should avoid storing functions for multiblocks and instead try to index them again
|
||||||
return (function ()
|
return (function ()
|
||||||
-- this will continuously be counting calls here as faults
|
-- 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
|
||||||
if self.fault_counts[key] == nil then
|
|
||||||
self.fault_counts[key] = 0
|
|
||||||
end
|
|
||||||
|
|
||||||
-- function failed
|
-- function failed
|
||||||
self.faulted = true
|
self.faulted = true
|
||||||
@ -151,12 +166,12 @@ local function peri_init(iface)
|
|||||||
count_str = " [" .. self.fault_counts[key] .. " total calls]"
|
count_str = " [" .. self.fault_counts[key] .. " total calls]"
|
||||||
end
|
end
|
||||||
|
|
||||||
log.error(util.c("PPM: caught undefined function ", key, "()", count_str))
|
log.error(util.c("PPM: [@", iface, "] caught undefined function ", key, "()", count_str))
|
||||||
end
|
end
|
||||||
|
|
||||||
self.fault_counts[key] = self.fault_counts[key] + 1
|
self.fault_counts[key] = self.fault_counts[key] + 1
|
||||||
|
|
||||||
return UNDEFINED_FIELD
|
return ACCESS_FAULT, UNDEFINED_FIELD
|
||||||
end)
|
end)
|
||||||
end
|
end
|
||||||
}
|
}
|
||||||
|
@ -22,7 +22,7 @@ local t_pack = table.pack
|
|||||||
local util = {}
|
local util = {}
|
||||||
|
|
||||||
-- scada-common version
|
-- scada-common version
|
||||||
util.version = "1.1.19"
|
util.version = "1.2.0"
|
||||||
|
|
||||||
util.TICK_TIME_S = 0.05
|
util.TICK_TIME_S = 0.05
|
||||||
util.TICK_TIME_MS = 50
|
util.TICK_TIME_MS = 50
|
||||||
|
Loading…
Reference in New Issue
Block a user