QDataStream прошу помощи



  • Добрый день!
    Получаю данные из последовательного порта через QSerialPort, данные как и в примерах складываются в QByteArray, далее необходимо парсить эти данные и вот тут я натыкаюсь на грабли. Данные представляют собой последовательность CV (Current Value) и далее 3 32х битных числа, таким образом посылка представляет собой последовательность из 14 байт. Разбираю вот так:

    void Pribor::Read_Data_in_Port()
    {
        const QByteArray data = Port->readAll();
        if ( data.at(0) == 'C' && data.at(1) == 'V' )
        {
        QDataStream ds( data );
        int32_t  A,B,C ;
        QChar Char_1, Char_2;
        ds >> Char_1 >> Char_2 >> A >> B >> C;
        ui->Lab_Ch_A->setText( "Значение A: " + QString::number(A) );
        if ( A == 0 ) ui->Lab_Ch_A->setText("Значение A: Нет сигнала");
    
        ui->Lab_Ch_B->setText( "Значение B: " + QString::number(B) );
        if ( B == 0 ) ui->Lab_Ch_B->setText("Значение B: Нет сигнала");
    
        ui->Lab_Ch_C->setText( "Значение C: " + QString::number(C) );
        if ( C == 0 ) ui->Lab_Ch_C->setText("Значение C: Нет сигнала");
        }
    }
    

    На выходи имею нули, т.е. нет сигнала, а сигнал то есть, если делаю вот так:

    void Pribor::Read_Data_in_Port()
    {
        const QByteArray data = Port->readAll();
        if ( data.at(0) == 'C' && data.at(1) == 'V' )
        {
    
        int32_t  A,B,C ;
        QByteArray Arr1;
    	 
    	 Arr1[0] = data[2];
    	 Arr1[1] = data[3];
    	 Arr1[2] = data[4];
    	 Arr1[3] = data[5];
    	 Arr1[4] = data[6];
    	 Arr1[5] = data[7];
    	 Arr1[6] = data[8];
    	 Arr1[7] = data[9];
    	 Arr1[8] = data[10];
    	 Arr1[9] = data[11];
    	 Arr1[10] = data[12];
    	 Arr1[11] = data[13];
         
    	QDataStream ds (Arr1);	
    	ds >> A >> B >> C;
    	ui->Lab_Ch_A->setText( "Значение A: " + QString::number(A) );
    	if ( A == 0 ) ui->Lab_Ch_A->setText("Значение A: Нет сигнала");
    
    
    	ui->Lab_Ch_B->setText( "Значение B: " + QString::number(B) );
    	if ( B == 0 ) ui->Lab_Ch_B->setText("Значение B: Нет сигнала");
    
    	ui->Lab_Ch_C->setText( "Значение C: " + QString::number(C) );
    	if ( C == 0 ) ui->Lab_Ch_C->setText("Значение C: Нет сигнала");
        }
    }
    

    То все отлично, но это как то неправильно. Прошу подсказать почему QDataStream не распознает символы, пытался сначала распознать 2 символа как строку, результат так же плачевный.



  • Насколько я понимаю, здесь входные данные не были сформированы с помощью QDataStream. QDataStream нельзя использовать для парсинга произвольных бинарных данных, это формат сериализации со своим заголовком и метаданными



  • Да, данные шлет контроллер STM32 из состава устройства. Контроллер формирует данные следующим образом:

    USB_TX_Buff[0] = 'C';
    USB_TX_Buff[1] = 'V';
    
    USB_TX_Buff[2] = ( Value1 >> 24 ) & 0xFF;
    USB_TX_Buff[3] = ( Value1 >> 16 ) & 0xFF;
    USB_TX_Buff[4] = ( Value1 >> 8 ) & 0xFF;
    USB_TX_Buff[5] = Value1 & 0xFF;
    
    USB_TX_Buff[6] = ( Value2 >> 24 ) & 0xFF;
    USB_TX_Buff[7] = ( Value2 >> 16 ) & 0xFF;
    USB_TX_Buff[8] = ( Value2 >> 8 ) & 0xFF;
    USB_TX_Buff[9] = Value2 & 0xFF;
    
    USB_TX_Buff[10] = ( Value3 >> 24 ) & 0xFF;
    USB_TX_Buff[11] = ( Value3 >> 16 ) & 0xFF;
    USB_TX_Buff[12] = ( Value3 >> 8 ) & 0xFF;
    USB_TX_Buff[13] = Value3 & 0xFF;
    
    CDC_Transmit_FS (USB_TX_Buff, 14) ;
    

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

    void Pribor::Read_Data_in_Port()
    {
        const QByteArray data = Port->readAll();
    
        if ( data.at(0) == 'C' && data.at(1) == 'V' )
        {
    
    		int32_t Number;
    		Number = data[2];
    		Number = Number << 8;
    		Number = Number + data[3];
    		Number = Number << 8;
    		Number = Number + data[4];
    		Number = Number << 8;
    		Number = Number + data[5];
    
    		ui->Lab_Ch_A->setText( "Значение A: " + QString::number(Number) );
    		if ( Number == 0 ) ui->Lab_Ch_A->setText("Значение A: Нет сигнала");
    
    		Number = data[6];
    		Number = Number << 8;
    		Number = Number + data [7];
    		Number = Number << 8;
    		Number = Number + data [8];
    		Number = Number << 8;
    		Number = Number + data [9];
    		ui->Lab_Ch_B->setText( "Значение B: " + QString::number(Number) );
    		if ( Number == 0 ) ui->Lab_Ch_B->setText("Значение B: Нет сигнала");
    
    		Number = data[10];
    		Number = Number << 8;
    		Number = Number + data [11];
    		Number = Number << 8;
    		Number = Number + data [12];
    		Number = Number << 8;
    		Number = Number + data [13];
    
    		ui->Lab_Ch_C->setText( "Значение C: " + QString::number(Number) );
    		if ( Number == 0 ) ui->Lab_Ch_C->setText("Значение C: Нет сигнала");
        }
    }
    

    Вот тут то напутать вроде бы нечего... Но данные выводились то правильно то с ошибками, и ошибки как то близки к 255, но не понятно из-за чего возникают...
    Когда прибор снимает показания 850 попугаев и на компьютере 850 попугаев, когда прибор снимает 1000 попугаев на компьютере 750 попугаев, когда прибор снимает 1100 попугаев на компьютере снова 1100 и снова все в порядке.
    Из-за этого и стал копать в сторону QDataStream.



  • @Konstantin-Tokarev said in QDataStream прошу помощи:

    QDataStream нельзя использовать для парсинга произвольных бинарных данных

    Не, ну для простых типов (int, double и пр.) или raw данных то можно.



  • @kuzulis said in QDataStream прошу помощи:

    Не, ну для простых типов (int, double и пр.) или raw данных то можно.

    Вот тут то и вопрос как мне правильно отпарсить первые два символа, так как копировать один QByteArray в другой это по моему не правильно.

    Возможно вопросы глупые, признаюсь только начинаю все это дело изучать )))



  • @kuzulis said in QDataStream прошу помощи:

    @Konstantin-Tokarev said in QDataStream прошу помощи:

    QDataStream нельзя использовать для парсинга произвольных бинарных данных

    Не, ну для простых типов (int, double и пр.) или raw данных то можно.

    Но зачем так извращаться, когда можно использовать QByteArray::fromRawData и конвертировать в нужный тип? Только не забыть endian учесть



  • @Konstantin-Tokarev said in QDataStream прошу помощи:

    Но зачем так извращаться, когда можно использовать QByteArray::fromRawData и конвертировать в нужный тип? Только не забыть endian учесть

    Изврат - это использовать QByteArray::fromRawData(), ИМХО. C QDataStream это проще.

    Вот тут то и вопрос как мне правильно отпарсить первые два символа, так как копировать один QByteArray в другой это по моему не правильно.

    Foo::onReadyRead()
    {
        for (;;) {
            const auto bytesAvailable = m_serial->bytesAvailable();
            if (bytesAvailable < 14)
                return;
            // Synchronizing... Lookup for 'CV' sequence.
            char c = 0;
            if (!m_serial->getChar(&c))
                continue;
            if (c != 'C')
                continue;
            if (!m_serial->getChar(&c))
                continue;
            if (c != 'V')
                continue;
    
            // 'CV' sequence where received, now we can read data.
            QDadaStream in(m_serial);
            quint32 value1 = 0;
            quint32 value2 = 0;
            quint32 value3 = 0;
            in >> value1 >> value2 >> value3;
    
            // Values where received... Handle values...
        }
    }
    


  • @kuzulis QDataStream вообще не для того предназначен, это формат сериализации



  • Для удобного чтения бинарных данных можно использовать, например, std::stringstream



  • Решил проблему с "лишними символами" удалением их из QByteArray, после чего передаю его в QDataStream и все отлично парсится без лишних массивов

    void Pribor::Read_Data_in_Port()
    {
        QByteArray data = Port->readAll();
        
        if ( data.at(0) == 'C' && data.at(1) == 'V' )
        {
    
        int32_t  A,B,C ;
        
        data.remove(0,2);
    		
        QDataStream ds (data);	
    		
        ds >> A >> B >> C;
    		
        ui->Lab_Ch_A->setText( "Значение A: " + QString::number(A) );
        if ( A == 0 ) ui->Lab_Ch_A->setText("Значение A: Нет сигнала");
    
        ui->Lab_Ch_B->setText( "Значение B: " + QString::number(B) );
        if ( B == 0 ) ui->Lab_Ch_B->setText("Значение B: Нет сигнала");
    
        ui->Lab_Ch_C->setText( "Значение C: " + QString::number(C) );
        if ( C == 0 ) ui->Lab_Ch_C->setText("Значение C: Нет сигнала");
        }
    }
    

    Прошу комментариев/критики, чем грозит перевод данного QByteArray из const ?



  • Ничем не грозит, const вообще был лишним в оригинале



  • А вот использование QDataStream грозит проблемами в будущем, особенно если не зафиксировать версию формата и endianness



  • А вот использование QDataStream грозит проблемами в будущем, особенно если не зафиксировать версию формата и endianness

    Вот тут я поспорю, т.к. версия формата тут ни к месту (еще раз повторюсь - простые типы сериализуются без всяких "выкрутасов", как есть), и я не понимаю, причем тут endianless вообще (даже лучше что оно есть)?

    Решил проблему с "лишними символами" удалением их из QByteArray,

    Ты неправильно читаешь из порта.. как правильно я тебе выложил код выше.



  • еще раз повторюсь - простые типы сериализуются без всяких "выкрутасов", как есть

    Нет никаких гарантий, что в следующих версиях формата это не изменится, или вообще внутри не будет какой-нибудь CBOR

    я не понимаю, причем тут endianless вообще

    Тогда о чем с вами дальше говорить



  • @kuzulis said in QDataStream прошу помощи:

    Ты неправильно читаешь из порта.. как правильно я тебе выложил код выше.

    Прошу пояснить почему не правильно читаю? Это конструкция взята из примеров QSerialPort. Вот отсюда https://doc.qt.io/qt-5/qtserialport-terminal-example.html



  • @VasiliyVN said in QDataStream прошу помощи:

    Прошу пояснить почему не правильно читаю?

    Port->readAll();

    Даю подсказку: что readAll() по твоему мнению должен делать? и что значит all, это сколько? и зачем вообще вычитывать в QByteArray?

    ЗЫ: Я не хочу каждый раз (снова и снова) разжевывать очевидные вещи (я устал)... Дальше уже разбирайся сам.



  • @kuzulis said in QDataStream прошу помощи:

    Прошу пояснить почему не правильно читаю?

    Port->readAll();

    Даю подсказку: что readAll() по твоему мнению должен делать? и что значит all, это сколько? и зачем вообще вычитывать в QByteArray?
    ЗЫ: Я не хочу каждый раз (снова и снова) разжевывать очевидные вещи (я устал)... Дальше уже разбирайся сам.

    Ну тут как бы понятно, radAll это считать все что есть в буфере порта на момент когда пришел сигнал readyRead. И логично предположить, что этот QByteArray надо успеть отпарсить ну и среагировать до следующего прихода данных.



  • @VasiliyVN said in QDataStream прошу помощи:

    надо успеть отпарсить

    Не надо ничего успевать, т.к. QSP все данные буферизирует у себя.

    все что есть в буфере порта на момент когда пришел сигнал readyRead

    Ну а теперь посмотри на свой код, а если придет только один или два байта? Что у тебя случится тогда?



  • @kuzulis said in QDataStream прошу помощи:

    Ну а теперь посмотри на свой код, а если придет только один или два байта? Что у тебя случится тогда?

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

    Соответственно если придут 2 байта или 1 то вывалится программа с ошибкой, так как посылка будет принята а QBA такого индекса иметь не будет, понял, введу дополнительную проверку. Спасибо!


Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.