Skip to content

[feat] 增强 ZLG 适配器的细粒度发送回显功能的建议 #13

@zyzy811

Description

@zyzy811

Problem to solve

  • ZLG 适配器在接收帧时没有正确处理特有的 txEchoed 回显标记
  • ZLG 适配器支持比全局总线回显模式更细粒度的帧级别回显控制

麻烦评估一下是否需要实现?
最终目标

// 1. 使用总线全局回显模式(原有方式)
bus.Options.WorkMode = ChannelWorkMode.Echo;
bus.Transmit(frame);

// 2. 使用单帧回显(新增方式,无需总线回显模式)
var frameWithEcho = CanFrame.Fd(id, data)
{
    Flags = FrameFlags.Echo  // 设置帧级别的回显请求
};
bus.Transmit(frameWithEcho);  // 即使总线不在回显模式,该帧也会被回显

Proposal

1、通用api修改
新增 FrameFlags.Echo 标志(CanFrame.cs)

[Flags]
public enum FrameFlags : ushort
{
    None = 0,
    Ext = 1,
    Rtr = 2,
    Brs = 4,
    Esi = 8,
    Error = 16,
    Echo = 32  // 新增: 软件级发送回显请求标志
}

在 CanFrameView 和 CanFrame中新增 IsEchoRequested 属性 public bool IsEchoRequested => (Flags & FrameFlags.Echo) != 0;

在 CanFrame 的工厂方法中添加 isEchoRequested 参数以方便使用
在以下工厂方法中添加可选的 isEchoRequested 参数:

  • CanFrame.Classic() (两个重载)
  • CanFrame.Fd() (两个重载)
    这样用户可以更方便地创建带回显请求的帧,而不需要手动设置 Flags。

2、ZLG适配器修改
新增细粒度回显特性标志 ( ZlgEnums.cs )

[Flags]
public enum ZlgFeature
{
    None = 0x0,
    MergeReceive = 0x4,
    SkipBitRate = 0x8,
    PerFrameEcho = 0x10  // 新增: 细粒度单帧回显支持
}

修复接收时的回显标记处理 ( ZlgUtils.cs )

  • 在 FromZCANDataClassic() 和 FromZCANDataFd() 中设置 IsEcho = pObj.data.fdData.txEchoed,这两个方法在从 ZCANDataObj 转换时,忽略了 txEchoed 标记,导致通过合并接收方式收到的回显帧无法被识别
// 设置 IsEcho
    return new CanReceiveData(result) { IsEcho = pObj.data.fdData.txEchoed };
  • 在 ZlgCanFdTransceiver.Receive() 中检查 TX_ECHO_FLAG,在从 ZCAN_ReceiveFD_Data 转换时,没有检查 TX_ECHO_FLAG ,导致通过独立通道接收方式收到的回显帧无法被识别
public IEnumerable<CanReceiveData> Receive(ICanBus<IBusRTOptionsConfigurator> bus, int count = 1, int timeOut = 0)
{
    var pool = ArrayPool<ZCAN_ReceiveFD_Data>.Shared;
    var buf = pool.Rent(ZCAN.BATCH_COUNT);
    try
    {
        while (count > 0)
        {
            var recCount = ZCAN.ZCAN_ReceiveFD(((ZlgCanBus)bus).Handle, buf, (uint)count, remaining);
            for (int i = 0; i < recCount; i++)
            {
                // 检查 TX_ECHO_FLAG 来判断是否为回显帧
                var isEcho = (buf[i].frame.flags & ZCAN.TX_ECHO_FLAG) != 0;
                
                yield return new CanReceiveData(buf[i].frame.FromReceiveData(bus.Options.BufferAllocator))
                {
                    // ZLG timestamp is in microseconds
                    ReceiveTimestamp = TimeSpan.FromTicks((long)buf[i].timestamp * 10),
                    IsEcho = isEcho  // 设置回显标记
                };
            }
            count -= (int)recCount;
        }
    }
    finally
    {
        pool.Return(buf);
    }
}

实现帧级别的回显控制 ( ZlgUtils.cs )
在所有发送转换方法中实现:bool shouldEcho = frame.IsEchoRequested || echo; // 帧级别优先,否则使用总线设置
在所有 ZLG Provider 中启用新特性

Alternatives considered

在 FrameFlags 中添加软件级 Echo 标志,但我看FrameFlags中的其它枚举是对应的硬件含义,添加一个软件的Echo是否不太好?
考虑将回显控制移到 API 参数层面而非标志层面(如果语义一致性很重要)
如果需要保持 FrameFlags 只包含硬件协议位的语义一致性,可以:

  • 从 FrameFlags 中移除 Echo 标志
  • 在 ITransceiver.Transmit() 和 ICanBus.Transmit() 系列方法中添加可选的 requestEcho 参数
  • 或者创建一个包含 requestEcho 字段的发送选项类
    这样可以保持 API 的语义一致性,但需要修改通用 API。

Areas

  • Core
  • PCAN
  • Kvaser
  • SocketCAN
  • ZLG
  • Docs

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions