home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Shareware Overload
/
ShartewareOverload.cdr
/
progm
/
ibmcom.zip
/
IBMCOM.C
< prev
next >
Wrap
Text File
|
1987-11-11
|
31KB
|
988 lines
/***************************************************
* *
* I B M C O M *
* =========== *
* *
* Comments: IBM RS232 interrupted driven *
* communications routines. If you whish *
* to see these routines continue to be *
* supported with ehancements,bug fixes, *
* protocals, terminal emulators,etc. *
* Send $15 to: *
* Intrinsic Computers *
* RR 4 *
* Oak Ridge,NJ 07438 *
* Send $25 and we'll give you the latest*
* version on a diskette. *
* *
* Programmer(s): Al Morgan *
* Revision 1.0 *
* Revision Date:09/17/1987 *
* Converted to TurboC *
* *
* Description of Routines: *
* init_handl( int port_num) *
* Initializes port_num interrupt routines. *
* Must be called after init_port(),but before *
* using any other routines. *
* *
* init_port(port_num,baudrate,parity,data_bits, *
* stopbit) *
* Must be called before init_handl(). It sets *
* the port_num's baud rate,parity,etc.. *
* *
* check_port_hw(port_num) *
* Used to check if a port error has occured or *
* if no error it returns the number of char *
* in the ports interrupt buffer. *
* *
* check_port_buf(port_num) *
* Returns port_num's buffer overflow status. *
* *
* com_status(port_num) *
* Returns port_num's port status. *
* *
* clear_char_from_port(port_num) *
* Reads a char from port_num. Used to clear *
* a character from the port after a port error *
* detected. *
* *
* reset_port(port_num) *
* Resets port_num so that it will not interrupt*
* the IBM anymore. Used to halt communications *
* Should be called before exiting your programs*
* or interrupts will still be active and *
* hang the machine (or worse). *
* *
* putc_com(port_num,character) *
* Outputs the indicated character to port_num *
* Does not buffer the character. It uses a *
* polling technique. Depending on user *
* response I may make it interrupt driven in a *
* later version of these routines. *
* *
* puts_com(port_num,string,num_char) *
* Outputs the indicated num_char from string *
* to port_num. *
* *
* getc_com(port_num) *
* Gets a char from port_num's buffer. If the *
* buffer is empty it returns 0xFF which could *
* be a valid character. This routine should be *
* used in conjunction with check_port_buf() to *
* see if any characters are in the buffer *
* before call this routine. *
* *
* gets_com(buffer,num_bytes,port_num) *
* Gets num_bytes from port_num and puts it *
* into the string buffer. *
* *
* report_serial_stauts(error_code) *
* Will print out the port status if you pass *
* it the port status (obtained from *
* com_status(). Note, not all status bits are *
* errors, some are normal. See this routines *
* code for detailed explanation of what the *
* bits mean. *
* *
* Compilation Instructions: *
* Compile this file with DEBUG set to FALSE *
* to use with your routines. Set DEBUG to TRUE *
* to test these routines by themseleves. *
* *
* Linking Instructions: *
* Not a main file (unless you compile with *
* DEBUG set to TRUE). Must be linked with *
* a main() and circ_buf.obj *
* *
* References Used: *
* Interrupts and the IBM PC Parts 1&2, *
* Nov/Dec 83,January 84,PC Tech Journal *
* *
* *
* 8088 Assembly Lanquage Programming : The *
* IBM PC,Willow D.,Krantz J.,Howard Sames & Co., *
* Indianapolis,Indiana *
* *
***************************************************/
/*
This file plus circ_buf.c implements a simple set of interrupt
routines for ports 1 and 2 of the IBM PC/XT family and clones. The
interrupt routines use circular buffers. These routines have been
tested up 19.2kbaud. Buffer sizes and other features can be changed
by changing defines in the following code.
The input side of the routines are interrupt driven using an
unconventional approach to implementing interrupts with TurboC (but
such is life). They where written that way because our philosohy in
a interrupt routine is to do it fast, with minimum of overhead.
Knowing that the interrupt itself imposes a high overhead (as
compared to a dedicated polling techique) we decided to bypass
Borlands interrupt implementation. The output side of the routines
use a simple polled technique. This will get you by, untill we can
write a interrupt output routine (we're working on it). If you have
any comments lets us know via our compuserve number (75036,1602). Do
you want support for ports 3 and 4? Do you want interrupt output?
Any bugs? Let us know.
Thanks
Al Morgan
PS. This code is subject to the normal disclaimer. We specifically
disclaim all warranties, expressed or implied, including but not
limited to implied warranties of merchantability and fitness for a
particular purpose with respect to defects in the documentation and
with respect to any particular application, use, or purpose. In
no event shall Intrinsic be liable for any loss of profit or any
other commercial damage, including but not limited to special,
incidental consequential or other damages.
*/
#include <stdio.h>
#include <dos.h>
#include "circ_buf.h" /* contains circular buffer structure definitions */
#define FALSE 0
#define TRUE 1
/* Change the buffer size and recompile to your likeing, Max is 32k */
#define BUFFER_1_SIZE 1000 /* define size of buffer */
#define BUFFER_2_SIZE 1000 /* define size of buffer */
#define PORT1_BASE_AD 0x3f8
#define PORT1_INT_VECTOR_NUM 12
#define PORT1_INT_MASK 0xEF
#define PORT2_BASE_AD 0x2f8
#define PORT2_INT_VECTOR_NUM 11
#define PORT2_INT_MASK 0xF7
#define PORT3_BASE_AD 0x2f8
#define PORT3_INT_VECTOR_NUM 11
#define PORT3_INT_MASK 0xF7
#define PORT4_BASE_AD 0x2f8
#define PORT4_INT_VECTOR_NUM 11
#define PORT4_INT_MASK 0xF7
#define DEBUG TRUE
/* The follwing define allows you have the interrupt routines
set a flag (message_in_buffer) when the EOM_CHAR is recieved
by the interrupt routine. This is particularly useful if all
your messages are terminated with a particular character such
as a carraige return. You must define the character if you
want to use it, otherwise comment it out or delete it. If you
do use it, it is up to your routines to reset the
message_in_buffer flag. */
#define EOM_CHAR '!'
#if DEBUG != TRUE
#ifdef EOM_CHAR
extern int message_in_buffer; /* You must define it in your main file */
#endif
#endif
static int serial_port_address[]={PORT1_BASE_AD,PORT2_BASE_AD};
static int vector_number[]={PORT1_INT_VECTOR_NUM,PORT2_INT_VECTOR_NUM};
static unsigned char interrupt_mask[]={PORT1_INT_MASK,PORT2_INT_MASK};
static char buffer2[BUFFER_1_SIZE],buffer1[BUFFER_2_SIZE];
static circ_buffer_description cb1,cb2;
static circ_buffer_description *buffer_descript[]={&cb1,&cb2};
#ifdef EOM_CHAR
static char eom=EOM_CHAR;
#endif
#if DEBUG == TRUE
int message_in_buffer=0;
void init_handl(int),dump_buf(int,int);
void report_serial_status(int),putc_com(int,char),report_circ_status(int);
unsigned char com_status(int);
main ()
{
int pe,i,j,nc,port;
char tbuffer[100];
/*
This main routine is mainly for testing the communications routines.
Its also shows how the routine can be used, and in what sequence.
*/
printf("Testing %s\n",__FILE__);
printf("Version Date: %s, Time: %s\n",__DATE__,__TIME__);
port = 1;
/* First initialize the ports baud rate, parity, etc */
if( init_port(port,19200,'n',8,1) != TRUE)
{
puts("Error on initializing the baud rate,etc\n");
exit(0);
}
/* Next initialize the interrupt drivers for the port */
init_handl(port);
/* Output a string through the port */
puts_com(port,"Testing IBMCOM.C\n",17);
do
{
if( (pe=check_port_hw(port)) < 0 ) /* If < 0 then a port error */
{
printf("Port Error 0x%02x\n",-pe);
report_serial_status(-pe); /* print out the error code in english */
}
/* report_circ_status(port); */ /* for debugging */
if(pe > 0 || check_port_buf(port)) /* If no port errors, see any chars in ports buffer */
{
while((nc = gets_com (tbuffer,sizeof(tbuffer),port)) != 0)
{
for(i=0;i<nc;i++)
{
putch(tbuffer[i]); /* display the characters on the console */
putc_com(port,tbuffer[i]); /* echo back characters */
}
}
/* report_serial_status(com_status(port)); */ /* for debugging */
}
sleep(3); /* delay for a while */
}
while(ci() != 27);
reset_port(port); /* before we exit, turn off interrupts */
}
void report_circ_status(int port_num)
{
/* This routine used for debugging only */
printf("\n**** Circular buffer status for Port %d\n",port_num);
printf("\tHead ptr = %d\n",buffer_descript[port_num-1]->head);
printf("\tTail ptr = %d\n",buffer_descript[port_num-1]->tail);
printf("\tBuf adrs = %d\n",buffer_descript[port_num-1]->address);
printf("\tBuf end = %d\n",buffer_descript[port_num-1]->end);
printf("\tBuf length = %d\n",buffer_descript[port_num-1]->length);
printf("\tChar Count = %d\n",buffer_descript[port_num-1]->char_count);
printf("\tOverflow flag = %d\n",buffer_descript[port_num-1]->overflow_flag);
/* printf("\tOverflow flag = %d\n",cb1.overflow_flag); */
dump_buf(port_num,buffer_descript[port_num-1]->length+3);
}
int ci(void)
{
/* This routine used for debugging only */
int c;
if (!bioskey(1))
return(0);
c = getch();
return(c);
}
vputc(char tchar)
{
/* This routine used for debugging only */
union REGS regs;
regs.h.ah = 0x0a;
regs.h.al = tchar;
regs.h.bh = 0; /* page 0 */
regs.h.cl = 1; /* number of times to write char */
regs.h.ch = 0;
int86(0x10,®s,®s);
printf("\tOverflow flag = %d\n",cb1.overflow_flag);
}
#endif
/*****************************************
** **
** Init_handl **
** **
*****************************************/
void init_handl (int port_num)
{
int port_address;
char in_byte;
unsigned asynch_offset; /* offset of Asynch routine */
void interrupt (*int_routine_pntr)();
int dummy_value;
dummy_value=1;
if(port_num<1 || port_num>2)
return;
/*
This routine initializes the hardware for the serial ports 1 & 2
of the IBM PC/XT to interrupt the processor when a character is
recieved. The routine also sets up the proper vector locations
to point to a interupt handler for each port. The interupt handler
are contained in this routine. This routine sets aside a
buffer for storage of the incomming characters. The buffer size is
definable by the user (from 0 to 32k) and is passed when the routine
is compiled.
The routine should be called after the port parameters
(baudrate,parity,stop bits,etc) had been setup (by init_port(..).
and then never again (unless the port has been reset (by reset_port() ).
The routine returns a FALSE if the port_num is not 1 or 2.
*/
if ( port_num == 1)
{
buffer_descript[0]->address = buffer1;
buffer_descript[0]->length = sizeof(buffer1);
asm mov ax,offset asynch_int1 /* put this ports interrupt handler offset into table */
asm mov asynch_offset,ax
}
if (port_num == 2)
{
buffer_descript[1]->address = buffer2;
buffer_descript[1]->length = sizeof(buffer2);
asm mov ax,offset asynch_int2 /*put this ports interrupt handler offset into table */
asm mov asynch_offset,ax
}
buffer_descript[port_num-1]->end
= buffer_descript[port_num-1]->address
+ buffer_descript[port_num-1]->length-1;
reset_circ_buffer(buffer_descript[port_num-1]);
/* Initialize the Handlers */
port_address = serial_port_address[port_num-1];
reset_port(port_num);
clear_char_from_port(port_num);
int_routine_pntr = MK_FP(_CS,asynch_offset);
setvect(vector_number[port_num-1],int_routine_pntr); /* Set interrupt vector to interrupt handler */
disable(); /* Disable interrupts */
/* Enable IRQ on 8259 interupt controller */
in_byte = inportb(0x21); /* get interrupt mask register */
in_byte = in_byte & interrupt_mask[port_num-1]; /* set up RS-232 interrupts */
outportb(0x21,in_byte); /* do it! */
/* The following logic sets up the data ready interupt */
in_byte = inportb(port_address+3); /* Get LCR for port */
in_byte = in_byte & 0x7F; /* Set DLAB = 0 */
outportb(port_address+3,in_byte); /* Send back LCR */
outportb(port_address+1,0x01); /* Enable Data Ready Interrupts of IER */
outportb(port_address+4,0x08); /* Set up out2 on 8250 */
asm mov cs:word data_ad,ds
enable(); /* Enable interrupts */
if(dummy_value)
return;
/* Interrupt Handler's */
/* The following routines are the interupt handlers for port 1&2. */
/* There is one interrupt handler per port. Each gets its incomming */
/* character from the port and stuffs it into a circular buffer */
/* The routine will throw characters away once the buffer is full */
/* Other code must be quick enough to get the characters out of the */
/* buffer before it overwrites them. Also, this routine does not */
/* detect hardware errors, other logic does this (ie check_port(..)). */
/* Interrupt Handler 1 */
asm asynch_int1:
asm sti /* enable interupts */
asm push bx /* Save regs used by this routine */
asm push ax
asm push dx
asm push ds /* ds might not be this progs ds */
/* This code gets the character from the port */
asm mov ds,cs:word data_ad /* get ds that init_handl() saved */
asm mov dx,03f8h /* set up dx to point to port addrs */
asm in al,dx /* get char in al */
asm cli /* inhibit interupts */
/* This code checks for a buffer full condition,and ignores the */
/* character if so and sets the buffer overflow flag */
asm mov dx,word cb1.char_count /* first check if buffer overflow */
asm cmp dx,word cb1.length /* is number of char < buffer size? */
asm jl int1_contin /* if so, continue on processing the char */
asm mov ah,01H /* else,set up AH so we can .... */
asm mov byte cb1.overflow_flag,ah /* ...flag overflow conditon */
asm jmp exit_int1 /* exit without saveing char */
/* This code checks for a "End of Message" (EOM) character. If the */
/* incomming character is an EOM char it will set the message_in_buffer */
/* flag to signal that an EOM has arrived, and places the EOM into the */
/* buffer (ie. treats it like any other character) */
int1_contin:
#ifdef EOM_CHAR
asm cmp al,byte eom /* test for end of message */
asm jne orcra
asm mov bx,01H /* if eom set flag */
asm mov word message_in_buffer,bx
#endif
/* This code puts the character into the buffer */
/* Note: Buffer is a circular buffer and the code */
/* deals mostly with handling the "wrap around" condition. */
orcra:
asm mov bx,word cb1.head /* get next char pointer */
asm mov dx,word cb1.end /* get end of buffer address */
asm mov [bx],al /* save char in buffer */
asm inc bx /* up bx to point to next byte to put */
/*... a char into */
asm cmp bx,dx /* have we crossed over the end of the */
/*... buffer(next_char_ptr > end_buffer)? */
asm jbe int1 /* no,so use new pointer */
asm mov bx,word cb1.address /* yes,so reset bx to point to start of */
/*... buffer */
int1:
asm mov word cb1.head,bx /* save new pointer address */
asm inc word cb1.char_count /* increment character counter */
/*... ( other logic decrements it ) */
/* This logic signals end of interupt */
exit_int1:
asm mov al,20H /* set up to do a EOI */
asm out 20H,al /* do it */
asm sti /* enable interupts */
asm pop ds /* restore used registers */
asm pop dx
asm pop ax
asm pop bx
asm iret /* return from interrupt routine */
/******************************/
/* END of Interrupt handler 1 */
/******************************/
asm data_ad dw 0 /* storage in code segment for saving DS of interrupt buffers */
/* Interrupt Handler 2 */
/*************************/
asm asynch_int2:
asm sti /* enable interupts */
asm push bx
asm push ax
asm push dx
asm push ds
asm mov ds,cs:word data_ad /* get ds that init_handl() saved */
asm mov dx,02f8H /* set up dx to point to port addrs */
asm in al,dx /* get char in al */
asm cli /* inhibit interupts */
/* This code checks for a buffer full condition,and ignores the */
/* character if so and sets the buffer overflow flag */
asm mov dx,word cb2.char_count /* first check if buffer overflow */
asm cmp dx,word cb2.length /* is number of char < buffer size? */
asm jl int2_contin /* if so, continue on processing the char */
asm mov ah,01H /* set up AH so we can .... */
asm mov byte cb2.overflow_flag,ah /* ...flag overflow conditon */
asm jmp exit_int2 /* exit without saveing char */
/* This code checks for a "End of Message" (EOM) character. If the */
/* incomming character is an EOM char it will set the message_in_buffer */
/* flag to signal that an EOM has arrived, and places the EOM into the */
/* buffer (ie. treats it like any other character) */
int2_contin:
#ifdef EOM_CHAR
asm cmp al,byte eom /* test for end of message */
asm jne orcrb
asm mov bx,01H /* if eom set flag */
asm mov word message_in_buffer,bx
#endif
orcrb:
asm mov bx,word cb2.head /* get next char pointer */
asm mov dx,word cb2.end /* get end of buffer address */
asm mov [bx],al /* save char in buffer */
/*... to put a char in buffer */
asm inc bx /* up bx to point to next byte to put */
/*... a char into */
asm cmp bx,dx /* have we crossed over the end of the */
/*... buffer(next_char_ptr > end_buffer)? */
asm jbe int2 /* no,so use new pointer */
asm mov bx,word cb2.address /* yes,so reset bx to point to start of */
/*... buffer */
int2:
asm mov word cb2.head,bx /* save new pointer address */
asm inc word cb2.char_count /* increment counter to flag another */
/* char has arrived (other logic decrements */
/* it) */
exit_int2:
asm mov al,20H /* set up to do a EOI */
asm out 20H,al /* do it */
asm sti /* enable interupts */
asm pop ds /* restore used registers */
asm pop dx
asm pop ax
asm pop bx
asm iret /* return from interrupt routine */
/* END of Interrupt handler 2 */
/******************************/
}
/*****************************************
** **
** Init_port function **
** **
*****************************************/
int init_port( int port_num,int baudrate,char parity,int data_bits,int stopbit )
{
int port_address;
char msb,lsb,t;
/*
This routine intializes one of the two IBM PC/XT ports
comunications parameter (baud,parity,data bits,stop bits).
*/
if(port_num<1 || port_num>2)
return (FALSE);
t = 0;
port_address = serial_port_address[port_num-1];
switch (baudrate)
{
case 3:
case 300:
msb = 01;
lsb = 0x80;
break;
case 6:
case 600:
msb = 00;
lsb = 0xc0;
break;
case 12:
case 1200:
msb = 00;
lsb = 0x60;
break;
case 24:
case 2400:
msb = 00;
lsb = 0x30;
break;
case 48:
case 4800:
msb = 00;
lsb = 0x18;
break;
case 96:
case 9600:
msb = 00;
lsb = 0x0c;
break;
case 19200:
case 19:
msb = 00;
lsb = 0x06;
break;
default:
/* printf ("Error: illegal baudrate\n"); */
return (FALSE);
}
switch (parity)
{
case 'e':
case 'E':
t = t | 030;
break;
case 'n':
case 'N':
t = t | 000;
break;
case 'o':
case 'O':
t = t | 010;
break;
default:
/* printf ("Error: Illegal parity parameter\n"); */
return (FALSE);
}
if (stopbit == 1)
;
else
if (stopbit == 2 )
t = t|04;
else
{
/* printf ("Error: Illegal # of stop bits\n"); */
return (FALSE);
}
switch (data_bits)
{
case 5:
break;
case 6:
t = t | 01;
break;
case 7:
t = t | 02;
break;
case 8:
t = t | 03;
break;
default:
/* printf ("Error: Illegal data bit length"); */
return (FALSE);
}
/* printf ("t = %x,msb = %x,lsb = %x\n",t,msb,lsb); */
outportb(port_address+3,0x80); /* Set bit 7 of LCR for init */
outportb(port_address ,lsb); /* Do lsb of baud rate */
outportb(port_address+1,msb); /* Do msb of baud rate */
outportb(port_address+3,t ); /* Do line control word */
return (TRUE);
}
/**************************
* *
* Check the port *
* *
**************************/
int check_port_hw(int port_num)
{
/*
This routine is used to check if an error on a port has
occured. If so, it returns the negative of the line control
status register of the port. If there is no error it returns
the number of characters in the ports buffer.
*/
unsigned char in_byte;
int port_address;
if(port_num<1 || port_num>2)
return (-1);
in_byte = com_status(port_num);
if(in_byte & 0x1E) /* Test for any error status bits set */
{
clear_char_from_port(port_num); /* read any bad char in port (if any) */
return(-((int)in_byte)); /* return the negative of status to indicate port error */
}
/* No errors , so return the number of chars in buffer (for partic port) */
return(check_circ_buffer_fill(buffer_descript[port_num-1]));
}
/**************************
* *
* Check the port buffer *
* *
**************************/
int check_port_buf(int port_num)
{
/*
This routine is used to check if a buffer overflow has occured.
It returns the buffer overflow setting - 1 for overflow,0 for
no overflow. It returns -1 for an illegal port number.
*/
if(port_num<1 || port_num>2)
return (-1);
return(check_circ_buffer_over(buffer_descript[port_num-1]));
}
/**************************
* *
* Com_status *
* *
**************************/
unsigned char com_status(int port_num)
{
/*
This routine is used to get the port status. It returns the
port status or if the port number is illegal it returns zero.
*/
int port_address;
char in_byte;
if(port_num<1 || port_num>2)
return (0);
port_address = serial_port_address[port_num-1];
in_byte = inportb(port_address+5);
return(in_byte);
}
/**************************
* *
* Clear_char_from_port *
* *
**************************/
clear_char_from_port(int port_num)
{
/*
This routine reads a byte from the port without checking to see
if a character is ready to be read. It is mainly used to flush out
"known" or "don't care if there is a" bad character at the port.
It returns TRUE if the port number is legal,otherwise it returns FALSE.
*/
int port_address;
char in_byte;
if(port_num<1 || port_num>2)
return(FALSE);
port_address = serial_port_address[port_num-1];
inportb(port_address); /* read in char from port to clear it */
return(TRUE);
}
/**************************
* *
* Reset the port *
* *
**************************/
int reset_port(int port_num)
{
/*
This routine resets the port so that it will not interrupt the processor.
It should be used when the program is ready to finish, otherwise interrupts
will continue to be recieved and really screw up the processor.
*/
char in_byte;
int port_address;
if(port_num<1 || port_num>2)
return(FALSE);
port_address = serial_port_address[port_num-1];
disable(); /* disable interrupts */
/* Disable 8259 interrupts for this RS232 port's interrupts */
in_byte = inportb(0x21);
in_byte = in_byte | ~interrupt_mask[port_num-1];
outportb(0x21,in_byte);
/* Disable 8250 Data Ready interrupt */
in_byte = inportb(port_address+3); /* Get Line Control Register */
in_byte = in_byte & 0x7F; /* Reset Bit 7,but keep rest intact so that we can access the IER register */
outportb(port_address+3,in_byte); /* Do it */
outportb(port_address+1,0); /* Now we can reset IER */
outportb(port_address+4,0); /* Reset MCR */
enable(); /* enable interrupts */
/* puts("Returning from resetting the port"); */
return(TRUE);
}
/*****************************************
** **
** Putc_Output function **
** **
*****************************************/
void putc_com (int port_num,char tchar)
{
/*
This routine output a character to the indicated port.
*/
int port_address;
while (!(com_status(port_num) & 0x20)) /* wait untill trans holding register ready */
;
port_address = serial_port_address[port_num-1];
outportb(port_address,tchar); /* read in char from port to clear it */
}
/*****************************************
** **
** Puts_com function **
** **
*****************************************/
int puts_com (int port,char *string,int num_char)
{
void putc_com();
/*
This routine outputs a string to the indicated port.
It loops until all the characters are output. It does
not timeout.
*/
while(num_char--)
putc_com(port,*string++);
return(TRUE);
}
/*****************************************
** **
** Dump Buffer **
** **
*****************************************/
void dump_buf(int port_num,int num_char_to_dump)
{
/*
This routine dumps the buffer for port 1. Starting at the
begining of the buffer (not the begining of the remaning characters
in the buffer). This is used mainly to see what the buffer has in
it (for debugging).
*/
int i,j;
printf("Buffer for port %d contains....\n",port_num);
for ( i=0 ; i<200 ; i+= 40)
{
for ( j=0 ; j < 40 ; j++)
{
printf ("%c",*(buffer_descript[port_num-1]->address+j+i));
num_char_to_dump--;
if(!num_char_to_dump)
{
printf("\n");
return;
}
}
printf("\n");
}
}
/*************************************
* *
* Get a character from port's buffer *
* *
*************************************/
unsigned char getc_com(int port_num)
{
/*
This routine returns one character from the ports buffer. If the
buffer is empty it returns an octal FF. Note this routine must be defined
as short in the calling rotuine.
*/
unsigned char t1;
t1 = 255;
if(port_num<1 || port_num>2)
return(t1);
if(!buffer_descript[port_num-1]->char_count)
return(255);
t1=*buffer_descript[port_num-1]->tail;
if(++buffer_descript[port_num-1]->tail>buffer_descript[port_num-1]->end)
buffer_descript[port_num-1]->tail = buffer_descript[port_num-1]->address;
disable(); /* disable interrupts while changing something the interrupt */
/* handler could change if it occured now */
buffer_descript[port_num-1]->char_count--;
buffer_descript[port_num-1]->overflow_flag = 0; /* reset overflow condition flag */
enable(); /* ok, let any interrupts come through */
return(t1);
}
/*****************************************
** **
** Get data from the Port function **
** **
*****************************************/
int gets_com(char *buffer,int bytes_wanted,int port_num)
/*
This routine will place a given number of bytes from the communciation buffer
into a user supplied buffer. It also returns the actual number transferred.
It will return a zero if bytes_wanted is negative. The string returned
is not null terminated (as a NULL is a valid character).
*/
{
int tcount;
if(bytes_wanted <= 0 )
return (0); /* Illegal bytes_wanted arg */
if(port_num<1 || port_num>2)
return(0);
tcount = gets_circ_buffer (buffer,bytes_wanted,buffer_descript[port_num-1]);
return(tcount);
}
/*****************************************
** **
** Report serial status **
** **
*****************************************/
void report_serial_status(int error_code)
{
/*
All status bits are harware status bits.
Reference page 1-231 of IBM Technical Reference (1502237),
Personal Computer XT Hardware Reference
Library,April 1983 Edition.
Bit 7 (hi order bit) => if set Unknown Error
6 => if set Tx Shift Register Empty (TSRE)
5 => if set Transmitter Holding Register Empty (THRE)
4 => if set Break Interrupt (BI)
3 => if set Framming Error (FE)
2 => if set Parity Error (PE)
1 => if set Overrun Error (OR)
0 => if set Data Ready (DR)
*/
if (error_code & 0x80)
puts("Unknown Error (Bit 8)");
if (error_code & 0x40)
puts("Tx Shift Register Empty (TSRE)");
if (error_code & 0x20)
puts("Transmitter Holding Register Empty (THRE)");
if (error_code & 0x10)
puts ("Break Interrupt (BI)");
if (error_code & 0x08)
puts ("Framming Error (FE)");
if (error_code & 0x04)
puts("Parity Error (PE)");
if (error_code & 0x02)
puts("Overrun Error (OR)");
if (error_code & 0x01)
puts("Data Ready (DR)");
}