diff --git a/dump1090.c b/dump1090.c index 8fd47c4..835be49 100644 --- a/dump1090.c +++ b/dump1090.c @@ -395,7 +395,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" @@ -417,7 +417,7 @@ 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)\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" @@ -506,6 +506,68 @@ void backgroundTasks(void) { // //========================================================================= // +int verbose_device_search(char *s) +{ + int i, device_count, device, offset; + char *s2; + char vendor[256], product[256], serial[256]; + device_count = rtlsdr_get_device_count(); + if (!device_count) { + fprintf(stderr, "No supported devices found.\n"); + return -1; + } + fprintf(stderr, "Found %d device(s):\n", device_count); + for (i = 0; i < device_count; i++) { + rtlsdr_get_device_usb_strings(i, vendor, product, serial); + fprintf(stderr, " %d: %s, %s, SN: %s\n", i, vendor, product, serial); + } + fprintf(stderr, "\n"); + /* does string look like raw id number */ + device = (int)strtol(s, &s2, 0); + if (s2[0] == '\0' && device >= 0 && device < device_count) { + fprintf(stderr, "Using device %d: %s\n", + device, rtlsdr_get_device_name((uint32_t)device)); + return device; + } + /* does string exact match a serial */ + for (i = 0; i < device_count; i++) { + rtlsdr_get_device_usb_strings(i, vendor, product, serial); + if (strcmp(s, serial) != 0) { + continue;} + device = i; + fprintf(stderr, "Using device %d: %s\n", + device, rtlsdr_get_device_name((uint32_t)device)); + return device; + } + /* does string prefix match a serial */ + for (i = 0; i < device_count; i++) { + rtlsdr_get_device_usb_strings(i, vendor, product, serial); + if (strncmp(s, serial, strlen(s)) != 0) { + continue;} + device = i; + fprintf(stderr, "Using device %d: %s\n", + device, rtlsdr_get_device_name((uint32_t)device)); + return device; + } + /* does string suffix match a serial */ + for (i = 0; i < device_count; i++) { + rtlsdr_get_device_usb_strings(i, vendor, product, serial); + offset = strlen(serial) - strlen(s); + if (offset < 0) { + continue;} + if (strncmp(s, serial+offset, strlen(s)) != 0) { + continue;} + device = i; + fprintf(stderr, "Using device %d: %s\n", + device, rtlsdr_get_device_name((uint32_t)device)); + return device; + } + fprintf(stderr, "No matching devices found.\n"); + return -1; +} +// +//========================================================================= +// int main(int argc, char **argv) { int j; @@ -518,7 +580,7 @@ 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 } else if (!strcmp(argv[j],"--enable-agc")) { diff --git a/mode_s.c b/mode_s.c index cc62259..67708ce 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) @@ -944,7 +960,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 @@ -1060,7 +1076,23 @@ void decodeModesMessage(struct modesMessage *mm, unsigned char *msg) { mm->heading = ((((msg[5] & 0x03) << 8) | msg[6]) * 45) >> 7; } } - } + } else if (mm->metype == 23) { // Test metype squawk field + if (mm->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 (mm->metype == 28) { // Emergency status squawk field + if (mm->mesub == 1) { + int ID13Field = (((msg[5] << 8) | msg[6]) & 0x1FFF); + if (ID13Field) { + mm->bFlags |= MODES_ACFLAGS_SQUAWK_VALID; + mm->modeA = decodeID13Field(ID13Field); + } + } + } } // Fields for DF20, DF21 Comm-B @@ -1159,8 +1191,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 +1209,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 +1225,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"); @@ -1275,6 +1307,20 @@ void displayModesMessage(struct modesMessage *mm) { //} else if (mm->metype >= 20 && mm->metype <= 22) { // Airborne position GNSS + } 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); } @@ -1976,12 +2022,24 @@ 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 { + surface_rlat = Modes.fUserLat; + return; + } + 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; @@ -2006,7 +2064,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; } diff --git a/net_io.c b/net_io.c index 7b54fb6..f9f5470 100644 --- a/net_io.c +++ b/net_io.c @@ -46,22 +46,30 @@ // // 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}, - {"FlightAware TSV output", &Modes.fatsvos, MODES_NET_OUTPUT_FA_TSV_PORT} - }; int j; + struct service svc[MODES_NET_SERVICES_NUM] = { + {"Raw TCP output", &Modes.ros, Modes.net_output_raw_port, 1}, + {"Raw TCP input", &Modes.ris, Modes.net_input_raw_port, 1}, + {"Beast TCP output", &Modes.bos, Modes.net_output_beast_port, 1}, + {"Beast TCP input", &Modes.bis, Modes.net_input_beast_port, 1}, + {"HTTP server", &Modes.https, Modes.net_http_port, 1}, + {"Basestation TCP output", &Modes.sbsos, Modes.net_output_sbs_port, 1}, + {"FlightAware TSV output", &Modes.fatsvos, MODES_NET_OUTPUT_FA_TSV_PORT, 1} + }; + + memcpy(&services, &svc, sizeof(svc));//services = svc; + Modes.clients = NULL; #ifdef _WIN32 @@ -76,14 +84,19 @@ void modesInitNet(void) { #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, strerror(errno)); + 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 @@ -100,39 +113,31 @@ struct client * modesAcceptClients(void) { int fd, port; unsigned int j; struct client *c; - int services[MODES_NET_SERVICES_NUM]; - - services[0] = Modes.ros; - services[1] = Modes.ris; - services[2] = Modes.bos; - services[3] = Modes.bis; - services[4] = Modes.https; - services[5] = Modes.sbsos; - services[6] = Modes.fatsvos; 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; - anetNonBlock(Modes.aneterr, fd); - c = (struct client *) malloc(sizeof(*c)); - c->service = services[j]; - c->next = Modes.clients; - c->fd = fd; - c->buflen = 0; - c->tsvVerbatim[0] = '\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].socket; + c->next = Modes.clients; + c->fd = fd; + c->buflen = 0; + Modes.clients = c; + anetSetSendBuffer(Modes.aneterr,fd, (MODES_NET_SNDBUF_SIZE << Modes.net_sndbuf_size)); - if (services[j] == Modes.sbsos) Modes.stat_sbs_connections++; - if (services[j] == Modes.fatsvos) Modes.stat_fatsv_connections++; - if (services[j] == Modes.ros) Modes.stat_raw_connections++; - if (services[j] == Modes.bos) Modes.stat_beast_connections++; + 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 (*services[j].socket == Modes.fatsvos) Modes.stat_fatsv_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; } diff --git a/view1090.c b/view1090.c index de6477f..e2e27dc 100644 --- a/view1090.c +++ b/view1090.c @@ -115,6 +115,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 ==================================== // @@ -181,6 +209,7 @@ void showCopyright(void) { int main(int argc, char **argv) { int j, fd; struct client *c; + char pk_buf[8]; // Set sane defaults @@ -244,45 +273,32 @@ 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. - - c = (struct client *) malloc(sizeof(*c)); - c->next = NULL; - c->buflen = 0; - c->fd = - c->service = - Modes.bis = fd; - Modes.clients = c; // Keep going till the user does something that stops us while (!Modes.exit) { - modesReadFromClient(c,"",decodeBinMessage); interactiveRemoveStaleAircrafts(); 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);} -#ifndef _WIN32 - pthread_exit(0); -#else return (0); -#endif } // //========================================================================= diff --git a/view1090.h b/view1090.h index af4ec21..05a9ebf 100644 --- a/view1090.h +++ b/view1090.h @@ -49,6 +49,8 @@ #include #include #include + #include + #include #include "rtl-sdr.h" #include "anet.h" #else