2012年3月31日土曜日

コレジャナイ Android アプリ

MtkDLut の Android 版のような機能ショボイもの作成中.
機能としてはログのダウンロード・消去とログ Hz の設定だけだけど,これができたら出先で PhotoMate887 の Flash がいっぱいになってもスマフォにログを退避できたりして便利.

で,やってみているんだけど,どうも Bluetooth 経由の受信データが欠落する.
こんなふうに↓
$GPRMC,145602.100,A,35xx.xxxxxx,N,135xx.xxxxxx,E,0.756,262.36,300312,,,A*5E
$GPGGA,145602.200,35xx.xxxxxx,N,135xx.xxxxxx,E,1,,,126.783,M,,,,*2C
$GPRMC,145602.200,A,35xx.xxxxxx,N,135xx.xxxxxx,E,0.757,262.59,300312,,,A*56
5xx.xxxxxx,E,1,,,126.883,M,,,,*28
$GPRMC,145602.700,A,35xx.xxxxxx,N,135xx.xxxxxx,E,0.740,264.02,300312,,,A*53
$GPGGA,145602.800,35xx.xxxxxx,N,135xx.xxxxxx,E,1,,,126.905,M,,,,*2B
$GPRMC,145602.800,A,35xx.xxxxxx,N,135xx.xxxxxx,E,0.748,264.31,300312,,,A*57
$GPGGA,145602.900,35xx.xxxxxx,N,135xx.xxxxxx,E,1,,,126.930,M,,,,*25
$GPRMC,145602.900,A,35xx.xxxxxx,N,135xx.xxxxxx,E,0.752,264.60,300312,,,A*50
xx.xxxxxx,N,135xx.xxxxxx,E,1,,,126.990,M,,,,*25
$GPRMC,145603.300,A,35xx.xxxxxx,N,135xx.xxxxxx,E,0.719,265.51,300312,,,A*56
$GPGGA,145603.400,35xx.xxxxxx,N,135xx.xxxxxx,E,1,,,127.017,M,,,,*2E
行頭が $ でない行はそもそもデータが壊れている.

BT との通信やり取りは,PhotoMate887 へのコマンド / からのレスポンスと,NMEA データの 2つがやり取りされてるけど,NMEA 出力頻度が高いとどこかのバッファがオーバーフローして PhotoMate887 からのレスポンスがかき消されるっぽい?

PC+BT ドングル⇔PhotoMate887 だと欠落しないので,Android 固有の問題なのかなぁ.

PhotoMate887 の NMEA 出力を全部 OFF にすれば Android 側は問題ないんだけど,今度は PC の本家 MtkDLut が "No signal." とか言っておかしくなるし.
ンー,どうしたもんか.

アプリアイコンも作ってみたが.コレジャナイ感がハンパねぇ(;´д⊂)
-----
一応データ欠落も解決して完成したので公開しとく.→MtkUtility
・Android2.2 以降用
・BlueTooth 経由の NMEA ログ出力頻度 (Flash へのログ書込み頻度のことではない) を勝手に変更します.
・PhotoMate887 と 1分以上接続できないときは,アプリを再起動するよろし
・ログが消えても泣かない

2012年3月19日月曜日

Android Bluetooth プロジェクト完了

Bluetooth モジュールの使い方は一通りわかったので,今日はデータロガー (H8 マイコン) に接続し,Android 側のソフトも Bluetooth 接続に改造してみた.

Android 側は Bluetooth Chat という優秀なサンプルがあるので,ここから必要なコードをコピペしたらほぼ終わった.ちょっとハマったのは,Bluetooth のマスター/スレーブと BluetoothSocket のサーバ/クライアントを混同していたことで,要は Desire が Bluetooth マスターであり BluetoothSocket のクライアントであった.
BluetoothSocket さえ取得してしまえば後は Ether だろうとファイルだろうと扱いは同じなので,コードの修正もそんなに多くなく,無事接続完了ヽ(´ー`)ノ

一番時間かかったのは,本題とは関係がない,接続先の Bluetooth デバイスの設定を一覧から選ぶ処理www

終わってみれば大した障害もなく簡単にできた.
世間では Android Open Accessory なる物がでてきて,組込みとかのハードが開発できるようだが,手軽さで行ったらこっちの Bluetooth シリアル変換使ったほうが上だろうな.

これで晴れて Fonera+ はお役御免に.

2012年3月17日土曜日

Android と BlueTooth 接続

BlueTooth⇔シリアル通信モジュールを Get ヽ(´ー`)ノ
この手のモジュールは日本では¥3K~4K くらいが最安値なんだけど,DealExtreme の SKU 104299 は破格の $8.20 (¥700 くらい).そのかわりマニュアルとか一切のドキュメントが無いという人柱臭がプンプンしまくるデンジャラスな一品www
とはいえ,先人たちがいろいろ解析してくれてるみたいなので,失敗しても¥700 (しかも中国からなのに送料無料) ならいいや,ということでポチッとな.

で,今日届いたので早速試してみる.内容物は,BT 基盤とケーブル一本のみ.
シリアルは RS-232C といいつつ電圧は 3.6~6V のようなので,PC とつなぐには電圧変換がめんどくさいので,とりあえず上の写真の通り Fonera+ のシリアルポートにつないでみた.この時に,Fonera+ への Ethernet 通信を全部シリアルポートに垂れ流すようにしているので,PC から Fonera+ へ接続すれば BT モジュールへのシリアル通信ができる.
BT モジュールはデフォルトで 9600bps なので,Fonera+ のシリアルポートもそのように設定する.

で,この BT モジュールには 2 つのモードがあって,一つは BT モジュールへの設定モード,もう一つは BT モジュールへのシリアル通信を BT 電波に垂れ流すモード.
BT モジュールへの設定は AT コマンドで行い,使えそうな AT コマンドはここの 2012/1/21 の書き込みにあった.↓↓↓
AT+VERSION 
  Returns the software version of the module
AT+BAUDx 
  Sets the baud rate of the module 
  1: 1200 
  2: 2400 
  3: 4800 
  4: 9600 (Default) 
  5: 19200 
  6: 38400 
  7: 57600 
  8: 115200 
  9: 230400
AT+NAME
  Sets the name of the module
  Any name can be specified up to 20 characters
AT+PINxxxx
  Sets the pairing password of the device
  Any 4 digit number can be used, the default 
  pincode is 1234
AT+PN 
  Sets the parity of the module

まず "AT" とだけ送ってみたら,"OK" が返ってきた.うっしゃあ,まずは BT モジュールとの通信が成功.
次にボーレートを 38400bps にするために "AT+BAUD6" を送ってみたら,"OK38400" が返ってきた.ここでちょっとハマったのは,TeraTerm で実験するとき,キーボードで手打ちするとコマンドが認識されないので,予めコマンド文字列をコピーしておいて TeraTerm にペーストすることと,改行文字は一切入れないこと.

BT モジュール⇔シリアルポートの通信・設定は成功したので,お次は BT モジュール⇔Android との通信をテスト.Android 側のアプリは,SENA BTerm Bluetooth Terminal をつかってみた.

ここで問題になるのが,BT モジュールをデータ垂れ流しモードにどうやって切り替えるのかということ.上の AT コマンドが載っていた投稿は「pin34 を…」とか書いてるけど,この方法だと余計な配線が必要なので,何か別の方法を模索していたんだけど,単純に BT モジュール⇔BT マスター の接続が確立すると垂れ流しモードに切り替わるっぽい.(そしてマスターとの接続が切れるとまた設定モードに戻る.)
垂れ流しモードでは当然ながら AT コマンドを送ってもそれが垂れ流されるだけなので,BT モジュールの設定はマスターと通信が確立する前に済まさなければならないっぽい.
ただし,ボーレートなどの設定はどこかに保存されているらしく,BT モジュールの電源を入れなおした後も変更した設定が有効だった.

こうして,無事に BT モジュール⇔Android 通信が成功ヽ(´ー`)ノ PC の TeraTerm で打った文字が BT 経由で Android に表示される.
接続が確立すると,BT モジュールの赤 LED が点滅から常時点灯に変わる.

Fonera の起動メッセージも BT 経由で表示できた.


値段の割に機能も必要十分で,当初の心配とは裏腹に制御も簡単で,結構遊べる一品.
これで,エリーゼから無線 LAN ルータが下ろせるよwww

2012年3月11日日曜日

マフラー磨き

リアナンバープレートステーを外したお陰でマフラー丸出しになって,なんとなくレーシーになったのはいいんだけど,マフラーが焼き付いていて見栄えがあまりよくない.
という訳で,定番のヤケトールを買ってきて磨いてみた.

これが施行前.

みんカラとかで他の人の施工しているのを見ても,1~2分でピカピカ! みたいな記事ばっかりなので,自分もパイプ全部ピカピカにしてやんよ! ってな意気込みでキコキコ磨いてみたけど,ヒジョ~に緩慢なペースでしか綺麗にならず(;´д⊂)

これが施行後.

20分位かけてやっと片方のテールパイプが綺麗になった.ここですでにやる気を喪失していたけど,片方だけ綺麗ってのもあんまりだなぁと,頑張ってもう片方のテールパイプも磨く.
ホントは奥に見えるパイプも磨きたかったけど,このペースだと磨ききる気がしなかったので諦めたヽ(´ー`)ノ 自分には磨きは極められないっす.

んーなんかやり方間違ってんのかなぁ?

2012年3月10日土曜日

https proxy 経由で Net::Google::Calender を使う

Aipo と Google カレンダー連携」で,perl スクリプトから python スクリプトを呼ぶという汚い実装をしていたのだけど,perl にも Net::Google::Calender があって,perl だけで完結して Google カレンダーを操作できそうなので,やってみたらハマった(汗

まず cygwin に Net::Google::Calendar 入れようとしたらうまくいかない.ここを見ながら無理やりインストール.

次に,Aipo を運用している某所はプロキシサーバ経由で http / https アクセスしなければならないので,まずここを見ながら,$ENV{HTTP_PROXY} $ENV{HTTPS_PROXY} を設定してみたら,「500 SSL negotiation failed:」とかで失敗した.
そこで,Net::Google::Calender が内部で使用している LWP の,proxy 経由の https 方法を検索して見つけたのがここ.LWP は proxy 経由の httpsをうまく扱えないので,ちょっと変わった設定をする必要がある.

ここで気を付けなければならないのは,$ENV{HTTPS_PROXY} = ... をした後 $ua->env_proxy; を呼んでしまうと,LWP が proxy 経由の https を処理しようとして (? ココらへんは仕組みがよくわからない),結局うまく動かない.
ここらへんのコードだと $ENV{HTTPS_PROXY} 設定後に $ua->env_proxy; を呼んでいるのだが,うちでは $ua->env_proxy; を外さないとダメだった.

で,そのように設定して Net::Google::Calender を動かしてみたら,
「500 Server closed connection without sending any data back at /usr/lib/perl5/site_perl/5.10/Net/Google/Calendar.pm line 619.」
とかで失敗.

んーと思って,Net::Google::Calender の new メソッドを見てみたら,
sub new {
    my ($class, %opts) = @_;
    $opts{_ua}   = LWP::UserAgent->new( max_redirect => 0 );
    $opts{_ua}->env_proxy; ←★★ここ★★
    $opts{_auth} = Net::Google::AuthSub->new( service => 'cl' );
    $opts{_cookie_jar} = HTTP::Cookies->new;
    $opts{no_event_modification} ||= 0;
    my $self = bless \%opts, $class;
    $self->_find_calendar_id if $opts{url};
    return $self;
}
変なところに env_proxy; が入ってる(;´д⊂)
という訳で,結局 Calender.pm の上記の行をコメントアウトしたら,うまく動いたヽ(´ー`)ノ

という訳で以下コード.
Net::Google::Calendar 部分のコードや設定はこちらを参考にさせていただいた.
以下のコードを utf-8 で保存して $UserName, $Password, $ProxyURL の設定を各自の設定に書き換えれば動くはず.
#!/usr/bin/perl -w

use encoding 'utf-8';
use Encode qw(from_to);
use DateTime;
use Net::Google::Calendar;
use strict 'vars';

# 設定
my $UserName    = 'hoge.fuga@gmail.com'; # xxxx@gmail.com
my $Password    = 'password';
my $ProxyURL    = 'http://proxy.server:8080';   # proxy がいらない場合は '' にする

# stdin を全部読み込んでいったん utf-8 に変換
$_ = join( '', <> );
from_to( $_, 'jis', 'utf-8' );
@_ = split( /\s*\x0D*\x0A/, $_ );

# メールのパース

my $Summery;
my $Location;
my $Description = '';
my $DateStart;
my $DateEnd;
my $AllDay  = 0;

while( $#_ >= 0 ){
    $_ = shift( @_ );
    
    if( $_ eq '[予定]' ){
        $Summery = shift( @_ );
    }elsif( $_ eq '[日時]' ){
        $_ = shift( @_ );
        if( m#(\d+)/(\d+)/(\d+)\s+(\d+):(\d+)[^\d]+(\d+):(\d+)# ){
            # 時間指定あり
            $DateStart = DateTime->new(
                time_zone   => 'local',
                year        => $1,
                month       => $2,
                day         => $3,
                hour        => $4,
                minute      => $5,
                second      => 0
            );
            
            $DateEnd = DateTime->new(
                time_zone   => 'local',
                year        => $1,
                month       => $2,
                day         => $3,
                hour        => $6,
                minute      => $7,
                second      => 0
            );
        }elsif( m#(\d+)/(\d+)/(\d+)# ){
            # 時間指定なし
            $DateStart = DateTime->new(
                time_zone   => 'local',
                year        => $1,
                month       => $2,
                day         => $3,
                hour        => 0,
                minute      => 0,
                second      => 0
            );
            
            $DateEnd = $DateStart->add( days => 1 );
            $AllDay = 1;
        }else{
            # よくわからない時間指定,とりあえず脱出
            exit( 0 );
        }
        
    }elsif( $_ eq '[場所]' ){
        $Location = shift( @_ );
    }elsif( $_ eq '[内容]' ){
        while( $#_ >= 0 ){
            $_ = shift( @_ );
            last if( $_ =~ /^\[/ );
            
            $Description .= "\n" if( $Description ne '' );
            $Description .= $_;
        }
    }
}

# ログイン
my $Cal = Net::Google::Calendar->new();
if( $ProxyURL ){
    # proxy 設定
    $Cal->{_ua}->proxy( 'http', $ProxyURL );
    $ENV{ 'HTTPS_PROXY' } = $ProxyURL;
}
$Cal->login( $UserName, $Password );

# イベントのエントリー
my $Entry = Net::Google::Calendar::Entry->new();
$Entry->title( $Summery );
$Entry->content( $Description ) if( $Description );
$Entry->status( 'confirmed' );
$Entry->location( $Location )   if( defined( $Location ));
$Entry->transparency( 'opaque' );
$Entry->visibility( 'private' );
$Entry->when( $DateStart, $DateEnd, $AllDay );
$Cal->add_entry( $Entry );