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

358 lines
19 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using System;
using System.Collections.Generic;
using System.Linq;
namespace Modbus.Net.Modbus
{
/// <summary>
/// Modbus 长度计算工具类 / Modbus Length Calculation Utility Class
/// <remarks>
/// 提供 Modbus 协议各种模式的长度计算函数
/// Provides length calculation functions for various Modbus protocol modes
/// <para>
/// 主要功能 / Main Functions:
/// <list type="bullet">
/// <item><strong>ModbusAsciiLengthCalc</strong> - ASCII 协议长度计算 / ASCII protocol length calculation</item>
/// <item><strong>ModbusRtuResponseLengthCalc</strong> - RTU 响应长度计算 / RTU response length calculation</item>
/// <item><strong>ModbusRtuRequestLengthCalc</strong> - RTU 请求长度计算 / RTU request length calculation</item>
/// </list>
/// </para>
/// <para>
/// 使用场景 / Use Cases:
/// <list type="bullet">
/// <item>Controller 的 lengthCalc 参数 / Controller's lengthCalc parameter</item>
/// <item>数据帧切分 / Data frame splitting</item>
/// <item>TCP 粘包处理 / TCP sticky packet handling</item>
/// </list>
/// </para>
/// </remarks>
/// </summary>
public static class ModbusLengthCalc
{
/// <summary>
/// Modbus ASCII 协议长度计算 / Modbus ASCII Protocol Length Calculation
/// <remarks>
/// ASCII 协议以冒号 (0x3A) 开始,以 CRLF (0x0D 0x0A) 结束
/// ASCII protocol starts with colon (0x3A) and ends with CRLF (0x0D 0x0A)
/// <para>
/// 帧格式 / Frame Format:
/// <code>: [从站地址][功能码][数据][LRC][CR][LF]</code>
/// </para>
/// <para>
/// 计算逻辑 / Calculation Logic:
/// <list type="number">
/// <item>检查首字节是否为 0x3A (冒号) / Check if first byte is 0x3A (colon)</item>
/// <item>遍历查找 0x0D 0x0A (CRLF) / Traverse to find 0x0D 0x0A (CRLF)</item>
/// <item>返回 CRLF 后的位置 / Return position after CRLF</item>
/// <item>如果未找到,返回 0 / Return 0 if not found</item>
/// </list>
/// </para>
/// </remarks>
/// </summary>
public static Func<byte[], int> ModbusAsciiLengthCalc => content =>
{
// 检查首字节是否为冒号 / Check if first byte is colon
if (content[0] != 0x3a) return 0;
// 查找 CRLF 结束符 / Find CRLF terminator
for (int i = 1; i < content.Length; i++)
{
if (content[i - 1] == 0x0D && content[i] == 0x0A) return i + 1;
}
return 0;
};
/// <summary>
/// Modbus RTU 接收协议长度计算 / Modbus RTU Response Protocol Length Calculation
/// <remarks>
/// 根据功能码计算响应帧长度
/// Calculate response frame length based on function code
/// <para>
/// 帧格式 / Frame Format:
/// <code>[从站地址][功能码][数据长度/数据][CRC 低][CRC 高]</code>
/// </para>
/// <para>
/// 长度规则 / Length Rules:
/// <list type="bullet">
/// <item>异常响应 (功能码&gt;128): 5 字节 / Exception response (function code&gt;128): 5 bytes</item>
/// <item>写单个线圈/寄存器 (05/06): 8 字节 / Write single coil/register: 8 bytes</item>
/// <item>诊断/事件计数器 (08/11): 8 字节 / Diagnostics/Event Counter: 8 bytes</item>
/// <item>读线圈/离散输入 (01/02): 动态长度 / Read coils/discrete inputs: dynamic length</item>
/// <item>读寄存器 (03/04): 动态长度 / Read registers: dynamic length</item>
/// </list>
/// </para>
/// </remarks>
/// </summary>
public static Func<byte[], int> ModbusRtuResponseLengthCalc => (content) =>
{
// 异常响应 (功能码最高位为 1) / Exception response (function code MSB is 1)
if (content[1] > 128) return 5; // [从站][功能码][异常码][CRC 低][CRC 高]
// 固定长度响应 / Fixed length responses
else if (content[1] == 5 || content[1] == 6 || content[1] == 8 || content[1] == 11 || content[1] == 15 || content[1] == 16) return 8;
else if (content[1] == 7) return 5; // 读异常状态 / Read exception status
else if (content[1] == 22) return 10; // 掩码写寄存器 / Mask write register
// 动态长度响应 (读操作) / Dynamic length responses (read operations)
// 使用 DuplicateWithCount 计算 / Use DuplicateWithCount to calculate
// 格式:[从站 (1)][功能码 (1)][字节数 (1)][数据 (N)][CRC (2)]
// Format: [Slave (1)][Function (1)][Byte Count (1)][Data (N)][CRC (2)]
else return DuplicateWithCount.GetDuplcateFunc(new List<int> { 2 }, 5).Invoke(content);
};
/// <summary>
/// Modbus RTU 发送协议长度计算 / Modbus RTU Request Protocol Length Calculation
/// <remarks>
/// 根据功能码计算请求帧长度
/// Calculate request frame length based on function code
/// <para>
/// 帧格式 / Frame Format:
/// <code>[从站地址][功能码][参数...][CRC 低][CRC 高]</code>
/// </para>
/// <para>
/// 长度规则 / Length Rules:
/// <list type="bullet">
/// <item>读线圈/寄存器 (01-04): 8 字节 / Read coils/registers: 8 bytes</item>
/// <item>写单个线圈/寄存器 (05/06): 8 字节 / Write single coil/register: 8 bytes</item>
/// <item>诊断 (08): 8 字节 / Diagnostics: 8 bytes</item>
/// <item>读异常状态 (07): 4 字节 / Read exception status: 4 bytes</item>
/// <item>写多个线圈/寄存器 (15/16): 动态长度 / Write multiple coils/registers: dynamic length</item>
/// </list>
/// </para>
/// </remarks>
/// </summary>
public static Func<byte[], int> ModbusRtuRequestLengthCalc => (content) =>
{
// 读操作 (01-04) / Read operations (01-04)
// 格式:[从站 (1)][功能码 (1)][起始地址 (2)][数量 (2)][CRC (2)]
// Format: [Slave (1)][Function (1)][Start Addr (2)][Quantity (2)][CRC (2)]
if (content[1] == 1 || content[1] == 2 || content[1] == 3 || content[1] == 4 || content[1] == 5 || content[1] == 6 || content[1] == 8) return 8;
// 简单命令 (07/11/12/17) / Simple commands (07/11/12/17)
// 格式:[从站 (1)][功能码 (1)][CRC (2)]
// Format: [Slave (1)][Function (1)][CRC (2)]
else if (content[1] == 7 || content[1] == 11 || content[1] == 12 || content[1] == 17) return 4;
// 写多个线圈/寄存器 (15/16) / Write multiple coils/registers (15/16)
// 格式:[从站 (1)][功能码 (1)][起始地址 (2)][数量 (2)][字节数 (1)][数据 (N)][CRC (2)]
// Format: [Slave (1)][Function (1)][Start Addr (2)][Quantity (2)][Byte Count (1)][Data (N)][CRC (2)]
else if (content[1] == 15 || content[1] == 16) { return DuplicateWithCount.GetDuplcateFunc(new List<int> { 6 }, 9).Invoke(content); }
// 掩码写寄存器 (22) / Mask write register (22)
// 格式:[从站 (1)][功能码 (1)][地址 (2)][AND 掩码 (2)][OR 掩码 (2)][CRC (2)]
// Format: [Slave (1)][Function (1)][Address (2)][AND Mask (2)][OR Mask (2)][CRC (2)]
else if (content[1] == 22) return 10;
// 读写多个寄存器 (23) / Read/write multiple registers (23)
else if (content[1] == 23) return 19;
// 读 FIFO 队列 (24) / Read FIFO queue (24)
else if (content[1] == 24) return 6;
// 默认:使用字节数计算 / Default: use byte count calculation
else return DuplicateWithCount.GetDuplcateFunc(new List<int> { 2 }, 5).Invoke(content);
};
}
/// <summary>
/// Modbus ASCII 协议控制器 / Modbus ASCII Protocol Controller
/// <remarks>
/// 用于 Modbus ASCII 串口通信的 FIFO 控制器
/// FIFO controller for Modbus ASCII serial communication
/// <para>
/// 特点 / Characteristics:
/// <list type="bullet">
/// <item>使用 LRC 校验 / Uses LRC checksum</item>
/// <item>ASCII 编码 / ASCII encoding</item>
/// <item>以冒号开始CRLF 结束 / Starts with colon, ends with CRLF</item>
/// </list>
/// </para>
/// </remarks>
/// </summary>
public class ModbusAsciiController : FifoController
{
/// <summary>
/// 构造函数 / Constructor
/// <remarks>
/// 从配置读取参数初始化 ASCII 控制器
/// Initialize ASCII controller with parameters read from configuration
/// </remarks>
/// </summary>
/// <param name="com">
/// 串口名称 / Serial Port Name
/// <remarks>如 "COM1", "COM2" 等 / e.g., "COM1", "COM2", etc.</remarks>
/// </param>
/// <param name="slaveAddress">
/// 从站号 / Slave Address
/// <remarks>Modbus 从站地址,范围 1-247 / Modbus slave address, range 1-247</remarks>
/// </param>
public ModbusAsciiController(string com, int slaveAddress) : base(
// 从配置读取获取间隔时间 / Read fetch interval time from configuration
int.Parse(ConfigurationReader.GetValue("COM:" + com + ":" + slaveAddress, "FetchSleepTime")),
// ASCII 长度计算函数 / ASCII length calculation function
lengthCalc: ModbusLengthCalc.ModbusAsciiLengthCalc,
// LRC 校验函数 / LRC check function
checkRightFunc: ContentCheck.LrcCheckRight,
// 从配置读取等待队列长度 / Read waiting list count from configuration
waitingListMaxCount: ConfigurationReader.GetValue("COM:" + com + ":" + slaveAddress, "WaitingListCount") != null ?
int.Parse(ConfigurationReader.GetValue("COM:" + com + ":" + slaveAddress, "WaitingListCount")) :
null
)
{ }
}
/// <summary>
/// Modbus ASCII in TCP 协议控制器 / Modbus ASCII in TCP Protocol Controller
/// <remarks>
/// 用于 Modbus ASCII over TCP 的 FIFO 控制器
/// FIFO controller for Modbus ASCII over TCP
/// <para>
/// 使用场景 / Use Cases:
/// <list type="bullet">
/// <item>串口服务器 / Serial device server</item>
/// <item>TCP 透传 ASCII 数据 / TCP tunneling of ASCII data</item>
/// </list>
/// </para>
/// </remarks>
/// </summary>
public class ModbusAsciiInTcpController : FifoController
{
/// <summary>
/// 构造函数 / Constructor
/// <remarks>
/// 从配置读取参数初始化 ASCII in TCP 控制器
/// Initialize ASCII in TCP controller with parameters read from configuration
/// </remarks>
/// </summary>
/// <param name="ip">
/// IP 地址 / IP Address
/// <remarks>如 "192.168.1.100" / e.g., "192.168.1.100"</remarks>
/// </param>
/// <param name="port">
/// 端口号 / Port Number
/// <remarks>如 8899 (串口服务器常用端口) / e.g., 8899 (common for serial servers)</remarks>
/// </param>
public ModbusAsciiInTcpController(string ip, int port) : base(int.Parse(ConfigurationReader.GetValue("TCP:" + ip + ":" + port, "FetchSleepTime")),
// ASCII 长度计算函数 / ASCII length calculation function
lengthCalc: ModbusLengthCalc.ModbusAsciiLengthCalc,
// LRC 校验函数 / LRC check function
checkRightFunc: ContentCheck.LrcCheckRight,
// 从配置读取等待队列长度 / Read waiting list count from configuration
waitingListMaxCount: ConfigurationReader.GetValue("TCP:" + ip + ":" + port, "WaitingListCount") != null
? int.Parse(ConfigurationReader.GetValue("TCP:" + ip + ":" + port, "WaitingListCount"))
: null
)
{ }
}
/// <summary>
/// Modbus ASCII in UDP 协议控制器 / Modbus ASCII in UDP Protocol Controller
/// <remarks>
/// 用于 Modbus ASCII over UDP 的 FIFO 控制器
/// FIFO controller for Modbus ASCII over UDP
/// </remarks>
/// </summary>
public class ModbusAsciiInUdpController : FifoController
{
/// <summary>
/// 构造函数 / Constructor
/// <remarks>
/// 从配置读取参数初始化 ASCII in UDP 控制器
/// Initialize ASCII in UDP controller with parameters read from configuration
/// </remarks>
/// </summary>
/// <param name="ip">IP 地址 / IP Address</param>
/// <param name="port">端口号 / Port Number</param>
public ModbusAsciiInUdpController(string ip, int port) : base(int.Parse(ConfigurationReader.GetValue("UDP:" + ip + ":" + port, "FetchSleepTime")),
lengthCalc: ModbusLengthCalc.ModbusAsciiLengthCalc,
checkRightFunc: ContentCheck.LrcCheckRight,
waitingListMaxCount: ConfigurationReader.GetValue("UDP:" + ip + ":" + port, "WaitingListCount") != null
? int.Parse(ConfigurationReader.GetValue("UDP:" + ip + ":" + port, "WaitingListCount"))
: null
)
{ }
}
/// <summary>
/// Modbus RTU 发送协议控制器 / Modbus RTU Request Protocol Controller
/// <remarks>
/// 用于 Modbus RTU 串口通信的 FIFO 控制器
/// FIFO controller for Modbus RTU serial communication
/// <para>
/// 特点 / Characteristics:
/// <list type="bullet">
/// <item>使用 CRC16 校验 / Uses CRC16 checksum</item>
/// <item>二进制编码 / Binary encoding</item>
/// <item>最高效的 Modbus 模式 / Most efficient Modbus mode</item>
/// </list>
/// </para>
/// </remarks>
/// </summary>
public class ModbusRtuController : FifoController
{
/// <summary>
/// 构造函数 / Constructor
/// <remarks>
/// 从配置读取参数初始化 RTU 控制器
/// Initialize RTU controller with parameters read from configuration
/// </remarks>
/// </summary>
/// <param name="com">串口名称 / Serial Port Name</param>
/// <param name="slaveAddress">从站号 / Slave Address</param>
public ModbusRtuController(string com, int slaveAddress) : base(
// 从配置读取获取间隔时间 / Read fetch interval time from configuration
int.Parse(ConfigurationReader.GetValue("COM:" + com + ":" + slaveAddress, "FetchSleepTime")),
// RTU 响应长度计算函数 / RTU response length calculation function
lengthCalc: ModbusLengthCalc.ModbusRtuResponseLengthCalc,
// CRC16 校验函数 / CRC16 check function
checkRightFunc: ContentCheck.Crc16CheckRight,
// 从配置读取等待队列长度 / Read waiting list count from configuration
waitingListMaxCount: ConfigurationReader.GetValue("COM:" + com + ":" + slaveAddress, "WaitingListCount") != null ?
int.Parse(ConfigurationReader.GetValue("COM:" + com + ":" + slaveAddress, "WaitingListCount")) :
null
)
{ }
}
/// <summary>
/// Modbus RTU 接收协议控制器 / Modbus RTU Response Protocol Controller
/// <remarks>
/// 用于 Modbus RTU 服务器端响应的 FIFO 控制器
/// FIFO controller for Modbus RTU server-side responses
/// <para>
/// 与 ModbusRtuController 的区别 / Difference from ModbusRtuController:
/// <list type="bullet">
/// <item>ModbusRtuController: 客户端请求 / ModbusRtuController: Client requests</item>
/// <item>ModbusRtuResponseController: 服务器端响应 / ModbusRtuResponseController: Server responses</item>
/// </list>
/// </para>
/// </remarks>
/// </summary>
public class ModbusRtuResponseController : FifoController
{
/// <summary>
/// 构造函数 / Constructor
/// <remarks>
/// 从配置读取参数初始化 RTU 响应控制器
/// Initialize RTU response controller with parameters read from configuration
/// </remarks>
/// </summary>
/// <param name="com">串口名称 / Serial Port Name</param>
/// <param name="slaveAddress">从站号 / Slave Address</param>
public ModbusRtuResponseController(string com, int slaveAddress) : base(
int.Parse(ConfigurationReader.GetValue("COM:" + com + ":" + slaveAddress, "FetchSleepTime")),
// RTU 请求长度计算函数 / RTU request length calculation function
lengthCalc: ModbusLengthCalc.ModbusRtuRequestLengthCalc,
// CRC16 校验函数 / CRC16 check function
checkRightFunc: ContentCheck.Crc16CheckRight,
waitingListMaxCount: ConfigurationReader.GetValue("COM:" + com + ":" + slaveAddress, "WaitingListCount") != null ?
int.Parse(ConfigurationReader.GetValue("COM:" + com + ":" + slaveAddress, "WaitingListCount")) :
null
)
{ }
}
// 更多控制器类 (ModbusTcpController, ModbusRtuInTcpController 等) 的注释类似
// More controller classes (ModbusTcpController, ModbusRtuInTcpController, etc.) have similar annotations
}