using System;
using System.Collections.ObjectModel;
using System.Linq;
using System.Threading.Tasks;
using System.Windows;
using Prism.Commands;
using TeamAAS.Feeder.Interfaces;
using TeamAAS.Feeder.Models;
using TeamAAS.Views;
namespace TeamAAS.ViewModels
{
///
/// 供料器扩展功能(partial SettingViewModel):
/// 系统参数(超时)、料斗输入输出、输入触发、收发通讯日志、Feeder IP 自动搜索。
/// 命令均采用懒加载,避免改动主构造函数。
///
public partial class SettingViewModel
{
private const string FeederLogSource = "Feeder";
#region 收发通讯日志(SendLog/ReceiveLog)
/// 收发报文日志(仅界面显示,不落文件)。
public ObservableCollection CommLogs { get; }
= new ObservableCollection();
private const int MaxCommLogEntries = 500;
/// 订阅自 IFeeder.MessageExchanged,可能在非 UI 线程触发。
private void OnFeederMessageExchanged(IFeeder dev, string content, bool isSend)
{
var entry = new FeederCommLogEntry
{
Time = DateTime.Now,
IsSend = isSend,
Content = content
};
var dispatcher = Application.Current?.Dispatcher;
if (dispatcher != null && !dispatcher.CheckAccess())
dispatcher.BeginInvoke(new Action(() => AppendCommLog(entry)));
else
AppendCommLog(entry);
}
private void AppendCommLog(FeederCommLogEntry entry)
{
CommLogs.Add(entry);
while (CommLogs.Count > MaxCommLogEntries)
CommLogs.RemoveAt(0);
}
private DelegateCommand _clearCommLogCommand;
public DelegateCommand ClearCommLogCommand =>
_clearCommLogCommand ?? (_clearCommLogCommand = new DelegateCommand(() => CommLogs.Clear()));
#endregion
#region 系统参数(超时/背光)
private FeederSystemParam _systemParam = new FeederSystemParam();
public FeederSystemParam SystemParam
{
get { return _systemParam; }
set { SetProperty(ref _systemParam, value); }
}
private DelegateCommand _readSystemParamCommand;
public DelegateCommand ReadSystemParamCommand =>
_readSystemParamCommand ?? (_readSystemParamCommand = new DelegateCommand(async () => await ReadSystemParamAsync()));
private DelegateCommand _writeSystemParamCommand;
public DelegateCommand WriteSystemParamCommand =>
_writeSystemParamCommand ?? (_writeSystemParamCommand = new DelegateCommand(async () => await WriteSystemParamAsync()));
private async Task ReadSystemParamAsync()
{
if (!EnsureFeederConnected()) return;
try
{
FeederStatusText = "读取系统参数...";
var p = await _activeDevice.GetSystemParamAsync();
SystemParam = p;
FeederStatusText = "系统参数已读取";
AppLogger.Info($"读取系统参数: 背光超时={p.LightTimeout} 亮度={p.LightBrightness} 闪烁={p.LightFlashTime} 平台振动超时={p.PlatShakeTimeout} 料斗振动超时={p.HopperShakeTimeout}", FeederLogSource);
}
catch (Exception ex)
{
FeederStatusText = "读取系统参数失败";
AppLogger.Error("读取供料器系统参数失败", ex, FeederLogSource);
DialogHelper.ShowError("读取系统参数失败", ex);
}
}
private async Task WriteSystemParamAsync()
{
if (!EnsureFeederConnected()) return;
try
{
FeederStatusText = "写入系统参数...";
var p = SystemParam;
await _activeDevice.SetSystemParamAsync(p);
FeederStatusText = "系统参数已写入并保存";
AppLogger.Info($"写入系统参数: 背光超时={p.LightTimeout} 亮度={p.LightBrightness} 闪烁={p.LightFlashTime} 平台振动超时={p.PlatShakeTimeout} 料斗振动超时={p.HopperShakeTimeout}", FeederLogSource);
DialogHelper.Success("系统参数已写入设备");
}
catch (Exception ex)
{
FeederStatusText = "写入系统参数失败";
AppLogger.Error("写入供料器系统参数失败", ex, FeederLogSource);
DialogHelper.ShowError("写入系统参数失败", ex);
}
}
#endregion
#region 料斗输入输出
/// 料斗输出参数组序号(0~25)。
public int[] HopperGroupList { get; } = Enumerable.Range(0, 26).ToArray();
private int _selectedHopperGroup;
public int SelectedHopperGroup
{
get { return _selectedHopperGroup; }
set { SetProperty(ref _selectedHopperGroup, value); }
}
private HopperOutputParam _hopperParam = new HopperOutputParam();
public HopperOutputParam HopperParam
{
get { return _hopperParam; }
set { SetProperty(ref _hopperParam, value); }
}
private DelegateCommand _readHopperParamCommand;
public DelegateCommand ReadHopperParamCommand =>
_readHopperParamCommand ?? (_readHopperParamCommand = new DelegateCommand(async () => await ReadHopperParamAsync()));
private DelegateCommand _writeHopperParamCommand;
public DelegateCommand WriteHopperParamCommand =>
_writeHopperParamCommand ?? (_writeHopperParamCommand = new DelegateCommand(async () => await WriteHopperParamAsync()));
private DelegateCommand _runHopperOutputCommand;
public DelegateCommand RunHopperOutputCommand =>
_runHopperOutputCommand ?? (_runHopperOutputCommand = new DelegateCommand(async () => await RunHopperOutputAsync()));
private DelegateCommand _stopHopperOutputCommand;
public DelegateCommand StopHopperOutputCommand =>
_stopHopperOutputCommand ?? (_stopHopperOutputCommand = new DelegateCommand(async () => await StopHopperOutputAsync()));
private async Task ReadHopperParamAsync()
{
if (!EnsureFeederConnected()) return;
try
{
FeederStatusText = $"读取料斗输出参数(组 {SelectedHopperGroup})...";
HopperParam = await _activeDevice.GetHopperParamAsync(SelectedHopperGroup);
FeederStatusText = "料斗输出参数已读取";
AppLogger.Info($"读取料斗输出参数 组={SelectedHopperGroup}", FeederLogSource);
}
catch (Exception ex)
{
FeederStatusText = "读取料斗参数失败";
AppLogger.Error("读取料斗输出参数失败", ex, FeederLogSource);
DialogHelper.ShowError("读取料斗参数失败", ex);
}
}
private async Task WriteHopperParamAsync()
{
if (!EnsureFeederConnected()) return;
try
{
FeederStatusText = $"下载料斗输出参数(组 {SelectedHopperGroup})...";
await _activeDevice.SetHopperParamAsync(SelectedHopperGroup, HopperParam);
FeederStatusText = "料斗输出参数已下载";
AppLogger.Info($"下载料斗输出参数 组={SelectedHopperGroup} 数字1={HopperParam.HopperDigitalOutput1} 模拟1={HopperParam.HopperAnalogOutput1} 数字2={HopperParam.HopperDigitalOutput2} 模拟2={HopperParam.HopperAnalogOutput2} 持续={HopperParam.HopperDuration}ms", FeederLogSource);
DialogHelper.Success("料斗输出参数已下载到设备");
}
catch (Exception ex)
{
FeederStatusText = "下载料斗参数失败";
AppLogger.Error("下载料斗输出参数失败", ex, FeederLogSource);
DialogHelper.ShowError("下载料斗参数失败", ex);
}
}
private async Task RunHopperOutputAsync()
{
if (!EnsureFeederConnected()) return;
try
{
int id = SelectedHopperGroup + 1;
FeederStatusText = $"执行料斗动作 {id}...";
await _activeDevice.RunHopperOutputAsync(id, HopperParam.HopperDuration > 0 ? HopperParam.HopperDuration : (int?)null);
FeederStatusText = $"料斗动作 {id} 执行完成";
AppLogger.Info($"执行料斗动作 id={id} 持续={HopperParam.HopperDuration}ms", FeederLogSource);
}
catch (Exception ex)
{
FeederStatusText = "料斗动作执行失败";
AppLogger.Error("执行料斗动作失败", ex, FeederLogSource);
DialogHelper.ShowError("料斗动作执行失败", ex);
}
}
private async Task StopHopperOutputAsync()
{
if (_activeDevice == null) return;
try
{
await _activeDevice.StopHopperOutputAsync();
FeederStatusText = "料斗振动已停止";
AppLogger.Info("停止料斗振动", FeederLogSource);
}
catch (Exception ex)
{
AppLogger.Error("停止料斗振动失败", ex, FeederLogSource);
DialogHelper.ShowError("停止料斗振动失败", ex);
}
}
#endregion
#region 输入触发序列ID
private int _inputTrigger1;
public int InputTrigger1
{
get { return _inputTrigger1; }
set { SetProperty(ref _inputTrigger1, value); }
}
private int _inputTrigger2;
public int InputTrigger2
{
get { return _inputTrigger2; }
set { SetProperty(ref _inputTrigger2, value); }
}
private DelegateCommand _readInputTriggerCommand;
public DelegateCommand ReadInputTriggerCommand =>
_readInputTriggerCommand ?? (_readInputTriggerCommand = new DelegateCommand(async () => await ReadInputTriggerAsync()));
private DelegateCommand _writeInputTriggerCommand;
public DelegateCommand WriteInputTriggerCommand =>
_writeInputTriggerCommand ?? (_writeInputTriggerCommand = new DelegateCommand(async () => await WriteInputTriggerAsync()));
private async Task ReadInputTriggerAsync()
{
if (!EnsureFeederConnected()) return;
try
{
InputTrigger1 = await _activeDevice.GetInputTriggerAsync(0);
InputTrigger2 = await _activeDevice.GetInputTriggerAsync(1);
FeederStatusText = $"输入触发已读取: 输入1={InputTrigger1} 输入2={InputTrigger2}";
AppLogger.Info($"读取输入触发序列ID: 输入1={InputTrigger1} 输入2={InputTrigger2}", FeederLogSource);
}
catch (Exception ex)
{
FeederStatusText = "读取输入触发失败";
AppLogger.Error("读取输入触发序列ID失败", ex, FeederLogSource);
DialogHelper.ShowError("读取输入触发失败", ex);
}
}
private async Task WriteInputTriggerAsync()
{
if (!EnsureFeederConnected()) return;
try
{
await _activeDevice.SetInputTriggerAsync(0, InputTrigger1);
await _activeDevice.SetInputTriggerAsync(1, InputTrigger2);
FeederStatusText = "输入触发已写入";
AppLogger.Info($"写入输入触发序列ID: 输入1={InputTrigger1} 输入2={InputTrigger2}", FeederLogSource);
DialogHelper.Success("输入触发参数已写入设备");
}
catch (Exception ex)
{
FeederStatusText = "写入输入触发失败";
AppLogger.Error("写入输入触发序列ID失败", ex, FeederLogSource);
DialogHelper.ShowError("写入输入触发失败", ex);
}
}
#endregion
#region Feeder IP 自动搜索
private DelegateCommand _searchFeederIpCommand;
public DelegateCommand SearchFeederIpCommand =>
_searchFeederIpCommand ?? (_searchFeederIpCommand = new DelegateCommand(OpenFeederSearchDialog));
private void OpenFeederSearchDialog()
{
if (SelectedFeeder == null)
{
DialogHelper.Warning("请先选择或添加一个供料器");
return;
}
var dialog = new SearchFeederWindow { Owner = Application.Current.MainWindow };
if (dialog.ShowDialog() == true && dialog.SelectedResult != null)
{
var r = dialog.SelectedResult;
SelectedFeeder.IP = r.IP;
SelectedFeeder.Port = r.Port;
FeederStatusText = $"已回填 {r.IP}:{r.Port}";
AppLogger.Info($"搜索回填 Feeder IP: {r.FeederType} {r.IP}:{r.Port} MAC={r.MAC}", FeederLogSource);
}
}
#endregion
/// 确保已连接供料器;未连接则提示并返回 false。
private bool EnsureFeederConnected()
{
if (_activeDevice == null || !_activeDevice.IsConnected)
{
DialogHelper.Warning("请先连接供料器");
return false;
}
return true;
}
}
/// 供料器收发报文日志条目(界面 SendLog/ReceiveLog 显示用)。
public class FeederCommLogEntry
{
public DateTime Time { get; set; }
public bool IsSend { get; set; }
public string Content { get; set; }
public string Direction => IsSend ? "TX →" : "RX ←";
public string TimeText => Time.ToString("HH:mm:ss.fff");
public string Display => $"{TimeText} {Direction} {Content}";
}
}