참고 문헌 : http://www.simplymodbus.ca/ASCII.htm

 

Modbus ASCII vs RTU | Simply Modbus Software

 

www.simplymodbus.ca

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();
    }
   
  
}

Test 결과

 

제발 이거 보고 짜길 바란다..ㅎ;;;

+ Recent posts