mirror of
https://github.com/MikaylaFischler/cc-mek-scada.git
synced 2024-08-30 18:22:34 +00:00
#100 interactive reactor controls (start, scram, reset)
This commit is contained in:
parent
aaab34f1a8
commit
806b217d58
@ -431,15 +431,27 @@ function coordinator.comms(version, modem, sv_port, sv_listen, api_listen, sv_wa
|
||||
-- unit command acknowledgement
|
||||
if packet.length == 3 then
|
||||
local cmd = packet.data[1]
|
||||
local unit = packet.data[2]
|
||||
local unit_id = packet.data[2]
|
||||
local ack = packet.data[3]
|
||||
|
||||
local unit = iocontrol.get_db().units[unit_id] ---@type ioctl_entry
|
||||
|
||||
if unit ~= nil then
|
||||
if cmd == CRDN_COMMANDS.SCRAM then
|
||||
unit.scram_ack(ack)
|
||||
elseif cmd == CRDN_COMMANDS.START then
|
||||
unit.start_ack(ack)
|
||||
elseif cmd == CRDN_COMMANDS.RESET_RPS then
|
||||
unit.reset_rps_ack(ack)
|
||||
elseif cmd == CRDN_COMMANDS.SET_BURN then
|
||||
unit.set_burn_ack(ack)
|
||||
elseif cmd == CRDN_COMMANDS.SET_WASTE then
|
||||
unit.set_waste_ack(ack)
|
||||
else
|
||||
log.debug(util.c("received command ack with unknown command ", cmd))
|
||||
end
|
||||
else
|
||||
log.debug(util.c("received command ack with unknown unit ", unit_id))
|
||||
end
|
||||
else
|
||||
log.debug("unit command ack packet length mismatch")
|
||||
|
@ -38,6 +38,13 @@ function iocontrol.init(conf, comms)
|
||||
scram = function () end,
|
||||
reset_rps = function () end,
|
||||
set_burn = function (rate) end,
|
||||
set_waste = function (mode) end,
|
||||
|
||||
start_ack = function (success) end,
|
||||
scram_ack = function (success) end,
|
||||
reset_rps_ack = function (success) end,
|
||||
set_burn_ack = function (success) end,
|
||||
set_waste_ack = function (success) end,
|
||||
|
||||
reactor_ps = psil.create(),
|
||||
reactor_data = {}, ---@type reactor_db
|
||||
@ -71,6 +78,11 @@ function iocontrol.init(conf, comms)
|
||||
log.debug(util.c("UNIT[", i, "]: SET_BURN = ", rate))
|
||||
end
|
||||
|
||||
function entry.set_waste(mode)
|
||||
comms.send_command(CRDN_COMMANDS.SET_WASTE, i, mode)
|
||||
log.debug(util.c("UNIT[", i, "]: SET_WASTE = ", mode))
|
||||
end
|
||||
|
||||
-- create boiler tables
|
||||
for _ = 1, conf.defs[(i * 2) - 1] do
|
||||
local data = {} ---@type boilerv_session_db
|
||||
|
@ -16,7 +16,7 @@ local config = require("coordinator.config")
|
||||
local coordinator = require("coordinator.coordinator")
|
||||
local renderer = require("coordinator.renderer")
|
||||
|
||||
local COORDINATOR_VERSION = "alpha-v0.6.2"
|
||||
local COORDINATOR_VERSION = "alpha-v0.6.3"
|
||||
|
||||
local print = util.print
|
||||
local println = util.println
|
||||
|
@ -239,15 +239,32 @@ local function init(parent, id)
|
||||
---@todo radiation monitor
|
||||
IndicatorLight{parent=annunciator,label="Radiation Monitor",colors=cpair(colors.green,colors.gray)}
|
||||
IndicatorLight{parent=annunciator,label="Radiation Alarm",colors=cpair(colors.red,colors.gray),flash=true,period=period.BLINK_250_MS}
|
||||
DataIndicator{parent=main,x=34,y=51,label="",format="%10.1f",value=0,unit="mSv/h",lu_colors=lu_cpair,width=18,fg_bg=stat_fg_bg}
|
||||
DataIndicator{parent=main,x=22,y=22,label="",format="%3.2f",value=0,unit="mSv/h",lu_colors=lu_cpair,width=11,fg_bg=stat_fg_bg}
|
||||
|
||||
-- reactor controls --
|
||||
|
||||
HazardButton{parent=main,x=2,y=44,text="START",accent=colors.lightBlue,callback=unit.start,fg_bg=scram_fg_bg}
|
||||
HazardButton{parent=main,x=12,y=44,text="SCRAM",accent=colors.yellow,callback=unit.scram,fg_bg=scram_fg_bg}
|
||||
HazardButton{parent=main,x=22,y=44,text="RESET",accent=colors.red,callback=unit.reset_rps,fg_bg=scram_fg_bg}
|
||||
local dis_colors = cpair(colors.white, colors.lightGray)
|
||||
|
||||
local burn_control = Div{parent=main,x=12,y=40,width=19,height=3,fg_bg=cpair(colors.gray,colors.white)}
|
||||
local start = HazardButton{parent=main,x=2,y=26,text="START",accent=colors.lightBlue,dis_colors=dis_colors,callback=unit.start,fg_bg=scram_fg_bg}
|
||||
local scram = HazardButton{parent=main,x=12,y=26,text="SCRAM",accent=colors.yellow,dis_colors=dis_colors,callback=unit.scram,fg_bg=scram_fg_bg}
|
||||
local reset = HazardButton{parent=main,x=22,y=26,text="RESET",accent=colors.red,dis_colors=dis_colors,callback=unit.reset_rps,fg_bg=scram_fg_bg}
|
||||
|
||||
unit.start_ack = start.on_response
|
||||
unit.scram_ack = scram.on_response
|
||||
unit.reset_rps_ack = reset.on_response
|
||||
|
||||
local function start_button_en_check()
|
||||
if (unit.reactor_data ~= nil) and (unit.reactor_data.mek_status ~= nil) then
|
||||
local can_start = (not unit.reactor_data.mek_status.status) and (not unit.reactor_data.rps_tripped)
|
||||
if can_start then start.enable() else start.disable() end
|
||||
end
|
||||
end
|
||||
|
||||
r_ps.subscribe("status", start_button_en_check)
|
||||
r_ps.subscribe("rps_tripped", start_button_en_check)
|
||||
r_ps.subscribe("rps_tripped", function (active) if active then reset.enable() else reset.disable() end end)
|
||||
|
||||
local burn_control = Div{parent=main,x=2,y=22,width=19,height=3,fg_bg=cpair(colors.gray,colors.white)}
|
||||
local burn_rate = SpinboxNumeric{parent=burn_control,x=2,y=1,whole_num_precision=4,fractional_precision=1,arrow_fg_bg=cpair(colors.gray,colors.white),fg_bg=cpair(colors.black,colors.white)}
|
||||
TextBox{parent=burn_control,x=9,y=2,text="mB/t"}
|
||||
|
||||
@ -280,10 +297,9 @@ local function init(parent, id)
|
||||
}
|
||||
|
||||
---@todo waste selection
|
||||
local waste_sel_f = function (s) print("waste: " .. s) end
|
||||
local waste_sel = Div{parent=main,x=2,y=48,width=29,height=2,fg_bg=cpair(colors.black, colors.white)}
|
||||
|
||||
MultiButton{parent=waste_sel,x=1,y=1,options=opts,callback=waste_sel_f,min_width=6,fg_bg=cpair(colors.black, colors.white)}
|
||||
MultiButton{parent=waste_sel,x=1,y=1,options=opts,callback=unit.set_waste,min_width=6,fg_bg=cpair(colors.black, colors.white)}
|
||||
TextBox{parent=waste_sel,text="Waste Processing",alignment=TEXT_ALIGN.CENTER,x=1,y=1,height=1}
|
||||
|
||||
---@fixme test code
|
||||
|
@ -163,6 +163,11 @@ function element.new(args)
|
||||
function protected.on_update(...)
|
||||
end
|
||||
|
||||
-- callback on control press responses
|
||||
---@param result any
|
||||
function protected.response_callback(result)
|
||||
end
|
||||
|
||||
-- get value
|
||||
function protected.get_value()
|
||||
return protected.value
|
||||
@ -354,6 +359,12 @@ function element.new(args)
|
||||
protected.on_update(...)
|
||||
end
|
||||
|
||||
-- on a control request response
|
||||
---@param result any
|
||||
function public.on_response(result)
|
||||
protected.response_callback(result)
|
||||
end
|
||||
|
||||
-- VISIBILITY --
|
||||
|
||||
-- show the element
|
||||
|
@ -8,6 +8,7 @@ local element = require("graphics.element")
|
||||
---@class hazard_button_args
|
||||
---@field text string text to show on button
|
||||
---@field accent color accent color for hazard border
|
||||
---@field dis_colors? cpair text color and border color when disabled
|
||||
---@field callback function function to call on touch
|
||||
---@field parent graphics_element
|
||||
---@field id? string element id
|
||||
@ -62,6 +63,82 @@ local function hazard_button(args)
|
||||
e.window.write("\x99\x98\x98\x98\x98\x98\x98\x98\x99")
|
||||
end
|
||||
|
||||
-- on request timeout: recursively calls itself to double flash button text
|
||||
---@param n integer call count
|
||||
local function on_timeout(n)
|
||||
-- start at 0
|
||||
if n == nil then n = 0 end
|
||||
|
||||
if n == 0 then
|
||||
-- go back off
|
||||
e.window.setTextColor(args.fg_bg.fgd)
|
||||
e.window.setCursorPos(3, 2)
|
||||
e.window.write(args.text)
|
||||
end
|
||||
|
||||
if n >= 4 then
|
||||
-- done
|
||||
elseif n % 2 == 0 then
|
||||
-- toggle text color on after 0.25 seconds
|
||||
tcd.dispatch(0.25, function ()
|
||||
e.window.setTextColor(args.accent)
|
||||
e.window.setCursorPos(3, 2)
|
||||
e.window.write(args.text)
|
||||
on_timeout(n + 1)
|
||||
on_timeout(n + 1)
|
||||
end)
|
||||
elseif n % 1 then
|
||||
-- toggle text color off after 0.25 seconds
|
||||
tcd.dispatch(0.25, function ()
|
||||
e.window.setTextColor(args.fg_bg.fgd)
|
||||
e.window.setCursorPos(3, 2)
|
||||
e.window.write(args.text)
|
||||
on_timeout(n + 1)
|
||||
end)
|
||||
end
|
||||
end
|
||||
|
||||
-- blink routine for success indication
|
||||
local function on_success()
|
||||
e.window.setTextColor(args.fg_bg.fgd)
|
||||
e.window.setCursorPos(3, 2)
|
||||
e.window.write(args.text)
|
||||
end
|
||||
|
||||
-- blink routine for failure indication
|
||||
---@param n integer call count
|
||||
local function on_failure(n)
|
||||
-- start at 0
|
||||
if n == nil then n = 0 end
|
||||
|
||||
if n == 0 then
|
||||
-- go back off
|
||||
e.window.setTextColor(args.fg_bg.fgd)
|
||||
e.window.setCursorPos(3, 2)
|
||||
e.window.write(args.text)
|
||||
end
|
||||
|
||||
if n >= 2 then
|
||||
-- done
|
||||
elseif n % 2 == 0 then
|
||||
-- toggle text color on after 0.5 seconds
|
||||
tcd.dispatch(0.5, function ()
|
||||
e.window.setTextColor(args.accent)
|
||||
e.window.setCursorPos(3, 2)
|
||||
e.window.write(args.text)
|
||||
on_failure(n + 1)
|
||||
end)
|
||||
elseif n % 1 then
|
||||
-- toggle text color off after 0.25 seconds
|
||||
tcd.dispatch(0.25, function ()
|
||||
e.window.setTextColor(args.fg_bg.fgd)
|
||||
e.window.setCursorPos(3, 2)
|
||||
e.window.write(args.text)
|
||||
on_failure(n + 1)
|
||||
end)
|
||||
end
|
||||
end
|
||||
|
||||
-- handle touch
|
||||
---@param event monitor_touch monitor touch event
|
||||
---@diagnostic disable-next-line: unused-local
|
||||
@ -75,12 +152,25 @@ local function hazard_button(args)
|
||||
e.window.setCursorPos(3, 2)
|
||||
e.window.write(args.text)
|
||||
|
||||
-- restore text color after 1 second
|
||||
tcd.dispatch(1, function ()
|
||||
e.window.setTextColor(args.fg_bg.fgd)
|
||||
e.window.setCursorPos(3, 2)
|
||||
e.window.write(args.text)
|
||||
end)
|
||||
-- abort any other callbacks
|
||||
tcd.abort(on_timeout)
|
||||
tcd.abort(on_success)
|
||||
tcd.abort(on_failure)
|
||||
|
||||
-- 1.5 second timeout
|
||||
tcd.dispatch(1.5, on_timeout)
|
||||
end
|
||||
end
|
||||
|
||||
-- callback on request response
|
||||
---@param result boolean true for success, false for failure
|
||||
function e.response_callback(result)
|
||||
tcd.abort(on_timeout)
|
||||
|
||||
if result then
|
||||
on_success()
|
||||
else
|
||||
on_failure(0)
|
||||
end
|
||||
end
|
||||
|
||||
@ -90,8 +180,25 @@ local function hazard_button(args)
|
||||
if val then e.handle_touch(core.events.touch("", 1, 1)) end
|
||||
end
|
||||
|
||||
-- show the button as disabled
|
||||
function e.disable()
|
||||
if args.dis_colors then
|
||||
draw_border(args.dis_colors.color_a)
|
||||
e.window.setTextColor(args.dis_colors.color_b)
|
||||
e.window.setCursorPos(3, 2)
|
||||
e.window.write(args.text)
|
||||
end
|
||||
end
|
||||
|
||||
-- show the button as enabled
|
||||
function e.enable()
|
||||
draw_border(args.accent)
|
||||
e.window.setTextColor(args.fg_bg.fgd)
|
||||
e.window.setCursorPos(3, 2)
|
||||
e.window.write(args.text)
|
||||
end
|
||||
|
||||
-- initial draw of border
|
||||
---@todo disabling will change border
|
||||
draw_border(args.accent)
|
||||
|
||||
return e.get()
|
||||
|
@ -27,7 +27,7 @@ end
|
||||
---@param time number seconds
|
||||
---@param f function callback function
|
||||
function tcallbackdsp.dispatch_unique(time, f)
|
||||
-- ignore if already registered
|
||||
-- cancel if already registered
|
||||
for timer, entry in pairs(registry) do
|
||||
if entry.callback == f then
|
||||
-- found an instance of this function reference, abort it
|
||||
@ -49,6 +49,18 @@ function tcallbackdsp.dispatch_unique(time, f)
|
||||
-- log.debug(util.c("TCD: queued callback for ", f, " [timer: ", timer, "]"))
|
||||
end
|
||||
|
||||
-- abort a requested callback
|
||||
---@param f function callback function
|
||||
function tcallbackdsp.abort(f)
|
||||
for timer, entry in pairs(registry) do
|
||||
if entry.callback == f then
|
||||
-- cancel event and remove from registry (even if it fires it won't call)
|
||||
util.cancel_timer(timer)
|
||||
registry[timer] = nil
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- lookup a timer event and execute the callback if found
|
||||
---@param event integer timer event timer ID
|
||||
function tcallbackdsp.handle(event)
|
||||
|
@ -29,6 +29,7 @@ local CRD_S_CMDS = {
|
||||
}
|
||||
|
||||
local CRD_S_DATA = {
|
||||
CMD_ACK = 1
|
||||
}
|
||||
|
||||
coordinator.CRD_S_CMDS = CRD_S_CMDS
|
||||
@ -271,6 +272,12 @@ function coordinator.new_session(id, in_queue, out_queue, facility_units)
|
||||
end
|
||||
elseif message.qtype == mqueue.TYPE.DATA then
|
||||
-- instruction with body
|
||||
local cmd = message.message ---@type queue_data
|
||||
|
||||
if cmd.key == CRD_S_DATA.CMD_ACK then
|
||||
local ack = cmd.val ---@type coord_ack
|
||||
_send(SCADA_CRDN_TYPES.COMMAND_UNIT, { ack.cmd, ack.unit, ack.ack })
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -74,14 +74,12 @@ function plc.new_session(id, for_reactor, in_queue, out_queue)
|
||||
struct_req = (util.time() + 500),
|
||||
status_req = (util.time() + 500),
|
||||
scram_req = 0,
|
||||
enable_req = 0,
|
||||
burn_rate_req = 0,
|
||||
rps_reset_req = 0
|
||||
},
|
||||
-- command acknowledgements
|
||||
acks = {
|
||||
scram = true,
|
||||
enable = true,
|
||||
burn_rate = true,
|
||||
rps_reset = true
|
||||
},
|
||||
@ -355,7 +353,6 @@ function plc.new_session(id, for_reactor, in_queue, out_queue)
|
||||
-- enable acknowledgement
|
||||
local ack = _get_ack(pkt)
|
||||
if ack then
|
||||
self.acks.enable = true
|
||||
self.sDB.control_state = true
|
||||
elseif ack == false then
|
||||
log.debug(log_header .. "enable failed!")
|
||||
@ -537,8 +534,6 @@ function plc.new_session(id, for_reactor, in_queue, out_queue)
|
||||
local cmd = message.message
|
||||
if cmd == PLC_S_CMDS.ENABLE then
|
||||
-- enable reactor
|
||||
self.acks.enable = false
|
||||
self.retry_times.enable_req = util.time() + INITIAL_WAIT
|
||||
_send(RPLC_TYPES.RPS_ENABLE, {})
|
||||
elseif cmd == PLC_S_CMDS.SCRAM then
|
||||
-- SCRAM reactor
|
||||
@ -635,15 +630,6 @@ function plc.new_session(id, for_reactor, in_queue, out_queue)
|
||||
end
|
||||
end
|
||||
|
||||
-- enable request retry
|
||||
|
||||
if not self.acks.enable then
|
||||
if rtimes.enable_req - util.time() <= 0 then
|
||||
_send(RPLC_TYPES.RPS_ENABLE, {})
|
||||
rtimes.enable_req = util.time() + RETRY_PERIOD
|
||||
end
|
||||
end
|
||||
|
||||
-- burn rate request retry
|
||||
|
||||
if not self.acks.burn_rate then
|
||||
|
@ -14,6 +14,11 @@ local SV_Q_DATA = {
|
||||
CRDN_ACK = 7
|
||||
}
|
||||
|
||||
---@class coord_ack
|
||||
---@field unit integer
|
||||
---@field cmd integer
|
||||
---@field ack boolean
|
||||
|
||||
svqtypes.SV_Q_CMDS = SV_Q_CMDS
|
||||
svqtypes.SV_Q_DATA = SV_Q_DATA
|
||||
|
||||
|
@ -17,6 +17,7 @@ local SV_Q_DATA = svqtypes.SV_Q_DATA
|
||||
local PLC_S_CMDS = plc.PLC_S_CMDS
|
||||
local PLC_S_DATA = plc.PLC_S_DATA
|
||||
local CRD_S_CMDS = coordinator.CRD_S_CMDS
|
||||
local CRD_S_DATA = coordinator.CRD_S_DATA
|
||||
|
||||
local svsessions = {}
|
||||
|
||||
@ -70,7 +71,6 @@ local function _sv_handle_outq(session)
|
||||
|
||||
if cmd.key < SV_Q_DATA.__END_PLC_CMDS__ then
|
||||
-- PLC commands from coordinator
|
||||
local crdn_sid = session.instance.get_id()
|
||||
local plc_s = svsessions.get_reactor_session(cmd.val[1])
|
||||
|
||||
if plc_s ~= nil then
|
||||
@ -90,7 +90,11 @@ local function _sv_handle_outq(session)
|
||||
end
|
||||
else
|
||||
if cmd.key == SV_Q_DATA.CRDN_ACK then
|
||||
---@todo ack to be sent to coordinator
|
||||
-- ack to be sent to coordinator
|
||||
local crd_s = svsessions.get_coord_session()
|
||||
if crd_s ~= nil then
|
||||
crd_s.in_queue.push_data(CRD_S_DATA.CMD_ACK, cmd.val)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -13,7 +13,7 @@ local svsessions = require("supervisor.session.svsessions")
|
||||
local config = require("supervisor.config")
|
||||
local supervisor = require("supervisor.supervisor")
|
||||
|
||||
local SUPERVISOR_VERSION = "beta-v0.6.7"
|
||||
local SUPERVISOR_VERSION = "beta-v0.6.8"
|
||||
|
||||
local print = util.print
|
||||
local println = util.println
|
||||
|
Loading…
Reference in New Issue
Block a user