一.为什么做这个事
这个事情的前提,最近有个需求需要通过安卓设备进行串口调试,还要在使用RS232硬流控功能,直接调试过一些串口的例子,主要是基于google开源的串口助手,但是大部分都不包含流控功能。就在github是找了一个带流控的案例进行测试和调试。
参考项目地址Android-Serialport,
二.遇到的问题
首先是把这个项目clone下来编译,一切ok,在安卓8版本上运行没发现什么问题,但是在安卓10上出现权限问题,无法访问“ /proc/tty/drivers”
LineNumberReader r = new LineNumberReader(new FileReader("/proc/tty/drivers"));
报错代码这一行,多次尝试和查找解决问题,把项目的编译版本降低
compileSdk 29 defaultConfig { applicationId "com.ex.serialport" minSdk 14 targetSdk 29 versionCode 1 versionName "1.0" }
compileSdk 29和targetSdk 29从33降到了29后不再报错。
这个问题解决后测试可以正常开启流控。
三.CTS和RTS控制
但是要用硬流控我需要测试设备是否真正具有流控功能。那就需要添加一个CTS和TRTS的控制,这部分代码需要在jni进行控制
安卓端设置RTC,设置为false后,安卓端电平拉低,不再接收数据,电脑端无法发生数据。
public native void setRTC(boolean isOpen);
JNIEXPORT void JNICALL Java_android_1serialport_1api_SerialPort_setRTC
(JNIEnv *env, jobject thiz,jboolean isOpen) {
jclass SerialPortClass = (*env)->GetObjectClass(env, thiz);
jclass FileDescriptorClass = (*env)->FindClass(env, "java/io/FileDescriptor");
jfieldID mFdID = (*env)->GetFieldID(env, SerialPortClass, "mFd", "Ljava/io/FileDescriptor;");
jfieldID descriptorID = (*env)->GetFieldID(env, FileDescriptorClass, "descriptor", "I");
jobject mFd = (*env)->GetObjectField(env, thiz, mFdID);
jint descriptor = (*env)->GetIntField(env, mFd, descriptorID);
int rts_flag = TIOCM_RTS;
if (isOpen){
// 设置 RTS 信号(发送方准备好发送)
ioctl(descriptor, TIOCMBIS, &rts_flag);
} else{
// 清除 RTS 信号
ioctl(descriptor, TIOCMBIC, &rts_flag);
}
int rst_state ;
ioctl(descriptor, TIOCMGET, &rst_state);
if (rst_state & TIOCM_RTS) {
LOGE("RTS signal is high\n"); // 接收方准备好接收
} else {
LOGE("RTS signal is low\n"); // 接收方未准备好接收
}
}
读取CTS状态,CTS是由电脑端的RTS控制
public native boolean startCTSListener();
// 开始监听 CTS 信号状态
JNIEXPORT jboolean JNICALL Java_android_1serialport_1api_SerialPort_startCTSListener(JNIEnv *env,
jobject thiz) {
// 获取 Java 回调对象
jclass SerialPortClass = (*env)->GetObjectClass(env, thiz);
jclass FileDescriptorClass = (*env)->FindClass(env, "java/io/FileDescriptor");
jfieldID mFdID = (*env)->GetFieldID(env, SerialPortClass, "mFd", "Ljava/io/FileDescriptor;");
jfieldID descriptorID = (*env)->GetFieldID(env, FileDescriptorClass, "descriptor", "I");
jobject mFd = (*env)->GetObjectField(env, thiz, mFdID);
jint descriptor = (*env)->GetIntField(env, mFd, descriptorID);
// 在这里实现 CTS 信号状态监听逻辑,类似上面的 C 代码
// 获取CTS信号状态
int cts_flag;
ioctl(descriptor, TIOCMGET, &cts_flag);
int current_cts_state = (cts_flag & TIOCM_CTS) ? 1 : 0;
// CTS信号状态变化时输出
if (current_cts_state) {
LOGE("CTS signal is high - Ready to receive\n");
} else {
LOGE("CTS signal is low - Not ready to receive\n");
}
return current_cts_state;
}
在串口打开的时候开始循环去读取CTS状态
private class CTSThread
extends Thread {
private CTSThread() {
}
public void run() {
super.run();
while (!isInterrupted()&&isOpen()) {
CTSIsOpen(mSerialPort.startCTSListener());
try {
sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
没有做太多的修改,这里就不贴源码了,可以看上面git地址的,另外