Search code examples
c++xbee

Reading bytes from serial port C++ Windows


Hey I am trying to interface with the xbees I have connected to my windows machine. I am able to write to the end device through the coordinator in AT mode, and can see the data streamed to my XCTU console. However, I am having trouble understanding how to read that incoming data.

The code I am currently using is below. Essentially the only part that is crucial is the last 5 lines or so (Specifically the read and write file lines), but I am going to post all of it just to be thorough. How do I read the data I sent to the xbee over the com port? The data I sent was simply 0x00-0x0F.

I think I am misunderstanding how the read file functions. I am assuming that the bits I send to the xbee is stored in a buffer which can than be read one at a time. Is that correct? Or do I need to write the entire byte than read the data available? Im sorry if my train of though is confusing, I am fairly new to serial communication. Any help is appreciated.

#include <cstdlib>
#include <windows.h>
#include <iostream>
using namespace std;

/*
 * 
 */
int main(int argc, char** argv) {
    int n = 8; // Amount of Bytes to Read
    HANDLE hSerial;
    HANDLE hSerial2;
    hSerial = CreateFile("COM3",GENERIC_WRITE,0,0,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,0);// dont need to GENERIC _ WRITE
    hSerial2 = CreateFile("COM4",GENERIC_READ,0,0,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,0);// dont need to GENERIC _ WRITE
    if(hSerial==INVALID_HANDLE_VALUE || hSerial2==INVALID_HANDLE_VALUE){
        if(GetLastError()==ERROR_FILE_NOT_FOUND){
//serial port does not exist. Inform user.
    cout << "Serial port error, does not exist" << endl;
    }
//some other error occurred. Inform user.
    cout << "Serial port probably in use" << endl;
    }

    DCB dcbSerialParams = {0};
    dcbSerialParams.DCBlength=sizeof(dcbSerialParams);
    if (!GetCommState(hSerial, &dcbSerialParams)) {
        cout << "error getting state" << endl;
    }
    dcbSerialParams.BaudRate=CBR_9600;
    dcbSerialParams.ByteSize=8;
    dcbSerialParams.StopBits=ONESTOPBIT;
    dcbSerialParams.Parity=NOPARITY;
    if(!SetCommState(hSerial, &dcbSerialParams)){
        cout << "error setting serial port state" << endl;

    }

    COMMTIMEOUTS timeouts = {0};

    timeouts.ReadIntervalTimeout = 50;
    timeouts.ReadTotalTimeoutConstant = 50;
    timeouts.ReadTotalTimeoutMultiplier =10;
    timeouts.WriteTotalTimeoutConstant = 50;
    timeouts.WriteTotalTimeoutMultiplier = 10;

    if (!SetCommTimeouts(hSerial, &timeouts)){
        cout << "Error occurred" << endl;
    }

    DWORD dwBytesWritten = 0;
    DWORD dwBytesRead = 0;
    unsigned char oneChar;
    for (int i=0; i<16; i++)
        {
          oneChar=0x00+i;
          WriteFile(hSerial, (LPCVOID)&oneChar, 1, &dwBytesWritten, NULL);
          ReadFile (hSerial2, &oneChar, 1, &dwBytesRead, NULL); // what I tried to do, just outputs white space
        }

    CloseHandle(hSerial);



    return 0;
}

Solution

  • In your statement:

    ReadFile (hSerial2, &oneChar, 1, &dwBytesRead, NULL);
    

    You need to check the value of dwBytesRead to see if you actually read any bytes. Maybe on one side of the connection you want a simple program to send a byte every second. On the other end, you want to check for available bytes and dump them as they come in.

    What's likely happening in your program is that you're filling an outbound serial buffer in a short amount of time, not waiting long enough to read any data back, and then exiting the loop and closing the serial port, likely before it finishes sending the queued data. For example, write before your CloseHandle() call, you could add:

    COMSTAT stat;
    
    if (ClearCommError(hCom, NULL, &stat))
    {
        printf("%u bytes in outbound queue\n", (unsigned int) stat.cbOutQue);
    }
    

    And see whether your closing the handle before it's done sending.