code cleanup, type hints, bugfixes, and #98 removal of support for mek 10.0 RTU peripherals

This commit is contained in:
Mikayla Fischler
2022-09-21 15:53:51 -04:00
parent d0d20b1299
commit 36557fc345
31 changed files with 250 additions and 798 deletions

View File

@@ -1,48 +0,0 @@
local rtu = require("rtu.rtu")
local boiler_rtu = {}
-- create new boiler (mek 10.0) device
---@param boiler table
function boiler_rtu.new(boiler)
local unit = rtu.init_unit()
-- discrete inputs --
-- none
-- coils --
-- none
-- input registers --
-- build properties
unit.connect_input_reg(boiler.getBoilCapacity)
unit.connect_input_reg(boiler.getSteamCapacity)
unit.connect_input_reg(boiler.getWaterCapacity)
unit.connect_input_reg(boiler.getHeatedCoolantCapacity)
unit.connect_input_reg(boiler.getCooledCoolantCapacity)
unit.connect_input_reg(boiler.getSuperheaters)
unit.connect_input_reg(boiler.getMaxBoilRate)
-- current state
unit.connect_input_reg(boiler.getTemperature)
unit.connect_input_reg(boiler.getBoilRate)
-- tanks
unit.connect_input_reg(boiler.getSteam)
unit.connect_input_reg(boiler.getSteamNeeded)
unit.connect_input_reg(boiler.getSteamFilledPercentage)
unit.connect_input_reg(boiler.getWater)
unit.connect_input_reg(boiler.getWaterNeeded)
unit.connect_input_reg(boiler.getWaterFilledPercentage)
unit.connect_input_reg(boiler.getHeatedCoolant)
unit.connect_input_reg(boiler.getHeatedCoolantNeeded)
unit.connect_input_reg(boiler.getHeatedCoolantFilledPercentage)
unit.connect_input_reg(boiler.getCooledCoolant)
unit.connect_input_reg(boiler.getCooledCoolantNeeded)
unit.connect_input_reg(boiler.getCooledCoolantFilledPercentage)
-- holding registers --
-- none
return unit.interface()
end
return boiler_rtu

View File

@@ -1,30 +0,0 @@
local rtu = require("rtu.rtu")
local energymachine_rtu = {}
-- create new energy machine device
---@param machine table
function energymachine_rtu.new(machine)
local unit = rtu.init_unit()
-- discrete inputs --
-- none
-- coils --
-- none
-- input registers --
-- build properties
unit.connect_input_reg(machine.getTotalMaxEnergy)
-- containers
unit.connect_input_reg(machine.getTotalEnergy)
unit.connect_input_reg(machine.getTotalEnergyNeeded)
unit.connect_input_reg(machine.getTotalEnergyFilledPercentage)
-- holding registers --
-- none
return unit.interface()
end
return energymachine_rtu

View File

@@ -1,4 +1,5 @@
local rtu = require("rtu.rtu")
local rsio = require("scada-common.rsio")
local redstone_rtu = {}

View File

@@ -1,43 +0,0 @@
local rtu = require("rtu.rtu")
local turbine_rtu = {}
-- create new turbine (mek 10.0) device
---@param turbine table
function turbine_rtu.new(turbine)
local unit = rtu.init_unit()
-- discrete inputs --
-- none
-- coils --
-- none
-- input registers --
-- build properties
unit.connect_input_reg(turbine.getBlades)
unit.connect_input_reg(turbine.getCoils)
unit.connect_input_reg(turbine.getVents)
unit.connect_input_reg(turbine.getDispersers)
unit.connect_input_reg(turbine.getCondensers)
unit.connect_input_reg(turbine.getSteamCapacity)
unit.connect_input_reg(turbine.getMaxFlowRate)
unit.connect_input_reg(turbine.getMaxProduction)
unit.connect_input_reg(turbine.getMaxWaterOutput)
-- current state
unit.connect_input_reg(turbine.getFlowRate)
unit.connect_input_reg(turbine.getProductionRate)
unit.connect_input_reg(turbine.getLastSteamInputRate)
unit.connect_input_reg(turbine.getDumpingMode)
-- tanks
unit.connect_input_reg(turbine.getSteam)
unit.connect_input_reg(turbine.getSteamNeeded)
unit.connect_input_reg(turbine.getSteamFilledPercentage)
-- holding registers --
-- none
return unit.interface()
end
return turbine_rtu

View File

@@ -20,12 +20,15 @@ function modbus.new(rtu_dev, use_parallel_read)
local insert = table.insert
-- read a span of coils (digital outputs)
--
-- returns a table of readings or a MODBUS_EXCODE error code
---@param c_addr_start integer
---@param count integer
---@return boolean ok, table readings
---@return boolean ok, table|MODBUS_EXCODE readings
local function _1_read_coils(c_addr_start, count)
local tasks = {}
local readings = {}
local readings = {} ---@type table|MODBUS_EXCODE
local access_fault = false
local _, coils, _, _ = self.rtu.io_count()
local return_ok = ((c_addr_start + count) <= (coils + 1)) and (count > 0)
@@ -66,12 +69,15 @@ function modbus.new(rtu_dev, use_parallel_read)
return return_ok, readings
end
-- read a span of discrete inputs (digital inputs)
--
-- returns a table of readings or a MODBUS_EXCODE error code
---@param di_addr_start integer
---@param count integer
---@return boolean ok, table readings
---@return boolean ok, table|MODBUS_EXCODE readings
local function _2_read_discrete_inputs(di_addr_start, count)
local tasks = {}
local readings = {}
local readings = {} ---@type table|MODBUS_EXCODE
local access_fault = false
local discrete_inputs, _, _, _ = self.rtu.io_count()
local return_ok = ((di_addr_start + count) <= (discrete_inputs + 1)) and (count > 0)
@@ -112,12 +118,15 @@ function modbus.new(rtu_dev, use_parallel_read)
return return_ok, readings
end
-- read a span of holding registers (analog outputs)
--
-- returns a table of readings or a MODBUS_EXCODE error code
---@param hr_addr_start integer
---@param count integer
---@return boolean ok, table readings
---@return boolean ok, table|MODBUS_EXCODE readings
local function _3_read_multiple_holding_registers(hr_addr_start, count)
local tasks = {}
local readings = {}
local readings = {} ---@type table|MODBUS_EXCODE
local access_fault = false
local _, _, _, hold_regs = self.rtu.io_count()
local return_ok = ((hr_addr_start + count) <= (hold_regs + 1)) and (count > 0)
@@ -158,12 +167,15 @@ function modbus.new(rtu_dev, use_parallel_read)
return return_ok, readings
end
-- read a span of input registers (analog inputs)
--
-- returns a table of readings or a MODBUS_EXCODE error code
---@param ir_addr_start integer
---@param count integer
---@return boolean ok, table readings
---@return boolean ok, table|MODBUS_EXCODE readings
local function _4_read_input_registers(ir_addr_start, count)
local tasks = {}
local readings = {}
local readings = {} ---@type table|MODBUS_EXCODE
local access_fault = false
local _, _, input_regs, _ = self.rtu.io_count()
local return_ok = ((ir_addr_start + count) <= (input_regs + 1)) and (count > 0)
@@ -204,9 +216,10 @@ function modbus.new(rtu_dev, use_parallel_read)
return return_ok, readings
end
-- write a single coil (digital output)
---@param c_addr integer
---@param value any
---@return boolean ok, MODBUS_EXCODE|nil
---@return boolean ok, MODBUS_EXCODE
local function _5_write_single_coil(c_addr, value)
local response = nil
local _, coils, _, _ = self.rtu.io_count()
@@ -226,9 +239,10 @@ function modbus.new(rtu_dev, use_parallel_read)
return return_ok, response
end
-- write a single holding register (analog output)
---@param hr_addr integer
---@param value any
---@return boolean ok, MODBUS_EXCODE|nil
---@return boolean ok, MODBUS_EXCODE
local function _6_write_single_holding_register(hr_addr, value)
local response = nil
local _, _, _, hold_regs = self.rtu.io_count()
@@ -248,9 +262,10 @@ function modbus.new(rtu_dev, use_parallel_read)
return return_ok, response
end
-- write multiple coils (digital outputs)
---@param c_addr_start integer
---@param values any
---@return boolean ok, MODBUS_EXCODE|nil
---@return boolean ok, MODBUS_EXCODE
local function _15_write_multiple_coils(c_addr_start, values)
local response = nil
local _, coils, _, _ = self.rtu.io_count()
@@ -275,9 +290,10 @@ function modbus.new(rtu_dev, use_parallel_read)
return return_ok, response
end
-- write multiple holding registers (analog outputs)
---@param hr_addr_start integer
---@param values any
---@return boolean ok, MODBUS_EXCODE|nil
---@return boolean ok, MODBUS_EXCODE
local function _16_write_multiple_holding_registers(hr_addr_start, values)
local response = nil
local _, _, _, hold_regs = self.rtu.io_count()
@@ -403,6 +419,7 @@ function modbus.new(rtu_dev, use_parallel_read)
end
-- return a SERVER_DEVICE_BUSY error reply
---@param packet modbus_frame MODBUS packet frame
---@return modbus_packet reply
function modbus.reply__srv_device_busy(packet)
-- reply back with error flag and exception code
@@ -414,6 +431,7 @@ function modbus.reply__srv_device_busy(packet)
end
-- return a NEG_ACKNOWLEDGE error reply
---@param packet modbus_frame MODBUS packet frame
---@return modbus_packet reply
function modbus.reply__neg_ack(packet)
-- reply back with error flag and exception code
@@ -425,6 +443,7 @@ function modbus.reply__neg_ack(packet)
end
-- return a GATEWAY_PATH_UNAVAILABLE error reply
---@param packet modbus_frame MODBUS packet frame
---@return modbus_packet reply
function modbus.reply__gw_unavailable(packet)
-- reply back with error flag and exception code

View File

@@ -1,15 +1,12 @@
local comms = require("scada-common.comms")
local ppm = require("scada-common.ppm")
local log = require("scada-common.log")
local types = require("scada-common.types")
local util = require("scada-common.util")
local comms = require("scada-common.comms")
local ppm = require("scada-common.ppm")
local log = require("scada-common.log")
local util = require("scada-common.util")
local modbus = require("rtu.modbus")
local rtu = {}
local rtu_t = types.rtu_t
local PROTOCOLS = comms.PROTOCOLS
local SCADA_MGMT_TYPES = comms.SCADA_MGMT_TYPES
local RTU_UNIT_TYPES = comms.RTU_UNIT_TYPES
@@ -333,6 +330,7 @@ function rtu.comms(version, modem, local_port, server_port, conn_watchdog)
if protocol == PROTOCOLS.MODBUS_TCP then
local return_code = false
---@diagnostic disable-next-line: param-type-mismatch
local reply = modbus.reply__neg_ack(packet)
-- handle MODBUS instruction
@@ -342,17 +340,20 @@ function rtu.comms(version, modem, local_port, server_port, conn_watchdog)
if unit.name == "redstone_io" then
-- immediately execute redstone RTU requests
---@diagnostic disable-next-line: param-type-mismatch
return_code, reply = unit.modbus_io.handle_packet(packet)
if not return_code then
log.warning("requested MODBUS operation failed" .. unit_dbg_tag)
end
else
-- check validity then pass off to unit comms thread
---@diagnostic disable-next-line: param-type-mismatch
return_code, reply = unit.modbus_io.check_request(packet)
if return_code then
-- check if there are more than 3 active transactions
-- still queue the packet, but this may indicate a problem
if unit.pkt_queue.length() > 3 then
---@diagnostic disable-next-line: param-type-mismatch
reply = modbus.reply__srv_device_busy(packet)
log.debug("queueing new request with " .. unit.pkt_queue.length() ..
" transactions already in the queue" .. unit_dbg_tag)
@@ -366,6 +367,7 @@ function rtu.comms(version, modem, local_port, server_port, conn_watchdog)
end
else
-- unit ID out of range?
---@diagnostic disable-next-line: param-type-mismatch
reply = modbus.reply__gw_unavailable(packet)
log.error("received MODBUS packet for non-existent unit")
end

View File

@@ -4,28 +4,27 @@
require("/initenv").init_env()
local log = require("scada-common.log")
local mqueue = require("scada-common.mqueue")
local ppm = require("scada-common.ppm")
local rsio = require("scada-common.rsio")
local types = require("scada-common.types")
local util = require("scada-common.util")
local log = require("scada-common.log")
local mqueue = require("scada-common.mqueue")
local ppm = require("scada-common.ppm")
local rsio = require("scada-common.rsio")
local types = require("scada-common.types")
local util = require("scada-common.util")
local config = require("rtu.config")
local modbus = require("rtu.modbus")
local rtu = require("rtu.rtu")
local threads = require("rtu.threads")
local config = require("rtu.config")
local modbus = require("rtu.modbus")
local rtu = require("rtu.rtu")
local threads = require("rtu.threads")
local redstone_rtu = require("rtu.dev.redstone_rtu")
local boiler_rtu = require("rtu.dev.boiler_rtu")
local boilerv_rtu = require("rtu.dev.boilerv_rtu")
local energymachine_rtu = require("rtu.dev.energymachine_rtu")
local envd_rtu = require("rtu.dev.envd_rtu")
local imatrix_rtu = require("rtu.dev.imatrix_rtu")
local turbine_rtu = require("rtu.dev.turbine_rtu")
local turbinev_rtu = require("rtu.dev.turbinev_rtu")
local boilerv_rtu = require("rtu.dev.boilerv_rtu")
local envd_rtu = require("rtu.dev.envd_rtu")
local imatrix_rtu = require("rtu.dev.imatrix_rtu")
local redstone_rtu = require("rtu.dev.redstone_rtu")
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 = "beta-v0.7.12"
local RTU_VERSION = "beta-v0.8.0"
local rtu_t = types.rtu_t
@@ -219,9 +218,9 @@ local function configure()
index = entry_idx,
reactor = io_reactor,
device = capabilities, -- use device field for redstone channels
rtu = rs_rtu,
rtu = rs_rtu, ---@type rtu_device|rtu_rs_device
modbus_io = modbus.new(rs_rtu, false),
pkt_queue = nil,
pkt_queue = nil, ---@type mqueue|nil
thread = nil
}
@@ -267,31 +266,26 @@ local function configure()
local rtu_iface = nil ---@type rtu_device
local rtu_type = ""
if type == "boiler" then
if type == "boilerValve" then
-- boiler multiblock
rtu_type = rtu_t.boiler
rtu_iface = boiler_rtu.new(device)
elseif type == "boilerValve" then
-- boiler multiblock (10.1+)
rtu_type = rtu_t.boiler_valve
rtu_iface = boilerv_rtu.new(device)
elseif type == "turbine" then
-- turbine multiblock
rtu_type = rtu_t.turbine
rtu_iface = turbine_rtu.new(device)
elseif type == "turbineValve" then
-- turbine multiblock (10.1+)
-- turbine multiblock
rtu_type = rtu_t.turbine_valve
rtu_iface = turbinev_rtu.new(device)
elseif type == "mekanismMachine" then
-- assumed to be an induction matrix multiblock, pre Mekanism 10.1
-- also works with energy cubes
rtu_type = rtu_t.energy_machine
rtu_iface = energymachine_rtu.new(device)
elseif type == "inductionPort" then
-- induction matrix multiblock (10.1+)
-- induction matrix multiblock
rtu_type = rtu_t.induction_matrix
rtu_iface = imatrix_rtu.new(device)
elseif type == "spsPort" then
-- SPS multiblock
rtu_type = rtu_t.sps
rtu_iface = sps_rtu.new(device)
elseif type == "solarNeutronActivator" then
-- SNA
rtu_type = rtu_t.sps
rtu_iface = sna_rtu.new(device)
elseif type == "environmentDetector" then
-- advanced peripherals environment detector
rtu_type = rtu_t.env_detector
@@ -311,9 +305,9 @@ local function configure()
index = index,
reactor = for_reactor,
device = device,
rtu = rtu_iface,
rtu = rtu_iface, ---@type rtu_device|rtu_rs_device
modbus_io = modbus.new(rtu_iface, true),
pkt_queue = mqueue.new(),
pkt_queue = mqueue.new(), ---@type mqueue|nil
thread = nil
}

View File

@@ -1,15 +1,12 @@
local log = require("scada-common.log")
local mqueue = require("scada-common.mqueue")
local ppm = require("scada-common.ppm")
local types = require("scada-common.types")
local util = require("scada-common.util")
local log = require("scada-common.log")
local mqueue = require("scada-common.mqueue")
local ppm = require("scada-common.ppm")
local types = require("scada-common.types")
local util = require("scada-common.util")
local boiler_rtu = require("rtu.dev.boiler_rtu")
local boilerv_rtu = require("rtu.dev.boilerv_rtu")
local energymachine_rtu = require("rtu.dev.energymachine_rtu")
local imatrix_rtu = require("rtu.dev.imatrix_rtu")
local turbine_rtu = require("rtu.dev.turbine_rtu")
local turbinev_rtu = require("rtu.dev.turbinev_rtu")
local boilerv_rtu = require("rtu.dev.boilerv_rtu")
local imatrix_rtu = require("rtu.dev.imatrix_rtu")
local turbinev_rtu = require("rtu.dev.turbinev_rtu")
local modbus = require("rtu.modbus")
@@ -124,16 +121,10 @@ function threads.thread__main(smem)
-- found, re-link
unit.device = device
if unit.type == rtu_t.boiler then
unit.rtu = boiler_rtu.new(device)
elseif unit.type == rtu_t.boiler_valve then
if unit.type == rtu_t.boiler_valve then
unit.rtu = boilerv_rtu.new(device)
elseif unit.type == rtu_t.turbine then
unit.rtu = turbine_rtu.new(device)
elseif unit.type == rtu_t.turbine_valve then
unit.rtu = turbinev_rtu.new(device)
elseif unit.type == rtu_t.energy_machine then
unit.rtu = energymachine_rtu.new(device)
elseif unit.type == rtu_t.induction_matrix then
unit.rtu = imatrix_rtu.new(device)
end
@@ -163,7 +154,7 @@ function threads.thread__main(smem)
while not rtu_state.shutdown do
local status, result = pcall(public.exec)
if status == false then
log.fatal(result)
log.fatal(util.strval(result))
end
if not rtu_state.shutdown then
@@ -235,7 +226,7 @@ function threads.thread__comms(smem)
while not rtu_state.shutdown do
local status, result = pcall(public.exec)
if status == false then
log.fatal(result)
log.fatal(util.strval(result))
end
if not rtu_state.shutdown then
@@ -265,6 +256,11 @@ function threads.thread__unit_comms(smem, unit)
local last_update = util.time()
if packet_queue == nil then
log.error("rtu unit thread created without a message queue, exiting...", true)
return
end
-- thread loop
while true do
-- check for messages in the message queue
@@ -305,7 +301,7 @@ function threads.thread__unit_comms(smem, unit)
while not rtu_state.shutdown do
local status, result = pcall(public.exec)
if status == false then
log.fatal(result)
log.fatal(util.strval(result))
end
if not rtu_state.shutdown then