티스토리 뷰

심화

패킷 통신 - Start/Stop flag

Just4Fun 2016. 8. 10. 20:13

이번 글에서는 데이터를 수신하는 측에서 패킷의 시작과 끝을 알 수 있게 하는 방법에 대해서 설명하도록 하겠다.


패킷의 시작과 끝을 알수 있게 하는 방법은 무수히 많겠지만, 이미 잘 알고 있는 방법중에서 아이디어를 빌려오도록 하겠다.  그것은 다름아닌 HDLC(High-Level Data Link Control)를 이용하는 것이다.  HDLC는 IBM의 SDLC라는 프로토콜을 국제적으로 표준화한 방법인데, 기본 적인 패킷의 구조는 다음과 같다.


위의 그림에 보이는것처럼 패킷의 시작과 끝에 8비트 크기의 Flag 필드가 있다.  이 플래그는 이진수로 '01111110'의 값을 가진다. 헥사값으로 표시하면 '0x7E'이다.  나머지 필드들은 다음에 설명하기로 하고, 이번글에서는 Flag필드에만 초점을 맞추어 설명하도록 하겠다.


데이터를 송신하는 측에서 패킷의 시작과 끝부분에 Flag를 추가해주면 데이터를 수신하는 측에서는 flag값을 모니터링하여 데이터의 시작과 끝을 알수 있을것이다.


이제, 위의 설명에 따라 AK9875에서 추출한 데이터에 flag 필드를 추가하여 송신하는 프로그램을 만들어 보기로 하겠다.

패킷을 송신하는 send_packet()이라는 함수를 만들었다.  7, 14번 줄에 패킷데이터 앞뒤에 각각 start/stop flag를 추가해주는 코드가 들어가 있는 것을 볼 수 있다.


loop() 함수에서 send_packet() 함수를 불러 AK8975에서 얻은 값을 내보내도록 하였다.


데이터를 수신하는 컴퓨터에서는 어떻게 들어오는지 확인을 해보면 다음과 같은 결과를 볼 수 있다.

의도했던대로 패킷의 앞뒤에 Start/Stop flag가 덧붙여져 있는 것을 확인할 수 있다.

이제 수신측에서는 Start flag를 보고 있다가 start flag가 들어오면 그 다음 데이터부터 마지막 stop flag가 수신되기 직전까지의 데이터가 하나의 패킷이라 가정하고 처리하면 될것이다.


그러나 곰곰히 생각해 보면 한가지 문제점을 발견할 수 있을것이다.  만약 패킷안의 데이터 중에 하필이면 '0x7E'라는 값이 들어 있으면 어떻게 될까?  수신하는 측에서는 당연히 stop flag라고 판단하게 될것이다.  결과적으로 엉뚱하게 데이터가 처리될것이다.


하드웨어로 만들어진 HDLC 장비의 경우에는 이러한 문제점을 해결하기 위하여 보내는 쪽에서 데이터 중에 0x7E라는 데이터를 발견하면, 즉, 다시말해서 비트값 '1'이 연속해서 6개가 들어있으면 6번째비트에 0을 추가하여 1의 값이 연속해서 6번 발생하지 않도록 한다.  즉 1이 연속해서 5번 발생하면 무조건 0을 추가한다.  수신측 장비는 수신된 데이터 비트값에 1의 개수가 연속해서 5개 있으면 그다음에 오는 0은 무조건 버리도록 만든다.


하지만 소프트웨어적으로 이러한 방법으로 구현하기가 불가능하므로 다른 방법을 이용하여 문제를 해결하여야 된다.  데이터 중에 Start/Stop flag값이 있으면 일단 먼저 '0x7D'라는 escape 문자를 보내고 실제 데이터인 '0x7E'에 0x20을 exclusive-or를 하여 0x5E라는 데이터로 바꾸어서 내보내도록 한다.   그럼 수신하는 측에서는 데이터 중에 0x7D가 있으면 이 데이터는 버리고 다음에 따라오는 데이터를 0x20으로 exclusive-or를 수행하여 0x5E를 0x7E로 복구하면 될것이다.


Flag값과 동일한 데이터는 이렇게 하면 해결이 되었지만, 또다시 새로운 문제가 발생하게 된다.  이번에는 패킷안에 0x7D라는 데이터가 있게 되면 받는쪽에서 이 데이터를 버릴것이고 뒤따라 들어오는 데이터에 0x20으로 exclusive-or를 해서 엉뚱한 데이터를 만들게 될 것이다.


이 문제 역시 0x7D에 대해서도 flag값에 해당하는 데이터를 처리한것과 동일한 방법을 적용하여 이러한 문제를 해결할 수 있다.  데이터 중에 0x7D가 있으면 먼저 0x7D를 보내고 0x20으로 exclusive-or를 수행하여 0x5D로 변환하여 내 보내면 된다.  수신하는 측에서는 0x7D가 들어오면 이 데이터는 버리고 뒤이어 들어오는 데이터에 0x20으로 exclusive-or를 수행하면 이제 모든것이 해결될 것이다.


이러한 내용을 코드로 만들어 보면 다음과 같이 될것이다.


데이터 안에 Start/Stop flag가 있거나, escape 문자가 있을때 이를 처리하기 위한 방법이 추가된 것을 볼 수 있다.  실제로 데이터안에 인위적으로 이러한 flag 데이터를 집어 넣어 수신하는 측에서는 어떻게 들어오는지 확인해 본다.


5,6번줄에서 의도적으로 데이터를 바꾸었다.  이렇게 했을때 수신측에서의 결과는 다음과 같다.

그림의 빨간색 박스안에 보이는것처럼 0x7E라는 데이터가 '0x7D,0x5E'로 바뀌어져 있고, 0x7D는 '0x7D,0x5D'로 바뀌어져 있는것을 볼 수 있다.


송신측 기능은 확인하였으므로 수신측에서 flag필드와 escape 데이터를 처리하는 기능을 구현해 보도록 하겠다. 


그리고, 여기에 한가지 더 기능을 추가하도록 한다.  만약, 수신하는 측에서 프로그램을 시작하면서 데이터를 수신하였는데, 하필이면 패킷의 중간부분부터 데이터를 받게 되면 어떻게 될까?  수신측에서는 Flag 필드만 보고 있을것이므로 실제 Stop flag를 Start flag로 오인하게 될 수 있다.  따라서 뒤이어 들어오는 실제 Start flag가 Stop flag가 될것이고.

이렇게 되면 데이터 수신을 무한히 할 수 없게 되는 상황이 발생하게 된다.


이런 문제를 해결하는 방법도 같이 구현해 보도록 하겠다.

수신되는 패킷을 처리하기 위한 Packet이라는 클래스를 만들었다.  클래스에 있는 method중에서 packetIn은 Start/Stop 플래그에 대한 처리부분이다.  만약 데이터 중간부분에서부터 프로그램이 시작되면 Stop flag를 먼저 검출할 것이고 이를 Start flag로 인식하게 될것이다.  그러나 연속해서 flag 값이 들어오면 두번째 들어온 flag가 진짜 start flag가 됨을 알수 있게 된다.

processInPacket method는 수신된 패킷안에 flag값이나 escape 문자가 들어 있는지 처리하는 기능을 수행한다.  데이터 처리가 모두 끝나면 처리된 데이터를 parent class의 processPacket을 불러서 화면에 출력하도록 한다.


이제는 연속해서 들어오는 데이터가 아니라 하나의 패킷 형태를 가지므로 패킷단위로 출력이 가능하다.


위의 코드들을 적용한 컴퓨터에서 실행되는 수신 프로그램의 결과는 다음과 같다.

flag 처리가 제대로 되었음을 알수 있다.


packet.c

SerialPacket.py



심화 과정 목차

'심화' 카테고리의 다른 글

패킷 통신 - Message ID  (0) 2016.08.12
패킷 통신 - CRC  (2) 2016.08.11
패킷 통신 - 바이너리 데이터(Binary data)  (0) 2016.08.03
패킷 통신 - PC 프로그램  (0) 2016.08.03
패킷 통신 - 회로 구성  (0) 2016.07.30
댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
TAG
more
«   2024/05   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31
글 보관함