#33 lua module/require architecture changeover

This commit is contained in:
Mikayla Fischler
2022-05-04 13:37:01 -04:00
parent 7bcb260712
commit b575899d46
33 changed files with 679 additions and 518 deletions

View File

@@ -1,47 +1,49 @@
-- #REQUIRES rsio.lua
local rsio = require("scada-common.rsio")
local config = {}
-- port to send packets TO server
SERVER_PORT = 16000
config.SERVER_PORT = 16000
-- port to listen to incoming packets FROM server
LISTEN_PORT = 15001
config.LISTEN_PORT = 15001
-- log path
LOG_PATH = "/log.txt"
config.LOG_PATH = "/log.txt"
-- log mode
-- 0 = APPEND (adds to existing file on start)
-- 1 = NEW (replaces existing file on start)
LOG_MODE = 0
config.LOG_MODE = 0
-- RTU peripheral devices (named: side/network device name)
RTU_DEVICES = {
config.RTU_DEVICES = {
{
name = "boiler_0",
name = "boiler_1",
index = 1,
for_reactor = 1
},
{
name = "turbine_0",
name = "turbine_1",
index = 1,
for_reactor = 1
}
}
-- RTU redstone interface definitions
RTU_REDSTONE = {
config.RTU_REDSTONE = {
{
for_reactor = 1,
io = {
{
channel = rsio.RS_IO.WASTE_PO,
channel = rsio.IO.WASTE_PO,
side = "top",
bundled_color = colors.blue,
for_reactor = 1
},
{
channel = rsio.RS_IO.WASTE_PU,
channel = rsio.IO.WASTE_PU,
side = "top",
bundled_color = colors.cyan,
for_reactor = 1
},
{
channel = rsio.RS_IO.WASTE_AM,
channel = rsio.IO.WASTE_AM,
side = "top",
bundled_color = colors.purple,
for_reactor = 1
@@ -49,3 +51,5 @@ RTU_REDSTONE = {
}
}
}
return config

View File

@@ -1,8 +1,10 @@
-- #REQUIRES rtu.lua
local rtu = require("rtu")
function new(boiler)
local boiler_rtu = {}
boiler_rtu.new = function (boiler)
local self = {
rtu = rtu.rtu_init(),
rtu = rtu.init_unit(),
boiler = boiler
}
@@ -49,3 +51,5 @@ function new(boiler)
rtu_interface = rtu_interface
}
end
return boiler_rtu

View File

@@ -1,8 +1,10 @@
-- #REQUIRES rtu.lua
local rtu = require("rtu")
function new(boiler)
local boilerv_rtu = {}
boilerv_rtu.new = function (boiler)
local self = {
rtu = rtu.rtu_init(),
rtu = rtu.init_unit(),
boiler = boiler
}
@@ -54,3 +56,5 @@ function new(boiler)
rtu_interface = rtu_interface
}
end
return boilerv_rtu

View File

@@ -1,8 +1,10 @@
-- #REQUIRES rtu.lua
local rtu = require("rtu")
function new(machine)
local energymachine_rtu = {}
energymachine_rtu.new = function (machine)
local self = {
rtu = rtu.rtu_init(),
rtu = rtu.init_unit(),
machine = machine
}
@@ -31,3 +33,5 @@ function new(machine)
rtu_interface = rtu_interface
}
end
return energymachine_rtu

View File

@@ -1,8 +1,10 @@
-- #REQUIRES rtu.lua
local rtu = require("rtu")
function new(imatrix)
local imatrix_rtu = {}
imatrix_rtu.new = function (imatrix)
local self = {
rtu = rtu.rtu_init(),
rtu = rtu.init_unit(),
imatrix = imatrix
}
@@ -42,3 +44,5 @@ function new(imatrix)
rtu_interface = rtu_interface
}
end
return imatrix_rtu

View File

@@ -1,13 +1,14 @@
-- #REQUIRES rtu.lua
-- #REQUIRES rsio.lua
-- note: this RTU makes extensive use of the programming concept of closures
local rtu = require("rtu")
local rsio = require("scada-common.rsio")
local redstone_rtu = {}
local digital_read = rsio.digital_read
local digital_is_active = rsio.digital_is_active
function new()
redstone_rtu.new = function ()
local self = {
rtu = rtu.rtu_init()
rtu = rtu.init_unit()
}
local rtu_interface = function ()
@@ -91,3 +92,5 @@ function new()
link_ao = link_ao
}
end
return redstone_rtu

View File

@@ -1,8 +1,10 @@
-- #REQUIRES rtu.lua
local rtu = require("rtu")
function new(turbine)
local turbine_rtu = {}
turbine_rtu.new = function (turbine)
local self = {
rtu = rtu.rtu_init(),
rtu = rtu.init_unit(),
turbine = turbine
}
@@ -44,3 +46,5 @@ function new(turbine)
rtu_interface = rtu_interface
}
end
return turbine_rtu

View File

@@ -1,8 +1,10 @@
-- #REQUIRES rtu.lua
local rtu = require("rtu")
function new(turbine)
local turbinev_rtu = {}
turbinev_rtu.new = function (turbine)
local self = {
rtu = rtu.rtu_init(),
rtu = rtu.init_unit(),
turbine = turbine
}
@@ -14,8 +16,8 @@ function new(turbine)
-- none
-- coils --
self.rtu.connect_coil(function () self.turbine.incrementDumpingMode() end), function () end)
self.rtu.connect_coil(function () self.turbine.decrementDumpingMode() end), function () end)
self.rtu.connect_coil(function () self.turbine.incrementDumpingMode() end, function () end)
self.rtu.connect_coil(function () self.turbine.decrementDumpingMode() end, function () end)
-- input registers --
-- multiblock properties
@@ -54,3 +56,5 @@ function new(turbine)
rtu_interface = rtu_interface
}
end
return turbinev_rtu

View File

@@ -1,10 +1,13 @@
-- #REQUIRES types.lua
local comms = require("scada-common.comms")
local types = require("scada-common.types")
local modbus = {}
local MODBUS_FCODE = types.MODBUS_FCODE
local MODBUS_EXCODE = types.MODBUS_EXCODE
-- new modbus comms handler object
function new(rtu_dev, use_parallel_read)
modbus.new = function (rtu_dev, use_parallel_read)
local self = {
rtu = rtu_dev,
use_parallel = use_parallel_read
@@ -401,3 +404,5 @@ function new(rtu_dev, use_parallel_read)
reply__gw_unavailable = reply__gw_unavailable
}
end
return modbus

View File

@@ -1,12 +1,15 @@
-- #REQUIRES comms.lua
-- #REQUIRES modbus.lua
-- #REQUIRES ppm.lua
local comms = require("scada-common.comms")
local ppm = require("scada-common.ppm")
local modbus = require("modbus")
local rtu = {}
local PROTOCOLS = comms.PROTOCOLS
local SCADA_MGMT_TYPES = comms.SCADA_MGMT_TYPES
local RTU_ADVERT_TYPES = comms.RTU_ADVERT_TYPES
function rtu_init()
rtu.init_unit = function ()
local self = {
discrete_inputs = {},
coils = {},
@@ -117,7 +120,7 @@ function rtu_init()
}
end
function rtu_comms(modem, local_port, server_port)
rtu.comms = function (modem, local_port, server_port)
local self = {
seq_num = 0,
r_seq_num = nil,
@@ -187,7 +190,7 @@ function rtu_comms(modem, local_port, server_port)
pkt = mgmt_pkt.get()
end
else
log._error("illegal packet type " .. s_pkt.protocol(), true)
log.error("illegal packet type " .. s_pkt.protocol(), true)
end
end
@@ -203,7 +206,7 @@ function rtu_comms(modem, local_port, server_port)
if self.r_seq_num == nil then
self.r_seq_num = packet.scada_frame.seq_num()
elseif rtu_state.linked and self.r_seq_num >= packet.scada_frame.seq_num() then
log._warning("sequence out-of-order: last = " .. self.r_seq_num .. ", new = " .. packet.scada_frame.seq_num())
log.warning("sequence out-of-order: last = " .. self.r_seq_num .. ", new = " .. packet.scada_frame.seq_num())
return
else
self.r_seq_num = packet.scada_frame.seq_num()
@@ -224,7 +227,7 @@ function rtu_comms(modem, local_port, server_port)
-- immediately execute redstone RTU requests
local return_code, reply = unit.modbus_io.handle_packet(packet)
if not return_code then
log._warning("requested MODBUS operation failed")
log.warning("requested MODBUS operation failed")
end
else
-- check validity then pass off to unit comms thread
@@ -237,13 +240,13 @@ function rtu_comms(modem, local_port, server_port)
unit.pkt_queue.push(packet)
end
else
log._warning("cannot perform requested MODBUS operation")
log.warning("cannot perform requested MODBUS operation")
end
end
else
-- unit ID out of range?
reply = modbus.reply__gw_unavailable(packet)
log._error("MODBUS packet requesting non-existent unit")
log.error("MODBUS packet requesting non-existent unit")
end
send_modbus(reply)
@@ -253,7 +256,7 @@ function rtu_comms(modem, local_port, server_port)
-- close connection
conn_watchdog.cancel()
unlink(rtu_state)
if packet.type == SCADA_MGMT_TYPES.REMOTE_LINKED then
elseif packet.type == SCADA_MGMT_TYPES.REMOTE_LINKED then
-- acknowledgement
rtu_state.linked = true
self.r_seq_num = nil
@@ -262,11 +265,11 @@ function rtu_comms(modem, local_port, server_port)
send_advertisement(units)
else
-- not supported
log._warning("RTU got unexpected SCADA message type " .. packet.type, true)
log.warning("RTU got unexpected SCADA message type " .. packet.type, true)
end
else
-- should be unreachable assuming packet is from parse_packet()
log._error("illegal packet type " .. protocol, true)
log.error("illegal packet type " .. protocol, true)
end
end
end
@@ -337,3 +340,5 @@ function rtu_comms(modem, local_port, server_port)
close = close
}
end
return rtu

View File

@@ -2,28 +2,27 @@
-- RTU: Remote Terminal Unit
--
os.loadAPI("scada-common/log.lua")
os.loadAPI("scada-common/types.lua")
os.loadAPI("scada-common/util.lua")
os.loadAPI("scada-common/ppm.lua")
os.loadAPI("scada-common/comms.lua")
os.loadAPI("scada-common/mqueue.lua")
os.loadAPI("scada-common/rsio.lua")
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")
os.loadAPI("config.lua")
os.loadAPI("modbus.lua")
os.loadAPI("rtu.lua")
os.loadAPI("threads.lua")
local config = require("config")
local modbus = require("modbus")
local rtu = require("rtu")
local threads = require("threads")
os.loadAPI("dev/redstone_rtu.lua")
os.loadAPI("dev/boiler_rtu.lua")
os.loadAPI("dev/boilerv_rtu.lua")
os.loadAPI("dev/energymachine_rtu.lua")
os.loadAPI("dev/imatrix_rtu.lua")
os.loadAPI("dev/turbine_rtu.lua")
os.loadAPI("dev/turbinev_rtu.lua")
local redstone_rtu = require("dev.redstone_rtu")
local boiler_rtu = require("dev.boiler_rtu")
local boilerv_rtu = require("dev.boilerv_rtu")
local energymachine_rtu = require("dev.energymachine_rtu")
local imatrix_rtu = require("dev.imatrix_rtu")
local turbine_rtu = require("dev.turbine_rtu")
local turbinev_rtu = require("dev.turbinev_rtu")
local RTU_VERSION = "alpha-v0.5.0"
local RTU_VERSION = "alpha-v0.6.0"
local rtu_t = types.rtu_t
@@ -34,9 +33,9 @@ local println_ts = util.println_ts
log.init(config.LOG_PATH, config.LOG_MODE)
log._info("========================================")
log._info("BOOTING rtu.startup " .. RTU_VERSION)
log._info("========================================")
log.info("========================================")
log.info("BOOTING rtu.startup " .. RTU_VERSION)
log.info("========================================")
println(">> RTU " .. RTU_VERSION .. " <<")
----------------------------------------
@@ -77,11 +76,11 @@ local smem_sys = __shared_memory.rtu_sys
-- get modem
if smem_dev.modem == nil then
println("boot> wireless modem not found")
log._warning("no wireless modem on startup")
log.warning("no wireless modem on startup")
return
end
smem_sys.rtu_comms = rtu.rtu_comms(smem_dev.modem, config.LISTEN_PORT, config.SERVER_PORT)
smem_sys.rtu_comms = rtu.comms(smem_dev.modem, config.LISTEN_PORT, config.SERVER_PORT)
----------------------------------------
-- interpret config and init units
@@ -99,7 +98,7 @@ for reactor_idx = 1, #rtu_redstone do
local capabilities = {}
log._debug("init> starting redstone RTU I/O linking for reactor " .. rtu_redstone[reactor_idx].for_reactor .. "...")
log.debug("init> starting redstone RTU I/O linking for reactor " .. rtu_redstone[reactor_idx].for_reactor .. "...")
for i = 1, #io_table do
local valid = false
@@ -118,7 +117,7 @@ for reactor_idx = 1, #rtu_redstone do
local message = "init> invalid redstone definition at index " .. i .. " in definition block #" .. reactor_idx ..
" (for reactor " .. rtu_redstone[reactor_idx].for_reactor .. ")"
println_ts(message)
log._warning(message)
log.warning(message)
else
-- link redstone in RTU
local mode = rsio.get_io_mode(conf.channel)
@@ -132,13 +131,13 @@ for reactor_idx = 1, #rtu_redstone do
rs_rtu.link_ao(conf.channel, conf.side)
else
-- should be unreachable code, we already validated channels
log._error("init> fell through if chain attempting to identify IO mode", true)
log.error("init> fell through if chain attempting to identify IO mode", true)
break
end
table.insert(capabilities, conf.channel)
log._debug("init> linked redstone " .. #capabilities .. ": " .. rsio.to_string(conf.channel) .. " (" .. conf.side ..
log.debug("init> linked redstone " .. #capabilities .. ": " .. rsio.to_string(conf.channel) .. " (" .. conf.side ..
") for reactor " .. rtu_redstone[reactor_idx].for_reactor)
end
end
@@ -156,7 +155,7 @@ for reactor_idx = 1, #rtu_redstone do
thread = nil
})
log._debug("init> initialized RTU unit #" .. #units .. ": redstone_io (redstone) [1] for reactor " .. rtu_redstone[reactor_idx].for_reactor)
log.debug("init> initialized RTU unit #" .. #units .. ": redstone_io (redstone) [1] for reactor " .. rtu_redstone[reactor_idx].for_reactor)
end
-- mounted peripherals
@@ -166,7 +165,7 @@ for i = 1, #rtu_devices do
if device == nil then
local message = "init> '" .. rtu_devices[i].name .. "' not found"
println_ts(message)
log._warning(message)
log.warning(message)
else
local type = ppm.get_type(rtu_devices[i].name)
local rtu_iface = nil
@@ -200,7 +199,7 @@ for i = 1, #rtu_devices do
else
local message = "init> device '" .. rtu_devices[i].name .. "' is not a known type (" .. type .. ")"
println_ts(message)
log._warning(message)
log.warning(message)
end
if rtu_iface ~= nil then
@@ -221,7 +220,7 @@ for i = 1, #rtu_devices do
table.insert(units, rtu_unit)
log._debug("init> initialized RTU unit #" .. #units .. ": " .. rtu_devices[i].name .. " (" .. rtu_type .. ") [" ..
log.debug("init> initialized RTU unit #" .. #units .. ": " .. rtu_devices[i].name .. " (" .. rtu_type .. ") [" ..
rtu_devices[i].index .. "] for reactor " .. rtu_devices[i].for_reactor)
end
end
@@ -237,7 +236,7 @@ local comms_thread = threads.thread__comms(__shared_memory)
-- start connection watchdog
smem_sys.conn_watchdog = util.new_watchdog(5)
log._debug("init> conn watchdog started")
log.debug("init> conn watchdog started")
-- assemble thread list
local _threads = { main_thread.exec, comms_thread.exec }
@@ -251,4 +250,4 @@ end
parallel.waitForAll(table.unpack(_threads))
println_ts("exited")
log._info("exited")
log.info("exited")

View File

@@ -1,7 +1,22 @@
-- #REQUIRES comms.lua
-- #REQUIRES log.lua
-- #REQUIRES ppm.lua
-- #REQUIRES util.lua
local comms = require("scada-common.comms")
local log = require("scada-common.log")
local ppm = require("scada-common.ppm")
local types = require("scada-common.types")
local util = require("scada-common.util")
local redstone_rtu = require("dev.redstone_rtu")
local boiler_rtu = require("dev.boiler_rtu")
local boilerv_rtu = require("dev.boilerv_rtu")
local energymachine_rtu = require("dev.energymachine_rtu")
local imatrix_rtu = require("dev.imatrix_rtu")
local turbine_rtu = require("dev.turbine_rtu")
local turbinev_rtu = require("dev.turbinev_rtu")
local modbus = require("modbus")
local threads = {}
local rtu_t = types.rtu_t
local print = util.print
local println = util.println
@@ -14,10 +29,10 @@ local MAIN_CLOCK = 2 -- (2Hz, 40 ticks)
local COMMS_SLEEP = 150 -- (150ms, 3 ticks)
-- main thread
function thread__main(smem)
threads.thread__main = function (smem)
-- execute thread
local exec = function ()
log._debug("main thread start")
log.debug("main thread start")
-- advertisement/heartbeat clock
local loop_clock = os.startTimer(MAIN_CLOCK)
@@ -62,9 +77,9 @@ function thread__main(smem)
-- we only care if this is our wireless modem
if device.dev == rtu_dev.modem then
println_ts("wireless modem disconnected!")
log._warning("comms modem disconnected!")
log.warning("comms modem disconnected!")
else
log._warning("non-comms modem disconnected")
log.warning("non-comms modem disconnected")
end
else
for i = 1, #units do
@@ -88,9 +103,9 @@ function 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
@@ -102,11 +117,17 @@ function thread__main(smem)
-- found, re-link
unit.device = device
if unit.type == "boiler" then
if unit.type == rtu_t.boiler then
unit.rtu = boiler_rtu.new(device)
elseif unit.type == "turbine" then
elseif 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 == "imatrix" then
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
@@ -121,7 +142,7 @@ function thread__main(smem)
-- check for termination request
if event == "terminate" or ppm.should_terminate() then
rtu_state.shutdown = true
log._info("terminate requested, main thread exiting")
log.info("terminate requested, main thread exiting")
break
end
end
@@ -131,10 +152,10 @@ function thread__main(smem)
end
-- communications handler thread
function thread__comms(smem)
threads.thread__comms = function (smem)
-- execute thread
local exec = function ()
log._debug("comms thread start")
log.debug("comms thread start")
-- load in from shared memory
local rtu_state = smem.rtu_state
@@ -169,8 +190,8 @@ function thread__comms(smem)
-- check for termination request
if rtu_state.shutdown then
rtu_comms.close()
log._info("comms thread exiting")
rtu_comms.close(rtu_state)
log.info("comms thread exiting")
break
end
@@ -183,10 +204,10 @@ function thread__comms(smem)
end
-- per-unit communications handler thread
function thread__unit_comms(smem, unit)
threads.thread__unit_comms = function (smem, unit)
-- execute thread
local exec = function ()
log._debug("rtu unit thread start -> " .. unit.name .. "(" .. unit.type .. ")")
log.debug("rtu unit thread start -> " .. unit.name .. "(" .. unit.type .. ")")
-- load in from shared memory
local rtu_state = smem.rtu_state
@@ -219,7 +240,7 @@ function thread__unit_comms(smem, unit)
-- check for termination request
if rtu_state.shutdown then
log._info("rtu unit thread exiting -> " .. unit.name .. "(" .. unit.type .. ")")
log.info("rtu unit thread exiting -> " .. unit.name .. "(" .. unit.type .. ")")
break
end
@@ -230,3 +251,5 @@ function thread__unit_comms(smem, unit)
return { exec = exec }
end
return threads