Allow retrieval of native error codes and source locations

This commit is contained in:
Will Hedgecock 2021-11-16 21:01:49 -06:00
parent 28efbd1a51
commit 9395d29777
1 changed files with 62 additions and 43 deletions

View File

@ -2,7 +2,7 @@
* SerialPort.java
*
* Created on: Feb 25, 2012
* Last Updated on: Oct 22, 2021
* Last Updated on: Nov 12, 2021
* Author: Will Hedgecock
*
* Copyright (C) 2012-2021 Fazecast, Inc.
@ -308,7 +308,7 @@ public final class SerialPort
*
* @return An array of {@link SerialPort} objects.
*/
static public final native SerialPort[] getCommPorts();
static public final synchronized native SerialPort[] getCommPorts();
/**
* Allocates a {@link SerialPort} object corresponding to the user-specified port descriptor.
@ -506,7 +506,7 @@ public final class SerialPort
{
if (serialEventListener != null)
serialEventListener.stopListening();
closePortNative(portHandle);
portHandle = closePortNative(portHandle);
return (portHandle <= 0);
}
@ -533,20 +533,40 @@ public final class SerialPort
* exclusive locks on system resources.
*/
public final synchronized void disableExclusiveLock() { disableExclusiveLock = true; }
/**
* Returns the source code line location of the latest error encountered during execution of
* the native code for this port.
* <p>
* This function must be called while the port is still open as soon as an error is encountered,
* or it may return an incorrect source code line location.
*
* @return Source line of latest native code error.
*/
public final synchronized int getLastErrorLocation() { return (portHandle > 0) ? getLastErrorLocation(portHandle) : -1; }
/**
* Returns the error number returned by the most recent native source code line that failed execution.
* <p>
* This function must be called while the port is still open as soon as an error is encountered,
* or it may return an incorrect or invalid error code.
*
* @return Error number of the latest native code error.
*/
public final synchronized int getLastErrorCode() { return (portHandle > 0) ? getLastErrorCode(portHandle) : 0; }
// Serial Port Setup Methods
private static native void initializeLibrary(); // Initializes the JNI code
private static native void uninitializeLibrary(); // Un-initializes the JNI code
private final native long openPortNative(); // Opens serial port
private final native boolean closePortNative(long portHandle); // Closes serial port
private final native long closePortNative(long portHandle); // Closes serial port
private final native boolean configPort(long portHandle); // Changes/sets serial port parameters as defined by this class
private final native boolean configTimeouts(long portHandle); // Changes/sets serial port timeouts as defined by this class
private final native boolean configEventFlags(long portHandle); // Changes/sets which serial events to listen for as defined by this class
private final native boolean configTimeouts(long portHandle, int timeoutMode, int readTimeout, int writeTimeout, int eventsToMonitor); // Changes/sets serial port timeouts as defined by this class
private final native int waitForEvent(long portHandle); // Waits for serial event to occur as specified in eventFlags
private final native int bytesAvailable(long portHandle); // Returns number of bytes available for reading
private final native int bytesAwaitingWrite(long portHandle); // Returns number of bytes still waiting to be written
private final native int readBytes(long portHandle, byte[] buffer, long bytesToRead, long offset); // Reads bytes from serial port
private final native int writeBytes(long portHandle, byte[] buffer, long bytesToWrite, long offset); // Write bytes to serial port
private final native int readBytes(long portHandle, byte[] buffer, long bytesToRead, long offset, int timeoutMode, int readTimeout); // Reads bytes from serial port
private final native int writeBytes(long portHandle, byte[] buffer, long bytesToWrite, long offset, int timeoutMode); // Write bytes to serial port
private final native boolean setBreak(long portHandle); // Set BREAK status on serial line
private final native boolean clearBreak(long portHandle); // Clear BREAK status on serial line
private final native boolean setRTS(long portHandle); // Set RTS line to 1
@ -563,6 +583,8 @@ public final class SerialPort
private final native boolean getDTR(long portHandle); // Returns whether the DTR signal is 1
private final native boolean getRTS(long portHandle); // Returns whether the RTS signal is 1
private final native boolean getRI(long portHandle); // Returns whether the RI signal is 1
private final native int getLastErrorLocation(long portHandle); // Returns the source code line location of the latest native code error
private final native int getLastErrorCode(long portHandle); // Returns the errno value of the latest native code error
/**
* Returns the number of bytes available without blocking if {@link #readBytes(byte[], long)} were to be called immediately
@ -570,7 +592,7 @@ public final class SerialPort
*
* @return The number of bytes currently available to be read, or -1 if the port is not open.
*/
public final int bytesAvailable() { return bytesAvailable(portHandle); }
public final int bytesAvailable() { return (portHandle > 0) ? bytesAvailable(portHandle) : -1; }
/**
* Returns the number of bytes still waiting to be written in the device's output queue.
@ -579,7 +601,7 @@ public final class SerialPort
*
* @return The number of bytes currently waiting to be written, or -1 if the port is not open.
*/
public final int bytesAwaitingWrite() { return bytesAwaitingWrite(portHandle); }
public final int bytesAwaitingWrite() { return (portHandle > 0) ? bytesAwaitingWrite(portHandle) : -1; }
/**
* Reads up to <i>bytesToRead</i> raw data bytes from the serial port and stores them in the buffer.
@ -594,7 +616,7 @@ public final class SerialPort
* @param bytesToRead The number of bytes to read from the serial port.
* @return The number of bytes successfully read, or -1 if there was an error reading from the port.
*/
public final int readBytes(byte[] buffer, long bytesToRead) { return readBytes(portHandle, buffer, bytesToRead, 0); }
public final int readBytes(byte[] buffer, long bytesToRead) { return (portHandle > 0) ? readBytes(portHandle, buffer, bytesToRead, 0, timeoutMode, readTimeout) : -1; }
/**
* Reads up to <i>bytesToRead</i> raw data bytes from the serial port and stores them in the buffer starting at the indicated offset.
@ -610,7 +632,7 @@ public final class SerialPort
* @param offset The read buffer index into which to begin storing data.
* @return The number of bytes successfully read, or -1 if there was an error reading from the port.
*/
public final int readBytes(byte[] buffer, long bytesToRead, long offset) { return readBytes(portHandle, buffer, bytesToRead, offset); }
public final int readBytes(byte[] buffer, long bytesToRead, long offset) { return (portHandle > 0) ? readBytes(portHandle, buffer, bytesToRead, offset, timeoutMode, readTimeout) : -1; }
/**
* Writes up to <i>bytesToWrite</i> raw data bytes from the buffer parameter to the serial port.
@ -625,7 +647,7 @@ public final class SerialPort
* @param bytesToWrite The number of bytes to write to the serial port.
* @return The number of bytes successfully written, or -1 if there was an error writing to the port.
*/
public final int writeBytes(byte[] buffer, long bytesToWrite) { return writeBytes(portHandle, buffer, bytesToWrite, 0); }
public final int writeBytes(byte[] buffer, long bytesToWrite) { return (portHandle > 0) ? writeBytes(portHandle, buffer, bytesToWrite, 0, timeoutMode) : -1; }
/**
* Writes up to <i>bytesToWrite</i> raw data bytes from the buffer parameter to the serial port starting at the indicated offset.
@ -641,7 +663,7 @@ public final class SerialPort
* @param offset The buffer index from which to begin writing to the serial port.
* @return The number of bytes successfully written, or -1 if there was an error writing to the port.
*/
public final int writeBytes(byte[] buffer, long bytesToWrite, long offset) { return writeBytes(portHandle, buffer, bytesToWrite, offset); }
public final int writeBytes(byte[] buffer, long bytesToWrite, long offset) { return (portHandle > 0) ? writeBytes(portHandle, buffer, bytesToWrite, offset, timeoutMode) : -1; }
/**
* Returns the underlying transmit buffer size used by the serial port device driver. The device or operating system may choose to misrepresent this value.
@ -659,13 +681,13 @@ public final class SerialPort
* Sets the BREAK signal on the serial control line.
* @return true if successful, false if not.
*/
public final boolean setBreak() { return setBreak(portHandle); }
public final boolean setBreak() { return (portHandle > 0) && setBreak(portHandle); }
/**
* Clears the BREAK signal from the serial control line.
* @return true if successful, false if not.
*/
public final boolean clearBreak() { return clearBreak(portHandle); }
public final boolean clearBreak() { return (portHandle > 0) && clearBreak(portHandle); }
/**
* Sets the state of the RTS line to 1.
@ -674,7 +696,7 @@ public final class SerialPort
public final boolean setRTS()
{
isRtsEnabled = true;
return ((portHandle > 0) ? setRTS(portHandle) : presetRTS());
return (portHandle > 0) ? setRTS(portHandle) : presetRTS();
}
/**
@ -684,7 +706,7 @@ public final class SerialPort
public final boolean clearRTS()
{
isRtsEnabled = false;
return ((portHandle > 0) ? clearRTS(portHandle) : preclearRTS());
return (portHandle > 0) ? clearRTS(portHandle) : preclearRTS();
}
/**
@ -694,7 +716,7 @@ public final class SerialPort
public final boolean setDTR()
{
isDtrEnabled = true;
return ((portHandle > 0) ? setDTR(portHandle) : presetDTR());
return (portHandle > 0) ? setDTR(portHandle) : presetDTR();
}
/**
@ -704,26 +726,26 @@ public final class SerialPort
public final boolean clearDTR()
{
isDtrEnabled = false;
return ((portHandle > 0) ? clearDTR(portHandle) : preclearDTR());
return (portHandle > 0) ? clearDTR(portHandle) : preclearDTR();
}
/**
* Returns whether the CTS line is currently asserted.
* @return Whether or not the CTS line is asserted.
*/
public final boolean getCTS() { return getCTS(portHandle); }
public final boolean getCTS() { return (portHandle > 0) && getCTS(portHandle); }
/**
* Returns whether the DSR line is currently asserted.
* @return Whether or not the DSR line is asserted.
*/
public final boolean getDSR() { return getDSR(portHandle); }
public final boolean getDSR() { return (portHandle > 0) && getDSR(portHandle); }
/**
* Returns whether the DCD line is currently asserted.
* @return Whether or not the DCD line is asserted.
*/
public final boolean getDCD() { return getDCD(portHandle); }
public final boolean getDCD() { return (portHandle > 0) && getDCD(portHandle); }
/**
* Returns whether the DTR line is currently asserted.
@ -731,7 +753,7 @@ public final class SerialPort
* Note that polling this line's status is not supported on Windows, so results may be incorrect.
* @return Whether or not the DTR line is asserted.
*/
public final boolean getDTR() { return getDTR(portHandle); }
public final boolean getDTR() { return (portHandle > 0) && getDTR(portHandle); }
/**
* Returns whether the RTS line is currently asserted.
@ -739,13 +761,13 @@ public final class SerialPort
* Note that polling this line's status is not supported on Windows, so results may be incorrect.
* @return Whether or not the RTS line is asserted.
*/
public final boolean getRTS() { return getRTS(portHandle); }
public final boolean getRTS() { return (portHandle > 0) && getRTS(portHandle); }
/**
* Returns whether the RI line is currently asserted.
* @return Whether or not the RI line is asserted.
*/
public final boolean getRI() { return getRI(portHandle); }
public final boolean getRI() { return (portHandle > 0) && getRI(portHandle); }
// Default Constructor
private SerialPort() {}
@ -792,7 +814,7 @@ public final class SerialPort
if (portHandle > 0)
{
configEventFlags(portHandle);
configTimeouts(portHandle, timeoutMode, readTimeout, writeTimeout, eventFlags);
serialEventListener.startListening();
}
return true;
@ -808,6 +830,7 @@ public final class SerialPort
{
serialEventListener.stopListening();
serialEventListener = null;
configTimeouts(portHandle, timeoutMode, readTimeout, writeTimeout, eventFlags);
}
userDataListener = null;
}
@ -1032,7 +1055,7 @@ public final class SerialPort
{
if (safetySleepTimeMS > 0)
try { Thread.sleep(safetySleepTimeMS); } catch (Exception e) { Thread.currentThread().interrupt(); }
return configTimeouts(portHandle);
return configTimeouts(portHandle, timeoutMode, readTimeout, writeTimeout, eventFlags);
}
return true;
}
@ -1402,7 +1425,7 @@ public final class SerialPort
@Override
public void run()
{
while (eventListenerRunning && (portHandle > 0))
while (eventListenerRunning)
{
try { waitForSerialEvent(); }
catch (Exception e)
@ -1414,7 +1437,6 @@ public final class SerialPort
((SerialPortMessageListenerWithExceptions)userDataListener).catchException(e);
}
}
eventListenerRunning = false;
}
});
serialEventThread.start();
@ -1425,11 +1447,8 @@ public final class SerialPort
if (!eventListenerRunning)
return;
eventListenerRunning = false;
int oldEventFlags = eventFlags;
eventFlags = 0;
configEventFlags(portHandle);
eventFlags = oldEventFlags;
configTimeouts(portHandle, TIMEOUT_NONBLOCKING, 0, 0, 0);
try
{
serialEventThread.join(500);
@ -1453,9 +1472,9 @@ public final class SerialPort
int numBytesAvailable, bytesRemaining, newBytesIndex;
while (eventListenerRunning && ((numBytesAvailable = bytesAvailable(portHandle)) > 0))
{
byte[] newBytes = new byte[numBytesAvailable];
newBytesIndex = 0;
bytesRemaining = readBytes(portHandle, newBytes, newBytes.length, 0);
byte[] newBytes = new byte[numBytesAvailable];
bytesRemaining = readBytes(portHandle, newBytes, newBytes.length, 0, timeoutMode, readTimeout);
if (delimiters.length > 0)
{
int startIndex = 0;
@ -1542,7 +1561,7 @@ public final class SerialPort
throw new SerialPortIOException("This port appears to have been shutdown or disconnected.");
// Read from the serial port
int numRead = readBytes(portHandle, byteBuffer, 1L, 0);
int numRead = readBytes(portHandle, byteBuffer, 1L, 0, timeoutMode, readTimeout);
if (numRead == 0)
{
if (timeoutExceptionsSuppressed)
@ -1565,7 +1584,7 @@ public final class SerialPort
return 0;
// Read from the serial port
int numRead = readBytes(portHandle, b, b.length, 0);
int numRead = readBytes(portHandle, b, b.length, 0, timeoutMode, readTimeout);
if ((numRead == 0) && !timeoutExceptionsSuppressed)
throw new SerialPortTimeoutException("The read operation timed out before any data was returned.");
return numRead;
@ -1585,7 +1604,7 @@ public final class SerialPort
return 0;
// Read from the serial port
int numRead = readBytes(portHandle, b, len, off);
int numRead = readBytes(portHandle, b, len, off, timeoutMode, readTimeout);
if ((numRead == 0) && !timeoutExceptionsSuppressed)
throw new SerialPortTimeoutException("The read operation timed out before any data was returned.");
return numRead;
@ -1597,7 +1616,7 @@ public final class SerialPort
if (portHandle <= 0)
throw new SerialPortIOException("This port appears to have been shutdown or disconnected.");
byte[] buffer = new byte[(int)n];
return readBytes(portHandle, buffer, n, 0);
return readBytes(portHandle, buffer, n, 0, timeoutMode, readTimeout);
}
}
@ -1614,7 +1633,7 @@ public final class SerialPort
if (portHandle <= 0)
throw new SerialPortIOException("This port appears to have been shutdown or disconnected.");
byteBuffer[0] = (byte)(b & 0xFF);
int bytesWritten = writeBytes(portHandle, byteBuffer, 1L, 0);
int bytesWritten = writeBytes(portHandle, byteBuffer, 1L, 0, timeoutMode);
if (bytesWritten < 0)
throw new SerialPortIOException("No bytes written. This port appears to have been shutdown or disconnected.");
else if (bytesWritten == 0)
@ -1641,7 +1660,7 @@ public final class SerialPort
return;
// Write to the serial port
int numWritten = writeBytes(portHandle, b, len, off);
int numWritten = writeBytes(portHandle, b, len, off, timeoutMode);
if (numWritten < 0)
throw new SerialPortIOException("No bytes written. This port appears to have been shutdown or disconnected.");
else if (numWritten == 0)