Open virtuvas opened 3 years ago
hm, in the meantime I updated my NMEA Reader at home PC to latest version and now PGN126208 is analysed a bit more:
so when I try to toggle a button on Maretron DSM PGN126208 appears with the following settings:
Name: NMEA - Request group function
Source = 23, Destination = 138
Priority = 3, Length = 10
Number of Fields = 7
Field 1: Request Group Function Code = 1
Field 2: Requested PGN = 127501
Field 3: Transmission interval = 27:58:49.592
Field 4: Transmission interval offset = 00:00:00.030
Interesting observation: Field 4 changes according to which button I call: 020 for button1 030 for button2 040 for button3 050 for button4 Shall I assume that Field 4 is not quite right and it's not really time offset but has the info on which button is pressed? Then the teensy see what state it was and toggles it? Makes sense?
now next ms the teensy replies:
Name: NMEA - Request group function
Source = 138, Destination = 23
Priority = 3, Length = 7
Number of Fields = 7
Field 1: Request Group Function Code = 2
Field 2: Requested PGN = 127501
Field 3: Transmission interval = 13:58:52.176
Do I get that right that Maretron uses 126208 to "query" (as a wrapper so to speak) for 127501 (which it already gets every 15secs as maretron spec sheets mention)? Makes sense?
cheers
V.
If you want to see all messages on the bus, take my NMEA Simulator and use "Message List". It shows all messages in sequential order and their times. Unfortunately it does not show parsed messages in free version. Note that Actisense Reader is not very good for analyzing, since it does not show all messages. Also on list it shows last PGN from sender. If you e.g. send 2 130316 with different instance, it shows only the last. Simulator shows both even on "Message list", since they are different messages. Currently even paid Simulator does not do full parsing for 126208 - it is on my worklist.
You should respond to ISO Request and Group function messages. ISO request is simple, since it just reaquest you to send requested PGN, Tha you do simply by adding call back function. So you will have
bool ISORequestHandler(unsigned long RequestedPGN, unsigned char Requester, int /*DeviceIndex*/) {
if ( RequestedPGN==130826UL ) {
SendStatus();
return true; // I handled it
}
return false; // Not in my interest
}
void setup() {
...
NMEA2000.SetISORqstHandler(ISORequestHandler);
...
}
The above you should actually do for all PGNs you add to transmit. Library can not do them automatically, since it does not know how to construct messages. Instead it handles automatically all requests to system PGNs like 60928, 126996, 126998, 126993.
126208 is more complex. Library also automatically handle that for system messages, but for others it responds as default "no support". To provide support for 126208 for specific PGN, you have to inherit tN2kGroupFunctionHandler and write handlers. Then you add your handler with:
NMEA2000.AddGroupFunctionHandler(PGN130826GroupFunctionHandler);
There are examples for system messages on N2kGroupFunctionDefaultHandlers. You can study on document NMEA 2000-corrigendum-tc201401031 pgn 126208.pdf what you should do. The point is that with 126208 requester
Your 126208 request to 127501 does not tell all. It may request some specific fields or just resend 127501. You have to get full data of that and parse it out.
Timo, thanks for the pointers but unless I enrol in an Open University course on programming (now at 57), I wont be able to apply most of your suggestions...
To be honest reading the above was about to give up, but thought I'd give it a go reading bits from this 126208 that Maretron display is broadcasting as I was looking at some numbers that changed according to the button I was pressing. So a few hours playing around yesterday night and I'm at the following point:
126208.cpp
bool ParseN2kPGN126208(const tN2kMsg &N2kMsg, unsigned char &GroupFunctionCode
,int &PGN
,uint32_t &Status2
,uint16_t &Status3
,uint8_t &DeviceBankInstance
,uint8_t &BitStatusToggle
) {
if (N2kMsg.PGN!=126208L) return false;
int Index=0;
GroupFunctionCode=N2kMsg.GetByte(Index);
PGN=N2kMsg.Get3ByteUInt(Index);
Status2=N2kMsg.Get2ByteUInt(Index);
Status3=N2kMsg.GetByte(Index);
DeviceBankInstance=N2kMsg.GetByte(Index);
BitStatusToggle=N2kMsg.GetByte(Index);
return true;
}
126208.h
bool ParseN2kPGN126208(const tN2kMsg &N2kMsg, unsigned char &GroupFunctionCode,
int &PGN, uint32_t &BankStatus2,
uint16_t &BankStatus3, uint8_t &DeviceBankInstance,
uint8_t &BitStatusToggle);
inline bool ParseN2kBinaryStatus2(const tN2kMsg &N2kMsg, unsigned char &GroupFunctionCode,
int &PGN, uint32_t &BankStatus2,
uint16_t &BankStatus3, uint8_t &DeviceBankInstance,
uint8_t &BitStatusToggle) {
return ParseN2kPGN126208(N2kMsg,GroupFunctionCode,PGN,BankStatus2,BankStatus3,DeviceBankInstance,BitStatusToggle);
}
Configured a screen on the Maretron to have/show/toggle Bank2#1, Bank2#2, Bank6#3 and Bank6#4
[EDIT: corrected Bank6 number bits-weren't 1 and 2 as the Bank2, but 3 and 4, sorry for the confusion] hitting the respective toggles on the screen I get:
Bank#2#1:
Request Group Function Code: 1 Request PGN: 127501 BinaryStatus2: 760 BinaryStatus3: 1 Device Bank Instance: 2 Bit Status Toggle: 2
Bank#2#2:
Request Group Function Code: 1 Request PGN: 127501 BinaryStatus2: 760 BinaryStatus3: 1 Device Bank Instance: 2 Bit Status Toggle: 3
Bank#6#3:
Request Group Function Code: 1 Request PGN: 127501 BinaryStatus2: 760 BinaryStatus3: 1 Device Bank Instance: 6 Bit Status Toggle: 4
and similarly Bank#6#4:
Request Group Function Code: 1 Request PGN: 127501 BinaryStatus2: 760 BinaryStatus3: 1 Device Bank Instance: 6 Bit Status Toggle: 5
It's very tempting to finish off now, just pick on teensy Device Bank Instance and Bit Status toggle (as I named them) alter my 127501 and post it again to change the Maretron Display. Tried it works.
I know it's a hack but I don't think I can get much more than that tbh. Any idea what this 760 and 1 are, in theory they would be: Transmission interval (optional) and Transmission interval offset (also optional)
I can just ignore them I guess! I will come back on this statement of yours that I should reply on all the PGNs I'm reading (not doing it atm, will try to understand it better and will ask clarifications)
thanks
V.
The one problem is that you can not parse 126208 in your way. With first byte it changes to different handling. That is why there is class tN2kGroupFunctionHandler, which takes care of basic decisions and call virtual handlers.
In N2kGroupFunctionDefaultHandlers good examples for your case are tN2kGroupFunctionHandlerForPGN126996, tN2kGroupFunctionHandlerForPGN126998 or tN2kGroupFunctionHandlerForPGN126464. tN2kGroupFunctionHandlerForPGN126996 or tN2kGroupFunctionHandlerForPGN126464 does not have any HandleCommand inherited, since they does not have any configurable parameters. Instead tN2kGroupFunctionHandlerForPGN126998 has both installation description fields configurable, so it has inherited HandleCommand.
In your case you could use e.g. tN2kGroupFunctionHandlerForPGN126998 as a sample but not inherit first HandleCommand. HandleCommand you need, when you accept also commanding for switches. When you do not inherit some function, base class send right default answer (=not supported). For request matching actually tN2kGroupFunctionHandlerForPGN60928::HandleRequest is better sample, since tN2kGroupFunctionHandlerForPGN126998::HandleRequest does matching against strings and looks a bit more complex.
Also in your parser the first field after PGN should be 4 byte uint.
I meshed a bit. Your Group Function Code = 1, which means command, not request. In that case there is
So you read 760 2 bytes, 1 1 byte, 2 1 byte, 2 1 byte. 760=0x2f8, which translates priority setting = 8 = do not change reserverd 0xf number of pairs = 2 then first field = 1 (instance) first value = 2 (instance value) second field = 2 ( first bit ) Then you are missing data. If you read further, you would see is it requesting bit on or off.
This would be handled better, if you would use inherited tN2kGroupFunctionHandler and HandleCommand.
Timo, yes, noticed that by studying the N2K 126208 PDF
However, things are not quite right, bear with me.
I've come up with the following .ccp:
//*****************************************************************************
bool ParseN2kPGN126208(const tN2kMsg &N2kMsg
,uint8_t &GroupFunctionCode
,int &PGN
,int &PrioritySetting
,uint8_t &var1
,uint8_t &NumberofPairs
,unsigned char &DeviceBankInstance
,uint8_t &SwitchIndex
,uint8_t &ItemStatus
,uint8_t &var2
,uint8_t &var3
) {
if (N2kMsg.PGN!=126208L) return false;
int Index=0;
GroupFunctionCode=N2kMsg.GetByte(Index);
PGN=N2kMsg.Get3ByteUInt(Index);
uint16_t MsgPrioritySetting;
MsgPrioritySetting=N2kMsg.GetByte(Index); //Get2ByteUInt(Index);
PrioritySetting = MsgPrioritySetting & 0b00001111 ;
var1=N2kMsg.GetByte(Index);
NumberofPairs=N2kMsg.GetByte(Index);
DeviceBankInstance=N2kMsg.GetByte(Index);
SwitchIndex=N2kMsg.GetByte(Index);
ItemStatus=N2kMsg.GetByte(Index);
var2=N2kMsg.GetByte(Index);
var3=N2kMsg.GetByte(Index);
return true;
}
which deviates from what the PDF claims in the following:
A. there's a var1 that always has a value of two no matter which switch i'm toggling
B. each "pair" is not really a pair as the Field number of first commanded parameter (as per the PDF) is what i'd call Device Bank (or Instance for Maretron) and there's another byte which I call Switch Index (or Channel for Maretron) and THEN the third byte is the toggle value (0/1)
The above code for toggling in Maretron speak Instance 2, Channel 1 I'd get:
to turn on:
PGN126208
Command Group Function Code: 1
Commanded PGN: 127501
PrioritySetting: 8
VAR 1 : 2
Number of Pairs: 1
Device Bank Instance: 2
Switch Index to Toggle: 2
Toggle Status: 1
VAR 2 : 255
VAR 3 : 255
and to turn off:
PGN126208
Command Group Function Code: 1
Commanded PGN: 127501
PrioritySetting: 8
VAR 1 : 2
Number of Pairs: 1
Device Bank Instance: 2
Switch Index to Toggle: 2
Toggle Status: 0
VAR 2 : 255
VAR 3 : 255
Note, VAR 1 always 2, VAR2 and VAR3 (got them just in case there is something useful after the bytes I'm reading) 255, so I'll ignore them.
Pretty sure the rest is OK, as when I toggle for example Instance 6, Channel 3, I get:
Device Bank Instance: 6 Switch Index to Toggle: 4
Your views please, am I missing something, or is it simply that Maretron are not following the standard?
The only thing I could imagine is that PDF number 3&4 (Priority Setting and Reserved NMEA) is not one byte but two and that 7 (Value of first command parameter) is two byte the first being the Channel and the second the toggle value 0 or 1.
cheers
V.
I think you read it wrong. Your var1 is number of pairs - thats why it is 2 and your number of pairs is field index for first pair - field 1 is instance field. var2 and var 3 are just filling. length should show you that those are not used. Also in your code you should skip everything, if GroupFunctionCode!=1.
The strange thing is that 127501 is status PGN, which should not be commanded at all. It should be done by 127502. For 127501 all fields are marked prohibited for command parameter.
struggling a bit here Timo,
so new ver of .cpp
bool ParseN2kPGN126208(const tN2kMsg &N2kMsg
,uint8_t &GroupFunctionCode
,int &PGN
,int &PrioritySetting
,uint8_t &NumberofPairs
,uint8_t &var1
,unsigned char &DeviceInstance
,uint8_t &DeviceChannel
,uint8_t &ChannelStatus
) {
if (N2kMsg.PGN!=126208L) return false;
int Index=0;
GroupFunctionCode=N2kMsg.GetByte(Index);
if (GroupFunctionCode!=1) return false;
PGN=N2kMsg.Get3ByteUInt(Index);
uint16_t MsgPrioritySetting;
MsgPrioritySetting=N2kMsg.GetByte(Index);
PrioritySetting = MsgPrioritySetting & 0b00001111 ;
NumberofPairs=N2kMsg.GetByte(Index);
var1=N2kMsg.GetByte(Index);
DeviceInstance=N2kMsg.GetByte(Index);
DeviceChannel=N2kMsg.GetByte(Index);
ChannelStatus=N2kMsg.GetByte(Index);
return true;
}
and say I agree that we have two pairs of data.
first pair will be: var1 & DeviceInstance second pair will be: DeviceChannel & ChannelStatus
Note please that according to maretron at least we have: Instance 0-252 (and that's how it's reported) channel 1-28 (it's reported +1 in each case...) Also note that unless I'm posting every 15sec a PGN127501 for the particular Instance, Maretron wont sent 126208 for this instance.
So Instance 251, channel 3 Maretron button press is:
PGN126208
Command Group Function Code: 1
Commanded PGN: 127501
PrioritySetting: 8
Number of Pairs: 2
VAR 1 : 1
Device Instance: 251
Device Channel : 4
Channel Status: 0
and Instance 2, channel 1 is:
PGN126208
Command Group Function Code: 1
Commanded PGN: 127501
PrioritySetting: 8
Number of Pairs: 2
VAR 1 : 1
Device Instance: 2
Device Channel : 2
Channel Status: 0
Mind, Channel Status, toggles from 0 to 1 in every consecutive press on the Maretron and I've written a bit of code that follows and sends the right 127501 so the colour changes accordingly.
The only real question that remains is what is this var 1 ? I cannot accept that it is an index of pairs as then Device channel should be number 2 always but it isn't!
The strange thing is that 127501 is status PGN, which should not be commanded at all. It should be done by 127502. For 127501 all fields are marked prohibited for command parameter.
Is that considered commanding though? Maretron kindly asks its control device (likely DCR100) to change state in particular instance/channel combination. Control device (DCR100) does so and sends 127501 to the bus. Is it not more a matter of semantics?
your views please!
Now your var1 is first field index. Remeber that those are field/value pairs. So there is always field index and then its value. So field 1, value 2, field 2 value 0 on your last message. Status bits starts from field 2 so as you said channel 1 is on field 2. Note that this message has totally 29 fields, since it carry bank instance + 28 status bits (or channels as you call). Channel number does not need to be always 2. If you set "channel 28", it will have data 2 pairs, field 1, value 2 (instance), field 29, value 0 (off).
Just believe, they do it right.
no, cannot be Timo!
the following is for instance 251, channel 28:
PGN126208
Command Group Function Code: 1
Commanded PGN: 127501
PrioritySetting: 8
Number of Pairs: 2
VAR 1 : 1
Device Instance: 251
Device Channel : 29
Channel Status: 0
According to you first pair would be: VAR 1 = 1 Device instance = 251 which is fine
and second pair should be
2 and 29 but it's
29 for the channel 0 for the status bit (could also be 1)
last example was suitable to your argument but the one above it wouldn't work.
Instance 251, channel 3:
PGN126208
Command Group Function Code: 1
Commanded PGN: 127501
PrioritySetting: 8
Number of Pairs: 2
VAR 1 : 1
Device Instance: 251
Device Channel : 4
Channel Status: 0
there is something missing, or we just accept that the first pair uses the field index and value logic and the second pair is channel number and channel value, which is not a consistent behaviour.
V.
Exactly. 2 pairs. First pair field index (var1) = 1 (=instance field), first pair field value 251 (=instance value), second pair field index 29 (channel 28 field), second pair value 0 = off (channel 28 field commanded value).
Why you think there should be 2 on second pair? It is not index of pairs. It is index of field value commanded to set. Only difference that instance is required identifying field/value pair. Field values can be even in any order. So to set channels 3, 6, 9 all to 0 for bank instance 25 you can have data (field index/value) 4 pairs, 4/0, 10/0, 7/0, 1/25 So your code would not work for above, but it is right according to NMEA2000. Certification tool actually tests that device handles fields in any order for 60928 - that is why fields has to be looped and identified by field index as in my code - not by order.
Note also that commanding 127501 is simpler case, since all fields are 1 byte long, since values are in full bytes even channel values uses only 2 bits. If you would command 128520 target name and status you could have data: 3 pair count, 13 first pair field (name field) 4+"Test" name length 4 and name 4 bytes = Test 14 second pair field ( ref target) 1 enabled (field value) 2 third pair field ( ID) 1234 ID (field ID value), 2 bytes
On the other hand as order can be anything, it may be also 3 pair count, 2 first pair field ( ID) 1234 ID (field ID value), 2 bytes 14 second pair field ( ref target) 1 enabled (field value) 13 third pair field (name field) 4 "Test" name length 4 and name 4 bytes
If type those to hex you will se that there is no fixed postitions for information. It must be looped and take first field index, and then look from the database, how that field has to be handled and read out required data. After that there will be next field index and again one has to check the length and type of the field etc.
Exactly. 2 pairs. First pair field index (var1) = 1 (=instance field), first pair field value 251 (=instance value), second pair field index 29 (channel 28 field), second pair value 0 = off (channel 28 field commanded value).
Why you think there should be 2 on second pair? It is not index of pairs. It is index of field value commanded to set. Only difference that instance is required identifying field/value pair. Field values can be even in any order. So to set channels 3, 6, 9 all to 0 for bank instance 25 you can have data (field index/value) 4 pairs, 4/0, 10/0, 7/0, 1/25 So your code would not work for above, but it is right according to NMEA2000. Certification tool actually tests that device handles fields in any order for 60928 - that is why fields has to be looped and identified by field index as in my code - not by order.
OK, I thought it was index of pairs, you are right, so I'm done with this by the looks of it! Is there any point in adding it to the N2kMaretron.cpp /.h? If you want let me know. I already added it to my own custom lib so personally for my work, I'm OK.
BTW, I read in the PDF:
The Command Group Function message is directed to a specific address, the Global Address (255) shall not be used. Indeed my Maretron is 23 and the teensy that is acting as a switch is 138.
23 is indeed sending to 138, but I'm not doing anything about it in my code. I guess 23 checks which bus device broadcasts PGN127501 at right intervals and if a call is made for a switch operated by that device it broadcasts to it. Am I right in that?
BTW, how do I send the set status on one particular item only? I mean say in previous example of instance 251 and channel 3, how do I set that to 1? do I use N2kSetStatusBinaryOnStatus ? tried it didn't quite work!
V.
well,
N2kSetStatusBinaryOnStatus(DeviceInstance,ChannelStatus, DeviceChannel);
worked, BUT I had to change to:
bool ParseN2kPGN126208(const tN2kMsg &N2kMsg
,uint8_t &GroupFunctionCode
,int &PGN
,int &PrioritySetting
,uint8_t &NumberofPairs
,uint8_t &FieldIndex
,tN2kBinaryStatus &DeviceInstance
,uint8_t &DeviceChannel
,tN2kOnOff &ChannelStatus
) {
if (N2kMsg.PGN!=126208L) return false;
int Index=0;
GroupFunctionCode=N2kMsg.GetByte(Index);
if (GroupFunctionCode!=1) return false;
PGN=N2kMsg.Get3ByteUInt(Index);
uint16_t MsgPrioritySetting;
MsgPrioritySetting=N2kMsg.GetByte(Index);
PrioritySetting = MsgPrioritySetting & 0b00001111 ;
NumberofPairs=N2kMsg.GetByte(Index);
FieldIndex=N2kMsg.GetByte(Index);
DeviceInstance=N2kMsg.GetByte(Index);
DeviceChannel=N2kMsg.GetByte(Index);
ChannelStatus=N2kMsg.GetByte(Index);
return true;
}
why is:
typedef uint64_t tN2kBinaryStatus;
doesn't really match with the 126208 def...
V.
Is there any point in adding it to the N2kMaretron.cpp /.h?
No. Please keep it out from library files. Better not to add either to N2kMaretron on your own files, since if you update library, it will overwrite your module.
So there is things not done right. I would like to find more general solution before publishing anything.
I still wonder, why Maretron does changes with 127501. There is 127502 for commanding switches. On the other hand I have seen mentiond that 127502 would be deprecated. Do you set that you listen 127502 on your system?
OK, as I said, I'll keep it with my gvd.cpp/.h custom PGN library for my stabilisers and for my boat application only.
- Designed way to do this would be inherit tN2kGroupFunctionHandler and provide call back for changing bits.
- 127501 should not accept command according to my knowlegde.
You have mentioned tN2kGroupFunctionHandler, tbh haven't understood how I'm meant to use that, so I'll skip for now.
So there is things not done right. I would like to find more general solution before publishing anything.
no problem, if you do find anything and would like me to test it on board my system, let me know.
I still wonder, why Maretron does changes with 127501. There is 127502 for commanding switches. On the other hand I have seen mentiond that 127502 would be deprecated. Do you set that you listen 127502 on your system?
https://www.maretron.com/support/manuals/DSM250UM_1.6.2.html#_Toc432163424 has the PGN list that the device supports. There is NO mention of 127502, it does accept 127501 (among a zillion other PGNs!) and that's what I'm doing. BTW, I checked with NMEA Reader, no 127502 is broadcasted on the bus.
thanks again for your help Timo!
V.
for the record and in order to have a more inclusive view on this topic, I found this: How do I switch a relay channel on the Maretron DCR100 using a non-Maretron display? https://www.maretron.com/support/knowledgebase/phpkbv7/print.php?id=587
explains that whatever device sends 126208 with 127501 Binary Switch Bank Status message to the Maretron DC relay box, it acts upon it by changing relay state and then returns 127501. That seems to be what I'm doing. I hear what you say regarding not being according to spec, but it looks that Maretron are not following the N2K rules... closing this and starting another one regarding reading switch state
V.
good morning,
trying to get my DSM250 display to "communicate" with a teensy3.5 as far as switching relays is concerned.
Teensy sending PGN127501 sent every 15secs (as per the Maretron spec) does the trick in showing on the switch/breaker display the right buttons with the right standard colours (grey not configured, green on, red off) changing the PGN means that colours change on the Maretron screen so the teensy -> Maretron comms is fine.
Now, I was expecting that when I hit a button (well, toggle state) on the Maretron it would broadcast 127501 or 127502. It doesn't! Using NMEA Reader on a second teensy running ActisenseListener shows the following:
When I get to toggle status mode (remember not a touch screen so you have to get there first, navigate to the right screenbutton and then you hit a physical button to toggle state):
Maretron issues a PGN59904 which is an ISO Request to the teensy for PGN130826 teensy replies the next ms with PGN59392 ISO Acknowledgment regarding PGN130826. PGN130826 is according to Maretron docs Switch Indicator Status so I need to get to that! It obviously doesn't send it as I have no clue what should be there - that's point A.
when I actually toggle one button (follows navigation to the right button using the arrow keys that produces nothing on the bus- which I find normal):
Maretron issues a PGN126208 which is a NMEA Request group function (nothing reported on NMEA Reader...) teensy replies the next ms with PGN126208 as well (again nothing reported on NMEA Reader) - that's point B.
So to start from the easy bit: Point B: Do i really care about the 126208 or ignore it? Well to reply to myself and reading again the #128 issue, this pgn replaces 502, so I have to implement them and that's it, correct? Timo, have you got any pointers on this PGN? you do mention it's complicated, that's all and reading #162 and the 19p description of the PGN make me want to discard this idea of mine... Any code that might get me to toggle 4 (or 16) buttons would be nice, happy with 4 :-)
Point A: any idea how to progress with PGN130826?
Am I right in thinking that unless teensy sends 130826 with the right info, Maretron wont go any further as posting state of buttons on its screen? Seems odd as Maretron is already showing what teensy is posting through 127501, so I'm confused.
ideas?
V.