tok.c 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250
  1. /*
  2. *
  3. * NMEA library
  4. * URL: http://nmea.sourceforge.net
  5. * Author: Tim (xtimor@gmail.com)
  6. * Licence: http://www.gnu.org/licenses/lgpl.html
  7. * $Id: tok.c 17 2008-03-11 11:56:11Z xtimor $
  8. *
  9. */
  10. /*! \file tok.h */
  11. #include "nmea/tok.h"
  12. #include <stdarg.h>
  13. #include <stdlib.h>
  14. #include <stdio.h>
  15. #include <ctype.h>
  16. #include <string.h>
  17. #include <limits.h>
  18. #define NMEA_TOKS_COMPARE (1)
  19. #define NMEA_TOKS_PERCENT (2)
  20. #define NMEA_TOKS_WIDTH (3)
  21. #define NMEA_TOKS_TYPE (4)
  22. /**
  23. * \brief Calculate control sum of binary buffer
  24. */
  25. int nmea_calc_crc(const char *buff, int buff_sz)
  26. {
  27. int chsum = 0,
  28. it;
  29. for(it = 0; it < buff_sz; ++it)
  30. chsum ^= (int)buff[it];
  31. return chsum;
  32. }
  33. /**
  34. * \brief Convert string to number
  35. */
  36. int nmea_atoi(const char *str, int str_sz, int radix)
  37. {
  38. char *tmp_ptr;
  39. char buff[NMEA_CONVSTR_BUF];
  40. int res = 0;
  41. if(str_sz < NMEA_CONVSTR_BUF)
  42. {
  43. memcpy(&buff[0], str, str_sz);
  44. buff[str_sz] = '\0';
  45. res = strtol(&buff[0], &tmp_ptr, radix);
  46. }
  47. return res;
  48. }
  49. /**
  50. * \brief Convert string to fraction number
  51. */
  52. double nmea_atof(const char *str, int str_sz)
  53. {
  54. char *tmp_ptr;
  55. char buff[NMEA_CONVSTR_BUF];
  56. double res = 0;
  57. if(str_sz < NMEA_CONVSTR_BUF)
  58. {
  59. memcpy(&buff[0], str, str_sz);
  60. buff[str_sz] = '\0';
  61. res = strtod(&buff[0], &tmp_ptr);
  62. }
  63. return res;
  64. }
  65. /**
  66. * \brief Formating string (like standart printf) with CRC tail (*CRC)
  67. */
  68. int nmea_printf(char *buff, int buff_sz, const char *format, ...)
  69. {
  70. int retval, add = 0;
  71. va_list arg_ptr;
  72. if(buff_sz <= 0)
  73. return 0;
  74. va_start(arg_ptr, format);
  75. retval = NMEA_POSIX(vsnprintf)(buff, buff_sz, format, arg_ptr);
  76. if(retval > 0)
  77. {
  78. add = NMEA_POSIX(snprintf)(
  79. buff + retval, buff_sz - retval, "*%02x\r\n",
  80. nmea_calc_crc(buff + 1, retval - 1));
  81. }
  82. retval += add;
  83. if(retval < 0 || retval > buff_sz)
  84. {
  85. memset(buff, ' ', buff_sz);
  86. retval = buff_sz;
  87. }
  88. va_end(arg_ptr);
  89. return retval;
  90. }
  91. /**
  92. * \brief Analyse string (specificate for NMEA sentences)
  93. */
  94. int nmea_scanf(const char *buff, int buff_sz, const char *format, ...)
  95. {
  96. const char *beg_tok;
  97. const char *end_buf = buff + buff_sz;
  98. va_list arg_ptr;
  99. int tok_type = NMEA_TOKS_COMPARE;
  100. int width = 0;
  101. const char *beg_fmt = 0;
  102. int snum = 0, unum = 0;
  103. int tok_count = 0;
  104. void *parg_target;
  105. va_start(arg_ptr, format);
  106. for(; *format && buff < end_buf; ++format)
  107. {
  108. switch(tok_type)
  109. {
  110. case NMEA_TOKS_COMPARE:
  111. if('%' == *format)
  112. tok_type = NMEA_TOKS_PERCENT;
  113. else if(*buff++ != *format)
  114. goto fail;
  115. break;
  116. case NMEA_TOKS_PERCENT:
  117. width = 0;
  118. beg_fmt = format;
  119. tok_type = NMEA_TOKS_WIDTH;
  120. case NMEA_TOKS_WIDTH:
  121. if(isdigit(*format))
  122. break;
  123. {
  124. tok_type = NMEA_TOKS_TYPE;
  125. if(format > beg_fmt)
  126. width = nmea_atoi(beg_fmt, (int)(format - beg_fmt), 10);
  127. }
  128. case NMEA_TOKS_TYPE:
  129. beg_tok = buff;
  130. if(!width && ('c' == *format || 'C' == *format) && *buff != format[1])
  131. width = 1;
  132. if(width)
  133. {
  134. if(buff + width <= end_buf)
  135. buff += width;
  136. else
  137. goto fail;
  138. }
  139. else
  140. {
  141. if(!format[1] || (0 == (buff = (char *)memchr(buff, format[1], end_buf - buff))))
  142. buff = end_buf;
  143. }
  144. if(buff > end_buf)
  145. goto fail;
  146. tok_type = NMEA_TOKS_COMPARE;
  147. tok_count++;
  148. parg_target = 0; width = (int)(buff - beg_tok);
  149. switch(*format)
  150. {
  151. case 'c':
  152. case 'C':
  153. parg_target = (void *)va_arg(arg_ptr, char *);
  154. if(width && 0 != (parg_target))
  155. *((char *)parg_target) = *beg_tok;
  156. break;
  157. case 's':
  158. case 'S':
  159. parg_target = (void *)va_arg(arg_ptr, char *);
  160. if(width && 0 != (parg_target))
  161. {
  162. memcpy(parg_target, beg_tok, width);
  163. ((char *)parg_target)[width] = '\0';
  164. }
  165. break;
  166. case 'f':
  167. case 'g':
  168. case 'G':
  169. case 'e':
  170. case 'E':
  171. parg_target = (void *)va_arg(arg_ptr, double *);
  172. if(width && 0 != (parg_target))
  173. *((double *)parg_target) = nmea_atof(beg_tok, width);
  174. break;
  175. };
  176. if(parg_target)
  177. break;
  178. if(0 == (parg_target = (void *)va_arg(arg_ptr, int *)))
  179. break;
  180. if(!width)
  181. break;
  182. switch(*format)
  183. {
  184. case 'd':
  185. case 'i':
  186. snum = nmea_atoi(beg_tok, width, 10);
  187. memcpy(parg_target, &snum, sizeof(int));
  188. break;
  189. case 'u':
  190. unum = nmea_atoi(beg_tok, width, 10);
  191. memcpy(parg_target, &unum, sizeof(unsigned int));
  192. break;
  193. case 'x':
  194. case 'X':
  195. unum = nmea_atoi(beg_tok, width, 16);
  196. memcpy(parg_target, &unum, sizeof(unsigned int));
  197. break;
  198. case 'o':
  199. unum = nmea_atoi(beg_tok, width, 8);
  200. memcpy(parg_target, &unum, sizeof(unsigned int));
  201. break;
  202. default:
  203. goto fail;
  204. };
  205. break;
  206. };
  207. }
  208. fail:
  209. va_end(arg_ptr);
  210. return tok_count;
  211. }