// // This file is part of Dire Wolf, an amateur radio packet TNC. // // Copyright (C) 2011, 2012, 2013 John Langner, WB2OSZ // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 2 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program. If not, see . // /******************************************************************************** * * File: hdlc_rec2.c * * Purpose: Extract HDLC frame from a block of bits after someone * else has done the work of pulling it out from between * the special "flag" sequences. * *******************************************************************************/ #include #include #include #include "direwolf.h" #include "hdlc_rec2.h" #include "fcs_calc.h" #include "textcolor.h" #include "ax25_pad.h" #include "rrbb.h" #include "rdq.h" #include "multi_modem.h" /* * Minimum & maximum sizes of an AX.25 frame including the 2 octet FCS. */ #define MIN_FRAME_LEN ((AX25_MIN_PACKET_LEN) + 2) #define MAX_FRAME_LEN ((AX25_MAX_PACKET_LEN) + 2) /* * This is the current state of the HDLC decoder. * * It is possible to run multiple decoders concurrently by * having a separate set of state variables for each. * * Should have a reset function instead of initializations here. */ struct hdlc_state_s { int prev_raw; /* Keep track of previous bit so */ /* we can look for transitions. */ /* Should be only 0 or 1. */ unsigned char pat_det; /* 8 bit pattern detector shift register. */ /* See below for more details. */ unsigned char oacc; /* Accumulator for building up an octet. */ int olen; /* Number of bits in oacc. */ /* When this reaches 8, oacc is copied */ /* to the frame buffer and olen is zeroed. */ unsigned char frame_buf[MAX_FRAME_LEN]; /* One frame is kept here. */ int frame_len; /* Number of octets in frame_buf. */ /* Should be in range of 0 .. MAX_FRAME_LEN. */ }; static int try_decode (rrbb_t block, int chan, int subchan, int alevel, retry_t bits_flipped, int flip_a, int flip_b, int flip_c); static int try_to_fix_quick_now (rrbb_t block, int chan, int subchan, int alevel, retry_t fix_bits); static int sanity_check (unsigned char *buf, int blen, retry_t bits_flipped); #if DEBUG static double dtime_now (void); #endif /*********************************************************************************** * * Name: hdlc_rec2_block * * Purpose: Extract HDLC frame from a stream of bits. * * Inputs: block - Handle for bit array. * fix_bits - Level of effort to recover frames with bad FCS. * * Description: The other (original) hdlc decoder took one bit at a time * right out of the demodulator. * * This is different in that it processes a block of bits * previously extracted from between two "flag" patterns. * * This allows us to try decoding the same received data more * than once. * * Bugs: This does not work for 9600 baud, more accurately when * the transmitted bits are scrambled. * * Currently we unscramble the bits as they come from the * receiver. Instead we need to save the original received * bits and apply the descrambling after flipping the bits. * ***********************************************************************************/ void hdlc_rec2_block (rrbb_t block, retry_t fix_bits) { int chan = rrbb_get_chan(block); int subchan = rrbb_get_subchan(block); int alevel = rrbb_get_audio_level(block); int ok; int n; #if DEBUGx text_color_set(DW_COLOR_DEBUG); dw_printf ("\n--- try to decode ---\n"); #endif #if SLICENDICE /* * Unfinished experiment. Get back to this again someday. * The demodulator output is (should be) roughly in the range of -1 to 1. * Formerly we sliced it at 0 and saved only a single bit for the sample. * Now we save the sample so we can try adjusting the slicing point. * * First time thru, set the slicing point to 0. */ for (n = 0; n < 1 ; n++) { rrbb_set_slice_val (block, n); ok = try_decode (block, chan, subchan, alevel, RETRY_NONE, -1, -1, -1); if (ok) { //#if DEBUG text_color_set(DW_COLOR_INFO); dw_printf ("Got it with no errors. Slice val = %d \n", n); //#endif rrbb_delete (block); return; } } rrbb_set_slice_val (block, 0); #else /* not SLICENDICE */ ok = try_decode (block, chan, subchan, alevel, RETRY_NONE, -1, -1, -1); if (ok) { #if DEBUG text_color_set(DW_COLOR_INFO); dw_printf ("Got it the first time.\n"); #endif rrbb_delete (block); return; } #endif if (try_to_fix_quick_now (block, chan, subchan, alevel, fix_bits)) { rrbb_delete (block); return; } /* * Put in queue for retrying later at lower priority. */ if (fix_bits < RETRY_TWO_SEP) { rrbb_delete (block); return; } rdq_append (block); } static int try_to_fix_quick_now (rrbb_t block, int chan, int subchan, int alevel, retry_t fix_bits) { int ok; int len, i; len = rrbb_get_len(block); /* * Try fixing one bit. */ if (fix_bits < RETRY_SINGLE) { return 0; } for (i=0; i>= 1; if (dbit) { H.pat_det |= 0x80; } if (H.pat_det == 0x7e) { /* The special pattern 01111110 indicates beginning and ending of a frame. */ #if DEBUGx text_color_set(DW_COLOR_DEBUG); dw_printf ("try_decode: found flag, i=%d\n", i); #endif return 0; } else if (H.pat_det == 0xfe) { /* Valid data will never have 7 one bits in a row. */ #if DEBUGx text_color_set(DW_COLOR_DEBUG); dw_printf ("try_decode: found abort, i=%d\n", i); #endif return 0; } else if ( (H.pat_det & 0xfc) == 0x7c ) { /* * If we have five '1' bits in a row, followed by a '0' bit, * * 0111110xx * * the current '0' bit should be discarded because it was added for * "bit stuffing." */ ; } else { /* * In all other cases, accumulate bits into octets, and complete octets * into the frame buffer. */ H.oacc >>= 1; if (dbit) { H.oacc |= 0x80; } H.olen++; if (H.olen == 8) { H.olen = 0; if (H.frame_len < MAX_FRAME_LEN) { H.frame_buf[H.frame_len] = H.oacc; H.frame_len++; } } } } /* end of loop on all bits in block */ /* * Do we have a minimum number of complete bytes? */ #if DEBUGx text_color_set(DW_COLOR_DEBUG); dw_printf ("try_decode: olen=%d, frame_len=%d\n", H.olen, H.frame_len); #endif if (H.olen == 0 && H.frame_len >= MIN_FRAME_LEN) { unsigned short actual_fcs, expected_fcs; #if DEBUGx int j; text_color_set(DW_COLOR_DEBUG); dw_printf ("NEW WAY: frame len = %d\n", H.frame_len); for (j=0; j 10) { #if DEBUGx text_color_set(DW_COLOR_ERROR); dw_printf ("sanity_check: FAILED. Too few or many addresses.\n"); #endif return 0; } /* * Addresses can contain only upper case letters, digits, and space. */ for (j=0; j> 1; addr[1] = buf[j+1] >> 1; addr[2] = buf[j+2] >> 1; addr[3] = buf[j+3] >> 1; addr[4] = buf[j+4] >> 1; addr[5] = buf[j+5] >> 1; addr[6] = '\0'; if ( (! isupper(addr[0]) && ! isdigit(addr[0])) || (! isupper(addr[1]) && ! isdigit(addr[1]) && addr[1] != ' ') || (! isupper(addr[2]) && ! isdigit(addr[2]) && addr[2] != ' ') || (! isupper(addr[3]) && ! isdigit(addr[3]) && addr[3] != ' ') || (! isupper(addr[4]) && ! isdigit(addr[4]) && addr[4] != ' ') || (! isupper(addr[5]) && ! isdigit(addr[5]) && addr[5] != ' ')) { #if DEBUGx text_color_set(DW_COLOR_ERROR); dw_printf ("sanity_check: FAILED. Invalid characters in addresses \"%s\"\n", addr); #endif return 0; } } /* * The next two bytes should be 0x03 and 0xf0 for APRS. * Checking that would mean precluding use for other types of packet operation. * * The next section is also assumes APRS and might discard good data * for other protocols. */ /* * Finally, look for bogus characters in the information part. * In theory, the bytes could have any values. * In practice, we find only printable ASCII characters and: * * 0x0a line feed * 0x0d carriage return * 0x1c MIC-E * 0x1d MIC-E * 0x1e MIC-E * 0x1f MIC-E * 0x7f MIC-E * 0x80 "{UIV32N}<0x0d><0x9f><0x80>" * 0x9f "{UIV32N}<0x0d><0x9f><0x80>" * 0xb0 degree symbol, ISO LATIN1 * (Note: UTF-8 uses two byte sequence 0xc2 0xb0.) * 0xbe invalid MIC-E encoding. * 0xf8 degree symbol, Microsoft code page 437 * * So, if we have something other than these (in English speaking countries!), * chances are that we have bogus data from twiddling the wrong bits. * * Notice that we shouldn't get here for good packets. This extra level * of checking happens only if we twiddled a couple of bits, possibly * creating bad data. We want to be very fussy. */ for (j=alen+2; j= 0x1c && ch <= 0x7f) || ch == 0x0a || ch == 0x0d || ch == 0x80 || ch == 0x9f || ch == 0xb0 || ch == 0xf8) ) { #if DEBUGx text_color_set(DW_COLOR_ERROR); dw_printf ("sanity_check: FAILED. Probably bogus info char 0x%02x\n", ch); #endif return 0; } } return 1; } /* end hdlc_rec2.c */ // TODO: Also in xmit.c. Move to some common location. /* Current time in seconds but more resolution than time(). */ /* We don't care what date a 0 value represents because we */ /* only use this to calculate elapsed time. */ #if DEBUG static double dtime_now (void) { #if __WIN32__ /* 64 bit integer is number of 100 nanosecond intervals from Jan 1, 1601. */ FILETIME ft; GetSystemTimeAsFileTime (&ft); return ((( (double)ft.dwHighDateTime * (256. * 256. * 256. * 256.) + (double)ft.dwLowDateTime ) / 10000000.) - 11644473600.); #else /* tv_sec is seconds from Jan 1, 1970. */ struct timespec ts; clock_gettime (CLOCK_REALTIME, &ts); return (ts.tv_sec + ts.tv_nsec / 1000000000.); #endif } #endif