Очевидно, что это не правильный способ чтения с SerialPort - PullRequest
1 голос
/ 12 июня 2009

Допустим, я хочу иметь функцию, которая читает данные из SerialPort и возвращает байт [].

public byte[] RequestData(byte[] data)
{
    //See code below
}

Что-то настолько простое, что это действительно не работает / не работает и не очень надежно:

byte[] response = new byte[port.ReadBufferSize];

port.Open();    
port.Write(data, 0, data.Length);

Thread.Sleep(300); //Without this it doesn't even work at all

Console.WriteLine("Bytes to read: {0}", port.BytesToRead);

int count = port.Read(response, 0, port.ReadBufferSize);

Console.WriteLine("Read {0} bytes", count);

port.Close();
port.Dispose();       

return response.GetSubByteArray(0, count);

Я также попытался заменить Thread.Sleep на что-то вроде:

while (port.BytesToRead < 14)
{
    //Maybe Thread.Sleep(10) here?
}

Но это вызывает проблемы. (PS: я знаю, что мне нужно по крайней мере 14 байтов)

Конечно, лучшим способом (я думаю) было бы иметь что-то вроде:

port.ReceivedBytesThreshold = 14;
port.DataReceived += new SerialDataReceivedEventHandler(port_DataReceived);
port.Open();

port.Write(data, 0, data.Length);

А потом, конечно, есть обработчик:

void port_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
    var port = (SerialPort)sender;

    while (port.BytesToRead > 0)
    {
        //Read the data here
    }
}

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

(может быть отправлено несколько сообщений, и я могу представить, что одному сообщению потребуется больше времени для обработки на другой стороне, чем другому, или что-то в этом роде).

Любой совет будет приветствоваться

UPDATE

Следующий код работает намного лучше, но если я удалю операторы Thread.Sleep (), он снова перестанет работать правильно. Например, инструмент мониторинга последовательного порта четко указывает, что 17 последовательных байтов были записаны в последовательную линию. В первый раз BytesToRead = 10 и в следующий раз BytesToRead = 4, но затем BytesToRead остается 0, так куда же делись последние 3 байта?

void port_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
    Thread.Sleep(100);
    while (port.BytesToRead > 0)
    {
        Console.WriteLine("Bytes to read: {0}", port.BytesToRead);
        var count = port.BytesToRead;

        byte[] buffer = new byte[count];

        var read = port.Read(buffer, 0, count);

        if (count != read)
            Console.WriteLine("Count <> Read : {0} {1}", count, read);

        var collectAction = new Action(() =>
        {
            var response = dataCollector.Collect(buffer);

            if (response != null)
            {
                this.OnDataReceived(response);
            }
        });

        collectAction.BeginInvoke(null, null);
        Thread.Sleep(100);
    }    
}

Ответы [ 3 ]

3 голосов
/ 12 июня 2009

Вот как я это сделал:

У меня есть оболочка для класса, которая принимает важные данные для соединения в конструкторе и выполняет базовые настройки в этом конструкторе. Потребитель класса вызывает метод Connect, который запускает другой поток для выполнения соединения (неблокирование).

Когда соединение установлено, вызывается StateEvent, указывающее, что соединение установлено. В это время очередь отправки настроена, поток для работы, очередь запускается, и поток чтения также настроен. Поток чтения считывает 128 символов данных из SerialPort, преобразует их в строку и затем запускает событие для передачи полученных данных. Это оборачивается в поток while, который зацикливается, пока поддерживается соединение. Когда потребитель хочет что-то отправить, метод Send просто ставит в очередь данные для отправки.

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

0 голосов
/ 13 августа 2009

Проблема решена:

void port_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
    var count = port.BytesToRead;
    byte[] buffer = new byte[count];
    var read = port.Read(buffer, 0, count);

    var response = dataCollector.Collect(buffer);

    if (response != null)
    {
        this.OnDataReceived(response);
    }            
}

Кажется, проблема не в самом коде, а в коде метода dataCollector.Collect().

0 голосов
/ 07 августа 2009

Разве последовательные порты не веселые. Я думал только о том, что ваш fifo, предполагая, что ваше устройство имеет его и он включен, переполняется.

...