716 lines
26 KiB
C#
716 lines
26 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.ComponentModel;
|
|
using System.Data;
|
|
using System.Drawing;
|
|
using System.Linq;
|
|
using System.Text;
|
|
using System.Threading.Tasks;
|
|
using System.Windows.Forms;
|
|
using System.IO.Ports;
|
|
using System.IO;
|
|
using AR;
|
|
|
|
namespace Project
|
|
{
|
|
|
|
public partial class Form1 : Form
|
|
{
|
|
|
|
|
|
public Form1()
|
|
{
|
|
InitializeComponent();
|
|
|
|
PUB.init();
|
|
|
|
// 현재 설치되어있는 시리얼포트목록을 조회해서 cmbPort... 컨트롤에 미리 입력한다.
|
|
RefreshPortList();
|
|
|
|
// 기본 BaudRate 설정
|
|
tbBaudAGV.Text = "115200";
|
|
tbBaudBMS.Text = "9600";
|
|
}
|
|
|
|
/// <summary>
|
|
/// 시리얼 포트 목록을 새로고침하여 콤보박스에 추가
|
|
/// </summary>
|
|
private void RefreshPortList()
|
|
{
|
|
try
|
|
{
|
|
string[] ports = SerialPort.GetPortNames();
|
|
|
|
cmbPortAGV.Items.Clear();
|
|
cmbPortBMS.Items.Clear();
|
|
|
|
foreach (string port in ports)
|
|
{
|
|
cmbPortAGV.Items.Add(port);
|
|
cmbPortBMS.Items.Add(port);
|
|
}
|
|
|
|
|
|
|
|
addLog($"포트 목록 새로고침 완료: {ports.Length}개 포트 발견");
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
addLog($"포트 목록 조회 오류: {ex.Message}");
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// 설정파일에서 데이터를 읽어서 컨트롤에 설정한다
|
|
/// </summary>
|
|
void LoadSetting()
|
|
{
|
|
try
|
|
{
|
|
|
|
// AGV 설정
|
|
if (!string.IsNullOrEmpty(PUB.setting.Port_AGV))
|
|
{
|
|
this.cmbPortAGV.Text = PUB.setting.Port_AGV;
|
|
}
|
|
tbBaudAGV.Text = PUB.setting.Baud_AGV.ToString();
|
|
|
|
// BMS 설정
|
|
if (!string.IsNullOrEmpty(PUB.setting.Port_BAT))
|
|
{
|
|
cmbPortBMS.Text = PUB.setting.Port_BAT;
|
|
}
|
|
tbBaudBMS.Text = PUB.setting.Baud_BAT.ToString();
|
|
|
|
addLog("설정 파일 로드 완료");
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
addLog($"설정 로드 오류: {ex.Message}");
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// 현재 설정된 값을 확인하고 셋팅파일에 기록한다
|
|
/// </summary>
|
|
void SaveSetting()
|
|
{
|
|
try
|
|
{
|
|
// 현재 UI 값을 설정 객체에 반영
|
|
PUB.setting.Port_AGV = cmbPortAGV.SelectedItem?.ToString() ?? "";
|
|
PUB.setting.Baud_AGV = int.TryParse(tbBaudAGV.Text, out int agvBaud) ? agvBaud : 115200;
|
|
PUB.setting.Port_BAT = cmbPortBMS.SelectedItem?.ToString() ?? "";
|
|
PUB.setting.Baud_BAT = int.TryParse(tbBaudBMS.Text, out int bmsBaud) ? bmsBaud : 9600;
|
|
|
|
// 파일에 저장
|
|
PUB.setting.Save();
|
|
|
|
addLog("설정 파일 저장 완료");
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
addLog($"설정 저장 오류: {ex.Message}");
|
|
}
|
|
}
|
|
|
|
private void Form1_Load(object sender, EventArgs e)
|
|
{
|
|
LoadSetting();
|
|
}
|
|
|
|
private void btLoadSetting_Click(object sender, EventArgs e)
|
|
{
|
|
LoadSetting();
|
|
}
|
|
|
|
private void btSaveSetting_Click(object sender, EventArgs e)
|
|
{
|
|
SaveSetting();
|
|
}
|
|
|
|
private void btTestAGV_Click(object sender, EventArgs e)
|
|
{
|
|
// AGV 용 프로토콜을 전송해서 올바르게 피드백이 오는지 확인한다
|
|
// AGV Protocol: STX(0x02) + Data + ETX(0x03)
|
|
|
|
if (cmbPortAGV.SelectedItem == null)
|
|
{
|
|
addLog("[AGV] 포트를 선택해주세요");
|
|
return;
|
|
}
|
|
|
|
if (!int.TryParse(tbBaudAGV.Text, out int baudRate))
|
|
{
|
|
addLog("[AGV] BaudRate가 올바르지 않습니다");
|
|
return;
|
|
}
|
|
|
|
try
|
|
{
|
|
addLog($"[AGV] 테스트 시작: {cmbPortAGV.SelectedItem} @ {baudRate}bps");
|
|
|
|
|
|
using (arDev.Narumi port = new arDev.Narumi())
|
|
{
|
|
port.PortName = cmbPortAGV.SelectedItem.ToString();
|
|
port.BaudRate = baudRate;
|
|
port.Message += (s1, e1) =>{
|
|
addLog($"[AGV] 응답 수신: {e1.Message}");
|
|
};
|
|
port.Open();
|
|
addLog($"[AGV] 포트 열기 성공");
|
|
|
|
DateTime sendtime = DateTime.Now;
|
|
port.AGVMoveStop("test");//
|
|
addLog($"[AGV] 테스트 명령 전송:");
|
|
|
|
// 응답 대기
|
|
System.Threading.Thread.Sleep(1200);
|
|
|
|
|
|
if (port.lastRecvTime > sendtime)
|
|
{
|
|
|
|
// STX, ETX 확인
|
|
//if (response.Length >= 2 && response[0] == 0x02 && response[response.Length - 1] == 0x03)
|
|
//{
|
|
addLog($"[AGV] ✓ 통신 성공 - 올바른 프로토콜 응답");
|
|
//}
|
|
//else
|
|
//{
|
|
// addLog($"[AGV] ⚠ 응답은 받았으나 프로토콜 형식이 다름");
|
|
//}
|
|
}
|
|
else
|
|
{
|
|
addLog($"[AGV] ⚠ 응답 없음 - 포트는 열렸으나 장치 응답 없음");
|
|
}
|
|
|
|
port.Close();
|
|
addLog($"[AGV] 포트 닫기 완료");
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
addLog($"[AGV] ✗ 오류 발생: {ex.Message}");
|
|
}
|
|
}
|
|
|
|
|
|
|
|
private void btTestBMS_Click(object sender, EventArgs e)
|
|
{
|
|
// BMS 용 프로토콜을 전송해서 올바르게 피드백이 오는지 확인한다
|
|
// BMS Protocol: STX(0xDD) + Data(32 bytes) + ETX(0x77)
|
|
|
|
if (cmbPortBMS.SelectedItem == null)
|
|
{
|
|
addLog("[BMS] 포트를 선택해주세요");
|
|
return;
|
|
}
|
|
|
|
if (!int.TryParse(tbBaudBMS.Text, out int baudRate))
|
|
{
|
|
addLog("[BMS] BaudRate가 올바르지 않습니다");
|
|
return;
|
|
}
|
|
|
|
try
|
|
{
|
|
addLog($"[BMS] 테스트 시작: {cmbPortBMS.SelectedItem} @ {baudRate}bps");
|
|
|
|
using (SerialPort port = new SerialPort())
|
|
{
|
|
port.PortName = cmbPortBMS.SelectedItem.ToString();
|
|
port.BaudRate = baudRate;
|
|
port.DataBits = 8;
|
|
port.Parity = Parity.None;
|
|
port.StopBits = StopBits.One;
|
|
port.ReadTimeout = 3000;
|
|
port.WriteTimeout = 3000;
|
|
|
|
port.Open();
|
|
addLog($"[BMS] 포트 열기 성공");
|
|
|
|
// 간단한 테스트 명령 전송
|
|
var testCmd = new List<byte>();
|
|
testCmd.Add(0xDD);
|
|
testCmd.Add(0xA5);
|
|
testCmd.Add(0x03);
|
|
testCmd.Add(0x00);
|
|
testCmd.Add(0xFF);
|
|
testCmd.Add(0xFD);
|
|
testCmd.Add(0x77);
|
|
testCmd.Add(0x0D);
|
|
|
|
port.Write(testCmd.ToArray(), 0, testCmd.Count);//.Length);
|
|
addLog($"[BMS] 테스트 명령 전송: {BitConverter.ToString(testCmd.ToArray())}");
|
|
|
|
// 응답 대기
|
|
System.Threading.Thread.Sleep(1200);
|
|
|
|
if (port.BytesToRead > 0)
|
|
{
|
|
byte[] response = new byte[port.BytesToRead];
|
|
port.Read(response, 0, response.Length);
|
|
addLog($"[BMS] 응답 수신 ({response.Length} bytes): {BitConverter.ToString(response)}");
|
|
|
|
// STX, ETX 확인
|
|
if (response.Length >= 2 && response[0] == 0xDD && response[response.Length - 1] == 0x77)
|
|
{
|
|
addLog($"[BMS] ✓ 통신 성공 - 올바른 프로토콜 응답");
|
|
if (response.Length == 34 || response.Length == 23)
|
|
{
|
|
addLog($"[BMS] ✓ 데이터 길이 확인 ({response.Length} bytes)");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
addLog($"[BMS] ⚠ 응답은 받았으나 프로토콜 형식이 다름");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
addLog($"[BMS] ⚠ 응답 없음 - 포트는 열렸으나 장치 응답 없음");
|
|
}
|
|
|
|
port.Close();
|
|
addLog($"[BMS] 포트 닫기 완료");
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
addLog($"[BMS] ✗ 오류 발생: {ex.Message}");
|
|
}
|
|
}
|
|
|
|
void addLog(string msg)
|
|
{
|
|
// rtLog 컨트롤에 메세지를 추가하고, 추가된 메세지에 맞게 커서가 자동이동되게 한다
|
|
if (rtLog.InvokeRequired)
|
|
{
|
|
rtLog.Invoke(new Action(() => addLog(msg)));
|
|
}
|
|
else
|
|
{
|
|
string timestamp = DateTime.Now.ToString("HH:mm:ss.fff");
|
|
rtLog.AppendText($"[{timestamp}] {msg}\r\n");
|
|
rtLog.SelectionStart = rtLog.Text.Length;
|
|
rtLog.ScrollToCaret();
|
|
}
|
|
}
|
|
|
|
private async void btFindPort_Click(object sender, EventArgs e)
|
|
{
|
|
// 버튼 비활성화 (중복 실행 방지)
|
|
btFindPort.Enabled = false;
|
|
|
|
try
|
|
{
|
|
await Task.Run(() => FindPortsAsync());
|
|
}
|
|
finally
|
|
{
|
|
// 버튼 재활성화
|
|
btFindPort.Enabled = true;
|
|
}
|
|
}
|
|
|
|
private void FindPortsAsync()
|
|
{
|
|
// AGV와 BMS의 응답 포트를 병렬로 동시에 찾는다
|
|
addLog("===== 포트 자동 검색 시작 (병렬 모드) =====");
|
|
|
|
string[] ports = SerialPort.GetPortNames();
|
|
if (ports.Length == 0)
|
|
{
|
|
addLog("사용 가능한 포트가 없습니다");
|
|
return;
|
|
}
|
|
|
|
addLog($"총 {ports.Length}개 포트 검색 중...");
|
|
|
|
// 병렬 검색을 위한 변수
|
|
object lockObj = new object();
|
|
string foundAGVPort = null;
|
|
string foundBMSPort = null;
|
|
int agvBaud = 115200;
|
|
int bmsBaud = 9600;
|
|
bool bothFound = false;
|
|
|
|
// 현재 설정된 포트 (우선순위 표시용)
|
|
string currentAGVPort = null;
|
|
string currentBMSPort = null;
|
|
|
|
this.Invoke(new Action(() =>
|
|
{
|
|
currentAGVPort = cmbPortAGV.SelectedItem?.ToString();
|
|
currentBMSPort = cmbPortBMS.SelectedItem?.ToString();
|
|
}));
|
|
|
|
// 현재 설정 확인 로그
|
|
addLog($"현재 AGV 설정: {(string.IsNullOrEmpty(currentAGVPort) ? "(선택 안됨)" : currentAGVPort)}");
|
|
addLog($"현재 BMS 설정: {(string.IsNullOrEmpty(currentBMSPort) ? "(선택 안됨)" : currentBMSPort)}");
|
|
|
|
// === 1단계: 현재 설정된 포트 우선 테스트 ===
|
|
addLog("--- 1단계: 현재 설정 포트 우선 테스트 ---");
|
|
|
|
// AGV 현재 포트 우선 테스트
|
|
if (!string.IsNullOrEmpty(currentAGVPort) && ports.Contains(currentAGVPort))
|
|
{
|
|
addLog($"[우선] AGV 현재 포트 테스트: {currentAGVPort}");
|
|
for (int retry = 1; retry <= 3; retry++)
|
|
{
|
|
if (TestAGVPort(currentAGVPort, agvBaud))
|
|
{
|
|
foundAGVPort = currentAGVPort;
|
|
addLog($"✓ 현재 설정 포트에서 AGV 발견: {currentAGVPort}");
|
|
break;
|
|
}
|
|
if (retry < 3) System.Threading.Thread.Sleep(500);
|
|
}
|
|
}
|
|
|
|
// BMS 현재 포트 우선 테스트
|
|
if (!string.IsNullOrEmpty(currentBMSPort) && ports.Contains(currentBMSPort))
|
|
{
|
|
addLog($"[우선] BMS 현재 포트 테스트: {currentBMSPort}");
|
|
for (int retry = 1; retry <= 3; retry++)
|
|
{
|
|
if (TestBMSPort(currentBMSPort, bmsBaud))
|
|
{
|
|
foundBMSPort = currentBMSPort;
|
|
addLog($"✓ 현재 설정 포트에서 BMS 발견: {currentBMSPort}");
|
|
break;
|
|
}
|
|
if (retry < 3) System.Threading.Thread.Sleep(500);
|
|
}
|
|
}
|
|
|
|
// 둘 다 찾았으면 즉시 종료
|
|
if (foundAGVPort != null && foundBMSPort != null)
|
|
{
|
|
addLog("현재 설정 포트에서 모두 발견! 검색 종료");
|
|
ApplyFoundPorts(foundAGVPort, foundBMSPort, agvBaud, bmsBaud);
|
|
addLog("===== 포트 자동 검색 완료 =====");
|
|
return;
|
|
}
|
|
|
|
// === 2단계: 나머지 포트 병렬 검색 ===
|
|
if (foundAGVPort == null || foundBMSPort == null)
|
|
{
|
|
addLog("--- 2단계: 나머지 포트 병렬 검색 ---");
|
|
}
|
|
|
|
// 모든 포트를 병렬로 테스트 (단, 이미 테스트한 포트 제외)
|
|
List<Task> tasks = new List<Task>();
|
|
|
|
foreach (string portName in ports)
|
|
{
|
|
string port = portName; // 클로저 캡처용
|
|
|
|
// 이미 우선 테스트에서 체크한 포트는 제외
|
|
if (port == currentAGVPort || port == currentBMSPort)
|
|
continue;
|
|
|
|
Task task = Task.Run(() =>
|
|
{
|
|
// 이미 둘 다 찾았으면 즉시 종료
|
|
if (bothFound) return;
|
|
|
|
addLog($"[{port}] 검사 시작...");
|
|
|
|
// AGV 테스트 (3회 재시도)
|
|
for (int retry = 1; retry <= 3; retry++)
|
|
{
|
|
// 첫 번째 시도에서는 조기 종료하지 않고 전체 대기 시간 보장
|
|
if (retry > 1 && bothFound) return;
|
|
|
|
try
|
|
{
|
|
if (foundAGVPort == null && TestAGVPort(port, agvBaud))
|
|
{
|
|
lock (lockObj)
|
|
{
|
|
if (foundAGVPort == null)
|
|
{
|
|
foundAGVPort = port;
|
|
addLog($"[{port}] ✓ AGV 발견! (재시도: {retry}/3)");
|
|
|
|
// 둘 다 찾았는지 확인
|
|
if (foundBMSPort != null)
|
|
{
|
|
bothFound = true;
|
|
addLog("AGV와 BMS 모두 발견! 검색 종료");
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
catch { }
|
|
|
|
if (retry < 3 && foundAGVPort == null && !bothFound)
|
|
{
|
|
System.Threading.Thread.Sleep(500);
|
|
}
|
|
}
|
|
|
|
// BMS 테스트 (3회 재시도)
|
|
for (int retry = 1; retry <= 3; retry++)
|
|
{
|
|
// 첫 번째 시도에서는 조기 종료하지 않고 전체 대기 시간 보장
|
|
if (retry > 1 && bothFound) return;
|
|
|
|
try
|
|
{
|
|
if (foundBMSPort == null && TestBMSPort(port, bmsBaud))
|
|
{
|
|
lock (lockObj)
|
|
{
|
|
if (foundBMSPort == null)
|
|
{
|
|
foundBMSPort = port;
|
|
addLog($"[{port}] ✓ BMS 발견! (재시도: {retry}/3)");
|
|
|
|
// 둘 다 찾았는지 확인
|
|
if (foundAGVPort != null)
|
|
{
|
|
bothFound = true;
|
|
addLog("AGV와 BMS 모두 발견! 검색 종료");
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
catch { }
|
|
|
|
if (retry < 3 && foundBMSPort == null && !bothFound)
|
|
{
|
|
System.Threading.Thread.Sleep(500);
|
|
}
|
|
}
|
|
|
|
// 둘 다 실패한 경우에만 로그
|
|
if (!bothFound && foundAGVPort != port && foundBMSPort != port)
|
|
{
|
|
addLog($"[{port}] ✗ 응답 없음");
|
|
}
|
|
});
|
|
|
|
tasks.Add(task);
|
|
}
|
|
|
|
// 나머지 포트가 있을 경우만 대기
|
|
if (tasks.Count > 0)
|
|
{
|
|
addLog("나머지 포트 테스트 진행 중...");
|
|
|
|
// 주기적으로 체크하면서 둘 다 찾았으면 즉시 종료
|
|
while (!Task.WaitAll(tasks.ToArray(), 100))
|
|
{
|
|
if (bothFound)
|
|
{
|
|
addLog("검색 조기 종료 - 모든 포트 발견");
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
// 결과 적용
|
|
ApplyFoundPorts(foundAGVPort, foundBMSPort, agvBaud, bmsBaud);
|
|
addLog("===== 포트 자동 검색 완료 =====");
|
|
}
|
|
|
|
/// <summary>
|
|
/// 발견된 포트를 UI에 적용
|
|
/// </summary>
|
|
private void ApplyFoundPorts(string agvPort, string bmsPort, int agvBaud, int bmsBaud)
|
|
{
|
|
if (agvPort != null)
|
|
{
|
|
this.Invoke(new Action(() =>
|
|
{
|
|
int idx = cmbPortAGV.Items.IndexOf(agvPort);
|
|
if (idx >= 0)
|
|
{
|
|
cmbPortAGV.SelectedIndex = idx;
|
|
tbBaudAGV.Text = agvBaud.ToString();
|
|
}
|
|
}));
|
|
addLog($"✓ AGV 포트: {agvPort} (Baud: {agvBaud})");
|
|
}
|
|
else
|
|
{
|
|
addLog("⚠ AGV 포트를 찾지 못했습니다");
|
|
}
|
|
|
|
if (bmsPort != null)
|
|
{
|
|
this.Invoke(new Action(() =>
|
|
{
|
|
int idx = cmbPortBMS.Items.IndexOf(bmsPort);
|
|
if (idx >= 0)
|
|
{
|
|
cmbPortBMS.SelectedIndex = idx;
|
|
tbBaudBMS.Text = bmsBaud.ToString();
|
|
}
|
|
}));
|
|
addLog($"✓ BMS 포트: {bmsPort} (Baud: {bmsBaud})");
|
|
}
|
|
else
|
|
{
|
|
addLog("⚠ BMS 포트를 찾지 못했습니다");
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// AGV 포트인지 테스트 (btTestAGV_Click 코드 사용)
|
|
/// </summary>
|
|
private bool TestAGVPort(string portName, int baudRate)
|
|
{
|
|
try
|
|
{
|
|
using (arDev.Narumi port = new arDev.Narumi())
|
|
{
|
|
port.PortName = portName;
|
|
port.BaudRate = baudRate;
|
|
|
|
addLog($" >> AGV 테스트 시작: {portName} @ {baudRate}bps");
|
|
|
|
port.Open();
|
|
addLog($" >> AGV 포트 열기 성공: {portName}");
|
|
|
|
DateTime sendtime = DateTime.Now;
|
|
port.AGVMoveStop("test");
|
|
addLog($" >> AGV 명령 전송: {portName} (시간: {sendtime:HH:mm:ss.fff})");
|
|
|
|
// 응답 대기 (더 길게, 주기적으로 체크)
|
|
int maxWait = 2000; // 최대 2초 대기
|
|
int waitStep = 100;
|
|
int totalWait = 0;
|
|
|
|
while (totalWait < maxWait)
|
|
{
|
|
System.Threading.Thread.Sleep(waitStep);
|
|
totalWait += waitStep;
|
|
|
|
// lastRecvTime 확인
|
|
if (port.lastRecvTime > sendtime)
|
|
{
|
|
addLog($" >> ✓✓✓ AGV 응답 수신: {portName} (응답시간: {port.lastRecvTime:HH:mm:ss.fff}, 대기: {totalWait}ms)");
|
|
addLog($" >> 응답 데이터: {port.LastRecvString}");
|
|
port.Close();
|
|
return true;
|
|
}
|
|
|
|
// LastRecvString도 확인 (lastRecvTime이 업데이트 안 될 수도 있음)
|
|
if (!string.IsNullOrEmpty(port.LastRecvString))
|
|
{
|
|
addLog($" >> ✓✓✓ AGV 응답 감지 (문자열): {portName} (대기: {totalWait}ms)");
|
|
addLog($" >> 응답 데이터: {port.LastRecvString}");
|
|
port.Close();
|
|
return true;
|
|
}
|
|
}
|
|
|
|
addLog($" >> AGV 응답 없음: {portName} (최종 대기: {totalWait}ms, 마지막수신: {port.lastRecvTime:HH:mm:ss.fff})");
|
|
port.Close();
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
addLog($" >> AGV 테스트 오류: {portName} - {ex.Message}");
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
/// <summary>
|
|
/// BMS 포트인지 테스트 (btTestBMS_Click 코드 사용)
|
|
/// </summary>
|
|
private bool TestBMSPort(string portName, int baudRate)
|
|
{
|
|
try
|
|
{
|
|
using (SerialPort port = new SerialPort())
|
|
{
|
|
port.PortName = portName;
|
|
port.BaudRate = baudRate;
|
|
port.DataBits = 8;
|
|
port.Parity = Parity.None;
|
|
port.StopBits = StopBits.One;
|
|
port.ReadTimeout = 500;
|
|
port.WriteTimeout = 500;
|
|
|
|
addLog($" >> BMS 테스트 시작: {portName} @ {baudRate}bps");
|
|
|
|
port.Open();
|
|
addLog($" >> BMS 포트 열기 성공: {portName}");
|
|
|
|
// BMS 테스트 명령 전송 (테스트 버튼과 동일한 명령)
|
|
var testCmd = new List<byte>();
|
|
testCmd.Add(0xDD);
|
|
testCmd.Add(0xA5);
|
|
testCmd.Add(0x03);
|
|
testCmd.Add(0x00);
|
|
testCmd.Add(0xFF);
|
|
testCmd.Add(0xFD);
|
|
testCmd.Add(0x77);
|
|
testCmd.Add(0x0D);
|
|
|
|
port.Write(testCmd.ToArray(), 0, testCmd.Count);
|
|
addLog($" >> BMS 명령 전송: {portName} - {BitConverter.ToString(testCmd.ToArray())}");
|
|
|
|
// 응답 대기
|
|
System.Threading.Thread.Sleep(300);
|
|
|
|
if (port.BytesToRead > 0)
|
|
{
|
|
byte[] response = new byte[port.BytesToRead];
|
|
port.Read(response, 0, response.Length);
|
|
|
|
addLog($" >> BMS 응답 수신: {portName} ({response.Length} bytes) - {BitConverter.ToString(response)}");
|
|
|
|
// BMS 프로토콜 확인 (STX=0xDD, ETX=0x77)
|
|
if (response.Length >= 2 && response[0] == 0xDD && response[response.Length - 1] == 0x77)
|
|
{
|
|
addLog($" >> ✓✓✓ BMS 프로토콜 확인: {portName}");
|
|
port.Close();
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
addLog($" >> BMS 프로토콜 불일치: {portName}");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
addLog($" >> BMS 응답 없음: {portName}");
|
|
}
|
|
|
|
port.Close();
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
addLog($" >> BMS 테스트 오류: {portName} - {ex.Message}");
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
private void toolStripButton1_Click(object sender, EventArgs e)
|
|
{
|
|
LoadSetting();
|
|
}
|
|
|
|
private void toolStripButton2_Click(object sender, EventArgs e)
|
|
{
|
|
SaveSetting();
|
|
}
|
|
}
|
|
}
|