Парсинг - потеря данных

Rubis

✩✩✩✩✩✩✩
17 Дек 2021
11
3
Доброго времени суток Всем.
Захотел создать приложение по управлению Цветомузыкой на ПК. Использую уроки от @AlexGyver по парсингу, работе с Python и QT Designer. За основу взял переделанный проект: Цветомузыка на Arduino. FireEdition.
Во общем проблема: при отправке данных с ПК на Arduino Nano, пакеты пропускаются (доходят не с первого раза, или не доходят совсем).
Конкретно в этом случае: с ПК отправляю изменения BRIGHTNESS (которая пропускается) и в окне на ПК вижу результат своего действия отправленный с Arduino.

C++:
// с ардуино в SerialPort, терминатаор \n
// с пк в SerialPort, терминатаор ;
#if PARSER
void parser() {
  if (serial.available()) {
    noInterrupts();
    Parser data(serial.buf, ',');  // отдаём парсеру
    int ints[10];           // массив для численных данных
    data.parseInts(ints);   // парсим в него

    switch (ints[0]) {
      //case 0:

       // break;
      case 1:
        BRIGHTNESS = ints[1];

        break;
      //case 2:

       // break;
      //case 3:

       // break;
      //case 4:

        //break;
      //case 5:

        //break;
    }
    interrupts();
  }

}
void SendSerial (int key, int* data, int amount) {
    Serial.print(key);
    Serial.print(',');
    for (int i = 0; i < amount; i++) {
      Serial.print(data[i]);
      if (i != amount - 1) Serial.print(',');
  }
  Serial.print('\n');
 }
#endif

void PC_Packed () {
  int packet[3];
  packet[0] = BRIGHTNESS;
  packet[1] = mode_arr[0];
  packet[2] = this_submode;
  SendSerial(0, packet, 3);
}

Python:
from PyQt5 import QtWidgets, uic, QtCore
from PyQt5.QtSerialPort import QSerialPort, QSerialPortInfo
from PyQt5.QtCore import QIODevice


app = QtWidgets.QApplication([])
ui = uic.loadUi("LED_Control.ui")
ui.setWindowTitle("Color Music")



serial = QSerialPort()
serial.setBaudRate(115200)
portList = []
ports = QSerialPortInfo().availablePorts()
for port in ports:
    portList.append(port.portName())
ui.comSP.addItems(portList)


def onRead():
    if not serial.canReadLine(): return  # выходим если нечего читать
    rx = serial.readLine()
    rxs = str(rx, 'utf-8').strip()
    data = rxs.split(',')
    if data[0] == '0':
        ui.AcBrLb.setText(data[1])


def Con_to_Ard():
    serial.setPortName(ui.comSP.currentText())
    serial.open(QIODevice.ReadWrite)


def serialSend(data):
    txs = ""
    for val in data:
        txs += str(val)
        txs += ','
    txs = txs[:-1]
    txs += ';'
    serial.write(txs.encode())


def Dis_to_Ard():
    serial.close()


def Br_con():
    serialSend([1, ui.spinBr.value()])

serial.readyRead.connect(onRead)
ui.ConBut.clicked.connect(Con_to_Ard)
ui.DisBut.clicked.connect(Dis_to_Ard)

ui.spinBr.textChanged.connect(Br_con)

ui.show()
app.exec()

Предполагаю что скорости обработки не хватает у Arduino. Может есть варианты справиться с этой проблемой?
Использую библиотеки:
Parser.h
AsyncStream.h
 

Вложения

bort707

★★★★★★✩
21 Сен 2020
3,019
901
у ардуино более чем достаточно скорости для обработки Сериал, который по определению очень медленный. Ищите проблемы в другом месте, в частности посмотрите, нет ли в основном коде задержек, задаваемых delay(). Если в коде есть задержки более чем 100-200 мс - парсер будет терять данные
 

Bruzzer

★★★✩✩✩✩
23 Май 2020
432
129
Если в коде есть задержки более чем 100-200 мс - парсер будет терять данные
Я не знаю питон, но по моему ТС отправляет руками новые значения, и маловероятно, что он будет кликать по SpinBox со скоростью достаточной для переполнения буфера.
 

Rubis

✩✩✩✩✩✩✩
17 Дек 2021
11
3
@Старик Похабыч, уже делал. При скорости в 9600 пакеты начинают "делиться построчно". Парсинг на стороне Python происходит неправильно. Я поэтому и поднял скорость до 115200.

@bort707 проверяю на задержки, но ничего существенного не нашел. Есть задержки но они в функциях. Вызываются отдельно.

@Bruzzer совершенно верно. Пытаюсь отправить и просто вбив в SpinBox и стрелочками вверх и вниз, но в основном получаю 0 на Arduino. Пытался сделать на QSlider но результат тот же.
 
Изменено:

Bruzzer

★★★✩✩✩✩
23 Май 2020
432
129
@Rubis,
Насколько я понял parser() только читает из буфера Serial, но не удаляет обработанные данные (не сдвигает указатель). Я не увидел, где вы очищаете буфер Serial. Скажите, как вы удаляете обработанное?
 

Rubis

✩✩✩✩✩✩✩
17 Дек 2021
11
3
@Bruzzer
В библиотеке Parser.h, как я понял, есть функционал отчистки:
~Parser() {
clear();
}
void clear() {
if (str) free(str);
}
C++:
#ifndef Parser_h
#define Parser_h
// простой и быстрый парсер строк в отдельные строки и числа

class Parser {
  public:
    Parser (char* data, char newDiv = ',') {
      buf = data;
      div = newDiv;
    }
    ~Parser() {
      clear();
    }
    void clear() {
      if (str) free(str);
    }
    int amount() {
      int i = 0, count = 0;
      while (buf[i++]) if (buf[i] == div) count++;  // подсчёт разделителей
      return ++count;
    }
    int split() {
      int am = amount();            // количество данных
      clear();                      // освобождаем буфер
      str = (char**)malloc(am * sizeof(char*)); // создаём буфер
      str[0] = buf;                 // строка 0
      int i = 0, j = 0;             // счётчики
      while (buf[i]) {              // пока не NULL
        if (buf[i] == div) {        // если разделитель
          buf[i] = '\0';            // меняем на NULL
          str[++j] = buf + i + 1;   // запоминаем начало строки
        }
        i++;
      }
      return am;
    }
    int16_t getInt(int num) {
      return atol(str[num]);
    }
    float getFloat(int num) {
      return atof(str[num]);
    }
    bool equals(int num, const char* comp) {
      return !strcmp(str[num], comp);
    }
    int parseInts(int* data) {
      int count = 0;
      char* offset = buf;
      while (true) {
        data[count++] = atoi(offset);
        offset = strchr(offset, div);
        if (offset) offset++;
        else break;
      }
      return count;
    }
    int parseBytes(byte* data) {
      int count = 0;
      char* offset = buf;
      while (true) {
        data[count++] = atoi(offset);
        offset = strchr(offset, div);
        if (offset) offset++;
        else break;
      }
      return count;
    }

    char* buf = NULL;
    char** str = NULL;

    char* operator [] (uint16_t idx) {
      return str[idx];
    }
    char div;
  private:
};

#endif
 

bort707

★★★★★★✩
21 Сен 2020
3,019
901
В библиотеке Parser.h, как я понял, есть функционал отчистки:
нет, это деструктор всего обьекта Parser

проверяю на задержки, но ничего существенного не нашел. Есть задержки но они в функциях. Вызываются отдельно.
не важно, как они вызываются. Если цикл loop() основной программы занимает более 0.1 -0.2 сек - парсинг работать не будет. А у вас там в коде черти что наворочено :)
 

Bruzzer

★★★✩✩✩✩
23 Май 2020
432
129
@Rubis,
Я не заметил, что вы используете serial а не Serial . Мой вопрос был не корректен. Я не разбирался с <AsyncStream.h> .