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 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 observableValuesDesiredPower = new ObservableCollection(); ObservableCollection observableValuesCalibratedPower = new ObservableCollection(); Series = new ObservableCollection { new LineSeries { 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 { 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 list = new List { " % ", " 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 observableValuesDesiredPower = Series[0].Values as ObservableCollection; ObservableCollection observableValuesCalibratedPower = Series[1].Values as ObservableCollection; 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); } } }