using Common.Attributes;
using Logger;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.ComponentModel;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace ZLGUSBCANFD
{
    [ADPCommand]
    public class ZLGCANFD : IDisposable
    {
        // 硬件设备与通道句柄
        private IntPtr _deviceHandle = IntPtr.Zero;
        private readonly IntPtr[] _channelHandles;

        // 每个通道分配独立的 DBC 引擎句柄与锁，彻底解决台架间DBC冲突与锁竞争
        private readonly uint[] _dbcHandles;
        private readonly bool[] _isDbcLoadedArray;
        private readonly object[] _channelLocks; // 通道级细粒度锁 

        // 异步高性能接收线程控制
        private volatile bool _isRunning = false;
        private volatile bool _isClosing = false; // 关闭流程标志：通知循环发送任务尽快退出
        private readonly List<Thread> _receiveThreads = new List<Thread>();

        // DBC 循环发送任务管理：Key = (通道号, 帧ID)，Value = (CTS, Task)
        private readonly ConcurrentDictionary<(uint 通道号, uint 帧ID), (CancellationTokenSource Cts, Task SendTask)> _cyclicSenders = new ConcurrentDictionary<(uint, uint), (CancellationTokenSource, Task)>();

        // 信号值持久化覆盖表：Key = (通道号, 帧ID)，Value = 信号名 → 物理值
        // 每次 设置报文 会累积写入此表，发送时以 DBC 初始值为底再叠加此表覆盖值
        private readonly ConcurrentDictionary<(uint 通道号, uint 帧ID), Dictionary<string, double>> _signalOverrides = new ConcurrentDictionary<(uint, uint), Dictionary<string, double>>();

        // 动态硬件参数
        private readonly uint _deviceType;   // 76: USBCANFD-400U
        private readonly uint _deviceIndex;  // 设备索引
        private readonly int _maxChannels;   // 动态通道数

        // 通道波特率与终端电阻配置（构造时传入，所有通道共用）
        private readonly string _abitBaud;
        private readonly string _dbitBaud;
        private readonly bool _enableTerminalResistance;

        /// <summary>
        /// 当前 CAN 卡专属的 DBC 解析器，按通道隔离报文数据库。
        /// </summary>
        public ZLGDBCParser DBCParser { get; }

        /// <summary>
        /// 事件：当接收到 CAN/CANFD 报文并且通过 DBC 成功解析后触发
        /// 参数：uint 通道号 (0,1,2,3), ZDBC.DBCMessage 解析后的DBC消息结构体
        /// </summary>
        public event Action<uint, ZDBC.DBCMessage>? OnDbcMessageDecoded;

        public ZLGCANFD(uint deviceType = 76, uint deviceIndex = 0, int maxChannels = 4,
            string abitBaud = "500000", string dbitBaud = "2000000", bool enableTerminalResistance = true)
        {
            _deviceType = deviceType;
            _deviceIndex = deviceIndex;
            _maxChannels = maxChannels;
            _abitBaud = abitBaud;
            _dbitBaud = dbitBaud;
            _enableTerminalResistance = enableTerminalResistance;

            // 初始化通道相关状态数组
            _channelHandles = new IntPtr[_maxChannels];
            _dbcHandles = new uint[_maxChannels];
            _isDbcLoadedArray = new bool[_maxChannels];
            _channelLocks = new object[_maxChannels];
            DBCParser = new ZLGDBCParser(_maxChannels);

            for (int i = 0; i < _maxChannels; i++)
            {
                _channelHandles[i] = IntPtr.Zero;
                _dbcHandles[i] = 0;
                _isDbcLoadedArray[i] = false;
                _channelLocks[i] = new object();
            }
        }

        #region 1. 硬件连接与通道初始化

        /// <summary>
        /// 仅仅打开设备，不做具体的通道波特率配置（留给具体的台架去分别配置）
        /// </summary>
        public virtual bool 打开设备()
        {
            if (_deviceHandle != IntPtr.Zero) return true;
            _deviceHandle = ZLGCAN.ZCAN_OpenDevice(ZLGCAN.ZCAN_USBCANFD_400U, _deviceIndex, 0);
            return _deviceHandle != IntPtr.Zero;
        }

        /// <summary>
        /// 针对特定通道进行参数初始化并启动（使用构造时传入的波特率与终端电阻配置）
        /// </summary>
        public virtual bool 初始化并启动通道(uint 通道号)
        {
            _isClosing = false; // 重置关闭标志，允许循环发送
            if (_deviceHandle == IntPtr.Zero) throw new InvalidOperationException("请先调用 '打开设备()' 才能初始化通道。");
            if (通道号 >= _maxChannels) return false;

            lock (_channelLocks[通道号])
            {
                // 如果已经启动过，直接退出
                if (_channelHandles[通道号] != IntPtr.Zero)
                {
                    return true;
                    //ZLGCAN.ZCAN_ResetCAN(_channelHandles[通道号]);
                }

                // 1. 设置该通道专属的仲裁域与数据域波特率
                if (ZLGCAN.ZCAN_SetValue(_deviceHandle, $"{通道号}/canfd_abit_baud_rate", _abitBaud) != 1) return false;
                if (ZLGCAN.ZCAN_SetValue(_deviceHandle, $"{通道号}/canfd_dbit_baud_rate", _dbitBaud) != 1) return false;

                // 2. 设置该通道专属内部终端电阻状态
                string resistanceStr = _enableTerminalResistance ? "1" : "0";
                if (ZLGCAN.ZCAN_SetValue(_deviceHandle, $"{通道号}/initenal_resistance", resistanceStr) != 1) return false;

                // 3. 规范配置通道结构体
                ZLGCAN.ZCAN_CHANNEL_INIT_CONFIG config = new ZLGCAN.ZCAN_CHANNEL_INIT_CONFIG();
                config.can_type = 1;                 // 1 代表 CANFD 模式
                config.config.canfd.mode = 0;        // 0 代表正常工作模式

                IntPtr pConfig = Marshal.AllocHGlobal(Marshal.SizeOf(config));
                Marshal.StructureToPtr(config, pConfig, true);
                _channelHandles[通道号] = ZLGCAN.ZCAN_InitCAN(_deviceHandle, 通道号, pConfig);
                Marshal.FreeHGlobal(pConfig);

                if (_channelHandles[通道号] == IntPtr.Zero) return false;

                // 4. 启动 CAN 通道
                if (ZLGCAN.ZCAN_StartCAN(_channelHandles[通道号]) != 1) return false;

                // 5. 为该通道启动专属的独立后台高性能轮询接收线程（如果尚未启动轮询）
                if (!_isRunning) _isRunning = true;

                int chnIdx = (int)通道号;
                Thread rxThread = new Thread(() => 接收轮询核心(_channelHandles[chnIdx], (uint)chnIdx))
                {
                    IsBackground = true,
                    Name = $"ZLGCANFD_Dev{_deviceIndex}_CH{chnIdx}_RxThread"
                };
                _receiveThreads.Add(rxThread);
                rxThread.Start();

                return true;
            }
        }

        public virtual void 关闭CAN卡设备()
        {
            _isClosing = true;  // 通知循环发送任务尽快退出
            _isRunning = false; // 通知接收轮询线程退出
            停止所有循环发送(); // 内部会等待所有循环发送 Task 退出

            // 等待所有接收轮询线程真正退出（每个最多 1 秒）
            foreach (var thread in _receiveThreads)
            {
                if (thread.IsAlive)
                    thread.Join(1000);
            }
            _receiveThreads.Clear();

            // 动态复位所有通道并释放 DBC（使用 TryEnter 防止死锁）
            for (uint i = 0; i < _maxChannels; i++)
            {
                if (Monitor.TryEnter(_channelLocks[i], TimeSpan.FromSeconds(2)))
                {
                    try
                    {
                        if (_channelHandles[i] != IntPtr.Zero)
                        {
                            ZLGCAN.ZCAN_ResetCAN(_channelHandles[i]);
                            _channelHandles[i] = IntPtr.Zero;
                        }
                        释放通道DBC(i);
                    }
                    finally
                    {
                        Monitor.Exit(_channelLocks[i]);
                    }
                }
                else
                {
                    // 锁超时：循环发送 Task 可能仍阻塞在原生 API 调用中，强制清理
                    LoggerHelper.Info($"[ZLGCANFD] 关闭通道 {i} 时获取锁超时，强制清理");
                    if (_channelHandles[i] != IntPtr.Zero)
                    {
                        try { ZLGCAN.ZCAN_ResetCAN(_channelHandles[i]); } catch { }
                        _channelHandles[i] = IntPtr.Zero;
                    }
                    释放通道DBC(i);
                }
            }

            // 关闭设备主句柄
            if (_deviceHandle != IntPtr.Zero)
            {
                ZLGCAN.ZCAN_CloseDevice(_deviceHandle);
                _deviceHandle = IntPtr.Zero;
            }

            _isClosing = false;
        }

        #endregion

        #region 2. DBC 矩阵文件操作

        /// <summary>
        /// 指定通道加载特定的 DBC 文件（支持不同通道加载不同的DBC矩阵）
        /// </summary>
        public virtual bool 加载通道DBC文件(uint 通道号, string dbcFilePath)
        {
            if (通道号 >= _maxChannels) return false;

            lock (_channelLocks[通道号])
            {
                try
                {
                    if (_isDbcLoadedArray[通道号]) return true;
                    //加载前先卸载
                    释放通道DBC(通道号);
                    uint chDbcHandle = ZDBC.ZDBC_Init();
                    if (chDbcHandle == 0) return false;

                    IntPtr ptrPath = Marshal.StringToHGlobalAnsi(dbcFilePath);
                    bool success = ZDBC.ZDBC_LoadFile(chDbcHandle, ptrPath);
                    Marshal.FreeHGlobal(ptrPath);

                    if (success)
                    {
                        _dbcHandles[通道号] = chDbcHandle;
                        _isDbcLoadedArray[通道号] = true;
                        DBCParser.ParseAndLoadToDatabase(chDbcHandle, (int)通道号);
                    }
                    else
                    {
                        ZDBC.ZDBC_Release(chDbcHandle);
                    }
                    return success;
                }
                catch
                {
                    return false;
                }
            }
        }

        public virtual void 释放通道DBC(uint 通道号)
        {
            if (通道号 >= _maxChannels) return;

            lock (_channelLocks[通道号])
            {
                if (_isDbcLoadedArray[通道号] && _dbcHandles[通道号] != 0)
                {
                    ZDBC.ZDBC_Release(_dbcHandles[通道号]);
                    _dbcHandles[通道号] = 0;
                    _isDbcLoadedArray[通道号] = false;
                    DBCParser.MsgDatabase[(int)通道号].Clear();
                }
            }
        }

        #endregion

        #region 3. 轮询接收与实时自动化 DBC 解码

        private void 接收轮询核心(IntPtr channelHandle, uint channelIndex)
        {
            const int bufferSize = 100;
            int canStructSize = Marshal.SizeOf(typeof(ZLGCAN.ZCAN_Receive_Data));
            int canfdStructSize = Marshal.SizeOf(typeof(ZLGCAN.ZCAN_ReceiveFD_Data));
            int dbcMsgSize = Marshal.SizeOf(typeof(ZDBC.DBCMessage));

            IntPtr ptrCanBuffer = Marshal.AllocHGlobal(canStructSize * bufferSize);
            IntPtr ptrCanFDBuffer = Marshal.AllocHGlobal(canfdStructSize * bufferSize);
            IntPtr ptrDbcMsg = Marshal.AllocHGlobal(dbcMsgSize);

            try
            {
                while (_isRunning)
                {
                    bool currentTurnHasData = false;

                    // 1. 自动提取并解析经典 CAN 帧
                    uint canNum = ZLGCAN.ZCAN_GetReceiveNum(channelHandle, 0);
                    if (canNum > 0)
                    {
                        uint actualRecv = ZLGCAN.ZCAN_Receive(channelHandle, ptrCanBuffer, bufferSize, 5);
                        for (int i = 0; i < actualRecv; i++)
                        {
                            IntPtr framePtr = IntPtr.Add(ptrCanBuffer, i * canStructSize);

                            // 只锁定当前通道的DBC句柄进行解码，高并发完全不卡顿
                            lock (_channelLocks[channelIndex])
                            {
                                if (_isDbcLoadedArray[channelIndex] && ZDBC.ZDBC_Decode(_dbcHandles[channelIndex], ptrDbcMsg, framePtr, 1, 0))
                                {
                                    var msg = (ZDBC.DBCMessage)Marshal.PtrToStructure(ptrDbcMsg, typeof(ZDBC.DBCMessage));
                                    OnDbcMessageDecoded?.Invoke(channelIndex, msg);
                                }
                            }
                        }
                        currentTurnHasData = true;
                    }

                    // 2. 自动提取并解析高速 CANFD 帧
                    uint canfdNum = ZLGCAN.ZCAN_GetReceiveNum(channelHandle, 1);
                    if (canfdNum > 0)
                    {
                        uint actualRecvFd = ZLGCAN.ZCAN_ReceiveFD(channelHandle, ptrCanFDBuffer, bufferSize, 5);
                        for (int i = 0; i < actualRecvFd; i++)
                        {
                            IntPtr framePtr = IntPtr.Add(ptrCanFDBuffer, i * canfdStructSize);

                            lock (_channelLocks[channelIndex])
                            {
                                if (_isDbcLoadedArray[channelIndex] && ZDBC.ZDBC_Decode(_dbcHandles[channelIndex], ptrDbcMsg, framePtr, 1, 1))
                                {
                                    var msg = (ZDBC.DBCMessage)Marshal.PtrToStructure(ptrDbcMsg, typeof(ZDBC.DBCMessage));
                                    OnDbcMessageDecoded?.Invoke(channelIndex, msg);
                                }
                            }
                        }
                        currentTurnHasData = true;
                    }

                    if (!currentTurnHasData)
                    {
                        Thread.Sleep(2);
                    }
                }
            }
            finally
            {
                Marshal.FreeHGlobal(ptrCanBuffer);
                Marshal.FreeHGlobal(ptrCanFDBuffer);
                Marshal.FreeHGlobal(ptrDbcMsg);
            }
        }

        #endregion

        #region 4. DBC 自动打包与智能报文发送

        /// <summary>
        /// 发送一条 DBC 定义报文。
        /// </summary>
        /// <param name="通道号">通道号</param>
        /// <param name="帧ID">DBC 中定义的帧 ID</param>
        /// <param name="信号物理值字典">信号名称 → 物理值；只设置字典中包含的信号，其余信号保持 DBC 默认值</param>
        /// <param name="循环间隔毫秒">0 = 只发送一次；>0 = 按指定间隔循环发送（毫秒）</param>
        /// <param name="是否使用CANFD">1 = CANFD，0 = CAN</param>
        /// <returns>是否成功启动/发送</returns>
        public virtual bool 发送DBC定义报文(
            uint 通道号,
            uint 帧ID,
            Dictionary<string, double> 信号物理值字典,
            int 循环间隔毫秒 = 0,
            int 是否使用CANFD = 1)
        {
            if (通道号 >= _maxChannels || _channelHandles[通道号] == IntPtr.Zero) return false;
            if (!_isDbcLoadedArray[通道号]) throw new InvalidOperationException($"通道 {通道号} 的 DBC 协议未加载，无法执行打包发送指令。");
            if (循环间隔毫秒 < 0) throw new ArgumentOutOfRangeException(nameof(循环间隔毫秒), "循环间隔必须大于或等于 0。");
            if (信号物理值字典 == null || 信号物理值字典.Count == 0)
                throw new ArgumentException("信号物理值字典不能为空。", nameof(信号物理值字典));

            if (循环间隔毫秒 == 0)
            {
                // 单次发送：同步执行
                lock (_channelLocks[通道号])
                {
                    return 发送DBC定义报文单次(通道号, 帧ID, 信号物理值字典, 是否使用CANFD);
                }
            }

            // 循环发送：先停止同通道同帧 ID 的旧循环，再启动新循环
            停止循环发送(通道号, 帧ID);

            var cts = new CancellationTokenSource();
            var sendTask = Task.Run(async () =>
            {
                while (!cts.Token.IsCancellationRequested)
                {
                    if (_isClosing) break; // 关闭流程中立即退出
                    try
                    {
                        lock (_channelLocks[通道号])
                        {
                            if (_channelHandles[通道号] == IntPtr.Zero || _isClosing) break;
                            发送DBC定义报文单次(通道号, 帧ID, 信号物理值字典, 是否使用CANFD);
                        }

                        await Task.Delay(循环间隔毫秒, cts.Token);
                    }
                    catch (OperationCanceledException)
                    {
                        break;
                    }
                    catch (Exception ex)
                    {
                        Logger.LoggerHelper.Error($"[ZLGCANFD] 循环发送 DBC 报文失败: {ex.Message}");
                        break;
                    }
                }

                // 清理：仅当字典中存的仍然是本任务创建的 CTS 时才移除，避免误删新任务的 CTS
                if (_cyclicSenders.TryGetValue((通道号, 帧ID), out var current) && ReferenceEquals(current.Cts, cts))
                {
                    _cyclicSenders.TryRemove((通道号, 帧ID), out _);
                }
                cts.Dispose();
            }, cts.Token);

            _cyclicSenders[(通道号, 帧ID)] = (cts, sendTask);

            return true;
        }

        /// <summary>
        /// 停止指定通道、指定帧 ID 的循环发送。
        /// </summary>
        public virtual void 停止循环发送(uint 通道号, uint 帧ID)
        {
            if (_cyclicSenders.TryRemove((通道号, 帧ID), out var entry))
            {
                entry.Cts.Cancel();
                // 不在这里 Dispose，由 Task 的清理代码负责释放，避免 Task 仍在使用已释放的 Token
            }
        }

        /// <summary>
        /// 停止所有 DBC 循环发送任务。
        /// </summary>
        public virtual void 停止所有循环发送()
        {
            var entries = _cyclicSenders.ToArray();

            // 1. 取消所有 CTS（不 Dispose，由 Task 清理代码负责）
            foreach (var kvp in entries)
            {
                kvp.Value.Cts.Cancel();
            }

            // 2. 等待所有循环发送 Task 退出（最多 3 秒）
            var tasks = new List<Task>();
            foreach (var kvp in entries)
            {
                if (!kvp.Value.SendTask.IsCompleted)
                    tasks.Add(kvp.Value.SendTask);
            }
            if (tasks.Count > 0)
            {
                try
                {
                    Task.WaitAll(tasks.ToArray(), TimeSpan.FromSeconds(3));
                }
                catch { /* 忽略等待异常 */ }
            }

            _cyclicSenders.Clear();
        }

        /// <summary>
        /// 清除指定通道、指定帧 ID 的信号覆盖值，恢复为 DBC 初始值。
        /// </summary>
        public virtual void 清除信号覆盖(uint 通道号, uint 帧ID)
        {
            if (_signalOverrides.TryRemove((通道号, 帧ID), out var dict))
            {
                lock (dict) dict.Clear();
            }
        }

        /// <summary>
        /// 清除指定通道所有帧的信号覆盖值。
        /// </summary>
        public virtual void 清除通道信号覆盖(uint 通道号)
        {
            foreach (var key in _signalOverrides.Keys)
            {
                if (key.通道号 == 通道号 && _signalOverrides.TryRemove(key, out var dict))
                {
                    lock (dict) dict.Clear();
                }
            }
        }



        /// <summary>
        /// 单次发送 DBC 报文（调用方已持有通道锁）。
        /// </summary>
        private bool 发送DBC定义报文单次(uint 通道号, uint 帧ID, Dictionary<string, double> 信号物理值字典, int 是否使用CANFD)
        {
            uint chDbcHandle = _dbcHandles[通道号];

            IntPtr ptrDbcMsg = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(ZDBC.DBCMessage)));
            IntPtr ptrCount = Marshal.AllocHGlobal(sizeof(uint));
            Marshal.WriteInt32(ptrCount, 1);

            try
            {
                if (!ZDBC.ZDBC_GetMessageById(chDbcHandle, 帧ID, ptrDbcMsg)) return false;
                var msg = (ZDBC.DBCMessage)Marshal.PtrToStructure(ptrDbcMsg, typeof(ZDBC.DBCMessage));

                // 根据传入的物理值设置对应信号的原始值
                for (int i = 0; i < msg.nSignalCount; i++)
                {
                    var signal = msg.vSignals[i];
                    string signalName = Encoding.Default.GetString(signal.strName).TrimEnd('\0');
                    if (信号物理值字典.TryGetValue(signalName, out double physicalValue))
                    {
                        signal.nRawvalue = 物理值转原始值(signal, physicalValue);
                        msg.vSignals[i] = signal;
                    }
                }

                Marshal.StructureToPtr(msg, ptrDbcMsg, true);

                if (是否使用CANFD == 0)
                {
                    IntPtr ptrCanFrame = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(ZLGCAN.can_frame)));
                    try
                    {
                        if (!ZDBC.ZDBC_Encode(chDbcHandle, ptrCanFrame, ptrCount, ptrDbcMsg, 0)) return false;

                        ZLGCAN.can_frame canFrame = (ZLGCAN.can_frame)Marshal.PtrToStructure(ptrCanFrame, typeof(ZLGCAN.can_frame));
                        canFrame.__pad |= 0x20;

                        ZLGCAN.ZCAN_Transmit_Data txData = new ZLGCAN.ZCAN_Transmit_Data { frame = canFrame, transmit_type = 2 };
                        IntPtr pTx = Marshal.AllocHGlobal(Marshal.SizeOf(txData));
                        try
                        {
                            Marshal.StructureToPtr(txData, pTx, true);
                            return ZLGCAN.ZCAN_Transmit(_channelHandles[通道号], pTx, 1) == 1;
                        }
                        finally
                        {
                            Marshal.FreeHGlobal(pTx);
                        }
                    }
                    finally
                    {
                        Marshal.FreeHGlobal(ptrCanFrame);
                    }
                }
                else
                {
                    IntPtr ptrCanFDFrame = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(ZLGCAN.canfd_frame)));
                    try
                    {
                        if (!ZDBC.ZDBC_Encode(chDbcHandle, ptrCanFDFrame, ptrCount, ptrDbcMsg, 1)) return false;

                        ZLGCAN.canfd_frame canfdFrame = (ZLGCAN.canfd_frame)Marshal.PtrToStructure(ptrCanFDFrame, typeof(ZLGCAN.canfd_frame));
                        canfdFrame.flags |= 0x20;

                        ZLGCAN.ZCAN_TransmitFD_Data txFdData = new ZLGCAN.ZCAN_TransmitFD_Data { frame = canfdFrame, transmit_type = 2 };
                        IntPtr pTxFd = Marshal.AllocHGlobal(Marshal.SizeOf(txFdData));
                        try
                        {
                            Marshal.StructureToPtr(txFdData, pTxFd, true);
                            return ZLGCAN.ZCAN_TransmitFD(_channelHandles[通道号], pTxFd, 1) == 1;
                        }
                        finally
                        {
                            Marshal.FreeHGlobal(pTxFd);
                        }
                    }
                    finally
                    {
                        Marshal.FreeHGlobal(ptrCanFDFrame);
                    }
                }
            }
            finally
            {
                Marshal.FreeHGlobal(ptrDbcMsg);
                Marshal.FreeHGlobal(ptrCount);
            }
        }

        /// <summary>
        /// 不依赖通道锁的物理值到原始值转换。
        /// </summary>
        private static ulong 物理值转原始值(ZDBC.DBCSignal 信号定义, double 实际物理值)
        {
            IntPtr pSignal = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(ZDBC.DBCSignal)));
            IntPtr pValue = Marshal.AllocHGlobal(sizeof(double));
            try
            {
                Marshal.StructureToPtr(信号定义, pSignal, true);
                Marshal.StructureToPtr(实际物理值, pValue, true);
                return ZDBC.ZDBC_CalcRawValue(pSignal, pValue);
            }
            finally
            {
                Marshal.FreeHGlobal(pSignal);
                Marshal.FreeHGlobal(pValue);
            }
        }

        #endregion

        #region 4.1 报文设置与发送 (支持智能进制转换)
        /// <summary>
        /// 设置并发送指定信号值（帧 ID 支持 string 兼容模式）。
        /// 其余未指定信号使用 DBC 中定义的初始值填充，避免总线数据被意外清零。
        /// </summary>
        /// <param name="通道号">CAN/CANFD 通道索引</param>
        /// <param name="帧IDStr">对应报文的帧 ID（可以是 "26"、"0x1A"、"1A"）</param>
        /// <param name="信号名称">DBC 中定义的英文信号名称（不区分大小写）</param>
        /// <param name="物理值">要写入的实际物理数值</param>
        /// <param name="循环发送间隔毫秒">0 = 单次发送；>0 = 周期循环发送（单位毫秒）</param>
        /// <returns>操作是否成功</returns>
        public virtual bool 设置报文(uint 通道号, string 帧IDStr, string 信号名称, double 物理值, int 循环发送间隔毫秒 = 0, bool 直接发送 = false)
        {
            if (!TryParseFrameId(帧IDStr, out uint 帧ID))
            {
                Console.WriteLine($"[ZLGCANFD] 设置报文失败: 无法解析的帧 ID '{帧IDStr}'");
                return false;
            }

            if (通道号 >= _maxChannels || _channelHandles[通道号] == IntPtr.Zero) return false;
            if (!_isDbcLoadedArray[通道号]) return false;
            if (string.IsNullOrWhiteSpace(信号名称)) return false;

            // 将本次设置的信号值写入持久化覆盖表（累积，不会丢失之前设置的值）
            var overrides = _signalOverrides.GetOrAdd((通道号, 帧ID), _ => new Dictionary<string, double>(StringComparer.OrdinalIgnoreCase));
            lock (overrides)
            {
                overrides[信号名称] = 物理值;
            }

            // 构建发送字典：DBC 初始值 + 持久化覆盖表（已包含本次设置）
            var merged = 构建报文发送字典(通道号, 帧ID);

            if (直接发送) return 发送DBC定义报文(通道号, 帧ID, merged, 循环发送间隔毫秒);
            else return true;
        }

        /// <summary>
        /// 发送报文：以 DBC 中所有信号的初始值作为默认值发送（帧 ID 支持 string 兼容模式）。
        /// 如果之前调用 设置报文 保存过覆盖值，则会优先使用覆盖值。
        /// </summary>
        /// <param name="通道号">CAN/CANFD 通道索引</param>
        /// <param name="帧IDStr">DBC 中定义的帧 ID（可以是 "26"、"0x1A"、"1A"）</param>
        /// <param name="循环发送间隔毫秒">0 = 单次发送；>0 = 周期循环发送（毫秒）</param>
        /// <param name="是否使用CANFD">1 = 以 CANFD 格式发送；0 = 经典 CAN 格式</param>
        public virtual bool 发送报文(uint 通道号, string 帧IDStr, int 循环发送间隔毫秒 = 0, int 是否使用CANFD = 1)
        {
            if (!TryParseFrameId(帧IDStr, out uint 帧ID))
            {
                Console.WriteLine($"[ZLGCANFD] 发送报文失败: 无法解析的帧 ID '{帧IDStr}'");
                return false;
            }

            if (通道号 >= _maxChannels || _channelHandles[通道号] == IntPtr.Zero) return false;
            if (!_isDbcLoadedArray[通道号]) return false;
            if (循环发送间隔毫秒 < 0) throw new ArgumentOutOfRangeException(nameof(循环发送间隔毫秒));

            var merged = 构建报文发送字典(通道号, 帧ID);
            return 发送DBC定义报文(通道号, 帧ID, merged, 循环发送间隔毫秒, 是否使用CANFD);
        }

        /// <summary>
        /// 发送自定义报文（原始字节，帧 ID 支持 string 兼容模式）。
        /// </summary>
        /// <param name="通道号">CAN/CANFD 通道索引</param>
        /// <param name="帧IDStr">帧 ID（可以是 "26"、"0x1A"、"1A"）；扩展帧会自动置位 0x80000000</param>
        /// <param name="原始数据">原始帧数据</param>
        /// <param name="dlcLength">数据长度；CANFD 仅允许 0-8,12,16,20,24,32,48,64</param>
        /// <param name="是否是扩展帧">是否为 29 位扩展帧</param>
        /// <param name="是否是CANFD">true = CANFD；false = 经典 CAN</param>
        /// <param name="开启波特率加速BRS">CANFD 是否开启波特率加速</param>
        public virtual bool 发送自定义报文(
            uint 通道号,
            string 帧IDStr,
            byte[] 原始数据,
            byte dlcLength,
            bool 是否是扩展帧 = false,
            bool 是否是CANFD = true,
            bool 开启波特率加速BRS = true)
        {
            if (!TryParseFrameId(帧IDStr, out uint 帧ID))
            {
                Console.WriteLine($"[ZLGCANFD] 发送自定义报文失败: 无法解析的帧 ID '{帧IDStr}'");
                return false;
            }

            if (通道号 >= _maxChannels || _channelHandles[通道号] == IntPtr.Zero) return false;
            if (原始数据 == null) return false;

            // 扩展帧需要把最高位标志位置起来
            uint canId = 帧ID & 0x7FFFFFFF;
            if (是否是扩展帧) canId |= 0x80000000;

            lock (_channelLocks[通道号])
            {
                if (是否是CANFD)
                {
                    // CANFD 有效 DLC 校验
                    byte validFdDlc = 校验CANFD的Dlc(dlcLength);

                    ZLGCAN.canfd_frame fdFrame = new ZLGCAN.canfd_frame
                    {
                        can_id = canId,
                        len = validFdDlc,
                        flags = (byte)((是否是扩展帧 ? 0x01 : 0x00) | (开启波特率加速BRS ? 0x02 : 0x00) | 0x20), // 0x20 本地回显
                        data = new byte[64]
                    };
                    Array.Copy(原始数据, 0, fdFrame.data, 0, Math.Min(原始数据.Length, 64));

                    ZLGCAN.ZCAN_TransmitFD_Data txFdData = new ZLGCAN.ZCAN_TransmitFD_Data { frame = fdFrame, transmit_type = 2 };
                    IntPtr pTxFd = Marshal.AllocHGlobal(Marshal.SizeOf(txFdData));
                    try
                    {
                        Marshal.StructureToPtr(txFdData, pTxFd, true);
                        return ZLGCAN.ZCAN_TransmitFD(_channelHandles[通道号], pTxFd, 1) == 1;
                    }
                    finally { Marshal.FreeHGlobal(pTxFd); }
                }
                else
                {
                    ZLGCAN.can_frame standardFrame = new ZLGCAN.can_frame
                    {
                        can_id = canId,
                        can_dlc = dlcLength > 8 ? (byte)8 : dlcLength,
                        __pad = 0x20, // 发送回显
                        data = new byte[8]
                    };
                    Array.Copy(原始数据, 0, standardFrame.data, 0, Math.Min(原始数据.Length, 8));

                    ZLGCAN.ZCAN_Transmit_Data txData = new ZLGCAN.ZCAN_Transmit_Data { frame = standardFrame, transmit_type = 2 };
                    IntPtr pTx = Marshal.AllocHGlobal(Marshal.SizeOf(txData));
                    try
                    {
                        Marshal.StructureToPtr(txData, pTx, true);
                        return ZLGCAN.ZCAN_Transmit(_channelHandles[通道号], pTx, 1) == 1;
                    }
                    finally { Marshal.FreeHGlobal(pTx); }
                }
            }
        }

        /// <summary>
        /// 直接发送 8 字节原始报文（经典 CAN 或 CANFD 均可）。
        /// 无需加载 DBC，适合手动构造简单报文。
        /// </summary>
        /// <param name="通道号">通道号（0 ~ MaxChannels-1）</param>
        /// <param name="帧ID">帧 ID（标准 11 位，扩展帧自动置位 0x80000000）</param>
        /// <param name="data">原始数据；超过 8 字节会自动截断，不足 8 字节自动补零</param>
        /// <param name="是否是扩展帧">是否为 29 位扩展帧</param>
        /// <param name="是否是CANFD">true = CANFD 格式；false = 经典 CAN 格式</param>
        /// <param name="开启波特率加速BRS">CANFD 是否开启波特率加速（经典 CAN 忽略此参数）</param>
        /// <returns>是否发送成功</returns>
        public virtual bool 发送原始报文(
            uint 通道号,
            uint 帧ID,
            byte[] data,
            bool 是否是扩展帧 = false,
            bool 是否是CANFD = true,
            bool 开启波特率加速BRS = true)
        {
            if (通道号 >= _maxChannels || _channelHandles[通道号] == IntPtr.Zero) return false;

            byte[] buffer = new byte[8];
            if (data != null)
            {
                Array.Copy(data, 0, buffer, 0, Math.Min(data.Length, 8));
            }

            uint canId = 帧ID & 0x7FFFFFFF;
            if (是否是扩展帧) canId |= 0x80000000;

            lock (_channelLocks[通道号])
            {
                if (是否是CANFD)
                {
                    ZLGCAN.canfd_frame fdFrame = new ZLGCAN.canfd_frame
                    {
                        can_id = canId,
                        len = 8,
                        flags = (byte)((是否是扩展帧 ? 0x01 : 0x00) | (开启波特率加速BRS ? 0x02 : 0x00) | 0x20),
                        data = new byte[64]
                    };
                    Array.Copy(buffer, 0, fdFrame.data, 0, 8);

                    ZLGCAN.ZCAN_TransmitFD_Data txFdData = new ZLGCAN.ZCAN_TransmitFD_Data { frame = fdFrame, transmit_type = 2 };
                    IntPtr pTxFd = Marshal.AllocHGlobal(Marshal.SizeOf(txFdData));
                    try
                    {
                        Marshal.StructureToPtr(txFdData, pTxFd, true);
                        return ZLGCAN.ZCAN_TransmitFD(_channelHandles[通道号], pTxFd, 1) == 1;
                    }
                    finally { Marshal.FreeHGlobal(pTxFd); }
                }
                else
                {
                    ZLGCAN.can_frame standardFrame = new ZLGCAN.can_frame
                    {
                        can_id = canId,
                        can_dlc = 8,
                        __pad = 0x20,
                        data = new byte[8]
                    };
                    Array.Copy(buffer, 0, standardFrame.data, 0, 8);

                    ZLGCAN.ZCAN_Transmit_Data txData = new ZLGCAN.ZCAN_Transmit_Data { frame = standardFrame, transmit_type = 2 };
                    IntPtr pTx = Marshal.AllocHGlobal(Marshal.SizeOf(txData));
                    try
                    {
                        Marshal.StructureToPtr(txData, pTx, true);
                        return ZLGCAN.ZCAN_Transmit(_channelHandles[通道号], pTx, 1) == 1;
                    }
                    finally { Marshal.FreeHGlobal(pTx); }
                }
            }
        }

        /// <summary>
        /// 构建发送用信号字典：DBC 初始值 + 额外覆盖。
        /// 调用方需自行保证通道已初始化且 DBC 已加载。
        /// </summary>
        private Dictionary<string, double> 构建报文发送字典(uint 通道号, uint 帧ID, Dictionary<string, double>? 额外覆盖 = null)
        {
            uint chDbcHandle = _dbcHandles[通道号];
            IntPtr ptrDbcMsg = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(ZDBC.DBCMessage)));
            try
            {
                lock (_channelLocks[通道号])
                {
                    if (!ZDBC.ZDBC_GetMessageById(chDbcHandle, 帧ID, ptrDbcMsg))
                        return new Dictionary<string, double>(StringComparer.OrdinalIgnoreCase);

                    var msg = (ZDBC.DBCMessage)Marshal.PtrToStructure(ptrDbcMsg, typeof(ZDBC.DBCMessage));
                    var dict = new Dictionary<string, double>(StringComparer.OrdinalIgnoreCase);

                    // 1. DBC 初始值打底
                    for (int i = 0; i < msg.nSignalCount; i++)
                    {
                        var signal = msg.vSignals[i];
                        string signalName = Encoding.Default.GetString(signal.strName).TrimEnd('\0');
                        if (!string.IsNullOrEmpty(signalName) && signal.initialValueValid != 0)
                        {
                            dict[signalName] = signal.initialValue;
                        }
                    }

                    // 2. 叠加持久化覆盖表（之前 设置报文 累积的值）
                    if (_signalOverrides.TryGetValue((通道号, 帧ID), out var persisted))
                    {
                        lock (persisted)
                        {
                            foreach (var kvp in persisted)
                                dict[kvp.Key] = kvp.Value;
                        }
                    }

                    // 3. 叠加本次调用传入的额外覆盖（优先级最高）
                    if (额外覆盖 != null)
                    {
                        foreach (var kvp in 额外覆盖)
                        {
                            dict[kvp.Key] = kvp.Value;
                        }
                    }

                    return dict;
                }
            }
            finally
            {

                Marshal.FreeHGlobal(ptrDbcMsg);
            }
        }

        /// <summary>
        /// CANFD 有效 DLC 校验，非法值自动就近取到下一个合法 DLC。
        /// </summary>
        private static byte 校验CANFD的Dlc(byte dlc)
        {
            if (dlc <= 8) return dlc;
            if (dlc <= 12) return 12;
            if (dlc <= 16) return 16;
            if (dlc <= 20) return 20;
            if (dlc <= 24) return 24;
            if (dlc <= 32) return 32;
            if (dlc <= 48) return 48;
            return 64;
        }

        #endregion

        #region 5. 辅助工具子系统

        /// <summary>
        /// 计算物理值也需要传入对应通道，使用通道专属的DBC句柄进行计算
        /// </summary>
        /// <summary>
        /// 智能解析帧 ID 字符串，兼容 10 进制、16 进制（如 "0x1A", "1A", "26"）
        /// </summary>
        /// <param name="idStr">输入的帧 ID 字符串</param>
        /// <param name="frameId">解析成功后的 uint 帧 ID</param>
        /// <returns>是否解析成功</returns>
        [Browsable(false)]
        public static bool TryParseFrameId(string idStr, out uint frameId)
        {
            frameId = 0;
            if (string.IsNullOrWhiteSpace(idStr)) return false;

            idStr = idStr.Trim();

            try
            {
                // 1. 处理带 0x 或 0X 的标准 16 进制
                if (idStr.StartsWith("0x", StringComparison.OrdinalIgnoreCase))
                {
                    frameId = Convert.ToUInt32(idStr.Substring(2), 16);
                    return true;
                }

                // 2. 尝试当做纯 10 进制解析（如 "26"）
                if (uint.TryParse(idStr, out frameId))
                {
                    return true;
                }

                // 3. 如果不是纯数字，但符合 16 进制特征（如 "1A"、"ABC"），尝试按 16 进制解析
                // 使用 System.Globalization.NumberStyles.HexNumber
                if (uint.TryParse(idStr, System.Globalization.NumberStyles.HexNumber, null, out frameId))
                {
                    return true;
                }
            }
            catch
            {
                return false;
            }

            return false;
        }

        [Browsable(false)]
        public ulong 物理值转原始寄存器值(uint 通道号, ZDBC.DBCSignal 信号定义, double 实际物理值)
        {
            if (通道号 >= _maxChannels) return 0;

            IntPtr pSignal = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(ZDBC.DBCSignal)));
            IntPtr pValue = Marshal.AllocHGlobal(sizeof(double));

            try
            {
                Marshal.StructureToPtr(信号定义, pSignal, true);
                Marshal.StructureToPtr(实际物理值, pValue, true);
                lock (_channelLocks[通道号])
                {
                    return ZDBC.ZDBC_CalcRawValue(pSignal, pValue);
                }
            }
            finally
            {
                Marshal.FreeHGlobal(pSignal);
                Marshal.FreeHGlobal(pValue);
            }
        }

        #endregion

        [Browsable(false)]
        public void Dispose()
        {
            关闭CAN卡设备();
        }
    }
}