파일정리

This commit is contained in:
ChiKyun Kim
2026-01-29 14:03:17 +09:00
parent 00cc0ef5b7
commit 58ca67150d
440 changed files with 47236 additions and 99165 deletions

View File

@@ -38,14 +38,12 @@
<ApplicationIcon>icons8-robot-80.ico</ApplicationIcon> <ApplicationIcon>icons8-robot-80.ico</ApplicationIcon>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<Reference Include="arCommUtil, Version=25.11.25.2000, Culture=neutral, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\DLL\arCommUtil.dll</HintPath>
</Reference>
<Reference Include="arControl.Net4"> <Reference Include="arControl.Net4">
<HintPath>..\Cs_HMI\DLL\arControl.Net4.dll</HintPath> <HintPath>..\DLL\arControl.Net4.dll</HintPath>
</Reference>
<Reference Include="ArLog.Net4">
<HintPath>..\Cs_HMI\DLL\ArLog.Net4.dll</HintPath>
</Reference>
<Reference Include="ArSetting.Net4">
<HintPath>..\Cs_HMI\DLL\ArSetting.Net4.dll</HintPath>
</Reference> </Reference>
<Reference Include="System" /> <Reference Include="System" />
<Reference Include="System.Core" /> <Reference Include="System.Core" />
@@ -126,15 +124,11 @@
</Compile> </Compile>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\Cs_HMI\AGVLogic\AGVNavigationCore\AGVNavigationCore.csproj"> <ProjectReference Include="..\AGVLogic\AGVNavigationCore\AGVNavigationCore.csproj">
<Project>{c5f7a8b2-8d3e-4a1b-9c6e-7f4d5e2a9b1c}</Project> <Project>{c5f7a8b2-8d3e-4a1b-9c6e-7f4d5e2a9b1c}</Project>
<Name>AGVNavigationCore</Name> <Name>AGVNavigationCore</Name>
</ProjectReference> </ProjectReference>
<ProjectReference Include="..\Cs_HMI\SubProject\CommUtil\arCommUtil.csproj"> <ProjectReference Include="..\AGVLogic\ENIGProtocol\enigprotocol\ENIGProtocol.csproj">
<Project>{14e8c9a5-013e-49ba-b435-ffffff7dd623}</Project>
<Name>arCommUtil</Name>
</ProjectReference>
<ProjectReference Include="..\Cs_HMI\SubProject\EnigProtocol\enigprotocol\ENIGProtocol.csproj">
<Project>{9365803b-933d-4237-93c7-b502c855a71c}</Project> <Project>{9365803b-933d-4237-93c7-b502c855a71c}</Project>
<Name>ENIGProtocol</Name> <Name>ENIGProtocol</Name>
</ProjectReference> </ProjectReference>

View File

@@ -5,11 +5,9 @@ VisualStudioVersion = 17.14.36804.6 d17.14
MinimumVisualStudioVersion = 10.0.40219.1 MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AGVEmulator", "AGVEmulator.csproj", "{9312AB43-72F6-4365-A266-E767215FA7F5}" Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AGVEmulator", "AGVEmulator.csproj", "{9312AB43-72F6-4365-A266-E767215FA7F5}"
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AGVNavigationCore", "..\Cs_HMI\AGVLogic\AGVNavigationCore\AGVNavigationCore.csproj", "{C5F7A8B2-8D3E-4A1B-9C6E-7F4D5E2A9B1C}" Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AGVNavigationCore", "..\AGVLogic\AGVNavigationCore\AGVNavigationCore.csproj", "{C5F7A8B2-8D3E-4A1B-9C6E-7F4D5E2A9B1C}"
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ENIGProtocol", "..\Cs_HMI\SubProject\ENIGProtocol\enigprotocol\ENIGProtocol.csproj", "{9365803B-933D-4237-93C7-B502C855A71C}" Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ENIGProtocol", "..\AGVLogic\ENIGProtocol\enigprotocol\ENIGProtocol.csproj", "{9365803B-933D-4237-93C7-B502C855A71C}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "arCommUtil", "..\Cs_HMI\SubProject\CommUtil\arCommUtil.csproj", "{14E8C9A5-013E-49BA-B435-FFFFFF7DD623}"
EndProject EndProject
Global Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution GlobalSection(SolutionConfigurationPlatforms) = preSolution

View File

@@ -1,5 +1,4 @@
using arCtl; using System;
using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Drawing; using System.Drawing;
using System.Linq; using System.Linq;

View File

@@ -19,7 +19,7 @@ namespace AGVEmulator
{ {
public partial class fMain : Form public partial class fMain : Form
{ {
arUtil.Log logAGV, logBMS, logCAL; AR.Log logAGV, logBMS, logCAL;
DevBMS BMS; DevBMS BMS;
DevAGV AGV; DevAGV AGV;
DevXBE XBE; DevXBE XBE;
@@ -47,9 +47,9 @@ namespace AGVEmulator
InitializeComponent(); InitializeComponent();
this.Text = $"{Application.ProductName} ver.{Application.ProductVersion}"; this.Text = $"{Application.ProductName} ver.{Application.ProductVersion}";
// logPLC = new arUtil.Log(); // logPLC = new arUtil.Log();
logAGV = new arUtil.Log(); logAGV = new AR.Log();
logBMS = new arUtil.Log(); logBMS = new AR.Log();
logCAL = new arUtil.Log(); logCAL = new AR.Log();
// logPLC.FileNameFormat = "{yyyyMMdd}_PLC"; // logPLC.FileNameFormat = "{yyyyMMdd}_PLC";
logAGV.FileNameFormat = "{yyyyMMdd}_AGV"; logAGV.FileNameFormat = "{yyyyMMdd}_AGV";

View File

@@ -1,6 +1,7 @@

Microsoft Visual Studio Solution File, Format Version 12.00 Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Express 15 for Windows Desktop # Visual Studio Version 17
VisualStudioVersion = 15.0.36324.19 VisualStudioVersion = 17.14.36310.24
MinimumVisualStudioVersion = 10.0.40219.1 MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AGVMapEditor", "AGVMapEditor\AGVMapEditor.csproj", "{A1B2C3D4-E5F6-7890-ABCD-EF1234567890}" Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AGVMapEditor", "AGVMapEditor\AGVMapEditor.csproj", "{A1B2C3D4-E5F6-7890-ABCD-EF1234567890}"
EndProject EndProject
@@ -8,6 +9,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AGVNavigationCore", "AGVNav
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AGVSimulator", "AGVSimulator\AGVSimulator.csproj", "{B2C3D4E5-0000-0000-0000-000000000000}" Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AGVSimulator", "AGVSimulator\AGVSimulator.csproj", "{B2C3D4E5-0000-0000-0000-000000000000}"
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ENIGProtocol", "EnigProtocol\enigprotocol\ENIGProtocol.csproj", "{9365803B-933D-4237-93C7-B502C855A71C}"
EndProject
Global Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU Debug|Any CPU = Debug|Any CPU
@@ -26,11 +29,15 @@ Global
{B2C3D4E5-0000-0000-0000-000000000000}.Debug|Any CPU.Build.0 = Debug|Any CPU {B2C3D4E5-0000-0000-0000-000000000000}.Debug|Any CPU.Build.0 = Debug|Any CPU
{B2C3D4E5-0000-0000-0000-000000000000}.Release|Any CPU.ActiveCfg = Release|Any CPU {B2C3D4E5-0000-0000-0000-000000000000}.Release|Any CPU.ActiveCfg = Release|Any CPU
{B2C3D4E5-0000-0000-0000-000000000000}.Release|Any CPU.Build.0 = Release|Any CPU {B2C3D4E5-0000-0000-0000-000000000000}.Release|Any CPU.Build.0 = Release|Any CPU
{9365803B-933D-4237-93C7-B502C855A71C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{9365803B-933D-4237-93C7-B502C855A71C}.Debug|Any CPU.Build.0 = Debug|Any CPU
{9365803B-933D-4237-93C7-B502C855A71C}.Release|Any CPU.ActiveCfg = Release|Any CPU
{9365803B-933D-4237-93C7-B502C855A71C}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection EndGlobalSection
GlobalSection(SolutionProperties) = preSolution GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE HideSolutionNode = FALSE
EndGlobalSection EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {F2C60284-CCB5-450D-BCD0-19C693529FD6} SolutionGuid = {638744DA-A7C8-43E2-A98E-0DE9BDB1DA35}
EndGlobalSection EndGlobalSection
EndGlobal EndGlobal

View File

@@ -17,7 +17,7 @@
<DebugSymbols>true</DebugSymbols> <DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType> <DebugType>full</DebugType>
<Optimize>false</Optimize> <Optimize>false</Optimize>
<OutputPath>..\..\..\..\..\..\Amkor\AGV4\Test\MapEditor\</OutputPath> <OutputPath>bin\debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants> <DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport> <ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel> <WarningLevel>4</WarningLevel>

View File

@@ -17,7 +17,7 @@
<DebugSymbols>true</DebugSymbols> <DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType> <DebugType>full</DebugType>
<Optimize>false</Optimize> <Optimize>false</Optimize>
<OutputPath>..\..\..\..\..\..\Amkor\AGV4\Test\Simulator\</OutputPath> <OutputPath>bin\debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants> <DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport> <ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel> <WarningLevel>4</WarningLevel>

13
AGVLogic/EnigProtocol/.gitignore vendored Normal file
View File

@@ -0,0 +1,13 @@
obj
bin
*.user
*.v12
*.suo
.git
.vs
Debug
__vm
*.pdb
desktop.ini
packages
~*.xlsx

View File

@@ -0,0 +1,53 @@
using Xunit;
using ENIG;
namespace ENIGProtocol.Tests
{
public class EEProtocolTests
{
[Fact]
public void TestCRC16Calculation()
{
// 테스트 데이터
byte[] testData = new byte[] { 0x02,0x00,0xFF }; //payload에는 stx, len, ... crc,etx 는 제외한다
// CRC16 계산
var protocol = new EEProtocol();
ushort crc = protocol.CalculateCRC16(testData);
// 예상 결과와 비교
Assert.Equal(0x1789, crc);
}
[Fact]
public void TestPacketCreation()
{
// 패킷 생성 테스트
var protocol = new EEProtocol();
byte[] packet = protocol.CreatePacket(0x01, 0x02, new byte[] { 0x03, 0x04 });
// 패킷 구조 검증
Assert.Equal(0x02, packet[0]); // STX
Assert.Equal(0x04, packet[1]); // Length
Assert.Equal(0x01, packet[2]); // ID
Assert.Equal(0x02, packet[3]); // Command
Assert.Equal(0x03, packet[4]); // Data[0]
Assert.Equal(0x04, packet[5]); // Data[1]
}
[Fact]
public void TestPacketParsing()
{
// 패킷 파싱 테스트
var protocol = new EEProtocol();
//byte[] testPacket = new byte[] { 0x02, 0x04, 0x01, 0x02, 0x03, 0x04, 0x12, 0x34, 0x03 };
byte[] testPacket = new byte[] { 0x02, 0x02, 0x00, 0xFF, 0x89, 0x17, 0x03 };
bool result = protocol.ParsePacket(testPacket);
Assert.True(result);
}
}
}

View File

@@ -0,0 +1,33 @@
<Project Sdk="Microsoft.NET.Sdk" ToolsVersion="15.0">
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<IsPackable>false</IsPackable>
<IsTestProject>true</IsTestProject>
<TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
<FileUpgradeFlags>
</FileUpgradeFlags>
<UpgradeBackupLocation>
</UpgradeBackupLocation>
<OldToolsVersion>2.0</OldToolsVersion>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.13.0" />
<PackageReference Include="xunit" Version="2.9.3" />
<PackageReference Include="xunit.runner.visualstudio" Version="3.0.2">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
<PackageReference Include="coverlet.collector" Version="6.0.4">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\enigprotocol\enigprotocol.csproj" />
</ItemGroup>
<ItemGroup>
<Using Include="Xunit" />
</ItemGroup>
</Project>

View File

@@ -0,0 +1,10 @@
namespace ENIGProtocol.Tests;
public class UnitTest1
{
[Fact]
public void Test1()
{
}
}

View File

@@ -0,0 +1,43 @@
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Express 15 for Windows Desktop
VisualStudioVersion = 15.0.28307.1000
MinimumVisualStudioVersion = 10.0.40219.1
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "솔루션 항목", "솔루션 항목", "{0A11874A-E5C6-4170-9787-1FFF7AF0D289}"
ProjectSection(SolutionItems) = preProject
.gitignore = .gitignore
ReadMe.MD = ReadMe.MD
EndProjectSection
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SampleProject", "sample\SampleProject.csproj", "{FAB31C8A-7DCF-4152-8A82-76F3C10BABA4}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ENIGProtocol.Tests", "ENIGProtocol.Tests\ENIGProtocol.Tests.csproj", "{3A677629-1F08-49B2-BC75-58282E439FD4}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ENIGProtocol", "enigprotocol\ENIGProtocol.csproj", "{499D8912-4B96-41E5-A70D-CFE797883D65}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{FAB31C8A-7DCF-4152-8A82-76F3C10BABA4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{FAB31C8A-7DCF-4152-8A82-76F3C10BABA4}.Debug|Any CPU.Build.0 = Debug|Any CPU
{FAB31C8A-7DCF-4152-8A82-76F3C10BABA4}.Release|Any CPU.ActiveCfg = Release|Any CPU
{FAB31C8A-7DCF-4152-8A82-76F3C10BABA4}.Release|Any CPU.Build.0 = Release|Any CPU
{3A677629-1F08-49B2-BC75-58282E439FD4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{3A677629-1F08-49B2-BC75-58282E439FD4}.Debug|Any CPU.Build.0 = Debug|Any CPU
{3A677629-1F08-49B2-BC75-58282E439FD4}.Release|Any CPU.ActiveCfg = Release|Any CPU
{3A677629-1F08-49B2-BC75-58282E439FD4}.Release|Any CPU.Build.0 = Release|Any CPU
{499D8912-4B96-41E5-A70D-CFE797883D65}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{499D8912-4B96-41E5-A70D-CFE797883D65}.Debug|Any CPU.Build.0 = Debug|Any CPU
{499D8912-4B96-41E5-A70D-CFE797883D65}.Release|Any CPU.ActiveCfg = Release|Any CPU
{499D8912-4B96-41E5-A70D-CFE797883D65}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {07331835-C46C-4B93-965F-AD2714F97F88}
EndGlobalSection
EndGlobal

View File

@@ -0,0 +1,246 @@
# ENIG Protocol
ENIG 프로토콜 통신 라이브러리
**Explanation of the README Content:**
1. **Title and Overview:** Clearly states the purpose of the library.
2. **Key Components:** Explains the main building blocks:
* `DeviceType` enum: Lists the device types.
* `Packet` class: Describes the packet structure.
* `EEProtocol` class: Explains its role in packet handling.
3. **Key Features:** Details the core functionalities of the `EEProtocol` class:
* Packet creation.
* Packet parsing.
* Data reception.
* Event-driven nature.
* CRC16 calculation.
4. **Usage:** Provides code examples for:
* Creating a packet.
* Parsing a packet.
* Processing received data.
5. **Error Handling:** Explains how the library handles invalid data and incomplete packets.
6. **Dependencies:** Lists any required frameworks or libraries.
7. **License:** Placeholder for the project's license.
This README provides a comprehensive overview of the `ENIGProtocol` library, making it easy for other developers to understand and use it. I hope this is helpful!
## 개발 환경
- Frameworks : .NET Standard 2.0
- Visual Studio 2022 또는 Visual Studio Code
## 프로젝트 구조
- `EEProtocol.cs`: ENIG 프로토콜 구현
- `EEProtocolTests.cs`: 단위 테스트 코드
- `Sample`: C# Winform 샘플 프로젝트
## 장비 목록
```
public enum DeviceType : byte
{
ACS = 0,
AGV1 = 10+1,
AGV2 = 10+2,
BUFFER1 = 20+1,
BUFFER2 = 20+2,
BUFFER3 = 20+3,
BUFFER4 = 20+4,
BUFFER5 = 20+5,
DOOR = 30,
}
```
public enum DeviceAlias : byte
{
B1 = 20 + 1, //BUFFER1 ~ 5
B2 = 20 + 2,
B3 = 20 + 3,
B4 = 20 + 4,
B5 = 20 + 5,
C1 = 40 + 1, //충전소 1
C2 = 40 + 2, //충전소 2
C3 = 40 + 3, //충전소 3
C4 = 40 + 4, //충전소 4
E1 = 90 + 1, //장비1 (SSOTRON Loader)
E2 = 90 + 2, //장비2 (TOPS ENIG)
E3 = 90 + 3, //장비3 (SSOTRON DIVERTER)
}
//11번 AGV야! BUFFER1로 이동해라!
//0x02 0x03 0x0B 0x6B 0x42 0x31 {CRC} 0x03
### 기본 패킷 구조
```
[STX][LEN][ID][CMD][DATA][CRC16][ETX]
```
- **STX (Start of Text)**: 0x02
- **LEN (Length)**: 데이터 길이 (1바이트) = {CMD+DATA}
- **ID (Client ID)**: 데이터 길이 (1바이트) : 디바이스식별코드(=DeviceType)
- **CMD (Command)**: 명령어 코드 (1바이트)
- **DATA**: 명령어에 따른 데이터 (가변 길이)
- **CRC16**: 데이터 무결성 검사 (2바이트)
- **ETX (End of Text)**: 0x03
### 통신 방향 (호스트=ACS, 장비=agv,buffer,door)
- H -> E: 호스트에서 장비로 전송
- E -> H: 장비에서 호스트로 전송
### 명령어 목록
1. **ACS (AGV Control System)**
2. **Buffer**
- E -> H | cmd(3): 상태 (data len=1 : 0=카트없음, 1=카트있음, 2=바쁨, 3=알수없음, 255=오류)
- H -> E | cmd(1): Lock
- Target[1] = {DeviceType}
- H -> E | cmd(2): UnLock
- Target[1] = {DeviceType}
3. **AGV**
- H -> E | Move : cmd(100) : 대상태그까지 이동(자동이동)
- Target[1] = {DeviceType}
- TagID[4] = "0000"
- H -> E | Stop : cmd(101) : 멈춤
- H -> E | Reset : cmd(102) : 오류 소거
- H -> E | SetCurrent : cmd(103) : 현재위치설정
- Target[1] = {DeviceType}
- TagID[4] = "0000"
- H -> E | MoveManual : cmd(104) : 메뉴얼이동
- Target[1] = {DeviceType}
- Direction[1] : 0=Backward, 1=Forward, 2=TurnLeft, 3=TurnRight
- Speed[1] : 0=Slow, 1=Normal, 2=Fast
- H -> E | MarkStop : cmd(105) : 마크센서스톱
- Target[1] = {DeviceType}
- H -> E | Lift Control : cmd(106) : 리프트제어
- Target[1] = {DeviceType}
- Action[1] : 0=STOP, 1=UP, 2=DOWN
- H -> E | Move : cmd(107) : 대상별칭까지 이동(자동이동)
- Target[1] = {DeviceType}
- AliasName[n] = ".....
- H -> E | MoveAuto : cmd(108) : 자동이동
- Target[1] = {DeviceType}
- MotDirection[1] : 0=Backward, 1=Forward
- MagnetDirection[1] : 0=Straight,1=Left, 2=Right
- Speed[1] : 0=Slow, 1=Normal, 2=Fast
- H -> E | Charge On: cmd(109) : 충전실행(충전기 이동 후 자동 충전 진행)
- Target[1] = {DeviceType}
- Action[1] : 0=Charge Off, 1=Charge On
- E -> H | Move Complete : cmd(1) : 목적지이동완료 후 전송
- TagID[4] : "0000"
- E -> H | TagID Received : cmd(2) : 태그값 인식시 전송
- TagID[4] : "0000"
- E -> H | Status : cmd(3)
- Mode[1] : 0=manual, 1=auto
- RunSt[1] : 0=stop, 1=run, 2=error
- Diection[1] : 0=straight, 1=left, 2=right, 3=markstop
- Inposition[1] : 0=off, 1=on : 목적위치에 도달완료 시 설정 이동 이동시 OFF됨
- ChargeSt[1] : 0=off, 1=on
- CartSt[1] : 0=off, 1=on, 2=unknown
- LiftSt[1] : 0=down , 1=up, 2=unknown
- LastTag[4] : "0000"
- CurrentPath[1] : Path ID , 0=미설정, 1~255(순차증가)
4. **Door**
- H -> E | cmd(1): 출입문 열기
- H -> E | cmd(2): 출입문 닫기
- E -> H | cmd(3): 출입문 상태 (data len=1 : 0=닫힘, 1=열림, 2=바쁨, 3=알수없음, 255=오류)
### CRC16 계산
- CRC16 다항식 사용
- 초기값: 0xFFFF
- 데이터 무결성 검증에 사용
#### CRC-16 테이블 값
```
0x0000, 0x408E, 0x73EF, 0x3361, 0x152D, 0x55A3, 0x66C2, 0x264C,
0x2A5A, 0x6AD4, 0x59B5, 0x193B, 0x3F77, 0x7FF9, 0x4C98, 0x0C16,
0x54B4, 0x143A, 0x275B, 0x67D5, 0x4199, 0x0117, 0x3276, 0x72F8,
0x7EEE, 0x3E60, 0x0D01, 0x4D8F, 0x6BC3, 0x2B4D, 0x182C, 0x58A2,
0x5B9B, 0x1B15, 0x2874, 0x68FA, 0x4EB6, 0x0E38, 0x3D59, 0x7DD7,
0x71C1, 0x314F, 0x022E, 0x42A0, 0x64EC, 0x2462, 0x1703, 0x578D,
0x0F2F, 0x4FA1, 0x7CC0, 0x3C4E, 0x1A02, 0x5A8C, 0x69ED, 0x2963,
0x2575, 0x65FB, 0x569A, 0x1614, 0x3058, 0x70D6, 0x43B7, 0x0339,
0x45C5, 0x054B, 0x362A, 0x76A4, 0x50E8, 0x1066, 0x2307, 0x6389,
0x6F9F, 0x2F11, 0x1C70, 0x5CFE, 0x7AB2, 0x3A3C, 0x095D, 0x49D3,
0x1171, 0x51FF, 0x629E, 0x2210, 0x045C, 0x44D2, 0x77B3, 0x373D,
0x3B2B, 0x7BA5, 0x48C4, 0x084A, 0x2E06, 0x6E88, 0x5DE9, 0x1D67,
0x1E5E, 0x5ED0, 0x6DB1, 0x2D3F, 0x0B73, 0x4BFD, 0x789C, 0x3812,
0x3404, 0x748A, 0x47EB, 0x0765, 0x2129, 0x61A7, 0x52C6, 0x1248,
0x4AEA, 0x0A64, 0x3905, 0x798B, 0x5FC7, 0x1F49, 0x2C28, 0x6CA6,
0x60B0, 0x203E, 0x135F, 0x53D1, 0x759D, 0x3513, 0x0672, 0x46FC,
0x7979, 0x39F7, 0x0A96, 0x4A18, 0x6C54, 0x2CDA, 0x1FBB, 0x5F35,
0x5323, 0x13AD, 0x20CC, 0x6042, 0x460E, 0x0680, 0x35E1, 0x756F,
0x2DCD, 0x6D43, 0x5E22, 0x1EAC, 0x38E0, 0x786E, 0x4B0F, 0x0B81,
0x0797, 0x4719, 0x7478, 0x34F6, 0x12BA, 0x5234, 0x6155, 0x21DB,
0x22E2, 0x626C, 0x510D, 0x1183, 0x37CF, 0x7741, 0x4420, 0x04AE,
0x08B8, 0x4836, 0x7B57, 0x3BD9, 0x1D95, 0x5D1B, 0x6E7A, 0x2EF4,
0x7656, 0x36D8, 0x05B9, 0x4537, 0x637B, 0x23F5, 0x1094, 0x501A,
0x5C0C, 0x1C82, 0x2FE3, 0x6F6D, 0x4921, 0x09AF, 0x3ACE, 0x7A40,
0x3CBC, 0x7C32, 0x4F53, 0x0FDD, 0x2991, 0x691F, 0x5A7E, 0x1AF0,
0x16E6, 0x5668, 0x6509, 0x2587, 0x03CB, 0x4345, 0x7024, 0x30AA,
0x6808, 0x2886, 0x1BE7, 0x5B69, 0x7D25, 0x3DAB, 0x0ECA, 0x4E44,
0x4252, 0x02DC, 0x31BD, 0x7133, 0x577F, 0x17F1, 0x2490, 0x641E,
0x6727, 0x27A9, 0x14C8, 0x5446, 0x720A, 0x3284, 0x01E5, 0x416B,
0x4D7D, 0x0DF3, 0x3E92, 0x7E1C, 0x5850, 0x18DE, 0x2BBF, 0x6B31,
0x3393, 0x731D, 0x407C, 0x00F2, 0x26BE, 0x6630, 0x5551, 0x15DF,
0x19C9, 0x5947, 0x6A26, 0x2AA8, 0x0CE4, 0x4C6A, 0x7F0B, 0x3F85,
```
#### CRC16 계산 테이블 생성 코드
```csharp
const ushort polynomial = 0x7979;
ushort[] CRC16_TABLE = new ushort[256];
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;
}
```
#### CRC16 계산 예시
```csharp
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;
}
```
## 라이센스

View File

@@ -0,0 +1,8 @@
################################################################################
# 이 .gitignore 파일은 Microsoft(R) Visual Studio에서 자동으로 만들어졌습니다.
################################################################################
/obj
/bin
/.vs
/.git

View File

@@ -0,0 +1,111 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace ENIGProtocol
{
/// <summary>
/// host -> eq
/// </summary>
public enum AGVCommandHE : byte
{
Goto = 100,
Stop = 101,
Reset = 102,
SetCurrent = 103,
Manual = 104,
MarkStop = 105,
LiftControl = 106,
GotoAlias = 107,
AutoMove = 108,
ChargeControl = 109,
Charger = 112,
LTurn = 113,
RTurn = 114,
LTurn180 = 115,
RTurn180 = 116,
PickOnEnter = 117,
PickOffEnter = 118,
PickOnExit = 119,
PickOffExit = 120,
}
/// <summary>
/// eq -> host
/// </summary>
public enum AGVCommandEH : byte
{
Error = 1,
Arrived = 2,
ReadRFID = 3,
Status = 9,
}
public enum AGVErrorCode : byte
{
None = 0,
PredictFix,
TurnTimeout,
TurnError,
EmptyNode,
Goto,
ManualMode,
UnknownCommand,
UnknownAlias,
// Operational Errors
CART_EXIST,
MARK_TIMEOUT,
MARK_SENSOR_FAIL,
LIFT_ERROR,
AGV_SPEED_SET_FAIL,
AGV_RUN_FAIL,
AGV_STOP_FAIL,
PATH_INTEGRITY_FAIL,
TURN_FAIL,
NO_CHARGEPOINT,
NOTSET_CHARGEPOINT,
ALREADY_CHARGE,
CHARGE_RETRY_OVER,
}
public static class AGVUtility
{
/// <summary>
/// 에러코드에 해당하는 오류메세지를 반환 합니다
/// </summary>
/// <param name="ecode"></param>
/// <returns></returns>
public static string GetAGVErrorMessage(AGVErrorCode ecode)
{
switch (ecode)
{
case AGVErrorCode.None: return "No Error";
case AGVErrorCode.PredictFix: return "이동 예측이 동작하지 않습니다";
case AGVErrorCode.TurnTimeout: return "회전작업 시간초과";
case AGVErrorCode.TurnError: return "회전작업이 완료되지 않았습니다";
case AGVErrorCode.EmptyNode: return "노드정보를 찾을 수 없습니다";
case AGVErrorCode.Goto: return "이동 명령 오류";
case AGVErrorCode.ManualMode: return "자동운전 상태가 아닙니다";
case AGVErrorCode.UnknownCommand: return "알수 없는 명령입니다";
case AGVErrorCode.UnknownAlias: return "알수 없는 별칭 입니다";
case AGVErrorCode.CART_EXIST: return "카트 감지 센서 오류";
case AGVErrorCode.MARK_TIMEOUT: return "마크 정지 신호 시간초과";
case AGVErrorCode.MARK_SENSOR_FAIL: return "마크 센서 미감지";
case AGVErrorCode.LIFT_ERROR: return "리프트 동작 오류";
case AGVErrorCode.AGV_SPEED_SET_FAIL: return "AGV 속도 설정 실패";
case AGVErrorCode.AGV_RUN_FAIL: return "AGV 구동 실패";
case AGVErrorCode.AGV_STOP_FAIL: return "AGV 정지 실패";
case AGVErrorCode.PATH_INTEGRITY_FAIL: return "경로 무결성 검증 실패";
case AGVErrorCode.TURN_FAIL: return "턴 동작 실패";
case AGVErrorCode.NO_CHARGEPOINT: return "충전 위치 아님";
case AGVErrorCode.NOTSET_CHARGEPOINT: return "충전기 노드 미설정";
case AGVErrorCode.ALREADY_CHARGE: return "이미 충전 중 상태임";
case AGVErrorCode.CHARGE_RETRY_OVER: return $"충전명령 재전송 횟수 초과";
default: return ecode.ToString();
}
}
}
}

View File

@@ -0,0 +1,235 @@
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 테이블 출력
//Console.WriteLine("CRC16 테이블 값:");
//for (int i = 0; i < CRC16_TABLE.Length; i++)
//{
// if (i % 8 == 0)
// {
// Console.WriteLine();
// }
// 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
{
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];
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);
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(Exception ex)
{
RaiseMessage(ex.Message, true);
return false;
}
}
// 데이터 수신 처리 메서드 (시리얼 포트에서 데이터를 받았을 때 호출)
private List<byte> buffer = new List<byte>();
private int ProtocolParseError = 0;
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);
var parseOK = ParsePacket(packetData);
if(parseOK==false) //분석이 실패되었다면 해당 데이터는 삭제한다.
{
ProtocolParseError += 1;
if (ProtocolParseError > 3) buffer.Clear();
} else ProtocolParseError = 0;
if(buffer.Any())
{
System.Threading.Thread.Sleep(1);
}
}
}
}
}

View File

@@ -0,0 +1,56 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{9365803B-933D-4237-93C7-B502C855A71C}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>enigprotocol</RootNamespace>
<AssemblyName>enigprotocol</AssemblyName>
<TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<Deterministic>true</Deterministic>
<TargetFrameworkProfile />
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Data" />
<Reference Include="System.Net.Http" />
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="Commands.cs" />
<Compile Include="EEProtocol.cs" />
<Compile Include="EventArgs.cs" />
<Compile Include="Packet.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
<ItemGroup>
<None Include=".gitignore" />
<None Include="ReadMe.MD" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
</Project>

View File

@@ -0,0 +1,18 @@
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; }
}
}
}

View File

@@ -0,0 +1,20 @@
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];
}
}
}

View File

@@ -5,11 +5,11 @@ using System.Runtime.InteropServices;
// 어셈블리에 대한 일반 정보는 다음 특성 집합을 통해 // 어셈블리에 대한 일반 정보는 다음 특성 집합을 통해
// 제어됩니다. 어셈블리와 관련된 정보를 수정하려면 // 제어됩니다. 어셈블리와 관련된 정보를 수정하려면
// 이러한 특성 값을 변경하세요. // 이러한 특성 값을 변경하세요.
[assembly: AssemblyTitle("ClassLibrary1")] [assembly: AssemblyTitle("enigprotocol")]
[assembly: AssemblyDescription("")] [assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")] [assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")] [assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("ClassLibrary1")] [assembly: AssemblyProduct("enigprotocol")]
[assembly: AssemblyCopyright("Copyright © 2025")] [assembly: AssemblyCopyright("Copyright © 2025")]
[assembly: AssemblyTrademark("")] [assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")] [assembly: AssemblyCulture("")]
@@ -20,7 +20,7 @@ using System.Runtime.InteropServices;
[assembly: ComVisible(false)] [assembly: ComVisible(false)]
// 이 프로젝트가 COM에 노출되는 경우 다음 GUID는 typelib의 ID를 나타냅니다. // 이 프로젝트가 COM에 노출되는 경우 다음 GUID는 typelib의 ID를 나타냅니다.
[assembly: Guid("19675e19-eb91-493e-88c3-32b3c094b749")] [assembly: Guid("9365803b-933d-4237-93c7-b502c855a71c")]
// 어셈블리의 버전 정보는 다음 네 가지 값으로 구성됩니다. // 어셈블리의 버전 정보는 다음 네 가지 값으로 구성됩니다.
// //

View File

@@ -0,0 +1,236 @@
# ENIG Protocol
ENIG 프로토콜 통신 라이브러리
**Explanation of the README Content:**
1. **Title and Overview:** Clearly states the purpose of the library.
2. **Key Components:** Explains the main building blocks:
* `DeviceType` enum: Lists the device types.
* `Packet` class: Describes the packet structure.
* `EEProtocol` class: Explains its role in packet handling.
3. **Key Features:** Details the core functionalities of the `EEProtocol` class:
* Packet creation.
* Packet parsing.
* Data reception.
* Event-driven nature.
* CRC16 calculation.
4. **Usage:** Provides code examples for:
* Creating a packet.
* Parsing a packet.
* Processing received data.
5. **Error Handling:** Explains how the library handles invalid data and incomplete packets.
6. **Dependencies:** Lists any required frameworks or libraries.
7. **License:** Placeholder for the project's license.
This README provides a comprehensive overview of the `ENIGProtocol` library, making it easy for other developers to understand and use it. I hope this is helpful!
## 개발 환경
- Frameworks : .NET Standard 2.0
- Visual Studio 2022 또는 Visual Studio Code
## 프로젝트 구조
- `EEProtocol.cs`: ENIG 프로토콜 구현
- `EEProtocolTests.cs`: 단위 테스트 코드
- `Sample`: C# Winform 샘플 프로젝트
### Xbee Setting value
- **NARMI 70 : AGV No 70
- **NARMI 70 (LIFT) : P46A6,C17,DH:0,DL:FFFF,MY40
- **NARMI 70 (AGV) : P46A6,C17,DH:0,DL:FFFF,MY41
- **NARMI 77 : AGV No 71
- **NARMI 71 (LIFT) : P46A6,C17,DH:0,DL:FFFF,MY30
- **NARMI 71 (AGV) : P46A6,C17,DH:0,DL:FFFF,MY31
- **충전기04 : P46A6,C17,DH:0,DL:FFFF,MY41
- **충전기71 : P46A6,C17,DH:0,DL:FFFF,MY46
- **ACS : P46A5,C17,DH:0,DL:FFFF,MY10
- **BUFFER : P46A5,C17,DH:0,DL:FFFF,MY60~65
- **AGV1 : P46A5,C17,DH:0,DL:FFFF,MY50
- **AGV2 : P46A5,C17,DH:0,DL:FFFF,MY51
- **DOOR : P46A5,C17,DH:0,DL:FFFF,MY30
## 장비 목록
```
public enum DeviceType : byte
{
ACS = 0,
AGV1 = 10+1,
AGV2 = 10+2,
BUFFER1 = 20+1,
BUFFER2 = 20+2,
BUFFER3 = 20+3,
BUFFER4 = 20+4,
BUFFER5 = 20+5,
DOOR = 30,
}
```
### 기본 패킷 구조
```
[STX][LEN][ID][CMD][DATA][CRC16][ETX]
```
- **STX (Start of Text)**: 0x02
- **LEN (Length)**: 데이터 길이 (1바이트) = {ID+CMD+DATA}
- **ID (Client ID)**: 데이터 길이 (1바이트) : 디바이스식별코드(=DeviceType)
- **CMD (Command)**: 명령어 코드 (1바이트)
- **DATA**: 명령어에 따른 데이터 (가변 길이)
- **CRC16**: 데이터 무결성 검사 (2바이트)
- **ETX (End of Text)**: 0x03
### 통신 방향 (호스트=ACS, 장비=agv,buffer,door)
- H -> E: 호스트에서 장비로 전송
- E -> H: 장비에서 호스트로 전송
### 명령어 목록
1. **ACS (AGV Control System)**
2. **Buffer**
- E -> H | cmd('S'): 상태 (............) BIT & 1BYTE 0:CART1, 1:CART2, 2:BASKET1, 3:BASKET2, 4:OPEN, 5:CLOSE
- H -> E | cmd('L'): Lock
- Target[1] = {DeviceType}
- H -> E | cmd('U'): UnLock
- Target[1] = {DeviceType}
3. **AGV**
- H -> E | Move : cmd(100) : 대상태그까지 이동(자동이동)
- Target[1] = {DeviceType}
- TagID[4] = "0000"
- H -> E | Move : cmd(107) : 대상별칭까지 이동(자동이동)
- Target[1] = {DeviceType}
- AliasName[n] = "....."
- H -> E | Stop : cmd(101) : 멈춤
- H -> E | Reset : cmd(102) : 오류 소거
- H -> E | Charge On: cmd(103) : 충전실행(충전기 이동 후 자동 충전 진행)
- Target[1] = {DeviceType}
- Action[1] : 0=Charge Off, 1=Charge On
- H -> E | MoveManual : cmd(104) : 메뉴얼이동
- Target[1] = {DeviceType}
- Direction[1] : 0=Backward, 1=Forward, 2=TurnLeft, 3=TurnRight
- Speed[1] : 0=Slow, 1=Normal, 2=Fast
- Runtime[1] : 0 second
- H -> E | MarkStop : cmd(105) : 마크센서스톱
- Target[1] = {DeviceType}
- H -> E | Lift Control : cmd(106) : 리프트제어
- Target[1] = {DeviceType}
- Action[1] : 0=STOP, 1=UP, 2=DOWN
- E -> H | Move Complete : cmd(1) : 목적지이동완료 후 전송
- TagID[4] : "0000"
- E -> H | TagID Received : cmd(2) : 태그값 인식시 전송
- TagID[4] : "0000"
- E -> H | Status : cmd(3) - 총 12바이트
- Mode[1] : 0=manual, 1=auto
- RunSt[1] : 0=stop, 1=run, 2=error
MotDirection[1] : 0:Forward, 1:Backward, 0xFF:unknown
- MagDiection[1] : 0=straight, 1=left, 2=right , 0xFF:unknown
- Inposition[1] : 0=off, 1=on : 목적위치에 도달완료 시 설정 이동 이동시 OFF됨
- ChargeSt[1] : 0=off, 1=on
- CartSt[1] : 0=off, 1=on, 2=unknown
- LiftSt[1] : 0=down , 1=up, 2=unknown
- LastTag[4] : "0000" (ASCII 4바이트)
4. **Door**
- H -> E | cmd(1): 출입문 열기
- H -> E | cmd(2): 출입문 닫기
- E -> H | cmd(3): 출입문 상태 (data len=1 : 0=닫힘, 1=열림, 2=바쁨, 3=알수없음, 255=오류)
### CRC16 계산
- CRC16 다항식 사용
- 초기값: 0xFFFF
- 데이터 무결성 검증에 사용
#### CRC-16 테이블 값
```
0x0000, 0x408E, 0x73EF, 0x3361, 0x152D, 0x55A3, 0x66C2, 0x264C,
0x2A5A, 0x6AD4, 0x59B5, 0x193B, 0x3F77, 0x7FF9, 0x4C98, 0x0C16,
0x54B4, 0x143A, 0x275B, 0x67D5, 0x4199, 0x0117, 0x3276, 0x72F8,
0x7EEE, 0x3E60, 0x0D01, 0x4D8F, 0x6BC3, 0x2B4D, 0x182C, 0x58A2,
0x5B9B, 0x1B15, 0x2874, 0x68FA, 0x4EB6, 0x0E38, 0x3D59, 0x7DD7,
0x71C1, 0x314F, 0x022E, 0x42A0, 0x64EC, 0x2462, 0x1703, 0x578D,
0x0F2F, 0x4FA1, 0x7CC0, 0x3C4E, 0x1A02, 0x5A8C, 0x69ED, 0x2963,
0x2575, 0x65FB, 0x569A, 0x1614, 0x3058, 0x70D6, 0x43B7, 0x0339,
0x45C5, 0x054B, 0x362A, 0x76A4, 0x50E8, 0x1066, 0x2307, 0x6389,
0x6F9F, 0x2F11, 0x1C70, 0x5CFE, 0x7AB2, 0x3A3C, 0x095D, 0x49D3,
0x1171, 0x51FF, 0x629E, 0x2210, 0x045C, 0x44D2, 0x77B3, 0x373D,
0x3B2B, 0x7BA5, 0x48C4, 0x084A, 0x2E06, 0x6E88, 0x5DE9, 0x1D67,
0x1E5E, 0x5ED0, 0x6DB1, 0x2D3F, 0x0B73, 0x4BFD, 0x789C, 0x3812,
0x3404, 0x748A, 0x47EB, 0x0765, 0x2129, 0x61A7, 0x52C6, 0x1248,
0x4AEA, 0x0A64, 0x3905, 0x798B, 0x5FC7, 0x1F49, 0x2C28, 0x6CA6,
0x60B0, 0x203E, 0x135F, 0x53D1, 0x759D, 0x3513, 0x0672, 0x46FC,
0x7979, 0x39F7, 0x0A96, 0x4A18, 0x6C54, 0x2CDA, 0x1FBB, 0x5F35,
0x5323, 0x13AD, 0x20CC, 0x6042, 0x460E, 0x0680, 0x35E1, 0x756F,
0x2DCD, 0x6D43, 0x5E22, 0x1EAC, 0x38E0, 0x786E, 0x4B0F, 0x0B81,
0x0797, 0x4719, 0x7478, 0x34F6, 0x12BA, 0x5234, 0x6155, 0x21DB,
0x22E2, 0x626C, 0x510D, 0x1183, 0x37CF, 0x7741, 0x4420, 0x04AE,
0x08B8, 0x4836, 0x7B57, 0x3BD9, 0x1D95, 0x5D1B, 0x6E7A, 0x2EF4,
0x7656, 0x36D8, 0x05B9, 0x4537, 0x637B, 0x23F5, 0x1094, 0x501A,
0x5C0C, 0x1C82, 0x2FE3, 0x6F6D, 0x4921, 0x09AF, 0x3ACE, 0x7A40,
0x3CBC, 0x7C32, 0x4F53, 0x0FDD, 0x2991, 0x691F, 0x5A7E, 0x1AF0,
0x16E6, 0x5668, 0x6509, 0x2587, 0x03CB, 0x4345, 0x7024, 0x30AA,
0x6808, 0x2886, 0x1BE7, 0x5B69, 0x7D25, 0x3DAB, 0x0ECA, 0x4E44,
0x4252, 0x02DC, 0x31BD, 0x7133, 0x577F, 0x17F1, 0x2490, 0x641E,
0x6727, 0x27A9, 0x14C8, 0x5446, 0x720A, 0x3284, 0x01E5, 0x416B,
0x4D7D, 0x0DF3, 0x3E92, 0x7E1C, 0x5850, 0x18DE, 0x2BBF, 0x6B31,
0x3393, 0x731D, 0x407C, 0x00F2, 0x26BE, 0x6630, 0x5551, 0x15DF,
0x19C9, 0x5947, 0x6A26, 0x2AA8, 0x0CE4, 0x4C6A, 0x7F0B, 0x3F85,
```
#### CRC16 계산 테이블 생성 코드
```csharp
const ushort polynomial = 0x7979;
ushort[] CRC16_TABLE = new ushort[256];
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;
}
```
#### CRC16 계산 예시
```csharp
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;
}
```
## 라이센스

View File

@@ -0,0 +1,450 @@
namespace SampleProject
{
partial class Form1
{
/// <summary>
/// 필수 디자이너 변수입니다.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// 사용 중인 모든 리소스를 정리합니다.
/// </summary>
/// <param name="disposing">관리되는 리소스를 삭제해야 하면 true이고, 그렇지 않으면 false입니다.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form
/// <summary>
/// 디자이너 지원에 필요한 메서드입니다.
/// 이 메서드의 내용을 코드 편집기로 수정하지 마세요.
/// </summary>
private void InitializeComponent()
{
this.components = new System.ComponentModel.Container();
this.rtRx = new System.Windows.Forms.RichTextBox();
this.rtTx = new System.Windows.Forms.RichTextBox();
this.tbmsg = new System.Windows.Forms.TextBox();
this.btsend = new System.Windows.Forms.Button();
this.cmbport = new System.Windows.Forms.ComboBox();
this.btconnect = new System.Windows.Forms.Button();
this.tbbaud = new System.Windows.Forms.ComboBox();
this.statusStrip1 = new System.Windows.Forms.StatusStrip();
this.sbPort = new System.Windows.Forms.ToolStripStatusLabel();
this.timer1 = new System.Windows.Forms.Timer(this.components);
this.cmbid = new System.Windows.Forms.ComboBox();
this.btsim = new System.Windows.Forms.Button();
this.rtMsg = new System.Windows.Forms.RichTextBox();
this.tbCmd = new System.Windows.Forms.TextBox();
this.tableLayoutPanel1 = new System.Windows.Forms.TableLayoutPanel();
this.panel1 = new System.Windows.Forms.Panel();
this.label5 = new System.Windows.Forms.Label();
this.label4 = new System.Windows.Forms.Label();
this.label3 = new System.Windows.Forms.Label();
this.panel2 = new System.Windows.Forms.Panel();
this.label2 = new System.Windows.Forms.Label();
this.label1 = new System.Windows.Forms.Label();
this.tabControl1 = new System.Windows.Forms.TabControl();
this.tabPage1 = new System.Windows.Forms.TabPage();
this.tabPage2 = new System.Windows.Forms.TabPage();
this.btSave = new System.Windows.Forms.Button();
this.btload = new System.Windows.Forms.Button();
this.rtCmd = new System.Windows.Forms.RichTextBox();
this.statusStrip1.SuspendLayout();
this.tableLayoutPanel1.SuspendLayout();
this.panel1.SuspendLayout();
this.panel2.SuspendLayout();
this.tabControl1.SuspendLayout();
this.tabPage1.SuspendLayout();
this.tabPage2.SuspendLayout();
this.SuspendLayout();
//
// rtRx
//
this.rtRx.Dock = System.Windows.Forms.DockStyle.Fill;
this.rtRx.Font = new System.Drawing.Font("굴림", 9.75F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(129)));
this.rtRx.Location = new System.Drawing.Point(4, 5);
this.rtRx.Margin = new System.Windows.Forms.Padding(4, 5, 4, 5);
this.rtRx.Name = "rtRx";
this.rtRx.Size = new System.Drawing.Size(462, 302);
this.rtRx.TabIndex = 0;
this.rtRx.Text = "";
//
// rtTx
//
this.rtTx.Dock = System.Windows.Forms.DockStyle.Fill;
this.rtTx.Font = new System.Drawing.Font("굴림", 9.75F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(129)));
this.rtTx.Location = new System.Drawing.Point(474, 5);
this.rtTx.Margin = new System.Windows.Forms.Padding(4, 5, 4, 5);
this.rtTx.Name = "rtTx";
this.rtTx.Size = new System.Drawing.Size(462, 302);
this.rtTx.TabIndex = 1;
this.rtTx.Text = "";
//
// tbmsg
//
this.tbmsg.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(192)))), ((int)(((byte)(255)))), ((int)(((byte)(192)))));
this.tbmsg.Dock = System.Windows.Forms.DockStyle.Fill;
this.tbmsg.Font = new System.Drawing.Font("굴림", 24F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(129)));
this.tbmsg.Location = new System.Drawing.Point(436, 5);
this.tbmsg.Margin = new System.Windows.Forms.Padding(4, 5, 4, 5);
this.tbmsg.Name = "tbmsg";
this.tbmsg.Size = new System.Drawing.Size(273, 44);
this.tbmsg.TabIndex = 2;
this.tbmsg.Text = "mesage";
this.tbmsg.TextAlign = System.Windows.Forms.HorizontalAlignment.Center;
this.tbmsg.TextChanged += new System.EventHandler(this.tbmsg_TextChanged);
//
// btsend
//
this.btsend.Dock = System.Windows.Forms.DockStyle.Right;
this.btsend.Font = new System.Drawing.Font("굴림", 12F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(129)));
this.btsend.Location = new System.Drawing.Point(709, 5);
this.btsend.Margin = new System.Windows.Forms.Padding(4, 5, 4, 5);
this.btsend.Name = "btsend";
this.btsend.Size = new System.Drawing.Size(120, 42);
this.btsend.TabIndex = 3;
this.btsend.Text = "Send";
this.btsend.UseVisualStyleBackColor = true;
this.btsend.Click += new System.EventHandler(this.btsend_Click);
//
// cmbport
//
this.cmbport.Dock = System.Windows.Forms.DockStyle.Left;
this.cmbport.Font = new System.Drawing.Font("굴림", 24F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(129)));
this.cmbport.FormattingEnabled = true;
this.cmbport.Location = new System.Drawing.Point(58, 3);
this.cmbport.Margin = new System.Windows.Forms.Padding(4, 5, 4, 5);
this.cmbport.Name = "cmbport";
this.cmbport.Size = new System.Drawing.Size(218, 40);
this.cmbport.TabIndex = 4;
//
// btconnect
//
this.btconnect.Dock = System.Windows.Forms.DockStyle.Right;
this.btconnect.Location = new System.Drawing.Point(765, 3);
this.btconnect.Margin = new System.Windows.Forms.Padding(4, 5, 4, 5);
this.btconnect.Name = "btconnect";
this.btconnect.Size = new System.Drawing.Size(186, 40);
this.btconnect.TabIndex = 5;
this.btconnect.Text = "connect";
this.btconnect.UseVisualStyleBackColor = true;
this.btconnect.Click += new System.EventHandler(this.btconnect_Click);
//
// tbbaud
//
this.tbbaud.Dock = System.Windows.Forms.DockStyle.Left;
this.tbbaud.Font = new System.Drawing.Font("굴림", 24F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(129)));
this.tbbaud.FormattingEnabled = true;
this.tbbaud.Location = new System.Drawing.Point(331, 3);
this.tbbaud.Margin = new System.Windows.Forms.Padding(4, 5, 4, 5);
this.tbbaud.Name = "tbbaud";
this.tbbaud.Size = new System.Drawing.Size(171, 40);
this.tbbaud.TabIndex = 6;
this.tbbaud.Text = "9600";
//
// statusStrip1
//
this.statusStrip1.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {
this.sbPort});
this.statusStrip1.Location = new System.Drawing.Point(0, 583);
this.statusStrip1.Name = "statusStrip1";
this.statusStrip1.Padding = new System.Windows.Forms.Padding(1, 0, 20, 0);
this.statusStrip1.Size = new System.Drawing.Size(954, 22);
this.statusStrip1.TabIndex = 7;
this.statusStrip1.Text = "statusStrip1";
//
// sbPort
//
this.sbPort.Name = "sbPort";
this.sbPort.Size = new System.Drawing.Size(121, 17);
this.sbPort.Text = "toolStripStatusLabel1";
//
// timer1
//
this.timer1.Tick += new System.EventHandler(this.timer1_Tick);
//
// cmbid
//
this.cmbid.Dock = System.Windows.Forms.DockStyle.Left;
this.cmbid.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
this.cmbid.Font = new System.Drawing.Font("굴림", 24F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(129)));
this.cmbid.FormattingEnabled = true;
this.cmbid.Location = new System.Drawing.Point(60, 5);
this.cmbid.Margin = new System.Windows.Forms.Padding(4, 5, 4, 5);
this.cmbid.Name = "cmbid";
this.cmbid.Size = new System.Drawing.Size(183, 40);
this.cmbid.TabIndex = 8;
//
// btsim
//
this.btsim.Dock = System.Windows.Forms.DockStyle.Right;
this.btsim.Font = new System.Drawing.Font("굴림", 12F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(129)));
this.btsim.Location = new System.Drawing.Point(829, 5);
this.btsim.Margin = new System.Windows.Forms.Padding(4, 5, 4, 5);
this.btsim.Name = "btsim";
this.btsim.Size = new System.Drawing.Size(120, 42);
this.btsim.TabIndex = 9;
this.btsim.Text = "Test";
this.btsim.UseVisualStyleBackColor = true;
this.btsim.Click += new System.EventHandler(this.btsim_Click);
//
// rtMsg
//
this.rtMsg.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(224)))), ((int)(((byte)(224)))), ((int)(((byte)(224)))));
this.tableLayoutPanel1.SetColumnSpan(this.rtMsg, 2);
this.rtMsg.Dock = System.Windows.Forms.DockStyle.Fill;
this.rtMsg.Location = new System.Drawing.Point(4, 317);
this.rtMsg.Margin = new System.Windows.Forms.Padding(4, 5, 4, 5);
this.rtMsg.Name = "rtMsg";
this.rtMsg.Size = new System.Drawing.Size(932, 124);
this.rtMsg.TabIndex = 10;
this.rtMsg.Text = "";
//
// tbCmd
//
this.tbCmd.Dock = System.Windows.Forms.DockStyle.Left;
this.tbCmd.Font = new System.Drawing.Font("굴림", 24F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(129)));
this.tbCmd.Location = new System.Drawing.Point(298, 5);
this.tbCmd.Margin = new System.Windows.Forms.Padding(4, 5, 4, 5);
this.tbCmd.Name = "tbCmd";
this.tbCmd.Size = new System.Drawing.Size(83, 44);
this.tbCmd.TabIndex = 11;
this.tbCmd.Text = "cmd";
this.tbCmd.TextAlign = System.Windows.Forms.HorizontalAlignment.Center;
//
// tableLayoutPanel1
//
this.tableLayoutPanel1.ColumnCount = 2;
this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 50F));
this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 50F));
this.tableLayoutPanel1.Controls.Add(this.rtMsg, 0, 1);
this.tableLayoutPanel1.Controls.Add(this.rtRx, 0, 0);
this.tableLayoutPanel1.Controls.Add(this.rtTx, 1, 0);
this.tableLayoutPanel1.Dock = System.Windows.Forms.DockStyle.Fill;
this.tableLayoutPanel1.Location = new System.Drawing.Point(3, 3);
this.tableLayoutPanel1.Name = "tableLayoutPanel1";
this.tableLayoutPanel1.RowCount = 2;
this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 70F));
this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 30F));
this.tableLayoutPanel1.Size = new System.Drawing.Size(940, 446);
this.tableLayoutPanel1.TabIndex = 12;
//
// panel1
//
this.panel1.Controls.Add(this.tbmsg);
this.panel1.Controls.Add(this.label5);
this.panel1.Controls.Add(this.tbCmd);
this.panel1.Controls.Add(this.label4);
this.panel1.Controls.Add(this.cmbid);
this.panel1.Controls.Add(this.label3);
this.panel1.Controls.Add(this.btsend);
this.panel1.Controls.Add(this.btsim);
this.panel1.Dock = System.Windows.Forms.DockStyle.Bottom;
this.panel1.Location = new System.Drawing.Point(0, 531);
this.panel1.Name = "panel1";
this.panel1.Padding = new System.Windows.Forms.Padding(5);
this.panel1.Size = new System.Drawing.Size(954, 52);
this.panel1.TabIndex = 13;
//
// label5
//
this.label5.Dock = System.Windows.Forms.DockStyle.Left;
this.label5.Font = new System.Drawing.Font("Arial", 12F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
this.label5.Location = new System.Drawing.Point(381, 5);
this.label5.Name = "label5";
this.label5.Size = new System.Drawing.Size(55, 42);
this.label5.TabIndex = 14;
this.label5.Text = "DATA\r\n(n)";
this.label5.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
//
// label4
//
this.label4.Dock = System.Windows.Forms.DockStyle.Left;
this.label4.Font = new System.Drawing.Font("Arial", 12F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
this.label4.Location = new System.Drawing.Point(243, 5);
this.label4.Name = "label4";
this.label4.Size = new System.Drawing.Size(55, 42);
this.label4.TabIndex = 13;
this.label4.Text = "CMD\r\n(1)";
this.label4.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
//
// label3
//
this.label3.Dock = System.Windows.Forms.DockStyle.Left;
this.label3.Font = new System.Drawing.Font("Arial", 12F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
this.label3.Location = new System.Drawing.Point(5, 5);
this.label3.Name = "label3";
this.label3.Size = new System.Drawing.Size(55, 42);
this.label3.TabIndex = 12;
this.label3.Text = "ID\r\n(1)";
this.label3.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
//
// panel2
//
this.panel2.Controls.Add(this.tbbaud);
this.panel2.Controls.Add(this.label2);
this.panel2.Controls.Add(this.cmbport);
this.panel2.Controls.Add(this.btconnect);
this.panel2.Controls.Add(this.label1);
this.panel2.Dock = System.Windows.Forms.DockStyle.Top;
this.panel2.Location = new System.Drawing.Point(0, 0);
this.panel2.Name = "panel2";
this.panel2.Padding = new System.Windows.Forms.Padding(3);
this.panel2.Size = new System.Drawing.Size(954, 46);
this.panel2.TabIndex = 14;
//
// label2
//
this.label2.Dock = System.Windows.Forms.DockStyle.Left;
this.label2.Location = new System.Drawing.Point(276, 3);
this.label2.Name = "label2";
this.label2.Size = new System.Drawing.Size(55, 40);
this.label2.TabIndex = 8;
this.label2.Text = "baud";
this.label2.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
//
// label1
//
this.label1.Dock = System.Windows.Forms.DockStyle.Left;
this.label1.Location = new System.Drawing.Point(3, 3);
this.label1.Name = "label1";
this.label1.Size = new System.Drawing.Size(55, 40);
this.label1.TabIndex = 7;
this.label1.Text = "port";
this.label1.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
//
// tabControl1
//
this.tabControl1.Controls.Add(this.tabPage1);
this.tabControl1.Controls.Add(this.tabPage2);
this.tabControl1.Dock = System.Windows.Forms.DockStyle.Fill;
this.tabControl1.Location = new System.Drawing.Point(0, 46);
this.tabControl1.Name = "tabControl1";
this.tabControl1.SelectedIndex = 0;
this.tabControl1.Size = new System.Drawing.Size(954, 485);
this.tabControl1.TabIndex = 15;
//
// tabPage1
//
this.tabPage1.Controls.Add(this.tableLayoutPanel1);
this.tabPage1.Location = new System.Drawing.Point(4, 29);
this.tabPage1.Name = "tabPage1";
this.tabPage1.Padding = new System.Windows.Forms.Padding(3);
this.tabPage1.Size = new System.Drawing.Size(946, 452);
this.tabPage1.TabIndex = 0;
this.tabPage1.Text = "Test";
this.tabPage1.UseVisualStyleBackColor = true;
//
// tabPage2
//
this.tabPage2.Controls.Add(this.btSave);
this.tabPage2.Controls.Add(this.btload);
this.tabPage2.Controls.Add(this.rtCmd);
this.tabPage2.Location = new System.Drawing.Point(4, 29);
this.tabPage2.Name = "tabPage2";
this.tabPage2.Padding = new System.Windows.Forms.Padding(3);
this.tabPage2.Size = new System.Drawing.Size(946, 452);
this.tabPage2.TabIndex = 1;
this.tabPage2.Text = "Command";
this.tabPage2.UseVisualStyleBackColor = true;
//
// btSave
//
this.btSave.Location = new System.Drawing.Point(820, 50);
this.btSave.Name = "btSave";
this.btSave.Size = new System.Drawing.Size(113, 29);
this.btSave.TabIndex = 13;
this.btSave.Text = "Save";
this.btSave.UseVisualStyleBackColor = true;
this.btSave.Click += new System.EventHandler(this.btSave_Click);
//
// btload
//
this.btload.Location = new System.Drawing.Point(820, 15);
this.btload.Name = "btload";
this.btload.Size = new System.Drawing.Size(113, 29);
this.btload.TabIndex = 12;
this.btload.Text = "Load";
this.btload.UseVisualStyleBackColor = true;
this.btload.Click += new System.EventHandler(this.btload_Click);
//
// rtCmd
//
this.rtCmd.Dock = System.Windows.Forms.DockStyle.Fill;
this.rtCmd.Location = new System.Drawing.Point(3, 3);
this.rtCmd.Margin = new System.Windows.Forms.Padding(4, 5, 4, 5);
this.rtCmd.Name = "rtCmd";
this.rtCmd.Size = new System.Drawing.Size(940, 446);
this.rtCmd.TabIndex = 11;
this.rtCmd.Text = "";
//
// Form1
//
this.AutoScaleDimensions = new System.Drawing.SizeF(10F, 19F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(954, 605);
this.Controls.Add(this.tabControl1);
this.Controls.Add(this.panel2);
this.Controls.Add(this.panel1);
this.Controls.Add(this.statusStrip1);
this.Font = new System.Drawing.Font("굴림", 14.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(129)));
this.Margin = new System.Windows.Forms.Padding(4, 5, 4, 5);
this.Name = "Form1";
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;
this.Text = "!!";
this.Load += new System.EventHandler(this.Form1_Load);
this.statusStrip1.ResumeLayout(false);
this.statusStrip1.PerformLayout();
this.tableLayoutPanel1.ResumeLayout(false);
this.panel1.ResumeLayout(false);
this.panel1.PerformLayout();
this.panel2.ResumeLayout(false);
this.tabControl1.ResumeLayout(false);
this.tabPage1.ResumeLayout(false);
this.tabPage2.ResumeLayout(false);
this.ResumeLayout(false);
this.PerformLayout();
}
#endregion
private System.Windows.Forms.RichTextBox rtRx;
private System.Windows.Forms.RichTextBox rtTx;
private System.Windows.Forms.TextBox tbmsg;
private System.Windows.Forms.Button btsend;
private System.Windows.Forms.ComboBox cmbport;
private System.Windows.Forms.Button btconnect;
private System.Windows.Forms.ComboBox tbbaud;
private System.Windows.Forms.StatusStrip statusStrip1;
private System.Windows.Forms.ToolStripStatusLabel sbPort;
private System.Windows.Forms.Timer timer1;
private System.Windows.Forms.ComboBox cmbid;
private System.Windows.Forms.Button btsim;
private System.Windows.Forms.RichTextBox rtMsg;
private System.Windows.Forms.TextBox tbCmd;
private System.Windows.Forms.TableLayoutPanel tableLayoutPanel1;
private System.Windows.Forms.Panel panel1;
private System.Windows.Forms.Panel panel2;
private System.Windows.Forms.Label label2;
private System.Windows.Forms.Label label1;
private System.Windows.Forms.Label label5;
private System.Windows.Forms.Label label4;
private System.Windows.Forms.Label label3;
private System.Windows.Forms.TabControl tabControl1;
private System.Windows.Forms.TabPage tabPage1;
private System.Windows.Forms.TabPage tabPage2;
private System.Windows.Forms.RichTextBox rtCmd;
private System.Windows.Forms.Button btSave;
private System.Windows.Forms.Button btload;
}
}

View File

@@ -0,0 +1,225 @@
using AR;
using ENIG;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Security.Cryptography.X509Certificates;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace SampleProject
{
enum messageType
{
rx,
tx,
normal,
error
}
public partial class Form1 : Form
{
System.IO.Ports.SerialPort dev;
EEProtocol proto;
Dictionary<string, byte> idlist;
public Form1()
{
InitializeComponent();
this.Text = $"Amkor ENIG Protocol Test (PanID:46A5, CH:17)";
proto = new EEProtocol();
proto.OnDataReceived += Proto_OnDataReceived;
proto.OnMessage += Proto_OnMessage;
dev = new System.IO.Ports.SerialPort();
dev.ReadTimeout = 2000;
dev.WriteTimeout = 1000;
dev.DataReceived += (s1, e1) =>
{
var buffer = new byte[dev.BytesToRead];
dev.Read(buffer, 0, buffer.Length);
proto.ProcessReceivedData(buffer);
};
idlist = new Dictionary<string, byte>();
idlist.Add("ACS", 0);
idlist.Add("AGV1", 10);
idlist.Add("AGV2", 11);
idlist.Add("BUFFER1", 20);
idlist.Add("BUFFER2", 21);
idlist.Add("BUFFER3", 22);
idlist.Add("BUFFER4", 23);
idlist.Add("BUFFER5", 24);
idlist.Add("DOOR", 30);
this.cmbid.Items.Clear();
foreach (var item in idlist)
cmbid.Items.Add($"{item.Key}");
tbCmd.Text = "FF";
tbmsg.Text = string.Empty;
}
private void Proto_OnDataReceived(object sender, EEProtocol.DataEventArgs e)
{
var hexstrRaw = e.ReceivedPacket.RawData.HexString();
var hexstr = e.ReceivedPacket.Data.HexString();
var cmd = e.ReceivedPacket.Command.ToString("X2");
var id = e.ReceivedPacket.ID.ToString("X2");
AddMessage($"{hexstrRaw}\nID:{id},CMD:{cmd},DATA:{hexstr}", messageType.rx);
}
private void Proto_OnMessage(object sender, EEProtocol.MessageEventArgs e)
{
AddMessage(e.Message);
}
void AddMessage(string msg, messageType type = messageType.normal)
{
if (this.InvokeRequired)
{
this.BeginInvoke(new Action(() => AddMessage(msg, type)));
return;
}
if (type == messageType.rx)
{
rtRx.AppendText($"<{DateTime.Now.ToString("HH:mm:ss")} RX> {msg}\r\n");
rtRx.ScrollToCaret();
}
else if (type == messageType.tx)
{
rtTx.AppendText($"<{DateTime.Now.ToString("HH:mm:ss")} TX> {msg}\r\n");
rtTx.ScrollToCaret();
}
else
{
rtMsg.AppendText($"<{DateTime.Now.ToString("HH:mm:ss")} > {msg}\r\n");
rtMsg.ScrollToCaret();
}
}
private void Form1_Load(object sender, EventArgs e)
{
cmbport.Items.Clear();
foreach (var item in System.IO.Ports.SerialPort.GetPortNames())
{
cmbport.Items.Add(item);
}
if (Pub.Setting.LastPort.isEmpty() == false) cmbport.Text = Pub.Setting.LastPort;
else if (cmbport.Items.Count > 0) cmbport.SelectedIndex = 0;
if (Pub.Setting.LastBaud.isEmpty() == false) tbbaud.Text = Pub.Setting.LastBaud;
if (cmbid.Items.Count > 0) cmbid.SelectedIndex = 0;
LoadCmds();
this.timer1.Start();
}
private void btconnect_Click(object sender, EventArgs e)
{
var port = cmbport.Text.Trim();
var baud = tbbaud.Text.toInt();
//setting save
Pub.Setting.LastPort = port;
Pub.Setting.LastBaud = baud.ToString();
Pub.Setting.Save();
if (dev.IsOpen)
{
dev.Close();
AddMessage("port closed");
}
else
{
try
{
this.dev.PortName = port;
this.dev.BaudRate = baud;
dev.Open();
AddMessage("port opened");
}
catch (Exception ex)
{
AddMessage(ex.Message, messageType.error);
}
}
}
private void timer1_Tick(object sender, EventArgs e)
{
sbPort.Text = $"{dev.PortName}:{dev.BaudRate} {(dev.IsOpen ? "Open" : "Closed")}";
}
private void tbmsg_TextChanged(object sender, EventArgs e)
{
}
private void btsend_Click(object sender, EventArgs e)
{
//send to device
var msg = tbmsg.Text.Trim();
var id = this.idlist[cmbid.Text];
var cmdHex = this.tbCmd.Text.Trim();
byte cmd = Convert.ToByte(cmdHex, 16);
byte[] msgBytes = Encoding.ASCII.GetBytes(msg); // 메시지를 byte 배열로 변환
var data = proto.CreatePacket(id, cmd, msgBytes);
SendToDevice(data);
}
void SendToDevice(byte[] packet)
{
if (dev.IsOpen == false)
{
AddMessage("port closed", messageType.error);
}
else
{
dev.Write(packet, 0, packet.Length);
var hexstring = packet.HexString();
AddMessage(hexstring, messageType.tx);
}
}
private void btsim_Click(object sender, EventArgs e)
{
//packet test
var msg = tbmsg.Text.Trim();
var id = this.idlist[cmbid.Text];
var cmdHex = this.tbCmd.Text.Trim();
byte cmd = Convert.ToByte(cmdHex, 16); // 16진수 문자열을 byte로 변환
byte[] msgBytes = Encoding.ASCII.GetBytes(msg); // 메시지를 byte 배열로 변환
var data = proto.CreatePacket(id, cmd, msgBytes);
this.proto.PacketTest(data);
}
string fn = "cmds.rtf";
private void btSave_Click(object sender, EventArgs e)
{
System.IO.File.WriteAllText("cmds.rtf", rtCmd.Rtf, System.Text.Encoding.Default);
}
private void btload_Click(object sender, EventArgs e)
{
LoadCmds();
}
void LoadCmds()
{
var fi = new System.IO.FileInfo("cmds.rtf");
if (fi.Exists == false)
{
AddMessage("no cmds file", messageType.error);
return;
}
var data = System.IO.File.ReadAllText("cmds.rtf", System.Text.Encoding.Default);
rtCmd.Rtf = data;
}
}
}

View File

@@ -0,0 +1,126 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<metadata name="statusStrip1.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>17, 17</value>
</metadata>
<metadata name="timer1.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>134, 17</value>
</metadata>
</root>

View File

@@ -0,0 +1,23 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace SampleProject
{
internal static class Program
{
/// <summary>
/// 해당 애플리케이션의 주 진입점입니다.
/// </summary>
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Pub.init();
Application.Run(new Form1());
}
}
}

View File

@@ -0,0 +1,36 @@
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// 어셈블리에 대한 일반 정보는 다음 특성 집합을 통해
// 제어됩니다. 어셈블리와 관련된 정보를 수정하려면
// 이러한 특성 값을 변경하세요.
[assembly: AssemblyTitle("SampleProject")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("ATK")]
[assembly: AssemblyProduct("SampleProject")]
[assembly: AssemblyCopyright("Copyright © ATK 2025")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// ComVisible을 false로 설정하면 이 어셈블리의 형식이 COM 구성 요소에
// 표시되지 않습니다. COM에서 이 어셈블리의 형식에 액세스하려면
// 해당 형식에 대해 ComVisible 특성을 true로 설정하세요.
[assembly: ComVisible(false)]
// 이 프로젝트가 COM에 노출되는 경우 다음 GUID는 typelib의 ID를 나타냅니다.
[assembly: Guid("fab31c8a-7dcf-4152-8a82-76f3c10baba4")]
// 어셈블리의 버전 정보는 다음 네 가지 값으로 구성됩니다.
//
// 주 버전
// 부 버전
// 빌드 번호
// 수정 버전
//
// 모든 값을 지정하거나 아래와 같이 '*'를 사용하여 빌드 번호 및 수정 번호를
// 기본값으로 할 수 있습니다.
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]

View File

@@ -0,0 +1,71 @@
//------------------------------------------------------------------------------
// <auto-generated>
// 이 코드는 도구를 사용하여 생성되었습니다.
// 런타임 버전:4.0.30319.42000
//
// 파일 내용을 변경하면 잘못된 동작이 발생할 수 있으며, 코드를 다시 생성하면
// 이러한 변경 내용이 손실됩니다.
// </auto-generated>
//------------------------------------------------------------------------------
namespace SampleProject.Properties
{
/// <summary>
/// 지역화된 문자열 등을 찾기 위한 강력한 형식의 리소스 클래스입니다.
/// </summary>
// 이 클래스는 ResGen 또는 Visual Studio와 같은 도구를 통해 StronglyTypedResourceBuilder
// 클래스에서 자동으로 생성되었습니다.
// 멤버를 추가하거나 제거하려면 .ResX 파일을 편집한 다음 /str 옵션을 사용하여
// ResGen을 다시 실행하거나 VS 프로젝트를 다시 빌드하십시오.
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
internal class Resources
{
private static global::System.Resources.ResourceManager resourceMan;
private static global::System.Globalization.CultureInfo resourceCulture;
[global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
internal Resources()
{
}
/// <summary>
/// 이 클래스에서 사용하는 캐시된 ResourceManager 인스턴스를 반환합니다.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Resources.ResourceManager ResourceManager
{
get
{
if ((resourceMan == null))
{
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("SampleProject.Properties.Resources", typeof(Resources).Assembly);
resourceMan = temp;
}
return resourceMan;
}
}
/// <summary>
/// 이 강력한 형식의 리소스 클래스를 사용하여 모든 리소스 조회에 대해 현재 스레드의 CurrentUICulture 속성을
/// 재정의합니다.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Globalization.CultureInfo Culture
{
get
{
return resourceCulture;
}
set
{
resourceCulture = value;
}
}
}
}

View File

@@ -0,0 +1,30 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version:4.0.30319.42000
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
namespace SampleProject.Properties
{
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "11.0.0.0")]
internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase
{
private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
public static Settings Default
{
get
{
return defaultInstance;
}
}
}
}

Some files were not shown because too many files have changed in this diff Show More