#118 RTU/PLC code cleanup

This commit is contained in:
Mikayla Fischler
2023-02-21 23:50:43 -05:00
parent ce0198f389
commit 79494f0587
14 changed files with 222 additions and 208 deletions

View File

@@ -3,6 +3,7 @@ local rtu = require("rtu.rtu")
local boilerv_rtu = {}
-- create new boiler (mek 10.1+) device
---@nodiscard
---@param boiler table
function boilerv_rtu.new(boiler)
local unit = rtu.init_unit()

View File

@@ -3,6 +3,7 @@ local rtu = require("rtu.rtu")
local envd_rtu = {}
-- create new environment detector device
---@nodiscard
---@param envd table
function envd_rtu.new(envd)
local unit = rtu.init_unit()

View File

@@ -3,6 +3,7 @@ local rtu = require("rtu.rtu")
local imatrix_rtu = {}
-- create new induction matrix (mek 10.1+) device
---@nodiscard
---@param imatrix table
function imatrix_rtu.new(imatrix)
local unit = rtu.init_unit()

View File

@@ -1,7 +1,7 @@
local rtu = require("rtu.rtu")
local rsio = require("scada-common.rsio")
local rtu = require("rtu.rtu")
local redstone_rtu = {}
local IO_LVL = rsio.IO_LVL
@@ -10,14 +10,15 @@ local digital_read = rsio.digital_read
local digital_write = rsio.digital_write
-- create new redstone device
---@nodiscard
function redstone_rtu.new()
local unit = rtu.init_unit()
-- get RTU interface
local interface = unit.interface()
-- extends rtu_device; fields added manually to please Lua diagnostics
---@class rtu_rs_device
--- extends rtu_device; fields added manually to please Lua diagnostics
local public = {
io_count = interface.io_count,
read_coil = interface.read_coil,

View File

@@ -2,7 +2,8 @@ local rtu = require("rtu.rtu")
local sna_rtu = {}
-- create new solar neutron activator (sna) device
-- create new solar neutron activator (SNA) device
---@nodiscard
---@param sna table
function sna_rtu.new(sna)
local unit = rtu.init_unit()

View File

@@ -2,7 +2,8 @@ local rtu = require("rtu.rtu")
local sps_rtu = {}
-- create new super-critical phase shifter (sps) device
-- create new super-critical phase shifter (SPS) device
---@nodiscard
---@param sps table
function sps_rtu.new(sps)
local unit = rtu.init_unit()

View File

@@ -3,6 +3,7 @@ local rtu = require("rtu.rtu")
local turbinev_rtu = {}
-- create new turbine (mek 10.1+) device
---@nodiscard
---@param turbine table
function turbinev_rtu.new(turbine)
local unit = rtu.init_unit()

View File

@@ -7,22 +7,15 @@ local MODBUS_FCODE = types.MODBUS_FCODE
local MODBUS_EXCODE = types.MODBUS_EXCODE
-- new modbus comms handler object
---@nodiscard
---@param rtu_dev rtu_device|rtu_rs_device RTU device
---@param use_parallel_read boolean whether or not to use parallel calls when reading
function modbus.new(rtu_dev, use_parallel_read)
local self = {
rtu = rtu_dev,
use_parallel = use_parallel_read
}
---@class modbus
local public = {}
local insert = table.insert
-- read a span of coils (digital outputs)
--
-- read a span of coils (digital outputs)<br>
-- returns a table of readings or a MODBUS_EXCODE error code
---@nodiscard
---@param c_addr_start integer
---@param count integer
---@return boolean ok, table|MODBUS_EXCODE readings
@@ -30,20 +23,20 @@ function modbus.new(rtu_dev, use_parallel_read)
local tasks = {}
local readings = {} ---@type table|MODBUS_EXCODE
local access_fault = false
local _, coils, _, _ = self.rtu.io_count()
local _, coils, _, _ = rtu_dev.io_count()
local return_ok = ((c_addr_start + count) <= (coils + 1)) and (count > 0)
if return_ok then
for i = 1, count do
local addr = c_addr_start + i - 1
if self.use_parallel then
if use_parallel_read then
insert(tasks, function ()
local reading, fault = self.rtu.read_coil(addr)
local reading, fault = rtu_dev.read_coil(addr)
if fault then access_fault = true else readings[i] = reading end
end)
else
readings[i], access_fault = self.rtu.read_coil(addr)
readings[i], access_fault = rtu_dev.read_coil(addr)
if access_fault then
return_ok = false
@@ -54,7 +47,7 @@ function modbus.new(rtu_dev, use_parallel_read)
end
-- run parallel tasks if configured
if self.use_parallel then
if use_parallel_read then
parallel.waitForAll(table.unpack(tasks))
end
@@ -69,9 +62,9 @@ function modbus.new(rtu_dev, use_parallel_read)
return return_ok, readings
end
-- read a span of discrete inputs (digital inputs)
--
-- read a span of discrete inputs (digital inputs)<br>
-- returns a table of readings or a MODBUS_EXCODE error code
---@nodiscard
---@param di_addr_start integer
---@param count integer
---@return boolean ok, table|MODBUS_EXCODE readings
@@ -79,20 +72,20 @@ function modbus.new(rtu_dev, use_parallel_read)
local tasks = {}
local readings = {} ---@type table|MODBUS_EXCODE
local access_fault = false
local discrete_inputs, _, _, _ = self.rtu.io_count()
local discrete_inputs, _, _, _ = rtu_dev.io_count()
local return_ok = ((di_addr_start + count) <= (discrete_inputs + 1)) and (count > 0)
if return_ok then
for i = 1, count do
local addr = di_addr_start + i - 1
if self.use_parallel then
if use_parallel_read then
insert(tasks, function ()
local reading, fault = self.rtu.read_di(addr)
local reading, fault = rtu_dev.read_di(addr)
if fault then access_fault = true else readings[i] = reading end
end)
else
readings[i], access_fault = self.rtu.read_di(addr)
readings[i], access_fault = rtu_dev.read_di(addr)
if access_fault then
return_ok = false
@@ -103,7 +96,7 @@ function modbus.new(rtu_dev, use_parallel_read)
end
-- run parallel tasks if configured
if self.use_parallel then
if use_parallel_read then
parallel.waitForAll(table.unpack(tasks))
end
@@ -118,9 +111,9 @@ function modbus.new(rtu_dev, use_parallel_read)
return return_ok, readings
end
-- read a span of holding registers (analog outputs)
--
-- read a span of holding registers (analog outputs)<br>
-- returns a table of readings or a MODBUS_EXCODE error code
---@nodiscard
---@param hr_addr_start integer
---@param count integer
---@return boolean ok, table|MODBUS_EXCODE readings
@@ -128,20 +121,20 @@ function modbus.new(rtu_dev, use_parallel_read)
local tasks = {}
local readings = {} ---@type table|MODBUS_EXCODE
local access_fault = false
local _, _, _, hold_regs = self.rtu.io_count()
local _, _, _, hold_regs = rtu_dev.io_count()
local return_ok = ((hr_addr_start + count) <= (hold_regs + 1)) and (count > 0)
if return_ok then
for i = 1, count do
local addr = hr_addr_start + i - 1
if self.use_parallel then
if use_parallel_read then
insert(tasks, function ()
local reading, fault = self.rtu.read_holding_reg(addr)
local reading, fault = rtu_dev.read_holding_reg(addr)
if fault then access_fault = true else readings[i] = reading end
end)
else
readings[i], access_fault = self.rtu.read_holding_reg(addr)
readings[i], access_fault = rtu_dev.read_holding_reg(addr)
if access_fault then
return_ok = false
@@ -152,7 +145,7 @@ function modbus.new(rtu_dev, use_parallel_read)
end
-- run parallel tasks if configured
if self.use_parallel then
if use_parallel_read then
parallel.waitForAll(table.unpack(tasks))
end
@@ -167,9 +160,9 @@ function modbus.new(rtu_dev, use_parallel_read)
return return_ok, readings
end
-- read a span of input registers (analog inputs)
--
-- read a span of input registers (analog inputs)<br>
-- returns a table of readings or a MODBUS_EXCODE error code
---@nodiscard
---@param ir_addr_start integer
---@param count integer
---@return boolean ok, table|MODBUS_EXCODE readings
@@ -177,20 +170,20 @@ function modbus.new(rtu_dev, use_parallel_read)
local tasks = {}
local readings = {} ---@type table|MODBUS_EXCODE
local access_fault = false
local _, _, input_regs, _ = self.rtu.io_count()
local _, _, input_regs, _ = rtu_dev.io_count()
local return_ok = ((ir_addr_start + count) <= (input_regs + 1)) and (count > 0)
if return_ok then
for i = 1, count do
local addr = ir_addr_start + i - 1
if self.use_parallel then
if use_parallel_read then
insert(tasks, function ()
local reading, fault = self.rtu.read_input_reg(addr)
local reading, fault = rtu_dev.read_input_reg(addr)
if fault then access_fault = true else readings[i] = reading end
end)
else
readings[i], access_fault = self.rtu.read_input_reg(addr)
readings[i], access_fault = rtu_dev.read_input_reg(addr)
if access_fault then
return_ok = false
@@ -201,7 +194,7 @@ function modbus.new(rtu_dev, use_parallel_read)
end
-- run parallel tasks if configured
if self.use_parallel then
if use_parallel_read then
parallel.waitForAll(table.unpack(tasks))
end
@@ -217,16 +210,17 @@ function modbus.new(rtu_dev, use_parallel_read)
end
-- write a single coil (digital output)
---@nodiscard
---@param c_addr integer
---@param value any
---@return boolean ok, MODBUS_EXCODE
local function _5_write_single_coil(c_addr, value)
local response = nil
local _, coils, _, _ = self.rtu.io_count()
local _, coils, _, _ = rtu_dev.io_count()
local return_ok = c_addr <= coils
if return_ok then
local access_fault = self.rtu.write_coil(c_addr, value)
local access_fault = rtu_dev.write_coil(c_addr, value)
if access_fault then
return_ok = false
@@ -240,16 +234,17 @@ function modbus.new(rtu_dev, use_parallel_read)
end
-- write a single holding register (analog output)
---@nodiscard
---@param hr_addr integer
---@param value any
---@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()
local _, _, _, hold_regs = rtu_dev.io_count()
local return_ok = hr_addr <= hold_regs
if return_ok then
local access_fault = self.rtu.write_holding_reg(hr_addr, value)
local access_fault = rtu_dev.write_holding_reg(hr_addr, value)
if access_fault then
return_ok = false
@@ -263,19 +258,20 @@ function modbus.new(rtu_dev, use_parallel_read)
end
-- write multiple coils (digital outputs)
---@nodiscard
---@param c_addr_start integer
---@param values any
---@return boolean ok, MODBUS_EXCODE
local function _15_write_multiple_coils(c_addr_start, values)
local response = nil
local _, coils, _, _ = self.rtu.io_count()
local _, coils, _, _ = rtu_dev.io_count()
local count = #values
local return_ok = ((c_addr_start + count) <= (coils + 1)) and (count > 0)
if return_ok then
for i = 1, count do
local addr = c_addr_start + i - 1
local access_fault = self.rtu.write_coil(addr, values[i])
local access_fault = rtu_dev.write_coil(addr, values[i])
if access_fault then
return_ok = false
@@ -291,19 +287,20 @@ function modbus.new(rtu_dev, use_parallel_read)
end
-- write multiple holding registers (analog outputs)
---@nodiscard
---@param hr_addr_start integer
---@param values any
---@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()
local _, _, _, hold_regs = rtu_dev.io_count()
local count = #values
local return_ok = ((hr_addr_start + count) <= (hold_regs + 1)) and (count > 0)
if return_ok then
for i = 1, count do
local addr = hr_addr_start + i - 1
local access_fault = self.rtu.write_holding_reg(addr, values[i])
local access_fault = rtu_dev.write_holding_reg(addr, values[i])
if access_fault then
return_ok = false
@@ -318,7 +315,11 @@ function modbus.new(rtu_dev, use_parallel_read)
return return_ok, response
end
---@class modbus
local public = {}
-- validate a request without actually executing it
---@nodiscard
---@param packet modbus_frame
---@return boolean return_code, modbus_packet reply
function public.check_request(packet)
@@ -360,6 +361,7 @@ function modbus.new(rtu_dev, use_parallel_read)
end
-- handle a MODBUS TCP packet and generate a reply
---@nodiscard
---@param packet modbus_frame
---@return boolean return_code, modbus_packet reply
function public.handle_packet(packet)
@@ -420,6 +422,7 @@ function modbus.new(rtu_dev, use_parallel_read)
end
-- return a SERVER_DEVICE_BUSY error reply
---@nodiscard
---@param packet modbus_frame MODBUS packet frame
---@return modbus_packet reply
function modbus.reply__srv_device_busy(packet)
@@ -432,6 +435,7 @@ function modbus.reply__srv_device_busy(packet)
end
-- return a NEG_ACKNOWLEDGE error reply
---@nodiscard
---@param packet modbus_frame MODBUS packet frame
---@return modbus_packet reply
function modbus.reply__neg_ack(packet)
@@ -444,6 +448,7 @@ function modbus.reply__neg_ack(packet)
end
-- return a GATEWAY_PATH_UNAVAILABLE error reply
---@nodiscard
---@param packet modbus_frame MODBUS packet frame
---@return modbus_packet reply
function modbus.reply__gw_unavailable(packet)

View File

@@ -19,7 +19,8 @@ local println = util.println
local print_ts = util.print_ts
local println_ts = util.println_ts
-- create a new RTU
-- create a new RTU unit
---@nodiscard
function rtu.init_unit()
local self = {
discrete_inputs = {},
@@ -153,14 +154,13 @@ function rtu.init_unit()
-- public RTU device access
-- get the public interface to this RTU
function protected.interface()
return public
end
function protected.interface() return public end
return protected
end
-- RTU Communications
---@nodiscard
---@param version string RTU version
---@param modem table modem device
---@param local_port integer local listening port
@@ -169,20 +169,12 @@ end
---@param conn_watchdog watchdog watchdog reference
function rtu.comms(version, modem, local_port, server_port, range, conn_watchdog)
local self = {
version = version,
seq_num = 0,
r_seq_num = nil,
txn_id = 0,
modem = modem,
s_port = server_port,
l_port = local_port,
conn_watchdog = conn_watchdog,
last_est_ack = ESTABLISH_ACK.ALLOW
}
---@class rtu_comms
local public = {}
local insert = table.insert
comms.set_trusted_range(range)
@@ -191,8 +183,8 @@ function rtu.comms(version, modem, local_port, server_port, range, conn_watchdog
-- configure modem channels
local function _conf_channels()
self.modem.closeAll()
self.modem.open(self.l_port)
modem.closeAll()
modem.open(local_port)
end
_conf_channels()
@@ -207,7 +199,7 @@ function rtu.comms(version, modem, local_port, server_port, range, conn_watchdog
m_pkt.make(msg_type, msg)
s_pkt.make(self.seq_num, PROTOCOL.SCADA_MGMT, m_pkt.raw_sendable())
self.modem.transmit(self.s_port, self.l_port, s_pkt.raw_sendable())
modem.transmit(server_port, local_port, s_pkt.raw_sendable())
self.seq_num = self.seq_num + 1
end
@@ -218,6 +210,7 @@ function rtu.comms(version, modem, local_port, server_port, range, conn_watchdog
end
-- generate device advertisement table
---@nodiscard
---@param units table
---@return table advertisement
local function _generate_advertisement(units)
@@ -227,11 +220,7 @@ function rtu.comms(version, modem, local_port, server_port, range, conn_watchdog
local unit = units[i] ---@type rtu_unit_registry_entry
if type ~= nil then
local advert = {
unit.type,
unit.index,
unit.reactor
}
local advert = { unit.type, unit.index, unit.reactor }
if type == RTU_UNIT_TYPE.REDSTONE then
insert(advert, unit.device)
@@ -246,20 +235,22 @@ function rtu.comms(version, modem, local_port, server_port, range, conn_watchdog
-- PUBLIC FUNCTIONS --
---@class rtu_comms
local public = {}
-- send a MODBUS TCP packet
---@param m_pkt modbus_packet
function public.send_modbus(m_pkt)
local s_pkt = comms.scada_packet()
s_pkt.make(self.seq_num, PROTOCOL.MODBUS_TCP, m_pkt.raw_sendable())
self.modem.transmit(self.s_port, self.l_port, s_pkt.raw_sendable())
modem.transmit(server_port, local_port, s_pkt.raw_sendable())
self.seq_num = self.seq_num + 1
end
-- reconnect a newly connected modem
---@param modem table
---@diagnostic disable-next-line: redefined-local
function public.reconnect_modem(modem)
self.modem = modem
---@param new_modem table
function public.reconnect_modem(new_modem)
modem = new_modem
_conf_channels()
end
@@ -273,7 +264,7 @@ function rtu.comms(version, modem, local_port, server_port, range, conn_watchdog
-- close the connection to the server
---@param rtu_state rtu_state
function public.close(rtu_state)
self.conn_watchdog.cancel()
conn_watchdog.cancel()
public.unlink(rtu_state)
_send(SCADA_MGMT_TYPE.CLOSE, {})
end
@@ -281,7 +272,7 @@ function rtu.comms(version, modem, local_port, server_port, range, conn_watchdog
-- send establish request (includes advertisement)
---@param units table
function public.send_establish(units)
_send(SCADA_MGMT_TYPE.ESTABLISH, { comms.version, self.version, DEVICE_TYPE.RTU, _generate_advertisement(units) })
_send(SCADA_MGMT_TYPE.ESTABLISH, { comms.version, version, DEVICE_TYPE.RTU, _generate_advertisement(units) })
end
-- send capability advertisement
@@ -297,6 +288,7 @@ function rtu.comms(version, modem, local_port, server_port, range, conn_watchdog
end
-- parse a MODBUS/SCADA packet
---@nodiscard
---@param side string
---@param sender integer
---@param reply_to integer
@@ -333,10 +325,10 @@ function rtu.comms(version, modem, local_port, server_port, range, conn_watchdog
-- handle a MODBUS/SCADA packet
---@param packet modbus_frame|mgmt_frame
---@param units table
---@param units table RTU units
---@param rtu_state rtu_state
function public.handle_packet(packet, units, rtu_state)
if packet ~= nil and packet.scada_frame.local_port() == self.l_port then
if packet.scada_frame.local_port() == local_port then
-- check sequence number
if self.r_seq_num == nil then
self.r_seq_num = packet.scada_frame.seq_num()
@@ -348,14 +340,14 @@ function rtu.comms(version, modem, local_port, server_port, range, conn_watchdog
end
-- feed watchdog on valid sequence number
self.conn_watchdog.feed()
conn_watchdog.feed()
local protocol = packet.scada_frame.protocol()
if protocol == PROTOCOL.MODBUS_TCP then
---@cast packet modbus_frame
if rtu_state.linked then
local return_code = false
---@diagnostic disable-next-line: param-type-mismatch
local reply = modbus.reply__neg_ack(packet)
-- handle MODBUS instruction
@@ -365,20 +357,17 @@ function rtu.comms(version, modem, local_port, server_port, range, 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)
@@ -392,7 +381,6 @@ function rtu.comms(version, modem, local_port, server_port, range, 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
@@ -402,6 +390,7 @@ function rtu.comms(version, modem, local_port, server_port, range, conn_watchdog
log.debug("discarding MODBUS packet before linked")
end
elseif protocol == PROTOCOL.SCADA_MGMT then
---@cast packet mgmt_frame
-- SCADA management packet
if packet.type == SCADA_MGMT_TYPE.ESTABLISH then
if packet.length == 1 then
@@ -419,10 +408,10 @@ function rtu.comms(version, modem, local_port, server_port, range, conn_watchdog
if est_ack == ESTABLISH_ACK.BAD_VERSION then
-- version mismatch
println_ts("supervisor comms version mismatch (try updating), retrying...")
log.warning("supervisor connection denied due to comms version mismatch")
log.warning("supervisor connection denied due to comms version mismatch, retrying")
else
println_ts("supervisor connection denied, retrying...")
log.warning("supervisor connection denied")
log.warning("supervisor connection denied, retrying")
end
end
@@ -452,13 +441,13 @@ function rtu.comms(version, modem, local_port, server_port, range, conn_watchdog
end
elseif packet.type == SCADA_MGMT_TYPE.CLOSE then
-- close connection
self.conn_watchdog.cancel()
conn_watchdog.cancel()
public.unlink(rtu_state)
println_ts("server connection closed by remote host")
log.warning("server connection closed by remote host")
elseif packet.type == SCADA_MGMT_TYPE.RTU_ADVERT then
-- request for capabilities again
public.send_advertisement(units)
public.send_advertisement(units)
else
-- not supported
log.warning("received unsupported SCADA_MGMT message type " .. packet.type)

View File

@@ -25,7 +25,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 = "beta-v0.11.2"
local RTU_VERSION = "v0.12.0"
local RTU_UNIT_TYPE = types.RTU_UNIT_TYPE
@@ -132,13 +132,17 @@ local function main()
-- CHECK: reactor ID must be >= to 1
if (not util.is_int(io_reactor)) or (io_reactor < 0) then
println(util.c("configure> redstone entry #", entry_idx, " : ", io_reactor, " isn't an integer >= 0"))
local message = util.c("configure> redstone entry #", entry_idx, " : ", io_reactor, " isn't an integer >= 0")
println(message)
log.fatal(message)
return false
end
-- CHECK: io table exists
if type(io_table) ~= "table" then
println(util.c("configure> redstone entry #", entry_idx, " no IO table found"))
local message = util.c("configure> redstone entry #", entry_idx, " no IO table found")
println(message)
log.fatal(message)
return false
end
@@ -148,7 +152,7 @@ local function main()
local continue = true
-- check for duplicate entries
-- CHECK: no duplicate entries
for i = 1, #units do
local unit = units[i] ---@type rtu_unit_registry_entry
if unit.reactor == io_reactor and unit.type == RTU_UNIT_TYPE.REDSTONE then
@@ -181,7 +185,7 @@ local function main()
local message = util.c("configure> invalid redstone definition at index ", i, " in definition block #", entry_idx,
" (for reactor ", io_reactor, ")")
println(message)
log.error(message)
log.fatal(message)
return false
else
-- link redstone in RTU
@@ -245,7 +249,7 @@ local function main()
for_message = util.c("reactor ", io_reactor)
end
log.debug(util.c("configure> initialized RTU unit #", #units, ": redstone_io (redstone) [1] for ", for_message))
log.info(util.c("configure> initialized RTU unit #", #units, ": redstone_io (redstone) [1] for ", for_message))
unit.uid = #units
end
@@ -259,25 +263,31 @@ local function main()
-- CHECK: name is a string
if type(name) ~= "string" then
println(util.c("configure> device entry #", i, ": device ", name, " isn't a string"))
local message = util.c("configure> device entry #", i, ": device ", name, " isn't a string")
println(message)
log.fatal(message)
return false
end
-- CHECK: index is an integer >= 1
if (not util.is_int(index)) or (index <= 0) then
println(util.c("configure> device entry #", i, ": index ", index, " isn't an integer >= 1"))
local message = util.c("configure> device entry #", i, ": index ", index, " isn't an integer >= 1")
println(message)
log.fatal(message)
return false
end
-- CHECK: reactor is an integer >= 0
if (not util.is_int(for_reactor)) or (for_reactor < 0) then
println(util.c("configure> device entry #", i, ": reactor ", for_reactor, " isn't an integer >= 0"))
local message = util.c("configure> device entry #", i, ": reactor ", for_reactor, " isn't an integer >= 0")
println(message)
log.fatal(message)
return false
end
local device = ppm.get_periph(name)
local type = nil
local type = nil ---@type string|nil
local rtu_iface = nil ---@type rtu_device
local rtu_type = nil ---@type RTU_UNIT_TYPE
local is_multiblock = false
@@ -382,7 +392,7 @@ local function main()
table.insert(units, rtu_unit)
if is_multiblock and not formed then
log.debug(util.c("configure> device '", name, "' is not formed"))
log.info(util.c("configure> device '", name, "' is not formed"))
end
local for_message = "facility"
@@ -390,7 +400,7 @@ local function main()
for_message = util.c("reactor ", for_reactor)
end
log.debug(util.c("configure> initialized RTU unit #", #units, ": ", name, " (", types.rtu_type_to_string(rtu_type), ") [", index, "] for ", for_message))
log.info(util.c("configure> initialized RTU unit #", #units, ": ", name, " (", types.rtu_type_to_string(rtu_type), ") [", index, "] for ", for_message))
rtu_unit.uid = #units
end
@@ -408,12 +418,12 @@ local function main()
if configure() then
-- start connection watchdog
smem_sys.conn_watchdog = util.new_watchdog(config.COMMS_TIMEOUT)
log.debug("boot> conn watchdog started")
log.debug("startup> conn watchdog started")
-- setup comms
smem_sys.rtu_comms = rtu.comms(RTU_VERSION, smem_dev.modem, config.LISTEN_PORT, config.SERVER_PORT,
config.TRUSTED_RANGE, smem_sys.conn_watchdog)
log.debug("boot> comms init")
log.debug("startup> comms init")
-- init threads
local main_thread = threads.thread__main(__shared_memory)
@@ -427,6 +437,8 @@ local function main()
end
end
log.info("startup> completed")
-- run threads
parallel.waitForAll(table.unpack(_threads))
else

View File

@@ -1,17 +1,17 @@
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 boilerv_rtu = require("rtu.dev.boilerv_rtu")
local envd_rtu = require("rtu.dev.envd_rtu")
local imatrix_rtu = require("rtu.dev.imatrix_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 boilerv_rtu = require("rtu.dev.boilerv_rtu")
local envd_rtu = require("rtu.dev.envd_rtu")
local imatrix_rtu = require("rtu.dev.imatrix_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 modbus = require("rtu.modbus")
local modbus = require("rtu.modbus")
local threads = {}
@@ -26,6 +26,7 @@ local MAIN_CLOCK = 2 -- (2Hz, 40 ticks)
local COMMS_SLEEP = 100 -- (100ms, 2 ticks)
-- main thread
---@nodiscard
---@param smem rtu_shared_memory
function threads.thread__main(smem)
---@class parallel_thread
@@ -114,9 +115,9 @@ function threads.thread__main(smem)
rtu_comms.reconnect_modem(rtu_dev.modem)
println_ts("wireless modem reconnected.")
log.info("comms modem reconnected.")
log.info("comms modem reconnected")
else
log.info("wired modem reconnected.")
log.info("wired modem reconnected")
end
else
-- relink lost peripheral to correct unit entry
@@ -233,6 +234,7 @@ function threads.thread__main(smem)
end
-- communications handler thread
---@nodiscard
---@param smem rtu_shared_memory
function threads.thread__comms(smem)
---@class parallel_thread
@@ -243,13 +245,13 @@ function threads.thread__comms(smem)
log.debug("comms thread start")
-- load in from shared memory
local rtu_state = smem.rtu_state
local rtu_comms = smem.rtu_sys.rtu_comms
local units = smem.rtu_sys.units
local rtu_state = smem.rtu_state
local rtu_comms = smem.rtu_sys.rtu_comms
local units = smem.rtu_sys.units
local comms_queue = smem.q.mq_comms
local comms_queue = smem.q.mq_comms
local last_update = util.time()
local last_update = util.time()
-- thread loop
while true do
@@ -306,6 +308,7 @@ function threads.thread__comms(smem)
end
-- per-unit communications handler thread
---@nodiscard
---@param smem rtu_shared_memory
---@param unit rtu_unit_registry_entry
function threads.thread__unit_comms(smem, unit)