#include <reg52.h>
//#include <absacc.h>
//#include <string.h>
//#include <stdio.h>
#include <REG_NE2K.H>
#include <ethernet.h>
//BYTE efp;
//WORD len;

sbit HW_RESET=P2^7;
int  number;
BYTE mymac[MACLEN];
typedef struct {                    /*  NIC hardware packet ```*/
    BYTE stat;                      /*  Error status */
    BYTE next;                      /*  Pointer to next block */
    WORD len;                       /*  Length of this frame incl. CRC */
} NICHDR;
NICHDR nichdr;

WORD put_ethernet(void *efp,WORD len);
WORD get_ethernet(void *efp);

void delay_ms(int number);
void resetnic();
void getnic(WORD addr,BYTE buf[],WORD len);
void putnic(WORD addr,BYTE buf[],WORD len);
BYTE nicwrap(BYTE page);

//***************************************************
//		接收数据包,将8019中的数据包读入指定的数据包缓冲区pkt,帧头读入nichdr结构中
//		全局变量 nichdr
//      全局变量 next_packet
//      返回:如果接收到数据包,返回数据包长度len,(该长度为减去校验和长度)
//            否则  : 0
//      get packet into buffer,return length (excel  CRC ),or 0 if no available
//***************************************************
WORD get_ethernet(void *efp)
{
	WORD current_offset;
	BYTE curr_page;
	BYTE bnry;
	if (EN0_ISR &0x10) resetnic();
									/* Get the Receive Page, CURR */
		EN_CMD = EN_NODMA + EN_PAGE1 + EN_START;
		curr_page = EN1_CURPAG;
		EN_CMD = EN_NODMA + EN_PAGE0 + EN_START;
		bnry=EN0_BOUNDARY+1;		/* Get the BOUNDARY Register  */
		if (bnry>RX_Stop_PG)  bnry=RX_START_PG;
		/* Remove one frame from the ring.  Boundary is always a page behind. */
//		if (curr_page==0) return (0);
		if (bnry!=curr_page)
	    {
			current_offset = (WORD)(bnry << 8);
			/* Get the header of this packet */
			//memset(&nichdr,0xee,sizeof(nichdr));
			getnic(current_offset, (BYTE *)&nichdr,sizeof(nichdr));
			nichdr.len=(nichdr.len/256)+((nichdr.len %256)<<8);
						//keil c 在结构中使用该方法时,编译器编译的不正确(keil c bug)
//			nichdr.len=(nichdr.len>>8)&0xff+(nichdr.len&0xff)<<8;
			if ((nichdr.stat &0x01) && nichdr.len>=MINFRAMEC  && nichdr.len<=MAXFRAMEC)
				getnic(current_offset+sizeof(nichdr),(BYTE *)efp,nichdr.len-sizeof(nichdr));
			if (nichdr.next>=RX_START_PG && nichdr.next<RX_Stop_PG)
				bnry=nichdr.next;
			else
				bnry=nicwrap(bnry+1);		//nic error
			bnry=nicwrap(bnry-1);
			EN0_BOUNDARY=bnry;
			return (nichdr.len-sizeof(nichdr)-sizeof(ETHERHDR));
		}
		return (0);
}
//*************************************************************
//  Send Ethernet packet give Len   excl. CRC,return 0 if NIC busy
//  全局变量   locnode.mac   (本地的以太物理地址 )
//
//*************************************************************
 WORD put_ethernet(void *efp,WORD len)
 {
 	 if  (EN_CMD & EN_TRANS)  /* if still TXing,return 0 */
 	     len=0;
 	 else
 	 {
 	 	len=min(MAXFRAME,max(len,MINFRAME));
 	 	EN_CMD=EN_PAGE0+EN_NODMA;
 		EN0_ISR=EN_RREAD+EN_START;
 		EN0_TCNTLO=(BYTE)(len & 0xff);
 		EN0_TCNTHI=(BYTE)(len>>8);
 		putnic(TX_START_PG<<8,(BYTE *)efp,len);
 		EN_CMD=EN_NODMA+EN_PAGE0+EN_TRANS;
	 }
	 return(len);
}
//*************************************************************
//      reset nic (ne2000 compact 8019as)
//*************************************************************
void resetnic()
{
    HW_RESET = 1;           /* Hardware RESET.   when EN_RESET = 0; is Software  */
    delay_ms(10);
    HW_RESET = 0;
	delay_ms(10);

    EN_CMD = EN_PAGE0 + EN_NODMA + EN_Stop; /* 00001010B: PS1 PS0 RD2 RD1 RD0 TXP STA STP */
    delay_ms(4);
//EN0_DCFG = ENDCFG_FT10 + ENDCFG_BMS + ENDCFG_BOS; /*  ?FIFO treshold 8byte !!,normal operation, byte transfer mode selection */
    						/* Clear the remote	byte count registers. */
    EN0_DCFG = ENDCFG_FT10 + ENDCFG_BMS;
    EN0_RCNTHI = 0x00; 			/* MSB remote byte count reg */
    EN0_RCNTLO = 0x00; 			/* LSB remote byte count reg */

    EN0_RXCR = E8390_RXOFF; 	/* RX configuration reg    Monitor mode (no packet receive) */
    EN0_TXCR = E8390_TXOFF; 	/* TX configuration reg    set internal loopback mode  */

    EN0_TPSR = NE_START_PG;
    EN0_STARTPG = RX_START_PG ; /* DMA START PAGE 46h */
                                /* Starting page of ring buffer. First page of Rx ring buffer 46h*/
    EN0_StopPG = NE_Stop_PG;    /* Ending page +1 of ring buffer */
    EN0_BOUNDARY = RX_START_PG;	/* Boundary page of ring buffer */
    EN0_ISR = 0xff; 			/* INTerrupt stauts reg */
    EN0_IMR = 0; 				/* INTerrupt mask reg = Disable all Interrupt */


    EN_CMD = EN_PAGE1 + EN_NODMA+EN_Stop;
    delay_ms(4);
    EN1_PAR0 = mymac[0];
    EN1_PAR1 = mymac[1];
    EN1_PAR2 = mymac[2];
    EN1_PAR3 = mymac[3];
    EN1_PAR4 = mymac[4];
    EN1_PAR5 = mymac[5];
    /* Initialize the multicast list to accept-all.  If we enable multicast
	   the higher levels can do the filtering. multicast filter mask array (8 bytes) */
    EN1_MAR0 = 0xff;
    EN1_MAR1 = 0xff;
    EN1_MAR2 = 0xff;
    EN1_MAR3 = 0xff;
    EN1_MAR4 = 0xff;
    EN1_MAR5 = 0xff;
    EN1_MAR6 = 0xff;
    EN1_MAR7 = 0xff;

    EN1_CURR = RX_START_PG + 1; /* RX_CURR_PG; Current memory page = RX_CURR_PG  ? */

    EN_CMD = EN_PAGE0 + EN_NODMA ;  /* 00001010B: PS1 PS0 RD2 RD1 RD0 TXP STA STP */

    EN0_RXCR = ENRXCR_RXCONFIG;      /* rx on(broadcasts, no multicast,errors   04*/
    EN0_TXCR = ENTXCR_TXCONFIG;      /* xmit on. */

    EN0_ISR = 0xff; 	 /* Individual bits are cleared by writing a "1" into it. */
    					 /* It must be cleared after power up. */

    EN0_IMR = ENISR_ALL; /* INTerrupt mask reg */

	EN_CMD = EN_PAGE0 + EN_NODMA + EN_START;
}
//*******************************************
//  get a packet form a given address in NIC's RAM
//  DMA READ
//
//*******************************************
void getnic(WORD addr, BYTE buf[],WORD len)
{
	EN0_ISR=ENISR_RDC;			//clear remote dma interrupt flag
  	EN0_RCNTLO = (BYTE)(len&0xff);			// read length low
	EN0_RCNTHI = (BYTE)(len>>8);			// read length high
	EN0_RSARLO=(BYTE)(addr &0xff);			// read address low
	EN0_RSARHI=(BYTE)(addr>>8);			// read address high
	EN_CMD=EN_RREAD+EN_START+EN_PAGE0;		// do dma read
	while (len--)
		*buf++=EN_DATA;
}

//*******************************************
//  put a packet into a given address in NIC's RAM
//  DMA Write
//
//*******************************************
void putnic(WORD addr, BYTE buf[],WORD len)
{
	len+=len&0x01;
	EN0_ISR=ENISR_RDC;			//clear remote dma interrupt flag
	EN0_RCNTLO = (BYTE)(len&0xff);
	EN0_RCNTHI = (BYTE)(len>>8);
	EN0_RSARLO=(BYTE)(addr &0xff);
	EN0_RSARHI=(BYTE)(addr>>8);
	EN_CMD=EN_RWRITE+EN_START+EN_PAGE0;
	while (len--)
		EN_DATA=*buf++;
	len=10000;
	while ((len && (EN0_ISR & ENISR_RDC))==0)
			len--;
}
//***************************************
//    wrap an rx page number
//***************************************
BYTE nicwrap(BYTE page)
{
	if (page>=RX_Stop_PG)
		page+=RX_START_PG-RX_Stop_PG;
	else   if(page<RX_START_PG)
				page+=RX_Stop_PG-RX_START_PG;
	return (page);
}

//*********************************************************************
//         延时子程序        1ms
//*********************************************************************
void delay_ms(int number)
{									//craystal  22.1184Mhz
	unsigned char i;
	unsigned int j;
	for (j=0;j<number;j++)
	{
			for (i=0;i<229;i++);   //11.0592Mhz   (1ms)
			for (i=0;i<229;i++);   //22.1184Mhz   (1ms)
	}
}
//*********************************************************************
//         延时子程序       100ms
//*********************************************************************

//void delay_100ms(int number)
//{
//	unsigned int j;
//	for (j=0;j<number;j++)
//		delay_ms(100);
//}

/* Make a frame, given data length. Return length of complete frame
** If Ethernet, set dest addr & protocol type; if SLIP, ignore these */
int make_frame(ETHERFRAME *efp, BYTE srce[],BYTE dest[], WORD pcol, WORD dlen)
{

        efp->e.ptype = pcol;
        //memcpy(efp->e.dest, dest, MACLEN);
	//    memcpy(efp->e.srce, srce, MACLEN);
        dlen += sizeof(ETHERHDR);
    	return(dlen);
}


/* Do TCP-style checksum. Improved algorithm is from RFC 1071 */
WORD csum(void *dp, WORD count)
{
    register LWORD total=0L;
    register WORD n, *p, carries;

    n = count / 2;
    p = (WORD *)dp;
    while (n--)
        total += *p++;
    if (count & 1)
        total += (*(BYTE *)p)<<8;
    while ((carries=(WORD)(total>>16))!=0)
        total = (total & 0xffffL) + carries;
    return((WORD)total);
}