[LRC] LRC 계산 코드 만들기
참고 문헌 : http://www.simplymodbus.ca/ASCII.htm
Modbus RTU는 구현을 했고... Modbus Ascii를 구현하기 위해 필요한 LRC...
LRC가 뭔지 찾아보니깐 Longitudinal Redundancy Check 라는 놈이란다.
구글 번역기 왈 "종 방향 중복검사"
흠... 뭔 소리지... 일단 에러 체크 방법 중 하나기는 한데...
에러를 어떻게 체크하는지 알아보니깐
LRC 이전 Ascii 코드를 바이너리로 다 바꾼 다음에,
다 더하고, 2의 보수를 취해준 결과값을 LRC랑 비교를 한다고 한다.
음... 그렇구나 ㅎㅎ
그건 그렇고 그래서 LRC는 어떻게 구하는데?
찾아보니
이렇게 구한단다.
1. byte를 모두 더해준다~
2. 8bit가 넘어가는 carry는 삭제!
3. 2의 보수를 취해준다~
4. 쨘
무지 간단하네 ㅋㅋㅋ
바로 코드로 옮겨보았다.
calcLRC()_python
def calcLRC(data):
#Add the RTU Value
RTU_sum = ((sum(data) & 0xff) ^ 0xff) + 0x01
lrc = [RTU_sum >> 4, RTU_sum & 0xf]
return lrc
뭐가 이리 간단해?ㅋㅋㅋ
입력값은 이렇다.
LRC = calcLRC([0x11, 0x03, 0x00, 0x6B, 0x00, 0x03])
위의 코드를 해석해보자면.... 음... 일단 다 더하고? 비트 연산을 이용해서 8bit 이후의 값은 제거해주고, 1의 보수를 취해준 다음에 1을 뙇 더해주면?(2의 보수지요)
끗.
그 결과를 Hi, Lo 두 개로 나눠서 리스트에 넣고 반환해줬다.
진짜 되는지는 PLC에서 확인해봐야겠찌 ㅎㅎ
hexToAscii()_python
def hexToAscii(data):
ret = []
for d in data:
ret.append(ord(format(d, 'X')))
return ret
추가로 hex를 Ascii로 바꿔주는 함수이다.
data 타입은 calcLRC와 동일!
코드를 쪼금만 분석해보자면....
format(d, 'X') : d를 대문자 hexa형태의 String으로 변환해주는 것이다.
즉, d에 10이라는 int 타입이 있다면 10의 hex값은 A이니깐
format(d, 'X') = "A"라는 의미.
ord(parameter) : parameter를 Ascii값으로 바꿔주는 놈이다!
c의 경우 char라는 아주 좋은 타입이 있어서 'A' 하면 바로 Ascii로 인식되지만 이놈의 파이썬은 타입관련된 내용들이 참 그지같다..ㅎ
무튼 parameter가 'A'라면 A의 아스키코드값은 65(=0x41) 이므로 해당 값을 int 형태로 반환한다.
추가_2020.09.16
Java로 코드를 짜봤다.
이번에는 인풋이 그냥 ASCII String 형태로 들어올 때 출력해주는 걸로 짜봤다.
package test;
class Hello {
public static void main(String[] args) {
String s = "0101000A0001";
//반환된 LRC값을 기존 명령 코드에 추가한다.
s=s + calcLRC(s);
//완성된 명령 코드 앞뒤에 Head와 Tail을 붙여 ASCII to Byte로 변환한 후 전송한다.
byte[] s_byte = s.getBytes();
byte[] head = {0x3A};
byte[] tail = {0x0D, 0x0A};
byte[] result_b = new byte[head.length + s_byte.length + tail.length];
System.arraycopy(head, 0, result_b, 0, head.length);
System.arraycopy(s_byte, 0, result_b, head.length, s_byte.length);
System.arraycopy(tail, 0, result_b, head.length+s_byte.length, tail.length);
String result_s = new String(result_b);
System.out.print("HEX : ");
for (byte b : result_b){
System.out.print("0x"+Integer.toHexString(b).toUpperCase()+ " ");
}
System.out.println();
System.out.println("ASCII: " + result_s);
System.out.println("(CR LF는 공백이라서 표시 안됨)");
}
static String calcLRC(String s) {
int sum = 0;
int len = s.length();
for(int i=0; i<len; i=i+2) {
//String을 1byte씩 잘라 Integer로 변환 한 값을 전부 더한다.
String subS = s.substring(i, i+2);
sum += Integer.parseInt(subS, 16);
}
//2's complement 수행
sum = (((sum & 0xff) ^ 0xff) + 0x01);
//상위 4bit, 하위 4bit로 자른다.
int lrcH = sum >> 4;
int lrcL = sum & 0xf;
//자른 Bit를 다시 ASCII(HexaString 형태)로 변환한다.
String res = Integer.toHexString(lrcH) + Integer.toHexString(lrcL);
return res.toUpperCase();
}
}
제발 이거 보고 짜길 바란다..ㅎ;;;