コグノスケ


link 未来から過去へ表示(*)  link 過去から未来へ表示

link もっと前
2024年3月17日 >>> 2024年3月4日
link もっと後

2024年3月14日

JavaとM5Stamp C3とBluetooth LE - Bluetoothデバイスとの通信

目次: Arduino

M5Stamp C3をBluetooth LEデバイスにして、Linux PCもしくはRaspberry PiなどのLinux SBCとお話する取り組みの続編です。

今回はbluez-dbusを使ってBluetoothデバイスと通信します。

データ通信の仕組み

前回の話と少し重複しますが、Bluetoothデバイス特にBLEデバイスとはGATTプロファイルを使って通信します。BLEデバイスはサーバーになります。サーバーはService(=提供する機能)を1つもしくは複数持っていて、Service、Characteristic、ValueとDescriptorが入れ子の構造になっています。

GATTサーバー(BLEデバイス)
Service
Characteristic
  • Value
  • Descriptor
  • Descriptor
  • ...

GATTのデータ送受信はCharacteristicのValueを読み書きすることで実現します。まずは簡単な送信側(Write)からご紹介します。

送信の方法、クライアント→サーバー(BLEデバイス)

private BluetoothGattCharacteristic GattTx;

byte[] dat = new byte[len];

//送信するデータを用意する
//...

GattTx.writeValue(bpart, null);

バイト配列を用意してwriteValue()を呼びます。書き換え属性を持っているCharacteristicでないと書き込みが失敗します。

次は受信側(Read)です。writeValue()と同様にreadValue()も用意されていて、最後にReadした値を読み出せます。しかし一度読んだ値なのか新しい値なのか区別が付きません、つまり値の更新の有無がわかりません。

最新の値を読む方法、サーバー(BLEデバイス)→クライアント

BluetoothGattCharacteristic GattRx;

byte[] dat = GattRx.readValue(null);

ではこの方法はダメなのか?というとそんなことはありません。一定時間ごとに現在値を見たい場合、例えば「温度計の値を1分ごとに読み出す」といった用途で役立ちます。

一方でストリームデータを扱う場合、新しい値がきたときだけ読み出したいので更新を検出する必要があります。検出には少しややこしい処理が必要です。bluez-dbusは何かの状態変化が起きるとPropertiesChangedというイベントで知らせてくることを利用します。使い方は、

  • AbstractPropertiesChangedHandlerを継承したハンドラクラスを作成
  • ハンドラクラスのインスタンスをDeviceManagerに登録
  • BluetoothGattCharacteristicのstartNotify()を呼ぶ(BLEデバイスからのNotifyを検知できるようになる)

コードで書くと下記のようになります。

状態変化イベントのハンドラ登録

public class PropertiesChangedHandler extends AbstractPropertiesChangedHandler {
    @Override
    public void handle(Properties.PropertiesChanged props) {
    }
}

BluetoothGattCharacteristic GattRx;

DeviceManager deviceManager = DeviceManager.getInstance();
PropertiesChangedHandler handler = new PropertiesChangedHandler(...);
deviceManager.registerPropertyHandler(handler);

GattRx.startNotify();

PropertiesChangedハンドラはCharacteristicsの値の更新も、別の関係ないイベントも何でも受け取るので、何のイベントが発生したか判定する必要があります。bluez-dbusのBluetoothGattCharacteristicクラスと、PropertiesChangedクラスはいずれもD-Busのパス(/org/bluez/hci0/dev_xx_xx_xx_xx_xx_xx/service0028/char0029のような文字列)を返すメソッドを持っていますので、D-Busのパスが一致するかどうかで確かめます。

変化した値と名前のMapをgetPropertiesChanged()で取得できるので、全要素を調べて名前がValueであり、バイト配列を保持していればCharacteristicの値の変化を通知するイベントのはずです。

イベントの種類の判別(簡易版)

BluetoothGattCharacteristic GattRx;

Map<String, Variant<?>> mapProp = props.getPropertiesChanged();

if (GattRx.getDbusPath().equalsIgnoreCase(props.getPath())) {
    for (Map.Entry<String, Variant<?>> e : mapProp.entrySet()) {
        if (e.getValue().getValue() instanceof byte[]) {
            dat = (byte[])e.getValue().getValue();
        }
    }
}

自分でBLEデバイス側の実装をしているなら、意図しないイベントが混ざることはありません。上記のコードのように簡素なチェック(例えば単にバイト配列かどうかだけチェック)でも動作するはずです。

編集者:すずき(2024/03/16 23:03)

コメント一覧

  • コメントはありません。
open/close この記事にコメントする



2024年3月10日

誕生日

早いもので41歳になりました。昨年の日記(2023年3月10日の日記参照)を見ると、コロナの流行を心配していました。

コロナの流行は相変わらずのように思いますが、世の人々はもう対策に疲れたのか、感染リスクを無視して暮らすスタイルが定着したようです。個人的には感染しないに越したことはないので、これからもマスクなど予防は心がけたいと思います。花粉症にもなりたくないし……。

働き方はリモート10割から、リモート:出社=7:3〜5:5くらいの割合に落ち着きつつあります。特にオフィスに用事がなければ行かないなんて、昔では考えられない通勤スタイルですね。

この働き方の利点は「遠隔地に居る人」が気にならなくなることです。オフィスに集まる場合を除けば、家も沖縄も北海道も大して変わらないのです。実際、東京から離れて住んでいる人もいるようですね。

編集者:すずき(2024/03/15 03:34)

コメント一覧

  • コメントはありません。
open/close この記事にコメントする



2024年3月9日

車のバッテリー完全に死亡で交換かと思いきや

目次:

またまた車のバッテリーが干上がって死にました。写真は撮っていませんが2Vくらいになっていたように思います。

しかし今日はディーラーでの半年点検の日でディーラーに行かなければならないので、ジャンプスタートしてエンジンをかけてディーラーまで行きました。去年買った(2023年4月22日の日記参照)KashimuraのジャンプスターターKD-238が大活躍です。活躍しないほうが本当は良いけど。

ディーラーに辿り着いて車を預けたら、ディーラーの駐車場から動かそうとしたらバッテリーが上がってて動かせなかった、ジャンプスタートしたと言われました。ごめんね……。

ディーラーからの意外な提案

またバッテリー交換で財布が軽くなるな〜と思っていたら、整備士さんからは意外な提案が返ってきました。

  • 一時的にディーラー所有のバッテリーに交換して車を返す
  • 上がった方のバッテリーは1週間掛けて充電してみる
  • バッテリーが充電できたら連絡するからまた来てほしい

とのこと。

バッテリー交換以外の新たなパターンに出会いました。交換して1年、走行距離も1000km程度、バッテリーはこんなに劣化しないはず?と判断したみたいです。たぶん安く何とかしてみたい、というご提案だと理解して素直に承諾しました。

バッテリー復活なるか?いつもと違うので楽しみですね。

編集者:すずき(2024/03/16 00:56)

コメント一覧

  • コメントはありません。
open/close この記事にコメントする



2024年3月8日

JavaとM5Stamp C3とBluetooth LE - BluetoothデバイスとServiceの列挙

目次: Arduino

M5Stamp C3をBluetooth LEデバイスにして、Linux PCもしくはRaspberry PiなどのLinux SBCとお話する取り組みの続編です。

今回はbluez-dbusを使ってBluetoothデバイスの列挙、GATTのServiceの列挙を行います。

アダプタとデバイスの列挙

DeviceManagerというクラスとDeviceManagerクラスのスタティックメソッドが、bluez-dbusを使うときの根っこになります。

DeviceManagerのインスタンスを作成するため最初にcreateInstance()を呼ぶ必要があります。1回で良いです。これ以降はDeviceManager.getInstance()でDeviceManagerのインスタンスが取得できます。引数はfalseならシステム全体用のバスインタフェース、trueなら現在のログインセッション用のバスインタフェースに接続します。Bluetoothの仕組みとは関係なくて、Bluezが依存しているD-Busの仕組みが透けて見えています。たぶんfalseで良いはず。

bluez-dbusの初期化、createInstance()の呼び出し

//一番最初に1回呼ぶ
DeviceManager.createInstance(false);

//以降はgetInstance()でDeviceManagerオブジェクトを取得できる
DeviceManager.getInstance();

システムに存在するBluetoothアダプターの一覧を得る方法はこんな感じです。お手軽です。

Bluetoothアダプタの列挙

DeviceManager deviceManager = DeviceManager.getInstance();

List<BluetoothAdapter> adapters = deviceManager.getAdapters();

Bluetoothアダプターを1つ選んだら、Bluetoothデバイスを探して(Discovery)、ある程度時間を置いて見つかったデバイスの一覧を取得します。

Bluetoothデバイスの列挙

BluetoothAdapter adapter;

adapter.startDiscovery();
try {
    Thread.sleep(3000);
} catch (InterruptedException ex) {
    //ignore
}
adapter.stopDiscovery();

List<BluetoothDevice> devices = deviceManager.getDevices(true);

注意点としてはstartDiscovery()とstopDiscovery()の間はある程度の時間を開けないとデバイスが1個も見つかりません。

Serviceの列挙

Bluetoothデバイス特にBLE(Bluetooth Low Energy)デバイスとはGATTプロファイルを使って通信します。BluetoothにはATTプロトコル(Attribute Protocol)という属性をやり取りするプロトコルがあります。GATTはATTプロトコルの上で汎用的(Generic)にデータを通信するための取り決め(プロファイル)になります。

GATTというかATTはクライアント・サーバー方式のプロトコルでして、BLEデバイスはサーバーになります。サーバーはService(=提供する機能)を1つもしくは複数持っています。1つのService内にはCharacteristicが並んでおり、CharacteristicにはValueとDescriptorが並んでいます。こんな感じです。

GATTサーバー(BLEデバイス)
Service
Characteristic
  • Value
  • Descriptor
  • Descriptor
  • ...
Characteristic
  • Value
  • Descriptor
Service
Characteristic
...
Characteristic
...

通信に使うのはCharacteristicですが、いきなりCharacteristicを列挙することはできません。上位側にあるServiceから列挙します。Serviceを探すにはconnect()してgetGattServices()を呼びます。connect()とdisconnect()は数秒レベルで時間がかかります。

今回はM5Stamp C3に対してペアリングなしで接続しています。ペアリングなし=通信路の盗聴や乗っ取りをされる可能性があります。今回は特に困らないのでこのまま話を進めますが、盗聴や乗っ取りをされると困る場合はペアリングをする必要があります。ペアリングの方法もご紹介したいですが、今はやり方がわかりません。わかったらまた別の日記にでも書きます。

Serviceの列挙
BluetoothDevice device;
device.connect();
device.refreshGattServices();

List<BluetoothGattService> gattServices = device.getGattServices();

device.disconnect();

GATTのService内のCharacteristicを探すにはgetGattCharacteristics()を呼びます。

Characteristicの列挙

BluetoothGattService srv;
srv.refreshGattCharacteristics();

List<BluetoothGattCharacteristic> gattCharacteristics = srv.getGattCharacteristics();

CharacteristicのDescriptorも取得できます(getGattDescriptors()メソッドを使います)が、今回は特に必要ありませんので列挙するためのコードは割愛します。

送受信の方法はまた今度。

編集者:すずき(2024/03/16 23:03)

コメント一覧

  • コメントはありません。
open/close この記事にコメントする



2024年3月6日

Raspberry Pi 3 model Bの代わりにROCK 3 model C

目次: Arduino

最近、M5Stamp C3 + Raspberry Piを組み合わせて的あてゲームを作っています。Bluetooth通信クライアント側のLinuxマシンにRaspberry Pi 3 model Bを使っているものの、販売終了につき新品が手に入りません。今は1台あれば良いので困りませんが、後でN増しするとき困りそうです。

Linuxマシン側の要件を挙げると、

  • Must: Linuxが動作、x86でもARMでも良い
  • Must: HDMI出力、USBホスト機能
  • Want: Bluetooth 4.0以上(BLEを使う)
  • Want: Raspberry Pi 3より速い、Raspberry Pi 5ほど性能は要らない
  • Want: 昔のRaspberry Pi 3Bくらいの価格(5,000円くらい)

まず値段的にx86のノートPCやNUCは購入候補から外れます(中古品でも厳しい)。ARMのSBCですと、FRIENDLY ELECのNanoPi R5系(Rockcihp RK3568B, Cortex-A55 x 4)か、OKDO/Radxa ROCK 3 model C 1GB版(Rockchip RK3566, Cortex-A55 x 4)がちょうど良さそうでした。

NanoPiとROCK 3はどちらでも良かったのですが、RSコンポーネンツで容易に購入できるROCK 3 model C 1GB版に決めました。

JavaのGraphics 2Dが遅い?

ROCK 3 model CはRaspberry Pi 3 model Bを置き換えるにふさわしい製品だと思いますが、私の使い方だと1点だけ問題があって、Javaの画面描画が致命的に遅いです。5秒に1回くらいしか描画されません。このままでは使いたい目的に合いません。

最初にGPUが有効になっているか確認です。GPU使用率を/sys/devices/platform/fed60000.gpu/utilizationを見ると、無負荷のときは0、アプリ起動時で20くらいでGPUは動いています。問題なさそうです。むしろ暇しているというか余裕すらありそうです。Javaのライブラリ系orアプリ実装の問題でしょう。

次にJavaのライブラリ系を確認です。現在、画面描画のダブルバッファリングに使っているのはBufferStrategyで、BufferStrategyが返すVolatileImageのisAccelerated()はTrueを返します。OpenGLによるHW描画が使われているようです。これも問題なさそうです。残るはアプリ実装の問題ですね。

余談ですが下記のようにGraphics2D経由で確認すると、

Graphics2D経由でisAccelerated()を呼ぶ
((Graphics2D)strategy.getDrawGraphics()).getDeviceConfiguration().getImageCapabilities().isAccelerated()

なぜかisAccelerated()がFalseになります。良くわからん動きです。

Graphics2Dのアンチエイリアス機能が遅い

タイトルの通りですが、アプリ実装が原因でした。コードでいえば下記の部分です。

図形描画とテキスト描画のアンチエイリアスON

Graphics2D g2;

g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);

図形描画とテキスト描画のアンチエイリアスをONにして使っていましたが、このうち図形描画のアンチエイリアスをONにすると著しく描画速度が下がることがわかりました。Raspberry Pi 3 model Bは双方のアンチエイリアスをONにしても特に問題がなかったため、気づくまで結構手間取りました。

図形描画のアンチエイリアスは今のところ見た目にさほど影響がないので、OFFにしました。テキスト描画のアンチエイリアスも描画速度に多少影響ありますが、OFFにすると見た目が悪くなりすぎるので、ONのまま使います。

問題の解決はしていませんが、回避できたのは良かったです。勢いで3つも買ってしまったROCK 3 model Cの不良在庫化を避けられました……。

編集者:すずき(2024/03/12 01:18)

コメント一覧

  • コメントはありません。
open/close この記事にコメントする



2024年3月4日

volatileをnon-volatileで参照してはいけない

目次: GCC

過去の日記(2021年3月13日の日記参照)にプログラムがバグっていて未定義動作だ(つまりGCCのせいじゃない)とコメントいただいたので、C11規格を眺めていました。

C11 committee draft(N1570) 6.7.3 Type qualifiersの6に、volatileとnon-volatileを併用したときの未定義動作の記述がありました。

N1570
6.7.3 Type qualifiers

...

6
If an attempt is made to modify an object defined with a const-qualified type through use of 
an lvalue with non-const-qualified type, the behavior is undefined. If an attempt is made to 
refer to an object defined with a volatile-qualified type through use of an lvalue with 
non-volatile-qualified type, the behavior is undefined. 133)

133) This applies to those objects that behave as if they were defined with qualified types, 
even if they are never actually defined as objects in the program (such as an object at a 
memory-mapped input/output address).

(ざっくり訳)
const-qualified型で定義したオブジェクトをnon-const-qualified型の左辺値(lvalue)を使用して変更した場合、
動作は未定義です。volatile-qualified型で定義したオブジェクトを、non-volatile-qualified型の左辺値で参照した場合、
動作は未定義です。

133)
たとえプログラム内でオブジェクトとして定義されていなくても、これ(注: 上記の6のこと)は修飾された型で定義されたように
振る舞うオブジェクト(メモリマップされたI/Oアドレスにあるオブジェクトなど)に適用されます。

未定義動作ならmemmoveやmemcopyに何が起きても不思議ではないですね。C言語難しいわ……。

編集者:すずき(2024/03/06 00:09)

コメント一覧

  • コメントはありません。
open/close この記事にコメントする



link もっと前
2024年3月17日 >>> 2024年3月4日
link もっと後

管理用メニュー

link 記事を新規作成

<2024>
<<<03>>>
-----12
3456789
10111213141516
17181920212223
24252627282930
31------

最近のコメント5件

  • link 24年10月1日
    すずきさん (10/06 03:41)
    「xrdpで十分動作しているので、Wayl...」
  • link 24年10月1日
    hdkさん (10/03 19:05)
    「GNOMEをお使いでしたら今はWayla...」
  • link 24年10月1日
    すずきさん (10/03 10:12)
    「私は逆にVNCサーバーに繋ぐ使い方をした...」
  • link 24年10月1日
    hdkさん (10/03 08:30)
    「おー、面白いですね。xrdpはすでに立ち...」
  • link 14年6月13日
    2048player...さん (09/26 01:04)
    「最後に、この式を出すのに紙4枚(A4)も...」

最近の記事20件

  • link 24年10月28日
    すずき (10/30 23:49)
    「[Linuxからリモートデスクトップ] 目次: Linux開発用のLinuxマシンの画面を見るにはいろいろな手段がありますが、...」
  • link 23年4月10日
    すずき (10/30 23:46)
    「[Linux - まとめリンク] 目次: Linux関係の深いまとめリンク。目次: RISC-V目次: ROCK64/ROCK...」
  • link 24年10月24日
    すずき (10/25 02:35)
    「[ONKYOからM-AUDIOのUSB DACへ] 目次: PCかれこれ10年以上(2013年3月16日の日記参照)活躍してく...」
  • link 24年7月25日
    すずき (10/25 02:24)
    「[OpenSBIを調べる - デバイスツリーの扱い(別方法)] 目次: LinuxOpenSBIのブート部分を調べます。Ope...」
  • link 24年8月7日
    すずき (10/25 02:23)
    「[Debian独自の挙動をするQEMUとbinfmt_misc] 目次: Linux前回はbinfmt_miscの使い方や動作...」
  • link 24年9月9日
    すずき (10/25 02:22)
    「[GDBの便利コマンド] 目次: LinuxGDBは便利ですが、少し使わないでいるとあっという間にコマンドを忘れます。便利&使...」
  • link 24年10月20日
    すずき (10/25 02:22)
    「[ゲームを買ったら遊びましょう2] 目次: ゲーム前回の振り返り(2022年5月13日の日記参照)から2年半経ちました。所持し...」
  • link 24年8月2日
    すずき (10/25 02:21)
    「[Debian on RISC-V] 目次: LinuxOpenSBI + Linuxの環境まで動いたので、次はLinuxのデ...」
  • link 24年8月6日
    すずき (10/25 02:21)
    「[他アーキテクチャ向けバイナリを実行する仕組みbinfmt_misc] 目次: LinuxRISC-V 64bit用の実行ファ...」
  • link 24年8月27日
    すずき (10/25 02:20)
    「[Milk-V Jupiterが届いた] 目次: RISC-VMilk-V Jupiterが届きました。お値段が非常に安かった...」
  • link 24年9月13日
    すずき (10/25 02:20)
    「[OpenSBIを調べる - OpenSBIとRISC-V ISA extensions] 目次: Linux今回はOpenS...」
  • link 24年10月11日
    すずき (10/25 02:19)
    「[企業のドメイン] 今の企業は公式サイトを持っていなほうが珍しいと思いますが、ドメイン名の使い方は各社でバラバラで面白いです。...」
  • link 24年10月21日
    すずき (10/25 02:18)
    「[OpenPilotを調べる - プロセス間通信msgqの仕組み] 目次: OpenPilot最近はOSSの運転支援ソフトウェ...」
  • link 24年10月6日
    すずき (10/25 02:11)
    「[OpenPilotを調べる - ビルドと実行] 目次: OpenPilot最近はOSSの運転支援ソフトウェアOpenPilo...」
  • link 24年7月13日
    すずき (10/25 02:10)
    「[RISC-V 64向けLinuxブートローダー(OpenSBI)の構築] 目次: Linux以前、Berkeley Boot...」
  • link 24年7月19日
    すずき (10/25 02:09)
    「[OpenSBIを調べる - ブート処理とペイロード] 目次: LinuxOpenSBIのブート部分を調べます。OpenSBI...」
  • link 24年7月23日
    すずき (10/25 02:08)
    「[OpenSBIを調べる - QEMUのデバイスツリー] 目次: LinuxOpenSBIのブート部分を調べます。OpenSB...」
  • link 24年7月24日
    すずき (10/25 02:08)
    「[OpenSBIを調べる - デバイスツリーの扱い(genericプラットフォーム)] 目次: LinuxOpenSBIのブー...」
  • link 24年6月27日
    すずき (10/25 02:07)
    「[何もない組み込み環境でDOOMを動かす - その4 - 自作OSの組み込み環境へ移植] 目次: RISC-V目次: 独自OS...」
  • link 24年6月24日
    すずき (10/25 02:06)
    「[何もない組み込み環境でDOOMを動かす - その1 - 準備編] 目次: RISC-VみなさまはDOOMをご存じでしょうか?...」
link もっとみる

こんてんつ

open/close wiki
open/close Linux JM
open/close Java API

過去の日記

open/close 2002年
open/close 2003年
open/close 2004年
open/close 2005年
open/close 2006年
open/close 2007年
open/close 2008年
open/close 2009年
open/close 2010年
open/close 2011年
open/close 2012年
open/close 2013年
open/close 2014年
open/close 2015年
open/close 2016年
open/close 2017年
open/close 2018年
open/close 2019年
open/close 2020年
open/close 2021年
open/close 2022年
open/close 2023年
open/close 2024年
open/close 過去日記について

その他の情報

open/close アクセス統計
open/close サーバ一覧
open/close サイトの情報

合計:  counter total
本日:  counter today

link About www.katsuster.net
RDFファイル RSS 1.0

最終更新: 10/30 23:49