以下仅仅是实现8019发udp数据程序,不用arp协议.
typedef struct
{
unsigned char dest_hwaddr[6];
unsigned char source_hwaddr[6];
unsigned int frame_type;
} ETH_HEADER;
typedef struct
{
unsigned char ver_len;
unsigned char type_of_service;
unsigned int total_length;
unsigned int identifier;
unsigned int fragment_info;
unsigned char time_to_live;
unsigned char protocol_id;
unsigned int header_cksum;
unsigned long source_ipaddr;
unsigned long dest_ipaddr;
} IP_HEADER;
typedef struct
{
unsigned int source_port;
unsigned int dest_port;
unsigned int length;
unsigned int checksum;
unsigned char msg_data;
} UDP_HEADER;
sbit reset=P3^4;
#define reg00 XBYTE[0xc000] //reg00- 10为isa网卡接口的寄存器地址240-25fh;
#define reg01 XBYTE[0xc100]
#define reg02 XBYTE[0xc200]
#define reg03 XBYTE[0xc300]
#define reg04 XBYTE[0xc400]
#define reg05 XBYTE[0xc500]
#define reg06 XBYTE[0xc600]
#define reg07 XBYTE[0xc700]
#define reg08 XBYTE[0xc800]
#define reg09 XBYTE[0xc900]
#define reg0a XBYTE[0xca00]
#define reg0b XBYTE[0xcb00]
#define reg0c XBYTE[0xcc00]
#define reg0d XBYTE[0xcd00]
#define reg0e XBYTE[0xce00]
#define reg0f XBYTE[0xcf00]
#define reg10 XBYTE[0xd000]
#define reg1f XBYTE[0xdf00]
/******************************设置网卡地址***********************/
void ReadRtl8019NodeID(void)
{
}
void WriteRtl8019NodeID(void) //直接设置本机物理地址
{
page(1);
reg01=0x00;
reg02=0x01;
reg03=0x02;
reg04=0x03;
reg05=0x04;
reg06=0x05;
page(0);
}
void rtl8019as_rst() //复位网卡
{
uchar temp;
reset=1;
delay_ms(800);
reset=0;
delay_ms(800);
}
/************8019初始化*******************/
void page(unsigned char pagenumber)//选择页面
{
unsigned char data temp;
temp=reg00;
temp=temp&0x3B ;
pagenumber=pagenumber < <6;
temp=temp | pagenumber;
reg00=temp;
}
void init_8019(void)
{
delay_ms(10);
rtl8019as_rst(); //复位8019
// R8019_CHIP_SELECT;
reg00=0x21; //使芯片处于停止模式,这时进行寄存器设置 停止模式下,将不会发送和接收数据包
delay_ms(10); //延时10毫秒,确保芯片进入停止模式
page(0);
reg0a=0x00;
reg0b=0x00;
reg0c=0xe0; //RCR
reg0d=0xe2; //loop back mode 使芯片处于mon和loopback模式,跟外部网络断开
//使用0x40-0x4B为网卡的发送缓冲区,共12页,刚好可以存储2个最大的以太网包。
//使用0x4c-0x7f为网卡的接收缓冲区,共52页?
reg01=0x4C; //Pstart 接收缓冲区范围
reg02=0x80; //Pstop 接收缓冲区尾地址
reg04=0x40; //TPSR 发送缓冲区范围
reg03=0x4C; //BNRY 指向最后一个已经读取的页(读指针)
//刚开始,网卡没有接收到任何数据包,所以,BNRY设置为指向第一个接收缓冲区的页0x4c)
reg07=0xff; //清除所有中断标志位
reg0f=0x00; //disable all interrupt
reg0e=0xc8; //byte dma 8位dma方式
page(1); //选择页1的寄存器
reg07=0x4D; //CURR CURR 当前的接收结束页地址。(写指针)
reg08=0x00; //MAR0 设置多点播送的参数
reg09=0x41; //MAR1
reg0a=0x00; //MAR2
reg0b=0x80; //MAR3
reg0c=0x00; //MAR4
reg0d=0x00; //MAR5
reg0e=0x00; //MAR6
reg0f=0x00; //MAR7
reg00=0x22; //这时让芯片开始工作
ReadRtl8019NodeID(); //读出网卡的物理地址48位
WriteRtl8019NodeID(); //将网卡地址写入到mar寄存器
//将网卡设置成正常的模式,跟外部网络连接
page(0);
reg0c=0xcc; //RCR 接收配置寄存器,设置为使用接收缓冲区,仅接收自己的地址的数据包(以及广播地址数据包)和多点播送地址包,小于64字节的包丢弃(这是协议的规定,设置成接收是用于网络分析),校验错的数据包不接收
reg0d=0xe0; //TCR 发送配置寄存器,启用crc自动生成和自动校验,工作在正常模式
reg00=0x22; //这时让芯片开始工作
reg07=0xff; //清除所有中断标志位
}
/************udp***************/
static ulong code my_ipaddr=0xC0A8000A;//设置ip为192.168.0.10
static uint xdata sender_udpport=1025;//发送端口为1025
static ulong xdata sender_ipaddr=0xCAC1318C;//pc机ip为202.193.49.140
void udp_send(uchar xdata *inbuf, uint port, uint len)
{
unsigned long idata sum;
unsigned int idata result;
unsigned char xdata * outbuf;
UDP_HEADER xdata * udp;
IP_HEADER xdata * ip;
// Allocate memory for entire outgoing message including
// eth & IP headers. Total ethernet message length is:
// 14 byte eth header + 20 byte IP header + 8 byte UDP header
// + length of this data
outbuf = (uchar xdata *)malloc(42 + len);//malloc返回为一个(42+len)大小对象所分配的内存指针.如果返回
udp = (UDP_HEADER xdata *)(outbuf + 34);
ip = (IP_HEADER xdata *)(outbuf + 14);
// Direct message back to the senders port.
udp-> dest_port = sender_udpport;
udp-> source_port = port;
udp-> length = 8 + len;
udp-> checksum = 0;
// Fill in data
// Important do not free receive buffer prior to this
memcpy(&udp-> msg_data, (inbuf + 42), len);
// Compute checksum including 12 bytes of pseudoheader
// Must pre-fill 2 items in outbuf to do this
// Direct message back to senders ip address
ip-> dest_ipaddr = sender_ipaddr;
ip-> source_ipaddr = my_ipaddr;
// Sum source_ipaddr, dest_ipaddr, and entire UDP message
sum = (ulong)cksum(outbuf + 26, 8 + udp-> length);
// Add in the rest of pseudoheader which is
// zero, protocol id, and UDP length
sum += (ulong)0x0011;
sum += (ulong)udp-> length;
// In case there was a carry, add it back around
result = (uint)(sum + (sum > > 16));
udp-> checksum = ~result;
ip_send(outbuf, sender_ipaddr, UDP_TYPE, udp-> length);
}
/************ip*****************/
void ip_send(uchar xdata * outbuf, ulong ipaddr, uchar proto_id, uint len)
{
IP_HEADER xdata * ip;
uchar xdata * hwaddr;
static uint ip_ident = 0;
ip = (IP_HEADER xdata *)(outbuf + 14);
ip-> ver_len = 0x45; // IPv4 with 20 byte header
ip-> type_of_service = 0;
ip-> total_length = 20 + len;
ip-> identifier = ip_ident++; // sequential identifier
ip-> fragment_info = 0; // not fragmented
ip-> time_to_live = 32; // max hops
ip-> protocol_id = proto_id; // type of payload
ip-> header_cksum = 0;
ip-> source_ipaddr = my_ipaddr;
// Outgoing IP address
ip-> dest_ipaddr = ipaddr;
// Compute and insert complement of checksum of ip header
// Outgoing ip header length is always 20 bytes
ip-> header_cksum = ~cksum(outbuf + 14, 20);
// Use ARP to get hardware address to send this to
hwaddr = ("0x52","0x54","0xAB","0x4F","0x5E","0x9F");
// Null means that the ARP resolver did not find the IP address
// in its cache so had to send an ARP request
if (hwaddr == NULL)
{
// Fill in the destination information so ehrn the ARP response
// arrives we can identify it and know what to do when we get it
wait.buf = outbuf;
wait.ipaddr = ip-> dest_ipaddr;
wait.proto_id = proto_id;
wait.len = len;
wait.timer = ARP_TIMEOUT;
return;
}
eth_send(outbuf, hwaddr, IP_PACKET, 20 + len);
}
/**************EHER******************/
bit txd_buffer_select=0;
extern uchar code my_hwaddr[6]={0x00, 0x01, 0x02, 0x03, 0x04, 0x05};
void send_frame(uchar xdata * outbuf, uint len)/*发送一个数据包的命令,长度最小为60字节,最大1514字节*/
{
uchar i;
uint ii;
page(0);
if(len <60)len=60;
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=len> > 8; //read count high
reg0a=len&0xff; //read count low;
reg00=0x12; //write dma, page0
for (ii=0;ii <len;ii++) //for (ii=4;ii <len+4;ii++) //是否加4有待验证
{
reg10=*(outbuf+ii);
}
/* 以下3句为中止dma的操作,可以不要 */
reg0b=0x00; //read count high 中止DMA操作
reg0a=0x00; //read count low;
reg00=0x22; //complete dma page 0
for(i=0;i <16;i++) //最多重发16次
{
for(ii=0;ii <1000;ii++) //检查txp为是否为低
{
if ((reg00&0x04)==0) break;
}
if ((reg04&0x01)!=0) break; //表示发送成功
reg00=0x3e;
}
for(i=0;i <16;i++) //最多重发16次
{
for(ii=0;ii <1000;ii++) //检查txp为是否为低
{
if ((reg00&0x04)==0) break;
}
if ((reg04&0x01)!=0) break; //表示发送成功
reg00=0x3e;
}
reg07=0xff;
if(txd_buffer_select)
reg04=0x40; //txd packet start;
else
reg04=0x46; //txd packet start;
reg06=len> > 8; //high byte counter
reg05=len&0xff; //low byte counter
reg07=0xff;
reg00=0x3e; //to sendpacket;
free(outbuf);//free(p) 释放指针为p所指向的存储器区域,p必须是calloc.malloc或者realloc函数分配的存储器区域
}
void eth_send(uchar xdata * outbuf, uchar * hwaddr, uint ptype, uint len)
{
ETH_HEADER xdata * eth;
eth = (ETH_HEADER xdata *)outbuf; //怎么理解指针的含义
// Add 14 byte Ethernet header
memcpy(eth-> dest_hwaddr, hwaddr, 6);
memcpy(eth-> source_hwaddr, my_hwaddr, 6);
eth-> frame_type = ptype;
// We just added 14 bytes to length
send_frame(outbuf, len + 14);
}
/************主程序*****************/
void main(void)
{char bb="abcdedgh";
init_8019();
for(;;)
{udp_send(&bb,1025,8);
}
}
运行后在udpdemo里不能接收到数据,经过测试硬件没有问题,寄存器读写都正常,调试了好久还是没有眉目.