Проблема потери данных по UART

Anton991
Offline
Зарегистрирован: 09.10.2017

Здравствуйте. У меня возникла проблема следущего рода: по UART приходят данные большими пакетами 200-256 байт, я их считываю но конец обрывается, у меня подозрения что это из за буфера UART. Плата wemos D1 

Код ниже, Serial запущен на скорости 115200

String  msg;
while (Serial.available() > 0) {
    byte inChar = Serial.read();
    msg += inChar;
}
Serial.println(msg);

Как можно решить проблему потери данных?

P.S. в файле HardwareSerial.h буфер пробывал увеличивать до 256 и до 255, не помогло. 

#define SERIAL_TX_BUFFER_SIZE 255
#define SERIAL_RX_BUFFER_SIZE 255
 
Возможности уменшить пакеты с отправителя тоже нету
b707
Offline
Зарегистрирован: 26.05.2017

А с чего вы взяли, что они обрываются именно при приеме? Может вы их просто правильно вывести на печать не можете?

Какие данные в пакете - текстовые или бинарные? Если бинарные - для их хранения и вывода на печать String и println() не подходят.

Anton991
Offline
Зарегистрирован: 09.10.2017

Данные бинарные, raw data с gps приемника пакет в HEX кодировке. Использовал String, потому что потом пересылаю их по ethernnet на сервер через команду client.println(). А какие инструменты лучше использовать для работы с бинарными данными? 

sadman41
Offline
Зарегистрирован: 19.10.2016

А вы в цикле while делайте Serial.println( .. , HEX) байта, который приняли и всё поймете - буфер виноват или нет.

Anton991
Offline
Зарегистрирован: 09.10.2017

попробовал, отправляется по 200-256 байт, доходит 140-150. Интересно если бы дело было в буфере наверно дохлдило всегда бы одинаковое количество байт.

 Serial.println( "++++++++++++++++++BEGIN++++++++++++++++");
  int i=1;
  while (Serial.available() > 0) {
    byte inChar = Serial.read();
    
    Serial.print("#"+ String(i)+ ": ");
    Serial.println(inChar, HEX);
    i=i+1;
    delay(5);   
    }
   Serial.println( "________________END_________________");

скриншот демонстрирует что происходит какая-то ерунда под конец посылки.

sadman41
Offline
Зарегистрирован: 19.10.2016

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

Anton991
Offline
Зарегистрирован: 09.10.2017

ни каких прерываний вроде нет, код что выше, это весь скетч остальное я все пока закоментировал, ну еще в setup инициализируется serial.

Penni
Penni аватар
Offline
Зарегистрирован: 18.01.2015

а delay(5) зачем? попробуйте без него

Anton991
Offline
Зарегистрирован: 09.10.2017

Может у меня не увиличился буфер UART, 

"P.S. в файле HardwareSerial.h буфер пробывал увеличивать до 256 и до 255, не помогло. 

#define SERIAL_TX_BUFFER_SIZE 255

#define SERIAL_RX_BUFFER_SIZE 255 "

и эти изменения не заработали, и буфер так и остался 128 байт?

Anton991
Offline
Зарегистрирован: 09.10.2017

Penni пишет:

а delay(5) зачем? попробуйте без него

без него считывается первый байт и выходт из цикла while, и в следующем loop дочитываются остальные

Penni
Penni аватар
Offline
Зарегистрирован: 18.01.2015

Ну вот вам и проблема, если шлете пакетами то такого не должно быть. Значит кто-то куда-то отвлекает проц, как писали выше прерывания или еще что-то

sadman41
Offline
Зарегистрирован: 19.10.2016

Anton991 пишет:

без него считывается первый байт и выходт из цикла while, и в следующем loop дочитываются остальные

while (true) {
   if (Serial.available() > 0) {
       byte inChar = Serial.read();
      Serial.println(inChar, HEX);      
    }
}
   

Так вам точно в этом лупе ничего не помешает кроме прерываний.  GPS только TX-ом подключен, надеюсь?

 
Anton991
Offline
Зарегистрирован: 09.10.2017

да к gps идет только питание и линия с TX gps на RX arduino. Попробую, отпишусь.

Anton991
Offline
Зарегистрирован: 09.10.2017

Теперь вроде приходит все, ну беглым взглядом потерь нет. 

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

А если заменить контролер на Arduino due или на STM32F103? проблема останеться?

sadman41
Offline
Зарегистрирован: 19.10.2016

Как минимум - нужно знать длину пакета, если он у вас RAW и содержит 0x00. То есть как вы определяете, что он целиком принят?

Потом, лично я бы, если по простому писал алгоритм, складывал принятые байты в байтовый массив, по окончании передачи делал ethernetClient.write() этого буфера на длину пакета. Или, может, ваш ethernetClient дает доступ указателю на свой буфер? Тогда бы писал принятое сразу туда.

Anton991
Offline
Зарегистрирован: 09.10.2017

Длинна плавает в зависимости от количества спутников. Еще gps модуль может общаться по SPI и I2C может на нах попробовать?

sadman41
Offline
Зарегистрирован: 19.10.2016

Ну плавает - это понятно. Конец пакета как-то же ловится? Просто я сейчас абстракциями оперирую - мне неизвестно, какая у вас ethernet библиотека, формат пакета GPS, поэтому вы получаете общие рекомендации, которые подходят в большинстве случаев.

5N62V
Offline
Зарегистрирован: 25.02.2016

Anton991 пишет:

Длинна плавает в зависимости от количества спутников. Еще gps модуль может общаться по SPI и I2C может на нах попробовать?

Не знаю как в SPI, но в стандартной библиотеке i2C буфер еще короче, и равен аж 32м байтам. Можно его в библиотеке выставить большим, но это тянет за собой пожирание ресурсов.

А что за модуль? Интересен , если действительно имеет SPI и I2C.

Anton991
Offline
Зарегистрирован: 09.10.2017

Я посмотрел лог сообщений в программе для работы с UBLOX трекерами, там длина плавает от 160 до 304 байт с шагом в 24 байта. 

Вот скриншот протокола, этого сообщения:

Anton991
Offline
Зарегистрирован: 09.10.2017

Ublox NEO 6T

sadman41
Offline
Зарегистрирован: 19.10.2016

Не совсем понятно, сколько занимает Length - если оно двубайтовое, то никакой памяти вам в ардуине не хватит, если резервировать ее под буфер максимального размера. Если же однобайтовое, то все просто: начинаете читать с сериала, инкрементируя i и одновременно записывая в байтовый массив, на i == 0 проверяете inByte == 0xB5, при i == 1 на inByte == 0x62, в случае неудачи на любой проверке скидываете i в 0 и начинаете всё сначала. Если всё ОК, то читаете еще 3 байта и в buffer[4] получаете длину пакета. Продолжаете читать/писать, (пока i < buffer[4]). Дошли до конца, CRC проверили, если совпадает - отсылаете в Ethernet, не совпадает - i=0 и ждете байтов из Serial. Проще всего такое сделать на "машине состояний".

Anton991
Offline
Зарегистрирован: 09.10.2017

sadman41 пишет:

Не совсем понятно, сколько занимает Length - если оно двубайтовое, то никакой памяти вам в ардуине не хватит, если резервировать ее под буфер максимального размера. Если же однобайтовое, то все просто: начинаете читать с сериала, инкрементируя i и одновременно записывая в байтовый массив, на i == 0 проверяете inByte == 0xB5, при i == 1 на inByte == 0x62, в случае неудачи на любой проверке скидываете i в 0 и начинаете всё сначала. Если всё ОК, то читаете еще 3 байта и в buffer[4] получаете длину пакета. Продолжаете читать/писать, (пока i < buffer[4]). Дошли до конца, CRC проверили, если совпадает - отсылаете в Ethernet, не совпадает - i=0 и ждете байтов из Serial. Проще всего такое сделать на "машине состояний".

Я так понял 2 байта под длину(

P.S Длину не с того байта посчитал HEX 110 = 272

Arduino DUE или STM32F103 справяться?)

sadman41
Offline
Зарегистрирован: 19.10.2016

Тогда гарантированного способа принять всё я не вижу.

Можно, конечно, взять некий максимально доступный объём памяти под буфер, зарезав буфер UART, к примеру, и не принимать пакет, если его длина превышает размер выделенной памяти, но тогда есть шанс, что при большом количестве спутников, ни один пакет не будет принят. Можно снизить скорость UART и попытаться закидывать в ethernet частями, но тогда CRC должен проверяться на удаленной стороне.

Посчитайте длину, которая может быть определена в двух байтах. И сравните ее с доступной памятью на других платформах.

Anton991
Offline
Зарегистрирован: 09.10.2017

Попробую частями, ну по сути памяти хватает, максимальная длина будет 400-500 байт это 20-25 спутников, что маловероятно. а вдвух байтах максимум 65 535 значений, мне кажется взяли два байта, потомучто одного байта с 255 значениями мало.

у платы wemos d1, она на базе ESP2866, при данной прошивке такие значения памяти: 

Скетч использует 231933 байт (22%) памяти устройства. Всего доступно 1044464 байт.
Глобальные переменные используют 32188 байт (39%) динамической памяти, оставляя 49732 байт для локальных переменных. Максимум: 81920 байт.
sadman41
Offline
Зарегистрирован: 19.10.2016

Ну, вполне может быть и так, что 640 байт хватит всем. В этом случае вам поможет корректируемая при работе переменная "максимальная длина пакета" и какой-нибудь счётчик пропущенных пакетов, а так же статистика его роста.

 

sadman41
Offline
Зарегистрирован: 19.10.2016

Anton991 пишет:

Ublox NEO 6T

У этого модуля GLONASS есть или нет - не знаете? Даташит молчит что-то по этому поводу.

Anton991
Offline
Зарегистрирован: 09.10.2017

нету, у 7 и 8 серии вроде есть, 6 уже не выпускают вроде.

на али и в прочих магазинах популярен neo 6m, там и raw data нельзя вытащить.