kopia lustrzana https://github.com/cyoung/stratux
Merge branch 'master' of https://github.com/cyoung/stratux
commit
6de59749f0
|
@ -1,3 +0,0 @@
|
||||||
[submodule "dump1090"]
|
|
||||||
path = dump1090
|
|
||||||
url = https://github.com/antirez/dump1090
|
|
1
dump1090
1
dump1090
|
@ -1 +0,0 @@
|
||||||
Subproject commit 823631979b74f83caa48da69c86f8967e4c17c47
|
|
|
@ -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
|
|
@ -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.
|
|
@ -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.
|
|
@ -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;
|
||||||
|
}
|
|
@ -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
|
Plik diff jest za duży
Load Diff
|
@ -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
|
@ -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>
|
Ładowanie…
Reference in New Issue