Compare commits
6 Commits
635-optimi
...
647-update
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
db1b90df90 | ||
|
|
ebfdec2294 | ||
|
|
68ae061ed3 | ||
|
|
7f951a985b | ||
|
|
965fa0c7d1 | ||
|
|
99742c621a |
@@ -327,10 +327,10 @@ function facility.receive_sv(side, sender, reply_to, message, distance)
|
|||||||
local s_pkt = self.nic.receive(side, sender, reply_to, message, distance)
|
local s_pkt = self.nic.receive(side, sender, reply_to, message, distance)
|
||||||
|
|
||||||
if s_pkt and s_pkt.protocol() == PROTOCOL.SCADA_MGMT then
|
if s_pkt and s_pkt.protocol() == PROTOCOL.SCADA_MGMT then
|
||||||
local pkt = comms.mgmt_packet().decode(s_pkt)
|
local mgmt_pkt = comms.mgmt_packet()
|
||||||
if pkt then
|
if mgmt_pkt.decode(s_pkt) then
|
||||||
tcd.abort(handle_timeout)
|
tcd.abort(handle_timeout)
|
||||||
handle_packet(pkt)
|
handle_packet(mgmt_pkt.get())
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -374,10 +374,18 @@ function coordinator.comms(version, nic, wl_nic, sv_watchdog)
|
|||||||
local pkt = nil
|
local pkt = nil
|
||||||
|
|
||||||
if s_pkt then
|
if s_pkt then
|
||||||
|
-- get as SCADA management packet
|
||||||
if s_pkt.protocol() == PROTOCOL.SCADA_MGMT then
|
if s_pkt.protocol() == PROTOCOL.SCADA_MGMT then
|
||||||
pkt = comms.mgmt_packet().decode(s_pkt)
|
local mgmt_pkt = comms.mgmt_packet()
|
||||||
|
if mgmt_pkt.decode(s_pkt) then
|
||||||
|
pkt = mgmt_pkt.get()
|
||||||
|
end
|
||||||
|
-- get as coordinator packet
|
||||||
elseif s_pkt.protocol() == PROTOCOL.SCADA_CRDN then
|
elseif s_pkt.protocol() == PROTOCOL.SCADA_CRDN then
|
||||||
pkt = comms.crdn_packet().decode(s_pkt)
|
local crdn_pkt = comms.crdn_packet()
|
||||||
|
if crdn_pkt.decode(s_pkt) then
|
||||||
|
pkt = crdn_pkt.get()
|
||||||
|
end
|
||||||
else
|
else
|
||||||
log.debug("attempted parse of illegal packet type " .. s_pkt.protocol(), true)
|
log.debug("attempted parse of illegal packet type " .. s_pkt.protocol(), true)
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -33,6 +33,15 @@ local HIGH_RTT = 1500 -- 3.33x as long as expected w/ 0 ping
|
|||||||
|
|
||||||
local iocontrol = {}
|
local iocontrol = {}
|
||||||
|
|
||||||
|
local _ioctl = {
|
||||||
|
-- connection states for status evaluation
|
||||||
|
wd_modem = true,
|
||||||
|
wl_modem = true,
|
||||||
|
speaker = true,
|
||||||
|
monitor_states = {},
|
||||||
|
coroutines = {}
|
||||||
|
}
|
||||||
|
|
||||||
---@class ioctl
|
---@class ioctl
|
||||||
local io = {
|
local io = {
|
||||||
---@class ioctl_front_panel
|
---@class ioctl_front_panel
|
||||||
@@ -279,6 +288,15 @@ end
|
|||||||
|
|
||||||
--#region Front Panel PSIL
|
--#region Front Panel PSIL
|
||||||
|
|
||||||
|
-- evaluate and publish system health status
|
||||||
|
local function fp_eval_status()
|
||||||
|
local ok = _ioctl.wd_modem and _ioctl.wl_modem and _ioctl.speaker
|
||||||
|
for _, v in pairs(_ioctl.monitor_states) do ok = ok and v end
|
||||||
|
for _, v in pairs(_ioctl.coroutines) do ok = ok and v end
|
||||||
|
|
||||||
|
io.fp.ps.publish("status", ok)
|
||||||
|
end
|
||||||
|
|
||||||
-- toggle heartbeat indicator
|
-- toggle heartbeat indicator
|
||||||
function iocontrol.heartbeat() io.fp.ps.toggle("heartbeat") end
|
function iocontrol.heartbeat() io.fp.ps.toggle("heartbeat") end
|
||||||
|
|
||||||
@@ -292,15 +310,30 @@ end
|
|||||||
|
|
||||||
-- report presence of the wired comms modem
|
-- report presence of the wired comms modem
|
||||||
---@param has_modem boolean
|
---@param has_modem boolean
|
||||||
function iocontrol.fp_has_wd_modem(has_modem) io.fp.ps.publish("has_wd_modem", has_modem) end
|
function iocontrol.fp_has_wd_modem(has_modem)
|
||||||
|
io.fp.ps.publish("has_wd_modem", has_modem)
|
||||||
|
|
||||||
|
_ioctl.wd_modem = has_modem
|
||||||
|
fp_eval_status()
|
||||||
|
end
|
||||||
|
|
||||||
-- report presence of the wireless comms modem
|
-- report presence of the wireless comms modem
|
||||||
---@param has_modem boolean
|
---@param has_modem boolean
|
||||||
function iocontrol.fp_has_wl_modem(has_modem) io.fp.ps.publish("has_wl_modem", has_modem) end
|
function iocontrol.fp_has_wl_modem(has_modem)
|
||||||
|
io.fp.ps.publish("has_wl_modem", has_modem)
|
||||||
|
|
||||||
|
_ioctl.wl_modem = has_modem
|
||||||
|
fp_eval_status()
|
||||||
|
end
|
||||||
|
|
||||||
-- report presence of the speaker
|
-- report presence of the speaker
|
||||||
---@param has_speaker boolean
|
---@param has_speaker boolean
|
||||||
function iocontrol.fp_has_speaker(has_speaker) io.fp.ps.publish("has_speaker", has_speaker) end
|
function iocontrol.fp_has_speaker(has_speaker)
|
||||||
|
io.fp.ps.publish("has_speaker", has_speaker)
|
||||||
|
|
||||||
|
_ioctl.speaker = has_speaker
|
||||||
|
fp_eval_status()
|
||||||
|
end
|
||||||
|
|
||||||
-- report supervisor link state
|
-- report supervisor link state
|
||||||
---@param state integer
|
---@param state integer
|
||||||
@@ -322,6 +355,9 @@ function iocontrol.fp_monitor_state(id, connected)
|
|||||||
|
|
||||||
if name ~= nil then
|
if name ~= nil then
|
||||||
io.fp.ps.publish(name, connected)
|
io.fp.ps.publish(name, connected)
|
||||||
|
|
||||||
|
_ioctl.monitor_states[name] = connected ~= 1
|
||||||
|
fp_eval_status()
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -329,7 +365,12 @@ end
|
|||||||
---@param thread string thread name
|
---@param thread string thread name
|
||||||
---@param ok boolean thread state
|
---@param ok boolean thread state
|
||||||
function iocontrol.fp_rt_status(thread, ok)
|
function iocontrol.fp_rt_status(thread, ok)
|
||||||
io.fp.ps.publish(util.c("routine__", thread), ok)
|
local name = util.c("routine__", thread)
|
||||||
|
|
||||||
|
io.fp.ps.publish(name, ok)
|
||||||
|
|
||||||
|
_ioctl.coroutines[name] = ok
|
||||||
|
fp_eval_status()
|
||||||
end
|
end
|
||||||
|
|
||||||
-- report PKT firmware version and PKT session connection state
|
-- report PKT firmware version and PKT session connection state
|
||||||
|
|||||||
@@ -59,9 +59,9 @@ local function init(panel, config)
|
|||||||
|
|
||||||
local status = LED{parent=system,label="STATUS",colors=cpair(colors.green,colors.red)}
|
local status = LED{parent=system,label="STATUS",colors=cpair(colors.green,colors.red)}
|
||||||
local heartbeat = LED{parent=system,label="HEARTBEAT",colors=led_grn}
|
local heartbeat = LED{parent=system,label="HEARTBEAT",colors=led_grn}
|
||||||
status.update(true)
|
|
||||||
system.line_break()
|
system.line_break()
|
||||||
|
|
||||||
|
status.register(ps, "status", status.update)
|
||||||
heartbeat.register(ps, "heartbeat", heartbeat.update)
|
heartbeat.register(ps, "heartbeat", heartbeat.update)
|
||||||
|
|
||||||
if config.WirelessModem and config.WiredModem then
|
if config.WirelessModem and config.WiredModem then
|
||||||
|
|||||||
@@ -626,13 +626,21 @@ function pocket.comms(version, nic, sv_watchdog, api_watchdog, nav)
|
|||||||
---@return mgmt_frame|crdn_frame|nil packet
|
---@return mgmt_frame|crdn_frame|nil packet
|
||||||
function public.parse_packet(side, sender, reply_to, message, distance)
|
function public.parse_packet(side, sender, reply_to, message, distance)
|
||||||
local s_pkt = nic.receive(side, sender, reply_to, message, distance)
|
local s_pkt = nic.receive(side, sender, reply_to, message, distance)
|
||||||
|
|
||||||
local pkt = nil
|
local pkt = nil
|
||||||
|
|
||||||
if s_pkt then
|
if s_pkt then
|
||||||
|
-- get as SCADA management packet
|
||||||
if s_pkt.protocol() == PROTOCOL.SCADA_MGMT then
|
if s_pkt.protocol() == PROTOCOL.SCADA_MGMT then
|
||||||
pkt = comms.mgmt_packet().decode(s_pkt)
|
local mgmt_pkt = comms.mgmt_packet()
|
||||||
|
if mgmt_pkt.decode(s_pkt) then
|
||||||
|
pkt = mgmt_pkt.get()
|
||||||
|
end
|
||||||
|
-- get as coordinator packet
|
||||||
elseif s_pkt.protocol() == PROTOCOL.SCADA_CRDN then
|
elseif s_pkt.protocol() == PROTOCOL.SCADA_CRDN then
|
||||||
pkt = comms.crdn_packet().decode(s_pkt)
|
local crdn_pkt = comms.crdn_packet()
|
||||||
|
if crdn_pkt.decode(s_pkt) then
|
||||||
|
pkt = crdn_pkt.get()
|
||||||
|
end
|
||||||
else
|
else
|
||||||
log.debug("attempted parse of illegal packet type " .. s_pkt.protocol(), true)
|
log.debug("attempted parse of illegal packet type " .. s_pkt.protocol(), true)
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -22,7 +22,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 = "v1.0.5"
|
local POCKET_VERSION = "v1.0.4"
|
||||||
|
|
||||||
local println = util.println
|
local println = util.println
|
||||||
local println_ts = util.println_ts
|
local println_ts = util.println_ts
|
||||||
|
|||||||
@@ -249,10 +249,10 @@ function check.receive_sv(side, sender, reply_to, message, distance)
|
|||||||
local s_pkt = self.nic.receive(side, sender, reply_to, message, distance)
|
local s_pkt = self.nic.receive(side, sender, reply_to, message, distance)
|
||||||
|
|
||||||
if s_pkt and s_pkt.protocol() == PROTOCOL.SCADA_MGMT then
|
if s_pkt and s_pkt.protocol() == PROTOCOL.SCADA_MGMT then
|
||||||
local pkt = comms.mgmt_packet().decode(s_pkt)
|
local mgmt_pkt = comms.mgmt_packet()
|
||||||
if pkt then
|
if mgmt_pkt.decode(s_pkt) then
|
||||||
tcd.abort(handle_timeout)
|
tcd.abort(handle_timeout)
|
||||||
handle_packet(pkt)
|
handle_packet(mgmt_pkt.get())
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -11,11 +11,22 @@ local databus = {}
|
|||||||
-- databus PSIL
|
-- databus PSIL
|
||||||
databus.ps = psil.create()
|
databus.ps = psil.create()
|
||||||
|
|
||||||
local dbus_iface = {
|
local _dbus = {
|
||||||
rps_scram = function () log.debug("DBUS: unset rps_scram() called") end,
|
rps_scram = function () log.debug("DBUS: unset rps_scram() called") end,
|
||||||
rps_reset = function () log.debug("DBUS: unset rps_reset() called") end
|
rps_reset = function () log.debug("DBUS: unset rps_reset() called") end,
|
||||||
|
|
||||||
|
degraded = false,
|
||||||
|
coroutines = {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
-- evaluate and publish system health status
|
||||||
|
local function eval_status()
|
||||||
|
local ok = not _dbus.degraded
|
||||||
|
for _, v in pairs(_dbus.coroutines) do ok = ok and v end
|
||||||
|
|
||||||
|
databus.ps.publish("status", ok)
|
||||||
|
end
|
||||||
|
|
||||||
-- call to toggle heartbeat signal
|
-- call to toggle heartbeat signal
|
||||||
function databus.heartbeat() databus.ps.toggle("heartbeat") end
|
function databus.heartbeat() databus.ps.toggle("heartbeat") end
|
||||||
|
|
||||||
@@ -23,15 +34,15 @@ function databus.heartbeat() databus.ps.toggle("heartbeat") end
|
|||||||
---@param scram function reactor SCRAM function
|
---@param scram function reactor SCRAM function
|
||||||
---@param reset function RPS reset function
|
---@param reset function RPS reset function
|
||||||
function databus.link_rps(scram, reset)
|
function databus.link_rps(scram, reset)
|
||||||
dbus_iface.rps_scram = scram
|
_dbus.rps_scram = scram
|
||||||
dbus_iface.rps_reset = reset
|
_dbus.rps_reset = reset
|
||||||
end
|
end
|
||||||
|
|
||||||
-- transmit a command to the RPS to SCRAM
|
-- transmit a command to the RPS to SCRAM
|
||||||
function databus.rps_scram() dbus_iface.rps_scram() end
|
function databus.rps_scram() _dbus.rps_scram() end
|
||||||
|
|
||||||
-- transmit a command to the RPS to reset
|
-- transmit a command to the RPS to reset
|
||||||
function databus.rps_reset() dbus_iface.rps_reset() end
|
function databus.rps_reset() _dbus.rps_reset() end
|
||||||
|
|
||||||
-- transmit firmware versions
|
-- transmit firmware versions
|
||||||
---@param plc_v string PLC version
|
---@param plc_v string PLC version
|
||||||
@@ -50,17 +61,24 @@ end
|
|||||||
-- transmit hardware status
|
-- transmit hardware status
|
||||||
---@param plc_state plc_state
|
---@param plc_state plc_state
|
||||||
function databus.tx_hw_status(plc_state)
|
function databus.tx_hw_status(plc_state)
|
||||||
databus.ps.publish("degraded", plc_state.degraded)
|
|
||||||
databus.ps.publish("reactor_dev_state", util.trinary(plc_state.no_reactor, 1, util.trinary(plc_state.reactor_formed, 3, 2)))
|
databus.ps.publish("reactor_dev_state", util.trinary(plc_state.no_reactor, 1, util.trinary(plc_state.reactor_formed, 3, 2)))
|
||||||
databus.ps.publish("has_wd_modem", plc_state.wd_modem)
|
databus.ps.publish("has_wd_modem", plc_state.wd_modem)
|
||||||
databus.ps.publish("has_wl_modem", plc_state.wl_modem)
|
databus.ps.publish("has_wl_modem", plc_state.wl_modem)
|
||||||
|
|
||||||
|
_dbus.degraded = plc_state.degraded
|
||||||
|
eval_status()
|
||||||
end
|
end
|
||||||
|
|
||||||
-- transmit thread (routine) statuses
|
-- transmit thread (routine) statuses
|
||||||
---@param thread string thread name
|
---@param thread string thread name
|
||||||
---@param ok boolean thread state
|
---@param ok boolean thread state
|
||||||
function databus.tx_rt_status(thread, ok)
|
function databus.tx_rt_status(thread, ok)
|
||||||
databus.ps.publish(util.c("routine__", thread), ok)
|
local name = util.c("routine__", thread)
|
||||||
|
|
||||||
|
databus.ps.publish(name, ok)
|
||||||
|
|
||||||
|
_dbus.coroutines[name] = ok
|
||||||
|
eval_status()
|
||||||
end
|
end
|
||||||
|
|
||||||
-- transmit supervisor link state
|
-- transmit supervisor link state
|
||||||
|
|||||||
@@ -50,11 +50,11 @@ local function init(panel, config)
|
|||||||
|
|
||||||
local system = Div{parent=panel,width=14,height=18,x=2,y=3}
|
local system = Div{parent=panel,width=14,height=18,x=2,y=3}
|
||||||
|
|
||||||
local degraded = LED{parent=system,label="STATUS",colors=cpair(colors.red,colors.green)}
|
local sys_status = LED{parent=system,label="STATUS",colors=cpair(colors.green,colors.red)}
|
||||||
local heartbeat = LED{parent=system,label="HEARTBEAT",colors=ind_grn}
|
local heartbeat = LED{parent=system,label="HEARTBEAT",colors=ind_grn}
|
||||||
system.line_break()
|
system.line_break()
|
||||||
|
|
||||||
degraded.register(databus.ps, "degraded", degraded.update)
|
sys_status.register(databus.ps, "status", sys_status.update)
|
||||||
heartbeat.register(databus.ps, "heartbeat", heartbeat.update)
|
heartbeat.register(databus.ps, "heartbeat", heartbeat.update)
|
||||||
|
|
||||||
local reactor = LEDPair{parent=system,label="REACTOR",off=colors.red,c1=colors.yellow,c2=colors.green}
|
local reactor = LEDPair{parent=system,label="REACTOR",off=colors.red,c1=colors.yellow,c2=colors.green}
|
||||||
|
|||||||
@@ -923,10 +923,14 @@ function plc.comms(version, nic, reactor, rps, conn_watchdog)
|
|||||||
local pkt = nil
|
local pkt = nil
|
||||||
|
|
||||||
if s_pkt then
|
if s_pkt then
|
||||||
|
-- get as RPLC packet
|
||||||
if s_pkt.protocol() == PROTOCOL.RPLC then
|
if s_pkt.protocol() == PROTOCOL.RPLC then
|
||||||
pkt = comms.rplc_packet().decode(s_pkt)
|
local rplc_pkt = comms.rplc_packet()
|
||||||
|
if rplc_pkt.decode(s_pkt) then pkt = rplc_pkt.get() end
|
||||||
|
-- get as SCADA management packet
|
||||||
elseif s_pkt.protocol() == PROTOCOL.SCADA_MGMT then
|
elseif s_pkt.protocol() == PROTOCOL.SCADA_MGMT then
|
||||||
pkt = comms.mgmt_packet().decode(s_pkt)
|
local mgmt_pkt = comms.mgmt_packet()
|
||||||
|
if mgmt_pkt.decode(s_pkt) then pkt = mgmt_pkt.get() end
|
||||||
else
|
else
|
||||||
log.debug("unsupported packet type " .. s_pkt.protocol(), true)
|
log.debug("unsupported packet type " .. s_pkt.protocol(), true)
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -19,7 +19,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.10.1"
|
local R_PLC_VERSION = "v1.10.2"
|
||||||
|
|
||||||
local println = util.println
|
local println = util.println
|
||||||
local println_ts = util.println_ts
|
local println_ts = util.println_ts
|
||||||
|
|||||||
@@ -326,10 +326,10 @@ function check.receive_sv(side, sender, reply_to, message, distance)
|
|||||||
local s_pkt = self.nic.receive(side, sender, reply_to, message, distance)
|
local s_pkt = self.nic.receive(side, sender, reply_to, message, distance)
|
||||||
|
|
||||||
if s_pkt and s_pkt.protocol() == PROTOCOL.SCADA_MGMT then
|
if s_pkt and s_pkt.protocol() == PROTOCOL.SCADA_MGMT then
|
||||||
local pkt = comms.mgmt_packet().decode(s_pkt)
|
local mgmt_pkt = comms.mgmt_packet()
|
||||||
if pkt then
|
if mgmt_pkt.decode(s_pkt) then
|
||||||
tcd.abort(handle_timeout)
|
tcd.abort(handle_timeout)
|
||||||
handle_packet(pkt)
|
handle_packet(mgmt_pkt.get())
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -7,6 +7,20 @@ local util = require("scada-common.util")
|
|||||||
|
|
||||||
local databus = {}
|
local databus = {}
|
||||||
|
|
||||||
|
local _dbus = {
|
||||||
|
wd_modem = true,
|
||||||
|
wl_modem = true,
|
||||||
|
coroutines = {}
|
||||||
|
}
|
||||||
|
|
||||||
|
-- evaluate and publish system health status
|
||||||
|
local function eval_status()
|
||||||
|
local ok = _dbus.wd_modem and _dbus.wl_modem
|
||||||
|
for _, v in pairs(_dbus.coroutines) do ok = ok and v end
|
||||||
|
|
||||||
|
databus.ps.publish("status", ok)
|
||||||
|
end
|
||||||
|
|
||||||
-- databus PSIL
|
-- databus PSIL
|
||||||
databus.ps = psil.create()
|
databus.ps = psil.create()
|
||||||
|
|
||||||
@@ -35,12 +49,18 @@ end
|
|||||||
---@param has_modem boolean
|
---@param has_modem boolean
|
||||||
function databus.tx_hw_wd_modem(has_modem)
|
function databus.tx_hw_wd_modem(has_modem)
|
||||||
databus.ps.publish("has_wd_modem", has_modem)
|
databus.ps.publish("has_wd_modem", has_modem)
|
||||||
|
|
||||||
|
_dbus.wd_modem = has_modem
|
||||||
|
eval_status()
|
||||||
end
|
end
|
||||||
|
|
||||||
-- transmit hardware status for the wireless comms modem
|
-- transmit hardware status for the wireless comms modem
|
||||||
---@param has_modem boolean
|
---@param has_modem boolean
|
||||||
function databus.tx_hw_wl_modem(has_modem)
|
function databus.tx_hw_wl_modem(has_modem)
|
||||||
databus.ps.publish("has_wl_modem", has_modem)
|
databus.ps.publish("has_wl_modem", has_modem)
|
||||||
|
|
||||||
|
_dbus.wl_modem = has_modem
|
||||||
|
eval_status()
|
||||||
end
|
end
|
||||||
|
|
||||||
-- transmit the number of speakers connected
|
-- transmit the number of speakers connected
|
||||||
@@ -67,7 +87,12 @@ end
|
|||||||
---@param thread string thread name
|
---@param thread string thread name
|
||||||
---@param ok boolean thread state
|
---@param ok boolean thread state
|
||||||
function databus.tx_rt_status(thread, ok)
|
function databus.tx_rt_status(thread, ok)
|
||||||
databus.ps.publish(util.c("routine__", thread), ok)
|
local name = util.c("routine__", thread)
|
||||||
|
|
||||||
|
databus.ps.publish(name, ok)
|
||||||
|
|
||||||
|
_dbus.coroutines[name] = ok
|
||||||
|
eval_status()
|
||||||
end
|
end
|
||||||
|
|
||||||
-- transmit supervisor link state
|
-- transmit supervisor link state
|
||||||
|
|||||||
@@ -51,11 +51,11 @@ local function init(panel, config, units)
|
|||||||
|
|
||||||
local system = Div{parent=panel,width=14,height=term_h-5,x=2,y=3}
|
local system = Div{parent=panel,width=14,height=term_h-5,x=2,y=3}
|
||||||
|
|
||||||
local on = LED{parent=system,label="STATUS",colors=cpair(colors.green,colors.red)}
|
local status = LED{parent=system,label="STATUS",colors=cpair(colors.green,colors.red)}
|
||||||
local heartbeat = LED{parent=system,label="HEARTBEAT",colors=ind_grn}
|
local heartbeat = LED{parent=system,label="HEARTBEAT",colors=ind_grn}
|
||||||
on.update(true)
|
|
||||||
system.line_break()
|
system.line_break()
|
||||||
|
|
||||||
|
status.register(databus.ps, "status", status.update)
|
||||||
heartbeat.register(databus.ps, "heartbeat", heartbeat.update)
|
heartbeat.register(databus.ps, "heartbeat", heartbeat.update)
|
||||||
|
|
||||||
if config.WirelessModem and config.WiredModem then
|
if config.WirelessModem and config.WiredModem then
|
||||||
|
|||||||
12
rtu/rtu.lua
12
rtu/rtu.lua
@@ -425,10 +425,18 @@ function rtu.comms(version, nic, conn_watchdog)
|
|||||||
local pkt = nil
|
local pkt = nil
|
||||||
|
|
||||||
if s_pkt then
|
if s_pkt then
|
||||||
|
-- get as MODBUS TCP packet
|
||||||
if s_pkt.protocol() == PROTOCOL.MODBUS_TCP then
|
if s_pkt.protocol() == PROTOCOL.MODBUS_TCP then
|
||||||
pkt = comms.modbus_packet().decode(s_pkt)
|
local m_pkt = comms.modbus_packet()
|
||||||
|
if m_pkt.decode(s_pkt) then
|
||||||
|
pkt = m_pkt.get()
|
||||||
|
end
|
||||||
|
-- get as SCADA management packet
|
||||||
elseif s_pkt.protocol() == PROTOCOL.SCADA_MGMT then
|
elseif s_pkt.protocol() == PROTOCOL.SCADA_MGMT then
|
||||||
pkt = comms.mgmt_packet().decode(s_pkt)
|
local mgmt_pkt = comms.mgmt_packet()
|
||||||
|
if mgmt_pkt.decode(s_pkt) then
|
||||||
|
pkt = mgmt_pkt.get()
|
||||||
|
end
|
||||||
else
|
else
|
||||||
log.debug("illegal packet type " .. s_pkt.protocol(), true)
|
log.debug("illegal packet type " .. s_pkt.protocol(), true)
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -414,7 +414,6 @@ function comms.modbus_packet()
|
|||||||
---@param unit_id integer
|
---@param unit_id integer
|
||||||
---@param func_code MODBUS_FCODE
|
---@param func_code MODBUS_FCODE
|
||||||
---@param data table
|
---@param data table
|
||||||
---@return boolean success
|
|
||||||
function public.make(txn_id, unit_id, func_code, data)
|
function public.make(txn_id, unit_id, func_code, data)
|
||||||
if type(data) == "table" then
|
if type(data) == "table" then
|
||||||
self.txn_id = txn_id
|
self.txn_id = txn_id
|
||||||
@@ -426,33 +425,37 @@ function comms.modbus_packet()
|
|||||||
-- populate raw array
|
-- populate raw array
|
||||||
self.raw = { self.txn_id, self.unit_id, self.func_code }
|
self.raw = { self.txn_id, self.unit_id, self.func_code }
|
||||||
for i = 1, self.length do insert(self.raw, data[i]) end
|
for i = 1, self.length do insert(self.raw, data[i]) end
|
||||||
|
else
|
||||||
return true
|
log.error("COMMS: modbus_packet.make(): data not a table")
|
||||||
end
|
end
|
||||||
|
|
||||||
log.error("COMMS: modbus_packet.make(): data not a table")
|
|
||||||
return false
|
|
||||||
end
|
end
|
||||||
|
|
||||||
-- decode a MODBUS packet from a SCADA frame
|
-- decode a MODBUS packet from a SCADA frame
|
||||||
---@param frame scada_packet
|
---@param frame scada_packet
|
||||||
---@return modbus_frame|nil frame the decoded frame, if valid
|
---@return boolean success
|
||||||
function public.decode(frame)
|
function public.decode(frame)
|
||||||
if frame then
|
if frame then
|
||||||
self.frame = frame
|
self.frame = frame
|
||||||
|
|
||||||
if frame.protocol() == PROTOCOL.MODBUS_TCP then
|
if frame.protocol() == PROTOCOL.MODBUS_TCP then
|
||||||
if frame.length() >= 3 then
|
local size_ok = frame.length() >= 3
|
||||||
|
|
||||||
|
if size_ok then
|
||||||
local data = frame.data()
|
local data = frame.data()
|
||||||
|
public.make(data[1], data[2], data[3], { table.unpack(data, 4, #data) })
|
||||||
if public.make(data[1], data[2], data[3], { table.unpack(data, 4, #data) }) then
|
|
||||||
return public.get()
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
else log.debug("COMMS: attempted MODBUS_TCP parse of incorrect protocol " .. frame.protocol(), true) end
|
|
||||||
else log.debug("COMMS: nil frame encountered", true) end
|
|
||||||
|
|
||||||
return nil
|
local valid = type(self.txn_id) == "number" and type(self.unit_id) == "number" and type(self.func_code) == "number"
|
||||||
|
|
||||||
|
return size_ok and valid
|
||||||
|
else
|
||||||
|
log.debug("COMMS: attempted MODBUS_TCP parse of incorrect protocol " .. frame.protocol(), true)
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
else
|
||||||
|
log.debug("COMMS: nil frame encountered", true)
|
||||||
|
return false
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
-- get raw to send
|
-- get raw to send
|
||||||
@@ -497,7 +500,6 @@ function comms.rplc_packet()
|
|||||||
---@param id integer
|
---@param id integer
|
||||||
---@param packet_type RPLC_TYPE
|
---@param packet_type RPLC_TYPE
|
||||||
---@param data table
|
---@param data table
|
||||||
---@return boolean success
|
|
||||||
function public.make(id, packet_type, data)
|
function public.make(id, packet_type, data)
|
||||||
if type(data) == "table" then
|
if type(data) == "table" then
|
||||||
-- packet accessor properties
|
-- packet accessor properties
|
||||||
@@ -509,33 +511,37 @@ function comms.rplc_packet()
|
|||||||
-- populate raw array
|
-- populate raw array
|
||||||
self.raw = { self.id, self.type }
|
self.raw = { self.id, self.type }
|
||||||
for i = 1, #data do insert(self.raw, data[i]) end
|
for i = 1, #data do insert(self.raw, data[i]) end
|
||||||
|
else
|
||||||
return true
|
log.error("COMMS: rplc_packet.make(): data not a table")
|
||||||
end
|
end
|
||||||
|
|
||||||
log.error("COMMS: rplc_packet.make(): data not a table")
|
|
||||||
return false
|
|
||||||
end
|
end
|
||||||
|
|
||||||
-- decode an RPLC packet from a SCADA frame
|
-- decode an RPLC packet from a SCADA frame
|
||||||
---@param frame scada_packet
|
---@param frame scada_packet
|
||||||
---@return rplc_frame|nil frame the decoded frame, if valid
|
---@return boolean success
|
||||||
function public.decode(frame)
|
function public.decode(frame)
|
||||||
if frame then
|
if frame then
|
||||||
self.frame = frame
|
self.frame = frame
|
||||||
|
|
||||||
if frame.protocol() == PROTOCOL.RPLC then
|
if frame.protocol() == PROTOCOL.RPLC then
|
||||||
if frame.length() >= 2 then
|
local ok = frame.length() >= 2
|
||||||
|
|
||||||
|
if ok then
|
||||||
local data = frame.data()
|
local data = frame.data()
|
||||||
|
public.make(data[1], data[2], { table.unpack(data, 3, #data) })
|
||||||
if public.make(data[1], data[2], { table.unpack(data, 3, #data) }) and (type(self.id) == "number") then
|
|
||||||
return public.get()
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
else log.debug("COMMS: attempted RPLC parse of incorrect protocol " .. frame.protocol(), true) end
|
|
||||||
else log.debug("COMMS: nil frame encountered", true) end
|
|
||||||
|
|
||||||
return nil
|
ok = ok and type(self.id) == "number"
|
||||||
|
|
||||||
|
return ok
|
||||||
|
else
|
||||||
|
log.debug("COMMS: attempted RPLC parse of incorrect protocol " .. frame.protocol(), true)
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
else
|
||||||
|
log.debug("COMMS: nil frame encountered", true)
|
||||||
|
return false
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
-- get raw to send
|
-- get raw to send
|
||||||
@@ -577,7 +583,6 @@ function comms.mgmt_packet()
|
|||||||
-- make a SCADA management packet
|
-- make a SCADA management packet
|
||||||
---@param packet_type MGMT_TYPE
|
---@param packet_type MGMT_TYPE
|
||||||
---@param data table
|
---@param data table
|
||||||
---@return boolean success
|
|
||||||
function public.make(packet_type, data)
|
function public.make(packet_type, data)
|
||||||
if type(data) == "table" then
|
if type(data) == "table" then
|
||||||
-- packet accessor properties
|
-- packet accessor properties
|
||||||
@@ -588,33 +593,35 @@ function comms.mgmt_packet()
|
|||||||
-- populate raw array
|
-- populate raw array
|
||||||
self.raw = { self.type }
|
self.raw = { self.type }
|
||||||
for i = 1, #data do insert(self.raw, data[i]) end
|
for i = 1, #data do insert(self.raw, data[i]) end
|
||||||
|
else
|
||||||
return true
|
log.error("COMMS: mgmt_packet.make(): data not a table")
|
||||||
end
|
end
|
||||||
|
|
||||||
log.error("COMMS: mgmt_packet.make(): data not a table")
|
|
||||||
return false
|
|
||||||
end
|
end
|
||||||
|
|
||||||
-- decode a SCADA management packet from a SCADA frame
|
-- decode a SCADA management packet from a SCADA frame
|
||||||
---@param frame scada_packet
|
---@param frame scada_packet
|
||||||
---@return mgmt_frame|nil frame the decoded frame, if valid
|
---@return boolean success
|
||||||
function public.decode(frame)
|
function public.decode(frame)
|
||||||
if frame then
|
if frame then
|
||||||
self.frame = frame
|
self.frame = frame
|
||||||
|
|
||||||
if frame.protocol() == PROTOCOL.SCADA_MGMT then
|
if frame.protocol() == PROTOCOL.SCADA_MGMT then
|
||||||
if frame.length() >= 1 then
|
local ok = frame.length() >= 1
|
||||||
|
|
||||||
|
if ok then
|
||||||
local data = frame.data()
|
local data = frame.data()
|
||||||
|
public.make(data[1], { table.unpack(data, 2, #data) })
|
||||||
if public.make(data[1], { table.unpack(data, 2, #data) }) then
|
|
||||||
return public.get()
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
else log.debug("COMMS: attempted SCADA_MGMT parse of incorrect protocol " .. frame.protocol(), true) end
|
|
||||||
else log.debug("COMMS: nil frame encountered", true) end
|
|
||||||
|
|
||||||
return nil
|
return ok
|
||||||
|
else
|
||||||
|
log.debug("COMMS: attempted SCADA_MGMT parse of incorrect protocol " .. frame.protocol(), true)
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
else
|
||||||
|
log.debug("COMMS: nil frame encountered", true)
|
||||||
|
return false
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
-- get raw to send
|
-- get raw to send
|
||||||
@@ -655,7 +662,6 @@ function comms.crdn_packet()
|
|||||||
-- make a coordinator packet
|
-- make a coordinator packet
|
||||||
---@param packet_type CRDN_TYPE
|
---@param packet_type CRDN_TYPE
|
||||||
---@param data table
|
---@param data table
|
||||||
---@return boolean success
|
|
||||||
function public.make(packet_type, data)
|
function public.make(packet_type, data)
|
||||||
if type(data) == "table" then
|
if type(data) == "table" then
|
||||||
-- packet accessor properties
|
-- packet accessor properties
|
||||||
@@ -666,33 +672,35 @@ function comms.crdn_packet()
|
|||||||
-- populate raw array
|
-- populate raw array
|
||||||
self.raw = { self.type }
|
self.raw = { self.type }
|
||||||
for i = 1, #data do insert(self.raw, data[i]) end
|
for i = 1, #data do insert(self.raw, data[i]) end
|
||||||
|
else
|
||||||
return true
|
log.error("COMMS: crdn_packet.make(): data not a table")
|
||||||
end
|
end
|
||||||
|
|
||||||
log.error("COMMS: crdn_packet.make(): data not a table")
|
|
||||||
return false
|
|
||||||
end
|
end
|
||||||
|
|
||||||
-- decode a coordinator packet from a SCADA frame
|
-- decode a coordinator packet from a SCADA frame
|
||||||
---@param frame scada_packet
|
---@param frame scada_packet
|
||||||
---@return crdn_frame|nil frame the decoded frame, if valid
|
---@return boolean success
|
||||||
function public.decode(frame)
|
function public.decode(frame)
|
||||||
if frame then
|
if frame then
|
||||||
self.frame = frame
|
self.frame = frame
|
||||||
|
|
||||||
if frame.protocol() == PROTOCOL.SCADA_CRDN then
|
if frame.protocol() == PROTOCOL.SCADA_CRDN then
|
||||||
if frame.length() >= 1 then
|
local ok = frame.length() >= 1
|
||||||
|
|
||||||
|
if ok then
|
||||||
local data = frame.data()
|
local data = frame.data()
|
||||||
|
public.make(data[1], { table.unpack(data, 2, #data) })
|
||||||
if public.make(data[1], { table.unpack(data, 2, #data) }) then
|
|
||||||
return public.get()
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
else log.debug("COMMS: attempted SCADA_CRDN parse of incorrect protocol " .. frame.protocol(), true) end
|
|
||||||
else log.debug("COMMS: nil frame encountered", true) end
|
|
||||||
|
|
||||||
return nil
|
return ok
|
||||||
|
else
|
||||||
|
log.debug("COMMS: attempted SCADA_CRDN parse of incorrect protocol " .. frame.protocol(), true)
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
else
|
||||||
|
log.debug("COMMS: nil frame encountered", true)
|
||||||
|
return false
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
-- get raw to send
|
-- get raw to send
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ local t_pack = table.pack
|
|||||||
local util = {}
|
local util = {}
|
||||||
|
|
||||||
-- scada-common version
|
-- scada-common version
|
||||||
util.version = "1.6.1"
|
util.version = "1.6.0"
|
||||||
|
|
||||||
util.TICK_TIME_S = 0.05
|
util.TICK_TIME_S = 0.05
|
||||||
util.TICK_TIME_MS = 50
|
util.TICK_TIME_MS = 50
|
||||||
|
|||||||
@@ -6,10 +6,20 @@ local const = require("scada-common.constants")
|
|||||||
local psil = require("scada-common.psil")
|
local psil = require("scada-common.psil")
|
||||||
local util = require("scada-common.util")
|
local util = require("scada-common.util")
|
||||||
|
|
||||||
local pgi = require("supervisor.panel.pgi")
|
local pgi = require("supervisor.panel.pgi")
|
||||||
|
|
||||||
local databus = {}
|
local databus = {}
|
||||||
|
|
||||||
|
local _dbus = {
|
||||||
|
wd_modem = true,
|
||||||
|
wl_modem = true
|
||||||
|
}
|
||||||
|
|
||||||
|
-- evaluate and publish system health status
|
||||||
|
local function eval_status()
|
||||||
|
databus.ps.publish("status", _dbus.wd_modem and _dbus.wl_modem)
|
||||||
|
end
|
||||||
|
|
||||||
-- databus PSIL
|
-- databus PSIL
|
||||||
databus.ps = psil.create()
|
databus.ps = psil.create()
|
||||||
|
|
||||||
@@ -28,12 +38,18 @@ end
|
|||||||
---@param has_modem boolean
|
---@param has_modem boolean
|
||||||
function databus.tx_hw_wd_modem(has_modem)
|
function databus.tx_hw_wd_modem(has_modem)
|
||||||
databus.ps.publish("has_wd_modem", has_modem)
|
databus.ps.publish("has_wd_modem", has_modem)
|
||||||
|
|
||||||
|
_dbus.wd_modem = has_modem
|
||||||
|
eval_status()
|
||||||
end
|
end
|
||||||
|
|
||||||
-- transmit hardware status for the wireless comms modem
|
-- transmit hardware status for the wireless comms modem
|
||||||
---@param has_modem boolean
|
---@param has_modem boolean
|
||||||
function databus.tx_hw_wl_modem(has_modem)
|
function databus.tx_hw_wl_modem(has_modem)
|
||||||
databus.ps.publish("has_wl_modem", has_modem)
|
databus.ps.publish("has_wl_modem", has_modem)
|
||||||
|
|
||||||
|
_dbus.wl_modem = has_modem
|
||||||
|
eval_status()
|
||||||
end
|
end
|
||||||
|
|
||||||
-- transmit PLC firmware version and session connection state
|
-- transmit PLC firmware version and session connection state
|
||||||
|
|||||||
@@ -58,11 +58,11 @@ local function init(panel, config)
|
|||||||
|
|
||||||
local system = Div{parent=main_page,width=18,height=17,x=2,y=2}
|
local system = Div{parent=main_page,width=18,height=17,x=2,y=2}
|
||||||
|
|
||||||
local on = LED{parent=system,label="STATUS",colors=cpair(colors.green,colors.red)}
|
local status = LED{parent=system,label="STATUS",colors=cpair(colors.green,colors.red)}
|
||||||
local heartbeat = LED{parent=system,label="HEARTBEAT",colors=ind_grn}
|
local heartbeat = LED{parent=system,label="HEARTBEAT",colors=ind_grn}
|
||||||
on.update(true)
|
|
||||||
system.line_break()
|
system.line_break()
|
||||||
|
|
||||||
|
status.register(databus.ps, "status", status.update)
|
||||||
heartbeat.register(databus.ps, "heartbeat", heartbeat.update)
|
heartbeat.register(databus.ps, "heartbeat", heartbeat.update)
|
||||||
|
|
||||||
if config.WirelessModem and config.WiredModem then
|
if config.WirelessModem and config.WiredModem then
|
||||||
|
|||||||
@@ -413,14 +413,22 @@ function supervisor.comms(_version, fp_ok, facility)
|
|||||||
end
|
end
|
||||||
|
|
||||||
if s_pkt then
|
if s_pkt then
|
||||||
|
-- get as MODBUS TCP packet
|
||||||
if s_pkt.protocol() == PROTOCOL.MODBUS_TCP then
|
if s_pkt.protocol() == PROTOCOL.MODBUS_TCP then
|
||||||
pkt = comms.modbus_packet().decode(s_pkt)
|
local m_pkt = comms.modbus_packet()
|
||||||
|
if m_pkt.decode(s_pkt) then pkt = m_pkt.get() end
|
||||||
|
-- get as RPLC packet
|
||||||
elseif s_pkt.protocol() == PROTOCOL.RPLC then
|
elseif s_pkt.protocol() == PROTOCOL.RPLC then
|
||||||
pkt = comms.rplc_packet().decode(s_pkt)
|
local rplc_pkt = comms.rplc_packet()
|
||||||
|
if rplc_pkt.decode(s_pkt) then pkt = rplc_pkt.get() end
|
||||||
|
-- get as SCADA management packet
|
||||||
elseif s_pkt.protocol() == PROTOCOL.SCADA_MGMT then
|
elseif s_pkt.protocol() == PROTOCOL.SCADA_MGMT then
|
||||||
pkt = comms.mgmt_packet().decode(s_pkt)
|
local mgmt_pkt = comms.mgmt_packet()
|
||||||
|
if mgmt_pkt.decode(s_pkt) then pkt = mgmt_pkt.get() end
|
||||||
|
-- get as coordinator packet
|
||||||
elseif s_pkt.protocol() == PROTOCOL.SCADA_CRDN then
|
elseif s_pkt.protocol() == PROTOCOL.SCADA_CRDN then
|
||||||
pkt = comms.crdn_packet().decode(s_pkt)
|
local crdn_pkt = comms.crdn_packet()
|
||||||
|
if crdn_pkt.decode(s_pkt) then pkt = crdn_pkt.get() end
|
||||||
else
|
else
|
||||||
log.debug("parse_packet(" .. side .. "): attempted parse of illegal packet type " .. s_pkt.protocol(), true)
|
log.debug("parse_packet(" .. side .. "): attempted parse of illegal packet type " .. s_pkt.protocol(), true)
|
||||||
end
|
end
|
||||||
|
|||||||
Reference in New Issue
Block a user