2026-03-30 17:09:29 +09:00

547 lines
24 KiB
C#

using Aurora;
using Aurora.Api;
using Aurora.Api.Manager;
using Aurora.View;
using AuroraLaserScanner;
using AuroraUIComponent.Chart;
using LiveChartsCore;
using LiveChartsCore.Defaults;
using LiveChartsCore.SkiaSharpView;
using LiveChartsCore.SkiaSharpView.Painting;
using LiveChartsCore.SkiaSharpView.Painting.Effects;
using SkiaSharp;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Data;
using System.Windows;
using System.Windows.Input;
using System.Windows.Threading;
using Axis = LiveChartsCore.SkiaSharpView.Axis;
namespace WeldingCommon.Views
{
internal class UCPowerCalibrationViewModel : NotifyPropertyChangedBase
{
private readonly Logger Log = new Logger("PowerCalibration");
enum eColumnIndex
{
index,
DesiredPower,
CalibratedPower
}
#region Binding Properties
private bool _radioBeamTypeCenterChecked;
public bool radioBeamTypeCenterChecked { get => _radioBeamTypeCenterChecked; set => SetProperty(ref _radioBeamTypeCenterChecked, value); }
private bool _radioBeamTypeRingChecked;
public bool radioBeamTypeRingChecked { get => _radioBeamTypeRingChecked; set => SetProperty(ref _radioBeamTypeRingChecked, value); }
private double _dbPercent;
public double dbPercent { get => _dbPercent; set => SetProperty(ref _dbPercent, value); }
private double _dbVoltage;
public double dbVoltage { get => _dbVoltage; set => SetProperty(ref _dbVoltage, value); }
private double _dbWatt;
public double dbWatt { get => _dbWatt; set => SetProperty(ref _dbWatt, value); }
private string _cbOutputControl;
public string cbOutputControl { get => _cbOutputControl; set => SetProperty(ref _cbOutputControl, value); }
private double _dbControlValue;
public double dbControlValue { get => _dbControlValue; set => SetProperty(ref _dbControlValue, value); }
private string _strControlUnit;
public string strControlUnit { get => _strControlUnit; set => SetProperty(ref _strControlUnit, value); }
private int _nSliderValue;
public int nSliderValue { get => _nSliderValue; set => SetProperty(ref _nSliderValue, value); }
private int _nSliderMax;
public int nSliderMax { get => _nSliderMax; set => SetProperty(ref _nSliderMax, value); }
private int _nPowerReadingTime;
public int nPowerReadingTime { get => _nPowerReadingTime; set => SetProperty(ref _nPowerReadingTime, value); }
private int _nSamplingPeriod;
public int nSamplingPeriod { get => _nSamplingPeriod; set => SetProperty(ref _nSamplingPeriod, value); }
private double _dbAveragePower;
public double dbAveragePower { get => _dbAveragePower; set => SetProperty(ref _dbAveragePower, value); }
private double _dbPeakPower;
public double dbPeakPower { get => _dbPeakPower; set => SetProperty(ref _dbPeakPower, value); }
private int _nSampingCount;
public int nSampingCount { get => _nSampingCount; set => SetProperty(ref _nSampingCount, value); }
private int _nInterval;
public int nInterval { get => _nInterval; set => SetProperty(ref _nInterval, value); }
private int _nMaximumPower;
public int nMaximumPower { get => _nMaximumPower; set => SetProperty(ref _nMaximumPower, value); }
private uint m_beamMode { get; set; }
private DataTable _CalibrationDataTable;
public DataTable CalibrationDataTable { get => _CalibrationDataTable; set => SetProperty(ref _CalibrationDataTable, value); }
public UCLineChartViewModel PowerMeterChart { get; }
public ObservableCollection<ISeries> Series { get; set; }
public Axis[] XAxes { get; set; }
// Y axis
public Axis[] YAxes { get; set; }
public SolidColorPaint LegendTextPaint { get; set; } = new SolidColorPaint {
Color = new SKColor(255, 255, 255)
};
#endregion
#region EventCommands
public ICommand CMD_VisibleChanged { get; }
public ICommand EH_ComboBoxIndexChanged { get; }
public ICommand CMD_PowerReading { get; }
public ICommand CMD_StopEmission { get; }
public ICommand CMD_Apply { get; }
public ICommand CMD_AutoSet { get; }
public ICommand CMD_InitializeTable { get; }
public ICommand SELECT_BeamType { get; }
#endregion
private Scanner m_Scanner = null;
//private RscPowerMeter RscPowerMeter;
private readonly IDeviceManager DeviceManager;
private readonly AuroraPowerMeter.PowerMeter powermeter;
private readonly DispatcherTimer MonitorTimer;
public bool IsVisible { get; set; }
internal UCPowerCalibrationViewModel(IAuroraEnvironment aurora)
{
DeviceManager = aurora.DeviceManager;
#region Initialize Binding Properties
// Motor ID 를 List 에 넣기. devicemanager 에서 motor ID 를 받아오자.
// motor 가 define 되지 않았으니 테스트를 위해 임시로 몇개 넣어둔다.
PowerMeterChart = new UCLineChartViewModel(aurora);
PowerMeterChart.SetChart("POWER", string.Empty);
PowerMeterChart.SetChartLine("Power");
//PowerMeterChart.SetChartLineRange(true);
PowerMeterChart.InitChart();
nInterval = 1;
nMaximumPower = 200;
radioBeamTypeCenterChecked = true;
radioBeamTypeRingChecked = false;
nSliderMax = 100;
#endregion
#region Chart 속성 초기화
// 그래프 초기화
ObservableCollection<ObservablePoint> observableValuesDesiredPower = new ObservableCollection<ObservablePoint>();
ObservableCollection<ObservablePoint> observableValuesCalibratedPower = new ObservableCollection<ObservablePoint>();
Series = new ObservableCollection<ISeries> {
new LineSeries<ObservablePoint> {
Name = "DesiredPower",
Stroke = null,
Fill = null,
GeometryFill = new SolidColorPaint(SKColors.Green), // 내부색
GeometryStroke = new SolidColorPaint(SKColors.Green) {StrokeThickness = 1}, // 윤곽선
//GeometryStroke = null,
GeometrySize = 4,
LineSmoothness = 0,
Values = observableValuesDesiredPower,
// Tooltip formatter: 모두 F3 로...: 축 전환시, X 축의 소수 자릿수를 바꿀 방법이 없네...
//YToolTipLabelFormatter = (chartPoint) => $"X: {chartPoint.SecondaryValue}, Y: {chartPoint.PrimaryValue:F3}"
},
new LineSeries<ObservablePoint> {
Name = "CalibratedPower",
//Fill = new SolidColorPaint(SKColors.Tomato),
//GeometrySize = 4,
Stroke = null,
Fill = null,
GeometryFill = new SolidColorPaint(SKColors.Gold),
GeometryStroke = new SolidColorPaint(SKColors.Gold) {StrokeThickness = 1},
//GeometryStroke = null,
GeometrySize = 4,
LineSmoothness = 0,
Values = observableValuesCalibratedPower,
// Tooltip formatter
//YToolTipLabelFormatter = (chartPoint) => $"X: {chartPoint.SecondaryValue}, Y: {chartPoint.PrimaryValue:F3}"
},
};
// X axis
XAxes = new Axis[] {
new Axis {
Name = "Index",
NamePaint = new SolidColorPaint(SKColors.White),
LabelsPaint = new SolidColorPaint(SKColors.White)
}
};
YAxes = new Axis[] {
new Axis {
Name = "Watt",
NamePaint = new SolidColorPaint(SKColors.White),
LabelsPaint = new SolidColorPaint(SKColors.White),
// 배경 눈금선
SeparatorsPaint = new SolidColorPaint(SKColors.LightSlateGray) {
PathEffect = new DashEffect(new float[] { 3, 3})
}
}
};
#endregion
#region DelegateCommands
CMD_VisibleChanged = new DelegateCommand(VisibleChange);
CMD_PowerReading = new DelegateCommand(PowerReading);
CMD_StopEmission = new DelegateCommand(StopEmission);
CMD_Apply = new DelegateCommand(ChartApply);
CMD_AutoSet = new DelegateCommand(ChartAutoSet);
CMD_InitializeTable = new DelegateCommand(InitializeTable);
SELECT_BeamType = new DelegateCommand(SelecteBeamType);
#endregion
powermeter = DeviceManager[CommonDeviceIds.PowerMeter] as AuroraPowerMeter.PowerMeter;
#region Initialize Units
//Initialize 확인은 프로그램 실행시 할필요없음..
//InitializePowerMeter();
//InitializeScanner();
UpdateTableFromCalibrationData();
#endregion
MonitorTimer = new DispatcherTimer();
MonitorTimer.Tick += OnMonitoring;
MonitorTimer.Interval = TimeSpan.FromMilliseconds(100);
}
private void InitializePowerMeter()
{
if (powermeter != null) {
if (!powermeter.IsActivated) powermeter.Activate();
}
#region Legacy code
//RscPowerMeter = (RscPowerMeter)Program.tm.GetResource(Task.Properties.Settings.Default.RscPowerMeterID);
//if (RscPowerMeter.InitializeState)
//{
// RscPowerMeter.Start();
//}
#endregion
}
private void InitializeScanner()
{
m_Scanner = DeviceManager[CommonDeviceIds.Scanner] as Scanner;
if (m_Scanner.IsSimul) {
} else {
if (!m_Scanner.IsActivated)
m_Scanner.Activate();
}
}
private void UpdateTableFromCalibrationData()
{
//CalibrationDataTable = DB.Dao.WeldingLinesRecipe.laserPowerCalibrationParam.CenterCalibrationTable;
}
private void VisibleChange(object obj)
{
bool visible = (bool)obj;
if (visible) {
MonitorTimer.Start();
} else {
MonitorTimer.Stop();
}
}
private void OnMonitoring(object sender, EventArgs e)
{
try {
} catch (Exception ex) {
MessageBox.Show(ex.Message);
}
}
public void ComboBoxIndexChanged(int SelectedIndex)
{
try {
nSliderValue = 0;
List<string> list = new List<string> { " % ", " V ", " W " };
if (SelectedIndex < list.Count) strControlUnit = list[SelectedIndex];
} catch (Exception ex) {
MessageBox.Show(ex.Message);
}
}
public void SlinderValueChanged(int ComboBoxSelectedIndex)
{
double dbSliderValue = Convert.ToDouble(nSliderValue);
// database 에서 calibration 된 voltage, watt, percent 등을 받아와야한다.
dbPercent = dbSliderValue * 0.01;
dbVoltage = dbSliderValue * 0.1;
dbWatt = dbSliderValue * 1.0;
switch (ComboBoxSelectedIndex) {
case 0:
dbControlValue = dbPercent;
break;
case 1:
dbControlValue = dbVoltage;
break;
case 2:
double tbCoefficient = 1.0;
//datagrid 에서 maximum 을 받아서 비율로 변환해준다. datagrid 만든 후에 적용, 원래 코드는 행열이 바뀐거 같은데...이상하여 일단 바꿔본다
//double.TryParse(dataGridViewCalibrationTable[calibratedPowerIndex, dataGridViewCalibrationTable.RowCount - 2].Value.ToString(), out tbCoefficient);
tbCoefficient = (double)CalibrationDataTable.Rows[CalibrationDataTable.Rows.Count - 2][(int)eColumnIndex.CalibratedPower];
tbCoefficient = tbCoefficient / nSliderMax;
dbControlValue = dbWatt * tbCoefficient;
break;
default:
break;
}
}
public void ControlValueChanged(int ComboBoxSelectedIndex)
{
switch (ComboBoxSelectedIndex) {
case 0:
if (dbControlValue < 0 || dbControlValue > 100) {
nSliderValue = 0;
dbControlValue = 0;
MessageBox.Show("범위를 벗어났습니다. 0 ~ 100 %");
} else {
nSliderValue = Convert.ToInt32(dbControlValue * 100);
}
break;
case 1:
// Legacy code 가 이상하다. 10V 를 1000을 곱하면 trackbar 가 10000이 된다. 곱하기 배수가 틀린듯함. 10으로 고쳐준다.
if (dbControlValue < 0 || dbControlValue > 10) {
nSliderValue = 0;
dbControlValue = 0;
MessageBox.Show("범위를 벗어났습니다. 0 ~ 10 V");
} else {
nSliderValue = Convert.ToInt32(dbControlValue * 10);
}
break;
case 2:
double tbCoefficient = 1.0;
// CalibrationDataTable 에서 받아오는 코드가 있는데, index 가 이상함. tbCoefficient 변수에 넣어둔다.
//double.TryParse(dataGridViewCalibrationTable[calibratedPowerIndex, dataGridViewCalibrationTable.RowCount - 2].Value.ToString(), out tbCoefficient);
tbCoefficient = (double)CalibrationDataTable.Rows[CalibrationDataTable.Rows.Count - 2][(int)eColumnIndex.CalibratedPower];
if (tbCoefficient < dbControlValue) {
nSliderValue = 0;
dbControlValue = 0;
MessageBox.Show($"범위를 벗어났습니다. 0 ~ {tbCoefficient}V");
} else {
nSliderValue = Convert.ToInt32(100 * dbControlValue / tbCoefficient);
}
//datagrid 에서 maximum 을 받아서 비율로 변환해준다. datagrid 만든 후에 적용
//double.TryParse(dataGridViewCalibrationTable[calibratedPowerIndex, dataGridViewCalibrationTable.RowCount - 2].Value.ToString(), out tbCoefficient);
tbCoefficient = (double)CalibrationDataTable.Rows[CalibrationDataTable.Rows.Count - 2][(int)eColumnIndex.CalibratedPower];
tbCoefficient = tbCoefficient / nSliderMax;
dbControlValue = dbWatt * tbCoefficient;
break;
default:
break;
}
}
private void SelecteBeamType(object obj)
{
if (radioBeamTypeCenterChecked) {
//CalibrationDataTable = DB.Dao.WeldingLinesRecipe.laserPowerCalibrationParam.CenterCalibrationTable;
} else if (radioBeamTypeRingChecked) {
//CalibrationDataTable = DB.Dao.WeldingLinesRecipe.laserPowerCalibrationParam.RingCalibrationTable;
}
}
private void PowerReading(object obj)
{
try {
// parameter 범위 interlock 처리
if (nSamplingPeriod < 100 || nSamplingPeriod > 1000) {
MessageBox.Show("Check the Sampling period (100~1000).");
return;
}
if (nPowerReadingTime < 10000 || nPowerReadingTime > 60000) {
MessageBox.Show("Check the Power Reading Time (10000~60000).");
return;
}
// Laser Test : 위의 주석 삭제 후, 아래 레이저 관련 주석 또한 삭제.
// 그리고 밑에 파워메터는 잠깐 주석처리해놓는 걸로. 3ms 발진해보기.
uint laserPeriod = 1, laserPulseWidth = 1000;
LaserOn(nPowerReadingTime, laserPeriod, laserPulseWidth);
{
// Lasa Legacy code 에서도 주석처리 되어 있음
//if( channel 감지)
//RecPowerMeter.mPowerMeter[channel].AverageModeSet(readingTime, samplingTime);
}
//var primepowermeter = powermeter._PowerMeter as PrimesPowerMeter;
//primepowermeter.m_PrimesPowerMeterUnit.AverageModeSet(nPowerReadingTime, nSamplingPeriod);
} catch { }
}
private void StopEmission(object obj)
{
try {
if (m_Scanner.IsSimul)
Log.I("Scanner Stop. Simualation mode.");
else if (m_Scanner.IsActivated) {
//m_Scanner._scannerObj.StopExecution();
//m_Scanner._scannerObj.SetStandby(10, 0);
m_Scanner.StopExecution();
m_Scanner.SetStandby(10, 0);
} else
Log.I("Scanner is not activated. Already Stopped.");
if (powermeter.IsActivated) {
// IPowermeter 에는 stop 이 없음
}
#region Legacy code
//power meter 도 추가할 것.
//if (RscPowerMeter.InitializeState && RscScanner.InitializeState)
//{
// // Lasa Legacy code 에서도 주석처리 되어 있음
// //RscScanner.Scanner.StopExecution();
// //RscScanner.Scanner.SetStandby(10, 0);
// RscPowerMeter.Stop();
//}
#endregion
} catch { }
}
private void ChartApply(object obj)
{
try {
ObservableCollection<ObservablePoint> observableValuesDesiredPower = Series[0].Values as ObservableCollection<ObservablePoint>;
ObservableCollection<ObservablePoint> observableValuesCalibratedPower = Series[1].Values as ObservableCollection<ObservablePoint>;
observableValuesDesiredPower.Clear();
observableValuesCalibratedPower.Clear();
foreach (DataRow row in CalibrationDataTable.Rows) {
ObservablePoint point1 = new ObservablePoint(Convert.ToDouble(row[(int)eColumnIndex.index]), Convert.ToDouble(row[(int)eColumnIndex.DesiredPower]));
ObservablePoint point2 = new ObservablePoint(Convert.ToDouble(row[(int)eColumnIndex.index]), Convert.ToDouble(row[(int)eColumnIndex.CalibratedPower]));
observableValuesDesiredPower.Add(point1);
observableValuesCalibratedPower.Add(point2);
}
uint beamMode = radioBeamTypeCenterChecked ? (uint)0 : (uint)1;
//DB.Dao.WeldingLinesRecipe.laserPowerCalibrationParam.SaveTable(
// CalibrationDataTable,
// beamMode);
} catch { }
}
private void ChartAutoSet(object obj)
{
// LASA Legacy code 에 아무 내용이 없음
}
private void InitializeTable(object obj)
{
try {
// parameter 범위 interlock check
if (nInterval < 1 || nInterval > 100) {
MessageBox.Show("Check Range of Interval parameter.(1~100)");
return;
}
if (nMaximumPower < 1) {
MessageBox.Show("Check Range of MaximumPower parameter.(MaximumPower>0)");
return;
}
{
//uint beamMode = SelectBeamMode();
DataTable m_dataTable = new DataTable();
// 아래 코드와 동일한 기능인듯.
//DB.Dao.WeldingLinesRecipe.laserPowerCalibrationParam.InitializeTable
// (nMaximumPower, nInterval, out m_dataTable, m_beamMode);
// 동작확인을 위한 임시 데이터 처리. 작업 후 삭제
{
m_dataTable.Columns.Add(new DataColumn("Index", typeof(double)));
m_dataTable.Columns.Add(new DataColumn("DesiredPower", typeof(double)));
m_dataTable.Columns.Add(new DataColumn("CalibratedPower", typeof(double)));
double index = 0;
object[] rowArray;
DataRow row;
while (index < 100) {
double dItemValue = nMaximumPower * index / 100;
row = m_dataTable.NewRow();
rowArray = new object[3];
rowArray[0] = index;
rowArray[1] = dItemValue;
rowArray[2] = dItemValue + 0.1;
row.ItemArray = rowArray;
m_dataTable.Rows.Add(row);
index = index + nInterval;
}
//마지막 100% 인 경우를 추가
row = m_dataTable.NewRow();
rowArray = new object[3];
rowArray[0] = index;
rowArray[1] = nMaximumPower;
rowArray[2] = nMaximumPower;
row.ItemArray = rowArray;
m_dataTable.Rows.Add(row);
}
CalibrationDataTable = m_dataTable;
}
} catch { }
}
public void SetLaserPower()
{
if (m_Scanner.IsSimul) {
Log.I("Scanner Set Powor. Simualation mode.");
} else if (m_Scanner.IsActivated) {
//m_Scanner._scannerObj.WriteDA(m_beamMode, (float)dbPercent);
m_Scanner.WriteDA(m_beamMode, (float)dbPercent);
} else {
Log.I("Scanner is not activated. Try Scanner Initialze agian.");
}
}
private void LaserOn(double laserOnTime, uint laserPeriod, uint laser1PulseWidth)
{
// Scanner Device 적용 후 주석풀기
//if (m_Scanner._scannerObj.GetBusyStatus()) {
if (m_Scanner.GetBusyStatus()) {
MessageBox.Show("Scanner is busy.");
return;
}
// 1. Laser Power 입력
SetLaserPower();
//// 2. Laser 출사
//m_Scanner._scannerObj.SetStartList(eListNo.LIST1);
//m_Scanner._scannerObj.SetLaserTiming(laserPeriod, laser1PulseWidth, laser1PulseWidth);
//m_Scanner._scannerObj.SetStandby(laserPeriod, laser1PulseWidth);
//m_Scanner._scannerObj.LaserOnList(laserOnTime);
//m_Scanner._scannerObj.SetEndList();
//m_Scanner._scannerObj.ExecuteList(eListNo.LIST1);
m_Scanner.SetStartList(eListNo.LIST1);
m_Scanner.SetLaserTiming(laserPeriod, laser1PulseWidth, laser1PulseWidth);
m_Scanner.SetStandby(laserPeriod, laser1PulseWidth);
m_Scanner.LaserOnList(laserOnTime);
m_Scanner.SetEndList();
m_Scanner.ExecuteList(eListNo.LIST1);
}
}
}