كيفية اكتشاف ما إذا كان جهاز HID Bluetooth قد تم فصله؟

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

  •  22-09-2019
  •  | 
  •  

سؤال

أنا استخدم CreateFile لفتح مقبض ملف غير متزامن على جهاز HED Bluetooth على النظام. سيبدأ الجهاز بعد ذلك في دفق البيانات ، وأنا أستخدمه ReadFile لقراءة البيانات من الجهاز. المشكلة هي أنه إذا تم إسقاط اتصال البلوتوث ، ReadFile فقط يحافظ على العطاء ERROR_IO_PENDING بدلا من الإبلاغ عن الفشل.

لا يمكنني الاعتماد على الموعد ، لأن الجهاز لا يرسل أي بيانات إذا لم يكن هناك شيء للإبلاغ عنه. لا أريد ذلك إلى وقت الخروج إذا كان الاتصال لا يزال على قيد الحياة ، ولكن ببساطة لا توجد بيانات لفترة من الوقت.

ومع ذلك ، فإن مدير Bluetooth (كل من Windows One و Toshiba One) يلاحظ على الفور أن الاتصال قد فقد. لذلك هذه المعلومات موجودة في مكان ما داخل النظام ؛ انها فقط لا تصل إلى ReadFile.

لدي:

  • مقبض الملف (HANDLE القيمة) للجهاز ،
  • المسار الذي تم استخدامه لفتح هذا المقبض (لكنني لا أريد محاولة فتحه مرة أخرى ، وإنشاء اتصال جديد ...)
  • و OVERLAPPED البنية المستخدمة للاختلاف غير المتزامن ReadFile.

لست متأكدًا مما إذا كانت هذه المشكلة محددة من Bluetooth أو HID محددة أو تحدث مع الأجهزة بشكل عام. هل هناك أي طريقة يمكنني إما

  • احصل على ReadFile لإرجاع خطأ عند إسقاط الاتصال ، أو
  • يكشف بسرعة على مهلة من ReadFile ما إذا كان الاتصال لا يزال على قيد الحياة (يجب أن يكون سريعًا لأن ReadFile يسمى ما لا يقل عن 100 مرة في الثانية) ، أو
  • حل هذه المشكلة بطريقة أخرى لم أفكر فيها؟
هل كانت مفيدة؟

المحلول

سيتعين عليك الحصول على نوع من الاقتراع للتحقق. ما لم يكن هناك حدث يمكنك إرفاقه (لست على دراية بالسائق) ، فإن أبسط طريقة هي استطلاع منفذ COM الخاص بك عن طريق إجراء عملية قراءة والتحقق من dwbytesread> 0 عند إرسال أمر. يجب أن يكون هناك بعض أمر الحالة الذي يمكنك إرساله أو يمكنك التحقق مما إذا كان يمكنك الكتابة إلى المنفذ ونسخ تلك البايتات المكتوبة إلى dwbyteswrite باستخدام WriteFile ، على سبيل المثال ، والتحقق مما إذا كان ذلك مساوياً لطول البايتات التي ترسلها. على سبيل المثال:

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

هذه هي الطريقة التي أفعل بها في طلبي. قد يبدو أدناه وكأنه مجموعة من رمز Boilerplate ، لكنني أعتقد أنه سيساعدك على الوصول إلى جذر مشكلتك. لقد فتحت أولاً منفذ 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