lwip-users
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [lwip-users] usage of ethernetif_input in a single-threaded environm


From: address@hidden
Subject: Re: [lwip-users] usage of ethernetif_input in a single-threaded environment with NO_SYS=0
Date: Wed, 27 Nov 2019 20:19:41 +0100
User-agent: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:60.0) Gecko/20100101 Thunderbird/60.9.1

Am 25.11.2019 um 21:41 schrieb samyuktar:
Hello,

I am using a CC1352P1 TI launchpad interfaced with an ENC28J60 SPI-Ethernet
bridge. I saw the driver for the ethernet interface and have inserted my
functions into the interface. I have NO_SYS = 0 and am using threads in my
environment. One of the threads will be responsible only for lwIP functions,
and the other thread will be completely unrelated. I am unclear on a few
things:

As of now, I have set netif_add with the input function as ethernet_input.
netif->input is called within ethernetif_input. I have initialized the
interface as follows:


IP4_ADDR(&gw, 192,168,1,1);
   IP4_ADDR(&ip_addr, 192,168,1,10);
   IP4_ADDR(&netmask, 255,255,255,0);
   IP4_ADDR(&dest_ip, 192,168,1,11);
   /* First add the interface - ethernetif_init is defined in ethernetif.c,
for NO_SYS=0 input function is ethernetif_input */
   /* set this netif as the default */
   netif_set_default(netif_add(&mynetif, &ip_addr, &netmask,
                               &gw, NULL, (netif_init_fn) ethernetif_init,
ethernetif_input));

This is wrong. The input function passed here is the one your driver
input function will call. This has to be 'ethernet_input' without an OS
or 'tcpip_input' with an OS (unless you know better).

In contrast to this, 'ethernetif_input' is your driver input function.
You'll have to take care of calling this, e.g. after an interrupt or via
some kind of polling.

   /* Bring the interface up */
   netif_set_up(&mynetif);

   /* Bring the link up */
   netif_set_link_up(&mynetif);


ethernetif_input calls low_level_input, which calls my ethernet drivers to
transmit and receive. I am able to transmit and receive raw ethernet frames
without lwIP if I directly insert the MAC address - in ethernetif.c, I
believe I am supposed to insert my low level driver functions, which I did.
Here's my ethernetif_input:



/**
  * This function should be called when a packet is ready to be read
  * from the interface. It uses the function low_level_input() that
  * should handle the actual reception of bytes from the network
  * interface. Then the type of the received packet is determined and
  * the appropriate input function is called.
  * I will have to decide when to call this function
  * @param netif the lwip network interface structure for this ethernetif
  */
void
ethernetif_input(struct netif *netif)
{
   struct ethernetif *ethernetif;
   struct eth_hdr *ethhdr;
   struct pbuf *p;

   ethernetif = netif->state;

   Display_printf(display, 0, 0, "I'm in ethernetif input function: %s", p);
   /* move received packet into a new pbuf */
   p = low_level_input(netif);
   Display_printf(display, 0, 0, "Out of the low_level_input function: %s",
p);
   /* if no packet could be read, silently ignore this */
   if (p != NULL) {
     /* pass all packets to ethernet_input, which decides what packets it
supports */
     if (netif->input(p, netif) != ERR_OK) {   // netif->input here would be
ethernet_input

How can that be ethernet_input when you passed ethernetif_input above
(as argument to netif_add)?

         status_blink_gr_LED();
       LWIP_DEBUGF(NETIF_DEBUG, ("ethernetif_input: IP input error\n"));
       pbuf_free(p);
       p = NULL;
     }
   }
}



and my low_level_input looks like the following :

/**
  * Should allocate a pbuf and transfer the bytes of the incoming
  * packet from the interface into the pbuf.
  *
  * @param netif the lwip network interface structure for this ethernetif
  * @return a pbuf filled with the received packet (including MAC header)
  *         NULL on memory error
  */
static struct pbuf *
low_level_input(struct netif *netif)
{
   struct ethernetif *ethernetif = netif->state;
   struct pbuf *p, *q;
   u16_t len;

   /* Obtain the size of the packet and put it into the "len"
      variable. */
   uint8_t header[6];
   len = ethernet_getRecvLength(header);   // my own low level enc28j60
ethernet drivr fn to get packet length
#if ETH_PAD_SIZE
   len += ETH_PAD_SIZE; /* allow room for Ethernet padding */
#endif

   /* We allocate a pbuf chain of pbufs from the pool. */
   p = pbuf_alloc(PBUF_RAW, len, PBUF_POOL);

   if (p != NULL) {

#if ETH_PAD_SIZE
     pbuf_remove_header(p, ETH_PAD_SIZE); /* drop the padding word */
#endif

     /* We iterate over the pbuf chain until we have read the entire
      * packet into the pbuf. */
     for (q = p; q != NULL; q = q->next) {
       /* Read enough bytes to fill this pbuf in the chain. The
        * available data in the pbuf is given by the q->len
        * variable.
        * This does not necessarily have to be a memcpy, you can also
preallocate
        * pbufs for a DMA-enabled MAC and after receiving truncate it to the
        * actually received size. In this case, ensure the tot_len member of
the
        * pbuf is the sum of the chained pbuf len members.
        */
//      read data into(q->payload, q->len);
        ethernet_packetReceive(q->payload, q->len); // my own low level enc28j60
ethernet drivr fn to read the received packet
        Display_printf(display, 0, 0, "Data being input: %s, len: %d\n",
q->payload, q->len);
     }
//    Not sure what to put in here - maybe I can write a read ack function
//    acknowledge that packet has been read();
    Display_printf(display, 0, 0, "Received data\n");
    //status_blink_LED();
     MIB2_STATS_NETIF_ADD(netif, ifinoctets, p->tot_len);
     if (((u8_t *)p->payload)[0] & 1) {
       /* broadcast or multicast packet*/
       MIB2_STATS_NETIF_INC(netif, ifinnucastpkts);
     } else {
       /* unicast packet*/
       MIB2_STATS_NETIF_INC(netif, ifinucastpkts);
     }
#if ETH_PAD_SIZE
     pbuf_add_header(p, ETH_PAD_SIZE); /* reclaim the padding word */
#endif

     LINK_STATS_INC(link.recv);
   } else {

//    What is the drop_packet function here? Write a function to drop a
packet
//    drop packet();
     LINK_STATS_INC(link.memerr);
     LINK_STATS_INC(link.drop);
     MIB2_STATS_NETIF_INC(netif, ifindiscards);
   }

   Display_printf(display, 0, 0, "Print p: %s", p);
   return p;
}


and in the netif thread, I poll a register on the ENC28J60 which indicates
that a packet has been received. When that packet has been received, or when
the register returns a positive value, I call ethernetif_input function with
my initialized interface.

Currently, there's only this single thread running in my code. Even so, My
code gets stuck as soon as it says a packet has been received and I believe
it gets stuck in the ethernet_input function. Am I understanding something
completely wrong?

I guess you mean ethernetif_input here? I think you have a recursive
call loop: your ethernetif_input calls itself again because netif->input
== ethernetif_input.


I read elsewhere that I can say NO_SYS=0 for a system where there's an RTOS
and I am using threads, which is my system. It also says that I should use
tcpip_init and tcpip_input() in that initialization, but I am unable to see
where I would put in my low level ethernet_receive function in that case.
There's no slot to enter my low level driver function, like there is in
ethernetif_input.

Is ethernetif_input to be used with NO_SYS=1 or NO_SYS=0?

And again you seem to confuse ethernet_input with ethernetif_input?

Regards,
Simon



reply via email to

[Prev in Thread] Current Thread [Next in Thread]