mirror of
https://github.com/MikaylaFischler/cc-mek-scada.git
synced 2024-08-30 18:22:34 +00:00
#307 PLC integration with new config storage
This commit is contained in:
parent
b1446637ad
commit
bfa24b3665
@ -5,8 +5,8 @@
|
|||||||
local types = require("scada-common.types")
|
local types = require("scada-common.types")
|
||||||
local util = require("scada-common.util")
|
local util = require("scada-common.util")
|
||||||
|
|
||||||
local config = require("reactor-plc.config")
|
|
||||||
local databus = require("reactor-plc.databus")
|
local databus = require("reactor-plc.databus")
|
||||||
|
local plc = require("reactor-plc.plc")
|
||||||
|
|
||||||
local style = require("reactor-plc.panel.style")
|
local style = require("reactor-plc.panel.style")
|
||||||
|
|
||||||
@ -86,7 +86,7 @@ local function init(panel)
|
|||||||
local active = LED{parent=status,x=2,width=12,label="RCT ACTIVE",colors=ind_grn}
|
local active = LED{parent=status,x=2,width=12,label="RCT ACTIVE",colors=ind_grn}
|
||||||
|
|
||||||
-- only show emergency coolant LED if emergency coolant is configured for this device
|
-- only show emergency coolant LED if emergency coolant is configured for this device
|
||||||
if type(config.EMERGENCY_COOL) == "table" then
|
if plc.config.EmerCoolEnable then
|
||||||
local emer_cool = LED{parent=status,x=2,width=14,label="EMER COOLANT",colors=cpair(colors.yellow,colors.yellow_off)}
|
local emer_cool = LED{parent=status,x=2,width=14,label="EMER COOLANT",colors=cpair(colors.yellow,colors.yellow_off)}
|
||||||
emer_cool.register(databus.ps, "emer_cool", emer_cool.update)
|
emer_cool.register(databus.ps, "emer_cool", emer_cool.update)
|
||||||
end
|
end
|
||||||
|
@ -26,14 +26,58 @@ local RPS_LIMITS = const.RPS_LIMITS
|
|||||||
local PCALL_SCRAM_MSG = "pcall: Scram requires the reactor to be active."
|
local PCALL_SCRAM_MSG = "pcall: Scram requires the reactor to be active."
|
||||||
local PCALL_START_MSG = "pcall: Reactor is already active."
|
local PCALL_START_MSG = "pcall: Reactor is already active."
|
||||||
|
|
||||||
|
---@type plc_config
|
||||||
|
local config = {}
|
||||||
|
|
||||||
|
plc.config = config
|
||||||
|
|
||||||
|
-- load the PLC configuration
|
||||||
|
function plc.load_config()
|
||||||
|
config.Networked = settings.get("Networked")
|
||||||
|
config.UnitID = settings.get("UnitID")
|
||||||
|
config.EmerCoolEnable = settings.get("EmerCoolEnable")
|
||||||
|
config.EmerCoolSide = settings.get("EmerCoolSide")
|
||||||
|
config.EmerCoolColor = settings.get("EmerCoolColor")
|
||||||
|
config.SVR_Channel = settings.get("SVR_Channel")
|
||||||
|
config.PLC_Channel = settings.get("PLC_Channel")
|
||||||
|
config.ConnTimeout = settings.get("ConnTimeout")
|
||||||
|
config.TrustedRange = settings.get("TrustedRange")
|
||||||
|
config.AuthKey = settings.get("AuthKey")
|
||||||
|
config.LogMode = settings.get("LogMode")
|
||||||
|
config.LogPath = settings.get("LogPath")
|
||||||
|
config.LogDebug = settings.get("LogDebug")
|
||||||
|
|
||||||
|
local cfv = util.new_validator()
|
||||||
|
|
||||||
|
cfv.assert_type_bool(config.Networked)
|
||||||
|
cfv.assert_type_int(config.UnitID)
|
||||||
|
cfv.assert_type_bool(config.EmerCoolEnable)
|
||||||
|
cfv.assert_channel(config.SVR_Channel)
|
||||||
|
cfv.assert_channel(config.PLC_Channel)
|
||||||
|
cfv.assert_type_int(config.ConnTimeout)
|
||||||
|
cfv.assert_min(config.ConnTimeout, 2)
|
||||||
|
cfv.assert_type_num(config.TrustedRange)
|
||||||
|
cfv.assert_type_str(config.AuthKey)
|
||||||
|
cfv.assert_type_int(config.LogMode)
|
||||||
|
cfv.assert_type_str(config.LogPath)
|
||||||
|
cfv.assert_type_bool(config.LogDebug)
|
||||||
|
|
||||||
|
-- check emergency coolant configuration if enabled
|
||||||
|
if config.EmerCoolEnable then
|
||||||
|
cfv.assert_eq(rsio.is_valid_side(config.EmerCoolSide), true)
|
||||||
|
cfv.assert_eq(config.EmerCoolColor == nil or rsio.is_color(config.EmerCoolColor), true)
|
||||||
|
end
|
||||||
|
|
||||||
|
return cfv.valid()
|
||||||
|
end
|
||||||
|
|
||||||
-- RPS: Reactor Protection System<br>
|
-- RPS: Reactor Protection System<br>
|
||||||
-- identifies dangerous states and SCRAMs reactor if warranted<br>
|
-- identifies dangerous states and SCRAMs reactor if warranted<br>
|
||||||
-- autonomous from main SCADA supervisor/coordinator control
|
-- autonomous from main SCADA supervisor/coordinator control
|
||||||
---@nodiscard
|
---@nodiscard
|
||||||
---@param reactor table
|
---@param reactor table
|
||||||
---@param is_formed boolean
|
---@param is_formed boolean
|
||||||
---@param emer_cool nil|table emergency coolant configuration
|
function plc.rps_init(reactor, is_formed)
|
||||||
function plc.rps_init(reactor, is_formed, emer_cool)
|
|
||||||
local state_keys = {
|
local state_keys = {
|
||||||
high_dmg = 1,
|
high_dmg = 1,
|
||||||
high_temp = 2,
|
high_temp = 2,
|
||||||
@ -73,22 +117,22 @@ function plc.rps_init(reactor, is_formed, emer_cool)
|
|||||||
---@param state boolean true to enable emergency coolant, false to disable
|
---@param state boolean true to enable emergency coolant, false to disable
|
||||||
local function _set_emer_cool(state)
|
local function _set_emer_cool(state)
|
||||||
-- check if this was configured: if it's a table, fields have already been validated.
|
-- check if this was configured: if it's a table, fields have already been validated.
|
||||||
if type(emer_cool) == "table" then
|
if config.EmerCoolEnable then
|
||||||
local level = rsio.digital_write_active(rsio.IO.U_EMER_COOL, state)
|
local level = rsio.digital_write_active(rsio.IO.U_EMER_COOL, state)
|
||||||
|
|
||||||
if level ~= false then
|
if level ~= false then
|
||||||
if rsio.is_color(emer_cool.color) then
|
if rsio.is_color(config.EmerCoolColor) then
|
||||||
local output = rs.getBundledOutput(emer_cool.side)
|
local output = rs.getBundledOutput(config.EmerCoolSide)
|
||||||
|
|
||||||
if rsio.digital_write(level) then
|
if rsio.digital_write(level) then
|
||||||
output = colors.combine(output, emer_cool.color)
|
output = colors.combine(output, config.EmerCoolColor)
|
||||||
else
|
else
|
||||||
output = colors.subtract(output, emer_cool.color)
|
output = colors.subtract(output, config.EmerCoolColor)
|
||||||
end
|
end
|
||||||
|
|
||||||
rs.setBundledOutput(emer_cool.side, output)
|
rs.setBundledOutput(config.EmerCoolSide, output)
|
||||||
else
|
else
|
||||||
rs.setOutput(emer_cool.side, rsio.digital_write(level))
|
rs.setOutput(config.EmerCoolSide, rsio.digital_write(level))
|
||||||
end
|
end
|
||||||
|
|
||||||
if state ~= self.emer_cool_active then
|
if state ~= self.emer_cool_active then
|
||||||
@ -443,16 +487,12 @@ end
|
|||||||
|
|
||||||
-- Reactor PLC Communications
|
-- Reactor PLC Communications
|
||||||
---@nodiscard
|
---@nodiscard
|
||||||
---@param id integer reactor ID
|
|
||||||
---@param version string PLC version
|
---@param version string PLC version
|
||||||
---@param nic nic network interface device
|
---@param nic nic network interface device
|
||||||
---@param plc_channel integer PLC comms channel
|
|
||||||
---@param svr_channel integer supervisor server channel
|
|
||||||
---@param range integer trusted device connection range
|
|
||||||
---@param reactor table reactor device
|
---@param reactor table reactor device
|
||||||
---@param rps rps RPS reference
|
---@param rps rps RPS reference
|
||||||
---@param conn_watchdog watchdog watchdog reference
|
---@param conn_watchdog watchdog watchdog reference
|
||||||
function plc.comms(id, version, nic, plc_channel, svr_channel, range, reactor, rps, conn_watchdog)
|
function plc.comms(version, nic, reactor, rps, conn_watchdog)
|
||||||
local self = {
|
local self = {
|
||||||
sv_addr = comms.BROADCAST,
|
sv_addr = comms.BROADCAST,
|
||||||
seq_num = 0,
|
seq_num = 0,
|
||||||
@ -466,13 +506,13 @@ function plc.comms(id, version, nic, plc_channel, svr_channel, range, reactor, r
|
|||||||
max_burn_rate = nil
|
max_burn_rate = nil
|
||||||
}
|
}
|
||||||
|
|
||||||
comms.set_trusted_range(range)
|
comms.set_trusted_range(config.TrustedRange)
|
||||||
|
|
||||||
-- PRIVATE FUNCTIONS --
|
-- PRIVATE FUNCTIONS --
|
||||||
|
|
||||||
-- configure network channels
|
-- configure network channels
|
||||||
nic.closeAll()
|
nic.closeAll()
|
||||||
nic.open(plc_channel)
|
nic.open(config.PLC_Channel)
|
||||||
|
|
||||||
-- send an RPLC packet
|
-- send an RPLC packet
|
||||||
---@param msg_type RPLC_TYPE
|
---@param msg_type RPLC_TYPE
|
||||||
@ -481,10 +521,10 @@ function plc.comms(id, version, nic, plc_channel, svr_channel, range, reactor, r
|
|||||||
local s_pkt = comms.scada_packet()
|
local s_pkt = comms.scada_packet()
|
||||||
local r_pkt = comms.rplc_packet()
|
local r_pkt = comms.rplc_packet()
|
||||||
|
|
||||||
r_pkt.make(id, msg_type, msg)
|
r_pkt.make(config.UnitID, msg_type, msg)
|
||||||
s_pkt.make(self.sv_addr, self.seq_num, PROTOCOL.RPLC, r_pkt.raw_sendable())
|
s_pkt.make(self.sv_addr, self.seq_num, PROTOCOL.RPLC, r_pkt.raw_sendable())
|
||||||
|
|
||||||
nic.transmit(svr_channel, plc_channel, s_pkt)
|
nic.transmit(config.SVR_Channel, config.PLC_Channel, s_pkt)
|
||||||
self.seq_num = self.seq_num + 1
|
self.seq_num = self.seq_num + 1
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -498,7 +538,7 @@ function plc.comms(id, version, nic, plc_channel, svr_channel, range, reactor, r
|
|||||||
m_pkt.make(msg_type, msg)
|
m_pkt.make(msg_type, msg)
|
||||||
s_pkt.make(self.sv_addr, self.seq_num, PROTOCOL.SCADA_MGMT, m_pkt.raw_sendable())
|
s_pkt.make(self.sv_addr, self.seq_num, PROTOCOL.SCADA_MGMT, m_pkt.raw_sendable())
|
||||||
|
|
||||||
nic.transmit(svr_channel, plc_channel, s_pkt)
|
nic.transmit(config.SVR_Channel, config.PLC_Channel, s_pkt)
|
||||||
self.seq_num = self.seq_num + 1
|
self.seq_num = self.seq_num + 1
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -673,7 +713,7 @@ function plc.comms(id, version, nic, plc_channel, svr_channel, range, reactor, r
|
|||||||
|
|
||||||
-- attempt to establish link with supervisor
|
-- attempt to establish link with supervisor
|
||||||
function public.send_link_req()
|
function public.send_link_req()
|
||||||
_send_mgmt(MGMT_TYPE.ESTABLISH, { comms.version, version, DEVICE_TYPE.PLC, id })
|
_send_mgmt(MGMT_TYPE.ESTABLISH, { comms.version, version, DEVICE_TYPE.PLC, config.UnitID })
|
||||||
end
|
end
|
||||||
|
|
||||||
-- send live status information
|
-- send live status information
|
||||||
@ -769,7 +809,7 @@ function plc.comms(id, version, nic, plc_channel, svr_channel, range, reactor, r
|
|||||||
local src_addr = packet.scada_frame.src_addr()
|
local src_addr = packet.scada_frame.src_addr()
|
||||||
|
|
||||||
-- handle packets now that we have prints setup
|
-- handle packets now that we have prints setup
|
||||||
if l_chan == plc_channel then
|
if l_chan == config.PLC_Channel then
|
||||||
-- check sequence number
|
-- check sequence number
|
||||||
if self.r_seq_num == nil then
|
if self.r_seq_num == nil then
|
||||||
self.r_seq_num = packet.scada_frame.seq_num()
|
self.r_seq_num = packet.scada_frame.seq_num()
|
||||||
|
@ -10,52 +10,40 @@ local log = require("scada-common.log")
|
|||||||
local mqueue = require("scada-common.mqueue")
|
local mqueue = require("scada-common.mqueue")
|
||||||
local network = require("scada-common.network")
|
local network = require("scada-common.network")
|
||||||
local ppm = require("scada-common.ppm")
|
local ppm = require("scada-common.ppm")
|
||||||
local rsio = require("scada-common.rsio")
|
|
||||||
local util = require("scada-common.util")
|
local util = require("scada-common.util")
|
||||||
|
|
||||||
local config = require("reactor-plc.config")
|
local configure = require("reactor-plc.configure")
|
||||||
local databus = require("reactor-plc.databus")
|
local databus = require("reactor-plc.databus")
|
||||||
local plc = require("reactor-plc.plc")
|
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.5.10"
|
local R_PLC_VERSION = "v1.6.0"
|
||||||
|
|
||||||
local println = util.println
|
local println = util.println
|
||||||
local println_ts = util.println_ts
|
local println_ts = util.println_ts
|
||||||
|
|
||||||
----------------------------------------
|
----------------------------------------
|
||||||
-- config validation
|
-- get configuration
|
||||||
----------------------------------------
|
----------------------------------------
|
||||||
|
|
||||||
local cfv = util.new_validator()
|
if not plc.load_config() then
|
||||||
|
-- try to reconfigure (user action)
|
||||||
cfv.assert_type_bool(config.NETWORKED)
|
local success, error = configure.configure(true)
|
||||||
cfv.assert_type_int(config.REACTOR_ID)
|
if success then
|
||||||
cfv.assert_channel(config.SVR_CHANNEL)
|
assert(plc.load_config(), "failed to load valid reactor PLC configuration")
|
||||||
cfv.assert_channel(config.PLC_CHANNEL)
|
else
|
||||||
cfv.assert_type_int(config.TRUSTED_RANGE)
|
assert(success, "reactor PLC configuration error: " .. error)
|
||||||
cfv.assert_type_num(config.COMMS_TIMEOUT)
|
|
||||||
cfv.assert_min(config.COMMS_TIMEOUT, 2)
|
|
||||||
cfv.assert_type_str(config.LOG_PATH)
|
|
||||||
cfv.assert_type_int(config.LOG_MODE)
|
|
||||||
|
|
||||||
assert(cfv.valid(), "bad config file: missing/invalid fields")
|
|
||||||
|
|
||||||
-- check emergency coolant configuration
|
|
||||||
if type(config.EMERGENCY_COOL) == "table" then
|
|
||||||
if not rsio.is_valid_side(config.EMERGENCY_COOL.side) then
|
|
||||||
assert(false, "bad config file: emergency coolant side unrecognized")
|
|
||||||
elseif config.EMERGENCY_COOL.color ~= nil and not rsio.is_color(config.EMERGENCY_COOL.color) then
|
|
||||||
assert(false, "bad config file: emergency coolant invalid redstone channel color provided")
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
local config = plc.config
|
||||||
|
|
||||||
----------------------------------------
|
----------------------------------------
|
||||||
-- log init
|
-- log init
|
||||||
----------------------------------------
|
----------------------------------------
|
||||||
|
|
||||||
log.init(config.LOG_PATH, config.LOG_MODE, config.LOG_DEBUG == true)
|
log.init(config.LogPath, config.LogMode, config.LogDebug)
|
||||||
|
|
||||||
log.info("========================================")
|
log.info("========================================")
|
||||||
log.info("BOOTING reactor-plc.startup " .. R_PLC_VERSION)
|
log.info("BOOTING reactor-plc.startup " .. R_PLC_VERSION)
|
||||||
@ -75,21 +63,21 @@ local function main()
|
|||||||
|
|
||||||
-- record firmware versions and ID
|
-- record firmware versions and ID
|
||||||
databus.tx_versions(R_PLC_VERSION, comms.version)
|
databus.tx_versions(R_PLC_VERSION, comms.version)
|
||||||
databus.tx_id(config.REACTOR_ID)
|
databus.tx_id(config.UnitID)
|
||||||
|
|
||||||
-- mount connected devices
|
-- mount connected devices
|
||||||
ppm.mount_all()
|
ppm.mount_all()
|
||||||
|
|
||||||
-- message authentication init
|
-- message authentication init
|
||||||
if type(config.AUTH_KEY) == "string" then
|
if string.len(config.AuthKey) > 0 then
|
||||||
network.init_mac(config.AUTH_KEY)
|
network.init_mac(config.AuthKey)
|
||||||
end
|
end
|
||||||
|
|
||||||
-- shared memory across threads
|
-- shared memory across threads
|
||||||
---@class plc_shared_memory
|
---@class plc_shared_memory
|
||||||
local __shared_memory = {
|
local __shared_memory = {
|
||||||
-- networked setting
|
-- networked setting
|
||||||
networked = config.NETWORKED, ---@type boolean
|
networked = config.Networked,
|
||||||
|
|
||||||
-- PLC system state flags
|
-- PLC system state flags
|
||||||
---@class plc_state
|
---@class plc_state
|
||||||
@ -196,18 +184,17 @@ local function main()
|
|||||||
|
|
||||||
if plc_state.init_ok then
|
if plc_state.init_ok then
|
||||||
-- init reactor protection system
|
-- init reactor protection system
|
||||||
smem_sys.rps = plc.rps_init(smem_dev.reactor, plc_state.reactor_formed, config.EMERGENCY_COOL)
|
smem_sys.rps = plc.rps_init(smem_dev.reactor, plc_state.reactor_formed)
|
||||||
log.debug("init> rps init")
|
log.debug("init> rps init")
|
||||||
|
|
||||||
if __shared_memory.networked then
|
if __shared_memory.networked then
|
||||||
-- comms watchdog
|
-- comms watchdog
|
||||||
smem_sys.conn_watchdog = util.new_watchdog(config.COMMS_TIMEOUT)
|
smem_sys.conn_watchdog = util.new_watchdog(config.ConnTimeout)
|
||||||
log.debug("init> conn watchdog started")
|
log.debug("init> conn watchdog started")
|
||||||
|
|
||||||
-- create network interface then setup comms
|
-- create network interface then setup comms
|
||||||
smem_sys.nic = network.nic(smem_dev.modem)
|
smem_sys.nic = network.nic(smem_dev.modem)
|
||||||
smem_sys.plc_comms = plc.comms(config.REACTOR_ID, R_PLC_VERSION, smem_sys.nic, config.PLC_CHANNEL, config.SVR_CHANNEL,
|
smem_sys.plc_comms = plc.comms(R_PLC_VERSION, smem_sys.nic, smem_dev.reactor, smem_sys.rps, smem_sys.conn_watchdog)
|
||||||
config.TRUSTED_RANGE, smem_dev.reactor, smem_sys.rps, smem_sys.conn_watchdog)
|
|
||||||
log.debug("init> comms init")
|
log.debug("init> comms init")
|
||||||
else
|
else
|
||||||
_println_no_fp("init> starting in offline mode")
|
_println_no_fp("init> starting in offline mode")
|
||||||
@ -215,7 +202,7 @@ local function main()
|
|||||||
end
|
end
|
||||||
|
|
||||||
-- notify user of emergency coolant configuration status
|
-- notify user of emergency coolant configuration status
|
||||||
if config.EMERGENCY_COOL ~= nil then
|
if config.EmerCoolEnable then
|
||||||
println("init> emergency coolant control ready")
|
println("init> emergency coolant control ready")
|
||||||
log.info("init> running with emergency coolant control available")
|
log.info("init> running with emergency coolant control available")
|
||||||
end
|
end
|
||||||
|
Loading…
x
Reference in New Issue
Block a user