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

462 lines
16 KiB
C#

using Aurora.Api;
using Aurora.Api.Devices;
using Aurora.Util.HislogPlus;
using Hermes;
using PropertyTools.DataAnnotations;
using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using System.Windows.Input;
using static AuroraHeightSensor.HeightSensor;
namespace AuroraHeightSensor.Keyence
{
public enum ILResponseType
{
Write = 0,
Read = 1,
}
public enum ILCommandType
{
//데이터 번호 1 ~ 28까지는 무조건 Write만 가능하고 설정 데이터를 +000000001로 해야 한다.
CurrentReadValue = 0, //0은 없지만 데이터 측정 시에 대해서 쓰기 위해 생성
ZeroOffsetRequest = 1,
ZeroOffsetClearRequest = 2,
ResetRequest = 3,
ElevationDifferenceCountFilter = 28,
ZeroOffsetResult = 54, //Read만 가능
ResetResult = 55, //Read만 가능
ZeroShiftSave = 152 //Read, Write 둘 다 가능
}
public static class ILAmpNo
{
//2개를 사용중이며 CH No에 따른 제품 번호를 정의 한다.
public const string IL1000_1 = "01";
public const string IL1000_2 = "02";
public const string IL1000_3 = "03";
public const string IL1050 = "04";
}
public class HeightSensorIL : SocketConn, IHeightSensor
{
private readonly Dictionary<int, string> ErrorMessages = new Dictionary<int, string>()
{
{ 009, "입력된 데이터가 유효 범위 밖입니다." },
{ 012, "동작 명령이 실행 불가능한 상태입니다." },
{ 014, "이 주소는 쓰기 금지 또는 쓰기할 수 없는 상태입니다." },
{ 016, "이 데이터 번호는 읽기 금지 또는 읽기가 불가능한 상태입니다." },
{ 020, "데이터 번호가 유효 범위 밖입니다." },
{ 022, "앰프 번호가 유효 범위 밖입니다." },
{ 031, "지정된 앰프 번호, 데이터 번호에 대한 읽기/쓰기에 센서가 대응하지 않습니다. 현재의 모드로는 쓰기할 수 없습니다." },
{ 254, "시스템 에러 상태입니다. 기동 시간을 대기하거나 재기동이 필요할 수 있습니다." },
{ 255, "커맨드 포맷이 바르지 않습니다." }
};
private readonly Dictionary<string, string> MeasureState = new Dictionary<string, string>()
{
{ "+100000000", "측정 데이터 에러" },
{ "+099999999", "측정 데이터 오버 레인지(센서 앰프의 표시가 FFFF)" },
{ "-099999999", "측정 데이터 언더 레인지(센서 앰프의 표시가 -FFFF)" },
{ "-099999998", "측정 데이터 무효 상태(센서 앰프의 표시가 ----)" }
};
private const string ReadCmd = "SR";
private const string WriteCmd = "SW";
private const string MeasureAllCmd = "M0\r\n";
private string _ampNo = "01"; // [DL 유닛 경우, 00] // [기본 유닛 경우, 01..15 최대 15개까지 가능]
private ILCommandType _sendCommand;
private object _lock = new object();
public HeightSensorIL(string deviceId, bool isSimul = false, SocketProtocol type = SocketProtocol.TCP, Action<bool> commErr = null) : base(deviceId, isSimul, type, commErr)
{
}
public int Activate(IConnConfig Config)
{
return Connect(Config as SocketConnConfig);
}
public bool CheckConnected()
{
return IsConnected();
}
public int Deactivate()
{
return Close();
}
public int Measure(eChannel channel, out double value)
{
value = double.NaN;
switch (channel) {
case eChannel.CH0:
_ampNo = ILAmpNo.IL1000_1;
break;
case eChannel.CH1:
_ampNo = ILAmpNo.IL1000_2;
break;
case eChannel.CH2:
_ampNo = ILAmpNo.IL1000_3;
break;
case eChannel.CH3:
_ampNo = ILAmpNo.IL1050;
break;
default:
_ampNo = ILAmpNo.IL1000_1;
break;
}
byte[] receive = new byte[64];
lock (_lock) {
var command = MakeCommand(_ampNo, ILCommandType.CurrentReadValue, "0", 1);
if (SendAndRecieve(command, out receive, 2000) != E1.OK) {
Log.I($"[Fail] : Measure Request >> {command}");
return E1.NETWORK;
}
Task.Delay(100);
if (!ParseResponse(Encoding.ASCII.GetString(receive), ILCommandType.CurrentReadValue))
return E2.UNKNOWN;
}
return E1.OK;
}
public int MeasureAll(out List<double> Sensorvalue)
{
Sensorvalue = null;
byte[] receive = new byte[64];
lock (_lock) {
if (SendAndRecieve(MeasureAllCmd, out receive) != E1.OK) {
Log.I($"[Fail] : {MeasureAllCmd}");
return E1.OK;
}
if (!ParseResponse(Encoding.ASCII.GetString(receive), out Sensorvalue))
return E1.OK;
}
return E1.OK;
}
public int SetLed(bool isOn)
{
return 0;
}
public int SetZero(eChannel channel, bool isSet = true)
{
return E1.OK;
}
public int StartStopAutoTransmit(bool isOn, ICommand callback)
{
return 0;
}
public int SetZeroShiftSave(eChannel channel)
{
byte[] receive = new byte[64];
lock (_lock) {
switch (channel) {
case eChannel.CH0:
_ampNo = ILAmpNo.IL1000_1;
break;
case eChannel.CH1:
_ampNo = ILAmpNo.IL1000_2;
break;
case eChannel.CH2:
_ampNo = ILAmpNo.IL1000_3;
break;
case eChannel.CH3:
_ampNo = ILAmpNo.IL1050;
break;
default:
_ampNo = ILAmpNo.IL1000_1;
break;
}
var command = MakeCommand(_ampNo, ILCommandType.ZeroShiftSave, "+000000001", 0);
if (SendAndRecieve(command, out receive, 1000) != E1.OK) {
Log.I($"[Fail] : Zero Request >> {command}");
return E1.NETWORK;
}
Task.Delay(100);
if (!ParseResponse(Encoding.ASCII.GetString(receive), ILCommandType.ZeroShiftSave))
return E2.UNKNOWN;
}
return E1.OK;
}
public int SetZeroShift(eChannel channel)
{
byte[] receive = new byte[64];
lock (_lock) {
switch (channel) {
case eChannel.CH0:
_ampNo = ILAmpNo.IL1000_1;
break;
case eChannel.CH1:
_ampNo = ILAmpNo.IL1000_2;
break;
case eChannel.CH2:
_ampNo = ILAmpNo.IL1000_3;
break;
case eChannel.CH3:
_ampNo = ILAmpNo.IL1050;
break;
default:
_ampNo = ILAmpNo.IL1000_1;
break;
}
SetZeroShiftSave(channel);
Task.Delay(100);
var command = MakeCommand(_ampNo, ILCommandType.ZeroOffsetRequest, "+000000001", 0);
if (SendAndRecieve(command, out receive, 1000) != E1.OK) {
Log.I($"[Fail] : Zero Request >> {command}");
return E1.NETWORK;
}
Task.Delay(100);
if (!ParseResponse(Encoding.ASCII.GetString(receive), ILCommandType.ZeroOffsetRequest))
return E2.UNKNOWN;
command = MakeCommand(_ampNo, ILCommandType.ZeroOffsetResult, "0", 1);
if (SendAndRecieve(command, out receive, 1000) != E1.OK) {
Log.I($"[Fail] : Zero Result >> {command}");
return E1.NETWORK;
}
Task.Delay(100);
if (!ParseResponse(Encoding.ASCII.GetString(receive), ILCommandType.ZeroOffsetResult))
return E2.UNKNOWN;
}
return E1.OK;
}
public int SetZeroShiftReset(eChannel channel)
{
byte[] receive = new byte[64];
lock (_lock) {
switch (channel) {
case eChannel.CH0:
_ampNo = ILAmpNo.IL1000_1;
break;
case eChannel.CH1:
_ampNo = ILAmpNo.IL1000_2;
break;
case eChannel.CH2:
_ampNo = ILAmpNo.IL1000_3;
break;
case eChannel.CH3:
_ampNo = ILAmpNo.IL1050;
break;
default:
_ampNo = ILAmpNo.IL1000_1;
break;
}
var command = MakeCommand(_ampNo, ILCommandType.ZeroOffsetClearRequest, "+000000001", 0);
if (SendAndRecieve(command, out receive, 1000) != E1.OK) {
Log.I($"[Fail] : ZeroReset Request >> {command}");
return E1.NETWORK;
}
Task.Delay(100);
if (!ParseResponse(Encoding.ASCII.GetString(receive), ILCommandType.ZeroOffsetClearRequest))
return E2.UNKNOWN;
command = MakeCommand(_ampNo, ILCommandType.ZeroOffsetResult, "0", 1);
if (SendAndRecieve(command, out receive, 1000) != E1.OK) {
Log.I($"[Fail] : ZeroReset Result >> {command}");
return E1.NETWORK;
}
Task.Delay(100);
if (!ParseResponse(Encoding.ASCII.GetString(receive), ILCommandType.ZeroOffsetResult))
return E2.UNKNOWN;
}
return E1.OK;
}
public int Reset(eChannel channel)
{
byte[] receive = new byte[64];
lock (_lock) {
switch (channel) {
case eChannel.CH0:
_ampNo = ILAmpNo.IL1000_1;
break;
case eChannel.CH1:
_ampNo = ILAmpNo.IL1000_2;
break;
case eChannel.CH2:
_ampNo = ILAmpNo.IL1000_3;
break;
case eChannel.CH3:
_ampNo = ILAmpNo.IL1050;
break;
default:
_ampNo = ILAmpNo.IL1000_1;
break;
}
var command = MakeCommand(_ampNo, ILCommandType.ResetRequest, "+000000001", 0);
if (SendAndRecieve(command, out receive, 1000) != E1.OK) {
Log.I($"[Fail] : Reset Request >> {command}");
return E1.NETWORK;
}
Task.Delay(100);
if (!ParseResponse(Encoding.ASCII.GetString(receive), ILCommandType.ResetRequest))
return E2.UNKNOWN;
command = MakeCommand(_ampNo, ILCommandType.ResetResult, "0", 1);
if (SendAndRecieve(command, out receive, 1000) != E1.OK) {
Log.I($"[Fail] : Reset Result >> {command}");
return E1.NETWORK;
}
Task.Delay(100);
if (!ParseResponse(Encoding.ASCII.GetString(receive), ILCommandType.ResetResult))
return E2.UNKNOWN;
}
return E1.OK;
}
public bool ParseResponse(string response, ILCommandType cmd)
{
if(string.IsNullOrEmpty(response))
return false;
// Command 확인
if (_sendCommand != cmd)
return false;
// 정상 종료가 확인
//if (CheckResponse(response) != ILResponseType.NormalComplete)
// return false;
// 에러 확인 (ER,**,ddd\r\n)
if (CheckErrorResponse(response))
return false;
return true;
}
public bool ParseResponse(string response, ILCommandType cmd, out double value)
{
value = double.NaN;
if (ParseResponse(response, cmd))
return false;
value = CheckValueResponse(response);
return true;
}
public bool ParseResponse(string response, out List<double> values)
{
values = null;
// 정상 종료가 확인
//if (CheckResponse(response) != ILResponseType.NormalComplete)
// return false;
// 애러 확인
if (CheckErrorResponse(response))
return false;
values = CheckValuesResponse(response);
return true;
}
private ILResponseType CheckResponse(string response)
{
//if (response.Contains("+000000000"))
// return ILResponseType.Running;
//if (response.Contains("+000000002"))
// return ILResponseType.AbnormalComplete;
//return ILResponseType.NormalComplete;
return 0;
}
private bool CheckErrorResponse(string response)
{
try {
var errorMatch = Regex.Match(response, @"ER,[A-Z]+,?(\d{3})");
if (errorMatch.Success) {
int errorCode = int.Parse(errorMatch.Groups[1].Value);
if (ErrorMessages.TryGetValue(errorCode, out string message)) {
Log.I($"[에러 {errorCode}] {message}");
}
return true;
}
} catch (Exception ex) {
Log.I($"Exception : {ex.Message}");
}
return false;
}
private double CheckValueResponse(string response)
{
try {
var match = Regex.Match(response, @"[\+\-]\d{9}");
if (match.Success) {
var value = Convert.ToDouble(match.Value) / 1000;
Log.I($"Height Measure : {value}");
return value;
}
} catch (Exception ex) {
Log.I($"Exception : {ex.Message}");
}
return double.NaN;
}
private List<double> CheckValuesResponse(string response)
{
try {
List<double> list = new List<double>();
string[] parts = response.Split(',');
for (int i = 1; i < parts.Length; i++) // 0번째는 "M0"
{
string value = parts[i].Replace("\r", "").Replace("\n", "").Trim();
list.Add(Convert.ToDouble(value) / 1000);
}
return list;
} catch (Exception ex) {
Log.I($"Exception : {ex.Message}");
}
return null;
}
public string MakeCommand(string ampNo, ILCommandType command, string sendValue, int attribute)
{
string ret;
if(command == ILCommandType.CurrentReadValue){
ret = "M0";
}
else if(attribute == 0){ //0이면 Write
ret = ($"{WriteCmd},{ampNo},{(int)command:000},{sendValue}");
}
else{
ret = ($"{ReadCmd},{ampNo},{(int)command:000}");
}
ret += "\r\n";
_sendCommand = command;
return ret;
}
}
}