Как обнаружить, было ли отключение устройства Hid Bluetooth?

StackOverflow https://stackoverflow.com/questions/1790293

  •  22-09-2019
  •  | 
  •  

Вопрос

я использую CreateFile Чтобы открыть асинхронную ручку файла на устройство HID Bluetooth в системе. Устройство будет затем начнет потоковую передачу данных, и я использую ReadFile Чтобы прочитать данные с устройства. Проблема в том, что если соединение Bluetooth отброшено, ReadFile просто продолжает давать ERROR_IO_PENDING вместо того, чтобы сообщать о неудаче.

Я не могу полагаться на тайм -ауты, потому что устройство не отправляет никаких данных, если нечего сообщать. Я не хочу, чтобы это было время, если соединение все еще жива, но на какое -то время нет данных.

Тем не менее, Bluetooth Manager (как Windows One, так и Toshiba One) сразу же заметили, что соединение было потеряно. Таким образом, эта информация находится где -то внутри системы; это просто не переживает ReadFile.

Я доступен:

  • Ручка файла (HANDLE значение) для устройства,
  • Путь, который использовался для открытия этой ручки (но я не хочу пытаться открыть ее в другой раз, создавая новое соединение ...)
  • атмосфера OVERLAPPED структура, используемая для асинхронного ReadFile.

Я не уверен, является ли эта проблема специфичной для Bluetooth, HID-специфической или возникает с устройствами в целом. Есть ли какой -нибудь способ, которым я могу либо

  • получить ReadFile Чтобы вернуть ошибку, когда соединение было сброшено, или
  • обнаруживать быстро В тайм -аут от ReadFile Жизненная ли связь (она должна быть быстро, потому что ReadFile называется не менее 100 раз в секунду), или
  • Решите эту проблему другим способом, о котором я не думал?
Это было полезно?

Решение

Вам нужно будет иметь какой -то опрос, чтобы проверить. Если нет события, которое вы можете прикрепить (я не знаком с драйвером), самый простой способ - опросить ваш COM -порт, выполнив чтение и проверку DwbytesRead> 0 при отправке команды. Должна быть какая -то команда статуса, которую вы можете отправить, или вы можете проверить, можете ли вы написать в порт и скопировать эти байты, записанные на DwbytesWrite, например, с помощью записи, и проверить, равно ли это длине байтов, которые вы отправляете. Например:

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

Вот как я делаю это в своем приложении. Ниже может показаться кучей кода шаблона, но я думаю, что это поможет вам добраться до корня вашей проблемы. Сначала я открываю порт Comm в начале.

У меня есть множество портов 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;
 }
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top