JNIEXPORT jboolean JNICALL Java_com_fazecast_jSerialComm_SerialPort_configPort()

in src/main/c/Windows/SerialPort_Windows.c [938:1119]


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;
	DWORD baudRate = (DWORD)(*env)->GetIntField(env, obj, baudRateField);
	if (checkJniError(env, __LINE__ - 1)) return JNI_FALSE;
	BYTE byteSize = (BYTE)(*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 flowControl = (*env)->GetIntField(env, obj, flowControlField);
	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 writeTimeout = (*env)->GetIntField(env, obj, writeTimeoutField);
	if (checkJniError(env, __LINE__ - 1)) return JNI_FALSE;
	int eventsToMonitor = (*env)->GetIntField(env, obj, eventFlagsField);
	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;
	DWORD sendDeviceQueueSize = (DWORD)(*env)->GetIntField(env, obj, sendDeviceQueueSizeField);
	if (checkJniError(env, __LINE__ - 1)) return JNI_FALSE;
	DWORD receiveDeviceQueueSize = (DWORD)(*env)->GetIntField(env, obj, receiveDeviceQueueSizeField);
	if (checkJniError(env, __LINE__ - 1)) return JNI_FALSE;
	BYTE rs485ModeEnabled = (BYTE)(*env)->GetBooleanField(env, obj, rs485ModeField);
	if (checkJniError(env, __LINE__ - 1)) return JNI_FALSE;
	BYTE isDtrEnabled = (*env)->GetBooleanField(env, obj, isDtrEnabledField);
	if (checkJniError(env, __LINE__ - 1)) return JNI_FALSE;
	BYTE isRtsEnabled = (*env)->GetBooleanField(env, obj, isRtsEnabledField);
	if (checkJniError(env, __LINE__ - 1)) return JNI_FALSE;
	BYTE stopBits = (stopBitsInt == com_fazecast_jSerialComm_SerialPort_ONE_STOP_BIT) ? ONESTOPBIT : ((stopBitsInt == com_fazecast_jSerialComm_SerialPort_ONE_POINT_FIVE_STOP_BITS) ? ONE5STOPBITS : TWOSTOPBITS);
	BYTE parity = (parityInt == com_fazecast_jSerialComm_SerialPort_NO_PARITY) ? NOPARITY : ((parityInt == com_fazecast_jSerialComm_SerialPort_ODD_PARITY) ? ODDPARITY : ((parityInt == com_fazecast_jSerialComm_SerialPort_EVEN_PARITY) ? EVENPARITY : ((parityInt == com_fazecast_jSerialComm_SerialPort_MARK_PARITY) ? MARKPARITY : SPACEPARITY)));
	BOOL isParity = (parityInt == com_fazecast_jSerialComm_SerialPort_NO_PARITY) ? FALSE : TRUE;
	BOOL CTSEnabled = (((flowControl & com_fazecast_jSerialComm_SerialPort_FLOW_CONTROL_CTS_ENABLED) > 0) ||
			((flowControl & com_fazecast_jSerialComm_SerialPort_FLOW_CONTROL_RTS_ENABLED) > 0));
	BOOL DSREnabled = (((flowControl & com_fazecast_jSerialComm_SerialPort_FLOW_CONTROL_DSR_ENABLED) > 0) ||
			((flowControl & com_fazecast_jSerialComm_SerialPort_FLOW_CONTROL_DTR_ENABLED) > 0));
	BYTE DTRValue = ((flowControl & com_fazecast_jSerialComm_SerialPort_FLOW_CONTROL_DTR_ENABLED) > 0) ? DTR_CONTROL_HANDSHAKE : (isDtrEnabled ? DTR_CONTROL_ENABLE : DTR_CONTROL_DISABLE);
	BYTE RTSValue = (rs485ModeEnabled ? RTS_CONTROL_TOGGLE :
			(((flowControl & com_fazecast_jSerialComm_SerialPort_FLOW_CONTROL_RTS_ENABLED) > 0) ? RTS_CONTROL_HANDSHAKE : (isRtsEnabled ? RTS_CONTROL_ENABLE : RTS_CONTROL_DISABLE)));
	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);
	SetupComm(port->handle, receiveDeviceQueueSize, sendDeviceQueueSize);
	if (!GetCommState(port->handle, &dcbSerialParams))
	{
		port->errorLineNumber = lastErrorLineNumber = __LINE__ - 2;
		port->errorNumber = lastErrorNumber = GetLastError();
		return JNI_FALSE;
	}

	// Configure port parameters if not explicitly disabled
	if (!disableConfig)
	{
		// 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;
		}
	}
	else
	{
		// Update the Java-side port configuration values
		(*env)->SetIntField(env, obj, baudRateField, (int)dcbSerialParams.BaudRate);
		(*env)->SetIntField(env, obj, dataBitsField, (int)dcbSerialParams.ByteSize);
		(*env)->SetIntField(env, obj, stopBitsField, (dcbSerialParams.StopBits == ONESTOPBIT) ? com_fazecast_jSerialComm_SerialPort_ONE_STOP_BIT : ((dcbSerialParams.StopBits == ONE5STOPBITS) ? com_fazecast_jSerialComm_SerialPort_ONE_POINT_FIVE_STOP_BITS : com_fazecast_jSerialComm_SerialPort_TWO_STOP_BITS));
		if (dcbSerialParams.fParity)
			(*env)->SetIntField(env, obj, parityField, (dcbSerialParams.Parity == NOPARITY) ? com_fazecast_jSerialComm_SerialPort_NO_PARITY : ((dcbSerialParams.Parity == ODDPARITY) ? com_fazecast_jSerialComm_SerialPort_ODD_PARITY : ((dcbSerialParams.Parity == EVENPARITY) ? com_fazecast_jSerialComm_SerialPort_EVEN_PARITY : ((dcbSerialParams.Parity == MARKPARITY) ? com_fazecast_jSerialComm_SerialPort_MARK_PARITY : com_fazecast_jSerialComm_SerialPort_SPACE_PARITY))));
		else
			(*env)->SetIntField(env, obj, parityField, com_fazecast_jSerialComm_SerialPort_NO_PARITY);
		(*env)->SetByteField(env, obj, xonStartCharField, dcbSerialParams.XonChar);
		(*env)->SetByteField(env, obj, xoffStopCharField, dcbSerialParams.XoffChar);
		int flowControl = (dcbSerialParams.fInX ? com_fazecast_jSerialComm_SerialPort_FLOW_CONTROL_XONXOFF_IN_ENABLED : 0) | (dcbSerialParams.fOutX ? com_fazecast_jSerialComm_SerialPort_FLOW_CONTROL_XONXOFF_OUT_ENABLED : 0) |
				(dcbSerialParams.fOutxCtsFlow ? com_fazecast_jSerialComm_SerialPort_FLOW_CONTROL_CTS_ENABLED : 0) | (dcbSerialParams.fOutxDsrFlow ? com_fazecast_jSerialComm_SerialPort_FLOW_CONTROL_DSR_ENABLED : 0) |
				((dcbSerialParams.fDtrControl == DTR_CONTROL_HANDSHAKE) ? com_fazecast_jSerialComm_SerialPort_FLOW_CONTROL_DTR_ENABLED : 0) |
				((dcbSerialParams.fRtsControl == RTS_CONTROL_HANDSHAKE) ? com_fazecast_jSerialComm_SerialPort_FLOW_CONTROL_RTS_ENABLED : 0);
		(*env)->SetIntField(env, obj, flowControlField, flowControl);
		(*env)->SetBooleanField(env, obj, isDtrEnabledField, dcbSerialParams.fDtrControl == DTR_CONTROL_ENABLE);
		(*env)->SetBooleanField(env, obj, isRtsEnabledField, dcbSerialParams.fRtsControl == RTS_CONTROL_ENABLE);
		(*env)->SetBooleanField(env, obj, rs485ModeField, dcbSerialParams.fRtsControl == RTS_CONTROL_TOGGLE);
	}

	// Get event flags from the Java class
	int eventFlags = EV_ERR;
	if ((eventsToMonitor & com_fazecast_jSerialComm_SerialPort_LISTENING_EVENT_DATA_AVAILABLE) || (eventsToMonitor & com_fazecast_jSerialComm_SerialPort_LISTENING_EVENT_DATA_RECEIVED))
		eventFlags |= EV_RXCHAR;
	if (eventsToMonitor & com_fazecast_jSerialComm_SerialPort_LISTENING_EVENT_DATA_WRITTEN)
		eventFlags |= EV_TXEMPTY;
	if (eventsToMonitor & com_fazecast_jSerialComm_SerialPort_LISTENING_EVENT_BREAK_INTERRUPT)
		eventFlags |= EV_BREAK;
	if (eventsToMonitor & com_fazecast_jSerialComm_SerialPort_LISTENING_EVENT_CTS)
		eventFlags |= EV_CTS;
	if (eventsToMonitor & com_fazecast_jSerialComm_SerialPort_LISTENING_EVENT_DSR)
		eventFlags |= EV_DSR;
	if (eventsToMonitor & com_fazecast_jSerialComm_SerialPort_LISTENING_EVENT_RING_INDICATOR)
		eventFlags |= EV_RING;
	if (eventsToMonitor & com_fazecast_jSerialComm_SerialPort_LISTENING_EVENT_CARRIER_DETECT)
		eventFlags |= EV_RLSD;

	// Set updated port timeouts
	COMMTIMEOUTS timeouts;
	memset(&timeouts, 0, sizeof(COMMTIMEOUTS));
	timeouts.WriteTotalTimeoutMultiplier = 0;
	timeouts.WriteTotalTimeoutConstant = (timeoutMode & com_fazecast_jSerialComm_SerialPort_TIMEOUT_WRITE_BLOCKING) ? writeTimeout : 0;
	if (eventsToMonitor & com_fazecast_jSerialComm_SerialPort_LISTENING_EVENT_DATA_RECEIVED)
	{
		// Force specific read timeouts if we are monitoring data received
		timeouts.ReadIntervalTimeout = MAXDWORD;
		timeouts.ReadTotalTimeoutMultiplier = MAXDWORD;
		timeouts.ReadTotalTimeoutConstant = 1000;
	}
	else if (timeoutMode & com_fazecast_jSerialComm_SerialPort_TIMEOUT_SCANNER)
	{
		timeouts.ReadIntervalTimeout = MAXDWORD;
		timeouts.ReadTotalTimeoutMultiplier = MAXDWORD;
		timeouts.ReadTotalTimeoutConstant = 0x0FFFFFFF;
	}
	else if (timeoutMode & com_fazecast_jSerialComm_SerialPort_TIMEOUT_READ_SEMI_BLOCKING)
	{
		timeouts.ReadIntervalTimeout = MAXDWORD;
		timeouts.ReadTotalTimeoutMultiplier = MAXDWORD;
		timeouts.ReadTotalTimeoutConstant = readTimeout ? readTimeout : 0x0FFFFFFF;
	}
	else if (timeoutMode & com_fazecast_jSerialComm_SerialPort_TIMEOUT_READ_BLOCKING)
	{
		timeouts.ReadIntervalTimeout = 0;
		timeouts.ReadTotalTimeoutMultiplier = 0;
		timeouts.ReadTotalTimeoutConstant = readTimeout;
	}
	else		// Non-blocking
	{
		timeouts.ReadIntervalTimeout = MAXDWORD;
		timeouts.ReadTotalTimeoutMultiplier = 0;
		timeouts.ReadTotalTimeoutConstant = 0;
	}

	// Apply changes
	if (!SetCommTimeouts(port->handle, &timeouts) || !SetCommMask(port->handle, eventFlags))
	{
		port->errorLineNumber = lastErrorLineNumber = __LINE__ - 2;
		port->errorNumber = lastErrorNumber = GetLastError();
		return JNI_FALSE;
	}
	return JNI_TRUE;
}