一,android序列槽通信 序列槽通信采用一個第三方開源項目,實作序列槽資料收發。
使用了 api和jni;
支援4序列槽同時收發,有定時自動發送功能,收發模式可選Txt或Hex模式;
n,8,1,沒得選;
為減輕界面卡頓的情況,接收區的重新整理采用單獨的線程進行定時重新整理;
發送區的資料以及一些設定項,在程式關閉時會自動儲存,打開時自動載入;
jni使用最新的NDKr8b重新編譯了一下
簡單編寫步驟: 1.建立一個項目,自己起個名字 2.直接複制serialport api和jni檔案夾到建立的工程,如果不想自己編譯jni,就連libs檔案夾也一起複制 3.去android官方網站下載下傳NDK,解壓,在CMD中轉到jni目錄,并執行 絕對路徑ndk-build 4.自己再封裝一個工具類或直接使用SerialPort類都行,舉個直接使用的例: 直接剽竊原項目的SerialPortActivity.java,并稍微改一下,重點改這裡 mSerialPort = mApplication.getSerialPort(); 這裡可以改成 new SerialPort(new File("/dev/s3c2410_serial0"), 9600, 0);//COM0,波特率9600
SerialPortFinder的使用就沒什麼好講的了,執行個體化後用.getAllDevicesPath()就能擷取到所有裝置了。其它如資料轉換等請參考源碼
源碼可以參考谷歌android-serialport-api例子
二,序列槽通信協定解析 1.通信基本格式 字段 描述 長度(位元組) 起始符 0F,十六進制碼 1 資訊類型 一個位元組,十六進制碼(0F,F0,FF等保留碼不用)1 資訊長度 是資訊内容的長度,ASCII碼表示(0~9,A~F,最大長度為256)(例如長為11個,十六進制是0B,則兩個位元組就寫0x30 0x42)。 注:因為最大長度256不能滿足有些指令的要求,是以對長度做了擴充,下面是擴充說明: 如果第一個位元組的最高位為1,則表示擴充長度。在擴充長度狀态下,其他15個位元組通過16進制大端模式來儲存長度。比如:0x80 0x12表示長度為0x001 2,0x81 0x12表示長度為0x0112。2 資訊内容 一組十六進制碼 N 校驗 一個位元組,十六進制碼,是自資訊類型起至對象号止所有碼的異或。1 結束符 F0,一個位元組,十六進制碼 (為了保證可靠性,車機下發的結束符為F0 FF)1
2.協定解析
private class ReadThread extends Thread {
@Override
public void run() {
super.run();
// 定義一個包的最大長度
int maxLength = 2048;
byte[] buffer = new byte[maxLength];
// 每次收到實際長度
int available = 0;
// 目前已經收到包的總長度
int currentLength = 0;
// 協定頭長度4個位元組(開始符1,類型1,長度2)
int headerLength = 4;
while (!isInterrupted()) {
try {
available = mInputStream.available();
if (available > 0) {
// 防止超出數組最大長度導緻溢出
if (available > maxLength - currentLength) {
available = maxLength - currentLength;
}
mInputStream.read(buffer, currentLength, available);
currentLength += available;
}
}
catch (Exception e) {
e.printStackTrace();
}
int cursor = 0;
// 如果目前收到包大于頭的長度,則解析目前包
while (currentLength >= headerLength) {
// 取到頭部第一個位元組
if (buffer[cursor] != 0x0F) {
--currentLength;
++cursor;
continue;
}
int contentLenght = parseLen(buffer, cursor, headerLength);
// 如果内容包的長度大于最大内容長度或者小于等于0,則說明這個包有問題,丢棄
if (contentLenght <= 0 || contentLenght > maxLength - 5) {
currentLength = 0;
break;
}
// 如果目前擷取到長度小于整個包的長度,則跳出循環等待繼續接收資料
int factPackLen = contentLenght + 5;
if (currentLength < contentLenght + 5) {
break;
}
// 一個完整包即産生
// proceOnePacket(buffer,i,factPackLen);
onDataReceived(buffer, cursor, factPackLen);
currentLength -= factPackLen;
cursor += factPackLen;
}
// 殘留位元組移到緩沖區首
if (currentLength > 0 && cursor > 0) {
System.arraycopy(buffer, cursor, buffer, 0, currentLength);
}
}
}
}
public int parseLen(byte buffer[], int index, int headerLength) {
// if (buffer.length - index < headerLength) { return 0; }
byte a = buffer[index + 2];
byte b = buffer[index + 3];
int rlt = 0;
if (((a >> 7) & 0x1) == 0x1) {
rlt = (((a & 0x7f) << 8) | b);
}
else {
char[] tmp = new char[2];
tmp[0] = (char) a;
tmp[1] = (char) b;
String s = new String(tmp, 0, 2);
rlt = Integer.parseInt(s, 16);
}
return rlt;
}
protected void onDataReceived(final byte[] buffer, final int index, final int packlen) {
System.out.println("收到資訊");
byte[] buf = new byte[packlen];
System.arraycopy(buffer, index, buf, 0, packlen);
ProtocolAnalyze.getInstance(myHandler).analyze(buf);
}