mirror of
https://github.com/MikaylaFischler/cc-mek-scada.git
synced 2024-08-30 18:22:34 +00:00
#74 comms establish on boot
This commit is contained in:
parent
409e8083a7
commit
1444008479
@ -6,7 +6,7 @@ config.SCADA_SV_PORT = 16100
|
|||||||
config.SCADA_SV_LISTEN = 16101
|
config.SCADA_SV_LISTEN = 16101
|
||||||
-- listen port for SCADA coordinator API access
|
-- listen port for SCADA coordinator API access
|
||||||
config.SCADA_API_LISTEN = 16200
|
config.SCADA_API_LISTEN = 16200
|
||||||
-- expected number of reactor units
|
-- expected number of reactor units, used only to require that number of unit monitors
|
||||||
config.NUM_UNITS = 4
|
config.NUM_UNITS = 4
|
||||||
-- graphics color
|
-- graphics color
|
||||||
config.RECOLOR = true
|
config.RECOLOR = true
|
||||||
|
@ -1,19 +1,15 @@
|
|||||||
|
|
||||||
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 ppm = require("scada-common.ppm")
|
local ppm = require("scada-common.ppm")
|
||||||
local psil = require("scada-common.psil")
|
|
||||||
local util = require("scada-common.util")
|
local util = require("scada-common.util")
|
||||||
|
|
||||||
local apisessions = require("coordinator.apisessions")
|
local apisessions = require("coordinator.apisessions")
|
||||||
|
local database = require("coordinator.database")
|
||||||
|
|
||||||
local dialog = require("coordinator.util.dialog")
|
local dialog = require("coordinator.util.dialog")
|
||||||
|
|
||||||
local coordinator = {}
|
local coordinator = {}
|
||||||
|
|
||||||
---@class coord_db
|
|
||||||
local db = {}
|
|
||||||
|
|
||||||
local print = util.print
|
local print = util.print
|
||||||
local println = util.println
|
local println = util.println
|
||||||
local print_ts = util.print_ts
|
local print_ts = util.print_ts
|
||||||
@ -148,36 +144,12 @@ function coordinator.configure_monitors(num_units)
|
|||||||
return true, monitors
|
return true, monitors
|
||||||
end
|
end
|
||||||
|
|
||||||
-- initialize the coordinator database
|
|
||||||
---@param num_units integer number of units expected
|
|
||||||
function coordinator.init_database(num_units)
|
|
||||||
db.facility = {
|
|
||||||
num_units = num_units,
|
|
||||||
ps = psil.create()
|
|
||||||
}
|
|
||||||
|
|
||||||
db.units = {}
|
|
||||||
for i = 1, num_units do
|
|
||||||
table.insert(db.units, {
|
|
||||||
uint_id = i,
|
|
||||||
initialized = false,
|
|
||||||
|
|
||||||
reactor_ps = psil.create(),
|
|
||||||
reactor_data = {},
|
|
||||||
|
|
||||||
boiler_ps_tbl = {},
|
|
||||||
boiler_data_tbl = {},
|
|
||||||
|
|
||||||
turbine_ps_tbl = {},
|
|
||||||
turbine_data_tbl = {}
|
|
||||||
})
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
-- dmesg print wrapper
|
-- dmesg print wrapper
|
||||||
---@param message string message
|
---@param message string message
|
||||||
---@param dmesg_tag string tag
|
---@param dmesg_tag string tag
|
||||||
local function log_dmesg(message, dmesg_tag)
|
---@param working? boolean to use dmesg_working
|
||||||
|
---@return function? update, function? done
|
||||||
|
local function log_dmesg(message, dmesg_tag, working)
|
||||||
local colors = {
|
local colors = {
|
||||||
GRAPHICS = colors.green,
|
GRAPHICS = colors.green,
|
||||||
SYSTEM = colors.cyan,
|
SYSTEM = colors.cyan,
|
||||||
@ -185,14 +157,22 @@ local function log_dmesg(message, dmesg_tag)
|
|||||||
COMMS = colors.purple
|
COMMS = colors.purple
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if working then
|
||||||
|
return log.dmesg_working(message, dmesg_tag, colors[dmesg_tag])
|
||||||
|
else
|
||||||
log.dmesg(message, dmesg_tag, colors[dmesg_tag])
|
log.dmesg(message, dmesg_tag, colors[dmesg_tag])
|
||||||
end
|
end
|
||||||
|
end
|
||||||
|
|
||||||
function coordinator.log_graphics(message) log_dmesg(message, "GRAPHICS") end
|
function coordinator.log_graphics(message) log_dmesg(message, "GRAPHICS") end
|
||||||
function coordinator.log_sys(message) log_dmesg(message, "SYSTEM") end
|
function coordinator.log_sys(message) log_dmesg(message, "SYSTEM") end
|
||||||
function coordinator.log_boot(message) log_dmesg(message, "BOOT") end
|
function coordinator.log_boot(message) log_dmesg(message, "BOOT") end
|
||||||
function coordinator.log_comms(message) log_dmesg(message, "COMMS") end
|
function coordinator.log_comms(message) log_dmesg(message, "COMMS") end
|
||||||
|
|
||||||
|
---@param message string
|
||||||
|
---@return function update, function done
|
||||||
|
function coordinator.log_comms_connecting(message) return log_dmesg(message, "COMMS", true) end
|
||||||
|
|
||||||
-- coordinator communications
|
-- coordinator communications
|
||||||
---@param version string
|
---@param version string
|
||||||
---@param modem table
|
---@param modem table
|
||||||
@ -202,6 +182,7 @@ function coordinator.log_comms(message) log_dmesg(message, "COMMS") end
|
|||||||
---@param sv_watchdog watchdog
|
---@param sv_watchdog watchdog
|
||||||
function coordinator.comms(version, modem, sv_port, sv_listen, api_listen, sv_watchdog)
|
function coordinator.comms(version, modem, sv_port, sv_listen, api_listen, sv_watchdog)
|
||||||
local self = {
|
local self = {
|
||||||
|
sv_linked = false,
|
||||||
sv_seq_num = 0,
|
sv_seq_num = 0,
|
||||||
sv_r_seq_num = nil,
|
sv_r_seq_num = nil,
|
||||||
modem = modem,
|
modem = modem,
|
||||||
@ -259,6 +240,51 @@ function coordinator.comms(version, modem, sv_port, sv_listen, api_listen, sv_wa
|
|||||||
_open_channels()
|
_open_channels()
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- attempt to connect to the subervisor
|
||||||
|
---@param timeout_s number timeout in seconds
|
||||||
|
---@param tick_dmesg_waiting function callback to tick dmesg waiting
|
||||||
|
---@param task_done function callback to show done on dmesg
|
||||||
|
---@return boolean sv_linked true if connected, false otherwise
|
||||||
|
--- EVENT_CONSUMER: this function consumes events
|
||||||
|
function public.sv_connect(timeout_s, tick_dmesg_waiting, task_done)
|
||||||
|
local clock = util.new_clock(1)
|
||||||
|
local start = util.time_s()
|
||||||
|
local terminated = false
|
||||||
|
|
||||||
|
_send_sv(PROTOCOLS.COORD_DATA, COORD_TYPES.ESTABLISH, {})
|
||||||
|
|
||||||
|
clock.start()
|
||||||
|
|
||||||
|
while (util.time_s() - start) < timeout_s and not self.sv_linked do
|
||||||
|
---@diagnostic disable-next-line: undefined-field
|
||||||
|
local event, p1, p2, p3, p4, p5 = os.pullEventRaw()
|
||||||
|
|
||||||
|
if event == "timer" and clock.is_clock(p1) then
|
||||||
|
-- timed out attempt, try again
|
||||||
|
tick_dmesg_waiting(math.max(0, timeout_s - (util.time_s() - start)))
|
||||||
|
_send_sv(PROTOCOLS.COORD_DATA, COORD_TYPES.ESTABLISH, {})
|
||||||
|
clock.start()
|
||||||
|
elseif event == "modem_message" then
|
||||||
|
-- handle message
|
||||||
|
local packet = public.parse_packet(p1, p2, p3, p4, p5)
|
||||||
|
if packet ~= nil and packet.type == COORD_TYPES.ESTABLISH then
|
||||||
|
public.handle_packet(packet)
|
||||||
|
end
|
||||||
|
elseif event == "terminate" then
|
||||||
|
terminated = true
|
||||||
|
task_done(false)
|
||||||
|
coordinator.log_comms("supervisor connection attempt cancelled by user")
|
||||||
|
break
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if not terminated then
|
||||||
|
task_done(self.sv_linked)
|
||||||
|
end
|
||||||
|
|
||||||
|
return self.sv_linked
|
||||||
|
end
|
||||||
|
|
||||||
-- parse a packet
|
-- parse a packet
|
||||||
---@param side string
|
---@param side string
|
||||||
---@param sender integer
|
---@param sender integer
|
||||||
@ -325,6 +351,30 @@ function coordinator.comms(version, modem, sv_port, sv_listen, api_listen, sv_wa
|
|||||||
-- handle packet
|
-- handle packet
|
||||||
if protocol == PROTOCOLS.COORD_DATA then
|
if protocol == PROTOCOLS.COORD_DATA then
|
||||||
if packet.type == COORD_TYPES.ESTABLISH then
|
if packet.type == COORD_TYPES.ESTABLISH then
|
||||||
|
-- connection with supervisor established
|
||||||
|
if packet.length > 1 then
|
||||||
|
-- get configuration
|
||||||
|
|
||||||
|
---@class facility_conf
|
||||||
|
local conf = {
|
||||||
|
num_units = packet.data[1],
|
||||||
|
defs = {} -- boilers and turbines
|
||||||
|
}
|
||||||
|
|
||||||
|
if (packet.length - 1) == (conf.num_units * 2) then
|
||||||
|
-- record sequence of pairs of [#boilers, #turbines] per unit
|
||||||
|
for i = 2, packet.length do
|
||||||
|
table.insert(conf.defs, packet.data[i])
|
||||||
|
end
|
||||||
|
|
||||||
|
-- init database structure
|
||||||
|
database.init(conf)
|
||||||
|
else
|
||||||
|
log.debug("supervisor conn establish packet length mismatch")
|
||||||
|
end
|
||||||
|
else
|
||||||
|
log.debug("supervisor conn establish packet length mismatch")
|
||||||
|
end
|
||||||
elseif packet.type == COORD_TYPES.QUERY_UNIT then
|
elseif packet.type == COORD_TYPES.QUERY_UNIT then
|
||||||
elseif packet.type == COORD_TYPES.QUERY_FACILITY then
|
elseif packet.type == COORD_TYPES.QUERY_FACILITY then
|
||||||
elseif packet.type == COORD_TYPES.COMMAND_UNIT then
|
elseif packet.type == COORD_TYPES.COMMAND_UNIT then
|
||||||
|
54
coordinator/database.lua
Normal file
54
coordinator/database.lua
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
local psil = require("scada-common.psil")
|
||||||
|
|
||||||
|
local database = {}
|
||||||
|
|
||||||
|
database.WASTE = { Pu = 0, Po = 1, AntiMatter = 2 }
|
||||||
|
|
||||||
|
---@class coord_db
|
||||||
|
local db = {}
|
||||||
|
|
||||||
|
-- initialize the coordinator database
|
||||||
|
---@param conf facility_conf configuration
|
||||||
|
function database.init(conf)
|
||||||
|
db.facility = {
|
||||||
|
scram = false,
|
||||||
|
num_units = conf.num_units,
|
||||||
|
ps = psil.create()
|
||||||
|
}
|
||||||
|
|
||||||
|
db.units = {}
|
||||||
|
for i = 1, conf.num_units do
|
||||||
|
---@class coord_db_entry
|
||||||
|
local entry = {
|
||||||
|
unit_id = i, ---@type integer
|
||||||
|
initialized = false,
|
||||||
|
|
||||||
|
waste_mode = 0,
|
||||||
|
|
||||||
|
reactor_ps = psil.create(),
|
||||||
|
reactor_data = {}, ---@type reactor_db
|
||||||
|
|
||||||
|
boiler_ps_tbl = {},
|
||||||
|
boiler_data_tbl = {},
|
||||||
|
|
||||||
|
turbine_ps_tbl = {},
|
||||||
|
turbine_data_tbl = {}
|
||||||
|
}
|
||||||
|
|
||||||
|
for _ = 1, conf.defs[(i * 2) - 1] do
|
||||||
|
local data = {} ---@type boiler_session_db|boilerv_session_db
|
||||||
|
table.insert(entry.boiler_ps_tbl, psil.create())
|
||||||
|
table.insert(entry.boiler_data_tbl, data)
|
||||||
|
end
|
||||||
|
|
||||||
|
for _ = 1, conf.defs[i * 2] do
|
||||||
|
local data = {} ---@type turbine_session_db|turbinev_session_db
|
||||||
|
table.insert(entry.turbine_ps_tbl, psil.create())
|
||||||
|
table.insert(entry.turbine_data_tbl, data)
|
||||||
|
end
|
||||||
|
|
||||||
|
table.insert(db.units, entry)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return database
|
@ -13,7 +13,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.2.4"
|
local COORDINATOR_VERSION = "alpha-v0.3.0"
|
||||||
|
|
||||||
local print = util.print
|
local print = util.print
|
||||||
local println = util.println
|
local println = util.println
|
||||||
@ -24,6 +24,7 @@ local log_graphics = coordinator.log_graphics
|
|||||||
local log_sys = coordinator.log_sys
|
local log_sys = coordinator.log_sys
|
||||||
local log_boot = coordinator.log_boot
|
local log_boot = coordinator.log_boot
|
||||||
local log_comms = coordinator.log_comms
|
local log_comms = coordinator.log_comms
|
||||||
|
local log_comms_connecting = coordinator.log_comms_connecting
|
||||||
|
|
||||||
----------------------------------------
|
----------------------------------------
|
||||||
-- config validation
|
-- config validation
|
||||||
@ -100,10 +101,21 @@ local coord_comms = coordinator.comms(COORDINATOR_VERSION, modem, config.SCADA_S
|
|||||||
log.debug("boot> comms init")
|
log.debug("boot> comms init")
|
||||||
log_comms("comms initialized")
|
log_comms("comms initialized")
|
||||||
|
|
||||||
-- base loop clock (6.67Hz, 3 ticks)
|
-- base loop clock (2Hz, 10 ticks)
|
||||||
local MAIN_CLOCK = 0.15
|
local MAIN_CLOCK = 0.5
|
||||||
local loop_clock = util.new_clock(MAIN_CLOCK)
|
local loop_clock = util.new_clock(MAIN_CLOCK)
|
||||||
|
|
||||||
|
local tick_waiting, task_done = log_comms_connecting("attempting to connect to configured supervisor on channel " .. config.SCADA_SV_PORT)
|
||||||
|
|
||||||
|
-- attempt to establish a connection with the supervisory computer
|
||||||
|
if not coord_comms.sv_connect(60, tick_waiting, task_done) then
|
||||||
|
log_comms("supervisor connection failed")
|
||||||
|
println("boot> failed to connect to supervisor")
|
||||||
|
log.fatal("failed to connect to supervisor")
|
||||||
|
log_sys("system shutdown")
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
----------------------------------------
|
----------------------------------------
|
||||||
-- start the UI
|
-- start the UI
|
||||||
----------------------------------------
|
----------------------------------------
|
||||||
|
@ -201,7 +201,7 @@ end
|
|||||||
---@param target_timing integer minimum amount of milliseconds to wait for
|
---@param target_timing integer minimum amount of milliseconds to wait for
|
||||||
---@param last_update integer millisecond time of last update
|
---@param last_update integer millisecond time of last update
|
||||||
---@return integer time_now
|
---@return integer time_now
|
||||||
-- EVENT_CONSUMER: this function consumes events
|
--- EVENT_CONSUMER: this function consumes events
|
||||||
function util.adaptive_delay(target_timing, last_update)
|
function util.adaptive_delay(target_timing, last_update)
|
||||||
local sleep_for = target_timing - (util.time() - last_update)
|
local sleep_for = target_timing - (util.time() - last_update)
|
||||||
-- only if >50ms since worker loops already yield 0.05s
|
-- only if >50ms since worker loops already yield 0.05s
|
||||||
|
Loading…
Reference in New Issue
Block a user