IPacker 接口 - Snet Docs

🧩 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 使用协议保守默认 MaxReadLength,正数仍受 PhysicalMaxBytes / 65535 上限约束
format 数据字节序格式

返回(ResultData):支持组包时为优化 Address,否则原地址透传;null 输入或支持协议的空点集允许 null。常规错误包装为失败 OperateResult,但入口/异步取消不承诺永不抛异常。全部未优化点保留原对象、原 Length 和全部扩展参数,不附加单点模型;组包不是地址校正器。

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

仅 AddressDataType=ByteArray 且扩展参数可取得 List 时按字节批解码;其他值以单点字典返回原 AddressValue 同对象,Status 由 Quality==Normal 决定。已识别字节批须质量正常且 OriginalValue 为 byte[],否则按每个模型返回 Exception 质量点并置 Status=false。偏移、长度或 BoolIndex 越界保留失败项,成功项仍可读取。空字节对非空模型逐项校验边界,空模型可成功返回空字典。异步取消可能传播异常,不承诺取消仅返回失败结果。

字典重载可统一处理组包批与直接值,对各项 Status 做与运算,保留所有返回字典(包括失败/部分结果)。任一失败则整体 Status=false(部分点位解包失败);仍应读取 ResultData 并逐点检查 Quality,不要丢弃结果列表。空字典成功返回空列表,null 输入失败。同名多规格结果键可带 \u0001DataType/序号后缀,AddressValue.AddressName 保留原地址。

快速入门

using Snet.Siemens;
using Snet.Model.data;
using Snet.Model.@enum;
using Snet.Model.@interface;   // IPacker
using System.Collections.Concurrent;

await using var op = await SiemensOperate.InstanceAsync(new SiemensData.Basics
{
    IpAddress = "192.168.1.100",
    Port = 102
});

// 1) 组包:将分散地址合并为最少的批量读取
if (!(await op.OnAsync()).Status) return;

var address = new Address(new List<AddressDetails>
{
    new("DB1.DBD0", DataType.Float),
    new("DB1.DBD4", DataType.Float),
    new("DB1.DBW8", DataType.Int16),
    new("DB1.DBX10.3", DataType.Bool)
});
OperateResult packed = await op.PackerAsync(address, "SiemensS7Net_S1200");
if (!packed.Status) return;                                   // 组包失败;不支持协议正常透传
var packedAddr = packed.GetSource<Address>();                 // ResultData = 优化后的 Address
if (packedAddr is null) return;

// 2) 一次往返读取组包后的批次
OperateResult result = await op.ReadAsync(packedAddr);
if (!result.Status) return;                                   // 读取失败
var data = result.GetSource<ConcurrentDictionary<string, AddressValue>>();
if (data is null) return;

// 3) 解包:将每个批次的原始字节解析回各地址的值
OperateResult unpacked = await op.UnPackerAsync(data);
if (!unpacked.Status) Console.Error.WriteLine(unpacked.Message);
var values = unpacked.GetSource<List<ConcurrentDictionary<string, AddressValue>>>();
if (values is null) return;
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) Console.Error.WriteLine(unpacked.Message);
var values = unpacked.GetSource<ConcurrentDictionary<string, AddressValue>>();
if (values is null) return;
注意

GetSource<T>() 属于 OperateResult(来自 ResultModel),无参数,只转换非空 ResultData,并不检查 Status。应在结果对象上调用而非 ResultData 上;Status=false 时也可能读取到保留的失败/部分数据,随后逐点检查 Quality。

透传行为

当前映射还排除 SiemensFetchWriteNet、MelsecMcRNet、MelsecA1ENet、MelsecA1EAsciiNet、MelsecFxSerial、MelsecFxSerialOverTcp;A3C/A4C 仍可组包。完整协议/范围边界见 组包引擎。

Packer 不会盲目优化——符号/标签寻址的协议原样返回:

  • SiemensS7Plus(符号访问)
  • MelsecCipNet(标签访问)
  • OmronCipNet / OmronConnectedCipNet(标签访问)
  • OmronHostLinkCMode / OmronHostLinkCModeOverTcp(已不在组包器供应商映射表中——原样返回)

成功时结果 Message 为 "组包成功",解包为 "解包成功"。

底层机制

组件 角色
DaqAbstract.packerHandler 公共字段——Packer 使用的 PackerHandler 单例
DaqAbstract.bytesHandler 公共字段——UnPacker 使用的 BytesHandler 单例
Snet.Core.packer.IPackerCore 底层按协议实现的组包引擎(每个协议族一个实现)

引擎细节、受支持的协议族与 maxByteLength 语义:地址自动组包。

相关资源