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 TSMasterLIN { [ACPCommand] public class LIN : IDisposable { #region 静态成员 public static event Action? ConnectEvent; public static event Action? DisConnectEvent; public static bool ConnectFlag { get; set; } = false; /// /// 实时接收到的 LIN 报文缓存(按帧 ID 索引,保留最新帧)。 /// public static ConcurrentDictionary RealTimeMessages { get; } = new(); #endregion #region 实例字段与属性 /// 设备类型号 public uint DeviceType { get; } /// 设备索引 public uint DeviceIndex { get; } /// 最大通道数 public int MaxChannels { get; } /// 波特率(LIN 常用 19.2 kbps) public float BaudRate { get; } /// LIN 协议版本 public LIN_PROTOCOL Protocol { get; } /// /// LIN 帧解码事件:当接收到帧后触发。 /// 参数:(通道号, 帧信息) /// public event Action? OnLinFrameReceived; private bool _disposed; private bool _isOpened; private TLINQueueEvent_Win32? _instanceListener; #endregion #region 构造函数 /// 默认构造函数(1 通道、19.2 kbps、LIN 2.1) public LIN() : this(43, 0, 1, 19.2f, LIN_PROTOCOL.LIN_PROTOCOL_21) { } /// /// 带配置参数的构造函数。 /// /// 设备类型号 /// 设备索引 /// 最大通道数 /// 波特率(常用 19.2) /// LIN 协议版本 public LIN(uint deviceType, uint deviceIndex, int maxChannels, float baudRate, LIN_PROTOCOL protocol) { DeviceType = deviceType; DeviceIndex = deviceIndex; MaxChannels = maxChannels; BaudRate = baudRate; Protocol = protocol; } #endregion #region 实例方法 — 设备管理 /// /// 打开设备:初始化 TSMaster 库 → 设置通道数 → 配置波特率与协议 → 连接 → 注册监听。 /// /// true 表示成功 public bool 打开设备() { if (_isOpened) return true; if (ConnectFlag) { _isOpened = true; return true; } try { // 1. 初始化 TSMaster 库 var re = Init("TSMasterLIN"); if (re != 0) { Debug.WriteLine($"TSMaster LIN 初始化失败,错误代码:{re}"); return false; } // 2. 设置通道数 TsMasterApi.tsapp_set_lin_channel_count(MaxChannels); // 3. 配置各通道波特率与协议 for (int ch = 0; ch < MaxChannels; ch++) { TsMasterApi.tsapp_configure_baudrate_lin(ch, BaudRate, (int)Protocol); } // 4. 连接硬件 re = Connect(); if (re != 0) { Debug.WriteLine($"LIN 连接失败,错误代码:{re}"); return false; } // 5. 注册接收监听 _instanceListener = new TLINQueueEvent_Win32(OnLinReceived); RegisterListener(_instanceListener); _isOpened = true; return true; } catch (Exception ex) { Debug.WriteLine($"打开 LIN 设备异常:{ex.Message}"); return false; } } /// /// 关闭 LIN 设备:注销监听 → 断开连接。 /// public void 关闭LIN设备() { if (!_isOpened && !ConnectFlag) return; try { if (_instanceListener != null) { UnRegisterListener(_instanceListener); _instanceListener = null; } DisConnect(); } catch (Exception ex) { Debug.WriteLine($"关闭LIN设备异常:{ex.Message}"); } finally { _isOpened = false; } } /// /// LIN 接收回调:缓存最新帧 → 触发 OnLinFrameReceived 事件。 /// private void OnLinReceived(ref int AObj, ref TLIBLIN AData) { if (_disposed) return; // 始终缓存最新报文(按 ID) RealTimeMessages[AData.FIdentifier] = AData; OnLinFrameReceived?.Invoke(AData.FIdxChn, AData); } #endregion #region IDisposable public void Dispose() { if (_disposed) return; _disposed = true; 关闭LIN设备(); GC.SuppressFinalize(this); } #endregion /// /// 初始化 TSMasterLIN /// /// /// 工程路径,为空则仅初始化库 /// [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(); } public static int obj = 0; public static TLINQueueEvent_Win32? listener; [Browsable(false)] public static int RegisterListener(TLINQueueEvent_Win32 listenEvent) { listener = listenEvent; var re = TsMasterApi.tsapp_register_event_lin(ref obj, listener); Debug.Assert(re == 0); return re; } [Browsable(false)] public static int UnRegisterListener(TLINQueueEvent_Win32? listenEvent = null) { if (listenEvent is not null) { listener = listenEvent; } var re = TsMasterApi.tsapp_unregister_event_lin(ref obj, listener); Debug.Assert(re == 0); return re; } /// /// 连接 /// /// public static int Connect() { var re = TsMasterApi.tsapp_connect(); if (re == 0) { ConnectFlag = true; Task.Run(() => ConnectEvent?.Invoke()); } else { Debug.WriteLine($"LIN 连接失败,错误代码:{re}"); } return re; } /// /// 断开 /// /// public static int DisConnect() { var re = TsMasterApi.tsapp_disconnect(); if (re == 0) { ConnectFlag = false; Task.Run(() => DisConnectEvent?.Invoke()); } else { Debug.WriteLine($"断开 LIN 连接失败,错误代码:{re}"); } return re; } /// /// 设置节点角色(LIN 特有:主节点/从节点) /// LIN 是单主多从总线,只有 Master 能发起帧头调度。 /// /// 通道号(0-based) /// 节点类型:T_MasterNode / T_SlaveNode /// public static int SetNodeType(byte channel, TLINNodeType nodeType) { return TsMasterApi.tslin_set_node_functiontype(channel, nodeType); } /// /// 设置当前通道为主节点 /// public static int SetMaster(byte channel) { return TsMasterApi.tslin_set_node_functiontype(channel, TLINNodeType.T_MasterNode); } /// /// 设置当前通道为从节点 /// public static int SetSlave(byte channel) { return TsMasterApi.tslin_set_node_functiontype(channel, TLINNodeType.T_SlaveNode); } /// /// 弹出通道映射窗口 /// [Browsable(false)] public static int ShowChannelMappingWindow(bool isWait = false) { return TsMasterApi.tsapp_show_tsmaster_window("Hardware", isWait); } /// /// 发送一帧 LIN(异步)。 /// LIN 发送语义:Master 发帧头(Header)后由指定节点应答数据。 /// /// /// [Browsable(false)] public static int SendMsg(TLIBLIN msg) { return TsMasterApi.tsapp_transmit_lin_async(ref msg); } /// /// 发送一帧 LIN(按参数构造)。 /// /// 通道索引(0-based) /// 帧 ID(6 位有效) /// 数据长度(1~8 字节) /// true=Master 同时发送数据(Master 发送帧+数据);false=仅发帧头,等待从节点应答 /// public static int SendMsg(byte AIdxChn, int AID, byte ADLC, bool AIsTx) { var send = new TLIBLIN((APP_CHANNEL)AIdxChn, (byte)AID, ADLC, AIsTx); return TsMasterApi.tsapp_transmit_lin_async(ref send); } /// /// 发送一帧 LIN(携带数据)。 /// /// 通道索引 /// 帧 ID /// 数据数组(最多 8 字节) /// true=Master 发送数据;false=仅发帧头 /// public static int SendMsg(byte AIdxChn, int AID, byte[] AData, bool AIsTx = true) { byte dlc = (byte)Math.Min(AData.Length, 8); var send = new TLIBLIN((APP_CHANNEL)AIdxChn, (byte)AID, dlc, AIsTx); Array.Copy(AData, 0, send.FData, 0, dlc); return TsMasterApi.tsapp_transmit_lin_async(ref send); } /// /// 开始记录日志 /// 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}"; } } }