Fazecast / jSerialComm

Platform-independent serial port access for Java
GNU Lesser General Public License v3.0
1.35k stars 287 forks source link

Reset reception in event-driven callback mode #479

Closed Beta-Tester-AF closed 1 year ago

Beta-Tester-AF commented 1 year ago

I am using your library for master<->slave communication. Master sends a command, slave sends a response. Reception on the master side is done in event-driven byte-delimited message callback mode.

Before the master sends a command, he wants to reset the reception so that only bytes received from that moment on count as a response. How can I do this?

See the code below which illustrates this. It is intended to run in loopback mode, i.e. by connecting the Rx and Tx lines together so that the same PC simulates master and slave.

Desired output: Rx: [4, 5, 6, 127] Actual output: Rx: [1, 2, 3, 4, 5, 6, 127]

NOTE: I found a "solution" to add the SerialPortMessageListener before sending each command and remove it after receiving a response (or after a timeout if no response). The drawback is that calling comPort.removeDataListener() takes 500ms which reduces the throughput unacceptably.

public class Test {

    private static final byte TERMINATOR = 0x7F;
    private SerialPort comPort = null;

    public static void main(String[] args) throws Exception {
        Test test = new Test();
        test.init();

        // Simulate some bytes sent to master earlier, e.g. by mistake:
        test.comPort.writeBytes(new byte[]{0x01, 0x02, 0x03}, 3);

        // Master wants to start a fresh reception, dropping all the bytes he
        // might have received before. What to do?
        test.comPort.flushIOBuffers​(); // no effect!

        // Master would send a command here; we don't do it in loopback mode.

        // Simulate the arrival of slave's response:
        test.comPort.writeBytes(new byte[]{0x04, 0x05, 0x06, TERMINATOR}, 4);

        Thread.sleep(1000);
        test.close();
    }

    private void init() {
        SerialPort[] comPorts = SerialPort.getCommPorts();
        comPort = comPorts[0];
        comPort.openPort();
        comPort.addDataListener(new SerialPortMessageListener() {
            @Override
            public int getListeningEvents() {
                return SerialPort.LISTENING_EVENT_DATA_RECEIVED;
            }

            @Override
            public byte[] getMessageDelimiter() {
                return new byte[]{TERMINATOR};
            }

            @Override
            public boolean delimiterIndicatesEndOfMessage() {
                return true;
            }

            @Override
            public void serialEvent(SerialPortEvent event) {
                System.out.println("Rx: " + Arrays.toString(event.getReceivedData()));
            }
        });
    }

    private void close() {
        if (comPort != null) {
            comPort.removeDataListener();
            comPort.closePort();
        }
    }

}
hedgecrw commented 1 year ago

Hi there! If you are still monitoring this thread, could you please test the following beta JAR version of this library:

https://www.dropbox.com/t/nUibOse3aweB1ZOw

I've implemented a new method, flushDataListener() which you should be able to call to delete any received data in an event/data listener prior to it being passed to the user callback. Thanks!

hedgecrw commented 1 year ago

This was fully implemented in the latest release of v2.10.1. Thanks!