Arduino.Serial + Qt5: Сказ о том, как генералы пустой буфер получали

iCpu
iCpu аватар
Offline
Зарегистрирован: 12.02.2016

Нужно передавать на ардуинку дамп hex-файлов из компа. Желательно делать это быстро, решительно. Взял Мегу 2560. Наваял прожект на Qt, прицепил к Ардуинке, передаю куски по 16 байт (там же 64 байта в Serial кеш).  На деле же получается весьма плачевно: принимается каждая третья передача, при этом ещё и портится. Что я делаю не так?

void setup() {
  Serial.begin(115200);
}
 
long prog_size =0;
void loop() {
    ++prog_size;
    byte inbuffer[48] = {0};
    
    Serial.write((byte)1);
    while(!Serial.available());
      Serial.readBytes(inbuffer,1);
  
    memset(inbuffer,0,48);
    Serial.write(2);
    Serial.write((byte*)&prog_size,4);
    while(!Serial.available());
    Serial.readBytes(inbuffer,16);
    
    Serial.write(3);
    Serial.write((byte*)&prog_size,4);
    Serial.write(inbuffer,16);
}
void MainWindow::on_comboBox_currentIndexChanged(int index)
{
    if (index < 0)
        return;
    if (port)
        port->deleteLater();
    port = new QSerialPort(ui->comboBox->itemText(index));
    port->setBaudRate(QSerialPort::Baud115200);
    port->open(QIODevice::ReadWrite);
    connect(port,SIGNAL(readyRead()),SLOT(PortInput()));
}
 
void MainWindow::PortInput()
{
    quint8 command = (quint8)port->read(1).data()[0];
    qDebug() << "command" << command;
    if (command == 1)
    {
        port->write((char*)&(rom.prgPagesCount),1);
        qDebug() << "size" << rom.PagesCount;
    }
    if (command == 2)
    {
        quint32 offset = port->read(4).toUInt();
        QByteArray buffer = rom.Pages[offset/BANK_SIZE].mid(offset%BANK_SIZE,16);
        port->write(buffer.data(),buffer.size());
        qDebug() << "buffer" << buffer;
    }
    if (command == 3)
    {
        QByteArray buffer = port->read(4);
        qDebug() << "offset" << buffer;
        qDebug() << "buffer" << port->read(16);
    }
}
command 1
size 1
command 2
buffer "L\f\xE8\xA5h)\x02\xF0\x01`\xA2\x00\x86m\xB5`"
command 3
offset "\x01\x00\x00\x00"
buffer "\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
command 1
size 1
command 2
buffer "L\f\xE8\xA5h)\x02\xF0\x01`\xA2\x00\x86m\xB5`"
command 3
offset "\x02\x00\x00\x00"
buffer "\f\xE8\xA5h)\x02\xF0\x01`\xA2\x00\x86m\xB5`\x00"

 

Radjah
Offline
Зарегистрирован: 06.08.2014

Дык на момент чтения в буфере данные есть? Или читаешь абы читать?

Попробуй в настройках порта в скетче поставить два стоповых бита вместо одного.

iCpu
iCpu аватар
Offline
Зарегистрирован: 12.02.2016

Radjah пишет:

Дык на момент чтения в буфере данные есть? Или читаешь абы читать?

А разве там не стоит isAvailable?

Radjah пишет:

Попробуй в настройках порта в скетче поставить два стоповых бита вместо одного.

А можно глупый вопрос? А как? Точнее, где прочитать, какой из параметров config в Serial.begin(speed, config) что означает. ибо после документации Qt чтение таковой на СС оставило впечатление посещения "Зелёного слоника".

Radjah
Offline
Зарегистрирован: 06.08.2014

Во втором куске кода я ничего подобного не вижу, потому и спрашиваю.

SERIAL_8N2

Только для хардварного Serial.

8 бит данных

Без контроля четности

2 стоповых бита

Arduino\hardware\arduino\avr\cores\arduino\HardwareSerial.h

iCpu
iCpu аватар
Offline
Зарегистрирован: 12.02.2016

Нет, не в этом дело. Даже если это и изменило ситуацию к лучшему, уж точно не кардинально.

1) quint32 i = port->read(4).toUInt(); не отрабатывал, но quint32 i; memcpy(&i,port->read(4).data(),4); отрабатывает на ура. Сраная техномагия.

2) Помогает delay(20); Serial.flush(); после больших кусков данных. Такой мерзкий велосипед, аж во рту пересохло... А, не, это кальмары.

3) Никак не влияют паузы или, наоборот, ускорение работы с портом на стороне ПК. Мерзость! 

В целом, я заставил эту хрень работать. Но ощущения жутко негативные. Целиком. Я прекрасно понимаю, что я ничего не понимаю, но я даже не понимаю, что мне нужно понять для того, чтобы понимать то, что я сейчас не понимаю. Иными словами, у этой техномагии есть нормальный кодекс?

Radjah
Offline
Зарегистрирован: 06.08.2014

Или у тебя мусор посылается, или не всё вычитываешь из буфера.

iCpu
iCpu аватар
Offline
Зарегистрирован: 12.02.2016

Сложно не вычистить буфер, который создаёся на стеке и заполняется нулями. Проблема, видимо, была в том, что буфер порта переполнялся раньше окончания считывания. А может и нет. В душе не держу. Факт в том, что паузы после записи и очистка хардварного буфера помогает. ( А ведь flush прежде всего об этом, нэ?)

allesanbr
Offline
Зарегистрирован: 31.01.2016

Для начала сюда: https://www.arduino.cc/en/Serial/Read

Смысл написанного сводится к тому, что чтение происходит побайтово. То есть за один раз ты можешь передать только один байт. То есть: например число int от 0 до 255.
Для преодоления данного препятствия специально-обученные самизнаетекто(к коим отношусь и я) понаписали кучу всякого непотребства называемом "библиотеки" или "либы", не путать с "лыбой".

Посмотри вот это моё творение, библиотека для ардуино и для процессинга(Java) для обмена данными правда под кью-ти нет, варианта, но с небольшим допиливанием, должна подойти библиотека от собственно ардуино(потребуется исправить serial-функции приёма-передачи данных в сторону Qt).

Окунись в код, ознакомься с примерами: http://arduino.ru/forum/programmirovanie/arduino-rasshirennaya-peredacha...

iCpu
iCpu аватар
Offline
Зарегистрирован: 12.02.2016

allesanbr пишет:
Смысл написанного сводится к тому, что чтение происходит побайтово. То есть за один раз ты можешь передать только один байт. То есть: например число int от 0 до 255. Для преодоления данного препятствия специально-обученные самизнаетекто(к коим отношусь и я) понаписали кучу всякого непотребства называемом "библиотеки" или "либы", не путать с "лыбой". Посмотри вот это моё творение, библиотека для ардуино и для процессинга(Java) для обмена данными правда под кью-ти нет, варианта, но с небольшим допиливанием, должна подойти библиотека от собственно ардуино(потребуется исправить serial-функции приёма-передачи данных в сторону Qt).

Для начала позвольте вас отблагодарить, капитан, ваши услуги незаменимы!

Затем - сюда: https://www.arduino.cc/en/Serial/ReadBytes Смысл написанного сводится к тому, что Serial может в передачу-приём блоков данных. А любая книжка по Си скажет, что с точки зрения процессора все эти ваши инты - просто 2 WORD или 4 BYTE, которые можно скормить в сыром виде в memcpy. Более того, available передаёт размер уже прибывшего буфера, и мы можем сидеть и ждать данные для чтения. Так что проблема была не в этом. (Кстати, ваша библиотека была бы куда умнее, если бы могла паковать 10-битные значения с использованием сдвигов. И если бы использовала 2^n размеры полей, а не 10^m, потомучто)

Далее - окунаемся сюда https://ru.wikipedia.org/wiki/RS-232 И узнаём, что у последовательных портов есть уйма параметров передачи: скорость потока, число бит данных, стоповые биты, проверка чётности и тп. А так же банальная разница скоростей ардуины и ПК, ведь первая могла не успеть переварить все данные, а второй - отреагировать. Именно в этом разделе у меня и был вопрос, как их настроить и на какой скорости.

Следующий пункт - Qt. Учитывая то, что QSerialPort - сторонняя шлюпка, прибитая к гиганту волнами, есть все причины полагать, что в нём есть баги или, как минимум, недосказанности в документации, о которых мне могли бы рассказать опытные товарисчи.

Очень позабавил ваш PR вашего, кхм, творения. Я не претендую на звание "Программист года" даже в той фирме, на которую работаю, но даже мне с ходу видны... как бы это помягче... Неподготовленность вашей библиотеки к внешнему миру. Вы больше не отца, а сутенёра напоминаете, который лолитками торгует. Такого, знаете, классического американского, всего в золоте, шубах и дешёвых понтах. Для начала ознакомьтесь с нормальным тоном разметки, где public:, к примеру, будет стоять на один уровень раньше методов и полей. Это САМОЕ базовое замечание, а их больше, чем байт в ваших исходниках. Ну и вообще, странно, человек на Qt пишет, а ему processing подкладывают. 

Так, что-то меня понесло. Ах, это мои рабы. Успеть бы жмакнуть "Сохранить", пока рука дотягивается.

allesanbr
Offline
Зарегистрирован: 31.01.2016

Для реализации того, что Вы здесь нагородили, об умности библиотеки, и возможностях RS232 следует отказаться от библиотеки serial и использовать свою собственную.
я же предложил лишь надстройку над serial, чтобы не лепить собственные костыли. От ардуино бОльших возможностей и не требуется.

Вам шашечки или ехать?

Что же касается вашего бахвальства про программирование на Qt, то во первых: я "подкладывал" не Processing а исходники библиотеки от Arduino ибо Processing это джава, и я по рассеяности не положил исходник библиотеки в архив, да это и смысла не имеет, так как кто способен собрать, тот им сам такое напишет заглянув в сорцы "ардуино", а кто не способен, тому там делать нечего.

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

Например я года три не вылазил из KDevelop, я ведь не смотрю на Вас и Ваше Qt как на говно. Хотя Вы вполне этого заслуживаете за Ваши поползновения оскорбить меня сутенёром.
))))

Logik
Offline
Зарегистрирован: 05.08.2014

В строке 17 делать проверку available()<16. Сейчас у Вас из цикла выходит при наличии в бухере хоть чего. И его мало. 

allesanbr
Offline
Зарегистрирован: 31.01.2016

Logik пишет:

В строке 17 делать проверку available()<16. Сейчас у Вас из цикла выходит при наличии в бухере хоть чего. И его мало. 

Приведите практический пример некорректности работы библиотеки.
Буду Вам очень признателен.

Logik
Offline
Зарегистрирован: 05.08.2014

allesanbr пишет:
Logik пишет:

В строке 17 делать проверку available()<16. Сейчас у Вас из цикла выходит при наличии в бухере хоть чего. И его мало. 

Приведите практический пример некорректности работы библиотеки. Буду Вам очень признателен.

Чего?!  Это не либа некоректно работает, это ТС её неверно использует. Строки17-18 как раз и есть примером. available() возвращает кол-во реально принятых на момент вызова байт. 

allesanbr
Offline
Зарегистрирован: 31.01.2016

Logik пишет:
available() возвращает кол-во реально принятых на момент вызова байт. 

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

Radjah
Offline
Зарегистрирован: 06.08.2014

Проверяй количество данных в буфере перед чтением!

Logik
Offline
Зарегистрирован: 05.08.2014

allesanbr пишет:
Logik пишет:
available() возвращает кол-во реально принятых на момент вызова байт. 

 

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

Так и я не хочу вникать в Christina. Вобще с чего о ней речь? ТС сделал на стандартной Serial, но напутал с проверкой. Ошибка легко исправима, о чем ему и написал я. Какая такая Christina?! Зачем она здесь?

allesanbr
Offline
Зарегистрирован: 31.01.2016

Radjah пишет:

Проверяй количество данных в буфере перед чтением!

iCpu
iCpu аватар
Offline
Зарегистрирован: 12.02.2016

Logik, Radjah, увы, это ничего не даёт. Даже если допустить, что я сжираю только первый символ, они не совпадают ни одним битом.

0x4c = 01001100b

0x01 = 00000001b

Так что дело действительно либо в настройках передачи, либо в задержках работы программы на ПК. (Это не голословное заявление, я только что встал и проверил. Тухло.)

 

allesanbr > Для реализации того, что Вы здесь нагородили, об умности библиотеки, и возможностях RS232 следует отказаться от библиотеки serial и использовать свою собственную.

Для реализации вашего барахла неплохо было бы изучить битовые поля у структур. 

struct to_gather {
byte to : 2;
byte gather : 6;
}:
union death_of_it_all{ to_gather togather; char we; byte fall; };
sizeof(to_gather) // 1 byte
sizeof(death_of_it_all) // 1 byte

allesanbr > я же предложил лишь надстройку над serial, чтобы не лепить собственные костыли. От ардуино бОльших возможностей и не требуется.

А вас об этом просили? Вы, вообще, поняли о чём вопрос? Хотя бы после разжёвывания? Не похоже.

allesanbr > Вам шашечки или ехать?

Мне автомобиль.

allesanbr > Что же касается вашего бахвальства... и прочий баттхёрт.

Мне глубоко (как бы это поуважительнее к остальной публике сказать) поровну на все языки программирования. Их тысячи, они приходят и уходят, одни я изучаю(-л), другие - даже не имею представления об их существовании. Меня интересует конкретная проблема и её конкретное решение. И то, что это решение должно быть приближено к Qt я обозначил в самом первом посте.

Вы же прилепили дерьмовую, буду честным, библиотеку по передаче 10 бит в виде 4 (четырёх, Карл!) байт, которые считываются с аналогового пина. Чёрт подери, я во второй вечер от скуки сделал осциллограф с отрисовкой графика, просто потому, что мне было скучно, но я же этот говнокод не пихаю людям. Я же знаю, что в интернетах есть исходники на пару порядков круче моего. А сейчас я хочу сделать программатор для M27C2001, просто потому как с наскока не нашёл. И именно в передаче больших массивов я и спустил обойму в собственную ногу. Конечно, больших массивов можно избежать, но проблема уже появилясь и она настойчиво требовала моего внимания. А как говорил один герой экрана, "не мы властны над нашим разумом".

allesanbr > оскорбить меня сутенёром.

Тупым американским сутенёром с дешёвыми понтами и несовершеннолетним товаром. Мне больше нравится эта полная формулировка. И, поверьте, я познакомился с вашими постами\комментариями\опусами перед тем, как составить такое мнение.

iCpu
iCpu аватар
Offline
Зарегистрирован: 12.02.2016

Всё, сомненья развеяны, всё дело в задержках Qt. Всё взаимодействие нужно вывести в отдельный поток, так как GUI вносит критичные, в данном случае, задержки в работу "протокола".

allesanbr
Offline
Зарегистрирован: 31.01.2016

iCpu пишет:

Всё, сомненья развеяны, всё дело в задержках Qt. Всё взаимодействие нужно вывести в отдельный поток, так как GUI вносит критичные, в данном случае, задержки в работу "протокола".

То есть Вы стесняетесь даже свои собственные алгоритмы взаимодействия между устройствами называть - протокол. И берёте это слово в кавычки?!

Да у Вас мания ничтожества!
)))
Поэтому: Естественно для Вас всё - говно. Даже Вы сами.

Так вот дорогой друг, я Вам открою тайну:

Можете не ставить кавычки вокруг слова - протокол, если речь идёт об алгоритмах взаимодействия между двумя устройствами. Я Вам больше скажу: даже между двумя программами!!! Это слово как раз и говорит нам о том, что речь идёт о неких соглашениях об обмене данными между чем-то и чем-то.

На то, что Вы думаете обо мне лично - мне абсолютно фиолетово, а вот у Вас есть большие проблемы с самооценкой.

Что же касается четырёх (...Карл!) байт, то даже 9600 бод это скорость в такое количество раз превышающая реакцию любого аналогового датчика, что на конечном результате это не отражается - от слова - никак.
Кстати в отличии от настоятельно рекомендуемого ардуино delay(); при работе с аналоговыми пинами. Учите матчасть!

iCpu
iCpu аватар
Offline
Зарегистрирован: 12.02.2016

allesanbr> На то, что Вы думаете обо мне лично - мне абсолютно фиолетово

Тогда почему у вас так лихо припекает снизу, что аж до "комплексов ничтожества" дошло? Это, батенька, ложь, вам очень хочется похвалы. А её нет. Даже если у меня такой комплекс есть, вас не смущает то, что с высоты этого комплекса я смотрю на вас сверху? Вы себя загоняете в угол, батенька.

allesanbr> Что же касается четырёх (...Карл!) байт, то даже 9600 бод это скорость в такое количество раз превышающая реакцию любого аналогового датчика, что на конечном результате это не отражается - от слова - никак.

16 аналогов, 11 шимов, 24 пина, 3 хардварных порта и, конечно, I2C. Обыкновенная Мега. Если разбрасываться операциями так, как вы советуете, то половина из перечисленного нафиг не сдалась, а вторая будет дико лагать, ибо имеем мы всего 14 МГц. Кстати, как ваша библиотека, может в несколько портов одновременно?

allesanbr
Offline
Зарегистрирован: 31.01.2016

iCpu пишет:
Кстати, как ваша библиотека, может в несколько портов одновременно?

Слава яйцам коня Тамерлана! Хоть один вопрос по теме.

Нет не может в несколько портов. Так как я во время решения задачи, просто не знал о serial-возможностях "меги".

Учитывая что:

"Для Arduino Mega: Serial1, Serial2, Serial3"

То она может и не работать на "меге". В исходники класса Serial пока не заглядывал(сюрприз будет) ;)

iCpu
iCpu аватар
Offline
Зарегистрирован: 12.02.2016

allesanbr пишет:
Слава яйцам коня Тамерлана! Хоть один вопрос по теме.
Вообще-то я вас мокнул в ваш код. Я его бегло просмотрел, было дело, и жиденькие места мне известны.

А теперь, если можно, прекратите писать в этой теме. Ваш "код" мне абсолютно не интересен, никакой полезной нагрузки вы не несёте, а посраться лучше на политических форумах. 

allesanbr
Offline
Зарегистрирован: 31.01.2016

iCpu пишет:

А теперь, если можно, прекратите писать в этой теме. Ваш "код" мне абсолютно не интересен, никакой полезной нагрузки вы не несёте, а посраться лучше на политических форумах. 

С удовольствием выполняю Вашу просьбу.

iCpu пишет:
Вообще-то я вас мокнул в ваш код. Я его бегло просмотрел, было дело, и жиденькие места мне известны.

...а насчёт самооценки, Вы всё же подумайте. У Вас в двух предложениях подряд - два слова "я", и одно слово "мне".

Это звоночек.
Не говоря уже о том, что Вы пытаетесь поставить себя выше собеседника.

Всего хорошего.