android串口开发使用byte[]数组接收串口消息,但是发现如果消息过长,那么无论byte[]长度设置多长,每次都只能接收到32个字节。用的是google提供的串口开发工具包。
由于本博客开篇时离问题解决已经有一段时间了,因此不再对问题现象进行截图说明,只简单描述一下。
串口通信是硬件通信协议,我并没有任何研究,仅仅咨询硬件部门同事,说是我们的硬件底层使用RS-485协议。
不知道这是什么意思。多次沟通后对问题原因稍微有了一点点靠谱的猜测。
硬件部门同事设置的接收串口消息缓存区大小是200.因此超过200的时候,硬件就不会完整接收了(也就是说图省事直接不处理断包情况,而是直接根据业务设置一个不可能达到上限的缓存区,避免了自己动手拼包)。
我没看过google的串口工具包源码,只是简单的编译了一下方法路径然后照葫芦画瓢集成到android项目里就开始与设备进行串口通信了。当我用commix模拟硬件消息时,发送的消息如果超过了32字节,则Android窗口打印数据会分次打印,每次最多32字节。
依据硬件同事的科普,我认为google串口工具包内部设置的接收串口消息的缓存应该只有32个字节,所以,我们使用这个工具的时候,也可以不用给消息设置太大的接收缓存,只给32位。
我们的硬件通信命令一般不会超过32字节,不过既然已经发现了断包问题,为了保险起见,还是对google串口接收消息的demo代码做了一些简单的改动,改动思想如下:每次接收到消息都拼接到另一个更大的数组后面,每个20毫秒检查一次缓存中是否接收到消息,如果100毫秒内没有接收到下条消息则认为本次消息传递完成。关键代码如下
自定义的Thread
private class ReadThread extends Thread {
private SendRunnable runnable = new SendRunnable();
// private long last;
//第一次运行线程时设置成true
private boolean beginning = false;
//缓冲区()
byte[] buffer = new byte[64];
@Override
public void run() {
super.run();
while (!isInterrupted()) {
int size;
try {
if (mInputStream == null) return;
//读取数据,同时获取数据长度(数据长度不是数组长度,而是实际接收到的数据长度),数据被读取到了缓冲区 buffer中
size = mInputStream.read(buffer);
if (size > 0) {
System.err.println("接收数据长度:" + size);
//临时数组,将缓冲区buffer中的有效数据读取出来,临时数据长度就是接收到的数据长度。
byte[] temp = new byte[size];
System.arraycopy(buffer, 0, temp, 0, size);
//具体注释见init方法
runnable.init(temp, size);
//如果程序第一次运行
if (!beginning) {
//运行runnable,只在第一次执行,如果重复执行虽不会抛出异常,但是也无法正常执行功能
mHandler.post(runnable);
}
}
} catch (IOException e) {
e.printStackTrace();
return;
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
处理断包的Runnable
public class SendRunnable implements Runnable {
private byte[] lastBuffer;
int time = 0;
boolean work = true;
private int lastBufferLength;
//断包处理逻辑包含其中
public void init(byte[] buffer, int size) {
if (lastBuffer == null) {
lastBuffer = buffer;
} else {
lastBufferLength = lastBuffer.length;
byte[] temp = new byte[lastBufferLength + size];
//先拷贝之前的数据
System.arraycopy(lastBuffer, 0, temp, 0, lastBufferLength);
//再拷贝刚接收到的数据
System.arraycopy(buffer, 0, temp, lastBufferLength, size);
lastBuffer = null;
lastBuffer = temp;
temp = null;
}
work = true;
time = 0;
}
public void reStart() {
work = true;
time = 0;
}
public void stop() {
work = false;
time = 0;
}
//接收完成后重置完整消息缓冲区
public void reset() {
work = false;
time = 0;
lastBuffer = null;
}
@Override
public void run() {
while (work) {
try {
Thread.sleep(20);
time += 20;
} catch (InterruptedException e) {
e.printStackTrace();
}
if (time >= 100) {
byte[] finalBuffer = lastBuffer;
reset();
//业务处理方法
onDataReceived(finalBuffer, finalBuffer.length);
}
}
}
}
网友评论