• 记一次调试串口设备Bug的经历


    最近花了差不多1天的时间在折腾一个Bug,该Bug的表象如下: 

    这个Bug还特别独特,在开发电脑中无提示,在终端用户那里每次使用软件的时候都报这个。仔细思考了一下最近在源码中新添加的功能,没发现有啥特别明显的问题。于是,根据字面意思的理解是“运行时错误”,所以一开始解决这个问题的思路是将所有应用程序的运行时拷贝至应用程序目录。尝试过之后,依然报这个异常。分析可能跟运行时的动态链接库没有关系。于是,调整解决问题的思路,考虑将工程中新添加的代码进行分割。部分部分的测试新添加的代码到底那里有问题,排查到最后是这个函数内部发生了异常。异常函数的代码如下:

    void CleanSerialPort()
    {
        if(g_hEvent != NULL)
        {
            CloseHandle(g_hEvent);
            g_hEvent = NULL;
        }
    
        if(g_SerialPort.IsOpen())
        {
            COMMPROP properties;
            memset(&properties, 0, sizeof(properties));
            g_SerialPort.GetProperties();
            g_SerialPort.ClearWriteBuffer();
            g_SerialPort.ClearReadBuffer();
            g_SerialPort.Flush();
            g_SerialPort.CancelIo();
            g_SerialPort.Close();
        }
    }

    一开始仔细读了几遍代码,没发现有啥异常的地方。在这个时候,只能通过一点一点调试编译器来最终确定问题在那里。调试编译器的方式比较传统,是通过MessageBox消息来实现。最终定位到g_SerialPort的Close函数。该函数的原型如下: 

    void CSerialPort::Close()
    {
        if(IsOpen())
        {
            CloseHandle(m_hComm);
            m_hComm = INVALID_HANDLE_VALUE;
        }
    }
    

    仔细读了几遍,依然没发现问题在那里。但是,又反复琢磨了一段时间之后,把这个问题想清楚了。当把串口数据线拔出之后,串口设备已经在操作系统中不存在,这个时候却还要去强行关闭串口设备,此时当然会发生异常,不发生异常才是不正常的情况。于是,考虑在这一大段代码的外围加一个try…catch…,果不其然,成功捕获到异常,异常代码的值为0x05,代表的含义为ERROR_ACCESS_DENIED,表示拒绝访问。目前操作系统中已经不存在该串口设备,因此拒绝访问是正常的状态。最终的代码如下:   

    void CleanSerialPort()
    {
        try
        {
            if(g_hEvent != NULL)
            {
                CloseHandle(g_hEvent);
                g_hEvent = NULL;
            }
    
            if(g_SerialPort.IsOpen())
            {
                COMMPROP properties;
                memset(&properties, 0, sizeof(properties));
                g_SerialPort.GetProperties();
                g_SerialPort.ClearWriteBuffer();
                g_SerialPort.ClearReadBuffer();
                g_SerialPort.Flush();
                g_SerialPort.CancelIo();
                g_SerialPort.Close();
            }
        }
        catch(CSerialException &e)
        {
            ATLTRACE("Unexpected CSerialPort exception, Error:%u
    ", e.m_dwError);
            UNREFERENCED_PARAMETER(e);
        }
    }

    捕获到这个异常之后,在不关闭应用程序的情况下,不影响再次初始化串口设备,而应用程序也不报一开始的Runtime error,因此默认目前的处理方案可行。 

    作者:常想一二
    出处:http://www.cnblogs.com/wolfmvp/
    本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
    如果文中有什么错误,欢迎指出。以免更多的人被误导。
  • 相关阅读:
    python使用Fabric模块实现自动化运维
    sublime 字体设置
    java语言输出Fibonacci数列:1 1 2 3 5 8 13....直到55
    Java-取出字符串中第一个出现且唯一的字母
    java中charAt()方法的使用
    Java indexOf() 方法
    idea查找 enter class name的快捷键
    spring boot配置文件加载位置
    @PropertySource&@ImportResource&@Bean
    @Value获取值和@ConfigurationProperties获取值比较
  • 原文地址:https://www.cnblogs.com/wolfmvp/p/7008956.html
Copyright © 2020-2023  润新知