Merge branch 'devel' into 51-hmac-message-authentication

This commit is contained in:
Mikayla Fischler
2023-06-22 16:05:46 -04:00
15 changed files with 99 additions and 74 deletions

View File

@@ -21,7 +21,7 @@ local sounder = require("coordinator.sounder")
local apisessions = require("coordinator.session.apisessions") local apisessions = require("coordinator.session.apisessions")
local COORDINATOR_VERSION = "v0.17.0" local COORDINATOR_VERSION = "v0.17.1"
local println = util.println local println = util.println
local println_ts = util.println_ts local println_ts = util.println_ts

File diff suppressed because one or more lines are too long

View File

@@ -18,7 +18,7 @@ local coreio = require("pocket.coreio")
local pocket = require("pocket.pocket") local pocket = require("pocket.pocket")
local renderer = require("pocket.renderer") local renderer = require("pocket.renderer")
local POCKET_VERSION = "alpha-v0.5.0" local POCKET_VERSION = "alpha-v0.5.1"
local println = util.println local println = util.println
local println_ts = util.println_ts local println_ts = util.println_ts

View File

@@ -639,7 +639,7 @@ function plc.comms(id, version, modem, plc_channel, svr_channel, range, reactor,
parallel.waitForAll(table.unpack(tasks)) parallel.waitForAll(table.unpack(tasks))
if not reactor.__p_is_faulted() then if reactor.__p_is_ok() then
_send(RPLC_TYPE.MEK_STRUCT, mek_data) _send(RPLC_TYPE.MEK_STRUCT, mek_data)
self.resend_build = false self.resend_build = false
end end
@@ -836,7 +836,7 @@ function plc.comms(id, version, modem, plc_channel, svr_channel, range, reactor,
success = true success = true
else else
reactor.setBurnRate(burn_rate) reactor.setBurnRate(burn_rate)
success = not reactor.__p_is_faulted() success = reactor.__p_is_ok()
end end
else else
log.debug(burn_rate .. " rate outside of 0 < x <= " .. self.max_burn_rate) log.debug(burn_rate .. " rate outside of 0 < x <= " .. self.max_burn_rate)

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.4.6" local R_PLC_VERSION = "v1.4.7"
local println = util.println local println = util.println
local println_ts = util.println_ts local println_ts = util.println_ts

View File

@@ -10,6 +10,7 @@ function boilerv_rtu.new(boiler)
local unit = rtu.init_unit() local unit = rtu.init_unit()
-- disable auto fault clearing -- disable auto fault clearing
boiler.__p_clear_fault()
boiler.__p_disable_afc() boiler.__p_disable_afc()
-- discrete inputs -- -- discrete inputs --

View File

@@ -10,6 +10,7 @@ function envd_rtu.new(envd)
local unit = rtu.init_unit() local unit = rtu.init_unit()
-- disable auto fault clearing -- disable auto fault clearing
envd.__p_clear_fault()
envd.__p_disable_afc() envd.__p_disable_afc()
-- discrete inputs -- -- discrete inputs --

View File

@@ -10,6 +10,7 @@ function imatrix_rtu.new(imatrix)
local unit = rtu.init_unit() local unit = rtu.init_unit()
-- disable auto fault clearing -- disable auto fault clearing
imatrix.__p_clear_fault()
imatrix.__p_disable_afc() imatrix.__p_disable_afc()
-- discrete inputs -- -- discrete inputs --

View File

@@ -10,6 +10,7 @@ function sna_rtu.new(sna)
local unit = rtu.init_unit() local unit = rtu.init_unit()
-- disable auto fault clearing -- disable auto fault clearing
sna.__p_clear_fault()
sna.__p_disable_afc() sna.__p_disable_afc()
-- discrete inputs -- -- discrete inputs --

View File

@@ -10,6 +10,7 @@ function sps_rtu.new(sps)
local unit = rtu.init_unit() local unit = rtu.init_unit()
-- disable auto fault clearing -- disable auto fault clearing
sps.__p_clear_fault()
sps.__p_disable_afc() sps.__p_disable_afc()
-- discrete inputs -- -- discrete inputs --

View File

@@ -10,6 +10,7 @@ function turbinev_rtu.new(turbine)
local unit = rtu.init_unit() local unit = rtu.init_unit()
-- disable auto fault clearing -- disable auto fault clearing
turbine.__p_clear_fault()
turbine.__p_disable_afc() turbine.__p_disable_afc()
-- discrete inputs -- -- discrete inputs --

View File

@@ -28,7 +28,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.3.6" local RTU_VERSION = "v1.3.7"
local RTU_UNIT_TYPE = types.RTU_UNIT_TYPE local RTU_UNIT_TYPE = types.RTU_UNIT_TYPE
local RTU_UNIT_HW_STATE = databus.RTU_UNIT_HW_STATE local RTU_UNIT_HW_STATE = databus.RTU_UNIT_HW_STATE
@@ -236,18 +236,19 @@ local function main()
---@class rtu_unit_registry_entry ---@class rtu_unit_registry_entry
local unit = { local unit = {
uid = 0, ---@type integer uid = 0, ---@type integer
name = "redstone_io", ---@type string name = "redstone_io", ---@type string
type = RTU_UNIT_TYPE.REDSTONE, ---@type RTU_UNIT_TYPE type = RTU_UNIT_TYPE.REDSTONE, ---@type RTU_UNIT_TYPE
index = entry_idx, ---@type integer index = entry_idx, ---@type integer
reactor = io_reactor, ---@type integer reactor = io_reactor, ---@type integer
device = capabilities, ---@type table use device field for redstone ports device = capabilities, ---@type table use device field for redstone ports
is_multiblock = false, ---@type boolean is_multiblock = false, ---@type boolean
formed = nil, ---@type boolean|nil formed = nil, ---@type boolean|nil
rtu = rs_rtu, ---@type rtu_device|rtu_rs_device hw_state = RTU_UNIT_HW_STATE.OK, ---@type RTU_UNIT_HW_STATE
rtu = rs_rtu, ---@type rtu_device|rtu_rs_device
modbus_io = modbus.new(rs_rtu, false), modbus_io = modbus.new(rs_rtu, false),
pkt_queue = nil, ---@type mqueue|nil pkt_queue = nil, ---@type mqueue|nil
thread = nil ---@type parallel_thread|nil thread = nil ---@type parallel_thread|nil
} }
table.insert(units, unit) table.insert(units, unit)
@@ -261,7 +262,7 @@ local function main()
unit.uid = #units unit.uid = #units
databus.tx_unit_hw_status(unit.uid, RTU_UNIT_HW_STATE.OK) databus.tx_unit_hw_status(unit.uid, unit.hw_state)
end end
end end
@@ -403,6 +404,7 @@ local function main()
device = device, ---@type table device = device, ---@type table
is_multiblock = is_multiblock, ---@type boolean is_multiblock = is_multiblock, ---@type boolean
formed = formed, ---@type boolean|nil formed = formed, ---@type boolean|nil
hw_state = RTU_UNIT_HW_STATE.OFFLINE, ---@type RTU_UNIT_HW_STATE
rtu = rtu_iface, ---@type rtu_device|rtu_rs_device rtu = rtu_iface, ---@type rtu_device|rtu_rs_device
modbus_io = modbus.new(rtu_iface, true), modbus_io = modbus.new(rtu_iface, true),
pkt_queue = mqueue.new(), ---@type mqueue|nil pkt_queue = mqueue.new(), ---@type mqueue|nil
@@ -422,19 +424,21 @@ local function main()
rtu_unit.uid = #units rtu_unit.uid = #units
-- report hardware status -- determine hardware status
if rtu_unit.type == RTU_UNIT_TYPE.VIRTUAL then if rtu_unit.type == RTU_UNIT_TYPE.VIRTUAL then
databus.tx_unit_hw_status(rtu_unit.uid, RTU_UNIT_HW_STATE.OFFLINE) rtu_unit.hw_state = RTU_UNIT_HW_STATE.OFFLINE
else else
if rtu_unit.is_multiblock then if rtu_unit.is_multiblock then
databus.tx_unit_hw_status(rtu_unit.uid, util.trinary(rtu_unit.formed == true, RTU_UNIT_HW_STATE.OK, RTU_UNIT_HW_STATE.UNFORMED)) rtu_unit.hw_state = util.trinary(rtu_unit.formed == true, RTU_UNIT_HW_STATE.OK, RTU_UNIT_HW_STATE.UNFORMED)
elseif faulted then elseif faulted then
databus.tx_unit_hw_status(rtu_unit.uid, RTU_UNIT_HW_STATE.FAULTED) rtu_unit.hw_state = RTU_UNIT_HW_STATE.FAULTED
else else
databus.tx_unit_hw_status(rtu_unit.uid, RTU_UNIT_HW_STATE.OK) rtu_unit.hw_state = RTU_UNIT_HW_STATE.OK
end end
end end
-- report hardware status
databus.tx_unit_hw_status(rtu_unit.uid, rtu_unit.hw_state)
end end
-- we made it through all that trusting-user-to-write-a-config-file chaos -- we made it through all that trusting-user-to-write-a-config-file chaos

View File

@@ -105,13 +105,15 @@ function threads.thread__main(smem)
for i = 1, #units do for i = 1, #units do
-- find disconnected device -- find disconnected device
if units[i].device == device then if units[i].device == device then
-- we are going to let the PPM prevent crashes -- will let the PPM prevent crashes, which will indicate failures in MODBUS queries
-- return fault flags/codes to MODBUS queries
local unit = units[i] ---@type rtu_unit_registry_entry local unit = units[i] ---@type rtu_unit_registry_entry
local type_name = types.rtu_type_to_string(unit.type) local type_name = types.rtu_type_to_string(unit.type)
println_ts(util.c("lost the ", type_name, " on interface ", unit.name)) println_ts(util.c("lost the ", type_name, " on interface ", unit.name))
log.warning(util.c("lost the ", type_name, " unit peripheral on interface ", unit.name)) log.warning(util.c("lost the ", type_name, " unit peripheral on interface ", unit.name))
databus.tx_unit_hw_status(unit.uid, UNIT_HW_STATE.OFFLINE)
unit.hw_state = UNIT_HW_STATE.OFFLINE
databus.tx_unit_hw_status(unit.uid, unit.hw_state)
break break
end end
end end
@@ -144,6 +146,8 @@ function threads.thread__main(smem)
-- note: cannot check isFormed as that would yield this coroutine and consume events -- note: cannot check isFormed as that would yield this coroutine and consume events
if unit.name == param1 then if unit.name == param1 then
local resend_advert = false local resend_advert = false
local faulted = false
local unknown = false
-- found, re-link -- found, re-link
unit.device = device unit.device = device
@@ -177,57 +181,58 @@ function threads.thread__main(smem)
end end
if unit.type == RTU_UNIT_TYPE.BOILER_VALVE then if unit.type == RTU_UNIT_TYPE.BOILER_VALVE then
unit.rtu = boilerv_rtu.new(device) unit.rtu, faulted = boilerv_rtu.new(device)
-- if not formed, indexing the multiblock functions would have resulted in a PPM fault -- if not formed, indexing the multiblock functions would have resulted in a PPM fault
unit.formed = util.trinary(device.__p_is_faulted(), false, nil) unit.formed = util.trinary(faulted, false, nil)
databus.tx_unit_hw_status(unit.uid, UNIT_HW_STATE.UNFORMED)
elseif unit.type == RTU_UNIT_TYPE.TURBINE_VALVE then elseif unit.type == RTU_UNIT_TYPE.TURBINE_VALVE then
unit.rtu = turbinev_rtu.new(device) unit.rtu, faulted = turbinev_rtu.new(device)
-- if not formed, indexing the multiblock functions would have resulted in a PPM fault -- if not formed, indexing the multiblock functions would have resulted in a PPM fault
unit.formed = util.trinary(device.__p_is_faulted(), false, nil) unit.formed = util.trinary(faulted, false, nil)
databus.tx_unit_hw_status(unit.uid, UNIT_HW_STATE.UNFORMED)
elseif unit.type == RTU_UNIT_TYPE.IMATRIX then elseif unit.type == RTU_UNIT_TYPE.IMATRIX then
unit.rtu = imatrix_rtu.new(device) unit.rtu, faulted = imatrix_rtu.new(device)
-- if not formed, indexing the multiblock functions would have resulted in a PPM fault -- if not formed, indexing the multiblock functions would have resulted in a PPM fault
unit.formed = util.trinary(device.__p_is_faulted(), false, nil) unit.formed = util.trinary(faulted, false, nil)
databus.tx_unit_hw_status(unit.uid, UNIT_HW_STATE.UNFORMED)
elseif unit.type == RTU_UNIT_TYPE.SPS then elseif unit.type == RTU_UNIT_TYPE.SPS then
unit.rtu = sps_rtu.new(device) unit.rtu, faulted = sps_rtu.new(device)
-- if not formed, indexing the multiblock functions would have resulted in a PPM fault -- if not formed, indexing the multiblock functions would have resulted in a PPM fault
unit.formed = util.trinary(device.__p_is_faulted(), false, nil) unit.formed = util.trinary(faulted, false, nil)
databus.tx_unit_hw_status(unit.uid, UNIT_HW_STATE.UNFORMED)
elseif unit.type == RTU_UNIT_TYPE.SNA then elseif unit.type == RTU_UNIT_TYPE.SNA then
unit.rtu = sna_rtu.new(device) unit.rtu, faulted = sna_rtu.new(device)
databus.tx_unit_hw_status(unit.uid, UNIT_HW_STATE.OK)
elseif unit.type == RTU_UNIT_TYPE.ENV_DETECTOR then elseif unit.type == RTU_UNIT_TYPE.ENV_DETECTOR then
unit.rtu = envd_rtu.new(device) unit.rtu, faulted = envd_rtu.new(device)
databus.tx_unit_hw_status(unit.uid, UNIT_HW_STATE.OK)
else else
unknown = true
log.error(util.c("failed to identify reconnected RTU unit type (", unit.name, ")"), true) log.error(util.c("failed to identify reconnected RTU unit type (", unit.name, ")"), true)
end end
if unit.is_multiblock then if unit.is_multiblock then
if (unit.formed == false) then unit.hw_state = UNIT_HW_STATE.UNFORMED
if unit.formed == false then
log.info(util.c("assuming ", unit.name, " is not formed due to PPM faults while initializing")) log.info(util.c("assuming ", unit.name, " is not formed due to PPM faults while initializing"))
databus.tx_unit_hw_status(unit.uid, UNIT_HW_STATE.UNFORMED)
end end
elseif device.__p_is_faulted() then elseif faulted then
databus.tx_unit_hw_status(unit.uid, UNIT_HW_STATE.FAULTED) unit.hw_state = UNIT_HW_STATE.FAULTED
elseif not unknown then
unit.hw_state = UNIT_HW_STATE.OK
else else
databus.tx_unit_hw_status(unit.uid, UNIT_HW_STATE.OK) unit.hw_state = UNIT_HW_STATE.OFFLINE
end end
unit.modbus_io = modbus.new(unit.rtu, true) databus.tx_unit_hw_status(unit.uid, unit.hw_state)
local type_name = types.rtu_type_to_string(unit.type) if not unknown then
local message = util.c("reconnected the ", type_name, " on interface ", unit.name) unit.modbus_io = modbus.new(unit.rtu, true)
println_ts(message)
log.info(message)
if resend_advert then local type_name = types.rtu_type_to_string(unit.type)
rtu_comms.send_advertisement(units) local message = util.c("reconnected the ", type_name, " on interface ", unit.name)
else println_ts(message)
rtu_comms.send_remounted(unit.uid) log.info(message)
if resend_advert then
rtu_comms.send_advertisement(units)
else
rtu_comms.send_remounted(unit.uid)
end
end end
end end
end end
@@ -391,13 +396,6 @@ function threads.thread__unit_comms(smem, unit)
-- received a packet -- received a packet
local _, reply = unit.modbus_io.handle_packet(msg.message) local _, reply = unit.modbus_io.handle_packet(msg.message)
rtu_comms.send_modbus(reply) rtu_comms.send_modbus(reply)
-- check if there was a problem and update the hardware state if so
local frame = reply.get()
if unit.formed and (bit.band(frame.func_code, types.MODBUS_FCODE.ERROR_FLAG) ~= 0) and
(frame.data[1] == types.MODBUS_EXCODE.SERVER_DEVICE_FAIL) then
databus.tx_unit_hw_status(unit.uid, UNIT_HW_STATE.FAULTED)
end
end end
end end
@@ -413,12 +411,10 @@ function threads.thread__unit_comms(smem, unit)
if unit.formed == nil then if unit.formed == nil then
unit.formed = is_formed unit.formed = is_formed
if is_formed then databus.tx_unit_hw_status(unit.uid, UNIT_HW_STATE.OK) end if is_formed then unit.hw_state = UNIT_HW_STATE.OK end
end end
if not unit.formed then if not unit.formed then unit.hw_state = UNIT_HW_STATE.UNFORMED end
databus.tx_unit_hw_status(unit.uid, UNIT_HW_STATE.UNFORMED)
end
if (not unit.formed) and is_formed then if (not unit.formed) and is_formed then
-- newly re-formed -- newly re-formed
@@ -463,11 +459,11 @@ function threads.thread__unit_comms(smem, unit)
if unit.formed and faulted then if unit.formed and faulted then
-- something is still wrong = can't mark as formed yet -- something is still wrong = can't mark as formed yet
unit.formed = false unit.formed = false
unit.hw_state = UNIT_HW_STATE.UNFORMED
log.info(util.c("assuming ", unit.name, " is not formed due to PPM faults while initializing")) log.info(util.c("assuming ", unit.name, " is not formed due to PPM faults while initializing"))
databus.tx_unit_hw_status(unit.uid, UNIT_HW_STATE.UNFORMED)
else else
unit.hw_state = UNIT_HW_STATE.OK
rtu_comms.send_remounted(unit.uid) rtu_comms.send_remounted(unit.uid)
databus.tx_unit_hw_status(unit.uid, UNIT_HW_STATE.OK)
end end
local type_name = types.rtu_type_to_string(unit.type) local type_name = types.rtu_type_to_string(unit.type)
@@ -484,6 +480,16 @@ function threads.thread__unit_comms(smem, unit)
unit.formed = is_formed unit.formed = is_formed
end end
-- check hardware status
if unit.device.__p_is_healthy() then
if unit.hw_state == UNIT_HW_STATE.FAULTED then unit.hw_state = UNIT_HW_STATE.OK end
else
if unit.hw_state == UNIT_HW_STATE.OK then unit.hw_state = UNIT_HW_STATE.FAULTED end
end
-- update hw status
databus.tx_unit_hw_status(unit.uid, unit.hw_state)
-- check for termination request -- check for termination request
if rtu_state.shutdown then if rtu_state.shutdown then
log.info("rtu unit thread exiting -> " .. short_name) log.info("rtu unit thread exiting -> " .. short_name)

View File

@@ -101,22 +101,31 @@ local function peri_init(iface)
end end
end end
-- fault management functions -- fault management & monitoring functions
local function clear_fault() self.faulted = false end local function clear_fault() self.faulted = false end
local function get_last_fault() return self.last_fault end local function get_last_fault() return self.last_fault end
local function is_faulted() return self.faulted end local function is_faulted() return self.faulted end
local function is_ok() return not self.faulted end local function is_ok() return not self.faulted end
-- check if a peripheral has any faulted functions<br>
-- contrasted with is_faulted() and is_ok() as those only check if the last operation failed,
-- unless auto fault clearing is disabled, at which point faults become sticky faults
local function is_healthy()
for _, v in pairs(self.fault_counts) do if v > 0 then return false end end
return true
end
local function enable_afc() self.auto_cf = true end local function enable_afc() self.auto_cf = true end
local function disable_afc() self.auto_cf = false end local function disable_afc() self.auto_cf = false end
-- append to device functions -- append PPM functions to device functions
self.device.__p_clear_fault = clear_fault self.device.__p_clear_fault = clear_fault
self.device.__p_last_fault = get_last_fault self.device.__p_last_fault = get_last_fault
self.device.__p_is_faulted = is_faulted self.device.__p_is_faulted = is_faulted
self.device.__p_is_ok = is_ok self.device.__p_is_ok = is_ok
self.device.__p_is_healthy = is_healthy
self.device.__p_enable_afc = enable_afc self.device.__p_enable_afc = enable_afc
self.device.__p_disable_afc = disable_afc self.device.__p_disable_afc = disable_afc
@@ -156,7 +165,7 @@ local function peri_init(iface)
return { return {
type = self.type, type = self.type,
dev = self.device dev = self.device
} }
end end

View File

@@ -20,7 +20,7 @@ local supervisor = require("supervisor.supervisor")
local svsessions = require("supervisor.session.svsessions") local svsessions = require("supervisor.session.svsessions")
local SUPERVISOR_VERSION = "v0.17.9" local SUPERVISOR_VERSION = "v0.17.10"
local println = util.println local println = util.println
local println_ts = util.println_ts local println_ts = util.println_ts