views:

67

answers:

2

Hi, I'm implementing a class that talks to a motor controller over a USB device. I have everything working except for a way to indicate whether a parameter fetched over the comm link is "fresh" or not. What I have so far:

class MyCommClass
{
public:
  bool getSpeed( double *speed );

private:
  void rxThread();

  struct MsgBase 
  { /* .. */ };

  struct Msg1 : public MsgBase
  { /* .. */ };

  struct Msg2 : public MsgBase
  { /* .. */ };

  /* .. */

  struct MsgN : public MsgBase
  { /* .. */ };

  Msg1 msg1;
  Msg2 msg2;
  /* .. */
  MsgN msgn;

  std::map< unsigned long id, MsgBase *msg > messages;
};

rxThead() is an infinite loop running in a separate thread checking the USB device for available messages. Each message has a unique identifier which rxThread() uses to stick it into the right msgx object. What I need is when the user calls the getSpeed() function it needs to be able to tell whether the current speed value is "fresh" or "stale" i.e. whether the msgx object that contains the speed value was updated within a specified timeout period. So each message object needs to implement its own timeout (since they vary per message).

All messages are transmitted periodically by the motor controller, but there are also some that get transmitted as soon as their contents change (but they will also be transmitted periodically if the contents do not change). This means that receiving a message at more than the nominal rate is OK, but it should appear at least once within the maximum timeout period.

The USB device provides timestamps along with the messages so I have access to that information. The timestamp does not reflect the current time, it is an unsigned long number with microsecond resolution that the device updates every time a message is received. I suspect the device just starts incrementing this from 0 from the time I call its initialization functions. A couple of different ways I can think of implementing this are:

  • Each message object launches a thread that runs infinitely waiting (WaitForSingleObject) for the timeout period. After the timeout it checks whether a counter variable (that was cached before the wait) has been incremented. If not it sets a flag marking the message as stale. The counter would be incremented every time rxThread() updates that message object.

  • rxThread(), in addition to stuffing messages, also iterates through the list of messages and checks the timestamp that each was last updated. If the timestamp exceeds the timeout it flags the message as stale. This method might have a problem with the amount of processing required. It probably wouldn't be a problem on most machines but this code needs to run on a piggishly slow 'industrial computer'.

I'd really appreciate your thoughts and suggestions on how to implement this. I'm open to ideas other than the two I've mentioned. I'm using Visual Studio 2005 and cross-platform portability is not a big concern as the USB device drivers are Windows only. There are currently about 8 messages I'm monitoring, but it would be nice if the solution were lightweight enough that I could add several (maybe another 8) more without running into processing horsepower limitations.

Thanks in advance, Ashish.

+1  A: 

How about storing the timestamp in the message, and having getSpeed() check the timestamp?

Hasturkun
The timestamp is not the current time, its just an `unsigned long` counter with microsecond resolution that will keep rolling over. So the only way to determine a timeout is to take the difference of 2 timestamps or cache the existing timestamp, then wait for timeout period and see if the timestamp has been updated. `getSpeed()` itself is not called periodically, so it has no idea when the message was updated simply by looking at the timestamp number. I'll update the description with details of the timestamp.
Praetorian
You can store your own timestamp based on the received value. this would work much the same way as your second implementation idea.
Hasturkun
@Hasturkun's got a great idea there. I'd just store my own timestamps on the messages, then check `now - timestamp` in `getSpeed()`. Note: implementation may be fiddly if your timeout values need to be small and/or precise. The best precision you can rely on under Windows is as per `gettickcount()` - ~16ms (as QueryPerformanceCounter commonly suffers from core missync issues that MS blame on BIOS/HAL implementers that can easily be hundreds or thousands of milliseconds).
Tony
+1  A: 

If you don't need to do something "right away" when a message becomes stale, I think you can skip using timers if you store both the computer's time and the device's timestamp with each message:

#include <ctime>
#include <climits>

class TimeStamps {
public:
  std::time_t sys_time() const;   // in seconds
  unsigned long dev_time() const; // in ms
  /* .. */
};

class MyCommClass {
  /* .. */
private:
  struct MsgBase {
    TimeStamps time;
    /* .. */
  };

  TimeStamps most_recent_time;

  bool msg_stale(MsgBase const& msg, unsigned long ms_timeout) const {
    if (most_recent_time.sys_time() - msg.time.sys_time() > ULONG_MAX/1000)
      return true; // device timestamps have wrapped around
    // Note the subtraction may "wrap".
    return most_recent_time.dev_time() - msg.time.dev_time() >= ms_timeout;
  }
  /* .. */
};

Of course, TimeStamps can be another nested class in MyCommClass if you prefer.

Finally, rxThread() should set the appropriate message's TimeStamps object and the most_recent_time member each time a message is received. All this won't detect a message as stale if it became stale after the last message of any other type was received, but your second possible solution in the question would have the same issue, so maybe that doesn't matter. If it does matter, something like this could still work, if msg_stale() also compares the current time.

aschepler