2400 bps PSK compatibility with MFJ-2400.

This commit is contained in:
wb2osz 2019-05-19 20:57:56 -04:00
parent ad12fa86d6
commit b37fda96fb
18 changed files with 426 additions and 131 deletions

View File

@ -15,6 +15,8 @@
- "-g" option to force G3RUH mode for lower speeds where a different modem type may be the default.
- 2400 bps compatibility with MFJ-2400. See ***2400-4800-PSK-for-APRS-Packet-Radio.pdf*** for details
- "atest -h" will display the frame in hexadecimal for closer inspection.
- Add support for Multi-GNSS NMEA sentences.

View File

@ -735,7 +735,7 @@ install-rpi :
# Combine some unit tests into a single regression sanity check.
check : dtest ttest tttexttest pftest tlmtest lltest enctest kisstest pad2test xidtest dtmftest check-modem1200 check-modem300 check-modem9600 check-modem19200 check-modem2400 check-modem2400-g check-modem4800
check : dtest ttest tttexttest pftest tlmtest lltest enctest kisstest pad2test xidtest dtmftest check-modem1200 check-modem300 check-modem9600 check-modem19200 check-modem2400-a check-modem2400-b check-modem2400-g check-modem4800
# Can we encode and decode at popular data rates?
@ -763,11 +763,17 @@ check-modem19200 : gen_packets atest
./atest -B19200 -F1 -L64 -G68 /tmp/test19.wav
rm /tmp/test19.wav
check-modem2400 : gen_packets atest
./gen_packets -B2400 -n 100 -o /tmp/test24.wav
./atest -B2400 -F0 -L70 -G78 /tmp/test24.wav
./atest -B2400 -F1 -L80 -G87 /tmp/test24.wav
rm /tmp/test24.wav
check-modem2400-a : gen_packets atest
./gen_packets -B2400 -j -n 100 -o /tmp/test24-a.wav
./atest -B2400 -j -F0 -L76 -G80 test24-a.wav
./atest -B2400 -j -F1 -L84 -G88 test24-a.wav
rm /tmp/test24-a.wav
check-modem2400-b : gen_packets atest
./gen_packets -B2400 -J -n 100 -o /tmp/test24-b.wav
./atest -B2400 -J -F0 -L79 -G83 test24-b.wav
./atest -B2400 -J -F1 -L87 -G91 test24-b.wav
rm /tmp/test24-b.wav
check-modem2400-g : gen_packets atest
./gen_packets -B2400 -g -n 100 -o /tmp/test24-g.wav

View File

@ -277,7 +277,7 @@ strlcat.o : misc/strlcat.c
# Combine some unit tests into a single regression sanity check.
check : dtest ttest tttexttest pftest tlmtest lltest enctest kisstest pad2test xidtest dtmftest check-modem1200 check-modem300 check-modem9600 check-modem19200 check-modem2400 check-modem2400-g check-modem4800
check : dtest ttest tttexttest pftest tlmtest lltest enctest kisstest pad2test xidtest dtmftest check-modem1200 check-modem300 check-modem9600 check-modem19200 check-modem2400-a check-modem2400-b check-modem2400-g check-modem4800
# Can we encode and decode at popular data rates?
# Verify that single bit fixup increases the count.
@ -324,13 +324,21 @@ check-modem19200 : gen_packets atest
sleep 1
rm test19.wav
check-modem2400 : gen_packets atest
gen_packets -B2400 -n 100 -o test24.wav
check-modem2400-a : gen_packets atest
gen_packets -B2400 -j -n 100 -o test24-a.wav
sleep 1
atest -B2400 -F0 -L70 -G78 test24.wav
atest -B2400 -F1 -L80 -G87 test24.wav
atest -B2400 -j -F0 -L76 -G80 test24-a.wav
atest -B2400 -j -F1 -L84 -G88 test24-a.wav
sleep 1
rm test24.wav
rm test24-a.wav
check-modem2400-b : gen_packets atest
gen_packets -B2400 -J -n 100 -o test24-b.wav
sleep 1
atest -B2400 -J -F0 -L79 -G83 test24-b.wav
atest -B2400 -J -F1 -L87 -G91 test24-b.wav
sleep 1
rm test24-b.wav
check-modem2400-g : gen_packets atest
gen_packets -B2400 -g -n 100 -o test24-g.wav
@ -518,8 +526,8 @@ testagc96 : atest.c fsk_fast_filter.h tune.h demod.c demod_afsk.c demod_psk.c de
misc.a regex.a
rm -f atest96.exe
$(CC) $(CFLAGS) -o atest96 $^
./atest96 -B 9600 ../walkabout9600c.wav | grep "packets decoded in" >atest.out
#./atest96 -B 9600 ../walkabout9600c.wav noisy96.wav zzz16.wav zzz16.wav zzz16.wav zzz8.wav zzz8.wav zzz8.wav | grep "packets decoded in" >atest.out
./atest96 -B 9600 ../walkabout9600c.wav noisy96.wav zzz16.wav zzz16.wav zzz16.wav zzz8.wav zzz8.wav zzz8.wav | grep "packets decoded in" >atest.out
#./atest96 -B 9600 ../walkabout9600c.wav | grep "packets decoded in" >atest.out
#./atest96 -B 9600 zzz16.wav zzz8.wav | grep "packets decoded in" >atest.out
#./atest96 -B 9600 noisy96.wav | grep "packets decoded in" >atest.out
#./atest96 -B 9600 19990303_0225_9600_8bis_22kHz.wav | grep "packets decoded in" >atest.out
@ -536,10 +544,22 @@ testagc24 : atest.c fsk_fast_filter.h tune.h demod.c demod_afsk.c demod_psk.c de
misc.a regex.a
rm -f atest24.exe
sleep 1
$(CC) $(CFLAGS) -o atest24 $^
$(CC) $(CFLAGS) -o atest24mfj $^
./atest24 -B 2400 test2400.wav | grep "packets decoded in" >atest.out
echo " " > tune.h
testagc24mfj : atest.c fsk_fast_filter.h tune.h demod.c demod_afsk.c demod_psk.c demod_9600.c \
dsp.o hdlc_rec.o hdlc_rec2.o multi_modem.o \
rrbb.o fcs_calc.o ax25_pad.o decode_aprs.o \
dwgpsnmea.o dwgps.o serial_port.o latlong.o \
symbols.o tt_text.o textcolor.o telemetry.o dtime_now.o \
misc.a regex.a
rm -f atest24mfj.exe
sleep 1
$(CC) $(CFLAGS) -o atest24mfj $^
./atest24mfj -F 1 -B 2400 ../ref-doc/MFJ-2400-PSK/2k4_short.wav
echo " " > tune.h
testagc48 : atest.c fsk_fast_filter.h tune.h demod.c demod_afsk.c demod_psk.c demod_9600.c \
dsp.o hdlc_rec.o hdlc_rec2.o multi_modem.o \
rrbb.o fcs_calc.o ax25_pad.o decode_aprs.o \

128
atest.c
View File

@ -2,7 +2,7 @@
//
// This file is part of Dire Wolf, an amateur radio packet TNC.
//
// Copyright (C) 2011, 2012, 2013, 2014, 2015, 2016 John Langner, WB2OSZ
// Copyright (C) 2011, 2012, 2013, 2014, 2015, 2016, 2019 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
@ -182,7 +182,10 @@ static int sample_number = -1; /* Sample number from the file. */
static int B_opt = DEFAULT_BAUD; // Bits per second. Need to change all baud references to bps.
static int g_opt = 0; // G3RUH modem regardless of speed.
static int j_opt = 0; /* 2400 bps PSK compatible with direwolf <= 1.5 */
static int J_opt = 0; /* 2400 bps PSK compatible MFJ-2400 and maybe others. */
static int h_opt = 0; // Hexadecimal display of received packet.
static char P_opt[16] = ""; // Demodulator profiles.
int main (int argc, char *argv[])
@ -219,49 +222,6 @@ int main (int argc, char *argv[])
my_audio_config.adev[0].samples_per_sec = DEFAULT_SAMPLES_PER_SEC;
my_audio_config.adev[0].bits_per_sample = DEFAULT_BITS_PER_SAMPLE;
// Results v0.9:
//
// fix_bits = 0 971 packets, 69 sec
// fix_bits = SINGLE 990 64
// fix_bits = DOUBLE 992 65
// fix_bits = TRIPLE 992 67
// fix_bits = TWO_SEP 1004 476
// Essentially no difference in time for those with order N time.
// Time increases greatly for the one with order N^2 time.
// Results: version 1.1, decoder C, my_audio_config.fix_bits = RETRY_MAX - 1
//
// 971 NONE
// +19 SINGLE
// +2 DOUBLE
// +12 TWO_SEP
// +3 REMOVE_MANY
// ----
// 1007 Total in 1008 sec. More than twice as long as earlier version.
// Results: version 1.1, decoders ABC, my_audio_config.fix_bits = RETRY_MAX - 1
//
// 976 NONE
// +21 SINGLE
// +1 DOUBLE
// +22 TWO_SEP
// +1 MANY
// +3 REMOVE_MANY
// ----
// 1024 Total in 2042 sec.
// About 34 minutes of CPU time for a roughly 40 minute CD.
// Many computers wouldn't be able to keep up.
// The SINGLE and TWO_SEP techniques are the most effective.
// Should we reorder the enum values so that TWO_SEP
// comes after SINGLE? That way "FIX_BITS 2" would
// use the two most productive techniques and not waste
// time on the others. People with plenty of CPU power
// to spare can still specify larger numbers for the other
// techniques with less return on investment.
for (channel=0; channel<MAX_CHANS; channel++) {
@ -299,7 +259,7 @@ int main (int argc, char *argv[])
/* ':' following option character means arg is required. */
c = getopt_long(argc, argv, "B:P:D:U:gF:L:G:012h",
c = getopt_long(argc, argv, "B:P:D:U:gjJF:L:G:012h",
long_options, &option_index);
if (c == -1)
break;
@ -316,10 +276,20 @@ int main (int argc, char *argv[])
g_opt = 1;
break;
case 'j': /* -j V.26 compatible with earlier direwolf. */
j_opt = 1;
break;
case 'J': /* -J V.26 compatible with MFJ-2400. */
J_opt = 1;
break;
case 'P': /* -P for modem profile. */
dw_printf ("Demodulator profile set to \"%s\"\n", optarg);
strlcpy (my_audio_config.achan[0].profiles, optarg, sizeof(my_audio_config.achan[0].profiles));
// Wait until after other options processed.
strlcpy (P_opt, optarg, sizeof(P_opt));
break;
case 'D': /* -D reduce sampling rate for lower CPU usage. */
@ -353,7 +323,7 @@ int main (int argc, char *argv[])
my_audio_config.achan[0].upsample = upsample;
break;
case 'F': /* -D set "fix bits" level. */
case 'F': /* -F set "fix bits" level. */
my_audio_config.achan[0].fix_bits = atoi(optarg);
@ -411,7 +381,7 @@ int main (int argc, char *argv[])
/*
* Set modem type based on data rate.
* (Could be overridden by -g later.)
* (Could be overridden by -g, -j, or -J later.)
*/
/* 300 implies 1600/1800 AFSK. */
/* 1200 implies 1200/2200 AFSK. */
@ -478,6 +448,40 @@ int main (int argc, char *argv[])
strlcpy (my_audio_config.achan[0].profiles, " ", sizeof(my_audio_config.achan[0].profiles)); // avoid getting default later.
}
/*
* We have two different incompatible flavors of V.26.
*/
if (j_opt) {
// V.26 compatible with earlier versions of direwolf.
// Example: -B 2400 -j or simply -j
my_audio_config.achan[0].v26_alternative = V26_A;
my_audio_config.achan[0].modem_type = MODEM_QPSK;
my_audio_config.achan[0].mark_freq = 0;
my_audio_config.achan[0].space_freq = 0;
my_audio_config.achan[0].baud = 2400;
strlcpy (my_audio_config.achan[0].profiles, "", sizeof(my_audio_config.achan[0].profiles));
}
if (J_opt) {
// V.26 compatible with MFJ and maybe others.
// Example: -B 2400 -J or simply -J
my_audio_config.achan[0].v26_alternative = V26_B;
my_audio_config.achan[0].modem_type = MODEM_QPSK;
my_audio_config.achan[0].mark_freq = 0;
my_audio_config.achan[0].space_freq = 0;
my_audio_config.achan[0].baud = 2400;
strlcpy (my_audio_config.achan[0].profiles, "", sizeof(my_audio_config.achan[0].profiles));
}
// Needs to be after -B, -j, -J.
if (strlen(P_opt) > 0) {
dw_printf ("Demodulator profile set to \"%s\"\n", P_opt);
strlcpy (my_audio_config.achan[0].profiles, P_opt, sizeof(my_audio_config.achan[0].profiles));
}
memcpy (&my_audio_config.achan[1], &my_audio_config.achan[0], sizeof(my_audio_config.achan[0]));
@ -879,11 +883,15 @@ static void usage (void) {
dw_printf (" atest [ options ] wav-file-in\n");
dw_printf ("\n");
dw_printf (" -B n Bits/second for data. Proper modem automatically selected for speed.\n");
dw_printf (" 300 baud uses 1600/1800 Hz AFSK.\n");
dw_printf (" 1200 (default) baud uses 1200/2200 Hz AFSK.\n");
dw_printf (" 9600 baud uses K9NG/G2RUH standard.\n");
dw_printf (" 300 bps defaults to AFSK tones of 1600 & 1800.\n");
dw_printf (" 1200 bps uses AFSK tones of 1200 & 2200.\n");
dw_printf (" 2400 bps uses QPSK based on V.26 standard.\n");
dw_printf (" 4800 bps uses 8PSK based on V.27 standard.\n");
dw_printf (" 9600 bps and up uses K9NG/G3RUH standard.\n");
dw_printf ("\n");
dw_printf (" -g Force G3RUH modem rather rather than default for data rate.\n");
dw_printf (" -g Use G3RUH modem rather rather than default for data rate.\n");
dw_printf (" -j 2400 bps QPSK compatible with direwolf <= 1.5.\n");
dw_printf (" -J 2400 bps QPSK compatible with MFJ-2400.\n");
dw_printf ("\n");
dw_printf (" -D n Divide audio sample rate by n.\n");
dw_printf ("\n");
@ -894,8 +902,12 @@ static void usage (void) {
dw_printf (" 1 = Try to fix only a single bit. \n");
dw_printf (" more = Try modifying more bits to get a good CRC.\n");
dw_printf ("\n");
dw_printf (" -P m Select the demodulator type such as A, B, C, D (default for 300 baud),\n");
dw_printf (" E (default for 1200 baud), F, A+, B+, C+, D+, E+, F+.\n");
dw_printf (" -L Error if less than this number decoded.\n");
dw_printf ("\n");
dw_printf (" -G Error if greater than this number decoded.\n");
dw_printf ("\n");
dw_printf (" -P m Select the demodulator type such as D (default for 300 bps),\n");
dw_printf (" E+ (default for 1200 bps), PQRS for 2400 bps, etc.\n");
dw_printf ("\n");
dw_printf (" -0 Use channel 0 (left) of stereo audio (default).\n");
dw_printf (" -1 use channel 1 (right) of stereo audio.\n");
@ -918,11 +930,11 @@ static void usage (void) {
dw_printf (" bits per second.\n");
dw_printf ("\n");
dw_printf (" atest 02_Track_2.wav\n");
dw_printf (" atest -P C+ 02_Track_2.wav\n");
dw_printf (" atest -P E- 02_Track_2.wav\n");
dw_printf (" atest -F 1 02_Track_2.wav\n");
dw_printf (" atest -P C+ -F 1 02_Track_2.wav\n");
dw_printf (" atest -P E- -F 1 02_Track_2.wav\n");
dw_printf ("\n");
dw_printf (" Try different combinations of options to find the best decoding\n");
dw_printf (" Try different combinations of options to compare decoding\n");
dw_printf (" performance.\n");
exit (1);

16
audio.h
View File

@ -18,7 +18,7 @@
#include "direwolf.h" /* for MAX_CHANS used throughout the application. */
#include "ax25_pad.h" /* for AX25_MAX_ADDR_LEN */
#include "version.h"
/*
@ -141,6 +141,20 @@ struct audio_s {
/* Might try MFJ-2400 / CCITT v.26 / Bell 201 someday. */
/* No modem. Might want this for DTMF only channel. */
enum v26_e { V26_UNSPECIFIED=0, V26_A, V26_B } v26_alternative;
// Original implementaion used alternative A for 2400 bbps PSK.
// Years later, we discover that MFJ-2400 used alternative B.
// It's likely the others did too.
// For release 1.6, default to original style but print warning.
// Later default to MFJ compatible and still print warning if
// if user did not pick one explicitly.
#if (MAJOR_VERSION > 1) || (MINOR_VERSION > 6)
#define V26_DEFAULT V26_B
#else
#define V26_DEFAULT V26_A
#endif
enum dtmf_decode_t { DTMF_DECODE_OFF, DTMF_DECODE_ON } dtmf_decode;

View File

@ -761,6 +761,7 @@ void config_init (char *fname, struct audio_s *p_audio_config,
/* set to radio when corresponding */
/* audio device is defined. */
p_audio_config->achan[channel].modem_type = MODEM_AFSK;
p_audio_config->achan[channel].v26_alternative = V26_UNSPECIFIED;
p_audio_config->achan[channel].mark_freq = DEFAULT_MARK_FREQ; /* -m option */
p_audio_config->achan[channel].space_freq = DEFAULT_SPACE_FREQ; /* -s option */
p_audio_config->achan[channel].baud = DEFAULT_BAUD; /* -b option */
@ -1264,6 +1265,7 @@ void config_init (char *fname, struct audio_s *p_audio_config,
* *9 - Upsample ratio for G3RUH.
* [A-Z+-]+ - Letters, plus, minus for the demodulator "profile."
* g3ruh - This modem type regardless of default for speed.
* v26a or v26b - V.26 alternative. a=original, b=MFJ compatible
*/
else if (strcasecmp(t, "MODEM") == 0) {
@ -1540,6 +1542,19 @@ void config_init (char *fname, struct audio_s *p_audio_config,
p_audio_config->achan[channel].space_freq = 0;
}
else if (strcasecmp(t, "V26A") == 0 || /* Compatible with direwolf versions <= 1.5. New in 1.6. */
strcasecmp(t, "V26B") == 0) { /* Compatible with MFJ-2400. New in 1.6. */
if (p_audio_config->achan[channel].modem_type != MODEM_QPSK ||
p_audio_config->achan[channel].baud != 2400) {
text_color_set(DW_COLOR_ERROR);
dw_printf ("Line %d: %s option can only be used with 2400 bps PSK.\n", line, t);
continue;
}
p_audio_config->achan[channel].v26_alternative = (strcasecmp(t, "V26A") == 0) ? V26_A : V26_B;
}
else {
text_color_set(DW_COLOR_ERROR);
dw_printf ("Line %d: Unrecognized option for MODEM: %s\n", line, t);

36
demod.c
View File

@ -1,7 +1,7 @@
//
// This file is part of Dire Wolf, an amateur radio packet TNC.
//
// Copyright (C) 2011, 2012, 2013, 2014, 2015, 2016 John Langner, WB2OSZ
// Copyright (C) 2011, 2012, 2013, 2014, 2015, 2016, 2019 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
@ -94,7 +94,6 @@ static int sample_count[MAX_CHANS][MAX_SUBCHANS];
int demod_init (struct audio_s *pa)
{
//int j;
int chan; /* Loop index over number of radio channels. */
char profile;
@ -520,6 +519,31 @@ int demod_init (struct audio_s *pa)
case MODEM_QPSK: // New for 1.4
// In versions 1.4 and 1.5, V.26 "Alternative A" was used.
// years later, I discover that the MFJ-2400 used "Alternative B."
// It looks like the other two manufacturers use the same but we
// can't be sure until we find one for compatbility testing.
// In version 1.6 we add a choice for the user.
// If neither one was explicitly specified, print a message and take
// a default. My current thinking is that we default to direwolf <= 1.5
// compatible for version 1.6 and MFJ compatible after that.
if (save_audio_config_p->achan[chan].v26_alternative == V26_UNSPECIFIED) {
text_color_set(DW_COLOR_ERROR);
dw_printf ("Two incompatible versions of 2400 bps QPSK are now available.\n");
dw_printf ("For compatbility with direwolf <= 1.5, use 'V26A' modem option in config file.\n");
dw_printf ("For compatbility MFJ-2400 use 'V26B' modem option in config file.\n");
dw_printf ("Command line options -j and -J can be used for channel 0.\n");
dw_printf ("For more information, read the Dire Wolf User Guide and\n");
dw_printf ("2400-4800-PSK-for-APRS-Packet-Radio.pdf.\n");
dw_printf ("The default in this release could be different in a later release.\n");
save_audio_config_p->achan[chan].v26_alternative = V26_DEFAULT;
}
// TODO: See how much CPU this takes on ARM and decide if we should have different defaults.
if (strlen(save_audio_config_p->achan[chan].profiles) == 0) {
@ -539,6 +563,12 @@ int demod_init (struct audio_s *pa)
save_audio_config_p->adev[ACHAN2ADEV(chan)].samples_per_sec);
if (save_audio_config_p->achan[chan].decimate != 1)
dw_printf (" / %d", save_audio_config_p->achan[chan].decimate);
if (save_audio_config_p->achan[chan].v26_alternative == V26_B)
dw_printf (", compatible with MFJ-2400");
else
dw_printf (", compatible with earlier direwolf");
if (save_audio_config_p->achan[chan].dtmf_decode != DTMF_DECODE_OFF)
dw_printf (", DTMF decoder enabled");
dw_printf (".\n");
@ -556,6 +586,7 @@ int demod_init (struct audio_s *pa)
// save_audio_config_p->achan[chan].modem_type, profile);
demod_psk_init (save_audio_config_p->achan[chan].modem_type,
save_audio_config_p->achan[chan].v26_alternative,
save_audio_config_p->adev[ACHAN2ADEV(chan)].samples_per_sec / save_audio_config_p->achan[chan].decimate,
save_audio_config_p->achan[chan].baud,
profile,
@ -610,6 +641,7 @@ int demod_init (struct audio_s *pa)
// save_audio_config_p->achan[chan].modem_type, profile);
demod_psk_init (save_audio_config_p->achan[chan].modem_type,
save_audio_config_p->achan[chan].v26_alternative,
save_audio_config_p->adev[ACHAN2ADEV(chan)].samples_per_sec / save_audio_config_p->achan[chan].decimate,
save_audio_config_p->achan[chan].baud,
profile,

View File

@ -1,7 +1,7 @@
//
// This file is part of Dire Wolf, an amateur radio packet TNC.
//
// Copyright (C) 2016 John Langner, WB2OSZ
// Copyright (C) 2016, 2019 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
@ -24,6 +24,7 @@
//#define DEBUG4 1 /* capture PSK demodulator output to log files */
//#define DEBUG5 1 /* Print bit stream */
/*------------------------------------------------------------------
@ -63,8 +64,7 @@
* http://www.brazoriacountyares.org/winlink-collection/TNC%20manuals/Kantronics/2400_modem_operators_guide@rgf.pdf
*
*
* The MFJ and AEA both use the EXAR XR-2123 PSK modem chip.
* The Kantronics has a P423 ???
* From what I'm able to gather, they all used the EXAR XR-2123 PSK modem chip.
*
* Can't find the chip specs on the EXAR website so Google it.
*
@ -79,8 +79,8 @@
* "bis" and "ter" are from Latin for second and third.
* I used the "ter" version which has phase shifts of 0, 90, 180, and 270 degrees.
*
* There are other references to an alternative B which uses other multiples of 45.
* The XR-2123 data sheet mentions only multiples of 90. That's what I went with.
* There are ealier references to an alternative B which uses other phase shifts offset
* by another 45 degrees.
*
* The XR-2123 does not perform the scrambling as specified in V.26 so I wonder if
* the vendors implemented it in software or just left it out.
@ -161,6 +161,8 @@ static inline float my_atan2f (float y, float x)
*
* Inputs: modem_type - MODEM_QPSK or MODEM_8PSK.
*
* v26_alt - V26_A (classic) or V25_B (MFJ compatible)
*
* samples_per_sec - Audio sample rate.
*
* bps - Bits per second.
@ -189,7 +191,7 @@ static inline float my_atan2f (float y, float x)
*
*----------------------------------------------------------------*/
void demod_psk_init (enum modem_t modem_type, int samples_per_sec, int bps, char profile, struct demodulator_state_s *D)
void demod_psk_init (enum modem_t modem_type, enum v26_e v26_alt, int samples_per_sec, int bps, char profile, struct demodulator_state_s *D)
{
int correct_baud; // baud is not same as bits/sec here!
int carrier_freq;
@ -199,6 +201,8 @@ void demod_psk_init (enum modem_t modem_type, int samples_per_sec, int bps, char
memset (D, 0, sizeof(struct demodulator_state_s));
D->modem_type = modem_type;
D->v26_alt = v26_alt;
D->num_slicers = 1; // Haven't thought about this yet. Is it even applicable?
@ -210,6 +214,8 @@ void demod_psk_init (enum modem_t modem_type, int samples_per_sec, int bps, char
if (modem_type == MODEM_QPSK) {
assert (D->v26_alt != V26_UNSPECIFIED);
correct_baud = bps / 2;
// Originally I thought of scaling it to the data rate,
// e.g. 2400 bps -> 1800 Hz, but decided to make it a
@ -645,7 +651,16 @@ void demod_psk_process_sample (int chan, int subchan, int sam, struct demodulato
id = ((int)((delta / (2.f * (float)M_PI) + 1.f) * 256.f)) & 0xff;
if (D->modem_type == MODEM_QPSK) {
demod_phase_shift = ((id + 32) >> 6) & 0x3;
#ifdef TUNE_PSKOFFSET
demod_phase_shift = ((id + TUNE_PSKOFFSET) >> 6) & 0x3;
#else
if (D->v26_alt == V26_B) {
demod_phase_shift = ((id + 2) >> 6) & 0x3; // MFJ compatible
}
else {
demod_phase_shift = ((id + 32) >> 6) & 0x3; // Classic
}
#endif
}
else {
demod_phase_shift = ((id + 16) >> 5) & 0x7;
@ -671,25 +686,20 @@ void demod_psk_process_sample (int chan, int subchan, int sam, struct demodulato
if (D->modem_type == MODEM_QPSK) {
#if 1 // Speed up special case.
if (I > 0) {
if (Q > 0)
demod_phase_shift = 0; /* 0 to 90 degrees, etc. */
else
demod_phase_shift = 1;
}
else {
if (Q > 0)
demod_phase_shift = 3;
else
demod_phase_shift = 2;
}
#else
a = my_atan2f(I,Q);
float a = my_atan2f(I,Q);
int id = ((int)((a / (2.f * (float)M_PI) + 1.f) * 256.f)) & 0xff;
// 128 compensates for 180 degree phase shift due
// to 1 1/2 carrier cycles per symbol period.
demod_phase_shift = ((id + 128) >> 6) & 0x3;
#ifdef TUNE_PSKOFFSET
demod_phase_shift = ((id + TUNE_PSKOFFSET) >> 6) & 0x3;
#else
if (D->v26_alt == V26_B) {
demod_phase_shift = ((id + 98) >> 6) & 0x3; // MFJ compatible
}
else {
demod_phase_shift = ((id + 128) >> 6) & 0x3; // Classic
}
#endif
}
else {
@ -752,7 +762,13 @@ void demod_psk_process_sample (int chan, int subchan, int sam, struct demodulato
} /* end demod_psk_process_sample */
#ifdef TUNE_GRAY
TUNE_GRAY
#else
static const int phase_to_gray_v26[4] = {0, 1, 3, 2};
#endif
static const int phase_to_gray_v27[8] = {1, 0, 2, 3, 7, 6, 4, 5};
@ -813,6 +829,9 @@ inline static void nudge_pll (int chan, int subchan, int slice, int demod_bits,
a * 360 / (2*M_PI), delta * 360 / (2*M_PI), demod_bits, (gray >> 1) & 1, gray & 1);
//dw_printf ("phaseshift=%d, bits= %d %d \n", demod_bits, (gray >> 1) & 1, gray & 1);
#endif
#if DEBUG5
dw_printf ("%d\n%d\n", (gray >> 1) & 1, gray & 1);
#endif
hdlc_rec_bit (chan, subchan, slice, (gray >> 1) & 1, 0, -1);
hdlc_rec_bit (chan, subchan, slice, gray & 1, 0, -1);

View File

@ -2,6 +2,6 @@
/* demod_psk.h */
void demod_psk_init (enum modem_t modem_type, int samples_per_sec, int bps, char profile, struct demodulator_state_s *D);
void demod_psk_init (enum modem_t modem_type, enum v26_e v26_alt, int samples_per_sec, int bps, char profile, struct demodulator_state_s *D);
void demod_psk_process_sample (int chan, int subchan, int sam, struct demodulator_state_s *D);

View File

@ -1,7 +1,7 @@
//
// This file is part of Dire Wolf, an amateur radio packet TNC.
//
// Copyright (C) 2011, 2012, 2013, 2014, 2015, 2016, 2017 John Langner, WB2OSZ
// Copyright (C) 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2019 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
@ -201,6 +201,8 @@ int main (int argc, char *argv[])
int t_opt = 1; /* Text color option. */
int a_opt = 0; /* "-a n" interval, in seconds, for audio statistics report. 0 for none. */
int g_opt = 0; /* G3RUH mode, ignoring default for speed. */
int j_opt = 0; /* 2400 bps PSK compatible with direwolf <= 1.5 */
int J_opt = 0; /* 2400 bps PSK compatible MFJ-2400 and maybe others. */
int d_k_opt = 0; /* "-d k" option for serial port KISS. Can be repeated for more detail. */
int d_n_opt = 0; /* "-d n" option for Network KISS. Can be repeated for more detail. */
@ -354,7 +356,7 @@ int main (int argc, char *argv[])
/* ':' following option character means arg is required. */
c = getopt_long(argc, argv, "P:B:gD:U:c:pxr:b:n:d:q:t:ul:L:Sa:E:T:",
c = getopt_long(argc, argv, "P:B:gjJD:U:c:pxr:b:n:d:q:t:ul:L:Sa:E:T:",
long_options, &option_index);
if (c == -1)
break;
@ -411,6 +413,16 @@ int main (int argc, char *argv[])
g_opt = 1;
break;
case 'j': /* -j V.26 compatible with earlier direwolf. */
j_opt = 1;
break;
case 'J': /* -J V.26 compatible with MFJ-2400. */
J_opt = 1;
break;
case 'P': /* -P for modem profile. */
//debug: dw_printf ("Demodulator profile set to \"%s\"\n", optarg);
@ -691,11 +703,34 @@ int main (int argc, char *argv[])
audio_config.achan[0].space_freq = 0;
}
if (j_opt) {
// V.26 compatible with earlier versions of direwolf.
// Example: -B 2400 -j or simply -j
audio_config.achan[0].v26_alternative = V26_A;
audio_config.achan[0].modem_type = MODEM_QPSK;
audio_config.achan[0].mark_freq = 0;
audio_config.achan[0].space_freq = 0;
audio_config.achan[0].baud = 2400;
}
if (J_opt) {
// V.26 compatible with MFJ and maybe others.
// Example: -B 2400 -J or simply -J
audio_config.achan[0].v26_alternative = V26_B;
audio_config.achan[0].modem_type = MODEM_QPSK;
audio_config.achan[0].mark_freq = 0;
audio_config.achan[0].space_freq = 0;
audio_config.achan[0].baud = 2400;
}
audio_config.statistics_interval = a_opt;
if (strlen(P_opt) > 0) {
/* -P for modem profile. */
/* TODO: Not yet documented. Should probably since it is consistent with atest. */
strlcpy (audio_config.achan[0].profiles, P_opt, sizeof(audio_config.achan[0].profiles));
}
@ -1293,6 +1328,9 @@ static void usage (char **argv)
dw_printf (" 4800 bps uses 8PSK based on V.27 standard.\n");
dw_printf (" 9600 bps and up uses K9NG/G3RUH standard.\n");
dw_printf (" -g Force G3RUH modem regardless of speed.\n");
dw_printf (" -j 2400 bps QPSK compatible with direwolf <= 1.5.\n");
dw_printf (" -J 2400 bps QPSK compatible with MFJ-2400.\n");
dw_printf (" -P xxx Modem Profiles.\n");
dw_printf (" -D n Divide audio sample rate by n for channel 0.\n");
dw_printf (" -d Debug options:\n");
dw_printf (" a a = AGWPE network protocol client.\n");

Binary file not shown.

View File

@ -28,6 +28,8 @@ struct demodulator_state_s
*/
enum modem_t modem_type; // MODEM_AFSK, MODEM_8PSK, etc.
enum v26_e v26_alt; // Which alternative when V.26.
char profile; // 'A', 'B', etc. Upper case.
// Only needed to see if we are using 'F' to take fast path.
@ -145,6 +147,7 @@ struct demodulator_state_s
float pre_filter[MAX_FILTER_SIZE] __attribute__((aligned(16)));
/*
* Kernel for the mark and space detection filters.
*/
@ -227,6 +230,7 @@ struct demodulator_state_s
float m_valley, s_valley;
float m_amp_prev, s_amp_prev;
/*
* For the PLL and data bit timing.
* starting in version 1.2 we can have multiple slicers for one demodulator.

View File

@ -1,7 +1,7 @@
//
// This file is part of Dire Wolf, an amateur radio packet TNC.
//
// Copyright (C) 2011, 2013, 2014, 2015, 2016 John Langner, WB2OSZ
// Copyright (C) 2011, 2013, 2014, 2015, 2016, 2019 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
@ -164,6 +164,9 @@ int main(int argc, char **argv)
int chan;
int experiment = 0;
int g_opt = 0;
int j_opt = 0;
int J_opt = 0;
/*
* Set up default values for the modem.
@ -215,7 +218,7 @@ int main(int argc, char **argv)
/* ':' following option character means arg is required. */
c = getopt_long(argc, argv, "gm:s:a:b:B:r:n:o:z:82M:X",
c = getopt_long(argc, argv, "gjJm:s:a:b:B:r:n:o:z:82M:X",
long_options, &option_index);
if (c == -1)
break;
@ -310,11 +313,17 @@ int main(int argc, char **argv)
case 'g': /* -g for g3ruh scrambling */
// FIXME: order dependent. -g must come after -B.
g_opt = 1;
break;
modem.achan[0].modem_type = MODEM_SCRAMBLE;
text_color_set(DW_COLOR_INFO);
dw_printf ("Using scrambled baseband signal rather than AFSK.\n");
case 'j': /* -j V.26 compatible with earlier direwolf. */
j_opt = 1;
break;
case 'J': /* -J V.26 compatible with MFJ-2400. */
J_opt = 1;
break;
case 'm': /* -m for Mark freq */
@ -449,6 +458,41 @@ int main(int argc, char **argv)
}
}
// These must be processed after -B option.
if (g_opt) { /* -g for g3ruh scrambling */
modem.achan[0].modem_type = MODEM_SCRAMBLE;
text_color_set(DW_COLOR_INFO);
dw_printf ("Using G3RUH mode regardless of bit rate.\n");
}
if (j_opt) { /* -j V.26 compatible with earlier direwolf. */
modem.achan[0].v26_alternative = V26_A;
modem.achan[0].modem_type = MODEM_QPSK;
modem.achan[0].mark_freq = 0;
modem.achan[0].space_freq = 0;
modem.achan[0].baud = 2400;
}
if (J_opt) { /* -J V.26 compatible with MFJ-2400. */
modem.achan[0].v26_alternative = V26_B;
modem.achan[0].modem_type = MODEM_QPSK;
modem.achan[0].mark_freq = 0;
modem.achan[0].space_freq = 0;
modem.achan[0].baud = 2400;
}
if (modem.achan[0].modem_type == MODEM_QPSK &&
modem.achan[0].v26_alternative == V26_UNSPECIFIED) {
text_color_set(DW_COLOR_ERROR);
dw_printf ("ERROR: Either -j or -J must be specified when using 2400 bps QPSK.\n");
usage (argv);
exit (1);
}
/*
* Open the output file.
@ -689,6 +733,8 @@ static void usage (char **argv)
dw_printf (" -b <number> Bits / second for data. Default is %d.\n", DEFAULT_BAUD);
dw_printf (" -B <number> Bits / second for data. Proper modem selected for 300, 1200, 2400, 4800, 9600.\n");
dw_printf (" -g Scrambled baseband rather than AFSK.\n");
dw_printf (" -j 2400 bps QPSK compatible with direwolf <= 1.5.\n");
dw_printf (" -J 2400 bps QPSK compatible with MFJ-2400.\n");
dw_printf (" -m <number> Mark frequency. Default is %d.\n", DEFAULT_MARK_FREQ);
dw_printf (" -s <number> Space frequency. Default is %d.\n", DEFAULT_SPACE_FREQ);
dw_printf (" -r <number> Audio sample Rate. Default is %d.\n", DEFAULT_SAMPLES_PER_SEC);

View File

@ -280,6 +280,8 @@ int gen_tone_init (struct audio_s *audio_config_p, int amp, int gen_packets)
* This avoids overshoot, ringing, and adding more jitter.
* Alternating bits come out has sine wave of baud/2 Hz.
*
* Version 1.6: MFJ-2400 compatibility for V.26.
*
*--------------------------------------------------------------------*/
static const int gray2phase_v26[4] = {0, 1, 3, 2};
@ -304,6 +306,8 @@ void tone_gen_put_bit (int chan, int dat)
dat = 0;
}
// TODO: change to switch instead of if if if
if (save_audio_config_p->achan[chan].modem_type == MODEM_QPSK) {
int dibit;
@ -324,7 +328,9 @@ void tone_gen_put_bit (int chan, int dat)
symbol = gray2phase_v26[dibit];
tone_phase[chan] += symbol * PHASE_SHIFT_90;
if (save_audio_config_p->achan[chan].v26_alternative == V26_B) {
tone_phase[chan] += PHASE_SHIFT_45;
}
bit_count[chan]++;
}

View File

@ -21,17 +21,46 @@ atest \- Decode AX.25 frames from an audio file.
.SH OPTIONS
.TP
.BI "-B " "n"
Bits / second for data. Proper modem selected for 300, 1200, 9600.
300 baud uses 1600/1800 Hz AFSK.
1200 (default) baud uses 1200/2200 Hz AFSK.
9600 baud uses K9NG/G2RUH standard.
Data rate in bits/sec. Standard values are 300, 1200, 2400, 4800, 9600.
.PD 0
.RS
.RS
300 bps defaults to AFSK tones of 1600 & 1800.
.P
1200 bps uses AFSK tones of 1200 & 2200.
.P
2400 bps uses QPSK based on V.26 standard.
.P
4800 bps uses 8PSK based on V.27 standard.
.P
9600 bps and up uses K9NG/G3RUH standard.
.RE
.RE
.PD
.TP
.BI "-g "
Force G3RUH modem regardless of data rate.
.TP
.BI "-j "
2400 bps QPSK compatible with Dire Wolf <= 1.5.
.TP
.BI "-J "
2400 bps QPSK compatible with MFJ-2400.
.TP
.BI "-D " "n"
Divide audio sample rate by n.
.TP
.BI "-h "
Print frame contents as hexadecimal bytes.
.TP
.BI "-F " "n"
Amount of effort to try fixing frames with an invalid CRC.
@ -39,9 +68,17 @@ Amount of effort to try fixing frames with an invalid CRC.
1 = Try to fix only a single bit.
more = Try modifying more bits to get a good CRC.
.TP
.BI "-L "
Error if Less than this number decoded.
.TP
.BI "-G "
Error if Greater than this number decoded.
.TP
.BI "-P " "m"
Select the demodulator type such as A, B, C, D (default for 300 baud), E (default for 1200 baud), F, A+, B+, C+, D+, E+, F+.
Select the demodulator type such as D (default for 300 bps), E+ (default for 1200 bps), PQRS for 2400 bps, etc.
@ -72,20 +109,20 @@ This generates and decodes 3 test files with 1200, 300, and 9600 bits per second
.PD 0
.B atest 02_Track_2.wav
.P
.B atest -P C+ 02_Track_2.wav
.B atest -P E- 02_Track_2.wav
.P
.B atest -F 1 02_Track_2.wav
.P
.B atest -P C+ -F 1 02_Track_2.wav
.B atest -P E- -F 1 02_Track_2.wav
.PD
.P
.RS
Try different combinations of options to find the best decoding performance.
Try different combinations of options to compare decoding performance.
.RE
.P
.SH SEE ALSO
More detailed information is in the pdf files in /usr/local/share/doc/direwolf, or possibly /usr/share/doc/direwolf, depending on installation location.
Applications in this package: aclients, atest, decode_aprs, direwolf, gen_packets, kissutil, ll2utm, log2gpx, text2tt, tt2text, utm2ll
Applications in this package: aclients, atest, cm108, decode_aprs, direwolf, gen_packets, kissutil, ll2utm, log2gpx, text2tt, tt2text, utm2ll

View File

@ -48,19 +48,35 @@ Audio sample size for first channel. 8 or 16. Default 16.
.TP
.BI "-B " "n"
Data rate in bits/sec for first channel. Standard values are 300, 1200, 9600.
Data rate in bits/sec for first channel. Standard values are 300, 1200, 2400, 4800, 9600.
.PD 0
.RS
.RS
If < 600, tones are set to 1600 & 1800.
300 bps defaults to AFSK tones of 1600 & 1800.
.P
If > 2400, K9NG/G3RUH scrambling is used.
1200 bps uses AFSK tones of 1200 & 2200.
.P
Otherwise, AFSK tones are set to 1200 & 2200.
2400 bps uses QPSK based on V.26 standard.
.P
4800 bps uses 8PSK based on V.27 standard.
.P
9600 bps and up uses K9NG/G3RUH standard.
.RE
.RE
.PD
.TP
.BI "-g "
Force G3RUH modem regardless of data rate.
.TP
.BI "-j "
2400 bps QPSK compatible with Dire Wolf <= 1.5.
.TP
.BI "-J "
2400 bps QPSK compatible with MFJ-2400.
.TP
.BI "-D " "n"
Divide audio sample by n for first channel.
@ -92,6 +108,10 @@ o = Output controls such as PTT and DCD.
i = IGate
.P
h = Hamlib verbose level. Repeat for more.
.P
m = Monitor heard station list.
.P
f = Packet filtering.
.RE
.RE
.PD
@ -152,5 +172,5 @@ rtl_fm \-f 144.39M \-o 4 \- | direwolf \-n 1 \-r 24000 \-b 16 \-
.SH SEE ALSO
More detailed information is in the pdf files in /usr/local/share/doc/direwolf, or possibly /usr/share/doc/direwolf, depending on installation location.
Applications in this package: aclients, atest, decode_aprs, direwolf, gen_packets, kissutil, ll2utm, log2gpx, text2tt, tt2text, utm2ll
Applications in this package: aclients, atest, cm108, decode_aprs, direwolf, gen_packets, kissutil, ll2utm, log2gpx, text2tt, tt2text, utm2ll

View File

@ -33,11 +33,35 @@ Bits / second for data. Default is 1200.
.TP
.BI "-B " "n"
Bits / second for data. Proper modem selected for 300, 1200, 9600.
Data rate in bits/sec for first channel. Standard values are 300, 1200, 2400, 4800, 9600.
.PD 0
.RS
.RS
300 bps defaults to AFSK tones of 1600 & 1800.
.P
1200 bps uses AFSK tones of 1200 & 2200.
.P
2400 bps uses QPSK based on V.26 standard.
.P
4800 bps uses 8PSK based on V.27 standard.
.P
9600 bps and up uses K9NG/G3RUH standard.
.RE
.RE
.PD
.TP
.BI "-g "
Scrambled baseband rather than AFSK.
Force G3RUH modem regardless of data rate.
.TP
.BI "-j "
2400 bps QPSK compatible with Dire Wolf <= 1.5.
.TP
.BI "-J "
2400 bps QPSK compatible with MFJ-2400.
.TP
.BI "-m " "n"
@ -112,5 +136,5 @@ Read message from stdin and put quarter volume sound into the file x.wav. Decod
.SH SEE ALSO
More detailed information is in the pdf files in /usr/local/share/doc/direwolf, or possibly /usr/share/doc/direwolf, depending on installation location.
Applications in this package: aclients, atest, decode_aprs, direwolf, gen_packets, ll2utm, log2gpx, text2tt, tt2text, utm2ll
Applications in this package: aclients, atest, cm108, decode_aprs, direwolf, gen_packets, kissutil, ll2utm, log2gpx, text2tt, tt2text, utm2ll