home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Hall of Fame
/
HallofFameCDROM.cdr
/
proglc
/
serialm5.lzh
/
SERIAL.C
< prev
next >
Wrap
Text File
|
1989-03-07
|
8KB
|
334 lines
/*
S E R I A L . C
Copyright (c) 1988, 1989 by Oklahoma Software Systems
This code was written to allow a good set of interrupt driven
serial routines to be available for Microsoft C 5.x under MS/PC-DOS
3.x or higher. These routines are nothing fancy; but they will
support X and Ymodem transfer algorithms (I have them here) using
either Checksum or CRC-16 error-checking.
If you have any questions you can contact me via EchoMAIL at 147/30
where I operate as a Point-mail system.
Ron Merts
*/
#include "serial.h"
#include <dos.h>
#include <stdio.h>
#include <conio.h>
#include <bios.h>
#include <process.h>
int SError;
int portbase=0;
void (interrupt far *oldvects[3])();
char ccbuf[SBUFSIZ];
int startbuf=0;
int endbuf=0;
/* this does the hard work (handling interrupts) */
void far interrupt com_int (void)
{
_disable ();
if ((inp (portbase+IIR) & RX_MASK)==RX_ID) {
if (((endbuf+1) & 0x1fff)==startbuf)
SError=BUFOVFL;
ccbuf[endbuf++]=inp (portbase+RX);
endbuf&=0x1fff;
};
outp (ICR,EOI);
_enable ();
}
/* this routine returns the currently value in the buffer */
int getccb(void)
{
int res;
if (endbuf==startbuf) return (-1);
res=(int) ccbuf[startbuf];
startbuf=(startbuf+1) % SBUFSIZ;
return (res);
}
void setvects (void)
{
oldvects[0]= _dos_getvect(0x0b);
oldvects[1]= _dos_getvect(0x0c);
_dos_setvect(0x0b,com_int);
_dos_setvect(0x0c,com_int);
}
void resvects (void)
{
_dos_setvect(0x0b,oldvects[0]);
_dos_setvect(0x0c,oldvects[1]);
}
void i_enable (int pnum)
{
int c;
_disable();
c = inp (portbase+MCR) | MC_INT;
outp (portbase+MCR,c);
outp (portbase+IER,RX_INT);
c = inp (IMR) & (pnum==2 ? IRQ3 : IRQ4);
outp (IMR,c);
_enable();
}
void i_disable (void)
{
int c;
_disable ();
c=inp (IMR) | ~IRQ3 | ~IRQ4;
outp (IMR,c);
outp (portbase + IER,0);
c=inp (portbase+MCR) & ~MC_INT;
outp (portbase+MCR,c);
_enable ();
}
void comon (void)
{
int c,pnum;
pnum = portbase == COM1BASE ? 1 : 2;
i_enable (pnum);
c=inp (portbase + MCR) | DTR | RTS;
outp (portbase + MCR,c);
}
void initserial (void)
{
endbuf=startbuf=0;
setvects();
comon();
};
void comoff (void)
{
i_disable ();
outp (portbase+MCR,0);
}
void closeserial(void)
{
comoff();
resvects();
};
/* this outputs a serial character */
int SerialOut (char x)
{
long timeout = 0x0000ffff;
outp (portbase+MCR,OUT2|DTR|RTS);
/* wait for clear to send */
while ((inp(portbase + MSR) & CTS)==0)
if ((--timeout)==0) return (-1);
timeout=0x0000ffff;
/* wait for outport register to clear */
while ((inp(portbase+LSR) & DSR)==0)
if ((--timeout)==0) return (-1);
_disable ();
outp (portbase+TX,x);
_enable ();
return (0);
}
/* this routine sets which port we are working with */
int SetPort (int Port)
{
char far * RS232_Addr;
int Offset;
switch (Port) { /* sort out the base address */
case 1 :
Offset=0x0000;
break; /* only ports one & two allowed */
case 2 :
Offset=0x0002;
break;
default :
return (-1);
};
FP_OFF(RS232_Addr) = Offset; /* find out where the port is */
FP_SEG(RS232_Addr) = 0x0040;
if (*RS232_Addr==0)
return (-1); /* if it ain't there return (-1)*/
switch (Port) {
case 1:
portbase=0x03F8;
break;
case 2:
portbase=0x02F8;
break;
};
return (0);
}
/* this routine sets the speed; will accept funny baud rates */
int SetSpeed (int Speed)
{
char c;
int divisor;
if (Speed==0)
return (-1); /* avoid divide by zero */
else
divisor=(int)(115200L/Speed);
if (portbase==0)
return (-11);
_disable ();
c=inp (portbase+LCR);
outp (portbase+LCR,(c|0x80)); /* set DLAB */
outp (portbase+DLL,(divisor & 0x00ff)); /* set divisor */
outp (portbase+DLH,((divisor>>8)&0x00ff));
outp (portbase+LCR,c);
_enable();
return (0);
}
/* This routine set the LCR */
int SetOthers (int Parity,int Bits,int StopBit)
{
int temp;
if (portbase==0)
return (-1);
if ((Parity<NO_PAR) || (Parity>OD_PAR))
return (-1);
if ((Bits<5) || (Bits>8))
return (-1);
if ((StopBit<1) || (StopBit>2))
return (-1);
temp=Bits-5;
temp|=((StopBit==1) ? 0x00 : 0x04);
switch (Parity) {
case NO_PAR:
temp |= 0x00;
break;
case OD_PAR:
temp |= 0x08;
break;
case EV_PAR:
temp |= 0x18;
break;
}
_disable(); /* turn off interrupts */
outp (portbase+LCR,temp);
_enable(); /* turn em back on */
return (0);
}
/* This routine sets the ports */
int setserial (int Port,int Speed,int Parity,int Bits,int StopBit)
{
if (SetPort(Port)==-1)
return(-1);
if (SetSpeed(Speed)==-1)
return(-1);
if (SetOthers(Parity,Bits,StopBit)==-1)
return(-1);
return(0);
}
/* This routine check for Carrier Detect,
returns 1 if CD present or
returns 0 if CD not present
*/
int checkCD()
{
int c;
_disable(); /* disable Interrupts */
c = inp(portbase+MSR) & CD;
if (c == 128)
c = 1;
_enable(); /* Enable Interrupts again */
return(c);
}
/* short demo */
/* this opens the ports and echos to screen until */
/* Ctrl-Z received */
main (argc, argv)
int argc;
char **argv;
{
int c, c_m, bd_rate, com_port_num;
if (argc != 3) {
printf("USAGE: serial <1 | 2> <Baud-rate>\n\n\n");
printf("serial 2 2400 - Sets COM2 to 2400 Baud\n");
printf("serial 1 1200 - Sets COM1 to 1200 Baud\n");
exit(1);
}
com_port_num = atoi(argv[1]);
if (com_port_num != 1 && com_port_num != 2) {
printf("Give me a break, 1 or 2 only please!\n\n");
exit(1);
}
bd_rate = atoi(argv[2]);
switch (bd_rate) {
case 300:
case 1200:
case 2400:
case 4800:
case 9600:
break;
default:
printf("Are you trying to be difficult????\n");
printf(" Valid baud rates are 300,1200,2400,4800 and 9600\n\n");
exit(1);
}
if (setserial (com_port_num,bd_rate,NO_PAR,8,1) ==-1)
exit(1);
initserial();
printf("You're now in terminal mode. Press ESC to quit the program.\n\n");
do {
if (kbhit()) { /* Check local keyboard */
c = getch(); /* If we got something */
if (c==27)
break;
SerialOut(c); /* Send it to the COM port */
}
if ((c_m=getccb())!=-1) /* Check the COM port, -1 means nothing there */
putchar (c_m); /* If we got something, print it */
} while (c!=27);
closeserial();
}