usb-serial-for-android icon indicating copy to clipboard operation
usb-serial-for-android copied to clipboard

[Support] Reading data into the ByteBuffer at a specific offset.

Open nghinguyengr opened this issue 6 months ago • 1 comments

Hello everyone,

In my use case, I need to read the data from the serial port into the ByteBuffer at a specific offset.

Currently, the library only allows the offset to start from 0. You can verify it at line 219, CommonUsbSerialPort.java

protected int read(final byte[] dest, int length, final int timeout, boolean testConnection) throws IOException {
        testConnection(false);
        if(length <= 0) {
            throw new IllegalArgumentException("Read length too small");
        }
        length = Math.min(length, dest.length);
        final int nread;
        if (timeout != 0) {
            // bulkTransfer will cause data loss with short timeout + high baud rates + continuous transfer
            //   https://stackoverflow.com/questions/9108548/android-usb-host-bulktransfer-is-losing-data
            // but mConnection.requestWait(timeout) available since Android 8.0 es even worse,
            // as it crashes with short timeout, e.g.
            //   A/libc: Fatal signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 0x276a in tid 29846 (pool-2-thread-1), pid 29618 (.usbserial.test)
            //     /system/lib64/libusbhost.so (usb_request_wait+192)
            //     /system/lib64/libandroid_runtime.so (android_hardware_UsbDeviceConnection_request_wait(_JNIEnv*, _jobject*, long)+84)
            // data loss / crashes were observed with timeout up to 200 msec
            long endTime = testConnection ? MonotonicClock.millis() + timeout : 0;
            int readMax = (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) ? length : Math.min(length, MAX_READ_SIZE);
            nread = mConnection.bulkTransfer(mReadEndpoint, dest, readMax, timeout);
            // Android error propagation is improvable:
            //  nread == -1 can be: timeout, connection lost, buffer to small, ???
            if(nread == -1 && testConnection)
                testConnection(MonotonicClock.millis() < endTime);

        } else {
            final ByteBuffer buf = ByteBuffer.wrap(dest, 0, length);
            if (!mUsbRequest.queue(buf, length)) {
                throw new IOException("Queueing USB request failed");
            }
            final UsbRequest response = mConnection.requestWait();
            if (response == null) {
                throw new IOException("Waiting for USB request failed");
            }
            nread = buf.position();
            // Android error propagation is improvable:
            //   response != null & nread == 0 can be: connection lost, buffer to small, ???
            if(nread == 0) {
                testConnection(true);
            }
        }
        return Math.max(nread, 0);
    }

Please forgive me if something is wrong. I'd appreciate your help.

nghinguyengr avatar May 21 '25 10:05 nghinguyengr

Hi @kai-morich ,

Here is the logic for writing/reading by Sink/Source. You can find it in UDP Connection

Source:

Image

Sink:

Image

You can see that write/read methods of the UDP Channel both support specifying an offset to write/read.

I want to contribute to that repo so that it works with serial, but I'm stuck here.

nghinguyengr avatar May 22 '25 01:05 nghinguyengr