Подтвердить что ты не робот

Чтение из последовательного порта в С#

Я попытался использовать Readline(), и данные упали, я попытался использовать Read(), но я не уверен, как использовать метод доказательства ошибок, поскольку я могу получить несколько пакетов один за другим, и у меня нет способ узнать, что будет другой пакет. Между пакетами BytesToRead равно 0, поэтому я не могу его использовать. Когда вы читаете данные в буфер, у вас есть таймер или помещаете поток в режим сна, чтобы все пакеты могли прибыть?

Я потерялся. Не знаю, что делать дальше.

Я должен упомянуть, что я не гарантирую, что строка, выходящая из последовательного порта, будет завершена \n или\r или \r\n. Мне просто нужен надежный способ прочитать ВСЕ пакеты, которые будут поступать из шкалы, когда пользователь нажимает на нее ПЕЧАТЬ.

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

4b9b3361

Ответ 1

Пробовали ли вы прослушать DataRecieved событие SerialPort класс?

public class MySerialReader : IDisposable
{
    private SerialPort serialPort;
    private Queue<byte> recievedData = new Queue<byte>();

    public MySerialReader()
    {
        serialPort = new SerialPort();
        serialPort.Open();

        serialPort.DataReceived += serialPort_DataReceived;
    }

    void serialPort_DataReceived(object s, SerialDataReceivedEventArgs e)
    {
        byte[] data = new byte[serialPort.BytesToRead];
        serialPort.Read(data, 0, data.Length);

        data.ToList().ForEach(b => recievedData.Enqueue(b));

        processData();
    }

    void processData()
    {
        // Determine if we have a "packet" in the queue
        if (recievedData.Count > 50)
        {
            var packet = Enumerable.Range(0, 50).Select(i => recievedData.Dequeue());
        }
    }

    public void Dispose()
    {
        if (serialPort != null)
            serialPort.Dispose();
    }

Ответ 2

Мы прошли один и тот же процесс некоторое время назад.

Единственный способ прочитать "пакеты" - это иметь некоторое представление о том, где начало и конец находятся в потоке.

От msdn:

Поскольку класс SerialPort буферизует данные, а поток, содержащийся в свойстве BaseStream, не работает, оба могут столкнуться с проблемой того, сколько байтов доступно для чтения. Свойство BytesToRead может указывать на то, что есть байты для чтения, но эти байты могут быть недоступны для потока, содержащегося в свойстве BaseStream, потому что они были буферизованы для класса SerialPort.

Мы использовали обратную нить (вы могли использовать BackgroundWorker) для чтения данных в буфер. Если вы не можете надежно установить завершающий символ с использованием свойства SerialPort.Newline(потому что, скажем, оно меняется!), Вам нужно будет реализовать свою собственную систему обнаружения пакетов, потому что вы не сможете использовать блокировку SerialPort.Readline() метод.

Вы можете просто прочитать в байтовый буфер, используя SerialPort.Read() (или строку, используя метод SerialPort.ReadExisting()) и сгенерировать событие, когда вы обнаруживаете действительный пакет в данных. Обратите внимание, что Read() (и я полагаю, что ReadExisting()) очищает буфер SerialPort, поэтому вам нужно сохранить данные где-то еще.

Если вы установите SerialPort.ReadTimeout, вы можете обработать исключение TimeoutException и иметь простой способ обработки условий, при которых ваше устройство не передает. Это хороший способ для reset обнаружения вашего пакета, если вы используете фиксированное количество байтов или какую-либо другую схему без прерывания. (используйте SerialPort.DiscardInBuffer() в таймаут, если вам не нужны частичные пакеты).

Удачи.

Ответ 3

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

  • буферизировать входящие данные
  • сканирование вашего буфера, чтобы найти полные данные
  • удалить использованные данные из буфера

Мне просто интересно, есть ли у вас проблемы с последовательным портом. Если это так, я разработал язык программирования последовательного порта в С#, и я считаю, что он решает почти все проблемы, с которыми сталкиваются все.

Не могли бы вы взглянуть и попробовать? Например; вы можете буферизовать входящие данные из последовательного порта, как и следующие, и легко выполнять операции с строкой.

state Init
  // define a global variable
  our $BUFFER = "";
  jump(Receive);
end state

state Receive
  recv();
  $len = length($DATA_PACKET);
  if("$len > 0") {
    $BUFFER += $DATA_PACKET;
    call(Parser);
  }
end state

state Parser
  // check if buffer matchs regular expression pattern
  if(match($BUFFER, "(?<WILLDELETE>.*?<STX>(?<DATA>.*?)<ETX>(?<CHECKSUM>[0-9A-F]{2}))")) {
    // Received complete data
    $lenData = length($WILLDELETE);
    $BUFFER = remove($BUFFER, 0, $lenData);

    // Do operations with the other parsed fields. $DATA and $CHECKSUM in this example.
  }
end state

Проект свободно доступен на sourceforge, и если у вас есть какие-либо вопросы, пожалуйста, не стесняйтесь спрашивать.

Страница проекта

Ссылка для скачивания