Skip to content

Acccord/AndroidSerialPort

Repository files navigation

Android 串口通信库

Android 串口通信库,面向长期稳定运行的工程场景(工控、售货机、智能柜等)。

本库以**“快速使用 / 自定义使用”**为主线:
快速使用用于极速完成串口收发;自定义使用覆盖协议、重连、监控与高端场景。


旧版文档(1.x.x)

如果你当前使用的是 1.x.x 版本,请查看之前的 README 文档:


目录

  • 串口测试工具
  • 配置
  • 混淆
  • 快速使用
    • 第1步:打开串口
    • 第2步:往串口发数据
    • 第3步:串口返回的数据接收
    • 第4步:异常监听
  • 自定义使用
    • 2.1 入口选择
    • 2.1.1 回调线程提示
    • 2.2 SerialConnection + 协议帧(CRLF)
    • 2.3 SerialManager 管理多串口
    • 2.4 高端场景(NIO + 监控 + 重连)
    • 2.5 自定义帧解码
    • 2.6 配置说明(SerialConfig
  • 更新记录

串口测试工具

项目内提供了一个用于串口收发调试的测试工具 App,可用于联调、演示和问题排查。


配置

在项目的build.gradle添加

allprojects {
    repositories {
        maven { url 'https://jitpack.io' }
    }
}

在模块的build.gradle添加

dependencies {
    implementation 'com.github.Acccord:AndroidSerialPort:2.0.4'
}

混淆

通常无需额外手动配置,以下规则仅供需要手动配置或排查混淆问题时参考。

-keep class com.temon.serial.** { *; }
-keepclassmembers class * { native <methods>; }

# Preserve useful debugging information.
-keepattributes SourceFile,LineNumberTable,Signature,InnerClasses,EnclosingMethod


快速使用

针对没有特殊串口通信设置需求,使用默认串口配置。

【EasySerial】默认能力包括:

  • 8N1(8 数据位、无校验、1 停止位)
  • 默认主线程回调(EasySerial)
  • 默认帧解码:Idle-Gap(处理半包/粘包,默认空闲间隔 50ms、最大帧长 2048)
  • 默认自动重连(指数退避策略,仅运行期进入 ERROR 才触发;手动 close 不重连;权限错误不重连)
  • 默认发送间隔:300ms(sendIntervalMs(DEFAULT_SEND_INTERVAL_MS))
  • 默认支持多串口 提示:同一端口被其他进程占用时会打开失败,需先释放占用或更换端口。

使用提示(建议顺序):

  • 先注册 onDataReceived / onError,再 open,避免首包或首个异常被错过

第1步:打开串口

EasySerial.open("/dev/ttyS1", 9600);
EasySerial.open("/dev/ttyS2", 9600);  // 可同时打开多个串口

返回值说明(打开阶段的即时结果):

  • OPEN_OK (0):打开成功
  • OPEN_NO_PERMISSION (-1):无权限访问设备节点
  • OPEN_UNKNOWN_ERROR (-2):未知错误(设备异常/系统返回异常等)
  • OPEN_INVALID_PARAM (-3):参数非法(端口为空、波特率 <= 0)

第2步:往串口发数据

EasySerial.send("/dev/ttyS1", HexCodec.decode("AA033C0000E9"));

提示:只有在对应端口 open 成功后再发送;port 必须与 open 时一致。

第3步:串口返回的数据接收

EasySerial.onDataReceived(new EasySerial.OnDataReceivedListener() {
    @Override
    public void onDataReceived(String port, byte[] data, int length) {
        String hex = HexCodec.encode(data, 0, length);
        System.out.println("[" + port + "] RX: " + hex);
    }
});

第4步:异常监听

EasySerial.onError(new EasySerial.OnErrorListener() {
    @Override
    public void onError(String port, SerialError error, String message, Throwable throwable) {
        System.err.println("[" + port + "] Error: " + message);
        if (throwable != null) throwable.printStackTrace();
    }
});

说明:运行过程中的断线、读写异常等属于异步错误,需要通过 onError 监听获取。 常见处理:权限不足请确认设备节点权限;设备路径不存在或被占用会导致 OPEN_FAILED/CLOSED。 建议:应用退出或不再使用时调用 close / closeAll,避免资源泄漏。

SerialError 枚举说明:

  • INVALID_PARAMETER:参数错误
  • PERMISSION_DENIED:权限不足
  • OPEN_FAILED:打开串口失败
  • IO_ERROR:读写异常
  • CLOSED:串口已关闭或未打开

常见问题(简要排查):

  • PERMISSION_DENIED:确认设备节点权限或授予设备访问权限
  • OPEN_FAILED:检查设备路径是否存在、是否被其他进程占用
  • CLOSED:先 opensend,并确保端口名一致

总结: 快速使用只需要 open 成功后,就可以调用 send 往串口发送数据,同时 onDataReceived 来监听串口数据返回。如需使用其他功能,可参考下面的自定义使用


自定义使用(协议 / 多串口精细管理 / 高端场景)

2.1 入口选择

  • SerialConnection:单连接、可控性高
  • SerialManager:多串口精细管理

2.1.1 回调线程提示

  • SerialConnection / SerialManager 默认回调线程为 IO 线程(Dispatchers.direct()),请避免在回调里执行耗时操作。
  • EasySerial 默认回调在主线程(见“快速使用”)。
  • 如需切换到主线程或自定义线程池,请使用 callbackDispatcher(...) 配置。

2.2 SerialConnection + 协议帧(CRLF)

SerialConfig config = new SerialConfig.Builder()
    .port("/dev/ttyS1")
    .baudRate(9600)
    .build();

SerialConnection conn = SerialConnection.builder(config)
    .frameDecoder(SerialFraming.crlf())
    .callbackDispatcher(Dispatchers.mainThread())
    .listener(new SerialListenerAdapter() {
        @Override
        public void onFrame(byte[] frame, int length) {
            String hex = HexCodec.encode(frame, 0, length);
            System.out.println("Frame: " + hex);
        }
    })
    .build();

conn.open();

提示:SerialConnection 默认不自动重连,只有配置 reconnectPolicy(...) 才会启用。 提示:重连仅在运行期进入 ERROR 状态触发,不会覆盖手动 close 的行为。

2.3 SerialManager 管理多串口

SerialManager manager = new SerialManager();
manager.setCallbackDispatcher(Dispatchers.mainThread());

try {
    manager.open("/dev/ttyS1", 9600);
    manager.addDataListener("/dev/ttyS1", new SerialManager.OnHexDataListener() {
        @Override
        public void onData(String hex) {
            System.out.println("Received: " + hex);
        }
    });
    manager.sendHex("/dev/ttyS1", "AA033C0000E9");
} catch (SerialException e) {
    e.printStackTrace();
}

提示:sendHex/sendBytes 在端口未打开时会抛出 CLOSED;多端口场景请使用 port 区分回调来源。 提示:同一端口重复 open 会关闭旧连接并创建新连接,请避免并发重复打开。 提示:SerialManager 默认是 raw 模式(未设置解码器),不会按帧回调;如需分帧请用 config().frameDecoder(...)config().idleGap(...) 等配置。

2.4 高端场景(NIO + 监控 + 重连)

SerialConfig config = new SerialConfig.Builder()
    .port("/dev/ttyS1")
    .baudRate(500000)
    .readTimeoutMs(50)
    .deviceCheckIntervalMs(1000)
    .useNioMode(true)
    .readBufferSize(8192)
    .build();

SerialConnection connection = SerialConnection.builder(config)
    .frameDecoder(SerialFraming.crlf())
    .logger(new AndroidSerialLogger(true))
    .reconnectPolicy(new ReconnectPolicy.ExponentialBackoff(10, 100, 2.0, 5000))
    .build();

connection.open();
SerialStatistics stats = connection.getStatistics();
System.out.println("Throughput: " + stats.getReceiveThroughputBps() + " B/s");
System.out.println("Error rate: " + stats.getErrorRate() + " errors/s");

提示:readTimeoutMs 越小 CPU 轮询越频繁;deviceCheckIntervalMs 越小越敏感但更耗电;readBufferSize 过小易增大分帧/拷贝开销。

2.5 自定义帧解码

FrameDecoder fixed = SerialFraming.fixedLength(64);
FrameDecoder length = SerialFraming.lengthFieldBuilder()
    .lengthFieldOffset(0)
    .lengthFieldLength(2)
    .lengthAdjustment(0)
    .initialBytesToStrip(2)
    .build();
FrameDecoder idle = SerialFraming.idleGap(100, 1024);

说明:lengthFieldBuilder() 默认大端、maxFrameLength=4096initialBytesToStrip 表示丢弃前 N 个字节。 提示:长度字段是否包含头部/校验,需与协议定义一致,否则会导致错帧或丢弃。

丢弃计数说明:
当帧解码器检测到异常数据流(超长/非法长度)会丢弃缓冲区。可通过解码器实例读取丢弃次数与字节数:

FrameDecoder decoder = SerialFraming.crlf();
if (decoder instanceof DelimiterFrameDecoder) {
    long dropped = ((DelimiterFrameDecoder) decoder).getDroppedCount();
    long droppedBytes = ((DelimiterFrameDecoder) decoder).getDroppedBytes();
}

提示:丢弃计数持续增长通常意味着帧边界或长度配置不匹配,请检查协议定义与解码器参数。

2.6 配置说明(SerialConfig

配置项 类型 默认值 说明
port String - 串口路径(必需)
baudRate int - 波特率(必需)
stopBits int 1 停止位(1或2)
dataBits int 8 数据位(5-8)
parity int 0 奇偶校验(0=None, 1=Odd, 2=Even)
flowCon int 0 流控(0=None, 1=Hard, 2=Soft)
readTimeoutMs int 1000 读超时(0=阻塞,>0=超时毫秒)
sendIntervalMs int 0 发送间隔(毫秒)
deviceCheckIntervalMs int 5000 设备在线检查间隔(毫秒,0=禁用)
useNioMode boolean false 启用 NIO Selector(毫秒级超时精度)
readBufferSize int 1024 读缓冲区(字节,0=默认=1024)
permissionStrategy PermissionStrategy - 设备权限策略(空表示不做自动权限处理)

更新记录

  • 2026-02-07:native libserial_port.so 增加 16KB 页对齐链接参数,兼容 Android 15+ 16KB 设备要求。

About

Android串口通信SDK,由 Google 串口通信库进行封装,可同时打开多个串口,快速接入。并扩展支持设置 su 路径、串口路径、波特率、校验位、数据位、停止位

Topics

Resources

Stars

Watchers

Forks

Packages

 
 
 

Contributors