commit
6eb9ac5845
@ -132,7 +132,9 @@ function iocontrol.init(conf, comms, temp_scale, energy_scale)
|
||||
sps_data_tbl = {}, ---@type sps_session_db[]
|
||||
|
||||
tank_ps_tbl = {}, ---@type psil[]
|
||||
tank_data_tbl = {} ---@type dynamicv_session_db[]
|
||||
tank_data_tbl = {}, ---@type dynamicv_session_db[]
|
||||
|
||||
rad_monitors = {} ---@type { radiation: radiation_reading, raw: number }[]
|
||||
}
|
||||
|
||||
-- create induction and SPS tables (currently only 1 of each is supported)
|
||||
@ -242,7 +244,9 @@ function iocontrol.init(conf, comms, temp_scale, energy_scale)
|
||||
turbine_data_tbl = {}, ---@type turbinev_session_db[]
|
||||
|
||||
tank_ps_tbl = {}, ---@type psil[]
|
||||
tank_data_tbl = {} ---@type dynamicv_session_db[]
|
||||
tank_data_tbl = {}, ---@type dynamicv_session_db[]
|
||||
|
||||
rad_monitors = {} ---@type { radiation: radiation_reading, raw: number }[]
|
||||
}
|
||||
|
||||
-- on other facility modes, overwrite unit TANK option with facility tank defs
|
||||
@ -797,7 +801,9 @@ function iocontrol.update_facility_status(status)
|
||||
if type(rtu_statuses.envds) == "table" then
|
||||
local max_rad, max_reading, any_conn, any_faulted = 0, types.new_zero_radiation_reading(), false, false
|
||||
|
||||
for _, envd in pairs(rtu_statuses.envds) do
|
||||
fac.rad_monitors = {}
|
||||
|
||||
for id, envd in pairs(rtu_statuses.envds) do
|
||||
local rtu_faulted = envd[1] ---@type boolean
|
||||
local radiation = envd[2] ---@type radiation_reading
|
||||
local rad_raw = envd[3] ---@type number
|
||||
@ -809,6 +815,10 @@ function iocontrol.update_facility_status(status)
|
||||
max_rad = rad_raw
|
||||
max_reading = radiation
|
||||
end
|
||||
|
||||
if not rtu_faulted then
|
||||
fac.rad_monitors[id] = { radiation = radiation, raw = rad_raw }
|
||||
end
|
||||
end
|
||||
|
||||
if any_conn then
|
||||
@ -1099,9 +1109,12 @@ function iocontrol.update_unit_statuses(statuses)
|
||||
if type(rtu_statuses.envds) == "table" then
|
||||
local max_rad, max_reading, any_conn = 0, types.new_zero_radiation_reading(), false
|
||||
|
||||
for _, envd in pairs(rtu_statuses.envds) do
|
||||
local radiation = envd[2] ---@type radiation_reading
|
||||
local rad_raw = envd[3] ---@type number
|
||||
unit.rad_monitors = {}
|
||||
|
||||
for id, envd in pairs(rtu_statuses.envds) do
|
||||
local rtu_faulted = envd[1] ---@type boolean
|
||||
local radiation = envd[2] ---@type radiation_reading
|
||||
local rad_raw = envd[3] ---@type number
|
||||
|
||||
any_conn = true
|
||||
|
||||
@ -1109,6 +1122,10 @@ function iocontrol.update_unit_statuses(statuses)
|
||||
max_rad = rad_raw
|
||||
max_reading = radiation
|
||||
end
|
||||
|
||||
if not rtu_faulted then
|
||||
unit.rad_monitors[id] = { radiation = radiation, raw = rad_raw }
|
||||
end
|
||||
end
|
||||
|
||||
if any_conn then
|
||||
|
||||
@ -427,6 +427,13 @@ function pocket.new_session(id, s_addr, i_seq_num, in_queue, out_queue, timeout)
|
||||
}
|
||||
|
||||
_send(CRDN_TYPE.API_GET_WASTE, data)
|
||||
elseif pkt.type == CRDN_TYPE.API_GET_RAD then
|
||||
local data = {}
|
||||
|
||||
for i = 1, #db.units do data[i] = db.units[i].rad_monitors end
|
||||
data[#db.units + 1] = db.facility.rad_monitors
|
||||
|
||||
_send(CRDN_TYPE.API_GET_RAD, data)
|
||||
else
|
||||
log.debug(log_tag .. "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.6.15"
|
||||
local COORDINATOR_VERSION = "v1.6.16"
|
||||
|
||||
local CHUNK_LOAD_DELAY_S = 30.0
|
||||
|
||||
|
||||
@ -98,7 +98,8 @@ function iocontrol.init_core(pkt_comms, nav, cfg)
|
||||
get_unit = function (unit) comms.api__get_unit(unit) end,
|
||||
get_ctrl = function () comms.api__get_control() end,
|
||||
get_proc = function () comms.api__get_process() end,
|
||||
get_waste = function () comms.api__get_waste() end
|
||||
get_waste = function () comms.api__get_waste() end,
|
||||
get_rad = function () comms.api__get_rad() end
|
||||
}
|
||||
end
|
||||
|
||||
@ -184,7 +185,9 @@ function iocontrol.init_fac(conf)
|
||||
sps_data_tbl = {}, ---@type sps_session_db[]
|
||||
|
||||
tank_ps_tbl = {}, ---@type psil[]
|
||||
tank_data_tbl = {} ---@type dynamicv_session_db[]
|
||||
tank_data_tbl = {}, ---@type dynamicv_session_db[]
|
||||
|
||||
rad_monitors = {} ---@type { radiation: radiation_reading, raw: number }[]
|
||||
}
|
||||
|
||||
-- create induction and SPS tables (currently only 1 of each is supported)
|
||||
@ -264,7 +267,9 @@ function iocontrol.init_fac(conf)
|
||||
turbine_data_tbl = {}, ---@type turbinev_session_db[]
|
||||
|
||||
tank_ps_tbl = {}, ---@type psil[]
|
||||
tank_data_tbl = {} ---@type dynamicv_session_db[]
|
||||
tank_data_tbl = {}, ---@type dynamicv_session_db[]
|
||||
|
||||
rad_monitors = {} ---@type { radiation: radiation_reading, raw: number }[]
|
||||
}
|
||||
|
||||
-- on other facility modes, overwrite unit TANK option with facility tank defs
|
||||
|
||||
@ -658,7 +658,6 @@ function iorx.record_waste_data(data)
|
||||
fac.ps.publish("sps_process_rate", f_data[9])
|
||||
end
|
||||
|
||||
|
||||
-- update facility app with facility and unit data from API_GET_FAC_DTL
|
||||
---@param data table
|
||||
function iorx.record_fac_detail_data(data)
|
||||
@ -819,6 +818,59 @@ function iorx.record_fac_detail_data(data)
|
||||
s_ps.publish("SPSStateStatus", s_stat)
|
||||
end
|
||||
|
||||
-- update the radiation monitor app with radiation monitor data from API_GET_RAD
|
||||
---@param data table
|
||||
function iorx.record_radiation_data(data)
|
||||
-- unit radiation monitors
|
||||
|
||||
for u_id = 1, #io.units do
|
||||
local unit = io.units[u_id]
|
||||
local max_rad = 0
|
||||
local connected = {}
|
||||
|
||||
unit.radiation = types.new_zero_radiation_reading()
|
||||
unit.rad_monitors = data[u_id]
|
||||
|
||||
for id, mon in pairs(unit.rad_monitors) do
|
||||
table.insert(connected, id)
|
||||
|
||||
unit.unit_ps.publish("radiation@" .. id, mon.radiation)
|
||||
|
||||
if mon.raw > max_rad then
|
||||
max_rad = mon.raw
|
||||
unit.radiation = mon.radiation
|
||||
end
|
||||
end
|
||||
|
||||
unit.unit_ps.publish("radiation", unit.radiation)
|
||||
unit.unit_ps.publish("radiation_monitors", textutils.serialize(connected))
|
||||
end
|
||||
|
||||
-- facility radiation monitors
|
||||
|
||||
local fac = io.facility
|
||||
|
||||
fac.radiation = types.new_zero_radiation_reading()
|
||||
fac.rad_monitors = data[#io.units + 1]
|
||||
|
||||
local max_rad = 0
|
||||
local connected = {}
|
||||
|
||||
for id, mon in pairs(fac.rad_monitors) do
|
||||
table.insert(connected, id)
|
||||
|
||||
fac.ps.publish("radiation@" .. id, mon.radiation)
|
||||
|
||||
if mon.raw > max_rad then
|
||||
max_rad = mon.raw
|
||||
fac.radiation = mon.radiation
|
||||
end
|
||||
end
|
||||
|
||||
fac.ps.publish("radiation", fac.radiation)
|
||||
fac.ps.publish("radiation_monitors", textutils.serialize(connected))
|
||||
end
|
||||
|
||||
return function (io_obj)
|
||||
io = io_obj
|
||||
return iorx
|
||||
|
||||
@ -96,11 +96,12 @@ local APP_ID = {
|
||||
WASTE = 7,
|
||||
GUIDE = 8,
|
||||
ABOUT = 9,
|
||||
RADMON = 10,
|
||||
-- diagnostic app pages
|
||||
ALARMS = 10,
|
||||
ALARMS = 11,
|
||||
-- other
|
||||
DUMMY = 11,
|
||||
NUM_APPS = 11
|
||||
DUMMY = 12,
|
||||
NUM_APPS = 12
|
||||
}
|
||||
|
||||
pocket.APP_ID = APP_ID
|
||||
@ -369,8 +370,7 @@ function pocket.init_nav(smem)
|
||||
self.help_return = self.cur_app
|
||||
|
||||
nav.open_app(APP_ID.GUIDE, function ()
|
||||
local show = self.help_map[key]
|
||||
if show then show() end
|
||||
if self.help_map[key] then self.help_map[key]() end
|
||||
end)
|
||||
end
|
||||
|
||||
@ -583,6 +583,11 @@ function pocket.comms(version, nic, sv_watchdog, api_watchdog, nav)
|
||||
if self.api.linked then _send_api(CRDN_TYPE.API_GET_WASTE, {}) end
|
||||
end
|
||||
|
||||
-- coordinator get radiation app data
|
||||
function public.api__get_rad()
|
||||
if self.api.linked then _send_api(CRDN_TYPE.API_GET_RAD, {}) end
|
||||
end
|
||||
|
||||
-- send a facility command
|
||||
---@param cmd FAC_COMMAND command
|
||||
---@param option any? optional option options for the optional options (like waste mode)
|
||||
@ -759,6 +764,10 @@ function pocket.comms(version, nic, sv_watchdog, api_watchdog, nav)
|
||||
if _check_length(packet, #iocontrol.get_db().units + 1) then
|
||||
iocontrol.rx.record_waste_data(packet.data)
|
||||
end
|
||||
elseif packet.type == CRDN_TYPE.API_GET_RAD then
|
||||
if _check_length(packet, #iocontrol.get_db().units + 1) then
|
||||
iocontrol.rx.record_radiation_data(packet.data)
|
||||
end
|
||||
else _fail_type(packet) end
|
||||
else
|
||||
log.debug("discarding coordinator SCADA_CRDN packet before linked")
|
||||
|
||||
@ -22,7 +22,7 @@ local pocket = require("pocket.pocket")
|
||||
local renderer = require("pocket.renderer")
|
||||
local threads = require("pocket.threads")
|
||||
|
||||
local POCKET_VERSION = "v0.13.4-beta"
|
||||
local POCKET_VERSION = "v0.13.5-beta"
|
||||
|
||||
local println = util.println
|
||||
local println_ts = util.println_ts
|
||||
|
||||
219
pocket/ui/apps/radiation.lua
Normal file
219
pocket/ui/apps/radiation.lua
Normal file
@ -0,0 +1,219 @@
|
||||
--
|
||||
-- Radiation Monitor App
|
||||
--
|
||||
|
||||
local util = require("scada-common.util")
|
||||
|
||||
local iocontrol = require("pocket.iocontrol")
|
||||
local pocket = require("pocket.pocket")
|
||||
|
||||
local style = require("pocket.ui.style")
|
||||
|
||||
local core = require("graphics.core")
|
||||
|
||||
local Div = require("graphics.elements.Div")
|
||||
local ListBox = require("graphics.elements.ListBox")
|
||||
local MultiPane = require("graphics.elements.MultiPane")
|
||||
local Rectangle = require("graphics.elements.Rectangle")
|
||||
local TextBox = require("graphics.elements.TextBox")
|
||||
|
||||
local WaitingAnim = require("graphics.elements.animations.Waiting")
|
||||
|
||||
local RadIndicator = require("graphics.elements.indicators.RadIndicator")
|
||||
|
||||
local ALIGN = core.ALIGN
|
||||
local cpair = core.cpair
|
||||
local border = core.border
|
||||
|
||||
local APP_ID = pocket.APP_ID
|
||||
|
||||
local label_fg_bg = style.label
|
||||
local lu_col = style.label_unit_pair
|
||||
|
||||
-- new radiation monitor page view
|
||||
---@param root Container parent
|
||||
local function new_view(root)
|
||||
local db = iocontrol.get_db()
|
||||
|
||||
local frame = Div{parent=root,x=1,y=1}
|
||||
|
||||
local app = db.nav.register_app(APP_ID.RADMON, frame, nil, false, true)
|
||||
|
||||
local load_div = Div{parent=frame,x=1,y=1}
|
||||
local main = Div{parent=frame,x=1,y=1}
|
||||
|
||||
TextBox{parent=load_div,y=12,text="Loading...",alignment=ALIGN.CENTER}
|
||||
WaitingAnim{parent=load_div,x=math.floor(main.get_width()/2)-1,y=8,fg_bg=cpair(colors.yellow,colors._INHERIT)}
|
||||
|
||||
local load_pane = MultiPane{parent=main,x=1,y=1,panes={load_div,main}}
|
||||
|
||||
app.set_sidebar({ { label = " # ", tall = true, color = core.cpair(colors.black, colors.green), callback = db.nav.go_home } })
|
||||
|
||||
local page_div = nil ---@type Div|nil
|
||||
|
||||
-- load the app (create the elements)
|
||||
local function load()
|
||||
local f_ps = db.facility.ps
|
||||
|
||||
page_div = Div{parent=main,y=2,width=main.get_width()}
|
||||
|
||||
local panes = {} ---@type Div[]
|
||||
|
||||
-- create all page divs
|
||||
for _ = 1, db.facility.num_units + 2 do
|
||||
local div = Div{parent=page_div}
|
||||
table.insert(panes, div)
|
||||
end
|
||||
|
||||
local last_update = 0
|
||||
-- refresh data callback, every 500ms it will re-send the query
|
||||
local function update()
|
||||
if util.time_ms() - last_update >= 500 then
|
||||
db.api.get_rad()
|
||||
last_update = util.time_ms()
|
||||
end
|
||||
end
|
||||
|
||||
-- create a new radiation monitor list
|
||||
---@param parent Container
|
||||
---@param ps psil
|
||||
local function new_mon_list(parent, ps)
|
||||
local mon_list = ListBox{parent=parent,y=6,scroll_height=100,nav_fg_bg=cpair(colors.lightGray,colors.gray),nav_active=cpair(colors.white,colors.gray)}
|
||||
|
||||
local elem_list = {} ---@type graphics_element[]
|
||||
|
||||
mon_list.register(ps, "radiation_monitors", function (data)
|
||||
local ids = textutils.unserialize(data)
|
||||
|
||||
-- delete any disconnected monitors
|
||||
for id, elem in pairs(elem_list) do
|
||||
if not util.table_contains(ids, id) then
|
||||
elem.delete()
|
||||
elem_list[id] = nil
|
||||
end
|
||||
end
|
||||
|
||||
-- add newly connected monitors
|
||||
for _, id in pairs(ids) do
|
||||
if not elem_list[id] then
|
||||
elem_list[id] = Div{parent=mon_list,height=5}
|
||||
local mon_rect = Rectangle{parent=elem_list[id],height=4,x=2,width=20,border=border(1,colors.gray,true),thin=true,fg_bg=cpair(colors.black,colors.lightGray)}
|
||||
|
||||
TextBox{parent=mon_rect,text="Env. Detector "..id}
|
||||
local mon_rad = RadIndicator{parent=mon_rect,x=2,label="",format="%13.3f",lu_colors=cpair(colors.gray,colors.gray),width=18}
|
||||
mon_rad.register(ps, "radiation@" .. id, mon_rad.update)
|
||||
end
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
--#region unit radiation monitors
|
||||
|
||||
for i = 1, db.facility.num_units do
|
||||
local u_pane = panes[i]
|
||||
local u_div = Div{parent=u_pane}
|
||||
local unit = db.units[i]
|
||||
local u_ps = unit.unit_ps
|
||||
|
||||
local u_page = app.new_page(nil, i)
|
||||
u_page.tasks = { update }
|
||||
|
||||
TextBox{parent=u_div,y=1,text="Unit #"..i.." Monitors",alignment=ALIGN.CENTER}
|
||||
|
||||
TextBox{parent=u_div,x=2,y=3,text="Max Radiation",fg_bg=label_fg_bg}
|
||||
local radiation = RadIndicator{parent=u_div,x=2,label="",format="%17.3f",lu_colors=lu_col,width=21}
|
||||
radiation.register(u_ps, "radiation", radiation.update)
|
||||
|
||||
new_mon_list(u_div, u_ps)
|
||||
end
|
||||
|
||||
--#endregion
|
||||
|
||||
--#region overview page
|
||||
|
||||
local s_pane = panes[db.facility.num_units + 1]
|
||||
local s_div = Div{parent=s_pane,x=2,width=main.get_width()-2}
|
||||
|
||||
local stat_page = app.new_page(nil, db.facility.num_units + 1)
|
||||
stat_page.tasks = { update }
|
||||
|
||||
TextBox{parent=s_div,y=1,text=" Radiation Monitoring",alignment=ALIGN.CENTER}
|
||||
|
||||
TextBox{parent=s_div,y=3,text="Max Facility Rad.",fg_bg=label_fg_bg}
|
||||
local s_f_rad = RadIndicator{parent=s_div,label="",format="%17.3f",lu_colors=lu_col,width=21}
|
||||
s_f_rad.register(f_ps, "radiation", s_f_rad.update)
|
||||
|
||||
for i = 1, db.facility.num_units do
|
||||
local unit = db.units[i]
|
||||
local u_ps = unit.unit_ps
|
||||
|
||||
s_div.line_break()
|
||||
TextBox{parent=s_div,text="Max Unit "..i.." Radiation",fg_bg=label_fg_bg}
|
||||
local s_u_rad = RadIndicator{parent=s_div,label="",format="%17.3f",lu_colors=lu_col,width=21}
|
||||
s_u_rad.register(u_ps, "radiation", s_u_rad.update)
|
||||
end
|
||||
|
||||
--#endregion
|
||||
|
||||
--#region overview page
|
||||
|
||||
local f_pane = panes[db.facility.num_units + 2]
|
||||
local f_div = Div{parent=f_pane,width=main.get_width()}
|
||||
|
||||
local fac_page = app.new_page(nil, db.facility.num_units + 2)
|
||||
fac_page.tasks = { update }
|
||||
|
||||
TextBox{parent=f_div,y=1,text="Facility Monitors",alignment=ALIGN.CENTER}
|
||||
|
||||
TextBox{parent=f_div,x=2,y=3,text="Max Radiation",fg_bg=label_fg_bg}
|
||||
local f_rad = RadIndicator{parent=f_div,x=2,label="",format="%17.3f",lu_colors=lu_col,width=21}
|
||||
f_rad.register(f_ps, "radiation", f_rad.update)
|
||||
|
||||
new_mon_list(f_div, f_ps)
|
||||
|
||||
--#endregion
|
||||
|
||||
-- setup multipane
|
||||
local u_pane = MultiPane{parent=page_div,x=1,y=1,panes=panes}
|
||||
app.set_root_pane(u_pane)
|
||||
|
||||
-- setup sidebar
|
||||
|
||||
local list = {
|
||||
{ label = " # ", tall = true, color = core.cpair(colors.black, colors.green), callback = db.nav.go_home },
|
||||
{ label = " \x1e ", color = core.cpair(colors.black, colors.blue), callback = stat_page.nav_to },
|
||||
{ label = "FAC", color = core.cpair(colors.black, colors.yellow), callback = fac_page.nav_to }
|
||||
}
|
||||
|
||||
for i = 1, db.facility.num_units do
|
||||
table.insert(list, { label = "U-" .. i, color = core.cpair(colors.black, colors.lightGray), callback = function () app.switcher(i) end })
|
||||
end
|
||||
|
||||
app.set_sidebar(list)
|
||||
|
||||
-- done, show the app
|
||||
stat_page.nav_to()
|
||||
load_pane.set_value(2)
|
||||
end
|
||||
|
||||
-- delete the elements and switch back to the loading screen
|
||||
local function unload()
|
||||
if page_div then
|
||||
page_div.delete()
|
||||
page_div = nil
|
||||
end
|
||||
|
||||
app.set_sidebar({ { label = " # ", tall = true, color = core.cpair(colors.black, colors.green), callback = db.nav.go_home } })
|
||||
app.delete_pages()
|
||||
|
||||
-- show loading screen
|
||||
load_pane.set_value(1)
|
||||
end
|
||||
|
||||
app.set_load(load)
|
||||
app.set_unload(unload)
|
||||
|
||||
return main
|
||||
end
|
||||
|
||||
return new_view
|
||||
@ -14,6 +14,7 @@ local facil_app = require("pocket.ui.apps.facility")
|
||||
local guide_app = require("pocket.ui.apps.guide")
|
||||
local loader_app = require("pocket.ui.apps.loader")
|
||||
local process_app = require("pocket.ui.apps.process")
|
||||
local rad_app = require("pocket.ui.apps.radiation")
|
||||
local sys_apps = require("pocket.ui.apps.sys_apps")
|
||||
local unit_app = require("pocket.ui.apps.unit")
|
||||
local waste_app = require("pocket.ui.apps.waste")
|
||||
@ -71,6 +72,7 @@ local function init(main)
|
||||
process_app(page_div)
|
||||
waste_app(page_div)
|
||||
guide_app(page_div)
|
||||
rad_app(page_div)
|
||||
loader_app(page_div)
|
||||
sys_apps(page_div)
|
||||
diag_apps(page_div)
|
||||
|
||||
@ -29,8 +29,9 @@ local function new_view(root)
|
||||
|
||||
local apps_1 = Div{parent=main,x=1,y=1,height=15}
|
||||
local apps_2 = Div{parent=main,x=1,y=1,height=15}
|
||||
local apps_3 = Div{parent=main,x=1,y=1,height=15}
|
||||
|
||||
local panes = { apps_1, apps_2 }
|
||||
local panes = { apps_1, apps_2, apps_3 }
|
||||
|
||||
local app_pane = AppMultiPane{parent=main,x=1,y=1,height=18,panes=panes,active_color=colors.lightGray,nav_colors=cpair(colors.lightGray,colors.gray),scroll_nav=true,drag_nav=true,callback=app.switcher}
|
||||
|
||||
@ -50,15 +51,17 @@ local function new_view(root)
|
||||
App{parent=apps_1,x=16,y=2,text="\x15",title="Control",callback=function()open(APP_ID.CONTROL)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.PROCESS)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.WASTE)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.GUIDE)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}
|
||||
App{parent=apps_1,x=16,y=7,text="\xb6",title="Guide",callback=function()open(APP_ID.GUIDE)end,app_fg_bg=cpair(colors.black,colors.cyan),active_fg_bg=active_fg_bg}
|
||||
App{parent=apps_1,x=2,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,alignment=ALIGN.CENTER}
|
||||
App{parent=apps_2,x=2,y=2,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_2,x=9,y=2,text="\x1e",title="Rad",callback=function()open(APP_ID.RADMON)end,app_fg_bg=cpair(colors.black,colors.yellow),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}
|
||||
TextBox{parent=apps_3,text="Diagnostic Apps",x=1,y=2,alignment=ALIGN.CENTER}
|
||||
|
||||
App{parent=apps_3,x=2,y=4,text="\x0f",title="Alarm",callback=function()open(APP_ID.ALARMS)end,app_fg_bg=cpair(colors.black,colors.yellow),active_fg_bg=active_fg_bg}
|
||||
App{parent=apps_3,x=9,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_3,x=16,y=4,text="R",title="RS Test",callback=function()open(APP_ID.DUMMY)end,app_fg_bg=cpair(colors.black,colors.red),active_fg_bg=active_fg_bg}
|
||||
|
||||
return main
|
||||
end
|
||||
|
||||
@ -82,8 +82,9 @@ function system.create(tool_ctl, main_pane, cfg_sys, divs, style, exit)
|
||||
local plc_c_2 = Div{parent=plc_cfg,x=2,y=4,width=49}
|
||||
local plc_c_3 = Div{parent=plc_cfg,x=2,y=4,width=49}
|
||||
local plc_c_4 = Div{parent=plc_cfg,x=2,y=4,width=49}
|
||||
local plc_c_5 = Div{parent=plc_cfg,x=2,y=4,width=49}
|
||||
|
||||
local plc_pane = MultiPane{parent=plc_cfg,x=1,y=4,panes={plc_c_1,plc_c_2,plc_c_3,plc_c_4}}
|
||||
local plc_pane = MultiPane{parent=plc_cfg,x=1,y=4,panes={plc_c_1,plc_c_2,plc_c_3,plc_c_4,plc_c_5}}
|
||||
|
||||
TextBox{parent=plc_cfg,x=1,y=2,text=" PLC Configuration",fg_bg=cpair(colors.black,colors.orange)}
|
||||
|
||||
@ -152,13 +153,21 @@ function system.create(tool_ctl, main_pane, cfg_sys, divs, style, exit)
|
||||
|
||||
function self.bundled_emcool(en) if en then color.enable() else color.disable() end end
|
||||
|
||||
TextBox{parent=plc_c_5,x=1,y=1,height=5,text="Advanced Options"}
|
||||
local invert = Checkbox{parent=plc_c_5,x=1,y=3,label="Invert",default=ini_cfg.EmerCoolInvert,box_fg_bg=cpair(colors.orange,colors.black),callback=function()end}
|
||||
TextBox{parent=plc_c_5,x=10,y=3,text="new!",fg_bg=cpair(colors.red,colors._INHERIT)} ---@todo remove NEW tag on next revision
|
||||
TextBox{parent=plc_c_5,x=3,y=4,height=4,text="Digital I/O is already inverted (or not) based on intended use. If you have a non-standard setup, you can use this option to avoid needing a redstone inverter.",fg_bg=cpair(colors.gray,colors.lightGray)}
|
||||
PushButton{parent=plc_c_5,x=1,y=14,text="\x1b Back",callback=function()plc_pane.set_value(4)end,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
|
||||
|
||||
local function submit_emcool()
|
||||
tmp_cfg.EmerCoolSide = side_options_map[side.get_value()]
|
||||
tmp_cfg.EmerCoolColor = util.trinary(bundled.get_value(), color_options_map[color.get_value()], nil)
|
||||
tmp_cfg.EmerCoolInvert = invert.get_value()
|
||||
next_from_plc()
|
||||
end
|
||||
|
||||
PushButton{parent=plc_c_4,x=1,y=14,text="\x1b Back",callback=function()plc_pane.set_value(3)end,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
|
||||
PushButton{parent=plc_c_4,x=33,y=14,min_width=10,text="Advanced",callback=function()plc_pane.set_value(5)end,fg_bg=cpair(colors.black,colors.yellow),active_fg_bg=btn_act_fg_bg,dis_fg_bg=btn_dis_fg_bg}
|
||||
PushButton{parent=plc_c_4,x=44,y=14,text="Next \x1a",callback=submit_emcool,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
|
||||
|
||||
--#endregion
|
||||
@ -461,6 +470,7 @@ function system.create(tool_ctl, main_pane, cfg_sys, divs, style, exit)
|
||||
try_set(side, side_to_idx(ini_cfg.EmerCoolSide))
|
||||
try_set(bundled, ini_cfg.EmerCoolColor ~= nil)
|
||||
if ini_cfg.EmerCoolColor ~= nil then try_set(color, color_to_idx(ini_cfg.EmerCoolColor)) end
|
||||
try_set(invert, ini_cfg.EmerCoolInvert)
|
||||
try_set(svr_chan, ini_cfg.SVR_Channel)
|
||||
try_set(plc_chan, ini_cfg.PLC_Channel)
|
||||
try_set(timeout, ini_cfg.ConnTimeout)
|
||||
@ -533,9 +543,11 @@ function system.create(tool_ctl, main_pane, cfg_sys, divs, style, exit)
|
||||
if tmp_cfg.EmerCoolEnable then
|
||||
tmp_cfg.EmerCoolSide = config.EMERGENCY_COOL.side
|
||||
tmp_cfg.EmerCoolColor = config.EMERGENCY_COOL.color
|
||||
tmp_cfg.EmerCoolInvert = false
|
||||
else
|
||||
tmp_cfg.EmerCoolSide = nil
|
||||
tmp_cfg.EmerCoolColor = nil
|
||||
tmp_cfg.EmerCoolInvert = false
|
||||
end
|
||||
|
||||
tmp_cfg.SVR_Channel = config.SVR_CHANNEL
|
||||
|
||||
@ -32,7 +32,8 @@ local changes = {
|
||||
{ "v1.6.2", { "AuthKey minimum length is now 8 (if set)" } },
|
||||
{ "v1.6.8", { "ConnTimeout can now have a fractional part" } },
|
||||
{ "v1.6.15", { "Added front panel UI theme", "Added color accessibility modes" } },
|
||||
{ "v1.7.3", { "Added standard with black off state color mode", "Added blue indicator color modes" } }
|
||||
{ "v1.7.3", { "Added standard with black off state color mode", "Added blue indicator color modes" } },
|
||||
{ "v1.8.21", { "Added option to invert emergency coolant redstone control" } }
|
||||
}
|
||||
|
||||
---@class plc_configurator
|
||||
@ -76,6 +77,7 @@ local tmp_cfg = {
|
||||
EmerCoolEnable = false,
|
||||
EmerCoolSide = nil, ---@type string|nil
|
||||
EmerCoolColor = nil, ---@type color|nil
|
||||
EmerCoolInvert = false, ---@type boolean
|
||||
SVR_Channel = nil, ---@type integer
|
||||
PLC_Channel = nil, ---@type integer
|
||||
ConnTimeout = nil, ---@type number
|
||||
@ -100,6 +102,7 @@ local fields = {
|
||||
{ "EmerCoolEnable", "Emergency Coolant", false },
|
||||
{ "EmerCoolSide", "Emergency Coolant Side", nil },
|
||||
{ "EmerCoolColor", "Emergency Coolant Color", nil },
|
||||
{ "EmerCoolInvert", "Emergency Coolant Invert", false },
|
||||
{ "SVR_Channel", "SVR Channel", 16240 },
|
||||
{ "PLC_Channel", "PLC Channel", 16241 },
|
||||
{ "ConnTimeout", "Connection Timeout", 5 },
|
||||
|
||||
@ -43,6 +43,7 @@ function plc.load_config()
|
||||
config.EmerCoolEnable = settings.get("EmerCoolEnable")
|
||||
config.EmerCoolSide = settings.get("EmerCoolSide")
|
||||
config.EmerCoolColor = settings.get("EmerCoolColor")
|
||||
config.EmerCoolInvert = settings.get("EmerCoolInvert")
|
||||
|
||||
config.SVR_Channel = settings.get("SVR_Channel")
|
||||
config.PLC_Channel = settings.get("PLC_Channel")
|
||||
@ -98,6 +99,7 @@ function plc.validate_config(cfg)
|
||||
if cfg.EmerCoolEnable then
|
||||
cfv.assert_eq(rsio.is_valid_side(cfg.EmerCoolSide), true)
|
||||
cfv.assert_eq(cfg.EmerCoolColor == nil or rsio.is_color(cfg.EmerCoolColor), true)
|
||||
cfv.assert_type_bool(cfg.EmerCoolInvert)
|
||||
end
|
||||
|
||||
return cfv.valid()
|
||||
@ -166,7 +168,8 @@ function plc.rps_init(reactor, is_formed)
|
||||
local function _set_emer_cool(state)
|
||||
-- check if this was configured: if it's a table, fields have already been validated.
|
||||
if config.EmerCoolEnable then
|
||||
local level = rsio.digital_write_active(rsio.IO.U_EMER_COOL, state)
|
||||
-- use ~= as XOR for simple inversion
|
||||
local level = rsio.digital_write_active(rsio.IO.U_EMER_COOL, config.EmerCoolInvert ~= state)
|
||||
|
||||
if level ~= false then
|
||||
if rsio.is_color(config.EmerCoolColor) then
|
||||
|
||||
@ -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.8.20"
|
||||
local R_PLC_VERSION = "v1.8.22"
|
||||
|
||||
local println = util.println
|
||||
local println_ts = util.println_ts
|
||||
|
||||
@ -195,7 +195,7 @@ local function self_check()
|
||||
valid = is_int_min_max(entry.unit, 1, 4)
|
||||
elseif p_type == "dynamicValve" then
|
||||
valid = (entry.unit == nil and is_int_min_max(entry.index, 1, 4)) or is_int_min_max(entry.unit, 1, 4)
|
||||
elseif p_type == "environmentDetector" then
|
||||
elseif p_type == "environmentDetector" or p_type == "environment_detector" then
|
||||
valid = (entry.unit == nil or is_int_min_max(entry.unit, 1, 4)) and util.is_int(entry.index)
|
||||
else
|
||||
valid = true
|
||||
|
||||
@ -43,8 +43,8 @@ local self = {
|
||||
|
||||
local peripherals = {}
|
||||
|
||||
local RTU_DEV_TYPES = { "boilerValve", "turbineValve", "dynamicValve", "inductionPort", "spsPort", "solarNeutronActivator", "environmentDetector" }
|
||||
local NEEDS_UNIT = { "boilerValve", "turbineValve", "dynamicValve", "solarNeutronActivator", "environmentDetector" }
|
||||
local RTU_DEV_TYPES = { "boilerValve", "turbineValve", "dynamicValve", "inductionPort", "spsPort", "solarNeutronActivator", "environmentDetector", "environment_detector" }
|
||||
local NEEDS_UNIT = { "boilerValve", "turbineValve", "dynamicValve", "solarNeutronActivator", "environmentDetector", "environment_detector" }
|
||||
|
||||
-- create the peripherals configuration view
|
||||
---@param tool_ctl _rtu_cfg_tool_ctl
|
||||
@ -165,7 +165,7 @@ function peripherals.create(tool_ctl, main_pane, cfg_sys, peri_cfg, style)
|
||||
end
|
||||
|
||||
self.p_desc.set_value("Each reactor unit can have at most 1 tank and the facility can have at most 4. Each facility tank must have a unique # 1 through 4, regardless of where it is connected. Only a total of 4 tanks can be displayed on the flow monitor.")
|
||||
elseif type == "environmentDetector" then
|
||||
elseif type == "environmentDetector" or type == "environment_detector" then
|
||||
reposition("This is the below system's # env. detector.", 29, 99, 17, 6, 8)
|
||||
self.p_assign_btn.show()
|
||||
self.p_assign_btn.redraw()
|
||||
@ -281,7 +281,7 @@ function peripherals.create(tool_ctl, main_pane, cfg_sys, peri_cfg, style)
|
||||
local idx = tonumber(self.p_idx.get_value())
|
||||
|
||||
if util.table_contains(NEEDS_UNIT, peri_type) then
|
||||
if (peri_type == "dynamicValve" or peri_type == "environmentDetector") and for_facility then
|
||||
if (peri_type == "dynamicValve" or peri_type == "environmentDetector" or peri_type == "environment_detector") and for_facility then
|
||||
-- skip
|
||||
elseif not (util.is_int(u) and u > 0 and u < 5) then
|
||||
self.p_err.set_value("Unit ID must be within 1 to 4.")
|
||||
@ -310,7 +310,7 @@ function peripherals.create(tool_ctl, main_pane, cfg_sys, peri_cfg, style)
|
||||
else index = idx end
|
||||
elseif peri_type == "dynamicValve" then
|
||||
index = 1
|
||||
elseif peri_type == "environmentDetector" then
|
||||
elseif peri_type == "environmentDetector" or peri_type == "environment_detector" then
|
||||
if not (util.is_int(idx) and idx > 0) then
|
||||
self.p_err.set_value("Index must be greater than 0.")
|
||||
self.p_err.show()
|
||||
|
||||
@ -506,7 +506,7 @@ function system.create(tool_ctl, main_pane, cfg_sys, divs, ext, style)
|
||||
local u, idx = def.unit, def.index
|
||||
|
||||
if util.table_contains(NEEDS_UNIT, mount.type) then
|
||||
if (mount.type == "dynamicValve" or mount.type == "environmentDetector") and for_facility then
|
||||
if (mount.type == "dynamicValve" or mount.type == "environmentDetector" or mount.type == "environment_detector") and for_facility then
|
||||
-- skip
|
||||
elseif not (util.is_int(u) and u > 0 and u < 5) then
|
||||
err = true
|
||||
@ -527,7 +527,7 @@ function system.create(tool_ctl, main_pane, cfg_sys, divs, ext, style)
|
||||
else index = idx end
|
||||
elseif mount.type == "dynamicValve" then
|
||||
index = 1
|
||||
elseif mount.type == "environmentDetector" then
|
||||
elseif mount.type == "environmentDetector" or mount.type == "environment_detector" then
|
||||
if not (util.is_int(idx) and idx > 0) then
|
||||
err = true
|
||||
else index = idx 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.12.1"
|
||||
local RTU_VERSION = "v1.12.2"
|
||||
|
||||
local RTU_UNIT_TYPE = types.RTU_UNIT_TYPE
|
||||
local RTU_HW_STATE = databus.RTU_HW_STATE
|
||||
@ -472,7 +472,7 @@ local function main()
|
||||
|
||||
rtu_type = RTU_UNIT_TYPE.SNA
|
||||
rtu_iface, faulted = sna_rtu.new(device)
|
||||
elseif type == "environmentDetector" then
|
||||
elseif type == "environmentDetector" or type == "environment_detector" then
|
||||
-- advanced peripherals environment detector
|
||||
if not validate_index(1) then return false end
|
||||
if not validate_assign(entry.unit == nil) then return false end
|
||||
|
||||
@ -89,7 +89,7 @@ local function handle_unit_mount(smem, println_ts, iface, type, device, unit)
|
||||
if unit.reactor < 1 or unit.reactor > 4 then fail(util.c("SNA '", unit.name, "' cannot init, not assigned to a valid unit")) end
|
||||
|
||||
unit.type = RTU_UNIT_TYPE.SNA
|
||||
elseif type == "environmentDetector" then
|
||||
elseif type == "environmentDetector" or type == "environment_detector" then
|
||||
-- advanced peripherals environment detector
|
||||
if unit.reactor < 0 or unit.reactor > 4 then fail(util.c("environment detector '", unit.name, "' cannot init, no valid assignment provided")) end
|
||||
if (unit.index == false) or unit.index < 1 then fail(util.c("environment detector '", unit.name, "' cannot init, invalid index provided")) end
|
||||
|
||||
@ -17,8 +17,8 @@ local max_distance = nil
|
||||
local comms = {}
|
||||
|
||||
-- protocol/data versions (protocol/data independent changes tracked by util.lua version)
|
||||
comms.version = "3.0.6"
|
||||
comms.api_version = "0.0.9"
|
||||
comms.version = "3.0.7"
|
||||
comms.api_version = "0.0.10"
|
||||
|
||||
---@enum PROTOCOL
|
||||
local PROTOCOL = {
|
||||
@ -72,7 +72,8 @@ local CRDN_TYPE = {
|
||||
API_GET_UNIT = 10, -- API: get reactor unit data
|
||||
API_GET_CTRL = 11, -- API: get data for the control app
|
||||
API_GET_PROC = 12, -- API: get data for the process app
|
||||
API_GET_WASTE = 13 -- API: get data for the waste app
|
||||
API_GET_WASTE = 13, -- API: get data for the waste app
|
||||
API_GET_RAD = 14 -- API: get data for the radiation monitor app
|
||||
}
|
||||
|
||||
---@enum ESTABLISH_ACK
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user