night199uk - is there specific support for canb...

is there specific support for canboat anywhere? I'm working to add support to canboat, canboatjs, and eventually signalk-nmea2000 for the propetiary raymarine autopilot PGNs. 130918 and 130848. this should help signalk to control raymarine autopilot heads like the raymarine p70, I hope. raymarine PGNs seem to contain an string type that I cannot find support for in canboat today. it is a fixed maximum number of bytes (i.e. 16 bytes), but shorter string are allowed & NULL-terminated. in canboat pgn.h I see either STRING_FIXED (which reads and displays all 16 bytes, including the NULL and garbage after the NULL), or variable length types like STRINGLZ, which is a string with length encoded. is there a CANBOAT type for "NULL terminated string, with maximum length", that I'm not finding?
165 Replies
Tony
Tony9mo ago
Assuming you’re aware of the documentation. https://canboat.github.io/canboat/canboat.html this shows what’s been developed so far and which PGNs have already been reverse engineered
night199uk
night199ukOP9mo ago
@Tony yup; thanks - I do see that. i'm wondering which files need to be modified when adding support for these new PGNs? i guess a different question would be - what is the purpose of each of canboat.json, canboat.xml, canboat.html?
Tony
Tony9mo ago
If you start with the Readme on the GitHub repo it will walk you through everything including contributing https://github.com/canboat/canboat/wiki The readme takes you to the link I posted Specifically this page explains extending to more pgns https://github.com/canboat/canboat/wiki/Extending Regarding the definitions (q2) https://github.com/canboat/canboat/wiki/Using-the-definitions-in-other-software
Scott Bender
Scott Bender9mo ago
There is already support for the Raymarine autopilots
night199uk
night199ukOP9mo ago
There is support for the simple -1, +1 type autopilot. But not for Waypoint tracking.
Scott Bender
Scott Bender9mo ago
Yes. True.
night199uk
night199ukOP9mo ago
Not sure if the modern Raymarine EV-1s support the 129284 navigationData PGNs, but at least the older X30/P70 control units don't, and only use the 130848 and 130918 Raymarine custom PGNs for route and waypoint information.
Scott Bender
Scott Bender9mo ago
If you need help, best to open issues in the canboat git repository
night199uk
night199ukOP9mo ago
I think I got it all figured out. Seems the xml & json are auto-generated from pgn.h.
Scott Bender
Scott Bender9mo ago
Kees and I can help you there
Scott Bender
Scott Bender9mo ago
Yes
night199uk
night199ukOP9mo ago
And I raised an issue on canboatjs to update that project. I think that's the right way to get things done, let me know if not 🙂 once i can hook all this up, this should get full waypoint tracking autopilot working for raymarine.
Scott Bender
Scott Bender9mo ago
Yep. Once Kees merges that and does a canboat release. Then I can do a canboatjs release.
night199uk
night199ukOP9mo ago
my goal is to have e.g. aqua maps be able to full drive my raymarine autopilot via signalk.
Scott Bender
Scott Bender9mo ago
If you want to start testing things now, you can copy that generated canboat.json file into your @canboat/pgns module
night199uk
night199ukOP9mo ago
awesome! let me try that. that's the only change required in canboatjs?
Scott Bender
Scott Bender9mo ago
Yes
night199uk
night199ukOP9mo ago
perfect, thanks! i want to move to the signalk side now and have it start generating those PGNs so I can test fully is there a simple tool to generate NMEA-2K PGNs from the CLI? i looked at cansend, but that seems to be raw CAN frames and much more raw maybe i need to spend more time on cansend
Scott Bender
Scott Bender9mo ago
Easiest is through the data fiddler in the sk server You can enter the canboat json and send that out to the canbus
night199uk
night199ukOP9mo ago
oh, nice. is there an example of sending an nmea-2k frame with the data fiddler?
Scott Bender
Scott Bender9mo ago
It’s just the canboat json format
night199uk
night199ukOP9mo ago
oh wow, shit. that's awesome.
Scott Bender
Scott Bender9mo ago
Examples here
Scott Bender
Scott Bender9mo ago
GitHub
canboatjs/test/pgns at master · canboat/canboatjs
Native javascript NMEA 2000 decoder and encoder. Contribute to canboat/canboatjs development by creating an account on GitHub.
Scott Bender
Scott Bender9mo ago
The “expected” in those
night199uk
night199ukOP9mo ago
so first i'd have to add the support to canboat, canboatjs (copying the json file), then restart my sk server then i should be able to send raw json like this: {"timestamp":"2025-03-09-20:54:28.297","prio":7,"src":6,"dst":255,"pgn":130848,"description":"SeaTalk: Waypoint Information","fields":{"Manufacturer Code":"Raymarine","Industry Code":"Marine Industry","SID":191,"Waypoint Name":"Waypoint 134Qwer","Waypoint Sequence":"0001","Bearing to Waypoint, True":10.8,"Bearing to Waypoint, Magnetic":20.0,"Distance to Waypoint":1915725.00}} {"timestamp":"2025-03-09-20:54:28.303","prio":7,"src":6,"dst":255,"pgn":130918,"description":"SeaTalk: Route Information","fields":{"Manufacturer Code":"Raymarine","Industry Code":"Marine Industry","Current Waypoint Sequence":1,"Current Waypoint Name":"Waypoint 134Qwer","Next Waypoint Sequence":2,"Next Waypoint Name":"Waypoint 746;�","Distance to Waypoint":4912407.04,"Bearing to Waypoint, True":85.1,"Bearing to Next Waypoint, True":79.2}}
Scott Bender
Scott Bender9mo ago
Yes
night199uk
night199ukOP9mo ago
that's awesome. alright, let me go fiddle with that. thanks! sorry - i didn't see a response to my original question on this thread do you know if there is a "null terminated with maximum length" string type in canboat? i think there is not.
Scott Bender
Scott Bender9mo ago
I thought so Give me a few minutes, I can check…
night199uk
night199ukOP9mo ago
sure. these raymarine strings are always 16 bytes, but if the contents is < 16 bytes long, it is null terminated and the rest of the bytes filled with junk. e.g. in the json above you see: *Waypoint 746;� Waypoint 746 is 13 characters + 1 byte for NULL, the rest of the characters up to 16 bytes are filled with junk. using STRING_FIXED expects all 16 characters to be "relevant". sorry, hard to explain what I mean by this
Scott Bender
Scott Bender9mo ago
I think you are right there;s no type for that @Kees Verruijt ? easy enough to add, but should confirm with Kees, probably best to open an issue so we can track it
Kees Verruijt
Kees Verruijt9mo ago
I’ve just reread the description for STRING_FIXED and although I think Raymarine is being sloppy here I don’t think there is harm if we terminate on the first zero byte. Please open an issue!
night199uk
night199ukOP9mo ago
i can work on an implementation. it's preventing me moving further now as it's messing up the json parser due to binary in the stream. would you prefer to fix the current implementation of STRING_FIXED to terminate on \0, or add a new type, like, STRING_NULL(xxx, MAX_BYTES)? Error: Invalid JSON (Unexpected "\u0002" at position 336 in state STOP) etc
Scott Bender
Scott Bender9mo ago
Where is that invalid json coming from?
night199uk
night199ukOP9mo ago
candump can0 | candump2analyzer | analyzer -json | bin/n2k-signalk
Scott Bender
Scott Bender9mo ago
can you try with canboatjs?
night199uk
night199ukOP9mo ago
so i guess i could work around it, but still, it seems like being thorough i should fix this on the way through @Scott Bender what would be the comparaible to candump can0 | candump2analyzer | analyzer -json? i notice the output of canboatjs is marginally different is canboatjs can0 | bin/n2-signalk enough?
Scott Bender
Scott Bender9mo ago
candumpjs can0
night199uk
night199ukOP9mo ago
k, thx
Scott Bender
Scott Bender9mo ago
Obviously, canboat needs fixed. But just interested in how canboatjs is handling it…
night199uk
night199ukOP9mo ago
canboatjs works good oh wait canboatjs is quoting it {"canId":503277062,"prio":7,"src":6,"dst":255,"pgn":130918,"timestamp":"2025-03-10T01:08:29.801Z","input":["2025-03-10T01:08:29.796Z,7,130918,6,255,8,60,2f,3b,9f,01,00,57,61","2025-03-10T01:08:29.797Z,7,130918,6,255,8,61,79,70,6f,69,6e,74,20","2025-03-10T01:08:29.797Z,7,130918,6,255,8,62,31,33,34,51,77,65,72","2025-03-10T01:08:29.798Z,7,130918,6,255,8,63,02,00,57,61,79,70,6f","2025-03-10T01:08:29.799Z,7,130918,6,255,8,64,69,6e,74,20,37,34,36","2025-03-10T01:08:29.800Z,7,130918,6,255,8,65,00,3b,a7,02,00,bf,47","2025-03-10T01:08:29.801Z,7,130918,6,255,8,66,1d,00,3a,07,36,d3,ff"],"fields":{"Manufacturer Code":"Raymarine","Industry Code":"Marine Industry","Current Waypoint Sequence":1,"Current Waypoint Name":"Waypoint 134Qwer","Next Waypoint Sequence":2,"Next Waypoint Name":"Waypoint 746\u0000;'\u0002","Distance to Waypoint":4912412.16,"Bearing to Waypoint, True":1.4848,"Bearing to Next Waypoint, True":1.3831},"description":"SeaTalk: Route Information"} note: "Waypoint 746\u0000;'\u0002"
Scott Bender
Scott Bender9mo ago
Ok. Not surprised.
night199uk
night199ukOP9mo ago
so waypoint 746 is a 12-byte null-terminated string in a fixed 16-byte field
Scott Bender
Scott Bender9mo ago
At least it’s valid json 🤣
night199uk
night199ukOP9mo ago
yeah there are some other things i see in this raymarine data that is just yucky. when there is no waypoint name, they just pad the whole 16-byte field with 0xff 🤦‍♂️
Scott Bender
Scott Bender9mo ago
How does canboatjs handle that? (And trust me, I’ve done a lot of reverse engineering of Raymarine stuff, always fun!)
night199uk
night199ukOP9mo ago
will test shortly and confirm this is my first can/n2k/nmea decoding rodeo but not my first reverse engineering obviously, so yeah, always fun
Scott Bender
Scott Bender9mo ago
I have an EV-1, so this never came up for me.
night199uk
night199ukOP9mo ago
does the ev-1 honour the standard 129284 PGNs?
Scott Bender
Scott Bender9mo ago
I think so, but I’m not sure.
night199uk
night199ukOP9mo ago
that has a p70s control head?
Scott Bender
Scott Bender9mo ago
Yes
night199uk
night199ukOP9mo ago
i'm not convinced the p70s honours them
Scott Bender
Scott Bender9mo ago
The p70 has nothing to do with it
night199uk
night199ukOP9mo ago
can you use "track" mode to track a route on your p70s with routes provided by e.g. signalk?
Scott Bender
Scott Bender9mo ago
P70 is just the control head You don’t even need that I have not tried to provide routes from signalk. Cause I use an Axiom for that.
night199uk
night199ukOP9mo ago
ahhh, there 🙂 yeah, my axiom upgrade is in the post i bought the boat a year ago and i'm just finishing my first season in the bahamas and heading back to the US, and have a big pile of upgrades sat waiting for me. but still, i'd prefer to be able to send routes from aqua maps these days than rely on the mfds. this boat currently has 2x e126 MFDs that are TERRIBLE and slow. so i've become accustomed to navionics and aqua maps and i'd just rather be able to drive the whole thing from aqua maps than rely on the MFDs. just far more intuitive these days to sit in bed and program a route on aqua maps on the ipad and then get up the next day and sail it.
Scott Bender
Scott Bender9mo ago
I’ve been very happy with Navionics+Axiom. But it will be very cool to get this working.
night199uk
night199ukOP9mo ago
yeah, i think it's easier to move GPX based routes from navionics to axiom? getting a route from navionics to my e126 is terrible
Scott Bender
Scott Bender9mo ago
It’s pretty easy
night199uk
night199ukOP9mo ago
anyway, never let a good problem go unsolved. might as well fix this while i'm here. 🙂 this should work for your axiom as well
Scott Bender
Scott Bender9mo ago
Agreed. I can try to get it working with with the EV-1 too. For fun.
night199uk
night199ukOP9mo ago
so now i'm going to try and get signalk->nmea2000 generating these pgns
Scott Bender
Scott Bender9mo ago
I can work on making canboatjs handle these strings tomorrow… An example of the empty, 0xff one would help.
night199uk
night199ukOP9mo ago
how do you want it? what format? don't suppose you use 010 editor?
Scott Bender
Scott Bender9mo ago
No The output you pasted about will work. It has the “input” data in it
night199uk
night199ukOP9mo ago
okay, will have to regenerate it, means faffing with my e126 for ages i have a binary stream of about 20 different PGNs i'm working on would be easy just to send you that
Scott Bender
Scott Bender9mo ago
That’s fine
night199uk
night199ukOP9mo ago
got an email address?
Scott Bender
Scott Bender9mo ago
scott@scottbender.net
night199uk
night199ukOP9mo ago
sent
Scott Bender
Scott Bender9mo ago
Oh. I thought it was going to be candump… Definitely easier for me if in a format canboat understands
night199uk
night199ukOP9mo ago
ahhh yeah no worries. i'll have to recollect all the data. spent all day collecting data and generating test cases from my e126. was slow going to build all these samples. will have to rebuild it in candump format tomorrow if you need it that way. can send it to you tomorrow.
Scott Bender
Scott Bender9mo ago
I have enough from above to work on the 0 terminated string. And I can hack together the other one. I’ll let you know if I need more.
night199uk
night199ukOP9mo ago
yeah, i mean it's pretty simple. there are three cases: 1) 16 byte string in a 16 byte field -> all valid, no null terminator: Waypoint 134Qwer -> 57 61 79 70 6F 69 6E 74 20 31 33 34 51 77 65 72 2) 12 (or shorter) byte string in a 16 byte field -> only 12 valid bytes, null terminator and uninitialized junk after the null: Waypoint 166 -> 57 61 79 70 6F 69 6E 74 20 31 36 36 00 30 D7 3F (30 d7 3f are junk) 3) no valid waypoint, string field padded with nothing (0xff) -> FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
Scott Bender
Scott Bender9mo ago
GitHub
fix: issues with STRING_FIX field type decoding by sbender9 · Pull ...
Handle 0 terminated strings (fixes issues with some proprietary Raymarine pgns) Code to find end of strings did not work properly with some data
night199uk
night199ukOP9mo ago
nice. question, does string_fix also now append the zero byte when creating strings? i'm just working on the signalk-to-nmea2000 plugin code to generate PGNs 130848 and 130918 having problems right now but will figure that out
Scott Bender
Scott Bender9mo ago
No. It does is according to the n2k standard. It fills with 0xff
night199uk
night199ukOP9mo ago
interesting. let me test this and see how the raymarine units deal with it. it seems like the RM stuff is in breach of the spec from the sounds. I don't have the NMEA2K spec
Scott Bender
Scott Bender9mo ago
We’re going to have to figure out a way to zero terminate these specific ones. Definitely don’t want to change it to do that by default.
night199uk
night199ukOP9mo ago
yeah. perhaps what we need is STRING_FIX_RAYMARINE or some such to keep STRING_FIX N2K spec compliant otherwise you'll find some issue with N2K compliant units elsewhere
Scott Bender
Scott Bender9mo ago
Yep
night199uk
night199ukOP9mo ago
question: is any modification needed to canboatjs to generate my new 130848 PGNs with toPgn? i've added code to signalk-to-nmea2000 to generate these new PGNs, but my new PGNs are always coming back empty Raymarine Waypoint Information (130848) test # 0/0 works: AssertionError: expected { Object (prio, pgn, ...) } to have the same json representation as { Object (prio, pgn, ...) } + expected - actual { "dst": 255 - "fields": {} + "fields": { + "SID": 136 + } "pgn": 130848 "prio": 2 }
Scott Bender
Scott Bender9mo ago
You updated canboat.json?
night199uk
night199ukOP9mo ago
yup, updated canboat.json
Scott Bender
Scott Bender9mo ago
so you updated it in node_modules/@canboat/pgns/ inside your signalk-to-nmea2000 ?
night199uk
night199ukOP9mo ago
yup hrm, okay, i found something broken. sec.
Scott Bender
Scott Bender9mo ago
and you shouold probably test these strings the way they will be encoded now. It's possible the Raymarine stuff will hande it if it's not zero terminated.
night199uk
night199ukOP9mo ago
yeah, i will. hrm. i just cannot get signalk-to-nmea2000 to generate these PGNs properly. fixed a few issues i could find. - "fields": {} The PGNs I get back during npm test are just empty of fields.
Scott Bender
Scott Bender9mo ago
can you email the canboat.json and the signalk-to-nmea2000 changes?
night199uk
night199ukOP9mo ago
yeah, just debugging it. let me look first before wasting your time. looks like toPgn is working good actually. whoop, got it working. briefly saw an autopilot track on my e126 head unit 🙂 yay! just hit "track" on my autopilot and it now prompts me to follow a track / route sent from signalk to the raymarine. 😄 my e126 MFDs also show me as tracking a route 😄 will be pretty cool. my test case is sending route information from aqua maps to signalk via it's TCP NMEA0183 interface with the autopilot beta control turned on. then signalk forwards that to NMEA. can control my whole route from aqua maps. rather, can program a route in aqua maps and then just tell the boat autopilot to track it. no need to turn my raymarine MFDs on any more 😄 where does the course-provider in signalk get its data? i see my aqua maps tcp-client populating, e.g. navigation.courseRhumbline.nextPoint.position. then i see courseApi populating navigation.courseGreatCircle.; with almost the same data as courseRhumbLine. then i see the course-provider plugin populating navigation.course.calcValues.
Scott Bender
Scott Bender9mo ago
I’m not familiar with that stuff. Going to need @AdrianP for that.
night199uk
night199ukOP9mo ago
thanks. i see the conversions for 129284 use data from courseRhumbLine and courseGreatCircle as appropriate. but I'm not sure what are the correct course data values to send in 130848 and 130918. i don't know if those raymarine packets want great circle or rhumb line data, essentially. and can i assume that if aqua maps is populating courseRhumbLine, the courseApi will correctly populate courseGreatCircle automatically from that data? currently i have this conversion using the data in navigation.course.calcValues.* and what i see on my plotter looks broadly correct.
AdrianP
AdrianP9mo ago
See https://demo.signalk.org/documentation/develop/rest-api/course_calculations.html The course API sets values under the path vessels/self/navigation/course and the calculations are made from these values. Course-provider emits deltas for both the version 1 paths courseRhumbline, etc as well as the calcValues paths See also https://demo.signalk.org/documentation/develop/rest-api/course_api.html
night199uk
night199ukOP9mo ago
thanks Adrian. I read both of those. I think my confusion perhaps is that when I look at the signalk-to-nmea plugin and the 129284 PGN, that is using the values from e.g. navigation.courseRhumbline.bearingToDestinationTrue & navigation.courseGreatCircle.bearingToDestinationTrue Then there are also updated variables in: navigation.course.calcValues.bearingMagnetic navigation.course.calcValues.bearingTrue So I think my confusion is around which is the "right" place those PGNs should be sourcing the true and magnetic path to the destination from. i'm approaching this from zero and I'm not an expert in great circle vs rhumbline or course APIs in general, so I'm probably missing a bunch of context and history i guess the key question for me is: which variables should PGNs 130848 and 130918 (Raymarine Waypoint Information & Raymarine Route Information) use to populate the magnetic and true bearings? If I use the code in 129284 as an example, it should either be: navigation.courseGreatCircle.bearingToDestinationMagnetic navigation.courseGreatCircle.bearingToDestinationTrue or: navigation.courseRhumbLine.bearingToDestinationMagnetic navigation.courseRhumbLine.bearingToDestinationTrue But I do not know if the raymarine expects RhumbLine or GreatCircle in those PGNs and have no knowledge of the internals of the Raymarine so don't know how I could figure out the answer to that.
AdrianP
AdrianP9mo ago
The course API does listen for courseRhumbline.nextPoint.position and courseGreatCircle.nextPoint.position deltas and will treat this in the same way as an API request to set the destination and populate all the associated paths accordingly. The approach of the course API is to manage all the associated Signal K paths, to basically tell me where you want to go and it will facilitate all the relevant calculations. Clients then consume this information via signal K deltas or NMEA via the sk to NMEA plugins
night199uk
night199ukOP9mo ago
sure. i guess that doesn't help me (sorry) i'm sort of confused about the different between rhumb line and great circle. i understand the basic principle i guess; but i don't understand practically how to apply it. say today, aqua maps is sending a route to singalk using RMB; which ends up with the courseApi populating a RhumbLine route:
night199uk
night199ukOP9mo ago
No description
night199uk
night199ukOP9mo ago
does that mean what should be sent out in 130848 is the bearingToDestinationMagnetic and bearingToDestinationTrue from the Rhumbline route? and now i have Course Data Provider set to "Great Circle" and it is similarly making separate calculations. Is it calculating a Great Circle route to the same lng, lat in parallel to the Rhumbline route?
AdrianP
AdrianP9mo ago
So as it stands the RMB sentence should be translated to courseRhumbline.nextPoint.position by the nmea0183-to-signalk plugin. The course API will see this and should set the destination from this.
night199uk
night199ukOP9mo ago
I see I think I got it. so assuming we have position (lat, lng) we can calculate either a great circle or a rhumb line route to that destination lat/lng? (or calculate both)
AdrianP
AdrianP9mo ago
The course provider plugins will calculate one or the other based on the config
night199uk
night199ukOP9mo ago
but then it's entirely user preference which set of bearings (rhumb line or great circle) we send to the autopilot i.e depending on which one of the two routes they want to follow okay, i think i understand what's going on now. In the code for 129284, because there are two paths - GreatCircle and RhumbLine, depending on which nodes are populated in signalk only one 129284 will be sent. either great circle or rhumb line. so in my case if Aqua Maps is sending a Rhumb Line route and populating those paths, the code that sends the 129284 will pick up the populated rhumb line paths and send those in the 129284 packet.
Kees Verruijt
Kees Verruijt9mo ago
If you've got some example raw data I'm happy to create my own issue and fix it.
Scott Bender
Scott Bender9mo ago
@night199uk I released a new canboatjs with the string fix
Kees Verruijt
Kees Verruijt9mo ago
And I merged the string fix as well in canboat. No release as of yet but you can just use head.
night199uk
night199ukOP9mo ago
https://github.com/SignalK/signalk-to-nmea2000/pull/117 Combined with the canboat PR that already got merged, this should get Raymarine autopilots (like P70/X30, and EV1/ACU-400) to enable "track" mode to track a route sourced by SIgnalK. example PGNs: { "timestamp": "2025-03-12-01:27:50.397", "prio": 3, "src": 100, "dst": 255, "pgn": 130848, "description": "SeaTalk: Waypoint Information", "fields": { "Manufacturer Code": "Raymarine", "Industry Code": "Marine Industry", "SID": 136, "Waypoint Name": "Waypoint 1", "Waypoint Sequence": "0001", "Bearing to Waypoint, True": 221.2, "Bearing to Waypoint, Magnetic": 212.0, "Distance to Waypoint": 1243.28 } } { "timestamp": "2025-03-12-01:27:50.402", "prio": 3, "src": 100, "dst": 255, "pgn": 130918, "description": "SeaTalk: Route Information", "fields": { "Manufacturer Code": "Raymarine", "Industry Code": "Marine Industry", "Current Waypoint Sequence": 1, "Current Waypoint Name": "Waypoint 1", "Next Waypoint Sequence": 255, "Distance to Waypoint": 1243.28, "Bearing to Waypoint, True": 221.2 } } I'm moving the boat on a long route tomorrow and will try it out on a route sourced from Aqua Maps. at least right now it's doing the right things sat here on anchor. hrm. the raymarine plugin works okay (except some string handling things, which I need to pull in @Scott Bender 's PR to look at). my raymarine head can now "track" directly to waypoints provided by signalk. but i'm interested to understand the intricacies / thinking behind the different course data. with the current version of the PR i'm using data provided by this plugin: https://github.com/SignalK/course-provider-plugin?tab=readme-ov-file#course-provider-plugin specifically bearingTrue and bearingMagnetic. however this seems to be sometimes significantly off from the data in navigation.course.Rhumbline.*. so i guess i'm trying to understand the discrepency to make sure i'm using right navigation data in the PGNs. i think what i'm seeing is that the data in the course provider always wants to keep you on the track line, i.e. the perfect line from a->b first. i thought that's what: navigation.course.calcValues.bearingTrackMagnetic & navigation.course.calcValues.bearingTrackTrue should provide, but even bearingTrue and bearingMagnetic seem to show the same behaviour. e.g. i'm on the water right now and navigation.course.calcValues.bearingMagnetic is almost 20degrees less than navigation.courseRhumbline.bearingToDestinationMagnetic. for a waypoint just 2-3nm away i wouldn't expect this discrepency.
AdrianP
AdrianP9mo ago
The course provider uses the values in course.nextPoint.position and course.previousPoint.position which are populated by the course API. As per the spec .... bearingTrackTrue is calculated using previousPoint and nextPoint bearingTrue is calculated using the vesselPosition and nextPoint Can you confirm these paths have the expected values as they AFAIK only populated when the course API methods are used. NMEA to Signalk plugins do not populate these paths, they populate courseRhumbline.nextPoint.position.
night199uk
night199ukOP9mo ago
weird. those paths are getting populated. so I think the issues I was seeing are due to xte. It seems like by default, when you're offline the course line from a->b, the raymarine autopilot uses XTE first to track quickly back onto the a->b course line, before turning forward towards b. i'm new to mfd routing and autopilots in general, so i didn't really know about xte. but given the xte behavior this is working as expected. i saw one other instance where the autopilot didn't do what i expected, but i didn't dig into that one too much. otherwise i used this plugin for an 8 hour route today. the only major down side right now is that because RMB is "waypoint by waypoint" the raymarine turns the autopilot off at the end of each waypoint as that is also the end of the route. right now aqua maps doesn't support programming the whole forward route I guess. so i'm going to do some more work: i'm going to write a signalk plugin to import routes directly from your public folder in aqua map via gpx to the route api. then i need to do some changes here to expose the future waypoints to the raymarine. tl;dr, i need to get some routes into signalk so that I can make this pgn support full routes, not just single waypoints. i also emailed aqua maps to see if they would consider programming full routes into signalk via the routes API. that would obviate the need for a signalk plugin to retrieve routes. i'm halfway done on the plugin to retrieve gpx files from aqua maps. i have it working in python already. just need to convert it to JS.
AdrianP
AdrianP9mo ago
It may not help but I'll mention it anyway, the course API allows a route to be "activated" if the route is available via /signalk/v2/api/resources/routes
night199uk
night199ukOP9mo ago
yup. saw that. hey all. adding support for the raymarine PGNs worked great and I can track waypoints originated via RMB from Aqua Maps. it's sort of clunky due to the limitations of the NMEA-0183 PGNs, but it works. I now created a plugin to import routes from aqua maps so they can be run by the course API which will help to remove some of the clunkiness of the above approach. but i'm running into an issue. here's the problem: the PGN129284 is never sent for courses being run by the course API. looking here: https://github.com/SignalK/signalk-to-nmea2000/pull/63 it seems like there is a course API v1 and a course API v2? when i follow a course sent in via an external device (via e.g. RMB over NMEA0183); i see navigation.courseRhumbLine.* updated by the external device PGNs. currently 129284 tracks only those paths. when I activate a route in the course API using e.g. freeboard-sk, and follow it, I notice that we only update the course API paths: course.navigation.* PGN 129284 is never sent which external autopilots like my Raymarine require. i'd like to try and fix this, by having 129284 generated for navigation.course.* paths, essentially completing PR#63 above, but wanted some input on the right approach to do that? @AdrianP i think the above is your PR so maybe you have most input 🙂
AdrianP
AdrianP9mo ago
The signalk-to-n2k plugin is responsible for emitting the PGNs, so as long as the Signalk paths are populated and a map exists for the PGN it should be all good. The course provider plugins populates the V1 paths so that part should be ok. I'll have a look when I get a chance
night199uk
night199ukOP9mo ago
yeah, i spent the day working on this. i came up with a newer version of https://github.com/SignalK/signalk-to-nmea2000/pull/63 that pulls data from the course-data-provider instead of the old v1 paths. what i'm trying to understand is the heritage i guess and how much needs to be preserved i.e. why did https://github.com/SignalK/signalk-to-nmea2000/pull/63 never land? i have it working great here, with 129284 & 130848 & 130918 migrated to the course-data-provider paths. but the question is what should happen to the old navigation.course.Rhumbline & navigation.course.GreatCircle paths?
AdrianP
AdrianP9mo ago
They are considered deprecated from a version 2 perspective, and will remain for the momernt for backwards compatibility.
night199uk
night199ukOP9mo ago
so if I raise a PR that moves 129284 to just read from the newer course-data-provider paths, that would make sense?
AdrianP
AdrianP9mo ago
I think that should be fine.
night199uk
night199ukOP9mo ago
thanks. in that case, since i'm here should i look at the incoming NMEA0183 PGNs as well? RMB, XTE, etc. otherwise this becomes a breaking change, potentially. if NMEA0183 -> RMB writes to navigation.course.Rhumbline, but 129284 is not reading from that then i guess stuff will break. i'm new to signalk and don't know a lot of history here, so i don't know where the bodies are buried sort of thing..
Scott Bender
Scott Bender9mo ago
there are no bodies here. just love.
night199uk
night199ukOP9mo ago
what would y'all think of a PR to expose the full details of the active route in navigation.course.ActiveRoute? he's the problem: for Raymarine PGN130918; they want to know the name and bearing not just to nextPoint, but to subsequentPoint (nextPoint+1). this is to know that when we reach the next waypoint (nextPoint) whether we are at the end of the route or not; and how to draw the forward path. as i understand it right now, i have two routes for how to do it: - read the route from the url in href - add the full route to activeRoute since PGN130918 are sent regularly (same as 129284). can be as often as 500ms) querying the route via href just to get details about subsequentPoint would be quite expensive to do at that cadence. so my thinking is to show the whole active route into course.Navigation.activeRoute? (going to start floating some PRs for all this in the next day or two)
AdrianP
AdrianP9mo ago
A reference would be the preferred approach as it insulates against ensuring it is being updated when the route is modified. Also as nextPoint (and nextPoint + 1) values only change as you anvigate through the route so not sure why regular calls would be required to the route href.... only need to call when a change in nextPoint value is detected.
night199uk
night199ukOP9mo ago
@AdrianP when you say a reference - you mean storing the href? "why regular calls would be required to the route href.... only need to call when a change in nextPoint value is detected" how would the conversion code cache the subsequentPoint to send the 130918 PGN? each time the PGN is generated we need to include data about subsequentPoint, so as I understand it we either need to get the data via an expensive http request or cache it somehow? maybe there is a way to cache "subsequentPoint" in conversions.js? not sure or rather cache the whole route? i guess we can cache the "activeRoute" via the href and only update it when activeRoute changes?
Scott Bender
Scott Bender9mo ago
You can get any data from signalk via app.getSelfPath. No need for http call.
night199uk
night199ukOP9mo ago
ooh. got an example? let me grep
Scott Bender
Scott Bender9mo ago
Yeah, check the other conversations
night199uk
night199ukOP9mo ago
oh wait. app.getSelfPath is just for "data" though? can i get a route object this way? e.g. i see: server.getSelfPath('navigation.position');
Scott Bender
Scott Bender9mo ago
I think so? That’s in the full tree, right?
night199uk
night199ukOP9mo ago
i don't think it is is it? that's the reason for my question actually 🙂 unless i'm misunderstanding
Scott Bender
Scott Bender9mo ago
Ahh. Getting into stuff I am not familiar with… Let’s see what @AdrianP says…
night199uk
night199ukOP9mo ago
like this
No description
night199uk
night199ukOP9mo ago
so i can get navigation.course.activeRoute via getSelfPath. but then I think i still need to do an http call to resolve the href to the actual route data? i think that's why i was asking if activeRoute should contain the "full" route object of the current route, so we can query it quickly via app.getSelfPath, instead of making the fetch call to the href. if there is a way to do app.getSelfPath to resolve get the full route object via getSelfPath from the href though, that would work too... for 130918 i need to get "subsequentPoint" lat & lng and calculate the "next" angle between nextPoint and subsequentPoint so the raymarine knows where to turn after the completion of the current waypoint. without a subsequentPoint in 130918, the raymarine thinks the route has ended when the current waypoint is reached and turns off tracking. "subsequentPoint" as i call it seems to be the way the raymarine knows the route is not finished and continues after "nextPoint" is reached.
AdrianP
AdrianP9mo ago
Server plugin API exposes resource API methods to access and write resource entries without the need for http request. https://demo.signalk.org/documentation/develop/plugins/server_plugin_api.html#resources-api-interface
night199uk
night199ukOP9mo ago
fyi https://github.com/SignalK/signalk-to-nmea2000/pull/118 @AdrianP I think this should be a newer and slightly more extensive version of PR#63: https://github.com/SignalK/signalk-to-nmea2000/pull/63 @Scott Bender just testing with the fix for #489, seems broken. working on it here. with that fix it breaks output to jq 😦 jq: parse error: Invalid string: control characters from U+0000 through U+001F must be escaped at line 34, column 336 samples of the offending packets: 2025-03-18-14:54:19.336,7,130918,6,255,8,00,2f,3b,9f,01,00,57,61 2025-03-18-14:54:19.337,7,130918,6,255,8,01,79,70,6f,69,6e,74,20 2025-03-18-14:54:19.338,7,130918,6,255,8,02,31,33,34,51,77,65,72 2025-03-18-14:54:19.339,7,130918,6,255,8,03,02,00,57,61,79,70,6f 2025-03-18-14:54:19.340,7,130918,6,255,8,04,69,6e,74,20,37,34,36 2025-03-18-14:54:19.341,7,130918,6,255,8,05,00,0b,95,be,00,e2,3a 2025-03-18-14:54:19.342,7,130918,6,255,8,06,1c,00,8b,09,36,d3,ff 2025-03-18-14:54:20.344,7,130918,6,255,8,20,2f,3b,9f,01,00,57,61 2025-03-18-14:54:20.344,7,130918,6,255,8,21,79,70,6f,69,6e,74,20 2025-03-18-14:54:20.345,7,130918,6,255,8,22,31,33,34,51,77,65,72 2025-03-18-14:54:20.346,7,130918,6,255,8,23,02,00,57,61,79,70,6f 2025-03-18-14:54:20.347,7,130918,6,255,8,24,69,6e,74,20,37,34,36 2025-03-18-14:54:20.348,7,130918,6,255,8,25,00,0b,95,be,00,e2,3a 2025-03-18-14:54:20.348,7,130918,6,255,8,26,1c,00,8b,09,36,d3,ff
Scott Bender
Scott Bender9mo ago
What’s jq?
night199uk
night199ukOP9mo ago
the json processing tool e.g. candump can0 | candump2analyzer | analyzer -json | jq 'select(.pgn == 130918)' kind of like xslt or something for json. super handy. candump can0 | candump2analyzer | analyzer -json | jq 'select(.src == 6 and .pgn == 130918)' etc but it's complaining of invalid json in the stream with the fix for #498 basically. looking now, have to go out in a bit tho.
Scott Bender
Scott Bender9mo ago
going to have to work with @Kees Verruijt in that does it work with the latest canboatjs?
night199uk
night199ukOP9mo ago
i'm wondering if I need to create a new STRING_FIXED_RM for Raymarine, as we'll also need to be able to encode Raymarine compatible strings.
Scott Bender
Scott Bender9mo ago
The default encoding might work, have you tried it?
night199uk
night199ukOP9mo ago
i notice a bunch of things on the RAymarine are expecting null terminated strings in NMEA packets. I was looking at AIS data the other day and the Raymarine is reading junk from the end of the strings because they're not null terminated.
Scott Bender
Scott Bender9mo ago
That’s very strange, can’t image they would required their messed up encoding for AIS pgns
night199uk
night199ukOP9mo ago
yeah, i tried it. the raymarine reads junk for the 0xffs. raymarine even seem to be parsing some of the standard NMEA-2K PGNs incorrectly in this regard and are expecting null terminated strings. yeah. i'll find some examples. i just updated my e126 to lighthouse v19 from v11 (yeah, old) to see if they'd fixed any of the bugs. need to play a little more.
Scott Bender
Scott Bender9mo ago
I have AIS from a different vendor and the Raymarine stuff reads it fine
night199uk
night199ukOP9mo ago
yeah. it's not all fields that are affected. i noticed it in some random fields. duh. my bad https://github.com/canboat/canboat/pull/491 @Kees Verruijt fyi, https://github.com/SignalK/signalk-to-nmea2000/pull/117 and https://github.com/SignalK/signalk-to-nmea2000/pull/118 should be ready to go. I will start to look at support for PGN129285 for more route information shortly. @Scott Bender @Kees Verruijt example of Raymarine displaying garbage when strings aren’t null terminated in regular non proprietary PGNs. Will do a little more debug on this.
night199uk
night199ukOP9mo ago
No description
night199uk
night199ukOP9mo ago
This is an E126 running lighthouse v19 which is the latest from 2017. So already 7 years old, hardly up to date. Maybe a big don’t care 🙂
Scott Bender
Scott Bender9mo ago
Ok. I’ll take a look tomorrow. And I can test with an Axiom with the latest software.
night199uk
night199ukOP9mo ago
Yeah. V19 is the latest you get for E126. I’m replacing them soon with Axiom anyway. I’m just a stickler for bugs. 😂 I will dig more too. I have to figure out why my SignalK is looping back class A PGNs received over N2K too. I don’t have other sources of vessels right now.
Scott Bender
Scott Bender9mo ago
Not sure what you mean “looping back”
night199uk
night199ukOP9mo ago
Yeah ignore me. Maybe these were received over NMEA0183 and sent out N2K hrm, i'm stuck i need to call app.resourcesApi.getResource('routes', routeId) in my sk->nmea-2k converter (signalk-to-nmea2000). however, because getResource returns a promise, it's async and i cannot for the life of me figure out how to do this. i tried to "await" the value but that requires making the callback itself async/a promise; which breaks the n2k converter around toPgn, as it doesn't expect a promise. to be able to truely convert route data into PGNs, we need to be able to get the current route in the N2K converter and I cannot figure out how to do that synchronously. any ideas?
Scott Bender
Scott Bender9mo ago
Probably need to make a change to sk-to-n2k internals so the converter calls can be async. (If it’s not there already). I’ll look into it…
night199uk
night199ukOP9mo ago
yeah. i took a look but my JS is not up to scratch enough to know where to start with it.
AdrianP
AdrianP9mo ago
This use case triggers the question of whether there needs to be the capability to "route" decoded NMEA data to either the data model or an API. Alarm PGNs are a good example if we are to implement an Alarm Manager on the Server. The messages should be directed to the Alarm API which then emits the appropriate signalk deltas to allow for silencing, acknowledgement, etc. Autopilot API would also benefit from this as would the Course API based on the current use case.
night199uk
night199ukOP9mo ago
yeah, i was thinking about this the other day. there are multiple use cases for signalk. as a simple proxy from nmea0183, as a full fledged mfd, and sometimes half way in between. i have been juggling that in some of the things i'm looking at. aqua maps sends nmea0183 commands to program routes, which are incomplete. those in turn program the course api. so you end up with two possible courses - the one from aqua maps or the one from the course api. it depends if "aqua maps" is your primary "driver" and you want to trust it for everything, or just have aqua maps program the course and have signalk be the brains and do the routing. there are places i'm finding right now where it's not clear which paradigm you want
AdrianP
AdrianP9mo ago
With a routing system in place it can become as simple as a configuration setting..... @Teppo Kurki any thoughts on this?
night199uk
night199ukOP9mo ago
why would activeRoute = app.getSelfPath('navigation.course.activeRoute') return undefined despite there being valid data in that delta? does getSelfPath consider a timeout/age of the data and ignore data over a certain age? hrm. when I query getSelfPath("navigation") and dump all the data I get back, course.activeRoute is missing. only calcValues exists under course. But when I look at the web UI data browser, I see navigation.course.activeRoute clearly there. why do I see different results in getSelfPath vs the web UI data browser? @Scott Bender fyi, i updated the raymarine autopilot support and added support for promises returned from converters as a separate commit in there: https://github.com/SignalK/signalk-to-nmea2000/pull/117 we could break that out into a separate feature/PR if it's preferable. not sure how y'all roll.
Scott Bender
Scott Bender9mo ago
yes, please break into separate PRs
night199uk
night199ukOP9mo ago
cool, will do it tomorrow. i'm no javascript guru so let me know any comments on the implementation. it's working well here.
AdrianP
AdrianP9mo ago
FYI v2 delta messages are not written to the data model, so will not be available via getSelfPath, etc. You need to fetch the values via app.resourcesApi methods.
night199uk
night199ukOP9mo ago
ahh yeah, I found it under app.courseApi in the end It's quite confusing that they appear in the webpage data browser and not the model though and also it's hit and miss. SOME courseApi deltas are there some aren't might be worth documenting that somewhere. I didn't find it mentioned and it was surprising. I spent quite a lot of time trying to figure it out 😦
AdrianP
AdrianP9mo ago
FYI.... http://192.168.86.32:3000/documentation/develop/developer_notes.html Stream Interface Currently, when v2 REST APIs emit deltas that contain v2 paths and structure, but they do not end up in the full model. This means that these paths and values are only available via API GET requests.
night199uk
night199ukOP9mo ago
https://github.com/SignalK/signalk-to-nmea2000/pull/119 Broke out converter Promise support into it's own PR. This should be landed before https://github.com/SignalK/signalk-to-nmea2000/pull/117 as #117 now relies on the promise support in #119. hrm. in signalk-to-nmea2000: is there a way to easily test "timer" type conversions? onValueChange type conversions take their keys as arguments to the callback, so they are easy to mock. but timer type services I'm having to do app.getSelfPath to retrieve the keys I need; which i don't know how to mock. i was thinking to modify "timer" type services in signalk-to-nmea2000 so they could also specify a "keys" variable, like "onValueChange" conversions. Then, we resolve the keys and supply them to the callback before calling it. that way it makes the timer conversions themselves easier to mock and test. does that make sense as a change?
Scott Bender
Scott Bender9mo ago
Did you look at how the systemTime test works?
night199uk
night199ukOP9mo ago
yeah, it sort of cheats var dateObj = date ? date : new Date(); so it checks if the arg is null and if it is just creates new Date() object. This leads to a lot of: arg = arg ? arg : app.getSelfPath("thing") to deal with testing. my converter has 8 arguments, so it's a lot of boiler plate code. hence the idea to move the key resolution out. i'm working on a PoC now. it works, but it doesn't solve my whole problem right now. i've modified it so that 'timer' tests can also specify their keys, just like onValueChange tests. they're resolved externally and passed in. this means we can test them exactly the same way we test others. it also removes all the boiler plate: arg = arg || app.getSelfPath("some.variable") it's much cleaner. I will PR it. it solves some of my problem but not all, but I still think it helps. because navigation.course.activeRoute is not exposed in the data tree, we have to use app.courseApi to look it up. problem is app.courseApi is not mocked for the npm tests, so a converter that depends on the courseApi or navigation.course.activeRoute is untestable right now as far as I can tell. @AdrianP maybe as you helped me with the course API stuff before
Scott Bender
Scott Bender9mo ago
You could pass a dummy app object in
night199uk
night199ukOP9mo ago
yeah, will have to create a mock app & courseApi hey folks, just did some more polish on: https://github.com/SignalK/signalk-to-nmea2000/pull/117 https://github.com/SignalK/signalk-to-nmea2000/pull/118 and broke out the other work I mentioned above into: https://github.com/SignalK/signalk-to-nmea2000/pull/119 https://github.com/SignalK/signalk-to-nmea2000/pull/120 wondered what it might look like to get these landed please? i'm going to start working on pgn129285 now Initial implementation of 129285 done ✅

Did you find this page helpful?