HOWTO- handle serial ports in QNX (and probably unix in general)
1.0 Introduction
Under QNX, the kernel only handles message routing between processes. Dev is the device manager and oversees various device drivers. Dev.ser drives the serial ports on PC architectures. The port parameters (baud rate, parity,...) can be set by Dev.ser in /etc/sysinit, or they can be altered in a shell by stty or within a user process by tcsetattr(). Processes can detect the state of the serial port with tcgetattr(). At the shell level, use "stty < /dev/ser". Most of this was figured out by trial and error with John Staren and by following examples in qtalk 1.0 by Quantum Software Systems.
2.0 C code
2.1 Define the basic data type
The examples are b_port.h and b_port.c. Within the include file, we define a structure,
where we have separated the input and output channels. This is easiest, since then you can be sloppy about the handshaking INSIDE the code. You still have to be careful with the hardware. The buffers are merely conveniences.
2.2 Initialize
A sample initial code is:
Here portlocation is the string of the pathname to the serial port, such as "/dev/ser1".
By using pointers to PORTs, one can define them with
PORT *serport;
This is a convenient method since it can become an array of ports by allocating memory BEFORE initializing. For example:
serport = (PORT *)calloc(NUMBEROPORTS,sizeof(PORT));
which allocates enough contiguous memory for NUMBEROPORTS serial port structures. Then they can be referred by serport, serport+1, ... serport+NUMBEROPORTS. This may be too abstract and one may wish to define aliases in the preprocessor, i.e. #define COMPORT2 serport+1 or #define SERCONSOLE serport+4.
2.3 Reading and Writing
One can now write to a port with fprintf(). For example,
void swritep(PORT *sp, char *buffer) {
fprintf(sp->osp,"%s",buffer);
fflush(sp->osp); /*needed to force transmission*/
}
Reading is a bit more problematic because we have to decide when the port has failed to read anything or when the reception is finished. Under QNX one can conveniently use dev_read() which contains timers to to quit the read when the transmission stops or becomes slow. Example:
int sreadp(PORT *sp) {
int result=0,n;
if ( (n=dev_ischars(sp->ifd)) > 0 ) { /*if there are characters*/
result = dev_read(sp->ifd,sp->ibuf,n,BSIZE,1,1,0,0); /*read them and */
} return result; /*return length of string*/
}
See the Watcom library manuals for a description of dev_read. dev_*() functions require the file descriptor, which is why we add it to the PORT structure.
In these examples we simply pass strings back and forth. Other ways of doing it might be to pass a union if the device you were talking to was going to hand back bytes only.
Error checking has to be performed above the sreadp(), swritep() level.