AnsweredAssumed Answered

LWIP on LPC4357, stuck in lpc_low_level_output

Question asked by Mitchell Jones on Jul 27, 2017
Latest reply on Apr 16, 2019 by Jean-Marc Rouxel

Hi, I'm stuck here with the TX side of my app. It appears I am running out of descriptors. I've already modified the famous loop that is problematic as follows: 

(in lpc18xx_43xx_emac)

 volatile u32_t check = lpc_tx_ready(netif);

 

while(dn > check)
#if NO_SYS == 0
{ xSemaphoreTake(lpc_netifdata->xTXDCountSem, 0);}
#else
{
  lpc_tx_reclaim(netif);
  check = lpc_tx_ready(netif);
}

The strange thing is this is only happening when I'm sending a payload that is following a full packet. So if I'm sending anything under 1460 bytes I can do as many transmissions as I want. When I send 1460 followed by a shorter packet of say 500 then it gets stuck. It is very strange. I'll include the mechanisms I'm using to queue the data.

send_buffer(const void* pvBuffer, uint32 uiNumBytes)

struct pbuf *ptr;
ptr = pbuf_alloc(PBUF_TRANSPORT, uiNumBytes , PBUF_RAM);
pbuf_take(ptr, pvBuffer, uiNumBytes);
// std::memcpy(ptr->payload, pvBuffer, uiNumBytes);
// ptr->len = ptr->tot_len = uiNumBytes;
return AddDataAndSend(ptr);

and

 

if(mxDataSet.out_pb == NULL || mxDataSet.out_pb->tot_len == 0)
{
// load data to out_pb
if(mxDataSet.out_pb->tot_len == 0)
{
pbuf_free(mxDataSet.out_pb);
}
mxDataSet.out_pb = ptr;
}else
{
pbuf_cat(mxDataSet.out_pb, ptr);
}
return tcp_client_send_data_set(&mxDataSet);

which is implemented as follows

 

static void tcp_client_raw_send(struct EStreamDataSet* data_set)
{
struct pbuf *ptr;
err_t wr_err = ERR_OK;

while ((wr_err == ERR_OK) && (data_set->out_pb != NULL) && (data_set->out_pb->len <= tcp_sndbuf(data_set->pcb)))
{
ptr = data_set->out_pb;
/* enqueue data for transmission */
wr_err = tcp_write(data_set->pcb, ptr->payload, ptr->len, 1);
if (wr_err == ERR_OK) {
/* continue with next pbuf in chain (if any) */
data_set->out_pb = ptr->next;
if(data_set->out_pb != NULL) {
/* new reference! */
pbuf_ref(data_set->out_pb);
}
/* chop first pbuf from chain */
pbuf_free(ptr);
} else if(wr_err == ERR_MEM) {
/* we are low on memory, try later / harder, defer to poll */
data_set->out_pb = ptr;
} else {
/* other problem ?? */
}
}
}

and 

static err_t tcp_client_raw_sent(void *arg, struct tcp_pcb *tpcb, u16_t len)
{
struct EStreamDataSet *data_set;
data_set = (struct EStreamDataSet *)arg;

LWIP_UNUSED_ARG(len);

if(data_set->out_pb != NULL)
{
/* still got pbufs to send */
tcp_sent(tpcb, tcp_client_raw_sent);
tcp_client_raw_send(data_set);
} else
{
/* no more pbufs to send */
}
return ERR_OK;
}

Do you think I'm experiencing underflow problems? Or is this a different issue entirely? 

 

Note the payloads are getting queued in seperate calls to the send function, the first with a full buffer 1460 the second with an amount less than that. In this instance it seems that second packets descriptor is not clearing, and after 4 of these sequences of 2 (the number of descriptors I have) I get stuck in an infinite loop in emac.

 

oh and just in case, here's my poll

 

static err_t
tcp_client_raw_poll(void *arg, struct tcp_pcb *tpcb)
{
err_t ret_err;
struct EStreamDataSet *data_set;
data_set = (struct EStreamDataSet *)arg;

if (data_set != NULL)
{
if ((data_set->out_pb != NULL) && (data_set->out_pb->tot_len > 0))
{
/* there is a remaining pbuf (chain) */
tcp_client_raw_send(data_set);
} else
{
/* no remaining pbuf (chain) */
// TODO: what needs to happen here?
if (data_set->out_pb != NULL)
{
// Free the buffer.
pbuf_free(data_set->out_pb);
}
}
ret_err = ERR_OK;
} else
{
/* nothing to be done */
// tcp_abort(tpcb);
ret_err = ERR_ABRT;
}
return ret_err;
}

Outcomes