#604 reworked supervisor redstone RTU interface

This commit is contained in:
Mikayla 2025-04-29 02:38:42 +00:00
parent be462db50b
commit e6f5ab8ef4
7 changed files with 176 additions and 134 deletions

View File

@ -125,7 +125,7 @@ function types.new_zero_coordinate() return { x = 0, y = 0, z = 0 } end
---@field type RTU_UNIT_TYPE ---@field type RTU_UNIT_TYPE
---@field index integer|false ---@field index integer|false
---@field reactor integer ---@field reactor integer
---@field rsio IO_PORT[]|nil ---@field rs_conns IO_PORT[][]|nil
-- create a new reactor database -- create a new reactor database
---@nodiscard ---@nodiscard

View File

@ -157,7 +157,7 @@ function facility.new(config)
self.rtu_list = { self.redstone, self.induction, self.sps, self.tanks, self.envd } self.rtu_list = { self.redstone, self.induction, self.sps, self.tanks, self.envd }
-- init redstone RTU I/O controller -- init redstone RTU I/O controller
self.io_ctl = rsctl.new(self.redstone) self.io_ctl = rsctl.new(self.redstone, 0)
-- fill blank alarm/tone states -- fill blank alarm/tone states
for _ = 1, 12 do table.insert(self.test_alarm_states, false) end for _ = 1, 12 do table.insert(self.test_alarm_states, false) end

View File

@ -9,7 +9,8 @@ local rsctl = {}
-- create a new redstone RTU I/O controller -- create a new redstone RTU I/O controller
---@nodiscard ---@nodiscard
---@param redstone_rtus redstone_session[] redstone RTU sessions ---@param redstone_rtus redstone_session[] redstone RTU sessions
function rsctl.new(redstone_rtus) ---@param bank integer I/O bank (unit/facility assignment) to interface with
function rsctl.new(redstone_rtus, bank)
---@class rs_controller ---@class rs_controller
local public = {} local public = {}
@ -18,7 +19,7 @@ function rsctl.new(redstone_rtus)
---@return boolean ---@return boolean
function public.is_connected(port) function public.is_connected(port)
for i = 1, #redstone_rtus do for i = 1, #redstone_rtus do
if redstone_rtus[i].get_db().io[port] ~= nil then return true end if redstone_rtus[i].get_db().io[bank][port] ~= nil then return true end
end end
return false return false
@ -29,7 +30,7 @@ function rsctl.new(redstone_rtus)
---@param value boolean ---@param value boolean
function public.digital_write(port, value) function public.digital_write(port, value)
for i = 1, #redstone_rtus do for i = 1, #redstone_rtus do
local io = redstone_rtus[i].get_db().io[port] local io = redstone_rtus[i].get_db().io[bank][port]
if io ~= nil then io.write(value) end if io ~= nil then io.write(value) end
end end
end end
@ -40,7 +41,7 @@ function rsctl.new(redstone_rtus)
---@return boolean|nil ---@return boolean|nil
function public.digital_read(port) function public.digital_read(port)
for i = 1, #redstone_rtus do for i = 1, #redstone_rtus do
local io = redstone_rtus[i].get_db().io[port] local io = redstone_rtus[i].get_db().io[bank][port]
if io ~= nil then return io.read() --[[@as boolean|nil]] end if io ~= nil then return io.read() --[[@as boolean|nil]] end
end end
end end
@ -52,7 +53,7 @@ function rsctl.new(redstone_rtus)
---@param max number maximum value for scaling 0 to 15 ---@param max number maximum value for scaling 0 to 15
function public.analog_write(port, value, min, max) function public.analog_write(port, value, min, max)
for i = 1, #redstone_rtus do for i = 1, #redstone_rtus do
local io = redstone_rtus[i].get_db().io[port] local io = redstone_rtus[i].get_db().io[bank][port]
if io ~= nil then io.write(rsio.analog_write(value, min, max)) end if io ~= nil then io.write(rsio.analog_write(value, min, max)) end
end end
end end

View File

@ -93,7 +93,7 @@ function rtu.new_session(id, s_addr, i_seq_num, in_queue, out_queue, timeout, ad
type = self.advert[i][1], type = self.advert[i][1],
index = self.advert[i][2], index = self.advert[i][2],
reactor = self.advert[i][3], reactor = self.advert[i][3],
rsio = self.advert[i][4] rs_conns = self.advert[i][4]
} }
local u_type = unit_advert.type ---@type RTU_UNIT_TYPE|boolean local u_type = unit_advert.type ---@type RTU_UNIT_TYPE|boolean
@ -105,13 +105,19 @@ function rtu.new_session(id, s_addr, i_seq_num, in_queue, out_queue, timeout, ad
advert_validator.assert_type_int(unit_advert.reactor) advert_validator.assert_type_int(unit_advert.reactor)
if u_type == RTU_UNIT_TYPE.REDSTONE then if u_type == RTU_UNIT_TYPE.REDSTONE then
advert_validator.assert_type_table(unit_advert.rsio) advert_validator.assert_type_table(unit_advert.rs_conns)
end end
if advert_validator.valid() then if advert_validator.valid() then
if util.is_int(unit_advert.index) then advert_validator.assert_min(unit_advert.index, 1) end if util.is_int(unit_advert.index) then advert_validator.assert_min(unit_advert.index, 1) end
advert_validator.assert_min(unit_advert.reactor, 0)
advert_validator.assert_max(unit_advert.reactor, #self.fac_units) if unit_advert.reactor == -1 then
advert_validator.assert_type_table(unit_advert.rs_conns)
else
advert_validator.assert_min(unit_advert.reactor, 0)
advert_validator.assert_max(unit_advert.reactor, #self.fac_units)
end
if not advert_validator.valid() then u_type = false end if not advert_validator.valid() then u_type = false end
else else
u_type = false u_type = false
@ -126,15 +132,32 @@ function rtu.new_session(id, s_addr, i_seq_num, in_queue, out_queue, timeout, ad
-- validation fail -- validation fail
log.debug(log_tag .. "_handle_advertisement(): advertisement unit validation failure") log.debug(log_tag .. "_handle_advertisement(): advertisement unit validation failure")
else else
if unit_advert.reactor > 0 then if unit_advert.reactor == -1 then
local target_unit = self.fac_units[unit_advert.reactor] -- redstone RTUs can be used in multiple different assignments
-- unit RTUs
if u_type == RTU_UNIT_TYPE.REDSTONE then if u_type == RTU_UNIT_TYPE.REDSTONE then
-- redstone -- redstone
unit = svrs_redstone.new(id, i, unit_advert, self.modbus_q) unit = svrs_redstone.new(id, i, unit_advert, self.modbus_q)
if type(unit) ~= "nil" then target_unit.add_redstone(unit) end
elseif u_type == RTU_UNIT_TYPE.BOILER_VALVE then -- link this to any subsystems this RTU provides connections for
if type(unit) ~= "nil" then
for assignment, _ in pairs(unit_advert.rs_conns) do
if assignment == 0 then
facility.add_redstone(unit)
elseif assignment > 0 and assignment < #self.fac_units then
self.fac_units[assignment].add_redstone(unit)
else
log.warning(util.c(log_tag, "_handle_advertisement(): unrecognized redstone RTU assignment ", assignment, " ", type_string))
end
end
end
else
log.warning(util.c(log_tag, "_handle_advertisement(): encountered unsupported multi-assignment RTU type ", type_string))
end
elseif unit_advert.reactor > 0 then
local target_unit = self.fac_units[unit_advert.reactor]
-- unit RTUs
if u_type == RTU_UNIT_TYPE.BOILER_VALVE then
-- boiler -- boiler
unit = svrs_boilerv.new(id, i, unit_advert, self.modbus_q) unit = svrs_boilerv.new(id, i, unit_advert, self.modbus_q)
if type(unit) ~= "nil" then target_unit.add_boiler(unit) end if type(unit) ~= "nil" then target_unit.add_boiler(unit) end

View File

@ -39,6 +39,9 @@ local PERIODICS = {
OUTPUT_SYNC = 200 OUTPUT_SYNC = 200
} }
-- create a new block of IO banks (facility, then each unit)
local function new_io_block() return { [0] = {}, {}, {}, {}, {} } end
---@class dig_phy_entry ---@class dig_phy_entry
---@field phy IO_LVL actual value ---@field phy IO_LVL actual value
---@field req IO_LVL commanded value ---@field req IO_LVL commanded value
@ -74,27 +77,27 @@ function redstone.new(session_id, unit_id, advert, out_queue)
next_ir_req = 0, next_ir_req = 0,
next_hr_sync = 0 next_hr_sync = 0
}, },
---@class rs_io_list ---@class rs_io_map
io_list = { io_map = {
digital_in = {}, ---@type IO_PORT[] discrete inputs digital_in = {}, ---@type { bank: integer, port: IO_PORT }[] discrete inputs
digital_out = {}, ---@type IO_PORT[] coils digital_out = {}, ---@type { bank: integer, port: IO_PORT }[] coils
analog_in = {}, ---@type IO_PORT[] input registers analog_in = {}, ---@type { bank: integer, port: IO_PORT }[] input registers
analog_out = {} ---@type IO_PORT[] holding registers analog_out = {} ---@type { bank: integer, port: IO_PORT }[] holding registers
}, },
phy_trans = { coils = -1, hold_regs = -1 }, phy_trans = { coils = -1, hold_regs = -1 },
-- last set/read ports (reflecting the current state of the RTU) -- last set/read ports (reflecting the current state of the RTU)
---@class rs_io_states ---@class rs_io_states
phy_io = { phy_io = {
digital_in = {}, ---@type dig_phy_entry[] discrete inputs digital_in = new_io_block(), ---@type dig_phy_entry[][] discrete inputs
digital_out = {}, ---@type dig_phy_entry[] coils digital_out = new_io_block(), ---@type dig_phy_entry[][] coils
analog_in = {}, ---@type ana_phy_entry[] input registers analog_in = new_io_block(), ---@type ana_phy_entry[][] input registers
analog_out = {} ---@type ana_phy_entry[] holding registers analog_out = new_io_block() ---@type ana_phy_entry[][] holding registers
}, },
---@class redstone_session_db ---@class redstone_session_db
db = { db = {
-- read/write functions for connected I/O -- read/write functions for connected I/O
---@type (rs_db_dig_io|rs_db_ana_io)[] ---@type (rs_db_dig_io|rs_db_ana_io)[][]
io = {} io = new_io_block()
} }
} }
@ -103,93 +106,91 @@ function redstone.new(session_id, unit_id, advert, out_queue)
-- INITIALIZE -- -- INITIALIZE --
-- create all ports as disconnected
for _ = 1, #IO_PORT do
table.insert(self.db, IO_LVL.DISCONNECT)
end
-- setup I/O -- setup I/O
for i = 1, #advert.rsio do for bank = 0, 4 do
local port = advert.rsio[i] for i = 1, #advert.rs_conns[bank] do
local port = advert.rs_conns[bank][i]
if rsio.is_valid_port(port) then if rsio.is_valid_port(port) then
local mode = rsio.get_io_mode(port) local mode = rsio.get_io_mode(port)
local io_entry = { bank = bank, port = port }
if mode == IO_MODE.DIGITAL_IN then if mode == IO_MODE.DIGITAL_IN then
self.has_di = true self.has_di = true
table.insert(self.io_list.digital_in, port) table.insert(self.io_map.digital_in, io_entry)
self.phy_io.digital_in[port] = { phy = IO_LVL.FLOATING, req = IO_LVL.FLOATING } self.phy_io.digital_in[bank][port] = { phy = IO_LVL.FLOATING, req = IO_LVL.FLOATING }
---@class rs_db_dig_io ---@class rs_db_dig_io
local io_f = { local io_f = {
---@nodiscard ---@nodiscard
read = function () return rsio.digital_is_active(port, self.phy_io.digital_in[port].phy) end, read = function () return rsio.digital_is_active(port, self.phy_io.digital_in[bank][port].phy) end,
write = function () end write = function () end
} }
self.db.io[port] = io_f self.db.io[port] = io_f
elseif mode == IO_MODE.DIGITAL_OUT then elseif mode == IO_MODE.DIGITAL_OUT then
self.has_do = true self.has_do = true
table.insert(self.io_list.digital_out, port) table.insert(self.io_map.digital_out, io_entry)
self.phy_io.digital_out[port] = { phy = IO_LVL.FLOATING, req = IO_LVL.FLOATING } self.phy_io.digital_out[bank][port] = { phy = IO_LVL.FLOATING, req = IO_LVL.FLOATING }
---@class rs_db_dig_io ---@class rs_db_dig_io
local io_f = { local io_f = {
---@nodiscard ---@nodiscard
read = function () return rsio.digital_is_active(port, self.phy_io.digital_out[port].phy) end, read = function () return rsio.digital_is_active(port, self.phy_io.digital_out[bank][port].phy) end,
---@param active boolean ---@param active boolean
write = function (active) write = function (active)
local level = rsio.digital_write_active(port, active) local level = rsio.digital_write_active(port, active)
if level ~= nil then self.phy_io.digital_out[port].req = level end if level ~= nil then self.phy_io.digital_out[bank][port].req = level end
end
}
self.db.io[port] = io_f
elseif mode == IO_MODE.ANALOG_IN then
self.has_ai = true
table.insert(self.io_list.analog_in, port)
self.phy_io.analog_in[port] = { phy = 0, req = 0 }
---@class rs_db_ana_io
local io_f = {
---@nodiscard
---@return integer
read = function () return self.phy_io.analog_in[port].phy end,
write = function () end
}
self.db.io[port] = io_f
elseif mode == IO_MODE.ANALOG_OUT then
self.has_ao = true
table.insert(self.io_list.analog_out, port)
self.phy_io.analog_out[port] = { phy = 0, req = 0 }
---@class rs_db_ana_io
local io_f = {
---@nodiscard
---@return integer
read = function () return self.phy_io.analog_out[port].phy end,
---@param value integer
write = function (value)
if value >= 0 and value <= 15 then
self.phy_io.analog_out[port].req = value
end end
end }
}
self.db.io[port] = io_f self.db.io[port] = io_f
elseif mode == IO_MODE.ANALOG_IN then
self.has_ai = true
table.insert(self.io_map.analog_in, io_entry)
self.phy_io.analog_in[bank][port] = { phy = 0, req = 0 }
---@class rs_db_ana_io
local io_f = {
---@nodiscard
---@return integer
read = function () return self.phy_io.analog_in[bank][port].phy end,
write = function () end
}
self.db.io[port] = io_f
elseif mode == IO_MODE.ANALOG_OUT then
self.has_ao = true
table.insert(self.io_map.analog_out, io_entry)
self.phy_io.analog_out[bank][port] = { phy = 0, req = 0 }
---@class rs_db_ana_io
local io_f = {
---@nodiscard
---@return integer
read = function () return self.phy_io.analog_out[bank][port].phy end,
---@param value integer
write = function (value)
if value >= 0 and value <= 15 then
self.phy_io.analog_out[bank][port].req = value
end
end
}
self.db.io[port] = io_f
else
-- should be unreachable code, we already validated ports
log.error(util.c(log_tag, "failed to identify advertisement port IO mode (", bank, ":", port, ")"), true)
return nil
end
else else
-- should be unreachable code, we already validated ports log.error(util.c(log_tag, "invalid advertisement port (", bank, ":", port, ")"), true)
log.error(util.c(log_tag, "failed to identify advertisement port IO mode (", port, ")"), true)
return nil return nil
end end
else
log.error(util.c(log_tag, "invalid advertisement port (", port, ")"), true)
return nil
end end
end end
@ -197,12 +198,12 @@ function redstone.new(session_id, unit_id, advert, out_queue)
-- query discrete inputs -- query discrete inputs
local function _request_discrete_inputs() local function _request_discrete_inputs()
self.session.send_request(TXN_TYPES.DI_READ, MODBUS_FCODE.READ_DISCRETE_INPUTS, { 1, #self.io_list.digital_in }) self.session.send_request(TXN_TYPES.DI_READ, MODBUS_FCODE.READ_DISCRETE_INPUTS, { 1, #self.io_map.digital_in })
end end
-- query input registers -- query input registers
local function _request_input_registers() local function _request_input_registers()
self.session.send_request(TXN_TYPES.INPUT_REG_READ, MODBUS_FCODE.READ_INPUT_REGS, { 1, #self.io_list.analog_in }) self.session.send_request(TXN_TYPES.INPUT_REG_READ, MODBUS_FCODE.READ_INPUT_REGS, { 1, #self.io_map.analog_in })
end end
-- write all coil outputs -- write all coil outputs
@ -210,9 +211,9 @@ function redstone.new(session_id, unit_id, advert, out_queue)
local params = { 1 } local params = { 1 }
local outputs = self.phy_io.digital_out local outputs = self.phy_io.digital_out
for i = 1, #self.io_list.digital_out do for i = 1, #self.io_map.digital_out do
local port = self.io_list.digital_out[i] local entry = self.io_map.digital_out[i]
table.insert(params, outputs[port].req) table.insert(params, outputs[entry.bank][entry.port].req)
end end
self.phy_trans.coils = self.session.send_request(TXN_TYPES.COIL_WRITE, MODBUS_FCODE.WRITE_MUL_COILS, params) self.phy_trans.coils = self.session.send_request(TXN_TYPES.COIL_WRITE, MODBUS_FCODE.WRITE_MUL_COILS, params)
@ -220,7 +221,7 @@ function redstone.new(session_id, unit_id, advert, out_queue)
-- read all coil outputs -- read all coil outputs
local function _read_coils() local function _read_coils()
self.session.send_request(TXN_TYPES.COIL_READ, MODBUS_FCODE.READ_COILS, { 1, #self.io_list.digital_out }) self.session.send_request(TXN_TYPES.COIL_READ, MODBUS_FCODE.READ_COILS, { 1, #self.io_map.digital_out })
end end
-- write all holding register outputs -- write all holding register outputs
@ -228,9 +229,9 @@ function redstone.new(session_id, unit_id, advert, out_queue)
local params = { 1 } local params = { 1 }
local outputs = self.phy_io.analog_out local outputs = self.phy_io.analog_out
for i = 1, #self.io_list.analog_out do for i = 1, #self.io_map.analog_out do
local port = self.io_list.analog_out[i] local entry = self.io_map.analog_out[i]
table.insert(params, outputs[port].req) table.insert(params, outputs[entry.bank][entry.port].req)
end end
self.phy_trans.hold_regs = self.session.send_request(TXN_TYPES.HOLD_REG_WRITE, MODBUS_FCODE.WRITE_MUL_HOLD_REGS, params) self.phy_trans.hold_regs = self.session.send_request(TXN_TYPES.HOLD_REG_WRITE, MODBUS_FCODE.WRITE_MUL_HOLD_REGS, params)
@ -238,7 +239,7 @@ function redstone.new(session_id, unit_id, advert, out_queue)
-- read all holding register outputs -- read all holding register outputs
local function _read_holding_registers() local function _read_holding_registers()
self.session.send_request(TXN_TYPES.HOLD_REG_READ, MODBUS_FCODE.READ_MUL_HOLD_REGS, { 1, #self.io_list.analog_out }) self.session.send_request(TXN_TYPES.HOLD_REG_READ, MODBUS_FCODE.READ_MUL_HOLD_REGS, { 1, #self.io_map.analog_out })
end end
-- PUBLIC FUNCTIONS -- -- PUBLIC FUNCTIONS --
@ -259,24 +260,24 @@ function redstone.new(session_id, unit_id, advert, out_queue)
end end
elseif txn_type == TXN_TYPES.DI_READ then elseif txn_type == TXN_TYPES.DI_READ then
-- discrete input read response -- discrete input read response
if m_pkt.length == #self.io_list.digital_in then if m_pkt.length == #self.io_map.digital_in then
for i = 1, m_pkt.length do for i = 1, m_pkt.length do
local port = self.io_list.digital_in[i] local entry = self.io_map.digital_in[i]
local value = m_pkt.data[i] local value = m_pkt.data[i]
self.phy_io.digital_in[port].phy = value self.phy_io.digital_in[entry.bank][entry.port].phy = value
end end
else else
log.debug(log_tag .. "MODBUS transaction reply length mismatch (" .. TXN_TAGS[txn_type] .. ")") log.debug(log_tag .. "MODBUS transaction reply length mismatch (" .. TXN_TAGS[txn_type] .. ")")
end end
elseif txn_type == TXN_TYPES.INPUT_REG_READ then elseif txn_type == TXN_TYPES.INPUT_REG_READ then
-- input register read response -- input register read response
if m_pkt.length == #self.io_list.analog_in then if m_pkt.length == #self.io_map.analog_in then
for i = 1, m_pkt.length do for i = 1, m_pkt.length do
local port = self.io_list.analog_in[i] local entry = self.io_map.analog_in[i]
local value = m_pkt.data[i] local value = m_pkt.data[i]
self.phy_io.analog_in[port].phy = value self.phy_io.analog_in[entry.bank][entry.port].phy = value
end end
else else
log.debug(log_tag .. "MODBUS transaction reply length mismatch (" .. TXN_TAGS[txn_type] .. ")") log.debug(log_tag .. "MODBUS transaction reply length mismatch (" .. TXN_TAGS[txn_type] .. ")")
@ -288,15 +289,14 @@ function redstone.new(session_id, unit_id, advert, out_queue)
-- update phy I/O table -- update phy I/O table
-- if there are multiple outputs for the same port, they will overwrite eachother (but *should* be identical) -- if there are multiple outputs for the same port, they will overwrite eachother (but *should* be identical)
-- given these are redstone outputs, if one worked they all should have, so no additional verification will be done -- given these are redstone outputs, if one worked they all should have, so no additional verification will be done
if m_pkt.length == #self.io_list.digital_out then if m_pkt.length == #self.io_map.digital_out then
for i = 1, m_pkt.length do for i = 1, m_pkt.length do
local port = self.io_list.digital_out[i] local entry = self.io_map.digital_out[i]
local state = self.phy_io.digital_out[entry.bank][entry.port]
local value = m_pkt.data[i] local value = m_pkt.data[i]
self.phy_io.digital_out[port].phy = value state.phy = value
if self.phy_io.digital_out[port].req == IO_LVL.FLOATING then if state.req == IO_LVL.FLOATING then state.req = value end
self.phy_io.digital_out[port].req = value
end
end end
self.phy_trans.coils = TXN_READY self.phy_trans.coils = TXN_READY
@ -310,12 +310,12 @@ function redstone.new(session_id, unit_id, advert, out_queue)
-- update phy I/O table -- update phy I/O table
-- if there are multiple outputs for the same port, they will overwrite eachother (but *should* be identical) -- if there are multiple outputs for the same port, they will overwrite eachother (but *should* be identical)
-- given these are redstone outputs, if one worked they all should have, so no additional verification will be done -- given these are redstone outputs, if one worked they all should have, so no additional verification will be done
if m_pkt.length == #self.io_list.analog_out then if m_pkt.length == #self.io_map.analog_out then
for i = 1, m_pkt.length do for i = 1, m_pkt.length do
local port = self.io_list.analog_out[i] local entry = self.io_map.analog_out[i]
local value = m_pkt.data[i] local value = m_pkt.data[i]
self.phy_io.analog_out[port].phy = value self.phy_io.analog_out[entry.bank][entry.port].phy = value
end end
else else
log.debug(log_tag .. "MODBUS transaction reply length mismatch (" .. TXN_TAGS[txn_type] .. ")") log.debug(log_tag .. "MODBUS transaction reply length mismatch (" .. TXN_TAGS[txn_type] .. ")")
@ -343,8 +343,17 @@ function redstone.new(session_id, unit_id, advert, out_queue)
-- sync digital outputs -- sync digital outputs
if self.has_do then if self.has_do then
if (self.periodics.next_cl_sync <= time_now) and (self.phy_trans.coils == TXN_READY) then if (self.periodics.next_cl_sync <= time_now) and (self.phy_trans.coils == TXN_READY) then
for _, entry in pairs(self.phy_io.digital_out) do for bank = 0, 4 do
if entry.phy ~= entry.req then local changed = false
for _, entry in pairs(self.phy_io.digital_out[bank]) do
if entry.phy ~= entry.req then
changed = true
break
end
end
if changed then
_write_coils() _write_coils()
break break
end end
@ -365,8 +374,17 @@ function redstone.new(session_id, unit_id, advert, out_queue)
-- sync analog outputs -- sync analog outputs
if self.has_ao then if self.has_ao then
if (self.periodics.next_hr_sync <= time_now) and (self.phy_trans.hold_regs == TXN_READY) then if (self.periodics.next_hr_sync <= time_now) and (self.phy_trans.hold_regs == TXN_READY) then
for _, entry in pairs(self.phy_io.analog_out) do for bank = 0, 4 do
if entry.phy ~= entry.req then local changed = false
for _, entry in pairs(self.phy_io.analog_out[bank]) do
if entry.phy ~= entry.req then
changed = true
break
end
end
if changed then
_write_holding_registers() _write_holding_registers()
break break
end end

View File

@ -23,7 +23,7 @@ local supervisor = require("supervisor.supervisor")
local svsessions = require("supervisor.session.svsessions") local svsessions = require("supervisor.session.svsessions")
local SUPERVISOR_VERSION = "v1.6.8" local SUPERVISOR_VERSION = "v1.7.0"
local println = util.println local println = util.println
local println_ts = util.println_ts local println_ts = util.println_ts

View File

@ -258,7 +258,7 @@ function unit.new(reactor_id, num_boilers, num_turbines, ext_idle, aux_coolant)
self.rtu_list = { self.redstone, self.boilers, self.turbines, self.tanks, self.snas, self.envd } self.rtu_list = { self.redstone, self.boilers, self.turbines, self.tanks, self.snas, self.envd }
-- init redstone RTU I/O controller -- init redstone RTU I/O controller
self.io_ctl = rsctl.new(self.redstone) self.io_ctl = rsctl.new(self.redstone, reactor_id)
-- init boiler table fields -- init boiler table fields
for _ = 1, num_boilers do for _ = 1, num_boilers do