diff --git a/Cs_HMI/AGVLogic/AGVMapEditor/Forms/MainForm.cs b/Cs_HMI/AGVLogic/AGVMapEditor/Forms/MainForm.cs
index 28f5d78..6ad2a96 100644
--- a/Cs_HMI/AGVLogic/AGVMapEditor/Forms/MainForm.cs
+++ b/Cs_HMI/AGVLogic/AGVMapEditor/Forms/MainForm.cs
@@ -36,20 +36,20 @@ namespace AGVMapEditor.Forms
{
public string FromNodeId { get; set; }
public string FromNodeName { get; set; }
- public string FromRfidId { get; set; }
+ public ushort FromRfidId { get; set; }
public string ToNodeId { get; set; }
public string ToNodeName { get; set; }
- public string ToRfidId { get; set; }
+ public ushort ToRfidId { get; set; }
public string ConnectionType { get; set; }
public override string ToString()
{
// RFID가 있으면 RFID(노드이름), 없으면 NodeID(노드이름) 형태로 표시
- string fromDisplay = !string.IsNullOrEmpty(FromRfidId)
+ string fromDisplay = FromRfidId > 0
? $"{FromRfidId}({FromNodeName})"
: $"---({FromNodeId})";
- string toDisplay = !string.IsNullOrEmpty(ToRfidId)
+ string toDisplay = ToRfidId > 0
? $"{ToRfidId}({ToNodeName})"
: $"---({ToNodeId})";
@@ -420,7 +420,7 @@ namespace AGVMapEditor.Forms
return;
}
- var rfidDisplay = (_selectedNode as MapNode)?.RfidId ?? "";
+ var rfidDisplay = (_selectedNode as MapNode)?.RfidId ?? 0;
var result = MessageBox.Show($"노드 {rfidDisplay}[{_selectedNode.Id}] 를 삭제하시겠습니까?\n연결된 RFID 매핑도 함께 삭제됩니다.",
"삭제 확인", MessageBoxButtons.YesNo, MessageBoxIcon.Question);
@@ -1107,8 +1107,8 @@ namespace AGVMapEditor.Forms
// RFID 값 변경시 중복 검사
if (e.ChangedItem.PropertyDescriptor.Name == "RFID")
{
- string newRfidValue = e.ChangedItem.Value?.ToString();
- if (!string.IsNullOrEmpty(newRfidValue) && CheckRfidDuplicate(newRfidValue))
+ var newRfidValue = ushort.Parse(e.ChangedItem.Value?.ToString());
+ if (newRfidValue != 0 && CheckRfidDuplicate(newRfidValue))
{
// 중복된 RFID 값 발견
MessageBox.Show($"RFID 값 '{newRfidValue}'이(가) 이미 다른 노드에서 사용 중입니다.\n입력값을 되돌립니다.",
@@ -1174,29 +1174,15 @@ namespace AGVMapEditor.Forms
///
/// 검사할 RFID 값
/// 중복되면 true, 아니면 false
- private bool CheckRfidDuplicate(string rfidValue)
+ private bool CheckRfidDuplicate(ushort rfidValue)
{
- if (string.IsNullOrEmpty(rfidValue) || this._mapCanvas.Nodes == null)
+ if (rfidValue == 0 || this._mapCanvas.Nodes == null)
return false;
// 현재 편집 중인 노드 제외하고 중복 검사
string currentNodeId = null;
var selectedObject = _propertyGrid.SelectedObject;
- // 다양한 PropertyWrapper 타입 처리
- //if (selectedObject is NodePropertyWrapper nodeWrapper)
- //{
- // currentNodeId = nodeWrapper.WrappedNode?.NodeId;
- //}
- //else if (selectedObject is LabelNodePropertyWrapper labelWrapper)
- //{
- // currentNodeId = labelWrapper.WrappedNode?.NodeId;
- //}
- //else if (selectedObject is ImageNodePropertyWrapper imageWrapper)
- //{
- // currentNodeId = imageWrapper.WrappedNode?.NodeId;
- //}
-
int duplicateCount = 0;
foreach (var node in this._mapCanvas.Nodes)
{
@@ -1205,7 +1191,7 @@ namespace AGVMapEditor.Forms
continue;
// 같은 RFID 값을 가진 노드가 있는지 확인
- if (!string.IsNullOrEmpty(node.RfidId) && node.RfidId.Equals(rfidValue, StringComparison.OrdinalIgnoreCase))
+ if (node.RfidId != 0 && node.RfidId == rfidValue)
{
duplicateCount++;
break; // 하나라도 발견되면 중복
diff --git a/Cs_HMI/AGVLogic/AGVNavigationCore/Controls/UnifiedAGVCanvas.Events.cs b/Cs_HMI/AGVLogic/AGVNavigationCore/Controls/UnifiedAGVCanvas.Events.cs
index 26014c2..79eb226 100644
--- a/Cs_HMI/AGVLogic/AGVNavigationCore/Controls/UnifiedAGVCanvas.Events.cs
+++ b/Cs_HMI/AGVLogic/AGVNavigationCore/Controls/UnifiedAGVCanvas.Events.cs
@@ -1140,7 +1140,8 @@ namespace AGVNavigationCore.Controls
// 위쪽에 표시할 이름 (노드의 Name 속성)
- string TopIDText = node.HasRfid() ? node.RfidId : $"[{node.Id}]";
+ string TopIDText = node.HasRfid() ? node.RfidId.ToString("0000") : $"[{node.Id}]";
+
// 아래쪽에 표시할 값 (RFID 우선, 없으면 노드ID)
string BottomLabelText = node.Text;
diff --git a/Cs_HMI/AGVLogic/AGVNavigationCore/Controls/UnifiedAGVCanvas.Mouse.cs b/Cs_HMI/AGVLogic/AGVNavigationCore/Controls/UnifiedAGVCanvas.Mouse.cs
index cdfd576..c6d81be 100644
--- a/Cs_HMI/AGVLogic/AGVNavigationCore/Controls/UnifiedAGVCanvas.Mouse.cs
+++ b/Cs_HMI/AGVLogic/AGVNavigationCore/Controls/UnifiedAGVCanvas.Mouse.cs
@@ -121,7 +121,7 @@ namespace AGVNavigationCore.Controls
if (hitNode == null) return;
- if (hitNode.Type == NodeType.Normal)
+ if (hitNode.Type == NodeType.Normal)
{
HandleNormalNodeDoubleClick(hitNode as MapNode);
}
@@ -146,15 +146,19 @@ namespace AGVNavigationCore.Controls
private void HandleNormalNodeDoubleClick(MapNode node)
{
// RFID 입력창 표시
- string currentRfid = node.RfidId ?? "";
+ var currentRfid = node.RfidId;
string newRfid = Microsoft.VisualBasic.Interaction.InputBox(
$"노드 '{node.RfidId}[{node.Id}]'의 RFID를 입력하세요:",
"RFID 설정",
- currentRfid);
+ currentRfid.ToString());
- if (!string.IsNullOrWhiteSpace(newRfid) && newRfid != currentRfid)
+ if (ushort.TryParse(newRfid, out ushort newrfidvalue) == false) return;
+ if (newrfidvalue < 1) return;
+
+
+ if (newrfidvalue != currentRfid)
{
- node.RfidId = newRfid.Trim();
+ node.RfidId = newrfidvalue;
MapChanged?.Invoke(this, EventArgs.Empty);
Invalidate();
}
@@ -229,7 +233,7 @@ namespace AGVNavigationCore.Controls
return;
}
-
+
}
// 팬 시작 (좌클릭 - 모드에 따라)
@@ -272,7 +276,7 @@ namespace AGVNavigationCore.Controls
// 호버 업데이트
var newHoveredNode = GetItemAt(worldPoint);
- bool hoverChanged = (newHoveredNode != _hoveredNode) ;
+ bool hoverChanged = (newHoveredNode != _hoveredNode);
if (hoverChanged)
{
@@ -700,8 +704,8 @@ namespace AGVNavigationCore.Controls
{
// 연결선을 클릭했을 때 삭제 확인
var (fromNode, toNode) = connection.Value;
- string fromDisplay = !string.IsNullOrEmpty(fromNode.RfidId) ? fromNode.RfidId : fromNode.Id;
- string toDisplay = !string.IsNullOrEmpty(toNode.RfidId) ? toNode.RfidId : toNode.Id;
+ string fromDisplay = fromNode.HasRfid() ? fromNode.RfidId.ToString("0000") : fromNode.Id;
+ string toDisplay = toNode.HasRfid() ? toNode.RfidId.ToString("0000") : toNode.Id;
var result = MessageBox.Show(
$"연결을 삭제하시겠습니까?\n\n{fromDisplay} ↔ {toDisplay}",
diff --git a/Cs_HMI/AGVLogic/AGVNavigationCore/Controls/UnifiedAGVCanvas.cs b/Cs_HMI/AGVLogic/AGVNavigationCore/Controls/UnifiedAGVCanvas.cs
index bff437e..4555ef3 100644
--- a/Cs_HMI/AGVLogic/AGVNavigationCore/Controls/UnifiedAGVCanvas.cs
+++ b/Cs_HMI/AGVLogic/AGVNavigationCore/Controls/UnifiedAGVCanvas.cs
@@ -851,13 +851,13 @@ namespace AGVNavigationCore.Controls
return;
// RFID값과 해당 노드의 인덱스를 저장
- var rfidToNodeIndex = new Dictionary>();
+ var rfidToNodeIndex = new Dictionary>();
// 모든 노드의 RFID값 수집
for (int i = 0; i < _nodes.Count; i++)
{
var node = _nodes[i];
- if (!string.IsNullOrEmpty(node.RfidId))
+ if (node.HasRfid())
{
if (!rfidToNodeIndex.ContainsKey(node.RfidId))
{
diff --git a/Cs_HMI/AGVLogic/AGVNavigationCore/Models/MapNode.cs b/Cs_HMI/AGVLogic/AGVNavigationCore/Models/MapNode.cs
index 641c7fd..51e3702 100644
--- a/Cs_HMI/AGVLogic/AGVNavigationCore/Models/MapNode.cs
+++ b/Cs_HMI/AGVLogic/AGVNavigationCore/Models/MapNode.cs
@@ -83,7 +83,7 @@ namespace AGVNavigationCore.Models
[Category("RFID 정보")]
[Description("물리적 RFID 태그 ID입니다.")]
- public string RfidId { get; set; } = string.Empty;
+ public UInt16 RfidId { get; set; } = 0;
[Category("노드 텍스트"), DisplayName("TextColor")]
@@ -161,7 +161,7 @@ namespace AGVNavigationCore.Models
public bool HasRfid()
{
- return !string.IsNullOrEmpty(RfidId);
+ return RfidId > 0;
}
}
}
\ No newline at end of file
diff --git a/Cs_HMI/AGVLogic/AGVNavigationCore/Models/VirtualAGV.cs b/Cs_HMI/AGVLogic/AGVNavigationCore/Models/VirtualAGV.cs
index e658cdb..af428dd 100644
--- a/Cs_HMI/AGVLogic/AGVNavigationCore/Models/VirtualAGV.cs
+++ b/Cs_HMI/AGVLogic/AGVNavigationCore/Models/VirtualAGV.cs
@@ -611,18 +611,7 @@ namespace AGVNavigationCore.Models
PositionChanged?.Invoke(this, (_currentPosition, _currentDirection, _currentNode));
}
- ///
- /// 현재 RFID 시뮬레이션 (현재 위치 기준)
- ///
- public string SimulateRfidReading(List mapNodes)
- {
- var closestNode = FindClosestNode(_currentPosition, mapNodes);
- if (closestNode == null)
- return null;
-
- return closestNode.HasRfid() ? closestNode.RfidId : null;
- }
-
+
#endregion
@@ -630,10 +619,11 @@ namespace AGVNavigationCore.Models
///
/// 노드 ID를 RFID 값으로 변환 (NodeResolver 사용)
///
- public string GetRfidByNodeId(List _mapNodes, string nodeId)
+ public ushort GetRfidByNodeId(List _mapNodes, string nodeId)
{
var node = _mapNodes?.FirstOrDefault(n => n.Id == nodeId);
- return node?.HasRfid() == true ? node.RfidId : nodeId;
+ if ((node?.HasRfid() ?? false) == false) return 0;
+ return node.RfidId;
}
diff --git a/Cs_HMI/AGVLogic/AGVNavigationCore/PathFinding/Planning/AGVPathfinder.cs b/Cs_HMI/AGVLogic/AGVNavigationCore/PathFinding/Planning/AGVPathfinder.cs
index 4bf93e8..0ad07df 100644
--- a/Cs_HMI/AGVLogic/AGVNavigationCore/PathFinding/Planning/AGVPathfinder.cs
+++ b/Cs_HMI/AGVLogic/AGVNavigationCore/PathFinding/Planning/AGVPathfinder.cs
@@ -447,7 +447,7 @@ namespace AGVNavigationCore.PathFinding.Planning
{
var node = path1.Path[i];
string nodeId = node.Id;
- string RfidId = node.RfidId;
+ var RfidId = node.RfidId;
string nextNodeId = (i + 1 < path1.Path.Count) ? path1.Path[i + 1].Id : null;
// 노드 정보 생성 (현재 방향 유지)
diff --git a/Cs_HMI/AGVLogic/AGVNavigationCore/PathFinding/Planning/DirectionChangePlanner.cs b/Cs_HMI/AGVLogic/AGVNavigationCore/PathFinding/Planning/DirectionChangePlanner.cs
index 3fdc685..79a1686 100644
--- a/Cs_HMI/AGVLogic/AGVNavigationCore/PathFinding/Planning/DirectionChangePlanner.cs
+++ b/Cs_HMI/AGVLogic/AGVNavigationCore/PathFinding/Planning/DirectionChangePlanner.cs
@@ -770,9 +770,9 @@ namespace AGVNavigationCore.PathFinding.Planning
private string GetDisplayName(string nodeId)
{
var node = _mapNodes.FirstOrDefault(n => n.Id == nodeId);
- if (node != null && !string.IsNullOrEmpty(node.RfidId))
+ if (node != null && node.HasRfid())
{
- return node.RfidId;
+ return node.RfidId.ToString("0000");
}
return $"({nodeId})";
}
diff --git a/Cs_HMI/AGVLogic/AGVNavigationCore/PathFinding/Planning/NodeMotorInfo.cs b/Cs_HMI/AGVLogic/AGVNavigationCore/PathFinding/Planning/NodeMotorInfo.cs
index 760dba0..597fc25 100644
--- a/Cs_HMI/AGVLogic/AGVNavigationCore/PathFinding/Planning/NodeMotorInfo.cs
+++ b/Cs_HMI/AGVLogic/AGVNavigationCore/PathFinding/Planning/NodeMotorInfo.cs
@@ -40,7 +40,7 @@ namespace AGVNavigationCore.PathFinding.Planning
///
/// RFID Value
///
- public string RfidId { get; set; }
+ public ushort RfidId { get; set; }
///
/// 해당 노드에서의 모터방향
@@ -87,7 +87,7 @@ namespace AGVNavigationCore.PathFinding.Planning
///
public string SpecialActionDescription { get; set; }
- public NodeMotorInfo(int seqno,string nodeId,string rfid, AgvDirection motorDirection, string nextNodeId = null, MagnetDirection magnetDirection = MagnetDirection.Straight)
+ public NodeMotorInfo(int seqno,string nodeId,ushort rfid, AgvDirection motorDirection, string nextNodeId = null, MagnetDirection magnetDirection = MagnetDirection.Straight)
{
seq = seqno;
NodeId = nodeId;
diff --git a/Cs_HMI/AGVLogic/AGVNavigationCore/Utils/DirectionalHelper.cs b/Cs_HMI/AGVLogic/AGVNavigationCore/Utils/DirectionalHelper.cs
index 2dd7faf..028ffb9 100644
--- a/Cs_HMI/AGVLogic/AGVNavigationCore/Utils/DirectionalHelper.cs
+++ b/Cs_HMI/AGVLogic/AGVNavigationCore/Utils/DirectionalHelper.cs
@@ -204,7 +204,7 @@ namespace AGVNavigationCore.Utils
}
Console.WriteLine(
- $"\n 최종선택: {bestNode?.RfidId ?? "null"}[{bestNode?.Id ?? "null"}] (점수: {bestScore:F4})");
+ $"\n 최종선택: {bestNode?.RfidId ?? 0}[{bestNode?.Id ?? "null"}] (점수: {bestScore:F4})");
Console.WriteLine(
$"[GetNextNodeByDirection] ========== 다음 노드 선택 종료 ==========\n");
diff --git a/Cs_HMI/AGVLogic/AGVNavigationCore/Utils/DirectionalPathfinderTest.cs b/Cs_HMI/AGVLogic/AGVNavigationCore/Utils/DirectionalPathfinderTest.cs
index 672fb6c..08b28b9 100644
--- a/Cs_HMI/AGVLogic/AGVNavigationCore/Utils/DirectionalPathfinderTest.cs
+++ b/Cs_HMI/AGVLogic/AGVNavigationCore/Utils/DirectionalPathfinderTest.cs
@@ -16,12 +16,12 @@ namespace AGVNavigationCore.Utils
public class DirectionalPathfinderTest
{
private List _allNodes;
- private Dictionary _nodesByRfidId;
+ private Dictionary _nodesByRfidId;
private AGVDirectionCalculator _calculator;
public DirectionalPathfinderTest()
{
- _nodesByRfidId = new Dictionary();
+ _nodesByRfidId = new Dictionary();
_calculator = new AGVDirectionCalculator();
}
@@ -52,7 +52,7 @@ namespace AGVNavigationCore.Utils
// RFID ID로 인덱싱
foreach (var node in _allNodes)
{
- if (!string.IsNullOrEmpty(node.RfidId))
+ if (node.HasRfid())
{
_nodesByRfidId[node.RfidId] = node;
}
@@ -71,7 +71,7 @@ namespace AGVNavigationCore.Utils
///
/// 테스트: RFID 번호로 노드를 찾고, 다음 노드를 계산
///
- public void TestDirectionalMovement(string previousRfidId, string currentRfidId, AgvDirection direction)
+ public void TestDirectionalMovement(ushort previousRfidId, ushort currentRfidId, AgvDirection direction)
{
Console.WriteLine($"\n========================================");
Console.WriteLine($"테스트: {previousRfidId} → {currentRfidId} (방향: {direction})");
@@ -140,7 +140,7 @@ namespace AGVNavigationCore.Utils
///
/// 특정 RFID 노드의 상세 정보 출력
///
- public void PrintNodeInfo(string rfidId)
+ public void PrintNodeInfo(ushort rfidId)
{
if (!_nodesByRfidId.TryGetValue(rfidId, out var node))
{
diff --git a/Cs_HMI/AGVLogic/AGVNavigationCore/Utils/GetNextNodeIdTest.cs b/Cs_HMI/AGVLogic/AGVNavigationCore/Utils/GetNextNodeIdTest.cs
index 454a652..43fba4f 100644
--- a/Cs_HMI/AGVLogic/AGVNavigationCore/Utils/GetNextNodeIdTest.cs
+++ b/Cs_HMI/AGVLogic/AGVNavigationCore/Utils/GetNextNodeIdTest.cs
@@ -28,10 +28,10 @@ namespace AGVNavigationCore.Utils
Console.WriteLine("================================================\n");
// 테스트 노드 생성
- var node001 = new MapNode { Id = "N001", RfidId = "001", Position = new Point(65, 229), ConnectedNodes = new List { "N002" } };
- var node002 = new MapNode { Id = "N002", RfidId = "002", Position = new Point(206, 244), ConnectedNodes = new List { "N001", "N003" } };
- var node003 = new MapNode { Id = "N003", RfidId = "003", Position = new Point(278, 278), ConnectedNodes = new List { "N002", "N004" } };
- var node004 = new MapNode { Id = "N004", RfidId = "004", Position = new Point(380, 340), ConnectedNodes = new List { "N003", "N022", "N031" } };
+ var node001 = new MapNode { Id = "N001", RfidId = 001, Position = new Point(65, 229), ConnectedNodes = new List { "N002" } };
+ var node002 = new MapNode { Id = "N002", RfidId = 002, Position = new Point(206, 244), ConnectedNodes = new List { "N001", "N003" } };
+ var node003 = new MapNode { Id = "N003", RfidId = 003, Position = new Point(278, 278), ConnectedNodes = new List { "N002", "N004" } };
+ var node004 = new MapNode { Id = "N004", RfidId = 004, Position = new Point(380, 340), ConnectedNodes = new List { "N003", "N022", "N031" } };
var allNodes = new List { node001, node002, node003, node004 };
@@ -114,7 +114,7 @@ namespace AGVNavigationCore.Utils
AgvDirection motorDir = currentMotorDirection ?? direction;
Console.WriteLine($"설명: {description}");
- Console.WriteLine($"이전 위치: {prevPos} (RFID: {allNodes.First(n => n.Position == prevPos)?.RfidId ?? "?"})");
+ Console.WriteLine($"이전 위치: {prevPos} (RFID: {allNodes.First(n => n.Position == prevPos)?.RfidId.ToString("0000") ?? "?"})");
Console.WriteLine($"현재 노드: {currentNode.Id} (RFID: {currentNode.RfidId}) - 위치: {currentNode.Position}");
Console.WriteLine($"현재 모터 방향: {motorDir}");
Console.WriteLine($"요청 방향: {direction}");
diff --git a/Cs_HMI/AGVLogic/AGVNavigationCore/Utils/TestRunner.cs b/Cs_HMI/AGVLogic/AGVNavigationCore/Utils/TestRunner.cs
index f621f78..2cdf995 100644
--- a/Cs_HMI/AGVLogic/AGVNavigationCore/Utils/TestRunner.cs
+++ b/Cs_HMI/AGVLogic/AGVNavigationCore/Utils/TestRunner.cs
@@ -29,26 +29,26 @@ namespace AGVNavigationCore.Utils
tester.PrintAllNodes();
// 테스트 시나리오 1: 001 → 002 → Forward (003 기대)
- tester.PrintNodeInfo("001");
- tester.PrintNodeInfo("002");
- tester.TestDirectionalMovement("001", "002", AgvDirection.Forward);
+ tester.PrintNodeInfo(001);
+ tester.PrintNodeInfo(002);
+ tester.TestDirectionalMovement(001, 002, AgvDirection.Forward);
// 테스트 시나리오 2: 002 → 001 → Backward (000 또는 이전 기대)
- tester.TestDirectionalMovement("002", "001", AgvDirection.Backward);
+ tester.TestDirectionalMovement(002, 001, AgvDirection.Backward);
// 테스트 시나리오 3: 002 → 003 → Forward
- tester.PrintNodeInfo("003");
- tester.TestDirectionalMovement("002", "003", AgvDirection.Forward);
+ tester.PrintNodeInfo(003);
+ tester.TestDirectionalMovement(002, 003, AgvDirection.Forward);
// 테스트 시나리오 4: 003 → 004 → Forward
- tester.PrintNodeInfo("004");
- tester.TestDirectionalMovement("003", "004", AgvDirection.Forward);
+ tester.PrintNodeInfo(004);
+ tester.TestDirectionalMovement(003, 004, AgvDirection.Forward);
// 테스트 시나리오 5: 003 → 004 → Right (030 기대)
- tester.TestDirectionalMovement("003", "004", AgvDirection.Right);
+ tester.TestDirectionalMovement(003, 004, AgvDirection.Right);
// 테스트 시나리오 6: 004 → 003 → Backward
- tester.TestDirectionalMovement("004", "003", AgvDirection.Backward);
+ tester.TestDirectionalMovement(004, 003, AgvDirection.Backward);
Console.WriteLine("\n\n=== 테스트 완료 ===");
}
diff --git a/Cs_HMI/AGVLogic/AGVSimulator/Forms/SimulatorForm.cs b/Cs_HMI/AGVLogic/AGVSimulator/Forms/SimulatorForm.cs
index 4aa4eb1..cec54cb 100644
--- a/Cs_HMI/AGVLogic/AGVSimulator/Forms/SimulatorForm.cs
+++ b/Cs_HMI/AGVLogic/AGVSimulator/Forms/SimulatorForm.cs
@@ -635,7 +635,7 @@ namespace AGVSimulator.Forms
///
/// 맵 스캔 모드에서 RFID로부터 노드 생성
///
- private void CreateNodeFromRfidScan(string rfidId, VirtualAGV selectedAGV)
+ private void CreateNodeFromRfidScan(ushort rfidId, VirtualAGV selectedAGV)
{
try
{
@@ -644,7 +644,7 @@ namespace AGVSimulator.Forms
var currentDirection = directionItem?.Direction ?? AgvDirection.Forward;
// 중복 RFID 확인
- var existingNode = _simulatorCanvas.Nodes?.FirstOrDefault(n => n.RfidId.Equals(rfidId, StringComparison.OrdinalIgnoreCase));
+ var existingNode = _simulatorCanvas.Nodes?.FirstOrDefault(n => n.RfidId == rfidId);
if (existingNode != null)
{
// 이미 존재하는 노드로 이동
@@ -805,7 +805,7 @@ namespace AGVSimulator.Forms
if (agv.CurrentNodeId != null && agv.CurrentNodeId != _lastSentNodeId)
{
var rfid = GetRfidByNodeId(agv.CurrentNodeId);
- if (!string.IsNullOrEmpty(rfid))
+ if (rfid > 0)
{
SendTag(rfid);
_lastSentNodeId = agv.CurrentNodeId;
@@ -842,7 +842,7 @@ namespace AGVSimulator.Forms
// RFID 값 확인
var rfidId = _rfidTextBox.Text.Trim();
- if (string.IsNullOrEmpty(rfidId))
+ if (ushort.TryParse(rfidId,out ushort rfidvalue)==false)
{
MessageBox.Show("RFID 값을 입력해주세요.", "알림", MessageBoxButtons.OK, MessageBoxIcon.Information);
return;
@@ -856,13 +856,13 @@ namespace AGVSimulator.Forms
// 맵 스캔 모드일 때: 노드 자동 생성
if (_isMapScanMode)
{
- CreateNodeFromRfidScan(rfidId, selectedAGV);
+ CreateNodeFromRfidScan(rfidvalue, selectedAGV);
this._simulatorCanvas.FitToNodes();
return;
}
// RFID에 해당하는 노드 직접 찾기
- var targetNode = _simulatorCanvas.Nodes?.FirstOrDefault(n => n.RfidId.Equals(rfidId, StringComparison.OrdinalIgnoreCase));
+ var targetNode = _simulatorCanvas.Nodes?.FirstOrDefault(n => n.RfidId == rfidvalue);
if (targetNode == null)
{
MessageBox.Show($"RFID '{rfidId}'에 해당하는 노드를 찾을 수 없습니다.\n\n사용 가능한 RFID 목록:\n{GetAvailableRfidList()}",
@@ -1255,10 +1255,12 @@ namespace AGVSimulator.Forms
///
/// 노드 ID를 RFID 값으로 변환 (NodeResolver 사용)
///
- private string GetRfidByNodeId(string nodeId)
+ private ushort GetRfidByNodeId(string nodeId)
{
var node = _simulatorCanvas.Nodes?.FirstOrDefault(n => n.Id == nodeId);
- return node?.HasRfid() == true ? node.RfidId : nodeId;
+ if (node == null) return 0;
+ if (node.HasRfid()) return node.RfidId;
+ else return 0;
}
///
@@ -1267,9 +1269,9 @@ namespace AGVSimulator.Forms
private string GetDisplayName(string nodeId)
{
var node = _simulatorCanvas.Nodes?.FirstOrDefault(n => n.Id == nodeId);
- if (node != null && !string.IsNullOrEmpty(node.RfidId))
+ if (node != null && node.HasRfid())
{
- return node.RfidId;
+ return node.RfidId.ToString("0000");
}
return $"({nodeId})";
}
@@ -1366,7 +1368,7 @@ namespace AGVSimulator.Forms
{
var info = advancedResult.DetailedPath[i];
var rfidId = GetRfidByNodeId(info.NodeId);
- var nextRfidId = info.NextNodeId != null ? GetRfidByNodeId(info.NextNodeId) : "END";
+ var nextRfidId = info.NextNodeId != null ? GetRfidByNodeId(info.NextNodeId).ToString("0000") : "-END-";
var flags = new List();
if (info.CanRotate) flags.Add("회전가능");
@@ -1616,12 +1618,8 @@ namespace AGVSimulator.Forms
///
private string GetNodeDisplayName(MapNode node)
{
- if (node == null)
- return "-";
-
- if (!string.IsNullOrEmpty(node.RfidId))
- return node.RfidId;
-
+ if (node == null) return "-";
+ if (node.HasRfid()) return node.RfidId.ToString("0000");
return $"({node.Id})";
}
@@ -1792,7 +1790,7 @@ namespace AGVSimulator.Forms
this.Invoke((MethodInvoker)delegate
{
// RFID 텍스트박스에 값 입력
- _rfidTextBox.Text = nodeA.RfidId;
+ _rfidTextBox.Text = nodeA.RfidId.ToString();
// 방향 콤보박스 선택
SetDirectionComboBox(direction);
@@ -1808,7 +1806,7 @@ namespace AGVSimulator.Forms
this.Invoke((MethodInvoker)delegate
{
// RFID 텍스트박스에 값 입력
- _rfidTextBox.Text = nodeB.RfidId;
+ _rfidTextBox.Text = nodeB.RfidId.ToString();
// 방향 콤보박스 선택
SetDirectionComboBox(direction);
@@ -2415,19 +2413,18 @@ namespace AGVSimulator.Forms
catch { }
}
- public void SendTag(string tagno)
+ public void SendTag(ushort tagno)
{
if (_emulatorPort == null || !_emulatorPort.IsOpen) return;
- tagno = tagno.PadLeft(6, '0');
- if (tagno.Length > 6) tagno = tagno.Substring(0, 6);
+ var tagnostr = tagno.ToString("000000");
var barr = new List();
barr.Add(0x02);
barr.Add((byte)'T');
barr.Add((byte)'A');
barr.Add((byte)'G');
- barr.AddRange(System.Text.Encoding.Default.GetBytes(tagno));
+ barr.AddRange(System.Text.Encoding.Default.GetBytes(tagnostr));
barr.Add((byte)'*');
barr.Add((byte)'*');
barr.Add(0x03);
diff --git a/Cs_HMI/Project/AGV4.csproj b/Cs_HMI/Project/AGV4.csproj
index d5bd2c9..119d01b 100644
--- a/Cs_HMI/Project/AGV4.csproj
+++ b/Cs_HMI/Project/AGV4.csproj
@@ -226,9 +226,6 @@
fSystem.cs
-
- Form
-
Form
@@ -363,9 +360,6 @@
Form
-
- Form
-
Form
diff --git a/Cs_HMI/Project/Class/CResult.cs b/Cs_HMI/Project/Class/CResult.cs
index 0eb814d..4cde1ac 100644
--- a/Cs_HMI/Project/Class/CResult.cs
+++ b/Cs_HMI/Project/Class/CResult.cs
@@ -22,11 +22,31 @@ namespace Project
public Color SMSG_ShadowColor = Color.Transparent;
public float SMSG_ProgressValue = 0;
public string SMSG_Tag = string.Empty;
- //public event EventHandler SMSG_Update;
- //public void UpdateStatusMessage()
- //{
- // SMSG_Update?.Invoke(null, null);
- //}
+ ///
+ /// 이동대상위치(상차,하차,충전)
+ ///
+ private ePosition _targetPos = ePosition.NONE;
+ public string result_message = "";
+ public double result_progressmax = 0;
+ public double result_progressvalue = 0;
+ public DateTime StopMessageTimePLC = DateTime.Parse("1982-11-23");
+ public DateTime StopMessageTimeSWR = DateTime.Parse("1982-11-23");
+ public string StopMessagePLC = string.Empty;
+ public string StopMessageSWR = string.Empty;
+ private ePosition _currentpos = ePosition.NONE;
+ private string _currentposcw = string.Empty;
+ public ushort LastTAG { get; set; } = 0;
+ public ePosition NextPos = ePosition.NONE;
+ private char _comandKit { get; set; }
+ public string Memo;
+ public eResult ResultCode { get; set; }
+ public eECode ResultErrorCode;
+ public string ResultMessage { get; set; }
+ public Boolean isError { get; set; }
+ public int retry = 0;
+ public DateTime retryTime;
+ public Device.Socket.Message RecvMessage;
+
///
/// 작업시작시간
///
@@ -52,9 +72,6 @@ namespace Project
}
}
- //public DateTime ChargeStartTime = DateTime.Parse("1982-11-23");
-
-
#region "AGV Status Value"
public string PLC1_RawData { get; set; }
public string PLC2_RawData { get; set; }
@@ -62,25 +79,7 @@ namespace Project
#endregion
- ///
- /// 이동대상위치(상차,하차,충전)
- ///
- private ePosition _targetPos = ePosition.NONE;
-
-
- public string result_message = "";
- public double result_progressmax = 0;
- public double result_progressvalue = 0;
-
-
- public DateTime StopMessageTimePLC = DateTime.Parse("1982-11-23");
- public DateTime StopMessageTimeSWR = DateTime.Parse("1982-11-23");
- public string StopMessagePLC = string.Empty;
- public string StopMessageSWR = string.Empty;
- //public DateTime LastChar
- //geTime = DateTime.Parse("1982-11-23");
-
- public ePosition NextPos = ePosition.NONE;
+
public ePosition TargetPos
{
get
@@ -94,7 +93,7 @@ namespace Project
}
}
- private char _comandKit { get; set; }
+
public char CommandKit
{
get
@@ -109,28 +108,7 @@ namespace Project
}
}
-
- //private ePosition _currentPos = ePosition.NONE;
- //public ePosition CurrentPos
- //{
- // get
- // {
- // return _currentPos;
- // }
- // set
- // {
- // if (_currentPos != value) //값이바뀔떄만 메세지 220628
- // PUB.log.Add(string.Format("현재위치 설정:{0}->{1}", _currentPos, value));
-
- // _currentPos = value;
- // }
- //}
-
- private ePosition _currentpos = ePosition.NONE;
- private string _currentposcw = string.Empty;
-
- // public ePosition LastPos = ePosition.NONE;
- public string LastTAG { get; set; } = string.Empty;
+
public ePosition CurrentPos
{
get
@@ -161,11 +139,7 @@ namespace Project
_currentposcw = value;
}
}
- public string Memo;
-
- public eResult ResultCode { get; set; }
- public eECode ResultErrorCode;
- public string ResultMessage { get; set; }
+
#region "SetResultMessage"
@@ -203,14 +177,7 @@ namespace Project
#endregion
-
-
- public Boolean isError { get; set; }
-
- public int retry = 0;
- public DateTime retryTime;
- public Device.Socket.Message RecvMessage;
-
+
public CResult()
{
this.Clear();
diff --git a/Cs_HMI/Project/Device/Xbee.cs b/Cs_HMI/Project/Device/Xbee.cs
index cd67b98..4e99c9f 100644
--- a/Cs_HMI/Project/Device/Xbee.cs
+++ b/Cs_HMI/Project/Device/Xbee.cs
@@ -38,6 +38,8 @@ namespace Project.Device
public Xbee()
{
+ this.WriteTimeout = 500;
+ this.ReadTimeout = 500;
this.DataReceived += Xbee_DataReceived;
proto = new EEProtocol();
proto.OnDataReceived += Proto_OnDataReceived;
@@ -166,12 +168,18 @@ namespace Project.Device
public bool CleanerInComplete { get; set; }
public bool CleanerOutComplete { get; set; }
+ ManualResetEvent sendlock = new ManualResetEvent(true);
+
///
/// AGV상태를 Xbee 로 전송한다
///
public void SendStatus()
{
+ if (this.IsOpen == false) return;
+ if ( sendlock.WaitOne() == false) return;
+ sendlock.Reset();
+
/*
Mode[1] : 0=manual, 1=auto
RunSt[1] : 0=stop, 1=run, 2=error
@@ -246,7 +254,9 @@ namespace Project.Device
var cmd = (byte)ENIGProtocol.AGVCommandEH.Status;
var packet = proto.CreatePacket(PUB.setting.XBE_ID, cmd, data);
if (Send(packet))
- PUB.logxbee.AddI($"Send status {packet.Length} {packet.HexString()}");
+ PUB.logxbee.AddI($"Send status [O] : {packet.Length} {packet.HexString()}");
+ else
+ PUB.logxbee.AddE($"Send status [X] : {packet.Length} {packet.HexString()}");
LastStatusSendTime = DateTime.Now;
}
catch (Exception ex)
@@ -254,6 +264,11 @@ namespace Project.Device
errorMessage = ex.Message;
PUB.logxbee.AddE(errorMessage);
}
+ finally
+ {
+ sendlock.Set();
+ }
+
}
diff --git a/Cs_HMI/Project/Device/_DeviceManagement.cs b/Cs_HMI/Project/Device/_DeviceManagement.cs
deleted file mode 100644
index 93af0a2..0000000
--- a/Cs_HMI/Project/Device/_DeviceManagement.cs
+++ /dev/null
@@ -1,323 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Data;
-using System.Drawing;
-using System.Linq;
-using System.Text;
-using System.Threading;
-using System.Threading.Tasks;
-using System.Windows.Media.Animation;
-using AR;
-using arCtl;
-using COMM;
-using Project.StateMachine;
-
-namespace Project
-{
- ///
- /// 장치 연결 및 상태 전송을 담당하는 별도 태스크
- ///
- public partial class fMain
- {
- // 장치 관리 태스크 관련
- private Task deviceManagementTask;
- private CancellationTokenSource deviceManagementCts;
- private volatile bool isDeviceManagementRunning = false;
-
- ///
- /// 장치 관리 태스크 시작 (IDLE 상태 진입 시 호출)
- ///
- public void StartDeviceManagementTask()
- {
- if (isDeviceManagementRunning)
- {
- PUB.log.Add("DeviceManagement", "이미 실행 중입니다.");
- return;
- }
-
- isDeviceManagementRunning = true;
- deviceManagementCts = new CancellationTokenSource();
-
- deviceManagementTask = Task.Factory.StartNew(
- () => DeviceManagementWorker(deviceManagementCts.Token),
- deviceManagementCts.Token,
- TaskCreationOptions.LongRunning,
- TaskScheduler.Default
- );
-
- PUB.log.Add("DeviceManagement", "장치 관리 태스크 시작");
- }
-
- ///
- /// 장치 관리 태스크 종료
- /// File : /device/_DeviceManagement.cs
- ///
- public void StopDeviceManagementTask()
- {
- if (!isDeviceManagementRunning)
- return;
-
- isDeviceManagementRunning = false;
-
- try
- {
- deviceManagementCts?.Cancel();
-
- if (deviceManagementTask != null)
- {
- if (!deviceManagementTask.Wait(3000)) // 3초 대기
- {
- PUB.log.AddE("DeviceManagement:태스크 종료 대기 시간 초과");
- }
- }
- }
- catch (Exception ex)
- {
- PUB.log.AddE($"DeviceManagement 종료 중 오류: {ex.Message}");
- }
- finally
- {
- deviceManagementCts?.Dispose();
- deviceManagementCts = null;
- deviceManagementTask = null;
- PUB.log.Add("DeviceManagement", "장치 관리 태스크 종료");
- }
- }
-
- ///
- /// 장치 관리 워커 (별도 태스크에서 실행)
- /// - 장치 연결 관리 (AGV, XBee, BMS)
- /// - 자동 상태 전송 (XBee, BMS)
- ///
- private void DeviceManagementWorker(CancellationToken cancellationToken)
- {
- PUB.log.Add("DeviceManagementWorker", "시작");
-
- DateTime lastXbeStatusSendTime = DateTime.Now;
- DateTime lastBmsQueryTime = DateTime.Now;
-
- while (!cancellationToken.IsCancellationRequested && isDeviceManagementRunning)
- {
- try
- {
- // 상태머신이 IDLE 이상이고 CLOSING 미만일 때만 동작
- if (PUB.sm.Step >= eSMStep.IDLE && PUB.sm.Step < eSMStep.CLOSING)
- {
- // ========== 1. 장치 연결 관리 ==========
- ManageDeviceConnections();
-
- // ========== 2. XBee 상태 전송 ==========
- if (PUB.XBE != null && PUB.XBE.IsOpen)
- {
- var tsXbe = DateTime.Now - lastXbeStatusSendTime;
- if (tsXbe.TotalSeconds >= PUB.setting.interval_xbe)
- {
- lastXbeStatusSendTime = DateTime.Now;
- ThreadPool.QueueUserWorkItem(_ =>
- {
- try
- {
- PUB.XBE.SendStatus();
- }
- catch (Exception ex)
- {
- PUB.log.AddE($"XBee SendStatus 오류: {ex.Message}");
- }
- });
- }
- }
-
- // ========== 3. BMS 쿼리 및 배터리 경고 ==========
- if (PUB.BMS != null && PUB.BMS.IsOpen)
- {
- var tsBms = DateTime.Now - lastBmsQueryTime;
- if (tsBms.TotalSeconds >= PUB.setting.interval_bms)
- {
- lastBmsQueryTime = DateTime.Now;
- ThreadPool.QueueUserWorkItem(_ =>
- {
- try
- {
- PUB.BMS.SendQuery();
- }
- catch (Exception ex)
- {
- PUB.log.AddE($"BMS SendQuery 오류: {ex.Message}");
- }
- });
- }
-
- // 배터리 경고음
- try
- {
- Update_BatteryWarnSpeak();
- }
- catch (Exception ex)
- {
- PUB.log.AddE($"BatteryWarnSpeak 오류: {ex.Message}");
- }
- }
- }
- }
- catch (Exception ex)
- {
- PUB.log.AddE($"DeviceManagementWorker 오류: {ex.Message}");
- }
-
- // 1초 대기 (또는 취소 요청 시 즉시 종료)
- try
- {
- Task.Delay(1000, cancellationToken).Wait();
- }
- catch (OperationCanceledException)
- {
- break;
- }
- }
- PUB.log.Add("DeviceManagementWorker", "종료");
- }
-
- ///
- /// 장치 연결 상태 관리
- ///
- private void ManageDeviceConnections()
- {
- try
- {
- // AGV 연결
- ConnectSerialPort(PUB.AGV, PUB.setting.Port_AGV, PUB.setting.Baud_AGV,
- eVarTime.LastConn_AGV, eVarTime.LastConnTry_AGV, eVarTime.LastRecv_AGV);
-
- // XBee 연결
- ConnectSerialPort(PUB.XBE, PUB.setting.Port_XBE, PUB.setting.Baud_XBE,
- eVarTime.LastConn_XBE, eVarTime.LastConnTry_XBE, eVarTime.LastRecv_XBE);
-
- // BMS 연결
- if (PUB.BMS.IsOpen == false)
- {
- var ts = VAR.TIME.RUN(eVarTime.LastConn_BAT);
- if (ts.TotalSeconds > 3)
- {
- PUB.log.Add($"BMS 연결 시도: {PUB.setting.Port_BAT}");
- PUB.BMS.PortName = PUB.setting.Port_BAT;
- if (PUB.BMS.Open())
- PUB.log.AddI($"BMS 연결 완료({PUB.setting.Port_BAT})");
-
- VAR.TIME.Update(eVarTime.LastConn_BAT);
- VAR.TIME.Update(eVarTime.LastConnTry_BAT);
- }
- }
- else if (PUB.BMS.IsValid == false)
- {
- var ts = VAR.TIME.RUN(eVarTime.LastConnTry_BAT);
- if (ts.TotalSeconds > (PUB.setting.interval_bms * 2.5))
- {
- PUB.log.Add("BMS 자동 연결 해제 (응답 없음)");
- PUB.BMS.Close();
- VAR.TIME.Set(eVarTime.LastConn_BAT, DateTime.Now.AddSeconds(5));
- }
- }
- }
- catch (Exception ex)
- {
- PUB.log.AddE($"ManageDeviceConnections 오류: {ex.Message}");
- }
- }
-
- ///
- /// 시리얼 포트 연결 (arDev.arRS232)
- ///
- bool ConnectSerialPort(arDev.arRS232 dev, string port, int baud, eVarTime conn, eVarTime conntry, eVarTime recvtime)
- {
- if(port.isEmpty()) return false;
-
- if (dev.IsOpen == false && port.isEmpty() == false)
- {
- var tsPLC = VAR.TIME.RUN(conntry);
- if (tsPLC.TotalSeconds > 5)
- {
- VAR.TIME.Update(conntry);
- try
- {
- VAR.TIME.Update(recvtime);
- dev.PortName = port;
- dev.BaudRate = baud;
- if (dev.Open())
- {
- PUB.log.Add(port, $"[AGV:{port}:{baud}] 연결 완료");
- }
- else
- {
- //존재하지 않는 포트라면 sync를 벗어난다
- var ports = System.IO.Ports.SerialPort.GetPortNames().Select(t => t.ToLower()).ToList();
- if (ports.Contains(PUB.setting.Port_AGV.ToLower()) == false)
- {
- return false;
- }
- else
- {
- var errmessage = dev.errorMessage;
- PUB.log.AddE($"[AGV:{port}:{baud}] {errmessage}");
- }
- }
- VAR.TIME.Update(conn);
- VAR.TIME.Update(conntry);
- }
- catch (Exception ex)
- {
- PUB.log.AddE(ex.Message);
- }
- }
- }
- else if (dev.PortName.Equals(port) == false)
- {
- PUB.log.Add(port, $"포트 변경({dev.PortName}->{port})으로 연결 종료");
- dev.Close();
- VAR.TIME.Update(conntry);
- }
- return true;
- }
-
- ///
- /// 시리얼 포트 연결 (Device.Xbee)
- ///
- void ConnectSerialPort(Device.Xbee dev, string port, int baud, eVarTime conn, eVarTime conntry, eVarTime recvtime)
- {
- if (dev.IsOpen == false && port.isEmpty() == false)
- {
- var tsPLC = VAR.TIME.RUN(conntry);
- if (tsPLC.TotalSeconds > 5)
- {
- VAR.TIME.Update(conntry);
- try
- {
- VAR.TIME.Update(recvtime);
- dev.PortName = port;
- dev.BaudRate = baud;
- if (dev.Open())
- {
- PUB.log.Add(port, $"[XBEE:{port}:{baud}] 연결 완료");
- }
- else
- {
- var errmessage = dev.errorMessage;
- PUB.log.AddE($"[XBEE:{port}:{baud}] {errmessage}");
- }
- VAR.TIME.Update(conn);
- VAR.TIME.Update(conntry);
- }
- catch (Exception ex)
- {
- PUB.log.AddE(ex.Message);
- }
- }
- }
- else if (dev.PortName.Equals(port) == false)
- {
- PUB.log.Add(port, $"포트 변경({dev.PortName}->{port})으로 연결 종료");
- dev.Close();
- VAR.TIME[(int)conntry] = DateTime.Now;
- }
- }
- }
-}
diff --git a/Cs_HMI/Project/Dialog/DriveDetector.cs b/Cs_HMI/Project/Dialog/DriveDetector.cs
deleted file mode 100644
index 91ab200..0000000
--- a/Cs_HMI/Project/Dialog/DriveDetector.cs
+++ /dev/null
@@ -1,815 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Text;
-using System.Windows.Forms; // required for Message
-using System.Runtime.InteropServices; // required for Marshal
-using System.IO;
-using Microsoft.Win32.SafeHandles;
-// DriveDetector - rev. 1, Oct. 31 2007
-
-namespace usbdetect
-{
- ///
- /// Hidden Form which we use to receive Windows messages about flash drives
- ///
- internal class DetectorForm : Form
- {
- private Label label1;
- private DriveDetector mDetector = null;
-
- ///
- /// Set up the hidden form.
- ///
- /// DriveDetector object which will receive notification about USB drives, see WndProc
- public DetectorForm(DriveDetector detector)
- {
- mDetector = detector;
- this.MinimizeBox = false;
- this.MaximizeBox = false;
- this.ShowInTaskbar = false;
- this.ShowIcon = false;
- this.FormBorderStyle = FormBorderStyle.None;
- this.Load += new System.EventHandler(this.Load_Form);
- this.Activated += new EventHandler(this.Form_Activated);
- }
-
- private void Load_Form(object sender, EventArgs e)
- {
- // We don't really need this, just to display the label in designer ...
- InitializeComponent();
-
- // Create really small form, invisible anyway.
- this.Size = new System.Drawing.Size(5, 5);
- }
-
- private void Form_Activated(object sender, EventArgs e)
- {
- this.Visible = false;
- }
-
- ///
- /// This function receives all the windows messages for this window (form).
- /// We call the DriveDetector from here so that is can pick up the messages about
- /// drives arrived and removed.
- ///
- protected override void WndProc(ref Message m)
- {
- base.WndProc(ref m);
-
- if (mDetector != null)
- {
- mDetector.WndProc(ref m);
- }
- }
-
- private void InitializeComponent()
- {
- this.label1 = new System.Windows.Forms.Label();
- this.SuspendLayout();
- //
- // label1
- //
- this.label1.AutoSize = true;
- this.label1.Location = new System.Drawing.Point(13, 30);
- this.label1.Name = "label1";
- this.label1.Size = new System.Drawing.Size(377, 12);
- this.label1.TabIndex = 0;
- this.label1.Text = "This is invisible form. To see DriveDetector code click View Code";
- //
- // DetectorForm
- //
- this.ClientSize = new System.Drawing.Size(435, 80);
- this.Controls.Add(this.label1);
- this.Name = "DetectorForm";
- this.ResumeLayout(false);
- this.PerformLayout();
-
- }
- } // class DetectorForm
-
-
- // Delegate for event handler to handle the device events
- public delegate void DriveDetectorEventHandler(Object sender, DriveDetectorEventArgs e);
-
- ///
- /// Our class for passing in custom arguments to our event handlers
- ///
- ///
- public class DriveDetectorEventArgs : EventArgs
- {
-
-
- public DriveDetectorEventArgs()
- {
- Cancel = false;
- Drive = "";
- HookQueryRemove = false;
- }
-
- ///
- /// Get/Set the value indicating that the event should be cancelled
- /// Only in QueryRemove handler.
- ///
- public bool Cancel;
-
- ///
- /// Drive letter for the device which caused this event
- ///
- public string Drive;
-
- ///
- /// Set to true in your DeviceArrived event handler if you wish to receive the
- /// QueryRemove event for this drive.
- ///
- public bool HookQueryRemove;
-
- }
-
-
- ///
- /// Detects insertion or removal of removable drives.
- /// Use it in 1 or 2 steps:
- /// 1) Create instance of this class in your project and add handlers for the
- /// DeviceArrived, DeviceRemoved and QueryRemove events.
- /// AND (if you do not want drive detector to creaate a hidden form))
- /// 2) Override WndProc in your form and call DriveDetector's WndProc from there.
- /// If you do not want to do step 2, just use the DriveDetector constructor without arguments and
- /// it will create its own invisible form to receive messages from Windows.
- ///
- class DriveDetector : IDisposable
- {
- ///
- /// Events signalized to the client app.
- /// Add handlers for these events in your form to be notified of removable device events
- ///
- public event DriveDetectorEventHandler DeviceArrived;
- public event DriveDetectorEventHandler DeviceRemoved;
- public event DriveDetectorEventHandler QueryRemove;
-
- ///
- /// The easiest way to use DriveDetector.
- /// It will create hidden form for processing Windows messages about USB drives
- /// You do not need to override WndProc in your form.
- ///
- public DriveDetector()
- {
- DetectorForm frm = new DetectorForm(this);
- frm.Show(); // will be hidden immediatelly
- Init(frm, null);
- }
-
- ///
- /// Alternate constructor.
- /// Pass in your Form and DriveDetector will not create hidden form.
- ///
- /// object which will receive Windows messages.
- /// Pass "this" as this argument from your form class.
- public DriveDetector(Control control)
- {
- Init(control, null);
- }
-
- ///
- /// Consructs DriveDetector object setting also path to file which should be opened
- /// when registering for query remove.
- ///
- ///object which will receive Windows messages.
- /// Pass "this" as this argument from your form class.
- /// Optional. Name of a file on the removable drive which should be opened.
- /// If null, root directory of the drive will be opened. Opening a file is needed for us
- /// to be able to register for the query remove message. TIP: For files use relative path without drive letter.
- /// e.g. "SomeFolder\file_on_flash.txt"
- public DriveDetector(Control control, string FileToOpen)
- {
- Init(control, FileToOpen);
- }
-
- ///
- /// init the DriveDetector object
- ///
- ///
- private void Init(Control control, string fileToOpen)
- {
- mFileToOpen = fileToOpen;
- mFileOnFlash = null;
- mDeviceNotifyHandle = IntPtr.Zero;
- mRecipientHandle = control.Handle;
- mDirHandle = IntPtr.Zero; // handle to the root directory of the flash drive which we open
- mCurrentDrive = "";
- }
-
- ///
- /// Gets the value indicating whether the query remove event will be fired.
- ///
- public bool IsQueryHooked
- {
- get
- {
- if (mDeviceNotifyHandle == IntPtr.Zero)
- return false;
- else
- return true;
- }
- }
-
- ///
- /// Gets letter of drive which is currently hooked. Empty string if none.
- /// See also IsQueryHooked.
- ///
- public string HookedDrive
- {
- get
- {
- return mCurrentDrive;
- }
- }
-
- ///
- /// Gets the file stream for file which this class opened on a drive to be notified
- /// about it's removal.
- /// This will be null unless you specified a file to open (DriveDetector opens root directory of the flash drive)
- ///
- public FileStream OpenedFile
- {
- get
- {
- return mFileOnFlash;
- }
- }
-
- ///
- /// Hooks specified drive to receive a message when it is being removed.
- /// This can be achieved also by setting e.HookQueryRemove to true in your
- /// DeviceArrived event handler.
- /// By default DriveDetector will open the root directory of the flash drive to obtain notification handle
- /// from Windows (to learn when the drive is about to be removed).
- ///
- /// Drive letter or relative path to a file on the drive which should be
- /// used to get a handle - required for registering to receive query remove messages.
- /// If only drive letter is specified (e.g. "D:\\", root directory of the drive will be opened.
- /// true if hooked ok, false otherwise
- public bool EnableQueryRemove(string fileOnDrive)
- {
- if (fileOnDrive == null || fileOnDrive.Length == 0)
- throw new ArgumentException("Drive path must be supplied to register for Query remove.");
-
- if ( fileOnDrive.Length == 2 && fileOnDrive[1] == ':' )
- fileOnDrive += '\\'; // append "\\" if only drive letter with ":" was passed in.
-
- if (mDeviceNotifyHandle != IntPtr.Zero)
- {
- // Unregister first...
- RegisterForDeviceChange(false, null);
- }
-
- if (Path.GetFileName(fileOnDrive).Length == 0 ||!File.Exists(fileOnDrive))
- mFileToOpen = null; // use root directory...
- else
- mFileToOpen = fileOnDrive;
-
- RegisterQuery(Path.GetPathRoot(fileOnDrive));
- if (mDeviceNotifyHandle == IntPtr.Zero)
- return false; // failed to register
-
- return true;
- }
-
- ///
- /// Unhooks any currently hooked drive so that the query remove
- /// message is not generated for it.
- ///
- public void DisableQueryRemove()
- {
- if (mDeviceNotifyHandle != IntPtr.Zero)
- {
- RegisterForDeviceChange(false, null);
- }
- }
-
-
- ///
- /// Unregister and close the file we may have opened on the removable drive.
- /// Garbage collector will call this method.
- ///
- public void Dispose()
- {
- RegisterForDeviceChange(false, null);
- }
-
-
- #region WindowProc
- ///
- /// Message handler which must be called from client form.
- /// Processes Windows messages and calls event handlers.
- ///
- ///
- public void WndProc(ref Message m)
- {
- int devType;
- char c;
-
- if (m.Msg == WM_DEVICECHANGE)
- {
- // WM_DEVICECHANGE can have several meanings depending on the WParam value...
- switch (m.WParam.ToInt32())
- {
-
- //
- // New device has just arrived
- //
- case DBT_DEVICEARRIVAL:
-
- devType = Marshal.ReadInt32(m.LParam, 4);
- if (devType == DBT_DEVTYP_VOLUME)
- {
- DEV_BROADCAST_VOLUME vol;
- vol = (DEV_BROADCAST_VOLUME)
- Marshal.PtrToStructure(m.LParam, typeof(DEV_BROADCAST_VOLUME));
-
- // Get the drive letter
- c = DriveMaskToLetter(vol.dbcv_unitmask);
-
-
- //
- // Call the client event handler
- //
- // We should create copy of the event before testing it and
- // calling the delegate - if any
- DriveDetectorEventHandler tempDeviceArrived = DeviceArrived;
- if ( tempDeviceArrived != null )
- {
- DriveDetectorEventArgs e = new DriveDetectorEventArgs();
- e.Drive = c + ":\\";
- tempDeviceArrived(this, e);
-
- // Register for query remove if requested
- if (e.HookQueryRemove)
- {
- // If something is already hooked, unhook it now
- if (mDeviceNotifyHandle != IntPtr.Zero)
- {
- RegisterForDeviceChange(false, null);
- }
-
- RegisterQuery(c + ":\\");
- }
- } // if has event handler
-
-
- }
- break;
-
-
-
- //
- // Device is about to be removed
- // Any application can cancel the removal
- //
- case DBT_DEVICEQUERYREMOVE:
-
- devType = Marshal.ReadInt32(m.LParam, 4);
- if (devType == DBT_DEVTYP_HANDLE)
- {
- // TODO: we could get the handle for which this message is sent
- // from vol.dbch_handle and compare it against a list of handles for
- // which we have registered the query remove message (?)
- //DEV_BROADCAST_HANDLE vol;
- //vol = (DEV_BROADCAST_HANDLE)
- // Marshal.PtrToStructure(m.LParam, typeof(DEV_BROADCAST_HANDLE));
- // if ( vol.dbch_handle ....
-
-
- //
- // Call the event handler in client
- //
- DriveDetectorEventHandler tempQuery = QueryRemove;
- if (tempQuery != null)
- {
- DriveDetectorEventArgs e = new DriveDetectorEventArgs();
- e.Drive = mCurrentDrive; // drive which is hooked
- tempQuery(this, e);
-
- // If the client wants to cancel, let Windows know
- if (e.Cancel)
- {
- m.Result = (IntPtr)BROADCAST_QUERY_DENY;
- }
- else
- {
- // Change 28.10.2007: Unregister the notification, this will
- // close the handle to file or root directory also.
- // We have to close it anyway to allow the removal so
- // even if some other app cancels the removal we would not know about it...
- RegisterForDeviceChange(false, null); // will also close the mFileOnFlash
- }
-
- }
- }
- break;
-
-
- //
- // Device has been removed
- //
- case DBT_DEVICEREMOVECOMPLETE:
-
- devType = Marshal.ReadInt32(m.LParam, 4);
- if (devType == DBT_DEVTYP_VOLUME)
- {
- devType = Marshal.ReadInt32(m.LParam, 4);
- if (devType == DBT_DEVTYP_VOLUME)
- {
- DEV_BROADCAST_VOLUME vol;
- vol = (DEV_BROADCAST_VOLUME)
- Marshal.PtrToStructure(m.LParam, typeof(DEV_BROADCAST_VOLUME));
- c = DriveMaskToLetter(vol.dbcv_unitmask);
-
- //
- // Call the client event handler
- //
- DriveDetectorEventHandler tempDeviceRemoved = DeviceRemoved;
- if (tempDeviceRemoved != null)
- {
- DriveDetectorEventArgs e = new DriveDetectorEventArgs();
- e.Drive = c + ":\\";
- tempDeviceRemoved(this, e);
- }
-
- // TODO: we could unregister the notify handle here if we knew it is the
- // right drive which has been just removed
- //RegisterForDeviceChange(false, null);
- }
- }
- break;
- }
-
- }
-
- }
- #endregion
-
-
-
- #region Private Area
-
- ///
- /// New: 28.10.2007 - handle to root directory of flash drive which is opened
- /// for device notification
- ///
- private IntPtr mDirHandle = IntPtr.Zero;
-
- ///
- /// Class which contains also handle to the file opened on the flash drive
- ///
- private FileStream mFileOnFlash = null;
-
- ///
- /// Name of the file to try to open on the removable drive for query remove registration
- ///
- private string mFileToOpen;
-
- ///
- /// Handle to file which we keep opened on the drive if query remove message is required by the client
- ///
- private IntPtr mDeviceNotifyHandle;
-
- ///
- /// Handle of the window which receives messages from Windows. This will be a form.
- ///
- private IntPtr mRecipientHandle;
-
- ///
- /// Drive which is currently hooked for query remove
- ///
- private string mCurrentDrive;
-
-
- // Win32 constants
- private const int DBT_DEVTYP_DEVICEINTERFACE = 5;
- private const int DBT_DEVTYP_HANDLE = 6;
- private const int BROADCAST_QUERY_DENY = 0x424D5144;
- private const int WM_DEVICECHANGE = 0x0219;
- private const int DBT_DEVICEARRIVAL = 0x8000; // system detected a new device
- private const int DBT_DEVICEQUERYREMOVE = 0x8001; // Preparing to remove (any program can disable the removal)
- private const int DBT_DEVICEREMOVECOMPLETE = 0x8004; // removed
- private const int DBT_DEVTYP_VOLUME = 0x00000002; // drive type is logical volume
-
- ///
- /// Registers for receiving the query remove message for a given drive.
- /// We need to open a handle on that drive and register with this handle.
- /// Client can specify this file in mFileToOpen or we will open root directory of the drive
- ///
- /// drive for which to register.
- private void RegisterQuery(string drive)
- {
- bool register = true;
-
- if (mFileToOpen == null)
- {
- // Change 28.10.2007 - Open the root directory if no file specified - leave mFileToOpen null
- // If client gave us no file, let's pick one on the drive...
- //mFileToOpen = GetAnyFile(drive);
- //if (mFileToOpen.Length == 0)
- // return; // no file found on the flash drive
- }
- else
- {
- // Make sure the path in mFileToOpen contains valid drive
- // If there is a drive letter in the path, it may be different from the actual
- // letter assigned to the drive now. We will cut it off and merge the actual drive
- // with the rest of the path.
- if (mFileToOpen.Contains(":"))
- {
- string tmp = mFileToOpen.Substring(3);
- string root = Path.GetPathRoot(drive);
- mFileToOpen = Path.Combine(root, tmp);
- }
- else
- mFileToOpen = Path.Combine(drive, mFileToOpen);
- }
-
-
- try
- {
- //mFileOnFlash = new FileStream(mFileToOpen, FileMode.Open);
- // Change 28.10.2007 - Open the root directory
- if (mFileToOpen == null) // open root directory
- mFileOnFlash = null;
- else
- mFileOnFlash = new FileStream(mFileToOpen, FileMode.Open);
- }
- catch (Exception)
- {
- // just do not register if the file could not be opened
- register = false;
- }
-
-
- if (register)
- {
- //RegisterForDeviceChange(true, mFileOnFlash.SafeFileHandle);
- //mCurrentDrive = drive;
- // Change 28.10.2007 - Open the root directory
- if (mFileOnFlash == null)
- RegisterForDeviceChange(drive);
- else
- // old version
- RegisterForDeviceChange(true, mFileOnFlash.SafeFileHandle);
-
- mCurrentDrive = drive;
- }
-
-
- }
-
-
- ///
- /// New version which gets the handle automatically for specified directory
- /// Only for registering! Unregister with the old version of this function...
- ///
- ///
- /// e.g. C:\\dir
- private void RegisterForDeviceChange(string dirPath)
- {
- IntPtr handle = Native.OpenDirectory(dirPath);
- if (handle == IntPtr.Zero)
- {
- mDeviceNotifyHandle = IntPtr.Zero;
- return;
- }
- else
- mDirHandle = handle; // save handle for closing it when unregistering
-
- // Register for handle
- DEV_BROADCAST_HANDLE data = new DEV_BROADCAST_HANDLE();
- data.dbch_devicetype = DBT_DEVTYP_HANDLE;
- data.dbch_reserved = 0;
- data.dbch_nameoffset = 0;
- //data.dbch_data = null;
- //data.dbch_eventguid = 0;
- data.dbch_handle = handle;
- data.dbch_hdevnotify = (IntPtr)0;
- int size = Marshal.SizeOf(data);
- data.dbch_size = size;
- IntPtr buffer = Marshal.AllocHGlobal(size);
- Marshal.StructureToPtr(data, buffer, true);
-
- mDeviceNotifyHandle = Native.RegisterDeviceNotification(mRecipientHandle, buffer, 0);
-
- }
-
- ///
- /// Registers to be notified when the volume is about to be removed
- /// This is requierd if you want to get the QUERY REMOVE messages
- ///
- /// true to register, false to unregister
- /// handle of a file opened on the removable drive
- private void RegisterForDeviceChange(bool register, SafeFileHandle fileHandle)
- {
- if (register)
- {
- // Register for handle
- DEV_BROADCAST_HANDLE data = new DEV_BROADCAST_HANDLE();
- data.dbch_devicetype = DBT_DEVTYP_HANDLE;
- data.dbch_reserved = 0;
- data.dbch_nameoffset = 0;
- //data.dbch_data = null;
- //data.dbch_eventguid = 0;
- data.dbch_handle = fileHandle.DangerousGetHandle(); //Marshal. fileHandle;
- data.dbch_hdevnotify = (IntPtr)0;
- int size = Marshal.SizeOf(data);
- data.dbch_size = size;
- IntPtr buffer = Marshal.AllocHGlobal(size);
- Marshal.StructureToPtr(data, buffer, true);
-
- mDeviceNotifyHandle = Native.RegisterDeviceNotification(mRecipientHandle, buffer, 0);
- }
- else
- {
- // close the directory handle
- if (mDirHandle != IntPtr.Zero)
- {
- Native.CloseDirectoryHandle(mDirHandle);
- // string er = Marshal.GetLastWin32Error().ToString();
- }
-
- // unregister
- if (mDeviceNotifyHandle != IntPtr.Zero)
- {
- Native.UnregisterDeviceNotification(mDeviceNotifyHandle);
- }
-
-
- mDeviceNotifyHandle = IntPtr.Zero;
- mDirHandle = IntPtr.Zero;
-
- mCurrentDrive = "";
- if (mFileOnFlash != null)
- {
- mFileOnFlash.Close();
- mFileOnFlash = null;
- }
- }
-
- }
-
- ///
- /// Gets drive letter from a bit mask where bit 0 = A, bit 1 = B etc.
- /// There can actually be more than one drive in the mask but we
- /// just use the last one in this case.
- ///
- ///
- ///
- private static char DriveMaskToLetter(int mask)
- {
- char letter;
- string drives = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
- // 1 = A
- // 2 = B
- // 4 = C...
- int cnt = 0;
- int pom = mask / 2;
- while (pom != 0)
- {
- // while there is any bit set in the mask
- // shift it to the righ...
- pom = pom / 2;
- cnt++;
- }
-
- if (cnt < drives.Length)
- letter = drives[cnt];
- else
- letter = '?';
-
- return letter;
- }
-
- /* 28.10.2007 - no longer needed
- ///
- /// Searches for any file in a given path and returns its full path
- ///
- /// drive to search
- /// path of the file or empty string
- private string GetAnyFile(string drive)
- {
- string file = "";
- // First try files in the root
- string[] files = Directory.GetFiles(drive);
- if (files.Length == 0)
- {
- // if no file in the root, search whole drive
- files = Directory.GetFiles(drive, "*.*", SearchOption.AllDirectories);
- }
-
- if (files.Length > 0)
- file = files[0]; // get the first file
-
- // return empty string if no file found
- return file;
- }*/
- #endregion
-
-
- #region Native Win32 API
- ///
- /// WinAPI functions
- ///
- private class Native
- {
- // HDEVNOTIFY RegisterDeviceNotification(HANDLE hRecipient,LPVOID NotificationFilter,DWORD Flags);
- [DllImport("user32.dll", CharSet = CharSet.Auto)]
- public static extern IntPtr RegisterDeviceNotification(IntPtr hRecipient, IntPtr NotificationFilter, uint Flags);
-
- [DllImport("user32.dll", CharSet = CharSet.Auto)]
- public static extern uint UnregisterDeviceNotification(IntPtr hHandle);
-
- //
- // CreateFile - MSDN
- const uint GENERIC_READ = 0x80000000;
- const uint OPEN_EXISTING = 3;
- const uint FILE_SHARE_READ = 0x00000001;
- const uint FILE_SHARE_WRITE = 0x00000002;
- const uint FILE_ATTRIBUTE_NORMAL = 128;
- const uint FILE_FLAG_BACKUP_SEMANTICS = 0x02000000;
- static readonly IntPtr INVALID_HANDLE_VALUE = new IntPtr(-1);
-
-
- // should be "static extern unsafe"
- [DllImport("kernel32", SetLastError = true)]
- static extern IntPtr CreateFile(
- string FileName, // file name
- uint DesiredAccess, // access mode
- uint ShareMode, // share mode
- uint SecurityAttributes, // Security Attributes
- uint CreationDisposition, // how to create
- uint FlagsAndAttributes, // file attributes
- int hTemplateFile // handle to template file
- );
-
-
- [DllImport("kernel32", SetLastError = true)]
- static extern bool CloseHandle(
- IntPtr hObject // handle to object
- );
-
- ///
- /// Opens a directory, returns it's handle or zero.
- ///
- /// path to the directory, e.g. "C:\\dir"
- /// handle to the directory. Close it with CloseHandle().
- static public IntPtr OpenDirectory(string dirPath)
- {
- // open the existing file for reading
- IntPtr handle = CreateFile(
- dirPath,
- GENERIC_READ,
- FILE_SHARE_READ | FILE_SHARE_WRITE,
- 0,
- OPEN_EXISTING,
- FILE_FLAG_BACKUP_SEMANTICS | FILE_ATTRIBUTE_NORMAL,
- 0);
-
- if ( handle == INVALID_HANDLE_VALUE)
- return IntPtr.Zero;
- else
- return handle;
- }
-
-
- public static bool CloseDirectoryHandle(IntPtr handle)
- {
- return CloseHandle(handle);
- }
- }
-
-
- // Structure with information for RegisterDeviceNotification.
- [StructLayout(LayoutKind.Sequential)]
- public struct DEV_BROADCAST_HANDLE
- {
- public int dbch_size;
- public int dbch_devicetype;
- public int dbch_reserved;
- public IntPtr dbch_handle;
- public IntPtr dbch_hdevnotify;
- public Guid dbch_eventguid;
- public long dbch_nameoffset;
- //public byte[] dbch_data[1]; // = new byte[1];
- public byte dbch_data;
- public byte dbch_data1;
- }
-
- // Struct for parameters of the WM_DEVICECHANGE message
- [StructLayout(LayoutKind.Sequential)]
- public struct DEV_BROADCAST_VOLUME
- {
- public int dbcv_size;
- public int dbcv_devicetype;
- public int dbcv_reserved;
- public int dbcv_unitmask;
- }
- #endregion
-
- }
-}
diff --git a/Cs_HMI/Project/PUB.cs b/Cs_HMI/Project/PUB.cs
index e41d1a8..32edef8 100644
--- a/Cs_HMI/Project/PUB.cs
+++ b/Cs_HMI/Project/PUB.cs
@@ -647,7 +647,7 @@ namespace Project
/// 읽은 RFID ID
/// 모터 방향 (Forward/Backward)
/// 업데이트 성공 여부
- public static bool UpdateAGVFromRFID(string rfidId, AgvDirection motorDirection = AgvDirection.Forward)
+ public static bool UpdateAGVFromRFID(ushort rfidId, AgvDirection motorDirection = AgvDirection.Forward)
{
var _mapNodes = PUB._mapCanvas.Nodes;
if (_virtualAGV == null || _mapNodes == null) return false;
diff --git a/Cs_HMI/Project/StateMachine/Step/_STEP_CLOSE.cs b/Cs_HMI/Project/StateMachine/Step/_STEP_CLOSE.cs
index 2f89adc..40022ac 100644
--- a/Cs_HMI/Project/StateMachine/Step/_STEP_CLOSE.cs
+++ b/Cs_HMI/Project/StateMachine/Step/_STEP_CLOSE.cs
@@ -16,10 +16,7 @@ namespace Project
private void _STEP_CLOSING_START(eSMStep step)
{
PUB.bShutdown = true;
-
- // 장치 관리 태스크 종료
- StopDeviceManagementTask();
-
+
PUB.AddEEDB("프로그램 종료");
PUB.log.Add("Program Close");
PUB.LogFlush();
diff --git a/Cs_HMI/Project/StateMachine/_AGV.cs b/Cs_HMI/Project/StateMachine/_AGV.cs
index 0931bac..f7e081d 100644
--- a/Cs_HMI/Project/StateMachine/_AGV.cs
+++ b/Cs_HMI/Project/StateMachine/_AGV.cs
@@ -19,10 +19,8 @@ namespace Project
private void AGV_Message(object sender, arDev.Narumi.MessageEventArgs e)
{
if (e.MsgType == arDev.arRS232.MessageType.Normal)
-
PUB.logagv.AddE(e.Message);
else if (e.MsgType == arDev.arRS232.MessageType.Normal)
-
PUB.logagv.Add(e.Message);
else if (e.MsgType == arDev.arRS232.MessageType.Recv)
{
@@ -33,7 +31,6 @@ namespace Project
PUB.logagv.Add("AGV-TX", e.Message);
else
{
-
PUB.logagv.Add(e.MsgType.ToString(), e.Message);
}
}
@@ -44,6 +41,7 @@ namespace Project
{
try
{
+ VAR.TIME.Set(eVarTime.LastRecv_AGV, DateTime.Now);
//데이터 파싱
switch (e.DataType)
{
@@ -160,8 +158,8 @@ namespace Project
case arDev.Narumi.DataType.TAG:
{
//자동 실행 중이다.
-
- PUB.Result.LastTAG = PUB.AGV.data.TagNo.ToString("0000");
+
+ PUB.Result.LastTAG = PUB.AGV.data.TagNo;//.ToString("0000");
PUB.log.Add($"AGV 태그수신 : {PUB.AGV.data.TagNo} LastTag:{PUB.Result.LastTAG}");
//POT/NOT 보면 일단 바로 멈추게한다
if (PUB.Result.CurrentPos == ePosition.POT || PUB.Result.CurrentPos == ePosition.NOT)
@@ -172,7 +170,7 @@ namespace Project
}
//virtual agv setting
- var CurrentNode = PUB._mapCanvas.Nodes.FirstOrDefault(t => t.RfidId.Equals(PUB.Result.LastTAG, StringComparison.OrdinalIgnoreCase));
+ var CurrentNode = PUB._mapCanvas.Nodes.FirstOrDefault(t => t.RfidId == PUB.Result.LastTAG);
if (CurrentNode == null)
{
//없는 노드는 자동으로 추가한다
@@ -237,7 +235,6 @@ namespace Project
PUB._mapCanvas.PredictMessage = message;
}
-
}
catch (Exception ex)
{
@@ -245,4 +242,4 @@ namespace Project
}
}
}
-}
+}
\ No newline at end of file
diff --git a/Cs_HMI/Project/StateMachine/_Loop.cs b/Cs_HMI/Project/StateMachine/_Loop.cs
index f97eb72..0bee820 100644
--- a/Cs_HMI/Project/StateMachine/_Loop.cs
+++ b/Cs_HMI/Project/StateMachine/_Loop.cs
@@ -154,9 +154,7 @@ namespace Project
UpdateStatusMessage("준비 완료", Color.Red, Color.Gold);
if (startuptime.Year == 1982) startuptime = DateTime.Now;
- // 장치 관리 태스크 시작 (IDLE 진입 시 한 번만)
- StartDeviceManagementTask();
-
+
// 동기화 모드 종료 (혹시 남아있을 경우)
if (PUB._mapCanvas != null)
{
diff --git a/Cs_HMI/Project/StateMachine/_SPS.cs b/Cs_HMI/Project/StateMachine/_SPS.cs
index 8a3d287..9ba6c5b 100644
--- a/Cs_HMI/Project/StateMachine/_SPS.cs
+++ b/Cs_HMI/Project/StateMachine/_SPS.cs
@@ -21,22 +21,230 @@ namespace Project
{
DateTime chargesynctime = DateTime.Now;
DateTime agvsendstarttime = DateTime.Now;
+ DateTime lastXbeStatusSendTime = DateTime.Now;
+ DateTime lastBmsQueryTime = DateTime.Now;
void sm_SPS(object sender, EventArgs e)
{
- if (PUB.sm.Step < eSMStep.IDLE || PUB.sm.Step >= eSMStep.CLOSING) return;
+ if (PUB.sm == null || PUB.sm.Step < eSMStep.IDLE || PUB.sm.Step >= eSMStep.CLOSING || PUB.bShutdown == true) return;
// SPS는 이제 간단한 작업만 수행
// 장치 연결 및 상태 전송은 별도 태스크(_DeviceManagement.cs)에서 처리
+ // 장치 연결이 별도로 존재할때 1회 수신 후 통신이 전체 먹통되는 증상이 있어 우선 복귀 251215
try
{
- // 여기에 SPS에서 처리해야 할 간단한 작업만 남김
- // 현재는 비어있음 - 필요한 경우 추가
+
+ // ========== 1. 장치 연결 관리 ==========
+ // AGV 연결
+ ConnectSerialPort(PUB.AGV, PUB.setting.Port_AGV, PUB.setting.Baud_AGV,
+ eVarTime.LastConn_AGV, eVarTime.LastConnTry_AGV, eVarTime.LastRecv_AGV);
+
+ // XBee 연결
+ ConnectSerialPort(PUB.XBE, PUB.setting.Port_XBE, PUB.setting.Baud_XBE,
+ eVarTime.LastConn_XBE, eVarTime.LastConnTry_XBE, eVarTime.LastRecv_XBE);
+
+ // BMS 연결
+ if (PUB.BMS.IsOpen == false)
+ {
+ var ts = VAR.TIME.RUN(eVarTime.LastConn_BAT);
+ if (ts.TotalSeconds > 3)
+ {
+ PUB.log.Add($"BMS 연결 시도: {PUB.setting.Port_BAT}");
+ PUB.BMS.PortName = PUB.setting.Port_BAT;
+ if (PUB.BMS.Open())
+ PUB.log.AddI($"BMS 연결 완료({PUB.setting.Port_BAT})");
+
+ VAR.TIME.Update(eVarTime.LastConn_BAT);
+ VAR.TIME.Update(eVarTime.LastConnTry_BAT);
+ }
+ }
+ else if (PUB.BMS.IsValid == false)
+ {
+ var ts = VAR.TIME.RUN(eVarTime.LastConnTry_BAT);
+ if (ts.TotalSeconds > (PUB.setting.interval_bms * 2.5))
+ {
+ this.BeginInvoke(new Action(() => {
+ PUB.log.Add("BMS 자동 연결 해제 (응답 없음)");
+ PUB.BMS.Close();
+ }));
+ VAR.TIME.Set(eVarTime.LastConn_BAT, DateTime.Now.AddSeconds(5));
+ }
+ }
+
+ // ========== 2. XBee 상태 전송 ==========
+ if (PUB.XBE != null && PUB.XBE.IsOpen)
+ {
+ var tsXbe = DateTime.Now - lastXbeStatusSendTime;
+ if (tsXbe.TotalSeconds >= PUB.setting.interval_xbe)
+ {
+ lastXbeStatusSendTime = DateTime.Now;
+ ThreadPool.QueueUserWorkItem(_ =>
+ {
+ try
+ {
+ PUB.XBE.SendStatus();
+ }
+ catch (Exception ex)
+ {
+ PUB.log.AddE($"XBee SendStatus 오류: {ex.Message}");
+ }
+ });
+ }
+ }
+
+ // ========== 3. BMS 쿼리 및 배터리 경고 ==========
+ if (PUB.BMS != null && PUB.BMS.IsOpen)
+ {
+ var tsBms = DateTime.Now - lastBmsQueryTime;
+ if (tsBms.TotalSeconds >= PUB.setting.interval_bms)
+ {
+ lastBmsQueryTime = DateTime.Now;
+ ThreadPool.QueueUserWorkItem(_ =>
+ {
+ try
+ {
+ PUB.BMS.SendQuery();
+ }
+ catch (Exception ex)
+ {
+ PUB.log.AddE($"BMS SendQuery 오류: {ex.Message}");
+ }
+ });
+ }
+
+ // 배터리 경고음
+ try
+ {
+ Update_BatteryWarnSpeak();
+ }
+ catch (Exception ex)
+ {
+ PUB.log.AddE($"BatteryWarnSpeak 오류: {ex.Message}");
+ }
+
+ }
}
catch (Exception ex)
{
PUB.log.AddE($"sm_SPS Exception: {ex.Message}");
}
}
+
+ ///
+ /// 시리얼 포트 연결 (arDev.arRS232)
+ ///
+ bool ConnectSerialPort(arDev.arRS232 dev, string port, int baud, eVarTime conn, eVarTime conntry, eVarTime recvtime)
+ {
+ if (port.isEmpty()) return false;
+
+ if (dev.IsOpen == false && port.isEmpty() == false)
+ {
+ var tsPLC = VAR.TIME.RUN(conntry);
+ if (tsPLC.TotalSeconds > 5)
+ {
+ VAR.TIME.Update(conntry);
+ try
+ {
+ VAR.TIME.Update(recvtime);
+ dev.PortName = port;
+ dev.BaudRate = baud;
+ PUB.log.Add($"Connect to {port}:{baud}");
+ if (dev.Open())
+ {
+ PUB.log.Add(port, $"[AGV:{port}:{baud}] 연결 완료");
+ }
+ else
+ {
+ //존재하지 않는 포트라면 sync를 벗어난다
+ var ports = System.IO.Ports.SerialPort.GetPortNames().Select(t => t.ToLower()).ToList();
+ if (ports.Contains(PUB.setting.Port_AGV.ToLower()) == false)
+ {
+ return false;
+ }
+ else
+ {
+ var errmessage = dev.errorMessage;
+ PUB.log.AddE($"[AGV:{port}:{baud}] {errmessage}");
+ }
+ }
+ VAR.TIME.Update(conn);
+ VAR.TIME.Update(conntry);
+ }
+ catch (Exception ex)
+ {
+ PUB.log.AddE(ex.Message);
+ }
+ }
+ }
+ else if (dev.PortName.Equals(port) == false)
+ {
+ this.BeginInvoke(new Action(() => {
+ PUB.log.Add(port, $"포트 변경({dev.PortName}->{port})으로 연결 종료");
+ dev.Close();
+ }));
+
+ VAR.TIME.Update(conntry);
+ }
+ else if (dev.IsOpen)
+ {
+ //연결은 되었으나 통신이 지난지 10초가 지났다면 자동종료한다
+ var tsRecv = VAR.TIME.RUN(recvtime);
+ var tsConn = VAR.TIME.RUN(conntry);
+ if (tsRecv.TotalSeconds > 10 && tsConn.TotalSeconds > 5)
+ {
+ this.BeginInvoke(new Action(() => {
+ PUB.log.Add($"{port} 자동 연결 해제 (응답 없음)");
+ dev.Close();
+ }));
+ VAR.TIME.Set(conntry, DateTime.Now);
+ }
+ }
+ return true;
+ }
+
+ ///
+ /// 시리얼 포트 연결 (Device.Xbee)
+ ///
+ void ConnectSerialPort(Device.Xbee dev, string port, int baud, eVarTime conn, eVarTime conntry, eVarTime recvtime)
+ {
+ if (dev.IsOpen == false && port.isEmpty() == false)
+ {
+ var tsPLC = VAR.TIME.RUN(conntry);
+ if (tsPLC.TotalSeconds > 5)
+ {
+ VAR.TIME.Update(conntry);
+ try
+ {
+ VAR.TIME.Update(recvtime);
+ dev.PortName = port;
+ dev.BaudRate = baud;
+ if (dev.Open())
+ {
+ PUB.log.Add(port, $"[XBEE:{port}:{baud}] 연결 완료");
+ }
+ else
+ {
+ var errmessage = dev.errorMessage;
+ PUB.log.AddE($"[XBEE:{port}:{baud}] {errmessage}");
+ }
+ VAR.TIME.Update(conn);
+ VAR.TIME.Update(conntry);
+ }
+ catch (Exception ex)
+ {
+ PUB.log.AddE(ex.Message);
+ }
+ }
+ }
+ else if (dev.PortName.Equals(port) == false)
+ {
+ this.BeginInvoke(new Action(() => {
+ PUB.log.Add(port, $"포트 변경({dev.PortName}->{port})으로 연결 종료");
+ dev.Close();
+ }));
+ VAR.TIME[(int)conntry] = DateTime.Now;
+ }
+ }
+
}
}
diff --git a/Cs_HMI/Project/StateMachine/_Xbee.cs b/Cs_HMI/Project/StateMachine/_Xbee.cs
index a60030a..7c2a75c 100644
--- a/Cs_HMI/Project/StateMachine/_Xbee.cs
+++ b/Cs_HMI/Project/StateMachine/_Xbee.cs
@@ -48,20 +48,24 @@ namespace Project
if (data.Length > 4)
{
var currTag = System.Text.Encoding.Default.GetString(data, 1, data.Length - 1);
- var node = PUB._mapCanvas.Nodes.FirstOrDefault(t => t.RfidId == currTag);
- if (node == null)
+ if (ushort.TryParse(currTag, out ushort currtagValue))
{
- PUB.log.AddE($"[{logPrefix}-SetCurrent] 노드정보를 찾을 수 없습니다 RFID:{currTag}");
- PUB.XBE.SendError(ENIGProtocol.AGVErrorCode.EmptyNode, $"{currTag}");
- return;
- }
- else
- {
- PUB.log.AddI($"XBEE:현재위치설정:[{node.RfidId}]{node.Id}");
- }
+ var node = PUB._mapCanvas.Nodes.FirstOrDefault(t => t.RfidId == currtagValue);
+ if (node == null)
+ {
+ PUB.log.AddE($"[{logPrefix}-SetCurrent] 노드정보를 찾을 수 없습니다 RFID:{currTag}");
+ PUB.XBE.SendError(ENIGProtocol.AGVErrorCode.EmptyNode, $"{currTag}");
+ return;
+ }
+ else
+ {
+ PUB.log.AddI($"XBEE:현재위치설정:[{node.RfidId}]{node.Id}");
+ }
- PUB._mapCanvas.SetAGVPosition(PUB.setting.MCID, node, PUB._virtualAGV.CurrentDirection);
- PUB._virtualAGV.SetPosition(node, PUB._virtualAGV.CurrentDirection);
+ PUB._mapCanvas.SetAGVPosition(PUB.setting.MCID, node, PUB._virtualAGV.CurrentDirection);
+ PUB._virtualAGV.SetPosition(node, PUB._virtualAGV.CurrentDirection);
+ }
+ else PUB.log.AddE($"[{logPrefix}-SetCurrent] TagString Value Errorr:{data}");
}
else PUB.log.AddE($"[{logPrefix}-SetCurrent] TagString Lenght Errorr:{data.Length}");
break;
@@ -111,58 +115,61 @@ namespace Project
if (data.Length > 4)
{
var currTag = System.Text.Encoding.Default.GetString(data, 1, data.Length - 1);
- var targetNode = PUB._mapCanvas.Nodes.FirstOrDefault(t => t.RfidId == currTag);
-
-
- //자동상태가아니라면 처리하지 않는다.
- if (VAR.BOOL[eVarBool.FLAG_AUTORUN] == false)
+ if(ushort.TryParse(currTag, out ushort currtagvalue))
{
- PUB.log.AddE($"[{logPrefix}-Goto] 자동실행상태가 아닙니다");
- PUB.XBE.SendError(ENIGProtocol.AGVErrorCode.ManualMode, $"{currTag}");
- }
+ var targetNode = PUB._mapCanvas.Nodes.FirstOrDefault(t => t.RfidId == currtagvalue);
- //목적지
- PUB._virtualAGV.TargetNode = targetNode;
- if (targetNode == null)
- {
- PUB.log.AddE($"[{logPrefix}-Goto] 노드정보를 찾을 수 없습니다 RFID:{currTag}");
- PUB.XBE.SendError(ENIGProtocol.AGVErrorCode.EmptyNode, $"{currTag}");
- return;
- }
- ///출발지
- var startNode = PUB._mapCanvas.Nodes.FirstOrDefault(t => t.RfidId == PUB._virtualAGV.CurrentNode.Id);
- PUB._virtualAGV.StartNode = startNode;
- if (startNode == null)
- {
- PUB.log.AddE($"[{logPrefix}-Goto] 시작노드가 없습니다(현재위치 없음) NodeID:{PUB._virtualAGV.CurrentNode.Id}");
- }
-
- if (startNode != null)
- {
- //시작위치가 존재한다면 경로를 예측한다.
- var rltGoto = CalcPath(startNode, targetNode);
- if (rltGoto.result == null)
+ //자동상태가아니라면 처리하지 않는다.
+ if (VAR.BOOL[eVarBool.FLAG_AUTORUN] == false)
{
- PUB.log.AddE($"[{logPrefix}-Goto] 경로예측실패 {rltGoto.message}");
+ PUB.log.AddE($"[{logPrefix}-Goto] 자동실행상태가 아닙니다");
+ PUB.XBE.SendError(ENIGProtocol.AGVErrorCode.ManualMode, $"{currTag}");
}
- else
+
+ //목적지
+ PUB._virtualAGV.TargetNode = targetNode;
+ if (targetNode == null)
{
- //경로예측을 화면에 표시해준다.
- PUB._virtualAGV.SetPath(rltGoto.result);
- var pathWithRfid = rltGoto.result.GetSimplePath().Select(nodeId => PUB._virtualAGV.GetRfidByNodeId(PUB._mapCanvas.Nodes, nodeId)).ToList();
- PUB.log.Add($"경로예측결과:{pathWithRfid}");
+ PUB.log.AddE($"[{logPrefix}-Goto] 노드정보를 찾을 수 없습니다 RFID:{currTag}");
+ PUB.XBE.SendError(ENIGProtocol.AGVErrorCode.EmptyNode, $"{currTag}");
+ return;
}
+
+ ///출발지
+ var startNode = PUB._mapCanvas.Nodes.FirstOrDefault(t => t.RfidId == PUB._virtualAGV.CurrentNode.RfidId);
+ PUB._virtualAGV.StartNode = startNode;
+ if (startNode == null)
+ {
+ PUB.log.AddE($"[{logPrefix}-Goto] 시작노드가 없습니다(현재위치 없음) NodeID:{PUB._virtualAGV.CurrentNode.Id}");
+ }
+
+ if (startNode != null)
+ {
+ //시작위치가 존재한다면 경로를 예측한다.
+ var rltGoto = CalcPath(startNode, targetNode);
+ if (rltGoto.result == null)
+ {
+ PUB.log.AddE($"[{logPrefix}-Goto] 경로예측실패 {rltGoto.message}");
+ }
+ else
+ {
+ //경로예측을 화면에 표시해준다.
+ PUB._virtualAGV.SetPath(rltGoto.result);
+ var pathWithRfid = rltGoto.result.GetSimplePath().Select(nodeId => PUB._virtualAGV.GetRfidByNodeId(PUB._mapCanvas.Nodes, nodeId)).ToList();
+ PUB.log.Add($"경로예측결과:{pathWithRfid}");
+ }
+ }
+
+ //대상이동으로 처리한다.
+ PUB.sm.SetNewRunStep(StateMachine.ERunStep.GOTO);
+
+ //Move to
+ PUB.log.Add($"[{logPrefix}-Goto] {startNode.RfidId} -> {targetNode.RfidId}");
}
-
- //대상이동으로 처리한다.
- PUB.sm.SetNewRunStep(StateMachine.ERunStep.GOTO);
-
- //Move to
- PUB.log.Add($"[{logPrefix}-Goto] {startNode.RfidId} -> {targetNode.RfidId}");
-
+ else PUB.log.AddE($"[{logPrefix}-Goto] TagString Value Error:{data}");
}
- else PUB.log.AddE($"[{logPrefix}-Goto] TagString Lenght Errorr:{data.Length}");
+ else PUB.log.AddE($"[{logPrefix}-Goto] TagString Lenght Error:{data.Length}");
break;
case ENIGProtocol.AGVCommandHE.Stop: //stop
diff --git a/Cs_HMI/Project/ViewForm/fAgv.Designer.cs b/Cs_HMI/Project/ViewForm/fAgv.Designer.cs
index cb33828..a53c9e5 100644
--- a/Cs_HMI/Project/ViewForm/fAgv.Designer.cs
+++ b/Cs_HMI/Project/ViewForm/fAgv.Designer.cs
@@ -48,13 +48,14 @@
this.button4 = new System.Windows.Forms.Button();
this.button9 = new System.Windows.Forms.Button();
this.panel2 = new System.Windows.Forms.Panel();
- this.button16 = new System.Windows.Forms.Button();
- this.button10 = new System.Windows.Forms.Button();
+ this.button15 = new System.Windows.Forms.Button();
+ this.button14 = new System.Windows.Forms.Button();
this.button11 = new System.Windows.Forms.Button();
this.button12 = new System.Windows.Forms.Button();
this.button13 = new System.Windows.Forms.Button();
- this.button14 = new System.Windows.Forms.Button();
- this.button15 = new System.Windows.Forms.Button();
+ this.button10 = new System.Windows.Forms.Button();
+ this.button16 = new System.Windows.Forms.Button();
+ this.lbPortName = new System.Windows.Forms.Label();
this.tableLayoutPanel1.SuspendLayout();
this.panel1.SuspendLayout();
this.panel2.SuspendLayout();
@@ -269,6 +270,7 @@
//
// panel2
//
+ this.panel2.Controls.Add(this.lbPortName);
this.panel2.Controls.Add(this.button15);
this.panel2.Controls.Add(this.button14);
this.panel2.Controls.Add(this.button11);
@@ -283,27 +285,27 @@
this.panel2.Size = new System.Drawing.Size(1050, 58);
this.panel2.TabIndex = 8;
//
- // button16
+ // button15
//
- this.button16.Dock = System.Windows.Forms.DockStyle.Left;
- this.button16.Location = new System.Drawing.Point(0, 0);
- this.button16.Name = "button16";
- this.button16.Size = new System.Drawing.Size(162, 58);
- this.button16.TabIndex = 0;
- this.button16.Text = "백턴유지시간";
- this.button16.UseVisualStyleBackColor = true;
- this.button16.Click += new System.EventHandler(this.button16_Click);
+ this.button15.Dock = System.Windows.Forms.DockStyle.Left;
+ this.button15.Location = new System.Drawing.Point(523, 0);
+ this.button15.Name = "button15";
+ this.button15.Size = new System.Drawing.Size(84, 58);
+ this.button15.TabIndex = 14;
+ this.button15.Text = "Mag Off";
+ this.button15.UseVisualStyleBackColor = true;
+ this.button15.Click += new System.EventHandler(this.button15_Click);
//
- // button10
+ // button14
//
- this.button10.Dock = System.Windows.Forms.DockStyle.Left;
- this.button10.Location = new System.Drawing.Point(162, 0);
- this.button10.Name = "button10";
- this.button10.Size = new System.Drawing.Size(162, 58);
- this.button10.TabIndex = 1;
- this.button10.Text = "GateOut Off Time";
- this.button10.UseVisualStyleBackColor = true;
- this.button10.Click += new System.EventHandler(this.button10_Click);
+ this.button14.Dock = System.Windows.Forms.DockStyle.Left;
+ this.button14.Location = new System.Drawing.Point(439, 0);
+ this.button14.Name = "button14";
+ this.button14.Size = new System.Drawing.Size(84, 58);
+ this.button14.TabIndex = 13;
+ this.button14.Text = "Mag On";
+ this.button14.UseVisualStyleBackColor = true;
+ this.button14.Click += new System.EventHandler(this.button14_Click);
//
// button11
//
@@ -338,27 +340,39 @@
this.button13.UseVisualStyleBackColor = true;
this.button13.Click += new System.EventHandler(this.button13_Click);
//
- // button14
+ // button10
//
- this.button14.Dock = System.Windows.Forms.DockStyle.Left;
- this.button14.Location = new System.Drawing.Point(439, 0);
- this.button14.Name = "button14";
- this.button14.Size = new System.Drawing.Size(84, 58);
- this.button14.TabIndex = 13;
- this.button14.Text = "Mag On";
- this.button14.UseVisualStyleBackColor = true;
- this.button14.Click += new System.EventHandler(this.button14_Click);
+ this.button10.Dock = System.Windows.Forms.DockStyle.Left;
+ this.button10.Location = new System.Drawing.Point(162, 0);
+ this.button10.Name = "button10";
+ this.button10.Size = new System.Drawing.Size(162, 58);
+ this.button10.TabIndex = 1;
+ this.button10.Text = "GateOut Off Time";
+ this.button10.UseVisualStyleBackColor = true;
+ this.button10.Click += new System.EventHandler(this.button10_Click);
//
- // button15
+ // button16
//
- this.button15.Dock = System.Windows.Forms.DockStyle.Left;
- this.button15.Location = new System.Drawing.Point(523, 0);
- this.button15.Name = "button15";
- this.button15.Size = new System.Drawing.Size(84, 58);
- this.button15.TabIndex = 14;
- this.button15.Text = "Mag Off";
- this.button15.UseVisualStyleBackColor = true;
- this.button15.Click += new System.EventHandler(this.button15_Click);
+ this.button16.Dock = System.Windows.Forms.DockStyle.Left;
+ this.button16.Location = new System.Drawing.Point(0, 0);
+ this.button16.Name = "button16";
+ this.button16.Size = new System.Drawing.Size(162, 58);
+ this.button16.TabIndex = 0;
+ this.button16.Text = "백턴유지시간";
+ this.button16.UseVisualStyleBackColor = true;
+ this.button16.Click += new System.EventHandler(this.button16_Click);
+ //
+ // lbPortName
+ //
+ this.lbPortName.Dock = System.Windows.Forms.DockStyle.Fill;
+ this.lbPortName.Font = new System.Drawing.Font("Tahoma", 15F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(129)));
+ this.lbPortName.ForeColor = System.Drawing.Color.White;
+ this.lbPortName.Location = new System.Drawing.Point(607, 0);
+ this.lbPortName.Name = "lbPortName";
+ this.lbPortName.Size = new System.Drawing.Size(203, 58);
+ this.lbPortName.TabIndex = 15;
+ this.lbPortName.Text = "--";
+ this.lbPortName.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
//
// fAgv
//
@@ -409,5 +423,6 @@
private System.Windows.Forms.Button button11;
private System.Windows.Forms.Button button12;
private System.Windows.Forms.Button button13;
+ private System.Windows.Forms.Label lbPortName;
}
}
\ No newline at end of file
diff --git a/Cs_HMI/Project/ViewForm/fAgv.cs b/Cs_HMI/Project/ViewForm/fAgv.cs
index 2ee59b6..b0f4888 100644
--- a/Cs_HMI/Project/ViewForm/fAgv.cs
+++ b/Cs_HMI/Project/ViewForm/fAgv.cs
@@ -42,7 +42,7 @@ namespace Project.ViewForm
richTextBox2.Rtf = PUB.AGV.system1.ToRtfString();
richTextBox3.Rtf = CombineRtfStrings(PUB.AGV.signal.ToRtfString(), PUB.AGV.data.ToRtfString());
richTextBox4.Rtf = PUB.AGV.error.ToRtfString();
-
+ lbPortName.Text = $"AGV:{PUB.setting.Port_AGV}\nBMS:{PUB.setting.Port_BAT}";
timer1.Start();
}
diff --git a/Cs_HMI/Project/ViewForm/fAuto.cs b/Cs_HMI/Project/ViewForm/fAuto.cs
index 54b7d0d..4e9d3c9 100644
--- a/Cs_HMI/Project/ViewForm/fAuto.cs
+++ b/Cs_HMI/Project/ViewForm/fAuto.cs
@@ -30,28 +30,11 @@ namespace Project.ViewForm
InitializeMapCanvas();
- //PUB.mapctl = new AGVControl.MapControl();
- //PUB.mapctl.Dock = DockStyle.Fill;
- //PUB.mapctl.Visible = true;
- //PUB.mapctl.Font = this.panel1.Font;
- //PUB.mapctl.BackColor = Color.FromArgb(32, 32, 32);
- //this.panel1.Controls.Add(PUB.mapctl);
}
private void InitializeMapCanvas()
{
- // RfidMappings 제거 - MapNode에 통합됨
-
- // 이벤트 연결
- //PUB._mapCanvas.NodeAdded += OnNodeAdded;
- // 이벤트 연결
- //PUB._mapCanvas.NodeAdded += OnNodeAdded;
- PUB._mapCanvas.NodeSelect += OnNodeSelected;
- //PUB._mapCanvas.NodeMoved += OnNodeMoved;
- //PUB._mapCanvas.NodeDeleted += OnNodeDeleted;
- //PUB._mapCanvas.ConnectionDeleted += OnConnectionDeleted;
- //PUB._mapCanvas.ImageNodeDoubleClicked += OnImageNodeDoubleClicked;
- //PUB._mapCanvas.MapChanged += OnMapChanged;
+ PUB._mapCanvas.NodeSelect += OnNodeSelected;;
// 스플리터 패널에 맵 캔버스 추가
panel1.Controls.Add(PUB._mapCanvas);
@@ -153,84 +136,7 @@ namespace Project.ViewForm
PUB.AGV.DataReceive += AGV_DataReceive;
- //auto load
- var mapPath = new System.IO.DirectoryInfo("route");
- if (mapPath.Exists == false) mapPath.Create();
-
-
- //맵파일로딩
- if (PUB.setting.LastMapFile.isEmpty()) PUB.setting.LastMapFile = System.IO.Path.Combine(mapPath.FullName, "default.json");
- System.IO.FileInfo filePath = new System.IO.FileInfo(PUB.setting.LastMapFile);
- if (filePath.Exists == false) filePath = new System.IO.FileInfo(System.IO.Path.Combine(mapPath.FullName, "default.json"));
- if (filePath.Exists == false) //그래도없다면 맵폴더에서 파일을 찾아본다.
- {
- var files = mapPath.GetFiles("*.json");
- if (files.Any()) filePath = files[0];
- }
-
- if (filePath.Exists)
- {
- var result = MapLoader.LoadMapFromFile(filePath.FullName);
-
- if (result.Success)
- {
- if (PUB._mapCanvas.Nodes == null) PUB._mapCanvas.Nodes = new List();
- else PUB._mapCanvas.Nodes.Clear();
- PUB._mapCanvas.Nodes.AddRange(result.Nodes);
-
- // 맵 캔버스에 데이터 설정
- PUB._mapCanvas.Nodes = PUB._mapCanvas.Nodes;
- PUB._mapCanvas.MapFileName = filePath.FullName;
-
- // 🔥 맵 설정 적용 (배경색, 그리드 표시)
- if (result.Settings != null)
- {
- PUB._mapCanvas.BackColor = System.Drawing.Color.FromArgb(result.Settings.BackgroundColorArgb);
- PUB._mapCanvas.ShowGrid = result.Settings.ShowGrid;
- }
-
- // 🔥 가상 AGV 초기화 (첫 노드 위치에 생성)
- if (PUB._virtualAGV == null && PUB._mapCanvas.Nodes.Count > 0)
- {
- var startNode = PUB._mapCanvas.Nodes.FirstOrDefault(n => n.IsNavigationNode());
- if (startNode != null)
- {
- PUB._virtualAGV = new VirtualAGV(PUB.setting.MCID, startNode.Position, AgvDirection.Forward);
- PUB._virtualAGV.LowBatteryThreshold = PUB.setting.BatteryLimit_Low;
- PUB._virtualAGV.SetPosition(startNode, AgvDirection.Forward);
-
- // 캔버스에 AGV 리스트 설정
- var agvList = new System.Collections.Generic.List { PUB._virtualAGV };
- PUB._mapCanvas.AGVList = agvList;
-
- PUB.log.Add($"가상 AGV 생성: {startNode.Id} 위치");
- }
- }
- else if (PUB._virtualAGV != null)
- {
- PUB._virtualAGV.LowBatteryThreshold = PUB.setting.BatteryLimit_Low;
- // 기존 AGV가 있으면 캔버스에 다시 연결
- var agvList = new System.Collections.Generic.List { PUB._virtualAGV };
- PUB._mapCanvas.AGVList = agvList;
- }
-
- // 맵 로드 후 자동으로 맵에 맞춤
- PUB._mapCanvas.FitToNodes();
-
- PUB.log.Add($"맵 파일 로드 완료: {filePath.Name}, 노드 수: {result.Nodes.Count}");
- }
- else
- {
- PUB.log.Add($"맵 파일 로딩 실패: {result.ErrorMessage}");
- MessageBox.Show($"맵 파일 로딩 실패: {result.ErrorMessage}", "오류",
- MessageBoxButtons.OK, MessageBoxIcon.Error);
- }
- }
- else
- {
- PUB.log.Add($"맵 파일을 찾을 수 없습니다: {filePath.FullName}");
- }
-
+
//var fn = string.Empty;
//if (files.Any() == false)
//{
diff --git a/Cs_HMI/Project/fMain.cs b/Cs_HMI/Project/fMain.cs
index 1a26117..62b90eb 100644
--- a/Cs_HMI/Project/fMain.cs
+++ b/Cs_HMI/Project/fMain.cs
@@ -33,7 +33,6 @@ namespace Project
bool remoteClose = false;
bool forceClose = false;
- readonly usbdetect.DriveDetector usbdet;
public fMain()
{
InitializeComponent();
@@ -57,19 +56,13 @@ namespace Project
if (DateTime.Now > PUB.LastInputTime) PUB.LastInputTime = DateTime.Now;
};
- usbdet = new usbdetect.DriveDetector(this);
- usbdet.DeviceArrived += Usbdet_DeviceArrived;
- usbdet.DeviceRemoved += Usbdet_DeviceRemoved;
-
-
+
PUB._mapCanvas = new AGVNavigationCore.Controls.UnifiedAGVCanvas();
PUB._mapCanvas.Dock = DockStyle.Fill;
PUB._mapCanvas.ShowGrid = false;
PUB._mapCanvas.BackColor = Color.FromArgb(32, 32, 32);
PUB._mapCanvas.ForeColor = Color.White;
-
-
this.panTopMenu.MouseMove += LbTitle_MouseMove;
this.panTopMenu.MouseUp += LbTitle_MouseUp;
this.panTopMenu.MouseDown += LbTitle_MouseDown;
@@ -82,33 +75,7 @@ namespace Project
}
- protected override void WndProc(ref Message m)
- {
- base.WndProc(ref m);
- if (usbdet != null)
- {
- usbdet.WndProc(ref m);
- }
- }
-
- private void Usbdet_DeviceRemoved(object sender, usbdetect.DriveDetectorEventArgs e)
- {
- //throw new NotImplementedException();
- Console.WriteLine(e.Drive);
- }
-
- private void Usbdet_DeviceArrived(object sender, usbdetect.DriveDetectorEventArgs e)
- {
- //throw new NotImplementedException();
- using (var fUpdate = new Dialog.fUpdateForm(e.Drive))
- if (fUpdate.ShowDialog() == DialogResult.Yes)
- {
- //종료한다
- remoteClose = true;
- this.Close();
- }
- }
-
+
private void __Closing(object sender, FormClosingEventArgs e)
{
// 장치 관리 태스크는 _STEP_CLOSING_START에서 종료됨
@@ -182,6 +149,9 @@ namespace Project
VAR.STR[eVarString.SWVersion] = Application.ProductVersion;
+
+ AutoLoadMapData();
+
//SETTING H/W
this.IOState.ItemClick += gridView2_ItemClick;
VAR.BOOL.PropertyChanged += BOOL_PropertyChanged;
@@ -280,7 +250,7 @@ namespace Project
//수량표시
PUB.counter.PropertyChanged += (s1, e1) => Update_Count();
Update_Count();
-
+
PUB.log.Add("프로그램 실행 기록 추가");
PUB.CheckNRegister3(Application.ProductName, "chi", Application.ProductVersion);
@@ -290,6 +260,71 @@ namespace Project
PUB.AddEEDB("프로그램 시작");
}
+ void AutoLoadMapData()
+ {
+ //auto load
+ var mapPath = new System.IO.DirectoryInfo("route");
+ if (mapPath.Exists == false) mapPath.Create();
+
+ //맵파일로딩
+ if (PUB.setting.LastMapFile.isEmpty()) PUB.setting.LastMapFile = System.IO.Path.Combine(mapPath.FullName, "default.json");
+ System.IO.FileInfo filePath = new System.IO.FileInfo(PUB.setting.LastMapFile);
+ if (filePath.Exists == false) filePath = new System.IO.FileInfo(System.IO.Path.Combine(mapPath.FullName, "default.json"));
+ if (filePath.Exists == false) //그래도없다면 맵폴더에서 파일을 찾아본다.
+ {
+ var files = mapPath.GetFiles("*.json");
+ if (files.Any()) filePath = files[0];
+ }
+
+ if (filePath.Exists)
+ {
+ var result = MapLoader.LoadMapFromFile(filePath.FullName);
+
+ if (result.Success)
+ {
+ PUB._mapCanvas.SetMapLoadResult(result);
+ PUB._mapCanvas.MapFileName = filePath.FullName;
+
+ // 🔥 가상 AGV 초기화 (첫 노드 위치에 생성)
+ if (PUB._virtualAGV == null && PUB._mapCanvas.Nodes.Count > 0)
+ {
+ var startNode = PUB._mapCanvas.Nodes.FirstOrDefault(n => n.IsNavigationNode());
+ if (startNode != null)
+ {
+ PUB._virtualAGV = new VirtualAGV(PUB.setting.MCID, startNode.Position, AgvDirection.Forward);
+ PUB._virtualAGV.LowBatteryThreshold = PUB.setting.BatteryLimit_Low;
+ PUB._virtualAGV.SetPosition(startNode, AgvDirection.Forward);
+
+ // 캔버스에 AGV 리스트 설정
+ var agvList = new System.Collections.Generic.List { PUB._virtualAGV };
+ PUB._mapCanvas.AGVList = agvList;
+
+ PUB.log.Add($"가상 AGV 생성: {startNode.Id} 위치");
+ }
+ }
+ else if (PUB._virtualAGV != null)
+ {
+ PUB._virtualAGV.LowBatteryThreshold = PUB.setting.BatteryLimit_Low;
+ // 기존 AGV가 있으면 캔버스에 다시 연결
+ var agvList = new System.Collections.Generic.List { PUB._virtualAGV };
+ PUB._mapCanvas.AGVList = agvList;
+ }
+ PUB.log.Add($"맵 파일 로드 완료: {filePath.Name}, 노드 수: {result.Nodes.Count}");
+ }
+ else
+ {
+ PUB.log.Add($"맵 파일 로딩 실패: {result.ErrorMessage}");
+ MessageBox.Show($"맵 파일 로딩 실패: {result.ErrorMessage}", "오류",
+ MessageBoxButtons.OK, MessageBoxIcon.Error);
+ }
+ }
+ else
+ {
+ PUB.log.Add($"맵 파일을 찾을 수 없습니다: {filePath.FullName}");
+ }
+
+ }
+
#region "Mouse Form Move"
private Boolean fMove = false;