(続き)Bluetooth近接検知装置
前回書いたシェルスクリプトは、BlueZに付属しているhcitoolを使ったけどひとつ問題がありました。デバイスが検知範囲外の場合に、探す時間が長すぎるという問題。スクリーンセーバーの応用では特に問題ないけど、ラップタイマーの場合は、10秒とか考え込んでしまうと困るので、2,3秒で見つからなければ検索を止めてほしかった。
そこで、最初はPerlで書き直して、fork()した上でhcitoolを使い、親プロセスで3秒経ったらhcitoolが走っている子プロセスをTERMするというのを試してみたのだけど、なぜか知らないけど10回くらいTERMしたらデバイスがおかしくなってしまったみたいで、検知範囲にあるのに検知できなかったりした。がっかり。
どうにか待ち時間を指定できないのかと調べていたら、Inline::Cを使った例に、BlueZのライブラリを直接使う方法が書いてあったので、やってみたよ。つまりlibbluetoothでexportされているhci_read_remote_nameという関数で、待ち時間を指定できる。その間CPANのProxy設定、LD_LIBRARY_PATHの環境変数の設定などいろいろ障害物はあったけど。。。まあ満足がいくように動きます。以下がhcitool nameに相当するモノ。例では2秒に設定してあります。
#! /usr/bin/perluse Inline C => Config =>
MYEXTLIB => '/usr/local/lib/libbluetooth.so';
use Inline C => <
#include
#include
#include
#include
#include
#include
#include#include
#include
#include
#include
#include
#include
#include#include
#include
#includeSV * devname( char * address )
{
bdaddr_t bdaddr;
char name [248];
int dd;
str2ba( address, &bdaddr );
int dev_id;
dev_id = hci_get_route(&bdaddr);
if ( dev_id < 0 )
{
/* printf("Device not available"); */
return ( newSVpvf("") );
}dd = hci_open_dev(dev_id);
if ( dd < 0 )
{
/* printf("HCI device open failed"); */
return ( newSVpvf("") );
}if ( hci_read_remote_name( dd, &bdaddr, sizeof(name), name, 2000 ) != 0 )
{
close(dd);
return ( newSVpvf("") );
}close(dd);
return ( newSVpvf( "%s", name ) );
}EOT
#-------------------------------------------------------------------
use strict;
use warnings;printf(devname("00:0b:0d:40:f1:4f") . "\n");
関係ないけど、Perlの編集はEclipseのプラグインでして、sambaでシェアしたvmwareのドライブに直接保存していたら、改行コードがおかしいことに気が付いて(Windows XPでEclipseを動かしているのでLFじゃなくてCRLFになっている)調べた結果、Exclipseの開発で長いこと検討されているのに標準のグローバルスイッチが無いらしいことを発見(Javaの環境変数に依存するみたい)。でもとりあえずメニューから[File - Convert Line Delimiter - UNIX]で解決しました。