/*->c.mnpintrf */
/*==========================================================================

                        The Microcom MNP Library
                                        (Microsoft C Version)

----------------------------------------------------------------------------

                    MNPINTRF - MNP Link Interface Routines

----------------------------------------------------------------------------

        Modification History

        3/30/87 - Compuserve V1.0

==========================================================================*/

/* Header files
*/


#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <signal.h>
#include <ctype.h>
#include <time.h>

#include "h.mnpdat"
#include "h.llvl"
#include "h.mnp"



/* Local definitions
*/
#define NOWAIT          0
#define BIT3SET(bit)            (lcb.status_3 & bit)
#define BIT1SET(bit)            (lcb.status_1 & bit)
#define SETBIT1(bit)            lcb.status_1 |= bit;
#define SETBIT3(bit)            lcb.status_3 |= bit;




/* Data declarations
*/
struct MNP_CB mnpcb;                    /* MNP control block */

USIGN_8 rbuf[RBUF_LEN];                 /* receive buffer */
USIGN_8 *rb_iptr,                               /* rcv insert ptr */
        *rb_rptr;                               /* rcv remove ptrs */
USIGN_16 rb_cnt;                                /* rcv count */

USIGN_8 sbuf[SBUF_LEN];                 /* send buffer */
USIGN_8 *sb_iptr,                               /* snd insert ptr */
        *sb_rptr;                                       /* snd remove ptr */
USIGN_16 sb_cnt;                                /* snd count */

USIGN_8 *iatbiptr;                              /* rcv temp insert ptr */
struct BLST *iatb_struct;               /* transmit buffers */

USIGN_16 baudrate;                               /* line speed */




int setpar(int byte,int parity)
{
 parity=0;
 return(byte);
}












/*GLOBAL***********************************************************************

        mnpconnect - establish an MNP link-connection

        synopsis:       retcode = mnpconnect(rate,format,port,mode);

        input:  int rate,               physical-connection speed 
                            format,     character format
                            port,               comm port
                            mode;               originator/answerer

        output: int retcode;    establishment result

**************************************************************************/


SIGN_16 mnpconnect(USIGN_16 rate,USIGN_16 format,USIGN_16 port,USIGN_16 mode)
{

/* Initialize send, receive counts and buffer pointers.
*/
rb_cnt = sb_cnt = 0;
rb_iptr = rb_rptr = rbuf;
sb_iptr = sb_rptr = sbuf;

/* Initialize physical-connection variables
*/
baudrate = rate;
mnpcb.parity = format;

/* Attempt link establishment and exit.  as_connect return code is
** returned as function value.
*/
return(as_connect(&mnpcb,mode));

}



/*GLOBAL***********************************************************************

        mnpdisconnect - terminate an MNP link-connection

        synopsis:       mnpdisconnect();

        input:  none

        output: none

****************************************************************************/


void mnpdisconnect(void)
{

/* Just call mnpllvl routine, signalling link-user initiated termination.
*/
as_disconnect(255,0);

}




/*GLOBAL***********************************************************************

        mnpreceive - receive data on an MNP link-connection

        synopsis:       retcode = mnpreceive(&buffer,buflen);

        input:  unsigned char *buffer;  pointer to user buffer
                        int buflen;                     length of user buffer

        output: int retcode;    if positive, the number of data bytes
                                                copied into the user data buffer;
                                                if negative, link error code

******************************************************************************/




SIGN_16 mnpreceive(USIGN_8 * bufptr,USIGN_16 buflen)
{

SIGN_16 retcode;
register USIGN_16 count;
register USIGN_8 c;

/* Maintain the link-connection.  On link error, return with the 
** error code as the function value.
*/
if ((retcode = as_link())!=NULL)
        return(retcode);
if ((retcode = ia_send(&mnpcb))!=NULL)
        return(retcode);

/* Initialize
*/
count = 0;

/* If there is receive data, copy as much as possible into the
** user's buffer.  Note that if a 7-bit character format has been
** selected for the link, then the high-order bit of the data octet
** is set to 0.
*/
while ((rb_cnt > 0) && (buflen > 0))
        {
     buflen--;
     count++;
     rb_cnt--;
     c = *rb_rptr++;
     if (mnpcb.parity) c &= 0x7f;
     *bufptr++ = c;
     if (rb_rptr >= (rbuf + RBUF_LEN))
                rb_rptr = rbuf;
     }

/* Maintain the link-connection.  On link error, return with error
** code as function value.
*/
if ((retcode = as_link())!=NULL)
        return(retcode);
if ((retcode = ia_send(&mnpcb))!=NULL)
        return (retcode);

/* Exit.  Function value is the number of octets moved into the user
** buffer.
*/
return(count);
}





/*GLOBAL***********************************************************************

        mnpsend - send data on an MNP link-connection

        synposis:       retcode = mnpsend(&buffer,buflen);

        input:  unsigned char *buffer;  pointer to user data buffer
                int buflen;                     length of user data buffer

        output:   int retcode - if positive, the number of data bytes
                                   copied from the user data buffer; 
                             if negative, link error code

***************************************************************************/


SIGN_16 mnpsend(USIGN_8 * bufptr,USIGN_16 buflen)
{

SIGN_16 retcode;
register USIGN_16 count;

/* Maintain the link-connection.
*/
if ((retcode = as_link())!=NULL)
        return(retcode);

/* Initialize
*/
count = 0;

/* Copy as much user data as possible into the send ring buffer.
*/
while ((sb_cnt < SBUF_LEN) && (buflen > 0))
        {
        count++;
        sb_cnt++;
        buflen--;
        *sb_iptr++ = (unsigned char) setpar(*bufptr++,mnpcb.parity);
        if (sb_iptr >= sbuf + SBUF_LEN)
                sb_iptr = sbuf;
        }

/* Try to send an LT LPDU or continue one in progress and maintain
** the link once again.
*/
if ((retcode = ia_send(&mnpcb))!=NULL)
        return(retcode);
if ((retcode = as_link())!=NULL)
        return(retcode);

/* Exit
*/
return(count);
}








/*GLOBAL***********************************************************************

        mnpstatus - get link-connection status information

        synopsis:       mnpstatus(&lstat_blk);

        input:  struct link_stat_blk *lstat_blk;        pointer to status block

        output: none

******************************************************************************/



void mnpstatus(struct link_stat_blk * lsb)
{

/* Maintain the link-connection.  Here ignore any link errors as these
** will be reflected in status values.
*/
as_link();
ia_send(&mnpcb);

/* Build link status block.
*/
if (lne_stat())
    lsb->p_status = FALSE;
else
    lsb->p_status = TRUE;

if (BIT1SET(LINK_EST))
    lsb->l_status = TRUE;
else
    lsb->l_status = FALSE;

/* Number of bytes free in send buffer. By definition this number is 
** the size of the send buffer when the link-connection is not 
** established.
*/
if (lsb->l_status == FALSE)
        sb_cnt = 0;
lsb->s_count  = SBUF_LEN - sb_cnt;

/* Amount of data in receive buffer
*/
lsb->r_count = rb_cnt;

/* Data is 'all sent' if the user send buffer is empty and all data
** messages have been acknowledged.
*/
if ((sb_cnt == 0) && (tbcnt == 0))
        lsb->all_sent = TRUE;
else
        lsb->all_sent = FALSE;

}








/*GLOBAL********************************************************************

        mnpbreak - send a break signal (using MNP attention)

        synopsis:       retcode = mnpbreak();

        input:  none

        output: int retcode;    link error code

***************************************************************************/

#ifdef NEVER

SIGN_16 mnpbreak(void)
{
SIGN_16 retcode;

/* If attention service has not been negotiated for this link-connection,
** return.  Function value = attention not supported.
*/
if (lcb.prot_level != 2)
        return(-75);

/* Maintain the link.  Return link error code if link has failed.
*/
if ((retcode = as_link())!=NULL)
        return(retcode);

/* If an attention has already been sent and not yet acknowledged, just
** return.  Funtion value = attention in progress.  
*/
if (BIT3SET(LN_SENT))
        return(-76);

/* Ok to send a destructive break using the MNP attention mechanism.
*/


/* clr_int(); */
rb_iptr = rb_rptr = rbuf;
sb_iptr = sb_rptr = sbuf;
rb_cnt = sb_cnt = NULL;

SETBIT3(LN_SENT)

link_reset();
dphase_init();

SETBIT3(LN_TIMER)
tmr.ln = lcb.lt_tmr;

++lcb.ln_ssn;
lcb.ln_stype=1;
/* set_int(); */
return(lpdu_send(LN,NOWAIT));
}


#endif




/*LOCAL------------------------------------------------------------------------

        ia_send - build an LT or add data to one in progress

-----------------------------------------------------------------------------*/

SIGN_16 ia_send(struct MNP_CB * mnpcb)
{

SIGN_16 retcode;

/* Just exit if there is nothing to send.
*/
if (sb_cnt == 0)
        return(SUCCESS);

/* Also just return if an attention is in progress.
*/
if (BIT3SET(LN_RECEIVED) || BIT3SET(LN_SENT))
        return(SUCCESS);

/* If the send framer is not busy and there is remote credit,
** start an LT LPDU.
*/
/* clr_int(); */
if (!sf_busy)
        {
        /* set_int(); */
        if (lcb.rem_credit == 0)
                return(SUCCESS);
        if (get_b(mnpcb->ftb, &iatb_struct) == FAILURE)
                return(SUCCESS);

        iatb_struct->len = 5;
        iatbiptr = iatb_struct->bptr;
        *iatbiptr++ = 4;
        *iatbiptr++ = LT;
        *iatbiptr++ = 1;
        *iatbiptr++ = 1;
        *iatbiptr++ = ++lcb.lt_ssn;

/* Copy bytes out of the send buffer as long as there are any and there
** is space in the LT LPDU (max is 64 + header of 5 = 69 for Class 3)
*/
        while ((iatb_struct->len < 69) && (sb_cnt > 0))
                {
                iatb_struct->len++;
                *iatbiptr++ = get_sbuf();
                }

/* Adjust remote credit.
*/
        /* clr_int(); */
        if (--lcb.rem_credit < 0)
                 lcb.rem_credit = 0;
        tbcnt++;
        /* set_int(); */

/* Now start sending an LT LPDU.  Initiate the LT retransmission timer
** if it is not already active.
*/
        if ((retcode = send_pdu(LT, NOWAIT, iatb_struct))!=NULL)
                return(retcode);
        sf_lt = 1;

        if (!BIT1SET(RET_TIMER))
                {
                SETBIT1(RET_TIMER)
                tmr.lt = lcb.lt_tmr;
                }

        if (ftb.used == 1)
                ftb.used_lst = iatb_struct;
        }

/* If the send framer is busy and it is busy with an LT LPDU, try to add
** as much send buffer data as possible to the current LT.
*/
else
        {
        if (sf_lt == 1)
                {
                while ((iatb_struct->len < 69) && (sb_cnt > 0))
                        {
                        iatb_struct->len++;
                        sf_len++;
                        *iatbiptr++ = get_sbuf();
                        }
                }
        }

/* Be sure that interrupts are re-enabled.
*/
/* set_int(); */

/* Exit
*/
return(SUCCESS);
}






/*LOCAL------------------------------------------------------------------------

        get_sbuf - get a data octet from the send buffer

-----------------------------------------------------------------------------*/

USIGN_8 get_sbuf(void)
{

register USIGN_8 c;

/* Remove an octet from the send buffer and return as function value.
** This routine handles the buffer count and pointer into the circular
** buffer.
*/
sb_cnt--;       
c = *sb_rptr++;
if (sb_rptr >= sbuf + SBUF_LEN)
        sb_rptr = sbuf;

/* Exit
*/
return(c);
}






