CAN Part 11 - XNet Signal Drop Out and Triggering

The most common XNet session type I've seen used is probably Signal Single Point.  In some testing environments you may want to know the time between every frame, but in most cases knowing what the newest value is, is acceptable.  For instance you might want to know the temperature of an ECU by reading a CAN signal sent by the ECU.  Do you need to get the message telling you the ECU is at 25 degrees C, 100 times a second?  Probably not.  And does it matter if one frame comes in a few milliseconds after it was expected to?  Also probably not.  We just expect this signal to change very slowly, and maybe we react if it goes above or below a threshold.  Single Point is great for these kinds of signals.  Just get me the last value for the signal, and I'll react to it, or log it as needed, knowing I might be missing some values between reads.

Signal Single Point Flaw

So since the most common type of session I've run into is Single Point, I've looked at a few ways to make this session type even better.  One flaw of the single point session read type, is that you can't know how long ago the value came in.  When you perform a read on the frame type it returns a timestamp in the cluster that is the frame.  But with the Signal type all you get is a double that corresponds to the engineering units of that signal.  So we might perform an XNet read and be told the ECU is at 25 degrees C, but what we can't know from that read alone, is how long ago the ECU told us that.  In an extreme situation, if after the first successful read the DB9 becomes disconnected from the XNet hardware, then every read performed after would still return 25 degrees C.  Dispite the fact that there has been no CAN traffic for some time.  This is because the Single Point read has no timeout.  It just holds the last read value until a new value replaces it.  If a new value never comes, then the old value is always returned.

This type of Signal Single Input flaw can make for buggy looking user interface if all you do is perform a read and display it.  A user might see values when the ECU is off, or disconnected for instance.  Contrast this with CANalyzer which will show the engineering units of the last read value, but next to the signal is a rotating ball that stops if CAN traffic stops.  This is a visual indicator that the last read value was there at one point, but that new data isn't coming in anymore.  There are a couple of techniques to be able to detect this signal drop out with XNet, but the one that I find the most efficient is to utilize the trigger feature of the XNet device.

Triggers

When creating most XNet sessions, a Signal List, or Frame List must be provided.  This is an array of the XNet Frame, or XNet Signal data types.  This data type is basically a string with some extra useful features.  All string manipulation functions operate on these data types as if they were strings, and the XNet Create Session subVIs also accept an array of strings.  I mention this because this allows for programmatically creating the list of signals or frames to read or write.  This also has the option for making strings that normally don't show up in the drop downs when you click the constant or control.  One such signal or frame type is the Trigger type.  This is a Frame or Signal reading function that will return a 0 or a 1, if a particular Signal or Frame has been updated since the last read.  The format for this string is the following:

:trigger:.<Frame Name>.<Signal Name>

or

:trigger:.<Frame Name>

Here is a quick example of how to create a trigger Signal, for every actual Signal intended to be read:


What we see here is a list of 3 signals to read on the left.  This goes through a For Loop, and generates the 3 corresponding trigger signals and creates a new session for these 6 Signals, with the trigger signals coming after the value signals.  A read will now return the value of the Signal, followed by the Signals Trigger Signal.

Holding Values

Looking at the rest of the example VI from above you'll notice that the rest of this VI now allows for the Signal In Single Point session type to have a hold function.  Where it will hold the value of a set of given signals for some amount of time; in this case 2 seconds.  At which point the signal's value will be set to NaN (not a number).  It does this by reading the trigger and if it is 1, then we know that signal has a new value.  If it is 0 then we should keep monitoring this signal, and if after two seconds the trigger still doesn't come then we can react.  Another technique I've tried to get this same result, would be to use the Signal XY session type, then read all the values, and throw away all of them except for the latest one.  If there are no new values to read, then we know that signal hasn't been sent, and to set the value to NaN if it continues for 2 seconds.  This also works but I found there was a decent amount more CPU and memory usage when trying to read all values and all times for a large list of signals, only to throw away all the old values.  This triggering technique works well and seems to be the most efficient way to get what I want.

Using this technique we can now show the last read values of a signal, but if no new data has come in then the values will be set to NaN to indicate this loss of communication.  Ideally we would do something like CANalyzer and still show the last value, but have a new indication that the data might not be accurate since the signal is gone.  But I've found most of the time it doesn't really matter what the last reading was, it is just important to show that it is gone.  Still someone could write a wrapper around the Signal Single Point read function where it returns an array of values, and an array of booleans indicating of the values have reached their timeout and are no longer valid.

Part 12

Having XNet signal as a single point, but tracking signal drop out is pretty handy.  But one extra feature users might find useful is keep track of the minimum and maximum values of a signal.  In Part 12 I discuss ways of doing all of using by using the XNet XY session type.