using Aurora; using Aurora.Api; using AuroraLaser.Amplitude.Satsuma; using AuroraLaser.Coherent.Arm; using Hermes; using MathNet.Numerics.Distributions; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading; using System.Threading.Tasks; using System.Windows; namespace AuroraLaser.Coherent.Compact { // Compact 시리즈가 아닌, Coherent 사 제품을 공통으로 묶을 수 있을까? public class LaserDeviceCompact : Device, ILaserDeviceCoherent { protected readonly Logger Log; private LaserCompactMiniSerialConn _laserCompactMiniSerialConn; // 공통 인터페이스 public LaserCompactMiniConfig Config { get; set; } protected const Int16 FAIL = -1; public int Index { get; set; } //----- For Simul double _powerPerc; Random _randomInt; Normal _randomValue; const double magForGaussian = 5.0; //=========================== #region 생성자 public LaserDeviceCompact(string deviceId, int laserIndex = 0) { DeviceId = deviceId; CommType = CommunicationType.Serial; Type = DeviceType.Laser; Index = laserIndex; Log = new Logger("Compact_" + deviceId); } #endregion #region 활성화/비활성화 protected override int DoActivate(IDeviceConfig config) { Config = config as LaserCompactMiniConfig; return ActivateDevice(); //_rawConfig = config as LaserCompactMiniConfig; //_laserCompactMiniSerialConn = new LaserCompactMiniSerialConn(DeviceId, IsSimul); //var result = _laserCompactMiniSerialConn.Connect(_rawConfig); //if (IsSimul == false) { // if (result == E1.OK) { // 통신 연결 성공 // if (_laserCompactMiniSerialConn.NeedConfigSave) { // 시리얼넘버의 최초 write 발생 시, config 저장 필요 // Application.Current.AuroraEnv().DeviceManager.SaveDeviceConfig(DeviceId); // Config 저장 // // SN 가 변경되었다는 이벤트 publish // EventPublisher.Publish(new EventMessage("LaserCompactMini", LaserEvent.EVENT_ID_SerialNumberUpdate)); // // reset // _laserCompactMiniSerialConn.NeedConfigSave = false; // Log.I($"Serial number ({_rawConfig.SerialNumber}) is saved"); // } // Log.I($"Activated Laser : {DeviceId}"); // } else { Log.E($"Activate Laser : {DeviceId} Fail"); } //} else { // 시뮬 // _randomInt = new Random(); // _randomValue = new Normal(0.0, 0.1); //} //return result; } protected override int DoDeactivate() { return DeactivateDevice(); //Log.I($"Deactivate Laser : {DeviceId}"); //if (IsSimul == false) { // return _laserCompactMiniSerialConn.Disconnect(); //} //return E1.OK; } #endregion public int ActivateDevice() { _laserCompactMiniSerialConn = new LaserCompactMiniSerialConn(DeviceId, IsSimul); var result = _laserCompactMiniSerialConn.Connect(Config); if (IsSimul == false) { if (result == E1.OK) { // 통신 연결 성공 if (_laserCompactMiniSerialConn.NeedConfigSave) { // 시리얼넘버의 최초 write 발생 시, config 저장 필요 Application.Current.AuroraEnv().DeviceManager.SaveDeviceConfig(DeviceId); // Config 저장 // SN 가 변경되었다는 이벤트 publish EventPublisher.Publish(new EventMessage("LaserCompactMini", LaserEvent.EVENT_ID_SerialNumberUpdate)); // reset _laserCompactMiniSerialConn.NeedConfigSave = false; Log.I($"Serial number ({Config.SerialNumber}) is saved"); } Log.I($"Activated Laser : {DeviceId}"); } else { Log.E($"Activate Laser : {DeviceId} Fail"); } } else { // 시뮬 _randomInt = new Random(); _randomValue = new Normal(0.0, 0.1); } return result; } public int DeactivateDevice() { Log.I($"Deactivate Laser : {DeviceId}"); if (IsSimul == false) { return _laserCompactMiniSerialConn.Disconnect(); } return E1.OK; } #region 통신 상태 public int Reconnect() { if (Monitor.TryEnter(_alarmLockReconnectObj) && (IsCommError || !_laserCompactMiniSerialConn.IsConnected())) { if (_laserCompactMiniSerialConn.Reconnect() == E1.OK) { ClearAlarm(CreateEigenAlarmCode(99)); ClearAlarm(CreateEigenAlarmCode(98)); return E1.OK; } return E1.NETWORK; } return E1.NETWORK; } public bool IsConnected() { if (!IsActivated) { return false; } IsCommError = !_laserCompactMiniSerialConn.IsConnected(); return IsCommError == false; } // 알람용인데, 흠 전체적인 그림을 봐야겠는데.... public bool IsNetworkError() { if (_laserCompactMiniSerialConn == null) { Log.E($"{DeviceId} is null"); return true; } else { IsCommError = _laserCompactMiniSerialConn.IsNetworkError || !_laserCompactMiniSerialConn.IsConnected(); if (IsCommError) { if (!_laserCompactMiniSerialConn.IsConnected()) { AddAlarm(CreateEigenAlarmCode(98)); // Eigen 단어가 어색한데....장치니까 Device 는 어떨까? } else { AddAlarm(CreateEigenAlarmCode(99)); } } return IsCommError; } } #endregion // 이 구조체들이 공용화가 어디까지 될까?? Compact 시리즈 모델이 추가되면 수정여부 재검토 public STRUCT_STATUS_REGISTER GetLaserStatusInfo() { return _laserCompactMiniSerialConn.GetLaserStatusInfo(); } public STRUCT_LASER_MODE_REGISTER GetLaserModeInfo() { return _laserCompactMiniSerialConn.GetLaserModeInfo(); } public STRUCT_ERROR_REGISTER GetLaserErrMsgInfo() { return _laserCompactMiniSerialConn.GetLaserErrMsgInfo(); } #region 레이저 관련, 통신 R/W API 포함 public bool IsLaserError() { bool result = _laserCompactMiniSerialConn.IsLaserError; if (result) { var statusInfo = GetLaserStatusInfo(); if (statusInfo.bErrorStatus) { AddAlarm(CreateEigenAlarmCode(10)); } if (statusInfo.bFatalError) { AddAlarm(CreateEigenAlarmCode(11)); } } return result; } public void ErrorReset() { _laserCompactMiniSerialConn.ErrorReset(); ClearAlarm(new int[2] { CreateEigenAlarmCode(10), CreateEigenAlarmCode(11) }); } public int SetOutputPower(double powerPerc) { _powerPerc = powerPerc; if (IsSimul == false) { return _laserCompactMiniSerialConn.SetOutputPower(powerPerc) ? E1.OK : FAIL; } return E1.OK; } #region Power calibration public int LoadLaserCalibrationData() { // Aurora Config Json reload Application.Current.AuroraEnv().DeviceManager.LoadDeviceConfig(DeviceId); _laserCompactMiniSerialConn.LoadLaserCalibrationData(); return E1.OK; } public List<(double perc, double watt)> GetPowerCalData() { return _laserCompactMiniSerialConn?.GetPowerCalData(); } public double Watt2Power(double watt) { return _laserCompactMiniSerialConn.Watt2Power(watt); } public double Watt2Power(double watt, eModelType calibType) { return _laserCompactMiniSerialConn.Watt2Power(watt, calibType); } // 오직 시뮬에서만 필요 public double Power2Watt(double dPowerPerc) { if (IsSimul) { return _laserCompactMiniSerialConn.Power2Watt(dPowerPerc); } else { Log.W("Only for Sim mode"); return 0.0; } } public void SetLaserPowerCalibMethod(string powerCalibMethod) { _laserCompactMiniSerialConn?.SetLaserPowerCalibMethod(powerCalibMethod); } public string GetLaserPowerCalibMethod() { return _laserCompactMiniSerialConn?.GetLaserPowerCalibMethod(); } #endregion public void Update() { if (!IsActivated) { return; } if (IsSimul == false) { _laserCompactMiniSerialConn.Update(); } else { // 시뮬 // 1. 레이저 Internal Set Power 업데이트 int iPow = (int)(Math.Round(_powerPerc, 1) * 10); // [0, 1000] var l_compactMiniRegister = (_laserCompactMiniSerialConn as LaserCompactMiniSerialConn).m_Register; l_compactMiniRegister.m_stStatus_Regster.PowerValue = iPow + (int)(Math.Round(_randomValue.Sample() * magForGaussian, 1) * 10.0); // 가우시안 노이즈 추가 // 2. 온도 시뮬레이션 l_compactMiniRegister.m_stStatus_Regster.Temp = _randomInt.Next(0, 51); // [0, 50] } } #endregion #region Alarm private const int _alarmPrefix = 32; // TYPE 값 기준으로 하는게 어떨까? private object _alarmObject = new object(); private readonly object _alarmLockReconnectObj = new object(); public override void ClearAlarms() { if (IsActivated) { lock (_alarmObject) { var list = GetAlarmList().ToArray(); foreach (var alarmCode in list) { switch (alarmCode % 100) { case 10: case 11: ErrorReset(); break; case 98: case 99: Reconnect(); break; default: ClearAlarm(alarmCode); break; } } } } else { base.ClearAlarms(); } } private int CreateEigenAlarmCode(int alarmCode) { return _alarmPrefix * 1000 + Index * 100 + alarmCode; } #endregion /////////////////////////////////////////////////////////// // Laser Interface 추가 // All LaserDevice 에서 선택하여 Device 가 생성될 때 사용되며, All LaserDevice 가 Activated 일 때만 true 가 됨. public bool IsActivated_InAllLaserDevice = false; private bool CanCallLaserFunction() { if (IsActivated_InAllLaserDevice == false && IsActivated == false) { return false; } return true; } public int LaserOn() { // TODO: 구현 필요 return 1; } public int LaserOff() { // TODO: 구현 필요 return 1; } public int PilotLaserOn() { // TODO: 구현 필요 return 1; } public int PilotLaserOff() { // TODO: 구현 필요 return 1; } public bool GetPilotLaserStatus() { // TODO: 구현 필요 return true; } public bool GetLaserReady() { // TODO: 구현 필요 return true; } public bool GetPilotLaserSetBitStatus() { // TODO: 구현 필요 return true; } public bool GetConnected() { // TODO: 구현 필요 return true; } public int SetData(int nTarget, int value) { // TODO: 구현 필요 return 1; } public int ResetLaser() { // TODO: 구현 필요 return E1.OK; } public string GetControlMode() { throw new NotImplementedException(); } public bool GetControlModeSetStatus() { throw new NotImplementedException(); } public bool GetEmissionStatus() { throw new NotImplementedException(); } public bool GetEStop() { throw new NotImplementedException(); } public bool GetInitCommunication() { throw new NotImplementedException(); } public bool GetLaserError() { throw new NotImplementedException(); } public bool GetLaserResetSetBitStatus() { throw new NotImplementedException(); } public bool GetLaserStartSetBitStatus() { throw new NotImplementedException(); } public string GetPowerCenter() { throw new NotImplementedException(); } public string GetPowerRing() { throw new NotImplementedException(); } public bool GetStartLaserSetBitStatus() { throw new NotImplementedException(); } public bool GetWarningStatus() { throw new NotImplementedException(); } public bool GetLaserInterlock() { throw new NotImplementedException(); } } }