1. 데이터 무결성
통신에 있어서 가장 중요한 건 내 생각엔 ‘이 데이터가 유효한 데이터인가?’이다. 유선통신이던 무선 통신이던 송신 측에서 10이란 값을 보냈다면 수신 측에서 10이란 값을 정상적으로 받았는지는 아무도 알 수가 없다. 알고자 또다시 통신한다면 그때 주고받은 데이터는 유효한지 누가 보장해주는가? 이러한 문제들 때문에 패킷에 정보를 담아 주고받을 때는 이 데이터가 이상 없이 전달되었다는 검증이 필요하다. 대표적으로 Checksum 방식이나 Crc 방식 등이 있다. Checksum방식의 경우 사용자가 정의하는 Byte 단위로 모든 데이터를 더하면 된다. 예를 들어 아래와 같이 3 Byte 데이터가 있다고 가정하자.

Checksum을 1 Byte로 계산한다고 해보자. 그럼 앞서 전송하고자 하는 3 Byte를 각 자리수를 더한다. 그 더한 값을 마지막 Byte로 붙여서 총 4 Byte를 전송하면 된다. 그럼 수신 측은 전송받은 앞 3 Byte를 동일한 방식으로 더해서 마지막으로 수신받은 Byte와 비교해본다.

이러한 방식은 매우 단순한만큼 단점이 크다. 사실 우연의 일치로 오염된 Checksum Data가 맞다고 판단되는 가능성이 크기 때문이다. 단적인 예로 모든 Byte가 0으로 수신되는 오류가 발생했다고 가정하자. 그렇다면 Byte [0] ~ Byte [2]가 0이므로 Checksum은 0일 것이다. 그러면 Byte [3]도 0이므로 올바른 수신으로 볼 것이다. 이러한 문제들이 많기 때문에 사실 통신 Packet에서는 CRC방식을 많이 쓴다. CRC개념은 이해하는데 조금 힘들다. 사실 나도 아직 완전한 이해는 안 되고 가져다 쓸 수 있는 수준이다. 그렇게 때문에 자세한 설명은 위키피디아를 참고하자.
CRC란?: https://ko.m.wikipedia.org/wiki/순환_중복_검사
순환 중복 검사 - 위키백과, 우리 모두의 백과사전
ko.m.wikipedia.org
하지만 우리는 Packet의 무결성에 critical한게 아니기 때문에 단순 checksum을 채용할 것이다. 추후 CRC방식도 spec 이원화를 통해 개발해 올릴 것이다.
2. Code 구현
수신측과 송신 측은 서로 반대되는 API를 사용하게 될 것이다. 송신하는 측에서는 보내고자 하는 유효 데이터를 Checksum을 계산하여 완전한 Packet형태로 준비해야 한다. 이를 Encoding함수라 지칭할 것이다. 송신 측이 유효 데이터를 Encoding 하여 4 Byte 데이터를 송신한다.
packet Encoding_Packet(uint8_t rw, uint8_t id, uint16_t data){
packet returnPacket;
returnPacket.R.rw = rw;
returnPacket.R.id = id;
returnPacket.R.data = data;
returnPacket.R.checksum = Create_Checksum(returnPacket);
return returnPacket;
}
uint8_t Create_Checksum(packet noChecksumPacket){
uint8_t checksum;
checksum = noChecksumPacket.Byte[3] + noChecksumPacket.Byte[2] + noChecksumPacket.Byte[1];
checksum = ~(checksum) + 1;
return checksum;
}
수신측에서는 4 Byte를 수신한 뒤에 이를 해석해야 한다. 해석하기 전에 수신받은 데이터가 오염되지 않았는지 송신 측에서 보낸 3 Byte를 Checksum 계산하고 마지막 Byte와 비교하여 같은지 판별한다. 두 값이 같을 경우 유효한 데이터라 판단하고 Decoding이라는 과정을 수행한다. 약속된 Packet에 맞춰 r/w, servise ID, data를 추출해내면 된다.
packet Decoding_Packet(uint8_t *rx_buf){
packet rx_packet;
rx_packet.Byte[0] = rx_buf[0];
rx_packet.Byte[1] = rx_buf[1];
rx_packet.Byte[2] = rx_buf[2];
rx_packet.Byte[3] = rx_buf[3];
if(Check_Checksum(rx_packet) == 1){
return rx_packet;
}
else{
rx_packet.Byte[3] = 0xC5;
rx_packet.Byte[2] = 0xC5;
rx_packet.Byte[1] = 0xBA;
rx_packet.Byte[0] = 0xAD;
return rx_packet;
}
}
uint8_t Check_Checksum(packet ChecksumPacket){
uint8_t result;
result = ChecksumPacket.Byte[3] + ChecksumPacket.Byte[2] + ChecksumPacket.Byte[1] + ChecksumPacket.Byte[0];
if (result == 0)
return 1;
else
return 0;
}
Github 주소: https://github.com/DongjinJ/Arduino_Monitor.git
GitHub - DongjinJ/Arduino_Monitor: 아두이노 Data를 시각화 하는 GUI
아두이노 Data를 시각화 하는 GUI. Contribute to DongjinJ/Arduino_Monitor development by creating an account on GitHub.
github.com
임베디드 외주 제작 문의: https://open.kakao.com/o/sp32L9ke
'프로젝트 일지 > 임베디드 모니터' 카테고리의 다른 글
[임베디드 모니터] Arduino Demo Code 구현 (0) | 2023.04.06 |
---|---|
[임베디드 모니터] GUI 개발 (0) | 2022.06.08 |
[임베디드 모니터] Serial 통신 & 데이터 무결성 - 1 (0) | 2021.12.14 |
[임베디드 모니터] UI 고민 (0) | 2021.12.01 |
[임베디드 모니터] 개발 계획 (0) | 2021.09.06 |