Закрытие последовательного порта USB оставляет порт недоступным - PullRequest
0 голосов
/ 05 марта 2020

Мое приложение использует последовательные порты USB для подключения к физическим аппаратным устройствам. Я могу открыть любой действительный порт USB и общаться с внешними устройствами. Однако, когда я закрываю соединение, USB-порт некоторое время остается в каком-то неопределенном состоянии, и в течение этого времени дальнейшие попытки повторного подключения приводят к ошибке «Доступ к порту« COM-- »запрещен». Однако через несколько секунд попытка переподключения успешна. Как определить, КОГДА USB-порт снова будет поддерживать новое соединение?

Код выглядит следующим образом:

    private void Setup(string Port)
    {
        bool ValidPort = false;
        int CloseSleep = 10;

        _PortName = Port;
        _PortType = this;

        string[] AvailablePorts = SerialPort.GetPortNames();  

        foreach(string aPort in AvailablePorts)
        {
            if (aPort == _PortName)
            {
                // The required port is listed in the list of available ports)
                ValidPort = true;
                break;
            }
        }

        if (ValidPort)
        {
            try
            {
                if (_ThePort != null)
                {
                    _ThePort.Close();
                    _ThePort.DataReceived -= ReceivedDataEventHandler;

                    while(CloseSleep-- > 0)
                        System.Threading.Thread.Sleep(100);

                    _ThePort.Dispose();
                    _ThePort = null;
                }
            }
            catch (Exception ex)
            {
                EMS_Config_Tool.ModalDialog md = new EMS_Config_Tool.ModalDialog("Closing Port: " + ex.Message, "System Exception");
                md.ShowDialog();
            }

            System.IO.Ports.SerialPort TheNewPort = new System.IO.Ports.SerialPort(Port, 38400);

            // Setup the event handlers from Tx and Rx
            Handler.DataOutEvent    += CommsSender;
            TheNewPort.DataReceived += ReceivedDataEventHandler;

            TheNewPort.DataBits  = 8;
            TheNewPort.Parity    = Parity.None;
            TheNewPort.Handshake = System.IO.Ports.Handshake.None;
            TheNewPort.StopBits  = System.IO.Ports.StopBits.One;

            // We will try 3 times to open the port, and report an error if we fail to open the port
            try
            {
                TheNewPort.Open();
            }
            catch (Exception)
            {
                System.Threading.Thread.Sleep(1000);

                try
                {
                    TheNewPort.Open();
                }
                catch (Exception)
                {
                    System.Threading.Thread.Sleep(1000);

                    try
                    {
                        TheNewPort.Open();
                    }
                    catch (Exception ex)
                    {
                        EMS_Config_Tool.ModalDialog md = new EMS_Config_Tool.ModalDialog("Opening Port: " + ex.Message, "System Exception");

                        return;
                    }
                }
            }

В последнем выражении catch выдается ошибка об отказе в доступе. , Обратите внимание, что моя попытка повторить попытку открытия порта 3 раза не очень помогает. Если я оставлю порт в покое примерно на 5–10 секунд и снова попытаюсь вызвать метод установки, он сразу преуспеет.

Ответы [ 2 ]

0 голосов
/ 06 марта 2020

Я исправил свой код, чтобы использовать ограниченное l oop, чтобы дать ему больше шансов на работу, что обычно и происходит. Я надеялся, что есть лучший способ сделать это, так как у меня есть довольно нетерпеливые пользователи, которые будут публиковать отчеты о дефектах, если им придется ждать 5 или 10 секунд, чтобы установить соединение ....

            // We will try several times to open the port, upto 10 times over 5 seconds, and report an error if we finally fail to open the port
            try
            {
                TheNewPort.Open();
            }
            catch (Exception ex)
            {
                RetryOpenTimer.Interval = 500;
                RetryCount = 10;
                RetryOpenTimer.Elapsed += new System.Timers.ElapsedEventHandler(RetryOpenTimer_Elapsed);
                WaitForOpen = true;
                RetryOpenTimer.Start();

                while (WaitForOpen && RetryCount > 0)
                {
                    System.Threading.Thread.Sleep(500);
                }
                if (WaitForOpen)
                {
                    EMS_Config_Tool.ModalDialog md = new EMS_Config_Tool.ModalDialog("Opening Port: " + ex.Message, "System Exception");
                    return;
                }
            }

...

    void RetryOpenTimer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
    {
        RetryOpenTimer.Stop();
        RetryOpenTimer.Elapsed -= RetryOpenTimer_Elapsed;

        try
        {
            if (RetryCount-- > 0)
            {
                TheNewPort.Open();

                WaitForOpen = false;
            }
            else
                return;
        }
        catch (Exception)
        {
            RetryOpenTimer.Start();
            RetryOpenTimer.Elapsed += RetryOpenTimer_Elapsed;
        }
    }
0 голосов
/ 05 марта 2020

Как сказал @Neil, проблем много. Лучше всего, на мой взгляд, поместить поиск в al oop, и как только будет открыт порт, он будет.

Я делал так:

public Task WaitingPort()
{
    while (port is null)
        {
            port = CheckPort();
        }
}

private SerialPort CheckPort()
{
    string[] listPort = SerialPort.GetPortNames();
    foreach(string namePort in listPort)
    {
        SerialPort port = new SerialPort(namePort, 9600);
        if (!port.IsOpen)
        {
            try
            {
                port.Open();
                port.ReadTimeout = 1500;
                string data = port.Readline();
                // I programmed my device to send an "A" until it receives
                // "777" to be able to recognize it once opened
                if (data.Substring(0, 1) == "A") 
                {
                    port.ReadTimeout = 200;
                    port.Write("777"); // to make it stop sending "A"
                    return port;
                }
                else
                {
                port.Close();
                }
            }
            catch (Exception e1)
            {
                port.Close();
            }
        }
    }
    return null;
}

Конечно, это просто какой-то шаблон, который вы должны изменить в соответствии с вашими потребностями

...