Search in sources :

Example 1 with RobotUsbTimeoutException

use of org.firstinspires.ftc.robotcore.internal.usb.exception.RobotUsbTimeoutException in project robotcode by OutoftheBoxFTC.

the class ModernRoboticsReaderWriter method readIncomingBytes.

protected void readIncomingBytes(byte[] buffer, int ibFirst, int cbToRead, int msExtraTimeout, @Nullable TimeWindow timeWindow, String debugContext) throws RobotUsbException, InterruptedException {
    if (cbToRead > 0) {
        // In theory, per the MR spec, we might see MS_INTER_BYTE_TIMEOUT elapse
        // between each incoming byte. For a long-ish read response, that can amount
        // to some significant time: we routinely read 31 byte swaths of data on the
        // motor controller, for example, which would amount to nearly a third of a second
        // to see the response. Now that doesn't happen in practice: most inter-byte intervals
        // are actually much smaller than permitted. We could in theory do the MS_INTER_BYTE_TIMEOUT
        // timeouts on each individual byte, but that's cumbersome and inefficient given the read
        // API we have to work with. So instead we specify the pessimistic maximum, plus a little
        // extra to help avoid false hits, and thus see any communications failure a little
        // later than we otherwise would see (but not ridiculously later).
        // 
        // Additionally, we allow for any extra timeout duration that has to do with other protocol
        // aspects unrelated to inter-byte timing.
        // 
        // Finally, we allow for a garbage collection.
        // 
        long msReadTimeout = MS_INTER_BYTE_TIMEOUT * (cbToRead + 2) + msExtraTimeout + MS_GARBAGE_COLLECTION_SPURT;
        // 
        // That all said, that leads to rediculously long timeouts. We got by for a long time with
        // a fixed 100ms timeout, and the retry logic above will help us even more. So we prune that
        // down
        // 
        msReadTimeout = Math.min(msReadTimeout, MS_MAX_TIMEOUT);
        long nsTimerStart = System.nanoTime();
        int cbRead = device.read(buffer, ibFirst, cbToRead, msReadTimeout, timeWindow);
        if (cbRead == cbToRead) {
        // We got all the data we came for. Just return gracefully
        } else if (cbRead == 0) {
            // Couldn't read all the data in the time allotted.
            throw new RobotUsbTimeoutException(nsTimerStart, "%s: unable to read %d bytes in %d ms", debugContext, cbToRead, msReadTimeout);
        } else {
            // An unexpected error occurred. We'll classify as a protocol error as a good guess, as
            // we did get *some* data, just not all we were expecting.
            logAndThrowProtocol("readIncomingBytes(%s) cbToRead=%d cbRead=%d", debugContext, cbToRead, cbRead);
        }
    }
}
Also used : RobotUsbTimeoutException(org.firstinspires.ftc.robotcore.internal.usb.exception.RobotUsbTimeoutException) SuppressLint(android.annotation.SuppressLint)

Example 2 with RobotUsbTimeoutException

use of org.firstinspires.ftc.robotcore.internal.usb.exception.RobotUsbTimeoutException in project robotcode by OutoftheBoxFTC.

the class ModernRoboticsReaderWriter method readResponse.

// ----------------------------------------------------------------------------------------------
// Response reading
// ----------------------------------------------------------------------------------------------
protected ModernRoboticsResponse readResponse(ModernRoboticsRequest request, @Nullable TimeWindow payloadTimeWindow) throws RobotUsbException, InterruptedException {
    responseDeadline.reset();
    while (!responseDeadline.hasExpired()) {
        // we're not currently there, then we can't possibly be synchronized.
        if (!device.mightBeAtUsbPacketStart()) {
            isSynchronized = false;
        }
        // Read the header, synchronizing carefully if we need to
        ModernRoboticsResponse header = ModernRoboticsResponse.newInstance(responseAllocationContext, 0);
        try {
            if (!isSynchronized) {
                byte[] singleByte = new byte[1];
                byte[] headerSuffix = new byte[ModernRoboticsDatagram.CB_HEADER - 2];
                // Synchronization bytes by their nature occur only at the start of USB packets.
                // So if we know we're not at such a boundary, skip along until the next one.
                device.skipToLikelyUsbPacketStart();
                // Synchronize by looking for the first synchronization byte
                if (readSingleByte(singleByte, MS_REQUEST_RESPONSE_TIMEOUT, null, "sync0") != ModernRoboticsResponse.syncBytes[0]) {
                    continue;
                }
                // Having found the first, if we don't next see the second, then go back to looking for the first
                if (readSingleByte(singleByte, 0, null, "sync1") != ModernRoboticsResponse.syncBytes[1]) {
                    continue;
                }
                // Read the remaining header bytes
                readIncomingBytes(headerSuffix, 0, headerSuffix.length, 0, null, "syncSuffix");
                // Assemble the header from the pieces
                System.arraycopy(ModernRoboticsResponse.syncBytes, 0, header.data, 0, 2);
                System.arraycopy(headerSuffix, 0, header.data, 2, headerSuffix.length);
            } else {
                readIncomingBytes(header.data, 0, header.data.length, MS_REQUEST_RESPONSE_TIMEOUT, null, "header");
                if (!header.syncBytesValid()) {
                    // We've lost synchronization, yet we received *some* data. Thus, since there
                    // is no retransmission in the USB protocol, we're never going to get the response
                    // that we were looking for. So get out of Dodge with an error.
                    logAndThrowProtocol(request, header, COMM_SYNC_LOST);
                }
            }
            // Make sure the request and response types match
            if (!header.isFailure()) {
                if (request.isRead() != header.isRead() || request.getFunction() != header.getFunction()) {
                    logAndThrowProtocol(request, header, request.isWrite() ? COMM_TYPE_ERROR_WRITE : COMM_TYPE_ERROR_READ);
                }
            }
            // How big of a payload is expected in the response? It should match the expectations
            // set in the request. If it doesn't, get out of Dodge.
            int cbPayloadExpected = header.isFailure() ? 0 : request.isWrite() ? 0 : request.getPayloadLength();
            if (cbPayloadExpected != header.getPayloadLength()) {
                // We're out of sync some how
                logAndThrowProtocol(request, header, request.isWrite() ? COMM_PAYLOAD_ERROR_WRITE : COMM_PAYLOAD_ERROR_READ);
            }
            // Assemble a response and read the payload data thereinto
            ModernRoboticsResponse result = ModernRoboticsResponse.newInstance(responseAllocationContext, header.getPayloadLength());
            System.arraycopy(header.data, 0, result.data, 0, header.data.length);
            readIncomingBytes(result.data, header.data.length, header.getPayloadLength(), 0, payloadTimeWindow, "payload");
            // We're ok to go more quickly the next time
            isSynchronized = true;
            return result;
        } finally {
            if (header != null) {
                header.close();
            }
        }
    }
    throw new RobotUsbTimeoutException(responseDeadline.startTimeNanoseconds(), "timeout waiting %d ms for response", responseDeadline.getDuration(TimeUnit.MILLISECONDS));
}
Also used : RobotUsbTimeoutException(org.firstinspires.ftc.robotcore.internal.usb.exception.RobotUsbTimeoutException) SuppressLint(android.annotation.SuppressLint)

Aggregations

SuppressLint (android.annotation.SuppressLint)2 RobotUsbTimeoutException (org.firstinspires.ftc.robotcore.internal.usb.exception.RobotUsbTimeoutException)2