mirror of
https://github.com/MikaylaFischler/cc-mek-scada.git
synced 2024-08-30 18:22:34 +00:00
commit
afc38e7e7a
@ -1449,9 +1449,11 @@ function configurator.configure(start_code, message)
|
||||
elseif event == "paste" then
|
||||
display.handle_paste(param1)
|
||||
elseif event == "peripheral_detach" then
|
||||
---@diagnostic disable-next-line: discard-returns
|
||||
ppm.handle_unmount(param1)
|
||||
tool_ctl.gen_mon_list()
|
||||
elseif event == "peripheral" then
|
||||
---@diagnostic disable-next-line: discard-returns
|
||||
ppm.mount(param1)
|
||||
tool_ctl.gen_mon_list()
|
||||
elseif event == "monitor_resize" then
|
||||
|
@ -228,6 +228,8 @@ function iocontrol.init(conf, comms, temp_scale)
|
||||
---@class ioctl_unit
|
||||
local entry = {
|
||||
unit_id = i,
|
||||
connected = false,
|
||||
rtu_hw = { boilers = {}, turbines = {} },
|
||||
|
||||
num_boilers = 0,
|
||||
num_turbines = 0,
|
||||
@ -319,12 +321,14 @@ function iocontrol.init(conf, comms, temp_scale)
|
||||
for _ = 1, conf.cooling.r_cool[i].BoilerCount do
|
||||
table.insert(entry.boiler_ps_tbl, psil.create())
|
||||
table.insert(entry.boiler_data_tbl, {})
|
||||
table.insert(entry.rtu_hw.boilers, { connected = false, faulted = false })
|
||||
end
|
||||
|
||||
-- create turbine tables
|
||||
for _ = 1, conf.cooling.r_cool[i].TurbineCount do
|
||||
table.insert(entry.turbine_ps_tbl, psil.create())
|
||||
table.insert(entry.turbine_data_tbl, {})
|
||||
table.insert(entry.rtu_hw.turbines, { connected = false, faulted = false })
|
||||
end
|
||||
|
||||
-- create tank tables
|
||||
@ -897,6 +901,7 @@ function iocontrol.update_unit_statuses(statuses)
|
||||
end
|
||||
|
||||
if #reactor_status == 0 then
|
||||
unit.connected = false
|
||||
unit.unit_ps.publish("computed_status", 1) -- disconnected
|
||||
elseif #reactor_status == 3 then
|
||||
local mek_status = reactor_status[1]
|
||||
@ -956,6 +961,8 @@ function iocontrol.update_unit_statuses(statuses)
|
||||
unit.unit_ps.publish(key, val)
|
||||
end
|
||||
end
|
||||
|
||||
unit.connected = true
|
||||
else
|
||||
log.debug(log_header .. "reactor status length mismatch")
|
||||
valid = false
|
||||
@ -970,7 +977,10 @@ function iocontrol.update_unit_statuses(statuses)
|
||||
local boil_sum = 0
|
||||
|
||||
for id = 1, #unit.boiler_ps_tbl do
|
||||
if rtu_statuses.boilers[id] == nil then
|
||||
local connected = rtu_statuses.boilers[id] ~= nil
|
||||
unit.rtu_hw.boilers[id].connected = connected
|
||||
|
||||
if not connected then
|
||||
-- disconnected
|
||||
unit.boiler_ps_tbl[id].publish("computed_status", 1)
|
||||
end
|
||||
@ -982,6 +992,7 @@ function iocontrol.update_unit_statuses(statuses)
|
||||
local ps = unit.boiler_ps_tbl[id] ---@type psil
|
||||
|
||||
local rtu_faulted = _record_multiblock_status(boiler, data, ps)
|
||||
unit.rtu_hw.boilers[id].faulted = rtu_faulted
|
||||
|
||||
if rtu_faulted then
|
||||
ps.publish("computed_status", 3) -- faulted
|
||||
@ -1013,7 +1024,10 @@ function iocontrol.update_unit_statuses(statuses)
|
||||
local flow_sum = 0
|
||||
|
||||
for id = 1, #unit.turbine_ps_tbl do
|
||||
if rtu_statuses.turbines[id] == nil then
|
||||
local connected = rtu_statuses.turbines[id] ~= nil
|
||||
unit.rtu_hw.turbines[id].connected = connected
|
||||
|
||||
if not connected then
|
||||
-- disconnected
|
||||
unit.turbine_ps_tbl[id].publish("computed_status", 1)
|
||||
end
|
||||
@ -1025,6 +1039,7 @@ function iocontrol.update_unit_statuses(statuses)
|
||||
local ps = unit.turbine_ps_tbl[id] ---@type psil
|
||||
|
||||
local rtu_faulted = _record_multiblock_status(turbine, data, ps)
|
||||
unit.rtu_hw.turbines[id].faulted = rtu_faulted
|
||||
|
||||
if rtu_faulted then
|
||||
ps.publish("computed_status", 3) -- faulted
|
||||
|
@ -138,21 +138,26 @@ function pocket.new_session(id, s_addr, in_queue, out_queue, timeout)
|
||||
}
|
||||
|
||||
_send(CRDN_TYPE.API_GET_FAC, data)
|
||||
elseif pkt.type == CRDN_TYPE.API_GET_UNITS then
|
||||
local data = {}
|
||||
elseif pkt.type == CRDN_TYPE.API_GET_UNIT then
|
||||
if pkt.length == 1 and type(pkt.data[1]) == "number" then
|
||||
local u = db.units[pkt.data[1]] ---@type ioctl_unit
|
||||
|
||||
for i = 1, #db.units do
|
||||
local u = db.units[i] ---@type ioctl_unit
|
||||
table.insert(data, {
|
||||
if u then
|
||||
local data = {
|
||||
u.unit_id,
|
||||
u.num_boilers,
|
||||
u.num_turbines,
|
||||
u.num_snas,
|
||||
u.has_tank
|
||||
})
|
||||
end
|
||||
u.connected,
|
||||
u.rtu_hw,
|
||||
u.alarms,
|
||||
u.annunciator,
|
||||
u.reactor_data,
|
||||
u.boiler_data_tbl,
|
||||
u.turbine_data_tbl,
|
||||
u.tank_data_tbl
|
||||
}
|
||||
|
||||
_send(CRDN_TYPE.API_GET_UNITS, data)
|
||||
_send(CRDN_TYPE.API_GET_UNIT, data)
|
||||
end
|
||||
end
|
||||
else
|
||||
log.debug(log_header .. "handler received unsupported CRDN packet type " .. pkt.type)
|
||||
end
|
||||
|
@ -19,7 +19,7 @@ local renderer = require("coordinator.renderer")
|
||||
local sounder = require("coordinator.sounder")
|
||||
local threads = require("coordinator.threads")
|
||||
|
||||
local COORDINATOR_VERSION = "v1.4.5"
|
||||
local COORDINATOR_VERSION = "v1.4.6"
|
||||
|
||||
local CHUNK_LOAD_DELAY_S = 30.0
|
||||
|
||||
|
@ -7,7 +7,7 @@ local flasher = require("graphics.flasher")
|
||||
|
||||
local core = {}
|
||||
|
||||
core.version = "2.2.3"
|
||||
core.version = "2.2.4"
|
||||
|
||||
core.flasher = flasher
|
||||
core.events = events
|
||||
|
@ -198,6 +198,9 @@ function element.new(args, child_offset_x, child_offset_y)
|
||||
---@param offset_y integer y offset for mouse events
|
||||
---@param next_y integer next line if no y was provided
|
||||
function protected.prepare_template(offset_x, offset_y, next_y)
|
||||
-- don't auto incrememnt y if inheriting height, that would cause an assertion
|
||||
next_y = util.trinary(args.height == nil, 1, next_y)
|
||||
|
||||
-- record offsets in case there is a reposition
|
||||
self.offset_x = offset_x
|
||||
self.offset_y = offset_y
|
||||
|
@ -30,7 +30,7 @@ local function app_button(args)
|
||||
element.assert(type(args.app_fg_bg) == "table", "app_fg_bg is a required field")
|
||||
|
||||
args.height = 4
|
||||
args.width = 5
|
||||
args.width = 7
|
||||
|
||||
-- create new graphics element base object
|
||||
local e = element.new(args)
|
||||
@ -46,7 +46,7 @@ local function app_button(args)
|
||||
end
|
||||
|
||||
-- draw icon
|
||||
e.w_set_cur(1, 1)
|
||||
e.w_set_cur(2, 1)
|
||||
e.w_set_fgd(fgd)
|
||||
e.w_set_bkg(bkg)
|
||||
e.w_write("\x9f\x83\x83\x83")
|
||||
@ -55,16 +55,16 @@ local function app_button(args)
|
||||
e.w_write("\x90")
|
||||
e.w_set_fgd(fgd)
|
||||
e.w_set_bkg(bkg)
|
||||
e.w_set_cur(1, 2)
|
||||
e.w_set_cur(2, 2)
|
||||
e.w_write("\x95 ")
|
||||
e.w_set_fgd(bkg)
|
||||
e.w_set_bkg(fgd)
|
||||
e.w_write("\x95")
|
||||
e.w_set_cur(1, 3)
|
||||
e.w_set_cur(2, 3)
|
||||
e.w_write("\x82\x8f\x8f\x8f\x81")
|
||||
|
||||
-- write the icon text
|
||||
e.w_set_cur(3, 2)
|
||||
e.w_set_cur(4, 2)
|
||||
e.w_set_fgd(fgd)
|
||||
e.w_set_bkg(bkg)
|
||||
e.w_write(args.text)
|
||||
|
@ -8,13 +8,7 @@ local element = require("graphics.element")
|
||||
|
||||
local MOUSE_CLICK = core.events.MOUSE_CLICK
|
||||
|
||||
---@class sidebar_tab
|
||||
---@field char string character identifier
|
||||
---@field color cpair tab colors (fg/bg)
|
||||
|
||||
---@class sidebar_args
|
||||
---@field tabs table sidebar tab options
|
||||
---@field callback function function to call on tab change
|
||||
---@field parent graphics_element
|
||||
---@field id? string element id
|
||||
---@field x? integer 1 if omitted
|
||||
@ -27,21 +21,16 @@ local MOUSE_CLICK = core.events.MOUSE_CLICK
|
||||
---@param args sidebar_args
|
||||
---@return graphics_element element, element_id id
|
||||
local function sidebar(args)
|
||||
element.assert(type(args.tabs) == "table", "tabs is a required field")
|
||||
element.assert(#args.tabs > 0, "at least one tab is required")
|
||||
element.assert(type(args.callback) == "function", "callback is a required field")
|
||||
|
||||
args.width = 3
|
||||
|
||||
-- create new graphics element base object
|
||||
local e = element.new(args)
|
||||
|
||||
element.assert(e.frame.h >= (#args.tabs * 3), "height insufficent to display all tabs")
|
||||
|
||||
-- default to 1st tab
|
||||
e.value = 1
|
||||
|
||||
local was_pressed = false
|
||||
local tabs = {}
|
||||
|
||||
-- show the button state
|
||||
---@param pressed? boolean if the currently selected tab should appear as actively pressed
|
||||
@ -51,10 +40,18 @@ local function sidebar(args)
|
||||
was_pressed = pressed
|
||||
pressed_idx = pressed_idx or e.value
|
||||
|
||||
for i = 1, #args.tabs do
|
||||
local tab = args.tabs[i] ---@type sidebar_tab
|
||||
-- clear
|
||||
e.w_set_fgd(e.fg_bg.fgd)
|
||||
e.w_set_bkg(e.fg_bg.bkg)
|
||||
for y = 1, e.frame.h do
|
||||
e.w_set_cur(1, y)
|
||||
e.w_write(" ")
|
||||
end
|
||||
|
||||
local y = ((i - 1) * 3) + 1
|
||||
-- draw tabs
|
||||
for i = 1, #tabs do
|
||||
local tab = tabs[i] ---@type sidebar_tab
|
||||
local y = tab.y_start
|
||||
|
||||
e.w_set_cur(1, y)
|
||||
|
||||
@ -66,38 +63,56 @@ local function sidebar(args)
|
||||
e.w_set_bkg(tab.color.bkg)
|
||||
end
|
||||
|
||||
if tab.tall then
|
||||
e.w_write(" ")
|
||||
e.w_set_cur(1, y + 1)
|
||||
if e.value == i then
|
||||
e.w_write(" " .. tab.char .. "\x10")
|
||||
else e.w_write(" " .. tab.char .. " ") end
|
||||
end
|
||||
|
||||
e.w_write(tab.label)
|
||||
|
||||
if tab.tall then
|
||||
e.w_set_cur(1, y + 2)
|
||||
e.w_write(" ")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- determine which tab was pressed
|
||||
---@param y integer y coordinate
|
||||
local function find_tab(y)
|
||||
for i = 1, #tabs do
|
||||
local tab = tabs[i] ---@type sidebar_tab
|
||||
|
||||
if y >= tab.y_start and y <= tab.y_end then
|
||||
return i
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- handle mouse interaction
|
||||
---@param event mouse_interaction mouse event
|
||||
function e.handle_mouse(event)
|
||||
-- determine what was pressed
|
||||
if e.enabled then
|
||||
local cur_idx = math.ceil(event.current.y / 3)
|
||||
local ini_idx = math.ceil(event.initial.y / 3)
|
||||
local cur_idx = find_tab(event.current.y)
|
||||
local ini_idx = find_tab(event.initial.y)
|
||||
local tab = tabs[cur_idx]
|
||||
|
||||
if args.tabs[cur_idx] ~= nil then
|
||||
-- handle press if a callback was provided
|
||||
if tab ~= nil and type(tab.callback) == "function" then
|
||||
if event.type == MOUSE_CLICK.TAP then
|
||||
e.value = cur_idx
|
||||
draw(true)
|
||||
-- show as unpressed in 0.25 seconds
|
||||
tcd.dispatch(0.25, function () draw(false) end)
|
||||
args.callback(e.value)
|
||||
tab.callback()
|
||||
elseif event.type == MOUSE_CLICK.DOWN then
|
||||
draw(true, cur_idx)
|
||||
elseif event.type == MOUSE_CLICK.UP then
|
||||
if cur_idx == ini_idx and e.in_frame_bounds(event.current.x, event.current.y) then
|
||||
e.value = cur_idx
|
||||
draw(false)
|
||||
args.callback(e.value)
|
||||
tab.callback()
|
||||
else draw(false) end
|
||||
end
|
||||
elseif event.type == MOUSE_CLICK.UP then
|
||||
@ -113,6 +128,35 @@ local function sidebar(args)
|
||||
draw(false)
|
||||
end
|
||||
|
||||
-- update the sidebar navigation options
|
||||
---@param items table sidebar entries
|
||||
function e.on_update(items)
|
||||
local next_y = 1
|
||||
|
||||
tabs = {}
|
||||
|
||||
for i = 1, #items do
|
||||
local item = items[i]
|
||||
local height = util.trinary(item.tall, 3, 1)
|
||||
|
||||
---@class sidebar_tab
|
||||
local entry = {
|
||||
y_start = next_y, ---@type integer
|
||||
y_end = next_y + height - 1, ---@type integer
|
||||
tall = item.tall, ---@type boolean
|
||||
label = item.label, ---@type string
|
||||
color = item.color, ---@type cpair
|
||||
callback = item.callback ---@type function|nil
|
||||
}
|
||||
|
||||
next_y = next_y + height
|
||||
|
||||
tabs[i] = entry
|
||||
end
|
||||
|
||||
draw()
|
||||
end
|
||||
|
||||
-- element redraw
|
||||
e.redraw = draw
|
||||
|
||||
|
@ -9,7 +9,7 @@ local element = require("graphics.element")
|
||||
---@class icon_indicator_args
|
||||
---@field label string indicator label
|
||||
---@field states table state color and symbol table
|
||||
---@field value? integer default state, defaults to 1
|
||||
---@field value? integer|boolean default state, defaults to 1 (true = 2, false = 1)
|
||||
---@field min_label_width? integer label length if omitted
|
||||
---@field parent graphics_element
|
||||
---@field id? string element id
|
||||
@ -33,6 +33,7 @@ local function icon(args)
|
||||
local e = element.new(args)
|
||||
|
||||
e.value = args.value or 1
|
||||
if e.value == true then e.value = 2 end
|
||||
|
||||
-- state blit strings
|
||||
local state_blit_cmds = {}
|
||||
@ -47,8 +48,11 @@ local function icon(args)
|
||||
end
|
||||
|
||||
-- on state change
|
||||
---@param new_state integer indicator state
|
||||
---@param new_state integer|boolean indicator state
|
||||
function e.on_update(new_state)
|
||||
new_state = new_state or 1
|
||||
if new_state == true then new_state = 2 end
|
||||
|
||||
local blit_cmd = state_blit_cmds[new_state]
|
||||
e.value = new_state
|
||||
e.w_set_cur(1, 1)
|
||||
@ -56,7 +60,7 @@ local function icon(args)
|
||||
end
|
||||
|
||||
-- set indicator state
|
||||
---@param val integer indicator state
|
||||
---@param val integer|boolean indicator state
|
||||
function e.set_value(val) e.on_update(val) end
|
||||
|
||||
-- element redraw
|
||||
|
@ -5,8 +5,10 @@
|
||||
local log = require("scada-common.log")
|
||||
local psil = require("scada-common.psil")
|
||||
local types = require("scada-common.types")
|
||||
local util = require("scada-common.util")
|
||||
|
||||
local ALARM = types.ALARM
|
||||
local ALARM_STATE = types.ALARM_STATE
|
||||
|
||||
---@todo nominal trip time is ping (0ms to 10ms usually)
|
||||
local WARN_TT = 40
|
||||
@ -72,6 +74,10 @@ function iocontrol.alloc_nav()
|
||||
self.pane = root_pane
|
||||
end
|
||||
|
||||
function io.nav.set_sidebar(sidebar)
|
||||
self.sidebar = sidebar
|
||||
end
|
||||
|
||||
-- register an app
|
||||
---@param app_id POCKET_APP_ID app ID
|
||||
---@param container graphics_element element that contains this app (usually a Div)
|
||||
@ -79,18 +85,36 @@ function iocontrol.alloc_nav()
|
||||
function io.nav.register_app(app_id, container, pane)
|
||||
---@class pocket_app
|
||||
local app = {
|
||||
root = { _p = nil, _c = {}, nav_to = function () end, tasks = {} }, ---@type nav_tree_page
|
||||
loaded = false,
|
||||
load = nil,
|
||||
cur_page = nil, ---@type nav_tree_page
|
||||
pane = pane,
|
||||
paned_pages = {}
|
||||
paned_pages = {},
|
||||
sidebar_items = {}
|
||||
}
|
||||
|
||||
app.load = function () app.loaded = true end
|
||||
|
||||
-- delayed set of the pane if it wasn't ready at the start
|
||||
---@param root_pane graphics_element multipane
|
||||
function app.set_root_pane(root_pane)
|
||||
app.pane = root_pane
|
||||
end
|
||||
|
||||
function app.set_sidebar(items)
|
||||
app.sidebar_items = items
|
||||
if self.sidebar then self.sidebar.update(items) end
|
||||
end
|
||||
|
||||
-- function to run on initial load into memory
|
||||
---@param on_load function callback
|
||||
function app.set_on_load(on_load)
|
||||
app.load = function ()
|
||||
on_load()
|
||||
app.loaded = true
|
||||
end
|
||||
end
|
||||
|
||||
-- if a pane was provided, this will switch between numbered pages
|
||||
---@param idx integer page index
|
||||
function app.switcher(idx)
|
||||
@ -107,9 +131,8 @@ function iocontrol.alloc_nav()
|
||||
---@type nav_tree_page
|
||||
local page = { _p = parent, _c = {}, nav_to = function () end, switcher = function () end, tasks = {} }
|
||||
|
||||
if parent == nil then
|
||||
app.root = page
|
||||
if app.cur_page == nil then app.cur_page = page end
|
||||
if parent == nil and app.cur_page == nil then
|
||||
app.cur_page = page
|
||||
end
|
||||
|
||||
if type(nav_to) == "number" then
|
||||
@ -160,9 +183,16 @@ function iocontrol.alloc_nav()
|
||||
-- open a given app
|
||||
---@param app_id POCKET_APP_ID
|
||||
function io.nav.open_app(app_id)
|
||||
if self.apps[app_id] then
|
||||
local app = self.apps[app_id] ---@type pocket_app
|
||||
if app then
|
||||
if not app.loaded then app.load() end
|
||||
|
||||
self.cur_app = app_id
|
||||
self.pane.set_value(app_id)
|
||||
|
||||
if #app.sidebar_items > 0 then
|
||||
self.sidebar.update(app.sidebar_items)
|
||||
end
|
||||
else
|
||||
log.debug("tried to open unknown app")
|
||||
end
|
||||
@ -227,6 +257,12 @@ function iocontrol.init_core(comms)
|
||||
alarm_buttons = {},
|
||||
tone_indicators = {} -- indicators to update from supervisor tone states
|
||||
}
|
||||
|
||||
-- API access
|
||||
---@class pocket_ioctl_api
|
||||
io.api = {
|
||||
get_unit = function (unit) comms.api__get_unit(unit) end
|
||||
}
|
||||
end
|
||||
|
||||
-- initialize facility-dependent components of pocket iocontrol
|
||||
@ -262,6 +298,16 @@ function iocontrol.init_fac(conf, temp_scale)
|
||||
auto_ramping = false,
|
||||
auto_saturated = false,
|
||||
|
||||
auto_scram = false,
|
||||
---@type ascram_status
|
||||
ascram_status = {
|
||||
matrix_dc = false,
|
||||
matrix_fill = false,
|
||||
crit_alarm = false,
|
||||
radiation = false,
|
||||
gen_fault = false
|
||||
},
|
||||
|
||||
---@type WASTE_PRODUCT
|
||||
auto_current_waste_product = types.WASTE_PRODUCT.PLUTONIUM,
|
||||
auto_pu_fallback_active = false,
|
||||
@ -282,11 +328,188 @@ function iocontrol.init_fac(conf, temp_scale)
|
||||
env_d_ps = psil.create(),
|
||||
env_d_data = {}
|
||||
}
|
||||
|
||||
-- create induction and SPS tables (currently only 1 of each is supported)
|
||||
table.insert(io.facility.induction_ps_tbl, psil.create())
|
||||
table.insert(io.facility.induction_data_tbl, {})
|
||||
table.insert(io.facility.sps_ps_tbl, psil.create())
|
||||
table.insert(io.facility.sps_data_tbl, {})
|
||||
|
||||
-- determine tank information
|
||||
if io.facility.tank_mode == 0 then
|
||||
io.facility.tank_defs = {}
|
||||
-- on facility tank mode 0, setup tank defs to match unit tank option
|
||||
for i = 1, conf.num_units do
|
||||
io.facility.tank_defs[i] = util.trinary(conf.cooling.r_cool[i].TankConnection, 1, 0)
|
||||
end
|
||||
|
||||
io.facility.tank_list = { table.unpack(io.facility.tank_defs) }
|
||||
else
|
||||
-- decode the layout of tanks from the connections definitions
|
||||
local tank_mode = io.facility.tank_mode
|
||||
local tank_defs = io.facility.tank_defs
|
||||
local tank_list = { table.unpack(tank_defs) }
|
||||
|
||||
local function calc_fdef(start_idx, end_idx)
|
||||
local first = 4
|
||||
for i = start_idx, end_idx do
|
||||
if io.facility.tank_defs[i] == 2 then
|
||||
if i < first then first = i end
|
||||
end
|
||||
end
|
||||
return first
|
||||
end
|
||||
|
||||
if tank_mode == 1 then
|
||||
-- (1) 1 total facility tank (A A A A)
|
||||
local first_fdef = calc_fdef(1, #tank_defs)
|
||||
for i = 1, #tank_defs do
|
||||
if i > first_fdef and tank_defs[i] == 2 then
|
||||
tank_list[i] = 0
|
||||
end
|
||||
end
|
||||
elseif tank_mode == 2 then
|
||||
-- (2) 2 total facility tanks (A A A B)
|
||||
local first_fdef = calc_fdef(1, math.min(3, #tank_defs))
|
||||
for i = 1, #tank_defs do
|
||||
if (i ~= 4) and (i > first_fdef) and (tank_defs[i] == 2) then
|
||||
tank_list[i] = 0
|
||||
end
|
||||
end
|
||||
elseif tank_mode == 3 then
|
||||
-- (3) 2 total facility tanks (A A B B)
|
||||
for _, a in pairs({ 1, 3 }) do
|
||||
local b = a + 1
|
||||
if (tank_defs[a] == 2) and (tank_defs[b] == 2) then
|
||||
tank_list[b] = 0
|
||||
end
|
||||
end
|
||||
elseif tank_mode == 4 then
|
||||
-- (4) 2 total facility tanks (A B B B)
|
||||
local first_fdef = calc_fdef(2, #tank_defs)
|
||||
for i = 1, #tank_defs do
|
||||
if (i ~= 1) and (i > first_fdef) and (tank_defs[i] == 2) then
|
||||
tank_list[i] = 0
|
||||
end
|
||||
end
|
||||
elseif tank_mode == 5 then
|
||||
-- (5) 3 total facility tanks (A A B C)
|
||||
local first_fdef = calc_fdef(1, math.min(2, #tank_defs))
|
||||
for i = 1, #tank_defs do
|
||||
if (not (i == 3 or i == 4)) and (i > first_fdef) and (tank_defs[i] == 2) then
|
||||
tank_list[i] = 0
|
||||
end
|
||||
end
|
||||
elseif tank_mode == 6 then
|
||||
-- (6) 3 total facility tanks (A B B C)
|
||||
local first_fdef = calc_fdef(2, math.min(3, #tank_defs))
|
||||
for i = 1, #tank_defs do
|
||||
if (not (i == 1 or i == 4)) and (i > first_fdef) and (tank_defs[i] == 2) then
|
||||
tank_list[i] = 0
|
||||
end
|
||||
end
|
||||
elseif tank_mode == 7 then
|
||||
-- (7) 3 total facility tanks (A B C C)
|
||||
local first_fdef = calc_fdef(3, #tank_defs)
|
||||
for i = 1, #tank_defs do
|
||||
if (not (i == 1 or i == 2)) and (i > first_fdef) and (tank_defs[i] == 2) then
|
||||
tank_list[i] = 0
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
io.facility.tank_list = tank_list
|
||||
end
|
||||
|
||||
-- create facility tank tables
|
||||
for i = 1, #io.facility.tank_list do
|
||||
if io.facility.tank_list[i] == 2 then
|
||||
table.insert(io.facility.tank_ps_tbl, psil.create())
|
||||
table.insert(io.facility.tank_data_tbl, {})
|
||||
end
|
||||
end
|
||||
|
||||
-- create unit data structures
|
||||
io.units = {}
|
||||
for i = 1, conf.num_units do
|
||||
---@class pioctl_unit
|
||||
local entry = {
|
||||
unit_id = i,
|
||||
connected = false,
|
||||
rtu_hw = {},
|
||||
|
||||
num_boilers = 0,
|
||||
num_turbines = 0,
|
||||
num_snas = 0,
|
||||
has_tank = conf.cooling.r_cool[i].TankConnection,
|
||||
|
||||
control_state = false,
|
||||
burn_rate_cmd = 0.0,
|
||||
radiation = types.new_zero_radiation_reading(),
|
||||
|
||||
sna_peak_rate = 0.0,
|
||||
sna_max_rate = 0.0,
|
||||
sna_out_rate = 0.0,
|
||||
|
||||
waste_mode = types.WASTE_MODE.MANUAL_PLUTONIUM,
|
||||
waste_product = types.WASTE_PRODUCT.PLUTONIUM,
|
||||
|
||||
-- auto control group
|
||||
a_group = 0,
|
||||
|
||||
---@type alarms
|
||||
alarms = { ALARM_STATE.INACTIVE, ALARM_STATE.INACTIVE, ALARM_STATE.INACTIVE, ALARM_STATE.INACTIVE, ALARM_STATE.INACTIVE, ALARM_STATE.INACTIVE, ALARM_STATE.INACTIVE, ALARM_STATE.INACTIVE, ALARM_STATE.INACTIVE, ALARM_STATE.INACTIVE, ALARM_STATE.INACTIVE, ALARM_STATE.INACTIVE },
|
||||
|
||||
annunciator = {}, ---@type annunciator
|
||||
|
||||
unit_ps = psil.create(),
|
||||
reactor_data = {}, ---@type reactor_db
|
||||
|
||||
boiler_ps_tbl = {},
|
||||
boiler_data_tbl = {},
|
||||
|
||||
turbine_ps_tbl = {},
|
||||
turbine_data_tbl = {},
|
||||
|
||||
tank_ps_tbl = {},
|
||||
tank_data_tbl = {}
|
||||
}
|
||||
|
||||
-- on other facility modes, overwrite unit TANK option with facility tank defs
|
||||
if io.facility.tank_mode ~= 0 then
|
||||
entry.has_tank = conf.cooling.fac_tank_defs[i] > 0
|
||||
end
|
||||
|
||||
-- create boiler tables
|
||||
for _ = 1, conf.cooling.r_cool[i].BoilerCount do
|
||||
table.insert(entry.boiler_ps_tbl, psil.create())
|
||||
table.insert(entry.boiler_data_tbl, {})
|
||||
end
|
||||
|
||||
-- create turbine tables
|
||||
for _ = 1, conf.cooling.r_cool[i].TurbineCount do
|
||||
table.insert(entry.turbine_ps_tbl, psil.create())
|
||||
table.insert(entry.turbine_data_tbl, {})
|
||||
end
|
||||
|
||||
-- create tank tables
|
||||
if io.facility.tank_defs[i] == 1 then
|
||||
table.insert(entry.tank_ps_tbl, psil.create())
|
||||
table.insert(entry.tank_data_tbl, {})
|
||||
end
|
||||
|
||||
entry.num_boilers = #entry.boiler_data_tbl
|
||||
entry.num_turbines = #entry.turbine_data_tbl
|
||||
|
||||
table.insert(io.units, entry)
|
||||
end
|
||||
end
|
||||
|
||||
-- set network link state
|
||||
---@param state POCKET_LINK_STATE
|
||||
function iocontrol.report_link_state(state)
|
||||
---@param sv_addr integer? supervisor address if linked
|
||||
---@param api_addr integer? coordinator address if linked
|
||||
function iocontrol.report_link_state(state, sv_addr, api_addr)
|
||||
io.ps.publish("link_state", state)
|
||||
|
||||
if state == LINK_STATE.API_LINK_ONLY or state == LINK_STATE.UNLINKED then
|
||||
@ -296,6 +519,11 @@ function iocontrol.report_link_state(state)
|
||||
if state == LINK_STATE.SV_LINK_ONLY or state == LINK_STATE.UNLINKED then
|
||||
io.ps.publish("crd_conn_quality", 0)
|
||||
end
|
||||
|
||||
if state == LINK_STATE.LINKED then
|
||||
io.ps.publish("sv_addr", sv_addr)
|
||||
io.ps.publish("api_addr", api_addr)
|
||||
end
|
||||
end
|
||||
|
||||
-- determine supervisor connection quality (trip time)
|
||||
@ -357,6 +585,188 @@ function iocontrol.record_facility_data(data)
|
||||
return valid
|
||||
end
|
||||
|
||||
-- update unit status data from API_GET_UNIT
|
||||
---@param data table
|
||||
function iocontrol.record_unit_data(data)
|
||||
if type(data[1]) == "number" and io.units[data[1]] then
|
||||
local unit = io.units[data[1]] ---@type pioctl_unit
|
||||
|
||||
unit.connected = data[2]
|
||||
unit.rtu_hw = data[3]
|
||||
unit.alarms = data[4]
|
||||
|
||||
--#region Annunciator
|
||||
|
||||
unit.annunciator = data[5]
|
||||
|
||||
local rcs_disconn, rcs_warn, rcs_hazard = false, false, false
|
||||
|
||||
for key, val in pairs(unit.annunciator) do
|
||||
if key == "BoilerOnline" or key == "TurbineOnline" then
|
||||
-- split up online arrays
|
||||
local every = true
|
||||
for id = 1, #val do
|
||||
every = every and val[id]
|
||||
unit.boiler_ps_tbl[id].publish(key, val[id])
|
||||
end
|
||||
|
||||
if not every then rcs_disconn = true end
|
||||
|
||||
unit.unit_ps.publish("U_" .. key, every)
|
||||
elseif key == "HeatingRateLow" or key == "WaterLevelLow" then
|
||||
-- split up array for all boilers
|
||||
local any = false
|
||||
for id = 1, #val do
|
||||
any = any or val[id]
|
||||
unit.boiler_ps_tbl[id].publish(key, val[id])
|
||||
end
|
||||
|
||||
if key == "HeatingRateLow" and any then
|
||||
rcs_warn = true
|
||||
elseif key == "WaterLevelLow" and any then
|
||||
rcs_hazard = true
|
||||
end
|
||||
|
||||
unit.unit_ps.publish("U_" .. key, any)
|
||||
elseif key == "SteamDumpOpen" or key == "TurbineOverSpeed" or key == "GeneratorTrip" or key == "TurbineTrip" then
|
||||
-- split up array for all turbines
|
||||
local any = false
|
||||
for id = 1, #val do
|
||||
any = any or val[id]
|
||||
unit.turbine_ps_tbl[id].publish(key, val[id])
|
||||
end
|
||||
|
||||
if key == "GeneratorTrip" and any then
|
||||
rcs_warn = true
|
||||
elseif (key == "TurbineOverSpeed" or key == "TurbineTrip") and any then
|
||||
rcs_hazard = true
|
||||
end
|
||||
|
||||
unit.unit_ps.publish("U_" .. key, any)
|
||||
else
|
||||
-- non-table fields
|
||||
unit.unit_ps.publish(key, val)
|
||||
end
|
||||
end
|
||||
|
||||
local anc = unit.annunciator
|
||||
rcs_hazard = rcs_hazard or anc.RCPTrip
|
||||
rcs_warn = rcs_warn or anc.RCSFlowLow or anc.CoolantLevelLow or anc.RCSFault or anc.MaxWaterReturnFeed or
|
||||
anc.CoolantFeedMismatch or anc.BoilRateMismatch or anc.SteamFeedMismatch or anc.MaxWaterReturnFeed
|
||||
|
||||
local rcs_status = 4
|
||||
if rcs_hazard then
|
||||
rcs_status = 2
|
||||
elseif rcs_warn then
|
||||
rcs_status = 3
|
||||
elseif rcs_disconn then
|
||||
rcs_status = 1
|
||||
end
|
||||
|
||||
unit.unit_ps.publish("U_RCS", rcs_status)
|
||||
|
||||
--#endregion
|
||||
|
||||
--#region Reactor Data
|
||||
|
||||
unit.reactor_data = data[6]
|
||||
|
||||
local control_status = 1
|
||||
local reactor_status = 1
|
||||
local rps_status = 1
|
||||
|
||||
if unit.connected then
|
||||
-- update RPS status
|
||||
if unit.reactor_data.rps_tripped then
|
||||
control_status = 2
|
||||
rps_status = util.trinary(unit.reactor_data.rps_trip_cause == "manual", 3, 2)
|
||||
else rps_status = 4 end
|
||||
|
||||
-- update reactor/control status
|
||||
if unit.reactor_data.mek_status.status then
|
||||
reactor_status = 4
|
||||
control_status = util.trinary(unit.annunciator.AutoControl, 4, 3)
|
||||
else
|
||||
if unit.reactor_data.no_reactor then
|
||||
reactor_status = 2
|
||||
elseif not unit.reactor_data.formed or unit.reactor_data.rps_status.force_dis then
|
||||
reactor_status = 3
|
||||
else
|
||||
reactor_status = 4
|
||||
end
|
||||
end
|
||||
|
||||
for key, val in pairs(unit.reactor_data) do
|
||||
if key ~= "rps_status" and key ~= "mek_struct" and key ~= "mek_status" then
|
||||
unit.unit_ps.publish(key, val)
|
||||
end
|
||||
end
|
||||
|
||||
if type(unit.reactor_data.rps_status) == "table" then
|
||||
for key, val in pairs(unit.reactor_data.rps_status) do
|
||||
unit.unit_ps.publish(key, val)
|
||||
end
|
||||
end
|
||||
|
||||
if type(unit.reactor_data.mek_status) == "table" then
|
||||
for key, val in pairs(unit.reactor_data.mek_status) do
|
||||
unit.unit_ps.publish(key, val)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
unit.unit_ps.publish("U_ControlStatus", control_status)
|
||||
unit.unit_ps.publish("U_ReactorStatus", reactor_status)
|
||||
unit.unit_ps.publish("U_RPS", rps_status)
|
||||
|
||||
--#endregion
|
||||
|
||||
unit.boiler_data_tbl = data[7]
|
||||
|
||||
for id = 1, #unit.boiler_data_tbl do
|
||||
local boiler = unit.boiler_data_tbl[id] ---@type boilerv_session_db
|
||||
local ps = unit.boiler_ps_tbl[id] ---@type psil
|
||||
|
||||
local boiler_status = 1
|
||||
|
||||
if unit.rtu_hw.boilers[id].connected then
|
||||
if unit.rtu_hw.boilers[id].faulted then
|
||||
boiler_status = 3
|
||||
elseif boiler.formed then
|
||||
boiler_status = 4
|
||||
else
|
||||
boiler_status = 2
|
||||
end
|
||||
end
|
||||
|
||||
ps.publish("BoilerStatus", boiler_status)
|
||||
end
|
||||
|
||||
unit.turbine_data_tbl = data[8]
|
||||
|
||||
for id = 1, #unit.turbine_data_tbl do
|
||||
local turbine = unit.turbine_data_tbl[id] ---@type turbinev_session_db
|
||||
local ps = unit.turbine_ps_tbl[id] ---@type psil
|
||||
|
||||
local turbine_status = 1
|
||||
|
||||
if unit.rtu_hw.turbines[id].connected then
|
||||
if unit.rtu_hw.turbines[id].faulted then
|
||||
turbine_status = 3
|
||||
elseif turbine.formed then
|
||||
turbine_status = 4
|
||||
else
|
||||
turbine_status = 2
|
||||
end
|
||||
end
|
||||
|
||||
ps.publish("TurbineStatus", turbine_status)
|
||||
end
|
||||
|
||||
unit.tank_data_tbl = data[9]
|
||||
end
|
||||
end
|
||||
|
||||
-- get the IO controller database
|
||||
function iocontrol.get_db() return io end
|
||||
|
||||
|
@ -119,6 +119,20 @@ function pocket.comms(version, nic, sv_watchdog, api_watchdog)
|
||||
self.api.seq_num = self.api.seq_num + 1
|
||||
end
|
||||
|
||||
-- send an API packet to the coordinator
|
||||
---@param msg_type CRDN_TYPE
|
||||
---@param msg table
|
||||
local function _send_api(msg_type, msg)
|
||||
local s_pkt = comms.scada_packet()
|
||||
local pkt = comms.crdn_packet()
|
||||
|
||||
pkt.make(msg_type, msg)
|
||||
s_pkt.make(self.api.addr, self.api.seq_num, PROTOCOL.SCADA_CRDN, pkt.raw_sendable())
|
||||
|
||||
nic.transmit(config.CRD_Channel, config.PKT_Channel, s_pkt)
|
||||
self.api.seq_num = self.api.seq_num + 1
|
||||
end
|
||||
|
||||
-- attempt supervisor connection establishment
|
||||
local function _send_sv_establish()
|
||||
_send_sv(MGMT_TYPE.ESTABLISH, { comms.version, version, DEVICE_TYPE.PKT })
|
||||
@ -192,7 +206,7 @@ function pocket.comms(version, nic, sv_watchdog, api_watchdog)
|
||||
end
|
||||
else
|
||||
-- linked, all good!
|
||||
iocontrol.report_link_state(LINK_STATE.LINKED)
|
||||
iocontrol.report_link_state(LINK_STATE.LINKED, self.sv.addr, self.api.addr)
|
||||
end
|
||||
end
|
||||
|
||||
@ -215,6 +229,11 @@ function pocket.comms(version, nic, sv_watchdog, api_watchdog)
|
||||
if self.sv.linked then _send_sv(MGMT_TYPE.DIAG_ALARM_SET, { id, state }) end
|
||||
end
|
||||
|
||||
-- coordinator get unit data
|
||||
function public.api__get_unit(unit)
|
||||
if self.api.linked then _send_api(CRDN_TYPE.API_GET_UNIT, { unit }) end
|
||||
end
|
||||
|
||||
-- parse a packet
|
||||
---@param side string
|
||||
---@param sender integer
|
||||
@ -304,7 +323,10 @@ function pocket.comms(version, nic, sv_watchdog, api_watchdog)
|
||||
if _check_length(packet, 11) then
|
||||
iocontrol.record_facility_data(packet.data)
|
||||
end
|
||||
elseif packet.type == CRDN_TYPE.API_GET_UNITS then
|
||||
elseif packet.type == CRDN_TYPE.API_GET_UNIT then
|
||||
if _check_length(packet, 9) then
|
||||
iocontrol.record_unit_data(packet.data)
|
||||
end
|
||||
else _fail_type(packet) end
|
||||
else
|
||||
log.debug("discarding coordinator SCADA_CRDN packet before linked")
|
||||
@ -358,7 +380,7 @@ function pocket.comms(version, nic, sv_watchdog, api_watchdog)
|
||||
self.api.addr = src_addr
|
||||
|
||||
if self.sv.linked then
|
||||
iocontrol.report_link_state(LINK_STATE.LINKED)
|
||||
iocontrol.report_link_state(LINK_STATE.LINKED, self.sv.addr, self.api.addr)
|
||||
else
|
||||
iocontrol.report_link_state(LINK_STATE.API_LINK_ONLY)
|
||||
end
|
||||
@ -497,7 +519,7 @@ function pocket.comms(version, nic, sv_watchdog, api_watchdog)
|
||||
self.sv.addr = src_addr
|
||||
|
||||
if self.api.linked then
|
||||
iocontrol.report_link_state(LINK_STATE.LINKED)
|
||||
iocontrol.report_link_state(LINK_STATE.LINKED, self.sv.addr, self.api.addr)
|
||||
else
|
||||
iocontrol.report_link_state(LINK_STATE.SV_LINK_ONLY)
|
||||
end
|
||||
|
@ -18,7 +18,7 @@ local iocontrol = require("pocket.iocontrol")
|
||||
local pocket = require("pocket.pocket")
|
||||
local renderer = require("pocket.renderer")
|
||||
|
||||
local POCKET_VERSION = "v0.8.0-alpha"
|
||||
local POCKET_VERSION = "v0.9.0-alpha"
|
||||
|
||||
local println = util.println
|
||||
local println_ts = util.println_ts
|
||||
|
@ -19,6 +19,8 @@ local function create_pages(root)
|
||||
db.nav.register_app(iocontrol.APP_ID.DUMMY, main).new_page(nil, function () end)
|
||||
|
||||
TextBox{parent=main,text="This app is not implemented yet.",x=1,y=2,alignment=core.ALIGN.CENTER}
|
||||
|
||||
TextBox{parent=main,text=" pretend something cool is here \x03",x=1,y=10,alignment=core.ALIGN.CENTER,fg_bg=core.cpair(colors.gray,colors.black)}
|
||||
end
|
||||
|
||||
return create_pages
|
||||
|
@ -3,10 +3,12 @@
|
||||
--
|
||||
|
||||
local comms = require("scada-common.comms")
|
||||
local lockbox = require("lockbox")
|
||||
local util = require("scada-common.util")
|
||||
|
||||
local lockbox = require("lockbox")
|
||||
|
||||
local iocontrol = require("pocket.iocontrol")
|
||||
local pocket = require("pocket.pocket")
|
||||
|
||||
local core = require("graphics.core")
|
||||
|
||||
@ -35,8 +37,9 @@ local function create_pages(root)
|
||||
local about_app = db.nav.register_app(iocontrol.APP_ID.ABOUT, about_root)
|
||||
|
||||
local about_page = about_app.new_page(nil, 1)
|
||||
local fw_page = about_app.new_page(about_page, 2)
|
||||
local hw_page = about_app.new_page(about_page, 3)
|
||||
local nt_page = about_app.new_page(about_page, 2)
|
||||
local fw_page = about_app.new_page(about_page, 3)
|
||||
local hw_page = about_app.new_page(about_page, 4)
|
||||
|
||||
local about = Div{parent=about_root,x=1,y=2}
|
||||
|
||||
@ -46,8 +49,42 @@ local function create_pages(root)
|
||||
local btn_active = cpair(colors.white, colors.black)
|
||||
local label = cpair(colors.lightGray, colors.black)
|
||||
|
||||
PushButton{parent=about,x=2,y=3,text="Firmware >",fg_bg=btn_fg_bg,active_fg_bg=btn_active,callback=fw_page.nav_to}
|
||||
PushButton{parent=about,x=2,y=4,text="Host Details >",fg_bg=btn_fg_bg,active_fg_bg=btn_active,callback=hw_page.nav_to}
|
||||
PushButton{parent=about,x=2,y=3,text="Network >",fg_bg=btn_fg_bg,active_fg_bg=btn_active,callback=nt_page.nav_to}
|
||||
PushButton{parent=about,x=2,y=4,text="Firmware >",fg_bg=btn_fg_bg,active_fg_bg=btn_active,callback=fw_page.nav_to}
|
||||
PushButton{parent=about,x=2,y=5,text="Host Details >",fg_bg=btn_fg_bg,active_fg_bg=btn_active,callback=hw_page.nav_to}
|
||||
|
||||
--#region Network Details
|
||||
|
||||
local config = pocket.config
|
||||
|
||||
local nt_div = Div{parent=about_root,x=1,y=2}
|
||||
TextBox{parent=nt_div,y=1,text="Network Details",height=1,alignment=ALIGN.CENTER}
|
||||
|
||||
PushButton{parent=nt_div,x=2,y=1,text="<",fg_bg=btn_fg_bg,active_fg_bg=btn_active,callback=about_page.nav_to}
|
||||
|
||||
TextBox{parent=nt_div,x=2,y=3,text="Pocket Address",height=1,alignment=ALIGN.LEFT,fg_bg=label}
|
||||
---@diagnostic disable-next-line: undefined-field
|
||||
TextBox{parent=nt_div,x=2,text=util.c(os.getComputerID(),":",config.PKT_Channel),height=1,alignment=ALIGN.LEFT}
|
||||
|
||||
nt_div.line_break()
|
||||
TextBox{parent=nt_div,x=2,text="Supervisor Address",height=1,alignment=ALIGN.LEFT,fg_bg=label}
|
||||
local sv = TextBox{parent=nt_div,x=2,text="",height=1,alignment=ALIGN.LEFT}
|
||||
|
||||
nt_div.line_break()
|
||||
TextBox{parent=nt_div,x=2,text="Coordinator Address",height=1,alignment=ALIGN.LEFT,fg_bg=label}
|
||||
local coord = TextBox{parent=nt_div,x=2,text="",height=1,alignment=ALIGN.LEFT}
|
||||
|
||||
sv.register(db.ps, "sv_addr", function (addr) sv.set_value(util.c(addr, ":", config.SVR_Channel)) end)
|
||||
coord.register(db.ps, "api_addr", function (addr) coord.set_value(util.c(addr, ":", config.CRD_Channel)) end)
|
||||
|
||||
nt_div.line_break()
|
||||
TextBox{parent=nt_div,x=2,text="Message Authentication",height=1,alignment=ALIGN.LEFT,fg_bg=label}
|
||||
local auth = util.trinary(type(config.AuthKey) == "string" and string.len(config.AuthKey) > 0, "HMAC-MD5", "None")
|
||||
TextBox{parent=nt_div,x=2,text=auth,height=1,alignment=ALIGN.LEFT}
|
||||
|
||||
--#endregion
|
||||
|
||||
--#region Firmware Versions
|
||||
|
||||
local fw_div = Div{parent=about_root,x=1,y=2}
|
||||
TextBox{parent=fw_div,y=1,text="Firmware Versions",height=1,alignment=ALIGN.CENTER}
|
||||
@ -81,6 +118,10 @@ local function create_pages(root)
|
||||
TextBox{parent=fw_list,x=2,text="Lockbox Version",height=1,alignment=ALIGN.LEFT,fg_bg=label}
|
||||
TextBox{parent=fw_list,x=2,text=lockbox.version,height=1,alignment=ALIGN.LEFT}
|
||||
|
||||
--#endregion
|
||||
|
||||
--#region Host Versions
|
||||
|
||||
local hw_div = Div{parent=about_root,x=1,y=2}
|
||||
TextBox{parent=hw_div,y=1,text="Host Versions",height=1,alignment=ALIGN.CENTER}
|
||||
|
||||
@ -94,7 +135,9 @@ local function create_pages(root)
|
||||
TextBox{parent=hw_div,x=2,text="Environment",height=1,alignment=ALIGN.LEFT,fg_bg=label}
|
||||
TextBox{parent=hw_div,x=2,text=_HOST,height=6,alignment=ALIGN.LEFT}
|
||||
|
||||
local root_pane = MultiPane{parent=about_root,x=1,y=1,panes={about,fw_div,hw_div}}
|
||||
--#endregion
|
||||
|
||||
local root_pane = MultiPane{parent=about_root,x=1,y=1,panes={about,nt_div,fw_div,hw_div}}
|
||||
|
||||
about_app.set_root_pane(root_pane)
|
||||
end
|
||||
|
@ -38,7 +38,7 @@ local function init(main)
|
||||
local db = iocontrol.get_db()
|
||||
|
||||
-- window header message
|
||||
TextBox{parent=main,y=1,text="DEV ALPHA APP S C ",alignment=ALIGN.LEFT,height=1,fg_bg=style.header}
|
||||
TextBox{parent=main,y=1,text="WIP ALPHA APP S C ",alignment=ALIGN.LEFT,height=1,fg_bg=style.header}
|
||||
local svr_conn = SignalBar{parent=main,y=1,x=22,compact=true,colors_low_med=cpair(colors.red,colors.yellow),disconnect_color=colors.lightGray,fg_bg=cpair(colors.green,colors.gray)}
|
||||
local crd_conn = SignalBar{parent=main,y=1,x=26,compact=true,colors_low_med=cpair(colors.red,colors.yellow),disconnect_color=colors.lightGray,fg_bg=cpair(colors.green,colors.gray)}
|
||||
|
||||
@ -71,10 +71,6 @@ local function init(main)
|
||||
|
||||
local page_div = Div{parent=main_pane,x=4,y=1}
|
||||
|
||||
local sidebar_tabs = {
|
||||
{ char = "#", color = cpair(colors.black, colors.green) }
|
||||
}
|
||||
|
||||
home_page(page_div)
|
||||
unit_page(page_div)
|
||||
|
||||
@ -84,13 +80,13 @@ local function init(main)
|
||||
|
||||
assert(#db.nav.get_containers() == iocontrol.APP_ID.NUM_APPS, "app IDs were not sequential or some apps weren't registered")
|
||||
|
||||
local page_pane = MultiPane{parent=page_div,x=1,y=1,panes=db.nav.get_containers()}
|
||||
db.nav.set_pane(page_pane)
|
||||
|
||||
Sidebar{parent=main_pane,x=1,y=1,tabs=sidebar_tabs,fg_bg=cpair(colors.white,colors.gray),callback=db.nav.open_app}
|
||||
db.nav.set_pane(MultiPane{parent=page_div,x=1,y=1,panes=db.nav.get_containers()})
|
||||
db.nav.set_sidebar(Sidebar{parent=main_pane,x=1,y=1,height=18,fg_bg=cpair(colors.white,colors.gray)})
|
||||
|
||||
PushButton{parent=main_pane,x=1,y=19,text="\x1b",min_width=3,fg_bg=cpair(colors.white,colors.gray),active_fg_bg=cpair(colors.gray,colors.black),callback=db.nav.nav_up}
|
||||
|
||||
db.nav.open_app(iocontrol.APP_ID.ROOT)
|
||||
|
||||
--#endregion
|
||||
end
|
||||
|
||||
|
@ -39,21 +39,26 @@ local function new_view(root)
|
||||
|
||||
local function open(id) db.nav.open_app(id) end
|
||||
|
||||
app.set_sidebar({
|
||||
{ label = " #\x10", tall = true, color = core.cpair(colors.black, colors.green), callback = function () open(APP_ID.ROOT) end }
|
||||
})
|
||||
|
||||
local active_fg_bg = cpair(colors.white,colors.gray)
|
||||
|
||||
App{parent=apps_1,x=3,y=2,text="U",title="Units",callback=function()open(APP_ID.UNITS)end,app_fg_bg=cpair(colors.black,colors.yellow),active_fg_bg=active_fg_bg}
|
||||
App{parent=apps_1,x=10,y=2,text="\x17",title="PRC",callback=function()open(APP_ID.DUMMY)end,app_fg_bg=cpair(colors.black,colors.purple),active_fg_bg=active_fg_bg}
|
||||
App{parent=apps_1,x=17,y=2,text="\x15",title="CTL",callback=function()open(APP_ID.DUMMY)end,app_fg_bg=cpair(colors.black,colors.green),active_fg_bg=active_fg_bg}
|
||||
App{parent=apps_1,x=3,y=7,text="\x08",title="DEV",callback=function()open(APP_ID.DUMMY)end,app_fg_bg=cpair(colors.black,colors.lightGray),active_fg_bg=active_fg_bg}
|
||||
App{parent=apps_1,x=10,y=7,text="\x7f",title="Waste",callback=function()open(APP_ID.DUMMY)end,app_fg_bg=cpair(colors.black,colors.brown),active_fg_bg=active_fg_bg}
|
||||
App{parent=apps_1,x=17,y=7,text="\xb6",title="Guide",callback=function()open(APP_ID.DUMMY)end,app_fg_bg=cpair(colors.black,colors.cyan),active_fg_bg=active_fg_bg}
|
||||
App{parent=apps_1,x=3,y=12,text="?",title="About",callback=function()open(APP_ID.ABOUT)end,app_fg_bg=cpair(colors.black,colors.white),active_fg_bg=active_fg_bg}
|
||||
App{parent=apps_1,x=2,y=2,text="U",title="Units",callback=function()open(APP_ID.UNITS)end,app_fg_bg=cpair(colors.black,colors.yellow),active_fg_bg=active_fg_bg}
|
||||
App{parent=apps_1,x=9,y=2,text="F",title="Facil",callback=function()open(APP_ID.DUMMY)end,app_fg_bg=cpair(colors.black,colors.orange),active_fg_bg=active_fg_bg}
|
||||
App{parent=apps_1,x=16,y=2,text="\x15",title="Control",callback=function()open(APP_ID.DUMMY)end,app_fg_bg=cpair(colors.black,colors.green),active_fg_bg=active_fg_bg}
|
||||
App{parent=apps_1,x=2,y=7,text="\x17",title="Process",callback=function()open(APP_ID.DUMMY)end,app_fg_bg=cpair(colors.black,colors.purple),active_fg_bg=active_fg_bg}
|
||||
App{parent=apps_1,x=9,y=7,text="\x7f",title="Waste",callback=function()open(APP_ID.DUMMY)end,app_fg_bg=cpair(colors.black,colors.brown),active_fg_bg=active_fg_bg}
|
||||
App{parent=apps_1,x=16,y=7,text="\x08",title="Devices",callback=function()open(APP_ID.DUMMY)end,app_fg_bg=cpair(colors.black,colors.lightGray),active_fg_bg=active_fg_bg}
|
||||
App{parent=apps_1,x=2,y=12,text="\xb6",title="Guide",callback=function()open(APP_ID.DUMMY)end,app_fg_bg=cpair(colors.black,colors.cyan),active_fg_bg=active_fg_bg}
|
||||
App{parent=apps_1,x=9,y=12,text="?",title="About",callback=function()open(APP_ID.ABOUT)end,app_fg_bg=cpair(colors.black,colors.white),active_fg_bg=active_fg_bg}
|
||||
|
||||
TextBox{parent=apps_2,text="Diagnostic Apps",x=1,y=2,height=1,alignment=ALIGN.CENTER}
|
||||
|
||||
App{parent=apps_2,x=3,y=4,text="\x0f",title="Alarm",callback=function()open(APP_ID.ALARMS)end,app_fg_bg=cpair(colors.black,colors.red),active_fg_bg=active_fg_bg}
|
||||
App{parent=apps_2,x=10,y=4,text="\x1e",title="LoopT",callback=function()open(APP_ID.DUMMY)end,app_fg_bg=cpair(colors.black,colors.cyan),active_fg_bg=active_fg_bg}
|
||||
App{parent=apps_2,x=17,y=4,text="@",title="Comps",callback=function()open(APP_ID.DUMMY)end,app_fg_bg=cpair(colors.black,colors.orange),active_fg_bg=active_fg_bg}
|
||||
App{parent=apps_2,x=2,y=4,text="\x0f",title="Alarm",callback=function()open(APP_ID.ALARMS)end,app_fg_bg=cpair(colors.black,colors.red),active_fg_bg=active_fg_bg}
|
||||
App{parent=apps_2,x=9,y=4,text="\x1e",title="LoopT",callback=function()open(APP_ID.DUMMY)end,app_fg_bg=cpair(colors.black,colors.cyan),active_fg_bg=active_fg_bg}
|
||||
App{parent=apps_2,x=16,y=4,text="@",title="Comps",callback=function()open(APP_ID.DUMMY)end,app_fg_bg=cpair(colors.black,colors.orange),active_fg_bg=active_fg_bg}
|
||||
|
||||
return main
|
||||
end
|
||||
|
@ -2,14 +2,56 @@
|
||||
-- Unit Overview Page
|
||||
--
|
||||
|
||||
local util = require("scada-common.util")
|
||||
-- local log = require("scada-common.log")
|
||||
|
||||
local iocontrol = require("pocket.iocontrol")
|
||||
|
||||
local core = require("graphics.core")
|
||||
|
||||
local Div = require("graphics.elements.div")
|
||||
local MultiPane = require("graphics.elements.multipane")
|
||||
local TextBox = require("graphics.elements.textbox")
|
||||
|
||||
local DataIndicator = require("graphics.elements.indicators.data")
|
||||
local IconIndicator = require("graphics.elements.indicators.icon")
|
||||
-- local RadIndicator = require("graphics.elements.indicators.rad")
|
||||
-- local VerticalBar = require("graphics.elements.indicators.vbar")
|
||||
|
||||
local PushButton = require("graphics.elements.controls.push_button")
|
||||
|
||||
local ALIGN = core.ALIGN
|
||||
local cpair = core.cpair
|
||||
|
||||
local basic_states = {
|
||||
{ color = cpair(colors.black, colors.lightGray), symbol = "\x07" },
|
||||
{ color = cpair(colors.black, colors.red), symbol = "-" },
|
||||
{ color = cpair(colors.black, colors.yellow), symbol = "\x1e" },
|
||||
{ color = cpair(colors.black, colors.green), symbol = "+" }
|
||||
}
|
||||
|
||||
local mode_states = {
|
||||
{ color = cpair(colors.black, colors.lightGray), symbol = "\x07" },
|
||||
{ color = cpair(colors.black, colors.red), symbol = "-" },
|
||||
{ color = cpair(colors.black, colors.green), symbol = "+" },
|
||||
{ color = cpair(colors.black, colors.purple), symbol = "A" }
|
||||
}
|
||||
|
||||
local emc_ind_s = {
|
||||
{ color = cpair(colors.black, colors.gray), symbol = "-" },
|
||||
{ color = cpair(colors.black, colors.white), symbol = "\x07" },
|
||||
{ color = cpair(colors.black, colors.green), symbol = "+" }
|
||||
}
|
||||
|
||||
local red_ind_s = {
|
||||
{ color = cpair(colors.black, colors.lightGray), symbol = "+" },
|
||||
{ color = cpair(colors.black, colors.red), symbol = "-" }
|
||||
}
|
||||
|
||||
local yel_ind_s = {
|
||||
{ color = cpair(colors.black, colors.lightGray), symbol = "+" },
|
||||
{ color = cpair(colors.black, colors.yellow), symbol = "-" }
|
||||
}
|
||||
|
||||
-- new unit page view
|
||||
---@param root graphics_element parent
|
||||
@ -19,11 +61,259 @@ local function new_view(root)
|
||||
local main = Div{parent=root,x=1,y=1}
|
||||
|
||||
local app = db.nav.register_app(iocontrol.APP_ID.UNITS, main)
|
||||
app.new_page(nil, function () end)
|
||||
|
||||
TextBox{parent=main,y=2,text="UNITS",height=1,alignment=ALIGN.CENTER}
|
||||
TextBox{parent=main,y=2,text="Units App",height=1,alignment=ALIGN.CENTER}
|
||||
|
||||
TextBox{parent=main,y=4,text="work in progress",height=1,alignment=ALIGN.CENTER}
|
||||
TextBox{parent=main,y=4,text="Loading...",height=1,alignment=ALIGN.CENTER}
|
||||
|
||||
local btn_fg_bg = cpair(colors.yellow, colors.black)
|
||||
local btn_active = cpair(colors.white, colors.black)
|
||||
-- local label = cpair(colors.lightGray, colors.black)
|
||||
|
||||
local nav_links = {}
|
||||
|
||||
local function set_sidebar(id)
|
||||
-- local unit = db.units[id] ---@type pioctl_unit
|
||||
|
||||
local list = {
|
||||
{ label = " # ", tall = true, color = core.cpair(colors.black, colors.green), callback = function () db.nav.open_app(iocontrol.APP_ID.ROOT) end },
|
||||
{ label = "U-" .. id, color = core.cpair(colors.black, colors.yellow), callback = function () app.switcher(id) end },
|
||||
{ label = " \x13 ", color = core.cpair(colors.black, colors.red), callback = nav_links[id].alarm },
|
||||
{ label = "RPS", tall = true, color = core.cpair(colors.black, colors.cyan), callback = nav_links[id].rps },
|
||||
-- { label = " R ", color = core.cpair(colors.black, colors.lightGray), callback = function () end },
|
||||
{ label = "RCS", tall = true, color = core.cpair(colors.black, colors.blue), callback = nav_links[id].rcs },
|
||||
}
|
||||
|
||||
-- for i = 1, unit.num_boilers do
|
||||
-- table.insert(list, { label = "B-" .. i, color = core.cpair(colors.black, colors.lightBlue), callback = function () end })
|
||||
-- end
|
||||
|
||||
-- for i = 1, unit.num_turbines do
|
||||
-- table.insert(list, { label = "T-" .. i, color = core.cpair(colors.black, colors.white), callback = function () end })
|
||||
-- end
|
||||
|
||||
app.set_sidebar(list)
|
||||
end
|
||||
|
||||
local function load()
|
||||
local page_div = Div{parent=main,x=2,y=2,width=main.get_width()-2}
|
||||
|
||||
local panes = {}
|
||||
|
||||
local active_unit = 1
|
||||
|
||||
-- create all page divs
|
||||
for _ = 1, db.facility.num_units do
|
||||
local div = Div{parent=page_div}
|
||||
table.insert(panes, div)
|
||||
table.insert(nav_links, {})
|
||||
end
|
||||
|
||||
-- previous unit
|
||||
local function prev(x)
|
||||
active_unit = util.trinary(x == 1, db.facility.num_units, x - 1)
|
||||
app.switcher(active_unit)
|
||||
set_sidebar(active_unit)
|
||||
end
|
||||
|
||||
-- next unit
|
||||
local function next(x)
|
||||
active_unit = util.trinary(x == db.facility.num_units, 1, x + 1)
|
||||
app.switcher(active_unit)
|
||||
set_sidebar(active_unit)
|
||||
end
|
||||
|
||||
for i = 1, db.facility.num_units do
|
||||
local u_div = panes[i] ---@type graphics_element
|
||||
local unit = db.units[i] ---@type pioctl_unit
|
||||
local u_ps = unit.unit_ps
|
||||
|
||||
-- refresh data callback, every 500ms it will re-send the query
|
||||
local last_update = 0
|
||||
local function update()
|
||||
if util.time_ms() - last_update >= 500 then
|
||||
db.api.get_unit(i)
|
||||
last_update = util.time_ms()
|
||||
end
|
||||
end
|
||||
|
||||
--#region Main Unit Overview
|
||||
|
||||
local u_page = app.new_page(nil, i)
|
||||
u_page.tasks = { update }
|
||||
|
||||
TextBox{parent=u_div,y=1,text="Reactor Unit #"..i,height=1,alignment=ALIGN.CENTER}
|
||||
PushButton{parent=u_div,x=1,y=1,text="<",fg_bg=btn_fg_bg,active_fg_bg=btn_active,callback=function()prev(i)end}
|
||||
PushButton{parent=u_div,x=21,y=1,text=">",fg_bg=btn_fg_bg,active_fg_bg=btn_active,callback=function()next(i)end}
|
||||
|
||||
local type = util.trinary(unit.num_boilers > 0, "Sodium Cooled Reactor", "Boiling Water Reactor")
|
||||
TextBox{parent=u_div,y=3,text=type,height=1,alignment=ALIGN.CENTER,fg_bg=cpair(colors.gray,colors.black)}
|
||||
|
||||
local lu_col = cpair(colors.lightGray, colors.lightGray)
|
||||
local text_fg = cpair(colors.white, colors._INHERIT)
|
||||
|
||||
local rate = DataIndicator{parent=u_div,y=5,lu_colors=lu_col,label="Rate",unit="mB/t",format="%10.2f",value=0,commas=true,width=26,fg_bg=text_fg}
|
||||
local temp = DataIndicator{parent=u_div,lu_colors=lu_col,label="Temp",unit="K",format="%10.2f",value=0,commas=true,width=26,fg_bg=text_fg}
|
||||
|
||||
local ctrl = IconIndicator{parent=u_div,x=1,y=8,label="Control State",states=mode_states}
|
||||
|
||||
rate.register(u_ps, "act_burn_rate", rate.update)
|
||||
temp.register(u_ps, "temp", temp.update)
|
||||
ctrl.register(u_ps, "U_ControlStatus", ctrl.update)
|
||||
|
||||
u_div.line_break()
|
||||
|
||||
local rct = IconIndicator{parent=u_div,x=1,label="Fission Reactor",states=basic_states}
|
||||
local rps = IconIndicator{parent=u_div,x=1,label="Protection System",states=basic_states}
|
||||
|
||||
rct.register(u_ps, "U_ReactorStatus", rct.update)
|
||||
rps.register(u_ps, "U_RPS", rps.update)
|
||||
|
||||
u_div.line_break()
|
||||
|
||||
local rcs = IconIndicator{parent=u_div,x=1,label="Coolant System",states=basic_states}
|
||||
rcs.register(u_ps, "U_RCS", rcs.update)
|
||||
|
||||
for b = 1, unit.num_boilers do
|
||||
local blr = IconIndicator{parent=u_div,x=1,label="Boiler "..b,states=basic_states}
|
||||
blr.register(unit.boiler_ps_tbl[b], "BoilerStatus", blr.update)
|
||||
end
|
||||
|
||||
for t = 1, unit.num_turbines do
|
||||
local tbn = IconIndicator{parent=u_div,x=1,label="Turbine "..t,states=basic_states}
|
||||
tbn.register(unit.turbine_ps_tbl[t], "TurbineStatus", tbn.update)
|
||||
end
|
||||
|
||||
--#endregion
|
||||
|
||||
--#region Alarms Tab
|
||||
|
||||
local alm_div = Div{parent=page_div}
|
||||
table.insert(panes, alm_div)
|
||||
|
||||
local alm_page = app.new_page(u_page, #panes)
|
||||
alm_page.tasks = { update }
|
||||
|
||||
nav_links[i].alarm = alm_page.nav_to
|
||||
|
||||
TextBox{parent=alm_div,y=1,text="Unit Alarms",height=1,alignment=ALIGN.CENTER}
|
||||
|
||||
TextBox{parent=alm_div,y=3,text="work in progress",height=1,alignment=ALIGN.CENTER,fg_bg=cpair(colors.gray,colors.black)}
|
||||
|
||||
--#endregion
|
||||
|
||||
--#region RPS Tab
|
||||
|
||||
local rps_div = Div{parent=page_div}
|
||||
table.insert(panes, rps_div)
|
||||
|
||||
local rps_page = app.new_page(u_page, #panes)
|
||||
rps_page.tasks = { update }
|
||||
|
||||
nav_links[i].rps = rps_page.nav_to
|
||||
|
||||
TextBox{parent=rps_div,y=1,text="Protection System",height=1,alignment=ALIGN.CENTER}
|
||||
|
||||
local r_trip = IconIndicator{parent=rps_div,y=3,label="RPS Trip",states=basic_states}
|
||||
r_trip.register(u_ps, "U_RPS", r_trip.update)
|
||||
|
||||
local r_mscrm = IconIndicator{parent=rps_div,y=5,label="Manual SCRAM",states=red_ind_s}
|
||||
local r_ascrm = IconIndicator{parent=rps_div,label="Automatic SCRAM",states=red_ind_s}
|
||||
local rps_tmo = IconIndicator{parent=rps_div,label="Timeout",states=yel_ind_s}
|
||||
local rps_flt = IconIndicator{parent=rps_div,label="PPM Fault",states=yel_ind_s}
|
||||
local rps_sfl = IconIndicator{parent=rps_div,label="Not Formed",states=red_ind_s}
|
||||
|
||||
r_mscrm.register(u_ps, "manual", r_mscrm.update)
|
||||
r_ascrm.register(u_ps, "automatic", r_ascrm.update)
|
||||
rps_tmo.register(u_ps, "timeout", rps_tmo.update)
|
||||
rps_flt.register(u_ps, "fault", rps_flt.update)
|
||||
rps_sfl.register(u_ps, "sys_fail", rps_sfl.update)
|
||||
|
||||
rps_div.line_break()
|
||||
local rps_dmg = IconIndicator{parent=rps_div,label="Reactor Damage Hi",states=red_ind_s}
|
||||
local rps_tmp = IconIndicator{parent=rps_div,label="Temp. Critical",states=red_ind_s}
|
||||
local rps_nof = IconIndicator{parent=rps_div,label="Fuel Level Lo",states=yel_ind_s}
|
||||
local rps_exw = IconIndicator{parent=rps_div,label="Waste Level Hi",states=yel_ind_s}
|
||||
local rps_loc = IconIndicator{parent=rps_div,label="Coolant Lo Lo",states=yel_ind_s}
|
||||
local rps_exh = IconIndicator{parent=rps_div,label="Heated Coolant Hi",states=yel_ind_s}
|
||||
|
||||
rps_dmg.register(u_ps, "high_dmg", rps_dmg.update)
|
||||
rps_tmp.register(u_ps, "high_temp", rps_tmp.update)
|
||||
rps_nof.register(u_ps, "no_fuel", rps_nof.update)
|
||||
rps_exw.register(u_ps, "ex_waste", rps_exw.update)
|
||||
rps_loc.register(u_ps, "low_cool", rps_loc.update)
|
||||
rps_exh.register(u_ps, "ex_hcool", rps_exh.update)
|
||||
|
||||
--#endregion
|
||||
|
||||
--#region RCS Tab
|
||||
|
||||
local rcs_div = Div{parent=page_div}
|
||||
table.insert(panes, rcs_div)
|
||||
|
||||
local rcs_page = app.new_page(u_page, #panes)
|
||||
rcs_page.tasks = { update }
|
||||
|
||||
nav_links[i].rcs = rcs_page.nav_to
|
||||
|
||||
TextBox{parent=rcs_div,y=1,text="Coolant System",height=1,alignment=ALIGN.CENTER}
|
||||
|
||||
local r_rtrip = IconIndicator{parent=rcs_div,y=3,label="RCP Trip",states=red_ind_s}
|
||||
local r_cflow = IconIndicator{parent=rcs_div,label="RCS Flow Lo",states=yel_ind_s}
|
||||
local r_clow = IconIndicator{parent=rcs_div,label="Coolant Level Lo",states=yel_ind_s}
|
||||
|
||||
r_rtrip.register(u_ps, "RCPTrip", r_rtrip.update)
|
||||
r_cflow.register(u_ps, "RCSFlowLow", r_cflow.update)
|
||||
r_clow.register(u_ps, "CoolantLevelLow", r_clow.update)
|
||||
|
||||
local c_flt = IconIndicator{parent=rcs_div,label="RCS HW Fault",states=yel_ind_s}
|
||||
local c_emg = IconIndicator{parent=rcs_div,label="Emergency Coolant",states=emc_ind_s}
|
||||
local c_mwrf = IconIndicator{parent=rcs_div,label="Max Water Return",states=yel_ind_s}
|
||||
|
||||
c_flt.register(u_ps, "RCSFault", c_flt.update)
|
||||
c_emg.register(u_ps, "EmergencyCoolant", c_emg.update)
|
||||
c_mwrf.register(u_ps, "MaxWaterReturnFeed", c_mwrf.update)
|
||||
|
||||
-- rcs_div.line_break()
|
||||
-- TextBox{parent=rcs_div,text="Mismatches",height=1,alignment=ALIGN.CENTER,fg_bg=label}
|
||||
local c_cfm = IconIndicator{parent=rcs_div,label="Coolant Feed",states=yel_ind_s}
|
||||
local c_brm = IconIndicator{parent=rcs_div,label="Boil Rate",states=yel_ind_s}
|
||||
local c_sfm = IconIndicator{parent=rcs_div,label="Steam Feed",states=yel_ind_s}
|
||||
|
||||
c_cfm.register(u_ps, "CoolantFeedMismatch", c_cfm.update)
|
||||
c_brm.register(u_ps, "BoilRateMismatch", c_brm.update)
|
||||
c_sfm.register(u_ps, "SteamFeedMismatch", c_sfm.update)
|
||||
|
||||
rcs_div.line_break()
|
||||
-- TextBox{parent=rcs_div,text="Aggregate Checks",height=1,alignment=ALIGN.CENTER,fg_bg=label}
|
||||
|
||||
if unit.num_boilers > 0 then
|
||||
local wll = IconIndicator{parent=rcs_div,label="Boiler Water Lo",states=red_ind_s}
|
||||
local hrl = IconIndicator{parent=rcs_div,label="Heating Rate Lo",states=yel_ind_s}
|
||||
|
||||
wll.register(u_ps, "U_WaterLevelLow", wll.update)
|
||||
hrl.register(u_ps, "U_HeatingRateLow", hrl.update)
|
||||
end
|
||||
|
||||
local tospd = IconIndicator{parent=rcs_div,label="TRB Over Speed",states=red_ind_s}
|
||||
local gtrip = IconIndicator{parent=rcs_div,label="Generator Trip",states=yel_ind_s}
|
||||
local ttrip = IconIndicator{parent=rcs_div,label="Turbine Trip",states=red_ind_s}
|
||||
|
||||
tospd.register(u_ps, "U_TurbineOverSpeed", tospd.update)
|
||||
gtrip.register(u_ps, "U_GeneratorTrip", gtrip.update)
|
||||
ttrip.register(u_ps, "U_TurbineTrip", ttrip.update)
|
||||
|
||||
--#endregion
|
||||
end
|
||||
|
||||
-- setup multipane
|
||||
local u_pane = MultiPane{parent=page_div,x=1,y=1,panes=panes}
|
||||
app.set_root_pane(u_pane)
|
||||
|
||||
set_sidebar(active_unit)
|
||||
end
|
||||
|
||||
app.set_on_load(load)
|
||||
|
||||
return main
|
||||
end
|
||||
|
@ -25,8 +25,8 @@ local RPS_LIMITS = const.RPS_LIMITS
|
||||
|
||||
-- I sure hope the devs don't change this error message, not that it would have safety implications
|
||||
-- I wish they didn't change it to be like this
|
||||
local PCALL_SCRAM_MSG = "pcall: Scram requires the reactor to be active."
|
||||
local PCALL_START_MSG = "pcall: Reactor is already active."
|
||||
local PCALL_SCRAM_MSG = "Scram requires the reactor to be active."
|
||||
local PCALL_START_MSG = "Reactor is already active."
|
||||
|
||||
---@type plc_config
|
||||
local config = {}
|
||||
@ -307,7 +307,7 @@ function plc.rps_init(reactor, is_formed)
|
||||
log.info("RPS: reactor SCRAM")
|
||||
|
||||
reactor.scram()
|
||||
if reactor.__p_is_faulted() and (reactor.__p_last_fault() ~= PCALL_SCRAM_MSG) then
|
||||
if reactor.__p_is_faulted() and not string.find(reactor.__p_last_fault(), PCALL_SCRAM_MSG) then
|
||||
log.error("RPS: failed reactor SCRAM")
|
||||
return false
|
||||
else
|
||||
@ -325,7 +325,7 @@ function plc.rps_init(reactor, is_formed)
|
||||
log.info("RPS: reactor start")
|
||||
|
||||
reactor.activate()
|
||||
if reactor.__p_is_faulted() and (reactor.__p_last_fault() ~= PCALL_START_MSG) then
|
||||
if reactor.__p_is_faulted() and not string.find(reactor.__p_last_fault(), PCALL_START_MSG) then
|
||||
log.error("RPS: failed reactor start")
|
||||
else
|
||||
self.reactor_enabled = true
|
||||
|
@ -18,7 +18,7 @@ local plc = require("reactor-plc.plc")
|
||||
local renderer = require("reactor-plc.renderer")
|
||||
local threads = require("reactor-plc.threads")
|
||||
|
||||
local R_PLC_VERSION = "v1.7.10"
|
||||
local R_PLC_VERSION = "v1.7.11"
|
||||
|
||||
local println = util.println
|
||||
local println_ts = util.println_ts
|
||||
|
@ -1669,9 +1669,11 @@ function configurator.configure(ask_config)
|
||||
elseif event == "paste" then
|
||||
display.handle_paste(param1)
|
||||
elseif event == "peripheral_detach" then
|
||||
---@diagnostic disable-next-line: discard-returns
|
||||
ppm.handle_unmount(param1)
|
||||
tool_ctl.update_peri_list()
|
||||
elseif event == "peripheral" then
|
||||
---@diagnostic disable-next-line: discard-returns
|
||||
ppm.mount(param1)
|
||||
tool_ctl.update_peri_list()
|
||||
end
|
||||
|
@ -31,7 +31,7 @@ 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 RTU_VERSION = "v1.9.5"
|
||||
local RTU_VERSION = "v1.9.6"
|
||||
|
||||
local RTU_UNIT_TYPE = types.RTU_UNIT_TYPE
|
||||
local RTU_UNIT_HW_STATE = databus.RTU_UNIT_HW_STATE
|
||||
|
@ -18,7 +18,7 @@ local comms = {}
|
||||
|
||||
-- protocol/data versions (protocol/data independent changes tracked by util.lua version)
|
||||
comms.version = "2.5.1"
|
||||
comms.api_version = "0.0.1"
|
||||
comms.api_version = "0.0.2"
|
||||
|
||||
---@enum PROTOCOL
|
||||
local PROTOCOL = {
|
||||
@ -67,7 +67,7 @@ local CRDN_TYPE = {
|
||||
UNIT_STATUSES = 5, -- state of each of the reactor units
|
||||
UNIT_CMD = 6, -- command a reactor unit
|
||||
API_GET_FAC = 7, -- API: get all the facility data
|
||||
API_GET_UNITS = 8 -- API: get all the reactor unit data
|
||||
API_GET_UNIT = 8 -- API: get reactor unit data
|
||||
}
|
||||
|
||||
---@enum ESTABLISH_ACK
|
||||
|
@ -658,6 +658,7 @@ function plc.new_session(id, s_addr, reactor_id, in_queue, out_queue, timeout, f
|
||||
local cmd = message.message
|
||||
if cmd == PLC_S_CMDS.ENABLE then
|
||||
-- enable reactor
|
||||
self.acks.disable = true
|
||||
if not self.auto_lock then
|
||||
_send(RPLC_TYPE.RPS_ENABLE, {})
|
||||
end
|
||||
@ -714,6 +715,7 @@ function plc.new_session(id, s_addr, reactor_id, in_queue, out_queue, timeout, f
|
||||
self.auto_cmd_token = 0
|
||||
self.ramping_rate = true
|
||||
self.acks.burn_rate = false
|
||||
self.acks.disable = true
|
||||
self.retry_times.burn_rate_req = util.time() + INITIAL_WAIT
|
||||
_send(RPLC_TYPE.MEK_BURN_RATE, { self.commanded_burn_rate, self.ramping_rate })
|
||||
end
|
||||
@ -728,6 +730,7 @@ function plc.new_session(id, s_addr, reactor_id, in_queue, out_queue, timeout, f
|
||||
|
||||
-- this is only for manual control, only retry auto ramps
|
||||
self.acks.burn_rate = not self.ramping_rate
|
||||
self.acks.disable = true
|
||||
self.retry_times.burn_rate_req = util.time() + INITIAL_AUTO_WAIT
|
||||
|
||||
_send(RPLC_TYPE.AUTO_BURN_RATE, { self.commanded_burn_rate, self.ramping_rate, self.auto_cmd_token })
|
||||
|
@ -21,7 +21,7 @@ local supervisor = require("supervisor.supervisor")
|
||||
|
||||
local svsessions = require("supervisor.session.svsessions")
|
||||
|
||||
local SUPERVISOR_VERSION = "v1.3.10"
|
||||
local SUPERVISOR_VERSION = "v1.3.11"
|
||||
|
||||
local println = util.println
|
||||
local println_ts = util.println_ts
|
||||
|
Loading…
Reference in New Issue
Block a user