From 6968bf92a6502074f527dae2c3ff25ca940fef71 Mon Sep 17 00:00:00 2001 From: terribl Date: Thu, 9 May 2013 17:59:26 +0300 Subject: [PATCH 1/3] Splitted gmap.html to multiple files in new 'public_html'-directory. Changes to 'dump1090.c'-file made accordingly. modified: .gitignore modified: dump1090.c deleted: gmap.html new file: public_html/gmap.html new file: public_html/script.js new file: public_html/style.css --- .gitignore | 2 + dump1090.c | 95 ++++++++++++--------- gmap.html | 180 ---------------------------------------- public_html/gmap.html | 23 ++++++ public_html/script.js | 188 ++++++++++++++++++++++++++++++++++++++++++ public_html/style.css | 34 ++++++++ 6 files changed, 304 insertions(+), 218 deletions(-) delete mode 100644 gmap.html create mode 100644 public_html/gmap.html create mode 100644 public_html/script.js create mode 100644 public_html/style.css diff --git a/.gitignore b/.gitignore index 0984522..90a0967 100644 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,5 @@ testfiles/*.bin misc frames.js .*.swp +~* + diff --git a/dump1090.c b/dump1090.c index ce07cca..897e9eb 100644 --- a/dump1090.c +++ b/dump1090.c @@ -3066,23 +3066,23 @@ char *aircraftsToJson(int *len) { altitude = (int) (altitude / 3.2828); speed = (int) (speed * 1.852); } - - if (a->lat != 0 && a->lon != 0) { - l = snprintf(p,buflen, - "{\"hex\":\"%06x\", \"flight\":\"%s\", \"lat\":%f, " - "\"lon\":%f, \"altitude\":%d, \"track\":%d, " - "\"speed\":%d},\n", - a->addr, a->flight, a->lat, a->lon, a->altitude, a->track, - a->speed); - p += l; buflen -= l; - /* Resize if needed. */ - if (buflen < 256) { - int used = p-buf; - buflen += 1024; /* Our increment. */ - buf = (char *) realloc(buf,used+buflen); - p = buf+used; - } + + l = snprintf(p,buflen, + "{\"hex\":\"%06x\", \"squawk\":\"%04x\", \"flight\":\"%s\", \"lat\":%f, " + "\"lon\":%f, \"altitude\":%d, \"track\":%d, " + "\"speed\":%d},\n", + a->addr, a->modeA, a->flight, a->lat, a->lon, a->altitude, a->track, + a->speed); + p += l; buflen -= l; + + /* Resize if needed. */ + if (buflen < 256) { + int used = p-buf; + buflen += 1024; // Our increment. + buf = (char *) realloc(buf,used+buflen); + p = buf+used; } + a = a->next; } /* Remove the final comma if any, and closes the json array. */ @@ -3099,7 +3099,9 @@ char *aircraftsToJson(int *len) { } #define MODES_CONTENT_TYPE_HTML "text/html;charset=utf-8" +#define MODES_CONTENT_TYPE_CSS "text/css;charset=utf-8" #define MODES_CONTENT_TYPE_JSON "application/json;charset=utf-8" +#define MODES_CONTENT_TYPE_JS "application/javascript;charset=utf-8" /* Get an HTTP request header and write the response to the client. * Again here we assume that the socket buffer is enough without doing @@ -3112,22 +3114,23 @@ int handleHTTPRequest(struct client *c) { int clen, hdrlen; int httpver, keepalive; char *p, *url, *content; - char *ctype; + char ctype[48]; + char getFile[1024]; if (Modes.debug & MODES_DEBUG_NET) printf("\nHTTP request: %s\n", c->buf); - /* Minimally parse the request. */ + // Minimally parse the request. httpver = (strstr(c->buf, "HTTP/1.1") != NULL) ? 11 : 10; if (httpver == 10) { - /* HTTP 1.0 defaults to close, unless otherwise specified. */ + // HTTP 1.0 defaults to close, unless otherwise specified. keepalive = strstr(c->buf, "Connection: keep-alive") != NULL; } else if (httpver == 11) { - /* HTTP 1.1 defaults to keep-alive, unless close is specified. */ + // HTTP 1.1 defaults to keep-alive, unless close is specified. keepalive = strstr(c->buf, "Connection: close") == NULL; } - /* Identify he URL. */ + // Identify he URL. p = strchr(c->buf,' '); if (!p) return 1; /* There should be the method and a space... */ url = ++p; /* Now this should point to the requested URL. */ @@ -3139,35 +3142,52 @@ int handleHTTPRequest(struct client *c) { printf("\nHTTP keep alive: %d\n", keepalive); printf("HTTP requested URL: %s\n\n", url); } + + if (strlen(url) < 2) { + snprintf(getFile, sizeof getFile, "./public_html/gmap.html"); // Default file + } else { + snprintf(getFile, sizeof getFile, "./public_html%s", url); + } /* Select the content to send, we have just two so far: * "/" -> Our google map application. * "/data.json" -> Our ajax request to update planes. */ if (strstr(url, "/data.json")) { content = aircraftsToJson(&clen); - ctype = MODES_CONTENT_TYPE_JSON; + //snprintf(ctype, sizeof ctype, MODES_CONTENT_TYPE_JSON); } else { struct stat sbuf; int fd = -1; - if (stat("gmap.html",&sbuf) != -1 && - (fd = open("gmap.html",O_RDONLY)) != -1) - { + if (stat(getFile, &sbuf) != -1 && (fd = open(getFile, O_RDONLY)) != -1) { content = (char *) malloc(sbuf.st_size); - if (read(fd,content,sbuf.st_size) == -1) { - snprintf(content,sbuf.st_size,"Error reading from file: %s", - strerror(errno)); + if (read(fd, content, sbuf.st_size) == -1) { + snprintf(content, sbuf.st_size, "Error reading from file: %s", strerror(errno)); } clen = sbuf.st_size; } else { char buf[128]; - - clen = snprintf(buf,sizeof(buf),"Error opening HTML file: %s", - strerror(errno)); + clen = snprintf(buf,sizeof(buf),"Error opening HTML file: %s", strerror(errno)); content = strdup(buf); } - if (fd != -1) close(fd); - ctype = MODES_CONTENT_TYPE_HTML; + + if (fd != -1) { + close(fd); + } + } + + // Get file extension and content type + snprintf(ctype, sizeof ctype, MODES_CONTENT_TYPE_HTML); // Default content type + char *ext = strrchr(getFile, '.'); + + if (strlen(ext) > 0) { + if (strstr(ext, ".json")) { + snprintf(ctype, sizeof ctype, MODES_CONTENT_TYPE_JSON); + } else if (strstr(ext, ".css")) { + snprintf(ctype, sizeof ctype, MODES_CONTENT_TYPE_CSS); + } else if (strstr(ext, ".js")) { + snprintf(ctype, sizeof ctype, MODES_CONTENT_TYPE_JS); + } } /* Create the header and send the reply. */ @@ -3182,13 +3202,12 @@ int handleHTTPRequest(struct client *c) { keepalive ? "keep-alive" : "close", clen); - if (Modes.debug & MODES_DEBUG_NET) + if (Modes.debug & MODES_DEBUG_NET) { printf("HTTP Reply header:\n%s", hdr); + } - /* Send header and content. */ - if (write(c->fd, hdr, hdrlen) == -1 || - write(c->fd, content, clen) == -1) - { + // Send header and content. + if (write(c->fd, hdr, hdrlen) == -1 || write(c->fd, content, clen) == -1) { free(content); return 1; } diff --git a/gmap.html b/gmap.html deleted file mode 100644 index b39a30a..0000000 --- a/gmap.html +++ /dev/null @@ -1,180 +0,0 @@ - - - - - - - - - - - -
-
-
-

Dump1090

-

-

Click on a plane for info.

-
-
- - diff --git a/public_html/gmap.html b/public_html/gmap.html new file mode 100644 index 0000000..e7f2ffb --- /dev/null +++ b/public_html/gmap.html @@ -0,0 +1,23 @@ + + + + + + + + + + + + +
+
+
+

Dump1090 - 00:00:00 UTC

+

+

Click on a plane for info.

+
+ +
+ + diff --git a/public_html/script.js b/public_html/script.js new file mode 100644 index 0000000..2105bc3 --- /dev/null +++ b/public_html/script.js @@ -0,0 +1,188 @@ +Map = null; +CenterLat = 45.0; +CenterLon = 9.0; +ZoomLvl = 5; +Planes={}; +NumPlanes = 0; +Selected=null + +if (localStorage['CenterLat']) { CenterLat = Number(localStorage['CenterLat']); } +if (localStorage['CenterLon']) { CenterLon = Number(localStorage['CenterLon']); } +if (localStorage['ZoomLvl']) { ZoomLvl = Number(localStorage['ZoomLvl']); } + +function getIconForPlane(plane) { + var r = 255, g = 255, b = 0; + var maxalt = 40000; /* Max altitude in the average case */ + var invalt = maxalt-plane.altitude; + var selected = (Selected == plane.hex); + + if (invalt < 0) invalt = 0; + b = parseInt(255/maxalt*invalt); + return { + strokeWeight: (selected ? 2 : 1), + path: google.maps.SymbolPath.FORWARD_CLOSED_ARROW, + scale: 5, + fillColor: 'rgb('+r+','+g+','+b+')', + fillOpacity: 0.9, + rotation: plane.track + }; +} + +function selectPlane() { + if (!Planes[this.planehex]) return; + var old = Selected; + Selected = this.planehex; + if (Planes[old]) { + /* Remove the highlight in the previously selected plane. */ + Planes[old].marker.setIcon(getIconForPlane(Planes[old])); + } + Planes[Selected].marker.setIcon(getIconForPlane(Planes[Selected])); + refreshSelectedInfo(); +} + +function refreshGeneralInfo() { + var i = document.getElementById('geninfo'); + + i.innerHTML = NumPlanes+' planes on screen.'; +} + +function refreshSelectedInfo() { + var i = document.getElementById('selinfo'); + var p = Planes[Selected]; + + if (!p) return; + var html = 'ICAO: '+p.hex+'
'; + if (p.flight.length) { + html += ''+p.flight+'
'; + } + html += 'Altitude: '+p.altitude+' feet
'; + html += 'Speed: '+p.speed+' knots
'; + html += 'Coordinates: '+p.lat+', '+p.lon+'
'; + i.innerHTML = html; +} + +function fetchData() { + $.getJSON('/data.json', function(data) { + var stillhere = {} + for (var j=0; j < data.length; j++) { + var plane = data[j]; + var marker = null; + stillhere[plane.hex] = true; + plane.flight = $.trim(plane.flight); + + if (Planes[plane.hex]) { + var myplane = Planes[plane.hex]; + marker = myplane.marker; + var icon = marker.getIcon(); + var newpos = new google.maps.LatLng(plane.lat, plane.lon); + marker.setPosition(newpos); + marker.setIcon(getIconForPlane(plane)); + myplane.altitude = plane.altitude; + myplane.speed = plane.speed; + myplane.lat = plane.lat; + myplane.lon = plane.lon; + myplane.track = plane.track; + myplane.flight = plane.flight; + if (myplane.hex == Selected) + refreshSelectedInfo(); + } else { + marker = new google.maps.Marker({ + position: new google.maps.LatLng(plane.lat, plane.lon), + map: Map, + icon: getIconForPlane(plane) + }); + plane.marker = marker; + marker.planehex = plane.hex; + Planes[plane.hex] = plane; + + /* Trap clicks for this marker. */ + google.maps.event.addListener(marker, 'click', selectPlane); + } + if (plane.flight.length == 0) + marker.setTitle(plane.hex) + else + marker.setTitle(plane.flight+' ('+plane.hex+')') + } + NumPlanes = data.length; + + /* Remove idle planes. */ + for (var p in Planes) { + if (!stillhere[p]) { + Planes[p].marker.setMap(null); + delete Planes[p]; + } + } + }); +} + +function checkTime(i) { + if (i < 10) { + return "0" + i; + } + return i; +} + +function printTime() { + var currentTime = new Date(); + var hours = checkTime(currentTime.getUTCHours()); + var minutes = checkTime(currentTime.getUTCMinutes()); + var seconds = checkTime(currentTime.getUTCSeconds()); + + if (document.getElementById) { + document.getElementById('utcTime').innerHTML = + hours + ":" + minutes + ":" + seconds; + } +} + +function placeFooter() { + var windHeight = $(window).height(); + var footerHeight = $('#info_footer').height(); + var offset = parseInt(windHeight) - parseInt(footerHeight); + + var footerWidth = parseInt($('#info_footer').width()); + var infoWidth = parseInt($('#info').width()); + var marginLeft = parseInt((infoWidth / 2) - (footerWidth / 2)); + + $('#info_footer').css('top',offset); + $('#info_footer').css('margin-left',marginLeft); +} + +function initialize() { + var mapOptions = { + center: new google.maps.LatLng(CenterLat, CenterLon), + zoom: ZoomLvl, + mapTypeId: google.maps.MapTypeId.ROADMAP + }; + Map = new google.maps.Map(document.getElementById("map_canvas"), mapOptions); + + // show footer at info-area + $(function(){ + $(window).resize(function(e){ + placeFooter(); + }); + placeFooter(); + // hide it before it's positioned + $('#info_footer').css('display','inline'); + }); + + // Listener for newly created Map + google.maps.event.addListener(Map, 'center_changed', function() { + localStorage['CenterLat'] = Map.getCenter().lat(); + localStorage['CenterLon'] = Map.getCenter().lng(); + }); + + google.maps.event.addListener(Map, 'zoom_changed', function() { + localStorage['ZoomLvl'] = Map.getZoom(); + }); + + // Setup our timer to poll from the server. + window.setInterval(function() { + fetchData(); + refreshGeneralInfo(); + }, 1000); + + // Faster timer, smoother things + window.setInterval(function() { + printTime(); + }, 250); +} diff --git a/public_html/style.css b/public_html/style.css new file mode 100644 index 0000000..8c58273 --- /dev/null +++ b/public_html/style.css @@ -0,0 +1,34 @@ +html { height: 100% } +body { height: 100%; margin: 0; padding: 0 } +#map_canvas { height: 100% } +#info { +position: absolute; +width:20%; +height:100%; +bottom:0px; +right:0px; +top:0px; +background-color: white; +border-left:1px #666 solid; +font-family:Helvetica; +} +#info div { +padding:0px; +padding-left:10px; +margin:0px; +} +#info div h1 { +margin-top:10px; +font-size:16px; +} +#info div p { +font-size:14px; +color:#333; +} +#info_footer { +position: absolute; +display: none; +text-align: center; +padding:0px; +margin:0px; +} From c5fdde64e4be02b4d03851dd7aa2a1f6aeae01e6 Mon Sep 17 00:00:00 2001 From: terribl Date: Thu, 9 May 2013 21:57:33 +0300 Subject: [PATCH 2/3] Added resetMap()-function to web-view. + some small tweaks. modified: dump1090.c modified: public_html/script.js --- dump1090.c | 5 +- public_html/script.js | 112 ++++++++++++++++++++++++++---------------- 2 files changed, 73 insertions(+), 44 deletions(-) diff --git a/dump1090.c b/dump1090.c index 897e9eb..6fe1820 100644 --- a/dump1090.c +++ b/dump1090.c @@ -3051,6 +3051,7 @@ int decodeHexMessage(struct client *c) { /* Return a description of planes in json. */ char *aircraftsToJson(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; @@ -3070,9 +3071,9 @@ char *aircraftsToJson(int *len) { l = snprintf(p,buflen, "{\"hex\":\"%06x\", \"squawk\":\"%04x\", \"flight\":\"%s\", \"lat\":%f, " "\"lon\":%f, \"altitude\":%d, \"track\":%d, " - "\"speed\":%d},\n", + "\"speed\":%d, \"messages\":%ld, \"seen\":%d},\n", a->addr, a->modeA, a->flight, a->lat, a->lon, a->altitude, a->track, - a->speed); + a->speed, a->messages, (int)(now - a->seen)); p += l; buflen -= l; /* Resize if needed. */ diff --git a/public_html/script.js b/public_html/script.js index 2105bc3..1666f64 100644 --- a/public_html/script.js +++ b/public_html/script.js @@ -1,10 +1,11 @@ -Map = null; +Map = null; CenterLat = 45.0; CenterLon = 9.0; ZoomLvl = 5; -Planes={}; -NumPlanes = 0; -Selected=null +Planes = {}; +PlanesOnMap = 0; +PlanesOnGrid = 0; +Selected = null; if (localStorage['CenterLat']) { CenterLat = Number(localStorage['CenterLat']); } if (localStorage['CenterLon']) { CenterLon = Number(localStorage['CenterLon']); } @@ -12,7 +13,7 @@ if (localStorage['ZoomLvl']) { ZoomLvl = Number(localStorage['ZoomLvl']); } function getIconForPlane(plane) { var r = 255, g = 255, b = 0; - var maxalt = 40000; /* Max altitude in the average case */ + var maxalt = 40000; // Max altitude in the average case var invalt = maxalt-plane.altitude; var selected = (Selected == plane.hex); @@ -42,8 +43,9 @@ function selectPlane() { function refreshGeneralInfo() { var i = document.getElementById('geninfo'); - - i.innerHTML = NumPlanes+' planes on screen.'; + + i.innerHTML = PlanesOnGrid + ' planes on grid.
'; + i.innerHTML += PlanesOnMap + ' planes on map.'; } function refreshSelectedInfo() { @@ -58,53 +60,69 @@ function refreshSelectedInfo() { html += 'Altitude: '+p.altitude+' feet
'; html += 'Speed: '+p.speed+' knots
'; html += 'Coordinates: '+p.lat+', '+p.lon+'
'; + html += 'Messages: '+p.messages+'
'; + html += 'Seen: '+p.seen+' sec
'; i.innerHTML = html; } function fetchData() { $.getJSON('/data.json', function(data) { var stillhere = {} + PlanesOnMap = 0; + for (var j=0; j < data.length; j++) { var plane = data[j]; - var marker = null; stillhere[plane.hex] = true; plane.flight = $.trim(plane.flight); + + if (plane.lat != 0 && plane.lon != 0) { + // Show only planes with position + var marker = null; + PlanesOnMap++; + + if (Planes[plane.hex]) { + // Move and refresh old plane on map + var myplane = Planes[plane.hex]; + marker = myplane.marker; + var icon = marker.getIcon(); + var newpos = new google.maps.LatLng(plane.lat, plane.lon); + marker.setPosition(newpos); + marker.setIcon(getIconForPlane(plane)); + myplane.altitude = plane.altitude; + myplane.speed = plane.speed; + myplane.lat = plane.lat; + myplane.lon = plane.lon; + myplane.track = plane.track; + myplane.flight = plane.flight; + myplane.seen = plane.seen; + myplane.messages = plane.messages; + if (myplane.hex == Selected) + refreshSelectedInfo(); + } else { + // Add new plane to map + marker = new google.maps.Marker({ + position: new google.maps.LatLng(plane.lat, plane.lon), + map: Map, + icon: getIconForPlane(plane) + }); + plane.marker = marker; + marker.planehex = plane.hex; + Planes[plane.hex] = plane; - if (Planes[plane.hex]) { - var myplane = Planes[plane.hex]; - marker = myplane.marker; - var icon = marker.getIcon(); - var newpos = new google.maps.LatLng(plane.lat, plane.lon); - marker.setPosition(newpos); - marker.setIcon(getIconForPlane(plane)); - myplane.altitude = plane.altitude; - myplane.speed = plane.speed; - myplane.lat = plane.lat; - myplane.lon = plane.lon; - myplane.track = plane.track; - myplane.flight = plane.flight; - if (myplane.hex == Selected) - refreshSelectedInfo(); - } else { - marker = new google.maps.Marker({ - position: new google.maps.LatLng(plane.lat, plane.lon), - map: Map, - icon: getIconForPlane(plane) - }); - plane.marker = marker; - marker.planehex = plane.hex; - Planes[plane.hex] = plane; - - /* Trap clicks for this marker. */ - google.maps.event.addListener(marker, 'click', selectPlane); + // Trap clicks for this marker. + google.maps.event.addListener(marker, 'click', selectPlane); + } + + if (plane.flight.length == 0) { + marker.setTitle(plane.hex) + } else { + marker.setTitle(plane.flight+' ('+plane.hex+')') + } } - if (plane.flight.length == 0) - marker.setTitle(plane.hex) - else - marker.setTitle(plane.flight+' ('+plane.hex+')') } - NumPlanes = data.length; + PlanesOnGrid = data.length; + /* Remove idle planes. */ for (var p in Planes) { if (!stillhere[p]) { @@ -143,8 +161,18 @@ function placeFooter() { var infoWidth = parseInt($('#info').width()); var marginLeft = parseInt((infoWidth / 2) - (footerWidth / 2)); - $('#info_footer').css('top',offset); - $('#info_footer').css('margin-left',marginLeft); + $('#info_footer').css('top', offset); + $('#info_footer').css('margin-left', marginLeft); +} + +function resetMap() { + localStorage['CenterLat'] = 45.0; + localStorage['CenterLon'] = 9.0; + localStorage['ZoomLvl'] = 5; + Map.setZoom(parseInt(localStorage['ZoomLvl'])); + Map.setCenter(new google.maps.LatLng(parseInt(localStorage['CenterLat']), parseInt(localStorage['CenterLon']))); + Selected = null; + document.getElementById('selinfo').innerHTML = ''; } function initialize() { From 914923f8bb827791ce72cd5c5602144e6760334e Mon Sep 17 00:00:00 2001 From: Malcolm Robb Date: Fri, 10 May 2013 00:12:36 +0100 Subject: [PATCH 3/3] Fix terribl's commit for Microsoft C Microsoft Visual C 6.0 doesn't support inline declaration of variables. Also, need to update the version number. --- dump1090.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/dump1090.c b/dump1090.c index 6fe1820..5156138 100644 --- a/dump1090.c +++ b/dump1090.c @@ -56,7 +56,7 @@ // 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.04.0705.13" +#define MODES_DUMP1090_VERSION "1.04.0905.13" #define MODES_DEFAULT_RATE 2000000 #define MODES_DEFAULT_FREQ 1090000000 @@ -3117,6 +3117,7 @@ int handleHTTPRequest(struct client *c) { char *p, *url, *content; char ctype[48]; char getFile[1024]; + char *ext; if (Modes.debug & MODES_DEBUG_NET) printf("\nHTTP request: %s\n", c->buf); @@ -3179,7 +3180,7 @@ int handleHTTPRequest(struct client *c) { // Get file extension and content type snprintf(ctype, sizeof ctype, MODES_CONTENT_TYPE_HTML); // Default content type - char *ext = strrchr(getFile, '.'); + ext = strrchr(getFile, '.'); if (strlen(ext) > 0) { if (strstr(ext, ".json")) {