using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using ProtocolUnit = Modbus.Net.ProtocolUnit; namespace Modbus.Net.Modbus { /// /// 跟读数据有关的功能码 /// public enum ModbusProtocolFunctionCode : byte { /// /// 读线圈 /// ReadCoilStatus = 1, /// /// 读输入线圈 /// ReadInputStatus = 2, /// /// 读保持寄存器 /// ReadHoldRegister = 3, /// /// 读输入寄存器 /// ReadInputRegister = 4, /// /// 写单个线圈 /// WriteSingleCoil = 5, /// /// 写单个寄存器 /// WriteSingleRegister = 6, /// /// 写多个线圈 /// WriteMultiCoil = 15, /// /// 写多个寄存器 /// WriteMultiRegister = 16, /// /// 读文件记录 /// ReadFileRecord = 20, /// /// 写文件记录 /// WriteFileRecord = 21, /// /// 写寄存器掩码 /// MaskWriteRegister = 22, /// /// 读写多个寄存器 /// ReadWriteMultipleRegister = 23, /// /// 读队列 /// ReadFIFOQueue = 24, } /// /// 只能在串口通信中使用的Modbus方法 /// 不能在TCP和UDP通信中使用 /// public enum ModbusSerialPortOnlyFunctionCode : byte { /// /// 读错误状态 /// ReadExceptionStatus = 7, /// /// 诊断 /// Diagnostics = 8, /// /// 读通讯事件计数器 /// GetCommEventCounter = 11, /// /// 读日志 /// GetCommEventLog = 12, /// /// 读从站ID /// ReportSlaveID = 17 } /// /// Modbus协议 /// public abstract class ModbusProtocol : BaseProtocol { /// /// 构造函数 /// /// 从站地址 /// 主站地址 protected ModbusProtocol(byte slaveAddress, byte masterAddress) : base(slaveAddress, masterAddress, Endian.BigEndianLsb) { } /// /// 连接 /// /// 是否连接成功 public override async Task ConnectAsync() { return await ProtocolLinker.ConnectAsync(); } } #region 读PLC数据 /// /// 读数据输入 /// public class ReadDataModbusInputStruct : IInputStruct { /// /// 构造函数 /// /// 从站地址 /// 开始地址 /// 读取个数 /// 地址翻译器 public ReadDataModbusInputStruct(byte slaveAddress, string startAddress, ushort getCount, AddressTranslator addressTranslator) { SlaveAddress = slaveAddress; var translateAddress = addressTranslator.AddressTranslate(startAddress, true); FunctionCode = (byte)translateAddress.Area; StartAddress = (ushort)translateAddress.Address; GetCount = (ushort)Math.Ceiling(getCount / addressTranslator.GetAreaByteLength(translateAddress.AreaString)); } /// /// 从站地址 /// public byte SlaveAddress { get; } /// /// 功能码 /// public byte FunctionCode { get; } /// /// 开始地址 /// public ushort StartAddress { get; } /// /// 获取个数 /// public ushort GetCount { get; } } /// /// 读数据输出 /// public class ReadDataModbusOutputStruct : IOutputStruct { /// /// 构造函数 /// /// 从站号 /// 功能码 /// 数据个数 /// 读取的数据值 public ReadDataModbusOutputStruct(byte slaveAddress, byte functionCode, int dataCount, byte[] dataValue) { SlaveAddress = slaveAddress; FunctionCode = functionCode; DataCount = dataCount; DataValue = dataValue.Clone() as byte[]; } /// /// 从站号 /// public byte SlaveAddress { get; private set; } /// /// 功能码 /// public byte FunctionCode { get; private set; } /// /// 数据个数 /// public int DataCount { get; private set; } /// /// 数据值 /// public byte[] DataValue { get; private set; } } /// /// 读数据协议 /// public class ReadDataModbusProtocol : ProtocolUnit { /// /// 格式化 /// /// 读取参数 /// 读取数据的协议核心 public override byte[] Format(IInputStruct message) { var r_message = (ReadDataModbusInputStruct)message; return Format(r_message.SlaveAddress, r_message.FunctionCode, r_message.StartAddress, r_message.GetCount); } /// /// 反格式化 /// /// 设备返回的信息 /// 当前反格式化的位置 /// 反格式化的信息 public override IOutputStruct Unformat(byte[] messageBytes, ref int pos) { var slaveAddress = ValueHelper.GetInstance(Endian).GetByte(messageBytes, ref pos); var functionCode = ValueHelper.GetInstance(Endian).GetByte(messageBytes, ref pos); var dataCount = ValueHelper.GetInstance(Endian).GetByte(messageBytes, ref pos); var dataValue = new byte[dataCount]; Array.Copy(messageBytes, 3, dataValue, 0, dataCount); return new ReadDataModbusOutputStruct(slaveAddress, functionCode, dataCount, dataValue); } } #endregion #region 写PLC数据 /// /// 写数据输入 /// public class WriteDataModbusInputStruct : IInputStruct { /// /// 构造函数 /// /// 从站号 /// 开始地址 /// 写入的数据 /// 地址翻译器 /// 端格式 public WriteDataModbusInputStruct(byte slaveAddress, string startAddress, object[] writeValue, AddressTranslator addressTranslator, Endian endian) { SlaveAddress = slaveAddress; var translateAddress = addressTranslator.AddressTranslate(startAddress, false); FunctionCode = (byte)translateAddress.Area; StartAddress = (ushort)translateAddress.Address; var writeByteValue = ValueHelper.GetInstance(endian).ObjectArrayToByteArray(writeValue); if (writeByteValue.Length % 2 == 1) writeByteValue = writeByteValue.ToList().Append(0).ToArray(); WriteCount = (ushort)(writeByteValue.Length / addressTranslator.GetAreaByteLength(translateAddress.AreaString)); WriteByteCount = (byte)writeByteValue.Length; WriteValue = writeByteValue; translateAddress = ((ModbusTranslatorBase)addressTranslator).AddressTranslate(startAddress, false, WriteCount == 1); FunctionCode = (byte)translateAddress.Area; StartAddress = (ushort)translateAddress.Address; } /// /// 从站号 /// public byte SlaveAddress { get; } /// /// 功能码 /// public byte FunctionCode { get; } /// /// 开始地址 /// public ushort StartAddress { get; } /// /// 写入个数 /// public ushort WriteCount { get; } /// /// 写入字节个数 /// public byte WriteByteCount { get; } /// /// 写入的数据 /// public byte[] WriteValue { get; } } /// /// 写数据输出 /// public class WriteDataModbusOutputStruct : IOutputStruct { /// /// 构造函数 /// /// 从站号 /// 功能码 /// 开始地址 /// 写入个数 public WriteDataModbusOutputStruct(byte slaveAddress, byte functionCode, ushort startAddress, ushort writeCount) { SlaveAddress = slaveAddress; FunctionCode = functionCode; StartAddress = startAddress; WriteCount = writeCount; } /// /// 从站号 /// public byte SlaveAddress { get; private set; } /// /// 功能码 /// public byte FunctionCode { get; private set; } /// /// 开始地址 /// public ushort StartAddress { get; private set; } /// /// 写入个数 /// public ushort WriteCount { get; private set; } } /// /// 写多个寄存器协议 /// public class WriteDataModbusProtocol : ProtocolUnit { /// /// 格式化 /// /// 写寄存器参数 /// 写寄存器协议核心 public override byte[] Format(IInputStruct message) { var r_message = (WriteDataModbusInputStruct)message; var dataValue = Format(r_message.WriteValue); byte[] formattingBytes; if (r_message.FunctionCode == (byte)ModbusProtocolFunctionCode.WriteSingleCoil || r_message.FunctionCode == (byte)ModbusProtocolFunctionCode.WriteSingleRegister) { formattingBytes = Format(r_message.SlaveAddress, r_message.FunctionCode, r_message.StartAddress, dataValue); } else { formattingBytes = Format(r_message.SlaveAddress, r_message.FunctionCode, r_message.StartAddress, r_message.WriteCount, r_message.WriteByteCount, dataValue); } 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 startAddress = ValueHelper.GetInstance(Endian).GetUShort(messageBytes, ref flag); var writeCount = ValueHelper.GetInstance(Endian).GetUShort(messageBytes, ref flag); if (functionCode == (byte)ModbusProtocolFunctionCode.WriteSingleCoil || functionCode == (byte)ModbusProtocolFunctionCode.WriteSingleRegister) { writeCount = 1; } return new WriteDataModbusOutputStruct(slaveAddress, functionCode, startAddress, writeCount); } } #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协议错误表 /// public class ModbusProtocolErrorException : ProtocolErrorException { private static readonly Dictionary ProtocolErrorDictionary = new Dictionary { {1, "ILLEGAL_FUNCTION"}, {2, "ILLEGAL_DATA_ACCESS"}, {3, "ILLEGAL_DATA_VALUE"}, {4, "SLAVE_DEVICE_FAILURE"}, {5, "ACKNOWLWDGE"}, {6, "SLAVE_DEVICE_BUSY"}, {8, "MEMORY_PARITY_ERROR" }, {10, "GATEWAY_PATH_UNAVAILABLE"}, {11, "GATEWAY_TARGET_DEVICE_FAILED_TO_RESPOND"} }; /// /// Modbus错误 /// /// Modbus错误号 public ModbusProtocolErrorException(int messageNumber) : base(ProtocolErrorDictionary[messageNumber]) { ErrorMessageNumber = messageNumber; } /// /// Modbus错误号 /// public int ErrorMessageNumber { get; private set; } } }