Hi,
My goal is to receive data from the GPIO ports continuously, store it in dual buffers and feed this out the ethernet port continuously. I was hoping to use the enet-lwip example as a starting point but this does leave me with many questions and a steep learning curve. partially because the examples are generally web servers. Firstly I understand LWIP is driven by callback functions. One of which is declared as err_t (* accept) (void * arg, struct tcp_pcb *newpcb, err_t) It is not well documented what one is meant to do in these callback function although I have scoured the web and plagarised heavily as in the attached code. Secondly where do you write the code when it is meant to called by the ethernet interrupt. I placed my initial trial code in the lwIPHostTimerHandler as the code was jumping to there after the call to lwIPInit() however that is obviously not the spot to place it eventually if I am to achieve my aim. Thirdly my current problem aside from these issues is that I can establish a connection to a client that a colleague wrote for me however I cannot seem to send anything. Some help and guidance at this early stage would be much appreciated. Regards, Lee. _______________________________________________ lwip-users mailing list [hidden email] https://lists.nongnu.org/mailman/listinfo/lwip-users |
Hi Lee, LwIP has 3 flavers, meaning you can use it in 3 different modes: 1. RAW mode 2. NetCon 3. BSD I have only experience with RAW mode, were you use the callbacks J BSD is similar to any other system like Linux etc.. NetCon is a socket based API but different from the BSD socket coding. RAW: In general when you define a server you bind your own IP with a server port and add an accept call-back Every connection to this server will trigger the call-back. Inside the call-back you call your own initializing code and assign your receive, poll and other call-back functions. This are bound to the accepted PCB or control block for the new connection. If your connection gets new packets the TCP stack will call the receive call-back for the new connection. If you a few connections at the same time the PCB for every connection is different but the call-back is the same. All these call-back functions should be reentrant with no static variables. This is on one leg… I suggest checking the contribution code and especially the echo server. This is very simple and will help you get the ide. Read the rawapi.txt inside the doc directory. It will also give you some inside information on how to work in RAW mode. Hope that helped. BR, Noam. From: lwip-users-bounces+noam=[hidden email] [mailto:lwip-users-bounces+noam=[hidden email]] On Behalf Of Lee Noack Hi, My goal is to receive data from the GPIO ports continuously, store it in dual buffers and feed this out the ethernet port continuously. I was hoping to use the enet-lwip example as a starting point but this does leave me with many questions and a steep learning curve. partially because the examples are generally web servers. Firstly I understand LWIP is driven by callback functions. One of which is declared as err_t (* accept) (void * arg, struct tcp_pcb *newpcb, err_t) It is not well documented what one is meant to do in these callback function although I have scoured the web and plagarised heavily as in the attached code. Secondly where do you write the code when it is meant to called by the ethernet interrupt. I placed my initial trial code in the lwIPHostTimerHandler as the code was jumping to there after the call to lwIPInit() however that is obviously not the spot to place it eventually if I am to achieve my aim. Thirdly my current problem aside from these issues is that I can establish a connection to a client that a colleague wrote for me however I cannot seem to send anything. Some help and guidance at this early stage would be much appreciated. Regards, Lee.
************************************************************************************ This footnote confirms that this email message has been scanned by PineApp Mail-SeCure for the presence of malicious code, vandals & computer viruses. ************************************************************************************ _______________________________________________ lwip-users mailing list [hidden email] https://lists.nongnu.org/mailman/listinfo/lwip-users |
I am using RAW mode and have read the rawapi.txt several times. I will have another look at the echo server example but seem to stuck at the moment at not being able to send data after obtaining a connection and then when I hopefully have that example working, where do I place my code to send data using pointers to my arrays. This has to be "in the interrupt context" somewhere so obviously not in main().
|
Hi Lee,
Do you use FreeRTOS or any other OS or no OS ? Working with LwIP in RAW mode is a bit tricky. You have just one thread that run everything. This is not so obvious at first. Let me explain: If you have a packet received in your receive call back and you try to send something back it will not be sent until you get out of the function. Sending from within the call-back means putting some data in the sent queue to be sent. As LwIP in Raw mode has just one thread if you do not get out from your call-back the TCP stack actually is On hold. Only after you get out from the function and the TCP stack resumes its house keeping your data will be sent. Also if you send lots of data in a loop, inside one of the call-backs, you may get out of memory. The reason is that In TCP the stack waits for an ACK from the remote end before freeing the used buffer. If you are inside one of the Call-backs and the LwIP does not run it will not process any ACK's and as a result will not free used buffers .. so you Get into memory limits ... You must design your server in such a way that sending is in a separate thread or do some scheduling. I got into problems in my own code, similar to what I have explained above. I had a packet received -> called my parser -> my parser sent back a reply. This does not work when you need to process large amount of data. What I did is when I got a packet I sent a message to a parser task. This message was pushed into a FIFO. After pushing It to the FIFO the LwIP call-back function was exited. The parser running in the background processed the data and if needed sent back information. This separated the LwIP and other code. Hope that helped a bit more. BR, Noam. -----Original Message----- From: lwip-users-bounces+noam=[hidden email] [mailto:lwip-users-bounces+noam=[hidden email]] On Behalf Of Lee Sent: Wednesday, December 17, 2014 11:52 PM To: [hidden email] Subject: Re: [lwip-users] TM4C1294 LWIP Usage I am using RAW mode and have read the rawapi.txt several times. I will have another look at the echo server example but seem to stuck at the moment at not being able to send data after obtaining a connection and then when I hopefully have that example working, where do I place my code to send data using pointers to my arrays. This has to be "in the interrupt context" somewhere so obviously not in main(). -- View this message in context: http://lwip.100.n7.nabble.com/TM4C1294-LWIP-Usage-tp23623p23625.html Sent from the lwip-users mailing list archive at Nabble.com. _______________________________________________ lwip-users mailing list [hidden email] https://lists.nongnu.org/mailman/listinfo/lwip-users ************************************************************************ ************ This footnote confirms that this email message has been scanned by PineApp Mail-SeCure for the presence of malicious code, vandals & computer viruses. ************************************************************************ ************ ************************************************************************************ This footnote confirms that this email message has been scanned by PineApp Mail-SeCure for the presence of malicious code, vandals & computer viruses. ************************************************************************************ _______________________________________________ lwip-users mailing list [hidden email] https://lists.nongnu.org/mailman/listinfo/lwip-users |
This post was updated on .
Hi Noam,
No I am not using an RTOS. I managed to echo characters today so that was a step forward. I was using a fairly simple and easy to understand tcp_echo code.tcp_echo_2.c However my goal is not to receive but only to send. So i won't need to use the recvd function and then tcp_write(),tcp_sent() to loopback. Once I have a connection I will only need to write. I should be able to DMA in my data into 2 large buffers (maybe 1400 Bytes each) and then call a tcp_write with a pointer to this buffer. Then when my other buffer is full, call a tcp_write with a pointer to this other buffer. I understand what you are saying about the code getting held up with lack of acks and freeing of buffers but I'm hoping the data will be fed out the ethernet faster than the data is coming in. The data will be coming in at 2.4MB/s so I'm not positive I can achieve the throughput with 100Mb/s ethernet. First problem though is using the tcp_write() outside of the recvd callback. Hopefully I can just go something like that which is attached but in a write function. Something like the following: static err_t tcp_write_buffer(char * my_buffer, struct tcp_pcb *pcb, err_t err ) { tcp_write( pcb, my_buffer, 1400, 0 ); tcp_sent( pcb, NULL ); return ERR_OK; } I'm not sure that I can use the pcb that I accepted the connection with though. |
Hi Lee,
You are talking on a client application. That's a bit different. Yes you are correct you do not need to use recvd but you must use the tcp_sent callback to be able to know when to send more. You can also check the amount of RAM left in the sent queue so you can send and send until you are on the limit, then wait for the tcp_sent to fire... All my code are servers so I do not have something on hand that can help. Here is one of my functions that I use. Instead of calling tcp_write directly I took something from one of the examples I so: static err_t my_write(struct tcp_pcb *pcb, const void* ptr, u16_t *length, u8_t apiflags) { u16_t len; err_t err; len = *length; do { err = tcp_write(pcb, ptr, len, apiflags); if(err == ERR_MEM) { if((tcp_sndbuf(pcb) == 0) || (pcb->snd_queuelen >= TCP_SND_QUEUELEN)) { /* no need to try smaller sizes */ len = 1; } else { len /= 2; } } else { // if we are here it means that we have a timeout or // network error and need to abort } } while ((err == ERR_MEM) && (len > 1)); *length = len; return err; } In the above code you try to send as much as you can and if tcp send buff is too small you try to send less and less, until you are successful or not. If you are not able to send everything you must wait for data buffers to get freed. This is done by calling the above code inside the tcp_sent call back Do not expect high throughput from LwIP. It is small but not very fast. I have read people are able to run it at about 1Mb, maybe I am wrong. BR, Noam. -----Original Message----- From: lwip-users-bounces+noam=[hidden email] [mailto:lwip-users-bounces+noam=[hidden email]] On Behalf Of Lee Sent: Thursday, December 18, 2014 11:40 AM To: [hidden email] Subject: Re: [lwip-users] TM4C1294 LWIP Usage Hi Noam, No I am not using an RTOS. I managed to echo characters today so that was a step forward. I was using a fairly simple and easy to understand tcp_echo code. tcp_echo_2.c <http://lwip.100.n7.nabble.com/file/n23627/tcp_echo_2.c> However my goal is not to receive but only to send. So i won't need to use the recvd function and then tcp_write(),tcp_sent() to loopback. Once I have a connection I will only need to write. I should be able to DMA in my data into 2 large buffers (maybe 1400 Bytes each) and then call a tcp_write with a pointer to this buffer. Then when my other buffer is full, call a tcp_write with a pointer to this buffer. I understand what you are saying about the code getting held up with lack of acks and freeing of buffers but I'm hoping the data will be fed out the ethernet faster than the data is coming in. The data will be coming in at 2.4MB/s so I'm not hopeful I can achieve the throughput with 100Mb/s ethernet. First problem though is using the tcp_write() outside of the recvd callback. Hopefully I can just go something like that which is attached but in a write function. tcp_write( pcb, my_buffer, 1400, 0 ); tcp_sent( pcb, NULL ); I'm not sure that I can use the pcb that I accepted with though. -- View this message in context: http://lwip.100.n7.nabble.com/TM4C1294-LWIP-Usage-tp23623p23627.html Sent from the lwip-users mailing list archive at Nabble.com. _______________________________________________ lwip-users mailing list [hidden email] https://lists.nongnu.org/mailman/listinfo/lwip-users ************************************************************************ ************ This footnote confirms that this email message has been scanned by PineApp Mail-SeCure for the presence of malicious code, vandals & computer viruses. ************************************************************************ ************ ************************************************************************************ This footnote confirms that this email message has been scanned by PineApp Mail-SeCure for the presence of malicious code, vandals & computer viruses. ************************************************************************************ _______________________________________________ lwip-users mailing list [hidden email] https://lists.nongnu.org/mailman/listinfo/lwip-users |
Noam weissman wrote:
> Do not expect high throughput from LwIP. It is small but not very fast. > I have read people are able to run it at about 1Mb, maybe I am wrong. Yes, you are. Getting 1 MByte/second on a TCP connection (if that's what you mean by 1Mb), is much too slow for lwIP. Back in 2006, I was able to get ~2,5 MByte/s without too much effort on a 50MHz Altera-Softcore processor with a MAC that required me to copy every packet to/from its buffers. Nowadays, having a Cortex-M and a zero-copy MAC, I'd expect to get much better rates. I haven't had a chance to test it, though, as we're still stuck with that old platform. I always wanted to benchmark it again, maybe I'll have to try and get a benchmark platform running... Anyway, if you're getting 1MByte/s only, I have no doubt there's something wrong with your lwIP configuration or with the port you're using. (Or you have set up lwIP to be slow to prevent it from stealing the CPU from more important tasks) Simon _______________________________________________ lwip-users mailing list [hidden email] https://lists.nongnu.org/mailman/listinfo/lwip-users |
Hi Simon, I'm using the TM4C1294 which is cortex M4 running at 120MHz so I hope to be able to give you some feedback in the near future. Although with data coming into the GPIO ports at 800kHz and being written to ping pong buffers I'm a little concerned, despite the uDMA. But that's a different bridge to cross. Lee. On Fri, Dec 19, 2014 at 5:00 AM, Simon Goldschmidt [via lwIP] <[hidden email]> wrote: Noam weissman wrote: |
In reply to this post by Noam weissman
Hi Noam, I would probably call it a data server. Is it not possible to start writing in either direction once the connection is established? Thank you for the code I shall look at it today. I'm not quite with you. If the data I wish to send is the maximum size of the payload of a packet, there should be nothing to queue so it should just be sent immediately?? Lee. On Fri, Dec 19, 2014 at 1:37 AM, Noam weissman <[hidden email]> wrote: Hi Lee, _______________________________________________ lwip-users mailing list [hidden email] https://lists.nongnu.org/mailman/listinfo/lwip-users |
In reply to this post by goldsimon@gmx.de
Hi Noam,
"The parser running in the background processed the data and if needed sent back information. This separated the LwIP and other code." I was told that the write function definitely has to be called from within the LWIP context, for instance from within the recvd callback or the poll callback or the sent callback. So refering to that parser task, where did you invoke the first write function? Did you do it in the mainloop or from within a callback? Being able to do it from the mainloop would be interesting, because then it would be possible to determine the moment when transfer starts. Regards, Martin H. _______________________________________________ lwip-users mailing list [hidden email] https://lists.nongnu.org/mailman/listinfo/lwip-users |
In reply to this post by Noam weissman
Hi Noam,
I am still trying to get a simple send function working which is frustrating. Perhaps it is more of a C issue than a LWIP (client or server) issue. Once I have a connection I can do 1 send with tcp_write called in either the recv callback or the accept. Once connected however I am stuck as to where to call another write. I think I would have to make the functions extern and the pcb more global to call another write from main or any included application code. Is this how you did it? Lee. |
Hi Lee,
In one of my previous mails I wrote that you can use the tcp_sent call-bak. If you are able to send one packet simply take you code that creates the reply and put it in your own function. Call this function either from the recv call back or from the tcp_sent call-back For every packet sent out the TCP stack will call your tcp_sent function. That is if you defined one and registered it in the accept call-back. BR, Noam. -----Original Message----- From: lwip-users-bounces+noam=[hidden email] on behalf of Lee Sent: Sat 12/20/2014 2:24 AM To: [hidden email] Subject: Re: [lwip-users] TM4C1294 LWIP Usage Hi Noam, I am still trying to get a simple send function working which is frustrating. Perhaps it is more of a C issue than a LWIP (client or server) issue. Once I have a connection I can do 1 send with tcp_write called in either the recv callback or the accept. Once connected however I am stuck as to where to call another write. I think I would have to make the functions extern and the pcb more global to call another write from main or any included application code. Is this how you did it? Lee. -- View this message in context: http://lwip.100.n7.nabble.com/TM4C1294-LWIP-Usage-tp23623p23636.html Sent from the lwip-users mailing list archive at Nabble.com. _______________________________________________ lwip-users mailing list [hidden email] https://lists.nongnu.org/mailman/listinfo/lwip-users ************************************************************************************ This footnote confirms that this email message has been scanned by PineApp Mail-SeCure for the presence of malicious code, vandals & computer viruses. ************************************************************************************ ************************************************************************************ This footnote confirms that this email message has been scanned by PineApp Mail-SeCure for the presence of malicious code, vandals & computer viruses. ************************************************************************************ _______________________________________________ lwip-users mailing list [hidden email] https://lists.nongnu.org/mailman/listinfo/lwip-users |
In reply to this post by Lee
Lee,
tcp_write puts the data in to the tcp buffer. After tcp_write try tcp_output. Paul ________________________________________ From: lwip-users-bounces+pwebber=[hidden email] <lwip-users-bounces+pwebber=[hidden email]> on behalf of Lee <[hidden email]> Sent: Friday, December 19, 2014 7:24 PM To: [hidden email] Subject: Re: [lwip-users] TM4C1294 LWIP Usage Hi Noam, I am still trying to get a simple send function working which is frustrating. Perhaps it is more of a C issue than a LWIP (client or server) issue. Once I have a connection I can do 1 send with tcp_write called in either the recv callback or the accept. Once connected however I am stuck as to where to call another write. I think I would have to make the functions extern and the pcb more global to call another write from main or any included application code. Is this how you did it? Lee. -- View this message in context: http://lwip.100.n7.nabble.com/TM4C1294-LWIP-Usage-tp23623p23636.html Sent from the lwip-users mailing list archive at Nabble.com. _______________________________________________ lwip-users mailing list [hidden email] https://lists.nongnu.org/mailman/listinfo/lwip-users _______________________________________________ lwip-users mailing list [hidden email] https://lists.nongnu.org/mailman/listinfo/lwip-users |
Hi Paul, Lee,
Calling tcp_output after tcp_write will notify the TCP stack to send the data immediately but if You do not exit the call-back function it will not be sent. Noam. -----Original Message----- From: lwip-users-bounces+noam=[hidden email] [mailto:lwip-users-bounces+noam=[hidden email]] On Behalf Of Paul Webber Sent: Saturday, December 20, 2014 9:20 PM To: [hidden email] Subject: Re: [lwip-users] TM4C1294 LWIP Usage Lee, tcp_write puts the data in to the tcp buffer. After tcp_write try tcp_output. Paul ________________________________________ From: lwip-users-bounces+pwebber=[hidden email] <lwip-users-bounces+pwebber=[hidden email]> on behalf of Lee <[hidden email]> Sent: Friday, December 19, 2014 7:24 PM To: [hidden email] Subject: Re: [lwip-users] TM4C1294 LWIP Usage Hi Noam, I am still trying to get a simple send function working which is frustrating. Perhaps it is more of a C issue than a LWIP (client or server) issue. Once I have a connection I can do 1 send with tcp_write called in either the recv callback or the accept. Once connected however I am stuck as to where to call another write. I think I would have to make the functions extern and the pcb more global to call another write from main or any included application code. Is this how you did it? Lee. -- View this message in context: http://lwip.100.n7.nabble.com/TM4C1294-LWIP-Usage-tp23623p23636.html Sent from the lwip-users mailing list archive at Nabble.com. _______________________________________________ lwip-users mailing list [hidden email] https://lists.nongnu.org/mailman/listinfo/lwip-users _______________________________________________ lwip-users mailing list [hidden email] https://lists.nongnu.org/mailman/listinfo/lwip-users ************************************************************************ ************ This footnote confirms that this email message has been scanned by PineApp Mail-SeCure for the presence of malicious code, vandals & computer viruses. ************************************************************************ ************ ************************************************************************************ This footnote confirms that this email message has been scanned by PineApp Mail-SeCure for the presence of malicious code, vandals & computer viruses. ************************************************************************************ _______________________________________________ lwip-users mailing list [hidden email] https://lists.nongnu.org/mailman/listinfo/lwip-users |
Hi Noam,
I did manage to get it working. <nabble_embed>#include "tcp_tx.h" #include <stdint.h> #include "lwip/debug.h" #include "lwip/stats.h" static err_t tx_sent(void *arg, struct tcp_pcb *pcb, u16_t len) { LWIP_UNUSED_ARG(len); LWIP_UNUSED_ARG( arg ); tcp_write( pcb, data_buffer,1024, 0 ); return ERR_OK; } static void close_conn (struct tcp_pcb *pcb ) { tcp_arg(pcb, NULL); tcp_sent(pcb, NULL); tcp_close(pcb); } static err_t tx_accept(void *arg, struct tcp_pcb *pcb, err_t err ) { LWIP_UNUSED_ARG( arg ); LWIP_UNUSED_ARG( err ); tcp_setprio( pcb, TCP_PRIO_MIN ); tcp_err( pcb, NULL ); tcp_write( pcb, data_buffer,1024, 0 ); tcp_sent(pcb,tx_sent); return ERR_OK; } void tcp_initialize( void ) { struct tcp_pcb *tcp_pcb; tcp_pcb = tcp_new(); tcp_bind(tcp_pcb, IP_ADDR_ANY, 1234); tcp_pcb = tcp_listen( tcp_pcb ); tcp_accept( tcp_pcb, tx_accept ); }</nabble_embed> It doesn't work without an initial tx_write in the accept function for some reason. Thanks for your help. I'll now start looking at how much data this will throughput but at the moment its very slow, partially due to my PC clent taking 0.2S to Ack. Lee. |
Free forum by Nabble | Edit this page |