Как прочитать (все доступные) данные из последовательного соединения при использовании JSSC?

Я пытаюсь работать с JSSC. Я создал свое приложение по этой ссылке:

https://code.google.com/p/java-simple-serial-connector/wiki/jSSC_examples

Мой обработчик событий выглядит так:

static class SerialPortReader implements SerialPortEventListener {

        public void serialEvent(SerialPortEvent event) {
            if(event.isRXCHAR()){//If data is available                                
                    try {
                        byte buffer[] = serialPort.readBytes();
                    }
                    catch (SerialPortException ex) {
                        System.out.println(ex);
                    }
                }
            }

        }
    }

Проблема в том, что я всегда не получаю входящие данные одним куском. (У меня сообщение имеет длину 100 байт, я получаю 48 и 52 байта в 2 отдельных вызовах) - Другая сторона отправляет мне сообщения разной длины.
- В ICD, с которым я работаю, есть поле, которое сообщает нам длину сообщения. (от байта № 10 до байта № 13) - я не могу прочитать 14 байтов:

 (serialPort.readBytes(14);, 

проанализируйте длину сообщения и прочитайте остальную часть сообщения:

 (serialPort.readBytes(messageLength-14);

Но если я это сделаю, у меня не будет сообщения одним куском (у меня будет 2 отдельных byte[] и мне нужно его одним куском (byte[]) без работы функции копирования.

  1. Является ли это возможным ?

При работе с Ethernet (SocketChannel) мы можем читать данные с помощью ByteBuffer. Но с JSSC мы не можем.

  1. Есть ли хорошая альтернатива JSSC?

Спасибо


person user3668129    schedule 11.01.2015    source источник
comment
Вы не можете рассчитывать на получение полных данных за один раз, этого, скорее всего, никогда не произойдет. Если ваше сообщение всегда состоит из 100 байтов, вам нужно только сохранять поступающие данные внутри переменной и активировать свой бизнес-код, как только вы получите 100 байтов, и сбросить переменную. Если у вас есть определенный SOH или конечный персонаж, вы можете активировать его соответствующим образом.   -  person Alexandre Lavoie    schedule 11.01.2015
comment
Как я могу зарегистрироваться на событие конечных символов?   -  person user3668129    schedule 11.01.2015


Ответы (3)


Вы не можете полагаться на какую-либо библиотеку, которая предоставит вам все необходимое содержимое сразу, потому что:

  • библиотека не знает, сколько данных вам нужно
  • библиотека предоставит вам данные по мере их поступления, а также в зависимости от буферов, оборудования и т. д.

Вы должны разработать собственную бизнес-логику для обработки приема пакетов. Конечно, это будет зависеть от того, как определены ваши пакеты: всегда ли они одинаковой длины, разделены ли они одним и тем же конечным символом и т. д.

Вот пример, который должен работать с вашей системой (обратите внимание, что вы должны использовать это как начало, а не полное решение, например, оно не включает тайм-аут):

static class SerialPortReader implements SerialPortEventListener
{
    private int m_nReceptionPosition = 0;
    private boolean m_bReceptionActive = false;
    private byte[] m_aReceptionBuffer = new byte[2048];

    @Override
    public void serialEvent(SerialPortEvent p_oEvent)
    {
        byte[] aReceiveBuffer = new byte[2048];

        int nLength = 0;
        int nByte = 0;

        switch(p_oEvent.getEventType())
        {
            case SerialPortEvent.RXCHAR:
                try
                {
                    aReceiveBuffer = serialPort.readBytes();

                    for(nByte = 0;nByte < aReceiveBuffer.length;nByte++)
                    {
                        //System.out.print(String.format("%02X ",aReceiveBuffer[nByte]));

                        m_aReceptionBuffer[m_nReceptionPosition] = aReceiveBuffer[nByte];

                        // Buffer overflow protection
                        if(m_nReceptionPosition >= 2047)
                        {

                            // Reset for next packet
                            m_bReceptionActive = false;
                            m_nReceptionPosition = 0;
                        }
                        else if(m_bReceptionActive)
                        {
                            m_nReceptionPosition++;

                            // Receive at least the start of the packet including the length
                            if(m_nReceptionPosition >= 14)
                            {
                                nLength = (short)((short)m_aReceptionBuffer[10] & 0x000000FF);
                                nLength |= ((short)m_aReceptionBuffer[11] << 8) & 0x0000FF00;
                                nLength |= ((short)m_aReceptionBuffer[12] << 16) & 0x00FF0000;
                                nLength |= ((short)m_aReceptionBuffer[13] << 24) & 0xFF000000;

                                //nLength += ..; // Depending if the length in the packet include ALL bytes from the packet or only the content part

                                if(m_nReceptionPosition >= nLength)
                                {
                                    // You received at least all the content

                                    // Reset for next packet
                                    m_bReceptionActive = false;
                                    m_nReceptionPosition = 0;
                                }
                            }

                        }
                        // Start receiving only if this is a Start Of Header
                        else if(m_aReceptionBuffer[0] == '\0')
                        {
                            m_bReceptionActive = true;
                            m_nReceptionPosition = 1;
                        }
                    }
                }
                catch(Exception e)
                {
                    e.printStackTrace();
                }
                break;
            default:
                break;
        }
    }
}
person Alexandre Lavoie    schedule 12.01.2015

После записи данных в последовательный порт его необходимо сбросить. Проверьте синхронизацию и обратите внимание на тот факт, что чтение должно происходить только после того, как другой конец запишет. размер чтения - это просто указание на чтение системного вызова и не гарантируется. Данные могут быть получены и буферизованы в аппаратном буфере последовательного порта, но могут не быть переданы в буфер операционной системы, следовательно, не в приложение. Рассмотрите возможность использования библиотеки scm, она сбрасывает данные после каждой записи http://www.embeddedunveiled.com/.

person samuel05051980    schedule 01.04.2015

Попробуй это:

Запишите свои данные в последовательный порт (используя serialPort.writeBytes()), и если вы ожидаете ответа, используйте это:

    byte[] getData() throws SerialPortException, IOException {
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        byte[] b;

        try {
            while ((b = serialPort.readBytes(1, 100)) != null) {
                baos.write(b);
    //                System.out.println ("Wrote: " + b.length + " bytes");
                }
    //            System.out.println("Returning: " + Arrays.toString(baos.toByteArray()));
            } catch (SerialPortTimeoutException ex) {
                ;   //don't want to catch it, it just means there is no more data         to read
            }
            return baos.toByteArray();
        }

Делайте что хотите с возвращенным массивом байтов; в моем случае я просто показываю его для тестирования.

Я обнаружил, что он отлично работает, если вы читаете по одному байту за раз, используя тайм-аут 100 мс, а когда он истекает, вы читаете все данные в буфере.

Источник: попытка поговорить с последовательным принтером Epson с помощью jssc и ESC/POS.

person John    schedule 10.01.2019