This commit is contained in:
Marcos Vives Del Sol 2014-11-09 15:57:14 +00:00
commit 88a3a36b4f
18 changed files with 499 additions and 99 deletions

1
.gitignore vendored
View File

@ -5,3 +5,4 @@ Makefile
/config.log
/config.status
/stamp-h1
autom4te.cache

55
aclocal.m4 vendored
View File

@ -180,6 +180,61 @@ else
fi[]dnl
])# PKG_CHECK_MODULES
# PKG_INSTALLDIR(DIRECTORY)
# -------------------------
# Substitutes the variable pkgconfigdir as the location where a module
# should install pkg-config .pc files. By default the directory is
# $libdir/pkgconfig, but the default can be changed by passing
# DIRECTORY. The user can override through the --with-pkgconfigdir
# parameter.
AC_DEFUN([PKG_INSTALLDIR],
[m4_pushdef([pkg_default], [m4_default([$1], ['${libdir}/pkgconfig'])])
m4_pushdef([pkg_description],
[pkg-config installation directory @<:@]pkg_default[@:>@])
AC_ARG_WITH([pkgconfigdir],
[AS_HELP_STRING([--with-pkgconfigdir], pkg_description)],,
[with_pkgconfigdir=]pkg_default)
AC_SUBST([pkgconfigdir], [$with_pkgconfigdir])
m4_popdef([pkg_default])
m4_popdef([pkg_description])
]) dnl PKG_INSTALLDIR
# PKG_NOARCH_INSTALLDIR(DIRECTORY)
# -------------------------
# Substitutes the variable noarch_pkgconfigdir as the location where a
# module should install arch-independent pkg-config .pc files. By
# default the directory is $datadir/pkgconfig, but the default can be
# changed by passing DIRECTORY. The user can override through the
# --with-noarch-pkgconfigdir parameter.
AC_DEFUN([PKG_NOARCH_INSTALLDIR],
[m4_pushdef([pkg_default], [m4_default([$1], ['${datadir}/pkgconfig'])])
m4_pushdef([pkg_description],
[pkg-config arch-independent installation directory @<:@]pkg_default[@:>@])
AC_ARG_WITH([noarch-pkgconfigdir],
[AS_HELP_STRING([--with-noarch-pkgconfigdir], pkg_description)],,
[with_noarch_pkgconfigdir=]pkg_default)
AC_SUBST([noarch_pkgconfigdir], [$with_noarch_pkgconfigdir])
m4_popdef([pkg_default])
m4_popdef([pkg_description])
]) dnl PKG_NOARCH_INSTALLDIR
# PKG_CHECK_VAR(VARIABLE, MODULE, CONFIG-VARIABLE,
# [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND])
# -------------------------------------------
# Retrieves the value of the pkg-config variable for the given module.
AC_DEFUN([PKG_CHECK_VAR],
[AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl
AC_ARG_VAR([$1], [value of $3 for $2, overriding pkg-config])dnl
_PKG_CONFIG([$1], [variable="][$3]["], [$2])
AS_VAR_COPY([$1], [pkg_cv_][$1])
AS_VAR_IF([$1], [""], [$5], [$4])dnl
])# PKG_CHECK_VAR
# Copyright (C) 2002, 2003, 2005, 2006, 2007, 2008, 2011 Free Software
# Foundation, Inc.
#

1
src/.gitignore vendored
View File

@ -1,3 +1,4 @@
/minimodem
/minimodem.1
/minimodem.1.html
/minimodem.exe

View File

@ -42,15 +42,20 @@ FSK_SRC = fsk.h fsk.c
BAUDOT_SRC = baudot.h baudot.c
UIC_SRC = uic_codes.h uic_codes.c
DATABITS_SRC = \
databits.h \
databits_ascii.c \
databits_binary.c \
databits_callerid.c \
databits_baudot.c $(BAUDOT_SRC)
databits_baudot.c $(BAUDOT_SRC) \
databits_uic.c $(UIC_SRC)
MISC_SRC = misc.h misc.c
minimodem_LDADD = $(DEPS_LIBS)
minimodem_SOURCES = minimodem.c $(DATABITS_SRC) $(FSK_SRC) $(SIMPLEAUDIO_SRC)
minimodem_SOURCES = minimodem.c $(DATABITS_SRC) $(FSK_SRC) $(SIMPLEAUDIO_SRC) $(MISC_SRC)
minimodem.1.html: minimodem.1 Makefile

View File

@ -83,15 +83,17 @@ CONFIG_CLEAN_VPATH_FILES =
am__installdirs = "$(DESTDIR)$(bindir)" "$(DESTDIR)$(man1dir)"
PROGRAMS = $(bin_PROGRAMS)
am__objects_1 = baudot.$(OBJEXT)
am__objects_2 = databits_ascii.$(OBJEXT) databits_binary.$(OBJEXT) \
am__objects_2 = uic_codes.$(OBJEXT)
am__objects_3 = databits_ascii.$(OBJEXT) databits_binary.$(OBJEXT) \
databits_callerid.$(OBJEXT) databits_baudot.$(OBJEXT) \
$(am__objects_1)
am__objects_3 = fsk.$(OBJEXT)
am__objects_4 = simpleaudio.$(OBJEXT) simple-tone-generator.$(OBJEXT) \
$(am__objects_1) databits_uic.$(OBJEXT) $(am__objects_2)
am__objects_4 = fsk.$(OBJEXT)
am__objects_5 = simpleaudio.$(OBJEXT) simple-tone-generator.$(OBJEXT) \
simpleaudio-pulse.$(OBJEXT) simpleaudio-alsa.$(OBJEXT) \
simpleaudio-benchmark.$(OBJEXT) simpleaudio-sndfile.$(OBJEXT)
am_minimodem_OBJECTS = minimodem.$(OBJEXT) $(am__objects_2) \
$(am__objects_3) $(am__objects_4)
am__objects_6 = misc.$(OBJEXT)
am_minimodem_OBJECTS = minimodem.$(OBJEXT) $(am__objects_3) \
$(am__objects_4) $(am__objects_5) $(am__objects_6)
minimodem_OBJECTS = $(am_minimodem_OBJECTS)
am__DEPENDENCIES_1 =
minimodem_DEPENDENCIES = $(am__DEPENDENCIES_1)
@ -247,15 +249,18 @@ SIMPLEAUDIO_SRC = \
FSK_SRC = fsk.h fsk.c
BAUDOT_SRC = baudot.h baudot.c
UIC_SRC = uic_codes.h uic_codes.c
DATABITS_SRC = \
databits.h \
databits_ascii.c \
databits_binary.c \
databits_callerid.c \
databits_baudot.c $(BAUDOT_SRC)
databits_baudot.c $(BAUDOT_SRC) \
databits_uic.c $(UIC_SRC)
MISC_SRC = misc.h misc.c
minimodem_LDADD = $(DEPS_LIBS)
minimodem_SOURCES = minimodem.c $(DATABITS_SRC) $(FSK_SRC) $(SIMPLEAUDIO_SRC)
minimodem_SOURCES = minimodem.c $(DATABITS_SRC) $(FSK_SRC) $(SIMPLEAUDIO_SRC) $(MISC_SRC)
all: all-am
.SUFFIXES:
@ -347,14 +352,17 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/databits_baudot.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/databits_binary.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/databits_callerid.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/databits_uic.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fsk.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/minimodem.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/misc.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/simple-tone-generator.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/simpleaudio-alsa.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/simpleaudio-benchmark.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/simpleaudio-pulse.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/simpleaudio-sndfile.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/simpleaudio.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/uic_codes.Po@am__quote@
.c.o:
@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<

View File

@ -22,7 +22,7 @@ typedef int (databits_encoder)(
typedef unsigned int (databits_decoder)(
char *dataout_p, unsigned int dataout_size,
unsigned int bits, unsigned int n_databits );
unsigned long long bits, unsigned int n_databits );
int
@ -30,7 +30,7 @@ databits_encode_ascii8( unsigned int *databits_outp, char char_out );
unsigned int
databits_decode_ascii8( char *dataout_p, unsigned int dataout_size,
unsigned int bits, unsigned int n_databits );
unsigned long long bits, unsigned int n_databits );
#include "baudot.h"
@ -40,7 +40,7 @@ databits_decode_ascii8( char *dataout_p, unsigned int dataout_size,
unsigned int
databits_decode_baudot( char *dataout_p, unsigned int dataout_size,
unsigned int bits, unsigned int n_databits );
unsigned long long bits, unsigned int n_databits );
int
@ -48,11 +48,17 @@ databits_encode_binary( unsigned int *databits_outp, char char_out );
unsigned int
databits_decode_binary( char *dataout_p, unsigned int dataout_size,
unsigned int bits, unsigned int n_databits );
unsigned long long bits, unsigned int n_databits );
unsigned int
databits_decode_callerid( char *dataout_p, unsigned int dataout_size,
unsigned int bits, unsigned int n_databits );
unsigned long long bits, unsigned int n_databits );
unsigned int
databits_decode_uic_ground( char *dataout_p, unsigned int dataout_size,
unsigned long long bits, unsigned int n_databits );
unsigned int
databits_decode_uic_train( char *dataout_p, unsigned int dataout_size,
unsigned long long bits, unsigned int n_databits );

View File

@ -34,7 +34,7 @@ databits_encode_ascii8( unsigned int *databits_outp, char char_out )
/* returns nbytes decoded */
unsigned int
databits_decode_ascii8( char *dataout_p, unsigned int dataout_size,
unsigned int bits, unsigned int n_databits )
unsigned long long bits, unsigned int n_databits )
{
if ( ! dataout_p ) // databits processor reset: noop
return 0;

View File

@ -28,7 +28,7 @@
/* returns nbytes decoded */
unsigned int
databits_decode_baudot( char *dataout_p, unsigned int dataout_size,
unsigned int bits, unsigned int n_databits )
unsigned long long bits, unsigned int n_databits )
{
if ( ! dataout_p ) { // databits processor reset: reset Baudot state
baudot_reset();

View File

@ -28,7 +28,7 @@
// returns nbytes decoded
unsigned int
databits_decode_binary( char *dataout_p, unsigned int dataout_size,
unsigned int bits, unsigned int n_databits )
unsigned long long bits, unsigned int n_databits )
{
if ( ! dataout_p ) // databits processor reset: noop
return 0;

View File

@ -157,7 +157,7 @@ decode_cid_reset()
/* returns nbytes decoded */
unsigned int
databits_decode_callerid( char *dataout_p, unsigned int dataout_size,
unsigned int bits, unsigned int n_databits )
unsigned long long bits, unsigned int n_databits )
{
if ( ! dataout_p ) // databits processor reset
return decode_cid_reset();
@ -183,7 +183,7 @@ databits_decode_callerid( char *dataout_p, unsigned int dataout_size,
// Collect input bytes until we've collected as many as the message
// length byte says there will be, plus two (the message type byte
// and the checksum byte)
unsigned int cid_msglen = cid_buf[1];
unsigned long long cid_msglen = cid_buf[1];
if ( cid_ndata < cid_msglen + 2)
return 0;

75
src/databits_uic.c Executable file
View File

@ -0,0 +1,75 @@
/*
* databits_uic.c
*
* Copyright (C) 2014 Marcos Vives Del Sol <socram8888@gmail.com>
*
* 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 3 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/>.
*/
#include <stdio.h>
#include "databits.h"
#include "uic_codes.h"
#include "misc.h"
/*
* UIC-751-3 Ground-train decoder
*/
unsigned int
databits_decode_uic(char *output,
unsigned long long input,
unsigned int type)
{
int written;
if (!output) {
return 0;
}
unsigned int code = (unsigned int) bit_reverse(bit_window(input, 24, 8), 8);
written = sprintf(output, "Train ID: %X%X%X%X%X%X - Message: %02X (%s)\n",
(unsigned int) bit_window(input, 0, 4),
(unsigned int) bit_window(input, 4, 4),
(unsigned int) bit_window(input, 8, 4),
(unsigned int) bit_window(input, 12, 4),
(unsigned int) bit_window(input, 16, 4),
(unsigned int) bit_window(input, 20, 4),
code,
uic_message_meaning(code, type)
);
return written;
}
unsigned int
databits_decode_uic_ground(char *output,
unsigned int outputSize,
unsigned long long input,
unsigned int inputSize)
{
return databits_decode_uic(output,
input,
UIC_TYPE_GROUNDTRAIN);
}
unsigned int
databits_decode_uic_train(char *output,
unsigned int outputSize,
unsigned long long input,
unsigned int inputSize)
{
return databits_decode_uic(output,
input,
UIC_TYPE_TRAINGROUND);
}

View File

@ -178,13 +178,13 @@ fsk_bit_analyze( fsk_plan *fskp, float *samples, unsigned int bit_nsamples,
static float
fsk_frame_analyze( fsk_plan *fskp, float *samples, float samples_per_bit,
int n_bits, const char *expect_bits_string,
unsigned int *bits_outp, float *ampl_outp )
unsigned long long *bits_outp, float *ampl_outp )
{
unsigned int bit_nsamples = (float)(samples_per_bit + 0.5);
unsigned int bit_values[32];
float bit_sig_mags[32];
float bit_noise_mags[32];
unsigned int bit_values[64];
float bit_sig_mags[64];
float bit_noise_mags[64];
unsigned int bit_begin_sample;
int bitnum;
@ -422,7 +422,7 @@ fsk_frame_analyze( fsk_plan *fskp, float *samples, float samples_per_bit,
// into the bits_outp word.
*bits_outp = 0;
for ( bitnum=0; bitnum<n_bits; bitnum++ )
*bits_outp |= bit_values[bitnum] << bitnum;
*bits_outp |= (unsigned long long) bit_values[bitnum] << bitnum;
debug_log(" frame algo=%u confidence=%f ampl=%f\n",
CONFIDENCE_ALGO, confidence, *ampl_outp);
@ -437,7 +437,7 @@ fsk_find_frame( fsk_plan *fskp, float *samples, unsigned int frame_nsamples,
unsigned int try_step_nsamples,
float try_confidence_search_limit,
const char *expect_bits_string,
unsigned int *bits_outp,
unsigned long long *bits_outp,
float *ampl_outp,
unsigned int *frame_start_outp
)
@ -450,7 +450,7 @@ fsk_find_frame( fsk_plan *fskp, float *samples, unsigned int frame_nsamples,
unsigned int best_t = 0;
float best_c = 0.0, best_a = 0.0;
unsigned int best_bits = 0;
unsigned long long best_bits = 0;
// Scan the frame positions starting with the one try_first_sample,
// alternating between a step above that, a step below that, above, below,
@ -466,7 +466,7 @@ fsk_find_frame( fsk_plan *fskp, float *samples, unsigned int frame_nsamples,
continue;
float c, ampl_out;
unsigned int bits_out = 0;
unsigned long long bits_out = 0;
debug_log("try fsk_frame_analyze at t=%d\n", t);
c = fsk_frame_analyze(fskp, samples+t, samples_per_bit,
expect_n_bits, expect_bits_string,

View File

@ -65,7 +65,7 @@ fsk_find_frame( fsk_plan *fskp, float *samples, unsigned int frame_nsamples,
unsigned int try_step_nsamples,
float try_confidence_search_limit,
const char *expect_bits_string,
unsigned int *bits_outp,
unsigned long long *bits_outp,
float *ampl_outp,
unsigned int *frame_start_outp
);

View File

@ -41,6 +41,7 @@
#include "simpleaudio.h"
#include "fsk.h"
#include "databits.h"
#include "misc.h"
char *program_name = "";
@ -81,20 +82,28 @@ static void fsk_transmit_frame(
float bfsk_mark_f,
float bfsk_space_f,
float bfsk_nstartbits,
float bfsk_nstopbits
float bfsk_nstopbits,
int invert_start_stop,
int bfsk_msb_first
)
{
int i;
if ( bfsk_nstartbits > 0 )
simpleaudio_tone(sa_out, bfsk_space_f,
simpleaudio_tone(sa_out, invert_start_stop ? bfsk_mark_f : bfsk_space_f,
bit_nsamples * bfsk_nstartbits); // start
for ( i=0; i<n_data_bits; i++ ) { // data
unsigned int bit = ( bits >> i ) & 1;
unsigned int bit;
if (bfsk_msb_first) {
bit = ( bits >> (n_data_bits - i - 1) ) & 1;
} else {
bit = ( bits >> i ) & 1;
}
float tone_freq = bit == 1 ? bfsk_mark_f : bfsk_space_f;
simpleaudio_tone(sa_out, tone_freq, bit_nsamples);
}
if ( bfsk_nstopbits > 0 )
simpleaudio_tone(sa_out, bfsk_mark_f,
simpleaudio_tone(sa_out, invert_start_stop ? bfsk_space_f : bfsk_mark_f,
bit_nsamples * bfsk_nstopbits); // stop
}
@ -107,6 +116,8 @@ static void fsk_transmit_stdin(
int n_data_bits,
float bfsk_nstartbits,
float bfsk_nstopbits,
int invert_start_stop,
int bfsk_msb_first,
unsigned int bfsk_do_tx_sync_bytes,
unsigned int bfsk_sync_byte,
databits_encoder encode
@ -151,19 +162,19 @@ static void fsk_transmit_stdin(
tx_transmitting = 1;
/* emit leader tone (mark) */
for ( j=0; j<tx_leader_bits_len; j++ )
simpleaudio_tone(sa_out, bfsk_mark_f, bit_nsamples);
simpleaudio_tone(sa_out, invert_start_stop ? bfsk_space_f : bfsk_mark_f, bit_nsamples);
/* emit "preamble" of sync bytes */
for ( j=0; j<bfsk_do_tx_sync_bytes; j++ )
fsk_transmit_frame(sa_out, bfsk_sync_byte, n_data_bits,
bit_nsamples, bfsk_mark_f, bfsk_space_f,
bfsk_nstartbits, bfsk_nstopbits);
bfsk_nstartbits, bfsk_nstopbits, invert_start_stop, 0);
}
/* emit data bits */
for ( j=0; j<nwords; j++ )
fsk_transmit_frame(sa_out, bits[j], n_data_bits,
bit_nsamples, bfsk_mark_f, bfsk_space_f,
bfsk_nstartbits, bfsk_nstopbits);
bfsk_nstartbits, bfsk_nstopbits, invert_start_stop, bfsk_msb_first);
if ( tx_interactive )
setitimer(ITIMER_REAL, &itv, NULL);
@ -337,6 +348,7 @@ usage()
" -S, --space {space_freq}\n"
" --startbits {n}\n"
" --stopbits {n.n}\n"
" --invert-start-stop\n"
" --sync-byte {0xXX}\n"
" -q, --quiet\n"
" -R, --samplerate {rate}\n"
@ -355,10 +367,58 @@ usage()
" rtty RTTY 45.45 bps --baudot --stopbits=1.5\n"
" same NOAA SAME 520.83 bps --sync-byte=0xAB ...\n"
" callerid Bell202 CID 1200 bps\n"
" uid-train UIC-751-3 Train-to-ground 600 bps\n"
" uid-ground UIC-751-3 Ground-to-train 600 bps\n"
);
exit(1);
}
int
build_expect_bit_string(char * expect_bits_string,
int bfsk_nstartbits,
int bfsk_n_data_bits,
float bfsk_nstopbits,
int invert_start_stop,
unsigned long long bfsk_sync_byte)
{
// example expect_bits_string
// 0123456789A
// isddddddddp i == idle bit (a.k.a. prev_stop bit)
// s == start bit d == data bits p == stop bit
// ebs = "10dddddddd1" <-- expected mark/space framing pattern
//
// NOTE! expect_n_bits ends up being (frame_n_bits+1), because
// we expect the prev_stop bit in addition to this frame's own
// (start + n_data_bits + stop) bits. But for each decoded frame,
// we will advance just frame_n_bits worth of samples, leaving us
// pointing at our stop bit -- it becomes the next frame's prev_stop.
//
// prev_stop--v
// start--v v--stop
// char *expect_bits_string = "10dddddddd1";
//
char start_bit_value = invert_start_stop ? '1' : '0';
char stop_bit_value = invert_start_stop ? '0' : '1';
int j = 0;
if ( bfsk_nstopbits != 0.0 )
expect_bits_string[j++] = stop_bit_value;
int i;
// Nb. only integer number of start bits works (for rx)
for ( i=0; i<bfsk_nstartbits; i++ )
expect_bits_string[j++] = start_bit_value;
for ( i=0; i<bfsk_n_data_bits; i++,j++ ) {
if ( (long long) bfsk_sync_byte >= 0 )
expect_bits_string[j] = ( (bfsk_sync_byte>>i)&1 ) + '0';
else
expect_bits_string[j] = 'd';
}
if ( bfsk_nstopbits != 0.0 )
expect_bits_string[j++] = stop_bit_value;
expect_bits_string[j] = 0;
return j;
}
int
main( int argc, char*argv[] )
{
@ -374,8 +434,13 @@ main( int argc, char*argv[] )
float bfsk_nstopbits = -1;
unsigned int bfsk_do_rx_sync = 0;
unsigned int bfsk_do_tx_sync_bytes = 0;
unsigned int bfsk_sync_byte = -1;
unsigned long long bfsk_sync_byte = -1;
unsigned int bfsk_n_data_bits = 0;
int bfsk_msb_first = 0;
char *expect_data_string = NULL;
char *expect_sync_string = NULL;
unsigned int expect_n_bits;
int invert_start_stop = 0;
int autodetect_shift;
char *filename = NULL;
@ -436,8 +501,10 @@ main( int argc, char*argv[] )
enum {
MINIMODEM_OPT_UNUSED=256, // placeholder
MINIMODEM_OPT_MSBFIRST,
MINIMODEM_OPT_STARTBITS,
MINIMODEM_OPT_STOPBITS,
MINIMODEM_OPT_INVERT_START_STOP,
MINIMODEM_OPT_SYNC_BYTE,
MINIMODEM_OPT_LUT,
MINIMODEM_OPT_FLOAT_SAMPLES,
@ -464,6 +531,7 @@ main( int argc, char*argv[] )
{ "ascii", 0, 0, '8' },
{ "", 0, 0, '7' },
{ "baudot", 0, 0, '5' },
{ "msb-first", 0, 0, MINIMODEM_OPT_MSBFIRST },
{ "file", 1, 0, 'f' },
{ "bandwidth", 1, 0, 'b' },
{ "volume", 1, 0, 'v' },
@ -471,6 +539,7 @@ main( int argc, char*argv[] )
{ "space", 1, 0, 'S' },
{ "startbits", 1, 0, MINIMODEM_OPT_STARTBITS },
{ "stopbits", 1, 0, MINIMODEM_OPT_STOPBITS },
{ "invert-start-stop", 0, 0, MINIMODEM_OPT_INVERT_START_STOP },
{ "sync-byte", 1, 0, MINIMODEM_OPT_SYNC_BYTE },
{ "quiet", 0, 0, 'q' },
{ "alsa", 2, 0, 'A' },
@ -528,6 +597,9 @@ main( int argc, char*argv[] )
bfsk_databits_decode = databits_decode_baudot;
bfsk_databits_encode = databits_encode_baudot;
break;
case MINIMODEM_OPT_MSBFIRST:
bfsk_msb_first = 1;
break;
case 'b':
band_width = atof(optarg);
assert( band_width != 0 );
@ -557,6 +629,9 @@ main( int argc, char*argv[] )
bfsk_nstopbits = atof(optarg);
assert( bfsk_nstopbits >= 0 );
break;
case MINIMODEM_OPT_INVERT_START_STOP:
invert_start_stop = 1;
break;
case MINIMODEM_OPT_SYNC_BYTE:
bfsk_do_rx_sync = 1;
bfsk_do_tx_sync_bytes = 16;
@ -671,6 +746,24 @@ main( int argc, char*argv[] )
bfsk_databits_decode = databits_decode_callerid;
bfsk_data_rate = 1200;
bfsk_n_data_bits = 8;
} else if ( strncasecmp(modem_mode, "uic-train", 9) == 0 || strncasecmp(modem_mode, "uic-ground", 10) == 0 ) {
if ( TX_mode ) {
fprintf(stderr, "E: uic-751-3 --tx mode is not supported.\n");
return 1;
}
// http://ec.europa.eu/transport/rail/interoperability/doc/ccs-tsi-en-annex.pdf
if (modem_mode[4] == 't' || modem_mode[4] == 'T')
bfsk_databits_decode = databits_decode_uic_train;
else
bfsk_databits_decode = databits_decode_uic_ground;
bfsk_data_rate = 600;
bfsk_n_data_bits = 39;
bfsk_mark_f = 1300;
bfsk_space_f = 1700;
bfsk_nstartbits = 8;
bfsk_nstopbits = 0;
expect_data_string = "11110010ddddddddddddddddddddddddddddddddddddddd";
expect_n_bits = 47;
} else {
bfsk_data_rate = atof(modem_mode);
if ( bfsk_n_data_bits == 0 )
@ -778,6 +871,8 @@ main( int argc, char*argv[] )
bfsk_n_data_bits,
bfsk_nstartbits,
bfsk_nstopbits,
invert_start_stop,
bfsk_msb_first,
bfsk_do_tx_sync_bytes,
bfsk_sync_byte,
bfsk_databits_encode
@ -788,7 +883,6 @@ main( int argc, char*argv[] )
return 0;
}
/*
* Open the input audio stream
*/
@ -837,19 +931,6 @@ main( int argc, char*argv[] )
nbits += bfsk_n_data_bits;
nbits += 1; // stop bit (first whole stop bit)
// FIXME EXPLAIN +1 goes with extra bit when scanning
size_t samplebuf_size = ceilf(nsamples_per_bit) * (nbits+1);
samplebuf_size *= 2; // account for the half-buf filling method
#define SAMPLE_BUF_DIVISOR 12
#ifdef SAMPLE_BUF_DIVISOR
// For performance, use a larger samplebuf_size than necessary
if ( samplebuf_size < sample_rate / SAMPLE_BUF_DIVISOR )
samplebuf_size = sample_rate / SAMPLE_BUF_DIVISOR;
#endif
float *samplebuf = malloc(samplebuf_size * sizeof(float));
size_t samples_nvalid = 0;
debug_log("samplebuf_size=%zu\n", samplebuf_size);
/*
* Run the main loop
*/
@ -891,6 +972,38 @@ main( int argc, char*argv[] )
float frame_n_bits = bfsk_n_data_bits + bfsk_nstartbits + bfsk_nstopbits;
unsigned int frame_nsamples = nsamples_per_bit * frame_n_bits + 0.5;
char expect_data_string_buffer[64];
if (expect_data_string == NULL) {
expect_data_string = expect_data_string_buffer;
expect_n_bits = build_expect_bit_string(expect_data_string, bfsk_nstartbits, bfsk_n_data_bits, bfsk_nstopbits, invert_start_stop, (unsigned long long) -1);
}
//fprintf(stderr, "eds = '%s' (%lu)\n", expect_data_string, strlen(expect_data_string));
char expect_sync_string_buffer[64];
if (expect_sync_string == NULL && bfsk_do_rx_sync && (long long) bfsk_sync_byte >= 0) {
expect_sync_string = expect_sync_string_buffer;
build_expect_bit_string(expect_sync_string, bfsk_nstartbits, bfsk_n_data_bits, bfsk_nstopbits, invert_start_stop, bfsk_sync_byte);
} else {
expect_sync_string = expect_data_string;
}
//fprintf(stderr, "ess = '%s' (%lu)\n", expect_sync_string, strlen(expect_sync_string));
unsigned int expect_nsamples = nsamples_per_bit * expect_n_bits;
size_t samplebuf_size = expect_nsamples * 2; // account for the half-buf filling method
#define SAMPLE_BUF_DIVISOR 12
#ifdef SAMPLE_BUF_DIVISOR
// For performance, use a larger samplebuf_size than necessary
if ( samplebuf_size < sample_rate / SAMPLE_BUF_DIVISOR )
{
debug_log("buffer too small (%i), ceiling to %i", samplebuf_size, sample_rate / SAMPLE_BUF_DIVISOR);
samplebuf_size = sample_rate / SAMPLE_BUF_DIVISOR;
}
#endif
float *samplebuf = malloc(samplebuf_size * sizeof(float));
size_t samples_nvalid = 0;
debug_log("samplebuf_size=%zu\n", samplebuf_size);
float track_amplitude = 0.0;
float peak_confidence = 0.0;
@ -987,47 +1100,7 @@ main( int argc, char*argv[] )
*/
debug_log( "--------------------------\n");
// example expect_bits_string
// 0123456789A
// isddddddddp i == idle bit (a.k.a. prev_stop bit)
// s == start bit d == data bits p == stop bit
// ebs = "10dddddddd1" <-- expected mark/space framing pattern
//
// NOTE! expect_n_bits ends up being (frame_n_bits+1), because
// we expect the prev_stop bit in addition to this frame's own
// (start + n_data_bits + stop) bits. But for each decoded frame,
// we will advance just frame_n_bits worth of samples, leaving us
// pointing at our stop bit -- it becomes the next frame's prev_stop.
//
// prev_stop--v
// start--v v--stop
// char *expect_bits_string = "10dddddddd1";
//
char expect_bits_string[32];
int j = 0;
if ( bfsk_nstopbits != 0.0 )
expect_bits_string[j++] = '1';
int i;
// Nb. only integer number of start bits works (for rx)
for ( i=0; i<bfsk_nstartbits; i++ )
expect_bits_string[j++] = '0';
for ( i=0; i<bfsk_n_data_bits; i++,j++ ) {
if ( ! carrier && bfsk_do_rx_sync )
expect_bits_string[j] = ( (bfsk_sync_byte>>i)&1 ) + '0';
else
expect_bits_string[j] = 'd';
}
if ( bfsk_nstopbits != 0.0 )
expect_bits_string[j++] = '1';
expect_bits_string[j++] = 0;
unsigned int expect_n_bits = strlen(expect_bits_string);
unsigned int expect_nsamples = nsamples_per_bit * expect_n_bits;
// fprintf(stderr, "ebs = '%s' (%lu) ; expect_nsamples=%u samples_nvalid=%lu\n", expect_bits_string, strlen(expect_bits_string), expect_nsamples, samples_nvalid);
//fprintf(stderr, "%i --- %i\n", samples_nvalid, expect_nsamples);
if ( samples_nvalid < expect_nsamples )
break;
@ -1053,7 +1126,7 @@ main( int argc, char*argv[] )
try_step_nsamples = 1;
float confidence, amplitude;
unsigned int bits = 0;
unsigned long long bits = 0;
/* Note: frame_start_sample is actually the sample where the
* prev_stop bit begins (since the "frame" includes the prev_stop). */
unsigned int frame_start_sample = 0;
@ -1069,7 +1142,7 @@ main( int argc, char*argv[] )
try_max_nsamples,
try_step_nsamples,
try_confidence_search_limit,
expect_bits_string,
carrier ? expect_data_string : expect_sync_string,
&bits,
&amplitude,
&frame_start_sample
@ -1170,14 +1243,14 @@ main( int argc, char*argv[] )
try_step_nsamples = 1;
try_confidence_search_limit = INFINITY;
float confidence2, amplitude2;
unsigned int bits2;
unsigned long long bits2;
unsigned int frame_start_sample2;
confidence2 = fsk_find_frame(fskp, samplebuf, expect_nsamples,
try_first_sample,
try_max_nsamples,
try_step_nsamples,
try_confidence_search_limit,
expect_bits_string,
carrier ? expect_data_string : expect_sync_string,
&bits2,
&amplitude2,
&frame_start_sample2
@ -1224,9 +1297,10 @@ main( int argc, char*argv[] )
*/
// chop off framing bits
unsigned int frame_bits_shift = bfsk_nstartbits;
unsigned int frame_bits_mask = (int)(1<<bfsk_n_data_bits) - 1;
bits = ( bits >> frame_bits_shift ) & frame_bits_mask;
bits = bit_window(bits, bfsk_nstartbits, bfsk_n_data_bits);
if (bfsk_msb_first) {
bits = bit_reverse(bits, bfsk_n_data_bits);
}
unsigned int dataout_size = 4096;
char dataoutbuf[4096];

46
src/misc.c Executable file
View File

@ -0,0 +1,46 @@
/*
* misc.c
*
* Copyright (C) 2014 Marcos Vives Del Sol <socram8888@gmail.com>
*
* 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 3 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/>.
*/
#include "misc.h"
// Reverses the ordering of the bits on an integer
unsigned long long
bit_reverse(unsigned long long value,
unsigned int bits)
{
unsigned int out = 0;
while (bits--) {
out = (out << 1) | (value & 1);
value >>= 1;
}
return out;
}
// Gets "bits" bits from "value" starting "offset" bits from the start
unsigned long long
bit_window(unsigned long long value,
unsigned int offset,
unsigned int bits)
{
unsigned long long mask = (1ULL << bits) - 1;
value = (value >> offset) & mask;
return value;
}

27
src/misc.h Executable file
View File

@ -0,0 +1,27 @@
/*
* misc.h
*
* Copyright (C) 2014 Marcos Vives Del Sol <socram8888@gmail.com>
*
* 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 3 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/>.
*/
unsigned long long
bit_reverse(unsigned long long value,
unsigned int bits);
unsigned long long
bit_window(unsigned long long value,
unsigned int offset,
unsigned int bits);

68
src/uic_codes.c Executable file
View File

@ -0,0 +1,68 @@
/*
* uic_codes.c
*
* Copyright (C) 2014 Marcos Vives Del Sol <socram8888@gmail.com>
*
* 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 3 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/>.
*/
#include <stdlib.h>
#include <assert.h>
#include "uic_codes.h"
uic_message uic_ground_to_train_messages[] = {
{ 0x00, "Test" },
{ 0x02, "Run slower" },
{ 0x03, "Extension of telegram" },
{ 0x04, "Run faster" },
{ 0x06, "Written order" },
{ 0x08, "Speech" },
{ 0x09, "Emergency stop" },
{ 0x0C, "Announcem. by loudspeaker" },
{ 0x55, "Idle" },
{ -1, NULL }
};
uic_message uic_train_to_ground_messages[] = {
{ 0x08, "Communic. desired" },
{ 0x0A, "Acknowl. of order" },
{ 0x06, "Advice" },
{ 0x00, "Test" },
{ 0x09, "Train staff wish to comm." },
{ 0x0C, "Telephone link desired" },
{ 0x03, "Extension of telegram" },
{ -1, NULL }
};
const char * uic_message_meaning(unsigned int code,
unsigned int type)
{
uic_message * messages;
if (type == UIC_TYPE_GROUNDTRAIN) {
messages = uic_ground_to_train_messages;
} else if (type == UIC_TYPE_TRAINGROUND) {
messages = uic_train_to_ground_messages;
} else {
assert(0);
}
while (messages->code != -1) {
if (messages->code == code) {
return messages->meaning;
}
messages++;
}
return "Unknown";
}

34
src/uic_codes.h Executable file
View File

@ -0,0 +1,34 @@
/*
* uic_codes.h
*
* Copyright (C) 2014 Marcos Vives Del Sol <socram8888@gmail.com>
*
* 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 3 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/>.
*/
typedef struct {
unsigned int code;
char * meaning;
} uic_message;
enum {
UIC_TYPE_GROUNDTRAIN,
UIC_TYPE_TRAINGROUND,
};
extern uic_message uic_ground_to_train_messages[];
extern uic_message uic_train_to_ground_messages[];
const char * uic_message_meaning(unsigned int code,
unsigned int type);