292 lines
9.1 KiB
C#
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();
|
|
}
|
|
} |