Оптимизация записи / чтения .NET SerialPort

У меня есть устройство UART, и я пишу ему команду (через System.IO.Ports.SerialPort), а затем устройство сразу же ответит.

Итак, в основном мой подход:

->Write to SerialPort->await Task.Delay->Read from the Port.

//The port is open all the time.
public async byte[] WriteAndRead(byte[] message){ 
port.Write(command, 0, command.Length);
await Task.Delay(timeout);
var msglen = port.BytesToRead;
    if (msglen > 0)
                {

                    byte[] message = new byte[msglen];
                    int readbytes = 0;

                    while (port.Read(message, readbytes, msglen - readbytes) <= 0)
                        ;

                    return message;

                    }

Это отлично работает на моем компьютере. Но если я попробую, например, на другом компьютере, свойство bytesToRead иногда не соответствует. В нем пустые байты или ответ не завершен. (Например, я получаю два байта, если я ожидаю один байт: 0xBB, 0x00 или 0x00, 0xBB)

Я также изучил событие SerialPort.DataReceived, но оно срабатывает слишком часто и (насколько я понимаю) не очень полезно для этого подхода к записи и чтению. (Как и жду ответа сразу от аппарата).

Есть ли лучший подход к чтению и записи?

int readbytes = 0; while (port.Read(message, readbytes, msglen - readbytes) <= 0); Так где же здесь обновить readbytes?
itsme86 22.03.2018 21:28

Никогда не теряйте возвращаемое значение Read (). И не забудьте удалить вызов Task.Delay (), который просто скрывает ошибки в вашем коде. Исправить их совершенно невозможно.

Hans Passant 22.03.2018 23:43

Я описываю подход к обработке входящих данных здесь stackoverflow.com/questions/15124132/… Вам просто нужно было бы построить другую абстракцию, чтобы превратить ее в последовательность, или использовать что-то вроде реактивных расширений

Keith Nicholas 23.03.2018 03:50

@HansPassant: Дело в том, что у устройства есть задержка (где-то 150-700 мс). Обычно это означает, что без ожидания SerialPort.BytesToRead равен 0. (Это означает, что данных нет). Как-то мне нужно ждать данных.

user3410599 23.03.2018 20:52

Read () уже ожидает данных, у вас есть гарантия, что он вернет хотя бы 1 байт. Так что откладывание в одиночестве не дает ничего полезного. Вам вообще не нужен BytesToRead, просто передайте msglen - totalbytes. Увеличьте общее количество байтов на возвращаемое значение Read ().

Hans Passant 23.03.2018 22:28
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
5
508
1

Ответы 1

Внимательно прочтите примечания в https://msdn.microsoft.com/en-us/library/ms143549(v=vs.110).aspx Не следует полагаться на значение BytesToRead для указания длины сообщения. Вы должны знать, сколько данных вы ожидаете прочитать, чтобы разложить сообщение. Кроме того, как заметил @ itsme85, вы не обновляете байты чтения, и поэтому вы всегда записываете полученные байты в начало вашего массива. Правильный код с обновлением readbytes должен выглядеть так:

int r;
while ((r = port.Read(message, readbytes, msglen - readbytes)) <= 0){
  readbytes += r;
}

Однако за время, пока вы будете читать данные, может появиться больше данных, и ваше «сообщение» может быть неполным. Подумайте, чего вы хотите достичь.

Я выполнил исправление и ваше предложение. Теперь msglen - это ожидаемая длина в байтах. Дело в том, что иногда операция будет отключаться по таймауту, потому что иногда устройство получает 9 байт вместо 10.

user3410599 23.03.2018 20:55

затем оберните время другим временем + некоторая задержка, когда вы будете ждать, пока массив сообщений не заполнится.

Miq 29.03.2018 09:31

Другие вопросы по теме