UDP and Raw API, lwip running with RTOS

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

UDP and Raw API, lwip running with RTOS

zulu4711
This post was updated on .
I have lwip up and running in an embbeded system using a RTOS (Keil RTX
kernel) and this seems to work alright. I'm testing with sockets and netconn
UDP, all ok (over PPP).I'm also beginning to look at the raw API (this will
fit the project best in the end), and this works also. Now, I know that the
raw API is only to be called from one single thread.However, I need to be
able to call send etc from several threads. I was wondering if the following
code is ok for that, before using the raw API I call
LOCK_TCPIP_CORE()/UNLOCK_TCPIP_CORE(). I followed the netconn API and it
seems this is the way the locking is done there ?Am I right in this, and is
this a "allowed" way of doing what I want ?Or, are there a better approach
to this
?
//---------------------------------------------------------------------------------------
// Callback function for received data
//---------------------------------------------------------------------------------------
static void rxUDP(void *arg, struct udp_pcb *upcb, struct pbuf *p, struct ip_addr *addr, u16_t port) {
	char str[128];
	// if packet is valid
	if (p != NULL) {
		// WARNING: p can be a chain of buffers (in this example we pretend it is just a single buffer :)!
		if (p->len < sizeof(str)) {
			memcpy(str, p->payload, p->len);
			str[p->len]=0;
			messageDebug(DBG_WAR, __MODULE__, __LINE__, "UDP Packet Received! Payload: [%s], port=%i", str, port);
		}
		pbuf_free(p);
	}
}

//---------------------------------------------------------------------------------------
// Thread that sends UDP message every 1000 to 2000 mSec
//---------------------------------------------------------------------------------------
void thRawUDP(void) {
	extern struct netif ppp_netif;
	
    err_t error;
    ip_addr_t ip_remote;
	
    struct udp_pcb *pUDPPCB;
    struct pbuf  *pBuf;
    char data[] = "Hello world";
	
	setNameRTXMON(__FUNCTION__);

	// wait for netif to come up (a little dirty)
	messageDebug(DBG_WAR, __MODULE__, __LINE__, "Waiting for PPP Netif to come up..");
	while (netif_is_link_up(&ppp_netif)==0)  OS_WAIT(1000);
	messageDebug(DBG_WAR, __MODULE__, __LINE__, "PPP Netif is up");
	
	// Convert from ASCII "xxx.xxx.xxx.xxx" to IP
	ipaddr_aton(SERVER_IP_ADDR, &ip_remote);

	// Lock the stack..
	LOCK_TCPIP_CORE();
		pUDPPCB = udp_new();
		// Bind to any local port
		error = udp_bind(pUDPPCB, IP_ADDR_ANY, 0);
		messageDebug(DBG_WAR, __MODULE__, __LINE__, "udp_bind=%i", error);

		error = udp_connect(pUDPPCB, &ip_remote, SERVER_PORT_NUM);
		messageDebug(DBG_WAR, __MODULE__, __LINE__, "udp_connect=%i", error);

		udp_recv(pUDPPCB, rxUDP, NULL);
	UNLOCK_TCPIP_CORE();	


	while (1) {
		// Allocate pbuf (might end up being a chain of buffers!)
		pBuf = pbuf_alloc(PBUF_TRANSPORT, sizeof(data), PBUF_POOL);
		if (!pBuf) {
			messageDebug(DBG_ERR, __MODULE__, __LINE__, "error allocating buffer");
			OS_WAIT(1000);
			continue;
		}

		// The pBuf we get can be a chain of buffers
		int bytesLeft = sizeof(data); // Number of bytes we still need to move to buffer(s)  
		struct pbuf *packetTempBuffer; // used to traverse the (possible) list of buffers 
		int chunk; // NUmber of bytes we copy to the current buffer	
		int index = 0;  // Index into the source buffer
		
		packetTempBuffer = pBuf;  
		while ( (bytesLeft) && (packetTempBuffer != NULL) )  {  

			chunk = bytesLeft;  
			if ( chunk > packetTempBuffer->len ) {  
				chunk = packetTempBuffer->len;  
			}  

			// copy one part  
			memcpy(packetTempBuffer->payload, &data[index], chunk);  

			// next buffer in chain (if any)  
			packetTempBuffer = packetTempBuffer->next;  

			bytesLeft -= chunk;  
			index += chunk;   
		};  		
		
		//memcpy(pBuf->payload, data, sizeof(data)); // WARNING: No gurantee that pbuf is not multiple buffers in order to hold the data!
		
		messageDebug(DBG_WAR, __MODULE__, __LINE__,"Sending");

		// Lock stack
		LOCK_TCPIP_CORE();
			udp_send(pUDPPCB, pBuf);
		UNLOCK_TCPIP_CORE();	
		
		pbuf_free(pBuf);
		
		OS_WAIT(1000+(rand()%1000));
	}
}

Reply | Threaded
Open this post in threaded view
|

Re: EXTERNAL: UDP and Raw API, lwip running with RTOS

Greenwood, Gregory A.

You may want to explore using messaging (RTOS) to the single thread that is handling UDP.

 

From: lwip-users <lwip-users-bounces+greenwoodg=[hidden email]> On Behalf Of zulu4711
Sent: Monday, October 1, 2018 12:55 AM
To: [hidden email]
Subject: EXTERNAL: [lwip-users] UDP and Raw API, lwip running with RTOS

 

I have lwip up and running in an embbeded system using a RTOS (Keil RTX kernel) and this seems to work alright. I'm testing with sockets and netconn UDP, all ok (over PPP). I'm also beginning to look at the raw API (this will fit the project best in the end), and this works also. Now, I know that the raw API is only to be called from one single thread. However, I need to be able to call send etc from several threads. I was wondering if the following code is ok for that, before using the raw API I call LOCK_TCPIP_CORE()/UNLOCK_TCPIP_CORE(). I followed the netconn API and it seems this is the way the locking is done there ? Am I right in this, and is this a "allowed" way of doing what I want ? Or, are there a better approach to this ? //--------------------------------------------------------------------------------------- // Callback function for received data //--------------------------------------------------------------------------------------- static void rxUDP(void *arg, struct udp_pcb *upcb, struct pbuf *p, struct ip_addr *addr, u16_t port) { char str[128]; // if packet is valid if (p != NULL) { // WARNING: p can be a chain of buffers (in this example we pretend it is just a single buffer :)! if (p->len < sizeof(str)) { memcpy(str, p->payload, p->len); str[p->len]=0; messageDebug(DBG_WAR, __MODULE__, __LINE__, "UDP Packet Received! Payload: [%s], port=%i", str, port); } pbuf_free(p); } } //--------------------------------------------------------------------------------------- // Thread that sends UDP message every 1000 to 2000 mSec //--------------------------------------------------------------------------------------- void thRawUDP(void) { extern struct netif ppp_netif; err_t error; ip_addr_t ip_remote; struct udp_pcb *pUDPPCB; struct pbuf *pBuf; char data[] = "Hello world"; setNameRTXMON(__FUNCTION__); // wait for netif to come up (a little dirty) messageDebug(DBG_WAR, __MODULE__, __LINE__, "Waiting for PPP Netif to come up.."); while (netif_is_link_up(&ppp_netif)==0) OS_WAIT(1000); messageDebug(DBG_WAR, __MODULE__, __LINE__, "PPP Netif is up"); // Convert from ASCII "xxx.xxx.xxx.xxx" to IP ipaddr_aton(SERVER_IP_ADDR, &ip_remote); // Lock the stack.. LOCK_TCPIP_CORE(); pUDPPCB = udp_new(); // Bind to any local port error = udp_bind(pUDPPCB, IP_ADDR_ANY, 0); messageDebug(DBG_WAR, __MODULE__, __LINE__, "udp_bind=%i", error); error = udp_connect(pUDPPCB, &ip_remote, SERVER_PORT_NUM); messageDebug(DBG_WAR, __MODULE__, __LINE__, "udp_connect=%i", error); udp_recv(pUDPPCB, rxUDP, NULL); UNLOCK_TCPIP_CORE(); while (1) { // Allocate pbuf (might end up being a chain of buffers!) pBuf = pbuf_alloc(PBUF_TRANSPORT, sizeof(data), PBUF_POOL); if (!pBuf) { messageDebug(DBG_ERR, __MODULE__, __LINE__, "error allocating buffer"); OS_WAIT(1000); continue; } // The pBuf we get can be a chain of buffers int bytesLeft = sizeof(data); // Number of bytes we still need to move to buffer(s) struct pbuf *packetTempBuffer; // used to traverse the (possible) list of buffers int chunk; // NUmber of bytes we copy to the current buffer int index = 0; // Index into the source buffer packetTempBuffer = pBuf; while ( (bytesLeft) && (packetTempBuffer != NULL) ) { chunk = bytesLeft; if ( chunk > packetTempBuffer->len ) { chunk = packetTempBuffer->len; } // copy one part memcpy(packetTempBuffer->payload, &data[index], chunk); // next buffer in chain (if any) packetTempBuffer = packetTempBuffer->next; bytesLeft -= chunk; index += chunk; }; //memcpy(pBuf->payload, data, sizeof(data)); // WARNING: No gurantee that pbuf is not multiple buffers in order to hold the data! messageDebug(DBG_WAR, __MODULE__, __LINE__,"Sending"); // Lock stack LOCK_TCPIP_CORE(); udp_send(pUDPPCB, pBuf); UNLOCK_TCPIP_CORE(); pbuf_free(pBuf); OS_WAIT(1000+(rand()%1000)); } }


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
Reply | Threaded
Open this post in threaded view
|

Re: EXTERNAL: UDP and Raw API, lwip running with RTOS

zulu4711
Gregory,
yes, thats absolutely also a (very good!) possibility, however it would make
things more complicated for me (lwip is taking over in an existing project)
and I would like to avoid messaging.
Hence I'm looking for a way of calling the stack (raw API) from other
threads and doing the LOCK from these threads when needed.
I'm just not 100% if my approach is correct, or if it can be done in another
(better way) ?



--
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: EXTERNAL: UDP and Raw API, lwip running with RTOS

goldsimon@gmx.de
On 01.10.2018 19:52, zulu4711 wrote:
> [..]
> Hence I'm looking for a way of calling the stack (raw API) from other
> threads and doing the LOCK from these threads when needed.
> I'm just not 100% if my approach is correct, or if it can be done in another
> (better way) ?

Using LOCK_TCPIP_CORE()/UNLOCK_TCPIP_CORE() is ok.
Unfortunately, I can't read the rest of your mail as the formatting got
corrupted.

Simon

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

Re: EXTERNAL: UDP and Raw API, lwip running with RTOS

zulu4711
Simon,
I edited my post on the forum afterwards (as I also discovered that it was
unreadable).
Anyway, I have included it here also, hope it works ?





--
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: UDP and Raw API, lwip running with RTOS

goldsimon@gmx.de
zulu4711 wrote:
> I edited my post on the forum afterwards (as I also discovered that it was
> unreadable).

Which forum are you talking about? This is a mailing list and you cannot
edit mails after you have sent them.

> Anyway, I have included it here also, hope it works ?

I'm not sure I understand that.


Simon

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

Re: UDP and Raw API, lwip running with RTOS

zulu4711
Reply | Threaded
Open this post in threaded view
|

Re: UDP and Raw API, lwip running with RTOS

goldsimon@gmx.de
zulu4711 wrote:
> Simon,
> I access it here:
> http://lwip.100.n7.nabble.com/UDP-and-Raw-API-lwip-running-with-RTOS-td33221.html

Ok, so you're using nabble. That's fine for you. I'm using this list. By now, you
may have noticed the difference ;-)

In other words, the formatting of your mail is still messed up. If you want
everyone being able to read your mails, not just nabble users, send correct mails.

Plus (and that goes for all nabble users): on mailing lists, you normally include
the text you reply to. In forums, you don't. That makes a difference regarding
readability and I quickly skip mails where I can't find the context fast enough...


Simon

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

Re: UDP and Raw API, lwip running with RTOS

zulu4711
Simon,
Sorry for that !
My "everyday" reading of lwip topics is done on nabble, hence I did the
question there. Anyway, here is the original question, Hope it is readable
now.


I have lwip up and running in an embbeded system using a RTOS (Keil RTX
kernel) and this seems to work alright. I'm testing with sockets and netconn
UDP, all ok (over PPP).I'm also beginning to look at the raw API (this will
fit the project best in the end), and this works also.
Now, I know that the raw API is only to be called from one single
thread.However, I need to be able to call send etc from several threads.
I was wondering if the following code is ok for that, before using the raw
API I call LOCK_TCPIP_CORE()/UNLOCK_TCPIP_CORE().
I followed the netconn API and it seems this is the way the locking is done
there ?
Am I right in this, and is this a "allowed" way of doing what I want ?
Or, are there a better approach to this  ?

//---------------------------------------------------------------------------------------
// Callback function for received data
//---------------------------------------------------------------------------------------
static void rxUDP(void *arg, struct udp_pcb *upcb, struct pbuf *p, struct
ip_addr *addr, u16_t port) {
  char str[128];
  // if packet is valid
  if (p != NULL) {
    // WARNING: p can be a chain of buffers (in this example we pretend it
is just a single buffer :)!
    if (p->len < sizeof(str)) {
      memcpy(str, p->payload, p->len);
      str[p->len]=0;
      messageDebug(DBG_WAR, __MODULE__, __LINE__, "UDP Packet Received!
Payload: [%s], port=%i", str, port);
    }
    pbuf_free(p);
  }
}

//---------------------------------------------------------------------------------------
// Thread that sends UDP message every 1000 to 2000 mSec
//---------------------------------------------------------------------------------------
void thRawUDP(void) {
  extern struct netif ppp_netif;
 
    err_t error;
    ip_addr_t ip_remote;
 
    struct udp_pcb *pUDPPCB;
    struct pbuf  *pBuf;
    char data[] = "Hello world";
 
  setNameRTXMON(__FUNCTION__);

  // wait for netif to come up (a little dirty)
  messageDebug(DBG_WAR, __MODULE__, __LINE__, "Waiting for PPP Netif to come
up..");
  while (netif_is_link_up(&ppp_netif)==0)  OS_WAIT(1000);
  messageDebug(DBG_WAR, __MODULE__, __LINE__, "PPP Netif is up");
 
  // Convert from ASCII "xxx.xxx.xxx.xxx" to IP
  ipaddr_aton(SERVER_IP_ADDR, &ip_remote);

  // Lock the stack..
  LOCK_TCPIP_CORE();
    pUDPPCB = udp_new();
    // Bind to any local port
    error = udp_bind(pUDPPCB, IP_ADDR_ANY, 0);
    messageDebug(DBG_WAR, __MODULE__, __LINE__, "udp_bind=%i", error);

    error = udp_connect(pUDPPCB, &ip_remote, SERVER_PORT_NUM);
    messageDebug(DBG_WAR, __MODULE__, __LINE__, "udp_connect=%i", error);

    udp_recv(pUDPPCB, rxUDP, NULL);
  UNLOCK_TCPIP_CORE();  


  while (1) {
    // Allocate pbuf (might end up being a chain of buffers!)
    pBuf = pbuf_alloc(PBUF_TRANSPORT, sizeof(data), PBUF_POOL);
    if (!pBuf) {
      messageDebug(DBG_ERR, __MODULE__, __LINE__, "error allocating
buffer");
      OS_WAIT(1000);
      continue;
    }

    // The pBuf we get can be a chain of buffers
    int bytesLeft = sizeof(data); // Number of bytes we still need to move
to buffer(s)  
    struct pbuf *packetTempBuffer; // used to traverse the (possible) list
of buffers
    int chunk; // NUmber of bytes we copy to the current buffer
    int index = 0;  // Index into the source buffer
   
    packetTempBuffer = pBuf;  
    while ( (bytesLeft) && (packetTempBuffer != NULL) )  {  

      chunk = bytesLeft;  
      if ( chunk > packetTempBuffer->len ) {  
        chunk = packetTempBuffer->len;  
      }  

      // copy one part  
      memcpy(packetTempBuffer->payload, &data[index], chunk);  

      // next buffer in chain (if any)  
      packetTempBuffer = packetTempBuffer->next;  

      bytesLeft -= chunk;  
      index += chunk;  
    };      
   
    //memcpy(pBuf->payload, data, sizeof(data)); // WARNING: No gurantee
that pbuf is not multiple buffers in order to hold the data!
   
    messageDebug(DBG_WAR, __MODULE__, __LINE__,"Sending");

    // Lock stack
    LOCK_TCPIP_CORE();
      udp_send(pUDPPCB, pBuf);
    UNLOCK_TCPIP_CORE();  
   
    pbuf_free(pBuf);
   
    OS_WAIT(1000+(rand()%1000));
  }
}




--
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: UDP and Raw API, lwip running with RTOS

goldsimon@gmx.de
zulu4711 wrote:
> Simon,
> Sorry for that !
> My "everyday" reading of lwip topics is done on nabble, hence I did the
> question there.

There's no problem in using nabble, you just have to make sure the result
is readable by everyone reading the list, not only by nabble users.
If you want a response, that is... ;-)

> Anyway, here is the original question, Hope it is readable now.

Yes, it is readable now.

I think your example looks correct. You might want to try the new hook
LWIP_ASSERT_CORE_LOCKED() that checks for correct threading (added with
2.1.0).


Simon

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

Re: UDP and Raw API, lwip running with RTOS

zulu4711
Thanks Simon,
I will try LWIP_ASSERT_CORE_LOCKED()  also (good idea!). This also forces me
to upgrade to 2.1.0 (running at 2.0.3 at the moment)




--
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