2015-07-27 00:35:07 +00:00
|
|
|
//
|
|
|
|
// This file is part of Dire Wolf, an amateur radio packet TNC.
|
|
|
|
//
|
2015-07-27 01:17:23 +00:00
|
|
|
// Copyright (C) 2011, 2012, 2013, 2014, 2015 John Langner, WB2OSZ
|
2015-07-27 00:35:07 +00:00
|
|
|
//
|
|
|
|
// 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 <http://www.gnu.org/licenses/>.
|
|
|
|
//
|
|
|
|
|
|
|
|
|
2015-07-27 01:17:23 +00:00
|
|
|
|
2015-07-27 00:35:07 +00:00
|
|
|
/********************************************************************************
|
|
|
|
*
|
|
|
|
* File: hdlc_rec.c
|
|
|
|
*
|
|
|
|
* Purpose: Extract HDLC frames from a stream of bits.
|
|
|
|
*
|
|
|
|
*******************************************************************************/
|
|
|
|
|
2016-07-03 22:09:34 +00:00
|
|
|
#include "direwolf.h"
|
|
|
|
|
2015-07-27 00:35:07 +00:00
|
|
|
#include <stdio.h>
|
|
|
|
#include <assert.h>
|
2015-11-29 15:44:30 +00:00
|
|
|
#include <string.h>
|
2020-06-14 01:33:10 +00:00
|
|
|
#include <stdint.h> // uint64_t
|
2015-07-27 00:35:07 +00:00
|
|
|
|
2019-05-13 10:25:12 +00:00
|
|
|
//#include "tune.h"
|
2015-07-27 00:35:07 +00:00
|
|
|
#include "demod.h"
|
|
|
|
#include "hdlc_rec.h"
|
|
|
|
#include "hdlc_rec2.h"
|
|
|
|
#include "fcs_calc.h"
|
|
|
|
#include "textcolor.h"
|
|
|
|
#include "ax25_pad.h"
|
|
|
|
#include "rrbb.h"
|
|
|
|
#include "multi_modem.h"
|
2015-07-27 01:17:23 +00:00
|
|
|
#include "demod_9600.h" /* for descramble() */
|
|
|
|
#include "ptt.h"
|
2020-01-06 01:08:22 +00:00
|
|
|
#include "fx25.h"
|
2021-10-22 21:29:20 +00:00
|
|
|
#include "il2p.h"
|
2015-07-27 00:35:07 +00:00
|
|
|
|
|
|
|
|
|
|
|
//#define TEST 1 /* Define for unit testing. */
|
|
|
|
|
|
|
|
//#define DEBUG3 1 /* monitor the data detect signal. */
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* 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 {
|
|
|
|
|
2015-07-27 01:17:23 +00:00
|
|
|
|
2015-07-27 00:35:07 +00:00
|
|
|
int prev_raw; /* Keep track of previous bit so */
|
|
|
|
/* we can look for transitions. */
|
|
|
|
/* Should be only 0 or 1. */
|
|
|
|
|
2015-07-27 01:17:23 +00:00
|
|
|
int lfsr; /* Descrambler shift register for 9600 baud. */
|
|
|
|
|
|
|
|
int prev_descram; /* Previous descrambled for 9600 baud. */
|
|
|
|
|
2015-07-27 00:35:07 +00:00
|
|
|
unsigned char pat_det; /* 8 bit pattern detector shift register. */
|
|
|
|
/* See below for more details. */
|
|
|
|
|
|
|
|
unsigned int flag4_det; /* Last 32 raw bits to look for 4 */
|
|
|
|
/* flag patterns in a row. */
|
|
|
|
|
|
|
|
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. */
|
|
|
|
/* The value of -1 is a special case meaning */
|
|
|
|
/* bits should not be accumulated. */
|
|
|
|
|
|
|
|
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. */
|
|
|
|
|
|
|
|
rrbb_t rrbb; /* Handle for bit array for raw received bits. */
|
2020-06-14 01:33:10 +00:00
|
|
|
|
|
|
|
uint64_t eas_acc; /* Accumulate most recent 64 bits received for EAS. */
|
|
|
|
|
|
|
|
int eas_gathering; /* Decoding in progress. */
|
|
|
|
|
|
|
|
int eas_plus_found; /* "+" seen, indicating end of geographical area list. */
|
|
|
|
|
|
|
|
int eas_fields_after_plus; /* Number of "-" characters after the "+". */
|
2015-07-27 00:35:07 +00:00
|
|
|
};
|
|
|
|
|
2015-11-29 15:44:30 +00:00
|
|
|
static struct hdlc_state_s hdlc_state[MAX_CHANS][MAX_SUBCHANS][MAX_SLICERS];
|
2015-07-27 00:35:07 +00:00
|
|
|
|
2015-07-27 01:17:23 +00:00
|
|
|
static int num_subchan[MAX_CHANS]; //TODO1.2 use ptr rather than copy.
|
|
|
|
|
2015-11-29 15:44:30 +00:00
|
|
|
static int composite_dcd[MAX_CHANS][MAX_SUBCHANS+1];
|
2015-07-27 00:35:07 +00:00
|
|
|
|
|
|
|
|
|
|
|
/***********************************************************************************
|
|
|
|
*
|
|
|
|
* Name: hdlc_rec_init
|
|
|
|
*
|
|
|
|
* Purpose: Call once at the beginning to initialize.
|
|
|
|
*
|
|
|
|
* Inputs: None.
|
|
|
|
*
|
|
|
|
***********************************************************************************/
|
|
|
|
|
|
|
|
static int was_init = 0;
|
|
|
|
|
2020-01-06 01:08:22 +00:00
|
|
|
static struct audio_s *g_audio_p;
|
|
|
|
|
2020-05-22 01:37:34 +00:00
|
|
|
|
2015-07-27 00:35:07 +00:00
|
|
|
void hdlc_rec_init (struct audio_s *pa)
|
|
|
|
{
|
2015-11-29 15:44:30 +00:00
|
|
|
int ch, sub, slice;
|
2015-07-27 00:35:07 +00:00
|
|
|
struct hdlc_state_s *H;
|
|
|
|
|
|
|
|
//text_color_set(DW_COLOR_DEBUG);
|
|
|
|
//dw_printf ("hdlc_rec_init (%p) \n", pa);
|
|
|
|
|
|
|
|
assert (pa != NULL);
|
2020-01-06 01:08:22 +00:00
|
|
|
g_audio_p = pa;
|
|
|
|
|
2015-11-29 15:44:30 +00:00
|
|
|
memset (composite_dcd, 0, sizeof(composite_dcd));
|
|
|
|
|
|
|
|
for (ch = 0; ch < MAX_CHANS; ch++)
|
2015-07-27 00:35:07 +00:00
|
|
|
{
|
|
|
|
|
2021-12-10 03:30:31 +00:00
|
|
|
if (pa->chan_medium[ch] == MEDIUM_RADIO) {
|
2015-07-27 00:35:07 +00:00
|
|
|
|
2015-11-29 15:44:30 +00:00
|
|
|
num_subchan[ch] = pa->achan[ch].num_subchan;
|
2015-07-27 00:35:07 +00:00
|
|
|
|
2015-11-29 15:44:30 +00:00
|
|
|
assert (num_subchan[ch] >= 1 && num_subchan[ch] <= MAX_SUBCHANS);
|
2015-07-27 01:17:23 +00:00
|
|
|
|
2015-11-29 15:44:30 +00:00
|
|
|
for (sub = 0; sub < num_subchan[ch]; sub++)
|
2015-07-27 01:17:23 +00:00
|
|
|
{
|
2015-11-29 15:44:30 +00:00
|
|
|
for (slice = 0; slice < MAX_SLICERS; slice++) {
|
|
|
|
|
|
|
|
H = &hdlc_state[ch][sub][slice];
|
|
|
|
|
|
|
|
H->olen = -1;
|
|
|
|
|
|
|
|
// TODO: FIX13 wasteful if not needed.
|
|
|
|
// Should loop on number of slicers, not max.
|
|
|
|
|
|
|
|
H->rrbb = rrbb_new(ch, sub, slice, pa->achan[ch].modem_type == MODEM_SCRAMBLE, H->lfsr, H->prev_descram);
|
|
|
|
}
|
2015-07-27 01:17:23 +00:00
|
|
|
}
|
2015-07-27 00:35:07 +00:00
|
|
|
}
|
|
|
|
}
|
2015-07-27 01:17:23 +00:00
|
|
|
hdlc_rec2_init (pa);
|
2015-07-27 00:35:07 +00:00
|
|
|
was_init = 1;
|
|
|
|
}
|
|
|
|
|
2020-01-06 01:08:22 +00:00
|
|
|
/* Own copy of random number generator so we can get */
|
|
|
|
/* same predictable results on different operating systems. */
|
|
|
|
/* TODO: Consolidate multiple copies somewhere. */
|
|
|
|
|
|
|
|
#define MY_RAND_MAX 0x7fffffff
|
|
|
|
static int seed = 1;
|
2015-07-27 00:35:07 +00:00
|
|
|
|
2020-01-06 01:08:22 +00:00
|
|
|
static int my_rand (void) {
|
|
|
|
// Perform the calculation as unsigned to avoid signed overflow error.
|
|
|
|
seed = (int)(((unsigned)seed * 1103515245) + 12345) & MY_RAND_MAX;
|
|
|
|
return (seed);
|
|
|
|
}
|
2015-07-27 00:35:07 +00:00
|
|
|
|
2020-06-14 01:33:10 +00:00
|
|
|
|
|
|
|
/***********************************************************************************
|
|
|
|
*
|
|
|
|
* Name: eas_rec_bit
|
|
|
|
*
|
|
|
|
* Purpose: Extract EAS trasmissions from a stream of bits.
|
|
|
|
*
|
|
|
|
* Inputs: chan - Channel number.
|
|
|
|
*
|
|
|
|
* subchan - This allows multiple demodulators per channel.
|
|
|
|
*
|
|
|
|
* slice - Allows multiple slicers per demodulator (subchannel).
|
|
|
|
*
|
|
|
|
* raw - One bit from the demodulator.
|
|
|
|
* should be 0 or 1.
|
|
|
|
*
|
|
|
|
* future_use - Not implemented yet. PSK already provides it.
|
|
|
|
*
|
|
|
|
*
|
|
|
|
* Description: This is called once for each received bit.
|
|
|
|
* For each valid transmission, process_rec_frame()
|
|
|
|
* is called for further processing.
|
|
|
|
*
|
|
|
|
***********************************************************************************/
|
|
|
|
|
|
|
|
#define PREAMBLE 0xababababababababULL
|
|
|
|
#define PREAMBLE_ZCZC 0x435a435aababababULL
|
|
|
|
#define PREAMBLE_NNNN 0x4e4e4e4eababababULL
|
|
|
|
#define EAS_MAX_LEN 268 // Not including preamble. Up to 31 geographic areas.
|
|
|
|
|
|
|
|
|
|
|
|
static void eas_rec_bit (int chan, int subchan, int slice, int raw, int future_use)
|
|
|
|
{
|
|
|
|
struct hdlc_state_s *H;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Different state information for each channel / subchannel / slice.
|
|
|
|
*/
|
|
|
|
H = &hdlc_state[chan][subchan][slice];
|
|
|
|
|
|
|
|
//dw_printf ("slice %d = %d\n", slice, raw);
|
|
|
|
|
|
|
|
// Accumulate most recent 64 bits.
|
|
|
|
|
|
|
|
H->eas_acc >>= 1;
|
|
|
|
if (raw) {
|
|
|
|
H->eas_acc |= 0x8000000000000000ULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
int done = 0;
|
|
|
|
|
|
|
|
if (H->eas_acc == PREAMBLE_ZCZC) {
|
|
|
|
//dw_printf ("ZCZC\n");
|
|
|
|
H->olen = 0;
|
|
|
|
H->eas_gathering = 1;
|
|
|
|
H->eas_plus_found = 0;
|
|
|
|
H->eas_fields_after_plus = 0;
|
|
|
|
strlcpy ((char*)(H->frame_buf), "ZCZC", sizeof(H->frame_buf));
|
|
|
|
H->frame_len = 4;
|
|
|
|
}
|
|
|
|
else if (H->eas_acc == PREAMBLE_NNNN) {
|
|
|
|
//dw_printf ("NNNN\n");
|
|
|
|
H->olen = 0;
|
|
|
|
H->eas_gathering = 1;
|
|
|
|
strlcpy ((char*)(H->frame_buf), "NNNN", sizeof(H->frame_buf));
|
|
|
|
H->frame_len = 4;
|
|
|
|
done = 1;
|
|
|
|
}
|
|
|
|
else if (H->eas_gathering) {
|
|
|
|
H->olen++;
|
|
|
|
if (H->olen == 8) {
|
|
|
|
H->olen = 0;
|
|
|
|
char ch = H->eas_acc >> 56;
|
|
|
|
H->frame_buf[H->frame_len++] = ch;
|
|
|
|
H->frame_buf[H->frame_len] = '\0';
|
|
|
|
//dw_printf ("frame_buf = %s\n", H->frame_buf);
|
|
|
|
|
|
|
|
// What characters are acceptable?
|
|
|
|
// Only ASCII is allowed. i.e. the MSB must be 0.
|
|
|
|
// The examples show only digits but the geographical area can
|
|
|
|
// contain anything in range of '!' to DEL or CR or LF.
|
|
|
|
// There are no restrictions listed for the originator and
|
|
|
|
// examples contain a slash.
|
|
|
|
// It's not clear if a space can occur in other places.
|
|
|
|
|
|
|
|
if ( ! (( ch >= ' ' && ch <= 0x7f) || ch == '\r' || ch == '\n')) {
|
|
|
|
//#define DEBUG_E 1
|
|
|
|
#ifdef DEBUG_E
|
|
|
|
dw_printf ("reject %d invalid character = %s\n", slice, H->frame_buf);
|
|
|
|
#endif
|
|
|
|
H->eas_gathering = 0;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (H->frame_len > EAS_MAX_LEN) { // FIXME: look for other places with max length
|
|
|
|
#ifdef DEBUG_E
|
|
|
|
dw_printf ("reject %d too long = %s\n", slice, H->frame_buf);
|
|
|
|
#endif
|
|
|
|
H->eas_gathering = 0;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (ch == '+') {
|
|
|
|
H->eas_plus_found = 1;
|
|
|
|
H->eas_fields_after_plus = 0;
|
|
|
|
}
|
|
|
|
if (H->eas_plus_found && ch == '-') {
|
|
|
|
H->eas_fields_after_plus++;
|
|
|
|
if (H->eas_fields_after_plus == 3) {
|
|
|
|
done = 1; // normal case
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (done) {
|
|
|
|
#ifdef DEBUG_E
|
|
|
|
dw_printf ("frame_buf %d = %s\n", slice, H->frame_buf);
|
|
|
|
#endif
|
|
|
|
alevel_t alevel = demod_get_audio_level (chan, subchan);
|
|
|
|
multi_modem_process_rec_frame (chan, subchan, slice, H->frame_buf, H->frame_len, alevel, 0, 0);
|
|
|
|
H->eas_gathering = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
} // end eas_rec_bit
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
|
|
|
EAS has no error detection.
|
|
|
|
Maybe that doesn't matter because we would normally be dealing with a reasonable
|
|
|
|
VHF FM or TV signal.
|
|
|
|
Let's see what happens when we intentionally introduce errors.
|
|
|
|
When some match and others don't, the multislice voting should give preference
|
|
|
|
to those matching others.
|
|
|
|
|
|
|
|
$ src/atest -P+ -B EAS -e 3e-3 ../../ref-doc/EAS/same.wav
|
|
|
|
Demodulator profile set to "+"
|
|
|
|
96000 samples per second. 16 bits per sample. 1 audio channels.
|
|
|
|
2079360 audio bytes in file. Duration = 10.8 seconds.
|
|
|
|
Fix Bits level = 0
|
|
|
|
Channel 0: 521 baud, AFSK 2083 & 1563 Hz, D+, 96000 sample rate / 3.
|
|
|
|
|
|
|
|
case 1: Slice 6 is different than others (EQS vs. EAS) so we want one of the others that match.
|
|
|
|
Slice 3 has an unexpected character (in 0120u7) so it is a mismatch.
|
|
|
|
At this point we are not doing validity checking other than all printable characters.
|
|
|
|
|
|
|
|
We are left with 0 & 4 which don't match (012057 vs. 012077).
|
|
|
|
So I guess we don't have any two that match so it is a toss up.
|
|
|
|
|
|
|
|
reject 7 invalid character = ZCZC-EAS-RWT-0120▒
|
|
|
|
reject 5 invalid character = ZCZC-ECW-RWT-012057-012081-012101-012103-012115+003
|
|
|
|
frame_buf 6 = ZCZC-EQS-RWT-012057-012081-012101-012103-012115+0030-2780415-WTSP/TV-
|
|
|
|
frame_buf 4 = ZCZC-EAS-RWT-012077-012081-012101-012103-012115+0030-2780415-WTSP/TV-
|
|
|
|
frame_buf 3 = ZCZC-EAS-RWT-0120u7-012281-012101-012103-092115+0038-2780415-VTSP/TV-
|
|
|
|
frame_buf 0 = ZCZC-EAS-RWT-012057-412081-012101-012103-012115+0030-2780415-WTSP/TV-
|
|
|
|
|
|
|
|
DECODED[1] 0:01.313 EAS audio level = 194(106/108) |__||_|__
|
|
|
|
[0.0] EAS>APDW16:{DEZCZC-EAS-RWT-012057-412081-012101-012103-012115+0030-2780415-WTSP/TV-
|
|
|
|
|
|
|
|
Case 2: We have two that match so pick either one.
|
|
|
|
|
|
|
|
reject 5 invalid character = ZCZC-EAS-RW▒
|
|
|
|
reject 7 invalid character = ZCZC-EAS-RWT-0
|
|
|
|
reject 3 invalid character = ZCZC-EAS-RWT-012057-012080-012101-012103-01211
|
|
|
|
reject 0 invalid character = ZCZC-EAS-RWT-012057-012081-012101-012103-012115+0030-2780415-W▒
|
|
|
|
frame_buf 6 = ZCZC-EAS-RWT-012057-012081-012!01-012103-012115+0030-2780415-WTSP/TV-
|
|
|
|
frame_buf 1 = ZCZC-EAS-RWT-012057-012081-012101-012103-012115+0030-2780415-WTSP/TV-
|
|
|
|
|
|
|
|
DECODED[2] 0:03.617 EAS audio level = 194(106/108) _|____|__
|
|
|
|
[0.1] EAS>APDW16:{DEZCZC-EAS-RWT-012057-012081-012101-012103-012115+0030-2780415-WTSP/TV-
|
|
|
|
|
|
|
|
Case 3: Slice 6 is a mismatch (EAs vs. EAS).
|
|
|
|
Slice 7 has RST rather than RWT.
|
|
|
|
2 & 4 don't match either (012141 vs. 012101).
|
|
|
|
We have another case where no two match so there is no clear winner.
|
|
|
|
|
|
|
|
|
|
|
|
reject 5 invalid character = ZCZC-EAS-RWT-012057-012081-012101-012103-012115+▒
|
|
|
|
frame_buf 7 = ZCZC-EAS-RST-012057-012081-012101-012103-012115+0030-2780415-WTSP/TV-
|
|
|
|
frame_buf 6 = ZCZC-EAs-RWT-012057-012081-012101-012103-012115+0030-2780415-WTSP/TV-
|
|
|
|
frame_buf 4 = ZCZC-EAS-RWT-112057-012081-012101-012103-012115+0030-2780415-WTSP/TV-
|
|
|
|
frame_buf 2 = ZCZC-EAS-RWT-012057-012081-012141-012103-012115+0030-2780415-WTSP/TV-
|
|
|
|
|
|
|
|
DECODED[3] 0:05.920 EAS audio level = 194(106/108) __|_|_||_
|
|
|
|
[0.2] EAS>APDW16:{DEZCZC-EAS-RWT-012057-012081-012141-012103-012115+0030-2780415-WTSP/TV-
|
|
|
|
|
|
|
|
Conclusions:
|
|
|
|
|
|
|
|
(1) The existing algorithm gives a higher preference to those frames matching others.
|
|
|
|
We didn't see any cases here where that would be to our advantage.
|
|
|
|
|
|
|
|
(2) A partial solution would be more validity checking. (i.e. non-digit where
|
|
|
|
digit is expected.) But wait... We might want to keep it for consideration:
|
|
|
|
|
|
|
|
(3) If I got REALLY ambitious, some day, we could compare all of them one column
|
|
|
|
at a time and take the most popular (and valid for that column) character and
|
|
|
|
use all of the most popular characters. Better yet, at the bit level.
|
|
|
|
|
|
|
|
Of course this is probably all overkill because we would normally expect to have pretty
|
|
|
|
decent signals. The designers didn't even bother to add any sort of checksum for error checking.
|
|
|
|
|
|
|
|
The random errors injected are also not realistic. Actual noise would probably wipe out the
|
|
|
|
same bit(s) for all of the slices.
|
|
|
|
|
|
|
|
The protocol specification suggests comparing all 3 transmissions and taking the best 2 out of 3.
|
|
|
|
I think that would best be left to an external application and we just concentrate on being
|
|
|
|
a good modem here and providing a result when it is received.
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
2015-07-27 00:35:07 +00:00
|
|
|
/***********************************************************************************
|
|
|
|
*
|
|
|
|
* Name: hdlc_rec_bit
|
|
|
|
*
|
|
|
|
* Purpose: Extract HDLC frames from a stream of bits.
|
|
|
|
*
|
|
|
|
* Inputs: chan - Channel number.
|
|
|
|
*
|
2015-11-29 15:44:30 +00:00
|
|
|
* subchan - This allows multiple demodulators per channel.
|
|
|
|
*
|
|
|
|
* slice - Allows multiple slicers per demodulator (subchannel).
|
2015-07-27 00:35:07 +00:00
|
|
|
*
|
|
|
|
* raw - One bit from the demodulator.
|
|
|
|
* should be 0 or 1.
|
|
|
|
*
|
|
|
|
* is_scrambled - Is the data scrambled?
|
|
|
|
*
|
2015-11-29 15:44:30 +00:00
|
|
|
* descram_state - Current descrambler state. (not used - remove)
|
2020-05-22 01:37:34 +00:00
|
|
|
* Not so fast - plans to add new parameter. PSK already provides it.
|
2015-07-27 00:35:07 +00:00
|
|
|
*
|
|
|
|
*
|
|
|
|
* Description: This is called once for each received bit.
|
|
|
|
* For each valid frame, process_rec_frame()
|
|
|
|
* is called for further processing.
|
|
|
|
*
|
|
|
|
***********************************************************************************/
|
|
|
|
|
2015-11-29 15:44:30 +00:00
|
|
|
void hdlc_rec_bit (int chan, int subchan, int slice, int raw, int is_scrambled, int not_used_remove)
|
2015-07-27 00:35:07 +00:00
|
|
|
{
|
|
|
|
|
|
|
|
int dbit; /* Data bit after undoing NRZI. */
|
|
|
|
/* Should be only 0 or 1. */
|
|
|
|
struct hdlc_state_s *H;
|
|
|
|
|
|
|
|
assert (was_init == 1);
|
|
|
|
|
|
|
|
assert (chan >= 0 && chan < MAX_CHANS);
|
|
|
|
assert (subchan >= 0 && subchan < MAX_SUBCHANS);
|
|
|
|
|
2015-11-29 15:44:30 +00:00
|
|
|
assert (slice >= 0 && slice < MAX_SLICERS);
|
|
|
|
|
2020-01-06 01:08:22 +00:00
|
|
|
// -e option can be used to artificially introduce the desired
|
|
|
|
// Bit Error Rate (BER) for testing.
|
|
|
|
|
|
|
|
if (g_audio_p->recv_ber != 0) {
|
|
|
|
double r = (double)my_rand() / (double)MY_RAND_MAX; // calculate as double to preserve all 31 bits.
|
|
|
|
if (g_audio_p->recv_ber > r) {
|
|
|
|
|
|
|
|
// FIXME
|
|
|
|
//text_color_set(DW_COLOR_DEBUG);
|
|
|
|
//dw_printf ("hdlc_rec_bit randomly clobber bit, ber = %.6f\n", g_audio_p->recv_ber);
|
|
|
|
|
|
|
|
raw = ! raw;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-06-14 01:33:10 +00:00
|
|
|
// EAS does not use HDLC.
|
|
|
|
|
|
|
|
if (g_audio_p->achan[chan].modem_type == MODEM_EAS) {
|
|
|
|
eas_rec_bit (chan, subchan, slice, raw, not_used_remove);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2015-07-27 00:35:07 +00:00
|
|
|
/*
|
2015-11-29 15:44:30 +00:00
|
|
|
* Different state information for each channel / subchannel / slice.
|
2015-07-27 00:35:07 +00:00
|
|
|
*/
|
2015-11-29 15:44:30 +00:00
|
|
|
H = &hdlc_state[chan][subchan][slice];
|
2015-07-27 00:35:07 +00:00
|
|
|
|
2020-06-14 01:33:10 +00:00
|
|
|
|
2015-07-27 00:35:07 +00:00
|
|
|
/*
|
|
|
|
* Using NRZI encoding,
|
|
|
|
* A '0' bit is represented by an inversion since previous bit.
|
|
|
|
* A '1' bit is represented by no change.
|
|
|
|
*/
|
|
|
|
|
2015-07-27 01:17:23 +00:00
|
|
|
if (is_scrambled) {
|
|
|
|
int descram;
|
|
|
|
|
|
|
|
descram = descramble(raw, &(H->lfsr));
|
|
|
|
|
|
|
|
dbit = (descram == H->prev_descram);
|
|
|
|
H->prev_descram = descram;
|
2019-05-13 10:25:12 +00:00
|
|
|
H->prev_raw = raw;
|
|
|
|
}
|
2015-07-27 01:17:23 +00:00
|
|
|
else {
|
|
|
|
|
|
|
|
dbit = (raw == H->prev_raw);
|
2019-05-13 10:25:12 +00:00
|
|
|
|
2015-07-27 01:17:23 +00:00
|
|
|
H->prev_raw = raw;
|
|
|
|
}
|
2015-07-27 00:35:07 +00:00
|
|
|
|
2020-01-06 01:08:22 +00:00
|
|
|
// After BER insertion, NRZI, and any descrambling, feed into FX.25 decoder as well.
|
2020-06-14 01:33:10 +00:00
|
|
|
// Don't waste time on this if AIS. EAS does not get this far.
|
2020-01-06 01:08:22 +00:00
|
|
|
|
2020-06-14 01:33:10 +00:00
|
|
|
if (g_audio_p->achan[chan].modem_type != MODEM_AIS) {
|
|
|
|
fx25_rec_bit (chan, subchan, slice, dbit);
|
2021-10-22 21:29:20 +00:00
|
|
|
il2p_rec_bit (chan, subchan, slice, raw); // Note: skip NRZI.
|
2020-06-14 01:33:10 +00:00
|
|
|
}
|
2019-05-13 10:25:12 +00:00
|
|
|
|
2015-07-27 00:35:07 +00:00
|
|
|
/*
|
|
|
|
* Octets are sent LSB first.
|
|
|
|
* Shift the most recent 8 bits thru the pattern detector.
|
|
|
|
*/
|
|
|
|
H->pat_det >>= 1;
|
|
|
|
if (dbit) {
|
|
|
|
H->pat_det |= 0x80;
|
|
|
|
}
|
|
|
|
|
|
|
|
H->flag4_det >>= 1;
|
|
|
|
if (dbit) {
|
|
|
|
H->flag4_det |= 0x80000000;
|
|
|
|
}
|
|
|
|
|
|
|
|
rrbb_append_bit (H->rrbb, raw);
|
2015-07-27 01:17:23 +00:00
|
|
|
|
2015-07-27 00:35:07 +00:00
|
|
|
if (H->pat_det == 0x7e) {
|
|
|
|
|
|
|
|
rrbb_chop8 (H->rrbb);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* The special pattern 01111110 indicates beginning and ending of a frame.
|
|
|
|
* If we have an adequate number of whole octets, it is a candidate for
|
|
|
|
* further processing.
|
|
|
|
*
|
|
|
|
* It might look odd that olen is being tested for 7 instead of 0.
|
|
|
|
* This is because oacc would already have 7 bits from the special
|
|
|
|
* "flag" pattern before it is detected here.
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
#if OLD_WAY
|
|
|
|
|
|
|
|
#if TEST
|
|
|
|
text_color_set(DW_COLOR_DEBUG);
|
|
|
|
dw_printf ("\nfound flag, olen = %d, frame_len = %d\n", olen, frame_len);
|
|
|
|
#endif
|
|
|
|
if (H->olen == 7 && H->frame_len >= MIN_FRAME_LEN) {
|
|
|
|
|
|
|
|
unsigned short actual_fcs, expected_fcs;
|
|
|
|
|
|
|
|
#if TEST
|
|
|
|
int j;
|
|
|
|
dw_printf ("TRADITIONAL: frame len = %d\n", H->frame_len);
|
|
|
|
for (j=0; j<H->frame_len; j++) {
|
|
|
|
dw_printf (" %02x", H->frame_buf[j]);
|
|
|
|
}
|
|
|
|
dw_printf ("\n");
|
|
|
|
|
|
|
|
#endif
|
|
|
|
/* Check FCS, low byte first, and process... */
|
|
|
|
|
|
|
|
/* Alternatively, it is possible to include the two FCS bytes */
|
|
|
|
/* in the CRC calculation and look for a magic constant. */
|
|
|
|
/* That would be easier in the case where the CRC is being */
|
|
|
|
/* accumulated along the way as the octets are received. */
|
|
|
|
/* I think making a second pass over it and comparing is */
|
|
|
|
/* easier to understand. */
|
|
|
|
|
|
|
|
actual_fcs = H->frame_buf[H->frame_len-2] | (H->frame_buf[H->frame_len-1] << 8);
|
|
|
|
|
|
|
|
expected_fcs = fcs_calc (H->frame_buf, H->frame_len - 2);
|
|
|
|
|
|
|
|
if (actual_fcs == expected_fcs) {
|
2015-07-27 01:17:23 +00:00
|
|
|
alevel_t alevel = demod_get_audio_level (chan, subchan);
|
2015-07-27 00:35:07 +00:00
|
|
|
|
2020-01-06 01:08:22 +00:00
|
|
|
multi_modem_process_rec_frame (chan, subchan, slice, H->frame_buf, H->frame_len - 2, alevel, RETRY_NONE, 0); /* len-2 to remove FCS. */
|
2015-07-27 00:35:07 +00:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
|
|
|
|
#if TEST
|
|
|
|
dw_printf ("*** actual fcs = %04x, expected fcs = %04x ***\n", actual_fcs, expected_fcs);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
#else
|
|
|
|
|
|
|
|
/*
|
|
|
|
* New way - Decode the raw bits in later step.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#if TEST
|
|
|
|
text_color_set(DW_COLOR_DEBUG);
|
2015-07-27 01:17:23 +00:00
|
|
|
dw_printf ("\nfound flag, channel %d.%d, %d bits in frame\n", chan, subchan, rrbb_get_len(H->rrbb) - 1);
|
2015-07-27 00:35:07 +00:00
|
|
|
#endif
|
|
|
|
if (rrbb_get_len(H->rrbb) >= MIN_FRAME_LEN * 8) {
|
|
|
|
|
2015-07-27 01:17:23 +00:00
|
|
|
alevel_t alevel = demod_get_audio_level (chan, subchan);
|
2015-07-27 00:35:07 +00:00
|
|
|
|
|
|
|
rrbb_set_audio_level (H->rrbb, alevel);
|
2015-07-27 01:17:23 +00:00
|
|
|
hdlc_rec2_block (H->rrbb);
|
2015-07-27 00:35:07 +00:00
|
|
|
/* Now owned by someone else who will free it. */
|
2015-11-29 15:44:30 +00:00
|
|
|
|
|
|
|
H->rrbb = rrbb_new (chan, subchan, slice, is_scrambled, H->lfsr, H->prev_descram); /* Allocate a new one. */
|
2015-07-27 00:35:07 +00:00
|
|
|
}
|
|
|
|
else {
|
2015-07-27 01:17:23 +00:00
|
|
|
rrbb_clear (H->rrbb, is_scrambled, H->lfsr, H->prev_descram);
|
2015-07-27 00:35:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
H->olen = 0; /* Allow accumulation of octets. */
|
|
|
|
H->frame_len = 0;
|
|
|
|
|
2015-07-27 01:17:23 +00:00
|
|
|
|
2015-07-27 00:35:07 +00:00
|
|
|
rrbb_append_bit (H->rrbb, H->prev_raw); /* Last bit of flag. Needed to get first data bit. */
|
2015-07-27 01:17:23 +00:00
|
|
|
/* Now that we are saving other initial state information, */
|
|
|
|
/* it would be sensible to do the same for this instead */
|
|
|
|
/* of lumping it in with the frame data bits. */
|
2015-07-27 00:35:07 +00:00
|
|
|
#endif
|
|
|
|
|
|
|
|
}
|
2015-07-27 01:17:23 +00:00
|
|
|
|
|
|
|
//#define EXPERIMENT12B 1
|
|
|
|
|
|
|
|
#if EXPERIMENT12B
|
|
|
|
|
|
|
|
else if (H->pat_det == 0xff) {
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Valid data will never have seven 1 bits in a row.
|
|
|
|
*
|
|
|
|
* 11111110
|
|
|
|
*
|
|
|
|
* This indicates loss of signal.
|
|
|
|
* But we will let it slip thru because it might diminish
|
|
|
|
* our single bit fixup effort. Instead give up on frame
|
|
|
|
* only when we see eight 1 bits in a row.
|
|
|
|
*
|
|
|
|
* 11111111
|
|
|
|
*
|
|
|
|
* What is the impact? No difference.
|
|
|
|
*
|
|
|
|
* Before: atest -P E -F 1 ../02_Track_2.wav = 1003
|
|
|
|
* After: atest -P E -F 1 ../02_Track_2.wav = 1003
|
|
|
|
*/
|
|
|
|
|
|
|
|
#else
|
2015-07-27 00:35:07 +00:00
|
|
|
else if (H->pat_det == 0xfe) {
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Valid data will never have 7 one bits in a row.
|
|
|
|
*
|
|
|
|
* 11111110
|
|
|
|
*
|
|
|
|
* This indicates loss of signal.
|
|
|
|
*/
|
|
|
|
|
2015-07-27 01:17:23 +00:00
|
|
|
#endif
|
|
|
|
|
2015-07-27 00:35:07 +00:00
|
|
|
H->olen = -1; /* Stop accumulating octets. */
|
|
|
|
H->frame_len = 0; /* Discard anything in progress. */
|
|
|
|
|
2015-07-27 01:17:23 +00:00
|
|
|
rrbb_clear (H->rrbb, is_scrambled, H->lfsr, H->prev_descram);
|
|
|
|
|
2015-07-27 00:35:07 +00:00
|
|
|
}
|
|
|
|
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.
|
|
|
|
*/
|
|
|
|
if (H->olen >= 0) {
|
|
|
|
|
|
|
|
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++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-05-22 01:37:34 +00:00
|
|
|
// TODO: Data Carrier Detect (DCD) is now based on DPLL lock
|
|
|
|
// rather than data patterns found here.
|
|
|
|
// It would make sense to move the next 2 functions to demod.c
|
|
|
|
// because this is done at the modem level, rather than HDLC decoder.
|
2015-07-27 01:17:23 +00:00
|
|
|
|
|
|
|
/*-------------------------------------------------------------------
|
|
|
|
*
|
|
|
|
* Name: dcd_change
|
|
|
|
*
|
2015-11-29 15:44:30 +00:00
|
|
|
* Purpose: Combine DCD states of all subchannels/ into an overall
|
2015-07-27 01:17:23 +00:00
|
|
|
* state for the channel.
|
|
|
|
*
|
|
|
|
* Inputs: chan
|
2015-09-07 23:56:20 +00:00
|
|
|
*
|
|
|
|
* subchan 0 to MAX_SUBCHANS-1 for HDLC.
|
2015-11-29 15:44:30 +00:00
|
|
|
* SPECIAL CASE --> MAX_SUBCHANS for DTMF decoder.
|
|
|
|
*
|
|
|
|
* slice slicer number, 0 .. MAX_SLICERS - 1.
|
2015-09-07 23:56:20 +00:00
|
|
|
*
|
2015-07-27 01:17:23 +00:00
|
|
|
* state 1 for active, 0 for not.
|
|
|
|
*
|
2015-11-29 15:44:30 +00:00
|
|
|
* Returns: None. Use hdlc_rec_data_detect_any to retrieve result.
|
2015-07-27 01:17:23 +00:00
|
|
|
*
|
2015-11-29 15:44:30 +00:00
|
|
|
* Description: DCD for the channel is active if ANY of the subchannels/slices
|
|
|
|
* are active. Update the DCD indicator.
|
2015-07-27 01:17:23 +00:00
|
|
|
*
|
2015-09-07 23:56:20 +00:00
|
|
|
* version 1.3: Add DTMF detection into the final result.
|
|
|
|
* This is now called from dtmf.c too.
|
2015-07-27 01:17:23 +00:00
|
|
|
*
|
|
|
|
*--------------------------------------------------------------------*/
|
|
|
|
|
2015-11-29 15:44:30 +00:00
|
|
|
void dcd_change (int chan, int subchan, int slice, int state)
|
2015-07-27 01:17:23 +00:00
|
|
|
{
|
|
|
|
int old, new;
|
|
|
|
|
|
|
|
assert (chan >= 0 && chan < MAX_CHANS);
|
2015-09-07 23:56:20 +00:00
|
|
|
assert (subchan >= 0 && subchan <= MAX_SUBCHANS);
|
2015-11-29 15:44:30 +00:00
|
|
|
assert (slice >= 0 && slice < MAX_SLICERS);
|
2015-07-27 01:17:23 +00:00
|
|
|
assert (state == 0 || state == 1);
|
|
|
|
|
|
|
|
#if DEBUG3
|
|
|
|
text_color_set(DW_COLOR_DEBUG);
|
2015-11-29 15:44:30 +00:00
|
|
|
dw_printf ("DCD %d.%d.%d = %d \n", chan, subchan, slice, state);
|
2015-07-27 01:17:23 +00:00
|
|
|
#endif
|
|
|
|
|
|
|
|
old = hdlc_rec_data_detect_any(chan);
|
|
|
|
|
|
|
|
if (state) {
|
2015-11-29 15:44:30 +00:00
|
|
|
composite_dcd[chan][subchan] |= (1 << slice);
|
2015-07-27 01:17:23 +00:00
|
|
|
}
|
|
|
|
else {
|
2015-11-29 15:44:30 +00:00
|
|
|
composite_dcd[chan][subchan] &= ~ (1 << slice);
|
2015-07-27 01:17:23 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
new = hdlc_rec_data_detect_any(chan);
|
|
|
|
|
|
|
|
if (new != old) {
|
|
|
|
ptt_set (OCTYPE_DCD, chan, new);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*-------------------------------------------------------------------
|
|
|
|
*
|
|
|
|
* Name: hdlc_rec_data_detect_any
|
2015-07-27 00:35:07 +00:00
|
|
|
*
|
2021-09-19 18:51:18 +00:00
|
|
|
* Purpose: Determine if the radio channel is currently busy
|
2015-07-27 00:35:07 +00:00
|
|
|
* with packet data.
|
|
|
|
* This version doesn't care about voice or other sounds.
|
|
|
|
* This is used by the transmit logic to transmit only
|
|
|
|
* when the channel is clear.
|
|
|
|
*
|
2015-07-27 01:17:23 +00:00
|
|
|
* Inputs: chan - Audio channel.
|
2015-07-27 00:35:07 +00:00
|
|
|
*
|
|
|
|
* Returns: True if channel is busy (data detected) or
|
|
|
|
* false if OK to transmit.
|
|
|
|
*
|
|
|
|
*
|
|
|
|
* Description: We have two different versions here.
|
|
|
|
*
|
|
|
|
* hdlc_rec_data_detect_any sees if ANY of the decoders
|
2021-09-19 18:51:18 +00:00
|
|
|
* for this channel are receiving a signal. This is
|
2015-07-27 00:35:07 +00:00
|
|
|
* used to determine whether the channel is clear and
|
|
|
|
* we can transmit. This would apply to the 300 baud
|
|
|
|
* HF SSB case where we have multiple decoders running
|
|
|
|
* at the same time. The channel is busy if ANY of them
|
|
|
|
* thinks the channel is busy.
|
|
|
|
*
|
2015-11-29 16:22:25 +00:00
|
|
|
* Version 1.3: New option for input signal to inhibit transmit.
|
|
|
|
*
|
2015-07-27 00:35:07 +00:00
|
|
|
*--------------------------------------------------------------------*/
|
|
|
|
|
|
|
|
int hdlc_rec_data_detect_any (int chan)
|
|
|
|
{
|
2015-11-17 18:19:12 +00:00
|
|
|
|
2015-11-29 15:44:30 +00:00
|
|
|
int sc;
|
2015-07-27 00:35:07 +00:00
|
|
|
assert (chan >= 0 && chan < MAX_CHANS);
|
|
|
|
|
2015-11-29 15:44:30 +00:00
|
|
|
for (sc = 0; sc < num_subchan[chan]; sc++) {
|
|
|
|
if (composite_dcd[chan][sc] != 0)
|
|
|
|
return (1);
|
|
|
|
}
|
2015-11-17 18:19:12 +00:00
|
|
|
|
2015-11-29 16:22:25 +00:00
|
|
|
if (get_input(ICTYPE_TXINH, chan) == 1) return (1);
|
2015-07-27 00:35:07 +00:00
|
|
|
|
2015-11-29 15:44:30 +00:00
|
|
|
return (0);
|
2015-07-27 00:35:07 +00:00
|
|
|
|
|
|
|
} /* end hdlc_rec_data_detect_any */
|
|
|
|
|
|
|
|
/* end hdlc_rec.c */
|
|
|
|
|
|
|
|
|