|
|
|
|
using System;
|
|
|
|
|
using System.IO.Ports;
|
|
|
|
|
|
|
|
|
|
namespace leak_test_project.Infrastructure
|
|
|
|
|
{
|
|
|
|
|
/// <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;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|