Initial commit of acarsdec. - acarsdec - an ACARS decoder
       
 (DIR) Log
 (DIR) Files
 (DIR) Refs
 (DIR) README
       ---
 (DIR) commit 45bafeee14982a9d10e1e3dd33b08beeb93eee6f
 (HTM) Author: Christoph Lohmann <20h@r-36.net>
       Date:   Wed, 13 Jun 2012 15:05:11 +0200
       
       Initial commit of acarsdec.
       
       Diffstat:
         Makefile                            |      21 +++++++++++++++++++++
         PROTOCOL                            |      30 ++++++++++++++++++++++++++++++
         README                              |      69 ++++++++++++++++++++++++++++++
         README.mod                          |      62 +++++++++++++++++++++++++++++++
         acarsdec.h                          |      36 +++++++++++++++++++++++++++++++
         example/acars.mp3                   |       0 
         example/acars.wav                   |       0 
         getbits.c                           |     192 +++++++++++++++++++++++++++++++
         getmesg.c                           |     218 +++++++++++++++++++++++++++++++
         input.c                             |     206 +++++++++++++++++++++++++++++++
         main.c                              |     235 +++++++++++++++++++++++++++++++
         rc.d/acarsdec.archlinux             |      44 +++++++++++++++++++++++++++++++
         rc.d/acarsdec.conf.d.archlinux      |       3 +++
         serv.c                              |     311 +++++++++++++++++++++++++++++++
         stdinsrv.py                         |     113 +++++++++++++++++++++++++++++++
         version.h                           |       3 +++
       
       16 files changed, 1543 insertions(+), 0 deletions(-)
       ---
 (DIR) diff --git a/Makefile b/Makefile
       @@ -0,0 +1,21 @@
       +
       +INCLUDES=-I.
       +
       +CFLAGS= -g -O2 -Wall $(INCLUDES)
       +
       +OBJS=  getbits.o input.o getmesg.o main.o serv.o
       +
       +acarsdec:        $(OBJS)
       +        $(CC) -o $@ $(OBJS) -lm -lsndfile -lasound
       +
       +main.o:        main.c version.h
       +
       +clean:
       +        rm -f *.o acarsdec
       +
       +getbits.o: acarsdec.h getbits.c
       +getmesg.o: acarsdec.h getmesg.c
       +main.o: acarsdec.h main.c
       +input.o: acarsdec.h input.c
       +serv.o: acarsdec.h serv.c
       +
 (DIR) diff --git a/PROTOCOL b/PROTOCOL
       @@ -0,0 +1,30 @@
       +PROTOCOL FOR -p FLAG
       +
       +Format:
       +
       +msg ::= "MESG\n" + descs + content + "END MESG\n";
       +descs ::= n * desc;
       +desc ::= name + ": " + value + "\n";
       +name ::= UTF-8-String;
       +value ::= UTF-8-String;
       +content ::= "CONTENT: " + UTF-8-String + "\n.\n";
       +
       +The content can be multi-line, so parse for "\n.\n".
       +
       +Example: 
       +
       +---[START]---
       +MESG
       +Mode: G
       +REG: .ZK-OKB
       +LABEL: BA
       +BLKID: 55
       +MSGNO: L34A
       +FLIGHTID: NZ0039
       +CONTENT: /MSTEC7X.DR1.ZK-OKB6A40B74740B55EBD70E7E2
       +.
       +TIMESTAMP: 2010-06-26T11:29:35+00:00
       +END MESG
       +
       +---[END]---
       +
 (DIR) diff --git a/README b/README
       @@ -0,0 +1,69 @@
       +
       +ACARSDEC
       +
       +Acarsdec is an open source, realtime  ACARS demodulator and position decoder for Linux.
       +
       +Aircraft Communication Addressing and Reporting System (or ACARS) is a digital datalink system for transmission of small messages between aircraft and ground stations via VHF radio.
       +
       +HOW DOES IT WORK ?
       +
       +To receive ACARS you need at least an AM VHF air band receiver tuned to one of these frequencies :
       +
       +131.725        Europe primary
       +131.525        European secondary
       +131.550        USA primary
       +130.025        USA secondary
       +131.450 Japan primary
       +(these are the most common, google is your friend for other frequencies)
       +
       +Audio output from this receiver is send to the soundcard input of your PC under Linux.
       +Then, acarsdec will demodulate the signals sent by aircrafts and print the received messages on its standart output in airnav log text format.
       +
       +BUILDING IT
       +On a Linux system, you will need libsnd librairy, alsa audio system and gcc/make installed.
       +Then just type :
       +make
       +
       +USING IT
       +acarsdec could be called with the following options :
       +acarsdec [-LR][-s noport] -d alsapcmdevice | -f sndfile 
       + -f sndfile :           decode from file sndfile (ie: a .wav file)
       + -d alsapcmdevice :     decode from soundcard input alsapcmdevice (ie: hw:0,0)
       + [-LR] :                diseable left or right channel decoding of stereo signal (save cpu)
       + [-s noport ] :         "xastir" mode : act as an APRS local server, on port : noport (see below)
       +
       +Input could be mono or stereo but with 48Khz sampling frequency.
       +If stereo, acarsdec will demod the 2 channels independantly (if no L ou R options specified)
       +
       +Typical usage for realtime decoding is :
       +acarsdec -d hw:0 
       +
       +Be sure that correct record level is set for the used soundcard input.
       +For testing, you could try to record your receiver output at 48khz sampling frequency with any audio recording tool.
       +Save as wav file, then decode it by :
       +acarsdec -f audiofile.wav.
       +
       +
       +USING IT WITH XASTIR
       +acarsdec have a special output mode to use it with APRS position reporting plotting program : xastir (www.xastir.org).
       +In this mode, acarsdec acts as a very basic local aprsd server.
       +ACARS messages, and in particular, position report messages are converted to APRS format, so you can plot aircraft positions on a map.
       +
       +PS: position decoding is in experimental stage. Mail me if you find errors or lack of position reporting.
       +
       +start acarsdec with the following option :
       +acarsdec -d hw:0 -s 14000
       +
       +Then in xastir, choose : Interface->Interface Control->Add
       +Select : Internet Server, then Add
       +Set Host at 127.0.0.1, Port 14000, Don't allow transmitting, then Ok.
       +This will add an interface in the Interface Control dialog.
       +
       +Then select this interface and press start.
       +To check that acarsdec send messages to xastir, select View->Incoming traffic
       +ACARS messages look like that in xastir :
       +F-XXYZ>ACARS:>Fid:AFXXXX Lbl:Q0
       +
       +Lots of ACARS messages are messages without position report, so be patient before seeing aircraft plotted on the map.
       +
       +
 (DIR) diff --git a/README.mod b/README.mod
       @@ -0,0 +1,62 @@
       +INTRODUCTION
       +
       +This acarsdec was modified by
       +        Christoph Lohmann <20h@r-36.net>
       +
       +In addition to this, stdinsrv.py was added, for additionaly functionality.
       +See the examples for how to use these possibilities.
       +
       +
       +INSTALLATION
       +
       + % make
       + % cp acarsdec /usr/bin
       + % cp stdinsrv.py /usr/bin/stdinsrv
       +
       +
       +STARTUP
       +
       +For a daemon mode, using stdinsrv, see the rc.d/* files. For now there
       +are the example files for an Archlinux installation.
       +
       +
       +EXAMPLES
       +
       +Reading from first alsa device, only processing the right stereo channel,
       +outputting to stdout, in a parseable format and multiplexing it to the
       +network on port 5102.
       +
       + % acarsdec -d hw0,0 -p -R | stdinsrv -p 5102 
       +
       +Decoding a recorded ACARS example wav file (48000!) on stdin, to the original
       +acarsdec format:
       +
       + % cat examples/acars.wav | acarsdec -t
       +
       +
       +COMPLEX EXAMPLE
       +
       +Server: ACARS receiver -> sound in
       +Client: We want to hear the ACARS signal and see the decoded message for
       +        a comparison, whether the acarsdec decodes them right. (See the
       +        examples folder for listening to an example ACARS message.) 
       +
       +Client:
       + % socat - TCP-L:5467 | aplay &
       +
       +Server:
       + % mkfifo /tmp/acarsdec
       + % arecord -f dat | tee /tmp/acarsdec | socat - TCP:$ClientIP:5467 &
       + % acarsdec -f /tmp/acarsdec -p | stdinsrv -p 5102
       +
       +Client:
       + % socat - TCP:$ServerIP:5102
       +
       +
       +OTHER FLAGS
       +
       +There is flag -v (verbose), which forces stdout output during the -s mode.
       +The -e flag enables some debugging output, you might find interesting.
       +
       +Have fun!
       +
 (DIR) diff --git a/acarsdec.h b/acarsdec.h
       @@ -0,0 +1,36 @@
       +ttypedef struct {
       +        unsigned char mode;
       +        unsigned char addr[8];
       +        unsigned char ack;
       +        unsigned char label[3];
       +        unsigned char bid;
       +        unsigned char no[5];
       +        unsigned char fid[7];
       +        char txt[256];
       +} msg_t;
       +
       +extern int initsample(char *sourcename, int src);
       +extern int getsample(short *sample, int nb);
       +extern void endsample(void);
       +
       +extern void init_bits(void);
       +extern void resetbits(int ch);
       +extern int getbit(short in, unsigned char *outbits, int ch);
       +
       +extern void init_mesg(void);
       +extern int getmesg(unsigned char r, msg_t * msg, int ch);
       +
       +extern int init_serv(short port);
       +extern int send_mesg(msg_t *msg);
       +extern void end_serv(void);
       +
       +enum {
       +        IN_FILE = 0,
       +        IN_ALSA = 1,
       +        IN_STDIN = 2,
       +        
       +        OUT_NET = 0x01,
       +        OUT_PRINT = 0x02,
       +        OUT_PROTO = 0x04,
       +};
       +
 (DIR) diff --git a/example/acars.mp3 b/example/acars.mp3
       Binary files differ.
 (DIR) diff --git a/example/acars.wav b/example/acars.wav
       Binary files differ.
 (DIR) diff --git a/getbits.c b/getbits.c
       @@ -0,0 +1,192 @@
       +/*
       + *  Copyright (c) 2007 by Thierry Leconte (F4DWV)
       + *
       + *      $Id: getbits.c,v 1.4 2007/04/15 15:06:54 f4dwv Exp $
       + *
       + *   This code is free software; you can redistribute it and/or modify
       + *   it under the terms of the GNU Library General Public License version 2
       + *   published by the Free Software Foundation.
       + *
       + *   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 Library General Public License for more details.
       + *
       + *   You should have received a copy of the GNU Library General Public
       + *   License along with this library; if not, write to the Free Software
       + *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
       + *
       + */
       +
       +#include <stdlib.h>
       +#include <stdio.h>
       +#include <math.h>
       +
       +#include "acarsdec.h"
       +
       +
       +#define Fe 48000.0
       +#define Freqh 4800.0/Fe*2.0*M_PI
       +#define Freql 2400.0/Fe*2.0*M_PI
       +#define BITLEN ((int)Fe/1200)
       +
       +static float h[BITLEN];
       +
       +static struct bstat_s {
       +        float hsample[BITLEN];
       +        float lsample[BITLEN];
       +        float isample[BITLEN];
       +        float qsample[BITLEN];
       +        float csample[BITLEN];
       +        int is;
       +        int clock;
       +        float lin;
       +        float phih,phil;
       +        float dfh,dfl;
       +        float pC,ppC;
       +        int sgI, sgQ;
       +        float ea;
       +} bstat[2];
       +
       +
       +void init_bits(void)
       +{
       +        int i;
       +        for (i = 0; i < BITLEN; i++)
       +                h[i] = sin(2.0 * M_PI * (float) i / (float) BITLEN);
       +
       +        for (i = 0; i < BITLEN; i++) {
       +                bstat[0].hsample[i] = bstat[0].lsample[i] =
       +                    bstat[0].isample[i] = bstat[0].qsample[i] =
       +                    bstat[0].csample[i] = 0.0;
       +                bstat[1].hsample[i] = bstat[1].lsample[i] =
       +                    bstat[1].isample[i] = bstat[1].qsample[i] =
       +                    bstat[1].csample[i] = 0.0;
       +        }
       +        bstat[0].is = bstat[0].clock = bstat[0].sgI = bstat[0].sgQ = 0;
       +        bstat[1].is = bstat[1].clock = bstat[1].sgI = bstat[1].sgQ = 0;
       +        bstat[0].phih = bstat[0].phil = bstat[0].dfh = bstat[0].dfl =
       +            bstat[0].pC = bstat[0].ppC = bstat[0].ea = 0.0;
       +        bstat[1].phih = bstat[1].phil = bstat[1].dfh = bstat[1].dfl =
       +            bstat[1].pC = bstat[1].ppC = bstat[1].ea = 0.0;
       +        bstat[0].lin=bstat[1].lin=1.0;
       +
       +}
       +
       +void resetbits(int ch)
       +{
       +        bstat[ch].sgI = bstat[ch].sgQ = 0;
       +}
       +
       +#define VFOPLL 0.7e-3
       +#define BITPLL 0.2
       +
       +int getbit(short sample, unsigned char *outbits, int ch)
       +{
       +        int i, bt;
       +        float in, in2;
       +        float C;
       +        float I, Q;
       +        float oscl, osch;
       +        struct bstat_s *st;
       +
       +        bt = 0;
       +        st = &bstat[ch];
       +
       +        in = (float) sample;
       +        st->lin = 0.003 * fabs(in) + 0.997 * st->lin;
       +        in /= st->lin;
       +        in2 = in * in;
       +
       +        st->is--;
       +        if (st->is < 0)
       +                st->is = BITLEN - 1;
       +
       +        /* VFOs */
       +        st->phih += Freqh - VFOPLL * st->dfh;
       +        if (st->phih >= 4.0 * M_PI)
       +                st->phih -= 4.0 * M_PI;
       +        st->hsample[st->is] = in2 * sin(st->phih);
       +        for (i = 0, st->dfh = 0.0; i < BITLEN / 2; i++) {
       +                st->dfh += st->hsample[(st->is + i) % BITLEN];
       +        }
       +        osch = cos(st->phih / 2.0);
       +
       +        st->phil += Freql - VFOPLL * st->dfl;
       +        if (st->phil >= 4.0 * M_PI)
       +                st->phil -= 4.0 * M_PI;
       +        st->lsample[st->is] = in2 * sin(st->phil);
       +        for (i = 0, st->dfl = 0.0; i < BITLEN / 2; i++) {
       +                st->dfl += st->lsample[(st->is + i) % BITLEN];
       +        }
       +        oscl = cos(st->phil / 2.0);
       +
       +        /* mix */
       +        st->isample[st->is] = in * (oscl + osch);
       +        st->qsample[st->is] = in * (oscl - osch);
       +        st->csample[st->is] = oscl * osch;
       +
       +
       +        /* bit clock */
       +        st->clock++;
       +        if (st->clock >= BITLEN/4 + st->ea) {
       +                st->clock = 0;
       +
       +                /*  clock filter  */
       +                for (i = 0, C = 0.0; i < BITLEN; i++) {
       +                        C += h[i] * st->csample[(st->is + i) % BITLEN];
       +                }
       +
       +                if (st->pC < C && st->pC < st->ppC) {
       +
       +                        /* integrator */
       +                        for (i = 0, Q = 0.0; i < BITLEN; i++) {
       +                                Q += st->qsample[(st->is + i) % BITLEN];
       +                        }
       +
       +                        if (st->sgQ == 0) {
       +                                if (Q < 0)
       +                                        st->sgQ = -1;
       +                                else
       +                                        st->sgQ = 1;
       +                        }
       +
       +                        *outbits =
       +                            ((*outbits) >> 1) | (unsigned
       +                                                 char) ((Q * st->sgQ >
       +                                                         0) ? 0x80 : 0);
       +                        bt = 1;
       +
       +                        st->ea = -BITPLL * (C - st->ppC);
       +                        if(st->ea > 2.0) st->ea=2.0;
       +                        if(st->ea < -2.0) st->ea=-2.0;
       +                }
       +                if (st->pC > C && st->pC > st->ppC) {
       +
       +                        /* integrator */
       +                        for (i = 0, I = 0.0; i < BITLEN; i++) {
       +                                I += st->isample[(st->is + i) % BITLEN];
       +                        }
       +
       +                        if (st->sgI == 0) {
       +                                if (I < 0)
       +                                        st->sgI = -1;
       +                                else
       +                                        st->sgI = 1;
       +                        }
       +
       +                        *outbits =
       +                            ((*outbits) >> 1) | (unsigned
       +                                                 char) ((I * st->sgI >
       +                                                         0) ? 0x80 : 0);
       +                        bt = 1;
       +
       +                        st->ea = BITPLL * (C - st->ppC);
       +                        if(st->ea > 2.0) st->ea=2.0;
       +                        if(st->ea < -2.0) st->ea=-2.0;
       +                }
       +                st->ppC = st->pC;
       +                st->pC = C;
       +        }
       +        return bt;
       +}
 (DIR) diff --git a/getmesg.c b/getmesg.c
       @@ -0,0 +1,218 @@
       +/*
       + *  Copyright (c) 2007 by Thierry Leconte (F4DWV)
       + *
       + *      $Id: getmesg.c,v 1.3 2007/03/28 06:26:05 f4dwv Exp $
       + *
       + *   This code is free software; you can redistribute it and/or modify
       + *   it under the terms of the GNU Library General Public License version 2
       + *   published by the Free Software Foundation.
       + *
       + *   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 Library General Public License for more details.
       + *
       + *   You should have received a copy of the GNU Library General Public
       + *   License along with this library; if not, write to the Free Software
       + *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
       + *
       + */
       +
       +#include <stdlib.h>
       +#include <stdio.h>
       +#include <string.h>
       +
       +#include "acarsdec.h"
       +
       +#define SYN 0x16
       +#define SOH 0x01
       +struct mstat_s {
       +        enum { HEADL, HEADF, BSYNC1, BSYNC2, SYN1, SYN2, SOH1, TXT, CRC1,
       +                    CRC2, END } state;
       +        int ind;
       +        unsigned short crc;
       +        char txt[243];
       +} mstat[2];
       +
       +
       +/* CCITT 16 CRC */
       +#define POLY 0x1021
       +static void update_crc(unsigned short *crc, unsigned char ch)
       +{
       +        unsigned char v;
       +        unsigned int i;
       +        unsigned short flag;
       +
       +        v = 1;
       +        for (i = 0; i < 8; i++) {
       +                flag = (*crc & 0x8000);
       +                *crc = *crc << 1;
       +
       +                if (ch & v)
       +                        *crc = *crc + 1;
       +
       +                if (flag != 0)
       +                        *crc = *crc ^ POLY;
       +
       +                v = v << 1;
       +        }
       +}
       +
       +static int build_mesg(char *txt, int len, msg_t * msg)
       +{
       +        int i, k;
       +        char r;
       +
       +        /* remove special chars */
       +        for (i = 0; i < len; i++) {
       +                r = txt[i];
       +                if (r < ' ' && r != 0x0d && r != 0x0a)
       +                        r = 0xa4;
       +                txt[i] = r;
       +        }
       +        txt[i] = '\0';
       +
       +        /* fill msg struct */
       +        k = 0;
       +        msg->mode = txt[k];
       +        k++;
       +
       +        for (i = 0; i < 7; i++, k++) {
       +                msg->addr[i] = txt[k];
       +        }
       +        msg->addr[7] = '\0';
       +
       +        /* ACK/NAK */
       +        msg->ack = txt[k];
       +        k++;
       +
       +        msg->label[0] = txt[k];
       +        k++;
       +        msg->label[1] = txt[k];
       +        k++;
       +        msg->label[2] = '\0';
       +
       +        msg->bid = txt[k];
       +        k++;
       +
       +        k++;
       +
       +        for (i = 0; i < 4; i++, k++) {
       +                msg->no[i] = txt[k];
       +        }
       +        msg->no[4] = '\0';
       +
       +        for (i = 0; i < 6; i++, k++) {
       +                msg->fid[i] = txt[k];
       +        }
       +        msg->fid[6] = '\0';
       +
       +        strcpy(msg->txt, &(txt[k]));
       +
       +        return 1;
       +}
       +
       +void init_mesg(void)
       +{
       +        mstat[0].state = mstat[1].state = HEADL;
       +}
       +
       +int getmesg(unsigned char r, msg_t * msg, int ch)
       +{
       +        struct mstat_s *st;
       +
       +        st = &(mstat[ch]);
       +
       +        do {
       +                switch (st->state) {
       +                case HEADL:
       +                        if (r == 0xff) {
       +                                st->state = HEADF;
       +                                return 8;
       +                        }
       +                        resetbits(ch);
       +                        return 8;
       +                        break;
       +                case HEADF:
       +                        if (r != 0xff) {
       +                                int i;
       +                                unsigned char m;
       +
       +                                for (i = 0, m = 1; i < 7; i++, m = m << 1) {
       +                                        if (!(r & m))
       +                                                break;
       +                                }
       +                                if (i < 2) {
       +                                        st->state = HEADL;
       +                                        break;
       +                                }
       +                                st->state = BSYNC1;
       +                                st->ind = 0;
       +                                if (i != 2)
       +                                        return (i - 2);
       +                                break;
       +                        }
       +                        return 6;
       +                case BSYNC1:
       +                        if (r != 0x80 + '+')
       +                                st->ind++;
       +                        st->state = BSYNC2;
       +                        return 8;
       +                case BSYNC2:
       +                        if (r != '*')
       +                                st->ind++;
       +                        st->state = SYN1;
       +                        return 8;
       +                case SYN1:
       +                        if (r != SYN)
       +                                st->ind++;
       +                        st->state = SYN2;
       +                        return 8;
       +                case SYN2:
       +                        if (r != SYN)
       +                                st->ind++;
       +                        st->state = SOH1;
       +                        return 8;
       +                case SOH1:
       +                        if (r != SOH)
       +                                st->ind++;
       +                        if (st->ind > 2) {
       +                                st->state = HEADL;
       +                                break;
       +                        }
       +                        st->state = TXT;
       +                        st->ind = 0;
       +                        st->crc = 0;
       +                        return 8;
       +                case TXT:
       +                        update_crc(&st->crc, r);
       +                        r = r & 0x7f;
       +                        if (r == 0x03 || r == 0x17) {
       +                                st->state = CRC1;
       +                                return 8;
       +                        }
       +                        st->txt[st->ind] = r;
       +                        st->ind++;
       +                        if (st->ind > 243) {
       +                                st->state = HEADL;
       +                                break;
       +                        }
       +                        return 8;
       +                case CRC1:
       +                        update_crc(&st->crc, r);
       +                        st->state = CRC2;
       +                        return 8;
       +                case CRC2:
       +                        update_crc(&st->crc, r);
       +                        st->state = END;
       +                        return 8;
       +                case END:
       +                        st->state = HEADL;
       +                        if (st->crc == 0) {
       +                                build_mesg(st->txt, st->ind, msg);
       +                                return 0;
       +                        }
       +                        return 8;
       +                }
       +        } while (1);
       +}
 (DIR) diff --git a/input.c b/input.c
       @@ -0,0 +1,206 @@
       +/*
       + *  Copyright (c) 2007 by Thierry Leconte (F4DWV)
       + *              (c) 2010 by Christoph Lohmann <20h@r-36.net>
       + *
       + *      $Id: input.c,v 1.3 2007/03/29 16:21:49 f4dwv Exp $
       + *
       + *   This library is free software; you can redistribute it and/or modify
       + *   it under the terms of the GNU Library General Public License version 2
       + *   published by the Free Software Foundation.
       + *
       + *   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 Library General Public License for more details.
       + *
       + *   You should have received a copy of the GNU Library General Public
       + *   License along with this library; if not, write to the Free Software
       + *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
       + *
       + */
       +
       +#include <stdlib.h>
       +#include <sndfile.h>
       +#include <alsa/asoundlib.h>
       +
       +#include "acarsdec.h"
       +
       +static int source = 0;
       +static int nbch = 0;
       +
       +static SNDFILE *inwav;
       +static int initstdin(void)
       +{
       +        SF_INFO infwav;
       +
       +/* open wav input file */
       +        infwav.format = 0;
       +        inwav = sf_open_fd(STDIN_FILENO, SFM_READ, &infwav, SF_TRUE);
       +        if (inwav == NULL) {
       +                fprintf(stderr, "could not open stdin\n");
       +                return (0);
       +        }
       +        if (infwav.samplerate != 48000) {
       +                fprintf(stderr,
       +                        "Bad Input File sample rate: %d. Must be 48000\n",
       +                        infwav.samplerate);
       +                return (0);
       +        }
       +        nbch=infwav.channels;
       +        return (infwav.channels);
       +}
       +
       +static SNDFILE *inwav;
       +static int initsnd(char *filename)
       +{
       +        SF_INFO infwav;
       +
       +/* open wav input file */
       +        infwav.format = 0;
       +        inwav = sf_open(filename, SFM_READ, &infwav);
       +        if (inwav == NULL) {
       +                fprintf(stderr, "could not open %s\n", filename);
       +                return (0);
       +        }
       +        if (infwav.samplerate != 48000) {
       +                fprintf(stderr,
       +                        "Bad Input File sample rate: %d. Must be 48000\n",
       +                        infwav.samplerate);
       +                return (0);
       +        }
       +        nbch=infwav.channels;
       +        return (infwav.channels);
       +}
       +
       +static snd_pcm_t *capture_handle;
       +static int initalsa(char *filename)
       +{
       +        snd_pcm_hw_params_t *hw_params;
       +        int err;
       +
       +        if ((err =
       +             snd_pcm_open(&capture_handle, filename,
       +                          SND_PCM_STREAM_CAPTURE, 0)) < 0) {
       +                fprintf(stderr, "cannot open audio device %s (%s)\n",
       +                        filename, snd_strerror(err));
       +                return 0;
       +        }
       +
       +        if ((err = snd_pcm_hw_params_malloc(&hw_params)) < 0) {
       +                fprintf(stderr,
       +                        "cannot allocate hardware parameter structure (%s)\n",
       +                        snd_strerror(err));
       +                return 0;
       +        }
       +
       +        if ((err = snd_pcm_hw_params_any(capture_handle, hw_params)) < 0) {
       +                fprintf(stderr,
       +                        "cannot initialize hardware parameter structure (%s)\n",
       +                        snd_strerror(err));
       +                return 0;
       +        }
       +
       +        if ((err =
       +             snd_pcm_hw_params_set_access(capture_handle, hw_params,
       +                                          SND_PCM_ACCESS_RW_INTERLEAVED)) <
       +            0) {
       +                fprintf(stderr, "cannot set access type (%s)\n",
       +                        snd_strerror(err));
       +                return 0;
       +        }
       +
       +        if ((err =
       +             snd_pcm_hw_params_set_format(capture_handle, hw_params,
       +                                          SND_PCM_FORMAT_S16)) < 0) {
       +                fprintf(stderr, "cannot set sample format (%s)\n",
       +                        snd_strerror(err));
       +                return 0;
       +        }
       +
       +        if ((err =
       +             snd_pcm_hw_params_set_rate(capture_handle, hw_params, 48000,
       +                                        0)) < 0) {
       +                fprintf(stderr, "cannot set sample rate (%s)\n",
       +                        snd_strerror(err));
       +                return 0;
       +        }
       +
       +        for(nbch=2;nbch>0;nbch--)  {
       +                if (snd_pcm_hw_params_set_channels(capture_handle, hw_params, nbch)==0)        
       +                        break;
       +        }
       +
       +        if (nbch ==0) {
       +                fprintf(stderr, "cannot set number of channels\n");
       +                return 0;
       +        }
       +
       +        if ((err = snd_pcm_hw_params(capture_handle, hw_params)) < 0) {
       +                fprintf(stderr, "cannot set parameters (%s)\n",
       +                        snd_strerror(err));
       +                return 0;
       +        }
       +        snd_pcm_hw_params_free(hw_params);
       +
       +        if ((err = snd_pcm_prepare(capture_handle)) < 0) {
       +                fprintf(stderr,
       +                        "cannot prepare audio interface for use (%s)\n",
       +                        snd_strerror(err));
       +                return 0;
       +        }
       +        return nbch;
       +}
       +
       +/* open input source*/
       +int initsample(char *sourcename, int src)
       +{
       +        source = src;
       +        switch(src) {
       +        case IN_STDIN:
       +                return initstdin();
       +        case IN_FILE:
       +                return initsnd(sourcename);
       +        case IN_ALSA:
       +                return initalsa(sourcename);
       +        }
       +
       +        return 0;
       +}
       +
       +int getsample(short *sample, int nb)
       +{
       +        int r = -1;
       +
       +        switch(source) {
       +        case IN_STDIN:
       +                r = sf_read_short(inwav, sample, nb);
       +                break;
       +        case IN_FILE:
       +                r = sf_read_short(inwav, sample, nb);
       +                if (r == 0)
       +                        r = -1;        /* this is the end */
       +                break;
       +        case IN_ALSA:
       +                r = snd_pcm_readi(capture_handle, sample, nb/nbch);
       +                if (r <= 0)
       +                        fprintf(stderr,
       +                                "cannot read from interface (%s)\n",
       +                                snd_strerror(r));
       +                r=r*nbch;
       +                break;
       +        }
       +        return r;
       +}
       +
       +void endsample(void)
       +{
       +        switch(source) {
       +        case IN_FILE:
       +        case IN_STDIN:
       +                sf_close(inwav);
       +                break;
       +        case IN_ALSA:
       +                snd_pcm_close(capture_handle);
       +                break;
       +        }
       +}
 (DIR) diff --git a/main.c b/main.c
       @@ -0,0 +1,235 @@
       +/*
       + *  Copyright (c) 2007 by Thierry Leconte (F4DWV)
       + *            (c) 2010 by Christoph Lohmann <20h@r-36.net>
       + *
       + *      $Id: main.c,v 1.5 2007/04/22 16:14:41 f4dwv Exp $
       + *
       + *   This code is free software; you can redistribute it and/or modify
       + *   it under the terms of the GNU Library General Public License version 2
       + *   published by the Free Software Foundation.
       + *
       + *   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 Library General Public License for more details.
       + *
       + *   You should have received a copy of the GNU Library General Public
       + *   License along with this library; if not, write to the Free Software
       + *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
       + *
       + */
       +
       +#include <stdio.h>
       +#include <stdlib.h>
       +#include <unistd.h>
       +#include <string.h>
       +#include <time.h>
       +
       +#include "version.h"
       +#include "acarsdec.h"
       +
       +extern int optind, opterr;
       +extern char *optarg;
       +
       +static void usage(void)
       +{
       +        fprintf(stderr, "%s\n", version);
       +        fprintf(stderr, "Usage: acarsdec [-vep][-LR][-s noport] -d "
       +                        "alsapcmdevice | -f sndfile | -t\n");
       +        fprintf(stderr, " -f sndfile :\t\tdecode from file sndfile "
       +                        "(ie: a .wav file)\n");
       +        fprintf(stderr, " -d alsapcmdevice :\tdecode from soundcard "
       +                        "input alsapcmdevice (ie: hw:0,0)\n");
       +        fprintf(stderr, " -t :\t\t\tread from stdin.\n");
       +        fprintf(stderr, " [-v] :\t\t\tbe verbose.\n");
       +        fprintf(stderr, " [-p] :\t\t\toutput should be parseable protocol.\n");
       +        fprintf(stderr, " [-e] :\t\t\tdo debug?\n");
       +        fprintf(stderr, " [-LR] :\t\tdisable left or right channel "
       +                        "decoding of stereo signal\n");
       +        fprintf(stderr, " [-s noport ] :\t\tact as an APRS local server, "
       +                        "on port : noport\n");
       +        fprintf(stderr, "Input could be mono or stereo but with 48Khz "
       +                        "sampling frequency.\nIf stereo, acarsdec will "
       +                        "demod the 2 channels independantly (if no L ou "
       +                        "R options specified)\n\n");
       +        exit(1);
       +}
       +
       +void print_mesg(msg_t * msg)
       +{
       +        time_t t;
       +        struct tm *tmp;
       +        char pos[128];
       +
       +        printf("ACARS mode: %c", msg->mode);
       +        printf(" Aircraft reg: %s\n", msg->addr);
       +        printf("Message label: %s", msg->label);
       +        printf(" Block id: %d", (int) msg->bid);
       +        printf(" Msg. no: %s\n", msg->no);
       +        printf("Flight id: %s\n", msg->fid);
       +        printf("Message content:-\n%s", msg->txt);
       +
       +        if (posconv(msg->txt, msg->label, pos)==0)
       +                printf("\nAPRS : Addr:%s Fid:%s Lbl:%s pos:%s\n", msg->addr, 
       +                        msg->fid,msg->label,pos);
       + 
       +        t = time(NULL);
       +        tmp = gmtime(&t);
       +        printf("\n--------------------------------------------"
       +                        "--------------[%02d/%02d/%04d %02d:%02d]\n\n",
       +             tmp->tm_mday, tmp->tm_mon + 1, tmp->tm_year + 1900,
       +             tmp->tm_hour, tmp->tm_min);
       +        fflush(stdout);
       +
       +}
       +
       +void print_proto(msg_t * msg)
       +{
       +        time_t t;
       +        struct tm *tmp;
       +        char pos[128];
       +        char timestamp[128];
       +
       +        printf("MESG\n");
       +        printf("Mode: %c\n", msg->mode);
       +        printf("REG: %s\n", msg->addr);
       +        printf("LABEL: %s\n", msg->label);
       +        printf("BLKID: %d\n", (int) msg->bid);
       +        printf("MSGNO: %s\n", msg->no);
       +        printf("FLIGHTID: %s\n", msg->fid);
       +        printf("CONTENT: %s\n.\n", msg->txt);
       +            if (posconv(msg->txt, msg->label, pos)==0) {
       +                printf("APRS-ADDR: %s\n", msg->addr);
       +                printf("APRS-FID: %s\n", msg->fid);
       +                printf("APRS-LABEL: %s\n", msg->label);
       +                printf("APRS-POS: %s\n", pos);
       +        }
       +        t = time(NULL);
       +        tmp = gmtime(&t);
       +        strftime(timestamp, sizeof(timestamp) - 1,
       +                "%FT%T+00:00", tmp);
       +        printf("TIMESTAMP: %s\n", timestamp);
       +        printf("END MESG\n\n");
       +        fflush(stdout);
       +}
       +
       +void do_output(int type, msg_t *msg)
       +{
       +
       +        if(type & OUT_NET)
       +                send_mesg(msg);
       +        if(type & OUT_PRINT)
       +                print_mesg(msg);
       +        if(type & OUT_PROTO)
       +                print_proto(msg);
       +}
       +
       +int main(int argc, char **argv)
       +{
       +        int c;
       +        unsigned char r[2];
       +        msg_t msg[2];
       +        int nbit[2] = {0, 0};
       +        int nrbit[2] = {8, 8};
       +        int nbch=0;
       +        int esel[2] = {1, 1};
       +        short port=0;
       +        int debug=0;
       +        int output = 0;
       +        int i;
       +
       +        while ((c = getopt(argc, argv, "ptevd:f:RLs:")) != EOF) {
       +                switch (c) {
       +                case 'd':
       +                        nbch = initsample(optarg, IN_ALSA);
       +                        break;
       +                case 'f':
       +                        nbch = initsample(optarg, IN_FILE);
       +                        break;
       +                case 't':
       +                        nbch = initsample("stdin", IN_STDIN);
       +                        break;
       +                case 'L':
       +                        esel[0] = 0;
       +                        break;
       +                case 'R':
       +                        esel[1] = 0;
       +                        break;
       +                case 's':
       +                        port=atoi(optarg);
       +                        output |= OUT_NET;
       +                        break;
       +                case 'v':
       +                        output |= OUT_PRINT;
       +                        break;
       +                case 'p':
       +                        output |= OUT_PROTO;
       +                        break;
       +                case 'e':
       +                        debug++;
       +                        break;
       +                default:
       +                        usage();
       +                        exit(1);
       +                }
       +        }
       +
       +        if (output == 0)
       +                output = OUT_PRINT;
       +
       +        if (nbch == 0) {
       +                usage();
       +                exit(1);
       +        }
       +
       +        if (port) { 
       +                if (init_serv(port))
       +                        exit(1);
       +                 if (debug)
       +                        fprintf(stderr, "Server initialized.\n");
       +        }
       +                
       +/* main loop */
       +        init_bits();
       +        init_mesg();
       +
       +        if(debug)
       +                fprintf(stderr, "Starting receive loop.\n");
       +        do {
       +                short sample[4096];
       +                int ind, len;
       +
       +                len = getsample(sample, 4096);
       +                if (debug)
       +                        fprintf(stderr, "Got sample: %d\n", len);
       +                if (len < 0)
       +                        break;
       +
       +                for (ind = 0; ind < len;) {
       +                        for (i = 0; i < nbch; i++,ind++) {
       +                                if (esel[i]) {
       +                                        nbit[i] += getbit(sample[ind], &r[i],
       +                                                        0);
       +                                        if (nbit[i] >= nrbit[i]) {
       +                                                nrbit[i] = getmesg(r[i],
       +                                                               &msg[i], 0);
       +                                                nbit[i] = 0;
       +                                                if (nrbit[i] == 0) {
       +                                                        do_output(output,
       +                                                                &msg[i]);
       +                                                        nrbit[i] = 8;
       +                                                }
       +                                        }
       +                                }
       +                        }
       +                }
       +        } while (1);
       +
       +
       +        if(port)
       +                end_serv();
       +
       +        endsample();
       +
       +        exit(0);
       +}
 (DIR) diff --git a/rc.d/acarsdec.archlinux b/rc.d/acarsdec.archlinux
       @@ -0,0 +1,44 @@
       +#!/bin/bash
       +
       +CONF=/etc/conf.d/acarsdec
       +
       +. /etc/rc.conf
       +. /etc/rc.d/functions
       +
       +t[ -f $CONF ] && . $CONF
       +
       +ACARSDECBIN=/usr/bin/acarsdec
       +STDINSRV=/usr/bin/stdinsrv
       +APID=`pidof -x $ACARSDECBIN`
       +case "$1" in
       +  force)
       +    stat_busy "Killing acarsdec by force."
       +    kill $APID &> /dev/null
       +    stat_done
       +    ;;
       +  start)
       +    stat_busy "Starting acarsdec server"
       +    [ -z "$APID" ] && $ACARSDECBIN $ACARSDECPARAMS \
       +            | $STDINSRV $STDINSRVPARAMS 2>&1 >> /dev/null &
       +    if [ $? -gt 0 ]; then
       +      stat_fail
       +    else
       +      add_daemon acarsdec 
       +      stat_done
       +    fi
       +    ;;
       +  stop)
       +    stat_busy "Stopping acarsdec"
       +    [ ! -z "$APID" ]  && kill $APID &>/dev/null
       +    rm_daemon acarsdec 
       +    stat_done
       +    ;;
       +  restart)
       +    $0 stop
       +    $0 start
       +    ;;
       +  *)
       +    echo "usage: $0 {start|stop|restart}"  
       +esac
       +exit 0
       +
 (DIR) diff --git a/rc.d/acarsdec.conf.d.archlinux b/rc.d/acarsdec.conf.d.archlinux
       @@ -0,0 +1,3 @@
       +ACARSDECPARAMS="-d hw:0,0 -p -R"
       +STDINSRVPARAMS="-p 5102"
       +
 (DIR) diff --git a/serv.c b/serv.c
       @@ -0,0 +1,311 @@
       +/*
       + *  Copyright (c) 2007 by Thierry Leconte (F4DWV)
       + *            (c) 2010 by Christoph Lohmann <20h@r-36.net>
       + *
       + *      $Id: serv.c,v 1.2 2007/04/22 16:14:41 f4dwv Exp $
       + *
       + *   This code is free software; you can redistribute it and/or modify
       + *   it under the terms of the GNU Library General Public License version 2
       + *   published by the Free Software Foundation.
       + *
       + *   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 Library General Public License for more details.
       + *
       + *   You should have received a copy of the GNU Library General Public
       + *   License along with this library; if not, write to the Free Software
       + *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
       + *
       + */
       +
       +#include <stdlib.h>
       +#include <unistd.h>
       +#include <stdio.h>
       +#include <string.h>
       +#include <sys/types.h>
       +#include <sys/socket.h>
       +#include <netinet/in.h>
       +#include <errno.h>
       +
       +#include "acarsdec.h"
       +
       +static int sa, sc;
       +
       +int init_serv(short port)
       +{
       +    struct sockaddr_in locaddr, remaddr;
       +    socklen_t len;
       +    char c;
       +    int res;
       +
       +    sa = socket(PF_INET, SOCK_STREAM, 0);
       +    if (sa < 0) {
       +        fprintf(stderr, "socket : %s\n", strerror(errno));
       +        return -1;
       +    }
       +
       +    res = 1;
       +    res = setsockopt(sa, SOL_SOCKET, SO_REUSEADDR, &res, sizeof(res));
       +    if (res) {
       +            fprintf(stderr, "reuseaddr : %s\n", strerror(errno));
       +            return -1;
       +    }
       +
       +    memset(&locaddr, 0, sizeof(locaddr));
       +    locaddr.sin_family = AF_INET;
       +    locaddr.sin_port = htons(port);
       +    locaddr.sin_addr.s_addr = htonl(INADDR_ANY);
       +
       +    len = sizeof(locaddr);
       +    res = bind(sa, (struct sockaddr *) &locaddr, len);
       +    if (res) {
       +        fprintf(stderr, "bind : %s\n", strerror(errno));
       +        return -1;
       +    }
       +
       +    res = listen(sa, 1);
       +    if (res) {
       +        fprintf(stderr, "listen : %s\n", strerror(errno));
       +        return -1;
       +    }
       +
       +    memset(&remaddr, 0, sizeof(remaddr));
       +    len = sizeof(remaddr);
       +    sc = accept(sa, (struct sockaddr *) &remaddr, &len);
       +    if (sc < 0) {
       +        fprintf(stderr, "accept : %s\n", strerror(errno));
       +        return -1;
       +    }
       +
       +    do {
       +        res = read(sc, &c, 1);
       +    } while (res == 1 && c != '\n');
       +
       +
       +    return 0;
       +}
       +
       +
       +/* convert ACARS position reports to APRS position */
       +static void toaprs(int la, char lac, int ln, char lnc, int prec, char *out)
       +{
       +    int lad, lnd;
       +    float lam, lnm;
       +
       +    lad = la / 10000;
       +    lnd = ln / 10000;
       +    lam = (float) (la - (lad * 10000)) * 60.0 / 10000.0;
       +    lnm = (float) (ln - (lnd * 10000)) * 60.0 / 10000.0;
       +
       +    switch (prec) {
       +        case 0:
       +                    sprintf(out, "%02d%02.0f.  %c/%03d%02.0f.  %c^", lad, lam, lac, lnd, lnm, lnc);
       +                break;
       +        case 1:
       +                    sprintf(out, "%02d%04.1f %c/%03d%04.1f %c^", lad, lam, lac, lnd, lnm, lnc);
       +                break;
       +        case 2:
       +        default:
       +                    sprintf(out, "%02d%05.2f%c/%03d%05.2f%c^", lad, lam, lac, lnd, lnm, lnc);
       +                break;
       +    }
       +}
       +
       +int posconv(char *txt, unsigned char *label, char *pos)
       +{
       +    char lac, lnc;
       +    int la, ln;
       +    char las[7], lns[7];
       +    int n;
       +    char *p;
       +
       +/*try different heuristics */
       +
       +    n = sscanf(txt, "#M1BPOS%c%05d%c%063d,", &lac, &la, &lnc, &ln);
       +    if (n == 4 && (lac == 'N' || lac == 'S') && (lnc == 'E' || lnc == 'W')) {
       +        la *= 10;
       +        ln *= 10;
       +        toaprs(la, lac, ln, lnc, 1, pos);
       +        return 0;;
       +    }
       +    n = sscanf(txt, "#M1AAEP%c%06d%c%07d", &lac, &la, &lnc, &ln);
       +    if (n == 4 && (lac == 'N' || lac == 'S') && (lnc == 'E' || lnc == 'W')) {
       +        toaprs(la, lac, ln, lnc, 2, pos);
       +        return 0;;
       +    }
       +
       +    if (strncmp(txt, "#M1B", 4) == 0) {
       +        if ((p = strstr(txt, "/FPO")) != NULL) {
       +            n = sscanf(p, "/FPO%c%05d%c%06d", &lac, &la, &lnc, &ln);
       +            if (n == 4 && (lac == 'N' || lac == 'S')
       +                && (lnc == 'E' || lnc == 'W')) {
       +                la *= 10;
       +                ln *= 10;
       +                toaprs(la, lac, ln, lnc, 1, pos);
       +                return 0;;
       +            }
       +        }
       +        if ((p = strstr(txt, "/PS")) != NULL) {
       +            n = sscanf(p, "/PS%c%05d%c%06d", &lac, &la, &lnc, &ln);
       +            if (n == 4 && (lac == 'N' || lac == 'S')
       +                && (lnc == 'E' || lnc == 'W')) {
       +                la *= 10;
       +                ln *= 10;
       +                toaprs(la, lac, ln, lnc, 1, pos);
       +                return 0;;
       +            }
       +        }
       +    }
       +
       +    n = sscanf(txt, "FST01%*8s%c%06d%c%07d", &lac, &la, &lnc, &ln);
       +    if (n == 4 && (lac == 'N' || lac == 'S') && (lnc == 'E' || lnc == 'W')) {
       +        toaprs(la, lac, ln, lnc, 2, pos);
       +        return 0;;
       +    }
       +
       +    n = sscanf(txt, "(2%c%5c%c%6c", &lac, las, &lnc, lns);
       +    if (n == 4 && (lac == 'N' || lac == 'S') && (lnc == 'E' || lnc == 'W')) {
       +        las[5] = 0;
       +        lns[6] = 0;
       +        la = 10 * atoi(las);
       +        ln = 10 * atoi(lns);
       +        toaprs(la, lac, ln, lnc, 1, pos);
       +        return 0;;
       +    }
       +
       +    n = sscanf(txt, "(:2%c%5c%c%6c", &lac, las, &lnc, lns);
       +    if (n == 4 && (lac == 'N' || lac == 'S') && (lnc == 'E' || lnc == 'W')) {
       +        las[5] = 0;
       +        lns[6] = 0;
       +        la = 10 * atoi(las);
       +        ln = 10 * atoi(lns);
       +        toaprs(la, lac, ln, lnc, 1, pos);
       +        return 0;;
       +    }
       +
       +
       +    n = sscanf(txt, "(2%*4s%c%5c%c%6c", &lac, las, &lnc, lns);
       +    if (n == 4 && (lac == 'N' || lac == 'S') && (lnc == 'E' || lnc == 'W')) {
       +        las[5] = 0;
       +        lns[6] = 0;
       +        la = 10 * atoi(las);
       +        ln = 10 * atoi(lns);
       +        toaprs(la, lac, ln, lnc, 1, pos);
       +        return 0;;
       +    }
       +
       +    n = sscanf(txt, "LAT %c%3c.%3c/LON %c%3c.%3c", &lac, las, &(las[3]),
       +               &lnc, lns, &(lns[3]));
       +    if (n == 6 && (lac == 'N' || lac == 'S') && (lnc == 'E' || lnc == 'W')) {
       +        las[6] = 0;
       +        lns[6] = 0;
       +        la = 10 * atoi(las);
       +        ln = 10 * atoi(lns);
       +        toaprs(la, lac, ln, lnc, 1, pos);
       +        return 0;;
       +    }
       +
       +
       +    n = sscanf(txt, "#DFB(POS-%*6s-%04d%c%05d%c/", &la, &lac, &ln, &lnc);
       +    if (n == 4 && (lac == 'N' || lac == 'S') && (lnc == 'E' || lnc == 'W')) {
       +        la *= 100;
       +        ln *= 100;
       +        toaprs(la, lac, ln, lnc, 0, pos);
       +        return 0;;
       +    }
       +
       +    n = sscanf(txt, "#DFB*POS\a%*8s%c%04d%c%05d/", &lac, &la, &lnc, &ln);
       +    if (n == 4 && (lac == 'N' || lac == 'S') && (lnc == 'E' || lnc == 'W')) {
       +        la *= 100;
       +        ln *= 100;
       +        toaprs(la, lac, ln, lnc, 0, pos);
       +        return 0;;
       +    }
       +
       +    n = sscanf(txt, "POS%c%05d%c%06d,", &lac, &la, &lnc, &ln);
       +    if (n == 4 && (lac == 'N' || lac == 'S') && (lnc == 'E' || lnc == 'W')) {
       +        la *= 10;
       +        ln *= 10;
       +        toaprs(la, lac, ln, lnc, 1, pos);
       +        return 0;;
       +    }
       +
       +    n = sscanf(txt, "POS%*2s,%c%05d%c%06d,", &lac, &la, &lnc, &ln);
       +    if (n == 4 && (lac == 'N' || lac == 'S') && (lnc == 'E' || lnc == 'W')) {
       +        la *= 10;
       +        ln *= 10;
       +        toaprs(la, lac, ln, lnc, 1, pos);
       +        return 0;;
       +    }
       +
       +    n = sscanf(txt, "RCL%*2s,%c%05d%c%06d,", &lac, &la, &lnc, &ln);
       +    if (n == 4 && (lac == 'N' || lac == 'S') && (lnc == 'E' || lnc == 'W')) {
       +        la *= 10;
       +        ln *= 10;
       +        toaprs(la, lac, ln, lnc, 1, pos);
       +        return 0;;
       +    }
       +
       +    n = sscanf(txt, "TWX%*2s,%c%05d%c%06d,", &lac, &la, &lnc, &ln);
       +    if (n == 4 && (lac == 'N' || lac == 'S') && (lnc == 'E' || lnc == 'W')) {
       +        la *= 10;
       +        ln *= 10;
       +        toaprs(la, lac, ln, lnc, 1, pos);
       +        return 0;;
       +    }
       +
       +    n = sscanf(txt, "CLA%*2s,%c%05d%c%06d,", &lac, &la, &lnc, &ln);
       +    if (n == 4 && (lac == 'N' || lac == 'S') && (lnc == 'E' || lnc == 'W')) {
       +        la *= 10;
       +        ln *= 10;
       +        toaprs(la, lac, ln, lnc, 1, pos);
       +        return 0;;
       +    }
       +
       +    n = sscanf(txt, "%c%05d/%c%06d,", &lac, &la, &lnc, &ln);
       +    if (n == 4 && (lac == 'N' || lac == 'S') && (lnc == 'E' || lnc == 'W')) {
       +        la *= 10;
       +        ln *= 10;
       +        toaprs(la, lac, ln, lnc, 1, pos);
       +        return 0;;
       +    }
       +
       +    return 1;
       +}
       +
       +int send_mesg(msg_t * msg)
       +{
       +    char apstr[512];
       +    char txt[512];
       +    char pos[64];
       +    unsigned char *ind;
       +
       +   if(msg->label[0]=='_' && msg->label[1]==0x7f)
       +        return 0;
       +
       +    strcpy(txt,msg->txt);
       +    for(ind = (unsigned char *)&txt; *ind != 0 ;ind++) {
       +        if(*ind==0x0a || *ind == 0x0d) *ind=' ';
       +     }
       +
       +    ind = msg->addr;
       +    while (*ind == '.' && *ind != 0)
       +        ind++;
       +
       +    if (posconv(msg->txt, msg->label, pos))
       +        sprintf(apstr, "%s>ACARS:>Fid:%s Lbl:%s %s\n", ind, msg->fid,msg->label,txt);
       +    else
       +        sprintf(apstr, "%s>ACARS:!%sFid:%s Lbl:%s %s\n", ind, pos,msg->fid,msg->label,txt);
       +
       +    write(sc, apstr, strlen(apstr));
       +
       +    return 0;
       +}
       +
       +
       +void end_serv(void)
       +{
       +    close(sc);
       +    close(sa);
       +}
 (DIR) diff --git a/stdinsrv.py b/stdinsrv.py
       @@ -0,0 +1,113 @@
       +#!/usr/bin/env python
       +# coding=utf-8
       +#
       +# Copy me if you can.
       +# by Christoph Lohmann <20h@r-36.net> 
       +#
       +
       +import sys
       +from socket import socket, AF_INET, SOCK_STREAM, SO_REUSEADDR, SOL_SOCKET
       +from select import poll, POLLIN, POLLPRI, POLLERR, POLLHUP
       +from fcntl import fcntl, F_GETFL, F_SETFL
       +from os import O_NONBLOCK
       +import errno
       +import time
       +from getopt import getopt, GetoptError
       +
       +def dbg(msg):
       +        sys.stderr.write("%s\n" % (msg))
       +
       +def usage(app):
       +        sys.stderr.write("usage: %s [-d] [-p port] [-h bind host]\n" % (app))
       +        sys.exit(1)
       +
       +def main(args):
       +        try:
       +                opts, args = getopt(args[1:], "dp:h:")
       +        except GetoptError, err:
       +                sys.stderr.write("%s\n" % (str(err)))
       +                usage(args[0])
       +
       +        debug = False
       +        host = ""
       +        port = 6789
       +        for o, a in opts:
       +                if o == "-p":
       +                        port = int(a)
       +                elif o == "-d":
       +                        debug = True
       +                elif o == "-h":
       +                        host = a
       +                else:
       +                        assert False, "unhandled option"
       +
       +        sock = socket(AF_INET, SOCK_STREAM)
       +        sock.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1)
       +        sock.bind((host, port))
       +        sock.listen(5)
       +
       +        fl = fcntl(sys.stdin, F_GETFL)
       +        fcntl(sys.stdin, F_SETFL, fl | O_NONBLOCK)
       +
       +        clients = []
       +        def getcli(fd):
       +                for i in clients:
       +                        if i.fileno() == fd:
       +                                return i
       +
       +        def broadcastcli(data):
       +                if debug == True:
       +                        dbg("Broadcast")
       +                for i in clients:
       +                        try:
       +                                i.send(data)
       +                                i.flush(data)
       +                        except:
       +                                next
       +
       +        def closecli(fd):
       +                if debug == True:
       +                        dbg("Close: %d" % (fd))
       +                cli = getcli(i[0])
       +                clients.remove(cli)
       +                po.unregister(cli)
       +                cli.close()
       +
       +        po = poll()
       +        po.register(sys.stdin, POLLIN|POLLPRI|POLLERR|POLLHUP)
       +        po.register(sock, POLLIN|POLLPRI)
       +        while 1:
       +                events = po.poll(30)
       +                for i in events:
       +                        if i[0] == sock.fileno():
       +                                cli = sock.accept()[0]
       +                                cli.setblocking(0)
       +                                clients.append(cli)
       +                                po.register(cli, POLLIN|POLLPRI)
       +                                if debug == True:
       +                                        dbg("Accept: %d" % (cli.fileno()))
       +                        elif i[1] in (POLLERR, POLLHUP):
       +                                if debug == True:
       +                                        dbg("err or hup: %d" % (i[0]))
       +                                if i[0] == sys.stdin.fileno():
       +                                        return 1
       +                                cli = getcli(i[0])
       +                                clients.remove(cli)
       +                                po.unregister(cli)
       +                                cli.close()
       +                        elif i[1] in (POLLIN, POLLPRI):
       +                                if i[0] == sys.stdin.fileno():
       +                                        if debug == True:
       +                                                dbg("Input on stdin.")
       +                                        broadcastcli(sys.stdin.read(4096))
       +                                else:
       +                                        if debug == True:
       +                                                dbg("Input from client: %d" % (i[0]))
       +                                        cli = getcli(i[0])
       +                                        a = cli.recv(4096)
       +                                        if len(a) == 0:
       +                                                closecli(i[0])
       +
       +if __name__ == "__main__":
       +        sys.exit(main(sys.argv))
       +
 (DIR) diff --git a/version.h b/version.h
       @@ -0,0 +1,3 @@
       +const char version[] = "Acarsdec 1.2  (c) 2007 Thierry Leconte F4DWV\n"
       +                "              (c) 2010 Christoph Lohmann <20h@r-36.net>\n";
       +