|
|
|
@ -0,0 +1,700 @@
|
|
|
|
|
using File_Watcher.Models;
|
|
|
|
|
using System.Diagnostics;
|
|
|
|
|
using System.Net.Sockets;
|
|
|
|
|
|
|
|
|
|
namespace File_Watcher.Helpers;
|
|
|
|
|
|
|
|
|
|
#pragma warning disable IDE0300
|
|
|
|
|
|
|
|
|
|
internal static partial class LabJackT7Helper
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
private static ModbusTransmissionControlProtocolClient? _ModbusTransmissionControlProtocolClient;
|
|
|
|
|
|
|
|
|
|
private class ModbusTransmissionControlProtocolClient : IDisposable
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
private ushort _TransactionID;
|
|
|
|
|
private NetworkStream? _NetworkStream;
|
|
|
|
|
private TcpClient? _TransmissionControlProtocolClient;
|
|
|
|
|
|
|
|
|
|
public ModbusTransmissionControlProtocolClient(string hostname, int port) =>
|
|
|
|
|
Connect(hostname, port);
|
|
|
|
|
|
|
|
|
|
public void Connect(string hostname, int port)
|
|
|
|
|
{
|
|
|
|
|
if (_TransmissionControlProtocolClient is not null)
|
|
|
|
|
Close();
|
|
|
|
|
|
|
|
|
|
_TransmissionControlProtocolClient = new TcpClient(hostname, port);
|
|
|
|
|
_NetworkStream = _TransmissionControlProtocolClient.GetStream();
|
|
|
|
|
_TransactionID = 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void Close()
|
|
|
|
|
{
|
|
|
|
|
_NetworkStream?.Close();
|
|
|
|
|
_NetworkStream = null;
|
|
|
|
|
|
|
|
|
|
_TransmissionControlProtocolClient?.Close();
|
|
|
|
|
_TransmissionControlProtocolClient = null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public bool IsConnected()
|
|
|
|
|
{
|
|
|
|
|
if (_TransmissionControlProtocolClient is not null)
|
|
|
|
|
return _TransmissionControlProtocolClient.Connected;
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void SetTimeouts(int sendTimeout, int receiveTimeout)
|
|
|
|
|
{
|
|
|
|
|
if (_TransmissionControlProtocolClient == null)
|
|
|
|
|
throw new Exception("Not connected.");
|
|
|
|
|
_TransmissionControlProtocolClient.ReceiveTimeout = receiveTimeout;
|
|
|
|
|
_TransmissionControlProtocolClient.SendTimeout = sendTimeout;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Write a byte array of data to the Modbus device.
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="address">The starting register address.</param>
|
|
|
|
|
/// <param name="data">The byte array of data to write.</param>
|
|
|
|
|
public void Write(ushort address, byte[] data)
|
|
|
|
|
{
|
|
|
|
|
if (_NetworkStream is null)
|
|
|
|
|
throw new Exception("Not connected.");
|
|
|
|
|
|
|
|
|
|
//Using Modbus function 16
|
|
|
|
|
|
|
|
|
|
//Create Modbus Command
|
|
|
|
|
if (data.Length > 254)
|
|
|
|
|
throw new Exception("Too many bytes. The maximum is 254.");
|
|
|
|
|
|
|
|
|
|
if (data.Length % 2 != 0)
|
|
|
|
|
throw new Exception("The number of bytes needs to be a multiple of 2.");
|
|
|
|
|
|
|
|
|
|
byte[] com = new byte[13 + data.Length];
|
|
|
|
|
com[7] = 16;
|
|
|
|
|
com[8] = (byte)(address >> 8);
|
|
|
|
|
com[9] = (byte)(address & 0xFF);
|
|
|
|
|
com[10] = 0;
|
|
|
|
|
com[11] = (byte)(data.Length / 2);
|
|
|
|
|
com[12] = (byte)data.Length;
|
|
|
|
|
Array.Copy(data, 0, com, 13, data.Length);
|
|
|
|
|
SetHeader(com);
|
|
|
|
|
_NetworkStream.Write(com, 0, com.Length);
|
|
|
|
|
|
|
|
|
|
byte[] res = new byte[12];
|
|
|
|
|
int expectedSize = res.Length;
|
|
|
|
|
int size = _NetworkStream.Read(res, 0, res.Length);
|
|
|
|
|
|
|
|
|
|
Array.Resize(ref res, size);
|
|
|
|
|
ResponseErrorChecks(res, expectedSize, com);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Read a byte array of data from the Modbus device.
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="address">The starting register address.</param>
|
|
|
|
|
/// <param name="data">The read byte array of data. The array length is
|
|
|
|
|
/// the amount of bytes to read.</param>
|
|
|
|
|
public void Read(ushort address, byte[] data)
|
|
|
|
|
{
|
|
|
|
|
if (_NetworkStream is null)
|
|
|
|
|
throw new Exception("Not connected.");
|
|
|
|
|
|
|
|
|
|
//Using Modbus function 3
|
|
|
|
|
|
|
|
|
|
//Create Modbus Command
|
|
|
|
|
if (data.Length > 254)
|
|
|
|
|
throw new Exception("Too many bytes. The maximum is 254.");
|
|
|
|
|
|
|
|
|
|
if (data.Length % 2 != 0)
|
|
|
|
|
throw new Exception("The number of bytes needs to be a multiple of 2.");
|
|
|
|
|
|
|
|
|
|
byte[] com = new byte[12];
|
|
|
|
|
com[7] = 3;
|
|
|
|
|
com[8] = (byte)(address >> 8);
|
|
|
|
|
com[9] = (byte)(address & 0xFF);
|
|
|
|
|
com[10] = 0;
|
|
|
|
|
com[11] = (byte)(data.Length / 2);
|
|
|
|
|
SetHeader(com);
|
|
|
|
|
_NetworkStream.Write(com, 0, com.Length);
|
|
|
|
|
|
|
|
|
|
byte[] res = new byte[9 + data.Length];
|
|
|
|
|
int expectedSize = res.Length;
|
|
|
|
|
int size = _NetworkStream.Read(res, 0, res.Length);
|
|
|
|
|
Array.Resize(ref res, size);
|
|
|
|
|
ResponseErrorChecks(res, expectedSize, com);
|
|
|
|
|
|
|
|
|
|
Array.Copy(res, 9, data, 0, data.Length);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Write an ushort array of data to the Modbus device.
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="address">The starting register address.</param>
|
|
|
|
|
/// <param name="data">The ushort array of data to write.</param>
|
|
|
|
|
public void Write(ushort address, ushort[] data)
|
|
|
|
|
{
|
|
|
|
|
if (data.Length > 127)
|
|
|
|
|
throw new Exception("Too many shorts. The maximum is 127.");
|
|
|
|
|
|
|
|
|
|
byte[] bytes = new byte[data.Length * 2];
|
|
|
|
|
for (int i = 0; i < data.Length; i++)
|
|
|
|
|
{
|
|
|
|
|
BitConverter.GetBytes(data[i]).CopyTo(bytes, i * 2);
|
|
|
|
|
if (BitConverter.IsLittleEndian)
|
|
|
|
|
Array.Reverse(bytes, i * 2, 2);
|
|
|
|
|
}
|
|
|
|
|
Write(address, bytes);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Read an ushort array of data from the Modbus device.
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="address">The starting register address.</param>
|
|
|
|
|
/// <param name="data">The read ushort array of data. The array length
|
|
|
|
|
/// is the amount of shorts to read.</param>
|
|
|
|
|
public void Read(ushort address, ushort[] data)
|
|
|
|
|
{
|
|
|
|
|
if (data.Length > 127)
|
|
|
|
|
throw new Exception("Too many shorts. The maximum is 127.");
|
|
|
|
|
|
|
|
|
|
byte[] bytes = new byte[data.Length * 2];
|
|
|
|
|
Read(address, bytes);
|
|
|
|
|
for (int i = 0; i < data.Length; i++)
|
|
|
|
|
{
|
|
|
|
|
if (BitConverter.IsLittleEndian)
|
|
|
|
|
Array.Reverse(bytes, i * 2, 2);
|
|
|
|
|
data[i] = BitConverter.ToUInt16(bytes, i * 2);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Write an uint array of data to the Modbus device.
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="address">The starting register address.</param>
|
|
|
|
|
/// <param name="data">The uint array of data to write.</param>
|
|
|
|
|
public void Write(ushort address, uint[] data)
|
|
|
|
|
{
|
|
|
|
|
if (data.Length > 63)
|
|
|
|
|
throw new Exception("Too many uint. The maximum is 63.");
|
|
|
|
|
|
|
|
|
|
byte[] bytes = new byte[data.Length * 4];
|
|
|
|
|
for (int i = 0; i < data.Length; i++)
|
|
|
|
|
{
|
|
|
|
|
BitConverter.GetBytes(data[i]).CopyTo(bytes, i * 4);
|
|
|
|
|
if (BitConverter.IsLittleEndian)
|
|
|
|
|
Array.Reverse(bytes, i * 4, 4);
|
|
|
|
|
}
|
|
|
|
|
Write(address, bytes);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Read an uint array of data from the Modbus device.
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="address">The starting register address.</param>
|
|
|
|
|
/// <param name="data">The read uint array of data. The array length is
|
|
|
|
|
/// the amount of ints to read.</param>
|
|
|
|
|
public void Read(ushort address, uint[] data)
|
|
|
|
|
{
|
|
|
|
|
if (data.Length > 63)
|
|
|
|
|
throw new Exception("Too many ints. The maximum is 63.");
|
|
|
|
|
|
|
|
|
|
byte[] bytes = new byte[data.Length * 4];
|
|
|
|
|
Read(address, bytes);
|
|
|
|
|
for (int i = 0; i < data.Length; i++)
|
|
|
|
|
{
|
|
|
|
|
if (BitConverter.IsLittleEndian)
|
|
|
|
|
Array.Reverse(bytes, i * 4, 4);
|
|
|
|
|
data[i] = BitConverter.ToUInt32(bytes, i * 4);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Write an int array of data to the Modbus device.
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="address">The starting register address.</param>
|
|
|
|
|
/// <param name="data">The int array of data to write.</param>
|
|
|
|
|
public void Write(ushort address, int[] data)
|
|
|
|
|
{
|
|
|
|
|
if (data.Length > 63)
|
|
|
|
|
throw new Exception("Too many ints. The maximum is 63.");
|
|
|
|
|
|
|
|
|
|
byte[] bytes = new byte[data.Length * 4];
|
|
|
|
|
for (int i = 0; i < data.Length; i++)
|
|
|
|
|
{
|
|
|
|
|
BitConverter.GetBytes(data[i]).CopyTo(bytes, i * 4);
|
|
|
|
|
if (BitConverter.IsLittleEndian)
|
|
|
|
|
Array.Reverse(bytes, i * 4, 4);
|
|
|
|
|
}
|
|
|
|
|
Write(address, bytes);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Read an int array of data from the Modbus device.
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="address">The starting register address.</param>
|
|
|
|
|
/// <param name="data">The read int array of data. The array length is
|
|
|
|
|
/// the amount of ints to read.</param>
|
|
|
|
|
public void Read(ushort address, int[] data)
|
|
|
|
|
{
|
|
|
|
|
if (data.Length > 63)
|
|
|
|
|
throw new Exception("Too many ints. The maximum is 63.");
|
|
|
|
|
|
|
|
|
|
byte[] bytes = new byte[data.Length * 4];
|
|
|
|
|
Read(address, bytes);
|
|
|
|
|
for (int i = 0; i < data.Length; i++)
|
|
|
|
|
{
|
|
|
|
|
if (BitConverter.IsLittleEndian)
|
|
|
|
|
Array.Reverse(bytes, i * 4, 4);
|
|
|
|
|
data[i] = BitConverter.ToInt32(bytes, i * 4);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Write a float array of data to the Modbus device.
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="address">The starting register address.</param>
|
|
|
|
|
/// <param name="data">The float array of data to write.</param>
|
|
|
|
|
public void Write(ushort address, float[] data)
|
|
|
|
|
{
|
|
|
|
|
if (data.Length > 63)
|
|
|
|
|
throw new Exception("Too many floats. The maximum is 63.");
|
|
|
|
|
|
|
|
|
|
byte[] bytes = new byte[data.Length * 4];
|
|
|
|
|
for (int i = 0; i < data.Length; i++)
|
|
|
|
|
{
|
|
|
|
|
BitConverter.GetBytes(data[i]).CopyTo(bytes, i * 4);
|
|
|
|
|
if (BitConverter.IsLittleEndian)
|
|
|
|
|
Array.Reverse(bytes, i * 4, 4);
|
|
|
|
|
}
|
|
|
|
|
Write(address, bytes);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Reads a float array of data from the Modbus device.
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="address">The starting register address.</param>
|
|
|
|
|
/// <param name="data">The read float array of data. The array length is
|
|
|
|
|
/// the amount of floats to read.</param>
|
|
|
|
|
public void Read(ushort address, float[] data)
|
|
|
|
|
{
|
|
|
|
|
if (data.Length > 63)
|
|
|
|
|
throw new Exception("Too many floats. The maximum is 63.");
|
|
|
|
|
|
|
|
|
|
byte[] bytes = new byte[data.Length * 4];
|
|
|
|
|
Read(address, bytes);
|
|
|
|
|
for (int i = 0; i < data.Length; i++)
|
|
|
|
|
{
|
|
|
|
|
if (BitConverter.IsLittleEndian)
|
|
|
|
|
Array.Reverse(bytes, i * 4, 4);
|
|
|
|
|
data[i] = BitConverter.ToSingle(bytes, i * 4);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Write a single ushort of data to the Modbus device.
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="address">The register address.</param>
|
|
|
|
|
/// <param name="data">The ushort data to write.</param>
|
|
|
|
|
public void Write(ushort address, ushort data)
|
|
|
|
|
{
|
|
|
|
|
ushort[] dataArray = new ushort[1];
|
|
|
|
|
dataArray[0] = data;
|
|
|
|
|
Write(address, dataArray);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Read a single ushort of data from the Modbus device.
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="address">The register address.</param>
|
|
|
|
|
/// <param name="data">The read ushort data.</param>
|
|
|
|
|
public void Read(ushort address, ref ushort data)
|
|
|
|
|
{
|
|
|
|
|
ushort[] dataArray = new ushort[1];
|
|
|
|
|
Read(address, dataArray);
|
|
|
|
|
data = dataArray[0];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Write a single uint of data to the Modbus device.
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="address">The starting register address.</param>
|
|
|
|
|
/// <param name="data">The uint data to write.</param>
|
|
|
|
|
public void Write(ushort address, uint data)
|
|
|
|
|
{
|
|
|
|
|
uint[] dataArray = new uint[1];
|
|
|
|
|
dataArray[0] = data;
|
|
|
|
|
Write(address, dataArray);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Read a single uint of data from the Modbus device.
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="address">The starting register address.</param>
|
|
|
|
|
/// <param name="value">The read uint data.</param>
|
|
|
|
|
public void Read(ushort address, ref uint data)
|
|
|
|
|
{
|
|
|
|
|
uint[] dataArray = new uint[1];
|
|
|
|
|
Read(address, dataArray);
|
|
|
|
|
data = dataArray[0];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Write a single int of data to the Modbus device.
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="address">The starting register address.</param>
|
|
|
|
|
/// <param name="data">The int data to write.</param>
|
|
|
|
|
public void Write(ushort address, int data)
|
|
|
|
|
{
|
|
|
|
|
int[] dataArray = new int[1];
|
|
|
|
|
dataArray[0] = data;
|
|
|
|
|
Write(address, dataArray);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Read a single int of data from the Modbus device.
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="address">The starting register address.</param>
|
|
|
|
|
/// <param name="data">The read int data.</param>
|
|
|
|
|
public void Read(ushort address, ref int data)
|
|
|
|
|
{
|
|
|
|
|
int[] dataArray = new int[1];
|
|
|
|
|
Read(address, dataArray);
|
|
|
|
|
data = dataArray[0];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Write a single float of data to the Modbus device.
|
|
|
|
|
/// 1 uint = 2 registers.
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="address">The starting register address.</param>
|
|
|
|
|
/// <param name="data">The float data to write.</param>
|
|
|
|
|
public void Write(ushort address, float data)
|
|
|
|
|
{
|
|
|
|
|
float[] dataArray = new float[1];
|
|
|
|
|
dataArray[0] = data;
|
|
|
|
|
Write(address, dataArray);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Read a single float of data from the Modbus device.
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="address">The starting register address.</param>
|
|
|
|
|
/// <param name="data">The read float data.</param>
|
|
|
|
|
public void Read(ushort address, ref float data)
|
|
|
|
|
{
|
|
|
|
|
float[] dataArray = new float[1];
|
|
|
|
|
Read(address, dataArray);
|
|
|
|
|
data = dataArray[0];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Sets the MBAP header of the Modbus TCP command.
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="command">The byte array for the Modbus TCP command.
|
|
|
|
|
/// The Modbus request bytes 7+ need to be set beforehand. The MBAP
|
|
|
|
|
/// header bytes 0 to 6 will be updated based on the request bytes.
|
|
|
|
|
/// </param>
|
|
|
|
|
private void SetHeader(byte[] command)
|
|
|
|
|
{
|
|
|
|
|
//Transaction ID
|
|
|
|
|
ushort transID = _TransactionID;
|
|
|
|
|
if (_TransactionID >= 65535)
|
|
|
|
|
{
|
|
|
|
|
//Rollover global transaction ID to 0.
|
|
|
|
|
_TransactionID = 0;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
//Increment global transaction ID.
|
|
|
|
|
_TransactionID++;
|
|
|
|
|
}
|
|
|
|
|
command[0] = (byte)(transID >> 8);
|
|
|
|
|
command[1] = (byte)(transID & 0xFF);
|
|
|
|
|
|
|
|
|
|
//Protocol ID
|
|
|
|
|
command[2] = 0;
|
|
|
|
|
command[3] = 0;
|
|
|
|
|
|
|
|
|
|
//Length
|
|
|
|
|
ushort length = (ushort)(command.Length - 6);
|
|
|
|
|
command[4] = (byte)(length >> 8);
|
|
|
|
|
command[5] = (byte)(length & 0xFF);
|
|
|
|
|
|
|
|
|
|
//Unit ID
|
|
|
|
|
command[6] = 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Checks the Modbus response for errors.
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="response">The Modbus response byte array.</param>
|
|
|
|
|
/// <param name="expectedSize">The expected response byte array length.</param>
|
|
|
|
|
/// <param name="command">The Modbus command byte array.</param>
|
|
|
|
|
private void ResponseErrorChecks(byte[] response, int expectedLength, byte[] command)
|
|
|
|
|
{
|
|
|
|
|
if (response.Length < expectedLength)
|
|
|
|
|
{
|
|
|
|
|
if (response.Length < 9)
|
|
|
|
|
{
|
|
|
|
|
throw new Exception("Invalid Modbus response.");
|
|
|
|
|
}
|
|
|
|
|
if ((response[7] & 0x80) > 0)
|
|
|
|
|
{
|
|
|
|
|
//Bit 7 set, indicating Modbus error
|
|
|
|
|
throw new Exception("Modbus exception code " + response[8] +
|
|
|
|
|
", " + GetExceptionCodeString(response[8]) + ".");
|
|
|
|
|
}
|
|
|
|
|
throw new Exception("Other Modbus response error.");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (response[0] != command[0] || response[1] != command[1])
|
|
|
|
|
{
|
|
|
|
|
throw new Exception("Modbus transaction ID mismatch.");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Get the Modbus exception name.
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="code">The exception code.</param>
|
|
|
|
|
/// <returns>The exception name.</returns>
|
|
|
|
|
private string GetExceptionCodeString(uint code) =>
|
|
|
|
|
code switch
|
|
|
|
|
{
|
|
|
|
|
1 => "Illegal Function",
|
|
|
|
|
2 => "Illegal Data Address",
|
|
|
|
|
3 => "Illegal Data Value",
|
|
|
|
|
4 => "Slave Device Failure",
|
|
|
|
|
5 => "Acknowledge",
|
|
|
|
|
6 => "Slave Device Busy",
|
|
|
|
|
7 => "Negative Acknowledge",
|
|
|
|
|
8 => "Memory Parity Error",
|
|
|
|
|
10 => "Gateway Path Unavailable",
|
|
|
|
|
11 => "Gateway Target Device Failed to Respond",
|
|
|
|
|
_ => ""
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
void IDisposable.Dispose() =>
|
|
|
|
|
Close();
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
internal static bool ReadAll(AppSettings appSettings, ILogger<Worker> logger)
|
|
|
|
|
{
|
|
|
|
|
LabJackT7Configuration configuration = appSettings.LabJackT7Configuration;
|
|
|
|
|
_ModbusTransmissionControlProtocolClient ??= new(configuration.InternetProtocolAddress, configuration.Port);
|
|
|
|
|
ReadAllAnalog(_ModbusTransmissionControlProtocolClient, logger);
|
|
|
|
|
ReadAllDigitalIO(_ModbusTransmissionControlProtocolClient, logger);
|
|
|
|
|
if (configuration.InternetProtocolAddress == "false")
|
|
|
|
|
ReadAllAnalogMux80(_ModbusTransmissionControlProtocolClient, logger);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Displays "AINxx : Values" readings.
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="startingAddress">Starting Modbus address of
|
|
|
|
|
/// readings.</param>
|
|
|
|
|
/// <param name="values">Float analog input (AIN) readings.</param>
|
|
|
|
|
private static void DisplayAnalogInputReadings(ILogger<Worker> logger, ushort startingAddress, float[] values)
|
|
|
|
|
{
|
|
|
|
|
for (int i = 0; i < values.Length; i++)
|
|
|
|
|
{
|
|
|
|
|
logger.LogInformation("AIN" + (startingAddress + i * 2) / 2 + " : " + values[i] + " V");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Displays all digital I/O readings.
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="directions">Reading from T7 Modbus address
|
|
|
|
|
/// 2850 (DIO_DIRECTION).</param>
|
|
|
|
|
/// <param name="states">Reading from T7 Modbus address
|
|
|
|
|
/// 2800 (DIO_STATE).</param>
|
|
|
|
|
private static void DisplayDigitalIOReadings(ILogger<Worker> logger, uint directions, uint states)
|
|
|
|
|
{
|
|
|
|
|
string fioDirs = "";
|
|
|
|
|
string fioStates = "";
|
|
|
|
|
string eioDirs = "";
|
|
|
|
|
string eioStates = "";
|
|
|
|
|
string cioDirs = "";
|
|
|
|
|
string cioStates = "";
|
|
|
|
|
string mioDirs = "";
|
|
|
|
|
string mioStates = "";
|
|
|
|
|
|
|
|
|
|
for (int i = 0; i < 8; i++)
|
|
|
|
|
{
|
|
|
|
|
fioDirs += Convert.ToString((directions >> i) & 1);
|
|
|
|
|
fioStates += Convert.ToString((states >> i) & 1);
|
|
|
|
|
}
|
|
|
|
|
logger.LogInformation("FIO0-FIO7 directions = " + fioDirs + ", states = " + fioStates);
|
|
|
|
|
|
|
|
|
|
for (int i = 8; i < 16; i++)
|
|
|
|
|
{
|
|
|
|
|
eioDirs += Convert.ToString((directions >> i) & 1);
|
|
|
|
|
eioStates += Convert.ToString((states >> i) & 1);
|
|
|
|
|
}
|
|
|
|
|
logger.LogInformation("EIO0-EIO7 directions = " + eioDirs + ", states = " + eioStates);
|
|
|
|
|
|
|
|
|
|
for (int i = 16; i < 20; i++)
|
|
|
|
|
{
|
|
|
|
|
cioDirs += Convert.ToString((directions >> i) & 1);
|
|
|
|
|
cioStates += Convert.ToString((states >> i) & 1);
|
|
|
|
|
}
|
|
|
|
|
logger.LogInformation("CIO0-CIO3 directions = " + cioDirs + ", states = " + cioStates);
|
|
|
|
|
|
|
|
|
|
for (int i = 20; i < 23; i++)
|
|
|
|
|
{
|
|
|
|
|
mioDirs += Convert.ToString((directions >> i) & 1);
|
|
|
|
|
mioStates += Convert.ToString((states >> i) & 1);
|
|
|
|
|
}
|
|
|
|
|
logger.LogInformation("MIO0-MIO2 directions = " + mioDirs + ", states = " + mioStates);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Configures range, negative channel, resolution index and settling
|
|
|
|
|
/// time for all analog inputs.
|
|
|
|
|
/// AIN_ALL_RANGE, AIN_ALL_NEGATIVE_CH, AIN_ALL_RESOLUTION_INDEX, and
|
|
|
|
|
/// AIN_ALL_SETTLING_US registers/settings are documented here:
|
|
|
|
|
/// https://labjack.com/support/datasheets/t-series/ain
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="mb">The ModbusTransmissionControlProtocolClient to the connected T7 </param>
|
|
|
|
|
/// <param name="range">AIN_ALL_RANGE setting.</param>
|
|
|
|
|
/// <param name="negativeChannel">AIN_ALL_NEGATIVE_CH setting.</param>
|
|
|
|
|
/// <param name="resolutionIndex">AIN_ALL_RESOLUTION_INDEX setting.</param>
|
|
|
|
|
/// <param name="settling">AIN_ALL_SETTLING_US setting.</param>
|
|
|
|
|
private static void ConfigureAllAnalog(ModbusTransmissionControlProtocolClient mb, float range, ushort negativeChannel, ushort resolutionIndex, float settling)
|
|
|
|
|
{
|
|
|
|
|
ushort address;
|
|
|
|
|
ushort uint16Value;
|
|
|
|
|
float float32Value;
|
|
|
|
|
|
|
|
|
|
// Configure all analog input ranges.
|
|
|
|
|
address = 43900; // 43900 = AIN_ALL_RANGE
|
|
|
|
|
float32Value = range;
|
|
|
|
|
mb.Write(address, float32Value);
|
|
|
|
|
|
|
|
|
|
// Configure all analog input negative channels.
|
|
|
|
|
address = 43902; // 43902 = AIN_ALL_NEGATIVE_CH
|
|
|
|
|
uint16Value = negativeChannel;
|
|
|
|
|
mb.Write(address, uint16Value);
|
|
|
|
|
|
|
|
|
|
// Configure all analog input resolution indexes.
|
|
|
|
|
address = 43903; // 43903 = AIN_ALL_RESOLUTION_INDEX
|
|
|
|
|
uint16Value = resolutionIndex;
|
|
|
|
|
mb.Write(address, uint16Value);
|
|
|
|
|
|
|
|
|
|
// Configure all analog input settling times.
|
|
|
|
|
address = 43904; // 43904 = AIN_ALL_SETTLING_US
|
|
|
|
|
float32Value = settling;
|
|
|
|
|
mb.Write(address, float32Value);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Example that configures, reads and displays all the analog
|
|
|
|
|
/// inputs (AIN0-AIN13) on the T7.
|
|
|
|
|
/// Analog inputs (AIN) registers used are documented here:
|
|
|
|
|
/// https://labjack.com/support/datasheets/t-series/ain
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="mb">The ModbusTransmissionControlProtocolClient to the connected T7.</param>
|
|
|
|
|
private static void ReadAllAnalog(ModbusTransmissionControlProtocolClient modbusTransmissionControlProtocolClient, ILogger<Worker> logger)
|
|
|
|
|
{
|
|
|
|
|
logger.LogInformation("Reading AIN0-AIN13.");
|
|
|
|
|
|
|
|
|
|
// Configure all analog inputs.
|
|
|
|
|
// Ranges = +/-10 to.
|
|
|
|
|
// Negative Channels = 199 (single-ended)
|
|
|
|
|
// Resolution Indexes = 8
|
|
|
|
|
// Settlings = 0 (auto)
|
|
|
|
|
ConfigureAllAnalog(modbusTransmissionControlProtocolClient, 10.0f, 199, 8, 0);
|
|
|
|
|
|
|
|
|
|
// Read all 14 analog inputs.
|
|
|
|
|
ushort startAddress = 0; // 0 = AIN0
|
|
|
|
|
float[] analogInputReadings = new float[14]; // 14 analog input readings
|
|
|
|
|
modbusTransmissionControlProtocolClient.Read(startAddress, analogInputReadings);
|
|
|
|
|
DisplayAnalogInputReadings(logger, startAddress, analogInputReadings);
|
|
|
|
|
|
|
|
|
|
logger.LogInformation("");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Example that reads and displays all the digital I/O (FIOs, EIOs,
|
|
|
|
|
/// CIOs, MIOs) on the T7.
|
|
|
|
|
/// Digital I/O registers used are documented here:
|
|
|
|
|
/// https://labjack.com/support/datasheets/t-series/digital-io
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="modbusTransmissionControlProtocolClient">The ModbusTransmissionControlProtocolClient to the connected T7.</param>
|
|
|
|
|
private static void ReadAllDigitalIO(ModbusTransmissionControlProtocolClient modbusTransmissionControlProtocolClient, ILogger<Worker> logger)
|
|
|
|
|
{
|
|
|
|
|
logger.LogInformation("Reading FIOs, EIOs, CIOs and MIO directions and states.");
|
|
|
|
|
ushort address;
|
|
|
|
|
uint directions = 0;
|
|
|
|
|
uint states = 0;
|
|
|
|
|
|
|
|
|
|
// Read all digital I/O directions and states.
|
|
|
|
|
address = 2850; // 2850 = DIO_DIRECTION
|
|
|
|
|
modbusTransmissionControlProtocolClient.Read(address, ref directions);
|
|
|
|
|
address = 2800; // 2800 = DIO_STATE
|
|
|
|
|
modbusTransmissionControlProtocolClient.Read(address, ref states);
|
|
|
|
|
|
|
|
|
|
DisplayDigitalIOReadings(logger, directions, states);
|
|
|
|
|
|
|
|
|
|
logger.LogInformation("");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Example that configures, reads and displays all the analog
|
|
|
|
|
/// inputs on the T7 with a Mux80 (AIN0-AIN3, AIN48-AIN127).
|
|
|
|
|
/// Analog inputs (AIN) registers used are documented here:
|
|
|
|
|
/// https://labjack.com/support/datasheets/t-series/ain
|
|
|
|
|
/// Extended channels AIN48+ are further documented here:
|
|
|
|
|
/// https://labjack.com/support/datasheets/t-series/ain/extended-channels
|
|
|
|
|
/// Mux80 data sheet can be found here:
|
|
|
|
|
/// https://labjack.com/support/datasheets/accessories/mux80
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="modbusTransmissionControlProtocolClient">The ModbusTransmissionControlProtocolClient to the connected T7.</param>
|
|
|
|
|
private static void ReadAllAnalogMux80(ModbusTransmissionControlProtocolClient modbusTransmissionControlProtocolClient, ILogger<Worker> logger)
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
// Many registers to channels are incorrect. Check with Steve.
|
|
|
|
|
|
|
|
|
|
logger.LogInformation("Reading AIN0-AIN3, AIN48-AIN127.");
|
|
|
|
|
|
|
|
|
|
// Configure all analog inputs.
|
|
|
|
|
// Ranges = +/-10 to.
|
|
|
|
|
// Negative Channels = 199 (single-ended)
|
|
|
|
|
// Resolution Indexes = 1
|
|
|
|
|
// Settlings = 0 (auto)
|
|
|
|
|
ConfigureAllAnalog(modbusTransmissionControlProtocolClient, 10.0f, 199, 1, 0);
|
|
|
|
|
|
|
|
|
|
//Reading from 84 analog inputs with the Mux80.
|
|
|
|
|
ushort startAddress;
|
|
|
|
|
float[] analogInputReadings;
|
|
|
|
|
|
|
|
|
|
// Read from AIN0-AIN3 on the T7 terminals.
|
|
|
|
|
startAddress = 0; // 0 = AIN0
|
|
|
|
|
analogInputReadings = new float[4]; // 4 analog input readings.
|
|
|
|
|
modbusTransmissionControlProtocolClient.Read(startAddress, analogInputReadings);
|
|
|
|
|
DisplayAnalogInputReadings(logger, startAddress, analogInputReadings);
|
|
|
|
|
|
|
|
|
|
// Read from AIN48-AIN87 on Mux80.
|
|
|
|
|
startAddress = 96; // 96 = AIN48
|
|
|
|
|
analogInputReadings = new float[40]; // 40 analog input readings
|
|
|
|
|
modbusTransmissionControlProtocolClient.Read(startAddress, analogInputReadings);
|
|
|
|
|
DisplayAnalogInputReadings(logger, startAddress, analogInputReadings);
|
|
|
|
|
|
|
|
|
|
// Read from AIN88-AIN127 on Mux80.
|
|
|
|
|
startAddress = 176; // 176 = AIN88
|
|
|
|
|
analogInputReadings = new float[40]; // 40 analog input readings
|
|
|
|
|
modbusTransmissionControlProtocolClient.Read(startAddress, analogInputReadings);
|
|
|
|
|
DisplayAnalogInputReadings(logger, startAddress, analogInputReadings);
|
|
|
|
|
|
|
|
|
|
logger.LogInformation("");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|