Part II • Managing Data in C
Listing 9.8. continued
int nStatus;
/* The PC’s serial port is at address 0040:0000
*(for COM1:). If a zero is stored at that address,
*a serial port is not installed.
*/
pSerialPort = MAKELP(BIOS_DATA_PAGE, COM1); nPort = *pSerialPort;
if (nPort == 0)
{/* No serial port is installed! */ printf(“No serial installed... WHY?\n”); return(0);
}
/* Write the data byte to the serial port’s data lines.
*The program must wait until the last character
*has been sent because the simple hardware does not
*have a queue.
*/
nStatus = inp(LSR_PORT);
while (!(nStatus & TRANS_HOLDING_REGISTER))
{/* Simply get the status again, which wastes time */ nStatus = inp(LSR_PORT);
}
outp(THR_PORT, chChar);
return(1);
}
int SerialStatus()
{
Part II • Managing Data in C
Listing 9.8. continued
else
{
printf(“RTS is low. \n”);
}
nStatus = inp(IER_PORT);
printf(“IER_PORT returned %2.2X\n”, nStatus);
nStatus = inp(IIR_PORT);
printf(“IIR_PORT returned %2.2X\n”, nStatus);
nStatus = inp(LCR_PORT);
printf(“LCR_PORT returned %2.2X\n”, nStatus);
nStatus = inp(MCR_PORT);
printf(“MCR_PORT returned %2.2X\n”, nStatus);
nStatus = inp(LSR_PORT);
printf(“LSR_PORT returned %2.2X\n”, nStatus);
nStatus = inp(MSR_PORT);
printf(“MSR_PORT returned %2.2X\n”, nStatus);
return(1);
}
SENDCOMM is simple, in that it only displays the status of the registers, then sends the string. Following is the code that sends the characters:
nStatus = inp(LSR_PORT);
while (!(nStatus & TRANS_HOLDING_REGISTER))
{/* Simply get the status again, which wastes time */
Disk Files and Other I/O |
C C C |
|
C9C |
|
C C C |
|
C |
nStatus = inp(LSR_PORT);
}
outp(THR_PORT, chChar);
First, the program gets the port’s status. If the TRANS_HOLDING_REGISTER bit is clear, the character can be sent. If the bit is set, the program waits for the hardware to send the current character, at which point the bit is cleared.
After the TRANS_HOLDING_REGISTER is clear, the program sends the character using a call to outp(). The hardware handles the serial transmission of the character in a serial format.
SENDCOMM.C is a simple character sending program. Receiving a character is just as easy. Listing 9.9, READCOMM.C, gets a character from the serial port, sends it back (echoes the character), and displays it on the terminal’s screen.
Listing 9.9. READCOMM.C.
/* READCOMM, written 1992 by Peter D. Hipson
*This program reads characters from the serial port.
*You should run this program under DOS on a PC. If
*your computer is not a PC-compatible, DO NOT RUN
*this program. Also, the program should be compiled
*with Microsoft C.
*/ |
|
|
#include <stdio.h> |
// Make includes first part of file |
#include <conio.h> |
// Console I/O functions |
#include <string.h> |
// For |
string functions |
#include <stdlib.h> |
// Standard include items |
#include <process.h> // For |
exit(), etc. |
#include <time.h> |
// To seed random numbers |
#define MAKELONG(low, high) |
((long)(((unsigned short int)(low)) \ |
| (((unsigned long |
int)((unsigned short int)(high))) << 16))) |
#define MAKELP(sel, |
off) |
((void _far*)MAKELONG((off), (sel))) |
/* Comm port definitions */
continues
Part II • Managing Data in C
Listing 9.9. continued
#define BIOS_DATA_PAGE |
0x0040 |
|
|
#define COM1 |
0x0000 |
|
|
/* Receive a character port (read only) */ |
|
#define RBR_PORT |
(nPort) |
|
/* Send (transmit) a character port (write only) */ |
|
#define THR_PORT |
(nPort) |
|
/* Interrupt enable register */ |
|
|
|
#define IER_PORT |
(nPort + 1) |
|
#define RECEIVED_DATA_AVAILABLE |
0x01 |
|
|
#define TRANSMIT_HOLD_EMPTY |
0x02 |
|
|
#define RECIEVER_LINE_STATUS |
0x04 |
|
|
#define MODEM_STATUS |
0x08 |
|
|
/* Other bits undefined */ |
|
|
|
/* Interrupt identify register (read only) */ |
|
#define IIR_PORT |
(nPort + 2) |
|
#define INTERUPT_PENDING_0 |
0x01 |
|
|
#define INTERUPT_ID_BIT_1 |
0x02 |
|
|
#define INTERUPT_ID_BIT_2 |
0x04 |
|
|
/* Other bits undefined */ |
|
|
|
/* Line control register */ |
|
|
|
#define LCR_PORT |
(nPort + 3) |
|
#define WORD_LENGTH_SELECT_1 |
0x01 |
/* 00 = 5 bits, 01 = 6 bits */ |
#define WORD_LENGTH_SELECT_2 |
0x02 |
/* 10 = 7 bits, 11 = 8 bits |
*/ |
#define NUMBER_STOP_BITS |
0x04 |
/* 0 = 1 stop, 1 = 2 stop |
*/ |
#define PARITY_ENABLE |
0x08 |
|
|
#define EVEN_PARITY_SELECT |
0x10 |
|
|
#define STICK_PARITY |
0x20 |
|
|
#define SET_BREAK |
0x40 |
|
|
#define DIVISOR_LATCH_BIT |
0x80 |
/* For DLL and DLH access */ |
|
/* Other bits undefined */ |
|
|
|
/* Modem control register */ |
|
|
|
#define MCR_PORT |
(nPort + 4) |
|
#define DTR |
0x01 |
|
|
#define RTS |
0x02 |
|
|
#define OUT_1 |
0x04 |
|
|
Part II • Managing Data in C
Listing 9.9. continued
#define |
BAUD_300 |
0x0180 |
#define |
BAUD_600 |
0x00C0 |
#define |
BAUD_1200 |
0x0060 |
#define |
BAUD_1800 |
0x0040 |
#define |
BAUD_2000 |
0x003A |
#define |
BAUD_2400 |
0x0030 |
#define |
BAUD_3600 |
0x0020 |
#define |
BAUD_4800 |
0x0018 |
#define |
BAUD_7200 |
0x0010 |
#define |
BAUD_9600 |
0x000C |
#define |
BAUD_14400 |
0x0008 |
#define |
BAUD_19200 |
0x0006 |
#define |
BAUD_38400 |
0x0003 |
#define |
BAUD_56000 |
0x0002 |
#define |
BAUD_112000 |
0x0001 |
/* End serial port definitions */ |
int main( |
// Define main() and the fact that |
int |
argc, |
// this program uses the passed parameters |
char |
*argv[], |
|
char |
*envp[] |
|
); |
|
|
int GetSerialCharacter(char *chChar); |
int SerialStatus(void); |
int main( |
|
int |
argc, |
|
char |
*argv[], |
|
char |
*envp[] |
|
) |
|
|
{ |
|
|
char |
chChar; |
|
int |
nStatus; |
|
int |
i; |
|
Part II • Managing Data in C
Listing 9.9. continued
if (nPort == 0)
{/* No serial is installed! */
printf(“No serial installed...Why?\n”); return(0);
}
/* To read a character, the DATA_READY signal must be set
*(see the previous defines). This bit is in LSR_PORT.
*If DATA_READY is set, the program reads a character
*and returns TRUE.
*/
nStatus = inp(LSR_PORT);
if (nStatus & DATA_READY)
{/* A character has been received. */ *chChar = inp(RBR_PORT);
/* Echo the data byte back to the sender. The program
*must wait until the last character has been sent
*because the simple hardware does not have a queue.
*/
nStatus = inp(LSR_PORT);
while (!(nStatus & TRANS_HOLDING_REGISTER))
{/* Simply get the status again, which wastes time */ nStatus = inp(LSR_PORT);
}
outp(THR_PORT, *chChar);
return(1);
}
return(0);
}
int SerialStatus()