2008年12月22日月曜日

OSX でTCPウインドウ制御

ある種の Firewallと MacOSX  の rfc1323実装の相性が悪いらしく、
職場の環境では大きいファイルのダウンロードをやっているとかならずストールしてしまう。

そんなとき以下のようにすればいいと教わった。
 sudo sysctl -w net.inet.tcp.rfc1323=0

これを毎回打つのもなんだかなーと思っていたら、 
/etc/sysctl.conf というファイルに以下の1行書いておけばいいらしい。

net.inet.tcp.rfc1323=0

実績はリブートしてのお楽しみ。

2008年12月15日月曜日

Gainer の PGA設定

Gainer(というよりPSoCの)PGAの倍率設定は0-15を指定すると、それに対応した倍率になる。
これがまた微妙な間隔で、覚えるのも大変なので覚え書きとして書いておく。
6,10,12 あたりが2x、4x、8xとなって判りやすいのでよく使うと思う。

指定値   倍率        
 0 1.00
 1 1.14
 2 1.33
 3 1.46
 4 1.60
 5 1.78
 6 2.00
 7 2.27
 8 2.67
 9 3.20
10 4.00
11 5.33
12 8.00
13 16.0
14 24.0
15 48.0

2008年11月4日火曜日

gainer-rubyを NetBSDの箱で動かす

gainer-rubyは rubyで作られたgainerのライブラリであり、rubyを知っていれば非常に簡単にgainerを使うことが出来るのが特徴だ。GUIを使った作品作りとは異なるが、本blogでも twitterとgainerをつなげるなどのエントリで活躍している。ruby自体にさまざまなライブラリが豊富なので twitterやIMなどとの連携を行いやすく、グラフィカルなインスタレーションではないような用途では非常に重宝する。

個人的には温度計を接続し、activerecord経由でDBと連携させて一定時間おきにtwitterに投稿するといった使い方をしている。

個人的なgainer-rubyの問題としては NetBSDをいれた小さい箱で動かなかった点がある。これはシリアルポートのtermiosの設定がうまくいっていないようなので、ここを修正することとした。また、ダウンロードできるgainer-rubyのソースには PGAのゲイン調整のコードが入っていないのでこれも追加したものを作ってみた。動作を確認したNetBSDは 4.0R のi386版である。
PGAのほうは作者にも送ってあるので次のバージョンには反映されるかもしれない。

コードの差分をリンクしておくので、試してみたい方はsvnで checkoutした gainer-ruby にあててみてほしい。PGAのゲインコントロール関数は amp_gain_agnd/amp_gain_dgnd でprocessing のライブラリと対応させてある。シリアルポートはtermiosの設定を変更したが、NetBSDの他にOSX(10.5) でも動作することは確認済みである。


これをつかった作品の全容はまた後ほど

2008年10月14日火曜日

ベリーショートなACタップ

テーブルタップのコードがからまるという問題は、古今東西あらゆる現代人が直面している問題のようで、さまざまなツールや解決案が提案されている。また、別のテーブルタップの問題としてはコンセントの口が少ないということがよくあげられる。総計1500Wの3つ口テーブルタップに、昔なら数百ワットを使うテレビやこたつといったものをつなぐのが普通だったのが、最近ではたった100W以下しか使わないゲーム機やパソコンのACアダプタを数多くつなぎたいという要求のほうが多い。

これを解決するには多口のタップを使うのが簡単だが、そう多いものは売られていない。そのため、タップは基本的にたこ足になってしまうのが一般的だが、その場合には長いコードのやり場に困る。

そこで個人的によくやっているのが、タップのコンセントを短く切断してしまう方法だ。とくにオフィスのデスクの下に転がすタップなどはデスクに磁石で取り付けることもあり、あまり長いと邪魔なだけなので、20cmくらいの長さになるようにコードを切断したものを用意している。

高級品のタップの場合にはタップ側を分解するとケーブルがねじ留めされているので、その場合にはねじを外して、コードを短く切り、もう一度ねじ止めする。普通のタップの場合には、ケーブルがハンダ付けされていたり分解できないようなネジや、接着といった方法でとめられていたりするのでその場合にはコンセント側を捨てることにして、新しいコンセントの部品をホームセンターで買ってくればいい。このときにコンセントを90度に曲がるものや回転するものなど、自分のさしたい場所にあわせてやるといいだろう。

写真は筆者のオフィスのテーブルに張り付いているタップである。真ん中が床下から生えてきているタップでそれを左右2つのタップに分岐して使っている。ただでさえ、イーサネットケーブルと電源ケーブルで混乱している机の下だが、このタップのケーブルが3mもある場合とは雲泥の差であるのは判ってもらえるだろう。

既製品を切り刻むのは抵抗があるのだろう。簡単にできる割にあまりやった話を聞かないのだが、自分の足下がおどろくほど快適になるのでぜひ試してみてほしい。

ちなみに切ってしまうと模様替えなどで長いケーブルが必要になると使えないじゃないか!と言う人もいるとおもうが、自分の手元に必要なテーブルタップの口数がかわらない以上は手元まで引っ張るものと手元でバラすものが必要なわけで、大きな問題にならないはずだ。

2008年10月1日水曜日

passenger(mod_rails) でバーチャルホストを使わない複数アプリケーション動作



railsの実行環境としてこの春あたりから話題騒然のpassengerを試してみた。このとき、普通にアプリケーションを立ち上げるのはみんながやっているが複数のアプリケーションをディレクトリで切り替えるというのはあまり見なかったので簡単にまとめておく。

まず、apache + passenger のインストールだが、どこのblogにも書いてあるので省略する。

passengerのための設定までは終了したとして、この後にそれぞれのアプリケーションを動かすための設定を行う。アプリケーションを動かすために設定しないといけない項目はシンボリックリンクを含めると合計4カ所だ。

まず最初にやるべきことはrails のアプリケーションのシンボリックリンクを作ることである。rails アプリケーションそのものが存在するディレクトリはapacheを動かしているユーザで
アクセスできれば、documentrootの中にある必要はないようだ。さすがアプリケーション。

railsアプリの名前が tasklist だとするとtasklistの中のpublic をシンボリックリンクで
Documentroot内の適当な場所にリンクする。だいたいこんな感じになるだろう。

---
cd /WWWROOT/rails/
ln -s /home/name/tasklist/public tasklist
---

次に設定するべきところは railsアプリの routingだ。ここでアプリの中でindexを開いたときに動くべきコントローラが taskであり、最初にアクセスされるべきアクションがindexだとして設定をおこなう。ここでは railsのアプリケーションの中の config/route.rb に以下の行を追加する。

--
map.connect '', :controller => "task", :action => 'index'
--
そして、public内のindex.htmlファイルにアクセスされないように index.htmlを
削除ないし名前変更する必要がある。これをやらないとindex.htmlをアクセスしていつまでたってもアプリケーションにたどり着かないことになってしまう。
これだけの設定でrailsアプリ側の準備ができた。

最後は httpd.confに railsのアプリケーションのrootを伝える設定を書き加える。passenger の設定の下に以下のような行を加えよう。

---
RailsBaseURI /rails/tasklist
---

このあと apacheをリスタートした後ブラウザから、 http://hostname/rails/tasklist とアクセスすると無事にアプリケーションが立ち上がっていることが確認できるだろう。

今回のポイントはこの最後の操作で、 RailsBaseURI の行を増やすと複数のアプリケーションに対応できるということにある。railsアプリを設定し、シンボリックリンクを作り、httpd.confに RailsBaseURIを書き加えれば、同時に複数のアプリケーションを立ち上げることが可能になる点がポイントだ。

以上、簡単だが主に自分でまた半年後にやるときの参考になればとおもい記録しておこう。

2008年7月8日火曜日

gainer clone で「かざぐるま」あるいは PWMによるモーターの駆動 (2)

前回のあらすじ
Gainerモジュールにトランジスタアレイでかざぐるまを駆動することに成功したCUE。
しかし、そのモーターからは脳を直撃する怪音が無限に鳴り響く!

すこし時間があいてしまったが、前回の最後で述べたとおり、怪音をなくすためにはPWMの周波数を変更するのがもっとも一般的かつ効果的な手法である。しかしながらgainerの配布されているファームウェアでは、PGAのゲインはコマンドで変更できてもPWMの周波数は変更できない。ということで、「Gainerのファームウェアを改造してノイズが出ないモータを実現するぞ」プロジェクトを決行した

当方ではファームウェアの不具合について感知しないのはもちろん、ファームウェアの焼き込みサービスも行ってないのであしからず。秋月電子などから PSOC miniProg を手に入れて各自で焼き込んでもらいたい。どのように作業したかは以下のとおりである。


1. ファームウェアの入手
firmware はgainer.cc のページからダウンロードできる。以下のページからファームウェアのソースファイルをダウンロードする。ダウンロードできたらこれを unzipして展開しておく。

2. ファームウェアの展開
ファームウェアはzipなので適当なツールを使って展開する。このとき置き場所は日本語の入っていないディレクトリでなければ、PSoCデザイナでmakeするときに不具合がでることがあるので注意したほうがよい。僕は C:\ に直接展開したフォルダをそのまま移動した。

3. 設定画面をながめる
書き換えポイントを探るためにコンフィグとソースをよく見て考える。
config_a にPWMモジュールが8つ発見できたので、これが出力用のPWMに違いないとあたりをつける。そのときに、PWMのクロックをどこからもらってるかを配線からながめると16ビットのカウンタを使ってブロードキャストバスに信号を流し込み、そのバスの信号をクロックとして使っているということがわかった。


その後で、ソースコードをかるく読んでみるとまさしく config-a の PWMモジュールの山がそのままPWMとして出力されることがわかる。これでconfig-a のPWMモジュールのクロックを書き換えるという方針が決定した。




4. 使えそうなクロックを探す
使えそうな clockとして Gainerの生の設定でPSoCモジュールが供給しているのは、24MHzの生クロックのほかこれを分周して作っている VC1,2,3 のそれぞれさらに専用のcounterにより作りだされているもともとのPWMの信号がある。それぞれのクロックはどれくらいの周期かというとPWMでは 256クロックで1周期ということなのでCPUCLK 24MHz が およそ 100KHzとなるがこれはすこし早すぎるようだ。

VC1は 24/3 = 8MHz VC2は 8/4 = 2MHz であり、これをさらに 1/256したものが周波数になる。よって VC1でおよそ 32KHz VC2では 8KHz となる。超音波領域に突入することが目標なので、 VC1のほうを採用することとした。

これをそのまま PWMのクロックに入れればいいのだが8つある設定を書き換えるのは大変なので大本となっている PWM用のカウンタであるCounter16に入力することにした。

このままでは counter16のソースが 8MHzとなったはいいがカウンタをつかってさらにスピードを落としているので、それをカウントしている部分を探すこれはソースコードのほうで発見した。
クロックの比は 1:1 なので226行目(あたり)のところの Counter16_A_PWMClk_WritePeriod(0); を 0に書き換える。これで毎回カウントアップのたびにCounterがあふれているはずだ。
実際のところcounter16など使わなくても、直接配線をVC1に変更しまくればそれでもOKなのだが、その場合には書き換えるポイントが8つになってしまうので、間違い等があると大変である。そこで今回はCounterはそのまま使って、そのカウンタの周期を修正したのである。修正ポイントのコードは以下のとおりである。

--ここから
// start analog outputs
// Counter16_A_PWMClk_WritePeriod(157); // 50Hz (i.e. 20ms)
  Counter16_A_PWMClk_WritePeriod(0); // 10KHz (i.e. 1ms)
Counter16_A_PWMClk_WriteCompareValue(0);
Counter16_A_PWMClk_Start();
--ここまで



この2つをやってからbuild を行う。今回はHitechC のフリー版つかってmakeを行った。Gainer自体はもともとimage-craftのコンパイラで作られていたはずだが、何の問題もなくコンパイルもおわったのでこれを miniprogを使って書き込んで完成である。

これで動作させればPWMでモータを駆動させても音がならないGainerが完成である。モータが動かなくなるくらい低いPWM値の場合にモータからの異音がしなくなるのがわかるはずだ。

改変した後のHEXファイルはこちらにおいておく。そのままmini-progで焼き込めば動くはずだ。

2008年6月25日水曜日

gainer clone で「かざぐるま」あるいは PWMによるモーターの駆動

Gainerは設定にもよるが 4ないし8本のアナログ出力(PWM)を使うことが出来る。前に作成した power gainer は電源にもよるがトランジスタアレイにより小型のモータを回転させるには十分な電力を供給することができる。そこで、前からやってみたかったアンビエントディスプレイである「かざぐるま」を作ってみた。

これは MITのメディアラボで行われているタンジブルコンピューティングの象徴的なアンビエントデバイスの一つである。(詳しくは Media LabのTangible Media Group を参照。) 

使ったのは前に作成したTD62083をワンボードに組み込んだGainer(Power gainer)とタミヤのプーリー基本キットである。これらをささえる土台となっているのは、100円ショップで買ってきたアクリルのメニュー立てだ。プラスチックのプーリーをゴムベルト(ゴムバンド)で回転させるプーリーキットは回転時に音がほとんどしないので、ギアボックスと違い常時動かしておくアンビエントディスプレイに適している。これに、ケント紙で作った風車を両面テープで貼付けてハードウェアのほうは完成である。



gainerのconfiguration3ならばPWM出力が8ch仕様ということで作成した風車のセットを同時に8つコントロールできるが、今回はサンプルということもあり1つの風車だけで満足しておくこととする。8ch同時で動かすにはUSBに寄生するだけではなくターゲットボードにACアダプタ等の外部電源が必要だろう。

このgainerをコントロールするプログラムはまず、テスト用ということで簡単なものを用意した。マウスカーソルを動かすとそれに従ってアナログ値が変化するものだ。これで、ウインドウ上をマウスを左右に動かすだけで回転を変化させることが出来るので動作確認には十分だろう。このプログラムはPWMで動かすデバイスの試験にいつも使っているものでもある。



video
以上のように風車は簡単に動くところまではきたのだが、ひとつ大きな問題が残ってしまった。ほとんど動いていないときもピーピーとモーターから音がする。これは Gainerの PWMの周波数が1KHzであるため、 1KHz周期でモータが振動してしまっている音であり、PWMでモータを動かす場合に起きる現象だ。このノイズを解決するためにはモータを駆動するPWMの周期を25KHz以上に上げる方法がよく使われる。こうなると、モーターの振動音が超音波の領域に入るため人間には聞こえなくなるのである。もちろんノイズがなくなるわけではないので、コウモリやイルカには迷惑なのかもしれないが、そこは気にしないことにして、ファームウェアを改造しPWMの周波数を上げる対策をとることとした。

(つづく)

PWMテスターのソースコードは以下のとおり。

----------
import processing.gainer.*;

Gainer gainer ;


void setup() {
size(500,100) ;
gainer = new Gainer(this) ;
}

void draw() {
int i ;
background(mouseX/4) ;

for ( i = 0; i<500;i+=100) {
stroke(255,0,0) ;
line(i ,0,i,100) ;
}

gainer.analogOutput(1,mouseX/2) ;
stroke(0,0,255);
line(mouseX,0,mouseX,100) ;
println("NOW: " + mouseX/2 + "*" ) ;
}
----------

2008年6月24日火曜日

Processingでtwitterと http認証 (basic auth)

Processingをつかって、httpをしゃべらせることは難しくはない。ただ通信してページを取ってくるだけならば、loadStrings() の引数にURLを指定してやれば、自動的にJavaのURLクラスを使ってStringsの配列として格納できる。これをつかって、twitterのデータを読み込もうとおもったのだが、twitterではbasic authを使わなければ自分のfriends timelineを取り出すことが出来ない。そこで basic authを processingでやってる例をさがしたのだが、発見できなかったので生のjavaでのbasic authの方法をそのまま取り込んで実現してみた。

さまざまなページによると javaでのhttp認証では java.net.authenticator とjava.net.PasswordAuthentication の2つのクラスを使い、Authenticator クラスを継承した認証クラスを作ってハンドラを設定する、というのが正解らしい。つまり、以下のようなコードとなるわけだ。



import java.net.Authenticator;
import java.net.PasswordAuthentication;

//public
class BasicAuth extends java.net.Authenticator{
private String user;
private String pass;
public BasicAuth(String user, String pass)
{
this.user = user;
this.pass = pass;
}

protected PasswordAuthentication getPasswordAuthentication()
{
return new PasswordAuthentication(user,pass.toCharArray());
}
}




このクラスの利用方法は、user名とpasswordを設定して作成したクラスのインスタンスを生成し、そのあとで、Authenticator の setDefaultを呼び出す。前処理としてこの作業を行うと以降の http通信で認証が必要とされる場合には設定した情報をベースに自動的に認証が行われる。これをそのまま、processingに追加して使った。Processingは基本的にjavaそのものなので、このような場合の拡張は非常に簡単ですばらしい。
本当はpackage化してライブラリとするといいのだろうがそれはまた今後の課題ということにしておこう。

さて、現実にtwitterの出力するXMLの解析には、simlpeMLというライブラリを使うことにした。simpleMLはdaniel shiffman(http://www.shiffman.net/) の開発したライブラリであり彼のページからダウンロードできる。loadStrings()を使うよりもよい点は、後で XMLライブラリを使ってエレメントを取り出すよりも簡単なことと thread をつかって非同期にhttpリクエストを発生させて、ページを取得できたときにイベントを発生させることが出来る点である。とくに後者は、一定時間ごとにページを取得して書き換えるような動作を行いたい場合には、非常に有効であろう。

timelineの twitterAPI呼び出しを行うにはBasic認証付きでAPIで定められたURLを呼びだせばよい。受信形式はいろいろ見比べた結果、後処理がもっともやりやすそうなRSS形式を指定した。これらをまとめるとコードは以下のようになる。あとは、数分おきにreloadをするとか、スクロールするとかのフィーチャーを盛り込めば、twitter viewerとしての機能は十分だろう。
ちなみに書き込みは post method が必要なのだが、こちらも processingで使えるモジュールはなさそうなのとすこし複雑な処理が必要そうなのでもう一工夫必要なようなので今後の課題としておこう。
動作させるためには、フォントを作成する必要がある。Processingのメニューから Tools-->Create Fontを選択すると次のような画面が出るので Osakaフォントの16pointを指定する。日本語表示には日本語のフォントも必要なので All Fontのチェックボックスにもチェックをいれておく必要があるだろう。こうやってフォントを作成した後、コードの中の user と pass を自分のものに入れ替えれば動作させてみることができる。



--------------------------------
import simpleML.*;

import java.net.Authenticator;
import java.net.PasswordAuthentication;

// configration
String user = "uname" ;
String pass = "xxxxx" ;

// request url
String url = "http://twitter.com/statuses/friends_timeline.rss" ;

//public
class BasicAuth extends java.net.Authenticator{
private String user;
private String pass;
public BasicAuth(String user, String pass)
{
this.user = user;
this.pass = pass;
}

protected PasswordAuthentication getPasswordAuthentication()
{
return new PasswordAuthentication(user,pass.toCharArray());
}

}


XMLRequest xmlRequest;

void setup() {
size(screen.width/2,screen.height/2);


BasicAuth tw_authenticator = new BasicAuth(user, pass);
Authenticator.setDefault(tw_authenticator);

// Creating and starting the request

xmlRequest = new XMLRequest(this,url);
xmlRequest.makeRequest();
}

void draw() {
// background(frameCount % 255);

}

// When the request is complete
void netEvent(XMLRequest ml) {

PFont fontA = loadFont("Osaka-16.vlw");
textFont(fontA, 16);

// Retrieving an array of all XML elements inside "" tags
String[] titles = ml.getElementArray("title");

for (int i = 0; i < titles.length ; i++) {
println(titles[i].replaceAll("\n",""));
fill(10*i,0,0) ;
text( titles[i].replaceAll("\n",""),5,18*(i+1)) ;
}

}

--------------------------------


ここまで。

2008年5月22日木曜日

戦利品


昨日のTIのセミナーでもらったお土産。
2.4Gの無線つき MSP430のモジュール。たくさんあると
スター型になれるらしいのですが2個入りでした。残念w

2008年5月15日木曜日

Xbeeの開発環境

東京ビックサイトで5/14-16で行われているESEC2008(組込システム開発技術展)にちょっとだけ用事があったので行ってきた。名前の通り、様々な組込系のボードや技術に関係しているベンダーがいろいろな製品やサービスを展示する展示会なんだが、いくつかのブースでは展示&会場限定で即売、みたいな事もやっていることがある。


Digiインターナショナルのブースをみてみたら、Xbeeの開発環境が会場限定で10000円とか書いてあったのでちょっと考えてから買ってしまった。Xbeeのモジュールが5枚と、Xbeeを刺すドーターボードが5枚、電源、ソフトウェアなど一式はいっているお大尽仕様だった。


普段は40000円(300USD)くらい。明日までやっているのでほしい人はいいチャンスかも!

2008年5月13日火曜日

OpenBSDでEmobile D02HWを使う(1)

縁あってOpenBSDの開発者の人たちと一緒にhackする機会があったので、なにかコントリビューションできることはないかなと考えたところ、OpenBSDの3Gモデムのサポートを拡張することにした。
特にD02HWは、本当の名前はE220といって世界各地で使われているメジャーなモデムなので、これがまともに使えるようになるとうれしい人がそれなりにいるだろうから、ちょうど良い。

OpenBSDもNetBSDと同様に、FreeBSD由来のUSBサブシステムを採用しているので、usbデバイスドライバは大きな差異は存在しない。NetBSD用につくったuhmodem(4)をそのまま移植するという手もあったのだけど、OpenBSDにはHSDPAモデム用のドライバとしてumsm(4)がすでに存在していたので、それを拡張する形で実装してみることにした。

umsm(4)(拡張前)
dev/usb/umsm.c(rev.1.21)を眺めてみると、非常にシンプルなドライバになっていた。具体的に言うと、

struct ucom_methods umsm_methods = {
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
};

となっていた。struct ucom_methods は、上位ドライバとなるucom(4)のopen/closeなどの各処理におけるデバイス依存コードへの関数ポインタを渡すための構造体なので、この状態ではシリアルに関する処理はucomでのデフォルト動作だけで実行されることを意味している。

どうしてこれで他のドライバが動作しているのだろうか?と「???」と思いながらざっくりとコードを追ってみたところ、シリアルデバイスのinterrupt endpointに関する処理がざっくりと抜け落ちていることに気がついた。単なるin/out endpointを処理するだけなら、確かにucom(4)における特別な処理は必要ないが、モデムで通信を行う際には自分から始めるだけではなく割り込み処理が必要である。
近くにいたOpenBSD開発者に聞いてみたら「おれが使っているE220で昔だれかが作ったパッチで試した見たところ、たしかにPPPまでは張れることもあるがうまく動かなかった。つながるけど切れたり通信できなかったりしてね。それから使ってない」と言われた。さもありなん、ということでinterrupt endpointの処理を拡張するところから始めることにする。D02HW(E220)以外でも役にたつだろう。

interrupt endpoint処理の追加

endpointの割り当て処理はumsm_attach()の中で行われる。data用のbulk in/out endpointしか処理していなかった部分を、以下のように変更する。また、struct umsm_softcにもinterrupt endpoint周りの状態を保持するための変数を拡張しておく。

if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN &&
UE_GET_XFERTYPE(ed->bmAttributes) == UE_INTERRUPT) {
sc->sc_intr_number = ed->bEndpointAddress;
sc->sc_isize = UGETW(ed->wMaxPacketSize);
DPRINTF(("%s: find interrupt endpoint for %s\n",
__func__, sc->sc_dev.dv_xname));
} else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN &&
UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK)
uca.bulkin = ed->bEndpointAddress;
else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_OUT &&
UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK)
uca.bulkout = ed->bEndpointAddress;


これで、interrupt endpointを持っているinterfaceがあったら、interrupt endpointを正しく扱うための準備ができる。

次に、ucomをopenしたときに検出したinterrupt endpointをucom割り込みとして利用するためのコードを追加しなければならない。まずucomをopenしたときにusb的にinterrupt endpointを登録するコード(usbd_open_pipe_intr()を呼ぶ)と、closeしたときに後始末(usbd_about_pipe() & usbd_close_pipe()を呼ぶ)をするデバイス依存の関数を追加する。それぞれubsa(4)から持ってきて、umsm_open(), umsm_close()ということにしておく。ucomがopen/closeされるタイミングで呼ばれるデバイス依存関数は、前述のstruct ucom_methodsで指定しておけばよい。

さらに割り込み発生時に呼び出されるデバイス依存関数とその補助関数として、同じくubsa(4)からumsm_intr(), umsm_get_status()を持ってくる。同様にstruct ucom_methodsに指定する。

これで、interrupt endpoint周りの処理は完了。普通のHSDPAモデムのDoCoMo A2502をつなげて試してPPPセッションが正しく張れるようになっていることを確認。とりあえずここまでで半分くらい終了。

ここまでのコードの差分は、OpenBSD CVSwebで確認できる。

次回のエントリーでは、D02HWのモード遷移のための関数の統合について書く予定。

2008年5月12日月曜日

背の低いUSBシリアル

ということで、ジャンパピンがでっぱってケースに入らないことがあるので、

ピンをはがしてワイヤハンダ付けして結線しなおし。
どうせ、設定決めたらいじらないし。

最近どうもコネタばかりだ。


2008年4月28日月曜日

PSoC書き込み器またまたあらわる

何度でもやるぞというくらいこのblogで出てくるネタとしてPSoCの書き込み方法がある。 mini-eval の丸ピンソケットをZIFにしてやれば書き込み器として使えるよねというアイデアは多くの人が提唱しているところではあるが、検索してみるとそれほど難しくなさそうだったのでやってみた。
簡単にいえば、秋月の28ピンZIFソケットをバラして、細いほうに組み直すという作業を行えばよい。ソケットをよく裏をみると内側にも2列穴があいていることに気づくはずだ。こちらにあわせてやればよいのだが、ソケットはナットではなくピンでとまっているのでこじあけなければならない。先の細い精密ドライバか割り箸のようなものをあてて、上からプラスチックハンマーで叩いてピンを外す。これで組み替えができるようになるので金具を左右いれかえてやる。そうすれば、無事に内側の穴から足のはえたZIFソケットができあがる。次の難関はどうやって元にもどすかだが、筒状のおさえがあれば、リングをささえて押し込むことが出来る。私が使ったのはノベルティのボールペンの先っぽ部分。分解して軸のほうの先をあて、穴のあいたところにピンの軸が入るようにしてやり、上からやはりプラハンで叩いて押し込む。


これで無事もとどおりになって、しかもスリム28pinのソケットに入るZIFが出来上がる。注意点としては、組み替えるときに上下逆さまではなく、金具を左右をいれかえなければひっかかりができずに使えないということだろう。参考となるページは多数あるようなので、詳しい写真などは他の人のブログを参考にして試してみればよいとおもう。これにより、先に書き込む中身が決まっているPSoCならストレスなしに書き込みが行える。簡単にいえばGainer互換チップを作るのに非常に重宝したというわけだ。

2008年4月12日土曜日

100ccで100g (転載というか移動)

知人がやっていたデジカメ連射があまりにも面白かったので、新しいデジカメとして EXILIM Z1080というすこし型落ちのモデルを手に入れた。連射性能と値段を考慮するとこれがベストの選択だろうということだ。

それまでは借り物の Cybershot DSC-T9という薄型ででっぱらないレンズのカメラを使っていたので最初の印象は「分厚いな」であり、手に持つと「軽いな」であった。二つをはかりにのせてみるとどちらもメモリとバッテリをいれて153gと159g だったので体感できるほどの差があるとは思えない。この差はなんだ?と思って思い出したのが10年以上前の学生時代に先生から聞いた一言だった。曰く「携帯電話ってのは 100g 100cc というのが一つの目標なんだよ」という言葉である。人間の体はほとんどが水分なので比重が1に達すると持ったときの違和感が薄れるということだそうだ。

この言葉を思い出してから、カタログを見ながら電卓をたたいてみるとまさにその通りの結果であった。

Casio Z1080  125cc 153g に対して Sony DSC-T9 は 159gで 85cc しかない。凝縮されている分だけ重く感じてしまうわけだ。

同じことを、以前使っていたレッツノートYシリーズから macbook air にかえたときにも思ったので、こちらも電卓をたたいてみることにした。ちなみに、重いと感じる macbook air が 1370g に対してLets note Y7 は 1510g なので140g すなわちケータイ1個分くらいはairのほうが軽い。それでもairを持った後にYを持つと「軽い!」と思う。

計算結果はというと macbook air はもっとも厚い部分がそのままスクエアで角をおとしていないという想定でもおよそ 1400ccであり、実質丸みをおびた分で8割程度しかないのではないだろうかと思われる。こうなると比重として 1をすこし超える程度となる。ある意味、重さと体積の黄金比でもあるわけで持ちあるくという意味での十分な比率にはなっていると思う。これに対して、レッツノートは十分に分厚い筐体のためか、最薄部分で考えても2100cc と、700ccも多く、比重を計算すると0.7程度と1を大きく下回っている。これが軽さを感じさせる理由であることは間違いなさそうだ。

重さを感じるのは最終的には脳なので、見た目も重さのうちということがよくわかる計算結果となった。それにしても、まだアナログ携帯電話の時代から比重の重要性を実感していた人たちはすごい。

--
(もともと別のblogに書いたものですが転載しました。)

2008年4月11日金曜日

Power Gainer  (またまたGainer 互換機)

Gainerを使ってブレッドボードで作品をつくると作品をブレッドボードのまま保存しないといけない。しかしながら、ブレッドボードだとパーツはともかく、配線がもげたりして、動かなくなりがちである。1作品に1個gainerを消費するのは耐えられないという貧乏性なのもありサーボのときもユニバーサル基板で簡単な回路を起こしたが、今度はトランジスタアレイを駆動することにしたボードを作ってみた。

このトランジスタアレイつきGainerならば小型モータくらいならそのまま動かすことができるので、power gainer と名付けてみた。こうやって作ってみた基板がこちら。これをコンフィグレーション3、4を使えば8ポートのアナログ出力をトランジスタでドライブした形で使うことができる。シンクドライバなのだが、論理の反転はトランジスタアレイがやるのでそのまま出力すれば問題なく、出力を変化させることができる。

実際には多チャンネルを外部から同時に利用するためには、トランジスタアレイに別途電源を用意しなければ、USB給電の限界が先にくることになるとはおもう。何に使うかはまだ決めていないが、最近のマイブームでは振動モータが熱いのでそれをPWMで複数駆動してみる予定である。

Gainerとrubyとtwitter (あるいはタンジブルなtwitter)

Gainerをコントロールするためのライブラリを探すと processingや Flashといった作者から提供されているものだけではないさまざまなライブラリが存在する。その中でも個人的に普段使う言語であるrubyのライブラリを発見したので、それを使ってみることにした。gainerでよく使っていたprocessingは基本的にディスプレイと一体化しているのでデーモンを作るのは困難であるが(とおもう)rubyならば簡単にバックグラウンドタスクで動かすことが出来る。さらにrubyの他のライブラリと同時に使うことでさまざまな処理を簡単に行うことができることも
、processingとの違いであろう。

processingを使うとグラフィックを簡単に表示できるので画面をつかったインタラクションを作るのには非常に向いているのであるが、今回のようなネットワークをつかったフロントエンドで、画面を必要としないようなものの場合には、rubyのほうがよいであろう。さらに、 C++のライブラリというのも見つけたので、組み込みマシンを使うならばそちらのほうがいいかもしれない。恐るべしgainer。
まあ、それはおいといて作ったものがこれ。ボタンをおすと twitterに「コーヒー飲みたい」みたいなメッセージを書き込む。ボタン2はランダムにfollowerを選択して「スゲー」と書き込む。
ruby-twitter のライブラリと gainer-rubyのおかげでとても簡単に書き上がった。回路はブレッドボードの上につくったがコンフィグレーション1のまま Din の4ポートにスイッチをつないだだけである。
一度かきこんだら1分以上たたないと書き込まないといった処理は追加してボタンの押し過ぎに対応しておく。こうやっておかないと無限にボタンを押して大変なことになることがある。

これだと単なるキーボードでよさそうだが、このままスイッチを人感センサーに変更すれば「部屋にひとがきた!」みたいなことをしゃべるtwitterを作ることも簡単だ。もちろん、コードを修正してアナログの入力をつかえば「部屋があついです」とかもね。

今回のコードは以下のとおり。動作環境は intel imac の leopard 上でデフォルトのrubyを使っている。gem で twitter (twitter4rではない) と gainer-ruby をインストールしておく必要があるので試してみる前にお忘れなく。ちなみに twitterは gemでそのまま入るが、 gainer-rubyは URLを指定してやる必要がある。



#!/usr/bin/ruby
#
# Twitter Button
#

require 'rubygems'

gem 'twitter'
require 'twitter'
gem 'gainer'
require 'gainer'

## setting for User account
id = "UserName"
pass = "password"

tc0 = Time.now - 80
tc1 = tc0
tc2 = tc0
tc3 = tc0
tcb = tc0

twit = Twitter::Base.new(id,pass)
gainer = Gainer::Serial.new(ARGV.shift)

puts "Ready.\n waiting buttun..."

gainer.on_pressed = proc do
puts 'Button pressed'
if (Time.now - tcb > 60 ) then
tcb = Time.now
fri = twit.followers()
fnum = fri.size
friend = fri[rand(fnum)].screen_name

puts "#{friend} SUGOI..."
twit.update("@#{friend} スゲー!w by XXX ")
end

end

loop do
sleep(0.1)
gainer.peek_digital_input

case gainer.digital_input[0]
when 1
puts "GET 1"
if (Time.now - tc0 > 60 ) then
tc0 = Time.now
puts "Give me COFFEE..."
twit.update("珈琲プリーズ だれかプリーズ")
end
when 2
puts "GET 2"
if (Time.now - tc1 > 60 ) then
tc1 = Time.now
# fri = twit.friends()
fri = twit.followers()
fnum = fri.size
friend = fri[rand(fnum)].screen_name

puts "#{friend} SUGOI..."
twit.update("@#{friend} スゲーョ!")
end
when 4
puts "GET 3"
if (Time.now - tc2 > 60 ) then
tc2 = Time.now
puts "I'm Sleepy..."
twit.update("ねむい中")
end
when 8
puts "GET 4"
if (Time.now - tc3 > 60 ) then
tc3 = Time.now
puts "Give me FOOODDDD..."
twit.update("はらへり、ヘリハラ")
end
else
## puts "NODATA"
end
end

2008年3月31日月曜日

gainer clone (互換機)でサーボを動かす

LEDばかりでは面白くないのでgainer を使ってラジコン用のサーボを動かしてみることにした。このサーボモータはもともとはラジコン自動車、飛行機などでつかわれていたが、最近ではロボコンブームのおかげでその基幹パーツとして多種大量に供給されるようになってきている。

一般的なラジコン用サーボモータはアナログのPWM信号によって移動角を制御している。基準として 1msecから2msecのパルス幅を投入すると、その幅に応じた角度にサーボモータの軸が回転する。これを周期的に与えてやることでその角度を維持したり、動作角度を変更したりすることが出来る。ロボットの場合には、この周期をどこまで早められるか、応答速度や、トルクといったメカトロてきな要素が非常に重要になるのだが、インタラクションデザインのためのサーボにはそこまでの精度は要求されないのが一般的だ。今回はgainerのアナログ出力が実際には電圧変化ではなく、PWM信号を用いていることを利用し、サーボモータの駆動を試してみることとする。

アナログサーボには個体差があるので、両端のぎりぎりの部分を使うためには、それぞれのサーボに応じたパルス幅を調べる必要がある。Aout(0) にサーボの信号線を繋ぎ込んで利用する前提で作成したコードは以下のとおり。
 
コントロールなしのダイアモンドカーソルでサーボの稼働角を調整できる。 E/X で 5ステップづつS/D で1ステップずつの稼働となっている。

コンソールに現在の数字が出るので幅を記録していこう。一般的な安いサーボモータは最大と最小で180度前後の回転角を得ることができる。Analogoutが最大で8ch までとることが出来るので、8個のサーボなら同時に動かすことが出来るはずだ。ただしその場合には、電力が足りなくなると思われるので、サーボ駆動の電源を別途用意する必要があるだろう。

手元のサーボで試したところパルス幅が 8から30程度ということで 180度を20分割程度にはできるようだ。回転角がシビアな用途でない、見せるための作品であれば十分に実用的な範囲だと考えられる。






import processing.gainer.*;
Gainer gainer ;
int i ;

void setup() {
gainer = new Gainer(this) ;
frameRate(5) ;
i = 20 ;
}

void keyPressed() {

switch(key) {
case 'x':
i -=5 ;
break ;

case 'e':
i +=5 ;
break ;

case 's':
i -- ;
break ;

case 'd':
i ++ ;
break ;
default:
}
}

void draw() {
gainer.analogOutput(0,i) ;
println("NOW: " + i + "..." ) ;
}

2008年3月12日水曜日

Gainer Clone でwebcamを操作する

前回はハードウェアをブレッドボード上にならべて満足したので次は簡単な実装としてgainer備え付けのボタンを押すとシャッターが切れてwebcamから写真がとれる、というものをつくってみた。基本的にはボタンだけでは面白くないがこのボタンを光電センサやドアの開け閉めに連動させればパソコンのキーボードを押してwebcamを操るのとは違うことができるはずだ。単純にボタンだけであっても長いUSBケーブルさえ用意すれば、レリーズのように遠隔でシャッターをおすことも可能だ。玄関のドアやブースの外側といったところにカメラをむけてセンサーをおけば、監視カメラとしての役割くらいは十分にこなせる。

コードは非常に簡単で写真を撮るためのcaptureオブジェクトの read をボタンが押されたときのハンドラに登録し画面に表示するだけだ。ほとんど何の処理もしていないが、サンプルコードは以下に示す。撮られた画像は画面に表示するだけなので、セーブが必要ならばそのようなルーチンを書き足す必要がある。
動作確認は OSX10.5 で内蔵の isight をつかって行った。カメラとgainerがうごけばwindowsでも動作するだろう。

この発展であるセンサーのアナログ値を使ったカメラの駆動はまた後ほどということで。



/*
capture by button

*/

import processing.gainer.*;
import processing.video.*;

Gainer gainer ;
Capture cam ;

void setup() {

size(320,240) ;
frameRate(24) ;
background(0) ;

cam = new Capture(this,320,240) ;
gainer = new Gainer(this) ;
delay(100) ;
cam.read() ;

}

void draw() {

if ( gainer.buttonPressed ) {
cam.read() ;
}
image(cam,0,0) ;
}

2008年2月28日木曜日

Gainer clone on BreadBoard


基板をつくる前にはブレッドボードである程度試作するのが最近の一般的な?流儀だとおもうが、ブレッドボード遊びに興じてしまったのでそちらの結果を先に。

PSoC を使った製品といえば、 iPod やGameboy microが有名だが、PSoCを使った「作品」となると gainer だろう。gainerはメディアアーティストのためのフィジカルコンピューティングデバイスとして設計されており、 Processing Flash MAX/MSPといった作品作りによく使われる環境に適応するためのライブラリが提供されており、親和性が非常に高い。

このキット オープンソースなHWであるが、焼かれた基板にパーツをつけて8500円という価格で売られている。8500円という値段は、ほとんど手作りに近い状態で作られて会社で売られるにはまっとうな値段だと思うが、ちょっと一瞬遊んでみるには一瞬躊躇する値段かもしれない。


どうせブレッドボードで使うのなら、最初っからパーツをブレッドボード上にくんでしまったら安上がりでは?とおもったので手持ちのパーツを使ってやってみた。回路図を見る限り USB-UARTに PSoCがつながれて、 LEDとSwitchが1つづつオマケにつながっているだけだ。LEDはアクティブハイにドライブされており、SWは内部 pulldownでVCCに直結されている。回路図をみながらとりあえずそのままボード上で再現してみた。

なにも難しいところはないけど、パズルのように配線をおこなって、まあ、これでいいんじゃないか?というところまではたどりついたので晒しておこうとおもう。

モジュールが秋月なのですべて秋月電子でそろえるとして、トータルコストとしては、
AKI-UM232R 950円
CY8C29466 500円
ブレッドボード EIC-102BJ 700円

とまあブレッドボードをいれても2000円強といったところ。

ブレッドボードには余分があるのでこの上に簡単な回路なら足すことはもちろん可能だ。そのためにベースは片側に寄せてくみ上げてある。

互換とするにはさらに電流制限抵抗とLEDとタクトスイッチが必要だが、電子工作をするものならこれくらいはパーツ箱から出てくるであろうということで、コストには加算していない。

これで合計2150円である。PSoCライターがない場合は PSOCのライターであるCY3210-MiniProg1 4000円が必要となるが、この場合にはminiprogにサンプルとして29466がついてくる。

とりあえずサンプルプログラムが動いたので、満足して作品として完成させるのはまた次回ということで。

2008年2月27日水曜日

(メモ)DoCoMo A2502の制御ポートアクセス

ずいぶん間があいてしまったけど「NetBSDでDoCoMo A2502をつかう」の続き。

DoCoMoのA2502は、正しくアタッチするとシリアルポートが3本生成される、ということは前回のエントリーで書いた。最初の一本は通信するためのモデムポートだが、残りの2本は通信以外に利用されている。

3本目のシリアルポートは通信制御や各種情報を取得するために利用されているようなので、少し中身を見ていたが、まとまったのでメモとしてここに書いておくことにする。

3本目のシリアルポートの使い方

D02HWなどと違って、atコマンドを受理したりはしてくれない。バイナリを送るとバイナリで返事をくれる、という仕様になっているようだ。(コマンドを全部解析したわけではないが、とりあえずアンテナレベルの取得くらいははできる。)

処理シーケンス

  • シリアルポートをオープンする
  • {0xcf, 0x18, 0x00, 0xc0, 0xdd, 0x7e}を書き込む。
  • 12バイトの返事がくるので読む(解析していない)
  • {0xcf, 0x00, 0x00, 0x91, 0x86, 0x7e}を書き込む
  • 14バイトの返事がくるので読む(解析していない)
ここまでで準備はおしまい。その後に適切なコマンドを送ると、いろいろな情報を取れる。
  • {0xcf, 0x07, 0x00, 0x99, 0xcb, 0x7e}を送ると、自分の電話番号などが含まれた51バイトの情報が返ってくる。(電話番号は5から16バイトの間)
  • {0xcf, 0x01, 0x00, 0x49, 0x9f, 0x7e}を送ると、シグナルレベルや、つながっているネットワークのIDが含まれた58バイトの情報が返ってくる(シグナルレベルは7バイト目、ネットワークIDは26から40バイト目)
みたいな感じ。ほかにもショートメッセージサービスへのアクセスができたりするようだが、そこはまだ見ていない。

rubyを用いたサンプルコード

というわけで、アンテナレベルと繋がっているネットワークの名前を出力するサンプルコードを載せておく。今回はrubyで書いてみた。シリアルポートのサポートライブラリにruby-serialを使っているので動かす場合にはインストールしておくこと。


require "serialport"

# open control serial port 38400/N81
sp = SerialPort.new("/dev/ttyU2", 38400, 8, 1, SerialPort::NONE)
sp.flow_control= SerialPort::NONE

cmd0 = [0xcf, 0x18, 0x00, 0xc0, 0xdd, 0x7e].pack('C*')
cmd1 = [0xcf, 0x00, 0x00, 0x91, 0x86, 0x7e].pack('C*')
telno = [0xcf, 0x07, 0x00, 0x99, 0xcb, 0x7e].pack('C*')
antcmd = [0xcf, 0x01, 0x00, 0x49, 0x9f, 0x7e].pack('C*')
cnt = 0

sp.write(cmd0)
buf = sp.read(12)
sp.write(cmd1)
buf = sp.read(14)

sp.write(telno)
buf = sp.read(51)
data = buf.unpack('C*')
telno = data[5..16].map!{|c| c.chr}.join
print "tel no:" , telno, "\n"

while (cnt < 20)
sp.write(antcmd)
buf = sp.read(58)
data = buf.unpack('C*')
network = data[26..40].map!{|c| c.chr }.join
print "signal level:" , data[17], " [network:" , network , "]\n"
cnt+=1
sleep 1
end
出力は

$ ruby a2502ant.rb
tel no:080XXXXXXX
signal level:20 [network:]
signal level:20 [network:]
signal level:20 [network:]
signal level:20 [network:]
signal level:20 [network:]
signal level:18 [network:]
signal level:18 [network:NTT DoCoMo]
signal level:19 [network:NTT DoCoMo]
[省略]

のようになる。アプリケーションを作る場合などにそれなりに使えるかな。

2008年2月17日日曜日

(メモ)DUS01まとめ

忘れる前にワンセグチューナーDUS-01の挙動についてメモしておく。半分は自分のため、あとの半分は「24時間ワンセグコミュニティ(?)」のため。Linuxやwindowsで使うときにどうぞ。

ハードウェア

  • CPU: Silicon Laboratories C8051F342
  • チューナー: sharp VA1A5JZ9902A (参考リンク:ascii24)
  • アンテナ:ロッドアンテナ
  • インターフェイス: USB1.1
シャープの9902Aは1-2世代前のワンセグモジュール。最新版には及ばないが感度が-107dbmは優秀なんじゃないかと思う。googleで探したけど仕様書等は見つからなかった。残念。

USBデバイス情報
USBデバイスとしては、こんな感じ。ほかに何をかけばいいのかな。
  • Vendor ID:0x1bc8 , Product ID:0x0001
  • endpointは0,1,2,3の4本。
  • EP1は制御用のバルク転送エンドポイント(読み書き可能)。
  • EP3はMPEG2TS転送用のアイソクロナス転送エンドポイント(読み込み専用)
  • EP2は使っているのを見たことないけど、ファームウェアアップデートなどに使うのじゃないかと推測
  • 起動時にファームウェアロードなどは発生しない。電源を入れれば動く。

さらに詳しく知りたい人のためにNetBSDのusbgenの出力を載せておく。
CONFIGURATION descriptor index 0:
bLength=9 bDescriptorType=2 wTotalLength=46 bNumInterface=1
bConfigurationValue=1 iConfiguration=0 bmAttributes=80 bMaxPower=150 mA

INTERFACE descriptor index 0, alt index 0:
bLength=9 bDescriptorType=4 bInterfaceNumber=0 bAlternateSetting=0
bNumEndpoints=4 bInterfaceClass=0 bInterfaceSubClass=0
bInterfaceProtocol=0 iInterface=0

ENDPOINT descriptor index 0:
bLength=7 bDescriptorType=5 bEndpointAddress=1-out
bmAttributes=2 wMaxPacketSize=64 bInterval=5

ENDPOINT descriptor index 1:
bLength=7 bDescriptorType=5 bEndpointAddress=1-in
bmAttributes=2 wMaxPacketSize=64 bInterval=5

ENDPOINT descriptor index 2:
bLength=7 bDescriptorType=5 bEndpointAddress=2-out
bmAttributes=2 wMaxPacketSize=64 bInterval=5

ENDPOINT descriptor index 3:
bLength=7 bDescriptorType=5 bEndpointAddress=3-in
bmAttributes=1 wMaxPacketSize=188 bInterval=1


制御コマンド
制御コマンドはEP1をつかってやりとりする。今のところ分かっているコマンドはこれだけ。全部推測なので正しいかはわからないけど。
  • ファームウェアバージョンチェック (0x9f) - 現在のファームウェアのバージョン(1.0.0)が返ってくる。
  • チャネル設定 (0x10) - これに加えてKHz単位の周波数をくべるとチューナーが設定される。
  • 入力検出(0x11) - 電波が受信できていたら0x1、受信できなければ0x0が返ってくる。
  • ストリームモードチェック(0x12) - たぶんMPEG2TSストリームを出しているかしないかをチェック。
  • ストリームスタート (0x20) - EP3へのMPEG2TS出力を開始する。
  • ストリームストップ(0x21) - EP3へのMPEG2TS出力を停止する。
  • シリアル番号チェック(0x43) - デバイス固有のシリアル番号を返す。
(2008/2/18 1:30修正:miroさんありがとうございました。)

それぞれのコマンドは10byte長で、先頭にコマンドを、引数がないものは0x0で埋めて送る。
チャネルを変えるときのシーケンスは
  • ストリームが出ていたら止める
  • 止まったかモードをチェックする
  • チャネル変更リクエストを出す
  • ちょっと待つ
  • 入力検出リクエストを出す
  • 返り値をチェックして0x0だったら「ちょっと待つまで戻る」。0x1が出るまでがんばる。(もしくはタイムアウトする)
  • ストリームを出力する
って感じ。チャネル設定コマンドは、{0x10, 0x04, 0x00, A, B, C, 0x00, 0x00, 0x00, 0x00} というフォーマットで、A,B,CにKHz単位の周波数を指定する。たとえば、521.43MHz(チャンネル21)なら{0x07, 0xf3, 0xb7}を埋め込めば良い。
(2008/2/19修正:チャネル設定コマンドの例の先頭バイトをtypoしていたので修正)

出力ストリーム
EP3からはMPEG2TSもどきが出力される。先頭はMPEG2TSで規定された同期ビット列(0x47)でかつ、パケット長が188Byteというのは良いのだが、MPEG2TSとして解釈すると全部エラーになる、という変な状態。きっと、プログラムミスでこうなってしまっているのだろうとおもう。あまりにも不憫なので正しいストリームに治してあげよう。
「先頭の0x47を除いて、他のバイト列に対して0xb5を排他的論理和を取る。」
すると、普通のMPEG2TSになる。

まとめ
USB的には、「USBデバイスとしてのJ200への不満」、はほぼ解決されているようなデバイスだった。最初はストリームが見えるか少しどきどきしたが、まあすぐにわかってよかった。
まだ入手性もよいみたいだし、ここにある情報を使えば他にも対応ソフトを作れそうな人がいると思うので、いけているデバイスじゃないかと思う。明日もう少し補充を(自分用に)買っておこう。。

NetBSDで「24時間ワンセグ野郎」(新デバイス)(3)

新デバイスさらに続き。

バイトストリームを眺め続ける人生にもちょっとだけ疲れたので、ここらで絵(と音)でも見てみたい、という願望が大きくなってきた。というわけで、ちょっと真面目に絵と音声を見る部分を書いてみることにした。もし絵とか音声が見えたら、それがちゃんとしたMPEG2TSストリームとして扱えているか?っていう検証になるし。(バイトストリームを検証するためにはちゃんとパーサーと表示系をいちいち書かないといけないから、すぐには対応できないし)
というわけで、新デバイスでも生TSをキャプチャして録画までできることを確認できた。(絵は今とったらこれだった、てだけ、意味はないです)。ワンセグチューナさわっていて初めてまともに絵を見たよ。

下手に書いちゃって動かないのに買っちゃう人がいたら災難だから「新デバイス」とだけ書いていたけど、これで今まで伏せていた製品名をかける。写真のRockridgesoundのDitune(DUS-01)が最近触っていたデバイス。秋葉原だと3000円弱で買える&結構店頭に並んでいるので見たことがある人も多いかもしれない。
外部アンテナはつながらないけど、選択肢の一つとしてはいいかな、と思っている。

NetBSDで「24時間ワンセグ野郎」(新デバイス)(2)

新デバイスの話再び。

前回のエントリー(NetBSDで「24時間ワンセグ野郎」(新デバイス))に、生TSっぽいのが出ているとかいてしまったが、ちょっと寝てから冷静に見直してみると、なんか変だということに気がついた。

簡単にいえば、「先頭の0x47以降は本来受信したはずのデータ列と異なっている」ようだ。キャプチャされたTSの解析結果も載せてあったので、鋭い人なら一目で気がつくような気もするけど、異様にフラグが多かったり、アダプテーションフィールド長が255だったり、(あそこには含まれていないけど、PIDが0x1fffを超えていたり)、していた。

また、

  • だいぶ感度が悪そう。ちょっと、置き場所を変えるだけで、MPEG2TSのパケットでTS_ERRORフラグが立ってしまう。あんまり頻度が高いと、TS_ERROR付きでも眺めてみる、みたいな処理に変えないといけないかもしれない。
とも書いていたが、これもTS_ERRORビットの値がずれているのが問題だったようだ。値を読み替えてからみてみると、感度はそんなに問題ないみたい。

幸いにもMPEG2TSヘッダは固定長で単純かつ、特定の部分に決まった情報が出やすいという特徴があるので、しばらく眺めていると変換のパターンは見えてくる。もう少し解析しないとだめだけど、今のところ、「各バイト単位で特定の値で排他的論理和をとる」っていう単純なルールでもとに戻るようだ。(コンティニュティカウンタの値が1->0->3->2->5と進むところで、XORじゃないか、って推測できたのが決め手だった)。

というわけで、今度こそ生TSだと思われる出力。それっぽくなった。
これで、MPEG2TSパーサーに戻れる。

2008年2月16日土曜日

NetBSDで「24時間ワンセグ野郎」(新デバイス)

このエントリーの一行まとめ: 使えるUSBワンセグチューナーは、実はたくさんある、かも?

本家の昨晩のエントリーでふれられていた「一部で非常に不評なLOG-J200のUSB(笑)」をおもに専門に扱っている:)わけですが、そこに非常に気になる記述があった。

  • ちゃんとエンドポイントは分かれてるしTSのデータはアイソクロナスで送ってきているし ^^; なんといってもコントロールコマンドがシンプル簡単で使いやすい!(笑) それこそ他OSでいじるベースとしては便利そうな感触ですよ。USBXPressではなく今度はEZ-USBベース、そして実売価格は3000円。探せばいろいろあるものです。

しかも入手性がいいようなので注目に値する情報だ。これで、24時間ワンセグ野郎コミュニティ(?)もさらに盛り上がるに違いない。
と、そのエントリーを読んだのが午前2時半すぎ。それまでは、ARIBの資料を眺めながらワンセグのMPEG2TSストリームの制御情報を処理する部分をつらつらと書いていたのだが、デバイスを触りたい気分がいきなり盛り上がってしまった。私も実は、その辺でみかけるたびにUSBデバイスを買ってあって、そろそろ家があふれそうだったりしているので、そのなかでまだ開けていなかった箱をいくつか取り出してUSBストリームを眺める、という作業に従事してみた。

2-3種類眺めてみると、やっぱりいろいろと特徴が見えてくる、その辺の話はまた今度まとめる機会を探すとして、また新しく「188byte単位の情報転送 & 先頭バイトが0x47」のストリームを吐くチューナーを見つけてしまった。俄然盛り上がったので、NetBSD用のデバイスドライバも書いてみた。(おかげで眠い)

このデバイスは、
  • CPUは8051ベース(シリコンラボラトリC8051F342)
  • チューナーはシャープ製
  • アンテナはロッドアンテナのみ
  • 眩しく光る青色LED付き
  • 3000円台のお得な値段で入手可能かも
というハードウェアで、基板を眺める限り、J200よりは出来がよさそう。挙動としては、
  • コマンド用のEndpoingとデータ用のEndpointがわかれている
  • データ用Endpointはアイソクロナス転送で188Byte単位で送ってくる
  • 初期化コマンド等はほとんどいらない。お行儀よくチャネル切り替えをすれば動く
  • 電波が安定するまではストリームを出力しない。チューナーがセットアップされたかどうかを問い合わせてみて0x1がかえってきたら、転送開始、みたいな処理をする。
というかんじで、この前のエントリに書いた不満はおおむね解消されているようだ。

ただ、気になるのが、まだソフトウェアが悪い可能性もあるので何ともいえないけど、だいぶ感度が悪そう。ちょっと、置き場所を変えるだけで、MPEG2TSのパケットでTS_ERRORフラグが立ってしまう。あんまり頻度が高いと、TS_ERROR付きでも眺めてみる、みたいな処理に変えないといけないかもしれない。付属のソフトではそんなに画像が乱れるみたいなことが頻発するわけではないので、もう少し調査が必要。
MPEG2TSのストリームはとれているみたいなので、もう少し調査して詳細をお知らせしたいとおもいます。というわけで、MPEG2TSストリームが出ている証拠も載せておきます。先頭バイトが0x47だけ、ってわけではないので安心。

2008年2月15日金曜日

基板CADと基板加工機


回路・基板CADとして制限はあるもののフリーで使える Eagleは非常によくできたツールである。
しかし、なぜか操作性があまりにも普通のGUIソフトと違うところは非常に残念だ。

とはいえダウンロードするだけでサイズ制限はあるものの2層基板をオートルートしてくれるというのは非常に便利である。さらにこの手のソフトに珍しくWindowsのほかに MacOSとLinuxもサポートしている。

このEagleも新しいバージョンのテストがおこなわれておりメジャーバージョンアップが近いようだ。次のバージョンからは Mac版がX11に依存しなくなるのでそれに期待しつつ、今日は現行の 4.16とベータ版の 4.92のアイコンが微妙に違うという写真をのせておこう。

これからしばらくはマイコンと同時に基板CADとそれを使ったプリント基板の作成方法の備忘録も載せていこうとおもう。

(ワンセグ)電波時計(の特性)


一発芸のつもりだった「ワンセグ電波時計」だったが、もう少し詳しく特性を調べてみることにした。
ARIBの仕様書では時刻情報(TOT)のデフォルト送出間隔は5秒と決まっているらしいが、その5秒刻みというのがどのくらい正確なのか?というあたりを知りたくなったからだ。

前回のエントリーではNTPで同期しているNetBSDの時刻情報と並べて表示していたが、今回はgettimeofday()を使ってマイクロ秒単位でTOTとTOTの間隔を計測してみた。108個(つまり540秒ほど)連続して受信したTOTの間隔の統計的な値を表に示しておく。

思っていたよりも精度が高いようで、うまくつかえば結構便利かもしれないな、と別の野望も妄想中。簡単な機材で大域時刻同期ができるって結構すごいことなんだよね。

2008年2月14日木曜日

(ワンセグ)電波時計


ワンセグのストリームを眺めていてふと思いついたので、つくってみた。
「ワンセグのストリームだけを使う時計」略称「ワンセグ電波時計」。

どのくらいの精度がでるのかな、とおもってNTPで同期しているシステム時間も同時に表示してみたけれど、少なくとも秒単位では合っているみたいだ。更新頻度は5秒おきなので、それくらいの精度しか出ないと思うけど、なんか使えないかしら?

NetBSDで「24時間ワンセグ野郎」(2)

さすがに平日はあまり時間が取れないので、あっと驚くような進捗があるわけではないけど、進んでいないというわけでもないので、メモがてらに書いてみることにした。Log-J200のUSBデバイスとしての感想など。

USBデバイスとしてのLog-J200
ざっくりいうとLog-J100もUOT-100も同じなんだが、どれもこれもUSBデバイスとしてみたときにはあまりいけているデバイスだとは言い難い。一言でいうなら、

  • USBデバイスのファーム設計のセオリーを見直してこい!
と、受け側のソフトを書きながら思わずデバイスに突っ込みをいれてしまうような、そんな仕様がいくつもある。たとえば、
  • 機能とエンドポイントの分離がうまくできてない、とか
  • コマンドを受理しても返答しない、という動作をするコマンドがある
  • なぜかbulk転送になっているMPEG2TSストリームの転送モード、とか
  • なぜか64Byte長で細切れな転送
とか。最初の「エンドポイントの使い方」は、endpoint0でやればよいようなデバイスの制御が、なぜかMPEG2TSストリームをやりとりしているendpoint2にのっている、とか、そのあたりが顕著な例。2つめも問題で、USBのホストコントローラ的には受理したならackを返してほしいと思っているのに、黙ってしまうのでコマンドがストールしたように見えてしまう。必ず受理される、と信じて送らないといけないのはどうかとおもう。
で、性能上問題になるのは3つめと4つめ。MPEG2TSのパケット長は188Byteで、空から約380KBps程度の速度でどんどんと情報が降ってきている。これを受け取るそばからUSBバスの上に流してあげる、というのがUSBワンセグチューナデバイスのお仕事。(たぶん)普通はこんな特性の情報を扱うためには、USBではアイソクロナス転送モードというのを使うことになっている。アイソクロナス転送にするとハンドシェイクやリトライをしないので時間制約に即した転送ができる、ので、次々に発生する事象(音とか映像とか電波とか)を扱うのに向いている。Log-J200(とその仲間たち)はなぜかMPEG2TSストリームの転送にBulkエンドポイントを採用している。Bulkエンドポイントでは転送サイズは64byteまでなので、188Byteの転送をするために少なくとも3回(J200の場合は4回)の転送要求発行しないといけない。

ちょっと計算してみるとわかるのだが、ワンセグのパケットは約1.2msくらいに一回の周期で受信される。つまり、1.2ms以内に4回のトランザクションを必ず発行するような動作をしていないと取りこぼしてしまう。
いまどきの速いコンピュータにとっては1msなんて無限な時間にみえるかもしれないが、実時間動作が苦手なUNIX系のOSではちゃんとやらないと実際に取りこぼしてしまう場合があった。

特に今回はugenをつかったユーザーランドアプリケーションとして書いてみているので、そのあたりは結構シビアだなあ、というのが感想。eggmanさんのlinuxデバイスドライバの話をみて、「やっぱりカーネルデバイスドライバのほうがかっこいいし、オーバーヘッド少なくなるからよいだろうなあ。」と思ったのは内緒だ。いつか気が向いたらkernelのデバイスドライバも書いてみよう。
でも、アイソクロナス転送のしてくれていれば、ユーザランドからさわってもこんなことは起こらないので、やっぱり設計に難がある、っていう気がしている。

ちなみに、内部バッファとかも持っていない設計になっているようで、USBデバイスへのポーリングが遅れるとデータの一部が化ける(nバイトシフトしているように見える&nバイト足りない)。最初は何で先頭にMPEG2TSの先頭バイト(0x47)が現れない場合があるんだろうか?と悩んでしまったが、USBアナライザの時間計測モードをつかってみたら、アクセス間隔がWindowsでみた場合とくらべて長いかった。
複数のkerenlへのリクエストをまとめるとか、小技を使って解決している。

Log-J200の受信感度
外付けアンテナがつくのであんまり問題にならないんだけど、受信したMPEG2TSストリームを数字で眺めていると、数パーセントの割合でエラーが出ているみたい。エラーとしては以下の3パターン。
  • そもそも受信できていない。MPEG2TSのカウンターを計測していると取れなかったことがわかる
  • MPEG2TSのトランスポートエラーインジケーターの値が1になっている。つまり、受信時に「このデータ使わないほうがいいじゃない?」と言ってきている
  • 先頭バイトが0x47じゃない。タイミング制約は満たしているはずだとは思うけど、たまに発生する
特にトランスポートエラーインジケーターは受信を開始してから200パケットくらいに全部ついているので、受信機が設定されてから正しいデータ出すまでに300msくらいはかかるってことかな?

NetBSDの24時間ワンセグ野郎の現状
とまあ、USBレベルでは取りこぼしもなく普通に受信情報を取り出せている。とりあえず受信データMPEG2TSの状態でファイルに書き出すこともできる。とまあ、そのくらい。いまは画像を眺めるというよりは、受信したストリームを数字で見ながら、ヘッダとかペイロードとかのいろいろな部分のパーサーとダンプ関数を書いてみて、「ほほー」とか言いながらにやけている状態。今日の参考資料はARIB-TR-B14(英語版)とかARIB-STD-B10(英語版)。なぜ英語かというと無料で公開されているから。(ARIBの英語版配布サイト

というわけで、外堀はほとんど埋まっているような感じですが、本家みたいな作りこみをできるまでには、まだしばらくかかりそうです。

最後に色気はないけど、動作中のテキスト出力など。ワンセグっていうことでPID=0x1fc8のパケット情報。本当になんかプログラムを書いている、ってい証拠に(なるかな?)。

== MPEG2TS header (PID:0x1fc8) -:P == Cont count:08, Flags PUSTART TRANSPRIO
== MPEG2TS header (PID:0x1fc8) -:P == Cont count:09, Flags PUSTART TRANSPRIO
== MPEG2TS header (PID:0x1fc8) -:P == Cont count:10, Flags PUSTART TRANSPRIO
== MPEG2TS header (PID:0x1fc8) -:P == Cont count:11, Flags PUSTART TRANSPRIO
== MPEG2TS header (PID:0x1fc8) -:P == Cont count:12, Flags PUSTART TRANSPRIO
== MPEG2TS header (PID:0x1fc8) -:P == Cont count:13, Flags PUSTART TRANSPRIO
== MPEG2TS header (PID:0x1fc8) -:P == Cont count:14, Flags PUSTART TRANSPRIO
== MPEG2TS header (PID:0x1fc8) -:P == Cont count:15, Flags PUSTART TRANSPRIO
== MPEG2TS header (PID:0x1fc8) -:P == Cont count:00, Flags PUSTART TRANSPRIO
== MPEG2TS header (PID:0x1fc8) -:P == Cont count:01, Flags PUSTART TRANSPRIO
== MPEG2TS header (PID:0x1fc8) -:P == Cont count:02, Flags PUSTART TRANSPRIO
== MPEG2TS header (PID:0x1fc8) -:P == Cont count:03, Flags PUSTART TRANSPRIO
== MPEG2TS header (PID:0x1fc8) -:P == Cont count:04, Flags PUSTART TRANSPRIO

2008年2月12日火曜日

NetBSDで「24時間ワンセグ野郎」(1)

MobileHackerz再起動日記で開発が進められている「24時間ワンセグ野郎」だが、ひと月ほど前のエントリーを見たときから「すげえ」素直に感嘆していた。「これはいけてる!」とおもって、その場でUOT-100を6本ほど買ってあった、ということからも(今はすでに入手困難だということを考えて)本当にぐっときたことは推測してもらえると思う。
ちょっと忙しくしていたので出遅れてしまったのだが、これができるということは、別のOS、たとえばNetBSDでも同じようなアプリケーションを構築できるんじゃないかとおもってやってみた、というのがこのエントリーの内容。
この3連休の時間で始めたことなので、本家の完成度には到底およばないけれど、最近一部でブームも盛り上がってきているようなのでちょっと参戦してみようと思う。

UOT-100を持っているから、といってもそれをそのまま使うのは二番煎じすぎる。本家にもなにか貢献できないかなーとおもって最近どこかで安いワンセグチューナを見かけるたびいくつかを購入してみていた。分解したり、USBのデータストリームを眺めていたりもしたのだが、まだ「これは!」という機種には出会えていない。
今回は、Log-J200をつかってワンセグ野郎をしてみることにする。
Log-J200はUOT-100と似たデバイスで、UOT-100と同様に「生TSをバス上に流している」ので、扱いが簡単だから、というのと、「まだ入手できるから」というのが理由。

いきなりkernelドライバを書いてもいいのだが、「ugenでラピッドプロトタイピング」という話も書いていたし、今回は

  • NetBSD ugenをつかったユーザランドアプリケーションで実装
  • ハードウェア改修なしに複数デバイスに対応
  • (できればネットワークサーバ化)
という感じでいってみている。

先に、現状を書いておくと、昨晩から24時間(当然途中では寝ているしごはんもたべてる)くらい経過したところで、
  • NetBSDで複数デバイス同時に認識
  • Windowsデバイスドライバには非依存
  • とりあえずチャネルは2チャンネルくらいは変更可能
  • 生TSだと思われるファイルを書きだしている(けど、まだみえない)
  • MPEG2TSの簡単なヘッダパーサを書いて、それなりにエラーハンドリングをできるようになりつつある
くらい。パケットダンプを見ている限り、それなりに正しくMPEG2TSのキャプチャはできているようにみえるので、あともう少しで画像がみえるか?という期待でここまで来ている、というところ。Log-J200は分解が大変(というか分解するとたぶん復元できない)ので、ハードウェアを触らなくてもいいというのは大きな利点じゃなかなと(個人的には)おもっている。

というわけで、現状報告を先にしておく。ソースをまとめたら公開予定(BSDライセンス)。
次のエントリーで解析した内容を書く予定。

週末の娯楽としては大変楽しめたし、これからもちょっと楽しめそう。がんばろう。

2008年2月11日月曜日

NetBSDでDoCoMo A2502をつかう(-currentにマージ)

NetBSDでDoCoMo A2502をつかう」で書いたようにNTT DoCoMoの3G/HSDPAモデムFOMA A2502をNetBSDで使えるようにして、patchを本家に送っておいた。
今日(2/11)無事に-currentにマージされたようだ。

D02HWにつづいてA2502も今日以降のNetBSD-currentを入れれば使えるようになる。
A2502もちょっと解析(アンテナレベルの取得とか)を進めていたので、もう少し進んだらまとめてみようとおもっている。

今日はお知らせだけで。

2008年2月7日木曜日

NetBSDでSONY GPS-CS1Kを使う

SONYはGPS-CS1KというGPSロガーを発売している。ずいぶん前(発売直後)に買ってあったのだけど、実はあまり使わずに棚の上のオブジェと化していた。一緒にblogをかいているCUEICHIがGoogle Mapと位置情報で遊んでいたのをみてGPSを持っていることを思い出しGPSを使おうと盛り上がった。
が、なぜかNetBSDでは動かない(OSXでも動かない。。)ので原因を調べてみた。
kerenlからのメッセージと、USBバスアナライザの出力を見る限り

  • UR_BBB_GET_MAX_LUNリクエスト受け取ったあとデバイスの挙動がどうも怪しい
  • しばらくリトライすると復帰する
ようだ。リトライのコードを入れてもいいのだが、他のデバイスへの影響が大きそう。あまり美しくはないがNetBSDのumassの例外コード(umass_quirks)を拡張してUR_BBB_GET_MAX_LUNを発行せずに決め打ちでLUNを指定する、というロジックを導入してみることにした。

その結果、sd0 on umass0として認識されるようになって、mount -t msdos /dev/sd0a /mntでディスクとしてマウントできるようになった。とりあえずpatchはsend-prしてある(kern/37948)。

NetBSDで動くようにはなったが、GPSロガーをどんなふうに使うかはまだ思案中。

こんなデバイスをみるたびに、「Windowsで動けばいい、みたいなデバイスの作り方はしないでほしいなー」と思う。で、同時に「Windowsのホストドライバってなにかあってもあきらめずに頑張るなー」とこっそり感心する。ここは純粋に評価してもいいね。

NetBSDでDoCoMo A2502をつかう


別に3Gモデムを攻略するのが趣味ってわけではないが、近くにNTT DoCoMoのHSDPAモデム A2502 (製品情報)があったのでどんなものか眺めてみた。結構あっさりとNetBSDで動くようになったので方法を書いておく。

A2502はAnyData社の製品とのことだが、イーモバイルのD02HW(HAUWEIのE220)みたいにメジャーな製品のOEMというわけではなさそう。検索してもあまり素性がわからないので、とりあえずUSBバスを観測してみたところ、コマンドの系列がこの前書いたD02HWと互換性がありそうだ。というわけで、とりあえずモデムモードになったあとのD02HWと同じように扱ってみたところ通信ができることを確認。

モデムとしては、

  • comポートが3本でてくる。ATコマンドを受理するのは最初の1つだけ。2つめは不明。3つめは網の情報がでているっぽいけど、特に処理するコードは書いていないので見えない。
  • D02HWみたいにUSBマスストレージがついていたりはしない、普通のモデム
  • 変なコマンドを送らなくても、最初からモデムとして動く
なので、D02HWよりは扱いやすい。ただ、不明なvendor specific requestがいくつもあるのでそれがなにかわからないのはちょっと気持ちわるい。

コード的には、いくつか初期化シーケンスを書いて、uhmodemをD02HWとA2502両用になるようにさらに汎用的なドライバとして整理しておいた。やったことは
  • deviceのvendor id, product idの構造体にいくつかの補足情報(comデバイスの数、デバイス種類のフラグ)を持つようにした
  • シリアルデバイスになるインターフェイスごとにちゃんとendpoint haltをかけるようにした。
  • いままで決め打ちだったendpoint 番号をusbフレームワーク的に解決するようにした
  • いままで決め打ちだったデバイス依存リクエストを整理して両方でつかえるようにした
というあたり。見直した結果コードは少しきれいになった。新しいデバイスに対応するのがもっと簡単になりそう。もう少しつかってみてから、NetBSD本家にsend-prしておく予定。寝る前にだせるかな。(追記: done)

とりあえずpppでつなげてみたところ、DoCoMoの網の挙動はイーモバイルの網とは違うことがわかった。
たとえばRTTの変化。イーモバイルはしばらくパケットを投げているとある段階で急にRTTが短くなるが、DoCoMoの場合はステップ的に減っていく。最終的は二つとも同じくらい(70ms-100ms)で収束するが、途中経過が違うのがおもしろかった。
(追記: emobileでもう一度RTTを計ってみたところ500ms → 200ms程度までしか変化しなかった。挙動がかわったのかもしれない。そういう意味ではDoCoMoの網のほうが良い特性かも?)

速度は追いこんでいないけど、SSHでscpして10MBくらいのファイルを転送したところ200KB/secくらいでていた。そんなに悪い数字じゃないね。

追記: NetBSD-pr kern/37978 すぐに試してみたい人はこれを見て手でパッチあててください。最近のcurrentには当たるはず。

2008年1月28日月曜日

ugenでラピッドプロトタイピング(*BSDでUSB)

*BSDにはugen(usb generic device)という汎用のUSBデバイスドライバが実装されていて、USBデバイスを刺したときに適切なデバイスドライバが見つからなかったときには、ugenデバイスしてアタッチするようになっている。普通は「なんだugenかよ」と思って「サポートされてないじゃんか」となる(普通じゃない人は「しょうがないからデバイスドライバ書くか」となる)のだが、実はugenとして見えるのはそれはそれで大変意味があることだ。
というわけで、ugenを使ったrapid prototypingについて書いてみようと思う。

ugenが出来ることは、

  • /dev/ugenN.MMというスペシャルファイルを介したUSBデバイスとのエンドポイントとの通信
で、read(), write(), ioctl()をつかって、USBデバイスの概ねほとんどの機能にアクセスできる。USBは「ユニバーサルシリアルバス」なのでread(), write()できれば、適切なアクセス方法をプログラムできれば大体なんでもできるはずだ。
もちろん、ugenもデバイスドライバなので、あるデバイスに適切なデバイスドライバが実装されていてkernelにコンフィグされているときはugenとしてアクセスすることは出来ない。(kernelコンフィグによっては強制的にugenにすることもできる。man ugen参照のこと)。

ugenで実装することとkernelで実装することの利点・欠点をまとめると、

ugen利用の利点:
  • kernelで実装しなくてもいいので、開発が楽
  • kernelに実装しなくていいので、配布や利用が楽
  • APIがあまり変わらないので、kernelバージョンがあがっても追従しやすい
  • ugenっぽいデバイスドライバがあるOSなら移植しやすい(かも)
ugen利用の欠点:
  • 参考になる実装や文書が少ない
  • kernelに取り込まれることは無いので、マージはされない
  • kernelスペースとuserlandのやりとりが多いのでパフォーマンスは期待できないかも
  • kernel内のほかのフレームワークとの連携は難しい
という感じだと理解している。本質的にはkernelで書こうがugen経由で書こうがUSB的にはやることはほとんど変わらないので、kernelをかける人もプロトタイプツールとしてugenというのは検討しても良いんじゃないだろうか。

というわけで簡単な使い方から。基本的なステップは
  • usbctlなどのツールでUSB device descriptorを取得して、エンドポイントの構造をざっくりと理解する。D02HWみたいに何かしたら化けるデバイスもあるので、ugenの-Dオプションを使って全部のconfigurationをdumpしておくと便利。何回もみるので、ファイルに出しておいたり、印刷して脇に置いたりしても良い。usbctlとかusbgenコマンドはpkgsrcのusbutilを入れれば入るはず。
  • デバイスを刺したときにでたugenのデバイスのugenN.00をO_RDWRでopen()する。これがコントロールエンドポイント(EP0)になる。
  • 開いたEP0に対して、ioctlでUSB_GET_DEVICEINFOを送りつけると、device descriptorが取得できる。取得したusb_device_info構造体にvendor IDとproduct IDが入っているのでこれでデバイスの認識をする。複数のデバイスをサポートしていないなら、お目当てのデバイスがみつからなければexitしてしまえばよい。
  • お目当てのデバイスがみつかったら、最初に調べておいたエンドポイントを必要な数だけopen()する。openするファイル名は/dev/ugenN.MMのMMがendpoint番号。endpointがINだったらO_RDONLY、OUTだったらO_WRONLYにするのを忘れずに。IN/OUTだったらO_RDWRで良い。
  • 後は開いたファイルディスクリプタに対して、書き込んだり、ioctlを発行すれば、usbのバスに必要なトランザクションが生成される
と、こんな感じ。

デバイスを探索するコードのサンプルを書いてみると、

#include </dev/usb/usb.h>
int
XXX_match(int fd) {
struct usb_device_info udi;

/* get device information */
if (ioctl (fd, USB_GET_DEVICEINFO, &udi) < 0) {
perror("can't get device information");
return -1;
}
fprintf(stderr, "device info: VID:%#.4x PID:%#.4x\n",
udi.udi_vendorNo, udi.udi_productNo);
/* check the device is XXX */
if (udi.udi_vendorNo != XXX_VID || udi.udi_productNo != XXX_PID){
fprintf(stderr, "can't find any NM30 on %s\n", dc->dev);
return -1;
}
printf("==== Found a XXX ====\n");
return 0;
}

のようになる。

使ってみていて注意しないといけない点は、
  • 結構kernelの奥深くをさわっているらしく、お行儀が悪いとすぐにkernelパニックを引き起こす
ということ。openしたファイルディスクリプタの始末や、書き込むメッセージのサニタライズは最初からそれなりにお行儀よくしておいたほうがいい。

長くなったので続きは次回。

2008年1月22日火曜日

NetBSDでEmobile D02HWを使う(-currentにマージ)

何回かにわたってD02HWをNetBSDで使う話を書いていたが、1/21付けでNetBSD(-current)にマージされた。
基本的に「NetBSDでEmobile D02HWを使う(新デバイスドライバ)」でsend-prしたものがおおむねそのままマージされたかんじ。cvsで吸い出すだけで使えるようになったはず。

使う人が出てきたら潜在的な問題とかが出てくるかもしれないけど、一段落。

2008年1月13日日曜日

Ruby on Rails で googlemapをかっこよく



今回はいつものハードウェアとは趣が違って web サービスのテクニックの話である。

ruby on rails上でgooglemapをつかった表示を行うときにすこし気の利いたインタラクティブな動作をさせるところがトピックである。

ruby on rails で googlemapを扱うのに使われる pluginとしてym4r/gm というのがある。geocodingもふくめ非常に簡単に使えるのだが、逆に細かいところに手がとどかない。

事の発端はgooglemapの地図上のマーカをクリックすると吹き出し形式でメッセージが見られるインターフェースを実装したのだが、マウスオーバーで見られるほうがいいのではないかという意見をこのblogの共著のYUO氏から貰ったことであった。

そこでこの機能を実現するためにgoogleを何時間かしらべたが、googlemapの使い方はわかったものの、railsでの ym4rを使った例は英語サイトもふくめて直接的な回答にはいきあたらず、ym4r開発者のサポートBBSでもほぼ1年ほど放置プレイだったので備忘録もふくめて書いておく。

googlemap上 でマウスをつかった特別なアクションを使うためにはaddListenerによってリスナを設定する必要がある。しかしながら、 ym4r/gm のコードをそのまま使ってマーカを設定するだけではこのような設定ができない。リスナを設定するためにはリスナになるオブジェクトを変数として代入し、バインドしてやる必要があるためだ。

declare_init をつかってオブジェクトを変数として宣言しなおしてやる必要がある。そしてこの後で、宣言された変数を使ってリスナを設定するのだが、このときに既存のメソッドは役に立たない。汎用につかえるrecord_initメソッドを使うことにより、 initializeのルーチンの中に自分で設定したjavascriptをそのまま書き込むことができるのでそれを利用することになる。


書き上げたコードの一部を切り出しておくと以下のようになる。

ポイントは markerを変数化するときに#{x.id} をつけることによりすべてのマーカで違う変数名を持つようにすることが1つ目である。もう1つのポイントとしては record_init をつかって直接 googlemapを動かすjavascriptのGEvent.addListener メソッドを記述するところである。また、 変数 pで生成している htmlの終端に改行がはいっていると地図のjavascriptのレンダリングがうまくいかないようなのでちゃんと partialなレンダリングをした後にchompすることを忘れないことが大切なようだ。

さらに今回はlistenerとして mouseover のほかに mouseout を設定することで、マウスがはずれると即座にウインドウが自動で閉じる処理を行っている。


実装例

marker = GMarker.new([x.lat,x.lon],
:title => " #{x.created_at.strftime("%m/%d-%H:%M")}" )
p = render_to_string(:partial => 'msg',
:locals => { :tag => tag , :pm => x }).chomp

@map.declare_init(marker,"marker#{x.id}")
@map.overlay_init(marker)
@map.record_init "GEvent.addListener(marker#{x.id},
'mouseover',
function(){marker#{x.id}.openInfoWindowHtml(\"#{p}\")}); "
@map.record_init "GEvent.addListener(marker#{x.id},
'mouseout',
function(){map.disableInfoWindow();
map.enableInfoWindow();}); "

2008年1月9日水曜日

NetBSDでWatchdog timerを使う(CS5535/CS5536)

ちょっと前にNetBSDでWatchdog timerを使う(for ALIX) (1) という一連のエントリーを書いたけれど、年が明けたころからNetBSD-currentへの統合作業をやっていた。手元にあるALIXでは普通に動くのだけど、ほかのボードではどうもうまく動かない(watchdog timerをenableすると一瞬でリブートされてしまう)と言うレポートが担当となったcommiterの人からあがってきてその理由を追ってみたので、メモがてらに何が起こっていたかを書いてみることにする。

  • 元々のコードの仮定:CS5536のMFGPT0はNetBSD kernel以外では使っていない。だから、watchdog timer用のtimerとしてMFGPT0を決めうちで使っても問題無い
動かないといわれても動かないボードは手元に無いので、debugの出力をてんこ盛りにしたテスト用のドライバをつくって、何回かやりとりをしてみた。その結果
  • 何者かがNetBSD kernelがアクセスする前に、MFGPT0を設定して(たぶん、何かの用途に使って)いる。
ことがわかった。MFGPTのsetupレジスタはほとんどのビットフィールドがwrite onceレジスタになっていて、一度設定されるとリセットするまで再設定はできない設計になっている。だから誰かが設定してしまうと、その後は必要な設定を上書きすることができないので事実上watchdog timerとしては利用できない。特に問題なのはタイマーの分周器の設定で、分周比が低すぎるとあっというまにタイマーがまわってしまって、watchdogが動く値に到達してしまう、というのがリブートされる理由だった。たぶん問題になったボードではBIOSなどが何かの用途に設定してしまっているのではないかと推測している。

この問題に対応するためにやったことは、
  • gcscpcib_attach()のwatchdog timerを設定するところで、gcscpcib_scan_mfgpt()という関数(とりあえず書いた)を使って、その時点で使われていないMFGPTを探して使うことにした
  • 必要なら決めうちで利用するMFGPTを指定できるようにした
というあたり。更にマージする前に、もう少しお行儀の良いコードにしようと思って
  • MFGPT関連のレジスタの更新ロジックを、仕様書に指定されている「前準備」−「更新」-「後始末」というシーケンスでやるようにした。
前準備ではカウンタを止めたり、割り込みを禁止したりする必要があり、後始末では関連フラグをクリアしたりしなければならないらしい。手元のALIXではそんなことをしなくても動いていたんだけど、debugする過程で書いてしまったので正式採用した。更に
  • watchdogの間隔を最低値(1秒)にすると運が悪い時にリブートしちゃう問題、が起こらないようにタイマーの精度を1Hzから4Hzにあげた。
  • define一つでタイマーの精度を指定できるようにした
  • まともなdebug messageを埋めた
あたりを入れ込んだ。

元々はAMD CS5536用のコードとしてsend-prしたが、CS5536とCS5535はほとんど一緒、ということもあって共用のドライバーとして扱うことにした。で、名前もOpenBSDのglxpcibからgcscpcibという名前に変更。

というわけでHEADにマージされました。cvswebでは明日以降ならみえるんじゃないかな。

2008年1月5日土曜日

NetBSDでEmobile D02HWを使う(新デバイスドライバ)

NetBSDでD02HWを使うためにいろいろとやった結果、前回のubsaデバイスドライバへのパッチというアプローチではどうも差分が大きくなりすぎる、という結論に達した。新しく別のデバイスドライバとしたほうがなにかと都合がよいので、uhmodem (USB huawei modem)という名前の新しいデバイスドライバをつくってみた。と、いってもubsaとの共有部分も多いのでそのままコピーして変更するのもいまいちな気がしたので、ubsa.cをubsavar.h, ubsa_common.c, ubsa.cの3つに分解して、uhmodem.cからはubsa_common.cを介してubsaの関数を使うことにした。

とりあえずdmesgを載せておく。

uhmodem0 at uhub0 port 1 configuration 1 interface 0
uhmodem0: HUAWEI Technologies HUAWEI Mobile, rev 1.10/0.00, addr 2
uhmodem0: mass storage only mode, reattach to enable modem
uhmodem0: at uhub0 port 1 (addr 2) disconnected
uhmodem0 detached
uhmodem0 at uhub0 port 1 configuration 1 interface 0
uhmodem0: HUAWEI Technologies HUAWEI Mobile, rev 1.10/0.00, addr 2
ucom0 at uhmodem0 portno 0: modem
ucom1 at uhmodem0 portno 1: monitor
umass0 at uhub0 port 1 configuration 1 interface 2
umass0: HUAWEI Technologies HUAWEI Mobile, rev 1.10/0.00, addr 2
umass0: using SCSI over Bulk-Only
scsibus0 at umass0: 2 targets, 1 lun per target
cd0 at scsibus0 target 0 lun 0: cdrom removable

attach時のメッセージを見てわかるように、uhmodemではD02HW(E220)が提供しているすべての機能(com *2, umass *1)を同時につかえるようになっている。
現状ではumassがつながっても、windowsのデバイスドライバが見えるだけだが、海外のほうでは、あの領域に好きなものを入れれるようなアクティビティもあるようなのでその時に役にたつかもなーくらいな気持ちでいれてみた。
ucom0, ucom1は前者が通信用のttyで、後者がモデムの状況や通信状況をモニターするための監視用ttyだ。ucom0を使っているときでもucom1を同時にアクセスできるので、メモ:D02HW解析に書いたDSFLOWRPTメッセージとか電波状態問い合わせ(^ANQUERY)の回答などを受け取れる。ユーザーインターフェイスアプリケーションを書くときには便利なはず。

というわけで、patchは大きくなったのでここに乗せるのは割愛しておく。すでにNetBSDにはsend-prしてある(kern/37692)ので急ぐ場合はそちらを参照すると良いかも。

とりあえずやることはおわったかなーーー。。

2008年1月4日金曜日

メモ:D02HW解析

イーモバイルのD02HW (Huawei E220のOEM)をNetBSDから使えるように触っている過程で調べたことをメモしておく。

マスストレージモード(電源投入時)
普通に認識すると、USB mass strageデバイスに見える。USB class 8(umass), subclass 6(SCSI), proto 80(BBB)。Interface 0: endpoint: 3(in)-4(out)。マウントするとCDROMにみえて、中身にwindows用のユーティリティとデバイスドライバが入っている。役立たず。

モデムモードへの変換
Host-to-DeviceでSet Future: DEVICE_REMOTE_WAKEUP, wIndex=0x2で送りつける。すると同じvender ID, product IDのままで別のデバイスに化ける。
(wIndex=0x1にしてdataに0x1を入れて送っても同じ結果になるが、違いは不明)

モデムモード(変換後)
モードがモデムモードになると、インターフェイスが3つに増える。

  • インターフェイス1: USB class 255, subclass 255, proto 255。完璧なベンダースペシフィックだが実はシリアル。シリアルデバイスはBELKINのとほとんど同じにみえる(NetBSDだとubsaドライバ)。これがモデムの主インターフェイス。endpoint: 1(intr)-2(in)-2(out)。
  • インターフェイス2:USB class 255, subclass 255, proto 255。インターフェイス1と同様にシリアルデバイス。モデムの観測用インターフェイス。endpoint: 5(in)-5(out)。通信しないからか割り込みが無い。
  • インターフェイス3: USB class 8, subclass 6, proto 80。マスストレージモードのときにインターフェイス1に見えていたUSB mass storage。
モデムの観測用インターフェイス
つなげるとATコマンドを受理する。ステートは主インターフェイスの設定を継承している(たとえばate0と主インターフェイスで打ち込んであるとATコマンドにエコーバックしない)。使い道は2つ。
  • 主インターフェイスで通信をしているときにもATコマンドを受理するので、AT^ANQUERY?(電波強度問い合わせ)などで状態を取得できる
  • 主インターフェイスで通信しているときは定期的(2秒に一回)、^DSFLORRPTという行が出力される。


DSFLORRPT
DSFLORRPTはこんな感じに出力される。(一行で)

^DSFLOWRPT:0000007C, 00000000, 00000000, 000000000001B1AE, 00000000004DD9D2, 0000AA50, 000EBA40

ざっくりと眺めたところ、意味は最初から[通信時間(秒)], [送信スループット(byte/s)], [受信スループット(byte/s)], [総送信量(byte/s)], [総受信量(byte/s)], [なんかのID], [なんかのID]となっているようだ。時間とデータ量は16進数で表現されている。

謎のコマンド
windows PCとD02HWの間のUSBトランザクションを眺めていると、標準的ではない制御トランザクションが観測される。何やっているか不明。
  1. (準備1)Endpoint:2-inにCLEAR_FEATUREリクエスト、ENDPOINT_HALTを送る
  2. (準備2)Endpoint:2-outにCLEAR_FEATUREリクエスト、ENDPOINT_HALTを送る。
  3. InterfaceにType:Class, bRequest=0x02, wValue=0x1, wIndex=0x0, wLength=0x2, Data[]={0x0, 0x0}を送る
  4. InterfaceにType:Class, bRequest=0x22, wValue=0x1, wIndex=0x0, wLength=0x0を送る
  5. InterfaceからType:Class, bRequest=0x21, wValue=0x0, wIndex=0x0で7byte読み込む。普通は{0x0, 0x96, 0x0, 0x0, 0x0, 0x0, 0x8}が見える。
  6. 前のリクエストで取得したバッファの2-3byteを{0x8, 0x7}にして書き戻す。bRequest=0x20
  7. InterfaceにType:Class, bRequest=0x22, wValue=0x3, wIndex=0x0, wLength=0x0を送る
たぶん、
  • bRequest=0x20: E220_CLASS_WRITE
  • bRequest=0x21: E220_CLASS_READ
  • bRequest=0x22: E220_CLASS_SETUP (or CMD)。bVlaue=0x1でstart, bValue=0x3でcommitみたいな感じ?
じゃないかと推測している。問題は読み書きする7byteの意味がわからない点。NetBSDで適当に実装して発行してみているが、何が変わったかはわからない。

通信時のUSBトランザクション
USBのendpointのデータ単位は64byte。TCP/IPで通信をしていると、大体46-48USBパケットがバースト的に送られてくる。モデム側のバッファサイズは3-4KBじゃないかと推測。

(おまけ)イーモバイル網の挙動
PPPで接続して普通にpingをうつと、RTTが300-400msくらいでガッカリする。しかし中身ではいろいろと複雑な制御をしているようで、5pps以上の頻度で同一ホストにパケットを送信すると、10-20パケットくらい経過してからRTTが70ms-100msに変化する。
しばらく通信がないとまたリセットされるので、フローごとに細かい制御をしているようだ。カットスルー?でもしてるんかいな。


とりあえずこのくらい。

NetBSDでEmobile D02HWを使う(スループット改善)(2)

しばらくsys/dev/usbの下を眺めていたが、USB的な律速が他にあるとしても触るにはおおごとになりそうなので、別の部分から攻めることにした。

「Windowsなら速い」という話でふと思いついたのが「TCPの動作の違い」だった。Windowsはいろいろなパラメータ調整でTCPの挙動を変えているが、それがイーモバイルの網の挙動とうまくあっているのかもしれない。または、専用ドライバがWindowsのパラメータを自分好みに変えているのかも。というわけで、NetBSDのネットワーク部分のパラメータを調整してみることにした。これはkernelにpatchを当てるとかいう話ではなく、sysctlで変えれる範囲でおこなった。

とりあえず今のところの/etc/sysctl.confを以下に示す。

net.inet.tcp.mss_ifmtu=1
net.inet.tcp.init_win=8
net.inet.tcp.sack.maxholes=64
net.inet.tcp.sendspace=65536
net.inet.tcp.recvspace=128000
net.inet.udp.recvspace=65536
kern.sbmax=2048000

この中で一番意味があるのがtcp.recvspaceだ。emobile網を使っていて思うのは、
  • 遅延はある程度大きいけど、そんなに落ちない。
ということだ。そんなネットワークではtcpのバッファサイズをある程度大きくしておかないと性能がでない。主記憶の量とどのくらいのセッション数をさばくつもりなのか?というあたりと要相談だが、たぶんいまのemobile網では128KBくらいあれば良いようにみえる。主記憶に余裕があればもう少し増やしておいてもよいかもしれない。recvspaceの大きさはkern.sbmaxに制限されるのでこちらも大きくしておくべき。

ここまでで、調子がよければ300KB/sを超えるようになる。気休めに/etc/ppp/peers/emobileの設定を2行ほど変えた。

# disable compressions
novj
##noccp
##nobsdcomp


実は並列して他にもいろいろな作業をしていたので、ここに書いただけで性能がそこまで上がるかはちょっと自信がないのだが、結果的には200KB/s - 440KB/sくらいは出るようになった。
調子の良い時はwgetで27MBくらいのmp4ファイルを転送して平均で390KB/sくらい、とそこそこの安定したスループットを見せてくれる。
ただ、現状ではWindowsなら300KB/sでているときにNetBSDでは200KB/sしかでない、という現象が発生する。まだ隠れている設定があるのかもしれない。

2008年1月3日木曜日

NetBSDでEmobile D02HWを使う(スループット改善)(1)

このエントリーの一行まとめ:HTTP/TCPで29KB/sしかでなかったけど440KB/s(3.4Mbps)まで改善した。うれしい。


最近のエントリーに結構話題にしたように、いろいろとごにょごにょとして、イーモバイルのD02HW(E220)をNetBSDでも普通に使えるようになった。使えないデバイスが使えるようにする作業をしていると、「使えるようになった!」時点でだいぶ達成感がでてしまってそこでゴールに着いてしまった気になりがちだ。今回もデバイスとして認識できない段階から、まがりなりにもPPPでセッションを張って通信できるようになったわけだから、まあそれでいいや、考えてしまっていた。
ちょっと間をおいて、実際に使ってみようとおもうと、どうも変な感じがする。windowsのNote PCにつなげて使っているときはすぐに見えるwebサイトなどが見えるのがだいぶ遅い。やっぱりスループットを計測してみるか、と重い腰を上げてやってみるた。
wgetコマンドをつかってHTTP/TCPで、ファイルを転送するときの速度を測ってみると………。(プロトコルオーバヘッドがあるので下部層ではあと10%くらい速いはず)。
  • Windows  (Panasonic Let's Note R5): 1.8Mbps-2.5MBps (230KB/s-320KB/s)くらい
  • NetBSD (ALIX 3C): コンスタントに0.225Mbps (29KB/s)
うーん、軽く1/10? と少しショックを感じながら改善作業に取り組むことにした。

2つの計測系で同一なのは「同じD02HWを使っている」「同じ場所で計測」「ほとんど同じ時間に計測」というところ。あとの計算機環境やソフトウェアは全部違っている。本当はできるだけそろえるべきなんだけど、Let's noteにNetBSDを入れるのもめんどくさいので実作業にうつることにした。とりあえず疑うべきは
  • D02HWの設定
  • D02HW用のデバイスドライバ
  • OSのUSBサブシステム
  • PPPの設定
  • PCの性能
あたり。ターゲットとしているALIX3は小さな組み込みボードといえども、500MHz駆動のAMD LX800で動いている。主記憶も256MBある。経験上これくらいの性能でたかだか数Mbpsのトラフィックを裁けないわけがない。USBホストのチップの問題もなさそう。というわけで、5つ目の「PCの性能」は「ほとんどなさそう」だ。

簡単なところが疑っていこうとおもって、次は「D02HW」の設定を追ってみることにした。といってもモデムとして見えるATコマンドでは無くUSBレベルでの話。USBバスアナライザでトランザクションを眺めていると、ベンダ独自のコマンドを使って設定用のレジスタをさわっているようにみえる。仕様書が無いのでこれが何を意味しているかはわからないが、設定しているということは意味があるのかもしれない?とおもってNetBSDからも同じ操作をする関数を実装してみた(どんな風にするかは後日別のエントリーで書く予定)。うーん?別に変わらない様子。

次は「デバイスドライバ」と「OSのUSBサブシステム」。一緒にみた方が良さそうなので同時に始末することにする。たぶん今回の問題の肝は「いつも同じ29KB/sである」ということだろう。windowsで見ていると、結構短い間隔でスループットが大きく変動しているのを観測できるが、NetBSDだとずっときっちりと29KB/sしかでない。つまりある層までは十分な性能があるのにかかわらずどこかに律速(ボトルネック)となる部分があってそれが原因でこんな状況になっている、と推測できる。こんなときにどこをさわればいいか?というのは、そのデータがデバイスからOSの上(tty)までどうやって流れてくるのかを理解して調べていかないといけない。幸いにも今回はD02HW対応でしばらくUSBのデバイスドライバをさわっていたので、ずいぶん勘がはたらくようになっていた。じーっとコードを眺めていると、USBのデータ処理単位とデバイスの単一のパケットサイズを同じ大きさ扱うようになっていた。たとえばUSB_ATTACH()のなかのエンドポイントディスクリプタを読んで上位のucomデバイスの送受信バッファサイズを設定するところ。


if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN &&
UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) {
uca.bulkin = ed->bEndpointAddress;
uca.ibufsize = UGETW(ed->wMaxPacketSize);
} else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_OUT &&
UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) {
uca.bulkout = ed->bEndpointAddress;
uca.obufsize = UGETW(ed->wMaxPacketSize);
}

単なるシリアルラインならともなく、D02HWは7.2Mbpsの高速シリアルデバイスなのでこれじゃだめだろうという気がする。というわけでその辺のコードをさわる。具体的には、uca(ucom attach arg構造体)のuca.ibufsize / uca.obufsizeをD02HWのパケットサイズ(64Byte)とは独立した大きさにする。試行錯誤の結果、4096Byteくらいがちょうど良い大きさだと判断した。uca構造体を設定する場所で決め打ちで4096を設定しておく。ucomとか関連する関数をチェックしたがそれで問題は無い。

ここまでの作業で、29KB/sec -> 12oKB/secくらいに劇的に改善した。1Mbpsくらいでている計算になる。でもwindowsの1/3くらいでしかないので更に解析と作業を進める。

(続く)