diff --git a/coordinator/sounder.lua b/coordinator/sounder.lua index 23fc702..e3b2051 100644 --- a/coordinator/sounder.lua +++ b/coordinator/sounder.lua @@ -76,30 +76,4 @@ function sounder.continue() return success end ---#region Test Functions - --- function sounder.test_1() add(1) play() end -- play tone T_340Hz_Int_2Hz --- function sounder.test_2() add(2) play() end -- play tone T_544Hz_440Hz_Alt --- function sounder.test_3() add(3) play() end -- play tone T_660Hz_Int_125ms --- function sounder.test_4() add(4) play() end -- play tone T_745Hz_Int_1Hz --- function sounder.test_5() add(5) play() end -- play tone T_800Hz_Int --- function sounder.test_6() add(6) play() end -- play tone T_800Hz_1000Hz_Alt --- function sounder.test_7() add(7) play() end -- play tone T_1000Hz_Int --- function sounder.test_8() add(8) play() end -- play tone T_1800Hz_Int_4Hz - --- function sounder.test_breach(active) test_alarms[ALARM.ContainmentBreach] = active end ---@param active boolean --- function sounder.test_rad(active) test_alarms[ALARM.ContainmentRadiation] = active end ---@param active boolean --- function sounder.test_lost(active) test_alarms[ALARM.ReactorLost] = active end ---@param active boolean --- function sounder.test_crit(active) test_alarms[ALARM.CriticalDamage] = active end ---@param active boolean --- function sounder.test_dmg(active) test_alarms[ALARM.ReactorDamage] = active end ---@param active boolean --- function sounder.test_overtemp(active) test_alarms[ALARM.ReactorOverTemp] = active end ---@param active boolean --- function sounder.test_hightemp(active) test_alarms[ALARM.ReactorHighTemp] = active end ---@param active boolean --- function sounder.test_wasteleak(active) test_alarms[ALARM.ReactorWasteLeak] = active end ---@param active boolean --- function sounder.test_highwaste(active) test_alarms[ALARM.ReactorHighWaste] = active end ---@param active boolean --- function sounder.test_rps(active) test_alarms[ALARM.RPSTransient] = active end ---@param active boolean --- function sounder.test_rcs(active) test_alarms[ALARM.RCSTransient] = active end ---@param active boolean --- function sounder.test_turbinet(active) test_alarms[ALARM.TurbineTrip] = active end ---@param active boolean - ---#endregion - return sounder diff --git a/graphics/elements/controls/app.lua b/graphics/elements/controls/app.lua index ae831da..226946c 100644 --- a/graphics/elements/controls/app.lua +++ b/graphics/elements/controls/app.lua @@ -1,4 +1,4 @@ --- Button Graphics Element +-- App Button Graphics Element local tcd = require("scada-common.tcd") @@ -40,7 +40,7 @@ local function app_button(args) e.window.setCursorPos(math.floor((e.frame.w - string.len(args.title)) / 2) + 1, 4) e.window.write(args.title) - -- draw the button + -- draw the app button local function draw() local fgd = args.app_fg_bg.fgd local bkg = args.app_fg_bg.bkg @@ -75,7 +75,7 @@ local function app_button(args) e.window.write(args.text) end - -- draw the button as pressed (if active_fg_bg set) + -- draw the app button as pressed (if active_fg_bg set) local function show_pressed() if e.enabled and args.active_fg_bg ~= nil then e.value = true @@ -85,7 +85,7 @@ local function app_button(args) end end - -- draw the button as unpressed (if active_fg_bg set) + -- draw the app button as unpressed (if active_fg_bg set) local function show_unpressed() if e.enabled and args.active_fg_bg ~= nil then e.value = false @@ -115,7 +115,7 @@ local function app_button(args) end end - -- set the value (true simulates pressing the button) + -- set the value (true simulates pressing the app button) ---@param val boolean new value function e.set_value(val) if val then e.handle_mouse(core.events.mouse_generic(core.events.CLICK_TYPE.UP, 1, 1)) end diff --git a/pocket/iocontrol.lua b/pocket/iocontrol.lua index 1bf3046..30645ae 100644 --- a/pocket/iocontrol.lua +++ b/pocket/iocontrol.lua @@ -1,5 +1,5 @@ -- --- I/O Control for Pocket Integration with Supervisor & Coordinator +-- I/O Control for Pocket Integration with Supervisor & Coordinator -- local psil = require("scada-common.psil") diff --git a/pocket/pocket.lua b/pocket/pocket.lua index 950f8f7..65b286a 100644 --- a/pocket/pocket.lua +++ b/pocket/pocket.lua @@ -155,18 +155,18 @@ function pocket.comms(version, nic, pkt_channel, svr_channel, crd_channel, range end end - -- supervisor test alarm tones by tone - ---@param id tone_id|0 tone ID, or 0 to stop all - ---@param state boolean tone state - function public.diag__set_alarm_tone(id, state) - if self.sv.linked then _send_sv(SCADA_MGMT_TYPE.DIAG_TONE_SET, { id, state }) end - end - -- supervisor get active alarm tones function public.diag__get_alarm_tones() if self.sv.linked then _send_sv(SCADA_MGMT_TYPE.DIAG_TONE_GET, {}) end end + -- supervisor test alarm tones by tone + ---@param id TONE|0 tone ID, or 0 to stop all + ---@param state boolean tone state + function public.diag__set_alarm_tone(id, state) + if self.sv.linked then _send_sv(SCADA_MGMT_TYPE.DIAG_TONE_SET, { id, state }) end + end + -- supervisor test alarm tones by alarm ---@param id ALARM|0 alarm ID, 0 to stop all ---@param state boolean alarm state diff --git a/pocket/ui/pages/diag_page.lua b/pocket/ui/pages/diag_page.lua index 9820a6a..38d9368 100644 --- a/pocket/ui/pages/diag_page.lua +++ b/pocket/ui/pages/diag_page.lua @@ -1,5 +1,3 @@ --- local style = require("pocket.ui.style") - local iocontrol = require("pocket.iocontrol") local core = require("graphics.core") diff --git a/rtu/rtu.lua b/rtu/rtu.lua index a5ac885..4c92afc 100644 --- a/rtu/rtu.lua +++ b/rtu/rtu.lua @@ -467,7 +467,7 @@ function rtu.comms(version, nic, rtu_channel, svr_channel, range, conn_watchdog) local s = sounders[i] ---@type rtu_speaker_sounder -- set tone states - for id = 1, #states do s.stream.set_active(id, states[id]) end + for id = 1, #states do s.stream.set_active(id, states[id] == true) end end end else diff --git a/scada-common/audio.lua b/scada-common/audio.lua index 29c8ab5..32dfb57 100644 --- a/scada-common/audio.lua +++ b/scada-common/audio.lua @@ -14,8 +14,8 @@ local _05s_SAMPLES = 24000 -- half a second worth of samples ---@class audio local audio = {} ----@enum tone_id -local TONES = { +---@enum TONE +local TONE = { T_340Hz_Int_2Hz = 1, T_544Hz_440Hz_Alt = 2, T_660Hz_Int_125ms = 3, @@ -26,7 +26,7 @@ local TONES = { T_1800Hz_Int_4Hz = 8 } -audio.TONES = TONES +audio.TONE = TONE local tone_data = { { {}, {}, {}, {} }, -- 340Hz @ 2Hz Intermittent @@ -251,7 +251,7 @@ function audio.new_stream() local public = {} -- add a tone to the output buffer - ---@param index tone_id tone ID + ---@param index TONE tone ID ---@param active boolean active state function public.set_active(index, active) if self.tone_active[index] ~= nil then @@ -261,7 +261,7 @@ function audio.new_stream() end -- check if a tone is active - ---@param index tone_id tone index + ---@param index TONE tone index function public.is_active(index) if self.tone_active[index] then return self.tone_active[index] end return false diff --git a/supervisor/facility.lua b/supervisor/facility.lua index 1564ae9..9735cd9 100644 --- a/supervisor/facility.lua +++ b/supervisor/facility.lua @@ -9,7 +9,7 @@ local unit = require("supervisor.unit") local rsctl = require("supervisor.session.rsctl") -local TONES = audio.TONES +local TONE = audio.TONE local ALARM = types.ALARM local PRIO = types.ALARM_PRIORITY @@ -783,13 +783,8 @@ function facility.new(num_reactors, cooling_conf) local alarms = { false, false, false, false, false, false, false, false, false, false, false, false } - for i = 1, #self.tone_states do - -- reset tone states before re-evaluting - self.tone_states[i] = false - - -- clear testing tones if we aren't using them - if (not allow_test) and (not self.test_tone_reset) then self.test_tone_states[i] = false end - end + -- reset tone states before re-evaluting + for i = 1, #self.tone_states do self.tone_states[i] = false end if allow_test then alarms = self.test_alarm_states @@ -799,64 +794,58 @@ function facility.new(num_reactors, cooling_conf) local u = self.units[i] ---@type reactor_unit for id, alarm in pairs(u.get_alarms()) do alarms[id] = alarms[id] or (alarm == ALARM_STATE.TRIPPED) - - -- clear testing alarms if we aren't using them - if not self.test_tone_reset then self.test_alarm_states[id] = false end end end - self.test_tone_reset = true - end - - -- flag that tones were reset to notify diagnostic accessor - if not allow_test then - self.test_tone_set = false - self.test_tone_reset = true + if not self.test_tone_reset then + -- clear testing alarms if we aren't using them + for i = 1, #self.test_alarm_states do self.test_alarm_states[i] = false end + end end -- Evaluate Alarms -- -- containment breach is worst case CRITICAL alarm, this takes priority if alarms[ALARM.ContainmentBreach] then - self.tone_states[TONES.T_1800Hz_Int_4Hz] = true + self.tone_states[TONE.T_1800Hz_Int_4Hz] = true else -- critical damage is highest priority CRITICAL level alarm if alarms[ALARM.CriticalDamage] then - self.tone_states[TONES.T_660Hz_Int_125ms] = true + self.tone_states[TONE.T_660Hz_Int_125ms] = true else -- EMERGENCY level alarms + URGENT over temp if alarms[ALARM.ReactorDamage] or alarms[ALARM.ReactorOverTemp] or alarms[ALARM.ReactorWasteLeak] then - self.tone_states[TONES.T_544Hz_440Hz_Alt] = true + self.tone_states[TONE.T_544Hz_440Hz_Alt] = true -- URGENT level turbine trip elseif alarms[ALARM.TurbineTrip] then - self.tone_states[TONES.T_745Hz_Int_1Hz] = true + self.tone_states[TONE.T_745Hz_Int_1Hz] = true -- URGENT level reactor lost elseif alarms[ALARM.ReactorLost] then - self.tone_states[TONES.T_340Hz_Int_2Hz] = true + self.tone_states[TONE.T_340Hz_Int_2Hz] = true -- TIMELY level alarms elseif alarms[ALARM.ReactorHighTemp] or alarms[ALARM.ReactorHighWaste] or alarms[ALARM.RCSTransient] then - self.tone_states[TONES.T_800Hz_Int] = true + self.tone_states[TONE.T_800Hz_Int] = true end end -- check RPS transient URGENT level alarm if alarms[ALARM.RPSTransient] then - self.tone_states[TONES.T_1000Hz_Int] = true + self.tone_states[TONE.T_1000Hz_Int] = true -- disable really painful audio combination - self.tone_states[TONES.T_340Hz_Int_2Hz] = false + self.tone_states[TONE.T_340Hz_Int_2Hz] = false end end -- radiation is a big concern, always play this CRITICAL level alarm if active if alarms[ALARM.ContainmentRadiation] then - self.tone_states[TONES.T_800Hz_1000Hz_Alt] = true + self.tone_states[TONE.T_800Hz_1000Hz_Alt] = true -- we are going to disable the RPS trip alarm audio due to conflict, and if it was enabled -- then we can re-enable the reactor lost alarm audio since it doesn't painfully combine with this one - if self.tone_states[TONES.T_1000Hz_Int] and alarms[ALARM.ReactorLost] then self.tone_states[TONES.T_340Hz_Int_2Hz] = true end + if self.tone_states[TONE.T_1000Hz_Int] and alarms[ALARM.ReactorLost] then self.tone_states[TONE.T_340Hz_Int_2Hz] = true end -- it sounds *really* bad if this is in conjunction with these other tones, so disable them - self.tone_states[TONES.T_745Hz_Int_1Hz] = false - self.tone_states[TONES.T_800Hz_Int] = false - self.tone_states[TONES.T_1000Hz_Int] = false + self.tone_states[TONE.T_745Hz_Int_1Hz] = false + self.tone_states[TONE.T_800Hz_Int] = false + self.tone_states[TONE.T_1000Hz_Int] = false end -- add to tone states if testing is active @@ -864,6 +853,17 @@ function facility.new(num_reactors, cooling_conf) for i = 1, #self.tone_states do self.tone_states[i] = self.tone_states[i] or self.test_tone_states[i] end + + self.test_tone_reset = false + else + if not self.test_tone_reset then + -- clear testing tones if we aren't using them + for i = 1, #self.test_tone_states do self.test_tone_states[i] = false end + end + + -- flag that tones were reset + self.test_tone_set = false + self.test_tone_reset = true end end @@ -1009,7 +1009,7 @@ function facility.new(num_reactors, cooling_conf) -- DIAGNOSTIC TESTING -- -- attempt to set a test tone state - ---@param id tone_id|0 tone ID or 0 to disable all + ---@param id TONE|0 tone ID or 0 to disable all ---@param state boolean state ---@return boolean allow_testing, table test_tone_states function public.diag_set_test_tone(id, state) diff --git a/supervisor/session/pocket.lua b/supervisor/session/pocket.lua index 7637cb5..30ca7eb 100644 --- a/supervisor/session/pocket.lua +++ b/supervisor/session/pocket.lua @@ -142,7 +142,7 @@ function pocket.new_session(id, s_addr, in_queue, out_queue, timeout, facility, if type(pkt.data[1]) == "number" and type(pkt.data[2]) == "boolean" then valid = true - -- try to set tone states, then send back if testing is allowed + -- try to set tone states, then send back if testing is allowed local allow_testing, test_tone_states = facility.diag_set_test_tone(pkt.data[1], pkt.data[2]) _send_mgmt(SCADA_MGMT_TYPE.DIAG_TONE_SET, { allow_testing, test_tone_states }) else @@ -165,7 +165,7 @@ function pocket.new_session(id, s_addr, in_queue, out_queue, timeout, facility, if type(pkt.data[1]) == "number" and type(pkt.data[2]) == "boolean" then valid = true - -- try to set alarm states, then send back if testing is allowed + -- try to set alarm states, then send back if testing is allowed local allow_testing, test_alarm_states = facility.diag_set_test_alarm(pkt.data[1], pkt.data[2]) _send_mgmt(SCADA_MGMT_TYPE.DIAG_ALARM_SET, { allow_testing, test_alarm_states }) else diff --git a/supervisor/unit.lua b/supervisor/unit.lua index cae423b..c0472cc 100644 --- a/supervisor/unit.lua +++ b/supervisor/unit.lua @@ -725,14 +725,14 @@ function unit.new(reactor_id, num_boilers, num_turbines) -- can't be disconnected if self.plc_i == nil then return false end + -- reactor must be stopped and RPS can't be tripped + if self.plc_i.get_status().status or self.plc_i.get_db().rps_tripped then return false end + -- alarms must be inactive and not tripping for _, alarm in pairs(self.alarms) do if not (alarm.state == AISTATE.INACTIVE or alarm.state == AISTATE.RING_BACK) then return false end end - -- reactor must be stopped and RPS can't be tripped - if self.plc_i.get_status().status or self.plc_i.get_db().rps_tripped then return false end - return true end