[hamradio-commits] [dump1090] 01/02: Imported Upstream version 1.09.1007.14+dfsg

Matthew Ernisse mernisse-guest at moszumanska.debian.org
Fri Oct 24 14:29:00 UTC 2014


This is an automated email from the git hooks/post-receive script.

mernisse-guest pushed a commit to branch master
in repository dump1090.

commit 8e9c659264ea04cc9b2511ca2be79946fdd3120b
Author: Matthew Ernisse <mernisse at ub3rgeek.net>
Date:   Fri Oct 24 10:01:38 2014 -0400

    Imported Upstream version 1.09.1007.14+dfsg
---
 .gitignore                         |   10 +
 Makefile                           |   30 +
 README.md                          |  284 +++++
 TODO                               |    5 +
 anet.c                             |  345 ++++++
 anet.h                             |   59 +
 coaa.h                             |    6 +
 dump1090-win.1.09.0608.14.zip      |  Bin 0 -> 614488 bytes
 dump1090.c                         |  901 +++++++++++++++
 dump1090.dsp                       |  148 +++
 dump1090.dsw                       |   41 +
 dump1090.h                         |  465 ++++++++
 dump1090.sh                        |   74 ++
 interactive.c                      |  561 ++++++++++
 makedump1090                       |   27 +
 makeppup1090                       |   27 +
 makeview1090                       |   27 +
 mode_ac.c                          |  386 +++++++
 mode_s.c                           | 2172 ++++++++++++++++++++++++++++++++++++
 net_io.c                           |  971 ++++++++++++++++
 ppup1090.c                         |  261 +++++
 ppup1090.h                         |  110 ++
 ppup1090.sh                        |   85 ++
 pthreads/pthread.h                 | 1368 +++++++++++++++++++++++
 pthreads/sched.h                   |  183 +++
 pthreads/semaphore.h               |  169 +++
 public_html/config.js              |   33 +
 public_html/coolclock/coolclock.js |  318 ++++++
 public_html/coolclock/excanvas.js  |  785 +++++++++++++
 public_html/coolclock/moreskins.js |  212 ++++
 public_html/extension.js           |   19 +
 public_html/gmap.html              |   63 ++
 public_html/options.js             |   17 +
 public_html/planeObject.js         |  254 +++++
 public_html/script.js              |  630 +++++++++++
 public_html/style.css              |   32 +
 rtlsdr/rtl-sdr.h                   |  366 ++++++
 rtlsdr/rtl-sdr_export.h            |   47 +
 testfiles/modes1.bin               |   13 +
 tools/debug.html                   |  193 ++++
 view1090.c                         |  321 ++++++
 view1090.dsp                       |  149 +++
 view1090.h                         |   84 ++
 winstubs.h                         |  110 ++
 44 files changed, 12361 insertions(+)

diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..67495f9
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,10 @@
+*.o
+dump1090
+testfiles/*.bin
+misc
+frames.js
+.*.swp
+*~
+*.rej
+*.orig
+untrackedDeveloperSettings.js
\ No newline at end of file
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..6bfe9ee
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,30 @@
+#
+# 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
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..3fdd396
--- /dev/null
+++ b/README.md
@@ -0,0 +1,284 @@
+Dump1090 README
+===
+
+Dump 1090 is a Mode S decoder specifically designed for RTLSDR devices.
+
+The main features are:
+
+* Robust decoding of weak messages, with mode1090 many users observed
+  improved range compared to other popular decoders.
+* Network support: TCP30003 stream (MSG5...), Raw packets, HTTP.
+* Embedded HTTP server that displays the currently detected aircrafts on
+  Google Map.
+* Single bit errors correction using the 24 bit CRC.
+* Ability to decode DF11, DF17 messages.
+* Ability to decode DF formats like DF0, DF4, DF5, DF16, DF20 and DF21
+  where the checksum is xored with the ICAO address by brute forcing the
+  checksum field using recently seen ICAO addresses.
+* Decode raw IQ samples from file (using --ifile command line switch).
+* Interactive command-line-interfae mode where aircrafts currently detected
+  are shown as a list refreshing as more data arrives.
+* CPR coordinates decoding and track calculation from velocity.
+* TCP server streaming and 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 at gmail.com> and is
+released under the BSD three clause license.
diff --git a/TODO b/TODO
new file mode 100644
index 0000000..041ad29
--- /dev/null
+++ b/TODO
@@ -0,0 +1,5 @@
+TODO
+
+* Extract more information from captured Mode S messages.
+* Improve the web interface gmap.html.
+* Enhance the algorithm to reliably decode more messages.
diff --git a/anet.c b/anet.c
new file mode 100644
index 0000000..859c98c
--- /dev/null
+++ b/anet.c
@@ -0,0 +1,345 @@
+/* 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;
+}
diff --git a/anet.h b/anet.h
new file mode 100644
index 0000000..6d74af5
--- /dev/null
+++ b/anet.h
@@ -0,0 +1,59 @@
+/* anet.c -- Basic TCP socket stuff made a bit less boring
+ *
+ * Copyright (c) 2006-2012, Salvatore Sanfilippo <antirez at gmail dot com>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *   * Redistributions of source code must retain the above copyright notice,
+ *     this list of conditions and the following disclaimer.
+ *   * Redistributions in binary form must reproduce the above copyright
+ *     notice, this list of conditions and the following disclaimer in the
+ *     documentation and/or other materials provided with the distribution.
+ *   * Neither the name of Redis nor the names of its contributors may be used
+ *     to endorse or promote products derived from this software without
+ *     specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef ANET_H
+#define ANET_H
+
+#define ANET_OK 0
+#define ANET_ERR -1
+#define ANET_ERR_LEN 256
+
+#if defined(__sun)
+#define AF_LOCAL AF_UNIX
+#endif
+
+int anetTcpConnect(char *err, char *addr, int port);
+int anetTcpNonBlockConnect(char *err, char *addr, int port);
+int anetUnixConnect(char *err, char *path);
+int anetUnixNonBlockConnect(char *err, char *path);
+int anetRead(int fd, char *buf, int count);
+int anetResolve(char *err, char *host, char *ipbuf);
+int anetTcpServer(char *err, int port, char *bindaddr);
+int anetUnixServer(char *err, char *path, mode_t perm);
+int anetTcpAccept(char *err, int serversock, char *ip, int *port);
+int anetUnixAccept(char *err, int serversock);
+int anetWrite(int fd, char *buf, int count);
+int anetNonBlock(char *err, int fd);
+int anetTcpNoDelay(char *err, int fd);
+int anetTcpKeepAlive(char *err, int fd);
+int anetPeerToString(int fd, char *ip, int *port);
+int anetSetSendBuffer(char *err, int fd, int buffsize);
+
+#endif
diff --git a/coaa.h b/coaa.h
new file mode 100644
index 0000000..3d07704
--- /dev/null
+++ b/coaa.h
@@ -0,0 +1,6 @@
+// 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 
+//
diff --git a/dump1090-win.1.09.0608.14.zip b/dump1090-win.1.09.0608.14.zip
new file mode 100644
index 0000000..5bd3d84
Binary files /dev/null and b/dump1090-win.1.09.0608.14.zip differ
diff --git a/dump1090.c b/dump1090.c
new file mode 100644
index 0000000..e8096a3
--- /dev/null
+++ b/dump1090.c
@@ -0,0 +1,901 @@
+// dump1090, a Mode S messages decoder for RTLSDR devices.
+//
+// Copyright (C) 2012 by Salvatore Sanfilippo <antirez at 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-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 at gmail.com>\n"
+" Copyright (C) 2014 by Malcolm Robb <support at 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-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
+}
+//
+//=========================================================================
+//
diff --git a/dump1090.dsp b/dump1090.dsp
new file mode 100644
index 0000000..d64d0d1
--- /dev/null
+++ b/dump1090.dsp
@@ -0,0 +1,148 @@
+# 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"
+# 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
diff --git a/dump1090.dsw b/dump1090.dsw
new file mode 100644
index 0000000..c29f0f1
--- /dev/null
+++ b/dump1090.dsw
@@ -0,0 +1,41 @@
+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>
+{{{
+}}}
+
+###############################################################################
+
diff --git a/dump1090.h b/dump1090.h
new file mode 100644
index 0000000..b7adae3
--- /dev/null
+++ b/dump1090.h
@@ -0,0 +1,465 @@
+// dump1090, a Mode S messages decoder for RTLSDR devices.
+//
+// Copyright (C) 2012 by Salvatore Sanfilippo <antirez at 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.09.0608.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
+    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
diff --git a/dump1090.sh b/dump1090.sh
new file mode 100644
index 0000000..d1b63e5
--- /dev/null
+++ b/dump1090.sh
@@ -0,0 +1,74 @@
+#!/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
+#
+
diff --git a/interactive.c b/interactive.c
new file mode 100644
index 0000000..4f7e029
--- /dev/null
+++ b/interactive.c
@@ -0,0 +1,561 @@
+// dump1090, a Mode S messages decoder for RTLSDR devices.
+//
+// Copyright (C) 2012 by Salvatore Sanfilippo <antirez at 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;
+            }
+        }
+    }
+}
+//
+//=========================================================================
+//
diff --git a/makedump1090 b/makedump1090
new file mode 100644
index 0000000..4d3fccb
--- /dev/null
+++ b/makedump1090
@@ -0,0 +1,27 @@
+#
+# 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
diff --git a/makeppup1090 b/makeppup1090
new file mode 100644
index 0000000..9df60aa
--- /dev/null
+++ b/makeppup1090
@@ -0,0 +1,27 @@
+#
+# 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
diff --git a/makeview1090 b/makeview1090
new file mode 100644
index 0000000..6cb76af
--- /dev/null
+++ b/makeview1090
@@ -0,0 +1,27 @@
+#
+# 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
diff --git a/mode_ac.c b/mode_ac.c
new file mode 100644
index 0000000..881a428
--- /dev/null
+++ b/mode_ac.c
@@ -0,0 +1,386 @@
+// dump1090, a Mode S messages decoder for RTLSDR devices.
+//
+// Copyright (C) 2012 by Salvatore Sanfilippo <antirez at 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  ===================
+//
\ No newline at end of file
diff --git a/mode_s.c b/mode_s.c
new file mode 100644
index 0000000..bb0da2c
--- /dev/null
+++ b/mode_s.c
@@ -0,0 +1,2172 @@
+// dump1090, a Mode S messages decoder for RTLSDR devices.
+//
+// Copyright (C) 2012 by Salvatore Sanfilippo <antirez at 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 S detection and decoding  ===================
+//
+// Parity table for MODE S Messages.
+// The table contains 112 elements, every element corresponds to a bit set
+// in the message, starting from the first bit of actual data after the
+// preamble.
+//
+// For messages of 112 bit, the whole table is used.
+// For messages of 56 bits only the last 56 elements are used.
+//
+// The algorithm is as simple as xoring all the elements in this table
+// for which the corresponding bit on the message is set to 1.
+//
+// The latest 24 elements in this table are set to 0 as the checksum at the
+// end of the message should not affect the computation.
+//
+// Note: this function can be used with DF11 and DF17, other modes have
+// the CRC xored with the sender address as they are reply to interrogations,
+// but a casual listener can't split the address from the checksum.
+//
+uint32_t modes_checksum_table[112] = {
+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
+};
+
+uint32_t modesChecksum(unsigned char *msg, int bits) {
+    uint32_t   crc = 0;
+    uint32_t   rem = 0;
+    int        offset = (bits == 112) ? 0 : (112-56);
+    uint8_t    theByte = *msg;
+    uint32_t * pCRCTable = &modes_checksum_table[offset];
+    int j;
+
+    // We don't really need to include the checksum itself
+    bits -= 24;
+    for(j = 0; j < bits; j++) {
+        if ((j & 7) == 0)
+            theByte = *msg++;
+
+        // If bit is set, xor with corresponding table entry.
+        if (theByte & 0x80) {crc ^= *pCRCTable;} 
+        pCRCTable++;
+        theByte = theByte << 1; 
+    }
+
+    rem = (msg[0] << 16) | (msg[1] << 8) | msg[2]; // message checksum
+    return ((crc ^ rem) & 0x00FFFFFF); // 24 bit checksum syndrome.
+}
+//
+//=========================================================================
+//
+// Given the Downlink Format (DF) of the message, return the message length in bits.
+//
+// All known DF's 16 or greater are long. All known DF's 15 or less are short. 
+// There are lots of unused codes in both category, so we can assume ICAO will stick to 
+// these rules, meaning that the most significant bit of the DF indicates the length.
+//
+int modesMessageLenByType(int type) {
+    return (type & 0x10) ? MODES_LONG_MSG_BITS : MODES_SHORT_MSG_BITS ;
+}
+//
+//=========================================================================
+//
+// Try to fix single bit errors using the checksum. On success modifies
+// the original buffer with the fixed version, and returns the position
+// of the error bit. Otherwise if fixing failed -1 is returned.
+/*
+int fixSingleBitErrors(unsigned char *msg, int bits) {
+    int j;
+    unsigned char aux[MODES_LONG_MSG_BYTES];
+
+    memcpy(aux, msg, bits/8);
+
+    // Do not attempt to error correct Bits 0-4. These contain the DF, and must
+    // be correct because we can only error correct DF17
+    for (j = 5; j < bits; j++) {
+        int byte    = j/8;
+        int bitmask = 1 << (7 - (j & 7));
+
+        aux[byte] ^= bitmask; // Flip j-th bit
+
+        if (0 == modesChecksum(aux, bits)) {
+            // The error is fixed. Overwrite the original buffer with the 
+            // corrected sequence, and returns the error bit position
+            msg[byte] = aux[byte];
+            return (j);
+        }
+
+        aux[byte] ^= bitmask; // Flip j-th bit back again
+    }
+    return (-1);
+}
+*/
+//=========================================================================
+//
+// Similar to fixSingleBitErrors() but try every possible two bit combination.
+// This is very slow and should be tried only against DF17 messages that
+// don't pass the checksum, and only in Aggressive Mode.
+/*
+int fixTwoBitsErrors(unsigned char *msg, int bits) {
+    int j, i;
+    unsigned char aux[MODES_LONG_MSG_BYTES];
+
+    memcpy(aux, msg, bits/8);
+
+    // Do not attempt to error correct Bits 0-4. These contain the DF, and must
+    // be correct because we can only error correct DF17
+    for (j = 5; j < bits; j++) {
+        int byte1    = j/8;
+        int bitmask1 = 1 << (7 - (j & 7));
+        aux[byte1] ^= bitmask1; // Flip j-th bit
+
+        // Don't check the same pairs multiple times, so i starts from j+1
+        for (i = j+1; i < bits; i++) {
+            int byte2    = i/8;
+            int bitmask2 = 1 << (7 - (i & 7));
+
+            aux[byte2] ^= bitmask2; // Flip i-th bit
+
+            if (0 == modesChecksum(aux, bits)) {
+                // The error is fixed. Overwrite the original buffer with
+                // the corrected sequence, and returns the error bit position
+                msg[byte1] = aux[byte1];
+                msg[byte2] = aux[byte2];
+
+                // We return the two bits as a 16 bit integer by shifting
+                // 'i' on the left. This is possible since 'i' will always
+                // be non-zero because i starts from j+1
+                return (j | (i << 8));
+
+            aux[byte2] ^= bitmask2; // Flip i-th bit back
+            }
+
+        aux[byte1] ^= bitmask1; // Flip j-th bit back
+        }
+    }
+    return (-1);
+}
+*/
+//
+//=========================================================================
+//
+// Code for introducing a less CPU-intensive method of correcting
+// single bit errors.
+//
+// Makes use of the fact that the crc checksum is linear with respect to
+// the bitwise xor operation, i.e.
+//      crc(m^e) = (crc(m)^crc(e)
+// where m and e are the message resp. error bit vectors.
+//
+// Call crc(e) the syndrome.
+//
+// The code below works by precomputing a table of (crc(e), e) for all
+// possible error vectors e (here only single bit and double bit errors),
+// search for the syndrome in the table, and correct the then known error.
+// The error vector e is represented by one or two bit positions that are
+// changed. If a second bit position is not used, it is -1.
+//
+// Run-time is binary search in a sorted table, plus some constant overhead,
+// instead of running through all possible bit positions (resp. pairs of
+// bit positions).
+//
+struct errorinfo {
+    uint32_t syndrome;                 // CRC syndrome
+    int      bits;                     // Number of bit positions to fix
+    int      pos[MODES_MAX_BITERRORS]; // Bit positions corrected by this syndrome
+};
+
+#define NERRORINFO \
+        (MODES_LONG_MSG_BITS+MODES_LONG_MSG_BITS*(MODES_LONG_MSG_BITS-1)/2)
+struct errorinfo bitErrorTable[NERRORINFO];
+
+// Compare function as needed for stdlib's qsort and bsearch functions
+int cmpErrorInfo(const void *p0, const void *p1) {
+    struct errorinfo *e0 = (struct errorinfo*)p0;
+    struct errorinfo *e1 = (struct errorinfo*)p1;
+    if (e0->syndrome == e1->syndrome) {
+        return 0;
+    } else if (e0->syndrome < e1->syndrome) {
+        return -1;
+    } else {
+        return 1;
+    }
+}
+//
+//=========================================================================
+//
+// Compute the table of all syndromes for 1-bit and 2-bit error vectors
+void modesInitErrorInfo() {
+    unsigned char msg[MODES_LONG_MSG_BYTES];
+    int i, j, n;
+    uint32_t crc;
+    n = 0;
+    memset(bitErrorTable, 0, sizeof(bitErrorTable));
+    memset(msg, 0, MODES_LONG_MSG_BYTES);
+    // Add all possible single and double bit errors
+    // don't include errors in first 5 bits (DF type)
+    for (i = 5;  i < MODES_LONG_MSG_BITS;  i++) {
+        int bytepos0 = (i >> 3);
+        int mask0 = 1 << (7 - (i & 7));
+        msg[bytepos0] ^= mask0;          // create error0
+        crc = modesChecksum(msg, MODES_LONG_MSG_BITS);
+        bitErrorTable[n].syndrome = crc;      // single bit error case
+        bitErrorTable[n].bits = 1;
+        bitErrorTable[n].pos[0] = i;
+        bitErrorTable[n].pos[1] = -1;
+        n += 1;
+
+        if (Modes.nfix_crc > 1) {
+            for (j = i+1;  j < MODES_LONG_MSG_BITS;  j++) {
+                int bytepos1 = (j >> 3);
+                int mask1 = 1 << (7 - (j & 7));
+                msg[bytepos1] ^= mask1;  // create error1
+                crc = modesChecksum(msg, MODES_LONG_MSG_BITS);
+                if (n >= NERRORINFO) {
+                    //fprintf(stderr, "Internal error, too many entries, fix NERRORINFO\n");
+                    break;
+                }
+                bitErrorTable[n].syndrome = crc; // two bit error case
+                bitErrorTable[n].bits = 2;
+                bitErrorTable[n].pos[0] = i;
+                bitErrorTable[n].pos[1] = j;
+                n += 1;
+                msg[bytepos1] ^= mask1;  // revert error1
+            }
+        }
+        msg[bytepos0] ^= mask0;          // revert error0
+    }
+    qsort(bitErrorTable, NERRORINFO, sizeof(struct errorinfo), cmpErrorInfo);
+
+    // Test code: report if any syndrome appears at least twice. In this
+    // case the correction cannot be done without ambiguity.
+    // Tried it, does not happen for 1- and 2-bit errors. 
+    /*
+    for (i = 1;  i < NERRORINFO;  i++) {
+        if (bitErrorTable[i-1].syndrome == bitErrorTable[i].syndrome) {
+            fprintf(stderr, "modesInitErrorInfo: Collision for syndrome %06x\n",
+                            (int)bitErrorTable[i].syndrome);
+        }
+    }
+
+    for (i = 0;  i < NERRORINFO;  i++) {
+        printf("syndrome %06x    bit0 %3d    bit1 %3d\n",
+               bitErrorTable[i].syndrome,
+               bitErrorTable[i].pos0, bitErrorTable[i].pos1);
+    }
+    */
+}
+//
+//=========================================================================
+//
+// Search for syndrome in table and if an entry is found, flip the necessary
+// bits. Make sure the indices fit into the array
+// Additional parameter: fix only less than maxcorrected bits, and record
+// fixed bit positions in corrected[]. This array can be NULL, otherwise
+// must be of length at least maxcorrected.
+// Return number of fixed bits.
+//
+int fixBitErrors(unsigned char *msg, int bits, int maxfix, char *fixedbits) {
+    struct errorinfo *pei;
+    struct errorinfo ei;
+    int bitpos, offset, res, i;
+    memset(&ei, 0, sizeof(struct errorinfo));
+    ei.syndrome = modesChecksum(msg, bits);
+    pei = bsearch(&ei, bitErrorTable, NERRORINFO,
+                  sizeof(struct errorinfo), cmpErrorInfo);
+    if (pei == NULL) {
+        return 0; // No syndrome found
+    }
+
+    // Check if the syndrome fixes more bits than we allow
+    if (maxfix < pei->bits) {
+        return 0;
+    }
+
+    // Check that all bit positions lie inside the message length
+    offset = MODES_LONG_MSG_BITS-bits;
+    for (i = 0;  i < pei->bits;  i++) {
+	    bitpos = pei->pos[i] - offset;
+	    if ((bitpos < 0) || (bitpos >= bits)) {
+		    return 0;
+	    }
+    }
+
+    // Fix the bits
+    for (i = res = 0;  i < pei->bits;  i++) {
+	    bitpos = pei->pos[i] - offset;
+	    msg[bitpos >> 3] ^= (1 << (7 - (bitpos & 7)));
+	    if (fixedbits) {
+		    fixedbits[res++] = bitpos;
+	    }
+    }
+    return res;
+}
+//
+// ============================== Debugging =================================
+//
+// Helper function for dumpMagnitudeVector().
+// It prints a single bar used to display raw signals.
+//
+// Since every magnitude sample is between 0-255, the function uses
+// up to 63 characters for every bar. Every character represents
+// a length of 4, 3, 2, 1, specifically:
+//
+// "O" is 4
+// "o" is 3
+// "-" is 2
+// "." is 1
+//
+void dumpMagnitudeBar(int index, int magnitude) {
+    char *set = " .-o";
+    char buf[256];
+    int div = magnitude / 256 / 4;
+    int rem = magnitude / 256 % 4;
+
+    memset(buf,'O',div);
+    buf[div] = set[rem];
+    buf[div+1] = '\0';
+
+    if (index >= 0)
+        printf("[%.3d] |%-66s 0x%04X\n", index, buf, magnitude);
+    else
+        printf("[%.2d] |%-66s 0x%04X\n", index, buf, magnitude);
+}
+//
+//=========================================================================
+//
+// Display an ASCII-art alike graphical representation of the undecoded
+// message as a magnitude signal.
+//
+// The message starts at the specified offset in the "m" buffer.
+// The function will display enough data to cover a short 56 bit message.
+//
+// If possible a few samples before the start of the messsage are included
+// for context.
+//
+void dumpMagnitudeVector(uint16_t *m, uint32_t offset) {
+    uint32_t padding = 5; // Show a few samples before the actual start.
+    uint32_t start = (offset < padding) ? 0 : offset-padding;
+    uint32_t end = offset + (MODES_PREAMBLE_SAMPLES)+(MODES_SHORT_MSG_SAMPLES) - 1;
+    uint32_t j;
+
+    for (j = start; j <= end; j++) {
+        dumpMagnitudeBar(j-offset, m[j]);
+    }
+}
+//
+//=========================================================================
+//
+// Produce a raw representation of the message as a Javascript file
+// loadable by debug.html.
+//
+void dumpRawMessageJS(char *descr, unsigned char *msg,
+                      uint16_t *m, uint32_t offset, int fixable, char *bitpos)
+{
+    int padding = 5; // Show a few samples before the actual start.
+    int start = offset - padding;
+    int end = offset + (MODES_PREAMBLE_SAMPLES)+(MODES_LONG_MSG_SAMPLES) - 1;
+    FILE *fp;
+    int j;
+
+    MODES_NOTUSED(fixable);
+    if ((fp = fopen("frames.js","a")) == NULL) {
+        fprintf(stderr, "Error opening frames.js: %s\n", strerror(errno));
+        exit(1);
+    }
+
+    fprintf(fp,"frames.push({\"descr\": \"%s\", \"mag\": [", descr);
+    for (j = start; j <= end; j++) {
+        fprintf(fp,"%d", j < 0 ? 0 : m[j]);
+        if (j != end) fprintf(fp,",");
+    }
+    fprintf(fp,"], \"fix1\": %d, \"fix2\": %d, \"bits\": %d, \"hex\": \"",
+	    bitpos[0], bitpos[1] , modesMessageLenByType(msg[0]>>3));
+    for (j = 0; j < MODES_LONG_MSG_BYTES; j++)
+        fprintf(fp,"\\x%02x",msg[j]);
+    fprintf(fp,"\"});\n");
+    fclose(fp);
+}
+//
+//=========================================================================
+//
+// This is a wrapper for dumpMagnitudeVector() that also show the message
+// in hex format with an additional description.
+//
+// descr  is the additional message to show to describe the dump.
+// msg    points to the decoded message
+// m      is the original magnitude vector
+// offset is the offset where the message starts
+//
+// The function also produces the Javascript file used by debug.html to
+// display packets in a graphical format if the Javascript output was
+// enabled.
+//
+void dumpRawMessage(char *descr, unsigned char *msg, uint16_t *m, uint32_t offset) {
+    int  j;
+    int  msgtype = msg[0] >> 3;
+    int  fixable = 0;
+    char bitpos[MODES_MAX_BITERRORS];
+
+    for (j = 0;  j < MODES_MAX_BITERRORS;  j++) {
+        bitpos[j] = -1;
+    }
+    if (msgtype == 17) {
+        fixable = fixBitErrors(msg, MODES_LONG_MSG_BITS, MODES_MAX_BITERRORS, bitpos);
+    }
+
+    if (Modes.debug & MODES_DEBUG_JS) {
+        dumpRawMessageJS(descr, msg, m, offset, fixable, bitpos);
+        return;
+    }
+
+    printf("\n--- %s\n    ", descr);
+    for (j = 0; j < MODES_LONG_MSG_BYTES; j++) {
+        printf("%02x",msg[j]);
+        if (j == MODES_SHORT_MSG_BYTES-1) printf(" ... ");
+    }
+    printf(" (DF %d, Fixable: %d)\n", msgtype, fixable);
+    dumpMagnitudeVector(m,offset);
+    printf("---\n\n");
+}
+//
+//=========================================================================
+//
+// Code for testing the timing: run all possible 1- and 2-bit error 
+// the test message by all 1-bit errors. Run the old code against
+// all of them, and new the code.
+//
+// Example measurements:
+// Timing old vs. new crc correction code:
+//    Old code: 1-bit errors on 112 msgs: 3934 usecs
+//    New code: 1-bit errors on 112 msgs: 104 usecs
+//    Old code: 2-bit errors on 6216 msgs: 407743 usecs
+//    New code: 2-bit errors on 6216 msgs: 5176 usecs
+// indicating a 37-fold resp. 78-fold improvement in speed for 1-bit resp.
+// 2-bit error.
+/*
+unsigned char tmsg0[MODES_LONG_MSG_BYTES] = {
+        // Test data: first ADS-B message from testfiles/modes1.bin
+        0x8f, 0x4d, 0x20, 0x23, 0x58, 0x7f, 0x34, 0x5e,
+        0x35, 0x83, 0x7e, 0x22, 0x18, 0xb2
+};
+#define NTWOBITS (MODES_LONG_MSG_BITS*(MODES_LONG_MSG_BITS-1)/2)
+unsigned char tmsg1[MODES_LONG_MSG_BITS][MODES_LONG_MSG_BYTES];
+unsigned char tmsg2[NTWOBITS][MODES_LONG_MSG_BYTES];
+// Init an array of cloned messages with all possible 1-bit errors present,
+// applied to each message at the respective position
+//
+void inittmsg1() {
+        int i, bytepos, mask;
+        for (i = 0;  i < MODES_LONG_MSG_BITS;  i++) {
+                bytepos = i >> 3;
+                mask = 1 << (7 - (i & 7));
+                memcpy(&tmsg1[i][0], tmsg0, MODES_LONG_MSG_BYTES);
+                tmsg1[i][bytepos] ^= mask;
+        }
+}
+
+// Run sanity check on all but first 5 messages / bits, as those bits
+// are not corrected.
+//
+void checktmsg1(FILE *out) {
+        int i, k;
+        uint32_t crc;
+        for (i = 5;  i < MODES_LONG_MSG_BITS;  i++) {
+                crc = modesChecksum(&tmsg1[i][0], MODES_LONG_MSG_BITS);
+                if (crc != 0) {
+                        fprintf(out, "CRC not fixed for "
+                                "positon %d\n", i);
+                        fprintf(out, "  MSG ");
+                        for (k = 0;  k < MODES_LONG_MSG_BYTES;  k++) {
+                                fprintf(out, "%02x", tmsg1[i][k]);
+                        }
+                        fprintf(out, "\n");
+                }
+        }
+}
+
+void inittmsg2() {
+        int i, j, n, bytepos0, bytepos1, mask0, mask1;
+        n = 0;
+        for (i = 0;  i < MODES_LONG_MSG_BITS;  i++) {
+                bytepos0 = i >> 3;
+                mask0 = 1 << (7 - (i & 7));
+                for (j = i+1;  j < MODES_LONG_MSG_BITS;  j++) {
+                        bytepos1 = j >> 3;
+                        mask1 = 1 << (7 - (j & 7));
+                        memcpy(&tmsg2[n][0], tmsg0, MODES_LONG_MSG_BYTES);
+                        tmsg2[n][bytepos0] ^= mask0;
+                        tmsg2[n][bytepos1] ^= mask1;
+                        n += 1;
+                }
+        }
+}
+
+long difftvusec(struct timeval *t0, struct timeval *t1) {
+        long res = 0;
+        res = t1->tv_usec-t0->tv_usec;
+        res += (t1->tv_sec-t0->tv_sec)*1000000L;
+        return res;
+}
+
+// the actual test code
+void testAndTimeBitCorrection() {
+        struct timeval starttv, endtv;
+        int i;
+        // Run timing on 1-bit errors
+        printf("Timing old vs. new crc correction code:\n");
+        inittmsg1();
+        gettimeofday(&starttv, NULL);
+        for (i = 0;  i < MODES_LONG_MSG_BITS;  i++) {
+            fixSingleBitErrors(&tmsg1[i][0], MODES_LONG_MSG_BITS);
+        }
+        gettimeofday(&endtv, NULL);
+        printf("   Old code: 1-bit errors on %d msgs: %ld usecs\n",
+               MODES_LONG_MSG_BITS, difftvusec(&starttv, &endtv));
+        checktmsg1(stdout);
+        // Re-init
+        inittmsg1();
+        gettimeofday(&starttv, NULL);
+        for (i = 0;  i < MODES_LONG_MSG_BITS;  i++) {
+            fixBitErrors(&tmsg1[i][0], MODES_LONG_MSG_BITS, MODES_MAX_BITERRORS, NULL);
+        }
+        gettimeofday(&endtv, NULL);
+        printf("   New code: 1-bit errors on %d msgs: %ld usecs\n",
+               MODES_LONG_MSG_BITS, difftvusec(&starttv, &endtv));
+        checktmsg1(stdout);
+        // Run timing on 2-bit errors
+        inittmsg2();
+        gettimeofday(&starttv, NULL);
+        for (i = 0;  i < NTWOBITS;  i++) {
+            fixSingleBitErrors(&tmsg2[i][0], MODES_LONG_MSG_BITS);
+        }
+        gettimeofday(&endtv, NULL);
+        printf("   Old code: 2-bit errors on %d msgs: %ld usecs\n",
+               NTWOBITS, difftvusec(&starttv, &endtv));
+        // Re-init
+        inittmsg2();
+        gettimeofday(&starttv, NULL);
+        for (i = 0;  i < NTWOBITS;  i++) {
+            fixBitErrors(&tmsg2[i][0], MODES_LONG_MSG_BITS, MODES_MAX_BITERRORS, NULL);
+        }
+        gettimeofday(&endtv, NULL);
+        printf("   New code: 2-bit errors on %d msgs: %ld usecs\n",
+               NTWOBITS, difftvusec(&starttv, &endtv));
+}
+*/
+//=========================================================================
+//
+// Hash the ICAO address to index our cache of MODES_ICAO_CACHE_LEN
+// elements, that is assumed to be a power of two
+//
+uint32_t ICAOCacheHashAddress(uint32_t a) {
+    // The following three rounds wil make sure that every bit affects
+    // every output bit with ~ 50% of probability.
+    a = ((a >> 16) ^ a) * 0x45d9f3b;
+    a = ((a >> 16) ^ a) * 0x45d9f3b;
+    a = ((a >> 16) ^ a);
+    return a & (MODES_ICAO_CACHE_LEN-1);
+}
+//
+//=========================================================================
+//
+// Add the specified entry to the cache of recently seen ICAO addresses.
+// Note that we also add a timestamp so that we can make sure that the
+// entry is only valid for MODES_ICAO_CACHE_TTL seconds.
+//
+void addRecentlySeenICAOAddr(uint32_t addr) {
+    uint32_t h = ICAOCacheHashAddress(addr);
+    Modes.icao_cache[h*2] = addr;
+    Modes.icao_cache[h*2+1] = (uint32_t) time(NULL);
+}
+//
+//=========================================================================
+//
+// Returns 1 if the specified ICAO address was seen in a DF format with
+// proper checksum (not xored with address) no more than * MODES_ICAO_CACHE_TTL
+// seconds ago. Otherwise returns 0.
+//
+int ICAOAddressWasRecentlySeen(uint32_t addr) {
+    uint32_t h = ICAOCacheHashAddress(addr);
+    uint32_t a = Modes.icao_cache[h*2];
+    uint32_t t = Modes.icao_cache[h*2+1];
+    uint64_t tn = time(NULL);
+
+    return ( (a) && (a == addr) && ( (tn - t) <= MODES_ICAO_CACHE_TTL) );
+}
+//
+//=========================================================================
+//
+// In the squawk (identity) field bits are interleaved as follows in
+// (message bit 20 to bit 32):
+//
+// C1-A1-C2-A2-C4-A4-ZERO-B1-D1-B2-D2-B4-D4
+//
+// So every group of three bits A, B, C, D represent an integer from 0 to 7.
+//
+// The actual meaning is just 4 octal numbers, but we convert it into a hex 
+// number tha happens to represent the four octal numbers.
+//
+// For more info: http://en.wikipedia.org/wiki/Gillham_code
+//
+int decodeID13Field(int ID13Field) {
+    int hexGillham = 0;
+
+    if (ID13Field & 0x1000) {hexGillham |= 0x0010;} // Bit 12 = C1
+    if (ID13Field & 0x0800) {hexGillham |= 0x1000;} // Bit 11 = A1
+    if (ID13Field & 0x0400) {hexGillham |= 0x0020;} // Bit 10 = C2
+    if (ID13Field & 0x0200) {hexGillham |= 0x2000;} // Bit  9 = A2
+    if (ID13Field & 0x0100) {hexGillham |= 0x0040;} // Bit  8 = C4
+    if (ID13Field & 0x0080) {hexGillham |= 0x4000;} // Bit  7 = A4
+  //if (ID13Field & 0x0040) {hexGillham |= 0x0800;} // Bit  6 = X  or M 
+    if (ID13Field & 0x0020) {hexGillham |= 0x0100;} // Bit  5 = B1 
+    if (ID13Field & 0x0010) {hexGillham |= 0x0001;} // Bit  4 = D1 or Q
+    if (ID13Field & 0x0008) {hexGillham |= 0x0200;} // Bit  3 = B2
+    if (ID13Field & 0x0004) {hexGillham |= 0x0002;} // Bit  2 = D2
+    if (ID13Field & 0x0002) {hexGillham |= 0x0400;} // Bit  1 = B4
+    if (ID13Field & 0x0001) {hexGillham |= 0x0004;} // Bit  0 = D4
+
+    return (hexGillham);
+    }
+//
+//=========================================================================
+//
+// Decode the 13 bit AC altitude field (in DF 20 and others).
+// Returns the altitude, and set 'unit' to either MODES_UNIT_METERS or MDOES_UNIT_FEETS.
+//
+int decodeAC13Field(int AC13Field, int *unit) {
+    int m_bit  = AC13Field & 0x0040; // set = meters, clear = feet
+    int q_bit  = AC13Field & 0x0010; // set = 25 ft encoding, clear = Gillham Mode C encoding
+
+    if (!m_bit) {
+        *unit = MODES_UNIT_FEET;
+        if (q_bit) {
+            // N is the 11 bit integer resulting from the removal of bit Q and M
+            int n = ((AC13Field & 0x1F80) >> 2) |
+                    ((AC13Field & 0x0020) >> 1) |
+                     (AC13Field & 0x000F);
+            // The final altitude is resulting number multiplied by 25, minus 1000.
+            return ((n * 25) - 1000);
+        } else {
+            // N is an 11 bit Gillham coded altitude
+            int n = ModeAToModeC(decodeID13Field(AC13Field));
+            if (n < -12) {n = 0;}
+
+            return (100 * n);
+        }
+    } else {
+        *unit = MODES_UNIT_METERS;
+        // TODO: Implement altitude when meter unit is selected
+    }
+    return 0;
+}
+//
+//=========================================================================
+//
+// Decode the 12 bit AC altitude field (in DF 17 and others).
+//
+int decodeAC12Field(int AC12Field, int *unit) {
+    int q_bit  = AC12Field & 0x10; // Bit 48 = Q
+
+    *unit = MODES_UNIT_FEET;
+    if (q_bit) {
+        /// N is the 11 bit integer resulting from the removal of bit Q at bit 4
+        int n = ((AC12Field & 0x0FE0) >> 1) | 
+                 (AC12Field & 0x000F);
+        // The final altitude is the resulting number multiplied by 25, minus 1000.
+        return ((n * 25) - 1000);
+    } else {
+        // Make N a 13 bit Gillham coded altitude by inserting M=0 at bit 6
+        int n = ((AC12Field & 0x0FC0) << 1) | 
+                 (AC12Field & 0x003F);
+        n = ModeAToModeC(decodeID13Field(n));
+        if (n < -12) {n = 0;}
+
+        return (100 * n);
+    }
+}
+//
+//=========================================================================
+//
+// Decode the 7 bit ground movement field PWL exponential style scale
+//
+int decodeMovementField(int movement) {
+    int gspeed;
+
+    // Note : movement codes 0,125,126,127 are all invalid, but they are 
+    //        trapped for before this function is called.
+
+    if      (movement  > 123) gspeed = 199; // > 175kt
+    else if (movement  > 108) gspeed = ((movement - 108)  * 5) + 100;
+    else if (movement  >  93) gspeed = ((movement -  93)  * 2) +  70;
+    else if (movement  >  38) gspeed = ((movement -  38)     ) +  15;
+    else if (movement  >  12) gspeed = ((movement -  11) >> 1) +   2;
+    else if (movement  >   8) gspeed = ((movement -   6) >> 2) +   1;
+    else                      gspeed = 0;
+
+    return (gspeed);
+}
+//
+//=========================================================================
+//
+// Capability table
+char *ca_str[8] = {
+    /* 0 */ "Level 1 (Surveillance Only)",
+    /* 1 */ "Level 2 (DF0,4,5,11)",
+    /* 2 */ "Level 3 (DF0,4,5,11,20,21)",
+    /* 3 */ "Level 4 (DF0,4,5,11,20,21,24)",
+    /* 4 */ "Level 2+3+4 (DF0,4,5,11,20,21,24,code7 - is on ground)",
+    /* 5 */ "Level 2+3+4 (DF0,4,5,11,20,21,24,code7 - is airborne)",
+    /* 6 */ "Level 2+3+4 (DF0,4,5,11,20,21,24,code7)",
+    /* 7 */ "Level 7 ???"
+};
+
+// DF 18 Control field table.
+char *cf_str[8] = {
+    /* 0 */ "ADS-B ES/NT device with ICAO 24-bit address",
+    /* 1 */ "ADS-B ES/NT device with other address",
+    /* 2 */ "Fine format TIS-B",
+    /* 3 */ "Coarse format TIS-B",
+    /* 4 */ "TIS-B management message",
+    /* 5 */ "TIS-B relay of ADS-B message with other address",
+    /* 6 */ "ADS-B rebroadcast using DF-17 message format",
+    /* 7 */ "Reserved"
+};
+
+// Flight status table
+char *fs_str[8] = {
+    /* 0 */ "Normal, Airborne",
+    /* 1 */ "Normal, On the ground",
+    /* 2 */ "ALERT,  Airborne",
+    /* 3 */ "ALERT,  On the ground",
+    /* 4 */ "ALERT & Special Position Identification. Airborne or Ground",
+    /* 5 */ "Special Position Identification. Airborne or Ground",
+    /* 6 */ "Value 6 is not assigned",
+    /* 7 */ "Value 7 is not assigned"
+};
+
+// Emergency state table
+// from https://www.ll.mit.edu/mission/aviation/publications/publication-files/atc-reports/Grappel_2007_ATC-334_WW-15318.pdf
+// and 1090-DO-260B_FRAC
+char *es_str[8] = {
+    /* 0 */ "No emergency",
+    /* 1 */ "General emergency (squawk 7700)",
+    /* 2 */ "Lifeguard/Medical",
+    /* 3 */ "Minimum fuel",
+    /* 4 */ "No communications (squawk 7600)",
+    /* 5 */ "Unlawful interference (squawk 7500)",
+    /* 6 */ "Downed Aircraft",
+    /* 7 */ "Reserved"
+};
+//
+//=========================================================================
+//
+char *getMEDescription(int metype, int mesub) {
+    char *mename = "Unknown";
+
+    if (metype >= 1 && metype <= 4)
+        mename = "Aircraft Identification and Category";
+    else if (metype >= 5 && metype <= 8)
+        mename = "Surface Position";
+    else if (metype >= 9 && metype <= 18)
+        mename = "Airborne Position (Baro Altitude)";
+    else if (metype == 19 && mesub >=1 && mesub <= 4)
+        mename = "Airborne Velocity";
+    else if (metype >= 20 && metype <= 22)
+        mename = "Airborne Position (GNSS Height)";
+    else if (metype == 23 && mesub == 0)
+        mename = "Test Message";
+    else if (metype == 23 && mesub == 7)
+        mename = "Test Message -- Squawk";
+    else if (metype == 24 && mesub == 1)
+        mename = "Surface System Status";
+    else if (metype == 28 && mesub == 1)
+        mename = "Extended Squitter Aircraft Status (Emergency)";
+    else if (metype == 28 && mesub == 2)
+        mename = "Extended Squitter Aircraft Status (1090ES TCAS RA)";
+    else if (metype == 29 && (mesub == 0 || mesub == 1))
+        mename = "Target State and Status Message";
+    else if (metype == 31 && (mesub == 0 || mesub == 1))
+        mename = "Aircraft Operational Status Message";
+    return mename;
+}
+//
+//=========================================================================
+//
+// Decode a raw Mode S message demodulated as a stream of bytes by detectModeS(), 
+// and split it into fields populating a modesMessage structure.
+//
+void decodeModesMessage(struct modesMessage *mm, unsigned char *msg) {
+    char *ais_charset = "?ABCDEFGHIJKLMNOPQRSTUVWXYZ????? ???????????????0123456789??????";
+
+    // Work on our local copy
+    memcpy(mm->msg, msg, MODES_LONG_MSG_BYTES);
+    msg = mm->msg;
+
+    // Get the message type ASAP as other operations depend on this
+    mm->msgtype         = msg[0] >> 3; // Downlink Format
+    mm->msgbits         = modesMessageLenByType(mm->msgtype);
+    mm->crc             = modesChecksum(msg, mm->msgbits);
+
+    if ((mm->crc) && (Modes.nfix_crc) && ((mm->msgtype == 17) || (mm->msgtype == 18))) {
+//  if ((mm->crc) && (Modes.nfix_crc) && ((mm->msgtype == 11) || (mm->msgtype == 17))) {
+        //
+        // Fixing single bit errors in DF-11 is a bit dodgy because we have no way to 
+        // know for sure if the crc is supposed to be 0 or not - it could be any value 
+        // less than 80. Therefore, attempting to fix DF-11 errors can result in a 
+        // multitude of possible crc solutions, only one of which is correct.
+        // 
+        // We should probably perform some sanity checks on corrected DF-11's before 
+        // using the results. Perhaps check the ICAO against known aircraft, and check
+        // IID against known good IID's. That's a TODO.
+        //
+        mm->correctedbits = fixBitErrors(msg, mm->msgbits, Modes.nfix_crc, mm->corrected);
+
+        // If we correct, validate ICAO addr to help filter birthday paradox solutions.
+        if (mm->correctedbits) {
+            uint32_t ulAddr = (msg[1] << 16) | (msg[2] << 8) | (msg[3]); 
+            if (!ICAOAddressWasRecentlySeen(ulAddr))
+                mm->correctedbits = 0;
+        }
+    }
+    //
+    // Note that most of the other computation happens *after* we fix the 
+    // single/two bit errors, otherwise we would need to recompute the fields again.
+    //
+    if (mm->msgtype == 11) { // DF 11
+        mm->iid   =  mm->crc;
+        mm->addr  = (msg[1] << 16) | (msg[2] << 8) | (msg[3]); 
+        mm->ca    = (msg[0] & 0x07); // Responder capabilities
+
+        if ((mm->crcok = (0 == mm->crc))) {
+            // DF 11 : if crc == 0 try to populate our ICAO addresses whitelist.
+            addRecentlySeenICAOAddr(mm->addr);
+        } else if (mm->crc < 80) {
+            mm->crcok = ICAOAddressWasRecentlySeen(mm->addr);
+            if (mm->crcok) {
+                addRecentlySeenICAOAddr(mm->addr);
+            }
+        }
+
+    } else if (mm->msgtype == 17) { // DF 17
+        mm->addr  = (msg[1] << 16) | (msg[2] << 8) | (msg[3]); 
+        mm->ca    = (msg[0] & 0x07); // Responder capabilities
+
+        if ((mm->crcok = (0 == mm->crc))) {
+            // DF 17 : if crc == 0 try to populate our ICAO addresses whitelist.
+            addRecentlySeenICAOAddr(mm->addr);
+        }
+
+    } else if (mm->msgtype == 18) { // DF 18
+        mm->addr  = (msg[1] << 16) | (msg[2] << 8) | (msg[3]); 
+        mm->ca    = (msg[0] & 0x07); // Control Field
+
+        if ((mm->crcok = (0 == mm->crc))) {
+            // DF 18 : if crc == 0 try to populate our ICAO addresses whitelist.
+            addRecentlySeenICAOAddr(mm->addr);
+        }
+
+    } else { // All other DF's
+        // Compare the checksum with the whitelist of recently seen ICAO 
+        // addresses. If it matches one, then declare the message as valid
+        mm->crcok = ICAOAddressWasRecentlySeen(mm->addr = mm->crc);
+    }
+
+    // If we're checking CRC and the CRC is invalid, then we can't trust any 
+    // of the data contents, so save time and give up now.
+    if ((Modes.check_crc) && (!mm->crcok) && (!mm->correctedbits)) { return;}
+
+    // Fields for DF0, DF16
+    if (mm->msgtype == 0  || mm->msgtype == 16) {
+        if (msg[0] & 0x04) {                       // VS Bit
+            mm->bFlags |= MODES_ACFLAGS_AOG_VALID | MODES_ACFLAGS_AOG;
+        } else {
+            mm->bFlags |= MODES_ACFLAGS_AOG_VALID;
+        }
+    }
+
+    // Fields for DF11, DF17
+    if (mm->msgtype == 11 || mm->msgtype == 17) {
+        if (mm->ca == 4) {
+            mm->bFlags |= MODES_ACFLAGS_AOG_VALID | MODES_ACFLAGS_AOG;
+        } else if (mm->ca == 5) {
+            mm->bFlags |= MODES_ACFLAGS_AOG_VALID;
+        }
+    }
+          
+    // Fields for DF5, DF21 = Gillham encoded Squawk
+    if (mm->msgtype == 5  || mm->msgtype == 21) {
+        int ID13Field = ((msg[2] << 8) | msg[3]) & 0x1FFF; 
+        if (ID13Field) {
+            mm->bFlags |= MODES_ACFLAGS_SQUAWK_VALID;
+            mm->modeA   = decodeID13Field(ID13Field);
+        }
+    }
+
+    // Fields for DF0, DF4, DF16, DF20 13 bit altitude
+    if (mm->msgtype == 0  || mm->msgtype == 4 ||
+        mm->msgtype == 16 || mm->msgtype == 20) {
+        int AC13Field = ((msg[2] << 8) | msg[3]) & 0x1FFF; 
+        if (AC13Field) { // Only attempt to decode if a valid (non zero) altitude is present
+            mm->bFlags  |= MODES_ACFLAGS_ALTITUDE_VALID;
+            mm->altitude = decodeAC13Field(AC13Field, &mm->unit);
+        }
+    }
+
+    // Fields for DF4, DF5, DF20, DF21
+    if ((mm->msgtype == 4) || (mm->msgtype == 20) ||
+        (mm->msgtype == 5) || (mm->msgtype == 21)) {
+        mm->bFlags  |= MODES_ACFLAGS_FS_VALID;
+        mm->fs       = msg[0]  & 7;               // Flight status for DF4,5,20,21
+        if (mm->fs <= 3) {
+            mm->bFlags |= MODES_ACFLAGS_AOG_VALID;
+            if (mm->fs & 1)
+                {mm->bFlags |= MODES_ACFLAGS_AOG;}
+        }
+    }
+
+    // Fields for DF17, DF18_CF0, DF18_CF1, DF18_CF6 squitters
+    if (  (mm->msgtype == 17) 
+      || ((mm->msgtype == 18) && ((mm->ca == 0) || (mm->ca == 1) || (mm->ca == 6)) )) {
+         int metype = mm->metype = msg[4] >> 3;   // Extended squitter message type
+         int mesub  = mm->mesub  = (metype == 29 ? ((msg[4]&6)>>1) : (msg[4]  & 7));   // Extended squitter message subtype
+
+        // Decode the extended squitter message
+
+        if (metype >= 1 && metype <= 4) { // Aircraft Identification and Category
+            uint32_t chars;
+            mm->bFlags |= MODES_ACFLAGS_CALLSIGN_VALID;
+
+            chars = (msg[5] << 16) | (msg[6] << 8) | (msg[7]);
+            mm->flight[3] = ais_charset[chars & 0x3F]; chars = chars >> 6;
+            mm->flight[2] = ais_charset[chars & 0x3F]; chars = chars >> 6;
+            mm->flight[1] = ais_charset[chars & 0x3F]; chars = chars >> 6;
+            mm->flight[0] = ais_charset[chars & 0x3F];
+
+            chars = (msg[8] << 16) | (msg[9] << 8) | (msg[10]);
+            mm->flight[7] = ais_charset[chars & 0x3F]; chars = chars >> 6;
+            mm->flight[6] = ais_charset[chars & 0x3F]; chars = chars >> 6;
+            mm->flight[5] = ais_charset[chars & 0x3F]; chars = chars >> 6;
+            mm->flight[4] = ais_charset[chars & 0x3F];
+
+            mm->flight[8] = '\0';
+
+        } else if (metype == 19) { // Airborne Velocity Message
+
+           // Presumably airborne if we get an Airborne Velocity Message
+            mm->bFlags |= MODES_ACFLAGS_AOG_VALID; 
+
+            if ( (mesub >= 1) && (mesub <= 4) ) {
+                int vert_rate = ((msg[8] & 0x07) << 6) | (msg[9] >> 2);
+                if (vert_rate) {
+                    --vert_rate;
+                    if (msg[8] & 0x08) 
+                      {vert_rate = 0 - vert_rate;}
+                    mm->vert_rate =  vert_rate * 64;
+                    mm->bFlags   |= MODES_ACFLAGS_VERTRATE_VALID;
+                }
+            }
+
+            if ((mesub == 1) || (mesub == 2)) {
+                int ew_raw = ((msg[5] & 0x03) << 8) |  msg[6];
+                int ew_vel = ew_raw - 1;
+                int ns_raw = ((msg[7] & 0x7F) << 3) | (msg[8] >> 5);
+                int ns_vel = ns_raw - 1;
+
+                if (mesub == 2) { // If (supersonic) unit is 4 kts
+                   ns_vel = ns_vel << 2;
+                   ew_vel = ew_vel << 2;
+                }
+
+                if (ew_raw) { // Do East/West  
+                    mm->bFlags |= MODES_ACFLAGS_EWSPEED_VALID;
+                    if (msg[5] & 0x04)
+                        {ew_vel = 0 - ew_vel;}                   
+                    mm->ew_velocity = ew_vel;
+                }
+
+                if (ns_raw) { // Do North/South
+                    mm->bFlags |= MODES_ACFLAGS_NSSPEED_VALID;
+                    if (msg[7] & 0x80)
+                        {ns_vel = 0 - ns_vel;}                   
+                    mm->ns_velocity = ns_vel;
+                }
+
+                if (ew_raw && ns_raw) {
+                    // Compute velocity and angle from the two speed components
+                    mm->bFlags |= (MODES_ACFLAGS_SPEED_VALID | MODES_ACFLAGS_HEADING_VALID | MODES_ACFLAGS_NSEWSPD_VALID);
+                    mm->velocity = (int) sqrt((ns_vel * ns_vel) + (ew_vel * ew_vel));
+
+                    if (mm->velocity) {
+                        mm->heading = (int) (atan2(ew_vel, ns_vel) * 180.0 / M_PI);
+                        // We don't want negative values but a 0-360 scale
+                        if (mm->heading < 0) mm->heading += 360;
+                    }
+                }
+
+            } else if (mesub == 3 || mesub == 4) {
+                int airspeed = ((msg[7] & 0x7f) << 3) | (msg[8] >> 5);
+                if (airspeed) {
+                    mm->bFlags |= MODES_ACFLAGS_SPEED_VALID;
+                    --airspeed;
+                    if (mesub == 4)  // If (supersonic) unit is 4 kts
+                        {airspeed = airspeed << 2;}
+                    mm->velocity =  airspeed;
+                }
+
+                if (msg[5] & 0x04) {
+                    mm->bFlags |= MODES_ACFLAGS_HEADING_VALID;
+                    mm->heading = ((((msg[5] & 0x03) << 8) | msg[6]) * 45) >> 7;
+                }
+            }
+
+        } else if (metype >= 5 && metype <= 22) { // Position Message
+            mm->raw_latitude  = ((msg[6] & 3) << 15) | (msg[7] << 7) | (msg[8] >> 1);
+            mm->raw_longitude = ((msg[8] & 1) << 16) | (msg[9] << 8) | (msg[10]);
+            mm->bFlags       |= (mm->msg[6] & 0x04) ? MODES_ACFLAGS_LLODD_VALID 
+                                                    : MODES_ACFLAGS_LLEVEN_VALID;
+            if (metype >= 9) {        // Airborne
+                int AC12Field = ((msg[5] << 4) | (msg[6] >> 4)) & 0x0FFF;
+                mm->bFlags |= MODES_ACFLAGS_AOG_VALID;
+                if (AC12Field) {// Only attempt to decode if a valid (non zero) altitude is present
+                    mm->bFlags |= MODES_ACFLAGS_ALTITUDE_VALID;
+                    mm->altitude = decodeAC12Field(AC12Field, &mm->unit);
+                }
+            } else {                      // Ground
+                int movement = ((msg[4] << 4) | (msg[5] >> 4)) & 0x007F;
+                mm->bFlags |= MODES_ACFLAGS_AOG_VALID | MODES_ACFLAGS_AOG;
+                if ((movement) && (movement < 125)) {
+                    mm->bFlags |= MODES_ACFLAGS_SPEED_VALID;
+                    mm->velocity = decodeMovementField(movement);
+                }
+
+                if (msg[5] & 0x08) {
+                    mm->bFlags |= MODES_ACFLAGS_HEADING_VALID;
+                    mm->heading = ((((msg[5] << 4) | (msg[6] >> 4)) & 0x007F) * 45) >> 4;
+                }
+            }
+
+        } else if (metype == 23) {	// Test metype squawk field
+			if (mesub == 7) {		// (see 1090-WP-15-20)
+				int ID13Field = (((msg[5] << 8) | msg[6]) & 0xFFF1)>>3;
+				if (ID13Field) {
+					mm->bFlags |= MODES_ACFLAGS_SQUAWK_VALID;
+					mm->modeA   = decodeID13Field(ID13Field);
+				}
+            }
+
+        } else if (metype == 24) { // Reserved for Surface System Status
+
+        } else if (metype == 28) { // Extended Squitter Aircraft Status
+			if (mesub == 1) {      // Emergency status squawk field
+				int ID13Field = (((msg[5] << 8) | msg[6]) & 0x1FFF);
+				if (ID13Field) {
+					mm->bFlags |= MODES_ACFLAGS_SQUAWK_VALID;
+					mm->modeA   = decodeID13Field(ID13Field);
+				}
+            }
+
+        } else if (metype == 29) { // Aircraft Trajectory Intent
+
+        } else if (metype == 30) { // Aircraft Operational Coordination
+
+        } else if (metype == 31) { // Aircraft Operational Status
+
+        } else { // Other metypes
+
+        }
+    }
+
+    // Fields for DF20, DF21 Comm-B
+    if ((mm->msgtype == 20) || (mm->msgtype == 21)){
+
+        if (msg[4] == 0x20) { // Aircraft Identification
+            uint32_t chars;
+            mm->bFlags |= MODES_ACFLAGS_CALLSIGN_VALID;
+
+            chars = (msg[5] << 16) | (msg[6] << 8) | (msg[7]);
+            mm->flight[3] = ais_charset[chars & 0x3F]; chars = chars >> 6;
+            mm->flight[2] = ais_charset[chars & 0x3F]; chars = chars >> 6;
+            mm->flight[1] = ais_charset[chars & 0x3F]; chars = chars >> 6;
+            mm->flight[0] = ais_charset[chars & 0x3F];
+
+            chars = (msg[8] << 16) | (msg[9] << 8) | (msg[10]);
+            mm->flight[7] = ais_charset[chars & 0x3F]; chars = chars >> 6;
+            mm->flight[6] = ais_charset[chars & 0x3F]; chars = chars >> 6;
+            mm->flight[5] = ais_charset[chars & 0x3F]; chars = chars >> 6;
+            mm->flight[4] = ais_charset[chars & 0x3F];
+
+            mm->flight[8] = '\0';
+        } else {
+        }
+    }
+}
+//
+//=========================================================================
+//
+// This function gets a decoded Mode S Message and prints it on the screen
+// in a human readable format.
+//
+void displayModesMessage(struct modesMessage *mm) {
+    int j;
+    unsigned char * pTimeStamp;
+
+    // Handle only addresses mode first.
+    if (Modes.onlyaddr) {
+        printf("%06x\n", mm->addr);
+        return;         // Enough for --onlyaddr mode
+    }
+
+    // Show the raw message.
+    if (Modes.mlat && mm->timestampMsg) {
+        printf("@");
+        pTimeStamp = (unsigned char *) &mm->timestampMsg;
+        for (j=5; j>=0;j--) {
+            printf("%02X",pTimeStamp[j]);
+        } 
+    } else
+        printf("*");
+
+    for (j = 0; j < mm->msgbits/8; j++) printf("%02x", mm->msg[j]);
+    printf(";\n");
+
+    if (Modes.raw) {
+        fflush(stdout); // Provide data to the reader ASAP
+        return;         // Enough for --raw mode
+    }
+
+    if (mm->msgtype < 32)
+        printf("CRC: %06x (%s)\n", (int)mm->crc, mm->crcok ? "ok" : "wrong");
+
+    if (mm->correctedbits != 0)
+        printf("No. of bit errors fixed: %d\n", mm->correctedbits);
+
+    if (mm->msgtype == 0) { // DF 0
+        printf("DF 0: Short Air-Air Surveillance.\n");
+        printf("  VS             : %s\n",  (mm->msg[0] & 0x04) ? "Ground" : "Airborne");
+        printf("  CC             : %d\n", ((mm->msg[0] & 0x02) >> 1));
+        printf("  SL             : %d\n", ((mm->msg[1] & 0xE0) >> 5));
+        printf("  Altitude       : %d %s\n", mm->altitude,
+            (mm->unit == MODES_UNIT_METERS) ? "meters" : "feet");
+        printf("  ICAO Address   : %06x\n", mm->addr);
+
+    } else if (mm->msgtype == 4 || mm->msgtype == 20) {
+        printf("DF %d: %s, Altitude Reply.\n", mm->msgtype,
+            (mm->msgtype == 4) ? "Surveillance" : "Comm-B");
+        printf("  Flight Status  : %s\n", fs_str[mm->fs]);
+        printf("  DR             : %d\n", ((mm->msg[1] >> 3) & 0x1F));
+        printf("  UM             : %d\n", (((mm->msg[1]  & 7) << 3) | (mm->msg[2] >> 5)));
+        printf("  Altitude       : %d %s\n", mm->altitude,
+            (mm->unit == MODES_UNIT_METERS) ? "meters" : "feet");
+        printf("  ICAO Address   : %06x\n", mm->addr);
+
+        if (mm->msgtype == 20) {
+            printf("  Comm-B BDS     : %x\n", mm->msg[4]);
+
+            // Decode the extended squitter message
+            if        ( mm->msg[4]       == 0x20) { // BDS 2,0 Aircraft identification
+                printf("    BDS 2,0 Aircraft Identification : %s\n", mm->flight);
+/*
+            } else if ( mm->msg[4]       == 0x10) { // BDS 1,0 Datalink Capability report
+                printf("    BDS 1,0 Datalink Capability report\n");
+
+            } else if ( mm->msg[4]       == 0x30) { // BDS 3,0 ACAS Active Resolution Advisory
+                printf("    BDS 3,0 ACAS Active Resolution Advisory\n");
+
+            } else if ((mm->msg[4] >> 3) ==   28) { // BDS 6,1 Extended Squitter Emergency/Priority Status
+                printf("    BDS 6,1 Emergency/Priority Status\n");
+
+            } else if ((mm->msg[4] >> 3) ==   29) { // BDS 6,2 Target State and Status
+                printf("    BDS 6,2 Target State and Status\n");
+
+            } else if ((mm->msg[4] >> 3) ==   31) { // BDS 6,5 Extended Squitter Aircraft Operational Status
+                printf("    BDS 6,5 Aircraft Operational Status\n");
+*/
+            }        
+        }
+
+    } else if (mm->msgtype == 5 || mm->msgtype == 21) {
+        printf("DF %d: %s, Identity Reply.\n", mm->msgtype,
+            (mm->msgtype == 5) ? "Surveillance" : "Comm-B");
+        printf("  Flight Status  : %s\n", fs_str[mm->fs]);
+        printf("  DR             : %d\n", ((mm->msg[1] >> 3) & 0x1F));
+        printf("  UM             : %d\n", (((mm->msg[1]  & 7) << 3) | (mm->msg[2] >> 5)));
+        printf("  Squawk         : %04x\n", mm->modeA);
+        printf("  ICAO Address   : %06x\n", mm->addr);
+
+        if (mm->msgtype == 21) {
+            printf("  Comm-B BDS     : %x\n", mm->msg[4]);
+
+            // Decode the extended squitter message
+            if        ( mm->msg[4]       == 0x20) { // BDS 2,0 Aircraft identification
+                printf("    BDS 2,0 Aircraft Identification : %s\n", mm->flight);
+/*
+            } else if ( mm->msg[4]       == 0x10) { // BDS 1,0 Datalink Capability report
+                printf("    BDS 1,0 Datalink Capability report\n");
+
+            } else if ( mm->msg[4]       == 0x30) { // BDS 3,0 ACAS Active Resolution Advisory
+                printf("    BDS 3,0 ACAS Active Resolution Advisory\n");
+
+            } else if ((mm->msg[4] >> 3) ==   28) { // BDS 6,1 Extended Squitter Emergency/Priority Status
+                printf("    BDS 6,1 Emergency/Priority Status\n");
+
+            } else if ((mm->msg[4] >> 3) ==   29) { // BDS 6,2 Target State and Status
+                printf("    BDS 6,2 Target State and Status\n");
+
+            } else if ((mm->msg[4] >> 3) ==   31) { // BDS 6,5 Extended Squitter Aircraft Operational Status
+                printf("    BDS 6,5 Aircraft Operational Status\n");
+*/
+            }        
+        }
+
+    } else if (mm->msgtype == 11) { // DF 11
+        printf("DF 11: All Call Reply.\n");
+        printf("  Capability  : %d (%s)\n", mm->ca, ca_str[mm->ca]);
+        printf("  ICAO Address: %06x\n", mm->addr);
+        if (mm->iid > 16)
+            {printf("  IID         : SI-%02d\n", mm->iid-16);}
+        else
+            {printf("  IID         : II-%02d\n", mm->iid);}
+
+    } else if (mm->msgtype == 16) { // DF 16
+        printf("DF 16: Long Air to Air ACAS\n");
+        printf("  VS             : %s\n",  (mm->msg[0] & 0x04) ? "Ground" : "Airborne");
+        printf("  CC             : %d\n", ((mm->msg[0] & 0x02) >> 1));
+        printf("  SL             : %d\n", ((mm->msg[1] & 0xE0) >> 5));
+        printf("  Altitude       : %d %s\n", mm->altitude,
+            (mm->unit == MODES_UNIT_METERS) ? "meters" : "feet");
+        printf("  ICAO Address   : %06x\n", mm->addr);
+
+    } else if (mm->msgtype == 17) { // DF 17
+        printf("DF 17: ADS-B message.\n");
+        printf("  Capability     : %d (%s)\n", mm->ca, ca_str[mm->ca]);
+        printf("  ICAO Address   : %06x\n", mm->addr);
+        printf("  Extended Squitter  Type: %d\n", mm->metype);
+        printf("  Extended Squitter  Sub : %d\n", mm->mesub);
+        printf("  Extended Squitter  Name: %s\n", getMEDescription(mm->metype, mm->mesub));
+
+        // Decode the extended squitter message
+        if (mm->metype >= 1 && mm->metype <= 4) { // Aircraft identification
+            printf("    Aircraft Type  : %c%d\n", ('A' + 4 - mm->metype), mm->mesub);
+            printf("    Identification : %s\n", mm->flight);
+
+        } else if (mm->metype == 19) { // Airborne Velocity
+            if (mm->mesub == 1 || mm->mesub == 2) {
+                printf("    EW status         : %s\n", (mm->bFlags & MODES_ACFLAGS_EWSPEED_VALID)  ? "Valid" : "Unavailable");
+                printf("    EW velocity       : %d\n", mm->ew_velocity);
+                printf("    NS status         : %s\n", (mm->bFlags & MODES_ACFLAGS_NSSPEED_VALID)  ? "Valid" : "Unavailable");
+                printf("    NS velocity       : %d\n", mm->ns_velocity);
+                printf("    Vertical status   : %s\n", (mm->bFlags & MODES_ACFLAGS_VERTRATE_VALID) ? "Valid" : "Unavailable");
+                printf("    Vertical rate src : %d\n", ((mm->msg[8] >> 4) & 1));
+                printf("    Vertical rate     : %d\n", mm->vert_rate);
+
+            } else if (mm->mesub == 3 || mm->mesub == 4) {
+                printf("    Heading status    : %s\n", (mm->bFlags & MODES_ACFLAGS_HEADING_VALID)  ? "Valid" : "Unavailable");
+                printf("    Heading           : %d\n", mm->heading);
+                printf("    Airspeed status   : %s\n", (mm->bFlags & MODES_ACFLAGS_SPEED_VALID)    ? "Valid" : "Unavailable");
+                printf("    Airspeed          : %d\n", mm->velocity);
+                printf("    Vertical status   : %s\n", (mm->bFlags & MODES_ACFLAGS_VERTRATE_VALID) ? "Valid" : "Unavailable");
+                printf("    Vertical rate src : %d\n", ((mm->msg[8] >> 4) & 1));
+                printf("    Vertical rate     : %d\n", mm->vert_rate);
+
+            } else {
+                printf("    Unrecognized ME subtype: %d subtype: %d\n", mm->metype, mm->mesub);
+            }
+
+        } else if (mm->metype >= 5 && mm->metype <= 22) { // Airborne position Baro
+            printf("    F flag   : %s\n", (mm->msg[6] & 0x04) ? "odd" : "even");
+            printf("    T flag   : %s\n", (mm->msg[6] & 0x08) ? "UTC" : "non-UTC");
+            printf("    Altitude : %d feet\n", mm->altitude);
+            if (mm->bFlags & MODES_ACFLAGS_LATLON_VALID) {
+                printf("    Latitude : %f\n", mm->fLat);
+                printf("    Longitude: %f\n", mm->fLon);
+            } else {
+                printf("    Latitude : %d (not decoded)\n", mm->raw_latitude);
+                printf("    Longitude: %d (not decoded)\n", mm->raw_longitude);
+            }
+
+        } else if (mm->metype == 28) { // Extended Squitter Aircraft Status
+            if (mm->mesub == 1) {
+				printf("    Emergency State: %s\n", es_str[(mm->msg[5] & 0xE0) >> 5]);
+				printf("    Squawk: %04x\n", mm->modeA);
+            } else {
+                printf("    Unrecognized ME subtype: %d subtype: %d\n", mm->metype, mm->mesub);
+            }
+
+        } else if (mm->metype == 23) { // Test Message
+			if (mm->mesub == 7) {
+				printf("    Squawk: %04x\n", mm->modeA);
+            } else {
+                printf("    Unrecognized ME subtype: %d subtype: %d\n", mm->metype, mm->mesub);
+			}
+        } else {
+            printf("    Unrecognized ME type: %d subtype: %d\n", mm->metype, mm->mesub);
+        }
+
+    } else if (mm->msgtype == 18) { // DF 18 
+        printf("DF 18: Extended Squitter.\n");
+        printf("  Control Field : %d (%s)\n", mm->ca, cf_str[mm->ca]);
+        if ((mm->ca == 0) || (mm->ca == 1) || (mm->ca == 6)) {
+            if (mm->ca == 1) {
+                printf("  Other Address : %06x\n", mm->addr);
+            } else {
+                printf("  ICAO Address  : %06x\n", mm->addr);
+            }
+            printf("  Extended Squitter  Type: %d\n", mm->metype);
+            printf("  Extended Squitter  Sub : %d\n", mm->mesub);
+            printf("  Extended Squitter  Name: %s\n", getMEDescription(mm->metype, mm->mesub));
+
+            // Decode the extended squitter message
+            if (mm->metype >= 1 && mm->metype <= 4) { // Aircraft identification
+                printf("    Aircraft Type  : %c%d\n", ('A' + 4 - mm->metype), mm->mesub);
+                printf("    Identification : %s\n", mm->flight);
+
+            } else if (mm->metype == 19) { // Airborne Velocity
+                if (mm->mesub == 1 || mm->mesub == 2) {
+                    printf("    EW status         : %s\n", (mm->bFlags & MODES_ACFLAGS_EWSPEED_VALID)  ? "Valid" : "Unavailable");
+                    printf("    EW velocity       : %d\n", mm->ew_velocity);
+                    printf("    NS status         : %s\n", (mm->bFlags & MODES_ACFLAGS_NSSPEED_VALID)  ? "Valid" : "Unavailable");
+                    printf("    NS velocity       : %d\n", mm->ns_velocity);
+                    printf("    Vertical status   : %s\n", (mm->bFlags & MODES_ACFLAGS_VERTRATE_VALID) ? "Valid" : "Unavailable");
+                    printf("    Vertical rate src : %d\n", ((mm->msg[8] >> 4) & 1));
+                    printf("    Vertical rate     : %d\n", mm->vert_rate);
+
+                } else if (mm->mesub == 3 || mm->mesub == 4) {
+                    printf("    Heading status    : %s\n", (mm->bFlags & MODES_ACFLAGS_HEADING_VALID)  ? "Valid" : "Unavailable");
+                    printf("    Heading           : %d\n", mm->heading);
+                    printf("    Airspeed status   : %s\n", (mm->bFlags & MODES_ACFLAGS_SPEED_VALID)    ? "Valid" : "Unavailable");
+                    printf("    Airspeed          : %d\n", mm->velocity);
+                    printf("    Vertical status   : %s\n", (mm->bFlags & MODES_ACFLAGS_VERTRATE_VALID) ? "Valid" : "Unavailable");
+                    printf("    Vertical rate src : %d\n", ((mm->msg[8] >> 4) & 1));
+                    printf("    Vertical rate     : %d\n", mm->vert_rate);
+
+                } else {
+                    printf("    Unrecognized ME subtype: %d subtype: %d\n", mm->metype, mm->mesub);
+                }
+
+            } else if (mm->metype >= 5 && mm->metype <= 22) { // Ground or Airborne position, Baro or GNSS
+                printf("    F flag   : %s\n", (mm->msg[6] & 0x04) ? "odd" : "even");
+                printf("    T flag   : %s\n", (mm->msg[6] & 0x08) ? "UTC" : "non-UTC");
+                printf("    Altitude : %d feet\n", mm->altitude);
+                if (mm->bFlags & MODES_ACFLAGS_LATLON_VALID) {
+                    printf("    Latitude : %f\n", mm->fLat);
+                    printf("    Longitude: %f\n", mm->fLon);
+                } else {
+                    printf("    Latitude : %d (not decoded)\n", mm->raw_latitude);
+                    printf("    Longitude: %d (not decoded)\n", mm->raw_longitude);
+                }
+
+            } else {
+                printf("    Unrecognized ME type: %d subtype: %d\n", mm->metype, mm->mesub);
+            }
+        }             
+
+    } else if (mm->msgtype == 19) { // DF 19
+        printf("DF 19: Military Extended Squitter.\n");
+
+    } else if (mm->msgtype == 22) { // DF 22
+        printf("DF 22: Military Use.\n");
+
+    } else if (mm->msgtype == 24) { // DF 24
+        printf("DF 24: Comm D Extended Length Message.\n");
+
+    } else if (mm->msgtype == 32) { // DF 32 is special code we use for Mode A/C
+        printf("SSR : Mode A/C Reply.\n");
+        if (mm->fs & 0x0080) {
+            printf("  Mode A : %04x IDENT\n", mm->modeA);
+        } else {
+            printf("  Mode A : %04x\n", mm->modeA);
+            if (mm->bFlags & MODES_ACFLAGS_ALTITUDE_VALID)
+                {printf("  Mode C : %d feet\n", mm->altitude);}
+        }
+
+    } else {
+        printf("DF %d: Unknown DF Format.\n", mm->msgtype);
+    }
+
+    printf("\n");
+}
+//
+//=========================================================================
+//
+// Turn I/Q samples pointed by Modes.data into the magnitude vector
+// pointed by Modes.magnitude.
+//
+void computeMagnitudeVector(uint16_t *p) {
+    uint16_t *m = &Modes.magnitude[MODES_PREAMBLE_SAMPLES+MODES_LONG_MSG_SAMPLES];
+    uint32_t j;
+
+    memcpy(Modes.magnitude,&Modes.magnitude[MODES_ASYNC_BUF_SAMPLES], MODES_PREAMBLE_SIZE+MODES_LONG_MSG_SIZE);
+
+    // Compute the magnitudo vector. It's just SQRT(I^2 + Q^2), but
+    // we rescale to the 0-255 range to exploit the full resolution.
+    for (j = 0; j < MODES_ASYNC_BUF_SAMPLES; j ++) {
+        *m++ = Modes.maglut[*p++];
+    }
+}
+//
+//=========================================================================
+//
+// Return -1 if the message is out of fase left-side
+// Return  1 if the message is out of fase right-size
+// Return  0 if the message is not particularly out of phase.
+//
+// Note: this function will access pPreamble[-1], so the caller should make sure to
+// call it only if we are not at the start of the current buffer
+//
+int detectOutOfPhase(uint16_t *pPreamble) {
+    if (pPreamble[ 3] > pPreamble[2]/3) return  1;
+    if (pPreamble[10] > pPreamble[9]/3) return  1;
+    if (pPreamble[ 6] > pPreamble[7]/3) return -1;
+    if (pPreamble[-1] > pPreamble[1]/3) return -1;
+    return 0;
+}
+//
+//=========================================================================
+//
+// This function does not really correct the phase of the message, it just
+// applies a transformation to the first sample representing a given bit:
+//
+// If the previous bit was one, we amplify it a bit.
+// If the previous bit was zero, we decrease it a bit.
+//
+// This simple transformation makes the message a bit more likely to be
+// correctly decoded for out of phase messages:
+//
+// When messages are out of phase there is more uncertainty in
+// sequences of the same bit multiple times, since 11111 will be
+// transmitted as continuously altering magnitude (high, low, high, low...)
+// 
+// However because the message is out of phase some part of the high
+// is mixed in the low part, so that it is hard to distinguish if it is
+// a zero or a one.
+//
+// However when the message is out of phase passing from 0 to 1 or from
+// 1 to 0 happens in a very recognizable way, for instance in the 0 -> 1
+// transition, magnitude goes low, high, high, low, and one of of the
+// two middle samples the high will be *very* high as part of the previous
+// or next high signal will be mixed there.
+//
+// Applying our simple transformation we make more likely if the current
+// bit is a zero, to detect another zero. Symmetrically if it is a one
+// it will be more likely to detect a one because of the transformation.
+// In this way similar levels will be interpreted more likely in the
+// correct way.
+//
+void applyPhaseCorrection(uint16_t *pPayload) {
+    int j;
+
+    for (j = 0; j < MODES_LONG_MSG_SAMPLES; j += 2, pPayload += 2) {
+        if (pPayload[0] > pPayload[1]) { // One
+            pPayload[2] = (pPayload[2] * 5) / 4;
+        } else {                         // Zero
+            pPayload[2] = (pPayload[2] * 4) / 5;
+        }
+    }
+}
+//
+//=========================================================================
+//
+// Detect a Mode S messages inside the magnitude buffer pointed by 'm' and of
+// size 'mlen' bytes. Every detected Mode S message is convert it into a
+// stream of bits and passed to the function to display it.
+//
+void detectModeS(uint16_t *m, uint32_t mlen) {
+    struct modesMessage mm;
+    unsigned char msg[MODES_LONG_MSG_BYTES], *pMsg;
+    uint16_t aux[MODES_LONG_MSG_SAMPLES];
+    uint32_t j;
+    int use_correction = 0;
+
+    memset(&mm, 0, sizeof(mm));
+
+    // The Mode S preamble is made of impulses of 0.5 microseconds at
+    // the following time offsets:
+    //
+    // 0   - 0.5 usec: first impulse.
+    // 1.0 - 1.5 usec: second impulse.
+    // 3.5 - 4   usec: third impulse.
+    // 4.5 - 5   usec: last impulse.
+    // 
+    // Since we are sampling at 2 Mhz every sample in our magnitude vector
+    // is 0.5 usec, so the preamble will look like this, assuming there is
+    // an impulse at offset 0 in the array:
+    //
+    // 0   -----------------
+    // 1   -
+    // 2   ------------------
+    // 3   --
+    // 4   -
+    // 5   --
+    // 6   -
+    // 7   ------------------
+    // 8   --
+    // 9   -------------------
+    //
+    for (j = 0; j < mlen; j++) {
+        int high, i, errors, errors56, errorsTy; 
+        uint16_t *pPreamble, *pPayload, *pPtr;
+        uint8_t  theByte, theErrs;
+        int msglen, scanlen, sigStrength;
+
+        pPreamble = &m[j];
+        pPayload  = &m[j+MODES_PREAMBLE_SAMPLES];
+
+        // Rather than clear the whole mm structure, just clear the parts which are required. The clear
+        // is required for every bit of the input stream, and we don't want to be memset-ing the whole
+        // modesMessage structure two million times per second if we don't have to..
+        mm.bFlags          =
+        mm.crcok           = 
+        mm.correctedbits   = 0;
+
+        if (!use_correction)  // This is not a re-try with phase correction
+            {                 // so try to find a new preamble
+
+            if (Modes.mode_ac) 
+                {
+                int ModeA = detectModeA(pPreamble, &mm);
+
+                if (ModeA) // We have found a valid ModeA/C in the data                    
+                    {
+                    mm.timestampMsg = Modes.timestampBlk + ((j+1) * 6);
+
+                    // Decode the received message
+                    decodeModeAMessage(&mm, ModeA);
+
+                    // Pass data to the next layer
+                    useModesMessage(&mm);
+
+                    j += MODEAC_MSG_SAMPLES;
+                    Modes.stat_ModeAC++;
+                    continue;
+                    }
+                }
+
+            // First check of relations between the first 10 samples
+            // representing a valid preamble. We don't even investigate further
+            // if this simple test is not passed
+            if (!(pPreamble[0] > pPreamble[1] &&
+                  pPreamble[1] < pPreamble[2] &&
+                  pPreamble[2] > pPreamble[3] &&
+                  pPreamble[3] < pPreamble[0] &&
+                  pPreamble[4] < pPreamble[0] &&
+                  pPreamble[5] < pPreamble[0] &&
+                  pPreamble[6] < pPreamble[0] &&
+                  pPreamble[7] > pPreamble[8] &&
+                  pPreamble[8] < pPreamble[9] &&
+                  pPreamble[9] > pPreamble[6]))
+            {
+                if (Modes.debug & MODES_DEBUG_NOPREAMBLE &&
+                    *pPreamble  > MODES_DEBUG_NOPREAMBLE_LEVEL)
+                    dumpRawMessage("Unexpected ratio among first 10 samples", msg, m, j);
+                continue;
+            }
+
+            // The samples between the two spikes must be < than the average
+            // of the high spikes level. We don't test bits too near to
+            // the high levels as signals can be out of phase so part of the
+            // energy can be in the near samples
+            high = (pPreamble[0] + pPreamble[2] + pPreamble[7] + pPreamble[9]) / 6;
+            if (pPreamble[4] >= high ||
+                pPreamble[5] >= high)
+            {
+                if (Modes.debug & MODES_DEBUG_NOPREAMBLE &&
+                    *pPreamble  > MODES_DEBUG_NOPREAMBLE_LEVEL)
+                    dumpRawMessage("Too high level in samples between 3 and 6", msg, m, j);
+                continue;
+            }
+
+            // Similarly samples in the range 11-14 must be low, as it is the
+            // space between the preamble and real data. Again we don't test
+            // bits too near to high levels, see above
+            if (pPreamble[11] >= high ||
+                pPreamble[12] >= high ||
+                pPreamble[13] >= high ||
+                pPreamble[14] >= high)
+            {
+                if (Modes.debug & MODES_DEBUG_NOPREAMBLE &&
+                    *pPreamble  > MODES_DEBUG_NOPREAMBLE_LEVEL)
+                    dumpRawMessage("Too high level in samples between 10 and 15", msg, m, j);
+                continue;
+            }
+            Modes.stat_valid_preamble++;
+        } 
+
+        else {
+            // If the previous attempt with this message failed, retry using
+            // magnitude correction
+            // Make a copy of the Payload, and phase correct the copy
+            memcpy(aux, pPayload, sizeof(aux));
+            applyPhaseCorrection(aux);
+            Modes.stat_out_of_phase++;
+            pPayload = aux;
+            // TODO ... apply other kind of corrections
+            }
+
+        // Decode all the next 112 bits, regardless of the actual message
+        // size. We'll check the actual message type later
+        pMsg    = &msg[0];
+        pPtr    = pPayload;
+        theByte = 0;
+        theErrs = 0; errorsTy = 0;
+        errors  = 0; errors56 = 0;
+
+        // We should have 4 'bits' of 0/1 and 1/0 samples in the preamble, 
+        // so include these in the signal strength 
+        sigStrength = (pPreamble[0]-pPreamble[1])
+                    + (pPreamble[2]-pPreamble[3])
+                    + (pPreamble[7]-pPreamble[6])
+                    + (pPreamble[9]-pPreamble[8]);
+
+        msglen = scanlen = MODES_LONG_MSG_BITS;
+        for (i = 0; i < scanlen; i++) {
+            uint32_t a = *pPtr++;
+            uint32_t b = *pPtr++;
+
+            if      (a > b) 
+                {theByte |= 1; if (i < 56) {sigStrength += (a-b);}} 
+            else if (a < b) 
+                {/*theByte |= 0;*/ if (i < 56) {sigStrength += (b-a);}} 
+            else if (i >= MODES_SHORT_MSG_BITS) //(a == b), and we're in the long part of a frame
+                {errors++;  /*theByte |= 0;*/} 
+            else if (i >= 5)                    //(a == b), and we're in the short part of a frame
+                {scanlen = MODES_LONG_MSG_BITS; errors56 = ++errors;/*theByte |= 0;*/}            
+            else if (i)                         //(a == b), and we're in the message type part of a frame
+                {errorsTy = errors56 = ++errors; theErrs |= 1; /*theByte |= 0;*/} 
+            else                                //(a == b), and we're in the first bit of the message type part of a frame
+                {errorsTy = errors56 = ++errors; theErrs |= 1; theByte |= 1;} 
+
+            if ((i & 7) == 7) 
+              {*pMsg++ = theByte;}
+            else if (i == 4) {
+              msglen  = modesMessageLenByType(theByte);
+              if (errors == 0)
+                  {scanlen = msglen;}
+            }
+
+            theByte = theByte << 1;
+            if (i < 7)
+              {theErrs = theErrs << 1;}
+
+            // If we've exceeded the permissible number of encoding errors, abandon ship now
+            if (errors > MODES_MSG_ENCODER_ERRS) {
+
+                if        (i < MODES_SHORT_MSG_BITS) {
+                    msglen = 0;
+
+                } else if ((errorsTy == 1) && (theErrs == 0x80)) {
+                    // If we only saw one error in the first bit of the byte of the frame, then it's possible 
+                    // we guessed wrongly about the value of the bit. We may be able to correct it by guessing
+                    // the other way.
+                    //
+                    // We guessed a '1' at bit 7, which is the DF length bit == 112 Bits.
+                    // Inverting bit 7 will change the message type from a long to a short. 
+                    // Invert the bit, cross your fingers and carry on.
+                    msglen  = MODES_SHORT_MSG_BITS;
+                    msg[0] ^= theErrs; errorsTy = 0;
+                    errors  = errors56; // revert to the number of errors prior to bit 56
+                    Modes.stat_DF_Len_Corrected++;
+
+                } else if (i < MODES_LONG_MSG_BITS) {
+                    msglen = MODES_SHORT_MSG_BITS;
+                    errors = errors56;
+
+                } else {
+                    msglen = MODES_LONG_MSG_BITS;
+                }
+
+            break;
+            }
+        }
+
+        // Ensure msglen is consistent with the DF type
+        i = modesMessageLenByType(msg[0] >> 3);
+        if      (msglen > i) {msglen = i;}
+        else if (msglen < i) {msglen = 0;}
+
+        //
+        // If we guessed at any of the bits in the DF type field, then look to see if our guess was sensible.
+        // Do this by looking to see if the original guess results in the DF type being one of the ICAO defined
+        // message types. If it isn't then toggle the guessed bit and see if this new value is ICAO defined.
+        // if the new value is ICAO defined, then update it in our message.
+        if ((msglen) && (errorsTy == 1) && (theErrs & 0x78)) {
+            // We guessed at one (and only one) of the message type bits. See if our guess is "likely" 
+            // to be correct by comparing the DF against a list of known good DF's
+            int      thisDF      = ((theByte = msg[0]) >> 3) & 0x1f;
+            uint32_t validDFbits = 0x017F0831;   // One bit per 32 possible DF's. Set bits 0,4,5,11,16.17.18.19,20,21,22,24
+            uint32_t thisDFbit   = (1 << thisDF);
+            if (0 == (validDFbits & thisDFbit)) {
+                // The current DF is not ICAO defined, so is probably an errors. 
+                // Toggle the bit we guessed at and see if the resultant DF is more likely
+                theByte  ^= theErrs;
+                thisDF    = (theByte >> 3) & 0x1f;
+                thisDFbit = (1 << thisDF);
+                // if this DF any more likely?
+                if (validDFbits & thisDFbit) {
+                    // Yep, more likely, so update the main message 
+                    msg[0] = theByte;
+                    Modes.stat_DF_Type_Corrected++;
+                    errors--; // decrease the error count so we attempt to use the modified DF.
+                }
+            }
+        }
+
+        // We measured signal strength over the first 56 bits. Don't forget to add 4 
+        // for the preamble samples, so round up and divide by 60.
+        sigStrength = (sigStrength + 29) / 60;
+
+        // When we reach this point, if error is small, and the signal strength is large enough
+        // we may have a Mode S message on our hands. It may still be broken and the CRC may not 
+        // be correct, but this can be handled by the next layer.
+        if ( (msglen) 
+          && (sigStrength >  MODES_MSG_SQUELCH_LEVEL) 
+          && (errors      <= MODES_MSG_ENCODER_ERRS) ) {
+
+            // Set initial mm structure details
+            mm.timestampMsg = Modes.timestampBlk + (j*6);
+            sigStrength    = (sigStrength + 0x7F) >> 8;
+            mm.signalLevel = ((sigStrength < 255) ? sigStrength : 255);
+            mm.phase_corrected = use_correction;
+
+            // Decode the received message
+            decodeModesMessage(&mm, msg);
+
+            // Update statistics
+            if (Modes.stats) {
+                if (mm.crcok || use_correction || mm.correctedbits) {
+
+                    if (use_correction) {
+                        switch (errors) {
+                            case 0: {Modes.stat_ph_demodulated0++; break;}
+                            case 1: {Modes.stat_ph_demodulated1++; break;}
+                            case 2: {Modes.stat_ph_demodulated2++; break;}
+                            default:{Modes.stat_ph_demodulated3++; break;}
+                        }
+                    } else {
+                        switch (errors) {
+                            case 0: {Modes.stat_demodulated0++; break;}
+                            case 1: {Modes.stat_demodulated1++; break;}
+                            case 2: {Modes.stat_demodulated2++; break;}
+                            default:{Modes.stat_demodulated3++; break;}
+                        }
+                    }
+
+                    if (mm.correctedbits == 0) {
+                        if (use_correction) {
+                            if (mm.crcok) {Modes.stat_ph_goodcrc++;}
+                            else          {Modes.stat_ph_badcrc++;}
+                        } else {
+                            if (mm.crcok) {Modes.stat_goodcrc++;}
+                            else          {Modes.stat_badcrc++;}
+                        }
+
+                    } else if (use_correction) {
+                        Modes.stat_ph_badcrc++;
+                        Modes.stat_ph_fixed++;
+                        if ( (mm.correctedbits) 
+                          && (mm.correctedbits <= MODES_MAX_BITERRORS) ) {
+                            Modes.stat_ph_bit_fix[mm.correctedbits-1] += 1;
+                        }
+
+                    } else {
+                        Modes.stat_badcrc++;
+                        Modes.stat_fixed++;
+                        if ( (mm.correctedbits) 
+                          && (mm.correctedbits <= MODES_MAX_BITERRORS) ) {
+                            Modes.stat_bit_fix[mm.correctedbits-1] += 1;
+                        }
+                    }
+                }
+            }
+
+            // Output debug mode info if needed
+            if (use_correction) {
+                if (Modes.debug & MODES_DEBUG_DEMOD)
+                    dumpRawMessage("Demodulated with 0 errors", msg, m, j);
+                else if (Modes.debug & MODES_DEBUG_BADCRC &&
+                         mm.msgtype == 17 &&
+                         (!mm.crcok || mm.correctedbits != 0))
+                    dumpRawMessage("Decoded with bad CRC", msg, m, j);
+                else if (Modes.debug & MODES_DEBUG_GOODCRC && mm.crcok &&
+                         mm.correctedbits == 0)
+                    dumpRawMessage("Decoded with good CRC", msg, m, j);
+            }
+
+            // Skip this message if we are sure it's fine
+            if (mm.crcok) {
+                j += (MODES_PREAMBLE_US+msglen)*2 - 1;
+            }
+
+            // Pass data to the next layer
+            useModesMessage(&mm);
+
+        } else {
+            if (Modes.debug & MODES_DEBUG_DEMODERR && use_correction) {
+                printf("The following message has %d demod errors\n", errors);
+                dumpRawMessage("Demodulated with errors", msg, m, j);
+            }
+        }
+
+        // Retry with phase correction if enabled, necessary and possible.
+        if (Modes.phase_enhance && !mm.crcok && !mm.correctedbits && !use_correction && j && detectOutOfPhase(pPreamble)) {
+            use_correction = 1; j--;
+        } else {
+            use_correction = 0; 
+        }
+    }
+
+    //Send any remaining partial raw buffers now
+    if (Modes.rawOutUsed || Modes.beastOutUsed)
+      {
+      Modes.net_output_raw_rate_count++;
+      if (Modes.net_output_raw_rate_count > Modes.net_output_raw_rate)
+        {
+        if (Modes.rawOutUsed) {
+            modesSendAllClients(Modes.ros, Modes.rawOut, Modes.rawOutUsed);
+            Modes.rawOutUsed = 0;
+        }
+        if (Modes.beastOutUsed) {
+            modesSendAllClients(Modes.bos, Modes.beastOut, Modes.beastOutUsed);
+            Modes.beastOutUsed = 0;
+        }
+        Modes.net_output_raw_rate_count = 0;
+        }
+      }
+    else if ( (Modes.net) 
+           && (Modes.net_heartbeat_rate) 
+           && ((++Modes.net_heartbeat_count) > Modes.net_heartbeat_rate) ) {
+      //
+      // We haven't received any Mode A/C/S messages for some time. To try and keep any TCP
+      // links alive, send a null frame. This will help stop any routers discarding our TCP 
+      // link which will cause an un-recoverable link error if/when a real frame arrives.   
+      //
+      // Fudge up a null message
+      memset(&mm, 0, sizeof(mm));
+      mm.msgbits      = MODES_SHORT_MSG_BITS;
+      mm.timestampMsg = Modes.timestampBlk;
+
+      // Feed output clients
+      modesQueueOutput(&mm);
+
+      // Reset the heartbeat counter
+      Modes.net_heartbeat_count = 0;
+      }
+}
+//
+//=========================================================================
+//
+// When a new message is available, because it was decoded from the RTL device, 
+// file, or received in the TCP input port, or any other way we can receive a 
+// decoded message, we call this function in order to use the message.
+//
+// Basically this function passes a raw message to the upper layers for further
+// processing and visualization
+//
+void useModesMessage(struct modesMessage *mm) {
+    if ((Modes.check_crc == 0) || (mm->crcok) || (mm->correctedbits)) { // not checking, ok or fixed
+
+        // Always track aircraft
+        interactiveReceiveData(mm);
+
+        // In non-interactive non-quiet mode, display messages on standard output
+        if (!Modes.interactive && !Modes.quiet) {
+            displayModesMessage(mm);
+        }
+
+        // Feed output clients
+        if (Modes.net) {modesQueueOutput(mm);}
+
+        // Heartbeat not required whilst we're seeing real messages
+        Modes.net_heartbeat_count = 0;
+    }
+}
+//
+//=========================================================================
+//
+// Always positive MOD operation, used for CPR decoding.
+//
+int cprModFunction(int a, int b) {
+    int res = a % b;
+    if (res < 0) res += b;
+    return res;
+}
+//
+//=========================================================================
+//
+// The NL function uses the precomputed table from 1090-WP-9-14
+//
+int cprNLFunction(double lat) {
+    if (lat < 0) lat = -lat; // Table is simmetric about the equator
+    if (lat < 10.47047130) return 59;
+    if (lat < 14.82817437) return 58;
+    if (lat < 18.18626357) return 57;
+    if (lat < 21.02939493) return 56;
+    if (lat < 23.54504487) return 55;
+    if (lat < 25.82924707) return 54;
+    if (lat < 27.93898710) return 53;
+    if (lat < 29.91135686) return 52;
+    if (lat < 31.77209708) return 51;
+    if (lat < 33.53993436) return 50;
+    if (lat < 35.22899598) return 49;
+    if (lat < 36.85025108) return 48;
+    if (lat < 38.41241892) return 47;
+    if (lat < 39.92256684) return 46;
+    if (lat < 41.38651832) return 45;
+    if (lat < 42.80914012) return 44;
+    if (lat < 44.19454951) return 43;
+    if (lat < 45.54626723) return 42;
+    if (lat < 46.86733252) return 41;
+    if (lat < 48.16039128) return 40;
+    if (lat < 49.42776439) return 39;
+    if (lat < 50.67150166) return 38;
+    if (lat < 51.89342469) return 37;
+    if (lat < 53.09516153) return 36;
+    if (lat < 54.27817472) return 35;
+    if (lat < 55.44378444) return 34;
+    if (lat < 56.59318756) return 33;
+    if (lat < 57.72747354) return 32;
+    if (lat < 58.84763776) return 31;
+    if (lat < 59.95459277) return 30;
+    if (lat < 61.04917774) return 29;
+    if (lat < 62.13216659) return 28;
+    if (lat < 63.20427479) return 27;
+    if (lat < 64.26616523) return 26;
+    if (lat < 65.31845310) return 25;
+    if (lat < 66.36171008) return 24;
+    if (lat < 67.39646774) return 23;
+    if (lat < 68.42322022) return 22;
+    if (lat < 69.44242631) return 21;
+    if (lat < 70.45451075) return 20;
+    if (lat < 71.45986473) return 19;
+    if (lat < 72.45884545) return 18;
+    if (lat < 73.45177442) return 17;
+    if (lat < 74.43893416) return 16;
+    if (lat < 75.42056257) return 15;
+    if (lat < 76.39684391) return 14;
+    if (lat < 77.36789461) return 13;
+    if (lat < 78.33374083) return 12;
+    if (lat < 79.29428225) return 11;
+    if (lat < 80.24923213) return 10;
+    if (lat < 81.19801349) return 9;
+    if (lat < 82.13956981) return 8;
+    if (lat < 83.07199445) return 7;
+    if (lat < 83.99173563) return 6;
+    if (lat < 84.89166191) return 5;
+    if (lat < 85.75541621) return 4;
+    if (lat < 86.53536998) return 3;
+    if (lat < 87.00000000) return 2;
+    else return 1;
+}
+//
+//=========================================================================
+//
+int cprNFunction(double lat, int fflag) {
+    int nl = cprNLFunction(lat) - (fflag ? 1 : 0);
+    if (nl < 1) nl = 1;
+    return nl;
+}
+//
+//=========================================================================
+//
+double cprDlonFunction(double lat, int fflag, int surface) {
+    return (surface ? 90.0 : 360.0) / cprNFunction(lat, fflag);
+}
+//
+//=========================================================================
+//
+// This algorithm comes from:
+// http://www.lll.lu/~edward/edward/adsb/DecodingADSBposition.html.
+//
+// A few remarks:
+// 1) 131072 is 2^17 since CPR latitude and longitude are encoded in 17 bits.
+//
+int decodeCPR(struct aircraft *a, int fflag, int surface) {
+    double AirDlat0 = (surface ? 90.0 : 360.0) / 60.0;
+    double AirDlat1 = (surface ? 90.0 : 360.0) / 59.0;
+    double lat0 = a->even_cprlat;
+    double lat1 = a->odd_cprlat;
+    double lon0 = a->even_cprlon;
+    double lon1 = a->odd_cprlon;
+
+    // Compute the Latitude Index "j"
+    int    j     = (int) floor(((59*lat0 - 60*lat1) / 131072) + 0.5);
+    double rlat0 = AirDlat0 * (cprModFunction(j,60) + lat0 / 131072);
+    double rlat1 = AirDlat1 * (cprModFunction(j,59) + lat1 / 131072);
+
+    time_t now = time(NULL);
+    double surface_rlat = MODES_USER_LATITUDE_DFLT;
+    double surface_rlon = MODES_USER_LONGITUDE_DFLT;
+
+    if (surface) {
+        // If we're on the ground, make sure we have a (likely) valid Lat/Lon
+        if ((a->bFlags & MODES_ACFLAGS_LATLON_VALID) && (((int)(now - a->seenLatLon)) < Modes.interactive_display_ttl)) {
+            surface_rlat = a->lat;
+            surface_rlon = a->lon;
+        } else if (Modes.bUserFlags & MODES_USER_LATLON_VALID) {
+            surface_rlat = Modes.fUserLat;
+            surface_rlon = Modes.fUserLon;
+        } else {
+            // No local reference, give up
+            return (-1);
+        }
+        rlat0 += floor(surface_rlat / 90.0) * 90.0;  // Move from 1st quadrant to our quadrant
+        rlat1 += floor(surface_rlat / 90.0) * 90.0;
+    } else {
+        if (rlat0 >= 270) rlat0 -= 360;
+        if (rlat1 >= 270) rlat1 -= 360;
+    }
+
+    // Check to see that the latitude is in range: -90 .. +90
+    if (rlat0 < -90 || rlat0 > 90 || rlat1 < -90 || rlat1 > 90)
+        return (-1);
+
+    // Check that both are in the same latitude zone, or abort.
+    if (cprNLFunction(rlat0) != cprNLFunction(rlat1))
+        return (-1);
+
+    // Compute ni and the Longitude Index "m"
+    if (fflag) { // Use odd packet.
+        int ni = cprNFunction(rlat1,1);
+        int m = (int) floor((((lon0 * (cprNLFunction(rlat1)-1)) -
+                              (lon1 * cprNLFunction(rlat1))) / 131072.0) + 0.5);
+        a->lon = cprDlonFunction(rlat1, 1, surface) * (cprModFunction(m, ni)+lon1/131072);
+        a->lat = rlat1;
+    } else {     // Use even packet.
+        int ni = cprNFunction(rlat0,0);
+        int m = (int) floor((((lon0 * (cprNLFunction(rlat0)-1)) -
+                              (lon1 * cprNLFunction(rlat0))) / 131072) + 0.5);
+        a->lon = cprDlonFunction(rlat0, 0, surface) * (cprModFunction(m, ni)+lon0/131072);
+        a->lat = rlat0;
+    }
+
+    if (surface) {
+        a->lon += floor(surface_rlon / 90.0) * 90.0;  // Move from 1st quadrant to our quadrant
+    } else if (a->lon > 180) {
+        a->lon -= 360;
+    }
+
+    a->seenLatLon      = a->seen;
+    a->timestampLatLon = a->timestamp;
+    a->bFlags         |= (MODES_ACFLAGS_LATLON_VALID | MODES_ACFLAGS_LATLON_REL_OK);
+
+    return 0;
+}
+//
+//=========================================================================
+//
+// This algorithm comes from:
+// 1090-WP29-07-Draft_CPR101 (which also defines decodeCPR() )
+//
+// There is an error in this document related to CPR relative decode.
+// Should use trunc() rather than the floor() function in Eq 38 and related for deltaZI.
+// floor() returns integer less than argument
+// trunc() returns integer closer to zero than argument.
+// Note:   text of document describes trunc() functionality for deltaZI calculation
+//         but the formulae use floor().
+//
+int decodeCPRrelative(struct aircraft *a, int fflag, int surface) {
+    double AirDlat;
+    double AirDlon;
+    double lat;
+    double lon;
+    double lonr, latr;
+    double rlon, rlat;
+    int j,m;
+
+    if (a->bFlags & MODES_ACFLAGS_LATLON_REL_OK) { // Ok to try aircraft relative first
+        latr = a->lat;
+        lonr = a->lon;
+    } else if (Modes.bUserFlags & MODES_USER_LATLON_VALID) { // Try ground station relative next
+        latr = Modes.fUserLat;
+        lonr = Modes.fUserLon;
+    } else {
+        return (-1); // Exit with error - can't do relative if we don't have ref.
+    }
+
+    if (fflag) { // odd
+        AirDlat = (surface ? 90.0 : 360.0) / 59.0;
+        lat = a->odd_cprlat;
+        lon = a->odd_cprlon;
+    } else {    // even
+        AirDlat = (surface ? 90.0 : 360.0) / 60.0;
+        lat = a->even_cprlat;
+        lon = a->even_cprlon;
+    }
+
+    // Compute the Latitude Index "j"
+    j = (int) (floor(latr/AirDlat) +
+               trunc(0.5 + cprModFunction((int)latr, (int)AirDlat)/AirDlat - lat/131072));
+    rlat = AirDlat * (j + lat/131072);
+    if (rlat >= 270) rlat -= 360;
+
+    // Check to see that the latitude is in range: -90 .. +90
+    if (rlat < -90 || rlat > 90) {
+        a->bFlags &= ~MODES_ACFLAGS_LATLON_REL_OK; // This will cause a quick exit next time if no global has been done
+        return (-1);                               // Time to give up - Latitude error
+    }
+
+    // Check to see that answer is reasonable - ie no more than 1/2 cell away 
+    if (fabs(rlat - a->lat) > (AirDlat/2)) {
+        a->bFlags &= ~MODES_ACFLAGS_LATLON_REL_OK; // This will cause a quick exit next time if no global has been done
+        return (-1);                               // Time to give up - Latitude error 
+    }
+
+    // Compute the Longitude Index "m"
+    AirDlon = cprDlonFunction(rlat, fflag, surface);
+    m = (int) (floor(lonr/AirDlon) +
+               trunc(0.5 + cprModFunction((int)lonr, (int)AirDlon)/AirDlon - lon/131072));
+    rlon = AirDlon * (m + lon/131072);
+    if (rlon > 180) rlon -= 360;
+
+    // Check to see that answer is reasonable - ie no more than 1/2 cell away
+    if (fabs(rlon - a->lon) > (AirDlon/2)) {
+        a->bFlags &= ~MODES_ACFLAGS_LATLON_REL_OK; // This will cause a quick exit next time if no global has been done
+        return (-1);                               // Time to give up - Longitude error
+    }
+
+    a->lat = rlat;
+    a->lon = rlon;
+
+    a->seenLatLon      = a->seen;
+    a->timestampLatLon = a->timestamp;
+    a->bFlags         |= (MODES_ACFLAGS_LATLON_VALID | MODES_ACFLAGS_LATLON_REL_OK);
+    return (0);
+}
+//
+// ===================== Mode S detection and decoding  ===================
+//
diff --git a/net_io.c b/net_io.c
new file mode 100644
index 0000000..f3a8397
--- /dev/null
+++ b/net_io.c
@@ -0,0 +1,971 @@
+// dump1090, a Mode S messages decoder for RTLSDR devices.
+//
+// Copyright (C) 2012 by Salvatore Sanfilippo <antirez at 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"
+//
+// ============================= Networking =============================
+//
+// Note: here we disregard any kind of good coding practice in favor of
+// extreme simplicity, that is:
+//
+// 1) We only rely on the kernel buffers for our I/O without any kind of
+//    user space buffering.
+// 2) We don't register any kind of event handler, from time to time a
+//    function gets called and we accept new connections. All the rest is
+//    handled via non-blocking I/O and manually polling clients to see if
+//    they have something new to share with us when reading is needed.
+//
+//=========================================================================
+//
+// Networking "stack" initialization
+//
+struct service {
+	char *descr;
+	int *socket;
+	int port;
+	int enabled;
+};
+
+struct service services[MODES_NET_SERVICES_NUM];
+
+void modesInitNet(void) {
+    int j;
+
+	struct service svc[MODES_NET_SERVICES_NUM] = {
+		{"Raw TCP output", &Modes.ros, Modes.net_output_raw_port, 1},
+		{"Raw TCP input", &Modes.ris, Modes.net_input_raw_port, 1},
+		{"Beast TCP output", &Modes.bos, Modes.net_output_beast_port, 1},
+		{"Beast TCP input", &Modes.bis, Modes.net_input_beast_port, 1},
+		{"HTTP server", &Modes.https, Modes.net_http_port, 1},
+		{"Basestation TCP output", &Modes.sbsos, Modes.net_output_sbs_port, 1}
+	};
+
+	memcpy(&services, &svc, sizeof(svc));//services = svc;
+
+    Modes.clients = 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
+
+    for (j = 0; j < MODES_NET_SERVICES_NUM; j++) {
+		services[j].enabled = (services[j].port != 0);
+		if (services[j].enabled) {
+			int s = anetTcpServer(Modes.aneterr, services[j].port, NULL);
+			if (s == -1) {
+				fprintf(stderr, "Error opening the listening port %d (%s): %s\n",
+					services[j].port, services[j].descr, Modes.aneterr);
+				exit(1);
+			}
+			anetNonBlock(Modes.aneterr, s);
+			*services[j].socket = s;
+		} else {
+			if (Modes.debug & MODES_DEBUG_NET) printf("%s port is disabled\n", services[j].descr);
+		}
+    }
+
+#ifndef _WIN32
+    signal(SIGPIPE, SIG_IGN);
+#endif
+}
+//
+//=========================================================================
+//
+// This function gets called from time to time when the decoding thread is
+// awakened by new data arriving. This usually happens a few times every second
+//
+struct client * modesAcceptClients(void) {
+    int fd, port;
+    unsigned int j;
+    struct client *c;
+
+    for (j = 0; j < MODES_NET_SERVICES_NUM; j++) {
+		if (services[j].enabled) {
+			fd = anetTcpAccept(Modes.aneterr, *services[j].socket, NULL, &port);
+			if (fd == -1) continue;
+
+			anetNonBlock(Modes.aneterr, fd);
+			c = (struct client *) malloc(sizeof(*c));
+			c->service    = *services[j].socket;
+			c->next       = Modes.clients;
+			c->fd         = fd;
+			c->buflen     = 0;
+			Modes.clients = c;
+			anetSetSendBuffer(Modes.aneterr,fd, (MODES_NET_SNDBUF_SIZE << Modes.net_sndbuf_size));
+
+			if (*services[j].socket == Modes.sbsos) Modes.stat_sbs_connections++;
+			if (*services[j].socket == Modes.ros)   Modes.stat_raw_connections++;
+			if (*services[j].socket == Modes.bos)   Modes.stat_beast_connections++;
+
+			j--; // Try again with the same listening port
+
+			if (Modes.debug & MODES_DEBUG_NET)
+				printf("Created new client %d\n", fd);
+		}
+    }
+    return Modes.clients;
+}
+//
+//=========================================================================
+//
+// On error free the client, collect the structure, adjust maxfd if needed.
+//
+void modesFreeClient(struct client *c) {
+
+    // Unhook this client from the linked list of clients
+    struct client *p = Modes.clients;
+    if (p) {
+        if (p == c) {
+            Modes.clients = c->next;
+        } else {
+            while ((p) && (p->next != c)) {
+                p = p->next;
+            }
+            if (p) {
+                p->next = c->next;
+            }
+        }
+    }
+
+    // It's now safe to remove this client
+    close(c->fd);
+    if (c->service == Modes.sbsos) {
+        if (Modes.stat_sbs_connections) Modes.stat_sbs_connections--;
+    } else if (c->service == Modes.ros) {
+        if (Modes.stat_raw_connections) Modes.stat_raw_connections--;
+    } else if (c->service == Modes.bos) {
+        if (Modes.stat_beast_connections) Modes.stat_beast_connections--;
+    }
+
+    if (Modes.debug & MODES_DEBUG_NET)
+        printf("Closing client %d\n", c->fd);
+
+    free(c);
+}
+//
+//=========================================================================
+//
+// Send the specified message to all clients listening for a given service
+//
+void modesSendAllClients(int service, void *msg, int len) {
+    struct client *c = Modes.clients;
+
+    while (c) {
+        // Read next before servicing client incase the service routine deletes the client! 
+        struct client *next = c->next;
+
+        if (c->service == service) {
+#ifndef _WIN32
+            int nwritten = write(c->fd, msg, len);
+#else
+            int nwritten = send(c->fd, msg, len, 0 );
+#endif
+            if (nwritten != len) {
+                modesFreeClient(c);
+            }
+        }
+        c = next;
+    }
+}
+//
+//=========================================================================
+//
+// Write raw output in Beast Binary format with Timestamp to TCP clients
+//
+void modesSendBeastOutput(struct modesMessage *mm) {
+    char *p = &Modes.beastOut[Modes.beastOutUsed];
+    int  msgLen = mm->msgbits / 8;
+    char * pTimeStamp;
+    char ch;
+    int  j;
+    int  iOutLen = msgLen + 9; // Escape, msgtype, timestamp, sigLevel, msg
+
+    *p++ = 0x1a;
+    if      (msgLen == MODES_SHORT_MSG_BYTES)
+      {*p++ = '2';}
+    else if (msgLen == MODES_LONG_MSG_BYTES)
+      {*p++ = '3';}
+    else if (msgLen == MODEAC_MSG_BYTES)
+      {*p++ = '1';}
+    else
+      {return;}
+
+    pTimeStamp = (char *) &mm->timestampMsg;
+    for (j = 5; j >= 0; j--) {
+        *p++ = (ch = pTimeStamp[j]);
+        if (0x1A == ch) {*p++ = ch; iOutLen++;}
+    }
+
+    *p++ = (ch = mm->signalLevel);
+    if (0x1A == ch) {*p++ = ch; iOutLen++;}
+
+    for (j = 0; j < msgLen; j++) {
+        *p++ = (ch = mm->msg[j]);
+        if (0x1A == ch) {*p++ = ch; iOutLen++;} 
+    }
+
+    Modes.beastOutUsed +=  iOutLen;
+    if (Modes.beastOutUsed >= Modes.net_output_raw_size)
+      {
+      modesSendAllClients(Modes.bos, Modes.beastOut, Modes.beastOutUsed);
+      Modes.beastOutUsed = 0;
+      Modes.net_output_raw_rate_count = 0;
+      }
+}
+//
+//=========================================================================
+//
+// Write raw output to TCP clients
+//
+void modesSendRawOutput(struct modesMessage *mm) {
+    char *p = &Modes.rawOut[Modes.rawOutUsed];
+    int  msgLen = mm->msgbits / 8;
+    int j;
+    unsigned char * pTimeStamp;
+
+    if (Modes.mlat && mm->timestampMsg) {
+        *p++ = '@';
+        pTimeStamp = (unsigned char *) &mm->timestampMsg;
+        for (j = 5; j >= 0; j--) {
+            sprintf(p, "%02X", pTimeStamp[j]);
+            p += 2;
+        }
+        Modes.rawOutUsed += 12; // additional 12 characters for timestamp
+    } else
+        *p++ = '*';
+
+    for (j = 0; j < msgLen; j++) {
+        sprintf(p, "%02X", mm->msg[j]);
+        p += 2;
+    }
+
+    *p++ = ';';
+    *p++ = '\n';
+
+    Modes.rawOutUsed += ((msgLen*2) + 3);
+    if (Modes.rawOutUsed >= Modes.net_output_raw_size)
+      {
+      modesSendAllClients(Modes.ros, Modes.rawOut, Modes.rawOutUsed);
+      Modes.rawOutUsed = 0;
+      Modes.net_output_raw_rate_count = 0;
+      }
+}
+//
+//=========================================================================
+//
+// Write SBS output to TCP clients
+// The message structure mm->bFlags tells us what has been updated by this message
+//
+void modesSendSBSOutput(struct modesMessage *mm) {
+    char msg[256], *p = msg;
+    uint32_t     offset;
+    struct timeb epocTime_receive, epocTime_now;
+    struct tm    stTime_receive, stTime_now;
+    int          msgType;
+
+    //
+    // SBS BS style output checked against the following reference
+    // http://www.homepages.mcb.net/bones/SBS/Article/Barebones42_Socket_Data.htm - seems comprehensive
+    //
+
+    // Decide on the basic SBS Message Type
+    if        ((mm->msgtype ==  4) || (mm->msgtype == 20)) {
+        msgType = 5;
+    } else if ((mm->msgtype ==  5) || (mm->msgtype == 21)) {
+        msgType = 6;
+    } else if ((mm->msgtype ==  0) || (mm->msgtype == 16)) {
+        msgType = 7;
+    } else if  (mm->msgtype == 11) {
+        msgType = 8;
+    } else if ((mm->msgtype != 17) && (mm->msgtype != 18)) {
+        return;
+    } else if ((mm->metype >= 1) && (mm->metype <=  4)) {
+        msgType = 1;
+    } else if ((mm->metype >= 5) && (mm->metype <=  8)) {
+        if (mm->bFlags & MODES_ACFLAGS_LATLON_VALID)
+            {msgType = 2;}
+        else
+            {msgType = 7;}
+    } else if ((mm->metype >= 9) && (mm->metype <= 18)) {
+        if (mm->bFlags & MODES_ACFLAGS_LATLON_VALID)
+            {msgType = 3;}
+        else
+            {msgType = 7;}
+    } else if (mm->metype !=  19) {
+        return;
+    } else if ((mm->mesub == 1) || (mm->mesub == 2)) {
+        msgType = 4;
+    } else {
+        return;
+    }
+
+    // Fields 1 to 6 : SBS message type and ICAO address of the aircraft and some other stuff
+    p += sprintf(p, "MSG,%d,111,11111,%06X,111111,", msgType, mm->addr); 
+
+    // Find current system time
+    ftime(&epocTime_now);                                         // get the current system time & date
+    stTime_now = *localtime(&epocTime_now.time);
+
+    // Find message reception time
+    if (mm->timestampMsg && !mm->remote) {                        // Make sure the records' timestamp is valid before using it
+        epocTime_receive = Modes.stSystemTimeBlk;                 // This is the time of the start of the Block we're processing
+        offset   = (int) (mm->timestampMsg - Modes.timestampBlk); // This is the time (in 12Mhz ticks) into the Block
+        offset   = offset / 12000;                                // convert to milliseconds
+        epocTime_receive.millitm += offset;                       // add on the offset time to the Block start time
+        if (epocTime_receive.millitm > 999) {                     // if we've caused an overflow into the next second...
+            epocTime_receive.millitm -= 1000;
+            epocTime_receive.time ++;                             //    ..correct the overflow
+        }
+        stTime_receive = *localtime(&epocTime_receive.time);
+    } else {
+        epocTime_receive = epocTime_now;                          // We don't have a usable reception time; use the current system time
+        stTime_receive = stTime_now;
+    }
+
+    // Fields 7 & 8 are the message reception time and date
+    p += sprintf(p, "%04d/%02d/%02d,", (stTime_receive.tm_year+1900),(stTime_receive.tm_mon+1), stTime_receive.tm_mday);
+    p += sprintf(p, "%02d:%02d:%02d.%03d,", stTime_receive.tm_hour, stTime_receive.tm_min, stTime_receive.tm_sec, epocTime_receive.millitm);
+
+    // Fields 9 & 10 are the current time and date
+    p += sprintf(p, "%04d/%02d/%02d,", (stTime_now.tm_year+1900),(stTime_now.tm_mon+1), stTime_now.tm_mday);
+    p += sprintf(p, "%02d:%02d:%02d.%03d", stTime_now.tm_hour, stTime_now.tm_min, stTime_now.tm_sec, epocTime_now.millitm);
+
+    // Field 11 is the callsign (if we have it)
+    if (mm->bFlags & MODES_ACFLAGS_CALLSIGN_VALID) {p += sprintf(p, ",%s", mm->flight);}
+    else                                           {p += sprintf(p, ",");}
+
+    // Field 12 is the altitude (if we have it) - force to zero if we're on the ground
+    if ((mm->bFlags & MODES_ACFLAGS_AOG_GROUND) == MODES_ACFLAGS_AOG_GROUND) {
+        p += sprintf(p, ",0");
+    } else if (mm->bFlags & MODES_ACFLAGS_ALTITUDE_VALID) {
+        p += sprintf(p, ",%d", mm->altitude);
+    } else {
+        p += sprintf(p, ",");
+    }
+
+    // Field 13 is the ground Speed (if we have it)
+    if (mm->bFlags & MODES_ACFLAGS_SPEED_VALID) {
+        p += sprintf(p, ",%d", mm->velocity);
+    } else {
+        p += sprintf(p, ","); 
+    }
+
+    // Field 14 is the ground Heading (if we have it)       
+    if (mm->bFlags & MODES_ACFLAGS_HEADING_VALID) {
+        p += sprintf(p, ",%d", mm->heading);
+    } else {
+        p += sprintf(p, ",");
+    }
+
+    // Fields 15 and 16 are the Lat/Lon (if we have it)
+    if (mm->bFlags & MODES_ACFLAGS_LATLON_VALID) {p += sprintf(p, ",%1.5f,%1.5f", mm->fLat, mm->fLon);}
+    else                                         {p += sprintf(p, ",,");}
+
+    // Field 17 is the VerticalRate (if we have it)
+    if (mm->bFlags & MODES_ACFLAGS_VERTRATE_VALID) {p += sprintf(p, ",%d", mm->vert_rate);}
+    else                                           {p += sprintf(p, ",");}
+
+    // Field 18 is  the Squawk (if we have it)
+    if (mm->bFlags & MODES_ACFLAGS_SQUAWK_VALID) {p += sprintf(p, ",%x", mm->modeA);}
+    else                                         {p += sprintf(p, ",");}
+
+    // Field 19 is the Squawk Changing Alert flag (if we have it)
+    if (mm->bFlags & MODES_ACFLAGS_FS_VALID) {
+        if ((mm->fs >= 2) && (mm->fs <= 4)) {
+            p += sprintf(p, ",-1");
+        } else {
+            p += sprintf(p, ",0");
+        }
+    } else {
+        p += sprintf(p, ",");
+    }
+
+    // Field 20 is the Squawk Emergency flag (if we have it)
+    if (mm->bFlags & MODES_ACFLAGS_SQUAWK_VALID) {
+        if ((mm->modeA == 0x7500) || (mm->modeA == 0x7600) || (mm->modeA == 0x7700)) {
+            p += sprintf(p, ",-1");
+        } else {
+            p += sprintf(p, ",0");
+        }
+    } else {
+        p += sprintf(p, ",");
+    }
+
+    // Field 21 is the Squawk Ident flag (if we have it)
+    if (mm->bFlags & MODES_ACFLAGS_FS_VALID) {
+        if ((mm->fs >= 4) && (mm->fs <= 5)) {
+            p += sprintf(p, ",-1");
+        } else {
+            p += sprintf(p, ",0");
+        }
+    } else {
+        p += sprintf(p, ",");
+    }
+
+    // Field 22 is the OnTheGround flag (if we have it)
+    if (mm->bFlags & MODES_ACFLAGS_AOG_VALID) {
+        if (mm->bFlags & MODES_ACFLAGS_AOG) {
+            p += sprintf(p, ",-1");
+        } else {
+            p += sprintf(p, ",0");
+        }
+    } else {
+        p += sprintf(p, ",");
+    }
+
+    p += sprintf(p, "\r\n");
+    modesSendAllClients(Modes.sbsos, msg, p-msg);
+}
+//
+//=========================================================================
+//
+void modesQueueOutput(struct modesMessage *mm) {
+    if (Modes.stat_sbs_connections)   {modesSendSBSOutput(mm);}
+    if (Modes.stat_beast_connections) {modesSendBeastOutput(mm);}
+    if (Modes.stat_raw_connections)   {modesSendRawOutput(mm);}
+}
+//
+//=========================================================================
+//
+// This function decodes a Beast binary format message
+//
+// The message is passed to the higher level layers, so it feeds
+// the selected screen output, the network output and so forth.
+//
+// If the message looks invalid it is silently discarded.
+//
+// The function always returns 0 (success) to the caller as there is no
+// case where we want broken messages here to close the client connection.
+//
+int decodeBinMessage(struct client *c, char *p) {
+    int msgLen = 0;
+    int  j;
+    char ch;
+    char * ptr;
+    unsigned char msg[MODES_LONG_MSG_BYTES];
+    struct modesMessage mm;
+    MODES_NOTUSED(c);
+    memset(&mm, 0, sizeof(mm));
+
+    ch = *p++; /// Get the message type
+    if (0x1A == ch) {p++;} 
+
+    if       ((ch == '1') && (Modes.mode_ac)) { // skip ModeA/C unless user enables --modes-ac
+        msgLen = MODEAC_MSG_BYTES;
+    } else if (ch == '2') {
+        msgLen = MODES_SHORT_MSG_BYTES;
+    } else if (ch == '3') {
+        msgLen = MODES_LONG_MSG_BYTES;
+    }
+
+    if (msgLen) {
+        // Mark messages received over the internet as remote so that we don't try to
+        // pass them off as being received by this instance when forwarding them
+        mm.remote      =    1;
+
+        ptr = (char*) &mm.timestampMsg;
+        for (j = 0; j < 6; j++) { // Grab the timestamp (big endian format)
+            ptr[5-j] = ch = *p++; 
+            if (0x1A == ch) {p++;}
+        }
+
+        mm.signalLevel = ch = *p++;  // Grab the signal level
+        if (0x1A == ch) {p++;}
+
+        for (j = 0; j < msgLen; j++) { // and the data
+            msg[j] = ch = *p++;
+            if (0x1A == ch) {p++;}
+        }
+
+        if (msgLen == MODEAC_MSG_BYTES) { // ModeA or ModeC
+            decodeModeAMessage(&mm, ((msg[0] << 8) | msg[1]));
+        } else {
+            decodeModesMessage(&mm, msg);
+        }
+
+        useModesMessage(&mm);
+    }
+    return (0);
+}
+//
+//=========================================================================
+//
+// Turn an hex digit into its 4 bit decimal value.
+// Returns -1 if the digit is not in the 0-F range.
+//
+int hexDigitVal(int c) {
+    c = tolower(c);
+    if (c >= '0' && c <= '9') return c-'0';
+    else if (c >= 'a' && c <= 'f') return c-'a'+10;
+    else return -1;
+}
+//
+//=========================================================================
+//
+// This function decodes a string representing message in raw hex format
+// like: *8D4B969699155600E87406F5B69F; The string is null-terminated.
+// 
+// The message is passed to the higher level layers, so it feeds
+// the selected screen output, the network output and so forth.
+// 
+// If the message looks invalid it is silently discarded.
+//
+// The function always returns 0 (success) to the caller as there is no 
+// case where we want broken messages here to close the client connection.
+//
+int decodeHexMessage(struct client *c, char *hex) {
+    int l = strlen(hex), j;
+    unsigned char msg[MODES_LONG_MSG_BYTES];
+    struct modesMessage mm;
+    MODES_NOTUSED(c);
+    memset(&mm, 0, sizeof(mm));
+
+    // Mark messages received over the internet as remote so that we don't try to
+    // pass them off as being received by this instance when forwarding them
+    mm.remote      =    1;
+    mm.signalLevel = 0xFF;
+
+    // Remove spaces on the left and on the right
+    while(l && isspace(hex[l-1])) {
+        hex[l-1] = '\0'; l--;
+    }
+    while(isspace(*hex)) {
+        hex++; l--;
+    }
+
+    // Turn the message into binary.
+    // Accept *-AVR raw @-AVR/BEAST timeS+raw %-AVR timeS+raw (CRC good) <-BEAST timeS+sigL+raw
+    // and some AVR records that we can understand
+    if (hex[l-1] != ';') {return (0);} // not complete - abort
+
+    switch(hex[0]) {
+        case '<': {
+            mm.signalLevel = (hexDigitVal(hex[13])<<4) | hexDigitVal(hex[14]);
+            hex += 15; l -= 16; // Skip <, timestamp and siglevel, and ;
+            break;}
+
+        case '@':     // No CRC check
+        case '%': {   // CRC is OK
+            hex += 13; l -= 14; // Skip @,%, and timestamp, and ;
+            break;}
+
+        case '*':
+        case ':': {
+            hex++; l-=2; // Skip * and ;
+            break;}
+
+        default: {
+            return (0); // We don't know what this is, so abort
+            break;}
+    }
+
+    if ( (l != (MODEAC_MSG_BYTES      * 2)) 
+      && (l != (MODES_SHORT_MSG_BYTES * 2)) 
+      && (l != (MODES_LONG_MSG_BYTES  * 2)) )
+        {return (0);} // Too short or long message... broken
+
+    if ( (0 == Modes.mode_ac) 
+      && (l == (MODEAC_MSG_BYTES * 2)) ) 
+        {return (0);} // Right length for ModeA/C, but not enabled
+
+    for (j = 0; j < l; j += 2) {
+        int high = hexDigitVal(hex[j]);
+        int low  = hexDigitVal(hex[j+1]);
+
+        if (high == -1 || low == -1) return 0;
+        msg[j/2] = (high << 4) | low;
+    }
+
+    if (l == (MODEAC_MSG_BYTES * 2)) {  // ModeA or ModeC
+        decodeModeAMessage(&mm, ((msg[0] << 8) | msg[1]));
+    } else {       // Assume ModeS
+        decodeModesMessage(&mm, msg);
+    }
+
+    useModesMessage(&mm);
+    return (0);
+}
+//
+//=========================================================================
+//
+// Return a description of planes in json. No metric conversion
+//
+char *aircraftsToJson(int *len) {
+    time_t now = time(NULL);
+    struct aircraft *a = Modes.aircrafts;
+    int buflen = 1024; // The initial buffer is incremented as needed
+    char *buf = (char *) malloc(buflen), *p = buf;
+    int l;
+
+    l = snprintf(p,buflen,"[\n");
+    p += l; buflen -= l;
+    while(a) {
+        int position = 0;
+        int track = 0;
+
+        if (a->modeACflags & MODEAC_MSG_FLAG) { // skip any fudged ICAO records Mode A/C
+            a = a->next;
+            continue;
+        }
+
+        if (a->bFlags & MODES_ACFLAGS_LATLON_VALID) {
+            position = 1;
+        }
+        
+        if (a->bFlags & MODES_ACFLAGS_HEADING_VALID) {
+            track = 1;
+        }
+        
+        // No metric conversion
+        l = snprintf(p,buflen,
+            "{\"hex\":\"%06x\", \"squawk\":\"%04x\", \"flight\":\"%s\", \"lat\":%f, "
+            "\"lon\":%f, \"validposition\":%d, \"altitude\":%d,  \"vert_rate\":%d,\"track\":%d, \"validtrack\":%d,"
+            "\"speed\":%d, \"messages\":%ld, \"seen\":%d},\n",
+            a->addr, a->modeA, a->flight, a->lat, a->lon, position, a->altitude, a->vert_rate, a->track, track,
+            a->speed, a->messages, (int)(now - a->seen));
+        p += l; buflen -= l;
+        
+        //Resize if needed
+        if (buflen < 256) {
+            int used = p-buf;
+            buflen += 1024; // Our increment.
+            buf = (char *) realloc(buf,used+buflen);
+            p = buf+used;
+        }
+        
+        a = a->next;
+    }
+
+    //Remove the final comma if any, and closes the json array.
+    if (*(p-2) == ',') {
+        *(p-2) = '\n';
+        p--;
+        buflen++;
+    }
+
+    l = snprintf(p,buflen,"]\n");
+    p += l; buflen -= l;
+
+    *len = p-buf;
+    return buf;
+}
+//
+//=========================================================================
+//
+#define MODES_CONTENT_TYPE_HTML "text/html;charset=utf-8"
+#define MODES_CONTENT_TYPE_CSS  "text/css;charset=utf-8"
+#define MODES_CONTENT_TYPE_JSON "application/json;charset=utf-8"
+#define MODES_CONTENT_TYPE_JS   "application/javascript;charset=utf-8"
+//
+// Get an HTTP request header and write the response to the client.
+// gain here we assume that the socket buffer is enough without doing
+// any kind of userspace buffering.
+//
+// Returns 1 on error to signal the caller the client connection should
+// be closed.
+//
+int handleHTTPRequest(struct client *c, char *p) {
+    char hdr[512];
+    int clen, hdrlen;
+    int httpver, keepalive;
+    char *url, *content;
+    char ctype[48];
+    char getFile[1024];
+    char *ext;
+
+    if (Modes.debug & MODES_DEBUG_NET)
+        printf("\nHTTP request: %s\n", c->buf);
+
+    // Minimally parse the request.
+    httpver = (strstr(p, "HTTP/1.1") != NULL) ? 11 : 10;
+    if (httpver == 10) {
+        // HTTP 1.0 defaults to close, unless otherwise specified.
+        keepalive = strstr(p, "Connection: keep-alive") != NULL;
+    } else if (httpver == 11) {
+        // HTTP 1.1 defaults to keep-alive, unless close is specified.
+        keepalive = strstr(p, "Connection: close") == NULL;
+    }
+
+    // Identify he URL.
+    p = strchr(p,' ');
+    if (!p) return 1; // There should be the method and a space
+    url = ++p;        // Now this should point to the requested URL
+    p = strchr(p, ' ');
+    if (!p) return 1; // There should be a space before HTTP/
+    *p = '\0';
+
+    if (Modes.debug & MODES_DEBUG_NET) {
+        printf("\nHTTP keep alive: %d\n", keepalive);
+        printf("HTTP requested URL: %s\n\n", url);
+    }
+    
+    if (strlen(url) < 2) {
+        snprintf(getFile, sizeof getFile, "%s/gmap.html", HTMLPATH); // Default file
+    } else {
+        snprintf(getFile, sizeof getFile, "%s/%s", HTMLPATH, url);
+    }
+
+    // Select the content to send, we have just two so far:
+    // "/" -> Our google map application.
+    // "/data.json" -> Our ajax request to update planes.
+    if (strstr(url, "/data.json")) {
+        content = aircraftsToJson(&clen);
+        //snprintf(ctype, sizeof ctype, MODES_CONTENT_TYPE_JSON);
+    } else {
+        struct stat sbuf;
+        int fd = -1;
+
+        if (stat(getFile, &sbuf) != -1 && (fd = open(getFile, O_RDONLY)) != -1) {
+            content = (char *) malloc(sbuf.st_size);
+            if (read(fd, content, sbuf.st_size) == -1) {
+                snprintf(content, sbuf.st_size, "Error reading from file: %s", strerror(errno));
+            }
+            clen = sbuf.st_size;
+        } else {
+            char buf[128];
+            clen = snprintf(buf,sizeof(buf),"Error opening HTML file: %s", strerror(errno));
+            content = strdup(buf);
+        }
+        
+        if (fd != -1) {
+            close(fd);
+        }
+    }
+
+    // Get file extension and content type
+    snprintf(ctype, sizeof ctype, MODES_CONTENT_TYPE_HTML); // Default content type
+    ext = strrchr(getFile, '.');
+
+    if (strlen(ext) > 0) {
+        if (strstr(ext, ".json")) {
+            snprintf(ctype, sizeof ctype, MODES_CONTENT_TYPE_JSON);
+        } else if (strstr(ext, ".css")) {
+            snprintf(ctype, sizeof ctype, MODES_CONTENT_TYPE_CSS);
+        } else if (strstr(ext, ".js")) {
+            snprintf(ctype, sizeof ctype, MODES_CONTENT_TYPE_JS);
+        }
+    }
+
+    // Create the header and send the reply
+    hdrlen = snprintf(hdr, sizeof(hdr),
+        "HTTP/1.1 200 OK\r\n"
+        "Server: Dump1090\r\n"
+        "Content-Type: %s\r\n"
+        "Connection: %s\r\n"
+        "Content-Length: %d\r\n"
+        "Cache-Control: no-cache, must-revalidate\r\n"
+        "Expires: Sat, 26 Jul 1997 05:00:00 GMT\r\n"
+        "\r\n",
+        ctype,
+        keepalive ? "keep-alive" : "close",
+        clen);
+
+    if (Modes.debug & MODES_DEBUG_NET) {
+        printf("HTTP Reply header:\n%s", hdr);
+    }
+
+    // Send header and content.
+#ifndef _WIN32
+    if ( (write(c->fd, hdr, hdrlen) != hdrlen) 
+      || (write(c->fd, content, clen) != clen) ) {
+#else
+    if ( (send(c->fd, hdr, hdrlen, 0) != hdrlen) 
+      || (send(c->fd, content, clen, 0) != clen) ) {
+#endif
+        free(content);
+        return 1;
+    }
+    free(content);
+    Modes.stat_http_requests++;
+    return !keepalive;
+}
+//
+//=========================================================================
+//
+// This function polls the clients using read() in order to receive new
+// messages from the net.
+//
+// The message is supposed to be separated from the next message by the
+// separator 'sep', which is a null-terminated C string.
+//
+// Every full message received is decoded and passed to the higher layers
+// calling the function's 'handler'.
+//
+// The handler returns 0 on success, or 1 to signal this function we should
+// close the connection with the client in case of non-recoverable errors.
+//
+void modesReadFromClient(struct client *c, char *sep,
+                         int(*handler)(struct client *, char *)) {
+    int left;
+    int nread;
+    int fullmsg;
+    int bContinue = 1;
+    char *s, *e, *p;
+
+    while(bContinue) {
+
+        fullmsg = 0;
+        left = MODES_CLIENT_BUF_SIZE - c->buflen;
+        // If our buffer is full discard it, this is some badly formatted shit
+        if (left <= 0) {
+            c->buflen = 0;
+            left = MODES_CLIENT_BUF_SIZE;
+            // If there is garbage, read more to discard it ASAP
+        }
+#ifndef _WIN32
+        nread = read(c->fd, c->buf+c->buflen, left);
+#else
+        nread = recv(c->fd, c->buf+c->buflen, left, 0);
+        if (nread < 0) {errno = WSAGetLastError();}
+#endif
+
+        // If we didn't get all the data we asked for, then return once we've processed what we did get.
+        if (nread != left) {
+            bContinue = 0;
+        }
+#ifndef _WIN32
+        if ( (nread < 0 && errno != EAGAIN && errno != EWOULDBLOCK) || nread == 0 ) { // Error, or end of file
+#else
+        if ( (nread < 0) && (errno != EWOULDBLOCK)) { // Error, or end of file
+#endif
+            modesFreeClient(c);
+            return;
+        }
+        if (nread <= 0) {
+            break; // Serve next client
+        }
+        c->buflen += nread;
+
+        // Always null-term so we are free to use strstr() (it won't affect binary case)
+        c->buf[c->buflen] = '\0';
+
+        e = s = c->buf;                                // Start with the start of buffer, first message
+
+        if (c->service == Modes.bis) {
+            // This is the Beast Binary scanning case.
+            // If there is a complete message still in the buffer, there must be the separator 'sep'
+            // in the buffer, note that we full-scan the buffer at every read for simplicity.
+
+            left = c->buflen;                                  // Length of valid search for memchr()
+            while (left && ((s = memchr(e, (char) 0x1a, left)) != NULL)) { // The first byte of buffer 'should' be 0x1a
+                s++;                                           // skip the 0x1a
+                if        (*s == '1') {
+                    e = s + MODEAC_MSG_BYTES      + 8;         // point past remainder of message
+                } else if (*s == '2') {
+                    e = s + MODES_SHORT_MSG_BYTES + 8;
+                } else if (*s == '3') {
+                    e = s + MODES_LONG_MSG_BYTES  + 8;
+                } else {
+                    e = s;                                     // Not a valid beast message, skip
+                    left = &(c->buf[c->buflen]) - e;
+                    continue;
+                }
+                // we need to be careful of double escape characters in the message body
+                for (p = s; p < e; p++) {
+                    if (0x1A == *p) {
+                        p++; e++;
+                        if (e > &(c->buf[c->buflen])) {
+                            break;
+                        }
+                    }
+                }
+                left = &(c->buf[c->buflen]) - e;
+                if (left < 0) {                                // Incomplete message in buffer
+                    e = s - 1;                                 // point back at last found 0x1a.
+                    break;
+                }
+                // Have a 0x1a followed by 1, 2 or 3 - pass message less 0x1a to handler.
+                if (handler(c, s)) {
+                    modesFreeClient(c);
+                    return;
+                }
+                fullmsg = 1;
+            }
+            s = e;     // For the buffer remainder below
+
+        } else {
+            //
+            // This is the ASCII scanning case, AVR RAW or HTTP at present
+            // If there is a complete message still in the buffer, there must be the separator 'sep'
+            // in the buffer, note that we full-scan the buffer at every read for simplicity.
+            //
+            while ((e = strstr(s, sep)) != NULL) { // end of first message if found
+                *e = '\0';                         // The handler expects null terminated strings
+                if (handler(c, s)) {               // Pass message to handler.
+                    modesFreeClient(c);            // Handler returns 1 on error to signal we .
+                    return;                        // should close the client connection
+                }
+                s = e + strlen(sep);               // Move to start of next message
+                fullmsg = 1;
+            }
+        }
+
+        if (fullmsg) {                             // We processed something - so
+            c->buflen = &(c->buf[c->buflen]) - s;  //     Update the unprocessed buffer length
+            memmove(c->buf, s, c->buflen);         //     Move what's remaining to the start of the buffer
+        } else {                                   // If no message was decoded process the next client
+            break;
+        }
+    }
+}
+//
+//=========================================================================
+//
+// Read data from clients. This function actually delegates a lower-level
+// function that depends on the kind of service (raw, http, ...).
+//
+void modesReadFromClients(void) {
+
+    struct client *c = modesAcceptClients();
+
+    while (c) {
+        // Read next before servicing client incase the service routine deletes the client! 
+        struct client *next = c->next;
+
+        if (c->service == Modes.ris) {
+            modesReadFromClient(c,"\n",decodeHexMessage);
+        } else if (c->service == Modes.bis) {
+            modesReadFromClient(c,"",decodeBinMessage);
+        } else if (c->service == Modes.https) {
+            modesReadFromClient(c,"\r\n\r\n",handleHTTPRequest);
+        }
+        c = next;
+    }
+}
+//
+// =============================== Network IO ===========================
+//
diff --git a/ppup1090.c b/ppup1090.c
new file mode 100644
index 0000000..afbbe2f
--- /dev/null
+++ b/ppup1090.c
@@ -0,0 +1,261 @@
+// ppup1090, a Mode S PlanePlotter Uploader for dump1090 devices.
+//
+// Copyright (C) 2013 by Malcolm Robb <Support at 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 at gmail.com>\n"
+" Copyright (C) 2014 by Malcolm Robb <support at 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
+}
+//
+//=========================================================================
+//
diff --git a/ppup1090.h b/ppup1090.h
new file mode 100644
index 0000000..6d0756d
--- /dev/null
+++ b/ppup1090.h
@@ -0,0 +1,110 @@
+// ppup1090, a Mode S PlanePlotter Uploader for dump1090 devices.
+//
+// Copyright (C) 2013 by Malcolm Robb <Support at 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
diff --git a/ppup1090.sh b/ppup1090.sh
new file mode 100644
index 0000000..8ed4ad3
--- /dev/null
+++ b/ppup1090.sh
@@ -0,0 +1,85 @@
+#!/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
+#
+
diff --git a/pthreads/pthread.h b/pthreads/pthread.h
new file mode 100644
index 0000000..b4072f7
--- /dev/null
+++ b/pthreads/pthread.h
@@ -0,0 +1,1368 @@
+/* This is an implementation of the threads API of POSIX 1003.1-2001.
+ *
+ * --------------------------------------------------------------------------
+ *
+ *      Pthreads-win32 - POSIX Threads Library for Win32
+ *      Copyright(C) 1998 John E. Bossom
+ *      Copyright(C) 1999,2005 Pthreads-win32 contributors
+ * 
+ *      Contact Email: rpj at 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( PTHREAD_H )
+#define PTHREAD_H
+
+/*
+ * See the README file for an explanation of the pthreads-win32 version
+ * numbering scheme and how the DLL is named etc.
+ */
+#define PTW32_VERSION 2,9,1,0
+#define PTW32_VERSION_STRING "2, 9, 1, 0\0"
+
+/* There are three implementations of cancel cleanup.
+ * Note that pthread.h is included in both application
+ * compilation units and also internally for the library.
+ * The code here and within the library aims to work
+ * for all reasonable combinations of environments.
+ *
+ * The three implementations are:
+ *
+ *   WIN32 SEH
+ *   C
+ *   C++
+ *
+ * Please note that exiting a push/pop block via
+ * "return", "exit", "break", or "continue" will
+ * lead to different behaviour amongst applications
+ * depending upon whether the library was built
+ * using SEH, C++, or C. For example, a library built
+ * with SEH will call the cleanup routine, while both
+ * C++ and C built versions will not.
+ */
+
+/*
+ * Define defaults for cleanup code.
+ * Note: Unless the build explicitly defines one of the following, then
+ * we default to standard C style cleanup. This style uses setjmp/longjmp
+ * in the cancelation and thread exit implementations and therefore won't
+ * do stack unwinding if linked to applications that have it (e.g.
+ * C++ apps). This is currently consistent with most/all commercial Unix
+ * POSIX threads implementations.
+ */
+#if !defined( __CLEANUP_SEH ) && !defined( __CLEANUP_CXX ) && !defined( __CLEANUP_C )
+# define __CLEANUP_C
+#endif
+
+#if defined( __CLEANUP_SEH ) && ( !defined( _MSC_VER ) && !defined(PTW32_RC_MSC))
+#error ERROR [__FILE__, line __LINE__]: SEH is not supported for this compiler.
+#endif
+
+/*
+ * Stop here if we are being included by the resource compiler.
+ */
+#if !defined(RC_INVOKED)
+
+#undef PTW32_LEVEL
+
+#if defined(_POSIX_SOURCE)
+#define PTW32_LEVEL 0
+/* Early POSIX */
+#endif
+
+#if defined(_POSIX_C_SOURCE) && _POSIX_C_SOURCE >= 199309
+#undef PTW32_LEVEL
+#define PTW32_LEVEL 1
+/* Include 1b, 1c and 1d */
+#endif
+
+#if defined(INCLUDE_NP)
+#undef PTW32_LEVEL
+#define PTW32_LEVEL 2
+/* Include Non-Portable extensions */
+#endif
+
+#define PTW32_LEVEL_MAX 3
+
+#if ( defined(_POSIX_C_SOURCE) && _POSIX_C_SOURCE >= 200112 )  || !defined(PTW32_LEVEL)
+#define PTW32_LEVEL PTW32_LEVEL_MAX
+/* Include everything */
+#endif
+
+#if defined(_UWIN)
+#   define HAVE_STRUCT_TIMESPEC 1
+#   define HAVE_SIGNAL_H        1
+#   undef HAVE_PTW32_CONFIG_H
+#   pragma comment(lib, "pthread")
+#endif
+
+/*
+ * -------------------------------------------------------------
+ *
+ *
+ * Module: pthread.h
+ *
+ * Purpose:
+ *      Provides an implementation of PThreads based upon the
+ *      standard:
+ *
+ *              POSIX 1003.1-2001
+ *  and
+ *    The Single Unix Specification version 3
+ *
+ *    (these two are equivalent)
+ *
+ *      in order to enhance code portability between Windows,
+ *  various commercial Unix implementations, and Linux.
+ *
+ *      See the ANNOUNCE file for a full list of conforming
+ *      routines and defined constants, and a list of missing
+ *      routines and constants not defined in this implementation.
+ *
+ * Authors:
+ *      There have been many contributors to this library.
+ *      The initial implementation was contributed by
+ *      John Bossom, and several others have provided major
+ *      sections or revisions of parts of the implementation.
+ *      Often significant effort has been contributed to
+ *      find and fix important bugs and other problems to
+ *      improve the reliability of the library, which sometimes
+ *      is not reflected in the amount of code which changed as
+ *      result.
+ *      As much as possible, the contributors are acknowledged
+ *      in the ChangeLog file in the source code distribution
+ *      where their changes are noted in detail.
+ *
+ *      Contributors are listed in the CONTRIBUTORS file.
+ *
+ *      As usual, all bouquets go to the contributors, and all
+ *      brickbats go to the project maintainer.
+ *
+ * Maintainer:
+ *      The code base for this project is coordinated and
+ *      eventually pre-tested, packaged, and made available by
+ *
+ *              Ross Johnson <rpj at callisto.canberra.edu.au>
+ *
+ * QA Testers:
+ *      Ultimately, the library is tested in the real world by
+ *      a host of competent and demanding scientists and
+ *      engineers who report bugs and/or provide solutions
+ *      which are then fixed or incorporated into subsequent
+ *      versions of the library. Each time a bug is fixed, a
+ *      test case is written to prove the fix and ensure
+ *      that later changes to the code don't reintroduce the
+ *      same error. The number of test cases is slowly growing
+ *      and therefore so is the code reliability.
+ *
+ * Compliance:
+ *      See the file ANNOUNCE for the list of implemented
+ *      and not-implemented routines and defined options.
+ *      Of course, these are all defined is this file as well.
+ *
+ * Web site:
+ *      The source code and other information about this library
+ *      are available from
+ *
+ *              http://sources.redhat.com/pthreads-win32/
+ *
+ * -------------------------------------------------------------
+ */
+
+/* Try to avoid including windows.h */
+#if (defined(__MINGW64__) || defined(__MINGW32__)) && defined(__cplusplus)
+#define PTW32_INCLUDE_WINDOWS_H
+#endif
+
+#if defined(PTW32_INCLUDE_WINDOWS_H)
+#include <windows.h>
+#endif
+
+#if defined(_MSC_VER) && _MSC_VER < 1300 || defined(__DMC__)
+/*
+ * VC++6.0 or early compiler's header has no DWORD_PTR type.
+ */
+typedef unsigned long DWORD_PTR;
+typedef unsigned long ULONG_PTR;
+#endif
+/*
+ * -----------------
+ * autoconf switches
+ * -----------------
+ */
+
+#if defined(HAVE_PTW32_CONFIG_H)
+#include "config.h"
+#endif /* HAVE_PTW32_CONFIG_H */
+
+#if !defined(NEED_FTIME)
+#include <time.h>
+#else /* NEED_FTIME */
+/* use native WIN32 time API */
+#endif /* NEED_FTIME */
+
+#if defined(HAVE_SIGNAL_H)
+#include <signal.h>
+#endif /* HAVE_SIGNAL_H */
+
+#include <limits.h>
+
+/*
+ * Boolean values to make us independent of system includes.
+ */
+enum {
+  PTW32_FALSE = 0,
+  PTW32_TRUE = (! PTW32_FALSE)
+};
+
+/*
+ * 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_LEVEL >= PTW32_LEVEL_MAX
+#if defined(NEED_ERRNO)
+#include "need_errno.h"
+#else
+#include <errno.h>
+#endif
+#endif /* PTW32_LEVEL >= PTW32_LEVEL_MAX */
+
+/*
+ * Several systems don't define some error numbers.
+ */
+#if !defined(ENOTSUP)
+#  define ENOTSUP 48   /* This is the value in Solaris. */
+#endif
+
+#if !defined(ETIMEDOUT)
+#  define ETIMEDOUT 10060 /* Same as WSAETIMEDOUT */
+#endif
+
+#if !defined(ENOSYS)
+#  define ENOSYS 140     /* Semi-arbitrary value */
+#endif
+
+#if !defined(EDEADLK)
+#  if defined(EDEADLOCK)
+#    define EDEADLK EDEADLOCK
+#  else
+#    define EDEADLK 36     /* This is the value in MSVC. */
+#  endif
+#endif
+
+/* POSIX 2008 - related to robust mutexes */
+#if !defined(EOWNERDEAD)
+#  define EOWNERDEAD 43
+#endif
+#if !defined(ENOTRECOVERABLE)
+#  define ENOTRECOVERABLE 44
+#endif
+
+#include <sched.h>
+
+/*
+ * To avoid including windows.h we define only those things that we
+ * actually need from it.
+ */
+#if !defined(PTW32_INCLUDE_WINDOWS_H)
+#if !defined(HANDLE)
+# define PTW32__HANDLE_DEF
+# define HANDLE void *
+#endif
+#if !defined(DWORD)
+# define PTW32__DWORD_DEF
+# define DWORD unsigned long
+#endif
+#endif
+
+#if !defined(HAVE_STRUCT_TIMESPEC)
+#define HAVE_STRUCT_TIMESPEC
+#if !defined(_TIMESPEC_DEFINED)
+#define _TIMESPEC_DEFINED
+struct timespec {
+        time_t tv_sec;
+        long tv_nsec;
+};
+#endif /* _TIMESPEC_DEFINED */
+#endif /* HAVE_STRUCT_TIMESPEC */
+
+#if !defined(SIG_BLOCK)
+#define SIG_BLOCK 0
+#endif /* SIG_BLOCK */
+
+#if !defined(SIG_UNBLOCK)
+#define SIG_UNBLOCK 1
+#endif /* SIG_UNBLOCK */
+
+#if !defined(SIG_SETMASK)
+#define SIG_SETMASK 2
+#endif /* SIG_SETMASK */
+
+#if defined(__cplusplus)
+extern "C"
+{
+#endif                          /* __cplusplus */
+
+/*
+ * -------------------------------------------------------------
+ *
+ * POSIX 1003.1-2001 Options
+ * =========================
+ *
+ * Options are normally set in <unistd.h>, which is not provided
+ * with pthreads-win32.
+ *
+ * For conformance with the Single Unix Specification (version 3), all of the
+ * options below are defined, and have a value of either -1 (not supported)
+ * or 200112L (supported).
+ *
+ * These options can neither be left undefined nor have a value of 0, because
+ * either indicates that sysconf(), which is not implemented, may be used at
+ * runtime to check the status of the option.
+ *
+ * _POSIX_THREADS (== 200112L)
+ *                      If == 200112L, you can use threads
+ *
+ * _POSIX_THREAD_ATTR_STACKSIZE (== 200112L)
+ *                      If == 200112L, you can control the size of a thread's
+ *                      stack
+ *                              pthread_attr_getstacksize
+ *                              pthread_attr_setstacksize
+ *
+ * _POSIX_THREAD_ATTR_STACKADDR (== -1)
+ *                      If == 200112L, you can allocate and control a thread's
+ *                      stack. If not supported, the following functions
+ *                      will return ENOSYS, indicating they are not
+ *                      supported:
+ *                              pthread_attr_getstackaddr
+ *                              pthread_attr_setstackaddr
+ *
+ * _POSIX_THREAD_PRIORITY_SCHEDULING (== -1)
+ *                      If == 200112L, you can use realtime scheduling.
+ *                      This option indicates that the behaviour of some
+ *                      implemented functions conforms to the additional TPS
+ *                      requirements in the standard. E.g. rwlocks favour
+ *                      writers over readers when threads have equal priority.
+ *
+ * _POSIX_THREAD_PRIO_INHERIT (== -1)
+ *                      If == 200112L, you can create priority inheritance
+ *                      mutexes.
+ *                              pthread_mutexattr_getprotocol +
+ *                              pthread_mutexattr_setprotocol +
+ *
+ * _POSIX_THREAD_PRIO_PROTECT (== -1)
+ *                      If == 200112L, you can create priority ceiling mutexes
+ *                      Indicates the availability of:
+ *                              pthread_mutex_getprioceiling
+ *                              pthread_mutex_setprioceiling
+ *                              pthread_mutexattr_getprioceiling
+ *                              pthread_mutexattr_getprotocol     +
+ *                              pthread_mutexattr_setprioceiling
+ *                              pthread_mutexattr_setprotocol     +
+ *
+ * _POSIX_THREAD_PROCESS_SHARED (== -1)
+ *                      If set, you can create mutexes and condition
+ *                      variables that can be shared with another
+ *                      process.If set, indicates the availability
+ *                      of:
+ *                              pthread_mutexattr_getpshared
+ *                              pthread_mutexattr_setpshared
+ *                              pthread_condattr_getpshared
+ *                              pthread_condattr_setpshared
+ *
+ * _POSIX_THREAD_SAFE_FUNCTIONS (== 200112L)
+ *                      If == 200112L you can use the special *_r library
+ *                      functions that provide thread-safe behaviour
+ *
+ * _POSIX_READER_WRITER_LOCKS (== 200112L)
+ *                      If == 200112L, you can use read/write locks
+ *
+ * _POSIX_SPIN_LOCKS (== 200112L)
+ *                      If == 200112L, you can use spin locks
+ *
+ * _POSIX_BARRIERS (== 200112L)
+ *                      If == 200112L, you can use barriers
+ *
+ *      + These functions provide both 'inherit' and/or
+ *        'protect' protocol, based upon these macro
+ *        settings.
+ *
+ * -------------------------------------------------------------
+ */
+
+/*
+ * POSIX Options
+ */
+#undef _POSIX_THREADS
+#define _POSIX_THREADS 200809L
+
+#undef _POSIX_READER_WRITER_LOCKS
+#define _POSIX_READER_WRITER_LOCKS 200809L
+
+#undef _POSIX_SPIN_LOCKS
+#define _POSIX_SPIN_LOCKS 200809L
+
+#undef _POSIX_BARRIERS
+#define _POSIX_BARRIERS 200809L
+
+#undef _POSIX_THREAD_SAFE_FUNCTIONS
+#define _POSIX_THREAD_SAFE_FUNCTIONS 200809L
+
+#undef _POSIX_THREAD_ATTR_STACKSIZE
+#define _POSIX_THREAD_ATTR_STACKSIZE 200809L
+
+/*
+ * The following options are not supported
+ */
+#undef _POSIX_THREAD_ATTR_STACKADDR
+#define _POSIX_THREAD_ATTR_STACKADDR -1
+
+#undef _POSIX_THREAD_PRIO_INHERIT
+#define _POSIX_THREAD_PRIO_INHERIT -1
+
+#undef _POSIX_THREAD_PRIO_PROTECT
+#define _POSIX_THREAD_PRIO_PROTECT -1
+
+/* TPS is not fully supported.  */
+#undef _POSIX_THREAD_PRIORITY_SCHEDULING
+#define _POSIX_THREAD_PRIORITY_SCHEDULING -1
+
+#undef _POSIX_THREAD_PROCESS_SHARED
+#define _POSIX_THREAD_PROCESS_SHARED -1
+
+
+/*
+ * POSIX 1003.1-2001 Limits
+ * ===========================
+ *
+ * These limits are normally set in <limits.h>, which is not provided with
+ * pthreads-win32.
+ *
+ * PTHREAD_DESTRUCTOR_ITERATIONS
+ *                      Maximum number of attempts to destroy
+ *                      a thread's thread-specific data on
+ *                      termination (must be at least 4)
+ *
+ * PTHREAD_KEYS_MAX
+ *                      Maximum number of thread-specific data keys
+ *                      available per process (must be at least 128)
+ *
+ * PTHREAD_STACK_MIN
+ *                      Minimum supported stack size for a thread
+ *
+ * PTHREAD_THREADS_MAX
+ *                      Maximum number of threads supported per
+ *                      process (must be at least 64).
+ *
+ * SEM_NSEMS_MAX
+ *                      The maximum number of semaphores a process can have.
+ *                      (must be at least 256)
+ *
+ * SEM_VALUE_MAX
+ *                      The maximum value a semaphore can have.
+ *                      (must be at least 32767)
+ *
+ */
+#undef _POSIX_THREAD_DESTRUCTOR_ITERATIONS
+#define _POSIX_THREAD_DESTRUCTOR_ITERATIONS     4
+
+#undef PTHREAD_DESTRUCTOR_ITERATIONS
+#define PTHREAD_DESTRUCTOR_ITERATIONS           _POSIX_THREAD_DESTRUCTOR_ITERATIONS
+
+#undef _POSIX_THREAD_KEYS_MAX
+#define _POSIX_THREAD_KEYS_MAX                  128
+
+#undef PTHREAD_KEYS_MAX
+#define PTHREAD_KEYS_MAX                        _POSIX_THREAD_KEYS_MAX
+
+#undef PTHREAD_STACK_MIN
+#define PTHREAD_STACK_MIN                       0
+
+#undef _POSIX_THREAD_THREADS_MAX
+#define _POSIX_THREAD_THREADS_MAX               64
+
+  /* Arbitrary value */
+#undef PTHREAD_THREADS_MAX
+#define PTHREAD_THREADS_MAX                     2019
+
+#undef _POSIX_SEM_NSEMS_MAX
+#define _POSIX_SEM_NSEMS_MAX                    256
+
+  /* Arbitrary value */
+#undef SEM_NSEMS_MAX
+#define SEM_NSEMS_MAX                           1024
+
+#undef _POSIX_SEM_VALUE_MAX
+#define _POSIX_SEM_VALUE_MAX                    32767
+
+#undef SEM_VALUE_MAX
+#define SEM_VALUE_MAX                           INT_MAX
+
+
+#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
+
+/*
+ * The Open Watcom C/C++ compiler uses a non-standard calling convention
+ * that passes function args in registers unless __cdecl is explicitly specified
+ * in exposed function prototypes.
+ *
+ * We force all calls to cdecl even though this could slow Watcom code down
+ * slightly. If you know that the Watcom compiler will be used to build both
+ * the DLL and application, then you can probably define this as a null string.
+ * Remember that pthread.h (this file) is used for both the DLL and application builds.
+ */
+#define PTW32_CDECL __cdecl
+
+#if defined(_UWIN) && PTW32_LEVEL >= PTW32_LEVEL_MAX
+#   include     <sys/types.h>
+#else
+/*
+ * Generic handle type - intended to extend uniqueness beyond
+ * that available with a simple pointer. It should scale for either
+ * IA-32 or IA-64.
+ */
+typedef struct {
+    void * p;                   /* Pointer to actual object */
+    unsigned int x;             /* Extra information - reuse count etc */
+} ptw32_handle_t;
+
+typedef ptw32_handle_t pthread_t;
+typedef struct pthread_attr_t_ * pthread_attr_t;
+typedef struct pthread_once_t_ pthread_once_t;
+typedef struct pthread_key_t_ * pthread_key_t;
+typedef struct pthread_mutex_t_ * pthread_mutex_t;
+typedef struct pthread_mutexattr_t_ * pthread_mutexattr_t;
+typedef struct pthread_cond_t_ * pthread_cond_t;
+typedef struct pthread_condattr_t_ * pthread_condattr_t;
+#endif
+typedef struct pthread_rwlock_t_ * pthread_rwlock_t;
+typedef struct pthread_rwlockattr_t_ * pthread_rwlockattr_t;
+typedef struct pthread_spinlock_t_ * pthread_spinlock_t;
+typedef struct pthread_barrier_t_ * pthread_barrier_t;
+typedef struct pthread_barrierattr_t_ * pthread_barrierattr_t;
+
+/*
+ * ====================
+ * ====================
+ * POSIX Threads
+ * ====================
+ * ====================
+ */
+
+enum {
+/*
+ * pthread_attr_{get,set}detachstate
+ */
+  PTHREAD_CREATE_JOINABLE       = 0,  /* Default */
+  PTHREAD_CREATE_DETACHED       = 1,
+
+/*
+ * pthread_attr_{get,set}inheritsched
+ */
+  PTHREAD_INHERIT_SCHED         = 0,
+  PTHREAD_EXPLICIT_SCHED        = 1,  /* Default */
+
+/*
+ * pthread_{get,set}scope
+ */
+  PTHREAD_SCOPE_PROCESS         = 0,
+  PTHREAD_SCOPE_SYSTEM          = 1,  /* Default */
+
+/*
+ * pthread_setcancelstate paramters
+ */
+  PTHREAD_CANCEL_ENABLE         = 0,  /* Default */
+  PTHREAD_CANCEL_DISABLE        = 1,
+
+/*
+ * pthread_setcanceltype parameters
+ */
+  PTHREAD_CANCEL_ASYNCHRONOUS   = 0,
+  PTHREAD_CANCEL_DEFERRED       = 1,  /* Default */
+
+/*
+ * pthread_mutexattr_{get,set}pshared
+ * pthread_condattr_{get,set}pshared
+ */
+  PTHREAD_PROCESS_PRIVATE       = 0,
+  PTHREAD_PROCESS_SHARED        = 1,
+
+/*
+ * pthread_mutexattr_{get,set}robust
+ */
+  PTHREAD_MUTEX_STALLED         = 0,  /* Default */
+  PTHREAD_MUTEX_ROBUST          = 1,
+
+/*
+ * pthread_barrier_wait
+ */
+  PTHREAD_BARRIER_SERIAL_THREAD = -1
+};
+
+/*
+ * ====================
+ * ====================
+ * Cancelation
+ * ====================
+ * ====================
+ */
+#define PTHREAD_CANCELED       ((void *)(size_t) -1)
+
+
+/*
+ * ====================
+ * ====================
+ * Once Key
+ * ====================
+ * ====================
+ */
+#define PTHREAD_ONCE_INIT       { PTW32_FALSE, 0, 0, 0}
+
+struct pthread_once_t_
+{
+  int          done;        /* indicates if user function has been executed */
+  void *       lock;
+  int          reserved1;
+  int          reserved2;
+};
+
+
+/*
+ * ====================
+ * ====================
+ * Object initialisers
+ * ====================
+ * ====================
+ */
+#define PTHREAD_MUTEX_INITIALIZER ((pthread_mutex_t)(size_t) -1)
+#define PTHREAD_RECURSIVE_MUTEX_INITIALIZER ((pthread_mutex_t)(size_t) -2)
+#define PTHREAD_ERRORCHECK_MUTEX_INITIALIZER ((pthread_mutex_t)(size_t) -3)
+
+/*
+ * Compatibility with LinuxThreads
+ */
+#define PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP PTHREAD_RECURSIVE_MUTEX_INITIALIZER
+#define PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP PTHREAD_ERRORCHECK_MUTEX_INITIALIZER
+
+#define PTHREAD_COND_INITIALIZER ((pthread_cond_t)(size_t) -1)
+
+#define PTHREAD_RWLOCK_INITIALIZER ((pthread_rwlock_t)(size_t) -1)
+
+#define PTHREAD_SPINLOCK_INITIALIZER ((pthread_spinlock_t)(size_t) -1)
+
+
+/*
+ * Mutex types.
+ */
+enum
+{
+  /* Compatibility with LinuxThreads */
+  PTHREAD_MUTEX_FAST_NP,
+  PTHREAD_MUTEX_RECURSIVE_NP,
+  PTHREAD_MUTEX_ERRORCHECK_NP,
+  PTHREAD_MUTEX_TIMED_NP = PTHREAD_MUTEX_FAST_NP,
+  PTHREAD_MUTEX_ADAPTIVE_NP = PTHREAD_MUTEX_FAST_NP,
+  /* For compatibility with POSIX */
+  PTHREAD_MUTEX_NORMAL = PTHREAD_MUTEX_FAST_NP,
+  PTHREAD_MUTEX_RECURSIVE = PTHREAD_MUTEX_RECURSIVE_NP,
+  PTHREAD_MUTEX_ERRORCHECK = PTHREAD_MUTEX_ERRORCHECK_NP,
+  PTHREAD_MUTEX_DEFAULT = PTHREAD_MUTEX_NORMAL
+};
+
+
+typedef struct ptw32_cleanup_t ptw32_cleanup_t;
+
+#if defined(_MSC_VER)
+/* Disable MSVC 'anachronism used' warning */
+#pragma warning( disable : 4229 )
+#endif
+
+typedef void (* PTW32_CDECL ptw32_cleanup_callback_t)(void *);
+
+#if defined(_MSC_VER)
+#pragma warning( default : 4229 )
+#endif
+
+struct ptw32_cleanup_t
+{
+  ptw32_cleanup_callback_t routine;
+  void *arg;
+  struct ptw32_cleanup_t *prev;
+};
+
+#if defined(__CLEANUP_SEH)
+        /*
+         * WIN32 SEH version of cancel cleanup.
+         */
+
+#define pthread_cleanup_push( _rout, _arg ) \
+        { \
+            ptw32_cleanup_t     _cleanup; \
+            \
+        _cleanup.routine        = (ptw32_cleanup_callback_t)(_rout); \
+            _cleanup.arg        = (_arg); \
+            __try \
+              { \
+
+#define pthread_cleanup_pop( _execute ) \
+              } \
+            __finally \
+                { \
+                    if( _execute || AbnormalTermination()) \
+                      { \
+                          (*(_cleanup.routine))( _cleanup.arg ); \
+                      } \
+                } \
+        }
+
+#else /* __CLEANUP_SEH */
+
+#if defined(__CLEANUP_C)
+
+        /*
+         * C implementation of PThreads cancel cleanup
+         */
+
+#define pthread_cleanup_push( _rout, _arg ) \
+        { \
+            ptw32_cleanup_t     _cleanup; \
+            \
+            ptw32_push_cleanup( &_cleanup, (ptw32_cleanup_callback_t) (_rout), (_arg) ); \
+
+#define pthread_cleanup_pop( _execute ) \
+            (void) ptw32_pop_cleanup( _execute ); \
+        }
+
+#else /* __CLEANUP_C */
+
+#if defined(__CLEANUP_CXX)
+
+        /*
+         * C++ version of cancel cleanup.
+         * - John E. Bossom.
+         */
+
+        class PThreadCleanup {
+          /*
+           * PThreadCleanup
+           *
+           * Purpose
+           *      This class is a C++ helper class that is
+           *      used to implement pthread_cleanup_push/
+           *      pthread_cleanup_pop.
+           *      The destructor of this class automatically
+           *      pops the pushed cleanup routine regardless
+           *      of how the code exits the scope
+           *      (i.e. such as by an exception)
+           */
+      ptw32_cleanup_callback_t cleanUpRout;
+          void    *       obj;
+          int             executeIt;
+
+        public:
+          PThreadCleanup() :
+            cleanUpRout( 0 ),
+            obj( 0 ),
+            executeIt( 0 )
+            /*
+             * No cleanup performed
+             */
+            {
+            }
+
+          PThreadCleanup(
+             ptw32_cleanup_callback_t routine,
+                         void    *       arg ) :
+            cleanUpRout( routine ),
+            obj( arg ),
+            executeIt( 1 )
+            /*
+             * Registers a cleanup routine for 'arg'
+             */
+            {
+            }
+
+          ~PThreadCleanup()
+            {
+              if ( executeIt && ((void *) cleanUpRout != (void *) 0) )
+                {
+                  (void) (*cleanUpRout)( obj );
+                }
+            }
+
+          void execute( int exec )
+            {
+              executeIt = exec;
+            }
+        };
+
+        /*
+         * C++ implementation of PThreads cancel cleanup;
+         * This implementation takes advantage of a helper
+         * class who's destructor automatically calls the
+         * cleanup routine if we exit our scope weirdly
+         */
+#define pthread_cleanup_push( _rout, _arg ) \
+        { \
+            PThreadCleanup  cleanup((ptw32_cleanup_callback_t)(_rout), \
+                                    (void *) (_arg) );
+
+#define pthread_cleanup_pop( _execute ) \
+            cleanup.execute( _execute ); \
+        }
+
+#else
+
+#error ERROR [__FILE__, line __LINE__]: Cleanup type undefined.
+
+#endif /* __CLEANUP_CXX */
+
+#endif /* __CLEANUP_C */
+
+#endif /* __CLEANUP_SEH */
+
+/*
+ * ===============
+ * ===============
+ * Methods
+ * ===============
+ * ===============
+ */
+
+/*
+ * PThread Attribute Functions
+ */
+PTW32_DLLPORT int PTW32_CDECL pthread_attr_init (pthread_attr_t * attr);
+
+PTW32_DLLPORT int PTW32_CDECL pthread_attr_destroy (pthread_attr_t * attr);
+
+PTW32_DLLPORT int PTW32_CDECL pthread_attr_getdetachstate (const pthread_attr_t * attr,
+                                         int *detachstate);
+
+PTW32_DLLPORT int PTW32_CDECL pthread_attr_getstackaddr (const pthread_attr_t * attr,
+                                       void **stackaddr);
+
+PTW32_DLLPORT int PTW32_CDECL pthread_attr_getstacksize (const pthread_attr_t * attr,
+                                       size_t * stacksize);
+
+PTW32_DLLPORT int PTW32_CDECL pthread_attr_setdetachstate (pthread_attr_t * attr,
+                                         int detachstate);
+
+PTW32_DLLPORT int PTW32_CDECL pthread_attr_setstackaddr (pthread_attr_t * attr,
+                                       void *stackaddr);
+
+PTW32_DLLPORT int PTW32_CDECL pthread_attr_setstacksize (pthread_attr_t * attr,
+                                       size_t stacksize);
+
+PTW32_DLLPORT int PTW32_CDECL pthread_attr_getschedparam (const pthread_attr_t *attr,
+                                        struct sched_param *param);
+
+PTW32_DLLPORT int PTW32_CDECL pthread_attr_setschedparam (pthread_attr_t *attr,
+                                        const struct sched_param *param);
+
+PTW32_DLLPORT int PTW32_CDECL pthread_attr_setschedpolicy (pthread_attr_t *,
+                                         int);
+
+PTW32_DLLPORT int PTW32_CDECL pthread_attr_getschedpolicy (const pthread_attr_t *,
+                                         int *);
+
+PTW32_DLLPORT int PTW32_CDECL pthread_attr_setinheritsched(pthread_attr_t * attr,
+                                         int inheritsched);
+
+PTW32_DLLPORT int PTW32_CDECL pthread_attr_getinheritsched(const pthread_attr_t * attr,
+                                         int * inheritsched);
+
+PTW32_DLLPORT int PTW32_CDECL pthread_attr_setscope (pthread_attr_t *,
+                                   int);
+
+PTW32_DLLPORT int PTW32_CDECL pthread_attr_getscope (const pthread_attr_t *,
+                                   int *);
+
+/*
+ * PThread Functions
+ */
+PTW32_DLLPORT int PTW32_CDECL pthread_create (pthread_t * tid,
+                            const pthread_attr_t * attr,
+                            void *(PTW32_CDECL *start) (void *),
+                            void *arg);
+
+PTW32_DLLPORT int PTW32_CDECL pthread_detach (pthread_t tid);
+
+PTW32_DLLPORT int PTW32_CDECL pthread_equal (pthread_t t1,
+                           pthread_t t2);
+
+PTW32_DLLPORT void PTW32_CDECL pthread_exit (void *value_ptr);
+
+PTW32_DLLPORT int PTW32_CDECL pthread_join (pthread_t thread,
+                          void **value_ptr);
+
+PTW32_DLLPORT pthread_t PTW32_CDECL pthread_self (void);
+
+PTW32_DLLPORT int PTW32_CDECL pthread_cancel (pthread_t thread);
+
+PTW32_DLLPORT int PTW32_CDECL pthread_setcancelstate (int state,
+                                    int *oldstate);
+
+PTW32_DLLPORT int PTW32_CDECL pthread_setcanceltype (int type,
+                                   int *oldtype);
+
+PTW32_DLLPORT void PTW32_CDECL pthread_testcancel (void);
+
+PTW32_DLLPORT int PTW32_CDECL pthread_once (pthread_once_t * once_control,
+                          void (PTW32_CDECL *init_routine) (void));
+
+#if PTW32_LEVEL >= PTW32_LEVEL_MAX
+PTW32_DLLPORT ptw32_cleanup_t * PTW32_CDECL ptw32_pop_cleanup (int execute);
+
+PTW32_DLLPORT void PTW32_CDECL ptw32_push_cleanup (ptw32_cleanup_t * cleanup,
+                                 ptw32_cleanup_callback_t routine,
+                                 void *arg);
+#endif /* PTW32_LEVEL >= PTW32_LEVEL_MAX */
+
+/*
+ * Thread Specific Data Functions
+ */
+PTW32_DLLPORT int PTW32_CDECL pthread_key_create (pthread_key_t * key,
+                                void (PTW32_CDECL *destructor) (void *));
+
+PTW32_DLLPORT int PTW32_CDECL pthread_key_delete (pthread_key_t key);
+
+PTW32_DLLPORT int PTW32_CDECL pthread_setspecific (pthread_key_t key,
+                                 const void *value);
+
+PTW32_DLLPORT void * PTW32_CDECL pthread_getspecific (pthread_key_t key);
+
+
+/*
+ * Mutex Attribute Functions
+ */
+PTW32_DLLPORT int PTW32_CDECL pthread_mutexattr_init (pthread_mutexattr_t * attr);
+
+PTW32_DLLPORT int PTW32_CDECL pthread_mutexattr_destroy (pthread_mutexattr_t * attr);
+
+PTW32_DLLPORT int PTW32_CDECL pthread_mutexattr_getpshared (const pthread_mutexattr_t
+                                          * attr,
+                                          int *pshared);
+
+PTW32_DLLPORT int PTW32_CDECL pthread_mutexattr_setpshared (pthread_mutexattr_t * attr,
+                                          int pshared);
+
+PTW32_DLLPORT int PTW32_CDECL pthread_mutexattr_settype (pthread_mutexattr_t * attr, int kind);
+PTW32_DLLPORT int PTW32_CDECL pthread_mutexattr_gettype (const pthread_mutexattr_t * attr, int *kind);
+
+PTW32_DLLPORT int PTW32_CDECL pthread_mutexattr_setrobust(
+                                           pthread_mutexattr_t *attr,
+                                           int robust);
+PTW32_DLLPORT int PTW32_CDECL pthread_mutexattr_getrobust(
+                                           const pthread_mutexattr_t * attr,
+                                           int * robust);
+
+/*
+ * Barrier Attribute Functions
+ */
+PTW32_DLLPORT int PTW32_CDECL pthread_barrierattr_init (pthread_barrierattr_t * attr);
+
+PTW32_DLLPORT int PTW32_CDECL pthread_barrierattr_destroy (pthread_barrierattr_t * attr);
+
+PTW32_DLLPORT int PTW32_CDECL pthread_barrierattr_getpshared (const pthread_barrierattr_t
+                                            * attr,
+                                            int *pshared);
+
+PTW32_DLLPORT int PTW32_CDECL pthread_barrierattr_setpshared (pthread_barrierattr_t * attr,
+                                            int pshared);
+
+/*
+ * Mutex Functions
+ */
+PTW32_DLLPORT int PTW32_CDECL pthread_mutex_init (pthread_mutex_t * mutex,
+                                const pthread_mutexattr_t * attr);
+
+PTW32_DLLPORT int PTW32_CDECL pthread_mutex_destroy (pthread_mutex_t * mutex);
+
+PTW32_DLLPORT int PTW32_CDECL pthread_mutex_lock (pthread_mutex_t * mutex);
+
+PTW32_DLLPORT int PTW32_CDECL pthread_mutex_timedlock(pthread_mutex_t * mutex,
+                                    const struct timespec *abstime);
+
+PTW32_DLLPORT int PTW32_CDECL pthread_mutex_trylock (pthread_mutex_t * mutex);
+
+PTW32_DLLPORT int PTW32_CDECL pthread_mutex_unlock (pthread_mutex_t * mutex);
+
+PTW32_DLLPORT int PTW32_CDECL pthread_mutex_consistent (pthread_mutex_t * mutex);
+
+/*
+ * Spinlock Functions
+ */
+PTW32_DLLPORT int PTW32_CDECL pthread_spin_init (pthread_spinlock_t * lock, int pshared);
+
+PTW32_DLLPORT int PTW32_CDECL pthread_spin_destroy (pthread_spinlock_t * lock);
+
+PTW32_DLLPORT int PTW32_CDECL pthread_spin_lock (pthread_spinlock_t * lock);
+
+PTW32_DLLPORT int PTW32_CDECL pthread_spin_trylock (pthread_spinlock_t * lock);
+
+PTW32_DLLPORT int PTW32_CDECL pthread_spin_unlock (pthread_spinlock_t * lock);
+
+/*
+ * Barrier Functions
+ */
+PTW32_DLLPORT int PTW32_CDECL pthread_barrier_init (pthread_barrier_t * barrier,
+                                  const pthread_barrierattr_t * attr,
+                                  unsigned int count);
+
+PTW32_DLLPORT int PTW32_CDECL pthread_barrier_destroy (pthread_barrier_t * barrier);
+
+PTW32_DLLPORT int PTW32_CDECL pthread_barrier_wait (pthread_barrier_t * barrier);
+
+/*
+ * Condition Variable Attribute Functions
+ */
+PTW32_DLLPORT int PTW32_CDECL pthread_condattr_init (pthread_condattr_t * attr);
+
+PTW32_DLLPORT int PTW32_CDECL pthread_condattr_destroy (pthread_condattr_t * attr);
+
+PTW32_DLLPORT int PTW32_CDECL pthread_condattr_getpshared (const pthread_condattr_t * attr,
+                                         int *pshared);
+
+PTW32_DLLPORT int PTW32_CDECL pthread_condattr_setpshared (pthread_condattr_t * attr,
+                                         int pshared);
+
+/*
+ * Condition Variable Functions
+ */
+PTW32_DLLPORT int PTW32_CDECL pthread_cond_init (pthread_cond_t * cond,
+                               const pthread_condattr_t * attr);
+
+PTW32_DLLPORT int PTW32_CDECL pthread_cond_destroy (pthread_cond_t * cond);
+
+PTW32_DLLPORT int PTW32_CDECL pthread_cond_wait (pthread_cond_t * cond,
+                               pthread_mutex_t * mutex);
+
+PTW32_DLLPORT int PTW32_CDECL pthread_cond_timedwait (pthread_cond_t * cond,
+                                    pthread_mutex_t * mutex,
+                                    const struct timespec *abstime);
+
+PTW32_DLLPORT int PTW32_CDECL pthread_cond_signal (pthread_cond_t * cond);
+
+PTW32_DLLPORT int PTW32_CDECL pthread_cond_broadcast (pthread_cond_t * cond);
+
+/*
+ * Scheduling
+ */
+PTW32_DLLPORT int PTW32_CDECL pthread_setschedparam (pthread_t thread,
+                                   int policy,
+                                   const struct sched_param *param);
+
+PTW32_DLLPORT int PTW32_CDECL pthread_getschedparam (pthread_t thread,
+                                   int *policy,
+                                   struct sched_param *param);
+
+PTW32_DLLPORT int PTW32_CDECL pthread_setconcurrency (int);
+ 
+PTW32_DLLPORT int PTW32_CDECL pthread_getconcurrency (void);
+
+/*
+ * Read-Write Lock Functions
+ */
+PTW32_DLLPORT int PTW32_CDECL pthread_rwlock_init(pthread_rwlock_t *lock,
+                                const pthread_rwlockattr_t *attr);
+
+PTW32_DLLPORT int PTW32_CDECL pthread_rwlock_destroy(pthread_rwlock_t *lock);
+
+PTW32_DLLPORT int PTW32_CDECL pthread_rwlock_tryrdlock(pthread_rwlock_t *);
+
+PTW32_DLLPORT int PTW32_CDECL pthread_rwlock_trywrlock(pthread_rwlock_t *);
+
+PTW32_DLLPORT int PTW32_CDECL pthread_rwlock_rdlock(pthread_rwlock_t *lock);
+
+PTW32_DLLPORT int PTW32_CDECL pthread_rwlock_timedrdlock(pthread_rwlock_t *lock,
+                                       const struct timespec *abstime);
+
+PTW32_DLLPORT int PTW32_CDECL pthread_rwlock_wrlock(pthread_rwlock_t *lock);
+
+PTW32_DLLPORT int PTW32_CDECL pthread_rwlock_timedwrlock(pthread_rwlock_t *lock,
+                                       const struct timespec *abstime);
+
+PTW32_DLLPORT int PTW32_CDECL pthread_rwlock_unlock(pthread_rwlock_t *lock);
+
+PTW32_DLLPORT int PTW32_CDECL pthread_rwlockattr_init (pthread_rwlockattr_t * attr);
+
+PTW32_DLLPORT int PTW32_CDECL pthread_rwlockattr_destroy (pthread_rwlockattr_t * attr);
+
+PTW32_DLLPORT int PTW32_CDECL pthread_rwlockattr_getpshared (const pthread_rwlockattr_t * attr,
+                                           int *pshared);
+
+PTW32_DLLPORT int PTW32_CDECL pthread_rwlockattr_setpshared (pthread_rwlockattr_t * attr,
+                                           int pshared);
+
+#if PTW32_LEVEL >= PTW32_LEVEL_MAX - 1
+
+/*
+ * Signal Functions. Should be defined in <signal.h> but MSVC and MinGW32
+ * already have signal.h that don't define these.
+ */
+PTW32_DLLPORT int PTW32_CDECL pthread_kill(pthread_t thread, int sig);
+
+/*
+ * Non-portable functions
+ */
+
+/*
+ * Compatibility with Linux.
+ */
+PTW32_DLLPORT int PTW32_CDECL pthread_mutexattr_setkind_np(pthread_mutexattr_t * attr,
+                                         int kind);
+PTW32_DLLPORT int PTW32_CDECL pthread_mutexattr_getkind_np(pthread_mutexattr_t * attr,
+                                         int *kind);
+
+/*
+ * Possibly supported by other POSIX threads implementations
+ */
+PTW32_DLLPORT int PTW32_CDECL pthread_delay_np (struct timespec * interval);
+PTW32_DLLPORT int PTW32_CDECL pthread_num_processors_np(void);
+PTW32_DLLPORT unsigned __int64 PTW32_CDECL pthread_getunique_np(pthread_t thread);
+
+/*
+ * Useful if an application wants to statically link
+ * the lib rather than load the DLL at run-time.
+ */
+PTW32_DLLPORT int PTW32_CDECL pthread_win32_process_attach_np(void);
+PTW32_DLLPORT int PTW32_CDECL pthread_win32_process_detach_np(void);
+PTW32_DLLPORT int PTW32_CDECL pthread_win32_thread_attach_np(void);
+PTW32_DLLPORT int PTW32_CDECL pthread_win32_thread_detach_np(void);
+
+/*
+ * Features that are auto-detected at load/run time.
+ */
+PTW32_DLLPORT int PTW32_CDECL pthread_win32_test_features_np(int);
+enum ptw32_features {
+  PTW32_SYSTEM_INTERLOCKED_COMPARE_EXCHANGE = 0x0001, /* System provides it. */
+  PTW32_ALERTABLE_ASYNC_CANCEL              = 0x0002  /* Can cancel blocked threads. */
+};
+
+/*
+ * Register a system time change with the library.
+ * Causes the library to perform various functions
+ * in response to the change. Should be called whenever
+ * the application's top level window receives a
+ * WM_TIMECHANGE message. It can be passed directly to
+ * pthread_create() as a new thread if desired.
+ */
+PTW32_DLLPORT void * PTW32_CDECL pthread_timechange_handler_np(void *);
+
+#endif /*PTW32_LEVEL >= PTW32_LEVEL_MAX - 1 */
+
+#if PTW32_LEVEL >= PTW32_LEVEL_MAX
+
+/*
+ * Returns the Win32 HANDLE for the POSIX thread.
+ */
+PTW32_DLLPORT HANDLE PTW32_CDECL pthread_getw32threadhandle_np(pthread_t thread);
+/*
+ * Returns the win32 thread ID for POSIX thread.
+ */
+PTW32_DLLPORT DWORD PTW32_CDECL pthread_getw32threadid_np (pthread_t thread);
+
+
+/*
+ * Protected Methods
+ *
+ * This function blocks until the given WIN32 handle
+ * is signaled or pthread_cancel had been called.
+ * This function allows the caller to hook into the
+ * PThreads cancel mechanism. It is implemented using
+ *
+ *              WaitForMultipleObjects
+ *
+ * on 'waitHandle' and a manually reset WIN32 Event
+ * used to implement pthread_cancel. The 'timeout'
+ * argument to TimedWait is simply passed to
+ * WaitForMultipleObjects.
+ */
+PTW32_DLLPORT int PTW32_CDECL pthreadCancelableWait (HANDLE waitHandle);
+PTW32_DLLPORT int PTW32_CDECL pthreadCancelableTimedWait (HANDLE waitHandle,
+                                        DWORD timeout);
+
+#endif /* PTW32_LEVEL >= PTW32_LEVEL_MAX */
+
+/*
+ * Thread-Safe C Runtime Library Mappings.
+ */
+#if !defined(_UWIN)
+#  if defined(NEED_ERRNO)
+     PTW32_DLLPORT int * PTW32_CDECL _errno( void );
+#  else
+#    if !defined(errno)
+#      if (defined(_MT) || defined(_DLL))
+         __declspec(dllimport) extern int * __cdecl _errno(void);
+#        define errno   (*_errno())
+#      endif
+#    endif
+#  endif
+#endif
+
+/*
+ * Some compiler environments don't define some things.
+ */
+#if defined(__BORLANDC__)
+#  define _ftime ftime
+#  define _timeb timeb
+#endif
+
+#if defined(__cplusplus)
+
+/*
+ * Internal exceptions
+ */
+class ptw32_exception {};
+class ptw32_exception_cancel : public ptw32_exception {};
+class ptw32_exception_exit   : public ptw32_exception {};
+
+#endif
+
+#if PTW32_LEVEL >= PTW32_LEVEL_MAX
+
+/* FIXME: This is only required if the library was built using SEH */
+/*
+ * Get internal SEH tag
+ */
+PTW32_DLLPORT DWORD PTW32_CDECL ptw32_get_exception_services_code(void);
+
+#endif /* PTW32_LEVEL >= PTW32_LEVEL_MAX */
+
+#if !defined(PTW32_BUILD)
+
+#if defined(__CLEANUP_SEH)
+
+/*
+ * Redefine the SEH __except keyword to ensure that applications
+ * propagate our internal exceptions up to the library's internal handlers.
+ */
+#define __except( E ) \
+        __except( ( GetExceptionCode() == ptw32_get_exception_services_code() ) \
+                 ? EXCEPTION_CONTINUE_SEARCH : ( E ) )
+
+#endif /* __CLEANUP_SEH */
+
+#if defined(__CLEANUP_CXX)
+
+/*
+ * Redefine the C++ catch keyword to ensure that applications
+ * propagate our internal exceptions up to the library's internal handlers.
+ */
+#if defined(_MSC_VER)
+        /*
+         * WARNING: Replace any 'catch( ... )' with 'PtW32CatchAll'
+         * if you want Pthread-Win32 cancelation and pthread_exit to work.
+         */
+
+#if !defined(PtW32NoCatchWarn)
+
+#pragma message("Specify \"/DPtW32NoCatchWarn\" compiler flag to skip this message.")
+#pragma message("------------------------------------------------------------------")
+#pragma message("When compiling applications with MSVC++ and C++ exception handling:")
+#pragma message("  Replace any 'catch( ... )' in routines called from POSIX threads")
+#pragma message("  with 'PtW32CatchAll' or 'CATCHALL' if you want POSIX thread")
+#pragma message("  cancelation and pthread_exit to work. For example:")
+#pragma message("")
+#pragma message("    #if defined(PtW32CatchAll)")
+#pragma message("      PtW32CatchAll")
+#pragma message("    #else")
+#pragma message("      catch(...)")
+#pragma message("    #endif")
+#pragma message("        {")
+#pragma message("          /* Catchall block processing */")
+#pragma message("        }")
+#pragma message("------------------------------------------------------------------")
+
+#endif
+
+#define PtW32CatchAll \
+        catch( ptw32_exception & ) { throw; } \
+        catch( ... )
+
+#else /* _MSC_VER */
+
+#define catch( E ) \
+        catch( ptw32_exception & ) { throw; } \
+        catch( E )
+
+#endif /* _MSC_VER */
+
+#endif /* __CLEANUP_CXX */
+
+#endif /* ! PTW32_BUILD */
+
+#if defined(__cplusplus)
+}                               /* End of extern "C" */
+#endif                          /* __cplusplus */
+
+#if defined(PTW32__HANDLE_DEF)
+# undef HANDLE
+#endif
+#if defined(PTW32__DWORD_DEF)
+# undef DWORD
+#endif
+
+#undef PTW32_LEVEL
+#undef PTW32_LEVEL_MAX
+
+#endif /* ! RC_INVOKED */
+
+#endif /* PTHREAD_H */
diff --git a/pthreads/sched.h b/pthreads/sched.h
new file mode 100644
index 0000000..f36a97a
--- /dev/null
+++ b/pthreads/sched.h
@@ -0,0 +1,183 @@
+/*
+ * 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 at 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 */
+
diff --git a/pthreads/semaphore.h b/pthreads/semaphore.h
new file mode 100644
index 0000000..c6e9407
--- /dev/null
+++ b/pthreads/semaphore.h
@@ -0,0 +1,169 @@
+/*
+ * 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 at 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 */
diff --git a/public_html/config.js b/public_html/config.js
new file mode 100644
index 0000000..c4d7ecd
--- /dev/null
+++ b/public_html/config.js
@@ -0,0 +1,33 @@
+// --------------------------------------------------------
+//
+// 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)";
+
+// -- 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);
+
diff --git a/public_html/coolclock/coolclock.js b/public_html/coolclock/coolclock.js
new file mode 100644
index 0000000..4411974
--- /dev/null
+++ b/public_html/coolclock/coolclock.js
@@ -0,0 +1,318 @@
+/**
+ * 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);
diff --git a/public_html/coolclock/excanvas.js b/public_html/coolclock/excanvas.js
new file mode 100644
index 0000000..3e1aedf
--- /dev/null
+++ b/public_html/coolclock/excanvas.js
@@ -0,0 +1,785 @@
+// 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
diff --git a/public_html/coolclock/moreskins.js b/public_html/coolclock/moreskins.js
new file mode 100644
index 0000000..e316181
--- /dev/null
+++ b/public_html/coolclock/moreskins.js
@@ -0,0 +1,212 @@
+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 }
+	}
+};
diff --git a/public_html/extension.js b/public_html/extension.js
new file mode 100644
index 0000000..f71fe17
--- /dev/null
+++ b/public_html/extension.js
@@ -0,0 +1,19 @@
+// -----------------------------------------------------
+//
+// 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
+}
diff --git a/public_html/gmap.html b/public_html/gmap.html
new file mode 100644
index 0000000..96f412a
--- /dev/null
+++ b/public_html/gmap.html
@@ -0,0 +1,63 @@
+<html>
+	<head>
+		<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&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>
+	</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> </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>
diff --git a/public_html/options.js b/public_html/options.js
new file mode 100644
index 0000000..f4e3627
--- /dev/null
+++ b/public_html/options.js
@@ -0,0 +1,17 @@
+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");
+}
diff --git a/public_html/planeObject.js b/public_html/planeObject.js
new file mode 100644
index 0000000..dfb0130
--- /dev/null
+++ b/public_html/planeObject.js
@@ -0,0 +1,254 @@
+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() {
+			// If this marker is selected we should make it lighter than the rest.
+			if (this.is_selected == true) {
+				this.markerColor = SelectedColor;
+			}
+			
+			// 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;
+		}
+};
diff --git a/public_html/script.js b/public_html/script.js
new file mode 100644
index 0000000..ed2a4dc
--- /dev/null
+++ b/public_html/script.js
@@ -0,0 +1,630 @@
+// 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 += ' <span class="squawk7500"> Squawking: Aircraft Hijacking </span>';
+	} else if (selected && selected.squawk == 7600) { // Radio Failure
+		html += ' <span class="squawk7600"> Squawking: Radio Failure </span>';
+	} else if (selected && selected.squawk == 7700) { // General Emergency
+		html += ' <span class="squawk7700"> Squawking: General Emergency </span>';
+	} else if (selected && selected.flight != '') {
+	    html += ' <a href="http://www.flightstats.com/go/FlightStatus/flightStatusByFlight.do?';
+        html += 'flightNumber='+selected.flight+'" target="_blank">[FlightStats]</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 + '°' + ' (' + normalizeTrack(selected.track, selected.vTrack)[1] +')';
+	} else {
+	    html += 'n/a';
+	}
+	html += '</td><td> </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 + '">Distance from Site: ' + dist +
+                (Metric ? ' km' : ' NM') + '</td></tr>';
+        } // End of SiteShow
+	} else {
+	    if (SiteShow) {
+	        html += '<tr><td colspan="' + columns + '">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>';
+	html += '<td onclick="setASC_DESC(\'5\');sortTable(\'tableinfo\',\'5\');" ' +
+	    'align="right">Track</td>';
+	html += '<td onclick="setASC_DESC(\'6\');sortTable(\'tableinfo\',\'6\');" ' +
+	    'align="right">Msgs</td>';
+	html += '<td onclick="setASC_DESC(\'7\');sortTable(\'tableinfo\',\'7\');" ' +
+	    '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"> </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>';
+    	    }
+			
+			html += '<td align="right">';
+			if (tableplane.vTrack) {
+    			 html += normalizeTrack(tableplane.track, tableplane.vTrack)[2];
+    			 // html += ' (' + normalizeTrack(tableplane.track, tableplane.vTrack)[1] + ')';
+    	    } else {
+    	        html += ' ';
+    	    }
+    	    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 {
+			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');
+}
diff --git a/public_html/style.css b/public_html/style.css
new file mode 100644
index 0000000..86cb053
--- /dev/null
+++ b/public_html/style.css
@@ -0,0 +1,32 @@
+html, body {
+    margin: 0; padding: 0; background-color: #ffffff; font-family: Tahoma, Sans-Serif;
+    font-size: 10pt; overflow: auto;
+}
+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; }
+
diff --git a/rtlsdr/rtl-sdr.h b/rtlsdr/rtl-sdr.h
new file mode 100644
index 0000000..bb028fe
--- /dev/null
+++ b/rtlsdr/rtl-sdr.h
@@ -0,0 +1,366 @@
+/*
+ * rtl-sdr, turns your Realtek RTL2832 based DVB dongle into a SDR receiver
+ * Copyright (C) 2012 by Steve Markgraf <steve at steve-m.de>
+ * Copyright (C) 2012 by Dimitri Stolnikov <horiz0n at 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 */
diff --git a/rtlsdr/rtl-sdr_export.h b/rtlsdr/rtl-sdr_export.h
new file mode 100644
index 0000000..69e178d
--- /dev/null
+++ b/rtlsdr/rtl-sdr_export.h
@@ -0,0 +1,47 @@
+/*
+ * rtl-sdr, turns your Realtek RTL2832 based DVB dongle into a SDR receiver
+ * Copyright (C) 2012 by Hoernchen <la at 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 */
diff --git a/testfiles/modes1.bin b/testfiles/modes1.bin
new file mode 100644
index 0000000..62f7f97
--- /dev/null
+++ b/testfiles/modes1.bin
@@ -0,0 +1,13 @@
+�~}}�~�~����~�~�������~~~�~~~���~�~����~�~}�~�}��x�n{�qzw{t|syvu|��u|v�x�p�|�x�{��������������������~�|�{~�f�t�x�v�~}�����}���������~}��{�w�z�t�v�r}y{rzyvuy{qzy~f�p�}x�y�~������������|����|�~�t�s��y�g~s}xwr��{ygvr~x�o��y�q�|�~~�������������������}��~���}��}pxp��}~�����v���}}�������}������~~~���������}�l�s��~�|���}}�����~��xf~}~�hp�{e~~���~�~���~|����||��~�~��~~~~~�wh}|���~���~�}�~�c��y�l��� [...]
�X�q�m�h���ɦ�����ט�}�e�Qu��_� �8zK{(dWY4We*H��Ws �8�[�.Îvi�d��ʔ��ӧ�����͞�x�x�h�Ep��J�.�`n g7^VK:Pl5WM�*{Y�#��s]�W�|�}���vn������̞�y�x�s�"�I�Q�0{N�+h[M&��R^*Y��|}}~~~���~���������������������~�~����$�b�
}_�~{~}%Mfs
y\���{����~�m聜y�䐛̿������{�_�p�;�e�"�\~�l? ms�Lex{ �l�)�d��yR�o���}~�䐗������|��i�t�B�g�*�^�
�Z[$q]6;fi!Y hj��|
�f�F�l�g�y����ݑ�˾��y}�}�_�4�o�)�`�xzbQ'ju�~c`|
�]�+��x�|t끡�׎��Ę�ݨ���y��L�n�/� i��jucB.is
c]v
�]��|+�5�}�{������̟�t|��y�s�� [...]
+�h�.�i�K�{�}���Ȕ�֨�����o�N�n�;�f�#~l}a>u{xu'Vaz!�e���y�z�\�������ϔ�ѫ����q�x�P�n�}��wr�yR0%p{|y^	�h�*�f�B�w�|�tᄜ�ӎ�����ߨ���v��N�3�j�*�`�&|a[1kd>Een%dby$�o�x�9�u�V�p������َ����|���m�v�@�$�h�&�bp"wn|y9=gp&df|�
+�u�z7�W�}����~����Ȍ���ሞ|�X�t�3��k�|l~yP*ot��}}�~����}���������������~��~~���~�~�~~|~}�~��>�JmKd>��wy��=sKwJ�;��}z����~t����um�����������d�m�V�X�I�H~Kw3��gI"Ec��6sBU� �[�\�ZŇpt�����sr���������so��\�\�K�J�E�BkGkDUWVQHjAgS| �H��tK�]�s�r�������������ˑi|�o�f�e��R�G�/��e;^Ibc
+,?n��5�F�R�J�f�9�w�o�ȑ������������q�_r��L�L�U� s?��^?XL\f @Ov?�?�Q�?��u^�U���u��������ɝox���X�Xt��D�L�F�@kLg at e]Be��7{E�M�F�^�V�q�j����������������x�mk��R�W�H�E|G{=bN\E`b2=q��9�C�^��f�m�p�k�œ����ٯ���Ѓj��b�b�O�L�H�AoJk>i]ReHo/r�;�I�^�U�p�n����Ó�������Ζoy�|�J�Ov��B�H{H{:sZ6OU��||}����������������������~~}~�~~~}~~~�}|��~����������yy��z��x�x�j�ex��}�~|~��jWee��RgdvU�]�_�5�q�j�r�}�}�����zv��̣�~t��v�t�m�=�k�X�X�xWT6fo��Pjb{^*�f��v_�s�y�z�����������������u�V�g}��R� [...]
��o�0�r���^�r�}������Ԏ�Ӣ���~��R��u�,�p~rynN2ol3Sju%{qw{�.�n�M�s��||�����~~����~~~�����~�~~����}��~~~������~{�{��z��|~��Ι��~�|{��e�@��P�5��bNeJ��{~��~~���}�������}~���~����~�{x��k�Q{��}�~�}�����~��~��~���~����������~�~��Kz��W�9��|��~�������~��{|��ů��}}���~~�|}��[�=~��|���{���<yTv��y~��~~�~��~��~~��~�}����}~��}~�~�qbe5jn>C�~y��{`�2�l�?��{~�~��||����ѩy��|�d�j�g�G�b�2|b~-shR-��ms
I&j�{\�/�r�+�O�z�u�{w�����u��Փ�~�_�Y{��_�;�`�+tbe-jjG at cv4]`�(�n��7��tx�c͆��ׅ��緾��ܞs��s�h�v�&�4~��hv t/ngD3��hwa.sf�&��zq�=�`�~|�����ʗ�����Ж�~�jz��e�@�o��-saj.lhJ?js&\�z^�-�l�8�|}~��~~�����������~���~~�~��~��}}�~~��x~��n�J~��}���~�}����~��~~�����~�͂�~z��~{��r�U��������|{��Y]VS��z|�~�~~�~~�������������~~�����~��~�����t|���}y��F�]y��z~�M<vh��+_vuy�)�y}�}�����~~����������~��~������a5zh��{�~~�~� [...]
+iq}(�e��|@�H�z���t���ҍ�{~��w�{�M�q�6�k�)�g}�T(yk5H@ry(|e}4�f�H�j��zs�{��Є�|w�~~~~��������~�~��~~~��{������~��������|u���~}��|��z�|��v�)��wmg*��flCM��~�~�~��~��~�~�~~����}~��u�7�}}�~����~�~��~~��~��~�~~~����~�}��]{��f�9��~����~������~���~��~�~~�����ņ�{{�������{x��k�B}��}����z~��IhLf��z|�}}~�������~�~��������~�~~~~�~���~��3�i� �}~|�~ms7Jkz!o{{}|~~��}|�y���~���������ړ���l�t [...]
+S]y� �g�%�d��uX�����x~�嗗׼���}~��`�r�7�a�
�W�~UT mY.9^gW kd��x�b�E�j�f�����旡t|鹟���e�p|��/� �h�}R��P
mmNVu�{� �k��x:�N�|��셪�ٓ�׺��w��}�|�P�j�,�[��WmwVD*g\%J[hoW~�}x}~}~�}~~~~~}�~�~���������������~���~}���Ex/{Q�&��{x��qv�yЎ���|t�����~s��z�bj��T�E�N�)�]f d:\TI=Nl2ZQ��~S��M΂ko�؉�������شqt���o�Vp��T�6�`� t!��cES;Rc8ONy+oN�+�W�;�i�X�{����vn������֚���g�`�c�5q��E�)z^Y J.��NX6WM}(vO�,�[�?�m�`Є��֘��Ϧ�ö��ܓ�~�[�Mt��O�0�b� n1kTF'��^b M �zB�4�^�F�r�iځ����Ʀ�����ў�{� [...]
+e6��xV�D�j�W�z�u�������wy���ȉz��|�I�\�`�7���Q};kabAblETiwp?�\�=�k�J��wv�����������ȭs���{�w�?�J��S�@x\s:hcZE_m at Zjzy5��|b�0�[�y�oą���y{����Ɩx��z�v�j�W�`�B�i�o4��oa(0LYWx=q_�9�g�B��ss�mǁ���������q}��dž�|�J�]�`�F�a�-��xbD
JK�VsAk\�9�e�F�m�\�x�{���ux�����������y�hz��m��E�^z/��ua.)OW]s<ib�.��x]�M�u�^�x�����sw������œ�w�p�v�.�N�\�;~ct1���zz�~}|~~~~~~��~~�~����������~�~��<�\fLmQ��zw�}9uXyL�O��{x�|~�xx����xp���������{�f�u�R�e�E�U}F}G��`G.'\h�~7uTyJ�
�f�X�]��pw� [...]
?dq>|QyN�I��wY�W�|�|y���됝����n~ˀ��j�5�l�D�XG~D��_E++[h�8wVwF�Q�Y�Z�k�`�y���������������~q��W�i�J�Y}E�QgHrQ^\
3Vn�|5�T�R��h�c�j�}n�ˉ����ږ������r�{�X�k�N�L~�x3�V_PlPNbZ`Rvy\~H�P�_�Z��rx���zz���Ƭ�x����e�l{��R��Q��p;yX\U[S��{y~~~}~}�~}~��~�������~�����������~~����~�;��yoa>��}~�����������~��~���}�Ā�z��~~~��}mm<�|~}~}�{��{Z�O��|{��~������~�����~���~~��|��~����}�|��~�����~Cqfy��{��|�^�{�|~�~|����u|��Ďr��v�jx���~��������� [...]
�\��nk�{�������os���������i�h�U�R�H�EzGw:n[/HW��:gFtH�;�]�
�d�l�i�����ui�����������t�ch��J�I�\� r=��^>\NKeB^Zx }>��uC�T�m�e����ƌ�����luŚ���{�\�Wq��E�F�Y� sOcK`FWd7U��It �C��zQ�/�p�x���zg�����������{�{�g�On��T� {<��h<dIT_NTJq;o[� �T�V�O�p�h���������po�����|Á�g�d�T�I�^� s<��`AXKbj :MsI~-��yE�Q�m�O�{����¢����������}g��_�]�Q�H�K�9y[F `TQ\IWPw.w��M��T��sc�j���{s���꼡sx���}�fn��T�T�R�6y��z~������������~�~�~�~~�~~~~��~�������bd��_t]}��}������~~��~~��}|��v [...]
+��n�?�y�{�{䂒���၀��ۤ���u�{�E�-�~�n�!�fk&rdC1qoF
`}~n� �o�+�?��}���~����֓�ԫ��ဉ�~�:�$�z�v�swmH'~xty"Xnz��l�-�w�x�a�|���񀁋�и��ߊ���]�B�}�q�'�g~$wbY+nh8Cfq%ec}%�c�0�i�K�r�s�}���ꄁ���󖁁�|�U�v�&��|�qr|o@ &*x}zwm�k�*�g�H�s�l�~��ڇ��χ������{�`�q�@�j�"�t�{_Isp.Cxxv{|m��$�s�M�y�|��ㄌ}}����}����������~�}���}�������������~�~��A�n~�
�n~��{�~�������~���������uz����vx��~��}��|�&�o}�{}~{��^w(u��{~��~~�~�~����~�}��������������� [...]
|ps>l[��GKesIl
se��z@�l�_�r�v�~�zw���������}�}�l�C�g{��7�`}F`lk��ASetGp
+~k�D�b�\�m��rtč퐛|x��ܼ�����{p��^�l�R��l�>vW��V at jnPaYa��}7�g�U�j�i�g�}x�Ï����������o�w�V�g�I�`�C�\hErbQTciLkh`��~@�+�s��uo�}����閑yy�������u�px��U�#�j�>�_kGs^TRggGiatE�V��}D�5�t�l�y���������wt��}�p�kr��F�d�L�
ylfDg]��CX_u��{~��������������~�����~~�~���~�}}|}~���~~����M^��~|��|^�Z��qk�y�n����}w���~~����}z����������~~~�~����~~�����~w���~x����~���������~~���������~������������\��rx����x���~�~��~~����������wyCb|�~�������xu�t��x~������x���|v��~�~~~~��~��}~���~���}�~��~�~����������Z��z~���{x����st����o}�y�vv��}����?~p���}~����������}����������~~�~��~x���{x���~��������~���~�~ [...]
gl)?bomm�y��z�x�T�z����눌��⾗����t�w�H�u�u��e� ] xyzp-3aq_]{�e�
�
�p�U�z��鉡�ܓ��‹����y�V�l�2�a��ctQ vv~x. Qv�r|�h��+�}�x�z�ᑝ�ȕ������|�}�C�q�� |s�{b @pi(7swr|w^�
�h�%�8���z�������~��������~�|�z�9�l�� ~r���|�~��~}~�~��~���~�}�������~������~�~�d�C�l��x��}��䑟�ğ�vz���~�}���&�`�
�Wm
vWD+g_'K_nn �g��{�#�s�h�y��接zy�М�����|�a�ly��"�_�
�Wj
tV?-hb%G Ne|�Y�)�]��vI�b���{{�ꓛ���Ζ�눫xs��H��f����\l> km��I\s~U�"�Y�:�g�`�s��慨������߲��r|�t�E�j��� �^��Wf
4 hm��H `c��Y�0�`��tS�p���yz�䗗wr��}�{�}~���~�~���}��~�|��~����� [...]
�c��od�{�����������ns�����lq��N�Z�R� |I��d.kTMRU[AjLo;�H�D�O�X�a�p�n���wo�ȟ����������s�`�Sn��4�K�Kn bR��UG1[t<s8��=��i�a�pĄj�ŵ���uu�������v�t�V�`�L�>{��)tLlP&^eBYOh=�GF�B��qP�i�y�~��r��~�����~~�����}�~~���~�~~�~�����}~�~�~��O�E��pU�i��t}��~��~����~~~����~��}{��saQ>��|~����{��xP�^��v|����~���|�Ȫ��x}��~��������������������~����~~~�������\�{�~�݈���ɺ�}��ڂx��x�Rz���~{���Np>��}y����~����~~����~�����~��~x��~�hy~��~��~}~ [...]
�v�}{G�b�}��܍�y{��뿒�ی�z{��W�,�n����zj\-nd>Gil(ed��} �i�6�8�w�l�|��ԉ��ƕ�y�ܝ���t�vy�����~���~����������~��~�~~~���������~[Ccd��/`b�}(�p�}Eɀ�z�{؃�}~��x|��ɘzy��~�~������~�������}��{w�hт����~�~�~����~�������~~���������tՁ���ʁ|~���~����~��~~����~���~-�h��}z����z��Ѓ~}�~��~��}u��k�Xu��~���}��~�~���~�����~�����~~~}��~~��;Mhw%l~�|��{l�F�s�dځ�~~�~���}�����x~z��9�4�d�,av(s`S3mm/ [...]
+AW��2r9yS� �F��qZ�_���zĝ��ű�����›�x�|�l�*�Fv��3�AoEr5g[ UYGl)f��C� �H��v]�N�u�����ui���������u�w�l�#�X�C�?|H|'��dJ
AW��Fr �8��tG�L�l�R�w�����tj������˜�r�t�j�$�By��H� |FgJP4��O] NHuD�*��yP�#�d�y�rǑ���wm���̵��|Ƅ�a�e�O�L�K�+��j6g<c`N`Es't��H� �L��mi�pń�����������Ԛf~�l�h�f��>|��3�6oY5 JJ��Lb ]4��|K��O��si�r���uo���������}ͅ�s�9�_�I�E�F�7oMb,��XT 18l�}6�=�R�A�f�Y�{�~���tp����vu��}�}�~~~~~}~�~���~�~~}~}�}~��~|~~z|��~�~���E}7yT�-��zy�rw�rȏ���~u���~u��x�ii��R�M�L�1^k l [...]
+?<��Wo,ii� �-��wd�R�y�nҋ��ҙ��ġ�ȫ��؆�w�P�Hy��Y�3|[y'vk=J at an'U��a} �+��|j�8�a�}���|r���¡�ǫ��؇�x�L�S�^�:�_�{�xeB
?8��er ]
�|[�5�o�7�c�t���ї��Ý�ǫ��ن�z�N�H{��h� �.y^b"��nh26]^y~��d��EɅvy�vՂ����ŗ�зzy���y�l�j�P�d�({�}Vt+ul7
ED`n$\��c�.��~o�E�l�u���͖�����̠�~��o�S�p��2�_z w�vg)=K]r0cb����h�#�OӁt|��ׇ�������ɨ��ԉ�p�c�f�E�e�#}�wXk0gfL=as0Xh} ~"��i�&�U�|�tӈ��ڂ}���}�}}�}�~}��}~������~��~�������~�������DkHjM�5��v��vf�e����ˀq���~�r}��̀i��a�c�Q�J�\� �MnL_5��W[?<q��J� [...]
gfD�S��vN�h�q�q��������������s|�}�Y�u�U�Yw��B�o[��UHlcDc[eNy
+�Y��|R�:�p��s|Ń�����������𢚅�r�z�[�k�M�_�D�YmFxX]S]Y��EdlfE�R��vQ�i�t�s�����������pyȎ���n�v�b�0�a��7�[tOOqlQYVe��8y[J�Y�[�8�q��vx��xv��ݿ��t~���e�u�[�]v��=�^rG{X]Pm[J`]fNtxf�H�Q��wX�W�y�����������������p~�p�K�fy��J�}[��c<n^]]<_r��{}�~��~�������~������~�}�}��~~~}��~���������GSjp?q_y��z��}J�l�k�p�~~��|x��{~����t~Ȃ���g�u�Q�'�l�;�^��c:?(ip��7euj��z;�h�Y�N�y�ā�~t���ϗ�x~Α���t�Z�p{��>�h�=�`k at y_TLpcDabp<}`|C��m��x^�u�����������������u��_�t�O��n�9�\��[:qiNX
Jg}�2�d� [...]
kL��g](:Ik��U{�K��{`�?�o�|�~�q���خ�rz�����z�]�m�b�Mw��N�E}�{~~~�}~�~~��~~������~~���}}�~~�~��������w|�}x��[�d�V�Mz�z��|}��U^Nd��Nw�S��vS�`�q�j������������������y�~�f�k�V�]�O�RwP}LdViTUdZ_NwRsP�O�X�S�i�H�s����}p���՜�����n�s�r�i�0�V|��C�TkRmQhe'0`lOsBv�~E�R�f�4�l�x�t�����zq��ھ��u}���k�gx��]� �P��yDzSaXfWUfXbQ{PrP�O�Z�V�i�f�|�v�����������������l�n�i�%�a�P�B��kFpV[aY\_r	e\~O�K�\�X�n�k��q�������ੜr������m�~�g�g�V�W�O�NpQuN`\cXSlUdNMwS�Q�_�Y�o�i���|��������� [...]
+�]�Y�S��||��~���~����~�~������}~~�~�~~~~���������~����}�w}���}w~z���|y�{�|}���{~���~��~�d�|��||�����y}����|~�~�����|��M�Q~�{~~���~��~�}�~���}��~�~~��~~����~��}��e�|��ˁ��������Ɉ�}��~|��t�2}v�yd%R2{}zy,R'k}�r�7�o�M�q�d�{��dž���������Ɨ���x�y�]�o�H�j�:�fy9xhZ>ur9G)Wz�o|3�l�C�o�W�w�q���ƅ������~��͊�}�h�S�~�v�9�n�'u"�}ztPEmt>ahx8}j�<�k�K�q�c�z��ɂ��ѷ˄���נۈ�}��V�H�p�?�j�3�xyuZ<ppCVjv9qg~7�n�6�=��|�pڈ܀�������ϩښ�~���c�Q�q�D�i�:�iq3~w [...]
\ No newline at end of file
diff --git a/tools/debug.html b/tools/debug.html
new file mode 100644
index 0000000..4d56d34
--- /dev/null
+++ b/tools/debug.html
@@ -0,0 +1,193 @@
+<!DOCTYPE html>
+<html>
+<body>
+<head>
+<script>
+var frames = [];
+var currentFrame = 0;
+
+var modes_checksum_table = [
+0x3935ea, 0x1c9af5, 0xf1b77e, 0x78dbbf, 0xc397db, 0x9e31e9, 0xb0e2f0, 0x587178,
+0x2c38bc, 0x161c5e, 0x0b0e2f, 0xfa7d13, 0x82c48d, 0xbe9842, 0x5f4c21, 0xd05c14,
+0x682e0a, 0x341705, 0xe5f186, 0x72f8c3, 0xc68665, 0x9cb936, 0x4e5c9b, 0xd8d449,
+0x939020, 0x49c810, 0x24e408, 0x127204, 0x093902, 0x049c81, 0xfdb444, 0x7eda22,
+0x3f6d11, 0xe04c8c, 0x702646, 0x381323, 0xe3f395, 0x8e03ce, 0x4701e7, 0xdc7af7,
+0x91c77f, 0xb719bb, 0xa476d9, 0xadc168, 0x56e0b4, 0x2b705a, 0x15b82d, 0xf52612,
+0x7a9309, 0xc2b380, 0x6159c0, 0x30ace0, 0x185670, 0x0c2b38, 0x06159c, 0x030ace,
+0x018567, 0xff38b7, 0x80665f, 0xbfc92b, 0xa01e91, 0xaff54c, 0x57faa6, 0x2bfd53,
+0xea04ad, 0x8af852, 0x457c29, 0xdd4410, 0x6ea208, 0x375104, 0x1ba882, 0x0dd441,
+0xf91024, 0x7c8812, 0x3e4409, 0xe0d800, 0x706c00, 0x383600, 0x1c1b00, 0x0e0d80,
+0x0706c0, 0x038360, 0x01c1b0, 0x00e0d8, 0x00706c, 0x003836, 0x001c1b, 0xfff409,
+0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000,
+0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000,
+0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000
+];
+
+function modesChecksum(frame) {
+    var crc = 0;
+    var bits = frame.bits;
+    var offset = (bits == 112) ? 0 : (112-56);
+
+    for(var j = 0; j < bits; j++) {
+        var byte = j/8;
+        var bit = j%8;
+        var bitmask = 1 << (7-bit);
+
+        /* If bit is set, xor with corresponding table entry. */
+        if (frame.hex.charCodeAt(byte) & bitmask)
+            crc ^= modes_checksum_table[j+offset];
+    }
+    return crc; /* 24 bit checksum. */
+}
+
+function getFrameChecksum(frame) {
+    var res = "";
+    for (j = 0; j < frame.hex.length; j++) {
+        var val = frame.hex.charCodeAt(j);
+        var h = val.toString(16);
+        if (h.length == 1) h = "0"+h;
+        res += h;
+    }
+    return res;
+}
+
+function displayFrame(i) {
+    var div = document.getElementById("frame");
+    var msgbits = 8+112;
+    var frame = frames[i];
+    var padding = frame.mag.length - msgbits*2;
+
+    /* Remove the old representation. */
+    var nodes = div.childNodes.length;
+    for(var j = 0; j < nodes; j++) {
+        div.removeChild(div.firstChild);
+    }
+
+    /* Display the new one. */
+    for (var j = -padding; j < msgbits*2+padding; j++) {
+        var m = frame.mag[j+padding];
+        var type;
+
+        if (j < 0) type = "noise";
+        if (j >= 0 && j < 16) type = "pre";
+        if (j >= 16) {
+            if (!(j % 2)) {
+                var next = frame.mag[j+padding+1];
+                if (m > next)
+                    type = "one";
+                else
+                    type = "zero";
+            }
+            var bit = (j-16)/2;
+            if (bit == frame.fix1 ||
+                bit == frame.fix2)
+                type = "err";
+        }
+        var sample = document.createElement("div");
+        sample.setAttribute("class","sample "+type);
+        sample.setAttribute("title","sample "+j+" ("+m+")");
+        sample.style.left = ""+((j+padding)*4)+"px";
+        sample.style.height = ""+(m/256)+"px";
+        div.appendChild(sample);
+    }
+    document.getElementById("info").innerHTML =
+        "#"+currentFrame+" "+frame.descr+"<br>"+
+        "Bits:"+frame.bits+"<br>"+
+        "DF  : "+(frame.hex.charCodeAt(0) >> 3)+"<br>"+
+        "fix1: "+frame.fix1+"<br>"+
+        "fix2: "+frame.fix2+"<br>"+
+        "hex : "+getFrameChecksum(frame)+"<br>"+
+        "crc (computed): "+modesChecksum(frame).toString(16)+"<br>";
+}
+
+function recomputeHex(frame) {
+    var padding = frame.mag.length - (112+8)*2;
+    var b = [];
+    var hex = "";
+
+    /* Get bits */
+    for (var j = 0; j < frame.bits*2; j += 2) {
+        var bit;
+        var l = frame.mag[padding+j+16];
+        var r = frame.mag[padding+j+1+16];
+        if (l > r)
+            bit = 1;
+        else
+            bit = 0;
+        b.push(bit);
+    }
+    /* Pack into bytes */
+    for (j = 0; j < frame.bits; j+= 8) {
+        hex += String.fromCharCode(
+            b[j]<<7 |
+            b[j+1]<<6 |
+            b[j+2]<<5 |
+            b[j+3]<<4 |
+            b[j+4]<<3 |
+            b[j+5]<<2 |
+            b[j+6]<<1 |
+            b[j+7]);
+    }
+    frame.hex = hex;
+}
+
+window.onload = function() {
+    document.getElementById("next").onclick = function() {
+        if (currentFrame != frames.length-1) currentFrame++;
+        displayFrame(currentFrame);
+    }
+    document.getElementById("prev").onclick = function() {
+        if (currentFrame != 0) currentFrame--;
+        displayFrame(currentFrame);
+    }
+    document.getElementById("re").onclick = function() {
+        recomputeHex(frames[currentFrame]);
+        displayFrame(currentFrame);
+    }
+    displayFrame(currentFrame);
+}
+</script>
+<script src="frames.js"></script>
+<style>
+#frame {
+    width: 1024px;
+    height: 255px;
+    border: 1px #aaa solid;
+    position: relative;
+}
+.sample {
+    position: absolute;
+    bottom: 0px;
+}
+.pre {
+    width:4px;
+    background-color: orange;
+}
+.one {
+    width:4px;
+    background-color: #0000cc;
+}
+.zero {
+    width:4px;
+    background-color: #aaaaaa;
+}
+.err {
+    width:4px;
+    background-color: #cc6666;
+}
+.noise {
+    width:2px;
+    background-color: #ffffff;
+    border: 1px #aaa dotted;
+}
+</style>
+</head>
+<div id="frame">
+</div>
+<pre id="info">
+</pre>
+<input type="button" id="prev" value="Prev frame">
+<input type="button" id="next" value="Next frame">
+<input type="button" id="re" value="Recompute Hex">
+</body>
+</html>
diff --git a/view1090.c b/view1090.c
new file mode 100644
index 0000000..0b9b8b9
--- /dev/null
+++ b/view1090.c
@@ -0,0 +1,321 @@
+// view1090, a Mode S messages viewer for dump1090 devices.
+//
+// Copyright (C) 2014 by Malcolm Robb <Support at 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 at gmail.com>\n"
+" Copyright (C) 2014 by Malcolm Robb <support at 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);
+}
+//
+//=========================================================================
+//
diff --git a/view1090.dsp b/view1090.dsp
new file mode 100644
index 0000000..de97af8
--- /dev/null
+++ b/view1090.dsp
@@ -0,0 +1,149 @@
+# 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
diff --git a/view1090.h b/view1090.h
new file mode 100644
index 0000000..03ad96d
--- /dev/null
+++ b/view1090.h
@@ -0,0 +1,84 @@
+// view1090, a Mode S messages viewer for dump1090 devices.
+//
+// Copyright (C) 2013 by Malcolm Robb <Support at 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
diff --git a/winstubs.h b/winstubs.h
new file mode 100644
index 0000000..f416668
--- /dev/null
+++ b/winstubs.h
@@ -0,0 +1,110 @@
+// dump1090, a Mode S messages decoder for RTLSDR devices.
+//
+// Copyright (C) 2014 by Malcolm Robb <support at 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 0;} 
+#define snprintf  _snprintf
+#define vsnprintf _vsnprintf
+
+_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

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-hamradio/dump1090.git



More information about the pkg-hamradio-commits mailing list