0

So I'm receiving byte arrays from USB device (some log messages) and I'm facing an issue, I don't know what is the best way to parse or read them...

So this is the receiver:

static class ReceiveLogsThread implements Runnable {
    private static final String TAG = "IoTReceiveLogsThread";
    Message msgRead;

    ReceiveLogsThread() {
    }

    public void run() {
        byte[] rbuf = new byte[4096];
        while (!Thread.currentThread().isInterrupted()) {
            try {
                int len = mSerial.readLog(rbuf, mSerialPortLog);
                if (len > 0) {
                //    Crashlytics.log(Log.DEBUG, TAG, "ReceiveLogsThread: " + printHex(rbuf));
                //    this.msgRead = receiveLogsHandler.obtainMessage(HANDLE_READ, printHex(rbuf));
                    this.msgRead = receiveLogsHandler.obtainMessage(HANDLE_READ, rbuf);
                    receiveLogsHandler.sendMessage(this.msgRead);
                }
            } catch (NullPointerException e1) {
                e1.printStackTrace();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        Thread.currentThread().interrupt();
        if (!mReadFlag) {
            Crashlytics.log(Log.WARN, TAG, "Receive thread finished");
        }
    }
}

As you can see, printHex() method is commented because I think it caused me an issue with losing some of those messages due to real time parsing, as you can see from it's implementation

   private static String printHex(byte[] bytes) {
    Formatter formatter = new Formatter();

    for (byte b : bytes) {
        formatter.format("%02x", b);
    }
    String hex = formatter.toString();
    return hex;
}

I don't thinks it's a good idea to do a printHex method as soon as I receive byte array, because bytes are comming so fast, so I want to try another way..

I want to send them as byte arrays and then parse them after I'm done with everything, so I'm not sure how to implement it right...

Here is a receive handler from my activity where I'm storing those arrays into List of byte arrays that could contain like 30000 byte arrays:

    private List<byte[]> logs = new ArrayList<>();

Handler receiveLogsHandler = new Handler(Looper.getMainLooper()) {
    public void handleMessage(Message msgRW) {
        super.handleMessage(msgRW);
        //   logMessagesList.add(msgRW.obj.toString().toUpperCase());
        //      String message = msgRW.obj.toString().toUpperCase();

        if(shouldCollectLogs) {
            byte[] message = (byte[]) msgRW.obj;
            logs.add(message);
        }

....

So the problem I'm facing here is, how to combine all those byte arrays into one! And then do printHex on that one big array..

joe
  • 1,341
  • 4
  • 21
  • 32
  • Even though I can't give you a detailed answer, I reccommend you to take a look to RxJava, especially to Flowables, Backpressure and Buffer. http://reactivex.io/intro.html – dglozano Nov 23 '18 at 18:35
  • Thank you my friend, but I don't have time to implement that :) – joe Nov 23 '18 at 18:38
  • So, maybe I am not understanding correctly: What you want to do is to process the List in your Handler and transform it into a List in which each string is the result of printToHex(bytes)? If that's the case, I'll post a simple answer now – dglozano Nov 23 '18 at 19:08
  • The issue is: I'm receiving byte arrays and I immediately format them via pritHex method, which I think causes some delays and I lose some bytes which then causes messages to be unreadable... So I want to, istead of formating it to hex right away, add all those byte arrays into something (list of byte arrays) and then combine then in one in one big byte array (could be huge!). And then go through that big array and do formatting... In that time, receiver will be stopped and hopefully no bytes would be lost... – joe Nov 23 '18 at 19:11
  • Yes, I understood the general idea, but I don't know if you need help with all of that or just the bytes formatting at the end – dglozano Nov 23 '18 at 19:18
  • I posted another question, generally about the whole idea.. But if you have any idea how to deal with all those byte arrays, please... :) – joe Nov 23 '18 at 19:22
  • There is nothing being lost, just your code is so bad. 1. Your printHex function is only returning the last byte. 2. You are ignoring the bytes read Len value, and assuming that the whole 4096 bytes have data, which is not always true. In addition, msgRead should not be a class variable. – lionscribe Nov 23 '18 at 19:37
  • Man, this is a legacy code, I feel the same! :) I'm in this company for only 2 months and we had to implement that functionality in short period, so I assume this isn't working as it should.. Please, if you have any solution that I could try, I have a deadline until tomorrow and any help would be very welcome – joe Nov 23 '18 at 19:43
  • I have posted some code. Just call `printToHex(rbuf, len)` – lionscribe Nov 23 '18 at 20:06

2 Answers2

0

Okay, so here are two alternatives to process the final list of byte arrays at the end, depending on what you want.

Alternative 1: Collect to List of String

List<String> hexStrings = listOfBytes.parallelStream() //Process in paralell each byte array
            .map(bytes -> printHex(bytes)) // Map each byte array from byte[] to String
            .collect(Collectors.toList());// Collect the streams into one final list

Alternative 2: Collect to one String

String oneBigStringOfBytesInHex = listOfBytes.parallelStream() //Process in paralell each byte array
                .map(bytes -> printHex(bytes)) // Map each byte array from byte[] to String
                .collect(Collectors.joining()); // Concat the streams into one final String

You should be careful with the second alternative, you have to consider that the maximum size of a String is 2147483647 (2^31 - 1). Anyway, if your final amount of data is a List of 30.000 bytes arrays of 4096 bytes each, you shouldn't have any problem.

dglozano
  • 6,369
  • 2
  • 19
  • 38
0

Your printToHex function should be as follows, passing the bytes read count. I copied some of the code from a different post.

private final static char[] hexArray = "0123456789ABCDEF".toCharArray(); 
public static String printToHex(byte[] bytes, int len) { 
    char[] hexChars = new char[len * 2]; 
    for ( int j = 0; j < len; j++ ) { 
        int v = bytes[j] & 0xFF; 
        hexChars[j * 2] = hexArray[v >>> 4];
        hexChars[j * 2 + 1] = hexArray[v & 0x0F]; 
    }
    return new String(hexChars); 
}
lionscribe
  • 3,413
  • 1
  • 16
  • 21
  • Still feels like I'm losing some messages :/ I don't know if the buffer size is a problem, or bulk transfer timeout.. I know I should receive more of that one particular message, but I only received one – joe Nov 23 '18 at 20:20
  • @joe Use the logCat to print how many bytes you get with call to printHex and without, and compare. – lionscribe Nov 23 '18 at 20:56
  • It's tough to log it that way, because I don't know how many messages I should receive... I know I should look for a particular messages that should occur, actually more of the same message should be received after I send particular AT command...I either see one message or sometimes none.. But I should receive more... so that could only mean that some of them are "lost" – joe Nov 24 '18 at 02:20