2026-06-05 13:44:39 +09:00

292 lines
9.1 KiB
C#

// Copyright (c) 2020 LG Electronics Inc.
// SPDX-License-Identifier: LicenseRef-LGE-Proprietary
using Aurora;
using Aurora.Api;
using Aurora.Api.Devices;
using Aurora.View;
using System;
using System.Collections.Generic;
using System.Reactive.Linq;
using System.Windows;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Threading;
namespace AuroraMotor.Views
{
public class UCAuroraMotorViewModel : NotifyPropertyChangedBase
{
static readonly Logger Log = new Logger("UCAuroraMotorViewModel");
static readonly SolidColorBrush ColorMoving
= new SolidColorBrush(Color.FromRgb(0, 200, 0));
static readonly SolidColorBrush ColorStopped
= Application.Current.Resources["MahApps.Brushes.Text"] as SolidColorBrush
?? new SolidColorBrush(Colors.GhostWhite);
static readonly SolidColorBrush ColorAlarm
= new SolidColorBrush(Colors.DarkRed);
static readonly TimeSpan TIMESPAN_NORMAL = TimeSpan.FromSeconds(1);
static readonly TimeSpan TIMESPAN_FREQUENT = TimeSpan.FromMilliseconds(300);
readonly IEventObservable mEventObservable;
readonly DispatcherTimer mMonitorTimer;
readonly DispatcherTimer mCurrentPosUpdateTimer;
IDisposable mDevActiveObserveDisposer;
AuroraMotorBase mActivatedMotor;
public AuroraMotorBase mSelectedMotor;
public AuroraMotorBase SelectedMotor
{
get => mSelectedMotor;
set
{
if (mSelectedMotor == value)
return;
mSelectedMotor = value;
OnMotorActiveChanged();
NotifyPropertyChanged(null);
OnMonitorTime();
}
}
public Range2<double> PosLimit => new Range2<double>(
mActivatedMotor?.GetPosLimit() ?? (0.0, 0.0)
);
public Range<double> VelLimit => new Range<double>(
mActivatedMotor?.GetVelLimit() ?? (0, 0)
);
public bool IsServoOn
{
get => mActivatedMotor?.IsServoOn() ?? false;
set
{
mActivatedMotor?.ServoOn(value);
NotifyPropertyChanged();
}
}
public IList<string> Alarms { get; private set; }
public double ActualPos
=> mActivatedMotor?.GetActualPos() ?? System.Double.NaN;
private Brush mCurrentPosBrush;
public Brush CurrentPosBrush
{
get => mCurrentPosBrush;
private set => SetProperty(ref mCurrentPosBrush, value);
}
public string HomeStatus =>
Application.Current.FindStrToken(
mActivatedMotor == null ? "NA"
: mActivatedMotor.IsHomeCompleted() ? "Completed"
: "NotCompleted"
);
public double TargetJogVel { get; set; }
public double TargetJogIncrement { get; set; }
public bool IsAbsTarget { get; set; }
public bool IsRelTarget { get; set; }
public double TargetPos { get; set; }
public double TargetVel { get; set; }
public ICommand CMD_ViewLoaded { get; }
public ICommand CMD_ViewUnloaded { get; }
public ICommand CMD_ClearAlarm { get; }
public ICommand CMD_Home { get; }
public ICommand CMD_Move { get; }
public ICommand CMD_JogPositive { get; }
public ICommand CMD_JogNegative { get; }
public ICommand CMD_JogGo { get; }
public ICommand CMD_Stop { get; }
#region 생성자
public UCAuroraMotorViewModel(IEventObservable eventObservable)
{
mEventObservable = eventObservable;
mActivatedMotor = null;
IsAbsTarget = true;
CMD_ViewLoaded = new DelegateCommand(OnViewLoaded);
CMD_ViewUnloaded = new DelegateCommand(OnViewUnloaded);
CMD_ClearAlarm = new DelegateCommand(HandleClearAlarm);
CMD_Home = new DelegateCommand(HandleHome);
CMD_Move = new DelegateCommand(HandleMove);
CMD_JogPositive = new DelegateCommand((_) => HandleJog(+1));
CMD_JogNegative = new DelegateCommand((_) => HandleJog(-1));
CMD_JogGo = new DelegateCommand(HandleJogGo);
CMD_Stop = new DelegateCommand(HandleStop);
mMonitorTimer = CreateTimer(
TIMESPAN_NORMAL,
OnMonitorTime
);
mCurrentPosUpdateTimer = CreateTimer(
TIMESPAN_NORMAL,
OnActualPosUpdateTime
);
}
#endregion
static DispatcherTimer CreateTimer(
TimeSpan interval,
Action onTime)
{
var timer = new DispatcherTimer();
timer.Tick += (s, e) => onTime();
timer.Interval = interval;
return timer;
}
void OnViewLoaded(object obj)
{
AuroraMotorBase.MotorMoved += OnMotorMoved;
mDevActiveObserveDisposer = Observable.Merge(
mEventObservable.AsObservable(AuroraSysEvent.SYS_DEVICE_ACTIVATED),
mEventObservable.AsObservable(AuroraSysEvent.SYS_DEVICE_DEACTIVATED)
).Where(
x => x.Param as string == mSelectedMotor?.DeviceId
).ObserveOn(
Application.Current.Dispatcher
).Subscribe(
x => OnMotorActiveChanged()
);
OnMotorActiveChanged();
mMonitorTimer.Start();
mCurrentPosUpdateTimer.Interval = TIMESPAN_NORMAL;
mCurrentPosUpdateTimer.Start();
}
void OnViewUnloaded(object obj)
{
AuroraMotorBase.MotorMoved -= OnMotorMoved;
mDevActiveObserveDisposer?.Dispose();
mMonitorTimer.Stop();
mCurrentPosUpdateTimer.Stop();
}
void OnMonitorTime()
{
if (mActivatedMotor == null || !mActivatedMotor.IsActivated)
return;
NotifyPropertyChanged("IsServoOn");
NotifyPropertyChanged("HomeStatus");
SetMoving(
mActivatedMotor?.IsMoving() ?? false
);
if (mActivatedMotor?.IsAlarm() ?? false)
{
Alarms = mActivatedMotor.GetAlarm();
CurrentPosBrush = ColorAlarm;
}
else
Alarms = null;
NotifyPropertyChanged("Alarms");
}
void OnActualPosUpdateTime()
{
NotifyPropertyChanged("ActualPos");
if (!mActivatedMotor?.IsMoving() ?? false)
mCurrentPosUpdateTimer.Interval = TIMESPAN_NORMAL;
}
void OnMotorMoved(object sender, EventArgs e)
{
if ( sender is AuroraMotorBase motor
&& mActivatedMotor != null
&& motor.DeviceId == mActivatedMotor.DeviceId)
mCurrentPosUpdateTimer.Interval = TIMESPAN_FREQUENT;
}
void OnMotorActiveChanged()
{
mActivatedMotor = mSelectedMotor?.IsActivated ?? false
? mSelectedMotor
: null;
NotifyPropertyChanged(null);
}
void SetMoving(bool moving)
=> CurrentPosBrush = moving
? ColorMoving
: ColorStopped;
void HandleClearAlarm(object obj)
=> mActivatedMotor?.ClearAlarm();
void HandleHome(object obj)
{
int err = mActivatedMotor?.Home() ?? -100;
if (err == 0)
SetMoving(true);
else
Log.W("ERROR: fail to home");
}
void HandleMove(object obj)
{
int err = mActivatedMotor?.SetTargetSPD(
TargetVel
) ?? -100;
if (err != 0)
{
Log.W($"ERROR: fail to move velocity: {TargetVel}");
return;
}
var targetType = IsAbsTarget ? TargetPosType.ABS : TargetPosType.REL;
err = mActivatedMotor?.SetTargetPos(
TargetPos,
targetType
) ?? -200;
if (err != 0)
{
Log.W($"ERROR: fail to move target: ({targetType} {TargetPos:f3})");
return;
}
err = mActivatedMotor?.Move() ?? - 300;
if (err == 0)
SetMoving(true);
else
Log.W("ERROR: fail to move");
}
void HandleJog(int sign)
{
int? err = mActivatedMotor?.Jog(
sign, TargetJogVel
);
if (err == 0)
SetMoving(true);
else
Log.W("ERROR: fail to jog increment");
}
void HandleJogGo(object obj)
{
int? err = mActivatedMotor?.JogIncrement(
TargetJogIncrement, TargetJogVel
);
if (err == 0)
SetMoving(true);
else
Log.W("ERROR: fail to jog");
}
void HandleStop(object obj)
=> mActivatedMotor?.Stop();
}
}