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);
}
}
}
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));
}
Aggregations