(続き)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/perl

use 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
#include

SV * 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]で解決しました。