mirror of
https://github.com/MikaylaFischler/cc-mek-scada.git
synced 2024-08-30 18:22:34 +00:00
code cleanup, type hints, bugfixes, and #98 removal of support for mek 10.0 RTU peripherals
This commit is contained in:
parent
d0d20b1299
commit
36557fc345
@ -21,6 +21,7 @@ local SCADA_CRDN_TYPES = comms.SCADA_CRDN_TYPES
|
|||||||
|
|
||||||
-- request the user to select a monitor
|
-- request the user to select a monitor
|
||||||
---@param names table available monitors
|
---@param names table available monitors
|
||||||
|
---@return boolean|string|nil
|
||||||
local function ask_monitor(names)
|
local function ask_monitor(names)
|
||||||
println("available monitors:")
|
println("available monitors:")
|
||||||
for i = 1, #names do
|
for i = 1, #names do
|
||||||
@ -71,7 +72,7 @@ function coordinator.configure_monitors(num_units)
|
|||||||
-- PRIMARY DISPLAY --
|
-- PRIMARY DISPLAY --
|
||||||
---------------------
|
---------------------
|
||||||
|
|
||||||
local iface_primary_display = settings.get("PRIMARY_DISPLAY")
|
local iface_primary_display = settings.get("PRIMARY_DISPLAY") ---@type boolean|string|nil
|
||||||
|
|
||||||
if not util.table_contains(names, iface_primary_display) then
|
if not util.table_contains(names, iface_primary_display) then
|
||||||
println("primary display is not connected")
|
println("primary display is not connected")
|
||||||
@ -85,7 +86,7 @@ function coordinator.configure_monitors(num_units)
|
|||||||
iface_primary_display = ask_monitor(names)
|
iface_primary_display = ask_monitor(names)
|
||||||
end
|
end
|
||||||
|
|
||||||
if iface_primary_display == false then return false end
|
if type(iface_primary_display) ~= "string" then return false end
|
||||||
|
|
||||||
settings.set("PRIMARY_DISPLAY", iface_primary_display)
|
settings.set("PRIMARY_DISPLAY", iface_primary_display)
|
||||||
util.filter_table(names, function (x) return x ~= iface_primary_display end)
|
util.filter_table(names, function (x) return x ~= iface_primary_display end)
|
||||||
@ -175,7 +176,10 @@ function coordinator.log_comms(message) log_dmesg(message, "COMMS") end
|
|||||||
|
|
||||||
---@param message string
|
---@param message string
|
||||||
---@return function update, function done
|
---@return function update, function done
|
||||||
function coordinator.log_comms_connecting(message) return log_dmesg(message, "COMMS", true) end
|
function coordinator.log_comms_connecting(message)
|
||||||
|
---@diagnostic disable-next-line: return-type-mismatch
|
||||||
|
return log_dmesg(message, "COMMS", true)
|
||||||
|
end
|
||||||
|
|
||||||
-- coordinator communications
|
-- coordinator communications
|
||||||
---@param version string
|
---@param version string
|
||||||
@ -306,6 +310,14 @@ function coordinator.comms(version, modem, sv_port, sv_listen, api_listen, sv_wa
|
|||||||
return self.sv_linked
|
return self.sv_linked
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- send a unit command
|
||||||
|
---@param unit integer unit ID
|
||||||
|
---@param cmd CRDN_COMMANDS command
|
||||||
|
---@param option any? optional options (like burn rate)
|
||||||
|
function public.send_command(unit, cmd, option)
|
||||||
|
_send_sv(PROTOCOLS.SCADA_CRDN, SCADA_CRDN_TYPES.COMMAND_UNIT, { unit, cmd, option })
|
||||||
|
end
|
||||||
|
|
||||||
-- parse a packet
|
-- parse a packet
|
||||||
---@param side string
|
---@param side string
|
||||||
---@param sender integer
|
---@param sender integer
|
||||||
@ -348,12 +360,13 @@ function coordinator.comms(version, modem, sv_port, sv_listen, api_listen, sv_wa
|
|||||||
end
|
end
|
||||||
|
|
||||||
-- handle a packet
|
-- handle a packet
|
||||||
---@param packet mgmt_frame|crdn_frame|capi_frame
|
---@param packet mgmt_frame|crdn_frame|capi_frame|nil
|
||||||
function public.handle_packet(packet)
|
function public.handle_packet(packet)
|
||||||
if packet ~= nil then
|
if packet ~= nil then
|
||||||
local protocol = packet.scada_frame.protocol()
|
local protocol = packet.scada_frame.protocol()
|
||||||
|
|
||||||
if protocol == PROTOCOLS.COORD_API then
|
if protocol == PROTOCOLS.COORD_API then
|
||||||
|
---@diagnostic disable-next-line: param-type-mismatch
|
||||||
apisessions.handle_packet(packet)
|
apisessions.handle_packet(packet)
|
||||||
else
|
else
|
||||||
-- check sequence number
|
-- check sequence number
|
||||||
@ -389,7 +402,7 @@ function coordinator.comms(version, modem, sv_port, sv_listen, api_listen, sv_wa
|
|||||||
end
|
end
|
||||||
|
|
||||||
-- init io controller
|
-- init io controller
|
||||||
iocontrol.init(conf)
|
iocontrol.init(conf, public)
|
||||||
|
|
||||||
self.sv_linked = true
|
self.sv_linked = true
|
||||||
else
|
else
|
||||||
|
@ -1,5 +1,9 @@
|
|||||||
local psil = require("scada-common.psil")
|
local comms = require("scada-common.comms")
|
||||||
local log = require("scada-common.log")
|
local log = require("scada-common.log")
|
||||||
|
local psil = require("scada-common.psil")
|
||||||
|
local util = require("scada-common.util")
|
||||||
|
|
||||||
|
local CRDN_COMMANDS = comms.CRDN_COMMANDS
|
||||||
|
|
||||||
local iocontrol = {}
|
local iocontrol = {}
|
||||||
|
|
||||||
@ -8,7 +12,8 @@ local io = {}
|
|||||||
|
|
||||||
-- initialize the coordinator IO controller
|
-- initialize the coordinator IO controller
|
||||||
---@param conf facility_conf configuration
|
---@param conf facility_conf configuration
|
||||||
function iocontrol.init(conf)
|
---@param comms coord_comms comms reference
|
||||||
|
function iocontrol.init(conf, comms)
|
||||||
io.facility = {
|
io.facility = {
|
||||||
scram = false,
|
scram = false,
|
||||||
num_units = conf.num_units,
|
num_units = conf.num_units,
|
||||||
@ -29,10 +34,20 @@ function iocontrol.init(conf)
|
|||||||
burn_rate_cmd = 0.0,
|
burn_rate_cmd = 0.0,
|
||||||
waste_control = 0,
|
waste_control = 0,
|
||||||
|
|
||||||
---@fixme debug stubs to be linked into comms later?
|
start = function ()
|
||||||
start = function () print("UNIT " .. i .. ": start") end,
|
comms.send_command(i, CRDN_COMMANDS.START)
|
||||||
scram = function () print("UNIT " .. i .. ": SCRAM") end,
|
log.debug(util.c("sent unit ", i, ": START"))
|
||||||
set_burn = function (rate) print("UNIT " .. i .. ": set burn rate to " .. rate) end,
|
end,
|
||||||
|
|
||||||
|
scram = function ()
|
||||||
|
comms.send_command(i, CRDN_COMMANDS.SCRAM)
|
||||||
|
log.debug(util.c("sent unit ", i, ": SCRAM"))
|
||||||
|
end,
|
||||||
|
|
||||||
|
set_burn = function (rate)
|
||||||
|
comms.send_command(i, CRDN_COMMANDS.SET_BURN, rate)
|
||||||
|
log.debug(util.c("sent unit ", i, ": SET_BURN = ", rate))
|
||||||
|
end,
|
||||||
|
|
||||||
reactor_ps = psil.create(),
|
reactor_ps = psil.create(),
|
||||||
reactor_data = {}, ---@type reactor_db
|
reactor_data = {}, ---@type reactor_db
|
||||||
@ -45,13 +60,13 @@ function iocontrol.init(conf)
|
|||||||
}
|
}
|
||||||
|
|
||||||
for _ = 1, conf.defs[(i * 2) - 1] do
|
for _ = 1, conf.defs[(i * 2) - 1] do
|
||||||
local data = {} ---@type boiler_session_db|boilerv_session_db
|
local data = {} ---@type boilerv_session_db
|
||||||
table.insert(entry.boiler_ps_tbl, psil.create())
|
table.insert(entry.boiler_ps_tbl, psil.create())
|
||||||
table.insert(entry.boiler_data_tbl, data)
|
table.insert(entry.boiler_data_tbl, data)
|
||||||
end
|
end
|
||||||
|
|
||||||
for _ = 1, conf.defs[i * 2] do
|
for _ = 1, conf.defs[i * 2] do
|
||||||
local data = {} ---@type turbine_session_db|turbinev_session_db
|
local data = {} ---@type turbinev_session_db
|
||||||
table.insert(entry.turbine_ps_tbl, psil.create())
|
table.insert(entry.turbine_ps_tbl, psil.create())
|
||||||
table.insert(entry.turbine_data_tbl, data)
|
table.insert(entry.turbine_data_tbl, data)
|
||||||
end
|
end
|
||||||
@ -225,7 +240,7 @@ function iocontrol.update_statuses(statuses)
|
|||||||
unit.boiler_data_tbl[id].state = boiler[1] ---@type table
|
unit.boiler_data_tbl[id].state = boiler[1] ---@type table
|
||||||
unit.boiler_data_tbl[id].tanks = boiler[2] ---@type table
|
unit.boiler_data_tbl[id].tanks = boiler[2] ---@type table
|
||||||
|
|
||||||
local data = unit.boiler_data_tbl[id] ---@type boiler_session_db|boilerv_session_db
|
local data = unit.boiler_data_tbl[id] ---@type boilerv_session_db
|
||||||
|
|
||||||
if data.state.boil_rate > 0 then
|
if data.state.boil_rate > 0 then
|
||||||
unit.boiler_ps_tbl[id].publish("computed_status", 3) -- active
|
unit.boiler_ps_tbl[id].publish("computed_status", 3) -- active
|
||||||
@ -255,7 +270,7 @@ function iocontrol.update_statuses(statuses)
|
|||||||
unit.turbine_data_tbl[id].state = turbine[1] ---@type table
|
unit.turbine_data_tbl[id].state = turbine[1] ---@type table
|
||||||
unit.turbine_data_tbl[id].tanks = turbine[2] ---@type table
|
unit.turbine_data_tbl[id].tanks = turbine[2] ---@type table
|
||||||
|
|
||||||
local data = unit.turbine_data_tbl[id] ---@type turbine_session_db|turbinev_session_db
|
local data = unit.turbine_data_tbl[id] ---@type turbinev_session_db
|
||||||
|
|
||||||
if data.tanks.steam_fill >= 0.99 then
|
if data.tanks.steam_fill >= 0.99 then
|
||||||
unit.turbine_ps_tbl[id].publish("computed_status", 4) -- trip
|
unit.turbine_ps_tbl[id].publish("computed_status", 4) -- trip
|
||||||
|
@ -16,7 +16,7 @@ local config = require("coordinator.config")
|
|||||||
local coordinator = require("coordinator.coordinator")
|
local coordinator = require("coordinator.coordinator")
|
||||||
local renderer = require("coordinator.renderer")
|
local renderer = require("coordinator.renderer")
|
||||||
|
|
||||||
local COORDINATOR_VERSION = "alpha-v0.4.12"
|
local COORDINATOR_VERSION = "alpha-v0.4.13"
|
||||||
|
|
||||||
local print = util.print
|
local print = util.print
|
||||||
local println = util.println
|
local println = util.println
|
||||||
@ -66,7 +66,7 @@ ppm.mount_all()
|
|||||||
|
|
||||||
-- setup monitors
|
-- setup monitors
|
||||||
local configured, monitors = coordinator.configure_monitors(config.NUM_UNITS)
|
local configured, monitors = coordinator.configure_monitors(config.NUM_UNITS)
|
||||||
if not configured then
|
if not configured or monitors == nil then
|
||||||
println("boot> monitor setup failed")
|
println("boot> monitor setup failed")
|
||||||
log.fatal("monitor configuration failed")
|
log.fatal("monitor configuration failed")
|
||||||
return
|
return
|
||||||
|
@ -9,6 +9,10 @@ local println_ts = util.println_ts
|
|||||||
|
|
||||||
local dialog = {}
|
local dialog = {}
|
||||||
|
|
||||||
|
-- ask the user yes or no
|
||||||
|
---@param question string
|
||||||
|
---@param default boolean
|
||||||
|
---@return boolean|nil
|
||||||
function dialog.ask_y_n(question, default)
|
function dialog.ask_y_n(question, default)
|
||||||
print(question)
|
print(question)
|
||||||
|
|
||||||
@ -31,6 +35,10 @@ function dialog.ask_y_n(question, default)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- ask the user for an input within a set of options
|
||||||
|
---@param options table
|
||||||
|
---@param cancel string
|
||||||
|
---@return boolean|string|nil
|
||||||
function dialog.ask_options(options, cancel)
|
function dialog.ask_options(options, cancel)
|
||||||
print("> ")
|
print("> ")
|
||||||
local response = read(nil, nil, function(text) return completion.choice(text, options) end)
|
local response = read(nil, nil, function(text) return completion.choice(text, options) end)
|
||||||
|
@ -19,8 +19,32 @@ local element = {}
|
|||||||
---@field gframe? graphics_frame frame instead of x/y/width/height
|
---@field gframe? graphics_frame frame instead of x/y/width/height
|
||||||
---@field fg_bg? cpair foreground/background colors
|
---@field fg_bg? cpair foreground/background colors
|
||||||
|
|
||||||
|
---@alias graphics_args graphics_args_generic
|
||||||
|
---|waiting_args
|
||||||
|
---|multi_button_args
|
||||||
|
---|push_button_args
|
||||||
|
---|scram_button_args
|
||||||
|
---|spinbox_args
|
||||||
|
---|start_button_args
|
||||||
|
---|switch_button_args
|
||||||
|
---|core_map_args
|
||||||
|
---|data_indicator_args
|
||||||
|
---|hbar_args
|
||||||
|
---|icon_indicator_args
|
||||||
|
---|indicator_light_args
|
||||||
|
---|state_indicator_args
|
||||||
|
---|tristate_indicator_light_args
|
||||||
|
---|vbar_args
|
||||||
|
---|colormap_args
|
||||||
|
---|displaybox_args
|
||||||
|
---|div_args
|
||||||
|
---|pipenet_args
|
||||||
|
---|rectangle_args
|
||||||
|
---|textbox_args
|
||||||
|
---|tiling_args
|
||||||
|
|
||||||
-- a base graphics element, should not be created on its own
|
-- a base graphics element, should not be created on its own
|
||||||
---@param args graphics_args_generic arguments
|
---@param args graphics_args arguments
|
||||||
function element.new(args)
|
function element.new(args)
|
||||||
local self = {
|
local self = {
|
||||||
id = -1,
|
id = -1,
|
||||||
|
@ -19,7 +19,6 @@ local element = require("graphics.element")
|
|||||||
-- new horizontal bar
|
-- new horizontal bar
|
||||||
---@param args hbar_args
|
---@param args hbar_args
|
||||||
---@return graphics_element element, element_id id
|
---@return graphics_element element, element_id id
|
||||||
---@return graphics_element element, element_id id
|
|
||||||
local function hbar(args)
|
local function hbar(args)
|
||||||
-- properties/state
|
-- properties/state
|
||||||
local last_num_bars = -1
|
local last_num_bars = -1
|
||||||
|
@ -315,7 +315,7 @@ function plc.comms(id, version, modem, local_port, server_port, reactor, rps, co
|
|||||||
|
|
||||||
-- send an RPLC packet
|
-- send an RPLC packet
|
||||||
---@param msg_type RPLC_TYPES
|
---@param msg_type RPLC_TYPES
|
||||||
---@param msg string
|
---@param msg table
|
||||||
local function _send(msg_type, msg)
|
local function _send(msg_type, msg)
|
||||||
local s_pkt = comms.scada_packet()
|
local s_pkt = comms.scada_packet()
|
||||||
local r_pkt = comms.rplc_packet()
|
local r_pkt = comms.rplc_packet()
|
||||||
@ -329,7 +329,7 @@ function plc.comms(id, version, modem, local_port, server_port, reactor, rps, co
|
|||||||
|
|
||||||
-- send a SCADA management packet
|
-- send a SCADA management packet
|
||||||
---@param msg_type SCADA_MGMT_TYPES
|
---@param msg_type SCADA_MGMT_TYPES
|
||||||
---@param msg string
|
---@param msg table
|
||||||
local function _send_mgmt(msg_type, msg)
|
local function _send_mgmt(msg_type, msg)
|
||||||
local s_pkt = comms.scada_packet()
|
local s_pkt = comms.scada_packet()
|
||||||
local m_pkt = comms.mgmt_packet()
|
local m_pkt = comms.mgmt_packet()
|
||||||
|
@ -13,7 +13,7 @@ local config = require("reactor-plc.config")
|
|||||||
local plc = require("reactor-plc.plc")
|
local plc = require("reactor-plc.plc")
|
||||||
local threads = require("reactor-plc.threads")
|
local threads = require("reactor-plc.threads")
|
||||||
|
|
||||||
local R_PLC_VERSION = "beta-v0.8.2"
|
local R_PLC_VERSION = "beta-v0.8.3"
|
||||||
|
|
||||||
local print = util.print
|
local print = util.print
|
||||||
local println = util.println
|
local println = util.println
|
||||||
|
@ -194,7 +194,7 @@ function threads.thread__main(smem, init)
|
|||||||
while not plc_state.shutdown do
|
while not plc_state.shutdown do
|
||||||
local status, result = pcall(public.exec)
|
local status, result = pcall(public.exec)
|
||||||
if status == false then
|
if status == false then
|
||||||
log.fatal(result)
|
log.fatal(util.strval(result))
|
||||||
end
|
end
|
||||||
|
|
||||||
-- if status is true, then we are probably exiting, so this won't matter
|
-- if status is true, then we are probably exiting, so this won't matter
|
||||||
@ -337,7 +337,7 @@ function threads.thread__rps(smem)
|
|||||||
while not plc_state.shutdown do
|
while not plc_state.shutdown do
|
||||||
local status, result = pcall(public.exec)
|
local status, result = pcall(public.exec)
|
||||||
if status == false then
|
if status == false then
|
||||||
log.fatal(result)
|
log.fatal(util.strval(result))
|
||||||
end
|
end
|
||||||
|
|
||||||
if not plc_state.shutdown then
|
if not plc_state.shutdown then
|
||||||
@ -412,7 +412,7 @@ function threads.thread__comms_tx(smem)
|
|||||||
while not plc_state.shutdown do
|
while not plc_state.shutdown do
|
||||||
local status, result = pcall(public.exec)
|
local status, result = pcall(public.exec)
|
||||||
if status == false then
|
if status == false then
|
||||||
log.fatal(result)
|
log.fatal(util.strval(result))
|
||||||
end
|
end
|
||||||
|
|
||||||
if not plc_state.shutdown then
|
if not plc_state.shutdown then
|
||||||
@ -460,7 +460,7 @@ function threads.thread__comms_rx(smem)
|
|||||||
-- received a packet
|
-- received a packet
|
||||||
-- handle the packet (setpoints passed to update burn rate setpoint)
|
-- handle the packet (setpoints passed to update burn rate setpoint)
|
||||||
-- (plc_state passed to check if degraded)
|
-- (plc_state passed to check if degraded)
|
||||||
plc_comms.handle_packet(msg.message, setpoints, plc_state)
|
plc_comms.handle_packet(msg.message, plc_state, setpoints)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -486,7 +486,7 @@ function threads.thread__comms_rx(smem)
|
|||||||
while not plc_state.shutdown do
|
while not plc_state.shutdown do
|
||||||
local status, result = pcall(public.exec)
|
local status, result = pcall(public.exec)
|
||||||
if status == false then
|
if status == false then
|
||||||
log.fatal(result)
|
log.fatal(util.strval(result))
|
||||||
end
|
end
|
||||||
|
|
||||||
if not plc_state.shutdown then
|
if not plc_state.shutdown then
|
||||||
@ -610,7 +610,7 @@ function threads.thread__setpoint_control(smem)
|
|||||||
while not plc_state.shutdown do
|
while not plc_state.shutdown do
|
||||||
local status, result = pcall(public.exec)
|
local status, result = pcall(public.exec)
|
||||||
if status == false then
|
if status == false then
|
||||||
log.fatal(result)
|
log.fatal(util.strval(result))
|
||||||
end
|
end
|
||||||
|
|
||||||
if not plc_state.shutdown then
|
if not plc_state.shutdown then
|
||||||
|
@ -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
|
|
@ -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
|
|
@ -1,4 +1,5 @@
|
|||||||
local rtu = require("rtu.rtu")
|
local rtu = require("rtu.rtu")
|
||||||
|
|
||||||
local rsio = require("scada-common.rsio")
|
local rsio = require("scada-common.rsio")
|
||||||
|
|
||||||
local redstone_rtu = {}
|
local redstone_rtu = {}
|
||||||
|
@ -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
|
|
@ -20,12 +20,15 @@ function modbus.new(rtu_dev, use_parallel_read)
|
|||||||
|
|
||||||
local insert = table.insert
|
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 c_addr_start integer
|
||||||
---@param count 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 function _1_read_coils(c_addr_start, count)
|
||||||
local tasks = {}
|
local tasks = {}
|
||||||
local readings = {}
|
local readings = {} ---@type table|MODBUS_EXCODE
|
||||||
local access_fault = false
|
local access_fault = false
|
||||||
local _, coils, _, _ = self.rtu.io_count()
|
local _, coils, _, _ = self.rtu.io_count()
|
||||||
local return_ok = ((c_addr_start + count) <= (coils + 1)) and (count > 0)
|
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
|
return return_ok, readings
|
||||||
end
|
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 di_addr_start integer
|
||||||
---@param count 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 function _2_read_discrete_inputs(di_addr_start, count)
|
||||||
local tasks = {}
|
local tasks = {}
|
||||||
local readings = {}
|
local readings = {} ---@type table|MODBUS_EXCODE
|
||||||
local access_fault = false
|
local access_fault = false
|
||||||
local discrete_inputs, _, _, _ = self.rtu.io_count()
|
local discrete_inputs, _, _, _ = self.rtu.io_count()
|
||||||
local return_ok = ((di_addr_start + count) <= (discrete_inputs + 1)) and (count > 0)
|
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
|
return return_ok, readings
|
||||||
end
|
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 hr_addr_start integer
|
||||||
---@param count 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 function _3_read_multiple_holding_registers(hr_addr_start, count)
|
||||||
local tasks = {}
|
local tasks = {}
|
||||||
local readings = {}
|
local readings = {} ---@type table|MODBUS_EXCODE
|
||||||
local access_fault = false
|
local access_fault = false
|
||||||
local _, _, _, hold_regs = self.rtu.io_count()
|
local _, _, _, hold_regs = self.rtu.io_count()
|
||||||
local return_ok = ((hr_addr_start + count) <= (hold_regs + 1)) and (count > 0)
|
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
|
return return_ok, readings
|
||||||
end
|
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 ir_addr_start integer
|
||||||
---@param count 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 function _4_read_input_registers(ir_addr_start, count)
|
||||||
local tasks = {}
|
local tasks = {}
|
||||||
local readings = {}
|
local readings = {} ---@type table|MODBUS_EXCODE
|
||||||
local access_fault = false
|
local access_fault = false
|
||||||
local _, _, input_regs, _ = self.rtu.io_count()
|
local _, _, input_regs, _ = self.rtu.io_count()
|
||||||
local return_ok = ((ir_addr_start + count) <= (input_regs + 1)) and (count > 0)
|
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
|
return return_ok, readings
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- write a single coil (digital output)
|
||||||
---@param c_addr integer
|
---@param c_addr integer
|
||||||
---@param value any
|
---@param value any
|
||||||
---@return boolean ok, MODBUS_EXCODE|nil
|
---@return boolean ok, MODBUS_EXCODE
|
||||||
local function _5_write_single_coil(c_addr, value)
|
local function _5_write_single_coil(c_addr, value)
|
||||||
local response = nil
|
local response = nil
|
||||||
local _, coils, _, _ = self.rtu.io_count()
|
local _, coils, _, _ = self.rtu.io_count()
|
||||||
@ -226,9 +239,10 @@ function modbus.new(rtu_dev, use_parallel_read)
|
|||||||
return return_ok, response
|
return return_ok, response
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- write a single holding register (analog output)
|
||||||
---@param hr_addr integer
|
---@param hr_addr integer
|
||||||
---@param value any
|
---@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 function _6_write_single_holding_register(hr_addr, value)
|
||||||
local response = nil
|
local response = nil
|
||||||
local _, _, _, hold_regs = self.rtu.io_count()
|
local _, _, _, hold_regs = self.rtu.io_count()
|
||||||
@ -248,9 +262,10 @@ function modbus.new(rtu_dev, use_parallel_read)
|
|||||||
return return_ok, response
|
return return_ok, response
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- write multiple coils (digital outputs)
|
||||||
---@param c_addr_start integer
|
---@param c_addr_start integer
|
||||||
---@param values any
|
---@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 function _15_write_multiple_coils(c_addr_start, values)
|
||||||
local response = nil
|
local response = nil
|
||||||
local _, coils, _, _ = self.rtu.io_count()
|
local _, coils, _, _ = self.rtu.io_count()
|
||||||
@ -275,9 +290,10 @@ function modbus.new(rtu_dev, use_parallel_read)
|
|||||||
return return_ok, response
|
return return_ok, response
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- write multiple holding registers (analog outputs)
|
||||||
---@param hr_addr_start integer
|
---@param hr_addr_start integer
|
||||||
---@param values any
|
---@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 function _16_write_multiple_holding_registers(hr_addr_start, values)
|
||||||
local response = nil
|
local response = nil
|
||||||
local _, _, _, hold_regs = self.rtu.io_count()
|
local _, _, _, hold_regs = self.rtu.io_count()
|
||||||
@ -403,6 +419,7 @@ function modbus.new(rtu_dev, use_parallel_read)
|
|||||||
end
|
end
|
||||||
|
|
||||||
-- return a SERVER_DEVICE_BUSY error reply
|
-- return a SERVER_DEVICE_BUSY error reply
|
||||||
|
---@param packet modbus_frame MODBUS packet frame
|
||||||
---@return modbus_packet reply
|
---@return modbus_packet reply
|
||||||
function modbus.reply__srv_device_busy(packet)
|
function modbus.reply__srv_device_busy(packet)
|
||||||
-- reply back with error flag and exception code
|
-- reply back with error flag and exception code
|
||||||
@ -414,6 +431,7 @@ function modbus.reply__srv_device_busy(packet)
|
|||||||
end
|
end
|
||||||
|
|
||||||
-- return a NEG_ACKNOWLEDGE error reply
|
-- return a NEG_ACKNOWLEDGE error reply
|
||||||
|
---@param packet modbus_frame MODBUS packet frame
|
||||||
---@return modbus_packet reply
|
---@return modbus_packet reply
|
||||||
function modbus.reply__neg_ack(packet)
|
function modbus.reply__neg_ack(packet)
|
||||||
-- reply back with error flag and exception code
|
-- reply back with error flag and exception code
|
||||||
@ -425,6 +443,7 @@ function modbus.reply__neg_ack(packet)
|
|||||||
end
|
end
|
||||||
|
|
||||||
-- return a GATEWAY_PATH_UNAVAILABLE error reply
|
-- return a GATEWAY_PATH_UNAVAILABLE error reply
|
||||||
|
---@param packet modbus_frame MODBUS packet frame
|
||||||
---@return modbus_packet reply
|
---@return modbus_packet reply
|
||||||
function modbus.reply__gw_unavailable(packet)
|
function modbus.reply__gw_unavailable(packet)
|
||||||
-- reply back with error flag and exception code
|
-- reply back with error flag and exception code
|
||||||
|
@ -1,15 +1,12 @@
|
|||||||
local comms = require("scada-common.comms")
|
local comms = require("scada-common.comms")
|
||||||
local ppm = require("scada-common.ppm")
|
local ppm = require("scada-common.ppm")
|
||||||
local log = require("scada-common.log")
|
local log = require("scada-common.log")
|
||||||
local types = require("scada-common.types")
|
|
||||||
local util = require("scada-common.util")
|
local util = require("scada-common.util")
|
||||||
|
|
||||||
local modbus = require("rtu.modbus")
|
local modbus = require("rtu.modbus")
|
||||||
|
|
||||||
local rtu = {}
|
local rtu = {}
|
||||||
|
|
||||||
local rtu_t = types.rtu_t
|
|
||||||
|
|
||||||
local PROTOCOLS = comms.PROTOCOLS
|
local PROTOCOLS = comms.PROTOCOLS
|
||||||
local SCADA_MGMT_TYPES = comms.SCADA_MGMT_TYPES
|
local SCADA_MGMT_TYPES = comms.SCADA_MGMT_TYPES
|
||||||
local RTU_UNIT_TYPES = comms.RTU_UNIT_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
|
if protocol == PROTOCOLS.MODBUS_TCP then
|
||||||
local return_code = false
|
local return_code = false
|
||||||
|
---@diagnostic disable-next-line: param-type-mismatch
|
||||||
local reply = modbus.reply__neg_ack(packet)
|
local reply = modbus.reply__neg_ack(packet)
|
||||||
|
|
||||||
-- handle MODBUS instruction
|
-- handle MODBUS instruction
|
||||||
@ -342,17 +340,20 @@ function rtu.comms(version, modem, local_port, server_port, conn_watchdog)
|
|||||||
|
|
||||||
if unit.name == "redstone_io" then
|
if unit.name == "redstone_io" then
|
||||||
-- immediately execute redstone RTU requests
|
-- immediately execute redstone RTU requests
|
||||||
|
---@diagnostic disable-next-line: param-type-mismatch
|
||||||
return_code, reply = unit.modbus_io.handle_packet(packet)
|
return_code, reply = unit.modbus_io.handle_packet(packet)
|
||||||
if not return_code then
|
if not return_code then
|
||||||
log.warning("requested MODBUS operation failed" .. unit_dbg_tag)
|
log.warning("requested MODBUS operation failed" .. unit_dbg_tag)
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
-- check validity then pass off to unit comms thread
|
-- 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)
|
return_code, reply = unit.modbus_io.check_request(packet)
|
||||||
if return_code then
|
if return_code then
|
||||||
-- check if there are more than 3 active transactions
|
-- check if there are more than 3 active transactions
|
||||||
-- still queue the packet, but this may indicate a problem
|
-- still queue the packet, but this may indicate a problem
|
||||||
if unit.pkt_queue.length() > 3 then
|
if unit.pkt_queue.length() > 3 then
|
||||||
|
---@diagnostic disable-next-line: param-type-mismatch
|
||||||
reply = modbus.reply__srv_device_busy(packet)
|
reply = modbus.reply__srv_device_busy(packet)
|
||||||
log.debug("queueing new request with " .. unit.pkt_queue.length() ..
|
log.debug("queueing new request with " .. unit.pkt_queue.length() ..
|
||||||
" transactions already in the queue" .. unit_dbg_tag)
|
" transactions already in the queue" .. unit_dbg_tag)
|
||||||
@ -366,6 +367,7 @@ function rtu.comms(version, modem, local_port, server_port, conn_watchdog)
|
|||||||
end
|
end
|
||||||
else
|
else
|
||||||
-- unit ID out of range?
|
-- unit ID out of range?
|
||||||
|
---@diagnostic disable-next-line: param-type-mismatch
|
||||||
reply = modbus.reply__gw_unavailable(packet)
|
reply = modbus.reply__gw_unavailable(packet)
|
||||||
log.error("received MODBUS packet for non-existent unit")
|
log.error("received MODBUS packet for non-existent unit")
|
||||||
end
|
end
|
||||||
|
@ -16,16 +16,15 @@ local modbus = require("rtu.modbus")
|
|||||||
local rtu = require("rtu.rtu")
|
local rtu = require("rtu.rtu")
|
||||||
local threads = require("rtu.threads")
|
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 boilerv_rtu = require("rtu.dev.boilerv_rtu")
|
||||||
local energymachine_rtu = require("rtu.dev.energymachine_rtu")
|
|
||||||
local envd_rtu = require("rtu.dev.envd_rtu")
|
local envd_rtu = require("rtu.dev.envd_rtu")
|
||||||
local imatrix_rtu = require("rtu.dev.imatrix_rtu")
|
local imatrix_rtu = require("rtu.dev.imatrix_rtu")
|
||||||
local turbine_rtu = require("rtu.dev.turbine_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 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
|
local rtu_t = types.rtu_t
|
||||||
|
|
||||||
@ -219,9 +218,9 @@ local function configure()
|
|||||||
index = entry_idx,
|
index = entry_idx,
|
||||||
reactor = io_reactor,
|
reactor = io_reactor,
|
||||||
device = capabilities, -- use device field for redstone channels
|
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),
|
modbus_io = modbus.new(rs_rtu, false),
|
||||||
pkt_queue = nil,
|
pkt_queue = nil, ---@type mqueue|nil
|
||||||
thread = nil
|
thread = nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -267,31 +266,26 @@ local function configure()
|
|||||||
local rtu_iface = nil ---@type rtu_device
|
local rtu_iface = nil ---@type rtu_device
|
||||||
local rtu_type = ""
|
local rtu_type = ""
|
||||||
|
|
||||||
if type == "boiler" then
|
if type == "boilerValve" then
|
||||||
-- boiler multiblock
|
-- 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_type = rtu_t.boiler_valve
|
||||||
rtu_iface = boilerv_rtu.new(device)
|
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
|
elseif type == "turbineValve" then
|
||||||
-- turbine multiblock (10.1+)
|
-- turbine multiblock
|
||||||
rtu_type = rtu_t.turbine_valve
|
rtu_type = rtu_t.turbine_valve
|
||||||
rtu_iface = turbinev_rtu.new(device)
|
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
|
elseif type == "inductionPort" then
|
||||||
-- induction matrix multiblock (10.1+)
|
-- induction matrix multiblock
|
||||||
rtu_type = rtu_t.induction_matrix
|
rtu_type = rtu_t.induction_matrix
|
||||||
rtu_iface = imatrix_rtu.new(device)
|
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
|
elseif type == "environmentDetector" then
|
||||||
-- advanced peripherals environment detector
|
-- advanced peripherals environment detector
|
||||||
rtu_type = rtu_t.env_detector
|
rtu_type = rtu_t.env_detector
|
||||||
@ -311,9 +305,9 @@ local function configure()
|
|||||||
index = index,
|
index = index,
|
||||||
reactor = for_reactor,
|
reactor = for_reactor,
|
||||||
device = device,
|
device = device,
|
||||||
rtu = rtu_iface,
|
rtu = rtu_iface, ---@type rtu_device|rtu_rs_device
|
||||||
modbus_io = modbus.new(rtu_iface, true),
|
modbus_io = modbus.new(rtu_iface, true),
|
||||||
pkt_queue = mqueue.new(),
|
pkt_queue = mqueue.new(), ---@type mqueue|nil
|
||||||
thread = nil
|
thread = nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4,11 +4,8 @@ local ppm = require("scada-common.ppm")
|
|||||||
local types = require("scada-common.types")
|
local types = require("scada-common.types")
|
||||||
local util = require("scada-common.util")
|
local util = require("scada-common.util")
|
||||||
|
|
||||||
local boiler_rtu = require("rtu.dev.boiler_rtu")
|
|
||||||
local boilerv_rtu = require("rtu.dev.boilerv_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 imatrix_rtu = require("rtu.dev.imatrix_rtu")
|
||||||
local turbine_rtu = require("rtu.dev.turbine_rtu")
|
|
||||||
local turbinev_rtu = require("rtu.dev.turbinev_rtu")
|
local turbinev_rtu = require("rtu.dev.turbinev_rtu")
|
||||||
|
|
||||||
local modbus = require("rtu.modbus")
|
local modbus = require("rtu.modbus")
|
||||||
@ -124,16 +121,10 @@ function threads.thread__main(smem)
|
|||||||
-- found, re-link
|
-- found, re-link
|
||||||
unit.device = device
|
unit.device = device
|
||||||
|
|
||||||
if unit.type == rtu_t.boiler then
|
if unit.type == rtu_t.boiler_valve then
|
||||||
unit.rtu = boiler_rtu.new(device)
|
|
||||||
elseif unit.type == rtu_t.boiler_valve then
|
|
||||||
unit.rtu = boilerv_rtu.new(device)
|
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
|
elseif unit.type == rtu_t.turbine_valve then
|
||||||
unit.rtu = turbinev_rtu.new(device)
|
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
|
elseif unit.type == rtu_t.induction_matrix then
|
||||||
unit.rtu = imatrix_rtu.new(device)
|
unit.rtu = imatrix_rtu.new(device)
|
||||||
end
|
end
|
||||||
@ -163,7 +154,7 @@ function threads.thread__main(smem)
|
|||||||
while not rtu_state.shutdown do
|
while not rtu_state.shutdown do
|
||||||
local status, result = pcall(public.exec)
|
local status, result = pcall(public.exec)
|
||||||
if status == false then
|
if status == false then
|
||||||
log.fatal(result)
|
log.fatal(util.strval(result))
|
||||||
end
|
end
|
||||||
|
|
||||||
if not rtu_state.shutdown then
|
if not rtu_state.shutdown then
|
||||||
@ -235,7 +226,7 @@ function threads.thread__comms(smem)
|
|||||||
while not rtu_state.shutdown do
|
while not rtu_state.shutdown do
|
||||||
local status, result = pcall(public.exec)
|
local status, result = pcall(public.exec)
|
||||||
if status == false then
|
if status == false then
|
||||||
log.fatal(result)
|
log.fatal(util.strval(result))
|
||||||
end
|
end
|
||||||
|
|
||||||
if not rtu_state.shutdown then
|
if not rtu_state.shutdown then
|
||||||
@ -265,6 +256,11 @@ function threads.thread__unit_comms(smem, unit)
|
|||||||
|
|
||||||
local last_update = util.time()
|
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
|
-- thread loop
|
||||||
while true do
|
while true do
|
||||||
-- check for messages in the message queue
|
-- check for messages in the message queue
|
||||||
@ -305,7 +301,7 @@ function threads.thread__unit_comms(smem, unit)
|
|||||||
while not rtu_state.shutdown do
|
while not rtu_state.shutdown do
|
||||||
local status, result = pcall(public.exec)
|
local status, result = pcall(public.exec)
|
||||||
if status == false then
|
if status == false then
|
||||||
log.fatal(result)
|
log.fatal(util.strval(result))
|
||||||
end
|
end
|
||||||
|
|
||||||
if not rtu_state.shutdown then
|
if not rtu_state.shutdown then
|
||||||
|
@ -57,6 +57,15 @@ local SCADA_CRDN_TYPES = {
|
|||||||
ALARM = 4 -- alarm signaling
|
ALARM = 4 -- alarm signaling
|
||||||
}
|
}
|
||||||
|
|
||||||
|
---@alias CRDN_COMMANDS integer
|
||||||
|
local CRDN_COMMANDS = {
|
||||||
|
SCRAM = 0, -- SCRAM the reactor
|
||||||
|
START = 1, -- start the reactor
|
||||||
|
RESET_RPS = 2, -- reset the RPS
|
||||||
|
SET_BURN = 3, -- set the burn rate
|
||||||
|
SET_WASTE = 4 -- set the waste processing mode
|
||||||
|
}
|
||||||
|
|
||||||
---@alias CAPI_TYPES integer
|
---@alias CAPI_TYPES integer
|
||||||
local CAPI_TYPES = {
|
local CAPI_TYPES = {
|
||||||
ESTABLISH = 0 -- initial greeting
|
ESTABLISH = 0 -- initial greeting
|
||||||
@ -65,15 +74,12 @@ local CAPI_TYPES = {
|
|||||||
---@alias RTU_UNIT_TYPES integer
|
---@alias RTU_UNIT_TYPES integer
|
||||||
local RTU_UNIT_TYPES = {
|
local RTU_UNIT_TYPES = {
|
||||||
REDSTONE = 0, -- redstone I/O
|
REDSTONE = 0, -- redstone I/O
|
||||||
BOILER = 1, -- boiler
|
BOILER_VALVE = 1, -- boiler mekanism 10.1+
|
||||||
BOILER_VALVE = 2, -- boiler mekanism 10.1+
|
TURBINE_VALVE = 2, -- turbine, mekanism 10.1+
|
||||||
TURBINE = 3, -- turbine
|
IMATRIX = 3, -- induction matrix
|
||||||
TURBINE_VALVE = 4, -- turbine, mekanism 10.1+
|
SPS = 4, -- SPS
|
||||||
EMACHINE = 5, -- energy machine
|
SNA = 5, -- SNA
|
||||||
IMATRIX = 6, -- induction matrix
|
ENV_DETECTOR = 6 -- environment detector
|
||||||
SPS = 7, -- SPS
|
|
||||||
SNA = 8, -- SNA
|
|
||||||
ENV_DETECTOR = 9 -- environment detector
|
|
||||||
}
|
}
|
||||||
|
|
||||||
comms.PROTOCOLS = PROTOCOLS
|
comms.PROTOCOLS = PROTOCOLS
|
||||||
@ -81,8 +87,13 @@ comms.RPLC_TYPES = RPLC_TYPES
|
|||||||
comms.RPLC_LINKING = RPLC_LINKING
|
comms.RPLC_LINKING = RPLC_LINKING
|
||||||
comms.SCADA_MGMT_TYPES = SCADA_MGMT_TYPES
|
comms.SCADA_MGMT_TYPES = SCADA_MGMT_TYPES
|
||||||
comms.SCADA_CRDN_TYPES = SCADA_CRDN_TYPES
|
comms.SCADA_CRDN_TYPES = SCADA_CRDN_TYPES
|
||||||
|
comms.CRDN_COMMANDS = CRDN_COMMANDS
|
||||||
|
comms.CAPI_TYPES = CAPI_TYPES
|
||||||
comms.RTU_UNIT_TYPES = RTU_UNIT_TYPES
|
comms.RTU_UNIT_TYPES = RTU_UNIT_TYPES
|
||||||
|
|
||||||
|
---@alias packet scada_packet|modbus_packet|rplc_packet|mgmt_packet|crdn_packet|capi_packet
|
||||||
|
---@alias frame modbus_frame|rplc_frame|mgmt_frame|crdn_frame|capi_frame
|
||||||
|
|
||||||
-- generic SCADA packet object
|
-- generic SCADA packet object
|
||||||
function comms.scada_packet()
|
function comms.scada_packet()
|
||||||
local self = {
|
local self = {
|
||||||
@ -616,16 +627,10 @@ end
|
|||||||
function comms.rtu_t_to_unit_type(type)
|
function comms.rtu_t_to_unit_type(type)
|
||||||
if type == rtu_t.redstone then
|
if type == rtu_t.redstone then
|
||||||
return RTU_UNIT_TYPES.REDSTONE
|
return RTU_UNIT_TYPES.REDSTONE
|
||||||
elseif type == rtu_t.boiler then
|
|
||||||
return RTU_UNIT_TYPES.BOILER
|
|
||||||
elseif type == rtu_t.boiler_valve then
|
elseif type == rtu_t.boiler_valve then
|
||||||
return RTU_UNIT_TYPES.BOILER_VALVE
|
return RTU_UNIT_TYPES.BOILER_VALVE
|
||||||
elseif type == rtu_t.turbine then
|
|
||||||
return RTU_UNIT_TYPES.TURBINE
|
|
||||||
elseif type == rtu_t.turbine_valve then
|
elseif type == rtu_t.turbine_valve then
|
||||||
return RTU_UNIT_TYPES.TURBINE_VALVE
|
return RTU_UNIT_TYPES.TURBINE_VALVE
|
||||||
elseif type == rtu_t.energy_machine then
|
|
||||||
return RTU_UNIT_TYPES.EMACHINE
|
|
||||||
elseif type == rtu_t.induction_matrix then
|
elseif type == rtu_t.induction_matrix then
|
||||||
return RTU_UNIT_TYPES.IMATRIX
|
return RTU_UNIT_TYPES.IMATRIX
|
||||||
end
|
end
|
||||||
@ -639,16 +644,10 @@ end
|
|||||||
function comms.advert_type_to_rtu_t(utype)
|
function comms.advert_type_to_rtu_t(utype)
|
||||||
if utype == RTU_UNIT_TYPES.REDSTONE then
|
if utype == RTU_UNIT_TYPES.REDSTONE then
|
||||||
return rtu_t.redstone
|
return rtu_t.redstone
|
||||||
elseif utype == RTU_UNIT_TYPES.BOILER then
|
|
||||||
return rtu_t.boiler
|
|
||||||
elseif utype == RTU_UNIT_TYPES.BOILER_VALVE then
|
elseif utype == RTU_UNIT_TYPES.BOILER_VALVE then
|
||||||
return rtu_t.boiler_valve
|
return rtu_t.boiler_valve
|
||||||
elseif utype == RTU_UNIT_TYPES.TURBINE then
|
|
||||||
return rtu_t.turbine
|
|
||||||
elseif utype == RTU_UNIT_TYPES.TURBINE_VALVE then
|
elseif utype == RTU_UNIT_TYPES.TURBINE_VALVE then
|
||||||
return rtu_t.turbine_valve
|
return rtu_t.turbine_valve
|
||||||
elseif utype == RTU_UNIT_TYPES.EMACHINE then
|
|
||||||
return rtu_t.energy_machine
|
|
||||||
elseif utype == RTU_UNIT_TYPES.IMATRIX then
|
elseif utype == RTU_UNIT_TYPES.IMATRIX then
|
||||||
return rtu_t.induction_matrix
|
return rtu_t.induction_matrix
|
||||||
end
|
end
|
||||||
|
@ -71,7 +71,7 @@ end
|
|||||||
|
|
||||||
-- encrypt plaintext
|
-- encrypt plaintext
|
||||||
---@param plaintext string
|
---@param plaintext string
|
||||||
---@return string initial_value, string ciphertext
|
---@return table initial_value, string ciphertext
|
||||||
function crypto.encrypt(plaintext)
|
function crypto.encrypt(plaintext)
|
||||||
local start = util.time()
|
local start = util.time()
|
||||||
|
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
|
|
||||||
local mqueue = {}
|
local mqueue = {}
|
||||||
|
|
||||||
---@alias TYPE integer
|
---@alias MQ_TYPE integer
|
||||||
local TYPE = {
|
local TYPE = {
|
||||||
COMMAND = 0,
|
COMMAND = 0,
|
||||||
DATA = 1,
|
DATA = 1,
|
||||||
@ -21,7 +21,7 @@ function mqueue.new()
|
|||||||
local remove = table.remove
|
local remove = table.remove
|
||||||
|
|
||||||
---@class queue_item
|
---@class queue_item
|
||||||
---@field qtype TYPE
|
---@field qtype MQ_TYPE
|
||||||
---@field message any
|
---@field message any
|
||||||
|
|
||||||
---@class queue_data
|
---@class queue_data
|
||||||
@ -42,8 +42,8 @@ function mqueue.new()
|
|||||||
function public.ready() return #queue ~= 0 end
|
function public.ready() return #queue ~= 0 end
|
||||||
|
|
||||||
-- push a new item onto the queue
|
-- push a new item onto the queue
|
||||||
---@param qtype TYPE
|
---@param qtype MQ_TYPE
|
||||||
---@param message string
|
---@param message any
|
||||||
local function _push(qtype, message)
|
local function _push(qtype, message)
|
||||||
insert(queue, { qtype = qtype, message = message })
|
insert(queue, { qtype = qtype, message = message })
|
||||||
end
|
end
|
||||||
@ -62,7 +62,7 @@ function mqueue.new()
|
|||||||
end
|
end
|
||||||
|
|
||||||
-- push a packet onto the queue
|
-- push a packet onto the queue
|
||||||
---@param packet scada_packet|modbus_packet|rplc_packet|crdn_packet|capi_packet
|
---@param packet packet|frame
|
||||||
function public.push_packet(packet)
|
function public.push_packet(packet)
|
||||||
_push(TYPE.PACKET, packet)
|
_push(TYPE.PACKET, packet)
|
||||||
end
|
end
|
||||||
|
@ -86,11 +86,8 @@ types.TRI_FAIL = {
|
|||||||
---@alias rtu_t string
|
---@alias rtu_t string
|
||||||
types.rtu_t = {
|
types.rtu_t = {
|
||||||
redstone = "redstone",
|
redstone = "redstone",
|
||||||
boiler = "boiler",
|
|
||||||
boiler_valve = "boiler_valve",
|
boiler_valve = "boiler_valve",
|
||||||
turbine = "turbine",
|
|
||||||
turbine_valve = "turbine_valve",
|
turbine_valve = "turbine_valve",
|
||||||
energy_machine = "emachine",
|
|
||||||
induction_matrix = "induction_matrix",
|
induction_matrix = "induction_matrix",
|
||||||
sps = "sps",
|
sps = "sps",
|
||||||
sna = "sna",
|
sna = "sna",
|
||||||
|
@ -8,6 +8,7 @@ local coordinator = {}
|
|||||||
local PROTOCOLS = comms.PROTOCOLS
|
local PROTOCOLS = comms.PROTOCOLS
|
||||||
local SCADA_MGMT_TYPES = comms.SCADA_MGMT_TYPES
|
local SCADA_MGMT_TYPES = comms.SCADA_MGMT_TYPES
|
||||||
local SCADA_CRDN_TYPES = comms.SCADA_CRDN_TYPES
|
local SCADA_CRDN_TYPES = comms.SCADA_CRDN_TYPES
|
||||||
|
local CRDN_COMMANDS = comms.CRDN_COMMANDS
|
||||||
|
|
||||||
local print = util.print
|
local print = util.print
|
||||||
local println = util.println
|
local println = util.println
|
||||||
@ -163,6 +164,24 @@ function coordinator.new_session(id, in_queue, out_queue, facility_units)
|
|||||||
if pkt.type == SCADA_CRDN_TYPES.STRUCT_BUILDS then
|
if pkt.type == SCADA_CRDN_TYPES.STRUCT_BUILDS then
|
||||||
-- acknowledgement to coordinator receiving builds
|
-- acknowledgement to coordinator receiving builds
|
||||||
self.acks.builds = true
|
self.acks.builds = true
|
||||||
|
elseif pkt.type == SCADA_CRDN_TYPES.COMMAND_UNIT then
|
||||||
|
if pkt.length > 2 then
|
||||||
|
-- get command and unit id
|
||||||
|
local cmd = pkt.data[1]
|
||||||
|
local uid = pkt.data[2]
|
||||||
|
|
||||||
|
-- continue if valid unit id
|
||||||
|
if util.is_int(uid) and uid > 0 and uid <= #self.units then
|
||||||
|
local unit = self.units[pkt.data[2]] ---@type reactor_unit
|
||||||
|
if cmd == CRDN_COMMANDS.SCRAM then
|
||||||
|
unit.scram()
|
||||||
|
end
|
||||||
|
else
|
||||||
|
log.debug(log_header .. "CRDN command unit invalid")
|
||||||
|
end
|
||||||
|
else
|
||||||
|
log.debug(log_header .. "CRDN command unit packet length mismatch")
|
||||||
|
end
|
||||||
else
|
else
|
||||||
log.debug(log_header .. "handler received unexpected SCADA_CRDN packet type " .. pkt.type)
|
log.debug(log_header .. "handler received unexpected SCADA_CRDN packet type " .. pkt.type)
|
||||||
end
|
end
|
||||||
|
@ -5,15 +5,12 @@ local rsio = require("scada-common.rsio")
|
|||||||
local util = require("scada-common.util")
|
local util = require("scada-common.util")
|
||||||
|
|
||||||
-- supervisor rtu sessions (svrs)
|
-- supervisor rtu sessions (svrs)
|
||||||
local svrs_boiler = require("supervisor.session.rtu.boiler")
|
|
||||||
local svrs_boilerv = require("supervisor.session.rtu.boilerv")
|
local svrs_boilerv = require("supervisor.session.rtu.boilerv")
|
||||||
local svrs_emachine = require("supervisor.session.rtu.emachine")
|
|
||||||
local svrs_envd = require("supervisor.session.rtu.envd")
|
local svrs_envd = require("supervisor.session.rtu.envd")
|
||||||
local svrs_imatrix = require("supervisor.session.rtu.imatrix")
|
local svrs_imatrix = require("supervisor.session.rtu.imatrix")
|
||||||
local svrs_redstone = require("supervisor.session.rtu.redstone")
|
local svrs_redstone = require("supervisor.session.rtu.redstone")
|
||||||
local svrs_sna = require("supervisor.session.rtu.sna")
|
local svrs_sna = require("supervisor.session.rtu.sna")
|
||||||
local svrs_sps = require("supervisor.session.rtu.sps")
|
local svrs_sps = require("supervisor.session.rtu.sps")
|
||||||
local svrs_turbine = require("supervisor.session.rtu.turbine")
|
|
||||||
local svrs_turbinev = require("supervisor.session.rtu.turbinev")
|
local svrs_turbinev = require("supervisor.session.rtu.turbinev")
|
||||||
|
|
||||||
local rtu = {}
|
local rtu = {}
|
||||||
@ -76,7 +73,6 @@ function rtu.new_session(id, in_queue, out_queue, advertisement, facility_units)
|
|||||||
},
|
},
|
||||||
rs_io_q = {},
|
rs_io_q = {},
|
||||||
turbine_cmd_q = {},
|
turbine_cmd_q = {},
|
||||||
turbine_cmd_capable = false,
|
|
||||||
units = {}
|
units = {}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -87,7 +83,6 @@ function rtu.new_session(id, in_queue, out_queue, advertisement, facility_units)
|
|||||||
self.units = {}
|
self.units = {}
|
||||||
self.rs_io_q = {}
|
self.rs_io_q = {}
|
||||||
self.turbine_cmd_q = {}
|
self.turbine_cmd_q = {}
|
||||||
self.turbine_cmd_capable = false
|
|
||||||
end
|
end
|
||||||
|
|
||||||
-- parse the recorded advertisement and create unit sub-sessions
|
-- parse the recorded advertisement and create unit sub-sessions
|
||||||
@ -110,7 +105,7 @@ function rtu.new_session(id, in_queue, out_queue, advertisement, facility_units)
|
|||||||
|
|
||||||
local target_unit = self.f_units[unit_advert.reactor] ---@type reactor_unit
|
local target_unit = self.f_units[unit_advert.reactor] ---@type reactor_unit
|
||||||
|
|
||||||
local u_type = unit_advert.type
|
local u_type = unit_advert.type ---@type integer|boolean
|
||||||
|
|
||||||
-- validate unit advertisement
|
-- validate unit advertisement
|
||||||
|
|
||||||
@ -137,26 +132,14 @@ function rtu.new_session(id, in_queue, out_queue, advertisement, facility_units)
|
|||||||
elseif u_type == RTU_UNIT_TYPES.REDSTONE then
|
elseif u_type == RTU_UNIT_TYPES.REDSTONE then
|
||||||
-- redstone
|
-- redstone
|
||||||
unit, rs_in_q = svrs_redstone.new(self.id, i, unit_advert, self.modbus_q)
|
unit, rs_in_q = svrs_redstone.new(self.id, i, unit_advert, self.modbus_q)
|
||||||
elseif u_type == RTU_UNIT_TYPES.BOILER then
|
|
||||||
-- boiler
|
|
||||||
unit = svrs_boiler.new(self.id, i, unit_advert, self.modbus_q)
|
|
||||||
target_unit.add_boiler(unit)
|
|
||||||
elseif u_type == RTU_UNIT_TYPES.BOILER_VALVE then
|
elseif u_type == RTU_UNIT_TYPES.BOILER_VALVE then
|
||||||
-- boiler (Mekanism 10.1+)
|
-- boiler (Mekanism 10.1+)
|
||||||
unit = svrs_boilerv.new(self.id, i, unit_advert, self.modbus_q)
|
unit = svrs_boilerv.new(self.id, i, unit_advert, self.modbus_q)
|
||||||
target_unit.add_boiler(unit)
|
if type(unit) ~= "nil" then target_unit.add_boiler(unit) end
|
||||||
elseif u_type == RTU_UNIT_TYPES.TURBINE then
|
|
||||||
-- turbine
|
|
||||||
unit = svrs_turbine.new(self.id, i, unit_advert, self.modbus_q)
|
|
||||||
target_unit.add_turbine(unit)
|
|
||||||
elseif u_type == RTU_UNIT_TYPES.TURBINE_VALVE then
|
elseif u_type == RTU_UNIT_TYPES.TURBINE_VALVE then
|
||||||
-- turbine (Mekanism 10.1+)
|
-- turbine (Mekanism 10.1+)
|
||||||
unit, tbv_in_q = svrs_turbinev.new(self.id, i, unit_advert, self.modbus_q)
|
unit, tbv_in_q = svrs_turbinev.new(self.id, i, unit_advert, self.modbus_q)
|
||||||
target_unit.add_turbine(unit)
|
if type(unit) ~= "nil" then target_unit.add_turbine(unit) end
|
||||||
self.turbine_cmd_capable = true
|
|
||||||
elseif u_type == RTU_UNIT_TYPES.EMACHINE then
|
|
||||||
-- mekanism [energy] machine
|
|
||||||
unit = svrs_emachine.new(self.id, i, unit_advert, self.modbus_q)
|
|
||||||
elseif u_type == RTU_UNIT_TYPES.IMATRIX then
|
elseif u_type == RTU_UNIT_TYPES.IMATRIX then
|
||||||
-- induction matrix
|
-- induction matrix
|
||||||
unit = svrs_imatrix.new(self.id, i, unit_advert, self.modbus_q)
|
unit = svrs_imatrix.new(self.id, i, unit_advert, self.modbus_q)
|
||||||
@ -202,8 +185,10 @@ function rtu.new_session(id, in_queue, out_queue, advertisement, facility_units)
|
|||||||
end
|
end
|
||||||
else
|
else
|
||||||
_reset_config()
|
_reset_config()
|
||||||
|
if type(u_type) == "number" then
|
||||||
local type_string = util.strval(comms.advert_type_to_rtu_t(u_type))
|
local type_string = util.strval(comms.advert_type_to_rtu_t(u_type))
|
||||||
log.error(log_header .. "bad advertisement: error occured while creating a unit (type is " .. type_string .. ")")
|
log.error(log_header .. "bad advertisement: error occured while creating a unit (type is " .. type_string .. ")")
|
||||||
|
end
|
||||||
break
|
break
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@ -265,6 +250,7 @@ function rtu.new_session(id, in_queue, out_queue, advertisement, facility_units)
|
|||||||
if pkt.scada_frame.protocol() == PROTOCOLS.MODBUS_TCP then
|
if pkt.scada_frame.protocol() == PROTOCOLS.MODBUS_TCP then
|
||||||
if self.units[pkt.unit_id] ~= nil then
|
if self.units[pkt.unit_id] ~= nil then
|
||||||
local unit = self.units[pkt.unit_id] ---@type unit_session
|
local unit = self.units[pkt.unit_id] ---@type unit_session
|
||||||
|
---@diagnostic disable-next-line: param-type-mismatch
|
||||||
unit.handle_packet(pkt)
|
unit.handle_packet(pkt)
|
||||||
end
|
end
|
||||||
elseif pkt.scada_frame.protocol() == PROTOCOLS.SCADA_MGMT then
|
elseif pkt.scada_frame.protocol() == PROTOCOLS.SCADA_MGMT then
|
||||||
|
@ -1,191 +0,0 @@
|
|||||||
local comms = require("scada-common.comms")
|
|
||||||
local log = require("scada-common.log")
|
|
||||||
local types = require("scada-common.types")
|
|
||||||
|
|
||||||
local unit_session = require("supervisor.session.rtu.unit_session")
|
|
||||||
|
|
||||||
local boiler = {}
|
|
||||||
|
|
||||||
local RTU_UNIT_TYPES = comms.RTU_UNIT_TYPES
|
|
||||||
local MODBUS_FCODE = types.MODBUS_FCODE
|
|
||||||
|
|
||||||
local TXN_TYPES = {
|
|
||||||
BUILD = 1,
|
|
||||||
STATE = 2,
|
|
||||||
TANKS = 3
|
|
||||||
}
|
|
||||||
|
|
||||||
local TXN_TAGS = {
|
|
||||||
"boiler.build",
|
|
||||||
"boiler.state",
|
|
||||||
"boiler.tanks"
|
|
||||||
}
|
|
||||||
|
|
||||||
local PERIODICS = {
|
|
||||||
BUILD = 1000,
|
|
||||||
STATE = 500,
|
|
||||||
TANKS = 1000
|
|
||||||
}
|
|
||||||
|
|
||||||
-- create a new boiler rtu session runner
|
|
||||||
---@param session_id integer
|
|
||||||
---@param unit_id integer
|
|
||||||
---@param advert rtu_advertisement
|
|
||||||
---@param out_queue mqueue
|
|
||||||
function boiler.new(session_id, unit_id, advert, out_queue)
|
|
||||||
-- type check
|
|
||||||
if advert.type ~= RTU_UNIT_TYPES.BOILER then
|
|
||||||
log.error("attempt to instantiate boiler RTU for type '" .. advert.type .. "'. this is a bug.")
|
|
||||||
return nil
|
|
||||||
end
|
|
||||||
|
|
||||||
local log_tag = "session.rtu(" .. session_id .. ").boiler(" .. advert.index .. "): "
|
|
||||||
|
|
||||||
local self = {
|
|
||||||
session = unit_session.new(unit_id, advert, out_queue, log_tag, TXN_TAGS),
|
|
||||||
has_build = false,
|
|
||||||
periodics = {
|
|
||||||
next_build_req = 0,
|
|
||||||
next_state_req = 0,
|
|
||||||
next_tanks_req = 0
|
|
||||||
},
|
|
||||||
---@class boiler_session_db
|
|
||||||
db = {
|
|
||||||
build = {
|
|
||||||
boil_cap = 0.0,
|
|
||||||
steam_cap = 0,
|
|
||||||
water_cap = 0,
|
|
||||||
hcoolant_cap = 0,
|
|
||||||
ccoolant_cap = 0,
|
|
||||||
superheaters = 0,
|
|
||||||
max_boil_rate = 0.0
|
|
||||||
},
|
|
||||||
state = {
|
|
||||||
temperature = 0.0,
|
|
||||||
boil_rate = 0.0
|
|
||||||
},
|
|
||||||
tanks = {
|
|
||||||
steam = 0,
|
|
||||||
steam_need = 0,
|
|
||||||
steam_fill = 0.0,
|
|
||||||
water = 0,
|
|
||||||
water_need = 0,
|
|
||||||
water_fill = 0.0,
|
|
||||||
hcool = {}, ---@type tank_fluid
|
|
||||||
hcool_need = 0,
|
|
||||||
hcool_fill = 0.0,
|
|
||||||
ccool = {}, ---@type tank_fluid
|
|
||||||
ccool_need = 0,
|
|
||||||
ccool_fill = 0.0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
local public = self.session.get()
|
|
||||||
|
|
||||||
-- PRIVATE FUNCTIONS --
|
|
||||||
|
|
||||||
-- query the build of the device
|
|
||||||
local function _request_build()
|
|
||||||
-- read input registers 1 through 7 (start = 1, count = 7)
|
|
||||||
self.session.send_request(TXN_TYPES.BUILD, MODBUS_FCODE.READ_INPUT_REGS, { 1, 7 })
|
|
||||||
end
|
|
||||||
|
|
||||||
-- query the state of the device
|
|
||||||
local function _request_state()
|
|
||||||
-- read input registers 8 through 9 (start = 8, count = 2)
|
|
||||||
self.session.send_request(TXN_TYPES.STATE, MODBUS_FCODE.READ_INPUT_REGS, { 8, 2 })
|
|
||||||
end
|
|
||||||
|
|
||||||
-- query the tanks of the device
|
|
||||||
local function _request_tanks()
|
|
||||||
-- read input registers 10 through 21 (start = 10, count = 12)
|
|
||||||
self.session.send_request(TXN_TYPES.TANKS, MODBUS_FCODE.READ_INPUT_REGS, { 10, 12 })
|
|
||||||
end
|
|
||||||
|
|
||||||
-- PUBLIC FUNCTIONS --
|
|
||||||
|
|
||||||
-- handle a packet
|
|
||||||
---@param m_pkt modbus_frame
|
|
||||||
function public.handle_packet(m_pkt)
|
|
||||||
local txn_type = self.session.try_resolve(m_pkt)
|
|
||||||
if txn_type == false then
|
|
||||||
-- nothing to do
|
|
||||||
elseif txn_type == TXN_TYPES.BUILD then
|
|
||||||
-- build response
|
|
||||||
-- load in data if correct length
|
|
||||||
if m_pkt.length == 7 then
|
|
||||||
self.db.build.boil_cap = m_pkt.data[1]
|
|
||||||
self.db.build.steam_cap = m_pkt.data[2]
|
|
||||||
self.db.build.water_cap = m_pkt.data[3]
|
|
||||||
self.db.build.hcoolant_cap = m_pkt.data[4]
|
|
||||||
self.db.build.ccoolant_cap = m_pkt.data[5]
|
|
||||||
self.db.build.superheaters = m_pkt.data[6]
|
|
||||||
self.db.build.max_boil_rate = m_pkt.data[7]
|
|
||||||
self.has_build = true
|
|
||||||
else
|
|
||||||
log.debug(log_tag .. "MODBUS transaction reply length mismatch (" .. TXN_TAGS[txn_type] .. ")")
|
|
||||||
end
|
|
||||||
elseif txn_type == TXN_TYPES.STATE then
|
|
||||||
-- state response
|
|
||||||
-- load in data if correct length
|
|
||||||
if m_pkt.length == 2 then
|
|
||||||
self.db.state.temperature = m_pkt.data[1]
|
|
||||||
self.db.state.boil_rate = m_pkt.data[2]
|
|
||||||
else
|
|
||||||
log.debug(log_tag .. "MODBUS transaction reply length mismatch (" .. TXN_TAGS[txn_type] .. ")")
|
|
||||||
end
|
|
||||||
elseif txn_type == TXN_TYPES.TANKS then
|
|
||||||
-- tanks response
|
|
||||||
-- load in data if correct length
|
|
||||||
if m_pkt.length == 12 then
|
|
||||||
self.db.tanks.steam = m_pkt.data[1]
|
|
||||||
self.db.tanks.steam_need = m_pkt.data[2]
|
|
||||||
self.db.tanks.steam_fill = m_pkt.data[3]
|
|
||||||
self.db.tanks.water = m_pkt.data[4]
|
|
||||||
self.db.tanks.water_need = m_pkt.data[5]
|
|
||||||
self.db.tanks.water_fill = m_pkt.data[6]
|
|
||||||
self.db.tanks.hcool = m_pkt.data[7]
|
|
||||||
self.db.tanks.hcool_need = m_pkt.data[8]
|
|
||||||
self.db.tanks.hcool_fill = m_pkt.data[9]
|
|
||||||
self.db.tanks.ccool = m_pkt.data[10]
|
|
||||||
self.db.tanks.ccool_need = m_pkt.data[11]
|
|
||||||
self.db.tanks.ccool_fill = m_pkt.data[12]
|
|
||||||
else
|
|
||||||
log.debug(log_tag .. "MODBUS transaction reply length mismatch (" .. TXN_TAGS[txn_type] .. ")")
|
|
||||||
end
|
|
||||||
elseif txn_type == nil then
|
|
||||||
log.error(log_tag .. "unknown transaction reply")
|
|
||||||
else
|
|
||||||
log.error(log_tag .. "unknown transaction type " .. txn_type)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
-- update this runner
|
|
||||||
---@param time_now integer milliseconds
|
|
||||||
function public.update(time_now)
|
|
||||||
if not self.has_build and self.periodics.next_build_req <= time_now then
|
|
||||||
_request_build()
|
|
||||||
self.periodics.next_build_req = time_now + PERIODICS.BUILD
|
|
||||||
end
|
|
||||||
|
|
||||||
if self.periodics.next_state_req <= time_now then
|
|
||||||
_request_state()
|
|
||||||
self.periodics.next_state_req = time_now + PERIODICS.STATE
|
|
||||||
end
|
|
||||||
|
|
||||||
if self.periodics.next_tanks_req <= time_now then
|
|
||||||
_request_tanks()
|
|
||||||
self.periodics.next_tanks_req = time_now + PERIODICS.TANKS
|
|
||||||
end
|
|
||||||
|
|
||||||
self.session.post_update()
|
|
||||||
end
|
|
||||||
|
|
||||||
-- get the unit session database
|
|
||||||
function public.get_db() return self.db end
|
|
||||||
|
|
||||||
return public
|
|
||||||
end
|
|
||||||
|
|
||||||
return boiler
|
|
@ -1,7 +1,6 @@
|
|||||||
local comms = require("scada-common.comms")
|
local comms = require("scada-common.comms")
|
||||||
local log = require("scada-common.log")
|
local log = require("scada-common.log")
|
||||||
local types = require("scada-common.types")
|
local types = require("scada-common.types")
|
||||||
local util = require("scada-common.util")
|
|
||||||
|
|
||||||
local unit_session = require("supervisor.session.rtu.unit_session")
|
local unit_session = require("supervisor.session.rtu.unit_session")
|
||||||
|
|
||||||
|
@ -1,131 +0,0 @@
|
|||||||
local comms = require("scada-common.comms")
|
|
||||||
local log = require("scada-common.log")
|
|
||||||
local types = require("scada-common.types")
|
|
||||||
|
|
||||||
local unit_session = require("supervisor.session.rtu.unit_session")
|
|
||||||
|
|
||||||
local emachine = {}
|
|
||||||
|
|
||||||
local RTU_UNIT_TYPES = comms.RTU_UNIT_TYPES
|
|
||||||
local MODBUS_FCODE = types.MODBUS_FCODE
|
|
||||||
|
|
||||||
local TXN_TYPES = {
|
|
||||||
BUILD = 1,
|
|
||||||
STORAGE = 2
|
|
||||||
}
|
|
||||||
|
|
||||||
local TXN_TAGS = {
|
|
||||||
"emachine.build",
|
|
||||||
"emachine.storage"
|
|
||||||
}
|
|
||||||
|
|
||||||
local PERIODICS = {
|
|
||||||
BUILD = 1000,
|
|
||||||
STORAGE = 500
|
|
||||||
}
|
|
||||||
|
|
||||||
-- create a new energy machine rtu session runner
|
|
||||||
---@param session_id integer
|
|
||||||
---@param unit_id integer
|
|
||||||
---@param advert rtu_advertisement
|
|
||||||
---@param out_queue mqueue
|
|
||||||
function emachine.new(session_id, unit_id, advert, out_queue)
|
|
||||||
-- type check
|
|
||||||
if advert.type ~= RTU_UNIT_TYPES.EMACHINE then
|
|
||||||
log.error("attempt to instantiate emachine RTU for type '" .. advert.type .. "'. this is a bug.")
|
|
||||||
return nil
|
|
||||||
end
|
|
||||||
|
|
||||||
local log_tag = "session.rtu(" .. session_id .. ").emachine(" .. advert.index .. "): "
|
|
||||||
|
|
||||||
local self = {
|
|
||||||
session = unit_session.new(unit_id, advert, out_queue, log_tag, TXN_TAGS),
|
|
||||||
has_build = false,
|
|
||||||
periodics = {
|
|
||||||
next_build_req = 0,
|
|
||||||
next_storage_req = 0
|
|
||||||
},
|
|
||||||
---@class emachine_session_db
|
|
||||||
db = {
|
|
||||||
build = {
|
|
||||||
max_energy = 0
|
|
||||||
},
|
|
||||||
storage = {
|
|
||||||
energy = 0,
|
|
||||||
energy_need = 0,
|
|
||||||
energy_fill = 0.0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
local public = self.session.get()
|
|
||||||
|
|
||||||
-- PRIVATE FUNCTIONS --
|
|
||||||
|
|
||||||
-- query the build of the device
|
|
||||||
local function _request_build()
|
|
||||||
-- read input register 1 (start = 1, count = 1)
|
|
||||||
self.session.send_request(TXN_TYPES.BUILD, MODBUS_FCODE.READ_INPUT_REGS, { 1, 1 })
|
|
||||||
end
|
|
||||||
|
|
||||||
-- query the state of the energy storage
|
|
||||||
local function _request_storage()
|
|
||||||
-- read input registers 2 through 4 (start = 2, count = 3)
|
|
||||||
self.session.send_request(TXN_TYPES.STORAGE, MODBUS_FCODE.READ_INPUT_REGS, { 2, 3 })
|
|
||||||
end
|
|
||||||
|
|
||||||
-- PUBLIC FUNCTIONS --
|
|
||||||
|
|
||||||
-- handle a packet
|
|
||||||
---@param m_pkt modbus_frame
|
|
||||||
function public.handle_packet(m_pkt)
|
|
||||||
local txn_type = self.session.try_resolve(m_pkt)
|
|
||||||
if txn_type == false then
|
|
||||||
-- nothing to do
|
|
||||||
elseif txn_type == TXN_TYPES.BUILD then
|
|
||||||
-- build response
|
|
||||||
if m_pkt.length == 1 then
|
|
||||||
self.db.build.max_energy = m_pkt.data[1]
|
|
||||||
self.has_build = true
|
|
||||||
else
|
|
||||||
log.debug(log_tag .. "MODBUS transaction reply length mismatch (" .. TXN_TAGS[txn_type] .. ")")
|
|
||||||
end
|
|
||||||
elseif txn_type == TXN_TYPES.STORAGE then
|
|
||||||
-- storage response
|
|
||||||
if m_pkt.length == 3 then
|
|
||||||
self.db.storage.energy = m_pkt.data[1]
|
|
||||||
self.db.storage.energy_need = m_pkt.data[2]
|
|
||||||
self.db.storage.energy_fill = m_pkt.data[3]
|
|
||||||
else
|
|
||||||
log.debug(log_tag .. "MODBUS transaction reply length mismatch (" .. TXN_TAGS[txn_type] .. ")")
|
|
||||||
end
|
|
||||||
elseif txn_type == nil then
|
|
||||||
log.error(log_tag .. "unknown transaction reply")
|
|
||||||
else
|
|
||||||
log.error(log_tag .. "unknown transaction type " .. txn_type)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
-- update this runner
|
|
||||||
---@param time_now integer milliseconds
|
|
||||||
function public.update(time_now)
|
|
||||||
if not self.has_build and self.periodics.next_build_req <= time_now then
|
|
||||||
_request_build()
|
|
||||||
self.periodics.next_build_req = time_now + PERIODICS.BUILD
|
|
||||||
end
|
|
||||||
|
|
||||||
if self.periodics.next_storage_req <= time_now then
|
|
||||||
_request_storage()
|
|
||||||
self.periodics.next_storage_req = time_now + PERIODICS.STORAGE
|
|
||||||
end
|
|
||||||
|
|
||||||
self.session.post_update()
|
|
||||||
end
|
|
||||||
|
|
||||||
-- get the unit session database
|
|
||||||
function public.get_db() return self.db end
|
|
||||||
|
|
||||||
return public
|
|
||||||
end
|
|
||||||
|
|
||||||
return emachine
|
|
@ -1,179 +0,0 @@
|
|||||||
local comms = require("scada-common.comms")
|
|
||||||
local log = require("scada-common.log")
|
|
||||||
local types = require("scada-common.types")
|
|
||||||
|
|
||||||
local unit_session = require("supervisor.session.rtu.unit_session")
|
|
||||||
|
|
||||||
local turbine = {}
|
|
||||||
|
|
||||||
local RTU_UNIT_TYPES = comms.RTU_UNIT_TYPES
|
|
||||||
local DUMPING_MODE = types.DUMPING_MODE
|
|
||||||
local MODBUS_FCODE = types.MODBUS_FCODE
|
|
||||||
|
|
||||||
local TXN_TYPES = {
|
|
||||||
BUILD = 1,
|
|
||||||
STATE = 2,
|
|
||||||
TANKS = 3
|
|
||||||
}
|
|
||||||
|
|
||||||
local TXN_TAGS = {
|
|
||||||
"turbine.build",
|
|
||||||
"turbine.state",
|
|
||||||
"turbine.tanks"
|
|
||||||
}
|
|
||||||
|
|
||||||
local PERIODICS = {
|
|
||||||
BUILD = 1000,
|
|
||||||
STATE = 500,
|
|
||||||
TANKS = 1000
|
|
||||||
}
|
|
||||||
|
|
||||||
-- create a new turbine rtu session runner
|
|
||||||
---@param session_id integer
|
|
||||||
---@param unit_id integer
|
|
||||||
---@param advert rtu_advertisement
|
|
||||||
---@param out_queue mqueue
|
|
||||||
function turbine.new(session_id, unit_id, advert, out_queue)
|
|
||||||
-- type check
|
|
||||||
if advert.type ~= RTU_UNIT_TYPES.TURBINE then
|
|
||||||
log.error("attempt to instantiate turbine RTU for type '" .. advert.type .. "'. this is a bug.")
|
|
||||||
return nil
|
|
||||||
end
|
|
||||||
|
|
||||||
local log_tag = "session.rtu(" .. session_id .. ").turbine(" .. advert.index .. "): "
|
|
||||||
|
|
||||||
local self = {
|
|
||||||
session = unit_session.new(unit_id, advert, out_queue, log_tag, TXN_TAGS),
|
|
||||||
has_build = false,
|
|
||||||
periodics = {
|
|
||||||
next_build_req = 0,
|
|
||||||
next_state_req = 0,
|
|
||||||
next_tanks_req = 0
|
|
||||||
},
|
|
||||||
---@class turbine_session_db
|
|
||||||
db = {
|
|
||||||
build = {
|
|
||||||
blades = 0,
|
|
||||||
coils = 0,
|
|
||||||
vents = 0,
|
|
||||||
dispersers = 0,
|
|
||||||
condensers = 0,
|
|
||||||
steam_cap = 0,
|
|
||||||
max_flow_rate = 0,
|
|
||||||
max_production = 0,
|
|
||||||
max_water_output = 0
|
|
||||||
},
|
|
||||||
state = {
|
|
||||||
flow_rate = 0,
|
|
||||||
prod_rate = 0,
|
|
||||||
steam_input_rate = 0,
|
|
||||||
dumping_mode = DUMPING_MODE.IDLE ---@type DUMPING_MODE
|
|
||||||
},
|
|
||||||
tanks = {
|
|
||||||
steam = 0,
|
|
||||||
steam_need = 0,
|
|
||||||
steam_fill = 0.0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
local public = self.session.get()
|
|
||||||
|
|
||||||
-- PRIVATE FUNCTIONS --
|
|
||||||
|
|
||||||
-- query the build of the device
|
|
||||||
local function _request_build()
|
|
||||||
-- read input registers 1 through 9 (start = 1, count = 9)
|
|
||||||
self.session.send_request(TXN_TYPES.BUILD, MODBUS_FCODE.READ_INPUT_REGS, { 1, 9 })
|
|
||||||
end
|
|
||||||
|
|
||||||
-- query the state of the device
|
|
||||||
local function _request_state()
|
|
||||||
-- read input registers 10 through 13 (start = 10, count = 4)
|
|
||||||
self.session.send_request(TXN_TYPES.STATE, MODBUS_FCODE.READ_INPUT_REGS, { 10, 4 })
|
|
||||||
end
|
|
||||||
|
|
||||||
-- query the tanks of the device
|
|
||||||
local function _request_tanks()
|
|
||||||
-- read input registers 14 through 16 (start = 14, count = 3)
|
|
||||||
self.session.send_request(TXN_TYPES.TANKS, MODBUS_FCODE.READ_INPUT_REGS, { 14, 3 })
|
|
||||||
end
|
|
||||||
|
|
||||||
-- PUBLIC FUNCTIONS --
|
|
||||||
|
|
||||||
-- handle a packet
|
|
||||||
---@param m_pkt modbus_frame
|
|
||||||
function public.handle_packet(m_pkt)
|
|
||||||
local txn_type = self.session.try_resolve(m_pkt)
|
|
||||||
if txn_type == false then
|
|
||||||
-- nothing to do
|
|
||||||
elseif txn_type == TXN_TYPES.BUILD then
|
|
||||||
-- build response
|
|
||||||
if m_pkt.length == 9 then
|
|
||||||
self.db.build.blades = m_pkt.data[1]
|
|
||||||
self.db.build.coils = m_pkt.data[2]
|
|
||||||
self.db.build.vents = m_pkt.data[3]
|
|
||||||
self.db.build.dispersers = m_pkt.data[4]
|
|
||||||
self.db.build.condensers = m_pkt.data[5]
|
|
||||||
self.db.build.steam_cap = m_pkt.data[6]
|
|
||||||
self.db.build.max_flow_rate = m_pkt.data[7]
|
|
||||||
self.db.build.max_production = m_pkt.data[8]
|
|
||||||
self.db.build.max_water_output = m_pkt.data[9]
|
|
||||||
self.has_build = true
|
|
||||||
else
|
|
||||||
log.debug(log_tag .. "MODBUS transaction reply length mismatch (" .. TXN_TAGS[txn_type] .. ")")
|
|
||||||
end
|
|
||||||
elseif txn_type == TXN_TYPES.STATE then
|
|
||||||
-- state response
|
|
||||||
if m_pkt.length == 4 then
|
|
||||||
self.db.state.flow_rate = m_pkt.data[1]
|
|
||||||
self.db.state.prod_rate = m_pkt.data[2]
|
|
||||||
self.db.state.steam_input_rate = m_pkt.data[3]
|
|
||||||
self.db.state.dumping_mode = m_pkt.data[4]
|
|
||||||
else
|
|
||||||
log.debug(log_tag .. "MODBUS transaction reply length mismatch (" .. TXN_TAGS[txn_type] .. ")")
|
|
||||||
end
|
|
||||||
elseif txn_type == TXN_TYPES.TANKS then
|
|
||||||
-- tanks response
|
|
||||||
if m_pkt.length == 3 then
|
|
||||||
self.db.tanks.steam = m_pkt.data[1]
|
|
||||||
self.db.tanks.steam_need = m_pkt.data[2]
|
|
||||||
self.db.tanks.steam_fill = m_pkt.data[3]
|
|
||||||
else
|
|
||||||
log.debug(log_tag .. "MODBUS transaction reply length mismatch (" .. TXN_TAGS[txn_type] .. ")")
|
|
||||||
end
|
|
||||||
elseif txn_type == nil then
|
|
||||||
log.error(log_tag .. "unknown transaction reply")
|
|
||||||
else
|
|
||||||
log.error(log_tag .. "unknown transaction type " .. txn_type)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
-- update this runner
|
|
||||||
---@param time_now integer milliseconds
|
|
||||||
function public.update(time_now)
|
|
||||||
if not self.has_build and self.periodics.next_build_req <= time_now then
|
|
||||||
_request_build()
|
|
||||||
self.periodics.next_build_req = time_now + PERIODICS.BUILD
|
|
||||||
end
|
|
||||||
|
|
||||||
if self.periodics.next_state_req <= time_now then
|
|
||||||
_request_state()
|
|
||||||
self.periodics.next_state_req = time_now + PERIODICS.STATE
|
|
||||||
end
|
|
||||||
|
|
||||||
if self.periodics.next_tanks_req <= time_now then
|
|
||||||
_request_tanks()
|
|
||||||
self.periodics.next_tanks_req = time_now + PERIODICS.TANKS
|
|
||||||
end
|
|
||||||
|
|
||||||
self.session.post_update()
|
|
||||||
end
|
|
||||||
|
|
||||||
-- get the unit session database
|
|
||||||
function public.get_db() return self.db end
|
|
||||||
|
|
||||||
return public
|
|
||||||
end
|
|
||||||
|
|
||||||
return turbine
|
|
@ -147,6 +147,7 @@ end
|
|||||||
---@return rtu_session_struct|nil
|
---@return rtu_session_struct|nil
|
||||||
function svsessions.find_rtu_session(remote_port)
|
function svsessions.find_rtu_session(remote_port)
|
||||||
-- check RTU sessions
|
-- check RTU sessions
|
||||||
|
---@diagnostic disable-next-line: return-type-mismatch
|
||||||
return _find_session(self.rtu_sessions, remote_port)
|
return _find_session(self.rtu_sessions, remote_port)
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -155,6 +156,7 @@ end
|
|||||||
---@return plc_session_struct|nil
|
---@return plc_session_struct|nil
|
||||||
function svsessions.find_plc_session(remote_port)
|
function svsessions.find_plc_session(remote_port)
|
||||||
-- check PLC sessions
|
-- check PLC sessions
|
||||||
|
---@diagnostic disable-next-line: return-type-mismatch
|
||||||
return _find_session(self.plc_sessions, remote_port)
|
return _find_session(self.plc_sessions, remote_port)
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -176,6 +178,7 @@ end
|
|||||||
---@return nil
|
---@return nil
|
||||||
function svsessions.find_coord_session(remote_port)
|
function svsessions.find_coord_session(remote_port)
|
||||||
-- check coordinator sessions
|
-- check coordinator sessions
|
||||||
|
---@diagnostic disable-next-line: return-type-mismatch
|
||||||
return _find_session(self.coord_sessions, remote_port)
|
return _find_session(self.coord_sessions, remote_port)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
local types = require "scada-common.types"
|
local types = require("scada-common.types")
|
||||||
local util = require "scada-common.util"
|
local util = require("scada-common.util")
|
||||||
local log = require "scada-common.log"
|
local log = require("scada-common.log")
|
||||||
|
|
||||||
local unit = {}
|
local unit = {}
|
||||||
|
|
||||||
@ -204,7 +204,7 @@ function unit.new(for_reactor, num_boilers, num_turbines)
|
|||||||
-- go through boilers for stats and online
|
-- go through boilers for stats and online
|
||||||
for i = 1, #self.boilers do
|
for i = 1, #self.boilers do
|
||||||
local session = self.boilers[i] ---@type unit_session
|
local session = self.boilers[i] ---@type unit_session
|
||||||
local boiler = session.get_db() ---@type boiler_session_db
|
local boiler = session.get_db() ---@type boilerv_session_db
|
||||||
|
|
||||||
total_boil_rate = total_boil_rate + boiler.state.boil_rate
|
total_boil_rate = total_boil_rate + boiler.state.boil_rate
|
||||||
boiler_steam_dt_sum = _get_dt(DT_KEYS.BoilerSteam .. self.boilers[i].get_device_idx())
|
boiler_steam_dt_sum = _get_dt(DT_KEYS.BoilerSteam .. self.boilers[i].get_device_idx())
|
||||||
@ -221,7 +221,7 @@ function unit.new(for_reactor, num_boilers, num_turbines)
|
|||||||
for i = 1, #self.boilers do
|
for i = 1, #self.boilers do
|
||||||
local boiler = self.boilers[i] ---@type unit_session
|
local boiler = self.boilers[i] ---@type unit_session
|
||||||
local idx = boiler.get_device_idx()
|
local idx = boiler.get_device_idx()
|
||||||
local db = boiler.get_db() ---@type boiler_session_db
|
local db = boiler.get_db() ---@type boilerv_session_db
|
||||||
|
|
||||||
if r_db.mek_status.status then
|
if r_db.mek_status.status then
|
||||||
self.db.annunciator.HeatingRateLow[idx] = db.state.boil_rate == 0
|
self.db.annunciator.HeatingRateLow[idx] = db.state.boil_rate == 0
|
||||||
@ -240,7 +240,7 @@ function unit.new(for_reactor, num_boilers, num_turbines)
|
|||||||
for i = 1, #self.boilers do
|
for i = 1, #self.boilers do
|
||||||
local boiler = self.boilers[i] ---@type unit_session
|
local boiler = self.boilers[i] ---@type unit_session
|
||||||
local idx = boiler.get_device_idx()
|
local idx = boiler.get_device_idx()
|
||||||
local db = boiler.get_db() ---@type boiler_session_db
|
local db = boiler.get_db() ---@type boilerv_session_db
|
||||||
|
|
||||||
local gaining_hc = _get_dt(DT_KEYS.BoilerHCool .. idx) > 0 or db.tanks.hcool_fill == 1
|
local gaining_hc = _get_dt(DT_KEYS.BoilerHCool .. idx) > 0 or db.tanks.hcool_fill == 1
|
||||||
|
|
||||||
@ -267,7 +267,7 @@ function unit.new(for_reactor, num_boilers, num_turbines)
|
|||||||
-- go through turbines for stats and online
|
-- go through turbines for stats and online
|
||||||
for i = 1, #self.turbines do
|
for i = 1, #self.turbines do
|
||||||
local session = self.turbines[i] ---@type unit_session
|
local session = self.turbines[i] ---@type unit_session
|
||||||
local turbine = session.get_db() ---@type turbine_session_db
|
local turbine = session.get_db() ---@type turbinev_session_db
|
||||||
|
|
||||||
total_flow_rate = total_flow_rate + turbine.state.flow_rate
|
total_flow_rate = total_flow_rate + turbine.state.flow_rate
|
||||||
total_input_rate = total_input_rate + turbine.state.steam_input_rate
|
total_input_rate = total_input_rate + turbine.state.steam_input_rate
|
||||||
@ -285,7 +285,7 @@ function unit.new(for_reactor, num_boilers, num_turbines)
|
|||||||
-- check if steam dumps are open
|
-- check if steam dumps are open
|
||||||
for i = 1, #self.turbines do
|
for i = 1, #self.turbines do
|
||||||
local turbine = self.turbines[i] ---@type unit_session
|
local turbine = self.turbines[i] ---@type unit_session
|
||||||
local db = turbine.get_db() ---@type turbine_session_db
|
local db = turbine.get_db() ---@type turbinev_session_db
|
||||||
local idx = turbine.get_device_idx()
|
local idx = turbine.get_device_idx()
|
||||||
|
|
||||||
if db.state.dumping_mode == DUMPING_MODE.IDLE then
|
if db.state.dumping_mode == DUMPING_MODE.IDLE then
|
||||||
@ -300,7 +300,7 @@ function unit.new(for_reactor, num_boilers, num_turbines)
|
|||||||
-- check if turbines are at max speed but not keeping up
|
-- check if turbines are at max speed but not keeping up
|
||||||
for i = 1, #self.turbines do
|
for i = 1, #self.turbines do
|
||||||
local turbine = self.turbines[i] ---@type unit_session
|
local turbine = self.turbines[i] ---@type unit_session
|
||||||
local db = turbine.get_db() ---@type turbine_session_db
|
local db = turbine.get_db() ---@type turbinev_session_db
|
||||||
local idx = turbine.get_device_idx()
|
local idx = turbine.get_device_idx()
|
||||||
|
|
||||||
self.db.annunciator.TurbineOverSpeed[idx] = (db.state.flow_rate == db.build.max_flow_rate) and (_get_dt(DT_KEYS.TurbineSteam .. idx) > 0)
|
self.db.annunciator.TurbineOverSpeed[idx] = (db.state.flow_rate == db.build.max_flow_rate) and (_get_dt(DT_KEYS.TurbineSteam .. idx) > 0)
|
||||||
@ -316,7 +316,7 @@ function unit.new(for_reactor, num_boilers, num_turbines)
|
|||||||
]]--
|
]]--
|
||||||
for i = 1, #self.turbines do
|
for i = 1, #self.turbines do
|
||||||
local turbine = self.turbines[i] ---@type unit_session
|
local turbine = self.turbines[i] ---@type unit_session
|
||||||
local db = turbine.get_db() ---@type turbine_session_db
|
local db = turbine.get_db() ---@type turbinev_session_db
|
||||||
|
|
||||||
local has_steam = db.state.steam_input_rate > 0 or db.tanks.steam_fill > 0.01
|
local has_steam = db.state.steam_input_rate > 0 or db.tanks.steam_fill > 0.01
|
||||||
self.db.annunciator.TurbineTrip[turbine.get_device_idx()] = has_steam and db.state.flow_rate == 0
|
self.db.annunciator.TurbineTrip[turbine.get_device_idx()] = has_steam and db.state.flow_rate == 0
|
||||||
|
@ -13,7 +13,7 @@ local svsessions = require("supervisor.session.svsessions")
|
|||||||
local config = require("supervisor.config")
|
local config = require("supervisor.config")
|
||||||
local supervisor = require("supervisor.supervisor")
|
local supervisor = require("supervisor.supervisor")
|
||||||
|
|
||||||
local SUPERVISOR_VERSION = "beta-v0.5.11"
|
local SUPERVISOR_VERSION = "beta-v0.5.12"
|
||||||
|
|
||||||
local print = util.print
|
local print = util.print
|
||||||
local println = util.println
|
local println = util.println
|
||||||
|
@ -164,7 +164,7 @@ function supervisor.comms(version, num_reactors, cooling_conf, modem, dev_listen
|
|||||||
end
|
end
|
||||||
|
|
||||||
-- handle a packet
|
-- handle a packet
|
||||||
---@param packet modbus_frame|rplc_frame|mgmt_frame|crdn_frame
|
---@param packet modbus_frame|rplc_frame|mgmt_frame|crdn_frame|nil
|
||||||
function public.handle_packet(packet)
|
function public.handle_packet(packet)
|
||||||
if packet ~= nil then
|
if packet ~= nil then
|
||||||
local l_port = packet.scada_frame.local_port()
|
local l_port = packet.scada_frame.local_port()
|
||||||
|
Loading…
Reference in New Issue
Block a user