lwip-users
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [lwip-users] using differnet protocols parallel


From: Çağlar AKYÜZ
Subject: Re: [lwip-users] using differnet protocols parallel
Date: Fri, 23 Feb 2007 15:32:15 +0200
User-agent: Mozilla Thunderbird 1.5.0.9 (Windows/20061207)

Marcel M. wrote:
I'm not sure to what extent lwIP has been integrated
into freertos - this may have been done for you already at the sockets
layer, assuming that is the API you wish to use.
Is there someone else here using freertos with lwIP who can provide more
concrete information on its capabilities?

Kieran

LWiP is pretty well ported to FreeRTOS. I'm using LWiP+FreeRTOS
combination very happly on a SAM7X.(altough you haven't
mentioned your arch, I think it should be okay for any arch which is
supported by FreeRTOS)

As long as I can see from the code, in FreeRTOS there is only one task
using the stack all the time. All other tasks communicate with this LWiP
task. In conclusion,
LWiP+FreeRTOS is capable of doing what you need.

Regards
Caglar AKYUZ


Thanks for your answers.
It seems that i have to use a STR912F44 µC with ethernet ans Memory
onchip(not 100% sure). I saw the lwIP examples with freertos too, but they
uses only one connection (port 80). Can i bind more than one port in the
lwip-stack-thread to run different protocols at the same time? Or can i bind
Ports in different threads?

Both options can be possible. You can dedicate each connection a task, or use one task for all. I think you are in phase of comparing uC to FreeRTOS for your application. I see that FreeRTOS STR912 port uses uIP(not LWiP). This may cause some problems
because you have to provide your sys_arch implementation in this case.

 Did Anyone of you implement this and can show me
a little example?

I used only LWiP raw and netconn_api layers. But I don't think implementing a telnet server or a PPP connection would be too confusing. I'm succesfully binding 2 ports and using connections at the same time,I think you can do more easily. I'm attaching how I accomplish these tasks in my
FreeRTOS SAM7X port. I simplified a bit for the sake of illustration.

Regards

Kind Regards,
Caglar AKYUZ

/* This file includes ethernet task and its related functions. Please refer to 
 * the header file for description of functions. 
 */
 
/* Standard includes. */
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

/* Scheduler includes. */
#include "FreeRTOS.h"
#include "task.h"
#include "semphr.h"

/* Demo includes. */
#include "SAM7_EMAC.h"

/* lwIP includes. */
#include "lwip/api.h" 
#include "lwip/tcpip.h"
#include "lwip/memp.h" 
#include "lwip/stats.h"
#include "netif/loopif.h"
#include "pio.h"
#include "mac_tasks.h"
#include "adc.h"
#include "spi.h"
#include "ADS1258.h"
#include "EMflash.h"


/* comm_open is used to hold the state of connection. When we are connected it
 * becomes 1. Then it is used to control the state of connection. If it is less
 * than 1 we don't send any data from ethernet. 
 */
static unsigned char comm_open;

/* config_mode is used to control the configuration mode of the device
 * from ethernet connection.
 */
static char config_mode = 0;
void adc_monitor_via_UDP( void *pvParameters )
{               
        /* MAC related variables */
        struct ip_addr my_ip_addr, my_net_mask, my_gateway;
        extern err_t ethernetif_init( struct netif *netif );
        static struct netif emac_if;
        /* UDP transfer variables */
        struct netconn *listen_pc;
        struct netbuf *buf;
        struct ip_addr addr;
                        
        /* Parameters are not used - suppress compiler error. */
        ( void ) pvParameters;  
                                        
        /* Create a binary semaphore to use common data buffer with spi 
         * This semaphore is taken from ISR when the buffer is filled 
         */
        vSemaphoreCreateBinary( spi_buffer_semaphore );
        if( spi_buffer_semaphore == NULL ) { 
                while( true )
                        pio_set_led( 0 , 0 ); 
        }       
        /* No communication avaliable in the beginning */
        comm_open = 0 ;
                
        /* Note that interface is already configured in the TCP task */ 
                        
        /* create a new UDP connection */
        listen_pc = netconn_new( NETCONN_UDP );
        
        /* set up the IP address of the remote host. This is one is 192.168.2.7 
*/       
        addr.addr = htonl(SETTINGS_PAGE[PC_IP]);
        
        /* connect the connection to the remote host */ 
        netconn_connect(listen_pc, &addr, SETTINGS_PAGE[PC_PORT] );
        
        /* Make datagram_recved callback function and bind to the local port */ 
        
        udp_recv( listen_pc->pcb.udp, datagram_recved, NULL );
        netconn_bind( listen_pc , NULL , SETTINGS_PAGE[LOCAL_PORT] );           
        
        /* create a new netbuf. This buffer is for referencing ethernet data. */
        buf = netbuf_new();     
        comm_open = 1;
        
        /* Loop forever */      
        for( ;; ) {             
                if( xSemaphoreTake( spi_buffer_semaphore, ( portTickType ) 
0xFFFF ) == pdTRUE ) {
                        if( comm_open > 1 ) {                                   
                                        
                                /* Reference the request data into net_buf */   
                        
                                netbuf_ref( buf , (int *)filter() , 
DATA_FRAGMENT_LENGTH );
                                //netbuf_ref( buf , (int *)mac_ptr , 
DATA_FRAGMENT_LENGTH );
                                /* Then send the datagram */            
                                netconn_send( listen_pc , buf );                
                                                
                        }                                                       
                } 
        }
}
void datagram_recved(void *arg, struct udp_pcb *pcb, struct pbuf *p, struct 
ip_addr *addr, u16_t port) 
{
        static int settings[SETTINGS_LENGTH];   
        
        /* Supress compiler warnings */
        ( void ) arg;
        ( void ) addr;
        ( void ) port;  
        
        /* If we are entered config mode before then this should be a config 
command.
         * Otherwise, process the datagram
         */
        if( config_mode ) {
                configure_device( &settings[0] , pcb , p );             
        } else {                
                process_message( &settings[0] , pcb , p );                      
                                                                                
                                                                                
                                        
        }       
        
        /* Don't forget to free buffer */               
        pbuf_free(p);   
}
inline void send_message(char *mes , struct udp_pcb *pcb) 
{
        char *ans;
        struct pbuf *res;               
         
        res = pbuf_alloc(PBUF_TRANSPORT, strlen(mes) , PBUF_RAM);
        
        if(res == NULL) 
                return;
        /* payload pointer should contain the actual data to send.  */  
        ans = (char *)res->payload;     
        strncpy( ans , mes , strlen(mes) );     
        udp_send(pcb, res);             
        pbuf_free(res);
}
inline void send_block(int *block , short length , struct udp_pcb *pcb) 
{
        struct pbuf *res;               
        int *ans; 
        res = pbuf_alloc(PBUF_TRANSPORT, sizeof(int)*length , PBUF_RAM);
        
        if(res == NULL) 
                return;
        
        /* payload pointer should contain the actual data to send.  */  
        ans = (int *)res->payload;
        /* length is not in bytes but in number of items. */    
        memcpy( ans , block , length * sizeof(int));    
        udp_send(pcb, res);             
        pbuf_free(res);
}
/* This file includes ethernet task and its related functions. Please refer to 
 * the header file for description of functions. 
 */
 
/* Standard includes. */
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

/* Scheduler includes. */
#include "FreeRTOS.h"
#include "task.h"
#include "semphr.h"

/* Demo includes. */
#include "SAM7_EMAC.h"

/* lwIP includes. */
#include "lwip/api.h" 
#include "lwip/tcpip.h"
#include "lwip/memp.h" 
#include "lwip/stats.h"
#include "netif/loopif.h"
#include "pio.h"
#include "mac_tasks.h"
#include "adc.h"
#include "spi.h"
#include "ADS1258.h"
#include "EMflash.h"

static struct tcp_pcb *netio_pcb;
/* comm_open is used to hold the state of connection. When we are connected it
 * becomes 1. Then it is used to control the state of connection. If it is less
 * than 1 we don't send any data from ethernet. 
 */
static unsigned char comm_open;

/* config_mode is used to control the configuration mode of the device
 * from ethernet connection.
 */
static char config_mode = 0;

void adc_monitor_via_TCP( void *pvParameters )
{       
        /* MAC related variables */
        struct ip_addr my_ip_addr, my_net_mask, my_gateway;
        extern err_t ethernetif_init( struct netif *netif );
        static struct netif emac_if;
                        
        /* Parameters are not used - suppress compiler error. */
        ( void ) pvParameters;  
                                        
        /* Create a binary semaphore to use common data buffer with spi 
         * This semaphore is taken from ISR when the buffer is filled 
         */
        vSemaphoreCreateBinary( spi_buffer_semaphore );
        if( spi_buffer_semaphore == NULL ) { 
                while( true )
                        pio_set_led( 0 , 0 ); 
        }       
        /* No communication avaliable in the beginning */
        comm_open = 0 ;
                
        /* Create and configure the EMAC interface. */
        
        IP4_ADDR(&my_ip_addr,(SETTINGS_PAGE[LOCAL_IP] & 0xFF000000) >> 24 \
                                                ,(SETTINGS_PAGE[LOCAL_IP] & 
0x00FF0000) >> 16 \
                                                ,(SETTINGS_PAGE[LOCAL_IP] & 
0x0000FF00) >> 8 \
                                                ,(SETTINGS_PAGE[LOCAL_IP] & 
0x000000FF) >> 0);
        
        IP4_ADDR(&my_net_mask,(SETTINGS_PAGE[NETMASK] & 0xFF000000) >> 24 \
                                                 ,(SETTINGS_PAGE[NETMASK] & 
0x00FF0000) >> 16 \
                                                 ,(SETTINGS_PAGE[NETMASK] & 
0x0000FF00) >> 8 \
                                                 ,(SETTINGS_PAGE[NETMASK] & 
0x000000FF) >> 0);  
        
IP4_ADDR(&my_gateway,emacGATEWAY_ADDR0,emacGATEWAY_ADDR1,emacGATEWAY_ADDR2,emacGATEWAY_ADDR3);
  
        netif_add(&emac_if, &my_ip_addr, &my_net_mask, &my_gateway, NULL, 
ethernetif_init, tcpip_input);
                        
        /* make it the default interface */
    netif_set_default(&emac_if);

        /* bring it up */
    netif_set_up(&emac_if);
    
    /* We are using then raw api of LWiP for tcp connections. You can refer to 
     * netio_ functions at the end. All listening,accepting,receiving events
     * handled using callback functions. We are initializing the sequence using
     * netio_init then stack directs us when a event occurs
     */  
        netio_init();
        /* No sending until we receive a "send" command */    
    comm_open = 1;
        for( ;; )
        {
                if( xSemaphoreTake( spi_buffer_semaphore, ( portTickType ) 
0xFFFF ) == pdTRUE ) {
                        if( comm_open > 1 ) {
                                /* The trick for increasing TCP performance is 
calling tcp_output
                                 * function after tcp_write provided that 
windows,send buffers are
                                 * big enough.
                                 */ 
                                if(tcp_write(netio_pcb, (int *)filter(), 
DATA_FRAGMENT_LENGTH, 0) == ERR_OK) {
                                        pio_toggle_led( 1 );
                                        tcp_output(netio_pcb);
                                }                                               
                
                        }                                                       
                } 
        }
}

err_t netio_recv(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err)
{
        /* This callback function is called when stack receives data from the 
MAC
         * interface(on our port of course). Then we can process this message
         */  
        static int settings[SETTINGS_LENGTH];
        (void) arg;
        if (err == ERR_OK && p != NULL)
        {
                /* if config_mode is not 0, then we are in configuration mode */
                if( config_mode ) {
                        configure_device_tcp( &settings[0] , pcb , p );         
                } else {
                        /* Process message then if we are not in config mode */
                        process_tcp_message( &settings[0] , pcb , p );          
                                                                                
                                                                                
                                                                
                }
                /* Acknowledge stack that we have processed the message so that 
it can 
                 * inrcrease window size 
                 */
                tcp_recved(pcb, p->tot_len);
                /* Never forget to free a buffer! */
                pbuf_free(p);           
        }
        else
                pbuf_free(p); /* Never forget to free a buffer! */

        if (err == ERR_OK && p == NULL)
        {
                /* If we are here this means that other side has closed the 
connection. */
                tcp_arg(pcb, NULL);
                tcp_sent(pcb, NULL);
                tcp_recv(pcb, NULL);
                tcp_close(pcb);
        }
        return ERR_OK;
}
err_t netio_accept(void *arg, struct tcp_pcb *pcb, err_t err)
{
        /* When there is a connection request this function is called by the 
stack */
        (void) arg;
        (void) err;
        tcp_arg(pcb, NULL);
        tcp_sent(pcb, NULL);
        /* Inform stack about which function to call-back when there is data on 
the line */ 
        tcp_recv(pcb, netio_recv);
        /* Hold the accepted connection pcb. This will used later when we 
desire to send
         * data asynchronously from the receive callback function
         */
        netio_pcb = pcb;
        pio_toggle_led( 0 );
        return ERR_OK;
}

struct tcp_pcb* netio_init(void)
{
        /* This function initalizes the connection. We start listenin on the 
desired port
         * and our defined callback function to be called by the stack when 
someone 
         * arrives
         */ 
        struct tcp_pcb *pcb;
        
        pcb = tcp_new();
        tcp_bind(pcb, IP_ADDR_ANY, SETTINGS_PAGE[LOCAL_PORT]);
        pcb = tcp_listen(pcb);  
        tcp_accept(pcb, netio_accept);
        return pcb;
}

reply via email to

[Prev in Thread] Current Thread [Next in Thread]