1

CreateFileシステム上のBluetoothHIDデバイスへの非同期ファイルハンドルを開くために使用しています。その後、デバイスはデータのストリーミングを開始し、私ReadFileはデバイスからデータを読み取るために使用します。問題は、Bluetooth接続が切断された場合、障害を報告するのではなく、ReadFile単に提供し続けることです。ERROR_IO_PENDING

報告するものがない場合、デバイスはデータを送信しないため、タイムアウトに依存することはできません。接続がまだ有効な場合はタイムアウトにしたくありませんが、しばらくの間データがないだけです。

それでも、Bluetoothマネージャー(WindowsとToshibaの両方)は、接続が失われたことにすぐに気付きます。したがって、この情報はシステム内のどこかにあります。に到達していないだけReadFileです。

私は利用可能です:

  • デバイスへのファイルハンドル(HANDLE値)、
  • そのハンドルを開くために使用されたパス(ただし、新しい接続を作成するために、もう一度それを開こうとはしません...)
  • OVERLAPPED非同期に使用される構造体ReadFile

この問題がBluetooth固有の問題なのか、HID固有の問題なのか、それとも一般的なデバイスで発生するのかはわかりません。私ができる方法はありますか

  • ReadFile接続が切断されたときにエラーを返すようになる、または
  • 接続がまだ有効であるかどうか( 1秒間に少なくとも100回呼び出されるため、高速である必要がある)からタイムアウト時に迅速に検出する、またはReadFileReadFile
  • 私が考えていなかった別の方法でこの問題を解決しますか?
4

1 に答える 1

0

確認するには、なんらかのポーリングが必要になります。アタッチできるイベントがない限り(私はドライバーに精通していません)、最も簡単な方法は、ReadFileを実行してCOMポートをポーリングし、コマンドを送信するときにdwBytesRead>0であることを確認することです。送信できるステータスコマンドがあるはずです。または、ポートに書き込み、WriteFileを使用してdwBytesWriteに書き込まれたバイトをコピーできるかどうかを確認し、送信するバイトの長さと同じかどうかを確認できます。例えば:

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

これが私のアプリケーションでのやり方です。以下は一連の定型コードのように見えるかもしれませんが、問題の根本を突き止めるのに役立つと思います。最初にCommPortを開きます。

維持している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;
 }
于 2009-11-24T15:57:05.393 に答える