Merge pull request #579 from MikaylaFischler/devel

2024.11.21 Release
This commit is contained in:
Mikayla 2024-11-21 18:40:52 -05:00 committed by GitHub
commit c6343e5956
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
36 changed files with 895 additions and 244 deletions

View File

@ -28,6 +28,9 @@ def minify(path: str):
contents = f.read() contents = f.read()
f.close() f.close()
# remove --[[@as type]] hints before anything, since it would detect as multiline comments
contents = re.sub(r' --+\[.+]]', '', contents)
if re.search(r'--+\[+', contents) != None: if re.search(r'--+\[+', contents) != None:
# absolutely not dealing with lua multiline comments # absolutely not dealing with lua multiline comments
# - there are more important things to do # - there are more important things to do

152
ccmsi.lua
View File

@ -15,7 +15,7 @@ WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
]]-- ]]--
local CCMSI_VERSION = "v1.19" local CCMSI_VERSION = "v1.20"
local install_dir = "/.install-cache" local install_dir = "/.install-cache"
local manifest_path = "https://mikaylafischler.github.io/cc-mek-scada/manifests/" local manifest_path = "https://mikaylafischler.github.io/cc-mek-scada/manifests/"
@ -149,16 +149,16 @@ local function get_remote_manifest()
end end
-- record the local installation manifest -- record the local installation manifest
local function write_install_manifest(manifest, dependencies) local function write_install_manifest(manifest, deps)
local versions = {} local versions = {}
for key, value in pairs(manifest.versions) do for key, value in pairs(manifest.versions) do
local is_dependency = false local is_dep = false
for _, dependency in pairs(dependencies) do for _, dep in pairs(deps) do
if (key == "bootloader" and dependency == "system") or key == dependency then if (key == "bootloader" and dep == "system") or key == dep then
is_dependency = true;break is_dep = true;break
end end
end end
if key == app or key == "comms" or is_dependency then versions[key] = value end if key == app or key == "comms" or is_dep then versions[key] = value end
end end
manifest.versions = versions manifest.versions = versions
@ -383,8 +383,10 @@ if mode == "check" then
yellow();println("\nA different version of the installer is available, it is recommended to update (use 'ccmsi update installer').");white() yellow();println("\nA different version of the installer is available, it is recommended to update (use 'ccmsi update installer').");white()
end end
elseif mode == "install" or mode == "update" then elseif mode == "install" or mode == "update" then
local ok, r_manifest, l_manifest
local update_installer = app == "installer" local update_installer = app == "installer"
local ok, manifest = get_remote_manifest() ok, r_manifest = get_remote_manifest()
if not ok then return end if not ok then return end
local ver = { local ver = {
@ -397,27 +399,27 @@ elseif mode == "install" or mode == "update" then
} }
-- try to find local versions -- try to find local versions
local local_ok, lmnf = read_local_manifest() ok, l_manifest = read_local_manifest()
if not local_ok then if mode == "update" and not update_installer then
if mode == "update" then if not ok then
red();println("Failed to load local installation information, cannot update.");white() red();println("Failed to load local installation information, cannot update.");white()
return return
end else
elseif not update_installer then ver.boot.v_local = l_manifest.versions.bootloader
ver.boot.v_local = lmnf.versions.bootloader ver.app.v_local = l_manifest.versions[app]
ver.app.v_local = lmnf.versions[app] ver.comms.v_local = l_manifest.versions.comms
ver.comms.v_local = lmnf.versions.comms ver.common.v_local = l_manifest.versions.common
ver.common.v_local = lmnf.versions.common ver.graphics.v_local = l_manifest.versions.graphics
ver.graphics.v_local = lmnf.versions.graphics ver.lockbox.v_local = l_manifest.versions.lockbox
ver.lockbox.v_local = lmnf.versions.lockbox
if lmnf.versions[app] == nil then if l_manifest.versions[app] == nil then
red();println("Another application is already installed, please uninstall it before installing a new application.");white() red();println("Another application is already installed, please uninstall it before installing a new application.");white()
return return
end end
end end
end
if manifest.versions.installer ~= CCMSI_VERSION then if r_manifest.versions.installer ~= CCMSI_VERSION then
if not update_installer then yellow();println("A different version of the installer is available, it is recommended to update to it.");white() end if not update_installer then yellow();println("A different version of the installer is available, it is recommended to update to it.");white() end
if update_installer or ask_y_n("Would you like to update now", true) then if update_installer or ask_y_n("Would you like to update now", true) then
lgray();println("GET ccmsi.lua") lgray();println("GET ccmsi.lua")
@ -440,12 +442,12 @@ elseif mode == "install" or mode == "update" then
return return
end end
ver.boot.v_remote = manifest.versions.bootloader ver.boot.v_remote = r_manifest.versions.bootloader
ver.app.v_remote = manifest.versions[app] ver.app.v_remote = r_manifest.versions[app]
ver.comms.v_remote = manifest.versions.comms ver.comms.v_remote = r_manifest.versions.comms
ver.common.v_remote = manifest.versions.common ver.common.v_remote = r_manifest.versions.common
ver.graphics.v_remote = manifest.versions.graphics ver.graphics.v_remote = r_manifest.versions.graphics
ver.lockbox.v_remote = manifest.versions.lockbox ver.lockbox.v_remote = r_manifest.versions.lockbox
green() green()
if mode == "install" then print("Installing ") else print("Updating ") end if mode == "install" then print("Installing ") else print("Updating ") end
@ -461,36 +463,33 @@ elseif mode == "install" or mode == "update" then
ver.graphics.changed = show_pkg_change("graphics", ver.graphics) ver.graphics.changed = show_pkg_change("graphics", ver.graphics)
ver.lockbox.changed = show_pkg_change("lockbox", ver.lockbox) ver.lockbox.changed = show_pkg_change("lockbox", ver.lockbox)
-------------------------- -- start install/update
-- START INSTALL/UPDATE --
--------------------------
local space_required = manifest.sizes.manifest local space_req = r_manifest.sizes.manifest
local space_available = fs.getFreeSpace("/") local space_avail = fs.getFreeSpace("/")
local single_file_mode = false local file_list = r_manifest.files
local file_list = manifest.files local size_list = r_manifest.sizes
local size_list = manifest.sizes local deps = r_manifest.depends[app]
local dependencies = manifest.depends[app]
table.insert(dependencies, app) table.insert(deps, app)
-- helper function to check if a dependency is unchanged -- helper function to check if a dependency is unchanged
local function unchanged(dependency) local function unchanged(dep)
if dependency == "system" then return not ver.boot.changed if dep == "system" then return not ver.boot.changed
elseif dependency == "graphics" then return not ver.graphics.changed elseif dep == "graphics" then return not ver.graphics.changed
elseif dependency == "lockbox" then return not ver.lockbox.changed elseif dep == "lockbox" then return not ver.lockbox.changed
elseif dependency == "common" then return not (ver.common.changed or ver.comms.changed) elseif dep == "common" then return not (ver.common.changed or ver.comms.changed)
elseif dependency == app then return not ver.app.changed elseif dep == app then return not ver.app.changed
else return true end else return true end
end end
local any_change = false local any_change = false
for _, dependency in pairs(dependencies) do for _, dep in pairs(deps) do
local size = size_list[dependency] local size = size_list[dep]
space_required = space_required + size space_req = space_req + size
any_change = any_change or not unchanged(dependency) any_change = any_change or not unchanged(dep)
end end
if mode == "update" and not any_change then if mode == "update" and not any_change then
@ -501,10 +500,7 @@ elseif mode == "install" or mode == "update" then
-- ask for confirmation -- ask for confirmation
if not ask_y_n("Continue", false) then return end if not ask_y_n("Continue", false) then return end
-- check space constraints local single_file_mode = space_avail < space_req
if space_available < space_required then
single_file_mode = true
end
local success = true local success = true
@ -548,7 +544,7 @@ elseif mode == "install" or mode == "update" then
success = false success = false
return return
end end
clean(manifest) clean(r_manifest)
sf_install(3) sf_install(3)
elseif attempt == 3 then elseif attempt == 3 then
yellow() yellow()
@ -574,30 +570,30 @@ elseif mode == "install" or mode == "update" then
local abort_attempt = false local abort_attempt = false
success = true success = true
for _, dependency in pairs(dependencies) do for _, dep in pairs(deps) do
if mode == "update" and unchanged(dependency) then if mode == "update" and unchanged(dep) then
pkg_message("skipping install of unchanged package", dependency) pkg_message("skipping install of unchanged package", dep)
else else
pkg_message("installing package", dependency) pkg_message("installing package", dep)
lgray() lgray()
-- beginning on the second try, delete the directory before starting -- beginning on the second try, delete the directory before starting
if attempt >= 2 then if attempt >= 2 then
if dependency == "system" then if dep == "system" then
elseif dependency == "common" then elseif dep == "common" then
if fs.exists("/scada-common") then if fs.exists("/scada-common") then
fs.delete("/scada-common") fs.delete("/scada-common")
println("deleted /scada-common") println("deleted /scada-common")
end end
else else
if fs.exists("/"..dependency) then if fs.exists("/"..dep) then
fs.delete("/"..dependency) fs.delete("/"..dep)
println("deleted /"..dependency) println("deleted /"..dep)
end end
end end
end end
local files = file_list[dependency] local files = file_list[dep]
for _, file in pairs(files) do for _, file in pairs(files) do
println("GET "..file) println("GET "..file)
mitigate_case(file) mitigate_case(file)
@ -620,14 +616,14 @@ elseif mode == "install" or mode == "update" then
if fs.exists(install_dir) then fs.delete(install_dir);fs.makeDir(install_dir) end if fs.exists(install_dir) then fs.delete(install_dir);fs.makeDir(install_dir) end
-- download all dependencies -- download all dependencies
for _, dependency in pairs(dependencies) do for _, dep in pairs(deps) do
if mode == "update" and unchanged(dependency) then if mode == "update" and unchanged(dep) then
pkg_message("skipping download of unchanged package", dependency) pkg_message("skipping download of unchanged package", dep)
else else
pkg_message("downloading package", dependency) pkg_message("downloading package", dep)
lgray() lgray()
local files = file_list[dependency] local files = file_list[dep]
for _, file in pairs(files) do for _, file in pairs(files) do
println("GET "..file) println("GET "..file)
local dl_stat = http_get_file(file, install_dir.."/") local dl_stat = http_get_file(file, install_dir.."/")
@ -650,14 +646,14 @@ elseif mode == "install" or mode == "update" then
-- copy in downloaded files (installation) -- copy in downloaded files (installation)
if success then if success then
for _, dependency in pairs(dependencies) do for _, dep in pairs(deps) do
if mode == "update" and unchanged(dependency) then if mode == "update" and unchanged(dep) then
pkg_message("skipping install of unchanged package", dependency) pkg_message("skipping install of unchanged package", dep)
else else
pkg_message("installing package", dependency) pkg_message("installing package", dep)
lgray() lgray()
local files = file_list[dependency] local files = file_list[dep]
for _, file in pairs(files) do for _, file in pairs(files) do
local temp_file = install_dir.."/"..file local temp_file = install_dir.."/"..file
if fs.exists(file) then fs.delete(file) end if fs.exists(file) then fs.delete(file) end
@ -671,13 +667,13 @@ elseif mode == "install" or mode == "update" then
end end
if success then if success then
write_install_manifest(manifest, dependencies) write_install_manifest(r_manifest, deps)
green() green()
if mode == "install" then if mode == "install" then
println("Installation completed successfully.") println("Installation completed successfully.")
else println("Update completed successfully.") end else println("Update completed successfully.") end
white();println("Ready to clean up unused files, press any key to continue...") white();println("Ready to clean up unused files, press any key to continue...")
any_key();clean(manifest) any_key();clean(r_manifest)
white();println("Done.") white();println("Done.")
else else
red() red()
@ -712,14 +708,14 @@ elseif mode == "uninstall" then
clean(manifest) clean(manifest)
local file_list = manifest.files local file_list = manifest.files
local dependencies = manifest.depends[app] local deps = manifest.depends[app]
table.insert(dependencies, app) table.insert(deps, app)
-- delete all installed files -- delete all installed files
lgray() lgray()
for _, dependency in pairs(dependencies) do for _, dep in pairs(deps) do
local files = file_list[dependency] local files = file_list[dep]
for _, file in pairs(files) do for _, file in pairs(files) do
if fs.exists(file) then fs.delete(file);println("deleted "..file) end if fs.exists(file) then fs.delete(file);println("deleted "..file) end
end end

View File

@ -1,11 +1,12 @@
print("CONFIGURE> SCANNING FOR CONFIGURATOR...") print("CONFIGURE> SCANNING FOR CONFIGURATOR...")
if fs.exists("reactor-plc/configure.lua") then require("reactor-plc.configure").configure() for _, app in ipairs({ "reactor-plc", "rtu", "supervisor", "coordinator", "pocket" }) do
elseif fs.exists("rtu/configure.lua") then require("rtu.configure").configure() if fs.exists(app .. "/configure.lua") then
elseif fs.exists("supervisor/configure.lua") then require("supervisor.configure").configure() local _, _, launch = require(app .. ".configure").configure()
elseif fs.exists("coordinator/configure.lua") then require("coordinator.configure").configure() if launch then shell.execute("/startup") end
elseif fs.exists("pocket/configure.lua") then require("pocket.configure").configure() return
else end
end
print("CONFIGURE> NO CONFIGURATOR FOUND") print("CONFIGURE> NO CONFIGURATOR FOUND")
print("CONFIGURE> EXIT") print("CONFIGURE> EXIT")
end

View File

@ -58,6 +58,7 @@ style.btn_dis_fg_bg = cpair(colors.lightGray,colors.white)
local tool_ctl = { local tool_ctl = {
sv_cool_conf = nil, ---@type [ integer, integer ][] list of boiler & turbine counts sv_cool_conf = nil, ---@type [ integer, integer ][] list of boiler & turbine counts
launch_startup = false,
start_fail = 0, start_fail = 0,
fail_message = "", fail_message = "",
has_config = false, has_config = false,
@ -236,9 +237,17 @@ local function config_view(display)
main_pane.set_value(8) main_pane.set_value(8)
end end
local function startup()
tool_ctl.launch_startup = true
exit()
end
PushButton{parent=main_page,x=2,y=17,min_width=6,text="Exit",callback=exit,fg_bg=cpair(colors.black,colors.red),active_fg_bg=btn_act_fg_bg} PushButton{parent=main_page,x=2,y=17,min_width=6,text="Exit",callback=exit,fg_bg=cpair(colors.black,colors.red),active_fg_bg=btn_act_fg_bg}
tool_ctl.color_cfg = PushButton{parent=main_page,x=23,y=17,min_width=15,text="Color Options",callback=jump_color,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg,dis_fg_bg=cpair(colors.lightGray,colors.white)} local start_btn = PushButton{parent=main_page,x=42,y=17,min_width=9,text="Startup",callback=startup,fg_bg=cpair(colors.black,colors.green),active_fg_bg=btn_act_fg_bg,dis_fg_bg=btn_dis_fg_bg}
PushButton{parent=main_page,x=39,y=17,min_width=12,text="Change Log",callback=function()main_pane.set_value(10)end,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg} tool_ctl.color_cfg = PushButton{parent=main_page,x=36,y=y_start,min_width=15,text="Color Options",callback=jump_color,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg,dis_fg_bg=cpair(colors.lightGray,colors.white)}
PushButton{parent=main_page,x=39,y=y_start+2,min_width=12,text="Change Log",callback=function()main_pane.set_value(10)end,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
if tool_ctl.start_fail ~= 0 then start_btn.disable() end
if not tool_ctl.has_config then if not tool_ctl.has_config then
tool_ctl.view_cfg.disable() tool_ctl.view_cfg.disable()
@ -372,7 +381,7 @@ function configurator.configure(start_code, message)
println("configurator error: " .. error) println("configurator error: " .. error)
end end
return status, error return status, error, tool_ctl.launch_startup
end end
return configurator return configurator

View File

@ -94,7 +94,7 @@ function iocontrol.init(conf, comms, temp_scale, energy_scale)
auto_scram = false, auto_scram = false,
---@type ascram_status ---@type ascram_status
ascram_status = { ascram_status = {
matrix_dc = false, matrix_fault = false,
matrix_fill = false, matrix_fill = false,
crit_alarm = false, crit_alarm = false,
radiation = false, radiation = false,
@ -105,6 +105,7 @@ function iocontrol.init(conf, comms, temp_scale, energy_scale)
auto_current_waste_product = types.WASTE_PRODUCT.PLUTONIUM, auto_current_waste_product = types.WASTE_PRODUCT.PLUTONIUM,
auto_pu_fallback_active = false, auto_pu_fallback_active = false,
auto_sps_disabled = false, auto_sps_disabled = false,
waste_stats = { 0, 0, 0, 0, 0, 0 }, -- waste in, pu, po, po pellets, am, spent waste
radiation = types.new_zero_radiation_reading(), radiation = types.new_zero_radiation_reading(),
@ -118,6 +119,7 @@ function iocontrol.init(conf, comms, temp_scale, energy_scale)
induction_ps_tbl = {}, ---@type psil[] induction_ps_tbl = {}, ---@type psil[]
induction_data_tbl = {}, ---@type imatrix_session_db[] induction_data_tbl = {}, ---@type imatrix_session_db[]
sps_status = 1,
sps_ps_tbl = {}, ---@type psil[] sps_ps_tbl = {}, ---@type psil[]
sps_data_tbl = {}, ---@type sps_session_db[] sps_data_tbl = {}, ---@type sps_session_db[]
@ -174,6 +176,7 @@ function iocontrol.init(conf, comms, temp_scale, energy_scale)
waste_mode = types.WASTE_MODE.MANUAL_PLUTONIUM, waste_mode = types.WASTE_MODE.MANUAL_PLUTONIUM,
waste_product = types.WASTE_PRODUCT.PLUTONIUM, waste_product = types.WASTE_PRODUCT.PLUTONIUM,
waste_stats = { 0, 0, 0 }, -- plutonium, polonium, po pellets
last_rate_change_ms = 0, last_rate_change_ms = 0,
turbine_flow_stable = false, turbine_flow_stable = false,
@ -540,7 +543,7 @@ function iocontrol.update_facility_status(status)
fac.auto_saturated = ctl_status[5] fac.auto_saturated = ctl_status[5]
fac.auto_scram = ctl_status[6] fac.auto_scram = ctl_status[6]
fac.ascram_status.matrix_dc = ctl_status[7] fac.ascram_status.matrix_fault = ctl_status[7]
fac.ascram_status.matrix_fill = ctl_status[8] fac.ascram_status.matrix_fill = ctl_status[8]
fac.ascram_status.crit_alarm = ctl_status[9] fac.ascram_status.crit_alarm = ctl_status[9]
fac.ascram_status.radiation = ctl_status[10] fac.ascram_status.radiation = ctl_status[10]
@ -555,7 +558,7 @@ function iocontrol.update_facility_status(status)
fac.ps.publish("auto_ramping", fac.auto_ramping) fac.ps.publish("auto_ramping", fac.auto_ramping)
fac.ps.publish("auto_saturated", fac.auto_saturated) fac.ps.publish("auto_saturated", fac.auto_saturated)
fac.ps.publish("auto_scram", fac.auto_scram) fac.ps.publish("auto_scram", fac.auto_scram)
fac.ps.publish("as_matrix_dc", fac.ascram_status.matrix_dc) fac.ps.publish("as_matrix_fault", fac.ascram_status.matrix_fault)
fac.ps.publish("as_matrix_fill", fac.ascram_status.matrix_fill) fac.ps.publish("as_matrix_fill", fac.ascram_status.matrix_fill)
fac.ps.publish("as_crit_alarm", fac.ascram_status.crit_alarm) fac.ps.publish("as_crit_alarm", fac.ascram_status.crit_alarm)
fac.ps.publish("as_radiation", fac.ascram_status.radiation) fac.ps.publish("as_radiation", fac.ascram_status.radiation)
@ -662,6 +665,8 @@ function iocontrol.update_facility_status(status)
-- SPS statuses -- SPS statuses
if type(rtu_statuses.sps) == "table" then if type(rtu_statuses.sps) == "table" then
local sps_status = 1
for id = 1, #fac.sps_ps_tbl do for id = 1, #fac.sps_ps_tbl do
if rtu_statuses.sps[id] == nil then if rtu_statuses.sps[id] == nil then
-- disconnected -- disconnected
@ -677,22 +682,21 @@ function iocontrol.update_facility_status(status)
local rtu_faulted = _record_multiblock_status(sps, data, ps) local rtu_faulted = _record_multiblock_status(sps, data, ps)
if rtu_faulted then if rtu_faulted then
ps.publish("computed_status", 3) -- faulted sps_status = 3 -- faulted
elseif data.formed then elseif data.formed then
if data.state.process_rate > 0 then -- active / idle
ps.publish("computed_status", 5) -- active sps_status = util.trinary(data.state.process_rate > 0, 5, 4)
else else sps_status = 2 end -- not formed
ps.publish("computed_status", 4) -- idle
end ps.publish("computed_status", sps_status)
else
ps.publish("computed_status", 2) -- not formed
end
io.facility.ps.publish("am_rate", data.state.process_rate * 1000) io.facility.ps.publish("am_rate", data.state.process_rate * 1000)
else else
log.debug(util.c(log_header, "invalid sps id ", id)) log.debug(util.c(log_header, "invalid sps id ", id))
end end
end end
io.facility.sps_status = sps_status
else else
log.debug(log_header .. "sps list not a table") log.debug(log_header .. "sps list not a table")
valid = false valid = false
@ -1192,6 +1196,7 @@ function iocontrol.update_unit_statuses(statuses)
local u_spent_rate = waste_rate local u_spent_rate = waste_rate
local u_pu_rate = util.trinary(is_pu, waste_rate, 0.0) local u_pu_rate = util.trinary(is_pu, waste_rate, 0.0)
local u_po_rate = unit.sna_out_rate local u_po_rate = unit.sna_out_rate
local u_po_pl_rate = 0
unit.unit_ps.publish("pu_rate", u_pu_rate) unit.unit_ps.publish("pu_rate", u_pu_rate)
unit.unit_ps.publish("po_rate", u_po_rate) unit.unit_ps.publish("po_rate", u_po_rate)
@ -1202,6 +1207,7 @@ function iocontrol.update_unit_statuses(statuses)
u_spent_rate = u_po_rate u_spent_rate = u_po_rate
unit.unit_ps.publish("po_pl_rate", u_po_rate) unit.unit_ps.publish("po_pl_rate", u_po_rate)
unit.unit_ps.publish("po_am_rate", 0) unit.unit_ps.publish("po_am_rate", 0)
u_po_pl_rate = u_po_rate
po_pl_rate = po_pl_rate + u_po_rate po_pl_rate = po_pl_rate + u_po_rate
elseif unit.waste_product == types.WASTE_PRODUCT.ANTI_MATTER then elseif unit.waste_product == types.WASTE_PRODUCT.ANTI_MATTER then
u_spent_rate = 0 u_spent_rate = 0
@ -1213,6 +1219,8 @@ function iocontrol.update_unit_statuses(statuses)
unit.unit_ps.publish("po_am_rate", 0) unit.unit_ps.publish("po_am_rate", 0)
end end
unit.waste_stats = { u_pu_rate, u_po_rate, u_po_pl_rate }
unit.unit_ps.publish("ws_rate", u_spent_rate) unit.unit_ps.publish("ws_rate", u_spent_rate)
pu_rate = pu_rate + u_pu_rate pu_rate = pu_rate + u_pu_rate
@ -1221,6 +1229,8 @@ function iocontrol.update_unit_statuses(statuses)
end end
end end
io.facility.waste_stats = { burn_rate_sum, pu_rate, po_rate, po_pl_rate, po_am_rate, spent_rate }
io.facility.ps.publish("burn_sum", burn_rate_sum) io.facility.ps.publish("burn_sum", burn_rate_sum)
io.facility.ps.publish("sna_count", sna_count_sum) io.facility.ps.publish("sna_count", sna_count_sum)
io.facility.ps.publish("pu_rate", pu_rate) io.facility.ps.publish("pu_rate", pu_rate)

View File

@ -445,36 +445,21 @@ end
---@param product WASTE_PRODUCT waste product for auto control ---@param product WASTE_PRODUCT waste product for auto control
function process.set_process_waste(product) function process.set_process_waste(product)
pctl.comms.send_fac_command(F_CMD.SET_WASTE_MODE, product) pctl.comms.send_fac_command(F_CMD.SET_WASTE_MODE, product)
log.debug(util.c("PROCESS: SET WASTE ", product)) log.debug(util.c("PROCESS: SET WASTE ", product))
-- update config table and save
pctl.control_states.process.waste_product = product
_write_auto_config()
end end
-- set automatic process control plutonium fallback -- set automatic process control plutonium fallback
---@param enabled boolean whether to enable plutonium fallback ---@param enabled boolean whether to enable plutonium fallback
function process.set_pu_fallback(enabled) function process.set_pu_fallback(enabled)
pctl.comms.send_fac_command(F_CMD.SET_PU_FB, enabled) pctl.comms.send_fac_command(F_CMD.SET_PU_FB, enabled)
log.debug(util.c("PROCESS: SET PU FALLBACK ", enabled)) log.debug(util.c("PROCESS: SET PU FALLBACK ", enabled))
-- update config table and save
pctl.control_states.process.pu_fallback = enabled
_write_auto_config()
end end
-- set automatic process control SPS usage at low power -- set automatic process control SPS usage at low power
---@param enabled boolean whether to enable SPS usage at low power ---@param enabled boolean whether to enable SPS usage at low power
function process.set_sps_low_power(enabled) function process.set_sps_low_power(enabled)
pctl.comms.send_fac_command(F_CMD.SET_SPS_LP, enabled) pctl.comms.send_fac_command(F_CMD.SET_SPS_LP, enabled)
log.debug(util.c("PROCESS: SET SPS LOW POWER ", enabled)) log.debug(util.c("PROCESS: SET SPS LOW POWER ", enabled))
-- update config table and save
pctl.control_states.process.sps_low_power = enabled
_write_auto_config()
end end
-- save process control settings -- save process control settings
@ -527,21 +512,30 @@ end
-- record waste product settting after attempting to change it -- record waste product settting after attempting to change it
---@param response WASTE_PRODUCT supervisor waste product settting ---@param response WASTE_PRODUCT supervisor waste product settting
function process.waste_ack_handle(response) function process.waste_ack_handle(response)
-- update config table and save
pctl.control_states.process.waste_product = response pctl.control_states.process.waste_product = response
_write_auto_config()
pctl.io.facility.ps.publish("process_waste_product", response) pctl.io.facility.ps.publish("process_waste_product", response)
end end
-- record plutonium fallback settting after attempting to change it -- record plutonium fallback settting after attempting to change it
---@param response boolean supervisor plutonium fallback settting ---@param response boolean supervisor plutonium fallback settting
function process.pu_fb_ack_handle(response) function process.pu_fb_ack_handle(response)
-- update config table and save
pctl.control_states.process.pu_fallback = response pctl.control_states.process.pu_fallback = response
_write_auto_config()
pctl.io.facility.ps.publish("process_pu_fallback", response) pctl.io.facility.ps.publish("process_pu_fallback", response)
end end
-- record SPS low power settting after attempting to change it -- record SPS low power settting after attempting to change it
---@param response boolean supervisor SPS low power settting ---@param response boolean supervisor SPS low power settting
function process.sps_lp_ack_handle(response) function process.sps_lp_ack_handle(response)
-- update config table and save
pctl.control_states.process.sps_low_power = response pctl.control_states.process.sps_low_power = response
_write_auto_config()
pctl.io.facility.ps.publish("process_sps_low_power", response) pctl.io.facility.ps.publish("process_sps_low_power", response)
end end

View File

@ -1,6 +1,7 @@
local comms = require("scada-common.comms") local comms = require("scada-common.comms")
local log = require("scada-common.log") local log = require("scada-common.log")
local mqueue = require("scada-common.mqueue") local mqueue = require("scada-common.mqueue")
local types = require("scada-common.types")
local util = require("scada-common.util") local util = require("scada-common.util")
local iocontrol = require("coordinator.iocontrol") local iocontrol = require("coordinator.iocontrol")
@ -14,6 +15,9 @@ local MGMT_TYPE = comms.MGMT_TYPE
local FAC_COMMAND = comms.FAC_COMMAND local FAC_COMMAND = comms.FAC_COMMAND
local UNIT_COMMAND = comms.UNIT_COMMAND local UNIT_COMMAND = comms.UNIT_COMMAND
local AUTO_GROUP = types.AUTO_GROUP
local WASTE_MODE = types.WASTE_MODE
-- retry time constants in ms -- retry time constants in ms
-- local INITIAL_WAIT = 1500 -- local INITIAL_WAIT = 1500
-- local RETRY_PERIOD = 1000 -- local RETRY_PERIOD = 1000
@ -166,8 +170,26 @@ function pocket.new_session(id, s_addr, i_seq_num, in_queue, out_queue, timeout)
log.info(log_tag .. "FAC ACK ALL ALARMS") log.info(log_tag .. "FAC ACK ALL ALARMS")
self.proc_handle.fac_ack_alarms() self.proc_handle.fac_ack_alarms()
elseif cmd == FAC_COMMAND.SET_WASTE_MODE then elseif cmd == FAC_COMMAND.SET_WASTE_MODE then
if pkt.length == 2 then
log.info(util.c(log_tag, " SET WASTE ", pkt.data[2]))
process.set_process_waste(pkt.data[2])
else
log.debug(log_tag .. "CRDN set waste mode packet length mismatch")
end
elseif cmd == FAC_COMMAND.SET_PU_FB then elseif cmd == FAC_COMMAND.SET_PU_FB then
if pkt.length == 2 then
log.info(util.c(log_tag, " SET PU FALLBACK ", pkt.data[2]))
process.set_pu_fallback(pkt.data[2] == true)
else
log.debug(log_tag .. "CRDN set pu fallback packet length mismatch")
end
elseif cmd == FAC_COMMAND.SET_SPS_LP then elseif cmd == FAC_COMMAND.SET_SPS_LP then
if pkt.length == 2 then
log.info(util.c(log_tag, " SET SPS LOW POWER ", pkt.data[2]))
process.set_sps_low_power(pkt.data[2] == true)
else
log.debug(log_tag .. "CRDN set sps low power packet length mismatch")
end
else else
log.debug(log_tag .. "CRDN facility command unknown") log.debug(log_tag .. "CRDN facility command unknown")
end end
@ -192,20 +214,28 @@ function pocket.new_session(id, s_addr, i_seq_num, in_queue, out_queue, timeout)
log.info(util.c(log_tag, "UNIT[", uid, "] RESET RPS")) log.info(util.c(log_tag, "UNIT[", uid, "] RESET RPS"))
self.proc_handle.reset_rps(uid) self.proc_handle.reset_rps(uid)
elseif cmd == UNIT_COMMAND.SET_BURN then elseif cmd == UNIT_COMMAND.SET_BURN then
if pkt.length == 3 then if (pkt.length == 3) and (type(pkt.data[3]) == "number") then
log.info(util.c(log_tag, "UNIT[", uid, "] SET BURN ", pkt.data[3])) log.info(util.c(log_tag, "UNIT[", uid, "] SET BURN ", pkt.data[3]))
process.set_rate(uid, pkt.data[3]) process.set_rate(uid, pkt.data[3])
else else
log.debug(log_tag .. "CRDN unit command burn rate missing option") log.debug(log_tag .. "CRDN unit command burn rate missing option")
end end
elseif cmd == UNIT_COMMAND.SET_WASTE then elseif cmd == UNIT_COMMAND.SET_WASTE then
if (pkt.length == 3) and (type(pkt.data[3]) == "number") and
(pkt.data[3] >= WASTE_MODE.AUTO) and (pkt.data[3] <= WASTE_MODE.MANUAL_ANTI_MATTER) then
log.info(util.c(log_tag, "UNIT[", id, "] SET WASTE ", pkt.data[3]))
process.set_unit_waste(uid, pkt.data[3])
else
log.debug(log_tag .. "CRDN unit command set waste missing/invalid option")
end
elseif cmd == UNIT_COMMAND.ACK_ALL_ALARMS then elseif cmd == UNIT_COMMAND.ACK_ALL_ALARMS then
log.info(util.c(log_tag, "UNIT[", uid, "] ACK ALL ALARMS")) log.info(util.c(log_tag, "UNIT[", uid, "] ACK ALL ALARMS"))
self.proc_handle.ack_all_alarms(uid) self.proc_handle.ack_all_alarms(uid)
elseif cmd == UNIT_COMMAND.ACK_ALARM then elseif cmd == UNIT_COMMAND.ACK_ALARM then
elseif cmd == UNIT_COMMAND.RESET_ALARM then elseif cmd == UNIT_COMMAND.RESET_ALARM then
elseif cmd == UNIT_COMMAND.SET_GROUP then elseif cmd == UNIT_COMMAND.SET_GROUP then
if pkt.length == 3 then if (pkt.length == 3) and (type(pkt.data[3]) == "number") and
(pkt.data[3] >= AUTO_GROUP.MANUAL) and (pkt.data[3] <= AUTO_GROUP.BACKUP) then
log.info(util.c(log_tag, "UNIT[", uid, "] SET GROUP ", pkt.data[3])) log.info(util.c(log_tag, "UNIT[", uid, "] SET GROUP ", pkt.data[3]))
process.set_group(uid, pkt.data[3]) process.set_group(uid, pkt.data[3])
else else
@ -275,7 +305,6 @@ function pocket.new_session(id, s_addr, i_seq_num, in_queue, out_queue, timeout)
u.annunciator.AutoControl, u.annunciator.AutoControl,
u.a_group u.a_group
} }
end end
_send(CRDN_TYPE.API_GET_CTRL, data) _send(CRDN_TYPE.API_GET_CTRL, data)
@ -310,6 +339,47 @@ function pocket.new_session(id, s_addr, i_seq_num, in_queue, out_queue, timeout)
} }
_send(CRDN_TYPE.API_GET_PROC, data) _send(CRDN_TYPE.API_GET_PROC, data)
elseif pkt.type == CRDN_TYPE.API_GET_WASTE then
local data = {}
local fac = db.facility
local proc = process.get_control_states().process
-- unit data
for i = 1, #db.units do
local u = db.units[i]
data[i] = {
u.waste_mode,
u.waste_product,
u.num_snas,
u.sna_peak_rate,
u.sna_max_rate,
u.sna_out_rate,
u.waste_stats
}
end
local process_rate = 0
if fac.sps_data_tbl[1].state then
process_rate = fac.sps_data_tbl[1].state.process_rate
end
-- facility data
data[#db.units + 1] = {
fac.auto_current_waste_product,
fac.auto_pu_fallback_active,
fac.auto_sps_disabled,
proc.waste_product,
proc.pu_fallback,
proc.sps_low_power,
fac.waste_stats,
fac.sps_status,
process_rate
}
_send(CRDN_TYPE.API_GET_WASTE, data)
else else
log.debug(log_tag .. "handler received unsupported CRDN packet type " .. pkt.type) log.debug(log_tag .. "handler received unsupported CRDN packet type " .. pkt.type)
end end

View File

@ -19,7 +19,7 @@ local renderer = require("coordinator.renderer")
local sounder = require("coordinator.sounder") local sounder = require("coordinator.sounder")
local threads = require("coordinator.threads") local threads = require("coordinator.threads")
local COORDINATOR_VERSION = "v1.5.13" local COORDINATOR_VERSION = "v1.5.16"
local CHUNK_LOAD_DELAY_S = 30.0 local CHUNK_LOAD_DELAY_S = 30.0

View File

@ -94,14 +94,14 @@ local function new_view(root, x, y)
main.line_break() main.line_break()
local auto_scram = IndicatorLight{parent=main,label="Automatic SCRAM",colors=ind_red,flash=true,period=period.BLINK_250_MS} local auto_scram = IndicatorLight{parent=main,label="Automatic SCRAM",colors=ind_red,flash=true,period=period.BLINK_250_MS}
local matrix_dc = IndicatorLight{parent=main,label="Matrix Disconnected",colors=ind_yel,flash=true,period=period.BLINK_500_MS} local matrix_flt = IndicatorLight{parent=main,label="Induction Matrix Fault",colors=ind_yel,flash=true,period=period.BLINK_500_MS}
local matrix_fill = IndicatorLight{parent=main,label="Matrix Charge High",colors=ind_red,flash=true,period=period.BLINK_500_MS} local matrix_fill = IndicatorLight{parent=main,label="Matrix Charge High",colors=ind_red,flash=true,period=period.BLINK_500_MS}
local unit_crit = IndicatorLight{parent=main,label="Unit Critical Alarm",colors=ind_red,flash=true,period=period.BLINK_250_MS} local unit_crit = IndicatorLight{parent=main,label="Unit Critical Alarm",colors=ind_red,flash=true,period=period.BLINK_250_MS}
local fac_rad_h = IndicatorLight{parent=main,label="Facility Radiation High",colors=ind_red,flash=true,period=period.BLINK_250_MS} local fac_rad_h = IndicatorLight{parent=main,label="Facility Radiation High",colors=ind_red,flash=true,period=period.BLINK_250_MS}
local gen_fault = IndicatorLight{parent=main,label="Gen. Control Fault",colors=ind_yel,flash=true,period=period.BLINK_500_MS} local gen_fault = IndicatorLight{parent=main,label="Gen. Control Fault",colors=ind_yel,flash=true,period=period.BLINK_500_MS}
auto_scram.register(facility.ps, "auto_scram", auto_scram.update) auto_scram.register(facility.ps, "auto_scram", auto_scram.update)
matrix_dc.register(facility.ps, "as_matrix_dc", matrix_dc.update) matrix_flt.register(facility.ps, "as_matrix_fault", matrix_flt.update)
matrix_fill.register(facility.ps, "as_matrix_fill", matrix_fill.update) matrix_fill.register(facility.ps, "as_matrix_fill", matrix_fill.update)
unit_crit.register(facility.ps, "as_crit_alarm", unit_crit.update) unit_crit.register(facility.ps, "as_crit_alarm", unit_crit.update)
fac_rad_h.register(facility.ps, "as_radiation", fac_rad_h.update) fac_rad_h.register(facility.ps, "as_radiation", fac_rad_h.update)

View File

@ -7,7 +7,7 @@ local flasher = require("graphics.flasher")
local core = {} local core = {}
core.version = "2.4.5" core.version = "2.4.6"
core.flasher = flasher core.flasher = flasher
core.events = events core.events = events

View File

@ -6,6 +6,7 @@ local element = require("graphics.element")
---@class checkbox_args ---@class checkbox_args
---@field label string checkbox text ---@field label string checkbox text
---@field box_fg_bg cpair colors for checkbox ---@field box_fg_bg cpair colors for checkbox
---@field disable_fg_bg? cpair text colors when disabled
---@field default? boolean default value ---@field default? boolean default value
---@field callback? function function to call on press ---@field callback? function function to call on press
---@field parent graphics_element ---@field parent graphics_element
@ -35,20 +36,27 @@ return function (args)
local function draw() local function draw()
e.w_set_cur(1, 1) e.w_set_cur(1, 1)
local fgd, bkg = args.box_fg_bg.fgd, args.box_fg_bg.bkg
if (not e.enabled) and type(args.disable_fg_bg) == "table" then
fgd = args.disable_fg_bg.bkg
bkg = args.disable_fg_bg.fgd
end
if e.value then if e.value then
-- show as selected -- show as selected
e.w_set_fgd(args.box_fg_bg.bkg) e.w_set_fgd(bkg)
e.w_set_bkg(args.box_fg_bg.fgd) e.w_set_bkg(fgd)
e.w_write("\x88") e.w_write("\x88")
e.w_set_fgd(args.box_fg_bg.fgd) e.w_set_fgd(fgd)
e.w_set_bkg(e.fg_bg.bkg) e.w_set_bkg(e.fg_bg.bkg)
e.w_write("\x95") e.w_write("\x95")
else else
-- show as unselected -- show as unselected
e.w_set_fgd(e.fg_bg.bkg) e.w_set_fgd(e.fg_bg.bkg)
e.w_set_bkg(args.box_fg_bg.bkg) e.w_set_bkg(bkg)
e.w_write("\x88") e.w_write("\x88")
e.w_set_fgd(args.box_fg_bg.bkg) e.w_set_fgd(bkg)
e.w_set_bkg(e.fg_bg.bkg) e.w_set_bkg(e.fg_bg.bkg)
e.w_write("\x95") e.w_write("\x95")
end end
@ -57,16 +65,18 @@ return function (args)
-- write label text -- write label text
local function draw_label() local function draw_label()
if e.enabled and e.is_focused() then if e.enabled and e.is_focused() then
e.w_set_cur(3, 1)
e.w_set_fgd(e.fg_bg.bkg) e.w_set_fgd(e.fg_bg.bkg)
e.w_set_bkg(e.fg_bg.fgd) e.w_set_bkg(e.fg_bg.fgd)
e.w_write(args.label) elseif (not e.enabled) and type(args.disable_fg_bg) == "table" then
e.w_set_fgd(args.disable_fg_bg.fgd)
e.w_set_bkg(args.disable_fg_bg.bkg)
else else
e.w_set_cur(3, 1)
e.w_set_fgd(e.fg_bg.fgd) e.w_set_fgd(e.fg_bg.fgd)
e.w_set_bkg(e.fg_bg.bkg) e.w_set_bkg(e.fg_bg.bkg)
e.w_write(args.label)
end end
e.w_set_cur(3, 1)
e.w_write(args.label)
end end
-- handle mouse interaction -- handle mouse interaction
@ -98,20 +108,20 @@ return function (args)
draw() draw()
end end
-- handle focus
e.on_focused = draw_label
e.on_unfocused = draw_label
-- handle enable
e.on_enabled = draw_label
e.on_disabled = draw_label
-- element redraw -- element redraw
function e.redraw() function e.redraw()
draw() draw()
draw_label() draw_label()
end end
-- handle focus
e.on_focused = draw_label
e.on_unfocused = draw_label
-- handle enable
e.on_enabled = e.redraw
e.on_disabled = e.redraw
---@class Checkbox:graphics_element ---@class Checkbox:graphics_element
local Checkbox, id = e.complete(true) local Checkbox, id = e.complete(true)

View File

@ -50,6 +50,7 @@ style.btn_dis_fg_bg = cpair(colors.lightGray, colors.white)
---@class _pkt_cfg_tool_ctl ---@class _pkt_cfg_tool_ctl
local tool_ctl = { local tool_ctl = {
launch_startup = false,
ask_config = false, ask_config = false,
has_config = false, has_config = false,
viewing_config = false, viewing_config = false,
@ -162,8 +163,16 @@ local function config_view(display)
if not tool_ctl.has_config then tool_ctl.view_cfg.disable() end if not tool_ctl.has_config then tool_ctl.view_cfg.disable() end
local function startup()
tool_ctl.launch_startup = true
exit()
end
PushButton{parent=main_page,x=2,y=18,min_width=6,text="Exit",callback=exit,fg_bg=cpair(colors.black,colors.red),active_fg_bg=btn_act_fg_bg} PushButton{parent=main_page,x=2,y=18,min_width=6,text="Exit",callback=exit,fg_bg=cpair(colors.black,colors.red),active_fg_bg=btn_act_fg_bg}
PushButton{parent=main_page,x=14,y=18,min_width=12,text="Change Log",callback=function()main_pane.set_value(6)end,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg} local start_btn = PushButton{parent=main_page,x=17,y=18,min_width=9,text="Startup",callback=startup,fg_bg=cpair(colors.black,colors.green),active_fg_bg=btn_act_fg_bg,dis_fg_bg=btn_dis_fg_bg}
PushButton{parent=main_page,x=2,y=y_start+4,min_width=12,text="Change Log",callback=function()main_pane.set_value(6)end,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
if tool_ctl.ask_config then start_btn.disable() end
--#endregion --#endregion
@ -254,7 +263,7 @@ function configurator.configure(ask_config)
println("configurator error: " .. error) println("configurator error: " .. error)
end end
return status, error return status, error, tool_ctl.launch_startup
end end
return configurator return configurator

View File

@ -94,7 +94,8 @@ function iocontrol.init_core(pkt_comms, nav, cfg)
io.api = { io.api = {
get_unit = function (unit) comms.api__get_unit(unit) end, get_unit = function (unit) comms.api__get_unit(unit) end,
get_ctrl = function () comms.api__get_control() end, get_ctrl = function () comms.api__get_control() end,
get_proc = function () comms.api__get_process() end get_proc = function () comms.api__get_process() end,
get_waste = function () comms.api__get_waste() end
} }
end end
@ -148,7 +149,7 @@ function iocontrol.init_fac(conf)
auto_scram = false, auto_scram = false,
---@type ascram_status ---@type ascram_status
ascram_status = { ascram_status = {
matrix_dc = false, matrix_fault = false,
matrix_fill = false, matrix_fill = false,
crit_alarm = false, crit_alarm = false,
radiation = false, radiation = false,
@ -158,6 +159,8 @@ function iocontrol.init_fac(conf)
---@type WASTE_PRODUCT ---@type WASTE_PRODUCT
auto_current_waste_product = types.WASTE_PRODUCT.PLUTONIUM, auto_current_waste_product = types.WASTE_PRODUCT.PLUTONIUM,
auto_pu_fallback_active = false, auto_pu_fallback_active = false,
auto_sps_disabled = false,
waste_stats = { 0, 0, 0, 0, 0, 0 }, -- waste in, pu, po, po pellets, am, spent waste
radiation = types.new_zero_radiation_reading(), radiation = types.new_zero_radiation_reading(),
@ -217,6 +220,7 @@ function iocontrol.init_fac(conf)
last_rate_change_ms = 0, last_rate_change_ms = 0,
turbine_flow_stable = false, turbine_flow_stable = false,
waste_stats = { 0, 0, 0 }, -- plutonium, polonium, po pellets
-- auto control group -- auto control group
a_group = types.AUTO_GROUP.MANUAL, a_group = types.AUTO_GROUP.MANUAL,
@ -908,7 +912,7 @@ function iocontrol.record_process_data(data)
fac.ps.publish("auto_saturated", fac.auto_saturated) fac.ps.publish("auto_saturated", fac.auto_saturated)
fac.ps.publish("auto_scram", fac.auto_scram) fac.ps.publish("auto_scram", fac.auto_scram)
fac.ps.publish("as_matrix_dc", fac.ascram_status.matrix_dc) fac.ps.publish("as_matrix_fault", fac.ascram_status.matrix_fault)
fac.ps.publish("as_matrix_fill", fac.ascram_status.matrix_fill) fac.ps.publish("as_matrix_fill", fac.ascram_status.matrix_fill)
fac.ps.publish("as_crit_alarm", fac.ascram_status.crit_alarm) fac.ps.publish("as_crit_alarm", fac.ascram_status.crit_alarm)
fac.ps.publish("as_radiation", fac.ascram_status.radiation) fac.ps.publish("as_radiation", fac.ascram_status.radiation)
@ -920,6 +924,65 @@ function iocontrol.record_process_data(data)
fac.ps.publish("process_gen_target", f_data[5][4]) fac.ps.publish("process_gen_target", f_data[5][4])
end end
-- update waste app with unit data from API_GET_WASTE
---@param data table
function iocontrol.record_waste_data(data)
-- get unit data
for u_id = 1, #io.units do
local unit = io.units[u_id]
local u_data = data[u_id]
unit.waste_mode = u_data[1]
unit.waste_product = u_data[2]
unit.num_snas = u_data[3]
unit.sna_peak_rate = u_data[4]
unit.sna_max_rate = u_data[5]
unit.sna_out_rate = u_data[6]
unit.waste_stats = u_data[7]
unit.unit_ps.publish("U_AutoWaste", unit.waste_mode == types.WASTE_MODE.AUTO)
unit.unit_ps.publish("U_WasteMode", unit.waste_mode)
unit.unit_ps.publish("U_WasteProduct", unit.waste_product)
unit.unit_ps.publish("sna_count", unit.num_snas)
unit.unit_ps.publish("sna_peak_rate", unit.sna_peak_rate)
unit.unit_ps.publish("sna_max_rate", unit.sna_max_rate)
unit.unit_ps.publish("sna_out_rate", unit.sna_out_rate)
unit.unit_ps.publish("pu_rate", unit.waste_stats[1])
unit.unit_ps.publish("po_rate", unit.waste_stats[2])
unit.unit_ps.publish("po_pl_rate", unit.waste_stats[3])
end
-- get facility data
local fac = io.facility
local f_data = data[#io.units + 1]
fac.auto_current_waste_product = f_data[1]
fac.auto_pu_fallback_active = f_data[2]
fac.auto_sps_disabled = f_data[3]
fac.ps.publish("current_waste_product", fac.auto_current_waste_product)
fac.ps.publish("pu_fallback_active", fac.auto_pu_fallback_active)
fac.ps.publish("sps_disabled_low_power", fac.auto_sps_disabled)
fac.ps.publish("process_waste_product", f_data[4])
fac.ps.publish("process_pu_fallback", f_data[5])
fac.ps.publish("process_sps_low_power", f_data[6])
fac.waste_stats = f_data[7]
fac.ps.publish("burn_sum", fac.waste_stats[1])
fac.ps.publish("pu_rate", fac.waste_stats[2])
fac.ps.publish("po_rate", fac.waste_stats[3])
fac.ps.publish("po_pl_rate", fac.waste_stats[4])
fac.ps.publish("po_am_rate", fac.waste_stats[5])
fac.ps.publish("spent_waste_rate", fac.waste_stats[6])
fac.ps.publish("sps_computed_status", f_data[8])
fac.ps.publish("sps_process_rate", f_data[9])
end
-- get the IO controller database -- get the IO controller database
function iocontrol.get_db() return io end function iocontrol.get_db() return io end

View File

@ -89,13 +89,14 @@ local APP_ID = {
UNITS = 3, UNITS = 3,
CONTROL = 4, CONTROL = 4,
PROCESS = 5, PROCESS = 5,
GUIDE = 6, WASTE = 6,
ABOUT = 7, GUIDE = 7,
ABOUT = 8,
-- diagnostic app pages -- diagnostic app pages
ALARMS = 8, ALARMS = 9,
-- other -- other
DUMMY = 9, DUMMY = 10,
NUM_APPS = 9 NUM_APPS = 10
} }
pocket.APP_ID = APP_ID pocket.APP_ID = APP_ID
@ -264,7 +265,8 @@ function pocket.init_nav(smem)
-- open an app -- open an app
---@param app_id POCKET_APP_ID ---@param app_id POCKET_APP_ID
function nav.open_app(app_id) ---@param on_loaded? function
function nav.open_app(app_id, on_loaded)
-- reset help return on navigating out of an app -- reset help return on navigating out of an app
if app_id == APP_ID.ROOT then self.help_return = nil end if app_id == APP_ID.ROOT then self.help_return = nil end
@ -277,7 +279,7 @@ function pocket.init_nav(smem)
app = self.apps[app_id] app = self.apps[app_id]
else self.loader_return = nil end else self.loader_return = nil end
if not app.loaded then smem.q.mq_render.push_data(MQ__RENDER_DATA.LOAD_APP, app_id) end if not app.loaded then smem.q.mq_render.push_data(MQ__RENDER_DATA.LOAD_APP, { app_id, on_loaded }) end
self.cur_app = app_id self.cur_app = app_id
self.pane.set_value(app_id) self.pane.set_value(app_id)
@ -360,10 +362,10 @@ function pocket.init_nav(smem)
function nav.open_help(key) function nav.open_help(key)
self.help_return = self.cur_app self.help_return = self.cur_app
nav.open_app(APP_ID.GUIDE) nav.open_app(APP_ID.GUIDE, function ()
local show = self.help_map[key]
local load = self.help_map[key] if show then show() end
if load then load() end end)
end end
-- link the help map from the guide app -- link the help map from the guide app
@ -565,6 +567,11 @@ function pocket.comms(version, nic, sv_watchdog, api_watchdog, nav)
if self.api.linked then _send_api(CRDN_TYPE.API_GET_PROC, {}) end if self.api.linked then _send_api(CRDN_TYPE.API_GET_PROC, {}) end
end end
-- coordinator get waste app data
function public.api__get_waste()
if self.api.linked then _send_api(CRDN_TYPE.API_GET_WASTE, {}) end
end
-- send a facility command -- send a facility command
---@param cmd FAC_COMMAND command ---@param cmd FAC_COMMAND command
---@param option any? optional option options for the optional options (like waste mode) ---@param option any? optional option options for the optional options (like waste mode)
@ -733,6 +740,10 @@ function pocket.comms(version, nic, sv_watchdog, api_watchdog, nav)
if _check_length(packet, #iocontrol.get_db().units + 1) then if _check_length(packet, #iocontrol.get_db().units + 1) then
iocontrol.record_process_data(packet.data) iocontrol.record_process_data(packet.data)
end end
elseif packet.type == CRDN_TYPE.API_GET_WASTE then
if _check_length(packet, #iocontrol.get_db().units + 1) then
iocontrol.record_waste_data(packet.data)
end
else _fail_type(packet) end else _fail_type(packet) end
else else
log.debug("discarding coordinator SCADA_CRDN packet before linked") log.debug("discarding coordinator SCADA_CRDN packet before linked")

View File

@ -85,6 +85,14 @@ function process.set_group(unit_id, group_id)
log.debug(util.c("PROCESS: UNIT[", unit_id, "] SET GROUP ", group_id)) log.debug(util.c("PROCESS: UNIT[", unit_id, "] SET GROUP ", group_id))
end end
-- set waste mode
---@param id integer unit ID
---@param mode integer waste mode
function process.set_unit_waste(id, mode)
self.comms.send_unit_command(U_CMD.SET_WASTE, id, mode)
log.debug(util.c("PROCESS: UNIT[", id, "] SET WASTE ", mode))
end
-- acknowledge all alarms -- acknowledge all alarms
---@param id integer unit ID ---@param id integer unit ID
function process.ack_all_alarms(id) function process.ack_all_alarms(id)
@ -131,6 +139,27 @@ function process.process_stop()
log.debug("PROCESS: STOP AUTO CTRL") log.debug("PROCESS: STOP AUTO CTRL")
end end
-- set automatic process control waste mode
---@param product WASTE_PRODUCT waste product for auto control
function process.set_process_waste(product)
self.comms.send_fac_command(F_CMD.SET_WASTE_MODE, product)
log.debug(util.c("PROCESS: SET WASTE ", product))
end
-- set automatic process control plutonium fallback
---@param enabled boolean whether to enable plutonium fallback
function process.set_pu_fallback(enabled)
self.comms.send_fac_command(F_CMD.SET_PU_FB, enabled)
log.debug(util.c("PROCESS: SET PU FALLBACK ", enabled))
end
-- set automatic process control SPS usage at low power
---@param enabled boolean whether to enable SPS usage at low power
function process.set_sps_low_power(enabled)
self.comms.send_fac_command(F_CMD.SET_SPS_LP, enabled)
log.debug(util.c("PROCESS: SET SPS LOW POWER ", enabled))
end
-- #endregion -- #endregion
--------------------------------- ---------------------------------

View File

@ -20,7 +20,7 @@ local pocket = require("pocket.pocket")
local renderer = require("pocket.renderer") local renderer = require("pocket.renderer")
local threads = require("pocket.threads") local threads = require("pocket.threads")
local POCKET_VERSION = "v0.12.7-alpha" local POCKET_VERSION = "v0.12.10-alpha"
local println = util.println local println = util.println
local println_ts = util.println_ts local println_ts = util.println_ts

View File

@ -165,15 +165,18 @@ function threads.thread__render(smem)
local cmd = msg.message ---@type queue_data local cmd = msg.message ---@type queue_data
if cmd.key == MQ__RENDER_DATA.LOAD_APP then if cmd.key == MQ__RENDER_DATA.LOAD_APP then
log.debug("RENDER: load app " .. cmd.val) log.debug("RENDER: load app " .. cmd.val[1])
local draw_start = util.time_ms() local draw_start = util.time_ms()
pkt_state.ui_ok, pkt_state.ui_error = pcall(function () nav.load_app(cmd.val) end) pkt_state.ui_ok, pkt_state.ui_error = pcall(function () nav.load_app(cmd.val[1]) end)
if not pkt_state.ui_ok then if not pkt_state.ui_ok then
log.fatal(util.c("RENDER: app load failed with error ", pkt_state.ui_error)) log.fatal(util.c("RENDER: app load failed with error ", pkt_state.ui_error))
else else
log.debug("RENDER: app loaded in " .. (util.time_ms() - draw_start) .. "ms") log.debug("RENDER: app loaded in " .. (util.time_ms() - draw_start) .. "ms")
-- call the on loaded function if provided
if type(cmd.val[2]) == "function" then cmd.val[2]() end
end end
end end
elseif msg.qtype == mqueue.TYPE.PACKET then elseif msg.qtype == mqueue.TYPE.PACKET then

View File

@ -269,7 +269,7 @@ local function new_view(root)
local auto_scram = IconIndicator{parent=a_div,y=3,label="Automatic SCRAM",states=red_ind_s} local auto_scram = IconIndicator{parent=a_div,y=3,label="Automatic SCRAM",states=red_ind_s}
TextBox{parent=a_div,y=5,text="Induction Matrix",fg_bg=label_fg_bg} TextBox{parent=a_div,y=5,text="Induction Matrix",fg_bg=label_fg_bg}
local matrix_dc = IconIndicator{parent=a_div,label="Disconnected",states=yel_ind_s} local matrix_flt = IconIndicator{parent=a_div,label="Matrix Fault",states=yel_ind_s}
local matrix_fill = IconIndicator{parent=a_div,label="Charge High",states=red_ind_s} local matrix_fill = IconIndicator{parent=a_div,label="Charge High",states=red_ind_s}
TextBox{parent=a_div,y=9,text="Assigned Units",fg_bg=label_fg_bg} TextBox{parent=a_div,y=9,text="Assigned Units",fg_bg=label_fg_bg}
@ -282,7 +282,7 @@ local function new_view(root)
local gen_fault = IconIndicator{parent=a_div,label="Control Fault",states=yel_ind_s} local gen_fault = IconIndicator{parent=a_div,label="Control Fault",states=yel_ind_s}
auto_scram.register(f_ps, "auto_scram", auto_scram.update) auto_scram.register(f_ps, "auto_scram", auto_scram.update)
matrix_dc.register(f_ps, "as_matrix_dc", matrix_dc.update) matrix_flt.register(f_ps, "as_matrix_fault", matrix_flt.update)
matrix_fill.register(f_ps, "as_matrix_fill", matrix_fill.update) matrix_fill.register(f_ps, "as_matrix_fill", matrix_fill.update)
unit_crit.register(f_ps, "as_crit_alarm", unit_crit.update) unit_crit.register(f_ps, "as_crit_alarm", unit_crit.update)
fac_rad_h.register(f_ps, "as_radiation", fac_rad_h.update) fac_rad_h.register(f_ps, "as_radiation", fac_rad_h.update)

310
pocket/ui/apps/waste.lua Normal file
View File

@ -0,0 +1,310 @@
--
-- Waste Control Page
--
local util = require("scada-common.util")
local iocontrol = require("pocket.iocontrol")
local pocket = require("pocket.pocket")
local process = require("pocket.process")
local style = require("pocket.ui.style")
local core = require("graphics.core")
local Div = require("graphics.elements.Div")
local MultiPane = require("graphics.elements.MultiPane")
local TextBox = require("graphics.elements.TextBox")
local WaitingAnim = require("graphics.elements.animations.Waiting")
local Checkbox = require("graphics.elements.controls.Checkbox")
local PushButton = require("graphics.elements.controls.PushButton")
local RadioButton = require("graphics.elements.controls.RadioButton")
local DataIndicator = require("graphics.elements.indicators.DataIndicator")
local IconIndicator = require("graphics.elements.indicators.IconIndicator")
local StateIndicator = require("graphics.elements.indicators.StateIndicator")
local ALIGN = core.ALIGN
local cpair = core.cpair
local APP_ID = pocket.APP_ID
local label_fg_bg = style.label
local text_fg = style.text_fg
local lu_col = style.label_unit_pair
local yel_ind_s = style.icon_states.yel_ind_s
local wht_ind_s = style.icon_states.wht_ind_s
-- new waste control 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.WASTE, 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.brown,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[]
local u_pages = {} ---@type nav_tree_page[]
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_waste()
last_update = util.time_ms()
end
end
--#region unit waste options/statistics
for i = 1, db.facility.num_units do
local u_pane = Div{parent=page_div}
local u_div = Div{parent=u_pane,x=2,width=main.get_width()-2}
local unit = db.units[i]
local u_ps = unit.unit_ps
table.insert(panes, u_div)
local u_page = app.new_page(nil, #panes)
u_page.tasks = { update }
table.insert(u_pages, u_page)
TextBox{parent=u_div,y=1,text="Reactor Unit #"..i,alignment=ALIGN.CENTER}
local function set_waste(mode) process.set_unit_waste(i, mode) end
local waste_prod = StateIndicator{parent=u_div,x=16,y=3,states=style.waste.states_abbrv,value=1,min_width=6}
local waste_mode = RadioButton{parent=u_div,y=3,options=style.waste.unit_opts,callback=set_waste,radio_colors=cpair(colors.lightGray,colors.gray),select_color=colors.white}
waste_prod.register(u_ps, "U_WasteProduct", waste_prod.update)
waste_mode.register(u_ps, "U_WasteMode", waste_mode.set_value)
TextBox{parent=u_div,y=8,text="Plutonium (Pellets)",fg_bg=label_fg_bg}
local pu = DataIndicator{parent=u_div,label="",format="%16.3f",value=0,unit="mB/t",lu_colors=lu_col,width=21,fg_bg=text_fg}
TextBox{parent=u_div,y=11,text="Polonium",fg_bg=label_fg_bg}
local po = DataIndicator{parent=u_div,label="",format="%16.3f",value=0,unit="mB/t",lu_colors=lu_col,width=21,fg_bg=text_fg}
TextBox{parent=u_div,y=14,text="Polonium (Pellets)",fg_bg=label_fg_bg}
local popl = DataIndicator{parent=u_div,label="",format="%16.3f",value=0,unit="mB/t",lu_colors=lu_col,width=21,fg_bg=text_fg}
pu.register(u_ps, "pu_rate", pu.update)
po.register(u_ps, "po_rate", po.update)
popl.register(u_ps, "po_pl_rate", popl.update)
local sna_div = Div{parent=u_pane,x=2,width=page_div.get_width()-2}
table.insert(panes, sna_div)
local sps_page = app.new_page(u_page, #panes)
sps_page.tasks = { update }
PushButton{parent=u_div,x=6,y=18,text="SNA DATA",min_width=12,fg_bg=cpair(colors.lightGray,colors.gray),active_fg_bg=cpair(colors.gray,colors.lightGray),callback=sps_page.nav_to}
PushButton{parent=sna_div,x=9,y=18,text="BACK",min_width=6,fg_bg=cpair(colors.lightGray,colors.gray),active_fg_bg=cpair(colors.gray,colors.lightGray),callback=u_page.nav_to}
TextBox{parent=sna_div,y=1,text="Unit "..i.." SNAs",alignment=ALIGN.CENTER}
TextBox{parent=sna_div,y=3,text="Connected",fg_bg=label_fg_bg}
local count = DataIndicator{parent=sna_div,x=20,y=3,label="",format="%2d",value=0,unit="",lu_colors=lu_col,width=2,fg_bg=text_fg}
TextBox{parent=sna_div,y=5,text="Peak Possible Rate\n In\n Out",fg_bg=label_fg_bg}
local peak_i = DataIndicator{parent=sna_div,x=6,y=6,label="",format="%11.2f",value=0,unit="mB/t",lu_colors=lu_col,width=17,fg_bg=text_fg}
local peak_o = DataIndicator{parent=sna_div,x=6,label="",format="%11.2f",value=0,unit="mB/t",lu_colors=lu_col,width=17,fg_bg=text_fg}
TextBox{parent=sna_div,y=9,text="Current Maximum Rate\n In\n Out",fg_bg=label_fg_bg}
local max_i = DataIndicator{parent=sna_div,x=6,y=10,label="",format="%11.2f",value=0,unit="mB/t",lu_colors=lu_col,width=17,fg_bg=text_fg}
local max_o = DataIndicator{parent=sna_div,x=6,label="",format="%11.2f",value=0,unit="mB/t",lu_colors=lu_col,width=17,fg_bg=text_fg}
TextBox{parent=sna_div,y=13,text="Current Rate\n In\n Out",fg_bg=label_fg_bg}
local cur_i = DataIndicator{parent=sna_div,x=6,y=14,label="",format="%11.2f",value=0,unit="mB/t",lu_colors=lu_col,width=17,fg_bg=text_fg}
local cur_o = DataIndicator{parent=sna_div,x=6,label="",format="%11.2f",value=0,unit="mB/t",lu_colors=lu_col,width=17,fg_bg=text_fg}
count.register(u_ps, "sna_count", count.update)
peak_i.register(u_ps, "sna_peak_rate", function (x) peak_i.update(x * 10) end)
peak_o.register(u_ps, "sna_peak_rate", peak_o.update)
max_i.register(u_ps, "sna_max_rate", function (x) max_i.update(x * 10) end)
max_o.register(u_ps, "sna_max_rate", max_o.update)
cur_i.register(u_ps, "sna_out_rate", function (x) cur_i.update(x * 10) end)
cur_o.register(u_ps, "sna_out_rate", cur_o.update)
end
--#endregion
--#region waste control page
local c_pane = Div{parent=page_div}
local c_div = Div{parent=c_pane,x=2,width=main.get_width()-2}
table.insert(panes, c_div)
local wst_ctrl = app.new_page(nil, #panes)
wst_ctrl.tasks = { update }
TextBox{parent=c_div,y=1,text="Waste Control",alignment=ALIGN.CENTER}
local status = StateIndicator{parent=c_div,x=3,y=3,states=style.waste.states,value=1,min_width=17}
local waste_prod = RadioButton{parent=c_div,y=5,options=style.waste.options,callback=process.set_process_waste,radio_colors=cpair(colors.lightGray,colors.gray),select_color=colors.white}
status.register(f_ps, "current_waste_product", status.update)
waste_prod.register(f_ps, "process_waste_product", waste_prod.set_value)
local fb_active = IconIndicator{parent=c_div,y=9,label="Fallback Active",states=wht_ind_s}
local sps_disabled = IconIndicator{parent=c_div,y=10,label="SPS Disabled LC",states=yel_ind_s}
fb_active.register(f_ps, "pu_fallback_active", fb_active.update)
sps_disabled.register(f_ps, "sps_disabled_low_power", sps_disabled.update)
TextBox{parent=c_div,y=12,text="Nuclear Waste In",fg_bg=label_fg_bg}
local sum_raw_waste = DataIndicator{parent=c_div,label="",format="%16.3f",value=0,unit="mB/t",lu_colors=lu_col,width=21,fg_bg=text_fg}
sum_raw_waste.register(f_ps, "burn_sum", sum_raw_waste.update)
TextBox{parent=c_div,y=15,text="Spent Waste Out",fg_bg=label_fg_bg}
local sum_sp_waste = DataIndicator{parent=c_div,label="",format="%16.3f",value=0,unit="mB/t",lu_colors=lu_col,width=21,fg_bg=text_fg}
sum_sp_waste.register(f_ps, "spent_waste_rate", sum_sp_waste.update)
local stats_div = Div{parent=c_pane,x=2,width=page_div.get_width()-2}
table.insert(panes, stats_div)
local stats_page = app.new_page(wst_ctrl, #panes)
stats_page.tasks = { update }
PushButton{parent=c_div,x=6,y=18,text="PROD RATES",min_width=12,fg_bg=cpair(colors.lightGray,colors.gray),active_fg_bg=cpair(colors.gray,colors.lightGray),callback=stats_page.nav_to}
PushButton{parent=stats_div,x=9,y=18,text="BACK",min_width=6,fg_bg=cpair(colors.lightGray,colors.gray),active_fg_bg=cpair(colors.gray,colors.lightGray),callback=wst_ctrl.nav_to}
TextBox{parent=stats_div,y=1,text="Production Rates",alignment=ALIGN.CENTER}
TextBox{parent=stats_div,y=3,text="Plutonium (Pellets)",fg_bg=label_fg_bg}
local pu = DataIndicator{parent=stats_div,label="",format="%16.3f",value=0,unit="mB/t",lu_colors=lu_col,width=21,fg_bg=text_fg}
TextBox{parent=stats_div,y=6,text="Polonium",fg_bg=label_fg_bg}
local po = DataIndicator{parent=stats_div,label="",format="%16.3f",value=0,unit="mB/t",lu_colors=lu_col,width=21,fg_bg=text_fg}
TextBox{parent=stats_div,y=9,text="Polonium (Pellets)",fg_bg=label_fg_bg}
local popl = DataIndicator{parent=stats_div,label="",format="%16.3f",value=0,unit="mB/t",lu_colors=lu_col,width=21,fg_bg=text_fg}
pu.register(f_ps, "pu_rate", pu.update)
po.register(f_ps, "po_rate", po.update)
popl.register(f_ps, "po_pl_rate", popl.update)
TextBox{parent=stats_div,y=12,text="Antimatter",fg_bg=label_fg_bg}
local am = DataIndicator{parent=stats_div,label="",format="%16d",value=0,unit="\xb5B/t",lu_colors=lu_col,width=21,fg_bg=text_fg}
am.register(f_ps, "sps_process_rate", function (r) am.update(r * 1000) end)
--#endregion
--#region waste options page
local o_pane = Div{parent=page_div}
local o_div = Div{parent=o_pane,x=2,width=main.get_width()-2}
table.insert(panes, o_pane)
local opt_page = app.new_page(nil, #panes)
opt_page.tasks = { update }
TextBox{parent=o_div,y=1,text="Waste Options",alignment=ALIGN.CENTER}
local pu_fallback = Checkbox{parent=o_div,x=2,y=3,label="Pu Fallback",callback=process.set_pu_fallback,box_fg_bg=cpair(colors.white,colors.gray)}
TextBox{parent=o_div,x=2,y=5,height=3,text="Switch to Pu when SNAs cannot keep up with waste.",fg_bg=label_fg_bg}
local lc_sps = Checkbox{parent=o_div,x=2,y=9,label="Low Charge SPS",callback=process.set_sps_low_power,box_fg_bg=cpair(colors.white,colors.gray)}
TextBox{parent=o_div,x=2,y=11,height=3,text="Use SPS at low charge, otherwise switches to Po.",fg_bg=label_fg_bg}
pu_fallback.register(f_ps, "process_pu_fallback", pu_fallback.set_value)
lc_sps.register(f_ps, "process_sps_low_power", lc_sps.set_value)
--#endregion
--#region SPS page
local s_pane = Div{parent=page_div}
local s_div = Div{parent=s_pane,x=2,width=main.get_width()-2}
table.insert(panes, s_pane)
local sps_page = app.new_page(nil, #panes)
sps_page.tasks = { update }
TextBox{parent=s_div,y=1,text="Facility SPS",alignment=ALIGN.CENTER}
local sps_status = StateIndicator{parent=s_div,x=5,y=3,states=style.sps.states,value=1,min_width=12}
sps_status.register(f_ps, "sps_computed_status", sps_status.update)
TextBox{parent=s_div,y=5,text="Input Rate",width=10,fg_bg=label_fg_bg}
local sps_in = DataIndicator{parent=s_div,label="",format="%16.2f",value=0,unit="mB/t",lu_colors=lu_col,width=21,fg_bg=text_fg}
sps_in.register(f_ps, "po_am_rate", sps_in.update)
TextBox{parent=s_div,y=8,text="Production Rate",width=15,fg_bg=label_fg_bg}
local sps_rate = DataIndicator{parent=s_div,label="",format="%16d",value=0,unit="\xb5B/t",lu_colors=lu_col,width=21,fg_bg=text_fg}
sps_rate.register(f_ps, "sps_process_rate", function (r) sps_rate.update(r * 1000) end)
--#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 = "WST", color = core.cpair(colors.black, colors.brown), callback = wst_ctrl.nav_to },
{ label = "OPT", color = core.cpair(colors.black, colors.white), callback = opt_page.nav_to },
{ label = "SPS", color = core.cpair(colors.black, colors.purple), callback = sps_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 = u_pages[i].nav_to })
end
app.set_sidebar(list)
-- done, show the app
wst_ctrl.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

View File

@ -148,7 +148,7 @@ doc("auto_ramping", "Process Ramping", "Automatic process control is performing
doc("auto_saturated", "Min/Max Burn Rate", "Auto control has either commanded 0 mB/t or the maximum total burn rate available (from assigned units).") doc("auto_saturated", "Min/Max Burn Rate", "Auto control has either commanded 0 mB/t or the maximum total burn rate available (from assigned units).")
sect("Automatic SCRAM") sect("Automatic SCRAM")
doc("auto_scram", "Automatic SCRAM", "Automatic control system SCRAM'ed the assigned reactors due to a safety hazard, shown by the below indicators.") doc("auto_scram", "Automatic SCRAM", "Automatic control system SCRAM'ed the assigned reactors due to a safety hazard, shown by the below indicators.")
doc("as_matrix_dc", "Matrix Disconnected", "Automatic SCRAM occurred due to loss of induction matrix connection.") doc("as_matrix_fault", "Matrix Fault", "Automatic SCRAM occurred due to the loss of the induction matrix connection, or the matrix being unformed or faulted.")
doc("as_matrix_fill", "Matrix Charge High", "Automatic SCRAM occurred due to induction matrix charge exceeding acceptable limit.") doc("as_matrix_fill", "Matrix Charge High", "Automatic SCRAM occurred due to induction matrix charge exceeding acceptable limit.")
doc("as_crit_alarm", "Unit Critical Alarm", "Automatic SCRAM occurred due to critical level unit alarm(s).") doc("as_crit_alarm", "Unit Critical Alarm", "Automatic SCRAM occurred due to critical level unit alarm(s).")
doc("as_radiation", "Facility Radiation High", "Automatic SCRAM occurred due to high facility radiation levels.") doc("as_radiation", "Facility Radiation High", "Automatic SCRAM occurred due to high facility radiation levels.")

View File

@ -15,6 +15,7 @@ local loader_app = require("pocket.ui.apps.loader")
local process_app = require("pocket.ui.apps.process") local process_app = require("pocket.ui.apps.process")
local sys_apps = require("pocket.ui.apps.sys_apps") local sys_apps = require("pocket.ui.apps.sys_apps")
local unit_app = require("pocket.ui.apps.unit") local unit_app = require("pocket.ui.apps.unit")
local waste_app = require("pocket.ui.apps.waste")
local home_page = require("pocket.ui.pages.home_page") local home_page = require("pocket.ui.pages.home_page")
@ -66,6 +67,7 @@ local function init(main)
unit_app(page_div) unit_app(page_div)
control_app(page_div) control_app(page_div)
process_app(page_div) process_app(page_div)
waste_app(page_div)
guide_app(page_div) guide_app(page_div)
loader_app(page_div) loader_app(page_div)
sys_apps(page_div) sys_apps(page_div)

View File

@ -49,7 +49,7 @@ local function new_view(root)
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=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.CONTROL)end,app_fg_bg=cpair(colors.black,colors.green),active_fg_bg=active_fg_bg} 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=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.DUMMY)end,app_fg_bg=cpair(colors.black,colors.brown),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=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=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=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}

View File

@ -214,4 +214,66 @@ style.imatrix = {
} }
} }
style.sps = {
-- SPS states
states = {
{
color = cpair(colors.black, colors.yellow),
text = "OFF-LINE"
},
{
color = cpair(colors.black, colors.orange),
text = "NOT FORMED"
},
{
color = cpair(colors.black, colors.orange),
text = "RTU FAULT"
},
{
color = cpair(colors.white, colors.gray),
text = "IDLE"
},
{
color = cpair(colors.black, colors.green),
text = "ACTIVE"
}
}
}
style.waste = {
-- auto waste processing states
states = {
{
color = cpair(colors.black, colors.green),
text = "PLUTONIUM"
},
{
color = cpair(colors.black, colors.cyan),
text = "POLONIUM"
},
{
color = cpair(colors.black, colors.purple),
text = "ANTI MATTER"
}
},
states_abbrv = {
{
color = cpair(colors.black, colors.green),
text = "Pu"
},
{
color = cpair(colors.black, colors.cyan),
text = "Po"
},
{
color = cpair(colors.black, colors.purple),
text = "AM"
}
},
-- process radio button options
options = { "Plutonium", "Polonium", "Antimatter" },
-- unit waste selection
unit_opts = { "Auto", "Plutonium", "Polonium", "Antimatter" }
}
return style return style

View File

@ -53,6 +53,7 @@ style.btn_dis_fg_bg = cpair(colors.lightGray, colors.white)
---@class _plc_cfg_tool_ctl ---@class _plc_cfg_tool_ctl
local tool_ctl = { local tool_ctl = {
launch_startup = false,
ask_config = false, ask_config = false,
has_config = false, has_config = false,
viewing_config = false, viewing_config = false,
@ -184,10 +185,18 @@ local function config_view(display)
main_pane.set_value(5) main_pane.set_value(5)
end end
local function startup()
tool_ctl.launch_startup = true
exit()
end
PushButton{parent=main_page,x=2,y=17,min_width=6,text="Exit",callback=exit,fg_bg=cpair(colors.black,colors.red),active_fg_bg=btn_act_fg_bg} PushButton{parent=main_page,x=2,y=17,min_width=6,text="Exit",callback=exit,fg_bg=cpair(colors.black,colors.red),active_fg_bg=btn_act_fg_bg}
PushButton{parent=main_page,x=10,y=17,min_width=12,text="Self-Check",callback=function()main_pane.set_value(8)end,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg,dis_fg_bg=btn_dis_fg_bg} local start_btn = PushButton{parent=main_page,x=42,y=17,min_width=9,text="Startup",callback=startup,fg_bg=cpair(colors.black,colors.green),active_fg_bg=btn_act_fg_bg,dis_fg_bg=btn_dis_fg_bg}
tool_ctl.color_cfg = PushButton{parent=main_page,x=23,y=17,min_width=15,text="Color Options",callback=jump_color,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg,dis_fg_bg=btn_dis_fg_bg} PushButton{parent=main_page,x=39,y=y_start,min_width=12,text="Self-Check",callback=function()main_pane.set_value(8)end,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg,dis_fg_bg=btn_dis_fg_bg}
PushButton{parent=main_page,x=39,y=17,min_width=12,text="Change Log",callback=function()main_pane.set_value(7)end,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg} tool_ctl.color_cfg = PushButton{parent=main_page,x=36,y=y_start+2,min_width=15,text="Color Options",callback=jump_color,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg,dis_fg_bg=btn_dis_fg_bg}
PushButton{parent=main_page,x=39,y=y_start+4,min_width=12,text="Change Log",callback=function()main_pane.set_value(7)end,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
if tool_ctl.ask_config then start_btn.disable() end
if not tool_ctl.has_config then if not tool_ctl.has_config then
tool_ctl.view_cfg.disable() tool_ctl.view_cfg.disable()
@ -293,7 +302,7 @@ function configurator.configure(ask_config)
println("configurator error: " .. error) println("configurator error: " .. error)
end end
return status, error return status, error, tool_ctl.launch_startup
end end
return configurator return configurator

View File

@ -18,7 +18,7 @@ local plc = require("reactor-plc.plc")
local renderer = require("reactor-plc.renderer") local renderer = require("reactor-plc.renderer")
local threads = require("reactor-plc.threads") local threads = require("reactor-plc.threads")
local R_PLC_VERSION = "v1.8.12" local R_PLC_VERSION = "v1.8.13"
local println = util.println local println = util.println
local println_ts = util.println_ts local println_ts = util.println_ts

View File

@ -39,6 +39,7 @@ local self = {
rs_cfg_unit_l = nil, ---@type TextBox rs_cfg_unit_l = nil, ---@type TextBox
rs_cfg_unit = nil, ---@type NumberField rs_cfg_unit = nil, ---@type NumberField
rs_cfg_side_l = nil, ---@type TextBox rs_cfg_side_l = nil, ---@type TextBox
rs_cfg_bundled = nil, ---@type Checkbox
rs_cfg_color = nil, ---@type Radio2D rs_cfg_color = nil, ---@type Radio2D
rs_cfg_shortcut = nil ---@type TextBox rs_cfg_shortcut = nil ---@type TextBox
} }
@ -195,6 +196,15 @@ function redstone.create(tool_ctl, main_pane, cfg_sys, rs_cfg, style)
local io_mode = rsio.get_io_mode(port) local io_mode = rsio.get_io_mode(port)
local inv = tri(rsio.digital_is_active(port, IO_LVL.LOW) == true, "inverted ", "") local inv = tri(rsio.digital_is_active(port, IO_LVL.LOW) == true, "inverted ", "")
if rsio.is_analog(port) then
self.rs_cfg_bundled.set_value(false)
self.rs_cfg_bundled.disable()
self.rs_cfg_color.disable()
else
self.rs_cfg_bundled.enable()
if self.rs_cfg_bundled.get_value() then self.rs_cfg_color.enable() else self.rs_cfg_color.disable() end
end
if io_mode == IO_MODE.DIGITAL_IN then if io_mode == IO_MODE.DIGITAL_IN then
io_type = inv .. "digital input " io_type = inv .. "digital input "
elseif io_mode == IO_MODE.DIGITAL_OUT then elseif io_mode == IO_MODE.DIGITAL_OUT then
@ -263,7 +273,7 @@ function redstone.create(tool_ctl, main_pane, cfg_sys, rs_cfg, style)
self.rs_cfg_shortcut = TextBox{parent=rs_c_3,x=1,y=9,height=4,text="This shortcut will add entries for each of the 4 waste outputs. If you select bundled, 4 colors will be assigned to the selected side. Otherwise, 4 default sides will be used."} self.rs_cfg_shortcut = TextBox{parent=rs_c_3,x=1,y=9,height=4,text="This shortcut will add entries for each of the 4 waste outputs. If you select bundled, 4 colors will be assigned to the selected side. Otherwise, 4 default sides will be used."}
self.rs_cfg_shortcut.hide(true) self.rs_cfg_shortcut.hide(true)
local bundled = Checkbox{parent=rs_c_3,x=1,y=7,label="Is Bundled?",default=false,box_fg_bg=cpair(colors.red,colors.black),callback=set_bundled} self.rs_cfg_bundled = Checkbox{parent=rs_c_3,x=1,y=7,label="Is Bundled?",default=false,box_fg_bg=cpair(colors.red,colors.black),callback=set_bundled,disable_fg_bg=g_lg_fg_bg}
self.rs_cfg_color = Radio2D{parent=rs_c_3,x=1,y=9,rows=4,columns=4,default=1,options=color_options,radio_colors=cpair(colors.lightGray,colors.black),color_map=color_options_map,disable_color=colors.gray,disable_fg_bg=g_lg_fg_bg} self.rs_cfg_color = Radio2D{parent=rs_c_3,x=1,y=9,rows=4,columns=4,default=1,options=color_options,radio_colors=cpair(colors.lightGray,colors.black),color_map=color_options_map,disable_color=colors.gray,disable_fg_bg=g_lg_fg_bg}
self.rs_cfg_color.disable() self.rs_cfg_color.disable()
@ -288,7 +298,7 @@ function redstone.create(tool_ctl, main_pane, cfg_sys, rs_cfg, style)
unit = tri(PORT_DSGN[port] == 1, u, nil), unit = tri(PORT_DSGN[port] == 1, u, nil),
port = port, port = port,
side = side_options_map[side.get_value()], side = side_options_map[side.get_value()],
color = tri(bundled.get_value(), color_options_map[self.rs_cfg_color.get_value()], nil) color = tri(self.rs_cfg_bundled.get_value() and rsio.is_digital(port), color_options_map[self.rs_cfg_color.get_value()], nil)
} }
if self.rs_cfg_editing == false then if self.rs_cfg_editing == false then
@ -304,8 +314,8 @@ function redstone.create(tool_ctl, main_pane, cfg_sys, rs_cfg, style)
table.insert(tmp_cfg.Redstone, { table.insert(tmp_cfg.Redstone, {
unit = tri(PORT_DSGN[IO.WASTE_PU + i] == 1, u, nil), unit = tri(PORT_DSGN[IO.WASTE_PU + i] == 1, u, nil),
port = IO.WASTE_PU + i, port = IO.WASTE_PU + i,
side = tri(bundled.get_value(), side_options_map[side.get_value()], default_sides[i + 1]), side = tri(self.rs_cfg_bundled.get_value(), side_options_map[side.get_value()], default_sides[i + 1]),
color = tri(bundled.get_value(), default_colors[i + 1], nil) color = tri(self.rs_cfg_bundled.get_value(), default_colors[i + 1], nil)
}) })
end end
end end
@ -314,7 +324,7 @@ function redstone.create(tool_ctl, main_pane, cfg_sys, rs_cfg, style)
tool_ctl.gen_rs_summary() tool_ctl.gen_rs_summary()
side.set_value(1) side.set_value(1)
bundled.set_value(false) self.rs_cfg_bundled.set_value(false)
self.rs_cfg_color.set_value(1) self.rs_cfg_color.set_value(1)
self.rs_cfg_color.disable() self.rs_cfg_color.disable()
else rs_err.show() end else rs_err.show() end
@ -356,6 +366,14 @@ function redstone.create(tool_ctl, main_pane, cfg_sys, rs_cfg, style)
text = text .. "the facility)." text = text .. "the facility)."
end end
if rsio.is_analog(def.port) then
self.rs_cfg_bundled.set_value(false)
self.rs_cfg_bundled.disable()
else
self.rs_cfg_bundled.enable()
self.rs_cfg_bundled.set_value(def.color ~= nil)
end
local value = 1 local value = 1
if def.color ~= nil then if def.color ~= nil then
value = color_to_idx(def.color) value = color_to_idx(def.color)
@ -367,7 +385,6 @@ function redstone.create(tool_ctl, main_pane, cfg_sys, rs_cfg, style)
self.rs_cfg_selection.set_value(text) self.rs_cfg_selection.set_value(text)
self.rs_cfg_side_l.set_value(tri(rsio.get_io_dir(def.port) == rsio.IO_DIR.IN, "Input Side", "Output Side")) self.rs_cfg_side_l.set_value(tri(rsio.get_io_dir(def.port) == rsio.IO_DIR.IN, "Input Side", "Output Side"))
side.set_value(side_to_idx(def.side)) side.set_value(side_to_idx(def.side))
bundled.set_value(def.color ~= nil)
self.rs_cfg_color.set_value(value) self.rs_cfg_color.set_value(value)
rs_pane.set_value(3) rs_pane.set_value(3)
end end

View File

@ -55,6 +55,7 @@ style.btn_dis_fg_bg = cpair(colors.lightGray, colors.white)
---@class _rtu_cfg_tool_ctl ---@class _rtu_cfg_tool_ctl
local tool_ctl = { local tool_ctl = {
launch_startup = false,
ask_config = false, ask_config = false,
has_config = false, has_config = false,
viewing_config = false, viewing_config = false,
@ -218,9 +219,17 @@ local function config_view(display)
main_pane.set_value(5) main_pane.set_value(5)
end end
local function startup()
tool_ctl.launch_startup = true
exit()
end
PushButton{parent=main_page,x=2,y=17,min_width=6,text="Exit",callback=exit,fg_bg=cpair(colors.black,colors.red),active_fg_bg=btn_act_fg_bg} PushButton{parent=main_page,x=2,y=17,min_width=6,text="Exit",callback=exit,fg_bg=cpair(colors.black,colors.red),active_fg_bg=btn_act_fg_bg}
tool_ctl.color_cfg = PushButton{parent=main_page,x=23,y=17,min_width=15,text="Color Options",callback=jump_color,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg,dis_fg_bg=btn_dis_fg_bg} local start_btn = PushButton{parent=main_page,x=42,y=17,min_width=9,text="Startup",callback=startup,fg_bg=cpair(colors.black,colors.green),active_fg_bg=btn_act_fg_bg,dis_fg_bg=btn_dis_fg_bg}
PushButton{parent=main_page,x=39,y=17,min_width=12,text="Change Log",callback=function()main_pane.set_value(7)end,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg} tool_ctl.color_cfg = PushButton{parent=main_page,x=36,y=y_start,min_width=15,text="Color Options",callback=jump_color,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg,dis_fg_bg=btn_dis_fg_bg}
PushButton{parent=main_page,x=39,y=y_start+2,min_width=12,text="Change Log",callback=function()main_pane.set_value(7)end,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
if tool_ctl.ask_config then start_btn.disable() end
if not tool_ctl.has_config then if not tool_ctl.has_config then
tool_ctl.view_gw_cfg.disable() tool_ctl.view_gw_cfg.disable()
@ -346,7 +355,7 @@ function configurator.configure(ask_config)
println("configurator error: " .. error) println("configurator error: " .. error)
end end
return status, error return status, error, tool_ctl.launch_startup
end end
return configurator return configurator

View File

@ -31,7 +31,7 @@ local sna_rtu = require("rtu.dev.sna_rtu")
local sps_rtu = require("rtu.dev.sps_rtu") local sps_rtu = require("rtu.dev.sps_rtu")
local turbinev_rtu = require("rtu.dev.turbinev_rtu") local turbinev_rtu = require("rtu.dev.turbinev_rtu")
local RTU_VERSION = "v1.10.14" local RTU_VERSION = "v1.10.16"
local RTU_UNIT_TYPE = types.RTU_UNIT_TYPE local RTU_UNIT_TYPE = types.RTU_UNIT_TYPE
local RTU_HW_STATE = databus.RTU_HW_STATE local RTU_HW_STATE = databus.RTU_HW_STATE

View File

@ -17,8 +17,8 @@ local max_distance = nil
local comms = {} local comms = {}
-- protocol/data versions (protocol/data independent changes tracked by util.lua version) -- protocol/data versions (protocol/data independent changes tracked by util.lua version)
comms.version = "3.0.1" comms.version = "3.0.2"
comms.api_version = "0.0.6" comms.api_version = "0.0.7"
---@enum PROTOCOL ---@enum PROTOCOL
local PROTOCOL = { local PROTOCOL = {
@ -68,8 +68,9 @@ local CRDN_TYPE = {
UNIT_CMD = 6, -- command a reactor unit UNIT_CMD = 6, -- command a reactor unit
API_GET_FAC = 7, -- API: get all the facility data API_GET_FAC = 7, -- API: get all the facility data
API_GET_UNIT = 8, -- API: get reactor unit data API_GET_UNIT = 8, -- API: get reactor unit data
API_GET_CTRL = 9, -- API: get data used for the control app API_GET_CTRL = 9, -- API: get data for the control app
API_GET_PROC = 10 -- API: get data used for the process app API_GET_PROC = 10, -- API: get data for the process app
API_GET_WASTE = 11 -- API: get data for the waste app
} }
---@enum ESTABLISH_ACK ---@enum ESTABLISH_ACK

View File

@ -1,4 +1,4 @@
local BOOTLOADER_VERSION = "1.1" local BOOTLOADER_VERSION = "1.2"
print("SCADA BOOTLOADER V" .. BOOTLOADER_VERSION) print("SCADA BOOTLOADER V" .. BOOTLOADER_VERSION)
print("BOOT> SCANNING FOR APPLICATIONS...") print("BOOT> SCANNING FOR APPLICATIONS...")

View File

@ -51,6 +51,7 @@ style.btn_dis_fg_bg = cpair(colors.lightGray, colors.white)
---@class _svr_cfg_tool_ctl ---@class _svr_cfg_tool_ctl
local tool_ctl = { local tool_ctl = {
launch_startup = false,
ask_config = false, ask_config = false,
has_config = false, has_config = false,
viewing_config = false, viewing_config = false,
@ -201,9 +202,17 @@ local function config_view(display)
main_pane.set_value(5) main_pane.set_value(5)
end end
local function startup()
tool_ctl.launch_startup = true
exit()
end
PushButton{parent=main_page,x=2,y=17,min_width=6,text="Exit",callback=exit,fg_bg=cpair(colors.black,colors.red),active_fg_bg=btn_act_fg_bg} PushButton{parent=main_page,x=2,y=17,min_width=6,text="Exit",callback=exit,fg_bg=cpair(colors.black,colors.red),active_fg_bg=btn_act_fg_bg}
tool_ctl.color_cfg = PushButton{parent=main_page,x=23,y=17,min_width=15,text="Color Options",callback=jump_color,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg,dis_fg_bg=btn_dis_fg_bg} local start_btn = PushButton{parent=main_page,x=42,y=17,min_width=9,text="Startup",callback=startup,fg_bg=cpair(colors.black,colors.green),active_fg_bg=btn_act_fg_bg,dis_fg_bg=btn_dis_fg_bg}
PushButton{parent=main_page,x=39,y=17,min_width=12,text="Change Log",callback=function()main_pane.set_value(7)end,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg} tool_ctl.color_cfg = PushButton{parent=main_page,x=36,y=y_start,min_width=15,text="Color Options",callback=jump_color,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg,dis_fg_bg=btn_dis_fg_bg}
PushButton{parent=main_page,x=39,y=y_start+2,min_width=12,text="Change Log",callback=function()main_pane.set_value(7)end,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
if tool_ctl.ask_config then start_btn.disable() end
if not tool_ctl.has_config then if not tool_ctl.has_config then
tool_ctl.view_cfg.disable() tool_ctl.view_cfg.disable()
@ -308,7 +317,7 @@ function configurator.configure(ask_config)
println("configurator error: " .. error) println("configurator error: " .. error)
end end
return status, error return status, error, tool_ctl.launch_startup
end end
return configurator return configurator

View File

@ -17,7 +17,7 @@ local WASTE = types.WASTE_PRODUCT
---@enum AUTO_SCRAM ---@enum AUTO_SCRAM
local AUTO_SCRAM = { local AUTO_SCRAM = {
NONE = 0, NONE = 0,
MATRIX_DC = 1, MATRIX_FAULT = 1,
MATRIX_FILL = 2, MATRIX_FILL = 2,
CRIT_ALARM = 3, CRIT_ALARM = 3,
RADIATION = 4, RADIATION = 4,
@ -81,7 +81,7 @@ function facility.new(config)
ascram_reason = AUTO_SCRAM.NONE, ascram_reason = AUTO_SCRAM.NONE,
---@class ascram_status ---@class ascram_status
ascram_status = { ascram_status = {
matrix_dc = false, matrix_fault = false,
matrix_fill = false, matrix_fill = false,
crit_alarm = false, crit_alarm = false,
radiation = false, radiation = false,
@ -91,8 +91,8 @@ function facility.new(config)
charge_conversion = 1.0, charge_conversion = 1.0,
time_start = 0.0, time_start = 0.0,
initial_ramp = true, initial_ramp = true,
waiting_on_ramp = false, waiting_on_ramp = false, -- waiting on auto ramping
waiting_on_stable = false, waiting_on_stable = false, -- waiting on gen rate stabilization
accumulator = 0.0, accumulator = 0.0,
saturated = false, saturated = false,
last_update = 0, last_update = 0,
@ -599,7 +599,7 @@ function facility.new(config)
self.waiting_on_ramp or self.waiting_on_stable, self.waiting_on_ramp or self.waiting_on_stable,
self.at_max_burn or self.saturated, self.at_max_burn or self.saturated,
self.ascram, self.ascram,
astat.matrix_dc, astat.matrix_fault,
astat.matrix_fill, astat.matrix_fill,
astat.crit_alarm, astat.crit_alarm,
astat.radiation, astat.radiation,

View File

@ -341,9 +341,17 @@ function update.auto_control(ExtChargeIdling)
if state_changed then if state_changed then
self.time_start = now self.time_start = now
self.saturated = true self.saturated = true
self.waiting_on_ramp = true
self.status_text = { "MONITORED MODE", "ramping reactors to limit" }
log.info("FAC: MAX_BURN process mode started")
elseif self.waiting_on_ramp then
if all_units_ramped() then
self.waiting_on_ramp = false
self.status_text = { "MONITORED MODE", "running reactors at limit" } self.status_text = { "MONITORED MODE", "running reactors at limit" }
log.info("FAC: MAX_BURN process mode started") log.info("FAC: MAX_BURN process mode initial ramp completed")
end
end end
allocate_burn_rate(self.max_burn_combined, true) allocate_burn_rate(self.max_burn_combined, true)
@ -351,8 +359,17 @@ function update.auto_control(ExtChargeIdling)
-- a total aggregate burn rate -- a total aggregate burn rate
if state_changed then if state_changed then
self.time_start = now self.time_start = now
self.status_text = { "BURN RATE MODE", "running" } self.waiting_on_ramp = true
self.status_text = { "BURN RATE MODE", "ramping to target" }
log.info("FAC: BURN_RATE process mode started") log.info("FAC: BURN_RATE process mode started")
elseif self.waiting_on_ramp then
if all_units_ramped() then
self.waiting_on_ramp = false
self.status_text = { "BURN RATE MODE", "running" }
log.info("FAC: BURN_RATE process mode initial ramp completed")
end
end end
local unallocated = allocate_burn_rate(self.burn_target, true) local unallocated = allocate_burn_rate(self.burn_target, true)
@ -511,13 +528,19 @@ function update.auto_safety()
local astatus = self.ascram_status local astatus = self.ascram_status
-- matrix related checks
if self.induction[1] ~= nil then if self.induction[1] ~= nil then
local db = self.induction[1].get_db() local db = self.induction[1].get_db()
-- clear matrix disconnected -- check for unformed or faulted state
if astatus.matrix_dc then local i_ok = db.formed and not self.induction[1].is_faulted()
astatus.matrix_dc = false
log.info("FAC: induction matrix reconnected, clearing ASCRAM condition") -- clear matrix fault if ok again
if astatus.matrix_fault and i_ok then
astatus.matrix_fault = false
log.info("FAC: induction matrix OK, clearing ASCRAM condition")
else
astatus.matrix_fault = not i_ok
end end
-- check matrix fill too high -- check matrix fill too high
@ -528,6 +551,13 @@ function update.auto_safety()
log.info(util.c("FAC: charge state of induction matrix entered acceptable range <= ", ALARM_LIMS.CHARGE_RE_ENABLE * 100, "%")) log.info(util.c("FAC: charge state of induction matrix entered acceptable range <= ", ALARM_LIMS.CHARGE_RE_ENABLE * 100, "%"))
end end
-- system not ready, will need to restart GEN_RATE mode
-- clears when we enter the fault waiting state
astatus.gen_fault = self.mode == PROCESS.GEN_RATE and not self.units_ready
else
astatus.matrix_fault = true
end
-- check for critical unit alarms -- check for critical unit alarms
astatus.crit_alarm = false astatus.crit_alarm = false
for i = 1, #self.units do for i = 1, #self.units do
@ -555,15 +585,8 @@ function update.auto_safety()
-- operator can restart the system or hit the stop/reset button -- operator can restart the system or hit the stop/reset button
end end
-- system not ready, will need to restart GEN_RATE mode
-- clears when we enter the fault waiting state
astatus.gen_fault = self.mode == PROCESS.GEN_RATE and not self.units_ready
else
astatus.matrix_dc = true
end
if (self.mode ~= PROCESS.INACTIVE) and (self.mode ~= PROCESS.SYSTEM_ALARM_IDLE) then if (self.mode ~= PROCESS.INACTIVE) and (self.mode ~= PROCESS.SYSTEM_ALARM_IDLE) then
local scram = astatus.matrix_dc or astatus.matrix_fill or astatus.crit_alarm or astatus.gen_fault local scram = astatus.matrix_fault or astatus.matrix_fill or astatus.crit_alarm or astatus.gen_fault
if scram and not self.ascram then if scram and not self.ascram then
-- SCRAM all units -- SCRAM all units
@ -587,14 +610,14 @@ function update.auto_safety()
self.status_text = { "AUTOMATIC SCRAM", "facility radiation high" } self.status_text = { "AUTOMATIC SCRAM", "facility radiation high" }
log.info("FAC: automatic SCRAM due to high facility radiation") log.info("FAC: automatic SCRAM due to high facility radiation")
elseif astatus.matrix_dc then elseif astatus.matrix_fault then
next_mode = PROCESS.MATRIX_FAULT_IDLE next_mode = PROCESS.MATRIX_FAULT_IDLE
self.ascram_reason = AUTO_SCRAM.MATRIX_DC self.ascram_reason = AUTO_SCRAM.MATRIX_FAULT
self.status_text = { "AUTOMATIC SCRAM", "induction matrix disconnected" } self.status_text = { "AUTOMATIC SCRAM", "induction matrix fault" }
if self.mode ~= PROCESS.MATRIX_FAULT_IDLE then self.return_mode = self.mode end if self.mode ~= PROCESS.MATRIX_FAULT_IDLE then self.return_mode = self.mode end
log.info("FAC: automatic SCRAM due to induction matrix disconnection") log.info("FAC: automatic SCRAM due to induction matrix disconnected, unformed, or faulted")
elseif astatus.matrix_fill then elseif astatus.matrix_fill then
next_mode = PROCESS.MATRIX_FAULT_IDLE next_mode = PROCESS.MATRIX_FAULT_IDLE
self.ascram_reason = AUTO_SCRAM.MATRIX_FILL self.ascram_reason = AUTO_SCRAM.MATRIX_FILL

View File

@ -278,13 +278,13 @@ function coordinator.new_session(id, s_addr, i_seq_num, in_queue, out_queue, tim
end end
elseif cmd == FAC_COMMAND.SET_PU_FB then elseif cmd == FAC_COMMAND.SET_PU_FB then
if pkt.length == 2 then if pkt.length == 2 then
_send(CRDN_TYPE.FAC_CMD, { cmd, facility.set_pu_fallback(pkt.data[2]) }) _send(CRDN_TYPE.FAC_CMD, { cmd, facility.set_pu_fallback(pkt.data[2] == true) })
else else
log.debug(log_tag .. "CRDN set pu fallback packet length mismatch") log.debug(log_tag .. "CRDN set pu fallback packet length mismatch")
end end
elseif cmd == FAC_COMMAND.SET_SPS_LP then elseif cmd == FAC_COMMAND.SET_SPS_LP then
if pkt.length == 2 then if pkt.length == 2 then
_send(CRDN_TYPE.FAC_CMD, { cmd, facility.set_sps_low_power(pkt.data[2]) }) _send(CRDN_TYPE.FAC_CMD, { cmd, facility.set_sps_low_power(pkt.data[2] == true) })
else else
log.debug(log_tag .. "CRDN set sps low power packet length mismatch") log.debug(log_tag .. "CRDN set sps low power packet length mismatch")
end end

View File

@ -22,7 +22,7 @@ local supervisor = require("supervisor.supervisor")
local svsessions = require("supervisor.session.svsessions") local svsessions = require("supervisor.session.svsessions")
local SUPERVISOR_VERSION = "v1.5.10" local SUPERVISOR_VERSION = "v1.5.17"
local println = util.println local println = util.println
local println_ts = util.println_ts local println_ts = util.println_ts

View File

@ -986,7 +986,8 @@ function unit.new(reactor_id, num_boilers, num_turbines, ext_idle)
local db = self.snas[i].get_db() local db = self.snas[i].get_db()
total_peak = total_peak + db.state.peak_production total_peak = total_peak + db.state.peak_production
total_avail = total_avail + db.state.production_rate total_avail = total_avail + db.state.production_rate
total_out = total_out + math.min(db.tanks.input.amount / 10, db.state.production_rate) local out_from_in = util.trinary(db.tanks.input.amount >= 10, db.tanks.input.amount / 10, 0)
total_out = total_out + math.min(out_from_in, db.state.production_rate)
end end
status.sna = { #self.snas, total_peak, total_avail, total_out } status.sna = { #self.snas, total_peak, total_avail, total_out }