Требуется помощь .NET Serial Port, в первую очередь с данными, полученными в нескольких пакетах.

Я новичок в отправке данных через последовательный порт через .net, и я заметил, что после реализации TCP-аналога мне было бы не так просто с последовательным портом!

Итак, начнем с самого начала, я почти закончил свою реализацию последовательной двунаправленной связи. Я просто застрял на нескольких вещах: -

  1. Мои чтения разделены на несколько сообщений или получены как фрагментированный ответ через COM-порт, и я не знаю, какие настройки мне могут понадобиться или как я должен написать код по-другому, чтобы исправить это. Что может быть причиной этого? Я проверяю сообщение в точке останова SerialPort_DataReceived.

В основном данные должны быть отправлены как:

01: LS|DA090521|TI111043|q
02: PS|RN102|PTC|TA1040000|P#0|DA090521|TI111429|j

но он разделяется (в случайных позициях при каждом запрошенном чтении)

01: LS|DA090521|TI111
02: 043|q
03: PS|RN102|PTC|TA1
04: 0000|P#0|DA090521|TI111429|j

– На вопрос 1 дан ответ, спасибо, Крис В. и другие! Теперь у меня есть сообщение, которое, как я ожидаю, будет постепенно строиться из фрагментов (с учетом STX, {msg body}, ETX), а затем выполняется действие, когда сообщение было полностью построено, и оно работает с потокобезопасной очередью, очень доволен .

. 2. Я получаю "|" символ через мое чтение почти каждый цикл, это из-за команды, которую я как-то неправильно установил, артефакта последовательной связи или чего-то, что устройство отправляет мне? (Хотя я так не думаю, поскольку подключение к гипертерминалу показывает, что этот символ не отправляется постоянно.)

. 3. Можете ли вы подтвердить, что я правильно читаю и записываю данные в соответствующих методах.

Спасибо, ребята, что посмотрели и мои другие два вопроса.

Соответствующий код следующим образом:

...
    //                          COM3,    9600,     None,   8,        One
    SerialPort = new SerialPort(comPort, baudRate, parity, dataBits, stopBits);
    if (SerialPort.IsOpen) SerialPort.Close();
    // SerialPort.RtsEnable = true; // Request-to-send
    // SerialPort.DtrEnable = true; // Data-terminal-ready
    SerialPort.ReadTimeout = 150; // tried this, but didn't help
    SerialPort.WriteTimeout = 150; // tried this, but didn't help
    SerialPort.Open();

    SerialPort.DataReceived += new SerialDataReceivedEventHandler(SerialPort_DataReceived);
}

void SerialPort_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
    // Process received data
    SerialPort sp = (SerialPort)sender;
    byte[] buffer = new byte[sp.BytesToRead];
    int bytesRead = sp.Read(buffer, 0, buffer.Length);

    // message has successfully been received
    message = Encoding.ASCII.GetString(buffer, 0, bytesRead);
}

public bool SendMessage(string text)
{
    // Only send message if a client is connected
    if (SerialPort != null && SerialPort.IsOpen)
    {
        byte[] buffer = Encoding.ASCII.GetBytes(text);
        SerialPort.Write(buffer, 0, buffer.Length);
    }
}

person GONeale    schedule 21.05.2009    source источник


Ответы (3)


Мои чтения разделены на несколько сообщений

Это нормальное, ожидаемое, неизбежное поведение. Это может произойти и с передачей данных по TCP. Для последовательного интерфейса это просто бесконечный поток байтов. Ваше приложение несет ответственность за переупаковку этих байтов в пакеты.

Если расположение границ пакетов важно и вы не можете сказать, где должны быть границы пакетов, глядя на полученные данные, вам может потребоваться переосмыслить формат данных, чтобы вы могли< /em> сообщить, где находятся границы пакета.

Я получаю "|" символ через мое чтение почти каждый цикл

Каково шестнадцатеричное значение этого символа? Посмотрите, улучшит ли ситуацию установка свойства Handshake на XOnXOff или RequestToSendXOnXOff.

person ChrisW    schedule 21.05.2009
comment
Спасибо за ответ, Крис, ценю это. Хорошо, возможно, я пытаюсь поместить это в слишком узкие рамки, если вы говорите, что нам почти нужно сделать собственное «управление пакетами», которое, к стыду (я не осознавал), вероятно, является основой для последовательного транспорт, тогда мне, возможно, потребуется опросить начало символов сообщения/конец сообщения, упаковать его, очистить, промыть и повторить. - person GONeale; 21.05.2009
comment
тогда не знаю; значения XON/XOFF по умолчанию — 0x13 и 0x11:- en.wikipedia.org/wiki/XON - person ChrisW; 21.05.2009
comment
Спасибо за ваши предложения Крис! Теперь у меня есть сообщение, которое создается постепенно (ища STX, {msg body}, ETX), а затем выполняется действие, когда сообщение полностью построено, и оно работает с потокобезопасной очередью‹T›, очень доволен. - person GONeale; 21.05.2009
comment
Звучит правильно, и я уверен, что вы понимаете такие слова, как ETX. Также имеется полезное свойство ReadIntervalTimeout в структуре COMMTIMEOUTS, передаваемой функции Win32 SetCommTimeouts, которое может вам подойти, если DCE отправляет целые пакеты с небольшой задержкой между каждым байтом и некоторой задержкой между каждым пакетом; но .NET API явно не включает эту функцию/свойство. - person ChrisW; 21.05.2009

На нижнем уровне последовательный порт может решить, когда инициировать событие получения данных. Он может принять решение сделать это до прибытия «полного» пакета. Но похоже, что в ожидаемом наборе данных у вас есть символ терминатора. Если это так, вы можете сделать следующее (обратите внимание, что я изменил ваше назначение SerialPort, чтобы избежать путаницы в синтаксисе:

        p = new SerialPort(PortName, BaudRate, Prty, DataBits, SBits);
        p.NewLine = Terminator;

где Terminator — это строка, содержащая ваши символы завершения. Затем вы можете использовать SerialPort.ReadLine() (и SerialPort.WriteLine(), если это применимо). Это может помочь, по крайней мере, с вашей первой проблемой.

person Community    schedule 21.05.2009
comment
Спасибо, чтение подсказки о NewLine имеет смысл, я слишком привык к TCP и идее создания и обработки пакетов для вас. Я просто предположил, что могу отправлять сообщения, а затем получать их. :) - person GONeale; 21.05.2009
comment
Как видите, мой символ NewLine должен быть 0x03, ну, на самом деле 0x03 + j. Мы понятия не имеем, почему он печатает случайный альфа-символ в конце, сейчас он всегда имеет тенденцию быть j. Я не знаю, коррелирует ли это, и я должен понимать NewLine как символ / символы, на которые я хочу разделить полученные данные? - person GONeale; 21.05.2009
comment
p.NewLine может быть строкой с любым количеством символов. Я когда-либо работал только с устройствами, где это \n или \r\n, но все что угодно. Какой последний символ в первой строке вашего примера пакета? - person ; 21.05.2009
comment
Ну, 0x03 (это ). Но мне нужно будет проверить 0x03 + случайный символ, который, как я узнал позже, является BCC (символ проверки блока). - person GONeale; 22.05.2009
comment
Извините, я использовал старый браузер, который странно отображал 0x03. В любом случае, да, вы можете установить p.Terminator = \x03, затем использовать p.ReadLine() и, возможно, удалить делегата в придачу. С другой стороны, в .NET есть свойства p.ReadTimeout и p.WriteTimout, указанные в целых миллисекундах. Надеюсь, эта информация вам еще пригодится! - person ; 27.05.2009

Я много занимался программированием последовательного порта Win32, но совсем немного с .NET, так что прислушайтесь к моему совету с долей скептицизма.

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

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

Если вы хотите получить больше данных, вы можете попробовать следующее:

  • настройка свойства System.Int32 ReceivedBytesThreshold
  • с использованием синхронного ввода-вывода и указанием фиксированного количества байтов для чтения, а не приема на основе событий

Я получаю "|" символ через мое чтение почти каждый цикл, это из-за команды, которую я как-то неправильно установил, артефакта последовательной связи или чего-то, что устройство отправляет мне? (Хотя я так не думаю, поскольку подключение к гипертерминалу показывает, что этот символ не отправляется постоянно.)

Если вам интересно, что происходит дальше, проверьте PortMon от SysInternals., бесплатное приложение, которое будет отслеживать ваш COM-порт во время передачи данных по линии. Это кажется техническим, но на самом деле вам просто нужно взглянуть на команды IRP_MJ_WRITE и IRP_MJ_READ, и в строке вы увидите длину в байтах и ​​данные, отправленные по сети. При этом вы сможете определить, связана ли проблема с объектом .NET SerialPort или же устройство действительно отправляет «|» над линией.

Можете ли вы подтвердить, что я правильно читаю и записываю данные в соответствующих методах.

Это выглядит правильно для событийного метода получения данных.

person Dr. Watson    schedule 21.05.2009
comment
Отлично, действительно проницательно, особенно инструмент PortMon. Это должно дать мне знать, откуда он исходит. Сейчас я обрабатываю свой пакет вручную, и это работает хорошо, я обновлю свой пост для пункта 1. - person GONeale; 21.05.2009