Click here to Skip to main content
15,881,812 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
need to receive data from serialport. I wrote a program with Windows.h library, using C++, Visual Studio 2010..

I receive all datas from an electronic card, we communicate by handshaking...

I've made the necessary adjustments for handshaking as shown below:

DCB dcb;

dcb.ByteSize = 8;
dcb.Parity = NOPARITY;
dcb.StopBits = ONESTOPBIT;
dcb.fOutxCtsFlow = TRUE;
dcb.fOutxDsrFlow = TRUE;
dcb.fBinary = TRUE;
dcb.fParity = FALSE;
dcb.fNull = FALSE;
dcb.fOutX = FALSE;
dcb.fInX =  FALSE;

Then I set RTS and DTR bits to say I'm ready to receive data as shown below. This one is the function I call:

bool ImSeriAygit::setHardwareControl(bool hardwareControl)
{
    DCB dcb;

    myHardwareControl = hardwareControl;

    if (getStatus() != STATUS_OPEN) // if closed
        return true;

    if (!GetCommState(myPort, &dcb)) // Default port
    {
        printf("ImSeriAygit::setHardwareControl: Could not get port Data.\n");
        return false;
    }

    if(myHardwareControl == 0) /* set control lines */
    {
        dcb.fRtsControl = RTS_CONTROL_ENABLE; // Enable RTS 
        dcb.fDtrControl = DTR_CONTROL_ENABLE; // Enable DTR
    }

    else
    {
        dcb.fRtsControl = RTS_CONTROL_DISABLE; // rts disable
        dcb.fDtrControl = DTR_CONTROL_DISABLE; // dtr disable
    }

    if (!SetCommState(myPort, &dcb)) 
    {  
        printf("ImSeriAygit::setHardwareControl: Could not set port Data.\n");
        return false;
    }  

  return true;
}

This is how I call it:

ser.setHardwareControl(false); // ser is the ImSeriAygit object.
After that I read the serial port using ReadFile function as shown below:

int ImSeriAygit::read(const char *data, unsigned int size, 
                      unsigned int msWait) 
{
    COMSTAT stat;

    unsigned long ret;
    unsigned int numToRead;

    if (myPort != INVALID_HANDLE_VALUE && myStatus == STATUS_OPEN)
    {
        if (!ClearCommError(myPort, &ret, &stat)) 
            return -1;

        if (stat.cbInQue == 0) 
            return 0;

        if (stat.cbInQue > size) 
            numToRead = size;
        else
            numToRead = stat.cbInQue;

        if(get

        if (ReadFile( myPort, (void *)data, numToRead, &ret, NULL))
        {
            return (int)ret;
        }
        else 
        {
            printf("ArSerialConnection::read:  Read failed.\n");
            return -1;
        }
    }

    printf("ArSerialConnection::read: Connection invalid.\n");
    return -1;
}

When I debug my program, I realised that sometimes the data I read is corrupted, which is in fact in a suitable form, but sometimes there is no corruption...

I guess I don't catch the incoming data properly although I'm handshaking...

Any suggestions to know if the data comes in time? My best regards...
Posted
Updated 10-Feb-12 4:23am
v2

1 solution

You are calling ClearCommError() but did not check the error value. Maybe that will help you finding the problem.

You are checking if there are more bytes available than your buffer can hold. That's good. But if this happens, you should call the receive function again immediately.

You are probably comparing a boolean value with 0 and uses reversed logic:
C++
// Parameter hardwareControl is bool
bool ImSeriAygit::setHardwareControl(bool hardwareControl)
{
...
// Copy parameter to member var. Really necessary? 
// Is myHardwareControl also of type bool?
    myHardwareControl = hardwareControl;
...
// Compare a boolean value (or is myHardwareControl of type int or other?)
//  with 0. Using 'false' would be better.
// But this is reversed logic: Setting control lines when value is false.
    if(myHardwareControl == 0) /* set control lines */


You did not show that you are toggling DTR and RTS later, thus signaling the other end that you are always ready to receive data. This can result in data loss when the receive buffer is full. This may even happen with rather slow serial communication when the system load is high (e.g. disk and network transfers). You may use RTS_CONTROL_HANDSHAKE and DTR_CONTROL_HANDSHAKE to avoid buffer overruns.

If the connected system is not only responding to requests, but sending data by itself, you should create a worker thread for receiving data using overlapped IO.
 
Share this answer
 
Comments
Un_NaMeD 10-Feb-12 10:27am    
Hi Jochen..
Thank you for your nice answer.

I have some questions for your answer...

What can I learn from checking ClearCommError()?
What do you mean by toggling DTR and RTS?
The system in fact works this way:
Pc sends data to card:
Card analyse it and starts sending data to PC...

Thank you again...
Jochen Arndt 10-Feb-12 11:06am    
The second parameter of ClearCommError() is a DWORD pointer receiving an error source mask. If for example the CE_OVERRUN bit is set, you know that you must redesign your receive routine to avoid this error. You should at least add a TRACE output call during development to see if there was any error.

Communication flow is a little bit more complicated:
DTR 0 -> 1: Your device knows that you are ready
RTS 0 -> 1: Your device will start to send if there are pending data
... your device is sending data
RTS 1 -> 0: Device: Uuups! Stop sending.
... device waits for RTS if there are more data
RTS 0 -> 1: Device: Aah! Continue transmission
Please note, that this is only a portion of handshake. The handshake on byte / char level is done automatically by using CTS and DSR flow.
Un_NaMeD 10-Feb-12 14:45pm    
Dude, one last question.
How does a pc's serial port buffers behave?
Fifo or any other things?
Could you explain a little bit?
Jochen Arndt 11-Feb-12 9:52am    
Explaining would be like writing an article. But there should be already enough information on the web. If you still have problems you might use some kind of serial class. http://www.codeproject.com/Articles/992/Serial-library-for-C might be a choice.

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900