commit 8223d9e9c8f668503d0f1e8ad01cb74be58b423a Author: Tomas Suchan Date: Wed Jul 18 01:20:23 2012 +0200 Initial commit - acarsdec-1.1, upstream vanilla version diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..208ff0e --- /dev/null +++ b/Makefile @@ -0,0 +1,20 @@ + +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 diff --git a/README b/README new file mode 100644 index 0000000..5ab44de --- /dev/null +++ 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. + + diff --git a/acarsdec.h b/acarsdec.h new file mode 100644 index 0000000..d33f9b2 --- /dev/null +++ b/acarsdec.h @@ -0,0 +1,26 @@ +typedef 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); + diff --git a/getbits.c b/getbits.c new file mode 100644 index 0000000..75ea75b --- /dev/null +++ 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 +#include +#include + +#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; +} diff --git a/getmesg.c b/getmesg.c new file mode 100644 index 0000000..31a7585 --- /dev/null +++ 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 +#include +#include + +#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); +} diff --git a/input.c b/input.c new file mode 100644 index 0000000..947189a --- /dev/null +++ b/input.c @@ -0,0 +1,166 @@ +/* + * Copyright (c) 2007 by Thierry Leconte (F4DWV) + * + * $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 +#include +#include + +#include "acarsdec.h" + +static int source = 0; +static int nbch = 0; + +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; + if (src) + return initsnd(sourcename); + else + return initalsa(sourcename); +} + +int getsample(short *sample, int nb) +{ + int r; + + if (source) { + r = sf_read_short(inwav, sample, nb); + if (r == 0) + r = -1; /* this is the end */ + } else { + 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; + } + return r; +} + +void endsample(void) +{ + if (source) + sf_close(inwav); + else + snd_pcm_close(capture_handle); +} diff --git a/main.c b/main.c new file mode 100644 index 0000000..3b93432 --- /dev/null +++ b/main.c @@ -0,0 +1,177 @@ +/* + * Copyright (c) 2007 by Thierry Leconte (F4DWV) + * + * $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 +#include +#include +#include +#include + +#include "version.h" +#include "acarsdec.h" + +extern int optind, opterr; +extern char *optarg; + +static void usage(void) +{ + fprintf(stderr, "Usage: acarsdec [-LR][-s noport] -d alsapcmdevice | -f sndfile \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, " [-LR] :\t\tdiseable 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); + +} + +int main(int argc, char **argv) +{ + int c; + msg_t msgl, msgr; + unsigned char rl, rr; + int nbitl, nbitr; + int nrbitl, nrbitr; + int nbch=0; + int el=1,er=1; + short port=0; + + + while ((c = getopt(argc, argv, "d:f:RLs:")) != EOF) { + switch (c) { + case 'd': + nbch = initsample(optarg, 0); + break; + case 'f': + nbch = initsample(optarg, 1); + break; + case 'L': + el=0; + break; + case 'R': + er=0; + break; + case 's': + port=atoi(optarg); + break; + default: + usage(); + exit(1); + } + } + + if (nbch == 0) { + usage(); + exit(1); + } + + if(port) + if(init_serv(port)) { + exit(1); + } + + +/* main loop */ + + init_bits(); + init_mesg(); + + nbitl = nbitr = 0; + nrbitl = nrbitr = 8; + + do { + short sample[4096]; + int ind, len; + + len = getsample(sample, 4096); + if (len < 0) + break; + + for (ind = 0; ind < len;) { + + if(el) { + nbitl += getbit(sample[ind], &rl, 0); + if (nbitl >= nrbitl) { + nrbitl = getmesg(rl, &msgl, 0); + nbitl = 0; + if (nrbitl == 0) { + if(port) + send_mesg(&msgl); + else + print_mesg(&msgl); + nrbitl = 8; + } + } + } + ind++; + + if (nbch >= 2) { + if(er) { + nbitr += getbit(sample[ind], &rr, 1); + if (nbitr >= nrbitr) { + nrbitr = getmesg(rr, &msgr, 1); + nbitr = 0; + if (nrbitr == 0) { + if(port) + send_mesg(&msgl); + else + print_mesg(&msgl); + nrbitr = 8; + } + } + } + ind++; + } + } + } while (1); + + + if(port) + end_serv(); + + endsample(); + + exit(0); +} diff --git a/serv.c b/serv.c new file mode 100644 index 0000000..c4909cd --- /dev/null +++ b/serv.c @@ -0,0 +1,303 @@ +/* + * Copyright (c) 2007 by Thierry Leconte (F4DWV) + * + * $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 +#include +#include +#include +#include +#include +#include +#include + +#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; + } + + memset(&locaddr, 0, sizeof(locaddr)); + locaddr.sin_family = AF_INET; + locaddr.sin_port = htons(port); + locaddr.sin_addr.s_addr = htonl(INADDR_LOOPBACK); + + 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 = 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); +} diff --git a/version.h b/version.h new file mode 100644 index 0000000..3ee808d --- /dev/null +++ b/version.h @@ -0,0 +1 @@ +const char version[] = "Acarsdec 1.1 (c) 2007 Thierry Leconte F4DWV";