partial commit of changes that should not break things in master
parent
4819e6a59a
commit
88a79489c0
|
@ -58,13 +58,13 @@ function update()
|
|||
|
||||
if(lastseen != null)
|
||||
d3.select("#freshness").html(lastseen.fromNow());
|
||||
d3.json("global", function(d) {
|
||||
d3.json("global.json", function(d) {
|
||||
lastseen = moment(1000*d["last-seen"]);
|
||||
d3.select("#freshness").html(lastseen.fromNow());
|
||||
});
|
||||
|
||||
|
||||
d3.json("almanac", function(d) {
|
||||
d3.json("almanac.json", function(d) {
|
||||
// put data in an array
|
||||
sats=d;
|
||||
var arr=[];
|
||||
|
@ -86,9 +86,6 @@ function update()
|
|||
var livearr=[];
|
||||
for(n = 0 ; n < arr.length; n++)
|
||||
{
|
||||
if(arr[n].sv[0]!='G')
|
||||
continue;
|
||||
|
||||
livearr.push(arr[n]);
|
||||
}
|
||||
|
||||
|
|
|
@ -22,13 +22,18 @@ function maketable(str, arr)
|
|||
.data(columns)
|
||||
.enter()
|
||||
.append("th")
|
||||
.text(function(column) {
|
||||
.html(function(column) {
|
||||
if(column == "delta_hz_corr")
|
||||
return "ΔHz";
|
||||
if(column == "delta-gps")
|
||||
return "ΔGPS ns";
|
||||
if(column == "delta-utc")
|
||||
return "ΔUTC ns";
|
||||
if(column == "sources")
|
||||
return '<a href="observers.html">sources</a>';
|
||||
if(column == "alma-dist")
|
||||
return '<a href="almanac.html">alma-dist</a>';
|
||||
|
||||
else
|
||||
return column;
|
||||
});
|
||||
|
@ -53,7 +58,7 @@ function maketable(str, arr)
|
|||
|
||||
ret.value = '<img width="16" height="16" src="https://ds9a.nl/tmp/'+ img +'"/>';
|
||||
// ret.value="";
|
||||
ret.value += " "+row.sv;
|
||||
ret.value += " <a href='sv.html?gnssid=2&sv="+row.svid+"&sigid="+row.sigid+"'>"+row.sv+"</a>";
|
||||
}
|
||||
else if(column == "aodc/e") {
|
||||
if(row["aodc"] != null && row["aode"] != null)
|
||||
|
@ -168,13 +173,13 @@ function update()
|
|||
d3.select("#freshness").html(lastseen.fromNow());
|
||||
|
||||
|
||||
d3.json("global", function(d) {
|
||||
d3.json("global.json", function(d) {
|
||||
d3.select('#facts').html("Galileo-UTC offset: <b>"+d["utc-offset-ns"].toFixed(2)+"</b> ns, Galileo-GPS offset: <b>"+d["gps-offset-ns"].toFixed(2)+"</b> ns, GPS UTC offset: <b>"+d["gps-utc-offset-ns"].toFixed(2)+"</b>. "+d["leap-seconds"]+"</b> leap seconds");
|
||||
lastseen = moment(1000*d["last-seen"]);
|
||||
d3.select("#freshness").html(lastseen.fromNow());
|
||||
});
|
||||
|
||||
d3.json("svs", function(d) {
|
||||
d3.json("svs.json", function(d) {
|
||||
// put data in an array
|
||||
sats=d;
|
||||
var arr=[];
|
||||
|
@ -186,7 +191,8 @@ function update()
|
|||
o.elev="";
|
||||
Object.keys(o.perrecv).forEach(function(k) {
|
||||
if(o.perrecv[k]["last-seen-s"] < 1800) {
|
||||
o.sources = o.sources + k +" ";
|
||||
o.sources = o.sources + '<a href="observer.html?observer=' + k + '">'+k+'</a> ';
|
||||
|
||||
o.db = o.db + o.perrecv[k].db +" ";
|
||||
if(o.perrecv[k].elev != null)
|
||||
o.elev = o.elev + o.perrecv[k].elev.toFixed(0)+" ";
|
||||
|
@ -203,7 +209,7 @@ function update()
|
|||
if(o.prres == null)
|
||||
o.prres ="";
|
||||
if(o.perrecv[k].prres != null)
|
||||
o.prres = o.prres + o.perrecv[k].prres.toFixed(1)+" ";
|
||||
o.prres = o.prres + o.perrecv[k].prres.toFixed(0)+" ";
|
||||
else
|
||||
o.prres = o.prres + "_ ";
|
||||
|
||||
|
|
|
@ -0,0 +1,128 @@
|
|||
body {
|
||||
height: 100%;
|
||||
margin: 0;
|
||||
width: 100%;
|
||||
float: left;
|
||||
background-color: #ccc;
|
||||
font-family: verdana, helvetica, arial, sans-serif;
|
||||
}
|
||||
|
||||
#galmongeo {
|
||||
border: blue 1px solid;
|
||||
margin: 5px;
|
||||
padding: 10px;
|
||||
width: 98%;
|
||||
background-color: white;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
}
|
||||
|
||||
#galmoninfo {
|
||||
border-top: blue 1px solid;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
#combined {
|
||||
display: inline-block;
|
||||
position: relative;
|
||||
background-color: transparent;
|
||||
// background-color: yellow;
|
||||
height: 700px;
|
||||
width: 100%;
|
||||
//margin-left: auto;
|
||||
//margin-right: auto;
|
||||
margin: 10px;
|
||||
}
|
||||
|
||||
#svgworld {
|
||||
position: absolute; top: 0; right: 0; bottom: 0; left: 0;
|
||||
// border: blue 1px solid;
|
||||
display: inline-block;
|
||||
// margin-left: auto;
|
||||
// margin-right: auto;
|
||||
}
|
||||
|
||||
#svggraticule {
|
||||
position: absolute; top: 0; right: 0; bottom: 0; left: 0;
|
||||
// border: blue 1px solid;
|
||||
display: inline-block;
|
||||
// margin-left: auto;
|
||||
// margin-right: auto;
|
||||
}
|
||||
|
||||
#svgobservers {
|
||||
position: absolute; top: 0; right: 0; bottom: 0; left: 0;
|
||||
// border: blue 1px solid;
|
||||
display: inline-block;
|
||||
// margin-left: auto;
|
||||
// margin-right: auto;
|
||||
}
|
||||
|
||||
#svgalmanac {
|
||||
position: absolute; top: 0; right: 0; bottom: 0; left: 0;
|
||||
// border: blue 1px solid;
|
||||
display: inline-block;
|
||||
// margin-left: auto;
|
||||
// margin-right: auto;
|
||||
}
|
||||
|
||||
svg {
|
||||
// border: red 1px solid;
|
||||
// background-color: transparent;
|
||||
padding: 20px;
|
||||
// margin-left: auto;
|
||||
// margin-right: auto;
|
||||
}
|
||||
|
||||
path.countries {
|
||||
stroke-width: 1;
|
||||
stroke: #75739F;
|
||||
fill: #5EAFC6;
|
||||
}
|
||||
path.coverage {
|
||||
stroke-width: 1;
|
||||
stroke: #888;
|
||||
fill: #888;
|
||||
fill-opacity: 0.1;
|
||||
}
|
||||
circle.sats {
|
||||
stroke-width: 1;
|
||||
stroke: #4F442B;
|
||||
//fill: #FCBC34;
|
||||
}
|
||||
text.labels {
|
||||
// stroke-width: 1;
|
||||
// stroke: #4F442B;
|
||||
// fill: #FCBC34;
|
||||
font-family: courier new, courier;
|
||||
font-style: italic;
|
||||
}
|
||||
circle.centroid {
|
||||
fill: #75739F;
|
||||
pointer-events: none;
|
||||
}
|
||||
rect.bbox {
|
||||
fill: none;
|
||||
stroke-dasharray: 5 5;
|
||||
stroke: #75739F;
|
||||
stroke-width: 2;
|
||||
pointer-events: none;
|
||||
}
|
||||
path.graticule {
|
||||
fill: none;
|
||||
stroke-width: 1;
|
||||
stroke: #9A8B7A;
|
||||
}
|
||||
path.graticule.line {
|
||||
stroke: #E5E1DE;
|
||||
}
|
||||
path.graticule.outline {
|
||||
stroke: #9A8B7A;
|
||||
}
|
||||
|
||||
path.merged {
|
||||
fill: #9A8B7A;
|
||||
stroke: #4F442B;
|
||||
stroke-width: 2px;
|
||||
}
|
||||
|
479
html/geo/geo.js
479
html/geo/geo.js
|
@ -1,110 +1,385 @@
|
|||
//
|
||||
//
|
||||
//
|
||||
|
||||
var fileWorld = "world.geojson";
|
||||
var fileAlmanac = "../almanac.json" // "https://galmon.eu/almanac"
|
||||
var fileObservers = "../observers.json" // "https://galmon.eu/observers"
|
||||
|
||||
var projectionChoice = "Fahey";
|
||||
var projectionChoice = "CylindricalStereographic";
|
||||
var projectionChoice = "Equirectangular";
|
||||
//var projectionChoice = "Aitoff";
|
||||
|
||||
//
|
||||
//
|
||||
//
|
||||
|
||||
var svgWorld = d3.select("#svgworld");
|
||||
var idWorld = document.getElementById("svgworld");
|
||||
|
||||
var svgGraticule = d3.select("#svggraticule");
|
||||
var idGraticule = document.getElementById("svggraticule");
|
||||
|
||||
var svgObservers = d3.select("#svgobservers");
|
||||
var idObservers = document.getElementById("svgobservers");
|
||||
|
||||
var svgAlmanac = d3.select("#svgalmanac");
|
||||
var idAlmanac = document.getElementById("svgalmanac");
|
||||
|
||||
var geoPath;
|
||||
var aProjection;
|
||||
|
||||
function draw_world(data_world)
|
||||
{
|
||||
// console.log("draw_world() " + data_world.features.length);
|
||||
|
||||
svgWorld.selectAll("path")
|
||||
.data(data_world.features)
|
||||
.enter()
|
||||
.append("path")
|
||||
.attr("class", "countries")
|
||||
.attr("d", geoPath);
|
||||
}
|
||||
|
||||
function draw_graticule()
|
||||
{
|
||||
// Graticule
|
||||
var graticule = d3.geoGraticule();
|
||||
|
||||
// console.log("draw_graticule()");
|
||||
|
||||
svgGraticule.selectAll("path")
|
||||
.data(graticule.lines())
|
||||
.enter()
|
||||
.append("path")
|
||||
.attr("class", "graticule line")
|
||||
.attr("id", function(d) {
|
||||
var c = d.coordinates;
|
||||
if (c[0][0] == c[1][0]) {
|
||||
return (c[0][0] < 0) ? -c[0][0] + "W" : +c[0][0] + "E";
|
||||
} else if (c[0][1] == c[1][1]) {
|
||||
return (c[0][1] < 0) ? -c[0][1] + "S" : c[0][1] + "N";
|
||||
}
|
||||
})
|
||||
.attr("d", geoPath);
|
||||
|
||||
svgGraticule.selectAll('text')
|
||||
.data(graticule.lines())
|
||||
.enter()
|
||||
.append("text")
|
||||
.text(function(d) {
|
||||
var c = d.coordinates;
|
||||
if ((c[0][0] == c[1][0]) && (c[0][0] % 30 == 0)) {
|
||||
return (c[0][0]);
|
||||
} else if (c[0][1] == c[1][1]) {
|
||||
return (c[0][1]);
|
||||
}
|
||||
})
|
||||
.attr("class","label")
|
||||
.attr("style", function(d) {
|
||||
var c = d.coordinates;
|
||||
return (c[0][1] == c[1][1]) ? "text-anchor: end" : "text-anchor: middle";
|
||||
})
|
||||
.attr("dx", function(d) {
|
||||
var c = d.coordinates;
|
||||
return (c[0][1] == c[1][1]) ? -10 : 0;
|
||||
})
|
||||
.attr("dy", function(d) {
|
||||
var c = d.coordinates;
|
||||
return (c[0][1] == c[1][1]) ? 4 : 10;
|
||||
})
|
||||
.attr('transform', function(d) {
|
||||
var c = d.coordinates;
|
||||
return ('translate(' + aProjection(c[0]) + ')')
|
||||
});
|
||||
|
||||
svgGraticule.append("path")
|
||||
.datum(graticule.outline)
|
||||
.attr("class", "graticule outline")
|
||||
.attr("d", geoPath);
|
||||
}
|
||||
|
||||
function get_almanac_valid(data_almanac)
|
||||
{
|
||||
var a=[];
|
||||
Object.keys(data_almanac).forEach(function(e) {
|
||||
var o = data_almanac[e];
|
||||
o.sv = e;
|
||||
if (o["eph-latitude"] != null) {
|
||||
a.push(o);
|
||||
}
|
||||
});
|
||||
return a;
|
||||
}
|
||||
|
||||
function draw_almanac(data_almanac)
|
||||
{
|
||||
var arr = get_almanac_valid(data_almanac);
|
||||
|
||||
console.log("draw_almanac() " + arr.length);
|
||||
|
||||
svgAlmanac.selectAll("circle")
|
||||
.data(arr)
|
||||
.enter()
|
||||
.append("circle")
|
||||
.attr("class", "sats")
|
||||
.attr("r", 3)
|
||||
.attr("cx", d => aProjection([d["eph-longitude"],d["eph-latitude"]])[0])
|
||||
.attr("cy", d => aProjection([d["eph-longitude"],d["eph-latitude"]])[1])
|
||||
.attr("fill", function(d) {
|
||||
switch (d.gnssid) {
|
||||
case 0: return "green"; // GPS
|
||||
case 1: return "gray"; // SBAS - not coded
|
||||
case 2: return "blue"; // Galileo
|
||||
case 3: return "red"; // BeiDou
|
||||
case 4: return "gray"; // IMES - not coded
|
||||
case 5: return "gray"; // QZSS - not coded
|
||||
case 6: return "yellow"; // GLONASS
|
||||
default: return "magenta"; // - should not happen
|
||||
}
|
||||
});
|
||||
|
||||
svgAlmanac.selectAll("text")
|
||||
.data(arr)
|
||||
.enter()
|
||||
.append("text")
|
||||
.attr("class", "labels")
|
||||
.text(d => d.sv)
|
||||
.attr("dx", d => 5+aProjection([d["eph-longitude"],d["eph-latitude"]])[0])
|
||||
.attr("dy", d => 5+aProjection([d["eph-longitude"],d["eph-latitude"]])[1])
|
||||
.attr("fill", function(d) {
|
||||
if (d.observed==true)
|
||||
return "black";
|
||||
return "#666666";
|
||||
})
|
||||
.attr("font-weight", function(d) {
|
||||
if (d.observed==true)
|
||||
return "bold";
|
||||
return null;
|
||||
});
|
||||
}
|
||||
|
||||
function draw_observers(data_observers)
|
||||
{
|
||||
console.log("draw_observers() " + data_observers.length);
|
||||
|
||||
svgObservers.selectAll("rect")
|
||||
.data(data_observers)
|
||||
.enter()
|
||||
.append("rect")
|
||||
.attr("class", "sats")
|
||||
.attr("width", 8)
|
||||
.attr("height", 8)
|
||||
.attr("x", d => aProjection([d["longitude"],d["latitude"]])[0]-4)
|
||||
.attr("y", d => aProjection([d["longitude"],d["latitude"]])[1]-4)
|
||||
.attr("fill", function(d) { return "black"; });
|
||||
|
||||
}
|
||||
|
||||
function draw_observers_coverage(data_observers)
|
||||
{
|
||||
var radius = 55; // XXX fix
|
||||
var geoCircle = d3.geoCircle();
|
||||
svgObservers.selectAll("path")
|
||||
.data(data_observers)
|
||||
.enter()
|
||||
.append("path")
|
||||
.attr("class", "coverage")
|
||||
.attr("d", function(r) {
|
||||
// console.log([r["longitude"], r["latitude"]] + " = " + aProjection([r["longitude"], r["latitude"]]));
|
||||
return geoPath(geoCircle.center([r["longitude"],r["latitude"]]).radius(radius)());
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
var display_observers_count = 0;
|
||||
|
||||
function do_update_almanac(error, results)
|
||||
{
|
||||
var data_almanac = results[0];
|
||||
var data_observers = results[1];
|
||||
|
||||
// console.log("do_update_almanac() " + Object.keys(data_almanac).length + " " + data_observers.length);
|
||||
|
||||
if (display_observers_count == 0) {
|
||||
// does not need that much updating!
|
||||
svgObservers.html("");
|
||||
draw_observers(data_observers);
|
||||
draw_observers_coverage(data_observers)
|
||||
display_observers_count = 10;
|
||||
}
|
||||
display_observers_count--;
|
||||
|
||||
// We write into the svgalmanac area - so clean it and rewrite it
|
||||
svgAlmanac.html("");
|
||||
draw_almanac(data_almanac);
|
||||
}
|
||||
|
||||
var repeat;
|
||||
|
||||
var world={};
|
||||
d3.json("world.geojson", function(result) {
|
||||
world=result;
|
||||
update();
|
||||
});
|
||||
|
||||
var oldsats=[];
|
||||
|
||||
function update()
|
||||
function do_timer()
|
||||
{
|
||||
var seconds = 60;
|
||||
clearTimeout(repeat);
|
||||
repeat=setTimeout(update, 1000.0*seconds);
|
||||
var seconds = 60;
|
||||
clearTimeout(repeat);
|
||||
repeat = setTimeout(do_timer, 1000.0*seconds);
|
||||
|
||||
d3.queue(1).defer(d3.json, "../almanac").defer(d3.json, "../observers").awaitAll(ready);
|
||||
|
||||
function ready(error, results)
|
||||
{
|
||||
// var aProjection = d3.geoMercator().scale(100).translate([250,250]);
|
||||
|
||||
// all this complexity is so we can scale to full screen.
|
||||
// see: https://stackoverflow.com/questions/14492284/center-a-map-in-d3-given-a-geojson-object
|
||||
|
||||
var mapDiv = document.getElementById("map");
|
||||
|
||||
var center = [0,0];
|
||||
var scale = 150;
|
||||
var offset = [mapDiv.clientWidth/2, mapDiv.clientHeight/2];
|
||||
|
||||
var aProjection = d3.geoEquirectangular().scale(scale).translate([mapDiv.clientWidth/2,mapDiv.clientHeight/2]);
|
||||
var geoPath = d3.geoPath().projection(aProjection);
|
||||
|
||||
// using the path determine the bounds of the current map and use
|
||||
// these to determine better values for the scale and translation
|
||||
var bounds = geoPath.bounds(world);
|
||||
var hscale = scale*mapDiv.clientWidth / (bounds[1][0] - bounds[0][0]);
|
||||
var vscale = scale*mapDiv.clientHeight / (bounds[1][1] - bounds[0][1]);
|
||||
scale = (hscale < vscale) ? hscale : vscale;
|
||||
var offset = [mapDiv.clientWidth - (bounds[0][0] + bounds[1][0])/2,
|
||||
mapDiv.clientHeight - (bounds[0][1] + bounds[1][1])/2];
|
||||
|
||||
// new projection
|
||||
aProjection = d3.geoEquirectangular().center(center)
|
||||
.scale(scale).translate(offset);
|
||||
|
||||
geoPath = d3.geoPath().projection(aProjection);
|
||||
|
||||
var svg =d3.select("svg");
|
||||
svg.html("");
|
||||
|
||||
svg.attr("width", mapDiv.clientWidth);
|
||||
svg.attr("height", mapDiv.clientHeight);
|
||||
|
||||
|
||||
svg.selectAll("path").data(world.features)
|
||||
.enter()
|
||||
.append("path")
|
||||
.attr("d", geoPath)
|
||||
.attr("class", "countries");
|
||||
|
||||
var arr=[];
|
||||
Object.keys(results[0]).forEach(function(e) {
|
||||
var o = results[0][e];
|
||||
o.sv=e;
|
||||
|
||||
if(o["eph-latitude"] != null) {
|
||||
arr.push(o);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
svg.selectAll("circle").data(arr)
|
||||
.enter()
|
||||
.append("circle")
|
||||
.attr("class", "sats")
|
||||
.attr("r", 3)
|
||||
.attr("cx", d => aProjection([d["eph-longitude"],d["eph-latitude"]])[0])
|
||||
.attr("cy", d => aProjection([d["eph-longitude"],d["eph-latitude"]])[1])
|
||||
.attr("fill", function(d) { if(d.gnssid==2) return "blue";
|
||||
else if(d.gnssid==3) return "red";
|
||||
else if(d.gnssid==6) return "yellow";
|
||||
else return "green"; });
|
||||
|
||||
svg.selectAll("text").data(arr)
|
||||
.enter()
|
||||
.append("text")
|
||||
.attr("dx", d => 5+aProjection([d["eph-longitude"],d["eph-latitude"]])[0])
|
||||
.attr("dy", d => 5+aProjection([d["eph-longitude"],d["eph-latitude"]])[1])
|
||||
.text(d => d.sv)
|
||||
.attr("fill", function(d) { if(d.observed==true) return "black"; return "#666666"; })
|
||||
.attr("font-weight", function(d) { if(d.observed==true) return "bold"; return null; });
|
||||
|
||||
svg.selectAll("rect").data(results[1])
|
||||
.enter()
|
||||
.append("rect")
|
||||
.attr("class", "sats")
|
||||
.attr("width", 8)
|
||||
.attr("height", 8)
|
||||
.attr("x", d => aProjection([d["longitude"],d["latitude"]])[0]-4)
|
||||
.attr("y", d => aProjection([d["longitude"],d["latitude"]])[1]-4)
|
||||
.attr("fill", function(d) { console.log("Hallo!"); return "black"; });
|
||||
|
||||
}
|
||||
d3.queue(1)
|
||||
.defer(d3.json, fileAlmanac)
|
||||
.defer(d3.json, fileObservers)
|
||||
.awaitAll(do_update_almanac);
|
||||
}
|
||||
|
||||
function set_projection(data_world)
|
||||
{
|
||||
// var aProjection = d3.geoMercator().scale(100).translate([250,250]);
|
||||
// all this complexity is so we can scale to full screen.
|
||||
// see: https://stackoverflow.com/questions/14492284/center-a-map-in-d3-given-a-geojson-object
|
||||
|
||||
var center = [0,0]; // This is very Euro-centric - but that's how these projections works.
|
||||
var scale = 210; // No idea what this does
|
||||
|
||||
var idCombined = document.getElementById("combined");
|
||||
|
||||
svgWorld = d3.select("#svgworld");
|
||||
idWorld = document.getElementById("svgworld");
|
||||
|
||||
svgGraticule = d3.select("#svggraticule");
|
||||
idGraticule = document.getElementById("svggraticule");
|
||||
|
||||
switch(projectionChoice) {
|
||||
default:
|
||||
console.log(projectionChoice + ": not coded");
|
||||
// fall thru to Equirectangular
|
||||
case 'Equirectangular':
|
||||
aProjection = d3.geoEquirectangular()
|
||||
.scale(scale)
|
||||
.translate([idCombined.clientWidth/2,idCombined.clientHeight/2]);
|
||||
break;
|
||||
case 'Aitoff':
|
||||
aProjection = d3.geoAitoff()
|
||||
.scale(scale)
|
||||
.translate([idCombined.clientWidth/2,idCombined.clientHeight/2]);
|
||||
break;
|
||||
case 'CylindricalStereographic':
|
||||
aProjection = d3.geoCylindricalStereographic()
|
||||
.scale(scale)
|
||||
.translate([idCombined.clientWidth/2,idCombined.clientHeight/2]);
|
||||
break;
|
||||
case 'Fahey':
|
||||
aProjection = d3.geoFahey()
|
||||
.scale(scale)
|
||||
.translate([idCombined.clientWidth/2,idCombined.clientHeight/2]);
|
||||
break;
|
||||
case 'Gilbert':
|
||||
aProjection = d3.geoGilbert()
|
||||
.scale(scale)
|
||||
.translate([idCombined.clientWidth/2,idCombined.clientHeight/2]);
|
||||
break;
|
||||
}
|
||||
|
||||
geoPath = d3.geoPath()
|
||||
.projection(aProjection);
|
||||
|
||||
// using the path determine the bounds of the current map and use
|
||||
// these to determine better values for the scale and translation
|
||||
var bounds = geoPath.bounds(data_world);;
|
||||
var hscale = scale*idCombined.clientWidth / (bounds[1][0] - bounds[0][0]);
|
||||
var vscale = scale*idCombined.clientHeight / (bounds[1][1] - bounds[0][1]);
|
||||
scale = (hscale < vscale) ? hscale : vscale;
|
||||
var offset = [
|
||||
idCombined.clientWidth - (bounds[0][0] + bounds[1][0])/2,
|
||||
idCombined.clientHeight - (bounds[0][1] + bounds[1][1])/2
|
||||
];
|
||||
|
||||
if (0) {
|
||||
|
||||
// new projection
|
||||
switch(projectionChoice) {
|
||||
default:
|
||||
console.log(projectionChoice + ": not coded");
|
||||
// fall thru to Equirectangular
|
||||
case 'Equirectangular':
|
||||
aProjection = d3.geoEquirectangular()
|
||||
.center(center)
|
||||
.scale(scale)
|
||||
.translate(offset);
|
||||
break;
|
||||
case 'Aitoff':
|
||||
aProjection = d3.geoAitoff()
|
||||
.center(center) .scale(scale)
|
||||
.translate(offset);
|
||||
break;
|
||||
case 'CylindricalStereographic':
|
||||
aProjection = d3.geoCylindricalStereographic()
|
||||
.center(center)
|
||||
.scale(scale)
|
||||
.translate(offset);
|
||||
break;
|
||||
case 'Fahey':
|
||||
aProjection = d3.geoFahey()
|
||||
.center(center)
|
||||
.scale(scale)
|
||||
.translate(offset);
|
||||
break;
|
||||
case 'Gilbert':
|
||||
aProjection = d3.geoGilbert()
|
||||
.center(center)
|
||||
.scale(scale)
|
||||
.translate(offset);
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
console.log("do_draw_world() " + "width=" + idCombined.clientWidth + "," + "height=" + idCombined.clientHeight);
|
||||
|
||||
svgWorld.attr("width", idCombined.clientWidth);
|
||||
svgWorld.attr("height", idCombined.clientHeight);
|
||||
|
||||
svgObservers.attr("width", idCombined.clientWidth);
|
||||
svgObservers.attr("height", idCombined.clientHeight);
|
||||
|
||||
svgGraticule.attr("height", idCombined.clientHeight);
|
||||
svgGraticule.attr("width", idCombined.clientWidth);
|
||||
|
||||
svgAlmanac.attr("height", idCombined.clientHeight);
|
||||
svgAlmanac.attr("width", idCombined.clientWidth);
|
||||
|
||||
}
|
||||
|
||||
function do_draw_world(data_world)
|
||||
{
|
||||
// console.log("do_draw_world()");
|
||||
|
||||
set_projection(data_world);
|
||||
|
||||
svgWorld.html("");
|
||||
draw_world(data_world);
|
||||
|
||||
svgGraticule.html("");
|
||||
draw_graticule();
|
||||
}
|
||||
|
||||
function read_world()
|
||||
{
|
||||
// console.log("read_world()");
|
||||
d3.json(fileWorld, function(result) {
|
||||
var data_world = result;
|
||||
do_draw_world(data_world);
|
||||
// after the world is read in and displayed - then start the timers!
|
||||
// we don't redraw the world!
|
||||
do_timer();
|
||||
});
|
||||
}
|
||||
|
||||
function geo_start()
|
||||
{
|
||||
// console.log("geo_start()");
|
||||
read_world();
|
||||
}
|
||||
|
||||
geo_start();
|
||||
|
||||
// d3.select("body").onresize = do_timer;
|
||||
|
||||
// d3.select("body").onresize = update;
|
||||
|
|
|
@ -1,68 +1,30 @@
|
|||
<html>
|
||||
<head>
|
||||
<style>
|
||||
body,
|
||||
svg {
|
||||
height: 100%;
|
||||
margin: 0;
|
||||
width: 100%;
|
||||
float: left;
|
||||
}
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
|
||||
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||
<head>
|
||||
<title>galmon.eu geo</title>
|
||||
<link rel="stylesheet" type="text/css" href="geo.css">
|
||||
|
||||
<script src="../d3.v4.min.js"></script>
|
||||
<script src="../ext/topojson.v1.min.js"></script>
|
||||
<script src="../ext/d3-geo-projection.v2.min.js"></script>
|
||||
|
||||
path.countries {
|
||||
stroke-width: 1;
|
||||
stroke: #75739F;
|
||||
fill: #5EAFC6;
|
||||
}
|
||||
circle.sats {
|
||||
stroke-width: 1;
|
||||
stroke: #4F442B;
|
||||
// fill: #FCBC34;
|
||||
}
|
||||
circle.centroid {
|
||||
fill: #75739F;
|
||||
pointer-events: none;
|
||||
}
|
||||
rect.bbox {
|
||||
fill: none;
|
||||
stroke-dasharray: 5 5;
|
||||
stroke: #75739F;
|
||||
stroke-width: 2;
|
||||
pointer-events: none;
|
||||
}
|
||||
path.graticule {
|
||||
fill: none;
|
||||
stroke-width: 1;
|
||||
stroke: #9A8B7A;
|
||||
}
|
||||
path.graticule.outline {
|
||||
stroke: #9A8B7A;
|
||||
}
|
||||
</head>
|
||||
<body>
|
||||
<div id="galmongeo">
|
||||
<h1>galmon.eu geo</h1>
|
||||
<div id="galmoninfo">
|
||||
This is a live map from the <a href="/">galmon.eu</a> project</p>
|
||||
</div>
|
||||
<div id="combined">
|
||||
<svg id="svgworld"></svg>
|
||||
<svg id="svggraticule"></svg>
|
||||
<svg id="svgobservers"></svg>
|
||||
<svg id="svgalmanac"></svg>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
path.merged {
|
||||
fill: #9A8B7A;
|
||||
stroke: #4F442B;
|
||||
stroke-width: 2px;
|
||||
}
|
||||
|
||||
#map {
|
||||
position: fixed;
|
||||
left: 0px;
|
||||
right: 0px;
|
||||
top: 0px;
|
||||
bottom: 0px;
|
||||
}
|
||||
|
||||
|
||||
</style>
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<div id="map">
|
||||
<svg width="100%" height="100%"></svg>
|
||||
</div>
|
||||
<script src="../d3.v4.min.js"></script>
|
||||
<script src="geo.js"></script>
|
||||
</body>
|
||||
<script src="geo.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
|
||||
|
|
|
@ -6,7 +6,6 @@ text {
|
|||
font: 12px sans-serif;
|
||||
}
|
||||
|
||||
|
||||
th, td {
|
||||
padding-left: 8px;
|
||||
padding-right: 8px;
|
||||
|
@ -42,7 +41,7 @@ tr:nth-child(odd) {background: #FFF}
|
|||
|
||||
</style>
|
||||
<body>
|
||||
Last update: <span id="freshness"></span>. More information about this Galileo/GPS/BeiDou/Glonass open source monitor can be found <a href="https://github.com/ahupowerdns/galmon/blob/master/README.md#galmon">here</a>. <br/>
|
||||
Last update: <span id="freshness"></span>. More information about this Galileo/GPS/BeiDou/Glonass open source monitor can be found <a href="https://github.com/ahupowerdns/galmon/blob/master/README.md#galmon">here</a>. Live map <a href="geo">here!</a>. Contact <a href="https://ds9a.nl/">me</a> if you want access to the Grafana dashboard.<br/>
|
||||
<table id="svs"></table>
|
||||
<hr>
|
||||
<p>
|
||||
|
|
16
navdump.cc
16
navdump.cc
|
@ -125,11 +125,12 @@ try
|
|||
|
||||
gm.tow = nmm.gi().gnsstow();
|
||||
gmwtypes[{nmm.gi().gnsssv(), wtype}] = gm;
|
||||
static map<int,GalileoMessage> oldEph;
|
||||
cout << "gal inav for "<<nmm.gi().gnssid()<<","<<nmm.gi().gnsssv()<<","<<nmm.gi().sigid()<<" tow "<< nmm.gi().gnsstow()<<" wtype "<< wtype<<" ";
|
||||
static uint32_t tow;
|
||||
if(wtype == 4) {
|
||||
// 2^-34 2^-46
|
||||
cout <<" af0 "<<gm.af0 <<" af1 "<<gm.af1 <<", scaled: "<<ldexp(1.0*gm.af0, 19-34)<<", "<<ldexp(1.0*gm.af1, 38-46);
|
||||
cout <<" iodnav "<<gm.iodnav <<" af0 "<<gm.af0 <<" af1 "<<gm.af1 <<", scaled: "<<ldexp(1.0*gm.af0, 19-34)<<", "<<ldexp(1.0*gm.af1, 38-46);
|
||||
if(tow && oldgm4s.count(nmm.gi().gnsssv()) && oldgm4s[nmm.gi().gnsssv()].iodnav != gm.iodnav) {
|
||||
auto& oldgm4 = oldgm4s[nmm.gi().gnsssv()];
|
||||
auto oldOffset = oldgm4.getAtomicOffset(tow);
|
||||
|
@ -192,11 +193,14 @@ try
|
|||
}
|
||||
cout<<" "<<gmwtypes[{sv,9}].alma3.svid <<" af0 "<<gm.alma3.af0<<" af1 "<< gm.alma3.af1 <<" e5bhs "<< gm.alma3.e5bhs<<" e1bhs "<< gm.alma3.e1bhs <<" a0g " << gm.a0g <<" a1g "<< gm.a1g <<" t0g "<<gm.t0g <<" wn0g "<<gm.wn0g;
|
||||
}
|
||||
|
||||
cout<<endl;
|
||||
}
|
||||
else if(nmm.type() == NavMonMessage::GPSInavType) {
|
||||
if(skipGPS)
|
||||
if(skipGPS) {
|
||||
cout<<endl;
|
||||
continue;
|
||||
}
|
||||
|
||||
int sv = nmm.gpsi().gnsssv();
|
||||
auto cond = getCondensedGPSMessage(std::basic_string<uint8_t>((uint8_t*)nmm.gpsi().contents().c_str(), nmm.gpsi().contents().size()));
|
||||
|
@ -280,8 +284,10 @@ try
|
|||
cout<<"\n";
|
||||
}
|
||||
else if(nmm.type() == NavMonMessage::BeidouInavTypeD1) {
|
||||
if(skipBeidou)
|
||||
if(skipBeidou) {
|
||||
cout<<endl;
|
||||
continue;
|
||||
}
|
||||
|
||||
int sv = nmm.bid1().gnsssv();
|
||||
auto cond = getCondensedBeidouMessage(std::basic_string<uint8_t>((uint8_t*)nmm.bid1().contents().c_str(), nmm.bid1().contents().size()));
|
||||
|
@ -361,8 +367,10 @@ try
|
|||
|
||||
}
|
||||
else if(nmm.type() == NavMonMessage::GlonassInavType) {
|
||||
if(skipGlonass)
|
||||
if(skipGlonass) {
|
||||
cout<<endl;
|
||||
continue;
|
||||
}
|
||||
|
||||
static map<int, GlonassMessage> gms;
|
||||
auto& gm = gms[nmm.gloi().gnsssv()];
|
||||
|
|
216
navparse.cc
216
navparse.cc
|
@ -169,6 +169,7 @@ struct SVIOD
|
|||
double getOmegaE() const { return 7.2921151467 * pow(10.0, -5.0);} // rad/s
|
||||
|
||||
uint32_t getT0e() const { return t0e; }
|
||||
uint32_t getT0c() const { return 60*t0c; }
|
||||
double getSqrtA() const { return ldexp(sqrtA, -19); }
|
||||
double getE() const { return ldexp(e, -33); }
|
||||
double getCuc() const { return ldexp(cuc, -29); } // radians
|
||||
|
@ -253,7 +254,7 @@ struct SVStat
|
|||
bool sf1{0}, sf2{0}, sf3{0}, sf4{0}, sf5{0};
|
||||
int BGDE1E5a{0}, BGDE1E5b{0};
|
||||
bool e5bdvs{false}, e1bdvs{false};
|
||||
bool disturb1{false}, disturb2{false}, disturb3{false}, disturb4{false}, disturb5{false};
|
||||
|
||||
uint16_t wn{0}; // we put the "unrolled" week number here!
|
||||
uint32_t tow{0}; // "last seen"
|
||||
//
|
||||
|
@ -611,6 +612,24 @@ std::string humanTime(int gnssid, int wn, int tow)
|
|||
strftime(buffer, sizeof(buffer), "%a, %d %b %Y %T %z", &tm);
|
||||
return buffer;
|
||||
}
|
||||
char getGNSSChar(int id)
|
||||
{
|
||||
if(id==0)
|
||||
return 'G';
|
||||
if(id==2)
|
||||
return 'E';
|
||||
if(id==3)
|
||||
return 'C';
|
||||
if(id==6)
|
||||
return 'R';
|
||||
else
|
||||
return '0'+id;
|
||||
}
|
||||
|
||||
std::string makeSatIDName(const SatID& satid)
|
||||
{
|
||||
return fmt::sprintf("%c%02d@%d", getGNSSChar(satid.gnss), satid.sv, satid.sigid);
|
||||
}
|
||||
|
||||
std::optional<double> getHzCorrection(time_t now, int src, unsigned int gnssid, unsigned int sigid, const svstats_t svstats)
|
||||
{
|
||||
|
@ -639,19 +658,6 @@ std::optional<double> getHzCorrection(time_t now, int src, unsigned int gnssid,
|
|||
return allHzCorr;
|
||||
}
|
||||
|
||||
char getGNSSChar(int id)
|
||||
{
|
||||
if(id==0)
|
||||
return 'G';
|
||||
if(id==2)
|
||||
return 'E';
|
||||
if(id==3)
|
||||
return 'C';
|
||||
if(id==6)
|
||||
return 'R';
|
||||
else
|
||||
return '0'+id;
|
||||
}
|
||||
|
||||
|
||||
std::string humanBhs(int bhs)
|
||||
|
@ -677,7 +683,7 @@ try
|
|||
H2OWebserver h2s("galmon");
|
||||
|
||||
|
||||
h2s.addHandler("/global", [](auto handler, auto req) {
|
||||
h2s.addHandler("/global.json", [](auto handler, auto req) {
|
||||
nlohmann::json ret = nlohmann::json::object();
|
||||
auto svstats = g_statskeeper.get();
|
||||
ret["leap-seconds"] = g_dtLS;
|
||||
|
@ -749,7 +755,7 @@ try
|
|||
return ret;
|
||||
});
|
||||
|
||||
h2s.addHandler("/almanac", [](auto handler, auto req) {
|
||||
h2s.addHandler("/almanac.json", [](auto handler, auto req) {
|
||||
auto beidoualma = g_beidoualmakeeper.get();
|
||||
auto svstats = g_statskeeper.get();
|
||||
nlohmann::json ret = nlohmann::json::object();
|
||||
|
@ -950,7 +956,7 @@ try
|
|||
return ret;
|
||||
});
|
||||
|
||||
h2s.addHandler("/observers", [](auto handler, auto req) {
|
||||
h2s.addHandler("/observers.json", [](auto handler, auto req) {
|
||||
nlohmann::json ret = nlohmann::json::array();
|
||||
for(const auto& src : g_srcpos) {
|
||||
nlohmann::json obj;
|
||||
|
@ -963,12 +969,154 @@ try
|
|||
obj["longitude"] = longlat.first;
|
||||
obj["latitude"] = longlat.second;
|
||||
obj["last-seen"] = src.second.lastSeen;
|
||||
auto svstats = g_statskeeper.get();
|
||||
nlohmann::json svs = nlohmann::json::object();
|
||||
|
||||
for(const auto& sv : svstats) {
|
||||
if(auto iter = sv.second.perrecv.find(src.first); iter != sv.second.perrecv.end()) {
|
||||
if(iter->second.db > 0 && time(0) - iter->second.t < 120) {
|
||||
nlohmann::json svo = nlohmann::json::object();
|
||||
svo["db"] = iter->second.db;
|
||||
|
||||
svo["elev"] = iter->second.el;
|
||||
svo["azi"] = iter->second.azi;
|
||||
|
||||
Point sat;
|
||||
|
||||
if((sv.first.gnss == 0 || sv.first.gnss == 2) && sv.second.completeIOD())
|
||||
getCoordinates(latestTow(sv.first.gnss, svstats), sv.second.liveIOD(), & sat);
|
||||
if(sv.first.gnss == 3 && sv.second.oldBeidouMessage.sow >= 0 && sv.second.oldBeidouMessage.sqrtA != 0) {
|
||||
getCoordinates(latestTow(sv.first.gnss, svstats), sv.second.oldBeidouMessage, &sat);
|
||||
}
|
||||
if(sv.first.gnss == 6) {
|
||||
sat.x = sv.second.glonassMessage.x;
|
||||
sat.y = sv.second.glonassMessage.y;
|
||||
sat.z = sv.second.glonassMessage.z;
|
||||
}
|
||||
if(sat.x) {
|
||||
Point our = g_srcpos[iter->first].pos;
|
||||
svo["elev"] = getElevationDeg(sat, our);
|
||||
svo["azi"] = getAzimuthDeg(sat, our);
|
||||
}
|
||||
|
||||
|
||||
svo["prres"] = iter->second.prres;
|
||||
svo["age-s"] = time(0) - iter->second.t;
|
||||
svo["last-seen"] = iter->second.t;
|
||||
svo["gnss"] = sv.first.gnss;
|
||||
svo["sv"] = sv.first.sv;
|
||||
svo["sigid"] = sv.first.sigid;
|
||||
|
||||
svs[makeSatIDName(sv.first)] = svo;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
obj["svs"]=svs;
|
||||
|
||||
ret.push_back(obj);
|
||||
}
|
||||
return ret;
|
||||
});
|
||||
|
||||
h2s.addHandler("/sv.json", [](auto handler, auto req) {
|
||||
string_view path = convert(req->path);
|
||||
|
||||
nlohmann::json ret = nlohmann::json::object();
|
||||
|
||||
SatID id;
|
||||
auto pos = path.find("sv=");
|
||||
if(pos == string::npos) {
|
||||
return ret;
|
||||
}
|
||||
id.sv = atoi(&path[0] + pos+3);
|
||||
|
||||
pos = path.find("gnssid=");
|
||||
if(pos == string::npos) {
|
||||
return ret;
|
||||
}
|
||||
id.gnss = atoi(&path[0]+pos+7);
|
||||
id.sigid = 1;
|
||||
pos = path.find("sigid=");
|
||||
if(pos != string::npos) {
|
||||
id.sigid = atoi(&path[0]+pos+7);
|
||||
}
|
||||
|
||||
|
||||
auto svstats = g_statskeeper.get();
|
||||
|
||||
ret["sv"] = id.sv;
|
||||
ret["gnssid"] =id.gnss;
|
||||
ret["sigid"] = id.sigid;
|
||||
auto iter = svstats.find(id);
|
||||
if(iter == svstats.end())
|
||||
return ret;
|
||||
const auto& s= iter->second;
|
||||
ret["a0"] = s.a0;
|
||||
ret["a1"] = s.a1;
|
||||
ret["a0g"] = s.a0g;
|
||||
ret["a1g"] = s.a1g;
|
||||
ret["sf1"] = s.sf1;
|
||||
ret["sf2"] = s.sf2;
|
||||
ret["sf3"] = s.sf3;
|
||||
ret["sf4"] = s.sf4;
|
||||
ret["sf5"] = s.sf5;
|
||||
ret["ai0"] = s.ai0;
|
||||
ret["ai1"] = s.ai1;
|
||||
ret["ai2"] = s.ai2;
|
||||
ret["BGDE1E5a"] = s.BGDE1E5a;
|
||||
ret["BGDE1E5b"] = s.BGDE1E5b;
|
||||
ret["wn"] = s.wn;
|
||||
ret["tow"] = s.tow;
|
||||
ret["dtLS"] = s.dtLS;
|
||||
ret["dtLSF"] = s.dtLSF;
|
||||
ret["wnLSF"] = s.wnLSF;
|
||||
ret["dn"] = s.dn;
|
||||
ret["e5bdvs"]=s.e5bdvs;
|
||||
ret["e1bdvs"]=s.e1bdvs;
|
||||
ret["e5bhs"]=s.e5bhs;
|
||||
ret["e1bhs"]=s.e1bhs;
|
||||
|
||||
|
||||
if(svstats[id].completeIOD()) {
|
||||
const auto& iod = svstats[id].liveIOD();
|
||||
ret["iod"]= svstats[id].getIOD();
|
||||
ret["e"] = iod.getE();
|
||||
ret["omega"] = iod.getOmega();
|
||||
ret["sqrtA"]= iod.getSqrtA();
|
||||
ret["M0"] = iod.getM0();
|
||||
ret["i0"] = iod.getI0();
|
||||
ret["delta-n"] = iod.getDeltan();
|
||||
ret["omega-dot"] = iod.getOmegadot();
|
||||
ret["omega0"] = iod.getOmega0();
|
||||
ret["idot"] = iod.getIdot();
|
||||
ret["t0e"] = iod.getT0e();
|
||||
ret["t0c"] = iod.getT0c();
|
||||
ret["cuc"] = iod.getCuc();
|
||||
ret["cus"] = iod.getCus();
|
||||
ret["crc"] = iod.getCrc();
|
||||
ret["crs"] = iod.getCrs();
|
||||
ret["cic"] = iod.getCic();
|
||||
ret["cis"] = iod.getCis();
|
||||
ret["sisa"] = iod.sisa;
|
||||
ret["af0"] = iod.af0;
|
||||
ret["af1"] = iod.af1;
|
||||
ret["af2"] = iod.af2;
|
||||
Point p;
|
||||
getCoordinates(s.tow, iod, &p);
|
||||
ret["x"] = p.x;
|
||||
ret["y"] = p.y;
|
||||
ret["z"] = p.z;
|
||||
auto longlat = getLongLat(p.x, p.y, p.z);
|
||||
ret["longitude"] = 180.0*longlat.first/M_PI;
|
||||
ret["latitude"] = 180.0*longlat.second/M_PI;
|
||||
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
);
|
||||
|
||||
h2s.addHandler("/svs", [](auto handler, auto req) {
|
||||
h2s.addHandler("/svs.json", [](auto handler, auto req) {
|
||||
auto svstats = g_statskeeper.get();
|
||||
nlohmann::json ret = nlohmann::json::object();
|
||||
|
||||
|
@ -1202,7 +1350,7 @@ try
|
|||
|
||||
item["wn"] = s.second.wn;
|
||||
item["tow"] = s.second.tow;
|
||||
ret[fmt::sprintf("%c%02d@%d", getGNSSChar(s.first.gnss), s.first.sv, s.first.sigid)] = item;
|
||||
ret[makeSatIDName(s.first)] = item;
|
||||
}
|
||||
return ret;
|
||||
});
|
||||
|
@ -1438,6 +1586,13 @@ try
|
|||
|
||||
if(hours < 4) {
|
||||
idb.addValue(id, "eph-disco", disco);
|
||||
g_svstats[id].latestDisco= disco;
|
||||
g_svstats[id].latestDiscoAge= hours*3600;
|
||||
}
|
||||
else
|
||||
g_svstats[id].latestDisco= -1;
|
||||
|
||||
if(hours < 24) {
|
||||
idb.addValue(id, nanoTime(id.gnss, ent.second.wn, ent.second.tow), "eph-disco2",
|
||||
{{"meters", disco},
|
||||
{"seconds", hours*3600.0},
|
||||
|
@ -1445,11 +1600,7 @@ try
|
|||
{"x", p.x}, {"y", p.y}, {"z", p.z},
|
||||
{"oid", 1.0*ent.second.getIOD()},
|
||||
{"oldoid", 1.0*ent.second.prevIOD.first}});
|
||||
g_svstats[id].latestDisco= disco;
|
||||
g_svstats[id].latestDiscoAge= hours*3600;
|
||||
}
|
||||
else
|
||||
g_svstats[id].latestDisco= -1;
|
||||
|
||||
|
||||
|
||||
|
@ -1483,6 +1634,11 @@ try
|
|||
}
|
||||
else if(nmm.type() == NavMonMessage::RFDataType) {
|
||||
SatID id{nmm.rfd().gnssid(), nmm.rfd().gnsssv(), nmm.rfd().sigid()};
|
||||
|
||||
if(id.gnss==2 && id.sigid == 0) // old ubxtool output gets this wrong
|
||||
id.sigid = 1;
|
||||
|
||||
|
||||
idb.addValue(id, nanoTime(0, nmm.rfd().rcvwn(), nmm.rfd().rcvtow()), "rfdata",
|
||||
{{"carrierphase", nmm.rfd().carrierphase()},
|
||||
{"doppler", nmm.rfd().doppler()},
|
||||
|
@ -1527,7 +1683,7 @@ try
|
|||
|
||||
time_t t = utcFromGPS(nmm.rfd().rcvwn(), nmm.rfd().rcvtow());
|
||||
|
||||
if(t - g_svstats[id].perrecv[nmm.sourceid()].deltaHzTime > 10) {
|
||||
if(t - g_svstats[id].perrecv[nmm.sourceid()].deltaHzTime > 10) { // only replace after 10 seconds
|
||||
g_svstats[id].perrecv[nmm.sourceid()].deltaHz = nmm.rfd().doppler() - res.preddop;
|
||||
g_svstats[id].perrecv[nmm.sourceid()].deltaHzTime = t;
|
||||
idb.addValue(id, "delta_hz", nmm.rfd().doppler() - res.preddop);
|
||||
|
@ -1676,6 +1832,18 @@ try
|
|||
}
|
||||
else
|
||||
svstat.latestDisco = -1;
|
||||
|
||||
if(hours < 24) {
|
||||
idb.addValue(id, nanoTime(id.gnss, bm.wn, bm.sow), "eph-disco2",
|
||||
{{"meters", jump.length()},
|
||||
{"seconds", hours*3600.0},
|
||||
{"oldx", oldpoint.x}, {"oldy", oldpoint.y}, {"oldz", oldpoint.z},
|
||||
{"x", newpoint.x}, {"y", newpoint.y}, {"z", newpoint.z},
|
||||
{"oid", 0},
|
||||
{"oldoid", 0}});
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
62
ubxtool.cc
62
ubxtool.cc
|
@ -515,6 +515,10 @@ int main(int argc, char** argv)
|
|||
if(version9) {
|
||||
cerr<<"Enabling UBX-NAV-SIG"<<endl; // satellite reception details
|
||||
enableUBXMessageUSB(fd, 0x01, 0x43, 8);
|
||||
|
||||
cerr<<"Enabling UBX-RXM-MEASX"<<endl; // satellite reception details
|
||||
enableUBXMessageUSB(fd, 0x02, 0x14, 1);
|
||||
|
||||
}
|
||||
else {
|
||||
cerr<<"Enabling UBX-NAV-SAT"<<endl; // satellite reception details
|
||||
|
@ -936,8 +940,66 @@ int main(int argc, char** argv)
|
|||
|
||||
emitNMM(1, nmm);
|
||||
}
|
||||
}
|
||||
else if(msg.getClass() == 1 && msg.getType() == 0x30) { // UBX-NAV-SVINFO
|
||||
|
||||
}
|
||||
else if(msg.getClass() == 0x02 && msg.getType() == 0x14) { // UBX-RXM-MEASX
|
||||
cerr<<"Got RXM-MEASX for "<<(int)payload[34]<<" satellites, r0 "<< (int)payload[30]<<" r1 " <<(int)payload[31]<<endl;
|
||||
for(unsigned int n = 0 ; n < payload[34] ; ++n) {
|
||||
uint16_t wholeChips;
|
||||
uint16_t fracChips;
|
||||
uint8_t intCodePhase = payload[64+24*n];
|
||||
uint32_t codePhase;
|
||||
|
||||
memcpy(&wholeChips, &payload[56+24*n], 2);
|
||||
memcpy(&fracChips, &payload[58+24*n], 2);
|
||||
memcpy(&codePhase, &payload[60+24*n], 4);
|
||||
|
||||
cerr<<(int)payload[44+24*n]<<","<<(int)payload[45+24*n]<<" whole-chips "<<wholeChips<<" frac-chips "<<fracChips<<" int-code-phase " <<(int)intCodePhase <<" frac-code-phase "<<ldexp(codePhase, -21) << " mpath " << (int)payload[47+24*n] << " r1 " << (int)payload[66+24*n] << " r2 " <<(int)payload[67+24*n]<<endl;
|
||||
}
|
||||
}
|
||||
else if(msg.getClass() == 0x02 && msg.getType() == 0x59) { // UBX-RXM-RLM
|
||||
int type = (int)payload[1];
|
||||
int sv = (int)payload[2];
|
||||
|
||||
NavMonMessage nmm;
|
||||
nmm.set_sourceid(g_srcid);
|
||||
nmm.set_localutcseconds(g_gstutc.tv_sec);
|
||||
nmm.set_localutcnanoseconds(g_gstutc.tv_nsec);
|
||||
|
||||
nmm.set_type(NavMonMessage::SARResponseType);
|
||||
nmm.mutable_sr()->set_gnssid(2); // Galileo only for now
|
||||
nmm.mutable_sr()->set_gnsssv(sv);
|
||||
nmm.mutable_sr()->set_sigid(0); // we should fill this in later
|
||||
nmm.mutable_sr()->set_type(payload[1]);
|
||||
nmm.mutable_sr()->set_identifier(string((char*)payload.c_str()+4, 8));
|
||||
nmm.mutable_sr()->set_code(payload[12]);
|
||||
nmm.mutable_sr()->set_params(string((char*)payload.c_str()+13, payload.size()-14));
|
||||
|
||||
string hexstring;
|
||||
for(int n = 0; n < 15; ++n)
|
||||
hexstring+=fmt::sprintf("%x", (int)getbitu(payload.c_str(), 36 + 4*n, 4));
|
||||
cerr<<"SAR RLM type "<<type<<" from gal sv " << sv << " beacon "<<hexstring <<" code "<<(int)payload[12]<<" params "<<payload[12] + 256*payload[13]<<endl;
|
||||
|
||||
// wk.emitLine(sv, "SAR "+hexstring);
|
||||
// cout<<"SAR: sv = "<< (int)msg[2] <<" ";
|
||||
// for(int n=4; n < 12; ++n)
|
||||
// fmt::printf("%02x", (int)msg[n]);
|
||||
|
||||
// for(int n = 0; n < 15; ++n)
|
||||
// fmt::printf("%x", (int)getbitu(msg.c_str(), 36 + 4*n, 4));
|
||||
|
||||
// cout << " Type: "<< (int) msg[12] <<"\n";
|
||||
// cout<<"Parameter: (len = "<<msg.length()<<") ";
|
||||
// for(unsigned int n = 13; n < msg.length(); ++n)
|
||||
// fmt::printf("%02x ", (int)msg[n]);
|
||||
// cout<<"\n";
|
||||
|
||||
}
|
||||
|
||||
else
|
||||
cerr<<"Uknown UBX message of class "<<(int) msg.getClass() <<" and type "<< (int) msg.getType()<<endl;
|
||||
|
||||
// writen2(1, payload.d_raw.c_str(),msg.d_raw.size());
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue