简体   繁体   English

关闭 USB 串行端口会使端口不可用

[英]Closing a USB serial port leaves the port unavailable

My app uses USB based serial ports to connect to physical hardware devices.我的应用程序使用基于 USB 的串行端口连接到物理硬件设备。 I can open any valid USB port and communicate with the external devices.我可以打开任何有效的 USB 端口并与外部设备通信。 However, when I close the connection, the USB port is left in some sort of indeterminate state for some time, and during that time further attempts to reconnect result in the "Access to port "COM--" is denied" error.但是,当我关闭连接时,USB 端口会在一段时间内处于某种不确定状态,并且在此期间进一步尝试重新连接会导致“访问端口“COM--”被拒绝”错误。 However, after some few seconds, attempting to reconnect is successful.但是,几秒钟后,尝试重新连接成功。 How can I determine WHEN the USB port will again support a new connection?如何确定 USB 端口何时将再次支持新连接?

The code looks like this:代码如下所示:

    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;
                    }
                }
            }

The final catch statement is where the error about Access being denied is issued.最后的 catch 语句是发出有关拒绝访问的错误的地方。 Note my attempt to retry opening the port 3 times doesn't really help.请注意,我尝试重新尝试打开端口 3 次并没有真正的帮助。 If I leave the port alone for about 5 to 10 seconds and retry calling the Setup method it succeeds immediately.如果我将端口单独放置大约 5 到 10 秒并重试调用 Setup 方法,它会立即成功。

As @Neil said, there are many issues.正如@Neil 所说,有很多问题。 The best thing to do, in my point of view, is to put the search in a loop, and as soon as the port can be opened, it will be.在我看来,最好的做法是将搜索置于循环中,一旦端口可以打开,它就会打开。

I used to do like this :我曾经这样做:

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;
}

Of course, this is just some kind of a template which you have to reshape to your use当然,这只是某种模板,您必须根据使用情况对其进行重塑

I have amended my code to use a constrained loop to give it a better chance to work, which it usually does.我已经修改了我的代码以使用约束循环来给它一个更好的工作机会,它通常会这样做。 I was hoping that there was a better way to do it, as I tend to have pretty impatient users who will be posting defect reports if they have to wait 5 or 10 seconds to make a connection....我希望有更好的方法来做到这一点,因为我往往有非常不耐烦的用户,如果他们必须等待 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;
        }
    }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM