• Main Page
  • Data Structures
  • Files
  • File List
  • Globals

src/helpers2.c

Go to the documentation of this file.
00001 /* $Id: helpers2.c 200 2011-05-22 16:42:29Z oh2gve $
00002  *
00003  * Copyright 2005, 2006, 2007, 2008, 2009, 2010 Tapio Sokura
00004  * Copyright 2007, 2008, 2009, 2010 Heikki Hannikainen
00005  *
00006  * Perl-to-C modifications
00007  * Copyright 2009, 2010, 2011 Tapio Aaltonen
00008  *
00009  * This file is part of libfap.
00010  *
00011  * Libfap is free software; you can redistribute it and/or modify it under the
00012  * terms of either:
00013  *
00014  * a) the GNU General Public License as published by the Free Software
00015  * Foundation; either version 1, or (at your option) any later
00016  * version, or
00017  * 
00018  * b) the "Artistic License". 
00019  * 
00020  * Both licenses can be found in the licenses directory of this source code
00021  * package.
00022  *
00023  * APRS is a registered trademark of APRS Software and Bob Bruninga, WB4APR.
00024 */
00025 
00033 #include "helpers2.h"
00034 #include "fap.h"
00035 #include "regs.h"
00036 #ifdef HAVE_CONFIG_H
00037 #include <config.h>
00038 #endif
00039 
00040 #include <stdio.h>
00041 #include <stdlib.h>
00042 #include <string.h>
00043 #include <regex.h>
00044 #include <ctype.h>
00045 #include <math.h>
00046 
00047 
00048 
00049 void fapint_clear_llist(fapint_llist_item_t* list)
00050 {
00051         fapint_llist_item_t* current_elem = list, *tmp_elem;
00052 
00053         while ( current_elem != NULL )
00054         {
00055                 if ( current_elem->text ) free(current_elem->text);
00056                 tmp_elem = current_elem->next;
00057                 free(current_elem);
00058                 current_elem = tmp_elem;
00059         }
00060 }
00061 
00062 
00063 
00064 double fapint_get_pos_resolution(int const minute_digit_count)
00065 {
00066         double retval = KNOT_TO_KMH;
00067         if ( minute_digit_count  <= -2 )
00068         {
00069                 retval *= 600;
00070         }
00071         else
00072         {
00073                 retval *= 1000;
00074         }
00075         return retval * pow(10, -1*minute_digit_count);
00076 }
00077 
00078 
00079 
00080 int fapint_parse_symbol_from_dst_callsign(fap_packet_t* packet)
00081 {
00082         int len;
00083         char leftover_str[3];
00084         char type;
00085 
00086         char numberid_str[3];
00087         int numberid;
00088 
00089         char dst_type[2];
00090         char overlay;
00091         char code[2];
00092         char tmp_2b[2];
00093 
00094         unsigned int const matchcount = 3;
00095         regmatch_t matches[matchcount];
00096 
00097 
00098         /* Check parameters. */
00099         if ( !packet || !packet->dst_callsign )
00100         {
00101           return 0;
00102         }
00103 
00104         /* Check if destination callsign seems to contain symbol info. */
00105         if ( regexec(&fapint_regex_nmea_dst, packet->dst_callsign, matchcount, (regmatch_t*)&matches, 0) == 0 )
00106         {
00107                 /* Save symbol-containing part. */
00108                 len = matches[2].rm_eo - matches[2].rm_so;
00109                 memset(leftover_str, 0, 3);
00110                 memcpy(leftover_str, packet->dst_callsign+matches[2].rm_so, len);
00111 
00112                 type = leftover_str[0];
00113 
00114                 if ( len == 3 )
00115                 {
00116                         if ( type == 'C' || type == 'E' )
00117                         {
00118                                 /* Get id. */
00119                                 memset(numberid_str, 0, 3);
00120                                 numberid_str[0] = leftover_str[1];
00121                                 numberid_str[1] = leftover_str[2];
00122                                 numberid = atoi(numberid_str);
00123                                 
00124                                 /* Save symbol, if id is valid. */
00125                                 if ( numberid > 0 && numberid < 95 )
00126                                 {
00127                                         packet->symbol_code = numberid + 32;
00128                                         if ( type == 'C' )
00129                                         {
00130                                                 packet->symbol_table = '/';
00131                                         }
00132                                         else
00133                                         {
00134                                                 packet->symbol_table = '\\';
00135                                         }
00136                                         return 1;
00137                                 }
00138                                 else
00139                                 {
00140                                         /* Invalid id. */
00141                                         return 0;
00142                                 }
00143                         }
00144                         else
00145                         {
00146                                 /* Secondary symbol table, with overlay. Check first that we really are in the secondary symbol table. */
00147                                 dst_type[0] = leftover_str[0];
00148                                 dst_type[1] = leftover_str[1];
00149                                 overlay = leftover_str[2];
00150                                 if ( (type == 'O' || type == 'A' || type == 'N' ||
00151                                                 type == 'D' || type == 'S' || type == 'Q') &&
00152                                           isalnum(overlay) )
00153                                 {
00154                                         if ( fapint_symbol_from_dst_type(dst_type, code) )
00155                                         {
00156                                                 packet->symbol_table = overlay;
00157                                                 packet->symbol_code = code[1];
00158                                                 return 1;
00159                                         }
00160                                         else
00161                                         {
00162                                                 /* Could not map into APRS symbol. */
00163                                                 return 0;
00164                                         }
00165                                 }
00166                                 else
00167                                 {
00168                                         /* Propably not in first symbol table. */
00169                                         return 0;
00170                                 }
00171                         }
00172                 }
00173                 else
00174                 {
00175                         /* Primary or secondary symbol table, no overlay. */
00176                         tmp_2b[0] = leftover_str[0];
00177                         tmp_2b[1] = leftover_str[1];
00178                         if ( fapint_symbol_from_dst_type(tmp_2b, code) )
00179                         {
00180                                 packet->symbol_table = code[0];
00181                                 packet->symbol_code = code[1];
00182                                 return 1;
00183                         }
00184                         else
00185                         {
00186                                 /* Could not map into APRS symbol. */
00187                                 return 0;
00188                         }
00189                 }
00190         }
00191         else
00192         {
00193                 return 0;
00194         }
00195 
00196         /* Failsafe catch-all. */
00197         return 0;
00198 }
00199 
00200 
00201 
00202 int fapint_symbol_from_dst_type(char input[2], char* output)
00203 {
00204         switch ( input[0] )
00205         {
00206                 case 'B':
00207                 case 'O':
00208                         if ( input[0] == 'B' )
00209                         {
00210                                 output[0] = '/';
00211                         }
00212                         else
00213                         {
00214                                 output[0] = '\\';
00215                         }
00216                         switch ( input[1] )
00217                         {
00218                                 case 'B':
00219                                         output[1] = '!';
00220                                         return 1;
00221                                 case 'C':
00222                                         output[1] = '"';
00223                                         return 1;
00224                                 case 'D':
00225                                         output[1] = '#';
00226                                         return 1;
00227                                 case 'E':
00228                                         output[1] = '$';
00229                                         return 1;
00230                                 case 'F':
00231                                         output[1] = '%';
00232                                         return 1;
00233                                 case 'G':
00234                                         output[1] = '&';
00235                                         return 1;
00236                                 case 'H':
00237                                         output[1] = '\'';
00238                                         return 1;
00239                                 case 'I':
00240                                         output[1] = '(';
00241                                         return 1;
00242                                 case 'J':
00243                                         output[1] = ')';
00244                                         return 1;
00245                                 case 'K':
00246                                         output[1] = '*';
00247                                         return 1;
00248                                 case 'L':
00249                                         output[1] = '+';
00250                                         return 1;
00251                                 case 'M':
00252                                         output[1] = ',';
00253                                         return 1;
00254                                 case 'N':
00255                                         output[1] = '-';
00256                                         return 1;
00257                                 case 'O':
00258                                         output[1] = '.';
00259                                         return 1;
00260                                 case 'P':
00261                                         output[1] = '/';
00262                                         return 1;
00263                         }
00264                         return 0;
00265                 case 'P':
00266                 case 'A':
00267                         if ( input[0] == 'P' )
00268                         {
00269                                 output[0] = '/';
00270                         }
00271                         else
00272                         {
00273                                 output[0] = '\\';
00274                         }
00275                         if ( isdigit(input[1]) || isupper(input[1]) )
00276                         {
00277                                 output[1] = input[1];
00278                                 return 1;
00279                         }
00280                         return 0;
00281                 case 'M':
00282                 case 'N':
00283                         if ( input[0] == 'M' )
00284                         {
00285                                 output[0] = '/';
00286                         }
00287                         else
00288                         {
00289                                 output[0] = '\\';
00290                         }
00291                         switch ( input[1] )
00292                         {
00293                                 case 'R':
00294                                         output[1] = ':';
00295                                         return 1;
00296                                 case 'S':
00297                                         output[1] = ';';
00298                                         return 1;
00299                                 case 'T':
00300                                         output[1] = '<';
00301                                         return 1;
00302                                 case 'U':
00303                                         output[1] = '=';
00304                                         return 1;
00305                                 case 'V':
00306                                         output[1] = '>';
00307                                         return 1;
00308                                 case 'W':
00309                                         output[1] = '?';
00310                                         return 1;
00311                                 case 'X':
00312                                         output[1] = '@';
00313                                         return 1;
00314                         }
00315                         return 0;
00316                 case 'H':
00317                 case 'D':
00318                         if ( input[0] == 'H' )
00319                         {
00320                                 output[0] = '/';
00321                         }
00322                         else
00323                         {
00324                                 output[0] = '\\';
00325                         }
00326                         switch ( input[1] )
00327                         {
00328                                 case 'S':
00329                                         output[1] = '[';
00330                                         return 1;
00331                                 case 'T':
00332                                         output[1] = '\\';
00333                                         return 1;
00334                                 case 'U':
00335                                         output[1] = ']';
00336                                         return 1;
00337                                 case 'V':
00338                                         output[1] = '^';
00339                                         return 1;
00340                                 case 'W':
00341                                         output[1] = '_';
00342                                         return 1;
00343                                 case 'X':
00344                                         output[1] = '`';
00345                                         return 1;
00346                         }
00347                         return 0;
00348                 case 'L':
00349                 case 'S':
00350                         if ( input[0] == 'L' )
00351                         {
00352                                 output[0] = '/';
00353                         }
00354                         else
00355                         {
00356                                 output[0] = '\\';
00357                         }
00358                         if ( isupper(input[1]) )
00359                         {
00360                                 output[1] = tolower(input[1]);
00361                                 return 1;
00362                         }
00363                         return 0;
00364                 case 'J':
00365                 case 'Q':
00366                         if ( input[0] == 'J' )
00367                         {
00368                                 output[0] = '/';
00369                         }
00370                         else
00371                         {
00372                                 output[0] = '\\';
00373                         }
00374                         switch ( input[1] )
00375                         {
00376                                 case '1':
00377                                         output[1] = '{';
00378                                         return 1;
00379                                 case '2':
00380                                         output[1] = '|';
00381                                         return 1;
00382                                 case '3':
00383                                         output[1] = '}';
00384                                         return 1;
00385                                 case '4':
00386                                         output[1] = '~';
00387                                         return 1;
00388                         }
00389                         return 0;
00390         }
00391         
00392         return 0;
00393 }
00394 
00395 
00396 
00397 int fapint_is_number(char const* input)
00398 {
00399         int i;
00400 
00401         if ( !input ) return 0;
00402 
00403         for ( i = 0; i < strlen(input); ++i )
00404         {
00405                 if ( !isdigit(input[i]) || ( i==0 && (input[i]=='-' || input[i]=='+') ) ) return 0;
00406         }
00407 
00408         return 1;
00409 }
00410 
00411 
00412 
00413 int fapint_check_date(unsigned int year, unsigned int month, unsigned int day)
00414 {
00415         return year < 10000 && month <= 12 && day <= 31;
00416 }
00417 
00418 
00419 
00420 int fapint_get_nmea_latlon(fap_packet_t* packet, char* field1, char* field2)
00421 {
00422         double value;
00423         char direction;
00424 
00425         char* tmp_str;
00426         unsigned int tmp_us;
00427         int len;
00428         
00429         unsigned int matchcount = 4;
00430         regmatch_t matches[matchcount];
00431         
00432 
00433         /* Check params. */
00434         if ( !packet || !field1 || !field2 )
00435         {
00436                 return 0;
00437         }
00438         
00439         /* Check and get sign. */
00440         if ( regexec(&fapint_regex_nmea_flag, field2, matchcount, (regmatch_t*)&matches, 0) == 0 )
00441         {
00442                 direction = field2[matches[1].rm_so];
00443         }
00444         else
00445         {
00446                 packet->error_code = malloc(sizeof(fap_error_code_t));
00447                 if ( packet->error_code ) *packet->error_code = fapNMEA_INV_SIGN;
00448                 return 0;
00449         }
00450         
00451         /* Be leninent on what to accept, anything goes as long as degrees
00452            has 1-3 digits, minutes has 2 digits and there is at least one
00453            decimal minute. */
00454         if ( regexec(&fapint_regex_nmea_coord, field1, matchcount, (regmatch_t*)&matches, 0) == 0 )
00455         {
00456                 len = matches[1].rm_eo - matches[1].rm_so;
00457                 tmp_str = malloc(len+1);
00458                 if ( !tmp_str ) return 0;
00459                 memcpy(tmp_str, field1+matches[1].rm_so, len);
00460                 tmp_str[len] = 0;
00461                 tmp_us = atoi(tmp_str);
00462                 free(tmp_str);
00463                 
00464                 len = matches[2].rm_eo - matches[2].rm_so;
00465                 tmp_str = malloc(len+1);
00466                 if ( !tmp_str ) return 0;
00467                 memcpy(tmp_str, field1+matches[2].rm_so, len);
00468                 tmp_str[len] = 0;
00469                 value = atof(tmp_str);
00470                 free(tmp_str);
00471                 
00472                 len = matches[3].rm_eo - matches[3].rm_so;
00473                 
00474                 value = tmp_us + value/60;
00475                 if ( !packet->pos_resolution )
00476                 {
00477                         packet->pos_resolution = malloc(sizeof(double));
00478                         if ( !packet->pos_resolution ) return 0;
00479                         *packet->pos_resolution = fapint_get_pos_resolution(len);
00480                 }
00481         }
00482         else
00483         {
00484                 packet->error_code = malloc(sizeof(fap_error_code_t));
00485                 if ( packet->error_code ) *packet->error_code = fapNMEA_INV_CVAL;
00486                 return 0;
00487         }
00488         
00489         /* Apply sign and save. */
00490         switch ( toupper(direction) )
00491         {
00492                 case 'E':
00493                 case 'W':
00494                         if ( value > 179.999999 )
00495                         {
00496                                 packet->error_code = malloc(sizeof(fap_error_code_t));
00497                                 if ( packet->error_code ) *packet->error_code = fapNMEA_LARGE_EW;
00498                                 return 0;
00499                         }
00500                         if ( toupper(direction) == 'W' )
00501                         {
00502                                 value *= -1;
00503                         }
00504                         packet->longitude = malloc(sizeof(double));
00505                         if ( !packet->longitude ) return 0;
00506                         *packet->longitude = value;
00507                         return 1;
00508                 case 'N':
00509                 case 'S':
00510                         if ( value > 89.999999 )
00511                         {
00512                                 packet->error_code = malloc(sizeof(fap_error_code_t));
00513                                 if ( packet->error_code ) *packet->error_code = fapNMEA_LARGE_NS;
00514                                 return 0;
00515                         }
00516                         if ( toupper(direction) == 'S' )
00517                         {
00518                                 value *= -1;
00519                         }
00520                         packet->latitude = malloc(sizeof(double));
00521                         if ( !packet->latitude ) return 0;
00522                         *packet->latitude = value;
00523                         return 1;
00524         }
00525                 
00526         return 0;
00527 }
00528 
00529 
00530 
00531 short fapint_valid_com_telem_char(char c)
00532 {
00533         if ( c >= '!' && c <= '{' )
00534         {
00535                 return 1;
00536         }
00537         return 0;
00538 }
00539 
00540 
00541 void fapint_parse_comment_telemetry(fap_packet_t* packet, char** rest, unsigned int* rest_len)
00542 {
00543         int len = 0, i = 0, j = 0, tmp;
00544         char* tmp_str;
00545         unsigned int tmp_us;
00546         char buf[10];
00547         
00548         /* Look for start marker. */
00549         for ( i = 0; i < *rest_len; ++i )
00550         {
00551                 if ( (*rest)[i] == '|' )
00552                 {
00553                         /* Look for stop marker. */
00554                         for ( j = i+1; j < *rest_len; ++j )
00555                         {
00556                                 if ( (*rest)[j] == '|' )
00557                                 {
00558                                         break;
00559                                 }
00560                         }
00561                         break;
00562                 }
00563         }
00564         
00565         /* Check that we found markers, and that they mark even-lenght string. */
00566         len = j - i + 1;
00567         if ( i < *rest_len && j < *rest_len && len > 1 && len % 2 == 0)
00568         {
00569                 /* Check for sequence id. */
00570                 if ( len >= 4 )
00571                 {
00572                         if ( fapint_valid_com_telem_char((*rest)[i+1]) &&
00573                              fapint_valid_com_telem_char((*rest)[i+2]) )
00574                         {
00575                                 /* Initialize results. */
00576                                 packet->telemetry = malloc(sizeof(fap_telemetry_t));
00577                                 if ( !packet->telemetry ) return;
00578                                 fapint_init_telemetry_report(packet->telemetry);
00579                                 
00580                                 packet->telemetry->seq = ((*rest)[i+1] - 33) * 91 + (*rest)[i+2] - 33;
00581                         }
00582                         else
00583                         {
00584                                 return;
00585                         }
00586                 }
00587                 
00588                 /* Check for first data value. */
00589                 if ( len >= 6 )
00590                 {
00591                         if ( fapint_valid_com_telem_char((*rest)[i+3]) &&
00592                              fapint_valid_com_telem_char((*rest)[i+4]) )
00593                         {
00594                                 packet->telemetry->val1 = ((*rest)[i+3] - 33) * 91 + (*rest)[i+4] - 33;
00595                         }
00596                         else
00597                         {
00598                                 free(packet->telemetry);
00599                                 packet->telemetry = NULL;
00600                                 return;
00601                         }
00602                 }
00603                 
00604                 /* Check for second data value. */
00605                 if ( len >= 8 )
00606                 {
00607                         if ( fapint_valid_com_telem_char((*rest)[i+5]) &&
00608                              fapint_valid_com_telem_char((*rest)[i+6]) )
00609                         {
00610                                 packet->telemetry->val2 = ((*rest)[i+5] - 33) * 91 + (*rest)[i+6] - 33;
00611                         }
00612                         else
00613                         {
00614                                 free(packet->telemetry);
00615                                 packet->telemetry = NULL;
00616                                 return;
00617                         }
00618                 }
00619                 
00620                 /* Check for third data value. */
00621                 if ( len >= 10 )
00622                 {
00623                         if ( fapint_valid_com_telem_char((*rest)[i+7]) &&
00624                              fapint_valid_com_telem_char((*rest)[i+8]) )
00625                         {
00626                                 packet->telemetry->val3 = ((*rest)[i+7] - 33) * 91 + (*rest)[i+8] - 33;
00627                         }
00628                         else
00629                         {
00630                                 free(packet->telemetry);
00631                                 packet->telemetry = NULL;
00632                                 return;
00633                         }
00634                 }
00635                 
00636                 /* Check for fourth data value. */
00637                 if ( len >= 12 )
00638                 {
00639                         if ( fapint_valid_com_telem_char((*rest)[i+9]) &&
00640                              fapint_valid_com_telem_char((*rest)[i+10]) )
00641                         {
00642                                 packet->telemetry->val4 = ((*rest)[i+9] - 33) * 91 + (*rest)[i+10] - 33;
00643                         }
00644                         else
00645                         {
00646                                 free(packet->telemetry);
00647                                 packet->telemetry = NULL;
00648                                 return;
00649                         }
00650                 }
00651                 
00652                 /* Check for fifth data value. */
00653                 if ( len >= 14 )
00654                 {
00655                         if ( fapint_valid_com_telem_char((*rest)[i+11]) &&
00656                              fapint_valid_com_telem_char((*rest)[i+12]) )
00657                         {
00658                                 packet->telemetry->val5 = ((*rest)[i+11] - 33) * 91 + (*rest)[i+12] - 33;
00659                         }
00660                         else
00661                         {
00662                                 free(packet->telemetry);
00663                                 packet->telemetry = NULL;
00664                                 return;
00665                         }
00666                 }
00667                 
00668                 /* Check for bits. */
00669                 if ( len >= 16 )
00670                 {
00671                         if ( fapint_valid_com_telem_char((*rest)[i+13]) &&
00672                              fapint_valid_com_telem_char((*rest)[i+14]) )
00673                         {
00674                                 tmp = ((*rest)[i+13] - 33) * 91 + (*rest)[i+14] - 33;
00675                                 
00676                                 /* Print bits as digits. */
00677                                 sprintf(buf, "%d%d%d%d%d%d%d%d", 0x01 & tmp, 0x02 & tmp, 0x04 & tmp, 0x08 & tmp, 0x10 & tmp, 0x20 & tmp, 0x40 & tmp, 0x80 & tmp);
00678                                 for ( tmp = 0; tmp < strlen(buf) && tmp < 8; ++tmp )
00679                                 {
00680                                         packet->telemetry->bits[tmp] = buf[tmp];
00681                                 }
00682                         }
00683                         else
00684                         {
00685                                 free(packet->telemetry);
00686                                 packet->telemetry = NULL;
00687                                 return;
00688                         }
00689                 }
00690                 
00691                 /* Remove telemetry string from comment. */
00692                 tmp_us = *rest_len;
00693                 tmp_str = fapint_remove_part(*rest, tmp_us, i, j+1, rest_len);
00694                 free(*rest);
00695                 *rest = tmp_str;
00696         }
00697 }
00698 
00699 
00700 
00701 void fapint_init_wx_report(fap_wx_report_t* wx_report)
00702 {
00703         wx_report->wind_gust = NULL;
00704         wx_report->wind_dir = NULL;
00705         wx_report->wind_speed = NULL;
00706         wx_report->temp = NULL;
00707         wx_report->temp_in = NULL;
00708         wx_report->rain_1h = NULL;
00709         wx_report->rain_24h = NULL;
00710         wx_report->rain_midnight = NULL;
00711         wx_report->humidity = NULL;
00712         wx_report->humidity_in = NULL;
00713         wx_report->pressure = NULL;
00714         wx_report->luminosity = NULL;
00715         wx_report->snow_24h = NULL;
00716         wx_report->soft = NULL;
00717 }
00718 
00719 
00720 
00721 void fapint_init_telemetry_report(fap_telemetry_t* telemetry)
00722 {
00723         if ( !telemetry ) return;
00724         telemetry->seq = 0;
00725         telemetry->val1 = 0.0;
00726         telemetry->val2 = 0.0;
00727         telemetry->val3 = 0.0;
00728         telemetry->val4 = 0.0;
00729         telemetry->val5 = 0.0;
00730         memset(telemetry->bits, '?', 8);
00731 }
00732 
00733 
00734 
00735 char* fapint_remove_part(char const* input, unsigned int const input_len,
00736                          unsigned int const part_so, unsigned int const part_eo,
00737                          unsigned int* result_len)
00738 {
00739         unsigned int i, part_i;
00740         char* result;
00741 
00742 
00743         /* Check params. */
00744         if( !input || !input_len || part_so >= input_len || part_eo > input_len || part_so >= part_eo )
00745         {
00746                 *result_len = 0;
00747                 return NULL;
00748         }
00749 
00750         /* Calculate size of result. */
00751         *result_len = input_len - (part_eo - part_so);
00752         if ( *result_len == 0 )
00753         {
00754                 return NULL;
00755         }
00756 
00757         /* Copy input into result. */
00758         result = malloc(*result_len+1);
00759         if ( !result )
00760         {
00761                 *result_len = 0;
00762                 return NULL;
00763         }
00764         part_i = 0;
00765         for ( i = 0; i < input_len; ++i )
00766         {
00767                 /* Skip given part. */
00768                 if ( i < part_so || i >= part_eo )
00769                 {
00770                         result[part_i] = input[i];
00771                         ++part_i;
00772                 }
00773         }
00774 
00775         /* Add 0 to the end. */
00776         result[*result_len] = 0;
00777 
00778 
00779         return result;
00780 }

Generated on Wed Dec 21 2011 23:04:42 for libfap by  doxygen 1.7.1