🧩 IPacker 接口
命名空间: Snet.Model.@interface | 接口: IPacker | 成员: 6 个方法(同步 + 异步)
IPacker 是地址自动组包与解包能力接口。每个数采驱动都通过 IDaq 实现它,因此在驱动实例上即可直接组包、解包——无需手动装配处理器。
public interface IPacker
{
OperateResult Packer(Address? address, string protocolTypeKey, int maxByteLength = 0, DataFormat format = DataFormat.ABCD);
Task<OperateResult> PackerAsync(Address? address, string protocolTypeKey, int maxByteLength = 0, DataFormat format = DataFormat.ABCD, CancellationToken token = default);
OperateResult UnPacker(AddressValue addressValue, bool isStringReverseByteWord = false);
Task<OperateResult> UnPackerAsync(AddressValue addressValue, bool isStringReverseByteWord = false, CancellationToken token = default);
OperateResult UnPacker(ConcurrentDictionary<string, AddressValue> pairs, bool isStringReverseByteWord = false);
Task<OperateResult> UnPackerAsync(ConcurrentDictionary<string, AddressValue> pairs, bool isStringReverseByteWord = false, CancellationToken token = default);
}
接口层次结构
IPacker 是组成 IDaq 的 15 个组件接口之一——IDaq : ... IClone, IPacker, IDisposable, IAsyncDisposable。由 DaqAbstract<,>(全部 36+ 协议驱动的基类)实现,内部委托 PackerHandler(组包)与 BytesHandler(解包)。
成员参考
Packer — 智能地址自动组包
| 成员 | 签名 | 描述 |
|---|---|---|
Packer |
OperateResult Packer(Address? address, string protocolTypeKey, int maxByteLength = 0, DataFormat format = DataFormat.ABCD) |
将地址集优化为最小批量读取结构 |
PackerAsync |
Task<OperateResult> PackerAsync(Address? address, string protocolTypeKey, int maxByteLength = 0, DataFormat format = DataFormat.ABCD, CancellationToken token = default) |
异步变体 |
参数:
| 参数 | 描述 |
|---|---|
address |
原始地址集合 |
protocolTypeKey |
供应商 ProtocolType 枚举的字符串名——如 "SiemensS7Net_S1200"、"ModbusTcpNet"、"OmronFinsNet"。接受各供应商数据类中 ProtocolType.ToString() 的返回值 |
maxByteLength |
单次批量读取最大字节数。0 = 自动使用协议上限(推荐)。也可以使用调试工具直接读取得知最大字节数 |
format |
数据字节序格式 |
返回(ResultData 负载):协议族支持组包 → 优化后的 Address;不支持 → 原样返回原始地址。传入 null 返回 null。永不抛异常——结果始终是 OperateResult。
UnPacker — 自动解包
| 成员 | 签名 | 描述 |
|---|---|---|
UnPacker |
OperateResult UnPacker(AddressValue addressValue, bool isStringReverseByteWord = false) |
解包单个组包批次,返回以地址名为键的 ConcurrentDictionary<string, AddressValue> |
UnPackerAsync |
Task<OperateResult> UnPackerAsync(AddressValue addressValue, bool isStringReverseByteWord = false, CancellationToken token = default) |
异步变体 |
UnPacker |
OperateResult UnPacker(ConcurrentDictionary<string, AddressValue> pairs, bool isStringReverseByteWord = false) |
解包一次读取结果的全部批次,返回 List<ConcurrentDictionary<string, AddressValue>> |
UnPackerAsync |
Task<OperateResult> UnPackerAsync(ConcurrentDictionary<string, AddressValue> pairs, bool isStringReverseByteWord = false, CancellationToken token = default) |
异步变体 |
参数:
| 参数 | 描述 |
|---|---|
isStringReverseByteWord |
String 解包时是否按 16 位字反转字节(每 2 字节一组交换)。连接级配置——如欧姆龙 FINS 的字符串按字反转字节读取。默认 false |
输入必须来自组包后的读取。组包时为每个批次附加特定参数(AddressExtendParam 持有各地址的 BytesModel 列表);UnPacker 据此将批次的原始字节解析回各地址的值。对非组包数据解包会失败并返回明确的错误信息。
快速入门
using Snet.Siemens;
using Snet.Model.data;
using Snet.Model.@enum;
using Snet.Model.@interface; // IPacker
var op = await SiemensOperate.InstanceAsync(new SiemensData.Basics
{
IpAddress = "192.168.1.100",
Port = 102
});
// 1) 组包:将分散地址合并为最少的批量读取
var address = new Address(new List<AddressDetails>
{
new("Reading", DataType.Float),
new("Reading 2", DataType.Float),
new("Reading 3", DataType.Int),
new("Reading 4", DataType.Bool)
});
OperateResult packed = await op.PackerAsync(address, "SiemensS7Net_S1200");
if (!packed.Status) return; // 组包失败 / 协议不支持
var packedAddr = packed.GetSource<Address>(); // ResultData = 优化后的 Address
// 2) 一次往返读取组包后的批次
OperateResult result = await op.ReadAsync(packedAddr);
if (!result.Status) return; // 读取失败
var data = result.GetSource<ConcurrentDictionary<string, AddressValue>>();
// 3) 解包:将每个批次的原始字节解析回各地址的值
OperateResult unpacked = await op.UnPackerAsync(data);
if (!unpacked.Status) return; // 解包失败
var values = unpacked.GetSource<List<ConcurrentDictionary<string, AddressValue>>>();
foreach (var dict in values)
foreach (var v in dict)
Console.WriteLine($"{v.Key} = {v.Value.ResultValue}");
解包单个批次
持有单个批次的 AddressValue 时(如来自订阅或事件负载),使用单值重载:
OperateResult unpacked = await op.UnPackerAsync(kv.Value); // kv.Value = 一个组包批次
if (!unpacked.Status) return; // 解包失败
var values = unpacked.GetSource<ConcurrentDictionary<string, AddressValue>>();
GetSource<T>() 是 OperateResult 的成员方法(继承自 ResultModel)——无参,自动把结果的 ResultData 解包为 T。在 OperateResult 对象本身上调用(packed.GetSource<Address>()),不要直接对 packed.ResultData 调用;使用解包值前先检查 Status(操作失败时返回 default)。
透传行为
Packer 不会盲目优化——符号/标签寻址的协议原样返回:
SiemensS7Plus(符号访问)MelsecCipNet(标签访问)OmronCipNet/OmronConnectedCipNet(标签访问)OmronHostLinkCMode/OmronHostLinkCModeOverTcp(已不在组包器供应商映射表中——原样返回)
成功时结果 Message 为 "组包成功",解包为 "解包成功"。
底层机制
| 组件 | 角色 |
|---|---|
DaqAbstract.packerHandler |
公共字段——Packer 使用的 PackerHandler 单例 |
DaqAbstract.bytesHandler |
公共字段——UnPacker 使用的 BytesHandler 单例 |
Snet.Core.packer.IPackerCore |
底层按协议实现的组包引擎(每个协议族一个实现) |
引擎细节、受支持的协议族与 maxByteLength 语义:地址自动组包。
