2015-12-02 25 views
0

我試圖通過以太網到串行轉換器將新微控制器連接到現有的OSC(開放式聲音控制)網絡。如何從MCU UART解析不確定長度的數據包?

的OSC消息具有以下格式發送:

  • OSC地址圖案:/串/任選的子 - >有額外NULL對準總是32位打包/ DWORD字節在端
  • 類型標記:int32(i),float32(f),string(s)
  • 數據:對於某些模式,這是已知的長度;對於其他人來說,它的長度不確定

我對如何最好地劃分代碼以及如何緩衝這個問題有點困惑。在我的UART接收ISR中,我希望只是將傳入的字節轉儲到SRAM緩衝區,然後在主循環中解碼它們,但我不確定如何在不確定長度的數據包中執行此操作。我從來沒有使用可變長度的數據包,但沒有在頭文件中指出數據包的大小。也沒有任何EOP /頁腳來表示數據包的完成,並且您將根據類型標籤解碼x個字節。

一些問題: 1.如何調整緩衝區大小?是的,我可以動態地做到這一點,但如果可能的話,我寧願避免這種開銷。這導致我走向一個循環緩衝區,但是如何在繼續解碼可變長度數據包的同時在主循環中提取我需要的內容? 2.在ISR中應該做多少解碼?我是否在主循環中設置了某種類型的狀態機,該狀態機根據傳入字節的ISR解碼而前進,然後在推進FSM時刷新這些字節?

尋找任何建議/指導如何最好地解決這個問題/架構的代碼。先謝謝你。

+0

一般來說,對於不確定長度的數據,並給出一個串行字節流,沒有可能的答案,你是完全愚蠢的,你的任務不能完成。 –

+0

歡迎訪問我的[關於EE SE的非常相關的問題](http://electronics.stackexchange.com/questions/186254/serial-protocol-delimiting-synchronization-techniques) –

+0

不要在ISR中進行任何解碼。主循環應該做所有的解碼/解析。循環緩衝區的大小應該儘可能大,以避免傳入的字符溢出,即對各種識別部分的解析應該比按照給定「波特」速率填充緩衝區花費的時間少。該緩衝區的長度與數據流的長度無關。此問題與使用編譯器解析源代碼非常相似。編譯器在解析更多代碼時未知源的長度。沒有編譯器使用緩衝區來保存整個源。 – tonypdmtr

回答

1

UART接收ISR應該簡單地從UART讀取傳入字節並將其複製到循環緩衝區。我不會對ISR中的字節進行任何解碼/解析/解釋。循環緩衝區應該足夠大,以包含您期望收到的最大消息(或者,如果消息突發可以比主循環能夠更快到達,則緩衝區更大)。

主循環應該使用狀態機將字節流解析爲消息。狀態可以被命名爲READ_ADDRESS,READ_TYPE和READ_DATA。或者您可能希望爲每種消息類型設置一個唯一的READ_DATA狀態。

從高層次來看,每個狀態應該從循環緩衝區中讀取適當的字節數,然後進入下一個狀態。這聽起來像數據狀態處理函數必須足夠聰明才能計算適當的數據字節數。如果必須解釋某些數據才能確定數據長度,那麼您可能需要考慮將READ_DATA狀態分爲兩種狀態,一種用於讀取足夠的數據以讀取其餘數據。

在設計狀態處理程序函數時,請考慮可能尚未將相應數量的字節接收到循環緩衝區中。從低級視圖看,當沒有足夠的字節可用時,狀態處理程序應該返回到主循環。這允許主循環在ISR接收更多字節的同時爲應用程序的其他部分提供服務。然後當你的主循環再次調用狀態機時,狀態處理程序應該從中斷處繼續。

0

假設你有一個協議,其中數據包的大小是任意的,但它們有一些可以識別的模式。對於一些識別技術,請參閱下文,首先閱讀過程。

  • 中斷:它只是加載字節到循環緩衝器,遞增寫指針(和推動所述讀指針當緩衝器是滿的,所以它丟棄字節以稍微清潔的方式)。

  • 主程序:輪詢緩衝區。它從當前讀指針開始,尋找是否可以識別數據包。如果找不到任何東西,它會嘗試從讀取指針+1中搜索,直到覆蓋緩衝區。讀指針保持不變(這很重要)。如果一個數據包可以被識別,它會處理它,然後(只有這樣)纔會在數據包的結尾處設置讀指針,從而丟棄它在循環緩衝區中的內容。

當沒有數據包可以被識別時,爲什麼不改變讀指針是很重要的?由於隨着更多字節的流入,更大的數據包可能會在稍後完成。

當緩衝區滿了垃圾時,因此中斷正在推出讀指針,您可能會遇到危險,這取決於您如何謹慎設計IT與主線程之間的交互。通常在任何合理理智的實現中,這裏不應該有太多問題。 IT中的推進行爲比通過寫指針傳遞讀指針(因此間接丟棄整個緩衝區)更加一致。

通常這種方法適用於任何事情。一旦我遇到了這樣一種情況:我的數據包類型中包含了一個較小的協議數據包。現在,這是討厭的修復,以獲得外包這些案件! (上面的算法會獲取內部數據包,因爲它可能更早到達)

10那麼識別呢?

  • 如果您有任何可識別的頭,同步字節或什麼的,這是比較容易得到的開頭(你可以快速關閉保釋如果從給定的開始在緩衝區偏移它看起來並不像一個正確的標題)。

  • 您可能需要在識別(當然在主程序中)中進行部分處理以確定數據包的長度。最簡單的,如果有任何直接的長度指示,但沒有它,如果有一個包類型標識(這意味着一個長度,這似乎是你的情況),這沒什麼更難。

  • 如果有任何校驗和或CRC,檢測數據包也是一件好事。即使複雜的標題看起來是正確的,也可以將其用作標識的一部分:如果它存在正確,那麼您肯定有一個有效的數據包。

  • 如果根本沒有校驗和或CRC,請使用數據包所具有的任何固定位,或協議對數據包內某些值施加的任何固定範圍,以查看它們是否與有效數據包匹配。

使用這些原則我能得到周圍相當失事協議正確,我的意思是它假定包之間的延遲幾乎沒有任何框架之類的東西,延誤作爲分隔符,這不復存在後的數據通過旅行因特網和/或由運行操作系統的PC取得(在操作系統環境中,中斷和循環緩衝區被OS自己的緩衝機制取代,檢測數據包的原理是相同的)。