JavaからBluetoothを扱う方法を調べてもなかなか前例がなかったので、 JNAを使ってSimpleBLE を使ってみたのでメモ。
そのうちラッパーとか作るかも。
手順
まずはReleasesから
実行環境にあった共有ライブラリ simpleble_shared_${OS}-${ARCH}.zip
をダウンロードしてくる。
runner/work/SimpleBLE/SimpleBLE/build/install/lib
の中に共有ライブラリ(macOSの場合はdylib)が入っているので、
適当なところに配置する。
以降、このパスを ${DYNAMIC_LINK_LIBRARY_PATH}
とする。
以下のコードを実行したらBLEデバイスのスキャンを開始し、 画面に見つかったデバイスの情報を表示する。
※ 「実行時に開発源が未確認〜」と表示されたら、 システム環境設定 > プライバシーとセキュリティ
から実行を許可する。
import com.sun.jna.Library;
import com.sun.jna.Structure;
import com.sun.jna.NativeLibrary;
import com.sun.jna.Native;
import com.sun.jna.Structure;
import com.sun.jna.PointerType;
import com.sun.jna.IntegerType;
import com.sun.jna.Pointer;
import com.sun.jna.Callback;
import com.sun.jna.Platform;
// 検出したデバイスの情報をとりあえず文字列で格納するArrayList
ArrayList<String> devices = new ArrayList<String>();
void setup() {
// 共有ライブラリの検索パスを追加して読み込み
String nativeLibraryPath = "${DYNAMIC_LINK_LIBRARY_PATH}";
NativeLibrary.addSearchPath("simpleble-c", nativeLibraryPath);
SimpleBLE simpleBle = (SimpleBLE)Native.load("simpleble-c", SimpleBLE.class);
// BLEアダプタが利用できない or BLEアダプタが無い場合は終了
if (!simpleBle.simpleble_adapter_is_bluetooth_enabled() || simpleBle.simpleble_adapter_get_count().intValue() == 0) {
exit();
}
// 0番目のBLEアダプタを取得
simpleble_adapter_t adapter = simpleBle.simpleble_adapter_get_handle(new size_t(0));
if (adapter == null) {
println("No adapter was found.\n");
exit();
}
// スキャンを開始した際のコールバックを登録
simpleBle.simpleble_adapter_set_callback_on_scan_start(
adapter,
new simpleble_adapter_set_callback_on_scan_start_callback() {
public void invoke(simpleble_adapter_t adapter, userdata userdata) {
println(adapter);
println(userdata);
}
}
, null);
// 周辺機器が見つかった際のコールバックを登録
// 見つかったらdevicesに追加
simpleBle.simpleble_adapter_set_callback_on_scan_found(
adapter,
new simpleble_adapter_set_callback_on_scan_found_callback() {
public void invoke(simpleble_adapter_t adapter, simpleble_peripheral_t peripheral, userdata userdata) {
String adapter_identifier = simpleBle.simpleble_adapter_identifier(adapter);
String peripheral_identifier = simpleBle.simpleble_peripheral_identifier(peripheral);
String peripheral_address = simpleBle.simpleble_peripheral_address(peripheral);
if (adapter_identifier == null || peripheral_identifier == null || peripheral_address == null) {
return;
}
String device = String.format("Adapter %s\nfound device: %s [%s]\n", adapter_identifier, peripheral_identifier, peripheral_address);
println(device);
devices.add(device);
simpleBle.simpleble_free(peripheral);
simpleBle.simpleble_free(peripheral_address);
simpleBle.simpleble_free(peripheral_identifier);
}
}
, null);
// 周辺機器のスキャンを開始
simpleBle.simpleble_adapter_scan_for(adapter, 5000);
size(500, 500);
}
void draw() {
background(100);
for (int i = 0; i < devices.size(); i++) {
text(devices.get(i), 10, i * 35 + 20);
}
}
/**
* C用のSimpleBLEで使われる関数を呼び出すためのインタフェース
*/
interface SimpleBLE extends Library {
boolean simpleble_adapter_is_bluetooth_enabled();
size_t simpleble_adapter_get_count();
simpleble_adapter_t simpleble_adapter_get_handle(size_t i);
int simpleble_adapter_set_callback_on_scan_start(simpleble_adapter_t handle, simpleble_adapter_set_callback_on_scan_start_callback callback, userdata userdata);
int simpleble_adapter_scan_for(simpleble_adapter_t handle, int timeout_ms);
int simpleble_adapter_set_callback_on_scan_found(simpleble_adapter_t handle, simpleble_adapter_set_callback_on_scan_found_callback callback, userdata userdata);
String simpleble_adapter_identifier(simpleble_adapter_t handle);
String simpleble_peripheral_identifier(simpleble_peripheral_t peripheral);
String simpleble_peripheral_address(simpleble_peripheral_t peripheral);
void simpleble_free(handle handle);
void simpleble_free(String handle);
}
/**
* size_t用のクラス
*/
public static class size_t extends IntegerType {
private static final long serialVersionUID = 1L;
public size_t() {
this(0);
}
public size_t(long value) {
super(Native.SIZE_T_SIZE, true);
setValue(value);
}
}
/**
* simpleble_adapter_set_callback_on_scan_startの引数に渡すコールバックのインタフェース
*/
public interface simpleble_adapter_set_callback_on_scan_start_callback extends Callback {
public void invoke(simpleble_adapter_t adapter, userdata userdata);
}
/**
* simpleble_adapter_set_callback_on_scan_foundの引数に渡すコールバックのインタフェース
*/
public interface simpleble_adapter_set_callback_on_scan_found_callback extends Callback {
public void invoke(simpleble_adapter_t adapter, simpleble_peripheral_t peripheral, userdata userdata);
}
/**
* アダプタを抽象化したポインタ
*/
public static class simpleble_adapter_t extends handle {
public simpleble_adapter_t() {
super();
}
public simpleble_adapter_t(Pointer p) {
super(p);
}
}
/**
* userdataを抽象化したポインタ(まだ用途がわからない)
*/
public static class userdata extends handle {
public userdata() {
super();
}
public userdata(Pointer p) {
super(p);
}
}
/**
* 周辺機器を抽象化したポインタ
*/
public static class simpleble_peripheral_t extends handle {
public simpleble_peripheral_t() {
super();
}
public simpleble_peripheral_t(Pointer p) {
super(p);
}
}
/**
* simpleble_free用に一応定義しておいた
*/
public static class handle extends PointerType {
public handle() {
super();
}
public handle(Pointer p) {
super(p);
}
}
参考文献
- https://github.com/OpenBluetoothToolbox/SimpleBLE/blob/main/examples/simpleble/c/scan.c
- https://github.com/OpenBluetoothToolbox/SimpleBLE/blob/main/simpleble/include/simpleble_c/adapter.h
- https://github.com/OpenBluetoothToolbox/SimpleBLE/blob/main/simpleble/include/simpleble_c/types.h
- https://mkguytone.github.io/java-opencl/ch05s04.html
- https://qiita.com/everylittle/items/b888cbec643f14de5ea6