android串列埠通訊接受自定義協議資料並解析問題
1.一般自定義的串列埠協議
串列埠傳輸介面底層是按位(bit)傳送的,上層是按byte傳送和接收的,但協議為了方便描述,每個byte用十六進位制數(0x00~0xFF)表示,範相當於十進位制的0~255,而byte為八位且是有符號型別,相當於十進位制的-128~127,明顯0x8F~0xFF(128~255)是不能準確轉換為byte的,咋辦?
byte b = 0xFF;
編譯器會提示出錯,因為0xFF被當作255整數處理,255超過了byte(-128~127)的範圍,不能直接賦值,那咋辦?強轉啊!
byte b = (byte) 0xFF;
這樣就沒問題了,但此時你會不會覺得這樣寫就和協議想傳送0xFF的想法不匹配了呢,我明明想發個255來著,那我告訴你,你一個一個位元組的發,每個位元組就只能是-128~127,不能在其他範圍,所以強轉的目的是你可以傳送這個0xFF的前提,傳送的值肯定不是255,具體是啥:
public class Main {
public static void main(String[] args) {
byte c1 = (byte) 0xFF;
int c2 = c1 & 0xFF;
System.out.println(""+c1);
System.out.println(""+c2);
}
}
-1
255
Process finished with exit code 0
可見,實際上是一個-1,但接受端為了表達這是個傳送端傳送給我的是0xFF(255)而不是-1,你可以通過取到該位元組值後 “ 該值 & 0xFF”轉為無符號值即255.
通常自定義協議的格式:
一.接收到資料是不固定的長度,協議是起始是AA AA 結束是DE D0
接收到的資料有可能是AA AA 08 56 82 44 DE DO
二.接受到資料是不固定的長度,協議的起始A0 55 第三個位元組為協議長度,結束位元組是傳送資料的異或校驗值,
列如:A0 55 04 51 00 00 55 A0 55 04 53 00 01 56
結束位元組是前面各個位元組異或後的值:
/** * 異或校驗和 * @param data * @return */ public static byte getXor(byte[] data){ byte temp=data[0]; for (int i = 1; i <data.length; i++) { temp ^=data[i]; } return temp; }
2.分段接收資料不好解析
在讀取串列埠資料時,通常線上程中讀取輸入流中的資料,這時接受的位元組數是不固定的,一條指令被分成若干段,接受到的散亂位元組不好處理,看到網上有做延時接受處理,也就是輸入流可用的時候就延時一會兒,等接受完了再一次性讀出來,效果不錯:
/**
* 4.接收串列埠資料的執行緒
*/
private class ReceiveThread extends Thread {
@Override
public void run() {
//條件判斷,只要條件為true,則一直執行這個執行緒
while (isStart) {
if (inputStream == null) {
return;
}
byte[] readData = new byte[1024*4];
try {
String receiveCmd = "";
String HEAD = "A055";
StringBuilder sb = new StringBuilder();
// 為了一次性讀完,做了延遲讀取
if (inputStream.available() > 0 ) {
SystemClock.sleep(200);
int size = inputStream.read(readData);
if (size > 0) {
String readString = DataUtils.ByteArrToHex(readData, 0, size);
LogUtils.d(readString);
if(!TextUtils.isEmpty(readString)){
String[] split = readString.split(HEAD);
for (int i = 1; i < split.length; i++) {
receiveCmd = HEAD+split[i];
sb.append(receiveCmd+"\n");
LogUtils.e(receiveCmd);
}
}
EventBus.getDefault().post(sb.toString());
sb.setLength(0);
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}