mirror of
https://github.com/brmlab/acarsdec.git
synced 2025-08-01 21:53:38 +02:00
Initial commit - acarsdec-1.1, upstream vanilla version
This commit is contained in:
commit
8223d9e9c8
9 changed files with 1172 additions and 0 deletions
20
Makefile
Normal file
20
Makefile
Normal file
|
@ -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
|
69
README
Normal file
69
README
Normal file
|
@ -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.
|
||||
|
||||
|
26
acarsdec.h
Normal file
26
acarsdec.h
Normal file
|
@ -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);
|
||||
|
192
getbits.c
Normal file
192
getbits.c
Normal file
|
@ -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;
|
||||
}
|
218
getmesg.c
Normal file
218
getmesg.c
Normal file
|
@ -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);
|
||||
}
|
166
input.c
Normal file
166
input.c
Normal file
|
@ -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 <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 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);
|
||||
}
|
177
main.c
Normal file
177
main.c
Normal file
|
@ -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 <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, "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);
|
||||
}
|
303
serv.c
Normal file
303
serv.c
Normal file
|
@ -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 <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;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
1
version.h
Normal file
1
version.h
Normal file
|
@ -0,0 +1 @@
|
|||
const char version[] = "Acarsdec 1.1 (c) 2007 Thierry Leconte F4DWV";
|
Loading…
Add table
Add a link
Reference in a new issue