using AutoMapper; using CapMachine.Core; using CapMachine.Model.CANLIN; using CapMachine.Wpf.CanDrive; using CapMachine.Wpf.Dtos; using CapMachine.Wpf.Services; 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.Linq; using System.Windows; using System.Windows.Controls; using static CapMachine.Wpf.Models.ComEnum; namespace CapMachine.Wpf.ViewModels { /// /// ZLG CAN/CANFD 合并配置 ViewModel(模式切换:单选)。 /// public class ZlgCanDriveConfigViewModel : NavigationViewModel { /// /// 构造函数。 /// 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; InitLoadCanConfigPro(); } /// /// Dialog 服务。 /// public IDialogService DialogService { get; } /// /// FreeSql。 /// public IFreeSql FreeSql { get; } /// /// 事件聚合。 /// public IEventAggregator EventAggregator { get; } /// /// 区域导航。 /// public IRegionManager RegionManager { get; } /// /// 系统运行服务。 /// public SysRunService SysRunService { get; } /// /// 通信互斥控制。 /// public ComActionService ComActionService { get; } /// /// 日志。 /// public ILogService LogService { get; } /// /// 逻辑规则服务。 /// public LogicRuleService LogicRuleService { get; } /// /// 配置服务。 /// public ConfigService ConfigService { get; } /// /// ZLG CAN 服务。 /// public ZlgCanDriveService ZlgCanDriveService { get; } /// /// ZLG LIN 服务(用于互斥判断)。 /// public ZlgLinDriveService ZlgLinDriveService { get; } /// /// Mapper。 /// public IMapper Mapper { get; } private List _canLinConfigPros = new List(); private string? _opTip; /// /// 操作提示(用于 UI 状态展示)。 /// public string? OpTip { get { return _opTip; } set { _opTip = value; RaisePropertyChanged(); } } private string? _lastError; /// /// 最近一次错误信息(用于 UI 状态展示)。 /// public string? LastError { get { return _lastError; } set { _lastError = value; RaisePropertyChanged(); } } private ZlgCanMode _selectedMode; /// /// 模式选择:CAN/CANFD(单选)。 /// public ZlgCanMode SelectedMode { get { return _selectedMode; } set { _selectedMode = value; RaisePropertyChanged(); RaisePropertyChanged(nameof(DbcPathTitle)); RaisePropertyChanged(nameof(SelectedModeKey)); RaisePropertyChanged(nameof(CurrentDbcPath)); RaisePropertyChanged(nameof(CurrentCycle)); RaisePropertyChanged(nameof(CurrentSchEnable)); RaisePropertyChanged(nameof(CanBaudRate)); RaisePropertyChanged(nameof(CanFdArbBaudRate)); RaisePropertyChanged(nameof(CanFdDataBaudRate)); RaisePropertyChanged(nameof(ConnectButtonText)); ZlgCanDriveService.Mode = value; InitLoadCanConfigPro(); } } /// /// 连接按钮文字(对齐 Toomoss 风格)。 /// public string ConnectButtonText { get { return SelectedMode == ZlgCanMode.Can ? "连接CAN" : "连接CANFD"; } } /// /// 绑定用:模式 Key(Can/CanFd)。 /// public string SelectedModeKey { get { return SelectedMode == ZlgCanMode.Can ? "Can" : "CanFd"; } set { 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; } } } /// /// DBC 路径标题。 /// public string DbcPathTitle { get { return SelectedMode == ZlgCanMode.Can ? "CAN DBC 文件路径:" : "CANFD DBC 文件路径:"; } } private ObservableCollection? _listCanLinConfigPro; /// /// 配置程序集合。 /// public ObservableCollection? ListCanLinConfigPro { get { return _listCanLinConfigPro; } set { _listCanLinConfigPro = value; RaisePropertyChanged(); } } /// /// 选中的配置程序。 /// public CanLinConfigPro? SelectCanLinConfigPro { get; set; } private ObservableCollection? _listCanDbcModel; /// /// DBC 信号集合。 /// public ObservableCollection? ListCanDbcModel { get { return _listCanDbcModel; } set { _listCanDbcModel = value; RaisePropertyChanged(); } } /// /// 当前选中的 DBC 信号。 /// public CanDbcModel? SelectedCanDbcModel { get; set; } private CANConfigExdDto? _selectedCANConfigExdDto; /// /// CAN 配置 DTO。 /// public CANConfigExdDto? SelectedCANConfigExdDto { get { return _selectedCANConfigExdDto; } set { _selectedCANConfigExdDto = value; RaisePropertyChanged(); } } private CANFdConfigExdDto? _selectedCANFdConfigExdDto; /// /// CANFD 配置 DTO。 /// public CANFdConfigExdDto? SelectedCANFdConfigExdDto { get { return _selectedCANFdConfigExdDto; } set { _selectedCANFdConfigExdDto = value; RaisePropertyChanged(); } } private void InitLoadCanConfigPro() { var info = SelectedMode == ZlgCanMode.Can ? CANLIN.CAN : CANLIN.CANFD; _canLinConfigPros = FreeSql.Select() .Where(a => a.CANLINInfo == info) .Include(a => a.CANConfigExd) .Include(a => a.CANFdConfigExd) .IncludeMany(a => a.CanLinConfigContents, then => then.Include(b => b.LogicRule)) .ToList(); ListCanLinConfigPro = new ObservableCollection(_canLinConfigPros); } private void SyncSelectedConfig() { if (SelectCanLinConfigPro == null) { return; } if (SelectedMode == ZlgCanMode.Can) { SelectedCANConfigExdDto = Mapper.Map(SelectCanLinConfigPro.CANConfigExd); SelectedCANFdConfigExdDto = null; } else { SelectedCANFdConfigExdDto = Mapper.Map(SelectCanLinConfigPro.CANFdConfigExd); SelectedCANConfigExdDto = null; } RaisePropertyChanged(nameof(CurrentDbcPath)); RaisePropertyChanged(nameof(CurrentCycle)); RaisePropertyChanged(nameof(CurrentSchEnable)); RaisePropertyChanged(nameof(CanBaudRate)); RaisePropertyChanged(nameof(CanFdArbBaudRate)); RaisePropertyChanged(nameof(CanFdDataBaudRate)); } /// /// 当前 DBC 路径(随模式切换映射到对应 DTO)。 /// 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(); } } /// /// 当前周期(随模式切换映射到对应 DTO)。 /// 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(); } } /// /// 当前调度使能(随模式切换映射到对应 DTO)。 /// 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(); } } /// /// CAN 波特率。 /// public int CanBaudRate { get { return SelectedCANConfigExdDto?.BaudRate ?? 0; } set { if (SelectedCANConfigExdDto == null) return; SelectedCANConfigExdDto.BaudRate = value; RaisePropertyChanged(); } } /// /// CANFD 仲裁波特率。 /// public int CanFdArbBaudRate { get { return SelectedCANFdConfigExdDto?.ArbBaudRate ?? 0; } set { if (SelectedCANFdConfigExdDto == null) return; SelectedCANFdConfigExdDto.ArbBaudRate = value; RaisePropertyChanged(); } } /// /// CANFD 数据波特率。 /// public int CanFdDataBaudRate { get { return SelectedCANFdConfigExdDto?.DataBaudRate ?? 0; } set { if (SelectedCANFdConfigExdDto == null) return; SelectedCANFdConfigExdDto.DataBaudRate = value; RaisePropertyChanged(); } } 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? _canConfigProGridSelectionChangedCmd; /// /// 配置程序选中变化。 /// public DelegateCommand CanConfigProGridSelectionChangedCmd { get { if (_canConfigProGridSelectionChangedCmd == null) { _canConfigProGridSelectionChangedCmd = new DelegateCommand(CanConfigProGridSelectionChangedCmdMethod); } return _canConfigProGridSelectionChangedCmd; } } private void CanConfigProGridSelectionChangedCmdMethod(object par) { if (par == null) 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? _loadDbcCmd; /// /// 选择 DBC 文件。 /// 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; openFileDialogInfo.ShowDialog(); string fileName = openFileDialogInfo.FileName; CurrentDbcPath = fileName; } catch { MessageBox.Show("可能未选择信息", "提示", MessageBoxButton.OKCancel, MessageBoxImage.Hand); } } private DelegateCommand? _schEnableCmd; /// /// 调度使能写入驱动。 /// public DelegateCommand SchEnableCmd { get { if (_schEnableCmd == null) { _schEnableCmd = new DelegateCommand(SchEnableCmdCall); } return _schEnableCmd; } } private void SchEnableCmdCall(object par) { // 与旧 Toomoss 行为对齐:UI 勾选后立即下发到驱动 ZlgCanDriveService.SchEnable = CurrentSchEnable; } private DelegateCommand? _canOpCmd; /// /// CAN 操作命令。 /// public DelegateCommand CanOpCmd { get { if (_canOpCmd == null) { _canOpCmd = new DelegateCommand(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(); } break; case "Close": ZlgCanDriveService.CloseDevice(); ConfigService.CanLinRunStateModel.CurSysSelectedCanLin = CanLinEnum.No; LastError = null; OpTip = "CAN 已关闭"; 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": ZlgCanDriveService.IsCycleSend = !ZlgCanDriveService.IsCycleSend; OpTip = ZlgCanDriveService.IsCycleSend ? "循环发送:已开启" : "循环发送:已关闭"; break; case "CycleRecive": ZlgCanDriveService.SetReceiveEnabled(!ZlgCanDriveService.IsCycleRevice); OpTip = ZlgCanDriveService.IsCycleRevice ? "循环接收:已开启" : "循环接收:已关闭"; break; case "Save": if (SelectCanLinConfigPro == null) { MessageBox.Show("选中CAN配置名称后再操作", "提示", MessageBoxButton.OK, MessageBoxImage.Hand); return; } if (SelectedMode == ZlgCanMode.Can) { if (SelectedCANConfigExdDto == null) return; FreeSql.Update() .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(); } else { if (SelectedCANFdConfigExdDto == null) return; FreeSql.Update() .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(); } InitLoadCanConfigPro(); 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); } } } }