📄 ethernet.c
字号:
#include <reg52.h>
#include <absacc.h>
#include <string.h>
#include <stdio.h>
#include "reg_ne2k.h"
#include "ethernet.h"
sbit HW_RESET=0xb4;
BYTE mymac[MACLEN];
typedef struct { /* NIC hardware packet header */
BYTE stat; /* Error status */
BYTE next; /* Pointer to next block */
WORD len; /* Length of this frame incl. CRC */
} NICHDR;
NICHDR nichdr;
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()
{
unsigned char c;
c = EN_RESET;
EN_RESET = c;
// 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)
for (i=0;i<255;i++); //24Mhz (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);
}
unsigned char check_rtl8019as(void)
{
EN_CMD = EN_PAGE0 + EN_NODMA + EN_STOP; /* 00001010B: PS1 PS0 RD2 RD1 RD0 TXP STA STP */
if(EN0_8019ID0 != 0x50)
return 1;
if(EN0_8019ID1 != 0x70)
return 2;
return 0;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -