본 포스팅에서 다뤄볼 내용은 NMEA-0183 문장의 checksum 계산 방법이다.
보통 GPS chip은 해석한 GPS신호를 NMEA라는 특정 형태의 프로토콜로 제공한다.
NMEA 가 무엇인지에 대해서 더 자세히 알고싶다면 아래 포스팅을 참고하도록 하자.
2017/08/10 - [하드웨어 Note/GPS 이야기] - [GPS 이야기] NMEA-0183 형식, NMEA Sentence Format
위 포스팅에 나와있듯이, NMEA sentence는 $ 문자로 시작해서 * 문자로 끝난다.
checksum의 계산은 $, * 의 사이에 있는 각각의 문자 하나하나를 exclusive-or (XOR) 연산 및 누적하면 된다.
어떤 NMEA sentence가 주어졌을 때, "*" 뒤에 있는 16진수 두자리의 checksum도 같이 주어질 텐데, 직접 XOR연산하여 checksum을 계산한 값과 주어진 checksum값이 일치하는지를 검사해야 한다. 일치하지 않는다면, 그 sentence는 통신상의 문제 등의 이유로, 결함이 있는 것으로 간주해야 하며, 사용하면 안된다.
구체적인 계산 예제 코드를 제시한다.
NMEA 체크섬 계산 함수(JAVA 버전)
char checkSum(String nmeaStr) {
char check = 0;
// iterate over the string, XOR each byte with the total sum:
for (int c = 0; c < theseChars.length(); c++) {
check = char(check ^ theseChars.charAt(c));
}
// return the result
return check;
}
인자 'nmeaStr' 은 $와 * 사이의 NMEA문자열을 넣으면 된다. 각 문자 하나하나를 XOR연산하여 'check' 변수에 저장하여 반환한다.
return type은 char 이다. 이것을 2bytes hex string으로 변환해서 사용하면 된다.
NMEA 체크섬 계산 함수 (C 버전 1)
#include <stdint.h>
#define NMEA_END_CHAR_1 '\n'
#define NMEA_MAX_LENGTH 70
uint8_t
nmea_get_checksum(const char *nmea_str)
{
const char *n = NULL;
uint8_t chk = 0;
if (strcmp(nmea_str[0], '$') == 0) {
n = nmea_str + 1; // skip '$' by plus one
} else {
n = nmea_str;
}
/* While current char isn't '*' or sentence ending (newline) */
while ('*' != *n && NMEA_END_CHAR_1 != *n) {
if ('\0' == *n || n - sentence > NMEA_MAX_LENGTH) {
/* Sentence too long or short */
return 0;
}
chk ^= (uint8_t) *n;
n++;
}
return chk;
}
인자 nmea_str은 $와 * 사이의 NMEA sentence를 넣으면 된다. 그러나 만약 인자로 들어오는 NMEA sentence가 $ 를 포함하고 있다면 생략하도록 방어코드를 넣어 두었다.
이제, checksum 값은 아래와 같이 계산하면 된다.
GPRMCBuf 가 NMEA sentence이다.
uint8_t chk = nmea_get_checksum(GPRMCBuf);
NMEA 체크섬 계산 함수 (C 버전 2)
또다른 방법으로 NMEA의 checksum 계산을 구현한 C언어 버전이다.
첫번째 인자 'buf'가 계산하려는 NMEA sentence이다. 위의 버전1과는 달리 $ 부터 * 까지의 NMEA sentence를 인자로 넣어도 된다.
두번째 인자 'len'는 buf의 길이이다.
int calc_NMEA_Checksum( char *buf, int len )
{
char Character;
int Checksum = 0;
int i; // loop counter
// foreach(char Character in sentence)
for (i=0; i < len; ++i)
{
Character = buf[i];
switch(Character)
{
case '$':
// Ignore the dollar sign
break;
case '*':
// Stop processing before the asterisk
i = len;
continue;
default:
// Is this the first value for the checksum?
if (Checksum == 0)
{
// Yes. Set the checksum to the value
Checksum = Character;
}
else
{
// No. XOR the checksum with this character's value
Checksum = Checksum ^ Character;
}
break;
}
}
// Return the checksum
return Checksum;
}
이 함수를 통해 checksum을 계산하면 int 형 결과가 반환된다.
이제, 비교하려는 NMEA sentence에서 2bytes의 char형 checksum 문자를 읽고, 1byte의 hex형으로 변환 한 후, 위 함수의 반환값과 비교하면 된다.
'개발자의 기록 노트 > GPS 이야기' 카테고리의 다른 글
[GPS 이야기] NMEA-0183 형식, NMEA Sentence Format (6) | 2017.08.10 |
---|---|
[GPS 이야기] TTFF와 Almanac, Ephemeris 그리고, GPS의 start 방식, Cold start/Hot start/Warm Start ? (2) | 2017.04.13 |