Archived

This topic is now archived and is closed to further replies.

Serial Port programming woes....

This topic is 5302 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts


#include <stdio.h>
#include <stdlib.h>
#include <ddraw.h>
#include <dinput.h>
#include <memory.h>

#include <mmsystem.h>
#include <vector>
#include <string>
using namespace std;

int main() {
	string portname="//./COM1";

	DCB m_dcb; //get current port settings

	BOOL b; //bools for checking

	//open our port

	HANDLE hComm =  CreateFile(portname.c_str(), GENERIC_READ | GENERIC_WRITE,0,0,OPEN_EXISTING,
		0,0);
	if(hComm==INVALID_HANDLE_VALUE) { //handle errors.

		printf("PROBLEM. #1\n");
		return (1);
	}
	
	b=GetCommState(hComm,&m_dcb);
	if(b==0) {
		printf("PROBLEM. #2\n");
		CloseHandle(hComm);
		return(1);
	}

	//fill in data.

	m_dcb.BaudRate=300;
	m_dcb.ByteSize=8;
	m_dcb.Parity=NOPARITY;
	m_dcb.StopBits=ONESTOPBIT;
	m_dcb.fBinary=TRUE;
	m_dcb.fDsrSensitivity=FALSE;
	m_dcb.fParity=FALSE;
	m_dcb.fOutX=false;
	m_dcb.fInX=false;
	m_dcb.fNull=false;
	m_dcb.fAbortOnError=TRUE;
	m_dcb.fOutxCtsFlow=FALSE;
	m_dcb.fOutxDsrFlow=false;
	m_dcb.fDtrControl=DTR_CONTROL_DISABLE;
	m_dcb.fDsrSensitivity=false;
	m_dcb.fRtsControl=RTS_CONTROL_DISABLE;
	
	b=SetCommState(hComm,&m_dcb);
	if(b==0) {
		printf("PROBLEM. #3\n");
		CloseHandle(hComm);
		return(1);
	}
	printf("Succesfully initialized stuff. I hope.\n");
	BYTE rx;
	BYTE resp=0;
	DWORD dwBytesTransferred=0;
	int i=0;
	char s[50];
	while(1) {
		for(int z=0;z<500;z++) {

			if(ReadFile(hComm,&rx,1,&dwBytesTransferred,0)) {
				if(dwBytesTransferred==1) {
					resp=rx; 
					s[i]=rx;	
				} else {
					break;
				}
			}
		}
		i=0;
		printf("TEXT RECIEVED: %s\n",s);

	}
	CloseHandle(hComm);
	return(0);
}
This code produces the output "Succesfully initiated..." Now, I THINK I have this set up right to continue reading the file for information sent. In hyperterminal, on the same settings, I can press the send button on the device, and it will display on the hyperterminal screen. This is all I need. I need to be able to, as fast and rapidly as possible get string after string that this may be sending. I also heard that I can "send" ?0 to the device, and it would continuously reply back, but I couldn''t get this to work under hyperterminal, so I''d like to go with the send button for now. Any comments on how to fix?

Share this post


Link to post
Share on other sites
i fiddle with the com port for a bit, i will send you my source code when i get home, can you e-mail me plz.

thanx
-danushka



A GOOD friend will come bail you out of jail...
but, a TRUE friend will be sitting next to you saying, "Damn, we fucked up."
Ingite 3D Game Engine Home -- Just click it

Share this post


Link to post
Share on other sites
Not exactly certain about what device you are trying to read from, but nevertheless, I pretty much followed one of the SDK samples to directly control my modem through the serial port.
Here is the relevant code I ended up using.


... snip ...

bool ModemAvailable()
{
if(hModem)
return false;
HANDLE temp= hModem=CreateFile( "COM1:", GENERIC_READ | GENERIC_WRITE,
0, // exclusive access

NULL, // no security attributes

OPEN_EXISTING,
FILE_FLAG_OVERLAPPED,
NULL
);
if(temp==INVALID_HANDLE_VALUE)
return false;
CloseHandle(temp);
return true;
}

DWORD WINAPI ReadingWorkerThread(LPVOID info)
{
BUNDLE *p=(BUNDLE*)(info);
if(!p || !p->hModem || !p->hWnd)
return 1;
DWORD rxevent=EV_RXCHAR | EV_RXFLAG;
DWORD readin;
bool doread=false;
bool waitingonread=false;
bool waitingonstat=false;
char readbuff[2050];
readbuff[2049]=0;
readbuff[2048]=0;
OVERLAPPED ovrstat={0};
OVERLAPPED ovrread={0};
SetCommMask(p->hModem, rxevent);
DWORD result=0;
ovrstat.hEvent=CreateEvent(NULL,TRUE,FALSE,NULL);
if(!ovrstat.hEvent)
return 10;
ovrread.hEvent=CreateEvent(NULL,TRUE,FALSE,NULL);
if(!ovrread.hEvent)
{
CloseHandle(ovrstat.hEvent);
return 11;
}
DWORD errors;

ClearCommError(p->hModem,&errors,NULL);

HANDLE evarray[3];
evarray[0]=ovrread.hEvent;
evarray[1]=ovrstat.hEvent;
evarray[2]=ghExitEvent;
DWORD err;
while(1)
{

if(!waitingonread)
{
if(!ReadFile(p->hModem,&readbuff,512,&readin,&ovrread))
{
err=GetLastError();
if(err!=ERROR_IO_PENDING)
{
SafeOutputDebugString("ReadFile failed");
result=1;
break;
}
waitingonread=true;
}
else
{
if(readin)
{
readbuff[readin]=0;
ProcessInput(readbuff,readin);
}
}
}

if(!waitingonstat)
{
DWORD rex=0;
if(!WaitCommEvent(p->hModem,&rex /*&rxevent*/,&ovrstat))
{
err=GetLastError();
if(err!=ERROR_IO_PENDING)
{
result=2;
break;
}
waitingonstat=true;
}
}
if(p->quit)
break;

if(waitingonread && waitingonstat)
{
DWORD res=WaitForMultipleObjects(3,evarray,FALSE,500);
switch(res)
{
case WAIT_OBJECT_0:
if(!GetOverlappedResult(p->hModem,&ovrread,&readin,FALSE))
{
err=GetLastError();
if(err!=ERROR_OPERATION_ABORTED)
{
result=3;
break;
}
}
if(readin)
{
readbuff[readin]=0;
ProcessInput(readbuff,readin);
}
waitingonread=false;
break;
case WAIT_OBJECT_0+1:
if(!GetOverlappedResult(p->hModem,&ovrstat,&readin,FALSE))
{
err=GetLastError();
if(err!=ERROR_OPERATION_ABORTED)
{
result=4;
break;
}
}
waitingonstat=false;
break;
case WAIT_OBJECT_0+2:
result=999;
ResetEvent(ghExitEvent);
break;
case WAIT_TIMEOUT:
break;
default:
result=5;
break;
}
if(result)
break;

}
}
if(result==999)
{
SafeOutputDebugString("************ READER THREAD EXITING BY WAIT_OBJECT_0+2");
result=0;
}
else
{
if(!result)
SafeOutputDebugString("************ READER THREAD EXITING NORMALLY");
}
CloseHandle(evarray[0]);
CloseHandle(evarray[1]);
return result;
}

bool OpenModem()
{
if(hModem)
return true;

reader_bundle.quit=FALSE;
hModem=CreateFile( "COM1:", GENERIC_READ | GENERIC_WRITE,
0, // exclusive access

NULL, // no security attributes

OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED,
NULL
);

if(hModem == INVALID_HANDLE_VALUE)
{
hModem=NULL;
return false;
}
DCB dcb = {0};
dcb.DCBlength = sizeof(dcb);
if(!GetCommState(hModem,&dcb))
{
hModem=NULL;
return false;
}

dcb.BaudRate=CBR_9600;
dcb.ByteSize=8;
dcb.Parity=NOPARITY;
dcb.StopBits=ONESTOPBIT;
dcb.fBinary=TRUE;
dcb.fParity=FALSE;
dcb.EvtChar = ''\0'';
dcb.fDtrControl=DTR_CONTROL_ENABLE;
dcb.fRtsControl=RTS_CONTROL_ENABLE;

dcb.fOutxCtsFlow = FALSE;
dcb.fOutxDsrFlow = FALSE;
dcb.fDsrSensitivity = FALSE;
dcb.fOutX = FALSE;
dcb.fInX = FALSE;
dcb.fTXContinueOnXoff = FALSE;
dcb.XonChar = ASCII_XON;
dcb.XoffChar = ASCII_XOFF;
dcb.XonLim = 0;
dcb.XoffLim = 0;

SetCommState(hModem,&dcb);
SetCommTimeouts(hModem,&gTimeouts);
SetupComm(hModem,2048,1024);

reader_bundle.hModem=hModem;
reader_bundle.hWnd=ghWnd;

readerThread=CreateThread(NULL,0,ReadingWorkerThread,&reader_bundle,0,&readerThreadId);
if(!readerThread)
{
CloseModem();
return false;
}
InitModem();
state=ackini;
return true;
}

void CloseModem()
{
reader_bundle.quit=TRUE;
if(ghExitEvent)
{
SetEvent(ghExitEvent);
Sleep(500); // lets wait a few a bit for reader thread to terminate nicely

}
if(hModem)
{
PurgeComm(hModem,PURGE_RXABORT | PURGE_TXABORT);
SetCommMask(hModem,0); // don''t trigger any events, and make WaitCommEvent exit immediately to signal other threads to quit

EscapeCommFunction(hModem,CLRDTR); // drop dtr to make modem hang up (since modem is configured to hangup when dtr is dropped)

CloseHandle(hModem);
hModem=NULL;
}
readerThreadId=0;
readerThread=NULL;
}

Share this post


Link to post
Share on other sites
Instead of Sleep(500), you can call WaitForSingleObject(readerThread, 5000) which will return either after 5000ms or once the reader thread terminates (whichever happens first). If it times-out, you shold call TerminateThread(readerThread) to make certain it dies.

Share this post


Link to post
Share on other sites
quote:
Original post by Muzlack
Is there any real differences in our code besides the way they are structured?

BTW--silvermace, still waiting for e-mail.


There are some fairly big differences. For one, you are not using overlapped i/o. Second, you don''t seem to be using any type of flow control.

Share this post


Link to post
Share on other sites
I have written a lot of commercial serial port code, and ain''t it fun! It sounds to me like:
1. Hyperterminal does exactly what you want it to.
2. Your code doesn''t.
Invest in a light box at Radio Shack. I think they still sell them. I think your lack of flow control is the culprit. Most devices use hardware flow control...RTS/CTS and DTR/DSR. I assume that you are using some form of NULL modem, since Hyperterminal works.
ClearCommError can be used to see if flow control is the culprit. EscapeCommFunction can be used to turn on RTS and DTR. I think your device is wanting the DTR before it sends anything.

To sum up, ALWAYS use RTS/DSR flow control unless you KNOW they are not needed. If Hyperterminal uses them, you must also. When a device wants to transmit, it raises RTS (Request To Send). The would-be receive device replies with CTS (Clear To Send). This is probably what Hyperterminal is doing that you aren''t. You can''t unilaterally decide against flow control, unless you hardwire the lines to loop back.

Share this post


Link to post
Share on other sites
So, use the EscapeCommFunction to set DTS and RTS on?

I''m really sorry. This comm stuff is all new to me, and I''m learning a lot, but it must be frustrating putting up w/ me

Share this post


Link to post
Share on other sites
Yes, that''s what I''m saying to do. You might also set the bits in the DCB before you open the port. RS-232 is pretty difficult in a "non-preemptive" multitasking OS, and there is no real standard to speak of...RS-232 really only defines pins numbers on the connector, but if you are working in a process control, or data acquisition system, its almost always hardware flow control, like I said before. The post about using a thread is a GREAT IDEA in any case. If you couple that to a user defined message in your message pump, and have the thread "wake-up" the app to process data. Works great, even at high rates (I have gotten 115200 bps with no problem using MFC, and the OnIdle thread.) I stayed away from letting Windows do that work, because high data rate, and proprietary nature of the application gave it fits. HOPE THIS HELPS.

Share this post


Link to post
Share on other sites