diff --git a/Release/view1090.exe b/Release/view1090.exe deleted file mode 100644 index 2a879c5..0000000 Binary files a/Release/view1090.exe and /dev/null differ diff --git a/anet.c b/anet.c index 8f8a904..859c98c 100644 --- a/anet.c +++ b/anet.c @@ -28,20 +28,25 @@ * POSSIBILITY OF SUCH DAMAGE. */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#ifndef _WIN32 + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include +#else + #include "winstubs.h" //Put everything Windows specific in here + #include "dump1090.h" +#endif #include "anet.h" @@ -58,7 +63,7 @@ static void anetSetError(char *err, const char *fmt, ...) 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. */ @@ -70,13 +75,21 @@ int anetNonBlock(char *err, int fd) 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, &yes, sizeof(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; @@ -86,7 +99,7 @@ int anetTcpNoDelay(char *err, int fd) int anetSetSendBuffer(char *err, int fd, int buffsize) { - if (setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &buffsize, sizeof(buffsize)) == -1) + if (setsockopt(fd, SOL_SOCKET, SO_SNDBUF, (void*)&buffsize, sizeof(buffsize)) == -1) { anetSetError(err, "setsockopt SO_SNDBUF: %s", strerror(errno)); return ANET_ERR; @@ -97,7 +110,7 @@ int anetSetSendBuffer(char *err, int fd, int buffsize) int anetTcpKeepAlive(char *err, int fd) { int yes = 1; - if (setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, &yes, sizeof(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; } @@ -109,7 +122,7 @@ int anetResolve(char *err, char *host, char *ipbuf) struct sockaddr_in sa; sa.sin_family = AF_INET; - if (inet_aton(host, &sa.sin_addr) == 0) { + if (inet_aton(host, (void*)&sa.sin_addr) == 0) { struct hostent *he; he = gethostbyname(host); @@ -126,13 +139,16 @@ int anetResolve(char *err, char *host, char *ipbuf) 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, &on, sizeof(on)) == -1) { + if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (void*)&on, sizeof(on)) == -1) { anetSetError(err, "setsockopt SO_REUSEADDR: %s", strerror(errno)); return ANET_ERR; } @@ -149,9 +165,10 @@ static int anetTcpGenericConnect(char *err, char *addr, int port, int flags) if ((s = anetCreateSocket(err,AF_INET)) == ANET_ERR) return ANET_ERR; + memset(&sa,0,sizeof(sa)); sa.sin_family = AF_INET; - sa.sin_port = htons(port); - if (inet_aton(addr, &sa.sin_addr) == 0) { + sa.sin_port = htons((uint16_t)port); + if (inet_aton(addr, (void*)&sa.sin_addr) == 0) { struct hostent *he; he = gethostbyname(addr); @@ -188,42 +205,6 @@ int anetTcpNonBlockConnect(char *err, char *addr, int port) return anetTcpGenericConnect(err,addr,port,ANET_CONNECT_NONBLOCK); } -int anetUnixGenericConnect(char *err, char *path, int flags) -{ - int s; - struct sockaddr_un sa; - - if ((s = anetCreateSocket(err,AF_LOCAL)) == ANET_ERR) - return ANET_ERR; - - sa.sun_family = AF_LOCAL; - strncpy(sa.sun_path,path,sizeof(sa.sun_path)-1); - if (flags & ANET_CONNECT_NONBLOCK) { - if (anetNonBlock(err,s) != ANET_OK) - return ANET_ERR; - } - if (connect(s,(struct sockaddr*)&sa,sizeof(sa)) == -1) { - if (errno == EINPROGRESS && - flags & ANET_CONNECT_NONBLOCK) - return s; - - anetSetError(err, "connect: %s", strerror(errno)); - close(s); - return ANET_ERR; - } - return s; -} - -int anetUnixConnect(char *err, char *path) -{ - return anetUnixGenericConnect(err,path,ANET_CONNECT_NONE); -} - -int anetUnixNonBlockConnect(char *err, char *path) -{ - return anetUnixGenericConnect(err,path,ANET_CONNECT_NONBLOCK); -} - /* Like read(2) but make sure 'count' is read before to return * (unless error or EOF condition is encountered) */ int anetRead(int fd, char *buf, int count) @@ -256,6 +237,9 @@ int anetWrite(int fd, char *buf, int count) 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; @@ -265,6 +249,9 @@ static int anetListen(char *err, int s, struct sockaddr *sa, socklen_t len) { * 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; @@ -282,9 +269,9 @@ int anetTcpServer(char *err, int port, char *bindaddr) memset(&sa,0,sizeof(sa)); sa.sin_family = AF_INET; - sa.sin_port = htons(port); + sa.sin_port = htons((uint16_t)port); sa.sin_addr.s_addr = htonl(INADDR_ANY); - if (bindaddr && inet_aton(bindaddr, &sa.sin_addr) == 0) { + if (bindaddr && inet_aton(bindaddr, (void*)&sa.sin_addr) == 0) { anetSetError(err, "invalid bind address"); close(s); return ANET_ERR; @@ -294,34 +281,20 @@ int anetTcpServer(char *err, int port, char *bindaddr) return s; } -int anetUnixServer(char *err, char *path, mode_t perm) -{ - int s; - struct sockaddr_un sa; - - if ((s = anetCreateSocket(err,AF_LOCAL)) == ANET_ERR) - return ANET_ERR; - - memset(&sa,0,sizeof(sa)); - sa.sun_family = AF_LOCAL; - strncpy(sa.sun_path,path,sizeof(sa.sun_path)-1); - if (anetListen(err,s,(struct sockaddr*)&sa,sizeof(sa)) == ANET_ERR) - return ANET_ERR; - if (perm) - chmod(sa.sun_path, perm); - return s; -} - static int anetGenericAccept(char *err, int s, struct sockaddr *sa, socklen_t *len) { int fd; while(1) { fd = accept(s,sa,len); if (fd == -1) { - if (errno == EINTR) +#ifndef _WIN32 + if (errno == EINTR) { continue; - else { +#else + errno = WSAGetLastError(); + if (errno == WSAEWOULDBLOCK) { +#endif + } else { anetSetError(err, "accept: %s", strerror(errno)); - return ANET_ERR; } } break; @@ -341,16 +314,6 @@ int anetTcpAccept(char *err, int s, char *ip, int *port) { return fd; } -int anetUnixAccept(char *err, int s) { - int fd; - struct sockaddr_un sa; - socklen_t salen = sizeof(sa); - if ((fd = anetGenericAccept(err,s,(struct sockaddr*)&sa,&salen)) == ANET_ERR) - return ANET_ERR; - - return fd; -} - int anetPeerToString(int fd, char *ip, int *port) { struct sockaddr_in sa; socklen_t salen = sizeof(sa); diff --git a/coaa1090.obj b/coaa1090.obj index 7e35631..ea337ca 100644 Binary files a/coaa1090.obj and b/coaa1090.obj differ 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 index 70a4d04..e8096a3 100644 --- a/dump1090.c +++ b/dump1090.c @@ -68,7 +68,9 @@ void modesInitConfig(void) { // 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; @@ -87,6 +89,7 @@ void modesInitConfig(void) { 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); @@ -131,6 +134,8 @@ void modesInit(void) { {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); @@ -391,7 +396,7 @@ void showHelp(void) { "| dump1090 ModeS Receiver Ver : " MODES_DUMP1090_VERSION " |\n" "-----------------------------------------------------------------------------\n" "--device-index Select RTL device (default: 0)\n" -"--gain Set gain (default: max gain. Use -100 for auto-gain)\n" +"--gain Set gain (default: max gain. Use -10 for auto-gain)\n" "--enable-agc Enable the Automatic Gain Control (default: off)\n" "--freq Set frequency (default: 1090 Mhz)\n" "--ifile Read data from file (use '-' for stdin)\n" @@ -412,6 +417,8 @@ void showHelp(void) { "--net-bo-port TCP Beast output listen port (default: 30005)\n" "--net-ro-size TCP raw output minimum size (default: 0)\n" "--net-ro-rate TCP raw output memory flush rate (default: 0)\n" +"--net-heartbeat TCP heartbeat rate in seconds (default: 60 sec; 0 to disable)\n" +"--net-buffer TCP buffer size 64Kb * (2^n) (default: n=0, 64Kb)\n" "--lat Reference/receiver latitude for surface posn (opt)\n" "--lon Reference/receiver longitude for surface posn (opt)\n" "--fix Enable single-bits error correction using CRC\n" @@ -421,6 +428,7 @@ void showHelp(void) { "--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 Show and reset stats every seconds\n" "--onlyaddr Show only ICAO addresses (testing purposes)\n" "--metric Use metric units (meters, km/h, ...)\n" "--snip Strip IQ file removing samples < level\n" @@ -438,6 +446,121 @@ void showHelp(void) { " 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 \n" +" Copyright (C) 2014 by Malcolm Robb \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 \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; + } +} + + // //========================================================================= // @@ -446,6 +569,8 @@ void showHelp(void) { // from the net, refreshing the screen in interactive mode, and so forth // void backgroundTasks(void) { + static time_t next_stats; + if (Modes.net) { modesReadFromClients(); } @@ -459,6 +584,77 @@ void backgroundTasks(void) { 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; } // //========================================================================= @@ -475,9 +671,9 @@ int main(int argc, char **argv) { int more = j+1 < argc; // There are more arguments if (!strcmp(argv[j],"--device-index") && more) { - Modes.dev_index = atoi(argv[++j]); + 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 + 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) { @@ -503,7 +699,9 @@ int main(int argc, char **argv) { } else if (!strcmp(argv[j],"--net-only")) { Modes.net = 1; Modes.net_only = 1; - } else if (!strcmp(argv[j],"--net-ro-size") && more) { + } 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]); @@ -522,6 +720,8 @@ int main(int argc, char **argv) { 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")) { @@ -557,7 +757,9 @@ int main(int argc, char **argv) { f++; } } else if (!strcmp(argv[j],"--stats")) { - Modes.stats = 1; + 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); @@ -582,6 +784,11 @@ int main(int argc, char **argv) { } } +#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);} @@ -597,7 +804,13 @@ int main(int argc, char **argv) { } else { if (Modes.filename[0] == '-' && Modes.filename[1] == '\0') { Modes.fd = STDIN_FILENO; - } else if ((Modes.fd = open(Modes.filename,O_RDONLY)) == -1) { + } else if ((Modes.fd = open(Modes.filename, +#ifdef _WIN32 + (O_RDONLY | O_BINARY) +#else + (O_RDONLY) +#endif + )) == -1) { perror("Opening data file"); exit(1); } @@ -640,6 +853,7 @@ int main(int argc, char **argv) { // 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; } @@ -654,7 +868,7 @@ int main(int argc, char **argv) { // 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); @@ -666,37 +880,7 @@ int main(int argc, char **argv) { // If --stats were given, print statistics if (Modes.stats) { - printf("\n\n"); - if (Modes.interactive) - interactiveShowData(); - 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); + display_stats(); } if (Modes.filename == NULL) { 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 index 28d7cf3..b7adae3 100644 --- a/dump1090.h +++ b/dump1090.h @@ -30,14 +30,14 @@ #ifndef __DUMP1090_H #define __DUMP1090_H -// File Version number +// 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.08.2302.14" +#define MODES_DUMP1090_VERSION "1.09.0608.14" // ============================= Include files ========================== @@ -62,11 +62,12 @@ #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, +// 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 @@ -75,8 +76,9 @@ #else #define MODES_USER_LATITUDE_DFLT (0.0) #define MODES_USER_LONGITUDE_DFLT (0.0) -#endif +#endif +#define MODES_DEFAULT_PPM 52 #define MODES_DEFAULT_RATE 2000000 #define MODES_DEFAULT_FREQ 1090000000 #define MODES_DEFAULT_WIDTH 1000 @@ -114,7 +116,7 @@ #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_SIZE (1500) #define MODES_RAWOUT_BUF_FLUSH (MODES_RAWOUT_BUF_SIZE - 200) #define MODES_RAWOUT_BUF_RATE (1000) // 1000 * 64mS = 1 Min approx @@ -137,12 +139,12 @@ #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_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_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) @@ -163,8 +165,9 @@ #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_MAX_FD 1024 #define MODES_NET_INPUT_RAW_PORT 30001 #define MODES_NET_OUTPUT_RAW_PORT 30002 #define MODES_NET_OUTPUT_SBS_PORT 30003 @@ -173,6 +176,7 @@ #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 @@ -184,10 +188,11 @@ // Structure used to describe a networking client struct 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 + 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 @@ -222,6 +227,16 @@ struct aircraft { 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; @@ -232,7 +247,7 @@ struct { // Internal state 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 iDataReady; // Fifo content count int iDataLost; // Count of missed buffers uint16_t *pFileData; // Raw IQ samples buffer (from a File) @@ -254,20 +269,19 @@ struct { // Internal state // Networking char aneterr[ANET_ERR_LEN]; - struct client *clients[MODES_NET_MAX_FD]; // Our clients - int maxfd; // Greatest fd currently active - 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 + 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 + WSADATA wsaData; // Windows socket initialisation #endif // Configuration @@ -281,6 +295,8 @@ struct { // Internal state 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 @@ -290,6 +306,7 @@ struct { // Internal state 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 @@ -309,6 +326,12 @@ struct { // Internal state // 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; @@ -323,7 +346,7 @@ struct { // Internal state // 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; @@ -339,10 +362,13 @@ struct { // Internal state // 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. @@ -410,7 +436,7 @@ void decodeModesMessage (struct modesMessage *mm, unsigned char *msg); void displayModesMessage(struct modesMessage *mm); void useModesMessage (struct modesMessage *mm); void computeMagnitudeVector(uint16_t *pData); -void decodeCPR (struct aircraft *a, int fflag, int surface); +int decodeCPR (struct aircraft *a, int fflag, int surface); int decodeCPRrelative (struct aircraft *a, int fflag, int surface); void modesInitErrorInfo (); // @@ -420,6 +446,8 @@ 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 diff --git a/dump1090.sh b/dump1090.sh index e1c0351..d1b63e5 100644 --- a/dump1090.sh +++ b/dump1090.sh @@ -13,7 +13,7 @@ ## 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" +PROG_ARGS="--quiet --net --net-ro-size 500 --net-ro-rate 5 --net-buffer 5" PIDFILE="/var/run/dump1090.pid" start() { diff --git a/interactive.c b/interactive.c index b2ce05a..4f7e029 100644 --- a/interactive.c +++ b/interactive.c @@ -42,6 +42,87 @@ static uint64_t mstime(void) { 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 @@ -70,7 +151,7 @@ struct aircraft *interactiveCreateAircraft(struct modesMessage *mm) { } else { mm->altitude = modeC * 100; mm->bFlags |= MODES_ACFLAGS_ALTITUDE_VALID; - } + } } return (a); } @@ -113,7 +194,7 @@ struct aircraft *interactiveFindAircraft(uint32_t addr) { // // 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; @@ -127,12 +208,12 @@ void interactiveUpdateAircraftModeA(struct aircraft *a) { b->modeAcount = a->messages; b->modeACflags |= MODEAC_MSG_MODEA_HIT; a->modeACflags |= MODEAC_MSG_MODEA_HIT; - if ( (b->modeAcount > 0) && - ( (b->modeCcount > 1) + 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) { @@ -143,7 +224,7 @@ void interactiveUpdateAircraftModeA(struct aircraft *a) { b->modeCcount = a->messages; b->modeACflags |= MODEAC_MSG_MODEC_HIT; a->modeACflags |= MODEAC_MSG_MODEC_HIT; - if ( (b->modeAcount > 0) && + 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 } @@ -160,7 +241,7 @@ void interactiveUpdateAircraftModeS() { while(a) { int flags = a->modeACflags; - if (flags & MODEAC_MSG_FLAG) { // find any fudged ICAO records + 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); @@ -179,7 +260,7 @@ 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)) + if (Modes.check_crc && (mm->crcok == 0) && (mm->correctedbits == 0)) return NULL; // Lookup our aircraft or create a new one @@ -258,10 +339,11 @@ struct aircraft *interactiveReceiveData(struct modesMessage *mm) { // 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; @@ -273,23 +355,23 @@ struct aircraft *interactiveReceiveData(struct modesMessage *mm) { a->even_cprtime = mstime(); } - if (((mm->bFlags | a->bFlags) & MODES_ACFLAGS_LLEITHER_VALID) == MODES_ACFLAGS_LLBOTH_VALID) { - // If we now have both even and odd, decode the CPR - - // Try relative CPR first - if (decodeCPRrelative(a, (mm->bFlags & MODES_ACFLAGS_LLODD_VALID), (mm->bFlags & MODES_ACFLAGS_AOG))) { - // If relative CPR fails then try global if the two data are less than 10 seconds apart - if (abs((int)(a->even_cprtime - a->odd_cprtime)) <= 10000) { - decodeCPR(a, (mm->bFlags & MODES_ACFLAGS_LLODD_VALID), (mm->bFlags & MODES_ACFLAGS_AOG)); - } + // 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; } + } - //If we sucessfully decoded, back copy the results to mm so that we can print them in list output - if (a->bFlags & MODES_ACFLAGS_LATLON_VALID) { - mm->bFlags |= MODES_ACFLAGS_LATLON_VALID; - mm->fLat = a->lat; - mm->fLon = a->lon; - } + // 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; } } @@ -298,20 +380,25 @@ struct aircraft *interactiveReceiveData(struct modesMessage *mm) { if (mm->msgtype == 32) { int flags = a->modeACflags; - if ((flags & (MODEAC_MSG_MODEC_HIT | MODEAC_MSG_MODEC_OLD)) == MODEAC_MSG_MODEC_OLD) { + 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. + // 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); @@ -332,10 +419,10 @@ void interactiveShowData(void) { if ((mstime() - Modes.interactive_last_update) < MODES_INTERACTIVE_REFRESH_TIME) {return;} - Modes.interactive_last_update = mstime(); + 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 + // 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(); @@ -379,7 +466,7 @@ void interactiveShowData(void) { altitude = (int) (altitude / 3.2828); speed = (int) (speed * 1.852); } - + if (a->bFlags & MODES_ACFLAGS_SQUAWK_VALID) { snprintf(strSquawk,5,"%04x", a->modeA);} @@ -388,10 +475,10 @@ void interactiveShowData(void) { 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) { @@ -426,8 +513,8 @@ void interactiveShowData(void) { } 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", + + 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)); } @@ -448,22 +535,24 @@ void interactiveRemoveStaleAircrafts(void) { struct aircraft *prev = NULL; time_t now = time(NULL); - while(a) { - if ((now - a->seen) > Modes.interactive_delete_ttl) { - struct aircraft *next = a->next; - // Remove the element from the linked list, with care - // if we are removing the first element + // Only do cleanup once per second + if (Modes.last_cleanup_time != now) { + Modes.last_cleanup_time = now; - if (!prev) - Modes.aircrafts = next; - else - prev->next = next; + interactiveRemoveStaleDF(now); - free(a); - a = next; - } else { - prev = a; - a = a->next; + 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/mode_s.c b/mode_s.c index 84bef2d..bb0da2c 100644 --- a/mode_s.c +++ b/mode_s.c @@ -746,7 +746,7 @@ int decodeMovementField(int movement) { // // Capability table char *ca_str[8] = { - /* 0 */ "Level 1 (Survillance Only)", + /* 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)", @@ -779,6 +779,20 @@ char *fs_str[8] = { /* 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" +}; // //========================================================================= // @@ -797,6 +811,8 @@ char *getMEDescription(int metype, int mesub) { 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) @@ -891,6 +907,10 @@ void decodeModesMessage(struct modesMessage *mm, unsigned char *msg) { 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 @@ -944,7 +964,7 @@ void decodeModesMessage(struct modesMessage *mm, unsigned char *msg) { 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 = msg[4] & 7; // Extended squitter message subtype + int mesub = mm->mesub = (metype == 29 ? ((msg[4]&6)>>1) : (msg[4] & 7)); // Extended squitter message subtype // Decode the extended squitter message @@ -966,32 +986,6 @@ void decodeModesMessage(struct modesMessage *mm, unsigned char *msg) { mm->flight[8] = '\0'; - } else if (metype >= 5 && metype <= 18) { // 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 == 19) { // Airborne Velocity Message // Presumably airborne if we get an Airborne Velocity Message @@ -1060,6 +1054,61 @@ void decodeModesMessage(struct modesMessage *mm, unsigned char *msg) { 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 + } } @@ -1159,8 +1208,8 @@ void displayModesMessage(struct modesMessage *mm) { } 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 Emergecy/Priority Status - printf(" BDS 6,1 Emergecy/Priority Status\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"); @@ -1177,7 +1226,7 @@ void displayModesMessage(struct modesMessage *mm) { 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 : %x\n", mm->modeA); + printf(" Squawk : %04x\n", mm->modeA); printf(" ICAO Address : %06x\n", mm->addr); if (mm->msgtype == 21) { @@ -1193,8 +1242,8 @@ void displayModesMessage(struct modesMessage *mm) { } 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 Emergecy/Priority Status - printf(" BDS 6,1 Emergecy/Priority Status\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"); @@ -1236,20 +1285,6 @@ void displayModesMessage(struct modesMessage *mm) { printf(" Aircraft Type : %c%d\n", ('A' + 4 - mm->metype), mm->mesub); printf(" Identification : %s\n", mm->flight); - //} else if (mm->metype >= 5 && mm->metype <= 8) { // Surface position - - } else if (mm->metype >= 9 && mm->metype <= 18) { // 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 == 19) { // Airborne Velocity if (mm->mesub == 1 || mm->mesub == 2) { printf(" EW status : %s\n", (mm->bFlags & MODES_ACFLAGS_EWSPEED_VALID) ? "Valid" : "Unavailable"); @@ -1273,8 +1308,32 @@ void displayModesMessage(struct modesMessage *mm) { printf(" Unrecognized ME subtype: %d subtype: %d\n", mm->metype, mm->mesub); } - //} else if (mm->metype >= 20 && mm->metype <= 22) { // Airborne position GNSS + } 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); } @@ -1297,20 +1356,6 @@ void displayModesMessage(struct modesMessage *mm) { printf(" Aircraft Type : %c%d\n", ('A' + 4 - mm->metype), mm->mesub); printf(" Identification : %s\n", mm->flight); - //} else if (mm->metype >= 5 && mm->metype <= 8) { // Surface position - - } else if (mm->metype >= 9 && mm->metype <= 18) { // 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 == 19) { // Airborne Velocity if (mm->mesub == 1 || mm->mesub == 2) { printf(" EW status : %s\n", (mm->bFlags & MODES_ACFLAGS_EWSPEED_VALID) ? "Valid" : "Unavailable"); @@ -1334,7 +1379,17 @@ void displayModesMessage(struct modesMessage *mm) { printf(" Unrecognized ME subtype: %d subtype: %d\n", mm->metype, mm->mesub); } - //} else if (mm->metype >= 20 && mm->metype <= 22) { // Airborne position GNSS + } 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); @@ -1774,7 +1829,7 @@ void detectModeS(uint16_t *m, uint32_t mlen) { // Skip this message if we are sure it's fine if (mm.crcok) { - j += (MODES_PREAMBLE_US+msglen)*2; + j += (MODES_PREAMBLE_US+msglen)*2 - 1; } // Pass data to the next layer @@ -1812,6 +1867,25 @@ void detectModeS(uint16_t *m, uint32_t mlen) { 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; + } } // //========================================================================= @@ -1836,6 +1910,9 @@ void useModesMessage(struct modesMessage *mm) { // Feed output clients if (Modes.net) {modesQueueOutput(mm);} + + // Heartbeat not required whilst we're seeing real messages + Modes.net_heartbeat_count = 0; } } // @@ -1937,11 +2014,8 @@ double cprDlonFunction(double lat, int fflag, int surface) { // // A few remarks: // 1) 131072 is 2^17 since CPR latitude and longitude are encoded in 17 bits. -// 2) We assume that we always received the odd packet as last packet for -// simplicity. This may provide a position that is less fresh of a few -// seconds. // -void decodeCPR(struct aircraft *a, int fflag, int surface) { +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; @@ -1954,19 +2028,36 @@ void decodeCPR(struct aircraft *a, int fflag, int surface) { 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 our receiver base station Lat/Lon - if (0 == (Modes.bUserFlags & MODES_USER_LATLON_VALID)) - {return;} - rlat0 += floor(Modes.fUserLat / 90.0) * 90.0; // Move from 1st quadrant to our quadrant - rlat1 += floor(Modes.fUserLat / 90.0) * 90.0; + // 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; + if (cprNLFunction(rlat0) != cprNLFunction(rlat1)) + return (-1); // Compute ni and the Longitude Index "m" if (fflag) { // Use odd packet. @@ -1984,7 +2075,7 @@ void decodeCPR(struct aircraft *a, int fflag, int surface) { } if (surface) { - a->lon += floor(Modes.fUserLon / 90.0) * 90.0; // Move from 1st quadrant to our quadrant + a->lon += floor(surface_rlon / 90.0) * 90.0; // Move from 1st quadrant to our quadrant } else if (a->lon > 180) { a->lon -= 360; } @@ -1992,6 +2083,8 @@ void decodeCPR(struct aircraft *a, int fflag, int surface) { a->seenLatLon = a->seen; a->timestampLatLon = a->timestamp; a->bFlags |= (MODES_ACFLAGS_LATLON_VALID | MODES_ACFLAGS_LATLON_REL_OK); + + return 0; } // //========================================================================= @@ -2041,6 +2134,12 @@ int decodeCPRrelative(struct aircraft *a, int fflag, int surface) { 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 @@ -2070,4 +2169,4 @@ int decodeCPRrelative(struct aircraft *a, int fflag, int surface) { } // // ===================== Mode S detection and decoding =================== -// \ No newline at end of file +// diff --git a/net_io.c b/net_io.c index 684b961..f3a8397 100644 --- a/net_io.c +++ b/net_io.c @@ -46,36 +46,61 @@ // // Networking "stack" initialization // +struct service { + char *descr; + int *socket; + int port; + int enabled; +}; + +struct service services[MODES_NET_SERVICES_NUM]; + void modesInitNet(void) { - struct { - char *descr; - int *socket; - int port; - } services[MODES_NET_SERVICES_NUM] = { - {"Raw TCP output", &Modes.ros, Modes.net_output_raw_port}, - {"Raw TCP input", &Modes.ris, Modes.net_input_raw_port}, - {"Beast TCP output", &Modes.bos, Modes.net_output_beast_port}, - {"Beast TCP input", &Modes.bis, Modes.net_input_beast_port}, - {"HTTP server", &Modes.https, Modes.net_http_port}, - {"Basestation TCP output", &Modes.sbsos, Modes.net_output_sbs_port} - }; int j; - memset(Modes.clients,0,sizeof(Modes.clients)); - Modes.maxfd = -1; + 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++) { - 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, strerror(errno)); - exit(1); - } - anetNonBlock(Modes.aneterr, s); - *services[j].socket = s; + 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 } // //========================================================================= @@ -83,83 +108,73 @@ void modesInitNet(void) { // 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 // -void modesAcceptClients(void) { +struct client * modesAcceptClients(void) { int fd, port; unsigned int j; struct client *c; - int services[6]; - - services[0] = Modes.ros; - services[1] = Modes.ris; - services[2] = Modes.bos; - services[3] = Modes.bis; - services[4] = Modes.https; - services[5] = Modes.sbsos; for (j = 0; j < MODES_NET_SERVICES_NUM; j++) { - fd = anetTcpAccept(Modes.aneterr, services[j], NULL, &port); - if (fd == -1) continue; + if (services[j].enabled) { + fd = anetTcpAccept(Modes.aneterr, *services[j].socket, NULL, &port); + if (fd == -1) continue; - if (fd >= MODES_NET_MAX_FD) { - close(fd); - return; // Max number of clients reached - } + 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)); - anetNonBlock(Modes.aneterr, fd); - c = (struct client *) malloc(sizeof(*c)); - c->service = services[j]; - c->fd = fd; - c->buflen = 0; - Modes.clients[fd] = c; - anetSetSendBuffer(Modes.aneterr,fd,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++; - if (Modes.maxfd < fd) Modes.maxfd = fd; - if (services[j] == Modes.sbsos) Modes.stat_sbs_connections++; - if (services[j] == Modes.ros) Modes.stat_raw_connections++; - if (services[j] == Modes.bos) Modes.stat_beast_connections++; + j--; // Try again with the same listening port - j--; // Try again with the same listening port - - if (Modes.debug & MODES_DEBUG_NET) - printf("Created new client %d\n", fd); + 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(int fd) { - close(fd); - if (Modes.clients[fd]->service == Modes.sbsos) { - if (Modes.stat_sbs_connections) Modes.stat_sbs_connections--; - } - else if (Modes.clients[fd]->service == Modes.ros) { - if (Modes.stat_raw_connections) Modes.stat_raw_connections--; - } - else if (Modes.clients[fd]->service == Modes.bos) { - if (Modes.stat_beast_connections) Modes.stat_beast_connections--; - } - free(Modes.clients[fd]); - Modes.clients[fd] = NULL; +void modesFreeClient(struct client *c) { - if (Modes.debug & MODES_DEBUG_NET) - printf("Closing client %d\n", fd); - - // If this was our maxfd, scan the clients array to find trhe new max. - // Note that we are sure there is no active fd greater than the closed - // fd, so we scan from fd-1 to 0. - if (Modes.maxfd == fd) { - int j; - - Modes.maxfd = -1; - for (j = fd-1; j >= 0; j--) { - if (Modes.clients[j]) { - Modes.maxfd = j; - break; + // 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); } // //========================================================================= @@ -167,17 +182,23 @@ void modesFreeClient(int fd) { // Send the specified message to all clients listening for a given service // void modesSendAllClients(int service, void *msg, int len) { - int j; - struct client *c; + struct client *c = Modes.clients; - for (j = 0; j <= Modes.maxfd; j++) { - c = Modes.clients[j]; - if (c && c->service == service) { - int nwritten = write(j, msg, len); + 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(j); + modesFreeClient(c); } } + c = next; } } // @@ -272,8 +293,8 @@ void modesSendRawOutput(struct modesMessage *mm) { void modesSendSBSOutput(struct modesMessage *mm) { char msg[256], *p = msg; uint32_t offset; - struct timeb epocTime; - struct tm stTime; + struct timeb epocTime_receive, epocTime_now; + struct tm stTime_receive, stTime_now; int msgType; // @@ -315,26 +336,33 @@ void modesSendSBSOutput(struct modesMessage *mm) { // 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); - // Fields 7 & 8 are the current time and date - if (mm->timestampMsg) { // Make sure the records' timestamp is valid before outputing it - epocTime = Modes.stSystemTimeBlk; // This is the time of the start of the Block we're processing + // 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.millitm += offset; // add on the offset time to the Block start time - if (epocTime.millitm > 999) // if we've caused an overflow into the next second... - {epocTime.millitm -= 1000; epocTime.time ++;} // ..correct the overflow - stTime = *localtime(&epocTime.time); // convert the time to year, month day, hours, min, sec - p += sprintf(p, "%04d/%02d/%02d,", (stTime.tm_year+1900),(stTime.tm_mon+1), stTime.tm_mday); - p += sprintf(p, "%02d:%02d:%02d.%03d,", stTime.tm_hour, stTime.tm_min, stTime.tm_sec, epocTime.millitm); + 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 { - p += sprintf(p, ",,"); - } + 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 - ftime(&epocTime); // get the current system time & date - stTime = *localtime(&epocTime.time); // convert the time to year, month day, hours, min, sec - p += sprintf(p, "%04d/%02d/%02d,", (stTime.tm_year+1900),(stTime.tm_mon+1), stTime.tm_mday); - p += sprintf(p, "%02d:%02d:%02d.%03d", stTime.tm_hour, stTime.tm_min, stTime.tm_sec, epocTime.millitm); + 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);} @@ -349,9 +377,19 @@ void modesSendSBSOutput(struct modesMessage *mm) { p += sprintf(p, ","); } - // Field 13 and 14 are the ground Speed and Heading (if we have them) - if (mm->bFlags & MODES_ACFLAGS_NSEWSPD_VALID) {p += sprintf(p, ",%d,%d", mm->velocity, mm->heading);} - 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);} @@ -437,16 +475,20 @@ 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)); - if ((*p == '1') && (Modes.mode_ac)) { // skip ModeA/C unless user enables --modes-ac + 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 (*p == '2') { + } else if (ch == '2') { msgLen = MODES_SHORT_MSG_BYTES; - } else if (*p == '3') { + } else if (ch == '3') { msgLen = MODES_LONG_MSG_BYTES; } @@ -454,8 +496,10 @@ int decodeBinMessage(struct client *c, char *p) { // 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; - for (j = 0; j < 7; j++) { // Skip the message type and timestamp - ch = *p++; + + 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++;} } @@ -755,8 +799,13 @@ int handleHTTPRequest(struct client *c, char *p) { } // 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; } @@ -797,14 +846,24 @@ void modesReadFromClient(struct client *c, char *sep, 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; } - if ( (nread < 0) && (errno != EAGAIN)) { // Error, or end of file - modesFreeClient(c->fd); +#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 @@ -851,7 +910,7 @@ void modesReadFromClient(struct client *c, char *sep, } // Have a 0x1a followed by 1, 2 or 3 - pass message less 0x1a to handler. if (handler(c, s)) { - modesFreeClient(c->fd); + modesFreeClient(c); return; } fullmsg = 1; @@ -867,7 +926,7 @@ void modesReadFromClient(struct client *c, char *sep, 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->fd); // Handler returns 1 on error to signal we . + 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 @@ -890,19 +949,21 @@ void modesReadFromClient(struct client *c, char *sep, // function that depends on the kind of service (raw, http, ...). // void modesReadFromClients(void) { - int j; - struct client *c; - modesAcceptClients(); + struct client *c = modesAcceptClients(); - for (j = 0; j <= Modes.maxfd; j++) { - if ((c = Modes.clients[j]) == NULL) continue; - if (c->service == Modes.ris) + 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) + } else if (c->service == Modes.bis) { modesReadFromClient(c,"",decodeBinMessage); - else if (c->service == Modes.https) + } else if (c->service == Modes.https) { modesReadFromClient(c,"\r\n\r\n",handleHTTPRequest); + } + c = next; } } // diff --git a/ppup1090.c b/ppup1090.c index 1c36dd5..afbbe2f 100644 --- a/ppup1090.c +++ b/ppup1090.c @@ -51,7 +51,8 @@ void ppup1090InitConfig(void) { // Now initialise things that should not be 0/NULL to their defaults Modes.check_crc = 1; Modes.quiet = 1; - strcpy(ppup1090.net_input_beast_ipaddr,PPUP1090_NET_OUTPUT_IP_ADDRESS); + 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; @@ -71,6 +72,10 @@ 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))) { @@ -104,6 +109,7 @@ void ppup1090Init(void) { 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)); @@ -126,10 +132,46 @@ void showHelp(void) { "-----------------------------------------------------------------------------\n" "--net-bo-ipaddr TCP Beast output listen IPv4 (default: 127.0.0.1)\n" "--net-bo-port TCP Beast output listen port (default: 30005)\n" + "--net-pp-ipaddr 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 \n" +" Copyright (C) 2014 by Malcolm Robb \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 \n" +"\n" + ); + + // delay for 1 second to give the user a chance to read the copyright + while (llTime >= time(NULL)) {} +} +#endif // //========================================================================= // @@ -150,6 +192,8 @@ int main(int argc, char **argv) { 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")) { @@ -162,6 +206,11 @@ int main(int argc, char **argv) { } } +#ifdef _WIN32 + // Try to comply with the Copyright license conditions for binary distribution + if (!ppup1090.quiet) {showCopyright();} +#endif + // Initialization ppup1090Init(); @@ -173,28 +222,21 @@ int main(int argc, char **argv) { // // 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 + // 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 + // 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, + // 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. - if (fd >= MODES_NET_MAX_FD) { // Max number of clients reached - close(fd); - exit(1); - } - c = (struct client *) malloc(sizeof(*c)); + c->next = NULL; c->buflen = 0; - c->fd = + c->fd = c->service = Modes.bis = fd; - Modes.clients[fd] = c; - if (Modes.maxfd < fd) { - Modes.maxfd = fd; - } + Modes.clients = c; // Keep going till the user does something that stops us while (!Modes.exit) { @@ -204,11 +246,15 @@ int main(int argc, char **argv) { } // The user has stopped us, so close any socket we opened - if (fd != ANET_ERR) + if (fd != ANET_ERR) {close(fd);} closeCOAA (); +#ifndef _WIN32 pthread_exit(0); +#else + return (0); +#endif } // //========================================================================= diff --git a/ppup1090.h b/ppup1090.h index 8a6806d..6d0756d 100644 --- a/ppup1090.h +++ b/ppup1090.h @@ -45,6 +45,9 @@ #include #include #include + #include + #include + #include #include #include #include @@ -69,19 +72,21 @@ // Program global state struct { // Internal state - int quiet; + int quiet; // Networking - char net_input_beast_ipaddr[32]; // IPv4 address or network name of server/RPi + 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 { - double fUserLat; - double fUserLon; - char strAuthCode[16]; - char strRegNo[16]; - char strVersion[16]; + uint32_t ppIPAddr; + double fUserLat; + double fUserLon; + char strAuthCode[16]; + char strRegNo[16]; + char strVersion[16]; } coaa1090; // ======================== function declarations ========================= 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@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 + * + * 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 +#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 +#else /* NEED_FTIME */ +/* use native WIN32 time API */ +#endif /* NEED_FTIME */ + +#if defined(HAVE_SIGNAL_H) +#include +#endif /* HAVE_SIGNAL_H */ + +#include + +/* + * 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 +#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 + +/* + * 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 , 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 , 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 +#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 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@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 +#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 +/* Required by Unix 98 */ +# include +# 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@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 +#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/gmap.html b/public_html/gmap.html index 80afe02..96f412a 100644 --- a/public_html/gmap.html +++ b/public_html/gmap.html @@ -3,7 +3,7 @@ - + diff --git a/public_html/script.js b/public_html/script.js index 9300c27..4a77db3 100644 --- a/public_html/script.js +++ b/public_html/script.js @@ -135,8 +135,12 @@ function initialize() { center: new google.maps.LatLng(CenterLat, CenterLon), zoom: ZoomLvl, mapTypeId: google.maps.MapTypeId.ROADMAP, + mapTypeControl: true, + streetViewControl: false, mapTypeControlOptions: { - mapTypeIds: mapTypeIds + mapTypeIds: mapTypeIds, + position: google.maps.ControlPosition.TOP_LEFT, + style: google.maps.MapTypeControlStyle.DROPDOWN_MENU } }; @@ -305,7 +309,7 @@ function refreshSelected() { html += 'Track: ' if (selected && selected.vTrack) { - html += selected.track + ' (' + normalizeTrack(selected.track, selected.vTrack)[1] +')'; + html += selected.track + '°' + ' (' + normalizeTrack(selected.track, selected.vTrack)[1] +')'; } else { html += 'n/a'; } diff --git a/public_html/style.css b/public_html/style.css index 63d0a45..86cb053 100644 --- a/public_html/style.css +++ b/public_html/style.css @@ -14,10 +14,9 @@ div#SpecialSquawkWarning { position: absolute; bottom: 25px; right: 430px; borde table#optionsTabs { width: 100%; font-size: small; font-family: monospace; background-color: #ddd; border: 1px; border-color: #000000;} -#tableinfo { font-size: x-small; font-family: monospace; } -#sudo_buttons { font-size: x-small; font-family: monospace; } +#tableinfo, #sudo_buttons { font-size: x-small; font-family: monospace; } -.vPosition { font-weight: bold; background-color: #f5fff5; } +.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; } 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 + * Copyright (C) 2012 by Dimitri Stolnikov + * + * 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 . + */ + +#ifndef __RTL_SDR_H +#define __RTL_SDR_H + +#ifdef __cplusplus +extern "C" { +#endif + +//#include +#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 + * + * 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 . + */ + +#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/view1090.c b/view1090.c index ae9ee89..0b9b8b9 100644 --- a/view1090.c +++ b/view1090.c @@ -1,6 +1,6 @@ // view1090, a Mode S messages viewer for dump1090 devices. // -// Copyright (C) 2013 by Malcolm Robb +// Copyright (C) 2014 by Malcolm Robb // // All rights reserved. // @@ -83,6 +83,21 @@ void view1090InitConfig(void) { // 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))) { @@ -115,6 +130,34 @@ void view1090Init(void) { // 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 ==================================== // @@ -140,12 +183,48 @@ void showHelp(void) { "--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 \n" +" Copyright (C) 2014 by Malcolm Robb \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 \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 @@ -195,6 +274,12 @@ int main(int argc, char **argv) { } } +#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);} @@ -204,50 +289,31 @@ int main(int argc, char **argv) { view1090Init(); // 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) { + 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); } - // - // 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. - - if (fd >= MODES_NET_MAX_FD) { // Max number of clients reached - fprintf(stderr, "Max number of clients exceeded : fd = 0x%X\n", fd); - close(fd); - exit(1); - } - - c = (struct client *) malloc(sizeof(*c)); - c->buflen = 0; - c->fd = - c->service = - Modes.bis = fd; - Modes.clients[fd] = c; - if (Modes.maxfd < fd) { - Modes.maxfd = fd; - } // Keep going till the user does something that stops us while (!Modes.exit) { - modesReadFromClient(c,"",decodeBinMessage); 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);} - pthread_exit(0); - 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 index c4c97fe..03ad96d 100644 --- a/view1090.h +++ b/view1090.h @@ -49,6 +49,8 @@ #include #include #include + #include + #include #include "rtl-sdr.h" #include "anet.h" #else 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 +// +// 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 +#include +#include + +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 +#include +#include +#include +#include +#include +#include + +#define M_PI 3.14159265358979323846 +#include +#include + +#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