This commit is contained in:
backuppc
2025-11-05 14:28:32 +09:00
parent 77a9d40662
commit 1eb59a0127
5 changed files with 253 additions and 229 deletions

View File

@@ -41,13 +41,13 @@ This README provides a comprehensive overview of the `ENIGProtocol` library, mak
public enum DeviceType : byte
{
ACS = 0,
AGV1 = 10,
AGV2 = 11,
BUFFER1 = 20,
BUFFER2 = 21,
BUFFER3 = 22,
BUFFER4 = 23,
BUFFER5 = 24,
AGV1 = 10+1,
AGV2 = 10+2,
BUFFER1 = 20+1,
BUFFER2 = 20+2,
BUFFER3 = 20+3,
BUFFER4 = 20+4,
BUFFER5 = 20+5,
DOOR = 30,
}
```
@@ -82,6 +82,9 @@ public enum DeviceType : byte
- H -> E | Move : cmd(100) : 대상태그까지 이동(자동이동)
- Target[1] = {DeviceType}
- TagID[4] = 0000
- H -> E | Move : cmd(107) : 대상별칭까지 이동(자동이동)
- Target[1] = {DeviceType}
- TagID[4] = 0000
- H -> E | Stop : cmd(101) : 멈춤
- H -> E | Reset : cmd(102) : 오류 소거
- H -> E | Charge On: cmd(103) : 충전실행(충전기 이동 후 자동 충전 진행)

View File

@@ -4,7 +4,10 @@ using System.Text;
namespace ENIGProtocol
{
public enum AGVCommands
/// <summary>
/// host -> eq
/// </summary>
public enum AGVCommandHE : byte
{
Goto = 100,
Stop = 101,
@@ -14,4 +17,22 @@ namespace ENIGProtocol
MarkStop,
LiftControl
}
/// <summary>
/// eq -> host
/// </summary>
public enum AGVCommandEH : byte
{
Error = 1,
Arrived = 2,
ReadRFID = 3,
Status=9,
}
public enum AGVErrorCode : byte
{
PredictFix,
TurnTimeout,
TurnError,
}
}

View File

@@ -1,55 +1,55 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace ENIG
{
// 장비 타입 정의
public enum DeviceType
{
ACS = 0,
AGV1 = 10,
AGV2 = 11,
BUFFER1 = 20,
BUFFER2 = 21,
BUFFER3 = 22,
BUFFER4 = 23,
BUFFER5 = 24,
DOOR = 30,
}
public partial class EEProtocol
{
// 패킷 수신 이벤트 정의
// 데이터 수신 이벤트 정의
public event EventHandler<DataEventArgs> OnDataReceived;
public event EventHandler<MessageEventArgs> OnMessage;
// CRC16 계산을 위한 테이블
private static readonly ushort[] CRC16_TABLE = new ushort[256];
// CRC16 테이블 초기화
public EEProtocol()
{
const ushort polynomial = 0x7979;
for (ushort i = 0; i < CRC16_TABLE.Length; i++)
{
ushort value = 0;
ushort temp = i;
for (byte j = 0; j < 8; j++)
{
if (((value ^ temp) & 0x0001) != 0)
{
value = (ushort)((value >> 1) ^ polynomial);
}
else
{
value >>= 1;
}
temp >>= 1;
}
CRC16_TABLE[i] = value;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace ENIG
{
// 장비 타입 정의
public enum DeviceType
{
ACS = 0,
AGV1 = 10,
AGV2 = 11,
BUFFER1 = 20,
BUFFER2 = 21,
BUFFER3 = 22,
BUFFER4 = 23,
BUFFER5 = 24,
DOOR = 30,
}
public partial class EEProtocol
{
// 패킷 수신 이벤트 정의
// 데이터 수신 이벤트 정의
public event EventHandler<DataEventArgs> OnDataReceived;
public event EventHandler<MessageEventArgs> OnMessage;
// CRC16 계산을 위한 테이블
private static readonly ushort[] CRC16_TABLE = new ushort[256];
// CRC16 테이블 초기화
public EEProtocol()
{
const ushort polynomial = 0x7979;
for (ushort i = 0; i < CRC16_TABLE.Length; i++)
{
ushort value = 0;
ushort temp = i;
for (byte j = 0; j < 8; j++)
{
if (((value ^ temp) & 0x0001) != 0)
{
value = (ushort)((value >> 1) ^ polynomial);
}
else
{
value >>= 1;
}
temp >>= 1;
}
CRC16_TABLE[i] = value;
}
//// CRC 테이블 출력
@@ -62,162 +62,162 @@ namespace ENIG
// }
// Console.Write($"0x{CRC16_TABLE[i]:X4}, ");
//}
//Console.WriteLine();
}
// CRC16 계산 메서드
public ushort CalculateCRC16(byte[] data)
{
ushort crc = 0xFFFF;
for (int i = 0; i < data.Length; i++)
{
byte index = (byte)(crc ^ data[i]);
crc = (ushort)((crc >> 8) ^ CRC16_TABLE[index]);
}
return crc;
}
// 패킷 생성 메서드
public byte[] CreatePacket(byte id, byte command, byte[] data)
{
var packet = new Packet
{
ID = id,
Command = command,
Data = data ?? new byte[0],
Length = (byte)(1 + 1 + (data?.Length ?? 0)) // ID + Command + Data 길이
};
// 패킷 조립
List<byte> packetData = new List<byte>();
packetData.Add(Packet.STX);
packetData.Add(packet.Length);
packetData.Add(packet.ID);
packetData.Add(packet.Command);
if (packet.Data != null)
packetData.AddRange(packet.Data);
// CRC16 계산
packet.CRC16 = CalculateCRC16(packetData.Skip(1).ToArray()); // STX 제외하고 계산
packetData.AddRange(BitConverter.GetBytes(packet.CRC16));
packetData.Add(Packet.ETX);
return packetData.ToArray();
}
//패킷테스트
public void PacketTest(byte[] rawData)
{
var hexstr = string.Join(" ", rawData.Select(t => t.ToString("X2")));
RaiseMessage( $"TestPacket : {hexstr}");
ParsePacket(rawData);
}
//메세지 발생
public void RaiseMessage(string message, bool isError = false)
{
OnMessage?.Invoke(this, new MessageEventArgs { IsError = isError, Message = message });
}
// 패킷 파싱 메서드
public bool ParsePacket(byte[] rawData)
{
try
{
//Console.WriteLine();
}
// CRC16 계산 메서드
public ushort CalculateCRC16(byte[] data)
{
ushort crc = 0xFFFF;
for (int i = 0; i < data.Length; i++)
{
byte index = (byte)(crc ^ data[i]);
crc = (ushort)((crc >> 8) ^ CRC16_TABLE[index]);
}
return crc;
}
// 패킷 생성 메서드
public byte[] CreatePacket(byte id, byte command, byte[] data)
{
var packet = new Packet
{
ID = id,
Command = command,
Data = data ?? new byte[0],
Length = (byte)(1 + 1 + (data?.Length ?? 0)) // ID + Command + Data 길이
};
// 패킷 조립
List<byte> packetData = new List<byte>();
packetData.Add(Packet.STX);
packetData.Add(packet.Length);
packetData.Add(packet.ID);
packetData.Add(packet.Command);
if (packet.Data != null)
packetData.AddRange(packet.Data);
// CRC16 계산
packet.CRC16 = CalculateCRC16(packetData.Skip(1).ToArray()); // STX 제외하고 계산
packetData.AddRange(BitConverter.GetBytes(packet.CRC16));
packetData.Add(Packet.ETX);
return packetData.ToArray();
}
//패킷테스트
public void PacketTest(byte[] rawData)
{
var hexstr = string.Join(" ", rawData.Select(t => t.ToString("X2")));
RaiseMessage( $"TestPacket : {hexstr}");
ParsePacket(rawData);
}
//메세지 발생
public void RaiseMessage(string message, bool isError = false)
{
OnMessage?.Invoke(this, new MessageEventArgs { IsError = isError, Message = message });
}
// 패킷 파싱 메서드
public bool ParsePacket(byte[] rawData)
{
try
{
if (rawData.Length < 7) // 최소 패킷 크기
{
var hexstring = string.Join(" ", rawData.Select(t => t.ToString("X2")));
RaiseMessage($"Too Short Data:{hexstring}");
return false;
}
}
if (rawData[0] != Packet.STX || rawData[rawData.Length - 1] != Packet.ETX)
{
var hexstring = string.Join(" ", rawData.Select(t => t.ToString("X2")));
RaiseMessage($"STX/ETX Error Data:{hexstring}");
return false;
}
byte length = rawData[1];
}
byte length = rawData[1];
if (length + 5 != rawData.Length) // STX + Length + CRC16(2) + ETX = 5
{
var hexstring = string.Join(" ", rawData.Select(t => t.ToString("X2")));
RaiseMessage($"Length Error ({length+5} != {rawData.Length}) Data:{hexstring}");
return false;
}
// CRC16 검증
byte[] dataForCrc = rawData.Skip(1).Take(length + 1).ToArray();
ushort calculatedCrc = CalculateCRC16(dataForCrc);
ushort receivedCrc = BitConverter.ToUInt16(rawData, rawData.Length - 3);
}
// CRC16 검증
byte[] dataForCrc = rawData.Skip(1).Take(length + 1).ToArray();
ushort calculatedCrc = CalculateCRC16(dataForCrc);
ushort receivedCrc = BitConverter.ToUInt16(rawData, rawData.Length - 3);
if (receivedCrc != 0xFFFF && calculatedCrc != receivedCrc) //FF 무시
{
RaiseMessage($"CRC Error ID:{rawData[2]:X2},CMD:{rawData[3]:X2}", true);
return false;
}
// 패킷 생성
var packet = new Packet
{
Length = length,
ID = rawData[2],
Command = rawData[3],
Data = rawData.Skip(4).Take(length - 2).ToArray(), // ID와 Command 길이(2) 제외
CRC16 = receivedCrc,
RawData = rawData,
};
// 이벤트 발생
OnDataReceived?.Invoke(this, new DataEventArgs { ReceivedPacket = packet });
return true;
}
catch
{
return false;
}
}
// 데이터 수신 처리 메서드 (시리얼 포트에서 데이터를 받았을 때 호출)
private List<byte> buffer = new List<byte>();
public void ProcessReceivedData(byte[] data)
{
buffer.AddRange(data);
while (buffer.Count > 0)
{
// STX 찾기
int stxIndex = buffer.FindIndex(b => b == Packet.STX);
if (stxIndex == -1)
{
buffer.Clear();
break;
}
// 불필요한 데이터 제거
if (stxIndex > 0)
buffer.RemoveRange(0, stxIndex);
// 패킷 길이 확인을 위한 최소 데이터 확인
if (buffer.Count < 2)
break;
int expectedLength = buffer[1] + 5; // 전체 패킷 길이
if (buffer.Count < expectedLength)
break;
// 패킷 추출 및 처리
byte[] packetData = buffer.Take(expectedLength).ToArray();
buffer.RemoveRange(0, expectedLength);
ParsePacket(packetData);
}
}
}
}
// 패킷 생성
var packet = new Packet
{
Length = length,
ID = rawData[2],
Command = rawData[3],
Data = rawData.Skip(4).Take(length - 2).ToArray(), // ID와 Command 길이(2) 제외
CRC16 = receivedCrc,
RawData = rawData,
};
// 이벤트 발생
OnDataReceived?.Invoke(this, new DataEventArgs { ReceivedPacket = packet });
return true;
}
catch
{
return false;
}
}
// 데이터 수신 처리 메서드 (시리얼 포트에서 데이터를 받았을 때 호출)
private List<byte> buffer = new List<byte>();
public void ProcessReceivedData(byte[] data)
{
buffer.AddRange(data);
while (buffer.Count > 0)
{
// STX 찾기
int stxIndex = buffer.FindIndex(b => b == Packet.STX);
if (stxIndex == -1)
{
buffer.Clear();
break;
}
// 불필요한 데이터 제거
if (stxIndex > 0)
buffer.RemoveRange(0, stxIndex);
// 패킷 길이 확인을 위한 최소 데이터 확인
if (buffer.Count < 2)
break;
int expectedLength = buffer[1] + 5; // 전체 패킷 길이
if (buffer.Count < expectedLength)
break;
// 패킷 추출 및 처리
byte[] packetData = buffer.Take(expectedLength).ToArray();
buffer.RemoveRange(0, expectedLength);
ParsePacket(packetData);
}
}
}
}

View File

@@ -1,18 +1,18 @@
using System;
namespace ENIG
{
public partial class EEProtocol
{
using System;
namespace ENIG
{
public partial class EEProtocol
{
public class MessageEventArgs : EventArgs
{
public string Message { get; set; }
public bool IsError { get; set; }
}
public class DataEventArgs : EventArgs
{
public Packet ReceivedPacket { get; set; }
}
}
}
public class DataEventArgs : EventArgs
{
public Packet ReceivedPacket { get; set; }
}
}
}

View File

@@ -1,20 +1,20 @@
namespace ENIG
namespace ENIG
{
// 패킷 구조체
public class Packet
{
public const byte STX = 0x02;
public const byte ETX = 0x03;
public byte Length { get; set; }
public byte ID { get; set; }
public byte Command { get; set; }
public byte[] Data { get; set; }
public ushort CRC16 { get; set; }
public byte[] RawData { get; set; }
public Packet()
{
Data = new byte[0];
}
}
public class Packet
{
public const byte STX = 0x02;
public const byte ETX = 0x03;
public byte Length { get; set; }
public byte ID { get; set; }
public byte Command { get; set; }
public byte[] Data { get; set; }
public ushort CRC16 { get; set; }
public byte[] RawData { get; set; }
public Packet()
{
Data = new byte[0];
}
}
}