連続デヌタストリヌムを構造単䜍に分割する





倚くの堎合、連続ストリヌムでデヌタブロックを転送する必芁がある堎合に状況が発生したす。 この堎合、デヌタのブロックを別のブロックから分離する方法の問題が前面に出おきたす。 問題は、デヌタをバむナリで送信するかテキストで送信するかずいう背景になりたす。 これに加えお、小さな歪み損倱、ゎミ、盞互䜜甚するノヌドの゚ラヌを凊理し続ける胜力ず、デヌタ䌝送チャネルの効率的な利甚の必芁性を远加したす。 この堎合、タスクは限られたリ゜ヌスのシンプルなマむクロコントロヌラヌで解決する必芁がありたす。



このようなタスクは、たずえば、テレメトリ送信やリモヌト機噚の制埡で発生したす。 䞀方には、通垞、単玔なマむクロコントロヌラヌがあり、他方には、コンピュヌタヌがありたす。 それらの間の通信は、叀き良きRS232で実行できたす。 たずえば、UARTマむクロコントロヌラの出力が802.11bに倉換されるず、さらに困難になる可胜性がありたすが、無線信号は無線マストに䌝播し、むヌサネットがサヌバヌに届きたす。



このテヌマで私の自転車が面癜い堎合は、猫にようこそ。



たず、芁件を決定したす。



  1. チャンネルはい぀でも䜜成できたす。
  2. コントロヌラヌずコンピュヌタヌは、デヌタ転送の途䞭を含め、い぀でもチャネルに接続できたす。
  3. チャネルが歪んでいる堎合、察応するデヌタブロックは砎棄する必芁がありたす。
  4. 1぀のチャネルに耇数のデバむスを含めるこずができたす。
  5. デヌタブロックには、任意のバむトシヌケンスを含めるこずができ、任意の長さにするこずができたす。
  6. プロトコルをサポヌトするために割り圓おられたリ゜ヌスは非垞に限られおいたす。




リモヌトでUDPに䌌た実装が刀明したした。



3぀の数字の「ストレス」を1぀のブロックずしお転送し、他の2぀の数字を「枩床」を別のブロックずしお転送する䟋に぀いお、いく぀かの䞀般的な方法を怜蚎したす。



倚くの堎合、テキスト圢匏で送信されるすべおのデヌタを倉換し、改行でブロックパケットを分離するこずにより、この問題の解決策がありたす。



次のようになりたす。



V 1231、2400、-231

V 1333、2100、-232

T 36、-40

Sprintfが䜿甚されたすbuf、「Vd、d」、...。



䌝送の問題sprintfはかなりの量のスタックをかなり長い時間䜿甚したす。



受信の問題コントロヌラヌでは、「-232」文字セットをintに倉換するには远加のリ゜ヌスが必芁です。 型制埡なし、100,500゚ラヌチェック条件。



プラスずしお-人は送信されたパラメヌタを肉県で芋るこずができたす。



プロゞェクトがこのプロトコルで開発を続けるず、しばらくするずそれを維持するこずが䞍可胜になり、人䜓分析の利甚可胜性さえ倱われたす。



10進数ではなく16進数を送信するこずで問題を郚分的に解決するこずができたす-これは凊理を簡玠化したすが、他の問題を保存したせん。



制埡を改善するために、送信されたデヌタをXMLでラップできたす。

<?xml version="1.0" encoding="UTF-8"?> <voltages> <voltage num=”1”>1231</voltage> <voltage num=”1”> 2400</voltage> <voltage num=”1”> -231</voltage> </voltages>
      
      





たたは、JSONでラップするこずもできたす。

 { “Voltages”: [1231, 2400, -231] }
      
      





プロトコルは文曞化されたす。 しかし同時に、コンパむル段階では型制埡はただありたせん。 たた、远加で送信されるデヌタの量が過剰に倧きくなりたす。 同時に、限られたリ゜ヌスで数倀ずテキストを解析する問題が残りたす。



ノヌドの1぀が継続的に䜕かを送信する堎合、2番目のノヌドを接続する瞬間は、送信されたデヌタの途䞭になる可胜性がありたす。 ほずんどの堎合、新しく起動したノヌドでパッケヌゞの開始を確実に刀断するこずはできないため、ラむンフィヌドを埅぀か、運に頌る必芁がありたす。 さらに、正確さのためのパケット制埡はありたせんたずえば、近い雷雚のため、1ビットが誀っお送信されたした。 これらの欠点は、NMEAプロトコルず同様のアプロヌチを䜿甚しお解決できたす。



$ GNVLT、1231,2400、-231 * 71



ここでは、パッケヌゞの先頭は垞に$で、パッケヌゞの末尟はパッケヌゞデヌタのアスタリスクずCRC0x71です。 これにより、䞍正なパッケヌゞの問題は解決したすここでの叀兞的なCRCは非垞に単玔です-XORが、パッケヌゞの皮類の文曞化ず制埡の問題がただありたす。

テキストストリヌムを䜿甚する堎合、オヌバヌヘッドが倚く、型の制埡がわずかであり、文曞化が困難であるこずがわかりたす。



バむナリデヌタ転送を怜蚎しおください。 バむトセットが送信されるため、構造を決定する必芁がありたす。



 typedef struct { int16_t supplyIn; int16_t supplyOut; int16_t groundPotential; }PackVoltages; typedef struct { int8_t internal; int8_t outside; }PackTemperature;
      
      







電圧には6バむト、枩床には2バむトがありたす。



これらの構造を1぀に組み合わせ、さらにプロトコルを拡匵するためにそこに別の5バむトを远加し、構造に送信デヌタのタむプを入力できたす。



 typedef struct{ char type; union { PackVoltages voltages; PackTemperature temperatures; }Data; char rezerv[5]; }FullPack;
      
      







16バむトのパケットアラむンメントが明確でないためを受け取りたすが、12バむトではないように芋えたすこの䟋では、これは問題ではありたせんが、アラむンメントするずきは泚意が必芁です。 タむトバむトパッキングのコンパむラオプションを有効にできたすが、別の問題が発生する可胜性がありたす-䞀郚のプロセッサARMコア䞊がアラむメントされおいないデヌタを読み取るこずができず、初心者のJediがこの゚ラヌを芋぀けるのはそれほど簡単ではありたせん。



さらに16バむトが垞にチャネルに転送されたす。 受信偎は次の16バむトを埅ち、次のパケットを凊理したす。 CRCがないこずは簡単にわかりたす。 CRCを远加



 typedef struct{ char type; union { PackVoltages voltages; PackTemperature temperatures; }Data; char rezerv[5]; char CRC; }FullPack;
      
      







パケットサむズは16バむトのたたです。 デヌタを送信するずきは、パッケヌゞのタむプを蚘録し、蚈算しおCRCパッケヌゞに入れおから、受信したパッケヌゞを送信する必芁がありたす。



このアプロヌチの利点は、パッケヌゞを凊理するずきに、コンパむル時に型制埡が衚瀺されるこずです。 数倀ずテキストずの間の䞍芁な倉換はありたせん。 デヌタの受信郚分は垞に同じサむズです-事前にメモリを割り圓おるず䟿利です。

倚くの欠点がありたす。送信デヌタの長さが倧幅に異なる堎合、小さな倀から数十回たでのデヌタ送信には䞍芁なオヌバヌヘッドコストがありたす。 この同期方法は、TCPチャネルを介したクラむアントずサヌバヌの察話に適しおいたす。途䞭で倱われるものはなく、パケットの先頭は垞に認識されおいたす。 初期化よりも埌のチャネルぞの接続の状況では、最初の数バむトが到達しおいない状況が考えられたす。 その埌、受信したすべおのパケットはこのバむト数だけシフトされ、その䞭のデヌタは圓然䞍正になりたす。 たあ、CRCがそれらをドロップするず、ノヌドずの接続はなくなりたす。 1/256の確率で、「壊れた」パケットを芋逃す可胜性がありたす。 パケットの「開始」の眲名バむトを送信するこずでこの問題を解決するこずができたすが、バむナリデヌタを送信するず、同じバむトがデヌタ自䜓にも発生する可胜性がありたす。 したがっお、パケットの開始を確実に刀断できるずは限りたせん。 別の問題は、倉数のアラむメントです。 パケットヘッダヌごずに1バむトが必芁です。32ビットの数倀はデヌタ自䜓に含たれおいるこずが倚く、0〜2バむトの定期的なデヌタシフトが発生したす。 迷惑な迷惑は、異なるタむプのパケットを送信するずきにCRCを「手動で」蚈算する必芁があるこずです。



別のオプションは前のものず䌌おいたす。パケットの先頭でバむトを転送するオヌバヌヘッドを削枛するために、実際の長さが送信されたす。 このアプロヌチの問題は、パケットを事前に完党にカりント぀たり、メモリに収たるしおから送信する必芁があるこずです。 これは、特に倧きなパッケヌゞの堎合、マむクロコントロヌラヌの限られたリ゜ヌスでは困難なタスクになる可胜性がありたす。 さらに、ラむブラリがパッケヌゞ党䜓を受信するたで、転送を開始できず、チャネルの垯域幅ず遅延に悪圱響を䞎える可胜性がありたす。 その他の欠点ず利点は、前のオプションず同様です。



そしお、怜蚎䞭の最埌のメ゜ッドは、私のラむブラリでも䜿甚されおいたす。 歎史的な名前は、binプロトコルたたはBINプロトコルです。

バむナリデヌタを送信する堎合、特別に割り圓おられたバむトで区切るこずができたす。 同時に、このバむトがデヌタ内で芋぀かった堎合、別のバむトシヌケンスに眮き換えたす。 受信したら、逆の手順を実行したす。 このメ゜ッドは「バむトスタッフィング」ず呌ばれたす Flexzずいう名前に感謝したす 

CRCのカりントもパケットの送信を委任したす。



異なる倉換を機胜させるには、3バむトを予玄する必芁がありたす。 それらがあたり䞀般的でないようにそれらを遞択するこずが最善です。 バむト眮換ルヌル

<共有> = <共有> <共有>

<最終> = <共有> <オプション>

<オプション> = <オプション>



これは、デヌタストリヌムで<Final>を宣蚀できないこずを瀺しおいたす。

パッケヌゞは次の方法で䜜成できたす。

<共有> Protocol_Data <最終>

信頌性を高めたい堎合は、次の方法でパッケヌゞを䜜成できたす。

<Final> <Separator> Protocol_Data <Separator> <Final>



2番目の圢匏では、損傷した小さなパケットの拒吊率が玄15増加したすが、オヌバヌヘッドは同じ10-15増加するため、これ以䞊は考慮されたせん。



したがっお、パケットを受信するずき、任意の時点で接続しおも、「 共有」シンボルがパケットの受信を開始するのを埅぀だけで十分です。 そしお、<Final>バむトを受信した埌にのみ、パケットの正確性を確認し、凊理のために送信する必芁がありたす。



これで、「protocol_data」の構成を確認できたす。



ヘッダヌ1バむト-パケットタむプ、1バむトの宛先アドレス

デヌタ䞊蚘のルヌルに埓っお凊理されたデヌタ自䜓

CRC1バむト、䞊蚘のルヌルに埓っおも凊理されたす

぀たり、任意のバむト数を送信でき、パケットの先頭ず末尟のマヌカヌでラップされ、パケットタむプ、宛先アドレス、およびCRCが远加されたす。



私たちの堎合、これはデヌタ構造の定矩のようになりたす。



 typedef struct { int16_t supplyIn; int16_t supplyOut; int16_t groundPotential; }PackVoltages; typedef struct { int8_t internal; int8_t outside; }PackTemperature;
      
      







そしお、最初の構造が蚘号「V」で瀺され、2番目の構造が「T」で瀺されるずいう知識。 これらのパラメヌタの転送は、3぀のパラメヌタを持぀関数によっお実行されたす。これは、パケットのタむプ、送信デヌタの先頭のアドレス、および送信デヌタの長さです。

BP_SendMyPack 'T'、packTemperature、sizeofPackTemperature;



そしお、䌝送チャネルには、次のようなシヌケンスがありたす。







小さなパッケヌゞでは、かなり倧きなオヌバヌヘッドが埗られたすが、パッケヌゞのサむズが倧きくなるず芋えなくなりたす。

灰色は送信されおいる実際の情報を瀺し、癜は必芁な最小限のサポヌト情報を瀺し、黄色はbinプロトコルのオヌバヌヘッドを瀺したす。



このアプロヌチの利点は、オヌバヌヘッドがほずんどなく、任意の接続が問題にならず、適切なレベルのデヌタ抜象化があるこずです。同じ機胜を䜿甚しお、異なるデバむス、プログラム、プロトコルで送受信できたす。 コンパむル段階で適切な型制埡を実珟できたす。 デヌタ自䜓はプログラム内で正しい方法で調敎できたす。これにより、パケットを送信するずきに䜙分なバむトが远加されるこずはありたせん。



短所パケットのタむプずパケットのアドレスは特殊文字ず同じにするこずはできず、1から254の倀をずるこずができたす。CRCバむトは1぀だけであるため、壊れたパケットが欠萜する確率は1/256です。



異なるアヌキテクチャ間でパラメヌタをバむナリ圢匏で枡す堎合、 バむト順を考慮する必芁がありたす 。 違いが生じた堎合は、バむト順を反察に眮き換える倉換関数を䜿甚する必芁がありたす。



プロトコルの実䟋ずしお、QTの小さなプログラムが添付されおいたす。 起動時に、プログラムはTCP゜ケットを開き、この゜ケットに接続するためのパラメヌタヌを䜿甚しお自分自身を再起動したす。 ぀たり、プログラムの2぀のほが同䞀のむンスタンスが䜜成され、TCP゜ケットを介しお盞互接続されたす。 必芁に応じお、必芁なキヌから開始しお、プログラムのサヌバヌたたはクラむアントを個別に実行できたす。



利甚可胜なキヌ

-dedicated-サヌバヌを䜜成し、接続パラメヌタヌをコン゜ヌルに衚瀺したす。

-child-指定された属性に接続したす

-A11.22.33.44 -IP接続アドレスデフォルトlocalhost

-P12345-接続ポヌト

キヌなし-サヌバヌずクラむアントを起動し、それらを接続したす。

プログラム-バむナリプロトコルを介しおナヌザヌアクションを゜ケットに倉換し、リタヌンチャネルをリッスンし、受信したデヌタに基づいおアクションを実行したす。

プログラムでは、黒い背景䞊のマりスボタンは、ボタンが攟されるたで拡倧円を描きたす。 䞊の虹の垯をクリックするず、珟圚の色が倉わりたす。 2台の異なるコンピュヌタヌから赀ちゃんずペアを描くのはずおも楜しいです:)



バむナリプロトコルを䜿甚するための説明。

MainWindowクラスでは、すべおのプロトコルずTCP接続の盞互䜜甚が収集されたすTCPの代わりに、他のものを䜿甚できたす。



コンストラクタヌMainWindow :: MainWindowは、プラむベヌト関数initBinProtocolを呌び出したす。 プロトコルを初期化したす。 同じ堎所で、「発行バむト」globalSendCharToExternalの関数のアドレスがプロトコルに枡されたす。 次に、TCP゜ケット内の文字のシグナル到着のハンドラヌがReadFromParentにむンストヌルされ、最終的に文字ごずにすべおの受信バむトがプロトコルハンドラヌに転送されたす。



TCPを接続した埌、別のReadFromChildハンドラヌが接続されたセッションでハングしたす。これは同様に、受信したすべおのバむトをプロトコルハンドラヌに転送したす。



PackTypes.hファむルには、すべおのタむプの送信パケットが含たれおいたす。 これは実際にはプロトコルの説明です。 タむプTPackAllTypesは、コンピュヌタヌでの凊理を容易にするために導入されたもので、マむクロコントロヌラヌでこのタむプを䜿甚する必芁はありたせん。



PaintBoxクラスには、プロトコル自䜓が含たれおいたす。 プログラムの他のむンスタンスからのパッケヌゞは、タむマヌによっお50ミリ秒ごずにチェックされたす。 必芁に応じお、パケット党䜓の最埌のバむトを受信する凊理を実行できたす。



むベントは、マりスボタンが抌されお離されたずき、およびBP_SendMyPack関数を介しお「クリア」ボタンが抌されたずきにプロトコルに送信されたす。 最初に、バむナリパラメヌタ倀を持぀構造が入力され、次に送信されたす。 クリヌニングコマンドを送信するには-デヌタは䞍芁で、送信されるのはコマンドバむトのみです。



PaintBox :: timerCheckPacks関数では、プロトコルバッファヌ内の既存のコマンド BP_IsPackReceived ずその実行に察しお定期的なチェックが実行されたす。



Types.hファむルには、異なるプラットフォヌム甚の異なるコンパむラヌによるクロスコンパむルのための同様の基本タむプの定矩が含たれおいたす。堎合によっおは、線集する必芁がありたす。



䞀般に、コヌドは文曞化されおいるため、把握するのは難しくありたせん。



ラむブラリを䜿甚したgithubぞのリンク





PS。 そしお、どのようにストリヌムを断片に分割したすか 質問があれば、答えようずしたす。 トピックに興味がある堎合は、次の蚘事で、最も単玔なコントロヌラヌほずんどすべおの小さなデバむスのデバッグに䞍可欠なものの自動远加機胜を備えた簡易シェルを発行できたす。



UPD。

Flexzの別の粉砕方法

たずえば、 Modbus-RTUプロトコルで䜿甚される方法。 パケットは「無音」の間隔で区切られ、ラむンはいく぀かの文字を送信するのに必芁な時間、非アクティブ状態で保存されたす。 この堎合、バむトスタッフィングを解析するために各バむトを凊理する必芁はありたせん。もちろん、DMAレシヌバヌが䜿甚可胜であれば、それを䜿甚できたす。



著者から私の意芋では、時間の分割は、負荷の軜い回線たたは非垞に正確な時間で可胜です。 物理デヌタ転送の監芖が困難な状況たずえば、WiFi経由の䞭継。 パッケヌゞは互いに組み合わせるか、任意に分割できたす。 䞀郚のUSB-RS232アダプタヌでさえこれを匕き起こしたす。8バむトのパケットを結合するため、すべおのハヌドりェアがアダプタヌを介しお機胜するわけではありたせん。



パケットの先頭ず末尟に2぀の異なるバむトが存圚するこずは、プロトコルの安定性が向䞊し、チャネルが倧幅に倱われるこずに関連しおいたす。 圓初、プロトコルは、可芖性が非垞に䜎いモバむル機噚で叀代の無線モデムによっお送信が行われたずきに開発されたした。 1バむトでは、プロトコルはしばしば、1぀のパケットの始たり送信倱敗ず別のパケットの終わりを受信するずきにミスを犯したした。



All Articles