Thread: Serial Port Basics

  1. #1
    Registered User
    Join Date
    May 2004
    Posts
    164

    Question Serial Port Basics

    OS: Windows XP
    Compiler: Visual Studio 6.0 C++
    Application: Diaglog Based

    I am trying to learn how to write a program that opens a serial port on the local machine and then monitors incoming messages from the port. I have been reading the msdn example when trying to follow the code I notice that such reference as:

    Code:
    DCB dcb;
    create unknown identifier errors, suggesting I am missing some key links to libraries or header files that define these attributes.

    I have been able to successfully compile code for opening and closing the port, but now that I want to setup control bus settings, I am coming up short. Plus read / write commands I am trying to follow in MSDN samples give me the same errors like the compiler has no way of knowing what I am referring to.

    Can some one point me to a good tutorial or tell me what I am missing to get started? I have not had much luck searching google or MSDN for more detailed information. Probably just my search practices....

    Thanks for any help-

  2. #2
    Registered User
    Join Date
    May 2004
    Posts
    164
    Ok, I found part of my problem, and it was related to missing header files, so I am back on track and I found, surprise surprise, not really, on this site after reworking my search.....

    I included the following and got a bit further:

    Code:
    #include <string>
    #include <cstring>
    #include <stdlib.h>
    #include <afx.h>
    time to see how far I can get....

  3. #3
    Registered User
    Join Date
    Mar 2005
    Location
    Mountaintop, Pa
    Posts
    1,058
    Code:
    #include <windows.h>
    #include <stdio.h>
    #include <string.h>
    
    HANDLE hPort;
    
    BOOL WriteByte(BYTE bybyte)
    {
        DWORD iBytesWritten=0;
        DWORD iBytesToRead = 1;
        if(WriteFile(hPort,(LPCVOID) 
            &bybyte,iBytesToRead,&iBytesWritten,NULL)==0)
            return FALSE;
        else return TRUE;
    }
    
    BOOL WriteString(const void *instring, int length)
    {
        int index;
        BYTE *inbyte = (BYTE *) instring;
        for(index = 0; index< length; ++index)
        {
            if (WriteByte(inbyte[index]) == FALSE)
                return FALSE;
        }
        return TRUE;
    }
    
    BOOL ReadByte(BYTE  &resp)
    {
        BOOL bReturn = TRUE;
        BYTE rx;
        DWORD dwBytesTransferred=0;
    
        if (ReadFile (hPort, &rx, 1, &dwBytesTransferred, 0)> 0)
        {
            if (dwBytesTransferred == 1)
            {
                resp=rx;
                bReturn  = TRUE;
            }
            else bReturn = FALSE;
        }
        else    bReturn = FALSE;
        return bReturn;
    }
    
    BOOL ReadString(void *outstring, int *length)
    {
        BYTE data;
        BYTE dataout[4096]={0};
        int index = 0;
        while(ReadByte(data)== TRUE)
        {
            dataout[index++] = data;
        }
        memcpy(outstring, dataout, index);
        *length = index;
        return TRUE;
    }
    
    void ClosePort()
    {
        CloseHandle(hPort);
        return;
    }
    
    HANDLE ConfigureSerialPort(LPCSTR  lpszPortName)
    {
        HANDLE hComm = NULL;
        DWORD dwError;
        DCB PortDCB;
        COMMTIMEOUTS CommTimeouts;
        // Open the serial port.
        hComm = CreateFile (lpszPortName, // Pointer to the name of the port
            GENERIC_READ | GENERIC_WRITE,
            // Access (read-write) mode
            0,              // Share mode
            NULL,           // Pointer to the security attribute
            OPEN_EXISTING,  // How to open the serial port
            0,              // Port attributes
            NULL);          // Handle to port with attribute to copy
        // Initialize the DCBlength member.
        PortDCB.DCBlength = sizeof (DCB);
        // Get the default port setting information.
        GetCommState (hComm, &PortDCB);
        // Change the DCB structure settings.
        PortDCB.BaudRate = 9600;              // Current baud
        PortDCB.fBinary = TRUE;               // Binary mode; no EOF check
        PortDCB.fParity = TRUE;               // Enable parity checking
        PortDCB.fOutxCtsFlow = FALSE;         // No CTS output flow control
        PortDCB.fOutxDsrFlow = FALSE;         // No DSR output flow control
        PortDCB.fDtrControl = DTR_CONTROL_ENABLE; // DTR flow control type
        PortDCB.fDsrSensitivity = FALSE;      // DSR sensitivity
        PortDCB.fTXContinueOnXoff = TRUE;     // XOFF continues Tx
        PortDCB.fOutX = FALSE;                // No XON/XOFF out flow control
        PortDCB.fInX = FALSE;                 // No XON/XOFF in flow control
        PortDCB.fErrorChar = FALSE;           // Disable error replacement
        PortDCB.fNull = FALSE;                // Disable null stripping
        PortDCB.fRtsControl = RTS_CONTROL_ENABLE; // RTS flow control
        PortDCB.fAbortOnError = FALSE;        // Do not abort reads/writes on error
        PortDCB.ByteSize = 8;                 // Number of bits/byte, 4-8
        PortDCB.Parity = NOPARITY;            // 0-4=no,odd,even,mark,space
        PortDCB.StopBits = ONESTOPBIT;        // 0,1,2 = 1, 1.5, 2
    
        // Configure the port according to the specifications of the DCB structure.
        if (!SetCommState (hComm, &PortDCB))
        {
            printf("Could not configure serial port\n");
            return NULL;
        }
        // Retrieve the time-out parameters for all read and write operations
        // on the port.
        GetCommTimeouts (hComm, &CommTimeouts);
        // Change the COMMTIMEOUTS structure settings.
        CommTimeouts.ReadIntervalTimeout = MAXDWORD;
        CommTimeouts.ReadTotalTimeoutMultiplier = 0;
        CommTimeouts.ReadTotalTimeoutConstant = 0;
        CommTimeouts.WriteTotalTimeoutMultiplier = 0;
        CommTimeouts.WriteTotalTimeoutConstant = 0;
        if (!SetCommTimeouts (hComm, &CommTimeouts))
        {
            printf("Could not set timeouts\n");
            return NULL;
        }
        return hComm;
    }
    
    int main(void)
    {
        //  Can also use COM2, COM3 or COM4 here
        hPort = ConfigureSerialPort("COM1");
        if(hPort == NULL)
        {
            printf("Com port configuration failed\n");
            return -1;
        }
        // Call your ReadString and WriteString functions here
        ClosePort();
        return 0;
    }

  4. #4
    Registered User
    Join Date
    May 2004
    Posts
    164

    Cool

    wow really cool, that just helped me alot. I was doing some research on settings and on port closure. thank you very much for the sample code, that really helped out on what I was working on.....

  5. #5
    Registered User
    Join Date
    May 2004
    Posts
    164

    Unhappy

    confusion and frustration grows! I successfully open and close my port, and using a basicstamp programing tool from radioshack and some downloadable code for the internet I have been able to get a stable environment for a device on my Comm port, see the ascii message and loop, however, every attempt I have made to create my own code for this has failed.

    I can open the port and close it, but the received messages I get are garble.... I have been trying to understand the gracious code supplied by others and their assistance but I am confused on varialbe types and pointers in these examples.
    Questions:
    1. What type of variable is DWORD?
    2. When the above code from bob declares the variable BYTE, is this representative of a single by variable like a char or is it literally a varialbe type BYTE?
    Code:
    BOOL ReadByte(BYTE &resp)
    {
        BYTE rx;
    }
    My current code that returns garble is posted below, I think I have tried 10 different attempts using alot of mixed code, and made my confusion worse, I am really trying to be as simple as possible and do a and OpenFile, ReadFile, CloseFile type structure, but I am not getting very far.... I apologize for the negative behavior, just frustrated, and I appreciate any assistance.

    Code:
     // rs232test.cpp : Defines the entry point for the console application.
    //
    
    #include "stdafx.h"
    #include "rs232test.h"
    #include <string>
    #include <cstring>
    #include <stdlib.h>
    #include <afx.h>
    #include <windows.h>
    #include <stdio.h>
    
    const unsigned short MAX_MESSAGE = 100;
    
    
    #ifdef _DEBUG
    #define new DEBUG_NEW
    #undef THIS_FILE
    static char THIS_FILE[] = __FILE__;
    #endif
    
    HANDLE hComm;
    
    /////////////////////////////////////////////////////////////////////////////
    // The one and only application object
    
    CWinApp theApp;
    
    using namespace std;
    
    //define functions for port settings and reading port
    
    
    
    
    int _tmain(int argc, TCHAR* argv[], TCHAR* envp[])
    {
    	int nRetCode = 0;
    	DCB dcb;
    	char gszPort [5] = "COM1";
    	DWORD dwRead;
    	BOOL fWaitingOnRead = FALSE;
    	OVERLAPPED osReader = {0};
    
    	//notify user of opening port
    	cout<<"opening port:COM1, Baud: 9600, Parity: N, Bytes: 8, StopBit: 1"<<endl;
    	hComm = CreateFile( gszPort,  
    						GENERIC_READ | GENERIC_WRITE, 
    						0, 
    						0, 
    						OPEN_EXISTING,
    						FILE_FLAG_OVERLAPPED,
    						0);
    	if (hComm == INVALID_HANDLE_VALUE)
    
    	FillMemory(&dcb, sizeof(dcb), 0);
        dcb.DCBlength = sizeof(dcb);
        if (!BuildCommDCB("9600,n,8,1", &dcb)) 
    	{   
          // Couldn't build the DCB. Usually a problem
          // with the communications specification string.
    	  cout<<"could not open port"<<endl;
          return FALSE;
        }
        else
    	{
    	  cout<<"Port opened and configured successfully"<<endl;
          // DCB is ready for use.
    
    		// Create the overlapped event. Must be closed before exiting
    		// to avoid a handle leak.
    		osReader.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
    
    		if (osReader.hEvent == NULL)
    		{
    			// Error creating overlapped event; abort.
    			cout <<"ERROR: creating overlapped event failed, aborting"<<endl;
    			return 0;
    		}
    
    		if (!fWaitingOnRead) 
    		{		
    		   // Issue read operation.
    			cout<<"inside read operation"<<endl;
    		    char mess [MAX_MESSAGE];
    			unsigned int lenBuff = MAX_MESSAGE;
    			unsigned long lenMessage;
    			static CString outPut;
    			ReadFile(hComm, mess, MAX_MESSAGE, &dwRead, &osReader);
    			cout<<mess<<endl;
    		}
    		else
    		{
    			cout<<"waiting to read port"<<endl;
    		}
    	}
    
    	CloseHandle(hComm);
    
    	   // error opening port; abort
    
    	return nRetCode;
    }

  6. #6
    Hurry Slowly vart's Avatar
    Join Date
    Oct 2006
    Location
    Rishon LeZion, Israel
    Posts
    6,788
    BYTE is representation of 8-bit unsigned value (in most cases it is defined as unsigned char)
    DWORD is representetion of 32-bit unsigned value (also mostly defined as unsigned int)

    But because this is platform specific - you should not make such an assumptions and use them as is.

    Why don't you try to start with the synchroneous read/write? You will not need to use events and overlapped structure?

    In your case the read function returned immediatly.
    After it return you can call WaitForSingleObject with osReader.hEvent handle to wait for the IO operation complitetion.
    When this function returns - you check the value, and if the IO operation is actually complited - you call
    GetOverlappedResult (if I remember correct) function to retreive number of bytes successfully sent)

    Maybe you should read this section http://msdn2.microsoft.com/en-us/library/aa363196.aspx
    I remember - that somewhere there was a sample for using overlapped operations, currently I cannot find it in short time...
    All problems in computer science can be solved by another level of indirection,
    except for the problem of too many layers of indirection.
    – David J. Wheeler

  7. #7
    Registered User
    Join Date
    May 2004
    Posts
    164
    so if I understand correctly, you are saying I opened the port and polled for a response before the response was complete? I need to wait and define that action to get the complete response then display that response?

    I am reading your links on msdn now to understand better what your referring too, I appreciate your response. I am trying to keep it as simple as possible to understand how it works....

  8. #8
    Hurry Slowly vart's Avatar
    Join Date
    Oct 2006
    Location
    Rishon LeZion, Israel
    Posts
    6,788
    Here is the short snipplet from the code illustrating how I'm reading from the com-port
    Hope it will help
    Code:
    	memset(&ovInternal,0,sizeof(ovInternal));
    	ovInternal.hEvent = CreateEvent(0,RV_TRUE,RV_FALSE,0);
    
    	if(ovInternal.hEvent == 0)
    	{
    		logEvent("Failed to create event object");
    		return ERROR_OUTOFRESOURCES;
    	}
    	
    	// Read the data
    	if (!ReadFile(hCom,pData,iLen,pdwRead,&ovInternal))
    	{
    		// Set the internal error code
    		long lLastError = GetLastError();
    
    		// Overlapped operation in progress is not an actual error
    		if (lLastError != ERROR_IO_PENDING)
    		{
    			logEvent("Unable to read data from com-port");
    			status = ERROR_UNKNOWN;
    		}
    		else
    		{
    			// Wait for the overlapped operation to complete
    			switch (WaitForSingleObject(ovInternal.hEvent,INFINITE))
    			{
    			case WAIT_OBJECT_0:
    				// The overlapped operation has completed
    				if (!GetOverlappedResult(hCom,&ovInternal,pdwRead,FALSE))
    				{
    					logEvent("Overlapped completed without result");
    					status = ERROR_UNKNOWN;
    				}
    					
    				break;
    
    			case WAIT_TIMEOUT:
    				// Cancel the I/O operation
    				CancelIo(hCom);
    
    				logEvent("Overlapped operation timed out");
    				status = ERROR_NETWORK_PROBLEM;
    				break;
    
    			default:
    				// Set the internal error code
    				logEvent("Unable to wait for read operation to complete");
    				status = ERROR_UNKNOWN;
    			}
    		}
    	}
    	else
    	{
    		// The operation completed immediatly. Just to be sure
    		// we'll set the overlapped structure's event handle.
    	}
    	CloseHandle(ovInternal.hEvent);
    All problems in computer science can be solved by another level of indirection,
    except for the problem of too many layers of indirection.
    – David J. Wheeler

  9. #9
    Registered User
    Join Date
    May 2004
    Posts
    164
    I appreciate the example, still reading through the msdn documents, i will try to evaluate and incorporate what you have sent to get a working sample and post success or failure, probably be tomorrow, just too tired at this point. I appreciate your help-

  10. #10
    Registered User
    Join Date
    May 2004
    Posts
    164
    Ok, getting better I think and I am trying to put more error checking to help find my issue.

    Now I appear to be opening the port ok, creating an even handler for the open port reference, but I am getting an error that I can not read data from the port.

    again I downloaded a sample program from the internet that does work and read the device I am trying to use for testing, so I know it has to be something my code is doing wrong.

    Are there some other errors I can check for??? I posted my revised code with the additional code provide to me. I am still trying to understand some of the pointer references and how to initialize the variables to use when calling the ReadFile() function, I have posted my code and the variable declarations, in hopes that someone will see my goof, slap me around a bit and hopefully be able to show me the error of my ways. Thanks again for all the help-

    OS: WindowsXP
    Compiler: MS Visual Studio 6.0 C++

    Code:
    // rs232test.cpp : Defines the entry point for the console application.
    //
    
    #include "stdafx.h"
    #include "rs232test.h"
    #include <string>
    #include <cstring>
    #include <stdlib.h>
    #include <afx.h>
    #include <windows.h>
    #include <stdio.h>
    
    const unsigned short MAX_MESSAGE = 100;
    
    
    #ifdef _DEBUG
    #define new DEBUG_NEW
    #undef THIS_FILE
    static char THIS_FILE[] = __FILE__;
    #endif
    
    HANDLE hComm;
    
    /////////////////////////////////////////////////////////////////////////////
    // The one and only application object
    
    CWinApp theApp;
    
    using namespace std;
    
    //define functions for port settings and reading port
    
    
    
    
    int _tmain(int argc, TCHAR* argv[], TCHAR* envp[])
    {
    	int nRetCode = 0;
    	DCB dcb;
    	char gszPort [5] = "COM1";
    	int iLen;
    	BYTE Data;
    	DWORD dwRead;
    	DWORD dwScanTime = 46;
    	BOOL fWaitingOnRead = FALSE;
    	OVERLAPPED osReader = {0};
    
    	//notify user of opening port
    	cout<<"opening port:COM1, Baud: 9600, Parity: N, Bytes: 8, StopBit: 1"<<endl;
    	hComm = CreateFile( gszPort,  
    						GENERIC_READ | GENERIC_WRITE, 
    						0, 
    						0, 
    						OPEN_EXISTING,
    						FILE_FLAG_OVERLAPPED,
    						0);
    	if (hComm == INVALID_HANDLE_VALUE)
    
    	FillMemory(&dcb, sizeof(dcb), 0);
        dcb.DCBlength = sizeof(dcb);
        if (!BuildCommDCB("9600,n,8,1", &dcb)) 
    	{   
          // Couldn't build the DCB. Usually a problem
          // with the communications specification string.
    	  cout<<"could not open port"<<endl;
          return FALSE;
        }
        else
    	{
    	  cout<<"Port opened and configured successfully"<<endl;
          // DCB is ready for use.
    
    		// Create the overlapped event. Must be closed before exiting
    		// to avoid a handle leak.
    		osReader.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
    
    		if (osReader.hEvent == NULL)
    		{
    			// Error creating overlapped event; abort.
    			cout <<"ERROR: creating overlapped event failed, aborting"<<endl;
    			return 0;
    		}
    
    		if (!fWaitingOnRead) 
    		{		
    		   // Issue read operation.
    			cout<<"inside read operation"<<endl;
    			memset(&osReader,0,sizeof(osReader));
    			osReader.hEvent = CreateEvent(0,true,false,0);
    
    			if(osReader.hEvent == 0)
    			{
    				cout<<"Failed to create event object"<<endl;
    				return 1;
    			}
    
    			else
    			{
    				cout<<"Event Handle appears to be created successfully"<<endl;
    				// Read the data
    				if (!ReadFile(hComm,&Data,iLen,&dwRead,&osReader))
    				{
    					// Set the internal error code
    					long lLastError = GetLastError();
    
    					// Overlapped operation in progress is not an actual error
    					if (lLastError != ERROR_IO_PENDING)
    					{
    						cout<<"Unable to read data from com-port"<<endl;
    						cout<<"GestLastError Code = "<<lLastError<<endl;
    						return 1;
    					}
    
    				}
    				else
    				{
    					// Wait for the overlapped operation to complete
    					switch (WaitForSingleObject(osReader.hEvent,INFINITE))
    					{
    					case WAIT_OBJECT_0:
    						// The overlapped operation has completed
    						if (!GetOverlappedResult(hComm,&osReader,&dwRead,FALSE))
    						{
    							cout<<"Overlapped completed without result"<<endl;
    							
    						}
    							
    						break;
    
    					case WAIT_TIMEOUT:
    						// Cancel the I/O operation
    						CancelIo(hComm);
    
    						cout<<"Overlapped operation timed out"<<endl;
    						break;
    
    					default:
    						// Set the internal error code
    						cout<<"Unable to wait for read operation to complete";
    					}
    				}
    			}
    		}
    	}
    
    	CloseHandle(hComm);
    
    	   // error opening port; abort
    
    	return nRetCode;
    }

    below is a list of the output from my program that I am using to try and found my issue:

    Code:
    opening port:COM1, Baud: 9600, Parity: N, Bytes: 8, StopBit: 1
    Port opened and configured successfully
    inside read operation
    Event Handle appears to be created successfully
    Unable to read data from com-port
    GestLastError Code = 998
    Press any key to continue

  11. #11
    Registered User
    Join Date
    May 2004
    Posts
    164
    Ok, so I looked up this return error code on msdn and found the following:
    Code:
    ERROR_NOACCESS
    998 Invalid access to memory location.
    So now I am thinking this is something to do with the variables I declared and how I am trying to assign the data to the variable coming in from the device to the port. The above response is from MSDN's system error codes page.

    Does this sound like it might be it??? Variable types and declaration or possibly how I am referencing the memory address???? Sorry I am sure this is a newbie question session....

  12. #12
    Registered User
    Join Date
    May 2004
    Posts
    164

    Talking

    ok, after reading over bob's previous send and his code, I think I am learning, but I need help on my varialbe declaration, I keep getting an error when attempting to call the following block of code and windows terminates my program due to memory location access violation, according to debug:

    BOB's Code for function
    Code:
    //the read byte function
    BOOL ReadByte(BYTE  &resp)
    {
        BOOL bReturn = TRUE;
        BYTE rx;
        DWORD dwBytesTransferred=0;
    
        if (ReadFile (hPort, &rx, 1, &dwBytesTransferred, 0)> 0)
        {
            if (dwBytesTransferred == 1)
            {
                resp=rx;
                bReturn  = TRUE;
            }
            else bReturn = FALSE;
        }
        else    bReturn = FALSE;
        return bReturn;
    }
    //the read string function
    BOOL ReadString(void *outstring, int *length)
    {
        BYTE data;
        BYTE dataout[4096]={0};
        int index = 0;
        while(ReadByte(data)== TRUE)
        {
            dataout[index++] = data;
        }
        memcpy(outstring, dataout, index);
        *length = index;
        return TRUE;
    }
    My code initializing Bob's code from my main and the variables I use:
    Code:
    int _tmain(int argc, TCHAR* argv[], TCHAR* envp[])
    {
    	int nRetCode = 0;
    	//open port and configure it
    	hPort = ConfigureSerialPort("COM1");
    
    	//declare data variables for read string function
    	char* message;
    	int* sizeBuffer =0;
    
    	//check to see if configure serial port failed
    	if(hPort==NULL)
    	{
    		cout<<"COM port config failed"<<endl;
    		return -1;
    	}
    	else
    	{
    		//call readfile function
    		ReadString(message, sizeBuffer);
    		cout<<message<<endl;
    	} 
    
    	//call the close port function
    	ClosePort();
    
    	return nRetCode;
    }
    I hope I am getting close.

  13. #13
    Registered User
    Join Date
    May 2004
    Posts
    164
    well it is definately something with my call of the ReadString function, because the app runs fine when I comment that section out, so I am guessing it has something to do with my variables I am passing to the function, I do not understand the what variables to declare and how to pass them to the function:

    function definition
    Code:
    BOOL ReadString(void *outstring, int *length)
    my call to the function and the variables I declare:
    Code:
    //declare data variables for read string function
    	char* message;
    	int* sizeBuffer =0;
    ReadString(message, sizeBuffer);
    sorry for the huge amount of questions the size of this post!

  14. #14
    Hurry Slowly vart's Avatar
    Join Date
    Oct 2006
    Location
    Rishon LeZion, Israel
    Posts
    6,788
    memcpy(outstring, dataout, index);
    *length = index;

    1. outstring is not initialized pointer - you copy destination is unknown to you
    2. length is null pointer

    Should be
    Code:
    //declare data variables for read string function
    	char message[4096];
    	int sizeBuffer =4096;
    ReadString(message, &sizeBuffer);
    Inside he function you
    1. check the incoming size to prevent memory overrun
    2. fill buffer
    3. update the length var to notify the calling function about real length of the buffer used
    All problems in computer science can be solved by another level of indirection,
    except for the problem of too many layers of indirection.
    – David J. Wheeler

  15. #15
    Registered User
    Join Date
    May 2004
    Posts
    164
    That definately resolved my issue, the program is not bombing now, thank you very much for the sample and most of all for the explanation. Sorry for the late response, I had to step away.

    Thanks again for the assistance I plan to do more with this later,

    Sincerely

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. serial port to poll on request
    By infineonintern in forum C++ Programming
    Replies: 2
    Last Post: 06-11-2009, 06:52 AM
  2. Can't Read From Serial Port
    By HalNineThousand in forum Linux Programming
    Replies: 14
    Last Post: 03-20-2008, 05:56 PM
  3. brace-enclosed error
    By jdc18 in forum C++ Programming
    Replies: 53
    Last Post: 05-03-2007, 05:49 PM
  4. need guidance to connect to serial port
    By gnychis in forum Linux Programming
    Replies: 1
    Last Post: 06-02-2005, 10:10 AM
  5. DOS, Serial, and Touch Screen
    By jon_nc17 in forum A Brief History of Cprogramming.com
    Replies: 0
    Last Post: 01-08-2003, 04:59 PM