2010-09-29 89 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