diff --git a/Release/dump1090.bat b/Release/dump1090.bat deleted file mode 100644 index dab0b46..0000000 --- a/Release/dump1090.bat +++ /dev/null @@ -1 +0,0 @@ -dump1090.exe --interactive --net --net-ro-size 500 --net-ro-rate 5 \ No newline at end of file diff --git a/Release/dump1090.exe b/Release/dump1090.exe deleted file mode 100644 index 3e0f87f..0000000 Binary files a/Release/dump1090.exe and /dev/null differ diff --git a/Release/view1090.exe b/Release/view1090.exe deleted file mode 100644 index 9d001f8..0000000 Binary files a/Release/view1090.exe and /dev/null differ diff --git a/anet.c b/anet.c index 049077d..2197c33 100644 --- a/anet.c +++ b/anet.c @@ -165,6 +165,7 @@ 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((uint16_t)port); if (inet_aton(addr, (void*)&sa.sin_addr) == 0) { diff --git a/coaa1090.obj b/coaa1090.obj index 4c67a3d..ea337ca 100644 Binary files a/coaa1090.obj and b/coaa1090.obj differ diff --git a/dump1090-win.1.08.2705.14.zip b/dump1090-win.1.09.0608.14.zip similarity index 83% rename from dump1090-win.1.08.2705.14.zip rename to dump1090-win.1.09.0608.14.zip index b40d5c6..5bd3d84 100644 Binary files a/dump1090-win.1.08.2705.14.zip and b/dump1090-win.1.09.0608.14.zip differ diff --git a/dump1090.bat b/dump1090.bat deleted file mode 100644 index 777769b..0000000 --- a/dump1090.bat +++ /dev/null @@ -1 +0,0 @@ -dump1090.exe --interactive --net --net-ro-port 30002 --net-beast --mlat diff --git a/dump1090.c b/dump1090.c index 835be49..cd53413 100644 --- a/dump1090.c +++ b/dump1090.c @@ -68,6 +68,7 @@ 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; @@ -89,6 +90,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); diff --git a/dump1090.exe b/dump1090.exe deleted file mode 100644 index 3e0f87f..0000000 Binary files a/dump1090.exe and /dev/null differ diff --git a/dump1090.h b/dump1090.h index 2c082bb..af28c47 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.2705.14" +#define MODES_DUMP1090_VERSION "1.09.0608.14" // ============================= Include files ========================== @@ -67,7 +67,7 @@ // ============================= #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 @@ -76,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 @@ -115,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 @@ -138,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) @@ -176,7 +177,7 @@ #define MODES_NET_OUTPUT_FA_TSV_PORT 10001 #define MODES_CLIENT_BUF_SIZE 1024 #define MODES_NET_SNDBUF_SIZE (1024*64) -#define MODES_NET_SNDBUF_MAX (7) +#define MODES_NET_SNDBUF_MAX (7) #ifndef HTMLPATH #define HTMLPATH "./public_html" // default path for gmap.html etc @@ -233,6 +234,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; @@ -243,7 +254,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) @@ -324,6 +335,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; @@ -338,7 +355,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_fatsv_connections; @@ -355,7 +372,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_ph_bit_fix[MODES_MAX_BITERRORS]; - + unsigned int stat_DF_Len_Corrected; unsigned int stat_DF_Type_Corrected; unsigned int stat_ModeAC; @@ -436,6 +453,8 @@ struct aircraft* interactiveReceiveData(struct modesMessage *mm, struct client * 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 97cd010..f0f7899 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 client * 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 @@ -259,7 +340,7 @@ struct aircraft *interactiveReceiveData(struct modesMessage *mm, struct client * // 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) { @@ -299,20 +380,25 @@ struct aircraft *interactiveReceiveData(struct modesMessage *mm, struct client * 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); @@ -333,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(); @@ -380,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);} @@ -389,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) { @@ -427,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)); } @@ -449,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 67708ce..552183b 100644 --- a/mode_s.c +++ b/mode_s.c @@ -907,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)) { return;} + // Fields for DF0, DF16 if (mm->msgtype == 0 || mm->msgtype == 16) { if (msg[0] & 0x04) { // VS Bit @@ -982,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 @@ -1076,23 +1054,62 @@ 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) + + } 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 (mm->metype == 28) { // Emergency status squawk field - if (mm->mesub == 1) { + + } else if (metype == 24) { // Reserved for Surface System Status + + } else if (metype == 28) { // Extended Squitter Aircraft Status + if (mesub == 1) { // Emergency status squawk field int ID13Field = (((msg[5] << 8) | msg[6]) & 0x1FFF); if (ID13Field) { mm->bFlags |= MODES_ACFLAGS_SQUAWK_VALID; mm->modeA = decodeID13Field(ID13Field); } } - } + + } else if (metype == 29) { // Aircraft Trajectory Intent + + } else if (metype == 30) { // Aircraft Operational Coordination + + } else if (metype == 31) { // Aircraft Operational Status + + } else { // Other metypes + + } } // Fields for DF20, DF21 Comm-B @@ -1268,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"); @@ -1305,7 +1308,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) { // 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) { @@ -1343,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"); @@ -1380,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); @@ -2035,7 +2044,6 @@ void decodeCPR(struct aircraft *a, int fflag, int surface) { 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 diff --git a/net_io.c b/net_io.c index f9f5470..3cce785 100644 --- a/net_io.c +++ b/net_io.c @@ -374,9 +374,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);} @@ -462,16 +472,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; } @@ -479,8 +493,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++;} } diff --git a/ppup1090.c b/ppup1090.c index 0d5aa7c..598dfed 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,6 +132,7 @@ 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" ); @@ -185,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")) { @@ -199,7 +208,7 @@ int main(int argc, char **argv) { #ifdef _WIN32 // Try to comply with the Copyright license conditions for binary distribution - if (!Modes.quiet) {showCopyright();} + if (!ppup1090.quiet) {showCopyright();} #endif // Initialization @@ -213,18 +222,18 @@ 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. c = (struct client *) malloc(sizeof(*c)); c->next = NULL; c->buflen = 0; - c->fd = + c->fd = c->service = Modes.bis = fd; Modes.clients = c; @@ -237,7 +246,7 @@ 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 (); diff --git a/ppup1090.h b/ppup1090.h index 30fe59b..f7ac643 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/view1090.c b/view1090.c index e2e27dc..733c874 100644 --- a/view1090.c +++ b/view1090.c @@ -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))) { @@ -262,6 +277,7 @@ 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