2009-11-24 1 views
0

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

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

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

У меня есть в наличии:

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

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

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

ответ

0

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

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

Я не решил это точно таким образом, но вы поместили меня на правильный путь. Я настроил устройство для отправки мне постоянных отчетов, даже если ничего не изменилось. Если я ничего не слышу от него в течение двух секунд, я предполагаю, что он отключен. – Thomas