in src/main/c/Posix/SerialPort_Posix.c [588:821]
JNIEXPORT jboolean JNICALL Java_com_fazecast_jSerialComm_SerialPort_configPort(JNIEnv *env, jobject obj, jlong serialPortPointer)
{
// 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);
if (checkJniError(env, __LINE__ - 1)) return JNI_FALSE;
int stopBitsInt = (*env)->GetIntField(env, obj, stopBitsField);
if (checkJniError(env, __LINE__ - 1)) return JNI_FALSE;
int parityInt = (*env)->GetIntField(env, obj, parityField);
if (checkJniError(env, __LINE__ - 1)) return JNI_FALSE;
int timeoutMode = (*env)->GetIntField(env, obj, timeoutModeField);
if (checkJniError(env, __LINE__ - 1)) return JNI_FALSE;
int readTimeout = (*env)->GetIntField(env, obj, readTimeoutField);
if (checkJniError(env, __LINE__ - 1)) return JNI_FALSE;
int eventsToMonitor = (*env)->GetIntField(env, obj, eventFlagsField);
if (checkJniError(env, __LINE__ - 1)) return JNI_FALSE;
int flowControl = (*env)->GetIntField(env, obj, flowControlField);
if (checkJniError(env, __LINE__ - 1)) return JNI_FALSE;
unsigned char rs485ModeEnabled = (*env)->GetBooleanField(env, obj, rs485ModeField);
if (checkJniError(env, __LINE__ - 1)) return JNI_FALSE;
unsigned char isDtrEnabled = (*env)->GetBooleanField(env, obj, isDtrEnabledField);
if (checkJniError(env, __LINE__ - 1)) return JNI_FALSE;
unsigned char isRtsEnabled = (*env)->GetBooleanField(env, obj, isRtsEnabledField);
if (checkJniError(env, __LINE__ - 1)) return JNI_FALSE;
char xonStartChar = (*env)->GetByteField(env, obj, xonStartCharField);
if (checkJniError(env, __LINE__ - 1)) return JNI_FALSE;
char xoffStopChar = (*env)->GetByteField(env, obj, xoffStopCharField);
if (checkJniError(env, __LINE__ - 1)) return JNI_FALSE;
#if defined(__linux__)
unsigned char rs485ModeControlEnabled = (*env)->GetBooleanField(env, obj, rs485ModeControlEnabledField);
if (checkJniError(env, __LINE__ - 1)) return JNI_FALSE;
int sendDeviceQueueSize = (*env)->GetIntField(env, obj, sendDeviceQueueSizeField);
if (checkJniError(env, __LINE__ - 1)) return JNI_FALSE;
int receiveDeviceQueueSize = (*env)->GetIntField(env, obj, receiveDeviceQueueSizeField);
if (checkJniError(env, __LINE__ - 1)) return JNI_FALSE;
int rs485DelayBefore = (*env)->GetIntField(env, obj, rs485DelayBeforeField);
if (checkJniError(env, __LINE__ - 1)) return JNI_FALSE;
int rs485DelayAfter = (*env)->GetIntField(env, obj, rs485DelayAfterField);
if (checkJniError(env, __LINE__ - 1)) return JNI_FALSE;
unsigned char rs485ActiveHigh = (*env)->GetBooleanField(env, obj, rs485ActiveHighField);
if (checkJniError(env, __LINE__ - 1)) return JNI_FALSE;
unsigned char rs485EnableTermination = (*env)->GetBooleanField(env, obj, rs485EnableTerminationField);
if (checkJniError(env, __LINE__ - 1)) return JNI_FALSE;
unsigned char rs485RxDuringTx = (*env)->GetBooleanField(env, obj, rs485RxDuringTxField);
if (checkJniError(env, __LINE__ - 1)) return JNI_FALSE;
#endif
// Configure port parameters if not explicitly disabled
struct termios options = { 0 };
tcgetattr(port->handle, &options);
if (!disableConfig)
{
// 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;
#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))
{
serInfo.closing_wait = 250;
serInfo.xmit_fifo_size = sendDeviceQueueSize;
serInfo.flags |= ASYNC_LOW_LATENCY;
ioctl(port->handle, TIOCSSERIAL, &serInfo);
}
// 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;
// Configure RS-485 mode if requested
if (rs485ModeControlEnabled) {
// 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)
{
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);
}
}
#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;
#endif
}
else
{
// Update the Java-side port configuration values
(*env)->SetIntField(env, obj, dataBitsField, (options.c_cflag & CS5) ? 5 : ((options.c_cflag & CS6) ? 6 : ((options.c_cflag & CS7) ? 7 : 8)));
(*env)->SetIntField(env, obj, stopBitsField, (options.c_cflag & CSTOPB) ? com_fazecast_jSerialComm_SerialPort_TWO_STOP_BITS : com_fazecast_jSerialComm_SerialPort_ONE_STOP_BIT);
(*env)->SetIntField(env, obj, parityField, ((options.c_cflag & (PARENB | CMSPAR | PARODD)) == (PARENB | CMSPAR | PARODD)) ? com_fazecast_jSerialComm_SerialPort_MARK_PARITY : (((options.c_cflag & (PARENB | CMSPAR)) == (PARENB | CMSPAR)) ? com_fazecast_jSerialComm_SerialPort_SPACE_PARITY : (((options.c_cflag & (PARENB | PARODD)) == (PARENB | PARODD)) ? com_fazecast_jSerialComm_SerialPort_ODD_PARITY : ((options.c_cflag & PARENB) ? com_fazecast_jSerialComm_SerialPort_EVEN_PARITY : com_fazecast_jSerialComm_SerialPort_NO_PARITY))));
(*env)->SetByteField(env, obj, xonStartCharField, options.c_cc[VSTART]);
(*env)->SetByteField(env, obj, xoffStopCharField, options.c_cc[VSTOP]);
int flowControl = ((options.c_cflag & CRTSCTS) ? (com_fazecast_jSerialComm_SerialPort_FLOW_CONTROL_CTS_ENABLED | com_fazecast_jSerialComm_SerialPort_FLOW_CONTROL_RTS_ENABLED) : 0) |
((options.c_iflag & IXOFF) ? com_fazecast_jSerialComm_SerialPort_FLOW_CONTROL_XONXOFF_IN_ENABLED : 0) |
((options.c_iflag & IXON) ? com_fazecast_jSerialComm_SerialPort_FLOW_CONTROL_XONXOFF_OUT_ENABLED : 0);
(*env)->SetIntField(env, obj, flowControlField, flowControl);
(*env)->SetBooleanField(env, obj, isDtrEnabledField, (options.c_cflag & CRTSCTS) > 0);
(*env)->SetBooleanField(env, obj, isRtsEnabledField, (options.c_cflag & CRTSCTS) > 0);
}
// Configure the serial port read and write timeouts
int flags = 0;
port->eventsMask = eventsToMonitor;
if ((eventsToMonitor & com_fazecast_jSerialComm_SerialPort_LISTENING_EVENT_DATA_RECEIVED) > 0)
{
// Force specific read timeouts if we are monitoring data received
options.c_cc[VMIN] = 0;
options.c_cc[VTIME] = 10;
}
else if (((timeoutMode & com_fazecast_jSerialComm_SerialPort_TIMEOUT_READ_SEMI_BLOCKING) > 0) && (readTimeout > 0)) // Read Semi-blocking with timeout
{
options.c_cc[VMIN] = 0;
options.c_cc[VTIME] = readTimeout / 100;
}
else if ((timeoutMode & com_fazecast_jSerialComm_SerialPort_TIMEOUT_READ_SEMI_BLOCKING) > 0) // Read Semi-blocking without timeout
{
options.c_cc[VMIN] = 1;
options.c_cc[VTIME] = 0;
}
else if (((timeoutMode & com_fazecast_jSerialComm_SerialPort_TIMEOUT_READ_BLOCKING) > 0) && (readTimeout > 0)) // Read Blocking with timeout
{
options.c_cc[VMIN] = 0;
options.c_cc[VTIME] = readTimeout / 100;
}
else if ((timeoutMode & com_fazecast_jSerialComm_SerialPort_TIMEOUT_READ_BLOCKING) > 0) // Read Blocking without timeout
{
options.c_cc[VMIN] = 1;
options.c_cc[VTIME] = 0;
}
else if ((timeoutMode & com_fazecast_jSerialComm_SerialPort_TIMEOUT_SCANNER) > 0) // Scanner Mode
{
options.c_cc[VMIN] = 1;
options.c_cc[VTIME] = 1;
}
else // Non-blocking
{
flags = O_NONBLOCK;
options.c_cc[VMIN] = 0;
options.c_cc[VTIME] = 0;
}
// Apply changes
if (fcntl(port->handle, F_SETFL, flags))
{
port->errorLineNumber = lastErrorLineNumber = __LINE__ - 2;
port->errorNumber = lastErrorNumber = errno;
return JNI_FALSE;
}
baud_rate baudRateCode = getBaudRateCode(baudRate);
if (baudRateCode)
{
cfsetispeed(&options, baudRateCode);
cfsetospeed(&options, baudRateCode);
}
if (tcsetattr(port->handle, TCSANOW, &options))
{
port->errorLineNumber = lastErrorLineNumber = __LINE__ - 2;
port->errorNumber = lastErrorNumber = errno;
if (!disableConfig)
return JNI_FALSE;
}
if (!baudRateCode && setCustomBaudRate(port->handle, baudRate))
{
port->errorLineNumber = lastErrorLineNumber = __LINE__ - 2;
port->errorNumber = lastErrorNumber = errno;
return disableConfig ? JNI_TRUE : JNI_FALSE;
}
return JNI_TRUE;
}