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

📄 cs8900if.c

📁 cs8900网络芯片驱动 for lwip
💻 C
📖 第 1 页 / 共 2 页
字号:
      // could not allocate a pbuf
      else
      {
        // skip received frame
        // TODO: maybe do not skip the frame at this point in time?
        PACKETPP = CS_PP_RXCFG;
        PPDATA = (0x0003U | 0x0100U/*RxOKiE*/ | 0x0040U/*Skip_1*/);
#if (CS8900_STATS > 0)
        ((struct cs8900if *)netif->state)->dropped++;
#endif
#ifdef SNMP    
        if_inc_ifInDiscards();
#endif
        len = 0;
      }
    }
    // length was zero
    else
    {
    }
  }
  return p;
}


// To be called when the cs8900a needs service. Does
// not assume the cs8900a needs service. Does test the
// cs8900a whether it needs service. 
//
// As such, may be used robustly called as a deferred
// (or "late") interrupt handler, or may be called in
// a loop to implement polling, or both.
//
// Use cs8900if_service() from your application instead
// of this function. 

static void cs8900_service(struct netif *netif){  // amount of ISQ's to handle (> 0) in one cs8900_service() call
  unsigned char events2service = 1;
  // NOTES:
  // static, so only initialized to zero at program start.
  // irq_status will always hold the last ISQ event register that
  // still needs service. As such, we may leave this function if
  // we encounter an event we cannot service yet, and return later
  // to try to service it.
  static u16_t irq_status = 0x0000U;

  // The "cs8900_needs_service" flag indicates whether any events
  // still need to be serviced.  // clear flag here. 
  // a receive interrupt can, *concurrently with this function*,
  // set this flag on new ISQ event occurences.
  // we will re-evaluate the correct setting of this flag at
  // function exit (below).
  ((struct cs8900if *)netif->state)->needs_service = 0;
  leds_off(LED_FP1);

  // no unhandled irq_status left?
  if (irq_status == 0x0000U)
  {
    // read ISQ register
    irq_status = ISQ;
  }
  // ISQ interrupt event, and allowed to service in this loop?
  while ((irq_status != 0x0000U) && (events2service-- > 0))
  {
    // investigate event
    if ((irq_status & 0x003fU) == 0x0004U/*Receiver Event*/)
    {
      // correctly received frame, either broadcast or individual address
      // TODO: think where these checks should appear: here or in cs8900_input()
      if ((irq_status & 0x0100U/*RxOK*/) && (irq_status & 0x0c00U/*Broadcast | Individual*/))
      {
        // read the frame from the cs8900a
        cs8900if_input(netif);
      }
      else
      {
        // skip this frame
        PACKETPP = CS_PP_RXCFG;
        PPDATA |= 0x0040U/*Skip_1*/;
#if (CS8900_STATS > 0)
        ((struct cs8900if *)netif->state)->dropped++;
#endif
      }
    }
#if (CS8900_STATS > 0)
    else if ((irq_status & 0x003fU) == 0x0010U/*RxMISS Event*/)
    {
  	  ((struct cs8900if *)netif->state)->missed += (irq_status >> 6);
  	}
    else if ((irq_status & 0x003fU) == 0x0012U/*TxCOL Event*/)
    {
  	  ((struct cs8900if *)netif->state)->collisions += (irq_status >> 6);
  	}
#endif
    // read ISQ register
    irq_status = ISQ;
  }

  // we did not deplete the ISQ?
  if (irq_status != 0x0000U)
  {
    // the cs8900a still needs service
    ((struct cs8900if *)netif->state)->needs_service = 1;
    leds_on(LED_FP1);
  }
#if (CS8900_STATS > 1)
  // read RxMiss Counter (zeroes itself upon read)
  PACKETPP = CS_PP_RXMISS;
  ((struct cs8900if *)netif->state)->missed += (PPDATA >> 6);
  // read RxCol Counter (zeroes itself upon read)
  PACKETPP = CS_PP_TXCOL;
  ((struct cs8900if *)netif->state)->collisions += (PPDATA >> 6);
#endif
}
void cs8900if_service(struct netif *netif){
  // is there a reason to call the service routine?
  if ((((struct cs8900if *)netif->state)->needs_service) || (((struct cs8900if *)netif->state)->use_polling))
  {
    cs8900_service(netif);
  }}

/*-----------------------------------------------------------------------------------*//* * cs8900if_output(): * * This function is called by the TCP/IP stack when an IP packet * should be sent. After ARP address lookup, it calls cs8900_output() to * do the actual transmission of the packet. * *//*-----------------------------------------------------------------------------------*/static err_t cs8900if_output(struct netif *netif, struct pbuf *p, struct ip_addr *ipaddr){  struct cs8900if *cs8900if = netif->state;  p = etharp_output(netif, ipaddr, p);  if (p != NULL)
  {
    return cs8900_output(netif, p);
  }
  return ERR_OK;}/*-----------------------------------------------------------------------------------*//* * cs8900if_input(): * * This function should be called when a packet is ready to be read * from the interface. It uses the function cs8900_input() that * should handle the actual reception of bytes from the network * interface. * *//*-----------------------------------------------------------------------------------*/static voidcs8900if_input(struct netif *netif){  struct cs8900if *cs8900if = netif->state;  struct eth_hdr *ethhdr;  struct pbuf *p;  p = cs8900_input(netif);  if(p == NULL) {    return;  }  ethhdr = p->payload;  switch(htons(ethhdr->type)) {  case ETHTYPE_IP:    etharp_ip_input(netif, p);    pbuf_header(p, -14);    netif->input(p, netif);    break;  case ETHTYPE_ARP:    p = etharp_arp_input(netif, ((struct cs8900if *)netif->state)->ethaddr, p);    if(p != NULL) {      cs8900_output(netif, p);      pbuf_free(p);    }
    break;  default:    pbuf_free(p);    break;  }}/*-----------------------------------------------------------------------------------*//* * cs8900if_init(): * * Should be called at the beginning of the program to set up the * network interface. It calls the function low_level_init() to do the * actual setup of the hardware. * *//*-----------------------------------------------------------------------------------*/voidcs8900if_init(struct netif *netif){  struct cs8900if *cs8900if;  // TODO: check result!
  cs8900if = mem_malloc(sizeof(struct cs8900if));	if (cs8900if == NULL) return;

  netif->state = cs8900if;  netif->name[0] = IFNAME0;  netif->name[1] = IFNAME1;  netif->output = cs8900if_output;  netif->linkoutput = cs8900_output;  cs8900if->ethaddr = (struct eth_addr *)&(netif->hwaddr[0]);  // initially assume no ISQ event
  cs8900if->needs_service = 0;
  // set to 1 if polling method is used
  cs8900if->use_polling = 0;

#if (CS8900_STATS > 0)
  // number of interrupts (vector calls)
  cs8900if->interrupts = 0;
  cs8900if->missed = 0;
  cs8900if->dropped = 0;
  cs8900if->sentpackets = 0;
  cs8900if->sentbytes = 0;
#endif
  cs8900_init(netif);
  // TODO: remove this hack
  cs8900if_netif = netif; etharp_init();}/*-----------------------------------------------------------------------------------*/
// this basically dumps a array of bytes, length "len" into a UDP message. It bypasses
// any functionality within lwIP, acting as a low level debug output function (in case
// your hardware has no, or limited, display output available) to debug lwIP itself. 
//
void cs8900_send_debug(unsigned char *p, unsigned int len){	int tries = 0, i;
  // exit if link has failed
  PACKETPP = CS_PP_LINESTATUS;
  if ((PPDATA & 0x0080U/*LinkOK*/) == 0) return; // TODO: find a correct error code

  /* transmit command */  TXCMD = 0x00C9U;  TXLENGTH = (14 + 20 + 8 + len < 60)?60:(14 + 20 + 8 + len);  PACKETPP = CS_PP_BUSSTATUS;
  // not ready for transmission and still within 100 retries?  while(((PPDATA & 0x0100U/*Rdy4TxNOW*/) == 0) && (tries++ < 100))
  {
    // throw away the last committed received frame
    PACKETPP = CS_PP_RXCFG;
    PPDATA = (0x0003U | 0x0040U/*Skip_1*/ | 0x0100U/*RxOKiE*/);    PACKETPP = CS_PP_BUSSTATUS;    /* cs8900if->dropped++; CHECK: we do not know if we actually will drop a frame here, do we? */ 
  }
  // ready to transmit?
  if((PPDATA & 0x0100U/*Rdy4TxNOW*/) != 0)
  { 
    u16_t data, checksum = 0;
                     
    // destination Ethernet address
    RXTXREG = 0xffffU;//htons((0x00 << 8) | 0x0a); 
    RXTXREG = 0xffffU;//htons((0x24 << 8) | 0xc5); 
    RXTXREG = 0xffffU;//htons((0x72 << 8) | 0x6d); 
    // source Ethernet address
    RXTXREG = htons(((u16_t)eth_oui[0] << 8U) | (u16_t)eth_oui[1]); 
    RXTXREG = htons(((u16_t)eth_oui[2] << 8U) | (u16_t)eth_oui[3]); 
    RXTXREG = htons(((u16_t)eth_oui[4] << 8U) | (u16_t)eth_oui[5]);
    // frame type
    RXTXREG = htons(0x0800);
    // TOS, version
    RXTXREG = htons(data = ((0x40 | 0x05) << 8) | 0x00); 
    checksum += data;
    // length
    RXTXREG = htons(data = 20 + 12 + len); 
    checksum += data;
    // identifier
    RXTXREG = htons(data = 0); 
    checksum += data;
    // fragment offset
    RXTXREG = htons(data = 0); 
    checksum += data;
    // TTL, UDP protocol
    RXTXREG = htons(data = (255U << 8) | 17U); 
    checksum += data;

    checksum += (htonl(cs8900if_netif->ip_addr.addr) & 0xffff0000U) >> 16;
    checksum += htonl(cs8900if_netif->ip_addr.addr) & 0x0000ffffU;
    checksum += 0xc0a8U;
    checksum += 0x0001U;
    checksum += 2; // LW: kludge/hack: checksum calculation seems to be wrong somehow
    // LW: this seems (?) to fix it
    // checksum
    RXTXREG = htons(~checksum); 

    // source IP
    RXTXREG = htons((htonl(cs8900if_netif->ip_addr.addr) & 0xffff0000U) >> 16); 
    // source IP
    RXTXREG = htons(htonl(cs8900if_netif->ip_addr.addr) & 0x0000ffffU); 
    // destination IP
    RXTXREG = htons(0xc0a8U); 
    // destination IP
    RXTXREG = htons(0x0001U); 
    // source port 3000
    RXTXREG = htons(3000U); 
    // destination port 3000
    RXTXREG = htons(3000U); 
    // UDP length
    RXTXREG = htons(len); 
    // UDP checksum
    RXTXREG = htons(0);
    for (i = 0; i < len; i += 2)
    {
      RXTXREG = htons((p[i] << 8) | p[i + 1]);
    } 
		while (i < 60)
		{
      RXTXREG = 0;
			i += 2;
		}
  }}
void cs8900_init_debug(){  leds_off(LED_FP1);
  // set RESET bit  PACKETPP = CS_PP_SELFCTL;
  PPDATA = 0x0055U;

  // { the RESET bit will be cleared by the cs8900a
  //   as a result of the reset }
  // RESET bit cleared?
  while((PPDATA & 0x0040U) != 0); // TODO: add timeout

  // { after full initialization of the cs8900a
  //   the INITD bit will be set }

  PACKETPP = CS_PP_SELFTEST;
  // INITD bit still clear?
  while ((PPDATA & 0x0080U) == 0); // TODO: add timeout
  // { INITD bit is set }

  // Set MAC address  PACKETPP = CS_PP_IA1;  PPDATA = (u16_t)0x00 | ((u16_t)0x03 << 8U);  PACKETPP = CS_PP_IA2;  PPDATA = (u16_t)0x41 | ((u16_t)0x00 << 8U);  PACKETPP = CS_PP_IA3;  PPDATA = (u16_t)0x00 | ((u16_t)0x00 << 8U);

  // accept valid unicast or broadcast frames
  PACKETPP = CS_PP_RXCTL;
  PPDATA = (0x0005U | 0x0800U/*broadcast*/ | 0x0400U/*individual*/ | 0x0100U/*RxOK*/);
 
  // enable receive interrupt
  PACKETPP = CS_PP_RXCFG;
  PPDATA = (0x0003U | 0x0100U/*RXIRQ*/);
  // disable transmit interrupt (is default)
  PACKETPP = CS_PP_TXCFG;
  PPDATA = (0x0007U | 0);

  // use interrupt number 0
  PACKETPP = CS_PP_INTNUM;
  PPDATA = (0x0000U);

  // generate interrupt event on:
  // - the RxMISS counter reaches 0x200, or
  // - a received frame is lost
  PACKETPP = CS_PP_BUFCFG;
  PPDATA = (0x000bU |
#if (CS8900_STATS > 0) // interrupt before counter overflow 
  (0x2000U/*MissOvfloiE*/ | 0x1000U/*TxColOvfloiE*/) |
#endif
#if (CS8900_STATS > 1) // interrupt on counter increment
  (0x0400U/*RxMissiE*/) |
#endif
  0x0000U);

  // enable interrupt generation
  PACKETPP = CS_PP_BUSCTL;
  PPDATA = (0x0017U | 0x8000U/*EnableIRQ*/);

  // enable:
  // - receiver
  // - transmitter
  PACKETPP = CS_PP_LINECTL;
  PPDATA = (0x0013U | 0x0080U/*SerTxOn*/ | 0x0040U/*SerRxOn*/);
}

⌨️ 快捷键说明

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