px4-firmware/apps/gps/nmealib/tok.c

268 lines
6.1 KiB
C

/*
*
* NMEA library
* URL: http://nmea.sourceforge.net
* Author: Tim (xtimor@gmail.com)
* Licence: http://www.gnu.org/licenses/lgpl.html
* $Id: tok.c 17 2008-03-11 11:56:11Z xtimor $
*
*/
/*! \file tok.h */
#include "nmea/tok.h"
#include <stdarg.h>
#include <stdlib.h>
#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include <limits.h>
#define NMEA_TOKS_COMPARE (1)
#define NMEA_TOKS_PERCENT (2)
#define NMEA_TOKS_WIDTH (3)
#define NMEA_TOKS_TYPE (4)
//memchr replacement
void *
memchr(s, c, n)
const void *s;
unsigned char c;
size_t n;
{
if (n != 0) {
const unsigned char *p = s;
do {
if (*p++ == c)
return ((void *)(p - 1));
} while (--n != 0);
}
return (NULL);
}
/**
* \brief Calculate control sum of binary buffer
*/
int nmea_calc_crc(const char *buff, int buff_sz)
{
int chsum = 0,
it;
for(it = 0; it < buff_sz; ++it)
chsum ^= (int)buff[it];
return chsum;
}
/**
* \brief Convert string to number
*/
int nmea_atoi(const char *str, int str_sz, int radix)
{
char *tmp_ptr;
char buff[NMEA_CONVSTR_BUF];
int res = 0;
if(str_sz < NMEA_CONVSTR_BUF)
{
memcpy(&buff[0], str, str_sz);
buff[str_sz] = '\0';
res = strtol(&buff[0], &tmp_ptr, radix);
}
return res;
}
/**
* \brief Convert string to fraction number
*/
float nmea_atof(const char *str, int str_sz)
{
char *tmp_ptr;
char buff[NMEA_CONVSTR_BUF];
float res = 0;
if(str_sz < NMEA_CONVSTR_BUF)
{
memcpy(&buff[0], str, str_sz);
buff[str_sz] = '\0';
res = (float)strtod(&buff[0], &tmp_ptr);
}
return res;
}
/**
* \brief Formating string (like standart printf) with CRC tail (*CRC)
*/
int nmea_printf(char *buff, int buff_sz, const char *format, ...)
{
int retval, add = 0;
va_list arg_ptr;
if(buff_sz <= 0)
return 0;
va_start(arg_ptr, format);
retval = NMEA_POSIX(vsnprintf)(buff, buff_sz, format, arg_ptr);
if(retval > 0)
{
add = NMEA_POSIX(snprintf)(
buff + retval, buff_sz - retval, "*%02x\r\n",
nmea_calc_crc(buff + 1, retval - 1));
}
retval += add;
if(retval < 0 || retval > buff_sz)
{
memset(buff, ' ', buff_sz);
retval = buff_sz;
}
va_end(arg_ptr);
return retval;
}
/**
* \brief Analyse string (specificate for NMEA sentences)
*/
int nmea_scanf(const char *buff, int buff_sz, const char *format, ...)
{
const char *beg_tok;
const char *end_buf = buff + buff_sz;
va_list arg_ptr;
int tok_type = NMEA_TOKS_COMPARE;
int width = 0;
const char *beg_fmt = 0;
int snum = 0, unum = 0;
int tok_count = 0;
void *parg_target;
va_start(arg_ptr, format);
for(; *format && buff < end_buf; ++format)
{
switch(tok_type)
{
case NMEA_TOKS_COMPARE:
if('%' == *format)
tok_type = NMEA_TOKS_PERCENT;
else if(*buff++ != *format)
goto fail;
break;
case NMEA_TOKS_PERCENT:
width = 0;
beg_fmt = format;
tok_type = NMEA_TOKS_WIDTH;
case NMEA_TOKS_WIDTH:
if(isdigit(*format))
break;
{
tok_type = NMEA_TOKS_TYPE;
if(format > beg_fmt)
width = nmea_atoi(beg_fmt, (int)(format - beg_fmt), 10);
}
case NMEA_TOKS_TYPE:
beg_tok = buff;
if(!width && ('c' == *format || 'C' == *format) && *buff != format[1])
width = 1;
if(width)
{
if(buff + width <= end_buf)
buff += width;
else
goto fail;
}
else
{
if(!format[1] || (0 == (buff = (char *)memchr(buff, format[1], end_buf - buff))))
buff = end_buf;
}
if(buff > end_buf)
goto fail;
tok_type = NMEA_TOKS_COMPARE;
tok_count++;
parg_target = 0; width = (int)(buff - beg_tok);
switch(*format)
{
case 'c':
case 'C':
parg_target = (void *)va_arg(arg_ptr, char *);
if(width && 0 != (parg_target))
*((char *)parg_target) = *beg_tok;
break;
case 's':
case 'S':
parg_target = (void *)va_arg(arg_ptr, char *);
if(width && 0 != (parg_target))
{
memcpy(parg_target, beg_tok, width);
((char *)parg_target)[width] = '\0';
}
break;
case 'f':
case 'g':
case 'G':
case 'e':
case 'E':
parg_target = (void *)va_arg(arg_ptr, float *);
if(width && 0 != (parg_target))
*((float *)parg_target) = nmea_atof(beg_tok, width);
break;
};
if(parg_target)
break;
if(0 == (parg_target = (void *)va_arg(arg_ptr, int *)))
break;
if(!width)
break;
switch(*format)
{
case 'd':
case 'i':
snum = nmea_atoi(beg_tok, width, 10);
memcpy(parg_target, &snum, sizeof(int));
break;
case 'u':
unum = nmea_atoi(beg_tok, width, 10);
memcpy(parg_target, &unum, sizeof(unsigned int));
break;
case 'x':
case 'X':
unum = nmea_atoi(beg_tok, width, 16);
memcpy(parg_target, &unum, sizeof(unsigned int));
break;
case 'o':
unum = nmea_atoi(beg_tok, width, 8);
memcpy(parg_target, &unum, sizeof(unsigned int));
break;
default:
goto fail;
};
break;
};
}
fail:
va_end(arg_ptr);
return tok_count;
}