#c_sharp
Имеется следующий код. public static class PortHandler { private static ConnectionType _state; private static SerialPort _port; public static void init() { _state = ConnectionType.DETACHED; Thread serialMonitor = new Thread(SerialMonitor); serialMonitor.IsBackground = true; serialMonitor.Start(); } static void SerialMonitor() { while (true) { switch (_state) { case ConnectionType.DETACHED: scanPorts(); break; case ConnectionType.CONNECTED: FormFunctions.writeLog("Check Port. Size: " + SerialPort.GetPortNames().Length, MessageType.INFO); try { _port.Write(new byte[1] { 0x00 }, 0, 1); } catch (Exception e) { FormFunctions.writeLog("Fault to connect to " + _port.PortName + ". Exception: " + e, MessageType.INFO); _state = ConnectionType.DETACHED; } break; } Thread.Sleep(1000); } } private static void scanPorts() { string[] ports = SerialPort.GetPortNames(); if (ports.Length == 0) { FormFunctions.writeLog("Port list is empty.", MessageType.INFO); return; } foreach (string port in ports) { if (checkSerialPort(port)) { FormFunctions.writeLog("Port connected.", MessageType.SUCCESS); _state = ConnectionType.CONNECTED; break; } } } private static Boolean checkSerialPort(string name) { _port = new SerialPort(name); _port.BaudRate = 9600; _port.Parity = Parity.None; _port.StopBits = StopBits.One; _port.DataBits = 8; _port.Handshake = Handshake.None; _port.PinChanged += new SerialPinChangedEventHandler(SerialPinChangedEventHandler); _port.Open(); byte[] init = new byte[4] { 0xa1, 0xa1, 0xa1, 0xa1 }; _port.Write(init, 0, init.Length); return true; } private static void SerialPinChangedEventHandler(object sender, SerialPinChangedEventArgs e) { FormFunctions.writeLog("Pin Changed Event: " + e, MessageType.SUCCESS); } } Если закомментировать все стройчки с подключением к порту и отправкой информации, то в логах программы регистрируются все ивенты с подключением/отключением устройства синхронно со звуком в системе. Но стоит создать подключение, то всё работает до (!) эмуляции отвала устройства. Т.е. если я вручную выдёргиваю девайс, то получаю IO Exception на строке _port.Open(); Лог работы программы следующий: 12.12.2017, 11:57:11 [INFO]: Port list is empty. 12.12.2017, 11:57:12 [INFO]: Port list is empty. 12.12.2017, 11:57:13 [INFO]: Port list is empty. 12.12.2017, 11:57:14 [INFO]: Port list is empty. 12.12.2017, 11:57:15 [INFO]: Port list is empty. 12.12.2017, 11:57:16 [INFO]: Port list is empty. 12.12.2017, 11:57:17 [SUCCESS]: Port connected. 12.12.2017, 11:57:18 [INFO]: Check Port. Size: 1 12.12.2017, 11:57:19 [INFO]: Check Port. Size: 1 12.12.2017, 11:57:20 [INFO]: Check Port. Size: 1 12.12.2017, 11:57:21 [INFO]: Check Port. Size: 1 12.12.2017, 11:57:22 [INFO]: Check Port. Size: 1 12.12.2017, 11:57:22 [INFO]: Fault to connect to COM15. Exception: System.IO.IOException: Порт 'COM15' не существует. в System.IO.Ports.InternalResources.WinIOError(Int32 errorCode, String str) в System.IO.Ports.SerialStream.EndWrite(IAsyncResult asyncResult) в System.IO.Ports.SerialStream.Write(Byte[] array, Int32 offset, Int32 count, Int32 timeout) в System.IO.Ports.SerialPort.Write(Byte[] buffer, Int32 offset, Int32 count) в Infrared.common.PortHandler.SerialMonitor() в C:\...\PortHandler.cs:строка 42 Пробовал использовать ивент SerialPinChangedEventHandler, но никакой реакции на него нет. Также пробовал принудительно завершать текущее подключение, но получаю ошибку NPE на функции _port.Close(). Подскажите, где я неправ. P.S. Или статический класс не подходящий пример решения моей задачи, т.к. Dispose() с ним не работает? P.S.S. Есть ли смысл реализовать это в инстансе на Singleton?
Ответы
Ответ 1
По поводу SerialPort.Open(): Работает оно маленько не так как вы ожидаете. Если устройства не будет физические или оно в не валидном состоянии(см. MSDN), то этот метод выдаст исключение. Скорее всего этот метод вызывает внутри себя апишную CreateFile. По этому можно представить поведение SerialPort.Open(), как открытие файла и так его нет соответственно выбрасывается исключение. Но есть одно но. Если у вас порт на матиринке, то он будет виден даже когда устройство не подключено. И в этом случае SerialPort.Open() скорее всего завершится без ошибок, и возможно даже ОС даст вам слать туда данные. По поводу SerialPinChangedEventHandler Судя по документации нет ни каких гарантий, что это событие будет работать со всеми устройствами или дровами. Тут я могу ошибаться так как работать с этим не приходилось. По поводу Dispose() и Singleton Вызывать Dispose() считается хорошим тоном, даже если у вас объект живет в течении всего времени работы приложения. Но в вашем примере оно в принципе не особо нужно.Ответ 2
Должно же кому-то пригодиться. Судя из англоязычных форумов, сама Microsoft не даёт никаких гарантий на то, что сама реализация SerialPort() будет работать корректно. Это зависит от многих условностей: тип порта, драйвера, аппаратная реализация (какие каналы задействованы) и прочее, прочее, прочее. А также, стоит отметить что некоторые функции, например: SerialPort.Close() могут содержать несколько инструкций, которые могут генерировать собственные исключения. Но при этом они завершают, скажем так, начатое. Моя проблема с "залипанием" соединения на порту при "отвале" устройства (виртуальный COM порт) была решена просто: if (_port != null) { try { _port.Close(); } catch (Exception e) { // Ignore pointless exception. } _port = null; } Это необходимо добавлять в catch() блок где находится функция записи в порт. Иными словами, если запись в порт невозможна, то "убиваем не убитое". В итоге, порт освобождается и объект не содержит больше ничего. Что позволяет продолжать мониторинг "реальных" портов в системе и осуществлять повторное подключение по доступности. Со стороны это выглядит как мега костыль. P.S. Я сильно ошибался, считая Java самым убогим языком ООП. Каюсь.
Комментариев нет:
Отправить комментарий