⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 p16_eth.c

📁 16位单片机上的TCP/IP协议和WEB服务器
💻 C
📖 第 1 页 / 共 2 页
字号:
}

/* Copy data from Rx to Tx buffers, return actual byte count */
WORD copy_rx_tx(WORD maxlen)
{
    BYTE n, done=0;
    WORD count=0;

    save_txbuff();
    while (load_rxbuff(0, RXBUFFLEN) || rxbuffin>0)
    {
        n = rxbuffin;
        if (count+n >= maxlen)
        {
            done = 1;
            n = (BYTE)(maxlen - count);
        }
        for (rxbuffout=0; rxbuffout<n; rxbuffout++)
            put_byte(rxbuff[rxbuffout]);
        rxout += n;
        count += n;
        if (done)
            break;
    }
    net_txlen = MAX(txin, net_txlen);
    return(count);
}

/* Initialise NIC, return 0 if error */
BOOL init_net(void)
{
    BYTE i;

    reset_ether();
    delay_ms(2);
    NIC_RESET = 0;
    delay_ms(2);
    outnic(NE_RESET, innic(NE_RESET));  /* Do reset */
    delay_ms(2);
    if ((innic(ISR) & 0x80) == 0)       /* Report if failed */
    {
        put_ser("\nNIC init err ");
        return(0);
    }
    outnic(CMDR, 0x21);                 /* Stop, DMA abort, page 0 */
    delay_ms(2);                        /* ..wait to take effect */
    outnic(DCR, DCRVAL);
    outnic(RBCR0, 0);                   /* Clear remote byte count */
    outnic(RBCR1, 0);
    outnic(RCR, 0x20);                  /* Rx monitor mode */
    outnic(TCR, 0x02);                  /* Tx internal loopback */
    outnic(TPSR, TXSTART);              /* Set Tx start page */
    outnic(PSTART, RXSTART);            /* Set Rx start, stop, boundary */
    outnic(PSTOP, RXSTOP);
    outnic(BNRY, (BYTE)(RXSTOP-1));
    outnic(ISR, 0xff);                  /* Clear interrupt flags */
    outnic(IMR, 0);                     /* Mask all interrupts */
    outnic(CMDR, 0x61);                 /* Stop, DMA abort, page 1 */
    delay_ms(2);
    for (i=0; i<6; i++)                 /* Set Phys addr */
        outnic(PAR0+i, myeth[i]);
    for (i=0; i<8; i++)                 /* Multicast accept-all */
        outnic(MAR0+i, 0xff);
    outnic(CURRP, RXSTART+1);           /* Set current Rx page */
    next_page = RXSTART + 1;
// Set LED 0 to be a 'link' LED, not 'collision' LED
// It would be nice if the following code worked, but the upper bits of the
// RTL config3 register are obstinately read-only, so it doesn't!
//        outnic(CMDR, 0xe0);                 /* DMA abort, page 3 */
//        outnic(RTL9346CR, 0xc0);            /* Write-enable config regs */
//        outnic(RTL3, 0x10);                 /* Enable 'link' LED */
//        outnic(RTL9346CR, 0x00);            /* Write-protect config regs */
    outnic(CMDR, 0x20);                 /* DMA abort, page 0 */
#if PROMISC
    outnic(RCR, 0x14);                  /* Accept broadcasts and all packets!*/
#else
    outnic(RCR, 0x04);                  /* Accept broadcasts */
#endif
    outnic(TCR, 0);                     /* Normal Tx operation */
    outnic(ISR, 0xff);                  /* Clear interrupt flags */
    outnic(CMDR, 0x22);                 /* Start NIC */
    return(1);
}

/* Set up the I/O ports, reset the NIC */
void reset_ether(void)
{
    DATA_FROM_NIC;
    NIC_ADDR = 0;
    port_b_pullups(TRUE);
    set_tris_b(TRISB_VAL);
    NIC_IOW_ = NIC_IOR_ = 1;
    NIC_RESET = 1;
    set_tris_e(ALL_OUT);
}

/* Get packet into buffer, return 0 if none available */
BOOL get_net(void)
{
    WORD curr;
    BYTE bound;

    net_rxin = 0;
    if (innic(ISR) & 0x10)              /* If Rx overrun.. */
    {
        put_ser(" NIC Rx overrun ");
        init_net();                     /* ..reset controller (drastic!) */
    }
    outnic(CMDR, 0x60);                 /* DMA abort, page 1 */
    curr = innic(CURRP);                /* Get current page */
    outnic(CMDR, 0x20);                 /* DMA abort, page 0 */
    if (curr != next_page)              /* If Rx packet.. */
    {
        curr_rx_page = next_page;
        curr_rx_addr = (WORD)next_page << 8;
        init_rxbuff();
        getnic_rxbuff(sizeof(host));
        get_data((BYTE *)&host, sizeof(host));
        curr_rx_addr += sizeof(host);
        init_rxbuff();
        net_rxin = host.nic.len;        /* Take length from stored header */
        if ((host.nic.stat&1) && net_rxin>=MINFRAMEC && net_rxin<=MAXFRAMEC)
        {                               /* If hdr is OK, get packet */
            net_rxin -= ETHERHDR_LEN + CRCLEN;
            host.eth.pcol = swapw(host.eth.pcol);
#if DEBUG
            print_serial = TRUE;        /* Diagnostic printout of pkt size */
            print_net = print_lcd = FALSE;
            put_ser(" Rx");             /* Include 14-byte MAC hdr in size */
            disp_decword(net_rxin + ETHERHDR_LEN);
            serial_putch('>');
#endif
        }
        else                            /* If not, no packet data */
        {
            net_rxin = 0;
            put_ser(" NIC pkt err ");
        }                               /* Update next packet ptr */
        if (host.nic.next>=RXSTART && host.nic.next<RXSTOP)
            next_page = host.nic.next;
        else                            /* If invalid, use prev+1 */
        {
            net_rxin = 0;
            put_ser(" NIC ptr err ");
            next_page = nicwrap(next_page + 1);
        }                               /* Update boundary register */
        bound = nicwrap(next_page - 1);
        outnic(BNRY, bound);
    }
    return(net_rxin != 0);
}

/* Transmit the Ethernet frame */
void transmit(void)
{
    WORD dlen;
#if DROP_TX
    static BYTE dropcount=0;
#endif
    dlen = net_txlen;
    save_txbuff();
    setnic_tx(-ETHERHDR_LEN);
    txbuffin = 0;
    put_data(host.eth.srce, MACLEN);    /* Destination addr */
    put_data(myeth, MACLEN);            /* Source addr */
    put_byte((BYTE)(host.eth.pcol>>8)); /* Protocol */
    put_byte((BYTE)host.eth.pcol);
    dlen += ETHERHDR_LEN;               /* Bump up length for MAC header */
    putnic_txbuff();
    if (dlen < MINFRAME)
        dlen = MINFRAME;                /* Constrain length */
#if NET_TXBUFFERS > 1
    txbuff_lens[txbuffnum] = dlen;
    outnic(TPSR, txbuffnum ? (TXSTART+TXPAGES) : TXSTART);
#endif
    outnic(TBCR0, (BYTE)dlen);          /* Set Tx length regs */
    outnic(TBCR1, (BYTE)(dlen >> 8));
#if DROP_TX
    if (++dropcount == DROP_TX)
    {
        dropcount = 0;
        return;
    }
#endif
    outnic(CMDR, 0x24);                 /* Transmit the packet */
}
#if NET_TXBUFFERS > 1
/* Retransmit the Ethernet frame */
void retransmit(BYTE buffnum)
{
    WORD dlen;

    outnic(TPSR, buffnum ? (TXSTART+TXPAGES) : TXSTART);
    dlen = txbuff_lens[buffnum];
    outnic(TBCR0, (BYTE)dlen);          /* Set Tx length regs */
    outnic(TBCR1, (BYTE)(dlen >> 8));
    outnic(CMDR, 0x24);                 /* Transmit the packet */
}
#endif
/* Set the 'remote DMA' address in the NIC's RAM to be accessed */
void setnic_addr(WORD addr)
{
    outnic(ISR, 0x40);                  /* Clear remote DMA interrupt flag */
    outnic(RSAR0, addr&0xff);           /* Data addr */
    outnic(RSAR1, addr>>8);
}

/* Set the 'remote DMA' address in the NIC Tx packet buffer */
void setnic_tx(WORD addr)
{                                       /* Add on Tx buffer offset */
    addr += (TXSTART << 8) + ETHERHDR_LEN;
#if NET_TXBUFFERS > 1
    if (txbuffnum)                      /* ..additional offset if 2nd buffer */
        addr += (TXPAGES << 8);
#endif
    outnic(ISR, 0x40);                  /* Clear remote DMA interrupt flag */
    outnic(RSAR0, (BYTE)addr);          /* Remote DMA addr */
    outnic(RSAR1, (BYTE)(addr>>8));
    nic_tx_transfer = 1;
}

/* Set the 'remote DMA' address in the current NIC Rx packet buffer */
void setnic_rx(WORD addr)
{
    addr += curr_rx_addr;
    if (addr >= RXSTOP*256)
        addr += (RXSTART - RXSTOP)*256;
    outnic(ISR, 0x40);                  /* Clear remote DMA interrupt flag */
    outnic(RSAR0, (BYTE)addr);          /* Data addr */
    outnic(RSAR1, (BYTE)(addr>>8));
    nic_tx_transfer = 0;
}

/* Get data from NIC's RAM into the Rx buffer */
void getnic_rxbuff(BYTE len)
{
    if (len == 0)
        return;
    outnic(ISR, 0x40);                  /* Clear remote DMA interrupt flag */
    outnic(RBCR0, len);                 /* Byte count */
    outnic(RBCR1, 0);
    outnic(CMDR, 0x0a);                 /* Start, DMA remote read */
    NIC_ADDR = DATAPORT;
    DATA_FROM_NIC;
    while (len--)                       /* Get bytes */
    {
        NIC_IOR_ = 0;
        rxbuff[rxbuffin++] = NIC_DATA;
        NIC_IOR_ = 1;
    }
}

/* Put the given data into the NIC's RAM from the Tx buffer */
void putnic_txbuff(void)
{
    BYTE n=0, len;

    if ((len = txbuffin) == 0)
        return;
    len += len & 1;                     /* Round length up to an even value */
    outnic(ISR, 0x40);                  /* Clear remote DMA interrupt flag */
    outnic(RBCR0, len);                 /* Byte count */
    outnic(RBCR1, 0);
    outnic(CMDR, 0x12);                 /* Start, DMA remote write */
    NIC_ADDR = DATAPORT;
    DATA_TO_NIC;
    while (len--)                        /* O/P bytes */
    {
        NIC_DATA =  txbuff[n++];
        NIC_IOW_ = 0;
        DELAY_ONE_CYCLE;
        NIC_IOW_ = 1;
    }
    DATA_FROM_NIC;
    len = 255;                          /* Done: must ensure DMA complete */
    while (len && (innic(ISR)&0x40)==0)
        len--;
}

/* Wrap an NIC Rx page number */
BYTE nicwrap(BYTE page)
{
   if (page >= RXSTOP)
       page += RXSTART - RXSTOP;
   else if (page < RXSTART)
       page += RXSTOP - RXSTART;
   return(page);
}

/* Input a byte from a NIC register */
BYTE innic(BYTE reg)
{
    BYTE b;

    DATA_FROM_NIC;
    NIC_ADDR = reg;
    NIC_IOR_ = 0;
    b = NIC_DATA;
    NIC_IOR_ = 1;
    return(b);
}

/* Output a byte to a NIC register */
void outnic(BYTE reg, BYTE b)
{
    NIC_ADDR = reg;
    NIC_DATA = b;
    DATA_TO_NIC;
    NIC_IOW_ = 0;
    DELAY_ONE_CYCLE;
    NIC_IOW_ = 1;
    DATA_FROM_NIC;
}

/* EOF */

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -