обработка последовательного порта вопрос / ответ в C # - PullRequest
1 голос
/ 24 марта 2009

Хорошо, вот проблема (это связано с моим предыдущим постом)

Мне нужно иметь систему выдачи / ответа для последовательной связи, которая работает примерно так:

выпуск: привет Ответ: мир? вопросы: нет, привет медсестра ответ: ну, ты не весело.

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

a ReaderWriterLock'd 'readBuffer' Метод выпуска, который будет записывать в поток Метод ответа, который будет наблюдать за readBuffer, пока он не будет содержать то, что я ожидаю, или пока не истечет время ожидания.

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

Ответы [ 2 ]

4 голосов
/ 24 марта 2009

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

Вот несколько мыслей по этому поводу:

a) FIFO-буфер (очередь)

Прежде всего, у вас должен быть экземпляр поточно-ориентированной очереди (буфер FIFO) для каждого экземпляра вашего класса. Один поток получит данные и заполнит их, а другой прочитает данные потокобезопасным способом. Это только означает, что вам придется использовать блокировку при каждой операции постановки / снятия с очереди.

Очередь FIFO позволит вам одновременно обрабатывать данные в рабочем потоке, заполняя их из потока связи. Если вам необходимо получить много данных, вы можете удалить из очереди некоторые данные в рабочем потоке и проанализировать их до того, как все они будут получены. В противном случае вам нужно будет подождать, пока все данные не будут получены, чтобы проанализировать все сразу. В большинстве случаев вы не знаете, сколько данных вы должны получить, пока не начнете их анализировать.

b) Рабочий поток ожидает данных

Я бы создал рабочий поток, который будет ожидать сигнала о получении новых данных. Вы можете использовать ManualResetEvent.WaitOne(timeOut) для тайм-аута, если какое-то время ничего не происходит. Когда данные получены, вам придется их анализировать, исходя из вашего текущего состояния - так что это будет реализация конечного автомата .

c) Абстракция порта

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

 interface IPort
 { 
      void Open();
      void Close();
      event EventHandler<DataEventArgs> DataReceived;
      void Write(Data data);
 }

Это поможет вам отделить конкретный код связи от конечного автомата.

Примечание: (согласно Microsoft) Событие DataReceived не гарантируется для каждого полученного байта. Используйте свойство BytesToRead, чтобы определить, сколько данных осталось для чтения в буфере . Таким образом, вы можете создать свою собственную реализацию IPort, которая будет опрашивать SerialPort через регулярные промежутки времени, чтобы гарантировать, что вы не пропустите байт (есть вопрос SO, который уже решает эту проблему).

d) Получение данных

Чтобы получить данные, вам нужно будет прикрепить обработчик для события IPort.DataReceived (или SerialPort.DataReceived, если вы его не переносите) и поставить в очередь полученные данные в очередь внутри обработчика. В этом обработчике вы также установили бы упоминание ManualResetEvent, чтобы уведомить рабочий поток о получении новых данных.

0 голосов
/ 24 марта 2009

У меня была похожая проблема с написанием асинхронного прослушивателя сокетов для форматированных данных. Перевод того, что я придумал, в модель SerialPort / DataReceived будет выглядеть примерно так:

Основной класс инкапсулирует систему вопросов / ответов - он будет содержать логику для генерации ответа на основе входных данных. Каждый экземпляр класса будет связан с одним последовательным портом, который можно установить во время или после создания. Будет метод типа StartCommunications - он соединит событие DataReceived с другим методом в классе. Этот метод отвечает за получение данных из порта и определение того, поступило ли полное сообщение. Если это так, он вызывает свое собственное событие (определенное в классе), к которому будет подключен соответствующий метод. Вы также можете вызывать предопределенный метод в своем классе вместо того, чтобы вызывать событие - я определил событие для повышения гибкости.

Этот базовый проект прекрасно работает в производственной системе и может обрабатывать больше входных данных, чем остальные системы, подключенные к нему.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...