using CapMachine.Model; using CapMachine.Model.CANLIN; using Newtonsoft.Json; using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Text; namespace CapMachine.Wpf.Services { /// /// CAN/LIN 配置导入模式。 /// public enum CanLinImportMode { /// /// 覆盖导入:同名同类型配置先删除后导入。 /// Overwrite = 1, /// /// 增量导入:同名同类型配置自动重命名后导入。 /// IncrementalRename = 2, } /// /// 导入导出执行结果。 /// public class CanLinConfigImExportResult { /// /// 执行是否成功。 /// public bool IsSuccess { get; set; } /// /// 结果消息。 /// public string Message { get; set; } = string.Empty; /// /// 导出配置数量。 /// public int ExportedConfigCount { get; set; } /// /// 导入配置数量。 /// public int ImportedConfigCount { get; set; } /// /// 覆盖配置数量。 /// public int OverwrittenConfigCount { get; set; } /// /// 重命名配置数量。 /// public int RenamedConfigCount { get; set; } /// /// 新增规则数量。 /// public int InsertedRuleCount { get; set; } /// /// 覆盖规则数量。 /// public int UpdatedRuleCount { get; set; } /// /// 重命名后的配置明细。 /// public List RenamedConfigs { get; set; } = new List(); } /// /// CAN/CANFD/LIN 配置导入导出服务。 /// public class CanLinConfigImExportService { /// /// 文件结构版本。 /// private const string SchemaVersion = "1.0"; /// /// 初始化导入导出服务。 /// /// 数据库实例。 /// 日志服务。 public CanLinConfigImExportService(IFreeSql freeSql, ILogService logService) { FreeSql = freeSql; LogService = logService; } /// /// 数据库访问对象。 /// public IFreeSql FreeSql { get; } /// /// 日志服务。 /// public ILogService LogService { get; } /// /// 导出当前 CAN/CANFD/LIN 配置到 JSON 文件。 /// /// 目标文件路径。 /// 执行结果。 public CanLinConfigImExportResult ExportToFile(string filePath) { var result = new CanLinConfigImExportResult(); try { if (string.IsNullOrWhiteSpace(filePath)) { result.Message = "导出路径不能为空"; return result; } var package = BuildExportPackage(); var json = JsonConvert.SerializeObject(package, Formatting.Indented); var dir = Path.GetDirectoryName(filePath); if (!string.IsNullOrWhiteSpace(dir) && !Directory.Exists(dir)) { Directory.CreateDirectory(dir); } File.WriteAllText(filePath, json, Encoding.UTF8); result.IsSuccess = true; result.ExportedConfigCount = package.CanLinConfigPros.Count; result.Message = $"导出成功,配置数量:{result.ExportedConfigCount}"; return result; } catch (Exception ex) { LogService.Error($"导出 CAN/LIN 配置失败:{ex}"); result.Message = $"导出失败:{ex.Message}"; return result; } } /// /// 从 JSON 文件导入 CAN/CANFD/LIN 配置到数据库。 /// /// 源文件路径。 /// 导入模式。 /// 执行结果。 public CanLinConfigImExportResult ImportFromFile(string filePath, CanLinImportMode importMode) { var result = new CanLinConfigImExportResult(); try { if (string.IsNullOrWhiteSpace(filePath)) { result.Message = "导入文件路径不能为空"; return result; } if (!File.Exists(filePath)) { result.Message = "导入文件不存在"; return result; } var json = File.ReadAllText(filePath, Encoding.UTF8); var package = JsonConvert.DeserializeObject(json); if (package == null) { result.Message = "导入文件解析失败"; return result; } if (package.CanLinConfigPros == null || package.CanLinConfigPros.Count == 0) { result.Message = "导入文件中没有 CAN/CANFD/LIN 配置数据"; return result; } FreeSql.Transaction(() => { var ruleMaps = UpsertLogicRules(package.LogicRules ?? new List(), result); foreach (var configSnapshot in package.CanLinConfigPros) { ImportSingleConfig(configSnapshot, importMode, ruleMaps, result); } }); result.IsSuccess = true; result.Message = $"导入成功:新增配置 {result.ImportedConfigCount},覆盖配置 {result.OverwrittenConfigCount},重命名配置 {result.RenamedConfigCount},新增规则 {result.InsertedRuleCount},覆盖规则 {result.UpdatedRuleCount}"; return result; } catch (Exception ex) { LogService.Error($"导入 CAN/LIN 配置失败:{ex}"); result.Message = $"导入失败:{ex.Message}"; return result; } } /// /// 构建导出快照对象。 /// /// 导出快照。 private CanLinConfigPackageSnapshot BuildExportPackage() { var logicRules = FreeSql.Select().OrderBy(a => a.Id).ToList(); var canConfigPros = FreeSql.Select() .Where(a => a.CANLINInfo == CANLIN.CAN) .Include(a => a.CANConfigExd) .IncludeMany(a => a.CanLinConfigContents, then => then.Include(b => b.LogicRule)) .IncludeMany(a => a.CanScheduleConfigs) .ToList(); var canFdConfigPros = FreeSql.Select() .Where(a => a.CANLINInfo == CANLIN.CANFD) .Include(a => a.CANFdConfigExd) .IncludeMany(a => a.CanLinConfigContents, then => then.Include(b => b.LogicRule)) .IncludeMany(a => a.CanFdScheduleConfigs) .ToList(); var linConfigPros = FreeSql.Select() .Where(a => a.CANLINInfo == CANLIN.LIN) .Include(a => a.LINConfigExd) .IncludeMany(a => a.CanLinConfigContents, then => then.Include(b => b.LogicRule)) .IncludeMany(a => a.LinScheduleConfigs) .ToList(); var allConfigPros = new List(); allConfigPros.AddRange(canConfigPros); allConfigPros.AddRange(canFdConfigPros); allConfigPros.AddRange(linConfigPros); return new CanLinConfigPackageSnapshot { SchemaVersion = SchemaVersion, ExportTime = DateTime.Now, LogicRules = logicRules.Select(MapLogicRuleSnapshot).ToList(), CanLinConfigPros = allConfigPros.Select(MapConfigSnapshot).ToList(), }; } /// /// 导入单个配置程序。 /// /// 配置快照。 /// 导入模式。 /// 规则映射。 /// 结果对象。 private void ImportSingleConfig( CanLinConfigProSnapshot snapshot, CanLinImportMode importMode, ImportRuleMaps ruleMaps, CanLinConfigImExportResult result) { if (snapshot == null) { return; } var sourceName = (snapshot.ConfigName ?? string.Empty).Trim(); if (string.IsNullOrWhiteSpace(sourceName)) { throw new InvalidOperationException("导入文件中存在空配置名称"); } var canlinInfo = snapshot.CANLINInfo; var finalConfigName = sourceName; var sameConfigExists = FreeSql.Select() .Where(a => a.CANLINInfo == canlinInfo) .Where(a => a.ConfigName == sourceName) .Any(); if (sameConfigExists) { if (importMode == CanLinImportMode.Overwrite) { DeleteExistingConfig(sourceName, canlinInfo); result.OverwrittenConfigCount++; } else { finalConfigName = BuildUniqueImportName(sourceName, canlinInfo); result.RenamedConfigCount++; result.RenamedConfigs.Add($"{sourceName} -> {finalConfigName} ({canlinInfo})"); } } var configExdIds = CreateConfigExd(snapshot, canlinInfo); var insertPro = FreeSql.Insert(new CanLinConfigPro { ConfigName = finalConfigName, CANLINInfo = canlinInfo, CANConfigExdId = configExdIds.CANConfigExdId, CANFdConfigExdId = configExdIds.CANFdConfigExdId, LINConfigExdId = configExdIds.LINConfigExdId, }).ExecuteInserted().FirstOrDefault(); if (insertPro == null) { throw new InvalidOperationException($"配置程序导入失败:{finalConfigName}"); } var rwConfigs = snapshot.CanLinConfigContents ?? new List(); foreach (var rwConfig in rwConfigs) { var logicRuleId = ResolveLogicRuleId(rwConfig, ruleMaps); var rwInsertResult = FreeSql.Insert(new CanLinRWConfig { RWInfo = rwConfig.RWInfo, Name = string.IsNullOrWhiteSpace(rwConfig.Name) ? rwConfig.SignalName : rwConfig.Name, MsgFrameName = rwConfig.MsgFrameName ?? string.Empty, SignalName = rwConfig.SignalName ?? string.Empty, DefautValue = rwConfig.DefautValue, CanLinConfigProId = insertPro.Id, LogicRuleId = logicRuleId, }).ExecuteAffrows(); if (rwInsertResult <= 0) { throw new InvalidOperationException($"导入读写配置失败:{finalConfigName}/{rwConfig.SignalName}"); } } if (canlinInfo == CANLIN.CAN) { foreach (var sch in snapshot.CanScheduleConfigs ?? new List()) { FreeSql.Insert(new CANScheduleConfig { MsgName = sch.MsgName, Cycle = sch.Cycle, OrderSend = sch.OrderSend, SchTabIndex = sch.SchTabIndex, CanLinConfigProId = insertPro.Id, }).ExecuteAffrows(); } } else if (canlinInfo == CANLIN.CANFD) { foreach (var sch in snapshot.CanFdScheduleConfigs ?? new List()) { FreeSql.Insert(new CANFdScheduleConfig { MsgName = sch.MsgName, Cycle = sch.Cycle, OrderSend = sch.OrderSend, SchTabIndex = sch.SchTabIndex, CanLinConfigProId = insertPro.Id, }).ExecuteAffrows(); } } else if (canlinInfo == CANLIN.LIN) { foreach (var sch in snapshot.LinScheduleConfigs ?? new List()) { FreeSql.Insert(new LINScheduleConfig { IsActive = sch.IsActive, IsMsgActived = sch.IsMsgActived, MsgName = sch.MsgName, MsgNameIndex = sch.MsgNameIndex, Cycle = sch.Cycle, SchTabIndex = sch.SchTabIndex, SchTabName = sch.SchTabName, CanLinConfigProId = insertPro.Id, }).ExecuteAffrows(); } } result.ImportedConfigCount++; } /// /// 创建并保存配置扩展信息。 /// /// 配置快照。 /// 配置类型。 /// 扩展配置主键集合。 private ConfigExdIds CreateConfigExd(CanLinConfigProSnapshot snapshot, CANLIN canlinInfo) { var ids = new ConfigExdIds(); if (canlinInfo == CANLIN.CAN) { var canExd = snapshot.CANConfigExd ?? new CANConfigExdSnapshot(); var insert = FreeSql.Insert(new CANConfigExd { BaudRate = canExd.BaudRate, Cycle = canExd.Cycle, DbcPath = canExd.DbcPath ?? string.Empty, SchEnable = canExd.SchEnable, }).ExecuteInserted().FirstOrDefault(); if (insert == null) { throw new InvalidOperationException("导入 CAN 扩展配置失败"); } ids.CANConfigExdId = insert.Id; } else if (canlinInfo == CANLIN.CANFD) { var canFdExd = snapshot.CANFdConfigExd ?? new CANFdConfigExdSnapshot(); var insert = FreeSql.Insert(new CANFdConfigExd { DataBaudRate = canFdExd.DataBaudRate, ArbBaudRate = canFdExd.ArbBaudRate, ISOEnable = canFdExd.ISOEnable, ResEnable = canFdExd.ResEnable, Cycle = canFdExd.Cycle, DbcPath = canFdExd.DbcPath ?? string.Empty, SchEnable = canFdExd.SchEnable, }).ExecuteInserted().FirstOrDefault(); if (insert == null) { throw new InvalidOperationException("导入 CANFD 扩展配置失败"); } ids.CANFdConfigExdId = insert.Id; } else { var linExd = snapshot.LINConfigExd ?? new LINConfigExdSnapshot(); var insert = FreeSql.Insert(new LINConfigExd { BaudRate = linExd.BaudRate, Cycle = linExd.Cycle, LdfPath = linExd.LdfPath ?? string.Empty, SchEnable = linExd.SchEnable, }).ExecuteInserted().FirstOrDefault(); if (insert == null) { throw new InvalidOperationException("导入 LIN 扩展配置失败"); } ids.LINConfigExdId = insert.Id; } return ids; } /// /// 删除同名同类型的旧配置。 /// /// 配置名称。 /// 配置类型。 private void DeleteExistingConfig(string configName, CANLIN canlinInfo) { var oldConfigs = FreeSql.Select() .Where(a => a.CANLINInfo == canlinInfo) .Where(a => a.ConfigName == configName) .ToList(); foreach (var oldConfig in oldConfigs) { FreeSql.Delete().Where(a => a.CanLinConfigProId == oldConfig.Id).ExecuteAffrows(); FreeSql.Delete().Where(a => a.CanLinConfigProId == oldConfig.Id).ExecuteAffrows(); FreeSql.Delete().Where(a => a.CanLinConfigProId == oldConfig.Id).ExecuteAffrows(); FreeSql.Delete().Where(a => a.CanLinConfigProId == oldConfig.Id).ExecuteAffrows(); FreeSql.Delete(oldConfig.Id).ExecuteAffrows(); if (canlinInfo == CANLIN.CAN && oldConfig.CANConfigExdId > 0) { FreeSql.Delete(oldConfig.CANConfigExdId).ExecuteAffrows(); } else if (canlinInfo == CANLIN.CANFD && oldConfig.CANFdConfigExdId > 0) { FreeSql.Delete(oldConfig.CANFdConfigExdId).ExecuteAffrows(); } else if (canlinInfo == CANLIN.LIN && oldConfig.LINConfigExdId > 0) { FreeSql.Delete(oldConfig.LINConfigExdId).ExecuteAffrows(); } } } /// /// 生成可用的增量重命名配置名。 /// /// 原始名称。 /// 配置类型。 /// 可用名称。 private string BuildUniqueImportName(string originalName, CANLIN canlinInfo) { var baseName = $"{originalName}_import_{DateTime.Now:yyyyMMddHHmmss}"; var candidate = baseName; var suffix = 1; while (FreeSql.Select() .Where(a => a.CANLINInfo == canlinInfo) .Where(a => a.ConfigName == candidate) .Any()) { candidate = $"{baseName}_{suffix}"; suffix++; } return candidate; } /// /// 导入并覆盖逻辑规则。 /// /// 规则快照集合。 /// 执行结果。 /// 规则映射。 private ImportRuleMaps UpsertLogicRules(List logicRules, CanLinConfigImExportResult result) { var maps = new ImportRuleMaps(); foreach (var snapshot in logicRules) { if (snapshot == null) { continue; } var ruleName = (snapshot.Name ?? string.Empty).Trim(); if (string.IsNullOrWhiteSpace(ruleName)) { continue; } var oldRule = FreeSql.Select().Where(a => a.Name == ruleName).First(); if (oldRule != null) { FreeSql.Update() .Set(a => a.Description, snapshot.Description) .Set(a => a.Expression, snapshot.Expression) .Set(a => a.ParameterType, snapshot.ParameterType) .Where(a => a.Id == oldRule.Id) .ExecuteAffrows(); maps.NameToTargetId[ruleName] = oldRule.Id; if (snapshot.Id > 0) { maps.SourceIdToTargetId[snapshot.Id] = oldRule.Id; } result.UpdatedRuleCount++; } else { var insertRule = FreeSql.Insert(new LogicRule { Name = ruleName, Description = snapshot.Description, Expression = snapshot.Expression, ParameterType = snapshot.ParameterType, }).ExecuteInserted().FirstOrDefault(); if (insertRule == null) { throw new InvalidOperationException($"导入逻辑规则失败:{ruleName}"); } maps.NameToTargetId[ruleName] = insertRule.Id; if (snapshot.Id > 0) { maps.SourceIdToTargetId[snapshot.Id] = insertRule.Id; } result.InsertedRuleCount++; } } return maps; } /// /// 解析读写配置对应的目标规则 Id。 /// /// 读写配置快照。 /// 规则映射。 /// 规则 Id。 private long ResolveLogicRuleId(CanLinRWConfigSnapshot rwSnapshot, ImportRuleMaps ruleMaps) { if (rwSnapshot == null) { return 0; } if (rwSnapshot.LogicRule != null) { var ruleName = (rwSnapshot.LogicRule.Name ?? string.Empty).Trim(); if (!string.IsNullOrWhiteSpace(ruleName) && ruleMaps.NameToTargetId.TryGetValue(ruleName, out var byNameId)) { return byNameId; } } if (rwSnapshot.LogicRuleId > 0 && ruleMaps.SourceIdToTargetId.TryGetValue(rwSnapshot.LogicRuleId, out var bySourceId)) { return bySourceId; } return 0; } /// /// 将规则实体映射为快照。 /// /// 规则实体。 /// 规则快照。 private static LogicRuleSnapshot MapLogicRuleSnapshot(LogicRule rule) { return new LogicRuleSnapshot { Id = rule.Id, Name = rule.Name, Description = rule.Description, Expression = rule.Expression, ParameterType = rule.ParameterType, }; } /// /// 将配置实体映射为快照。 /// /// 配置实体。 /// 配置快照。 private static CanLinConfigProSnapshot MapConfigSnapshot(CanLinConfigPro configPro) { return new CanLinConfigProSnapshot { ConfigName = configPro.ConfigName, CANLINInfo = configPro.CANLINInfo, CreateTime = configPro.CreateTime, CANConfigExd = configPro.CANConfigExd == null ? null : new CANConfigExdSnapshot { BaudRate = configPro.CANConfigExd.BaudRate, Cycle = configPro.CANConfigExd.Cycle, DbcPath = configPro.CANConfigExd.DbcPath, SchEnable = configPro.CANConfigExd.SchEnable, }, CANFdConfigExd = configPro.CANFdConfigExd == null ? null : new CANFdConfigExdSnapshot { DataBaudRate = configPro.CANFdConfigExd.DataBaudRate, ArbBaudRate = configPro.CANFdConfigExd.ArbBaudRate, ISOEnable = configPro.CANFdConfigExd.ISOEnable, ResEnable = configPro.CANFdConfigExd.ResEnable, Cycle = configPro.CANFdConfigExd.Cycle, DbcPath = configPro.CANFdConfigExd.DbcPath, SchEnable = configPro.CANFdConfigExd.SchEnable, }, LINConfigExd = configPro.LINConfigExd == null ? null : new LINConfigExdSnapshot { BaudRate = configPro.LINConfigExd.BaudRate, Cycle = configPro.LINConfigExd.Cycle, LdfPath = configPro.LINConfigExd.LdfPath, SchEnable = configPro.LINConfigExd.SchEnable, }, CanLinConfigContents = (configPro.CanLinConfigContents ?? new List()) .Select(a => new CanLinRWConfigSnapshot { RWInfo = a.RWInfo, Name = a.Name, MsgFrameName = a.MsgFrameName, SignalName = a.SignalName, DefautValue = a.DefautValue, LogicRuleId = a.LogicRuleId, LogicRule = a.LogicRule == null ? null : MapLogicRuleSnapshot(a.LogicRule), }).ToList(), CanScheduleConfigs = (configPro.CanScheduleConfigs ?? new List()) .Select(a => new CANScheduleConfigSnapshot { MsgName = a.MsgName, Cycle = a.Cycle, OrderSend = a.OrderSend, SchTabIndex = a.SchTabIndex, }).ToList(), CanFdScheduleConfigs = (configPro.CanFdScheduleConfigs ?? new List()) .Select(a => new CANFdScheduleConfigSnapshot { MsgName = a.MsgName, Cycle = a.Cycle, OrderSend = a.OrderSend, SchTabIndex = a.SchTabIndex, }).ToList(), LinScheduleConfigs = (configPro.LinScheduleConfigs ?? new List()) .Select(a => new LINScheduleConfigSnapshot { IsActive = a.IsActive, IsMsgActived = a.IsMsgActived, MsgName = a.MsgName, MsgNameIndex = a.MsgNameIndex, Cycle = a.Cycle, SchTabIndex = a.SchTabIndex, SchTabName = a.SchTabName, }).ToList(), }; } /// /// 规则映射上下文。 /// private class ImportRuleMaps { /// /// 规则名称到目标库规则 Id 的映射。 /// public Dictionary NameToTargetId { get; set; } = new Dictionary(StringComparer.OrdinalIgnoreCase); /// /// 源文件规则 Id 到目标库规则 Id 的映射。 /// public Dictionary SourceIdToTargetId { get; set; } = new Dictionary(); } /// /// 扩展配置主键集合。 /// private class ConfigExdIds { /// /// CAN 扩展主键。 /// public long CANConfigExdId { get; set; } /// /// CANFD 扩展主键。 /// public long CANFdConfigExdId { get; set; } /// /// LIN 扩展主键。 /// public long LINConfigExdId { get; set; } } } /// /// CAN/LIN 配置导入导出文件根对象。 /// public class CanLinConfigPackageSnapshot { /// /// 文件结构版本。 /// public string SchemaVersion { get; set; } = string.Empty; /// /// 导出时间。 /// public DateTime ExportTime { get; set; } /// /// 规则集合。 /// public List LogicRules { get; set; } = new List(); /// /// 配置程序集合。 /// public List CanLinConfigPros { get; set; } = new List(); } /// /// 逻辑规则快照。 /// public class LogicRuleSnapshot { /// /// 主键。 /// public long Id { get; set; } /// /// 规则名称。 /// public string? Name { get; set; } /// /// 规则描述。 /// public string? Description { get; set; } /// /// 规则表达式。 /// public string? Expression { get; set; } /// /// 参数类型。 /// public string? ParameterType { get; set; } } /// /// 配置程序快照。 /// public class CanLinConfigProSnapshot { /// /// 配置名称。 /// public string? ConfigName { get; set; } /// /// 配置分类。 /// public CANLIN CANLINInfo { get; set; } /// /// 创建时间。 /// public DateTime CreateTime { get; set; } /// /// CAN 扩展配置。 /// public CANConfigExdSnapshot? CANConfigExd { get; set; } /// /// CANFD 扩展配置。 /// public CANFdConfigExdSnapshot? CANFdConfigExd { get; set; } /// /// LIN 扩展配置。 /// public LINConfigExdSnapshot? LINConfigExd { get; set; } /// /// 读写配置集合。 /// public List? CanLinConfigContents { get; set; } /// /// CAN 调度配置。 /// public List? CanScheduleConfigs { get; set; } /// /// CANFD 调度配置。 /// public List? CanFdScheduleConfigs { get; set; } /// /// LIN 调度配置。 /// public List? LinScheduleConfigs { get; set; } } /// /// CAN 扩展快照。 /// public class CANConfigExdSnapshot { /// /// 波特率。 /// public int BaudRate { get; set; } /// /// 周期。 /// public int Cycle { get; set; } /// /// DBC 路径。 /// public string? DbcPath { get; set; } /// /// 调度启用。 /// public bool SchEnable { get; set; } } /// /// CANFD 扩展快照。 /// public class CANFdConfigExdSnapshot { /// /// 数据波特率。 /// public int DataBaudRate { get; set; } /// /// 仲裁波特率。 /// public int ArbBaudRate { get; set; } /// /// ISO 开关。 /// public bool ISOEnable { get; set; } /// /// 终端电阻开关。 /// public bool ResEnable { get; set; } /// /// 周期。 /// public int Cycle { get; set; } /// /// DBC 路径。 /// public string? DbcPath { get; set; } /// /// 调度启用。 /// public bool SchEnable { get; set; } } /// /// LIN 扩展快照。 /// public class LINConfigExdSnapshot { /// /// 波特率。 /// public int BaudRate { get; set; } /// /// 周期。 /// public int Cycle { get; set; } /// /// LDF 路径。 /// public string? LdfPath { get; set; } /// /// 调度启用。 /// public bool SchEnable { get; set; } } /// /// 读写配置快照。 /// public class CanLinRWConfigSnapshot { /// /// 读写类型。 /// public RW RWInfo { get; set; } /// /// 配置名称。 /// public string? Name { get; set; } /// /// 帧名。 /// public string? MsgFrameName { get; set; } /// /// 信号名。 /// public string? SignalName { get; set; } /// /// 默认值。 /// public string? DefautValue { get; set; } /// /// 规则 Id。 /// public long LogicRuleId { get; set; } /// /// 规则对象。 /// public LogicRuleSnapshot? LogicRule { get; set; } } /// /// CAN 调度快照。 /// public class CANScheduleConfigSnapshot { /// /// 消息名。 /// public string? MsgName { get; set; } /// /// 周期。 /// public int Cycle { get; set; } /// /// 发送方式。 /// public int OrderSend { get; set; } /// /// 调度表索引。 /// public int SchTabIndex { get; set; } } /// /// CANFD 调度快照。 /// public class CANFdScheduleConfigSnapshot { /// /// 消息名。 /// public string? MsgName { get; set; } /// /// 周期。 /// public int Cycle { get; set; } /// /// 发送方式。 /// public int OrderSend { get; set; } /// /// 调度表索引。 /// public int SchTabIndex { get; set; } } /// /// LIN 调度快照。 /// public class LINScheduleConfigSnapshot { /// /// 是否启用。 /// public bool IsActive { get; set; } /// /// 是否消息激活。 /// public bool IsMsgActived { get; set; } /// /// 消息名。 /// public string? MsgName { get; set; } /// /// 消息索引。 /// public int MsgNameIndex { get; set; } /// /// 周期。 /// public int Cycle { get; set; } /// /// 调度索引。 /// public int SchTabIndex { get; set; } /// /// 调度名。 /// public string? SchTabName { get; set; } } }