Добро пожаловать в форум, Guest  >>   Войти | Регистрация | Поиск | Правила | В избранное | Подписаться
Все форумы / WinForms, .Net Framework Новый топик    Ответить
 Чтение из COM-порта без признака окончания передачи информации  [new]
WinterGraveyard
Member

Откуда:
Сообщений: 55
Ситуация: на COM-порт поступают некие данные. Размер пакета - от 4 до 8 байт. Данные поступают не непрерывно - т.е., например, пришло 6 байт, потом пауза минут 5, потом пришло 8 байт, пауза 2 секунды, пришло еще сколько-то байт. Можно считать, что минимальная пауза передачи данных - 1 секунда. Данные не содержат никаких признаков начала/окончания передачи. EOF на порт также не поступает - пишущая сторона постоянно держит свой порт открытым. Плюс есть еще такой нюанс: в зависимости от причин непонятного характера, весь пакет можно сразу получить на единственном срабатывании DataReceived - т.е. весь пакет находится внутри буфера чтения порта. А иногда получение пакета происходит за несколько срабатываний DataReceived, т.е. в буфер чтения пакет попадает порциями. При этом эмпирически выяснено, что между срабатываниями DataReceived при получении одного пакета интервал не более 0.1 сек. Вопрос: каким образом можно при считывании очередного пакета сгенерировать событие для передачи данных на обработку? Навскидку в голову приходит решение держать в переменной класса-обертки над COM-портом время последнего срабатывания DataReceived, если разница текущего времени, и времени последнего срабатывания больше 1 сек., то началась передача новой порции данных, и предыдущую можно отдавать на обработку. Но требуется полученную порцию данных отдавать на обработку сразу, как только истечет минимальный интервал паузы передачи данных (та самая 1 секунда). В DataReceived запускать таймер с таймаутом в 1 сек. (и который по срабатыванию будет райзить событие для обработки), если новый DataReceived сработал с интервалом меньше 1 сек., то останавливать таймер, и запускать его заново? Вместо таймера запускать Task? Еще как-то? Как лучше поступить в вышеописанной ситуации?
6 мар 19, 15:05    [21826383]     Ответить | Цитировать Сообщить модератору
 Re: Чтение из COM-порта без признака окончания передачи информации  [new]
Изопропил
Member

Откуда:
Сообщений: 30997
WinterGraveyard,

SetCommTimeouts из WinAPI
6 мар 19, 15:22    [21826401]     Ответить | Цитировать Сообщить модератору
 Re: Чтение из COM-порта без признака окончания передачи информации  [new]
WinterGraveyard
Member

Откуда:
Сообщений: 55
Изопропил
WinterGraveyard,

SetCommTimeouts из WinAPI

Спасибо за указание в нужном направлении - у SerialPort есть свойство ReadTimeout, при установке которого как раз вызывается SetCommTimeouts. По умолчанию оно равно бесконечности, мне просто нужно было на время чтения очередной порции выставить его в минимальный промежуток времени между поступлением порций. Сделал примерно так:
public event Action<byte[]> OnPacketReceived;

const int PacketReadTimeout = 500;
const int MaxPacketSize = 8;

readonly List<byte> _readBuffer = new List<byte>(MaxPacketSize);

void ListenPort(object sender, SerialDataReceivedEventArgs args)
{
  if (args.EventType == SerialData.Eof)
    return;
  if (_scannerPort.ReadTimeout != PacketReadTimeout)
    _scannerPort.ReadTimeout = PacketReadTimeout;
  try
  {
    while (_readBuffer.Count<MaxPacketSize)
    {
      var current = _scannerPort.ReadByte();
      if (current == -1) break;
      _readBuffer.Add((byte)current);
    }
    ReadCompleted();
  }
  catch (TimeoutException)
  {
    ReadCompleted();
  }
  catch (Exception e)
  {
    LogManager.GetLogger("*").Error(e.StackTrace);
  }
}

void ReadCompleted()
{
  _scannerPort.ReadTimeout = SerialPort.InfiniteTimeout;
  _scannerPort.DiscardOutBuffer();
  OnPacketReceived?.Invoke(_readBuffer.ToArray());
  _readBuffer.Clear();
}
7 мар 19, 14:06    [21827318]     Ответить | Цитировать Сообщить модератору
Все форумы / WinForms, .Net Framework Ответить