📄 rcomm.c
字号:
#include <stdio.h>
#include <dos.h>
#include <int.h>
#include <malloc.h>
#include <memory.h>
#define TRUE 1
#define FALSE 0
typedef unsigned char BYTE;
typedef unsigned char BOOL;
#include "rcomm.h"
#define THR 0
#define RDR 0
#define BRDL 0
#define BRDH 1
#define IER 1
#define IIR 2
#define LCR 3
#define MCR 4
#define LSR 5
#define MSR 6
void COM_ISR( int nPort );
int COM1_ISR( struct INT_DATA *pID )
{
COM_ISR(CP_COM1);
return( 1 );
}
int COM2_ISR( struct INT_DATA *pID )
{
COM_ISR(CP_COM2);
return( 1 );
}
int COM3_ISR( struct INT_DATA *pID )
{
COM_ISR(CP_COM3);
return( 1 );
}
int COM4_ISR( struct INT_DATA *pID )
{
COM_ISR(CP_COM4);
return( 1 );
}
typedef struct tagCYCLIC_BUFFER
{
BYTE *pBuffer;
int nLength;
int nCount;
BYTE *pHead, *pTail, *pLimit;
} CYCLIC_BUFFER;
typedef struct tagSERIAL_PORT
{
BOOL bEnabled;
CYCLIC_BUFFER inBuffer;
CYCLIC_BUFFER outBuffer;
} SERIAL_PORT;
static volatile SERIAL_PORT Ports[4];
static volatile unsigned int wIOPortBase[4]={ 0x03f8, 0x02f8, 0x03e8, 0x02e8 };
static volatile unsigned int wPortVector[4]={ 0x0c, 0x0b, 0x0c, 0x0b };
static volatile unsigned int wPortIRQ[4] ={ 0x04, 0x03, 0x04, 0x03 };
static BYTE cbIRQMask[4];
static int (*dwCOMISRs[4])(struct INT_DATA *pID)={ COM1_ISR,COM2_ISR,COM3_ISR,COM4_ISR };
static BOOL CycCreateBuffer( CYCLIC_BUFFER *pCyc,int nSize )
{
/* Create and initialise buffer */
if ( (pCyc->pBuffer=(BYTE *)malloc(nSize))==NULL ) return( FALSE );
pCyc->nLength = nSize;
pCyc->pLimit = pCyc->pBuffer + nSize - 1;
pCyc->pHead = pCyc->pTail = pCyc->pBuffer;
pCyc->nCount = 0;
return( TRUE );
}
static void CycDeleteBuffer( CYCLIC_BUFFER *pCyc )
{
free( pCyc->pBuffer );
}
static void CycFlushBuffer( CYCLIC_BUFFER *pCyc )
{
/* Flush contents of cyclic buffer */
pCyc->pHead = pCyc->pTail = pCyc->pBuffer;
pCyc->nCount = 0;
}
static int CycReadBuffer( CYCLIC_BUFFER *pCyc,void *pBuffer,int nCount )
{
/* Read nCount bytes from cyclic buffer */
register BYTE *pDest=(BYTE *)pBuffer;
int nRead=0;
while ( pCyc->nCount && nRead<nCount )
{
*pDest++ = *pCyc->pHead++;
pCyc->nCount--;
nRead++;
if ( pCyc->pHead>pCyc->pLimit ) pCyc->pHead=pCyc->pBuffer;
}
return( nRead );
}
static int CycWriteBuffer( CYCLIC_BUFFER *pCyc,void *pBuffer,int nCount )
{
/* Write nCount bytes to cyclic buffer */
register BYTE *pSource=(BYTE *)pBuffer;
int nWritten=0;
while ( pCyc->nCount<pCyc->nLength && nWritten<nCount )
{
*pCyc->pTail++ = *pSource++;
pCyc->nCount++;
nWritten++;
if ( pCyc->pTail>pCyc->pLimit ) pCyc->pTail=pCyc->pBuffer;
}
return( nWritten );
}
static void COM_ISR( int wPort )
{
volatile int wBase;
volatile BYTE cbChar;
volatile CYCLIC_BUFFER *pCyc;
outp( 0x20,0x20 );
if ( Ports[wPort].bEnabled )
{
wBase = wIOPortBase[wPort];
cbChar = inp(wBase+IIR)&0x06;
switch( cbChar )
{
case 0x04:
/* Character received */
pCyc = &Ports[wPort].inBuffer;
if ( pCyc->nCount<pCyc->nLength )
{
*pCyc->pTail++ = (BYTE)(unsigned int)inp(wBase+RDR);
pCyc->nCount++;
if ( pCyc->pTail>pCyc->pLimit ) pCyc->pTail=pCyc->pBuffer;
}
break;
case 0x02:
/* Transmit */
pCyc = &Ports[wPort].outBuffer;
if ( pCyc->nCount==0 )
{
/* Empty - disable THR empty interrupt */
outp( wBase+IER,0x01 );
}
else
{
outp( wBase+THR,(unsigned int)*pCyc->pHead );
pCyc->nCount--;
if ( ++pCyc->pHead>pCyc->pLimit ) pCyc->pHead=pCyc->pBuffer;
}
break;
}
/* Edge-trigger IER */
cbChar = (BYTE)inp(wBase+IER);
outp( wBase+IER,0x00 );
outp( wBase+IER,(unsigned int)cbChar );
}
}
BOOL COM_Open( COM_PORT cpPort,unsigned long nBaud,COM_DATA_BITS cdbBits,COM_STOP_BITS csbStop,COM_PARITY cbParity,int nBuffSize )
{
int wBase;
if ( cpPort<CP_COM1 || cpPort>CP_COM4 ) return( FALSE );
if ( Ports[cpPort].bEnabled ) return( FALSE );
if ( cdbBits!=CDB_8_BITS && cdbBits!=CDB_7_BITS ) return( FALSE );
if ( csbStop!=CSB_1_BIT && csbStop!=CSB_2_BIT ) return( FALSE );
if ( cbParity!=CP_NO_PARITY && cbParity!=CP_ODD_PARITY && cbParity!=CP_EVEN_PARITY ) return( FALSE );
if ( nBuffSize==0 || nBaud<300 ) return( FALSE );
if ( !CycCreateBuffer(&Ports[cpPort].inBuffer,nBuffSize) ) return( FALSE );
if ( !CycCreateBuffer(&Ports[cpPort].outBuffer,nBuffSize) )
{
CycDeleteBuffer( &Ports[cpPort].inBuffer );
return( FALSE );
}
Ports[cpPort].bEnabled = TRUE;
/* Record original interrupt enable mask */
cbIRQMask[cpPort] = inp(0x21)&(0x01<<wPortIRQ[cpPort]);
/* Intercept the vector */
int_intercept( wPortVector[cpPort],dwCOMISRs[cpPort],0 );
/* Enable interrupts in PIC */
_asm cli
if ( cbIRQMask[cpPort] )
{
outp( 0x21,inp(0x21)&((~cbIRQMask[cpPort])&0xff) );
}
/* Enable UART to interrupt on data ready */
wBase = wIOPortBase[cpPort];
outp( wBase+LCR,inp(wBase+LCR)&0x7f );
/* Test the UART */
outp( wBase+IER,0x00 );
if ( inp(wBase+IER)!=0x00 )
{
_asm sti
COM_Close( cpPort );
return( FALSE );
}
/* Clear UART status and data registers */
do
{
inp( wBase+RDR );
inp( wBase+LSR );
inp( wBase+MSR );
}
while ( !(inp(wBase+IIR)&CS_RX_READY) );
/* Enable MCR interrupts */
outp( wBase+MCR,inp(wBase+MCR)|0x08 );
/* Set baud rate */
nBaud = 0x0001C200L / nBaud;
outp( wBase+LCR,0xff );
outp( wBase+BRDL,nBaud&0xff );
outp( wBase+BRDH,(nBaud>>8)&0xff );
outp( wBase+LCR,(cbParity|cdbBits|csbStop)&0x7f );
_asm sti
/* Flush out buffers before return */
COM_Flush( cpPort,TRUE,TRUE );
return( TRUE );
}
BOOL COM_Close( COM_PORT cpPort )
{
int wBase;
if ( CP_COM1<=cpPort && cpPort<=CP_COM4 && Ports[cpPort].bEnabled )
{
BYTE cbMask=cbIRQMask[cpPort]&(0x01<<wPortIRQ[cpPort]);
/* Restore interrupt in PIC */
if ( cbMask ) outp( 0x21,inp(0x21)|cbMask );
/* Disable UART interrupts */
wBase = wIOPortBase[cpPort];
outp( wBase+LCR,inp(wBase+LCR)&0x7f );
outp( wBase+IER,0x00 );
outp( wBase+MCR,inp(wBase+MCR)&0xf7 );
/* Restore interrupt handler */
int_restore( wPortVector[cpPort] );
/* Free buffers */
CycDeleteBuffer( &Ports[cpPort].inBuffer );
CycDeleteBuffer( &Ports[cpPort].outBuffer );
Ports[cpPort].bEnabled = FALSE;
return( TRUE );
}
return( FALSE );
}
BOOL COM_Flush( COM_PORT cpPort, BOOL bFlushInput, BOOL bFlushOutput )
{
if ( CP_COM1<=cpPort && cpPort<=CP_COM4 )
{
if ( Ports[cpPort].bEnabled )
{
if ( bFlushInput ) CycFlushBuffer( &Ports[cpPort].inBuffer );
if ( bFlushOutput) CycFlushBuffer( &Ports[cpPort].outBuffer );
return( TRUE );
}
}
return( FALSE );
}
int COM_Write( COM_PORT cpPort,void *pBuffer,int nCount )
{
if ( CP_COM1<=cpPort && cpPort<=CP_COM4 )
{
if ( Ports[cpPort].bEnabled )
{
nCount = CycWriteBuffer(&Ports[cpPort].outBuffer,pBuffer,nCount);
if ( nCount )
{
/* Enable THR empty interrupt */
outp( wIOPortBase[cpPort]+IER,0x03 );
}
return( nCount );
}
}
return( 0 );
}
int COM_Read( COM_PORT cpPort,void *pBuffer,int nCount )
{
if ( CP_COM1<=cpPort && cpPort<=CP_COM4 )
{
if ( Ports[cpPort].bEnabled )
{
return( CycReadBuffer(&Ports[cpPort].inBuffer,pBuffer,nCount) );
}
}
return( 0 );
}
BOOL COM_IOCtrl( COM_PORT cpPort,BOOL bAssertRTS, BOOL bAssertDTR )
{
if ( CP_COM1<=cpPort && cpPort<=CP_COM4 && Ports[cpPort].bEnabled )
{
int nHandshake=0x08;
if ( bAssertRTS ) nHandshake|=0x02;
if ( bAssertDTR ) nHandshake|=0x01;
outp( wIOPortBase[cpPort]+MCR,nHandshake );
return( TRUE );
}
return( FALSE );
}
int COM_InQueue( COM_PORT cpPort )
{
if ( CP_COM1<=cpPort && cpPort<=CP_COM4 )
{
if ( Ports[cpPort].bEnabled ) return( Ports[cpPort].inBuffer.nCount );
}
return( 0 );
}
int COM_OutQueue( COM_PORT cpPort )
{
if ( CP_COM1<=cpPort && cpPort<=CP_COM4 )
{
if ( Ports[cpPort].bEnabled ) return( Ports[cpPort].outBuffer.nCount );
}
return( 0 );
}
COM_STATUS COM_Status( COM_PORT cpPort )
{
if ( CP_COM1<=cpPort && cpPort<=CP_COM4 && Ports[cpPort].bEnabled )
{
int wBase=wIOPortBase[cpPort];
return( (inp(wBase+MSR)<<8)|inp(wBase+LSR) );
}
return( 0 );
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -