From cd86d58898c481107103090b950ff41600d785d6 Mon Sep 17 00:00:00 2001 From: Malcolm Robb Date: Fri, 10 May 2013 17:27:34 +0100 Subject: [PATCH] Major Rewrite of SBS output code Remove dependency of the SBS output code on the historic (a) aircraft structure. The only items that were required were the decoded aircraft Lat/Lon and these are now included in the mm structure. Rewrite the SBS output code to use mm->bFlags when populating the output fields. This ensures that all available data is output, and also that no stale data is sent. Using the mm->bFlags variable for SBS output means there is no further requirement for the sbsFlags member in the aircraft structure, so remove it. Cross your fingers and hope this hasn't introduced too many bugs ! --- dump1090.c | 227 +++++++++++++++++++++++++++++++++-------------------- 1 file changed, 144 insertions(+), 83 deletions(-) diff --git a/dump1090.c b/dump1090.c index 9e860b2..c5826c0 100644 --- a/dump1090.c +++ b/dump1090.c @@ -126,8 +126,6 @@ #define MODES_ACFLAGS_LLBOTH_VALID (MODES_ACFLAGS_LLEVEN_VALID | MODES_ACFLAGS_LLODD_VALID) #define MODES_ACFLAGS_AOG_GROUND (MODES_ACFLAGS_AOG_VALID | MODES_ACFLAGS_AOG) -#define MODES_SBS_LAT_LONG_FRESH (1<<0) - #define MODES_DEBUG_DEMOD (1<<0) #define MODES_DEBUG_DEMODERR (1<<1) #define MODES_DEBUG_BADCRC (1<<2) @@ -187,7 +185,6 @@ struct aircraft { int even_cprlon; double lat, lon; // Coordinated obtained from CPR encoded data int bFlags; // Flags related to valid fields in this structure - int sbsflags; uint64_t odd_cprtime, even_cprtime; struct aircraft *next; // Next aircraft in our linked list }; @@ -328,7 +325,7 @@ struct aircraft* interactiveReceiveData(struct modesMessage *mm); void modesSendAllClients(int service, void *msg, int len); void modesSendRawOutput(struct modesMessage *mm); void modesSendBeastOutput(struct modesMessage *mm); -void modesSendSBSOutput(struct modesMessage *mm, struct aircraft *a); +void modesSendSBSOutput(struct modesMessage *mm); void useModesMessage(struct modesMessage *mm); int fixSingleBitErrors(unsigned char *msg, int bits); int fixTwoBitsErrors(unsigned char *msg, int bits); @@ -2233,40 +2230,42 @@ void detectModeS(uint16_t *m, uint32_t mlen) { } } } - -/* When a new message is available, because it was decoded from the - * RTL device, file, or received in the TCP input port, or any other - * way we can receive a decoded message, we call this function in order - * to use the message. - * - * Basically this function passes a raw message to the upper layers for - * further processing and visualization. */ +// +// When a new message is available, because it was decoded from the RTL device, +// file, or received in the TCP input port, or any other way we can receive a +// decoded message, we call this function in order to use the message. +// +// Basically this function passes a raw message to the upper layers for further +// processing and visualization +// void useModesMessage(struct modesMessage *mm) { if ((Modes.check_crc == 0) || (mm->crcok)) { + // Track aircrafts if... - if ( (Modes.interactive) // in interactive mode - || (Modes.stat_http_requests > 0) // or if the HTTP interface is enabled - || (Modes.stat_sbs_connections > 0) // or if sbs connections are established - || (Modes.mode_ac) ) { // or if mode A/C decoding is enabled - struct aircraft *a = interactiveReceiveData(mm); - if ( (a) - && (mm->msgtype < 32) // don't even try to send ModesA/C to SBS clients - && (Modes.stat_sbs_connections > 0) ) - {modesSendSBSOutput(mm, a);} // Feed SBS output clients + if ( (Modes.interactive) // in interactive mode + || (Modes.stat_http_requests) // or if the HTTP interface is enabled + || (Modes.stat_sbs_connections) // or if sbs connections are established + || (Modes.mode_ac) ) { // or if mode A/C decoding is enabled + interactiveReceiveData(mm); } - // In non-interactive mode, and non-quiet mode, display messages on - // standard output as they occur. + // In non-interactive non-quiet mode, display messages on standard output if (!Modes.interactive && !Modes.quiet) { displayModesMessage(mm); } + // Feed SBS output clients + if (Modes.stat_sbs_connections) { + modesSendSBSOutput(mm); + } + // Send data to connected network clients if (Modes.net) { - if (Modes.beast) + if (Modes.beast) { modesSendBeastOutput(mm); - else + } else { modesSendRawOutput(mm); + } } } } @@ -2529,7 +2528,6 @@ 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); - a->sbsflags |= MODES_SBS_LAT_LONG_FRESH; } /* This algorithm comes from: @@ -2602,8 +2600,6 @@ int decodeCPRrelative(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); - a->sbsflags |= MODES_SBS_LAT_LONG_FRESH; - return (0); } @@ -3072,30 +3068,56 @@ void modesSendRawOutput(struct modesMessage *mm) { Modes.net_output_raw_rate_count = 0; } } - -/* Write SBS output to TCP clients. */ -void modesSendSBSOutput(struct modesMessage *mm, struct aircraft *a) { +// +// Write SBS output to TCP clients +// +// We are passed in both the aircraft structure (a) and the message structure (mm). +// The message structure mm->bFlags tells us what has been updated by this message +// The aircraft structure a->bFlags tells us everything we currently know about this +// aircraft. Information not marked as 'new' in mm->bFlags will be historical/stale +// +void modesSendSBSOutput(struct modesMessage *mm) { char msg[256], *p = msg; - char strCommon[128], *pCommon = strCommon; - int emergency = 0, ground = 0, alert = 0, spi = 0; - uint32_t offset; + uint32_t offset; struct timeb epocTime; - struct tm stTime; + struct tm stTime; + int msgType; - if (mm->msgtype == 4 || mm->msgtype == 5 || mm->msgtype == 21) { - if (mm->modeA == 0x7500 || mm->modeA == 0x7600 || - mm->modeA == 0x7700) emergency = -1; - if (mm->fs == 1 || mm->fs == 3) ground = -1; - if (mm->fs == 2 || mm->fs == 3 || mm->fs == 4) alert = -1; - if (mm->fs == 4 || mm->fs == 5) spi = -1; + // + // SBS BS style output checked against the following reference + // http://www.homepages.mcb.net/bones/SBS/Article/Barebones42_Socket_Data.htm - seems comprehensive + // + + // Decide on the basic SBS Message Type + if ((mm->msgtype == 0) || (mm->msgtype == 4) || (mm->msgtype == 20)) { + msgType = 5; + } else if ((mm->msgtype == 5) || (mm->msgtype == 21)) { + msgType = 6; + } else if (mm->msgtype == 16) { + msgType = 7; + } else if (mm->msgtype == 11) { + msgType = 8; + } else if (mm->msgtype != 17) { + return; + } else if (mm->metype == 4) { + msgType = 1; + } else if ((mm->metype >= 5) && (mm->metype <= 8)) { + msgType = 2; + } else if ((mm->metype >= 9) && (mm->metype <= 18)) { + msgType = 3; + } else if (mm->metype != 19) { + return; + } else if ((mm->mesub == 1) || (mm->mesub == 2)) { + msgType = 4; + } else { + return; } - // ICAO address of the aircraft - pCommon += sprintf(pCommon, "111,11111,%06X,111111,", mm->addr); + // 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); - // Make sure the records' timestamp is valid before outputing it - if (mm->timestampMsg != (uint64_t)(-1)) { - // Do the records' time and date now + // Fields 7 & 8 are the current time and date + if (mm->timestampMsg != (uint64_t)(-1)) { // 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 offset = (int) (mm->timestampMsg - Modes.timestampBlk); // This is the time (in 12Mhz ticks) into the Block offset = offset / 12000; // convert to milliseconds @@ -3103,54 +3125,93 @@ void modesSendSBSOutput(struct modesMessage *mm, struct aircraft *a) { 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 - pCommon += sprintf(pCommon, "%04d/%02d/%02d,", (stTime.tm_year+1900),(stTime.tm_mon+1), stTime.tm_mday); - pCommon += sprintf(pCommon, "%02d:%02d:%02d.%03d,", stTime.tm_hour, stTime.tm_min, stTime.tm_sec, epocTime.millitm); + 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); } else { - pCommon += sprintf(pCommon, ",,"); + p += sprintf(p, ",,"); } - // Do the current time and date now + // 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 - pCommon += sprintf(pCommon, "%04d/%02d/%02d,", (stTime.tm_year+1900),(stTime.tm_mon+1), stTime.tm_mday); - pCommon += sprintf(pCommon, "%02d:%02d:%02d.%03d", stTime.tm_hour, stTime.tm_min, stTime.tm_sec, epocTime.millitm); + 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); - if (mm->msgtype == 0) { - p += sprintf(p, "MSG,5,%s,,%d,,,,,,,,,,", strCommon, mm->altitude); - } else if (mm->msgtype == 4) { - p += sprintf(p, "MSG,5,%s,,%d,,,,,,,%d,%d,%d,%d", strCommon, mm->altitude, alert, emergency, spi, ground); - - } else if (mm->msgtype == 5) { - p += sprintf(p, "MSG,6,%s,,,,,,,,%x,%d,%d,%d,%d", strCommon, mm->modeA, alert, emergency, spi, ground); - - } else if (mm->msgtype == 11) { - p += sprintf(p, "MSG,8,%s,,,,,,,,,,,,", strCommon); - - } else if (mm->msgtype == 17 && mm->metype == 4) { - p += sprintf(p, "MSG,1,%s,%s,,,,,,,,0,0,0,0", strCommon, mm->flight); - - } else if (mm->msgtype == 17 && mm->metype >= 9 && mm->metype <= 18) { - if ( ((a->lat == 0) && (a->lon == 0)) || ((a->sbsflags & MODES_SBS_LAT_LONG_FRESH) == 0) ){ - p += sprintf(p, "MSG,3,%s,,%d,,,,,,,0,0,0,0", strCommon, mm->altitude); - } else { - p += sprintf(p, "MSG,3,%s,,%d,,,%1.5f,%1.5f,,,0,0,0,0", strCommon, mm->altitude, a->lat, a->lon); - a->sbsflags &= ~MODES_SBS_LAT_LONG_FRESH; - } - - } else if (mm->msgtype == 17 && mm->metype == 19 && mm->mesub == 1) { - int vr = (mm->vert_rate_sign==0?1:-1) * (mm->vert_rate-1) * 64; - - p += sprintf(p, "MSG,4,%s,,,%d,%d,,,%i,,0,0,0,0", strCommon, mm->velocity, mm->heading, vr); - - } else if (mm->msgtype == 21) { - p += sprintf(p, "MSG,6,%s,,,,,,,,%x,%d,%d,%d,%d", strCommon, mm->modeA, alert, emergency, spi, ground); + // Field 11 is the callsign (if we have it) + if (mm->bFlags & MODES_ACFLAGS_CALLSIGN_VALID) {p += sprintf(p, ",%s", mm->flight);} + else {p += sprintf(p, ",");} + // Field 12 is the altitude (if we have it) - force to zero if we're on the ground + if ((mm->bFlags & MODES_ACFLAGS_AOG_GROUND) == MODES_ACFLAGS_AOG_GROUND) { + p += sprintf(p, ",0"); + } else if (mm->bFlags & MODES_ACFLAGS_ALTITUDE_VALID) { + p += sprintf(p, ",%d", mm->altitude); } else { - return; + p += sprintf(p, ","); } - *p++ = '\r'; *p++ = '\n'; // or just ?? + // 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, ",,");} + + // Fields 15 and 16 are the Lat/Lon (if we have it) + if (mm->bFlags & MODES_ACFLAGS_LATLON_VALID) {p += sprintf(p, ",%1.5f,%1.5f", mm->fLat, mm->fLon);} + else {p += sprintf(p, ",,");} + + // Field 17 is the VerticalRate (if we have it) + if (mm->bFlags & MODES_ACFLAGS_VERTRATE_VALID) {p += sprintf(p, ",%d", mm->vert_rate);} + else {p += sprintf(p, ",");} + + // Field 18 is the Squawk (if we have it) + if (mm->bFlags & MODES_ACFLAGS_SQUAWK_VALID) {p += sprintf(p, ",%x", mm->modeA);} + else {p += sprintf(p, ",");} + + // Field 19 is the Squawk Changing Alert flag (if we have it) + if (mm->bFlags & MODES_ACFLAGS_FS_VALID) { + if ((mm->fs >= 2) && (mm->fs <= 4)) { + p += sprintf(p, ",-1"); + } else { + p += sprintf(p, ",0"); + } + } else { + p += sprintf(p, ","); + } + + // Field 20 is the Squawk Emergency flag (if we have it) + if (mm->bFlags & MODES_ACFLAGS_SQUAWK_VALID) { + if ((mm->modeA == 0x7500) || (mm->modeA == 0x7600) || (mm->modeA == 0x7700)) { + p += sprintf(p, ",-1"); + } else { + p += sprintf(p, ",0"); + } + } else { + p += sprintf(p, ","); + } + + // Field 21 is the Squawk Ident flag (if we have it) + if (mm->bFlags & MODES_ACFLAGS_FS_VALID) { + if ((mm->fs >= 4) && (mm->fs <= 5)) { + p += sprintf(p, ",-1"); + } else { + p += sprintf(p, ",0"); + } + } else { + p += sprintf(p, ","); + } + + // Field 22 is the OnTheGround flag (if we have it) + if (mm->bFlags & MODES_ACFLAGS_AOG_VALID) { + if (mm->bFlags & MODES_ACFLAGS_AOG) { + p += sprintf(p, ",-1"); + } else { + p += sprintf(p, ",0"); + } + } else { + p += sprintf(p, ","); + } + + p += sprintf(p, "\r\n"); modesSendAllClients(Modes.sbsos, msg, p-msg); }