(注意)このブログは本家のほうの文章部分のみの転載です.ソースコードの配布,画像などについては本家のほうを参照してください.文章中のリンク先は面倒なのですべて本家のほうに変換してしまっているのでご注意ください.

前回でシリアル送受信ができるようになったのだけど,次はシリアル経由でのファイル転送ができるようにしたい.で,ファイル転送用の独自プロトコルを作るか適当な既存のプロトコルを実装するかだが,まあ独自プロトコルにしてしまうと送信アプリを書く必要が出てきてしまい,さらにその送信用アプリをLinuxでコンパイルして使うにはとかWindowsから使うにはどうすればいいかとかいった話になってしまって,それはそれでとっつきづらいと思うので,適当な既存のプロトコルを実装することにする.

で,プロトコルなのだけど,XMODEMというのが簡単そうなのでそれにしよう.まあXMODEMならLinuxとかWindowsとかでもいっぱい送信用アプリがあるだろうし.(WindowsならたぶんTeraTermでファイル転送できるだろうと思う)

ちなみにXMODEMにはファイルの終端が Ctrl-Z で終ってしまっている場合にそれを検出できないという問題があるようだが,実行形式ファイルのお尻がわからないだけで,実行形式ファイルの展開という意味ではとくに問題は無い.(実行形式は内部に独自にヘッダ情報を持っていて,それを見てメモリ上に別途展開するので,終端に余計なものが付いていても別に問題ない)

XMODEMについては,以下が参考になる.他にも改良版のYMODEMとかZMODEMとかあるらしいが,まあ転送するファイルのサイズもそれほど大きくはならないだろうから転送効率とかあんまし考えなくていいし,エラー時再送とかきちんとしなくても(信頼性が低くても)もう一度やりなおすだけだし,とりあえず実装が一番楽そうなXMODEMを実装する.

で,上のホームページを見て実装したのがこんなかんじ.

xmodem.c というファイルを追加してあってその中でファイル受信しているのだけど,xmodem.c はなんとたったの89行.うーん,簡単なプロトコルなので楽でいいのう.ちなみにファイルの転送先なのだけど,とりあえず loadbuf[] というバッファを適当なサイズで定義して,そこにそのままコピーするようにしてある.まあ対して難しいプログラムではないので,詳しくはソースを見てちょうだい.(現状,Cファイルとヘッダファイルだけで400行程度なので,十分に読み切れると思う)

あと細かいところをいろいろ修正してある.
  • H8の書籍とかちゃんと読んで,シリアルの送受信処理を見直し.とくに受信時にSSRのRDRFを落とす処理を追加.(これをやっていなかったので,連続して受信したときに読み出しデータがおかしなことになっていた)
  • リンカスクリプトを,もうちょっと修正.(MEMORYコマンドにより,ROM領域とRAM領域を明示的に定義するようにした.これにより,ROMやRAMのサイズ不足で溢れたときにはリンカがエラーにしてくれるようになる)
  • XMODEMでファイル受信するコマンドとして,loadコマンドを追加.あと受信したファイルの内容チェックのために dump コマンドを追加.
  • ライブラリ関数とかをこまごまと修正.
で,ビルドしてフラッシュROMに焼いて実行してみる.フラッシュROMへの転送のしかたは第1回を参照.

ちなみにフラッシュROMへの転送なのだけど,以下の手順で電源のOFF/ON無しでできるようだ.
  • フラッシュROMへの書き込み
    1. ディップスイッチを左からON,ON,OFF,ONにする.
    2. cuで接続している場合は,抜ける.(これをやらないとh8writeが動作できない)
    3. リセットボタンを押す.(電源OFF/ONは不要)
    4. h8writeで書き込む.
  • 書き込んだプログラムの起動
    1. ディップスイッチを左からON,OFF,ON,OFFにする.
    2. cuで接続する.
    3. リセットボタンを押す.(電源OFF/ONは不要)
    4. 実行が開始される.
上のような感じで,ディップスイッチを切替えてリセットボタンを押すだけで,電源のOFF/ON無しでフラッシュへの書き込みとプログラムの実行を繰り返すことができる.

で,以下,実行結果.

teapot# cu -l /dev/cuad0
Connected
Hello World!
>

cuでつないでからリセットボタンを押して起動すると,まず Hello World が表示される.

ここでXMODEMでのファイル受信用の「load」コマンドを実行する.

> load

コマンド実行すると,XMODEMでの受信待ちに入る.

で,FreeBSD側からのXMODEMでのファイル転送なのだけど,PowerPCのときも使った「lrzsz」を使う.インストールされていない場合はまずインストールする.(FreeBSDでは packages になっているので,パッケージインストールできます)

で,ファイル転送なのだけど,cuは「~C」を入力することで別コマンドを fork してその入出力を繋げることができるので,その機能を利用して lrzsz にXMODEMプロトコルをしゃべってもらってファイル転送する.まあ手っ取り早く言うと,loadコマンド実行後に,まず「~」「C」のようにキーボードから入力する.

> load
~CLocal command?

「Local command?」のように実行するコマンドを聞いてくる.lrzszでは,「lsx」というコマンドがXMODEMのためのコマンドなので,lsxを指定する.さらに,送信するファイルを引数として指定する.ここでは a.txt という適当なテキストファイルを作成して指定してみる.

> load
~CLocal command? lsx a.txt

ちなみにa.txtの内容は以下の通り.ほんとてきとう.

abcdefg
hijklmn

これで Enter を押すと,ファイル転送が開始される.

> load
~CLocal command? lsx a.txt
Sending a, 0 blocks: Give your local XMODEM receive command now.
Bytes Sent: 128 BPS:142

Transfer complete
eceive succeeded.

ちなみにWindowsとかだとXMODEMでファイル転送するためのアプリがきっといっぱいあるだろうから,それを使えばいいだろう.その場合,転送プロトコルは「XMODEM」で,転送ブロックサイズは128バイト,チェックサムは1バイト(8ビット)の単なる加算のもの(CRCチェックサムではない)を指定する.正式には「XMODEM/SUM」というらしい.(「XMODEM/CRC」とか「XMODEM/1k」だとダメなので注意)

ファイルが転送できたら,dumpコマンドでファイルの内容を確認してみる.

> dump
size: 128
61 62 63 64 65 66 67 0a 68 69 6a 6b 6c 6d 6e 0a
1a 1a 1a 1a 1a 1a 1a 1a 1a 1a 1a 1a 1a 1a 1a 1a
1a 1a 1a 1a 1a 1a 1a 1a 1a 1a 1a 1a 1a 1a 1a 1a
1a 1a 1a 1a 1a 1a 1a 1a 1a 1a 1a 1a 1a 1a 1a 1a
1a 1a 1a 1a 1a 1a 1a 1a 1a 1a 1a 1a 1a 1a 1a 1a
1a 1a 1a 1a 1a 1a 1a 1a 1a 1a 1a 1a 1a 1a 1a 1a
1a 1a 1a 1a 1a 1a 1a 1a 1a 1a 1a 1a 1a 1a 1a 1a
1a 1a 1a 1a 1a 1a 1a 1a 1a 1a 1a 1a 1a 1a 1a 1a

>

a.txtの内容がばっちり書き込まれている.(128バイト単位で,お尻はCtrl-Zで埋められる)

今回は実は最初はぜんぜんうまく動作しなかったのだけど,シリアルの受信処理に問題があっておかしなデータが受信されていたのが原因で,そこを直したらXMODEMの処理自体はあっさりと動いた.うーん楽でいいねえ.

これでシリアルからのコマンドを受け付けて,XMODEMでファイル転送できるようになった.なんかモニタっぽくなってきたね.次は実際にプログラムを転送して,動作できるようにしたい.オブジェクトファイルフォーマットを何にしようかなあ...やっぱしELFかなあ...