【问题标题】:Java jssc read from multiple COM ports, simultaneously, write all data out on one portJava jssc 从多个 COM 端口读取,同时在一个端口上写出所有数据
【发布时间】:2020-11-28 23:43:54
【问题描述】:

我有几个 COM 端口每 1-2 秒传输一次数据。每个设备的每一行都以 $ 开头,以 CR 和 LF 结尾。每行的长度不同,不超过 82 个字节。

我正在尝试将四个 4800 波特输入和一个 34800 波特输入组合成一条 192k 波特的输出线。

你可以在这里看到我的代码:https://github.com/ian5142/nema0183_aggregator

https://github.com/ian5142/nema0183_aggregator/find/master

  • NEMA_aggregator 是主要的
  • RS232Control 包含所有 JSSC 内容。
  • 在发送 GPS 数据时,RS232Control 调用 NEMADateUpdate。更改其中一行中的日期。工作正常。

main中的相关代码:

RS232Control gps = new RS232Control("COM32", 4800, true);
        while (true) {
            String line = gps.testRead2();
            sentences.add(line);
            gps.changePort("COM41", 115200, false);
            gps.testWrite(line);
            
            try {
                Thread.sleep(500);
            } catch (InterruptedException ex) {
                Logger.getLogger(Nema0183_aggregator.class.getName()).log(Level.SEVERE, null, ex);
            }
            for (int i = 0 ; (i < 8) && (!line.startsWith("$GPGLL")) ; i++ ) {
                gps.changePort("COM32", 4800, true);
                line = gps.testRead2();
                sentences.add(line);
                gps.changePort("COM41", 115200, false);
                gps.testWrite(line);

                try {
                    Thread.sleep(500);
                } catch (InterruptedException ex) {
                    Logger.getLogger(Nema0183_aggregator.class.getName()).log(Level.SEVERE, null, ex);
                }
            }
            gps.changePort("COM39", 4800, false);
            line = gps.testRead2();
            sentences.add(line);
            gps.changePort("COM41", 115200, false);
            gps.testWrite(line);
            
            gps.changePort("COM32", 4800, true);
            try {
                Thread.sleep(500);
            } catch (InterruptedException ex) {
                Logger.getLogger(Nema0183_aggregator.class.getName()).log(Level.SEVERE, null, ex);
            }
        }

那么RS232Control就在这里:

import java.util.ArrayList;
import java.util.Scanner;
import java.util.logging.Level;
import java.util.logging.Logger;
import jssc.*; // Java Simple Serial Connector, the library that contains the serial methods
import static nema0183_aggregator.RS232Control.serialPort;

/**
 *
 * @author Ian Van Schaick
 */
public class RS232Control {

    static SerialPort serialPort;
    String portName;
    static long portOpen;
    StringBuilder message;
    Boolean receivingMessage;
    SerialPortReader reader;
    String readLine;
    Boolean acknowledge;
    int baud;
    boolean gpsData;
    NEMADateUpdate gpsUpdate;
    String lineSep;

    /**
     * 
     * @param portNum
     * @param portbaud
     * @param gps 
     */
    public RS232Control(String portNum, int portbaud, boolean gps) {
        gpsData = gps;
        if (gpsData == true) {
            gpsUpdate = new NEMADateUpdate ();
        }
        portName = portNum;
        baud = portbaud;
        serialPort = new SerialPort(portName);
        message = new StringBuilder();
        receivingMessage = false;
        reader = new SerialPortReader();
        readLine = "";
        acknowledge = false;
        lineSep = System.getProperty("line.separator");
        openP();
    }

 protected void changePort (String portNum, int portbaud, boolean gps) {
        close();
        gpsData = gps;
        if (gpsData == true) {
            gpsUpdate = new NEMADateUpdate ();
        }
        portName = portNum;
        baud = portbaud;
        serialPort = new SerialPort(portName);
        message = new StringBuilder();
        receivingMessage = false;
        reader = new SerialPortReader();
        readLine = "";
        acknowledge = false;
        lineSep = System.getProperty("line.separator");
        openP();
    }
    
    /**
     * Opens a COM port at the specified settings (baudrate 8N1)
     * Can throw an error opening the port
     */
    private void openP() {
        try {
            serialPort.openPort();
            serialPort.setParams(baud,
                    SerialPort.DATABITS_8,
                    SerialPort.STOPBITS_1,
                    SerialPort.PARITY_NONE);

            serialPort.setFlowControlMode(SerialPort.FLOWCONTROL_NONE);
            int mask = SerialPort.MASK_RXCHAR;
            serialPort.setEventsMask(mask);
            serialPort.addEventListener(reader);
            serialPort.setRTS(false);
            serialPort.setDTR(false);
            acknowledge = true;
        } catch (SerialPortException ex) {
            Logger.getLogger(RS232Control.class.getName()).log(Level.SEVERE, null, ex);
            System.out.println("There is an error opening port т: " + ex);
        }
    }
    
    /**
     * Closes the serial port, can throw a SerialPortException error.
     *
     * @return
     */
    private boolean close() {
        boolean success = false;
        try {
            serialPort.closePort();
            success = true;
        } catch (SerialPortException ex) {
            Logger.getLogger(RS232Control.class.getName()).log(Level.SEVERE, null, ex);
        }
        return success;
    }
/**
     * Opens the serial port. Tries to read a string from the serial port.
     * Closes the serial port.
     *
     * @return Returns the byte array read from the serial port.
     */
    protected String testRead2() {
        String line = "";
        ArrayList <String> readList = new ArrayList <String> ();
        boolean lineFin = false;
        for (int i = 0; i < 100 && (!lineFin); i++) {
            try {
                line =  line + serialPort.readString(1);
            } catch (SerialPortException ex) {
                Logger.getLogger(RS232Control.class.getName()).log(Level.SEVERE, null, ex);
            }
            if (line.endsWith(lineSep)) {
                lineFin = true;
            }
        if (gpsData == true) {
            line = gpsUpdate.dateUpdate(line);
        }
    }
        return line;
    }
    
    /**
     * Writes the String message to the serial port
     *
     * @param message The string to write to the serial port
     * @return Returns true if the write was successful
     */
    protected boolean testWrite(String message) {
        boolean success = false;
        
        try {
            if ( (!message.isBlank() ) && message.startsWith("$") ) {
                success = serialPort.writeString(message);
            }
        } catch (SerialPortException ex) {
            Logger.getLogger(RS232Control.class.getName()).log(Level.SEVERE, null, ex);
        }
        return success;
    }
}

/**
 * In this class must implement the method serialEvent, through it we learn
 * about events that happened to our port. But we will not report on all events
 * but only those that we put in the mask. In this case the arrival of the data
 * and change the status lines CTS and DSR
 */
class SerialPortReader implements SerialPortEventListener {

    /**
     * Reads the data bit by bit from the serial port Can throw a
     * SerialPortException error
     *
     * @param event
     */
    @Override
    public void serialEvent(SerialPortEvent event) {
        if (event.isRXCHAR() && event.getEventValue() == 10) {
            try {
                byte buffer[] = serialPort.readBytes(10);
            } catch (SerialPortException ex) {
                System.out.println("Error in receiving string from COM-port: " + ex);
            }
        }
    }
    
    /**
     * Prints out the message read from the serial port
     *
     * @param message
     */
    protected void processMessage(String message) {
//        System.out.println(message);
    }
}

我尝试使用 for / while 循环遍历 COM 端口,但这意味着我错过了来自其他端口的传入数据。

关于如何做到这一点的任何想法?

【问题讨论】:

  • 嗨 ian5142!请在此处发布代码,而不是作为存储库的链接。它可以帮助尝试回答的人,以及一旦您提交答案,您的问题将不再有意义。使用反引号来格式化代码。请参阅编辑屏幕上的help 按钮。
  • @loa_in_ 我已经在上面添加了相关代码。谢谢。

标签: java jssc


【解决方案1】:

我建议使用全局列表变量来标识每个 COM 端口,可能使用一个类来创建两个成员:一个布尔值表示从 COM 端口读取数据时,另一个布尔值表示该 COM 端口的数据已经被当您在 while 循环中迭代它们时由您检查。如果它们都在不同的线程上,那么它们都可以同时接收数据,并且 while 循环将继续遍历所有 COM 端口,直到它们都将它们的 alreadyChecked(数据已经接收并发送到主端口)布尔值设置为 true。这可以通过在 while 循环中执行 for 循环来计算有多少类实例仍然存在已经检查布尔值到 false 我希望这会有所帮助。

【讨论】:

    【解决方案2】:

    听起来像条码扫描。但这并不重要。

    为每个端口保留单独的 RS232Control 实例。反复轮询它们,并将任何数据放入队列中。

    在另一个线程中从队列中取出,合并并转发。

    有时多线程解决方案更容易。值得您花时间。

    【讨论】:

      猜你喜欢
      • 2016-05-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多