Files
Modbus.Net/Modbus.Net/Modbus.Net.Modbus.SelfDefinedSample/ModbusProtocolTime.cs
2026-04-04 17:25:15 +08:00

575 lines
23 KiB
C#

using System;
using ProtocolUnit = Modbus.Net.ProtocolUnit<byte[], byte[]>;
namespace Modbus.Net.Modbus.SelfDefinedSample
{
/// <summary>
/// Modbus 时间协议功能码枚举 / Modbus Time Protocol Function Code Enum
/// <remarks>
/// 定义与时间读写相关的自定义功能码
/// Defines custom function codes related to time read/write
/// <para>
/// 注意 / Note:
/// <list type="bullet">
/// <item>这些是自定义功能码,非标准 Modbus 功能码</item>
/// <item>These are custom function codes, not standard Modbus function codes</item>
/// <item>实际使用时需确认设备支持的功能码</item>
/// <item>Confirm device-supported function codes before actual use</item>
/// </list>
/// </para>
/// </remarks>
/// </summary>
public enum ModbusProtocolTimeFunctionCode : byte
{
/// <summary>
/// 读系统时间 (功能码 3) / Get System Time (Function Code 3)
/// <remarks>
/// 读取设备的当前系统时间
/// Read device's current system time
/// <para>
/// 请求数据 / Request Data:
/// <list type="bullet">
/// <item>从站地址 (1 字节) / Slave address (1 byte)</item>
/// <item>功能码 3 (1 字节) / Function code 3 (1 byte)</item>
/// <item>起始地址 (2 字节) / Start address (2 bytes)</item>
/// <item>读取数量 5 (2 字节) / Read count 5 (2 bytes)</item>
/// </list>
/// </para>
/// <para>
/// 响应数据 / Response Data:
/// <list type="bullet">
/// <item>从站地址 (1 字节) / Slave address (1 byte)</item>
/// <item>功能码 3 (1 字节) / Function code 3 (1 byte)</item>
/// <item>字节数 10 (1 字节) / Byte count 10 (1 byte)</item>
/// <item>年 (2 字节) / Year (2 bytes)</item>
/// <item>日 (1 字节) / Day (1 byte)</item>
/// <item>月 (1 字节) / Month (1 byte)</item>
/// <item>时 (2 字节) / Hour (2 bytes)</item>
/// <item>秒 (1 字节) / Second (1 byte)</item>
/// <item>分 (1 字节) / Minute (1 byte)</item>
/// <item>毫秒 (2 字节) / Millisecond (2 bytes)</item>
/// </list>
/// </para>
/// </remarks>
/// </summary>
GetSystemTime = 3,
/// <summary>
/// 写系统时间 (功能码 16) / Set System Time (Function Code 16)
/// <remarks>
/// 写入设备的系统时间
/// Write device's system time
/// <para>
/// 请求数据 / Request Data:
/// <list type="bullet">
/// <item>从站地址 (1 字节) / Slave address (1 byte)</item>
/// <item>功能码 16 (1 字节) / Function code 16 (1 byte)</item>
/// <item>起始地址 (2 字节) / Start address (2 bytes)</item>
/// <item>写入数量 5 (2 字节) / Write count 5 (2 bytes)</item>
/// <item>字节数 10 (1 字节) / Byte count 10 (1 byte)</item>
/// <item>年 (2 字节) / Year (2 bytes)</item>
/// <item>日 (1 字节) / Day (1 byte)</item>
/// <item>月 (1 字节) / Month (1 byte)</item>
/// <item>时 (2 字节) / Hour (2 bytes)</item>
/// <item>秒 (1 字节) / Second (1 byte)</item>
/// <item>分 (1 字节) / Minute (1 byte)</item>
/// <item>毫秒 (2 字节) / Millisecond (2 bytes)</item>
/// </list>
/// </para>
/// <para>
/// 响应数据 / Response Data:
/// <list type="bullet">
/// <item>从站地址 (1 字节) / Slave address (1 byte)</item>
/// <item>功能码 16 (1 字节) / Function code 16 (1 byte)</item>
/// <item>起始地址 (2 字节) / Start address (2 bytes)</item>
/// <item>写入数量 5 (2 字节) / Write count 5 (2 bytes)</item>
/// </list>
/// </para>
/// </remarks>
/// </summary>
SetSystemTime = 16
}
#region PLC / Read PLC Time
/// <summary>
/// 读时间输入结构 / Read Time Input Structure
/// <remarks>
/// 封装读取设备时间的请求参数
/// Encapsulates request parameters for reading device time
/// </remarks>
/// </summary>
public class GetSystemTimeModbusInputStruct : IInputStruct
{
/// <summary>
/// 构造函数 / Constructor
/// <remarks>
/// 初始化读时间请求参数
/// Initialize read time request parameters
/// </remarks>
/// </summary>
/// <param name="slaveAddress">
/// 从站号 / Slave Address
/// <remarks>
/// Modbus 从站地址,范围 1-247
/// Modbus slave address, range 1-247
/// </remarks>
/// </param>
/// <param name="startAddress">
/// 起始地址 / Start Address
/// <remarks>
/// 时间寄存器起始地址
/// Starting address of time registers
/// </remarks>
/// </param>
public GetSystemTimeModbusInputStruct(byte slaveAddress, ushort startAddress)
{
SlaveAddress = slaveAddress;
FunctionCode = (byte)ModbusProtocolTimeFunctionCode.GetSystemTime;
StartAddress = startAddress;
GetCount = 5; // 时间占用 5 个寄存器 / Time occupies 5 registers
}
/// <summary>
/// 从站号 / Slave Address
/// <remarks>
/// Modbus 从站地址
/// Modbus slave address
/// </remarks>
/// </summary>
public byte SlaveAddress { get; }
/// <summary>
/// 功能码 / Function Code
/// <remarks>
/// 读时间功能码 (3)
/// Read time function code (3)
/// </remarks>
/// </summary>
public byte FunctionCode { get; }
/// <summary>
/// 开始地址 / Start Address
/// <remarks>
/// 时间寄存器起始地址
/// Starting address of time registers
/// </remarks>
/// </summary>
public ushort StartAddress { get; }
/// <summary>
/// 获取个数 / Get Count
/// <remarks>
/// 读取寄存器数量 (5 个)
/// Number of registers to read (5)
/// <para>
/// 年 (1) + 日月 (2) + 时分 (2) + 秒毫秒 (2) = 5 个寄存器
/// Year (1) + Day/Month (2) + Hour/Minute (2) + Second/Millisecond (2) = 5 registers
/// </para>
/// </remarks>
/// </summary>
public ushort GetCount { get; }
}
/// <summary>
/// 读时间输出结构 / Read Time Output Structure
/// <remarks>
/// 封装读取设备时间的响应数据
/// Encapsulates response data for reading device time
/// </remarks>
/// </summary>
public class GetSystemTimeModbusOutputStruct : IOutputStruct
{
/// <summary>
/// 构造函数 / Constructor
/// <remarks>
/// 初始化读时间响应数据
/// Initialize read time response data
/// </remarks>
/// </summary>
/// <param name="slaveAddress">从站号 / Slave Address</param>
/// <param name="functionCode">功能码 / Function Code</param>
/// <param name="writeByteCount">写入个数 / Write Byte Count</param>
/// <param name="year">年 / Year</param>
/// <param name="day">日 / Day</param>
/// <param name="month">月 / Month</param>
/// <param name="hour">时 / Hour</param>
/// <param name="second">秒 / Second</param>
/// <param name="minute">分 / Minute</param>
/// <param name="millisecond">毫秒 / Millisecond</param>
public GetSystemTimeModbusOutputStruct(byte slaveAddress, byte functionCode,
byte writeByteCount, ushort year, byte day, byte month, ushort hour, byte second, byte minute,
ushort millisecond)
{
SlaveAddress = slaveAddress;
FunctionCode = functionCode;
WriteByteCount = writeByteCount;
Time = new DateTime(year, month, day, hour, minute, second, millisecond);
}
/// <summary>
/// 从站号 / Slave Address
/// </summary>
public byte SlaveAddress { get; private set; }
/// <summary>
/// 功能码 / Function Code
/// </summary>
public byte FunctionCode { get; private set; }
/// <summary>
/// 写入个数 / Write Byte Count
/// </summary>
public byte WriteByteCount { get; private set; }
/// <summary>
/// 时间 / Time
/// <remarks>
/// 解析后的 DateTime 对象
/// Parsed DateTime object
/// </remarks>
/// </summary>
public DateTime Time { get; private set; }
}
/// <summary>
/// 读系统时间协议类 / Read System Time Protocol Class
/// <remarks>
/// 实现读系统时间的协议格式化和反格式化
/// Implements protocol formatting and unformatting for reading system time
/// </remarks>
/// </summary>
public class GetSystemTimeModbusProtocol : ProtocolUnit
{
/// <summary>
/// 格式化 (发送前) / Format (Before Sending)
/// <remarks>
/// 将读时间请求参数转换为字节数组
/// Convert read time request parameters to byte array
/// <para>
/// 格式 / Format:
/// <code>[从站地址][功能码][起始地址 (2)][读取数量 (2)]</code>
/// </para>
/// </remarks>
/// </summary>
/// <param name="message">
/// 读时间输入结构 / Read Time Input Structure
/// <remarks>
/// 包含从站地址、起始地址等参数
/// Contains slave address, start address, etc.
/// </remarks>
/// </param>
/// <returns>
/// 格式化后的字节数组 / Formatted Byte Array
/// <remarks>
/// Modbus 读时间请求帧
/// Modbus read time request frame
/// </remarks>
/// </returns>
public override byte[] Format(IInputStruct message)
{
var r_message = (GetSystemTimeModbusInputStruct)message;
return Format(r_message.SlaveAddress, r_message.FunctionCode,
r_message.StartAddress, r_message.GetCount);
}
/// <summary>
/// 反格式化 (接收后) / Unformat (After Receiving)
/// <remarks>
/// 将响应字节数组解析为读时间输出结构
/// Parse response byte array to read time output structure
/// <para>
/// 解析顺序 / Parse Order:
/// <list type="number">
/// <item>从站地址 (1 字节) / Slave address (1 byte)</item>
/// <item>功能码 (1 字节) / Function code (1 byte)</item>
/// <item>字节数 (1 字节) / Byte count (1 byte)</item>
/// <item>年 (2 字节) / Year (2 bytes)</item>
/// <item>日 (1 字节) / Day (1 byte)</item>
/// <item>月 (1 字节) / Month (1 byte)</item>
/// <item>时 (2 字节) / Hour (2 bytes)</item>
/// <item>秒 (1 字节) / Second (1 byte)</item>
/// <item>分 (1 字节) / Minute (1 byte)</item>
/// <item>毫秒 (2 字节) / Millisecond (2 bytes)</item>
/// </list>
/// </para>
/// </remarks>
/// </summary>
/// <param name="messageBytes">
/// 获取的信息 / Received Information
/// <remarks>
/// 设备返回的字节数组
/// Byte array returned from device
/// </remarks>
/// </param>
/// <param name="flag">
/// 当前反格式化的位置 / Current Unformat Position
/// <remarks>
/// 引用传递,自动更新
/// Passed by reference, auto-updated
/// </remarks>
/// </param>
/// <returns>
/// 反格式化的信息 / Unformatted Information
/// <remarks>
/// GetSystemTimeModbusOutputStruct 对象
/// GetSystemTimeModbusOutputStruct object
/// </remarks>
/// </returns>
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 writeByteCount = ValueHelper.GetInstance(Endian).GetByte(messageBytes, ref flag);
var year = ValueHelper.GetInstance(Endian).GetUShort(messageBytes, ref flag);
var day = ValueHelper.GetInstance(Endian).GetByte(messageBytes, ref flag);
var month = ValueHelper.GetInstance(Endian).GetByte(messageBytes, ref flag);
var hour = ValueHelper.GetInstance(Endian).GetUShort(messageBytes, ref flag);
var second = ValueHelper.GetInstance(Endian).GetByte(messageBytes, ref flag);
var minute = ValueHelper.GetInstance(Endian).GetByte(messageBytes, ref flag);
var millisecond = ValueHelper.GetInstance(Endian).GetUShort(messageBytes, ref flag);
return new GetSystemTimeModbusOutputStruct(slaveAddress, functionCode, writeByteCount, year, day,
month, hour, second, minute, millisecond);
}
}
#endregion
#region PLC / Write PLC Time
/// <summary>
/// 写时间输入结构 / Write Time Input Structure
/// <remarks>
/// 封装写入设备时间的请求参数
/// Encapsulates request parameters for writing device time
/// </remarks>
/// </summary>
public class SetSystemTimeModbusInputStruct : IInputStruct
{
/// <summary>
/// 构造函数 / Constructor
/// <remarks>
/// 初始化写时间请求参数,从 DateTime 提取各时间分量
/// Initialize write time request parameters, extract time components from DateTime
/// </remarks>
/// </summary>
/// <param name="slaveAddress">从站号 / Slave Address</param>
/// <param name="startAddress">起始地址 / Start Address</param>
/// <param name="time">时间 / Time</param>
public SetSystemTimeModbusInputStruct(byte slaveAddress, ushort startAddress, DateTime time)
{
SlaveAddress = slaveAddress;
FunctionCode = (byte)ModbusProtocolTimeFunctionCode.SetSystemTime;
StartAddress = startAddress;
WriteCount = 5; // 时间占用 5 个寄存器 / Time occupies 5 registers
WriteByteCount = 10; // 10 字节数据 / 10 bytes data
Year = (ushort)time.Year;
Day = (byte)time.Day;
Month = (byte)time.Month;
Hour = (ushort)time.Hour;
Second = (byte)time.Second;
Minute = (byte)time.Minute;
Millisecond = (ushort)time.Millisecond;
}
/// <summary>
/// 从站号 / Slave Address
/// </summary>
public byte SlaveAddress { get; }
/// <summary>
/// 功能码 / Function Code
/// </summary>
public byte FunctionCode { get; }
/// <summary>
/// 开始地址 / Start Address
/// </summary>
public ushort StartAddress { get; }
/// <summary>
/// 写入个数 / Write Count
/// </summary>
public ushort WriteCount { get; }
/// <summary>
/// 写入字节个数 / Write Byte Count
/// </summary>
public byte WriteByteCount { get; }
/// <summary>
/// 年 / Year
/// </summary>
public ushort Year { get; }
/// <summary>
/// 日 / Day
/// </summary>
public byte Day { get; }
/// <summary>
/// 月 / Month
/// </summary>
public byte Month { get; }
/// <summary>
/// 时 / Hour
/// </summary>
public ushort Hour { get; }
/// <summary>
/// 秒 / Second
/// </summary>
public byte Second { get; }
/// <summary>
/// 分 / Minute
/// </summary>
public byte Minute { get; }
/// <summary>
/// 毫秒 / Millisecond
/// </summary>
public ushort Millisecond { get; }
}
/// <summary>
/// 写时间输出结构 / Write Time Output Structure
/// <remarks>
/// 封装写入设备时间的响应数据
/// Encapsulates response data for writing device time
/// </remarks>
/// </summary>
public class SetSystemTimeModbusOutputStruct : IOutputStruct
{
/// <summary>
/// 构造函数 / Constructor
/// <remarks>
/// 初始化写时间响应数据
/// Initialize write time response data
/// </remarks>
/// </summary>
/// <param name="slaveAddress">从站号 / Slave Address</param>
/// <param name="functionCode">功能码 / Function Code</param>
/// <param name="startAddress">开始地址 / Start Address</param>
/// <param name="writeCount">写入个数 / Write Count</param>
public SetSystemTimeModbusOutputStruct(byte slaveAddress, byte functionCode,
ushort startAddress, ushort writeCount)
{
SlaveAddress = slaveAddress;
FunctionCode = functionCode;
StartAddress = startAddress;
WriteCount = writeCount;
}
/// <summary>
/// 从站号 / Slave Address
/// </summary>
public byte SlaveAddress { get; private set; }
/// <summary>
/// 功能码 / Function Code
/// </summary>
public byte FunctionCode { get; private set; }
/// <summary>
/// 开始地址 / Start Address
/// </summary>
public ushort StartAddress { get; private set; }
/// <summary>
/// 写入个数 / Write Count
/// </summary>
public ushort WriteCount { get; private set; }
}
/// <summary>
/// 写系统时间协议类 / Write System Time Protocol Class
/// <remarks>
/// 实现写系统时间的协议格式化和反格式化
/// Implements protocol formatting and unformatting for writing system time
/// </remarks>
/// </summary>
public class SetSystemTimeModbusProtocol : ProtocolUnit
{
/// <summary>
/// 格式化 (发送前) / Format (Before Sending)
/// <remarks>
/// 将写时间请求参数转换为字节数组
/// Convert write time request parameters to byte array
/// <para>
/// 格式 / Format:
/// <code>[从站地址][功能码][起始地址 (2)][写入数量 (2)][字节数 (1)][年 (2)][日 (1)][月 (1)][时 (2)][秒 (1)][分 (1)][毫秒 (2)]</code>
/// </para>
/// </remarks>
/// </summary>
/// <param name="message">
/// 写时间输入结构 / Write Time Input Structure
/// <remarks>
/// 包含从站地址、时间等参数
/// Contains slave address, time, etc.
/// </remarks>
/// </param>
/// <returns>
/// 格式化后的字节数组 / Formatted Byte Array
/// <remarks>
/// Modbus 写时间请求帧
/// Modbus write time request frame
/// </remarks>
/// </returns>
public override byte[] Format(IInputStruct message)
{
var r_message = (SetSystemTimeModbusInputStruct)message;
return Format(r_message.SlaveAddress, r_message.FunctionCode,
r_message.StartAddress, r_message.WriteCount, r_message.WriteByteCount, r_message.Year,
r_message.Day,
r_message.Month, r_message.Hour, r_message.Second, r_message.Minute, r_message.Millisecond);
}
/// <summary>
/// 反格式化 (接收后) / Unformat (After Receiving)
/// <remarks>
/// 将响应字节数组解析为写时间输出结构
/// Parse response byte array to write time output structure
/// <para>
/// 解析顺序 / Parse Order:
/// <list type="number">
/// <item>从站地址 (1 字节) / Slave address (1 byte)</item>
/// <item>功能码 (1 字节) / Function code (1 byte)</item>
/// <item>起始地址 (2 字节) / Start address (2 bytes)</item>
/// <item>写入数量 (2 字节) / Write count (2 bytes)</item>
/// </list>
/// </para>
/// </remarks>
/// </summary>
/// <param name="messageBytes">
/// 获取的信息 / Received Information
/// <remarks>
/// 设备返回的字节数组
/// Byte array returned from device
/// </remarks>
/// </param>
/// <param name="flag">
/// 当前反格式化的位置 / Current Unformat Position
/// <remarks>引用传递,自动更新 / Passed by reference, auto-updated</remarks>
/// </param>
/// <returns>
/// 反格式化的信息 / Unformatted Information
/// <remarks>
/// SetSystemTimeModbusOutputStruct 对象
/// SetSystemTimeModbusOutputStruct object
/// </remarks>
/// </returns>
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);
return new SetSystemTimeModbusOutputStruct(slaveAddress, functionCode, startAddress, writeCount);
}
}
#endregion
}