/*-------------------------------------------------------------------------
|
|
| rxtx is a native interface to serial ports in java.
|
|
| Copyright 2002-2004 Michal Hobot MichalHobot@netscape.net
|
|
| Copyright 1997-2004 by Trent Jarvi taj@parcelfarce.linux.theplanet.co.uk
|
|
|
|
|
| This library is free software; you can redistribute it and/or
|
|
| modify it under the terms of the GNU Library General Public
|
|
| License as published by the Free Software Foundation; either
|
|
| version 2 of the License, or (at your option) any later version.
|
|
|
|
|
| This library is distributed in the hope that it will be useful,
|
|
| but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
| Library General Public License for more details.
|
|
|
|
|
| You should have received a copy of the GNU Library General Public
|
|
| License along with this library; if not, write to the Free
|
|
| Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
--------------------------------------------------------------------------*/
|
|
#include "StdAfx.h"
|
|
#include "rxtxHelpers.h"
|
|
|
|
/*
|
|
Initialize
|
|
|
|
accept: none
|
|
perform: Initialize the native library
|
|
return: none
|
|
exceptions: none
|
|
comments:
|
|
* Class: gnu_io_RXTXPort
|
|
* Method: Initialize
|
|
* Signature: ()V
|
|
*/
|
|
JNIEXPORT void JNICALL Java_gnu_io_RXTXPort_Initialize(JNIEnv *env, jclass cls)
|
|
{
|
|
}
|
|
|
|
/*
|
|
open
|
|
|
|
accept: The device to open. ie "COM1:"
|
|
perform: open the device
|
|
return: handle
|
|
exceptions: IOExcepiton
|
|
comments: Very often people complain about not being able to get past
|
|
this function and it turns out to be permissions on the
|
|
device file or bios has the device disabled.
|
|
* Class: gnu_io_RXTXPort
|
|
* Method: open
|
|
* Signature: (Ljava/lang/String{ })I
|
|
*/
|
|
JNIEXPORT jint JNICALL Java_gnu_io_RXTXPort_open(JNIEnv *env, jobject jobj, jstring name)
|
|
{
|
|
DCB PortDCB;
|
|
COMMTIMEOUTS CommTimeouts;
|
|
LPCWSTR lpMsgBuf;
|
|
EventInfoStruct *EventInfo;
|
|
DWORD dwErr;
|
|
|
|
LPCWSTR wszName = env->GetStringChars(name, NULL);
|
|
HANDLE hPort = CreateFileW(wszName, // Pointer to the name of the port
|
|
GENERIC_READ | GENERIC_WRITE,// Access (read-write) mode
|
|
0, // Share mode
|
|
NULL, // Pointer to the security attribute
|
|
OPEN_EXISTING,// How to open the serial port
|
|
0, // Port attributes
|
|
NULL); // Handle to port with attribute to copy
|
|
// If it fails to open the port, return FALSE.
|
|
if ( hPort == INVALID_HANDLE_VALUE )
|
|
{ // Could not open the port.
|
|
CreateErrorMsg(GetLastError(), lpMsgBuf);
|
|
throw_java_exceptionW(env, PORT_IN_USE_EXCEPTION, L"open - CreateFile", lpMsgBuf );
|
|
// Free the buffers.
|
|
ReleaseErrorMsg(lpMsgBuf);
|
|
env->ReleaseStringChars(name, wszName);
|
|
return (jint)INVALID_HANDLE_VALUE;
|
|
}
|
|
|
|
|
|
PortDCB.DCBlength = sizeof (DCB);
|
|
|
|
// Get the default port setting information.
|
|
GetCommState(hPort, &PortDCB);
|
|
|
|
// Change the DCB structure settings.
|
|
PortDCB.fBinary = TRUE; // Binary mode; no EOF check
|
|
PortDCB.fParity = TRUE; // Enable parity checking
|
|
PortDCB.fOutxDsrFlow = FALSE; // No DSR output flow control
|
|
PortDCB.fDtrControl = DTR_CONTROL_HANDSHAKE;// DTR flow control type
|
|
PortDCB.fDsrSensitivity = FALSE; // DSR sensitivity
|
|
PortDCB.fTXContinueOnXoff = TRUE; // XOFF continues Tx
|
|
PortDCB.fErrorChar = FALSE; // Disable error replacement
|
|
PortDCB.fNull = FALSE; // Disable null stripping
|
|
PortDCB.fRtsControl = RTS_CONTROL_ENABLE;// RTS flow control
|
|
PortDCB.fAbortOnError = FALSE; // Do not abort reads/writes on error
|
|
|
|
// Configure the port according to the specifications of the DCB structure.
|
|
if (!SetCommState(hPort, &PortDCB))
|
|
{ // Could not set comm port state
|
|
CreateErrorMsg(GetLastError(), lpMsgBuf);
|
|
throw_java_exceptionW(env, PORT_IN_USE_EXCEPTION, L"open - SetCommState", lpMsgBuf);
|
|
// Free the buffers.
|
|
ReleaseErrorMsg(lpMsgBuf);
|
|
env->ReleaseStringChars(name, wszName);
|
|
return (jint)INVALID_HANDLE_VALUE;
|
|
}
|
|
|
|
// Retrieve the time-out parameters for all read and write operations
|
|
// on the port.
|
|
GetCommTimeouts(hPort, &CommTimeouts);
|
|
|
|
// Change the COMMTIMEOUTS structure settings.
|
|
CommTimeouts.ReadIntervalTimeout = 0;
|
|
CommTimeouts.ReadTotalTimeoutMultiplier = 0;
|
|
CommTimeouts.ReadTotalTimeoutConstant = MAXDWORD;
|
|
CommTimeouts.WriteTotalTimeoutMultiplier = 10;
|
|
CommTimeouts.WriteTotalTimeoutConstant = 1000;
|
|
|
|
// Set the time-out parameters for all read and write operations
|
|
// on the port.
|
|
if (!SetCommTimeouts(hPort, &CommTimeouts))
|
|
{ // Unable to set the time-out parameters
|
|
CreateErrorMsg(GetLastError(), lpMsgBuf);
|
|
throw_java_exceptionW(env, PORT_IN_USE_EXCEPTION, L"open - SetCommTimeouts", lpMsgBuf);
|
|
// Free the buffers.
|
|
ReleaseErrorMsg(lpMsgBuf);
|
|
env->ReleaseStringChars(name, wszName);
|
|
return (jint)INVALID_HANDLE_VALUE;
|
|
}
|
|
|
|
// SETRTS: Sends the RTS (request-to-send) signal.
|
|
EscapeCommFunction(hPort, SETRTS);
|
|
|
|
|
|
if(dwErr = InitialiseEventInfoStruct(hPort, &EventInfo))
|
|
{ // Unable to set up EventInfo structure for event processing
|
|
CreateErrorMsg(dwErr, lpMsgBuf);
|
|
throw_java_exceptionW(env, IO_EXCEPTION, L"open - InitialiseEventInfoStruct", lpMsgBuf);
|
|
// Free the buffers.
|
|
ReleaseErrorMsg(lpMsgBuf);
|
|
env->ReleaseStringChars(name, wszName);
|
|
return (jint)INVALID_HANDLE_VALUE;
|
|
}
|
|
|
|
jclass cls = env->GetObjectClass(jobj);
|
|
jfieldID jfEis = env->GetFieldID(cls, "eis", "I");
|
|
if( !jfEis ) {
|
|
IF_DEBUG
|
|
(
|
|
env->ExceptionDescribe();
|
|
)
|
|
env->ExceptionClear();
|
|
// Free the buffers.
|
|
env->ReleaseStringChars(name, wszName);
|
|
return (jint)INVALID_HANDLE_VALUE;
|
|
}
|
|
env->SetIntField(jobj, jfEis, (jint)EventInfo);
|
|
|
|
env->ReleaseStringChars(name, wszName);
|
|
// Returning HANDLE (which is a pointer) as file descriptor... Anyway, 32 bits are 32 bits
|
|
return (jint)hPort;
|
|
}
|
|
|
|
|
|
/*
|
|
nativeSetSerialPortParams
|
|
|
|
accept: speed, data bits, stop bits, parity
|
|
perform: set the serial port parameters
|
|
return: void
|
|
exceptions: UnsupportedCommOperationException
|
|
* Class: gnu_io_RXTXPort
|
|
* Method: nativeSetSerialPortParams
|
|
* Signature: (IIII)V
|
|
*/
|
|
JNIEXPORT void JNICALL Java_gnu_io_RXTXPort_nativeSetSerialPortParams(JNIEnv *env, jobject jobj, jint speed, jint dataBits, jint stopBits, jint parity)
|
|
{
|
|
DCB PortDCB;
|
|
LPCWSTR lpMsgBuf;
|
|
|
|
HANDLE hPort = get_fd(env, jobj);
|
|
PortDCB.DCBlength = sizeof(DCB);
|
|
|
|
IF_DEBUG
|
|
(
|
|
printj(env, L"--- RXTXPort.nativeSetSerialPortParams(%ld, %ld, %ld, %ld) called\n", speed, dataBits, stopBits, parity);
|
|
)
|
|
|
|
// Get the default port setting information.
|
|
if(!GetCommState(hPort, &PortDCB))
|
|
{ //Unable to get configuration of the serial port
|
|
CreateErrorMsg(GetLastError(), lpMsgBuf);
|
|
throw_java_exceptionW(env, UNSUPPORTED_COMM_OPERATION, L"nativeSetSerialPortParams - GetCommState", lpMsgBuf);
|
|
// Free the buffers.
|
|
ReleaseErrorMsg(lpMsgBuf);
|
|
return;
|
|
}
|
|
|
|
// Change the DCB structure settings.
|
|
PortDCB.BaudRate = speed; // Current baud
|
|
PortDCB.ByteSize = (BYTE)dataBits; // Number of bits/byte, 4-8
|
|
PortDCB.Parity = (BYTE)parity; // 0-4=no,odd,even,mark,space
|
|
switch(stopBits)
|
|
{
|
|
case gnu_io_RXTXPort_STOPBITS_1:
|
|
PortDCB.StopBits = ONESTOPBIT;
|
|
break;
|
|
|
|
case gnu_io_RXTXPort_STOPBITS_2:
|
|
PortDCB.StopBits = TWOSTOPBITS;
|
|
break;
|
|
|
|
case gnu_io_RXTXPort_STOPBITS_1_5:
|
|
PortDCB.StopBits = ONE5STOPBITS;
|
|
break;
|
|
|
|
default:
|
|
throw_java_exceptionW(env, UNSUPPORTED_COMM_OPERATION, L"nativeSetSerialPortParams", L"Incorrect stopBits");
|
|
|
|
}
|
|
|
|
// Configure the port according to the specifications of the DCB structure.
|
|
if (!SetCommState (hPort, &PortDCB))
|
|
{ //Unable to configure the serial port
|
|
CreateErrorMsg(GetLastError(), lpMsgBuf);
|
|
throw_java_exceptionW(env, UNSUPPORTED_COMM_OPERATION, L"nativeSetSerialPortParams - SetCommState", lpMsgBuf);
|
|
// Free the buffers.
|
|
ReleaseErrorMsg(lpMsgBuf);
|
|
return;
|
|
}
|
|
|
|
}
|
|
|
|
/*
|
|
setflowcontrol
|
|
|
|
accept: flowmode
|
|
FLOWCONTROL_NONE none
|
|
FLOWCONTROL_RTSCTS_IN hardware flow control
|
|
FLOWCONTROL_RTSCTS_OUT ""
|
|
FLOWCONTROL_XONXOFF_IN input software flow control
|
|
FLOWCONTROL_XONXOFF_OUT output software flow control
|
|
perform: set flow control to flowmode
|
|
return: none
|
|
exceptions: UnsupportedCommOperationException
|
|
comments: there is no differentiation between input and output hardware
|
|
flow control
|
|
* Class: gnu_io_RXTXPort
|
|
* Method: setflowcontrol
|
|
* Signature: (I)V
|
|
*/
|
|
JNIEXPORT void JNICALL Java_gnu_io_RXTXPort_setflowcontrol(JNIEnv *env, jobject jobj, jint flowcontrol)
|
|
{
|
|
DCB PortDCB;
|
|
LPCWSTR lpMsgBuf;
|
|
|
|
IF_DEBUG
|
|
(
|
|
printj(env, L"--- RXTXPort.setflowcontrol(%ld) called\n", flowcontrol);
|
|
)
|
|
|
|
HANDLE hPort = get_fd(env, jobj);
|
|
|
|
PortDCB.DCBlength = sizeof(DCB);
|
|
if(!GetCommState (hPort, &PortDCB))
|
|
{ //Unable to get configuration of the serial port
|
|
CreateErrorMsg(GetLastError(), lpMsgBuf);
|
|
throw_java_exceptionW(env, UNSUPPORTED_COMM_OPERATION, L"setflowcontrol - GetCommState", lpMsgBuf);
|
|
// Free the buffers.
|
|
ReleaseErrorMsg(lpMsgBuf);
|
|
return;
|
|
}
|
|
|
|
if(flowcontrol & (gnu_io_RXTXPort_FLOWCONTROL_RTSCTS_IN | gnu_io_RXTXPort_FLOWCONTROL_RTSCTS_OUT))
|
|
PortDCB.fRtsControl = RTS_CONTROL_HANDSHAKE;
|
|
else
|
|
PortDCB.fRtsControl = RTS_CONTROL_ENABLE;
|
|
|
|
if(flowcontrol & gnu_io_RXTXPort_FLOWCONTROL_RTSCTS_OUT)
|
|
PortDCB.fOutxCtsFlow = TRUE;
|
|
else
|
|
PortDCB.fOutxCtsFlow = FALSE;
|
|
|
|
if(flowcontrol & gnu_io_RXTXPort_FLOWCONTROL_XONXOFF_IN)
|
|
PortDCB.fInX = TRUE;
|
|
else
|
|
PortDCB.fInX = FALSE;
|
|
|
|
if(flowcontrol & gnu_io_RXTXPort_FLOWCONTROL_XONXOFF_OUT)
|
|
PortDCB.fOutX = TRUE;
|
|
else
|
|
PortDCB.fOutX = FALSE;
|
|
|
|
// Configure the port according to the specifications of the DCB structure.
|
|
if (!SetCommState (hPort, &PortDCB))
|
|
{ // Could not set params
|
|
CreateErrorMsg(GetLastError(), lpMsgBuf);
|
|
throw_java_exceptionW(env, UNSUPPORTED_COMM_OPERATION, L"setflowcontrol - SetCommState", lpMsgBuf);
|
|
// Free the buffers.
|
|
ReleaseErrorMsg(lpMsgBuf);
|
|
return;
|
|
}
|
|
}
|
|
|
|
/*
|
|
NativegetReceiveTimeout
|
|
|
|
accept: none
|
|
perform: get termios.c_cc[VTIME]
|
|
return: VTIME
|
|
comments: see NativeEnableReceiveTimeoutThreshold
|
|
* Class: gnu_io_RXTXPort
|
|
* Method: NativegetReceiveTimeout
|
|
* Signature: ()I
|
|
*/
|
|
JNIEXPORT jint JNICALL Java_gnu_io_RXTXPort_NativegetReceiveTimeout(JNIEnv *env, jobject jobj)
|
|
{
|
|
COMMTIMEOUTS CommTimeouts;
|
|
LPCWSTR lpMsgBuf;
|
|
HANDLE hPort = get_fd(env, jobj);
|
|
|
|
IF_DEBUG
|
|
(
|
|
printj(env, L"--- RXTXPort.NativegetReceiveTimeout() called\n");
|
|
)
|
|
|
|
// Retrieve the time-out parameters for all read and write operations on the port.
|
|
if (!GetCommTimeouts(hPort, &CommTimeouts))
|
|
{ // Unable to get the time-out parameters
|
|
CreateErrorMsg(GetLastError(), lpMsgBuf);
|
|
throw_java_exceptionW(env, IO_EXCEPTION, L"NativegetReceiveTimeout - GetCommTimeouts", lpMsgBuf);
|
|
// Free the buffers.
|
|
ReleaseErrorMsg(lpMsgBuf);
|
|
return -1;
|
|
}
|
|
|
|
// As far as I know c_cc is byte table
|
|
return CommTimeouts.ReadIntervalTimeout/100 <= 255 ? CommTimeouts.ReadIntervalTimeout / 100 : 255;
|
|
}
|
|
|
|
/*
|
|
NativeisReceiveTimeoutEnabled
|
|
|
|
accept: none
|
|
perform: determine if VTIME is none 0
|
|
return: JNI_TRUE if VTIME > 0 else JNI_FALSE
|
|
comments: see NativeEnableReceiveTimeoutThreshold
|
|
* Class: gnu_io_RXTXPort
|
|
* Method: NativeisReceiveTimeoutEnabled
|
|
* Signature: ()Z
|
|
*/
|
|
JNIEXPORT jboolean JNICALL Java_gnu_io_RXTXPort_NativeisReceiveTimeoutEnabled(JNIEnv *env, jobject jobj)
|
|
{
|
|
COMMTIMEOUTS CommTimeouts;
|
|
LPCWSTR lpMsgBuf;
|
|
HANDLE hPort = get_fd(env, jobj);
|
|
|
|
IF_DEBUG
|
|
(
|
|
printj(env, L"--- RXTXPort.NativeisReceiveTimeoutEnabled() called\n");
|
|
)
|
|
|
|
// Retrieve the time-out parameters for all read and write operations
|
|
// on the port.
|
|
if (!GetCommTimeouts(hPort, &CommTimeouts))
|
|
{ // Unable to get the time-out parameters
|
|
CreateErrorMsg(GetLastError(), lpMsgBuf);
|
|
throw_java_exceptionW(env, IO_EXCEPTION, L"NativeisReceiveTimeoutEnabled - GetCommTimeouts", lpMsgBuf);
|
|
// Free the buffers.
|
|
ReleaseErrorMsg(lpMsgBuf);
|
|
return -1;
|
|
}
|
|
|
|
return CommTimeouts.ReadIntervalTimeout || CommTimeouts.ReadTotalTimeoutConstant || CommTimeouts.ReadTotalTimeoutMultiplier ? JNI_TRUE : JNI_FALSE;
|
|
}
|
|
|
|
/*
|
|
NativeEnableReceiveTimeoutThreshold
|
|
accept: int threshold, int vtime,int buffer
|
|
perform: Set c_cc->VMIN to threshold and c_cc=>VTIME to vtime
|
|
return: void
|
|
exceptions: IOException
|
|
comments: This is actually all handled in read with select in
|
|
canonical input mode.
|
|
* Class: gnu_io_RXTXPort
|
|
* Method: NativeEnableReceiveTimeoutThreshold
|
|
* Signature: (III)V
|
|
*/
|
|
JNIEXPORT void JNICALL Java_gnu_io_RXTXPort_NativeEnableReceiveTimeoutThreshold(JNIEnv *env, jobject jobj, jint time, jint threshold, jint InputBuffer)
|
|
{
|
|
COMMTIMEOUTS CommTimeouts;
|
|
LPCWSTR lpMsgBuf;
|
|
HANDLE hPort = get_fd(env, jobj);
|
|
|
|
IF_DEBUG
|
|
(
|
|
printj(env, L"--- RXTXPort.NativeEnableReceiveTimeoutThreshold(%ld, %ld) called\n", time, threshold);
|
|
)
|
|
|
|
// Retrieve the time-out parameters for all read and write operations
|
|
// on the port.
|
|
if (!GetCommTimeouts(hPort, &CommTimeouts))
|
|
{ // Unable to get the time-out parameters
|
|
CreateErrorMsg(GetLastError(), lpMsgBuf);
|
|
throw_java_exceptionW(env, IO_EXCEPTION, L"NativeEnableReceiveTimeoutThreshold - GetCommTimeouts", lpMsgBuf);
|
|
// Free the buffers.
|
|
ReleaseErrorMsg(lpMsgBuf);
|
|
return;
|
|
}
|
|
|
|
/* ------ from javax.comm.CommPort javadoc -------------------------------------------------------------
|
|
| Threshold | Timeout |Read Buffer Size | Read Behaviour
|
|
|State |Value |State |Value| |
|
|
|disabled| - |disabled| - | n bytes | block until any data is available
|
|
|enabled |m bytes|disabled| - | n bytes | block until min(m,n) bytes are available
|
|
|disabled| - |enabled |x ms | n bytes | block for x ms or until any data is available
|
|
|enabled |m bytes|enabled |x ms | n bytes | block for x ms or until min(m,n) bytes are available
|
|
--------------------------------------------------------------------------------------------------------
|
|
|
|
Enabling the Timeout OR Threshold with a value a zero is a special case.
|
|
This causes the underlying driver to poll for incoming data instead being event driven.
|
|
Otherwise, the behaviour is identical to having both the Timeout and Threshold disabled.
|
|
*/
|
|
|
|
// Following is based on my understanding of timeout parameters meaning.
|
|
// Not completely precise (threshold?!)
|
|
|
|
if(time == 0)
|
|
{ // polling mode - return if no data
|
|
CommTimeouts.ReadIntervalTimeout = MAXDWORD;
|
|
CommTimeouts.ReadTotalTimeoutMultiplier = MAXDWORD;
|
|
CommTimeouts.ReadTotalTimeoutConstant = 1;
|
|
}
|
|
else if(time == -1)
|
|
{ // disable timeout
|
|
CommTimeouts.ReadIntervalTimeout = 0;
|
|
CommTimeouts.ReadTotalTimeoutMultiplier = 0;
|
|
CommTimeouts.ReadTotalTimeoutConstant = 0;
|
|
}
|
|
else
|
|
{ // set timeout
|
|
CommTimeouts.ReadIntervalTimeout = 0;
|
|
CommTimeouts.ReadTotalTimeoutMultiplier = 0;
|
|
CommTimeouts.ReadTotalTimeoutConstant = time;
|
|
}
|
|
|
|
// Set the time-out parameters for all read and write operations
|
|
// on the port.
|
|
if (!SetCommTimeouts (hPort, &CommTimeouts))
|
|
{ // Unable to set the time-out parameters
|
|
CreateErrorMsg(GetLastError(), lpMsgBuf);
|
|
throw_java_exceptionW(env, IO_EXCEPTION, L"NativeEnableReceiveTimeoutThreshold - SetCommTimeouts", lpMsgBuf);
|
|
// Free the buffers.
|
|
ReleaseErrorMsg(lpMsgBuf);
|
|
return;
|
|
}
|
|
}
|
|
|
|
/*
|
|
isDTR
|
|
|
|
accept: none
|
|
perform: check status of DTR
|
|
return: true if TIOCM_DTR is set
|
|
false if TIOCM_DTR is not set
|
|
exceptions: none
|
|
comments: DTR stands for Data Terminal Ready
|
|
* Class: gnu_io_RXTXPort
|
|
* Method: isDTR
|
|
* Signature: ()Z
|
|
*/
|
|
JNIEXPORT jboolean JNICALL Java_gnu_io_RXTXPort_isDTR(JNIEnv *env, jobject jobj)
|
|
{
|
|
DCB PortDCB;
|
|
HANDLE hPort = get_fd(env, jobj);
|
|
|
|
PortDCB.DCBlength = sizeof(DCB);
|
|
|
|
// Get the default port setting information.
|
|
if(!GetCommState(hPort, &PortDCB))
|
|
{
|
|
GetLastError();
|
|
return JNI_FALSE;
|
|
}
|
|
|
|
// This is not completely correct: I assume that nobody's playing with
|
|
// manually setting/resetting DTR. Instead, DTR is in handshake mode (ON unless
|
|
// port closed) or disable mode (OFF).
|
|
// So, don't use EscapeCommFunction(SETDTR/CLRDTR) in this library!
|
|
return PortDCB.fDtrControl != DTR_CONTROL_DISABLE ? JNI_TRUE : JNI_FALSE;
|
|
}
|
|
|
|
/*
|
|
setDTR
|
|
|
|
accept: new DTR state
|
|
perform: if state is true, TIOCM_DTR is set
|
|
if state is false, TIOCM_DTR is unset
|
|
return: none
|
|
exceptions: none
|
|
comments: DTR stands for Data Terminal Ready
|
|
* Class: gnu_io_RXTXPort
|
|
* Method: setDTR
|
|
* Signature: (Z)V
|
|
*/
|
|
JNIEXPORT void JNICALL Java_gnu_io_RXTXPort_setDTR(JNIEnv *env, jobject jobj, jboolean state)
|
|
{
|
|
DCB PortDCB;
|
|
|
|
HANDLE hPort = get_fd(env, jobj);
|
|
PortDCB.DCBlength = sizeof(DCB);
|
|
|
|
// Don't use EscapeCommFunction(SETDTR/CLRDTR) in this library!
|
|
|
|
// Get the default port setting information.
|
|
if(!GetCommState (hPort, &PortDCB))
|
|
{ //Unable to get configuration of the serial port
|
|
GetLastError();
|
|
return;
|
|
}
|
|
|
|
if(state == JNI_TRUE)
|
|
PortDCB.fDtrControl = DTR_CONTROL_HANDSHAKE;
|
|
else
|
|
PortDCB.fDtrControl = DTR_CONTROL_DISABLE;
|
|
|
|
|
|
// Configure the port according to the specifications of the DCB structure.
|
|
if (!SetCommState (hPort, &PortDCB))
|
|
{ //Unable to configure the serial port
|
|
GetLastError();
|
|
return;
|
|
}
|
|
}
|
|
|
|
/*
|
|
setRTS
|
|
|
|
accept: state flag to set/unset.
|
|
perform: depends on the state flag
|
|
if true TIOCM_RTS is set
|
|
if false TIOCM_RTS is unset
|
|
return: none
|
|
exceptions: none
|
|
comments: tcsetattr with c_cflag CRTS_IFLOW
|
|
* Class: gnu_io_RXTXPort
|
|
* Method: setRTS
|
|
* Signature: (Z)V
|
|
*/
|
|
JNIEXPORT void JNICALL Java_gnu_io_RXTXPort_setRTS(JNIEnv *env, jobject jobj, jboolean state)
|
|
{
|
|
HANDLE hPort = get_fd(env, jobj);
|
|
|
|
// EscapeCommFunction will fail if there's RTS/CTS flowcontrol. If it is incorrect,
|
|
// we could turn flowcontrol off when getting to this function
|
|
if(state == JNI_TRUE)
|
|
EscapeCommFunction(hPort, SETRTS);
|
|
else
|
|
EscapeCommFunction(hPort, CLRRTS);
|
|
}
|
|
|
|
/*
|
|
setDSR
|
|
|
|
accept: state flag to set/unset.
|
|
perform: depends on the state flag
|
|
if true TIOCM_DSR is set
|
|
if false TIOCM_DSR is unset
|
|
return: none
|
|
exceptions: none
|
|
comments: tcsetattr with c_cflag CRTS_IFLOW
|
|
* Class: gnu_io_RXTXPort
|
|
* Method: setDSR
|
|
* Signature: (Z)V
|
|
*/
|
|
JNIEXPORT void JNICALL Java_gnu_io_RXTXPort_setDSR(JNIEnv *env, jobject jobj, jboolean state)
|
|
{
|
|
DCB PortDCB;
|
|
|
|
HANDLE hPort = get_fd(env, jobj);
|
|
PortDCB.DCBlength = sizeof(DCB);
|
|
|
|
// Get the default port setting information.
|
|
if(!GetCommState (hPort, &PortDCB))
|
|
{ //Unable to get configuration of the serial port
|
|
GetLastError();
|
|
return;
|
|
}
|
|
|
|
// Change the DCB structure settings.
|
|
if(state != JNI_FALSE)
|
|
PortDCB.fOutxDsrFlow = TRUE;
|
|
else
|
|
PortDCB.fOutxDsrFlow = FALSE;
|
|
|
|
// Configure the port according to the specifications of the DCB
|
|
// structure.
|
|
if (!SetCommState (hPort, &PortDCB))
|
|
{ //Unable to configure the serial port
|
|
GetLastError();
|
|
return;
|
|
}
|
|
}
|
|
|
|
/*
|
|
isCTS
|
|
|
|
accept: none
|
|
perform: check status of CTS
|
|
return: true if TIOCM_CTS is set
|
|
false if TIOCM_CTS is not set
|
|
exceptions: none
|
|
comments: CTS stands for Clear To Send.
|
|
* Class: gnu_io_RXTXPort
|
|
* Method: isCTS
|
|
* Signature: ()Z
|
|
*/
|
|
JNIEXPORT jboolean JNICALL Java_gnu_io_RXTXPort_isCTS(JNIEnv *env, jobject jobj)
|
|
{
|
|
DWORD ModemStat;
|
|
HANDLE hPort = get_fd(env, jobj);
|
|
|
|
if(!GetCommModemStatus(hPort, &ModemStat))
|
|
return JNI_FALSE;
|
|
|
|
return ModemStat|MS_CTS_ON ? JNI_TRUE : JNI_FALSE;
|
|
}
|
|
|
|
/*
|
|
isDSR
|
|
|
|
accept: none
|
|
perform: check status of DSR
|
|
return: true if TIOCM_DSR is set
|
|
false if TIOCM_DSR is not set
|
|
exceptions: none
|
|
comments: DSR stands for Data Set Ready
|
|
* Class: gnu_io_RXTXPort
|
|
* Method: isDSR
|
|
* Signature: ()Z
|
|
*/
|
|
JNIEXPORT jboolean JNICALL Java_gnu_io_RXTXPort_isDSR(JNIEnv *env, jobject jobj)
|
|
{
|
|
DWORD ModemStat;
|
|
HANDLE hPort = get_fd(env, jobj);
|
|
|
|
if(!GetCommModemStatus(hPort, &ModemStat))
|
|
return JNI_FALSE;
|
|
|
|
return ModemStat|MS_DSR_ON ? JNI_TRUE : JNI_FALSE;
|
|
}
|
|
|
|
/*
|
|
isCD
|
|
|
|
accept: none
|
|
perform: check status of CD
|
|
return: true if TIOCM_CD is set
|
|
false if TIOCM_CD is not set
|
|
exceptions: none
|
|
comments: CD stands for Carrier Detect
|
|
The following comment has been made...
|
|
"well, it works, there might ofcourse be a bug, but making DCD
|
|
permanently on fixed it for me so I don't care"
|
|
* Class: gnu_io_RXTXPort
|
|
* Method: isCD
|
|
* Signature: ()Z
|
|
*/
|
|
JNIEXPORT jboolean JNICALL Java_gnu_io_RXTXPort_isCD(JNIEnv *env, jobject jobj)
|
|
{
|
|
DWORD ModemStat;
|
|
HANDLE hPort = get_fd(env, jobj);
|
|
|
|
if(!GetCommModemStatus(hPort, &ModemStat))
|
|
return JNI_FALSE;
|
|
|
|
return ModemStat|MS_RLSD_ON ? JNI_TRUE : JNI_FALSE;
|
|
}
|
|
|
|
/*
|
|
isRI
|
|
|
|
accept: none
|
|
perform: check status of RI
|
|
return: true if TIOCM_RI is set
|
|
false if TIOCM_RI is not set
|
|
exceptions: none
|
|
comments: RI stands for Ring Indicator
|
|
* Class: gnu_io_RXTXPort
|
|
* Method: isRI
|
|
* Signature: ()Z
|
|
*/
|
|
JNIEXPORT jboolean JNICALL Java_gnu_io_RXTXPort_isRI(JNIEnv *env, jobject jobj)
|
|
{
|
|
DWORD ModemStat;
|
|
HANDLE hPort = get_fd(env, jobj);
|
|
|
|
if(!GetCommModemStatus(hPort, &ModemStat))
|
|
return JNI_FALSE;
|
|
|
|
return ModemStat|MS_RING_ON ? JNI_TRUE : JNI_FALSE;
|
|
}
|
|
|
|
/*
|
|
isRTS
|
|
|
|
accept: none
|
|
perform: check status of RTS
|
|
return: true if TIOCM_RTS is set
|
|
false if TIOCM_RTS is not set
|
|
exceptions: none
|
|
comments: tcgetattr with c_cflag CRTS_IFLOW
|
|
* Class: gnu_io_RXTXPort
|
|
* Method: isRTS
|
|
* Signature: ()Z
|
|
*/
|
|
JNIEXPORT jboolean JNICALL Java_gnu_io_RXTXPort_isRTS(JNIEnv *env, jobject jobj)
|
|
{
|
|
DCB PortDCB;
|
|
HANDLE hPort = get_fd(env, jobj);
|
|
|
|
PortDCB.DCBlength = sizeof(DCB);
|
|
if(!GetCommState (hPort, &PortDCB))
|
|
{ //Unable to get configuration of the serial port
|
|
GetLastError();
|
|
return JNI_FALSE;
|
|
}
|
|
|
|
if(PortDCB.fRtsControl == RTS_CONTROL_DISABLE)
|
|
return JNI_FALSE;
|
|
|
|
if(PortDCB.fRtsControl == RTS_CONTROL_ENABLE)
|
|
return JNI_TRUE;
|
|
|
|
if(PortDCB.fRtsControl == RTS_CONTROL_HANDSHAKE)
|
|
{
|
|
//MessageBox(NULL, L"Undefined condition: isRTS() but control is RTS_CONTROL_HANDSHAKE\r\nReturning FALSE", L"Warning", MB_OK | MB_ICONWARNING | MB_SETFOREGROUND);
|
|
printj(env, L"Undefined condition: isRTS() but control is RTS_CONTROL_HANDSHAKE. Returning FALSE\n");
|
|
return JNI_FALSE;
|
|
}
|
|
|
|
return JNI_FALSE;
|
|
}
|
|
|
|
/*
|
|
sendBreak
|
|
|
|
accept: duration in milliseconds.
|
|
perform: send break for actual time. not less than 0.25 seconds.
|
|
exceptions: none
|
|
comments: not very precise
|
|
* Class: gnu_io_RXTXPort
|
|
* Method: sendBreak
|
|
* Signature: (I)V
|
|
*/
|
|
JNIEXPORT void JNICALL Java_gnu_io_RXTXPort_sendBreak(JNIEnv *env, jobject jobj, jint duration)
|
|
{
|
|
HANDLE hPort = get_fd(env, jobj);
|
|
|
|
SetCommBreak(hPort);
|
|
Sleep(duration);
|
|
ClearCommBreak(hPort);
|
|
}
|
|
|
|
/*
|
|
writeByte
|
|
|
|
accept: byte to write (passed as int)
|
|
perform: write a single byte to the port
|
|
return: none
|
|
exceptions: IOException
|
|
* Class: gnu_io_RXTXPort
|
|
* Method: writeByte
|
|
* Signature: (IZ)V
|
|
*/
|
|
JNIEXPORT void JNICALL Java_gnu_io_RXTXPort_writeByte(JNIEnv *env, jobject jobj, jint b, jboolean i)
|
|
{
|
|
DWORD dwNumBytesWritten;
|
|
LPCWSTR lpMsgBuf;
|
|
HANDLE hPort = get_fd(env, jobj);
|
|
BYTE bb = (BYTE)b;
|
|
|
|
do {
|
|
if (!WriteFile(hPort, // Port handle
|
|
&bb, // Pointer to the data to write
|
|
1, // Number of bytes to write
|
|
&dwNumBytesWritten, // Pointer to the number of bytes written
|
|
NULL)) // Must be NULL for Windows CE
|
|
{ // WriteFile failed. Report error.
|
|
CreateErrorMsg(GetLastError(), lpMsgBuf);
|
|
throw_java_exceptionW(env, IO_EXCEPTION, L"writeByte - WriteFile", lpMsgBuf );
|
|
// Free the buffers.
|
|
ReleaseErrorMsg(lpMsgBuf);
|
|
return;
|
|
}
|
|
} while(dwNumBytesWritten == 0);
|
|
}
|
|
|
|
/*
|
|
writeArray
|
|
|
|
accept: jbarray: bytes used for writing
|
|
off: offset in array to start writing
|
|
len: Number of bytes to write
|
|
perform: write length bytes of jbarray
|
|
return: none
|
|
exceptions: IOException
|
|
* Class: gnu_io_RXTXPort
|
|
* Method: writeArray
|
|
* Signature: ([BIIZ)V
|
|
*/
|
|
JNIEXPORT void JNICALL Java_gnu_io_RXTXPort_writeArray(JNIEnv *env, jobject jobj, jbyteArray b, jint off, jint len, jboolean i)
|
|
{
|
|
LPCWSTR lpMsgBuf;
|
|
DWORD dwNumBytesWritten;
|
|
jint total=0;
|
|
HANDLE hPort = get_fd(env, jobj);
|
|
|
|
jbyte *body = env->GetByteArrayElements(b, NULL);
|
|
|
|
do {
|
|
IF_DEBUG
|
|
(
|
|
printj(env, L"--- writeArray - %d bytes to write\n", len-total);
|
|
)
|
|
if (!WriteFile(hPort, // Port handle
|
|
body+total+off, // Pointer to the data to write
|
|
len-total, // Number of bytes to write
|
|
&dwNumBytesWritten, // Pointer to the number of bytes written
|
|
NULL)) // Must be NULL for Windows CE
|
|
{ // WriteFile failed. Report error.
|
|
CreateErrorMsg(GetLastError(), lpMsgBuf);
|
|
throw_java_exceptionW(env, IO_EXCEPTION, L"writeArray - WriteFile", lpMsgBuf );
|
|
// Free the buffers.
|
|
ReleaseErrorMsg(lpMsgBuf);
|
|
env->ReleaseByteArrayElements(b, body, JNI_ABORT);
|
|
return;
|
|
}
|
|
total += dwNumBytesWritten;
|
|
} while( total < len );
|
|
|
|
env->ReleaseByteArrayElements(b, body, JNI_ABORT);
|
|
}
|
|
|
|
/*
|
|
nativeDrain
|
|
|
|
accept: none
|
|
perform: wait until all data is transmitted
|
|
return: none
|
|
exceptions: IOException
|
|
comments: java.io.OutputStream.flush() is equivalent to tcdrain,
|
|
not tcflush, which throws away unsent bytes
|
|
|
|
count logic added to avoid infinite loops when EINTR is
|
|
true... Thread.yeild() was suggested.
|
|
* Class: gnu_io_RXTXPort
|
|
* Method: nativeDrain
|
|
* Signature: ()V
|
|
*/
|
|
JNIEXPORT jboolean JNICALL Java_gnu_io_RXTXPort_nativeDrain(JNIEnv *env, jobject jobj, jboolean i)
|
|
{
|
|
//COMSTAT Stat;
|
|
//DWORD dwErrors;
|
|
HANDLE hPort = get_fd(env, jobj);
|
|
|
|
IF_DEBUG
|
|
(
|
|
printj(env, L"--- RXTXPort.nativeDrain() called\n");
|
|
)
|
|
/*
|
|
if(!FlushFileBuffers(hPort))
|
|
{
|
|
IF_DEBUG
|
|
(
|
|
printj(env, L"!!! FlushFileBuffers() error %ld\n", GetLastError());
|
|
)
|
|
return JNI_FALSE;
|
|
}
|
|
*/
|
|
// Alternative implementation:
|
|
/*
|
|
do
|
|
{
|
|
if(!ClearCommError(hPort, &dwErrors, &Stat))
|
|
{
|
|
GetLastError();
|
|
return;
|
|
}
|
|
Sleep(10);
|
|
} while(Stat.cbOutQue > 0);*/
|
|
|
|
return JNI_FALSE;
|
|
}
|
|
|
|
/*
|
|
nativeavailable
|
|
|
|
accept: none
|
|
perform: find out the number of bytes available for reading
|
|
return: available bytes
|
|
-1 on error
|
|
exceptions: none /// should be IOException
|
|
* Class: gnu_io_RXTXPort
|
|
* Method: nativeavailable
|
|
* Signature: ()I
|
|
*/
|
|
JNIEXPORT jint JNICALL Java_gnu_io_RXTXPort_nativeavailable(JNIEnv *env, jobject jobj)
|
|
{
|
|
DWORD dwErrors;
|
|
COMSTAT Stat;
|
|
LPCWSTR lpMsgBuf;
|
|
HANDLE hPort = get_fd(env, jobj);
|
|
|
|
IF_DEBUG
|
|
(
|
|
printj(env, L"--- RXTXPort.nativeavailable() called");
|
|
)
|
|
|
|
if(!ClearCommError(hPort, &dwErrors, &Stat))
|
|
{
|
|
CreateErrorMsg(GetLastError(), lpMsgBuf);
|
|
throw_java_exceptionW(env, IO_EXCEPTION, L"nativeavailable - ClearCommError", lpMsgBuf );
|
|
// Free the buffers.
|
|
ReleaseErrorMsg(lpMsgBuf);
|
|
return -1;
|
|
}
|
|
|
|
IF_DEBUG
|
|
(
|
|
printj(env, L" - returning %ld\n", Stat.cbInQue);
|
|
)
|
|
|
|
return Stat.cbInQue;
|
|
}
|
|
|
|
/*
|
|
readByte
|
|
|
|
accept: none
|
|
perform: Read a single byte from the port
|
|
return: The byte read
|
|
exceptions: IOException
|
|
* Class: gnu_io_RXTXPort
|
|
* Method: readByte
|
|
* Signature: ()I
|
|
*/
|
|
JNIEXPORT jint JNICALL Java_gnu_io_RXTXPort_readByte(JNIEnv *env, jobject jobj)
|
|
{
|
|
BYTE bb;
|
|
DWORD dwNumBytesRead;
|
|
LPCWSTR lpMsgBuf;
|
|
HANDLE hPort = get_fd(env, jobj);
|
|
|
|
if (!ReadFile(hPort, &bb, 1, &dwNumBytesRead, NULL))
|
|
{ // ReadFile failed. Report error.
|
|
CreateErrorMsg(GetLastError(), lpMsgBuf);
|
|
throw_java_exceptionW(env, IO_EXCEPTION, L"readByte - ReadFile", lpMsgBuf);
|
|
// Free the buffers.
|
|
ReleaseErrorMsg(lpMsgBuf);
|
|
return -1;
|
|
}
|
|
|
|
return dwNumBytesRead > 0 ? bb : -1;
|
|
}
|
|
|
|
/*
|
|
readArray
|
|
|
|
accept: offset (offset to start storing data in the jbarray) and
|
|
Length (bytes to read)
|
|
perform: read bytes from the port into a byte array
|
|
return: bytes read on success
|
|
0 on read timeout
|
|
exceptions: IOException
|
|
comments: throws ArrayIndexOutOfBoundsException if asked to
|
|
read more than SSIZE_MAX bytes
|
|
* Class: gnu_io_RXTXPort
|
|
* Method: readArray
|
|
* Signature: ([BII)I
|
|
*/
|
|
JNIEXPORT jint JNICALL Java_gnu_io_RXTXPort_readArray(JNIEnv *env, jobject jobj, jbyteArray b, jint off, jint len)
|
|
{
|
|
LPCWSTR lpMsgBuf;
|
|
DWORD dwNumBytesRead, dwTotalRead = 0;
|
|
jint threshold;
|
|
HANDLE hPort = get_fd(env, jobj);
|
|
|
|
if(len < 0)
|
|
{
|
|
throw_java_exceptionW(env, ARRAY_INDEX_OUT_OF_BOUNDS, L"readArray", L"Negative number of character to read");
|
|
return -1;
|
|
}
|
|
|
|
jbyte *body = env->GetByteArrayElements(b, NULL);
|
|
threshold = get_java_int_var(env, jobj, "threshold");
|
|
|
|
do
|
|
{
|
|
if (!ReadFile(hPort, (unsigned char *)(body+off), len, &dwNumBytesRead, NULL))
|
|
{ // ReadFile failed. Report error.
|
|
CreateErrorMsg(GetLastError(), lpMsgBuf);
|
|
throw_java_exceptionW(env, IO_EXCEPTION, L"readArray - WriteFile", lpMsgBuf );
|
|
// Free the buffers.
|
|
ReleaseErrorMsg(lpMsgBuf);
|
|
env->ReleaseByteArrayElements(b, body, JNI_ABORT);
|
|
return -1;
|
|
}
|
|
|
|
dwTotalRead += dwNumBytesRead;
|
|
} while(dwNumBytesRead > 0 && threshold != 0 && dwTotalRead <= (DWORD)len && dwTotalRead < (DWORD)threshold);
|
|
|
|
env->ReleaseByteArrayElements(b, body, 0);
|
|
return dwTotalRead;
|
|
}
|
|
|
|
/*
|
|
eventLoop
|
|
|
|
accept: none
|
|
perform: periodically check for SerialPortEvents
|
|
return: none
|
|
exceptions: none
|
|
comments: please keep this function clean.
|
|
* Class: gnu_io_RXTXPort
|
|
* Method: eventLoop
|
|
* Signature: ()V
|
|
*/
|
|
JNIEXPORT void JNICALL Java_gnu_io_RXTXPort_eventLoop(JNIEnv *env, jobject jobj)
|
|
{
|
|
jfieldID jfMonitorThreadCloseLock, jfMonitorThreadLock, jfMonThreadisInterrupted;
|
|
jmethodID jmSendEvent;
|
|
HANDLE hCommEventThread;
|
|
DWORD dwThreadID, dwWaitResult, dwEvent;
|
|
int RetVal;
|
|
HANDLE hPort = get_fd(env, jobj);
|
|
EventInfoStruct *EventInfo = get_eis(env, jobj);
|
|
|
|
IF_DEBUG
|
|
(
|
|
printj(env, L"--- RXTXPort.eventLoop() start\n");
|
|
)
|
|
|
|
jclass cls = env->GetObjectClass(jobj);
|
|
|
|
// Get pointers to some Java variables and methods:
|
|
if( !(jfMonitorThreadLock = env->GetFieldID(cls, "MonitorThreadLock", "Z")) ||
|
|
!(jfMonThreadisInterrupted = env->GetFieldID(cls, "monThreadisInterrupted", "Z")) ||
|
|
!(jfMonitorThreadCloseLock = env->GetFieldID(cls, "MonitorThreadCloseLock", "Z")) ||
|
|
!(jmSendEvent = env->GetMethodID(cls, "sendEvent", "(IZ)Z"))
|
|
)
|
|
{
|
|
IF_DEBUG
|
|
(
|
|
env->ExceptionDescribe();
|
|
)
|
|
env->ExceptionClear();
|
|
return;
|
|
}
|
|
|
|
hCommEventThread = CreateThread(NULL, 0, CommEventThread, (LPVOID)EventInfo, 0, &dwThreadID);
|
|
if(hCommEventThread == NULL)
|
|
{
|
|
LPCWSTR lpMsgBuf;
|
|
CreateErrorMsg(GetLastError(), lpMsgBuf);
|
|
printj(env, L"!!! eventLoop - CreateThread() error: %s\n", lpMsgBuf);
|
|
ReleaseErrorMsg(lpMsgBuf);
|
|
return;
|
|
}
|
|
|
|
CloseHandle(hCommEventThread);
|
|
|
|
do
|
|
{
|
|
if(env->GetBooleanField(jobj, jfMonThreadisInterrupted) == JNI_TRUE)
|
|
{
|
|
IF_DEBUG
|
|
(
|
|
printj(env, L"--- RXTXPort.eventLoop() interrupted - exiting\n");
|
|
)
|
|
|
|
CloseHandle(EventInfo->eventHandle);
|
|
|
|
env->SetBooleanField(jobj, jfMonitorThreadCloseLock, JNI_FALSE);
|
|
return;
|
|
}
|
|
|
|
if(EventInfo->eventThreadReady)
|
|
{ // Thread is ready to work - pass signal to Java
|
|
IF_DEBUG
|
|
(
|
|
printj(env, L"--- RXTXPort.eventLoop() - EventThread is ready\n");
|
|
)
|
|
env->SetBooleanField(jobj, jfMonitorThreadLock, JNI_FALSE);
|
|
EventInfo->eventThreadReady = false;
|
|
}
|
|
|
|
if((dwWaitResult = WaitForSingleObject(EventInfo->eventHandle, 250)) == WAIT_FAILED)
|
|
{
|
|
IF_DEBUG
|
|
(
|
|
LPCWSTR lpMsgBuf;
|
|
CreateErrorMsg(GetLastError(), lpMsgBuf);
|
|
printj(env, L"!!! eventLoop - WaitForSingleObject() error: %s\n", lpMsgBuf);
|
|
ReleaseErrorMsg(lpMsgBuf);
|
|
)
|
|
CloseHandle(EventInfo->eventHandle);
|
|
env->SetBooleanField(jobj, jfMonitorThreadCloseLock, JNI_FALSE);
|
|
return;
|
|
}
|
|
|
|
if(dwWaitResult == WAIT_OBJECT_0)
|
|
{
|
|
dwEvent = EventInfo->event;
|
|
// Clearing event - event thread will continue
|
|
EventInfo->event = 0;
|
|
// Send events to Java
|
|
if(RetVal = SendEvents(env, jobj, dwEvent, EventInfo, jmSendEvent))
|
|
{
|
|
IF_DEBUG
|
|
(
|
|
printj(env, L"!!! eventLoop - SendEvents() result: %d\n", RetVal);
|
|
)
|
|
CloseHandle(EventInfo->eventHandle);
|
|
env->SetBooleanField(jobj, jfMonitorThreadCloseLock, JNI_FALSE);
|
|
return;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
IF_DEBUG
|
|
(
|
|
//printj(env, L"--- eventLoop() looping\n");
|
|
MessageBeep(MB_OK);
|
|
)
|
|
}
|
|
} while(TRUE);
|
|
}
|
|
|
|
|
|
/*
|
|
interruptEventLoop
|
|
|
|
accept: nothing
|
|
perform: sets monThreadisInterrupted
|
|
return: nothing
|
|
exceptions: none
|
|
comments: real monitoring thread will stay until port is closed
|
|
* Class: gnu_io_RXTXPort
|
|
* Method: interruptEventLoop
|
|
* Signature: ()V
|
|
*/
|
|
JNIEXPORT void JNICALL Java_gnu_io_RXTXPort_interruptEventLoop(JNIEnv *env, jobject jobj)
|
|
{
|
|
jfieldID jfid;
|
|
HANDLE hPort = get_fd(env, jobj);
|
|
|
|
jclass cls = env->GetObjectClass(jobj);
|
|
jfid = env->GetFieldID(cls, "monThreadisInterrupted", "Z");
|
|
env->SetBooleanField(jobj, jfid, JNI_TRUE);
|
|
}
|
|
|
|
|
|
/*
|
|
nativeSetEventFlag
|
|
|
|
accept: fd for finding the struct, event to flag, flag.
|
|
perform: toggle the flag
|
|
return: none
|
|
exceptions: none
|
|
comments: all the logic used to be done in Java but its too noisy
|
|
* Class: gnu_io_RXTXPort
|
|
* Method: nativeSetEventFlag
|
|
* Signature: (IIZ)V
|
|
*/
|
|
JNIEXPORT void JNICALL Java_gnu_io_RXTXPort_nativeSetEventFlag(JNIEnv *env, jobject jobj, jint fd, jint event, jboolean flag)
|
|
{
|
|
DWORD dwErr, NewFlag;
|
|
EventInfoStruct *EventInfo = get_eis(env, jobj);
|
|
HANDLE hPort = (HANDLE)fd;
|
|
|
|
IF_DEBUG
|
|
(
|
|
printj(env, L"--- nativeSetEventFlag(%ld, %d) called\n", event, (int)flag);
|
|
)
|
|
|
|
switch(event)
|
|
{
|
|
case SPE_DATA_AVAILABLE:
|
|
NewFlag = EV_RXCHAR;
|
|
break;
|
|
|
|
case SPE_OUTPUT_BUFFER_EMPTY:
|
|
NewFlag = EV_TXEMPTY;
|
|
break;
|
|
|
|
case SPE_CTS:
|
|
NewFlag = EV_CTS;
|
|
break;
|
|
|
|
case SPE_DSR:
|
|
NewFlag = EV_DSR;
|
|
break;
|
|
|
|
case SPE_RI:
|
|
NewFlag = EV_RING;
|
|
break;
|
|
|
|
case SPE_CD:
|
|
NewFlag = EV_RLSD;
|
|
break;
|
|
|
|
case SPE_OE:
|
|
case SPE_PE:
|
|
case SPE_FE:
|
|
NewFlag = EV_ERR;
|
|
break;
|
|
|
|
case SPE_BI:
|
|
NewFlag = EV_BREAK;
|
|
break;
|
|
|
|
}
|
|
|
|
if(flag == JNI_TRUE)
|
|
EventInfo->ef = EventInfo->ef | NewFlag;
|
|
else
|
|
EventInfo->ef = EventInfo->ef & ~NewFlag;
|
|
|
|
if(!SetCommMask(hPort, EventInfo->ef))
|
|
{
|
|
dwErr = GetLastError();
|
|
IF_DEBUG
|
|
(
|
|
LPCWSTR lpMsgBuf;
|
|
CreateErrorMsg(dwErr, lpMsgBuf);
|
|
printj(env, L"!!! nativeSetEventFlag - SetCommMask() error: %ld %s\n", dwErr, lpMsgBuf );
|
|
ReleaseErrorMsg(lpMsgBuf);
|
|
)
|
|
return;
|
|
}
|
|
|
|
}
|
|
|
|
/*
|
|
nativeClose
|
|
|
|
accept: none
|
|
perform: get the fd from the java end and close it
|
|
return: none
|
|
exceptions: none
|
|
* Class: gnu_io_RXTXPort
|
|
* Method: nativeClose
|
|
* Signature: (Ljava/lang/String{ })V
|
|
*/
|
|
JNIEXPORT void JNICALL Java_gnu_io_RXTXPort_nativeClose(JNIEnv *env, jobject jobj, jstring name)
|
|
{
|
|
HANDLE hPort = get_fd(env, jobj);
|
|
|
|
IF_DEBUG
|
|
(
|
|
LPCWSTR wszName = env->GetStringChars(name, NULL);
|
|
printj(env, L"--- RXTXPort.nativeClose(%s) called\n", wszName);
|
|
env->ReleaseStringChars(name, wszName);
|
|
)
|
|
|
|
if (!CloseHandle(hPort))
|
|
{
|
|
GetLastError();
|
|
return;
|
|
}
|
|
|
|
}
|
|
|
|
/*
|
|
nativeGetParityErrorChar
|
|
|
|
accept: -
|
|
perform: check the ParityErrorChar
|
|
return: The ParityErrorChar as an jbyte.
|
|
exceptions: UnsupportedCommOperationException if not implemented
|
|
comments: It appears the Parity char is usually \0. The windows
|
|
API allows for this to be changed. I cant find may
|
|
examples of this being done. Maybe for a reason.
|
|
|
|
Use a direct call to the termios file until we find a
|
|
solution.
|
|
* Class: gnu_io_RXTXPort
|
|
* Method: nativeGetParityErrorChar
|
|
* Signature: ()I
|
|
*/
|
|
JNIEXPORT jbyte JNICALL Java_gnu_io_RXTXPort_nativeGetParityErrorChar(JNIEnv *env, jobject jobj)
|
|
{
|
|
DCB PortDCB;
|
|
LPCWSTR lpMsgBuf;
|
|
|
|
HANDLE hPort = get_fd(env, jobj);
|
|
PortDCB.DCBlength = sizeof(DCB);
|
|
|
|
IF_DEBUG
|
|
(
|
|
printj(env, L"--- RXTXPort.nativeGetParityErrorChar() called\n");
|
|
)
|
|
|
|
// Get port setting information.
|
|
if(!GetCommState(hPort, &PortDCB))
|
|
{ //Unable to get configuration of the serial port
|
|
CreateErrorMsg(GetLastError(), lpMsgBuf);
|
|
IF_DEBUG
|
|
(
|
|
printj(env, L"!!! nativeGetParityErrorChar - GetCommState() error: %s\n", lpMsgBuf);
|
|
)
|
|
ReleaseErrorMsg(lpMsgBuf);
|
|
return -1;
|
|
}
|
|
|
|
return (jbyte)PortDCB.ErrorChar;
|
|
}
|
|
|
|
/*
|
|
nativeSetParityErrorChar
|
|
|
|
accept: the ParityArrorCharacter as an int.
|
|
perform: Set the ParityErrorChar
|
|
return: JNI_TRUE on success
|
|
exceptions: UnsupportedCommOperationException if not implemented
|
|
comments: It appears the Parity char is usually \0. The windows
|
|
API allows for this to be changed. I cant find may
|
|
examples of this being done. Maybe for a reason.
|
|
|
|
Use a direct call to the termios file until we find a
|
|
solution.
|
|
* Class: gnu_io_RXTXPort
|
|
* Method: nativeSetParityErrorChar
|
|
* Signature: (B)Z
|
|
*/
|
|
JNIEXPORT jboolean JNICALL Java_gnu_io_RXTXPort_nativeSetParityErrorChar(JNIEnv *env, jobject jobj, jbyte b)
|
|
{
|
|
DCB PortDCB;
|
|
LPCWSTR lpMsgBuf;
|
|
|
|
HANDLE hPort = get_fd(env, jobj);
|
|
PortDCB.DCBlength = sizeof(DCB);
|
|
|
|
IF_DEBUG
|
|
(
|
|
printj(env, L"--- RXTXPort.nativeSetParityErrorChar(%#x) called\n", (int)b);
|
|
)
|
|
|
|
// Get port setting information.
|
|
if(!GetCommState(hPort, &PortDCB))
|
|
{ //Unable to get configuration of the serial port
|
|
CreateErrorMsg(GetLastError(), lpMsgBuf);
|
|
IF_DEBUG
|
|
(
|
|
printj(env, L"!!! nativeSetParityErrorChar - GetCommState() error: %s\n", lpMsgBuf);
|
|
)
|
|
ReleaseErrorMsg(lpMsgBuf);
|
|
return JNI_FALSE;
|
|
}
|
|
|
|
if(b != 0)
|
|
{
|
|
PortDCB.fErrorChar = TRUE;
|
|
PortDCB.fParity = TRUE;
|
|
PortDCB.ErrorChar = b;
|
|
}
|
|
else
|
|
{
|
|
PortDCB.fErrorChar = FALSE;
|
|
PortDCB.fParity = FALSE;
|
|
PortDCB.ErrorChar = 0;
|
|
}
|
|
|
|
if (!SetCommState(hPort, &PortDCB))
|
|
{
|
|
CreateErrorMsg(GetLastError(), lpMsgBuf);
|
|
IF_DEBUG
|
|
(
|
|
printj(env, L"!!! nativeSetParityErrorChar - SetCommState() error: %s\n", lpMsgBuf);
|
|
)
|
|
ReleaseErrorMsg(lpMsgBuf);
|
|
return JNI_FALSE;
|
|
}
|
|
|
|
return JNI_TRUE;
|
|
}
|
|
|
|
/*
|
|
nativeGetEndOfInputChar
|
|
|
|
accept: -
|
|
perform: check the EndOf InputChar
|
|
return: the EndOfInputChar as an jbyte. -1 on error
|
|
exceptions: UnsupportedCommOperationException if not implemented
|
|
comments:
|
|
* Class: gnu_io_RXTXPort
|
|
* Method: nativeGetEndOfInputChar
|
|
* Signature: ()I
|
|
*/
|
|
JNIEXPORT jbyte JNICALL Java_gnu_io_RXTXPort_nativeGetEndOfInputChar(JNIEnv *env, jobject jobj)
|
|
{
|
|
DCB PortDCB;
|
|
LPCWSTR lpMsgBuf;
|
|
|
|
HANDLE hPort = get_fd(env, jobj);
|
|
PortDCB.DCBlength = sizeof(DCB);
|
|
|
|
IF_DEBUG
|
|
(
|
|
printj(env, L"--- RXTXPort.nativeGetEndOfInputChar() called\n");
|
|
)
|
|
|
|
// Get port setting information.
|
|
if(!GetCommState(hPort, &PortDCB))
|
|
{ //Unable to get configuration of the serial port
|
|
CreateErrorMsg(GetLastError(), lpMsgBuf);
|
|
IF_DEBUG
|
|
(
|
|
printj(env, L"!!! nativeGetEndOfInputChar - GetCommState() error: %s\n", lpMsgBuf);
|
|
)
|
|
ReleaseErrorMsg(lpMsgBuf);
|
|
return -1;
|
|
}
|
|
|
|
return (jbyte)PortDCB.EofChar;
|
|
}
|
|
|
|
|
|
/*
|
|
nativeSetEndOfInputChar
|
|
|
|
accept: The EndOfInputChar as an int
|
|
perform: set the EndOfInputChar
|
|
return: JNI_TRUE on success
|
|
exceptions: UnsupportedCommOperationException if not implemented
|
|
comments: This may cause troubles on Windows.
|
|
Lets give it a shot and see what happens.
|
|
|
|
See termios.c for the windows bits.
|
|
|
|
EofChar = val;
|
|
fBinary = false; //winapi docs say always use true. ?
|
|
* Class: gnu_io_RXTXPort
|
|
* Method: nativeSetEndOfInputChar
|
|
* Signature: (B)Z
|
|
*/
|
|
JNIEXPORT jboolean JNICALL Java_gnu_io_RXTXPort_nativeSetEndOfInputChar(JNIEnv *env, jobject jobj, jbyte b)
|
|
{
|
|
DCB PortDCB;
|
|
LPCWSTR lpMsgBuf;
|
|
|
|
HANDLE hPort = get_fd(env, jobj);
|
|
PortDCB.DCBlength = sizeof(DCB);
|
|
|
|
IF_DEBUG
|
|
(
|
|
printj(env, L"--- RXTXPort.nativeSetEndOfInputChar(%#x) called\n", (int)b);
|
|
)
|
|
|
|
// Get port setting information.
|
|
if(!GetCommState(hPort, &PortDCB))
|
|
{ //Unable to get configuration of the serial port
|
|
CreateErrorMsg(GetLastError(), lpMsgBuf);
|
|
IF_DEBUG
|
|
(
|
|
printj(env, L"!!! nativeSetEndOfInputChar - GetCommState() error: %s\n", lpMsgBuf);
|
|
)
|
|
ReleaseErrorMsg(lpMsgBuf);
|
|
return JNI_FALSE;
|
|
}
|
|
|
|
if( b != 0)
|
|
{
|
|
PortDCB.fBinary = FALSE;
|
|
PortDCB.EofChar = b;
|
|
}
|
|
else
|
|
{
|
|
PortDCB.fBinary = TRUE;
|
|
PortDCB.EofChar = 0;
|
|
}
|
|
|
|
if (!SetCommState(hPort, &PortDCB))
|
|
{
|
|
CreateErrorMsg(GetLastError(), lpMsgBuf);
|
|
IF_DEBUG
|
|
(
|
|
printj(env, L"!!! nativeSetEndOfInputChar - SetCommState() error: %s\n", lpMsgBuf);
|
|
)
|
|
throw_java_exceptionW(env, UNSUPPORTED_COMM_OPERATION, L"nativeSetEndOfInputChar", lpMsgBuf);
|
|
ReleaseErrorMsg(lpMsgBuf);
|
|
return JNI_FALSE;
|
|
}
|
|
|
|
return JNI_TRUE;
|
|
}
|
|
|
|
|
|
/*
|
|
* Class: gnu_io_RXTXPort
|
|
* Method: nativeSetUartType
|
|
* Signature: (Ljava/lang/String{ }Z)Z
|
|
*/
|
|
JNIEXPORT jboolean JNICALL Java_gnu_io_RXTXPort_nativeSetUartType(JNIEnv *env, jobject jobj, jstring type, jboolean test)
|
|
{
|
|
throw_java_exceptionW(env, UNSUPPORTED_COMM_OPERATION, L"nativeSetUartType", L"Operation not implemented");
|
|
return JNI_FALSE;
|
|
}
|
|
|
|
/*
|
|
* Class: gnu_io_RXTXPort
|
|
* Method: nativeGetUartType
|
|
* Signature: ()Ljava/lang/String{ }
|
|
*/
|
|
JNIEXPORT jstring JNICALL Java_gnu_io_RXTXPort_nativeGetUartType(JNIEnv *env, jobject jobj)
|
|
{
|
|
throw_java_exceptionW(env, UNSUPPORTED_COMM_OPERATION, L"nativeSetUartType", L"Operation not implemented");
|
|
return env->NewStringUTF("Unknown");
|
|
}
|
|
|
|
/*
|
|
* Class: gnu_io_RXTXPort
|
|
* Method: nativeSetBaudBase
|
|
* Signature: (I)Z
|
|
*/
|
|
JNIEXPORT jboolean JNICALL Java_gnu_io_RXTXPort_nativeSetBaudBase(JNIEnv *env, jobject jobj, jint baudBase)
|
|
{
|
|
throw_java_exceptionW(env, UNSUPPORTED_COMM_OPERATION, L"nativeSetBaudBase", L"Operation not implemented");
|
|
return JNI_FALSE;
|
|
}
|
|
|
|
/*
|
|
* Class: gnu_io_RXTXPort
|
|
* Method: nativeGetBaudBase
|
|
* Signature: ()I
|
|
*/
|
|
JNIEXPORT jint JNICALL Java_gnu_io_RXTXPort_nativeGetBaudBase(JNIEnv *env, jobject jobj)
|
|
{
|
|
throw_java_exceptionW(env, UNSUPPORTED_COMM_OPERATION, L"nativeGetBaudBase", L"Operation not implemented");
|
|
return -1;
|
|
}
|
|
|
|
/*
|
|
* Class: gnu_io_RXTXPort
|
|
* Method: nativeSetDivisor
|
|
* Signature: (I)Z
|
|
*/
|
|
JNIEXPORT jboolean JNICALL Java_gnu_io_RXTXPort_nativeSetDivisor(JNIEnv *env, jobject jobj, jint divisor)
|
|
{
|
|
throw_java_exceptionW(env, UNSUPPORTED_COMM_OPERATION, L"nativeSetDivisor", L"Operation not implemented");
|
|
return JNI_FALSE;
|
|
}
|
|
|
|
/*
|
|
* Class: gnu_io_RXTXPort
|
|
* Method: nativeGetDivisor
|
|
* Signature: ()I
|
|
*/
|
|
JNIEXPORT jint JNICALL Java_gnu_io_RXTXPort_nativeGetDivisor(JNIEnv *env, jobject jobj)
|
|
{
|
|
throw_java_exceptionW(env, UNSUPPORTED_COMM_OPERATION, L"nativeGetDivisor", L"Operation not implemented");
|
|
return -1;
|
|
}
|
|
|
|
/*
|
|
* Class: gnu_io_RXTXPort
|
|
* Method: nativeSetLowLatency
|
|
* Signature: ()Z
|
|
*/
|
|
JNIEXPORT jboolean JNICALL Java_gnu_io_RXTXPort_nativeSetLowLatency(JNIEnv *env, jobject jobj)
|
|
{
|
|
throw_java_exceptionW(env, UNSUPPORTED_COMM_OPERATION, L"nativeSetLowLatency", L"Operation not implemented");
|
|
return JNI_FALSE;
|
|
}
|
|
|
|
/*
|
|
* Class: gnu_io_RXTXPort
|
|
* Method: nativeGetLowLatency
|
|
* Signature: ()Z
|
|
*/
|
|
JNIEXPORT jboolean JNICALL Java_gnu_io_RXTXPort_nativeGetLowLatency(JNIEnv *env, jobject jobj)
|
|
{
|
|
throw_java_exceptionW(env, UNSUPPORTED_COMM_OPERATION, L"nativeGetLowLatency", L"Operation not implemented");
|
|
return JNI_FALSE;
|
|
}
|
|
|
|
/*
|
|
* Class: gnu_io_RXTXPort
|
|
* Method: nativeSetCallOutHangup
|
|
* Signature: (Z)Z
|
|
*/
|
|
JNIEXPORT jboolean JNICALL Java_gnu_io_RXTXPort_nativeSetCallOutHangup(JNIEnv *env, jobject jobj, jboolean noHup)
|
|
{
|
|
throw_java_exceptionW(env, UNSUPPORTED_COMM_OPERATION, L"nativeSetCallOutHangup", L"Operation not implemented");
|
|
return JNI_FALSE;
|
|
}
|
|
|
|
/*
|
|
* Class: gnu_io_RXTXPort
|
|
* Method: nativeGetCallOutHangup
|
|
* Signature: ()Z
|
|
*/
|
|
JNIEXPORT jboolean JNICALL Java_gnu_io_RXTXPort_nativeGetCallOutHangup(JNIEnv *env, jobject jobj)
|
|
{
|
|
throw_java_exceptionW(env, UNSUPPORTED_COMM_OPERATION, L"nativeGetCallOutHangup", L"Operation not implemented");
|
|
return JNI_FALSE;
|
|
}
|
|
|