Set DCB Fails When Attempting to Configure COM Port
Asked Answered
T

5

5

I'm trying to write a C++ MFC application that uses the serial port (e.g. COM8). Every time I try to set the DCB it fails. If someone can point out what I'm doing wrong, I'd really appreciate it.

DCB dcb = {0};

dcb.DCBlength = sizeof(DCB);
port.Insert( 0, L"\\\\.\\" );

m_hComm = CreateFile(
    port,                           // Virtual COM port
    GENERIC_READ | GENERIC_WRITE,   // Access: Read and write
    0,                              // Share: No sharing
    NULL,                           // Security: None
    OPEN_EXISTING,                  // The COM port already exists.
    FILE_FLAG_OVERLAPPED,           // Asynchronous I/O.
    NULL                            // No template file for COM port.
    );

if ( m_hComm == INVALID_HANDLE_VALUE )
{
    TRACE(_T("Unable to open COM port."));
    ThrowException();
}

if ( !::GetCommState( m_hComm, &dcb ) )
{
    TRACE(_T("CSerialPort : Failed to get the comm state - Error: %d"), GetLastError());
    ThrowException();
}

dcb.BaudRate = 38400;               // Setup the baud rate.
dcb.Parity = NOPARITY;              // Setup the parity.
dcb.ByteSize = 8;                   // Setup the data bits.
dcb.StopBits = 1;                   // Setup the stop bits.

if ( !::SetCommState( m_hComm, &dcb ) ) // <- Fails here.
{
    TRACE(_T("CSerialPort : Failed to set the comm state - Error: %d"), GetLastError());
    ThrowException();
}

Thanks.

Additional Info: The generated error code is 87: "The parameter is incorrect." Probably Microsoft's most useful error-code. j/k

Tinderbox answered 15/11, 2010 at 21:1 Comment(2)
You can mention the error code.Virgievirgil
@Amnon: Okay, I added the error-code info to my original post, but I don't think it helps much.Tinderbox
T
3

I was able to resolve the problem using BuildCommDCB:

DCB dcb = {0};

if ( !::BuildCommDCB( _T("baud=38400 parity=N data=8 stop=1"), &dcb ) )
{
    TRACE(_T("CSerialPort : Failed to build the DCB structure - Error: %d"), GetLastError());
    ThrowException();
}
Tinderbox answered 15/11, 2010 at 21:42 Comment(4)
So what was the difference between the fields set explicitly and BuildCommDCB? Or do we not care as long as it's working now!Cantus
I just wanted to get it working. The comments, which I've up-voted, about the stop-bits are probably correct.Tinderbox
So, from your original code you removed the setups for the baud rate, parity ect and you replaced them with BuildCommDCB, or you used both to make it work?Geis
This also gives me error: expected expression before ':' tokenGeis
B
12

My money is on this:

dcb.StopBits = 1; 

The MSDN docs says this about StopBits:

The number of stop bits to be used. This member can be one of the following values.

ONESTOPBIT    0    1 stop bit.
ONE5STOPBITS  1    1.5 stop bits.
TWOSTOPBITS   2    2 stop bits.

So, you're asking for 1.5 stop bits, which is such a horribly archaic thing I can't even remember where it comes from. Teleprinters, possibly.

I'd guess the chances of your driver/hardware supporting this mode are slim, hence the error.

So, change it to dcb.StopBits = ONESTOPBIT;

Bayou answered 15/11, 2010 at 22:49 Comment(0)
T
3

I was able to resolve the problem using BuildCommDCB:

DCB dcb = {0};

if ( !::BuildCommDCB( _T("baud=38400 parity=N data=8 stop=1"), &dcb ) )
{
    TRACE(_T("CSerialPort : Failed to build the DCB structure - Error: %d"), GetLastError());
    ThrowException();
}
Tinderbox answered 15/11, 2010 at 21:42 Comment(4)
So what was the difference between the fields set explicitly and BuildCommDCB? Or do we not care as long as it's working now!Cantus
I just wanted to get it working. The comments, which I've up-voted, about the stop-bits are probably correct.Tinderbox
So, from your original code you removed the setups for the baud rate, parity ect and you replaced them with BuildCommDCB, or you used both to make it work?Geis
This also gives me error: expected expression before ':' tokenGeis
B
3

Here are some possibilities in no particular order.

  • GetCommState is filling the structure with garbage since the port hasn't been initialized yet. You might just skip this step.
  • There are two parameters that control the Parity settings, and it's not clear if there's any invalid combinations.
  • The value for StopBits is not the number of bits, it's a magic number constant. The value 1 equates to ONE5STOPBITS which might be invalid when combined with the other parameters.
Befit answered 15/11, 2010 at 21:56 Comment(1)
Thanks for the tips. They are definitely worth keeping in mind.Tinderbox
L
1

This is my code and its working well.

/* Try to open the port */
hCom = CreateFile(szPort, GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_EXISTING, 0, 0);

if (hCom != INVALID_HANDLE_VALUE) {
    printf("Handle success\n");
}

    dcb = { 0 };
    dcb.DCBlength = sizeof(dcb);

    fSuccess = GetCommState(hCom, &dcb);

    if (!fSuccess) {
        // Handle the error.
        printf("GetCommState failed with error %d.\n", GetLastError());
        CloseHandle(hCom);
        return APP_ERROR;
    }

    // Fill in DCB: 57,600 bps, 8 data bits, no parity, and 1 stop bit.
    dcb = { 0 };
    dcb.DCBlength = sizeof(dcb);

    dcb.BaudRate = CBR_115200;     // Set the baud rate
    dcb.ByteSize = 8;              // Data size, xmit, and rcv
    dcb.Parity = NOPARITY;         // No parity bit
    dcb.StopBits = ONESTOPBIT;     // One stop bit

    fSuccess = SetCommState(hCom, &dcb);

    if (!fSuccess) {
        // Handle the error.
        printf("SetCommState failed with error %d.\n", GetLastError());
        CloseHandle(hCom);
        return APP_ERROR;
    }
}

printf("Serial port successfully reconfigured.\n");
Loki answered 11/6, 2018 at 12:30 Comment(0)
V
0

Look at the parameters you give to the function. They're probably incorrect, as the error code says. A google search for "SetCommState 87" shows several instances where the parameters (e.g. baud rate) weren't compatible with the serial port.

Virgievirgil answered 15/11, 2010 at 21:19 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.