From d7e65ff04b7b15b89a2dc7c44c62f31ade403cb3 Mon Sep 17 00:00:00 2001 From: Milan Hanajik Date: Wed, 17 Mar 2021 21:27:40 +0100 Subject: [PATCH] Modbus modified, UniCB Init. modified, RunDeviceAfter() called in reversed order, ver. 3.1.1597 --- Common/Telegram.cs | 35 ++++ TBF/Properties/AssemblyInfo.cs | 4 +- TBF/Rig/ControlBoard/Uni/UniCB.cs | 37 ++-- TBF/Rig/GenericDevices/IModbus.cs | 13 ++ TBF/Rig/Modbus/Ambient/Comet/Ambient.cs | 16 +- TBF/Rig/Modbus/Common/Modbus.cs | 176 +++++++++++------- TBF/Rig/Modbus/Easytherm/Easytherm.cs | 45 +++-- TBF/Rig/Modbus/Enums.cs | 2 +- .../PressureMeter/Meret/PressureMeter.cs | 15 +- TBF/Rig/Modbus/TempMeter/Groch/TempMeter.cs | 34 ++-- TBF/Rig/Modbus/TempMeter/Meret/TempMeter.cs | 15 +- .../Modbus/UltrasoundLevelMeter/LevelMeter.cs | 32 ++-- TBF/Rig/Modbus/WaterAnalyzer/Analyzer.cs | 19 +- TBF/Rig/StateMachine.cs | 7 +- 14 files changed, 293 insertions(+), 157 deletions(-) diff --git a/Common/Telegram.cs b/Common/Telegram.cs index 65bfccde6..d56cfe022 100644 --- a/Common/Telegram.cs +++ b/Common/Telegram.cs @@ -47,6 +47,21 @@ namespace Common return crc; } + /// + /// Calculates the CRC from a data telegram (an array of bytes). + /// A complete telegram including two bytes reserved for the CRC + /// must be supplied as an argument. + /// + /// Data telegram + /// Calculated CRC + public static UInt16 CalculateTelegramCRC(int offset, byte[] data, int enforcedLen = 0) + { + int len = (enforcedLen != 0) ? Math.Min(enforcedLen, data.Length - offset) : data.Length - offset; + UInt16 crc = crcSeed; + for (int i = 0; i < len - 2; i++) UpdateCRC(data[offset + i], ref crc); + return crc; + } + /// /// This function modifies the last 2 bytes in the message buffer /// by the CRC calculated from the remaining first (Lenght - 2) bytes. @@ -85,6 +100,26 @@ namespace Common return (data[len - 2] == (byte)(crc & 0xFF)) && (data[len - 1] == (byte)(crc >> 8)); } + /// + /// This function compares the last 2 bytes in the message buffer + /// with the CRC calculated from the remaining first (Lenght - 2) bytes. + /// A complete telegram including two bytes reserved for the CRC + /// must be supplied as an argument. + /// + /// Data telegram + /// true if the CRC in the telegram is correct + public static bool VerifyTelegramCRC(int offset, byte[] data, int enforcedLen = 0) + { + if (data == null || data.Length == 0 || enforcedLen > data.Length - offset) return false; + + int len = (enforcedLen != 0) ? enforcedLen : data.Length - offset; + if (len < 2) return false; + + UInt16 crc = CalculateTelegramCRC(offset, data, len); + + return (data[offset + len - 2] == (byte)(crc & 0xFF)) && (data[offset + len - 1] == (byte)(crc >> 8)); + } + /// diff --git a/TBF/Properties/AssemblyInfo.cs b/TBF/Properties/AssemblyInfo.cs index 83d50c13a..670963617 100644 --- a/TBF/Properties/AssemblyInfo.cs +++ b/TBF/Properties/AssemblyInfo.cs @@ -29,5 +29,5 @@ using System.Runtime.InteropServices; // Build Number // Revision // -[assembly: AssemblyVersion("3.1.1643.0")] -[assembly: AssemblyFileVersion("3.1.1643.0")] +[assembly: AssemblyVersion("3.1.1597.0")] +[assembly: AssemblyFileVersion("3.1.1597.0")] diff --git a/TBF/Rig/ControlBoard/Uni/UniCB.cs b/TBF/Rig/ControlBoard/Uni/UniCB.cs index 2162fd08b..808a1472f 100644 --- a/TBF/Rig/ControlBoard/Uni/UniCB.cs +++ b/TBF/Rig/ControlBoard/Uni/UniCB.cs @@ -179,12 +179,6 @@ namespace TBF.Rig.ControlBoard.Uni scopeAnalyzerData = null; switchCounterData = null; - serialPort = null; - buffer = new byte[BUFFER_SIZE]; - rcvdData = new byte[BUFFER_SIZE]; - cumulativeSums = new int[BUFFER_SIZE]; - rcvdBytesCount = 0; - routeMask = 0; for (int i = 0; i < 128; i++) { @@ -194,19 +188,6 @@ namespace TBF.Rig.ControlBoard.Uni } } - TBF.UiBridge.Bridge.RouteChangeHandler += delegate(object sndr, TBF.UiBridge.RouteChangeArgs args) - { - UInt128 mask = ((UInt128)1) << args.BitNr; - if ((benchModelRoute & mask) == 0) - { - benchModelRoute |= mask; - } - else - { - benchModelRoute &= (~mask); - } - }; - log.Warn(this.ToString()); } @@ -233,12 +214,30 @@ namespace TBF.Rig.ControlBoard.Uni return; } + buffer = new byte[BUFFER_SIZE]; + rcvdData = new byte[BUFFER_SIZE]; + cumulativeSums = new int[BUFFER_SIZE]; + rcvdBytesCount = 0; + serialPort = new SerialPort(comPort, 9600, Parity.None, 8, StopBits.One); serialPort.DtrEnable = true; serialPort.WriteTimeout = 4000; serialPort.ParityReplace = 0xFF; serialPort.Open(); + TBF.UiBridge.Bridge.RouteChangeHandler += delegate(object sndr, TBF.UiBridge.RouteChangeArgs args) + { + UInt128 mask = ((UInt128)1) << args.BitNr; + if ((benchModelRoute & mask) == 0) + { + benchModelRoute |= mask; + } + else + { + benchModelRoute &= (~mask); + } + }; + log.FatalFormat("{0} - Device successfully initialized", Name); } diff --git a/TBF/Rig/GenericDevices/IModbus.cs b/TBF/Rig/GenericDevices/IModbus.cs index e58a48300..52a91f3c5 100644 --- a/TBF/Rig/GenericDevices/IModbus.cs +++ b/TBF/Rig/GenericDevices/IModbus.cs @@ -27,5 +27,18 @@ namespace TBF.Rig.GenericDevices void SendMessage(byte modbusAddress, byte function, ushort dataAddress, ushort dataCount); Queue[] ReceivedTelegrams { get; } + + /// + /// Registers a modbus device for scheduled polling + /// + /// Ticket numeber to be used as IsMyTurn() argumenr + int RegisterForPolling(); + + /// + /// Determines whether the registered device should do polling now + /// + /// Ticket number in range 1 .. registered devs.count returned by RegisterForPolling() + /// true when yes + bool IsMyTurn(int ticketNr); } } diff --git a/TBF/Rig/Modbus/Ambient/Comet/Ambient.cs b/TBF/Rig/Modbus/Ambient/Comet/Ambient.cs index 743627134..62e12d045 100644 --- a/TBF/Rig/Modbus/Ambient/Comet/Ambient.cs +++ b/TBF/Rig/Modbus/Ambient/Comet/Ambient.cs @@ -74,9 +74,10 @@ namespace TBF.Rig.Modbus.Ambient.Comet /// Measurement time stamp when MsrmntState == MsrmntState.Valid int msrmntTimeStamp; - public Ambient() - { - } + int ticketNumber; /// 1 .. number of devices registered for regular polling + + + public Ambient() { } /// /// Ambient temperature / humidity / pressure meter 'Greco' connected via serial interface (RS232) @@ -106,6 +107,7 @@ namespace TBF.Rig.Modbus.Ambient.Comet } msrmntState = MsrmntState.Busy; + ticketNumber = modbus.RegisterForPolling(); log.FatalFormat("Successfully initialized device {0}", ToString()); } @@ -143,8 +145,13 @@ namespace TBF.Rig.Modbus.Ambient.Comet log.InfoFormat("Ambient: temperature = {0:F1} C, humidity = {1:F1} %, pressure = {2:F0} mbar", temperature, humidity, 1000 * pressure); } } + } - if ((StateMachine.Time % 10) == (ambientCfg.ModbusAddress % 10)) /// Each 10 seconds + public void RunDeviceAfter() + { + if (ambientCfg.DebugLevel != Config.Entities.DebugMode.Simulate && + ambientCfg.DebugLevel != Config.Entities.DebugMode.FailureDuringOperation && + modbus.IsMyTurn(ticketNumber)) { /// Read four registers: 0x31, 0x32, 0x33, 0x34 UInt16 regAddr = 0x0030; /// register addr. = 0x31 (Modbus!) @@ -163,7 +170,6 @@ namespace TBF.Rig.Modbus.Ambient.Comet } } - public void RunDeviceAfter() { } public void StopDevice() { } public void StopDevice2() { } diff --git a/TBF/Rig/Modbus/Common/Modbus.cs b/TBF/Rig/Modbus/Common/Modbus.cs index 9b555ba5a..a54b06d8d 100644 --- a/TBF/Rig/Modbus/Common/Modbus.cs +++ b/TBF/Rig/Modbus/Common/Modbus.cs @@ -27,10 +27,14 @@ namespace TBF.Rig.Modbus.Common const int MinTelegramLen = 4; - private readonly ModbusCfg modbusCommonCfg; + private readonly ModbusCfg modbusCfg; /// Private fields SerialPort serialPort; + const int BUFFER_SIZE = 1000; /// Size of input buffers + byte[] buffer; /// Buffer for data received in one attempt in RunDeviceBefore() + byte[] rcvdData; /// Buffer for all recevied but nut processed data. May contain data from several read attempts + int rcvdBytesCount; /// Count of valid bytes in rcvdData buffer DateTime lastSerialPortWrite; bool initialRunDeviceCommComplete; @@ -42,9 +46,10 @@ namespace TBF.Rig.Modbus.Common Queue telegramsToSend; - public Modbus() - { - } + int registeredDevicesCount; /// Number of devices registered for poling + + + public Modbus() { } /// /// Ambient temperature / humidity / pressure meter 'Greco' connected via serial interface (RS232) @@ -53,36 +58,37 @@ namespace TBF.Rig.Modbus.Common public Modbus(Generic.IComponentCfg cfg) : base(cfg) { - receivedTelegrams = new Queue[256]; - for (int i = 0; i < receivedTelegrams.Length; i++) - { - receivedTelegrams[i] = new Queue(); - } - telegramsToSend = new Queue(); - - serialPort = null; - modbusCommonCfg = cfg as ModbusCfg; + modbusCfg = cfg as ModbusCfg; log.Warn(this.ToString()); } - ~Modbus() - { - } - public void Initialize() { - if (modbusCommonCfg.DebugLevel == DebugMode.Simulate) + receivedTelegrams = new Queue[256]; + for (int i = 0; i < receivedTelegrams.Length; i++) + { + receivedTelegrams[i] = new Queue(); + } + telegramsToSend = new Queue(); + + if (modbusCfg.DebugLevel == DebugMode.Simulate) { serialPort = null; log.FatalFormat("{0} - Device simulated", Name); return; } - string comPortName = "COM" + modbusCommonCfg.ComPortNr.ToString(); - serialPort = new SerialPort(comPortName, modbusCommonCfg.BaudRate, modbusCommonCfg.Parity, modbusCommonCfg.DataBits, modbusCommonCfg.StopBits); - serialPort.Handshake = modbusCommonCfg.Handshake; + buffer = new byte[BUFFER_SIZE]; + rcvdData = new byte[BUFFER_SIZE]; + rcvdBytesCount = 0; + + string comPortName = "COM" + modbusCfg.ComPortNr.ToString(); + serialPort = new SerialPort(comPortName, modbusCfg.BaudRate, modbusCfg.Parity, modbusCfg.DataBits, modbusCfg.StopBits); + serialPort.Handshake = modbusCfg.Handshake; serialPort.Open(); + registeredDevicesCount = 0; + //stopWorkerThread = false; //workerThread = new Thread(Worker); //workerThread.Start(); @@ -93,6 +99,27 @@ namespace TBF.Rig.Modbus.Common } + /// + /// Registers a modbus device for scheduled polling + /// + /// Ticket numeber to be used as IsMyTurn() argumenr + public int RegisterForPolling() + { + registeredDevicesCount++; + return registeredDevicesCount; /// 1 .. number of registered devices + } + + /// + /// Determines whether the registered device should do polling now + /// + /// Ticket number in range 1 .. registered devs.count returned by RegisterForPolling() + /// true when yes + public bool IsMyTurn(int ticketNr) + { + return (StateMachine.Time % registeredDevicesCount == ticketNr - 1); + } + + /// /// Send an arbitrary modbus message. /// When the message length is N, however only bytes 1..N-2 have to be set. @@ -189,69 +216,92 @@ namespace TBF.Rig.Modbus.Common /// Run this device public void RunDeviceBefore() { - /// Create 'dataToProcess' buffer with all received bytes - int nrBytes; - if (serialPort == null || (nrBytes = serialPort.BytesToRead) < MinTelegramLen) return; - byte[] dataToProcess = new byte[nrBytes]; - serialPort.Read(dataToProcess, 0, nrBytes); + if (modbusCfg.DebugLevel != DebugMode.Normal || serialPort == null || !serialPort.IsOpen) return; - while (dataToProcess.Length >= MinTelegramLen) + /// Read new received bytes and append them to a buffer + int bytesCount = serialPort.BytesToRead; + if (bytesCount > 0) { - for (int candidateLen = MinTelegramLen; candidateLen <= dataToProcess.Length; candidateLen++) + bytesCount = serialPort.Read(buffer, 0, Math.Min(bytesCount, BUFFER_SIZE)); + } + /// + string st = string.Format("{0}", Name, Telegram.LogTelegram("Received data ", buffer, 0, bytesCount)); + Debug.WriteLine(st); + log.Debug(st); + /// + for (int i = 0; i < bytesCount && rcvdBytesCount < BUFFER_SIZE; i++, rcvdBytesCount++) + { + rcvdData[rcvdBytesCount] = buffer[i]; + } + + /// Try to detect various kinds of data in rcvdData buffer in a loop, start at offset 0 + int offset = 0; + int lastValidOffset = 0; /// Offset of the first byte after the last successfully parsed frame + do + { + bool anyProcessed = false; + + if (offset + 28 <= rcvdBytesCount && + rcvdData[offset] == '\r' && + rcvdData[offset + 1] == '\n' && + rcvdData[offset + 3] == 28 && + rcvdData[offset + 5] == 2) { - if (candidateLen == 28 && - dataToProcess[0] == '\r' && - dataToProcess[1] == '\n' && - dataToProcess[3] == 28 && - dataToProcess[5] == 2) + int sum = 0; + for (int i = offset; i < offset + 27; i++) sum += rcvdData[i]; + /// + if (rcvdData[offset + 27] == (sum & 0xFF)) { - int sum = 0; - for (int i = 0; i < 27; i++) sum += dataToProcess[i]; - /// - if (dataToProcess[27] == (sum & 0xFF)) - { - /// Split data in dataToProcess buffer into the verified telegram and newly created dataToProcess - byte[] receivedTelegram = dataToProcess.Take(candidateLen).ToArray(); - dataToProcess = dataToProcess.Skip(candidateLen).ToArray(); + /// Copy data to a created telegram + byte[] receivedTelegram = new byte[28]; + for (int i = 0; i < 28; i++) receivedTelegram[i] = rcvdData[offset + i]; - /// Enqueue - receivedTelegrams[0].Enqueue(receivedTelegram); + /// Enqueue + receivedTelegrams[0].Enqueue(receivedTelegram); - string s = string.Format("{0} - {1} queue size={2}", Name, Telegram.LogTelegram("Received message ", receivedTelegram), receivedTelegrams[0].Count); - Debug.WriteLine(s); - log.Debug(s); - break; /// Quit for loop - } + string s = string.Format("{0} queue size={1}", Telegram.LogTelegram("Received message ", receivedTelegram), receivedTelegrams[0].Count); + Debug.WriteLine(s); + log.Debug(s); + offset += 28; + lastValidOffset = offset; + anyProcessed = true; } + } - if (Telegram.VerifyTelegramCRC(dataToProcess, candidateLen)) + for (int candidateLen = 4; candidateLen <= rcvdBytesCount - offset; candidateLen++) + { + if (Telegram.VerifyTelegramCRC(offset, rcvdData, candidateLen)) { /// A valid telegram found in dataToProcess buffer - /// Split data in dataToProcess buffer into the verified telegram and newly created dataToProcess - byte[] receivedTelegram = dataToProcess.Take(candidateLen).ToArray(); - dataToProcess = dataToProcess.Skip(candidateLen).ToArray(); + /// Copy data to a created telegram + byte[] receivedTelegram = new byte[candidateLen]; + for (int i = 0; i < candidateLen; i++) receivedTelegram[i] = rcvdData[offset + i]; /// Enqueue int deviceAddress = receivedTelegram[0]; receivedTelegrams[deviceAddress].Enqueue(receivedTelegram); - string s = string.Format("{0} - {1} queue size={2}", Name, Telegram.LogTelegram("Received message ", receivedTelegram), receivedTelegrams[deviceAddress].Count); + string s = string.Format("{0} queue size={1}", Telegram.LogTelegram("Received message ", receivedTelegram), receivedTelegrams[deviceAddress].Count); Debug.WriteLine(s); log.Debug(s); - break; /// Quit for loop - } - else if (candidateLen == dataToProcess.Length) - { - /// All bytes considered but no valid telegram found - string s = Telegram.LogTelegram(string.Format("{0} - Invalid data received ", Name), dataToProcess); - Debug.WriteLine(s); - log.Debug(s); - return; + offset += candidateLen; + lastValidOffset = offset; + anyProcessed = true; } } + + if (!anyProcessed) offset++; } - } + while (offset <= rcvdBytesCount - 4); + + /// Remove processed data from the receive buffer + for (int i = lastValidOffset; i < rcvdBytesCount; i++) + { + rcvdData[i - lastValidOffset] = rcvdData[i]; + } + rcvdBytesCount -= lastValidOffset; + } /// Run this device public void RunDeviceAfter() diff --git a/TBF/Rig/Modbus/Easytherm/Easytherm.cs b/TBF/Rig/Modbus/Easytherm/Easytherm.cs index f9962f5f7..2864680ca 100644 --- a/TBF/Rig/Modbus/Easytherm/Easytherm.cs +++ b/TBF/Rig/Modbus/Easytherm/Easytherm.cs @@ -24,9 +24,10 @@ namespace TBF.Rig.Modbus.Easytherm public float requiredTemp { get { return easythermCfg.ProcParams.RequiredTemp; } } - public Easytherm() - { - } + int ticketNumber; /// 1 .. number of devices registered for regular polling + + + public Easytherm() { } public Easytherm(Generic.IComponentCfg cfg, IList components) : base(cfg) @@ -47,6 +48,7 @@ namespace TBF.Rig.Modbus.Easytherm temperatureSetPointValid = false; temperatureSetPointRequested = false; actualTemperatureIsValid = false; + ticketNumber = modbus.RegisterForPolling(); } /// Run this device @@ -81,26 +83,31 @@ namespace TBF.Rig.Modbus.Easytherm // StateMachine.ControlBoard.UpdateUI("ReservoirTemp", easythermCfg.ReservoirNr, actualTemperature); } } - } - - - if (!temperatureSetPointValid && !temperatureSetPointRequested) - { - RequestTemperatureSetpoint(); - temperatureSetPointRequested = true; - } - else if (temperatureSetPointValid && requiredTemp != temperatureSetPoint) - { - SetTemperatureSetpoint(requiredTemp); - log.InfoFormat("{0} - Set new temperature setpoint = {1}", Name, requiredTemp); - } - else if ((StateMachine.Time % 10) == (easythermCfg.ModbusAddress % 10)) /// This is to prevent overflow of the Modbus component queue for sending data + } + } + + public void RunDeviceAfter() + { + if (easythermCfg.DebugLevel != Config.Entities.DebugMode.Simulate && + easythermCfg.DebugLevel != Config.Entities.DebugMode.FailureDuringOperation) { - RequestActualTemperature(); + if (!temperatureSetPointValid && !temperatureSetPointRequested) + { + RequestTemperatureSetpoint(); + temperatureSetPointRequested = true; + } + else if (temperatureSetPointValid && requiredTemp != temperatureSetPoint) + { + SetTemperatureSetpoint(requiredTemp); + log.InfoFormat("{0} - Set new temperature setpoint = {1}", Name, requiredTemp); + } + else if (modbus.IsMyTurn(ticketNumber)) + { + RequestActualTemperature(); + } } } - public void RunDeviceAfter() { } public void StopDevice() { } public void StopDevice2() { } diff --git a/TBF/Rig/Modbus/Enums.cs b/TBF/Rig/Modbus/Enums.cs index f94f9be86..fa1f1e7d8 100644 --- a/TBF/Rig/Modbus/Enums.cs +++ b/TBF/Rig/Modbus/Enums.cs @@ -20,6 +20,6 @@ namespace TBF.Rig.Modbus public static class Constants { - public const int ModbusPollPeriod = 4; + public const int ModbusPollPeriod = 5; } } diff --git a/TBF/Rig/Modbus/PressureMeter/Meret/PressureMeter.cs b/TBF/Rig/Modbus/PressureMeter/Meret/PressureMeter.cs index 08842138f..0e4c2b4c8 100644 --- a/TBF/Rig/Modbus/PressureMeter/Meret/PressureMeter.cs +++ b/TBF/Rig/Modbus/PressureMeter/Meret/PressureMeter.cs @@ -25,6 +25,8 @@ namespace TBF.Rig.Modbus.PressureMeter.Meret public double MeasuredVal { get { return receivedPressure; } } public string AltString { get { return string.Empty; } } + int ticketNumber; /// 1 .. number of devices registered for regular polling + public PressureMeter() { } @@ -42,7 +44,10 @@ namespace TBF.Rig.Modbus.PressureMeter.Meret /// /// IDevice interface /// - public void Initialize() { } + public void Initialize() + { + ticketNumber = modbus.RegisterForPolling(); + } public void RunDeviceBefore() { @@ -71,8 +76,13 @@ namespace TBF.Rig.Modbus.PressureMeter.Meret log.WarnFormat("Pressure: {0}={1}bar", Name, receivedPressure.ToString("F3")); } } + } - if ((StateMachine.Time % Constants.ModbusPollPeriod) == (pressureMtrCfg.ModbusAddress % Constants.ModbusPollPeriod)) /// Each 'ModbusDevices' seconds + public void RunDeviceAfter() + { + if (pressureMtrCfg.DebugLevel != Config.Entities.DebugMode.Simulate && + pressureMtrCfg.DebugLevel != Config.Entities.DebugMode.FailureDuringOperation && + modbus.IsMyTurn(ticketNumber)) { const byte Function = 4; /// Read input registers const ushort Address = 0; /// Pressure @@ -80,7 +90,6 @@ namespace TBF.Rig.Modbus.PressureMeter.Meret } } - public void RunDeviceAfter() { } public void StopDevice() { } public void StopDevice2() { } diff --git a/TBF/Rig/Modbus/TempMeter/Groch/TempMeter.cs b/TBF/Rig/Modbus/TempMeter/Groch/TempMeter.cs index 974a575e8..d8d5688cd 100644 --- a/TBF/Rig/Modbus/TempMeter/Groch/TempMeter.cs +++ b/TBF/Rig/Modbus/TempMeter/Groch/TempMeter.cs @@ -42,9 +42,10 @@ namespace TBF.Rig.Modbus.TempMeter.Groch public double MeasuredVal { get { return ReadTemperature(); } } public string AltString { get { return "Invalid format"; } } - public TempMeter() - { - } + int ticketNumber; /// 1 .. number of devices registered for regular polling + + + public TempMeter() { } public TempMeter(Generic.IComponentCfg cfg, IList components) : base(cfg) @@ -89,7 +90,15 @@ namespace TBF.Rig.Modbus.TempMeter.Groch return calendarEvents; } - public void Initialize() { } + public void Initialize() + { + /// Only TempMeter with Channel == 0 communicates via the parent Modbus component + if (Channel == 0) + { + ticketNumber = modbus.RegisterForPolling(); + } + } + public void RunDeviceBefore() { if (Channel != 0 || @@ -104,7 +113,7 @@ namespace TBF.Rig.Modbus.TempMeter.Groch /// if (modbus.ReceivedTelegrams[0].Count > 0) { - byte[] telegram = modbus.ReceivedTelegrams[GrochAddress].Dequeue(); + byte[] telegram = modbus.ReceivedTelegrams[0].Dequeue(); if (telegram.Length == 28) { byte checksum = 0; @@ -138,17 +147,12 @@ namespace TBF.Rig.Modbus.TempMeter.Groch } public void RunDeviceAfter() { - if (Channel != 0 || - tempMtrCfg.DebugLevel == Config.Entities.DebugMode.Simulate || - tempMtrCfg.DebugLevel == Config.Entities.DebugMode.FailureDuringOperation) - { - return; - } - - /// /// Only TempMeter with Channel == 0 communicates via the parent Modbus component - /// - if ((StateMachine.Time % Constants.ModbusPollPeriod) == Constants.ModbusPollPeriod) /// Each 'ModbusDevices' seconds + + if (Channel == 0 && + tempMtrCfg.DebugLevel != Config.Entities.DebugMode.Simulate && + tempMtrCfg.DebugLevel != Config.Entities.DebugMode.FailureDuringOperation && + modbus.IsMyTurn(ticketNumber)) { modbus.SendMessageGroch(new byte[] { 0x20, 0x20, 0x20, 0x20, 0x10, 2, 1, 3, 6, 0x16 }); } diff --git a/TBF/Rig/Modbus/TempMeter/Meret/TempMeter.cs b/TBF/Rig/Modbus/TempMeter/Meret/TempMeter.cs index 7907190b2..22b9934da 100644 --- a/TBF/Rig/Modbus/TempMeter/Meret/TempMeter.cs +++ b/TBF/Rig/Modbus/TempMeter/Meret/TempMeter.cs @@ -25,6 +25,8 @@ namespace TBF.Rig.Modbus.TempMeter.Meret public double MeasuredVal { get { return receivedTemp; } } public string AltString { get { return string.Empty; } } + int ticketNumber; /// 1 .. number of devices registered for regular polling + public TempMeter() { } @@ -42,7 +44,10 @@ namespace TBF.Rig.Modbus.TempMeter.Meret /// /// IDevice interface /// - public void Initialize() { } + public void Initialize() + { + ticketNumber = modbus.RegisterForPolling(); + } /// Run this device public void RunDeviceBefore() @@ -72,8 +77,13 @@ namespace TBF.Rig.Modbus.TempMeter.Meret log.WarnFormat("Temperature: {0}={1}°C", Name, receivedTemp.ToString("F1")); } } + } - if ((StateMachine.Time % Constants.ModbusPollPeriod) == (tempMtrCfg.ModbusAddress % Constants.ModbusPollPeriod)) /// Each 'ModbusDevices' seconds + public void RunDeviceAfter() + { + if (tempMtrCfg.DebugLevel != Config.Entities.DebugMode.Simulate && + tempMtrCfg.DebugLevel != Config.Entities.DebugMode.FailureDuringOperation && + modbus.IsMyTurn(ticketNumber)) { const byte Function = 4; /// Read input registers const ushort Address = 0; /// Temperature @@ -81,7 +91,6 @@ namespace TBF.Rig.Modbus.TempMeter.Meret } } - public void RunDeviceAfter() { } public void StopDevice() { } public void StopDevice2() { } diff --git a/TBF/Rig/Modbus/UltrasoundLevelMeter/LevelMeter.cs b/TBF/Rig/Modbus/UltrasoundLevelMeter/LevelMeter.cs index 680fc44b4..49470ccf1 100644 --- a/TBF/Rig/Modbus/UltrasoundLevelMeter/LevelMeter.cs +++ b/TBF/Rig/Modbus/UltrasoundLevelMeter/LevelMeter.cs @@ -36,10 +36,10 @@ namespace TBF.Rig.Modbus.UltrasoundLevelMeter /// Measurement time stamp when MsrmntState == MsrmntState.Valid int msrmntTimeStamp; + int ticketNumber; /// 1 .. number of devices registered for regular polling - public LevelMeter() - { - } + + public LevelMeter() { } public LevelMeter(Generic.IComponentCfg cfg, IList components) : base(cfg) @@ -72,6 +72,7 @@ namespace TBF.Rig.Modbus.UltrasoundLevelMeter } msrmntState = MsrmntState.Busy; + ticketNumber = modbus.RegisterForPolling(); log.FatalFormat("Successfully initialized device {0}", ToString()); } @@ -124,11 +125,13 @@ namespace TBF.Rig.Modbus.UltrasoundLevelMeter Debug.WriteLine(line); } } + } - - byte[] msg = new byte[8]; /// Buffer for data to send - - if ((StateMachine.Time % 3) == 0) /// Each 3 seconds + public void RunDeviceAfter() + { + if (myCfg.DebugLevel != Config.Entities.DebugMode.Simulate && + myCfg.DebugLevel != Config.Entities.DebugMode.FailureDuringOperation && + modbus.IsMyTurn(ticketNumber)) { /// /// Read distance, level, quantity, percentage and temperature in IEEE754 (DWORD-s) @@ -137,17 +140,15 @@ namespace TBF.Rig.Modbus.UltrasoundLevelMeter UInt16 count = 5; /// Prepare data to be sent + byte[] msg = new byte[8]; /// Buffer for data to send msg[0] = myCfg.ModbusAddress; msg[1] = 3; /// CMD = msg[2] = (byte)(regAddr >> 8); /// Control Word Hi msg[3] = (byte)(regAddr & 0xFF); /// Control Word Lo msg[4] = (byte)(count >> 8); /// Serial Com Reference Hi msg[5] = (byte)(count & 0xFF); /// Serial Com Reference Lo - modbus.SendMessage(msg); - } - else if ((StateMachine.Time % 3) == 1) /// Each 3 seconds - { + ///// ///// Read STATUS1 ///// @@ -155,17 +156,15 @@ namespace TBF.Rig.Modbus.UltrasoundLevelMeter //UInt16 count = 1; ///// Prepare data to be sent + //byte[] msg = new byte[8]; /// Buffer for data to send //msg[0] = myCfg.ModbusAddress; //msg[1] = 3; /// CMD = //msg[2] = (byte)(regAddr >> 8); /// Control Word Hi //msg[3] = (byte)(regAddr & 0xFF); /// Control Word Lo //msg[4] = (byte)(count >> 8); /// Serial Com Reference Hi //msg[5] = (byte)(count & 0xFF); /// Serial Com Reference Lo - //modbus.SendMessage(msg); - } - else if ((StateMachine.Time % 3) == 2) /// Each 3 seconds - { + ///// ///// Read distance, level, quantity, percentage and temperature in IEEE754 (DWORD-s) ///// @@ -173,18 +172,17 @@ namespace TBF.Rig.Modbus.UltrasoundLevelMeter //UInt16 count = 10; ///// Prepare data to be sent + //byte[] msg = new byte[8]; /// Buffer for data to send //msg[0] = myCfg.ModbusAddress; //msg[1] = 3; /// CMD = //msg[2] = (byte)(regAddr >> 8); /// Control Word Hi //msg[3] = (byte)(regAddr & 0xFF); /// Control Word Lo //msg[4] = (byte)(count >> 8); /// Serial Com Reference Hi //msg[5] = (byte)(count & 0xFF); /// Serial Com Reference Lo - //modbus.SendMessage(msg); } } - public void RunDeviceAfter() { } public void StopDevice() { } public void StopDevice2() { } } diff --git a/TBF/Rig/Modbus/WaterAnalyzer/Analyzer.cs b/TBF/Rig/Modbus/WaterAnalyzer/Analyzer.cs index ab4756316..598954cbf 100644 --- a/TBF/Rig/Modbus/WaterAnalyzer/Analyzer.cs +++ b/TBF/Rig/Modbus/WaterAnalyzer/Analyzer.cs @@ -33,10 +33,10 @@ namespace TBF.Rig.Modbus.WaterAnalyzer /// Measurement time stamp when MsrmntState == MsrmntState.Valid int msrmntTimeStamp; + int ticketNumber; /// 1 .. number of devices registered for regular polling - public Analyzer() - { - } + + public Analyzer() { } public Analyzer(Generic.IComponentCfg cfg, IList components) : base(cfg) @@ -66,6 +66,7 @@ namespace TBF.Rig.Modbus.WaterAnalyzer } msrmntState = MsrmntState.Busy; + ticketNumber = modbus.RegisterForPolling(); log.FatalFormat("Successfully initialized device {0}", ToString()); } @@ -107,11 +108,13 @@ namespace TBF.Rig.Modbus.WaterAnalyzer Debug.WriteLine(line); } } + } - - byte[] msg = new byte[8]; /// Buffer for data to send - - if ((StateMachine.Time % 10) == 0) /// Each 10 seconds + public void RunDeviceAfter() + { + if (myCfg.DebugLevel != Config.Entities.DebugMode.Simulate && + myCfg.DebugLevel != Config.Entities.DebugMode.FailureDuringOperation && + modbus.IsMyTurn(ticketNumber)) { /// /// Send command to request 1 float value in 2 registers at addresses 0x50 and 0x51 from Modbus.WaterAnalyzer @@ -120,6 +123,7 @@ namespace TBF.Rig.Modbus.WaterAnalyzer UInt16 count = 2; /// Prepare data to be sent + byte[] msg = new byte[8]; /// Buffer for data to send msg[0] = myCfg.ModbusAddress; msg[1] = 3; /// CMD = msg[2] = (byte)(regAddr >> 8); /// Control Word Hi @@ -131,7 +135,6 @@ namespace TBF.Rig.Modbus.WaterAnalyzer } } - public void RunDeviceAfter() { } public void StopDevice() { } public void StopDevice2() { } diff --git a/TBF/Rig/StateMachine.cs b/TBF/Rig/StateMachine.cs index 530bc20ee..9f8eb7369 100644 --- a/TBF/Rig/StateMachine.cs +++ b/TBF/Rig/StateMachine.cs @@ -812,9 +812,12 @@ namespace TBF.Rig { Thread.Sleep(100); /// Insert 1/10 sec.delay between RunOperations() and RunDeviceAfter() - foreach (var device in devices) + /// Call RunDeviceAfter() functions in reversed order + /// so that the parent compnent's RunDeviceAfter() + /// is called after RunDeviceAfter() of it's children. + for (int i = devices.Count - 1; i >= 0; i--) { - device.RunDeviceAfter(); + devices[i].RunDeviceAfter(); } WaitNextTick();