Handling input from a serial port using Visual C++

  • Thread starter Thread starter Guest
  • Start date Start date
G

Guest

Sorry, don't know if this is the correct board for my question. I'm a novice so I guess I have a valid excuse

My question : I'm using Visual C++ and I need to collect data from a serial port. Specifically, I have a piece of equipment that outputs ASCII data to my computer through the serial port. Is there some way I can call the serial port from within Vis C++ and then save the data
I'd much rather do this than buy some sort of software, such as ProComm Plus or Hyper-terminal

Any and all help is appreciated - thank you.
 
Mike said:
Sorry, don't know if this is the correct
board for my question.

Technically, the topic of this group is the C++ programming language as
implemented by Visual Studio. Practically, we get lots of questions on how
to use the language to do things.
I'm a novice so I guess I have a valid excuse.

:-) Unlike the USENET groups we don't sacrifice our trespassers. If I knew
of a more appropriate group I'd direct you.
My question : I'm using Visual C++ and I need
to collect data from a serial port. Specifically, I
have a piece of equipment that outputs ASCII data
to my computer through the serial port. Is there
some way I can call the serial port from within Vis
C++ and then save the data?

Yes, of course. Windows' mantra is "everything is a handle". So you open up
a COMM port and get a handle. Armed with a handle you call ReadFile() and
WriteFile() almost as though you were reading from a file. I say, "almost"
because COMM ports have some properties that files do not. For example, you
need to set parity bit attribute as well as a reasonable timeout policy.

What follows is a little HACK, completley devoid of anything resembling
correct error handling which opens up a port on which this box has a modem
(COM3), sends a Hayes command (ATI1 = identify) and receives the modem
response through the port.

I suggest you consult the MSDN for the names of functions which are
unfamiliar to you. It should get you started.

Regards,
Will

#include <windows.h>
#include <stdio.h>

int main(int argc, char **argv)
{
char szBuffer[80];
DCB dcb = {0};
DWORD dwRead, dwWritten;
HANDLE hComm;
OVERLAPPED ovlr = {0}, ovlw = {0};
COMMTIMEOUTS cto;

// Create events for overlapped operation

ovlr.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
ovlw.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);

// Open the port

hComm = CreateFile("\\\\.\\COM3", GENERIC_READ | GENERIC_WRITE,
0, NULL, OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, NULL);

// Get the state of the device and modify it

dcb.DCBlength = sizeof(dcb);
GetCommState(hComm, &dcb);
dcb.BaudRate = CBR_9600;
SetCommState(hComm, &dcb);

// Set the timeout parameters nonsensically

cto.ReadIntervalTimeout = 1000;
cto.ReadTotalTimeoutConstant = 1000;
cto.ReadTotalTimeoutMultiplier = 1000;
cto.WriteTotalTimeoutConstant = 1000;
cto.WriteTotalTimeoutMultiplier = 1000;

SetCommTimeouts(hComm, &cto);

// Send a command and receieve a response. Note that
// we post the receive in advance of sending the
// command in order not to miss anything

printf("\r\nSending: ATI1\r\n");

ReadFile (hComm, szBuffer, sizeof(szBuffer), &dwRead, &ovlr);
WriteFile(hComm, "ATI1\r", strlen("ATI1\r"), &dwWritten, &ovlw);

// Wait for the receive to complete and display the response

if ( GetOverlappedResult(hComm, &ovlr, &dwRead, TRUE) )
{
szBuffer[dwRead] = 0;
printf("Received: %s\r\n", szBuffer);
}

// Close the device

CloseHandle(hComm);

return 0;
}
 
Mike said:
Thank you for the help.

You are welcome.
With the Read function - if I plan on continuously
reading form the serial port as my program
performs other functions, I have to use asynch
reading?

That depends on your protocol. When can "the other side" send? If it can do
that at any time then it would be wise to have one or more reads pending all
the time. In my little hack the other side is a modem and it only sends it
response to Hayes AT commands. So, I posted the read just before I issued
the write.
However, with the Write function I can simply
perform that at the end of my program using the
synch setup? (I've been looking through the MSDN,
but the examples haven't completely cleared this up for me)

There is always more than a little to know about async I/O (at least on
platforms that are modern enough to support it <g>). As much as it hurts you
may want to go back to the MSDN.

There you will find that there are extended variants of the read and write
functions ( ReadEx() and WriteEx() ) that allow for "completion routines" to
be called when the I/O operation has ended. They are a little like ASTs on
VAX/VMS (if that rings a bell) except that they are only dispatched when the
thread is in an "alertable wait" state. One strategy is to issue a
subsequent read in the completion routine for the previous one. In addition
there is the WaitCommEvent() function that allows you to wait on an
outstanding operation. Ultimately you will come up with something that make
sense in your scenario.

There used to be a COMM sample in the PSDK - I just checked and failed to
find it. If you have the SDK you may want to look for yourself.

Regards,
Will
 
Okay - a little more data..

I need to emulate ASCII data - this might be my current problem with the windings.
 
Mike said:
well, the ReadFile returns a '1', which if I'm correct in
assuming means the program itself is working correctly.

It means that the read completed successfully as zero signifies failure. The
function's fourth parameter should contain the number of bytes actually read
which are deposited into the buffer pointed to by the third parameter.
Is this some sort of normal character that C++
would output, or does it seem more like an
equipment problem?

Perhaps neither. Are you sure the other side sent anything? If you don't
have a way of tracing the transmission, I would add either look at the
buffer and length with the debugger after every read, or if that screws up
the timing, I would log the buffer's content up to the number of bytes read
in a trace file.

Regards,
Will
 
Back
Top