libfap  1.5
helpers2.c
Go to the documentation of this file.
1 /* $Id: helpers2.c 227 2015-01-31 12:27:07Z oh2gve $
2  *
3  * Copyright 2005-2012 Tapio Sokura
4  * Copyright 2007-2012 Heikki Hannikainen
5  *
6  * Perl-to-C modifications
7  * Copyright 2009-2014 Tapio Aaltonen
8  *
9  * This file is part of libfap.
10  *
11  * Libfap is free software; you can redistribute it and/or modify it under the
12  * terms of either:
13  *
14  * a) the GNU General Public License as published by the Free Software
15  * Foundation; either version 1, or (at your option) any later
16  * version, or
17  *
18  * b) the "Artistic License".
19  *
20  * Both licenses can be found in the licenses directory of this source code
21  * package.
22  *
23  * APRS is a registered trademark of APRS Software and Bob Bruninga, WB4APR.
24 */
25 
33 #include "helpers2.h"
34 #include "fap.h"
35 #include "regs.h"
36 #ifdef HAVE_CONFIG_H
37 #include <config.h>
38 #endif
39 
40 #include <stdio.h>
41 #include <stdlib.h>
42 #include <string.h>
43 #include <regex.h>
44 #include <ctype.h>
45 #include <math.h>
46 
47 
48 
50 {
51  fapint_llist_item_t* current_elem = list, *tmp_elem;
52 
53  while ( current_elem != NULL )
54  {
55  if ( current_elem->text ) free(current_elem->text);
56  tmp_elem = current_elem->next;
57  free(current_elem);
58  current_elem = tmp_elem;
59  }
60 }
61 
62 
63 
64 double fapint_get_pos_resolution(int const minute_digit_count)
65 {
66  double retval = KNOT_TO_KMH;
67  if ( minute_digit_count <= -2 )
68  {
69  retval *= 600;
70  }
71  else
72  {
73  retval *= 1000;
74  }
75  return retval * pow(10, -1*minute_digit_count);
76 }
77 
78 
79 
81 {
82  int len;
83  char leftover_str[3];
84  char type;
85 
86  char numberid_str[3];
87  int numberid;
88 
89  char dst_type[2];
90  char overlay;
91  char code[2];
92  char tmp_2b[2];
93 
94  unsigned int const matchcount = 3;
95  regmatch_t matches[matchcount];
96 
97 
98  /* Check parameters. */
99  if ( !packet || !packet->dst_callsign )
100  {
101  return 0;
102  }
103 
104  /* Check if destination callsign seems to contain symbol info. */
105  if ( regexec(&fapint_regex_nmea_dst, packet->dst_callsign, matchcount, (regmatch_t*)&matches, 0) == 0 )
106  {
107  /* Save symbol-containing part. */
108  len = matches[2].rm_eo - matches[2].rm_so;
109  memset(leftover_str, 0, 3);
110  memcpy(leftover_str, packet->dst_callsign+matches[2].rm_so, len);
111 
112  type = leftover_str[0];
113 
114  if ( len == 3 )
115  {
116  if ( type == 'C' || type == 'E' )
117  {
118  /* Get id. */
119  memset(numberid_str, 0, 3);
120  numberid_str[0] = leftover_str[1];
121  numberid_str[1] = leftover_str[2];
122  numberid = atoi(numberid_str);
123 
124  /* Save symbol, if id is valid. */
125  if ( numberid > 0 && numberid < 95 )
126  {
127  packet->symbol_code = numberid + 32;
128  if ( type == 'C' )
129  {
130  packet->symbol_table = '/';
131  }
132  else
133  {
134  packet->symbol_table = '\\';
135  }
136  return 1;
137  }
138  else
139  {
140  /* Invalid id. */
141  return 0;
142  }
143  }
144  else
145  {
146  /* Secondary symbol table, with overlay. Check first that we really are in the secondary symbol table. */
147  dst_type[0] = leftover_str[0];
148  dst_type[1] = leftover_str[1];
149  overlay = leftover_str[2];
150  if ( (type == 'O' || type == 'A' || type == 'N' ||
151  type == 'D' || type == 'S' || type == 'Q') &&
152  isalnum(overlay) )
153  {
154  if ( fapint_symbol_from_dst_type(dst_type, code) )
155  {
156  packet->symbol_table = overlay;
157  packet->symbol_code = code[1];
158  return 1;
159  }
160  else
161  {
162  /* Could not map into APRS symbol. */
163  return 0;
164  }
165  }
166  else
167  {
168  /* Propably not in first symbol table. */
169  return 0;
170  }
171  }
172  }
173  else
174  {
175  /* Primary or secondary symbol table, no overlay. */
176  tmp_2b[0] = leftover_str[0];
177  tmp_2b[1] = leftover_str[1];
178  if ( fapint_symbol_from_dst_type(tmp_2b, code) )
179  {
180  packet->symbol_table = code[0];
181  packet->symbol_code = code[1];
182  return 1;
183  }
184  else
185  {
186  /* Could not map into APRS symbol. */
187  return 0;
188  }
189  }
190  }
191  else
192  {
193  return 0;
194  }
195 
196  /* Failsafe catch-all. */
197  return 0;
198 }
199 
200 
201 
202 int fapint_symbol_from_dst_type(char input[2], char* output)
203 {
204  switch ( input[0] )
205  {
206  case 'B':
207  case 'O':
208  if ( input[0] == 'B' )
209  {
210  output[0] = '/';
211  }
212  else
213  {
214  output[0] = '\\';
215  }
216  switch ( input[1] )
217  {
218  case 'B':
219  output[1] = '!';
220  return 1;
221  case 'C':
222  output[1] = '"';
223  return 1;
224  case 'D':
225  output[1] = '#';
226  return 1;
227  case 'E':
228  output[1] = '$';
229  return 1;
230  case 'F':
231  output[1] = '%';
232  return 1;
233  case 'G':
234  output[1] = '&';
235  return 1;
236  case 'H':
237  output[1] = '\'';
238  return 1;
239  case 'I':
240  output[1] = '(';
241  return 1;
242  case 'J':
243  output[1] = ')';
244  return 1;
245  case 'K':
246  output[1] = '*';
247  return 1;
248  case 'L':
249  output[1] = '+';
250  return 1;
251  case 'M':
252  output[1] = ',';
253  return 1;
254  case 'N':
255  output[1] = '-';
256  return 1;
257  case 'O':
258  output[1] = '.';
259  return 1;
260  case 'P':
261  output[1] = '/';
262  return 1;
263  }
264  return 0;
265  case 'P':
266  case 'A':
267  if ( input[0] == 'P' )
268  {
269  output[0] = '/';
270  }
271  else
272  {
273  output[0] = '\\';
274  }
275  if ( isdigit(input[1]) || isupper(input[1]) )
276  {
277  output[1] = input[1];
278  return 1;
279  }
280  return 0;
281  case 'M':
282  case 'N':
283  if ( input[0] == 'M' )
284  {
285  output[0] = '/';
286  }
287  else
288  {
289  output[0] = '\\';
290  }
291  switch ( input[1] )
292  {
293  case 'R':
294  output[1] = ':';
295  return 1;
296  case 'S':
297  output[1] = ';';
298  return 1;
299  case 'T':
300  output[1] = '<';
301  return 1;
302  case 'U':
303  output[1] = '=';
304  return 1;
305  case 'V':
306  output[1] = '>';
307  return 1;
308  case 'W':
309  output[1] = '?';
310  return 1;
311  case 'X':
312  output[1] = '@';
313  return 1;
314  }
315  return 0;
316  case 'H':
317  case 'D':
318  if ( input[0] == 'H' )
319  {
320  output[0] = '/';
321  }
322  else
323  {
324  output[0] = '\\';
325  }
326  switch ( input[1] )
327  {
328  case 'S':
329  output[1] = '[';
330  return 1;
331  case 'T':
332  output[1] = '\\';
333  return 1;
334  case 'U':
335  output[1] = ']';
336  return 1;
337  case 'V':
338  output[1] = '^';
339  return 1;
340  case 'W':
341  output[1] = '_';
342  return 1;
343  case 'X':
344  output[1] = '`';
345  return 1;
346  }
347  return 0;
348  case 'L':
349  case 'S':
350  if ( input[0] == 'L' )
351  {
352  output[0] = '/';
353  }
354  else
355  {
356  output[0] = '\\';
357  }
358  if ( isupper(input[1]) )
359  {
360  output[1] = tolower(input[1]);
361  return 1;
362  }
363  return 0;
364  case 'J':
365  case 'Q':
366  if ( input[0] == 'J' )
367  {
368  output[0] = '/';
369  }
370  else
371  {
372  output[0] = '\\';
373  }
374  switch ( input[1] )
375  {
376  case '1':
377  output[1] = '{';
378  return 1;
379  case '2':
380  output[1] = '|';
381  return 1;
382  case '3':
383  output[1] = '}';
384  return 1;
385  case '4':
386  output[1] = '~';
387  return 1;
388  }
389  return 0;
390  }
391 
392  return 0;
393 }
394 
395 
396 
397 int fapint_is_number(char const* input)
398 {
399  int i;
400 
401  if ( !input ) return 0;
402 
403  for ( i = 0; i < strlen(input); ++i )
404  {
405  if ( !isdigit(input[i]) || ( i==0 && (input[i]=='-' || input[i]=='+') ) ) return 0;
406  }
407 
408  return 1;
409 }
410 
411 
412 
413 int fapint_check_date(unsigned int year, unsigned int month, unsigned int day)
414 {
415  return year < 10000 && month <= 12 && day <= 31;
416 }
417 
418 
419 
420 int fapint_get_nmea_latlon(fap_packet_t* packet, char* field1, char* field2)
421 {
422  double value;
423  char direction;
424 
425  char* tmp_str;
426  unsigned int tmp_us;
427  int len;
428 
429  unsigned int matchcount = 4;
430  regmatch_t matches[matchcount];
431 
432 
433  /* Check params. */
434  if ( !packet || !field1 || !field2 )
435  {
436  return 0;
437  }
438 
439  /* Check and get sign. */
440  if ( regexec(&fapint_regex_nmea_flag, field2, matchcount, (regmatch_t*)&matches, 0) == 0 )
441  {
442  direction = field2[matches[1].rm_so];
443  }
444  else
445  {
446  packet->error_code = malloc(sizeof(fap_error_code_t));
447  if ( packet->error_code ) *packet->error_code = fapNMEA_INV_SIGN;
448  return 0;
449  }
450 
451  /* Be leninent on what to accept, anything goes as long as degrees
452  has 1-3 digits, minutes has 2 digits and there is at least one
453  decimal minute. */
454  if ( regexec(&fapint_regex_nmea_coord, field1, matchcount, (regmatch_t*)&matches, 0) == 0 )
455  {
456  len = matches[1].rm_eo - matches[1].rm_so;
457  tmp_str = malloc(len+1);
458  if ( !tmp_str ) return 0;
459  memcpy(tmp_str, field1+matches[1].rm_so, len);
460  tmp_str[len] = 0;
461  tmp_us = atoi(tmp_str);
462  free(tmp_str);
463 
464  len = matches[2].rm_eo - matches[2].rm_so;
465  tmp_str = malloc(len+1);
466  if ( !tmp_str ) return 0;
467  memcpy(tmp_str, field1+matches[2].rm_so, len);
468  tmp_str[len] = 0;
469  value = atof(tmp_str);
470  free(tmp_str);
471 
472  len = matches[3].rm_eo - matches[3].rm_so;
473 
474  value = tmp_us + value/60;
475  if ( !packet->pos_resolution )
476  {
477  packet->pos_resolution = malloc(sizeof(double));
478  if ( !packet->pos_resolution ) return 0;
480  }
481  }
482  else
483  {
484  packet->error_code = malloc(sizeof(fap_error_code_t));
485  if ( packet->error_code ) *packet->error_code = fapNMEA_INV_CVAL;
486  return 0;
487  }
488 
489  /* Apply sign and save. */
490  switch ( toupper(direction) )
491  {
492  case 'E':
493  case 'W':
494  if ( value > 179.999999 )
495  {
496  packet->error_code = malloc(sizeof(fap_error_code_t));
497  if ( packet->error_code ) *packet->error_code = fapNMEA_LARGE_EW;
498  return 0;
499  }
500  if ( toupper(direction) == 'W' )
501  {
502  value *= -1;
503  }
504  packet->longitude = malloc(sizeof(double));
505  if ( !packet->longitude ) return 0;
506  *packet->longitude = value;
507  return 1;
508  case 'N':
509  case 'S':
510  if ( value > 89.999999 )
511  {
512  packet->error_code = malloc(sizeof(fap_error_code_t));
513  if ( packet->error_code ) *packet->error_code = fapNMEA_LARGE_NS;
514  return 0;
515  }
516  if ( toupper(direction) == 'S' )
517  {
518  value *= -1;
519  }
520  packet->latitude = malloc(sizeof(double));
521  if ( !packet->latitude ) return 0;
522  *packet->latitude = value;
523  return 1;
524  }
525 
526  return 0;
527 }
528 
529 
530 
531 short fapint_valid_com_telem_char(char c)
532 {
533  if ( c >= '!' && c <= '{' )
534  {
535  return 1;
536  }
537  return 0;
538 }
539 
540 
541 void fapint_parse_comment_telemetry(fap_packet_t* packet, char** rest, unsigned int* rest_len)
542 {
543  int tmp;
544  char* tmp_str;
545  unsigned int tmp_us;
546  char buf[100];
547 
548  unsigned int const matchcount = 8;
549  regmatch_t matches[matchcount];
550 
551  if ( rest == 0 || *rest == 0 || rest_len == 0 || *rest_len == 0 )
552  {
553  return;
554  }
555 
556  /* Look for base91-telemetry. */
557  if ( regexec(&fapint_regex_base91_telemetry, *rest, matchcount, (regmatch_t*)&matches, 0) == 0 )
558  {
559  /* Initialize results. */
560  packet->telemetry = malloc(sizeof(fap_telemetry_t));
561  if ( !packet->telemetry ) return;
563 
564  /* Get sequence number and first value. */
565  packet->telemetry->seq = malloc(sizeof(unsigned int));
566  if ( !packet->telemetry->seq ) return;
567  *packet->telemetry->seq = ((*rest)[matches[1].rm_so] - 33) * 91 + (*rest)[matches[1].rm_so+1] - 33;
568  packet->telemetry->val1 = malloc(sizeof(double));
569  if ( !packet->telemetry->val1 ) return;
570  *packet->telemetry->val1 = ((*rest)[matches[2].rm_so] - 33) * 91 + (*rest)[matches[2].rm_so+1] - 33;
571 
572  /* Get other values if defined. */
573  if ( matches[3].rm_eo - matches[3].rm_so > 0 )
574  {
575  packet->telemetry->val2 = malloc(sizeof(double));
576  if ( !packet->telemetry->val2 ) return;
577  *packet->telemetry->val2 = ((*rest)[matches[3].rm_so] - 33) * 91 + (*rest)[matches[3].rm_so+1] - 33;
578  }
579  if ( matches[4].rm_eo - matches[4].rm_so > 0 )
580  {
581  packet->telemetry->val3 = malloc(sizeof(double));
582  if ( !packet->telemetry->val3 ) return;
583  *packet->telemetry->val3 = ((*rest)[matches[4].rm_so] - 33) * 91 + (*rest)[matches[4].rm_so+1] - 33;
584  }
585  if ( matches[5].rm_eo - matches[5].rm_so > 0 )
586  {
587  packet->telemetry->val4 = malloc(sizeof(double));
588  if ( !packet->telemetry->val4 ) return;
589  *packet->telemetry->val4 = ((*rest)[matches[5].rm_so] - 33) * 91 + (*rest)[matches[5].rm_so+1] - 33;
590  }
591  if ( matches[6].rm_eo - matches[6].rm_so > 0 )
592  {
593  packet->telemetry->val5 = malloc(sizeof(double));
594  if ( !packet->telemetry->val5 ) return;
595  *packet->telemetry->val5 = ((*rest)[matches[6].rm_so] - 33) * 91 + (*rest)[matches[6].rm_so+1] - 33;
596  }
597 
598  /* Get bit values. */
599  if ( matches[7].rm_eo - matches[7].rm_so > 0 )
600  {
601  for (tmp = 0; tmp < 8; tmp++ ) packet->telemetry->bits[tmp] = '0';
602  tmp = ((*rest)[matches[7].rm_so] - 33) * 91 + (*rest)[matches[7].rm_so+1] - 33;
603  if ( 0x01 & tmp ) packet->telemetry->bits[0] = '1';
604  if ( 0x02 & tmp ) packet->telemetry->bits[1] = '1';
605  if ( 0x04 & tmp ) packet->telemetry->bits[2] = '1';
606  if ( 0x08 & tmp ) packet->telemetry->bits[3] = '1';
607  if ( 0x10 & tmp ) packet->telemetry->bits[4] = '1';
608  if ( 0x20 & tmp ) packet->telemetry->bits[5] = '1';
609  if ( 0x40 & tmp ) packet->telemetry->bits[6] = '1';
610  if ( 0x80 & tmp ) packet->telemetry->bits[7] = '1';
611  }
612 
613  /* Remove telemetry string from comment. */
614  tmp_us = *rest_len;
615  tmp_str = fapint_remove_part(*rest, tmp_us, matches[0].rm_so, matches[0].rm_eo, rest_len);
616  free(*rest);
617  *rest = tmp_str;
618  }
619 }
620 
621 
622 
624 {
625  wx_report->wind_gust = NULL;
626  wx_report->wind_dir = NULL;
627  wx_report->wind_speed = NULL;
628  wx_report->temp = NULL;
629  wx_report->temp_in = NULL;
630  wx_report->rain_1h = NULL;
631  wx_report->rain_24h = NULL;
632  wx_report->rain_midnight = NULL;
633  wx_report->humidity = NULL;
634  wx_report->humidity_in = NULL;
635  wx_report->pressure = NULL;
636  wx_report->luminosity = NULL;
637  wx_report->snow_24h = NULL;
638  wx_report->soft = NULL;
639 }
640 
641 
642 
644 {
645  tlm_report->seq = NULL;
646  tlm_report->val1 = NULL;
647  tlm_report->val2 = NULL;
648  tlm_report->val3 = NULL;
649  tlm_report->val4 = NULL;
650  tlm_report->val5 = NULL;
651 }
652 
653 
654 
655 char* fapint_remove_part(char const* input, unsigned int const input_len,
656  unsigned int const part_so, unsigned int const part_eo,
657  unsigned int* result_len)
658 {
659  unsigned int i, part_i;
660  char* result;
661 
662 
663  /* Check params. */
664  if( !input || !input_len || part_so >= input_len || part_eo > input_len || part_so >= part_eo )
665  {
666  *result_len = 0;
667  return NULL;
668  }
669 
670  /* Calculate size of result. */
671  *result_len = input_len - (part_eo - part_so);
672  if ( *result_len == 0 )
673  {
674  return NULL;
675  }
676 
677  /* Copy input into result. */
678  result = malloc(*result_len+1);
679  if ( !result )
680  {
681  *result_len = 0;
682  return NULL;
683  }
684  part_i = 0;
685  for ( i = 0; i < input_len; ++i )
686  {
687  /* Skip given part. */
688  if ( i < part_so || i >= part_eo )
689  {
690  result[part_i] = input[i];
691  ++part_i;
692  }
693  }
694 
695  /* Add 0 to the end. */
696  result[*result_len] = 0;
697 
698 
699  return result;
700 }