From 1a01bec7e41daea02b5a248754fc0a55b9f637ee Mon Sep 17 00:00:00 2001 From: Mikayla Fischler Date: Sat, 12 Nov 2022 01:35:31 -0500 Subject: [PATCH] #123 RTU startup without devices, fixed repeat RTU advert handling, added PPM virtual devices, fixed log out of space detection, updated RTU type conversion functions in comms --- coordinator/startup.lua | 2 +- reactor-plc/startup.lua | 2 +- rtu/startup.lua | 172 ++++++++++++------------ rtu/threads.lua | 44 +++++- scada-common/comms.lua | 12 ++ scada-common/log.lua | 11 +- scada-common/ppm.lua | 26 +++- supervisor/session/rtu.lua | 16 ++- supervisor/session/rtu/boilerv.lua | 2 +- supervisor/session/rtu/envd.lua | 2 +- supervisor/session/rtu/imatrix.lua | 2 +- supervisor/session/rtu/redstone.lua | 2 +- supervisor/session/rtu/sna.lua | 2 +- supervisor/session/rtu/sps.lua | 2 +- supervisor/session/rtu/turbinev.lua | 2 +- supervisor/session/rtu/unit_session.lua | 5 +- supervisor/session/unit.lua | 8 ++ supervisor/startup.lua | 2 +- 18 files changed, 205 insertions(+), 109 deletions(-) diff --git a/coordinator/startup.lua b/coordinator/startup.lua index 3792eb7..fa3576f 100644 --- a/coordinator/startup.lua +++ b/coordinator/startup.lua @@ -16,7 +16,7 @@ local config = require("coordinator.config") local coordinator = require("coordinator.coordinator") local renderer = require("coordinator.renderer") -local COORDINATOR_VERSION = "alpha-v0.6.9" +local COORDINATOR_VERSION = "alpha-v0.6.10" local print = util.print local println = util.println diff --git a/reactor-plc/startup.lua b/reactor-plc/startup.lua index 6af916a..785d668 100644 --- a/reactor-plc/startup.lua +++ b/reactor-plc/startup.lua @@ -13,7 +13,7 @@ local config = require("reactor-plc.config") local plc = require("reactor-plc.plc") local threads = require("reactor-plc.threads") -local R_PLC_VERSION = "beta-v0.9.4" +local R_PLC_VERSION = "beta-v0.9.5" local print = util.print local println = util.println diff --git a/rtu/startup.lua b/rtu/startup.lua index 12a166d..e50c93f 100644 --- a/rtu/startup.lua +++ b/rtu/startup.lua @@ -24,7 +24,7 @@ local sna_rtu = require("rtu.dev.sna_rtu") local sps_rtu = require("rtu.dev.sps_rtu") local turbinev_rtu = require("rtu.dev.turbinev_rtu") -local RTU_VERSION = "beta-v0.9.1" +local RTU_VERSION = "beta-v0.9.2" local rtu_t = types.rtu_t @@ -257,98 +257,104 @@ local function configure() local device = ppm.get_periph(name) + local type = nil + local rtu_iface = nil ---@type rtu_device + local rtu_type = "" + local formed = nil ---@type boolean|nil + if device == nil then - local message = util.c("configure> '", name, "' not found") + local message = util.c("configure> '", name, "' not found, using placeholder") println(message) - log.fatal(message) - return false + log.warning(message) + + -- mount a virtual (placeholder) device + type, device = ppm.mount_virtual() else - local type = ppm.get_type(name) - local rtu_iface = nil ---@type rtu_device - local rtu_type = "" - local formed = nil ---@type boolean|nil + type = ppm.get_type(name) + end - if type == "boilerValve" then - -- boiler multiblock - rtu_type = rtu_t.boiler_valve - rtu_iface = boilerv_rtu.new(device) - formed = device.isFormed() + if type == "boilerValve" then + -- boiler multiblock + rtu_type = rtu_t.boiler_valve + rtu_iface = boilerv_rtu.new(device) + formed = device.isFormed() - if formed == ppm.UNDEFINED_FIELD or formed == ppm.ACCESS_FAULT then - println_ts(util.c("configure> failed to check if '", name, "' is formed")) - log.fatal(util.c("configure> failed to check if '", name, "' is a formed boiler multiblock")) - return false - end - elseif type == "turbineValve" then - -- turbine multiblock - rtu_type = rtu_t.turbine_valve - rtu_iface = turbinev_rtu.new(device) - formed = device.isFormed() - - if formed == ppm.UNDEFINED_FIELD or formed == ppm.ACCESS_FAULT then - println_ts(util.c("configure> failed to check if '", name, "' is formed")) - log.fatal(util.c("configure> failed to check if '", name, "' is a formed turbine multiblock")) - return false - end - elseif type == "inductionPort" then - -- induction matrix multiblock - rtu_type = rtu_t.induction_matrix - rtu_iface = imatrix_rtu.new(device) - formed = device.isFormed() - - if formed == ppm.UNDEFINED_FIELD or formed == ppm.ACCESS_FAULT then - println_ts(util.c("configure> failed to check if '", name, "' is formed")) - log.fatal(util.c("configure> failed to check if '", name, "' is a formed induction matrix multiblock")) - return false - end - elseif type == "spsPort" then - -- SPS multiblock - rtu_type = rtu_t.sps - rtu_iface = sps_rtu.new(device) - formed = device.isFormed() - - if formed == ppm.UNDEFINED_FIELD or formed == ppm.ACCESS_FAULT then - println_ts(util.c("configure> failed to check if '", name, "' is formed")) - log.fatal(util.c("configure> failed to check if '", name, "' is a formed SPS multiblock")) - return false - end - elseif type == "solarNeutronActivator" then - -- SNA - rtu_type = rtu_t.sna - rtu_iface = sna_rtu.new(device) - elseif type == "environmentDetector" then - -- advanced peripherals environment detector - rtu_type = rtu_t.env_detector - rtu_iface = envd_rtu.new(device) - else - local message = util.c("configure> device '", name, "' is not a known type (", type, ")") - println_ts(message) - log.fatal(message) + if formed == ppm.UNDEFINED_FIELD or formed == ppm.ACCESS_FAULT then + println_ts(util.c("configure> failed to check if '", name, "' is formed")) + log.fatal(util.c("configure> failed to check if '", name, "' is a formed boiler multiblock")) return false end + elseif type == "turbineValve" then + -- turbine multiblock + rtu_type = rtu_t.turbine_valve + rtu_iface = turbinev_rtu.new(device) + formed = device.isFormed() - if rtu_iface ~= nil then - ---@class rtu_unit_registry_entry - local rtu_unit = { - name = name, - type = rtu_type, - index = index, - reactor = for_reactor, - device = device, - formed = formed, - rtu = rtu_iface, ---@type rtu_device|rtu_rs_device - modbus_io = modbus.new(rtu_iface, true), - pkt_queue = mqueue.new(), ---@type mqueue|nil - thread = nil - } - - rtu_unit.thread = threads.thread__unit_comms(__shared_memory, rtu_unit) - - table.insert(units, rtu_unit) - - log.debug(util.c("configure> initialized RTU unit #", #units, ": ", name, " (", rtu_type, ") [", index, "] for reactor ", for_reactor)) + if formed == ppm.UNDEFINED_FIELD or formed == ppm.ACCESS_FAULT then + println_ts(util.c("configure> failed to check if '", name, "' is formed")) + log.fatal(util.c("configure> failed to check if '", name, "' is a formed turbine multiblock")) + return false end + elseif type == "inductionPort" then + -- induction matrix multiblock + rtu_type = rtu_t.induction_matrix + rtu_iface = imatrix_rtu.new(device) + formed = device.isFormed() + + if formed == ppm.UNDEFINED_FIELD or formed == ppm.ACCESS_FAULT then + println_ts(util.c("configure> failed to check if '", name, "' is formed")) + log.fatal(util.c("configure> failed to check if '", name, "' is a formed induction matrix multiblock")) + return false + end + elseif type == "spsPort" then + -- SPS multiblock + rtu_type = rtu_t.sps + rtu_iface = sps_rtu.new(device) + formed = device.isFormed() + + if formed == ppm.UNDEFINED_FIELD or formed == ppm.ACCESS_FAULT then + println_ts(util.c("configure> failed to check if '", name, "' is formed")) + log.fatal(util.c("configure> failed to check if '", name, "' is a formed SPS multiblock")) + return false + end + elseif type == "solarNeutronActivator" then + -- SNA + rtu_type = rtu_t.sna + rtu_iface = sna_rtu.new(device) + elseif type == "environmentDetector" then + -- advanced peripherals environment detector + rtu_type = rtu_t.env_detector + rtu_iface = envd_rtu.new(device) + elseif type == ppm.VIRTUAL_DEVICE_TYPE then + -- placeholder device + rtu_type = "virtual" + rtu_iface = rtu.init_unit().interface() + else + local message = util.c("configure> device '", name, "' is not a known type (", type, ")") + println_ts(message) + log.fatal(message) + return false end + + ---@class rtu_unit_registry_entry + local rtu_unit = { + name = name, + type = rtu_type, + index = index, + reactor = for_reactor, + device = device, + formed = formed, + rtu = rtu_iface, ---@type rtu_device|rtu_rs_device + modbus_io = modbus.new(rtu_iface, true), + pkt_queue = mqueue.new(), ---@type mqueue|nil + thread = nil + } + + rtu_unit.thread = threads.thread__unit_comms(__shared_memory, rtu_unit) + + table.insert(units, rtu_unit) + + log.debug(util.c("configure> initialized RTU unit #", #units, ": ", name, " (", rtu_type, ") [", index, "] for reactor ", for_reactor)) end -- we made it through all that trusting-user-to-write-a-config-file chaos diff --git a/rtu/threads.lua b/rtu/threads.lua index e3d4cd7..fd08759 100644 --- a/rtu/threads.lua +++ b/rtu/threads.lua @@ -122,9 +122,37 @@ function threads.thread__main(smem) -- find disconnected device to reconnect -- note: cannot check isFormed as that would yield this coroutine and consume events if unit.name == param1 then + local resend_advert = false + -- found, re-link unit.device = device + if unit.type == "virtual" then + resend_advert = true + if type == "boilerValve" then + -- boiler multiblock + unit.type = rtu_t.boiler_valve + elseif type == "turbineValve" then + -- turbine multiblock + unit.type = rtu_t.turbine_valve + elseif type == "inductionPort" then + -- induction matrix multiblock + unit.type = rtu_t.induction_matrix + elseif type == "spsPort" then + -- SPS multiblock + unit.type = rtu_t.sps + elseif type == "solarNeutronActivator" then + -- SNA + unit.type = rtu_t.sna + elseif type == "environmentDetector" then + -- advanced peripherals environment detector + unit.type = rtu_t.env_detector + else + resend_advert = false + log.error(util.c("virtual device '", unit.name, "' cannot init to an unknown type (", type, ")")) + end + end + if unit.type == rtu_t.boiler_valve then unit.rtu = boilerv_rtu.new(device) unit.formed = true @@ -142,14 +170,19 @@ function threads.thread__main(smem) elseif unit.type == rtu_t.env_detector then unit.rtu = envd_rtu.new(device) else - log.error(util.c("unreachable case occured trying to identify reconnected RTU unit type (", unit.name, ")"), true) + log.error(util.c("failed to identify reconnected RTU unit type (", unit.name, ")"), true) end unit.modbus_io = modbus.new(unit.rtu, true) - rtu_comms.send_remounted(unit.index) - println_ts("reconnected the " .. unit.type .. " on interface " .. unit.name) + log.info("reconnected the " .. unit.type .. " on interface " .. unit.name) + + if resend_advert then + rtu_comms.send_advertisement(units) + else + rtu_comms.send_remounted(unit.index) + end end end end @@ -274,7 +307,6 @@ function threads.thread__unit_comms(smem, unit) local last_update = util.time() - local check_formed = type(unit.formed) == "boolean" local last_f_check = 0 local detail_name = util.c(unit.type, " (", unit.name, ") [", unit.index, "] for reactor ", unit.reactor) @@ -308,8 +340,8 @@ function threads.thread__unit_comms(smem, unit) end - -- check if multiblocks is still formed - if check_formed and (util.time() - last_f_check > 1000) then + -- check if multiblock is still formed if this is a multiblock + if (type(unit.formed) == "boolean") and (util.time() - last_f_check > 1000) then if (not unit.formed) and unit.device.isFormed() then -- newly re-formed local iface = ppm.get_iface(unit.device) diff --git a/scada-common/comms.lua b/scada-common/comms.lua index 696547e..16092ee 100644 --- a/scada-common/comms.lua +++ b/scada-common/comms.lua @@ -642,6 +642,12 @@ function comms.rtu_t_to_unit_type(type) return RTU_UNIT_TYPES.TURBINE_VALVE elseif type == rtu_t.induction_matrix then return RTU_UNIT_TYPES.IMATRIX + elseif type == rtu_t.sps then + return RTU_UNIT_TYPES.SPS + elseif type == rtu_t.sna then + return RTU_UNIT_TYPES.SNA + elseif type == rtu_t.env_detector then + return RTU_UNIT_TYPES.ENV_DETECTOR end return nil @@ -659,6 +665,12 @@ function comms.advert_type_to_rtu_t(utype) return rtu_t.turbine_valve elseif utype == RTU_UNIT_TYPES.IMATRIX then return rtu_t.induction_matrix + elseif utype == RTU_UNIT_TYPES.SPS then + return rtu_t.sps + elseif utype == RTU_UNIT_TYPES.SNA then + return rtu_t.sna + elseif utype == RTU_UNIT_TYPES.ENV_DETECTOR then + return rtu_t.env_detector end return nil diff --git a/scada-common/log.lua b/scada-common/log.lua index dadba40..1a44356 100644 --- a/scada-common/log.lua +++ b/scada-common/log.lua @@ -58,6 +58,7 @@ end -- private log write function ---@param msg string local function _log(msg) + local out_of_space = false local time_stamp = os.date("[%c] ") local stamped = time_stamp .. util.strval(msg) @@ -69,15 +70,17 @@ local function _log(msg) -- if we don't have space, we need to create a new log file - if not status then - if result == "Out of space" then + if (not status) and (result ~= nil) then + out_of_space = string.find(result, "Out of space") ~= nil + + if out_of_space then -- will delete log file - elseif result ~= nil then + else util.println("unknown error writing to logfile: " .. result) end end - if (result == "Out of space") or (free_space(_log_sys.path) < 100) then + if out_of_space or (free_space(_log_sys.path) < 100) then -- delete the old log file and open a new one _log_sys.file.close() fs.delete(_log_sys.path) diff --git a/scada-common/ppm.lua b/scada-common/ppm.lua index d7753cd..f69de1e 100644 --- a/scada-common/ppm.lua +++ b/scada-common/ppm.lua @@ -12,8 +12,11 @@ local ACCESS_FAULT = nil ---@type nil local UNDEFINED_FIELD = "undefined field" +local VIRTUAL_DEVICE_TYPE = "ppm_vdev" + ppm.ACCESS_FAULT = ACCESS_FAULT ppm.UNDEFINED_FIELD = UNDEFINED_FIELD +ppm.VIRTUAL_DEVICE_TYPE = VIRTUAL_DEVICE_TYPE ---------------------------- -- PRIVATE DATA/FUNCTIONS -- @@ -23,6 +26,7 @@ local REPORT_FREQUENCY = 20 -- log every 20 faults per function local _ppm_sys = { mounts = {}, + next_vid = 0, auto_cf = false, faulted = false, last_fault = "", @@ -42,10 +46,15 @@ local function peri_init(iface) last_fault = "", fault_counts = {}, auto_cf = true, - type = peripheral.getType(iface), - device = peripheral.wrap(iface) + type = VIRTUAL_DEVICE_TYPE, + device = {} } + if iface ~= "__virtual__" then + self.type = peripheral.getType(iface) + self.device = peripheral.wrap(iface) + end + -- initialization process (re-map) for key, func in pairs(self.device) do @@ -245,6 +254,19 @@ function ppm.mount(iface) return pm_type, pm_dev end +-- mount a virtual, placeholder device (specifically designed for RTU startup with missing devices) +---@return string type, table device +function ppm.mount_virtual() + local iface = "ppm_vdev_" .. _ppm_sys.next_vid + + _ppm_sys.mounts[iface] = peri_init("__virtual__") + _ppm_sys.next_vid = _ppm_sys.next_vid + 1 + + log.info(util.c("PPM: mount_virtual() -> allocated new virtual device ", iface)) + + return _ppm_sys.mounts[iface].type, _ppm_sys.mounts[iface].dev +end + -- manually unmount a peripheral from the PPM ---@param device table device table function ppm.unmount(device) diff --git a/supervisor/session/rtu.lua b/supervisor/session/rtu.lua index ec48bc0..b520ddc 100644 --- a/supervisor/session/rtu.lua +++ b/supervisor/session/rtu.lua @@ -89,8 +89,12 @@ function rtu.new_session(id, in_queue, out_queue, advertisement, facility_units) -- parse the recorded advertisement and create unit sub-sessions local function _handle_advertisement() - self.units = {} - self.rs_io_q = {} + _reset_config() + + for i = 1, #self.f_units do + local unit = self.f_units[i] ---@type reactor_unit + unit.purge_rtu_devices(self.id) + end for i = 1, #self.advert do local unit = nil ---@type unit_session|nil @@ -130,6 +134,7 @@ function rtu.new_session(id, in_queue, out_queue, advertisement, facility_units) if u_type == false then -- validation fail + log.debug(log_header .. "advertisement unit validation failure") else local target_unit = self.f_units[unit_advert.reactor] ---@type reactor_unit @@ -285,8 +290,13 @@ function rtu.new_session(id, in_queue, out_queue, advertisement, facility_units) _close() elseif pkt.type == SCADA_MGMT_TYPES.RTU_ADVERT then -- RTU unit advertisement - -- handle advertisement; this will re-create all unit sub-sessions + log.debug(log_header .. "received updated advertisement") + + -- copy advertisement and remove version tag self.advert = pkt.data + table.remove(self.advert, 1) + + -- handle advertisement; this will re-create all unit sub-sessions _handle_advertisement() elseif pkt.type == SCADA_MGMT_TYPES.RTU_DEV_REMOUNT then if pkt.length == 1 then diff --git a/supervisor/session/rtu/boilerv.lua b/supervisor/session/rtu/boilerv.lua index 8b5b02e..c0d9eb3 100644 --- a/supervisor/session/rtu/boilerv.lua +++ b/supervisor/session/rtu/boilerv.lua @@ -46,7 +46,7 @@ function boilerv.new(session_id, unit_id, advert, out_queue) local log_tag = "session.rtu(" .. session_id .. ").boilerv(" .. advert.index .. "): " local self = { - session = unit_session.new(unit_id, advert, out_queue, log_tag, TXN_TAGS), + session = unit_session.new(session_id, unit_id, advert, out_queue, log_tag, TXN_TAGS), has_build = false, periodics = { next_formed_req = 0, diff --git a/supervisor/session/rtu/envd.lua b/supervisor/session/rtu/envd.lua index a5546e4..4148b7d 100644 --- a/supervisor/session/rtu/envd.lua +++ b/supervisor/session/rtu/envd.lua @@ -37,7 +37,7 @@ function envd.new(session_id, unit_id, advert, out_queue) local log_tag = "session.rtu(" .. session_id .. ").envd(" .. advert.index .. "): " local self = { - session = unit_session.new(unit_id, advert, out_queue, log_tag, TXN_TAGS), + session = unit_session.new(session_id, unit_id, advert, out_queue, log_tag, TXN_TAGS), periodics = { next_rad_req = 0 }, diff --git a/supervisor/session/rtu/imatrix.lua b/supervisor/session/rtu/imatrix.lua index 3ebc7ab..ab5704c 100644 --- a/supervisor/session/rtu/imatrix.lua +++ b/supervisor/session/rtu/imatrix.lua @@ -46,7 +46,7 @@ function imatrix.new(session_id, unit_id, advert, out_queue) local log_tag = "session.rtu(" .. session_id .. ").imatrix(" .. advert.index .. "): " local self = { - session = unit_session.new(unit_id, advert, out_queue, log_tag, TXN_TAGS), + session = unit_session.new(session_id, unit_id, advert, out_queue, log_tag, TXN_TAGS), has_build = false, periodics = { next_formed_req = 0, diff --git a/supervisor/session/rtu/redstone.lua b/supervisor/session/rtu/redstone.lua index 35764ac..90e4b58 100644 --- a/supervisor/session/rtu/redstone.lua +++ b/supervisor/session/rtu/redstone.lua @@ -61,7 +61,7 @@ function redstone.new(session_id, unit_id, advert, out_queue) local log_tag = "session.rtu(" .. session_id .. ").redstone(" .. unit_id .. "): " local self = { - session = unit_session.new(unit_id, advert, out_queue, log_tag, TXN_TAGS), + session = unit_session.new(session_id, unit_id, advert, out_queue, log_tag, TXN_TAGS), in_q = mqueue.new(), has_di = false, has_ai = false, diff --git a/supervisor/session/rtu/sna.lua b/supervisor/session/rtu/sna.lua index 297708a..40014d3 100644 --- a/supervisor/session/rtu/sna.lua +++ b/supervisor/session/rtu/sna.lua @@ -43,7 +43,7 @@ function sna.new(session_id, unit_id, advert, out_queue) local log_tag = "session.rtu(" .. session_id .. ").sna(" .. advert.index .. "): " local self = { - session = unit_session.new(unit_id, advert, out_queue, log_tag, TXN_TAGS), + session = unit_session.new(session_id, unit_id, advert, out_queue, log_tag, TXN_TAGS), has_build = false, periodics = { next_build_req = 0, diff --git a/supervisor/session/rtu/sps.lua b/supervisor/session/rtu/sps.lua index 8b42bd1..f389049 100644 --- a/supervisor/session/rtu/sps.lua +++ b/supervisor/session/rtu/sps.lua @@ -46,7 +46,7 @@ function sps.new(session_id, unit_id, advert, out_queue) local log_tag = "session.rtu(" .. session_id .. ").sps(" .. advert.index .. "): " local self = { - session = unit_session.new(unit_id, advert, out_queue, log_tag, TXN_TAGS), + session = unit_session.new(session_id, unit_id, advert, out_queue, log_tag, TXN_TAGS), has_build = false, periodics = { next_formed_req = 0, diff --git a/supervisor/session/rtu/turbinev.lua b/supervisor/session/rtu/turbinev.lua index 2927fd2..ad3fea7 100644 --- a/supervisor/session/rtu/turbinev.lua +++ b/supervisor/session/rtu/turbinev.lua @@ -66,7 +66,7 @@ function turbinev.new(session_id, unit_id, advert, out_queue) local log_tag = "session.rtu(" .. session_id .. ").turbinev(" .. advert.index .. "): " local self = { - session = unit_session.new(unit_id, advert, out_queue, log_tag, TXN_TAGS), + session = unit_session.new(session_id, unit_id, advert, out_queue, log_tag, TXN_TAGS), in_q = mqueue.new(), has_build = false, periodics = { diff --git a/supervisor/session/rtu/unit_session.lua b/supervisor/session/rtu/unit_session.lua index 245461e..a3f27f2 100644 --- a/supervisor/session/rtu/unit_session.lua +++ b/supervisor/session/rtu/unit_session.lua @@ -22,12 +22,13 @@ unit_session.RTU_US_CMDS = RTU_US_CMDS unit_session.RTU_US_DATA = RTU_US_DATA -- create a new unit session runner +---@param session_id integer RTU session ID ---@param unit_id integer MODBUS unit ID ---@param advert rtu_advertisement RTU advertisement for this unit ---@param out_queue mqueue send queue ---@param log_tag string logging tag ---@param txn_tags table transaction log tags -function unit_session.new(unit_id, advert, out_queue, log_tag, txn_tags) +function unit_session.new(session_id, unit_id, advert, out_queue, log_tag, txn_tags) local self = { log_tag = log_tag, txn_tags = txn_tags, @@ -132,6 +133,8 @@ function unit_session.new(unit_id, advert, out_queue, log_tag, txn_tags) -- PUBLIC FUNCTIONS -- + -- get the unit ID + function public.get_session_id() return session_id end -- get the unit ID function public.get_unit_id() return self.unit_id end -- get the device index diff --git a/supervisor/session/unit.lua b/supervisor/session/unit.lua index 467fb60..86df0dd 100644 --- a/supervisor/session/unit.lua +++ b/supervisor/session/unit.lua @@ -401,6 +401,14 @@ function unit.new(for_reactor, num_boilers, num_turbines) table.insert(self.redstone[field], accessor) end + -- purge devices associated with the given RTU session ID + ---@param session integer RTU session ID + function public.purge_rtu_devices(session) + util.filter_table(self.turbines, function (s) return s.get_session_id() ~= session end) + util.filter_table(self.boilers, function (s) return s.get_session_id() ~= session end) + util.filter_table(self.redstone, function (s) return s.get_session_id() ~= session end) + end + -- UPDATE SESSION -- -- update (iterate) this unit diff --git a/supervisor/startup.lua b/supervisor/startup.lua index 0f1a4be..6a3abea 100644 --- a/supervisor/startup.lua +++ b/supervisor/startup.lua @@ -13,7 +13,7 @@ local svsessions = require("supervisor.session.svsessions") local config = require("supervisor.config") local supervisor = require("supervisor.supervisor") -local SUPERVISOR_VERSION = "beta-v0.7.3" +local SUPERVISOR_VERSION = "beta-v0.7.4" local print = util.print local println = util.println