『第
2 楼』:
class serial{
int flag;
int SetSerial();
int SetOthers(int Parity, int Bits, int StopBit);
int SetSpeed(int Speed);
int SetPort(int Port);
void init_serial(void);
void comm_on(void);
void comm_off(void);
public:
serial(int Port, int Speed, int Parity, int Bits, int StopBit);
serial &operator<<( char ch );
serial &operator<<( char *str );
serial &operator>>( char &ch );
~serial();
};
#define VERSION 0x0101
#define FALSE 0
#define TRUE 1
#define NO_ERROR 0 /* No error */
#define BUF_OVFL 1 /* Buffer overflowed */
#define IBUF_LEN 2048 // Incoming buffer
#define OBUF_LEN 1024 // Outgoing buffer
extern int SError = NO_ERROR;
extern int portbase = 0;
extern void interrupt(*oldvects[2])(...);
// char ccbuf[SBUFSIZ];
unsigned int startbuf = 0;
unsigned int endbuf = 0;
unsigned int inhead = 0;
unsigned int intail = 0;
unsigned int outhead = 0;
unsigned int outtail = 0;
char inbuf[IBUF_LEN]; // in buffer
char outbuf[OBUF_LEN]; // out buffer
void interrupt(*oldvects[2])(...);
/* get status of the port */
int read_status_com(int portn)
{
return(inp(portn+5));
}
/* send one valid char from the port */
void send_char_com(int portn,int cc)
{
while ((read_status_com(portn) & 0x40) == 0);
outportb(portn,cc);
}
/* send one string from the port */
void send_string_com(int portn,int strlen,unsigned char *buf)
{
int k; k=0;
do {
send_char_com(portn,*(buf + k)); k++;
} while ((k < strlen));
}
void interrupt com_int(...)
{
int temp;
disable();
temp = (inportb(portbase+IIR)) & IIR_MASK; // why interrupt was called
switch(temp)
{
case 0x00: // modem status changed
inportb(portbase+MSR); // read in useless char
break;
case 0x02: // Request To Send char
if (outhead != outtail) // there's a char to send
{
outportb(portbase+TXR,outbuf[outhead++]); // send the character
if (outhead == OBUF_LEN)
outhead=0; // if at end of buffer, reset pointer
}
break;
case 0x04: // character ready to be read in
inbuf[inhead++] = inportb(portbase+RXR);// read character into inbuffer
if (inhead == IBUF_LEN) // if at end of buffer
inhead=0; // reset pointer
break;
case 0x06: // line status has changed
inportb(portbase+LSR); // read in useless char
break;
default:
break;
}
outportb(PIC8259_ICR, PIC8259_EOI); // Signal end of hardware interrupt
enable(); // reenable interrupts at the end of the handler
}
// Inserts the character to be outputted into the output buffer, checking
// for an open slot in the output buffer array. If there is, insert
// the character, or if there isn't, wait until a slot opens up.
serial& serial::operator<<(char ch )
{
if (ch) // If this is a valid char
{
enable(); // turn on irqs to ensure data output
//outportb(portbase + MCR, MCR_INT | MCR_DTR | MCR_RTS);//modem control,
outportb(portbase + IER, IER_RX_INT);
// check buffer, and if full, wait for an available opening
// fprintf(stdout,"\n %c is pressed!\n",ch); //You can use this to verify which key is hit during your test
while((outhead-1==outtail) ||(outtail==OBUF_LEN-1 && outhead==0));
disable(); // make sure nothing happens while changing buffer
outbuf[outtail++] = ch; // insert character into buffer;
if (outtail == OBUF_LEN) // if at end of out buffer
outtail = 0; // reset pointer
if((inportb(portbase+IER)&IER_TX_INT) == 0)
outportb(portbase+IER,IER_TX_INT | IER_RX_INT);
enable(); // re-enable interrupts
}
return(*this);
}
serial &serial::operator<<(char *str)
// Outputs a string to the serial port
{
while (*str)
{
(*this) << (*str);
str++;
}
return(*this);
}
serial &serial::operator>>( char &ch )
// Returns either the character to be received from modem if there is one
// waiting in the buffer, or returns a 0 if there is no character waiting.
{
if (inhead != intail) // there is a character
{
disable(); // disable irqs while getting char
ch = inbuf[intail++]; // get character from buffer
if (intail == IBUF_LEN) // if at end of in buffer
intail=0; // reset pointer
enable(); // re-enable interrupt
return(*this); // return the char
}
ch = -1;
return(*this); // return nothing
}
/* Install our functions to handle communications */
void setvects(void)
{
oldvects[0] = getvect(0x0B);
oldvects[1] = getvect(0x0C);
setvect(0x0B, com_int);
setvect(0x0C, com_int);
}
/* Uninstall our vectors before exiting the program */
void resvects(void)
{
setvect(0x0B, oldvects[0]);
setvect(0x0C, oldvects[1]);
}
/* Tell modem that we're ready to go */
void serial::comm_on(void)
{
int temp, pnum;
disable();
temp = inportb(portbase + MCR) | 0x0f;//MCR_INT;
outportb(portbase + MCR, temp);
temp = (inportb(portbase + IER)) | IER_RX_INT;//|IER_TX_INT;
outportb(portbase + IER, temp);
pnum = (portbase == COM1BASE ? COM1 : COM2);
temp = inportb(PIC8259_IMR) & (pnum == COM1 ? IRQ4 : IRQ3);
outportb(PIC8259_IMR, temp);
// temp = inportb(portbase + MCR) | MCR_DTR | MCR_RTS;
// outportb(portbase + MCR, temp);
enable();
}
/* Go off-line */
void serial::comm_off(void)
{
int temp;
disable();
temp = inportb(PIC8259_IMR) | ~IRQ3 | ~IRQ4;
outportb(PIC8259_IMR, temp);
outportb(portbase + IER, 0);
outportb(portbase + MCR, 0);
enable();
}
void serial::init_serial(void)
{
endbuf = startbuf = 0;
setvects();
comm_on();
}
serial::~serial()
{
comm_off();
resvects();
}
/* Set the port number to use */
int serial::SetPort(int Port)
{
int Offset, far *RS232_Addr;
switch (Port)
{ /* Sort out the base address */
case COM1 :
Offset = 0x0000;
break;
case COM2 :
Offset = 0x0002;
break;
default :
printf("\ncannot find the serial port.\n");
return (-1);
}
RS232_Addr = (int far *)MK_FP(0x0040, Offset); /* Find out where the port is. */
if (*RS232_Addr == NULL)
{
printf("\ncannot find the serial port.\n");
return (-1); /* If NULL then port not used. */
}
portbase = *RS232_Addr; /* Otherwise set portbase */
return (0);
}
/* This routine sets the speed; will accept funny baud rates. */
/* Setting the speed requires that the DLAB be set on. */
int serial::SetSpeed(int Speed)
{
char c;
int divisor;
if (Speed == 0) /* Avoid divide by zero */
return (-1);
else
divisor = (int) (115200L/Speed);
if (portbase == 0)
return (-1);
disable();
c = inportb(portbase + LCR);
outportb(portbase + LCR, (c | 0x80)); /* Set DLAB */
outportb(portbase + DLL, (divisor & 0x00FF));
outportb(portbase + DLH, ((divisor >> 8) & 0x00FF));
outportb(portbase + LCR, c); /* Reset DLAB */
enable();
return (0);
}
/* Set other communications parameters */
int serial::SetOthers(int Parity, int Bits, int StopBit)
{
int setting;
if (portbase == 0)
return (-1);
if (Bits < 5 || Bits > 8)
return (-1);
if (StopBit != 1 && StopBit != 2)
return (-1);
if (Parity != LCR_NO_PARITY && Parity != LCR_ODD_PARITY && Parity != LCR_EVEN_PARITY)
return (-1);
setting = Bits-5;
setting |= ((StopBit == 1) ? 0x00 : 0x04);
setting |= Parity;
disable();
outportb(portbase + LCR, setting);
enable();
return (0);
}
/* Set up the port */
serial::serial(int Port, int Speed, int Parity, int Bits, int StopBit)
{
flag = 0;
if (SetPort(Port))
flag = -1;
if (SetSpeed(Speed))
flag = -1;
if (SetOthers(Parity, Bits, StopBit))
flag = -1;
if (!flag)
init_serial();
}
/* Control-Break interrupt handler */
int c_break(void)
{
int temp;
disable();
temp = inportb(PIC8259_IMR) | ~IRQ3 | ~IRQ4;
outportb(PIC8259_IMR, temp);
outportb(portbase + IER, 0);
outportb(portbase + MCR, 0);
enable();
fprintf(stderr, "\nStill online.\n");
return(0);
}
|