Files
CapMachine/CapMachine.Wpf/ViewModels/ZlgCanDriveConfigViewModel.cs
2026-02-02 21:22:01 +08:00

723 lines
26 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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
{
/// <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;
InitLoadCanConfigPro();
}
/// <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 List<CanLinConfigPro> _canLinConfigPros = new List<CanLinConfigPro>();
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 ZlgCanMode _selectedMode;
/// <summary>
/// 模式选择CAN/CANFD单选
/// </summary>
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();
}
}
/// <summary>
/// 连接按钮文字(对齐 Toomoss 风格)。
/// </summary>
public string ConnectButtonText
{
get { return SelectedMode == ZlgCanMode.Can ? "连接CAN" : "连接CANFD"; }
}
/// <summary>
/// 绑定用:模式 KeyCan/CanFd
/// </summary>
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;
}
}
}
/// <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>
public CanLinConfigPro? SelectCanLinConfigPro { get; set; }
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; set; }
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()
{
var info = SelectedMode == ZlgCanMode.Can ? CANLIN.CAN : CANLIN.CANFD;
_canLinConfigPros = FreeSql.Select<CanLinConfigPro>()
.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<CanLinConfigPro>(_canLinConfigPros);
}
private void SyncSelectedConfig()
{
if (SelectCanLinConfigPro == null)
{
return;
}
if (SelectedMode == ZlgCanMode.Can)
{
SelectedCANConfigExdDto = Mapper.Map<CANConfigExdDto>(SelectCanLinConfigPro.CANConfigExd);
SelectedCANFdConfigExdDto = null;
}
else
{
SelectedCANFdConfigExdDto = Mapper.Map<CANFdConfigExdDto>(SelectCanLinConfigPro.CANFdConfigExd);
SelectedCANConfigExdDto = null;
}
RaisePropertyChanged(nameof(CurrentDbcPath));
RaisePropertyChanged(nameof(CurrentCycle));
RaisePropertyChanged(nameof(CurrentSchEnable));
RaisePropertyChanged(nameof(CanBaudRate));
RaisePropertyChanged(nameof(CanFdArbBaudRate));
RaisePropertyChanged(nameof(CanFdDataBaudRate));
}
/// <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();
}
}
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 (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;
/// <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;
openFileDialogInfo.ShowDialog();
string fileName = openFileDialogInfo.FileName;
CurrentDbcPath = fileName;
}
catch
{
MessageBox.Show("可能未选择信息", "提示", MessageBoxButton.OKCancel, MessageBoxImage.Hand);
}
}
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>? _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();
}
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<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();
}
else
{
if (SelectedCANFdConfigExdDto == null) return;
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();
}
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);
}
}
}
}