javaserial-portxbeejssc

Merge XBee api fragments from serial port


I try to merge the fragments of a packet I receive by my Xbee (802.15.4) in API mode througth my RS-232 serial port. I get my fragment with the readBytes method from the jssc library for java.

Here is my reception code

    private static class PortReader implements SerialPortEventListener {

    @Override
    public void serialEvent(SerialPortEvent event) {
        if(event.isRXCHAR() && event.getEventValue() > 0) {
            try {
                byte[] receivedData = serialPort.readBytes(event.getEventValue());
                if(Utils.isConfirmPacket(Utils.toHex(receivedData))){
                    System.out.println("XBee confim that msg is sent!");
                }else{
                    System.out.println("Received response from port: " + Utils.toHex(receivedData));
                    int dataLength = Utils.toHex(receivedData).length();
                    receiveFile("testRx", receivedData, dataLength);
                }

            }
            catch (SerialPortException ex) {
                System.out.println("Error in receiving response from port: " + ex);
            }
        }
    }

My receiveFile() method need the full packet in one fragment. Here is what I get in my console:

Received response from port: 7e003c8100013200
Received response from port: 2000123200ff1200
Received response from port: 0001000500000000
Received response from port: 0000000020000000
Received response from port: 1251000012455222
Received response from port: 446174613a206365
Received response from port: 6369206573742075
Received response from port: 6e20746573743b90

Since I'm using the API mode, I have not been able to send an end delimiter to specified the end of the packet like I saw in other solutions (Read Complete Line Java Serial Port).

I was thinking of using the start delimiter of the next packet, but it didn't worked out.


Solution

  • I figured it out using the length of the api packet. Since the length is at the position [1] and [2] of the first array, I can use this value to keep building my packet as I receive data. When my msgLengthLeft value is at 0, I know the packet have all been received and I can return the full packet. Here is my code:

    private static class PortReader implements SerialPortEventListener {
        private short msgLength;
        private short msgLengthLeft;
        private byte[] receivedMsg = new byte[packetSize];
        ByteArrayOutputStream outputStream = new ByteArrayOutputStream( );
    
        @Override
        public void serialEvent(SerialPortEvent event) {
            if(event.isRXCHAR() && event.getEventValue() > 0) {
                try {
                    byte[] receivedData = serialPort.readBytes(event.getEventValue());
                    if(Utils.isConfirmPacket(Utils.toHex(receivedData))){
                        System.out.println("XBee confim that msg is sent!");
                    }else{
                        if(receivedData[0] == 0x7e){    //0x7e is the start delimiter of a frame
                            ByteBuffer wrapped = ByteBuffer.wrap(receivedData,1,2); // big-endian by default
                            msgLength = (short) (wrapped.getShort()+4); //Need to add 4 to the value becaus some field are not include in the length field of the api packet
                            msgLengthLeft = (short) (msgLength - receivedData.length);
                            outputStream.write(receivedData);  
                            return;
                        }else{
                            msgLengthLeft = (short) (msgLengthLeft - receivedData.length);
                            outputStream.write(receivedData); 
                            if(msgLengthLeft != 0){
                                return;
                            }
                        }
                        System.out.println("Received response from port: " + Utils.toHex(outputStream.toByteArray( )));
                        int dataLength = Utils.toHex(receivedMsg).length();
                        //receiveFile("testRx", receivedData, dataLength);
                    }
    
                }
                catch (SerialPortException | IOException ex) {
                    System.out.println("Error in receiving response from port: " + ex);
                }
            }
        }
    }