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 ErrorMessages = new Dictionary() { { 009, "입력된 데이터가 유효 범위 밖입니다." }, { 012, "동작 명령이 실행 불가능한 상태입니다." }, { 014, "이 주소는 쓰기 금지 또는 쓰기할 수 없는 상태입니다." }, { 016, "이 데이터 번호는 읽기 금지 또는 읽기가 불가능한 상태입니다." }, { 020, "데이터 번호가 유효 범위 밖입니다." }, { 022, "앰프 번호가 유효 범위 밖입니다." }, { 031, "지정된 앰프 번호, 데이터 번호에 대한 읽기/쓰기에 센서가 대응하지 않습니다. 현재의 모드로는 쓰기할 수 없습니다." }, { 254, "시스템 에러 상태입니다. 기동 시간을 대기하거나 재기동이 필요할 수 있습니다." }, { 255, "커맨드 포맷이 바르지 않습니다." } }; private readonly Dictionary MeasureState = new Dictionary() { { "+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 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 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 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 CheckValuesResponse(string response) { try { List list = new List(); 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; } } }