multithreadingjavafxjssc

JavaFX+JSSC(Java Simple Serial Connector) thread communication


I am working on a barcode scanning project. I use a barcode scanner to scan barcodes and the scanner communicates with my laptop via bluetooth. The bluetooth connection is emulated as the serial port communication.

I have developed a Java desktop application to retrieve the barcodes scanned and display them. I use Javafx for UI and the open source library JSSC(Java Simple Serial Connector) to listen to the serial port and retrieve the barcodes scanned. However, when a JSSC serialPort is added/started, a new thread is created. This new thread listens to the serial port and retrieves the barcodes scanned. What I want is to display the scanned barcodes on Javafx UI, which the barcodes retrieved in the JSSC listener thread have to be sent back to the parent Javafx application thread.

I explored the javafx.concurrent Package but found that JSSC wraps the thread creation into its own class and I don’t have control over it. Could someone suggest a solution for it? Here is my code snippet to start the JSSC listener within Javafx controller. Basically, how can I set buffer back to the FXML label variable barcode?

Really appreciate it in advance!

public class BarcodeScanningController {
    @FXML
    private Label barcode;

    private static SerialPort serialPort;

    @FXML
    void initialize() {
        serialPort = new SerialPort("COM5");
        try {
            if (serialPort!=null && serialPort.isOpened ()) {
                serialPort.closePort();
            }
            serialPort.openPort();

            serialPort.setParams(SerialPort.BAUDRATE_9600,
                SerialPort.DATABITS_8,
                SerialPort.STOPBITS_1,
                SerialPort.PARITY_NONE);
            int mask = SerialPort.MASK_RXCHAR + SerialPort.MASK_CTS + SerialPort.MASK_DSR;//Prepare mask
            serialPort.setEventsMask(mask);//Set mask
            serialPort.setFlowControlMode(SerialPort.FLOWCONTROL_RTSCTS_IN |
                SerialPort.FLOWCONTROL_RTSCTS_OUT);

            serialPort.addEventListener(new PortReader(),SerialPort.MASK_RXCHAR);
        } catch (SerialPortException ex) {
            System.out.println(ex);
        }
    }

    private class PortReader implements SerialPortEventListener {
        private String buffer;

        @Override
        public void serialEvent(SerialPortEvent event) {
            if(event.isRXCHAR()){
                try {
                    buffer = serialPort.readString();
                    System.out.println(buffer);
                } catch (SerialPortException ex) {
                    System.out.println(ex);
                }
        }
    }
}

Solution

  • Add a Consumer<String> to your PortReader class:

    private class PortReader implements SerialPortEventListener {
        private final Consumer<String> textHandler ;
    
        PortReader(Consumer<String> textHandler) {
            this.textHandler = textHandler ;
        }
    
        @Override
        public void serialEvent(SerialPortEvent event) {
            if(event.isRXCHAR()){
                try {
                    String buffer = serialPort.readString();
                    textHandler.accept(buffer);
                } catch (SerialPortException ex) {
                    System.out.println(ex);
                }
        }
    }
    

    And then just replace

    serialPort.addEventListener(new PortReader(),SerialPort.MASK_RXCHAR);
    

    with

    serialPort.addEventListener(
        new PortReader(buffer -> Platform.runLater(() -> barCode.setText(buffer))),
        SerialPort.MASK_RXCHAR);