zoukankan      html  css  js  c++  java
  • 基于8019芯片的在9S12下移植成功的TCP/IP协议族(一)

    / Net ETH.C
    //
    // This module is the Ethernet layer
    //----------------------------------------------------------------------------
    #include
    #include
    #include "C8051f.h"
    #include "net.h"
    #include "serial.h"
    #include "arp.h"
    #include "ip.h"
    #include "eth.h"
    /----------------------------------------------------------------------------


    #define reg00   XBYTE[0x8000]   //reg00- 10为isa网卡接口的寄存器地址300-310;
    #define reg01   XBYTE[0x8001]
    #define reg02   XBYTE[0x8002]
    #define reg03   XBYTE[0x8003]
    #define reg04   XBYTE[0x8004]
    #define reg05   XBYTE[0x8005]
    #define reg06   XBYTE[0x8006]
    #define reg07   XBYTE[0x8007]
    #define reg08   XBYTE[0x8008]
    #define reg09   XBYTE[0x8009]
    #define reg0a   XBYTE[0x800a]
    #define reg0b   XBYTE[0x800b]
    #define reg0c   XBYTE[0x800c]
    #define reg0d   XBYTE[0x800d]
    #define reg0e   XBYTE[0x800e]
    #define reg0f   XBYTE[0x800f]
    #define reg10   XBYTE[0x8010]

    bit txd_buffer_select=0;      //选择网卡的发送缓冲区
    extern UCHAR idata debug;
    extern UCHAR xdata arpbuf[];    //arp缓存
    extern UCHAR code my_hwaddr[]; //我的硬件地址缓存

    void Delay1ms(unsigned char T);

    extern UCHAR idata rcve_buf_allocated; //空间申请标志位
    extern UINT volatile event_word;        //当前行为字段

    #define Rtl8019ResetLow P5 &= ~(0x4); // P52
    #define Rtl8019ResetHigh P5 |= 0x4;    // P52

    //------------------------------------------------------------------------
    // Initialize the Cirrus Logic 8019 chip
    //------------------------------------------------------------------------

    void page(unsigned char pagenumber)         //翻页操作
    {
    unsigned char data temp;
    temp=reg00; 
    temp=temp&0x3B ;
    pagenumber=pagenumber <<6;
    temp=temp | pagenumber;
    reg00=temp;
    }

    void Rtl8019AS_Reset()                   //复位网卡
    {
    Rtl8019ResetHigh;;
    Delay1ms(200);
    Rtl8019ResetLow;
    Delay1ms(200);
    }

    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;
       }
    }

    void WriteRtl8019NodeID()                //向8019中写入地址
    {
    page(1);
    reg01=my_hwaddr[0];
    reg02=my_hwaddr[1];
    reg03=my_hwaddr[2];
    reg04=my_hwaddr[3];
    reg05=my_hwaddr[4];
    reg06=my_hwaddr[5];
    page(0);
    }

    void init_8019(void)
    {
    Delay1ms(10);
    Rtl8019AS_Reset();   //复位8019
    R8019_CHIP_SELECT;      //????
    reg00=0x21;     //使芯片处于停止模式,这时进行寄存器设置 停止模式下,将不会发送和接收数据包
    Delay1ms(10);    //延时10毫秒,确保芯片进入停止模式
    page(0);
    reg0a=0x00; reg0b=0x00;
    reg0c= 0xe0;    //monitor mode (no packet receive)
    reg0d= 0xe2;    //loop back mode 使芯片处于mon和loopback模式,跟外部网络断开
    reg01=0x4c;                 //接收缓冲区起始地址
    reg02=0x80;                 //接收缓冲区停止页面地址
    reg03=0x4c;                 //接收缓冲区最后页面地址(接收时自动递增)
    reg04=0x40;                 //发送缓冲区开始页面地址
    reg07=0xff;     //清除所有中断标志位(写1清除中断位)
    reg0f=0x00;     //disable all interrupt(屏蔽所有中断)
    reg0e=0xc8;     //byte dma 8位dma方式 11001000(最后一位选择了8位dma传输)
    page(1);                //翻页至第一页
    reg07=0x4d;                 //当前页面寄存器地址 CURR
    reg08=0x00;                 //
    reg09=0x00;
    reg0a=0x00;
    reg0b=0x00;
    reg0c=0x00;
    reg0d=0x00;
    reg0e=0x00;
    reg0f=0x00;                 //07-0f为多播地址,无用
    reg00=0x22;     //这时让芯片开始工作 0010 0010,处于完成dma读写状态
    ReadRtl8019NodeID(); //读出网卡的物理地址48位
    WriteRtl8019NodeID(); //将网卡地址写入到mar寄存器
    page(0);
    reg0c=0xcc;     //关闭monitor,将网卡设置成正常的模式,跟外部网络连接 1100 1100
    reg0d=0xe0;             //传输配置寄存器,使正常传输
    reg00=0x22;     //这时让芯片开始工作
    reg07=0xff;     //清除所有中断标志位
    }

    //------------------------------------------------------------------------
    // This functions checks 8019 status then sends an ethernet
    // frame to it by calling an assembler function.
    //------------------------------------------------------------------------
    /********发送一个数据包********/
    void send_frame(UCHAR xdata * outbuf, UINT len)/*发送一个数据包的命令,长度最小为60字节,最大1514字节*/
    {
    UCHAR i;
    UINT ii;
    page(0);                                 
    if(len<60)len=60;                         //最小长度为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;                        //需要读取字节数的高八位地址
    reg0a=len&0xff;                        //需要读取字节数的低八位地址 
    reg00=0x12;                         //write dma, page0   0001 0010 启动dma的写操作
    for (ii=0;ii<len;ii++) //for (ii=4;ii<len+4;ii++) //是否加4有待验证
    {
        reg10=*(outbuf+ii);
    }
                                                 //将数据写入发送dma区间,发送数据
    /* 以下3句为中止dma的操作,可以不要            */
    reg0b=0x00;                           //read count high   中止DMA操作
    reg0a=0x00;                           //read count low;
    reg00=0x22;                           //complete dma page 0(abort dma)


                 

    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;                         //0011 1110   数据包重发
    }
    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);                           //释放发送缓冲区
    }

    //------------------------------------------------------------------------
    // This functions checks the 8019 receive event status
    // word to see if an ethernet frame has arrived. If so,
    // set EVENT_ETH_ARRIVED bit in global event_word
    //------------------------------------------------------------------------
    /******查看是否有新的数据包到达******/
    void query_8019(void)

    char bnry,curr;
    page(0);                              //翻到第0页
       bnry=reg03;                        //bnry page have read 读BNRY指针值
    page(1);                              //翻到第一页
    curr=reg07;                        //curr writepoint 读8019写页CURR指针值
    page(0);
    if ((curr==0)) return;
    bnry=bnry++;
    if (bnry>0x7f) bnry=0x4c;
    if (bnry!=curr)                       //此时表示有新的数据包在缓冲区里
    {
       EA = 0;                           //停mcu中断,防止发生冲突
         event_word |= EVENT_ETH_ARRIVED;
        EA = 1;                           //重新开中断
    }
    /******关闭dma操作******/
       reg0b=0x00; reg0a=0x00; reg00=0x22;//complete dma page 0
    }

    //------------------------------------------------------------------------
    // This function gets an incoming Ethernet frame from the 8019.
    // There may be more than 1 waiting but just allocate memory for
    // one and read one in. Use the 8019 to queue incoming packets.
    //------------------------------------------------------------------------
    UCHAR xdata * rcve_frame(void)//如果收到一个有效的数据包,返回收到的数据,否则返回NULL
    {
    UCHAR bnry,curr,next_page;

    UINT len, ii;
    UCHAR temp;
    UCHAR xdata * buf;

    page(0);
       bnry=reg03;                  //bnry page have read 读页指针
    page(1);
    curr=reg07;                  //curr writepoint 8019写页指针
    page(0);
    if ((curr==0)) return NULL; //读的过程出错
    next_page=bnry;               
    bnry=bnry++;
    if (bnry>0x7f) bnry=0x4c;
    if (bnry!=curr)                 //此时表示有新的数据包在缓冲区里
    {
       //读取一包的前4个字节:4字节的8019头部
       page(0);
        reg09=bnry;             //read page address high
       reg08=0x00;             //read page address low
       reg0b=0x00;                //read count high
       reg0a=4;             //read count low;
       reg00=0x0a;             //read dma
     
       temp = reg10;   temp = reg10;
    //读取dma区段的数据,将数据保存到temp中,
    //因为第一个2字节的数据没什么用可以直接被第二个2字节的数据覆盖
    //而第二个2字节的数据是数据长度的高八位和低八位
            next_page = temp-1;    //next page start-1(下一个数据页存储地址减1)
       len = reg10;              //读取数据长度的高八位长度 
       temp = reg10;             //保存数据长度的低八位地址
       len += temp<<8;           //得到数据的长度值
    reg0b=0x00;
       reg0a=0x00;
            reg00=0x22;               //complete dma page 0(完成dma操作)

          // Allocate enough memory to hold the incoming frame
       buf = (UCHAR xdata *)malloc(len);
       if (buf == NULL)          //如果申请不到这么大的空间
       {
        // out of RAM
        // Tell 8019 to skip the frame,直接跳过这个数据包
        page(1);
        curr=reg07;        //page1,当前接收缓冲器的地址
        page(0);       //切换回page0
             bnry = curr -1;      //此时无数据到达
             if (bnry < 0x4c) bnry =0x7f;
             reg03=bnry;       //write to bnry 
        reg07=0xff;      //清除中断状态可以不用
        return NULL;        //返回
       }
       // This flag keeps track of allocated rcve memory
       rcve_buf_allocated = TRUE;
       // Call the assembler function to get the incoming frame
       reg09=bnry;            //read page address high
       reg08=4;             //read page address low,注意前4个字节为8019的串
       reg0b=len>>8;        //read count high
       reg0a=len&0xff;        //read count low;
       reg00=0x0a;            //read dma
            for(ii=0;ii<len;ii++)
            {
         buf[ii]=reg10;
            }
       reg0b=0x00; reg0a=0x00; reg00=0x22; //dma complete page0   
        // Return pointer to start of buffer
       bnry=next_page;
       if (bnry<0x4c) bnry=0x7f;
       reg03=bnry;        //write to bnry  
            reg07=0xff;           //屏蔽中断
       return (buf);       //返回缓冲
    }
    return NULL;
    }


    /**********以太网数据发送函数*********/
    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);
    }

    //------------------------------------------------------------------------
    // This is the handler for incoming Ethernet frames
    // This is designed to handle standard Ethernet (RFC 893) frames
    // See "TCP/IP Illustrated, Volume 1" Sect 2.2
    //------------------------------------------------------------------------
    void eth_rcve(UCHAR xdata * inbuf)                          //接受以太网数据包,按照不同的上层协议分别处理
    {
       ETH_HEADER xdata * eth;
     
       eth = (ETH_HEADER xdata *)inbuf;
     
       // Reject frames in IEEE 802 format where Eth type field
       // is used for length. Todo: Make it handle this format
       if (eth->frame_type < 1520)
       {
          if (debug) serial_send("ETH: IEEE 802 pkt rejected\r");
          return;    
       }

       // Figure out what type of frame it is from Eth header
       // Call appropriate handler and supply address of buffer
       switch (eth->frame_type)
       {
        case ARP_PACKET:
        arp_rcve(inbuf);
        break;
          
        case IP_PACKET:
        ip_rcve(inbuf);
          break;

          default:
       if (debug) serial_send("Error: Unknown pkt rcvd\r");
          break;
       }
    }

    引自本人的百度博客
  • 相关阅读:
    《相约星期二》--[美]米奇·阿尔博姆
    《把信送给加西亚》--[美]阿尔伯特·哈伯德
    《少有人走的路:心智成熟的旅程》--[美]M·斯科特·派克
    《穷爸爸和富爸爸》--[美]罗伯特·清崎,[美]莱希
    Error This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. T
    C#轻量级高性能日志组件EasyLogger
    我们为何要跳槽
    Grid++Report报表工具C/S实战篇(五)
    .NET 开源Protobuf-net从入门到精通
    怎样防止ddos攻击
  • 原文地址:https://www.cnblogs.com/biyeqingfeng/p/2150309.html
Copyright © 2011-2022 走看看