2013-05-23 5 views
2

Я создаю прототип своего рода док-станции на базе Arduino для планшета, используя USB-порт в качестве разъема. Это означает, что мне нужно поддерживать возможность подключения/отсоединения USB-разъема при работе приложения на планшете.СОМ-порт исчезает при отсоединении USB

Планшет запускает приложение C# (.net 4.5 на Win7 64 бит), в котором я подключаюсь к Arduino Uno. Когда приложение запускается цикл I все доступные COM-порты с помощью:

var ports = SerialPort.GetPortNames(); // -> [COM3,COM4,COM8] 
foreach (var port in ports) 
{ 
    var serial = new SerialPort(portname, baudRate); 
    //attempt handshake and connect to right port 
} 

Эта работа хорошо, но если я отключите и снова подключите кабель USB и повторить попытку повторного подключения к Arduino (в то время как приложение все еще работает), то не Arduino порт (COM8) больше не перечислены в:

SerialPort.GetPortNames(); // -> [COM3,COM4] and no COM8 

Даже перезапуска приложения (с Arduino клеммного блока) приведет только [COM3, COM4] быть в списке.

Единственный способ вернуть его на работу - отключить и поменять Arduino, пока приложение не работает.

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

Проблема возникает только при отключении и повторном подключении устройства при запуске приложения. Кажется, что, несмотря на возможность сброса COM-порта (в коде или вручную в диспетчере устройств), SerialClass (и собственный Win32_SerialPort - я тоже это проверил) не распознал это, если я не перезапустил приложение

Что может быть причина этого? И как я могу убедиться, что мое приложение может подключиться к этому порту? Существуют ли альтернативы использованию SerialPort для работы с USB-разъемом?

+0

Просто второй здесь, вы используете последовательный порт в качестве USB-порт или USB-порт, как последовательный порт? AFAIK, каждый раз, когда вы снова подключаете COM-порт, вам необходимо перезагрузить его. – Shark

+0

последовательный порт, я все время подключаю к серверам с перезагрузкой. Реальные последовательные порты (rs-232) очень надежны. (Я думал) –

+0

Когда виртуальный COM-порт уходит, поэтому все его интерфейсы и приложение, подключенные к ним, должны иметь дело с этими исключениями, а затем попытаться их снова открыть , Большинство приложений, использующих последовательные порты, являются старыми и не справляются с копированием того, что, как ожидается, являются аппаратными интерфейсами, что часто приводит к потере ресурса до перезагрузки. Я отмечаю, что Serial Monitor Arduino справляется с этим, за исключением довольно хорошо и восстанавливается. Он делает много шума на выходе на консоль. Возможно, вам захочется посмотреть, как это происходит, и перенести его на C# – mpflaga

ответ

2

Я нашел решение, которое может обрабатывать подключение и отключение с SerialPort.

Прежде всего, для этого необходимо использовать SafeSerialPort, что позволяет правильно утилизировать последовательный порт.

SafeSerialPort serialPort; 

private void Connect() 
{ 
    string portname = "COM8"; 
    serialPort = new SafeSerialPort(portname, 9600); 
    serialPort.DataReceived += port_DataReceived; 
    serialPort.Open(); 
} 

Во-вторых, вам нужно использовать LibUsbDotNet обнаружить, подключен ли устройство USB или отсоединен. Это позволит вам определить, следует ли подключаться к устройству или сбросить COM-порт.

public UsbDevice MyUsbDevice; 

//Find your vendor id etc by listing all available USB devices 
public UsbDeviceFinder MyUsbFinder = new UsbDeviceFinder(0x2341, 0x0001); 
public IDeviceNotifier UsbDeviceNotifier = DeviceNotifier.OpenDeviceNotifier(); 
private void OnDeviceNotifyEvent(object sender, DeviceNotifyEventArgs e) 
{ 
    if (e.Object.ToString().Split('\n')[1].Contains("0x2341")) 
    { 
     if (e.EventType == EventType.DeviceArrival) 
     { 
      Connect(); 
     } 
     else if(e.EventType == EventType.DeviceRemoveComplete) 
     { 
      ResetConnection(); 
     } 
    } 
} 

Наконец, располагая SerialPort волю убеждается он зарегистрирован в ОС Windows HKEY_LOCAL_MACHINE \ HARDWARE \ DEVICEMAP \ SERIALCOMM, что означает, что SerialPort.GetPortNames() может повторно обнаружить порт.

private void ResetConnection() 
{ 
    try 
    { 
     //Send any data to cause an IOException 
     serialPort.Write("Any value"); 
    } 
    catch (IOException ex) 
    { 
     //Dispose the SafeSerialPort 
     serialPort.Dispose(); 
     serialPort.Close(); 
    } 
} 

После этого процесса вы можете просто подключиться к COM-порту при подключении USB-устройства без необходимости перезапуска приложения.

Полный код:

using LibUsbDotNet; 
using LibUsbDotNet.DeviceNotify; 
using LibUsbDotNet.Info; 
using LibUsbDotNet.Main;  

SafeSerialPort serialPort; 

      public SerialPortTest() 
      { 
       Connect(); 

       UsbDeviceNotifier.OnDeviceNotify += OnDeviceNotifyEvent; 
      } 

      private void Connect() 
      { 
       string portname = "COM8"; 
       serialPort = new SafeSerialPort(portname, 9600); 
       serialPort.DataReceived += port_DataReceived; 
       serialPort.Open(); 
      } 

      private void ResetConnection() 
      { 
       try 
       { 
        serialPort.Write("Any value"); 
       } 
       catch (IOException ex) 
       { 
        serialPort.Dispose(); 
        serialPort.Close(); 
       } 
      } 


      void port_DataReceived(object sender, SerialDataReceivedEventArgs e) 
      { 
       Console.WriteLine(serialPort.ReadExisting()); 
      } 

      public UsbDevice MyUsbDevice; 

      //Vendor ID etc can be found through enumerating the USB devices 
      public UsbDeviceFinder MyUsbFinder = new UsbDeviceFinder(0x2341, 0x0001); 
      public IDeviceNotifier UsbDeviceNotifier = DeviceNotifier.OpenDeviceNotifier(); 
      private void OnDeviceNotifyEvent(object sender, DeviceNotifyEventArgs e) 
      { 
       //if this is your usb device, in my case an Arduino 
       if (e.Object.ToString().Split('\n')[1].Contains("0x2341")) 
       { 
        if (e.EventType == EventType.DeviceArrival) 
        { 
         Connect(); 
        } 
        else 
        { 
         ResetConnection(); 
        } 
       } 
      } 
1

Так что я считаю, что это происходит потому, что ваша программа кэширования адреса USB первый раз, когда он подключен к сети.

Когда кто-то подключает устройство, концентратор обнаруживает напряжение на любом D + или D- и сигнализирует о вставке на хост через это прерывание . Когда хост опросит эту конечную точку прерывания, он узнает, что новое устройство присутствует. Затем он инструктирует концентратор (через управляющий канал по умолчанию ), чтобы восстановить порт, в котором было подключено новое устройство. *** Этот сброс делает новое устройство принятым адресом 0,, а хост может , а затем взаимодействовать с ним непосредственно; это взаимодействие приведет к тому, что хост назначит новому (ненулевому) адресу устройству.

Ваш лучший выбор - научиться программировать сброс кеша адресов USB-устройств.

Ссылка: http://en.wikipedia.org/wiki/USB_hub

+0

То, что вы описываете, происходит на гораздо более низких уровнях. –

+0

@BenVoigt Я согласен, но я все еще думаю, что это проблема. Вероятно, ему нужно вручную вызвать обновление. –

+0

Но он видит только сбой, если его приложение имеет последовательный порт, открытый, когда устройство отключено. –