Skip to content

Commit

Permalink
Update "disableConfig" to allow timeouts to work
Browse files Browse the repository at this point in the history
  • Loading branch information
hedgecrw committed Aug 13, 2023
1 parent 21a2ed6 commit 40c1ca5
Show file tree
Hide file tree
Showing 3 changed files with 133 additions and 124 deletions.
166 changes: 85 additions & 81 deletions src/main/c/Posix/SerialPort_Posix.c
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
* SerialPort_Posix.c
*
* Created on: Feb 25, 2012
* Last Updated on: Jul 08, 2023
* Last Updated on: Aug 11, 2023
* Author: Will Hedgecock
*
* Copyright (C) 2012-2023 Fazecast, Inc.
Expand Down Expand Up @@ -473,8 +473,6 @@ JNIEXPORT jlong JNICALL Java_com_fazecast_jSerialComm_SerialPort_openPortNative(
if (checkJniError(env, __LINE__ - 1)) return 0;
unsigned char requestElevatedPermissions = (*env)->GetBooleanField(env, obj, requestElevatedPermissionsField);
if (checkJniError(env, __LINE__ - 1)) return 0;
unsigned char disableAutoConfig = (*env)->GetBooleanField(env, obj, disableConfigField);
if (checkJniError(env, __LINE__ - 1)) return 0;
unsigned char autoFlushIOBuffers = (*env)->GetBooleanField(env, obj, autoFlushIOBuffersField);
if (checkJniError(env, __LINE__ - 1)) return 0;
unsigned char isDtrEnabled = (*env)->GetBooleanField(env, obj, isDtrEnabledField);
Expand Down Expand Up @@ -537,7 +535,7 @@ JNIEXPORT jlong JNICALL Java_com_fazecast_jSerialComm_SerialPort_openPortNative(
port->handle = -1;
pthread_mutex_unlock(&criticalSection);
}
else if (!disableAutoConfig && !Java_com_fazecast_jSerialComm_SerialPort_configPort(env, obj, (jlong)(intptr_t)port))
else if (!Java_com_fazecast_jSerialComm_SerialPort_configPort(env, obj, (jlong)(intptr_t)port))
{
// Close the port if there was a problem setting the parameters
fcntl(port->handle, F_SETFL, O_NONBLOCK);
Expand Down Expand Up @@ -568,6 +566,8 @@ JNIEXPORT jboolean JNICALL Java_com_fazecast_jSerialComm_SerialPort_configPort(J
{
// Retrieve port parameters from the Java class
serialPort *port = (serialPort*)(intptr_t)serialPortPointer;
unsigned char disableConfig = (*env)->GetBooleanField(env, obj, disableConfigField);
if (checkJniError(env, __LINE__ - 1)) return JNI_FALSE;
baud_rate baudRate = (*env)->GetIntField(env, obj, baudRateField);
if (checkJniError(env, __LINE__ - 1)) return JNI_FALSE;
int byteSizeInt = (*env)->GetIntField(env, obj, dataBitsField);
Expand Down Expand Up @@ -611,97 +611,101 @@ JNIEXPORT jboolean JNICALL Java_com_fazecast_jSerialComm_SerialPort_configPort(J
if (checkJniError(env, __LINE__ - 1)) return JNI_FALSE;
#endif

// Clear any serial port flags and set up raw non-canonical port parameters
// Configure port parameters if not explicitly disabled
struct termios options = { 0 };
tcgetattr(port->handle, &options);
options.c_cc[VSTART] = (unsigned char)xonStartChar;
options.c_cc[VSTOP] = (unsigned char)xoffStopChar;
options.c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP | INLCR | INPCK | IGNPAR | IGNCR | ICRNL | IXON | IXOFF | IXANY);
options.c_oflag &= ~OPOST;
options.c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN);
options.c_cflag &= ~(CSIZE | PARENB | CMSPAR | PARODD | CSTOPB | CRTSCTS);

// Update the user-specified port parameters
tcflag_t byteSize = (byteSizeInt == 5) ? CS5 : (byteSizeInt == 6) ? CS6 : (byteSizeInt == 7) ? CS7 : CS8;
tcflag_t parity = (parityInt == com_fazecast_jSerialComm_SerialPort_NO_PARITY) ? 0 : (parityInt == com_fazecast_jSerialComm_SerialPort_ODD_PARITY) ? (PARENB | PARODD) : (parityInt == com_fazecast_jSerialComm_SerialPort_EVEN_PARITY) ? PARENB : (parityInt == com_fazecast_jSerialComm_SerialPort_MARK_PARITY) ? (PARENB | CMSPAR | PARODD) : (PARENB | CMSPAR);
options.c_cflag |= (byteSize | parity | CLOCAL | CREAD);
if (!isDtrEnabled || !isRtsEnabled)
options.c_cflag &= ~HUPCL;
if (!rs485ModeEnabled)
options.c_iflag |= BRKINT;
if (stopBitsInt == com_fazecast_jSerialComm_SerialPort_TWO_STOP_BITS)
options.c_cflag |= CSTOPB;
if (byteSizeInt < 8)
options.c_iflag |= ISTRIP;
if (parityInt != 0)
options.c_iflag |= (INPCK | IGNPAR);
if (((flowControl & com_fazecast_jSerialComm_SerialPort_FLOW_CONTROL_CTS_ENABLED) > 0) || ((flowControl & com_fazecast_jSerialComm_SerialPort_FLOW_CONTROL_RTS_ENABLED) > 0))
options.c_cflag |= CRTSCTS;
if ((flowControl & com_fazecast_jSerialComm_SerialPort_FLOW_CONTROL_XONXOFF_IN_ENABLED) > 0)
options.c_iflag |= IXOFF;
if ((flowControl & com_fazecast_jSerialComm_SerialPort_FLOW_CONTROL_XONXOFF_OUT_ENABLED) > 0)
options.c_iflag |= IXON;

#if defined(__linux__)

// Attempt to set the transmit buffer size, closing wait time, and latency flags
struct serial_struct serInfo = { 0 };
if (!ioctl(port->handle, TIOCGSERIAL, &serInfo))
if (!disableConfig)
{
serInfo.closing_wait = 250;
serInfo.xmit_fifo_size = sendDeviceQueueSize;
serInfo.flags |= ASYNC_LOW_LATENCY;
ioctl(port->handle, TIOCSSERIAL, &serInfo);
}
// Clear any serial port flags and set up raw non-canonical port parameters
options.c_cc[VSTART] = (unsigned char)xonStartChar;
options.c_cc[VSTOP] = (unsigned char)xoffStopChar;
options.c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP | INLCR | INPCK | IGNPAR | IGNCR | ICRNL | IXON | IXOFF | IXANY);
options.c_oflag &= ~OPOST;
options.c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN);
options.c_cflag &= ~(CSIZE | PARENB | CMSPAR | PARODD | CSTOPB | CRTSCTS);

// Update the user-specified port parameters
tcflag_t byteSize = (byteSizeInt == 5) ? CS5 : (byteSizeInt == 6) ? CS6 : (byteSizeInt == 7) ? CS7 : CS8;
tcflag_t parity = (parityInt == com_fazecast_jSerialComm_SerialPort_NO_PARITY) ? 0 : (parityInt == com_fazecast_jSerialComm_SerialPort_ODD_PARITY) ? (PARENB | PARODD) : (parityInt == com_fazecast_jSerialComm_SerialPort_EVEN_PARITY) ? PARENB : (parityInt == com_fazecast_jSerialComm_SerialPort_MARK_PARITY) ? (PARENB | CMSPAR | PARODD) : (PARENB | CMSPAR);
options.c_cflag |= (byteSize | parity | CLOCAL | CREAD);
if (!isDtrEnabled || !isRtsEnabled)
options.c_cflag &= ~HUPCL;
if (!rs485ModeEnabled)
options.c_iflag |= BRKINT;
if (stopBitsInt == com_fazecast_jSerialComm_SerialPort_TWO_STOP_BITS)
options.c_cflag |= CSTOPB;
if (byteSizeInt < 8)
options.c_iflag |= ISTRIP;
if (parityInt != 0)
options.c_iflag |= (INPCK | IGNPAR);
if (((flowControl & com_fazecast_jSerialComm_SerialPort_FLOW_CONTROL_CTS_ENABLED) > 0) || ((flowControl & com_fazecast_jSerialComm_SerialPort_FLOW_CONTROL_RTS_ENABLED) > 0))
options.c_cflag |= CRTSCTS;
if ((flowControl & com_fazecast_jSerialComm_SerialPort_FLOW_CONTROL_XONXOFF_IN_ENABLED) > 0)
options.c_iflag |= IXOFF;
if ((flowControl & com_fazecast_jSerialComm_SerialPort_FLOW_CONTROL_XONXOFF_OUT_ENABLED) > 0)
options.c_iflag |= IXON;

// Retrieve the driver-reported transmit buffer size
if (!ioctl(port->handle, TIOCGSERIAL, &serInfo))
sendDeviceQueueSize = serInfo.xmit_fifo_size;
receiveDeviceQueueSize = sendDeviceQueueSize;
(*env)->SetIntField(env, obj, sendDeviceQueueSizeField, sendDeviceQueueSize);
if (checkJniError(env, __LINE__ - 1)) return JNI_FALSE;
(*env)->SetIntField(env, obj, receiveDeviceQueueSizeField, receiveDeviceQueueSize);
if (checkJniError(env, __LINE__ - 1)) return JNI_FALSE;
#if defined(__linux__)

// Attempt to set the requested RS-485 mode
struct serial_rs485 rs485Conf = { 0 };
if (!ioctl(port->handle, TIOCGRS485, &rs485Conf))
{
if (rs485ModeEnabled)
rs485Conf.flags |= SER_RS485_ENABLED;
else
rs485Conf.flags &= ~SER_RS485_ENABLED;
if (rs485ActiveHigh)
// Attempt to set the transmit buffer size, closing wait time, and latency flags
struct serial_struct serInfo = { 0 };
if (!ioctl(port->handle, TIOCGSERIAL, &serInfo))
{
rs485Conf.flags |= SER_RS485_RTS_ON_SEND;
rs485Conf.flags &= ~(SER_RS485_RTS_AFTER_SEND);
serInfo.closing_wait = 250;
serInfo.xmit_fifo_size = sendDeviceQueueSize;
serInfo.flags |= ASYNC_LOW_LATENCY;
ioctl(port->handle, TIOCSSERIAL, &serInfo);
}
else

// Retrieve the driver-reported transmit buffer size
if (!ioctl(port->handle, TIOCGSERIAL, &serInfo))
sendDeviceQueueSize = serInfo.xmit_fifo_size;
receiveDeviceQueueSize = sendDeviceQueueSize;
(*env)->SetIntField(env, obj, sendDeviceQueueSizeField, sendDeviceQueueSize);
if (checkJniError(env, __LINE__ - 1)) return JNI_FALSE;
(*env)->SetIntField(env, obj, receiveDeviceQueueSizeField, receiveDeviceQueueSize);
if (checkJniError(env, __LINE__ - 1)) return JNI_FALSE;

// Attempt to set the requested RS-485 mode
struct serial_rs485 rs485Conf = { 0 };
if (!ioctl(port->handle, TIOCGRS485, &rs485Conf))
{
rs485Conf.flags &= ~(SER_RS485_RTS_ON_SEND);
rs485Conf.flags |= SER_RS485_RTS_AFTER_SEND;
if (rs485ModeEnabled)
rs485Conf.flags |= SER_RS485_ENABLED;
else
rs485Conf.flags &= ~SER_RS485_ENABLED;
if (rs485ActiveHigh)
{
rs485Conf.flags |= SER_RS485_RTS_ON_SEND;
rs485Conf.flags &= ~(SER_RS485_RTS_AFTER_SEND);
}
else
{
rs485Conf.flags &= ~(SER_RS485_RTS_ON_SEND);
rs485Conf.flags |= SER_RS485_RTS_AFTER_SEND;
}
if (rs485RxDuringTx)
rs485Conf.flags |= SER_RS485_RX_DURING_TX;
else
rs485Conf.flags &= ~(SER_RS485_RX_DURING_TX);
if (rs485EnableTermination)
rs485Conf.flags |= SER_RS485_TERMINATE_BUS;
else
rs485Conf.flags &= ~(SER_RS485_TERMINATE_BUS);
rs485Conf.delay_rts_before_send = rs485DelayBefore / 1000;
rs485Conf.delay_rts_after_send = rs485DelayAfter / 1000;
ioctl(port->handle, TIOCSRS485, &rs485Conf);
}
if (rs485RxDuringTx)
rs485Conf.flags |= SER_RS485_RX_DURING_TX;
else
rs485Conf.flags &= ~(SER_RS485_RX_DURING_TX);
if (rs485EnableTermination)
rs485Conf.flags |= SER_RS485_TERMINATE_BUS;
else
rs485Conf.flags &= ~(SER_RS485_TERMINATE_BUS);
rs485Conf.delay_rts_before_send = rs485DelayBefore / 1000;
rs485Conf.delay_rts_after_send = rs485DelayAfter / 1000;
ioctl(port->handle, TIOCSRS485, &rs485Conf);
}

#else

(*env)->SetIntField(env, obj, sendDeviceQueueSizeField, sysconf(_SC_PAGESIZE));
if (checkJniError(env, __LINE__ - 1)) return JNI_FALSE;
(*env)->SetIntField(env, obj, receiveDeviceQueueSizeField, sysconf(_SC_PAGESIZE));
if (checkJniError(env, __LINE__ - 1)) return JNI_FALSE;
(*env)->SetIntField(env, obj, sendDeviceQueueSizeField, sysconf(_SC_PAGESIZE));
if (checkJniError(env, __LINE__ - 1)) return JNI_FALSE;
(*env)->SetIntField(env, obj, receiveDeviceQueueSizeField, sysconf(_SC_PAGESIZE));
if (checkJniError(env, __LINE__ - 1)) return JNI_FALSE;

#endif
}

// Configure the serial port read and write timeouts
int flags = 0;
Expand Down
88 changes: 46 additions & 42 deletions src/main/c/Windows/SerialPort_Windows.c
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
* SerialPort_Windows.c
*
* Created on: Feb 25, 2012
* Last Updated on: Jul 08, 2023
* Last Updated on: Aug 11, 2023
* Author: Will Hedgecock
*
* Copyright (C) 2012-2023 Fazecast, Inc.
Expand Down Expand Up @@ -686,8 +686,6 @@ JNIEXPORT jlong JNICALL Java_com_fazecast_jSerialComm_SerialPort_openPortNative(
if (checkJniError(env, __LINE__ - 1)) return 0;
unsigned char requestElevatedPermissions = (*env)->GetBooleanField(env, obj, requestElevatedPermissionsField);
if (checkJniError(env, __LINE__ - 1)) return 0;
unsigned char disableAutoConfig = (*env)->GetBooleanField(env, obj, disableConfigField);
if (checkJniError(env, __LINE__ - 1)) return 0;
unsigned char autoFlushIOBuffers = (*env)->GetBooleanField(env, obj, autoFlushIOBuffersField);
if (checkJniError(env, __LINE__ - 1)) return 0;
unsigned char isDtrEnabled = (*env)->GetBooleanField(env, obj, isDtrEnabledField);
Expand Down Expand Up @@ -739,7 +737,7 @@ JNIEXPORT jlong JNICALL Java_com_fazecast_jSerialComm_SerialPort_openPortNative(
Java_com_fazecast_jSerialComm_SerialPort_clearRTS(env, obj, (jlong)(intptr_t)port);

// Configure the port parameters and timeouts
if (!disableAutoConfig && !Java_com_fazecast_jSerialComm_SerialPort_configPort(env, obj, (jlong)(intptr_t)port))
if (!Java_com_fazecast_jSerialComm_SerialPort_configPort(env, obj, (jlong)(intptr_t)port))
{
// Close the port if there was a problem setting the parameters
PurgeComm(port->handle, PURGE_RXABORT | PURGE_RXCLEAR | PURGE_TXABORT | PURGE_TXCLEAR);
Expand Down Expand Up @@ -767,6 +765,8 @@ JNIEXPORT jboolean JNICALL Java_com_fazecast_jSerialComm_SerialPort_configPort(J
{
// Retrieve port parameters from the Java class
serialPort *port = (serialPort*)(intptr_t)serialPortPointer;
unsigned char disableConfig = (*env)->GetBooleanField(env, obj, disableConfigField);
if (checkJniError(env, __LINE__ - 1)) return JNI_FALSE;
DWORD baudRate = (DWORD)(*env)->GetIntField(env, obj, baudRateField);
if (checkJniError(env, __LINE__ - 1)) return JNI_FALSE;
BYTE byteSize = (BYTE)(*env)->GetIntField(env, obj, dataBitsField);
Expand Down Expand Up @@ -812,46 +812,50 @@ JNIEXPORT jboolean JNICALL Java_com_fazecast_jSerialComm_SerialPort_configPort(J
BOOL XonXoffInEnabled = ((flowControl & com_fazecast_jSerialComm_SerialPort_FLOW_CONTROL_XONXOFF_IN_ENABLED) > 0);
BOOL XonXoffOutEnabled = ((flowControl & com_fazecast_jSerialComm_SerialPort_FLOW_CONTROL_XONXOFF_OUT_ENABLED) > 0);

// Retrieve existing port configuration
DCB dcbSerialParams;
memset(&dcbSerialParams, 0, sizeof(DCB));
dcbSerialParams.DCBlength = sizeof(DCB);
if (!SetupComm(port->handle, receiveDeviceQueueSize, sendDeviceQueueSize) || !GetCommState(port->handle, &dcbSerialParams))
// Configure port parameters if not explicitly disabled
if (!disableConfig)
{
port->errorLineNumber = lastErrorLineNumber = __LINE__ - 2;
port->errorNumber = lastErrorNumber = GetLastError();
return JNI_FALSE;
}

// Set updated port parameters
dcbSerialParams.BaudRate = baudRate;
dcbSerialParams.ByteSize = byteSize;
dcbSerialParams.StopBits = stopBits;
dcbSerialParams.Parity = parity;
dcbSerialParams.fParity = isParity;
dcbSerialParams.fBinary = TRUE;
dcbSerialParams.fAbortOnError = FALSE;
dcbSerialParams.fRtsControl = RTSValue;
dcbSerialParams.fOutxCtsFlow = CTSEnabled;
dcbSerialParams.fOutxDsrFlow = DSREnabled;
dcbSerialParams.fDtrControl = DTRValue;
dcbSerialParams.fDsrSensitivity = DSREnabled;
dcbSerialParams.fOutX = XonXoffOutEnabled;
dcbSerialParams.fInX = XonXoffInEnabled;
dcbSerialParams.fTXContinueOnXoff = TRUE;
dcbSerialParams.fErrorChar = FALSE;
dcbSerialParams.fNull = FALSE;
dcbSerialParams.XonLim = 2048;
dcbSerialParams.XoffLim = 512;
dcbSerialParams.XonChar = xonStartChar;
dcbSerialParams.XoffChar = xoffStopChar;
// Retrieve existing port configuration
DCB dcbSerialParams;
memset(&dcbSerialParams, 0, sizeof(DCB));
dcbSerialParams.DCBlength = sizeof(DCB);
if (!SetupComm(port->handle, receiveDeviceQueueSize, sendDeviceQueueSize) || !GetCommState(port->handle, &dcbSerialParams))
{
port->errorLineNumber = lastErrorLineNumber = __LINE__ - 2;
port->errorNumber = lastErrorNumber = GetLastError();
return JNI_FALSE;
}

// Apply changes
if (!SetCommState(port->handle, &dcbSerialParams))
{
port->errorLineNumber = lastErrorLineNumber = __LINE__ - 2;
port->errorNumber = lastErrorNumber = GetLastError();
return JNI_FALSE;
// Set updated port parameters
dcbSerialParams.BaudRate = baudRate;
dcbSerialParams.ByteSize = byteSize;
dcbSerialParams.StopBits = stopBits;
dcbSerialParams.Parity = parity;
dcbSerialParams.fParity = isParity;
dcbSerialParams.fBinary = TRUE;
dcbSerialParams.fAbortOnError = FALSE;
dcbSerialParams.fRtsControl = RTSValue;
dcbSerialParams.fOutxCtsFlow = CTSEnabled;
dcbSerialParams.fOutxDsrFlow = DSREnabled;
dcbSerialParams.fDtrControl = DTRValue;
dcbSerialParams.fDsrSensitivity = DSREnabled;
dcbSerialParams.fOutX = XonXoffOutEnabled;
dcbSerialParams.fInX = XonXoffInEnabled;
dcbSerialParams.fTXContinueOnXoff = TRUE;
dcbSerialParams.fErrorChar = FALSE;
dcbSerialParams.fNull = FALSE;
dcbSerialParams.XonLim = 2048;
dcbSerialParams.XoffLim = 512;
dcbSerialParams.XonChar = xonStartChar;
dcbSerialParams.XoffChar = xoffStopChar;

// Apply changes
if (!SetCommState(port->handle, &dcbSerialParams))
{
port->errorLineNumber = lastErrorLineNumber = __LINE__ - 2;
port->errorNumber = lastErrorNumber = GetLastError();
return JNI_FALSE;
}
}

// Get event flags from the Java class
Expand Down
3 changes: 2 additions & 1 deletion src/main/java/com/fazecast/jSerialComm/SerialPort.java
Original file line number Diff line number Diff line change
Expand Up @@ -450,7 +450,8 @@ static public SerialPort[] getCommPorts()
* Allocates a {@link SerialPort} object corresponding to the user-specified port descriptor.
* <p>
* On Windows machines, this descriptor should be in the form of "COM[*]".<br>
* On Linux machines, the descriptor will look similar to "/dev/tty[*]".
* On Linux machines, the descriptor will look similar to "/dev/tty[*]".<br>
* On Android machines, this method is unavailable and will return <b>null</b>.
*
* @param portDescriptor The desired serial port to use with this library.
* @return A {@link SerialPort} object.
Expand Down

0 comments on commit 40c1ca5

Please sign in to comment.