2204 lines
90 KiB
C#
2204 lines
90 KiB
C#
using AutoMapper;
|
||
using CapMachine.Core;
|
||
using CapMachine.Model.CANLIN;
|
||
using CapMachine.Wpf.CanDrive;
|
||
using CapMachine.Wpf.Dtos;
|
||
using CapMachine.Wpf.Services;
|
||
using CapMachine.Wpf.Views;
|
||
using ImTools;
|
||
using Microsoft.Win32;
|
||
using Prism.Commands;
|
||
using Prism.Events;
|
||
using Prism.Regions;
|
||
using Prism.Services.Dialogs;
|
||
using System;
|
||
using System.Collections.Generic;
|
||
using System.Collections.ObjectModel;
|
||
using System.IO;
|
||
using System.Linq;
|
||
using System.Windows;
|
||
using System.Windows.Controls;
|
||
using static CapMachine.Wpf.Models.ComEnum;
|
||
|
||
namespace CapMachine.Wpf.ViewModels
|
||
{
|
||
/// <summary>
|
||
/// ZLG CAN/CANFD 合并配置 ViewModel(模式切换:单选)。
|
||
/// </summary>
|
||
public class ZlgCanDriveConfigViewModel : NavigationViewModel
|
||
{
|
||
/// <summary>
|
||
/// 构造函数。
|
||
/// </summary>
|
||
public ZlgCanDriveConfigViewModel(IDialogService dialogService, IFreeSql freeSql,
|
||
IEventAggregator eventAggregator, IRegionManager regionManager, SysRunService sysRunService,
|
||
ComActionService comActionService, ILogService logService, LogicRuleService logicRuleService,
|
||
ConfigService configService, ZlgCanDriveService zlgCanDriveService, ZlgLinDriveService zlgLinDriveService,
|
||
IMapper mapper)
|
||
{
|
||
DialogService = dialogService;
|
||
FreeSql = freeSql;
|
||
EventAggregator = eventAggregator;
|
||
RegionManager = regionManager;
|
||
SysRunService = sysRunService;
|
||
ComActionService = comActionService;
|
||
LogService = logService;
|
||
LogicRuleService = logicRuleService;
|
||
ConfigService = configService;
|
||
ZlgCanDriveService = zlgCanDriveService;
|
||
ZlgLinDriveService = zlgLinDriveService;
|
||
Mapper = mapper;
|
||
|
||
SelectedMode = ZlgCanMode.Can;
|
||
|
||
ArbBaudRateCbxItems = new ObservableCollection<CbxItems>()
|
||
{
|
||
new CbxItems(){ Key="10000",Text="10 Kbps"},
|
||
new CbxItems(){ Key="20000",Text="20 Kbps"},
|
||
new CbxItems(){ Key="33000",Text="33 Kbps"},
|
||
new CbxItems(){ Key="50000",Text="50 Kbps"},
|
||
new CbxItems(){ Key="83000",Text="83 Kbps"},
|
||
new CbxItems(){ Key="100000",Text="100 Kbps"},
|
||
new CbxItems(){ Key="125000",Text="125 Kbps"},
|
||
new CbxItems(){ Key="150000",Text="150 Kbps"},
|
||
new CbxItems(){ Key="200000",Text="200 Kbps"},
|
||
new CbxItems(){ Key="250000",Text="250 Kbps"},
|
||
new CbxItems(){ Key="300000",Text="300 Kbps"},
|
||
new CbxItems(){ Key="400000",Text="400 Kbps"},
|
||
new CbxItems(){ Key="500000",Text="500 Kbps"},
|
||
new CbxItems(){ Key="666000",Text="666 Kbps"},
|
||
new CbxItems(){ Key="800000",Text="800 Kbps"},
|
||
new CbxItems(){ Key="1000000",Text="1.0 Mbps"},
|
||
};
|
||
|
||
DataBaudRateCbxItems = new ObservableCollection<CbxItems>()
|
||
{
|
||
new CbxItems(){ Key="100000",Text="100 Kbps"},
|
||
new CbxItems(){ Key="125000",Text="125 Kbps"},
|
||
new CbxItems(){ Key="200000",Text="200 Kbps"},
|
||
new CbxItems(){ Key="250000",Text="250 Kbps"},
|
||
new CbxItems(){ Key="400000",Text="400 Kbps"},
|
||
new CbxItems(){ Key="500000",Text="500 Kbps"},
|
||
new CbxItems(){ Key="666000",Text="666 Kbps"},
|
||
new CbxItems(){ Key="800000",Text="800 Kbps"},
|
||
new CbxItems(){ Key="1000000",Text="1.0 Mbps"},
|
||
|
||
new CbxItems(){ Key="1500000",Text="1.5 Mbps"},
|
||
new CbxItems(){ Key="2000000",Text="2.0 Mbps"},
|
||
new CbxItems(){ Key="3000000",Text="3.0 Mbps"},
|
||
new CbxItems(){ Key="4000000",Text="4.0 Mbps"},
|
||
new CbxItems(){ Key="5000000",Text="5.0 Mbps"},
|
||
new CbxItems(){ Key="6700000",Text="6.7 Mbps"},
|
||
new CbxItems(){ Key="8000000",Text="8.0 Mbps"},
|
||
new CbxItems(){ Key="10000000",Text="10.0 Mbps"},
|
||
};
|
||
|
||
InitWriteRuleCbx();
|
||
|
||
InitLoadCanConfigPro();
|
||
}
|
||
|
||
private void InitWriteRuleCbx()
|
||
{
|
||
WriteRuleCbxItems = new ObservableCollection<CbxItems>();
|
||
foreach (var itemRule in LogicRuleService.LogicRuleDtos)
|
||
{
|
||
WriteRuleCbxItems.Add(new CbxItems()
|
||
{
|
||
Key = itemRule.Id.ToString(),
|
||
Text = itemRule.Name
|
||
});
|
||
}
|
||
}
|
||
|
||
private void OpenRwDialog()
|
||
{
|
||
try
|
||
{
|
||
if (SelectCanLinConfigPro == null)
|
||
{
|
||
MessageBox.Show("选中CAN配置名称后再操作", "提示", MessageBoxButton.OK, MessageBoxImage.Hand);
|
||
return;
|
||
}
|
||
|
||
var writeClones = new ObservableCollection<CanLinRWConfigDto>(
|
||
(ListWriteCanLinRWConfigDto ?? new ObservableCollection<CanLinRWConfigDto>())
|
||
.Select(CloneRwDto));
|
||
|
||
foreach (var item in writeClones)
|
||
{
|
||
item.RWInfo = RW.Write;
|
||
}
|
||
|
||
var readClones = new ObservableCollection<CanLinRWConfigDto>(
|
||
(ListReadCanLinRWConfigDto ?? new ObservableCollection<CanLinRWConfigDto>())
|
||
.Select(CloneRwDto));
|
||
|
||
foreach (var item in readClones)
|
||
{
|
||
item.RWInfo = RW.Read;
|
||
}
|
||
|
||
var candidates = new ObservableCollection<DialogZlgCanLinRwConfigViewModel.SignalCandidate>();
|
||
if (ListCanDbcModel != null)
|
||
{
|
||
foreach (var sig in ListCanDbcModel)
|
||
{
|
||
candidates.Add(new DialogZlgCanLinRwConfigViewModel.SignalCandidate
|
||
{
|
||
MsgName = sig.MsgName,
|
||
SignalName = sig.SignalName,
|
||
Name = sig.Name,
|
||
Desc = sig.SignalDesc,
|
||
});
|
||
}
|
||
}
|
||
|
||
var pars = new DialogParameters
|
||
{
|
||
{ "Title", "读写设置" },
|
||
{ "CanLinConfigProId", SelectCanLinConfigPro.Id },
|
||
{ "IsEditable", IsRwEditable },
|
||
{ "WriteConfigs", writeClones },
|
||
{ "ReadConfigs", readClones },
|
||
{ "SignalCandidates", candidates },
|
||
};
|
||
|
||
DialogService.ShowDialog(nameof(DialogZlgCanLinRwConfigView), pars, r =>
|
||
{
|
||
if (r.Result == ButtonResult.OK)
|
||
{
|
||
ReloadCurrentConfigPro();
|
||
OpTip = "读写设置已保存";
|
||
}
|
||
});
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
LogService.Error($"ZLG 打开读写设置弹窗失败:{ex}");
|
||
MessageBox.Show(ex.Message, "错误", MessageBoxButton.OK, MessageBoxImage.Error);
|
||
}
|
||
}
|
||
|
||
private static CanLinRWConfigDto CloneRwDto(CanLinRWConfigDto src)
|
||
{
|
||
return new CanLinRWConfigDto
|
||
{
|
||
Id = src.Id,
|
||
RWInfo = src.RWInfo,
|
||
Name = src.Name,
|
||
MsgFrameName = src.MsgFrameName,
|
||
SignalName = src.SignalName,
|
||
DefautValue = src.DefautValue,
|
||
LogicRuleId = src.LogicRuleId,
|
||
LogicRuleDto = src.LogicRuleDto,
|
||
};
|
||
}
|
||
|
||
/// <summary>
|
||
/// Dialog 服务。
|
||
/// </summary>
|
||
public IDialogService DialogService { get; }
|
||
|
||
/// <summary>
|
||
/// FreeSql。
|
||
/// </summary>
|
||
public IFreeSql FreeSql { get; }
|
||
|
||
/// <summary>
|
||
/// 事件聚合。
|
||
/// </summary>
|
||
public IEventAggregator EventAggregator { get; }
|
||
|
||
/// <summary>
|
||
/// 区域导航。
|
||
/// </summary>
|
||
public IRegionManager RegionManager { get; }
|
||
|
||
/// <summary>
|
||
/// 系统运行服务。
|
||
/// </summary>
|
||
public SysRunService SysRunService { get; }
|
||
|
||
/// <summary>
|
||
/// 通信互斥控制。
|
||
/// </summary>
|
||
public ComActionService ComActionService { get; }
|
||
|
||
/// <summary>
|
||
/// 日志。
|
||
/// </summary>
|
||
public ILogService LogService { get; }
|
||
|
||
/// <summary>
|
||
/// 逻辑规则服务。
|
||
/// </summary>
|
||
public LogicRuleService LogicRuleService { get; }
|
||
|
||
/// <summary>
|
||
/// 配置服务。
|
||
/// </summary>
|
||
public ConfigService ConfigService { get; }
|
||
|
||
/// <summary>
|
||
/// ZLG CAN 服务。
|
||
/// </summary>
|
||
public ZlgCanDriveService ZlgCanDriveService { get; }
|
||
|
||
/// <summary>
|
||
/// ZLG LIN 服务(用于互斥判断)。
|
||
/// </summary>
|
||
public ZlgLinDriveService ZlgLinDriveService { get; }
|
||
|
||
/// <summary>
|
||
/// Mapper。
|
||
/// </summary>
|
||
public IMapper Mapper { get; }
|
||
|
||
private ObservableCollection<CbxItems> _arbBaudRateCbxItems = new ObservableCollection<CbxItems>();
|
||
/// <summary>
|
||
/// 仲裁波特率下拉项(bps)。
|
||
/// </summary>
|
||
public ObservableCollection<CbxItems> ArbBaudRateCbxItems
|
||
{
|
||
get { return _arbBaudRateCbxItems; }
|
||
set { _arbBaudRateCbxItems = value; RaisePropertyChanged(); }
|
||
}
|
||
|
||
private ObservableCollection<CbxItems> _dataBaudRateCbxItems = new ObservableCollection<CbxItems>();
|
||
/// <summary>
|
||
/// 数据波特率下拉项(bps)。
|
||
/// </summary>
|
||
public ObservableCollection<CbxItems> DataBaudRateCbxItems
|
||
{
|
||
get { return _dataBaudRateCbxItems; }
|
||
set { _dataBaudRateCbxItems = value; RaisePropertyChanged(); }
|
||
}
|
||
|
||
private List<CanLinConfigPro> _canLinConfigPros = new List<CanLinConfigPro>();
|
||
|
||
private ObservableCollection<CbxItems> _writeRuleCbxItems = new ObservableCollection<CbxItems>();
|
||
public ObservableCollection<CbxItems> WriteRuleCbxItems
|
||
{
|
||
get { return _writeRuleCbxItems; }
|
||
set { _writeRuleCbxItems = value; RaisePropertyChanged(); }
|
||
}
|
||
|
||
private ObservableCollection<CanLinRWConfigDto> _listWriteCanLinRWConfigDto = new ObservableCollection<CanLinRWConfigDto>();
|
||
public ObservableCollection<CanLinRWConfigDto> ListWriteCanLinRWConfigDto
|
||
{
|
||
get { return _listWriteCanLinRWConfigDto; }
|
||
set { _listWriteCanLinRWConfigDto = value; RaisePropertyChanged(); }
|
||
}
|
||
|
||
private ObservableCollection<CanLinRWConfigDto> _listReadCanLinRWConfigDto = new ObservableCollection<CanLinRWConfigDto>();
|
||
public ObservableCollection<CanLinRWConfigDto> ListReadCanLinRWConfigDto
|
||
{
|
||
get { return _listReadCanLinRWConfigDto; }
|
||
set { _listReadCanLinRWConfigDto = value; RaisePropertyChanged(); }
|
||
}
|
||
|
||
private CanLinRWConfigDto? SelectedWriteCanLinRWConfigDto { get; set; }
|
||
private CanLinRWConfigDto? SelectedReadCanLinRWConfigDto { get; set; }
|
||
|
||
private string? _opTip;
|
||
/// <summary>
|
||
/// 操作提示(用于 UI 状态展示)。
|
||
/// </summary>
|
||
public string? OpTip
|
||
{
|
||
get { return _opTip; }
|
||
set { _opTip = value; RaisePropertyChanged(); }
|
||
}
|
||
|
||
private string? _lastError;
|
||
/// <summary>
|
||
/// 最近一次错误信息(用于 UI 状态展示)。
|
||
/// </summary>
|
||
public string? LastError
|
||
{
|
||
get { return _lastError; }
|
||
set { _lastError = value; RaisePropertyChanged(); }
|
||
}
|
||
|
||
private bool _isCanConfigProActive;
|
||
/// <summary>
|
||
/// 当前配置程序是否已激活(对齐图莫斯 Active 语义)。
|
||
/// 激活后禁止切换配置程序。
|
||
/// </summary>
|
||
public bool IsCanConfigProActive
|
||
{
|
||
get { return _isCanConfigProActive; }
|
||
set
|
||
{
|
||
_isCanConfigProActive = value;
|
||
RaisePropertyChanged();
|
||
RaisePropertyChanged(nameof(IsRwEditable));
|
||
}
|
||
}
|
||
|
||
public bool IsRwEditable
|
||
{
|
||
get { return !IsCanConfigProActive; }
|
||
}
|
||
|
||
private bool _isCANConfigDatagridActive = true;
|
||
/// <summary>
|
||
/// 配置程序 DataGrid 是否可操作(与 IsCanConfigProActive 取反)。
|
||
/// </summary>
|
||
public bool IsCANConfigDatagridActive
|
||
{
|
||
get { return _isCANConfigDatagridActive; }
|
||
set { _isCANConfigDatagridActive = value; RaisePropertyChanged(); }
|
||
}
|
||
|
||
private ZlgCanMode _selectedMode;
|
||
/// <summary>
|
||
/// 模式选择:CAN/CANFD(单选)。
|
||
/// </summary>
|
||
public ZlgCanMode SelectedMode
|
||
{
|
||
get { return _selectedMode; }
|
||
set
|
||
{
|
||
// 打开状态下不允许切换模式,避免驱动状态错乱。
|
||
if (ZlgCanDriveService.OpenState && _selectedMode != value)
|
||
{
|
||
MessageBox.Show("请先关闭 CAN 后再切换 CAN/CANFD 模式", "提示", MessageBoxButton.OK, MessageBoxImage.Hand);
|
||
RaisePropertyChanged(nameof(SelectedModeKey));
|
||
return;
|
||
}
|
||
|
||
_selectedMode = value;
|
||
RaisePropertyChanged();
|
||
RaisePropertyChanged(nameof(SelectedModeKey));
|
||
RaisePropertyChanged(nameof(IsCanMode));
|
||
RaisePropertyChanged(nameof(IsCanFdMode));
|
||
RaisePropertyChanged(nameof(DbcPathTitle));
|
||
RaisePropertyChanged(nameof(ConnectButtonText));
|
||
RaisePropertyChanged(nameof(CloseButtonText));
|
||
RaisePropertyChanged(nameof(CurrentDbcPath));
|
||
RaisePropertyChanged(nameof(CurrentCycle));
|
||
RaisePropertyChanged(nameof(CurrentSchEnable));
|
||
RaisePropertyChanged(nameof(CurrentArbBaudRate));
|
||
RaisePropertyChanged(nameof(CurrentDataBaudRate));
|
||
RaisePropertyChanged(nameof(CurrentISOEnable));
|
||
RaisePropertyChanged(nameof(CurrentResEnable));
|
||
RaisePropertyChanged(nameof(BaudRateTitle));
|
||
RaisePropertyChanged(nameof(DataBaudRateTitle));
|
||
ZlgCanDriveService.Mode = value;
|
||
|
||
// 当用户手动切换 CAN/CANFD 时,如果当前配置缺少对应扩展 DTO,需要先生成默认 DTO,
|
||
// 否则界面控件无法编辑(setter 会因 DTO 为空直接 return)。
|
||
if (SelectCanLinConfigPro != null)
|
||
{
|
||
if (value == ZlgCanMode.Can)
|
||
{
|
||
if (SelectedCANConfigExdDto == null)
|
||
{
|
||
SelectedCANConfigExdDto = new CANConfigExdDto()
|
||
{
|
||
Id = 0,
|
||
BaudRate = 500000,
|
||
DbcPath = string.Empty,
|
||
Cycle = 100,
|
||
SchEnable = false,
|
||
};
|
||
}
|
||
}
|
||
else
|
||
{
|
||
if (SelectedCANFdConfigExdDto == null)
|
||
{
|
||
SelectedCANFdConfigExdDto = new CANFdConfigExdDto()
|
||
{
|
||
Id = 0,
|
||
ArbBaudRate = 500000,
|
||
DataBaudRate = 2000000,
|
||
ISOEnable = true,
|
||
ResEnable = false,
|
||
DbcPath = string.Empty,
|
||
Cycle = 100,
|
||
SchEnable = false,
|
||
};
|
||
}
|
||
}
|
||
}
|
||
|
||
// 切换模式后,为避免界面仍显示旧的 DBC 信号列表,清空信号集合。
|
||
// 配置程序列表不应随模式切换而过滤/刷新。
|
||
ListCanDbcModel = new ObservableCollection<CanDbcModel>();
|
||
}
|
||
}
|
||
|
||
private DelegateCommand<object>? _writeGridSelectionChangedCmd;
|
||
public DelegateCommand<object> WriteGridSelectionChangedCmd
|
||
{
|
||
get
|
||
{
|
||
if (_writeGridSelectionChangedCmd == null)
|
||
{
|
||
_writeGridSelectionChangedCmd = new DelegateCommand<object>(WriteGridSelectionChangedCmdMethod);
|
||
}
|
||
return _writeGridSelectionChangedCmd;
|
||
}
|
||
}
|
||
|
||
private void WriteGridSelectionChangedCmdMethod(object par)
|
||
{
|
||
if (par is CanLinRWConfigDto dto)
|
||
{
|
||
SelectedWriteCanLinRWConfigDto = dto;
|
||
}
|
||
}
|
||
|
||
private DelegateCommand<object>? _readGridSelectionChangedCmd;
|
||
public DelegateCommand<object> ReadGridSelectionChangedCmd
|
||
{
|
||
get
|
||
{
|
||
if (_readGridSelectionChangedCmd == null)
|
||
{
|
||
_readGridSelectionChangedCmd = new DelegateCommand<object>(ReadGridSelectionChangedCmdMethod);
|
||
}
|
||
return _readGridSelectionChangedCmd;
|
||
}
|
||
}
|
||
|
||
private void ReadGridSelectionChangedCmdMethod(object par)
|
||
{
|
||
if (par is CanLinRWConfigDto dto)
|
||
{
|
||
SelectedReadCanLinRWConfigDto = dto;
|
||
}
|
||
}
|
||
|
||
private DelegateCommand<string>? _writeCmd;
|
||
public DelegateCommand<string> WriteCmd
|
||
{
|
||
get
|
||
{
|
||
if (_writeCmd == null)
|
||
{
|
||
_writeCmd = new DelegateCommand<string>(WriteCmdMethod);
|
||
}
|
||
return _writeCmd;
|
||
}
|
||
}
|
||
|
||
private void WriteCmdMethod(string par)
|
||
{
|
||
if (SelectCanLinConfigPro == null)
|
||
{
|
||
MessageBox.Show("选中CAN配置名称后再操作", "提示", MessageBoxButton.OK, MessageBoxImage.Hand);
|
||
return;
|
||
}
|
||
|
||
if (IsCanConfigProActive)
|
||
{
|
||
MessageBox.Show("当前配置已激活,请先取消激活后再修改写入配置", "提示", MessageBoxButton.OK, MessageBoxImage.Hand);
|
||
return;
|
||
}
|
||
|
||
switch (par)
|
||
{
|
||
case "Edit":
|
||
foreach (var item in ListWriteCanLinRWConfigDto)
|
||
{
|
||
FreeSql.Update<CanLinRWConfig>(item.Id)
|
||
.Set(a => a.Name, item.Name)
|
||
.Set(a => a.LogicRuleId, item.LogicRuleId)
|
||
.Set(a => a.DefautValue, item.DefautValue)
|
||
.ExecuteAffrows();
|
||
}
|
||
ReloadCurrentConfigPro();
|
||
OpTip = "写入配置已保存";
|
||
break;
|
||
|
||
case "Delete":
|
||
if (SelectedWriteCanLinRWConfigDto == null)
|
||
{
|
||
MessageBox.Show("请选中写入列表中的一行后再删除", "提示", MessageBoxButton.OK, MessageBoxImage.Hand);
|
||
return;
|
||
}
|
||
FreeSql.Delete<CanLinRWConfig>(SelectedWriteCanLinRWConfigDto.Id).ExecuteAffrows();
|
||
ReloadCurrentConfigPro();
|
||
OpTip = "写入配置已删除";
|
||
break;
|
||
}
|
||
}
|
||
|
||
private DelegateCommand<string>? _readCmd;
|
||
public DelegateCommand<string> ReadCmd
|
||
{
|
||
get
|
||
{
|
||
if (_readCmd == null)
|
||
{
|
||
_readCmd = new DelegateCommand<string>(ReadCmdMethod);
|
||
}
|
||
return _readCmd;
|
||
}
|
||
}
|
||
|
||
private void ReadCmdMethod(string par)
|
||
{
|
||
if (SelectCanLinConfigPro == null)
|
||
{
|
||
MessageBox.Show("选中CAN配置名称后再操作", "提示", MessageBoxButton.OK, MessageBoxImage.Hand);
|
||
return;
|
||
}
|
||
|
||
if (IsCanConfigProActive)
|
||
{
|
||
MessageBox.Show("当前配置已激活,请先取消激活后再修改读取配置", "提示", MessageBoxButton.OK, MessageBoxImage.Hand);
|
||
return;
|
||
}
|
||
|
||
switch (par)
|
||
{
|
||
case "Edit":
|
||
foreach (var item in ListReadCanLinRWConfigDto)
|
||
{
|
||
FreeSql.Update<CanLinRWConfig>(item.Id)
|
||
.Set(a => a.Name, item.Name)
|
||
.Set(a => a.DefautValue, item.DefautValue)
|
||
.ExecuteAffrows();
|
||
}
|
||
ReloadCurrentConfigPro();
|
||
OpTip = "读取配置已保存";
|
||
break;
|
||
|
||
case "Delete":
|
||
if (SelectedReadCanLinRWConfigDto == null)
|
||
{
|
||
MessageBox.Show("请选中读取列表中的一行后再删除", "提示", MessageBoxButton.OK, MessageBoxImage.Hand);
|
||
return;
|
||
}
|
||
FreeSql.Delete<CanLinRWConfig>(SelectedReadCanLinRWConfigDto.Id).ExecuteAffrows();
|
||
ReloadCurrentConfigPro();
|
||
OpTip = "读取配置已删除";
|
||
break;
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 连接按钮文字(对齐 Toomoss 风格)。
|
||
/// </summary>
|
||
public string ConnectButtonText
|
||
{
|
||
get { return SelectedMode == ZlgCanMode.Can ? "连接CAN" : "连接CANFD"; }
|
||
}
|
||
|
||
/// <summary>
|
||
/// 当前是否为 CANFD 模式(用于 UI 启用/禁用某些仅 CANFD 支持的参数)。
|
||
/// </summary>
|
||
public bool IsCanFdMode
|
||
{
|
||
get { return SelectedMode == ZlgCanMode.CanFd; }
|
||
}
|
||
|
||
/// <summary>
|
||
/// 当前是否为 CAN 模式(用于 UI 启用/禁用某些仅 CANFD 支持的参数)。
|
||
/// </summary>
|
||
public bool IsCanMode
|
||
{
|
||
get { return SelectedMode == ZlgCanMode.Can; }
|
||
}
|
||
|
||
/// <summary>
|
||
/// 波特率标题:CAN 为“波特率”,CANFD 为“仲裁波特率”。
|
||
/// </summary>
|
||
public string BaudRateTitle
|
||
{
|
||
get { return SelectedMode == ZlgCanMode.Can ? "波特率" : "仲裁波特率"; }
|
||
}
|
||
|
||
/// <summary>
|
||
/// 数据波特率标题:仅 CANFD 有意义。
|
||
/// </summary>
|
||
public string DataBaudRateTitle
|
||
{
|
||
get { return "数据波特率"; }
|
||
}
|
||
|
||
/// <summary>
|
||
/// 关闭按钮文字(对齐 Toomoss 风格)。
|
||
/// </summary>
|
||
public string CloseButtonText
|
||
{
|
||
get { return SelectedMode == ZlgCanMode.Can ? "关闭CAN" : "关闭CANFD"; }
|
||
}
|
||
|
||
/// <summary>
|
||
/// 绑定用:模式 Key(Can/CanFd)。
|
||
/// </summary>
|
||
public string SelectedModeKey
|
||
{
|
||
get { return SelectedMode == ZlgCanMode.Can ? "Can" : "CanFd"; }
|
||
set
|
||
{
|
||
if (ZlgCanDriveService.OpenState)
|
||
{
|
||
MessageBox.Show("请先关闭 CAN 后再切换 CAN/CANFD 模式", "提示", MessageBoxButton.OK, MessageBoxImage.Hand);
|
||
RaisePropertyChanged();
|
||
return;
|
||
}
|
||
|
||
if (string.Equals(value, "Can", StringComparison.OrdinalIgnoreCase))
|
||
{
|
||
SelectedMode = ZlgCanMode.Can;
|
||
return;
|
||
}
|
||
|
||
if (string.Equals(value, "CanFd", StringComparison.OrdinalIgnoreCase) || string.Equals(value, "CanFD", StringComparison.OrdinalIgnoreCase))
|
||
{
|
||
SelectedMode = ZlgCanMode.CanFd;
|
||
return;
|
||
}
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// DBC 路径标题。
|
||
/// </summary>
|
||
public string DbcPathTitle
|
||
{
|
||
get { return SelectedMode == ZlgCanMode.Can ? "CAN-DBC文件路径:" : "CANFD-DBC文件路径:"; }
|
||
}
|
||
|
||
private ObservableCollection<CanLinConfigPro>? _listCanLinConfigPro;
|
||
/// <summary>
|
||
/// 配置程序集合。
|
||
/// </summary>
|
||
public ObservableCollection<CanLinConfigPro>? ListCanLinConfigPro
|
||
{
|
||
get { return _listCanLinConfigPro; }
|
||
set { _listCanLinConfigPro = value; RaisePropertyChanged(); }
|
||
}
|
||
|
||
/// <summary>
|
||
/// 选中的配置程序。
|
||
/// </summary>
|
||
private CanLinConfigPro? _selectCanLinConfigPro;
|
||
|
||
/// <summary>
|
||
/// 选中的配置程序。
|
||
/// </summary>
|
||
public CanLinConfigPro? SelectCanLinConfigPro
|
||
{
|
||
get { return _selectCanLinConfigPro; }
|
||
set
|
||
{
|
||
_selectCanLinConfigPro = value;
|
||
RaisePropertyChanged();
|
||
}
|
||
}
|
||
|
||
private ObservableCollection<CanDbcModel>? _listCanDbcModel;
|
||
/// <summary>
|
||
/// DBC 信号集合。
|
||
/// </summary>
|
||
public ObservableCollection<CanDbcModel>? ListCanDbcModel
|
||
{
|
||
get { return _listCanDbcModel; }
|
||
set { _listCanDbcModel = value; RaisePropertyChanged(); }
|
||
}
|
||
|
||
/// <summary>
|
||
/// 当前选中的 DBC 信号。
|
||
/// </summary>
|
||
public CanDbcModel? SelectedCanDbcModel
|
||
{
|
||
get { return _selectedCanDbcModel; }
|
||
set { _selectedCanDbcModel = value; RaisePropertyChanged(); }
|
||
}
|
||
|
||
private CanDbcModel? _selectedCanDbcModel;
|
||
|
||
private CANConfigExdDto? _selectedCANConfigExdDto;
|
||
/// <summary>
|
||
/// CAN 配置 DTO。
|
||
/// </summary>
|
||
public CANConfigExdDto? SelectedCANConfigExdDto
|
||
{
|
||
get { return _selectedCANConfigExdDto; }
|
||
set { _selectedCANConfigExdDto = value; RaisePropertyChanged(); }
|
||
}
|
||
|
||
private CANFdConfigExdDto? _selectedCANFdConfigExdDto;
|
||
/// <summary>
|
||
/// CANFD 配置 DTO。
|
||
/// </summary>
|
||
public CANFdConfigExdDto? SelectedCANFdConfigExdDto
|
||
{
|
||
get { return _selectedCANFdConfigExdDto; }
|
||
set { _selectedCANFdConfigExdDto = value; RaisePropertyChanged(); }
|
||
}
|
||
|
||
private void InitLoadCanConfigPro()
|
||
{
|
||
_canLinConfigPros = FreeSql.Select<CanLinConfigPro>()
|
||
.Where(a => a.CANLINInfo == CANLIN.CAN || a.CANLINInfo == CANLIN.CANFD)
|
||
.Include(a => a.CANConfigExd)
|
||
.Include(a => a.CANFdConfigExd)
|
||
.IncludeMany(a => a.CanLinConfigContents, then => then.Include(b => b.LogicRule))
|
||
.IncludeMany(a => a.CanScheduleConfigs)
|
||
.IncludeMany(a => a.CanFdScheduleConfigs)
|
||
.ToList();
|
||
|
||
ListCanLinConfigPro = new ObservableCollection<CanLinConfigPro>(_canLinConfigPros);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 同步选中的配置。
|
||
/// </summary>
|
||
private void SyncSelectedConfig()
|
||
{
|
||
if (SelectCanLinConfigPro == null)
|
||
{
|
||
return;
|
||
}
|
||
|
||
// 选中配置程序后,模式应跟随该配置自身的 CANLINInfo,避免“列表全量但右侧模式不匹配”。
|
||
var proMode = SelectCanLinConfigPro.CANLINInfo == CANLIN.CAN ? ZlgCanMode.Can : ZlgCanMode.CanFd;
|
||
if (SelectedMode != proMode)
|
||
{
|
||
SelectedMode = proMode;
|
||
}
|
||
|
||
// 同时映射两套配置(如不存在则为 null),这样用户可以在 UI 上切换模式后再保存。
|
||
SelectedCANConfigExdDto = SelectCanLinConfigPro.CANConfigExd != null
|
||
? Mapper.Map<CANConfigExdDto>(SelectCanLinConfigPro.CANConfigExd)
|
||
: null;
|
||
SelectedCANFdConfigExdDto = SelectCanLinConfigPro.CANFdConfigExd != null
|
||
? Mapper.Map<CANFdConfigExdDto>(SelectCanLinConfigPro.CANFdConfigExd)
|
||
: null;
|
||
|
||
RaisePropertyChanged(nameof(CurrentDbcPath));
|
||
RaisePropertyChanged(nameof(CurrentCycle));
|
||
RaisePropertyChanged(nameof(CurrentSchEnable));
|
||
RaisePropertyChanged(nameof(CurrentArbBaudRate));
|
||
RaisePropertyChanged(nameof(CurrentDataBaudRate));
|
||
RaisePropertyChanged(nameof(CurrentISOEnable));
|
||
RaisePropertyChanged(nameof(CurrentResEnable));
|
||
RaisePropertyChanged(nameof(CanBaudRate));
|
||
RaisePropertyChanged(nameof(CanFdArbBaudRate));
|
||
RaisePropertyChanged(nameof(CanFdDataBaudRate));
|
||
|
||
BuildAndLoadCmdDataToDrive();
|
||
|
||
var writeData = SelectCanLinConfigPro.CanLinConfigContents?.Where(a => a.RWInfo == RW.Write).ToList() ?? new List<CanLinRWConfig>();
|
||
ListWriteCanLinRWConfigDto = new ObservableCollection<CanLinRWConfigDto>(Mapper.Map<List<CanLinRWConfigDto>>(writeData));
|
||
|
||
var readData = SelectCanLinConfigPro.CanLinConfigContents?.Where(a => a.RWInfo == RW.Read).ToList() ?? new List<CanLinRWConfig>();
|
||
ListReadCanLinRWConfigDto = new ObservableCollection<CanLinRWConfigDto>(Mapper.Map<List<CanLinRWConfigDto>>(readData));
|
||
|
||
// 调度表(按模式)
|
||
if (SelectedMode == ZlgCanMode.Can)
|
||
{
|
||
if (SelectCanLinConfigPro.CanScheduleConfigs != null && SelectCanLinConfigPro.CanScheduleConfigs.Count > 0)
|
||
{
|
||
ListCANScheduleConfigDto = new ObservableCollection<CANScheduleConfigDto>(Mapper.Map<List<CANScheduleConfigDto>>(SelectCanLinConfigPro.CanScheduleConfigs));
|
||
}
|
||
else
|
||
{
|
||
ListCANScheduleConfigDto = new ObservableCollection<CANScheduleConfigDto>();
|
||
}
|
||
|
||
RaisePropertyChanged(nameof(ListCANScheduleConfigDto));
|
||
}
|
||
else
|
||
{
|
||
if (SelectCanLinConfigPro.CanFdScheduleConfigs != null && SelectCanLinConfigPro.CanFdScheduleConfigs.Count > 0)
|
||
{
|
||
ListCANFdScheduleConfigDto = new ObservableCollection<CANFdScheduleConfigDto>(Mapper.Map<List<CANFdScheduleConfigDto>>(SelectCanLinConfigPro.CanFdScheduleConfigs));
|
||
}
|
||
else
|
||
{
|
||
ListCANFdScheduleConfigDto = new ObservableCollection<CANFdScheduleConfigDto>();
|
||
}
|
||
|
||
RaisePropertyChanged(nameof(ListCANFdScheduleConfigDto));
|
||
}
|
||
|
||
ResetAndTryLoadDbcSignalsForSelectedConfig();
|
||
}
|
||
|
||
/// <summary>
|
||
/// 切换配置程序时重置并尝试加载当前配置对应的 DBC 信号集合。
|
||
/// </summary>
|
||
private void ResetAndTryLoadDbcSignalsForSelectedConfig()
|
||
{
|
||
SelectedCanDbcModel = null;
|
||
|
||
// 未连接时:信号集合应以当前配置的 DBC 为准(或为空),禁止沿用上一个配置的信号列表。
|
||
if (!ZlgCanDriveService.OpenState)
|
||
{
|
||
if (string.IsNullOrWhiteSpace(CurrentDbcPath))
|
||
{
|
||
ListCanDbcModel = new ObservableCollection<CanDbcModel>();
|
||
return;
|
||
}
|
||
|
||
try
|
||
{
|
||
ListCanDbcModel = ZlgCanDriveService.StartDbc(CurrentDbcPath);
|
||
MatchSeletedAndCanDbcModel();
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
ListCanDbcModel = new ObservableCollection<CanDbcModel>();
|
||
OpTip = "DBC 解析失败";
|
||
LogService.Warn($"切换配置程序时解析 DBC 失败:{CurrentDbcPath},{ex.Message}");
|
||
}
|
||
|
||
return;
|
||
}
|
||
|
||
// 已连接时:禁止切换配置程序,理论上不会执行到这里;保底清空,避免 UI 残留。
|
||
ListCanDbcModel = new ObservableCollection<CanDbcModel>();
|
||
}
|
||
|
||
private ObservableCollection<CANScheduleConfigDto> _listCANScheduleConfigDto = new ObservableCollection<CANScheduleConfigDto>();
|
||
/// <summary>
|
||
/// CAN 调度表集合。
|
||
/// </summary>
|
||
public ObservableCollection<CANScheduleConfigDto> ListCANScheduleConfigDto
|
||
{
|
||
get { return _listCANScheduleConfigDto; }
|
||
set { _listCANScheduleConfigDto = value; RaisePropertyChanged(); }
|
||
}
|
||
|
||
private ObservableCollection<CANFdScheduleConfigDto> _listCANFdScheduleConfigDto = new ObservableCollection<CANFdScheduleConfigDto>();
|
||
/// <summary>
|
||
/// CANFD 调度表集合。
|
||
/// </summary>
|
||
public ObservableCollection<CANFdScheduleConfigDto> ListCANFdScheduleConfigDto
|
||
{
|
||
get { return _listCANFdScheduleConfigDto; }
|
||
set { _listCANFdScheduleConfigDto = value; RaisePropertyChanged(); }
|
||
}
|
||
|
||
/// <summary>
|
||
/// 当前仲裁波特率(对 CAN:等同 BaudRate;对 CANFD:ArbBaudRate)。
|
||
/// </summary>
|
||
public int CurrentArbBaudRate
|
||
{
|
||
get
|
||
{
|
||
return SelectedMode == ZlgCanMode.Can
|
||
? (SelectedCANConfigExdDto?.BaudRate ?? 0)
|
||
: (SelectedCANFdConfigExdDto?.ArbBaudRate ?? 0);
|
||
}
|
||
set
|
||
{
|
||
if (SelectedMode == ZlgCanMode.Can)
|
||
{
|
||
if (SelectedCANConfigExdDto == null) return;
|
||
SelectedCANConfigExdDto.BaudRate = value;
|
||
}
|
||
else
|
||
{
|
||
if (SelectedCANFdConfigExdDto == null) return;
|
||
SelectedCANFdConfigExdDto.ArbBaudRate = value;
|
||
}
|
||
|
||
RaisePropertyChanged();
|
||
RaisePropertyChanged(nameof(CanBaudRate));
|
||
RaisePropertyChanged(nameof(CanFdArbBaudRate));
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 当前数据波特率(对 CAN:等同 BaudRate;对 CANFD:DataBaudRate)。
|
||
/// </summary>
|
||
public int CurrentDataBaudRate
|
||
{
|
||
get
|
||
{
|
||
return SelectedMode == ZlgCanMode.Can
|
||
? (SelectedCANConfigExdDto?.BaudRate ?? 0)
|
||
: (SelectedCANFdConfigExdDto?.DataBaudRate ?? 0);
|
||
}
|
||
set
|
||
{
|
||
if (SelectedMode == ZlgCanMode.Can)
|
||
{
|
||
if (SelectedCANConfigExdDto == null) return;
|
||
SelectedCANConfigExdDto.BaudRate = value;
|
||
}
|
||
else
|
||
{
|
||
if (SelectedCANFdConfigExdDto == null) return;
|
||
SelectedCANFdConfigExdDto.DataBaudRate = value;
|
||
}
|
||
|
||
RaisePropertyChanged();
|
||
RaisePropertyChanged(nameof(CanBaudRate));
|
||
RaisePropertyChanged(nameof(CanFdDataBaudRate));
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 当前 ISO 标准使能(仅 CANFD 有意义;CAN 固定为 false)。
|
||
/// </summary>
|
||
public bool CurrentISOEnable
|
||
{
|
||
get { return SelectedMode == ZlgCanMode.Can ? false : (SelectedCANFdConfigExdDto?.ISOEnable ?? false); }
|
||
set
|
||
{
|
||
if (SelectedMode == ZlgCanMode.Can)
|
||
{
|
||
return;
|
||
}
|
||
|
||
if (SelectedCANFdConfigExdDto == null) return;
|
||
SelectedCANFdConfigExdDto.ISOEnable = value;
|
||
RaisePropertyChanged();
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 当前终端电阻使能(仅 CANFD 有意义;CAN 固定为 true(驱动侧可忽略))。
|
||
/// </summary>
|
||
public bool CurrentResEnable
|
||
{
|
||
get { return SelectedMode == ZlgCanMode.Can ? true : (SelectedCANFdConfigExdDto?.ResEnable ?? false); }
|
||
set
|
||
{
|
||
if (SelectedMode == ZlgCanMode.Can)
|
||
{
|
||
return;
|
||
}
|
||
|
||
if (SelectedCANFdConfigExdDto == null) return;
|
||
SelectedCANFdConfigExdDto.ResEnable = value;
|
||
RaisePropertyChanged();
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 构建并加载命令数据到驱动。
|
||
/// </summary>
|
||
private void BuildAndLoadCmdDataToDrive()
|
||
{
|
||
try
|
||
{
|
||
if (SelectCanLinConfigPro?.CanLinConfigContents == null)
|
||
{
|
||
ZlgCanDriveService.LoadCmdDataToDrive(new List<CanCmdData>());
|
||
return;
|
||
}
|
||
|
||
var writeItems = SelectCanLinConfigPro.CanLinConfigContents
|
||
.Where(a => a.RWInfo == RW.Write)
|
||
.ToList();
|
||
|
||
var cmdList = new List<CanCmdData>();
|
||
foreach (var item in writeItems)
|
||
{
|
||
cmdList.Add(new CanCmdData()
|
||
{
|
||
ConfigName = item.Name,
|
||
MsgName = item.MsgFrameName,
|
||
SignalName = item.SignalName,
|
||
SignalCmdValue = double.TryParse(item.DefautValue, out double result) ? result : 0,
|
||
LogicRuleDto = Mapper.Map<LogicRuleDto>(item.LogicRule),
|
||
});
|
||
}
|
||
|
||
ZlgCanDriveService.LoadCmdDataToDrive(cmdList);
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
LogService.Warn($"ZLG CAN 构建/下发 CmdData 失败:{ex.Message}");
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 当前 DBC 路径(随模式切换映射到对应 DTO)。
|
||
/// </summary>
|
||
public string? CurrentDbcPath
|
||
{
|
||
get
|
||
{
|
||
return SelectedMode == ZlgCanMode.Can
|
||
? SelectedCANConfigExdDto?.DbcPath
|
||
: SelectedCANFdConfigExdDto?.DbcPath;
|
||
}
|
||
set
|
||
{
|
||
if (SelectedMode == ZlgCanMode.Can)
|
||
{
|
||
if (SelectedCANConfigExdDto == null) return;
|
||
SelectedCANConfigExdDto.DbcPath = value;
|
||
}
|
||
else
|
||
{
|
||
if (SelectedCANFdConfigExdDto == null) return;
|
||
SelectedCANFdConfigExdDto.DbcPath = value;
|
||
}
|
||
|
||
RaisePropertyChanged();
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 当前周期(随模式切换映射到对应 DTO)。
|
||
/// </summary>
|
||
public int CurrentCycle
|
||
{
|
||
get
|
||
{
|
||
return SelectedMode == ZlgCanMode.Can
|
||
? (SelectedCANConfigExdDto?.Cycle ?? 0)
|
||
: (SelectedCANFdConfigExdDto?.Cycle ?? 0);
|
||
}
|
||
set
|
||
{
|
||
if (SelectedMode == ZlgCanMode.Can)
|
||
{
|
||
if (SelectedCANConfigExdDto == null) return;
|
||
SelectedCANConfigExdDto.Cycle = value;
|
||
}
|
||
else
|
||
{
|
||
if (SelectedCANFdConfigExdDto == null) return;
|
||
SelectedCANFdConfigExdDto.Cycle = value;
|
||
}
|
||
|
||
RaisePropertyChanged();
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 当前调度使能(随模式切换映射到对应 DTO)。
|
||
/// </summary>
|
||
public bool CurrentSchEnable
|
||
{
|
||
get
|
||
{
|
||
return SelectedMode == ZlgCanMode.Can
|
||
? (SelectedCANConfigExdDto?.SchEnable ?? false)
|
||
: (SelectedCANFdConfigExdDto?.SchEnable ?? false);
|
||
}
|
||
set
|
||
{
|
||
if (SelectedMode == ZlgCanMode.Can)
|
||
{
|
||
if (SelectedCANConfigExdDto == null) return;
|
||
SelectedCANConfigExdDto.SchEnable = value;
|
||
}
|
||
else
|
||
{
|
||
if (SelectedCANFdConfigExdDto == null) return;
|
||
SelectedCANFdConfigExdDto.SchEnable = value;
|
||
}
|
||
|
||
RaisePropertyChanged();
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// CAN 波特率。
|
||
/// </summary>
|
||
public int CanBaudRate
|
||
{
|
||
get { return SelectedCANConfigExdDto?.BaudRate ?? 0; }
|
||
set
|
||
{
|
||
if (SelectedCANConfigExdDto == null) return;
|
||
SelectedCANConfigExdDto.BaudRate = value;
|
||
RaisePropertyChanged();
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// CANFD 仲裁波特率。
|
||
/// </summary>
|
||
public int CanFdArbBaudRate
|
||
{
|
||
get { return SelectedCANFdConfigExdDto?.ArbBaudRate ?? 0; }
|
||
set
|
||
{
|
||
if (SelectedCANFdConfigExdDto == null) return;
|
||
SelectedCANFdConfigExdDto.ArbBaudRate = value;
|
||
RaisePropertyChanged();
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// CANFD 数据波特率。
|
||
/// </summary>
|
||
public int CanFdDataBaudRate
|
||
{
|
||
get { return SelectedCANFdConfigExdDto?.DataBaudRate ?? 0; }
|
||
set
|
||
{
|
||
if (SelectedCANFdConfigExdDto == null) return;
|
||
SelectedCANFdConfigExdDto.DataBaudRate = value;
|
||
RaisePropertyChanged();
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 匹配选中的配置和 DBC 模型。
|
||
/// </summary>
|
||
private void MatchSeletedAndCanDbcModel()
|
||
{
|
||
if (ListCanDbcModel == null || ListCanDbcModel.Count == 0) return;
|
||
if (SelectCanLinConfigPro?.CanLinConfigContents == null || SelectCanLinConfigPro.CanLinConfigContents.Count == 0) return;
|
||
|
||
foreach (var itemCanDbcModel in ListCanDbcModel)
|
||
{
|
||
var findData = SelectCanLinConfigPro.CanLinConfigContents.FindFirst(a => a.SignalName == itemCanDbcModel.SignalName);
|
||
if (findData != null)
|
||
{
|
||
switch (findData.RWInfo)
|
||
{
|
||
case RW.Write:
|
||
itemCanDbcModel.IsSeletedInfo = 1;
|
||
break;
|
||
case RW.Read:
|
||
itemCanDbcModel.IsSeletedInfo = 2;
|
||
break;
|
||
default:
|
||
itemCanDbcModel.IsSeletedInfo = 0;
|
||
break;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
itemCanDbcModel.IsSeletedInfo = 0;
|
||
}
|
||
}
|
||
}
|
||
|
||
private DelegateCommand<object>? _canConfigProGridSelectionChangedCmd;
|
||
/// <summary>
|
||
/// 配置程序选中变化。
|
||
/// </summary>
|
||
public DelegateCommand<object> CanConfigProGridSelectionChangedCmd
|
||
{
|
||
get
|
||
{
|
||
if (_canConfigProGridSelectionChangedCmd == null)
|
||
{
|
||
_canConfigProGridSelectionChangedCmd = new DelegateCommand<object>(CanConfigProGridSelectionChangedCmdMethod);
|
||
}
|
||
return _canConfigProGridSelectionChangedCmd;
|
||
}
|
||
}
|
||
|
||
private void CanConfigProGridSelectionChangedCmdMethod(object par)
|
||
{
|
||
if (par == null) return;
|
||
|
||
if (ZlgCanDriveService.OpenState)
|
||
{
|
||
// 打开状态下禁止切换配置程序。
|
||
return;
|
||
}
|
||
|
||
if (IsCanConfigProActive)
|
||
{
|
||
// 激活状态下禁止切换配置程序。
|
||
return;
|
||
}
|
||
if (par is SelectionChangedEventArgs) return;
|
||
|
||
if (par is CanLinConfigPro)
|
||
{
|
||
SelectCanLinConfigPro = par as CanLinConfigPro;
|
||
SyncSelectedConfig();
|
||
return;
|
||
}
|
||
|
||
var args = par as SelectionChangedEventArgs;
|
||
if (args == null || args.AddedItems == null || args.AddedItems.Count == 0) return;
|
||
|
||
var selected = args.AddedItems[0] as CanLinConfigPro;
|
||
if (selected == null) return;
|
||
|
||
SelectCanLinConfigPro = selected;
|
||
SyncSelectedConfig();
|
||
}
|
||
|
||
private DelegateCommand<object>? _canConfigProGridPreviewMouseLeftButtonDownCmd;
|
||
/// <summary>
|
||
/// 配置程序切换前拦截(对齐图莫斯 PreviewMouseLeftButtonDown)。
|
||
/// 打开/激活状态下禁止切换,防止状态错乱。
|
||
/// </summary>
|
||
public DelegateCommand<object> CanConfigProGridPreviewMouseLeftButtonDownCmd
|
||
{
|
||
get
|
||
{
|
||
if (_canConfigProGridPreviewMouseLeftButtonDownCmd == null)
|
||
{
|
||
_canConfigProGridPreviewMouseLeftButtonDownCmd = new DelegateCommand<object>(CanConfigProGridPreviewMouseLeftButtonDownCmdMethod);
|
||
}
|
||
return _canConfigProGridPreviewMouseLeftButtonDownCmd;
|
||
}
|
||
}
|
||
|
||
private void CanConfigProGridPreviewMouseLeftButtonDownCmdMethod(object par)
|
||
{
|
||
try
|
||
{
|
||
if (ZlgCanDriveService.OpenState)
|
||
{
|
||
MessageBox.Show("CAN 已连接,请先关闭后再切换配置程序", "提示", MessageBoxButton.OK, MessageBoxImage.Hand);
|
||
if (par is System.Windows.Input.MouseButtonEventArgs e) e.Handled = true;
|
||
return;
|
||
}
|
||
|
||
if (IsCanConfigProActive)
|
||
{
|
||
MessageBox.Show("当前配置程序已激活,请先取消激活后再切换", "提示", MessageBoxButton.OK, MessageBoxImage.Hand);
|
||
if (par is System.Windows.Input.MouseButtonEventArgs e) e.Handled = true;
|
||
return;
|
||
}
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
LogService.Warn($"配置切换拦截异常:{ex.Message}");
|
||
}
|
||
}
|
||
|
||
private DelegateCommand? _loadDbcCmd;
|
||
/// <summary>
|
||
/// 选择 DBC 文件。
|
||
/// </summary>
|
||
public DelegateCommand LoadDbcCmd
|
||
{
|
||
get
|
||
{
|
||
if (_loadDbcCmd == null)
|
||
{
|
||
_loadDbcCmd = new DelegateCommand(LoadDbcCmdMethod);
|
||
}
|
||
return _loadDbcCmd;
|
||
}
|
||
}
|
||
|
||
private void LoadDbcCmdMethod()
|
||
{
|
||
try
|
||
{
|
||
if (SelectCanLinConfigPro == null)
|
||
{
|
||
MessageBox.Show("选中CAN配置名称后再操作", "提示", MessageBoxButton.OK, MessageBoxImage.Hand);
|
||
return;
|
||
}
|
||
|
||
OpenFileDialog openFileDialogInfo = new OpenFileDialog();
|
||
openFileDialogInfo.Filter = "(*.dbc;*.dbc)|*.dbc;*.dbc|all|*.*";
|
||
openFileDialogInfo.CheckFileExists = true;
|
||
openFileDialogInfo.CheckPathExists = true;
|
||
var dialogResult = openFileDialogInfo.ShowDialog();
|
||
if (dialogResult != true)
|
||
{
|
||
// 用户取消:保持原值,不清空 CurrentDbcPath
|
||
return;
|
||
}
|
||
|
||
var fileName = openFileDialogInfo.FileName;
|
||
if (string.IsNullOrWhiteSpace(fileName))
|
||
{
|
||
return;
|
||
}
|
||
|
||
if (!File.Exists(fileName))
|
||
{
|
||
MessageBox.Show("文件不存在,请重新选择", "提示", MessageBoxButton.OK, MessageBoxImage.Hand);
|
||
return;
|
||
}
|
||
|
||
CurrentDbcPath = fileName;
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
LogService.Error($"选择 DBC 文件失败:{ex}");
|
||
MessageBox.Show(ex.Message, "错误", MessageBoxButton.OK, MessageBoxImage.Error);
|
||
}
|
||
}
|
||
|
||
private DelegateCommand<object>? _schEnableCmd;
|
||
/// <summary>
|
||
/// 调度使能写入驱动。
|
||
/// </summary>
|
||
public DelegateCommand<object> SchEnableCmd
|
||
{
|
||
get
|
||
{
|
||
if (_schEnableCmd == null)
|
||
{
|
||
_schEnableCmd = new DelegateCommand<object>(SchEnableCmdCall);
|
||
}
|
||
return _schEnableCmd;
|
||
}
|
||
}
|
||
|
||
private void SchEnableCmdCall(object par)
|
||
{
|
||
// 与旧 Toomoss 行为对齐:UI 勾选后立即下发到驱动
|
||
ZlgCanDriveService.SchEnable = CurrentSchEnable;
|
||
}
|
||
|
||
private DelegateCommand<string>? _canLinConfigProCmd;
|
||
/// <summary>
|
||
/// 配置程序操作(新建/修改/删除)。
|
||
/// </summary>
|
||
public DelegateCommand<string> CanLinConfigProCmd
|
||
{
|
||
get
|
||
{
|
||
if (_canLinConfigProCmd == null)
|
||
{
|
||
_canLinConfigProCmd = new DelegateCommand<string>(CanLinConfigProCmdMethod);
|
||
}
|
||
return _canLinConfigProCmd;
|
||
}
|
||
}
|
||
|
||
private void CanLinConfigProCmdMethod(string par)
|
||
{
|
||
if (string.IsNullOrWhiteSpace(par)) return;
|
||
|
||
try
|
||
{
|
||
switch (par)
|
||
{
|
||
case "Add":
|
||
if (IsCanConfigProActive)
|
||
{
|
||
MessageBox.Show("当前配置已激活,请先取消激活后再新建/修改配置程序", "提示", MessageBoxButton.OK, MessageBoxImage.Hand);
|
||
return;
|
||
}
|
||
|
||
if (ZlgCanDriveService.OpenState)
|
||
{
|
||
MessageBox.Show("请先关闭 CAN 后再新建配置程序", "提示", MessageBoxButton.OK, MessageBoxImage.Hand);
|
||
return;
|
||
}
|
||
|
||
DialogService.ShowDialog("DialogCanLinConfigCreateView", new DialogParameters() { { "Name", "" } }, r =>
|
||
{
|
||
if (r.Result != ButtonResult.OK) return;
|
||
|
||
try
|
||
{
|
||
var name = r.Parameters.GetValue<string>("Name")?.Trim();
|
||
if (string.IsNullOrWhiteSpace(name))
|
||
{
|
||
MessageBox.Show("名称不能为空", "提示", MessageBoxButton.OK, MessageBoxImage.Hand);
|
||
return;
|
||
}
|
||
|
||
var info = SelectedMode == ZlgCanMode.Can ? CANLIN.CAN : CANLIN.CANFD;
|
||
var exists = FreeSql.Select<CanLinConfigPro>()
|
||
.Where(a => a.CANLINInfo == info)
|
||
.Where(a => a.ConfigName == name)
|
||
.Any();
|
||
if (exists)
|
||
{
|
||
MessageBox.Show("名称已存在,请更换名称", "提示", MessageBoxButton.OK, MessageBoxImage.Hand);
|
||
return;
|
||
}
|
||
|
||
long newProId = 0;
|
||
|
||
FreeSql.Transaction(() =>
|
||
{
|
||
if (SelectedMode == ZlgCanMode.Can)
|
||
{
|
||
var exdList = FreeSql.Insert<CANConfigExd>(new CANConfigExd()
|
||
{
|
||
BaudRate = 500000,
|
||
DbcPath = string.Empty,
|
||
Cycle = 100,
|
||
SchEnable = false,
|
||
}).ExecuteInserted();
|
||
|
||
var exd = exdList?.FirstOrDefault();
|
||
if (exd == null)
|
||
{
|
||
throw new InvalidOperationException("创建 CAN 扩展配置失败");
|
||
}
|
||
|
||
var proList = FreeSql.Insert<CanLinConfigPro>(new CanLinConfigPro()
|
||
{
|
||
ConfigName = name,
|
||
CANLINInfo = CANLIN.CAN,
|
||
CANConfigExdId = exd.Id,
|
||
}).ExecuteInserted();
|
||
|
||
var pro = proList?.FirstOrDefault();
|
||
if (pro == null)
|
||
{
|
||
throw new InvalidOperationException("创建 CAN 配置程序失败");
|
||
}
|
||
|
||
newProId = pro.Id;
|
||
}
|
||
else
|
||
{
|
||
var exdList = FreeSql.Insert<CANFdConfigExd>(new CANFdConfigExd()
|
||
{
|
||
ArbBaudRate = 500000,
|
||
DataBaudRate = 2000000,
|
||
ISOEnable = true,
|
||
ResEnable = false,
|
||
DbcPath = string.Empty,
|
||
Cycle = 100,
|
||
SchEnable = false,
|
||
}).ExecuteInserted();
|
||
|
||
var exd = exdList?.FirstOrDefault();
|
||
if (exd == null)
|
||
{
|
||
throw new InvalidOperationException("创建 CANFD 扩展配置失败");
|
||
}
|
||
|
||
var proList = FreeSql.Insert<CanLinConfigPro>(new CanLinConfigPro()
|
||
{
|
||
ConfigName = name,
|
||
CANLINInfo = CANLIN.CANFD,
|
||
CANFdConfigExdId = exd.Id,
|
||
}).ExecuteInserted();
|
||
|
||
var pro = proList?.FirstOrDefault();
|
||
if (pro == null)
|
||
{
|
||
throw new InvalidOperationException("创建 CANFD 配置程序失败");
|
||
}
|
||
|
||
newProId = pro.Id;
|
||
}
|
||
});
|
||
|
||
InitLoadCanConfigPro();
|
||
SelectCanLinConfigPro = _canLinConfigPros.Find(a => a.Id == newProId);
|
||
SyncSelectedConfig();
|
||
MatchSeletedAndCanDbcModel();
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
LogService.Error($"ZLG 新建配置程序失败:{ex}");
|
||
MessageBox.Show(ex.Message, "错误", MessageBoxButton.OK, MessageBoxImage.Error);
|
||
}
|
||
});
|
||
break;
|
||
|
||
case "Edit":
|
||
if (SelectCanLinConfigPro == null)
|
||
{
|
||
MessageBox.Show("选中后再操作", "提示", MessageBoxButton.OK, MessageBoxImage.Hand);
|
||
return;
|
||
}
|
||
|
||
if (IsCanConfigProActive)
|
||
{
|
||
MessageBox.Show("当前配置已激活,请先取消激活后再修改配置程序", "提示", MessageBoxButton.OK, MessageBoxImage.Hand);
|
||
return;
|
||
}
|
||
|
||
if (ZlgCanDriveService.OpenState)
|
||
{
|
||
MessageBox.Show("请先关闭 CAN 后再修改配置程序", "提示", MessageBoxButton.OK, MessageBoxImage.Hand);
|
||
return;
|
||
}
|
||
|
||
DialogService.ShowDialog("DialogCanLinConfigCreateView", new DialogParameters() { { "Name", SelectCanLinConfigPro.ConfigName } }, r =>
|
||
{
|
||
if (r.Result != ButtonResult.OK) return;
|
||
|
||
try
|
||
{
|
||
var name = r.Parameters.GetValue<string>("Name")?.Trim();
|
||
if (string.IsNullOrWhiteSpace(name))
|
||
{
|
||
MessageBox.Show("名称不能为空", "提示", MessageBoxButton.OK, MessageBoxImage.Hand);
|
||
return;
|
||
}
|
||
|
||
var info = SelectedMode == ZlgCanMode.Can ? CANLIN.CAN : CANLIN.CANFD;
|
||
var exists = FreeSql.Select<CanLinConfigPro>()
|
||
.Where(a => a.CANLINInfo == info)
|
||
.Where(a => a.ConfigName == name)
|
||
.Where(a => a.Id != SelectCanLinConfigPro.Id)
|
||
.Any();
|
||
if (exists)
|
||
{
|
||
MessageBox.Show("名称已存在,请更换名称", "提示", MessageBoxButton.OK, MessageBoxImage.Hand);
|
||
return;
|
||
}
|
||
|
||
FreeSql.Update<CanLinConfigPro>()
|
||
.Set(a => a.ConfigName, name)
|
||
.Where(a => a.Id == SelectCanLinConfigPro.Id)
|
||
.ExecuteAffrows();
|
||
|
||
ReloadCurrentConfigPro();
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
LogService.Error($"ZLG 修改配置程序失败:{ex}");
|
||
MessageBox.Show(ex.Message, "错误", MessageBoxButton.OK, MessageBoxImage.Error);
|
||
}
|
||
});
|
||
break;
|
||
|
||
case "Delete":
|
||
if (SelectCanLinConfigPro == null)
|
||
{
|
||
MessageBox.Show("选中后再操作", "提示", MessageBoxButton.OK, MessageBoxImage.Hand);
|
||
return;
|
||
}
|
||
|
||
if (IsCanConfigProActive)
|
||
{
|
||
MessageBox.Show("当前配置已激活,请先取消激活后再删除配置程序", "提示", MessageBoxButton.OK, MessageBoxImage.Hand);
|
||
return;
|
||
}
|
||
|
||
if (ZlgCanDriveService.OpenState)
|
||
{
|
||
MessageBox.Show("请先关闭 CAN 后再删除配置程序", "提示", MessageBoxButton.OK, MessageBoxImage.Hand);
|
||
return;
|
||
}
|
||
|
||
if (MessageBox.Show($"确定删除配置程序:{SelectCanLinConfigPro.ConfigName}?", "确认", MessageBoxButton.OKCancel, MessageBoxImage.Warning) != MessageBoxResult.OK)
|
||
{
|
||
return;
|
||
}
|
||
|
||
// 删除主表与内容
|
||
var repo = FreeSql.GetRepository<CanLinConfigPro>();
|
||
repo.DbContextOptions.EnableCascadeSave = true;
|
||
|
||
var delList = repo.Select
|
||
.Include(a => a.CANConfigExd)
|
||
.Include(a => a.CANFdConfigExd)
|
||
.IncludeMany(a => a.CanLinConfigContents)
|
||
.IncludeMany(a => a.CanScheduleConfigs)
|
||
.IncludeMany(a => a.CanFdScheduleConfigs)
|
||
.Where(a => a.Id == SelectCanLinConfigPro.Id)
|
||
.ToList();
|
||
|
||
repo.Delete(delList);
|
||
foreach (var item in delList)
|
||
{
|
||
// 允许配置在 CAN/CANFD 间切换保存后同时具备两套扩展表,此处统一清理避免残留孤儿记录。
|
||
if (item.CANConfigExdId > 0)
|
||
{
|
||
FreeSql.Delete<CANConfigExd>(item.CANConfigExdId).ExecuteAffrows();
|
||
}
|
||
if (item.CANFdConfigExdId > 0)
|
||
{
|
||
FreeSql.Delete<CANFdConfigExd>(item.CANFdConfigExdId).ExecuteAffrows();
|
||
}
|
||
}
|
||
|
||
SelectCanLinConfigPro = null;
|
||
SelectedCANConfigExdDto = null;
|
||
SelectedCANFdConfigExdDto = null;
|
||
InitLoadCanConfigPro();
|
||
ListCanDbcModel = new ObservableCollection<CanDbcModel>();
|
||
break;
|
||
|
||
case "Active":
|
||
// 激活到取消的状态的判断
|
||
if (IsCanConfigProActive)
|
||
{
|
||
IsCanConfigProActive = false;
|
||
IsCANConfigDatagridActive = true;
|
||
|
||
// 停止调度/发送,避免“取消激活但仍在发送”
|
||
ZlgCanDriveService.StopSchedule();
|
||
ZlgCanDriveService.IsCycleSend = false;
|
||
ZlgCanDriveService.LoadCmdDataToDrive(new List<CanCmdData>());
|
||
|
||
OpTip = "已取消激活";
|
||
return;
|
||
}
|
||
|
||
if (!ZlgCanDriveService.OpenState)
|
||
{
|
||
MessageBox.Show("请确保 CAN 已连接后再激活", "提示", MessageBoxButton.OK, MessageBoxImage.Hand);
|
||
return;
|
||
}
|
||
|
||
if (SelectCanLinConfigPro == null)
|
||
{
|
||
MessageBox.Show("选中后再操作", "提示", MessageBoxButton.OK, MessageBoxImage.Hand);
|
||
return;
|
||
}
|
||
|
||
if (string.IsNullOrWhiteSpace(CurrentDbcPath))
|
||
{
|
||
MessageBox.Show("请先选择并解析 DBC 文件后再激活", "提示", MessageBoxButton.OK, MessageBoxImage.Hand);
|
||
return;
|
||
}
|
||
|
||
// 激活前强制按“当前配置的 DBC 路径”重新解析,避免 DbcParserState 来自其它配置导致错配。
|
||
try
|
||
{
|
||
ListCanDbcModel = ZlgCanDriveService.StartDbc(CurrentDbcPath);
|
||
MatchSeletedAndCanDbcModel();
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
LogService.Error($"ZLG 激活前解析 DBC 失败:{ex}");
|
||
MessageBox.Show(ex.Message, "错误", MessageBoxButton.OK, MessageBoxImage.Error);
|
||
return;
|
||
}
|
||
|
||
IsCanConfigProActive = true;
|
||
IsCANConfigDatagridActive = false;
|
||
|
||
// 当前使用的配置程序
|
||
ZlgCanDriveService.InitCanConfig(SelectCanLinConfigPro);
|
||
|
||
// 下发指令集合与调度表
|
||
BuildAndLoadCmdDataToDrive();
|
||
if (SelectedMode == ZlgCanMode.Can)
|
||
{
|
||
ZlgCanDriveService.SetScheduleConfigs(ListCANScheduleConfigDto?.ToList() ?? new List<CANScheduleConfigDto>());
|
||
}
|
||
else
|
||
{
|
||
ZlgCanDriveService.SetScheduleConfigs(ListCANFdScheduleConfigDto?.ToList() ?? new List<CANFdScheduleConfigDto>());
|
||
}
|
||
|
||
OpTip = "已激活当前配置";
|
||
break;
|
||
}
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
LogService.Error($"ZLG 配置程序操作失败:{par},{ex}");
|
||
MessageBox.Show(ex.Message, "错误", MessageBoxButton.OK, MessageBoxImage.Error);
|
||
}
|
||
}
|
||
|
||
private DelegateCommand? _scheduleConfigCmd;
|
||
/// <summary>
|
||
/// 调度表配置(弹窗)。
|
||
/// </summary>
|
||
public DelegateCommand ScheduleConfigCmd
|
||
{
|
||
get
|
||
{
|
||
if (_scheduleConfigCmd == null)
|
||
{
|
||
_scheduleConfigCmd = new DelegateCommand(ScheduleConfigCmdMethod);
|
||
}
|
||
return _scheduleConfigCmd;
|
||
}
|
||
}
|
||
|
||
private void ScheduleConfigCmdMethod()
|
||
{
|
||
try
|
||
{
|
||
if (SelectCanLinConfigPro == null)
|
||
{
|
||
MessageBox.Show("选中CAN配置名称后再操作", "提示", MessageBoxButton.OK, MessageBoxImage.Hand);
|
||
return;
|
||
}
|
||
|
||
var msgList = ZlgCanDriveService.CmdData.GroupBy(a => a.MsgName).Select(a => a.Key).Where(a => !string.IsNullOrWhiteSpace(a)).ToList();
|
||
if (msgList == null || msgList.Count == 0)
|
||
{
|
||
MessageBox.Show("未发现写入指令数据(CmdData 为空),无法配置调度表", "提示", MessageBoxButton.OK, MessageBoxImage.Hand);
|
||
return;
|
||
}
|
||
|
||
if (SelectedMode == ZlgCanMode.Can)
|
||
{
|
||
DialogService.ShowDialog("DialogCANSchConfigView", new DialogParameters()
|
||
{
|
||
{ "ListMsg", msgList },
|
||
{ "ListCANScheduleConfigDto", ListCANScheduleConfigDto },
|
||
{ "SelectCanLinConfigProId", SelectCanLinConfigPro.Id },
|
||
}, r =>
|
||
{
|
||
if (r.Result != ButtonResult.OK) return;
|
||
ListCANScheduleConfigDto = r.Parameters.GetValue<ObservableCollection<CANScheduleConfigDto>>("ReturnValue") ?? new ObservableCollection<CANScheduleConfigDto>();
|
||
SelectCanLinConfigPro.CanScheduleConfigs = Mapper.Map<List<CANScheduleConfig>>(ListCANScheduleConfigDto.ToList());
|
||
ReloadCurrentConfigPro();
|
||
});
|
||
}
|
||
else
|
||
{
|
||
DialogService.ShowDialog("DialogCANFdSchConfigView", new DialogParameters()
|
||
{
|
||
{ "ListMsg", msgList },
|
||
{ "ListCANFdScheduleConfigDto", ListCANFdScheduleConfigDto },
|
||
{ "SelectCanLinConfigProId", SelectCanLinConfigPro.Id },
|
||
}, r =>
|
||
{
|
||
if (r.Result != ButtonResult.OK) return;
|
||
ListCANFdScheduleConfigDto = r.Parameters.GetValue<ObservableCollection<CANFdScheduleConfigDto>>("ReturnValue") ?? new ObservableCollection<CANFdScheduleConfigDto>();
|
||
SelectCanLinConfigPro.CanFdScheduleConfigs = Mapper.Map<List<CANFdScheduleConfig>>(ListCANFdScheduleConfigDto.ToList());
|
||
ReloadCurrentConfigPro();
|
||
});
|
||
}
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
LogService.Error($"调度表配置失败:{ex}");
|
||
MessageBox.Show(ex.Message, "错误", MessageBoxButton.OK, MessageBoxImage.Error);
|
||
}
|
||
}
|
||
|
||
private DelegateCommand<string>? _writeReadConfigCmd;
|
||
/// <summary>
|
||
/// 写入/读取/删除 信号配置项。
|
||
/// </summary>
|
||
public DelegateCommand<string> WriteReadConfigCmd
|
||
{
|
||
get
|
||
{
|
||
if (_writeReadConfigCmd == null)
|
||
{
|
||
_writeReadConfigCmd = new DelegateCommand<string>(WriteReadConfigCmdMethod);
|
||
}
|
||
return _writeReadConfigCmd;
|
||
}
|
||
}
|
||
|
||
private void WriteReadConfigCmdMethod(string par)
|
||
{
|
||
if (string.IsNullOrWhiteSpace(par)) return;
|
||
|
||
if (SelectCanLinConfigPro == null)
|
||
{
|
||
MessageBox.Show("选中CAN配置名称后再操作", "提示", MessageBoxButton.OK, MessageBoxImage.Hand);
|
||
return;
|
||
}
|
||
|
||
if (string.Equals(par, "OpenDialog", StringComparison.OrdinalIgnoreCase))
|
||
{
|
||
if (!ZlgCanDriveService.OpenState)
|
||
{
|
||
MessageBox.Show("当前未连接 CAN/CANFD,无法打开【读写设置】。请先连接设备后再操作。", "提示", MessageBoxButton.OK, MessageBoxImage.Hand);
|
||
return;
|
||
}
|
||
|
||
if (ListCanDbcModel == null || ListCanDbcModel.Count == 0)
|
||
{
|
||
MessageBox.Show("当前信号集合为空,无法打开【读写设置】。请先解析 DBC 并确保信号列表已加载后再操作。", "提示", MessageBoxButton.OK, MessageBoxImage.Hand);
|
||
return;
|
||
}
|
||
|
||
OpenRwDialog();
|
||
return;
|
||
}
|
||
|
||
if (IsCanConfigProActive)
|
||
{
|
||
MessageBox.Show("当前配置已激活,请先取消激活后再修改写入/读取配置", "提示", MessageBoxButton.OK, MessageBoxImage.Hand);
|
||
return;
|
||
}
|
||
|
||
if (SelectedCanDbcModel == null)
|
||
{
|
||
MessageBox.Show("请在右侧信号表中选中一个信号后再操作", "提示", MessageBoxButton.OK, MessageBoxImage.Hand);
|
||
return;
|
||
}
|
||
|
||
if (string.IsNullOrWhiteSpace(SelectedCanDbcModel.SignalName) || string.IsNullOrWhiteSpace(SelectedCanDbcModel.MsgName))
|
||
{
|
||
MessageBox.Show("选中的信号数据不完整(SignalName/MsgName 为空)", "提示", MessageBoxButton.OK, MessageBoxImage.Hand);
|
||
return;
|
||
}
|
||
|
||
try
|
||
{
|
||
if (par == "Delete")
|
||
{
|
||
FreeSql.Delete<CanLinRWConfig>()
|
||
.Where(a => a.CanLinConfigProId == SelectCanLinConfigPro.Id)
|
||
.Where(a => a.SignalName == SelectedCanDbcModel.SignalName)
|
||
.ExecuteAffrows();
|
||
|
||
ReloadCurrentConfigPro();
|
||
OpTip = "已删除配置项";
|
||
return;
|
||
}
|
||
|
||
var rw = par == "Write" ? RW.Write : RW.Read;
|
||
|
||
// 防重复:同一个 SignalName + RWInfo 只允许一条
|
||
var exists = FreeSql.Select<CanLinRWConfig>()
|
||
.Where(a => a.CanLinConfigProId == SelectCanLinConfigPro.Id)
|
||
.Where(a => a.SignalName == SelectedCanDbcModel.SignalName)
|
||
.Where(a => a.RWInfo == rw)
|
||
.Any();
|
||
|
||
if (exists)
|
||
{
|
||
OpTip = "配置已存在";
|
||
return;
|
||
}
|
||
|
||
FreeSql.Insert<CanLinRWConfig>(new CanLinRWConfig()
|
||
{
|
||
Name = SelectedCanDbcModel.SignalName,
|
||
SignalName = SelectedCanDbcModel.SignalName,
|
||
MsgFrameName = SelectedCanDbcModel.MsgName,
|
||
CanLinConfigProId = SelectCanLinConfigPro.Id,
|
||
DefautValue = "0",
|
||
RWInfo = rw,
|
||
LogicRuleId = 0,
|
||
}).ExecuteInserted();
|
||
|
||
ReloadCurrentConfigPro();
|
||
OpTip = rw == RW.Write ? "已加入写入配置" : "已加入读取配置";
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
LogService.Error($"ZLG 写入/读取配置操作失败:{par},{ex}");
|
||
MessageBox.Show(ex.Message, "错误", MessageBoxButton.OK, MessageBoxImage.Error);
|
||
}
|
||
}
|
||
|
||
private void ReloadCurrentConfigPro()
|
||
{
|
||
var id = SelectCanLinConfigPro?.Id;
|
||
InitLoadCanConfigPro();
|
||
|
||
if (id != null)
|
||
{
|
||
SelectCanLinConfigPro = _canLinConfigPros.Find(a => a.Id == id.Value);
|
||
SyncSelectedConfig();
|
||
}
|
||
|
||
MatchSeletedAndCanDbcModel();
|
||
}
|
||
|
||
private DelegateCommand<string>? _canOpCmd;
|
||
/// <summary>
|
||
/// CAN 操作命令。
|
||
/// </summary>
|
||
public DelegateCommand<string> CanOpCmd
|
||
{
|
||
get
|
||
{
|
||
if (_canOpCmd == null)
|
||
{
|
||
_canOpCmd = new DelegateCommand<string>(CanOpCmdMethod);
|
||
}
|
||
return _canOpCmd;
|
||
}
|
||
}
|
||
|
||
private void CanOpCmdMethod(string par)
|
||
{
|
||
if (string.IsNullOrWhiteSpace(par))
|
||
{
|
||
return;
|
||
}
|
||
|
||
try
|
||
{
|
||
switch (par)
|
||
{
|
||
case "Open":
|
||
if (ComActionService.IsCanToDoWork() == false)
|
||
{
|
||
MessageBox.Show("请关闭LIN连接后才能开启CAN,同一个时刻只能有一个通信驱动压缩机", "提示", MessageBoxButton.OK, MessageBoxImage.Hand);
|
||
return;
|
||
}
|
||
|
||
if (ZlgLinDriveService.OpenState)
|
||
{
|
||
MessageBox.Show("请先关闭 ZLG LIN 连接后再开启 ZLG CAN", "提示", MessageBoxButton.OK, MessageBoxImage.Hand);
|
||
return;
|
||
}
|
||
|
||
if (SelectCanLinConfigPro == null)
|
||
{
|
||
MessageBox.Show("选中CAN配置名称后再操作", "提示", MessageBoxButton.OK, MessageBoxImage.Hand);
|
||
return;
|
||
}
|
||
|
||
if (SelectedMode == ZlgCanMode.Can)
|
||
{
|
||
if (SelectedCANConfigExdDto == null)
|
||
{
|
||
MessageBox.Show("CAN配置为空", "提示", MessageBoxButton.OK, MessageBoxImage.Hand);
|
||
return;
|
||
}
|
||
|
||
// ZLG 底层实际为 CANFD 通道,CAN 经典帧使用 arbitration 波特率(data 亦沿用,保持一致即可)
|
||
ZlgCanDriveService.UpdateConfig(0, (uint)SelectedCANConfigExdDto.BaudRate, (uint)SelectedCANConfigExdDto.BaudRate, resEnable: true);
|
||
}
|
||
else
|
||
{
|
||
if (SelectedCANFdConfigExdDto == null)
|
||
{
|
||
MessageBox.Show("CANFD配置为空", "提示", MessageBoxButton.OK, MessageBoxImage.Hand);
|
||
return;
|
||
}
|
||
|
||
ZlgCanDriveService.UpdateConfig(0, (uint)SelectedCANFdConfigExdDto.ArbBaudRate, (uint)SelectedCANFdConfigExdDto.DataBaudRate, SelectedCANFdConfigExdDto.ResEnable);
|
||
}
|
||
|
||
ZlgCanDriveService.StartCanDrive();
|
||
|
||
if (ZlgCanDriveService.OpenState)
|
||
{
|
||
LastError = null;
|
||
OpTip = "CAN 已连接";
|
||
ConfigService.CanLinRunStateModel.CurSysSelectedCanLin = SelectedMode == ZlgCanMode.Can ? CanLinEnum.Can : CanLinEnum.CANFD;
|
||
}
|
||
else
|
||
{
|
||
OpTip = "CAN 连接失败";
|
||
MessageBox.Show("CAN 连接失败(OpenState=false),请检查设备/驱动/参数。", "提示", MessageBoxButton.OK, MessageBoxImage.Hand);
|
||
return;
|
||
}
|
||
|
||
// 自动解析 DBC
|
||
if (!string.IsNullOrWhiteSpace(CurrentDbcPath))
|
||
{
|
||
ListCanDbcModel = ZlgCanDriveService.StartDbc(CurrentDbcPath);
|
||
MatchSeletedAndCanDbcModel();
|
||
}
|
||
|
||
// 将当前配置的 CmdData 下发到驱动(用于事件驱动增量发送)
|
||
BuildAndLoadCmdDataToDrive();
|
||
|
||
break;
|
||
|
||
case "Close":
|
||
ZlgCanDriveService.CloseDevice();
|
||
ConfigService.CanLinRunStateModel.CurSysSelectedCanLin = CanLinEnum.No;
|
||
LastError = null;
|
||
OpTip = "CAN 已关闭";
|
||
|
||
// 关闭设备时自动退出激活,恢复可切换状态
|
||
IsCanConfigProActive = false;
|
||
IsCANConfigDatagridActive = true;
|
||
break;
|
||
|
||
case "Parse":
|
||
if (!ZlgCanDriveService.OpenState)
|
||
{
|
||
MessageBox.Show("请先打开CAN后再解析", "提示", MessageBoxButton.OK, MessageBoxImage.Hand);
|
||
return;
|
||
}
|
||
|
||
if (string.IsNullOrWhiteSpace(CurrentDbcPath))
|
||
{
|
||
MessageBox.Show("请选择DBC文件后再操作", "提示", MessageBoxButton.OKCancel, MessageBoxImage.Hand);
|
||
return;
|
||
}
|
||
|
||
ListCanDbcModel = ZlgCanDriveService.StartDbc(CurrentDbcPath);
|
||
MatchSeletedAndCanDbcModel();
|
||
LastError = null;
|
||
OpTip = "DBC 已解析";
|
||
break;
|
||
|
||
case "CycleSend":
|
||
if (!ZlgCanDriveService.OpenState)
|
||
{
|
||
MessageBox.Show("请先打开 CAN 后再进行循环发送", "提示", MessageBoxButton.OK, MessageBoxImage.Hand);
|
||
return;
|
||
}
|
||
|
||
if (!ZlgCanDriveService.DbcParserState)
|
||
{
|
||
MessageBox.Show("请先解析 DBC 后再进行循环发送", "提示", MessageBoxButton.OK, MessageBoxImage.Hand);
|
||
return;
|
||
}
|
||
|
||
// 与图莫斯一致:第一次点击开启,第二次点击关闭
|
||
if (!ZlgCanDriveService.IsCycleSend)
|
||
{
|
||
// 开启前:确保最新 CmdData 已下发
|
||
BuildAndLoadCmdDataToDrive();
|
||
|
||
// 同步 SchEnable(防止 UI 勾选但未触发 Command 导致服务端状态不一致)
|
||
ZlgCanDriveService.SchEnable = CurrentSchEnable;
|
||
|
||
if (ZlgCanDriveService.SchEnable)
|
||
{
|
||
// 使用调度表:校验每个 MsgName 都配置了周期
|
||
var groupMsg = ZlgCanDriveService.CmdData
|
||
.Where(a => !string.IsNullOrWhiteSpace(a.MsgName))
|
||
.GroupBy(a => a.MsgName)
|
||
.Select(g => g.Key)
|
||
.ToList();
|
||
|
||
if (groupMsg.Count == 0)
|
||
{
|
||
MessageBox.Show("未发现可发送的消息帧(CmdData.MsgName 为空)", "提示", MessageBoxButton.OK, MessageBoxImage.Hand);
|
||
return;
|
||
}
|
||
|
||
if (SelectedMode == ZlgCanMode.Can)
|
||
{
|
||
foreach (var msg in groupMsg)
|
||
{
|
||
if (!ListCANScheduleConfigDto.Any(a => string.Equals(a.MsgName, msg, StringComparison.Ordinal)))
|
||
{
|
||
MessageBox.Show($"你使能了调度表,但是调度表中没有设置【{msg}】信息,请设置后再操作", "提示", MessageBoxButton.OK, MessageBoxImage.Hand);
|
||
return;
|
||
}
|
||
}
|
||
|
||
if (ListCANScheduleConfigDto == null || ListCANScheduleConfigDto.Count == 0)
|
||
{
|
||
MessageBox.Show("调度表配置为空数据,请检查!将无法发送数据", "提示", MessageBoxButton.OK, MessageBoxImage.Hand);
|
||
return;
|
||
}
|
||
|
||
ZlgCanDriveService.SetScheduleConfigs(ListCANScheduleConfigDto.ToList());
|
||
}
|
||
else
|
||
{
|
||
foreach (var msg in groupMsg)
|
||
{
|
||
if (!ListCANFdScheduleConfigDto.Any(a => string.Equals(a.MsgName, msg, StringComparison.Ordinal)))
|
||
{
|
||
MessageBox.Show($"你使能了调度表,但是调度表中没有设置【{msg}】信息,请设置后再操作", "提示", MessageBoxButton.OK, MessageBoxImage.Hand);
|
||
return;
|
||
}
|
||
}
|
||
|
||
if (ListCANFdScheduleConfigDto == null || ListCANFdScheduleConfigDto.Count == 0)
|
||
{
|
||
MessageBox.Show("调度表配置为空数据,请检查!将无法发送数据", "提示", MessageBoxButton.OK, MessageBoxImage.Hand);
|
||
return;
|
||
}
|
||
|
||
ZlgCanDriveService.SetScheduleConfigs(ListCANFdScheduleConfigDto.ToList());
|
||
}
|
||
|
||
ZlgCanDriveService.StartSchedule();
|
||
}
|
||
else
|
||
{
|
||
// 不使用调度表:按当前配置周期做精确循环发送
|
||
var cycle = Math.Max(1, CurrentCycle);
|
||
ZlgCanDriveService.StartPrecisionCycleSend(cycle);
|
||
}
|
||
|
||
OpTip = "循环发送:已开启";
|
||
}
|
||
else
|
||
{
|
||
ZlgCanDriveService.IsCycleSend = false;
|
||
ZlgCanDriveService.StopSchedule();
|
||
OpTip = "循环发送:已关闭";
|
||
}
|
||
break;
|
||
|
||
case "CycleRecive":
|
||
ZlgCanDriveService.SetReceiveEnabled(!ZlgCanDriveService.IsCycleRevice);
|
||
OpTip = ZlgCanDriveService.IsCycleRevice ? "循环接收:已开启" : "循环接收:已关闭";
|
||
break;
|
||
|
||
case "Save":
|
||
if (SelectCanLinConfigPro == null)
|
||
{
|
||
MessageBox.Show("选中CAN配置名称后再操作", "提示", MessageBoxButton.OK, MessageBoxImage.Hand);
|
||
return;
|
||
}
|
||
|
||
// 允许在 UI 上修改当前配置的模式(CAN/CANFD),保存时同步更新 CanLinConfigPro.CANLINInfo。
|
||
FreeSql.Transaction(() =>
|
||
{
|
||
if (SelectedMode == ZlgCanMode.Can)
|
||
{
|
||
if (SelectedCANConfigExdDto == null || SelectedCANConfigExdDto.Id <= 0)
|
||
{
|
||
// 若原配置为 CANFD,切换到 CAN 时可能尚未存在 CAN 扩展配置,这里按默认值创建。
|
||
var inserted = FreeSql.Insert<CANConfigExd>(new CANConfigExd()
|
||
{
|
||
BaudRate = 500000,
|
||
DbcPath = string.Empty,
|
||
Cycle = 100,
|
||
SchEnable = false,
|
||
}).ExecuteInserted();
|
||
var exd = inserted?.FirstOrDefault();
|
||
if (exd == null) throw new InvalidOperationException("创建 CAN 扩展配置失败");
|
||
SelectedCANConfigExdDto = Mapper.Map<CANConfigExdDto>(exd);
|
||
}
|
||
|
||
FreeSql.Update<CANConfigExd>()
|
||
.Set(a => a.DbcPath, SelectedCANConfigExdDto.DbcPath)
|
||
.Set(a => a.Cycle, SelectedCANConfigExdDto.Cycle)
|
||
.Set(a => a.BaudRate, SelectedCANConfigExdDto.BaudRate)
|
||
.Set(a => a.SchEnable, SelectedCANConfigExdDto.SchEnable)
|
||
.Where(a => a.Id == SelectedCANConfigExdDto.Id)
|
||
.ExecuteUpdated();
|
||
|
||
FreeSql.Update<CanLinConfigPro>()
|
||
.Set(a => a.CANLINInfo, CANLIN.CAN)
|
||
.Set(a => a.CANConfigExdId, SelectedCANConfigExdDto.Id)
|
||
.Where(a => a.Id == SelectCanLinConfigPro.Id)
|
||
.ExecuteAffrows();
|
||
}
|
||
else
|
||
{
|
||
if (SelectedCANFdConfigExdDto == null || SelectedCANFdConfigExdDto.Id <= 0)
|
||
{
|
||
// 若原配置为 CAN,切换到 CANFD 时可能尚未存在 CANFD 扩展配置,这里按默认值创建。
|
||
var inserted = FreeSql.Insert<CANFdConfigExd>(new CANFdConfigExd()
|
||
{
|
||
ArbBaudRate = 500000,
|
||
DataBaudRate = 2000000,
|
||
ISOEnable = true,
|
||
ResEnable = false,
|
||
DbcPath = string.Empty,
|
||
Cycle = 100,
|
||
SchEnable = false,
|
||
}).ExecuteInserted();
|
||
var exd = inserted?.FirstOrDefault();
|
||
if (exd == null) throw new InvalidOperationException("创建 CANFD 扩展配置失败");
|
||
SelectedCANFdConfigExdDto = Mapper.Map<CANFdConfigExdDto>(exd);
|
||
}
|
||
|
||
FreeSql.Update<CANFdConfigExd>()
|
||
.Set(a => a.DbcPath, SelectedCANFdConfigExdDto.DbcPath)
|
||
.Set(a => a.Cycle, SelectedCANFdConfigExdDto.Cycle)
|
||
.Set(a => a.DataBaudRate, SelectedCANFdConfigExdDto.DataBaudRate)
|
||
.Set(a => a.ArbBaudRate, SelectedCANFdConfigExdDto.ArbBaudRate)
|
||
.Set(a => a.ISOEnable, SelectedCANFdConfigExdDto.ISOEnable)
|
||
.Set(a => a.ResEnable, SelectedCANFdConfigExdDto.ResEnable)
|
||
.Set(a => a.SchEnable, SelectedCANFdConfigExdDto.SchEnable)
|
||
.Where(a => a.Id == SelectedCANFdConfigExdDto.Id)
|
||
.ExecuteUpdated();
|
||
|
||
FreeSql.Update<CanLinConfigPro>()
|
||
.Set(a => a.CANLINInfo, CANLIN.CANFD)
|
||
.Set(a => a.CANFdConfigExdId, SelectedCANFdConfigExdDto.Id)
|
||
.Where(a => a.Id == SelectCanLinConfigPro.Id)
|
||
.ExecuteAffrows();
|
||
}
|
||
});
|
||
|
||
ReloadCurrentConfigPro();
|
||
LastError = null;
|
||
OpTip = "配置已保存";
|
||
break;
|
||
}
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
LastError = ex.Message;
|
||
OpTip = "操作失败";
|
||
LogService.Error($"ZLG CAN 操作失败:{par},{ex}");
|
||
MessageBox.Show(ex.Message, "错误", MessageBoxButton.OK, MessageBoxImage.Error);
|
||
}
|
||
}
|
||
}
|
||
}
|