⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 async.c

📁 主要是异步通讯编程
💻 C
字号:
/* A module of ASYNCx.LIB version 1.20 */

#include <alloc.h>  /* calloc, free, and malloc */
#include <dos.h>    /* MK_FP and port I/O       */
#include "asyncdef.h"

#define peekl(a,b) (*((long far*)MK_FP((a),(b))))
#define pokel(a,b,c) (*((long far*)MK_FP((a),(b))) = (long)(c))

static word async_base[8]={0x3f8,0x2f8,0x3220,0x3228,
                           0x4220,0x4228,0x5220,0x5228};
static ASYNC *aport[8];
static long orgintb=0L, /* original contents of    */
            orgintc=0L; /* INT 0Bh and 0Ch vectors */

/* interrupt handler for COM2 through COM8 */
static void interrupt newintb(void)
{ASYNC *p;
 byte *bp;
 int i,iir;
 for(i=1;i<8;i++) /* step through COM2 through COM8 */
  {p=aport[i];
   if (p)
    {iir=inportb(p->base+IIR);
     if (iir==4)                /* data is available from the UART           */
      {bp=p->ibufhead;     /* point to the next available byte in the buffer */
       *bp=inportb(p->base+DATA); /* read the byte from the UART             */
       bp++;
       p->icount++;         /* increase the count of bytes in the buffer */
       if (bp==p->ibufend)  /* wrap if necessary                         */
         bp=p->ibuf;
       if (bp==p->ibuftail) /* handle head-tail collision                */
        {p->ibuftail++;
         p->icount--;
         if (p->ibuftail==p->ibufend)
           p->ibuftail=p->ibuf;
        }
       p->ibufhead=bp;      /* update bufhead                            */
      }
     /*********************************************/
     /** Send a character from the output buffer **/
     /*********************************************/
     if (iir==2 && p->ocount)
      {bp=p->obuftail;
       outportb(p->base+DATA,*bp++);
       p->ocount--;
       if (bp==p->obufend)
         bp=p->obuf;
       p->obuftail=bp;
      }
    }
  }
 outportb(0x20,0x20);             /* reset the 8259 interrupt controller     */
} /* end of newintb() */

/* interrupt handler for COM1 */
static void interrupt newintc(void)
{ASYNC *p;
 byte *bp;
 int iir;
 p=aport[0];
 if (p)
  {iir=inportb(p->base+IIR);
   if (iir==4)                    /* data is available from the UART         */
    {bp=p->ibufhead;           /* point to next available byte in the buffer */
     *bp=inportb(p->base+DATA);   /* read the byte from the UART             */
     if (p->lookx && ((*bp) & 0xfd)==0x17)
       if (*bp==XON) /* an XON character was received */
        {p->recvxoff=0;
         if (p->ocount)
          {bp=p->obuftail;
           outportb(p->base+DATA,*bp++);
           if (bp==p->obufend)
             bp=p->obuf;
           p->obuftail=bp;
           p->ocount--;
          }
        }
       else /* an XOFF character was received */
         p->recvxoff=1;
     else /* Processing of received XON/XOFF characters is not required.     */
      {bp++;                      /* advance the input buffer pointer        */
       p->icount++;               /* add to the count of bytes in the buffer */
       if (bp==p->ibufend)        /* wrap if necessary                       */
         bp=p->ibuf;
       if (bp==p->ibuftail)       /* Handle head-tail collision              */
        {p->ibuftail++;           /* by overwriting the oldest data          */
         p->icount--;             /* in the input buffer.                    */
         if (p->ibuftail==p->ibufend)
           p->ibuftail=p->ibuf;
        }
       p->ibufhead=bp;            /* update bufhead                          */
       if (p->sentxoff && p->icount<p->xon) /* send an XON character */
        {bp=p->obufhead;
         *bp++=XON;
         if (bp==p->obufend)
           bp=p->obuf;
         if (bp!=p->obuftail) /* no output buffer overflow has occured */
          {p->obufhead=bp;
           p->ocount++;
           p->sentxoff=0;
          }
        }
       else
         if (!p->sentxoff && p->icount>p->xoff) /* send an XOFF character */
          {bp=p->obufhead;
           *bp++=XOFF;
           if (bp==p->obufend)
             bp=p->obuf;
           if (bp!=p->obuftail) /* no output buffer overflow has occured */
            {p->obufhead=bp;
             p->ocount++;
             p->sentxoff=1;
            }
          }
      }
    }
   else
     if (iir==2 && p->ocount && !p->recvxoff) /* we should send more data */
      {bp=p->obuftail;
       outportb(p->base+DATA,*bp++);
       if (bp==p->obufend)
         bp=p->obuf;
       p->obuftail=bp;
       p->ocount--;
      }
  }
 outportb(0x20,0x20);             /* reset the 8259 interrupt controller     */
} /* end of newintc() */

/********************************************************************
 Close the async port with which p is associated. This
 involves deallocating the memory occupied by its input
 buffer, output buffer (if one was declared for it), and by
 the control structure itself. Also, the interrupts that were
 enabled when the port was opened are disabled. A value of NULL
 is returned from this founction to facilitate setting the
 variable you pass as p to NULL. For example, you might say:

    ASYNC *port;
    .
    .
    .
    port=a_open(2,2400,PAR_NONE,8,1,4096,1024);
    .
    .
    .
    port=a_close(port);

********************************************************************/
ASYNC *a_close(ASYNC *p,int fc)
{int i;
 if (p)
  {for(i=0;i<8 && aport[i]!=p;i++); /* find this port in the array           */
   if (i>7)                 /* failed to close this port                     */
     return NULL;
   /************************************/
   /** shut down this particular port **/
   /************************************/
   outportb(p->base+MCR,fc & 3); /* disable interrupts for this port         */
   outportb(p->base+IER,0);      /* disable interrupts for this port         */
   /*******************************************************/
   /** unhook from the interrupt vector table if this is **/
   /** is the last port open that uses this vector.      **/
   /*******************************************************/
   aport[i]=NULL;           /* remove this port from active duty             */
   if (i==0)
    {i=inportb(0x21);       /* get the current IRQ mask                      */
     i|=0x10;               /* disable IRQ 4                                 */
     outportb(0x21,i);      /* set the new IRQ mask                          */
     pokel(0,0x30,orgintc);
     orgintc=0L;
    }
   else
    {for(i=1;i<8 && aport[i]==NULL;i++);
     if (i==8)                     /* no more ports are using this interrupt */
      {i=inport(0x21);      /* get the current IRQ mask                      */
       i|=0x08;             /* disable IRQ 3                                 */
       outportb(0x21,i);    /* set the new IRQ mask                          */
       pokel(0,0x2c,orgintb);
       orgintb=0L;
      }
    }
   /*********************************************/
   /** deallocate the memory used by this port **/
   /*********************************************/
   free(p->ibuf);           /* free the memory used by its input buffer      */
   free(p->obuf);           /* free the memory used by its output buffer     */
   free(p);                 /* free the memory used by its control structure */
  }
 return NULL;               /* failed to close this port                     */
} /* end of a_close(p) */

/**************************************************************
 Open an async port with the given characteristics. This
 involves allocating space in memory for its control
 structure, input buffer, and output buffer (if one is
 specified). The port parameter may be any integer in the
 range from 1 to 8 corresponding to the COMn specification
 that DOS uses to refer to the async ports. baud may be any
 2-byte unsigned integer and specifies the baud rate at which
 communications is to be carried out on this particular async
 port. par is the parity and may be one of PAR_NONE, PAR_ODD,
 PAR_EVEN, PAR_MARK, or PAR_SPACE. dbits is the number of data
 bits to be used with this port and may be anywhere from 5 to
 8. sbits is the nubmer of stop bits to be used with this port
 and may be either 1 or 2. None of the parameters listed above
 is validated, so it is up to the calling routine to get its
 own act together with respect to making sure that the
 parameters passed to this function make sense. The ibufsize
 and obufsize parameters specify the sizes of the input buffer
 and the output buffer in bytes, respectively. If you know
 what's good for you, you'll specify a healthy input buffer.
 The output buffer, however, is optional (provided that you
 don't want to take advantage of automatic XON/XOFF) and may
 be turned off by specifying an output buffer size of 0. This
 function returns a pointer to the control structure for the
 port being opened. If the port cannot be opened (because of
 insufficient memory to allocate for the buffers and control
 structure), a value of NULL is returned.
**************************************************************/
ASYNC *a_open(word port,word baud,word par,word dbits,
              word sbits,word ibufsize,word obufsize)
{int lcr;                  /* will hold the Line Control Register contents */
 int i;
 /***************************************/
 /** validate port and allocate memory **/
 /***************************************/
 port--;
 if (port>7)
   return NULL;
 if (aport[port])                       /* if this port is already in use, */
  {free(aport[port]->ibuf);             /* close it.                       */
   if (aport[port]->obuf)
     free(aport[port]->obuf);
   free(aport[port]);
   aport[port]=NULL;
  }
 aport[port]=calloc(1,sizeof(ASYNC));
 if (aport[port]==NULL)
   return NULL;
 aport[port]->base=async_base[port];
 aport[port]->ibuf=malloc(ibufsize); /* allocate space for the input buffer  */
 if (aport[port]->ibuf==NULL)
  {free(aport[port]);
   return NULL;
  }
 if (obufsize)
  {aport[port]->obuf=malloc(obufsize); /* make space for the output buffer */
   if (aport[port]->obuf==NULL)
    {free(aport[port]->obuf);
     free(aport[port]);
     return NULL;
    }
  }
 aport[port]->ibufend=aport[port]->ibuf+ibufsize;
 aport[port]->ibufhead=aport[port]->ibuftail=aport[port]->ibuf;
 aport[port]->obufend=aport[port]->obuf+obufsize;
 aport[port]->obufhead=aport[port]->obuftail=aport[port]->obuf;
 /*************************************/
 /** Turn off XON/XOFF flow control. **/
 /*************************************/
 aport[port]->xon=0;
 aport[port]->xoff=0xffff;
 /*****************************************/
 /** Initialize the communications port. **/
 /*****************************************/
 outportb(aport[port]->base+IER,0); /* turn off all UART's interrupts    */
 inportb(aport[port]->base+IIR);    /* reset all UART's interrupt flags  */
 outportb(aport[port]->base+MCR,7); /* reset modem & disable interrupts  */
 inportb(aport[port]->base+DATA);   /* empty the UART's input buffer     */
 /************************************/
 /** hook the appropriate interrupt **/
 /************************************/
 if (port)                              /* make sure that int 0Bh is hooked  */
  {if (orgintb==0L)
    {disable();
     orgintb=peekl(0,0x2c);             /* store the original contents       */
     pokel(0,0x2c,newintb);             /* install the new interrupt handler */
     enable();
    }
  }
 else                                   /* make sure that int 0Ch is hooked  */
   if (orgintc==0L)
    {disable();
     orgintc=peekl(0,0x30);             /* store the original contents       */
     pokel(0,0x30,newintc);             /* install the new interrupt handler */
     enable();
    }
 /****************************/
 /** set up the port itself **/
 /****************************/
 outportb(aport[port]->base+LCR,0x80);          /* set up to set buad rate   */
 baud=(int)(115200L/(long)baud);                /* compute baud rate divisor */
 outportb(aport[port]->base+BAUDL,baud & 0xff); /* set MSB of buad rate      */
 outportb(aport[port]->base+BAUDH,baud >> 8);   /* set LSB of baud rate      */
 lcr=(dbits-5) | (((sbits-1) & 1)<<2) | ((par & 7)<<3);
 outportb(aport[port]->base+LCR,lcr & 0x3f);  /* set data, parity, stop bits */
 /*************************/
 /** adjust the IRQ mask **/
 /*************************/
 i=inportb(0x21);                               /* get the current IRQ mask  */
 if (port)
   i&=0xf7;                                     /* enable IRQ 3              */
 else
   i&=0xef;                                     /* enable IRQ 4              */
 outportb(0x21,i);                              /* set the new IRQ mask      */
 /***************************************/
 /** Reset the UART's status registers **/
 /***************************************/
 inportb(aport[port]->base+LSR);    /* reset all line status bits        */
 inportb(aport[port]->base+MSR);    /* reset all modem status bits       */
 /***************************************************/
 /** tell the UART that it's OK to send interrupts **/
 /***************************************************/
 if (obufsize)
   outportb(aport[port]->base+IER,3);   /* enable DATA_READY and XMIT_BUF_MT */
 else
   outportb(aport[port]->base+IER,1);   /* enable DATA_READY only            */
 outportb(aport[port]->base+MCR,0x0b);  /* enable interrupts, DTR, and RTS   */
 return aport[port];
} /* end of a_open(port,baud,par,dbits,sbits) */

/**************************************************************
 Change the communications parameters associated with a port
 that has already been opened. The function parameter p is the
 port variable. The other function parameters are the same as
 the corresponding parameters of the a_open function.
***************************************************************/
int a_params(ASYNC *p,word baud,word par,word dbits,word sbits)
{int lcr;          /* will hold the Line Control Register contents */
 if (!p)
   return -1;
 outportb(p->base+LCR,0x80);          /* set up to set buad rate   */
 baud=(int)(115200L/(long)baud);      /* compute baud rate divisor */
 outportb(p->base+BAUDL,baud & 0xff); /* set MSB of buad rate      */
 outportb(p->base+BAUDH,baud >> 8);   /* set LSB of baud rate      */
 lcr=(dbits-5) | (((sbits-1) & 1)<<2) | ((par & 7)<<3);
 outportb(p->base+LCR,lcr & 0x3f); /* set data, parity, and stop bits */
 return 0;
} /* end of a_open(port,baud,par,dbits,sbits) */

/************************************************************************
 Return the number of the COM port with which p is associated. If is not
 associated with any port, return 0. Otherwise return an integer in the
 range from 1 to 8.
************************************************************************/
int a_portno(register ASYNC *p)
{int i;
 if (p)
  {for(i=0;i<8 && aport[i]!=p;i++);
   if (i<8)
     return(i+1);
  }
 return 0;
} /* end of a_portno(p) */

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -