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

src/fap.c

Go to the documentation of this file.
00001 /* $Id: fap.c 203 2011-11-20 05:50:04Z 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 
00075 #include "fap.h"
00076 #include "helpers.h"
00077 #include "helpers2.h"
00078 #include "regs.h"
00079 #ifdef HAVE_CONFIG_H
00080 #include <config.h>
00081 #endif
00082 
00083 #include <stdlib.h>
00084 #include <string.h>
00085 #include <regex.h>
00086 #include <ctype.h>
00087 #include <math.h>
00088 #include <stdio.h>
00089 
00090 
00092 #define PI 3.14159265
00093 
00094 #define DEG2RAD(x) (x/360*2*PI)
00095 
00096 #define RAD2DEG(x) (x*(180/PI))
00097 
00099 #define FEND 0xc0
00100 
00101 #define FESC 0xdb
00102 
00103 #define TFEND 0xdc
00104 
00105 #define TFESC 0xdd
00106 
00107 #define FRAME_MAXLEN 512
00108 
00110 #define AX25_FRAME_UI 0x03
00111 
00112 #define AX25_PID_APRS 0xf0
00113 
00114 
00115 
00116 /* Regexs needed by helpers. */
00117 regex_t fapint_regex_header, fapint_regex_ax25call, fapint_regex_digicall, fapint_regex_digicallv6;
00118 regex_t fapint_regex_normalpos, fapint_regex_normalamb, fapint_regex_timestamp;
00119 regex_t fapint_regex_mice_dstcall, fapint_regex_mice_body, fapint_regex_mice_amb;
00120 regex_t fapint_regex_comment, fapint_regex_phgr, fapint_regex_phg, fapint_regex_rng, fapint_regex_altitude;
00121 regex_t fapint_regex_mes_dst, fapint_regex_mes_ack, fapint_regex_mes_nack;
00122 regex_t fapint_regex_wx1, fapint_regex_wx2, fapint_regex_wx3, fapint_regex_wx4, fapint_regex_wx5;
00123 regex_t fapint_regex_wx_r1, fapint_regex_wx_r24, fapint_regex_wx_rami;
00124 regex_t fapint_regex_wx_humi, fapint_regex_wx_pres, fapint_regex_wx_lumi, fapint_regex_wx_what;
00125 regex_t fapint_regex_wx_snow, fapint_regex_wx_rrc, fapint_regex_wx_any, fapint_regex_wx_soft;
00126 regex_t fapint_regex_nmea_chksum, fapint_regex_nmea_dst, fapint_regex_nmea_time, fapint_regex_nmea_date;
00127 regex_t fapint_regex_nmea_specou, fapint_regex_nmea_fix, fapint_regex_nmea_altitude, fapint_regex_nmea_flag, fapint_regex_nmea_coord;
00128 regex_t fapint_regex_telemetry, fapint_regex_peet_splitter, fapint_regex_kiss_callsign, fapint_regex_kiss_digi;
00129 
00130 /* Regex needed in this file. */
00131 regex_t fapint_regex_detect_comp, fapint_regex_detect_wx, fapint_regex_detect_telem, fapint_regex_detect_exp;
00132 regex_t fapint_regex_kiss_hdrbdy, fapint_regex_hdr_detail;
00133 regex_t fapint_regex_hopcount1, fapint_regex_hopcount2;
00134 
00135 /* Regex status flag. */
00136 short fapint_initialized = 0;
00137 
00138 
00139 
00140 fap_packet_t* fap_parseaprs(char const* input, unsigned int const input_len, short const is_ax25)
00141 {
00142         fap_packet_t* result;
00143         int i, pos;
00144         unsigned int splitpos, body_len;
00145         char* body;
00146         char* tmp;
00147         char poschar, typechar;
00148         
00149         /* Check initialization status. */
00150         if ( !fapint_initialized )
00151         {
00152                 return NULL;
00153         }
00154         
00155         /* Create empty packet to be returned. */
00156         result = fapint_create_packet();
00157         
00158         /* Check for missing params. */
00159         if ( input == NULL || input_len == 0 )
00160         {
00161                 result->error_code = malloc(sizeof(fap_error_code_t));
00162                 if ( result->error_code ) *result->error_code = fapPACKET_NO;
00163                 return result;
00164         }
00165         
00166         /* Save the original packet. */
00167         result->orig_packet = malloc(input_len);
00168         result->orig_packet_len = input_len;
00169         memcpy(result->orig_packet, input, input_len);
00170         
00171         /* Find the end of header checking for NULL bytes while doing it. */
00172         splitpos = 0;
00173         for ( i = 0; i < input_len; ++i )
00174         {
00175                 if ( input[i] == 0 )
00176                 {
00177                         result->error_code = malloc(sizeof(fap_error_code_t));
00178                         if ( result->error_code ) *result->error_code = fapPACKET_INVALID;
00179                         return result;
00180                 }
00181                 if ( input[i] == ':' )
00182                 {
00183                         splitpos = i;
00184                         break;
00185                 }
00186         }
00187         /* Check that end was found and body has at least one byte. */
00188         if ( splitpos == 0 || splitpos + 1 == input_len )
00189         {
00190                 result->error_code = malloc(sizeof(fap_error_code_t));
00191                 if ( result->error_code ) *result->error_code = fapPACKET_NOBODY;
00192                 return result;
00193         }
00194         
00195         /* Save header and body. */
00196         result->header = fapint_remove_part(input, input_len, splitpos, input_len, &body_len);
00197         result->body = fapint_remove_part(input, input_len, 0, splitpos+1, &result->body_len);
00198 
00199         /* Parse source, target and path. */
00200         if ( !fapint_parse_header(result, is_ax25) )
00201         {
00202                 return result;
00203         }
00204 
00205         /* Create 0-terminated working copy of body. Remember that this added 0 is not always the first 0 in body. */
00206         body_len = result->body_len;
00207         body = malloc(body_len + 1);
00208         memcpy(body, result->body, body_len);
00209         body[body_len] = 0;
00210         
00211         /* Detect packet type char. */
00212         typechar = body[0];
00213 
00214         /* Check for mic-e packet. */
00215         if ( (typechar == 0x27 || typechar == 0x60) &&
00216              body_len >= 9 )
00217         {
00218                 result->type = malloc(sizeof(fap_packet_type_t));
00219                 if ( !result->type ) return result;
00220                 *result->type = fapLOCATION; /* not fapMICE, lol */
00221                 fapint_parse_mice(result, body+1, body_len-1);
00222         }
00223         /* Check for normal or compressed location packet. */
00224         else if ( typechar == '!' || typechar == '=' || typechar == '/' || typechar == '@' )
00225         {
00226                 /* Check for messaging. */
00227                 result->messaging = malloc(sizeof(short));
00228                 if ( !result->messaging ) return result;
00229                 if ( typechar == '=' || typechar == '@' )
00230                 {
00231                         *result->messaging = 1;
00232                 }
00233                 else
00234                 {
00235                         *result->messaging = 0;
00236                 }
00237                 /* Validate body. */
00238                 if ( body_len >= 14 )
00239                 {
00240                         result->type = malloc(sizeof(fap_packet_type_t));
00241                         if ( !result->type ) return result;
00242                         *result->type = fapLOCATION;
00243                         /* Check for timestamp. We use i as obfuscated status flag. Sorry. */
00244                         i = 1; /* we has no error */
00245                         if ( typechar == '/' || typechar == '@' )
00246                         {
00247                                 /* Parse and remove those 7 bytes, removing also the typechar byte. */
00248                                 result->timestamp = malloc(sizeof(time_t));
00249                                 if ( !result->timestamp ) return result;
00250                                 *result->timestamp = fapint_parse_timestamp(body+1);
00251                                 if ( result->timestamp == NULL )
00252                                 {
00253                                         result->error_code = malloc(sizeof(fap_error_code_t));
00254                                         if ( result->error_code ) *result->error_code = fapTIMESTAMP_INV_LOC;
00255                                         i = 0; /* we has error */
00256                                 }
00257                                 tmp = fapint_remove_part(body, body_len, 0, 8, &body_len);
00258                                 free(body);
00259                                 body = tmp;
00260                         }
00261                         else
00262                         {
00263                                 /* Remove only typechar byte. */
00264                                 tmp = fapint_remove_part(body, body_len, 0, 1, &body_len);
00265                                 free(body);
00266                                 body = tmp;
00267                         }
00268                         
00269                         /* If timestamp check didn't fail, go on with location parsing. */
00270                         if ( i )
00271                         {
00272                                 /* Get position type character. */
00273                                 poschar = body[0];
00274                                 
00275                                 /* Detect position type. */
00276                                 if ( poschar >= 48 && poschar <= 57 )
00277                                 {
00278                                         /* It's normal position. */
00279                                         if ( body_len >= 19 )
00280                                         {
00281                                                 i = fapint_parse_normal(result, body);
00282                                                 /* Check for comments or wx report. */
00283                                                 if ( body_len > 19 && i && result->symbol_code != '_' )
00284                                                 {
00285                                                         fapint_parse_comment(result, body+19, body_len-19);
00286                                                 }
00287                                                 else if ( body_len > 19 && i )
00288                                                 {
00289                                                         fapint_parse_wx(result, body+19, body_len-19);
00290                                                 }
00291                                         }
00292                                 }
00293                                 else if ( poschar == 47 || poschar == 92 || (poschar >= 65 && poschar <= 90) || (poschar >= 97 && poschar <= 106) )
00294                                 {
00295                                         /* It's compressed position. */
00296                                         if ( body_len >= 13 )
00297                                         {
00298                                                 i = fapint_parse_compressed(result, body);
00299                                                 /* Check for comment or wx report. */
00300                                                 if ( body_len > 13 && i && result->symbol_code != '_' )
00301                                                 {
00302                                                         fapint_parse_comment(result, body+13, body_len-13);
00303                                                 }
00304                                                 else if ( body_len > 13 && i )
00305                                                 {
00306                                                         fapint_parse_wx(result, body+13, body_len-13);
00307                                                 }
00308                                         }
00309                                         else
00310                                         {
00311                                                 result->error_code = malloc(sizeof(fap_error_code_t));
00312                                                 if ( result->error_code ) *result->error_code = fapCOMP_SHORT;
00313                                         }
00314                                 }
00315                                 else if ( poschar == 33 )
00316                                 {
00317                                         /* Weather report from Ultimeter 2000 */
00318                                         if ( result->type == NULL )
00319                                         {
00320                                                 result->type = malloc(sizeof(fap_packet_type_t));
00321                                                 if ( !result->type ) return result;
00322                                         }
00323                                         *result->type = fapWX;
00324                                         fapint_parse_wx_peet_logging(result, body+1);
00325                                 }
00326                                 else
00327                                 {
00328                                         /* Does not match any known type. */
00329                                         result->error_code = malloc(sizeof(fap_error_code_t));
00330                                         if ( result->error_code ) *result->error_code = fapPACKET_INVALID;
00331                                 }
00332                         }
00333                 }
00334                 else
00335                 {
00336                         result->error_code = malloc(sizeof(fap_error_code_t));
00337                         if ( result->error_code ) *result->error_code = fapPACKET_SHORT;
00338                 }
00339         }
00340         /* Check for NMEA data packet. */
00341         else if ( typechar == '$' )
00342         {
00343                 if ( body_len > 3 && body[0] == '$' && body[1] == 'G' && body[2] == 'P' )
00344                 {
00345                         result->type = malloc(sizeof(fap_packet_type_t));
00346                         if ( !result->type ) return result;
00347                         *result->type = fapLOCATION; /* not fapNMEA, lol */
00348                         fapint_parse_nmea(result, body+1, body_len-1);
00349                 }
00350                 else if ( body_len > 5 && body[0] == '$' && body[1] == 'U' && body[2] == 'L' && body[3] == 'T' && body[4] == 'W' )
00351                 {
00352                         result->type = malloc(sizeof(fap_packet_type_t));
00353                         if ( !result->type ) return result;
00354                         *result->type = fapWX;
00355                         fapint_parse_wx_peet_packet(result, body+5);
00356                 }
00357         }
00358         /* Check for object packet. */
00359         else if ( typechar == ';' )
00360         {   
00361                 if ( body_len >= 31 )
00362                 {
00363                         result->type = malloc(sizeof(fap_packet_type_t));
00364                         if ( !result->type ) return result;
00365                         *result->type = fapOBJECT;
00366                         fapint_parse_object(result, body, body_len);
00367                 }
00368         }
00369         /* Check for item packet. */
00370         else if ( typechar == ')' )
00371         {  
00372                 if ( body_len >= 18 )
00373                 {
00374                         result->type = malloc(sizeof(fap_packet_type_t));
00375                         if ( !result->type ) return result;
00376                         *result->type = fapITEM;
00377                         fapint_parse_item(result, body, body_len);
00378                 }
00379         }
00380         /* Check for message, bulletin or announcement packet. */
00381         else if ( typechar == ':' )
00382         {   
00383                 if ( body_len >= 11 )
00384                 {
00385                         /* All are labeled as messages for the time being. */
00386                         result->type = malloc(sizeof(fap_packet_type_t));
00387                         if ( !result->type ) return result;
00388                         *result->type = fapMESSAGE;
00389                         fapint_parse_message(result, body, body_len);
00390                 }
00391         }
00392         /* Check for capabilities packet. */
00393         else if ( typechar == '<' )
00394         {   
00395                 /* At least one other character besides '<' required. */
00396                 if ( body_len >= 2 )
00397                 {
00398                         result->type = malloc(sizeof(fap_packet_type_t));
00399                         if ( !result->type ) return result;
00400                         *result->type = fapCAPABILITIES;
00401                         fapint_parse_capabilities(result, body+1, body_len-1);
00402                 }
00403         }
00404         /* Check for status packet. */
00405         else if ( typechar == '>' )
00406         {
00407                 /* We can live with empty status reports. */
00408                 if ( body_len >= 1 )
00409                 {
00410                         result->type = malloc(sizeof(fap_packet_type_t));
00411                         if ( !result->type ) return result;
00412                         *result->type = fapSTATUS;
00413                         fapint_parse_status(result, body+1, body_len-1);
00414                 }
00415         }
00416         /* Check for weather packet. */
00417         else if ( typechar == '_' )
00418         {
00419                 if ( regexec(&fapint_regex_detect_wx, body, 0, NULL, 0) == 0 )
00420                 {
00421                         result->type = malloc(sizeof(fap_packet_type_t));
00422                         if ( !result->type ) return result;
00423                         *result->type = fapWX;
00424                         fapint_parse_wx(result, body+9, body_len-9);
00425                 }
00426                 else
00427                 {
00428                         result->error_code = malloc(sizeof(fap_error_code_t));
00429                         if ( result->error_code ) *result->error_code = fapWX_UNSUPP;
00430                 }
00431         }
00432         /* Check for telemetry packet. */
00433         else if ( regexec(&fapint_regex_detect_telem, body, 0, NULL, 0) == 0 )
00434         {   
00435                 result->type = malloc(sizeof(fap_packet_type_t));
00436                 if ( !result->type ) return result;
00437                 *result->type = fapTELEMETRY;
00438                 fapint_parse_telemetry(result, body+2);
00439         }
00440         /* Check for experimental packet. */
00441         else if ( regexec(&fapint_regex_detect_exp, body, 0, NULL, 0) == 0 )
00442         {   
00443                 result->type = malloc(sizeof(fap_packet_type_t));
00444                 if ( !result->type ) return result;
00445                 *result->type = fapEXPERIMENTAL;
00446                 result->error_code = malloc(sizeof(fap_error_code_t));
00447                 if ( result->error_code ) *result->error_code = fapEXP_UNSUPP;
00448         }
00449         /* Check for third party packets. */
00450         else if ( typechar == '}' )
00451         {
00452                 /* Come here to avoid the "when all else fails" option. */
00453         }
00454         /* When all else fails, try to look for a !-position that can occur
00455            anywhere within the 40 first characters according to the spec. */
00456         else
00457         {
00458                 tmp = strchr(body, '!');
00459                 if ( tmp != NULL && (pos = tmp-body) < 40 && pos+1 < body_len ) /* Check that pos is not last char. */
00460                 {
00461                         result->type = malloc(sizeof(fap_packet_type_t));
00462                         if ( !result->type ) return result;
00463                         *result->type = fapLOCATION;
00464                         poschar = tmp[1];
00465 
00466                         /* Detect position type. */
00467                         if ( poschar == 47 || poschar == 92 || (poschar >= 65 && poschar <= 90) || (poschar >= 97 && poschar <= 106) )
00468                         {
00469                                 /* It's compressed position. */
00470                                 if ( body_len >= pos + 1 + 13 )
00471                                 {
00472                                         i = fapint_parse_compressed(result, body+pos+1);
00473                                         /* Check for comment. */
00474                                         if ( body_len - (pos+1) > 13 && i && result->symbol_code != '_' )
00475                                         {
00476                                                 fapint_parse_comment(result, body+pos+1+13, body_len-pos-1-13);
00477                                         }
00478                                 }
00479                         }
00480                         else if ( isdigit(poschar) )
00481                         {
00482                                 /* It's normal position. */
00483                                 if ( body_len >= pos + 1 + 19 )
00484                                 {
00485                                         i = fapint_parse_normal(result, tmp+1);
00486                                         /* Check for comment. */
00487                                         if ( body_len - (pos+1) > 19 && i && result->symbol_code != '_' )
00488                                         {
00489                                                 fapint_parse_comment(result, body+pos+1+19, body_len-pos-1-19);
00490                                         }
00491                                 }
00492                         }
00493                 }
00494                 else
00495                 {
00496                         /* No luck. It's propably not APRS packet at all. */
00497                         result->error_code = malloc(sizeof(fap_error_code_t));
00498                         if ( result->error_code ) *result->error_code = fapNO_APRS;
00499                 }
00500         }
00501         
00502         /* We're done. */
00503         free(body);
00504         
00505         return result;
00506 }
00507 
00508 
00509 
00510 void fap_explain_error(fap_error_code_t const error, char* output)
00511 {
00512         /* Dummy check. */
00513         if ( output == NULL )
00514         {
00515                 return;
00516         }
00517         
00518         switch (error)
00519         {
00520                 case fapPACKET_NO:
00521                         sprintf(output, "No packet given to parse");
00522                         break;
00523                 case fapPACKET_SHORT:
00524                         sprintf(output, "Too short packet");
00525                         break;
00526                 case fapPACKET_NOBODY:
00527                         sprintf(output, "No body in packet");
00528                         break;
00529                 
00530                 case fapSRCCALL_NOAX25:
00531                         sprintf(output, "Source callsign is not a valid AX.25 call");
00532                         break;
00533                 case fapSRCCALL_BADCHARS:
00534                         sprintf(output, "Source callsign contains bad characters");
00535                         break;
00536                 
00537                 case fapDSTPATH_TOOMANY:
00538                         sprintf(output, "Too many destination path components to be AX.25");
00539                         break;
00540                 case fapDSTCALL_NONE:
00541                         sprintf(output, "No destination field in packet");
00542                         break;
00543                 case fapDSTCALL_NOAX25:
00544                         sprintf(output, "Destination callsign is not a valid AX.25 call");
00545                         break;
00546                 
00547                 case fapDIGICALL_NOAX25:
00548                         sprintf(output, "Digipeater callsign is not a valid AX.25 call");
00549                         break;
00550                 case fapDIGICALL_BADCHARS:
00551                         sprintf(output, "Digipeater callsign contains bad characters");
00552                         break;
00553                 
00554                 case fapTIMESTAMP_INV_LOC:
00555                         sprintf(output, "Invalid timestamp in location");
00556                         break;
00557                 case fapTIMESTAMP_INV_OBJ:
00558                         sprintf(output, "Invalid timestamp in object");
00559                         break;
00560                 case fapTIMESTAMP_INV_STA:
00561                         sprintf(output, "Invalid timestamp in status");
00562                         break;
00563                 case fapTIMESTAMP_INV_GPGGA:
00564                         sprintf(output, "Invalid timestamp in GPGGA sentence");
00565                         break;
00566                 case fapTIMESTAMP_INV_GPGLL:
00567                         sprintf(output, "Invalid timestamp in GPGLL sentence");
00568                         break;
00569                 
00570                 case fapPACKET_INVALID:
00571                         sprintf(output, "Invalid packet");
00572                         break;
00573                 
00574                 case fapNMEA_INV_CVAL:
00575                         sprintf(output, "Invalid coordinate value in NMEA sentence");
00576                         break;
00577                 case fapNMEA_LARGE_EW:
00578                         sprintf(output, "Too large value in NMEA sentence (east/west)");
00579                         break;
00580                 case fapNMEA_LARGE_NS:
00581                         sprintf(output, "Too large value in NMEA sentence (north/south)");
00582                         break;
00583                 case fapNMEA_INV_SIGN:
00584                         sprintf(output, "Invalid lat/long sign in NMEA sentence");
00585                         break;
00586                 case fapNMEA_INV_CKSUM:
00587                         sprintf(output, "Invalid checksum in NMEA sentence");
00588                         break;
00589                 
00590                 case fapGPRMC_FEWFIELDS:
00591                         sprintf(output, "Less than ten fields in GPRMC sentence");
00592                         break;
00593                 case fapGPRMC_NOFIX:
00594                         sprintf(output, "No GPS fix in GPRMC sentence");
00595                         break;
00596                 case fapGPRMC_INV_TIME:
00597                         sprintf(output, "Invalid timestamp in GPRMC sentence");
00598                         break;
00599                 case fapGPRMC_INV_DATE:
00600                         sprintf(output, "Invalid date in GPRMC sentence");
00601                         break;
00602                 case fapGPRMC_DATE_OUT:
00603                         sprintf(output, "GPRMC date does not fit in an Unix timestamp");
00604                         break;
00605                 
00606                 case fapGPGGA_FEWFIELDS:
00607                         sprintf(output, "Less than 11 fields in GPGGA sentence");
00608                         break;
00609                 case fapGPGGA_NOFIX:
00610                         sprintf(output, "No GPS fix in GPGGA sentence");
00611                         break;
00612                 
00613                 case fapGPGLL_FEWFIELDS:
00614                         sprintf(output, "Less than 5 fields in GPGLL sentence");
00615                         break;
00616                 case fapGPGLL_NOFIX:
00617                         sprintf(output, "No GPS fix in GPGLL sentence");
00618                         break;
00619                 
00620                 case fapNMEA_UNSUPP:
00621                         sprintf(output, "Unsupported NMEA sentence type");
00622                         break;
00623                 
00624                 case fapOBJ_SHORT:
00625                         sprintf(output, "Too short object");
00626                         break;
00627                 case fapOBJ_INV:
00628                         sprintf(output, "Invalid object");
00629                         break;
00630                 case fapOBJ_DEC_ERR:
00631                         sprintf(output, "Error in object location decoding");
00632                         break;
00633                 
00634                 case fapITEM_SHORT:
00635                         sprintf(output, "Too short item");
00636                         break;
00637                 case fapITEM_INV:
00638                         sprintf(output, "Invalid item");
00639                         break;
00640                 case fapITEM_DEC_ERR:
00641                         sprintf(output, "Error in item location decoding");
00642                         break;
00643                 
00644                 case fapLOC_SHORT:
00645                         sprintf(output, "Too short uncompressed location");
00646                         break;
00647                 case fapLOC_INV:
00648                         sprintf(output, "Invalid uncompressed location");
00649                         break;
00650                 case fapLOC_LARGE:
00651                         sprintf(output, "Degree value too large");
00652                         break;
00653                 case fapLOC_AMB_INV:
00654                         sprintf(output, "Invalid position ambiguity");
00655                         break;
00656                 
00657                 case fapMICE_SHORT:
00658                         sprintf(output, "Too short mic-e packet");
00659                         break;
00660                 case fapMICE_INV:
00661                         sprintf(output, "Invalid characters in mic-e packet");
00662                         break;
00663                 case fapMICE_INV_INFO:
00664                         sprintf(output, "Invalid characters in mic-e information field");
00665                         break;
00666                 case fapMICE_AMB_LARGE:
00667                         sprintf(output, "Too much position ambiguity in mic-e packet");
00668                         break;
00669                 case fapMICE_AMB_INV:
00670                         sprintf(output, "Invalid position ambiguity in mic-e packet");
00671                         break;
00672                 case fapMICE_AMB_ODD:
00673                         sprintf(output, "Odd position ambiguity in mic-e packet");
00674                         break;
00675                 
00676                 case fapCOMP_INV:
00677                         sprintf(output, "Invalid compressed packet");
00678                         break;
00679                 case fapCOMP_SHORT:
00680                         sprintf(output, "Short compressed packet");
00681                         break;
00682                 
00683                 case fapMSG_INV:
00684                         sprintf(output, "Invalid message packet");
00685                         break;
00686                 
00687                 case fapWX_UNSUPP:
00688                         sprintf(output, "Unsupported weather format");
00689                         break;
00690                 case fapUSER_UNSUPP:
00691                         sprintf(output, "Unsupported user format");
00692                         break;
00693                 
00694                 case fapDX_INV_SRC:
00695                         sprintf(output, "Invalid DX spot source callsign");
00696                         break;
00697                 case fapDX_INF_FREQ:
00698                         sprintf(output, "Invalid DX spot frequency");
00699                         break;
00700                 case fapDX_NO_DX:
00701                         sprintf(output, "No DX spot callsign found");
00702                         break;
00703                 
00704                 case fapTLM_INV:
00705                         sprintf(output, "Invalid telemetry packet");
00706                         break;
00707                 case fapTLM_LARGE:
00708                         sprintf(output, "Too large telemetry value");
00709                         break;
00710                 case fapTLM_UNSUPP:
00711                         sprintf(output, "Unsupported telemetry");
00712                         break;
00713                 
00714                 case fapEXP_UNSUPP:
00715                         sprintf(output, "Unsupported experimental");
00716                         break;
00717                 case fapSYM_INV_TABLE:
00718                         sprintf(output, "Invalid symbol table or overlay");
00719                         break;
00720                 
00721                 case fapNOT_IMPLEMENTED:
00722                         sprintf(output, "Sorry, feature not implemented yet.");
00723                         break;
00724                 case fapNMEA_NOFIELDS:
00725                         sprintf(output, "No fields in NMEA fields in NMEA packet.");
00726                         break;
00727                 
00728                 case fapNO_APRS:
00729                         sprintf(output, "Not an APRS packet");
00730                         break;
00731                 
00732                 default:
00733                         sprintf(output, "Default error message.");
00734                         break;
00735         }
00736 }
00737 
00738 
00739 
00740 void fap_mice_mbits_to_message(char const* bits, char* output)
00741 {
00742         /* Dummy check. */
00743         if ( bits == NULL || output == NULL )
00744         {
00745                 return;
00746         }
00747         
00748         /* Detect known bit combinations. */
00749         if ( strcmp(bits, "111") == 0 ) sprintf(output, "off duty");
00750         else if ( strcmp(bits, "222") == 0 ) sprintf(output, "custom 0");
00751         else if ( strcmp(bits, "110") == 0 ) sprintf(output, "en route");
00752         else if ( strcmp(bits, "220") == 0 ) sprintf(output, "custom 1");
00753         else if ( strcmp(bits, "101") == 0 ) sprintf(output, "in service");
00754         else if ( strcmp(bits, "202") == 0 ) sprintf(output, "custom 2");
00755         else if ( strcmp(bits, "100") == 0 ) sprintf(output, "returning");
00756         else if ( strcmp(bits, "200") == 0 ) sprintf(output, "custom 3");
00757         else if ( strcmp(bits, "011") == 0 ) sprintf(output, "committed");
00758         else if ( strcmp(bits, "022") == 0 ) sprintf(output, "custom 4");
00759         else if ( strcmp(bits, "010") == 0 ) sprintf(output, "special");
00760         else if ( strcmp(bits, "020") == 0 ) sprintf(output, "custom 5");
00761         else if ( strcmp(bits, "001") == 0 ) sprintf(output, "priority");
00762         else if ( strcmp(bits, "002") == 0 ) sprintf(output, "custom 6");
00763         else if ( strcmp(bits, "000") == 0 ) sprintf(output, "emergency");
00764         else sprintf(output, "unknown");
00765 }
00766 
00767 
00768 
00769 double fap_distance(double lon0, double lat0, double lon1, double lat1)
00770 {
00771         /* Convert degrees into radians. */
00772         lon0 = DEG2RAD(lon0);
00773         lat0 = DEG2RAD(lat0);
00774         lon1 = DEG2RAD(lon1);
00775         lat1 = DEG2RAD(lat1);
00776 
00777         /* Use the haversine formula for distance calculation
00778          * http://mathforum.org/library/drmath/view/51879.html */
00779         double dlon = lon1 - lon0;
00780         double dlat = lat1 - lat0;
00781         double a = pow(sin(dlat/2),2) + cos(lat0) * cos(lat1) * pow(sin(dlon/2), 2);
00782         double c = 2 * atan2(sqrt(a), sqrt(1-a));
00783         
00784         return c * 6366.71; /* in kilometers */
00785 }
00786 
00787 
00788 
00789 double fap_direction(double lon0, double lat0, double lon1, double lat1)
00790 {
00791         double direction;
00792 
00793         /* Convert degrees into radians. */
00794         lon0 = DEG2RAD(lon0);
00795         lat0 = DEG2RAD(lat0);
00796         lon1 = DEG2RAD(lon1);
00797         lat1 = DEG2RAD(lat1);
00798         
00799         /* Direction from Aviation Formulary V1.42 by Ed Williams by way of
00800          * http://mathforum.org/library/drmath/view/55417.html */
00801         direction = atan2(sin(lon1-lon0)*cos(lat1), cos(lat0)*sin(lat1)-sin(lat0)*cos(lat1)*cos(lon1-lon0));
00802         if ( direction < 0 )
00803         {
00804                 /* Make direction positive. */
00805                 direction += 2 * PI;
00806         }
00807 
00808         return RAD2DEG(direction);
00809 }
00810 
00811 
00812 
00813 int fap_count_digihops(fap_packet_t const* packet)
00814 {
00815         int i, len;
00816         unsigned int hopcount = 0, n, N;
00817         short wasdigied;
00818         char* element;
00819         char* call_ssid;
00820 
00821         unsigned int const matchcount = 3;
00822         regmatch_t matches[matchcount];
00823                                 
00824         
00825         /* Check input. */
00826         if ( !fapint_initialized || packet == NULL || packet->path == NULL )
00827         {
00828                 return -1;
00829         }
00830         
00831         /* Process all path elements. */
00832         for ( i = 0; i < packet->path_len; ++i )
00833         {
00834                 wasdigied = 0;
00835                 
00836                 /* Check if packet was digied due to this element. */
00837                 if ( regexec(&fapint_regex_hopcount1, packet->path[i], matchcount, (regmatch_t*)&matches, 0) == 0 )
00838                 {
00839                         wasdigied = 1;
00840 
00841                         /* Save working copy of the element, but without the '*'. */
00842                         len = matches[1].rm_eo - matches[1].rm_so;
00843                         element = malloc(len+1);
00844                         if ( !element ) return -1;
00845                         memcpy(element, packet->path[i]+matches[1].rm_so, len);
00846                         element[len] = 0;
00847   
00848                         /* Check the callsign for validity and expand it. */
00849                         call_ssid = fap_check_ax25_call(element, 1);
00850                         free(element);
00851                 }
00852                 else
00853                 {
00854                         call_ssid = fap_check_ax25_call(packet->path[i], 1);
00855                 }
00856 
00857                 /* Check validity test result. */
00858                 if ( call_ssid == NULL )
00859                 {
00860                         return -1;
00861                 }
00862                 
00863                 /* Check for WIDEn-N. */
00864                 if ( regexec(&fapint_regex_hopcount2, call_ssid, matchcount, (regmatch_t*)&matches, 0) == 0 )
00865                 {
00866                         /* Get n and N by converting them from ASCII digits to numbers. */
00867                         n = call_ssid[matches[1].rm_so] - 48;
00868                         N = call_ssid[matches[2].rm_so] - 48;
00869                         
00870                         /* Add difference to hopcount, if not negative. */
00871                         if ( (i = n - N) >= 0 )
00872                         {
00873                                 hopcount += i;
00874                         }
00875                 }
00876                 else
00877                 {
00878                         /* No WIDEn-N, TRACE and other things are calculated bases on the '*' indicators. */
00879                         if ( wasdigied )
00880                         {
00881                                 hopcount++;
00882                         }
00883                 }
00884                 
00885                 /* Prepare to check next path element. */
00886                 free(call_ssid);
00887         }
00888                                 
00889         return hopcount;
00890 }
00891 
00892 
00893 
00894 char* fap_check_ax25_call(char const* input, short const add_ssid0)
00895 {
00896         unsigned int const matchcount = 3;
00897         regmatch_t matches[matchcount];
00898 
00899         int ssid = 0, len;
00900         char call[7], ssid_str[4];
00901         
00902         char* result = NULL;
00903         char buf[10];
00904         
00905         
00906         /* Check initialization status. */
00907         if ( !fapint_initialized )
00908         {
00909                 return NULL;
00910         }
00911         
00912         /* Check input. */
00913         if ( !input || !strlen(input) )
00914         {
00915                 return NULL;
00916         }
00917         
00918         /* Validate callsign. */
00919         if ( regexec(&fapint_regex_ax25call, input, matchcount, (regmatch_t*)&matches, 0) == 0 )
00920         {
00921                 /* Get callsign. */
00922                 memset(call, 0, 7);
00923                 len = matches[1].rm_eo - matches[1].rm_so;
00924                 memcpy(call, input+matches[1].rm_so, len);
00925 
00926                 /* Get SSID. */
00927                 memset(ssid_str, 0, 4);
00928                 len = matches[2].rm_eo - matches[2].rm_so;
00929                 memcpy(ssid_str, input+matches[2].rm_so, len);
00930                 
00931                 /* If we got ssid, check that it is valid. */
00932                 if ( len )
00933                 {
00934                         ssid = atoi(ssid_str);
00935                         ssid = 0 - ssid;
00936                         if ( ssid > 15 )
00937                         {
00938                                 return NULL;
00939                         }
00940                 }
00941                 
00942                 /* Create result. */
00943                 memset(buf, 0, 10);
00944                 if ( !add_ssid0 && ssid == 0 )
00945                 {
00946                         sprintf(buf, "%s", call);
00947                 }
00948                 else
00949                 {
00950                         sprintf(buf, "%s-%d", call, ssid);
00951                 }
00952                         
00953                 result = malloc( strlen(buf)+1 );
00954                 if ( !result ) return NULL;
00955                 strcpy(result, buf);
00956         }
00957         
00958         /* We're done. */
00959         return result;
00960 }
00961 
00962 
00963 
00964 int fap_kiss_to_tnc2(char const* kissframe, unsigned int kissframe_len,
00965                      char* tnc2frame, unsigned int* tnc2frame_len, unsigned int* tnc_id)
00966 {
00967         char input[FRAME_MAXLEN];
00968         unsigned int input_len = 0;
00969         
00970         char output[2*FRAME_MAXLEN];
00971         unsigned int output_len = 0;
00972         
00973         int i = 0, j = 0, escape_mode = 0;
00974 
00975         /* Check that we got params. */
00976         if ( !kissframe || !kissframe_len || !tnc2frame || !tnc2frame_len || !tnc_id )
00977         {
00978                 return 0;
00979         }
00980         
00981         /* Check that frame is short enough. */
00982         if ( kissframe_len >= FRAME_MAXLEN )
00983         {
00984                 sprintf(output, "Too long KISS frame.");
00985                 output_len = strlen(output)+1;
00986                 if ( output_len > *tnc2frame_len ) output_len = *tnc2frame_len;
00987                 memcpy(tnc2frame, output, output_len);
00988                 *tnc2frame_len = output_len;
00989                 return 0;
00990         }
00991         
00992         /* Check for FEND at start, remove if found. */
00993         if ( kissframe_len > 0 && (kissframe[0] & 0xff) == FEND )
00994         {
00995                 kissframe += 1;
00996                 kissframe_len -= 1;
00997         }
00998         
00999         /* Check for ending FEND. */
01000         for ( i = 0; i < kissframe_len; ++i )
01001         {
01002                 if ( (kissframe[i] & 0xff) == FEND )
01003                 {
01004                         kissframe_len = i;
01005                 }
01006         }
01007         
01008         /* Save and remove tnc id. */
01009         if ( kissframe_len > 0 )
01010         {
01011                 *tnc_id = kissframe[0];
01012                 kissframe += 1;
01013                 kissframe_len -= 1;
01014         }
01015         
01016         /* Perform byte unstuffing. */
01017         j = 0;
01018         for ( i = 0; i < kissframe_len; ++i )
01019         {
01020                 if ( (kissframe[i] & 0xff) == FESC )
01021                 {
01022                         escape_mode = 1;
01023                         continue;
01024                 }
01025         
01026                 if ( escape_mode )
01027                 {
01028                         if ( (kissframe[i] & 0xff) == TFEND )
01029                         {
01030                                 input[j] = FEND;
01031                         }
01032                         else if ( (kissframe[i] & 0xff) == TFESC )
01033                         {
01034                                 input[j] = FESC;
01035                         }
01036                         escape_mode = 0;
01037                         ++j;
01038                         continue;
01039                 }
01040                 
01041                 input[j] = kissframe[i];
01042                 ++j;
01043         }
01044         input_len = j;
01045 
01046         /* Length checking _after_ byte unstuffing. */
01047         if ( input_len < 16 )
01048         {
01049                 sprintf(output, "Too short KISS frame (%d bytes after unstuffing).", input_len);
01050                 output_len = strlen(output)+1;
01051                 if ( output_len > *tnc2frame_len ) output_len = *tnc2frame_len;
01052                 memcpy(tnc2frame, output, output_len);
01053                 *tnc2frame_len = output_len;
01054                 return 0;
01055         }
01056         
01057         // Now we have an AX.25-frame, let's parse it.
01058         return fap_ax25_to_tnc2(input, input_len, tnc2frame, tnc2frame_len);
01059 }
01060 
01061 
01062 
01063 int fap_ax25_to_tnc2(char const* ax25frame, unsigned int ax25frame_len,
01064                      char* tnc2frame, unsigned int* tnc2frame_len)
01065 {
01066         int i, j, retval = 1;
01067         char *checked_call, *dst_callsign = NULL;
01068         int part_no, header_len, ssid, digi_count;
01069         char tmp_callsign[10];
01070         char charri;
01071 
01072         char output[2*FRAME_MAXLEN];
01073         unsigned int output_len = 0;
01074         
01075         /* Check that we got params. */
01076         if ( !ax25frame || !ax25frame_len || !tnc2frame || !tnc2frame_len )
01077         {
01078                 return 0;
01079         }
01080         
01081         /* Check that frame size is good. */
01082         if ( ax25frame_len >= FRAME_MAXLEN )
01083         {
01084                 sprintf(output, "Too long AX.25 frame.");
01085                 output_len = strlen(output)+1;
01086                 if ( output_len > *tnc2frame_len ) output_len = *tnc2frame_len;
01087                 memcpy(tnc2frame, output, output_len);
01088                 *tnc2frame_len = output_len;
01089                 return 0;
01090         }
01091         if ( ax25frame_len < 16 )
01092         {
01093                 sprintf(output, "Too short AX.25 frame (%d bytes).", ax25frame_len);
01094                 output_len = strlen(output)+1;
01095                 if ( output_len > *tnc2frame_len ) output_len = *tnc2frame_len;
01096                 memcpy(tnc2frame, output, output_len);
01097                 *tnc2frame_len = output_len;
01098                 return 0;
01099         }
01100         
01101         /* Go through the frame to get 4 parts: header, control field, pid and body. */
01102         part_no = 0;
01103         header_len = 0;
01104         memset(tmp_callsign, 0, 10);
01105         digi_count = 0;
01106         j = 0;
01107         for ( i = 0; i < ax25frame_len; ++i )
01108         {
01109                 charri = ax25frame[i];
01110                 
01111                 if ( part_no == 0 )
01112                 {
01113                         /* New byte to header. */
01114                         header_len++;
01115                         
01116                         /* We're at header, check if it should end with this byte. */
01117                         if ( charri & 1 )
01118                         {
01119                                 /* Yes, lets do some checks. */
01120                                 if ( header_len < 14 || header_len % 7 != 0 )
01121                                 {
01122                                         sprintf(output, "Invalid header lenght (%d).", header_len);
01123                                         output_len = strlen(output)+1;
01124                                         retval = 0;
01125                                         break;
01126                                 }
01127                                 
01128                                 /* Go for control field upon next cycle. */
01129                                 part_no = 1;
01130                         }
01131                         
01132                         /* Check if a callsign is about to be complete. */
01133                         if ( header_len && header_len % 7 == 0 )
01134                         {
01135                                 /* This byte is SSID, get the number. */
01136                                 ssid = (charri >> 1) & 0xf;
01137                                 if ( ssid != 0 )
01138                                 {
01139                                         sprintf(tmp_callsign+6, "-%d", ssid);
01140                                 }
01141                                 /* Validate callsign. */
01142                                 checked_call = fapint_check_kiss_callsign(tmp_callsign);
01143                                 if ( !checked_call )
01144                                 {
01145                                         sprintf(output, "Invalid callsign in header (%s).", tmp_callsign);
01146                                         output_len = strlen(output)+1;
01147                                         retval = 0;
01148                                         break;
01149                                 }
01150                                 /* Figure out which part of header this callsign is. */
01151                                 if ( header_len == 7 )
01152                                 {
01153                                         /* We have a destination callsign. */
01154                                         dst_callsign = checked_call;
01155                                 }
01156                                 else if ( header_len == 14 )
01157                                 {
01158                                         /* We have a source callsign, copy it to the final frame directly. */
01159                                         sprintf(output, "%s>%s", checked_call, dst_callsign);
01160                                         output_len = strlen(checked_call) + 1 + strlen(dst_callsign);
01161                                         free(dst_callsign);
01162                                         free(checked_call);
01163                                 }
01164                                 else if ( header_len > 14 )
01165                                 {
01166                                         /* We're at path part, save the call. */
01167                                         sprintf(output+output_len, "%s", checked_call);
01168                                         output_len += strlen(checked_call);
01169                                         free(checked_call);
01170                                         /* Get the has-been-repeated flag. */
01171                                         if ( charri & 0x80 ) 
01172                                         {
01173                                                 output[output_len] = '*';
01174                                                 output_len++;
01175                                         }
01176                                         digi_count++;
01177                                 }
01178                                 else
01179                                 {
01180                                         sprintf(output, "Internal error.");
01181                                         output_len = strlen(output)+1;
01182                                         retval = 0;
01183                                         break;
01184                                 }
01185                                 /* Check what happens next. */
01186                                 if ( part_no == 0 )
01187                                 {
01188                                         /* More address fields will follow. Check that there's no more than 8 digis in path. */
01189                                         if ( digi_count >= 8 )
01190                                         {
01191                                                 sprintf(output, "Too many digis.");
01192                                                 output_len = strlen(output)+1;
01193                                                 retval = 0;
01194                                                 break;
01195                                         }
01196                                         output[output_len] = ',';
01197                                         output_len++;
01198                                 }
01199                                 else
01200                                 {
01201                                         /* End of header. */
01202                                         output[output_len] = ':';
01203                                         output_len++;
01204                                 }
01205                                 j = 0;
01206                                 memset(tmp_callsign, 0, 10);
01207                                 continue;
01208                         }
01209                         
01210                         /* Shift one bit right to get the ascii character. */
01211                         tmp_callsign[j] = (charri & 0xff) >> 1;
01212                         ++j;
01213                 }
01214                 else if ( part_no == 1 )
01215                 {
01216                         /* We're at control field. We are only interested in UI frames, discard others. */
01217                         if ( (charri & 0xff) != AX25_FRAME_UI )
01218                         {
01219                                 retval = 0;
01220                                 break;
01221                         }
01222                         part_no = 2;
01223                 }
01224                 else if ( part_no == 2 )
01225                 {
01226                         /* We're at pid. */
01227                         if ( (charri & 0xff) != AX25_PID_APRS )
01228                         {
01229                                 retval = 0;
01230                                 break;
01231                         }
01232                         part_no = 3;
01233                 }
01234                 else
01235                 {
01236                         output[output_len] = charri;
01237                         output_len++;
01238                 }
01239         }
01240         
01241         /* Copy result to output. */
01242         if ( output_len > *tnc2frame_len ) output_len = *tnc2frame_len;
01243         memcpy(tnc2frame, output, output_len);
01244         *tnc2frame_len = output_len;
01245 
01246         return retval;
01247 }
01248 
01249 
01250 
01251 int fap_tnc2_to_kiss(char const* tnc2frame, unsigned int tnc2frame_len, unsigned int const tnc_id,
01252                      char* kissframe, unsigned int* kissframe_len)
01253 {
01254         char ax25frame[2*FRAME_MAXLEN];
01255         unsigned int ax25frame_len;
01256         int i;
01257 
01258         /* Initialize slot for starting FEND and tnc id by skipping two first bytes of our conversion buffer. */
01259         ax25frame_len = 2*FRAME_MAXLEN-2;
01260         memset(ax25frame, 0, 2);
01261         
01262         /* Convert into AX.25-frame. */
01263         if ( !fap_tnc2_to_ax25(tnc2frame, tnc2frame_len, ax25frame+2, &ax25frame_len) )
01264         {
01265                 strcpy(kissframe, ax25frame);
01266                 *kissframe_len = strlen(kissframe);
01267                 return 0;
01268         }
01269         ax25frame_len += 2;
01270         
01271         /* Check for room in output buffer. */
01272         if ( *kissframe_len <= ax25frame_len )
01273         {
01274                 return 0;
01275         }
01276         
01277         /* Perform byte stuffing. */
01278         *kissframe_len = 2;
01279         for ( i = 2; i < ax25frame_len; ++i )
01280         {
01281                 if ( (ax25frame[i] & 0xff) == FEND || (ax25frame[i] & 0xff) == FESC )
01282                 {
01283                         kissframe[*kissframe_len] = FESC;
01284                         (*kissframe_len)++;
01285                         if ( (ax25frame[i] & 0xff) == FEND )
01286                         {
01287                                 kissframe[*kissframe_len] = TFEND;
01288                         }
01289                         else
01290                         {
01291                                 kissframe[*kissframe_len] = TFESC;
01292                         }
01293                         (*kissframe_len)++;
01294                 }
01295                 else
01296                 {
01297                         kissframe[*kissframe_len] = ax25frame[i];
01298                         (*kissframe_len)++;
01299                 }
01300         }
01301         
01302         /* Put FENDs and tnc id in place. */
01303         kissframe[0] = FEND;
01304         kissframe[1] = tnc_id;
01305         kissframe[*kissframe_len] = FEND;
01306         (*kissframe_len)++;
01307         
01308         return 1;
01309 }
01310 
01311 
01312 
01313 int fap_tnc2_to_ax25(char const* tnc2frame, unsigned int tnc2frame_len,
01314                      char* ax25frame, unsigned int* ax25frame_len)
01315 {
01316         char input[FRAME_MAXLEN];
01317         
01318         char output[2*FRAME_MAXLEN];
01319         unsigned int output_len = 0;
01320 
01321         char *header = NULL, *digipeaters = NULL, *body = NULL;
01322         unsigned int digi_count, body_len;
01323 
01324         char sender[6], sender_ssid[4], receiver[6], receiver_ssid[4];
01325         int sender_ssid_num = 0, receiver_ssid_num = 0;
01326         
01327         char digicall[6], digicall_ssid[4], hbit;
01328         int digicall_ssid_num = 0;
01329 
01330         int retval = 1, len, i;
01331         char* tmp_str;
01332         
01333         unsigned int const matchcount = 6;
01334         regmatch_t matches[matchcount];
01335         
01336         
01337         /* Check params. */
01338         if ( !tnc2frame || !tnc2frame_len || tnc2frame_len >= FRAME_MAXLEN || !ax25frame || !ax25frame_len )
01339         {  
01340                 return 0;
01341         }
01342         
01343         /* Create working copy of input. */
01344         memset(input, 0, FRAME_MAXLEN);
01345         memcpy(input, tnc2frame, tnc2frame_len );
01346         
01347         /* Separate header and body. */
01348         if ( regexec(&fapint_regex_kiss_hdrbdy, input, matchcount, (regmatch_t*)&matches, 0) == 0 )
01349         {
01350                 len = matches[1].rm_eo - matches[1].rm_so;
01351                 header = malloc(len+1);
01352                 if ( !header ) return 0;
01353                 memcpy(header, input+matches[1].rm_so, len);
01354                 header[len] = 0;
01355                 
01356                 body_len = matches[2].rm_eo - matches[2].rm_so;
01357                 body = malloc(body_len);
01358                 if ( !body )
01359                 {
01360                         free(header);
01361                         return 0;
01362                 }
01363                 memcpy(body, input+matches[2].rm_so, body_len);
01364         }
01365         else
01366         {
01367                 sprintf(output, "Failed to separate header and body of TNC-2 packet.");
01368                 output_len = strlen(output)+1;
01369                 if ( output_len > *ax25frame_len ) output_len = *ax25frame_len;
01370                 strcpy(ax25frame, output);
01371                 *ax25frame_len = output_len;
01372                 return 0;
01373         }
01374         
01375         /* Separate the sender, recipient and digipeaters. */
01376         if ( regexec(&fapint_regex_hdr_detail, header, matchcount, (regmatch_t*)&matches, 0) == 0 )
01377         {
01378                 len = matches[1].rm_eo - matches[1].rm_so;
01379                 memset(sender, ' ', 6);
01380                 memcpy(sender, header+matches[1].rm_so, len);
01381                 
01382                 len = matches[2].rm_eo - matches[2].rm_so;
01383                 memset(sender_ssid, 0, 4);
01384                 if ( len )
01385                 {
01386                         memcpy(sender_ssid, header+matches[2].rm_so, len);
01387                 }
01388                 
01389                 len = matches[3].rm_eo - matches[3].rm_so;
01390                 memset(receiver, ' ', 6);
01391                 memcpy(receiver, header+matches[3].rm_so, len);
01392                 
01393                 len = matches[4].rm_eo - matches[4].rm_so;
01394                 memset(receiver_ssid, 0, 4);
01395                 if ( len )
01396                 {
01397                         memcpy(receiver_ssid, header+matches[4].rm_so, len);
01398                 }
01399                 
01400                 len = matches[5].rm_eo - matches[5].rm_so;
01401                 if ( len )
01402                 {
01403                         digipeaters = malloc(len+5);
01404                         if ( !digipeaters )
01405                         {
01406                                 free(header);
01407                                 free(body);
01408                                 return 0;
01409                         }
01410                         memcpy(digipeaters, header+matches[5].rm_so, len);
01411                         digipeaters[len] = 0;
01412                 }
01413         }
01414         else
01415         {
01416                 free(header);
01417                 free(body);
01418                 return 0;
01419         }
01420         free(header);
01421         
01422         /* Frame header compilation is done in a easy-to-break-out block. */
01423         while ( 1 )
01424         {
01425                 /* Check SSID format and convert to number. */
01426                 if ( sender_ssid[0] == '-' )
01427                 {
01428                         sender_ssid_num = 0 - atoi(sender_ssid);
01429                         if ( sender_ssid_num > 15 )
01430                         {
01431                                 retval = 0;
01432                                 break;
01433                         }
01434                 }
01435                 if ( receiver_ssid[0] == '-' )
01436                 {
01437                         receiver_ssid_num = 0 - atoi(receiver_ssid);
01438                         if ( receiver_ssid_num > 15 )
01439                         {
01440                                 retval = 0;
01441                                 break;
01442                         }
01443                 }
01444         
01445                 /* Encode destination and source. */
01446                 for ( i = 0; i < 6; ++i )
01447                 {
01448                         output[output_len] = receiver[i] << 1;
01449                         output_len++;
01450                 }
01451                 output[output_len] = 0xe0 | (receiver_ssid_num << 1);
01452                 output_len++;
01453                 for ( i = 0; i < 6; ++i )
01454                 {
01455                         output[output_len] = sender[i] << 1;
01456                         output_len++;
01457                 }   
01458                 if ( digipeaters )
01459                 {
01460                         output[output_len] = 0x60 | (sender_ssid_num << 1);
01461                 }
01462                 else
01463                 {
01464                         output[output_len] = 0x61 | (sender_ssid_num << 1);
01465                 }
01466                 output_len++;
01467                 
01468                 /* If there are digipeaters, add them. */
01469                 if ( digipeaters )
01470                 {
01471                         /* Split into parts. */
01472                         tmp_str = strtok(digipeaters+1, ",");
01473                         digi_count = 0;
01474                         while ( tmp_str != NULL )
01475                         {
01476                                 /* Split into callsign, SSID and h-bit. */
01477                                 if ( regexec(&fapint_regex_kiss_digi, tmp_str, matchcount, (regmatch_t*)&matches, 0) == 0 )
01478                                 {
01479                                         /* digi's plain callsign */
01480                                         len = matches[1].rm_eo - matches[1].rm_so;
01481                                         memset(digicall, ' ', 6);
01482                                         memcpy(digicall, tmp_str+matches[1].rm_so, len);
01483                                         
01484                                         /* ssid */
01485                                         digicall_ssid_num = 0;
01486                                         len = matches[2].rm_eo - matches[2].rm_so;
01487                                         if ( len )
01488                                         {
01489                                                 memset(digicall_ssid, 0, 4);
01490                                                 memcpy(digicall_ssid, tmp_str+matches[2].rm_so, len);
01491                                                 
01492                                                 digicall_ssid_num = 0 - atoi(digicall_ssid);
01493                                                 if ( digicall_ssid_num > 15 )
01494                                                 {
01495                                                         retval = 0;
01496                                                         break;
01497                                                 }
01498                                         }
01499                                         
01500                                         /* h-bit */
01501                                         hbit = 0x00;
01502                                         if ( tmp_str[matches[3].rm_so] == '*' )
01503                                         {
01504                                                 hbit = 0x80;
01505                                         }
01506                                         
01507                                         /* Check for next part. */
01508                                         tmp_str = strtok(NULL, ",");
01509                                         
01510                                         /* Add plain callsign frame. */
01511                                         for ( i = 0; i < 6; ++i )
01512                                         {
01513                                                 output[output_len] = digicall[i] << 1;
01514                                                 output_len++;
01515                                         }
01516                                         /* Add ssid. */
01517                                         if ( tmp_str )
01518                                         {
01519                                                 /* More digipeaters to follow. */
01520                                                 output[output_len] = 0x60 | (digicall_ssid_num << 1) | hbit;
01521                                         }
01522                                         else
01523                                         {
01524                                                 /* Last digipeater. */
01525                                                 output[output_len] = 0x61 | (digicall_ssid_num << 1) | hbit;
01526                                         }
01527                                         output_len++;
01528                                 }
01529                                 else
01530                                 {
01531                                         /* Invalid digi callsign. */
01532                                         retval = 0;
01533                                         break;
01534                                 }
01535                         }
01536                 }
01537                 
01538                 /* Frame header compiled. */
01539                 break;
01540         }   
01541         if ( digipeaters ) free(digipeaters);
01542         
01543         
01544         /* Add frame type and pid. */
01545         output[output_len] = AX25_FRAME_UI;
01546         output_len++;
01547         output[output_len] = AX25_PID_APRS;
01548         output_len++;
01549         
01550         /* Add body. */
01551         memcpy(output+output_len, body, body_len);
01552         output_len += body_len;
01553         free(body);
01554         
01555         /* Check how header compilation went. */
01556         if ( !retval )
01557         {
01558                 return 0;
01559         }
01560         
01561         /* Return result. */
01562         if ( output_len > *ax25frame_len ) output_len = *ax25frame_len;
01563         memcpy(ax25frame, output, output_len);
01564         *ax25frame_len = output_len;
01565         return 1;
01566 }
01567 
01568 
01569 
01570 void fap_init()
01571 {
01572         if ( !fapint_initialized )
01573         {
01574                 /* Compile regexs. */
01575                 regcomp(&fapint_regex_header, "^([A-Z0-9\\-]{1,9})>(.*)$", REG_EXTENDED);
01576                 regcomp(&fapint_regex_ax25call, "^([A-Z0-9]{1,6})(-[0-9]{1,2}|())$", REG_EXTENDED);
01577                 regcomp(&fapint_regex_digicall, "^([a-zA-Z0-9-]{1,9})([*]?)$", REG_EXTENDED);
01578                 regcomp(&fapint_regex_digicallv6, "^([0-9A-F]{32})$", REG_EXTENDED|REG_NOSUB);
01579 
01580                 regcomp(&fapint_regex_normalpos, "^([0-9]{2})([0-7 ][0-9 ]\\.[0-9 ]{2})([NnSs])(.)([0-9]{3})([0-7 ][0-9 ]\\.[0-9 ]{2})([EeWw])(.)", REG_EXTENDED);
01581                 regcomp(&fapint_regex_normalamb, "^([0-9]{0,4})( {0,4})$", REG_EXTENDED);
01582                 regcomp(&fapint_regex_timestamp, "^([0-9]{2})([0-9]{2})([0-9]{2})([zh\\/])", REG_EXTENDED);
01583 
01584                 regcomp(&fapint_regex_mice_dstcall, "^[0-9A-LP-Z]{3}[0-9LP-Z]{3}$", REG_EXTENDED|REG_NOSUB);      
01585                 regcomp(&fapint_regex_mice_body, "^[\\/\\\\A-Z0-9]", REG_EXTENDED|REG_NOSUB);
01586                 regcomp(&fapint_regex_mice_amb, "^([0-9]+)(_*)$", REG_EXTENDED);
01587                 
01588                 regcomp(&fapint_regex_comment, "^([0-9\\. ]{3})\\/([0-9\\. ]{3})", REG_EXTENDED|REG_NOSUB);
01589                 regcomp(&fapint_regex_phgr, "^PHG([0-9].[0-9]{2}[1-9A-Z])\\/", REG_EXTENDED|REG_NOSUB);
01590                 regcomp(&fapint_regex_phg, "^PHG([0-9].[0-9]{2})", REG_EXTENDED|REG_NOSUB);
01591                 regcomp(&fapint_regex_rng, "^RNG([0-9]{4})", REG_EXTENDED|REG_NOSUB);
01592                 regcomp(&fapint_regex_altitude, "\\/A=(-[0-9]{5}|[0-9]{6})", REG_EXTENDED);
01593                 
01594                 regcomp(&fapint_regex_mes_dst, "^:([A-Za-z0-9_ -]{9}):", REG_EXTENDED);
01595                 regcomp(&fapint_regex_mes_ack, "^ack([A-Za-z0-9}]{1,5}) *$", REG_EXTENDED);
01596                 regcomp(&fapint_regex_mes_nack, "^rej([A-Za-z0-9}]{1,5}) *$", REG_EXTENDED);
01597 
01598                 regcomp(&fapint_regex_wx1, "^_{0,1}([0-9 \\.\\-]{3})\\/([0-9 \\.]{3})g([0-9 \\.]+)t(-{0,1}[0-9 \\.]+)", REG_EXTENDED);
01599                 regcomp(&fapint_regex_wx2, "^_{0,1}c([0-9 \\.\\-]{3})s([0-9 \\.]{3})g([0-9 \\.]+)t(-{0,1}[0-9 \\.]+)", REG_EXTENDED);
01600                 regcomp(&fapint_regex_wx3, "^_{0,1}([0-9 \\.\\-]{3})\\/([0-9 \\.]{3})t(-{0,1}[0-9 \\.]+)", REG_EXTENDED);
01601                 regcomp(&fapint_regex_wx4, "^_{0,1}([0-9 \\.\\-]{3})\\/([0-9 \\.]{3})g([0-9 \\.]+)", REG_EXTENDED);
01602                 regcomp(&fapint_regex_wx5, "^g([0-9]+)t(-?[0-9 \\.]{1,3})", REG_EXTENDED);
01603  
01604                 regcomp(&fapint_regex_wx_r1, "r([0-9]{1,3})", REG_EXTENDED);
01605                 regcomp(&fapint_regex_wx_r24, "p([0-9]{1,3})", REG_EXTENDED);
01606                 regcomp(&fapint_regex_wx_rami, "P([0-9]{1,3})", REG_EXTENDED);
01607 
01608                 regcomp(&fapint_regex_wx_humi, "h([0-9]{1,3})", REG_EXTENDED);
01609                 regcomp(&fapint_regex_wx_pres, "b([0-9]{4,5})", REG_EXTENDED);
01610                 regcomp(&fapint_regex_wx_lumi, "([lL])([0-9]{1,3})", REG_EXTENDED);
01611                 regcomp(&fapint_regex_wx_what, "v([\\-\\+]{0,1}[0-9]+)", REG_EXTENDED);
01612                 
01613                 regcomp(&fapint_regex_wx_snow, "s([0-9]+)", REG_EXTENDED);
01614                 regcomp(&fapint_regex_wx_rrc, "#([0-9]+)", REG_EXTENDED);
01615                 regcomp(&fapint_regex_wx_any, "^([rPphblLs#][\\. ]{1,5})+", REG_EXTENDED);
01616                 regcomp(&fapint_regex_wx_soft, "^[a-zA-Z0-9\\-\\_]{3,5}$", REG_EXTENDED|REG_NOSUB);
01617                 
01618                 regcomp(&fapint_regex_nmea_chksum, "^(.+)\\*([0-9A-F]{2})$", REG_EXTENDED);
01619                 regcomp(&fapint_regex_nmea_dst, "^(GPS|SPC)([A-Z0-9]{2,3})", REG_EXTENDED);
01620                 regcomp(&fapint_regex_nmea_time, "^[:space:]*([0-9]{2})([0-9]{2})([0-9]{2})(()|\\.[0-9]+)[:space:]*$", REG_EXTENDED);
01621                 regcomp(&fapint_regex_nmea_date, "^[:space:]*([0-9]{2})([0-9]{2})([0-9]{2})[:space:]*$", REG_EXTENDED);
01622 
01623                 regcomp(&fapint_regex_nmea_specou, "^[:space:]*([0-9]+(()|\\.[0-9]+))[:space:]*$", REG_EXTENDED);
01624                 regcomp(&fapint_regex_nmea_fix, "^[:space:]*([0-9]+)[:space:]*$", REG_EXTENDED);
01625                 regcomp(&fapint_regex_nmea_altitude, "^(-?[0-9]+(()|\\.[0-9]+))$", REG_EXTENDED);
01626                 regcomp(&fapint_regex_nmea_flag, "^[:space:]*([NSEWnsew])[:space:]*$", REG_EXTENDED);
01627                 regcomp(&fapint_regex_nmea_coord, "^[:space:]*([0-9]{1,3})([0-5][0-9]\\.([0-9]+))[:space:]*$", REG_EXTENDED);
01628 
01629                 regcomp(&fapint_regex_telemetry, "^([0-9]+),(-?)([0-9]{1,6}|[0-9]+\\.[0-9]+|\\.[0-9]+)?,(-?)([0-9]{1,6}|[0-9]+\\.[0-9]+|\\.[0-9]+)?,(-?)([0-9]{1,6}|[0-9]+\\.[0-9]+|\\.[0-9]+)?,(-?)([0-9]{1,6}|[0-9]+\\.[0-9]+|\\.[0-9]+)?,(-?)([0-9]{1,6}|[0-9]+\\.[0-9]+|\\.[0-9]+)?,([01]{0,8})", REG_EXTENDED);
01630                 regcomp(&fapint_regex_peet_splitter, "^([0-9a-f]{4}|----)", REG_EXTENDED|REG_ICASE);
01631                 regcomp(&fapint_regex_kiss_callsign, "^([A-Z0-9]+) *(-[0-9]+)?$", REG_EXTENDED);
01632 
01633                 regcomp(&fapint_regex_detect_comp, "^[\\/\\\\A-Za-j]$", REG_EXTENDED|REG_NOSUB);
01634                 regcomp(&fapint_regex_detect_wx, "^_([0-9]{8})c[- .0-9]{1,3}s[- .0-9]{1,3}", REG_EXTENDED|REG_NOSUB);
01635                 regcomp(&fapint_regex_detect_telem, "^T#(.*?),(.*)$", REG_EXTENDED|REG_NOSUB);
01636                 regcomp(&fapint_regex_detect_exp, "^\\{\\{", REG_EXTENDED|REG_NOSUB);
01637         
01638                 regcomp(&fapint_regex_kiss_hdrbdy, "^([A-Z0-9,*>-]+):(.+)$", REG_EXTENDED);
01639                 regcomp(&fapint_regex_hdr_detail, "^([A-Z0-9]{1,6})(-[0-9]{1,2})?>([A-Z0-9]{1,6})(-[0-9]{1,2})?(,.*)?$", REG_EXTENDED);
01640                 regcomp(&fapint_regex_kiss_digi, "^([A-Z0-9]{1,6})(-[0-9]{1,2})?(\\*)?$", REG_EXTENDED);
01641                 
01642                 regcomp(&fapint_regex_hopcount1, "^([A-Z0-9-]+)\\*$", REG_EXTENDED);
01643                 regcomp(&fapint_regex_hopcount2, "^WIDE([1-7])-([0-7])$", REG_EXTENDED);
01644         
01645                 
01646                 /* Initialized. */
01647                 fapint_initialized = 1;
01648         }
01649 }
01650 
01651 
01652 
01653 void fap_cleanup()
01654 {
01655         if ( fapint_initialized )
01656         {
01657                 /* Free regexs. */
01658                 regfree(&fapint_regex_header);
01659                 regfree(&fapint_regex_ax25call);
01660                 regfree(&fapint_regex_digicall);
01661                 regfree(&fapint_regex_digicallv6);
01662 
01663                 regfree(&fapint_regex_normalpos);
01664                 regfree(&fapint_regex_normalamb);
01665                 regfree(&fapint_regex_timestamp);
01666                 
01667                 regfree(&fapint_regex_mice_dstcall);
01668                 regfree(&fapint_regex_mice_body);
01669                 regfree(&fapint_regex_mice_amb);
01670                 
01671                 regfree(&fapint_regex_comment);
01672                 regfree(&fapint_regex_phgr);
01673                 regfree(&fapint_regex_phg);
01674                 regfree(&fapint_regex_rng);
01675                 regfree(&fapint_regex_altitude);
01676                 
01677                 regfree(&fapint_regex_mes_dst);
01678                 regfree(&fapint_regex_mes_ack);
01679                 regfree(&fapint_regex_mes_nack);
01680                 
01681                 regfree(&fapint_regex_wx1);
01682                 regfree(&fapint_regex_wx2);
01683                 regfree(&fapint_regex_wx3);
01684                 regfree(&fapint_regex_wx4);
01685                 regfree(&fapint_regex_wx5);
01686                 
01687                 regfree(&fapint_regex_wx_r1);
01688                 regfree(&fapint_regex_wx_r24);
01689                 regfree(&fapint_regex_wx_rami);
01690 
01691                 regfree(&fapint_regex_wx_humi);
01692                 regfree(&fapint_regex_wx_pres);
01693                 regfree(&fapint_regex_wx_lumi);
01694                 regfree(&fapint_regex_wx_what);
01695                 
01696                 regfree(&fapint_regex_wx_snow);
01697                 regfree(&fapint_regex_wx_rrc);
01698                 regfree(&fapint_regex_wx_any);
01699                 regfree(&fapint_regex_wx_soft);
01700                 
01701                 regfree(&fapint_regex_nmea_chksum);
01702                 regfree(&fapint_regex_nmea_dst);
01703                 regfree(&fapint_regex_nmea_time);
01704                 regfree(&fapint_regex_nmea_date);
01705 
01706                 regfree(&fapint_regex_nmea_specou);
01707                 regfree(&fapint_regex_nmea_fix);
01708                 regfree(&fapint_regex_nmea_altitude);
01709                 regfree(&fapint_regex_nmea_flag);
01710                 regfree(&fapint_regex_nmea_coord);
01711                 
01712                 regfree(&fapint_regex_telemetry);
01713                 regfree(&fapint_regex_peet_splitter);
01714                 regfree(&fapint_regex_kiss_callsign);
01715                 
01716                 regfree(&fapint_regex_detect_comp);
01717                 regfree(&fapint_regex_detect_wx);
01718                 regfree(&fapint_regex_detect_telem);
01719                 regfree(&fapint_regex_detect_exp);
01720                 
01721                 regfree(&fapint_regex_kiss_hdrbdy);
01722                 regfree(&fapint_regex_hdr_detail);
01723                 regfree(&fapint_regex_kiss_digi);
01724                 
01725                 regfree(&fapint_regex_hopcount1);
01726                 regfree(&fapint_regex_hopcount2);
01727                 
01728                 /* No more initialized. */
01729                 fapint_initialized = 0;
01730         }
01731 }
01732 
01733 
01734 
01735 void fap_free(fap_packet_t* packet)
01736 {
01737         unsigned int i;
01738         
01739         if ( packet == NULL )
01740         {
01741                 return;
01742         }
01743 
01744         if ( packet->error_code ) { free(packet->error_code); }
01745         if ( packet->type ) { free(packet->type); }
01746         
01747         if ( packet->orig_packet ) { free(packet->orig_packet); }
01748 
01749         if ( packet->header ) { free(packet->header); }
01750         if ( packet->body ) { free(packet->body); }
01751         if ( packet->src_callsign ) { free(packet->src_callsign); }
01752         if ( packet->dst_callsign ) { free(packet->dst_callsign); }
01753         for ( i = 0; i < packet->path_len; ++i )
01754         {
01755                 if ( packet->path[i] ) { free(packet->path[i]); }
01756         }
01757         if ( packet->path ) { free(packet->path); }
01758 
01759         if ( packet->latitude ) { free(packet->latitude); }
01760         if ( packet->longitude ) { free(packet->longitude); }
01761         if ( packet->format ) { free(packet->format); }
01762         if ( packet->pos_resolution ) { free(packet->pos_resolution); }
01763         if ( packet->pos_ambiguity ) { free(packet->pos_ambiguity); }
01764         
01765         if ( packet->altitude ) { free(packet->altitude); }
01766         if ( packet->course ) { free(packet->course); }
01767         if ( packet->speed ) { free(packet->speed); }
01768 
01769         if ( packet->messaging ) { free(packet->messaging); }   
01770         if ( packet->destination ) { free(packet->destination); }
01771         if ( packet->message ) { free(packet->message); }   
01772         if ( packet->message_ack ) { free(packet->message_ack); }   
01773         if ( packet->message_nack ) { free(packet->message_nack); }   
01774         if ( packet->message_id ) { free(packet->message_id); }   
01775         if ( packet->comment ) { free(packet->comment); }
01776 
01777         if ( packet->object_or_item_name ) { free(packet->object_or_item_name); }
01778         if ( packet->alive ) { free(packet->alive); }
01779 
01780         if ( packet->gps_fix_status ) { free(packet->gps_fix_status); }
01781         if ( packet->radio_range ) { free(packet->radio_range); }
01782         if ( packet->phg ) { free(packet->phg); }
01783         if ( packet->timestamp ) { free(packet->timestamp); }
01784         if ( packet->nmea_checksum_ok ) { free(packet->nmea_checksum_ok); }
01785         
01786         if ( packet->wx_report )
01787         {
01788                 if ( packet->wx_report->wind_gust ) { free(packet->wx_report->wind_gust); }
01789                 if ( packet->wx_report->wind_dir ) { free(packet->wx_report->wind_dir); }
01790                 if ( packet->wx_report->wind_speed ) { free(packet->wx_report->wind_speed); }
01791 
01792                 if ( packet->wx_report->temp ) { free(packet->wx_report->temp); }
01793                 if ( packet->wx_report->temp_in ) { free(packet->wx_report->temp_in); }
01794 
01795                 if ( packet->wx_report->rain_1h ) { free(packet->wx_report->rain_1h); }
01796                 if ( packet->wx_report->rain_24h ) { free(packet->wx_report->rain_24h); }
01797                 if ( packet->wx_report->rain_midnight ) { free(packet->wx_report->rain_midnight); }
01798                 
01799                 if ( packet->wx_report->humidity ) { free(packet->wx_report->humidity); }
01800                 if ( packet->wx_report->humidity_in ) { free(packet->wx_report->humidity_in); }
01801                 
01802                 if ( packet->wx_report->pressure ) { free(packet->wx_report->pressure); }
01803                 if ( packet->wx_report->luminosity ) { free(packet->wx_report->luminosity); }
01804 
01805                 if ( packet->wx_report->snow_24h ) { free(packet->wx_report->snow_24h); }
01806 
01807                 if ( packet->wx_report->soft ) { free(packet->wx_report->soft); }
01808 
01809                 free(packet->wx_report);
01810         }
01811         
01812         if ( packet->telemetry ) { free(packet->telemetry); }
01813 
01814         if ( packet->messagebits ) { free(packet->messagebits); }
01815         if ( packet->status ) { free(packet->status); }
01816         for ( i = 0; i < packet->capabilities_len*2; i += 2 )
01817         {
01818                 if ( packet->capabilities[i] ) { free(packet->capabilities[i]); }
01819                 if ( packet->capabilities[i+1] ) { free(packet->capabilities[i+1]); }
01820         }
01821         if ( packet->capabilities ) { free(packet->capabilities); }
01822         
01823         free(packet);
01824 }

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