本日は強風で会社を早退したので,たまっていたKOZOSネタを一気に書いてしまおう.
実は別件でTFTP対応というのを進めている.で,実装してみて思ったのだけど, TFTPが次回の書籍ネタとして必要かなと思っている.
というのは次回作ではオブジェクトの動的リンクというのをやりたいと思っていて, まあいわゆるモジュールローディングなのだけど,そのためにはオブジェクトファイル をなんらかの方法で転送する必要がある.いちばん手っ取り早いのはXMODEMなのだけど KOZOSのXMODEMはそのまま流用しようとするとタスク処理とあまり相性がよくなくて, タスクベースの動作に書きなおす必要が出てしまいちょい面倒.
次に考えられるのはTCP/IPプロトコルスタックを利用したFTPでの転送だけど, TCP/IPの安定性が疑問なのとFTPは2ポート利用するのでモジュール転送だけのために 実装するのはそれはそれで面倒.
さらに考えられるのはもうファイル転送を考えず前もってフラッシュに書き込んで おくとかブートローダーでのOSロードの際にモジュールも(いっしょにかもしくは 別々に)ロードするとかだけど,これだとなんだかモジュールの動的ロードの インパクトが少なくてさびしい.
で,TFTPを実装してみて,これってモジュール転送の方法としていいのではないかと 思った.UDPで簡単に実装できるし,IPスタックも利用するのでネットワーク機能にも 実用的意味が出てくるし.
ということでTFTPを実装した.内容はあまり難しくなくてまずはUDPタスクを新たに 実装する.で,そのUDPタスクに依頼してUDP通信するような感じでTFTPタスクを 実装した.TFTPのプロトコルは簡単だしネットで検索するといくつか出てくるので 省略.まあ,ネットで拾った情報とwiresharkのキャプチャを見て適当に実装した 感じ.
今回はUDPとTFTPの実装として udp.c と tftp.c を追加したが, それ以外にも以下を修正してある.
まず各タスクの kz_recv() の箇所でポインタ関連のワーニングが出てしまうので (void *)にキャストする修正.
さらに netdrv.c と rtl8019.c で割り込み回りの修正を行う.というのは 送信割り込みの処理にタイミング的問題があって,どうやら送信割り込みを ラッチできていなくて受信のタイミングでようやく次の送信処理が行われる, という現象が発生していた.
いろいろ見てみたら netdrv_intr() の割り込み処理で,受信&送信割り込みの 処理の後に rtl8019_intr_clear() を読んでいたので,割り込み処理中に別割り込みが 発生してしまうと割り込みクリアされてその割り込みを取りこぼすような気がしたので クリア処理を先に行うように修正したらうまく動いた(これだと割り込み処理中の 割り込み発生時に,空割り込みが発生する可能性がある気がするが実害は無いし 取りこぼしよりははるかにマシだろう).これで送信処理がグッと安定する.
あとやはり netdrv.c のパケット送信処理で,送信割り込みを有効化してから 送信処理しないとやはり送信割り込みがとりこぼされてしまうかも?と思って この順番も修正. あと TCP_CMD_RECV がipタスクからtcpタスクへの受信処理とtcpタスクから 他タスクへの受信処理の両方に利用されていた.これらは別物なので本来分離なので, ipタスクのほうはTCP_CMD_IPRECV というのを新設してそっちを利用するように 修正する.
で動作だが,起動して「tftp」というコマンドを叩くと 192.168.10.1 に対して 「kozos」というファイルを取りに行くので,tftpサーバをてきとうに動作させて kozosというファイルを置いておくと転送されるのがwiresharkで確認できた. tftp.cのバッファサイズを16KBにしてあるので,ファイルサイズはそれ以下に すること.FreeBSDならば /tftpboot を作成して kozos というファイルを置いて, あとは /etc/inetd.conf でtftpdを有効化して inetd を kill -HUP すればよい.
ちなみに今回実装した udp.c は239行,tftp.c は175行だ.リンカスクリプトや Makefileも含めたOSの現在のソースコード量は5926行.TCP/IP,webサーバ, TFTP転送までできてもこの程度の分量だ.