準備オーケー
- NDK環境
- シリアル通信に使用するCファイル
注:cファイル内の関数名のパスを変更する必要があり、cファイルと.hヘッダーファイルの両方を変更する必要があります
基盤となるライブラリへのアクセス
SOライブラリを使用してインポート
- メインディレクトリに新しいjniレコードを作成し、そこにCファイルを配置します
- 新しいAndroid.mk、Application.mkファイルを作成し、構成します
- プロジェクトをコンパイルし、コンパイルされたsoライブラリファイルを取得します。コンパイルされたリリースバージョンがreleasseディレクトリにある場合、デフォルトで生成されるディレクトリはapp \ build \ intermediates \ jniLibs \ app \ debug \ armeabiです。
- メインディレクトリの下に新しいディレクトリjniLibsを作成し、生成されたsoライブラリをこれにコピーします
- appディレクトリでgradleファイルを構成します
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
ndk {
moduleName "serial_port"
ldLibs "log", "z", "m"
abiFilters "armeabi", "x86"
}
}
debug {
ndk {
moduleName "serial_port"
ldLibs "log", "z", "m"
abiFilters "armeabi", "x86"
}
}
}
- コードでクラスファイルを作成し、soライブラリファイルをロードして、シリアルポートを開閉する方法を定義します
CMake紹介
- メインディレクトリに新しいcppフォルダーを作成し、ここにcソースファイルを配置します
- CMakeLists.txtファイルを構成します
cmake_minimum_required(VERSION 3.4.1)
# 查找cpp目录下的所有源文件
# 并将名称保存到 DIR_LIB_SRC 变量
aux_source_directory(src/main/cpp/ DIR_LIB_SRC)
#设置源文件
add_library(SerialPort SHARED ${DIR_LIB_SRC})
#表明头文件位置
#include_directories(src/main/cpp/)
find_library( # Sets the name of the path variable.
log-lib
log)
target_link_libraries( # Specifies the target library.
SerialPort
${log-lib})
- アプリの下でgradleファイルを構成します
android {
defaultConfig {
...
externalNativeBuild {
cmake {
cppFlags ""
}
}
}
externalNativeBuild {
cmake {
path "CMakeLists.txt"
}
}
}
- コードでクラスファイルを作成し、soライブラリファイルをロードして、シリアルポートを開閉する方法を定義します
シリアルポートの開閉
jniで開閉
Cファイルには、シリアルポートを開く方法と閉じる方法の2つの方法が定義されています。シリアルポートを開く方法には戻り値があり、戻り値はFileDescriptorオブジェクトです。このオブジェクトを使用して、シリアルポートのデータの読み取りと書き込みを行います。
シリアルポートを開く
シリアルポートのクエリ
一部のカスタマイズされたデバイスには多くのシリアルポートがある場合があります。アプリケーションで開く必要のあるシリアルポートはどれですか。接続する必要のあるシリアルポートの名前をデバイスの製造元に問い合わせることができます。一方、すべてのシリアルポートを一覧表示して、1つずつ試すことしかできません。
すべてのシリアルポートを照会する:
SerialPortFinderクラスを定義し、/ proc / tty / driversファイルを読み取って、デバイスのすべてのシリアルポートとパスを一覧表示します。
メソッド:SerialPortFinderの getAllDevices()メソッド。特定の実装についてはコードSerialPortFinderを参照してください。
オンにする
対応するシリアルポートを見つけたら、jniメソッドを呼び出してシリアルポートを開きます。開くときは、シリアルポートパス、ボーレート、開く方法の3つのパラメータを渡す必要があります。
public SerialPort getSerialPort() throws SecurityException, IOException, InvalidParameterException {
if (mSerialPort == null) {
//这里是打开了/dev/ttyS3 串口,波特率9600,
mSerialPort = new SerialPort(new File("/dev/ttyS3"), 9600, 0);
}
return mSerialPort;
}
シリアルポートを開くことにより、FileDescriptorオブジェクトが取得され、そのオブジェクトに基づいて入力および出力ストリームが作成され、読み取りおよび書き込み操作が実現されます。
シリアルポートを閉じる
使用後、アプリケーションを終了する前に、シリアルポートを閉じる必要があります。これは、ファイルストリームを閉じる必要があるファイル操作と同等です。シリアル通信は本質的にファイル操作であるため、閉じる必要があります。
/**
* 关闭串口
* 使用结束时记得关闭串口
*/
public void closeSerialPort() {
if (mSerialPort != null) {
//调用native方法关闭串口
mSerialPort.close();
mSerialPort = null;
}
}
データの送信/読み取り
シリアルポートが開かれると、入力ストリームと出力ストリームが取得され、次の送信と読み取りはこのストリームで動作します。
データを送る:
送信データはバイト配列です。文字列や16進コマンドなどの場合は、バイト配列に変換して送信する必要があります。出力ストリームにデータを書き込むだけです。
public void sendBufferToSerial(byte[] data) {
try {
mFileOutputStream.write(data);
} catch (IOException e) {
e.printStackTrace();
}
}
データの読み取り:
シリアルデータをいつ送信するかわからないため、送信データに関してデータを読み取ります。データの長さを取得するタイミングを取得するには、入力ストリームからサブスレッドデータを常に開く必要があります。 0でない場合は、次のステップのためにデータを分析します
class ReadThread extends Thread {
@Override
public void run() {
super.run();
while (!isInterrupted()) {
int size;
final byte[] buffer;
try {
buffer = new byte[128];
if (mFileInputStream == null) return;
size = mFileInputStream.read(buffer);
if (size > 0) {
//回调
if (listener != null)
listener.receiveData(size, buffer);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
/**
* 开始接收串口数据
*
* @param onReceiveDataListener 数据回调
*/
public void startReceiveData(OnReceiveDataListener onReceiveDataListener) {
readThread = new ReadThread();
readThread.start();
listener = onReceiveDataListener;
}
/**
* 停止接收数据
*/
public void stopReceiveData() {
if (readThread != null) {
if (readThread.isInterrupted())
readThread.interrupt();
}
readThread = null;
listener = null;
}
読み取られたデータはバイト配列でもあり、データを解析する必要があります。通常、機器のサプライヤが対応する分析方法を提供します。
シリアルポートはデータの読み取りと送信を行います。識別ビットとして2〜5バイトがあり、通常は0xFFから始まります。各パケットは統合されているため、データの送信と解析には注意が必要です。
使用する
アプリケーションでシリアルポートを開き、プロジェクトのBaseActivityまたはBaseFragmentでデータの送受信方法を定義し、必要な場所で直接呼び出すことができます。
付属
Cソースファイル: