From e443beec19b547e683b323fd475533e1871f528d Mon Sep 17 00:00:00 2001 From: Mikayla Fischler Date: Sat, 4 Jun 2022 16:25:23 -0400 Subject: [PATCH] #66 SNA RTU supervisor session --- supervisor/session/rtu.lua | 3 +- supervisor/session/rtu/sna.lua | 169 +++++++++++++++++++++++++++++++++ supervisor/startup.lua | 2 +- 3 files changed, 172 insertions(+), 2 deletions(-) create mode 100644 supervisor/session/rtu/sna.lua diff --git a/supervisor/session/rtu.lua b/supervisor/session/rtu.lua index 00dc81b..e4827d9 100644 --- a/supervisor/session/rtu.lua +++ b/supervisor/session/rtu.lua @@ -9,6 +9,7 @@ local svrs_boiler = require("supervisor.session.rtu.boiler") local svrs_emachine = require("supervisor.session.rtu.emachine") local svrs_envd = require("supervisor.session.rtu.envd") local svrs_redstone = require("supervisor.session.rtu.redstone") +local svrs_sna = require("supervisor.session.rtu.sna") local svrs_sps = require("supervisor.session.rtu.sps") local svrs_turbine = require("supervisor.session.rtu.turbine") @@ -106,7 +107,7 @@ function rtu.new_session(id, in_queue, out_queue, advertisement) elseif u_type == RTU_UNIT_TYPES.SPS then unit = svrs_sps.new(self.id, i, unit_advert, self.out_q) elseif u_type == RTU_UNIT_TYPES.SNA then - -- @todo Mekanism 10.1+ + unit = svrs_sna.new(self.id, i, unit_advert, self.out_q) elseif u_type == RTU_UNIT_TYPES.ENV_DETECTOR then unit = svrs_envd.new(self.id, i, unit_advert, self.out_q) else diff --git a/supervisor/session/rtu/sna.lua b/supervisor/session/rtu/sna.lua new file mode 100644 index 0000000..27f2868 --- /dev/null +++ b/supervisor/session/rtu/sna.lua @@ -0,0 +1,169 @@ +local comms = require("scada-common.comms") +local log = require("scada-common.log") +local types = require("scada-common.types") + +local unit_session = require("supervisor.session.rtu.unit_session") + +local sna = {} + +local RTU_UNIT_TYPES = comms.RTU_UNIT_TYPES +local MODBUS_FCODE = types.MODBUS_FCODE + +local TXN_TYPES = { + BUILD = 1, + STATE = 2, + TANKS = 3 +} + +local TXN_TAGS = { + "sna.build", + "sna.state", + "sna.tanks", +} + +local PERIODICS = { + BUILD = 1000, + STATE = 500, + TANKS = 1000 +} + +-- create a new sna rtu session runner +---@param session_id integer +---@param unit_id integer +---@param advert rtu_advertisement +---@param out_queue mqueue +function sna.new(session_id, unit_id, advert, out_queue) + -- type check + if advert.type ~= RTU_UNIT_TYPES.SNA then + log.error("attempt to instantiate sna RTU for type '" .. advert.type .. "'. this is a bug.") + return nil + end + + 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), + has_build = false, + periodics = { + next_build_req = 0, + next_state_req = 0, + next_tanks_req = 0, + }, + ---@class sna_session_db + db = { + build = { + input_cap = 0, + output_cap = 0 + }, + state = { + production_rate = 0.0, + peak_production = 0.0 + }, + tanks = { + input = {}, ---@type tank_fluid + input_need = 0, + input_fill = 0.0, + output = {}, ---@type tank_fluid + output_need = 0, + output_fill = 0.0 + } + } + } + + local public = self.session.get() + + -- PRIVATE FUNCTIONS -- + + -- query the build of the device + local function _request_build() + -- read input registers 1 through 2 (start = 1, count = 2) + self.session.send_request(TXN_TYPES.BUILD, MODBUS_FCODE.READ_INPUT_REGS, { 1, 2 }) + end + + -- query the state of the device + local function _request_state() + -- read input registers 3 through 4 (start = 3, count = 2) + self.session.send_request(TXN_TYPES.STATE, MODBUS_FCODE.READ_INPUT_REGS, { 3, 2 }) + end + + -- query the tanks of the device + local function _request_tanks() + -- read input registers 5 through 10 (start = 5, count = 6) + self.session.send_request(TXN_TYPES.TANKS, MODBUS_FCODE.READ_INPUT_REGS, { 5, 6 }) + end + + -- PUBLIC FUNCTIONS -- + + -- handle a packet + ---@param m_pkt modbus_frame + function public.handle_packet(m_pkt) + local txn_type = self.session.try_resolve(m_pkt.txn_id) + if txn_type == false then + -- nothing to do + elseif txn_type == TXN_TYPES.BUILD then + -- build response + -- load in data if correct length + if m_pkt.length == 2 then + self.db.build.input_cap = m_pkt.data[1] + self.db.build.output_cap = m_pkt.data[2] + self.has_build = true + else + log.debug(log_tag .. "MODBUS transaction reply length mismatch (" .. TXN_TAGS[txn_type] .. ")") + end + elseif txn_type == TXN_TYPES.STATE then + -- state response + -- load in data if correct length + if m_pkt.length == 2 then + self.db.state.production_rate = m_pkt.data[1] + self.db.state.peak_production = m_pkt.data[2] + else + log.debug(log_tag .. "MODBUS transaction reply length mismatch (" .. TXN_TAGS[txn_type] .. ")") + end + elseif txn_type == TXN_TYPES.TANKS then + -- tanks response + -- load in data if correct length + if m_pkt.length == 6 then + self.db.tanks.input = m_pkt.data[1] + self.db.tanks.input_need = m_pkt.data[2] + self.db.tanks.input_fill = m_pkt.data[3] + self.db.tanks.output = m_pkt.data[4] + self.db.tanks.output_need = m_pkt.data[5] + self.db.tanks.output_fill = m_pkt.data[6] + else + log.debug(log_tag .. "MODBUS transaction reply length mismatch (" .. TXN_TAGS[txn_type] .. ")") + end + elseif txn_type == nil then + log.error(log_tag .. "unknown transaction reply") + else + log.error(log_tag .. "unknown transaction type " .. txn_type) + end + end + + -- update this runner + ---@param time_now integer milliseconds + function public.update(time_now) + if not self.has_build and self.periodics.next_build_req <= time_now then + _request_build() + self.periodics.next_build_req = time_now + PERIODICS.BUILD + end + + if self.periodics.next_state_req <= time_now then + _request_state() + self.periodics.next_state_req = time_now + PERIODICS.STATE + end + + if self.periodics.next_tanks_req <= time_now then + _request_tanks() + self.periodics.next_tanks_req = time_now + PERIODICS.TANKS + end + + self.session.post_update() + end + + -- get the unit session database + function public.get_db() return self.db end + + return public +end + +return sna diff --git a/supervisor/startup.lua b/supervisor/startup.lua index 456d9d8..c71804f 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.4.7" +local SUPERVISOR_VERSION = "beta-v0.4.8" local print = util.print local println = util.println