引言
MCU与应用之间的通信非常的快一般200ms左右就会交互一次,同时数据在传输过程中也很容易受到干扰“1”变成“0”或者“0”变成“1”,而且在读取数据流时候刚好是一包数据的中间或者结尾。总之能拿到一包正确的数据确实要考虑到很多的问题。
数据安全
上篇文章我会以“0xAA”举例就是因为“10101010”是它的二进制这个数比较有规律,受到干扰变成这样的二进制概率比较小,如果加上“01010101“就更好了,这样安全的多。但是数据还是不能以”AA 55“为一包数据的唯一校验方式,必须以CRC来校验因为出现”AA 55“开头的无效数据还是有可能的。CRC的校验方式有很多种,大家和电控同事确定一种就好。
数据读取
//示例代码
final BlockingQueue<Byte> CACHE_QUEUE = new ArrayBlockingQueue<>(256);
while (!isInterrupted()) {
try {
byte[] buffer = new byte[8];
if (mInputStream == null){
return;
}
int size = mInputStream.read(buffer);
if (size <= 0) {
continue;
}
for (int i = 0; i < size; i++) {
//往里添加数据
CACHE_QUEUE.offer(buffer[i]);
}
} catch (IOException e) {
e.printStackTrace();
}
}
ArrayBlockingQueue 阻塞队列很好的解决了多线程中数据的安全传输问题,同时保障了“先进先出” 这里里面主要是用到了“先进先出” 就像流水一下先取的数据先用来组合。
防止数据丢包
- 堵塞读取数据 CACHE_QUEUE.take()
while (true) {
try {
handle(CACHE_QUEUE.take());
} catch (InterruptedException e) {
e.printStackTrace();
continue;
}
}
- 读取每个字节从中取出一包有效数据
/**
* buffer 缓存读取一包数据
*/
byte[] buffer = null;
/**
* 处理每一个字节
*
* @param b
*/
@RequiresApi(api = Build.VERSION_CODES.O)
private void handle(byte b) {
if(index==0||index==1){
head(b);
} else if (index < length - 1) {
middle(b);
} else if (index == length - 1) {
last(b);
} else {
reset();
}
}
private void head(byte b) {
if (数据头) {
this.reset();
first = b;
index++;
} else {
this.reset();
}
}
/**
*数据中
*/
private void middle(byte b) {
buffer[index] = b;
index++;
}
/**
* 数据尾
*/
private void last(byte b) {
buffer[index] = b;
this.print(buffer);
// 校验CRC
if (FrameUtils.isAPacketData(buffer, buffer.length)) {
// 处理业务逻辑
// todo
System.out.println("一包数据");
reset();
} else {
//从头后数据再添加处理
byte[] tempBuffer = Arrays.copyOf(buffer, buffer.length);
reset();
for (int i = 2; i < tempBuffer.length; i++) {
this.handle(tempBuffer[i]);
}
}
}
/**
*重置
*/
private void reset() {
first = 0x00;
index = 0;
length = 0;
buffer = null;
}