ではその「柔軟な対応」の中身は? ということであるが、Hostの側は実は以外に単純である。Isochronous INの場合、
・CRC-32が一致しない
・DPPがAbort
・DPPが無い
・DPHに格納されたData lengthと、実際に送受信したPayload lengthが一致しない
といったケースでDP Errorとなるわけだが、この場合は短に受け取ったDPPを破棄して終りである。逆にIsochronous OUTの場合、そもそもエラー処理がない(何しろ自身が送り出す訳だし、結果がDeviceから返ってくるわけでもないので、意図的にエラーが混じったパケットを送出でもしない限りエラー検出は出来ないからだ)。もっともエラーでない(つまり正常に受信した)場合にはすぐその内容を処理する必要がある訳で、特に8DP Burstの場合にはそれなりのバッファを用意しないとすぐ溢れてしまうから注意が必要である。
逆にDevice側は? ということだが、まずIsochronous INの場合、Hostから最後にACK TPが返ってくる。このACK TPがInvalidの場合、仮にまだ送信すべきDPがあったとしても、そこで処理は中断である。Validであった場合は、もうDPが残ってなければ0 LenghtのDPを、残っていればそのDPを送り出す手順を取ることになる。
逆にIsochronous OUTの場合はもう少し面倒である。やはり受信したDP毎に、
・CRC-32が一致しない
・DPPがAbort
・DPPが無い
・DPHに格納されたData lengthと、実際に送受信したPayload lengthが一致しない
のチェックを行う。ここでエラーがあった場合は、素直にデータを捨てて受信終了であり、逆にエラーがなく、Sequence Numberが合っており、かつDeviceがデータ受信可能な状態ならば、それを受け取る事になる。ただそれ以外のケースもあり、
・エラーは無く、Sequence Numberも合っているが、Deviceが受信不能 : 受信データを破棄
・エラーは無いが、Sequence Numberが合っていない : Deviceが受信可能か否かに関わらず、受信データを破棄。更に、同一Service Interval内でこれ以降にやってくる全てのDPを破棄
といった対応が求められる。
ここでちょっと考えるべきは、そうなると「では最終的にIsochronousでデータの受信成功/失敗はどこで決まるか」という話で、これは言うまでも無くLPFがセットされた最終パケットまで受信できてからという事になる。Isochrnous IN/OUTはエラーがあると、「それ以降」のデータは破棄されるが、エラーが発生するまでに受信した分についてはノータッチであり、遡って破棄するような機能は勿論要求されていない。勿論これはあくまでもSpecificationでは定義していないという話だし、モノによっては例えば途中までのデータであっても困らない(例えばAudio OutをIsochronous OUTで実装していて、あるService Interval内の転送が丁度真ん中あたりで切れたとする場合、そのService Intervalの分をまるまる落とすと無音期間が長くなってしまう。ところが半分まででもそのまま出力すれば、無音期間がずっと少なくなることになる)からだ。
もっとも、このあたりはドライバなどの造りかたしだいでどうにでもなる部分である。Device側にしても、このあたりをスクラッチから作りこんでいれば、Isochrnous OUTの場合でもDP毎にBuffer出力されるか、あるいは全DPの受信後にまとめてBuffer出力されるかが選べるだろうが、IPで購入したものを組み込むなどという場合は、このあたりがどうなるかは微妙なところだ。Host側にしても、特定のHost Controllerに特化した作りこみが許されれば別だが、WindowsとかUnixの環境では複数種類のHost Controllerが混在する可能性があるから、特定のHost Controller向けのコードは書きにくいだろう。なので、安全策としてはドライバあるいは上位のアプリケーションの側で一度Bufferingして、全データ揃ったところで処理あるいは破棄を判断する形にするのが無難ではなかろうか。
もっともパフォーマンスを考えた場合、実はDPの受信毎にそれを出力というのは、かなりクリティカルである。例えばDPのサイズが1個1KBだとする。USB 2.0の場合、単純に考えてもDPの転送には17μsほど掛かる計算になる。実際はプロトコルオーバーヘッドもあるし、半二重通信なのでそちらのオーバーヘッドもあるから20μs程度の間隔でドライバからアプリケーションにDP受信の割り込みが掛かる計算だ。まぁこれは32bitのMCUならば、それほどクリティカルな数字ではない。が、USB 3.0ではこれが2μs程度になる。今度は通信も全二重だし、プロトコルオーバーヘッドも相対的に小さいから、これが3μsになることは期待できない。せいぜいが2.2~2.3μsだろう。こうなると、Device側にしてもUSBの通信専用に結構高速な32bit MCUを専用で貼り付けておかないと取りこぼしがでるだろうし、Host側にしても、この間隔で割り込みが入ったらシステム全体の負荷にそれなりの影響を及ぼすだろう。なので、やはり全DPを受け取る(or途中でエラーを検出して打ち切る)タイミングでまとめてデータが渡されるという実装が一般的ではないか、と筆者は考える。
(続く)