Packet Verification

Topics: Emulator Library
Dec 5, 2010 at 1:31 AM

When checking the packet to make sure that they are valid, there are three things that need to be checked.

  1. Packet Length
  2. Switch Bits
  3. Non-switch Bits

Packet length can never be checked directly. Instead, each switch subsection of the packets must be checked in accordance with the corresponding switch bits. See cRIO Communication Protocol in the docs for information about the switches and their lengths. The non-switch bits can be verified only by checking to see if the spots that are supposed to be zeros are, in fact, zeros. In the "real world" implementation of the cRIO, any bits that are supposed to be zeros are ignored. While it is best practice to keep these as zeros in the event that in the future they are used, the cRIO ignores them and only checks and executes what it knows. The emulator should ignore these non-used bits as well, even if they are not zeros, to correctly simulate the emulator.

Dec 5, 2010 at 8:41 PM
Edited Dec 5, 2010 at 9:14 PM

The next question that ought to be addressed, given the above, is:

If the packet begins with a section to, say, update the south end valve states, but is followed with an invalid section, should the south valve states be updated and the remainder of the packet discarded, or should the entire packet be discarded?

Finally, the Weir Packet and Mister Packet are identical? Given the current packet spec there is no way to differentiate the two.

Dec 6, 2010 at 4:16 AM
Edited Dec 6, 2010 at 4:18 AM

The cRIO will process a command until it reaches the end of the packet or an invalid switch bit. In your example, the cRIO would update the south end states, and then drop the rest of the packet. One thing to note, though, is that there is a "ping" packet that (according to the old PLC docs) will have the cRIO send the status report back. While I'm not sure if this is actually happens with the cRIO, I do know that the cRIO will allow for gaps between commands as long as it is filled with zeros. For example, 0x3 1 0 0 0 1 0 0 0 1 9 3 5 2 will result in weir 1 being activated (3 1), ignore the three zeros (0 0 0), turn on V1 (1 0 0 0 1), and then toss the rest of the packet because it doesn't match any known switches (9 3 5 2).

The Weir and Mister packets are different. I made an error when entering the documentation. That has now been corrected.

Dec 6, 2010 at 4:43 AM

Pardon me for being obnoxiously picky.

I think one of the two qualifiers needs to be added as far as packet validation goes, and not knowing as much about the communication protocol, I have to put them on the thread to determine which one is correct.

  1. The packet validation looks at an entire switch's (byte 0) value to determine what kind of data the packet should contain, or some subset of it (ie array[0] == 2)
  2. The packets are validated by simply checking if required bits are on (for example, bits 1 and 2 for the mister packet), but does so in a specific order to avoid ambiguity with other possible headers

As described, the cRIO checks for bits that should be on to determine the type of data that will follow that byte. For example, if bit 0 is on, then the next four bytes should describe the south end valve states. In C# code it could be implemented this way:

if((array[0] & 0x1) == 1){
// This must describe the south valve states, providing there are four more bytes following
The problem occurs specifically in the case of north end valve state vs. weir packet vs mister packet. The switch for the north end valve state is bit 1 on, however both the weir and mister packets also have bit 1 on. If we make checks in the fashion of the sample code above, and check first for north end valve state, then no weir nor mister packets will ever be interpreted, and data corruption could occur. So, one of the two qualifiers above needs to be added.

Dec 7, 2010 at 3:09 AM

I'm not exactly sure if I understand your question. The switch tells the cRIO what it is processing and how far it should look for the data. The (known) switches are:

  • 0x0 for ping
  • 0x1 for setting the south end valves
  • 0x2 for setting the north end valves
  • 0x3 for setting the weirs
  • 0x6 for setting the misters

In code, you could do something like

if(array[0] ==  0)
	// do nothing
else if (array[0] == 1 && array.length >= 5)
	// update the south end
else if (array[0] == 2 && array.length >= 5)
	// update the north end
else if (array[0] == 3 && array.length >= 2)
	// update the weirs
else if (array[0] == 6 && array.length >= 2)
	// update the misters
	throw new ArgumentException();
Looking at your code, this is almost exactly what you had. All I changed was adding the ping and weir identification. When validating a packet, the most you can do is check the switch and see if the length of the packet is large enough to hold the necessary data. If the packet contains additional information (i.e. has data where there should be zeros), the cRIO ignores that. You can think of those as don't-cares. Developers are only encouraged not to use them in the event that those bits are used in the future. If, for whatever reason, the developer screwed up and didn't provide the correct switch or added extra garbage to the packet that the cRIO doesn't care about, it just ignores the garbage and processes the packet according to the rules above. If the input is wrong, then an exception is thrown. You can't read minds, or at least I hope you can't! :D

I've stuck in some more notes about the cRIO protocol as well.

Dec 7, 2010 at 3:22 PM

Though you may not have understood it, the question has been addressed. What I was wondering about was what happened if there were ones in the places that zeroes should have been in the switch bytes (byte 0 of the packet, or really, the subsection of the packet). Given the code you presented, that would create a different switch, meaning all bits of Byte 0 are examined, but only used bits in the remainder of the packet are checked.

Dec 7, 2010 at 5:55 PM

Yes, that is correct. The entire switch byte is checked to see if it matches a known switch and, in the event of a match, then only checks the known bits for the new state. I'll update the documentation to clarify this.