358 lines
19 KiB
C#
358 lines
19 KiB
C#
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>异常响应 (功能码>128): 5 字节 / Exception response (function code>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
|
||
}
|