Code:
#include <dos.h>
#include <ctype.h>
#include <stdio.h>
#include <string.h>
#include <time.h>
#define BUFLEN 100
#define REPEAT_COUNT 5
#define TIME_LIMIT 5
#define FALSE 0
#define TRUE 1
#define IDLE 0
#define READING 1
#define WRITING 2
#define EVENT_IN_PROGRESS 0
#define EVENT_COMPLETE 1
// Serial Port Setup Addresses for COM1
#define COM1_BASE 0x3F8 // Base address for COM1 Port
#define COM1_BUFFERS COM1_BASE + 0 // Transmitter Holding Buffer (W) and Receiver Buffer (R) when DLAB=0
#define COM1_DL_LSB COM1_BASE + 0 // Divisor Latch (Baud Rate) Least Sig. Byte (R/W) when DLAB=1
#define COM1_INTERRUPT COM1_BASE + 1 // Interrupt Enable (R/W) when DLAB=0
#define COM1_DL_MSB COM1_BASE + 1 // Divisor Latch Baud Rate Most Sig. Byte (R/W) when DLAB=1
#define COM1_INT_ID COM1_BASE + 2 // Interrupt Identification (R)
#define COM1_LINE_CONTROL COM1_BASE + 3 // Line Control Register (R/W)
#define COM1_MODEM_CONTROL COM1_BASE + 4 // Modem Control Register (R/W)
#define COM1_LINE_STATUS COM1_BASE + 5 // Line Status Register (R) (bit 7 is DLAB bit)
#define COM1_MODEM_STATUS COM1_BASE + 6 // Modem Status Register (R)
#define COM1_INTVECT 0x0C // COM1's IRQ Base Address
#define PIC_MASK 0x21 // Programmable Interrupt Controller Mask Register
#define PIC_COMMAND 0x20 // Programmable Interrupt Controller Command Register
#define PIC_EOI 0x20 // End of Interrupt Code
#define RING_BUFFER_SIZE 1025 // Ring Buffer Size in Bytes (# of Chars)
// com_open Return Values
#define COM_OPEN_SUCCESS 0
#define COM_OPEN_INV_FLAG -101
#define COM_OPEN_INV_BAUD -102
#define COM_OPEN_PORT_OPEN -103
// com_close Return Values
#define COM_CLOSE_SUCCESS 0
#define COM_CLOSE_NOT_OPEN -201
// com_write Return Values
#define COM_WRITE_SUCCESS 0
#define COM_WRITE_NOT_OPEN -401
#define COM_WRITE_INV_BUFF -402
#define COM_WRITE_INV_COUNT -403
#define COM_WRITE_DEV_BUSY -404
// com_read Return Values
#define COM_READ_SUCCESS 0
#define COM_READ_NOT_OPEN -301
#define COM_READ_INV_BUFF -302
#define COM_READ_INV_COUNT -303
#define COM_READ_DEV_BUSY -304
// Device Control Block
typedef struct DCB {
int Is_Open;
int *Event_Flag;
int Status;
char *In_Buffer;
int *In_Count;
int *In_Done;
char *Out_Buffer;
int *Out_Count;
int *Out_Done;
char Ring_Buffer[RING_BUFFER_SIZE];
int Ring_Buffer_In;
int Ring_Buffer_Out;
int Ring_Buffer_Count;
} DCB;
// Function Prototypes
void Output_Interrupt(void);
/* com_open: open the com port */
/* RETURNS: error code, or zero if ok */
int com_open (int *ef_p, /* ptr to event flag */
int baud_rate /* requested speed */
);
/* com_close: close the com port */
/* RETURNS: error code, or zero if ok */
int com_close (void);
/* com_read: begin block input */
/* RETURNS: error code, or zero if ok */
int com_read (char *buf_p, /* ptr to buffer */
int *count_p /* ptr to max. no. of chars to read */
);
/* com_write: begin block output */
/* RETURNS: error code, or zero if ok */
int com_write (char *buf_p, /* ptr to buffer */
int *count_p /* ptr to no. of chars to write */
);
void abort_test(void);
DCB Com1;
// Begin COM1 Interrupt Setup Functions
void interrupt (*old_COM1_Interrupt)();
void interrupt COM1_Interrupt() {
if (Com1.Is_Open) {
switch (inportb(COM1_INT_ID) & 0x07) {
case 0 : // Modem Status Interrupt
inportb(COM1_MODEM_STATUS);
break;
case 1 : // Output Interrupt
Output_Interrupt();
break;
case 2 : // Input Interrupt
//Input_Interrupt();
break;
case 3 : // Line Status Interrupt
inportb(COM1_LINE_STATUS);
break;
}
}
outportb(PIC_COMMAND, PIC_EOI);
}
void Output_Interrupt() {
if (Com1.Status == WRITING) {
if (*Com1.Out_Count != *Com1.Out_Done) {
// Write next char to com port
outportb(COM1_BASE, *Com1.Out_Buffer);
Com1.Out_Buffer++;
(*Com1.Out_Done)++;
} else {
Com1.Status = IDLE;
*Com1.Event_Flag = EVENT_COMPLETE;
outportb(COM1_INTERRUPT, inportb(COM1_INTERRUPT) & ~0x02);
}
}
}
// End COM1 Interrupt Setup Functions
/* com_open
Version 0.1
April 2, 2009
*/
int com_open(int *eflag_p, int baud_rate) {
int Baud_Rate_Div;
int Return_Val = COM_OPEN_SUCCESS;
if (Com1.Is_Open) Return_Val = COM_OPEN_PORT_OPEN;
else if (eflag_p == 0) Return_Val = COM_OPEN_INV_FLAG;
else if (baud_rate < 0) Return_Val = COM_OPEN_INV_BAUD;
else {
// Initialize Com1 DCB
Com1.Is_Open = TRUE;
Com1.Event_Flag = eflag_p;
Com1.Status = IDLE;
Com1.Ring_Buffer_In = 0;
Com1.Ring_Buffer_Out = 0;
Com1.Ring_Buffer_Count = 0;
// Set up New Interrupts
outportb(COM1_LINE_CONTROL, 0x00); // Set DLAB = 0
outportb(COM1_INTERRUPT, 0x00); // Turn off interrupts
old_COM1_Interrupt = getvect(COM1_INTVECT); // Save Old Interrupt
setvect(COM1_INTVECT, COM1_Interrupt); // Set New Interrupt
Baud_Rate_Div = 115200 / (long) baud_rate;
outportb(COM1_LINE_CONTROL, 0x80); // Set DLAB = 1
outportb(COM1_DL_LSB, Baud_Rate_Div & 0xFF); // Set Baud rate - Divisor Latch Low Byte
outportb(COM1_DL_MSB, (Baud_Rate_Div >> 8) & 0xFF); // Set Baud rate - Divisor Latch High Byte
outportb(COM1_LINE_CONTROL, 0x03); // 8 Bits, No Parity, 1 Stop Bit
disable();
outportb(PIC_MASK, (inportb(PIC_MASK) & ~0x80));// Set Programmable Interrupt Controller
enable();
outportb(COM1_MODEM_CONTROL, 0x08); // Enable Serial Interrupts
outportb(COM1_INTERRUPT, 0x01); // Enable Input Ready Interrupts
}
return Return_Val;
}
/* com_close
Version 0.1
April 2, 2009
*/
int com_close() {
int Return_Val = COM_CLOSE_SUCCESS;
if (!Com1.Is_Open) Return_Val = COM_CLOSE_NOT_OPEN;
else {
Com1.Is_Open = FALSE;
// Reset Communication Protocol to original settings
outportb(COM1_LINE_CONTROL, 0x00); // Set DLAB = 0
outportb(COM1_MODEM_CONTROL, 0x00); // Disable Serial Interrupts
outportb(COM1_INTERRUPT, 0x00); // Turn off interrupts
disable();
outportb(PIC_MASK, (inportb(PIC_MASK) & 0x10)); // Set Programmable Interrupt Controller
enable();
setvect(COM1_INTVECT, old_COM1_Interrupt); // Restore Old Interrupt Vector
}
return Return_Val;
}
/* com_write
Version 0.1
April 2, 2009
*/
int com_write(char *buf_p, int *count_p) {
int Return_Value = COM_WRITE_SUCCESS;
if (!Com1.Is_Open) Return_Value = COM_WRITE_NOT_OPEN;
else if (Com1.Status != IDLE) Return_Value = COM_WRITE_DEV_BUSY;
else if (buf_p == 0) Return_Value = COM_WRITE_INV_BUFF;
else if (count_p == 0) Return_Value = COM_WRITE_INV_COUNT;
else {
Com1.Out_Buffer = buf_p;
Com1.Out_Count = count_p;
*Com1.Out_Done = 0;
Com1.Status = WRITING;
*Com1.Event_Flag = EVENT_IN_PROGRESS;
// Write first char to com port
outportb(COM1_BASE, *Com1.Out_Buffer);
Com1.Out_Buffer++;
Com1.Out_Done++;
outportb(COM1_INTERRUPT, inportb(COM1_INTERRUPT) | 0x02);
}
return Return_Value;
}
// CODE BELOW WAS PROVIDED AND CANNOT BE CHANGED
void main(void)
{
int e_flag; /* event flag */
int ix; /* loop index */
int rc; /* function return code */
char buffer[BUFLEN]; /* output buffer */
int length;
long tstart;
/* open com port */
rc = com_open( (int *) &e_flag, 1200);
if ( rc != 0) {
printf("\nOPEN failed!\n");
printf("error code = %d\n",rc);
abort_test();
}
/* fill buffer with Xs */
for (ix=0; ix<BUFLEN; ix++) buffer[ix] = 'X';
/* insert test string */
strcpy(buffer,"This is a test of com driver output ");
strcat(buffer,"abcdefghijklmnopqrstuvwxyz 0123456789\012\015");
length = strlen(buffer);
/* output test string the specified number of times */
for (ix=1; ix<=REPEAT_COUNT; ix++) {
e_flag = 0;
rc = com_write((char *) buffer, (int *) &length);
if (rc != 0) {
printf("\nWRITE error!\n");
printf("error code = %d\n",rc);
abort_test();
}
/* loop until output is done */
tstart = time(NULL);
while (e_flag == 0) {
if ((time(NULL) - tstart) > TIME_LIMIT) {
printf("\nTIMEOUT: event flag not set\n");
abort_test();
}
}
}
/* output final message */
e_flag = 0;
length = 31;
rc = com_write((char *) "End of Com Driver Output Test\012\015",
(int *) &length);
if (rc != 0) {
printf("\nWRITE error on final message!\n");
printf("error code = %d\n",rc);
abort_test();
}
/* loop until output is done */
tstart = time(NULL);
while (e_flag == 0) {
if ((time(NULL) - tstart) > TIME_LIMIT) {
printf("\nTIMEOUT: event flag not set\n");
abort_test();
}
}
/* close the com port */
rc = com_close();
if ( rc != 0) {
printf("\nCLOSE failed!\n");
printf("error code = %d\n",rc);
exit();
}
printf("Test completed successfully!\n");
}
/*
Abort after error
*/
void abort_test()
{
int err;
printf("\nAborting com port test\n");
err = com_close();
if (err!=OK) printf("Error on close\n");
exit();
}
When I run this, the first character of buffer ('T') is received, but no other chars are. I eventually get the following output...