Flexray,Lin添加
This commit is contained in:
@@ -45,6 +45,10 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ACP", "ACP\ACP.csproj", "{C
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TSMasterCAN", "TSMasterCAN\TSMasterCAN.csproj", "{B45DC94C-2CBB-4119-8787-B52A9E7EC58B}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TSMasterFlexRay", "TSMasterFlexRay\TSMasterFlexRay.csproj", "{68B228BA-52B4-4C01-B260-235F5444ADA7}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TSMasterLIN", "TSMasterLIN\TSMasterLIN.csproj", "{75F658D1-5DC4-4638-8959-2E7A87212B1D}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
@@ -131,6 +135,14 @@ Global
|
||||
{B45DC94C-2CBB-4119-8787-B52A9E7EC58B}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{B45DC94C-2CBB-4119-8787-B52A9E7EC58B}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{B45DC94C-2CBB-4119-8787-B52A9E7EC58B}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{68B228BA-52B4-4C01-B260-235F5444ADA7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{68B228BA-52B4-4C01-B260-235F5444ADA7}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{68B228BA-52B4-4C01-B260-235F5444ADA7}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{68B228BA-52B4-4C01-B260-235F5444ADA7}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{75F658D1-5DC4-4638-8959-2E7A87212B1D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{75F658D1-5DC4-4638-8959-2E7A87212B1D}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{75F658D1-5DC4-4638-8959-2E7A87212B1D}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{75F658D1-5DC4-4638-8959-2E7A87212B1D}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
|
||||
@@ -0,0 +1,470 @@
|
||||
|
||||
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;
|
||||
|
||||
/// <summary>
|
||||
/// 实时接收到的 FlexRay 报文缓存(按 SlotId 索引,保留最新帧)。
|
||||
/// 供界面轮询读取。
|
||||
/// </summary>
|
||||
public static ConcurrentDictionary<int, TLIBFlexRay> RealTimeMessages { get; } = new();
|
||||
|
||||
#endregion
|
||||
|
||||
#region 实例字段与属性
|
||||
|
||||
/// <summary>设备类型号(TSMaster 中作为配置参考保留)</summary>
|
||||
public uint DeviceType { get; }
|
||||
/// <summary>设备索引</summary>
|
||||
public uint DeviceIndex { get; }
|
||||
/// <summary>最大通道数</summary>
|
||||
public int MaxChannels { get; }
|
||||
/// <summary>工程路径(FlexRay 需通过 TSMaster 工程文件加载 Cluster 配置)</summary>
|
||||
public string ProjectPath { get; }
|
||||
|
||||
/// <summary>数据库解析器</summary>
|
||||
public FlexRayDBParse DBParser => FlexRayDBParse.Instance;
|
||||
|
||||
/// <summary>
|
||||
/// FlexRay 帧解码事件:当接收到帧并通过数据库解码后触发。
|
||||
/// 参数:(通道号, 解码后的报文信息)
|
||||
/// </summary>
|
||||
public event Action<uint, FlexRayDBMessage>? OnFrameDecoded;
|
||||
|
||||
private bool _disposed;
|
||||
private bool _isOpened;
|
||||
private TFlexRayQueueEvent_Win32? _instanceListener;
|
||||
private TFlexRayQueueEvent_Win32? _preTxListener;
|
||||
|
||||
#endregion
|
||||
|
||||
#region 构造函数
|
||||
|
||||
/// <summary>默认构造函数(使用默认工程路径)</summary>
|
||||
public FlexRay() : this(43, 0, 2, "") { }
|
||||
|
||||
/// <summary>
|
||||
/// 带配置参数的构造函数。
|
||||
/// </summary>
|
||||
/// <param name="deviceType">设备类型号</param>
|
||||
/// <param name="deviceIndex">设备索引</param>
|
||||
/// <param name="maxChannels">最大通道数</param>
|
||||
/// <param name="projectPath">TSMaster 工程路径(FlexRay 必须加载工程)</param>
|
||||
public FlexRay(uint deviceType, uint deviceIndex, int maxChannels, string projectPath)
|
||||
{
|
||||
DeviceType = deviceType;
|
||||
DeviceIndex = deviceIndex;
|
||||
MaxChannels = maxChannels;
|
||||
ProjectPath = projectPath;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region 实例方法 — 设备管理
|
||||
|
||||
/// <summary>
|
||||
/// 打开设备:加载工程 → 连接 → 启动 RBS → 注册监听。
|
||||
/// FlexRay 的硬件配置(波特率、集群参数等)由 TSMaster 工程统一管理,
|
||||
/// 代码中无法直接设置,需通过 ShowChannelMappingWindow 或工程本身配置。
|
||||
/// </summary>
|
||||
/// <returns>true 表示成功</returns>
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 关闭 FlexRay 设备:注销监听 → 停止 RBS → 断开连接。
|
||||
/// </summary>
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// FlexRay 接收回调:接收原始帧 → 缓存 → 触发 OnFrameDecoded 事件。
|
||||
/// </summary>
|
||||
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
|
||||
|
||||
/// <summary>
|
||||
/// 初始化 TSMaster FlexRay(必须加载工程文件)
|
||||
/// </summary>
|
||||
/// <param name="ProjectName">应用名</param>
|
||||
/// <param name="filePath">工程路径,为空则仅初始化库</param>
|
||||
/// <returns></returns>
|
||||
[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));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 释放 TSMaster
|
||||
/// </summary>
|
||||
[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;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 注册发送前回调(FlexRay 特有,可用于发送前修改帧内容)
|
||||
/// </summary>
|
||||
/// <param name="preTxEvent"></param>
|
||||
/// <returns></returns>
|
||||
[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);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 连接(含 RBS 启动)
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
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;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 断开(含 RBS 停止)
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
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;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取工程中 FlexRay 数据库数量
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public static int GetDBCount()
|
||||
{
|
||||
int count = 0;
|
||||
TsMasterApi.tsdb_get_flexray_db_count(ref count);
|
||||
return count;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 弹出通道映射窗口(FlexRay 硬件配置推荐通过此窗口完成)
|
||||
/// </summary>
|
||||
/// <param name="isWait"></param>
|
||||
/// <returns></returns>
|
||||
[Browsable(false)]
|
||||
public static int ShowChannelMappingWindow(bool isWait = false)
|
||||
{
|
||||
return TsMasterApi.tsapp_show_tsmaster_window("Hardware", isWait);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 发送一帧 FlexRay(异步)
|
||||
/// </summary>
|
||||
/// <param name="msg"></param>
|
||||
/// <returns></returns>
|
||||
[Browsable(false)]
|
||||
public static int SendMsg(TLIBFlexRay msg)
|
||||
{
|
||||
return tsapp_transmit_flexray_async(ref msg);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 发送一帧 FlexRay(按参数构造)
|
||||
/// </summary>
|
||||
/// <param name="AIdxChn">通道索引(0-based)</param>
|
||||
/// <param name="AChannelMask">通道掩码:1=A, 2=B, 3=AB</param>
|
||||
/// <param name="ADLC">有效负载长度</param>
|
||||
/// <param name="ABaseCycle">基准循环号</param>
|
||||
/// <param name="ASlotId">时隙号</param>
|
||||
/// <param name="AData">数据数组</param>
|
||||
/// <returns></returns>
|
||||
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);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 通过 FIFO 批量拉取已接收的 FlexRay 消息
|
||||
/// </summary>
|
||||
/// <param name="bufferSize">缓冲区大小</param>
|
||||
/// <param name="AChn">通道号(0-based)</param>
|
||||
/// <param name="ATxRx">true=TX, false=RX</param>
|
||||
/// <returns></returns>
|
||||
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;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 通过 RBS 地址获取信号值(地址格式:通道/Cluster/ECU/Frame/Signal)
|
||||
/// </summary>
|
||||
/// <param name="address"></param>
|
||||
/// <returns></returns>
|
||||
public static double GetSignalValue(string address)
|
||||
{
|
||||
double value = 0;
|
||||
TsMasterApi.tscom_flexray_rbs_get_signal_value_by_address(address, ref value);
|
||||
return value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 通过 RBS 地址设置信号值
|
||||
/// </summary>
|
||||
/// <param name="address"></param>
|
||||
/// <param name="value"></param>
|
||||
/// <returns></returns>
|
||||
public static int SetSignalValue(string address, double value)
|
||||
{
|
||||
TsMasterApi.tscom_flexray_rbs_set_signal_value_by_address(address, value);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 按名称激活 Cluster(RBS 仿真)
|
||||
/// </summary>
|
||||
/// <param name="chnIdx">通道索引</param>
|
||||
/// <param name="enable">true=激活</param>
|
||||
/// <param name="clusterName">Cluster 名称</param>
|
||||
/// <returns></returns>
|
||||
public static int ActivateCluster(int chnIdx, bool enable, string clusterName)
|
||||
{
|
||||
return TsMasterApi.tscom_flexray_rbs_activate_cluster_by_name(chnIdx, enable, clusterName, false);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 按名称激活 ECU(RBS 仿真)
|
||||
/// </summary>
|
||||
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);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 按名称激活 Frame(RBS 仿真)
|
||||
/// </summary>
|
||||
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);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 开始记录日志
|
||||
/// </summary>
|
||||
public static int StartLogging(string filePath)
|
||||
{
|
||||
return TsMasterApi.tsapp_start_logging(Path.GetFullPath(filePath));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 结束记录日志
|
||||
/// </summary>
|
||||
public static int StopLogging()
|
||||
{
|
||||
return TsMasterApi.tsapp_stop_logging();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取错误提示
|
||||
/// </summary>
|
||||
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);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,248 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
using System.Text.Json.Serialization;
|
||||
using TSMaster;
|
||||
|
||||
namespace TSMasterFlexRay
|
||||
{
|
||||
/// <summary>
|
||||
/// FlexRay 网络(Cluster)
|
||||
/// </summary>
|
||||
public struct flexray_network
|
||||
{
|
||||
[JsonInclude]
|
||||
public string network_name;
|
||||
[JsonInclude]
|
||||
public flexray_node[] flexray_nodes;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// FlexRay 节点(ECU)
|
||||
/// </summary>
|
||||
public struct flexray_node
|
||||
{
|
||||
[JsonInclude]
|
||||
public string node_name;
|
||||
[JsonInclude]
|
||||
public flexray_message[] tx_flexray_Messages;
|
||||
[JsonInclude]
|
||||
public flexray_message[] rx_flexray_Messages;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// FlexRay 帧(Frame)
|
||||
/// </summary>
|
||||
public struct flexray_message
|
||||
{
|
||||
[JsonInclude]
|
||||
public string message_name;
|
||||
[JsonInclude]
|
||||
public int slot_id;
|
||||
[JsonInclude]
|
||||
public int channel_mask;
|
||||
[JsonInclude]
|
||||
public int base_cycle;
|
||||
[JsonInclude]
|
||||
public int rep_cycle;
|
||||
[JsonInclude]
|
||||
public bool is_startup_frame;
|
||||
[JsonInclude]
|
||||
public int dlc;
|
||||
[JsonInclude]
|
||||
public string[] signals;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// FlexRay 解码后的信号信息
|
||||
/// </summary>
|
||||
public struct FlexRaySignal
|
||||
{
|
||||
/// <summary>信号名称</summary>
|
||||
public string name;
|
||||
/// <summary>起始位</summary>
|
||||
public int start_bit;
|
||||
/// <summary>长度(bit)</summary>
|
||||
public int length;
|
||||
/// <summary>因子</summary>
|
||||
public double factor;
|
||||
/// <summary>偏移</summary>
|
||||
public double offset;
|
||||
/// <summary>初始值</summary>
|
||||
public double init_value;
|
||||
/// <summary>信号类型</summary>
|
||||
public TSignalType signal_type;
|
||||
/// <summary>字节序(true=小端)</summary>
|
||||
public bool is_intel;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// FlexRay 解码后的报文信息
|
||||
/// </summary>
|
||||
public class FlexRayDBMessage
|
||||
{
|
||||
/// <summary>时隙号</summary>
|
||||
public int nSlotId;
|
||||
/// <summary>周期号</summary>
|
||||
public int nCycleNumber;
|
||||
/// <summary>通道掩码</summary>
|
||||
public int nChannelMask;
|
||||
/// <summary>有效负载长度</summary>
|
||||
public int nDataLength;
|
||||
/// <summary>数据</summary>
|
||||
public byte[] Data = Array.Empty<byte>();
|
||||
}
|
||||
|
||||
public class FlexRayDBParse
|
||||
{
|
||||
private static FlexRayDBParse? _instance;
|
||||
/// <summary>单例实例</summary>
|
||||
public static FlexRayDBParse Instance => _instance ??= new FlexRayDBParse();
|
||||
|
||||
/// <summary>最大通道数(等于 MsgDatabase 的维度)</summary>
|
||||
public int MaxChannels => MsgDatabase.Count;
|
||||
|
||||
/// <summary>
|
||||
/// FlexRay 报文数据库(按通道索引,每个通道包含该通道上所有帧)。
|
||||
/// </summary>
|
||||
public static List<List<flexray_message>> MsgDatabase { get; set; } =
|
||||
[.. Enumerable.Range(0, 12).Select(_ => new List<flexray_message>())];
|
||||
|
||||
/// <summary>FlexRay 网络拓扑(Cluster/ECU/Frame/Signal)</summary>
|
||||
public static flexray_network Network;
|
||||
|
||||
/// <summary>
|
||||
/// 解析指定索引的 FlexRay 数据库,填充 MsgDatabase 和 Network。
|
||||
/// FlexRay 数据库由工程加载,通过 tsdb_get_flexray_db_count 获取数量。
|
||||
/// </summary>
|
||||
/// <param name="dbIndex">数据库索引(0-based)</param>
|
||||
/// <param name="channel">映射的通道号</param>
|
||||
public static void parse(int dbIndex, int channel)
|
||||
{
|
||||
int ASignalCount = 0;
|
||||
int AFrameCount = 0;
|
||||
int AECUcount = 0;
|
||||
long ASupportMask = 0;
|
||||
long AFlags = 0;
|
||||
IntPtr temp1 = IntPtr.Zero;
|
||||
IntPtr temp2 = IntPtr.Zero;
|
||||
|
||||
// 1. 获取 Cluster 属性
|
||||
int ret = TsMasterApi.tsdb_get_flexray_db_properties_by_index_verbose(
|
||||
dbIndex, ref ASignalCount, ref AFrameCount, ref AECUcount,
|
||||
ref ASupportMask, ref AFlags, ref temp1, ref temp2);
|
||||
|
||||
string clusterName = Marshal.PtrToStringAnsi(temp1) ?? "";
|
||||
Network = new flexray_network
|
||||
{
|
||||
network_name = clusterName,
|
||||
flexray_nodes = new flexray_node[AECUcount]
|
||||
};
|
||||
|
||||
// 2. 遍历所有 ECU
|
||||
for (int i = 0; i < AECUcount; i++)
|
||||
{
|
||||
int ATXFramecount = 0;
|
||||
int ARXFramecount = 0;
|
||||
|
||||
TsMasterApi.tsdb_get_flexray_ecu_properties_by_index_verbose(
|
||||
dbIndex, i, ref ATXFramecount, ref ARXFramecount, ref temp1, ref temp2);
|
||||
|
||||
string ecuName = Marshal.PtrToStringAnsi(temp1) ?? "";
|
||||
Network.flexray_nodes[i].node_name = ecuName;
|
||||
Network.flexray_nodes[i].tx_flexray_Messages = new flexray_message[ATXFramecount];
|
||||
Network.flexray_nodes[i].rx_flexray_Messages = new flexray_message[ARXFramecount];
|
||||
|
||||
// TX Frame
|
||||
for (int tx = 0; tx < ATXFramecount; tx++)
|
||||
{
|
||||
var msg = ParseFrame(dbIndex, i, tx, true);
|
||||
Network.flexray_nodes[i].tx_flexray_Messages[tx] = msg;
|
||||
MsgDatabase[channel].Add(msg);
|
||||
}
|
||||
|
||||
// RX Frame
|
||||
for (int rx = 0; rx < ARXFramecount; rx++)
|
||||
{
|
||||
var msg = ParseFrame(dbIndex, i, rx, false);
|
||||
Network.flexray_nodes[i].rx_flexray_Messages[rx] = msg;
|
||||
}
|
||||
}
|
||||
|
||||
MsgDatabase[channel].Sort((a, b) => a.slot_id.CompareTo(b.slot_id));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 解析单帧属性(TX 或 RX)
|
||||
/// </summary>
|
||||
private static flexray_message ParseFrame(int dbIndex, int ecuIndex, int frameIndex, bool isTx)
|
||||
{
|
||||
int AFRChannelMask = 0;
|
||||
int AFRBaseCycle = 0;
|
||||
int ARepCycle = 0;
|
||||
bool isStartupFrame = false;
|
||||
int ASlotID = 0;
|
||||
long CycleMask = 0;
|
||||
int AFRSignalCount = 0;
|
||||
int AFRDLC = 0;
|
||||
IntPtr temp1 = IntPtr.Zero;
|
||||
IntPtr temp2 = IntPtr.Zero;
|
||||
|
||||
TsMasterApi.tsdb_get_flexray_frame_properties_by_index_verbose(
|
||||
dbIndex, ecuIndex, frameIndex, isTx,
|
||||
ref AFRChannelMask, ref AFRBaseCycle, ref ARepCycle, ref isStartupFrame,
|
||||
ref ASlotID, ref CycleMask, ref AFRSignalCount, ref AFRDLC,
|
||||
ref temp1, ref temp2);
|
||||
|
||||
string frameName = Marshal.PtrToStringAnsi(temp1) ?? "";
|
||||
var msg = new flexray_message
|
||||
{
|
||||
message_name = frameName,
|
||||
slot_id = ASlotID,
|
||||
channel_mask = AFRChannelMask,
|
||||
base_cycle = AFRBaseCycle,
|
||||
rep_cycle = ARepCycle,
|
||||
is_startup_frame = isStartupFrame,
|
||||
dlc = AFRDLC,
|
||||
signals = new string[AFRSignalCount]
|
||||
};
|
||||
|
||||
// 遍历信号
|
||||
for (int s = 0; s < AFRSignalCount; s++)
|
||||
{
|
||||
TSignalType Asignaltype = (TSignalType)0;
|
||||
TFlexRayCompuMethod ACompuMethod = (TFlexRayCompuMethod)0;
|
||||
bool AIsIntel = false;
|
||||
int AStartBit = 0;
|
||||
int AUpdateBit = 0;
|
||||
int ALength = 0;
|
||||
double AFactor = 0;
|
||||
double AOffset = 0;
|
||||
double AInitValue = 0;
|
||||
|
||||
TsMasterApi.tsdb_get_flexray_signal_properties_by_index_verbose(
|
||||
dbIndex, ecuIndex, frameIndex, s, isTx,
|
||||
ref Asignaltype, ref ACompuMethod, ref AIsIntel,
|
||||
ref AStartBit, ref AUpdateBit, ref ALength,
|
||||
ref AFactor, ref AOffset, ref AInitValue,
|
||||
ref temp1, ref temp2);
|
||||
|
||||
string sigName = Marshal.PtrToStringAnsi(temp1) ?? "";
|
||||
msg.signals[s] = sigName;
|
||||
}
|
||||
|
||||
return msg;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 解析网络拓扑(仅填充 Network,不写入 MsgDatabase)
|
||||
/// </summary>
|
||||
public static void rbs_parse(int dbIndex, int channel)
|
||||
{
|
||||
// parse 已同时填充 Network 和 MsgDatabase,此处保持与 CAN 一致的接口
|
||||
parse(dbIndex, channel);
|
||||
}
|
||||
}
|
||||
}
|
||||
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,19 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Common\Common.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Reference Include="Interop.TSMasterAPI">
|
||||
<HintPath>Interop.TSMasterAPI.dll</HintPath>
|
||||
</Reference>
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
Binary file not shown.
@@ -0,0 +1,382 @@
|
||||
|
||||
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;
|
||||
|
||||
/// <summary>
|
||||
/// 实时接收到的 LIN 报文缓存(按帧 ID 索引,保留最新帧)。
|
||||
/// </summary>
|
||||
public static ConcurrentDictionary<int, TLIBLIN> RealTimeMessages { get; } = new();
|
||||
|
||||
#endregion
|
||||
|
||||
#region 实例字段与属性
|
||||
|
||||
/// <summary>设备类型号</summary>
|
||||
public uint DeviceType { get; }
|
||||
/// <summary>设备索引</summary>
|
||||
public uint DeviceIndex { get; }
|
||||
/// <summary>最大通道数</summary>
|
||||
public int MaxChannels { get; }
|
||||
/// <summary>波特率(LIN 常用 19.2 kbps)</summary>
|
||||
public float BaudRate { get; }
|
||||
/// <summary>LIN 协议版本</summary>
|
||||
public LIN_PROTOCOL Protocol { get; }
|
||||
|
||||
/// <summary>
|
||||
/// LIN 帧解码事件:当接收到帧后触发。
|
||||
/// 参数:(通道号, 帧信息)
|
||||
/// </summary>
|
||||
public event Action<uint, TLIBLIN>? OnLinFrameReceived;
|
||||
|
||||
private bool _disposed;
|
||||
private bool _isOpened;
|
||||
private TLINQueueEvent_Win32? _instanceListener;
|
||||
|
||||
#endregion
|
||||
|
||||
#region 构造函数
|
||||
|
||||
/// <summary>默认构造函数(1 通道、19.2 kbps、LIN 2.1)</summary>
|
||||
public LIN() : this(43, 0, 1, 19.2f, LIN_PROTOCOL.LIN_PROTOCOL_21) { }
|
||||
|
||||
/// <summary>
|
||||
/// 带配置参数的构造函数。
|
||||
/// </summary>
|
||||
/// <param name="deviceType">设备类型号</param>
|
||||
/// <param name="deviceIndex">设备索引</param>
|
||||
/// <param name="maxChannels">最大通道数</param>
|
||||
/// <param name="baudRate">波特率(常用 19.2)</param>
|
||||
/// <param name="protocol">LIN 协议版本</param>
|
||||
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 实例方法 — 设备管理
|
||||
|
||||
/// <summary>
|
||||
/// 打开设备:初始化 TSMaster 库 → 设置通道数 → 配置波特率与协议 → 连接 → 注册监听。
|
||||
/// </summary>
|
||||
/// <returns>true 表示成功</returns>
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 关闭 LIN 设备:注销监听 → 断开连接。
|
||||
/// </summary>
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// LIN 接收回调:缓存最新帧 → 触发 OnLinFrameReceived 事件。
|
||||
/// </summary>
|
||||
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
|
||||
|
||||
/// <summary>
|
||||
/// 初始化 TSMasterLIN
|
||||
/// </summary>
|
||||
/// <param name="ProjectName"></param>
|
||||
/// <param name="filePath">工程路径,为空则仅初始化库</param>
|
||||
/// <returns></returns>
|
||||
[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));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 释放 TSMaster
|
||||
/// </summary>
|
||||
[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;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 连接
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
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;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 断开
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
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;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 设置节点角色(LIN 特有:主节点/从节点)
|
||||
/// LIN 是单主多从总线,只有 Master 能发起帧头调度。
|
||||
/// </summary>
|
||||
/// <param name="channel">通道号(0-based)</param>
|
||||
/// <param name="nodeType">节点类型:T_MasterNode / T_SlaveNode</param>
|
||||
/// <returns></returns>
|
||||
public static int SetNodeType(byte channel, TLINNodeType nodeType)
|
||||
{
|
||||
return TsMasterApi.tslin_set_node_functiontype(channel, nodeType);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 设置当前通道为主节点
|
||||
/// </summary>
|
||||
public static int SetMaster(byte channel)
|
||||
{
|
||||
return TsMasterApi.tslin_set_node_functiontype(channel, TLINNodeType.T_MasterNode);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 设置当前通道为从节点
|
||||
/// </summary>
|
||||
public static int SetSlave(byte channel)
|
||||
{
|
||||
return TsMasterApi.tslin_set_node_functiontype(channel, TLINNodeType.T_SlaveNode);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 弹出通道映射窗口
|
||||
/// </summary>
|
||||
[Browsable(false)]
|
||||
public static int ShowChannelMappingWindow(bool isWait = false)
|
||||
{
|
||||
return TsMasterApi.tsapp_show_tsmaster_window("Hardware", isWait);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 发送一帧 LIN(异步)。
|
||||
/// LIN 发送语义:Master 发帧头(Header)后由指定节点应答数据。
|
||||
/// </summary>
|
||||
/// <param name="msg"></param>
|
||||
/// <returns></returns>
|
||||
[Browsable(false)]
|
||||
public static int SendMsg(TLIBLIN msg)
|
||||
{
|
||||
return TsMasterApi.tsapp_transmit_lin_async(ref msg);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 发送一帧 LIN(按参数构造)。
|
||||
/// </summary>
|
||||
/// <param name="AIdxChn">通道索引(0-based)</param>
|
||||
/// <param name="AID">帧 ID(6 位有效)</param>
|
||||
/// <param name="ADLC">数据长度(1~8 字节)</param>
|
||||
/// <param name="AIsTx">true=Master 同时发送数据(Master 发送帧+数据);false=仅发帧头,等待从节点应答</param>
|
||||
/// <returns></returns>
|
||||
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);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 发送一帧 LIN(携带数据)。
|
||||
/// </summary>
|
||||
/// <param name="AIdxChn">通道索引</param>
|
||||
/// <param name="AID">帧 ID</param>
|
||||
/// <param name="AData">数据数组(最多 8 字节)</param>
|
||||
/// <param name="AIsTx">true=Master 发送数据;false=仅发帧头</param>
|
||||
/// <returns></returns>
|
||||
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);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 开始记录日志
|
||||
/// </summary>
|
||||
public static int StartLogging(string filePath)
|
||||
{
|
||||
return TsMasterApi.tsapp_start_logging(Path.GetFullPath(filePath));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 结束记录日志
|
||||
/// </summary>
|
||||
public static int StopLogging()
|
||||
{
|
||||
return TsMasterApi.tsapp_stop_logging();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取错误提示
|
||||
/// </summary>
|
||||
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}";
|
||||
}
|
||||
}
|
||||
}
|
||||
Binary file not shown.
@@ -0,0 +1,19 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Common\Common.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Reference Include="Interop.TSMasterAPI">
|
||||
<HintPath>Interop.TSMasterAPI.dll</HintPath>
|
||||
</Reference>
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
@@ -25,5 +25,7 @@
|
||||
<ProjectReference Include="..\ORM\ORM.csproj" />
|
||||
<ProjectReference Include="..\Service\Service.csproj" />
|
||||
<ProjectReference Include="..\TSMasterCAN\TSMasterCAN.csproj" />
|
||||
<ProjectReference Include="..\TSMasterFlexRay\TSMasterFlexRay.csproj" />
|
||||
<ProjectReference Include="..\TSMasterLIN\TSMasterLIN.csproj" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
|
||||
Reference in New Issue
Block a user