📄 eth.c
字号:
//-----------------------------------------------------------------------------
// Net ETH.C
//
// This module is the Ethernet layer
//-----------------------------------------------------------------------------
#include <general.h>
bit txd_buffer_select=0; //选择网卡的发送缓冲区 //用于标识网卡是否收到数据包
sbit P10=P1^0;
sbit P11=P1^1;
sbit P16=P1^6;
void Delay10ms();
#define MaxLenARPtable 10 //ARP表长度
#define MaxLenPingBuf 10 //PING缓冲区长度
xdata union arp_table_type arp_tab[MaxLenARPtable]; //ARP表,存在外部RAM区里
xdata struct ping_table_type ping_table[MaxLenPingBuf]; //ping表,在外部RAM里
xdata union netcard rxdnet; //接收缓冲区
xdata union netcard txdnet; //发送缓冲区
xdata union Ethernet_address my_ethernet_address; //本机的以太网地址 //存放网卡的MAC地址.在初始化网卡时,用该数组里的内容对PAR0~PARA5进行赋值
//当然,在初始化之前一定要从X5045里读出该参数.在调试时,可以先对该数组赋值.
xdata union Ethernet_address gateway_ethernet_address; //网关的以太网地址
xdata union Ethernet_address ping_ethernet_address; //用来ping的以太网地址
xdata union IP_address my_ip_address; //本机的ip地址
xdata union IP_address temp_ip_address; //用于存放临时IP地址
xdata union IP_address gateway_ip_address; //网关的ip地址
xdata union IP_address mask_ip_address; //子网掩码
xdata union IP_address ping_ip_address; //用于ping命令
unsigned char index=0; //ARP table 循环加入点
unsigned int frameindex=0; //IP包的序列号
//unsigned char xdata netRxBuf[MCU_RECV_RAM]; //收发缓冲区实体
//unsigned char xdata *pNetIn,*pNetOut;
extern xdata struct wait arpwait; //用于等待ARP.
extern unsigned char data WriteBuf; //写内容
extern unsigned char data addr0,addr1; //地址
//------------------------------------------------------------------------
// Initialize the Cirrus Logic 8019 chip
//------------------------------------------------------------------------
//------------------------------------------------------------------------
//函数功能:选择页面
//
//入参: 页码pagenumber
//
//返回值: 无
//
//作者:
//
//注释: Mingtree
//日期: 2004-09-19
//------------------------------------------------------------------------
void page(unsigned char pagenumber)
{
unsigned char data temp;
temp=reg00;
temp=temp&0x3B ;//不改变RD2—RD0,以及最后两位0011 1011
pagenumber=pagenumber <<6;
temp=temp | pagenumber;
reg00=temp;
}
//------------------------------------------------------------------------
//函数功能:将网卡软复位
//
//入参: 无
//
//返回值: 无
//
//作者:
//
//注释: Mingtree
//日期: 2004-09-19
//------------------------------------------------------------------------
void Rtl8019AS_Reset() //复位网卡
{
// unsigned char data temp;
//对18h进行读写操作
// page(0);
// reg18=temp;
// temp=reg18;
P16=1;
Delay10ms();
P16=0;
}
/*
void ReadRtl8019NodeID(void)//读出网卡的物理地址存到my_ethernet_address.bytes[6]里
{
unsigned char data i;
page(0);
reg09=0; //读取网卡的ram的地址为0x0000
reg08=0;
reg0b=0;
reg0a=12; //读取12个字节
reg00=0x0a; //读ram
for (i=0;i<6;i++)
{
// my_hwaddr[i]=reg10;
// my_hwaddr[i]=reg10;
}
}
*/
//------------------------------------------------------------------------
//函数功能:设置网卡的MAC地址
//
//入参: 无
//
//返回值: 无
//
//作者:
//
//注释: Mingtree
//日期: 2004-09-19
//------------------------------------------------------------------------
void WriteRtl8019NodeID()
{
page(1);
reg01=my_ethernet_address.bytes[0];
reg02=my_ethernet_address.bytes[1];
reg03=my_ethernet_address.bytes[2];
reg04=my_ethernet_address.bytes[3];
reg05=my_ethernet_address.bytes[4];
reg06=my_ethernet_address.bytes[5];
page(0);
}
//------------------------------------------------------------------------
//函数功能:初始化网卡
//
//入参: 无
//
//返回值: 无
//
//作者:
//
//注释: Mingtree
//日期: 2004-09-19
//------------------------------------------------------------------------
void init_8019(void)
{
Rtl8019AS_Reset(); //复位8019
reg00=0x21; //使芯片处于停止模式,这时进行寄存器设置 停止模式下,将不会发送和接收数据包
Delay10ms(); //延时500毫秒,确保芯片进入停止模式
page(0);
reg0a=0x00;
reg0b=0x00;
reg0c= 0xe0; //monitor mode (no packet receive)
reg0d= 0xe2; //loop back mode 使芯片处于mon和loopback模式,跟外部网络断开
//使用0x40-0x4B为网卡的发送缓冲区,共12页,刚好可以存储2个最大的以太网包。
//使用0x4c-0x7f为网卡的接收缓冲区,共52页。
reg01=0x4c; //PSTART
reg02=0x80; //PSTOP
reg03=0x4c; //BNRY
reg04=0x40; //TPSR
reg07=0xff; //清除所有中断标志位
reg0f=0x00; //disable all interrupt
reg0e=0xc8; //byte dma 8位dma方式
page(1);
reg07=0x4d; reg08=0x00; reg09=0x00; reg0a=0x00; reg0b=0x00;
reg0c=0x00; reg0d=0x00; reg0e=0x00; reg0f=0x00;
reg00=0x22; //这时让芯片开始工作
// ReadRtl8019NodeID(); //读出网卡的物理地址48位
WriteRtl8019NodeID(); //将网卡地址写入到mar寄存器
page(0);
reg0c=0xcc; //将网卡设置成正常的模式,跟外部网络连接
reg0d=0xe0;
//设置单片机接收缓冲区实体
// pNetIn = netRxBuf;
// pNetOut = netRxBuf;
reg00=0x22; //这时让芯片开始工作
reg07=0xff; //清除所有中断标志位
}
//------------------------------------------------------------------------
//函数功能:发送一个包
//
//入参: 指向发送包联合体的指针(netcard *类型),发送字节数
//
//返回值: 无
//
//作者:
//
//注释: Mingtree
//日期: 2004-09-28(MIDDLE AUTUMN)
//------------------------------------------------------------------------
void send_packet(union netcard xdata *pTxdnet,unsigned int Length)//ne2000发包子程序
{//发送一个数据包的命令,长度最小为60字节,最大1514字节需要发送的数据包要先存放在txdnet缓冲区
unsigned char i;
unsigned int ii;
page(0);
if(Length<60) Length=60;
for(i=0;i<3;i++)
pTxdnet->etherframe.uSourceID[i]=my_ethernet_address.words[i];
//如果上一个包用低地址,则这次用高地址.也就是高低地址轮流使用
txd_buffer_select=!txd_buffer_select;
if(txd_buffer_select)
reg09=0x40 ; //txdwrite highaddress
else
reg09=0x46 ; //txdwrite highaddress
reg08=0x00; //read page address low
reg0b=Length>>8; //read count high
reg0a=Length&0xFF; //read count low;
reg00=0x12; //write dma, page0
//加4的原因是8019as的收发包的结构不一样
for(ii=4;ii<Length+4;ii++)
reg10=pTxdnet->bytes.bytebuf[ii];
/* 以下3句为中止dma的操作 */
reg0b=0x00; //read count high 中止DMA操作
reg0a=0x00; //read count low;
reg00=0x22; //complete dma page 0
//下面的循环的作用是保证上一个包已经成功发送。发送完成的标志是REG00的第二位为0,
//发送成功(发送没有错误)的标志是发送状态寄存器(REG04)最后一位为1.读者Mingtree注释.
for(i=0;i<6;i++){ //最多重发6次
for(ii=0;ii<1000;ii++) //检查txp为是否为低
if((reg00&0x04)==0) break;
if((reg04&0x01)!=0) break; //表示发送成功(应该是表示上一个数据包发送成功)
reg00=0x3E;
}
if(txd_buffer_select)
reg04=0x40; //txd packet start;
else reg04=0x46; //txd packet start;
reg06=Length>>8; //high byte counter
reg05=Length&0xFF; //low byte counter
reg00=0x3E; //to sendpacket;
}
//------------------------------------------------------------------------
//函数功能:接收一个包
//
//入参: 指向发送包联合体的指针(netcard *类型).接收的包的长度在包首部里.
//
//返回值: unsigned char类型的值,0表示没收到包,1表示收到包
//
//作者:
//
//注释: Mingtree
//日期: 2004-09-28(MIDDLE AUTUMN)
//------------------------------------------------------------------------
unsigned char recv_packet(union netcard xdata *pRxdnet)//ne2000收包子程序
{
unsigned char i;
unsigned int ii;
unsigned char bnry,curr;
// unsigned char ucPacket; //收到包的数目,最多收208个包,所以可以用一个字节
// unsigned char bPacket; //表示是否还有包
// unsigned char xdata *pTemp;
// bPacket = TRUE;
page(0);
reg07=0xFF;
bnry=reg03; //bnry page have read 读页指针
page(1);
curr=reg07; //curr writepoint 8019写页指针
page(0);
if(curr==0)
return 0;
//bnry=bnry++;
bnry++;
if(bnry>0x7F) bnry=0x4C;
if(bnry!=curr)
{ //此时表示有新的数据包在缓冲区里
//读取一包的前18个字节:4字节的8019头部,6字节目的地址,6字节原地址,2字节协议
//在任何操作都最好返回page0
page(0);
reg09=bnry; //read page address high
reg08=0x00; //read page address low
reg0b=0x00; //read count high
reg0a=18; //read count low;
reg00=0x0A; //read dma
for(i=0;i<18;i++)
pRxdnet->bytes.bytebuf[i] = reg10;
/* 以下3句为中止dma的操作,可以不要 */
reg0b=0x00; //read count high 中止DMA操作
reg0a=0x00; //read count low;
reg00=0x22; //complete dma page 0
i=pRxdnet->bytes.bytebuf[3]; //将长度字段的高低字节掉转
pRxdnet->bytes.bytebuf[3]=pRxdnet->bytes.bytebuf[2];
pRxdnet->bytes.bytebuf[2]=i;
pRxdnet->etherframe.uLength=pRxdnet->etherframe.uLength-4;//去掉4个字节的CRC
//表示读入的数据包有效
if(((pRxdnet->bytes.bytebuf[0]&0x01)==0)||(pRxdnet->bytes.bytebuf[1]>0x7F)||(pRxdnet->bytes.bytebuf[1]<0x4C)||(pRxdnet->bytes.bytebuf[2]>0x06)){
//接收状态错误,或者next_page_start错误或者长度错误,将丢弃所有数据包
page(1);
curr=reg07; //page1
page(0); //切换回page0
bnry=curr-1;
if(bnry<0x4C) bnry=0x7F;
reg03=bnry; //write to bnry
return 0;
}
else
{//表示数据包是完好的.读取剩下的数据
if((pRxdnet->etherframe.protocal==0x0800)||(pRxdnet->etherframe.protocal==0x0806))
{
page(0);
//协议为IP或ARP才接收
reg09=bnry; //read page address high
reg08=0x04; //read page address low
reg0b=pRxdnet->etherframe.uLength>>8; //read count high
reg0a=pRxdnet->etherframe.uLength&0xFF; //read count low;
reg00=0x0A; //read dma
for(ii=4;ii<pRxdnet->etherframe.uLength+4;ii++)
pRxdnet->bytes.bytebuf[ii]=reg10;
/* 以下3句为中止dma的操作,可以不要 */
reg0b=0x00; //read count high 中止DMA操作
reg0a=0x00; //read count low;
reg00=0x22; //complete dma page 0
bnry=pRxdnet->bytes.bytebuf[1]-1;//next page start-1
if(bnry<0x4C) bnry=0x7F;
reg03=bnry; //write to bnry
return 1;
}
bnry=pRxdnet->bytes.bytebuf[1]-1;//next page start-1
if(bnry<0x4C) bnry=0x7F;
reg03=bnry; //write to bnry
return 0; //have new packet
}
}
return 0;
}
//------------------------------------------------------------------------
//函数功能:向指定的IP地址发送一个ARP请求
//
//入参: IP地址
//
//返回值: 无
//
//作者:
//
//注释: Mingtree
//日期: 2004-09-28(MIDDLE AUTUMN)
//------------------------------------------------------------------------
void arp_request(union IP_address ip_address)//ARP请求
{
unsigned char i;
txdnet.etherframe.protocal=0x0806;//arp protocal
for(i=0;i<3;i++){//复制对方网卡地址或网关地址
txdnet.etherframe.uDestID[i]=0xffff;//广播地址
//指定以太网数据包首部中的源MAC地址
txdnet.etherframe.uSourceID[i]=my_ethernet_address.words[i];
txdnet.arpframe.sourcenodeid[i]=my_ethernet_address.words[i];
txdnet.arpframe.destnodeid[i]=0x0000;
}
for(i=0;i<2;i++)
txdnet.arpframe.sourceip[i]=my_ip_address.words[i];
txdnet.arpframe.destip[0]=ip_address.words[0];
txdnet.arpframe.destip[1]=ip_address.words[1];
txdnet.arpframe.harewaretype=0x0001;
txdnet.arpframe.protocaltype=0x0800;
txdnet.arpframe.halength=0x06;
txdnet.arpframe.palength=0x04;
txdnet.arpframe.operation=0x0001;
for(i=0x2E;i<(0x2E+18);i++)
txdnet.bytes.bytebuf[i]=0x00;
send_packet(&txdnet,60);
}
//------------------------------------------------------------------------
//函数功能:对ARP请求进行应答
//
//入参: 无
//
//返回值: 无
//
//作者:
//
//注释: Mingtree
//日期: 2004-09-29
//------------------------------------------------------------------------
void arp_answer()//ARP应答
{
unsigned char i;
if (rxdnet.arpframe.destip[0]==my_ip_address.words[0])
if (rxdnet.arpframe.destip[1]==my_ip_address.words[1])
{//表示是向我这个ip地址的请求
for(i=16;i<64;i++)//复制arp到发送缓冲区
txdnet.bytes.bytebuf[i]=rxdnet.bytes.bytebuf[i];
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -