pull/29/head
Christopher Young 2015-09-01 14:07:47 -04:00
commit 6de59749f0
11 zmienionych plików z 3767 dodań i 4 usunięć

3
.gitmodules vendored
Wyświetl plik

@ -1,3 +0,0 @@
[submodule "dump1090"]
path = dump1090
url = https://github.com/antirez/dump1090

@ -1 +0,0 @@
Subproject commit 823631979b74f83caa48da69c86f8967e4c17c47

15
dump1090/Makefile 100644
Wyświetl plik

@ -0,0 +1,15 @@
CFLAGS?=-O2 -g -Wall -W $(shell pkg-config --cflags librtlsdr)
LDLIBS+=$(shell pkg-config --libs librtlsdr) -lpthread -lm
CC?=gcc
PROGNAME=dump1090
all: dump1090
%.o: %.c
$(CC) $(CFLAGS) -c $<
dump1090: dump1090.o anet.o
$(CC) -g -o dump1090 dump1090.o anet.o $(LDFLAGS) $(LDLIBS)
clean:
rm -f *.o dump1090

284
dump1090/README.md 100644
Wyświetl plik

@ -0,0 +1,284 @@
Dump1090 README
===
Dump 1090 is a Mode S decoder specifically designed for RTLSDR devices.
The main features are:
* Robust decoding of weak messages, with mode1090 many users observed
improved range compared to other popular decoders.
* Network support: TCP30003 stream (MSG5...), Raw packets, HTTP.
* Embedded HTTP server that displays the currently detected aircrafts on
Google Map.
* Single bit errors correction using the 24 bit CRC.
* Ability to decode DF11, DF17 messages.
* Ability to decode DF formats like DF0, DF4, DF5, DF16, DF20 and DF21
where the checksum is xored with the ICAO address by brute forcing the
checksum field using recently seen ICAO addresses.
* Decode raw IQ samples from file (using --ifile command line switch).
* Interactive command-line-interfae mode where aircrafts currently detected
are shown as a list refreshing as more data arrives.
* CPR coordinates decoding and track calculation from velocity.
* TCP server streaming and receiving raw data to/from connected clients
(using --net).
While from time to time I still add / fix stuff in my fork, I target
minimalism of the implementation. However there is a
[much more feature complete fork](https://github.com/MalcolmRobb/dump1090)
available, developed by MalcolmRobb.
Installation
---
Type "make".
Normal usage
---
To capture traffic directly from your RTL device and show the captured traffic
on standard output, just run the program without options at all:
./dump1090
To just output hexadecimal messages:
./dump1090 --raw
To run the program in interactive mode:
./dump1090 --interactive
To run the program in interactive mode, with networking support, and connect
with your browser to http://localhost:8080 to see live traffic:
./dump1090 --interactive --net
In iteractive mode it is possible to have a less information dense but more
"arcade style" output, where the screen is refreshed every second displaying
all the recently seen aircrafts with some additional information such as
altitude and flight number, extracted from the received Mode S packets.
Using files as source of data
---
To decode data from file, use:
./dump1090 --ifile /path/to/binfile
The binary file should be created using `rtl_sdr` like this (or with any other
program that is able to output 8-bit unsigned IQ samples at 2Mhz sample rate).
rtl_sdr -f 1090000000 -s 2000000 -g 50 output.bin
In the example `rtl_sdr` a gain of 50 is used, simply you should use the highest
gain availabe for your tuner. This is not needed when calling Dump1090 itself
as it is able to select the highest gain supported automatically.
It is possible to feed the program with data via standard input using
the --ifile option with "-" as argument.
Additional options
---
Dump1090 can be called with other command line options to set a different
gain, frequency, and so forth. For a list of options use:
./dump1090 --help
Everything is not documented here should be obvious, and for most users calling
it without arguments at all is the best thing to do.
Reliability
---
By default Dump1090 tries to fix single bit errors using the checksum.
Basically the program will try to flip every bit of the message and check if
the checksum of the resulting message matches.
This is indeed able to fix errors and works reliably in my experience,
however if you are interested in very reliable data I suggest to use
the --no-fix command line switch in order to disable error fixing.
Performances and sensibility of detection
---
In my limited experience Dump1090 was able to decode a big number of messages
even in conditions where I encountered problems using other programs, however
no formal test was performed so I can't really claim that this program is
better or worse compared to other similar programs.
If you can capture traffic that Dump1090 is not able to decode properly, drop
me an email with a download link. I may try to improve the detection during
my free time (this is just an hobby project).
Network server features
---
By enabling the networking support with --net Dump1090 starts listening
for clients connections on port 30002 and 30001 (you can change both the
ports if you want, see --help output).
Port 30002
---
Connected clients are served with data ASAP as they arrive from the device
(or from file if --ifile is used) in the raw format similar to the following:
*8D451E8B99019699C00B0A81F36E;
Every entry is separated by a simple newline (LF character, hex 0x0A).
Port 30001
---
Port 30001 is the raw input port, and can be used to feed Dump1090 with
data in the same format as specified above, with hex messages starting with
a `*` and ending with a `;` character.
So for instance if there is another remote Dump1090 instance collecting data
it is possible to sum the output to a local Dump1090 instance doing something
like this:
nc remote-dump1090.example.net 30002 | nc localhost 30001
It is important to note that what is received via port 30001 is also
broadcasted to clients listening to port 30002.
In general everything received from port 30001 is handled exactly like the
normal traffic from RTL devices or from file when --ifile is used.
It is possible to use Dump1090 just as an hub using --ifile with /dev/zero
as argument as in the following example:
./dump1090 --net-only
Or alternatively to see what's happening on the screen:
./dump1090 --net-only --interactive
Then you can feed it from different data sources from the internet.
Port 30003
---
Connected clients are served with messages in SBS1 (BaseStation) format,
similar to:
MSG,4,,,738065,,,,,,,,420,179,,,0,,0,0,0,0
MSG,3,,,738065,,,,,,,35000,,,34.81609,34.07810,,,0,0,0,0
This can be used to feed data to various sharing sites without the need to use another decoder.
Antenna
---
Mode S messages are transmitted in the 1090 Mhz frequency. If you have a decent
antenna you'll be able to pick up signals from aircrafts pretty far from your
position, especially if you are outdoor and in a position with a good sky view.
You can easily build a very cheap antenna following the istructions at:
http://antirez.com/news/46
With this trivial antenna I was able to pick up signals of aircrafts 200+ Km
away from me.
If you are interested in a more serious antenna check the following
resources:
* http://gnuradio.org/redmine/attachments/download/246/06-foster-adsb.pdf
* http://www.lll.lu/~edward/edward/adsb/antenna/ADSBantenna.html
* http://modesbeast.com/pix/adsb-ant-drawing.gif
Aggressive mode
---
With --aggressive it is possible to activate the *aggressive mode* that is a
modified version of the Mode S packet detection and decoding.
THe aggresive mode uses more CPU usually (especially if there are many planes
sending DF17 packets), but can detect a few more messages.
The algorithm in aggressive mode is modified in the following ways:
* Up to two demodulation errors are tolerated (adjacent entires in the magnitude
vector with the same eight). Normally only messages without errors are
checked.
* It tries to fix DF17 messages trying every two bits combination.
The use of aggressive mdoe is only advised in places where there is low traffic
in order to have a chance to capture some more messages.
Debug mode
---
The Debug mode is a visual help to improve the detection algorithm or to
understand why the program is not working for a given input.
In this mode messages are displayed in an ASCII-art style graphical
representation, where the individial magnitude bars sampled at 2Mhz are
displayed.
An index shows the sample number, where 0 is the sample where the first
Mode S peak was found. Some additional background noise is also added
before the first peak to provide some context.
To enable debug mode and check what combinations of packets you can
log, use `mode1090 --help` to obtain a list of available debug flags.
Debug mode includes an optional javascript output that is used to visualize
packets using a web browser, you can use the file debug.html under the
'tools' directory to load the generated frames.js file.
How this program works?
---
The code is very documented and written in order to be easy to understand.
For the diligent programmer with a Mode S specification on his hands it
should be trivial to understand how it works.
The algorithms I used were obtained basically looking at many messages
as displayed using a trow-away SDL program, and trying to model the algorithm
based on how the messages look graphically.
How to test the program?
---
If you have an RTLSDR device and you happen to be in an area where there
are aircrafts flying over your head, just run the program and check for signals.
However if you don't have an RTLSDR device, or if in your area the presence
of aircrafts is very limited, you may want to try the sample file distributed
with the Dump1090 distribution under the "testfiles" directory.
Just run it like this:
./dump1090 --ifile testfiles/modes1.bin
What is --strip mode?
---
It is just a simple filter that will get raw IQ 8 bit samples in input
and will output a file missing all the parts of the file where I and Q
are lower than the specified <level> for more than 32 samples.
Use it like this:
cat big.bin | ./dump1090 --snip 25 > small.bin
I used it in order to create a small test file to include inside this
program source code distribution.
Contributing
---
Dump1090 was written during some free time during xmas 2012, it is an hobby
project so I'll be able to address issues and improve it only during
free time, however you are incouraged to send pull requests in order to
improve the program. A good starting point can be the TODO list included in
the source distribution.
Credits
---
Dump1090 was written by Salvatore Sanfilippo <antirez@gmail.com> and is
released under the BSD three clause license.

5
dump1090/TODO 100644
Wyświetl plik

@ -0,0 +1,5 @@
TODO
* Extract more information from captured Mode S messages.
* Improve the web interface gmap.html.
* Enhance the algorithm to reliably decode more messages.

382
dump1090/anet.c 100644
Wyświetl plik

@ -0,0 +1,382 @@
/* anet.c -- Basic TCP socket stuff made a bit less boring
*
* Copyright (c) 2006-2012, Salvatore Sanfilippo <antirez at gmail dot com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of Redis nor the names of its contributors may be used
* to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/un.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
#include <netdb.h>
#include <errno.h>
#include <stdarg.h>
#include <stdio.h>
#include "anet.h"
static void anetSetError(char *err, const char *fmt, ...)
{
va_list ap;
if (!err) return;
va_start(ap, fmt);
vsnprintf(err, ANET_ERR_LEN, fmt, ap);
va_end(ap);
}
int anetNonBlock(char *err, int fd)
{
int flags;
/* Set the socket nonblocking.
* Note that fcntl(2) for F_GETFL and F_SETFL can't be
* interrupted by a signal. */
if ((flags = fcntl(fd, F_GETFL)) == -1) {
anetSetError(err, "fcntl(F_GETFL): %s", strerror(errno));
return ANET_ERR;
}
if (fcntl(fd, F_SETFL, flags | O_NONBLOCK) == -1) {
anetSetError(err, "fcntl(F_SETFL,O_NONBLOCK): %s", strerror(errno));
return ANET_ERR;
}
return ANET_OK;
}
int anetTcpNoDelay(char *err, int fd)
{
int yes = 1;
if (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &yes, sizeof(yes)) == -1)
{
anetSetError(err, "setsockopt TCP_NODELAY: %s", strerror(errno));
return ANET_ERR;
}
return ANET_OK;
}
int anetSetSendBuffer(char *err, int fd, int buffsize)
{
if (setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &buffsize, sizeof(buffsize)) == -1)
{
anetSetError(err, "setsockopt SO_SNDBUF: %s", strerror(errno));
return ANET_ERR;
}
return ANET_OK;
}
int anetTcpKeepAlive(char *err, int fd)
{
int yes = 1;
if (setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, &yes, sizeof(yes)) == -1) {
anetSetError(err, "setsockopt SO_KEEPALIVE: %s", strerror(errno));
return ANET_ERR;
}
return ANET_OK;
}
int anetResolve(char *err, char *host, char *ipbuf)
{
struct sockaddr_in sa;
sa.sin_family = AF_INET;
if (inet_aton(host, &sa.sin_addr) == 0) {
struct hostent *he;
he = gethostbyname(host);
if (he == NULL) {
anetSetError(err, "can't resolve: %s", host);
return ANET_ERR;
}
memcpy(&sa.sin_addr, he->h_addr, sizeof(struct in_addr));
}
strcpy(ipbuf,inet_ntoa(sa.sin_addr));
return ANET_OK;
}
static int anetCreateSocket(char *err, int domain) {
int s, on = 1;
if ((s = socket(domain, SOCK_STREAM, 0)) == -1) {
anetSetError(err, "creating socket: %s", strerror(errno));
return ANET_ERR;
}
/* Make sure connection-intensive things like the redis benckmark
* will be able to close/open sockets a zillion of times */
if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) == -1) {
anetSetError(err, "setsockopt SO_REUSEADDR: %s", strerror(errno));
return ANET_ERR;
}
return s;
}
#define ANET_CONNECT_NONE 0
#define ANET_CONNECT_NONBLOCK 1
static int anetTcpGenericConnect(char *err, char *addr, int port, int flags)
{
int s;
struct sockaddr_in sa;
if ((s = anetCreateSocket(err,AF_INET)) == ANET_ERR)
return ANET_ERR;
sa.sin_family = AF_INET;
sa.sin_port = htons(port);
if (inet_aton(addr, &sa.sin_addr) == 0) {
struct hostent *he;
he = gethostbyname(addr);
if (he == NULL) {
anetSetError(err, "can't resolve: %s", addr);
close(s);
return ANET_ERR;
}
memcpy(&sa.sin_addr, he->h_addr, sizeof(struct in_addr));
}
if (flags & ANET_CONNECT_NONBLOCK) {
if (anetNonBlock(err,s) != ANET_OK)
return ANET_ERR;
}
if (connect(s, (struct sockaddr*)&sa, sizeof(sa)) == -1) {
if (errno == EINPROGRESS &&
flags & ANET_CONNECT_NONBLOCK)
return s;
anetSetError(err, "connect: %s", strerror(errno));
close(s);
return ANET_ERR;
}
return s;
}
int anetTcpConnect(char *err, char *addr, int port)
{
return anetTcpGenericConnect(err,addr,port,ANET_CONNECT_NONE);
}
int anetTcpNonBlockConnect(char *err, char *addr, int port)
{
return anetTcpGenericConnect(err,addr,port,ANET_CONNECT_NONBLOCK);
}
int anetUnixGenericConnect(char *err, char *path, int flags)
{
int s;
struct sockaddr_un sa;
if ((s = anetCreateSocket(err,AF_LOCAL)) == ANET_ERR)
return ANET_ERR;
sa.sun_family = AF_LOCAL;
strncpy(sa.sun_path,path,sizeof(sa.sun_path)-1);
if (flags & ANET_CONNECT_NONBLOCK) {
if (anetNonBlock(err,s) != ANET_OK)
return ANET_ERR;
}
if (connect(s,(struct sockaddr*)&sa,sizeof(sa)) == -1) {
if (errno == EINPROGRESS &&
flags & ANET_CONNECT_NONBLOCK)
return s;
anetSetError(err, "connect: %s", strerror(errno));
close(s);
return ANET_ERR;
}
return s;
}
int anetUnixConnect(char *err, char *path)
{
return anetUnixGenericConnect(err,path,ANET_CONNECT_NONE);
}
int anetUnixNonBlockConnect(char *err, char *path)
{
return anetUnixGenericConnect(err,path,ANET_CONNECT_NONBLOCK);
}
/* Like read(2) but make sure 'count' is read before to return
* (unless error or EOF condition is encountered) */
int anetRead(int fd, char *buf, int count)
{
int nread, totlen = 0;
while(totlen != count) {
nread = read(fd,buf,count-totlen);
if (nread == 0) return totlen;
if (nread == -1) return -1;
totlen += nread;
buf += nread;
}
return totlen;
}
/* Like write(2) but make sure 'count' is read before to return
* (unless error is encountered) */
int anetWrite(int fd, char *buf, int count)
{
int nwritten, totlen = 0;
while(totlen != count) {
nwritten = write(fd,buf,count-totlen);
if (nwritten == 0) return totlen;
if (nwritten == -1) return -1;
totlen += nwritten;
buf += nwritten;
}
return totlen;
}
static int anetListen(char *err, int s, struct sockaddr *sa, socklen_t len) {
if (bind(s,sa,len) == -1) {
anetSetError(err, "bind: %s", strerror(errno));
close(s);
return ANET_ERR;
}
/* Use a backlog of 512 entries. We pass 511 to the listen() call because
* the kernel does: backlogsize = roundup_pow_of_two(backlogsize + 1);
* which will thus give us a backlog of 512 entries */
if (listen(s, 511) == -1) {
anetSetError(err, "listen: %s", strerror(errno));
close(s);
return ANET_ERR;
}
return ANET_OK;
}
int anetTcpServer(char *err, int port, char *bindaddr)
{
int s;
struct sockaddr_in sa;
if ((s = anetCreateSocket(err,AF_INET)) == ANET_ERR)
return ANET_ERR;
memset(&sa,0,sizeof(sa));
sa.sin_family = AF_INET;
sa.sin_port = htons(port);
sa.sin_addr.s_addr = htonl(INADDR_ANY);
if (bindaddr && inet_aton(bindaddr, &sa.sin_addr) == 0) {
anetSetError(err, "invalid bind address");
close(s);
return ANET_ERR;
}
if (anetListen(err,s,(struct sockaddr*)&sa,sizeof(sa)) == ANET_ERR)
return ANET_ERR;
return s;
}
int anetUnixServer(char *err, char *path, mode_t perm)
{
int s;
struct sockaddr_un sa;
if ((s = anetCreateSocket(err,AF_LOCAL)) == ANET_ERR)
return ANET_ERR;
memset(&sa,0,sizeof(sa));
sa.sun_family = AF_LOCAL;
strncpy(sa.sun_path,path,sizeof(sa.sun_path)-1);
if (anetListen(err,s,(struct sockaddr*)&sa,sizeof(sa)) == ANET_ERR)
return ANET_ERR;
if (perm)
chmod(sa.sun_path, perm);
return s;
}
static int anetGenericAccept(char *err, int s, struct sockaddr *sa, socklen_t *len) {
int fd;
while(1) {
fd = accept(s,sa,len);
if (fd == -1) {
if (errno == EINTR)
continue;
else {
anetSetError(err, "accept: %s", strerror(errno));
return ANET_ERR;
}
}
break;
}
return fd;
}
int anetTcpAccept(char *err, int s, char *ip, int *port) {
int fd;
struct sockaddr_in sa;
socklen_t salen = sizeof(sa);
if ((fd = anetGenericAccept(err,s,(struct sockaddr*)&sa,&salen)) == ANET_ERR)
return ANET_ERR;
if (ip) strcpy(ip,inet_ntoa(sa.sin_addr));
if (port) *port = ntohs(sa.sin_port);
return fd;
}
int anetUnixAccept(char *err, int s) {
int fd;
struct sockaddr_un sa;
socklen_t salen = sizeof(sa);
if ((fd = anetGenericAccept(err,s,(struct sockaddr*)&sa,&salen)) == ANET_ERR)
return ANET_ERR;
return fd;
}
int anetPeerToString(int fd, char *ip, int *port) {
struct sockaddr_in sa;
socklen_t salen = sizeof(sa);
if (getpeername(fd,(struct sockaddr*)&sa,&salen) == -1) {
*port = 0;
ip[0] = '?';
ip[1] = '\0';
return -1;
}
if (ip) strcpy(ip,inet_ntoa(sa.sin_addr));
if (port) *port = ntohs(sa.sin_port);
return 0;
}
int anetSockName(int fd, char *ip, int *port) {
struct sockaddr_in sa;
socklen_t salen = sizeof(sa);
if (getsockname(fd,(struct sockaddr*)&sa,&salen) == -1) {
*port = 0;
ip[0] = '?';
ip[1] = '\0';
return -1;
}
if (ip) strcpy(ip,inet_ntoa(sa.sin_addr));
if (port) *port = ntohs(sa.sin_port);
return 0;
}

59
dump1090/anet.h 100644
Wyświetl plik

@ -0,0 +1,59 @@
/* anet.c -- Basic TCP socket stuff made a bit less boring
*
* Copyright (c) 2006-2012, Salvatore Sanfilippo <antirez at gmail dot com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of Redis nor the names of its contributors may be used
* to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef ANET_H
#define ANET_H
#define ANET_OK 0
#define ANET_ERR -1
#define ANET_ERR_LEN 256
#if defined(__sun)
#define AF_LOCAL AF_UNIX
#endif
int anetTcpConnect(char *err, char *addr, int port);
int anetTcpNonBlockConnect(char *err, char *addr, int port);
int anetUnixConnect(char *err, char *path);
int anetUnixNonBlockConnect(char *err, char *path);
int anetRead(int fd, char *buf, int count);
int anetResolve(char *err, char *host, char *ipbuf);
int anetTcpServer(char *err, int port, char *bindaddr);
int anetUnixServer(char *err, char *path, mode_t perm);
int anetTcpAccept(char *err, int serversock, char *ip, int *port);
int anetUnixAccept(char *err, int serversock);
int anetWrite(int fd, char *buf, int count);
int anetNonBlock(char *err, int fd);
int anetTcpNoDelay(char *err, int fd);
int anetTcpKeepAlive(char *err, int fd);
int anetPeerToString(int fd, char *ip, int *port);
int anetSetSendBuffer(char *err, int fd, int buffsize);
#endif

2636
dump1090/dump1090.c 100644

Plik diff jest za duży Load Diff

180
dump1090/gmap.html 100644
Wyświetl plik

@ -0,0 +1,180 @@
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="initial-scale=1.0, user-scalable=no" />
<style type="text/css">
html { height: 100% }
body { height: 100%; margin: 0; padding: 0 }
#map_canvas { height: 100% }
#info {
position: absolute;
width:20%;
height:100%;
bottom:0px;
right:0px;
top:0px;
background-color: white;
border-left:1px #666 solid;
font-family:Helvetica;
}
#info div {
padding:0px;
padding-left:10px;
margin:0px;
}
#info div h1 {
margin-top:10px;
font-size:16px;
}
#info div p {
font-size:14px;
color:#333;
}
</style>
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js">
</script>
<script type="text/javascript"
src="https://maps.googleapis.com/maps/api/js?sensor=true">
</script>
<script type="text/javascript">
Map=null;
CenterLat=45.0;
CenterLon=9.0;
Planes={};
NumPlanes = 0;
Selected=null
function getIconForPlane(plane) {
var r = 255, g = 255, b = 0;
var maxalt = 40000; /* Max altitude in the average case */
var invalt = maxalt-plane.altitude;
var selected = (Selected == plane.hex);
if (invalt < 0) invalt = 0;
b = parseInt(255/maxalt*invalt);
return {
strokeWeight: (selected ? 2 : 1),
path: google.maps.SymbolPath.FORWARD_CLOSED_ARROW,
scale: 5,
fillColor: 'rgb('+r+','+g+','+b+')',
fillOpacity: 0.9,
rotation: plane.track
};
}
function selectPlane() {
if (!Planes[this.planehex]) return;
var old = Selected;
Selected = this.planehex;
if (Planes[old]) {
/* Remove the highlight in the previously selected plane. */
Planes[old].marker.setIcon(getIconForPlane(Planes[old]));
}
Planes[Selected].marker.setIcon(getIconForPlane(Planes[Selected]));
refreshSelectedInfo();
}
function refreshGeneralInfo() {
var i = document.getElementById('geninfo');
i.innerHTML = NumPlanes+' planes on screen.';
}
function refreshSelectedInfo() {
var i = document.getElementById('selinfo');
var p = Planes[Selected];
if (!p) return;
var html = 'ICAO: '+p.hex+'<br>';
if (p.flight.length) {
html += '<b>'+p.flight+'</b><br>';
}
html += 'Altitude: '+p.altitude+' feet<br>';
html += 'Speed: '+p.speed+' knots<br>';
html += 'Coordinates: '+p.lat+', '+p.lon+'<br>';
i.innerHTML = html;
}
function fetchData() {
$.getJSON('/data.json', function(data) {
var stillhere = {}
for (var j=0; j < data.length; j++) {
var plane = data[j];
var marker = null;
stillhere[plane.hex] = true;
plane.flight = $.trim(plane.flight);
if (Planes[plane.hex]) {
var myplane = Planes[plane.hex];
marker = myplane.marker;
var icon = marker.getIcon();
var newpos = new google.maps.LatLng(plane.lat, plane.lon);
marker.setPosition(newpos);
marker.setIcon(getIconForPlane(plane));
myplane.altitude = plane.altitude;
myplane.speed = plane.speed;
myplane.lat = plane.lat;
myplane.lon = plane.lon;
myplane.track = plane.track;
myplane.flight = plane.flight;
if (myplane.hex == Selected)
refreshSelectedInfo();
} else {
marker = new google.maps.Marker({
position: new google.maps.LatLng(plane.lat, plane.lon),
map: Map,
icon: getIconForPlane(plane)
});
plane.marker = marker;
marker.planehex = plane.hex;
Planes[plane.hex] = plane;
/* Trap clicks for this marker. */
google.maps.event.addListener(marker, 'click', selectPlane);
}
if (plane.flight.length == 0)
marker.setTitle(plane.hex)
else
marker.setTitle(plane.flight+' ('+plane.hex+')')
}
NumPlanes = data.length;
/* Remove idle planes. */
for (var p in Planes) {
if (!stillhere[p]) {
Planes[p].marker.setMap(null);
delete Planes[p];
}
}
});
}
function initialize() {
var mapOptions = {
center: new google.maps.LatLng(CenterLat, CenterLon),
zoom: 5,
mapTypeId: google.maps.MapTypeId.ROADMAP
};
Map = new google.maps.Map(document.getElementById("map_canvas"), mapOptions);
/* Setup our timer to poll from the server. */
window.setInterval(function() {
fetchData();
refreshGeneralInfo();
}, 1000);
}
</script>
</head>
<body onload="initialize()">
<div id="map_canvas" style="width:80%; height:100%"></div>
<div id="info">
<div>
<h1>Dump1090</h1>
<p id="geninfo"></p>
<p id="selinfo">Click on a plane for info.</p>
</div>
</div>
</body>
</html>

File diff suppressed because one or more lines are too long

Wyświetl plik

@ -0,0 +1,193 @@
<!DOCTYPE html>
<html>
<body>
<head>
<script>
var frames = [];
var currentFrame = 0;
var modes_checksum_table = [
0x3935ea, 0x1c9af5, 0xf1b77e, 0x78dbbf, 0xc397db, 0x9e31e9, 0xb0e2f0, 0x587178,
0x2c38bc, 0x161c5e, 0x0b0e2f, 0xfa7d13, 0x82c48d, 0xbe9842, 0x5f4c21, 0xd05c14,
0x682e0a, 0x341705, 0xe5f186, 0x72f8c3, 0xc68665, 0x9cb936, 0x4e5c9b, 0xd8d449,
0x939020, 0x49c810, 0x24e408, 0x127204, 0x093902, 0x049c81, 0xfdb444, 0x7eda22,
0x3f6d11, 0xe04c8c, 0x702646, 0x381323, 0xe3f395, 0x8e03ce, 0x4701e7, 0xdc7af7,
0x91c77f, 0xb719bb, 0xa476d9, 0xadc168, 0x56e0b4, 0x2b705a, 0x15b82d, 0xf52612,
0x7a9309, 0xc2b380, 0x6159c0, 0x30ace0, 0x185670, 0x0c2b38, 0x06159c, 0x030ace,
0x018567, 0xff38b7, 0x80665f, 0xbfc92b, 0xa01e91, 0xaff54c, 0x57faa6, 0x2bfd53,
0xea04ad, 0x8af852, 0x457c29, 0xdd4410, 0x6ea208, 0x375104, 0x1ba882, 0x0dd441,
0xf91024, 0x7c8812, 0x3e4409, 0xe0d800, 0x706c00, 0x383600, 0x1c1b00, 0x0e0d80,
0x0706c0, 0x038360, 0x01c1b0, 0x00e0d8, 0x00706c, 0x003836, 0x001c1b, 0xfff409,
0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000,
0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000,
0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000
];
function modesChecksum(frame) {
var crc = 0;
var bits = frame.bits;
var offset = (bits == 112) ? 0 : (112-56);
for(var j = 0; j < bits; j++) {
var byte = j/8;
var bit = j%8;
var bitmask = 1 << (7-bit);
/* If bit is set, xor with corresponding table entry. */
if (frame.hex.charCodeAt(byte) & bitmask)
crc ^= modes_checksum_table[j+offset];
}
return crc; /* 24 bit checksum. */
}
function getFrameChecksum(frame) {
var res = "";
for (j = 0; j < frame.hex.length; j++) {
var val = frame.hex.charCodeAt(j);
var h = val.toString(16);
if (h.length == 1) h = "0"+h;
res += h;
}
return res;
}
function displayFrame(i) {
var div = document.getElementById("frame");
var msgbits = 8+112;
var frame = frames[i];
var padding = frame.mag.length - msgbits*2;
/* Remove the old representation. */
var nodes = div.childNodes.length;
for(var j = 0; j < nodes; j++) {
div.removeChild(div.firstChild);
}
/* Display the new one. */
for (var j = -padding; j < msgbits*2+padding; j++) {
var m = frame.mag[j+padding];
var type;
if (j < 0) type = "noise";
if (j >= 0 && j < 16) type = "pre";
if (j >= 16) {
if (!(j % 2)) {
var next = frame.mag[j+padding+1];
if (m > next)
type = "one";
else
type = "zero";
}
var bit = (j-16)/2;
if (bit == frame.fix1 ||
bit == frame.fix2)
type = "err";
}
var sample = document.createElement("div");
sample.setAttribute("class","sample "+type);
sample.setAttribute("title","sample "+j+" ("+m+")");
sample.style.left = ""+((j+padding)*4)+"px";
sample.style.height = ""+(m/256)+"px";
div.appendChild(sample);
}
document.getElementById("info").innerHTML =
"#"+currentFrame+" "+frame.descr+"<br>"+
"Bits:"+frame.bits+"<br>"+
"DF : "+(frame.hex.charCodeAt(0) >> 3)+"<br>"+
"fix1: "+frame.fix1+"<br>"+
"fix2: "+frame.fix2+"<br>"+
"hex : "+getFrameChecksum(frame)+"<br>"+
"crc (computed): "+modesChecksum(frame).toString(16)+"<br>";
}
function recomputeHex(frame) {
var padding = frame.mag.length - (112+8)*2;
var b = [];
var hex = "";
/* Get bits */
for (var j = 0; j < frame.bits*2; j += 2) {
var bit;
var l = frame.mag[padding+j+16];
var r = frame.mag[padding+j+1+16];
if (l > r)
bit = 1;
else
bit = 0;
b.push(bit);
}
/* Pack into bytes */
for (j = 0; j < frame.bits; j+= 8) {
hex += String.fromCharCode(
b[j]<<7 |
b[j+1]<<6 |
b[j+2]<<5 |
b[j+3]<<4 |
b[j+4]<<3 |
b[j+5]<<2 |
b[j+6]<<1 |
b[j+7]);
}
frame.hex = hex;
}
window.onload = function() {
document.getElementById("next").onclick = function() {
if (currentFrame != frames.length-1) currentFrame++;
displayFrame(currentFrame);
}
document.getElementById("prev").onclick = function() {
if (currentFrame != 0) currentFrame--;
displayFrame(currentFrame);
}
document.getElementById("re").onclick = function() {
recomputeHex(frames[currentFrame]);
displayFrame(currentFrame);
}
displayFrame(currentFrame);
}
</script>
<script src="frames.js"></script>
<style>
#frame {
width: 1024px;
height: 255px;
border: 1px #aaa solid;
position: relative;
}
.sample {
position: absolute;
bottom: 0px;
}
.pre {
width:4px;
background-color: orange;
}
.one {
width:4px;
background-color: #0000cc;
}
.zero {
width:4px;
background-color: #aaaaaa;
}
.err {
width:4px;
background-color: #cc6666;
}
.noise {
width:2px;
background-color: #ffffff;
border: 1px #aaa dotted;
}
</style>
</head>
<div id="frame">
</div>
<pre id="info">
</pre>
<input type="button" id="prev" value="Prev frame">
<input type="button" id="next" value="Next frame">
<input type="button" id="re" value="Recompute Hex">
</body>
</html>