1
0
mirror of https://github.com/stargieg/bacnet-stack synced 2025-10-26 23:35:52 +08:00
bacnet-stack/ports/dos/serial.c
2013-03-21 22:53:31 +01:00

383 lines
9.5 KiB
C

/*
+----------------------------------------------------+
| Thunderbird Software |
+----------------------------------------------------+
| Filespec : Serial.c |
| Date : October 24, 1991 |
| Time : 15:03 |
| Revision : 1.1 |
| Update: August 29, 1994 |
+----------------------------------------------------+
| Programmer: Scott Andrews |
| Address : 5358 Summit RD SW |
| City/State: Pataskala, Ohio |
| Zip : 43062 |
+----------------------------------------------------+
| Released to the Public Domain |
+----------------------------------------------------+
*/
/*
+----------------------------------------------------------+
| Call open_serial to install the interrupt handler |
| You must call close_serial before exiting your program |
| or a machine crash will occur! |
+----------------------------------------------------------+
*/
#include <stdlib.h>
#include <dos.h>
#include <string.h>
#include "serial.h"
#include "queue.h"
QUEUE *Serial_In_Queue;
QUEUE *Serial_Out_Queue;
OLD_COMM_PARAMS old_comm_params;
COMM_STATUS comm_status;
void (
INTERRUPT FAR * oldvector_serial) (
);
/* save addr for intr handler */
int ComBase; /* Comm port address */
int IrqNum; /* Comm interrupt request */
void CloseComPort(
void)
{
int status;
/* restore UART to previous state */
outp(ComBase + INT_EN, (unsigned char) 0);
outp(ComBase + MODEM_CNTRL, (unsigned char) old_comm_params.modem);
status = inp(ComBase + LINE_CNTRL);
outp(ComBase + LINE_CNTRL, (unsigned char) status | 0x80);
outp(ComBase + BAUD_LSB, (unsigned char) old_comm_params.baud_lsb);
outp(ComBase + BAUD_MSB, (unsigned char) old_comm_params.baud_msb);
outp(ComBase + LINE_CNTRL, (unsigned char) old_comm_params.line);
outp(0x21, (unsigned char) old_comm_params.int_cntrl);
/* restore old interrupt handler */
setvect(IrqNum + 8, oldvector_serial);
/* free input and output queues */
free(Serial_In_Queue);
free(Serial_Out_Queue);
return;
}
int OpenComPort(
char Port)
{ /* install int. handler */
unsigned status;
int retval = -1;
/* allocate input and output queues */
Serial_In_Queue = alloc_queue(SerInBufSize);
if ((QUEUE *) 0 == Serial_In_Queue)
return retval;
Serial_Out_Queue = alloc_queue(SerOutBufSize);
if ((QUEUE *) 0 == Serial_Out_Queue) {
free(Serial_In_Queue);
return retval;
}
retval = 0;
/* Setup Comm base port address and IRQ number */
switch (Port) {
case '1':
ComBase = 0x3F8;
IrqNum = 4;
break;
case '2':
ComBase = 0x2F8;
IrqNum = 3;
break;
case '3':
ComBase = 0x3E8;
IrqNum = 4;
break;
case '4':
ComBase = 0x2E8;
IrqNum = 3;
break;
default:
ComBase = 0x3F8;
IrqNum = 4;
break;
}
old_comm_params.int_enable = inp(ComBase + INT_EN);
outp(ComBase + INT_EN, 0); /* turn off comm interrupts */
/* save old comm parameters */
old_comm_params.line = inp(ComBase + LINE_CNTRL);
old_comm_params.modem = inp(ComBase + MODEM_CNTRL);
status = inp(ComBase + LINE_CNTRL);
outp(ComBase + LINE_CNTRL, (unsigned char) status | 0x80);
old_comm_params.baud_lsb = inp(ComBase + BAUD_LSB);
old_comm_params.baud_msb = inp(ComBase + BAUD_MSB);
status = inp(ComBase + LINE_CNTRL);
outp(ComBase + LINE_CNTRL, (unsigned char) status | 0x7F);
status = OUT2 | DTR; /* DTR/OUT2 must be set! */
outp(ComBase + MODEM_CNTRL, (unsigned char) status);
/* get serial port address/vector */
oldvector_serial = (void (INTERRUPT FAR *) (void)) getvect(IrqNum + 8);
/* set our interrupt handler */
setvect(IrqNum + 8, serial);
/* save the PIC */
old_comm_params.int_cntrl = inp(0x21);
status = (1 << IrqNum); /* calculate int enable bit */
status = ~status;
/* ok enable comm ints */
outp(0x21,
(unsigned char) old_comm_params.int_cntrl & (unsigned char) status);
atexit(CloseComPort);
return retval;
}
void InitComPort(
char Baud[],
char Databits,
char Parity,
char Stopbits)
{
int status;
unsigned divisor;
long baudrate;
/* set baud rate */
status = inp(ComBase + LINE_CNTRL);
outp(ComBase + LINE_CNTRL, (unsigned char) status | 0x80);
baudrate = atol(Baud);
if (baudrate == 0)
baudrate = 2400L;
divisor = (unsigned) (115200L / baudrate);
outp(ComBase + BAUD_LSB, (unsigned char) (divisor & 0x00FF));
outp(ComBase + BAUD_MSB, (unsigned char) ((divisor >> 8) & 0x00FF));
status = 0x00;
/* set parity */
switch (Parity) { /* set parity value */
case 'O': /* odd parity */
case 'o':
status = 0x08;
break;
case 'E': /* even parity */
case 'e':
status = 0x18;
break;
case 'S': /* stick parity */
case 's':
status = 0x28;
break;
case 'N': /* no parity */
case 'n':
default:
status = 0x00;
}
/* set number data bits */
switch (Databits) {
case '5':
break;
case '6':
status = status | 0x01;
break;
case '7':
status = status | 0x02;
break;
case '8':
default:
status = status | 0x03;
}
/* set number stop bits */
switch (Stopbits) {
case '2':
status = status | 0x04;
break;
case '1':
default:
;
}
outp(ComBase + LINE_CNTRL, (unsigned char) status);
status = OUT2 | DTR; /* DTR/OUT2 must be set! */
outp(ComBase + MODEM_CNTRL, (unsigned char) status);
/* enable serial interrupts */
outp(ComBase + INT_EN, RX_INT | ERR_INT | RS_INT);
return;
}
void DropDtr(
void)
{
int status;
status = inp(ComBase + MODEM_CNTRL);
status &= 0xFE; /* turn off DTR bit */
outp(ComBase + MODEM_CNTRL, (unsigned char) status);
return;
}
void RaiseDtr(
void)
{
int status;
status = inp(ComBase + MODEM_CNTRL);
status |= 0x01; /* turn on DTR bit */
outp(ComBase + MODEM_CNTRL, (unsigned char) status);
return;
}
int ComRecChar(
void)
{
return de_queue(Serial_In_Queue);
}
int ComSendString(
char *string)
{
int retval;
char *pointer;
pointer = string;
while (*pointer) {
retval = en_queue(Serial_Out_Queue, *pointer);
pointer++;
}
if (0x0 == (comm_status.modem & 0x40))
RaiseDtr();
outp(ComBase + INT_EN, RX_INT | TBE_INT | ERR_INT | RS_INT);
return retval;
}
int ComSendData(
char *buffer,
unsigned buffer_length)
{
int retval;
char *pointer;
pointer = buffer;
unsigned i;
for (i = 0; i < buffer_length; i++) {
retval = en_queue(Serial_Out_Queue, *pointer);
pointer++;
}
if (0x0 == (comm_status.modem & 0x40))
RaiseDtr();
outp(ComBase + INT_EN, RX_INT | TBE_INT | ERR_INT | RS_INT);
return retval;
}
int ComSendChar(
char character)
{
int retval;
/* interrupt driven send */
if (0x0 == (comm_status.modem & 0x40))
RaiseDtr();
retval = en_queue(Serial_Out_Queue, character);
if (-1 != retval)
outp(ComBase + INT_EN, RX_INT | TBE_INT | ERR_INT | RS_INT);
return retval;
}
int ComStatus(
void)
{
unsigned status;
unsigned retval;
retval = inp(ComBase + LINE_STATUS);
retval = retval << 8;
status = inp(ComBase + MODEM_STATUS);
retval = retval | status;
if (queue_empty(Serial_In_Queue))
retval &= 0xFEFF;
else
retval |= 0x0100;
return (int) retval;
}
void INTERRUPT FAR serial(
void)
{ /* interrupt handler */
int temp;
disable();
while (1) {
comm_status.intrupt = inp(ComBase + INT_ID);
comm_status.intrupt &= 0x0f;
switch (comm_status.intrupt) {
case 0x00: /* modem interrupt */
comm_status.modem = inp(ComBase + MODEM_STATUS);
break;
case 0x02: /* xmit interrupt */
if (queue_empty(Serial_Out_Queue))
outp(ComBase + INT_EN, RX_INT | ERR_INT | RS_INT);
else {
temp = de_queue(Serial_Out_Queue);
if (-1 != temp)
outp(ComBase + XMIT, temp);
}
break;
case 0x04: /* receive interrupt */
en_queue(Serial_In_Queue, (char) inp(ComBase + REC));
break;
case 0x06: /* line interrupt */
comm_status.line = inp(ComBase + LINE_STATUS);
(void) inp(ComBase + REC);
en_queue(Serial_In_Queue, '!');
break;
default: /* No Mo` Left */
comm_status.modem = inp(ComBase + MODEM_STATUS);
outp(0x20, 0x20);
enable();
return;
} /* switch */
} /* while */
}
/* End of Serial.C */