#include <common.h>
#include <slip.h>
#include <ip.h>
#include <icmp.h>

unsigned char rxstate=RXIDLE;
unsigned int received=0;

BYTE rxbuff[RXMAXLEN];
/* #pragma locate rxbuffer 0x300;  Locates the array in 3rd RAM page */
BYTE txbuffer[TXMAXLEN];
/* #pragma locate txbuffer 0x400; */

extern WORD rxpos;
extern WORD txpos;

ipstats ipstat;

/******************************************************************************
 * Sends a packet of length "len", starting at location "p"
 * assumes the entire packet is stored in data memory
 * This function is an addaptation of the send_packet() function given
 * as an example in the SLIP RFC - 1055
 *****************************************************************************/
void slip_send(char *p, WORD len)
{
	/* toggle activity LED */
	LEDPORT^=(1<<LEDBIT);
	/* increment transmit stats counter */
	ipstat.txpackets++;
	
	/* add END (0300) to transmit buffer
	 * to clear possible noise between packets */
	AddTx(END);
        
	/* send each byte in turn, escaping where necessary */
	while (len--)
	{
		switch (*p)
		{
			/* swap END for ESC followed by ESC_END */
			case END:
				AddTx(ESC); AddTx(ESC_END);
				break;
			/* swap ESC for ESC followed by ESC_ESC */
			case ESC:
				AddTx(ESC); AddTx(ESC_ESC);
				break;
			/* just send out any other character */
			default:
				AddTx(*p);
				break;
		}
		p++;
	}
	/* send END to indicate end of packet */
	AddTx(END);
	
}

/*********************************************************************************
 * Reads a byte from the USART buffer, demultiplexing it according
 * to the SLIP RFC. This function will not return until the USART buffer
 * is empty.
 *******************************************************************************/
void slip_recv()
{
	BYTE c;
	/* toggle activity LED */
	LEDPORT^=(1<<LEDBIT);

	/* line is idle, this is the first byte
	 * if it's not an END, then it must be noise */
	if (rxstate == RXIDLE)
	{
		/* read the first byte */
		c = WaitRx();
		/* noise - ignore */
		if (c != END) return;
		/* set state flag to indicate 
		 * reception is in the middle of a packet */
		rxstate = RXACTIVE;
	}
	
	while (1)
	{
		/* zero bytes in buffer, don't really want to 'Wait' for a byte to
		 * appear if we could be doing something else instead */
		if (!GetRxSize()) return;
		/* get next byte from RX buffer */
		c = WaitRx();
	
		switch(c)
		{
			case END:
				/* got an END byte while in the middle of a packet - must 
				 * be the end */
				if (received) {
					rxstate = RXDONE;
					received=0;
					return;
				} else {
					break;
				}
			case ESC:
				/* need to know the next byte to decide what
				 * the original byte was */
				c = WaitRx();
				
				switch(c) {
					case ESC_END:
						c = END;
						break;
					case ESC_ESC:
						c = ESC;
						break;
				}
			default:
				/* the packet is too long */
				if (received == RXMAXLEN) {
					/* wait for END byte
					 * don't do anything with the data we receive now */
					while (WaitRx() != END) { }
					/* line goes idle again - ready for next packet */
					received = 0;
					rxstate = RXDONE;
					return;
				} else {
					/* place received byte in memory buffer */
					rxbuff[received++] = c;
				}
				break;
		}
	}
}

/************************************************************************
 * void copy_rx_byte(BYTE *byte)
 * copy a single byte from the receive buffer to the memory
 * location indicated by *byte
 * This function is used when a value from the receive buffer
 * must be saved for future use.
 ***********************************************************************/
void copy_rx_byte(BYTE *byte)
{
	*byte = rxbuff[rxpos++];
}

/************************************************************************
 * void copy_rx_word(WORD *word)
 * copy a 16-bit word from the receive buffer to the memory location
 * indicated by *word
 ***********************************************************************/
void copy_rx_word(WORD *word)
{
	BYTE high,low;
	/* 8 high bits into 8 bit long variable */
	high = rxbuff[rxpos++];
	/* 8 lower bits */
	low = rxbuff[rxpos++];
	
	/* cast to 16 bit length, move high up to higher bits and
	 * OR with low bits */
	*word = ((WORD)high<<8)|(WORD)low;
}

/************************************************************************
 * BYTE rx_byte()
 * reads a byte from the receive buffer and returns it
 * used mainly for comparisons, where the value need not
 * be retained.
 ***********************************************************************/
BYTE rx_byte()
{
	return rxbuff[rxpos++];
}


/************************************************************************
 * void discard_word()
 * move receive buffer pointer along to ignore unwanted stuff
 ***********************************************************************/
void discard_word()
{
	rxpos += 2;
}

/************************************************************************
 * Skip a 32 bit value from the receive buffer
 * this is used to ignore IP header options and such
 * should maybe recalculate the checksum here.. incrementally
 ***********************************************************************/
void SkipLong()
{
	rxpos += 4;
}

/************************************************************************
 * void tx_byte(BYTE sbyte)
 * add a single byte to the transmit buffer, if there's room
 ***********************************************************************/
void tx_byte(BYTE sbyte)
{
	if (txpos <= TXMAXLEN)
		txbuffer[txpos++] = sbyte;
}

/************************************************************************
 * void tx_word(WORD sword)
 * add a 16 bit word to the transmit buffer
 ***********************************************************************/
void tx_word(WORD sword)
{
	txbuffer[txpos++] = (BYTE)(sword>>8);
	txbuffer[txpos++] = (BYTE)sword;
}


syntax highlighted by Code2HTML, v. 0.9