mirror of
https://github.com/MikaylaFischler/cc-mek-scada.git
synced 2024-08-30 18:22:34 +00:00
#74 work on coordinator comms
This commit is contained in:
parent
2e4a533148
commit
b628472d81
@ -6,13 +6,19 @@ local util = require("scada-common.util")
|
||||
|
||||
local dialog = require("coordinator.util.dialog")
|
||||
|
||||
local coordinator = {}
|
||||
|
||||
local print = util.print
|
||||
local println = util.println
|
||||
local print_ts = util.print_ts
|
||||
local println_ts = util.println_ts
|
||||
|
||||
local coordinator = {}
|
||||
local PROTOCOLS = comms.PROTOCOLS
|
||||
local SCADA_MGMT_TYPES = comms.SCADA_MGMT_TYPES
|
||||
local COORD_TYPES = comms.COORD_TYPES
|
||||
|
||||
-- request the user to select a monitor
|
||||
---@param names table available monitors
|
||||
local function ask_monitor(names)
|
||||
println("available monitors:")
|
||||
for i = 1, #names do
|
||||
@ -30,6 +36,8 @@ local function ask_monitor(names)
|
||||
return iface
|
||||
end
|
||||
|
||||
-- configure monitor layout
|
||||
---@param num_units integer number of units expected
|
||||
function coordinator.configure_monitors(num_units)
|
||||
---@class monitors_struct
|
||||
local monitors = {
|
||||
@ -135,10 +143,162 @@ function coordinator.configure_monitors(num_units)
|
||||
end
|
||||
|
||||
-- coordinator communications
|
||||
function coordinator.coord_comms()
|
||||
---@param conn_watchdog watchdog
|
||||
function coordinator.coord_comms(version, num_reactors, modem, sv_port, sv_listen, api_listen, conn_watchdog)
|
||||
local self = {
|
||||
reactor_struct_cache = nil
|
||||
seq_num = 0,
|
||||
r_seq_num = nil,
|
||||
modem = modem,
|
||||
connected = false
|
||||
}
|
||||
|
||||
---@class coord_comms
|
||||
local public = {}
|
||||
|
||||
-- PRIVATE FUNCTIONS --
|
||||
|
||||
-- open all channels
|
||||
local function _open_channels()
|
||||
if not self.modem.isOpen(sv_listen) then
|
||||
self.modem.open(sv_listen)
|
||||
end
|
||||
|
||||
if not self.modem.isOpen(api_listen) then
|
||||
self.modem.open(api_listen)
|
||||
end
|
||||
end
|
||||
|
||||
-- open at construct time
|
||||
_open_channels()
|
||||
|
||||
-- send a coordinator packet
|
||||
---@param msg_type COORD_TYPES
|
||||
---@param msg string
|
||||
local function _send(msg_type, msg)
|
||||
local s_pkt = comms.scada_packet()
|
||||
local c_pkt = comms.coord_packet()
|
||||
|
||||
c_pkt.make(msg_type, msg)
|
||||
s_pkt.make(self.seq_num, PROTOCOLS.COORD_DATA, c_pkt.raw_sendable())
|
||||
|
||||
self.modem.transmit(sv_port, sv_listen, s_pkt.raw_sendable())
|
||||
self.seq_num = self.seq_num + 1
|
||||
end
|
||||
|
||||
-- send a SCADA management packet
|
||||
---@param msg_type SCADA_MGMT_TYPES
|
||||
---@param msg string
|
||||
local function _send_mgmt(msg_type, msg)
|
||||
local s_pkt = comms.scada_packet()
|
||||
local m_pkt = comms.mgmt_packet()
|
||||
|
||||
m_pkt.make(msg_type, msg)
|
||||
s_pkt.make(self.seq_num, PROTOCOLS.SCADA_MGMT, m_pkt.raw_sendable())
|
||||
|
||||
self.modem.transmit(sv_port, sv_listen, s_pkt.raw_sendable())
|
||||
self.seq_num = self.seq_num + 1
|
||||
end
|
||||
|
||||
-- PUBLIC FUNCTIONS --
|
||||
|
||||
-- reconnect a newly connected modem
|
||||
---@param modem table
|
||||
---@diagnostic disable-next-line: redefined-local
|
||||
function public.reconnect_modem(modem)
|
||||
self.modem = modem
|
||||
_open_channels()
|
||||
end
|
||||
|
||||
-- parse a packet
|
||||
---@param side string
|
||||
---@param sender integer
|
||||
---@param reply_to integer
|
||||
---@param message any
|
||||
---@param distance integer
|
||||
---@return mgmt_frame|coord_frame|capi_frame|nil packet
|
||||
function public.parse_packet(side, sender, reply_to, message, distance)
|
||||
local pkt = nil
|
||||
local s_pkt = comms.scada_packet()
|
||||
|
||||
-- parse packet as generic SCADA packet
|
||||
s_pkt.receive(side, sender, reply_to, message, distance)
|
||||
|
||||
if s_pkt.is_valid() then
|
||||
-- get as SCADA management packet
|
||||
if s_pkt.protocol() == PROTOCOLS.SCADA_MGMT then
|
||||
local mgmt_pkt = comms.mgmt_packet()
|
||||
if mgmt_pkt.decode(s_pkt) then
|
||||
pkt = mgmt_pkt.get()
|
||||
end
|
||||
-- get as coordinator packet
|
||||
elseif s_pkt.protocol() == PROTOCOLS.COORD_DATA then
|
||||
local coord_pkt = comms.coord_packet()
|
||||
if coord_pkt.decode(s_pkt) then
|
||||
pkt = coord_pkt.get()
|
||||
end
|
||||
-- get as coordinator API packet
|
||||
elseif s_pkt.protocol() == PROTOCOLS.COORD_API then
|
||||
local capi_pkt = comms.capi_packet()
|
||||
if capi_pkt.decode(s_pkt) then
|
||||
pkt = capi_pkt.get()
|
||||
end
|
||||
else
|
||||
log.debug("attempted parse of illegal packet type " .. s_pkt.protocol(), true)
|
||||
end
|
||||
end
|
||||
|
||||
return pkt
|
||||
end
|
||||
|
||||
-- handle a packet
|
||||
---@param packet mgmt_frame|coord_frame|capi_frame
|
||||
function public.handle_packet(packet)
|
||||
if packet ~= nil then
|
||||
-- check sequence number
|
||||
if self.r_seq_num == nil then
|
||||
self.r_seq_num = packet.scada_frame.seq_num()
|
||||
elseif self.connected and self.r_seq_num >= packet.scada_frame.seq_num() then
|
||||
log.warning("sequence out-of-order: last = " .. self.r_seq_num .. ", new = " .. packet.scada_frame.seq_num())
|
||||
return
|
||||
else
|
||||
self.r_seq_num = packet.scada_frame.seq_num()
|
||||
end
|
||||
|
||||
-- feed watchdog on valid sequence number
|
||||
conn_watchdog.feed()
|
||||
|
||||
local protocol = packet.scada_frame.protocol()
|
||||
|
||||
-- handle packet
|
||||
if protocol == PROTOCOLS.COORD_DATA then
|
||||
if packet.type == COORD_TYPES.ESTABLISH then
|
||||
elseif packet.type == COORD_TYPES.QUERY_UNIT then
|
||||
elseif packet.type == COORD_TYPES.QUERY_FACILITY then
|
||||
elseif packet.type == COORD_TYPES.COMMAND_UNIT then
|
||||
elseif packet.type == COORD_TYPES.ALARM then
|
||||
else
|
||||
log.warning("received unknown coordinator data packet type " .. packet.type)
|
||||
end
|
||||
elseif protocol == PROTOCOLS.COORD_API then
|
||||
elseif protocol == PROTOCOLS.SCADA_MGMT then
|
||||
if packet.type == SCADA_MGMT_TYPES.KEEP_ALIVE then
|
||||
-- keep alive response received
|
||||
elseif packet.type == SCADA_MGMT_TYPES.CLOSE then
|
||||
-- handle session close
|
||||
conn_watchdog.cancel()
|
||||
println_ts("server connection closed by remote host")
|
||||
log.warning("server connection closed by remote host")
|
||||
else
|
||||
log.warning("received unknown SCADA_MGMT packet type " .. packet.type)
|
||||
end
|
||||
else
|
||||
-- should be unreachable assuming packet is from parse_packet()
|
||||
log.error("illegal packet type " .. protocol, true)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return public
|
||||
end
|
||||
|
||||
return coordinator
|
||||
|
@ -48,6 +48,15 @@ local SCADA_MGMT_TYPES = {
|
||||
REMOTE_LINKED = 3 -- remote device linked
|
||||
}
|
||||
|
||||
---@alias COORD_TYPES integer
|
||||
local COORD_TYPES = {
|
||||
ESTABLISH = 0, -- initial greeting
|
||||
QUERY_UNIT = 1, -- query the state of a unit
|
||||
QUERY_FACILITY = 2, -- query general facility status
|
||||
COMMAND_UNIT = 3, -- command a reactor unit
|
||||
ALARM = 4 -- alarm signaling
|
||||
}
|
||||
|
||||
---@alias RTU_UNIT_TYPES integer
|
||||
local RTU_UNIT_TYPES = {
|
||||
REDSTONE = 0, -- redstone I/O
|
||||
@ -66,6 +75,7 @@ comms.PROTOCOLS = PROTOCOLS
|
||||
comms.RPLC_TYPES = RPLC_TYPES
|
||||
comms.RPLC_LINKING = RPLC_LINKING
|
||||
comms.SCADA_MGMT_TYPES = SCADA_MGMT_TYPES
|
||||
comms.COORD_TYPES = COORD_TYPES
|
||||
comms.RTU_UNIT_TYPES = RTU_UNIT_TYPES
|
||||
|
||||
-- generic SCADA packet object
|
||||
@ -436,9 +446,13 @@ function comms.coord_packet()
|
||||
---@class coord_packet
|
||||
local public = {}
|
||||
|
||||
-- check that type is known
|
||||
local function _coord_type_valid()
|
||||
-- @todo
|
||||
return false
|
||||
return self.type == COORD_TYPES.ESTABLISH or
|
||||
self.type == COORD_TYPES.QUERY_UNIT or
|
||||
self.type == COORD_TYPES.QUERY_FACILITY or
|
||||
self.type == COORD_TYPES.COMMAND_UNIT or
|
||||
self.type == COORD_TYPES.ALARM
|
||||
end
|
||||
|
||||
-- make a coordinator packet
|
||||
|
Loading…
Reference in New Issue
Block a user