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 !
This commit is contained in:
parent
7df6d656a0
commit
cd86d58898
227
dump1090.c
227
dump1090.c
|
@ -126,8 +126,6 @@
|
||||||
#define MODES_ACFLAGS_LLBOTH_VALID (MODES_ACFLAGS_LLEVEN_VALID | MODES_ACFLAGS_LLODD_VALID)
|
#define MODES_ACFLAGS_LLBOTH_VALID (MODES_ACFLAGS_LLEVEN_VALID | MODES_ACFLAGS_LLODD_VALID)
|
||||||
#define MODES_ACFLAGS_AOG_GROUND (MODES_ACFLAGS_AOG_VALID | MODES_ACFLAGS_AOG)
|
#define MODES_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_DEMOD (1<<0)
|
||||||
#define MODES_DEBUG_DEMODERR (1<<1)
|
#define MODES_DEBUG_DEMODERR (1<<1)
|
||||||
#define MODES_DEBUG_BADCRC (1<<2)
|
#define MODES_DEBUG_BADCRC (1<<2)
|
||||||
|
@ -187,7 +185,6 @@ struct aircraft {
|
||||||
int even_cprlon;
|
int even_cprlon;
|
||||||
double lat, lon; // Coordinated obtained from CPR encoded data
|
double lat, lon; // Coordinated obtained from CPR encoded data
|
||||||
int bFlags; // Flags related to valid fields in this structure
|
int bFlags; // Flags related to valid fields in this structure
|
||||||
int sbsflags;
|
|
||||||
uint64_t odd_cprtime, even_cprtime;
|
uint64_t odd_cprtime, even_cprtime;
|
||||||
struct aircraft *next; // Next aircraft in our linked list
|
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 modesSendAllClients(int service, void *msg, int len);
|
||||||
void modesSendRawOutput(struct modesMessage *mm);
|
void modesSendRawOutput(struct modesMessage *mm);
|
||||||
void modesSendBeastOutput(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);
|
void useModesMessage(struct modesMessage *mm);
|
||||||
int fixSingleBitErrors(unsigned char *msg, int bits);
|
int fixSingleBitErrors(unsigned char *msg, int bits);
|
||||||
int fixTwoBitsErrors(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
|
// When a new message is available, because it was decoded from the RTL device,
|
||||||
* RTL device, file, or received in the TCP input port, or any other
|
// file, or received in the TCP input port, or any other way we can receive a
|
||||||
* way we can receive a decoded message, we call this function in order
|
// decoded message, we call this function in order to use the message.
|
||||||
* to use the message.
|
//
|
||||||
*
|
// Basically this function passes a raw message to the upper layers for further
|
||||||
* Basically this function passes a raw message to the upper layers for
|
// processing and visualization
|
||||||
* further processing and visualization. */
|
//
|
||||||
void useModesMessage(struct modesMessage *mm) {
|
void useModesMessage(struct modesMessage *mm) {
|
||||||
if ((Modes.check_crc == 0) || (mm->crcok)) {
|
if ((Modes.check_crc == 0) || (mm->crcok)) {
|
||||||
|
|
||||||
// Track aircrafts if...
|
// Track aircrafts if...
|
||||||
if ( (Modes.interactive) // in interactive mode
|
if ( (Modes.interactive) // in interactive mode
|
||||||
|| (Modes.stat_http_requests > 0) // or if the HTTP interface is enabled
|
|| (Modes.stat_http_requests) // or if the HTTP interface is enabled
|
||||||
|| (Modes.stat_sbs_connections > 0) // or if sbs connections are established
|
|| (Modes.stat_sbs_connections) // or if sbs connections are established
|
||||||
|| (Modes.mode_ac) ) { // or if mode A/C decoding is enabled
|
|| (Modes.mode_ac) ) { // or if mode A/C decoding is enabled
|
||||||
struct aircraft *a = interactiveReceiveData(mm);
|
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
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// In non-interactive mode, and non-quiet mode, display messages on
|
// In non-interactive non-quiet mode, display messages on standard output
|
||||||
// standard output as they occur.
|
|
||||||
if (!Modes.interactive && !Modes.quiet) {
|
if (!Modes.interactive && !Modes.quiet) {
|
||||||
displayModesMessage(mm);
|
displayModesMessage(mm);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Feed SBS output clients
|
||||||
|
if (Modes.stat_sbs_connections) {
|
||||||
|
modesSendSBSOutput(mm);
|
||||||
|
}
|
||||||
|
|
||||||
// Send data to connected network clients
|
// Send data to connected network clients
|
||||||
if (Modes.net) {
|
if (Modes.net) {
|
||||||
if (Modes.beast)
|
if (Modes.beast) {
|
||||||
modesSendBeastOutput(mm);
|
modesSendBeastOutput(mm);
|
||||||
else
|
} else {
|
||||||
modesSendRawOutput(mm);
|
modesSendRawOutput(mm);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2529,7 +2528,6 @@ void decodeCPR(struct aircraft *a, int fflag, int surface) {
|
||||||
a->seenLatLon = a->seen;
|
a->seenLatLon = a->seen;
|
||||||
a->timestampLatLon = a->timestamp;
|
a->timestampLatLon = a->timestamp;
|
||||||
a->bFlags |= (MODES_ACFLAGS_LATLON_VALID | MODES_ACFLAGS_LATLON_REL_OK);
|
a->bFlags |= (MODES_ACFLAGS_LATLON_VALID | MODES_ACFLAGS_LATLON_REL_OK);
|
||||||
a->sbsflags |= MODES_SBS_LAT_LONG_FRESH;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* This algorithm comes from:
|
/* This algorithm comes from:
|
||||||
|
@ -2602,8 +2600,6 @@ int decodeCPRrelative(struct aircraft *a, int fflag, int surface) {
|
||||||
a->seenLatLon = a->seen;
|
a->seenLatLon = a->seen;
|
||||||
a->timestampLatLon = a->timestamp;
|
a->timestampLatLon = a->timestamp;
|
||||||
a->bFlags |= (MODES_ACFLAGS_LATLON_VALID | MODES_ACFLAGS_LATLON_REL_OK);
|
a->bFlags |= (MODES_ACFLAGS_LATLON_VALID | MODES_ACFLAGS_LATLON_REL_OK);
|
||||||
a->sbsflags |= MODES_SBS_LAT_LONG_FRESH;
|
|
||||||
|
|
||||||
return (0);
|
return (0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3072,30 +3068,56 @@ void modesSendRawOutput(struct modesMessage *mm) {
|
||||||
Modes.net_output_raw_rate_count = 0;
|
Modes.net_output_raw_rate_count = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
//
|
||||||
/* Write SBS output to TCP clients. */
|
// Write SBS output to TCP clients
|
||||||
void modesSendSBSOutput(struct modesMessage *mm, struct aircraft *a) {
|
//
|
||||||
|
// 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 msg[256], *p = msg;
|
||||||
char strCommon[128], *pCommon = strCommon;
|
uint32_t offset;
|
||||||
int emergency = 0, ground = 0, alert = 0, spi = 0;
|
|
||||||
uint32_t offset;
|
|
||||||
struct timeb epocTime;
|
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 ||
|
// SBS BS style output checked against the following reference
|
||||||
mm->modeA == 0x7700) emergency = -1;
|
// http://www.homepages.mcb.net/bones/SBS/Article/Barebones42_Socket_Data.htm - seems comprehensive
|
||||||
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;
|
// 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
|
// Fields 1 to 6 : SBS message type and ICAO address of the aircraft and some other stuff
|
||||||
pCommon += sprintf(pCommon, "111,11111,%06X,111111,", mm->addr);
|
p += sprintf(p, "MSG,%d,111,11111,%06X,111111,", msgType, mm->addr);
|
||||||
|
|
||||||
// Make sure the records' timestamp is valid before outputing it
|
// Fields 7 & 8 are the current time and date
|
||||||
if (mm->timestampMsg != (uint64_t)(-1)) {
|
if (mm->timestampMsg != (uint64_t)(-1)) { // Make sure the records' timestamp is valid before outputing it
|
||||||
// Do the records' time and date now
|
|
||||||
epocTime = Modes.stSystemTimeBlk; // This is the time of the start of the Block we're processing
|
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 = (int) (mm->timestampMsg - Modes.timestampBlk); // This is the time (in 12Mhz ticks) into the Block
|
||||||
offset = offset / 12000; // convert to milliseconds
|
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...
|
if (epocTime.millitm > 999) // if we've caused an overflow into the next second...
|
||||||
{epocTime.millitm -= 1000; epocTime.time ++;} // ..correct the overflow
|
{epocTime.millitm -= 1000; epocTime.time ++;} // ..correct the overflow
|
||||||
stTime = *localtime(&epocTime.time); // convert the time to year, month day, hours, min, sec
|
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);
|
p += sprintf(p, "%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, "%02d:%02d:%02d.%03d,", stTime.tm_hour, stTime.tm_min, stTime.tm_sec, epocTime.millitm);
|
||||||
} else {
|
} 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
|
ftime(&epocTime); // get the current system time & date
|
||||||
stTime = *localtime(&epocTime.time); // convert the time to year, month day, hours, min, sec
|
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);
|
p += sprintf(p, "%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, "%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) {
|
// Field 11 is the callsign (if we have it)
|
||||||
p += sprintf(p, "MSG,5,%s,,%d,,,,,,,%d,%d,%d,%d", strCommon, mm->altitude, alert, emergency, spi, ground);
|
if (mm->bFlags & MODES_ACFLAGS_CALLSIGN_VALID) {p += sprintf(p, ",%s", mm->flight);}
|
||||||
|
else {p += sprintf(p, ",");}
|
||||||
} 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 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 {
|
} else {
|
||||||
return;
|
p += sprintf(p, ",");
|
||||||
}
|
}
|
||||||
|
|
||||||
*p++ = '\r'; *p++ = '\n'; // <CRLF> or just <LF> ??
|
// 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);
|
modesSendAllClients(Modes.sbsos, msg, p-msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue