您的位置:首页 > 其它

win32系统下关于串口通讯API详解(microsoft )

2011-09-26 15:25 417 查看

SerialCommunicationsinWin32

 
AllenDenver

MicrosoftWindowsDeveloperSupport
December11,1995
Allenseldomeatsbreakfast,butifhehadtopickafavorite,Win32serialcommunicationswouldbethetopchoice.
ClicktoopenorcopythefilesintheMTTTYsampleapplicationforthistechnicalarticle.
 

Abstract

SerialcommunicationsinMicrosoft?Win32?issignificantlydifferentfromserialcommunicationsin16-bitMicrosoftWindows?Thosefamiliarwith16-bitserialcommunicationsfunctionswillhavetorelearnmanypartsofthesystemtoprogram
serialcommunicationsproperly.Thisarticlewillhelptoaccomplishthis.Thoseunfamiliarwithserialcommunicationswillfindthisarticleahelpfulfoundationfordevelopmentefforts.
ThisarticleassumesthereaderisfamiliarwiththefundamentalsofmultiplethreadingandsynchronizationinWin32.Inaddition,abasicfamiliarityoftheWin32heapfunctionsisusefultofullycomprehendthememorymanagement
methodsusedbythesample,MTTTY,includedwiththisarticle.Formoreinformationregardingthesefunctions,consultthePlatformSDKdocumentation,theMicrosoftWin32SDKKnowledgeBase,ortheMicrosoftDeveloperNetworkLibrary.Applicationprogramming
interfaces(APIs)thatcontroluserinterfacefeaturesofwindowsanddialogboxes,thoughnotdiscussedhere,areusefultoknowinordertofullycomprehendthesampleprovidedwiththisarticle.ReadersunfamiliarwithgeneralWindowsprogrammingpractices
shouldlearnsomeofthefundamentalsofgeneralWindowsprogrammingbeforetakingonserialcommunications.Inotherwords,getyourfeetwetbeforedivinginheadfirst.

Introduction

Thefocusofthisarticleisonapplicationprogramminginterfaces(APIs)andmethodsthatarecompatiblewithMicrosoft?WindowsNT?andWindows95;therefore,APIssupportedonbothplatformsaretheonlyonesdiscussed.Windows
95supportstheWin32?TelephonyAPI(TAPI)andWindowsNT3.xdoesnot;therefore,thisdiscussionwillnotincludeTAPI.TAPIdoesdeservemention,however,inthatitverynicelyimplementsmodeminterfacingandcallcontrolling.Aproductionapplication
thatworkswithmodemsandmakestelephonecallsshouldimplementthesefeaturesusingtheTAPIinterface.ThiswillallowseamlessintegrationwiththeotherTAPI-enabledapplicationsthatausermayhave.Furthermore,thisarticledoesnotdiscusssomeof
theconfigurationfunctionsinWin32,suchasGetCommProperties.
Thearticleisbrokenintothefollowingsections:Openingaport,readingandwriting(nonoverlappedandoverlapped),serialstatus(eventsanderrors),andserialsettings(DCB,flowcontrol,andcommunicationstime-outs).
Thesampleincludedwiththisarticle,MTTTY:MultithreadedTTY,implementsmanyofthefeaturesdiscussedhere.Itusesthreethreadsinitsimplementation:auserinterfacethreadthatdoesmemorymanagement,awriterthreadthatcontrols
allwriting,andareader/statusthreadthatreadsdataandhandlesstatuschangesontheport.Thesampleemploysafewdifferentdataheapsformemorymanagement.Italsomakesextensiveuseofsynchronizationmethodstofacilitatecommunicationbetween
threads.

OpeningaPort

TheCreateFilefunctionopensacommunicationsport.TherearetwowaystocallCreateFiletoopenthecommunicationsport:overlappedandnonoverlapped.Thefollowingistheproperwaytoopenacommunications
resourceforoverlappedoperation:

HANDLEhComm;


hComm=CreateFile(gszPort,


GENERIC_READ|GENERIC_WRITE,


0,


0,


OPEN_EXISTING,


FILE_FLAG_OVERLAPPED,


0);


if(hComm==INVALID_HANDLE_VALUE)


//erroropeningport;abort


RemovaloftheFILE_FLAG_OVERLAPPEDflagfromthecallto
CreateFile
specifiesnonoverlappedoperation.Thenextsectiondiscussesoverlappedandnonoverlappedoperations.
ThePlatformSDKdocumentationstatesthatwhenopeningacommunicationsport,thecalltoCreateFilehasthefollowingrequirements:

fdwShareModemustbezero.Communicationsportscannotbesharedinthesamemannerthatfilesareshared.ApplicationsusingTAPIcanusetheTAPIfunctionstofacilitatesharingresourcesbetweenapplications.ForWin32applications
notusingTAPI,handleinheritanceorduplicationisnecessarytosharethecommunicationsport.Handleduplicationisbeyondthescopeofthisarticle;pleaserefertothePlatformSDKdocumentationformoreinformation.

[align=justify]fdwCreatemustspecifytheOPEN_EXISTINGflag.[/align]

[align=justify]hTemplateFileparametermustbeNULL.[/align]

OnethingtonoteaboutportnamesisthattraditionallytheyhavebeenCOM1,COM2,COM3,orCOM4.TheWin32APIdoesnotprovideanymechanismfordeterminingwhatportsexistonasystem.WindowsNTandWindows95keeptrackofinstalled
portsdifferentlyfromoneanother,soanyonemethodwouldnotbeportableacrossallWin32platforms.Somesystemsevenhavemoreportsthanthetraditionalmaximumoffour.Hardwarevendorsandserial-device-driverwritersarefreetonametheportsanything
theylike.Forthisreason,itisbestthatusershavetheabilitytospecifytheportnametheywanttouse.Ifaportdoesnotexist,anerrorwilloccur(ERROR_FILE_NOT_FOUND)afterattemptingtoopentheport,andtheusershouldbenotifiedthattheport
isn’tavailable.

ReadingandWriting

ReadingfromandwritingtocommunicationsportsinWin32isverysimilartofileinput/output(I/O)inWin32.Infact,thefunctionsthataccomplishfileI/OarethesamefunctionsusedforserialI/O.I/OinWin32canbedoneeitherof
twoways:overlappedornonoverlapped.ThePlatformSDKdocumentationusestheterms
asynchronousandsynchronoustoconnotethesetypesofI/Ooperations.Thisarticle,however,usesthetermsoverlappedandnonoverlapped.
NonoverlappedI/OisfamiliartomostdevelopersbecausethisisthetraditionalformofI/O,whereanoperationisrequestedandisassumedtobecompletewhenthefunctionreturns.InthecaseofoverlappedI/O,thesystem
mayreturntothecallerimmediatelyevenwhenanoperationisnotfinishedandwillsignalthecallerwhentheoperationcompletes.TheprogrammayusethetimebetweentheI/Orequestanditscompletiontoperformsome“background?work.
ReadingandwritinginWin32issignificantlydifferentfromreadingandwritingserialcommunicationsportsin16-bitWindows.16-bitWindowsonlyhastheReadCommandWriteCommfunctions.Win32readingand
writingcaninvolvemanymorefunctionsandchoices.Theseissuesarediscussedbelow.

NonoverlappedI/O

NonoverlappedI/Oisverystraightforward,thoughithaslimitations.Anoperationtakesplacewhilethecallingthreadisblocked.Oncetheoperationiscomplete,thefunctionreturnsandthethreadcancontinueitswork.ThistypeofI/O
isusefulformultithreadedapplicationsbecausewhileonethreadisblockedonanI/Ooperation,otherthreadscanstillperformwork.Itistheresponsibilityoftheapplicationtoserializeaccesstotheportcorrectly.Ifonethreadisblockedwaiting
foritsI/Ooperationtocomplete,allotherthreadsthatsubsequentlycallacommunicationsAPIwillbeblockeduntiltheoriginaloperationcompletes.Forinstance,ifonethreadwerewaitingforaReadFilefunctiontoreturn,anyotherthread
thatissuedaWriteFilefunctionwouldbeblocked.
Oneofthemanyfactorstoconsiderwhenchoosingbetweennonoverlappedandoverlappedoperationsisportability.Overlappedoperationisnotagoodchoicebecausemostoperatingsystemsdonotsupportit.Mostoperatingsystemssupportsome
formofmultithreading,however,somultithreadednonoverlappedI/Omaybethebestchoiceforportabilityreasons.

OverlappedI/O

OverlappedI/OisnotasstraightforwardasnonoverlappedI/O,butallowsmoreflexibilityandefficiency.AportopenforoverlappedoperationsallowsmultiplethreadstodoI/Ooperationsatthesametimeandperformotherwork
whiletheoperationsarepending.Furthermore,thebehaviorofoverlappedoperationsallowsasinglethreadtoissuemanydifferentrequestsanddoworkinthebackgroundwhiletheoperationsarepending.
Inbothsingle-threadedandmultithreadedapplications,somesynchronizationmusttakeplacebetweenissuingrequestsandprocessingtheresults.Onethreadwillhavetobeblockeduntiltheresultofanoperationisavailable.Theadvantage
isthatoverlappedI/Oallowsathreadtodosomeworkbetweenthetimeoftherequestanditscompletion.Ifnoworkcanbedone,thentheonlycaseforoverlappedI/Oisthatitallowsforbetteruserresponsiveness.
OverlappedI/OisthetypeofoperationthattheMTTTYsampleuses.Itcreatesathreadthatisresponsibleforreadingtheport’sdataandreadingtheport’sstatus.Italsoperformsperiodicbackgroundwork.Theprogramcreatesanother
threadexclusivelyforwritingdataouttheport.
NoteApplicationssometimesabusemultithreadingsystemsbycreatingtoomanythreads.Althoughusingmultiplethreadscanresolvemanydifficultproblems,creatingexcessivethreadsisnotthemostefficientuseofthem
inanapplication.ThreadsarelessastrainonthesystemthanprocessesbutstillrequiresystemresourcessuchasCPUtimeandmemory.Anapplicationthatcreatesexcessivethreadsmayadverselyaffecttheperformanceoftheentiresystem.Abetteruse
ofthreadsistocreateadifferentrequestqueueforeachtypeofjobandtohaveaworkerthreadissueanI/Orequestforeachentryintherequestqueue.ThismethodisusedbytheMTTTYsampleprovidedwiththisarticle.
AnoverlappedI/Ooperationhastwoparts:thecreationoftheoperationandthedetectionofitscompletion.CreatingtheoperationentailssettingupanOVERLAPPEDstructure,creatingamanual-reseteventforsynchronization,
andcallingtheappropriatefunction(ReadFileorWriteFile).TheI/Ooperationmayormaynotbecompletedimmediately.Itisanerrorforanapplicationtoassumethatarequestforanoverlappedoperationalwaysyieldsan
overlappedoperation.Ifanoperationiscompletedimmediately,anapplicationneedstobereadytocontinueprocessingnormally.Thesecondpartofanoverlappedoperationistodetectitscompletion.Detectingcompletionoftheoperationinvolveswaiting
fortheeventhandle,checkingtheoverlappedresult,andthenhandlingthedata.Thereasonthatthereismoreworkinvolvedwithanoverlappedoperationisthattherearemorepointsoffailure.Ifanonoverlappedoperationfails,thefunctionjustreturns
anerror-returnresult.Ifanoverlappedoperationfails,itcanfailinthecreationoftheoperationorwhiletheoperationispending.Youmayalsohaveatime-outoftheoperationoratime-outwaitingforthesignalthattheoperationiscomplete.

Reading

TheReadFilefunctionissuesareadoperation.
ReadFileExalsoissuesareadoperation,butsinceitisnotavailableonWindows95,itisnotdiscussedinthisarticle.Hereisacodesnippetthatdetailshowtoissueareadrequest.Noticethatthefunctioncallsafunctiontoprocess
thedataiftheReadFilereturnsTRUE.Thisisthesamefunctioncallediftheoperationbecomesoverlapped.NotethefWaitingOnReadflagthatisdefinedbythecode;itindicateswhetherornotareadoperationisoverlapped.Itisusedto
preventthecreationofanewreadoperationifoneisoutstanding.

DWORDdwRead;


BOOLfWaitingOnRead=FALSE;


OVERLAPPEDosReader={0};




//Createtheoverlappedevent.Mustbeclosedbeforeexiting


//toavoidahandleleak.


osReader.hEvent=CreateEvent(NULL,TRUE,FALSE,NULL);




if(osReader.hEvent==NULL)


//Errorcreatingoverlappedevent;abort.




if(!fWaitingOnRead){


//Issuereadoperation.


if(!ReadFile(hComm,lpBuf,READ_BUF_SIZE,&dwRead,&osReader)){


if(GetLastError()!=ERROR_IO_PENDING)//readnotdelayed?


//Errorincommunications;reportit.


else


fWaitingOnRead=TRUE;


}


else{


//readcompletedimmediately


HandleASuccessfulRead(lpBuf,dwRead);


}


}


Thesecondpartoftheoverlappedoperationisthedetectionofitscompletion.TheeventhandleintheOVERLAPPEDstructureispassedtotheWaitForSingleObjectfunction,whichwillwaituntiltheobjectis
signaled.Oncetheeventissignaled,theoperationiscomplete.Thisdoesnotmeanthatitwascompletedsuccessfully,justthatitwascompleted.TheGetOverlappedResultfunctionreportstheresultoftheoperation.Ifanerroroccurred,GetOverlappedResult
returnsFALSEandGetLastErrorreturnstheerrorcode.Iftheoperationwascompletedsuccessfully,GetOverlappedResultwillreturnTRUE.
NoteGetOverlappedResultcandetectcompletionoftheoperation,aswellasreturntheoperation’sfailurestatus.GetOverlappedResultreturnsFALSEandGetLastErrorreturnsERROR_IO_INCOMPLETE
whentheoperationisnotcompleted.Inaddition,GetOverlappedResultcanbemadetoblockuntiltheoperationcompletes.ThiseffectivelyturnstheoverlappedoperationintoanonoverlappedoperationandisaccomplishedbypassingTRUEas
thebWaitparameter.
Hereisacodesnippetthatshowsonewaytodetectthecompletionofanoverlappedreadoperation.Notethatthecodecallsthesamefunctiontoprocessthedatathatwascalledwhentheoperationcompletedimmediately.Alsonotetheuse
ofthefWaitingOnReadflag.Hereitcontrolsentryintothedetectioncode,sinceitshouldbecalledonlywhenanoperationisoutstanding.

#defineREAD_TIMEOUT500//milliseconds




DWORDdwRes;




if(fWaitingOnRead){


dwRes=WaitForSingleObject(osReader.hEvent,READ_TIMEOUT);


switch(dwRes)


{


//Readcompleted.


caseWAIT_OBJECT_0:


if(!GetOverlappedResult(hComm,&osReader,&dwRead,FALSE))


//Errorincommunications;reportit.


else


//Readcompletedsuccessfully.


HandleASuccessfulRead(lpBuf,dwRead);




//Resetflagsothatanotheropertioncanbeissued.


fWaitingOnRead=FALSE;


break;




caseWAIT_TIMEOUT:


//Operationisn'tcompleteyet.fWaitingOnReadflagisn't


//changedsinceI'llloopbackaround,andIdon'twant


//toissueanotherreaduntilthefirstonefinishes.


//


//Thisisagoodtimetodosomebackgroundwork.


break;




default:


//ErrorintheWaitForSingleObject;abort.


//ThisindicatesaproblemwiththeOVERLAPPEDstructure's


//eventhandle.


break;


}


}


Writing

TransmittingdataoutthecommunicationsportisverysimilartoreadinginthatitusesalotofthesameAPIs.Thecodesnippetbelowdemonstrateshowtoissueandwaitforawriteoperationtobecompleted.

BOOLWriteABuffer(char*lpBuf,DWORDdwToWrite)


{


OVERLAPPEDosWrite={0};


DWORDdwWritten;


DWORDdwRes;


BOOLfRes;




//Createthiswriteoperation'sOVERLAPPEDstructure'shEvent.


osWrite.hEvent=CreateEvent(NULL,TRUE,FALSE,NULL);


if(osWrite.hEvent==NULL)


//errorcreatingoverlappedeventhandle


returnFALSE;




//Issuewrite.


if(!WriteFile(hComm,lpBuf,dwToWrite,&dwWritten,&osWrite)){


if(GetLastError()!=ERROR_IO_PENDING){


//WriteFilefailed,butisn'tdelayed.Reporterrorandabort.


fRes=FALSE;


}


else


//Writeispending.


dwRes=WaitForSingleObject(osWrite.hEvent,INFINITE);


switch(dwRes)


{


//OVERLAPPEDstructure'seventhasbeensignaled.


caseWAIT_OBJECT_0:


if(!GetOverlappedResult(hComm,&osWrite,&dwWritten,FALSE))


fRes=FALSE;


else


//Writeoperationcompletedsuccessfully.


fRes=TRUE;


break;




default:


//AnerrorhasoccurredinWaitForSingleObject.


//Thisusuallyindicatesaproblemwiththe


//OVERLAPPEDstructure'seventhandle.


fRes=FALSE;


break;


}


}


}


else


//WriteFilecompletedimmediately.


fRes=TRUE;




CloseHandle(osWrite.hEvent);


returnfRes;


}


NoticethatthecodeaboveusestheWaitForSingleObject
functionwithatime-outvalueofINFINITE.ThiscausestheWaitForSingleObjectfunctiontowaitforeveruntiltheoperationiscompleted;thismaymakethethreadorprogramappeartobe“hung?when,infact,thewriteoperationis
simplytakingalongtimetocompleteorflowcontrolhasblockedthetransmission.Statuschecking,discussedlater,candetectthiscondition,butdoesn’tcausetheWaitForSingleObjecttoreturn.Threethingscanalleviatethiscondition:

[align=justify]Placethecodeinaseparatethread.Thisallowsotherthreadstoexecuteanyfunctionstheydesirewhileourwriterthreadwaitsforthewritetobecompleted.ThisiswhattheMTTTYsampledoes.[/align]

[align=justify]UseCOMMTIMEOUTStocausethewritetobecompletedafteratime-outperiodhaspassed.Thisisdiscussedmorefullyinthe“CommunicationsTime-outs?sectionlaterinthisarticle.ThisisalsowhattheMTTTYsampleallows.[/align]

ChangetheWaitForSingleObjectcalltoincludearealtime-outvalue.Thiscausesmoreproblemsbecauseiftheprogramissuesanotheroperationwhileanolderoperationisstillpending,newOVERLAPPEDstructures
andoverlappedeventsneedtobeallocated.Thistypeofrecordkeepingisdifficult,particularlywhencomparedtousinga“jobqueue?designfortheoperations.The“jobqueue?methodisusedintheMTTTYsample.

Note:Thetime-outvaluesinsynchronizationfunctionsarenotcommunicationstime-outs.Synchronizationtime-outscauseWaitForSingleObjectorWaitForMultipleObjectstoreturnWAIT_TIMEOUT.
Thisisnotthesameasareadorwriteoperationtimingout.Communicationstime-outsaredescribedlaterinthisarticle.
BecausetheWaitForSingleObjectfunctionintheabovecodesnippetusesanINFINITEtime-out,itisequivalenttousingGetOverlappedResultwithTRUEforthefWaitparameter.Hereisequivalentcode
inamuchsimplifiedform:

BOOLWriteABuffer(char*lpBuf,DWORDdwToWrite)


{


OVERLAPPEDosWrite={0};


DWORDdwWritten;


BOOLfRes;




//CreatethiswritesOVERLAPPEDstructurehEvent.


osWrite.hEvent=CreateEvent(NULL,TRUE,FALSE,NULL);


if(osWrite.hEvent==NULL)


//Errorcreatingoverlappedeventhandle.


returnFALSE;




//Issuewrite.


if(!WriteFile(hComm,lpBuf,dwToWrite,&dwWritten,&osWrite)){


if(GetLastError()!=ERROR_IO_PENDING){


//WriteFilefailed,butitisn'tdelayed.Reporterrorandabort.


fRes=FALSE;


}


else{


//Writeispending.


if(!GetOverlappedResult(hComm,&osWrite,&dwWritten,TRUE))


fRes=FALSE;


else


//Writeoperationcompletedsuccessfully.


fRes=TRUE;


}


}


else


//WriteFilecompletedimmediately.


fRes=TRUE;




CloseHandle(osWrite.hEvent);


returnfRes;


}


GetOverlappedResultisnotalwaysthebestwaytowaitforanoverlappedoperationtobecompleted.Forexample,ifanapplicationneedstowaitonanothereventhandle,thefirstcodesnippetservesasabettermodelthan
thesecond.ThecalltoWaitForSingleObjectiseasytochangeto
WaitForMultipleObjectstoincludetheadditionalhandlesonwhichtowait.ThisiswhattheMTTTYsampleapplicationdoes.
AcommonmistakeinoverlappedI/OistoreuseanOVERLAPPEDstructurebeforethepreviousoverlappedoperationiscompleted.Ifanewoverlappedoperationisissuedbeforeapreviousoperationiscompleted,anewOVERLAPPED
structuremustbeallocatedforit.Anewmanual-reseteventforthehEventmemberoftheOVERLAPPEDstructuremustalsobecreated.Onceanoverlappedoperationiscomplete,theOVERLAPPEDstructureandits
eventarefreeforreuse.
TheonlymemberoftheOVERLAPPEDstructurethatneedsmodifyingforserialcommunicationsisthehEventmember.TheothermembersoftheOVERLAPPEDstructureshouldbeinitializedtozero
andleftalone.ModifyingtheothermembersoftheOVERLAPPEDstructureisnotnecessaryforserialcommunicationsdevices.ThedocumentationforReadFileandWriteFilestatethattheOffsetandOffsetHigh
membersoftheOVERLAPPEDstructuremustbeupdatedbytheapplication,orelseresultsareunpredictable.ThisguidelineshouldbeappliedtoOVERLAPPEDstructuresusedforothertypesofresources,suchasfiles.

SerialStatus

Therearetwomethodstoretrievethestatusofacommunicationsport.Thefirstistosetaneventmaskthatcausesnotificationoftheapplicationwhenthedesiredeventsoccur.TheSetCommMaskfunctionsetsthiseventmask,
andtheWaitCommEventfunctionwaitsforthedesiredeventstooccur.Thesefunctionsaresimilartothe16-bitfunctionsSetCommEventMaskandEnableCommNotification,exceptthattheWin32functionsdonotpost
WM_COMMNOTIFYmessages.Infact,theWM_COMMNOTIFYmessageisnotevenpartoftheWin32API.Thesecondmethodforretrievingthestatusofthecommunicationsportistoperiodicallycallafewdifferentstatusfunctions.Pollingis,ofcourse,neitherefficient
norrecommended.

CommunicationsEvents

Communicationseventscanoccuratanytimeinthecourseofusingacommunicationsport.Thetwostepsinvolvedinreceivingnotificationofcommunicationseventsareasfollows:

[align=justify]SetCommMasksetsthedesiredeventsthatcauseanotification.[/align]

[align=justify]WaitCommEventissuesastatuscheck.Thestatuscheckcanbeanoverlappedornonoverlappedoperation,justasthereadandwriteoperationscanbe.[/align]

Note:Thewordeventinthiscontextreferstocommunicationseventsonly.Itdoesnotrefertoaneventobjectusedforsynchronization.
HereisanexampleoftheSetCommMaskfunction:

DWORDdwStoredFlags;




dwStoredFlags=EV_BREAK|EV_CTS|EV_DSR|EV_ERR|EV_RING|\


EV_RLSD|EV_RXCHAR|EV_RXFLAG|EV_TXEMPTY;


if(!SetCommMask(hComm,dwStoredFlags))


//errorsettingcommunicationsmask


AdescriptionofeachtypeofeventisinTable1.
Table1.CommunicationsEventFlags

EventFlag

Description

EV_BREAK

Abreakwasdetectedoninput.

EV_CTS

TheCTS(clear-to-send)signalchangedstate.TogettheactualstateoftheCTSline,GetCommModemStatusshouldbecalled.

EV_DSR

TheDSR(data-set-ready)signalchangedstate.TogettheactualstateoftheDSRline,GetCommModemStatusshouldbecalled.

EV_ERR

Aline-statuserroroccurred.Line-statuserrorsareCE_FRAME,CE_OVERRUN,andCE_RXPARITY.Tofindthecauseoftheerror,ClearCommErrorshouldbecalled.

EV_RING

Aringindicatorwasdetected.

EV_RLSD

TheRLSD(receive-line-signal-detect)signalchangedstate.TogettheactualstateoftheRLSDline,GetCommModemStatusshouldbecalled.NotethatthisiscommonlyreferredtoastheCD(carrierdetect)line.

EV_RXCHAR

Anewcharacterwasreceivedandplacedintheinputbuffer.Seethe“Caveat?sectionbelowforadiscussionofthisflag.

EV_RXFLAG

Theeventcharacterwasreceivedandplacedintheinputbuffer.TheeventcharacterisspecifiedintheEvtCharmemberoftheDCBstructurediscussedlater.The“Caveat?sectionbelowalsoappliestothisflag.

EV_TXEMPTY

Thelastcharacterintheoutputbufferwassenttotheserialportdevice.Ifahardwarebufferisused,thisflagonlyindicatesthatalldatahasbeensenttothehardware.Thereisnowaytodetectwhenthehardwarebufferisemptywithouttalkingdirectly
tothehardwarewithadevicedriver.

Afterspecifyingtheeventmask,theWaitCommEventfunctiondetectstheoccurrenceoftheevents.Iftheportisopenfornonoverlappedoperation,thentheWaitCommEventfunctiondoesnotcontainanOVERLAPPED
structure.Thefunctionblocksthecallingthreaduntiltheoccurrenceofoneoftheevents.Ifaneventneveroccurs,thethreadmayblockindefinitely.
HereisacodesnippetthatshowshowtowaitforanEV_RINGeventwhentheportisopenfornonoverlappedoperation:

DWORDdwCommEvent;




if(!SetCommMask(hComm,EV_RING))


//Errorsettingcommunicationsmask


returnFALSE;




if(!WaitCommEvent(hComm,&dwCommEvent,NULL))


//Anerroroccurredwaitingfortheevent.


returnFALSE;


else


//Eventhasoccurred.


returnTRUE;


NoteTheMicrosoftWin32SDKKnowledgeBasedocumentsaproblemwithWindows95andtheEV_RINGflag.TheabovecodeneverreturnsinWindows95becausetheEV_RINGeventisnotdetectedbythesystem;WindowsNTproperly
reportstheEV_RINGevent.PleaseseetheWin32SDKKnowledgeBaseformoreinformationonthisbug.
Asnoted,thecodeabovecanbeblockedforeverifaneventneveroccurs.Abettersolutionwouldbetoopentheportforoverlappedoperationandwaitforastatuseventinthefollowingmanner:

#defineSTATUS_CHECK_TIMEOUT500//Milliseconds




DWORDdwRes;


DWORDdwCommEvent;


DWORDdwStoredFlags;


BOOLfWaitingOnStat=FALSE;


OVERLAPPEDosStatus={0};




dwStoredFlags=EV_BREAK|EV_CTS|EV_DSR|EV_ERR|EV_RING|\


EV_RLSD|EV_RXCHAR|EV_RXFLAG|EV_TXEMPTY;


if(!SetCommMask(comHandle,dwStoredFlags))


//errorsettingcommunicationsmask;abort


return0;




osStatus.hEvent=CreateEvent(NULL,TRUE,FALSE,NULL);


if(osStatus.hEvent==NULL)


//errorcreatingevent;abort


return0;




for(;;){


//Issueastatuseventcheckifonehasn'tbeenissuedalready.


if(!fWaitingOnStat){


if(!WaitCommEvent(hComm,&dwCommEvent,&osStatus)){


if(GetLastError()==ERROR_IO_PENDING)


bWaitingOnStatusHandle=TRUE;


else


//errorinWaitCommEvent;abort


break;


}


else


//WaitCommEventreturnedimmediately.


//Dealwithstatuseventasappropriate.


ReportStatusEvent(dwCommEvent);


}




//Checkonoverlappedoperation.


if(fWaitingOnStat){


//Waitalittlewhileforaneventtooccur.


dwRes=WaitForSingleObject(osStatus.hEvent,STATUS_CHECK_TIMEOUT);


switch(dwRes)


{


//Eventoccurred.


caseWAIT_OBJECT_0:


if(!GetOverlappedResult(hComm,&osStatus,&dwOvRes,FALSE))


//Anerroroccurredintheoverlappedoperation;


//callGetLastErrortofindoutwhatitwas


//andabortifitisfatal.


else


//Statuseventisstoredintheeventflag


//specifiedintheoriginalWaitCommEventcall.


//Dealwiththestatuseventasappropriate.


ReportStatusEvent(dwCommEvent);




//SetfWaitingOnStatflagtoindicatethatanew


//WaitCommEventistobeissued.


fWaitingOnStat=FALSE;


break;




caseWAIT_TIMEOUT:


//Operationisn'tcompleteyet.fWaitingOnStatusHandleflag


//isn'tchangedsinceI'llloopbackaroundandIdon'twant


//toissueanotherWaitCommEventuntilthefirstonefinishes.


//


//Thisisagoodtimetodosomebackgroundwork.


DoBackgroundWork();


break;




default:


//ErrorintheWaitForSingleObject;abort


//ThisindicatesaproblemwiththeOVERLAPPEDstructure's


//eventhandle.


CloseHandle(osStatus.hEvent);


return0;


}


}


}




CloseHandle(osStatus.hEvent);


Thecodeaboveverycloselyresemblesthecodeforoverlappedreading.Infact,theMTTTYsampleimplementsitsreadingandstatuscheckinginthesamethreadusingWaitForMultipleObjectstowaitforeitherthereadevent
orthestatuseventtobecomesignaled.
TherearetwointerestingsideeffectsofSetCommMaskand
WaitCommEvent.First,ifthecommunicationsportisopenfornonoverlappedoperation,WaitCommEventwillbeblockeduntilaneventoccurs.IfanotherthreadcallsSetCommMasktosetaneweventmask,thatthread
willbeblockedonthecalltoSetCommMask.ThereasonisthattheoriginalcalltoWaitCommEventinthefirstthreadisstillexecuting.ThecalltoSetCommMaskblocksthethreaduntiltheWaitCommEvent
functionreturnsinthefirstthread.ThissideeffectisuniversalforportsopenfornonoverlappedI/O.Ifathreadisblockedonanycommunicationsfunctionandanotherthreadcallsacommunicationsfunction,thesecondthreadisblockeduntilthe
communicationsfunctionreturnsinthefirstthread.Thesecondinterestingnoteaboutthesefunctionsistheiruseonaportopenforoverlappedoperation.IfSetCommMasksetsaneweventmask,anypendingWaitCommEventwill
completesuccessfully,andtheeventmaskproducedbytheoperationisNULL.

Caveat

UsingtheEV_RXCHARflagwillnotifythethreadthatabytearrivedattheport.Thisevent,usedincombinationwiththeReadFilefunction,enablesaprogramtoreaddataonlyafteritisinthereceivebuffer,as
opposedtoissuingareadthatwaitsforthedatatoarrive.Thisisparticularlyusefulwhenaportisopenfornonoverlappedoperationbecausetheprogramdoesnotneedtopollforincomingdata;theprogramisnotifiedoftheincomingdatabythe
occurrenceoftheEV_RXCHARevent.Initialattemptstocodethissolutionoftenproducethefollowingpseudocode,includingoneoversightcoveredlaterinthissection:

DWORDdwCommEvent;


DWORDdwRead;


charchRead;




if(!SetCommMask(hComm,EV_RXCHAR))


//Errorsettingcommunicationseventmask.




for(;;){


if(WaitCommEvent(hComm,&dwCommEvent,NULL)){


if(ReadFile(hComm,&chRead,1,&dwRead,NULL))


//Abytehasbeenread;processit.


else


//AnerroroccurredintheReadFilecall.


break;


}


else


//ErrorinWaitCommEvent.


break;


}


TheabovecodewaitsforanEV_RXCHAReventtooccur.Whenthishappens,thecodecallsReadFiletoreadtheonebytereceived.Theloopstartsagain,andthecodewaitsforanotherEV_RXCHARevent.Thiscodeworksfinewhen
oneortwobytesarriveinquicksuccession.ThebytereceptioncausestheEV_RXCHAReventtooccur.Thecodereadsthebyte.IfnootherbytearrivesbeforethecodecallsWaitCommEventagain,thenallisfine;thenextbytetoarrivewill
causetheWaitCommEventfunctiontoindicatetheoccurrenceoftheEV_RXCHARevent.IfanothersinglebytearrivesbeforethecodehasachancetoreachtheWaitCommEventfunction,thenallisfine,too.Thefirstbyteisread
asbefore;thearrivalofthesecondbytecausestheEV_RXCHARflagtobesetinternally.WhenthecodereturnstotheWaitCommEventfunction,itindicatestheoccurrenceoftheEV_RXCHAReventandthesecondbyteisreadfromtheportintheReadFile
call.
Theproblemwiththeabovecodeoccurswhenthreeormorebytesarriveinquicksuccession.ThefirstbytecausestheEV_RXCHAReventtooccur.ThesecondbytecausestheEV_RXCHARflagtobesetinternally.ThenexttimethecodecallsWaitCommEvent,
itindicatestheEV_RXCHARevent.Now,athirdbytearrivesatthecommunicationsport.ThisthirdbytecausesthesystemtoattempttosettheEV_RXCHARflaginternally.Becausethishasalreadyoccurredwhenthesecondbytearrived,thearrivalofthethird
bytegoesunnoticed.Thecodeeventuallywillreadthefirstbytewithoutaproblem.Afterthis,thecodewillcallWaitCommEvent,anditindicatestheoccurrenceoftheEV_RXCHARevent(fromthearrivalofthesecondbyte).Thesecondbyte
isread,andthecodereturnstotheWaitCommEventfunction.Thethirdbytewaitsinthesystem’sinternalreceivebuffer.Thecodeandthesystemarenowoutofsync.Whenafourthbytefinallyarrives,theEV_RXCHAReventoccurs,andthe
codereadsasinglebyte.Itreadsthethirdbyte.Thiswillcontinueindefinitely.
Thesolutiontothisproblemseemsaseasyasincreasingthenumberofbytesrequestedinthereadoperation.Insteadofrequestingasinglebyte,thecodecouldrequesttwo,ten,orsomeothernumberofbytes.Theproblemwiththisidea
isthatitstillfailswhentwoormoreextrabytesabovethesizeofthereadrequestarriveattheportinquicksuccession.So,iftwobytesareread,thenfourbytesarrivinginquicksuccessionwouldcausetheproblem.Tenbytesrequestedwouldstill
failiftwelvebytesarrivedinquicksuccession.
Therealsolutiontothisproblemistoreadfromtheportuntilnobytesareremaining.Thefollowingpseudocodesolvestheproblembyreadinginaloopuntilzerocharactersareread.AnotherpossiblemethodwouldbetocallClearCommError
todeterminethenumberofbytesinthebufferandreadthemallinonereadoperation.Thismethodrequiresmoresophisticatedbuffermanagement,butitreducesthenumberofreadswhenalotofdataarrivesatonce.

DWORDdwCommEvent;


DWORDdwRead;


charchRead;




if(!SetCommMask(hComm,EV_RXCHAR))


//Errorsettingcommunicationseventmask




for(;;){


if(WaitCommEvent(hComm,&dwCommEvent,NULL)){


do{


if(ReadFile(hComm,&chRead,1,&dwRead,NULL))


//Abytehasbeenread;processit.


else


//AnerroroccurredintheReadFilecall.


break;


}while(dwRead);


}


else


//ErrorinWaitCommEvent


break;


}


Theabovecodedoesnotworkcorrectlywithoutsettingthepropertime-outs.Communicationstime-outs,discussedlater,affectthebehavioroftheReadFileoperationinordertocauseittoreturnwithoutwaitingforbytes
toarrive.Discussionofthistopicoccurslaterinthe“CommunicationsTime-outs?sectionofthisarticle.
TheabovecaveatregardingEV_RXCHARalsoappliestoEV_RXFLAG.Ifflagcharactersarriveinquicksuccession,EV_RXFLAGeventsmaynotoccurforallofthem.Onceagain,thebestsolutionistoreadallbytesuntilnoneremain.
Theabovecaveatalsoappliestoothereventsnotrelatedtocharacterreception.Ifothereventsoccurinquicksuccessionsomeofthenotificationswillbelost.Forinstance,iftheCTSlinevoltagestartshigh,thengoeslow,high,and
lowagain,anEV_CTSeventoccurs.ThereisnoguaranteeofhowmanyEV_CTSeventswillactuallybedetectedwithWaitCommEventifthechangesintheCTSlinehappenquickly.Forthisreason,WaitCommEventcannotbeusedto
keeptrackofthestateoftheline.Linestatusiscoveredinthe“ModemStatus?sectionlaterinthisarticle.

ErrorHandlingandCommunicationsStatus

Oneofthecommunicationseventflagsspecifiedinthecallto
SetCommMaskispossiblyEV_ERR.TheoccurrenceoftheEV_ERReventindicatesthatanerrorconditionexistsinthecommunicationsport.OthererrorscanoccurintheportthatdonotcausetheEV_ERReventtooccur.Ineithercase,errorsassociated
withthecommunicationsportcauseallI/Ooperationstobesuspendeduntilremovaloftheerrorcondition.ClearCommErroristhefunctiontocalltodetecterrorsandcleartheerrorcondition.
ClearCommErroralsoprovidescommunicationsstatusindicatingwhytransmissionhasstopped;italsoindicatesthenumberofbyteswaitinginthetransmitandreceivebuffers.Thereasonwhytransmissionmaystopisbecause
oferrorsortoflowcontrol.Thediscussionofflowcontroloccurslaterinthisarticle.
HereissomecodethatdemonstrateshowtocallClearCommError:

COMSTATcomStat;


DWORDdwErrors;


BOOLfOOP,fOVERRUN,fPTO,fRXOVER,fRXPARITY,fTXFULL;


BOOLfBREAK,fDNS,fFRAME,fIOE,fMODE;




//Getandclearcurrenterrorsontheport.


if(!ClearCommError(hComm,&dwErrors,&comStat))


//ReporterrorinClearCommError.


return;




//Geterrorflags.


fDNS=dwErrors&CE_DNS;


fIOE=dwErrors&CE_IOE;


fOOP=dwErrors&CE_OOP;


fPTO=dwErrors&CE_PTO;


fMODE=dwErrors&CE_MODE;


fBREAK=dwErrors&CE_BREAK;


fFRAME=dwErrors&CE_FRAME;


fRXOVER=dwErrors&CE_RXOVER;


fTXFULL=dwErrors&CE_TXFULL;


fOVERRUN=dwErrors&CE_OVERRUN;


fRXPARITY=dwErrors&CE_RXPARITY;




//COMSTATstructurecontainsinformationregarding


//communicationsstatus.


if(comStat.fCtsHold)


//TxwaitingforCTSsignal




if(comStat.fDsrHold)


//TxwaitingforDSRsignal




if(comStat.fRlsdHold)


//TxwaitingforRLSDsignal




if(comStat.fXoffHold)


//Txwaiting,XOFFcharrec'd




if(comStat.fXoffSent)


//Txwaiting,XOFFcharsent




if(comStat.fEof)


//EOFcharacterreceived




if(comStat.fTxim)


//CharacterwaitingforTx;charqueuedwithTransmitCommChar




if(comStat.cbInQue)


//comStat.cbInQuebyteshavebeenreceived,butnotread




if(comStat.cbOutQue)


//comStat.cbOutQuebytesareawaitingtransfer


ModemStatus(a.k.a.LineStatus)

ThecalltoSetCommMaskmayincludetheflagsEV_CTS,EV_DSR,EV_RING,andEV_RLSD.Theseflagsindicatechangesinthevoltageonthelinesoftheserialport.Thereisnoindicationoftheactualstatusoftheselines,
justthatachangeoccurred.TheGetCommModemStatusfunctionretrievestheactualstateofthesestatuslinesbyreturningabitmaskindicatinga0forlowornovoltageand1forhighvoltageforeachofthelines.
PleasenotethatthetermRLSD(ReceiveLineSignalDetect)iscommonlyreferredtoastheCD(CarrierDetect)line.
NoteTheEV_RINGflagdoesnotworkinWindows95asmentionedearlier.TheGetCommModemStatusfunction,however,doesdetectthestateoftheRINGline.
Changesintheselinesmayalsocauseaflow-controlevent.The
ClearCommErrorfunctionreportswhethertransmissionissuspendedbecauseofflowcontrol.Ifnecessary,athreadmaycallClearCommErrortodetectwhethertheeventisthecauseofaflow-controlaction.Flowcontroliscovered
inthe“FlowControl?sectionlaterinthisarticle.
HereissomecodethatdemonstrateshowtocallGetCommModemStatus:

DWORDdwModemStatus;


BOOLfCTS,fDSR,fRING,fRLSD;




if(!GetCommModemStatus(hComm,&dwModemStatus))


//ErrorinGetCommModemStatus;


return;




fCTS=MS_CTS_ON&dwModemStatus;


fDSR=MS_DSR_ON&dwModemStatus;


fRING=MS_RING_ON&dwModemStatus;


fRLSD=MS_RLSD_ON&dwModemStatus;




//Dosomethingwiththeflags.


ExtendedFunctions

Thedriverwillautomaticallychangethestateofcontrollinesasnecessary.Generallyspeaking,changingstatuslinesisunderthecontrolofadriver.IfadeviceusescommunicationsportcontrollinesinamannerdifferentfromRS-232
standards,thestandardserialcommunicationsdriverwillnotworktocontrolthedevice.Ifthestandardserialcommunicationsdriverwillnotcontrolthedevice,acustomdevicedriverisnecessary.
Thereareoccasionswhenstandardcontrollinesareunderthecontroloftheapplicationinsteadoftheserialcommunicationsdriver.Forinstance,anapplicationmaywishtoimplementitsownflowcontrol.Theapplicationwould
beresponsibleforchangingthestatusoftheRTSandDTRlines.EscapeCommFunctiondirectsacommunicationsdrivertoperformsuchextendedoperations.EscapeCommFunctioncanmakethedriverperformsomeotherfunction,such
assettingorclearingaBREAKcondition.Formoreinformationonthisfunction,consultthePlatformSDKdocumentation,theMicrosoftWin32SDKKnowledgeBase,ortheMicrosoftDeveloperNetwork(MSDN)Library.

SerialSettings

DCBSettings

ThemostcrucialaspectofprogrammingserialcommunicationsapplicationsisthesettingsintheDevice-ControlBlock(DCB)structure.ThemostcommonerrorsinserialcommunicationsprogrammingoccurininitializingtheDCBstructureimproperly.
Whentheserialcommunicationsfunctionsdonotbehaveasexpected,acloseexaminationoftheDCBstructureusuallyrevealstheproblem.
TherearethreewaystoinitializeaDCBstructure.ThefirstmethodistousethefunctionGetCommState.ThisfunctionreturnsthecurrentDCBinuseforthecommunicationsport.ThefollowingcodeshowshowtousetheGetCommState
function:

DCBdcb={0};




if(!GetCommState(hComm,&dcb))


//ErrorgettingcurrentDCBsettings


else


//DCBisreadyforuse.


ThesecondmethodtoinitializeaDCBistouseafunctioncalled
BuildCommDCB.Thisfunctionfillsinthebaud,paritytype,numberofstopbits,andnumberofdatabitsmembersoftheDCB.Thefunctionalsosetstheflow-controlmemberstodefaultvalues.Consultthedocumentationofthe
BuildCommDCBfunctionfordetailsonwhichdefaultvaluesitusesforflow-controlmembers.OthermembersoftheDCBareunaffectedbythisfunction.Itistheprogram'sdutytomakesuretheothermembersoftheDCBdonotcauseerrors.The
simplestthingtodointhisregardistoinitializetheDCBstructurewithzerosandthensetthesizemembertothesize,inbytes,ofthestructure.IfthezeroinitializationoftheDCBstructuredoesnotoccur,thentheremaybenonzerovaluesinthe
reservedmembers;thisproducesanerrorwhentryingtousetheDCBlater.Thefollowingfunctionshowshowtoproperlyusethismethod:

DCBdcb;




FillMemory(&dcb,sizeof(dcb),0);


dcb.DCBlength=sizeof(dcb);


if(!BuildCommDCB("9600,n,8,1",&dcb)){


//Couldn'tbuildtheDCB.Usuallyaproblem


//withthecommunicationsspecificationstring.


returnFALSE;


}


else


//DCBisreadyforuse.


ThethirdmethodtoinitializeaDCBstructureistodoitmanually.TheprogramallocatestheDCBstructureandsetseachmemberwithanyvaluedesired.ThismethoddoesnotdealwellwithchangestotheDCBinfutureimplementationsof
Win32andisnotrecommended.
AnapplicationusuallyneedstosetsomeoftheDCBmembersdifferentlythanthedefaultsormayneedtomodifysettingsinthemiddleofexecution.OnceproperinitializationoftheDCBoccurs,modificationofindividualmembersispossible.
ThechangestotheDCBstructuredonothaveanyeffectonthebehavioroftheportuntilexecutionoftheSetCommStatefunction.HereisasectionofcodethatretrievesthecurrentDCB,changesthebaud,andthenattemptstosettheconfiguration:

DCBdcb;




FillMemory(&dcb,sizeof(dcb),0);


if(!GetCommState(hComm,&dcb))//getcurrentDCB


//ErrorinGetCommState


returnFALSE;




//UpdateDCBrate.


dcb.BaudRate=CBR_9600;




//Setnewstate.


if(!SetCommState(hComm,&dcb))


//ErrorinSetCommState.Possiblyaproblemwiththecommunications


//porthandleoraproblemwiththeDCBstructureitself.


HereisanexplanationofeachofthemembersoftheDCBandhowtheyaffectotherpartsoftheserialcommunicationsfunctions.
NoteMostofthisinformationisfromthePlatformSDKdocumentation.Becausedocumentationistheofficialwordinwhatthemembersactuallyareandwhattheymean,thistablemaynotbecompletelyaccurateifchanges
occurintheoperatingsystem.
Table2.TheDCBStructureMembers

Member

Description

DCBlength

Size,inbytes,ofthestructure.ShouldbesetbeforecallingSetCommStatetoupdatethesettings.

BaudRate

Specifiesthebaudatwhichthecommunicationsdeviceoperates.Thismembercanbeanactualbaudvalue,orabaudindex.

fBinary

Specifieswhetherbinarymodeisenabled.TheWin32APIdoesnotsupportnonbinarymodetransfers,sothismembershouldbeTRUE.TryingtouseFALSEwillnotwork.

fParity

Specifieswhetherparitycheckingisenabled.IfthismemberisTRUE,paritycheckingisperformedandparityerrorsarereported.ThisshouldnotbeconfusedwiththeParitymember,whichcontrolsthetypeofparityusedincommunications.

fOutxCtsFlow

SpecifieswhethertheCTS(clear-to-send)signalismonitoredforoutputflowcontrol.IfthismemberisTRUEandCTSislow,outputissuspendeduntilCTSishighagain.TheCTSsignalisundercontroloftheDCE(usuallyamodem),theDTE(usuallythe
PC)simplymonitorsthestatusofthissignal,theDTEdoesnotchangeit.

fOutxDsrFlow

SpecifieswhethertheDSR(data-set-ready)signalismonitoredforoutputflowcontrol.IfthismemberisTRUEandDSRislow,outputissuspendeduntilDSRishighagain.Onceagain,thissignalisunderthecontroloftheDCE;theDTEonlymonitorsthis
signal.

fDtrControl

SpecifiestheDTR(data-terminal-ready)inputflowcontrol.Thismembercanbeoneofthefollowingvalues:

Value

Meaning

DTR_CONTROL_DISABLE

LowerstheDTRlinewhenthedeviceisopened.TheapplicationcanadjustthestateofthelinewithEscapeCommFunction.

DTR_CONTROL_ENABLE

RaisestheDTRlinewhenthedeviceisopened.TheapplicationcanadjustthestateofthelinewithEscapeCommFunction.

DTR_CONTROL_HANDSHAKE

EnablesDTRflow-controlhandshaking.Ifthisvalueisused,itisanerrorfortheapplicationtoadjustthelinewithEscapeCommFunction.

fDsrSensitivity

SpecifieswhetherthecommunicationsdriverissensitivetothestateoftheDSRsignal.IfthismemberisTRUE,thedriverignoresanybytesreceived,unlesstheDSRmodeminputlineishigh.

fTXContinueOnXoff

SpecifieswhethertransmissionstopswhentheinputbufferisfullandthedriverhastransmittedtheXOFFcharacter.IfthismemberisTRUE,transmissioncontinuesaftertheXOFFcharacterhasbeensent.IfthismemberisFALSE,transmissiondoesnotcontinue
untiltheinputbufferiswithinXonLimbytesofbeingemptyandthedriverhastransmittedtheXONcharacter.

fOutX

SpecifieswhetherXON/XOFFflowcontrolisusedduringtransmission.IfthismemberisTRUE,transmissionstopswhentheXOFFcharacterisreceivedandstartsagainwhentheXONcharacterisreceived.

fInX

SpecifieswhetherXON/XOFFflowcontrolisusedduringreception.IfthismemberisTRUE,theXOFFcharacterissentwhentheinputbuffercomeswithinXoffLimbytesofbeingfull,andtheXONcharacterissentwhentheinputbuffercomeswithinXonLimbytes
ofbeingempty.

fErrorChar

SpecifieswhetherbytesreceivedwithparityerrorsarereplacedwiththecharacterspecifiedbytheErrorCharmember.IfthismemberisTRUEandthefParitymemberisTRUE,replacementoccurs.

fNull

Specifieswhethernullbytesarediscarded.IfthismemberisTRUE,nullbytesarediscardedwhenreceived.

fRtsControl

SpecifiestheRTS(request-to-send)inputflowcontrol.Ifthisvalueiszero,thedefaultisRTS_CONTROL_HANDSHAKE.Thismembercanbeoneofthefollowingvalues:

Value

Meaning

RTS_CONTROL_DISABLE

LowerstheRTSlinewhenthedeviceisopened.Theapplicationcanuse
EscapeCommFunction
tochangethestateoftheline.

RTS_CONTROL_ENABLE

RaisestheRTSlinewhenthedeviceisopened.Theapplicationcanuse
EscapeCommFunction
tochangethestateoftheline.

RTS_CONTROL_HANDSHAKE

EnablesRTSflow-controlhandshaking.ThedriverraisestheRTSline,enablingtheDCEtosend,whentheinputbufferhasenoughroomtoreceivedata.ThedriverlowerstheRTSline,preventingtheDCEtosend,whentheinputbufferdoesnothaveenough
roomtoreceivedata.Ifthisvalueisused,itisanerrorfortheapplicationtoadjustthelinewithEscapeCommFunction.

RTS_CONTROL_TOGGLE

SpecifiesthattheRTSlinewillbehighifbytesareavailablefortransmission.Afterallbufferedbyteshavebeensent,theRTSlinewillbelow.Ifthisvalueisset,itwouldbeanerrorforanapplicationtoadjustthelinewithEscapeCommFunction.
ThisvalueisignoredinWindows95;itcausesthedrivertoactasifRTS_CONTROL_ENABLEwerespecified.

fAbortOnError

Specifieswhetherreadandwriteoperationsareterminatedifanerroroccurs.IfthismemberisTRUE,thedriverterminatesallreadandwriteoperationswithanerrorstatus(ERROR_IO_ABORTED)ifanerroroccurs.Thedriverwillnotacceptanyfurther
communicationsoperationsuntiltheapplicationhasacknowledgedtheerrorbycallingtheClearCommErrorfunction.

fDummy2

Reserved;donotuse.

wReserved

Notused;mustbesettozero.

XonLim

SpecifiestheminimumnumberofbytesallowedintheinputbufferbeforetheXONcharacterissent.

XoffLim

SpecifiesthemaximumnumberofbytesallowedintheinputbufferbeforetheXOFFcharacterissent.Themaximumnumberofbytesallowediscalculatedbysubtractingthisvaluefromthesize,inbytes,oftheinputbuffer.

Parity

Specifiestheparityschemetobeused.Thismembercanbeoneofthefollowingvalues:

Value

Meaning

EVENPARITY

Even

MARKPARITY

Mark

NOPARITY

Noparity

ODDPARITY

Odd

StopBits

Specifiesthenumberofstopbitstobeused.Thismembercanbeoneofthefollowingvalues:

Value

Meaning

ONESTOPBIT

1stopbit

ONE5STOPBITS

1.5stopbits

TWOSTOPBITS

2stopbits

XonChar

SpecifiesthevalueoftheXONcharacterforbothtransmissionandreception.

XoffChar

SpecifiesthevalueoftheXOFFcharacterforbothtransmissionandreception.

ErrorChar

Specifiesthevalueofthecharacterusedtoreplacebytesreceivedwithaparityerror.

EofChar

Specifiesthevalueofthecharacterusedtosignaltheendofdata.

EvtChar

SpecifiesthevalueofthecharacterusedtocausetheEV_RXFLAGevent.ThissettingdoesnotactuallycauseanythingtohappenwithouttheuseofEV_RXFLAGintheSetCommMaskfunctionandtheuseofWaitCommEvent.

wReserved1

Reserved;donotuse.

FlowControl

Flowcontrolinserialcommunicationsprovidesamechanismforsuspendingcommunicationswhileoneofthedevicesisbusyorforsomereasoncannotdoanycommunication.Therearetraditionallytwotypesofflowcontrol:hardwareandsoftware.
Acommonproblemwithserialcommunicationsiswriteoperationsthatactuallydonotwritethedatatothedevice.Often,theproblemliesinflowcontrolbeingusedwhentheprogramdidnotspecifyit.AcloseexaminationoftheDCBstructure
revealsthatoneormoreofthefollowingmembersmaybeTRUE:fOutxCtsFlow,fOutxDsrFlow,orfOutX.AnothermechanismtorevealthatflowcontrolisenabledistocallClearCommErrorandexaminetheCOMSTATstructure.Itwill
revealwhentransmissionissuspendedbecauseofflowcontrol.
Beforediscussingthetypesofflowcontrol,agoodunderstandingofsometermsisinorder.Serialcommunicationstakesplacebetweentwodevices.Traditionally,thereisaPCandamodemorprinter.ThePCislabeledtheDataTerminalEquipment
(DTE).TheDTEissometimescalledthehost.Themodem,printer,orotherperipheralequipmentisidentifiedastheDataCommunicationsEquipment(DCE).TheDCEissometimesreferredtoasthedevice.

Hardwareflowcontrol

Hardwareflowcontrolusesvoltagesignalsoncontrollinesoftheserialcabletocontrolwhethersendingorreceivingisenabled.TheDTEandtheDCEmustagreeonthetypesofflowcontrolusedforacommunicationssession.Settingthe
DCBstructuretoenableflowcontroljustconfigurestheDTE.TheDCEalsoneedsconfigurationtomakecertaintheDTEandDCEusethesametypeofflowcontrol.ThereisnomechanismprovidedbyWin32tosettheflowcontroloftheDCE.DIPswitchesonthe
device,orcommandssenttoittypicallyestablishitsconfiguration.Thefollowingtabledescribesthecontrollines,thedirectionoftheflowcontrol,andtheline'seffectontheDTEandDCE.
Table3.HardwareFlow-controlLines

LineandDirection

EffectonDTE/DCE

CTS

(ClearToSend)

Outputflowcontrol

DCEsetsthelinehightoindicatethatitcanreceivedata.DCEsetsthelinelowtoindicatethatitcannotreceivedata.

IfthefOutxCtsFlowmemberoftheDCBisTRUE,thentheDTEwillnotsenddataifthislineislow.Itwillresumesendingifthelineishigh.

IfthefOutxCtsFlowmemberoftheDCBisFALSE,thenthestateofthelinedoesnotaffecttransmission.

DSR

(DataSetReady)

Outputflowcontrol

DCEsetsthelinehightoindicatethatitcanreceivedata.DCEsetsthelinelowtoindicatethatitcannotreceivedata.

IfthefOutxDsrFlowmemberoftheDCBisTRUE,thentheDTEwillnotsenddataifthislineislow.Itwillresumesendingifthelineishigh.

IfthefOutxDsrFlowmemberoftheDCBisFALSE,thenthestateofthelinedoesnotaffecttransmission.

DSR

(DataSetReady)

Inputflowcontrol

IftheDSRlineislow,thendatathatarrivesattheportisignored.IftheDSRlineishigh,datathatarrivesattheportisreceived.

ThisbehavioroccursifthefDsrSensitivitymemberoftheDCBissettoTRUE.IfitisFALSE,thenthestateofthelinedoesnotaffectreception.

RTS

(ReadyToSend)

Inputflowcontrol

TheRTSlineiscontrolledbytheDTE.

IfthefRtsControlmemberoftheDCBissettoRTS_CONTROL_HANDSHAKE,thefollowingflowcontrolisused:Iftheinputbufferhasenoughroomtoreceivedata(atleasthalfthebufferisempty),thedriversetstheRTSlinehigh.Ifthe
inputbufferhaslittleroomforincomingdata(lessthanaquarterofthebufferisempty),thedriversetstheRTSlinelow.

IfthefRtsControlmemberoftheDCBissettoRTS_CONTROL_TOGGLE,thedriversetstheRTSlinehighwhendataisavailableforsending.Thedriversetsthelinelowwhennodataisavailableforsending.Windows95ignoresthisvalueand
treatsitthesameasRTS_CONTROL_ENABLE.

IfthefRtsControlmemberoftheDCBissettoRTS_CONTROL_ENABLEorRTS_CONTROL_DISABLE,theapplicationisfreetochangethestateofthelineasitneeds.Notethatinthiscase,thestateofthelinedoesnotaffectreception.

TheDCEwillsuspendtransmissionwhenthelinegoeslow.TheDCEwillresumetransmissionwhenthelinegoeshigh.

DTR

(DataTerminalReady)

Inputflowcontrol

TheDTRlineiscontrolledbytheDTE.

IfthefDtrControlmemberoftheDCBissettoDTR_CONTROL_HANDSHAKE,thefollowingflowcontrolisused:Iftheinputbufferhasenoughroomtoreceivedata(atleasthalfthebufferisempty),thedriversetstheDTRlinehigh.Ifthe
inputbufferhaslittleroomforincomingdata(lessthanaquarterofthebufferisempty),thedriversetstheDTRlinelow.

IfthefDtrControlmemberoftheDCBissettoDTR_CONTROL_ENABLEorDTR_CONTROL_DISABLE,theapplicationisfreetochangethestateofthelineasitneeds.Inthiscase,thestateofthelinedoesnotaffectreception.

TheDCEwillsuspendtransmissionwhenthelinegoeslow.TheDCEwillresumetransmissionwhenthelinegoeshigh.

TheneedforflowcontroliseasytorecognizewhentheCE_RXOVERerroroccurs.Thiserrorindicatesanoverflowofthereceivebufferanddataloss.Ifdataarrivesattheportfasterthanitisread,CE_RXOVERcanoccur.Increasingthe
inputbuffersizemaycausetheerrortooccurlessfrequently,butitdoesnotcompletelysolvetheproblem.Inputflowcontrolisnecessarytocompletelyalleviatethisproblem.Whenthedriverdetectsthattheinputbufferisnearlyfull,itwilllower
theinputflow-controllines.ThisshouldcausetheDCEtostoptransmitting,whichgivestheDTEenoughtimetoreadthedatafromtheinputbuffer.Whentheinputbufferhasmoreroomavailable,thevoltageonflow-controllinesissethigh,andtheDCE
resumessendingdata.
AsimilarerrorisCE_OVERRUN.Thiserroroccurswhennewdataarrivesbeforethecommunicationshardwareandserialcommunicationsdrivercompletelyreceivesolddata.Thiscanoccurwhenthetransmissionspeedistoohighforthetypeof
communicationshardwareorCPU.Thiscanalsooccurwhentheoperatingsystemisnotfreetoservicethecommunicationshardware.Theonlywaytoalleviatethisproblemistoapplysomecombinationofdecreasingthetransmissionspeed,replacingthecommunications
hardware,andincreasingtheCPUspeed.Sometimesthird-partyhardwaredriversthatarenotveryefficientwithCPUresourcescausethiserror.FlowcontrolcannotcompletelysolvetheproblemsthatcausetheCE_OVERRUNerror,althoughitmayhelptoreduce
thefrequencyoftheerror.

Softwareflowcontrol

Softwareflowcontrolusesdatainthecommunicationsstreamtocontrolthetransmissionandreceptionofdata.Becausesoftwareflowcontrolusestwospecialcharacters,XOFFandXON,binarytransferscannotusesoftwareflowcontrol;the
XONorXOFFcharactermayappearinthebinarydataandwouldinterferewithdatatransfer.Softwareflowcontrolbefitstext-basedcommunicationsordatabeingtransferredthatdoesnotcontaintheXONandXOFFcharacters.
Inordertoenablesoftwareflowcontrol,thefOutXand
fInXmembersoftheDCBmustbesettoTRUE.ThefOutXmembercontrolsoutputflowcontrol.ThefInXmembercontrolsinputflowcontrol.
OnethingtonoteisthattheDCBallowstheprogramtodynamicallyassignthevaluesthesystemrecognizesasflow-controlcharacters.TheXoffCharmemberoftheDCBdictatestheXOFFcharacterforbothinputandoutputflow
control.TheXonCharmemberoftheDCBsimilarlydictatestheXONcharacter.
Forinputflowcontrol,theXoffLimmemberoftheDCBspecifiestheminimumamountoffreespaceallowedintheinputbufferbeforetheXOFFcharacterissent.Iftheamountoffreespaceintheinputbufferdropsbelowthis
amount,thentheXOFFcharacterissent.Forinputflowcontrol,theXonLimmemberoftheDCBspecifiestheminimumnumberofbytesallowedintheinputbufferbeforetheXONcharacterissent.Iftheamountofdataintheinputbufferdrops
belowthisvalue,thentheXONcharacterissent.
Table4liststhebehavioroftheDTEwhenusingXOFF/XONflowcontrol.
Table4.Softwareflow-controlbehavior

Flow-controlcharacter

Behavior

XOFFreceivedbyDTE

DTEtransmissionissuspendeduntilXONisreceived.DTEreceptioncontinues.ThefOutXmemberoftheDCBcontrolsthisbehavior.

XONreceivedbyDTE

IfDTEtransmissionissuspendedbecauseofapreviousXOFFcharacterbeingreceived,DTEtransmissionisresumed.ThefOutXmemberoftheDCBcontrolsthisbehavior.

XOFFsentfromDTE

XOFFisautomaticallysentbytheDTEwhenthereceivebufferapproachesfull.TheactuallimitisdictatedbytheXoffLimmemberoftheDCB.ThefInXmemberoftheDCBcontrolsthisbehavior.DTEtransmissioniscontrolled
bythefTXContinueOnXoffmemberoftheDCBasdescribedbelow.

XONsentfromtheDTE

XONisautomaticallysentbytheDTEwhenthereceivebufferapproachesempty.TheactuallimitisdictatedbytheXonLimmemberoftheDCB.ThefInXmemberoftheDCBcontrolsthisbehavior.

Ifsoftwareflowcontrolisenabledforinputcontrol,thenthe
fTXContinueOnXoffmemberoftheDCBtakeseffect.ThefTXContinueOnXoffmembercontrolswhethertransmissionissuspendedaftertheXOFFcharacterisautomaticallysentbythesystem.IffTXContinueOnXoffis
TRUE,thentransmissioncontinuesaftertheXOFFissentwhenthereceivebufferisfull.IffTXContinueOnXoffisFALSE,thentransmissionissuspendeduntilthesystemautomaticallysendstheXONcharacter.DCEdevicesusingsoftwareflow
controlwillsuspendtheirsendingaftertheXOFFcharacterisreceived.SomeequipmentwillresumesendingwhentheXONcharacterissentbytheDTE.Ontheotherhand,someDCEdeviceswillresumesendingafteranycharacterarrives.The
fTXContinueOnXoffmembershouldbesettoFALSEwhencommunicatingwithaDCEdevicethatresumessendingafteranycharacterarrives.IftheDTEcontinuedtransmissionafteritautomaticallysenttheXOFF,theresumptionoftransmissionwould
causetheDCEtocontinuesending,defeatingtheXOFF.
ThereisnomechanismavailableintheWin32APItocausetheDTEtobehavethesamewayasthesedevices.TheDCBstructurecontainsnomembersforspecifyingsuspendedtransmissiontoresumewhenanycharacterisreceived.TheXON
characteristheonlycharacterthatcausestransmissiontoresume.
OneotherinterestingnoteaboutsoftwareflowcontrolisthatreceptionofXONandXOFFcharacterscausespendingreadoperationstocompletewithzerobytesread.TheXONandXOFFcharacterscannotbereadbytheapplication,sincethey
arenotplacedintheinputbuffer.
Alotofprogramsonthemarket,includingtheTerminalprogramthatcomeswithWindows,givetheuserthreechoicesforflowcontrol:Hardware,Software,orNone.TheWindowsoperatingsystemitselfdoesnotlimitanapplicationinthis
way.ThesettingsoftheDCBallowforSoftwareandHardwareflowcontrolsimultaneously.Infact,itispossibletoseparatelyconfigureeachmemberoftheDCBthataffectsflowcontrol,whichallowsforseveraldifferentflow-controlconfigurations.
Thelimitsplacedonflow-controlchoicesarethereforease-of-usereasonstoreduceconfusionforendusers.Thelimitsplacedonflow-controlchoicesmayalsobebecausedevicesusedforcommunicationsmaynotsupportalltypesofflowcontrol.

CommunicationsTime-outs

Anothermajortopicaffectingthebehaviorofreadandwriteoperationsistime-outs.Time-outsaffectreadandwriteoperationsinthefollowingway.Ifanoperationtakeslongerthanthecomputedtime-outperiod,theoperationiscompleted.
ThereisnoerrorcodethatisreturnedbyReadFile,WriteFile,GetOverlappedResult,orWaitForSingleObject.Allindicatorsusedtomonitortheoperationindicatethatitcompletedsuccessfully.
Theonlywaytotellthattheoperationtimedoutisthatthenumberofbytesactuallytransferredarefewerthanthenumberofbytesrequested.So,ifReadFilereturnsTRUE,butfewerbyteswerereadthanwererequested,theoperationtimed
out.Ifanoverlappedwriteoperationtimesout,theoverlappedeventhandleissignaledandWaitForSingleObjectreturnsWAIT_OBJECT_O.GetOverlappedResultreturnsTRUE,butdwBytesTransferredcontainsthenumberofbytesthat
weretransferredbeforethetime-out.Thefollowingcodedemonstrateshowtohandlethisinanoverlappedwriteoperation:

BOOLWriteABuffer(char*lpBuf,DWORDdwToWrite)


{


OVERLAPPEDosWrite={0};


DWORDdwWritten;


DWORDdwRes;


BOOLfRes;




//Createthiswriteoperation'sOVERLAPPEDstructurehEvent.


osWrite.hEvent=CreateEvent(NULL,TRUE,FALSE,NULL);


if(osWrite.hEvent==NULL)


//Errorcreatingoverlappedeventhandle.


returnFALSE;




//Issuewrite


if(!WriteFile(hComm,lpBuf,dwToWrite,&dwWritten,&osWrite)){


if(GetLastError()!=ERROR_IO_PENDING){


//WriteFilefailed,butitisn'tdelayed.Reporterror.


fRes=FALSE;


}


else


//Writeispending.


dwRes=WaitForSingleObject(osWrite.hEvent,INFINITE);


switch(dwRes)


{


//Overlappedeventhasbeensignaled.


caseWAIT_OBJECT_0:


if(!GetOverlappedResult(hComm,&osWrite,&dwWritten,FALSE))


fRes=FALSE;


else{


if(dwWritten!=dwToWrite){


//Thewriteoperationtimedout.Inowneedto


//decideifIwanttoabortorretry.IfIretry,


//Ineedtosendonlythebytesthatweren'tsent.


//IfIwanttoabort,IwouldjustsetfResto


//FALSEandreturn.


fRes=FALSE;


}


else


//Writeoperationcompletedsuccessfully.


fRes=TRUE;


}


break;




default:


//AnerrorhasoccurredinWaitForSingleObject.Thisusually


//indicatesaproblemwiththeoverlappedeventhandle.


fRes=FALSE;


break;


}


}


}


else{


//WriteFilecompletedimmediately.




if(dwWritten!=dwToWrite){


//Thewriteoperationtimedout.Inowneedto


//decideifIwanttoabortorretry.IfIretry,


//Ineedtosendonlythebytesthatweren'tsent.


//IfIwanttoabort,thenIwouldjustsetfResto


//FALSEandreturn.


fRes=FALSE;


}


else


fRes=TRUE;


}




CloseHandle(osWrite.hEvent);


returnfRes;


}


TheSetCommTimeoutsfunctionspecifiesthecommunicationstime-outsforaport.Toretrievethecurrenttime-outsforaport,aprogramcallstheGetCommTimeoutsfunction.Anapplicationsshouldretrievethe
communicationstime-outsbeforemodifyingthem.Thisallowstheapplicationtosettime-outsbacktotheiroriginalsettingswhenitfinisheswiththeport.Followingisanexampleofsettingnewtime-outsusingSetCommTimeouts:

COMMTIMEOUTStimeouts;




timeouts.ReadIntervalTimeout=20;


timeouts.ReadTotalTimeoutMultiplier=10;


timeouts.ReadTotalTimeoutConstant=100;


timeouts.WriteTotalTimeoutMultiplier=10;


timeouts.WriteTotalTimeoutConstant=100;




if(!SetCommTimeouts(hComm,&timeouts))


//Errorsettingtime-outs.


NoteOnceagain,communicationstime-outsarenotthesameastime-outvaluessuppliedinsynchronizationfunctions.WaitForSingleObject,forinstance,usesatime-outvaluetowaitforanobjecttobecome
signaled;thisisnotthesameasacommunicationstime-out.
SettingthemembersoftheCOMMTIMEOUTSstructuretoallzeroscausesnotime-outstooccur.Nonoverlappedoperationswillblockuntilalltherequestedbytesaretransferred.TheReadFilefunctionisblocked
untilalltherequestedcharactersarriveattheport.TheWriteFilefunctionisblockeduntilallrequestedcharactersaresentout.Ontheotherhand,anoverlappedoperationwillnotfinishuntilallthecharactersaretransferredorthe
operationisaborted.Thefollowingconditionsoccuruntiltheoperationiscompleted:

[align=justify]WaitForSingleObjectalwaysreturnsWAIT_TIMEOUTifasynchronizationtime-outissupplied.WaitForSingleObjectwillblockforeverifanINFINITEsynchronizationtime-outisused.[/align]

GetOverlappedResultalwaysreturnsFALSEand
GetLastErrorreturnsERROR_IO_INCOMPLETEifcalleddirectlyafterthecalltoGetOverlappedResult.

SettingthemembersoftheCOMMTIMEOUTSstructureinthefollowingmannercausesreadoperationstocompleteimmediatelywithoutwaitingforanynewdatatoarrive:

COMMTIMEOUTStimeouts;




timeouts.ReadIntervalTimeout=MAXDWORD;


timeouts.ReadTotalTimeoutMultiplier=0;


timeouts.ReadTotalTimeoutConstant=0;


timeouts.WriteTotalTimeoutMultiplier=0;


timeouts.WriteTotalTimeoutConstant=0;




if(!SetCommTimeouts(hComm,&timeouts))


//Errorsettingtime-outs.


Thesesettingsarenecessarywhenusedwithanevent-basedreaddescribedinthe“Caveat?sectionearlier.InorderforReadFiletoreturn0bytesread,theReadIntervalTimeoutmemberoftheCOMMTIMEOUTS
structureissettoMAXDWORD,andtheReadTimeoutMultiplierandReadTimeoutConstantarebothsettozero.
Anapplicationmustalwaysspecificallysetcommunicationstime-outswhenitusesacommunicationsport.Thebehaviorofreadandwriteoperationsisaffectedbycommunicationstime-outs.Whenaportisinitiallyopen,itusesdefault
time-outssuppliedbythedriverortime-outsleftoverfromapreviouscommunicationsapplication.Ifanapplicationassumesthattime-outsaresetacertainway,whilethetime-outsareactuallydifferent,thenreadandwriteoperationsmaynevercomplete
ormaycompletetoooften.

Conclusion

Thisarticleservesasadiscussionofsomeofthecommonpitfallsandquestionsthatarisewhendevelopingaserialcommunicationsapplication.TheMultithreadedTTYsamplethatcomeswiththisarticleisdesignedusingmanyofthetechniques
discussedhere.Downloaditandtryitout.LearninghowitworkswillprovideathoroughunderstandingoftheWin32serialcommunicationsfunctions.

Bibliography

Brain,Marshall.Win32SystemServices:TheHeartofWindowsNT.EnglewoodCliffs,NJ:PrenticeHall,1994.
Campbell,Joe.CProgrammer’sGuidetoSerialCommunications.2ded.Indianapolis,IN:HowardW.Sams&Company,1994.
Mirho,Charles,andAndyTerrice.“CreateCommunicationsProgramsforWindows95withtheWin32CommAPI.?MicrosoftSystemsJournal12(December1994).(MSDNLibrary,BooksandPeriodicals)

Sendfeedbackonthisarticle.Findsupportoptions.
©2000MicrosoftCorporation.Allrightsreserved.Termsofuse.
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: