文字間のギャップを減らすために、tty termios APIから100ms未満のVTIMEを取得するには、カーネルパッチを見つけるのに役立ちます。 VTIMEがタイムアウトするまで読み取りシステム呼び出しをブロックします。
n_tty_read() 関数はパッチエントリポイントです。 https://elixir.bootlin.com/linux/latest/source/drivers/tty/n_tty.c#L2131
誰でも私にアドバイスを与えることができますか?非正規モード(フレームプロトコルなし、ASCIIなし、割り込みなし)を使用する必要があります。すべてのメッセージ長が可変であるため、VMINパラメーターは空です。すべての文字をポーリングするソリューションは、複数のuartシステムに比べて高価であり、複数のプロセスコンテキスト切り替えを意味します。
用語抽出ガイド:VTIMEタイムアウト10分の1秒非正規読み取りの場合(時間)。https://man7.org/linux/man-pages/man3/termios.3.html
Linuxカーネルパッチが必要です。または、グローバルHZを小さい値に設定しますか?
Microsoft WindowsシリアルAPIは1msで設定できますが、Linuxは設定できません。したがって、Windows はネイティブシリアルポートの処理に適しています。 読み取り間隔のタイムアウト:https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/ntddser/ns-ntddser-_serial_timeouts
レビューからの抜粋「非標準モードで...4095文字のみ許可されています。「私の考えにはここに問題があるようです。おそらくread_waitキューが目覚めない理由です。
https://elixir.bootlin.com/linux/latest/source/drivers/tty/n_tty.c#L1667
答え1
tty termios APIから100ms未満のVTIMEを取得するには、カーネルパッチを見つけるのに役立ちます。
Linuxカーネルパッチが必要です...
これらのカーネルパッチはユーザー空間APIを変更するので賢明ではありません。 Linuxは一貫したAPIを維持しようとし、要求されたパッチによって既存のアプリケーションがクラッシュする可能性があります。
これらのカーネルパッチがAPIを変更しなくても、信頼性が低く、明示されていない目標を達成する可能性はありません。時間で区切られたメッセージを検出するために、VMINおよびVTIME設定にのみ依存する必要はありません。
UARTがFIFOを使用して着信データをバッファリングすると、ハードウェアバッファはソフトウェアが検出できる文字間隔をマスクします。同様に、UARTドライバがDMAを使用して受信したデータを保存すると、文字間タイミングがマスクされます。
termios は、UART デバイスドライバの上の少なくとも全体のレイヤーを処理します。 termios レイヤーは、UART とそのドライバーがバイトを処理/バッファした後、ライン上で同じタイミング情報を見ることはできません。
Microsoft WindowsシリアルAPIは1msで設定できますが、Linuxは設定できません。したがって、Windows はネイティブシリアルポートの処理に適しています。
Windowsがアプリケーションに適していると思われる場合は、Windowsを使用する必要があります。ただし、広告されたコンテンツが必ずしもあなたが得るものではないことに注意してください。 Windows APIはただ開示するタイムアウト仕様(ミリ秒)正確。だからといって、実際にこのようなものが得られるという意味ではありません。正確さ。たとえば、次の警告があります。
タイムアウト間隔はシステムクロックに基づいて測定されます。タイムアウト測定の精度は、システムクロックの粒度によって制限されます。。したがって、指定されたタイムアウト間隔より速い1つのシステムクロック周期と1つのシステムクロック周期の間でタイムアウトが発生する可能性があります。、システムクロックサイクル間の間隔の開始時間と終了時間が正確にどこに属するかによって異なります。後でタイムアウトが発生する可能性があります。他装置の割り込み処理によりシステムクロック割り込み処理が遅れる場合。指定されたタイムアウト間隔がシステムクロックティック間の期間に近いか短い場合タイムアウトは遅延なしですぐに発生する可能性があります。。
私の考えの問題はここにあるようです。おそらくこれがread_waitキューが目覚めない理由です。
いいえ、あなたは間違った場所を見つけようとします。
私が以前に申し上げようとしていたように(参考としてこの投稿)、安定したソリューションにはアイドルUART受信機を検出するタイマーが必要です。ただし、UARTハードウェアがリスナータイムアウトを実装していても(私が検討した2つのLinuxドライバでは)、この機能は現在/アクティブDMA操作を中断するためにのみ使用されます。
受信機のタイムアウトは時間分離メッセージの終わりを検出する可能性があるため、UARTドライバが受信したデータを転送するときにこのイベント/情報をtermios層に転送する必要があります。これはVMIN > 0
、元のモードの新しいバリエーションについてtermiosに必要な欠落情報ですVTIME > 0
。この新しいバリエーションでは、UARTドライバはtermiosが文字間タイムアウトを確認するのではなく、受信したデータでタイムアウトイベントを表示する必要があります。
これは単なるカーネルパッチではありません。
答え2
幸いなことに、私はいくつかの説明を見つけ、私たちは次のような状況に直面したと結論付けました。API が廃止されましたこれは、過度のCPU消費によってバイパスされる可能性があることを意味します。
VTIMEタイムアウト粒度は次のとおりです。歴史的に定義されたバイト間間隔の単位です(POSIXではVTIME = 100msを定義します)。現在Linuxで使用されているバイト間隔は依然としてシリアルラインに対応しています。110ボーレート(110)。ただし、今日115200ボードのシリアルラインを使用している場合、1バイトのTX期間は約100μs(マイクロ秒)です。
Alan Cox: RE: termios VMIN ANDVTIMEアクション
非常に明確に定義されています。ブロックシリアル演算(uucpなど)を最適化するように設計されています。
VMIN - このパケットに予想されるバイト数 VTIME - 待機を放棄するタイミング
形式0、VTIMEは、選択/ポーリングなしで古いSYSVをポーリングするためにも使用されます。
POSIX 2007 6月§11.1.7非正規モード入力処理
非正規モード入力処理では、入力バイトがラインにアセンブルされず、削除および終了処理は発生しません。 c_cc配列のMINおよびTIMEメンバー値は、受信したバイトの処理方法を決定するために使用されます。 POSIX.1-200x は、O_NONBLOCK 設定が MIN または TIME 設定より優先されるかどうかを指定しません。したがって、O_NONBLOCKが設定されている場合、MINまたはTIMEの設定に関係なく、read()がすぐに返されることがあります。また、read() は、使用可能なデータがない場合は 0 を返し、errno が [EAGAIN] に設定されている場合は -1 を返すことができます。 MINは、read()関数が正常に返されたときに受信する必要がある最小バイト数を示します。TIMEは0.1秒単位のタイマーで、バーストおよび短期データ転送のタイムアウトに使用されます。MIN が {MAX_INPUT} より大きい場合、要求に対する応答は定義されません。
GNU Cライブラリリファレンスマニュアル、バージョン2.37、§17.4.10非標準入力
マクロ:int VTIMEこれは、c_cc配列のTIMEスロットインデックスです。したがって、termios.c_cc [VTIME]は値自体です。
TIMEスロットは非標準入力モードでのみ意味があります。戻り前の入力を待つ時間を0.1秒単位で指定します。[...]
MINは0ですが、TIMEは0以外の値を持ちます。この場合、読み出しは、入力が使用可能になるまでTIMEの間待機します。単一バイトの可用性だけでも読み取り要求を満たし、読み取りを返すことができます。返されると、要求された数まで使用可能な数の文字が返されます。タイマーが期限切れになる前に使用可能な入力がない場合、読み取りはゼロ値を返します。
- (最小値> 0、時間> 0)。
TIME>0だからインターバイトタイマー最初のデータバイトが受信されるとアクティブになり、各データバイトが受信されるとリセットされます。 MINとTIMEは次のように相互作用します。
- 1バイトのデータを受信すると、インターバイトタイマーが始まります。(タイマーは各バイトが受信された後にリセットされることを忘れないでください。)
- 以前にMINバイトのデータを受信した場合インターバイトタイマーが期限切れ、読み取りが正常に完了しました。
- もしインターバイトタイマーが期限切れ読み取りは、MINバイトのデータが受信されるまで、受信したすべてのバイトを送信します。
TIMEが期限切れになると、読み取りは少なくとも1バイトのデータを送信します。インターバイトタイマーが有効になっています。1バイトのデータを受信した場合にのみ該当します。この状況を使用するプログラムは、続行する前に少なくとも1バイトのデータを読み取るのを待つ必要があります。 (MIN> 0、TIME> 0)の場合、MINおよびTIMEを有効にするためにデータバイトが受信されるか、信号が読み取りを中断するまで読み取りはブロックされます。したがって、読み取りは少なくとも1バイトのデータを送信します。
[...]
- (最小=0、時間>0)。
MIN=0なので、TIMEはバイト間タイマーとして機能しなくなりました。しかし、現在、読み取りが処理されたときにアクティブになる読み取りタイマー(Canonで)として使用されます。データバイトが受信されるか、読み出しタイマーが期限切れになるとすぐに、読み取りは正常に完了します。読み出しタイマーの有効期限が切れると、読み出しはデータバイトを転送しません。読み取りタイマーが期限切れになっていない場合、一部のデータバイトが受信された場合にのみ読み取りは正常に完了します。 (MIN = 0、TIME> 0)の場合、読み取りはデータバイトを待って無期限にブロックされません。読み取り開始後にTIME * 0.10秒以内にバイトデータが受信されない場合は、0を返し、読み取りデータがないことを示します。読み出しが開始されたときにバッファにデータが保持されている場合は、すぐにデータを受信したかのように読み出しタイマーが開始されます。 MINとTIMEは、プログラムがTIME間隔後にデータを使用できないと仮定し、データが使用可能になる前に他の処理を完了できる場合に便利です。
答え3
カーネルAPIの互換性を維持するパッチを提案するために、主に可能なオフロードソリューションがあると思います。つまり、CANONモードのVEOFパラメータ値(未使用のunsigned char値)を使用してVTIMEを調整します(前にタイムアウト値を追加)。非CANONモード読み取り機能の場合は、Schedule_timeout機能分割要素))を適用します。
キヤノン以外のモードでは未使用のVEOF値を使用してください。 https://elixir.bootlin.com/linux/latest/source/include/linux/tty.h#L39
これには除算が適用されます。たとえば、VEOF 値がデフォルト値と異なる場合、VTIME タイムアウトの削減が適用されます。 https://elixir.bootlin.com/linux/latest/source/drivers/tty/n_tty.c#L2196