cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 
bharaini
Contributor
Contributor
2,250 Views
Registered: ‎06-28-2019

How to send large number of data through tcp_write() function.

Hello,

I'm working on Zynq Ultrascale+ ZCU102 ES2 board. Now I able to send data values through Ethernet from the board using tcp_write() function. But I able to send only around 2200 values(integer converted to string) at one time before tcp_close().

So, how do I send large number of values through the Ethernet?

Thank you.

 

0 Kudos
6 Replies
egatard
Visitor
Visitor
2,231 Views
Registered: ‎06-20-2018

Hello,

Since you are trying to use tcp_write(), I assume that you use lwip.

You can't send more data with one tcp_write() call than there is available space in the send buffer.

You can check the amount of free space with the tcp_sndbuf() function.

You cannot call tcp_write() with the parameter length bigger than what tcp_sndbuf() returns.

When a new tcp connection is accepted, you can use tcp_sent() to specify a callback  function to use for when some data has been successfully sent.

In that callback function you have to check the send buffer available space and send your next chunk of data with a new tcp_write() call.

This will unroll until you enventually have sent all your data.

egatard
Visitor
Visitor
2,203 Views
Registered: ‎06-20-2018

Hello,

You should not use tcp_write() in the accept callback function, that callback is used to define other callback functions called when data is sent/received on the tcp connection.

Those secondary callback are defined with tcp_recv() and tcp_sent().

You can find additional information about this sequence in lwip documentation:

https://lwip.fandom.com/wiki/Raw/TCP

 

Your callback function defined with tcp_sent() should look like something like this simplified function:

/****************************************************************************/
/* Callback after a packet is sent                                          */
/****************************************************************************/
static void ethernet_sent_callback_ET_System_data(void *arg, struct tcp_pcb *tpcb, uint16_t len)
{
   /* if there is data to send */
   if (bytes_to_send > 0)
   {
      /* make sure the write length is a multiple of 32bits */
      uint32_t write_length = tcp_sndbuf(tpcb) - (tcp_sndbuf(tpcb) % 4);

      /* Next data, zero-copy tcp write */
      tcp_write(tpcb, next_data_to_send_ptr, write_length, 0);

      /* Update the data counter */
      bytes_to_send = bytes_to_send - write_length;
      next_data_to_send_ptr = next_data_to_send_ptr + write_length/4;
   }
}
egatard
Visitor
Visitor
2,199 Views
Registered: ‎06-20-2018

I should have add:

the function tcp_write() is to be called the first time elsewhere in your program to start the data transfer which will then continue by itself thanks to the callback functions.

bharaini
Contributor
Contributor
2,188 Views
Registered: ‎06-28-2019

Hello @egatard 

Thanks for the reply. The code snippet which is down below is the one which I have worked on. I have used tcp_close() because once I open the IP connection, the values keeps on coming infinite times so to stop once all the values are received I have put that.  

Now I get all the 2040 values through the Ethernet and where should I add the code snippet that you suggested to get the remaining data. On the whole I must get atleast 4096 values through the Ethernet.

Thank you.

static err_t accept_callback(void *arg, struct tcp_pcb *pcb, err_t err)
{

  int x[4500];
  char *test[8500];
  char str[4500];
  LWIP_UNUSED_ARG (arg) ;

   for (int i=0; i<2040;i++)

      	{
      	x1[i]=Xil_In32(XPAR_BRAM_0_BASEADDR+(4*i));
       snprintf(str,sizeof(str),"%d",x1[i]);
       test[i]=strcat(str,"	");
       tcp_write(pcb,test[i], strlen(test[i]), 1);
       }
   
    tcp_close(pcb);
}

 

0 Kudos
egatard
Visitor
Visitor
2,181 Views
Registered: ‎06-20-2018

Hello,

in your code you use the accept callback to send data immediatly after the tcp connection is opened. This function should only hook up the callback functions for that new tcp connection:

err_t accept_callback(void *arg, struct tcp_pcb *newpcb, err_t err)
{
    /* specify callback to use for incoming data */
    tcp_recv(newpcb, recv_callback);

    /* specify callback to use for when some data has been successfully sent */
    tcp_sent(newpcb, sent_callback);

    return ERR_OK;
}

Somewhere else in your code you should initiate the transfer with a tcp_write() call.

When a tcp packet has been ACKed by whatever your data is sent to (presummably a PC), the sent_callback function will be automatically called, and in that function you will be able to send the next data with a new tcp_write() call.

You don't need the for loop, the callback function system will do that for you.

The sent_callback function should be next to your other ethernet functions like accept_callback, in the same .c file.

 

Your for loop keep adding data to the send buffer and eventually fill it up before tcp packets are sent, which will empty the send buffer.

Using the callback functions ensures that you add new data to transfer in the send buffer only when some data has been already sent, meaning that there is free space in the send buffer at each tcp_write() call.

bharaini
Contributor
Contributor
2,168 Views
Registered: ‎06-28-2019

Hello @egatard 

Thanks again for the reply. I got your point what you said about accept_callback(). I have loaded my data in Block RAM as a coe file so in order to get that I have used a for loop. Now where do I place the first tcp_write() inside any function or where? in order to get first set of values. Then I should use the first code snippet that you had sent?

Thank you.

0 Kudos