AirH"フォン(AH-J3003)をLinuxで遊ぶ 2005.2.23

     昨年よりアステルのPHSが使えなくなり、その代わりとしてDDI-Pocket(現在はWillcom)のAirH"フォン、AH-J3003Sを使用しております。このPHSは、電話帳機能やインターネットアクセス機能が充実しており、モバイル単体として使うには十分です。

     また、PCと組み合わせて使う場合にも、WindowsやMacに対しては、デバイスドライバーやファイル転送ユーティリティ、電話帳ソフト(H"問屋)などが無償で提供されており十分満足の行く製品となっています。

     ところが、やはりというかLinuxで使うとなると、とたんに八方ふさがりです。どのドライバーを使えば、AH-J3003をUSBシリアルデバイスとして認識させることができるのか、など一切の情報がありません。またLinux上からも電話帳データをメンテナンスしたり出来ると便利ですが、そのようなプログラムがメーカやWillcomから提供されるはずがありません。

     アステルが事業撤退し、NTTドコモのPHS事業も先行き不透明となれば残るのはWillcomの一社だけです。これからの選択肢はWillcomのPHSのみということになります。となれば、ここはなんとしてもLinuxで使える方法を探っておく必要がありそうです。

     というようなことから、今回独自にこの辺りの解析を行いました。その結果、一定の成果を見ることが出来ましたので、以下にレポートします。なお、ここに記述した内容は、全て独自の解析結果に基づくものであり、メーカやWillcomが保証しているものではありません。また、誤りや解釈間違いがあるかも知れません。本内容に関して、メーカやWillcomには絶対に問い合わせをしないでください。

    1 調査環境
      Linux
        Plamo 4.01 kernel version 2.4.27
     
       AirH" Phone
       JRC AH-J3003S ROM Version 1.50 2004/12/08
    
      ROMバージョンの相違、異機種では、本調査内容に合致しないかも知れません。
    

    2 USBドライバ
     ■ genericドライバを試して見る .....動きません

       AH-J3003をLinuxで使うためには、まず最初にUSBシリアルデバイスとしてカーネルに認識させることが必要です。

       ともかく、USBの基本ドライバーを
       # insmod usbcore
       # insmod usb-uhci
       # insmod usb-uhoi
      
      として insmod で読み込んだ後、PCのUSBポートにAH-J3003を接続し、dmesgでUSBドライバの吐き出すメッセージを読み取ります。
       # dmesg
       hub.c: new USB device 00:1f.2-2, assigned address 3
       usb.c: USB device 3 (vend/prod 0x1145/0x1) is not claimed by any active driver.
      
       メッセージの中のVendor ID, Product IDを見ると 0x1145 ,0x1であることが分かります。そこで、  
       # modprobe usbserial vendor=0x1145 product=0x1
      
      として、genericドライバーをロードして見ます。
       # dmesg
       usb.c: registered new driver serial
       usbserial.c: USB Serial support registered for Generic
       usbserial.c: Generic converter detected
       usbserial.c: Generic device with no bulk out, not allowed.
       usbserial.c: Generic converter detected
       usbserial.c: Generic converter now attached to ttyUSB0 (or usb/tts/0 for devfs)
       usbserial.c: USB Serial Driver core v1.4 
      
       dmesgで結果を見ると問題なくロードされ、デバイスファイルは、/dev/usb/ttyUSB0 に アタッチされたことが分かります。

       次に、cuコマンドを使って
       # cu -l /dev/usb/ttyUSB0 
      

      として、ATコマンドを入力して見ますがうまく動作しません。どうも専用のドライバが必要なようです。


     ■ acmドライバで動作させる .......動きました

       AH-J3003のUSBシリアルを構成するハードウェアチップのメーカ名などが分かれば何か掴めるかも知れません。まずは、Vendorコード 0x1145 がどこのメーカに割り当てられたものなのかネットで調べて見ました。当方の調査能力不足でしょうか、残念ながらこれからは何も情報を得ることが出来ませんでした。

       次に、JRCから提供されているWindows用のドライバーファイルから何か手がかりになりそうなものが無いか調べて見ました。Win98_Me用のUSB PORT用の定義ファイル「JRCUSBCDC.INF」 の中に、

      [3COMUSB]
      CopyFiles=USB.Drvrs,USB.VxD
      AddReg=3COMUSB.AddReg
      
      のような記述が発見できました。メーカー3Comに関連がありそうです。そこで、LinuxのUSBドライバーに、3Com関連のものがあるのかどうか調べて見ました。
       # cd /usr/src/linux/Documentation/usb
       # grep 3Com *
       CREDITS:        - 3Com GmbH for donating a ISDN Pro TA and supporting me
       acm.txt:        3Com OfficeConnect 56k
       acm.txt:        3Com Voice FaxModem Pro
       acm.txt:        3Com Sportster
       acm.txt:        3Com USR ISDN Pro TA
       acm.txt:S:  Manufacturer=3Com Inc.
       acm.txt:S:  Product=3Com U.S. Robotics Pro ISDN TA
       acm.txt:Manufacturer: 3Com Inc.
       acm.txt:Product: 3Com U.S. Robotics Pro ISDN TA
      
      どうやら、acmドライバーが3Comに関係ありそうです。試しに、
       # modprobe acm
      
      として、ドライバーを読み込みます。dmesg で結果を見てみます。
       # dmesg
       usb.c: registered new driver acm
       ttyACM0: USB ACM device
       acm.c: v0.21:USB Abstract Control Model driver for USB modems and ISDN adapters
      
       問題は発生していないようです。デバイスファイルは、/dev/usb/ttyACM0 にアタッチされています。
       次に、cuコマンドを使って
       # cu -l /dev/usb/ttyACM0 
      
      として、ATコマンドを入力して見ます。こちらではうまく動作しました。この結果から、acm ドライバでAH-J3003をUSBシリアルデバイス(モデム)として使用できることが分かりました。

    3 ファイル転送モード

     Windowsでは、JRCから提供されているファイル転送ユーティリティを使うと、AH-J3003に画像ファイルを書き込んだり、AH-J3003から電話帳データを読み出したり、書き込んだりが簡単に出来ます。これはどうやって実現されているのでしょうか、特別なATコマンドでもあるのでしょうか?

       ATコマンドを使うコマンドモードでは、PHSとバイナリデータを交互にやり取りすることは出来ません。そのためAH-J3003ではバイナリデータを転送するための専用のファイル転送モードが組み込まれています。

       このファイル転送モードは、2階層のプロトコルで構成されています。ATコマンドでは、ATで始まる文字列データがそのまま送信されましたが(いわゆる無手順)、ファイル転送モードでは、ATコマンドと同様、文字列からなる転送指示コマンド(FT_START[...]<CR><LF>)やそれに対する応答レスポンス(OK<CR><LF>)などが、バイナリデータを転送可能なもう一段下位のプロトコル階層でブロック転送されます。具体的な動きは下記のとおりとなります。

       コマンドモードからファイル転送モードへ移行するには、PC側からPHSに<ENQ(&H05)>を送信します。PHSからは、モードの移行完了を示す<ACK(&H06)>を返します。

       ここからは、PC側、PHS側どちらからでもデータを送信できる状態になります。どちらからデータの送信を開始するかは、上位のファイル転送プロトコルの仕様に基づきます。通常は、PC側から転送指示コマンドを送信することとなります。

       PC、PHSどちら側でも同じですが、送信データは1024バイト毎のブロックに分割して送信します。ブロックの構成は次のようになります。1024バイトのデータを送信する場合には、<STX(&H02)><LENGTH><DATA><CRC>となり、1024バイト未満のデータを送信する場合には<ETX(&H03)><LENGTH><DATA><CRC>となります。

       <LENGTH>は、2バイトのビッグインディアンで、<DATA>部分のバイト数を表わします。<STX>で始まるブロックでは、常に &H0400となり、1024バイトを示します。<DATA>部分は、ファイル転送指示コマンドであったり、応答レスポンスであったり、ファイルそのもののバイナリデータであったりします。通常、コマンドやレスポンスは短いので<ETX>ブロックのみの転送となります。

       <CRC>は、XMODEM/YMODEMなどと同様のCRC計算を使っています。CRCの演算対象は、<DATA>部分のみです。

       <STX>や<ETX>で始まるデータブロックを受信した側は、受信完了を示す<ACK>を返送します。大きなサイズのデータがブロック分割されて送信されてきた場合、受信側は、<ETX>で始まる最後のブロックを受信した後に、<ACK>を返します。途中で返送することはありません。

       最後に、ファイル転送モードからコマンドモードに戻るために、PC側から<EOT(&H04)>を送信し、PHS側から<ACK>を返して、ファイル転送モードを終了します。


     次に、上位のファイル転送プロトコルについて説明します。

       FT_START[<暗証番号>]<CR><LF>
        ファイル転送の開始をPCからPHSに要求します。
        暗証番号(4桁数字)には、PHS側に設定されている番号と同じ値をセットします。
        PHSからは、OK<CR><LF>を返送します。

       GET_LIST<CR><LF>
        PHSに格納されているファイルの一覧を送信するようPCからPHSに要求します。
        PHSは、OK<CR><LF>を返送した後、続けて、ファイルの一覧を送信します。
        PCは、ファイルの一覧を受信したら、OK<CR><LF>をPHSに返送します。

       GET_FILE[<ファイル名>]<CR><LF>
        ファイルの内容を送信するようにPCからPHSに要求します。
        ファイル名には、GET_LISTで取得したファイル一覧の中のファイル名をセットします。
        PHSは、OK<CR><LF>を返送した後、続けて、要求されたファイルの内容を送信します。
        要求されたファイルが存在しない場合には、REJ<CR><LF>を返送します。
        PCは、ファイルの受信を完了したらOK<CR><LF>を返送します。

       DEL[<ファイル名>]<CR><LF>
        ファイルを削除するようにPCからPHSに要求します。
        ファイル名には、GET_LISTで取得したファイル一覧の中のファイル名をセットします。
        PHSは、ファイルを削除した後、OK<CR><LF>を返送します。
        要求されたファイルが存在しない場合には、REJ<CR><LF>を返送します。

       PUT_FILE[<ファイル名> ,<ファイルサイズ> ,<00--- ハイフン30個 ------> ]<CR><LF>
        PC側のファイルの内容をPHSに送信し、PHSに書き込みを要求します。
        ファイル名には、PC側のファイル名とそのサイズを指定します。
        PHSは、OK<CR><LF>を返送した後、続けて、ファイルの内容を受信します。
        取扱不可能なファイルの場合には、REJ<CR><LF>を返送します。
        PHSは、ファイルの受信ならびに書き込みを完了したらOK<CR><LF>を返送します。

       FT_END<CR><LF>
        PCからファイル転送を終了することをPHSに要求します。
        PHSは、OK<CR><LF>を返送します。

    4 サンプルプログラム

     以上の解析結果を基に、コマンドベースのファイル転送ユーティリティを作成してみました。
    ソースファイルは次のとおりです。

    	Makefile
    	xn_xx.h
    	xn_xx.c	 USBシリアルデバイス通信処理プログラム
    	block.c ブロック転送処理プログラム
    	ahjut.c ファイル転送ユーティリティ
    
    	ahjut.tgz 上記一括
    
     コンパイルと操作方法ですが、上記ソースファイルを一つのディレクトリに格納し、makeコマンドを投入します。
     make で出来る ahjut が実行ファイルです。使い方は、次のとおりです。
     	ahjut [-l ttydevice] [-d 1|2]
    
     l オプションで、AH-J3003が接続されているUSBのttyデバイスファイルを指定します。省略時は、/dev/usb/ttyACM0となります。
     d オプションで、デバッグ表示を行います。1を指定するとファイル転送の上位プロトコルの実行内容を表示します。2を指定すると、上位プロトコルの内容表示にくわえて下位のブロック転送プロトコルの内容もヘキサダンプします。

     ./ahjutとコマンド入力し、ユーティリティを起動すると、以下の表示がでます。
    	ATZ
    	OK
    	ATE0
    	OK
    	************** File Transfer Start *****************
    	FT>
    
    
     この後、対話式にファイルの一覧表示、読み出し、書き込み、削除の操作ができます。終わる場合には、end を入力します。操作コマンドは、次のとおりです。
    	FT> list               PHSにあるファイルの一覧を表示します。
    	FT> ls                 PCのカレントディレクトリのファイル一覧を表示します。
    	FT> get ファイル名     PHSからファイルを読み出します。
    	FT> del ファイル名     PHSのファイルを削除します。
    	FT> put ファイル名     PCにあるファイルをPHSに書き込みます。
    	FT> end                プログラムを終了します。
    


    5 その他
    ■ 上位転送プロトコルシーケンス例
      PC側         PHS側            
                                             
      →→ FT_START[0000]<cr><lf>           
      ←← OK<cr><lf>     
                                              
      →→ GET_LIST<cr><lf> 
      ←← OK<cr><lf>     
      ←← #pic000001#540.jpg .. <cr><lf> 
      ←← MT000             ... <cr><lf> 
           ......
      →→ OK<cr><lf>       
      
      →→ GET_FILE[#1pic000001#540.jpg]<cr><lf>
      ←← OK<cr><lf>     
      ←← <file block>   
      →→ OK<cr><lf>       
      
      →→ FT_END<cr><lf>   
      ←← OK<cr><lf>    
      
      
    ■ 下位転送プロトコルシーケンス例
      PC側     PHS側
      →→   05    ENQ 転送モードの移行
      ←←   06    ACK
      
      →→ 03001046545F53544152545B303030305D0D0A1594    ETX,LENGTH=16,DATA="FT_START[0000],cr,lf",CRC=&h1594
      ←←   06                                          ACK
      ←← 0300044F4B0D0A8038                            ETX,LENGTH=4,DATA="OK,cr,lf",CRC=&H8038
      →→   06                                          ACK
      
      →→ 03000A4745545F4C4953540D0A819A                ETX,LENGTH=10,DATA="GET_LIST,cr,lf",CRC=&h819A
      ←←   06                                          ACK
      ←← 0300044F4B0D0A8038                            ETX,LENGTH=4,DATA="OK,cr,lf",CRC=&H8038
      →→   06                                          ACK
      ←← 02040023706963303030303123353430...           STX,LENGTH=1024,DATA="#pic000001#540... 
           ..............2D2D2D96C5                                ...... ---",CRC=&h96C5
      ←← 0300BD2D2D2D2D2D2D2D2D2D2D2D2D2D...           ETX,LENGTH=189,DATA="--------------...
           ....2D2D2D2C0D0A0D0A0CE0                                ..----,cr,lf,cr,lf",CRC=&h0CE0
      →→   06                                          ACK
      
      →→   04    EOT 転送モードの終了
      ←←   06    ACK