2010-09-29 41 views
1

我执行,超过一个USB设备会谈到电机控制器的类。除了用于指示通过通信链接获取的参数是否为“新鲜”的方法之外,我已经做了所有工作。我有什么至今:实现通信超时

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()是在一个单独的线程检查是否有可用的消息的USB设备运行的无限循环。每个消息具有rxThread()用来它粘成右msgx对象的唯一标识符。我需要的是当用户调用getSpeed()功能,它需要能够告诉当前速度值是否为“鲜”或“失效”,即包含速度值的msgx对象是否在指定的超时期限内更新。所以每个消息对象都需要实现自己的超时(因为它们根据消息而不同)。

所有消息由电机控制器定期发送的,但也有一些想要获取其内容改变传输(但他们也将定期,如果内容不改变发送)。这意味着以超过标称速率接收消息是可以的,但它应该在最大超时时间内至少出现一次。

的USB设备提供时间戳与消息一起,所以我有机会获得这些信息。时间戳不反映当前时间,它是一个unsigned long数字,分辨率为微秒,设备每次收到消息时都会更新。我怀疑该设备从我调用其初始化函数的时间开始,从0开始递增。一对夫妇不同的方式我能想到实现这个的是:

  • 每个报文对象启动运行无限等待(WaitForSingleObject的)的超时时间的线程。在超时之后,它检查一个计数器变量(在等待之前被缓存了)是否增加了。如果不是,它将标记该消息的标志设置为陈旧。每次rxThread()更新该消息对象时,计数器都会递增。

  • rxThread()除填充消息外,还遍历消息列表并检查每个消息的最后一次更新的时间戳。如果时间戳超过超时时间,则将该消息标记为陈旧。此方法可能会遇到所需处理量的问题。在大多数机器上它可能不会成为问题,但是这些代码需要在一台速度很慢的“工业计算机”上运行。

我真的很感激你的想法和建议,如何实现这一点。除了我刚才提到的两个之外,我都接受了其他想法。我使用的是Visual Studio 2005,因为USB设备驱动程序仅适用于Windows,所以跨平台可移植性不是什么大问题。目前我正在监控大约8条消息,但如果解决方案足够轻便,我可以添加多个(也许是另外8个)更多,而不会遇到处理马力限制的情况,那将会很不错。

在此先感谢, Ashish。

回答

1

如果您不需要做什么“马上”当消息变得陈旧,我想如果你同时存储在计算机的时间和设备的每个消息时间戳可以跳过使用定时器:

#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; 
    } 
    /* .. */ 
}; 

当然,如果您愿意,TimeStamps可以是MyCommClass中的另一个嵌套类。

最后,rxThread()应该在每次收到消息时设置适当的消息的TimeStamps对象和most_recent_time成员。如果在接收到任何其他类型的最后一条消息后它变得过时,所有这些都不会检测到过时的消息,但是在问题中您的第二个可能的解决方案会有同样的问题,所以也许这并不重要。如果它确实很重要,如果msg_stale()也比较当前时间,这样的事情仍然可以工作。

1

如何存储在消息中的时间戳,并具有getSpeed()检查时间戳?

+0

时间戳不是当前时间,它只是一个具有微秒分辨率的'unsigned long'计数器,它将继续滚动。因此,确定超时的唯一方法是取两个时间戳的差值或缓存现有时间戳,然后等待超时期限并查看时间戳是否已更新。 'getSpeed()'本身并不是周期性的调用,所以它不知道消息什么时候通过查看时间戳数字来更新。我会用时间戳的详细信息更新描述。 – Praetorian 2010-09-29 02:36:34

+1

您可以根据收到的值存储自己的时间戳。这与您的第二个实现想法的工作方式大致相同。 – Hasturkun 2010-09-29 02:47:49

+0

@ Hasturkun在那里有个好主意。我只在消息上存储自己的时间戳,然后在'getSpeed()'中检查'now - timestamp'。注意:如果你的超时值需要很小和/或精确,实现可能会很费力。在Windows下可以依赖的最佳精度是按照gettickcount()〜〜16ms(因为QueryPerformanceCounter通常遭受核心错误同步问题,MS责备BIOS/HAL实现者,可能容易上百或上千毫秒)。 – 2010-09-29 04:10:26