리크 테스트 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
4.8 KiB

using System;
using System.IO.Ports;
namespace leak_test_project.Infrastructure
{
/// <summary>
/// 하드웨어 통신을 위한 추상화 인터페이스.
/// 시리얼(RS232), 이더넷(TCP/IP) 등 통신 방식에 상관없이
/// 상위 서비스에서 동일한 방식으로 하드웨어에 접근할 수 있도록 정의함.
/// </summary>
public interface ICommunication
{
/// <summary> 통신 채널 식별 이름 (예: COM1, TCP_192.168.0.1) </summary>
string Name { get; }
/// <summary> 현재 통신 채널이 열려 있는지 여부 </summary>
bool IsOpen { get; }
/// <summary> 통신 채널을 연결함 </summary>
bool Open();
/// <summary> 통신 채널 연결을 해제함 </summary>
void Close();
/// <summary> 데이터를 하드웨어로 전송함 </summary>
bool Write(string data);
/// <summary> 수신 버퍼를 비워 잔류 데이터를 제거함 </summary>
void ClearBuffer();
/// <summary> 하드웨어로부터 데이터를 수신했을 때 발생하는 이벤트 </summary>
event System.EventHandler<string> DataReceived;
/// <summary> 연결 상태가 변경되었을 때 발생하는 이벤트 (connected, disconnected) </summary>
event System.EventHandler<bool> ConnectionStatusChanged;
}
/// <summary>
/// RS232 시리얼 통신을 담당하는 구현체.
/// 연결 안정성 강화를 위한 예외 처리 및 상태 감지 로직 포함.
/// </summary>
public class SerialProvider : ICommunication, IDisposable
{
private SerialPort _serialPort;
private bool _disposed = false;
public string Name { get; private set; }
public bool IsOpen => _serialPort != null && !_disposed && _serialPort.IsOpen;
public event EventHandler<string> DataReceived;
public event EventHandler<bool> ConnectionStatusChanged;
public SerialProvider(string portName, int baudRate)
{
Name = portName;
_serialPort = new SerialPort(portName, baudRate, Parity.None, 8, StopBits.One);
_serialPort.Handshake = Handshake.None;
_serialPort.DtrEnable = true; // 터미널 프로그램(포트몬)과 동일하게 제어 신호 활성화
_serialPort.RtsEnable = true;
_serialPort.ReadTimeout = 500;
_serialPort.WriteTimeout = 500;
_serialPort.DataReceived += (s, e) => {
try {
string data = _serialPort.ReadExisting();
if (!string.IsNullOrEmpty(data))
DataReceived?.Invoke(this, data);
} catch (Exception ex) {
Console.WriteLine($"[Serial Error] Read error on {Name}: {ex.Message}");
}
};
// 기기가 끊겼을 때 감지 (일부 환경에서는 PinChanged 등으로 감지 가능)
_serialPort.ErrorReceived += (s, e) => {
ConnectionStatusChanged?.Invoke(this, false);
};
}
public bool Open()
{
if (_disposed) return false;
try {
if (IsOpen) return true;
_serialPort.Open();
ConnectionStatusChanged?.Invoke(this, true);
return true;
} catch (Exception ex) {
Console.WriteLine($"[Serial Error] Failed to open {Name}: {ex.Message}");
ConnectionStatusChanged?.Invoke(this, false);
return false;
}
}
public void Close()
{
try {
if (IsOpen) {
_serialPort.Close();
ConnectionStatusChanged?.Invoke(this, false);
}
} catch (Exception ex) {
Console.WriteLine($"[Serial Error] Error closing {Name}: {ex.Message}");
}
}
public bool Write(string data)
{
if (!IsOpen) return false;
try {
_serialPort.Write(data);
return true;
} catch (Exception ex) {
Console.WriteLine($"[Serial Error] Write error on {Name}: {ex.Message}");
return false;
}
}
public void ClearBuffer()
{
if (IsOpen) {
try {
_serialPort.DiscardInBuffer();
_serialPort.DiscardOutBuffer();
_serialPort.ReadExisting();
} catch { }
}
}
public void Dispose()
{
if (!_disposed)
{
_disposed = true;
Close();
_serialPort?.Dispose();
_serialPort = null;
}
}
}
}