mirror of
https://github.com/MikaylaFischler/cc-mek-scada.git
synced 2024-08-30 18:22:34 +00:00
#61 monitor configuration and init, render engine started, dmesg changes, ppm monitor listing changes
This commit is contained in:
parent
ff5b163c1d
commit
e65a1bf6e1
4
.vscode/settings.json
vendored
4
.vscode/settings.json
vendored
@ -8,6 +8,8 @@
|
|||||||
"parallel",
|
"parallel",
|
||||||
"colors",
|
"colors",
|
||||||
"textutils",
|
"textutils",
|
||||||
"shell"
|
"shell",
|
||||||
|
"settings",
|
||||||
|
"window"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
22
coordinator/config.lua
Normal file
22
coordinator/config.lua
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
local config = {}
|
||||||
|
|
||||||
|
-- port of the SCADA supervisor
|
||||||
|
config.SCADA_SV_PORT = 16100
|
||||||
|
-- port to listen to incoming packets from supervisor
|
||||||
|
config.SCADA_SV_LISTEN = 16101
|
||||||
|
-- listen port for SCADA coordinator API access
|
||||||
|
config.SCADA_API_LISTEN = 16200
|
||||||
|
-- expected number of reactor units
|
||||||
|
config.NUM_UNITS = 4
|
||||||
|
-- log path
|
||||||
|
config.LOG_PATH = "/log.txt"
|
||||||
|
-- log mode
|
||||||
|
-- 0 = APPEND (adds to existing file on start)
|
||||||
|
-- 1 = NEW (replaces existing file on start)
|
||||||
|
config.LOG_MODE = 0
|
||||||
|
-- crypto config
|
||||||
|
config.SECURE = true
|
||||||
|
-- must be common between all devices
|
||||||
|
config.PASSWORD = "testpassword!"
|
||||||
|
|
||||||
|
return config
|
@ -1,9 +1,141 @@
|
|||||||
|
|
||||||
local comms = require("scada-common.comms")
|
local comms = require("scada-common.comms")
|
||||||
|
local log = require("scada-common.log")
|
||||||
|
local ppm = require("scada-common.ppm")
|
||||||
|
local util = require("scada-common.util")
|
||||||
|
|
||||||
|
local dialog = require("coordinator.util.dialog")
|
||||||
|
|
||||||
|
local print = util.print
|
||||||
|
local println = util.println
|
||||||
|
local print_ts = util.print_ts
|
||||||
|
local println_ts = util.println_ts
|
||||||
|
|
||||||
local coordinator = {}
|
local coordinator = {}
|
||||||
|
|
||||||
|
local function ask_monitor(names)
|
||||||
|
println("available monitors:")
|
||||||
|
for i = 1, #names do
|
||||||
|
print(" " .. names[i])
|
||||||
|
end
|
||||||
|
println("")
|
||||||
|
println("select a monitor or type c to cancel")
|
||||||
|
|
||||||
|
local iface = dialog.ask_options(names, "c")
|
||||||
|
|
||||||
|
if iface ~= false and iface ~= nil then
|
||||||
|
util.filter_table(names, function (x) return x ~= iface end)
|
||||||
|
end
|
||||||
|
|
||||||
|
return iface
|
||||||
|
end
|
||||||
|
|
||||||
|
function coordinator.configure_monitors(num_units)
|
||||||
|
---@class monitors_struct
|
||||||
|
local monitors = {
|
||||||
|
primary = nil,
|
||||||
|
unit_displays = {}
|
||||||
|
}
|
||||||
|
|
||||||
|
local monitors_avail = ppm.get_monitor_list()
|
||||||
|
local names = {}
|
||||||
|
|
||||||
|
-- get all interface names
|
||||||
|
for iface, _ in pairs(monitors_avail) do
|
||||||
|
table.insert(names, iface)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- we need a certain number of monitors (1 per unit + 1 primary display)
|
||||||
|
if #names ~= num_units + 1 then
|
||||||
|
println("not enough monitors connected (need " .. num_units + 1 .. ")")
|
||||||
|
log.warning("insufficient monitors present (need " .. num_units + 1 .. ")")
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
-- attempt to load settings
|
||||||
|
settings.load("/coord.settings")
|
||||||
|
|
||||||
|
---------------------
|
||||||
|
-- PRIMARY DISPLAY --
|
||||||
|
---------------------
|
||||||
|
|
||||||
|
local iface_primary_display = settings.get("PRIMARY_DISPLAY")
|
||||||
|
|
||||||
|
if not util.table_contains(names, iface_primary_display) then
|
||||||
|
println("primary display is not connected")
|
||||||
|
local response = dialog.ask_y_n("would you like to change it", true)
|
||||||
|
if response == false then return false end
|
||||||
|
iface_primary_display = nil
|
||||||
|
end
|
||||||
|
|
||||||
|
while iface_primary_display == nil and #names > 0 do
|
||||||
|
-- lets get a monitor
|
||||||
|
iface_primary_display = ask_monitor(names)
|
||||||
|
end
|
||||||
|
|
||||||
|
if iface_primary_display == false then return false end
|
||||||
|
|
||||||
|
settings.set("PRIMARY_DISPLAY", iface_primary_display)
|
||||||
|
util.filter_table(names, function (x) return x ~= iface_primary_display end)
|
||||||
|
|
||||||
|
monitors.primary = ppm.get_periph(iface_primary_display)
|
||||||
|
|
||||||
|
-------------------
|
||||||
|
-- UNIT DISPLAYS --
|
||||||
|
-------------------
|
||||||
|
|
||||||
|
local unit_displays = settings.get("UNIT_DISPLAYS")
|
||||||
|
|
||||||
|
if unit_displays == nil then
|
||||||
|
unit_displays = {}
|
||||||
|
for i = 1, num_units do
|
||||||
|
local display = nil
|
||||||
|
|
||||||
|
while display == nil and #names > 0 do
|
||||||
|
-- lets get a monitor
|
||||||
|
println("please select monitor for unit " .. i)
|
||||||
|
display = ask_monitor(names)
|
||||||
|
end
|
||||||
|
|
||||||
|
if display == false then return false end
|
||||||
|
|
||||||
|
unit_displays[i] = display
|
||||||
|
end
|
||||||
|
else
|
||||||
|
-- make sure all displays are connected
|
||||||
|
for i = 1, num_units do
|
||||||
|
---@diagnostic disable-next-line: need-check-nil
|
||||||
|
local display = unit_displays[i]
|
||||||
|
|
||||||
|
if not util.table_contains(names, display) then
|
||||||
|
local response = dialog.ask_y_n("unit display " .. i .. " is not connected, would you like to change it?", true)
|
||||||
|
if response == false then return false end
|
||||||
|
display = nil
|
||||||
|
end
|
||||||
|
|
||||||
|
while display == nil and #names > 0 do
|
||||||
|
-- lets get a monitor
|
||||||
|
display = ask_monitor(names)
|
||||||
|
end
|
||||||
|
|
||||||
|
if display == false then return false end
|
||||||
|
|
||||||
|
unit_displays[i] = display
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
settings.set("UNIT_DISPLAYS", unit_displays)
|
||||||
|
settings.save("/coord.settings")
|
||||||
|
|
||||||
|
for i = 1, #unit_displays do
|
||||||
|
monitors.unit_displays[i] = ppm.get_periph(unit_displays[i])
|
||||||
|
end
|
||||||
|
|
||||||
|
return true, monitors
|
||||||
|
end
|
||||||
|
|
||||||
-- coordinator communications
|
-- coordinator communications
|
||||||
coordinator.coord_comms = function ()
|
function coordinator.coord_comms()
|
||||||
local self = {
|
local self = {
|
||||||
reactor_struct_cache = nil
|
reactor_struct_cache = nil
|
||||||
}
|
}
|
||||||
|
41
coordinator/renderer.lua
Normal file
41
coordinator/renderer.lua
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
local log = require("scada-common.log")
|
||||||
|
local util = require("scada-common.util")
|
||||||
|
|
||||||
|
local renderer = {}
|
||||||
|
|
||||||
|
local engine = {
|
||||||
|
monitors = nil,
|
||||||
|
dmesg_window = nil
|
||||||
|
}
|
||||||
|
|
||||||
|
---@param monitors monitors_struct
|
||||||
|
function renderer.set_displays(monitors)
|
||||||
|
engine.monitors = monitors
|
||||||
|
end
|
||||||
|
|
||||||
|
function renderer.reset()
|
||||||
|
-- reset primary monitor
|
||||||
|
engine.monitors.primary.setTextScale(0.5)
|
||||||
|
engine.monitors.primary.setTextColor(colors.white)
|
||||||
|
engine.monitors.primary.setBackgroundColor(colors.black)
|
||||||
|
engine.monitors.primary.clear()
|
||||||
|
engine.monitors.primary.setCursorPos(1, 1)
|
||||||
|
|
||||||
|
-- reset unit displays
|
||||||
|
for _, monitor in pairs(engine.monitors.unit_displays) do
|
||||||
|
monitor.setTextScale(0.5)
|
||||||
|
monitor.setTextColor(colors.white)
|
||||||
|
monitor.setBackgroundColor(colors.black)
|
||||||
|
monitor.clear()
|
||||||
|
monitor.setCursorPos(1, 1)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function renderer.init_dmesg()
|
||||||
|
local disp_x, disp_y = engine.monitors.primary.getSize()
|
||||||
|
engine.dmesg_window = window.create(engine.monitors.primary, 1, 1, disp_x, disp_y)
|
||||||
|
|
||||||
|
log.direct_dmesg(engine.dmesg_window)
|
||||||
|
end
|
||||||
|
|
||||||
|
return renderer
|
@ -10,6 +10,7 @@ local util = require("scada-common.util")
|
|||||||
|
|
||||||
local config = require("coordinator.config")
|
local config = require("coordinator.config")
|
||||||
local coordinator = require("coordinator.coordinator")
|
local coordinator = require("coordinator.coordinator")
|
||||||
|
local renderer = require("coordinator.renderer")
|
||||||
|
|
||||||
local COORDINATOR_VERSION = "alpha-v0.1.2"
|
local COORDINATOR_VERSION = "alpha-v0.1.2"
|
||||||
|
|
||||||
@ -18,7 +19,7 @@ local println = util.println
|
|||||||
local print_ts = util.print_ts
|
local print_ts = util.print_ts
|
||||||
local println_ts = util.println_ts
|
local println_ts = util.println_ts
|
||||||
|
|
||||||
log.init("/log.txt", log.MODE.APPEND)
|
log.init(config.LOG_PATH, config.LOG_MODE)
|
||||||
|
|
||||||
log.info("========================================")
|
log.info("========================================")
|
||||||
log.info("BOOTING coordinator.startup " .. COORDINATOR_VERSION)
|
log.info("BOOTING coordinator.startup " .. COORDINATOR_VERSION)
|
||||||
@ -28,10 +29,31 @@ println(">> SCADA Coordinator " .. COORDINATOR_VERSION .. " <<")
|
|||||||
-- mount connected devices
|
-- mount connected devices
|
||||||
ppm.mount_all()
|
ppm.mount_all()
|
||||||
|
|
||||||
local modem = ppm.get_wireless_modem()
|
-- setup monitors
|
||||||
|
local configured, monitors = coordinator.configure_monitors(config.NUM_UNITS)
|
||||||
-- we need a modem
|
if not configured then
|
||||||
if modem == nil then
|
println("boot> monitor setup failed")
|
||||||
println("please connect a wireless modem")
|
log.fatal("monitor configuration failed")
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
|
log.info("monitors ready, dmesg input incoming...")
|
||||||
|
|
||||||
|
-- init renderer
|
||||||
|
renderer.set_displays(monitors)
|
||||||
|
renderer.reset()
|
||||||
|
renderer.init_dmesg()
|
||||||
|
|
||||||
|
log.dmesg("displays connected and reset", "GRAPHICS", colors.green)
|
||||||
|
log.dmesg("system start on " .. os.date("%c"), "SYSTEM", colors.cyan)
|
||||||
|
log.dmesg("starting " .. COORDINATOR_VERSION, "BOOT", colors.blue)
|
||||||
|
|
||||||
|
-- get the communications modem
|
||||||
|
local modem = ppm.get_wireless_modem()
|
||||||
|
if modem == nil then
|
||||||
|
println("boot> wireless modem not found")
|
||||||
|
log.fatal("no wireless modem on startup")
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
log.dmesg("wireless modem connected", "COMMS", colors.purple)
|
||||||
|
45
coordinator/util/dialog.lua
Normal file
45
coordinator/util/dialog.lua
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
local completion = require("cc.completion")
|
||||||
|
|
||||||
|
local util = require("scada-common.util")
|
||||||
|
|
||||||
|
local print = util.print
|
||||||
|
local println = util.println
|
||||||
|
local print_ts = util.print_ts
|
||||||
|
local println_ts = util.println_ts
|
||||||
|
|
||||||
|
local dialog = {}
|
||||||
|
|
||||||
|
function dialog.ask_y_n(question, default)
|
||||||
|
print(question)
|
||||||
|
|
||||||
|
if default == true then
|
||||||
|
print(" (Y/n)? ")
|
||||||
|
else
|
||||||
|
print(" (y/N)? ")
|
||||||
|
end
|
||||||
|
|
||||||
|
local response = read(nil, nil)
|
||||||
|
|
||||||
|
if response == "" then
|
||||||
|
return default
|
||||||
|
elseif response == "Y" or response == "y" then
|
||||||
|
return true
|
||||||
|
elseif response == "N" or response == "n" then
|
||||||
|
return false
|
||||||
|
else
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function dialog.ask_options(options, cancel)
|
||||||
|
print("> ")
|
||||||
|
local response = read(nil, nil, function(text) return completion.choice(text, options) end)
|
||||||
|
|
||||||
|
if response == cancel then return false end
|
||||||
|
|
||||||
|
if util.table_contains(options, response) then
|
||||||
|
return response
|
||||||
|
else return nil end
|
||||||
|
end
|
||||||
|
|
||||||
|
return dialog
|
@ -49,6 +49,12 @@ log.init = function (path, write_mode, dmesg_redirect)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- direct dmesg output to a monitor/window
|
||||||
|
---@param window table window or terminal reference
|
||||||
|
log.direct_dmesg = function (window)
|
||||||
|
_log_sys.dmesg_out = window
|
||||||
|
end
|
||||||
|
|
||||||
-- private log write function
|
-- private log write function
|
||||||
---@param msg string
|
---@param msg string
|
||||||
local _log = function (msg)
|
local _log = function (msg)
|
||||||
@ -84,9 +90,16 @@ local _log = function (msg)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
-- write a message to the dmesg output
|
-- dmesg style logging for boot because I like linux-y things
|
||||||
---@param msg string message to write
|
---@param msg string message
|
||||||
local _write = function (msg)
|
---@param tag? string log tag
|
||||||
|
---@param tag_color? integer log tag color
|
||||||
|
log.dmesg = function (msg, tag, tag_color)
|
||||||
|
msg = util.strval(msg)
|
||||||
|
tag = tag or ""
|
||||||
|
tag = util.strval(tag)
|
||||||
|
|
||||||
|
local t_stamp = string.format("%12.2f", os.clock())
|
||||||
local out = _log_sys.dmesg_out
|
local out = _log_sys.dmesg_out
|
||||||
local out_w, out_h = out.getSize()
|
local out_w, out_h = out.getSize()
|
||||||
|
|
||||||
@ -116,8 +129,7 @@ local _write = function (msg)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
-- output message
|
-- start output with tag and time, assuming we have enough width for this to be on one line
|
||||||
for i = 1, #lines do
|
|
||||||
local cur_x, cur_y = out.getCursorPos()
|
local cur_x, cur_y = out.getCursorPos()
|
||||||
|
|
||||||
if cur_x > 1 then
|
if cur_x > 1 then
|
||||||
@ -129,17 +141,43 @@ local _write = function (msg)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- colored time
|
||||||
|
local initial_color = out.getTextColor()
|
||||||
|
out.setTextColor(colors.white)
|
||||||
|
out.write("[")
|
||||||
|
out.setTextColor(colors.lightGray)
|
||||||
|
out.write(t_stamp)
|
||||||
|
out.setTextColor(colors.white)
|
||||||
|
out.write("] ")
|
||||||
|
|
||||||
|
-- colored tag
|
||||||
|
if tag ~= "" then
|
||||||
|
out.write("[")
|
||||||
|
out.setTextColor(tag_color)
|
||||||
|
out.write(tag)
|
||||||
|
out.setTextColor(colors.white)
|
||||||
|
out.write("] ")
|
||||||
|
end
|
||||||
|
|
||||||
|
out.setTextColor(initial_color)
|
||||||
|
|
||||||
|
-- output message
|
||||||
|
for i = 1, #lines do
|
||||||
|
cur_x, cur_y = out.getCursorPos()
|
||||||
|
|
||||||
|
if i > 1 and cur_x > 1 then
|
||||||
|
if cur_y == out_h then
|
||||||
|
out.scroll(1)
|
||||||
|
out.setCursorPos(1, cur_y)
|
||||||
|
else
|
||||||
|
out.setCursorPos(1, cur_y + 1)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
out.write(lines[i])
|
out.write(lines[i])
|
||||||
end
|
end
|
||||||
end
|
|
||||||
|
|
||||||
-- dmesg style logging for boot because I like linux-y things
|
_log("[" .. t_stamp .. "] " .. tag .. " " .. msg)
|
||||||
---@param msg string message
|
|
||||||
---@param show_term? boolean whether or not to show on terminal output
|
|
||||||
log.dmesg = function (msg, show_term)
|
|
||||||
local message = string.format("[%10.3f] ", os.clock()) .. util.strval(msg)
|
|
||||||
if show_term then _write(message) end
|
|
||||||
_log(message)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
-- log debug messages
|
-- log debug messages
|
||||||
|
@ -317,8 +317,16 @@ end
|
|||||||
|
|
||||||
-- list all connected monitors
|
-- list all connected monitors
|
||||||
---@return table monitors
|
---@return table monitors
|
||||||
ppm.list_monitors = function ()
|
ppm.get_monitor_list = function ()
|
||||||
return ppm.get_all_devices("monitor")
|
local list = {}
|
||||||
|
|
||||||
|
for iface, device in pairs(_ppm_sys.mounts) do
|
||||||
|
if device.type == "monitor" then
|
||||||
|
list[iface] = device
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return list
|
||||||
end
|
end
|
||||||
|
|
||||||
return ppm
|
return ppm
|
||||||
|
Loading…
Reference in New Issue
Block a user