2008年12月22日月曜日
OSX でTCPウインドウ制御
2008年12月15日月曜日
Gainer の PGA設定
2008年11月4日火曜日
gainer-rubyを NetBSDの箱で動かす
2008年10月14日火曜日
ベリーショートなACタップ
2008年10月1日水曜日
passenger(mod_rails) でバーチャルホストを使わない複数アプリケーション動作
ラベル: ruby on rails, 小ネタ
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で焼き込めば動くはずだ。
ラベル: gainer, Processing, PSoC
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で動かすデバイスの試験にいつも使っているものでもある。
以上のように風車は簡単に動くところまではきたのだが、ひとつ大きな問題が残ってしまった。ほとんど動いていないときもピーピーとモーターから音がする。これは 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 + "*" ) ;
}
----------
ラベル: gainer, Processing, 作ってみた
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 "
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)) ;
}
}
--------------------------------
ここまで。
ラベル: Processing, twitter, 作ってみた
2008年5月22日木曜日
2008年5月15日木曜日
Xbeeの開発環境
東京ビックサイトで5/14-16で行われているESEC2008(組込システム開発技術展)にちょっとだけ用事があったので行ってきた。名前の通り、様々な組込系のボードや技術に関係しているベンダーがいろいろな製品やサービスを展示する展示会なんだが、いくつかのブースでは展示&会場限定で即売、みたいな事もやっていることがある。
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日月曜日
2008年4月28日月曜日
PSoC書き込み器またまたあらわる
2008年4月12日土曜日
100ccで100g (転載というか移動)
2008年4月11日金曜日
Power Gainer (またまたGainer 互換機)
Gainerとrubyとtwitter (あるいはタンジブルなtwitter)
#!/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 + "..." ) ;
}
ラベル: gainer, Processing, 作ってみた
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
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) - デバイス固有のシリアル番号を返す。
それぞれのコマンドは10byte長で、先頭にコマンドを、引数がないものは0x0で埋めて送る。
チャネルを変えるときのシーケンスは
- ストリームが出ていたら止める
- 止まったかモードをチェックする
- チャネル変更リクエストを出す
- ちょっと待つ
- 入力検出リクエストを出す
- 返り値をチェックして0x0だったら「ちょっと待つまで戻る」。0x1が出るまでがんばる。(もしくはタイムアウトする)
- ストリームを出力する
(2008/2/19修正:チャネル設定コマンドの例の先頭バイトをtypoしていたので修正)
出力ストリーム
EP3からはMPEG2TSもどきが出力される。先頭はMPEG2TSで規定された同期ビット列(0x47)でかつ、パケット長が188Byteというのは良いのだが、MPEG2TSとして解釈すると全部エラーになる、という変な状態。きっと、プログラムミスでこうなってしまっているのだろうとおもう。あまりにも不憫なので正しいストリームに治してあげよう。
「先頭の0x47を除いて、他のバイト列に対して0xb5を排他的論理和を取る。」
すると、普通のMPEG2TSになる。
まとめ
USB的には、「USBデバイスとしてのJ200への不満」、はほぼ解決されているようなデバイスだった。最初はストリームが見えるか少しどきどきしたが、まあすぐにわかってよかった。
まだ入手性もよいみたいだし、ここにある情報を使えば他にも対応ソフトを作れそうな人がいると思うので、いけているデバイスじゃないかと思う。明日もう少し補充を(自分用に)買っておこう。。
ラベル: 24時間ワンセグ野郎, USB
NetBSDで「24時間ワンセグ野郎」(新デバイス)(3)
新デバイスさらに続き。
バイトストリームを眺め続ける人生にもちょっとだけ疲れたので、ここらで絵(と音)でも見てみたい、という願望が大きくなってきた。というわけで、ちょっと真面目に絵と音声を見る部分を書いてみることにした。もし絵とか音声が見えたら、それがちゃんとしたMPEG2TSストリームとして扱えているか?っていう検証になるし。(バイトストリームを検証するためにはちゃんとパーサーと表示系をいちいち書かないといけないから、すぐには対応できないし)
というわけで、新デバイスでも生TSをキャプチャして録画までできることを確認できた。(絵は今とったらこれだった、てだけ、意味はないです)。ワンセグチューナさわっていて初めてまともに絵を見たよ。
下手に書いちゃって動かないのに買っちゃう人がいたら災難だから「新デバイス」とだけ書いていたけど、これで今まで伏せていた製品名をかける。写真のRockridgesoundのDitune(DUS-01)が最近触っていたデバイス。秋葉原だと3000円弱で買える&結構店頭に並んでいるので見たことがある人も多いかもしれない。
外部アンテナはつながらないけど、選択肢の一つとしてはいいかな、と思っている。
ラベル: 24時間ワンセグ野郎, NetBSD
NetBSDで「24時間ワンセグ野郎」(新デバイス)(2)
新デバイスの話再び。
前回のエントリー(NetBSDで「24時間ワンセグ野郎」(新デバイス))に、生TSっぽいのが出ているとかいてしまったが、ちょっと寝てから冷静に見直してみると、なんか変だということに気がついた。
簡単にいえば、「先頭の0x47以降は本来受信したはずのデータ列と異なっている」ようだ。キャプチャされたTSの解析結果も載せてあったので、鋭い人なら一目で気がつくような気もするけど、異様にフラグが多かったり、アダプテーションフィールド長が255だったり、(あそこには含まれていないけど、PIDが0x1fffを超えていたり)、していた。
また、
- だいぶ感度が悪そう。ちょっと、置き場所を変えるだけで、MPEG2TSのパケットでTS_ERRORフラグが立ってしまう。あんまり頻度が高いと、TS_ERROR付きでも眺めてみる、みたいな処理に変えないといけないかもしれない。
幸いにもMPEG2TSヘッダは固定長で単純かつ、特定の部分に決まった情報が出やすいという特徴があるので、しばらく眺めていると変換のパターンは見えてくる。もう少し解析しないとだめだけど、今のところ、「各バイト単位で特定の値で排他的論理和をとる」っていう単純なルールでもとに戻るようだ。(コンティニュティカウンタの値が1->0->3->2->5と進むところで、XORじゃないか、って推測できたのが決め手だった)。
というわけで、今度こそ生TSだと思われる出力。それっぽくなった。
これで、MPEG2TSパーサーに戻れる。
ラベル: 24時間ワンセグ野郎, NetBSD
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円台のお得な値段で入手可能かも
- コマンド用のEndpoingとデータ用のEndpointがわかれている
- データ用Endpointはアイソクロナス転送で188Byte単位で送ってくる
- 初期化コマンド等はほとんどいらない。お行儀よくチャネル切り替えをすれば動く
- 電波が安定するまではストリームを出力しない。チューナーがセットアップされたかどうかを問い合わせてみて0x1がかえってきたら、転送開始、みたいな処理をする。
ただ、気になるのが、まだソフトウェアが悪い可能性もあるので何ともいえないけど、だいぶ感度が悪そう。ちょっと、置き場所を変えるだけで、MPEG2TSのパケットでTS_ERRORフラグが立ってしまう。あんまり頻度が高いと、TS_ERROR付きでも眺めてみる、みたいな処理に変えないといけないかもしれない。付属のソフトではそんなに画像が乱れるみたいなことが頻発するわけではないので、もう少し調査が必要。
MPEG2TSのストリームはとれているみたいなので、もう少し調査して詳細をお知らせしたいとおもいます。というわけで、MPEG2TSストリームが出ている証拠も載せておきます。先頭バイトが0x47だけ、ってわけではないので安心。
ラベル: 24時間ワンセグ野郎, NetBSD
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の間隔の統計的な値を表に示しておく。
思っていたよりも精度が高いようで、うまくつかえば結構便利かもしれないな、と別の野望も妄想中。簡単な機材で大域時刻同期ができるって結構すごいことなんだよね。
ラベル: 24時間ワンセグ野郎, NetBSD, 小ネタ
2008年2月14日木曜日
(ワンセグ)電波時計
NetBSDで「24時間ワンセグ野郎」(2)
さすがに平日はあまり時間が取れないので、あっと驚くような進捗があるわけではないけど、進んでいないというわけでもないので、メモがてらに書いてみることにした。Log-J200のUSBデバイスとしての感想など。
USBデバイスとしてのLog-J200
ざっくりいうとLog-J100もUOT-100も同じなんだが、どれもこれもUSBデバイスとしてみたときにはあまりいけているデバイスだとは言い難い。一言でいうなら、
- USBデバイスのファーム設計のセオリーを見直してこい!
- 機能とエンドポイントの分離がうまくできてない、とか
- コマンドを受理しても返答しない、という動作をするコマンドがある
- なぜかbulk転送になっているMPEG2TSストリームの転送モード、とか
- なぜか64Byte長で細切れな転送
で、性能上問題になるのは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じゃない。タイミング制約は満たしているはずだとは思うけど、たまに発生する
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
ラベル: 24時間ワンセグ野郎, NetBSD
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の簡単なヘッダパーサを書いて、それなりにエラーハンドリングをできるようになりつつある
というわけで、現状報告を先にしておく。ソースをまとめたら公開予定(BSDライセンス)。
次のエントリーで解析した内容を書く予定。
週末の娯楽としては大変楽しめたし、これからもちょっと楽しめそう。がんばろう。
ラベル: 24時間ワンセグ野郎, NetBSD
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リクエスト受け取ったあとデバイスの挙動がどうも怪しい
- しばらくリトライすると復帰する
その結果、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マスストレージがついていたりはしない、普通のモデム
- 変なコマンドを送らなくても、最初からモデムとして動く
コード的には、いくつか初期化シーケンスを書いて、uhmodemをD02HWとA2502両用になるようにさらに汎用的なドライバとして整理しておいた。やったことは
- deviceのvendor id, product idの構造体にいくつかの補足情報(comデバイスの数、デバイス種類のフラグ)を持つようにした
- シリアルデバイスになるインターフェイスごとにちゃんとendpoint haltをかけるようにした。
- いままで決め打ちだったendpoint 番号をusbフレームワーク的に解決するようにした
- いままで決め打ちだったデバイス依存リクエストを整理して両方でつかえるようにした
とりあえず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デバイスとのエンドポイントとの通信
もちろん、ugenもデバイスドライバなので、あるデバイスに適切なデバイスドライバが実装されていてkernelにコンフィグされているときはugenとしてアクセスすることは出来ない。(kernelコンフィグによっては強制的にugenにすることもできる。man ugen参照のこと)。
ugenで実装することとkernelで実装することの利点・欠点をまとめると、
ugen利用の利点:
- kernelで実装しなくてもいいので、開発が楽
- kernelに実装しなくていいので、配布や利用が楽
- APIがあまり変わらないので、kernelバージョンがあがっても追従しやすい
- ugenっぽいデバイスドライバがあるOSなら移植しやすい(かも)
- 参考になる実装や文書が少ない
- kernelに取り込まれることは無いので、マージはされない
- kernelスペースとuserlandのやりとりが多いのでパフォーマンスは期待できないかも
- kernel内のほかのフレームワークとの連携は難しい
というわけで簡単な使い方から。基本的なステップは
- 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パニックを引き起こす
長くなったので続きは次回。
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を決めうちで使っても問題無い
- 何者かがNetBSD kernelがアクセスする前に、MFGPT0を設定して(たぶん、何かの用途に使って)いる。
この問題に対応するためにやったことは、
- gcscpcib_attach()のwatchdog timerを設定するところで、gcscpcib_scan_mfgpt()という関数(とりあえず書いた)を使って、その時点で使われていないMFGPTを探して使うことにした
- 必要なら決めうちで利用するMFGPTを指定できるようにした
- MFGPT関連のレジスタの更新ロジックを、仕様書に指定されている「前準備」−「更新」-「後始末」というシーケンスでやるようにした。
- 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:
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)Endpoint:2-inにCLEAR_FEATUREリクエスト、ENDPOINT_HALTを送る
- (準備2)Endpoint:2-outにCLEAR_FEATUREリクエスト、ENDPOINT_HALTを送る。
- InterfaceにType:Class, bRequest=0x02, wValue=0x1, wIndex=0x0, wLength=0x2, Data[]={0x0, 0x0}を送る
- InterfaceにType:Class, bRequest=0x22, wValue=0x1, wIndex=0x0, wLength=0x0を送る
- InterfaceからType:Class, bRequest=0x21, wValue=0x0, wIndex=0x0で7byte読み込む。普通は{0x0, 0x96, 0x0, 0x0, 0x0, 0x0, 0x8}が見える。
- 前のリクエストで取得したバッファの2-3byteを{0x8, 0x7}にして書き戻す。bRequest=0x20
- 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みたいな感じ?
通信時の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)
「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
- 遅延はある程度大きいけど、そんなに落ちない。
ここまでで、調子がよければ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)
- Windows (Panasonic Let's Note R5): 1.8Mbps-2.5MBps (230KB/s-320KB/s)くらい
- NetBSD (ALIX 3C): コンスタントに0.225Mbps (29KB/s)
- D02HWの設定
- D02HW用のデバイスドライバ
- OSのUSBサブシステム
- PPPの設定
- PCの性能
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);
}