#580 work on reactor PLC wired comms

This commit is contained in:
Mikayla 2025-10-26 20:54:09 +00:00
parent b57aceff15
commit c62eaeb5a2
6 changed files with 284 additions and 146 deletions

189
reactor-plc/backplane.lua Normal file
View File

@ -0,0 +1,189 @@
--
-- Reactor PLC System Core Peripheral Backplane
--
local log = require("scada-common.log")
local network = require("scada-common.network")
local ppm = require("scada-common.ppm")
local util = require("scada-common.util")
local databus = require("reactor-plc.databus")
local plc = require("reactor-plc.plc")
local println = util.println
---@class plc_backplane
local backplane = {}
local _bp = {
smem = nil, ---@type plc_shared_memory
wlan_pref = true,
lan_iface = "",
act_nic = nil, ---@type nic
wl_act = true,
wd_nic = nil, ---@type nic|nil
wl_nic = nil ---@type nic|nil
}
-- initialize the system peripheral backplane<br>
---@param config plc_config
---@param __shared_memory plc_shared_memory
--- EVENT_CONSUMER: this function consumes events
function backplane.init(config, __shared_memory)
_bp.smem = __shared_memory
_bp.wlan_pref = config.PreferWireless
_bp.lan_iface = config.WiredModem
local plc_dev = __shared_memory.plc_dev
local plc_state = __shared_memory.plc_state
-- Modem Init
-- init wired NIC
if type(config.WiredModem) == "string" then
local modem = ppm.get_modem(_bp.lan_iface)
_bp.wd_nic = network.nic(modem)
log.info("BKPLN: WIRED PHY_" .. util.trinary(modem, "UP ", "DOWN ") .. _bp.lan_iface)
-- set this as active for now
_bp.wl_act = false
_bp.act_nic = _bp.wd_nic
end
-- init wireless NIC(s)
if config.WirelessModem then
local modem, iface = ppm.get_wireless_modem()
_bp.wl_nic = network.nic(modem)
log.info("BKPLN: WIRELESS PHY_" .. util.trinary(modem, "UP ", "DOWN ") .. iface)
-- set this as active if connected or if both modems are disconnected and this is preferred
if (modem and _bp.wlan_pref) or not (_bp.act_nic and _bp.act_nic.is_connected()) then
_bp.wl_act = true
_bp.act_nic = _bp.wl_nic
end
end
plc_state.no_modem = not _bp.act_nic.is_connected()
databus.tx_hw_modem(not plc_state.no_modem)
-- comms modem is required if networked
if __shared_memory.networked and plc_state.no_modem then
println("startup> comms modem not found")
log.warning("BKPLN: no comms modem on startup")
plc_state.degraded = true
end
-- Reactor Init
---@diagnostic disable-next-line: assign-type-mismatch
plc_dev.reactor = ppm.get_fission_reactor()
plc_state.no_reactor = plc_dev.reactor == nil
-- we need a reactor, can at least do some things even if it isn't formed though
if plc_state.no_reactor then
println("startup> fission reactor not found")
log.warning("BKPLN: no reactor on startup")
plc_state.degraded = true
plc_state.reactor_formed = false
-- mount a virtual peripheral to init the RPS with
local _, dev = ppm.mount_virtual()
plc_dev.reactor = dev
log.info("BKPLN: mounted virtual device as reactor")
elseif not plc_dev.reactor.isFormed() then
println("startup> fission reactor is not formed")
log.warning("BKPLN: reactor logic adapter present, but reactor is not formed")
plc_state.degraded = true
plc_state.reactor_formed = false
else
log.info("BKPLN: reactor detected")
end
end
-- get the active NIC
---@return nic|nil
function backplane.active_nic() return _bp.act_nic end
-- handle a backplane peripheral attach
---@param iface string
---@param type string
---@param device table
---@param print_no_fp function
function backplane.attach(iface, type, device, print_no_fp)
local networked = _bp.smem.networked
local state = _bp.smem.plc_state
local dev = _bp.smem.plc_dev
local sys = _bp.smem.plc_sys
if state.no_reactor and (type == "fissionReactorLogicAdapter") then
-- reconnected reactor
dev.reactor = device
state.no_reactor = false
print_no_fp("reactor reconnected")
log.info("BKPLN: reactor reconnected")
-- we need to assume formed here as we cannot check in this main loop
-- RPS will identify if it isn't and this will get set false later
state.reactor_formed = true
-- determine if we are still in a degraded state
if (not networked or not state.no_modem) and state.reactor_formed then
state.degraded = false
end
_bp.smem.q.mq_rps.push_command(MQ__RPS_CMD.SCRAM)
sys.rps.reconnect_reactor(dev.reactor)
if networked then
sys.plc_comms.reconnect_reactor(dev.reactor)
end
-- partial reset of RPS, specific to becoming formed/reconnected
-- without this, auto control can't resume on chunk load
sys.rps.reset_formed()
elseif networked and type == "modem" then
---@cast device Modem
local is_comms_modem = util.trinary(dev.modem_wired, dev.modem_iface == iface, device.isWireless())
-- note, check init_ok first since nic will be nil if it is false
if is_comms_modem and not (state.init_ok and nic.is_connected()) then
-- reconnected modem
dev.modem = device
state.no_modem = false
if state.init_ok then nic.connect(device) end
print_no_fp("comms modem reconnected")
log.info("comms modem reconnected")
-- determine if we are still in a degraded state
if not state.no_reactor then
state.degraded = false
end
elseif device.isWireless() then
log.info("unused wireless modem connected")
else
log.info("non-comms wired modem connected")
end
end
end
-- handle a backplane peripheral detach
---@param iface string
---@param type string
---@param device table
---@param print_no_fp function
function backplane.detach(iface, type, device, print_no_fp)
end
return backplane

View File

@ -81,7 +81,9 @@ local tmp_cfg = {
SVR_Channel = nil, ---@type integer SVR_Channel = nil, ---@type integer
PLC_Channel = nil, ---@type integer PLC_Channel = nil, ---@type integer
ConnTimeout = nil, ---@type number ConnTimeout = nil, ---@type number
WirelessModem = true,
WiredModem = false, ---@type string|false WiredModem = false, ---@type string|false
PreferWireless = true,
TrustedRange = nil, ---@type number TrustedRange = nil, ---@type number
AuthKey = "", ---@type string AuthKey = "", ---@type string
LogMode = 0, ---@type LOG_MODE LogMode = 0, ---@type LOG_MODE
@ -107,7 +109,9 @@ local fields = {
{ "SVR_Channel", "SVR Channel", 16240 }, { "SVR_Channel", "SVR Channel", 16240 },
{ "PLC_Channel", "PLC Channel", 16241 }, { "PLC_Channel", "PLC Channel", 16241 },
{ "ConnTimeout", "Connection Timeout", 5 }, { "ConnTimeout", "Connection Timeout", 5 },
{ "WiredModem", "Wired Modem", false }, { "WirelessModem", "Wireless/Ender Comms Modem", true },
{ "WiredModem", "Wired Comms Modem", false },
{ "PreferWireless", "Prefer Wireless Modem", true },
{ "TrustedRange", "Trusted Range", 0 }, { "TrustedRange", "Trusted Range", 0 },
{ "AuthKey", "Facility Auth Key" , ""}, { "AuthKey", "Facility Auth Key" , ""},
{ "LogMode", "Log Mode", log.MODE.APPEND }, { "LogMode", "Log Mode", log.MODE.APPEND },

View File

@ -48,7 +48,9 @@ function plc.load_config()
config.SVR_Channel = settings.get("SVR_Channel") config.SVR_Channel = settings.get("SVR_Channel")
config.PLC_Channel = settings.get("PLC_Channel") config.PLC_Channel = settings.get("PLC_Channel")
config.ConnTimeout = settings.get("ConnTimeout") config.ConnTimeout = settings.get("ConnTimeout")
config.WirelessModem = settings.get("WirelessModem")
config.WiredModem = settings.get("WiredModem") config.WiredModem = settings.get("WiredModem")
config.PreferWireless = settings.get("PreferWireless")
config.TrustedRange = settings.get("TrustedRange") config.TrustedRange = settings.get("TrustedRange")
config.AuthKey = settings.get("AuthKey") config.AuthKey = settings.get("AuthKey")
@ -71,12 +73,15 @@ function plc.validate_config(cfg)
cfv.assert_type_int(cfg.UnitID) cfv.assert_type_int(cfg.UnitID)
cfv.assert_type_bool(cfg.EmerCoolEnable) cfv.assert_type_bool(cfg.EmerCoolEnable)
if cfg.Networked == true then if cfg.Networked then
cfv.assert_channel(cfg.SVR_Channel) cfv.assert_channel(cfg.SVR_Channel)
cfv.assert_channel(cfg.PLC_Channel) cfv.assert_channel(cfg.PLC_Channel)
cfv.assert_type_num(cfg.ConnTimeout) cfv.assert_type_num(cfg.ConnTimeout)
cfv.assert_min(cfg.ConnTimeout, 2) cfv.assert_min(cfg.ConnTimeout, 2)
cfv.assert_type_bool(cfg.WirelessModem)
cfv.assert((cfg.WiredModem == false) or (type(cfg.WiredModem) == "string")) cfv.assert((cfg.WiredModem == false) or (type(cfg.WiredModem) == "string"))
cfv.assert(cfg.WirelessModem or (type(cfg.WiredModem) == "string"))
cfv.assert_type_bool(cfg.PreferWireless)
cfv.assert_type_num(cfg.TrustedRange) cfv.assert_type_num(cfg.TrustedRange)
cfv.assert_min(cfg.TrustedRange, 0) cfv.assert_min(cfg.TrustedRange, 0)
cfv.assert_type_str(cfg.AuthKey) cfv.assert_type_str(cfg.AuthKey)

View File

@ -3,6 +3,7 @@
-- --
require("/initenv").init_env() require("/initenv").init_env()
local backplane = require("reactor-plc.backplane")
local comms = require("scada-common.comms") local comms = require("scada-common.comms")
local crash = require("scada-common.crash") local crash = require("scada-common.crash")
@ -87,7 +88,6 @@ local function main()
-- PLC system state flags -- PLC system state flags
---@class plc_state ---@class plc_state
plc_state = { plc_state = {
init_ok = true,
fp_ok = false, fp_ok = false,
shutdown = false, shutdown = false,
degraded = true, degraded = true,
@ -103,15 +103,14 @@ local function main()
burn_rate = 0.0 burn_rate = 0.0
}, },
-- core PLC devices -- global PLC devices, still initialized by the backplane
---@class plc_dev
plc_dev = { plc_dev = {
reactor = ppm.get_fission_reactor(), reactor = nil ---@type table
modem_wired = type(config.WiredModem) == "string",
modem_iface = config.WiredModem,
modem = nil
}, },
-- system objects -- system objects
---@class plc_sys
plc_sys = { plc_sys = {
rps = nil, ---@type rps rps = nil, ---@type rps
nic = nil, ---@type nic nic = nil, ---@type nic
@ -132,115 +131,66 @@ local function main()
local plc_state = __shared_memory.plc_state local plc_state = __shared_memory.plc_state
-- get the configured modem -- reactor and modem initialization
if smem_dev.modem_wired then backplane.init(config, __shared_memory)
smem_dev.modem = ppm.get_modem(smem_dev.modem_iface)
else smem_dev.modem = ppm.get_wireless_modem() end
-- initial state evaluation
plc_state.no_reactor = smem_dev.reactor == nil
plc_state.no_modem = smem_dev.modem == nil
-- we need a reactor, can at least do some things even if it isn't formed though
if plc_state.no_reactor then
println("init> fission reactor not found")
log.warning("init> no reactor on startup")
plc_state.init_ok = false
plc_state.degraded = true
elseif not smem_dev.reactor.isFormed() then
println("init> fission reactor is not formed")
log.warning("init> reactor logic adapter present, but reactor is not formed")
plc_state.degraded = true
plc_state.reactor_formed = false
end
-- comms modem is required if networked
if __shared_memory.networked and plc_state.no_modem then
println("init> comms modem not found")
log.warning("init> no comms modem on startup")
-- scram reactor if present and enabled
if (smem_dev.reactor ~= nil) and plc_state.reactor_formed and smem_dev.reactor.getStatus() then
smem_dev.reactor.scram()
end
plc_state.init_ok = false
plc_state.degraded = true
end
-- print a log message to the terminal as long as the UI isn't running
local function _println_no_fp(message) if not plc_state.fp_ok then println(message) end end
-- PLC init<br>
--- EVENT_CONSUMER: this function consumes events
local function init()
-- scram on boot if networked, otherwise leave the reactor be -- scram on boot if networked, otherwise leave the reactor be
if __shared_memory.networked and (not plc_state.no_reactor) and plc_state.reactor_formed and smem_dev.reactor.getStatus() then if __shared_memory.networked and (not plc_state.no_reactor) and plc_state.reactor_formed and smem_dev.reactor.getStatus() then
log.debug("startup> power-on SCRAM")
smem_dev.reactor.scram() smem_dev.reactor.scram()
end end
-- setup front panel -- setup front panel
if not renderer.ui_ready() then
local message local message
plc_state.fp_ok, message = renderer.try_start_ui(config.FrontPanelTheme, config.ColorMode) plc_state.fp_ok, message = renderer.try_start_ui(config.FrontPanelTheme, config.ColorMode)
-- ...or not -- ...or not
if not plc_state.fp_ok then if not plc_state.fp_ok then
println_ts(util.c("UI error: ", message)) println_ts(util.c("UI error: ", message))
println("init> running without front panel") println("startup> running without front panel")
log.error(util.c("front panel GUI render failed with error ", message)) log.error(util.c("front panel GUI render failed with error ", message))
log.info("init> running in headless mode without front panel") log.info("startup> running in headless mode without front panel")
end
end end
if plc_state.init_ok then -- print a log message to the terminal as long as the UI isn't running
local function _println_no_fp(msg) if not plc_state.fp_ok then println(msg) end end
----------------------------------------
-- initialize PLC
----------------------------------------
-- init reactor protection system -- init reactor protection system
smem_sys.rps = plc.rps_init(smem_dev.reactor, plc_state.reactor_formed) smem_sys.rps = plc.rps_init(smem_dev.reactor, plc_state.reactor_formed)
log.debug("init> rps init") log.debug("startup> rps init")
if __shared_memory.networked then
-- comms watchdog
smem_sys.conn_watchdog = util.new_watchdog(config.ConnTimeout)
log.debug("init> conn watchdog started")
-- create network interface then setup comms
smem_sys.nic = network.nic(smem_dev.modem)
smem_sys.plc_comms = plc.comms(R_PLC_VERSION, smem_sys.nic, smem_dev.reactor, smem_sys.rps, smem_sys.conn_watchdog)
log.debug("init> comms init")
else
_println_no_fp("init> starting in offline mode")
log.info("init> running without networking")
end
-- notify user of emergency coolant configuration status -- notify user of emergency coolant configuration status
if config.EmerCoolEnable then if config.EmerCoolEnable then
println("init> emergency coolant control ready") _println_no_fp("startup> emergency coolant control ready")
log.info("init> running with emergency coolant control available") log.info("startup> emergency coolant control available")
end end
util.push_event("clock_start") -- conditionally init comms
if __shared_memory.networked then
-- comms watchdog
smem_sys.conn_watchdog = util.new_watchdog(config.ConnTimeout)
log.debug("startup> conn watchdog started")
_println_no_fp("init> completed") -- create network interface then setup comms
log.info("init> startup completed") smem_sys.nic = network.nic(backplane.active_nic())
smem_sys.plc_comms = plc.comms(R_PLC_VERSION, smem_sys.nic, smem_dev.reactor, smem_sys.rps, smem_sys.conn_watchdog)
log.debug("startup> comms init")
else else
_println_no_fp("init> system in degraded state, awaiting devices...") _println_no_fp("startup> starting in non-networked mode")
log.warning("init> started in a degraded state, awaiting peripheral connections...") log.info("startup> starting without networking")
end end
databus.tx_hw_status(plc_state) databus.tx_hw_status(plc_state)
end
---------------------------------------- _println_no_fp("startup> completed")
-- start system log.info("startup> completed")
----------------------------------------
-- initialize PLC
init()
-- init threads -- init threads
local main_thread = threads.thread__main(__shared_memory, init) local main_thread = threads.thread__main(__shared_memory)
local rps_thread = threads.thread__rps(__shared_memory) local rps_thread = threads.thread__rps(__shared_memory)
if __shared_memory.networked then if __shared_memory.networked then
@ -254,14 +204,12 @@ local function main()
-- run threads -- run threads
parallel.waitForAll(main_thread.p_exec, rps_thread.p_exec, comms_thread_tx.p_exec, comms_thread_rx.p_exec, sp_ctrl_thread.p_exec) parallel.waitForAll(main_thread.p_exec, rps_thread.p_exec, comms_thread_tx.p_exec, comms_thread_rx.p_exec, sp_ctrl_thread.p_exec)
if plc_state.init_ok then
-- send status one last time after RPS shutdown -- send status one last time after RPS shutdown
smem_sys.plc_comms.send_status(plc_state.no_reactor, plc_state.reactor_formed) smem_sys.plc_comms.send_status(plc_state.no_reactor, plc_state.reactor_formed)
smem_sys.plc_comms.send_rps_status() smem_sys.plc_comms.send_rps_status()
-- close connection -- close connection
smem_sys.plc_comms.close() smem_sys.plc_comms.close()
end
else else
-- run threads, excluding comms -- run threads, excluding comms
parallel.waitForAll(main_thread.p_exec, rps_thread.p_exec) parallel.waitForAll(main_thread.p_exec, rps_thread.p_exec)

View File

@ -31,8 +31,7 @@ local MQ__COMM_CMD = {
-- main thread -- main thread
---@nodiscard ---@nodiscard
---@param smem plc_shared_memory ---@param smem plc_shared_memory
---@param init function function threads.thread__main(smem)
function threads.thread__main(smem, init)
-- print a log message to the terminal as long as the UI isn't running -- print a log message to the terminal as long as the UI isn't running
local function println_ts(message) if not smem.plc_state.fp_ok then util.println_ts(message) end end local function println_ts(message) if not smem.plc_state.fp_ok then util.println_ts(message) end end
@ -42,7 +41,7 @@ function threads.thread__main(smem, init)
-- execute thread -- execute thread
function public.exec() function public.exec()
databus.tx_rt_status("main", true) databus.tx_rt_status("main", true)
log.debug("main thread init, clock inactive") log.debug("main thread start")
-- send status updates at 2Hz (every 10 server ticks) (every loop tick) -- send status updates at 2Hz (every 10 server ticks) (every loop tick)
-- send link requests at 0.5Hz (every 40 server ticks) (every 8 loop ticks) -- send link requests at 0.5Hz (every 40 server ticks) (every 8 loop ticks)
@ -55,6 +54,9 @@ function threads.thread__main(smem, init)
local plc_state = smem.plc_state local plc_state = smem.plc_state
local plc_dev = smem.plc_dev local plc_dev = smem.plc_dev
-- start clock
loop_clock.start()
-- event loop -- event loop
while true do while true do
-- get plc_sys fields (may have been set late due to degraded boot) -- get plc_sys fields (may have been set late due to degraded boot)
@ -67,7 +69,6 @@ function threads.thread__main(smem, init)
-- handle event -- handle event
if event == "timer" and loop_clock.is_clock(param1) then if event == "timer" and loop_clock.is_clock(param1) then
-- note: loop clock is only running if init_ok = true
-- blink heartbeat indicator -- blink heartbeat indicator
databus.heartbeat() databus.heartbeat()
@ -118,14 +119,14 @@ function threads.thread__main(smem, init)
-- update indicators -- update indicators
databus.tx_hw_status(plc_state) databus.tx_hw_status(plc_state)
elseif event == "modem_message" and networked and plc_state.init_ok and nic.is_connected() then elseif event == "modem_message" and networked and nic.is_connected() then
-- got a packet -- got a packet
local packet = plc_comms.parse_packet(param1, param2, param3, param4, param5) local packet = plc_comms.parse_packet(param1, param2, param3, param4, param5)
if packet ~= nil then if packet ~= nil then
-- pass the packet onto the comms message queue -- pass the packet onto the comms message queue
smem.q.mq_comms_rx.push_packet(packet) smem.q.mq_comms_rx.push_packet(packet)
end end
elseif event == "timer" and networked and plc_state.init_ok and conn_watchdog.is_timer(param1) then elseif event == "timer" and networked and conn_watchdog.is_timer(param1) then
-- haven't heard from server recently? close connection and shutdown reactor -- haven't heard from server recently? close connection and shutdown reactor
plc_comms.close() plc_comms.close()
smem.q.mq_rps.push_command(MQ__RPS_CMD.TRIP_TIMEOUT) smem.q.mq_rps.push_command(MQ__RPS_CMD.TRIP_TIMEOUT)
@ -146,8 +147,7 @@ function threads.thread__main(smem, init)
elseif networked and type == "modem" then elseif networked and type == "modem" then
---@cast device Modem ---@cast device Modem
-- we only care if this is our comms modem -- we only care if this is our comms modem
-- note, check init_ok first since nic will be nil if it is false if nic.is_modem(device) then
if plc_state.init_ok and nic.is_modem(device) then
nic.disconnect() nic.disconnect()
println_ts("comms modem disconnected!") println_ts("comms modem disconnected!")
@ -184,7 +184,7 @@ function threads.thread__main(smem, init)
plc_dev.reactor = device plc_dev.reactor = device
plc_state.no_reactor = false plc_state.no_reactor = false
println_ts("reactor reconnected.") println_ts("reactor reconnected")
log.info("reactor reconnected") log.info("reactor reconnected")
-- we need to assume formed here as we cannot check in this main loop -- we need to assume formed here as we cannot check in this main loop
@ -220,7 +220,7 @@ function threads.thread__main(smem, init)
if plc_state.init_ok then nic.connect(device) end if plc_state.init_ok then nic.connect(device) end
println_ts("comms modem reconnected.") println_ts("comms modem reconnected")
log.info("comms modem reconnected") log.info("comms modem reconnected")
-- determine if we are still in a degraded state -- determine if we are still in a degraded state
@ -235,22 +235,12 @@ function threads.thread__main(smem, init)
end end
end end
-- if not init'd and no longer degraded, proceed to init
if not plc_state.init_ok and not plc_state.degraded then
plc_state.init_ok = true
init()
end
-- update indicators -- update indicators
databus.tx_hw_status(plc_state) databus.tx_hw_status(plc_state)
elseif event == "mouse_click" or event == "mouse_up" or event == "mouse_drag" or event == "mouse_scroll" or elseif event == "mouse_click" or event == "mouse_up" or event == "mouse_drag" or event == "mouse_scroll" or
event == "double_click" then event == "double_click" then
-- handle a mouse event -- handle a mouse event
renderer.handle_mouse(core.events.new_mouse_event(event, param1, param2, param3)) renderer.handle_mouse(core.events.new_mouse_event(event, param1, param2, param3))
elseif event == "clock_start" then
-- start loop clock
loop_clock.start()
log.debug("main thread clock started")
end end
-- check for termination request -- check for termination request
@ -280,7 +270,6 @@ function threads.thread__main(smem, init)
-- this thread cannot be slept because it will miss events (namely "terminate" otherwise) -- this thread cannot be slept because it will miss events (namely "terminate" otherwise)
if not plc_state.shutdown then if not plc_state.shutdown then
log.info("main thread restarting now...") log.info("main thread restarting now...")
util.push_event("clock_start")
end end
end end
end end
@ -399,15 +388,15 @@ function threads.thread__rps(smem)
if plc_state.shutdown then if plc_state.shutdown then
-- safe exit -- safe exit
log.info("rps thread shutdown initiated") log.info("rps thread shutdown initiated")
if plc_state.init_ok then
if rps.scram() then if rps.scram() then
println_ts("reactor disabled") println_ts("exiting, reactor disabled")
log.info("rps thread reactor SCRAM OK") log.info("rps thread reactor SCRAM OK")
else else
println_ts("exiting, reactor failed to disable") println_ts("exiting, reactor failed to disable")
log.error("rps thread failed to SCRAM reactor on exit") log.error("rps thread failed to SCRAM reactor on exit")
end end
end
log.info("rps thread exiting") log.info("rps thread exiting")
break break
end end
@ -430,7 +419,7 @@ function threads.thread__rps(smem)
databus.tx_rt_status("rps", false) databus.tx_rt_status("rps", false)
if not plc_state.shutdown then if not plc_state.shutdown then
if plc_state.init_ok then smem.plc_sys.rps.scram() end smem.plc_sys.rps.scram()
log.info("rps thread restarting in 5 seconds...") log.info("rps thread restarting in 5 seconds...")
util.psleep(5) util.psleep(5)
end end

View File

@ -78,7 +78,7 @@ end
-- NIC: Network Interface Controller<br> -- NIC: Network Interface Controller<br>
-- utilizes HMAC-MD5 for message authentication, if enabled and this is wireless -- utilizes HMAC-MD5 for message authentication, if enabled and this is wireless
---@param modem Modem modem to use ---@param modem Modem|nil modem to use
function network.nic(modem) function network.nic(modem)
local self = { local self = {
-- modem interface name -- modem interface name
@ -86,9 +86,9 @@ function network.nic(modem)
-- phy name -- phy name
name = "?", name = "?",
-- used to quickly return out of tx/rx functions if there is nothing to do -- used to quickly return out of tx/rx functions if there is nothing to do
connected = true, connected = false,
-- used to avoid costly MAC calculations if not required -- used to avoid costly MAC calculations if not required
use_hash = c_eng.hmac and modem.isWireless(), use_hash = false,
-- open channels -- open channels
channels = {} channels = {}
} }
@ -135,13 +135,13 @@ function network.nic(modem)
function public.is_modem(device) return device == modem end function public.is_modem(device) return device == modem end
-- wrap modem functions, then create custom functions -- wrap modem functions, then create custom functions
public.connect(modem) if modem then public.connect(modem) end
-- open a channel on the modem<br> -- open a channel on the modem<br>
-- if disconnected *after* opening, previousy opened channels will be re-opened on reconnection -- if disconnected *after* opening, previousy opened channels will be re-opened on reconnection
---@param channel integer ---@param channel integer
function public.open(channel) function public.open(channel)
modem.open(channel) if modem then modem.open(channel) end
local already_open = false local already_open = false
for i = 1, #self.channels do for i = 1, #self.channels do
@ -159,7 +159,7 @@ function network.nic(modem)
-- close a channel on the modem -- close a channel on the modem
---@param channel integer ---@param channel integer
function public.close(channel) function public.close(channel)
modem.close(channel) if modem then modem.close(channel) end
for i = 1, #self.channels do for i = 1, #self.channels do
if self.channels[i] == channel then if self.channels[i] == channel then
@ -171,7 +171,7 @@ function network.nic(modem)
-- close all channels on the modem -- close all channels on the modem
function public.closeAll() function public.closeAll()
modem.closeAll() if modem then modem.closeAll() end
self.channels = {} self.channels = {}
end end
@ -193,7 +193,10 @@ function network.nic(modem)
-- log.debug("network.modem.transmit: data processing took " .. (util.time_ms() - start) .. "ms") -- log.debug("network.modem.transmit: data processing took " .. (util.time_ms() - start) .. "ms")
end end
---@diagnostic disable-next-line: need-check-nil
modem.transmit(dest_channel, local_channel, tx_packet.raw_sendable()) modem.transmit(dest_channel, local_channel, tx_packet.raw_sendable())
else
log.debug("network.transmit tx dropped, link is down")
end end
end end