From 4298dc7a50c04a8b54b8f815743b786f016eb818 Mon Sep 17 00:00:00 2001 From: luosheng Date: Sat, 6 May 2023 13:49:09 +0800 Subject: [PATCH] Implement all Modbus function except 43 (Not tested) --- Modbus.Net/Modbus.Net.Modbus/Interfaces.cs | 219 +++ .../Modbus.Net.Modbus/ModbusProtocol.cs | 1410 ++++++++++++++++- Modbus.Net/Modbus.Net.Modbus/ModbusUtility.cs | 325 +++- 3 files changed, 1925 insertions(+), 29 deletions(-) create mode 100644 Modbus.Net/Modbus.Net.Modbus/Interfaces.cs diff --git a/Modbus.Net/Modbus.Net.Modbus/Interfaces.cs b/Modbus.Net/Modbus.Net.Modbus/Interfaces.cs new file mode 100644 index 0000000..fde2fd6 --- /dev/null +++ b/Modbus.Net/Modbus.Net.Modbus/Interfaces.cs @@ -0,0 +1,219 @@ +using System.Threading.Tasks; + +namespace Modbus.Net.Modbus +{ + /// + /// 异常状态获取方法 + /// + public interface IUtilityMethodExceptionStatus + { + /// + /// 获取异常状态 + /// + /// + Task> GetExceptionStatusAsync(); + } + + /// + /// 诊断返回数据 + /// + public class DiagnoticsData + { + /// + /// 子方法编号 + /// + public ushort SubFunction { get; set; } + + /// + /// 诊断数据 + /// + public ushort[] Data { get; set; } + } + + /// + /// 诊断获取方法 + /// + public interface IUtilityMethodDiagnotics + { + /// + /// 获取诊断信息 + /// + /// 子方法编号 + /// 诊断数据 + /// + Task> GetDiagnoticsAsync(ushort subFunction, ushort[] data); + } + + /// + /// 通讯事件计数器获取数据 + /// + public class CommEventCounterData + { + /// + /// 通讯状态 + /// + public ushort Status { get; set; } + + /// + /// 事件计数 + /// + public ushort EventCount { get; set; } + } + + /// + /// 通讯事件计数器获取方法 + /// + public interface IUtilityMethodCommEventCounter + { + /// + /// 获取通讯事件计数器 + /// + /// + Task> GetCommEventCounterAsync(); + } + + /// + /// 通讯事件获取数据 + /// + public class CommEventLogData + { + /// + /// 状态 + /// + public ushort Status { get; set; } + + /// + /// 事件内容 + /// + public byte[] Events { get; set; } + } + + /// + /// 通讯事件获取方法 + /// + public interface IUtilityMethodCommEventLog + { + /// + /// 获取通讯事件 + /// + /// + Task> GetCommEventLogAsync(); + } + + /// + /// 获取从站号数据 + /// + public class SlaveIdData + { + /// + /// 从站号 + /// + public byte SlaveId { get; set; } + + /// + /// 指示状态 + /// + public byte IndicatorStatus { get; set; } + + /// + /// 附加信息 + /// + public byte[] AdditionalData { get; set; } + } + + /// + /// 获取从站号方法 + /// + public interface IUtilityMethodSlaveId + { + /// + /// 获取从站号 + /// + /// + Task> GetSlaveIdAsync(); + } + + /// + /// 文件记录读写方法 + /// + public interface IUtilityMethodFileRecord + { + /// + /// 读文件记录 + /// + /// 读文件记录定义 + /// + Task> GetFileRecordAsync(ReadFileRecordInputDef[] recordDefs); + /// + /// 写文件记录 + /// + /// 写文件记录定义 + /// + Task> SetFileRecordAsync(WriteFileRecordInputDef[] recordDefs); + } + + /// + /// 掩码写入数据 + /// + public class MaskRegisterData + { + /// + /// 地址索引 + /// + public ushort ReferenceAddress { get; set; } + + /// + /// 与掩码 + /// + public ushort AndMask { get; set; } + + /// + /// 或掩码 + /// + public ushort OrMask { get; set; } + } + + /// + /// 掩码写入方法 + /// + public interface IUtilityMethodMaskRegister + { + /// + /// 写入掩码 + /// + /// 地址索引 + /// 与掩码 + /// 或掩码 + /// + Task> SetMaskRegister(ushort referenceAddress, ushort andMask, ushort orMask); + } + + /// + /// 寄存器读写方法 + /// + public interface IUtilityMethodMultipleRegister + { + /// + /// 读写多寄存器 + /// + /// 读起始地址 + /// 读数量 + /// 写寄存器地址 + /// 写数据 + /// + Task> GetMultipleRegister(ushort readStartingAddress, ushort quantityToRead, ushort writeStartingAddress, ushort[] writeValues); + } + + /// + /// FIFO队列读取方法 + /// + public interface IUtilityMethodFIFOQueue + { + /// + /// 读FIFO队列 + /// + /// FIFO队列地址 + /// + Task> GetFIFOQueue(ushort fifoPointerAddress); + } +} diff --git a/Modbus.Net/Modbus.Net.Modbus/ModbusProtocol.cs b/Modbus.Net/Modbus.Net.Modbus/ModbusProtocol.cs index 6fee1b8..30c7bde 100644 --- a/Modbus.Net/Modbus.Net.Modbus/ModbusProtocol.cs +++ b/Modbus.Net/Modbus.Net.Modbus/ModbusProtocol.cs @@ -77,22 +77,6 @@ namespace Modbus.Net.Modbus ReadFIFOQueue = 24, } - /// - /// Modbus MEI方式 - /// - public enum ModbusMEIProtocolFunctionCode : ushort - { - /// - /// - /// - CANopenGeneralReferenceRequestandResponsePDU = 0x2B0D, - - /// - /// 读设备信息 - /// - ReadDeviceIdentification = 0x2B0E - } - /// /// 只能在串口通信中使用的Modbus方法 /// 不能在TCP和UDP通信中使用 @@ -432,6 +416,1400 @@ namespace Modbus.Net.Modbus #endregion + #region 读异常信息 + + /// + /// 读异常输入 + /// + public class ReadExceptionStatusModbusInputStruct : IInputStruct + { + /// + /// 构造函数 + /// + /// 从站号 + public ReadExceptionStatusModbusInputStruct(byte slaveAddress) + { + SlaveAddress = slaveAddress; + FunctionCode = (byte)ModbusSerialPortOnlyFunctionCode.ReadExceptionStatus; + } + + /// + /// 从站号 + /// + public byte SlaveAddress { get; } + + /// + /// 功能码 + /// + public byte FunctionCode { get; } + } + + /// + /// 读异常输出 + /// + public class ReadExceptionStatusModbusOutputStruct : IOutputStruct + { + /// + /// 构造函数 + /// + /// 从站号 + /// 功能码 + /// 异常信息 + public ReadExceptionStatusModbusOutputStruct(byte slaveAddress, byte functionCode, + byte outputData) + { + SlaveAddress = slaveAddress; + FunctionCode = functionCode; + OutputData = outputData; + } + + /// + /// 从站号 + /// + public byte SlaveAddress { get; private set; } + + /// + /// 功能码 + /// + public byte FunctionCode { get; private set; } + + /// + /// 异常信息 + /// + public byte OutputData { get; private set; } + } + + /// + /// 读异常协议 + /// + public class ReadExceptionStatusModbusProtocol : ProtocolUnit + { + /// + /// 格式化 + /// + /// 写寄存器参数 + /// 写寄存器协议核心 + public override byte[] Format(IInputStruct message) + { + var r_message = (ReadExceptionStatusModbusInputStruct)message; + byte[] formattingBytes; + + formattingBytes = Format(r_message.SlaveAddress, r_message.FunctionCode); + + return formattingBytes; + } + + /// + /// 反格式化 + /// + /// 设备返回的信息 + /// 当前反格式化的位置 + /// 反格式化的信息 + public override IOutputStruct Unformat(byte[] messageBytes, ref int flag) + { + var slaveAddress = ValueHelper.GetInstance(Endian).GetByte(messageBytes, ref flag); + var functionCode = ValueHelper.GetInstance(Endian).GetByte(messageBytes, ref flag); + var outputData = ValueHelper.GetInstance(Endian).GetByte(messageBytes, ref flag); + return new ReadExceptionStatusModbusOutputStruct(slaveAddress, functionCode, outputData); + } + } + + #endregion + + #region 诊断 + + /// + /// 诊断输入 + /// + public class DiagnoticsModbusInputStruct : IInputStruct + { + /// + /// 构造函数 + /// + /// 从站号 + /// 诊断码 + /// 诊断内容 + public DiagnoticsModbusInputStruct(byte slaveAddress, ushort subFunction, ushort[] data) + { + SlaveAddress = slaveAddress; + FunctionCode = (byte)ModbusSerialPortOnlyFunctionCode.Diagnostics; + SubFunction = subFunction; + Data = data.Clone() as ushort[]; + } + + /// + /// 从站号 + /// + public byte SlaveAddress { get; } + + /// + /// 功能码 + /// + public byte FunctionCode { get; } + + /// + /// 诊断码 + /// + public ushort SubFunction { get; } + + /// + /// 诊断内容 + /// + public ushort[] Data { get; } + } + + /// + /// 诊断输出 + /// + public class DiagnoticsModbusOutputStruct : IOutputStruct + { + /// + /// 构造函数 + /// + /// 从站号 + /// 功能码 + /// 诊断码 + /// 诊断内容 + public DiagnoticsModbusOutputStruct(byte slaveAddress, byte functionCode, + ushort subFunction, ushort[] data) + { + SlaveAddress = slaveAddress; + FunctionCode = functionCode; + SubFunction = subFunction; + Data = data; + } + + /// + /// 从站号 + /// + public byte SlaveAddress { get; private set; } + + /// + /// 功能码 + /// + public byte FunctionCode { get; private set; } + + /// + /// 诊断码 + /// + public ushort SubFunction { get; } + + /// + /// 诊断内容 + /// + public ushort[] Data { get; } + } + + /// + /// 诊断协议 + /// + public class DiagnoticsModbusProtocol : ProtocolUnit + { + /// + /// 格式化 + /// + /// 写寄存器参数 + /// 写寄存器协议核心 + public override byte[] Format(IInputStruct message) + { + var r_message = (DiagnoticsModbusInputStruct)message; + + var formattingBytes = Format(r_message.SlaveAddress, r_message.FunctionCode, + r_message.SubFunction, r_message.Data); + + return formattingBytes; + } + + /// + /// 反格式化 + /// + /// 设备返回的信息 + /// 当前反格式化的位置 + /// 反格式化的信息 + public override IOutputStruct Unformat(byte[] messageBytes, ref int flag) + { + var slaveAddress = ValueHelper.GetInstance(Endian).GetByte(messageBytes, ref flag); + var functionCode = ValueHelper.GetInstance(Endian).GetByte(messageBytes, ref flag); + var subFunction = ValueHelper.GetInstance(Endian).GetUShort(messageBytes, ref flag); + var dataValueBytes = new byte[subFunction * 2]; + Array.Copy(messageBytes, 3, dataValueBytes, 0, subFunction * 2); + var dataValue = ValueHelper.GetInstance(Endian).ByteArrayToDestinationArray(dataValueBytes, subFunction); + return new DiagnoticsModbusOutputStruct(slaveAddress, functionCode, subFunction, dataValue); + } + } + + #endregion + + #region 读事件计数 + + /// + /// 读事件计数输入 + /// + public class GetCommEventCounterModbusInputStruct : IInputStruct + { + /// + /// 构造函数 + /// + /// 从站号 + public GetCommEventCounterModbusInputStruct(byte slaveAddress) + { + SlaveAddress = slaveAddress; + FunctionCode = (byte)ModbusSerialPortOnlyFunctionCode.GetCommEventCounter; + } + + /// + /// 从站号 + /// + public byte SlaveAddress { get; } + + /// + /// 功能码 + /// + public byte FunctionCode { get; } + } + + /// + /// 读事件计数输出 + /// + public class GetCommEventCounterModbusOutputStruct : IOutputStruct + { + /// + /// 构造函数 + /// + /// 从站号 + /// 功能码 + /// 状态 + /// 事件个数 + public GetCommEventCounterModbusOutputStruct(byte slaveAddress, byte functionCode, + ushort status, ushort eventCount) + { + SlaveAddress = slaveAddress; + FunctionCode = functionCode; + Status = status; + EventCount = eventCount; + } + + /// + /// 从站号 + /// + public byte SlaveAddress { get; private set; } + + /// + /// 功能码 + /// + public byte FunctionCode { get; private set; } + + /// + /// 状态 + /// + public ushort Status { get; } + + /// + /// 事件个数 + /// + public ushort EventCount { get; } + } + + /// + /// 读事件计数协议 + /// + public class GetCommEventCounterModbusProtocol : ProtocolUnit + { + /// + /// 格式化 + /// + /// 写寄存器参数 + /// 写寄存器协议核心 + public override byte[] Format(IInputStruct message) + { + var r_message = (GetCommEventCounterModbusInputStruct)message; + + var formattingBytes = Format(r_message.SlaveAddress, r_message.FunctionCode); + + return formattingBytes; + } + + /// + /// 反格式化 + /// + /// 设备返回的信息 + /// 当前反格式化的位置 + /// 反格式化的信息 + public override IOutputStruct Unformat(byte[] messageBytes, ref int flag) + { + var slaveAddress = ValueHelper.GetInstance(Endian).GetByte(messageBytes, ref flag); + var functionCode = ValueHelper.GetInstance(Endian).GetByte(messageBytes, ref flag); + var status = ValueHelper.GetInstance(Endian).GetUShort(messageBytes, ref flag); + var eventCount = ValueHelper.GetInstance(Endian).GetUShort(messageBytes, ref flag); + return new GetCommEventCounterModbusOutputStruct(slaveAddress, functionCode, status, eventCount); + } + } + + #endregion + + #region 读事件 + + /// + /// 读事件输入 + /// + public class GetCommEventLogModbusInputStruct : IInputStruct + { + /// + /// 构造函数 + /// + /// 从站号 + public GetCommEventLogModbusInputStruct(byte slaveAddress) + { + SlaveAddress = slaveAddress; + FunctionCode = (byte)ModbusSerialPortOnlyFunctionCode.GetCommEventLog; + } + + /// + /// 从站号 + /// + public byte SlaveAddress { get; } + + /// + /// 功能码 + /// + public byte FunctionCode { get; } + } + + /// + /// 诊断输出 + /// + public class GetCommEventLogModbusOutputStruct : IOutputStruct + { + /// + /// 构造函数 + /// + /// 从站号 + /// 功能码 + /// 字节个数 + /// 状态码 + /// 事件个数 + /// 消息个数 + /// 事件信息 + public GetCommEventLogModbusOutputStruct(byte slaveAddress, byte functionCode, + byte byteCount, ushort status, ushort eventCount, ushort messageCount, byte[] events) + { + SlaveAddress = slaveAddress; + FunctionCode = functionCode; + ByteCount = byteCount; + Status = status; + EventCount = eventCount; + MessageCount = messageCount; + Events = events; + } + + /// + /// 从站号 + /// + public byte SlaveAddress { get; private set; } + + /// + /// 功能码 + /// + public byte FunctionCode { get; private set; } + + /// + /// 字节个数 + /// + public byte ByteCount { get; private set; } + + /// + /// 状态码 + /// + public ushort Status { get; private set; } + + /// + /// 事件个数 + /// + public ushort EventCount { get; private set; } + + /// + /// 消息个数 + /// + public ushort MessageCount { get; private set; } + + /// + /// 事件信息 + /// + public byte[] Events { get; private set; } + } + + /// + /// 诊断协议 + /// + public class GetCommEventLogModbusProtocol : ProtocolUnit + { + /// + /// 格式化 + /// + /// 写寄存器参数 + /// 写寄存器协议核心 + public override byte[] Format(IInputStruct message) + { + var r_message = (GetCommEventLogModbusInputStruct)message; + + var formattingBytes = Format(r_message.SlaveAddress, r_message.FunctionCode); + + return formattingBytes; + } + + /// + /// 反格式化 + /// + /// 设备返回的信息 + /// 当前反格式化的位置 + /// 反格式化的信息 + public override IOutputStruct Unformat(byte[] messageBytes, ref int flag) + { + var slaveAddress = ValueHelper.GetInstance(Endian).GetByte(messageBytes, ref flag); + var functionCode = ValueHelper.GetInstance(Endian).GetByte(messageBytes, ref flag); + var byteCount = ValueHelper.GetInstance(Endian).GetByte(messageBytes, ref flag); + var status = ValueHelper.GetInstance(Endian).GetUShort(messageBytes, ref flag); + var eventCount = ValueHelper.GetInstance(Endian).GetUShort(messageBytes, ref flag); + var messageCount = ValueHelper.GetInstance(Endian).GetUShort(messageBytes, ref flag); + var events = new byte[byteCount - 6]; + Array.Copy(messageBytes, 9, events, 0, byteCount - 6); + return new GetCommEventLogModbusOutputStruct(slaveAddress, functionCode, byteCount, status, eventCount, messageCount, events); + } + } + + #endregion + + #region 报告从站ID + + /// + /// 报告从站ID输入 + /// + public class ReportSlaveIdModbusInputStruct : IInputStruct + { + /// + /// 构造函数 + /// + /// 从站号 + public ReportSlaveIdModbusInputStruct(byte slaveAddress) + { + SlaveAddress = slaveAddress; + FunctionCode = (byte)ModbusSerialPortOnlyFunctionCode.ReportSlaveID; + } + + /// + /// 从站号 + /// + public byte SlaveAddress { get; } + + /// + /// 功能码 + /// + public byte FunctionCode { get; } + } + + /// + /// 报告从站ID输出 + /// + public class ReportSlaveIdModbusOutputStruct : IOutputStruct + { + /// + /// 构造函数 + /// + /// 从站号 + /// 功能码 + /// 字节个数 + /// 从站ID + /// 运行状态 + /// 附加信息 + public ReportSlaveIdModbusOutputStruct(byte slaveAddress, byte functionCode, + byte byteCount, byte slaveId, byte runIndicatorStatus, byte[] additionalData) + { + SlaveAddress = slaveAddress; + FunctionCode = functionCode; + ByteCount = byteCount; + SlaveId = slaveId; + RunIndicatorStatus = runIndicatorStatus; + AdditionalData = additionalData; + } + + /// + /// 从站号 + /// + public byte SlaveAddress { get; private set; } + + /// + /// 功能码 + /// + public byte FunctionCode { get; private set; } + + /// + /// 字节个数 + /// + public byte ByteCount { get; private set; } + + /// + /// 从站ID + /// + public byte SlaveId { get; private set; } + + /// + /// 运行状态 + /// + public byte RunIndicatorStatus { get; private set; } + + /// + /// 附加信息 + /// + public byte[] AdditionalData { get; private set; } + } + + /// + /// 报告从站ID协议 + /// + public class ReportSlaveIdModbusProtocol : ProtocolUnit + { + /// + /// 格式化 + /// + /// 写寄存器参数 + /// 写寄存器协议核心 + public override byte[] Format(IInputStruct message) + { + var r_message = (ReportSlaveIdModbusInputStruct)message; + + var formattingBytes = Format(r_message.SlaveAddress, r_message.FunctionCode); + + return formattingBytes; + } + + /// + /// 反格式化 + /// + /// 设备返回的信息 + /// 当前反格式化的位置 + /// 反格式化的信息 + public override IOutputStruct Unformat(byte[] messageBytes, ref int flag) + { + var slaveAddress = ValueHelper.GetInstance(Endian).GetByte(messageBytes, ref flag); + var functionCode = ValueHelper.GetInstance(Endian).GetByte(messageBytes, ref flag); + var byteCount = ValueHelper.GetInstance(Endian).GetByte(messageBytes, ref flag); + var slaveId = ValueHelper.GetInstance(Endian).GetByte(messageBytes, ref flag); + var runIndicatorStatus = ValueHelper.GetInstance(Endian).GetByte(messageBytes, ref flag); + var additionalData = new byte[byteCount - 2]; + Array.Copy(messageBytes, 5, additionalData, 0, byteCount - 2); + return new ReportSlaveIdModbusOutputStruct(slaveAddress, functionCode, byteCount, slaveId, runIndicatorStatus, additionalData); + } + } + + #endregion + + #region 读文件记录 + + /// + /// 读文件输入数据定义 + /// + public class ReadFileRecordInputDef + { + /// + /// 引用类型,Modbus里固定为6 + /// + public byte RefrenceType { get; } = 6; + /// + /// 文件计数 + /// + public ushort FileNumber { get; set; } + /// + /// 记录计数 + /// + public ushort RecordNumber { get; set; } + /// + /// 记录长度 + /// + public ushort RecordLength { get; set; } + } + + /// + /// 读文件输出数据定义 + /// + public class ReadFileRecordOutputDef + { + /// + /// 返回长度 + /// + public byte ResponseLength { get; set; } + /// + /// 引用类型 + /// + public byte RefrenceType { get; set; } + /// + /// 记录数据 + /// + public ushort[] RecordData { get; set; } + } + + /// + /// 读文件记录输入 + /// + public class ReadFileRecordModbusInputStruct : IInputStruct + { + /// + /// 构造函数 + /// + /// 从站号 + /// 读文件记录定义 + public ReadFileRecordModbusInputStruct(byte slaveAddress, ReadFileRecordInputDef[] recordDefs) + { + SlaveAddress = slaveAddress; + FunctionCode = (byte)ModbusProtocolFunctionCode.ReadFileRecord; + ByteCount = (byte)(recordDefs.Count() * 7); + RecordDefs = recordDefs.Clone() as ReadFileRecordInputDef[]; + } + + /// + /// 从站号 + /// + public byte SlaveAddress { get; } + + /// + /// 功能码 + /// + public byte FunctionCode { get; } + + /// + /// 字节长度 + /// + public byte ByteCount { get; } + + /// + /// 记录定义 + /// + public ReadFileRecordInputDef[] RecordDefs { get; } + } + + /// + /// 读文件记录输出 + /// + public class ReadFileRecordModbusOutputStruct : IOutputStruct + { + /// + /// 构造函数 + /// + /// 从站号 + /// 功能码 + /// 字节个数 + /// 文件记录返回结果 + public ReadFileRecordModbusOutputStruct(byte slaveAddress, byte functionCode, + byte byteCount, ReadFileRecordOutputDef[] recordDefs) + { + SlaveAddress = slaveAddress; + FunctionCode = functionCode; + ByteCount = byteCount; + RecordDefs = recordDefs; + } + + /// + /// 从站号 + /// + public byte SlaveAddress { get; private set; } + + /// + /// 功能码 + /// + public byte FunctionCode { get; private set; } + + /// + /// 字节个数 + /// + public byte ByteCount { get; private set; } + + /// + /// 输出记录 + /// + public ReadFileRecordOutputDef[] RecordDefs { get; private set; } + } + + /// + /// 读文件记录协议 + /// + public class ReadFileRecordModbusProtocol : ProtocolUnit + { + /// + /// 格式化 + /// + /// 写寄存器参数 + /// 写寄存器协议核心 + public override byte[] Format(IInputStruct message) + { + var r_message = (ReadFileRecordModbusInputStruct)message; + + var formattingBytes = Format(r_message.SlaveAddress, r_message.FunctionCode); + + foreach (var def in r_message.RecordDefs) + { + formattingBytes = Format(formattingBytes, def.RefrenceType, def.FileNumber, def.RecordNumber, def.RecordLength); + } + + return formattingBytes; + } + + /// + /// 反格式化 + /// + /// 设备返回的信息 + /// 当前反格式化的位置 + /// 反格式化的信息 + public override IOutputStruct Unformat(byte[] messageBytes, ref int flag) + { + var slaveAddress = ValueHelper.GetInstance(Endian).GetByte(messageBytes, ref flag); + var functionCode = ValueHelper.GetInstance(Endian).GetByte(messageBytes, ref flag); + var byteCount = ValueHelper.GetInstance(Endian).GetByte(messageBytes, ref flag); + List records = new List(); + for (int i = 0; i < byteCount; i++) + { + ReadFileRecordOutputDef record = new ReadFileRecordOutputDef(); + var fileResponseLength = ValueHelper.GetInstance(Endian).GetByte(messageBytes, ref flag); + record.ResponseLength = fileResponseLength; + i++; + var fileReferenceType = ValueHelper.GetInstance(Endian).GetByte(messageBytes, ref flag); + record.RefrenceType = fileReferenceType; + i++; + var recordLength = (fileResponseLength - 1) / 2; + ushort[] recordContent = new ushort[recordLength]; + for (int j = 0; j < recordLength; j++) + { + recordContent[j] = ValueHelper.GetInstance(Endian).GetUShort(messageBytes, ref flag); + i += 2; + } + record.RecordData = recordContent; + records.Add(record); + } + return new ReadFileRecordModbusOutputStruct(slaveAddress, functionCode, byteCount, records.ToArray()); + } + } + + #endregion + + #region 写文件记录 + + /// + /// 写文件记录输入定义 + /// + public class WriteFileRecordInputDef + { + /// + /// 引用类型,Modbus固定为6 + /// + public byte RefrenceType { get; } = 6; + /// + /// 文件计数 + /// + public ushort FileNumber { get; set; } + /// + /// 记录计数 + /// + public ushort RecordNumber { get; set; } + /// + /// 记录长度 + /// + public ushort RecordLength => RecordData != null ? (ushort)RecordData.Length : (ushort)0; + /// + /// 记录数据 + /// + public ushort[] RecordData { get; set; } + } + + /// + /// 写文件记录输出定义 + /// + public class WriteFileRecordOutputDef + { + /// + /// 引用类型 + /// + public byte RefrenceType { get; set; } + /// + /// 文件计数 + /// + public ushort FileNumber { get; set; } + /// + /// 记录计数 + /// + public ushort RecordNumber { get; set; } + /// + /// 记录长度 + /// + public ushort RecordLength { get; set; } + /// + /// 记录数据 + /// + public ushort[] RecordData { get; set; } + } + + /// + /// 写文件记录输入 + /// + public class WriteFileRecordModbusInputStruct : IInputStruct + { + /// + /// 构造函数 + /// + /// 从站号 + /// 写文件记录内容 + public WriteFileRecordModbusInputStruct(byte slaveAddress, WriteFileRecordInputDef[] writeRecords) + { + SlaveAddress = slaveAddress; + FunctionCode = (byte)ModbusProtocolFunctionCode.WriteFileRecord; + byte count = 0; + foreach(var writeRecord in writeRecords) + { + count += (byte)(writeRecord.RecordData.Length * 2 + 7); + } + ByteCount = count; + WriteRecords = writeRecords.Clone() as WriteFileRecordInputDef[]; + } + + /// + /// 从站号 + /// + public byte SlaveAddress { get; } + + /// + /// 功能码 + /// + public byte FunctionCode { get; } + + /// + /// 字节个数 + /// + public byte ByteCount { get; private set; } + + /// + /// 写记录数据 + /// + public WriteFileRecordInputDef[] WriteRecords { get; private set; } + } + + /// + /// 写文件记录输出 + /// + public class WriteFileRecordModbusOutputStruct : IOutputStruct + { + /// + /// 构造函数 + /// + /// 从站号 + /// 功能码 + /// 字节个数 + /// 写文件记录返回 + public WriteFileRecordModbusOutputStruct(byte slaveAddress, byte functionCode, + byte byteCount, WriteFileRecordOutputDef[] writeRecords) + { + SlaveAddress = slaveAddress; + FunctionCode = functionCode; + ByteCount = byteCount; + WriteRecords = writeRecords; + } + + /// + /// 从站号 + /// + public byte SlaveAddress { get; private set; } + + /// + /// 功能码 + /// + public byte FunctionCode { get; private set; } + + /// + /// 字节个数 + /// + public byte ByteCount { get; private set; } + + /// + /// 写记录数据 + /// + public WriteFileRecordOutputDef[] WriteRecords { get; private set; } + } + + /// + /// 写文件记录协议 + /// + public class WriteFileRecordModbusProtocol : ProtocolUnit + { + /// + /// 格式化 + /// + /// 写寄存器参数 + /// 写寄存器协议核心 + public override byte[] Format(IInputStruct message) + { + var r_message = (WriteFileRecordModbusInputStruct)message; + + var formattingBytes = Format(r_message.SlaveAddress, r_message.FunctionCode, r_message.ByteCount); + + foreach (var record in r_message.WriteRecords) + { + formattingBytes = Format(formattingBytes, record.RefrenceType, record.FileNumber, record.RecordNumber, record.RecordLength, record.RecordData); + } + + return formattingBytes; + } + + /// + /// 反格式化 + /// + /// 设备返回的信息 + /// 当前反格式化的位置 + /// 反格式化的信息 + public override IOutputStruct Unformat(byte[] messageBytes, ref int flag) + { + var slaveAddress = ValueHelper.GetInstance(Endian).GetByte(messageBytes, ref flag); + var functionCode = ValueHelper.GetInstance(Endian).GetByte(messageBytes, ref flag); + var byteCount = ValueHelper.GetInstance(Endian).GetByte(messageBytes, ref flag); + List records = new List(); + for (int i = 0; i < byteCount; i++) + { + WriteFileRecordOutputDef record = new WriteFileRecordOutputDef(); + var fileReferenceType = ValueHelper.GetInstance(Endian).GetByte(messageBytes, ref flag); + record.RefrenceType = fileReferenceType; + i++; + var fileNumber = ValueHelper.GetInstance(Endian).GetUShort(messageBytes, ref flag); + record.FileNumber = fileNumber; + i += 2; + var fileRecordNumber = ValueHelper.GetInstance(Endian).GetUShort(messageBytes, ref flag); + record.RecordNumber = fileRecordNumber; + i += 2; + var fileRecordLength = ValueHelper.GetInstance(Endian).GetUShort(messageBytes, ref flag); + record.RecordLength = fileRecordLength; + i += 2; + ushort[] recordContent = new ushort[fileRecordLength]; + for (int j = 0; j < fileRecordLength; j++) + { + recordContent[j] = ValueHelper.GetInstance(Endian).GetUShort(messageBytes, ref flag); + i += 2; + } + record.RecordData = recordContent; + records.Add(record); + } + return new WriteFileRecordModbusOutputStruct(slaveAddress, functionCode, byteCount, records.ToArray()); + } + } + + #endregion + + #region 写掩码 + + /// + /// 写文件记录输入 + /// + public class MaskWriteRegisterModbusInputStruct : IInputStruct + { + /// + /// 构造函数 + /// + /// 从站号 + /// 地址索引 + /// 与掩码 + /// 或掩码 + public MaskWriteRegisterModbusInputStruct(byte slaveAddress, ushort referenceAddress, ushort andMask, ushort orMask) + { + SlaveAddress = slaveAddress; + FunctionCode = (byte)ModbusProtocolFunctionCode.MaskWriteRegister; + ReferenceAddress = referenceAddress; + AndMask = andMask; + OrMask = orMask; + } + + /// + /// 从站号 + /// + public byte SlaveAddress { get; } + + /// + /// 功能码 + /// + public byte FunctionCode { get; } + + /// + /// 地址索引 + /// + public ushort ReferenceAddress { get; } + + /// + /// 与掩码 + /// + public ushort AndMask { get; } + + /// + /// 或掩码 + /// + public ushort OrMask { get; } + } + + /// + /// 写文件记录输出 + /// + public class MaskWriteRegisterModbusOutputStruct : IOutputStruct + { + /// + /// 构造函数 + /// + /// 从站号 + /// 功能码 + /// 地址索引 + /// 与掩码 + /// 或掩码 + public MaskWriteRegisterModbusOutputStruct(byte slaveAddress, byte functionCode, + ushort referenceAddress, ushort andMask, ushort orMask) + { + SlaveAddress = slaveAddress; + FunctionCode = functionCode; + ReferenceAddress = referenceAddress; + AndMask = andMask; + OrMask = orMask; + } + + /// + /// 从站号 + /// + public byte SlaveAddress { get; private set; } + + /// + /// 功能码 + /// + public byte FunctionCode { get; private set; } + + /// + /// 地址索引 + /// + public ushort ReferenceAddress { get; } + + /// + /// 与掩码 + /// + public ushort AndMask { get; } + + /// + /// 或掩码 + /// + public ushort OrMask { get; } + } + + /// + /// 写文件记录协议 + /// + public class MaskWriteRegisterModbusProtocol : ProtocolUnit + { + /// + /// 格式化 + /// + /// 写寄存器参数 + /// 写寄存器协议核心 + public override byte[] Format(IInputStruct message) + { + var r_message = (MaskWriteRegisterModbusInputStruct)message; + + var formattingBytes = Format(r_message.SlaveAddress, r_message.FunctionCode, r_message.ReferenceAddress, r_message.AndMask, r_message.OrMask); + + return formattingBytes; + } + + /// + /// 反格式化 + /// + /// 设备返回的信息 + /// 当前反格式化的位置 + /// 反格式化的信息 + public override IOutputStruct Unformat(byte[] messageBytes, ref int flag) + { + var slaveAddress = ValueHelper.GetInstance(Endian).GetByte(messageBytes, ref flag); + var functionCode = ValueHelper.GetInstance(Endian).GetByte(messageBytes, ref flag); + var referenceAddress = ValueHelper.GetInstance(Endian).GetUShort(messageBytes, ref flag); + var andMask = ValueHelper.GetInstance(Endian).GetUShort(messageBytes, ref flag); + var orMask = ValueHelper.GetInstance(Endian).GetUShort(messageBytes, ref flag); + return new MaskWriteRegisterModbusOutputStruct(slaveAddress, functionCode, referenceAddress, andMask, orMask); + } + } + + #endregion + + #region 读写多个输入寄存器 + + /// + /// 读写多个输入寄存器输入 + /// + public class ReadWriteMultipleRegistersModbusInputStruct : IInputStruct + { + /// + /// 构造函数 + /// + /// 从站号 + /// 读起始地址 + /// 读个数 + /// 写起始地址 + /// 写内容 + public ReadWriteMultipleRegistersModbusInputStruct(byte slaveAddress, ushort readStartingAddress, ushort quantityToRead, ushort writeStartingAddress, ushort[] writeValues) + { + SlaveAddress = slaveAddress; + FunctionCode = (byte)ModbusProtocolFunctionCode.ReadWriteMultipleRegister; + ReadStartingAddress = readStartingAddress; + QuantityToRead = quantityToRead; + WriteStartingAddress = writeStartingAddress; + QuantityToWrite = (ushort)writeValues.Count(); + WriteByteCount = (ushort)(QuantityToWrite * 2); + WriteValues = writeValues.Clone() as ushort[]; + } + + /// + /// 从站号 + /// + public byte SlaveAddress { get; } + + /// + /// 功能码 + /// + public byte FunctionCode { get; } + + /// + /// 读起始地址 + /// + public ushort ReadStartingAddress { get; } + + /// + /// 读个数 + /// + public ushort QuantityToRead { get; } + + /// + /// 写起始地址 + /// + public ushort WriteStartingAddress { get; } + + /// + /// 写个数 + /// + public ushort QuantityToWrite { get; } + + /// + /// 写字节个数 + /// + public ushort WriteByteCount { get; } + + /// + /// 写数据 + /// + public ushort[] WriteValues { get; } + } + + /// + /// 读写多个输入寄存器输出 + /// + public class ReadWriteMultipleRegistersModbusOutputStruct : IOutputStruct + { + /// + /// 构造函数 + /// + /// 从站号 + /// 功能码 + /// 获取的字节数 + /// 读取的寄存器内容 + public ReadWriteMultipleRegistersModbusOutputStruct(byte slaveAddress, byte functionCode, byte byteCount, ushort[] readRegisterValues) + { + SlaveAddress = slaveAddress; + FunctionCode = functionCode; + ByteCount = byteCount; + ReadRegisterValues = readRegisterValues; + } + + /// + /// 从站号 + /// + public byte SlaveAddress { get; private set; } + + /// + /// 功能码 + /// + public byte FunctionCode { get; private set; } + + /// + /// 字节个数 + /// + public byte ByteCount { get; private set; } + + /// + /// 读数据内容 + /// + public ushort[] ReadRegisterValues { get; private set; } + } + + /// + /// 读写多个输入寄存器协议 + /// + public class ReadWriteMultipleRegistersModbusProtocol : ProtocolUnit + { + /// + /// 格式化 + /// + /// 写寄存器参数 + /// 写寄存器协议核心 + public override byte[] Format(IInputStruct message) + { + var r_message = (ReadWriteMultipleRegistersModbusInputStruct)message; + + var formattingBytes = Format(r_message.SlaveAddress, r_message.FunctionCode, r_message.ReadStartingAddress, + r_message.QuantityToRead, r_message.WriteStartingAddress, r_message.QuantityToWrite, + r_message.WriteByteCount, r_message.WriteValues); + + return formattingBytes; + } + + /// + /// 反格式化 + /// + /// 设备返回的信息 + /// 当前反格式化的位置 + /// 反格式化的信息 + public override IOutputStruct Unformat(byte[] messageBytes, ref int flag) + { + var slaveAddress = ValueHelper.GetInstance(Endian).GetByte(messageBytes, ref flag); + var functionCode = ValueHelper.GetInstance(Endian).GetByte(messageBytes, ref flag); + var byteCount = ValueHelper.GetInstance(Endian).GetByte(messageBytes, ref flag); + ushort[] readValues= new ushort[byteCount / 2]; + for (int i = 0; i< byteCount / 2; i++) + { + readValues[i] = ValueHelper.GetInstance(Endian).GetUShort(messageBytes, ref flag); + } + return new ReadWriteMultipleRegistersModbusOutputStruct(slaveAddress, functionCode, byteCount, readValues); + } + } + + #endregion + + #region 读FIFO队列 + + /// + /// 读写多个输入寄存器输入 + /// + public class ReadFIFOQueueModbusInputStruct : IInputStruct + { + /// + /// 构造函数 + /// + /// 从站号 + /// FIFO队列地址索引 + public ReadFIFOQueueModbusInputStruct(byte slaveAddress, ushort fifoPointerAddress) + { + SlaveAddress = slaveAddress; + FunctionCode = (byte)ModbusProtocolFunctionCode.ReadFIFOQueue; + FIFOPointerAddress = fifoPointerAddress; + } + + /// + /// 从站号 + /// + public byte SlaveAddress { get; } + + /// + /// 功能码 + /// + public byte FunctionCode { get; } + + /// + /// FIFO地址 + /// + public ushort FIFOPointerAddress { get; } + } + + /// + /// 读写多个输入寄存器输出 + /// + public class ReadFIFOQueueModbusOutputStruct : IOutputStruct + { + /// + /// 构造函数 + /// + /// 从站号 + /// 功能码 + /// 获取的字节数 + /// FIFO个数 + /// FIFO值 + public ReadFIFOQueueModbusOutputStruct(byte slaveAddress, byte functionCode, ushort byteCount, ushort fifoCount, ushort[] fifoValueRegister) + { + SlaveAddress = slaveAddress; + FunctionCode = functionCode; + ByteCount = byteCount; + FIFOCount = fifoCount; + FIFOValueRegister = fifoValueRegister; + } + + /// + /// 从站号 + /// + public byte SlaveAddress { get; private set; } + + /// + /// 功能码 + /// + public byte FunctionCode { get; private set; } + + /// + /// 字节个数 + /// + public ushort ByteCount { get; private set; } + + /// + /// FIFO个数 + /// + public ushort FIFOCount { get; private set; } + + /// + /// FIFO内容 + /// + public ushort[] FIFOValueRegister { get; private set; } + } + + /// + /// 读写多个输入寄存器协议 + /// + public class ReadFIFOQueueModbusProtocol : ProtocolUnit + { + /// + /// 格式化 + /// + /// 写寄存器参数 + /// 写寄存器协议核心 + public override byte[] Format(IInputStruct message) + { + var r_message = (ReadFIFOQueueModbusInputStruct)message; + + var formattingBytes = Format(r_message.SlaveAddress, r_message.FunctionCode, r_message.FIFOPointerAddress); + + return formattingBytes; + } + + /// + /// 反格式化 + /// + /// 设备返回的信息 + /// 当前反格式化的位置 + /// 反格式化的信息 + public override IOutputStruct Unformat(byte[] messageBytes, ref int flag) + { + var slaveAddress = ValueHelper.GetInstance(Endian).GetByte(messageBytes, ref flag); + var functionCode = ValueHelper.GetInstance(Endian).GetByte(messageBytes, ref flag); + var byteCount = ValueHelper.GetInstance(Endian).GetUShort(messageBytes, ref flag); + var fifoCount = ValueHelper.GetInstance(Endian).GetUShort(messageBytes, ref flag); + ushort[] readValues = new ushort[fifoCount]; + for (int i = 0; i < fifoCount; i++) + { + readValues[i] = ValueHelper.GetInstance(Endian).GetUShort(messageBytes, ref flag); + } + return new ReadFIFOQueueModbusOutputStruct(slaveAddress, functionCode, byteCount, fifoCount, readValues); + } + } + + #endregion + /// /// Modbus协议错误表 /// diff --git a/Modbus.Net/Modbus.Net.Modbus/ModbusUtility.cs b/Modbus.Net/Modbus.Net.Modbus/ModbusUtility.cs index d1e5365..a19f62a 100644 --- a/Modbus.Net/Modbus.Net.Modbus/ModbusUtility.cs +++ b/Modbus.Net/Modbus.Net.Modbus/ModbusUtility.cs @@ -53,7 +53,16 @@ namespace Modbus.Net.Modbus /// /// Modbus基础Api入口 /// - public class ModbusUtility : BaseUtility, PipeUnit> + public class ModbusUtility : BaseUtility, PipeUnit>, + IUtilityMethodExceptionStatus, + IUtilityMethodDiagnotics, + IUtilityMethodCommEventCounter, + IUtilityMethodCommEventLog, + IUtilityMethodSlaveId, + IUtilityMethodFileRecord, + IUtilityMethodMaskRegister, + IUtilityMethodMultipleRegister, + IUtilityMethodFIFOQueue { private static readonly ILogger logger = LogProvider.CreateLogger(); @@ -242,12 +251,7 @@ namespace Modbus.Net.Modbus ModbusType = (ModbusType)connectionType; } - /// - /// 读数据 - /// - /// 起始地址 - /// 获取字节个数 - /// 获取的结果 + /// public override async Task> GetDatasAsync(string startAddress, int getByteCount) { try @@ -278,12 +282,7 @@ namespace Modbus.Net.Modbus } } - /// - /// 写数据 - /// - /// 起始地址 - /// 需要设置的数据 - /// 设置是否成功 + /// public override async Task> SetDatasAsync(string startAddress, object[] setContents) { try @@ -313,5 +312,305 @@ namespace Modbus.Net.Modbus }; } } + + /// + public async Task> GetExceptionStatusAsync() + { + try + { + var inputStruct = new ReadExceptionStatusModbusInputStruct(SlaveAddress); + var outputStruct = await + Wrapper.SendReceiveAsync(Wrapper[typeof(ReadExceptionStatusModbusProtocol)], + inputStruct); + return new ReturnStruct() + { + Datas = outputStruct.OutputData, + IsSuccess = true, + ErrorCode = 0, + ErrorMsg = null + }; + } + catch (ModbusProtocolErrorException e) + { + logger.LogError(e, $"ModbusUtility -> SetDatas: {ConnectionString} error: {e.Message}"); + return new ReturnStruct + { + Datas = 0, + IsSuccess = false, + ErrorCode = e.ErrorMessageNumber, + ErrorMsg = e.Message + }; + } + } + + /// + public async Task> GetDiagnoticsAsync(ushort subFunction, ushort[] data) + { + try + { + var inputStruct = new DiagnoticsModbusInputStruct(SlaveAddress, subFunction, data); + var outputStruct = await + Wrapper.SendReceiveAsync(Wrapper[typeof(DiagnoticsModbusProtocol)], + inputStruct); + return new ReturnStruct() + { + Datas = new DiagnoticsData() { SubFunction = outputStruct.SubFunction, Data = outputStruct.Data }, + IsSuccess = true, + ErrorCode = 0, + ErrorMsg = null + }; + } + catch (ModbusProtocolErrorException e) + { + logger.LogError(e, $"ModbusUtility -> SetDatas: {ConnectionString} error: {e.Message}"); + return new ReturnStruct + { + Datas = null, + IsSuccess = false, + ErrorCode = e.ErrorMessageNumber, + ErrorMsg = e.Message + }; + } + } + + /// + public async Task> GetCommEventCounterAsync() + { + try + { + var inputStruct = new GetCommEventCounterModbusInputStruct(SlaveAddress); + var outputStruct = await + Wrapper.SendReceiveAsync(Wrapper[typeof(GetCommEventCounterModbusProtocol)], + inputStruct); + return new ReturnStruct() + { + Datas = new CommEventCounterData() { EventCount = outputStruct.EventCount, Status = outputStruct.Status }, + IsSuccess = true, + ErrorCode = 0, + ErrorMsg = null + }; + } + catch (ModbusProtocolErrorException e) + { + logger.LogError(e, $"ModbusUtility -> SetDatas: {ConnectionString} error: {e.Message}"); + return new ReturnStruct + { + Datas = null, + IsSuccess = false, + ErrorCode = e.ErrorMessageNumber, + ErrorMsg = e.Message + }; + } + } + + /// + public async Task> GetCommEventLogAsync() + { + try + { + var inputStruct = new GetCommEventLogModbusInputStruct(SlaveAddress); + var outputStruct = await + Wrapper.SendReceiveAsync(Wrapper[typeof(GetCommEventLogModbusProtocol)], + inputStruct); + return new ReturnStruct() + { + Datas = new CommEventLogData() { Status = outputStruct.Status, Events = outputStruct.Events}, + IsSuccess = true, + ErrorCode = 0, + ErrorMsg = null + }; + } + catch (ModbusProtocolErrorException e) + { + logger.LogError(e, $"ModbusUtility -> SetDatas: {ConnectionString} error: {e.Message}"); + return new ReturnStruct + { + Datas = null, + IsSuccess = false, + ErrorCode = e.ErrorMessageNumber, + ErrorMsg = e.Message + }; + } + } + + /// + public async Task> GetSlaveIdAsync() + { + try + { + var inputStruct = new ReportSlaveIdModbusInputStruct(SlaveAddress); + var outputStruct = await + Wrapper.SendReceiveAsync(Wrapper[typeof(ReportSlaveIdModbusProtocol)], + inputStruct); + return new ReturnStruct() + { + Datas = new SlaveIdData() { SlaveId = outputStruct.SlaveId, IndicatorStatus = outputStruct.RunIndicatorStatus, AdditionalData = outputStruct.AdditionalData}, + IsSuccess = true, + ErrorCode = 0, + ErrorMsg = null + }; + } + catch (ModbusProtocolErrorException e) + { + logger.LogError(e, $"ModbusUtility -> SetDatas: {ConnectionString} error: {e.Message}"); + return new ReturnStruct + { + Datas = null, + IsSuccess = false, + ErrorCode = e.ErrorMessageNumber, + ErrorMsg = e.Message + }; + } + } + + /// + public async Task> GetFileRecordAsync(ReadFileRecordInputDef[] recordDefs) + { + try + { + var inputStruct = new ReadFileRecordModbusInputStruct(SlaveAddress, recordDefs); + var outputStruct = await + Wrapper.SendReceiveAsync(Wrapper[typeof(ReadFileRecordModbusProtocol)], + inputStruct); + return new ReturnStruct() + { + Datas = outputStruct.RecordDefs, + IsSuccess = true, + ErrorCode = 0, + ErrorMsg = null + }; + } + catch (ModbusProtocolErrorException e) + { + logger.LogError(e, $"ModbusUtility -> SetDatas: {ConnectionString} error: {e.Message}"); + return new ReturnStruct + { + Datas = null, + IsSuccess = false, + ErrorCode = e.ErrorMessageNumber, + ErrorMsg = e.Message + }; + } + } + + /// + public async Task> SetFileRecordAsync(WriteFileRecordInputDef[] recordDefs) + { + try + { + var inputStruct = new WriteFileRecordModbusInputStruct(SlaveAddress, recordDefs); + var outputStruct = await + Wrapper.SendReceiveAsync(Wrapper[typeof(WriteFileRecordModbusProtocol)], + inputStruct); + return new ReturnStruct() + { + Datas = outputStruct.WriteRecords, + IsSuccess = true, + ErrorCode = 0, + ErrorMsg = null + }; + } + catch (ModbusProtocolErrorException e) + { + logger.LogError(e, $"ModbusUtility -> SetDatas: {ConnectionString} error: {e.Message}"); + return new ReturnStruct + { + Datas = null, + IsSuccess = false, + ErrorCode = e.ErrorMessageNumber, + ErrorMsg = e.Message + }; + } + } + + /// + public async Task> SetMaskRegister(ushort referenceAddress, ushort andMask, ushort orMask) + { + try + { + var inputStruct = new MaskWriteRegisterModbusInputStruct(SlaveAddress, referenceAddress, andMask, orMask); + var outputStruct = await + Wrapper.SendReceiveAsync(Wrapper[typeof(MaskWriteRegisterModbusProtocol)], + inputStruct); + return new ReturnStruct() + { + Datas = new MaskRegisterData() { ReferenceAddress = outputStruct.ReferenceAddress, AndMask = outputStruct.AndMask, OrMask = outputStruct.OrMask}, + IsSuccess = true, + ErrorCode = 0, + ErrorMsg = null + }; + } + catch (ModbusProtocolErrorException e) + { + logger.LogError(e, $"ModbusUtility -> SetDatas: {ConnectionString} error: {e.Message}"); + return new ReturnStruct + { + Datas = null, + IsSuccess = false, + ErrorCode = e.ErrorMessageNumber, + ErrorMsg = e.Message + }; + } + } + + /// + public async Task> GetMultipleRegister(ushort readStartingAddress, ushort quantityToRead, ushort writeStartingAddress, ushort[] writeValues) + { + try + { + var inputStruct = new ReadWriteMultipleRegistersModbusInputStruct(SlaveAddress, readStartingAddress, quantityToRead, writeStartingAddress, writeValues); + var outputStruct = await + Wrapper.SendReceiveAsync(Wrapper[typeof(ReadWriteMultipleRegistersModbusProtocol)], + inputStruct); + return new ReturnStruct() + { + Datas = outputStruct.ReadRegisterValues, + IsSuccess = true, + ErrorCode = 0, + ErrorMsg = null + }; + } + catch (ModbusProtocolErrorException e) + { + logger.LogError(e, $"ModbusUtility -> SetDatas: {ConnectionString} error: {e.Message}"); + return new ReturnStruct + { + Datas = null, + IsSuccess = false, + ErrorCode = e.ErrorMessageNumber, + ErrorMsg = e.Message + }; + } + } + + /// + public async Task> GetFIFOQueue(ushort fifoPointerAddress) + { + try + { + var inputStruct = new ReadFIFOQueueModbusInputStruct(SlaveAddress, fifoPointerAddress); + var outputStruct = await + Wrapper.SendReceiveAsync(Wrapper[typeof(ReadFIFOQueueModbusProtocol)], + inputStruct); + return new ReturnStruct() + { + Datas = outputStruct.FIFOValueRegister, + IsSuccess = true, + ErrorCode = 0, + ErrorMsg = null + }; + } + catch (ModbusProtocolErrorException e) + { + logger.LogError(e, $"ModbusUtility -> SetDatas: {ConnectionString} error: {e.Message}"); + return new ReturnStruct + { + Datas = null, + IsSuccess = false, + ErrorCode = e.ErrorMessageNumber, + ErrorMsg = e.Message + }; + } + } } } \ No newline at end of file