Thursday, February 05, 2009

Win32 DCB Trap

In Win32 serial communication functions, the DCB is very important struct (which is similar to termios struct in *UIX). There are several Win32 functions can change the struct - SetCommState, GetCommState and BuildCommDCB. When you want to use them, you have to notice some traps:

Trap 1:
DCB dcbSerial = {0};
dcbSerial.DCBlength = sizeof(dcbSerial);
dcbSerial.BaudRate = CBR_19200;
dcbSerial.ByteSize = 8;
dcbSerial.StopBits = ONESTOPBIT;
dcbSerial.Parity = NOPARITY;
if(!SetCommState(hSerial, &dcbSerial)){
//error setting serial port state
}
In above code, you clear all fields first and set some basic parameters. Please DON'T set DCB in this way.  That will set zero to important fields such as XonLim and XoffLim and cause some serial adapter driver to return fail. XonLim can not be the same as XoffLim if any flow control is enabled. 


Trap 2:
DCB dcbSerial = {0};
dcbSerial.DCBlength = sizeof(dcbSerial);
BuildCommDCB(“baud=1200 parity=N data=8 stop=1”, &dcbSerial);
if(!SetCommState(hSerial, &dcbSerial)){
//error setting serial port state
}  
This is very similar to trap 1. BuildCommDCB is just for compatbility and only few people will use it in Win32. It use the "mode" (one DOS program) style to describe serial parameter. 

The best way to set DCB is to get previous setting by calling GetCommState. This is also verys similer to *UIX termios - you should get old termios setting before setting new termios. That means: Get all old settings, change the field which you really want to change and set the new settings.

Correct way:
DCB dcbSerial = {0};
dcbSerial.DCBlength = sizeof(dcbSerial);
GetCommDCB(hSerial, &dcbSerial);
dcbSerial.BaudRate = CBR_19200;
dcbSerial.ByteSize = 8;
dcbSerial.StopBits = ONESTOPBIT;
dcbSerial.Parity = NOPARITY;
if(!SetCommState(hSerial, &dcbSerial)){
//error setting serial port state

Change the specific field only and don't touch others if and only if you know what you are doing. This way can keep the previous settings.

No comments: