この記事は Android スマホ用のアプリ開発の中で、
今後の開発で再使用性が高いと思われるコーディングをまとめたものです。
Java での開発経験、XML 構文規則、Android のアプリ開発経験がある方を対象としています。
Android のアプリ開発でお役にたててれば、嬉しいです。
(これから Android のアプリ開発や Java での開発を始めたい方への案内は、記事の最後で紹介します)
Android3.1以降でUSBホストモードがサポートされました。
この機能を使用すれば、接続したUSBデバイスとデータ受送信などシリアル通信の実装が可能です。
USBホストとアクセサリの概要
センサー自体はRS-232Cなどのシリアル通信で行い、通信を中継するUSBシリアル変換をもつUSBデバイスが存在します。この場合、通信相手はセンサーモジュールではなく、USB変換モジュールです。
USB変換モジュールには、FTDI、CP2102、CH340、PL2303などが存在します。
それぞれのモジュールにドライバーが存在し、アプリで個々に対応するのかなり面倒です。
usb-serial-for-androidは、モジュールの種類を意識することなく透過的にシリアル通信を可能とするライブラリです。
usb-serial-for-androidは、Androidで使用できるオープンソフトウェアライブラリです。
USB変換モジュールは、PL2303GC(Prolific)です。
usb-serial-for-androidを使用するための準備
usb-serial-for-androidを使用するには、
プロジェクトおよび、モジュールのbuild.gradleファイル、settings.gradleに定義の追加が必要です。
◎build.gradle(プロジェクト)
:
allprojects {
repositories {
:
maven { url 'https://jitpack.io' }
}
}
:
◎build.gradle(モジュール)
2024年10月現在の最新バージョンは 3.8.0 です。
dependencies {
:
implementation 'com.github.mik3y:usb-serial-for-android:3.8.0'
}
◎settings.gradle
:
dependencyResolutionManagement {
repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
repositories {
:
maven { url 'https://jitpack.io' }
}
}
:
◎ライセンス表記
usb-serial-for-androidは、MIT Licenseです。
アプリで使用する場合、ライセンス表記が必要です。
USBシリアル通信の実装
USBデバイスの接続とシリアル通信に分けて、USBシリアル通信を実装します。
USBデバイスの接続はUSBホストAPI、シリアル通信はusb-serial-for-androidを使用します。
サンプルは、サービスで実装しています。
USBホストの概要
USBデバイスの接続
USBデバイスの接続は、USBホストAPIで実装します。
UsbManagerを使用して、USBに接続しているデバイスを取得し、権限チェックを行います。
権限がない場合は、ユーザ承認リクエストを発行します。
権限がある、ユーザ承認リクエストでOKの場合は、シリアル通信の接続を生成します。
import com.hoho.android.usbserial.driver.FtdiSerialDriver;
import com.hoho.android.usbserial.driver.ProbeTable;
import com.hoho.android.usbserial.driver.UsbSerialDriver;
import com.hoho.android.usbserial.driver.UsbSerialPort;
import com.hoho.android.usbserial.driver.UsbSerialProber;
import com.hoho.android.usbserial.util.SerialInputOutputManager;
:
public class USBConnectService extends Service {
private static final String ACTION_USB_PERMISSION = "com.jiseifirm.mls.service.LocationService.USB_PERMISSION";
private UsbManager usbManager;
private UsbDevice device;
private Connect connect;
private int PORT = 0;
:
@Override
public void onCreate() {
super.onCreate();
// マルチポートのUSBに接続している場合、シリアル通信のポート(PORT)を指定
:
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
:
usbConnect();
return START_NOT_STICKY;
}
private void usbConnect() {
usbManager = (UsbManager) context.getSystemService(Service.USB_SERVICE);
// 接続するUSBデバイスのベンダーID(vender)とプロダクトID(product)
device = attachedDevice(vender, product);
if (device != null) {
if (usbManager.hasPermission(device)) {
// シリアル通信の接続を生成
//noinspection InstantiatingAThreadWithDefaultRunMethod
connect = new Connect(device);
} else {
PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 0, new Intent(ACTION_USB_PERMISSION).setPackage(getPackageName()), PendingIntent.FLAG_MUTABLE);
IntentFilter intentFilter = new IntentFilter(ACTION_USB_PERMISSION);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
registerReceiver(usbReceiver, intentFilter, RECEIVER_EXPORTED);
} else {
registerReceiver(usbReceiver, intentFilter);
}
usbManager.requestPermission(device, pendingIntent);
}
} else {
// 接続できるデバイスがない場合の処理
:
}
:
// USBデバイスの取得
private UsbDevice attachedDevice(int vender, int product) {
try {
for (UsbDevice usbDevice : usbManager.getDeviceList().values()) {
if (usbDevice.getVendorId() == vender & usbDevice.getProductId() == product) {
return usbDevice;
}
}
} catch (Exception e) {
// エラー処理
:
}
return null;
}
:
サンプルでは、接続するUSBデバイスのベンダーIDとプロダクトIDが一致するデバイスを取得しています。
取得したUSBデバイスの権限チェックは、UsbManagerのhasPermissionで行います。
マルチポートのUSBに接続している場合、シリアル通信のポート(PORT)を指定します。
◎承認リクエストの結果確認
承認リクエストの結果確認はBroadcastReceiverで行います。
// 承認リクエストの結果確認
private final BroadcastReceiver usbReceiver = new BroadcastReceiver() {
public void onReceive(Context context, Intent intent) {
if (ACTION_USB_PERMISSION.equals(intent.getAction())) {
synchronized (this) {
unregisterReceiver(usbReceiver);
if (intent.getBooleanExtra(UsbManager.EXTRA_PERMISSION_GRANTED, false)) {
// OKの場合の処理
:
} else {
// キャンセルの場合の処理
:
}
}
}
}
}
:
ユーザ承認リクエストの発行はPendingIntentを行いますが、PendingIntent生成時にFLAG_MUTABLEを指定しないと、Intentに結果がセットされないので、注意が必要です。
詳しくは、USBデバイスの権限チェックとユーザ承認リクエストを参照ください。