Add UIC-751-3 decoding and optional MSB-first TX/RX

[ kamal: cleanup ]
This commit is contained in:
Marcos Vives Del Sol 2014-08-15 23:29:27 +02:00 committed by Kamal Mostafa
parent ff0346f5a8
commit 25d01f73d8
7 changed files with 268 additions and 16 deletions

View File

@ -42,12 +42,15 @@ 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)
minimodem_LDADD = $(DEPS_LIBS)
minimodem_SOURCES = minimodem.c $(DATABITS_SRC) $(FSK_SRC) $(SIMPLEAUDIO_SRC)

View File

@ -111,15 +111,16 @@ 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_minimodem_OBJECTS = minimodem.$(OBJEXT) $(am__objects_3) \
$(am__objects_4) $(am__objects_5)
minimodem_OBJECTS = $(am_minimodem_OBJECTS)
am__DEPENDENCIES_1 =
minimodem_DEPENDENCIES = $(am__DEPENDENCIES_1)
@ -314,12 +315,14 @@ 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)
minimodem_LDADD = $(DEPS_LIBS)
minimodem_SOURCES = minimodem.c $(DATABITS_SRC) $(FSK_SRC) $(SIMPLEAUDIO_SRC)
@ -417,6 +420,7 @@ 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)/simple-tone-generator.Po@am__quote@
@ -425,6 +429,7 @@ distclean-compile:
@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@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<

View File

@ -17,6 +17,32 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
// Reverses the ordering of the bits on an integer
static inline 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
static inline 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;
}
typedef int (databits_encoder)(
unsigned int *databits_outp, char char_out );
@ -55,4 +81,10 @@ unsigned int
databits_decode_callerid( char *dataout_p, unsigned int dataout_size,
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 );

74
src/databits_uic.c Executable file
View File

@ -0,0 +1,74 @@
/*
* 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"
/*
* 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

@ -81,7 +81,8 @@ static void fsk_transmit_frame(
float bfsk_mark_f,
float bfsk_space_f,
float bfsk_nstartbits,
float bfsk_nstopbits
float bfsk_nstopbits,
int bfsk_msb_first
)
{
int i;
@ -89,7 +90,13 @@ static void fsk_transmit_frame(
simpleaudio_tone(sa_out, 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);
}
@ -107,6 +114,7 @@ static void fsk_transmit_stdin(
int n_data_bits,
float bfsk_nstartbits,
float bfsk_nstopbits,
int bfsk_msb_first,
unsigned int bfsk_do_tx_sync_bytes,
unsigned int bfsk_sync_byte,
databits_encoder encode
@ -156,14 +164,14 @@ static void fsk_transmit_stdin(
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, 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, bfsk_msb_first);
if ( tx_interactive )
setitimer(ITIMER_REAL, &itv, NULL);
@ -356,6 +364,8 @@ 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"
" uic-train UIC-751-3 Train-to-ground 600 bps\n"
" uic-ground UIC-751-3 Ground-to-train 600 bps\n"
);
exit(1);
}
@ -424,6 +434,7 @@ main( int argc, char*argv[] )
unsigned int bfsk_do_tx_sync_bytes = 0;
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;
@ -488,6 +499,7 @@ 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,
@ -517,6 +529,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' },
@ -582,6 +595,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 );
@ -728,6 +744,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 )
@ -835,6 +869,7 @@ main( int argc, char*argv[] )
bfsk_n_data_bits,
bfsk_nstartbits,
bfsk_nstopbits,
bfsk_msb_first,
bfsk_do_tx_sync_bytes,
bfsk_sync_byte,
bfsk_databits_encode
@ -1257,10 +1292,11 @@ main( int argc, char*argv[] )
*/
// chop off framing bits
unsigned int frame_bits_shift = bfsk_nstartbits;
unsigned long long frame_bits_mask = (long long)(1ULL<<bfsk_n_data_bits) - 1;
debug_log("Input: %08x%08x - Databits: %i - Shift: %i - Mask: %08x\n", (unsigned int)(bits >> 32), (unsigned int)bits, bfsk_n_data_bits, bfsk_nstartbits, (unsigned int)(frame_bits_mask >> 32), (unsigned int)(frame_bits_mask));
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);
}
debug_log("Input: %08x%08x - Databits: %i - Shift: %i\n", (unsigned int)(bits >> 32), (unsigned int)bits, bfsk_n_data_bits, bfsk_nstartbits);
unsigned int dataout_size = 4096;
char dataoutbuf[4096];

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);