리크 테스트 gui
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

140 lines
6.3 KiB

1 week ago
using System;
using System.Threading.Tasks;
using leak_test_project.Infrastructure;
using leak_test_project.Models;
using leak_test_project.Utils;
namespace leak_test_project.Services
{
/// <summary>
/// 신규 4253 보드를 사용하여 제품 ID를 읽는 센서 서비스.
/// ZmdiSensorService와 동일한 구조로 구현되어 교체가 용이함.
/// </summary>
public class Board4253SensorService : IIdSensorService
{
private readonly Board4253Service _service;
private readonly int _sensorIndex;
public event EventHandler<string> ProgressMessage;
public event EventHandler<string> ErrorMessage;
public event EventHandler<bool> ConnectionChanged;
public Board4253SensorService(Board4253Service service, int sensorIndex)
{
_service = service;
_sensorIndex = sensorIndex;
// 좌우 오류 간섭을 막기 위해 공용 에러 이벤트 구독 해제
_service.ConnectionChanged += (s, isConnected) => ConnectionChanged?.Invoke(this, isConnected);
}
public bool Connect() => _service.Connect();
public void Disconnect() => _service.Disconnect();
public SensorIdData ReadSensor()
{
try
{
ProgressMessage?.Invoke(this, "4253 보드에서 ID 읽기 시도 중...");
int channel = _sensorIndex + 1;
// 1. 보드 상태 확인 (Fail인 경우 중단)
int extendedTimeout = 15000;
string statusCmd = $"x00c_00{channel}101:owt28006727ea97c7801";
var statusTask = Task.Run(() => _service.CheckStatusAsync(channel));
if (!statusTask.Wait(extendedTimeout))
{
string buf = _service.GetLastBuffer();
string displayBuf = string.IsNullOrEmpty(buf) ? "수신된 데이터 없음" : buf;
ErrorMessage?.Invoke(this, $"통신 실패 (4253 보드 CH{channel} 상태 타임아웃)\r\n[송신값]: {statusCmd}\r\n[수신값]: {displayBuf}");
return null;
}
if (!statusTask.Result)
{
string buf = _service.GetLastBuffer();
string displayBuf = string.IsNullOrEmpty(buf) ? "수신된 데이터 없음" : buf;
ErrorMessage?.Invoke(this, $"통신 실패 (4253 보드 CH{channel} 상태 이상 또는 Fail)\r\n[송신값]: {statusCmd}\r\n[수신값]: {displayBuf}");
return null;
}
1 week ago
// 2. ID 읽기 (끝자리가 F일 경우 최대 3회 시도)
1 week ago
string idCmd = $"x00c_00{channel}101:ow2800326003e";
1 week ago
string rawId = null;
int maxAttempts = 3;
1 week ago
1 week ago
for (int attempt = 1; attempt <= maxAttempts; attempt++)
1 week ago
{
1 week ago
var idTask = Task.Run(() => _service.ReadIdAsync(channel));
if (!idTask.Wait(extendedTimeout))
{
if (attempt == maxAttempts)
{
string buf = _service.GetLastBuffer();
string displayBuf = string.IsNullOrEmpty(buf) ? "수신된 데이터 없음" : buf;
ErrorMessage?.Invoke(this, $"통신 실패 (4253 보드 CH{channel} ID 대기 타임아웃)\r\n[송신값]: {idCmd}\r\n[수신값]: {displayBuf}");
return null;
}
continue;
}
rawId = idTask.Result;
if (string.IsNullOrEmpty(rawId))
{
if (attempt == maxAttempts)
{
string buf = _service.GetLastBuffer();
string displayBuf = string.IsNullOrEmpty(buf) ? "수신된 데이터 없음" : buf;
ErrorMessage?.Invoke(this, $"통신 실패 (4253 보드 CH{channel} ID 응답 없거나 파싱 오류)\r\n[송신값]: {idCmd}\r\n[수신값]: {displayBuf}");
return null;
}
continue;
}
// 정상적으로 파싱된 경우, 끝자리가 'F'인지 확인
if (rawId.EndsWith("F", StringComparison.OrdinalIgnoreCase))
{
if (attempt < maxAttempts)
{
ProgressMessage?.Invoke(this, $"ID 끝자리가 'F'입니다 ({rawId}). 재시도 중... ({attempt}/{maxAttempts})");
Task.Delay(500).Wait(); // 재시도 전 약간의 딜레이
continue;
}
else
{
ProgressMessage?.Invoke(this, $"최대 재시도(2회 추가) 초과. 끝자리가 F인 ID({rawId})를 사용합니다.");
}
}
// 제대로 된 값을 얻었거나 최대 횟수에 도달하면 루프 탈출
break;
1 week ago
}
// 3. SensorIdData 객체 구성 (16자리 ID를 각 필드에 적절히 분배)
// 신규 보드는 16자리 전체가 ID이므로, 파싱 로직 없이 통째로 넣거나
// 특정 규칙이 있다면 여기서 분할함.
var data = new SensorIdData
{
LowID = rawId,
ID = rawId, // 16자리 전체를 ID로 사용
Serial = "", // 시리얼 번호는 현재 존재하지 않으므로 강제로 파싱하지 않음
Item = "N/A",
PrevResult = "F" // '불량제품 투입' 필터를 통과하기 위한 강제 초기화
};
ProgressMessage?.Invoke(this, "ID 읽기 성공");
return data;
}
catch (Exception ex)
{
ErrorMessage?.Invoke(this, $"4253 보드 읽기 중 예외 발생: {ex.Message}");
return null;
}
}
public void Dispose()
{
_service.Dispose();
}
}
}