| 42 | #ifdef Q_OS_WIN |
| 43 | |
| 44 | bool SerialPortController::open(const QString& portName, int baudRate, |
| 45 | int dataBits, int parity, int stopBits) |
| 46 | { |
| 47 | if (isOpen()) close(); |
| 48 | |
| 49 | // Prepend "\\.\" so COMxx > COM9 open correctly |
| 50 | QString devPath = portName.startsWith("COM", Qt::CaseInsensitive) |
| 51 | ? "\\\\.\\" + portName : portName; |
| 52 | |
| 53 | // Non-overlapped: WaitCommEvent is called synchronously in the watcher thread, |
| 54 | // which blocks until a pin change occurs. SetCommMask(0) aborts it on close. |
| 55 | // Overlapped mode causes silent WaitCommEvent failures on some FTDI VCP drivers. |
| 56 | HANDLE hPort = ::CreateFileW( |
| 57 | reinterpret_cast<LPCWSTR>(devPath.utf16()), |
| 58 | GENERIC_READ | GENERIC_WRITE, |
| 59 | 0, // no sharing — COM ports are exclusive |
| 60 | nullptr, |
| 61 | OPEN_EXISTING, |
| 62 | 0, // synchronous I/O |
| 63 | nullptr |
| 64 | ); |
| 65 | if (hPort == INVALID_HANDLE_VALUE) { |
| 66 | DWORD err = ::GetLastError(); |
| 67 | qCWarning(lcDevices) << "SerialPortController: failed to open" << portName |
| 68 | << "Win32 error" << err; |
| 69 | emit errorOccurred(QString("Failed to open %1 (error %2)").arg(portName).arg(err)); |
| 70 | return false; |
| 71 | } |
| 72 | |
| 73 | // Configure baud rate / framing via DCB |
| 74 | DCB dcb = {}; |
| 75 | dcb.DCBlength = sizeof(DCB); |
| 76 | if (!::GetCommState(hPort, &dcb)) { |
| 77 | DWORD err = ::GetLastError(); |
| 78 | qCWarning(lcDevices) << "SerialPortController: GetCommState failed on" << portName |
| 79 | << "Win32 error" << err; |
| 80 | emit errorOccurred(QString("Failed to read port state for %1 (error %2)").arg(portName).arg(err)); |
| 81 | ::CloseHandle(hPort); |
| 82 | return false; |
| 83 | } |
| 84 | dcb.BaudRate = static_cast<DWORD>(baudRate); |
| 85 | dcb.ByteSize = static_cast<BYTE>(dataBits); |
| 86 | dcb.Parity = static_cast<BYTE>(parity); |
| 87 | dcb.StopBits = (stopBits == 2) ? TWOSTOPBITS : ONESTOPBIT; |
| 88 | dcb.fBinary = TRUE; |
| 89 | dcb.fParity = (parity != NOPARITY); |
| 90 | // Software-controlled outputs, start HIGH (Windows default on open) |
| 91 | dcb.fDtrControl = DTR_CONTROL_ENABLE; |
| 92 | dcb.fRtsControl = RTS_CONTROL_ENABLE; |
| 93 | dcb.fOutxCtsFlow = FALSE; |
| 94 | dcb.fOutxDsrFlow = FALSE; |
| 95 | dcb.fDsrSensitivity = FALSE; |
| 96 | if (!::SetCommState(hPort, &dcb)) { |
| 97 | DWORD err = ::GetLastError(); |
| 98 | qCWarning(lcDevices) << "SerialPortController: SetCommState failed on" << portName |
| 99 | << "Win32 error" << err; |
| 100 | emit errorOccurred(QString("Failed to configure %1 (baud/framing, error %2)").arg(portName).arg(err)); |
| 101 | ::CloseHandle(hPort); |
nothing calls this directly
no test coverage detected