using Common.Attributes; using System.Collections.Concurrent; using System.Collections.Generic; using System.ComponentModel; using System.Diagnostics; using System.IO; using System.Runtime.InteropServices; using System.Text; using System.Text.Json; using TSMaster; namespace TSMasterFlexRay { [ACPCommand] public class FlexRay : IDisposable { #region 静态成员 public static event Action? ConnectEvent; public static event Action? DisConnectEvent; public static bool ConnectFlag { get; set; } = false; /// /// 实时接收到的 FlexRay 报文缓存(按 SlotId 索引,保留最新帧)。 /// 供界面轮询读取。 /// public static ConcurrentDictionary RealTimeMessages { get; } = new(); #endregion #region 实例字段与属性 /// 设备类型号(TSMaster 中作为配置参考保留) public uint DeviceType { get; } /// 设备索引 public uint DeviceIndex { get; } /// 最大通道数 public int MaxChannels { get; } /// 工程路径(FlexRay 需通过 TSMaster 工程文件加载 Cluster 配置) public string ProjectPath { get; } /// 数据库解析器 public FlexRayDBParse DBParser => FlexRayDBParse.Instance; /// /// FlexRay 帧解码事件:当接收到帧并通过数据库解码后触发。 /// 参数:(通道号, 解码后的报文信息) /// public event Action? OnFrameDecoded; private bool _disposed; private bool _isOpened; private TFlexRayQueueEvent_Win32? _instanceListener; private TFlexRayQueueEvent_Win32? _preTxListener; #endregion #region 构造函数 /// 默认构造函数(使用默认工程路径) public FlexRay() : this(43, 0, 2, "") { } /// /// 带配置参数的构造函数。 /// /// 设备类型号 /// 设备索引 /// 最大通道数 /// TSMaster 工程路径(FlexRay 必须加载工程) public FlexRay(uint deviceType, uint deviceIndex, int maxChannels, string projectPath) { DeviceType = deviceType; DeviceIndex = deviceIndex; MaxChannels = maxChannels; ProjectPath = projectPath; } #endregion #region 实例方法 — 设备管理 /// /// 打开设备:加载工程 → 连接 → 启动 RBS → 注册监听。 /// FlexRay 的硬件配置(波特率、集群参数等)由 TSMaster 工程统一管理, /// 代码中无法直接设置,需通过 ShowChannelMappingWindow 或工程本身配置。 /// /// true 表示成功 public bool 打开设备() { if (_isOpened) return true; if (ConnectFlag) { _isOpened = true; return true; } try { // 1. 通过工程文件初始化(FlexRay 必须依赖工程) var re = Init("TSMasterFlexRay", ProjectPath); if (re != 0) { Debug.WriteLine($"TSMaster FlexRay 工程加载失败,错误代码:{re}"); return false; } // 2. 使能接收 FIFO(可选,用于批量拉取模式) TsMasterApi.tsfifo_enable_receive_fifo(); // 3. 连接硬件 re = Connect(); if (re != 0) { Debug.WriteLine($"FlexRay 连接失败,错误代码:{re}"); return false; } // 4. 注册接收监听 _instanceListener = new TFlexRayQueueEvent_Win32(OnFlexRayReceived); RegisterListener(_instanceListener); _isOpened = true; return true; } catch (Exception ex) { Debug.WriteLine($"打开 FlexRay 设备异常:{ex.Message}"); return false; } } /// /// 关闭 FlexRay 设备:注销监听 → 停止 RBS → 断开连接。 /// public void 关闭FlexRay设备() { if (!_isOpened && !ConnectFlag) return; try { if (_preTxListener != null) { UnRegisterPreTxListener(_preTxListener); _preTxListener = null; } if (_instanceListener != null) { UnRegisterListener(_instanceListener); _instanceListener = null; } DisConnect(); } catch (Exception ex) { Debug.WriteLine($"关闭FlexRay设备异常:{ex.Message}"); } finally { _isOpened = false; } } /// /// FlexRay 接收回调:接收原始帧 → 缓存 → 触发 OnFrameDecoded 事件。 /// private void OnFlexRayReceived(ref int AObj, ref TLIBFlexRay AData) { if (_disposed) return; // 始终缓存最新帧(按 SlotId) RealTimeMessages[AData.FSlotId] = AData; if (OnFrameDecoded == null) return; try { var decoded = new FlexRayDBMessage { nSlotId = AData.FSlotId, nCycleNumber = AData.FCycleNumber, nChannelMask = AData.FChannelMask, nDataLength = AData.FActualPayloadLength, Data = new byte[AData.FActualPayloadLength] }; Array.Copy(AData.FData, decoded.Data, AData.FActualPayloadLength); OnFrameDecoded?.Invoke(AData.FIdxChn, decoded); } catch (Exception ex) { Debug.WriteLine($"FlexRay 帧解码异常:{ex.Message}"); } } #endregion #region IDisposable public void Dispose() { if (_disposed) return; _disposed = true; 关闭FlexRay设备(); GC.SuppressFinalize(this); } #endregion /// /// 初始化 TSMaster FlexRay(必须加载工程文件) /// /// 应用名 /// 工程路径,为空则仅初始化库 /// [Browsable(false)] public static int Init(string ProjectName, string? filePath = null) { if (string.IsNullOrEmpty(filePath)) { return TsMasterApi.initialize_lib_tsmaster(ProjectName); } else { return TsMasterApi.initialize_lib_tsmaster_with_project(ProjectName, Path.GetFullPath(filePath)); } } /// /// 释放 TSMaster /// [Browsable(false)] public static void Release() { TsMasterApi.finalize_lib_tsmaster(); } [Browsable(false)] public static int RegisterListener(TFlexRayQueueEvent_Win32 listenEvent) { int obj = 0; var re = TsMasterApi.tsapp_register_event_flexray(ref obj, listenEvent); Debug.Assert(re == 0); return re; } [Browsable(false)] public static int UnRegisterListener(TFlexRayQueueEvent_Win32 listenEvent) { int obj = 0; var re = TsMasterApi.tsapp_unregister_event_flexray(ref obj, listenEvent); Debug.Assert(re == 0); return re; } /// /// 注册发送前回调(FlexRay 特有,可用于发送前修改帧内容) /// /// /// [Browsable(false)] public static int RegisterPreTxListener(TFlexRayQueueEvent_Win32 preTxEvent) { int obj = 0; return TsMasterApi.tsapp_register_pretx_event_flexray(ref obj, preTxEvent); } [Browsable(false)] public static int UnRegisterPreTxListener(TFlexRayQueueEvent_Win32 preTxEvent) { int obj = 0; return TsMasterApi.tsapp_unregister_pretx_event_flexray(ref obj, preTxEvent); } /// /// 连接(含 RBS 启动) /// /// public static int Connect() { var re = TsMasterApi.tsapp_connect(); if (re == 0) { // FlexRay RBS 需先 enable 再 start TsMasterApi.tscom_flexray_rbs_enable(true); re = TsMasterApi.tscom_flexray_rbs_start(); if (re == 0) { ConnectFlag = true; Task.Run(() => ConnectEvent?.Invoke()); } else { Debug.WriteLine($"FlexRay RBS 启动失败,错误代码:{re}"); } } else { Debug.WriteLine($"FlexRay 连接失败,错误代码:{re}"); } return re; } /// /// 断开(含 RBS 停止) /// /// public static int DisConnect() { var re = TsMasterApi.tsapp_disconnect(); if (re == 0) { TsMasterApi.tscom_flexray_rbs_enable(false); TsMasterApi.tscom_flexray_rbs_stop(); ConnectFlag = false; Task.Run(() => DisConnectEvent?.Invoke()); } else { Debug.WriteLine($"断开 FlexRay 连接失败,错误代码:{re}"); } return re; } /// /// 获取工程中 FlexRay 数据库数量 /// /// public static int GetDBCount() { int count = 0; TsMasterApi.tsdb_get_flexray_db_count(ref count); return count; } /// /// 弹出通道映射窗口(FlexRay 硬件配置推荐通过此窗口完成) /// /// /// [Browsable(false)] public static int ShowChannelMappingWindow(bool isWait = false) { return TsMasterApi.tsapp_show_tsmaster_window("Hardware", isWait); } /// /// 发送一帧 FlexRay(异步) /// /// /// [Browsable(false)] public static int SendMsg(TLIBFlexRay msg) { return tsapp_transmit_flexray_async(ref msg); } /// /// 发送一帧 FlexRay(按参数构造) /// /// 通道索引(0-based) /// 通道掩码:1=A, 2=B, 3=AB /// 有效负载长度 /// 基准循环号 /// 时隙号 /// 数据数组 /// public static int SendMsg(byte AIdxChn, byte AChannelMask, byte ADLC, byte ABaseCycle, ushort ASlotId, byte[] AData) { var send = new TLIBFlexRay(AIdxChn, AChannelMask, ADLC, ABaseCycle, ASlotId, AData); return tsapp_transmit_flexray_async(ref send); } /// /// 通过 FIFO 批量拉取已接收的 FlexRay 消息 /// /// 缓冲区大小 /// 通道号(0-based) /// true=TX, false=RX /// public static TLIBFlexRay[] ReceiveMsgs(ref int bufferSize, byte AChn, bool ATxRx) { TLIBFlexRay[] buffer = new TLIBFlexRay[bufferSize]; TsMasterApi.tsfifo_receive_flexray_msgs_list(ref buffer, ref bufferSize, AChn, ATxRx); return buffer; } /// /// 通过 RBS 地址获取信号值(地址格式:通道/Cluster/ECU/Frame/Signal) /// /// /// public static double GetSignalValue(string address) { double value = 0; TsMasterApi.tscom_flexray_rbs_get_signal_value_by_address(address, ref value); return value; } /// /// 通过 RBS 地址设置信号值 /// /// /// /// public static int SetSignalValue(string address, double value) { TsMasterApi.tscom_flexray_rbs_set_signal_value_by_address(address, value); return 0; } /// /// 按名称激活 Cluster(RBS 仿真) /// /// 通道索引 /// true=激活 /// Cluster 名称 /// public static int ActivateCluster(int chnIdx, bool enable, string clusterName) { return TsMasterApi.tscom_flexray_rbs_activate_cluster_by_name(chnIdx, enable, clusterName, false); } /// /// 按名称激活 ECU(RBS 仿真) /// public static int ActivateECU(int chnIdx, bool enable, string clusterName, string ecuName) { return TsMasterApi.tscom_flexray_rbs_activate_ecu_by_name(chnIdx, enable, clusterName, ecuName, false); } /// /// 按名称激活 Frame(RBS 仿真) /// public static int ActivateFrame(int chnIdx, bool enable, string clusterName, string ecuName, string frameName) { return TsMasterApi.tscom_flexray_rbs_activate_frame_by_name(chnIdx, enable, clusterName, ecuName, frameName); } /// /// 开始记录日志 /// public static int StartLogging(string filePath) { return TsMasterApi.tsapp_start_logging(Path.GetFullPath(filePath)); } /// /// 结束记录日志 /// public static int StopLogging() { return TsMasterApi.tsapp_stop_logging(); } /// /// 获取错误提示 /// public static string GetErrorDescription(int errorCode) { IntPtr ADesc = IntPtr.Zero; TsMasterApi.tsapp_get_error_description(errorCode, ref ADesc); if (ADesc == IntPtr.Zero) return $"未知错误代码: {errorCode}"; string? description = Marshal.PtrToStringAnsi(ADesc); return description ?? $"未知错误代码: {errorCode}"; } // FlexRay 发送函数(TSMaster.dll 中 StdCall 导出,需手动声明) [DllImport(".\\TSMaster.dll", CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Ansi)] public static extern int tsapp_transmit_flexray_async(ref TLIBFlexRay AMsg); } }