#118 supervisor cleanup

This commit is contained in:
Mikayla Fischler
2023-02-24 23:36:16 -05:00
parent 38ac552613
commit b7895080cb
19 changed files with 241 additions and 156 deletions

View File

@@ -13,6 +13,7 @@ local SCADA_MGMT_TYPE = comms.SCADA_MGMT_TYPE
local SCADA_CRDN_TYPE = comms.SCADA_CRDN_TYPE
local UNIT_COMMAND = comms.UNIT_COMMAND
local FAC_COMMAND = comms.FAC_COMMAND
local RTU_UNIT_TYPE = types.RTU_UNIT_TYPE
local SV_Q_CMDS = svqtypes.SV_Q_CMDS
@@ -46,6 +47,7 @@ local PERIODICS = {
}
-- coordinator supervisor session
---@nodiscard
---@param id integer session ID
---@param in_queue mqueue in message queue
---@param out_queue mqueue out message queue
@@ -55,8 +57,6 @@ function coordinator.new_session(id, in_queue, out_queue, timeout, facility)
local log_header = "crdn_session(" .. id .. "): "
local self = {
in_q = in_queue,
out_q = out_queue,
units = facility.get_units(),
-- connection properties
seq_num = 0,
@@ -100,7 +100,7 @@ function coordinator.new_session(id, in_queue, out_queue, timeout, facility)
c_pkt.make(msg_type, msg)
s_pkt.make(self.seq_num, PROTOCOL.SCADA_CRDN, c_pkt.raw_sendable())
self.out_q.push_packet(s_pkt)
out_queue.push_packet(s_pkt)
self.seq_num = self.seq_num + 1
end
@@ -114,7 +114,7 @@ function coordinator.new_session(id, in_queue, out_queue, timeout, facility)
m_pkt.make(msg_type, msg)
s_pkt.make(self.seq_num, PROTOCOL.SCADA_MGMT, m_pkt.raw_sendable())
self.out_q.push_packet(s_pkt)
out_queue.push_packet(s_pkt)
self.seq_num = self.seq_num + 1
end
@@ -275,14 +275,14 @@ function coordinator.new_session(id, in_queue, out_queue, timeout, facility)
local unit = self.units[uid] ---@type reactor_unit
if cmd == UNIT_COMMAND.START then
self.out_q.push_data(SV_Q_DATA.START, data)
out_queue.push_data(SV_Q_DATA.START, data)
elseif cmd == UNIT_COMMAND.SCRAM then
self.out_q.push_data(SV_Q_DATA.SCRAM, data)
out_queue.push_data(SV_Q_DATA.SCRAM, data)
elseif cmd == UNIT_COMMAND.RESET_RPS then
self.out_q.push_data(SV_Q_DATA.RESET_RPS, data)
out_queue.push_data(SV_Q_DATA.RESET_RPS, data)
elseif cmd == UNIT_COMMAND.SET_BURN then
if pkt.length == 3 then
self.out_q.push_data(SV_Q_DATA.SET_BURN, data)
out_queue.push_data(SV_Q_DATA.SET_BURN, data)
else
log.debug(log_header .. "CRDN unit command burn rate missing option")
end
@@ -333,9 +333,11 @@ function coordinator.new_session(id, in_queue, out_queue, timeout, facility)
local public = {}
-- get the session ID
---@nodiscard
function public.get_id() return id end
-- check if a timer matches this session's watchdog
---@nodiscard
function public.check_wd(timer)
return self.conn_watchdog.is_timer(timer) and self.connected
end
@@ -349,6 +351,7 @@ function coordinator.new_session(id, in_queue, out_queue, timeout, facility)
end
-- iterate the session
---@nodiscard
---@return boolean connected
function public.iterate()
if self.connected then
@@ -358,9 +361,9 @@ function coordinator.new_session(id, in_queue, out_queue, timeout, facility)
local handle_start = util.time()
while self.in_q.ready() and self.connected do
while in_queue.ready() and self.connected do
-- get a new message to process
local message = self.in_q.pop()
local message = in_queue.pop()
if message ~= nil then
if message.qtype == mqueue.TYPE.PACKET then

View File

@@ -12,7 +12,6 @@ local PROTOCOL = comms.PROTOCOL
local RPLC_TYPE = comms.RPLC_TYPE
local SCADA_MGMT_TYPE = comms.SCADA_MGMT_TYPE
local PLC_AUTO_ACK = comms.PLC_AUTO_ACK
local UNIT_COMMAND = comms.UNIT_COMMAND
local print = util.print
@@ -47,18 +46,16 @@ local PERIODICS = {
}
-- PLC supervisor session
---@nodiscard
---@param id integer session ID
---@param for_reactor integer reactor ID
---@param reactor_id integer reactor ID
---@param in_queue mqueue in message queue
---@param out_queue mqueue out message queue
---@param timeout number communications timeout
function plc.new_session(id, for_reactor, in_queue, out_queue, timeout)
function plc.new_session(id, reactor_id, in_queue, out_queue, timeout)
local log_header = "plc_session(" .. id .. "): "
local self = {
for_reactor = for_reactor,
in_q = in_queue,
out_q = out_queue,
commanded_state = false,
commanded_burn_rate = 0.0,
auto_cmd_token = 0,
@@ -250,10 +247,10 @@ function plc.new_session(id, for_reactor, in_queue, out_queue, timeout)
local s_pkt = comms.scada_packet()
local r_pkt = comms.rplc_packet()
r_pkt.make(for_reactor, msg_type, msg)
r_pkt.make(reactor_id, msg_type, msg)
s_pkt.make(self.seq_num, PROTOCOL.RPLC, r_pkt.raw_sendable())
self.out_q.push_packet(s_pkt)
out_queue.push_packet(s_pkt)
self.seq_num = self.seq_num + 1
end
@@ -267,11 +264,12 @@ function plc.new_session(id, for_reactor, in_queue, out_queue, timeout)
m_pkt.make(msg_type, msg)
s_pkt.make(self.seq_num, PROTOCOL.SCADA_MGMT, m_pkt.raw_sendable())
self.out_q.push_packet(s_pkt)
out_queue.push_packet(s_pkt)
self.seq_num = self.seq_num + 1
end
-- get an ACK status
---@nodiscard
---@param pkt rplc_frame
---@return boolean|nil ack
local function _get_ack(pkt)
@@ -299,8 +297,8 @@ function plc.new_session(id, for_reactor, in_queue, out_queue, timeout)
-- process packet
if pkt.scada_frame.protocol() == PROTOCOL.RPLC then
-- check reactor ID
if pkt.id ~= for_reactor then
log.warning(log_header .. "RPLC packet with ID not matching reactor ID: reactor " .. self.for_reactor .. " != " .. pkt.id)
if pkt.id ~= reactor_id then
log.warning(log_header .. "RPLC packet with ID not matching reactor ID: reactor " .. reactor_id .. " != " .. pkt.id)
return
end
@@ -342,7 +340,7 @@ function plc.new_session(id, for_reactor, in_queue, out_queue, timeout)
if status then
-- copied in structure data OK
self.received_struct = true
self.out_q.push_data(svqtypes.SV_Q_DATA.PLC_BUILD_CHANGED, for_reactor)
out_queue.push_data(svqtypes.SV_Q_DATA.PLC_BUILD_CHANGED, reactor_id)
else
-- error copying structure data
log.error(log_header .. "failed to parse struct packet data")
@@ -360,8 +358,8 @@ function plc.new_session(id, for_reactor, in_queue, out_queue, timeout)
end
-- send acknowledgement to coordinator
self.out_q.push_data(svqtypes.SV_Q_DATA.CRDN_ACK, {
unit = self.for_reactor,
out_queue.push_data(svqtypes.SV_Q_DATA.CRDN_ACK, {
unit = reactor_id,
cmd = UNIT_COMMAND.SET_BURN,
ack = ack
})
@@ -375,8 +373,8 @@ function plc.new_session(id, for_reactor, in_queue, out_queue, timeout)
end
-- send acknowledgement to coordinator
self.out_q.push_data(svqtypes.SV_Q_DATA.CRDN_ACK, {
unit = self.for_reactor,
out_queue.push_data(svqtypes.SV_Q_DATA.CRDN_ACK, {
unit = reactor_id,
cmd = UNIT_COMMAND.START,
ack = ack
})
@@ -391,8 +389,8 @@ function plc.new_session(id, for_reactor, in_queue, out_queue, timeout)
end
-- send acknowledgement to coordinator
self.out_q.push_data(svqtypes.SV_Q_DATA.CRDN_ACK, {
unit = self.for_reactor,
out_queue.push_data(svqtypes.SV_Q_DATA.CRDN_ACK, {
unit = reactor_id,
cmd = UNIT_COMMAND.SCRAM,
ack = ack
})
@@ -443,8 +441,8 @@ function plc.new_session(id, for_reactor, in_queue, out_queue, timeout)
end
-- send acknowledgement to coordinator
self.out_q.push_data(svqtypes.SV_Q_DATA.CRDN_ACK, {
unit = self.for_reactor,
out_queue.push_data(svqtypes.SV_Q_DATA.CRDN_ACK, {
unit = reactor_id,
cmd = UNIT_COMMAND.RESET_RPS,
ack = ack
})
@@ -503,17 +501,22 @@ function plc.new_session(id, for_reactor, in_queue, out_queue, timeout)
-- PUBLIC FUNCTIONS --
-- get the session ID
---@nodiscard
function public.get_id() return id end
-- get the session database
---@nodiscard
function public.get_db() return self.sDB end
-- check if ramping is completed by first verifying auto command token ack
---@nodiscard
function public.is_ramp_complete()
return (self.sDB.auto_ack_token == self.auto_cmd_token) and (self.commanded_burn_rate == self.sDB.mek_status.act_burn_rate)
end
-- get the reactor structure
---@nodiscard
---@return mek_struct|table struct struct or empty table
function public.get_struct()
if self.received_struct then
return self.sDB.mek_struct
@@ -523,6 +526,8 @@ function plc.new_session(id, for_reactor, in_queue, out_queue, timeout)
end
-- get the reactor status
---@nodiscard
---@return mek_status|table struct status or empty table
function public.get_status()
if self.received_status_cache then
return self.sDB.mek_status
@@ -532,11 +537,13 @@ function plc.new_session(id, for_reactor, in_queue, out_queue, timeout)
end
-- get the reactor RPS status
---@nodiscard
function public.get_rps()
return self.sDB.rps_status
end
-- get the general status information
---@nodiscard
function public.get_general_status()
return {
self.sDB.last_status_update,
@@ -564,10 +571,11 @@ function plc.new_session(id, for_reactor, in_queue, out_queue, timeout)
---@param ramp boolean true to ramp, false to not
function public.auto_set_burn(rate, ramp)
self.ramping_rate = ramp
self.in_q.push_data(PLC_S_DATA.AUTO_BURN_RATE, rate)
in_queue.push_data(PLC_S_DATA.AUTO_BURN_RATE, rate)
end
-- check if a timer matches this session's watchdog
---@nodiscard
function public.check_wd(timer)
return self.plc_conn_watchdog.is_timer(timer) and self.connected
end
@@ -576,11 +584,12 @@ function plc.new_session(id, for_reactor, in_queue, out_queue, timeout)
function public.close()
_close()
_send_mgmt(SCADA_MGMT_TYPE.CLOSE, {})
println("connection to reactor " .. self.for_reactor .. " PLC closed by server")
println("connection to reactor " .. reactor_id .. " PLC closed by server")
log.info(log_header .. "session closed by server")
end
-- iterate the session
---@nodiscard
---@return boolean connected
function public.iterate()
if self.connected then
@@ -590,9 +599,9 @@ function plc.new_session(id, for_reactor, in_queue, out_queue, timeout)
local handle_start = util.time()
while self.in_q.ready() and self.connected do
while in_queue.ready() and self.connected do
-- get a new message to process
local message = self.in_q.pop()
local message = in_queue.pop()
if message ~= nil then
if message.qtype == mqueue.TYPE.PACKET then
@@ -688,7 +697,7 @@ function plc.new_session(id, for_reactor, in_queue, out_queue, timeout)
-- exit if connection was closed
if not self.connected then
println("connection to reactor " .. self.for_reactor .. " PLC closed by remote host")
println("connection to reactor " .. reactor_id .. " PLC closed by remote host")
log.info(log_header .. "session closed by remote host")
return self.connected
end

View File

@@ -5,6 +5,7 @@
local rsctl = {}
-- create a new redstone RTU I/O controller
---@nodiscard
---@param redstone_rtus table redstone RTU sessions
function rsctl.new(redstone_rtus)
---@class rs_controller

View File

@@ -32,6 +32,7 @@ local PERIODICS = {
}
-- create a new RTU session
---@nodiscard
---@param id integer session ID
---@param in_queue mqueue in message queue
---@param out_queue mqueue out message queue
@@ -42,8 +43,6 @@ function rtu.new_session(id, in_queue, out_queue, timeout, advertisement, facili
local log_header = "rtu_session(" .. id .. "): "
local self = {
in_q = in_queue,
out_q = out_queue,
modbus_q = mqueue.new(),
advert = advertisement,
fac_units = facility.get_units(),
@@ -196,7 +195,7 @@ function rtu.new_session(id, in_queue, out_queue, timeout, advertisement, facili
s_pkt.make(self.seq_num, PROTOCOL.MODBUS_TCP, m_pkt.raw_sendable())
self.out_q.push_packet(s_pkt)
out_queue.push_packet(s_pkt)
self.seq_num = self.seq_num + 1
end
@@ -210,7 +209,7 @@ function rtu.new_session(id, in_queue, out_queue, timeout, advertisement, facili
m_pkt.make(msg_type, msg)
s_pkt.make(self.seq_num, PROTOCOL.SCADA_MGMT, m_pkt.raw_sendable())
self.out_q.push_packet(s_pkt)
out_queue.push_packet(s_pkt)
self.seq_num = self.seq_num + 1
end
@@ -262,10 +261,7 @@ function rtu.new_session(id, in_queue, out_queue, timeout, advertisement, facili
elseif pkt.type == SCADA_MGMT_TYPE.RTU_ADVERT then
-- RTU unit advertisement
log.debug(log_header .. "received updated advertisement")
-- copy advertisement and remove version tag
self.advert = pkt.data
table.remove(self.advert, 1)
-- handle advertisement; this will re-create all unit sub-sessions
_handle_advertisement()
@@ -291,6 +287,7 @@ function rtu.new_session(id, in_queue, out_queue, timeout, advertisement, facili
function public.get_id() return id end
-- check if a timer matches this session's watchdog
---@nodiscard
---@param timer number
function public.check_wd(timer)
return self.rtu_conn_watchdog.is_timer(timer) and self.connected
@@ -305,6 +302,7 @@ function rtu.new_session(id, in_queue, out_queue, timeout, advertisement, facili
end
-- iterate the session
---@nodiscard
---@return boolean connected
function public.iterate()
if self.connected then
@@ -314,9 +312,9 @@ function rtu.new_session(id, in_queue, out_queue, timeout, advertisement, facili
local handle_start = util.time()
while self.in_q.ready() and self.connected do
while in_queue.ready() and self.connected do
-- get a new message to process
local msg = self.in_q.pop()
local msg = in_queue.pop()
if msg ~= nil then
if msg.qtype == mqueue.TYPE.PACKET then
@@ -389,7 +387,7 @@ function rtu.new_session(id, in_queue, out_queue, timeout, advertisement, facili
-- instruction with body
local cmd = msg.message ---@type queue_data
if cmd.key == unit_session.RTU_US_DATA.BUILD_CHANGED then
self.out_q.push_data(svqtypes.SV_Q_DATA.RTU_BUILD_CHANGED, cmd.val)
out_queue.push_data(svqtypes.SV_Q_DATA.RTU_BUILD_CHANGED, cmd.val)
end
end
end

View File

@@ -31,6 +31,7 @@ local PERIODICS = {
}
-- create a new boilerv rtu session runner
---@nodiscard
---@param session_id integer RTU session ID
---@param unit_id integer RTU unit ID
---@param advert rtu_advertisement RTU advertisement table
@@ -238,6 +239,7 @@ function boilerv.new(session_id, unit_id, advert, out_queue)
end
-- get the unit session database
---@nodiscard
function public.get_db() return self.db end
return public

View File

@@ -22,6 +22,7 @@ local PERIODICS = {
}
-- create a new environment detector rtu session runner
---@nodiscard
---@param session_id integer
---@param unit_id integer
---@param advert rtu_advertisement
@@ -99,6 +100,7 @@ function envd.new(session_id, unit_id, advert, out_queue)
end
-- get the unit session database
---@nodiscard
function public.get_db() return self.db end
return public

View File

@@ -31,6 +31,7 @@ local PERIODICS = {
}
-- create a new imatrix rtu session runner
---@nodiscard
---@param session_id integer RTU session ID
---@param unit_id integer RTU unit ID
---@param advert rtu_advertisement RTU advertisement table
@@ -212,6 +213,7 @@ function imatrix.new(session_id, unit_id, advert, out_queue)
end
-- get the unit session database
---@nodiscard
function public.get_db() return self.db end
return public

View File

@@ -45,6 +45,7 @@ local PERIODICS = {
---@field req IO_LVL
-- create a new redstone rtu session runner
---@nodiscard
---@param session_id integer
---@param unit_id integer
---@param advert rtu_advertisement
@@ -118,6 +119,7 @@ function redstone.new(session_id, unit_id, advert, out_queue)
---@class rs_db_dig_io
local io_f = {
---@nodiscard
read = function () return rsio.digital_is_active(port, self.phy_io.digital_in[port].phy) end,
---@param active boolean
write = function (active) end
@@ -132,6 +134,7 @@ function redstone.new(session_id, unit_id, advert, out_queue)
---@class rs_db_dig_io
local io_f = {
---@nodiscard
read = function () return rsio.digital_is_active(port, self.phy_io.digital_out[port].phy) end,
---@param active boolean
write = function (active)
@@ -149,6 +152,7 @@ function redstone.new(session_id, unit_id, advert, out_queue)
---@class rs_db_ana_io
local io_f = {
---@nodiscard
---@return integer
read = function () return self.phy_io.analog_in[port].phy end,
---@param value integer
@@ -164,6 +168,7 @@ function redstone.new(session_id, unit_id, advert, out_queue)
---@class rs_db_ana_io
local io_f = {
---@nodiscard
---@return integer
read = function () return self.phy_io.analog_out[port].phy end,
---@param value integer
@@ -378,6 +383,7 @@ function redstone.new(session_id, unit_id, advert, out_queue)
end
-- get the unit session database
---@nodiscard
function public.get_db() return self.db end
return public

View File

@@ -28,6 +28,7 @@ local PERIODICS = {
}
-- create a new sna rtu session runner
---@nodiscard
---@param session_id integer RTU session ID
---@param unit_id integer RTU unit ID
---@param advert rtu_advertisement RTU advertisement table
@@ -175,6 +176,7 @@ function sna.new(session_id, unit_id, advert, out_queue)
end
-- get the unit session database
---@nodiscard
function public.get_db() return self.db end
return public

View File

@@ -31,6 +31,7 @@ local PERIODICS = {
}
-- create a new sps rtu session runner
---@nodiscard
---@param session_id integer RTU session ID
---@param unit_id integer RTU unit ID
---@param advert rtu_advertisement RTU advertisement table
@@ -112,7 +113,7 @@ function sps.new(session_id, unit_id, advert, out_queue)
-- query the tanks of the device
local function _request_tanks()
-- read input registers 11 through 19 (start = 11, count = 9)
self.session.send_request(TXN_TYPES.TANKS, MODBUS_FCODE.READ_INPUT_REGS, { 10, 12 })
self.session.send_request(TXN_TYPES.TANKS, MODBUS_FCODE.READ_INPUT_REGS, { 11, 9 })
end
-- PUBLIC FUNCTIONS --
@@ -222,6 +223,7 @@ function sps.new(session_id, unit_id, advert, out_queue)
end
-- get the unit session database
---@nodiscard
function public.get_db() return self.db end
return public

View File

@@ -43,6 +43,7 @@ local PERIODICS = {
}
-- create a new turbinev rtu session runner
---@nodiscard
---@param session_id integer RTU session ID
---@param unit_id integer RTU unit ID
---@param advert rtu_advertisement RTU advertisement table
@@ -309,6 +310,7 @@ function turbinev.new(session_id, unit_id, advert, out_queue)
end
-- get the unit session database
---@nodiscard
function public.get_db() return self.db end
return public

View File

@@ -6,9 +6,10 @@ local util = require("scada-common.util")
local txnctrl = {}
local TIMEOUT = 2000 -- 2000ms max wait
local TIMEOUT = 2000 -- 2000ms max wait
-- create a new transaction controller
---@nodiscard
function txnctrl.new()
local self = {
list = {},
@@ -22,16 +23,19 @@ function txnctrl.new()
local remove = table.remove
-- get the length of the transaction list
---@nodiscard
function public.length()
return #self.list
end
-- check if there are no active transactions
---@nodiscard
function public.empty()
return #self.list == 0
end
-- create a new transaction of the given type
---@nodiscard
---@param txn_type integer
---@return integer txn_id
function public.create(txn_type)
@@ -49,6 +53,7 @@ function txnctrl.new()
end
-- mark a transaction as resolved to get its transaction type
---@nodiscard
---@param txn_id integer
---@return integer txn_type
function public.resolve(txn_id)

View File

@@ -23,6 +23,7 @@ unit_session.RTU_US_CMDS = RTU_US_CMDS
unit_session.RTU_US_DATA = RTU_US_DATA
-- create a new unit session runner
---@nodiscard
---@param session_id integer RTU session ID
---@param unit_id integer MODBUS unit ID
---@param advert rtu_advertisement RTU advertisement for this unit
@@ -31,12 +32,8 @@ unit_session.RTU_US_DATA = RTU_US_DATA
---@param txn_tags table transaction log tags
function unit_session.new(session_id, unit_id, advert, out_queue, log_tag, txn_tags)
local self = {
log_tag = log_tag,
txn_tags = txn_tags,
unit_id = unit_id,
device_index = advert.index,
reactor = advert.reactor,
out_q = out_queue,
transaction_controller = txnctrl.new(),
connected = true,
device_fail = false
@@ -61,21 +58,22 @@ function unit_session.new(session_id, unit_id, advert, out_queue, log_tag, txn_t
local m_pkt = comms.modbus_packet()
local txn_id = self.transaction_controller.create(txn_type)
m_pkt.make(txn_id, self.unit_id, f_code, register_param)
m_pkt.make(txn_id, unit_id, f_code, register_param)
self.out_q.push_packet(m_pkt)
out_queue.push_packet(m_pkt)
return txn_id
end
-- try to resolve a MODBUS transaction
---@nodiscard
---@param m_pkt modbus_frame MODBUS packet
---@return integer|false txn_type, integer txn_id transaction type or false on error/busy, transaction ID
function protected.try_resolve(m_pkt)
if m_pkt.scada_frame.protocol() == PROTOCOL.MODBUS_TCP then
if m_pkt.unit_id == self.unit_id then
if m_pkt.unit_id == unit_id then
local txn_type = self.transaction_controller.resolve(m_pkt.txn_id)
local txn_tag = " (" .. util.strval(self.txn_tags[txn_type]) .. ")"
local txn_tag = " (" .. util.strval(txn_tags[txn_type]) .. ")"
if bit.band(m_pkt.func_code, MODBUS_FCODE.ERROR_FLAG) ~= 0 then
-- transaction incomplete or failed
@@ -135,26 +133,35 @@ function unit_session.new(session_id, unit_id, advert, out_queue, log_tag, txn_t
end
-- get the public interface
---@nodiscard
function protected.get() return public end
-- PUBLIC FUNCTIONS --
-- get the unit ID
---@nodiscard
function public.get_session_id() return session_id end
-- get the unit ID
function public.get_unit_id() return self.unit_id end
---@nodiscard
function public.get_unit_id() return unit_id end
-- get the device index
---@nodiscard
function public.get_device_idx() return self.device_index end
-- get the reactor ID
---@nodiscard
function public.get_reactor() return self.reactor end
-- get the command queue
---@nodiscard
function public.get_cmd_queue() return protected.in_q end
-- close this unit
---@nodiscard
function public.close() self.connected = false end
-- check if this unit is connected
---@nodiscard
function public.is_connected() return self.connected end
-- check if this unit is faulted
---@nodiscard
function public.is_faulted() return self.device_fail end
-- PUBLIC TEMPLATE FUNCTIONS --
@@ -179,6 +186,7 @@ function unit_session.new(session_id, unit_id, advert, out_queue, log_tag, txn_t
end
-- get the unit session database
---@nodiscard
function public.get_db()
log.debug("template unit_session.get_db() called", true)
return {}

View File

@@ -183,9 +183,10 @@ local function _free_closed(sessions)
end
-- find a session by remote port
---@nodiscard
---@param list table
---@param port integer
---@return plc_session_struct|rtu_session_struct|nil
---@return plc_session_struct|rtu_session_struct|coord_session_struct|nil
local function _find_session(list, port)
for i = 1, #list do
if list[i].r_port == port then return list[i] end
@@ -212,54 +213,63 @@ function svsessions.relink_modem(modem)
end
-- find an RTU session by the remote port
---@nodiscard
---@param remote_port integer
---@return rtu_session_struct|nil
function svsessions.find_rtu_session(remote_port)
-- check RTU sessions
---@diagnostic disable-next-line: return-type-mismatch
return _find_session(self.rtu_sessions, remote_port)
local session = _find_session(self.rtu_sessions, remote_port)
---@cast session rtu_session_struct
return session
end
-- find a PLC session by the remote port
---@nodiscard
---@param remote_port integer
---@return plc_session_struct|nil
function svsessions.find_plc_session(remote_port)
-- check PLC sessions
---@diagnostic disable-next-line: return-type-mismatch
return _find_session(self.plc_sessions, remote_port)
local session = _find_session(self.plc_sessions, remote_port)
---@cast session plc_session_struct
return session
end
-- find a PLC/RTU session by the remote port
---@nodiscard
---@param remote_port integer
---@return plc_session_struct|rtu_session_struct|nil
function svsessions.find_device_session(remote_port)
-- check RTU sessions
local s = _find_session(self.rtu_sessions, remote_port)
local session = _find_session(self.rtu_sessions, remote_port)
-- check PLC sessions
if s == nil then s = _find_session(self.plc_sessions, remote_port) end
if session == nil then session = _find_session(self.plc_sessions, remote_port) end
---@cast session plc_session_struct|rtu_session_struct|nil
return s
return session
end
-- find a coordinator session by the remote port
--
-- find a coordinator session by the remote port<br>
-- only one coordinator is allowed, but this is kept to be consistent with all other session tables
---@nodiscard
---@param remote_port integer
---@return nil
---@return coord_session_struct|nil
function svsessions.find_coord_session(remote_port)
-- check coordinator sessions
---@diagnostic disable-next-line: return-type-mismatch
return _find_session(self.coord_sessions, remote_port)
local session = _find_session(self.coord_sessions, remote_port)
---@cast session coord_session_struct
return session
end
-- get the a coordinator session if exists
---@nodiscard
---@return coord_session_struct|nil
function svsessions.get_coord_session()
return self.coord_sessions[1]
end
-- get a session by reactor ID
---@nodiscard
---@param reactor integer
---@return plc_session_struct|nil session
function svsessions.get_reactor_session(reactor)
@@ -275,6 +285,7 @@ function svsessions.get_reactor_session(reactor)
end
-- establish a new PLC session
---@nodiscard
---@param local_port integer
---@param remote_port integer
---@param for_reactor integer
@@ -314,6 +325,7 @@ function svsessions.establish_plc_session(local_port, remote_port, for_reactor,
end
-- establish a new RTU session
---@nodiscard
---@param local_port integer
---@param remote_port integer
---@param advertisement table
@@ -344,6 +356,7 @@ function svsessions.establish_rtu_session(local_port, remote_port, advertisement
end
-- establish a new coordinator session
---@nodiscard
---@param local_port integer
---@param remote_port integer
---@param version string