in src/main/c/Posix/SerialPort_Posix.c [965:1050]
JNIEXPORT jint JNICALL Java_com_fazecast_jSerialComm_SerialPort_readBytes(JNIEnv *env, jobject obj, jlong serialPortPointer, jbyteArray buffer, jint bytesToRead, jint offset, jint timeoutMode, jint readTimeout)
{
// Ensure that a positive number of bytes was passed in to read
jsize bufferLength = (*env)->GetArrayLength(env, buffer);
serialPort *port = (serialPort*)(intptr_t)serialPortPointer;
if ((bytesToRead < 0) || (offset < 0) || (bufferLength < offset))
return -1;
// Fetch a pointer to the underlying data buffer
int numBytesRead = -1, numBytesReadTotal = offset, ioctlResult = 0;
int bytesRemaining = ((bytesToRead + offset) > bufferLength) ? (bufferLength - offset) : bytesToRead;
jbyte *readBuffer = (*env)->GetByteArrayElements(env, buffer, NULL);
if (checkJniError(env, __LINE__ - 1) || !readBuffer)
return -1;
// Infinite blocking mode specified, don't return until we have completely finished the read
if (((timeoutMode & com_fazecast_jSerialComm_SerialPort_TIMEOUT_READ_BLOCKING) > 0) && (readTimeout == 0))
{
// While there are more bytes we are supposed to read
while (bytesRemaining > 0)
{
// Attempt to read some number of bytes from the serial port
port->errorLineNumber = __LINE__ + 1;
do { errno = 0; numBytesRead = read(port->handle, readBuffer + numBytesReadTotal, bytesRemaining); port->errorNumber = errno; } while ((numBytesRead < 0) && (errno == EINTR));
if ((numBytesRead == -1) || ((numBytesRead == 0) && (ioctl(port->handle, FIONREAD, &ioctlResult) == -1)))
{
// If all bytes were not successfully read, it is an error
numBytesRead = -1;
break;
}
// Fix index variables
numBytesReadTotal += numBytesRead;
bytesRemaining -= numBytesRead;
}
}
else if ((timeoutMode & com_fazecast_jSerialComm_SerialPort_TIMEOUT_READ_BLOCKING) > 0) // Blocking mode, but not indefinitely
{
// Get current system time
struct timespec expireTime, currTime;
clock_gettime(CLOCK_MONOTONIC, &expireTime);
expireTime.tv_sec += (readTimeout / 1000);
expireTime.tv_nsec += ((readTimeout % 1000) * 1000000);
if (expireTime.tv_nsec >= 1000000000)
{
expireTime.tv_sec += 1;
expireTime.tv_nsec -= 1000000000;
}
// While there are more bytes we are supposed to read and the timeout has not elapsed
do
{
port->errorLineNumber = __LINE__ + 1;
do { errno = 0; numBytesRead = read(port->handle, readBuffer + numBytesReadTotal, bytesRemaining); port->errorNumber = errno; } while ((numBytesRead < 0) && (errno == EINTR));
if ((numBytesRead == -1) || ((numBytesRead == 0) && (ioctl(port->handle, FIONREAD, &ioctlResult) == -1)))
{
// If any bytes were read, return those bytes
if (!numBytesReadTotal)
numBytesRead = -1;
break;
}
// Fix index variables
numBytesReadTotal += numBytesRead;
bytesRemaining -= numBytesRead;
// Get current system time
clock_gettime(CLOCK_MONOTONIC, &currTime);
} while ((bytesRemaining > 0) && ((expireTime.tv_sec > currTime.tv_sec) || ((expireTime.tv_sec == currTime.tv_sec) && (expireTime.tv_nsec > currTime.tv_nsec))));
}
else // Semi- or non-blocking specified
{
// Read from the port
port->errorLineNumber = __LINE__ + 1;
do { errno = 0; numBytesRead = read(port->handle, readBuffer + numBytesReadTotal, bytesRemaining); port->errorNumber = errno; } while ((numBytesRead < 0) && (errno == EINTR));
if ((numBytesRead == -1) || ((numBytesRead == 0) && (ioctl(port->handle, FIONREAD, &ioctlResult) == -1)))
numBytesRead = -1;
else
numBytesReadTotal += numBytesRead;
}
// Return number of bytes read if successful
(*env)->ReleaseByteArrayElements(env, buffer, readBuffer, (numBytesRead == -1) ? JNI_ABORT : 0);
checkJniError(env, __LINE__ - 1);
return (numBytesRead == -1) ? -1 : (numBytesReadTotal - offset);
}