代码之家  ›  专栏  ›  技术社区  ›  Thomas

如何检测蓝牙HID设备是否已断开?

  •  0
  • Thomas  · 技术社区  · 15 年前

    我在用 CreateFile 打开系统上蓝牙HID设备的异步文件句柄。然后设备将开始传输数据,我使用 ReadFile 从设备读取数据。问题是,如果蓝牙连接中断, 读取文件 只是不断地给予 ERROR_IO_PENDING 而不是报告故障。

    我不能依赖超时,因为如果没有要报告的数据,设备不会发送任何数据。如果连接仍然存在,我不希望它超时,但暂时没有数据。

    不过,蓝牙管理器(包括WindowsOne和东芝One)确实立即注意到连接中断。所以这个信息就在系统内部的某个地方,它只是没有通过 读取文件 .

    我有空:

    • 文件句柄( HANDLE 值)到设备,
    • 用于打开该句柄的路径(但我不想再次尝试打开它,创建新连接…)
    • OVERLAPPED 用于异步的结构 读取文件 .

    我不确定此问题是蓝牙特定的、HID特定的,还是一般设备发生的。我也有办法吗

    • 得到 读取文件 在断开连接时返回错误,或
    • 发现 迅速地 在以下时间发生超时时 读取文件 连接是否仍处于活动状态(因为 读取文件 每秒至少调用100次),或
    • 用另一种我没想到的方法解决这个问题?
    1 回复  |  直到 15 年前
        1
  •  0
  •   user195488    15 年前

    您必须要进行某种投票检查。除非有可以附加的事件(我不熟悉驱动程序),否则最简单的方法是通过执行readfile来轮询COM端口,并在发送命令时检查dwbytesread>0。应该有一些状态命令可以发送,或者您可以检查是否可以写入端口并复制那些使用writefile写入dwbytes的字节,然后检查这是否等于您发送的字节长度。例如:

    WriteFile(bcPort, cmd, len, &dwBytesWrite, NULL);
    if (len == dwBytesWrite) {
       // Good! Return true
    } else
       // Bad! Return false
    }
    

    这就是我在应用程序中的做法。下面可能看起来像是一堆样板代码,但我认为它将帮助您找到问题的根源。我首先打开通信端口。

    我维护了一组COM端口,并在写入特定的COM端口之前检查它们是否打开。例如,它们是在开始时打开的。

    int j;
        DWORD dwBytesRead;
    
        if (systemDetect == SYS_DEMO)  
            return;
    
        if (port <= 0 || port >= MAX_PORT)
            return;
    
        if (hComm[port]) {
            ShowPortMessage(true, 20, port, "Serial port already open:");
            return;
        }
    
        wsprintf(buff, "COM%d", port);
        hComm[port] = CreateFile(buff,
                          GENERIC_READ | GENERIC_WRITE,
                          0,    //Set of bit flags that specifies how the object can be shared
                          0,    //Security Attributes
                          OPEN_EXISTING,
                          0,    //Specifies the file attributes and flags for the file
                          0);   //access to a template file
    
        if (hComm[port] != INVALID_HANDLE_VALUE) {
            if (GetCommState(hComm[port], &dcbCommPort)) {
                if(baudrate == 9600) {
                        dcbCommPort.BaudRate = CBR_9600;//current baud rate
                } else {
                   if(baudrate == 115200) {
                       dcbCommPort.BaudRate = CBR_115200;
                   }
                }
                dcbCommPort.fBinary = 1;        //binary mode, no EOF check
                dcbCommPort.fParity = 0;        //enable parity checking
                dcbCommPort.fOutxCtsFlow = 0;   //CTS output flow control
                dcbCommPort.fOutxDsrFlow = 0;   //DSR output flow control
    //           dcbCommPort.fDtrControl = 1;    //DTR flow control type
                dcbCommPort.fDtrControl = 0;    //DTR flow control type
                dcbCommPort.fDsrSensitivity = 0;//DSR sensitivity
                dcbCommPort.fTXContinueOnXoff = 0; //XOFF continues Tx
                dcbCommPort.fOutX = 0;          //XON/XOFF out flow control
                dcbCommPort.fInX = 0;           //XON/XOFF in flow control
                dcbCommPort.fErrorChar = 0;     //enable error replacement
                dcbCommPort.fNull = 0;          //enable null stripping
                //dcbCommPort.fRtsControl = 1;  //RTS flow control
                dcbCommPort.fRtsControl = 0;    //RTS flow control
                dcbCommPort.fAbortOnError = 0;  //abort reads/writes on error
                dcbCommPort.fDummy2 = 0;        //reserved
    
                dcbCommPort.XonLim = 2048;      //transmit XON threshold
                dcbCommPort.XoffLim = 512;      //transmit XOFF threshold
                dcbCommPort.ByteSize = 8;       //number of bits/byte, 4-8
                dcbCommPort.Parity = 0;         //0-4=no,odd,even,mark,space
                dcbCommPort.StopBits = 0;       //0,1,2 = 1, 1.5, 2
                dcbCommPort.XonChar = 0x11;     //Tx and Rx XON character
                dcbCommPort.XoffChar = 0x13;    //Tx and Rx XOFF character
                dcbCommPort.ErrorChar = 0;      //error replacement character
                dcbCommPort.EofChar = 0;        //end of input character
                dcbCommPort.EvtChar = 0;        //received event character
                if (!SetCommState(hComm[port], &dcbCommPort)) {
                    setBit(SystemState, SYSTEM_PORT_ERROR);
                    //ShowPortMessage(true, 21, port, "Cannot set serial port state information:");
                    if (!CloseHandle(hComm[port])) {
                        //ShowPortMessage(true, 22, port, "Cannot close serial port:");
                    }
                    hComm[port] = NULL;
                    return;
                }
            } else {
                setBit(SystemState, SYSTEM_PORT_ERROR); 
                //ShowPortMessage(true, 29, port, "Cannot get serial port state information:");
                if (!CloseHandle(hComm[port])) {
                    //ShowPortMessage(true, 22, port, "Cannot close serial port:");
                }
                hComm[port] = NULL;
                return;
            }
    
            if (!SetupComm(hComm[port], 1024*4, 1024*2)) {
                setBit(SystemState, SYSTEM_PORT_ERROR); 
                //ShowPortMessage(true, 23, port, "Cannot set serial port I/O buffer size:");
                if (!CloseHandle(hComm[port])) {
                    //ShowPortMessage(true, 22, port, "Cannot close serial port:");
                }
                hComm[port] = NULL;
                return;
            }
    
            if (GetCommTimeouts(hComm[port], &ctmoOld)) {
                memmove(&ctmoNew, &ctmoOld, sizeof(ctmoNew));
                //default setting
                ctmoNew.ReadTotalTimeoutConstant = 100;
                ctmoNew.ReadTotalTimeoutMultiplier = 0;
                ctmoNew.WriteTotalTimeoutMultiplier = 0;
                ctmoNew.WriteTotalTimeoutConstant = 0;
                if (!SetCommTimeouts(hComm[port], &ctmoNew)) {
                    setBit(SystemState, SYSTEM_PORT_ERROR); 
                    //ShowPortMessage(true, 24, port, "Cannot set serial port timeout information:");
                    if (!CloseHandle(hComm[port])) {
                        //ShowPortMessage(true, 22, port, "Cannot close serial port:");
                    }
                    hComm[port] = NULL;
                    return;
                }
            } else {
                setBit(SystemState, SYSTEM_PORT_ERROR); 
                //ShowPortMessage(true, 25, port, "Cannot get serial port timeout information:");
                if (!CloseHandle(hComm[port])) {
                    //ShowPortMessage(true, 22, port, "Cannot close serial port:");
                }
                hComm[port] = NULL;
                return;
            }
    
            for (j = 0; j < 255; j++) {
                if (!ReadFile(hComm[port], buff, sizeof(buff), &dwBytesRead, NULL)) {
                    setBit(SystemState, SYSTEM_PORT_ERROR); 
                    //ShowPortMessage(true, 26, port, "Cannot read serial port:");
                    j = 999;    //read error
                    break;
                }
    
                if (dwBytesRead == 0)   //No data in COM buffer
                    break;
    
                Sleep(10);   //Have to sleep certain time to let hardware flush buffer
            }
    
            if (j != 999) {
                setBit(pcState[port], PORT_OPEN);
            }
        } else {
            setBit(SystemState, SYSTEM_PORT_ERROR); 
            //ShowPortMessage(true, 28, port, "Cannot open serial port:");
            hComm[port] = NULL;
        }
    
    
    HANDLE TCommPorts::OpenCommPort(void) {
    
     // OPEN THE COMM PORT.
     if (hComm)
         return NULL;  // if already open, don't bother
    
     if (systemDetect == SYS_DEMO)  
        return NULL;
    
     hComm = CreateFile(port,
                 GENERIC_READ | GENERIC_WRITE,
                 0, //Set of bit flags that specifies how the object can be shared
                 0, //Security Attributes
                 OPEN_EXISTING,
                 0, //Specifies the file attributes and flags for the file
             0);//access to a template file
    
    
    // If CreateFile fails, throw an exception. CreateFile will fail if the
    // port is already open, or if the com port does not exist.
    
    // If the function fails, the return value is INVALID_HANDLE_VALUE.
    // To get extended error information, call GetLastError.
    
     if (hComm == INVALID_HANDLE_VALUE) {
    //     throw ECommError(ECommError::OPEN_ERROR);
         return INVALID_HANDLE_VALUE;
     }
    
     // GET THE DCB PROPERTIES OF THE PORT WE JUST OPENED
     if (GetCommState(hComm, &dcbCommPort)) {
        // set the properties of the port we want to use
        dcbCommPort.BaudRate = CBR_9600;// current baud rate
        //dcbCommPort.BaudRate = CBR_115200;
        dcbCommPort.fBinary = 1;        // binary mode, no EOF check
        dcbCommPort.fParity = 0;        // enable parity checking
        dcbCommPort.fOutxCtsFlow = 0;   // CTS output flow control
        dcbCommPort.fOutxDsrFlow = 0;   // DSR output flow control
        //dcbCommPort.fDtrControl = 1;  // DTR flow control type
        dcbCommPort.fDtrControl = 0;    // DTR flow control type
        dcbCommPort.fDsrSensitivity = 0;// DSR sensitivity
        dcbCommPort.fTXContinueOnXoff = 0; // XOFF continues Tx
        dcbCommPort.fOutX = 0;          // XON/XOFF out flow control
        dcbCommPort.fInX = 0;           // XON/XOFF in flow control
        dcbCommPort.fErrorChar = 0;     // enable error replacement
        dcbCommPort.fNull = 0;          // enable null stripping
        //dcbCommPort.fRtsControl = 1;  // RTS flow control
        dcbCommPort.fRtsControl = 0;    // RTS flow control
        dcbCommPort.fAbortOnError = 0;  // abort reads/writes on error
        dcbCommPort.fDummy2 = 0;        // reserved
        dcbCommPort.XonLim = 2048;      // transmit XON threshold
        dcbCommPort.XoffLim = 512;      // transmit XOFF threshold
        dcbCommPort.ByteSize = 8;       // number of bits/byte, 4-8
        dcbCommPort.Parity = 0;         // 0-4=no,odd,even,mark,space
        dcbCommPort.StopBits = 0;       // 0,1,2 = 1, 1.5, 2
        dcbCommPort.XonChar = 0x11;     // Tx and Rx XON character
        dcbCommPort.XoffChar = 0x13;    // Tx and Rx XOFF character
        dcbCommPort.ErrorChar = 0;      // error replacement character
        dcbCommPort.EofChar = 0;        // end of input character
        dcbCommPort.EvtChar = 0;        // received event character
     }
     else
     {
     // something is way wrong, close the port and return
        CloseHandle(hComm);
        throw ECommError(ECommError::GETCOMMSTATE);
     }
    
    
     // SET BAUD RATE, PARITY, WORD SIZE, AND STOP BITS TO OUR SETTINGS.
     // REMEMBERTHAT THE ARGUMENT FOR BuildCommDCB MUST BE A POINTER TO A STRING.
     // ALSO NOTE THAT BuildCommDCB() DEFAULTS TO NO HANDSHAKING.
     //    wsprintf(portSetting, "%s,%c,%c,%c", baud, parity, databits, stopbits);
    
        dcbCommPort.DCBlength = sizeof(DCB);
    //    BuildCommDCB(portSetting, &dcbCommPort);
    
        if (!SetCommState(hComm, &dcbCommPort)) {
            // something is way wrong, close the port and return
            CloseHandle(hComm);
            throw ECommError(ECommError::SETCOMMSTATE);
        }
    
        // set the intial size of the transmit and receive queues.
        // I set the receive buffer to 32k, and the transmit buffer
        // to 9k (a default).
        if (!SetupComm(hComm, 1024*32, 1024*9))
        {
            // something is hay wire, close the port and return
            CloseHandle(hComm);
            throw ECommError(ECommError::SETUPCOMM);
        }
     // SET THE COMM TIMEOUTS.
        if (GetCommTimeouts(hComm,&ctmoOld)) {
            memmove(&ctmoNew, &ctmoOld, sizeof(ctmoNew));
            //default settings
            ctmoNew.ReadTotalTimeoutConstant = 100;
            ctmoNew.ReadTotalTimeoutMultiplier = 0;
            ctmoNew.WriteTotalTimeoutMultiplier = 0;
            ctmoNew.WriteTotalTimeoutConstant = 0;
            if (!SetCommTimeouts(hComm, &ctmoNew)) {
                // something is way wrong, close the port and return
                CloseHandle(hComm);
                throw ECommError(ECommError::SETCOMMTIMEOUTS);
            }
         } else {
            CloseHandle(hComm);
            throw ECommError(ECommError::GETCOMMTIMEOUTS);
         }
    
         return hComm;
     }