usage of ethernetif_input in a single-threaded environment with NO_SYS=0

classic Classic list List threaded Threaded
2 messages Options
Reply | Threaded
Open this post in threaded view
|

usage of ethernetif_input in a single-threaded environment with NO_SYS=0

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));
  /* 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
        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 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?





--
Sent from: http://lwip.100.n7.nabble.com/lwip-users-f3.html

_______________________________________________
lwip-users mailing list
[hidden email]
https://lists.nongnu.org/mailman/listinfo/lwip-users
Reply | Threaded
Open this post in threaded view
|

Re: usage of ethernetif_input in a single-threaded environment with NO_SYS=0

goldsimon@gmx.de
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

_______________________________________________
lwip-users mailing list
[hidden email]
https://lists.nongnu.org/mailman/listinfo/lwip-users