272 lines
8.9 KiB
C#
272 lines
8.9 KiB
C#
using Aurora;
|
|
using Aurora.Api;
|
|
using Hermes;
|
|
using MathNet.Numerics.Distributions;
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Threading;
|
|
using System.Windows;
|
|
|
|
namespace AuroraLaser.Coherent
|
|
{
|
|
// Compact 시리즈가 아닌, Coherent 사 제품을 공통으로 묶을 수 있을까?
|
|
public class LaserCompact : Device
|
|
{
|
|
protected readonly Logger Log;
|
|
|
|
private ILaserCompact _laser; // 공통 인터페이스
|
|
public LaserCompactMiniConfig _rawConfig;
|
|
|
|
protected bool _isSimulBySetting;
|
|
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 LaserCompact(string deviceId, bool isSimulBySetting = false, int laserIndex = 0)
|
|
{
|
|
DeviceId = deviceId;
|
|
CommType = CommunicationType.Serial;
|
|
Type = DeviceType.Laser;
|
|
_isSimulBySetting = isSimulBySetting;
|
|
|
|
Index = laserIndex;
|
|
Log = new Logger("Compact_" + deviceId);
|
|
}
|
|
#endregion
|
|
|
|
#region 활성화/비활성화
|
|
protected override int DoActivate(IDeviceConfig config)
|
|
{
|
|
_rawConfig = config as LaserCompactMiniConfig;
|
|
IsSimul = _rawConfig.IsSimul || _isSimulBySetting;
|
|
|
|
_laser = new CompactMini(DeviceId, IsSimul);
|
|
var result = _laser.Connect(_rawConfig);
|
|
if (IsSimul == false) {
|
|
if (result == E1.OK) { // 통신 연결 성공
|
|
if (_laser.NeedConfigSave) { // 시리얼넘버의 최초 write 발생 시, config 저장 필요
|
|
Application.Current.AuroraEnv().DeviceManager.SaveDeviceConfig(DeviceId); // Config 저장
|
|
// SN 가 변경되었다는 이벤트 publish
|
|
EventPublisher.Publish(new EventMessage("LaserCompactMini", LaserEvent.EVENT_ID_SerialNumberUpdate));
|
|
|
|
// reset
|
|
_laser.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()
|
|
{
|
|
Log.I($"Deactivate Laser : {DeviceId}");
|
|
|
|
if (IsSimul == false) return _laser.Disconnect();
|
|
else return E1.OK;
|
|
}
|
|
#endregion
|
|
|
|
#region 통신 상태
|
|
public int Reconnect()
|
|
{
|
|
if (Monitor.TryEnter(_alarmLockReconnectObj) && (IsCommError || !_laser.IsConnected())) {
|
|
if (_laser.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 = !_laser.IsConnected();
|
|
return IsCommError == false;
|
|
}
|
|
|
|
// 알람용인데, 흠 전체적인 그림을 봐야겠는데....
|
|
public bool IsNetworkError()
|
|
{
|
|
if (_laser == null) {
|
|
Log.E($"{DeviceId} is null");
|
|
return true;
|
|
} else {
|
|
IsCommError = _laser.IsNetworkError || !_laser.IsConnected();
|
|
if (IsCommError) {
|
|
if (!_laser.IsConnected()) {
|
|
AddAlarm(CreateEigenAlarmCode(98)); // Eigen 단어가 어색한데....장치니까 Device 는 어떨까?
|
|
} else {
|
|
AddAlarm(CreateEigenAlarmCode(99));
|
|
}
|
|
}
|
|
return IsCommError;
|
|
}
|
|
}
|
|
#endregion
|
|
|
|
|
|
// 이 구조체들이 공용화가 어디까지 될까?? Compact 시리즈 모델이 추가되면 수정여부 재검토
|
|
public STRUCT_STATUS_REGISTER GetLaserStatusInfo()
|
|
{
|
|
return _laser.GetLaserStatusInfo();
|
|
}
|
|
|
|
public STRUCT_LASER_MODE_REGISTER GetLaserModeInfo()
|
|
{
|
|
return _laser.GetLaserModeInfo();
|
|
}
|
|
|
|
public STRUCT_ERROR_REGISTER GetLaserErrMsgInfo()
|
|
{
|
|
return _laser.GetLaserErrMsgInfo();
|
|
}
|
|
|
|
#region 레이저 관련, 통신 R/W API 포함
|
|
public bool IsLaserError()
|
|
{
|
|
bool result = _laser.IsLaserError;
|
|
if (result) {
|
|
var statusInfo = GetLaserStatusInfo();
|
|
if (statusInfo.bErrorStatus) { AddAlarm(CreateEigenAlarmCode(10)); }
|
|
if (statusInfo.bFatalError) { AddAlarm(CreateEigenAlarmCode(11)); }
|
|
}
|
|
return result;
|
|
}
|
|
|
|
public void ErrorReset()
|
|
{
|
|
_laser.ErrorReset();
|
|
ClearAlarm(new int[2] { CreateEigenAlarmCode(10), CreateEigenAlarmCode(11) });
|
|
}
|
|
|
|
public int SetOutputPower(double powerPerc)
|
|
{
|
|
_powerPerc = powerPerc;
|
|
if (IsSimul == false) {
|
|
return _laser.SetOutputPower(powerPerc) ? E1.OK : FAIL;
|
|
}
|
|
|
|
return E1.OK;
|
|
}
|
|
|
|
#region Power calibration
|
|
public int LoadLaserCalibrationData()
|
|
{
|
|
// Aurora Config Json reload
|
|
Application.Current.AuroraEnv().DeviceManager.LoadDeviceConfig(DeviceId);
|
|
_laser.LoadLaserCalibrationData();
|
|
return E1.OK;
|
|
}
|
|
|
|
public List<(double perc, double watt)> GetPowerCalData()
|
|
{
|
|
return _laser?.GetPowerCalData();
|
|
}
|
|
public double Watt2Power(double watt)
|
|
{
|
|
return _laser.Watt2Power(watt);
|
|
}
|
|
|
|
public double Watt2Power(double watt, eModelType calibType)
|
|
{
|
|
return _laser.Watt2Power(watt, calibType);
|
|
}
|
|
|
|
// 오직 시뮬에서만 필요
|
|
public double Power2Watt(double dPowerPerc)
|
|
{
|
|
if (IsSimul) {
|
|
return _laser.Power2Watt(dPowerPerc);
|
|
} else {
|
|
Log.W("Only for Sim mode");
|
|
return 0.0;
|
|
}
|
|
}
|
|
public void SetLaserPowerCalibMethod(string powerCalibMethod)
|
|
{
|
|
_laser?.SetLaserPowerCalibMethod(powerCalibMethod);
|
|
}
|
|
|
|
public string GetLaserPowerCalibMethod()
|
|
{
|
|
return _laser?.GetLaserPowerCalibMethod();
|
|
}
|
|
#endregion
|
|
|
|
public void Update()
|
|
{
|
|
if (!IsActivated) return;
|
|
|
|
if (IsSimul == false) {
|
|
_laser.Update();
|
|
} else { // 시뮬
|
|
// 1. 레이저 Internal Set Power 업데이트
|
|
int iPow = (int)(Math.Round(_powerPerc, 1) * 10); // [0, 1000]
|
|
var l_compactMiniRegister = (_laser as CompactMini).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
|
|
}
|
|
}
|