2026-01-26 18:56:53 +09:00

462 lines
14 KiB
C#

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();
}
}
}