Читаем с UART. Как лучше?

Тема в разделе "Iskra JS, Espruino, Йодо", создана пользователем ИгорьК, 15 апр 2016.

  1. ИгорьК

    ИгорьК Гуру

    Есть UART, который шлет нам приветы в виде групп байтов. Количество байтов бывает разным, правильное - 8.
    Принимаю их следующим образом:
    Код (C++):
    Serial.on('data', function (data) {
      cmd = cmd+data; // суммирую в стринг  глобальной видимости
      if(cmd.length === 8) { // досчитал до восьми
        sendTo(cmd); // отправляю в переработку в другую функцию
        cmd="";
      }
    });
    Вопрос вот в чем. Если байт пришло 7, UART ждет восьмого, отправляет группу на переработку и, предположим, с очередными 7 ждет нового приема.
    Работа нарушается.

    В Ардуине было бы все по-другому. Читаем порт пока не кончатся данные, определяем длину приема, если искомые восемь - обрабатываем, если меньше - сливаем в унитаз. Снова готовы к приему информауии.
    Можно ли здесь поступать аналогичным образом и как это сделать?

    ПС. Нет никакого стоп байта типа "\n" и т.п.. Ловить - не чего.
     
    Последнее редактирование: 15 апр 2016
  2. Unixon

    Unixon Оракул Модератор

    Здесь data выполняет роль промежуточного буфера приема, по идее его содержимое нужно по одному символу прогнать через автомат, в котором разбирается формат пакета.
     
  3. ИгорьК

    ИгорьК Гуру

    Поскольку нет никакого стопового байта, вопрос заключается в том, принята или нет текущая группа байтов.
    В ардуино есть конструкция Serial.available() . Выкачиваем все и анализируем что есть.
    Как быть в случае с JS?
    Да, здесь тоже есть function Serial.available(). Пользоваться ей? Можно, но ей, видимо, нужна обертка типа while(true), что, честно говоря, уже становится непривычным как стиль. Или я ошибаюсь?
    Вот пример с сайта espruino:
    Код (Javascript):
    var cmd="";
    Serial1.setup(9600/*baud*/);
    Serial1.on('data', function (data) {
      Serial1.print(data);
      cmd+=data;
      var idx = cmd.indexOf("\r");
      while (idx>=0) {
        var line = cmd.substr(0,idx);
        cmd = cmd.substr(idx+1);
        var s = "'"+line+"' = "+eval(line);
        print(s);
        Serial1.println(s);
        idx = cmd.indexOf("\r");
      }
    });
    Он вполне понятен, но есть заковыка - алгоритм ловит "\r". В нашем случае ловить не чего. За что большое спасибо авторам железки, которую я уже готов скестить с IskraJS и, таким образом, познакомить вас друг с другом. Ох, забавная мне видится статейка :) Ребята отожгли... со своим устройством.
     
    Последнее редактирование: 15 апр 2016
  4. Unixon

    Unixon Оракул Модератор

    Все то же самое, только вы выкачиваете уже из data. Способ определения границы пакета зависит от его содержимого.
     
  5. nailxx

    nailxx Официальный Нерд Администратор

    Согласен с @Unixon. Если протокол не подразумевает зацепок в виде начала-конца пакета, работа через Serial не будет стабильной, а в случае с Arduino вам «везло»: все данные успевали скопиться в буфере до того, как вы начинали их обрабатывать, что в общем случае не всегда обязано происходить. Проблема, известная как racing.

    Я так понимаю, уместный критерий для вас — это «8 байт пришли быстро друг за дружкой». В этом случае, я бы при приёме первого байта новой порции взводил setTimeout на принятие пакета и в нём бы уже разбирал накопленный cmd и принимал решение:

    Код (Javascript):

    var cmd = '';

    Serial.on('data', function (data) {
      if (!cmd) {
        setTimeout(processCmd, 5 /* мс */);
      }

      cmd += data;
    });

    function processCmd() {
      if (cmd.length === 8) {
        sendTo(cmd);
      } else {
        print('Bad packet length. Expected 8, got', cmd.length);
      }

      cmd = '';
    }
     
    ИгорьК нравится это.
  6. ИгорьК

    ИгорьК Гуру

    В том и проблема, что афффтар не предусмотрел указания границы пакета.
    Я с исследуемой здесь ситуацией еще ни разу не встречался - всегда была граница пакета.
    Ну, видимо так. А что еще делать то. Куда деваться.
    Вот уж премного благодарен. Я, не имея опыта, считал что ситуация типовая, ан нет, оказывается...
    В общем, прикручиваю новую железку nooLite к Iskra JS. И столько у меня желания постебаться над ней. А Вы этого желания еще добавили :)
     
  7. nailxx

    nailxx Официальный Нерд Администратор

    Ооо… Это интересно. Как раз ремонт назревает, хочу несколько блоков nooLite поставить.
     
  8. ИгорьК

    ИгорьК Гуру

    А я хочу вызвериться на них... :) Особенно за эту последнюю железку - UART приемник всего, что шлется передатчиками. Сначала я ее прикрутил к ESP8266. Почти прикрутил... Потом решил прикручивать к IskraJS. В принципе, мой код работает, однако, бывают нюансы.
    И, кстати, все больше уважаю Iskra JS. Пока не вижу в ней недостатков (хотя какой я профессионал, но разница в логике, продуманности и поддержке колоссальная в сравнении с упоминаемыми здесь ). Можно было бы еще немного ног вывести в виде отверстий для пайки. Но и так отлично все. ИМХО.
     
  9. Unixon

    Unixon Оракул Модератор

  10. ИгорьК

    ИгорьК Гуру

    Нет. По ссылке передатчик. А у меня - приемник. Его похоже на сайте нет.
     
  11. Unixon

    Unixon Оракул Модератор

    А описание протокола есть?
     
  12. ИгорьК

    ИгорьК Гуру

    А как же... :)
    img013.jpg
     
  13. ИгорьК

    ИгорьК Гуру

    А вот как это выглядит. MT1132 (зеленый) и MR1132 (синий).
    005.jpg

    Вот она, реально работающая Iskra JS с nooLite MR1132. :)
    009.jpg
     
    Последнее редактирование: 15 апр 2016
  14. Unixon

    Unixon Оракул Модератор

    Так вот же в примечании (1) написано как детектировать границу пакета.
     
  15. ИгорьК

    ИгорьК Гуру

    Вот она, реально работающая Iskra JS с nooLite
    Ну... и как это выглядит в коде?
     

    Вложения:

    • 009.jpg
      009.jpg
      Размер файла:
      39,2 КБ
      Просмотров:
      671
  16. Unixon

    Unixon Оракул Модератор

    Берете буфер, просматриваете, если в n-том байте лежит m, т в n+L-том лежит (m+1)%m_max, между ними, скорее всего, пакет, проверяете все остальные байты на соответствие ограничениям по спеку. Если есть возможность, накапливаете несколько пакетов или постоянно ведете опрос устройства, чтобы получать новые пакеты и проверять по ним выравнивание. Если пакет получен, выкидываете L байт, если нет, то только первый.
     
  17. ИгорьК

    ИгорьК Гуру

    Я видел это примечание, но тяму моего не хватает для понимания ситуации.
    Всё что Вы пишете логично до первого пропущенного пакета.
    Модуль шлет пакеты, увеличивая первый байт в указанных битах каждый раз на единицу. Как только вы пропускаете очередной - вся эта арифметика не стоит и ломаного гроша.
    И второй забавный вопрос - как определить, что самый первый, пришедший после включения принимающего устройства, байт правильный. Можно за него "зацепиться" или слить. Ведь мы начинаем работу не с чистого листа - передатчик уже наприсылал много пакетов и у него свой счет команд.
     
  18. Unixon

    Unixon Оракул Модератор

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

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

    Unixon Оракул Модератор

    Ну, смотрите, у вас же куча вспомогательных условий есть:

    1) байт n должен инкрементировать число в младшие 5 бит и дублировать 0-й в 7-й;
    2) байт n+1 не должен превышать 63;
    3) байт n+2 не должен превышать 21;
    4) байт n+3 не должен превышать 3, содержит число m;
    5) байт n+2^(m-1) должен быть началом следующего пакета, т.е. удовлетворять (1);

    Пишете функцию-валидатор и прикладываете ее к потоку, начиная с каждого следующего байта. Если валидация прошла - принимаете пакет и смещаетесь к следующему, если нет - продолжаете ползти в потоке по одному байту и пытаться валидировать новый пакет.
     
    Megakoteyka и ИгорьК нравится это.
  20. ИгорьК

    ИгорьК Гуру

    "Следствие ведут Знатоки"... И это устройство для облегчения жизни домашнему самоделкину.
    Уверен, что Вы продвинулись гораздо дальше чем продумал его конструктор. :)