diff --git a/debian/changelog b/debian/changelog index 884b953..8ed7acf 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,9 @@ +dump1090-mutability (1.10.3010.14mu-10) UNRELEASED; urgency=medium + + * JSON / webmap cleanups. + + -- Oliver Jowett Mon, 05 Jan 2015 21:43:58 +0000 + dump1090-mutability (1.10.3010.14mu-9) unstable; urgency=medium * Fix warnings. Add -Werror so they break the build in future. diff --git a/net_io.c b/net_io.c index 1d60c83..eeefb21 100644 --- a/net_io.c +++ b/net_io.c @@ -671,58 +671,59 @@ char *generateAircraftJson(int *len) { time_t now = time(NULL); struct aircraft *a = Modes.aircrafts; int buflen = 1024; // The initial buffer is incremented as needed - char *buf = (char *) malloc(buflen), *p = buf; - int l; + char *buf = (char *) malloc(buflen), *p = buf, *end = buf+buflen; + int first = 1; + + p += snprintf(p, end-p, + "{ \"now\" : %d,\n" + " \"aircraft\" : [", + (int)now); - l = snprintf(p,buflen,"[\n"); - p += l; buflen -= l; while(a) { - int position = 0; - int track = 0; - if (a->modeACflags & MODEAC_MSG_FLAG) { // skip any fudged ICAO records Mode A/C a = a->next; continue; } - if (a->bFlags & MODES_ACFLAGS_LATLON_VALID) { - position = 1; - } + if (first) + first = 0; + else + *p++ = ','; + + p += snprintf(p, end-p, "\n {\"hex\":\"%06x\"", a->addr); + if (a->bFlags & MODES_ACFLAGS_SQUAWK_VALID) + p += snprintf(p, end-p, ",\"squawk\":\"%04x\"", a->modeA); + if (a->bFlags & MODES_ACFLAGS_CALLSIGN_VALID) + p += snprintf(p, end-p, ",\"flight\":\"%s\"", a->flight); + if (a->bFlags & MODES_ACFLAGS_LATLON_VALID) + p += snprintf(p, end-p, ",\"lat\":%f,\"lon\":%f", a->lat, a->lon); + if ((a->bFlags & MODES_ACFLAGS_AOG_VALID) && (a->bFlags & MODES_ACFLAGS_AOG)) + p += snprintf(p, end-p, ",\"altitude\":\"ground\""); + else if (a->bFlags & MODES_ACFLAGS_ALTITUDE_VALID) + p += snprintf(p, end-p, ",\"altitude\":%d", a->altitude); + if (a->bFlags & MODES_ACFLAGS_VERTRATE_VALID) + p += snprintf(p, end-p, ",\"vert_rate\":%d", a->vert_rate); + if (a->bFlags & MODES_ACFLAGS_HEADING_VALID) + p += snprintf(p, end-p, ",\"track\":%d", a->track); + if (a->bFlags & MODES_ACFLAGS_SPEED_VALID) + p += snprintf(p, end-p, ",\"speed\":%d", a->speed); + + p += snprintf(p, end-p, ",\"messages\":%ld, \"seen\":%d}", + a->messages, (int)(now - a->seen)); - if (a->bFlags & MODES_ACFLAGS_HEADING_VALID) { - track = 1; - } - - // No metric conversion - l = snprintf(p,buflen, - "{\"hex\":\"%06x\", \"squawk\":\"%04x\", \"flight\":\"%s\", \"lat\":%f, " - "\"lon\":%f, \"validposition\":%d, \"altitude\":%d, \"vert_rate\":%d,\"track\":%d, \"validtrack\":%d," - "\"speed\":%d, \"messages\":%ld, \"seen\":%d},\n", - a->addr, a->modeA, a->flight, a->lat, a->lon, position, a->altitude, a->vert_rate, a->track, track, - a->speed, a->messages, (int)(now - a->seen)); - p += l; buflen -= l; - - //Resize if needed - if (buflen < 256) { - int used = p-buf; - buflen += 1024; // Our increment. - buf = (char *) realloc(buf,used+buflen); + // If we're getting near the end of the buffer, expand it. + if ((end - p) < 256) { + int used = p - buf; + buflen *= 2; + buf = (char *) realloc(buf, buflen); p = buf+used; + end = buf + buflen; } a = a->next; } - //Remove the final comma if any, and closes the json array. - if (*(p-2) == ',') { - *(p-2) = '\n'; - p--; - buflen++; - } - - l = snprintf(p,buflen,"]\n"); - p += l; buflen -= l; - + p += snprintf(p, end-p, "\n ]\n}\n"); *len = p-buf; return buf; } diff --git a/public_html/planeObject.js b/public_html/planeObject.js index 98153fd..a4748af 100644 --- a/public_html/planeObject.js +++ b/public_html/planeObject.js @@ -20,10 +20,6 @@ var planeObject = { messages : null, seen : null, - // Vaild... - vPosition : false, - vTrack : false, - // GMap Details marker : null, markerColor : MarkerColor, @@ -130,85 +126,69 @@ var planeObject = { }, // Update our data - funcUpdateData : function(data){ - // So we can find out if we moved - var oldlat = this.latitude; - var oldlon = this.longitude; - var oldalt = this.altitude; - - // Update all of our data - this.updated = new Date().getTime(); + funcUpdateData : function(receiver_now,data){ + // So we can find out if we moved + var oldlat = this.latitude; + var oldlon = this.longitude; + var oldalt = this.altitude; + + // Update all of our data + this.updated = new Date().getTime(); + this.icao = data.hex; + this.messages = data.messages; + this.seen = data.seen; + + if (typeof data.altitude !== "undefined") this.altitude = data.altitude; - this.speed = data.speed; - this.track = data.track; + if (typeof data.speed !== "undefined") + this.speed = data.speed; + if (typeof data.track !== "undefined") + this.track = data.track; + if (typeof data.lat !== "undefined") { this.latitude = data.lat; this.longitude = data.lon; + } + if (typeof data.flight !== "undefined") this.flight = data.flight; + if (typeof data.squawk !== "undefined") this.squawk = data.squawk; - this.icao = data.hex; - this.messages = data.messages; - this.seen = data.seen; - // If no packet in over 58 seconds, consider the plane reapable - // This way we can hold it, but not show it just in case the plane comes back - if (this.seen > 58) { - this.reapable = true; - if (this.marker) { - this.marker.setMap(null); - this.marker = null; + // If no packet in over 58 seconds, consider the plane reapable + // This way we can hold it, but not show it just in case the plane comes back + if (this.seen > 58) { + this.reapable = true; + if (this.marker) { + this.marker.setMap(null); + this.marker = null; + } + if (this.line) { + this.line.setMap(null); + this.line = null; + } + if (SelectedPlane == this.icao) { + if (this.is_selected) { + this.is_selected = false; } - if (this.line) { - this.line.setMap(null); - this.line = null; + SelectedPlane = null; + } + } else { + this.reapable = false; + } + + // Is the position valid? + if (!this.reapable && typeof data.lat !== "undefined") { + // Detech if the plane has moved + if (oldlat != this.latitude || oldlon != this.longitude) { + this.funcAddToTrack(); + if (this.is_selected) { + this.line = this.funcUpdateLines(); } - if (SelectedPlane == this.icao) { - if (this.is_selected) { - this.is_selected = false; - } - SelectedPlane = null; - } - } else { - if (this.reapable == true) { - } - this.reapable = false; } - // Is the position valid? - if ((data.validposition == 1) && (this.reapable == false)) { - this.vPosition = true; - - // Detech if the plane has moved - changeLat = false; - changeLon = false; - changeAlt = false; - if (oldlat != this.latitude) { - changeLat = true; - } - if (oldlon != this.longitude) { - changeLon = true; - } - if (oldalt != this.altitude) { - changeAlt = true; - } - // Right now we only care about lat/long, if alt is updated only, oh well - if ((changeLat == true) || (changeLon == true)) { - this.funcAddToTrack(); - if (this.is_selected) { - this.line = this.funcUpdateLines(); - } - } - this.marker = this.funcUpdateMarker(); - PlanesOnMap++; - } else { - this.vPosition = false; - } - - // Do we have a valid track for the plane? - if (data.validtrack == 1) - this.vTrack = true; - else - this.vTrack = false; - }, + this.marker = this.funcUpdateMarker(); + PlanesOnMap++; + } + }, // Update our marker on the map funcUpdateMarker: function() { @@ -231,7 +211,7 @@ var planeObject = { } // Setting the marker title - if (this.flight.length == 0) { + if (this.flight === null || this.flight.length == 0) { this.marker.setTitle(this.hex); } else { this.marker.setTitle(this.flight+' ('+this.icao+')'); diff --git a/public_html/script.js b/public_html/script.js index 2d95fb5..81b5002 100644 --- a/public_html/script.js +++ b/public_html/script.js @@ -7,10 +7,9 @@ var PlanesToReap = 0; var SelectedPlane = null; var SpecialSquawk = false; -var iSortCol=-1; -var bSortASC=true; -var bDefaultSortASC=true; -var iDefaultSortCol=3; +var sortColumn = 3; +var sortAscending = true; +var sortNumeric = true; // Get current map settings CenterLat = Number(localStorage['CenterLat']) || CONST_CENTERLAT; @@ -22,32 +21,34 @@ RefreshInterval = 1000; function fetchData() { $.getJSON('data/aircraft.json', function(data) { - PlanesOnMap = 0 + PlanesOnMap = 0; SpecialSquawk = false; // Loop through all the planes in the data packet - for (var j=0; j < data.length; j++) { + console.log("I was called\n"); + var now = data.now; + var acs = data.aircraft; + for (var j=0; j < acs.length; j++) { + var ac = acs[j]; // Do we already have this plane object in Planes? // If not make it. - if (Planes[data[j].hex]) { - var plane = Planes[data[j].hex]; + if (Planes[ac.hex]) { + var plane = Planes[ac.hex]; } else { var plane = jQuery.extend(true, {}, planeObject); + Planes[ac.hex] = plane; } // Set SpecialSquawk-value - if (data[j].squawk == '7500' || data[j].squawk == '7600' || data[j].squawk == '7700') { + if (ac.squawk == '7500' || ac.squawk == '7600' || ac.squawk == '7700') { SpecialSquawk = true; } // Call the function update - plane.funcUpdateData(data[j]); - - // Copy the plane into Planes - Planes[plane.icao] = plane; + plane.funcUpdateData(now, ac); } - PlanesOnTable = data.length; + PlanesOnTable = acs.length; }); } @@ -291,15 +292,17 @@ function refreshSelected() { } html += ''; - if (selected) { - if (Metric) { - html += 'Altitude: ' + Math.round(selected.altitude / 3.2828) + ' m'; + if (selected && selected.altitude !== null) { + if (selected.altitude === "ground") + html += 'Altitude: on ground'; + else if (Metric) { + html += 'Altitude: ' + Math.round(selected.altitude / 3.2828) + ' m'; + } else { + html += 'Altitude: ' + selected.altitude + ' ft'; + } } else { - html += 'Altitude: ' + selected.altitude + ' ft'; + html += 'Altitude: n/a'; } - } else { - html += 'Altitude: n/a'; - } if (selected && selected.squawk != '0000') { html += 'Squawk: ' + selected.squawk + ''; @@ -326,15 +329,15 @@ function refreshSelected() { } html += 'Track: ' - if (selected && selected.vTrack) { - html += selected.track + '°' + ' (' + normalizeTrack(selected.track, selected.vTrack)[1] +')'; + if (selected && selected.track !== null) { + html += selected.track + '°' + ' (' + trackLongName(selected.track) +')'; } else { html += 'n/a'; } html += ' '; html += 'Lat/Long: '; - if (selected && selected.vPosition) { + if (selected && selected.latitude !== null) { html += selected.latitude + ', ' + selected.longitude + ''; // Let's show some extra data if we have site coordinates @@ -366,73 +369,38 @@ function refreshSelected() { document.getElementById('plane_detail').innerHTML = html; } -// Right now we have no means to validate the speed is good -// Want to return (n/a) when we dont have it -// TODO: Edit C code to add a valid speed flag -// TODO: Edit js code to use said flag -function normalizeSpeed(speed, valid) { - return speed +function trackShortName(track) { + var trackIndex = Math.floor((track+22.5) / 45); + if ((trackIndex < 0) || (trackIndex >= 8)) + return "n/a"; + return ["N","NE","E","SE","S","SW","W","NW"][trackIndex]; } -// Returns back a long string, short string, and the track if we have a vaild track path -function normalizeTrack(track, valid){ - x = [] - if ((track > -1) && (track < 22.5)) { - x = ["North", "N", track] - } - if ((track > 22.5) && (track < 67.5)) { - x = ["North East", "NE", track] - } - if ((track > 67.5) && (track < 112.5)) { - x = ["East", "E", track] - } - if ((track > 112.5) && (track < 157.5)) { - x = ["South East", "SE", track] - } - if ((track > 157.5) && (track < 202.5)) { - x = ["South", "S", track] - } - if ((track > 202.5) && (track < 247.5)) { - x = ["South West", "SW", track] - } - if ((track > 247.5) && (track < 292.5)) { - x = ["West", "W", track] - } - if ((track > 292.5) && (track < 337.5)) { - x = ["North West", "NW", track] - } - if ((track > 337.5) && (track < 361)) { - x = ["North", "N", track] - } - if (!valid) { - x = [" ", "n/a", ""] - } - return x +function trackLongName(track) { + var trackIndex = Math.floor((track+22.5) / 45); + if ((trackIndex < 0) || (trackIndex >= 8)) + return "n/a"; + return ["North","Northeast","East","Southeast","South","Southwest","West","Northwest"][trackIndex]; } // Refeshes the larger table of all the planes + function refreshTableInfo() { var html = ''; html += ''; - html += ''; - html += ''; - html += ''; - html += ''; - html += ''; - // Add distance column header to table if site coordinates are provided + html += ''; + html += ''; + html += ''; + html += ''; + html += ''; + // Add distance column header to table if site coordinates are provided if (SiteShow && (typeof SiteLat !== 'undefined' || typeof SiteLon !== 'undefined')) { - html += ''; + html += ''; } - html += ''; - html += ''; - html += ''; + html += ''; + html += ''; + html += ''; + for (var tablep in Planes) { var tableplane = Planes[tablep] if (!tableplane.reapable) { @@ -454,70 +422,76 @@ function refreshTableInfo() { specialStyle += " squawk7700"; } - if (tableplane.vPosition == true) { + if (tableplane.latitude !== null) html += ''; - } else { + else html += ''; - } - + html += ''; - html += ''; - if (tableplane.squawk != '0000' ) { - html += ''; - } else { - html += ''; - } - - if (Metric) { - html += ''; - html += ''; - } else { - html += ''; - html += ''; - } + + if (tableplane.flight !== null) + html += ''; + else + html += ''; + + if (tableplane.squawk !== null) + html += ''; + else + html += ''; + + if (tableplane.altitude === null) + html += ''; + else if (tableplane.altitude === "ground") + html += ''; + else if (Metric) + html += ''; + else + html += ''; + + if (tableplane.speed === null) + html += ''; + else if (Metric) + html += ''; + else + html += ''; + // Add distance column to table if site coordinates are provided if (SiteShow && (typeof SiteLat !== 'undefined' || typeof SiteLon !== 'undefined')) { - html += ''; + html += ''; } html += ''; + if (tableplane.track !== null) + html += tableplane.track; + html += ''; html += ''; html += ''; html += ''; } } html += '
ICAOFlightSquawkAltitudeSpeedICAOFlightSquawkAltitudeSpeedDistanceDistanceTrackMsgsSeen
TrackMsgsSeen
' + tableplane.icao + '' + tableplane.flight + '' + tableplane.squawk + ' ' + Math.round(tableplane.altitude / 3.2828) + '' + Math.round(tableplane.speed * 1.852) + '' + tableplane.altitude + '' + tableplane.speed + '' + tableplane.flight + '' + tableplane.squawk + ' ground' + Math.round(tableplane.altitude / 3.2828) + '' + tableplane.altitude + ' ' + Math.round(tableplane.speed * 1.852) + '' + tableplane.speed + ''; - if (tableplane.vPosition) { - var siteLatLon = new google.maps.LatLng(SiteLat, SiteLon); - var planeLatLon = new google.maps.LatLng(tableplane.latitude, tableplane.longitude); - var dist = google.maps.geometry.spherical.computeDistanceBetween (siteLatLon, planeLatLon); - if (Metric) { - dist /= 1000; - } else { - dist /= 1852; - } - dist = (Math.round((dist)*10)/10).toFixed(1); - html += dist; - } else { - html += '0'; - } - html += ''; + if (tableplane.latitude !== null) { + var siteLatLon = new google.maps.LatLng(SiteLat, SiteLon); + var planeLatLon = new google.maps.LatLng(tableplane.latitude, tableplane.longitude); + var dist = google.maps.geometry.spherical.computeDistanceBetween (siteLatLon, planeLatLon); + if (Metric) { + dist /= 1000; + } else { + dist /= 1852; + } + dist = (Math.round((dist)*10)/10).toFixed(1); + html += dist; + } + html += ''; - if (tableplane.vTrack) { - html += normalizeTrack(tableplane.track, tableplane.vTrack)[2]; - // html += ' (' + normalizeTrack(tableplane.track, tableplane.vTrack)[1] + ')'; - } else { - html += ' '; - } - html += '' + tableplane.messages + '' + tableplane.seen + '
'; - + document.getElementById('planes_table').innerHTML = html; - + if (SpecialSquawk) { - $('#SpecialSquawkWarning').css('display', 'inline'); - } else { - $('#SpecialSquawkWarning').css('display', 'none'); - } - + $('#SpecialSquawkWarning').css('display', 'inline'); + } else { + $('#SpecialSquawkWarning').css('display', 'none'); + } + // Click event for table $('#planes_table').find('tr').click( function(){ var hex = $(this).find('td:first').text(); @@ -527,65 +501,59 @@ function refreshTableInfo() { refreshSelected(); } }); - - sortTable("tableinfo"); + + resortTable(); } -// Credit goes to a co-worker that needed a similar functions for something else -// we get a copy of it free ;) -function setASC_DESC(iCol) { - if(iSortCol==iCol) { - bSortASC=!bSortASC; - } else { - bSortASC=bDefaultSortASC; - } +function sortBy(colName,numeric) { + var header_cells = document.getElementById('tableinfo').tHead.rows[0].cells; + for (var i = 0; i < header_cells.length; ++i) { + if (header_cells[i].id === colName) { + if (i == sortColumn) + sortAscending = !sortAscending; + else { + sortColumn = i; + sortNumeric = numeric; + sortAscending = true; + } + + resortTable(); + return; + } + } + + console.warn("column not found: " + colName); } -function sortTable(szTableID,iCol) { - //if iCol was not provided, and iSortCol is not set, assign default value - if (typeof iCol==='undefined'){ - if(iSortCol!=-1){ - var iCol=iSortCol; - } else if (SiteShow && (typeof SiteLat !== 'undefined' || typeof SiteLon !== 'undefined')) { - var iCol=5; - } else { - var iCol=iDefaultSortCol; - } - } +function resortTable() { + sortTable('tableinfo', sortColumn, sortAscending, sortNumeric); +} +function sortTable(tableId, col, asc, numeric) { //retrieve passed table element - var oTbl=document.getElementById(szTableID).tBodies[0]; + var oTbl=document.getElementById(tableId).tBodies[0]; var aStore=[]; - - //If supplied col # is greater than the actual number of cols, set sel col = to last col - if (typeof oTbl.rows[0] !== 'undefined' && oTbl.rows[0].cells.length <= iCol) { - iCol=(oTbl.rows[0].cells.length-1); - } - - //store the col # - iSortCol=iCol; - - //determine if we are delaing with numerical, or alphanumeric content - var bNumeric = false; - if ((typeof oTbl.rows[0] !== 'undefined') && - (!isNaN(parseFloat(oTbl.rows[0].cells[iSortCol].textContent || - oTbl.rows[0].cells[iSortCol].innerText)))) { - bNumeric = true; - } - + //loop through the rows, storing each one inro aStore - for (var i=0,iLen=oTbl.rows.length;i