diff --git a/dump1090.h b/dump1090.h index b7eb1ab..b1cba8f 100644 --- a/dump1090.h +++ b/dump1090.h @@ -153,18 +153,17 @@ typedef enum { * (Earlier values are higher priority) */ typedef enum { - ADDR_ADSB_ICAO, /* Mode S or ADS-B, ICAO address, transponder sourced */ - ADDR_ADSB_ICAO_NT, /* ADS-B, ICAO address, non-transponder */ - ADDR_ADSR_ICAO, /* ADS-R, ICAO address */ - ADDR_TISB_ICAO, /* TIS-B, ICAO address */ + ADDR_ADSB_ICAO, /* Mode S or ADS-B, ICAO address, transponder sourced */ + ADDR_ADSB_ICAO_NT, /* ADS-B, ICAO address, non-transponder */ + ADDR_ADSR_ICAO, /* ADS-R, ICAO address */ + ADDR_TISB_ICAO, /* TIS-B, ICAO address */ - ADDR_ADSB_OTHER, /* ADS-B, other address format, non-transponder */ - ADDR_ADSR_OTHER, /* ADS-R, other address format */ - ADDR_TISB_OTHER, /* TIS-B, other address format */ + ADDR_ADSB_OTHER, /* ADS-B, other address format */ + ADDR_ADSR_OTHER, /* ADS-R, other address format */ + ADDR_TISB_TRACKFILE, /* TIS-B, Mode A code + track file number */ + ADDR_TISB_OTHER, /* TIS-B, other address format */ - ADDR_TISB_ANON, /* ADS-R/TIS-B, anonymized address */ - - ADDR_UNKNOWN /* unknown address format */ + ADDR_UNKNOWN /* unknown address format */ } addrtype_t; typedef enum { diff --git a/mode_s.c b/mode_s.c index ff51cee..1580ba0 100644 --- a/mode_s.c +++ b/mode_s.c @@ -796,11 +796,12 @@ static void setIMF(struct modesMessage *mm) switch (mm->addrtype) { case ADDR_ADSB_ICAO: case ADDR_ADSB_ICAO_NT: + // Shouldn't happen, but let's try to handle it mm->addrtype = ADDR_ADSB_OTHER; break; case ADDR_TISB_ICAO: - mm->addrtype = ADDR_TISB_OTHER; + mm->addrtype = ADDR_TISB_TRACKFILE; break; case ADDR_ADSR_ICAO: @@ -1164,39 +1165,43 @@ static void decodeExtendedSquitter(struct modesMessage *mm) // Check CF on DF18 to work out the format of the ES and whether we need to look for an IMF bit if (mm->msgtype == 18) { switch (mm->CF) { - case 0: // ADS-B ES/NT devices that report the ICAO 24-bit address in the AA field + case 0: // ADS-B Message from a non-transponder device, AA field holds 24-bit ICAO aircraft address mm->addrtype = ADDR_ADSB_ICAO_NT; break; - case 1: // Reserved for ADS-B for ES/NT devices that use other addressing techniques in the AA field + case 1: // Reserved for ADS-B Message in which the AA field holds anonymous address or ground vehicle address or fixed obstruction address mm->addrtype = ADDR_ADSB_OTHER; mm->addr |= MODES_NON_ICAO_ADDRESS; break; - case 2: // Fine TIS-B message (formats are close enough to DF17 for our purposes) + case 2: // Fine TIS-B Message + // IMF=0: AA field contains the 24-bit ICAO aircraft address + // IMF=1: AA field contains the 12-bit Mode A code followed by a 12-bit track file number mm->source = SOURCE_TISB; mm->addrtype = ADDR_TISB_ICAO; check_imf = 1; break; case 3: // Coarse TIS-B airborne position and velocity. - // TODO: decode me. + // IMF=0: AA field contains the 24-bit ICAO aircraft address + // IMF=1: AA field contains the 12-bit Mode A code followed by a 12-bit track file number + // For now we only look at the IMF bit. mm->source = SOURCE_TISB; mm->addrtype = ADDR_TISB_ICAO; - if (getbit(me, 1)) { - mm->addr |= MODES_NON_ICAO_ADDRESS; - mm->addrtype = ADDR_TISB_OTHER; - } + if (getbit(me, 1)) + setIMF(mm); return; - case 5: // TIS-B messages that relay ADS-B Messages using anonymous 24-bit addresses (format not explicitly defined, but it seems to follow DF17) - mm->addrtype = ADDR_TISB_ANON; + case 5: // Fine TIS-B Message, AA field contains a non-ICAO 24-bit address + mm->addrtype = ADDR_TISB_OTHER; mm->source = SOURCE_TISB; mm->addr |= MODES_NON_ICAO_ADDRESS; break; - case 6: // ADS-B rebroadcast using the same type codes and message formats as defined for DF = 17 ADS-B messages + case 6: // Rebroadcast of ADS-B Message from an alternate data link + // IMF=0: AA field holds 24-bit ICAO aircraft address + // IMF=1: AA field holds anonymous address or ground vehicle address or fixed obstruction address mm->addrtype = ADDR_ADSR_ICAO; check_imf = 1; break; @@ -1370,8 +1375,8 @@ static const char *addrtype_to_string(addrtype_t type) { return "TIS-B"; case ADDR_TISB_OTHER: return "TIS-B, other addressing scheme"; - case ADDR_TISB_ANON: - return "TIS-B, anonymized address"; + case ADDR_TISB_TRACKFILE: + return "TIS-B, Mode A code and track file number"; case ADDR_ADSR_ICAO: return "ADS-R"; case ADDR_ADSR_OTHER: diff --git a/net_io.c b/net_io.c index 60be682..9f0c325 100644 --- a/net_io.c +++ b/net_io.c @@ -993,18 +993,18 @@ static const char *addrtype_short_string(addrtype_t type) { return "adsb_icao"; case ADDR_ADSB_ICAO_NT: return "adsb_icao_nt"; - case ADDR_ADSB_OTHER: - return "adsb_other"; - case ADDR_TISB_ICAO: - return "tisb_icao"; - case ADDR_TISB_OTHER: - return "tisb_other"; - case ADDR_TISB_ANON: - return "tisb_anon"; case ADDR_ADSR_ICAO: return "adsr_icao"; + case ADDR_TISB_ICAO: + return "tisb_icao"; + case ADDR_ADSB_OTHER: + return "adsb_other"; case ADDR_ADSR_OTHER: return "adsr_other"; + case ADDR_TISB_OTHER: + return "tisb_other"; + case ADDR_TISB_TRACKFILE: + return "tisb_trackfile"; default: return "unknown"; } @@ -1752,16 +1752,19 @@ static void writeFATSVEvent(struct modesMessage *mm, struct aircraft *a) break; case 17: - // DF 17: extended squitter - // type 28 subtype 2: ACAS RA report - // first byte has the type/subtype, remaining bytes match the BDS 3,0 format + case 18: + // DF 17/18: extended squitter if (mm->metype == 28 && mm->mesub == 2 && memcmp(&mm->ME[1], &a->fatsv_emitted_bds_30[1], 6) != 0) { + // type 28 subtype 2: ACAS RA report + // first byte has the type/subtype, remaining bytes match the BDS 3,0 format memcpy(a->fatsv_emitted_bds_30, &mm->ME[1], 6); writeFATSVEventMessage(mm, "es_acas_ra", mm->ME, 7); } else if (mm->metype == 31 && (mm->mesub == 0 || mm->mesub == 1) && memcmp(mm->ME, a->fatsv_emitted_es_status, 7) != 0) { + // aircraft operational status memcpy(a->fatsv_emitted_es_status, mm->ME, 7); writeFATSVEventMessage(mm, "es_op_status", mm->ME, 7); } else if (mm->metype == 29 && (mm->mesub == 0 || mm->mesub == 1) && memcmp(mm->ME, a->fatsv_emitted_es_target, 7) != 0) { + // target state and status memcpy(a->fatsv_emitted_es_target, mm->ME, 7); writeFATSVEventMessage(mm, "es_target", mm->ME, 7); } @@ -1797,6 +1800,7 @@ static void writeFATSV() int headingValid = 0; int headingMagValid = 0; int airgroundValid = 0; + int categoryValid = 0; uint64_t minAge; @@ -1824,6 +1828,7 @@ static void writeFATSV() speedValid = trackDataValidEx(&a->speed_valid, now, 15000, SOURCE_MODE_S_CHECKED); speedIASValid = trackDataValidEx(&a->speed_ias_valid, now, 15000, SOURCE_MODE_S_CHECKED); speedTASValid = trackDataValidEx(&a->speed_tas_valid, now, 15000, SOURCE_MODE_S_CHECKED); + categoryValid = trackDataValidEx(&a->category_valid, now, 15000, SOURCE_MODE_S_CHECKED); // If we are definitely on the ground, suppress any unreliable altitude info. // When on the ground, ADS-B transponders don't emit an ADS-B message that includes @@ -1899,7 +1904,7 @@ static void writeFATSV() p += snprintf(p, bufsize(p, end), "\taddrtype\t%s", addrtype_short_string(a->addrtype)); } - if (trackDataValidEx(&a->callsign_valid, now, 120000, SOURCE_MODE_S_CHECKED)) { // we accept quite old idents as they shouldn't change often + if (trackDataValidEx(&a->callsign_valid, now, 15000, SOURCE_MODE_S_CHECKED) && strcmp(a->callsign, " ") != 0 && a->callsign_valid.updated > a->fatsv_last_emitted) { p += snprintf(p, bufsize(p,end), "\tident\t%s", a->callsign); switch (a->callsign_valid.source) { case SOURCE_MODE_S: @@ -1919,13 +1924,16 @@ static void writeFATSV() if (a->callsign_valid.source == SOURCE_TISB) { used_tisb = 1; } + + useful = 1; } - if (trackDataValidEx(&a->squawk_valid, now, 120000, SOURCE_MODE_S)) { // we accept quite old squawks as they shouldn't change often + if (trackDataValidEx(&a->squawk_valid, now, 15000, SOURCE_MODE_S) && a->squawk_valid.updated > a->fatsv_last_emitted) { p += snprintf(p, bufsize(p,end), "\tsquawk\t%04x", a->squawk); if (a->squawk_valid.source == SOURCE_TISB) { used_tisb = 1; } + useful = 1; } // only emit alt, speed, latlon, track if they have been received since the last time @@ -2002,7 +2010,7 @@ static void writeFATSV() useful = 1; } - if (airgroundValid && (a->airground == AG_GROUND || a->airground == AG_AIRBORNE)) { + if (airgroundValid && (a->airground == AG_GROUND || a->airground == AG_AIRBORNE) && a->airground_valid.updated > a->fatsv_last_emitted) { p += snprintf(p, bufsize(p,end), "\tairGround\t%s", a->airground == AG_GROUND ? "G+" : "A+"); a->fatsv_emitted_airground = a->airground; if (a->airground_valid.source == SOURCE_TISB) { @@ -2011,9 +2019,17 @@ static void writeFATSV() useful = 1; } - // if we didn't get at least an alt or a speed or a latlon or - // a heading, bail out. We don't need to do anything special - // to unwind prepareWrite(). + if (categoryValid && (a->category & 0xF0) != 0xA0 && a->category_valid.updated > a->fatsv_last_emitted) { + // interesting category, not a regular aircraft + p += snprintf(p, bufsize(p,end), "\tcategory\t%02X", a->category); + if (a->category_valid.source == SOURCE_TISB) { + used_tisb = 1; + } + useful = 1; + } + + // if we didn't get anything interesting, bail out. + // We don't need to do anything special to unwind prepareWrite(). if (!useful) { continue; } diff --git a/public_html/test/markers_test.html b/public_html/test/markers_test.html new file mode 100644 index 0000000..f89ad9b --- /dev/null +++ b/public_html/test/markers_test.html @@ -0,0 +1,18 @@ + + + + + + + + + + + DUMP1090 MARKERS TEST + + + +
+ + + diff --git a/public_html/test/markers_test.js b/public_html/test/markers_test.js new file mode 100644 index 0000000..c8e7bcf --- /dev/null +++ b/public_html/test/markers_test.js @@ -0,0 +1,75 @@ +"use strict"; + +var MarkerLayer; +var NextLon = 0; +var NextLat = 0; + +function setup_markers_test() { + MarkerLayer = new ol.layer.Vector({ + source: new ol.source.Vector(), + }); + + var map = new ol.Map({ + target: 'map_canvas', + layers: [ + MarkerLayer + ], + view: new ol.View({ + center: ol.proj.fromLonLat([5, 0]), + zoom: 7 + }), + controls: [new ol.control.Zoom(), + new ol.control.Rotate()], + loadTilesWhileAnimating: true, + loadTilesWhileInteracting: true + }); + + for (var type in TypeIcons) { + add_marker(type, TypeIcons[type]); + } + + for (var category in CategoryIcons) { + add_marker(category, CategoryIcons[category]); + } + + add_marker("Default", DefaultIcon); + + map.getView().setCenter(ol.proj.fromLonLat([5, NextLat/2])); +} + +function add_marker(title, baseMarker) { + var weight = (1 / baseMarker.scale).toFixed(1); + var icon = new ol.style.Icon({ + anchor: baseMarker.anchor, + anchorXUnits: 'pixels', + anchorYUnits: 'pixels', + scale: baseMarker.scale, + imgSize: baseMarker.size, + src: svgPathToURI(baseMarker.path, baseMarker.size, '#000000', weight, '#00C000'), + rotation: 0, + opacity: 1.0, + rotateWithView: (baseMarker.noRotate ? false : true) + }); + + var markerStyle = new ol.style.Style({ + image: icon, + text: new ol.style.Text({ + textAlign: 'center', + textBaseline: 'top', + offsetY: 30, + text: title, + scale: 1.5 + }) + }); + + var pos = [NextLon, NextLat]; + var marker = new ol.Feature(new ol.geom.Point(ol.proj.fromLonLat(pos))); + marker.setStyle(markerStyle); + MarkerLayer.getSource().addFeature(marker); + + NextLon += 1; + if (NextLon >= 10) { + NextLon -= 10; + NextLat -= 1; + } +}