Extreme Java
       @Fantom_JAC
自己紹介
• Java原人
• Java原理主義者
• Javaのためならなんでも
  – ハードウェア設計(回路、PCB等)
  – ハードウェア実装(ホットプレートリフローを
    提唱)
  – サーバーサイド技術(REST/SOAP等)
  – 組み込みJVM
• 無線、特にZigBeeが好き
  – 日本ZigBeeユーザーグループ代表
(Java原人からみた)
        Javaとは
• 小型の組み込み機器等に使われるプラット
  フォーム
• センサーやクレジットカード、ICパスポート
  に組み込まれることが多い
• 最近はパソコンでも動くようになったらしい
• JVMと呼ばれる海のなかで動く
  – OSの上で動くことは稀
  – OSがある時はLinuxが多い
• ARMと仲がいい
• お前にサンは救えない
やった(やりたかった)こと
   これを繋ぎたい
用意された環境
• Javaで直接レジスタが叩ける
• EHCIに準拠したレジスタ群
当初のイメージ


 Java側
   アプリ              ドングル側
              USB
便利なAPI用ドライバ          便利なAPI

                     TCP/IP

                      MAC

                      PHY
突付けられた現実
 Java側
    アプリ

   TCP/IP

    MAC
               USB   ドングル側
                      仕様の分からない
仕様の分からないドライバ
                      不親切なAPI
                     中途半端なMAC

                        PHY
必要なもの
• EHCIドライバ(HCD)
     – 実質OTGドライバも必要だった
•   USBスタック/フレームワーク
•   Ralinkドライバ
•   802.11MACスタック
•   TCP/IPスタック
EHCIとは
•   USB2.0用のコントローラー仕様
•   Intelが作った(んでしたっけ)
•   HCIの一種
•   ちゃんとレジスタの仕様が公開されてるo(^▽^)o
•   3年前のことなので大分忘れてます
用意されたUSB環境
• cHCが存在しない
  – EHCIで1.1も繋がる謎仕様
• 1ポート
• OTGを経由している
  – OTGにはレジスタ仕様の標準がない
コントローラ構成


Global Controller

           OTG Controller


    Device               Host
   Controller          Controller
Global Controller
• GC割り込みがかかるので、フラグを見て
  HC、OTG、DCどの割り込みがかかったのか
  振り分ける
• 特にThreadは用意しない
OTG Controller
• Threadを一本用意してステートマシンを記述
  – Stateが変わる(Parameter入力される)まで
    wait
• GCからOTG割込がかかったら
  – フラグをチェック
  – 独自仕様なので、独断と偏見でOTG仕様の
    Parameterに解釈
  – パラメータ入力して先述のThreadにnotify
• OTG仕様に沿ってState変更
  – やるべきことをやる
  – State変更してまたwaitに戻る
OTG Controller
• b_idle時はid入力以外無視
   – Device Controllerは実装してません
• 小技として・・・
   – State変更時はyieldせずに即座に次のアクショ
     ンをとっている
   – Stateが変更されないとき(orサボって実装して
     ないとき)はwaitする
   – waitは1000msで一応外すようにしている
Host Controller
•   OTGと同じくThread一本でステートマシン
•   GCからの割込でUSBSTSをチェック
•   起動時はIdle状態
•   OTGからのReset要求でポートリセット
     – ポートリセット出来ないのでHC再起動
• PORTSCでポート検知、OTGにb_conn入力
• Asynchronous ListとPeriodic Frame Listを準
  備
• AsyncListに初期QHを突っ込む
Asynchronous List
• QHとQTDを管理
• やってることは普通のEHCI
  – Javaらしく
     • QueueHead#setNextQH(QueueHead qh)
     • QueueElement#fillPayload(byte[], int, int)
  – newできないので自分でメモリ管理
     •   ImmortalHeapで予めたくさんとっておく
     •   #allocAlignedArrayとかできるので便利
     •   分割して、それぞれ先頭のアドレスをPool
     •   Javaらしく
            – QueueHead#newQueueHead
Periodic Frame List
• Isochronousは絶対にやりません
• FSTNもやりません
• QHのスケジュールがめんどくさい
  – 2の冪でないといけない
     • bIntervalが10だったら8とかになる
  – HSの場合更に1/8ms単位でスケジューリングす
    る
  – 帯域オーバーしていないか常にチェックする
  – SplitTransactionの場合はC-Maskも空きがある
    か調べる
Periodic Frame List




 1/8    2/8   4/8   8/8
Periodic Frame List




 1/8    2/8   4/8   8/8
Periodic Frame List

          125us x 8 = 1ms

  0   0    0   0   0   0   0   1




  0   0    0   0   0   0   1   0
USBスタック
• JSR-80に(たぶん)準拠
  – TCKは通してません(キリッ
• IBMの作ったRIを使用
• RIで足りないハード依存部を実装
  – Device Enumeration等
• EHCIと合わせて概ね快調に動作
squilla-jsr80
• JSR-80をOSGiに対応させた
• JSR-80ではドライバやデバイスの管理は規定
  されていない
  – OSGiのDeviceManagentに対応
  – UsbDeviceDriverを継承するだけで簡単ドライ
    バ開発
• HubドライバやMSD(BulkOnly)ドライバを同
  梱
• ひっそりオープンソースで公開
Ralink
• その界隈ではあまりにも有名
• RT2860/3070を使用
  – 一番安かった
  – 隣のビックカメラにたくさん売ってた
• FreeBSD用非公式ドライバを大部分移植
  – 公式でLinuxドライバがあるが・・・
• 1Mbpsのみ対応
  – 気合と根性と納期が足りなかった
• WEPのみ対応
  – 気合とは・・・根性とは・・・
• STAのみ対応
Ralinkの公式ドライバ
Ralink IO
• Ralink共通(?)のAPIセット
• たぶんUSB以外のインターフェースでも共通
    – APIのインターフェース実装さえ変えれば他の
      インターフェースにも対応?
• public interface RTIO
    – public class USBIO implements RTIO
• USBの実装はControl転送を使用
    – Vendor Request
• read32とかwrite8とか
    – たぶんMCUのレジスタとお話してる
Ralinkの謎
• 起動時にファームウェアをまるごと転送
  – 普通フラッシュに書かれてるのでは・・・
  – 転送がよくコケる
• 膨大な量の定数
  – 改造すれば普通に電波法やぶれそう
  – メモリいじってパッチを当てている疑惑
• 怪しいノード管理
  – wcid = associationId & 0xFF
• ControlFrameだけ実装されているぽい
  – リアルタイム性の問題?
Ralink系チップ想像図



Interface    8051
  MCU        MCU

                     Radio


            EEPROM
squilla-net
• Javaでプロトコルスタックを書くためのライ
  ブラリを作った
• 各種フレームの生成
   – 802.11、TCP/IP、ARP、802.3・・・
• 802.11関連多し
   – ManagementFrame
   – MLME
   – Javaに欠けているWLAN用API
      • Androidにはあるのに・・・(ボソ
      • (↑大分参考にした)
• ひっそりオープンソースで公開
MLME
• 最低限のリクエストのみ実装
  – SCAN
  – JOIN
  – AUTHENTICATE
  – ASSOCIATE
• JOINがよくわからない
  – 特にRalinkの場合、自動でやっている気がする
  – JOINって名前が紛らわしい
802.11+Ralink
• じぶんでもびっくりするくらい動いた
  – SSIDがちゃんとスキャンできた日は興奮が収ま
    りませんでした
TCP/IPスタック

TCPConnectionManager        UDPConnectionManager




                 IPv4Service       ARPService



送受信FIFO+Thread          EthernetService



       EthernetConnection   ・・・           EthernetConnection
IPv4
•   適当
•   たぶんもっとまじめに実装しなきゃいけない
•   フラグメント未対応
•   受診時チェックサム計算省略
     – 少しでもパフォーマンスが上がると思った
       の・・・
• 特にThreadなし
ARP
• RequestおよびReply監視用Thread一本
• IPv4側からRequest発行可能
   – waitし、Reply到着後Threadからnotifyされるま
     で待機
• 一方的なReplyが来ても、テーブルになければ
  一応登録
• Requestされたときは、そのまま同一Thread
  上で返信
   – もう一本Thread置くか迷った
UDP
• 簡単
• Thread未使用




   UDPConnection    ・・・       UDPConnection




              UDPConnectionManager
TCP
• 1人に聞いた!もう二度と実装したくないプロ
  トコルスタック堂々の第一位
• なんでこんなプロトコルが30年以上まともに
  動いているのかまったく不明
• 不可解な輻輳制御
• 理不尽な仕様書
• ひどい相性問題 TCPConnection
                           ・・・
                        TCPConnection




                   TCPConnectionManager
TCP
•   Slow-startもCongestion avoidanceもなし
•   Fast Recoveryなんてムリムリ
•   Fast Retransmitだけやった
•   輻輳制御なんてむりだお・・・
•   TCPConnection毎にThread一本
      – 頑張って再送まで含めて一本におさめた
• Connectionは頻繁に開閉するので専用の
  ThreadPoolを作成
TCPConnection概要

InputStream                   OutputStream




BufferedPipe                  BufferedPipe
(Ring Buffer)                 (Ring Buffer)




 TCPInput                      TCPOutput



                                        ThreadPoolより割当
                                        られた専用Thread
              TCPConnection
基本動作
• 基本はステートマシン
• tickと呼ばれるMethodを無限ループで呼び続
  ける
  – 3Dゲーム開発でよくやる手法
• tickされた時に・・・
  – 受信FIFOに溜まっていれば取り出して
    TCPInputに投げ、処理
  – なければTCPInputにて、ACK可能であるか判断
    し、可能であれば送信
  – 最後に再送タイムアウトが発生したかチェック
    し、必要であれば再送
     • タイムスタンプと現在時刻で判断
なぜSingle-Threadか
• 当初はマルチスレッドにする予定だった
  – タイムアウトタイマー用Thread
  – 送信受信それぞれにThread一本づつ
• GCが使えないので管理が大変
  – GCより高いプライオリティで動いている
• プログラムのミスを起こしやすい
  – 同期を取るのが大変
• リソースを消費する
• tickが空回りしないように何もないときは
  50ms程度sleepする
BufferedPipe
• スライディングウィンドウ実現のために作っ
  たクラス
• 内部はリングバッファ
• 非同期に可変長のバイト列を入れる
• 非同期に可変長のバイト列を取り出す
• つまり、両端がInputStream/OutputStream


     InputStream            OutputStream
BufferedPipe
• 探したけど意外とこういうクラスはなかった
• 元々TCP向けなので、入出力個別にシャット
  ダウン可能
  – 例えば入力を切ると出力側でEOF
• 意外とTCP以外の場面でも活躍する
• read()するとちゃんとブロックする
• 便利なのでひっそりとオープンソースで公開
  – squilla-commons
残酷な現実
• やっぱりどうしてTCPはまともに動かない
  – UDPはTCPに比べたらまとも
• 相性がひどい
  – 同じWindowsでもパソコン変えただけで通信で
    きたりできなかったり
  – Mac相手だとやたら不安定だったり
• 簡単なSocket通信だと良いけど
  – HELLOとか
• HTTPとか載せた瞬間に激不安定
スクラッチから実装することの意義
• 勉強になる
  – 百聞は一コーディングにしかず
• デバッグが容易
  – 腐っても自分の書いたコード
• ライセンス問題ゼロ
• 話のネタになる
わかったこと
• Linuxはすごい(いろんな意味で)
  – EHCIのコードの雑さ
  – ネット周りのスパゲティさ
  – よくこれで動いてるな
• FreeBSDは読みやすい
  – 特にネットスタック
• IEEEの仕様書は非常に親切で読みやすい
• IETFの仕様書は非常に不親切で読みにくい
そもそもの経緯
• ギョウムで必要でした
• 半年強で実装しました
• 結局使われませんでした
今後
• 眠ってても仕方ないのでオープンソース化?
  – 欲しい人いるの?
• JavaMEがCortex-M向けに出るらしいので
  – 利用価値が出てくるかも
• 使い道募集中
Special Thanks
• @naobsd氏
• @tawakemono氏
• 802.11関連で助けて下さいました
宣伝
• squilla
     – http://code.google.com/p/squilla/
• Jazzkaffe
     – http://code.google.com/p/jazzkaffe/
• Japan ZigBee User Group
     – http://jzug.org/

20apr2012 kernelvm7-main