kopia lustrzana https://github.com/sp9skp/spdxl
649 wiersze
15 KiB
C
649 wiersze
15 KiB
C
/*
|
|
* dxlAPRS toolchain
|
|
*
|
|
* Copyright (C) Christian Rabler <oe5dxl@oevsv.at>
|
|
*
|
|
* SPDX-License-Identifier: GPL-2.0+
|
|
*/
|
|
|
|
|
|
#define X2C_int32
|
|
#define X2C_index32
|
|
#ifndef X2C_H_
|
|
#include "X2C.h"
|
|
#endif
|
|
#define adsb2aprs_C_
|
|
#ifndef osi_H_
|
|
#include "osi.h"
|
|
#endif
|
|
#include <osic.h>
|
|
#ifndef mlib_H_
|
|
#include "mlib.h"
|
|
#endif
|
|
#ifndef tcp_H_
|
|
#include "tcp.h"
|
|
#endif
|
|
#ifndef udp_H_
|
|
#include "udp.h"
|
|
#endif
|
|
#ifndef aprsstr_H_
|
|
#include "aprsstr.h"
|
|
#endif
|
|
#ifndef tcpb_H_
|
|
#include "tcpb.h"
|
|
#endif
|
|
|
|
/* dump1090 tcp output to aprs beacon by OE5DXL */
|
|
#define adsb2aprs_TIMETOL 20
|
|
/* max seconds between dir/speed and pos */
|
|
|
|
#define adsb2aprs_PURGETIME 120
|
|
/* seconds keep context */
|
|
|
|
#define adsb2aprs_DEFAULTBEACONTIME 20
|
|
|
|
#define adsb2aprs_SYMBOL "/^"
|
|
|
|
#define adsb2aprs_KNOTS 1.852
|
|
/* nautic miles */
|
|
|
|
#define adsb2aprs_FEET 0.3048
|
|
|
|
typedef char CSV[100][21];
|
|
|
|
struct FLY;
|
|
|
|
typedef struct FLY * pFLY;
|
|
|
|
|
|
struct FLY {
|
|
pFLY next;
|
|
char hex[6];
|
|
char name[21];
|
|
float lat;
|
|
float long0;
|
|
float alt;
|
|
float speed;
|
|
float dir;
|
|
uint32_t speedtime;
|
|
uint32_t postime;
|
|
uint32_t lasttime;
|
|
uint32_t lastbeacon;
|
|
char newpos;
|
|
};
|
|
|
|
static char url[1001];
|
|
|
|
static char port[1001];
|
|
|
|
static char reconn;
|
|
|
|
static char verb;
|
|
|
|
static char verb2;
|
|
|
|
static int32_t fd;
|
|
|
|
static pFLY dbase;
|
|
|
|
static uint32_t btime;
|
|
|
|
static char mycall[10];
|
|
|
|
static char symbol[2];
|
|
|
|
static int32_t udpsock;
|
|
|
|
static uint32_t ipnum;
|
|
|
|
static uint32_t toport;
|
|
|
|
|
|
static void Error(char text[], uint32_t text_len)
|
|
{
|
|
X2C_PCOPY((void **)&text,text_len);
|
|
osi_Werr(text, text_len);
|
|
osi_WerrLn(" error abort", 13ul);
|
|
X2C_ABORT();
|
|
X2C_PFREE(text);
|
|
} /* end Error() */
|
|
|
|
|
|
static char GetNum(const char h[], uint32_t h_len, char eot,
|
|
uint32_t * p, uint32_t * n)
|
|
{
|
|
*n = 0UL;
|
|
while ((uint8_t)h[*p]>='0' && (uint8_t)h[*p]<='9') {
|
|
*n = ( *n*10UL+(uint32_t)(uint8_t)h[*p])-48UL;
|
|
++*p;
|
|
}
|
|
return h[*p]==eot;
|
|
} /* end GetNum() */
|
|
|
|
|
|
static uint32_t truncc(double r)
|
|
{
|
|
if (r<=0.0) return 0UL;
|
|
else if (r>=2.147483647E+9) return 2147483647UL;
|
|
else return (uint32_t)X2C_TRUNCC(r,0UL,X2C_max_longcard);
|
|
return 0;
|
|
} /* end truncc() */
|
|
|
|
|
|
static uint32_t truncr(float r)
|
|
{
|
|
if (r<=0.0f) return 0UL;
|
|
else if (r>=2.147483647E+9f) return 2147483647UL;
|
|
else return (uint32_t)X2C_TRUNCC(r,0UL,X2C_max_longcard);
|
|
return 0;
|
|
} /* end truncr() */
|
|
|
|
|
|
static int32_t GetIp(char h[], uint32_t h_len, uint32_t * p,
|
|
uint32_t * ip0, uint32_t * port0)
|
|
{
|
|
uint32_t n;
|
|
uint32_t i;
|
|
char ok0;
|
|
int32_t GetIp_ret;
|
|
X2C_PCOPY((void **)&h,h_len);
|
|
*p = 0UL;
|
|
h[h_len-1] = 0;
|
|
*ip0 = 0UL;
|
|
for (i = 0UL; i<=4UL; i++) {
|
|
n = 0UL;
|
|
ok0 = 0;
|
|
while ((uint8_t)h[*p]>='0' && (uint8_t)h[*p]<='9') {
|
|
ok0 = 1;
|
|
n = (n*10UL+(uint32_t)(uint8_t)h[*p])-48UL;
|
|
++*p;
|
|
}
|
|
if (!ok0) {
|
|
GetIp_ret = -1L;
|
|
goto label;
|
|
}
|
|
if (i<3UL) {
|
|
if (h[*p]!='.' || n>255UL) {
|
|
GetIp_ret = -1L;
|
|
goto label;
|
|
}
|
|
*ip0 = *ip0*256UL+n;
|
|
}
|
|
else if (i==3UL) {
|
|
*ip0 = *ip0*256UL+n;
|
|
if (h[*p]!=':' || n>255UL) {
|
|
GetIp_ret = -1L;
|
|
goto label;
|
|
}
|
|
}
|
|
else if (n>65535UL) {
|
|
GetIp_ret = -1L;
|
|
goto label;
|
|
}
|
|
*port0 = n;
|
|
++*p;
|
|
} /* end for */
|
|
GetIp_ret = 0L;
|
|
label:;
|
|
X2C_PFREE(h);
|
|
return GetIp_ret;
|
|
} /* end GetIp() */
|
|
|
|
|
|
static void Parms(void)
|
|
{
|
|
char s[1001];
|
|
uint32_t n;
|
|
uint32_t m;
|
|
reconn = 0;
|
|
verb = 0;
|
|
verb2 = 0;
|
|
strncpy(url,"127.0.0.1",1001u);
|
|
strncpy(port,"30003",1001u);
|
|
mycall[0] = 0;
|
|
btime = 20UL;
|
|
strncpy(symbol,"/^",2u);
|
|
for (;;) {
|
|
osi_NextArg(s, 1001ul);
|
|
if (s[0U]==0) break;
|
|
if ((s[0U]=='-' && s[1U]) && s[2U]==0) {
|
|
if (s[1U]=='t') {
|
|
osi_NextArg(s, 1001ul); /* url */
|
|
n = 0UL;
|
|
while ((n<1000UL && s[n]) && s[n]!=':') {
|
|
if (n<1000UL) url[n] = s[n];
|
|
++n;
|
|
}
|
|
if (n>1000UL) n = 1000UL;
|
|
url[n] = 0;
|
|
if (s[n]==':') {
|
|
m = 0UL;
|
|
++n;
|
|
while ((n<1000UL && s[n]) && m<1000UL) {
|
|
port[m] = s[n];
|
|
++n;
|
|
++m;
|
|
}
|
|
if (m>1000UL) m = 1000UL;
|
|
port[m] = 0;
|
|
}
|
|
}
|
|
else if (s[1U]=='k') reconn = 1;
|
|
else if (s[1U]=='b') {
|
|
osi_NextArg(s, 1001ul);
|
|
n = 0UL;
|
|
if (!GetNum(s, 1001ul, 0, &n, &btime)) Error("-b <s>", 7ul);
|
|
}
|
|
else if (s[1U]=='I') {
|
|
osi_NextArg(mycall, 10ul);
|
|
if (aprsstr_Length(mycall, 10ul)<3UL || aprsstr_Length(mycall,
|
|
10ul)>9UL) Error("-I <callsign>", 14ul);
|
|
}
|
|
else if (s[1U]=='s') {
|
|
osi_NextArg(symbol, 2ul);
|
|
if (aprsstr_Length(symbol, 2ul)!=2UL || symbol[0U]=='-') {
|
|
Error("-s <symbol>", 12ul);
|
|
}
|
|
}
|
|
else if (s[1U]=='u') {
|
|
osi_NextArg(s, 1001ul);
|
|
n = 0UL;
|
|
if (GetIp(s, 1001ul, &n, &ipnum, &toport)<0L) {
|
|
Error("-u ip:port number", 18ul);
|
|
}
|
|
udpsock = openudp();
|
|
if (udpsock<0L) Error("cannot open udp socket", 23ul);
|
|
}
|
|
else if (s[1U]=='v') verb = 1;
|
|
else if (s[1U]=='V') {
|
|
verb = 1;
|
|
verb2 = 1;
|
|
}
|
|
else if (s[1U]=='h') {
|
|
osi_WrStrLn("", 1ul);
|
|
osi_WrStrLn("dump1090 basestation format tcp output to aprs objec\
|
|
t beacon", 61ul);
|
|
osi_WrStrLn("", 1ul);
|
|
osi_WrStrLn(" -b <seconds> aprs minimum send intervall -b \
|
|
10 (20)", 60ul);
|
|
osi_WrStrLn(" -h help", 26ul);
|
|
osi_WrStrLn(" -I <mycall> Sender of Object Callsign -I OE\
|
|
0AAA", 57ul);
|
|
osi_WrStrLn(" -k keep tcp connection", 41ul);
|
|
osi_WrStrLn(" -s <symbol> aprs symbol (/^)", 38ul);
|
|
osi_WrStrLn(" -t <url:port> connect dump1090 tcp server (12\
|
|
7.0.0.1:30003)", 67ul);
|
|
osi_WrStrLn(" -u <ip>:<port> send AXUDP -u 127.0.0.1:9001 us\
|
|
e udpgate4 or aprsmap as receiver", 86ul);
|
|
osi_WrStrLn(" -v verbous", 29ul);
|
|
osi_WrStrLn("example: -t 127.0.0.1:30003 -I YOURCALL-11 -u 127.0.\
|
|
0.1:9002 -k -v", 67ul);
|
|
osi_WrStrLn("before this start \"dump1090 --net\"", 35ul);
|
|
osi_WrStrLn("", 1ul);
|
|
X2C_ABORT();
|
|
}
|
|
else Error("-h", 3ul);
|
|
}
|
|
else Error("-h", 3ul);
|
|
}
|
|
} /* end Parms() */
|
|
|
|
|
|
static void decodeline(const char line0[], uint32_t line_len,
|
|
CSV csv0)
|
|
{
|
|
uint32_t j;
|
|
uint32_t w;
|
|
uint32_t i;
|
|
memset((char *)csv0,(char)0,2100UL);
|
|
i = 0UL;
|
|
j = 0UL;
|
|
w = 0UL;
|
|
while (i<=line_len-1 && (uint8_t)line0[i]>=' ') {
|
|
if (line0[i]!=',') {
|
|
if (w<=99UL && j<=20UL) {
|
|
csv0[w][j] = line0[i];
|
|
++j;
|
|
}
|
|
}
|
|
else {
|
|
++w;
|
|
j = 0UL;
|
|
}
|
|
++i;
|
|
}
|
|
} /* end decodeline() */
|
|
|
|
|
|
static char num(uint32_t n)
|
|
{
|
|
return (char)(n%10UL+48UL);
|
|
} /* end num() */
|
|
|
|
|
|
static uint32_t dao91(double x)
|
|
/* radix91(xx/1.1) of dddmm.mmxx */
|
|
{
|
|
double a;
|
|
a = fabs(x);
|
|
return ((truncc((a-(double)(float)truncc(a))*6.E+5)%100UL)
|
|
*20UL+11UL)/22UL;
|
|
} /* end dao91() */
|
|
|
|
|
|
static void sendaprs(char dao, uint32_t time0, char mycall0[],
|
|
uint32_t mycall_len, char destcall[],
|
|
uint32_t destcall_len, char via[], uint32_t via_len,
|
|
char sym[], uint32_t sym_len, char obj[],
|
|
uint32_t obj_len, double lat, double long0,
|
|
double alt, double course, double speed,
|
|
char comm[], uint32_t comm_len)
|
|
{
|
|
char ds[201];
|
|
char h[201];
|
|
char b[201];
|
|
char raw[361];
|
|
int32_t rp;
|
|
uint32_t n;
|
|
uint32_t i;
|
|
float a;
|
|
X2C_PCOPY((void **)&mycall0,mycall_len);
|
|
X2C_PCOPY((void **)&destcall,destcall_len);
|
|
X2C_PCOPY((void **)&via,via_len);
|
|
X2C_PCOPY((void **)&sym,sym_len);
|
|
X2C_PCOPY((void **)&obj,obj_len);
|
|
X2C_PCOPY((void **)&comm,comm_len);
|
|
b[0] = 0;
|
|
aprsstr_Append(b, 201ul, mycall0, mycall_len);
|
|
aprsstr_Append(b, 201ul, ">", 2ul);
|
|
aprsstr_Append(b, 201ul, destcall, destcall_len);
|
|
if (via[0UL]) {
|
|
aprsstr_Append(b, 201ul, ",", 2ul);
|
|
aprsstr_Append(b, 201ul, via, via_len);
|
|
}
|
|
aprsstr_Append(b, 201ul, ":;", 3ul);
|
|
aprsstr_Assign(h, 201ul, obj, obj_len);
|
|
aprsstr_Append(h, 201ul, " ", 10ul);
|
|
h[9U] = 0;
|
|
aprsstr_Append(b, 201ul, h, 201ul);
|
|
aprsstr_Append(b, 201ul, "*", 2ul);
|
|
aprsstr_DateToStr(time0, ds, 201ul);
|
|
ds[0U] = ds[11U];
|
|
ds[1U] = ds[12U];
|
|
ds[2U] = ds[14U];
|
|
ds[3U] = ds[15U];
|
|
ds[4U] = ds[17U];
|
|
ds[5U] = ds[18U];
|
|
ds[6U] = 0;
|
|
aprsstr_Append(b, 201ul, ds, 201ul);
|
|
aprsstr_Append(b, 201ul, "h", 2ul);
|
|
i = aprsstr_Length(b, 201ul);
|
|
a = (float)fabs(lat);
|
|
n = truncr(a);
|
|
b[i] = num(n/10UL);
|
|
++i;
|
|
b[i] = num(n);
|
|
++i;
|
|
n = truncr((a-(float)n)*6000.0f);
|
|
b[i] = num(n/1000UL);
|
|
++i;
|
|
b[i] = num(n/100UL);
|
|
++i;
|
|
b[i] = '.';
|
|
++i;
|
|
b[i] = num(n/10UL);
|
|
++i;
|
|
b[i] = num(n);
|
|
++i;
|
|
if (lat>=0.0) b[i] = 'N';
|
|
else b[i] = 'S';
|
|
++i;
|
|
b[i] = sym[0UL];
|
|
++i;
|
|
a = (float)fabs(long0);
|
|
n = truncr(a);
|
|
b[i] = num(n/100UL);
|
|
++i;
|
|
b[i] = num(n/10UL);
|
|
++i;
|
|
b[i] = num(n);
|
|
++i;
|
|
n = truncr((a-(float)n)*6000.0f);
|
|
b[i] = num(n/1000UL);
|
|
++i;
|
|
b[i] = num(n/100UL);
|
|
++i;
|
|
b[i] = '.';
|
|
++i;
|
|
b[i] = num(n/10UL);
|
|
++i;
|
|
b[i] = num(n);
|
|
++i;
|
|
if (lat>=0.0) b[i] = 'E';
|
|
else b[i] = 'W';
|
|
++i;
|
|
b[i] = sym[1UL];
|
|
++i;
|
|
if (speed>0.5) {
|
|
n = truncr((float)(course+1.5));
|
|
b[i] = num(n/100UL);
|
|
++i;
|
|
b[i] = num(n/10UL);
|
|
++i;
|
|
b[i] = num(n);
|
|
++i;
|
|
b[i] = '/';
|
|
++i;
|
|
n = truncr((float)(speed*5.3995680345572E-1+0.5));
|
|
b[i] = num(n/100UL);
|
|
++i;
|
|
b[i] = num(n/10UL);
|
|
++i;
|
|
b[i] = num(n);
|
|
++i;
|
|
}
|
|
if (alt>0.5) {
|
|
b[i] = '/';
|
|
++i;
|
|
b[i] = 'A';
|
|
++i;
|
|
b[i] = '=';
|
|
++i;
|
|
n = truncr((float)fabs(alt*3.2808398950131+0.5));
|
|
if (alt>=0.0) b[i] = num(n/100000UL);
|
|
else b[i] = '-';
|
|
++i;
|
|
b[i] = num(n/10000UL);
|
|
++i;
|
|
b[i] = num(n/1000UL);
|
|
++i;
|
|
b[i] = num(n/100UL);
|
|
++i;
|
|
b[i] = num(n/10UL);
|
|
++i;
|
|
b[i] = num(n);
|
|
++i;
|
|
}
|
|
if (dao) {
|
|
b[i] = '!';
|
|
++i;
|
|
b[i] = 'w';
|
|
++i;
|
|
b[i] = (char)(33UL+dao91(lat));
|
|
++i;
|
|
b[i] = (char)(33UL+dao91(long0));
|
|
++i;
|
|
b[i] = '!';
|
|
++i;
|
|
}
|
|
b[i] = 0;
|
|
aprsstr_Append(b, 201ul, comm, comm_len);
|
|
if (verb) osi_WrStrLn(b, 201ul);
|
|
aprsstr_mon2raw(b, 201ul, raw, 361ul, &rp);
|
|
rp = udpsend(udpsock, raw, rp, toport, ipnum);
|
|
X2C_PFREE(mycall0);
|
|
X2C_PFREE(destcall);
|
|
X2C_PFREE(via);
|
|
X2C_PFREE(sym);
|
|
X2C_PFREE(obj);
|
|
X2C_PFREE(comm);
|
|
} /* end sendaprs() */
|
|
|
|
|
|
static void aprs(const struct FLY f)
|
|
{
|
|
char h[31];
|
|
aprsstr_Assign(h, 31ul, f.name, 21ul);
|
|
h[9U] = 0;
|
|
while (aprsstr_Length(h, 31ul)<9UL) aprsstr_Append(h, 31ul, " ", 2ul);
|
|
sendaprs(0, f.postime, mycall, 10ul, "APLFR1", 7ul, "", 1ul, "/^", 3ul, h,
|
|
31ul, (double)f.lat, (double)f.long0,
|
|
(double)f.alt, (double)f.dir,
|
|
(double)(f.speed*1.852f), "", 1ul);
|
|
} /* end aprs() */
|
|
|
|
|
|
static void store(const CSV csv0)
|
|
{
|
|
pFLY f0;
|
|
pFLY f1;
|
|
pFLY f;
|
|
uint32_t msg;
|
|
uint32_t t;
|
|
float oalt;
|
|
float olong;
|
|
float olat;
|
|
t = osic_time();
|
|
if ((((csv0[0U][0U]=='M' && csv0[0U][1U]=='S') && csv0[0U][2U]=='G')
|
|
&& aprsstr_StrToCard(csv0[1U], 21ul,
|
|
&msg)) && ((msg==1UL || msg==3UL) || msg==4UL)) {
|
|
f = dbase;
|
|
f0 = 0;
|
|
while (f && !aprsstr_StrCmp(f->hex, 6ul, csv0[4U], 21ul)) {
|
|
f1 = f->next;
|
|
if (f->lasttime+120UL<t) {
|
|
if (f0==0) dbase = f1;
|
|
else f0->next = f1;
|
|
if (verb2) {
|
|
osi_WrStr("purge ", 7ul);
|
|
osi_WrStrLn(f->hex, 6ul);
|
|
}
|
|
osic_free((char * *) &f, sizeof(struct FLY));
|
|
}
|
|
else f0 = f;
|
|
f = f1;
|
|
}
|
|
if (f==0) {
|
|
osic_alloc((char * *) &f, sizeof(struct FLY));
|
|
if (f==0) {
|
|
osi_WerrLn("Out of Memory", 14ul);
|
|
return;
|
|
}
|
|
memset((char *)f,(char)0,sizeof(struct FLY));
|
|
f->next = dbase;
|
|
dbase = f;
|
|
aprsstr_Assign(f->hex, 6ul, csv0[4U], 21ul);
|
|
if (verb2) {
|
|
osi_WrStr("new ", 5ul);
|
|
osi_WrStrLn(f->hex, 6ul);
|
|
}
|
|
}
|
|
f->lasttime = t;
|
|
if (msg==1UL) {
|
|
if (verb2 && f->name[0U]==0) {
|
|
osi_WrStr("found name ", 12ul);
|
|
osi_WrStr(f->hex, 6ul);
|
|
osi_WrStr(" ", 2ul);
|
|
osi_WrStrLn(f->name, 21ul);
|
|
}
|
|
aprsstr_Assign(f->name, 21ul, csv0[10U], 21ul);
|
|
}
|
|
else if (msg==4UL) {
|
|
if (((aprsstr_StrToFix(&f->speed, csv0[12U],
|
|
21ul) && aprsstr_StrToFix(&f->dir, csv0[13U],
|
|
21ul)) && f->dir>=0.0f) && f->dir<=360.0f) f->speedtime = t;
|
|
}
|
|
else if (msg==3UL) {
|
|
if (((((((aprsstr_StrToFix(&oalt, csv0[11U],
|
|
21ul) && aprsstr_StrToFix(&olat, csv0[14U],
|
|
21ul)) && olat>(-90.0f)) && olat<90.0f)
|
|
&& aprsstr_StrToFix(&olong, csv0[15U],
|
|
21ul)) && olong>(-180.0f)) && olong<180.0f)
|
|
&& (olong!=f->long0 || olat!=f->lat)) {
|
|
f->postime = t;
|
|
f->newpos = 1;
|
|
f->lat = olat;
|
|
f->long0 = olong;
|
|
f->alt = oalt*0.3048f;
|
|
}
|
|
}
|
|
if (f->lastbeacon>t) f->lastbeacon = t;
|
|
if (((((((f->newpos && f->name[0U]) && f->postime+20UL>=t)
|
|
&& f->speedtime+20UL>=t) && f->speed>0.0f) && f->lat!=0.0f)
|
|
&& f->long0!=0.0f) && f->lastbeacon+btime<t) {
|
|
aprs(*f);
|
|
f->newpos = 0;
|
|
f->lastbeacon = t;
|
|
}
|
|
}
|
|
} /* end store() */
|
|
|
|
static char ibuf[201];
|
|
|
|
static char line[201];
|
|
|
|
static uint32_t ip;
|
|
|
|
static uint32_t lp;
|
|
|
|
static CSV csv;
|
|
|
|
|
|
X2C_STACK_LIMIT(100000l)
|
|
extern int main(int argc, char **argv)
|
|
{
|
|
X2C_BEGIN(&argc,argv,1,4000000l,8000000l);
|
|
if (sizeof(CSV)!=2100) X2C_ASSERT(0);
|
|
aprsstr_BEGIN();
|
|
osi_BEGIN();
|
|
Parms();
|
|
fd = -1L;
|
|
dbase = 0;
|
|
fd = connecttob(url, port);
|
|
lp = 0UL;
|
|
for (;;) {
|
|
if (fd>=0L) {
|
|
if (readsockb(fd, (char *)ibuf, 201L)<0L) {
|
|
/* connect lost */
|
|
osic_Close(fd);
|
|
fd = -1L;
|
|
}
|
|
else {
|
|
for (ip = 0UL; ip<=200UL; ip++) {
|
|
if ((uint8_t)ibuf[ip]<' ') {
|
|
if (lp<200UL) line[lp] = 0;
|
|
if (verb) osi_WrStrLn(line, 201ul);
|
|
decodeline(line, 201ul, csv);
|
|
store(csv);
|
|
lp = 0UL;
|
|
}
|
|
else if (lp<200UL) {
|
|
line[lp] = ibuf[ip];
|
|
++lp;
|
|
}
|
|
} /* end for */
|
|
}
|
|
}
|
|
else if (reconn) {
|
|
osi_WerrLn("connection lost", 16ul);
|
|
usleep(1000000UL);
|
|
fd = connecttob(url, port);
|
|
}
|
|
else break;
|
|
}
|
|
X2C_EXIT();
|
|
return 0;
|
|
}
|
|
|
|
X2C_MAIN_DEFINITION
|