-
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:
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-
-
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....
-
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;
}
-
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.....
-
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;
}
-
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...
-
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....
-
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);
-
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-
-
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
-
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....
-
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.
-
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!
-
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
-
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
-
ok, well, I have been playing and having fun with this console app and it works great, now I have hit my next challenge,
Dialog based app, and running a continous feed from the port to my application.
So my question, is....
As a newbie, should I face the fact that I will now need to try and tackle creating a multi-thread app, the main and the one that runs the serial port monitor and returns message to main?
or
are there other methods to updating a variable embedded in a dialog of this sort that I can update to screen while the dialog runs other functions?
so far my attempts have created an endless loop program that gets stuck monitoring the port and never reacts to the dialog window again.
This is more of an advice request, I know this is a very general question, just want to get an idea of how to direct my research attempts to best fit this next problem, concerned threads may be too deep for me at this point.....
-
The general approach is - to have a thread for the GUI and thread for serial communication (or two separate threads for reading/writing - depending on your needs)
And then apply some mechanism of the thread communication when the data arrived should be displayed by the GUI thread (for example ThreadSendMessage)
-
well cool, time to start reading on that. I appreciate the info. Thanks again for the las example you sent by the way and to bob who sent that really cool code. Both helped alot.
Time to start learning threads! Thanks everyone. I will do my best to stop this thread, ha ha. Thanks again for all the help-