2014-01-15 6 views
7

У меня возникает много проблем, пытаясь получить последовательный порт для получения правильного сообщения. Он продолжает обрезать сообщения. Вот мой код, и я попытаюсь проработать после кода.Проблемы с SerialPort Class

public SerialComms(SerialPort sp) 
{ 
    this.sp = sp; 
    this.sp.Open(); 
    this.sp.DataReceived += new SerialDataReceivedEventHandler(sp_DataReceived); 

    do 
    { 
     Console.WriteLine("port open waiting message"); 
     Console.ReadKey(); 
    } while(!_terminate); 

    this.sp.Close(); 
} 

void sp_DataReceived(object sender, SerialDataReceivedEventArgs e) 
{ 
    string dataReceived; 
    StringComparer strComp = StringComparer.OrdinalIgnoreCase; 
    SerialPort sp = (SerialPort)sender; 
    int i = sp.BytesToRead; 
    byte[] _byte = new byte[i]; 
    char[] _char = new char[i]; 
    sp.read(_byte, 0, i); 
    dataReceived = Encoding.UTF8.GetString(_byte); 
    //dataReceived = new string(_char); 
    //dataReceived = sp.ReadExisting(); 

    if (strComp.Equals("00000000000000"), dataReceived)) 
     _terminate = true; 

    Console.WriteLine(dataReceived); 
} 

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

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

На мониторе последовательного порта передается сообщение (я отправил его три с интервалом в несколько секунд "между каждым отправкой сообщения):
02 31 32 33 34 35 36 37 38 39 30 31 32 33 34 03 .123456789.
02 31 32 33 34 35 36 37 38 39 30 31 32 33 34 03 +0,123456789. 31 32 33 34 35 36 37 38 39 30 31 32 33 34 03 +0,123456789.

на консоли я получил следующее (☺ ♥ и символы 02 и 03 , они STX и ETX сообщение, которое является стандартом для наших передач):
☺123456
789♥

4 ♥

4 ♥

Эта проблема сводит меня с ума !!! Пожалуйста помоги! Унаследовано использование устаревшего MSCommLib, и мы переходим к .Net 4

+0

Я заменил ваши заполнители настоящими символами, если я их отменил, пожалуйста, исправьте. Для скриншотов, ссылки на сайт, например, http://imgur.com/, и более высокий пользователь rep могут повернуть ссылки на изображения. –

ответ

5

Это абсолютно нормальный и распространенный в любом протоколе связи. У TCP по сети есть это свойство. Байты передаются как поток , а не пакет данных. Поэтому, когда срабатывает обработчик событий DataReceived, вы знаете только, что у вас есть байт. Вы должны собрать полученные байты в полный ответ, прежде чем обрабатывать его.

Для этого требуется протокол , способ узнать, что у вас есть полный ответ. У вас есть один, эти байты STX и ETX расскажут вам. ETX, в частности, STX - способ отфильтровать шумовые байты, которые вы можете получить при подключении устройства.

Очень простой способ добиться этого - установить свойство NewLine на (char)3 и просто вызвать ReadLine().

Лучший способ сделать это, чтобы фильтровать шум, который STX помогает устранить, а также позволяет избежать сценария тупиковой:

private const int MaxResponse = 42; 
private const int STX = 2; 
private const int ETX = 3; 
private byte[MaxResponse] response; 
private int responseLength; 

void sp_DataReceived(object sender, SerialDataReceivedEventArgs e) 
{ 
    var sp = (SerialPort)sender; 
    int cnt = sp.BytesToReceive; 
    for (int ix = 0; ix < cnt; ++ix) { 
     byte b = (byte)sp.ReadByte(); 
     if (responseLength == 0 && b != STX) continue; 
     if (b != ETX) response[responseLength++] = b; 
     else { 
      var str = Encoding.ASCII.GetString(response, 0, responseLength); 
      HandleResponse(str); 
      responseLength = 0; 
     } 
    } 
} 

И написать метод HandleResponse() для обработки данных, которые вы получили.

+0

Спасибо, что мне так много работать! Вопрос? Почему у вас ++ длина ответа и смещение индекса ответа [] на 1? Также, чтобы избежать случайного уничтожения ответа [] (в случае, когда он получает только первую часть передачи и затем возвращается с другим вызовом, полученным с помощью DataReceived), не должен быть else if (b == ETX), а затем иначе еще продолжайте; ? Еще раз спасибо, что это была большая проницательность! – alykins

+0

Кроме того, я знаю, что наши сообщения, поступающие из ПЛК, всегда будут 16 байтов (2 байта для сообщения stx/etx, а затем 14 байтов) ... Это вызовет проблему с изменением MaxREsponse int на 16 вместо 42? – alykins

+0

Я ничего не компенсирую на 1, он увеличивается * после этого *. Использование ответа [++ responseLength] было бы неправильным. Ничего не уничтожено, ответ [] не является локальной переменной. Я использовал b! = ETX для удобочитаемости. Разумеется, использование 16. 42 - это просто ответ на жизнь, вселенную и все такое. –

3

Возможна комбинация из двух проблем.

Во-первых, общая ошибка при работе с потоками является то, что только потому, что вы запрашиваете i байт из Read не означает, что Read будет на самом деле читал, что много байт, это не вероятно, ваша проблема, но вы должны знать об этом, see this question's answer for the proper pattern ,

Вторая проблема - это потоки, это потоки, а не сообщения. Он не знает, что вы отправили ☺123456789♥, он просто знает, что он получил ☺123456 между последним проверенным временем и теперь и должен сообщить эту информацию пользователю.

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

+0

+1 Это именно то, что я собирался предложить. Но зачем писать, когда кто-то уже так выразился? :) – itsme86

+0

Благодарим вас за отзыв! Я присоединяюсь к этой теории с приведенным выше примером кода - теперь она имеет гораздо больше смысла! Я думал о завтраке, что, возможно, я должен проверить стартовый байт, который в значительной степени сказал то, что вы сказали: P – alykins

Смежные вопросы