Пожалуйста, простите меня, так как это будет довольно длинный пост. В настоящее время я использую класс SerialPort на C# для написания приложения для связи с устройством под названием Fluke 5500A. В прошлом у меня было много проблем, поскольку количество времени, которое требуется устройству для выдачи команды и возврата того, что оно выводит, в лучшем случае непредсказуемо. Вчера я задал вопрос здесь: System.Timers.Timer Usage Ответ на вопрос замечательный и большую часть времени, кажется, работает отлично. Например, мой класс, который я использую для подключения к SerialPort, теперь выглядит так:
public class SerialPortConnection
{
private SerialPort serialPort;
private string ping;
double failOut;
bool isReceiving;
public SerialPortConnection(string comPort = "Com1", int baud = 9600, System.IO.Ports.Parity parity = System.IO.Ports.Parity.None, int dataBits = 8, System.IO.Ports.StopBits stopBits = System.IO.Ports.StopBits.One, string ping = "*IDN?", double failOut = 2)
{
this.ping = ping;
this.failOut = failOut * 1000;
try
{
serialPort = new SerialPort(comPort, baud, parity, dataBits, stopBits);
serialPort.NewLine = ">";
serialPort.ReadTimeout = 1000;
}
catch (Exception e)
{
serialPort = null;
}
}
//Open Serial Connection. Returns False If Unable To Open.
public bool OpenSerialConnection()
{
//Opens Initial Connection:
try
{
serialPort.Open();
serialPort.Write("REMOTE\r");
}
catch (Exception e)
{
return false;
}
serialPort.Write(ping + "\r");
var testReceived = "";
try
{
testReceived += serialPort.ReadLine();
return true;
}
catch
{
return false;
}
}
public string WriteSerialConnection(string SerialCommand)
{
serialPort.Write(String.Format(SerialCommand + "\r"));
var received = "";
try
{
received += serialPort.ReadLine();
return received;
}
catch
{
received = "Error: No Data Received From Device";
return received;
}
}
public bool CloseSerialConnection()
{
try
{
serialPort.Write("LOCAL\r");
serialPort.Close();
return true;
}
catch (Exception e)
{
return false;
}
}
}
Как видите, когда я открываю соединение с Com1
, я проверяю соединение, записывая команду *IDN?
в SerialPort. Возврат этой команды выглядит так:
FLUKE,5500A,8030005,2.61+1.3+2.0+*
66>
В классе я установил ">"
в качестве свойства NewLine, так что SerialPort.ReadLine() не завершится, пока не найдет этот токен. У меня ни разу не было случая, чтобы сам класс выдавал исключение, но во время отладки я заметил, что иногда testReceived
не может правильно поймать возвращаемые данные, несмотря на то, что исключения не выдаются, и код продолжает выполняться правильно, и вместо этого received
будет поймать возвращаемую строку:
FLUKE,5500A,8030005,2.61+1.3+2.0+*
66>
всякий раз, когда я передаю свою первую команду через SerialPort.Write();
Важно знать, что команды могут выполняться без полного возврата этих данных. Меня беспокоит то, что начальный ReadLine()
, кажется, иногда пропускает это, не улавливая весь возврат. Я думаю, что в устройстве, с которым я общаюсь, есть неотъемлемая ошибка, вызывающая это, но я бы предпочел быть полностью уверенным, прежде чем продолжать.
Мой порядок команд выглядит так:
Сначала я отправляю команду при запуске:
REMOTE
Это отключает взаимодействие с ручным интерфейсом устройства и позволяет мне отправлять команды через последовательный порт.
Затем я выдаю *IDN?
, в данном случае, чтобы проверить, что устройство подключено:
*IDN?
Если ничего не возвращается, приложение настроено на отображение ошибки в окне сообщения, а затем FailFast
. Если все пойдет хорошо, команду можно отправить так:
STBY
OUT 30MV,60HZ
OPER
Единственная команда, представленная здесь вручную, это OUT 30,MV,60HZ
. STBY
и OPER
устанавливаются в app.config, поскольку они только добавляют ненужный шаг к использованию приложения. Команда STBY
переводит машину в режим ожидания из соображений безопасности. Команда OPER
переводит его в рабочий режим, и устройство начинает работать с заданными параметрами.
Затем приложение ожидает, пока технический специалист введет результат в текстовое поле и отправит его. Содержание этих результатов не имеет особого значения, но при нажатии кнопки результата машина снова переходит в режим ожидания:
STBY
Наконец, при закрытии приложения отправляются еще две команды:
*RST
LOCAL
Сначала *RST
сбрасывает машину, чтобы убедиться, что она находится в том же состоянии, что и при включении (т.е. она не работает и параметры не установлены). Затем LOCAL
повторно включает ручной интерфейс для взаимодействия с пользователем и отключает доступ через последовательный порт до тех пор, пока REMOTE
не будет выдано еще раз.
Как видите, команда выдается после *IDN?
и перед первой отправляемой вручную командой (в данном случае мы предполагаем, что это команда OUT 30MV,60HZ
). Проблема в том, что иногда я получаю вывод *IDN
всякий раз, когда я проверяю вывод OUT 30MV,60HZ
, но я не вижу никаких проблем в моем коде или процедуре, которую я использую для работы машины. Есть ли причина, по которой это может происходить?
Как я уже сказал, эту ошибку чрезвычайно трудно воспроизвести (я видел ее дважды, может быть, за сорок прогонов). Тем не менее, любая ошибка такого типа неприемлема в производственной среде, и эту ошибку необходимо исправить, прежде чем я смогу полностью протестировать свое приложение. Я буду продолжать пытаться воспроизвести ошибку, чтобы привести пример и, надеюсь, предоставить дополнительные разъяснения относительно того, в чем может быть проблема.
РЕДАКТИРОВАТЬ:
Я также хотел бы уточнить, что я совершенно уверен, что ошибка не находится где-то в самом моем приложении, поскольку код несколько упрощен по своей природе:
public string SubmitCommand()
{
if (_command_Input != "No further commands to input.")
{
string received;
serialPort.WriteSerialConnection("STBY");
received = serialPort.WriteSerialConnection(_command_Input);
serialPort.WriteSerialConnection("OPER");
//Controls Enabled:
_input_IsEnabled = false;
_user_Input_IsEnabled = true;
_results_Input_IsEnabled = false;
RaisePropertyChanged("Input_IsEnabled");
RaisePropertyChanged("User_Input_IsEnabled");
RaisePropertyChanged("Results_Input_IsEnabled");
return received;
}
else
return "";
}
полученный затем обрабатывается следующим образом:
public bool SetOutput()
{
string inter1 = SubmitCommand();
try
{
string[] lines = inter1.Split(Environment.NewLine.ToCharArray()).ToArray();
_results_Changed = lines[2];
RaisePropertyChanged("Results_Changed");
}
catch
{
_results_Changed = inter1;
RaisePropertyChanged("Results_Changed");
}
return true;
}
Я могу предоставить дополнительный код, если это необходимо, но в настоящее время я не вижу никакого другого кода, который мог бы иметь отношение к рассматриваемому вопросу.
IO.Ports.SerialPort
ужасно сломан. У меня самого были проблемы, и я видел отчеты других о различных проблемах, которые исчезли после перехода на прямое использование Win32. - person Ben Voigt   schedule 16.07.2013IO.Ports.SerialPort
, а не аппаратная ошибка? - person DanteTheEgregore   schedule 16.07.2013ReadLine
истечет время ожидания, не похоже, что у вас есть какая-либо логика восстановления для синхронизации. - person Ben Voigt   schedule 16.07.2013">"
было найденоReadLine()
, а возвращаемая строка не была правильно перехваченаReadLine()
. - person DanteTheEgregore   schedule 16.07.2013IO.Ports.SerialPort
глючит, сколько в плохом дизайне. Это заставляет вас использовать глупый подход, вызывая несущественные API-интерфейсы конфигурации во время открытия, используя потоки пула потоков для получения событий, а затем синхронизируя данные между потоками, не допуская межсимвольных тайм-аутов. Что очень затрудняет правильное использование. - person Ben Voigt   schedule 16.07.2013catch (Exception e) { throw e; }
? Если вы не знакомы с обработкой исключений, этот блок совершенно бесполезен. - person Ben Voigt   schedule 16.07.2013TimeoutException
. Хотя мне интересно, что происходит, если в буфере приема есть>
или просто передается с устройства, когда его программа запускается. - person Ben Voigt   schedule 16.07.2013ReadLine()
всегда должен проверять">"
или ждать, пока не истечет время чтения. Если время чтения истекло, метод возвращаетFalse
иFailFast
включен. Я бы не столкнулся с этой ошибкой, если бы она не встречала">"
. - person DanteTheEgregore   schedule 16.07.201366>
— это приглашение, показывающее, что запись в буфер завершена и устройство готово принять другую команду. - person DanteTheEgregore   schedule 16.07.2013">"
получается после каждой команды, которую я ввожу. Насколько мне известно, это постоянно (могут быть довольно неясные команды, которые я не использую, но они не относятся к делу). В настоящее время я использую WPF и .Net 4.0. - person DanteTheEgregore   schedule 16.07.2013