JSSC - 断开连接会导致阻塞串行端口

时间:2017-06-05 12:40:08

标签: java serial-port jssc

我正在使用JSSC串行端口包在我的应用程序和连接到串行端口的设备之间交换数据。我做了一个简单的应用程序,它可以向设备发送识别信息并打印响应。我希望它能够抵抗连接错误(例如在通信过程中拔下电缆后)。

动作序列Init - >打开 - > IDN - >关闭效果很好。 当我打开端口后拔下电缆时,我无法发送消息(对我来说似乎合乎逻辑)并关闭端口(没有什么可以关闭了所以我也明白了)。

一开始我很惊讶我再次插上电缆后无法关闭端口,但我发现在每次连接设备后,操作系统给它一个不同的编号,JSSC库使用它来处理端口。幸运的是,事实证明只需在重新连接后打开端口即可解决所有问题,因为应用程序可以再次发送消息。

不幸的是,当端口打开时有更多尝试断开/连接电缆时,问题就开始了。每次尝试后,应用程序工作得越来越慢,以便在没有消息可以再发送的状态下结束。另一件事是,在那种状态下,所有串口(不仅是我尝试与之通信的串口)都被阻止,我甚至无法通过类似终端的应用程序访问它们。

所以问题是:

如何在不阻塞端口和降低性能的情况下使应用程序能够抵抗连接中断?

我想这可能是关于某种资源,内存管理等等,但我对这些事情的了解还不足以自己解决问题。

沟通的实施:

import jssc.SerialPort;
import jssc.SerialPortEvent;
import jssc.SerialPortEventListener;
import jssc.SerialPortException;

class Connection implements SerialPortEventListener {
  private static final int SERIAL_PORT_BAUD_RATE = 9600;
  private static final int SERIAL_PORT_DATA_BITS_NUMBER = 8;
  private static final int SERIAL_PORT_STOP_BITS_NUMBER = 1;
  private static final int SERIAL_PORT_PARITY = 0;

  private SerialPort serialPort;
  private String portName;

  public Connection(String portName) {
    this.portName = portName;
  }

  public void open() throws SerialPortException {
    serialPort = new SerialPort(portName);
    serialPort.openPort();
    serialPort.setParams(SERIAL_PORT_BAUD_RATE,
            SERIAL_PORT_DATA_BITS_NUMBER,
            SERIAL_PORT_STOP_BITS_NUMBER,
            SERIAL_PORT_PARITY);
    serialPort.addEventListener(this);
  }

  public void close() throws SerialPortException {
    if (serialPort != null) {
      serialPort.closePort();
    }
  }

  public void simpleMessage() throws SerialPortException {
    if (serialPort != null) {
      serialPort.writeString("IDN");
    }
  }

  @Override
  public void serialEvent(SerialPortEvent serialPortEvent) {
    if (serialPortEvent.getEventType() == SerialPortEvent.RXCHAR) {
      try {
        System.out.println(serialPort.readString());
      } catch (SerialPortException e) {
        System.out.println("Error while reading a string.");
      }
    }
  }
}

主要课程:

import javafx.application.Application;
import javafx.application.Platform;
import javafx.fxml.FXMLLoader;
import javafx.scene.Scene;
import javafx.scene.layout.Pane;
import javafx.stage.Stage;
import java.io.IOException;

public class MainApplication extends Application{
  public static void main(String [] args) {
    Application.launch();
  }

  @Override
  public void start(Stage primaryStage) throws Exception {
    Pane rootPane = null;
    FXMLLoader loader = new FXMLLoader();
    loader.setLocation(MainApplication.class.getResource("front.fxml"));

    try{
      rootPane = loader.load();
    } catch (IOException exception) {
      exception.printStackTrace();
    }

    Scene scene = new Scene(rootPane);
    primaryStage.setScene(scene);
    primaryStage.show();
    primaryStage.setOnCloseRequest(event -> {
      Platform.exit();
      System.exit(0);
    });
  }
}

FXML代码:

<?xml version="1.0" encoding="UTF-8"?>

<?import javafx.scene.layout.StackPane?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.layout.VBox?>

<StackPane fx:id="rootPane"
           xmlns="http://javafx.com/javafx/8.0.60"
           xmlns:fx="http://javafx.com/fxml/1"
           fx:controller="FrontController">
    <VBox>
        <Button text="Init" onAction="#init"/>
        <Button text="Open" onAction="#openPort"/>
        <Button text="Close" onAction="#closePort"/>
        <Button text="IDN" onAction="#idn"/>
        <Button text="Get Ports" onAction="#getPorts"/>
        <Button text="Is opened?" onAction="#isPortOpen"/>
    </VBox>
</StackPane>

控制器:

import javafx.fxml.FXML;
import jssc.SerialPortException;
import jssc.SerialPortList;
import java.util.Arrays;

public class FrontController {

  private Connection connection;

  @FXML
  private void init() {
    String portName = "COM4";
    connection = new Connection(portName);
  }

  @FXML
  private void openPort() {
    try {
      connection.open();
    } catch (SerialPortException e) {
      e.printStackTrace();
    }
  }

  @FXML
  private void closePort() {
    try {
      connection.close();
    } catch (SerialPortException e) {
      e.printStackTrace();
    }
  }

  @FXML
  private void idn() {
    try {
      connection.idnMessage();
    } catch (SerialPortException e) {
      e.printStackTrace();
    }
  }

  @FXML
  private void getPorts() {
    System.out.println(Arrays.toString(SerialPortList.getPortNames()));
  }

  @FXML
  private void isPortOpen() {
    System.out.println(connection.getSerialPort().isOpened());
  }
}

1 个答案:

答案 0 :(得分:0)

基本上拔出设备而不关闭(有时在Windows操作系统中大多数情况下)会使操作系统处于不一致状态。删除设备时需要清理。请注意,即使设备已被移除,关闭端口也非常重要。我们可能会留下关闭的返回值。这提示操作系统应用程序也对设备不感兴趣,因此操作系统可以释放我们也想要的资源。 因此,简而言之,我们需要创建一个线程来监视我们的设备是否连接到系统。