Wie kann ich feststellen, ob ein Bluetooth -HID -Gerät getrennt wurde?
Frage
Ich benutze CreateFile
So öffnen Sie eine asynchrone Dateihandle für ein Bluetooth -HID -Gerät auf dem System. Das Gerät startet dann Streaming -Daten und ich verwende ReadFile
Daten aus dem Gerät lesen. Das Problem ist, dass, wenn die Bluetooth -Verbindung fallen gelassen wird, ReadFile
Gib einfach weiter ERROR_IO_PENDING
Anstatt einen Fehler zu melden.
Ich kann mich nicht auf Timeouts verlassen, da das Gerät keine Daten sendet, wenn nichts zu melden ist. Ich möchte nicht, dass es sich verabschieden, wenn die Verbindung noch lebt, aber es gibt einfach keine Daten für eine Weile.
Trotzdem bemerkt der Bluetooth -Manager (sowohl der Windows One als auch der Toshiba One) sofort, dass die Verbindung verloren ging. Diese Informationen befinden sich also irgendwo im System; Es kommt einfach nicht durch ReadFile
.
Ich habe verfügbar:
- der Dateihandle (
HANDLE
Wert) zum Gerät, - Der Pfad, der verwendet wurde, um diesen Griff zu öffnen (aber ich möchte nicht versuchen, ihn ein anderes Mal zu öffnen und eine neue Verbindung herzustellen ...)
- ein
OVERLAPPED
Struktur für asynchronReadFile
.
Ich bin mir nicht sicher, ob dieses Problem bluetoothspezifisch, versteckt ist oder mit Geräten im Allgemeinen auftritt. Gibt es eine Möglichkeit, wie ich entweder kann?
- erhalten
ReadFile
um einen Fehler zurückzugeben, wenn die Verbindung fallen oder - erkennen schnell bei einer Auszeit von
ReadFile
ob die Verbindung noch lebt (sie muss schnell sein, weilReadFile
wird mindestens 100 Mal pro Sekunde bezeichnet) oder - Lösen Sie dieses Problem auf andere Weise, an die ich nicht gedacht habe?
Lösung
Sie müssen eine Art Umfrage haben, um zu überprüfen. Wenn es keine Veranstaltung gibt, die Sie anhängen können (ich bin mit dem Treiber nicht vertraut), besteht die einfachste Möglichkeit, Ihren COM -Port durch eine Readdatei zu befragen und zu überprüfen, ob dwByTesRead> 0 Wenn Sie einen Befehl senden. Es sollte einen Statusbefehl geben, den Sie senden können, oder Sie können überprüfen, ob Sie beispielsweise an den Port schreiben und diese Bytes kopieren können. Zum Beispiel:
WriteFile(bcPort, cmd, len, &dwBytesWrite, NULL);
if (len == dwBytesWrite) {
// Good! Return true
} else
// Bad! Return false
}
So mache ich es in meiner Bewerbung. Unten mag wie ein Haufen Boilerplate -Code erscheinen, aber ich denke, er hilft Ihnen dabei, die Wurzel Ihres Problems zu erreichen. Ich öffne zuerst den COMM -Port zu Beginn.
Ich habe eine Reihe von COM -Ports, die ich unterhiele und überprüfe, ob sie geöffnet sind, bevor sie an einen bestimmten COM -Port schreiben. Zum Beispiel werden sie am Anfang geöffnet.
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;
}