more Readme edits and file cleanup

Former-commit-id: 6953975a19bc00dd58b4ec8881df6f8788a374d4
Former-commit-id: 81667ba89b5356b649b7e74b07636fe49b19814e
This commit is contained in:
nathan 2020-06-08 15:57:11 -07:00
parent bf3e7d42d7
commit dba4babbd2
79 changed files with 42 additions and 12249 deletions

5
.gitignore vendored
View file

@ -2,9 +2,8 @@
*.bin *.bin
*.svg *.svg
view1090
map1090
*.swp *.swp
.~ .~
thumbs.db thumbs.db
viz1090

View file

@ -7,13 +7,13 @@ CFLAGS=-O2 -g -Wno-write-strings
LIBS=-lm -lSDL2 -lSDL2_ttf -lSDL2_gfx LIBS=-lm -lSDL2 -lSDL2_ttf -lSDL2_gfx
CC=g++ CC=g++
all: map1090 all: viz1090
%.o: %.c %.cpp %.o: %.c %.cpp
$(CC) $(CFLAGS) $(EXTRACFLAGS) -c $< $(CC) $(CFLAGS) $(EXTRACFLAGS) -c $<
map1090: map1090.o AppData.o AircraftList.o Aircraft.o anet.o interactive.o mode_ac.o mode_s.o net_io.o Input.o View.o Map.o parula.o monokai.o viz1090: viz1090.o AppData.o AircraftList.o Aircraft.o anet.o interactive.o mode_ac.o mode_s.o net_io.o Input.o View.o Map.o parula.o monokai.o
$(CC) -g -o map1090 map1090.o AppData.o AircraftList.o Aircraft.o anet.o interactive.o mode_ac.o mode_s.o net_io.o Input.o View.o Map.o parula.o monokai.o $(LIBS) $(LDFLAGS) $(CC) -g -o viz1090 viz1090.o AppData.o AircraftList.o Aircraft.o anet.o interactive.o mode_ac.o mode_s.o net_io.o Input.o View.o Map.o parula.o monokai.o $(LIBS) $(LDFLAGS)
clean: clean:
rm -f *.o map1090 rm -f *.o viz1090

View file

@ -1,5 +1,12 @@
# viz1090 # viz1090
**This is work in progress**
There are a lot of missing pieces in this implementation so far:
* A proper map system yet. Eventually map data should be pulled from Mapbox or similar.
* In-application menus or configuration yet.
* Theming/colormaps (important as this is primarily intended to be eye candy!)
* Integration with handheld features like GPS, battery monitors, buttons/dials, etc.
* Android build is currently broken
### BUILDING ### BUILDING
@ -26,9 +33,9 @@ make clean; make
``` ```
3. Download and process map data 3. Download and process map data
Until more comprehensive map source (e.g., Mapbox) is integrated, map1090 uses the lat/lon SVG files from https://www.mccurley.org Until more comprehensive map source (e.g., Mapbox) is integrated, viz1090 uses the lat/lon SVG files from https://www.mccurley.org
The getmap.sh pulls the svg file for the contiguous 48 US states and produces a binary file for map1090 to read. The getmap.sh pulls the svg file for the contiguous 48 US states and produces a binary file for viz1090 to read.
``` ```
sudo apt install python3 python3-pip sudo apt install python3 python3-pip
@ -40,7 +47,14 @@ pip3 install lxml numpy
As WSL does not have an X server built in, you will need to install a 3rd party X server, such as https://sourceforge.net/projects/vcxsrv/ As WSL does not have an X server built in, you will need to install a 3rd party X server, such as https://sourceforge.net/projects/vcxsrv/
When running vcxsrv Xlaunch, make sure to **uncheck "Use Native openGL"** * run Xlaunch from the start menu
* Uncheck "Use Native openGL"
* Open the Ubuntu WSL terminal
* Specify the X display to use
```
export DISPLAY=:0
```
* Start viz1090 as described below.
### RUNNING ### RUNNING
@ -49,17 +63,17 @@ When running vcxsrv Xlaunch, make sure to **uncheck "Use Native openGL"**
dump1090 --net dump1090 --net
``` ```
2. Run map1090 2. Run viz1090
``` ```
./view1090 --fullsceen --lat [your latitude] --lon [your longitude] ./viz1090 --fullsceen --lat [your latitude] --lon [your longitude]
``` ```
map1090 will open an SDL window set to the resolution of your screen. viz1090 will open an SDL window set to the resolution of your screen.
### RUNTIME OPTIONS ### RUNTIME OPTIONS
--server [domain name or ip] Specify a dump1090 server. Renamed from the view1090 "--net-bo-ip-addr" argument --server [domain name or ip] Specify a dump1090 server. Renamed from the viz1090 "--net-bo-ip-addr" argument
--port [port number] Specify dump1090 server port. Renamed from the view1090 "--net-bo-port" argument --port [port number] Specify dump1090 server port. Renamed from the viz1090 "--net-bo-port" argument
--metric Display metric units rather than imperial. --metric Display metric units rather than imperial.
--lat Specify your latitude in degrees --lat Specify your latitude in degrees
@ -71,27 +85,28 @@ map1090 will open an SDL window set to the resolution of your screen.
### HARDWARE NOTES ### HARDWARE NOTES
map1090 is designed to be portable and work on a variety of systems, however it is intended to be used on a handheld device. This software was originally intended for Raspberry Pi devices, and it is currently optimized for the Raspberry Pi 4 with the following configuration:
The software was originally develped for Raspberry Pi devices, and it is currently optimized for the Raspberry Pi 4 with the following configuration:
* Raspberry Pi 4 * Raspberry Pi 4
* A display: * A display:
* [Pimoroni HyperPixel 4.0 Display] (https://shop.pimoroni.com/products/hyperpixel-4) \*best overall, but requires some rework to use battery monitoring features of the PiJuice mentioned below * [Pimoroni HyperPixel 4.0 Display](https://shop.pimoroni.com/products/hyperpixel-4) \*best overall, but requires some rework to use battery monitoring features of the PiJuice mentioned below
* [Waveshare 5.5" AMOLED] (https://www.waveshare.com/5.5inch-hdmi-amoled.htm) \*this is very good screen but the Google Pixel 2 phone mentioned below has a very similar display for the same price (along with everything else you need in a nice package) * [Waveshare 5.5" AMOLED](https://www.waveshare.com/5.5inch-hdmi-amoled.htm) \*this is very good screen but the Google Pixel 2 phone mentioned below has a very similar display for the same price (along with everything else you need in a nice package)
* [Waveshare 4.3" HDMI(B)] (https://www.waveshare.com/wiki/4.3inch_HDMI_LCD_(B)) * [Waveshare 4.3" HDMI(B)](https://www.waveshare.com/wiki/4.3inch_HDMI_LCD_(B))
* [Adafruit 2.8" Capacitive Touch] (https://www.adafruit.com/product/2423) * [Adafruit 2.8" Capacitive Touch](https://www.adafruit.com/product/2423)
* A battery hat, such as: * A battery hat, such as:
* [PiJuice Battery Hat] (https://uk.pi-supply.com/products/pijuice-standard) \*I2C pins must be reworked to connect to the Hyperpixel nonstandard I2C breakout pins, unfortunately * [PiJuice Battery Hat](https://uk.pi-supply.com/products/pijuice-standard) \*I2C pins must be reworked to connect to the Hyperpixel nonstandard I2C breakout pins, unfortunately
* [MakerFocus UPS Hat] (https://www.amazon.com/Makerfocus-Raspberry-2500mAh-Lithium-Battery/dp/B01MQYX4UX) * [MakerFocus UPS Hat](https://www.amazon.com/Makerfocus-Raspberry-2500mAh-Lithium-Battery/dp/B01MQYX4UX)
* Any USB SDR receiver: * Any USB SDR receiver:
* [Noelec Nano V3] (https://www.nooelec.com/store/nesdr-nano-three.html) * [Noelec Nano V3](https://www.nooelec.com/store/nesdr-nano-three.html)
* Stratux V2 \*very low power but hard to find * Stratux V2 \*very low power but hard to find
If running as a front end only, with a separate dump1090 server, the best option is to use an Android phone, such as the Pixel 2, which significantly outperforms a Raspberry Pi 4. If running as a front end only, with a separate dump1090 server, the best option is to use an Android phone, such as the Pixel 2, which significantly outperforms a Raspberry Pi 4.
map1090 has been tested on other boards such as the UP Core and UP Squared, but these boards have significantly poorer performance than the Raspberry Pi 4 with less software and peripheral support, so they are not recommended. With low resolution maps the software will run on these boards or even a Raspberry Pi Zero, so these remain options with some tradeoffs. viz1090 has been tested on other boards such as the UP Core and UP Squared, but these boards have poor performance compared to a Raspberry Pi 4, along with worse software and peripheral support, so they are not recommended. viz1090 with a low resolution map will run on these boards or even a Raspberry Pi Zero, so these remain options with some tradeoffs.
Of course, a variety of other devices work well for this purpose - all of the development so far has been done on a touchscreen Dell XPS laptop. Of course, a variety of other devices work well for this purpose - all of the development so far has been done on a touchscreen Dell XPS laptop.
### Credits
viz1090 is largely based on [dump1090](https://github.com/MalcolmRobb/dump1090) (Malcom Robb, Salvatore Sanfilippo)

37
TODO.md
View file

@ -1,37 +0,0 @@
todo
UI stuff
+tap on plane sets plane to active
+animated recenter to active
+toggle follow and orient (and other popup info?)
double tap to zoom
animated label show and hide
+draw map to texture and only redraw on move
color themes (requires settings load)
settings (button popups or panes, sliders, etc)
battery level (need separate linux/win/android)
Utility stuff
+map load (and write from python) --> start by reducing lat/lon precision to 4 or 5 decimal places and change storage to float instead of double
libconfig load settings
Platforms
migrate Android project into main repo
SDL_AndroidGetJNIEnv() to access parameters, system info, etc
windows
naming
viz1090
map1090
sdl1090

View file

@ -1,21 +0,0 @@
Android build notes
This example works:
https://github.com/pvallet/hello-sdl2-android
the only JDK that seems to work is oracle-java8-installer, discontinued but available as of 2/18/2020 from
sudo add-apt-repository ppa:ts.sch.gr/ppa
sudo apt-get update
sudo apt-get install oracle-java8-installer
per https://askubuntu.com/questions/1139387/update-to-latest-version-of-java-after-ppa-is-discontinued
SDL2, SDL2_gfx, SDL2_ttf official need to go in external
SDL2_gfx official doesn't have Android.mk, but this one does:
https://github.com/keera-studios/SDL2_gfx
App parameters are in android/app/src/main/java/[pvallet/com/github/hellosdl2/helloSDL2Activity.java] (network access, fullscreen immersive mode"
Resources (fonts etc) need to go in android/app/src/main/res
build settings (arch, android version) are in android/AndroidManifest.xml AND android/SDL2/src/main/AndroidManifest.xml (not sure if the second one needs to be changed)

View file

@ -1 +0,0 @@
6c9ac166c74d8d6e7d80eaa3f318cc32e1c83140

Binary file not shown.

Before

Width:  |  Height:  |  Size: 20 KiB

View file

@ -1 +0,0 @@
c0d04ee4985a78dfc389debfb93114ff8e33e7bb

View file

@ -1 +0,0 @@
gcc -I /usr/include/libusb-1.0 -I ./convenience/ -I ./getopt -shared -Wl,-soname,rtl_fm_python -o rtl_fm_python.so -fPIC rtl_fm_python.c convenience/convenience.c getopt/getopt.c -lrtlsdr

View file

@ -1,92 +0,0 @@
#include "DigiKeyboard.h"
#define encoder0PinA 0
#define encoder0PinB 2
#define aIn //5 is 0 on the digistump
#define avgPeriod 100
static boolean rotating=false;
float avgRead = 0;
float lastRead = 0;
unsigned char avgCount = 0;
float buttonState = 0;
bool lastButtonState = 0;
int rotIncrement = 0;
void setup() {
pinMode(encoder0PinA, INPUT);
digitalWrite(encoder0PinA, HIGH);
pinMode(encoder0PinB, INPUT);
digitalWrite(encoder0PinB, HIGH);
pinMode(1, INPUT);
digitalWrite(1, HIGH);
attachInterrupt(0, rotEncoder, CHANGE);
}
void rotEncoder(){
rotating=true;
}
void loop() {
DigiKeyboard.update();
avgRead += (float)analogRead(0) / avgPeriod;
avgCount++;
buttonState += (float)digitalRead(1) / avgPeriod;
if(avgCount >= avgPeriod) {
if(abs(avgRead - lastRead) >= 1) {
DigiKeyboard.print(String((int)avgRead, HEX));
DigiKeyboard.println("");
lastRead = avgRead;
}
if((buttonState > .5) != lastButtonState) {
lastButtonState = (buttonState > .5);
if(lastButtonState) {
DigiKeyboard.print("n");
} else {
DigiKeyboard.print("m");
}
}
avgRead = 0;
avgCount = 0;
buttonState = 0;
}
while(rotating) {
delay(2);
if (digitalRead(encoder0PinA) == digitalRead(encoder0PinB)) {
rotIncrement++;
}
else {
rotIncrement--;
}
rotating=false; // Reset the flag back to false
}
if(rotIncrement >= 2) {
DigiKeyboard.print("z");
rotIncrement = 0;
}
if(rotIncrement <= -2) {
DigiKeyboard.print("x");
rotIncrement = 0;
}
}

View file

@ -1,125 +0,0 @@
#include "DigiKeyboard.h"
#define encoderPinA 0
#define encoderPinB 2
#define selectPin 1
#define sqlPin 0 //5 is 0 on the digistump
#define bufferPeriod 100
float encoderPinABuffer = 0;
float encoderPinBBuffer = 0;
float selectPinBuffer = 0;
float sqlPinBuffer = 0;
int encoderCounter = 0;
bool encoderPinALast = 0;
bool encoderPinBLast = 0;
bool selectPinLast = 0;
float sqlPinLast = 0;
int bufferCounter = 0;
int8_t lookup_table[] = {0,-1,1,0,1,0,0,-1,-1,0,0,1,0,1,-1,0};
uint8_t index = 0;
void setup() {
pinMode(encoderPinA, INPUT);
digitalWrite(encoderPinA, HIGH);
pinMode(encoderPinB, INPUT);
digitalWrite(encoderPinB, HIGH);
pinMode(selectPin, INPUT);
digitalWrite(selectPin, HIGH);
pinMode(sqlPin, INPUT);
}
void loop() {
//update buffers
//encoderPinABuffer += (float)digitalRead(encoderPinA) / bufferPeriod;
//encoderPinBBuffer += (float)digitalRead(encoderPinB) / bufferPeriod;
selectPinBuffer += (float)digitalRead(selectPin) / bufferPeriod;
sqlPinBuffer += (float)analogRead(sqlPin) / bufferPeriod;
bufferCounter++;
bool encoderPinAState = (bool)digitalRead(encoderPinA);
bool encoderPinBState = (bool)digitalRead(encoderPinB);
if((encoderPinAState != encoderPinALast) | (encoderPinBState != encoderPinBLast)) {
index = (index << 2) & 0b1100;
index = index | ((encoderPinAState << 1) + encoderPinBState);
encoderCounter += lookup_table[index & 0b1111];
if(encoderCounter > 2) {
DigiKeyboard.print("z");
encoderCounter = 0;
}
if(encoderCounter < -2) {
DigiKeyboard.print("x");
encoderCounter = 0;
}
encoderPinALast = encoderPinAState;
encoderPinBLast = encoderPinBState;
}
//check pin values
if(bufferCounter > bufferPeriod) {
//usb keepalive
DigiKeyboard.update();
//bool encoderPinAState = encoderPinABuffer > .5;
//bool encoderPinBState = encoderPinBBuffer > .5;
bool selectPinState = selectPinBuffer > .5;
//check encoder pins nd transmit
// if(encoderPinAState != encoderPinALast || encoderPinBState != encoderPinBLast) {
//
// uint8_t index = (encoderPinALast << 4) + (encoderPinBLast << 3) + (encoderPinAState << 1) + encoderPinBState;
//
// //encoderDetentCounter += lookup_table[index];
//
// if(lookup_table[index] > 0) {
// DigiKeyboard.print("z");
// } else if (lookup_table[index] < 0) {
// DigiKeyboard.print("x");
// }
//
// encoderPinALast = encoderPinAState;
// encoderPinBLast = encoderPinBState;
// }
//check select pin and transmit
if(selectPinState != selectPinLast) {
selectPinLast = selectPinState;
if(selectPinLast) {
DigiKeyboard.print("n");
} else {
DigiKeyboard.print("m");
}
}
//check squelch knob and transmit
if(abs(sqlPinBuffer - sqlPinLast) >= 1) {
DigiKeyboard.print(String((int)sqlPinBuffer, HEX));
DigiKeyboard.println("");
sqlPinLast = sqlPinBuffer;
}
// reset buffers
encoderPinABuffer = 0;
encoderPinBBuffer = 0;
selectPinBuffer = 0;
sqlPinBuffer = 0;
bufferCounter = 0;
}
}

View file

@ -1 +0,0 @@
For information on installing libraries, see: http://www.arduino.cc/en/Guide/Libraries

View file

@ -1,4 +0,0 @@
#!/bin/sh
gpio -g mode 18 pwm
gpio -g pwm 18 100

View file

@ -1,2 +0,0 @@
*.o
dump1090

View file

@ -1,30 +0,0 @@
#
# When building a package or installing otherwise in the system, make
# sure that the variable PREFIX is defined, e.g. make PREFIX=/usr/local
#
PROGNAME=dump1090
ifdef PREFIX
BINDIR=$(PREFIX)/bin
SHAREDIR=$(PREFIX)/share/$(PROGNAME)
EXTRACFLAGS=-DHTMLPATH=\"$(SHAREDIR)\"
endif
CFLAGS=-O2 -g -Wall -W `pkg-config --cflags librtlsdr`
LIBS=`pkg-config --libs librtlsdr` -lpthread -lm
CC=gcc
all: dump1090 view1090
%.o: %.c
$(CC) $(CFLAGS) $(EXTRACFLAGS) -c $<
dump1090: dump1090.o anet.o interactive.o mode_ac.o mode_s.o net_io.o
$(CC) -g -o dump1090 dump1090.o anet.o interactive.o mode_ac.o mode_s.o net_io.o $(LIBS) $(LDFLAGS)
view1090: view1090.o anet.o interactive.o mode_ac.o mode_s.o net_io.o
$(CC) -g -o view1090 view1090.o anet.o interactive.o mode_ac.o mode_s.o net_io.o $(LIBS) $(LDFLAGS)
clean:
rm -f *.o dump1090 view1090

View file

@ -1,284 +0,0 @@
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 recceiving raw data to/from connected clients
(using --net).
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 checks for decoding errors using the 24-bit CRC checksum,
where available. Messages with errors are discarded.
The --fix command line switch enables fixing single bit error correction
based on the CRC checksum. Technically, it uses a table of precomputed
checksum differences resulting from single bit errors to look up the
wrong bit position.
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 with CRC errors resulting from any two bit
errors.
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.

View file

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

View file

@ -1,345 +0,0 @@
/* 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 _WIN32
#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>
#else
#include "winstubs.h" //Put everything Windows specific in here
#include "dump1090.h"
#endif
#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;
#ifndef _WIN32
/* 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;
}
#else
flags = 1;
if (ioctlsocket(fd, FIONBIO, &flags)) {
errno = WSAGetLastError();
anetSetError(err, "ioctlsocket(FIONBIO): %s", strerror(errno));
return ANET_ERR;
}
#endif
return ANET_OK;
}
int anetTcpNoDelay(char *err, int fd)
{
int yes = 1;
if (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (void*)&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, (void*)&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, (void*)&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, (void*)&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) {
#ifdef _WIN32
errno = WSAGetLastError();
#endif
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, (void*)&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;
memset(&sa,0,sizeof(sa));
sa.sin_family = AF_INET;
sa.sin_port = htons((uint16_t)port);
if (inet_aton(addr, (void*)&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);
}
/* 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) {
#ifdef _WIN32
errno = WSAGetLastError();
#endif
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) {
#ifdef _WIN32
errno = WSAGetLastError();
#endif
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((uint16_t)port);
sa.sin_addr.s_addr = htonl(INADDR_ANY);
if (bindaddr && inet_aton(bindaddr, (void*)&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;
}
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) {
#ifndef _WIN32
if (errno == EINTR) {
continue;
#else
errno = WSAGetLastError();
if (errno == WSAEWOULDBLOCK) {
#endif
} else {
anetSetError(err, "accept: %s", strerror(errno));
}
}
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 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;
}

View file

@ -1,59 +0,0 @@
/* 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

View file

@ -1,6 +0,0 @@
// coaa.h configuration file for Plane Plotter Uploader
//
// You MUST apply via the COAA website for your own personal version of this file
// Do not disclose the contents of this file to anyone thereafter as it uniquely
// identifies you to the PlanePlotter system
//

Binary file not shown.

View file

@ -1 +0,0 @@
670d4181c3a6710f0becf3d4c232b386ee904bf1

View file

@ -1,904 +0,0 @@
// dump1090, a Mode S messages decoder for RTLSDR devices.
//
// Copyright (C) 2012 by Salvatore Sanfilippo <antirez@gmail.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.
//
// 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
// HOLDER 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 "coaa.h"
#include "dump1090.h"
//
// ============================= Utility functions ==========================
//
void sigintHandler(int dummy) {
MODES_NOTUSED(dummy);
signal(SIGINT, SIG_DFL); // reset signal handler - bit extra safety
Modes.exit = 1; // Signal to threads that we are done
}
//
// =============================== Terminal handling ========================
//
#ifndef _WIN32
// Get the number of rows after the terminal changes size.
int getTermRows() {
struct winsize w;
ioctl(STDOUT_FILENO, TIOCGWINSZ, &w);
return (w.ws_row);
}
// Handle resizing terminal
void sigWinchCallback() {
signal(SIGWINCH, SIG_IGN);
Modes.interactive_rows = getTermRows();
interactiveShowData();
signal(SIGWINCH, sigWinchCallback);
}
#else
int getTermRows() { return MODES_INTERACTIVE_ROWS;}
#endif
//
// =============================== Initialization ===========================
//
void modesInitConfig(void) {
// Default everything to zero/NULL
memset(&Modes, 0, sizeof(Modes));
// Now initialise things that should not be 0/NULL to their defaults
Modes.gain = MODES_MAX_GAIN;
Modes.freq = MODES_DEFAULT_FREQ;
Modes.ppm_error = MODES_DEFAULT_PPM;
Modes.check_crc = 1;
Modes.net_heartbeat_rate = MODES_NET_HEARTBEAT_RATE;
Modes.net_output_sbs_port = MODES_NET_OUTPUT_SBS_PORT;
Modes.net_output_raw_port = MODES_NET_OUTPUT_RAW_PORT;
Modes.net_input_raw_port = MODES_NET_INPUT_RAW_PORT;
Modes.net_output_beast_port = MODES_NET_OUTPUT_BEAST_PORT;
Modes.net_input_beast_port = MODES_NET_INPUT_BEAST_PORT;
Modes.net_http_port = MODES_NET_HTTP_PORT;
Modes.interactive_rows = getTermRows();
Modes.interactive_delete_ttl = MODES_INTERACTIVE_DELETE_TTL;
Modes.interactive_display_ttl = MODES_INTERACTIVE_DISPLAY_TTL;
Modes.fUserLat = MODES_USER_LATITUDE_DFLT;
Modes.fUserLon = MODES_USER_LONGITUDE_DFLT;
}
//
//=========================================================================
//
void modesInit(void) {
int i, q;
pthread_mutex_init(&Modes.pDF_mutex,NULL);
pthread_mutex_init(&Modes.data_mutex,NULL);
pthread_cond_init(&Modes.data_cond,NULL);
// Allocate the various buffers used by Modes
if ( ((Modes.icao_cache = (uint32_t *) malloc(sizeof(uint32_t) * MODES_ICAO_CACHE_LEN * 2) ) == NULL) ||
((Modes.pFileData = (uint16_t *) malloc(MODES_ASYNC_BUF_SIZE) ) == NULL) ||
((Modes.magnitude = (uint16_t *) malloc(MODES_ASYNC_BUF_SIZE+MODES_PREAMBLE_SIZE+MODES_LONG_MSG_SIZE) ) == NULL) ||
((Modes.maglut = (uint16_t *) malloc(sizeof(uint16_t) * 256 * 256) ) == NULL) ||
((Modes.beastOut = (char *) malloc(MODES_RAWOUT_BUF_SIZE) ) == NULL) ||
((Modes.rawOut = (char *) malloc(MODES_RAWOUT_BUF_SIZE) ) == NULL) )
{
fprintf(stderr, "Out of memory allocating data buffer.\n");
exit(1);
}
// Clear the buffers that have just been allocated, just in-case
memset(Modes.icao_cache, 0, sizeof(uint32_t) * MODES_ICAO_CACHE_LEN * 2);
memset(Modes.pFileData,127, MODES_ASYNC_BUF_SIZE);
memset(Modes.magnitude, 0, MODES_ASYNC_BUF_SIZE+MODES_PREAMBLE_SIZE+MODES_LONG_MSG_SIZE);
// Validate the users Lat/Lon home location inputs
if ( (Modes.fUserLat > 90.0) // Latitude must be -90 to +90
|| (Modes.fUserLat < -90.0) // and
|| (Modes.fUserLon > 360.0) // Longitude must be -180 to +360
|| (Modes.fUserLon < -180.0) ) {
Modes.fUserLat = Modes.fUserLon = 0.0;
} else if (Modes.fUserLon > 180.0) { // If Longitude is +180 to +360, make it -180 to 0
Modes.fUserLon -= 360.0;
}
// If both Lat and Lon are 0.0 then the users location is either invalid/not-set, or (s)he's in the
// Atlantic ocean off the west coast of Africa. This is unlikely to be correct.
// Set the user LatLon valid flag only if either Lat or Lon are non zero. Note the Greenwich meridian
// is at 0.0 Lon,so we must check for either fLat or fLon being non zero not both.
// Testing the flag at runtime will be much quicker than ((fLon != 0.0) || (fLat != 0.0))
Modes.bUserFlags &= ~MODES_USER_LATLON_VALID;
if ((Modes.fUserLat != 0.0) || (Modes.fUserLon != 0.0)) {
Modes.bUserFlags |= MODES_USER_LATLON_VALID;
}
// Limit the maximum requested raw output size to less than one Ethernet Block
if (Modes.net_output_raw_size > (MODES_RAWOUT_BUF_FLUSH))
{Modes.net_output_raw_size = MODES_RAWOUT_BUF_FLUSH;}
if (Modes.net_output_raw_rate > (MODES_RAWOUT_BUF_RATE))
{Modes.net_output_raw_rate = MODES_RAWOUT_BUF_RATE;}
if (Modes.net_sndbuf_size > (MODES_NET_SNDBUF_MAX))
{Modes.net_sndbuf_size = MODES_NET_SNDBUF_MAX;}
// Initialise the Block Timers to something half sensible
ftime(&Modes.stSystemTimeBlk);
for (i = 0; i < MODES_ASYNC_BUF_NUMBER; i++)
{Modes.stSystemTimeRTL[i] = Modes.stSystemTimeBlk;}
// Each I and Q value varies from 0 to 255, which represents a range from -1 to +1. To get from the
// unsigned (0-255) range you therefore subtract 127 (or 128 or 127.5) from each I and Q, giving you
// a range from -127 to +128 (or -128 to +127, or -127.5 to +127.5)..
//
// To decode the AM signal, you need the magnitude of the waveform, which is given by sqrt((I^2)+(Q^2))
// The most this could be is if I&Q are both 128 (or 127 or 127.5), so you could end up with a magnitude
// of 181.019 (or 179.605, or 180.312)
//
// However, in reality the magnitude of the signal should never exceed the range -1 to +1, because the
// values are I = rCos(w) and Q = rSin(w). Therefore the integer computed magnitude should (can?) never
// exceed 128 (or 127, or 127.5 or whatever)
//
// If we scale up the results so that they range from 0 to 65535 (16 bits) then we need to multiply
// by 511.99, (or 516.02 or 514). antirez's original code multiplies by 360, presumably because he's
// assuming the maximim calculated amplitude is 181.019, and (181.019 * 360) = 65166.
//
// So lets see if we can improve things by subtracting 127.5, Well in integer arithmatic we can't
// subtract half, so, we'll double everything up and subtract one, and then compensate for the doubling
// in the multiplier at the end.
//
// If we do this we can never have I or Q equal to 0 - they can only be as small as +/- 1.
// This gives us a minimum magnitude of root 2 (0.707), so the dynamic range becomes (1.414-255). This
// also affects our scaling value, which is now 65535/(255 - 1.414), or 258.433254
//
// The sums then become mag = 258.433254 * (sqrt((I*2-255)^2 + (Q*2-255)^2) - 1.414)
// or mag = (258.433254 * sqrt((I*2-255)^2 + (Q*2-255)^2)) - 365.4798
//
// We also need to clip mag just incaes any rogue I/Q values somehow do have a magnitude greater than 255.
//
for (i = 0; i <= 255; i++) {
for (q = 0; q <= 255; q++) {
int mag, mag_i, mag_q;
mag_i = (i * 2) - 255;
mag_q = (q * 2) - 255;
mag = (int) round((sqrt((mag_i*mag_i)+(mag_q*mag_q)) * 258.433254) - 365.4798);
Modes.maglut[(i*256)+q] = (uint16_t) ((mag < 65535) ? mag : 65535);
}
}
// Prepare error correction tables
modesInitErrorInfo();
}
//
// =============================== RTLSDR handling ==========================
//
void modesInitRTLSDR(void) {
int j;
int device_count;
char vendor[256], product[256], serial[256];
device_count = rtlsdr_get_device_count();
if (!device_count) {
fprintf(stderr, "No supported RTLSDR devices found.\n");
exit(1);
}
fprintf(stderr, "Found %d device(s):\n", device_count);
for (j = 0; j < device_count; j++) {
rtlsdr_get_device_usb_strings(j, vendor, product, serial);
fprintf(stderr, "%d: %s, %s, SN: %s %s\n", j, vendor, product, serial,
(j == Modes.dev_index) ? "(currently selected)" : "");
}
if (rtlsdr_open(&Modes.dev, Modes.dev_index) < 0) {
fprintf(stderr, "Error opening the RTLSDR device: %s\n",
strerror(errno));
exit(1);
}
// Set gain, frequency, sample rate, and reset the device
rtlsdr_set_tuner_gain_mode(Modes.dev,
(Modes.gain == MODES_AUTO_GAIN) ? 0 : 1);
if (Modes.gain != MODES_AUTO_GAIN) {
if (Modes.gain == MODES_MAX_GAIN) {
// Find the maximum gain available
int numgains;
int gains[100];
numgains = rtlsdr_get_tuner_gains(Modes.dev, gains);
Modes.gain = gains[numgains-1];
fprintf(stderr, "Max available gain is: %.2f\n", Modes.gain/10.0);
}
rtlsdr_set_tuner_gain(Modes.dev, Modes.gain);
fprintf(stderr, "Setting gain to: %.2f\n", Modes.gain/10.0);
} else {
fprintf(stderr, "Using automatic gain control.\n");
}
rtlsdr_set_freq_correction(Modes.dev, Modes.ppm_error);
if (Modes.enable_agc) rtlsdr_set_agc_mode(Modes.dev, 1);
rtlsdr_set_center_freq(Modes.dev, Modes.freq);
rtlsdr_set_sample_rate(Modes.dev, MODES_DEFAULT_RATE);
rtlsdr_reset_buffer(Modes.dev);
fprintf(stderr, "Gain reported by device: %.2f\n",
rtlsdr_get_tuner_gain(Modes.dev)/10.0);
}
//
//=========================================================================
//
// We use a thread reading data in background, while the main thread
// handles decoding and visualization of data to the user.
//
// The reading thread calls the RTLSDR API to read data asynchronously, and
// uses a callback to populate the data buffer.
//
// A Mutex is used to avoid races with the decoding thread.
//
void rtlsdrCallback(unsigned char *buf, uint32_t len, void *ctx) {
MODES_NOTUSED(ctx);
// Lock the data buffer variables before accessing them
pthread_mutex_lock(&Modes.data_mutex);
Modes.iDataIn &= (MODES_ASYNC_BUF_NUMBER-1); // Just incase!!!
// Get the system time for this block
ftime(&Modes.stSystemTimeRTL[Modes.iDataIn]);
if (len > MODES_ASYNC_BUF_SIZE) {len = MODES_ASYNC_BUF_SIZE;}
// Queue the new data
Modes.pData[Modes.iDataIn] = (uint16_t *) buf;
Modes.iDataIn = (MODES_ASYNC_BUF_NUMBER-1) & (Modes.iDataIn + 1);
Modes.iDataReady = (MODES_ASYNC_BUF_NUMBER-1) & (Modes.iDataIn - Modes.iDataOut);
if (Modes.iDataReady == 0) {
// Ooooops. We've just received the MODES_ASYNC_BUF_NUMBER'th outstanding buffer
// This means that RTLSDR is currently overwriting the MODES_ASYNC_BUF_NUMBER+1
// buffer, but we havent yet processed it, so we're going to lose it. There
// isn't much we can do to recover the lost data, but we can correct things to
// avoid any additional problems.
Modes.iDataOut = (MODES_ASYNC_BUF_NUMBER-1) & (Modes.iDataOut+1);
Modes.iDataReady = (MODES_ASYNC_BUF_NUMBER-1);
Modes.iDataLost++;
}
// Signal to the other thread that new data is ready, and unlock
pthread_cond_signal(&Modes.data_cond);
pthread_mutex_unlock(&Modes.data_mutex);
}
//
//=========================================================================
//
// This is used when --ifile is specified in order to read data from file
// instead of using an RTLSDR device
//
void readDataFromFile(void) {
pthread_mutex_lock(&Modes.data_mutex);
while(Modes.exit == 0) {
ssize_t nread, toread;
unsigned char *p;
if (Modes.iDataReady) {
pthread_cond_wait(&Modes.data_cond, &Modes.data_mutex);
continue;
}
if (Modes.interactive) {
// When --ifile and --interactive are used together, slow down
// playing at the natural rate of the RTLSDR received.
pthread_mutex_unlock(&Modes.data_mutex);
usleep(64000);
pthread_mutex_lock(&Modes.data_mutex);
}
toread = MODES_ASYNC_BUF_SIZE;
p = (unsigned char *) Modes.pFileData;
while(toread) {
nread = read(Modes.fd, p, toread);
if (nread <= 0) {
Modes.exit = 1; // Signal the other threads to exit.
break;
}
p += nread;
toread -= nread;
}
if (toread) {
// Not enough data on file to fill the buffer? Pad with no signal.
memset(p,127,toread);
}
Modes.iDataIn &= (MODES_ASYNC_BUF_NUMBER-1); // Just incase!!!
// Get the system time for this block
ftime(&Modes.stSystemTimeRTL[Modes.iDataIn]);
// Queue the new data
Modes.pData[Modes.iDataIn] = Modes.pFileData;
Modes.iDataIn = (MODES_ASYNC_BUF_NUMBER-1) & (Modes.iDataIn + 1);
Modes.iDataReady = (MODES_ASYNC_BUF_NUMBER-1) & (Modes.iDataIn - Modes.iDataOut);
// Signal to the other thread that new data is ready
pthread_cond_signal(&Modes.data_cond);
}
}
//
//=========================================================================
//
// We read data using a thread, so the main thread only handles decoding
// without caring about data acquisition
//
void *readerThreadEntryPoint(void *arg) {
MODES_NOTUSED(arg);
if (Modes.filename == NULL) {
rtlsdr_read_async(Modes.dev, rtlsdrCallback, NULL,
MODES_ASYNC_BUF_NUMBER,
MODES_ASYNC_BUF_SIZE);
} else {
readDataFromFile();
}
// Signal to the other thread that new data is ready - dummy really so threads don't mutually lock
pthread_cond_signal(&Modes.data_cond);
pthread_mutex_unlock(&Modes.data_mutex);
#ifndef _WIN32
pthread_exit(NULL);
#else
return NULL;
#endif
}
//
// ============================== Snip mode =================================
//
// Get raw IQ samples and filter everything is < than the specified level
// for more than 256 samples in order to reduce example file size
//
void snipMode(int level) {
int i, q;
uint64_t c = 0;
while ((i = getchar()) != EOF && (q = getchar()) != EOF) {
if (abs(i-127) < level && abs(q-127) < level) {
c++;
if (c > MODES_PREAMBLE_SIZE) continue;
} else {
c = 0;
}
putchar(i);
putchar(q);
}
}
//
// ================================ Main ====================================
//
void showHelp(void) {
printf(
"-----------------------------------------------------------------------------\n"
"| dump1090 ModeS Receiver Ver : " MODES_DUMP1090_VERSION " |\n"
"-----------------------------------------------------------------------------\n"
"--device-index <index> Select RTL device (default: 0)\n"
"--gain <db> Set gain (default: max gain. Use -10 for auto-gain)\n"
"--enable-agc Enable the Automatic Gain Control (default: off)\n"
"--freq <hz> Set frequency (default: 1090 Mhz)\n"
"--ifile <filename> Read data from file (use '-' for stdin)\n"
"--interactive Interactive mode refreshing data on screen\n"
"--interactive-rows <num> Max number of rows in interactive mode (default: 15)\n"
"--interactive-ttl <sec> Remove from list if idle for <sec> (default: 60)\n"
"--interactive-rtl1090 Display flight table in RTL1090 format\n"
"--raw Show only messages hex values\n"
"--net Enable networking\n"
"--modeac Enable decoding of SSR Modes 3/A & 3/C\n"
"--net-beast TCP raw output in Beast binary format\n"
"--net-only Enable just networking, no RTL device or file used\n"
"--net-bind-address <ip> IP address to bind to (default: Any; Use 127.0.0.1 for private)\n"
"--net-http-port <port> HTTP server port (default: 8080)\n"
"--net-ri-port <port> TCP raw input listen port (default: 30001)\n"
"--net-ro-port <port> TCP raw output listen port (default: 30002)\n"
"--net-sbs-port <port> TCP BaseStation output listen port (default: 30003)\n"
"--net-bi-port <port> TCP Beast input listen port (default: 30004)\n"
"--net-bo-port <port> TCP Beast output listen port (default: 30005)\n"
"--net-ro-size <size> TCP raw output minimum size (default: 0)\n"
"--net-ro-rate <rate> TCP raw output memory flush rate (default: 0)\n"
"--net-heartbeat <rate> TCP heartbeat rate in seconds (default: 60 sec; 0 to disable)\n"
"--net-buffer <n> TCP buffer size 64Kb * (2^n) (default: n=0, 64Kb)\n"
"--lat <latitude> Reference/receiver latitude for surface posn (opt)\n"
"--lon <longitude> Reference/receiver longitude for surface posn (opt)\n"
"--fix Enable single-bits error correction using CRC\n"
"--no-fix Disable single-bits error correction using CRC\n"
"--no-crc-check Disable messages with broken CRC (discouraged)\n"
"--phase-enhance Enable phase enhancement\n"
"--aggressive More CPU for more messages (two bits fixes, ...)\n"
"--mlat display raw messages in Beast ascii mode\n"
"--stats With --ifile print stats at exit. No other output\n"
"--stats-every <seconds> Show and reset stats every <seconds> seconds\n"
"--onlyaddr Show only ICAO addresses (testing purposes)\n"
"--metric Use metric units (meters, km/h, ...)\n"
"--snip <level> Strip IQ file removing samples < level\n"
"--debug <flags> Debug mode (verbose), see README for details\n"
"--quiet Disable output to stdout. Use for daemon applications\n"
"--ppm <error> Set receiver error in parts per million (default 0)\n"
"--help Show this help\n"
"\n"
"Debug mode flags: d = Log frames decoded with errors\n"
" D = Log frames decoded with zero errors\n"
" c = Log frames with bad CRC\n"
" C = Log frames with good CRC\n"
" p = Log frames with bad preamble\n"
" n = Log network debugging info\n"
" j = Log frames to frames.js, loadable by debug.html\n"
);
}
#ifdef _WIN32
void showCopyright(void) {
uint64_t llTime = time(NULL) + 1;
printf(
"-----------------------------------------------------------------------------\n"
"| dump1090 ModeS Receiver Ver : " MODES_DUMP1090_VERSION " |\n"
"-----------------------------------------------------------------------------\n"
"\n"
" Copyright (C) 2012 by Salvatore Sanfilippo <antirez@gmail.com>\n"
" Copyright (C) 2014 by Malcolm Robb <support@attavionics.com>\n"
"\n"
" All rights reserved.\n"
"\n"
" THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n"
" ""AS IS"" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n"
" LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n"
" A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n"
" HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n"
" SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\n"
" LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n"
" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n"
" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n"
" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n"
" OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n"
"\n"
" For further details refer to <https://github.com/MalcolmRobb/dump1090>\n"
"\n"
);
// delay for 1 second to give the user a chance to read the copyright
while (llTime >= time(NULL)) {}
}
#endif
static void display_stats(void) {
int j;
time_t now = time(NULL);
printf("\n\n");
if (Modes.interactive)
interactiveShowData();
printf("Statistics as at %s", ctime(&now));
printf("%d sample blocks processed\n", Modes.stat_blocks_processed);
printf("%d sample blocks dropped\n", Modes.stat_blocks_dropped);
printf("%d ModeA/C detected\n", Modes.stat_ModeAC);
printf("%d valid Mode-S preambles\n", Modes.stat_valid_preamble);
printf("%d DF-?? fields corrected for length\n", Modes.stat_DF_Len_Corrected);
printf("%d DF-?? fields corrected for type\n", Modes.stat_DF_Type_Corrected);
printf("%d demodulated with 0 errors\n", Modes.stat_demodulated0);
printf("%d demodulated with 1 error\n", Modes.stat_demodulated1);
printf("%d demodulated with 2 errors\n", Modes.stat_demodulated2);
printf("%d demodulated with > 2 errors\n", Modes.stat_demodulated3);
printf("%d with good crc\n", Modes.stat_goodcrc);
printf("%d with bad crc\n", Modes.stat_badcrc);
printf("%d errors corrected\n", Modes.stat_fixed);
for (j = 0; j < MODES_MAX_BITERRORS; j++) {
printf(" %d with %d bit %s\n", Modes.stat_bit_fix[j], j+1, (j==0)?"error":"errors");
}
if (Modes.phase_enhance) {
printf("%d phase enhancement attempts\n", Modes.stat_out_of_phase);
printf("%d phase enhanced demodulated with 0 errors\n", Modes.stat_ph_demodulated0);
printf("%d phase enhanced demodulated with 1 error\n", Modes.stat_ph_demodulated1);
printf("%d phase enhanced demodulated with 2 errors\n", Modes.stat_ph_demodulated2);
printf("%d phase enhanced demodulated with > 2 errors\n", Modes.stat_ph_demodulated3);
printf("%d phase enhanced with good crc\n", Modes.stat_ph_goodcrc);
printf("%d phase enhanced with bad crc\n", Modes.stat_ph_badcrc);
printf("%d phase enhanced errors corrected\n", Modes.stat_ph_fixed);
for (j = 0; j < MODES_MAX_BITERRORS; j++) {
printf(" %d with %d bit %s\n", Modes.stat_ph_bit_fix[j], j+1, (j==0)?"error":"errors");
}
}
printf("%d total usable messages\n", Modes.stat_goodcrc + Modes.stat_ph_goodcrc + Modes.stat_fixed + Modes.stat_ph_fixed);
fflush(stdout);
Modes.stat_blocks_processed =
Modes.stat_blocks_dropped = 0;
Modes.stat_ModeAC =
Modes.stat_valid_preamble =
Modes.stat_DF_Len_Corrected =
Modes.stat_DF_Type_Corrected =
Modes.stat_demodulated0 =
Modes.stat_demodulated1 =
Modes.stat_demodulated2 =
Modes.stat_demodulated3 =
Modes.stat_goodcrc =
Modes.stat_badcrc =
Modes.stat_fixed = 0;
Modes.stat_out_of_phase =
Modes.stat_ph_demodulated0 =
Modes.stat_ph_demodulated1 =
Modes.stat_ph_demodulated2 =
Modes.stat_ph_demodulated3 =
Modes.stat_ph_goodcrc =
Modes.stat_ph_badcrc =
Modes.stat_ph_fixed = 0;
for (j = 0; j < MODES_MAX_BITERRORS; j++) {
Modes.stat_ph_bit_fix[j] = 0;
Modes.stat_bit_fix[j] = 0;
}
}
//
//=========================================================================
//
// This function is called a few times every second by main in order to
// perform tasks we need to do continuously, like accepting new clients
// from the net, refreshing the screen in interactive mode, and so forth
//
void backgroundTasks(void) {
static time_t next_stats;
if (Modes.net) {
modesReadFromClients();
}
// If Modes.aircrafts is not NULL, remove any stale aircraft
if (Modes.aircrafts) {
interactiveRemoveStaleAircrafts();
}
// Refresh screen when in interactive mode
if (Modes.interactive) {
interactiveShowData();
}
if (Modes.stats > 0) {
time_t now = time(NULL);
if (now > next_stats) {
if (next_stats != 0)
display_stats();
next_stats = now + Modes.stats;
}
}
}
//
//=========================================================================
//
int verbose_device_search(char *s)
{
int i, device_count, device, offset;
char *s2;
char vendor[256], product[256], serial[256];
device_count = rtlsdr_get_device_count();
if (!device_count) {
fprintf(stderr, "No supported devices found.\n");
return -1;
}
fprintf(stderr, "Found %d device(s):\n", device_count);
for (i = 0; i < device_count; i++) {
rtlsdr_get_device_usb_strings(i, vendor, product, serial);
fprintf(stderr, " %d: %s, %s, SN: %s\n", i, vendor, product, serial);
}
fprintf(stderr, "\n");
/* does string look like raw id number */
device = (int)strtol(s, &s2, 0);
if (s2[0] == '\0' && device >= 0 && device < device_count) {
fprintf(stderr, "Using device %d: %s\n",
device, rtlsdr_get_device_name((uint32_t)device));
return device;
}
/* does string exact match a serial */
for (i = 0; i < device_count; i++) {
rtlsdr_get_device_usb_strings(i, vendor, product, serial);
if (strcmp(s, serial) != 0) {
continue;}
device = i;
fprintf(stderr, "Using device %d: %s\n",
device, rtlsdr_get_device_name((uint32_t)device));
return device;
}
/* does string prefix match a serial */
for (i = 0; i < device_count; i++) {
rtlsdr_get_device_usb_strings(i, vendor, product, serial);
if (strncmp(s, serial, strlen(s)) != 0) {
continue;}
device = i;
fprintf(stderr, "Using device %d: %s\n",
device, rtlsdr_get_device_name((uint32_t)device));
return device;
}
/* does string suffix match a serial */
for (i = 0; i < device_count; i++) {
rtlsdr_get_device_usb_strings(i, vendor, product, serial);
offset = strlen(serial) - strlen(s);
if (offset < 0) {
continue;}
if (strncmp(s, serial+offset, strlen(s)) != 0) {
continue;}
device = i;
fprintf(stderr, "Using device %d: %s\n",
device, rtlsdr_get_device_name((uint32_t)device));
return device;
}
fprintf(stderr, "No matching devices found.\n");
return -1;
}
//
//=========================================================================
//
int main(int argc, char **argv) {
int j;
// Set sane defaults
modesInitConfig();
signal(SIGINT, sigintHandler); // Define Ctrl/C handler (exit program)
// Parse the command line options
for (j = 1; j < argc; j++) {
int more = j+1 < argc; // There are more arguments
if (!strcmp(argv[j],"--device-index") && more) {
Modes.dev_index = verbose_device_search(argv[++j]);
} else if (!strcmp(argv[j],"--gain") && more) {
Modes.gain = (int) (atof(argv[++j])*10); // Gain is in tens of DBs
} else if (!strcmp(argv[j],"--enable-agc")) {
Modes.enable_agc++;
} else if (!strcmp(argv[j],"--freq") && more) {
Modes.freq = (int) strtoll(argv[++j],NULL,10);
} else if (!strcmp(argv[j],"--ifile") && more) {
Modes.filename = strdup(argv[++j]);
} else if (!strcmp(argv[j],"--fix")) {
Modes.nfix_crc = 1;
} else if (!strcmp(argv[j],"--no-fix")) {
Modes.nfix_crc = 0;
} else if (!strcmp(argv[j],"--no-crc-check")) {
Modes.check_crc = 0;
} else if (!strcmp(argv[j],"--phase-enhance")) {
Modes.phase_enhance = 1;
} else if (!strcmp(argv[j],"--raw")) {
Modes.raw = 1;
} else if (!strcmp(argv[j],"--net")) {
Modes.net = 1;
} else if (!strcmp(argv[j],"--modeac")) {
Modes.mode_ac = 1;
} else if (!strcmp(argv[j],"--net-beast")) {
Modes.beast = 1;
} else if (!strcmp(argv[j],"--net-only")) {
Modes.net = 1;
Modes.net_only = 1;
} else if (!strcmp(argv[j],"--net-heartbeat") && more) {
Modes.net_heartbeat_rate = atoi(argv[++j]) * 15;
} else if (!strcmp(argv[j],"--net-ro-size") && more) {
Modes.net_output_raw_size = atoi(argv[++j]);
} else if (!strcmp(argv[j],"--net-ro-rate") && more) {
Modes.net_output_raw_rate = atoi(argv[++j]);
} else if (!strcmp(argv[j],"--net-ro-port") && more) {
if (Modes.beast) // Required for legacy backward compatibility
{Modes.net_output_beast_port = atoi(argv[++j]);;}
else
{Modes.net_output_raw_port = atoi(argv[++j]);}
} else if (!strcmp(argv[j],"--net-ri-port") && more) {
Modes.net_input_raw_port = atoi(argv[++j]);
} else if (!strcmp(argv[j],"--net-bo-port") && more) {
Modes.net_output_beast_port = atoi(argv[++j]);
} else if (!strcmp(argv[j],"--net-bi-port") && more) {
Modes.net_input_beast_port = atoi(argv[++j]);
} else if (!strcmp(argv[j],"--net-bind-address") && more) {
Modes.net_bind_address = strdup(argv[++j]);
} else if (!strcmp(argv[j],"--net-http-port") && more) {
Modes.net_http_port = atoi(argv[++j]);
} else if (!strcmp(argv[j],"--net-sbs-port") && more) {
Modes.net_output_sbs_port = atoi(argv[++j]);
} else if (!strcmp(argv[j],"--net-buffer") && more) {
Modes.net_sndbuf_size = atoi(argv[++j]);
} else if (!strcmp(argv[j],"--onlyaddr")) {
Modes.onlyaddr = 1;
} else if (!strcmp(argv[j],"--metric")) {
Modes.metric = 1;
} else if (!strcmp(argv[j],"--aggressive")) {
Modes.nfix_crc = MODES_MAX_BITERRORS;
} else if (!strcmp(argv[j],"--interactive")) {
Modes.interactive = 1;
} else if (!strcmp(argv[j],"--interactive-rows") && more) {
Modes.interactive_rows = atoi(argv[++j]);
} else if (!strcmp(argv[j],"--interactive-ttl") && more) {
Modes.interactive_display_ttl = atoi(argv[++j]);
} else if (!strcmp(argv[j],"--lat") && more) {
Modes.fUserLat = atof(argv[++j]);
} else if (!strcmp(argv[j],"--lon") && more) {
Modes.fUserLon = atof(argv[++j]);
} else if (!strcmp(argv[j],"--debug") && more) {
char *f = argv[++j];
while(*f) {
switch(*f) {
case 'D': Modes.debug |= MODES_DEBUG_DEMOD; break;
case 'd': Modes.debug |= MODES_DEBUG_DEMODERR; break;
case 'C': Modes.debug |= MODES_DEBUG_GOODCRC; break;
case 'c': Modes.debug |= MODES_DEBUG_BADCRC; break;
case 'p': Modes.debug |= MODES_DEBUG_NOPREAMBLE; break;
case 'n': Modes.debug |= MODES_DEBUG_NET; break;
case 'j': Modes.debug |= MODES_DEBUG_JS; break;
default:
fprintf(stderr, "Unknown debugging flag: %c\n", *f);
exit(1);
break;
}
f++;
}
} else if (!strcmp(argv[j],"--stats")) {
Modes.stats = -1;
} else if (!strcmp(argv[j],"--stats-every") && more) {
Modes.stats = atoi(argv[++j]);
} else if (!strcmp(argv[j],"--snip") && more) {
snipMode(atoi(argv[++j]));
exit(0);
} else if (!strcmp(argv[j],"--help")) {
showHelp();
exit(0);
} else if (!strcmp(argv[j],"--ppm") && more) {
Modes.ppm_error = atoi(argv[++j]);
} else if (!strcmp(argv[j],"--quiet")) {
Modes.quiet = 1;
} else if (!strcmp(argv[j],"--mlat")) {
Modes.mlat = 1;
} else if (!strcmp(argv[j],"--interactive-rtl1090")) {
Modes.interactive = 1;
Modes.interactive_rtl1090 = 1;
} else {
fprintf(stderr,
"Unknown or not enough arguments for option '%s'.\n\n",
argv[j]);
showHelp();
exit(1);
}
}
#ifdef _WIN32
// Try to comply with the Copyright license conditions for binary distribution
if (!Modes.quiet) {showCopyright();}
#endif
#ifndef _WIN32
// Setup for SIGWINCH for handling lines
if (Modes.interactive) {signal(SIGWINCH, sigWinchCallback);}
#endif
// Initialization
modesInit();
if (Modes.net_only) {
fprintf(stderr,"Net-only mode, no RTL device or file open.\n");
} else if (Modes.filename == NULL) {
modesInitRTLSDR();
} else {
if (Modes.filename[0] == '-' && Modes.filename[1] == '\0') {
Modes.fd = STDIN_FILENO;
} else if ((Modes.fd = open(Modes.filename,
#ifdef _WIN32
(O_RDONLY | O_BINARY)
#else
(O_RDONLY)
#endif
)) == -1) {
perror("Opening data file");
exit(1);
}
}
if (Modes.net) modesInitNet();
// If the user specifies --net-only, just run in order to serve network
// clients without reading data from the RTL device
while (Modes.net_only) {
if (Modes.exit) exit(0); // If we exit net_only nothing further in main()
backgroundTasks();
usleep(100000);
}
// Create the thread that will read the data from the device.
pthread_create(&Modes.reader_thread, NULL, readerThreadEntryPoint, NULL);
pthread_mutex_lock(&Modes.data_mutex);
while (Modes.exit == 0) {
if (Modes.iDataReady == 0) {
pthread_cond_wait(&Modes.data_cond,&Modes.data_mutex); // This unlocks Modes.data_mutex, and waits for Modes.data_cond
continue; // Once (Modes.data_cond) occurs, it locks Modes.data_mutex
}
// Modes.data_mutex is Locked, and (Modes.iDataReady != 0)
if (Modes.iDataReady) { // Check we have new data, just in case!!
Modes.iDataOut &= (MODES_ASYNC_BUF_NUMBER-1); // Just incase
// Translate the next lot of I/Q samples into Modes.magnitude
computeMagnitudeVector(Modes.pData[Modes.iDataOut]);
Modes.stSystemTimeBlk = Modes.stSystemTimeRTL[Modes.iDataOut];
// Update the input buffer pointer queue
Modes.iDataOut = (MODES_ASYNC_BUF_NUMBER-1) & (Modes.iDataOut + 1);
Modes.iDataReady = (MODES_ASYNC_BUF_NUMBER-1) & (Modes.iDataIn - Modes.iDataOut);
// If we lost some blocks, correct the timestamp
if (Modes.iDataLost) {
Modes.timestampBlk += (MODES_ASYNC_BUF_SAMPLES * 6 * Modes.iDataLost);
Modes.stat_blocks_dropped += Modes.iDataLost;
Modes.iDataLost = 0;
}
// It's safe to release the lock now
pthread_cond_signal (&Modes.data_cond);
pthread_mutex_unlock(&Modes.data_mutex);
// Process data after releasing the lock, so that the capturing
// thread can read data while we perform computationally expensive
// stuff at the same time.
detectModeS(Modes.magnitude, MODES_ASYNC_BUF_SAMPLES);
// Update the timestamp ready for the next block
Modes.timestampBlk += (MODES_ASYNC_BUF_SAMPLES*6);
Modes.stat_blocks_processed++;
} else {
pthread_cond_signal (&Modes.data_cond);
pthread_mutex_unlock(&Modes.data_mutex);
}
backgroundTasks();
pthread_mutex_lock(&Modes.data_mutex);
}
// If --stats were given, print statistics
if (Modes.stats) {
display_stats();
}
if (Modes.filename == NULL) {
rtlsdr_cancel_async(Modes.dev); // Cancel rtlsdr_read_async will cause data input thread to terminate cleanly
rtlsdr_close(Modes.dev);
}
pthread_cond_destroy(&Modes.data_cond); // Thread cleanup
pthread_mutex_destroy(&Modes.data_mutex);
pthread_join(Modes.reader_thread,NULL); // Wait on reader thread exit
#ifndef _WIN32
pthread_exit(0);
#else
return (0);
#endif
}
//
//=========================================================================
//

View file

@ -1,152 +0,0 @@
# Microsoft Developer Studio Project File - Name="dump1090" - Package Owner=<4>
# Microsoft Developer Studio Generated Build File, Format Version 6.00
# ** DO NOT EDIT **
# TARGTYPE "Win32 (x86) Console Application" 0x0103
CFG=dump1090 - Win32 Debug
!MESSAGE This is not a valid makefile. To build this project using NMAKE,
!MESSAGE use the Export Makefile command and run
!MESSAGE
!MESSAGE NMAKE /f "dump1090.mak".
!MESSAGE
!MESSAGE You can specify a configuration when running NMAKE
!MESSAGE by defining the macro CFG on the command line. For example:
!MESSAGE
!MESSAGE NMAKE /f "dump1090.mak" CFG="dump1090 - Win32 Debug"
!MESSAGE
!MESSAGE Possible choices for configuration are:
!MESSAGE
!MESSAGE "dump1090 - Win32 Release" (based on "Win32 (x86) Console Application")
!MESSAGE "dump1090 - Win32 Debug" (based on "Win32 (x86) Console Application")
!MESSAGE
# Begin Project
# PROP AllowPerConfigDependencies 0
# PROP Scc_ProjName ""
# PROP Scc_LocalPath ""
CPP=cl.exe
RSC=rc.exe
!IF "$(CFG)" == "dump1090 - Win32 Release"
# PROP BASE Use_MFC 0
# PROP BASE Use_Debug_Libraries 0
# PROP BASE Output_Dir "Release"
# PROP BASE Intermediate_Dir "Release"
# PROP BASE Target_Dir ""
# PROP Use_MFC 0
# PROP Use_Debug_Libraries 0
# PROP Output_Dir "Release"
# PROP Intermediate_Dir "Release"
# PROP Ignore_Export_Lib 0
# PROP Target_Dir ""
# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /Yu"stdafx.h" /FD /c
# ADD CPP /nologo /W3 /GX /O2 /I ".\pthreads\." /I ".\rtlsdr\." /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /FR /FD /c
# SUBTRACT CPP /YX /Yc /Yu
# ADD BASE RSC /l 0x809 /d "NDEBUG"
# ADD RSC /l 0x809 /d "NDEBUG"
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
LINK32=link.exe
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386
# ADD LINK32 ws2_32.lib /nologo /subsystem:console /machine:I386 /out:"./dump1090.exe"
!ELSEIF "$(CFG)" == "dump1090 - Win32 Debug"
# PROP BASE Use_MFC 0
# PROP BASE Use_Debug_Libraries 1
# PROP BASE Output_Dir "Debug"
# PROP BASE Intermediate_Dir "Debug"
# PROP BASE Target_Dir ""
# PROP Use_MFC 0
# PROP Use_Debug_Libraries 1
# PROP Output_Dir "Debug"
# PROP Intermediate_Dir "Debug"
# PROP Ignore_Export_Lib 0
# PROP Target_Dir ""
# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /Yu"stdafx.h" /FD /GZ /c
# ADD CPP /nologo /W3 /Gm /GX /ZI /Od /I ".\pthreads\." /I ".\rtlsdr\." /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /FR /FD /GZ /c
# SUBTRACT CPP /YX /Yc /Yu
# ADD BASE RSC /l 0x809 /d "_DEBUG"
# ADD RSC /l 0x809 /d "_DEBUG"
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
LINK32=link.exe
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
# ADD LINK32 ws2_32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
!ENDIF
# Begin Target
# Name "dump1090 - Win32 Release"
# Name "dump1090 - Win32 Debug"
# Begin Group "Source Files"
# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
# Begin Source File
SOURCE=.\anet.c
# End Source File
# Begin Source File
SOURCE=.\dump1090.c
# End Source File
# Begin Source File
SOURCE=.\interactive.c
# End Source File
# Begin Source File
SOURCE=.\mode_ac.c
# End Source File
# Begin Source File
SOURCE=.\mode_s.c
# End Source File
# Begin Source File
SOURCE=.\net_io.c
# End Source File
# End Group
# Begin Group "Header Files"
# PROP Default_Filter "h;hpp;hxx;hm;inl"
# Begin Source File
SOURCE=.\anet.h
# End Source File
# Begin Source File
SOURCE=.\dump1090.h
# End Source File
# Begin Source File
SOURCE=.\winstubs.h
# End Source File
# End Group
# Begin Group "Resource Files"
# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"
# Begin Source File
SOURCE=.\Dump1090.rc
# End Source File
# End Group
# Begin Group "Library Files"
# PROP Default_Filter ""
# Begin Source File
SOURCE=.\pthreads\pthreadVC2.lib
# End Source File
# Begin Source File
SOURCE=.\rtlsdr\rtlsdr.lib
# End Source File
# End Group
# End Target
# End Project

View file

@ -1,41 +0,0 @@
Microsoft Developer Studio Workspace File, Format Version 6.00
# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE!
###############################################################################
Project: "dump1090"=.\dump1090.dsp - Package Owner=<4>
Package=<5>
{{{
}}}
Package=<4>
{{{
}}}
###############################################################################
Project: "view1090"=.\view1090.dsp - Package Owner=<4>
Package=<5>
{{{
}}}
Package=<4>
{{{
}}}
###############################################################################
Global:
Package=<5>
{{{
}}}
Package=<3>
{{{
}}}
###############################################################################

View file

@ -1,466 +0,0 @@
// dump1090, a Mode S messages decoder for RTLSDR devices.
//
// Copyright (C) 2012 by Salvatore Sanfilippo <antirez@gmail.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.
//
// 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
// HOLDER 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 __DUMP1090_H
#define __DUMP1090_H
// File Version number
// ====================
// Format is : MajorVer.MinorVer.DayMonth.Year"
// MajorVer changes only with significant changes
// MinorVer changes when additional features are added, but not for bug fixes (range 00-99)
// DayDate & Year changes for all changes, including for bug fixes. It represent the release date of the update
//
#define MODES_DUMP1090_VERSION "1.10.3010.14"
// ============================= Include files ==========================
#ifndef _WIN32
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <pthread.h>
#include <stdint.h>
#include <errno.h>
#include <unistd.h>
#include <math.h>
#include <sys/time.h>
#include <sys/timeb.h>
#include <signal.h>
#include <fcntl.h>
#include <ctype.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include "rtl-sdr.h"
#include "anet.h"
#else
#include "winstubs.h" //Put everything Windows specific in here
#include "rtl-sdr.h"
#include "anet.h"
#endif
// ============================= #defines ===============================
//
// If you have a valid coaa.h, these values will come from it. If not,
// then you can enter your own values in the #else section here
//
#ifdef USER_LATITUDE
#define MODES_USER_LATITUDE_DFLT (USER_LATITUDE)
#define MODES_USER_LONGITUDE_DFLT (USER_LONGITUDE)
#else
#define MODES_USER_LATITUDE_DFLT (0.0)
#define MODES_USER_LONGITUDE_DFLT (0.0)
#endif
#define MODES_DEFAULT_PPM 52
#define MODES_DEFAULT_RATE 2000000
#define MODES_DEFAULT_FREQ 1090000000
#define MODES_DEFAULT_WIDTH 1000
#define MODES_DEFAULT_HEIGHT 700
#define MODES_ASYNC_BUF_NUMBER 16
#define MODES_ASYNC_BUF_SIZE (16*16384) // 256k
#define MODES_ASYNC_BUF_SAMPLES (MODES_ASYNC_BUF_SIZE / 2) // Each sample is 2 bytes
#define MODES_AUTO_GAIN -100 // Use automatic gain
#define MODES_MAX_GAIN 999999 // Use max available gain
#define MODES_MSG_SQUELCH_LEVEL 0x02FF // Average signal strength limit
#define MODES_MSG_ENCODER_ERRS 3 // Maximum number of encoding errors
// When changing, change also fixBitErrors() and modesInitErrorTable() !!
#define MODES_MAX_BITERRORS 2 // Global max for fixable bit erros
#define MODEAC_MSG_SAMPLES (25 * 2) // include up to the SPI bit
#define MODEAC_MSG_BYTES 2
#define MODEAC_MSG_SQUELCH_LEVEL 0x07FF // Average signal strength limit
#define MODEAC_MSG_FLAG (1<<0)
#define MODEAC_MSG_MODES_HIT (1<<1)
#define MODEAC_MSG_MODEA_HIT (1<<2)
#define MODEAC_MSG_MODEC_HIT (1<<3)
#define MODEAC_MSG_MODEA_ONLY (1<<4)
#define MODEAC_MSG_MODEC_OLD (1<<5)
#define MODES_PREAMBLE_US 8 // microseconds = bits
#define MODES_PREAMBLE_SAMPLES (MODES_PREAMBLE_US * 2)
#define MODES_PREAMBLE_SIZE (MODES_PREAMBLE_SAMPLES * sizeof(uint16_t))
#define MODES_LONG_MSG_BYTES 14
#define MODES_SHORT_MSG_BYTES 7
#define MODES_LONG_MSG_BITS (MODES_LONG_MSG_BYTES * 8)
#define MODES_SHORT_MSG_BITS (MODES_SHORT_MSG_BYTES * 8)
#define MODES_LONG_MSG_SAMPLES (MODES_LONG_MSG_BITS * 2)
#define MODES_SHORT_MSG_SAMPLES (MODES_SHORT_MSG_BITS * 2)
#define MODES_LONG_MSG_SIZE (MODES_LONG_MSG_SAMPLES * sizeof(uint16_t))
#define MODES_SHORT_MSG_SIZE (MODES_SHORT_MSG_SAMPLES * sizeof(uint16_t))
#define MODES_RAWOUT_BUF_SIZE (1500)
#define MODES_RAWOUT_BUF_FLUSH (MODES_RAWOUT_BUF_SIZE - 200)
#define MODES_RAWOUT_BUF_RATE (1000) // 1000 * 64mS = 1 Min approx
#define MODES_ICAO_CACHE_LEN 1024 // Power of two required
#define MODES_ICAO_CACHE_TTL 60 // Time to live of cached addresses
#define MODES_UNIT_FEET 0
#define MODES_UNIT_METERS 1
#define MODES_USER_LATLON_VALID (1<<0)
#define MODES_ACFLAGS_LATLON_VALID (1<<0) // Aircraft Lat/Lon is decoded
#define MODES_ACFLAGS_ALTITUDE_VALID (1<<1) // Aircraft altitude is known
#define MODES_ACFLAGS_HEADING_VALID (1<<2) // Aircraft heading is known
#define MODES_ACFLAGS_SPEED_VALID (1<<3) // Aircraft speed is known
#define MODES_ACFLAGS_VERTRATE_VALID (1<<4) // Aircraft vertical rate is known
#define MODES_ACFLAGS_SQUAWK_VALID (1<<5) // Aircraft Mode A Squawk is known
#define MODES_ACFLAGS_CALLSIGN_VALID (1<<6) // Aircraft Callsign Identity
#define MODES_ACFLAGS_EWSPEED_VALID (1<<7) // Aircraft East West Speed is known
#define MODES_ACFLAGS_NSSPEED_VALID (1<<8) // Aircraft North South Speed is known
#define MODES_ACFLAGS_AOG (1<<9) // Aircraft is On the Ground
#define MODES_ACFLAGS_LLEVEN_VALID (1<<10) // Aircraft Even Lot/Lon is known
#define MODES_ACFLAGS_LLODD_VALID (1<<11) // Aircraft Odd Lot/Lon is known
#define MODES_ACFLAGS_AOG_VALID (1<<12) // MODES_ACFLAGS_AOG is valid
#define MODES_ACFLAGS_FS_VALID (1<<13) // Aircraft Flight Status is known
#define MODES_ACFLAGS_NSEWSPD_VALID (1<<14) // Aircraft EW and NS Speed is known
#define MODES_ACFLAGS_LATLON_REL_OK (1<<15) // Indicates it's OK to do a relative CPR
#define MODES_ACFLAGS_LLEITHER_VALID (MODES_ACFLAGS_LLEVEN_VALID | MODES_ACFLAGS_LLODD_VALID)
#define MODES_ACFLAGS_LLBOTH_VALID (MODES_ACFLAGS_LLEVEN_VALID | MODES_ACFLAGS_LLODD_VALID)
#define MODES_ACFLAGS_AOG_GROUND (MODES_ACFLAGS_AOG_VALID | MODES_ACFLAGS_AOG)
#define MODES_DEBUG_DEMOD (1<<0)
#define MODES_DEBUG_DEMODERR (1<<1)
#define MODES_DEBUG_BADCRC (1<<2)
#define MODES_DEBUG_GOODCRC (1<<3)
#define MODES_DEBUG_NOPREAMBLE (1<<4)
#define MODES_DEBUG_NET (1<<5)
#define MODES_DEBUG_JS (1<<6)
// When debug is set to MODES_DEBUG_NOPREAMBLE, the first sample must be
// at least greater than a given level for us to dump the signal.
#define MODES_DEBUG_NOPREAMBLE_LEVEL 25
#define MODES_INTERACTIVE_REFRESH_TIME 250 // Milliseconds
#define MODES_INTERACTIVE_ROWS 22 // Rows on screen
#define MODES_INTERACTIVE_DELETE_TTL 300 // Delete from the list after 300 seconds
#define MODES_INTERACTIVE_DISPLAY_TTL 60 // Delete from display after 60 seconds
#define MODES_NET_HEARTBEAT_RATE 900 // Each block is approx 65mS - default is > 1 min
#define MODES_NET_SERVICES_NUM 6
#define MODES_NET_INPUT_RAW_PORT 30001
#define MODES_NET_OUTPUT_RAW_PORT 30002
#define MODES_NET_OUTPUT_SBS_PORT 30003
#define MODES_NET_INPUT_BEAST_PORT 30004
#define MODES_NET_OUTPUT_BEAST_PORT 30005
#define MODES_NET_HTTP_PORT 8080
#define MODES_CLIENT_BUF_SIZE 1024
#define MODES_NET_SNDBUF_SIZE (1024*64)
#define MODES_NET_SNDBUF_MAX (7)
#ifndef HTMLPATH
#define HTMLPATH "./public_html" // default path for gmap.html etc
#endif
#define MODES_NOTUSED(V) ((void) V)
//======================== structure declarations =========================
// Structure used to describe a networking client
struct client {
struct client* next; // Pointer to next client
int fd; // File descriptor
int service; // TCP port the client is connected to
int buflen; // Amount of data on buffer
char buf[MODES_CLIENT_BUF_SIZE+1]; // Read buffer
};
// Structure used to describe an aircraft in iteractive mode
struct aircraft {
uint32_t addr; // ICAO address
char flight[16]; // Flight number
unsigned char signalLevel[8]; // Last 8 Signal Amplitudes
int altitude; // Altitude
int speed; // Velocity
int track; // Angle of flight
int vert_rate; // Vertical rate.
time_t seen; // Time at which the last packet was received
time_t seenLatLon; // Time at which the last lat long was calculated
uint64_t timestamp; // Timestamp at which the last packet was received
uint64_t timestampLatLon;// Timestamp at which the last lat long was calculated
long messages; // Number of Mode S messages received
int modeA; // Squawk
int modeC; // Altitude
long modeAcount; // Mode A Squawk hit Count
long modeCcount; // Mode C Altitude hit Count
int modeACflags; // Flags for mode A/C recognition
// Encoded latitude and longitude as extracted by odd and even CPR encoded messages
int odd_cprlat;
int odd_cprlon;
int even_cprlat;
int even_cprlon;
uint64_t odd_cprtime;
uint64_t even_cprtime;
double lat, lon; // Coordinated obtained from CPR encoded data
int bFlags; // Flags related to valid fields in this structure
struct aircraft *next; // Next aircraft in our linked list
};
struct stDF {
struct stDF *pNext; // Pointer to next item in the linked list
struct stDF *pPrev; // Pointer to previous item in the linked list
struct aircraft *pAircraft; // Pointer to the Aircraft structure for this DF
time_t seen; // Dos/UNIX Time at which the this packet was received
uint64_t llTimestamp; // Timestamp at which the this packet was received
uint32_t addr; // Timestamp at which the this packet was received
unsigned char msg[MODES_LONG_MSG_BYTES]; // the binary
} tDF;
// Program global state
struct { // Internal state
pthread_t reader_thread;
pthread_mutex_t data_mutex; // Mutex to synchronize buffer access
pthread_cond_t data_cond; // Conditional variable associated
uint16_t *pData [MODES_ASYNC_BUF_NUMBER]; // Raw IQ sample buffers from RTL
struct timeb stSystemTimeRTL[MODES_ASYNC_BUF_NUMBER]; // System time when RTL passed us this block
int iDataIn; // Fifo input pointer
int iDataOut; // Fifo output pointer
int iDataReady; // Fifo content count
int iDataLost; // Count of missed buffers
uint16_t *pFileData; // Raw IQ samples buffer (from a File)
uint16_t *magnitude; // Magnitude vector
uint64_t timestampBlk; // Timestamp of the start of the current block
struct timeb stSystemTimeBlk; // System time when RTL passed us currently processing this block
int fd; // --ifile option file descriptor
uint32_t *icao_cache; // Recently seen ICAO addresses cache
uint16_t *maglut; // I/Q -> Magnitude lookup table
int exit; // Exit from the main loop when true
// RTLSDR
int dev_index;
int gain;
int enable_agc;
rtlsdr_dev_t *dev;
int freq;
int ppm_error;
// Networking
char aneterr[ANET_ERR_LEN];
struct client *clients; // Our clients
int sbsos; // SBS output listening socket
int ros; // Raw output listening socket
int ris; // Raw input listening socket
int bos; // Beast output listening socket
int bis; // Beast input listening socket
int https; // HTTP listening socket
char *rawOut; // Buffer for building raw output data
int rawOutUsed; // How much of the buffer is currently used
char *beastOut; // Buffer for building beast output data
int beastOutUsed; // How much if the buffer is currently used
#ifdef _WIN32
WSADATA wsaData; // Windows socket initialisation
#endif
// Configuration
char *filename; // Input form file, --ifile option
int phase_enhance; // Enable phase enhancement if true
int nfix_crc; // Number of crc bit error(s) to correct
int check_crc; // Only display messages with good CRC
int raw; // Raw output format
int beast; // Beast binary format output
int mode_ac; // Enable decoding of SSR Modes A & C
int debug; // Debugging mode
int net; // Enable networking
int net_only; // Enable just networking
int net_heartbeat_count; // TCP heartbeat counter
int net_heartbeat_rate; // TCP heartbeat rate
int net_output_sbs_port; // SBS output TCP port
int net_output_raw_size; // Minimum Size of the output raw data
int net_output_raw_rate; // Rate (in 64mS increments) of output raw data
int net_output_raw_rate_count; // Rate (in 64mS increments) of output raw data
int net_output_raw_port; // Raw output TCP port
int net_input_raw_port; // Raw input TCP port
int net_output_beast_port; // Beast output TCP port
int net_input_beast_port; // Beast input TCP port
char *net_bind_address; // Bind address
int net_http_port; // HTTP port
int net_sndbuf_size; // TCP output buffer size (64Kb * 2^n)
int quiet; // Suppress stdout
int interactive; // Interactive mode
int interactive_rows; // Interactive mode: max number of rows
int interactive_display_ttl; // Interactive mode: TTL display
int interactive_delete_ttl; // Interactive mode: TTL before deletion
int stats; // Print stats at exit in --ifile mode
int onlyaddr; // Print only ICAO addresses
int metric; // Use metric units
int mlat; // Use Beast ascii format for raw data output, i.e. @...; iso *...;
int interactive_rtl1090; // flight table in interactive mode is formatted like RTL1090
// User details
double fUserLat; // Users receiver/antenna lat/lon needed for initial surface location
double fUserLon; // Users receiver/antenna lat/lon needed for initial surface location
int bUserFlags; // Flags relating to the user details
// Interactive mode
struct aircraft *aircrafts;
uint64_t interactive_last_update; // Last screen update in milliseconds
time_t last_cleanup_time; // Last cleanup time in seconds
// DF List mode
int bEnableDFLogging; // Set to enable DF Logging
pthread_mutex_t pDF_mutex; // Mutex to synchronize pDF access
struct stDF *pDF; // Pointer to DF list
// Statistics
unsigned int stat_valid_preamble;
unsigned int stat_demodulated0;
unsigned int stat_demodulated1;
unsigned int stat_demodulated2;
unsigned int stat_demodulated3;
unsigned int stat_goodcrc;
unsigned int stat_badcrc;
unsigned int stat_fixed;
// Histogram of fixed bit errors: index 0 for single bit erros,
// index 1 for double bit errors etc.
unsigned int stat_bit_fix[MODES_MAX_BITERRORS];
unsigned int stat_http_requests;
unsigned int stat_sbs_connections;
unsigned int stat_raw_connections;
unsigned int stat_beast_connections;
unsigned int stat_out_of_phase;
unsigned int stat_ph_demodulated0;
unsigned int stat_ph_demodulated1;
unsigned int stat_ph_demodulated2;
unsigned int stat_ph_demodulated3;
unsigned int stat_ph_goodcrc;
unsigned int stat_ph_badcrc;
unsigned int stat_ph_fixed;
// Histogram of fixed bit errors: index 0 for single bit erros,
// index 1 for double bit errors etc.
unsigned int stat_ph_bit_fix[MODES_MAX_BITERRORS];
unsigned int stat_DF_Len_Corrected;
unsigned int stat_DF_Type_Corrected;
unsigned int stat_ModeAC;
unsigned int stat_blocks_processed;
unsigned int stat_blocks_dropped;
} Modes;
// The struct we use to store information about a decoded message.
struct modesMessage {
// Generic fields
unsigned char msg[MODES_LONG_MSG_BYTES]; // Binary message.
int msgbits; // Number of bits in message
int msgtype; // Downlink format #
int crcok; // True if CRC was valid
uint32_t crc; // Message CRC
int correctedbits; // No. of bits corrected
char corrected[MODES_MAX_BITERRORS]; // corrected bit positions
uint32_t addr; // ICAO Address from bytes 1 2 and 3
int phase_corrected; // True if phase correction was applied
uint64_t timestampMsg; // Timestamp of the message
int remote; // If set this message is from a remote station
unsigned char signalLevel; // Signal Amplitude
// DF 11
int ca; // Responder capabilities
int iid;
// DF 17, DF 18
int metype; // Extended squitter message type.
int mesub; // Extended squitter message subtype.
int heading; // Reported by aircraft, or computed from from EW and NS velocity
int raw_latitude; // Non decoded latitude.
int raw_longitude; // Non decoded longitude.
double fLat; // Coordinates obtained from CPR encoded data if/when decoded
double fLon; // Coordinates obtained from CPR encoded data if/when decoded
char flight[16]; // 8 chars flight number.
int ew_velocity; // E/W velocity.
int ns_velocity; // N/S velocity.
int vert_rate; // Vertical rate.
int velocity; // Reported by aircraft, or computed from from EW and NS velocity
// DF4, DF5, DF20, DF21
int fs; // Flight status for DF4,5,20,21
int modeA; // 13 bits identity (Squawk).
// Fields used by multiple message types.
int altitude;
int unit;
int bFlags; // Flags related to fields in this structure
};
// ======================== function declarations =========================
#ifdef __cplusplus
extern "C" {
#endif
//
// Functions exported from mode_ac.c
//
int detectModeA (uint16_t *m, struct modesMessage *mm);
void decodeModeAMessage(struct modesMessage *mm, int ModeA);
int ModeAToModeC (unsigned int ModeA);
//
// Functions exported from mode_s.c
//
void detectModeS (uint16_t *m, uint32_t mlen);
void decodeModesMessage (struct modesMessage *mm, unsigned char *msg);
void displayModesMessage(struct modesMessage *mm);
void useModesMessage (struct modesMessage *mm);
void computeMagnitudeVector(uint16_t *pData);
int decodeCPR (struct aircraft *a, int fflag, int surface);
int decodeCPRrelative (struct aircraft *a, int fflag, int surface);
void modesInitErrorInfo ();
//
// Functions exported from interactive.c
//
struct aircraft* interactiveReceiveData(struct modesMessage *mm);
void interactiveShowData(void);
void interactiveRemoveStaleAircrafts(void);
int decodeBinMessage (struct client *c, char *p);
struct aircraft *interactiveFindAircraft(uint32_t addr);
struct stDF *interactiveFindDF (uint32_t addr);
//
// Functions exported from net_io.c
//
void modesInitNet (void);
void modesReadFromClients (void);
void modesSendAllClients (int service, void *msg, int len);
void modesQueueOutput (struct modesMessage *mm);
void modesReadFromClient(struct client *c, char *sep, int(*handler)(struct client *, char *));
#ifdef __cplusplus
}
#endif
#endif // __DUMP1090_H

View file

@ -1,115 +0,0 @@
//Microsoft Developer Studio generated resource script.
//
#include "resource.h"
#define APSTUDIO_READONLY_SYMBOLS
/////////////////////////////////////////////////////////////////////////////
//
// Generated from the TEXTINCLUDE 2 resource.
//
#define APSTUDIO_HIDDEN_SYMBOLS
#include "windows.h"
#undef APSTUDIO_HIDDEN_SYMBOLS
#include "ntverp.h"
/////////////////////////////////////////////////////////////////////////////
#undef APSTUDIO_READONLY_SYMBOLS
/////////////////////////////////////////////////////////////////////////////
// English (U.S.) resources
#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
#ifdef _WIN32
LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
#pragma code_page(1252)
#endif //_WIN32
#ifndef _MAC
/////////////////////////////////////////////////////////////////////////////
//
// Version
//
VS_VERSION_INFO VERSIONINFO
FILEVERSION 1,10,2910,14
PRODUCTVERSION 1,10,2910,14
FILEFLAGSMASK 0x3fL
#ifdef _DEBUG
FILEFLAGS 0x1L
#else
FILEFLAGS 0x0L
#endif
FILEOS 0x40004L
FILETYPE 0x3L
FILESUBTYPE 0x7L
BEGIN
BLOCK "StringFileInfo"
BEGIN
BLOCK "040904b0"
BEGIN
VALUE "Comments", "Dump1090 for Win32 \0"
VALUE "CompanyName", "\0"
VALUE "FileDescription", "Mode A/C/S decoder for RTL Dongles\0"
VALUE "FileVersion", "1, 10, 2910, 14\0"
VALUE "InternalName", "DUMP1090.EXE\0"
VALUE "LegalCopyright", "Copyright © 2012 by Salvatore Sanfilippo <antirez@gmail.com>\r\nCopyright © 2014 by Malcolm Robb <support@attavionics.com>\0"
VALUE "LegalTrademarks", "\0"
VALUE "OriginalFilename", "DUMP1090.EXE\0"
VALUE "PrivateBuild", "\0"
VALUE "ProductName", "DUMP1090\0"
VALUE "ProductVersion", "1, 10, 2910, 14\0"
VALUE "SpecialBuild", "\0"
END
END
BLOCK "VarFileInfo"
BEGIN
VALUE "Translation", 0x409, 1200
END
END
#endif // !_MAC
#ifdef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// TEXTINCLUDE
//
1 TEXTINCLUDE DISCARDABLE
BEGIN
"resource.h\0"
END
2 TEXTINCLUDE DISCARDABLE
BEGIN
"#define APSTUDIO_HIDDEN_SYMBOLS\r\n"
"#include ""windows.h""\r\n"
"#undef APSTUDIO_HIDDEN_SYMBOLS\r\n"
"#include ""ntverp.h""\r\n"
"\0"
END
3 TEXTINCLUDE DISCARDABLE
BEGIN
"\r\n"
"\0"
END
#endif // APSTUDIO_INVOKED
#endif // English (U.S.) resources
/////////////////////////////////////////////////////////////////////////////
#ifndef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// Generated from the TEXTINCLUDE 3 resource.
//
/////////////////////////////////////////////////////////////////////////////
#endif // not APSTUDIO_INVOKED

View file

@ -1,74 +0,0 @@
#!/bin/bash
### BEGIN INIT INFO
#
# Provides: dump1090
# Required-Start: $remote_fs
# Required-Stop: $remote_fs
# Default-Start: 2 3 4 5
# Default-Stop: 0 1 6
# Short-Description: dump1090 initscript
#
### END INIT INFO
## Fill in name of program here.
PROG="dump1090"
PROG_PATH="/home/pi/dump1090"
PROG_ARGS="--quiet --net --net-ro-size 500 --net-ro-rate 5 --net-buffer 5"
PIDFILE="/var/run/dump1090.pid"
start() {
if [ -e $PIDFILE ]; then
## Program is running, exit with error.
echo "Error! $PROG is currently running!" 1>&2
exit 1
else
## Change from /dev/null to something like /var/log/$PROG if you want to save output.
cd $PROG_PATH
./$PROG $PROG_ARGS 2>&1 >/dev/null &
echo "$PROG started"
touch $PIDFILE
fi
}
stop() {
if [ -e $PIDFILE ]; then
## Program is running, so stop it
echo "$PROG is running"
killall $PROG
rm -f $PIDFILE
echo "$PROG stopped"
else
## Program is not running, exit with error.
echo "Error! $PROG not started!" 1>&2
exit 1
fi
}
## Check to see if we are running as root first.
## Found at http://www.cyberciti.biz/tips/shell-root-user-check-script.html
if [ "$(id -u)" != "0" ]; then
echo "This script must be run as root" 1>&2
exit 1
fi
case "$1" in
start)
start
exit 0
;;
stop)
stop
exit 0
;;
reload|restart|force-reload)
stop
start
exit 0
;;
**)
echo "Usage: $0 {start|stop|reload}" 1>&2
exit 1
;;
esac
#

View file

@ -1,649 +0,0 @@
// dump1090, a Mode S messages decoder for RTLSDR devices.
//
// Copyright (C) 2012 by Salvatore Sanfilippo <antirez@gmail.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.
//
// 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
// HOLDER 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 "dump1090.h"
#include <math.h>
#include <locale.h>
#include <wchar.h>
//
// ============================= Utility functions ==========================
//
static uint64_t mstime(void) {
struct timeval tv;
uint64_t mst;
gettimeofday(&tv, NULL);
mst = ((uint64_t)tv.tv_sec)*1000;
mst += tv.tv_usec/1000;
return mst;
}
//
//=========================================================================
//
// Add a new DF structure to the interactive mode linked list
//
void interactiveCreateDF(struct aircraft *a, struct modesMessage *mm) {
struct stDF *pDF = (struct stDF *) malloc(sizeof(*pDF));
if (pDF) {
// Default everything to zero/NULL
memset(pDF, 0, sizeof(*pDF));
// Now initialise things
pDF->seen = a->seen;
pDF->llTimestamp = mm->timestampMsg;
pDF->addr = mm->addr;
pDF->pAircraft = a;
memcpy(pDF->msg, mm->msg, MODES_LONG_MSG_BYTES);
if (!pthread_mutex_lock(&Modes.pDF_mutex)) {
if ((pDF->pNext = Modes.pDF)) {
Modes.pDF->pPrev = pDF;
}
Modes.pDF = pDF;
pthread_mutex_unlock(&Modes.pDF_mutex);
} else {
free(pDF);
}
}
}
//
// Remove stale DF's from the interactive mode linked list
//
void interactiveRemoveStaleDF(time_t now) {
struct stDF *pDF = NULL;
struct stDF *prev = NULL;
// Only fiddle with the DF list if we gain possession of the mutex
// If we fail to get the mutex we'll get another chance to tidy the
// DF list in a second or so.
if (!pthread_mutex_trylock(&Modes.pDF_mutex)) {
pDF = Modes.pDF;
while(pDF) {
if ((now - pDF->seen) > Modes.interactive_delete_ttl) {
if (Modes.pDF == pDF) {
Modes.pDF = NULL;
} else {
prev->pNext = NULL;
}
// All DF's in the list from here onwards will be time
// expired, so delete them all
while (pDF) {
prev = pDF; pDF = pDF->pNext;
free(prev);
}
} else {
prev = pDF; pDF = pDF->pNext;
}
}
pthread_mutex_unlock (&Modes.pDF_mutex);
}
}
struct stDF *interactiveFindDF(uint32_t addr) {
struct stDF *pDF = NULL;
if (!pthread_mutex_lock(&Modes.pDF_mutex)) {
pDF = Modes.pDF;
while(pDF) {
if (pDF->addr == addr) {
pthread_mutex_unlock (&Modes.pDF_mutex);
return (pDF);
}
pDF = pDF->pNext;
}
pthread_mutex_unlock (&Modes.pDF_mutex);
}
return (NULL);
}
//
//========================= Interactive mode ===============================
//
// Return a new aircraft structure for the interactive mode linked list
// of aircraft
//
struct aircraft *interactiveCreateAircraft(struct modesMessage *mm) {
struct aircraft *a = (struct aircraft *) malloc(sizeof(*a));
// Default everything to zero/NULL
memset(a, 0, sizeof(*a));
// Now initialise things that should not be 0/NULL to their defaults
a->addr = mm->addr;
a->lat = a->lon = 0.0;
memset(a->signalLevel, mm->signalLevel, 8); // First time, initialise everything
// to the first signal strength
// mm->msgtype 32 is used to represent Mode A/C. These values can never change, so
// set them once here during initialisation, and don't bother to set them every
// time this ModeA/C is received again in the future
if (mm->msgtype == 32) {
int modeC = ModeAToModeC(mm->modeA | mm->fs);
a->modeACflags = MODEAC_MSG_FLAG;
if (modeC < -12) {
a->modeACflags |= MODEAC_MSG_MODEA_ONLY;
} else {
mm->altitude = modeC * 100;
mm->bFlags |= MODES_ACFLAGS_ALTITUDE_VALID;
}
}
return (a);
}
//
//=========================================================================
//
// Return the aircraft with the specified address, or NULL if no aircraft
// exists with this address.
//
struct aircraft *interactiveFindAircraft(uint32_t addr) {
struct aircraft *a = Modes.aircrafts;
while(a) {
if (a->addr == addr) return (a);
a = a->next;
}
return (NULL);
}
//
//=========================================================================
//
// We have received a Mode A or C response.
//
// Search through the list of known Mode-S aircraft and tag them if this Mode A/C
// matches their known Mode S Squawks or Altitudes(+/- 50feet).
//
// A Mode S equipped aircraft may also respond to Mode A and Mode C SSR interrogations.
// We can't tell if this is a Mode A or C, so scan through the entire aircraft list
// looking for matches on Mode A (squawk) and Mode C (altitude). Flag in the Mode S
// records that we have had a potential Mode A or Mode C response from this aircraft.
//
// If an aircraft responds to Mode A then it's highly likely to be responding to mode C
// too, and vice verca. Therefore, once the mode S record is tagged with both a Mode A
// and a Mode C flag, we can be fairly confident that this Mode A/C frame relates to that
// Mode S aircraft.
//
// Mode C's are more likely to clash than Mode A's; There could be several aircraft
// cruising at FL370, but it's less likely (though not impossible) that there are two
// aircraft on the same squawk. Therefore, give precidence to Mode A record matches
//
// Note : It's theoretically possible for an aircraft to have the same value for Mode A
// and Mode C. Therefore we have to check BOTH A AND C for EVERY S.
//
void interactiveUpdateAircraftModeA(struct aircraft *a) {
struct aircraft *b = Modes.aircrafts;
while(b) {
if ((b->modeACflags & MODEAC_MSG_FLAG) == 0) {// skip any fudged ICAO records
// If both (a) and (b) have valid squawks...
if ((a->bFlags & b->bFlags) & MODES_ACFLAGS_SQUAWK_VALID) {
// ...check for Mode-A == Mode-S Squawk matches
if (a->modeA == b->modeA) { // If a 'real' Mode-S ICAO exists using this Mode-A Squawk
b->modeAcount = a->messages;
b->modeACflags |= MODEAC_MSG_MODEA_HIT;
a->modeACflags |= MODEAC_MSG_MODEA_HIT;
if ( (b->modeAcount > 0) &&
( (b->modeCcount > 1)
|| (a->modeACflags & MODEAC_MSG_MODEA_ONLY)) ) // Allow Mode-A only matches if this Mode-A is invalid Mode-C
{a->modeACflags |= MODEAC_MSG_MODES_HIT;} // flag this ModeA/C probably belongs to a known Mode S
}
}
// If both (a) and (b) have valid altitudes...
if ((a->bFlags & b->bFlags) & MODES_ACFLAGS_ALTITUDE_VALID) {
// ... check for Mode-C == Mode-S Altitude matches
if ( (a->modeC == b->modeC ) // If a 'real' Mode-S ICAO exists at this Mode-C Altitude
|| (a->modeC == b->modeC + 1) // or this Mode-C - 100 ft
|| (a->modeC + 1 == b->modeC ) ) { // or this Mode-C + 100 ft
b->modeCcount = a->messages;
b->modeACflags |= MODEAC_MSG_MODEC_HIT;
a->modeACflags |= MODEAC_MSG_MODEC_HIT;
if ( (b->modeAcount > 0) &&
(b->modeCcount > 1) )
{a->modeACflags |= (MODEAC_MSG_MODES_HIT | MODEAC_MSG_MODEC_OLD);} // flag this ModeA/C probably belongs to a known Mode S
}
}
}
b = b->next;
}
}
//
//=========================================================================
//
void interactiveUpdateAircraftModeS() {
struct aircraft *a = Modes.aircrafts;
while(a) {
int flags = a->modeACflags;
if (flags & MODEAC_MSG_FLAG) { // find any fudged ICAO records
// clear the current A,C and S hit bits ready for this attempt
a->modeACflags = flags & ~(MODEAC_MSG_MODEA_HIT | MODEAC_MSG_MODEC_HIT | MODEAC_MSG_MODES_HIT);
interactiveUpdateAircraftModeA(a); // and attempt to match them with Mode-S
}
a = a->next;
}
}
//
//=========================================================================
//
// Receive new messages and populate the interactive mode with more info
//
struct aircraft *interactiveReceiveData(struct modesMessage *mm) {
struct aircraft *a, *aux;
// Return if (checking crc) AND (not crcok) AND (not fixed)
if (Modes.check_crc && (mm->crcok == 0) && (mm->correctedbits == 0))
return NULL;
// Lookup our aircraft or create a new one
a = interactiveFindAircraft(mm->addr);
if (!a) { // If it's a currently unknown aircraft....
a = interactiveCreateAircraft(mm); // ., create a new record for it,
a->next = Modes.aircrafts; // .. and put it at the head of the list
Modes.aircrafts = a;
} else {
/* If it is an already known aircraft, move it on head
* so we keep aircrafts ordered by received message time.
*
* However move it on head only if at least one second elapsed
* since the aircraft that is currently on head sent a message,
* othewise with multiple aircrafts at the same time we have an
* useless shuffle of positions on the screen. */
if (0 && Modes.aircrafts != a && (time(NULL) - a->seen) >= 1) {
aux = Modes.aircrafts;
while(aux->next != a) aux = aux->next;
/* Now we are a node before the aircraft to remove. */
aux->next = aux->next->next; /* removed. */
/* Add on head */
a->next = Modes.aircrafts;
Modes.aircrafts = a;
}
}
a->signalLevel[a->messages & 7] = mm->signalLevel;// replace the 8th oldest signal strength
a->seen = time(NULL);
a->timestamp = mm->timestampMsg;
a->messages++;
// If a (new) CALLSIGN has been received, copy it to the aircraft structure
if (mm->bFlags & MODES_ACFLAGS_CALLSIGN_VALID) {
memcpy(a->flight, mm->flight, sizeof(a->flight));
}
// If a (new) ALTITUDE has been received, copy it to the aircraft structure
if (mm->bFlags & MODES_ACFLAGS_ALTITUDE_VALID) {
if ( (a->modeCcount) // if we've a modeCcount already
&& (a->altitude != mm->altitude ) ) // and Altitude has changed
// && (a->modeC != mm->modeC + 1) // and Altitude not changed by +100 feet
// && (a->modeC + 1 != mm->modeC ) ) // and Altitude not changes by -100 feet
{
a->modeCcount = 0; //....zero the hit count
a->modeACflags &= ~MODEAC_MSG_MODEC_HIT;
}
a->altitude = mm->altitude;
a->modeC = (mm->altitude + 49) / 100;
}
// If a (new) SQUAWK has been received, copy it to the aircraft structure
if (mm->bFlags & MODES_ACFLAGS_SQUAWK_VALID) {
if (a->modeA != mm->modeA) {
a->modeAcount = 0; // Squawk has changed, so zero the hit count
a->modeACflags &= ~MODEAC_MSG_MODEA_HIT;
}
a->modeA = mm->modeA;
}
// If a (new) HEADING has been received, copy it to the aircraft structure
if (mm->bFlags & MODES_ACFLAGS_HEADING_VALID) {
a->track = mm->heading;
}
// If a (new) SPEED has been received, copy it to the aircraft structure
if (mm->bFlags & MODES_ACFLAGS_SPEED_VALID) {
a->speed = mm->velocity;
}
// If a (new) Vertical Descent rate has been received, copy it to the aircraft structure
if (mm->bFlags & MODES_ACFLAGS_VERTRATE_VALID) {
a->vert_rate = mm->vert_rate;
}
// if the Aircraft has landed or taken off since the last message, clear the even/odd CPR flags
if ((mm->bFlags & MODES_ACFLAGS_AOG_VALID) && ((a->bFlags ^ mm->bFlags) & MODES_ACFLAGS_AOG)) {
a->bFlags &= ~(MODES_ACFLAGS_LLBOTH_VALID | MODES_ACFLAGS_AOG);
}
// If we've got a new cprlat or cprlon
if (mm->bFlags & MODES_ACFLAGS_LLEITHER_VALID) {
int location_ok = 0;
if (mm->bFlags & MODES_ACFLAGS_LLODD_VALID) {
a->odd_cprlat = mm->raw_latitude;
a->odd_cprlon = mm->raw_longitude;
a->odd_cprtime = mstime();
} else {
a->even_cprlat = mm->raw_latitude;
a->even_cprlon = mm->raw_longitude;
a->even_cprtime = mstime();
}
// If we have enough recent data, try global CPR
if (((mm->bFlags | a->bFlags) & MODES_ACFLAGS_LLEITHER_VALID) == MODES_ACFLAGS_LLBOTH_VALID && abs((int)(a->even_cprtime - a->odd_cprtime)) <= 10000) {
if (decodeCPR(a, (mm->bFlags & MODES_ACFLAGS_LLODD_VALID), (mm->bFlags & MODES_ACFLAGS_AOG)) == 0) {
location_ok = 1;
}
}
// Otherwise try relative CPR.
if (!location_ok && decodeCPRrelative(a, (mm->bFlags & MODES_ACFLAGS_LLODD_VALID), (mm->bFlags & MODES_ACFLAGS_AOG)) == 0) {
location_ok = 1;
}
//If we sucessfully decoded, back copy the results to mm so that we can print them in list output
if (location_ok) {
mm->bFlags |= MODES_ACFLAGS_LATLON_VALID;
mm->fLat = a->lat;
mm->fLon = a->lon;
}
}
// Update the aircrafts a->bFlags to reflect the newly received mm->bFlags;
a->bFlags |= mm->bFlags;
if (mm->msgtype == 32) {
int flags = a->modeACflags;
if ((flags & (MODEAC_MSG_MODEC_HIT | MODEAC_MSG_MODEC_OLD)) == MODEAC_MSG_MODEC_OLD) {
//
// This Mode-C doesn't currently hit any known Mode-S, but it used to because MODEAC_MSG_MODEC_OLD is
// set So the aircraft it used to match has either changed altitude, or gone out of our receiver range
//
// We've now received this Mode-A/C again, so it must be a new aircraft. It could be another aircraft
// at the same Mode-C altitude, or it could be a new airctraft with a new Mods-A squawk.
//
// To avoid masking this aircraft from the interactive display, clear the MODEAC_MSG_MODES_OLD flag
// and set messages to 1;
//
a->modeACflags = flags & ~MODEAC_MSG_MODEC_OLD;
a->messages = 1;
}
}
// If we are Logging DF's, and it's not a Mode A/C
if ((Modes.bEnableDFLogging) && (mm->msgtype < 32)) {
interactiveCreateDF(a,mm);
}
return (a);
}
//
//=========================================================================
//
// Show the currently captured interactive data on screen.
//
void interactiveShowData(void) {
struct aircraft *a = Modes.aircrafts;
time_t now = time(NULL);
int count = 0;
char progress;
char spinner[4] = "|/-\\";
// Refresh screen every (MODES_INTERACTIVE_REFRESH_TIME) miliseconde
if ((mstime() - Modes.interactive_last_update) < MODES_INTERACTIVE_REFRESH_TIME)
{return;}
Modes.interactive_last_update = mstime();
// Attempt to reconsile any ModeA/C with known Mode-S
// We can't condition on Modes.modeac because ModeA/C could be comming
// in from a raw input port which we can't turn off.
interactiveUpdateAircraftModeS();
progress = spinner[time(NULL)%4];
#ifndef _WIN32
printf("\x1b[H\x1b[2J"); // Clear the screen
#else
cls();
#endif
setlocale(LC_ALL,"");
//\xiB[30;47m
if (Modes.interactive_rtl1090 == 0) {
printf (
// original version "Hex Mode Sqwk Flight Alt Spd Hdg Lat Long Sig Msgs Ti%c\n", progress);
// pitft version "\x1B[30;47m\e[1mFlight Alt Spd Lat Long \n", progress);
"\x1B[30;47m\e[1m Flight Alt(m) km/h D(km) H S ");
} else {
printf (
"Hex Flight Alt V/S GS TT SSR G*456^ Msgs Seen %c\n", progress);
}
// printf(
//"---------------------------------------");
printf("\x1B[37;40m");
int numNoDir = 0;
// while(a && (count < 10)) {
while(a && (count < Modes.interactive_rows)) {
if ((now - a->seen) < Modes.interactive_display_ttl)
{
int msgs = a->messages;
int flags = a->modeACflags;
if ( (((flags & (MODEAC_MSG_FLAG )) == 0 ) )
|| (((flags & (MODEAC_MSG_MODES_HIT | MODEAC_MSG_MODEA_ONLY)) == MODEAC_MSG_MODEA_ONLY) && (msgs > 4 ) )
|| (((flags & (MODEAC_MSG_MODES_HIT | MODEAC_MSG_MODEC_OLD )) == 0 ) && (msgs > 127) )
) {
int altitude = a->altitude, speed = a->speed;
char strSquawk[5] = " ";
char strFl[6] = " ";
char strTt[5] = " ";
char strGs[5] = " ";
// Convert units to metric if --metric was specified
//if (Modes.metric) {
altitude = (int) (altitude / 3.2828);
speed = (int) (speed * 1.852);
//}
if (a->bFlags & MODES_ACFLAGS_SQUAWK_VALID) {
snprintf(strSquawk,5,"%04x", a->modeA);}
if (a->bFlags & MODES_ACFLAGS_SPEED_VALID) {
snprintf (strGs, 5,"%3d", speed);}
if (a->bFlags & MODES_ACFLAGS_HEADING_VALID) {
snprintf (strTt, 5,"%03d", a->track);}
if (msgs > 99999) {
msgs = 99999;}
// Dump1090 display mode
char strMode[5] = " ";
char strLat[8] = " ";
char strLon[9] = " ";
char strD[5] = " ";
char cLat = ' ';
char cLon = ' ';
double d;
unsigned char * pSig = a->signalLevel;
unsigned int signalAverage = (pSig[0] + pSig[1] + pSig[2] + pSig[3] +
pSig[4] + pSig[5] + pSig[6] + pSig[7] + 3) >> 3;
if (a->bFlags & MODES_ACFLAGS_AOG) {
snprintf(strFl, 6," grnd");
} else if (a->bFlags & MODES_ACFLAGS_ALTITUDE_VALID) {
snprintf(strFl, 6, "%5d", altitude);
}
if ((flags & MODEAC_MSG_FLAG) == 0) {
strMode[0] = 'S';
} else if (flags & MODEAC_MSG_MODEA_ONLY) {
strMode[0] = 'A';
}
if (flags & MODEAC_MSG_MODEA_HIT) {strMode[2] = 'a';}
if (flags & MODEAC_MSG_MODEC_HIT) {strMode[3] = 'c';}
if (a->bFlags & MODES_ACFLAGS_LATLON_VALID) {
double dLon = a->lon+87.6651033;
double dLat = a->lat-41.9809263;
snprintf(strLat, 8,"%7.03f", dLat);
snprintf(strLon, 9,"%8.03f", dLon);
double x = dLon * M_PI / 180.0f * cos(((a->lat+41.9809263)/2.0f) * M_PI / 180.0f);
double y = dLat * M_PI / 180.0f;
d = sqrt(x*x + y*y) * 6371.0;
if(fabs(dLon) < .01 && fabs(dLat) > fabs(dLon)) {
cLon = ' ';
} else {
if(dLon < 0) {
cLon = 'W';
} else {
cLon = 'E';
}
}
if(fabs(dLat) < .01 && fabs(dLon) > fabs(dLat)) {
cLat = ' ';
} else {
if(dLat < 0) {
cLat = 'S';
} else {
cLat = 'N';
}
}
snprintf(strD, 5,"%4.01f", d);
/*
//formatted for Unifont 8x16, rotated 90
printf("\n\x1B[%d;31m%-8s\x1B[%d;32m%5s \x1B[%d;33m%3s \x1B[%d;34m%6s \x1B[%d;36m%c%c \x1B[%d;37m%lc",
count%2, a->flight,
count%2, strFl,
count%2, strGs,
count%2, strD,
count%2, cLat, cLon,
count%2, 0x2581 + (wint_t) (2*signalAverage));
*/
//formatted for terminusBold 10x20, no unicode
if(d<5) {
printf("%ls",L"\n\x1B[1;37m┌──────────────────────────────┐\n");
} else {
printf("\n ");
}
if ((now - a->seen) > 30 ) {
printf("\x1B[1;30m%-8s%5s %4s %5s %c%c %d",
a->flight,
strFl,
strGs,
strD,
cLat, cLon,
(int)((float)signalAverage/25.0f));
} else {
printf("\x1B[1;31m%-8s\x1B[1;32m%5s \x1B[1;33m%4s \x1B[1;34m%5s \x1B[1;36m%c%c \x1B[1;35m%d",
a->flight,
strFl,
strGs,
strD,
cLat, cLon,
(int)((float)signalAverage/25.0f));
}
if(d<5) {
printf("%ls",L"\x1B[1;37m│\n└──────────────────────────────┘");
count+=2;
}
count++;
} else {
numNoDir++;
}
}
}
a = a->next;
}
while(count < 10) {
printf("\n");
count++;
}
printf("\x1B[30;47m\e[1m\n%+3d %c \x1B[37;40m",numNoDir,progress);
fflush(stdout);
}
//
//=========================================================================
//
// When in interactive mode If we don't receive new nessages within
// MODES_INTERACTIVE_DELETE_TTL seconds we remove the aircraft from the list.
//
void interactiveRemoveStaleAircrafts(void) {
struct aircraft *a = Modes.aircrafts;
struct aircraft *prev = NULL;
time_t now = time(NULL);
// Only do cleanup once per second
if (Modes.last_cleanup_time != now) {
Modes.last_cleanup_time = now;
interactiveRemoveStaleDF(now);
while(a) {
if ((now - a->seen) > Modes.interactive_delete_ttl) {
// Remove the element from the linked list, with care
// if we are removing the first element
if (!prev) {
Modes.aircrafts = a->next; free(a); a = Modes.aircrafts;
} else {
prev->next = a->next; free(a); a = prev->next;
}
} else {
prev = a; a = a->next;
}
}
}
}
//
//=========================================================================
//

View file

@ -1,561 +0,0 @@
// dump1090, a Mode S messages decoder for RTLSDR devices.
//
// Copyright (C) 2012 by Salvatore Sanfilippo <antirez@gmail.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.
//
// 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
// HOLDER 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 "dump1090.h"
//
// ============================= Utility functions ==========================
//
static uint64_t mstime(void) {
struct timeval tv;
uint64_t mst;
gettimeofday(&tv, NULL);
mst = ((uint64_t)tv.tv_sec)*1000;
mst += tv.tv_usec/1000;
return mst;
}
//
//=========================================================================
//
// Add a new DF structure to the interactive mode linked list
//
void interactiveCreateDF(struct aircraft *a, struct modesMessage *mm) {
struct stDF *pDF = (struct stDF *) malloc(sizeof(*pDF));
if (pDF) {
// Default everything to zero/NULL
memset(pDF, 0, sizeof(*pDF));
// Now initialise things
pDF->seen = a->seen;
pDF->llTimestamp = mm->timestampMsg;
pDF->addr = mm->addr;
pDF->pAircraft = a;
memcpy(pDF->msg, mm->msg, MODES_LONG_MSG_BYTES);
if (!pthread_mutex_lock(&Modes.pDF_mutex)) {
if ((pDF->pNext = Modes.pDF)) {
Modes.pDF->pPrev = pDF;
}
Modes.pDF = pDF;
pthread_mutex_unlock(&Modes.pDF_mutex);
} else {
free(pDF);
}
}
}
//
// Remove stale DF's from the interactive mode linked list
//
void interactiveRemoveStaleDF(time_t now) {
struct stDF *pDF = NULL;
struct stDF *prev = NULL;
// Only fiddle with the DF list if we gain possession of the mutex
// If we fail to get the mutex we'll get another chance to tidy the
// DF list in a second or so.
if (!pthread_mutex_trylock(&Modes.pDF_mutex)) {
pDF = Modes.pDF;
while(pDF) {
if ((now - pDF->seen) > Modes.interactive_delete_ttl) {
if (Modes.pDF == pDF) {
Modes.pDF = NULL;
} else {
prev->pNext = NULL;
}
// All DF's in the list from here onwards will be time
// expired, so delete them all
while (pDF) {
prev = pDF; pDF = pDF->pNext;
free(prev);
}
} else {
prev = pDF; pDF = pDF->pNext;
}
}
pthread_mutex_unlock (&Modes.pDF_mutex);
}
}
struct stDF *interactiveFindDF(uint32_t addr) {
struct stDF *pDF = NULL;
if (!pthread_mutex_lock(&Modes.pDF_mutex)) {
pDF = Modes.pDF;
while(pDF) {
if (pDF->addr == addr) {
pthread_mutex_unlock (&Modes.pDF_mutex);
return (pDF);
}
pDF = pDF->pNext;
}
pthread_mutex_unlock (&Modes.pDF_mutex);
}
return (NULL);
}
//
//========================= Interactive mode ===============================
//
// Return a new aircraft structure for the interactive mode linked list
// of aircraft
//
struct aircraft *interactiveCreateAircraft(struct modesMessage *mm) {
struct aircraft *a = (struct aircraft *) malloc(sizeof(*a));
// Default everything to zero/NULL
memset(a, 0, sizeof(*a));
// Now initialise things that should not be 0/NULL to their defaults
a->addr = mm->addr;
a->lat = a->lon = 0.0;
memset(a->signalLevel, mm->signalLevel, 8); // First time, initialise everything
// to the first signal strength
// mm->msgtype 32 is used to represent Mode A/C. These values can never change, so
// set them once here during initialisation, and don't bother to set them every
// time this ModeA/C is received again in the future
if (mm->msgtype == 32) {
int modeC = ModeAToModeC(mm->modeA | mm->fs);
a->modeACflags = MODEAC_MSG_FLAG;
if (modeC < -12) {
a->modeACflags |= MODEAC_MSG_MODEA_ONLY;
} else {
mm->altitude = modeC * 100;
mm->bFlags |= MODES_ACFLAGS_ALTITUDE_VALID;
}
}
return (a);
}
//
//=========================================================================
//
// Return the aircraft with the specified address, or NULL if no aircraft
// exists with this address.
//
struct aircraft *interactiveFindAircraft(uint32_t addr) {
struct aircraft *a = Modes.aircrafts;
while(a) {
if (a->addr == addr) return (a);
a = a->next;
}
return (NULL);
}
//
//=========================================================================
//
// We have received a Mode A or C response.
//
// Search through the list of known Mode-S aircraft and tag them if this Mode A/C
// matches their known Mode S Squawks or Altitudes(+/- 50feet).
//
// A Mode S equipped aircraft may also respond to Mode A and Mode C SSR interrogations.
// We can't tell if this is a Mode A or C, so scan through the entire aircraft list
// looking for matches on Mode A (squawk) and Mode C (altitude). Flag in the Mode S
// records that we have had a potential Mode A or Mode C response from this aircraft.
//
// If an aircraft responds to Mode A then it's highly likely to be responding to mode C
// too, and vice verca. Therefore, once the mode S record is tagged with both a Mode A
// and a Mode C flag, we can be fairly confident that this Mode A/C frame relates to that
// Mode S aircraft.
//
// Mode C's are more likely to clash than Mode A's; There could be several aircraft
// cruising at FL370, but it's less likely (though not impossible) that there are two
// aircraft on the same squawk. Therefore, give precidence to Mode A record matches
//
// Note : It's theoretically possible for an aircraft to have the same value for Mode A
// and Mode C. Therefore we have to check BOTH A AND C for EVERY S.
//
void interactiveUpdateAircraftModeA(struct aircraft *a) {
struct aircraft *b = Modes.aircrafts;
while(b) {
if ((b->modeACflags & MODEAC_MSG_FLAG) == 0) {// skip any fudged ICAO records
// If both (a) and (b) have valid squawks...
if ((a->bFlags & b->bFlags) & MODES_ACFLAGS_SQUAWK_VALID) {
// ...check for Mode-A == Mode-S Squawk matches
if (a->modeA == b->modeA) { // If a 'real' Mode-S ICAO exists using this Mode-A Squawk
b->modeAcount = a->messages;
b->modeACflags |= MODEAC_MSG_MODEA_HIT;
a->modeACflags |= MODEAC_MSG_MODEA_HIT;
if ( (b->modeAcount > 0) &&
( (b->modeCcount > 1)
|| (a->modeACflags & MODEAC_MSG_MODEA_ONLY)) ) // Allow Mode-A only matches if this Mode-A is invalid Mode-C
{a->modeACflags |= MODEAC_MSG_MODES_HIT;} // flag this ModeA/C probably belongs to a known Mode S
}
}
// If both (a) and (b) have valid altitudes...
if ((a->bFlags & b->bFlags) & MODES_ACFLAGS_ALTITUDE_VALID) {
// ... check for Mode-C == Mode-S Altitude matches
if ( (a->modeC == b->modeC ) // If a 'real' Mode-S ICAO exists at this Mode-C Altitude
|| (a->modeC == b->modeC + 1) // or this Mode-C - 100 ft
|| (a->modeC + 1 == b->modeC ) ) { // or this Mode-C + 100 ft
b->modeCcount = a->messages;
b->modeACflags |= MODEAC_MSG_MODEC_HIT;
a->modeACflags |= MODEAC_MSG_MODEC_HIT;
if ( (b->modeAcount > 0) &&
(b->modeCcount > 1) )
{a->modeACflags |= (MODEAC_MSG_MODES_HIT | MODEAC_MSG_MODEC_OLD);} // flag this ModeA/C probably belongs to a known Mode S
}
}
}
b = b->next;
}
}
//
//=========================================================================
//
void interactiveUpdateAircraftModeS() {
struct aircraft *a = Modes.aircrafts;
while(a) {
int flags = a->modeACflags;
if (flags & MODEAC_MSG_FLAG) { // find any fudged ICAO records
// clear the current A,C and S hit bits ready for this attempt
a->modeACflags = flags & ~(MODEAC_MSG_MODEA_HIT | MODEAC_MSG_MODEC_HIT | MODEAC_MSG_MODES_HIT);
interactiveUpdateAircraftModeA(a); // and attempt to match them with Mode-S
}
a = a->next;
}
}
//
//=========================================================================
//
// Receive new messages and populate the interactive mode with more info
//
struct aircraft *interactiveReceiveData(struct modesMessage *mm) {
struct aircraft *a, *aux;
// Return if (checking crc) AND (not crcok) AND (not fixed)
if (Modes.check_crc && (mm->crcok == 0) && (mm->correctedbits == 0))
return NULL;
// Lookup our aircraft or create a new one
a = interactiveFindAircraft(mm->addr);
if (!a) { // If it's a currently unknown aircraft....
a = interactiveCreateAircraft(mm); // ., create a new record for it,
a->next = Modes.aircrafts; // .. and put it at the head of the list
Modes.aircrafts = a;
} else {
/* If it is an already known aircraft, move it on head
* so we keep aircrafts ordered by received message time.
*
* However move it on head only if at least one second elapsed
* since the aircraft that is currently on head sent a message,
* othewise with multiple aircrafts at the same time we have an
* useless shuffle of positions on the screen. */
if (0 && Modes.aircrafts != a && (time(NULL) - a->seen) >= 1) {
aux = Modes.aircrafts;
while(aux->next != a) aux = aux->next;
/* Now we are a node before the aircraft to remove. */
aux->next = aux->next->next; /* removed. */
/* Add on head */
a->next = Modes.aircrafts;
Modes.aircrafts = a;
}
}
a->signalLevel[a->messages & 7] = mm->signalLevel;// replace the 8th oldest signal strength
a->seen = time(NULL);
a->timestamp = mm->timestampMsg;
a->messages++;
// If a (new) CALLSIGN has been received, copy it to the aircraft structure
if (mm->bFlags & MODES_ACFLAGS_CALLSIGN_VALID) {
memcpy(a->flight, mm->flight, sizeof(a->flight));
}
// If a (new) ALTITUDE has been received, copy it to the aircraft structure
if (mm->bFlags & MODES_ACFLAGS_ALTITUDE_VALID) {
if ( (a->modeCcount) // if we've a modeCcount already
&& (a->altitude != mm->altitude ) ) // and Altitude has changed
// && (a->modeC != mm->modeC + 1) // and Altitude not changed by +100 feet
// && (a->modeC + 1 != mm->modeC ) ) // and Altitude not changes by -100 feet
{
a->modeCcount = 0; //....zero the hit count
a->modeACflags &= ~MODEAC_MSG_MODEC_HIT;
}
a->altitude = mm->altitude;
a->modeC = (mm->altitude + 49) / 100;
}
// If a (new) SQUAWK has been received, copy it to the aircraft structure
if (mm->bFlags & MODES_ACFLAGS_SQUAWK_VALID) {
if (a->modeA != mm->modeA) {
a->modeAcount = 0; // Squawk has changed, so zero the hit count
a->modeACflags &= ~MODEAC_MSG_MODEA_HIT;
}
a->modeA = mm->modeA;
}
// If a (new) HEADING has been received, copy it to the aircraft structure
if (mm->bFlags & MODES_ACFLAGS_HEADING_VALID) {
a->track = mm->heading;
}
// If a (new) SPEED has been received, copy it to the aircraft structure
if (mm->bFlags & MODES_ACFLAGS_SPEED_VALID) {
a->speed = mm->velocity;
}
// If a (new) Vertical Descent rate has been received, copy it to the aircraft structure
if (mm->bFlags & MODES_ACFLAGS_VERTRATE_VALID) {
a->vert_rate = mm->vert_rate;
}
// if the Aircraft has landed or taken off since the last message, clear the even/odd CPR flags
if ((mm->bFlags & MODES_ACFLAGS_AOG_VALID) && ((a->bFlags ^ mm->bFlags) & MODES_ACFLAGS_AOG)) {
a->bFlags &= ~(MODES_ACFLAGS_LLBOTH_VALID | MODES_ACFLAGS_AOG);
}
// If we've got a new cprlat or cprlon
if (mm->bFlags & MODES_ACFLAGS_LLEITHER_VALID) {
int location_ok = 0;
if (mm->bFlags & MODES_ACFLAGS_LLODD_VALID) {
a->odd_cprlat = mm->raw_latitude;
a->odd_cprlon = mm->raw_longitude;
a->odd_cprtime = mstime();
} else {
a->even_cprlat = mm->raw_latitude;
a->even_cprlon = mm->raw_longitude;
a->even_cprtime = mstime();
}
// If we have enough recent data, try global CPR
if (((mm->bFlags | a->bFlags) & MODES_ACFLAGS_LLEITHER_VALID) == MODES_ACFLAGS_LLBOTH_VALID && abs((int)(a->even_cprtime - a->odd_cprtime)) <= 10000) {
if (decodeCPR(a, (mm->bFlags & MODES_ACFLAGS_LLODD_VALID), (mm->bFlags & MODES_ACFLAGS_AOG)) == 0) {
location_ok = 1;
}
}
// Otherwise try relative CPR.
if (!location_ok && decodeCPRrelative(a, (mm->bFlags & MODES_ACFLAGS_LLODD_VALID), (mm->bFlags & MODES_ACFLAGS_AOG)) == 0) {
location_ok = 1;
}
//If we sucessfully decoded, back copy the results to mm so that we can print them in list output
if (location_ok) {
mm->bFlags |= MODES_ACFLAGS_LATLON_VALID;
mm->fLat = a->lat;
mm->fLon = a->lon;
}
}
// Update the aircrafts a->bFlags to reflect the newly received mm->bFlags;
a->bFlags |= mm->bFlags;
if (mm->msgtype == 32) {
int flags = a->modeACflags;
if ((flags & (MODEAC_MSG_MODEC_HIT | MODEAC_MSG_MODEC_OLD)) == MODEAC_MSG_MODEC_OLD) {
//
// This Mode-C doesn't currently hit any known Mode-S, but it used to because MODEAC_MSG_MODEC_OLD is
// set So the aircraft it used to match has either changed altitude, or gone out of our receiver range
//
// We've now received this Mode-A/C again, so it must be a new aircraft. It could be another aircraft
// at the same Mode-C altitude, or it could be a new airctraft with a new Mods-A squawk.
//
// To avoid masking this aircraft from the interactive display, clear the MODEAC_MSG_MODES_OLD flag
// and set messages to 1;
//
a->modeACflags = flags & ~MODEAC_MSG_MODEC_OLD;
a->messages = 1;
}
}
// If we are Logging DF's, and it's not a Mode A/C
if ((Modes.bEnableDFLogging) && (mm->msgtype < 32)) {
interactiveCreateDF(a,mm);
}
return (a);
}
//
//=========================================================================
//
// Show the currently captured interactive data on screen.
//
void interactiveShowData(void) {
struct aircraft *a = Modes.aircrafts;
time_t now = time(NULL);
int count = 0;
char progress;
char spinner[4] = "|/-\\";
// Refresh screen every (MODES_INTERACTIVE_REFRESH_TIME) miliseconde
if ((mstime() - Modes.interactive_last_update) < MODES_INTERACTIVE_REFRESH_TIME)
{return;}
Modes.interactive_last_update = mstime();
// Attempt to reconsile any ModeA/C with known Mode-S
// We can't condition on Modes.modeac because ModeA/C could be comming
// in from a raw input port which we can't turn off.
interactiveUpdateAircraftModeS();
progress = spinner[time(NULL)%4];
#ifndef _WIN32
printf("\x1b[H\x1b[2J"); // Clear the screen
#else
cls();
#endif
if (Modes.interactive_rtl1090 == 0) {
printf (
"Hex Mode Sqwk Flight Alt Spd Hdg Lat Long Sig Msgs Ti%c\n", progress);
} else {
printf (
"Hex Flight Alt V/S GS TT SSR G*456^ Msgs Seen %c\n", progress);
}
printf(
"-------------------------------------------------------------------------------\n");
while(a && (count < Modes.interactive_rows)) {
if ((now - a->seen) < Modes.interactive_display_ttl)
{
int msgs = a->messages;
int flags = a->modeACflags;
if ( (((flags & (MODEAC_MSG_FLAG )) == 0 ) )
|| (((flags & (MODEAC_MSG_MODES_HIT | MODEAC_MSG_MODEA_ONLY)) == MODEAC_MSG_MODEA_ONLY) && (msgs > 4 ) )
|| (((flags & (MODEAC_MSG_MODES_HIT | MODEAC_MSG_MODEC_OLD )) == 0 ) && (msgs > 127) )
) {
int altitude = a->altitude, speed = a->speed;
char strSquawk[5] = " ";
char strFl[6] = " ";
char strTt[5] = " ";
char strGs[5] = " ";
// Convert units to metric if --metric was specified
if (Modes.metric) {
altitude = (int) (altitude / 3.2828);
speed = (int) (speed * 1.852);
}
if (a->bFlags & MODES_ACFLAGS_SQUAWK_VALID) {
snprintf(strSquawk,5,"%04x", a->modeA);}
if (a->bFlags & MODES_ACFLAGS_SPEED_VALID) {
snprintf (strGs, 5,"%3d", speed);}
if (a->bFlags & MODES_ACFLAGS_HEADING_VALID) {
snprintf (strTt, 5,"%03d", a->track);}
if (msgs > 99999) {
msgs = 99999;}
if (Modes.interactive_rtl1090) { // RTL1090 display mode
if (a->bFlags & MODES_ACFLAGS_ALTITUDE_VALID) {
snprintf(strFl,6,"F%03d",(altitude/100));
}
printf("%06x %-8s %-4s %-3s %-3s %4s %-6d %-2d\n",
a->addr, a->flight, strFl, strGs, strTt, strSquawk, msgs, (int)(now - a->seen));
} else { // Dump1090 display mode
char strMode[5] = " ";
char strLat[8] = " ";
char strLon[9] = " ";
unsigned char * pSig = a->signalLevel;
unsigned int signalAverage = (pSig[0] + pSig[1] + pSig[2] + pSig[3] +
pSig[4] + pSig[5] + pSig[6] + pSig[7] + 3) >> 3;
if ((flags & MODEAC_MSG_FLAG) == 0) {
strMode[0] = 'S';
} else if (flags & MODEAC_MSG_MODEA_ONLY) {
strMode[0] = 'A';
}
if (flags & MODEAC_MSG_MODEA_HIT) {strMode[2] = 'a';}
if (flags & MODEAC_MSG_MODEC_HIT) {strMode[3] = 'c';}
if (a->bFlags & MODES_ACFLAGS_LATLON_VALID) {
snprintf(strLat, 8,"%7.03f", a->lat);
snprintf(strLon, 9,"%8.03f", a->lon);
}
if (a->bFlags & MODES_ACFLAGS_AOG) {
snprintf(strFl, 6," grnd");
} else if (a->bFlags & MODES_ACFLAGS_ALTITUDE_VALID) {
snprintf(strFl, 6, "%5d", altitude);
}
printf("%06X %-4s %-4s %-8s %5s %3s %3s %7s %8s %3d %5d %2d\n",
a->addr, strMode, strSquawk, a->flight, strFl, strGs, strTt,
strLat, strLon, signalAverage, msgs, (int)(now - a->seen));
}
count++;
}
}
a = a->next;
}
}
//
//=========================================================================
//
// When in interactive mode If we don't receive new nessages within
// MODES_INTERACTIVE_DELETE_TTL seconds we remove the aircraft from the list.
//
void interactiveRemoveStaleAircrafts(void) {
struct aircraft *a = Modes.aircrafts;
struct aircraft *prev = NULL;
time_t now = time(NULL);
// Only do cleanup once per second
if (Modes.last_cleanup_time != now) {
Modes.last_cleanup_time = now;
interactiveRemoveStaleDF(now);
while(a) {
if ((now - a->seen) > Modes.interactive_delete_ttl) {
// Remove the element from the linked list, with care
// if we are removing the first element
if (!prev) {
Modes.aircrafts = a->next; free(a); a = Modes.aircrafts;
} else {
prev->next = a->next; free(a); a = prev->next;
}
} else {
prev = a; a = a->next;
}
}
}
}
//
//=========================================================================
//

View file

@ -1,27 +0,0 @@
#
# When building a package or installing otherwise in the system, make
# sure that the variable PREFIX is defined, e.g. make PREFIX=/usr/local
#
PROGNAME=dump1090
ifdef PREFIX
BINDIR=$(PREFIX)/bin
SHAREDIR=$(PREFIX)/share/$(PROGNAME)
EXTRACFLAGS=-DHTMLPATH=\"$(SHAREDIR)\"
endif
CFLAGS=-O2 -g -Wall -W `pkg-config --cflags librtlsdr`
LIBS=`pkg-config --libs librtlsdr` -lpthread -lm
CC=gcc
all: dump1090
%.o: %.c
$(CC) $(CFLAGS) $(EXTRACFLAGS) -c $<
dump1090: dump1090.o anet.o interactive.o mode_ac.o mode_s.o net_io.o
$(CC) -g -o dump1090 dump1090.o anet.o interactive.o mode_ac.o mode_s.o net_io.o $(LIBS) $(LDFLAGS)
clean:
rm -f *.o dump1090

View file

@ -1,27 +0,0 @@
#
# When building a package or installing otherwise in the system, make
# sure that the variable PREFIX is defined, e.g. make PREFIX=/usr/local
#
PROGNAME=ppup1090
ifdef PREFIX
BINDIR=$(PREFIX)/bin
SHAREDIR=$(PREFIX)/share/$(PROGNAME)
EXTRACFLAGS=-DHTMLPATH=\"$(SHAREDIR)\"
endif
CFLAGS=-O2 -g -Wall -W `pkg-config --cflags librtlsdr`
LIBS=`pkg-config --libs librtlsdr` -lpthread -lm
CC=gcc
all: ppup1090
%.o: %.c
$(CC) $(CFLAGS) $(EXTRACFLAGS) -c $<
ppup1090: ppup1090.o anet.o interactive.o mode_ac.o mode_s.o net_io.o
$(CC) -g -o ppup1090 ppup1090.o anet.o interactive.o mode_ac.o mode_s.o net_io.o coaa1090.obj $(LIBS) $(LDFLAGS)
clean:
rm -f *.o ppup1090

View file

@ -1,27 +0,0 @@
#
# When building a package or installing otherwise in the system, make
# sure that the variable PREFIX is defined, e.g. make PREFIX=/usr/local
#
PROGNAME=view1090
ifdef PREFIX
BINDIR=$(PREFIX)/bin
SHAREDIR=$(PREFIX)/share/$(PROGNAME)
EXTRACFLAGS=-DHTMLPATH=\"$(SHAREDIR)\"
endif
CFLAGS=-O2 -g -Wall -W `pkg-config --cflags librtlsdr`
LIBS=`pkg-config --libs librtlsdr` -lpthread -lm
CC=gcc
all: view1090
%.o: %.c
$(CC) $(CFLAGS) $(EXTRACFLAGS) -c $<
view1090: view1090.o anet.o interactive.o mode_ac.o mode_s.o net_io.o
$(CC) -g -o view1090 view1090.o anet.o interactive.o mode_ac.o mode_s.o net_io.o $(LIBS) $(LDFLAGS)
clean:
rm -f *.o view1090

View file

@ -1,386 +0,0 @@
// dump1090, a Mode S messages decoder for RTLSDR devices.
//
// Copyright (C) 2012 by Salvatore Sanfilippo <antirez@gmail.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.
//
// 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
// HOLDER 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 "dump1090.h"
//
// ===================== Mode A/C detection and decoding ===================
//
//
// This table is used to build the Mode A/C variable called ModeABits.Each
// bit period is inspected, and if it's value exceeds the threshold limit,
// then the value in this table is or-ed into ModeABits.
//
// At the end of message processing, ModeABits will be the decoded ModeA value.
//
// We can also flag noise in bits that should be zeros - the xx bits. Noise in
// these bits cause bits (31-16) in ModeABits to be set. Then at the end of message
// processing we can test for errors by looking at these bits.
//
uint32_t ModeABitTable[24] = {
0x00000000, // F1 = 1
0x00000010, // C1
0x00001000, // A1
0x00000020, // C2
0x00002000, // A2
0x00000040, // C4
0x00004000, // A4
0x40000000, // xx = 0 Set bit 30 if we see this high
0x00000100, // B1
0x00000001, // D1
0x00000200, // B2
0x00000002, // D2
0x00000400, // B4
0x00000004, // D4
0x00000000, // F2 = 1
0x08000000, // xx = 0 Set bit 27 if we see this high
0x04000000, // xx = 0 Set bit 26 if we see this high
0x00000080, // SPI
0x02000000, // xx = 0 Set bit 25 if we see this high
0x01000000, // xx = 0 Set bit 24 if we see this high
0x00800000, // xx = 0 Set bit 23 if we see this high
0x00400000, // xx = 0 Set bit 22 if we see this high
0x00200000, // xx = 0 Set bit 21 if we see this high
0x00100000, // xx = 0 Set bit 20 if we see this high
};
//
// This table is used to produce an error variable called ModeAErrs.Each
// inter-bit period is inspected, and if it's value falls outside of the
// expected range, then the value in this table is or-ed into ModeAErrs.
//
// At the end of message processing, ModeAErrs will indicate if we saw
// any inter-bit anomolies, and the bits that are set will show which
// bits had them.
//
uint32_t ModeAMidTable[24] = {
0x80000000, // F1 = 1 Set bit 31 if we see F1_C1 error
0x00000010, // C1 Set bit 4 if we see C1_A1 error
0x00001000, // A1 Set bit 12 if we see A1_C2 error
0x00000020, // C2 Set bit 5 if we see C2_A2 error
0x00002000, // A2 Set bit 13 if we see A2_C4 error
0x00000040, // C4 Set bit 6 if we see C3_A4 error
0x00004000, // A4 Set bit 14 if we see A4_xx error
0x40000000, // xx = 0 Set bit 30 if we see xx_B1 error
0x00000100, // B1 Set bit 8 if we see B1_D1 error
0x00000001, // D1 Set bit 0 if we see D1_B2 error
0x00000200, // B2 Set bit 9 if we see B2_D2 error
0x00000002, // D2 Set bit 1 if we see D2_B4 error
0x00000400, // B4 Set bit 10 if we see B4_D4 error
0x00000004, // D4 Set bit 2 if we see D4_F2 error
0x20000000, // F2 = 1 Set bit 29 if we see F2_xx error
0x08000000, // xx = 0 Set bit 27 if we see xx_xx error
0x04000000, // xx = 0 Set bit 26 if we see xx_SPI error
0x00000080, // SPI Set bit 15 if we see SPI_xx error
0x02000000, // xx = 0 Set bit 25 if we see xx_xx error
0x01000000, // xx = 0 Set bit 24 if we see xx_xx error
0x00800000, // xx = 0 Set bit 23 if we see xx_xx error
0x00400000, // xx = 0 Set bit 22 if we see xx_xx error
0x00200000, // xx = 0 Set bit 21 if we see xx_xx error
0x00100000, // xx = 0 Set bit 20 if we see xx_xx error
};
//
// The "off air" format is,,
// _F1_C1_A1_C2_A2_C4_A4_xx_B1_D1_B2_D2_B4_D4_F2_xx_xx_SPI_
//
// Bit spacing is 1.45uS, with 0.45uS high, and 1.00us low. This is a problem
// because we ase sampling at 2Mhz (500nS) so we are below Nyquist.
//
// The bit spacings are..
// F1 : 0.00,
// 1.45, 2.90, 4.35, 5.80, 7.25, 8.70,
// X : 10.15,
// : 11.60, 13.05, 14.50, 15.95, 17.40, 18.85,
// F2 : 20.30,
// X : 21.75, 23.20, 24.65
//
// This equates to the following sample point centers at 2Mhz.
// [ 0.0],
// [ 2.9], [ 5.8], [ 8.7], [11.6], [14.5], [17.4],
// [20.3],
// [23.2], [26.1], [29.0], [31.9], [34.8], [37.7]
// [40.6]
// [43.5], [46.4], [49.3]
//
// We know that this is a supposed to be a binary stream, so the signal
// should either be a 1 or a 0. Therefore, any energy above the noise level
// in two adjacent samples must be from the same pulse, so we can simply
// add the values together..
//
int detectModeA(uint16_t *m, struct modesMessage *mm)
{
int j, lastBitWasOne;
int ModeABits = 0;
int ModeAErrs = 0;
int byte, bit;
int thisSample, lastBit, lastSpace = 0;
int m0, m1, m2, m3, mPhase;
int n0, n1, n2 ,n3;
int F1_sig, F1_noise;
int F2_sig, F2_noise;
int fSig, fNoise, fLevel, fLoLo;
// m[0] contains the energy from 0 -> 499 nS
// m[1] contains the energy from 500 -> 999 nS
// m[2] contains the energy from 1000 -> 1499 nS
// m[3] contains the energy from 1500 -> 1999 nS
//
// We are looking for a Frame bit (F1) whose width is 450nS, followed by
// 1000nS of quiet.
//
// The width of the frame bit is 450nS, which is 90% of our sample rate.
// Therefore, in an ideal world, all the energy for the frame bit will be
// in a single sample, preceeded by (at least) one zero, and followed by
// two zeros, Best case we can look for ...
//
// 0 - 1 - 0 - 0
//
// However, our samples are not phase aligned, so some of the energy from
// each bit could be spread over two consecutive samples. Worst case is
// that we sample half in one bit, and half in the next. In that case,
// we're looking for
//
// 0 - 0.5 - 0.5 - 0.
m0 = m[0]; m1 = m[1];
if (m0 >= m1) // m1 *must* be bigger than m0 for this to be F1
{return (0);}
m2 = m[2]; m3 = m[3];
//
// if (m2 <= m0), then assume the sample bob on (Phase == 0), so don't look at m3
if ((m2 <= m0) || (m2 < m3))
{m3 = m2; m2 = m0;}
if ( (m3 >= m1) // m1 must be bigger than m3
|| (m0 > m2) // m2 can be equal to m0 if ( 0,1,0,0 )
|| (m3 > m2) ) // m2 can be equal to m3 if ( 0,1,0,0 )
{return (0);}
// m0 = noise
// m1 = noise + (signal * X))
// m2 = noise + (signal * (1-X))
// m3 = noise
//
// Hence, assuming all 4 samples have similar amounts of noise in them
// signal = (m1 + m2) - ((m0 + m3) * 2)
// noise = (m0 + m3) / 2
//
F1_sig = (m1 + m2) - ((m0 + m3) << 1);
F1_noise = (m0 + m3) >> 1;
if ( (F1_sig < MODEAC_MSG_SQUELCH_LEVEL) // minimum required F1 signal amplitude
|| (F1_sig < (F1_noise << 2)) ) // minimum allowable Sig/Noise ratio 4:1
{return (0);}
// If we get here then we have a potential F1, so look for an equally valid F2 20.3uS later
//
// Our F1 is centered somewhere between samples m[1] and m[2]. We can guestimate where F2 is
// by comparing the ratio of m1 and m2, and adding on 20.3 uS (40.6 samples)
//
mPhase = ((m2 * 20) / (m1 + m2));
byte = (mPhase + 812) / 20;
n0 = m[byte++]; n1 = m[byte++];
if (n0 >= n1) // n1 *must* be bigger than n0 for this to be F2
{return (0);}
n2 = m[byte++];
//
// if the sample bob on (Phase == 0), don't look at n3
//
if ((mPhase + 812) % 20)
{n3 = m[byte++];}
else
{n3 = n2; n2 = n0;}
if ( (n3 >= n1) // n1 must be bigger than n3
|| (n0 > n2) // n2 can be equal to n0 ( 0,1,0,0 )
|| (n3 > n2) ) // n2 can be equal to n3 ( 0,1,0,0 )
{return (0);}
F2_sig = (n1 + n2) - ((n0 + n3) << 1);
F2_noise = (n0 + n3) >> 1;
if ( (F2_sig < MODEAC_MSG_SQUELCH_LEVEL) // minimum required F2 signal amplitude
|| (F2_sig < (F2_noise << 2)) ) // maximum allowable Sig/Noise ratio 4:1
{return (0);}
fSig = (F1_sig + F2_sig) >> 1;
fNoise = (F1_noise + F2_noise) >> 1;
fLoLo = fNoise + (fSig >> 2); // 1/2
fLevel = fNoise + (fSig >> 1);
lastBitWasOne = 1;
lastBit = F1_sig;
//
// Now step by a half ModeA bit, 0.725nS, which is 1.45 samples, which is 29/20
// No need to do bit 0 because we've already selected it as a valid F1
// Do several bits past the SPI to increase error rejection
//
for (j = 1, mPhase += 29; j < 48; mPhase += 29, j ++)
{
byte = 1 + (mPhase / 20);
thisSample = m[byte] - fNoise;
if (mPhase % 20) // If the bit is split over two samples...
{thisSample += (m[byte+1] - fNoise);} // add in the second sample's energy
// If we're calculating a space value
if (j & 1)
{lastSpace = thisSample;}
else
{// We're calculating a new bit value
bit = j >> 1;
if (thisSample >= fLevel)
{// We're calculating a new bit value, and its a one
ModeABits |= ModeABitTable[bit--]; // or in the correct bit
if (lastBitWasOne)
{ // This bit is one, last bit was one, so check the last space is somewhere less than one
if ( (lastSpace >= (thisSample>>1)) || (lastSpace >= lastBit) )
{ModeAErrs |= ModeAMidTable[bit];}
}
else
{// This bit,is one, last bit was zero, so check the last space is somewhere less than one
if (lastSpace >= (thisSample >> 1))
{ModeAErrs |= ModeAMidTable[bit];}
}
lastBitWasOne = 1;
}
else
{// We're calculating a new bit value, and its a zero
if (lastBitWasOne)
{ // This bit is zero, last bit was one, so check the last space is somewhere in between
if (lastSpace >= lastBit)
{ModeAErrs |= ModeAMidTable[bit];}
}
else
{// This bit,is zero, last bit was zero, so check the last space is zero too
if (lastSpace >= fLoLo)
{ModeAErrs |= ModeAMidTable[bit];}
}
lastBitWasOne = 0;
}
lastBit = (thisSample >> 1);
}
}
//
// Output format is : 00:A4:A2:A1:00:B4:B2:B1:00:C4:C2:C1:00:D4:D2:D1
//
if ((ModeABits < 3) || (ModeABits & 0xFFFF8808) || (ModeAErrs) )
{return (ModeABits = 0);}
fSig = (fSig + 0x7F) >> 8;
mm->signalLevel = ((fSig < 255) ? fSig : 255);
return ModeABits;
}
//
//=========================================================================
//
// Input format is : 00:A4:A2:A1:00:B4:B2:B1:00:C4:C2:C1:00:D4:D2:D1
//
int ModeAToModeC(unsigned int ModeA)
{
unsigned int FiveHundreds = 0;
unsigned int OneHundreds = 0;
if ( (ModeA & 0xFFFF888B) // D1 set is illegal. D2 set is > 62700ft which is unlikely
|| ((ModeA & 0x000000F0) == 0) ) // C1,,C4 cannot be Zero
{return -9999;}
if (ModeA & 0x0010) {OneHundreds ^= 0x007;} // C1
if (ModeA & 0x0020) {OneHundreds ^= 0x003;} // C2
if (ModeA & 0x0040) {OneHundreds ^= 0x001;} // C4
// Remove 7s from OneHundreds (Make 7->5, snd 5->7).
if ((OneHundreds & 5) == 5) {OneHundreds ^= 2;}
// Check for invalid codes, only 1 to 5 are valid
if (OneHundreds > 5)
{return -9999;}
//if (ModeA & 0x0001) {FiveHundreds ^= 0x1FF;} // D1 never used for altitude
if (ModeA & 0x0002) {FiveHundreds ^= 0x0FF;} // D2
if (ModeA & 0x0004) {FiveHundreds ^= 0x07F;} // D4
if (ModeA & 0x1000) {FiveHundreds ^= 0x03F;} // A1
if (ModeA & 0x2000) {FiveHundreds ^= 0x01F;} // A2
if (ModeA & 0x4000) {FiveHundreds ^= 0x00F;} // A4
if (ModeA & 0x0100) {FiveHundreds ^= 0x007;} // B1
if (ModeA & 0x0200) {FiveHundreds ^= 0x003;} // B2
if (ModeA & 0x0400) {FiveHundreds ^= 0x001;} // B4
// Correct order of OneHundreds.
if (FiveHundreds & 1) {OneHundreds = 6 - OneHundreds;}
return ((FiveHundreds * 5) + OneHundreds - 13);
}
//
//=========================================================================
//
void decodeModeAMessage(struct modesMessage *mm, int ModeA)
{
mm->msgtype = 32; // Valid Mode S DF's are DF-00 to DF-31.
// so use 32 to indicate Mode A/C
mm->msgbits = 16; // Fudge up a Mode S style data stream
mm->msg[0] = (ModeA >> 8);
mm->msg[1] = (ModeA);
// Fudge an ICAO address based on Mode A (remove the Ident bit)
// Use an upper address byte of FF, since this is ICAO unallocated
mm->addr = 0x00FF0000 | (ModeA & 0x0000FF7F);
// Set the Identity field to ModeA
mm->modeA = ModeA & 0x7777;
mm->bFlags |= MODES_ACFLAGS_SQUAWK_VALID;
// Flag ident in flight status
mm->fs = ModeA & 0x0080;
// Not much else we can tell from a Mode A/C reply.
// Just fudge up a few bits to keep other code happy
mm->crcok = 1;
mm->correctedbits = 0;
}
//
// ===================== Mode A/C detection and decoding ===================
//

View file

@ -1 +0,0 @@
cd129a02b926ab42fbf9f41ab984f4bb2a3e5e59

File diff suppressed because it is too large Load diff

View file

@ -1,261 +0,0 @@
// ppup1090, a Mode S PlanePlotter Uploader for dump1090 devices.
//
// Copyright (C) 2013 by Malcolm Robb <Support@ATTAvionics.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.
//
// 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
// HOLDER 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 "coaa.h"
#include "ppup1090.h"
//
// ============================= Utility functions ==========================
//
void sigintHandler(int dummy) {
NOTUSED(dummy);
signal(SIGINT, SIG_DFL); // reset signal handler - bit extra safety
Modes.exit = 1; // Signal to threads that we are done
}
//
// =============================== Initialization ===========================
//
void ppup1090InitConfig(void) {
int iErr;
// Default everything to zero/NULL
memset(&Modes, 0, sizeof(Modes));
memset(&ppup1090, 0, sizeof(ppup1090));
// Now initialise things that should not be 0/NULL to their defaults
Modes.check_crc = 1;
Modes.quiet = 1;
Modes.bEnableDFLogging = 1;
strcpy(ppup1090.net_input_beast_ipaddr,PPUP1090_NET_OUTPUT_IP_ADDRESS);
Modes.net_input_beast_port = MODES_NET_OUTPUT_BEAST_PORT;
Modes.interactive_delete_ttl = MODES_INTERACTIVE_DELETE_TTL;
Modes.interactive_display_ttl = MODES_INTERACTIVE_DISPLAY_TTL;
Modes.fUserLat = MODES_USER_LATITUDE_DFLT;
Modes.fUserLon = MODES_USER_LONGITUDE_DFLT;
if ((iErr = openCOAA()))
{
fprintf(stderr, "Error 0x%X initialising uploader\n", iErr);
exit(1);
}
}
//
//=========================================================================
//
void ppup1090Init(void) {
int iErr;
pthread_mutex_init(&Modes.pDF_mutex,NULL);
pthread_mutex_init(&Modes.data_mutex,NULL);
pthread_cond_init(&Modes.data_cond,NULL);
// Allocate the various buffers used by Modes
if ( NULL == (Modes.icao_cache = (uint32_t *) malloc(sizeof(uint32_t) * MODES_ICAO_CACHE_LEN * 2)))
{
fprintf(stderr, "Out of memory allocating data buffer.\n");
exit(1);
}
// Clear the buffers that have just been allocated, just in-case
memset(Modes.icao_cache, 0, sizeof(uint32_t) * MODES_ICAO_CACHE_LEN * 2);
// Validate the users Lat/Lon home location inputs
if ( (Modes.fUserLat > 90.0) // Latitude must be -90 to +90
|| (Modes.fUserLat < -90.0) // and
|| (Modes.fUserLon > 360.0) // Longitude must be -180 to +360
|| (Modes.fUserLon < -180.0) ) {
Modes.fUserLat = Modes.fUserLon = 0.0;
} else if (Modes.fUserLon > 180.0) { // If Longitude is +180 to +360, make it -180 to 0
Modes.fUserLon -= 360.0;
}
// If both Lat and Lon are 0.0 then the users location is either invalid/not-set, or (s)he's in the
// Atlantic ocean off the west coast of Africa. This is unlikely to be correct.
// Set the user LatLon valid flag only if either Lat or Lon are non zero. Note the Greenwich meridian
// is at 0.0 Lon,so we must check for either fLat or fLon being non zero not both.
// Testing the flag at runtime will be much quicker than ((fLon != 0.0) || (fLat != 0.0))
Modes.bUserFlags &= ~MODES_USER_LATLON_VALID;
if ((Modes.fUserLat != 0.0) || (Modes.fUserLon != 0.0)) {
Modes.bUserFlags |= MODES_USER_LATLON_VALID;
}
// Prepare error correction tables
modesInitErrorInfo();
// Setup the uploader - read the user paramaters from the coaa.h header file
coaa1090.ppIPAddr = ppup1090.net_pp_ipaddr;
coaa1090.fUserLat = MODES_USER_LATITUDE_DFLT;
coaa1090.fUserLon = MODES_USER_LONGITUDE_DFLT;
strcpy(coaa1090.strAuthCode,STR(USER_AUTHCODE));
strcpy(coaa1090.strRegNo, STR(USER_REGNO));
strcpy(coaa1090.strVersion, MODES_DUMP1090_VERSION);
if ((iErr = initCOAA (coaa1090)))
{
fprintf(stderr, "Error 0x%X initialising uploader\n", iErr);
exit(1);
}
}
//
// ================================ Main ====================================
//
void showHelp(void) {
printf(
"-----------------------------------------------------------------------------\n"
"| ppup1090 RPi Uploader for COAA Planeplotter Ver : "MODES_DUMP1090_VERSION " |\n"
"-----------------------------------------------------------------------------\n"
"--net-bo-ipaddr <IPv4> TCP Beast output listen IPv4 (default: 127.0.0.1)\n"
"--net-bo-port <port> TCP Beast output listen port (default: 30005)\n"
"--net-pp-ipaddr <IPv4> Plane Plotter LAN IPv4 Address (default: 0.0.0.0)\n"
"--quiet Disable output to stdout. Use for daemon applications\n"
"--help Show this help\n"
);
}
#ifdef _WIN32
void showCopyright(void) {
uint64_t llTime = time(NULL) + 1;
printf(
"-----------------------------------------------------------------------------\n"
"| ppup1090 RPi Uploader for COAA Planeplotter Ver : "MODES_DUMP1090_VERSION " |\n"
"-----------------------------------------------------------------------------\n"
"\n"
" Copyright (C) 2012 by Salvatore Sanfilippo <antirez@gmail.com>\n"
" Copyright (C) 2014 by Malcolm Robb <support@attavionics.com>\n"
"\n"
" All rights reserved.\n"
"\n"
" THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n"
" ""AS IS"" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n"
" LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n"
" A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n"
" HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n"
" SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\n"
" LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n"
" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n"
" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n"
" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n"
" OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n"
"\n"
" For further details refer to <https://github.com/MalcolmRobb/dump1090>\n"
"\n"
);
// delay for 1 second to give the user a chance to read the copyright
while (llTime >= time(NULL)) {}
}
#endif
//
//=========================================================================
//
int main(int argc, char **argv) {
int j, fd;
struct client *c;
// Set sane defaults
ppup1090InitConfig();
signal(SIGINT, sigintHandler); // Define Ctrl/C handler (exit program)
// Parse the command line options
for (j = 1; j < argc; j++) {
int more = ((j + 1) < argc); // There are more arguments
if (!strcmp(argv[j],"--net-bo-port") && more) {
Modes.net_input_beast_port = atoi(argv[++j]);
} else if (!strcmp(argv[j],"--net-bo-ipaddr") && more) {
strcpy(ppup1090.net_input_beast_ipaddr, argv[++j]);
} else if (!strcmp(argv[j],"--net-pp-ipaddr") && more) {
inet_aton(argv[++j], (void *)&ppup1090.net_pp_ipaddr);
} else if (!strcmp(argv[j],"--quiet")) {
ppup1090.quiet = 1;
} else if (!strcmp(argv[j],"--help")) {
showHelp();
exit(0);
} else {
fprintf(stderr, "Unknown or not enough arguments for option '%s'.\n\n", argv[j]);
showHelp();
exit(1);
}
}
#ifdef _WIN32
// Try to comply with the Copyright license conditions for binary distribution
if (!ppup1090.quiet) {showCopyright();}
#endif
// Initialization
ppup1090Init();
// Try to connect to the selected ip address and port. We only support *ONE* input connection which we initiate.here.
if ((fd = anetTcpConnect(Modes.aneterr, ppup1090.net_input_beast_ipaddr, Modes.net_input_beast_port)) == ANET_ERR) {
fprintf(stderr, "Failed to connect to %s:%d\n", ppup1090.net_input_beast_ipaddr, Modes.net_input_beast_port);
exit(1);
}
//
// Setup a service callback client structure for a beast binary input (from dump1090)
// This is a bit dodgy under Windows. The fd parameter is a handle to the internet
// socket on which we are receiving data. Under Linux, these seem to start at 0 and
// count upwards. However, Windows uses "HANDLES" and these don't nececeriy start at 0.
// dump1090 limits fd to values less than 1024, and then uses the fd parameter to
// index into an array of clients. This is ok-ish if handles are allocated up from 0.
// However, there is no gaurantee that Windows will behave like this, and if Windows
// allocates a handle greater than 1024, then dump1090 won't like it. On my test machine,
// the first Windows handle is usually in the 0x54 (84 decimal) region.
c = (struct client *) malloc(sizeof(*c));
c->next = NULL;
c->buflen = 0;
c->fd =
c->service =
Modes.bis = fd;
Modes.clients = c;
// Keep going till the user does something that stops us
while (!Modes.exit) {
modesReadFromClient(c,"",decodeBinMessage);
interactiveRemoveStaleAircrafts();
postCOAA ();
}
// The user has stopped us, so close any socket we opened
if (fd != ANET_ERR)
{close(fd);}
closeCOAA ();
#ifndef _WIN32
pthread_exit(0);
#else
return (0);
#endif
}
//
//=========================================================================
//

View file

@ -1,110 +0,0 @@
// ppup1090, a Mode S PlanePlotter Uploader for dump1090 devices.
//
// Copyright (C) 2013 by Malcolm Robb <Support@ATTAvionics.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.
//
// 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
// HOLDER 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 __PPUP1090_H
#define __PPUP1090_H
// ============================= Include files ==========================
#include "dump1090.h"
#ifndef _WIN32
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <pthread.h>
#include <stdint.h>
#include <errno.h>
#include <unistd.h>
#include <math.h>
#include <sys/time.h>
#include <sys/timeb.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <arpa/inet.h>
#include <signal.h>
#include <fcntl.h>
#include <ctype.h>
#include <sys/stat.h>
#include "rtl-sdr.h"
#include "anet.h"
#include <netdb.h>
#else
#include "winstubs.h" //Put everything Windows specific in here
#endif
// ============================= #defines ===============================
#define PPUP1090_NET_OUTPUT_IP_ADDRESS "127.0.0.1"
#define NOTUSED(V) ((void) V)
#define STR_HELPER(x) #x
#define STR(x) STR_HELPER(x)
// ======================== structure declarations ========================
// Program global state
struct { // Internal state
int quiet;
// Networking
uint32_t net_pp_ipaddr; // IPv4 address of PP instance
char net_input_beast_ipaddr[32]; // IPv4 address or network name of server/RPi
} ppup1090;
// COAA Initialisation structure
struct _coaa1090 {
uint32_t ppIPAddr;
double fUserLat;
double fUserLon;
char strAuthCode[16];
char strRegNo[16];
char strVersion[16];
} coaa1090;
// ======================== function declarations =========================
#ifdef __cplusplus
extern "C" {
#endif
//
// Functions exported from coaa1090.c
//
int openCOAA (void);
int closeCOAA (void);
int initCOAA (struct _coaa1090 coaa1090);
void postCOAA (void);
#ifdef __cplusplus
}
#endif
#endif // __PPUP1090_H

View file

@ -1,85 +0,0 @@
#!/bin/bash
### BEGIN INIT INFO
#
# Provides: dump1090
# Required-Start: $remote_fs
# Required-Stop: $remote_fs
# Default-Start: 2 3 4 5
# Default-Stop: 0 1 6
# Short-Description: dump1090 initscript
#
### END INIT INFO
## Fill in name of program here.
PROG="dump1090"
PROG_PATH="/home/pi/dump1090"
PROG_ARGS="--quiet --net --net-ro-size 500 --net-ro-rate 5 --net-buffer 5"
PIDFILE="/var/run/dump1090.pid"
PROG2="ppup1090"
PROG2_ARGS="--quiet --net-pp-addr 192.168.1.64"
PIDFILE2="/var/run/$PROG2.pid"
DELAY=5
start() {
if [ -e $PIDFILE ]; then
## Program is running, exit with error.
echo "Error! $PROG is currently running!" 1>&2
exit 1
else
## Change from /dev/null to something like /var/log/$PROG if you want to save output.
cd $PROG_PATH
./$PROG $PROG_ARGS 2>&1 >/dev/null &
echo "$PROG started, waiting $DELAY seconds"
touch $PIDFILE
sleep $DELAY
echo "Attempting to start $PROG2.."
./$PROG2 $PROG2_ARGS 2>1 >/dev/null &
echo "$PROG2 started"
touch $PIDFILE2
fi
}
stop() {
if [ -e $PIDFILE ]; then
## Program is running, so stop it
echo "$PROG is running"
killall $PROG2
killall $PROG
rm -f $PIDFILE2
rm -f $PIDFILE
echo "$PROG stopped"
else
## Program is not running, exit with error.
echo "Error! $PROG not started!" 1>&2
exit 1
fi
}
## Check to see if we are running as root first.
## Found at http://www.cyberciti.biz/tips/shell-root-user-check-script.html
if [ "$(id -u)" != "0" ]; then
echo "This script must be run as root" 1>&2
exit 1
fi
case "$1" in
start)
start
exit 0
;;
stop)
stop
exit 0
;;
reload|restart|force-reload)
stop
start
exit 0
;;
**)
echo "Usage: $0 {start|stop|reload}" 1>&2
exit 1
;;
esac
#

File diff suppressed because it is too large Load diff

View file

@ -1,183 +0,0 @@
/*
* Module: sched.h
*
* Purpose:
* Provides an implementation of POSIX realtime extensions
* as defined in
*
* POSIX 1003.1b-1993 (POSIX.1b)
*
* --------------------------------------------------------------------------
*
* Pthreads-win32 - POSIX Threads Library for Win32
* Copyright(C) 1998 John E. Bossom
* Copyright(C) 1999,2005 Pthreads-win32 contributors
*
* Contact Email: rpj@callisto.canberra.edu.au
*
* The current list of contributors is contained
* in the file CONTRIBUTORS included with the source
* code distribution. The list can also be seen at the
* following World Wide Web location:
* http://sources.redhat.com/pthreads-win32/contributors.html
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library in the file COPYING.LIB;
* if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#if !defined(_SCHED_H)
#define _SCHED_H
#undef PTW32_SCHED_LEVEL
#if defined(_POSIX_SOURCE)
#define PTW32_SCHED_LEVEL 0
/* Early POSIX */
#endif
#if defined(_POSIX_C_SOURCE) && _POSIX_C_SOURCE >= 199309
#undef PTW32_SCHED_LEVEL
#define PTW32_SCHED_LEVEL 1
/* Include 1b, 1c and 1d */
#endif
#if defined(INCLUDE_NP)
#undef PTW32_SCHED_LEVEL
#define PTW32_SCHED_LEVEL 2
/* Include Non-Portable extensions */
#endif
#define PTW32_SCHED_LEVEL_MAX 3
#if ( defined(_POSIX_C_SOURCE) && _POSIX_C_SOURCE >= 200112 ) || !defined(PTW32_SCHED_LEVEL)
#define PTW32_SCHED_LEVEL PTW32_SCHED_LEVEL_MAX
/* Include everything */
#endif
#if defined(__GNUC__) && !defined(__declspec)
# error Please upgrade your GNU compiler to one that supports __declspec.
#endif
/*
* When building the library, you should define PTW32_BUILD so that
* the variables/functions are exported correctly. When using the library,
* do NOT define PTW32_BUILD, and then the variables/functions will
* be imported correctly.
*/
#if !defined(PTW32_STATIC_LIB)
# if defined(PTW32_BUILD)
# define PTW32_DLLPORT __declspec (dllexport)
# else
# define PTW32_DLLPORT __declspec (dllimport)
# endif
#else
# define PTW32_DLLPORT
#endif
/*
* This is a duplicate of what is in the autoconf config.h,
* which is only used when building the pthread-win32 libraries.
*/
#if !defined(PTW32_CONFIG_H)
# if defined(WINCE)
# define NEED_ERRNO
# define NEED_SEM
# endif
# if defined(__MINGW64__)
# define HAVE_STRUCT_TIMESPEC
# define HAVE_MODE_T
# elif defined(_UWIN) || defined(__MINGW32__)
# define HAVE_MODE_T
# endif
#endif
/*
*
*/
#if PTW32_SCHED_LEVEL >= PTW32_SCHED_LEVEL_MAX
#if defined(NEED_ERRNO)
#include "need_errno.h"
#else
#include <errno.h>
#endif
#endif /* PTW32_SCHED_LEVEL >= PTW32_SCHED_LEVEL_MAX */
#if (defined(__MINGW64__) || defined(__MINGW32__)) || defined(_UWIN)
# if PTW32_SCHED_LEVEL >= PTW32_SCHED_LEVEL_MAX
/* For pid_t */
# include <sys/types.h>
/* Required by Unix 98 */
# include <time.h>
# else
typedef int pid_t;
# endif
#else
typedef int pid_t;
#endif
/* Thread scheduling policies */
enum {
SCHED_OTHER = 0,
SCHED_FIFO,
SCHED_RR,
SCHED_MIN = SCHED_OTHER,
SCHED_MAX = SCHED_RR
};
struct sched_param {
int sched_priority;
};
#if defined(__cplusplus)
extern "C"
{
#endif /* __cplusplus */
PTW32_DLLPORT int __cdecl sched_yield (void);
PTW32_DLLPORT int __cdecl sched_get_priority_min (int policy);
PTW32_DLLPORT int __cdecl sched_get_priority_max (int policy);
PTW32_DLLPORT int __cdecl sched_setscheduler (pid_t pid, int policy);
PTW32_DLLPORT int __cdecl sched_getscheduler (pid_t pid);
/*
* Note that this macro returns ENOTSUP rather than
* ENOSYS as might be expected. However, returning ENOSYS
* should mean that sched_get_priority_{min,max} are
* not implemented as well as sched_rr_get_interval.
* This is not the case, since we just don't support
* round-robin scheduling. Therefore I have chosen to
* return the same value as sched_setscheduler when
* SCHED_RR is passed to it.
*/
#define sched_rr_get_interval(_pid, _interval) \
( errno = ENOTSUP, (int) -1 )
#if defined(__cplusplus)
} /* End of extern "C" */
#endif /* __cplusplus */
#undef PTW32_SCHED_LEVEL
#undef PTW32_SCHED_LEVEL_MAX
#endif /* !_SCHED_H */

View file

@ -1,169 +0,0 @@
/*
* Module: semaphore.h
*
* Purpose:
* Semaphores aren't actually part of the PThreads standard.
* They are defined by the POSIX Standard:
*
* POSIX 1003.1b-1993 (POSIX.1b)
*
* --------------------------------------------------------------------------
*
* Pthreads-win32 - POSIX Threads Library for Win32
* Copyright(C) 1998 John E. Bossom
* Copyright(C) 1999,2005 Pthreads-win32 contributors
*
* Contact Email: rpj@callisto.canberra.edu.au
*
* The current list of contributors is contained
* in the file CONTRIBUTORS included with the source
* code distribution. The list can also be seen at the
* following World Wide Web location:
* http://sources.redhat.com/pthreads-win32/contributors.html
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library in the file COPYING.LIB;
* if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#if !defined( SEMAPHORE_H )
#define SEMAPHORE_H
#undef PTW32_SEMAPHORE_LEVEL
#if defined(_POSIX_SOURCE)
#define PTW32_SEMAPHORE_LEVEL 0
/* Early POSIX */
#endif
#if defined(_POSIX_C_SOURCE) && _POSIX_C_SOURCE >= 199309
#undef PTW32_SEMAPHORE_LEVEL
#define PTW32_SEMAPHORE_LEVEL 1
/* Include 1b, 1c and 1d */
#endif
#if defined(INCLUDE_NP)
#undef PTW32_SEMAPHORE_LEVEL
#define PTW32_SEMAPHORE_LEVEL 2
/* Include Non-Portable extensions */
#endif
#define PTW32_SEMAPHORE_LEVEL_MAX 3
#if !defined(PTW32_SEMAPHORE_LEVEL)
#define PTW32_SEMAPHORE_LEVEL PTW32_SEMAPHORE_LEVEL_MAX
/* Include everything */
#endif
#if defined(__GNUC__) && ! defined (__declspec)
# error Please upgrade your GNU compiler to one that supports __declspec.
#endif
/*
* When building the library, you should define PTW32_BUILD so that
* the variables/functions are exported correctly. When using the library,
* do NOT define PTW32_BUILD, and then the variables/functions will
* be imported correctly.
*/
#if !defined(PTW32_STATIC_LIB)
# if defined(PTW32_BUILD)
# define PTW32_DLLPORT __declspec (dllexport)
# else
# define PTW32_DLLPORT __declspec (dllimport)
# endif
#else
# define PTW32_DLLPORT
#endif
/*
* This is a duplicate of what is in the autoconf config.h,
* which is only used when building the pthread-win32 libraries.
*/
#if !defined(PTW32_CONFIG_H)
# if defined(WINCE)
# define NEED_ERRNO
# define NEED_SEM
# endif
# if defined(__MINGW64__)
# define HAVE_STRUCT_TIMESPEC
# define HAVE_MODE_T
# elif defined(_UWIN) || defined(__MINGW32__)
# define HAVE_MODE_T
# endif
#endif
/*
*
*/
#if PTW32_SEMAPHORE_LEVEL >= PTW32_SEMAPHORE_LEVEL_MAX
#if defined(NEED_ERRNO)
#include "need_errno.h"
#else
#include <errno.h>
#endif
#endif /* PTW32_SEMAPHORE_LEVEL >= PTW32_SEMAPHORE_LEVEL_MAX */
#define _POSIX_SEMAPHORES
#if defined(__cplusplus)
extern "C"
{
#endif /* __cplusplus */
#if !defined(HAVE_MODE_T)
typedef unsigned int mode_t;
#endif
typedef struct sem_t_ * sem_t;
PTW32_DLLPORT int __cdecl sem_init (sem_t * sem,
int pshared,
unsigned int value);
PTW32_DLLPORT int __cdecl sem_destroy (sem_t * sem);
PTW32_DLLPORT int __cdecl sem_trywait (sem_t * sem);
PTW32_DLLPORT int __cdecl sem_wait (sem_t * sem);
PTW32_DLLPORT int __cdecl sem_timedwait (sem_t * sem,
const struct timespec * abstime);
PTW32_DLLPORT int __cdecl sem_post (sem_t * sem);
PTW32_DLLPORT int __cdecl sem_post_multiple (sem_t * sem,
int count);
PTW32_DLLPORT int __cdecl sem_open (const char * name,
int oflag,
mode_t mode,
unsigned int value);
PTW32_DLLPORT int __cdecl sem_close (sem_t * sem);
PTW32_DLLPORT int __cdecl sem_unlink (const char * name);
PTW32_DLLPORT int __cdecl sem_getvalue (sem_t * sem,
int * sval);
#if defined(__cplusplus)
} /* End of extern "C" */
#endif /* __cplusplus */
#undef PTW32_SEMAPHORE_LEVEL
#undef PTW32_SEMAPHORE_LEVEL_MAX
#endif /* !SEMAPHORE_H */

View file

@ -1,34 +0,0 @@
// --------------------------------------------------------
//
// This file is to configure the configurable settings.
// Load this file before script.js file at gmap.html.
//
// --------------------------------------------------------
// -- Output Settings -------------------------------------
// Show metric values
Metric = false; // true or false
// -- Map settings ----------------------------------------
// The Latitude and Longitude in decimal format
CONST_CENTERLAT = 45.0;
CONST_CENTERLON = 9.0;
// The google maps zoom level, 0 - 16, lower is further out
CONST_ZOOMLVL = 5;
// -- Marker settings -------------------------------------
// The default marker color
MarkerColor = "rgb(127, 127, 127)";
SelectedColor = "rgb(225, 225, 225)";
StaleColor = "rgb(190, 190, 190)";
// -- Site Settings ---------------------------------------
SiteShow = false; // true or false
// The Latitude and Longitude in decimal format
SiteLat = 45.0;
SiteLon = 9.0;
SiteCircles = true; // true or false (Only shown if SiteShow is true)
// In nautical miles or km (depending settings value 'Metric')
SiteCirclesDistances = new Array(100,150,200);

View file

@ -1,318 +0,0 @@
/**
* CoolClock 2.1.4
* Copyright 2010, Simon Baird
* Released under the BSD License.
*
* Display an analog clock using canvas.
* http://randomibis.com/coolclock/
*
*/
// Constructor for CoolClock objects
window.CoolClock = function(options) {
return this.init(options);
}
// Config contains some defaults, and clock skins
CoolClock.config = {
tickDelay: 1000,
longTickDelay: 15000,
defaultRadius: 85,
renderRadius: 100,
defaultSkin: "chunkySwiss",
// Should be in skin probably...
// (TODO: allow skinning of digital display)
showSecs: true,
showAmPm: true,
skins: {
// There are more skins in moreskins.js
// Try making your own skin by copy/pasting one of these and tweaking it
swissRail: {
outerBorder: { lineWidth: 2, radius:95, color: "black", alpha: 1 },
smallIndicator: { lineWidth: 2, startAt: 88, endAt: 92, color: "black", alpha: 1 },
largeIndicator: { lineWidth: 4, startAt: 79, endAt: 92, color: "black", alpha: 1 },
hourHand: { lineWidth: 8, startAt: -15, endAt: 50, color: "black", alpha: 1 },
minuteHand: { lineWidth: 7, startAt: -15, endAt: 75, color: "black", alpha: 1 },
secondHand: { lineWidth: 1, startAt: -20, endAt: 85, color: "red", alpha: 1 },
secondDecoration: { lineWidth: 1, startAt: 70, radius: 4, fillColor: "red", color: "red", alpha: 1 }
},
chunkySwiss: {
outerBorder: { lineWidth: 4, radius:97, color: "black", alpha: 1 },
smallIndicator: { lineWidth: 4, startAt: 89, endAt: 93, color: "black", alpha: 1 },
largeIndicator: { lineWidth: 8, startAt: 80, endAt: 93, color: "black", alpha: 1 },
hourHand: { lineWidth: 12, startAt: -15, endAt: 60, color: "black", alpha: 1 },
minuteHand: { lineWidth: 10, startAt: -15, endAt: 85, color: "black", alpha: 1 },
secondHand: { lineWidth: 4, startAt: -20, endAt: 85, color: "red", alpha: 1 },
secondDecoration: { lineWidth: 2, startAt: 70, radius: 8, fillColor: "red", color: "red", alpha: 1 }
},
chunkySwissOnBlack: {
outerBorder: { lineWidth: 4, radius:97, color: "white", alpha: 1 },
smallIndicator: { lineWidth: 4, startAt: 89, endAt: 93, color: "white", alpha: 1 },
largeIndicator: { lineWidth: 8, startAt: 80, endAt: 93, color: "white", alpha: 1 },
hourHand: { lineWidth: 12, startAt: -15, endAt: 60, color: "white", alpha: 1 },
minuteHand: { lineWidth: 10, startAt: -15, endAt: 85, color: "white", alpha: 1 },
secondHand: { lineWidth: 4, startAt: -20, endAt: 85, color: "red", alpha: 1 },
secondDecoration: { lineWidth: 2, startAt: 70, radius: 8, fillColor: "red", color: "red", alpha: 1 }
}
},
// Test for IE so we can nurse excanvas in a couple of places
isIE: !!document.all,
// Will store (a reference to) each clock here, indexed by the id of the canvas element
clockTracker: {},
// For giving a unique id to coolclock canvases with no id
noIdCount: 0
};
// Define the CoolClock object's methods
CoolClock.prototype = {
// Initialise using the parameters parsed from the colon delimited class
init: function(options) {
// Parse and store the options
this.canvasId = options.canvasId;
this.skinId = options.skinId || CoolClock.config.defaultSkin;
this.displayRadius = options.displayRadius || CoolClock.config.defaultRadius;
this.showSecondHand = typeof options.showSecondHand == "boolean" ? options.showSecondHand : true;
this.gmtOffset = (options.gmtOffset != null && options.gmtOffset != '') ? parseFloat(options.gmtOffset) : null;
this.showDigital = typeof options.showDigital == "boolean" ? options.showDigital : false;
this.logClock = typeof options.logClock == "boolean" ? options.logClock : false;
this.logClockRev = typeof options.logClock == "boolean" ? options.logClockRev : false;
this.tickDelay = CoolClock.config[ this.showSecondHand ? "tickDelay" : "longTickDelay" ];
// Get the canvas element
this.canvas = document.getElementById(this.canvasId);
// Make the canvas the requested size. It's always square.
this.canvas.setAttribute("width",this.displayRadius*2);
this.canvas.setAttribute("height",this.displayRadius*2);
this.canvas.style.width = this.displayRadius*2 + "px";
this.canvas.style.height = this.displayRadius*2 + "px";
// Explain me please...?
this.renderRadius = CoolClock.config.renderRadius;
this.scale = this.displayRadius / this.renderRadius;
// Initialise canvas context
this.ctx = this.canvas.getContext("2d");
this.ctx.scale(this.scale,this.scale);
// Keep track of this object
CoolClock.config.clockTracker[this.canvasId] = this;
// Start the clock going
this.tick();
return this;
},
// Draw a circle at point x,y with params as defined in skin
fullCircleAt: function(x,y,skin) {
this.ctx.save();
this.ctx.globalAlpha = skin.alpha;
this.ctx.lineWidth = skin.lineWidth;
if (!CoolClock.config.isIE) {
this.ctx.beginPath();
}
if (CoolClock.config.isIE) {
// excanvas doesn't scale line width so we will do it here
this.ctx.lineWidth = this.ctx.lineWidth * this.scale;
}
this.ctx.arc(x, y, skin.radius, 0, 2*Math.PI, false);
if (CoolClock.config.isIE) {
// excanvas doesn't close the circle so let's fill in the tiny gap
this.ctx.arc(x, y, skin.radius, -0.1, 0.1, false);
}
if (skin.fillColor) {
this.ctx.fillStyle = skin.fillColor
this.ctx.fill();
}
else {
// XXX why not stroke and fill
this.ctx.strokeStyle = skin.color;
this.ctx.stroke();
}
this.ctx.restore();
},
// Draw some text centered vertically and horizontally
drawTextAt: function(theText,x,y) {
this.ctx.save();
this.ctx.font = '15px sans-serif';
var tSize = this.ctx.measureText(theText);
if (!tSize.height) tSize.height = 15; // no height in firefox.. :(
this.ctx.fillText(theText,x - tSize.width/2,y - tSize.height/2);
this.ctx.restore();
},
lpad2: function(num) {
return (num < 10 ? '0' : '') + num;
},
tickAngle: function(second) {
// Log algorithm by David Bradshaw
var tweak = 3; // If it's lower the one second mark looks wrong (?)
if (this.logClock) {
return second == 0 ? 0 : (Math.log(second*tweak) / Math.log(60*tweak));
}
else if (this.logClockRev) {
// Flip the seconds then flip the angle (trickiness)
second = (60 - second) % 60;
return 1.0 - (second == 0 ? 0 : (Math.log(second*tweak) / Math.log(60*tweak)));
}
else {
return second/60.0;
}
},
timeText: function(hour,min,sec) {
var c = CoolClock.config;
return '' +
(c.showAmPm ? ((hour%12)==0 ? 12 : (hour%12)) : hour) + ':' +
this.lpad2(min) +
(c.showSecs ? ':' + this.lpad2(sec) : '') +
(c.showAmPm ? (hour < 12 ? ' am' : ' pm') : '')
;
},
// Draw a radial line by rotating then drawing a straight line
// Ha ha, I think I've accidentally used Taus, (see http://tauday.com/)
radialLineAtAngle: function(angleFraction,skin) {
this.ctx.save();
this.ctx.translate(this.renderRadius,this.renderRadius);
this.ctx.rotate(Math.PI * (2.0 * angleFraction - 0.5));
this.ctx.globalAlpha = skin.alpha;
this.ctx.strokeStyle = skin.color;
this.ctx.lineWidth = skin.lineWidth;
if (CoolClock.config.isIE)
// excanvas doesn't scale line width so we will do it here
this.ctx.lineWidth = this.ctx.lineWidth * this.scale;
if (skin.radius) {
this.fullCircleAt(skin.startAt,0,skin)
}
else {
this.ctx.beginPath();
this.ctx.moveTo(skin.startAt,0)
this.ctx.lineTo(skin.endAt,0);
this.ctx.stroke();
}
this.ctx.restore();
},
render: function(hour,min,sec) {
// Get the skin
var skin = CoolClock.config.skins[this.skinId];
if (!skin) skin = CoolClock.config.skins[CoolClock.config.defaultSkin];
// Clear
this.ctx.clearRect(0,0,this.renderRadius*2,this.renderRadius*2);
// Draw the outer edge of the clock
if (skin.outerBorder)
this.fullCircleAt(this.renderRadius,this.renderRadius,skin.outerBorder);
// Draw the tick marks. Every 5th one is a big one
for (var i=0;i<60;i++) {
(i%5) && skin.smallIndicator && this.radialLineAtAngle(this.tickAngle(i),skin.smallIndicator);
!(i%5) && skin.largeIndicator && this.radialLineAtAngle(this.tickAngle(i),skin.largeIndicator);
}
// Write the time
if (this.showDigital) {
this.drawTextAt(
this.timeText(hour,min,sec),
this.renderRadius,
this.renderRadius+this.renderRadius/2
);
}
// Draw the hands
if (skin.hourHand)
this.radialLineAtAngle(this.tickAngle(((hour%12)*5 + min/12.0)),skin.hourHand);
if (skin.minuteHand)
this.radialLineAtAngle(this.tickAngle((min + sec/60.0)),skin.minuteHand);
if (this.showSecondHand && skin.secondHand)
this.radialLineAtAngle(this.tickAngle(sec),skin.secondHand);
// Second hand decoration doesn't render right in IE so lets turn it off
if (!CoolClock.config.isIE && this.showSecondHand && skin.secondDecoration)
this.radialLineAtAngle(this.tickAngle(sec),skin.secondDecoration);
},
// Check the time and display the clock
refreshDisplay: function() {
var now = new Date();
if (this.gmtOffset != null) {
// Use GMT + gmtOffset
var offsetNow = new Date(now.valueOf() + (this.gmtOffset * 1000 * 60 * 60));
this.render(offsetNow.getUTCHours(),offsetNow.getUTCMinutes(),offsetNow.getUTCSeconds());
}
else {
// Use local time
this.render(now.getHours(),now.getMinutes(),now.getSeconds());
}
},
// Set timeout to trigger a tick in the future
nextTick: function() {
setTimeout("CoolClock.config.clockTracker['"+this.canvasId+"'].tick()",this.tickDelay);
},
// Check the canvas element hasn't been removed
stillHere: function() {
return document.getElementById(this.canvasId) != null;
},
// Main tick handler. Refresh the clock then setup the next tick
tick: function() {
if (this.stillHere()) {
this.refreshDisplay()
this.nextTick();
}
}
};
// Find all canvas elements that have the CoolClock class and turns them into clocks
CoolClock.findAndCreateClocks = function() {
// (Let's not use a jQuery selector here so it's easier to use frameworks other than jQuery)
var canvases = document.getElementsByTagName("canvas");
for (var i=0;i<canvases.length;i++) {
// Pull out the fields from the class. Example "CoolClock:chunkySwissOnBlack:1000"
var fields = canvases[i].className.split(" ")[0].split(":");
if (fields[0] == "CoolClock") {
if (!canvases[i].id) {
// If there's no id on this canvas element then give it one
canvases[i].id = '_coolclock_auto_id_' + CoolClock.config.noIdCount++;
}
// Create a clock object for this element
new CoolClock({
canvasId: canvases[i].id,
skinId: fields[1],
displayRadius: fields[2],
showSecondHand: fields[3]!='noSeconds',
gmtOffset: fields[4],
showDigital: fields[5]=='showDigital',
logClock: fields[6]=='logClock',
logClockRev: fields[6]=='logClockRev'
});
}
}
};
// If you don't have jQuery then you need a body onload like this: <body onload="CoolClock.findAndCreateClocks()">
// If you do have jQuery and it's loaded already then we can do it right now
if (window.jQuery) jQuery(document).ready(CoolClock.findAndCreateClocks);

View file

@ -1,785 +0,0 @@
// Copyright 2006 Google Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// Known Issues:
//
// * Patterns are not implemented.
// * Radial gradient are not implemented. The VML version of these look very
// different from the canvas one.
// * Clipping paths are not implemented.
// * Coordsize. The width and height attribute have higher priority than the
// width and height style values which isn't correct.
// * Painting mode isn't implemented.
// * Canvas width/height should is using content-box by default. IE in
// Quirks mode will draw the canvas using border-box. Either change your
// doctype to HTML5
// (http://www.whatwg.org/specs/web-apps/current-work/#the-doctype)
// or use Box Sizing Behavior from WebFX
// (http://webfx.eae.net/dhtml/boxsizing/boxsizing.html)
// * Optimize. There is always room for speed improvements.
// only add this code if we do not already have a canvas implementation
if (!window.CanvasRenderingContext2D) {
(function () {
// alias some functions to make (compiled) code shorter
var m = Math;
var mr = m.round;
var ms = m.sin;
var mc = m.cos;
// this is used for sub pixel precision
var Z = 10;
var Z2 = Z / 2;
var G_vmlCanvasManager_ = {
init: function (opt_doc) {
var doc = opt_doc || document;
if (/MSIE/.test(navigator.userAgent) && !window.opera) {
var self = this;
doc.attachEvent("onreadystatechange", function () {
self.init_(doc);
});
}
},
init_: function (doc) {
if (doc.readyState == "complete") {
// create xmlns
if (!doc.namespaces["g_vml_"]) {
doc.namespaces.add("g_vml_", "urn:schemas-microsoft-com:vml");
}
// setup default css
var ss = doc.createStyleSheet();
ss.cssText = "canvas{display:inline-block;overflow:hidden;" +
// default size is 300x150 in Gecko and Opera
"text-align:left;width:300px;height:150px}" +
"g_vml_\\:*{behavior:url(#default#VML)}";
// find all canvas elements
var els = doc.getElementsByTagName("canvas");
for (var i = 0; i < els.length; i++) {
if (!els[i].getContext) {
this.initElement(els[i]);
}
}
}
},
fixElement_: function (el) {
// in IE before version 5.5 we would need to add HTML: to the tag name
// but we do not care about IE before version 6
var outerHTML = el.outerHTML;
var newEl = el.ownerDocument.createElement(outerHTML);
// if the tag is still open IE has created the children as siblings and
// it has also created a tag with the name "/FOO"
if (outerHTML.slice(-2) != "/>") {
var tagName = "/" + el.tagName;
var ns;
// remove content
while ((ns = el.nextSibling) && ns.tagName != tagName) {
ns.removeNode();
}
// remove the incorrect closing tag
if (ns) {
ns.removeNode();
}
}
el.parentNode.replaceChild(newEl, el);
return newEl;
},
/**
* Public initializes a canvas element so that it can be used as canvas
* element from now on. This is called automatically before the page is
* loaded but if you are creating elements using createElement you need to
* make sure this is called on the element.
* @param {HTMLElement} el The canvas element to initialize.
* @return {HTMLElement} the element that was created.
*/
initElement: function (el) {
el = this.fixElement_(el);
el.getContext = function () {
if (this.context_) {
return this.context_;
}
return this.context_ = new CanvasRenderingContext2D_(this);
};
// do not use inline function because that will leak memory
el.attachEvent('onpropertychange', onPropertyChange);
el.attachEvent('onresize', onResize);
var attrs = el.attributes;
if (attrs.width && attrs.width.specified) {
// TODO: use runtimeStyle and coordsize
// el.getContext().setWidth_(attrs.width.nodeValue);
el.style.width = attrs.width.nodeValue + "px";
} else {
el.width = el.clientWidth;
}
if (attrs.height && attrs.height.specified) {
// TODO: use runtimeStyle and coordsize
// el.getContext().setHeight_(attrs.height.nodeValue);
el.style.height = attrs.height.nodeValue + "px";
} else {
el.height = el.clientHeight;
}
//el.getContext().setCoordsize_()
return el;
}
};
function onPropertyChange(e) {
var el = e.srcElement;
switch (e.propertyName) {
case 'width':
el.style.width = el.attributes.width.nodeValue + "px";
el.getContext().clearRect();
break;
case 'height':
el.style.height = el.attributes.height.nodeValue + "px";
el.getContext().clearRect();
break;
}
}
function onResize(e) {
var el = e.srcElement;
if (el.firstChild) {
el.firstChild.style.width = el.clientWidth + 'px';
el.firstChild.style.height = el.clientHeight + 'px';
}
}
G_vmlCanvasManager_.init();
// precompute "00" to "FF"
var dec2hex = [];
for (var i = 0; i < 16; i++) {
for (var j = 0; j < 16; j++) {
dec2hex[i * 16 + j] = i.toString(16) + j.toString(16);
}
}
function createMatrixIdentity() {
return [
[1, 0, 0],
[0, 1, 0],
[0, 0, 1]
];
}
function matrixMultiply(m1, m2) {
var result = createMatrixIdentity();
for (var x = 0; x < 3; x++) {
for (var y = 0; y < 3; y++) {
var sum = 0;
for (var z = 0; z < 3; z++) {
sum += m1[x][z] * m2[z][y];
}
result[x][y] = sum;
}
}
return result;
}
function copyState(o1, o2) {
o2.fillStyle = o1.fillStyle;
o2.lineCap = o1.lineCap;
o2.lineJoin = o1.lineJoin;
o2.lineWidth = o1.lineWidth;
o2.miterLimit = o1.miterLimit;
o2.shadowBlur = o1.shadowBlur;
o2.shadowColor = o1.shadowColor;
o2.shadowOffsetX = o1.shadowOffsetX;
o2.shadowOffsetY = o1.shadowOffsetY;
o2.strokeStyle = o1.strokeStyle;
o2.arcScaleX_ = o1.arcScaleX_;
o2.arcScaleY_ = o1.arcScaleY_;
}
function processStyle(styleString) {
var str, alpha = 1;
styleString = String(styleString);
if (styleString.substring(0, 3) == "rgb") {
var start = styleString.indexOf("(", 3);
var end = styleString.indexOf(")", start + 1);
var guts = styleString.substring(start + 1, end).split(",");
str = "#";
for (var i = 0; i < 3; i++) {
str += dec2hex[Number(guts[i])];
}
if ((guts.length == 4) && (styleString.substr(3, 1) == "a")) {
alpha = guts[3];
}
} else {
str = styleString;
}
return [str, alpha];
}
function processLineCap(lineCap) {
switch (lineCap) {
case "butt":
return "flat";
case "round":
return "round";
case "square":
default:
return "square";
}
}
/**
* This class implements CanvasRenderingContext2D interface as described by
* the WHATWG.
* @param {HTMLElement} surfaceElement The element that the 2D context should
* be associated with
*/
function CanvasRenderingContext2D_(surfaceElement) {
this.m_ = createMatrixIdentity();
this.mStack_ = [];
this.aStack_ = [];
this.currentPath_ = [];
// Canvas context properties
this.strokeStyle = "#000";
this.fillStyle = "#000";
this.lineWidth = 1;
this.lineJoin = "miter";
this.lineCap = "butt";
this.miterLimit = Z * 1;
this.globalAlpha = 1;
this.canvas = surfaceElement;
var el = surfaceElement.ownerDocument.createElement('div');
el.style.width = surfaceElement.clientWidth + 'px';
el.style.height = surfaceElement.clientHeight + 'px';
el.style.overflow = 'hidden';
el.style.position = 'absolute';
surfaceElement.appendChild(el);
this.element_ = el;
this.arcScaleX_ = 1;
this.arcScaleY_ = 1;
};
var contextPrototype = CanvasRenderingContext2D_.prototype;
contextPrototype.clearRect = function() {
this.element_.innerHTML = "";
this.currentPath_ = [];
};
contextPrototype.beginPath = function() {
// TODO: Branch current matrix so that save/restore has no effect
// as per safari docs.
this.currentPath_ = [];
};
contextPrototype.moveTo = function(aX, aY) {
this.currentPath_.push({type: "moveTo", x: aX, y: aY});
this.currentX_ = aX;
this.currentY_ = aY;
};
contextPrototype.lineTo = function(aX, aY) {
this.currentPath_.push({type: "lineTo", x: aX, y: aY});
this.currentX_ = aX;
this.currentY_ = aY;
};
contextPrototype.bezierCurveTo = function(aCP1x, aCP1y,
aCP2x, aCP2y,
aX, aY) {
this.currentPath_.push({type: "bezierCurveTo",
cp1x: aCP1x,
cp1y: aCP1y,
cp2x: aCP2x,
cp2y: aCP2y,
x: aX,
y: aY});
this.currentX_ = aX;
this.currentY_ = aY;
};
contextPrototype.quadraticCurveTo = function(aCPx, aCPy, aX, aY) {
// the following is lifted almost directly from
// http://developer.mozilla.org/en/docs/Canvas_tutorial:Drawing_shapes
var cp1x = this.currentX_ + 2.0 / 3.0 * (aCPx - this.currentX_);
var cp1y = this.currentY_ + 2.0 / 3.0 * (aCPy - this.currentY_);
var cp2x = cp1x + (aX - this.currentX_) / 3.0;
var cp2y = cp1y + (aY - this.currentY_) / 3.0;
this.bezierCurveTo(cp1x, cp1y, cp2x, cp2y, aX, aY);
};
contextPrototype.arc = function(aX, aY, aRadius,
aStartAngle, aEndAngle, aClockwise) {
aRadius *= Z;
var arcType = aClockwise ? "at" : "wa";
var xStart = aX + (mc(aStartAngle) * aRadius) - Z2;
var yStart = aY + (ms(aStartAngle) * aRadius) - Z2;
var xEnd = aX + (mc(aEndAngle) * aRadius) - Z2;
var yEnd = aY + (ms(aEndAngle) * aRadius) - Z2;
// IE won't render arches drawn counter clockwise if xStart == xEnd.
if (xStart == xEnd && !aClockwise) {
xStart += 0.125; // Offset xStart by 1/80 of a pixel. Use something
// that can be represented in binary
}
this.currentPath_.push({type: arcType,
x: aX,
y: aY,
radius: aRadius,
xStart: xStart,
yStart: yStart,
xEnd: xEnd,
yEnd: yEnd});
};
contextPrototype.rect = function(aX, aY, aWidth, aHeight) {
this.moveTo(aX, aY);
this.lineTo(aX + aWidth, aY);
this.lineTo(aX + aWidth, aY + aHeight);
this.lineTo(aX, aY + aHeight);
this.closePath();
};
contextPrototype.strokeRect = function(aX, aY, aWidth, aHeight) {
// Will destroy any existing path (same as FF behaviour)
this.beginPath();
this.moveTo(aX, aY);
this.lineTo(aX + aWidth, aY);
this.lineTo(aX + aWidth, aY + aHeight);
this.lineTo(aX, aY + aHeight);
this.closePath();
this.stroke();
};
contextPrototype.fillRect = function(aX, aY, aWidth, aHeight) {
// Will destroy any existing path (same as FF behaviour)
this.beginPath();
this.moveTo(aX, aY);
this.lineTo(aX + aWidth, aY);
this.lineTo(aX + aWidth, aY + aHeight);
this.lineTo(aX, aY + aHeight);
this.closePath();
this.fill();
};
contextPrototype.createLinearGradient = function(aX0, aY0, aX1, aY1) {
var gradient = new CanvasGradient_("gradient");
return gradient;
};
contextPrototype.createRadialGradient = function(aX0, aY0,
aR0, aX1,
aY1, aR1) {
var gradient = new CanvasGradient_("gradientradial");
gradient.radius1_ = aR0;
gradient.radius2_ = aR1;
gradient.focus_.x = aX0;
gradient.focus_.y = aY0;
return gradient;
};
contextPrototype.drawImage = function (image, var_args) {
var dx, dy, dw, dh, sx, sy, sw, sh;
// to find the original width we overide the width and height
var oldRuntimeWidth = image.runtimeStyle.width;
var oldRuntimeHeight = image.runtimeStyle.height;
image.runtimeStyle.width = 'auto';
image.runtimeStyle.height = 'auto';
// get the original size
var w = image.width;
var h = image.height;
// and remove overides
image.runtimeStyle.width = oldRuntimeWidth;
image.runtimeStyle.height = oldRuntimeHeight;
if (arguments.length == 3) {
dx = arguments[1];
dy = arguments[2];
sx = sy = 0;
sw = dw = w;
sh = dh = h;
} else if (arguments.length == 5) {
dx = arguments[1];
dy = arguments[2];
dw = arguments[3];
dh = arguments[4];
sx = sy = 0;
sw = w;
sh = h;
} else if (arguments.length == 9) {
sx = arguments[1];
sy = arguments[2];
sw = arguments[3];
sh = arguments[4];
dx = arguments[5];
dy = arguments[6];
dw = arguments[7];
dh = arguments[8];
} else {
throw "Invalid number of arguments";
}
var d = this.getCoords_(dx, dy);
var w2 = sw / 2;
var h2 = sh / 2;
var vmlStr = [];
var W = 10;
var H = 10;
// For some reason that I've now forgotten, using divs didn't work
vmlStr.push(' <g_vml_:group',
' coordsize="', Z * W, ',', Z * H, '"',
' coordorigin="0,0"' ,
' style="width:', W, ';height:', H, ';position:absolute;');
// If filters are necessary (rotation exists), create them
// filters are bog-slow, so only create them if abbsolutely necessary
// The following check doesn't account for skews (which don't exist
// in the canvas spec (yet) anyway.
if (this.m_[0][0] != 1 || this.m_[0][1]) {
var filter = [];
// Note the 12/21 reversal
filter.push("M11='", this.m_[0][0], "',",
"M12='", this.m_[1][0], "',",
"M21='", this.m_[0][1], "',",
"M22='", this.m_[1][1], "',",
"Dx='", mr(d.x / Z), "',",
"Dy='", mr(d.y / Z), "'");
// Bounding box calculation (need to minimize displayed area so that
// filters don't waste time on unused pixels.
var max = d;
var c2 = this.getCoords_(dx + dw, dy);
var c3 = this.getCoords_(dx, dy + dh);
var c4 = this.getCoords_(dx + dw, dy + dh);
max.x = Math.max(max.x, c2.x, c3.x, c4.x);
max.y = Math.max(max.y, c2.y, c3.y, c4.y);
vmlStr.push("padding:0 ", mr(max.x / Z), "px ", mr(max.y / Z),
"px 0;filter:progid:DXImageTransform.Microsoft.Matrix(",
filter.join(""), ", sizingmethod='clip');")
} else {
vmlStr.push("top:", mr(d.y / Z), "px;left:", mr(d.x / Z), "px;")
}
vmlStr.push(' ">' ,
'<g_vml_:image src="', image.src, '"',
' style="width:', Z * dw, ';',
' height:', Z * dh, ';"',
' cropleft="', sx / w, '"',
' croptop="', sy / h, '"',
' cropright="', (w - sx - sw) / w, '"',
' cropbottom="', (h - sy - sh) / h, '"',
' />',
'</g_vml_:group>');
this.element_.insertAdjacentHTML("BeforeEnd",
vmlStr.join(""));
};
contextPrototype.stroke = function(aFill) {
var lineStr = [];
var lineOpen = false;
var a = processStyle(aFill ? this.fillStyle : this.strokeStyle);
var color = a[0];
var opacity = a[1] * this.globalAlpha;
var W = 10;
var H = 10;
lineStr.push('<g_vml_:shape',
' fillcolor="', color, '"',
' filled="', Boolean(aFill), '"',
' style="position:absolute;width:', W, ';height:', H, ';"',
' coordorigin="0 0" coordsize="', Z * W, ' ', Z * H, '"',
' stroked="', !aFill, '"',
' strokeweight="', this.lineWidth, '"',
' strokecolor="', color, '"',
' path="');
var newSeq = false;
var min = {x: null, y: null};
var max = {x: null, y: null};
for (var i = 0; i < this.currentPath_.length; i++) {
var p = this.currentPath_[i];
if (p.type == "moveTo") {
lineStr.push(" m ");
var c = this.getCoords_(p.x, p.y);
lineStr.push(mr(c.x), ",", mr(c.y));
} else if (p.type == "lineTo") {
lineStr.push(" l ");
var c = this.getCoords_(p.x, p.y);
lineStr.push(mr(c.x), ",", mr(c.y));
} else if (p.type == "close") {
lineStr.push(" x ");
} else if (p.type == "bezierCurveTo") {
lineStr.push(" c ");
var c = this.getCoords_(p.x, p.y);
var c1 = this.getCoords_(p.cp1x, p.cp1y);
var c2 = this.getCoords_(p.cp2x, p.cp2y);
lineStr.push(mr(c1.x), ",", mr(c1.y), ",",
mr(c2.x), ",", mr(c2.y), ",",
mr(c.x), ",", mr(c.y));
} else if (p.type == "at" || p.type == "wa") {
lineStr.push(" ", p.type, " ");
var c = this.getCoords_(p.x, p.y);
var cStart = this.getCoords_(p.xStart, p.yStart);
var cEnd = this.getCoords_(p.xEnd, p.yEnd);
lineStr.push(mr(c.x - this.arcScaleX_ * p.radius), ",",
mr(c.y - this.arcScaleY_ * p.radius), " ",
mr(c.x + this.arcScaleX_ * p.radius), ",",
mr(c.y + this.arcScaleY_ * p.radius), " ",
mr(cStart.x), ",", mr(cStart.y), " ",
mr(cEnd.x), ",", mr(cEnd.y));
}
// TODO: Following is broken for curves due to
// move to proper paths.
// Figure out dimensions so we can do gradient fills
// properly
if(c) {
if (min.x == null || c.x < min.x) {
min.x = c.x;
}
if (max.x == null || c.x > max.x) {
max.x = c.x;
}
if (min.y == null || c.y < min.y) {
min.y = c.y;
}
if (max.y == null || c.y > max.y) {
max.y = c.y;
}
}
}
lineStr.push(' ">');
if (typeof this.fillStyle == "object") {
var focus = {x: "50%", y: "50%"};
var width = (max.x - min.x);
var height = (max.y - min.y);
var dimension = (width > height) ? width : height;
focus.x = mr((this.fillStyle.focus_.x / width) * 100 + 50) + "%";
focus.y = mr((this.fillStyle.focus_.y / height) * 100 + 50) + "%";
var colors = [];
// inside radius (%)
if (this.fillStyle.type_ == "gradientradial") {
var inside = (this.fillStyle.radius1_ / dimension * 100);
// percentage that outside radius exceeds inside radius
var expansion = (this.fillStyle.radius2_ / dimension * 100) - inside;
} else {
var inside = 0;
var expansion = 100;
}
var insidecolor = {offset: null, color: null};
var outsidecolor = {offset: null, color: null};
// We need to sort 'colors' by percentage, from 0 > 100 otherwise ie
// won't interpret it correctly
this.fillStyle.colors_.sort(function (cs1, cs2) {
return cs1.offset - cs2.offset;
});
for (var i = 0; i < this.fillStyle.colors_.length; i++) {
var fs = this.fillStyle.colors_[i];
colors.push( (fs.offset * expansion) + inside, "% ", fs.color, ",");
if (fs.offset > insidecolor.offset || insidecolor.offset == null) {
insidecolor.offset = fs.offset;
insidecolor.color = fs.color;
}
if (fs.offset < outsidecolor.offset || outsidecolor.offset == null) {
outsidecolor.offset = fs.offset;
outsidecolor.color = fs.color;
}
}
colors.pop();
lineStr.push('<g_vml_:fill',
' color="', outsidecolor.color, '"',
' color2="', insidecolor.color, '"',
' type="', this.fillStyle.type_, '"',
' focusposition="', focus.x, ', ', focus.y, '"',
' colors="', colors.join(""), '"',
' opacity="', opacity, '" />');
} else if (aFill) {
lineStr.push('<g_vml_:fill color="', color, '" opacity="', opacity, '" />');
} else {
lineStr.push(
'<g_vml_:stroke',
' opacity="', opacity,'"',
' joinstyle="', this.lineJoin, '"',
' miterlimit="', this.miterLimit, '"',
' endcap="', processLineCap(this.lineCap) ,'"',
' weight="', this.lineWidth, 'px"',
' color="', color,'" />'
);
}
lineStr.push("</g_vml_:shape>");
this.element_.insertAdjacentHTML("beforeEnd", lineStr.join(""));
this.currentPath_ = [];
};
contextPrototype.fill = function() {
this.stroke(true);
}
contextPrototype.closePath = function() {
this.currentPath_.push({type: "close"});
};
/**
* @private
*/
contextPrototype.getCoords_ = function(aX, aY) {
return {
x: Z * (aX * this.m_[0][0] + aY * this.m_[1][0] + this.m_[2][0]) - Z2,
y: Z * (aX * this.m_[0][1] + aY * this.m_[1][1] + this.m_[2][1]) - Z2
}
};
contextPrototype.save = function() {
var o = {};
copyState(this, o);
this.aStack_.push(o);
this.mStack_.push(this.m_);
this.m_ = matrixMultiply(createMatrixIdentity(), this.m_);
};
contextPrototype.restore = function() {
copyState(this.aStack_.pop(), this);
this.m_ = this.mStack_.pop();
};
contextPrototype.translate = function(aX, aY) {
var m1 = [
[1, 0, 0],
[0, 1, 0],
[aX, aY, 1]
];
this.m_ = matrixMultiply(m1, this.m_);
};
contextPrototype.rotate = function(aRot) {
var c = mc(aRot);
var s = ms(aRot);
var m1 = [
[c, s, 0],
[-s, c, 0],
[0, 0, 1]
];
this.m_ = matrixMultiply(m1, this.m_);
};
contextPrototype.scale = function(aX, aY) {
this.arcScaleX_ *= aX;
this.arcScaleY_ *= aY;
var m1 = [
[aX, 0, 0],
[0, aY, 0],
[0, 0, 1]
];
this.m_ = matrixMultiply(m1, this.m_);
};
/******** STUBS ********/
contextPrototype.clip = function() {
// TODO: Implement
};
contextPrototype.arcTo = function() {
// TODO: Implement
};
contextPrototype.createPattern = function() {
return new CanvasPattern_;
};
// Gradient / Pattern Stubs
function CanvasGradient_(aType) {
this.type_ = aType;
this.radius1_ = 0;
this.radius2_ = 0;
this.colors_ = [];
this.focus_ = {x: 0, y: 0};
}
CanvasGradient_.prototype.addColorStop = function(aOffset, aColor) {
aColor = processStyle(aColor);
this.colors_.push({offset: 1-aOffset, color: aColor});
};
function CanvasPattern_() {}
// set up externs
G_vmlCanvasManager = G_vmlCanvasManager_;
CanvasRenderingContext2D = CanvasRenderingContext2D_;
CanvasGradient = CanvasGradient_;
CanvasPattern = CanvasPattern_;
})();
} // if

View file

@ -1,212 +0,0 @@
CoolClock.config.skins = {
swissRail: {
outerBorder: { lineWidth: 2, radius: 95, color: "black", alpha: 1 },
smallIndicator: { lineWidth: 2, startAt: 88, endAt: 92, color: "black", alpha: 1 },
largeIndicator: { lineWidth: 4, startAt: 79, endAt: 92, color: "black", alpha: 1 },
hourHand: { lineWidth: 8, startAt: -15, endAt: 50, color: "black", alpha: 1 },
minuteHand: { lineWidth: 7, startAt: -15, endAt: 75, color: "black", alpha: 1 },
secondHand: { lineWidth: 1, startAt: -20, endAt: 85, color: "red", alpha: 1 },
secondDecoration: { lineWidth: 1, startAt: 70, radius: 4, fillColor: "red", color: "red", alpha: 1 }
},
chunkySwiss: {
outerBorder: { lineWidth: 4, radius: 97, color: "black", alpha: 1 },
smallIndicator: { lineWidth: 4, startAt: 89, endAt: 93, color: "black", alpha: 1 },
largeIndicator: { lineWidth: 8, startAt: 80, endAt: 93, color: "black", alpha: 1 },
hourHand: { lineWidth: 12, startAt: -15, endAt: 60, color: "black", alpha: 1 },
minuteHand: { lineWidth: 10, startAt: -15, endAt: 85, color: "black", alpha: 1 },
secondHand: { lineWidth: 4, startAt: -20, endAt: 85, color: "red", alpha: 1 },
secondDecoration: { lineWidth: 2, startAt: 70, radius: 8, fillColor: "red", color: "red", alpha: 1 }
},
chunkySwissOnBlack: {
outerBorder: { lineWidth: 4, radius: 97, color: "white", alpha: 1 },
smallIndicator: { lineWidth: 4, startAt: 89, endAt: 93, color: "white", alpha: 1 },
largeIndicator: { lineWidth: 8, startAt: 80, endAt: 93, color: "white", alpha: 1 },
hourHand: { lineWidth: 12, startAt: -15, endAt: 60, color: "white", alpha: 1 },
minuteHand: { lineWidth: 10, startAt: -15, endAt: 85, color: "white", alpha: 1 },
secondHand: { lineWidth: 4, startAt: -20, endAt: 85, color: "red", alpha: 1 },
secondDecoration: { lineWidth: 2, startAt: 70, radius: 8, fillColor: "red", color: "red", alpha: 1 }
},
fancy: {
outerBorder: { lineWidth: 5, radius: 95, color: "green", alpha: 0.7 },
smallIndicator: { lineWidth: 1, startAt: 80, endAt: 93, color: "black", alpha: 0.4 },
largeIndicator: { lineWidth: 1, startAt: 30, endAt: 93, color: "black", alpha: 0.5 },
hourHand: { lineWidth: 8, startAt: -15, endAt: 50, color: "blue", alpha: 0.7 },
minuteHand: { lineWidth: 7, startAt: -15, endAt: 92, color: "red", alpha: 0.7 },
secondHand: { lineWidth: 10, startAt: 80, endAt: 85, color: "blue", alpha: 0.3 },
secondDecoration: { lineWidth: 1, startAt: 30, radius: 50, fillColor: "blue", color: "red", alpha: 0.15 }
},
machine: {
outerBorder: { lineWidth: 60, radius: 55, color: "#dd6655", alpha: 1 },
smallIndicator: { lineWidth: 4, startAt: 80, endAt: 95, color: "white", alpha: 1 },
largeIndicator: { lineWidth: 14, startAt: 77, endAt: 92, color: "#dd6655", alpha: 1 },
hourHand: { lineWidth: 18, startAt: -15, endAt: 40, color: "white", alpha: 1 },
minuteHand: { lineWidth: 14, startAt: 24, endAt: 100, color: "#771100", alpha: 0.5 },
secondHand: { lineWidth: 3, startAt: 22, endAt: 83, color: "green", alpha: 0 },
secondDecoration: { lineWidth: 1, startAt: 52, radius: 26, fillColor: "#ffcccc", color: "red", alpha: 0.5 }
},
simonbaird_com: {
hourHand: { lineWidth: 80, startAt: -15, endAt: 35, color: 'magenta', alpha: 0.5 },
minuteHand: { lineWidth: 80, startAt: -15, endAt: 65, color: 'cyan', alpha: 0.5 },
secondDecoration: { lineWidth: 1, startAt: 40, radius: 40, color: "#fff", fillColor: 'yellow', alpha: 0.5 }
},
// by bonstio, http://bonstio.net
classic/*was gIG*/: {
outerBorder: { lineWidth: 185, radius: 1, color: "#E5ECF9", alpha: 1 },
smallIndicator: { lineWidth: 2, startAt: 89, endAt: 94, color: "#3366CC", alpha: 1 },
largeIndicator: { lineWidth: 4, startAt: 83, endAt: 94, color: "#3366CC", alpha: 1 },
hourHand: { lineWidth: 5, startAt: 0, endAt: 60, color: "black", alpha: 1 },
minuteHand: { lineWidth: 4, startAt: 0, endAt: 80, color: "black", alpha: 1 },
secondHand: { lineWidth: 1, startAt: -20, endAt: 85, color: "red", alpha: .85 },
secondDecoration: { lineWidth: 3, startAt: 0, radius: 2, fillColor: "black", color: "black", alpha: 1 }
},
modern/*was gIG2*/: {
outerBorder: { lineWidth: 185, radius: 1, color: "#E5ECF9", alpha: 1 },
smallIndicator: { lineWidth: 5, startAt: 88, endAt: 94, color: "#3366CC", alpha: 1 },
largeIndicator: { lineWidth: 5, startAt: 88, endAt: 94, color: "#3366CC", alpha: 1 },
hourHand: { lineWidth: 8, startAt: 0, endAt: 60, color: "black", alpha: 1 },
minuteHand: { lineWidth: 8, startAt: 0, endAt: 80, color: "black", alpha: 1 },
secondHand: { lineWidth: 5, startAt: 80, endAt: 85, color: "red", alpha: .85 },
secondDecoration: { lineWidth: 3, startAt: 0, radius: 4, fillColor: "black", color: "black", alpha: 1 }
},
simple/*was gIG3*/: {
outerBorder: { lineWidth: 185, radius: 1, color: "#E5ECF9", alpha: 1 },
smallIndicator: { lineWidth: 10, startAt: 90, endAt: 94, color: "#3366CC", alpha: 1 },
largeIndicator: { lineWidth: 10, startAt: 90, endAt: 94, color: "#3366CC", alpha: 1 },
hourHand: { lineWidth: 8, startAt: 0, endAt: 60, color: "black", alpha: 1 },
minuteHand: { lineWidth: 8, startAt: 0, endAt: 80, color: "black", alpha: 1 },
secondHand: { lineWidth: 5, startAt: 80, endAt: 85, color: "red", alpha: .85 },
secondDecoration: { lineWidth: 3, startAt: 0, radius: 4, fillColor: "black", color: "black", alpha: 1 }
},
// by securephp
securephp: {
outerBorder: { lineWidth: 100, radius: 0.45, color: "#669900", alpha: 0.3 },
smallIndicator: { lineWidth: 2, startAt: 80, endAt: 90 , color: "green", alpha: 1 },
largeIndicator: { lineWidth: 8.5, startAt: 20, endAt: 40 , color: "green", alpha: 0.4 },
hourHand: { lineWidth: 3, startAt: 0, endAt: 60, color: "black", alpha: 1 },
minuteHand: { lineWidth: 2, startAt: 0, endAt: 75, color: "black", alpha: 1 },
secondHand: { lineWidth: 1, startAt: -10, endAt: 80, color: "blue", alpha: 0.8 },
secondDecoration: { lineWidth: 1, startAt: 70, radius: 4, fillColor: "blue", color: "red", alpha: 1 }
},
Tes2: {
outerBorder: { lineWidth: 4, radius: 95, color: "black", alpha: 0.5 },
smallIndicator: { lineWidth: 1, startAt: 10, endAt: 50 , color: "#66CCFF", alpha: 1 },
largeIndicator: { lineWidth: 8.5, startAt: 60, endAt: 70, color: "#6699FF", alpha: 1 },
hourHand: { lineWidth: 5, startAt: -15, endAt: 60, color: "black", alpha: 0.7 },
minuteHand: { lineWidth: 3, startAt: -25, endAt: 75, color: "black", alpha: 0.7 },
secondHand: { lineWidth: 1.5, startAt: -20, endAt: 88, color: "red", alpha: 1 },
secondDecoration: { lineWidth: 1, startAt: 20, radius: 4, fillColor: "blue", color: "red", alpha: 1 }
},
Lev: {
outerBorder: { lineWidth: 10, radius: 95, color: "#CCFF33", alpha: 0.65 },
smallIndicator: { lineWidth: 5, startAt: 84, endAt: 90, color: "#996600", alpha: 1 },
largeIndicator: { lineWidth: 40, startAt: 25, endAt: 95, color: "#336600", alpha: 0.55 },
hourHand: { lineWidth: 4, startAt: 0, endAt: 65, color: "black", alpha: 0.9 },
minuteHand: { lineWidth: 3, startAt: 0, endAt: 80, color: "black", alpha: 0.85 },
secondHand: { lineWidth: 1, startAt: 0, endAt: 85, color: "black", alpha: 1 },
secondDecoration: { lineWidth: 2, startAt: 5, radius: 10, fillColor: "black", color: "black", alpha: 1 }
},
Sand: {
outerBorder: { lineWidth: 1, radius: 70, color: "black", alpha: 0.5 },
smallIndicator: { lineWidth: 3, startAt: 50, endAt: 70, color: "#0066FF", alpha: 0.5 },
largeIndicator: { lineWidth: 200, startAt: 80, endAt: 95, color: "#996600", alpha: 0.75 },
hourHand: { lineWidth: 4, startAt: 0, endAt: 65, color: "black", alpha: 0.9 },
minuteHand: { lineWidth: 3, startAt: 0, endAt: 80, color: "black", alpha: 0.85 },
secondHand: { lineWidth: 1, startAt: 0, endAt: 85, color: "black", alpha: 1 },
secondDecoration: { lineWidth: 2, startAt: 5, radius: 10, fillColor: "black", color: "black", alpha: 1 }
},
Sun: {
outerBorder: { lineWidth: 100, radius: 140, color: "#99FFFF", alpha: 0.2 },
smallIndicator: { lineWidth: 300, startAt: 50, endAt: 70, color: "black", alpha: 0.1 },
largeIndicator: { lineWidth: 5, startAt: 80, endAt: 95, color: "black", alpha: 0.65 },
hourHand: { lineWidth: 4, startAt: 0, endAt: 65, color: "black", alpha: 0.9 },
minuteHand: { lineWidth: 3, startAt: 0, endAt: 80, color: "black", alpha: 0.85 },
secondHand: { lineWidth: 1, startAt: 0, endAt: 90, color: "black", alpha: 1 },
secondDecoration: { lineWidth: 2, startAt: 5, radius: 10, fillColor: "black", color: "black", alpha: 1 }
},
Tor: {
outerBorder: { lineWidth: 10, radius: 88, color: "#996600", alpha: 0.9 },
smallIndicator: { lineWidth: 6, startAt: -10, endAt: 73, color: "green", alpha: 0.3 },
largeIndicator: { lineWidth: 6, startAt: 73, endAt: 100, color: "black", alpha: 0.65 },
hourHand: { lineWidth: 4, startAt: 0, endAt: 65, color: "black", alpha: 1 },
minuteHand: { lineWidth: 3, startAt: 0, endAt: 80, color: "black", alpha: 1 },
secondHand: { lineWidth: 1, startAt: -73, endAt: 73, color: "black", alpha: 0.8 },
secondDecoration: { lineWidth: 2, startAt: 5, radius: 10, fillColor: "black", color: "black", alpha: 1 }
},
Cold: {
outerBorder: { lineWidth: 15, radius: 90, color: "black", alpha: 0.3 },
smallIndicator: { lineWidth: 15, startAt: -10, endAt: 95, color: "blue", alpha: 0.1 },
largeIndicator: { lineWidth: 3, startAt: 80, endAt: 95, color: "blue", alpha: 0.65 },
hourHand: { lineWidth: 4, startAt: 0, endAt: 65, color: "black", alpha: 1 },
minuteHand: { lineWidth: 3, startAt: 0, endAt: 80, color: "black", alpha: 1 },
secondHand: { lineWidth: 1, startAt: 0, endAt: 85, color: "black", alpha: 0.8 },
secondDecoration: { lineWidth: 5, startAt: 30, radius: 10, fillColor: "black", color: "black", alpha: 1 }
},
Babosa: {
outerBorder: { lineWidth: 100, radius: 25, color: "blue", alpha: 0.25 },
smallIndicator: { lineWidth: 3, startAt: 90, endAt: 95, color: "#3366CC", alpha: 1 },
largeIndicator: { lineWidth: 4, startAt: 75, endAt: 95, color: "#3366CC", alpha: 1 },
hourHand: { lineWidth: 4, startAt: 0, endAt: 60, color: "black", alpha: 1 },
minuteHand: { lineWidth: 3, startAt: 0, endAt: 85, color: "black", alpha: 1 },
secondHand: { lineWidth: 12, startAt: 75, endAt: 90, color: "red", alpha: 0.8 },
secondDecoration: { lineWidth: 3, startAt: 0, radius: 4, fillColor: "black", color: "black", alpha: 1 }
},
Tumb: {
outerBorder: { lineWidth: 105, radius: 5, color: "green", alpha: 0.4 },
smallIndicator: { lineWidth: 1, startAt: 93, endAt: 98, color: "green", alpha: 1 },
largeIndicator: { lineWidth: 50, startAt: 0, endAt: 89, color: "red", alpha: 0.14 },
hourHand: { lineWidth: 4, startAt: 0, endAt: 65, color: "black", alpha: 1 },
minuteHand: { lineWidth: 3, startAt: 0, endAt: 80, color: "black", alpha: 1 },
secondHand: { lineWidth: 1, startAt: 0, endAt: 85, color: "black", alpha: 0.8 },
secondDecoration: { lineWidth: 5, startAt: 50, radius: 90, fillColor: "black", color: "black", alpha: 0.05 }
},
Stone: {
outerBorder: { lineWidth: 15, radius: 80, color: "#339933", alpha: 0.5 },
smallIndicator: { lineWidth: 2, startAt: 70, endAt: 90, color: "#FF3300", alpha: 0.7 },
largeIndicator: { lineWidth: 15, startAt: 0, endAt: 29, color: "#FF6600", alpha: 0.3 },
hourHand: { lineWidth: 4, startAt: 0, endAt: 65, color: "black", alpha: 1 },
minuteHand: { lineWidth: 3, startAt: 0, endAt: 75, color: "black", alpha: 1 },
secondHand: { lineWidth: 1, startAt: 0, endAt: 85, color: "black", alpha: 0.8 },
secondDecoration: { lineWidth: 5, startAt: 50, radius: 90, fillColor: "black", color: "black", alpha: 0.05 }
},
Disc: {
outerBorder: { lineWidth: 105, radius: 1, color: "#666600", alpha: 0.2 },
smallIndicator: { lineWidth: 1, startAt: 58, endAt: 95, color: "#669900", alpha: 0.8 },
largeIndicator: { lineWidth: 6, startAt: 25, endAt: 35, color: "#666600", alpha: 1 },
hourHand: { lineWidth: 4, startAt: 0, endAt: 65, color: "black", alpha: 1 },
minuteHand: { lineWidth: 3, startAt: 0, endAt: 75, color: "black", alpha: 1 },
secondHand: { lineWidth: 1, startAt: -75, endAt: 75, color: "#99CC00", alpha: 0.8 },
secondDecoration: { lineWidth: 5, startAt: 50, radius: 90, fillColor: "#00FF00", color: "green", alpha: 0.05 }
},
// By Yoo Nhe
watermelon: {
outerBorder: { lineWidth: 100, radius: 1.7, color: "#d93d04", alpha: 5 },
smallIndicator: { lineWidth: 2, startAt: 50, endAt: 70, color: "#d93d04", alpha: 5 },
largeIndicator: { lineWidth: 2, startAt: 45, endAt: 94, color: "#a9bf04", alpha: 1 },
hourHand: { lineWidth: 5, startAt: -20, endAt: 80, color: "#8c0d17", alpha: 1 },
minuteHand: { lineWidth: 2, startAt: -20, endAt: 80, color: "#7c8c03", alpha: .9 },
secondHand: { lineWidth: 2, startAt: 70, endAt: 94, color: "#d93d04", alpha: .85 },
secondDecoration: { lineWidth: 1, startAt: 70, radius: 3, fillColor: "red", color: "black", alpha: .7 }
}
};

View file

@ -1,19 +0,0 @@
// -----------------------------------------------------
//
// This file is so users can modify how the page acts
// without diving to deep in the code. This way we can
// also try out or hold custom code for ourselves and
// not check it into the repo.
//
// There is a div id'ed as plane_extension for use with
// this javascript file.
// -----------------------------------------------------
function extendedInitalize() {
// Write your initalization here
// Gets called just before the 1-sec function call loop is setup
}
function extendedPulse() {
// This will get called every second after all the main functions
}

View file

@ -1,65 +0,0 @@
<html>
<head>
<meta charset="utf-8"/>
<link rel="stylesheet" type="text/css" href="style.css" />
<link rel="stylesheet" href="http://code.jquery.com/ui/1.10.3/themes/smoothness/jquery-ui.css" />
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<script src="//ajax.googleapis.com/ajax/libs/jqueryui/1.10.3/jquery-ui.min.js"></script>
<script type="text/javascript" src="https://maps.googleapis.com/maps/api/js?sensor=false&amp;libraries=geometry"></script>
<script type="text/javascript" src="config.js"></script>
<script type="text/javascript" src="planeObject.js"></script>
<script type="text/javascript" src="options.js"></script>
<script type="text/javascript" src="extension.js"></script>
<script type="text/javascript" src="script.js"></script>
<script type="text/javascript" src="coolclock/excanvas.js"></script>
<script type="text/javascript" src="coolclock/coolclock.js"></script>
<script type="text/javascript" src="coolclock/moreskins.js"></script>
<title>DUMP1090</title>
</head>
<body onload="initialize()">
<div id="dialog-modal" title="Basic modal dialog" style="display:none;">
<p>The settings feature is coming soon. Keep checking GitHub.</p>
</div>
<div id="map_container">
<div id="map_canvas"></div>
</div>
<div id="sidebar_container">
<div id="sidebar_canvas">
<div id="timestamps" style="align: center">
<table width="100%"><tr>
<td>Local Time</td>
<td>
<canvas id="localclock" class="CoolClock:classic:40"></canvas>
</td>
<td>UTC Time</td>
<td>
<canvas id="gmtclock" class="CoolClock:classic:40::0"></canvas>
</td>
</tr></table>
</div>
<div id="sudo_buttons">
<table width="100%"><tr>
<td width="150" style="text-align: center;" class="pointer">
[ <span onclick="resetMap();">Reset Map</span> ]
</td>
<td>&nbsp;</td>
<td width="150" style="text-align: center;" id="setings_button" class="pointer">
[ <span onclick="optionsModal();">Settings</span> ]
</td>
</tr></table>
</div>
<div id="plane_detail"></div>
<div id="options"></div>
<div id="planes_table"></div>
<div id="plane_extension"></div>
</div>
</div>
<div id="SpecialSquawkWarning">
<b>Squak 7x00 is reported and shown.</b><br>
This is most likely an error in reciving or decoding.<br>
Please do not call the local authorities, they already know about it if it is valid squak.
</div>
<div id="container_splitter"></div>
</body>
</html>

View file

@ -1,17 +0,0 @@
var listKMLType = ['Approch', 'Departure', 'Transit', 'Custom1', 'Custom2'];
var listKMLs = localStorage['listKMLs'] || [];
function optionsInitalize() {
// Write your initalization here
// Gets called just before the 1-sec function call loop is setup
$( "#dialog-modal" ).dialog({
height: 140,
modal: true,
autoOpen: false,
closeOnEscape: false
});
}
function optionsModal() {
$( "#dialog-modal" ).dialog( "open");
}

View file

@ -1,260 +0,0 @@
var planeObject = {
oldlat : null,
oldlon : null,
oldalt : null,
// Basic location information
altitude : null,
speed : null,
track : null,
latitude : null,
longitude : null,
// Info about the plane
flight : null,
squawk : null,
icao : null,
is_selected : false,
// Data packet numbers
messages : null,
seen : null,
// Vaild...
vPosition : false,
vTrack : false,
// GMap Details
marker : null,
markerColor : MarkerColor,
lines : [],
trackdata : new Array(),
trackline : new Array(),
// When was this last updated?
updated : null,
reapable : false,
// Appends data to the running track so we can get a visual tail on the plane
// Only useful for a long running browser session.
funcAddToTrack : function(){
// TODO: Write this function out
this.trackdata.push([this.latitude, this.longitude, this.altitude, this.track, this.speed]);
this.trackline.push(new google.maps.LatLng(this.latitude, this.longitude));
},
// This is to remove the line from the screen if we deselect the plane
funcClearLine : function() {
if (this.line) {
this.line.setMap(null);
this.line = null;
}
},
// Should create an icon for us to use on the map...
funcGetIcon : function() {
this.markerColor = MarkerColor;
// If this marker is selected we should make it lighter than the rest.
if (this.is_selected == true) {
this.markerColor = SelectedColor;
}
// If we have not seen a recent update, change color
if (this.seen > 15) {
this.markerColor = StaleColor;
}
// Plane marker
var baseSvg = {
planeData : "M 1.9565564,41.694305 C 1.7174505,40.497708 1.6419973,38.448747 " +
"1.8096508,37.70494 1.8936398,37.332056 2.0796653,36.88191 2.222907,36.70461 " +
"2.4497603,36.423844 4.087816,35.47248 14.917931,29.331528 l 12.434577," +
"-7.050718 -0.04295,-7.613412 c -0.03657,-6.4844888 -0.01164,-7.7625804 " +
"0.168134,-8.6194061 0.276129,-1.3160905 0.762276,-2.5869575 1.347875," +
"-3.5235502 l 0.472298,-0.7553719 1.083746,-0.6085497 c 1.194146,-0.67053522 " +
"1.399524,-0.71738842 2.146113,-0.48960552 1.077005,0.3285939 2.06344," +
"1.41299352 2.797602,3.07543322 0.462378,1.0469993 0.978731,2.7738408 " +
"1.047635,3.5036272 0.02421,0.2570284 0.06357,3.78334 0.08732,7.836246 0.02375," +
"4.052905 0.0658,7.409251 0.09345,7.458546 0.02764,0.04929 5.600384,3.561772 " +
"12.38386,7.805502 l 12.333598,7.715871 0.537584,0.959688 c 0.626485,1.118378 " +
"0.651686,1.311286 0.459287,3.516442 -0.175469,2.011604 -0.608966,2.863924 " +
"-1.590344,3.127136 -0.748529,0.200763 -1.293144,0.03637 -10.184829,-3.07436 " +
"C 48.007733,41.72562 44.793806,40.60197 43.35084,40.098045 l -2.623567," +
"-0.916227 -1.981212,-0.06614 c -1.089663,-0.03638 -1.985079,-0.05089 -1.989804," +
"-0.03225 -0.0052,0.01863 -0.02396,2.421278 -0.04267,5.339183 -0.0395,6.147742 " +
"-0.143635,7.215456 -0.862956,8.845475 l -0.300457,0.680872 2.91906,1.361455 " +
"c 2.929379,1.366269 3.714195,1.835385 4.04589,2.41841 0.368292,0.647353 " +
"0.594634,2.901439 0.395779,3.941627 -0.0705,0.368571 -0.106308,0.404853 " +
"-0.765159,0.773916 L 41.4545,62.83158 39.259237,62.80426 c -6.030106,-0.07507 " +
"-16.19508,-0.495041 -16.870991,-0.697033 -0.359409,-0.107405 -0.523792," +
"-0.227482 -0.741884,-0.541926 -0.250591,-0.361297 -0.28386,-0.522402 -0.315075," +
"-1.52589 -0.06327,-2.03378 0.23288,-3.033615 1.077963,-3.639283 0.307525," +
"-0.2204 4.818478,-2.133627 6.017853,-2.552345 0.247872,-0.08654 0.247455," +
"-0.102501 -0.01855,-0.711959 -0.330395,-0.756986 -0.708622,-2.221756 -0.832676," +
"-3.224748 -0.05031,-0.406952 -0.133825,-3.078805 -0.185533,-5.937448 -0.0517," +
"-2.858644 -0.145909,-5.208974 -0.209316,-5.222958 -0.06341,-0.01399 -0.974464," +
"-0.0493 -2.024551,-0.07845 L 23.247235,38.61921 18.831373,39.8906 C 4.9432155," +
"43.88916 4.2929558,44.057819 3.4954426,43.86823 2.7487826,43.690732 2.2007966," +
"42.916622 1.9565564,41.694305 z"
};
// If the squawk code is one of the international emergency codes,
// match the info window alert color.
if (this.squawk == 7500) {
this.markerColor = "rgb(255, 85, 85)";
}
if (this.squawk == 7600) {
this.markerColor = "rgb(0, 255, 255)";
}
if (this.squawk == 7700) {
this.markerColor = "rgb(255, 255, 0)";
}
// If we have not overwritten color by now, an extension still could but
// just keep on trucking. :)
return {
strokeWeight: (this.is_selected ? 2 : 1),
path: "M 0,0 "+ baseSvg["planeData"],
scale: 0.4,
fillColor: this.markerColor,
fillOpacity: 0.9,
anchor: new google.maps.Point(32, 32), // Set anchor to middle of plane.
rotation: this.track
};
},
// TODO: Trigger actions of a selecting a plane
funcSelectPlane : function(selectedPlane){
selectPlaneByHex(this.icao);
},
// Update our data
funcUpdateData : function(data){
// So we can find out if we moved
var oldlat = this.latitude;
var oldlon = this.longitude;
var oldalt = this.altitude;
// Update all of our data
this.updated = new Date().getTime();
this.altitude = data.altitude;
this.speed = data.speed;
this.track = data.track;
this.latitude = data.lat;
this.longitude = data.lon;
this.flight = data.flight;
this.squawk = data.squawk;
this.icao = data.hex;
this.messages = data.messages;
this.seen = data.seen;
// If no packet in over 58 seconds, consider the plane reapable
// This way we can hold it, but not show it just in case the plane comes back
if (this.seen > 58) {
this.reapable = true;
if (this.marker) {
this.marker.setMap(null);
this.marker = null;
}
if (this.line) {
this.line.setMap(null);
this.line = null;
}
if (SelectedPlane == this.icao) {
if (this.is_selected) {
this.is_selected = false;
}
SelectedPlane = null;
}
} else {
if (this.reapable == true) {
}
this.reapable = false;
}
// Is the position valid?
if ((data.validposition == 1) && (this.reapable == false)) {
this.vPosition = true;
// Detech if the plane has moved
changeLat = false;
changeLon = false;
changeAlt = false;
if (oldlat != this.latitude) {
changeLat = true;
}
if (oldlon != this.longitude) {
changeLon = true;
}
if (oldalt != this.altitude) {
changeAlt = true;
}
// Right now we only care about lat/long, if alt is updated only, oh well
if ((changeLat == true) || (changeLon == true)) {
this.funcAddToTrack();
if (this.is_selected) {
this.line = this.funcUpdateLines();
}
}
this.marker = this.funcUpdateMarker();
PlanesOnMap++;
} else {
this.vPosition = false;
}
// Do we have a valid track for the plane?
if (data.validtrack == 1)
this.vTrack = true;
else
this.vTrack = false;
},
// Update our marker on the map
funcUpdateMarker: function() {
if (this.marker) {
this.marker.setPosition(new google.maps.LatLng(this.latitude, this.longitude));
this.marker.setIcon(this.funcGetIcon());
} else {
this.marker = new google.maps.Marker({
position: new google.maps.LatLng(this.latitude, this.longitude),
map: GoogleMap,
icon: this.funcGetIcon(),
visable: true
});
// This is so we can match icao address
this.marker.icao = this.icao;
// Trap clicks for this marker.
google.maps.event.addListener(this.marker, 'click', this.funcSelectPlane);
}
// Setting the marker title
if (this.flight.length == 0) {
this.marker.setTitle(this.hex);
} else {
this.marker.setTitle(this.flight+' ('+this.icao+')');
}
return this.marker;
},
// Update our planes tail line,
// TODO: Make this multi colored based on options
// altitude (default) or speed
funcUpdateLines: function() {
if (this.line) {
var path = this.line.getPath();
path.push(new google.maps.LatLng(this.latitude, this.longitude));
} else {
this.line = new google.maps.Polyline({
strokeColor: '#000000',
strokeOpacity: 1.0,
strokeWeight: 3,
map: GoogleMap,
path: this.trackline
});
}
return this.line;
}
};

View file

@ -1,658 +0,0 @@
// Define our global variables
var GoogleMap = null;
var Planes = {};
var PlanesOnMap = 0;
var PlanesOnTable = 0;
var PlanesToReap = 0;
var SelectedPlane = null;
var SpecialSquawk = false;
var iSortCol=-1;
var bSortASC=true;
var bDefaultSortASC=true;
var iDefaultSortCol=3;
// Get current map settings
CenterLat = Number(localStorage['CenterLat']) || CONST_CENTERLAT;
CenterLon = Number(localStorage['CenterLon']) || CONST_CENTERLON;
ZoomLvl = Number(localStorage['ZoomLvl']) || CONST_ZOOMLVL;
function fetchData() {
$.getJSON('/dump1090/data.json', function(data) {
PlanesOnMap = 0
SpecialSquawk = false;
// Loop through all the planes in the data packet
for (var j=0; j < data.length; j++) {
// Do we already have this plane object in Planes?
// If not make it.
if (Planes[data[j].hex]) {
var plane = Planes[data[j].hex];
} else {
var plane = jQuery.extend(true, {}, planeObject);
}
/* For special squawk tests
if (data[j].hex == '48413x') {
data[j].squawk = '7700';
} //*/
// Set SpecialSquawk-value
if (data[j].squawk == '7500' || data[j].squawk == '7600' || data[j].squawk == '7700') {
SpecialSquawk = true;
}
// Call the function update
plane.funcUpdateData(data[j]);
// Copy the plane into Planes
Planes[plane.icao] = plane;
}
PlanesOnTable = data.length;
});
}
// Initalizes the map and starts up our timers to call various functions
function initialize() {
// Make a list of all the available map IDs
var mapTypeIds = [];
for(var type in google.maps.MapTypeId) {
mapTypeIds.push(google.maps.MapTypeId[type]);
}
// Push OSM on to the end
mapTypeIds.push("OSM");
mapTypeIds.push("dark_map");
// Styled Map to outline airports and highways
var styles = [
{
"featureType": "administrative",
"stylers": [
{ "visibility": "off" }
]
},{
"featureType": "landscape",
"stylers": [
{ "visibility": "off" }
]
},{
"featureType": "poi",
"stylers": [
{ "visibility": "off" }
]
},{
"featureType": "road",
"stylers": [
{ "visibility": "off" }
]
},{
"featureType": "transit",
"stylers": [
{ "visibility": "off" }
]
},{
"featureType": "landscape",
"stylers": [
{ "visibility": "on" },
{ "weight": 8 },
{ "color": "#000000" }
]
},{
"featureType": "water",
"stylers": [
{ "lightness": -74 }
]
},{
"featureType": "transit.station.airport",
"stylers": [
{ "visibility": "on" },
{ "weight": 8 },
{ "invert_lightness": true },
{ "lightness": 27 }
]
},{
"featureType": "road.highway",
"stylers": [
{ "visibility": "simplified" },
{ "invert_lightness": true },
{ "gamma": 0.3 }
]
},{
"featureType": "road",
"elementType": "labels",
"stylers": [
{ "visibility": "off" }
]
}
]
// Add our styled map
var styledMap = new google.maps.StyledMapType(styles, {name: "Dark Map"});
// Define the Google Map
var mapOptions = {
center: new google.maps.LatLng(CenterLat, CenterLon),
zoom: ZoomLvl,
mapTypeId: google.maps.MapTypeId.ROADMAP,
mapTypeControl: true,
streetViewControl: false,
mapTypeControlOptions: {
mapTypeIds: mapTypeIds,
position: google.maps.ControlPosition.TOP_LEFT,
style: google.maps.MapTypeControlStyle.DROPDOWN_MENU
}
};
GoogleMap = new google.maps.Map(document.getElementById("map_canvas"), mapOptions);
//Define OSM map type pointing at the OpenStreetMap tile server
GoogleMap.mapTypes.set("OSM", new google.maps.ImageMapType({
getTileUrl: function(coord, zoom) {
return "http://tile.openstreetmap.org/" + zoom + "/" + coord.x + "/" + coord.y + ".png";
},
tileSize: new google.maps.Size(256, 256),
name: "OpenStreetMap",
maxZoom: 18
}));
GoogleMap.mapTypes.set("dark_map", styledMap);
// Listeners for newly created Map
google.maps.event.addListener(GoogleMap, 'center_changed', function() {
localStorage['CenterLat'] = GoogleMap.getCenter().lat();
localStorage['CenterLon'] = GoogleMap.getCenter().lng();
});
google.maps.event.addListener(GoogleMap, 'zoom_changed', function() {
localStorage['ZoomLvl'] = GoogleMap.getZoom();
});
// Add home marker if requested
if (SiteShow && (typeof SiteLat !== 'undefined' || typeof SiteLon !== 'undefined')) {
var siteMarker = new google.maps.LatLng(SiteLat, SiteLon);
var markerImage = new google.maps.MarkerImage(
'http://maps.google.com/mapfiles/kml/pal4/icon57.png',
new google.maps.Size(32, 32), // Image size
new google.maps.Point(0, 0), // Origin point of image
new google.maps.Point(16, 16)); // Position where marker should point
var marker = new google.maps.Marker({
position: siteMarker,
map: GoogleMap,
icon: markerImage,
title: 'My Radar Site',
zIndex: -99999
});
if (SiteCircles) {
for (var i=0;i<SiteCirclesDistances.length;i++) {
drawCircle(marker, SiteCirclesDistances[i]); // in meters
}
}
}
// These will run after page is complitely loaded
$(window).load(function() {
$('#dialog-modal').css('display', 'inline'); // Show hidden settings-windows content
});
// Load up our options page
optionsInitalize();
// Did our crafty user need some setup?
extendedInitalize();
// Setup our timer to poll from the server.
window.setInterval(function() {
fetchData();
refreshTableInfo();
refreshSelected();
reaper();
extendedPulse();
}, 1000);
}
// This looks for planes to reap out of the master Planes variable
function reaper() {
PlanesToReap = 0;
// When did the reaper start?
reaptime = new Date().getTime();
// Loop the planes
for (var reap in Planes) {
// Is this plane possibly reapable?
if (Planes[reap].reapable == true) {
// Has it not been seen for 5 minutes?
// This way we still have it if it returns before then
// Due to loss of signal or other reasons
if ((reaptime - Planes[reap].updated) > 300000) {
// Reap it.
delete Planes[reap];
}
PlanesToReap++;
}
};
}
// Refresh the detail window about the plane
function refreshSelected() {
var selected = false;
if (typeof SelectedPlane !== 'undefined' && SelectedPlane != "ICAO" && SelectedPlane != null) {
selected = Planes[SelectedPlane];
}
var columns = 2;
var html = '';
if (selected) {
html += '<table id="selectedinfo" width="100%">';
} else {
html += '<table id="selectedinfo" class="dim" width="100%">';
}
// Flight header line including squawk if needed
if (selected && selected.flight == "") {
html += '<tr><td colspan="' + columns + '" id="selectedinfotitle"><b>N/A (' +
selected.icao + ')</b>';
} else if (selected && selected.flight != "") {
html += '<tr><td colspan="' + columns + '" id="selectedinfotitle"><b>' +
selected.flight + '</b>';
} else {
html += '<tr><td colspan="' + columns + '" id="selectedinfotitle"><b>DUMP1090</b>';
}
if (selected && selected.squawk == 7500) { // Lets hope we never see this... Aircraft Hijacking
html += '&nbsp;<span class="squawk7500">&nbsp;Squawking: Aircraft Hijacking&nbsp;</span>';
} else if (selected && selected.squawk == 7600) { // Radio Failure
html += '&nbsp;<span class="squawk7600">&nbsp;Squawking: Radio Failure&nbsp;</span>';
} else if (selected && selected.squawk == 7700) { // General Emergency
html += '&nbsp;<span class="squawk7700">&nbsp;Squawking: General Emergency&nbsp;</span>';
} else if (selected && selected.flight != '') {
html += '&nbsp;<a href="http://fr24.com/'+selected.flight+'" target="_blank">[FR24]</a>';
html += '&nbsp;<a href="http://www.flightstats.com/go/FlightStatus/flightStatusByFlight.do?';
html += 'flightNumber='+selected.flight+'" target="_blank">[FlightStats]</a>';
html += '&nbsp;<a href="http://flightaware.com/live/flight/'+selected.flight+'" target="_blank">[FlightAware]</a>';
}
html += '<td></tr>';
if (selected) {
if (Metric) {
html += '<tr><td>Altitude: ' + Math.round(selected.altitude / 3.2828) + ' m</td>';
} else {
html += '<tr><td>Altitude: ' + selected.altitude + ' ft</td>';
}
} else {
html += '<tr><td>Altitude: n/a</td>';
}
if (selected && selected.squawk != '0000') {
html += '<td>Squawk: ' + selected.squawk + '</td></tr>';
} else {
html += '<td>Squawk: n/a</td></tr>';
}
html += '<tr><td>Speed: '
if (selected) {
if (Metric) {
html += Math.round(selected.speed * 1.852) + ' km/h';
} else {
html += selected.speed + ' kt';
}
} else {
html += 'n/a';
}
html += '</td>';
if (selected) {
html += '<td>ICAO (hex): ' + selected.icao + '</td></tr>';
} else {
html += '<td>ICAO (hex): n/a</td></tr>'; // Something is wrong if we are here
}
html += '<tr><td>Track: '
if (selected && selected.vTrack) {
html += selected.track + '&deg;' + ' (' + normalizeTrack(selected.track, selected.vTrack)[1] +')';
} else {
html += 'n/a';
}
html += '</td><td>&nbsp;</td></tr>';
html += '<tr><td colspan="' + columns + '" align="center">Lat/Long: ';
if (selected && selected.vPosition) {
html += selected.latitude + ', ' + selected.longitude + '</td></tr>';
// Let's show some extra data if we have site coordinates
if (SiteShow) {
var siteLatLon = new google.maps.LatLng(SiteLat, SiteLon);
var planeLatLon = new google.maps.LatLng(selected.latitude, selected.longitude);
var dist = google.maps.geometry.spherical.computeDistanceBetween (siteLatLon, planeLatLon);
if (Metric) {
dist /= 1000;
} else {
dist /= 1852;
}
dist = (Math.round((dist)*10)/10).toFixed(1);
html += '<tr><td colspan="' + columns + '" align="center">Distance from Site: ' + dist +
(Metric ? ' km' : ' NM') + '</td></tr>';
} // End of SiteShow
} else {
if (SiteShow) {
html += '<tr><td colspan="' + columns + '" align="center">Distance from Site: n/a ' +
(Metric ? ' km' : ' NM') + '</td></tr>';
} else {
html += 'n/a</td></tr>';
}
}
html += '</table>';
document.getElementById('plane_detail').innerHTML = html;
}
// Right now we have no means to validate the speed is good
// Want to return (n/a) when we dont have it
// TODO: Edit C code to add a valid speed flag
// TODO: Edit js code to use said flag
function normalizeSpeed(speed, valid) {
return speed
}
// Returns back a long string, short string, and the track if we have a vaild track path
function normalizeTrack(track, valid){
x = []
if ((track > -1) && (track < 22.5)) {
x = ["North", "N", track]
}
if ((track > 22.5) && (track < 67.5)) {
x = ["North East", "NE", track]
}
if ((track > 67.5) && (track < 112.5)) {
x = ["East", "E", track]
}
if ((track > 112.5) && (track < 157.5)) {
x = ["South East", "SE", track]
}
if ((track > 157.5) && (track < 202.5)) {
x = ["South", "S", track]
}
if ((track > 202.5) && (track < 247.5)) {
x = ["South West", "SW", track]
}
if ((track > 247.5) && (track < 292.5)) {
x = ["West", "W", track]
}
if ((track > 292.5) && (track < 337.5)) {
x = ["North West", "NW", track]
}
if ((track > 337.5) && (track < 361)) {
x = ["North", "N", track]
}
if (!valid) {
x = [" ", "n/a", ""]
}
return x
}
// Refeshes the larger table of all the planes
function refreshTableInfo() {
var html = '<table id="tableinfo" width="100%">';
html += '<thead style="background-color: #BBBBBB; cursor: pointer;">';
html += '<td onclick="setASC_DESC(\'0\');sortTable(\'tableinfo\',\'0\');">ICAO</td>';
html += '<td onclick="setASC_DESC(\'1\');sortTable(\'tableinfo\',\'1\');">Flight</td>';
html += '<td onclick="setASC_DESC(\'2\');sortTable(\'tableinfo\',\'2\');" ' +
'align="right">Squawk</td>';
html += '<td onclick="setASC_DESC(\'3\');sortTable(\'tableinfo\',\'3\');" ' +
'align="right">Altitude</td>';
html += '<td onclick="setASC_DESC(\'4\');sortTable(\'tableinfo\',\'4\');" ' +
'align="right">Speed</td>';
// Add distance column header to table if site coordinates are provided
if (SiteShow && (typeof SiteLat !== 'undefined' || typeof SiteLon !== 'undefined')) {
html += '<td onclick="setASC_DESC(\'5\');sortTable(\'tableinfo\',\'5\');" ' +
'align="right">Distance</td>';
}
html += '<td onclick="setASC_DESC(\'5\');sortTable(\'tableinfo\',\'6\');" ' +
'align="right">Track</td>';
html += '<td onclick="setASC_DESC(\'6\');sortTable(\'tableinfo\',\'7\');" ' +
'align="right">Msgs</td>';
html += '<td onclick="setASC_DESC(\'7\');sortTable(\'tableinfo\',\'8\');" ' +
'align="right">Seen</td></thead><tbody>';
for (var tablep in Planes) {
var tableplane = Planes[tablep]
if (!tableplane.reapable) {
var specialStyle = "";
// Is this the plane we selected?
if (tableplane.icao == SelectedPlane) {
specialStyle += " selected";
}
// Lets hope we never see this... Aircraft Hijacking
if (tableplane.squawk == 7500) {
specialStyle += " squawk7500";
}
// Radio Failure
if (tableplane.squawk == 7600) {
specialStyle += " squawk7600";
}
// Emergancy
if (tableplane.squawk == 7700) {
specialStyle += " squawk7700";
}
if (tableplane.vPosition == true) {
html += '<tr class="plane_table_row vPosition' + specialStyle + '">';
} else {
html += '<tr class="plane_table_row ' + specialStyle + '">';
}
html += '<td>' + tableplane.icao + '</td>';
html += '<td>' + tableplane.flight + '</td>';
if (tableplane.squawk != '0000' ) {
html += '<td align="right">' + tableplane.squawk + '</td>';
} else {
html += '<td align="right">&nbsp;</td>';
}
if (Metric) {
html += '<td align="right">' + Math.round(tableplane.altitude / 3.2828) + '</td>';
html += '<td align="right">' + Math.round(tableplane.speed * 1.852) + '</td>';
} else {
html += '<td align="right">' + tableplane.altitude + '</td>';
html += '<td align="right">' + tableplane.speed + '</td>';
}
// Add distance column to table if site coordinates are provided
if (SiteShow && (typeof SiteLat !== 'undefined' || typeof SiteLon !== 'undefined')) {
html += '<td align="right">';
if (tableplane.vPosition) {
var siteLatLon = new google.maps.LatLng(SiteLat, SiteLon);
var planeLatLon = new google.maps.LatLng(tableplane.latitude, tableplane.longitude);
var dist = google.maps.geometry.spherical.computeDistanceBetween (siteLatLon, planeLatLon);
if (Metric) {
dist /= 1000;
} else {
dist /= 1852;
}
dist = (Math.round((dist)*10)/10).toFixed(1);
html += dist;
} else {
html += '0';
}
html += '</td>';
}
html += '<td align="right">';
if (tableplane.vTrack) {
html += normalizeTrack(tableplane.track, tableplane.vTrack)[2];
// html += ' (' + normalizeTrack(tableplane.track, tableplane.vTrack)[1] + ')';
} else {
html += '&nbsp;';
}
html += '</td>';
html += '<td align="right">' + tableplane.messages + '</td>';
html += '<td align="right">' + tableplane.seen + '</td>';
html += '</tr>';
}
}
html += '</tbody></table>';
document.getElementById('planes_table').innerHTML = html;
if (SpecialSquawk) {
$('#SpecialSquawkWarning').css('display', 'inline');
} else {
$('#SpecialSquawkWarning').css('display', 'none');
}
// Click event for table
$('#planes_table').find('tr').click( function(){
var hex = $(this).find('td:first').text();
if (hex != "ICAO") {
selectPlaneByHex(hex);
refreshTableInfo();
refreshSelected();
}
});
sortTable("tableinfo");
}
// Credit goes to a co-worker that needed a similar functions for something else
// we get a copy of it free ;)
function setASC_DESC(iCol) {
if(iSortCol==iCol) {
bSortASC=!bSortASC;
} else {
bSortASC=bDefaultSortASC;
}
}
function sortTable(szTableID,iCol) {
//if iCol was not provided, and iSortCol is not set, assign default value
if (typeof iCol==='undefined'){
if(iSortCol!=-1){
var iCol=iSortCol;
} else if (SiteShow && (typeof SiteLat !== 'undefined' || typeof SiteLon !== 'undefined')) {
var iCol=5;
} else {
var iCol=iDefaultSortCol;
}
}
//retrieve passed table element
var oTbl=document.getElementById(szTableID).tBodies[0];
var aStore=[];
//If supplied col # is greater than the actual number of cols, set sel col = to last col
if (typeof oTbl.rows[0] !== 'undefined' && oTbl.rows[0].cells.length <= iCol) {
iCol=(oTbl.rows[0].cells.length-1);
}
//store the col #
iSortCol=iCol;
//determine if we are delaing with numerical, or alphanumeric content
var bNumeric = false;
if ((typeof oTbl.rows[0] !== 'undefined') &&
(!isNaN(parseFloat(oTbl.rows[0].cells[iSortCol].textContent ||
oTbl.rows[0].cells[iSortCol].innerText)))) {
bNumeric = true;
}
//loop through the rows, storing each one inro aStore
for (var i=0,iLen=oTbl.rows.length;i<iLen;i++){
var oRow=oTbl.rows[i];
vColData=bNumeric?parseFloat(oRow.cells[iSortCol].textContent||oRow.cells[iSortCol].innerText):String(oRow.cells[iSortCol].textContent||oRow.cells[iSortCol].innerText);
aStore.push([vColData,oRow]);
}
//sort aStore ASC/DESC based on value of bSortASC
if (bNumeric) { //numerical sort
aStore.sort(function(x,y){return bSortASC?x[0]-y[0]:y[0]-x[0];});
} else { //alpha sort
aStore.sort();
if(!bSortASC) {
aStore.reverse();
}
}
//rewrite the table rows to the passed table element
for(var i=0,iLen=aStore.length;i<iLen;i++){
oTbl.appendChild(aStore[i][1]);
}
aStore=null;
}
function selectPlaneByHex(hex) {
// If SelectedPlane has something in it, clear out the selected
if (SelectedPlane != null) {
Planes[SelectedPlane].is_selected = false;
Planes[SelectedPlane].funcClearLine();
Planes[SelectedPlane].markerColor = MarkerColor;
// If the selected has a marker, make it not stand out
if (Planes[SelectedPlane].marker) {
Planes[SelectedPlane].marker.setIcon(Planes[SelectedPlane].funcGetIcon());
}
}
// If we are clicking the same plane, we are deselected it.
if (String(SelectedPlane) != String(hex)) {
// Assign the new selected
SelectedPlane = hex;
Planes[SelectedPlane].is_selected = true;
// If the selected has a marker, make it stand out
if (Planes[SelectedPlane].marker) {
Planes[SelectedPlane].funcUpdateLines();
Planes[SelectedPlane].marker.setIcon(Planes[SelectedPlane].funcGetIcon());
}
} else {
SelectedPlane = null;
}
refreshSelected();
refreshTableInfo();
}
function resetMap() {
// Reset localStorage values
localStorage['CenterLat'] = CONST_CENTERLAT;
localStorage['CenterLon'] = CONST_CENTERLON;
localStorage['ZoomLvl'] = CONST_ZOOMLVL;
// Try to read values from localStorage else use CONST_s
CenterLat = Number(localStorage['CenterLat']) || CONST_CENTERLAT;
CenterLon = Number(localStorage['CenterLon']) || CONST_CENTERLON;
ZoomLvl = Number(localStorage['ZoomLvl']) || CONST_ZOOMLVL;
// Set and refresh
GoogleMap.setZoom(parseInt(ZoomLvl));
GoogleMap.setCenter(new google.maps.LatLng(parseFloat(CenterLat), parseFloat(CenterLon)));
if (SelectedPlane) {
selectPlaneByHex(SelectedPlane);
}
refreshSelected();
refreshTableInfo();
}
function drawCircle(marker, distance) {
if (typeof distance === 'undefined') {
return false;
if (!(!isNaN(parseFloat(distance)) && isFinite(distance)) || distance < 0) {
return false;
}
}
distance *= 1000.0;
if (!Metric) {
distance *= 1.852;
}
// Add circle overlay and bind to marker
var circle = new google.maps.Circle({
map: GoogleMap,
radius: distance, // In meters
fillOpacity: 0.0,
strokeWeight: 1,
strokeOpacity: 0.3
});
circle.bindTo('center', marker, 'position');
}

View file

@ -1,32 +0,0 @@
html, body {
margin: 0; padding: 0; background-color: #ffffff; font-family: Tahoma, Sans-Serif;
font-size: 10pt; overflow: auto; height: 100%;
}
div#map_container { float: left; width: 100%; height: 100%; }
div#map_canvas { height: 100%; margin-right: 420px; }
div#sidebar_container { float: left; width: 410px; margin-left: -410px; height: 100%; overflow: auto; }
div#SpecialSquawkWarning { position: absolute; bottom: 25px; right: 430px; border: 2px solid red;
background-color: #FFFFA3; opacity: 0.75; filter:alpha(opacity=75); padding: 5px;
display: none; text-align: center; }
table#optionsTabs { width: 100%; font-size: small; font-family: monospace; background-color: #ddd;
border: 1px; border-color: #000000;}
#tableinfo, #sudo_buttons { font-size: x-small; font-family: monospace; }
.vPosition { font-weight: bold; background-color: #d5ffd5; }
.squawk7500 { font-weight: bold; background-color: #ff5555; }
.squawk7600 { font-weight: bold; background-color: #00ffff; }
.squawk7700 { font-weight: bold; background-color: #ffff00; }
.selected { background-color: #dddddd; }
.plane_table_row { cursor: pointer; }
#selectedinfotitle { font-size: larger; }
#selectedinfo { font-size: small; }
#selectedinfo a { text-decoration: none; color: blue; font-size: x-small;}
#selectedinfo.dim { opacity: 0.3; filter:alpha(opacity=30); /* For IE8 and earlier */ }
.pointer { cursor: pointer; }

View file

@ -1,366 +0,0 @@
/*
* rtl-sdr, turns your Realtek RTL2832 based DVB dongle into a SDR receiver
* Copyright (C) 2012 by Steve Markgraf <steve@steve-m.de>
* Copyright (C) 2012 by Dimitri Stolnikov <horiz0n@gmx.net>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
*
* 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __RTL_SDR_H
#define __RTL_SDR_H
#ifdef __cplusplus
extern "C" {
#endif
//#include <stdint.h>
#include "rtl-sdr_export.h"
typedef struct rtlsdr_dev rtlsdr_dev_t;
RTLSDR_API uint32_t rtlsdr_get_device_count(void);
RTLSDR_API const char* rtlsdr_get_device_name(uint32_t index);
/*!
* Get USB device strings.
*
* NOTE: The string arguments must provide space for up to 256 bytes.
*
* \param index the device index
* \param manufact manufacturer name, may be NULL
* \param product product name, may be NULL
* \param serial serial number, may be NULL
* \return 0 on success
*/
RTLSDR_API int rtlsdr_get_device_usb_strings(uint32_t index,
char *manufact,
char *product,
char *serial);
/*!
* Get device index by USB serial string descriptor.
*
* \param serial serial string of the device
* \return device index of first device where the name matched
* \return -1 if name is NULL
* \return -2 if no devices were found at all
* \return -3 if devices were found, but none with matching name
*/
RTLSDR_API int rtlsdr_get_index_by_serial(const char *serial);
RTLSDR_API int rtlsdr_open(rtlsdr_dev_t **dev, uint32_t index);
RTLSDR_API int rtlsdr_close(rtlsdr_dev_t *dev);
/* configuration functions */
/*!
* Set crystal oscillator frequencies used for the RTL2832 and the tuner IC.
*
* Usually both ICs use the same clock. Changing the clock may make sense if
* you are applying an external clock to the tuner or to compensate the
* frequency (and samplerate) error caused by the original (cheap) crystal.
*
* NOTE: Call this function only if you fully understand the implications.
*
* \param dev the device handle given by rtlsdr_open()
* \param rtl_freq frequency value used to clock the RTL2832 in Hz
* \param tuner_freq frequency value used to clock the tuner IC in Hz
* \return 0 on success
*/
RTLSDR_API int rtlsdr_set_xtal_freq(rtlsdr_dev_t *dev, uint32_t rtl_freq,
uint32_t tuner_freq);
/*!
* Get crystal oscillator frequencies used for the RTL2832 and the tuner IC.
*
* Usually both ICs use the same clock.
*
* \param dev the device handle given by rtlsdr_open()
* \param rtl_freq frequency value used to clock the RTL2832 in Hz
* \param tuner_freq frequency value used to clock the tuner IC in Hz
* \return 0 on success
*/
RTLSDR_API int rtlsdr_get_xtal_freq(rtlsdr_dev_t *dev, uint32_t *rtl_freq,
uint32_t *tuner_freq);
/*!
* Get USB device strings.
*
* NOTE: The string arguments must provide space for up to 256 bytes.
*
* \param dev the device handle given by rtlsdr_open()
* \param manufact manufacturer name, may be NULL
* \param product product name, may be NULL
* \param serial serial number, may be NULL
* \return 0 on success
*/
RTLSDR_API int rtlsdr_get_usb_strings(rtlsdr_dev_t *dev, char *manufact,
char *product, char *serial);
/*!
* Write the device EEPROM
*
* \param dev the device handle given by rtlsdr_open()
* \param data buffer of data to be written
* \param offset address where the data should be written
* \param len length of the data
* \return 0 on success
* \return -1 if device handle is invalid
* \return -2 if EEPROM size is exceeded
* \return -3 if no EEPROM was found
*/
RTLSDR_API int rtlsdr_write_eeprom(rtlsdr_dev_t *dev, uint8_t *data,
uint8_t offset, uint16_t len);
/*!
* Read the device EEPROM
*
* \param dev the device handle given by rtlsdr_open()
* \param data buffer where the data should be written
* \param offset address where the data should be read from
* \param len length of the data
* \return 0 on success
* \return -1 if device handle is invalid
* \return -2 if EEPROM size is exceeded
* \return -3 if no EEPROM was found
*/
RTLSDR_API int rtlsdr_read_eeprom(rtlsdr_dev_t *dev, uint8_t *data,
uint8_t offset, uint16_t len);
RTLSDR_API int rtlsdr_set_center_freq(rtlsdr_dev_t *dev, uint32_t freq);
/*!
* Get actual frequency the device is tuned to.
*
* \param dev the device handle given by rtlsdr_open()
* \return 0 on error, frequency in Hz otherwise
*/
RTLSDR_API uint32_t rtlsdr_get_center_freq(rtlsdr_dev_t *dev);
/*!
* Set the frequency correction value for the device.
*
* \param dev the device handle given by rtlsdr_open()
* \param ppm correction value in parts per million (ppm)
* \return 0 on success
*/
RTLSDR_API int rtlsdr_set_freq_correction(rtlsdr_dev_t *dev, int ppm);
/*!
* Get actual frequency correction value of the device.
*
* \param dev the device handle given by rtlsdr_open()
* \return correction value in parts per million (ppm)
*/
RTLSDR_API int rtlsdr_get_freq_correction(rtlsdr_dev_t *dev);
enum rtlsdr_tuner {
RTLSDR_TUNER_UNKNOWN = 0,
RTLSDR_TUNER_E4000,
RTLSDR_TUNER_FC0012,
RTLSDR_TUNER_FC0013,
RTLSDR_TUNER_FC2580,
RTLSDR_TUNER_R820T
};
/*!
* Get the tuner type.
*
* \param dev the device handle given by rtlsdr_open()
* \return RTLSDR_TUNER_UNKNOWN on error, tuner type otherwise
*/
RTLSDR_API enum rtlsdr_tuner rtlsdr_get_tuner_type(rtlsdr_dev_t *dev);
/*!
* Get a list of gains supported by the tuner.
*
* NOTE: The gains argument must be preallocated by the caller. If NULL is
* being given instead, the number of available gain values will be returned.
*
* \param dev the device handle given by rtlsdr_open()
* \param gains array of gain values. In tenths of a dB, 115 means 11.5 dB.
* \return <= 0 on error, number of available (returned) gain values otherwise
*/
RTLSDR_API int rtlsdr_get_tuner_gains(rtlsdr_dev_t *dev, int *gains);
/*!
* Set the gain for the device.
* Manual gain mode must be enabled for this to work.
*
* Valid gain values (in tenths of a dB) for the E4000 tuner:
* -10, 15, 40, 65, 90, 115, 140, 165, 190,
* 215, 240, 290, 340, 420, 430, 450, 470, 490
*
* Valid gain values may be queried with \ref rtlsdr_get_tuner_gains function.
*
* \param dev the device handle given by rtlsdr_open()
* \param gain in tenths of a dB, 115 means 11.5 dB.
* \return 0 on success
*/
RTLSDR_API int rtlsdr_set_tuner_gain(rtlsdr_dev_t *dev, int gain);
/*!
* Get actual gain the device is configured to.
*
* \param dev the device handle given by rtlsdr_open()
* \return 0 on error, gain in tenths of a dB, 115 means 11.5 dB.
*/
RTLSDR_API int rtlsdr_get_tuner_gain(rtlsdr_dev_t *dev);
/*!
* Set the intermediate frequency gain for the device.
*
* \param dev the device handle given by rtlsdr_open()
* \param stage intermediate frequency gain stage number (1 to 6 for E4000)
* \param gain in tenths of a dB, -30 means -3.0 dB.
* \return 0 on success
*/
RTLSDR_API int rtlsdr_set_tuner_if_gain(rtlsdr_dev_t *dev, int stage, int gain);
/*!
* Set the gain mode (automatic/manual) for the device.
* Manual gain mode must be enabled for the gain setter function to work.
*
* \param dev the device handle given by rtlsdr_open()
* \param manual gain mode, 1 means manual gain mode shall be enabled.
* \return 0 on success
*/
RTLSDR_API int rtlsdr_set_tuner_gain_mode(rtlsdr_dev_t *dev, int manual);
/* this will select the baseband filters according to the requested sample rate */
RTLSDR_API int rtlsdr_set_sample_rate(rtlsdr_dev_t *dev, uint32_t rate);
/*!
* Get actual sample rate the device is configured to.
*
* \param dev the device handle given by rtlsdr_open()
* \return 0 on error, sample rate in Hz otherwise
*/
RTLSDR_API uint32_t rtlsdr_get_sample_rate(rtlsdr_dev_t *dev);
/*!
* Enable test mode that returns an 8 bit counter instead of the samples.
* The counter is generated inside the RTL2832.
*
* \param dev the device handle given by rtlsdr_open()
* \param test mode, 1 means enabled, 0 disabled
* \return 0 on success
*/
RTLSDR_API int rtlsdr_set_testmode(rtlsdr_dev_t *dev, int on);
/*!
* Enable or disable the internal digital AGC of the RTL2832.
*
* \param dev the device handle given by rtlsdr_open()
* \param digital AGC mode, 1 means enabled, 0 disabled
* \return 0 on success
*/
RTLSDR_API int rtlsdr_set_agc_mode(rtlsdr_dev_t *dev, int on);
/*!
* Enable or disable the direct sampling mode. When enabled, the IF mode
* of the RTL2832 is activated, and rtlsdr_set_center_freq() will control
* the IF-frequency of the DDC, which can be used to tune from 0 to 28.8 MHz
* (xtal frequency of the RTL2832).
*
* \param dev the device handle given by rtlsdr_open()
* \param on 0 means disabled, 1 I-ADC input enabled, 2 Q-ADC input enabled
* \return 0 on success
*/
RTLSDR_API int rtlsdr_set_direct_sampling(rtlsdr_dev_t *dev, int on);
/*!
* Get state of the direct sampling mode
*
* \param dev the device handle given by rtlsdr_open()
* \return -1 on error, 0 means disabled, 1 I-ADC input enabled
* 2 Q-ADC input enabled
*/
RTLSDR_API int rtlsdr_get_direct_sampling(rtlsdr_dev_t *dev);
/*!
* Enable or disable offset tuning for zero-IF tuners, which allows to avoid
* problems caused by the DC offset of the ADCs and 1/f noise.
*
* \param dev the device handle given by rtlsdr_open()
* \param on 0 means disabled, 1 enabled
* \return 0 on success
*/
RTLSDR_API int rtlsdr_set_offset_tuning(rtlsdr_dev_t *dev, int on);
/*!
* Get state of the offset tuning mode
*
* \param dev the device handle given by rtlsdr_open()
* \return -1 on error, 0 means disabled, 1 enabled
*/
RTLSDR_API int rtlsdr_get_offset_tuning(rtlsdr_dev_t *dev);
/* streaming functions */
RTLSDR_API int rtlsdr_reset_buffer(rtlsdr_dev_t *dev);
RTLSDR_API int rtlsdr_read_sync(rtlsdr_dev_t *dev, void *buf, int len, int *n_read);
typedef void(*rtlsdr_read_async_cb_t)(unsigned char *buf, uint32_t len, void *ctx);
/*!
* Read samples from the device asynchronously. This function will block until
* it is being canceled using rtlsdr_cancel_async()
*
* NOTE: This function is deprecated and is subject for removal.
*
* \param dev the device handle given by rtlsdr_open()
* \param cb callback function to return received samples
* \param ctx user specific context to pass via the callback function
* \return 0 on success
*/
RTLSDR_API int rtlsdr_wait_async(rtlsdr_dev_t *dev, rtlsdr_read_async_cb_t cb, void *ctx);
/*!
* Read samples from the device asynchronously. This function will block until
* it is being canceled using rtlsdr_cancel_async()
*
* \param dev the device handle given by rtlsdr_open()
* \param cb callback function to return received samples
* \param ctx user specific context to pass via the callback function
* \param buf_num optional buffer count, buf_num * buf_len = overall buffer size
* set to 0 for default buffer count (32)
* \param buf_len optional buffer length, must be multiple of 512,
* set to 0 for default buffer length (16 * 32 * 512)
* \return 0 on success
*/
RTLSDR_API int rtlsdr_read_async(rtlsdr_dev_t *dev,
rtlsdr_read_async_cb_t cb,
void *ctx,
uint32_t buf_num,
uint32_t buf_len);
/*!
* Cancel all pending asynchronous operations on the device.
*
* \param dev the device handle given by rtlsdr_open()
* \return 0 on success
*/
RTLSDR_API int rtlsdr_cancel_async(rtlsdr_dev_t *dev);
#ifdef __cplusplus
}
#endif
#endif /* __RTL_SDR_H */

View file

@ -1,47 +0,0 @@
/*
* rtl-sdr, turns your Realtek RTL2832 based DVB dongle into a SDR receiver
* Copyright (C) 2012 by Hoernchen <la@tfc-server.de>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
*
* 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef RTLSDR_EXPORT_H
#define RTLSDR_EXPORT_H
#if defined __GNUC__
# if __GNUC__ >= 4
# define __SDR_EXPORT __attribute__((visibility("default")))
# define __SDR_IMPORT __attribute__((visibility("default")))
# else
# define __SDR_EXPORT
# define __SDR_IMPORT
# endif
#elif _MSC_VER
# define __SDR_EXPORT __declspec(dllexport)
# define __SDR_IMPORT __declspec(dllimport)
#else
# define __SDR_EXPORT
# define __SDR_IMPORT
#endif
#ifndef rtlsdr_STATIC
# ifdef rtlsdr_EXPORTS
# define RTLSDR_API __SDR_EXPORT
# else
# define RTLSDR_API __SDR_IMPORT
# endif
#else
#define RTLSDR_API
#endif
#endif /* RTLSDR_EXPORT_H */

View file

@ -1 +0,0 @@
62f7f97e41c0ad19d03f7bfd16da920c9b6b096b

View file

@ -1,193 +0,0 @@
<!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>

View file

@ -1 +0,0 @@
3574a87a5df1ebab0124dc0e276a82636506f036

View file

@ -1,321 +0,0 @@
// view1090, a Mode S messages viewer for dump1090 devices.
//
// Copyright (C) 2014 by Malcolm Robb <Support@ATTAvionics.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.
//
// 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
// HOLDER 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 "coaa.h"
#include "view1090.h"
//
// ============================= Utility functions ==========================
//
void sigintHandler(int dummy) {
NOTUSED(dummy);
signal(SIGINT, SIG_DFL); // reset signal handler - bit extra safety
Modes.exit = 1; // Signal to threads that we are done
}
//
// =============================== Terminal handling ========================
//
#ifndef _WIN32
// Get the number of rows after the terminal changes size.
int getTermRows() {
struct winsize w;
ioctl(STDOUT_FILENO, TIOCGWINSZ, &w);
return (w.ws_row);
}
// Handle resizing terminal
void sigWinchCallback() {
signal(SIGWINCH, SIG_IGN);
Modes.interactive_rows = getTermRows();
interactiveShowData();
signal(SIGWINCH, sigWinchCallback);
}
#else
int getTermRows() { return MODES_INTERACTIVE_ROWS;}
#endif
//
// =============================== Initialization ===========================
//
void view1090InitConfig(void) {
// Default everything to zero/NULL
memset(&Modes, 0, sizeof(Modes));
memset(&View1090, 0, sizeof(View1090));
// Now initialise things that should not be 0/NULL to their defaults
Modes.check_crc = 1;
strcpy(View1090.net_input_beast_ipaddr,VIEW1090_NET_OUTPUT_IP_ADDRESS);
Modes.net_input_beast_port = MODES_NET_OUTPUT_BEAST_PORT;
Modes.interactive_rows = getTermRows();
Modes.interactive_delete_ttl = MODES_INTERACTIVE_DELETE_TTL;
Modes.interactive_display_ttl = MODES_INTERACTIVE_DISPLAY_TTL;
Modes.fUserLat = MODES_USER_LATITUDE_DFLT;
Modes.fUserLon = MODES_USER_LONGITUDE_DFLT;
Modes.interactive = 1;
}
//
//=========================================================================
//
void view1090Init(void) {
pthread_mutex_init(&Modes.pDF_mutex,NULL);
pthread_mutex_init(&Modes.data_mutex,NULL);
pthread_cond_init(&Modes.data_cond,NULL);
#ifdef _WIN32
if ( (!Modes.wsaData.wVersion)
&& (!Modes.wsaData.wHighVersion) ) {
// Try to start the windows socket support
if (WSAStartup(MAKEWORD(2,1),&Modes.wsaData) != 0)
{
fprintf(stderr, "WSAStartup returned Error\n");
}
}
#endif
// Allocate the various buffers used by Modes
if ( NULL == (Modes.icao_cache = (uint32_t *) malloc(sizeof(uint32_t) * MODES_ICAO_CACHE_LEN * 2)))
{
fprintf(stderr, "Out of memory allocating data buffer.\n");
exit(1);
}
// Clear the buffers that have just been allocated, just in-case
memset(Modes.icao_cache, 0, sizeof(uint32_t) * MODES_ICAO_CACHE_LEN * 2);
// Validate the users Lat/Lon home location inputs
if ( (Modes.fUserLat > 90.0) // Latitude must be -90 to +90
|| (Modes.fUserLat < -90.0) // and
|| (Modes.fUserLon > 360.0) // Longitude must be -180 to +360
|| (Modes.fUserLon < -180.0) ) {
Modes.fUserLat = Modes.fUserLon = 0.0;
} else if (Modes.fUserLon > 180.0) { // If Longitude is +180 to +360, make it -180 to 0
Modes.fUserLon -= 360.0;
}
// If both Lat and Lon are 0.0 then the users location is either invalid/not-set, or (s)he's in the
// Atlantic ocean off the west coast of Africa. This is unlikely to be correct.
// Set the user LatLon valid flag only if either Lat or Lon are non zero. Note the Greenwich meridian
// is at 0.0 Lon,so we must check for either fLat or fLon being non zero not both.
// Testing the flag at runtime will be much quicker than ((fLon != 0.0) || (fLat != 0.0))
Modes.bUserFlags &= ~MODES_USER_LATLON_VALID;
if ((Modes.fUserLat != 0.0) || (Modes.fUserLon != 0.0)) {
Modes.bUserFlags |= MODES_USER_LATLON_VALID;
}
// Prepare error correction tables
modesInitErrorInfo();
}
// Set up data connection
int setupConnection(struct client *c) {
int fd;
// Try to connect to the selected ip address and port. We only support *ONE* input connection which we initiate.here.
if ((fd = anetTcpConnect(Modes.aneterr, View1090.net_input_beast_ipaddr, Modes.net_input_beast_port)) != ANET_ERR) {
anetNonBlock(Modes.aneterr, fd);
//
// Setup a service callback client structure for a beast binary input (from dump1090)
// This is a bit dodgy under Windows. The fd parameter is a handle to the internet
// socket on which we are receiving data. Under Linux, these seem to start at 0 and
// count upwards. However, Windows uses "HANDLES" and these don't nececeriy start at 0.
// dump1090 limits fd to values less than 1024, and then uses the fd parameter to
// index into an array of clients. This is ok-ish if handles are allocated up from 0.
// However, there is no gaurantee that Windows will behave like this, and if Windows
// allocates a handle greater than 1024, then dump1090 won't like it. On my test machine,
// the first Windows handle is usually in the 0x54 (84 decimal) region.
c->next = NULL;
c->buflen = 0;
c->fd =
c->service =
Modes.bis = fd;
Modes.clients = c;
}
return fd;
}
//
// ================================ Main ====================================
//
void showHelp(void) {
printf(
"-----------------------------------------------------------------------------\n"
"| view1090 dump1090 Viewer Ver : "MODES_DUMP1090_VERSION " |\n"
"-----------------------------------------------------------------------------\n"
"--interactive Interactive mode refreshing data on screen\n"
"--interactive-rows <num> Max number of rows in interactive mode (default: 15)\n"
"--interactive-ttl <sec> Remove from list if idle for <sec> (default: 60)\n"
"--interactive-rtl1090 Display flight table in RTL1090 format\n"
"--modeac Enable decoding of SSR modes 3/A & 3/C\n"
"--net-bo-ipaddr <IPv4> TCP Beast output listen IPv4 (default: 127.0.0.1)\n"
"--net-bo-port <port> TCP Beast output listen port (default: 30005)\n"
"--lat <latitude> Reference/receiver latitide for surface posn (opt)\n"
"--lon <longitude> Reference/receiver longitude for surface posn (opt)\n"
"--no-crc-check Disable messages with broken CRC (discouraged)\n"
"--no-fix Disable single-bits error correction using CRC\n"
"--fix Enable single-bits error correction using CRC\n"
"--aggressive More CPU for more messages (two bits fixes, ...)\n"
"--metric Use metric units (meters, km/h, ...)\n"
"--help Show this help\n"
);
}
#ifdef _WIN32
void showCopyright(void) {
uint64_t llTime = time(NULL) + 1;
printf(
"-----------------------------------------------------------------------------\n"
"| view1090 ModeS Viewer Ver : " MODES_DUMP1090_VERSION " |\n"
"-----------------------------------------------------------------------------\n"
"\n"
" Copyright (C) 2012 by Salvatore Sanfilippo <antirez@gmail.com>\n"
" Copyright (C) 2014 by Malcolm Robb <support@attavionics.com>\n"
"\n"
" All rights reserved.\n"
"\n"
" THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n"
" ""AS IS"" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n"
" LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n"
" A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n"
" HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n"
" SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\n"
" LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n"
" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n"
" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n"
" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n"
" OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n"
"\n"
" For further details refer to <https://github.com/MalcolmRobb/dump1090>\n"
"\n"
);
// delay for 1 second to give the user a chance to read the copyright
while (llTime >= time(NULL)) {}
}
#endif
//
//=========================================================================
//
int main(int argc, char **argv) {
int j, fd;
struct client *c;
char pk_buf[8];
// Set sane defaults
view1090InitConfig();
signal(SIGINT, sigintHandler); // Define Ctrl/C handler (exit program)
// Parse the command line options
for (j = 1; j < argc; j++) {
int more = ((j + 1) < argc); // There are more arguments
if (!strcmp(argv[j],"--net-bo-port") && more) {
Modes.net_input_beast_port = atoi(argv[++j]);
} else if (!strcmp(argv[j],"--net-bo-ipaddr") && more) {
strcpy(View1090.net_input_beast_ipaddr, argv[++j]);
} else if (!strcmp(argv[j],"--modeac")) {
Modes.mode_ac = 1;
} else if (!strcmp(argv[j],"--interactive-rows") && more) {
Modes.interactive_rows = atoi(argv[++j]);
} else if (!strcmp(argv[j],"--interactive")) {
Modes.interactive = 1;
} else if (!strcmp(argv[j],"--interactive-ttl") && more) {
Modes.interactive_display_ttl = atoi(argv[++j]);
} else if (!strcmp(argv[j],"--interactive-rtl1090")) {
Modes.interactive = 1;
Modes.interactive_rtl1090 = 1;
} else if (!strcmp(argv[j],"--lat") && more) {
Modes.fUserLat = atof(argv[++j]);
} else if (!strcmp(argv[j],"--lon") && more) {
Modes.fUserLon = atof(argv[++j]);
} else if (!strcmp(argv[j],"--metric")) {
Modes.metric = 1;
} else if (!strcmp(argv[j],"--no-crc-check")) {
Modes.check_crc = 0;
} else if (!strcmp(argv[j],"--fix")) {
Modes.nfix_crc = 1;
} else if (!strcmp(argv[j],"--no-fix")) {
Modes.nfix_crc = 0;
} else if (!strcmp(argv[j],"--aggressive")) {
Modes.nfix_crc = MODES_MAX_BITERRORS;
} else if (!strcmp(argv[j],"--help")) {
showHelp();
exit(0);
} else {
fprintf(stderr, "Unknown or not enough arguments for option '%s'.\n\n", argv[j]);
showHelp();
exit(1);
}
}
#ifdef _WIN32
// Try to comply with the Copyright license conditions for binary distribution
if (!Modes.quiet) {showCopyright();}
#define MSG_DONTWAIT 0
#endif
#ifndef _WIN32
// Setup for SIGWINCH for handling lines
if (Modes.interactive) {signal(SIGWINCH, sigWinchCallback);}
#endif
// Initialization
view1090Init();
// Try to connect to the selected ip address and port. We only support *ONE* input connection which we initiate.here.
c = (struct client *) malloc(sizeof(*c));
if ((fd = setupConnection(c)) == ANET_ERR) {
fprintf(stderr, "Failed to connect to %s:%d\n", View1090.net_input_beast_ipaddr, Modes.net_input_beast_port);
exit(1);
}
// Keep going till the user does something that stops us
while (!Modes.exit) {
interactiveRemoveStaleAircrafts();
interactiveShowData();
if ((fd == ANET_ERR) || (recv(c->fd, pk_buf, sizeof(pk_buf), MSG_PEEK | MSG_DONTWAIT) == 0)) {
free(c);
usleep(1000000);
c = (struct client *) malloc(sizeof(*c));
fd = setupConnection(c);
continue;
}
modesReadFromClient(c,"",decodeBinMessage);
usleep(100000);
}
// The user has stopped us, so close any socket we opened
if (fd != ANET_ERR)
{close(fd);}
return (0);
}
//
//=========================================================================
//

View file

@ -1,149 +0,0 @@
# Microsoft Developer Studio Project File - Name="view1090" - Package Owner=<4>
# Microsoft Developer Studio Generated Build File, Format Version 6.00
# ** DO NOT EDIT **
# TARGTYPE "Win32 (x86) Console Application" 0x0103
CFG=view1090 - Win32 Debug
!MESSAGE This is not a valid makefile. To build this project using NMAKE,
!MESSAGE use the Export Makefile command and run
!MESSAGE
!MESSAGE NMAKE /f "view1090.mak".
!MESSAGE
!MESSAGE You can specify a configuration when running NMAKE
!MESSAGE by defining the macro CFG on the command line. For example:
!MESSAGE
!MESSAGE NMAKE /f "view1090.mak" CFG="view1090 - Win32 Debug"
!MESSAGE
!MESSAGE Possible choices for configuration are:
!MESSAGE
!MESSAGE "view1090 - Win32 Release" (based on "Win32 (x86) Console Application")
!MESSAGE "view1090 - Win32 Debug" (based on "Win32 (x86) Console Application")
!MESSAGE
# Begin Project
# PROP AllowPerConfigDependencies 0
# PROP Scc_ProjName ""
# PROP Scc_LocalPath ""
CPP=cl.exe
RSC=rc.exe
!IF "$(CFG)" == "view1090 - Win32 Release"
# PROP BASE Use_MFC 0
# PROP BASE Use_Debug_Libraries 0
# PROP BASE Output_Dir "Release"
# PROP BASE Intermediate_Dir "Release"
# PROP BASE Target_Dir ""
# PROP Use_MFC 0
# PROP Use_Debug_Libraries 0
# PROP Output_Dir "Release"
# PROP Intermediate_Dir "Release"
# PROP Ignore_Export_Lib 0
# PROP Target_Dir ""
# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /Yu"stdafx.h" /FD /c
# ADD CPP /nologo /W3 /GX /O2 /I ".\pthreads\." /I ".\rtlsdr\." /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /FR /FD /c
# SUBTRACT CPP /YX /Yc /Yu
# ADD BASE RSC /l 0x809 /d "NDEBUG"
# ADD RSC /l 0x809 /d "NDEBUG"
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
LINK32=link.exe
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386
# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib ws2_32.lib /nologo /subsystem:console /machine:I386
# SUBTRACT LINK32 /pdb:none
!ELSEIF "$(CFG)" == "view1090 - Win32 Debug"
# PROP BASE Use_MFC 0
# PROP BASE Use_Debug_Libraries 1
# PROP BASE Output_Dir "Debug"
# PROP BASE Intermediate_Dir "Debug"
# PROP BASE Target_Dir ""
# PROP Use_MFC 0
# PROP Use_Debug_Libraries 1
# PROP Output_Dir "Debug"
# PROP Intermediate_Dir "Debug"
# PROP Ignore_Export_Lib 0
# PROP Target_Dir ""
# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /Yu"stdafx.h" /FD /GZ /c
# ADD CPP /nologo /W3 /Gm /GX /ZI /Od /I ".\pthreads\." /I ".\rtlsdr\." /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /FR /FD /GZ /c
# SUBTRACT CPP /YX /Yc /Yu
# ADD BASE RSC /l 0x809 /d "_DEBUG"
# ADD RSC /l 0x809 /d "_DEBUG"
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
LINK32=link.exe
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib ws2_32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
!ENDIF
# Begin Target
# Name "view1090 - Win32 Release"
# Name "view1090 - Win32 Debug"
# Begin Group "Source Files"
# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
# Begin Source File
SOURCE=.\anet.c
# End Source File
# Begin Source File
SOURCE=.\interactive.c
# End Source File
# Begin Source File
SOURCE=.\mode_ac.c
# End Source File
# Begin Source File
SOURCE=.\mode_s.c
# End Source File
# Begin Source File
SOURCE=.\net_io.c
# End Source File
# Begin Source File
SOURCE=.\view1090.c
# End Source File
# End Group
# Begin Group "Header Files"
# PROP Default_Filter "h;hpp;hxx;hm;inl"
# Begin Source File
SOURCE=.\dump1090.h
# End Source File
# Begin Source File
SOURCE=.\view1090.h
# End Source File
# Begin Source File
SOURCE=.\winstubs.h
# End Source File
# End Group
# Begin Group "Resource Files"
# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"
# End Group
# Begin Group "Library Files"
# PROP Default_Filter ""
# Begin Source File
SOURCE=.\pthreads\pthreadVC2.lib
# End Source File
# Begin Source File
SOURCE=.\rtlsdr\rtlsdr.lib
# End Source File
# End Group
# End Target
# End Project

View file

@ -1,84 +0,0 @@
// view1090, a Mode S messages viewer for dump1090 devices.
//
// Copyright (C) 2013 by Malcolm Robb <Support@ATTAvionics.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.
//
// 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
// HOLDER 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 __VIEW1090_H
#define __VIEW1090_H
// ============================= Include files ==========================
#include "dump1090.h"
#ifndef _WIN32
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <pthread.h>
#include <stdint.h>
#include <errno.h>
#include <unistd.h>
#include <math.h>
#include <sys/time.h>
#include <sys/timeb.h>
#include <signal.h>
#include <fcntl.h>
#include <ctype.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/socket.h>
#include "rtl-sdr.h"
#include "anet.h"
#else
#include "winstubs.h" //Put everything Windows specific in here
#endif
// ============================= #defines ===============================
#define VIEW1090_NET_OUTPUT_IP_ADDRESS "127.0.0.1"
#define NOTUSED(V) ((void) V)
// ======================== structure declarations ========================
// Program global state
struct { // Internal state
// Networking
char net_input_beast_ipaddr[32]; // IPv4 address or network name of server/RPi
} View1090;
// ======================== function declarations =========================
#ifdef __cplusplus
extern "C" {
#endif
#ifdef __cplusplus
}
#endif
#endif // __VIEW1090_H

View file

@ -1,111 +0,0 @@
// dump1090, a Mode S messages decoder for RTLSDR devices.
//
// Copyright (C) 2014 by Malcolm Robb <support@attavionics.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.
//
// 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
// HOLDER 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.
//
// This file provides basic Windows implementation of Linux specific functions
// used in the dump1090 project. This allows dump1090 to be compiled and debugged
// using Microsoft Visual C++ 6.0
//
// Note that not all functions actually provide equivalent functionality to their
// Linux equivalents. They are simply stubs to allow the project to compile.
//
#ifndef __WINSTUBS_H
#define __WINSTUBS_H
#include <winsock2.h>
#include <windows.h>
#include <basetsd.h>
typedef UCHAR uint8_t;
typedef USHORT uint16_t;
typedef UINT32 uint32_t;
typedef UINT64 uint64_t;
typedef UINT32 mode_t;
typedef long ssize_t;
typedef int socklen_t;
#include <stdio.h>
#include <time.h>
#include <sys/timeb.h>
#include <sys/stat.h>
#include <signal.h>
#include <io.h>
#include <fcntl.h>
#define M_PI 3.14159265358979323846
#include <math.h>
#include <pthread.h>
#ifdef __cplusplus
extern "C" {
#endif
//Functions not included in the MSVC maths library. This will do for our use.
_inline double round(double d) {return floor(d + 0.5);}
_inline double trunc(double d) {return (d>0) ? floor(d):ceil(d) ;}
//usleep works in microseconds, and isn't supported in Windows. This will do for our use.
_inline void usleep(UINT32 ulSleep) {Sleep(ulSleep/1000);}
_inline uint64_t strtoll(const char *p, void *e, UINT32 base) {return _atoi64(p);}
_inline int inet_aton(const char * cp, DWORD * ulAddr) { *ulAddr = inet_addr(cp); return (INADDR_NONE != *ulAddr);}
#define snprintf _snprintf
#define vsnprintf _vsnprintf
#define realpath(N,R) _fullpath((R),(N),_MAX_PATH)
_inline void cls() {
HANDLE hStdOut = GetStdHandle(STD_OUTPUT_HANDLE);
COORD coord = {0, 0};
DWORD count;
CONSOLE_SCREEN_BUFFER_INFO csbi;
GetConsoleScreenBufferInfo(hStdOut, &csbi);
FillConsoleOutputCharacter(hStdOut, ' ', csbi.dwSize.X * csbi.dwSize.Y, coord, &count);
SetConsoleCursorPosition(hStdOut, coord);
}
_inline int gettimeofday(struct timeval *tv, struct timezone *tz) {
SYSTEMTIME stSystemTime;
GetLocalTime(&stSystemTime);
tv->tv_sec = stSystemTime.wSecond + (60 * (stSystemTime.wMinute + (60 * stSystemTime.wHour)));
tv->tv_usec = stSystemTime.wMilliseconds * 1000;
return 0;
}
#define STDIN_FILENO 0
#define EINPROGRESS WSAEINPROGRESS
#define EWOULDBLOCK WSAEWOULDBLOCK
#ifdef __cplusplus
}
#endif
#endif // __WINSTUBS_H

View file

@ -1,36 +0,0 @@
import pygame
import os
from time import sleep
import RPi.GPIO as GPIO
#Note #21 changed to #27 for rev2 Pi
button_map = {23:(255,0,0), 22:(0,255,0), 27:(0,0,255), 17:(0,0,0)}
#Setup the GPIOs as inputs with Pull Ups since the buttons are connected to GND
GPIO.setmode(GPIO.BCM)
for k in button_map.keys():
GPIO.setup(k, GPIO.IN, pull_up_down=GPIO.PUD_UP)
#Colours
WHITE = (255,255,255)
os.putenv('SDL_FBDEV', '/dev/fb1')
pygame.init()
pygame.mouse.set_visible(False)
lcd = pygame.display.set_mode((320, 240))
lcd.fill((0,0,0))
pygame.display.update()
font_big = pygame.font.Font(None, 100)
while True:
# Scan the buttons
for (k,v) in button_map.items():
if GPIO.input(k) == False:
lcd.fill(v)
text_surface = font_big.render('%d'%k, True, WHITE)
rect = text_surface.get_rect(center=(160,120))
lcd.blit(text_surface, rect)
pygame.display.update()
sleep(0.1)

View file

@ -1,60 +0,0 @@
#!/usr/bin/python
import pygame
import os
from time import sleep
#Colours
WHITE = (255,255,255)
os.putenv('SDL_FBDEV', '/dev/fb1')
pygame.init()
pygame.mouse.set_visible(False)
lcd = pygame.display.set_mode((320, 240))
font_big = pygame.font.Font(None, 100)
font_small = pygame.font.Font(None, 18)
lcd.fill((0,0,0))
pygame.display.update()
top_1 = (0,0,80,40);
top_2 = (80,0,80,40);
top_3 = (160,0,80,40);
top_4 = (240,0,80,40);
pygame.draw.rect(lcd, (10,10,10), top_1, 2)
pygame.draw.rect(lcd, (10,10,10), top_2, 2)
pygame.draw.rect(lcd, (10,10,10), top_3, 2)
pygame.draw.rect(lcd, (10,10,10), top_4, 2)
text_surface = font_small.render('DEMOD', True, WHITE)
rect = text_surface.get_rect(center=(40, 20))
lcd.blit(text_surface, rect)
text_surface = font_small.render('SQLCH', True, WHITE)
rect = text_surface.get_rect(center=(120, 20))
lcd.blit(text_surface, rect)
text_surface = font_small.render('GAIN', True, WHITE)
rect = text_surface.get_rect(center=(200, 20))
lcd.blit(text_surface, rect)
text_surface = font_small.render('MENU', True, WHITE)
rect = text_surface.get_rect(center=(280, 20))
lcd.blit(text_surface, rect)
sql_gain_box = (0,40,32,200)
pygame.draw.rect(lcd, (10,10,10), sql_gain_box, 2)
for x in range(0,6):
pygame.draw.rect(lcd, (10,10,10), (32 + x * 48,40,48,80),2)
text_surface = font_big.render('%d'%x, True, WHITE)
rect = text_surface.get_rect(center=(32 + (x + .5) * 48, 80))
lcd.blit(text_surface, rect)
while True:
pygame.display.update()
sleep(1)

View file

@ -1,60 +0,0 @@
#!/usr/bin/python
import pygame
import os
from time import sleep
#Colours
WHITE = (255,255,255)
#os.putenv('SDL_FBDEV', '/dev/fb1')
pygame.init()
pygame.mouse.set_visible(False)
lcd = pygame.display.set_mode((320, 240))
font_big = pygame.font.Font(None, 100)
font_small = pygame.font.Font(None, 18)
lcd.fill((0,0,0))
pygame.display.update()
top_1 = (0,0,80,40);
top_2 = (80,0,80,40);
top_3 = (160,0,80,40);
top_4 = (240,0,80,40);
pygame.draw.rect(lcd, (100,100,100), top_1, 2)
pygame.draw.rect(lcd, (100,100,100), top_2, 2)
pygame.draw.rect(lcd, (100,100,100), top_3, 2)
pygame.draw.rect(lcd, (100,100,100), top_4, 2)
text_surface = font_small.render('DEMOD', True, WHITE)
rect = text_surface.get_rect(center=(40, 20))
lcd.blit(text_surface, rect)
text_surface = font_small.render('SQLCH', True, WHITE)
rect = text_surface.get_rect(center=(120, 20))
lcd.blit(text_surface, rect)
text_surface = font_small.render('GAIN', True, WHITE)
rect = text_surface.get_rect(center=(200, 20))
lcd.blit(text_surface, rect)
text_surface = font_small.render('MENU', True, WHITE)
rect = text_surface.get_rect(center=(280, 20))
lcd.blit(text_surface, rect)
sql_gain_box = (0,40,32,200)
pygame.draw.rect(lcd, (10,10,10), sql_gain_box, 2)
for x in range(0,6):
pygame.draw.rect(lcd, (10,10,10), (32 + x * 48,40,48,80),2)
text_surface = font_big.render('%d'%x, True, WHITE)
rect = text_surface.get_rect(center=(32 + (x + .5) * 48, 80))
lcd.blit(text_surface, rect)
while True:
pygame.display.update()
sleep(1)

View file

@ -1,137 +0,0 @@
#!/usr/bin/python
import pygame
import os
from time import sleep
import RPi.GPIO as GPIO
from rtl_fm_python_thread import *
make_rtl_fm_thread(block=False)
#Note #21 changed to #27 for rev2 Pi
button_map = {23:(255,0,0), 22:(0,255,0), 27:(0,0,255), 17:(0,0,0)}
#Setup the GPIOs as inputs with Pull Ups since the buttons are connected to GND
GPIO.setmode(GPIO.BCM)
for k in button_map.keys():
GPIO.setup(k, GPIO.IN, pull_up_down=GPIO.PUD_UP)
#Colours
WHITE = (255,255,255)
os.putenv('SDL_FBDEV', '/dev/fb1')
pygame.init()
pygame.mouse.set_visible(False)
lcd = pygame.display.set_mode((320, 240))
lcd.fill((0,0,0))
pygame.display.update()
font_big = pygame.font.Font(None, 100)
font_small = pygame.font.Font(None, 18)
dial = 0
dialColor = (255,255,255)
sql = 0
sql_str = list("0x")
freq = [1,6,2,5,5,0]
freq_idx = 0
wasdown = 0
sql_gain_select = 0
redraw = 1
set_frequency(int(''.join(str(x) for x in freq) + "000"))
while True:
for event in pygame.event.get():
if event.type == pygame.KEYDOWN:
redraw = 1
if event.key == pygame.K_x:
freq[freq_idx] = (freq[freq_idx] + 1) % 10
set_frequency(int(''.join(str(x) for x in freq) + "000"))
elif event.key == pygame.K_z:
freq[freq_idx] = (freq[freq_idx] - 1) % 10
set_frequency(int(''.join(str(x) for x in freq) + "000"))
elif event.key == pygame.K_m:
wasdown = 1;
elif event.key == pygame.K_n:
if(wasdown == 1):
wasdown = 0
freq_idx = (freq_idx + 1) % 6
elif event.key == pygame.K_0:
sql_str.append('0')
elif event.key == pygame.K_1:
sql_str.append('1')
elif event.key == pygame.K_2:
sql_str.append('2')
elif event.key == pygame.K_3:
sql_str.append('3')
elif event.key == pygame.K_4:
sql_str.append('4')
elif event.key == pygame.K_5:
sql_str.append('5')
elif event.key == pygame.K_6:
sql_str.append('6')
elif event.key == pygame.K_7:
sql_str.append('7')
elif event.key == pygame.K_8:
sql_str.append('8')
elif event.key == pygame.K_9:
sql_str.append('9')
elif event.key == pygame.K_a:
sql_str.append('a')
elif event.key == pygame.K_b:
sql_str.append('b')
elif event.key == pygame.K_c:
sql_str.append('c')
elif event.key == pygame.K_d:
sql_str.append('d')
elif event.key == pygame.K_e:
sql_str.append('e')
elif event.key == pygame.K_f:
sql_str.append('f')
elif event.key == pygame.K_RETURN:
sql = int("".join(sql_str), 0)
if sql_gain_select:
set_gain(sql)
else:
set_squelch(sql)
sql_str = list("0x")
# Scan the buttons
for (k,v) in button_map.items():
if GPIO.input(k) == False:
redraw = 1
if k == 27:
sql_gain_select = ~sql_gain_select
if redraw:
lcd.fill((0,0,0))
for x in range(0,6):
text_surface = font_big.render('%d'%freq[x], True, WHITE)
rect = text_surface.get_rect(center=((x + .5) * 320 / 6, 80))
lcd.blit(text_surface, rect)
pygame.draw.rect(lcd, WHITE, (freq_idx * 320 / 6, 50, 320 / 6, 70), 1)
pygame.draw.rect(lcd, (255, 200, 10), (10,10,20, 220 * sql / 1024), 0)
if sql_gain_select:
sql_gain_surface = font_small.render("VOL", True, WHITE)
else:
sql_gain_surface = font_small.render("SQL", True, WHITE)
rect = sql_gain_surface.get_rect(center=(25,25))
lcd.blit(sql_gain_surface, rect)
pygame.display.update()
redraw = 0
sleep(0.1)

View file

@ -1,103 +0,0 @@
import pygame
import os
from time import sleep
import RPi.GPIO as GPIO
#Note #21 changed to #27 for rev2 Pi
button_map = {23:(255,0,0), 22:(0,255,0), 27:(0,0,255), 17:(0,0,0)}
#Setup the GPIOs as inputs with Pull Ups since the buttons are connected to GND
GPIO.setmode(GPIO.BCM)
for k in button_map.keys():
GPIO.setup(k, GPIO.IN, pull_up_down=GPIO.PUD_UP)
#Colours
WHITE = (255,255,255)
os.putenv('SDL_FBDEV', '/dev/fb1')
pygame.init()
pygame.mouse.set_visible(False)
lcd = pygame.display.set_mode((320, 240))
lcd.fill((0,0,0))
pygame.display.update()
font_big = pygame.font.Font(None, 100)
dial = 0
dialColor = (255,255,255)
sql = 0
sql_str = list("0x");
while True:
for event in pygame.event.get():
if event.type == pygame.KEYDOWN:
print pygame.key.name(event.key)
if event.key == pygame.K_x:
dial += 1
elif event.key == pygame.K_z:
dial -= 1
elif event.key == pygame.K_m:
dialColor = (127,255,255)
elif event.key == pygame.K_n:
dialColor = (255,255,255)
elif event.key == pygame.K_0:
sql_str.append('0')
elif event.key == pygame.K_1:
sql_str.append('1')
elif event.key == pygame.K_2:
sql_str.append('2')
elif event.key == pygame.K_3:
sql_str.append('3')
elif event.key == pygame.K_4:
sql_str.append('4')
elif event.key == pygame.K_5:
sql_str.append('5')
elif event.key == pygame.K_6:
sql_str.append('6')
elif event.key == pygame.K_7:
sql_str.append('7')
elif event.key == pygame.K_8:
sql_str.append('8')
elif event.key == pygame.K_9:
sql_str.append('9')
elif event.key == pygame.K_a:
sql_str.append('a')
elif event.key == pygame.K_b:
sql_str.append('b')
elif event.key == pygame.K_c:
sql_str.append('c')
elif event.key == pygame.K_d:
sql_str.append('d')
elif event.key == pygame.K_e:
sql_str.append('e')
elif event.key == pygame.K_f:
sql_str.append('f')
elif event.key == pygame.K_RETURN:
sql = int("".join(sql_str), 0)
sql_str = list("0x")
lcd.fill((0,0,0))
text_surface = font_big.render('%d'%dial, True, dialColor)
rect = text_surface.get_rect(center=(160,100))
lcd.blit(text_surface, rect)
sql_surface = font_big.render('%d'%sql, True, WHITE)
rect = text_surface.get_rect(center=(160,140))
lcd.blit(sql_surface, rect)
pygame.display.update()
# Scan the buttons
# for (k,v) in button_map.items():
# if GPIO.input(k) == False:
# lcd.fill(v)
# text_surface = font_big.render('%d'%k, True, WHITE)
# rect = text_surface.get_rect(center=(160,120))
# lcd.blit(text_surface, rect)
# pygame.display.update()
# sleep(0.1)

View file

@ -1,117 +0,0 @@
import pygame
import os
from time import sleep
import RPi.GPIO as GPIO
#Note #21 changed to #27 for rev2 Pi
button_map = {23:(255,0,0), 22:(0,255,0), 27:(0,0,255), 17:(0,0,0)}
#Setup the GPIOs as inputs with Pull Ups since the buttons are connected to GND
GPIO.setmode(GPIO.BCM)
for k in button_map.keys():
GPIO.setup(k, GPIO.IN, pull_up_down=GPIO.PUD_UP)
#Colours
WHITE = (255,255,255)
os.putenv('SDL_FBDEV', '/dev/fb1')
pygame.init()
pygame.mouse.set_visible(False)
lcd = pygame.display.set_mode((320, 240))
lcd.fill((0,0,0))
pygame.display.update()
font_big = pygame.font.Font(None, 100)
dial = 0
dialColor = (255,255,255)
sql = 0
sql_str = list("0x")
freq = [4,4,2,2,7,5]
freq_idx = 0;
wasdown = 0;
while True:
for event in pygame.event.get():
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_x:
freq[freq_idx] = (freq[freq_idx] + 1) % 10
elif event.key == pygame.K_z:
freq[freq_idx] = (freq[freq_idx] - 1) % 10
elif event.key == pygame.K_m:
wasdown = 1;
elif event.key == pygame.K_n:
if(wasdown == 1):
wasdown = 0
freq_idx = (freq_idx + 1) % 6
elif event.key == pygame.K_0:
sql_str.append('0')
elif event.key == pygame.K_1:
sql_str.append('1')
elif event.key == pygame.K_2:
sql_str.append('2')
elif event.key == pygame.K_3:
sql_str.append('3')
elif event.key == pygame.K_4:
sql_str.append('4')
elif event.key == pygame.K_5:
sql_str.append('5')
elif event.key == pygame.K_6:
sql_str.append('6')
elif event.key == pygame.K_7:
sql_str.append('7')
elif event.key == pygame.K_8:
sql_str.append('8')
elif event.key == pygame.K_9:
sql_str.append('9')
elif event.key == pygame.K_a:
sql_str.append('a')
elif event.key == pygame.K_b:
sql_str.append('b')
elif event.key == pygame.K_c:
sql_str.append('c')
elif event.key == pygame.K_d:
sql_str.append('d')
elif event.key == pygame.K_e:
sql_str.append('e')
elif event.key == pygame.K_f:
sql_str.append('f')
elif event.key == pygame.K_RETURN:
sql = int("".join(sql_str), 0)
sql_str = list("0x")
lcd.fill((0,0,0))
#text_surface = font_big.render('%d'%dial, True, dialColor)
#rect = text_surface.get_rect(center=(160,100))
#lcd.blit(text_surface, rect)
for x in range(0,6):
text_surface = font_big.render('%d'%freq[x], True, WHITE)
rect = text_surface.get_rect(center=((x + .5) * 320 / 6, 80))
lcd.blit(text_surface, rect)
pygame.draw.rect(lcd, WHITE, (freq_idx * 320 / 6, 50, 320 / 6, 70), 1)
pygame.draw.rect(lcd, (255, 200, 10), (10,10,20, 220 * sql / 1024), 0)
#sql_surface = font_big.render('%d'%sql, True, WHITE)
#rect = text_surface.get_rect(center=(160,140))
#lcd.blit(sql_surface, rect)
pygame.display.update()
# Scan the buttons
# for (k,v) in button_map.items():
# if GPIO.input(k) == False:
# lcd.fill(v)
# text_surface = font_big.render('%d'%k, True, WHITE)
# rect = text_surface.get_rect(center=(160,120))
# lcd.blit(text_surface, rect)
# pygame.display.update()
# sleep(0.1)

View file

@ -1,124 +0,0 @@
#!/usr/bin/python
import pygame
import os
from time import sleep
import RPi.GPIO as GPIO
from rtl_fm_python_thread import *
make_rtl_fm_thread(block=False)
#Note #21 changed to #27 for rev2 Pi
button_map = {23:(255,0,0), 22:(0,255,0), 27:(0,0,255), 17:(0,0,0)}
#Setup the GPIOs as inputs with Pull Ups since the buttons are connected to GND
GPIO.setmode(GPIO.BCM)
for k in button_map.keys():
GPIO.setup(k, GPIO.IN, pull_up_down=GPIO.PUD_UP)
#Colours
WHITE = (255,255,255)
os.putenv('SDL_FBDEV', '/dev/fb1')
pygame.init()
pygame.mouse.set_visible(False)
lcd = pygame.display.set_mode((320, 240))
lcd.fill((0,0,0))
pygame.display.update()
font_big = pygame.font.Font(None, 100)
dial = 0
dialColor = (255,255,255)
sql = 0
sql_str = list("0x")
freq = [4,4,2,2,7,5]
freq_idx = 0;
wasdown = 0;
while True:
for event in pygame.event.get():
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_x:
freq[freq_idx] = (freq[freq_idx] + 1) % 10
set_frequency(int(''.join(str(x) for x in freq) + "000"))
elif event.key == pygame.K_z:
freq[freq_idx] = (freq[freq_idx] - 1) % 10
set_frequency(int(''.join(str(x) for x in freq) + "000"))
elif event.key == pygame.K_m:
wasdown = 1;
elif event.key == pygame.K_n:
if(wasdown == 1):
wasdown = 0
freq_idx = (freq_idx + 1) % 6
elif event.key == pygame.K_0:
sql_str.append('0')
elif event.key == pygame.K_1:
sql_str.append('1')
elif event.key == pygame.K_2:
sql_str.append('2')
elif event.key == pygame.K_3:
sql_str.append('3')
elif event.key == pygame.K_4:
sql_str.append('4')
elif event.key == pygame.K_5:
sql_str.append('5')
elif event.key == pygame.K_6:
sql_str.append('6')
elif event.key == pygame.K_7:
sql_str.append('7')
elif event.key == pygame.K_8:
sql_str.append('8')
elif event.key == pygame.K_9:
sql_str.append('9')
elif event.key == pygame.K_a:
sql_str.append('a')
elif event.key == pygame.K_b:
sql_str.append('b')
elif event.key == pygame.K_c:
sql_str.append('c')
elif event.key == pygame.K_d:
sql_str.append('d')
elif event.key == pygame.K_e:
sql_str.append('e')
elif event.key == pygame.K_f:
sql_str.append('f')
elif event.key == pygame.K_RETURN:
sql = int("".join(sql_str), 0)
set_squelch(sql)
sql_str = list("0x")
lcd.fill((0,0,0))
#text_surface = font_big.render('%d'%dial, True, dialColor)
#rect = text_surface.get_rect(center=(160,100))
#lcd.blit(text_surface, rect)
for x in range(0,6):
text_surface = font_big.render('%d'%freq[x], True, WHITE)
rect = text_surface.get_rect(center=((x + .5) * 320 / 6, 80))
lcd.blit(text_surface, rect)
pygame.draw.rect(lcd, WHITE, (freq_idx * 320 / 6, 50, 320 / 6, 70), 1)
pygame.draw.rect(lcd, (255, 200, 10), (10,10,20, 220 * sql / 1024), 0)
#sql_surface = font_big.render('%d'%sql, True, WHITE)
#rect = text_surface.get_rect(center=(160,140))
#lcd.blit(sql_surface, rect)
pygame.display.update()
# Scan the buttons
# for (k,v) in button_map.items():
# if GPIO.input(k) == False:
# lcd.fill(v)
# text_surface = font_big.render('%d'%k, True, WHITE)
# rect = text_surface.get_rect(center=(160,120))
# lcd.blit(text_surface, rect)
# pygame.display.update()
# sleep(0.1)

View file

@ -1 +0,0 @@
a899270edd156bceac4243cab7ce9286364ca7d0

View file

@ -1,141 +0,0 @@
# rtl-sdr, turns your Realtek RTL2832 based DVB dongle into a SDR receiver
# Copyright (C) 2012 by Steve Markgraf <steve@steve-m.de>
# Copyright (C) 2012 by Hoernchen <la@tfc-server.de>
# Copyright (C) 2012 by Kyle Keen <keenerd@gmail.com>
# Copyright (C) 2013 by Elias Oenal <EliasOenal@gmail.com>
# Copyright (C) 2014 by Thomas Winningham <winningham@gmail.com>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 2 of the License, or
# (at your option) any later version.
#
# 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 General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
from __future__ import print_function
import ctypes, sys
from time import sleep
from threading import Thread
printstderr = lambda x : print(x,file=sys.stderr)
fm = ctypes.CDLL('./rtl_fm_python.so')
get_s_level = fm.lib_get_s_level
get_frequency = fm.lib_get_frequency
set_demod_fm = fm.lib_set_demod_fm
set_demod_wbfm = fm.lib_set_demod_wbfm
set_demod_am = fm.lib_set_demod_am
set_demod_lsb = fm.lib_set_demod_lsb
set_demod_usb = fm.lib_set_demod_usb
set_demod_raw = fm.lib_set_demod_raw
set_frequency = lambda f : fm.lib_set_frequency(ctypes.c_uint32(f))
set_squelch = lambda l : fm.lib_set_squelch_level(ctypes.c_int(l))
get_demod = lambda : chr(fm.lib_get_demod_mode())
str_to_freq = fm.lib_frequency_convert
def process_args(l):
c=len(l)+1
argc=ctypes.c_int(c)
argv_var=ctypes.c_char_p *c
argu = ['rtl_fm'] + l
argv=argv_var(*argu)
return (argc,argv)
def mag(value, e, suffix):
t = float('1e%s' % e)
i = int(value / float(t))
r = int(value % float(t))
r = str(r).rjust(e,'0')
s = "%s.%s" % (i,r)
while (s[-1]=="0" or s[-1]=="."):
if s[-1]==".":
s=s[:-1]
break
s=s[:-1]
return s + suffix
def freq_to_str(f):
if f >= 1000000000:
return mag(f,9,'G')
if f >= 1000000:
return mag(f,6,'M')
if f >= 1000:
return mag(f,3,'K')
return str(f)
set_freq_human = lambda f : set_frequency(str_to_freq(f))
get_freq_human = lambda : freq_to_str(get_frequency())
def set_demod(c):
if c=='w' : set_demod_wbfm()
if c=='f' : set_demod_fm()
if c=='a' : set_demod_am()
if c=='l' : set_demod_lsb()
if c=='u' : set_demod_usb()
if c=='r' : set_demod_raw()
def get_gains():
c=fm.lib_get_tuner_gains_count()
b=(ctypes.c_int * c)()
fm.lib_get_tuner_gains(b)
return list(b)
def set_gain(g):
fm.lib_set_real_gain(g)
def get_gain():
return fm.lib_get_gain()
def get_auto_gain():
return get_gain()==-100
def set_gain_human(g):
fm.lib_set_gain(g)
def set_auto_gain():
fm.lib_set_auto_gain()
def rtl_fm(args=["--help"]):
fm.main(*process_args(args))
def rtl_fm_setup_and_go(args):
fm.lib_init_first()
fm.lib_process_args(*process_args(args))
fm.lib_input_open()
fm.lib_output_open()
fm.lib_go()
def rtl_fm_loop():
fm.lib_loop()
def rtl_fm_finish():
fm.lib_stop()
fm.lib_output_close()
def rtl_fm_wrapped(args=["--help"]):
rtl_fm_setup_and_go(args)
try:
while True:
sleep(0.01)
except KeyboardInterrupt:
rtl_fm_finish()

View file

@ -1,54 +0,0 @@
#!/usr/bin/python -i
# rtl-sdr, turns your Realtek RTL2832 based DVB dongle into a SDR receiver
# Copyright (C) 2012 by Steve Markgraf <steve@steve-m.de>
# Copyright (C) 2012 by Hoernchen <la@tfc-server.de>
# Copyright (C) 2012 by Kyle Keen <keenerd@gmail.com>
# Copyright (C) 2013 by Elias Oenal <EliasOenal@gmail.com>
# Copyright (C) 2014 by Thomas Winningham <winningham@gmail.com>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 2 of the License, or
# (at your option) any later version.
#
# 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 General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
from rtl_fm_python_common import *
running = True
queue=[]
def rtl_fm_thread(args):
rtl_fm_setup_and_go(args)
while running==True:
if len(queue) > 0:
queue.pop()()
sleep(1)
rtl_fm_finish()
def make_rtl_fm_thread(args=sys.argv[1:],block=False):
t = Thread(target=rtl_fm_thread,args=(args,))
t.daemon=True
t.start()
if block:
try:
while True:
sleep(1)
except KeyboardInterrupt:
running = False
def stop_thread():
running = False
if __name__ == "__main__":
make_rtl_fm_thread(block=False)

View file

@ -1,85 +0,0 @@
#!/usr/bin/python
# rtl-sdr, turns your Realtek RTL2832 based DVB dongle into a SDR receiver
# Copyright (C) 2012 by Steve Markgraf <steve@steve-m.de>
# Copyright (C) 2012 by Hoernchen <la@tfc-server.de>
# Copyright (C) 2012 by Kyle Keen <keenerd@gmail.com>
# Copyright (C) 2013 by Elias Oenal <EliasOenal@gmail.com>
# Copyright (C) 2014 by Thomas Winningham <winningham@gmail.com>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 2 of the License, or
# (at your option) any later version.
#
# 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 General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
from flask import Flask, jsonify, url_for, redirect
from rtl_fm_python_thread import *
make_rtl_fm_thread(block=False)
app = Flask(__name__)
@app.route('/')
def web_root():
return redirect(url_for('static', filename='index.html'))
@app.route('/state')
def web_state():
return jsonify(
{
's_level' : get_s_level(),
'freq_s' : get_freq_human(),
'freq_i' : get_frequency(),
'mod' : get_demod(),
'gain' : get_gain(),
'autogain' : get_auto_gain()
})
@app.route('/frequency/<int:f>')
def web_set_frequency(f):
set_frequency(f)
return web_state()
@app.route('/frequency/human/<f>')
def web_set_human_frequency(f):
set_freq_human(str(f))
return web_state()
@app.route('/demod/<c>')
def web_set_demod(c):
set_demod(str(c))
return web_state()
@app.route('/gain/<g>')
def web_set_gain(g):
gain = int(str(g))
set_gain(gain)
return web_state()
@app.route('/gain/human/<g>')
def web_set_gain_human(g):
gain = int(str(g))
set_gain_human(gain)
return web_state()
@app.route('/gain/auto')
def web_set_auto_gain():
set_auto_gain()
return web_state()
@app.route('/gain/list')
def web_get_gain_list():
l=get_gains()
return jsonify({'gains':l})
if __name__ == '__main__':
app.run(host='0.0.0.0',port=10100)
stop_thread()

View file

@ -1,2 +0,0 @@
#!/bin/sh
/usr/bin/fbi -T 2 -d /dev/fb1 -noverbose -a /home/nmatsuda/spidr/test_001.png

View file

@ -1 +0,0 @@
./key.py -M fm -f 162.55M -s 32k - |aplay -r 32k -f S16_LE -t raw -c 1

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.7 KiB

View file

@ -1,2 +0,0 @@
#!/bin/bash
./map1090 --screensize 640 360 --fullscreen --server adsb --lat 47.6 --lon -122.3

2
run_viz1090.sh Executable file
View file

@ -0,0 +1,2 @@
#!/bin/bash
./viz1090 --screensize 640 360 --fullscreen --server adsb --lat 47.6 --lon -122.3