Created
April 6, 2021 11:29
-
-
Save antipole2/d12d22176dca90f5e9d89b6b57fafaf5 to your computer and use it in GitHub Desktop.
Cause remove device to follow OpenCPN route navigation
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// This script sends any active route out as WPT and RTE sentences so that iNavX shows the up-to-date active route. | |
// If the route or its routepoints are updated, iNavX will update to reflect this | |
// V2.0 - major rewrite to utilise latest plugin capabilities - much simplified | |
Position = require("Position"); // load the required constructors | |
Route = require("Route"); | |
// here we define enduring variables we need outside the functions | |
var debug = false; // for debug prints | |
const prefix = "$JS"; // NMEA identifier | |
const repeatInterval = 20; // repeat after this number of seconds | |
var activeRoutepointName = ""; // to hold the active routepoint name, else "" | |
var activeRouteName = ""; // the name of the active route | |
var lastRoutePoint; // these two are needed to fix up RMB sentences and synthesise a BOD sentence… | |
var nextRoutePoint; // … which is needed so iNavX can work out which leg of the route we are on | |
var bearingToDest; // bearing to destination WP from where WP is activated | |
var fromHere; // position we are navigating from | |
var variation; // magnetic variation | |
var workingPosition = new Position(); // creates a working position object | |
var route = new Route(); // a working route object | |
OCPNonNMEAsentence(processNMEA); // start processing NMEA sentences | |
listenOut(); | |
consoleHide(); // start listening | |
function listenOut(){ | |
if (debug) print("Listening out\n"); | |
// this is where we start the action | |
APRgpx = OCPNgetARPgpx(); // get Active Route Point as GPX | |
if (debug) print(APRgpx, "\n"); | |
if (APRgpx.length > 0){ | |
// we have an Active Route Point. Need to extract the routepoint name and save for later | |
routepointPart = /<name>.*<\/name>/.exec(APRgpx); | |
routepointName = routepointPart[0].slice(6, -7); | |
if (routepointName != activeRoutepointName){ | |
// active routepoint has changed | |
bearingToDest = ""; // invalidate any previous info | |
lastRoutePoint = ""; nextRoutePoint = ""; | |
activeRoutepointName = routepointName; | |
// we need to remember our position for navigation from here to next routepoint | |
here = OCPNgetNavigation(); | |
fromHere = here.position; // saves the lat and long | |
variation = here.variation; //save magnetic variation | |
// now get the route leg | |
OCPNonMessageName(handleAR, "OCPN_ACTIVE_ROUTELEG_RESPONSE"); | |
OCPNsendMessage("OCPN_ACTIVE_ROUTELEG_REQUEST"); | |
} | |
else { // still on same leg - send same stuff | |
formSentences(); | |
} | |
} | |
else { | |
// print("No active route routepoint in GPX\n"); | |
activeRoutepointName = ""; | |
} | |
onSeconds(listenOut, repeatInterval); // Do it again | |
} | |
function handleAR(activeRouteJS){ | |
// we have received the active route, if there is one | |
activeRoute = JSON.parse(activeRouteJS); | |
if (debug) print("Active route:\n", activeRoute, "\n"); | |
// NB the JSON returned creates an array | |
if (!activeRoute[0].error ){ | |
// we have an active route | |
routeGUID = activeRoute[0].active_route_GUID; | |
route.get(routeGUID); | |
if (debug) print("Route is:\n", route, "\n"); | |
activeRouteName = route.Name; // attribute in here has capitalised name! | |
lastRoutePoint = ""; nextRoutePoint = ""; // clear out previous route info | |
formSentences(); | |
} | |
else throw("Active route point but active route returned had error"); | |
} | |
function formSentences(){ | |
// we work through the route points, sending out WPL sentences and noting which is the next and last | |
for (i in route.waypoints){ // push out the WPT sentences | |
workingPosition.latitude = route.waypoints[i].position.latitude; // convert from position as in JSOn to our way of doing it | |
workingPosition.longitude = route.waypoints[i].position.longitude; | |
sentence = prefix + "WPL" + "," + workingPosition.NMEA + "," + route.waypoints[i].markName; | |
if (debug) print(sentence, "\n"); | |
OCPNpushNMEA(sentence); | |
if (route.waypoints[i].markName == activeRoutepointName){ | |
activeWPL = sentence; // remember for later] | |
if (debug) print("Remembering:", activeWPL, "\n"); | |
if (i > 0) { | |
// not the first | |
lastRoutePoint = route.waypoints[i-1].markName; | |
nextRoutePoint = route.waypoints[i].markName; | |
} | |
else { | |
// Still to reach first point | |
lastRoutePoint = ""; // no last point | |
nextRoutePoint = route.waypoints[i].markName; | |
} | |
} | |
} | |
// next we build an array of lists of routepoints to go in each RTE sentence as space permits | |
available = 79 - 12 - route.name.length - 3; // space available in RTE for routepoint names | |
spaceLeft = available; | |
var wpLists = [""]; // create our array of routepoint groups to go in an RTE sentence | |
listIndex = 0; | |
for (i in route.waypoints){ | |
wpName = route.waypoints[i].markName; | |
wpNameLength = wpName.length; | |
if (spaceLeft >= wpNameLength){ | |
wpLists[listIndex] += (wpName + ","); | |
spaceLeft -= (wpNameLength+1); //allow for comma | |
continue; | |
} | |
else{ | |
// no more space in this one | |
wpLists[listIndex] = wpLists[listIndex].slice(0,-1); // drop trailing comma | |
wpLists.push(""); // new array member starts empty | |
listIndex += 1; spaceLeft = available; | |
i -= 1; // don't forget this last routepoint still to be fitted in next time | |
} | |
} | |
// we may have a trailing comma after last one | |
lastOne = wpLists[listIndex]; | |
lastChar = lastOne.charAt(lastOne.length - 1); | |
if (lastChar == ",") lastOne = lastOne.slice(0,-1); // drop it | |
wpLists[listIndex] = lastOne; | |
arrayCount = wpLists.length; | |
for (i in wpLists) { // send out the RTE sentences | |
sentence = prefix + "RTE," + arrayCount + "," + (i*1+1) + ",c," + route.name + "," + wpLists[i]; | |
if (debug) print(sentence, "\n"); | |
OCPNpushNMEA(sentence); | |
} | |
// Now to send a BOD sentence | |
if (bearingToDest != ""){ // can only do this if we have acquired a bearing - else wait until we have it | |
bearingToDest = bearingToDest*1; // very odd - have to force this to be number for next bit | |
bearingToDestM = bearingToDest + variation; | |
sentence = prefix + "BOD" + "," + bearingToDest.toFixed(2) + "," + "T" + "," + bearingToDestM.toFixed(2) + "," + "M" + "," + nextRoutePoint + "," + lastRoutePoint; | |
if (debug) print(sentence, "\n"); | |
OCPNpushNMEA(sentence); | |
if (activeWPL != "") OCPNpushNMEA(activeWPL); // repeat the active WPL fer th BOD, as per MacENC | |
} | |
} | |
function processNMEA(input){ // we need to un-abbreviate the routepoint name in APB sentences | |
if(input.OK && (activeRouteName != "")){ // only bother if have active routepoint | |
switch (input.value.slice(0,6)) { | |
case "$OCRMB": | |
{ | |
if (debug) print("Have RMB with nextRoutePoint:", nextRoutePoint, "\n"); | |
if (nextRoutePoint == "") break; // we cannot act until we have this | |
splut = input.value.split(",", 20); | |
shortWPname = splut[5]; | |
if (activeRoutepointName.startsWith(shortWPname)){ // we check this really is the right one | |
splut[0] = prefix + "RMB"; // give it our branding | |
splut[4] = lastRoutePoint; // and add the origin WP name | |
splut[5] = nextRoutePoint; // the full destination WP Name | |
bearingToDest = splut[11]; // remember the bearing | |
result = splut.join(","); // put it back together | |
OCPNpushNMEA(result); | |
} | |
break; | |
} | |
case "$OCAPB": | |
{ | |
// print("APB received\n"); | |
splut = input.value.split(",", 20); | |
splut[0] = prefix + "APB"; // give it our branding | |
splut[10] = nextRoutePoint; // the full destination WP Name | |
result = splut.join(","); // put it back together | |
OCPNpushNMEA(result); | |
break; | |
} | |
default: | |
break; | |
} | |
} | |
OCPNonNMEAsentence(processNMEA); // Listen out for another NMEA sentence | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment