org.bidib.jbidibc.ftdi.serial.FtdiSerialConnectorLinux Maven / Gradle / Ivy
package org.bidib.jbidibc.ftdi.serial;
import java.util.EnumSet;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.ftdi.DeviceStatus;
import com.ftdi.FTD2XX;
import com.ftdi.FTD2XXException;
import com.ftdi.FTDevice;
import com.sun.jna.Pointer;
import com.sun.jna.platform.unix.LibPThread;
import com.sun.jna.platform.unix.LibPThread.EVENT_HANDLE;
public class FtdiSerialConnectorLinux extends AbstractFtdiSerialConnector {
private static final Logger LOGGER = LoggerFactory.getLogger(FtdiSerialConnectorLinux.class);
private static final LibPThread libPThreadExt = LibPThread.INSTANCE;
private EVENT_HANDLE hEvent;
private byte[] inputBuffer = new byte[2048];
@Override
protected void closeHandle() {
LOGGER.info("Close the handle: {}", this.hEvent);
if (this.hEvent != null) {
EVENT_HANDLE hEvent = this.hEvent;
this.hEvent = null;
libPThreadExt.pthread_cond_signal(hEvent.eCondVar.getPointer());
libPThreadExt.pthread_cond_destroy(hEvent.eCondVar.getPointer());
libPThreadExt.pthread_mutex_destroy(hEvent.eMutex.getPointer());
}
}
@Override
protected Thread createReceiverThread() {
return new ReceiverThread();
}
public class ReceiverThread extends Thread {
public ReceiverThread() {
super("FTDI-Receiver");
}
@Override
public void run() {
receiverRunning.set(true);
Thread.currentThread().setPriority(MAX_PRIORITY);
final FTDevice serialPort = getFTDevice();
LOGGER.info("Started the receiver thread.");
FtdiSerialConnectorLinux.this.hEvent = new EVENT_HANDLE();
int retVal = libPThreadExt.pthread_mutex_init(hEvent.eMutex.getPointer(), Pointer.NULL);
LOGGER.info("Initialized the mutex: {}", retVal);
retVal = libPThreadExt.pthread_cond_init(hEvent.eCondVar.getPointer(), Pointer.NULL);
LOGGER.info("Initialized the condVar: {}", retVal);
int eventMask = FTD2XX.NotificationEvents.FT_EVENT_RXCHAR | FTD2XX.NotificationEvents.FT_EVENT_MODEM_STATUS;
try {
// Set the event notification
serialPort.SetEventNotification(hEvent.getPointer(), eventMask);
}
catch (FTD2XXException ex) {
LOGGER.warn("Set the event notification failed.", ex);
receiverRunning.set(false);
if (serialPort == null || serialPort.isOpen()) {
triggerClosePort();
}
}
while (receiverRunning.get()) {
try {
LOGGER.trace("Try to read data.");
libPThreadExt.pthread_mutex_lock(hEvent.eMutex.getPointer());
libPThreadExt.pthread_cond_wait(hEvent.eCondVar.getPointer(), hEvent.eMutex.getPointer());
if (FtdiSerialConnectorLinux.this.hEvent != null) {
libPThreadExt.pthread_mutex_unlock(hEvent.eMutex.getPointer());
}
// LOGGER.trace("After wait for read data");
int[] status = serialPort.getStatus();
if ((status[2]
& FTD2XX.NotificationEvents.FT_EVENT_MODEM_STATUS) == FTD2XX.NotificationEvents.FT_EVENT_MODEM_STATUS) {
LOGGER.info("Received modem or line status event: {}", status[2]);
final EnumSet deviceStatusSet = serialPort.getDeviceStatus();
if (deviceStatusSet.contains(DeviceStatus.CTS)) {
LOGGER.info(">>>> CTS is high.");
fireCtsChanged(true, false);
}
else {
LOGGER.info(">>>> CTS is low.");
fireCtsChanged(false, false);
}
if (deviceStatusSet.contains(DeviceStatus.DSR)) {
LOGGER.info(">>>> DSR is high.");
}
else {
LOGGER.info(">>>> DSR is low.");
}
}
int available = status[0];
int len = -1;
if (available > 0) {
len = serialPort.read(inputBuffer, 0, available);
LOGGER.trace("Read len: {}", len);
}
else {
LOGGER
.warn("Received no data, available: {}, status.rx: {}, status.event: {}", available,
status[0], status[2]);
}
if (len < 0 && status[2] == 0) {
// check if the port was closed.
boolean portClosed = !serialPort.isOpen();
LOGGER.info("Port closed: {}", portClosed);
if (portClosed) {
// say good-bye
LOGGER.info("The port is closed. Leave the receiver loop.");
receiverRunning.set(false);
continue;
}
}
if (len > 0) {
receive(inputBuffer, len);
}
}
catch (FTD2XXException ex) {
LOGGER.warn("Receive data failed with an exception!", ex);
receiverRunning.set(false);
if (serialPort == null || serialPort.isOpen()) {
triggerClosePort();
}
}
catch (NullPointerException ex) {
LOGGER.error("Receive data failed with an NPE! The port might be closed.", ex);
receiverRunning.set(false);
}
catch (Exception ex) {
LOGGER.error("Message receiver returned from receive with an exception!", ex);
}
}
closeHandle();
LOGGER.info("Leaving receiver loop.");
}
}
}