본문으로 이동

FEnet 프로토콜 라이브러리

lse
Hschoi2 (토론 | 기여)님의 2025년 8월 18일 (월) 07:51 판 (새 문서: I-NET 단종과 더블어 해당 라이브러리 해석에 대한 내용이 있어서, 보존 차원으로 백업한다. [https://m.blog.naver.com/vagabond-k/222877084987 블로그내용] 백업 C#으로 만든 라이브러리임 =라이브러리= 설명 및 설치 C#, 닷넷 ==LS 프로토콜== Modbus RTU/ASCII/TCP 프로토콜, LS ELECTRIC(구 LS산전)의 Cnet, FEnet 프로토콜 등으로 장치와 통신하는 기능들을 구현했습니다. [https://github.com/Vag...)
(차이) ← 이전 판 | 최신판 (차이) | 다음 판 → (차이)

I-NET 단종과 더블어 해당 라이브러리 해석에 대한 내용이 있어서, 보존 차원으로 백업한다.

블로그내용 백업

C#으로 만든 라이브러리임

라이브러리

[편집 | 원본 편집]

설명 및 설치 C#, 닷넷


LS 프로토콜

[편집 | 원본 편집]

Modbus RTU/ASCII/TCP 프로토콜, LS ELECTRIC(구 LS산전)의 Cnet, FEnet 프로토콜 등으로 장치와 통신하는 기능들을 구현했습니다.

github관련 내용


LS산전 FEnet 라이브러리 NuGet 패키지 설치

[편집 | 원본 편집]

LS산전 FEnet 통신 기능이 들어있는 NuGet 패키지는 VagabondK.Protocols.LSElectric이다.

저번에 소개했던 Cnet 프로토콜 라이브러리도 마찬가지로 VagabondK.Protocols.LSElectric 패키지에 들어있다.

단, FEnet을 사용하기 위해서는 v1.1.0 이상의 패키지를 설치해야 한다.

파일다운로드 위치

FEnet은 일단 이더넷 기반 통신 프로토콜이다.

물론 시리얼 포트 기반 채널로도 통신이 가능하긴 하지만, 굳이 그렇게 시리얼 디바이스 서버(시리얼 to 이더넷 컨버터) 같은 환경을 꾸며가면서 시리얼 채널을 쓰게 될 일은 없을 것이라 판단된다.

따라서 TCP 또는 UDP 통신 채널을 제공하는 VagabondK.Protocols.Channels 패키지만 설치하면 될 것으로 생각된다.


Visual Studio를 이용한 설치 방법은 지난 Cnet 프로토콜 라이브러리 소개 참고

[편집 | 원본 편집]


FEnet 클라이언트 사용법

[편집 | 원본 편집]

본 라이브리에서 주로 사용하는 클래스는 FEnetClient 클래스.

일단 다음의 예제 코드를 보자.

using System; using System.Linq; using VagabondK.Protocols.Channels; using VagabondK.Protocols.LSElectric; using VagabondK.Protocols.LSElectric.FEnet;

class Program {

   static void Main(string[] args)
   {
       FEnetClient client = new FEnetClient(new TcpChannel("127.0.0.1", 2004));
       //변수 %MW100와 %MW200을 각각 읽어오기
       foreach (var item in client.Read("%MW100", "%MW200"))
       {
           Console.WriteLine($"변수: {item.Key}, 값: {item.Value.WordValue}");
       }
       //변수 %MB200(%MW100)부터 바이트 10개를 연속으로 읽어오기
       var bytes = client.Read(DeviceType.M, 200, 10).ToArray();
       for (int i = 0; i < bytes.Length; i+=2)
       {
           Console.WriteLine($"변수: %MW{100 + i / 2}, 값: {BitConverter.ToInt16(bytes, i)}");
       }


       //변수 %MW102에 값 10을, %MW202에 값 20을 쓰기
       client.Write(("%MW102", 10), ("%MW202", 20));
       //변수 %MB600(%MW300)부터 연속으로 4개의 바이트 쓰기, 쓸 값은 각각 10, 0, 20, 0
       client.Write(DeviceType.M, 600, 10, 0, 20, 0);
   }

}

Cnet 프로토콜 라이브러리 소개 글의 예제와 동일한 결과를 나타내는 코드라고 볼 수 있다.

(물론, FEnet에는 모니터 기능이 없으므로 해당 기능은 열외)

CnetClient 클래스 사용법과 거의 비슷하지만, FEnetClient에서는 국번 매개변수가 사라졌다.

뭐, 당연하겠지만 이더넷 기반 통신이므로, 즉 아이피 주소로 모든 PLC의 아이디가 결정되므로 굳이 국번이 필요 없다.

그리고 연속 변수 읽기의 경우 바이트 형식으로만 읽을 수 있기 때문에, DeviceVariable 구조체를 매개변수로 사용하지 않고 DataType 열거형과 시작 주소, 읽을 개수 등으로 읽기 요청을 수행한다.

그리고 그 반환 결과는 byte 형식의 리스트가 된다.

예제의 경우는 시작 주소를 %MB200으로 설정하고 연속으로 10개를 읽도록 했다.

이것은 결국 예전의 Cnet 설명 글의 예제와 마찬가지로 2바이트 워드 단위로 %MW100부터 5개를 읽는 것이나 마찬가지라고 볼 수 있다.

아까 설명했듯이 FEnet의 연속 읽기는 바이트 단위로만 가능하기 때문에,

2바이트 워드 단위 주소인 %MW100의 주소를 바이트 단위 주소인 %MB200으로 바꾸고,

개수는 두 배로 늘린 것이다.

결과 값은 바이트를 열거하기 때문에 바이트 배열로부터 BitConverter로 2바이트씩 끊어서 직접 읽어야 한다.

음... 뭔가 조금 Cnet보다 번거롭다.

  • 상세 사용법

기타 상세 사용법

변수 개별 쓰기, 연속 쓰기도 지난번의 Cnet 프로토콜 라이브러리 소개 글의 예제와 동일한 결과를 나타낼 것이다.

그렇지만 연속 쓰기도 마찬가지로 바이트 단위로만 쓰기가 가능하므로 유의해서 사용해야 한다.


FEnetClient 클래스 심화(?) 사용법

[편집 | 원본 편집]

FEnet 프로토콜 라이브러리도 Cnet과 마찬가지로 요청과 응답을 위한 클래스들을 일일이 구현했다.

FEnet 프로토콜을 이용하여 .NET 기반 응용프로그램에 데이터 맵 설정 기능을 설계한다거나 체계적인 데이터 관리를 하고 싶다면,

설정에 따라 요청 클래스들을 적절히 생성하여 배열에 저장해두고, 적당한 시간 간격으로 Request 메서드를 일괄적으로 호출하도록 구현하면 될 것이다.

아까의 예제 코드를 요청 및 응답 클래스를 이용하여 다시 구현한 예제는 다음과 같다.

using System; using System.Linq; using VagabondK.Protocols.Channels; using VagabondK.Protocols.LSElectric; using VagabondK.Protocols.LSElectric.FEnet;

class Program {

   static void Main(string[] args)
   {
       FEnetClient client = new FEnetClient(new TcpChannel("127.0.0.1", 2004));
       //NAK 응답을 받아도 예외를 발생시키지 않고 FEnetNAKResponse 객체로 반환하도록 설정
       client.ThrowsExceptionFromNAK = false;
       //변수 %MW100와 %MW200을 각각 읽어오기
       //foreach (var item in client.Read("%MW100", "%MW200"))
       //{
       //    Console.WriteLine($"변수: {item.Key}, 값: {item.Value.WordValue}");
       //}
       FEnetRequest request = new FEnetReadIndividualRequest("%MW100", "%MW200");
       foreach (var item in client.Request(request) as FEnetReadIndividualResponse)
       {
           Console.WriteLine($"변수: {item.Key}, 값: {item.Value.WordValue}");
       }
       //변수 %MB200(%MW100)부터 바이트 10개를 연속으로 읽어오기
       //var bytes = client.Read(DeviceType.M, 200, 10).ToArray();
       //for (int i = 0; i < bytes.Length; i += 2)
       //{
       //    Console.WriteLine($"변수: %MW{100 + i / 2}, 값: {BitConverter.ToInt16(bytes, i)}");
       //}
       request = new FEnetReadContinuousRequest(DeviceType.M, 200, 10);
       var bytes = (client.Request(request) as FEnetReadContinuousResponse).ToArray();
       for (int i = 0; i < bytes.Length; i += 2)
       {
           Console.WriteLine($"변수: %MW{100 + i / 2}, 값: {BitConverter.ToInt16(bytes, i)}");
       }


       //변수 %MW102에 값 10을, %MW202에 값 20을 쓰기
       //client.Write(("%MW102", 10), ("%MW202", 20));
       request = new FEnetWriteIndividualRequest(DataType.Word)
       {
           ["%MW102"] = 10,
           ["%MW202"] = 20,
       };
       var nakResponse = client.Request(request) as FEnetNAKResponse;
       if (nakResponse != null)
       {
           Console.WriteLine($"쓰기 오류 발생:{nakResponse.NAKCode}, {nakResponse.NAKCodeValue}");
       }
       //변수 %MB600(%MW300)부터 연속으로 4개의 바이트 쓰기, 쓸 값은 각각 10, 0, 20, 0
       //client.Write(DeviceType.M, 600, 10, 0, 20, 0);
       request = new FEnetWriteContinuousRequest(DeviceType.M, 600) { 10, 0, 20, 0 };
       nakResponse = client.Request(request) as FEnetNAKResponse;
       if (nakResponse != null)
       {
           Console.WriteLine($"쓰기 오류 발생:{nakResponse.NAKCode}, {nakResponse.NAKCodeValue}");
       }
   }

}

통신 요청과 응답의 로깅

[편집 | 원본 편집]

그리도 일단 통신 프레임 구조가 다르기 때문에 여기서도 소개하고자 한다.

통신을 진행하는 과정에서 발생하는 요청 메시지들과 응답 메시지들을 모니터링 하고 싶을 때는 Logger를 사용하면 된다.


Logger는 IChannelLogger 인터페이스를 구현하여 만들 수 있으며, 기본적으로 ConsoleChannelLogger, CollectionChannelLogger, StreamChannelLogger 등을 구현했다.


다음은 ConsoleChannelLogger를 이용하여 콘솔 창에 요청과 응답시 발생하는 메시지들을 출력하는 예제이다.


using System; using System.Linq; using VagabondK.Protocols.Channels; using VagabondK.Protocols.Logging; using VagabondK.Protocols.LSElectric; using VagabondK.Protocols.LSElectric.FEnet;

class Program {

   static void Main(string[] args)
   {
       FEnetClient client = new FEnetClient(new TcpChannel("127.0.0.1", 2004)
       {
           Logger = new ConsoleChannelLogger(),     //콘솔 기반 Logger 설정
       });
       foreach (var item in client.Read("%MW100", "%MW200"))
       {
           Console.WriteLine($"변수: {item.Key}, 값: {item.Value.WordValue}");
       }
       var bytes = client.Read(DeviceType.M, 200, 10).ToArray();
       for (int i = 0; i < bytes.Length; i += 2)
       {
           Console.WriteLine($"변수: %MW{100 + i / 2}, 값: {BitConverter.ToInt16(bytes, i)}");
       }
       client.Write(("%MW102", 10), ("%MW202", 20));
       client.Write(DeviceType.M, 600, 10, 0, 20, 0);
   }

}

TcpChannel 객체의 Logger 속성에 ConsoleChannelLogger를 설정햇다.


예제 코드에서 Console.WriteLine으로 직접 출력한 내용 이외에 TCP 소켓을 통해 주고 받은 내용도 함께 표시된다.

로깅 내용은 헤더 부분의 경우 LSIS-XGT 및 단종 모델인 LGIS-GLOFA 헤더 부분을 문자열로 그대로 표시하고,

나머지 부분은 통신 프로토콜 매뉴얼에서 설명하고 있는 프레임 구조에 맞게 적절하게 끊어서 표시했다.

​만약, 채널에 두 개 이상의 Logger를 설정하고 싶다면 ChannelLoggerGroup을 이용하면 된다.

다음은 ChannelLoggerGroupConsoleChannelLoggerStreamChannelLogger를 설정하는 예제이다.

using System; using System.IO; using System.Linq; using VagabondK.Protocols.Channels; using VagabondK.Protocols.Logging; using VagabondK.Protocols.LSElectric; using VagabondK.Protocols.LSElectric.FEnet;

class Program {

   static void Main(string[] args)
   {
       using (var streamChannelLogger = new StreamChannelLogger(File.OpenWrite("logs.txt")))
       {
           FEnetClient client = new FEnetClient(new TcpChannel("127.0.0.1", 2004)
           {
               Logger = new ChannelLoggerGroup(new IChannelLogger[]
               {
                   new ConsoleChannelLogger(),     //콘솔 기반 Logger 설정
                   streamChannelLogger,            //동시에 파일 스트림에도 작성함
               })
           });
           foreach (var item in client.Read("%MW100", "%MW200"))
           {
               Console.WriteLine($"변수: {item.Key}, 값: {item.Value.WordValue}");
           }
           var bytes = client.Read(DeviceType.M, 200, 10).ToArray();
           for (int i = 0; i < bytes.Length; i += 2)
           {
               Console.WriteLine($"변수: %MW{100 + i / 2}, 값: {BitConverter.ToInt16(bytes, i)}");
           }
           client.Write(("%MW102", 10), ("%MW202", 20));
           client.Write(DeviceType.M, 600, 10, 0, 20, 0);
       }
   }

}

로깅을 콘솔 창에 하면서 logs.txt 파일에도 써주게 된다. 실행하면 Console.WriteLine으로 직접 콘솔에 출력한 내용을 제외하고, 로깅 내용들만 텍스트 파일에 기록된다.

  • 테스트 환경

간단하게 FEnetSimulationService 클래스를 만들어서 가상으로만 테스트

CNet 상세 설명



실제로 실행해보면 다음의 그림과 같이 콘솔 창에 나타난다.