Home | Music | 3D Animations | Utilities | Code | Search | Forums | About | Contact | Accessibility |
|
Com Port MonitorUpdated June 27 2003 Intro, In a nutshell, Source code, MSVC project, Changes Intro, In a nutshell, Source code, MSVC project IntroI recently had to do some programming to listen to a com port for the Lambdoma Keyboard interface for my Fractal Tune Smithy program. It took a lot of searching on the web to find out how to do it and I got the impression that there is a fair amount of confusion about how it is done. So, here is an example to show how to program it, kept simple, so one can read it and easily understand how the code works. It's for reading only, as that is all I've needed to do. However it seems from the documentation that writing is similar so I think one should have no problem converting it to do that as well once one understands this. There really isn't much to it once one understands that it is overlapped i/o and one has to set and reset events to keep track of that - but rather a lot of false trails one can follow on the way to understanding that!. In a NutshellIn a nutshell, this is what you have to do: When you start the thread, or before you start it, you make an event which will be set to signalled to stop it if needed. hEndComPortEvent = CreateEvent ( NULL, // no security attributes TRUE, // auto reset event FALSE, // not signaled NULL // no name ); Now in the thread, what you do is: char *szComm[]= "com1"; // or "com2" etc. HANDLE hCom; hCom = CreateFile (szComm,GENERIC_READ ,0, // exclusive access NULL, // no security OPEN_EXISTING, FILE_FLAG_OVERLAPPED, // overlapped I/O NULL // null template ); Has to be overlapped i.o. so that the com port monitor thread can be closed without using TerminateThread - if you want to stop and start it anyway - e.g. to change any of the settings while it is running. if(hCom) { DCB dcb; SetupComm(hCom, MAX_BUFF, MAX_BUFF); // set buffer sizes GetCommState(hCom, &dcb); // Then set all the parameters in the dcb structure that you need to // set - if you want to use the existing values, don't need to do anything // here. // Now do the time outs - use MAXDWORD if unsure COMMTIMEOUTS CommTimeouts; SetCommState(hCom, &dcb); GetCommTimeouts(hCom, &CommTimeouts); CommTimeouts.ReadIntervalTimeout = MAXDWORD;//100; CommTimeouts.ReadTotalTimeoutConstant = 0;//100; CommTimeouts.ReadTotalTimeoutMultiplier =0;// 50; CommTimeouts.WriteTotalTimeoutConstant = 0;//100; CommTimeouts.WriteTotalTimeoutMultiplier = 0;//50; bPortReady = SetCommTimeouts(hCom, &CommTimeouts); // Make an overlapped structure for i.o. OVERLAPPED overlapped; // be sure to intialised all the fields of overlapped to 0 - if you don't // do this, it causes an error in XP - though it works fine in 9x. memset(&overlapped,0,sizeof(overlapped)); overlapped.hEvent = CreateEvent( NULL, // no security attributes TRUE, // auto reset event FALSE, // not signaled NULL // no name ); // Set the mask for the events you want to listen for fSuccess = SetCommMask (hCom,EV_RXCHAR | EV_RXFLAG); // If all is well, go into a loop looking for data // Now here the thing is that we read the data as overlapped. // So WaitCommEvent will return immediately - and set the // handle in its overlapped structure when data arrives. if(fSuccess) { DWORD dwError=0; COMSTAT comState; HANDLE hArray[2];// an array of events to pass to WaitForMultipleObjects hArray[0]=overlapped.hEvent; hArray[1]=hEndComPortEvent; ClearCommError(hCom,&dwError,&comState); for(;;) { WaitCommEvent(hCom, &dwEvtMask,&overlapped); // wait for data - but this // will return immediately because // it is overlapped ClearCommError(hCom,&dwError,&comState); // wait for either of the two events to get signalled // - the one from WaitCommEvent or the one you set yourself // to end this thread switch(WaitForMultipleObjects(2,hArray,FALSE, INFINITE)) { case WAIT_OBJECT_0:// input pending - this is the first of the array // entries, i.e. overlapped.hEvent ResetEvent(hArray[0]);// reset the event to not signalled break; case WAIT_OBJECT_0+1:// this is the one to end the thread ResetEvent(hArray[1]); goto end_thread; case WAIT_FAILED:; } // now we can get the data for(;;) { int iBytesReadThisTime=0; int iBytesWas=iBytesRead; BOOL bRead; if(end_com_threads) goto end_thread; // you need to pass &overlapped again as the final argument to ReadFile bRead= ReadFile(hCom, &szData[iBytesRead], MAX_BUFF-iBytesRead-1, &iBytesReadThisTime,&overlapped); iBytesRead+=iBytesReadThisTime; if(bRead==FALSE&&GetLastError()==ERROR_IO_PENDING) { Sleep(2); read_loops++; continue; } else // we have got it all now break; } szData[iBytesRead]='\0'; } // Clean up - just close the handle. PurgeCom just in case we // stopped it in the middle of something. end_thread:; if(hCom) { PurgeComm(hCom,PURGE_RXABORT|PURGE_RXCLEAR|PURGE_TXCLEAR|PURGE_TXABORT); CloseHandle(hCom); hCom=0; } Source codeSo, here is the source code:
MSVC projectHere you can download a zip of the example program using this procedure.
ChangesJune 27 2003 Changed the ADD_ERROR(...) macro to an AddError(...) routine. April 5 2003 Release |
Bookmark this page: - and many more - What are these? |
Disclaimer | Copyright |
Site Designed with advice from Sojo Media (Thanks!) | © Robert Walker 2008 |
tool tips by overlib |
NEW metronome software - Download Bounce Metronome Pro with bounces and conducting patterns to help you stay in time.