質問

私は使用しています CreateFile システム上のBluetooth HIDデバイスに非同期ファイルハンドルを開く。その後、デバイスはストリーミングデータを開始し、使用します ReadFile デバイスからデータを読み取るため。問題は、Bluetooth接続がドロップされている場合、 ReadFile ただ与え続けます ERROR_IO_PENDING 失敗を報告する代わりに。

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

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

私は利用可能です:

  • ファイルハンドル(HANDLE 値)デバイスに、
  • そのハンドルを開くために使用されたパス(しかし、私はそれを別の時間に開けようとしたくありません、新しい接続を作成します...)
  • an OVERLAPPED 非同期に使用される構造 ReadFile.

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

  • 得る ReadFile 接続がドロップされたときにエラーを返すか、
  • 探知 早く からのタイムアウト時 ReadFile 接続がまだ生きているかどうか(それは速くする必要があります。 ReadFile 少なくとも1秒あたり100回と呼ばれています)、または
  • 私が考えていない別の方法でこの問題を解決しますか?
役に立ちましたか?

解決

チェックするために何らかのポーリングを必要とする必要があります。添付できるイベントがない限り(ドライバーに精通していません)、最も簡単な方法は、コマンドを送信するときにreadfileを実行してチェックすることでcomポートを投票することです。送信できるステータスコマンドがある必要があります。たとえば、WriteFileを使用してWriteFileを使用してDwbyteswriteに書かれたバイトをコピーして、送信しているバイトの長さに等しいかどうかを確認できます。例えば:

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;
 }
ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top