iT邦幫忙

0

透過sublist擷取arraylist 擷取資料問題

  • 分享至 

  • xImage

先敘述背景,最近在撰寫android ble的接收應用, 一筆資料的data frame依序是---> 4 byte header(2,1,4,3) + 4 byte serial number + 4 byte length value(顯示資料多長 為實際資料長度+4) + unfixed length data(真正的資料) + 4 byte tail(-1,-1,-1,-1), 寫了一個簡單的介面

其流程大約如附件

https://ithelp.ithome.com.tw/upload/images/20211103/201436588gMKhNOooH.png

ble oncharacteristic的code

@RequiresApi(api = Build.VERSION_CODES.N)
        @Override
        public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) {
            broadcastUpdate(ACTION_DATA_AVAILABLE, characteristic);
            if (mBluetoothAdapter == null || mBluetoothGatt == null) {
                Log.w(TAG, "BluetoothAdapter not initialized");
                return;
            }
            lockCharacteristicRead = true;
            mBluetoothGatt.readCharacteristic(characteristic);

            byte[] temp = characteristic.getValue();

            byte[] increaseCapacity = new byte[temp.length];

            System.arraycopy(temp, 0, increaseCapacity, 0, temp.length);

            Byte[] byteObjects6 = new Byte[increaseCapacity.length];

            int i = 0;
            // Associating Byte array values with bytes. (byte[] to Byte[])
            for (byte b : increaseCapacity) {
                byteObjects6[i++] = b;  // Autoboxing.....
            }
            rawDataList.addAll(Arrays.asList(byteObjects6));

            Process p1 = new Process();
            p1.run();
        }
    }

runnable 介面的code

public class Process implements Runnable {
        @Override
        public void run() {
            dataProcess testProcess = new dataProcess();
            testProcess.checkHeadTail(rawDataList);
        }
    }

資料處理的code

class dataProcess {
        public synchronized void checkHeadTail(ArrayList<Byte> rawDataList) {
            int size = rawDataList.size();
            for (int k = 0; k < size; k++) {
                if (k + 1 < size && k + 2 < size && k + 3 < size) {
                    if ((rawDataList.get(k) & 0xFF) == 2 && (rawDataList.get(k+1) & 0xFF) == 1 && (rawDataList.get(k+2) & 0xFF) == 4 && (rawDataList.get(k+3) & 0xFF) == 3) {
                        length = (rawDataList.get(k + 8) & 0xFF);
                        length2 = (rawDataList.get(k + 9) & 0xFF);
                        length3 = (rawDataList.get(k + 10) & 0xFF);
                        length4 = (rawDataList.get(k + 11) & 0xFF);

                        dataLength = length + length2 + length3 + length4 - 4;

                        if (k+dataLength+12 < size && k+dataLength+13 < size && k+dataLength+14 < size && k+dataLength+15 < size) {
                            if ((rawDataList.get(k+dataLength+12)) == -1 && rawDataList.get(k+dataLength+13) == -1 && rawDataList.get(k+dataLength+14) == -1 && rawDataList.get(k+dataLength+15) == -1) {
                                subList2 = rawDataList.subList(k+12, k+12+dataLength);
                            }
                        }
                    }
                }

            }
            StringBuilder stringBuilder = new StringBuilder(subList2.size());
            for (byte byteChar : subList2)
                stringBuilder.append(String.format("%02X ", byteChar));
            System.out.println(stringBuilder.toString());
        }
    }```

接收的測資(想擷取的資料分開在不同封包內)
//region PATTERN_04
    static int  mPatterm04Count = 0;
    static int mPatterm04CycleTimes = 3;
    /**
     * PATTERN_04 為3段不同長度的, 每段完整的資料, 但切開在 3 個封包內
     */
    final static byte[] PATTERN_04a = {0x02, 0x01, 0x04, 0x03
            , 0x01, 0x00, 0x00, 0x00
            , (byte) 0x0C, 0x00, 0x00, 0x00
            , 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00
    };

    final static byte[] PATTERN_04b = {
            (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF
            , 0x02, 0x01, 0x04, 0x03
            , 0x02, 0x00, 0x00, 0x00
            , (byte) 0x14, 0x00, 0x00, 0x00
            , 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02
    };

    final static byte[] PATTERN_04c = {
            0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00
            , (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF
            , 0x02, 0x01, 0x04, 0x03
            , 0x03, 0x00, 0x00, 0x00
            , (byte) 0x1C, 0x00, 0x00, 0x00
            , 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00
            , (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF
    };
    //endregion



想要輸出的結果
00 00 00 00 01 00 00 00 
00 00 00 00 01 00 00 00 02 00 00 00 03 00 00 00 
00 00 00 00 01 00 00 00 02 00 00 00 03 00 00 00 04 00 00 00 05 00 00 00

實際輸出的結果
I/System.out: 00 00 00 00 01 00 00 00 02 00 00 00 03 00 00 00 04 00 00 00 05 00 00 00 
I/System.out: 00 00 00 00 01 00 00 00 02 00 00 00 03 00 00 00 04 00 00 00 05 00 00 00 
I/System.out: 00 00 00 00 01 00 00 00 02 00 00 00 03 00 00 00 04 00 00 00 05 00 00 00 
I/System.out: 00 00 00 00 01 00 00 00 
I/System.out: 00 00 00 00 01 00 00 00 02 00 00 00 03 00 00 00 04 00 00 00 05 00 00 00 
I/System.out: 00 00 00 00 01 00 00 00 
I/System.out: 00 00 00 00 01 00 00 00 02 00 00 00 03 00 00 00 
I/System.out: 00 00 00 00 01 00 00 00 02 00 00 00 03 00 00 00 04 00 00 00 05 00 00 00 
I/System.out: 00 00 00 00 01 00 00 00 02 00 00 00 03 00 00 00 04 00 00 00 05 00 00 00 
I/System.out: 00 00 00 00 01 00 00 00 
I/System.out: 00 00 00 00 01 00 00 00 02 00 00 00 03 00 00 00 
I/System.out: 00 00 00 00 01 00 00 00 02 00 00 00 03 00 00 00 04 00 00 00 05 00 00 00 
I/System.out: 00 00 00 00 01 00 00 00 02 00 00 00 03 00 00 00 04 00 00 00 05 00 00 00 
I/System.out: 00 00 00 00 01 00 00 00 
I/System.out: 00 00 00 00 01 00 00 00 02 00 00 00 03 00 00 00 
I/System.out: 00 00 00 00 01 00 00 00 02 00 00 00 03 00 00 00 04 00 00 00 05 00 00 00 
I/System.out: 00 00 00 00 01 00 00 00 
I/System.out: 00 00 00 00 01 00 00 00 02 00 00 00 03 00 00 00 04 00 00 00 05 00 00 00 
I/System.out: 00 00 00 00 01 00 00 00 
I/System.out: 00 00 00 00 01 00 00 00 02 00 00 00 03 00 00 00 
I/System.out: 00 00 00 00 01 00 00 00 02 00 00 00 03 00 00 00 04 00 00 00 05 00 00 00 
I/System.out: 00 00 00 00 01 00 00 00 
I/System.out: 00 00 00 00 01 00 00 00 02 00 00 00 03 00 00 00 
I/System.out: 00 00 00 00 01 00 00 00 02 00 00 00 03 00 00 00 04 00 00 00 05 00 00 00 
I/System.out: 00 00 00 00 01 00 00 00 02 00 00 00 03 00 00 00 04 00 00 00 05 00 00 00 
I/System.out: 00 00 00 00 01 00 00 00 
I/System.out: 00 00 00 00 01 00 00 00 02 00 00 00 03 00 00 00 
I/System.out: 00 00 00 00 01 00 00 00 02 00 00 00 03 00 00 00 04 00 00 00 05 00 00 00 


尋求站內各位大神協助 解決此bug

圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

1 個回答

1
海綿寶寶
iT邦大神 1 級 ‧ 2021-11-03 10:34:43
最佳解答

https://ithelp.ithome.com.tw/upload/images/20211103/20001787Y8EFMtbzBg.png

主要的部份沒錯
我只有把輸出的部份搬一下地方
因為照程式的寫法
subList2 每次都會「覆蓋」前一個封包的結果

import java.util.ArrayList;
import java.util.List;

public class HelloWorld{
    static ArrayList<Byte> arrAll = new ArrayList<Byte>();
    static byte[] pattern_04a = {
        0x02, 0x01, 0x04, 0x03,
        0x01, 0x00, 0x00, 0x00,
        (byte)0x0C, 0x00, 0x00, 0x00, 
        0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
        (byte) 0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF,
    };
    static byte[] pattern_04b = {
        0x02, 0x01, 0x04, 0x03,
        0x02, 0x00, 0x00, 0x00,
        (byte)0x14, 0x00, 0x00, 0x00, 
        0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
        0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
        (byte) 0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF,
    };
    static byte[] pattern_04c = {
        0x02, 0x01, 0x04, 0x03,
        0x02, 0x00, 0x00, 0x00,
        (byte)0x1C, 0x00, 0x00, 0x00, 
        0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
        0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 
        (byte) 0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF
    };

     public static void main(String []args){
         arrAll.clear();
         for(byte b : pattern_04a){ arrAll.add(b); }
         for(byte b : pattern_04b){ arrAll.add(b); }
         for(byte b : pattern_04c){ arrAll.add(b); }
         checkHeadTail(arrAll);
     }
     
    public static synchronized void checkHeadTail(ArrayList<Byte> rawDataList) {
            List<Byte> subList2 = new ArrayList();
            int length,length2,length3,length4,dataLength;
            
            int size = rawDataList.size();
            for (int k = 0; k < size; k++) {
                if (k + 1 < size && k + 2 < size && k + 3 < size) {
                    if ((rawDataList.get(k) & 0xFF) == 2 && (rawDataList.get(k+1) & 0xFF) == 1 && (rawDataList.get(k+2) & 0xFF) == 4 && (rawDataList.get(k+3) & 0xFF) == 3) {
                        length = (rawDataList.get(k + 8) & 0xFF);
                        length2 = (rawDataList.get(k + 9) & 0xFF);
                        length3 = (rawDataList.get(k + 10) & 0xFF);
                        length4 = (rawDataList.get(k + 11) & 0xFF);

                        dataLength = length + length2 + length3 + length4 - 4;

                        if (k+dataLength+12 < size && k+dataLength+13 < size && k+dataLength+14 < size && k+dataLength+15 < size) {
                            if ((rawDataList.get(k+dataLength+12)) == -1 && rawDataList.get(k+dataLength+13) == -1 && rawDataList.get(k+dataLength+14) == -1 && rawDataList.get(k+dataLength+15) == -1) {
                                subList2 = rawDataList.subList(k+12, k+12+dataLength);

                                StringBuilder stringBuilder = new StringBuilder(subList2.size());
                                for (byte byteChar : subList2)
                                    stringBuilder.append(String.format("%02X ", byteChar));
                                System.out.println(stringBuilder.toString());                            }
                        }
                    }
                }

            }
        }
}
看更多先前的回應...收起先前的回應...
habb2930 iT邦新手 5 級 ‧ 2021-11-03 14:30:56 檢舉

我先修改看看 但因為部分變數沒法跟你一樣使用區域變數 但還是謝謝你 有問題我馬上再來詢問

你不用使用區域變數, 原來的程式都不用動

你只要修改(搬)下面這段程式碼的位置即可

StringBuilder stringBuilder = new StringBuilder(subList2.size());

for (byte byteChar : subList2)
    stringBuilder.append(String.format("%02X ", byteChar));
    System.out.println(stringBuilder.toString()); 
habb2930 iT邦新手 5 級 ‧ 2021-11-03 14:47:31 檢舉

我按照說的只搬移那端

class dataProcess {
        public synchronized void checkHeadTail(ArrayList<Byte> rawDataList) {
            int size = rawDataList.size();
            for (int k = 0; k < size; k++) {
                if (k + 1 < size && k + 2 < size && k + 3 < size) {
                    if ((rawDataList.get(k) & 0xFF) == 2 && (rawDataList.get(k + 1) & 0xFF) == 1 && (rawDataList.get(k + 2) & 0xFF) == 4 && (rawDataList.get(k + 3) & 0xFF) == 3) {
                        length = (rawDataList.get(k + 8) & 0xFF);
                        length2 = (rawDataList.get(k + 9) & 0xFF);
                        length3 = (rawDataList.get(k + 10) & 0xFF);
                        length4 = (rawDataList.get(k + 11) & 0xFF);

                        dataLength = length + length2 + length3 + length4 - 4;

                        if (k+dataLength+12 < size && k+dataLength+13 < size && k+dataLength+14 < size && k+dataLength+15 < size) {
                            if ((rawDataList.get(k+dataLength+12)) == -1 && rawDataList.get(k+dataLength+13) == -1 && rawDataList.get(k+dataLength+14) == -1 && rawDataList.get(k+dataLength+15) == -1) {
                                subList2 = rawDataList.subList(k+12, k+12+dataLength);
                                StringBuilder stringBuilder = new StringBuilder(subList2.size());
                                for (byte byteChar : subList2)
                                    stringBuilder.append(String.format("%02X ", byteChar));
                                System.out.println(stringBuilder.toString());
                            }
                        }
                    }
                }

            }

        }
    }

輸出是

I/System.out: 00 00 00 00 01 00 00 00 02 00 00 00 03 00 00 00 
I/System.out: 00 00 00 00 01 00 00 00 02 00 00 00 03 00 00 00 04 00 00 00 05 00 00 00 
I/System.out: 00 00 00 00 01 00 00 00 02 00 00 00 03 00 00 00 
I/System.out: 00 00 00 00 01 00 00 00 02 00 00 00 03 00 00 00 04 00 00 00 05 00 00 00 
I/System.out: 00 00 00 00 01 00 00 00 02 00 00 00 03 00 00 00 
I/System.out: 00 00 00 00 01 00 00 00 02 00 00 00 03 00 00 00 04 00 00 00 05 00 00 00 
I/System.out: 00 00 00 00 01 00 00 00 
I/System.out: 00 00 00 00 01 00 00 00 02 00 00 00 03 00 00 00 
I/System.out: 00 00 00 00 01 00 00 00 02 00 00 00 03 00 00 00 04 00 00 00 05 00 00 00 
I/System.out: 00 00 00 00 01 00 00 00 
I/System.out: 00 00 00 00 01 00 00 00 02 00 00 00 03 00 00 00 
I/System.out: 00 00 00 00 01 00 00 00 02 00 00 00 03 00 00 00 04 00 00 00 05 00 00 00 
I/System.out: 00 00 00 00 01 00 00 00 02 00 00 00 03 00 00 00 
I/System.out: 00 00 00 00 01 00 00 00 02 00 00 00 03 00 00 00 04 00 00 00 05 00 00 00 
I/System.out: 00 00 00 00 01 00 00 00 
I/System.out: 00 00 00 00 01 00 00 00 02 00 00 00 03 00 00 00 
I/System.out: 00 00 00 00 01 00 00 00 02 00 00 00 03 00 00 00 04 00 00 00 05 00 00 00 
habb2930 iT邦新手 5 級 ‧ 2021-11-03 14:49:49 檢舉

Android Studio還是這樣的輸出 只有幾次是正常的 輸出還會常常 少一個封包內的資料 總覺得哪怪怪的 還是說我的擷取邏輯要改

我只有測試 checkHeadTail 這部份
確定「只呼叫一次,在 ArrayList 是那些 bytes 時,他可以產生你要的結果」

至於「怎麼把 bytes 讀進 ArrayList」「用幾個 thread 呼叫幾次 checkHeadTail」
還是得靠你自己 debug 了

habb2930 iT邦新手 5 級 ‧ 2021-11-03 15:10:20 檢舉

我是專門為這功能做1個thread 只有1個thread 呼叫checkHeadTail 是每次收到1個封包 啟動1次並呼叫1次 我有個問題 java thread是不是每次使用完後要記得關掉 另外你提及的「怎麼把 bytes 讀進 ArrayList」是指最一開始byte array收到資料後 放進ArrayList的部分嗎?

habb2930 iT邦新手 5 級 ‧ 2021-11-03 15:12:59 檢舉

此外 我其實發送端是同事寫一個手機app用手機發送 我這邊接收端也是我的手機 不是一般開發板與模組 硬體端應該不太會有問題

我要發表回答

立即登入回答