繁体   English   中英

Java jssc 从多个 COM 端口读取,同时将所有数据写入一个端口

[英]Java jssc read from multiple COM ports, simultaneously, write all data out on one port

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

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

你可以在这里看到我的代码: 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 端口,但这意味着我错过了来自其他端口的传入数据。

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

I would suggest using a global list variable to indentify each COM port, probably with a class, to create two members: a boolean for when data is read from the COM port and another boolean for when that COM port's data has already been checked by you当您在 while 循环中迭代它们时。 如果它们都在不同的线程上,那么它们都可以同时接收数据,并且 while 循环将继续遍历所有 COM 端口,直到它们都将其已经检查(数据已接收并发送到主端口)布尔值设置为 true。 这可以通过在 while 循环中执行 for 循环来计算有多少 class 实例仍然存在已经检查 boolean 为 false 我希望这会有所帮助。

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

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

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

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM