Elektroda.pl
Elektroda.pl
X
Proszę, dodaj wyjątek www.elektroda.pl do Adblock.
Dzięki temu, że oglądasz reklamy, wspierasz portal i użytkowników.

[AT91SAM7X256][C/FreeRTOS] Serwer www

don diego 30 Wrz 2008 00:17 4178 11
  • #1 30 Wrz 2008 00:17
    don diego
    Poziom 32  

    Witajcie,
    Próbuję zbudować prosty serwer www wykorzystując demo FreeRTOS'a ze stosem lwIP dla AT91SAM7X256 (płytka Olimexu SAM7-EX256) pod CrossStudio.

    Po drobnych modyfikacjach udało mi się za pomocą formularza wysłać dane do serwera (przynajmniej tak mi się wydaje).
    Ale, gdy wyświetlam odebrany bufor na swojej stronie, nie ma na nim danych wysłanych w formularzu. Przy odświeżaniu strony pojawiają się jakieś przypadkowe ciągi znaków z poprzednich transmisji. Długość pola z danymi jest podawana prawidłowo, na przykład

    Cytat:
    Content-Length: 13
    , ale po tym powinny pojawić się dane z formularza.
    Kod webserwera wygląda następująco:
    Code:

    /* Standard includes. */
    #include <stdio.h>
    #include <string.h>

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

    /* Demo includes. */
    #include "BasicWEB.h"
    #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"


    /* The size of the buffer in which the dynamic WEB page is created. */
    #define webMAX_PAGE_SIZE   2048

    /* Standard GET response. */
    #define webHTTP_OK   "HTTP/1.0 200 OK\r\nContent-type: text/html\r\n\r\n"

    /* The port on which we listen. */
    #define webHTTP_PORT      ( 80 )

    /* Delay on close error. */
    #define webSHORT_DELAY      ( 10 )

    /* Format of the dynamic page that is returned on each connection. */
    #define webHTML_START \
    "<html>\
    <head><title>System kontrolno-pomiarowy</title></head>\
    <BODY onLoad=\"\"bgcolor=\"#CCFF00\" text=\"#000000\">\
    \r\nLiczba odwiedzin= "

    #define webHTML_END \
    "\
    \r\n</BODY>\
    </html>"

    /*------------------------------------------------------------*/

    /*
     * Process an incoming connection on port 80.
     *
     * This simply checks to see if the incoming data contains a GET request, and
     * if so sends back a single dynamically created page.  The connection is then
     * closed.  A more complete implementation could create a task for each
     * connection.
     */
    static void vProcessConnection( struct netconn *pxNetCon );

    /*------------------------------------------------------------*/

    static void vProcessConnection( struct netconn *pxNetCon )




    {
    static portCHAR cDynamicPage[ webMAX_PAGE_SIZE ], cPageHits[ 11 ];
    struct netbuf *pxRxBuffer;
    portCHAR *pcRxString;
    unsigned portSHORT usLength;
    static unsigned portLONG ulPageHits = 0;
           
       /* We expect to immediately get data. */
       pxRxBuffer = netconn_recv( pxNetCon );

       if( pxRxBuffer != NULL )
       {
          /* Where is the data? */
          netbuf_data( pxRxBuffer, ( void * ) &pcRxString, &usLength );      
       
          /* Is this a GET? */
          if( !strncmp( pcRxString, "GET", 3 ) )
          {         
                            //pcRxString = cDynamicPage;


             /* Update the hit count. */
             ulPageHits++;
             sprintf( cPageHits, "%lu", ulPageHits );

             /* Write out the HTTP OK header. */
                            netconn_write(pxNetCon, webHTTP_OK, (u16_t)strlen( webHTTP_OK ), NETCONN_COPY );

             /* Generate the dynamic page...

             ... First the page header. */
             strcpy( cDynamicPage, webHTML_START );
             /* ... Then the hit count... */
             strcat( cDynamicPage, cPageHits );
             /* ... Finally the page footer. */
                            strcat( cDynamicPage, "<p>########STRONA TESTOWA FreeRTOS&lwIP##########<br>************************************************<br>" );
                            strcat( cDynamicPage, "\
    <p><fieldset>\
    <legend>Sterowanie diodami</legend>\
    <FORM ACTION=\"index.html\" METHOD=\"post\"><BR>\
    <label><INPUT TYPE=\"checkbox\" NAME=\"LED1\" VALUE=\"1\">LED1</label><BR>\
    <label><INPUT TYPE=\"checkbox\" NAME=\"LED2\" VALUE=\"2\">LED2</label><BR>\
    <label><INPUT TYPE=\"checkbox\" NAME=\"LED3\" VALUE=\"3\">LED3</label><br>\
    <INPUT TYPE=\"submit\" VALUE=\"Update IO\"></FORM></fieldset>" );
                            strcat( cDynamicPage, webHTML_END );

             /* Write out the dynamically generated page. */
             netconn_write(pxNetCon, cDynamicPage, (u16_t)strlen( cDynamicPage ), NETCONN_COPY );
          }
                    else{
                    /* Is this a POST?*/
          if( !strncmp( pcRxString, "POST", 4 ) )
          {
             char *bufor;
                            bufor = pcRxString;
                            pcRxString = cDynamicPage;
                   
             /* Update the hit count. */
             ulPageHits++;
             sprintf( cPageHits, "%lu", ulPageHits );

             /* Write out the HTTP OK header. */
                            netconn_write(pxNetCon, webHTTP_OK, (u16_t)strlen( webHTTP_OK ), NETCONN_COPY );

             /* Generate the dynamic page...

             ... First the page header. */
                            strcpy( cDynamicPage, NULL );
             strcpy( cDynamicPage, webHTML_START );
                            /* ... Then the hit count... */
             strcat( cDynamicPage, cPageHits );
             strcat( cDynamicPage, "<p>########STRONA TESTOWA FreeRTOS&lwIP##########<br>***********************************************<br>" );
                            strcat( cDynamicPage, "<p><FORM ACTION=\"index.html\"METHOD=\"POST\" enctype=\"text/plain\">\
    <label><INPUT TYPE=\"radio\" NAME=\"LED1\" VALUE=\"ON\">LED1 ON   </label><label><INPUT TYPE=\"radio\" NAME=\"LED1\" VALUE=\"OFF\">LED1 OFF</label><BR>\
    <label><INPUT TYPE=\"checkbox\" NAME=\"LED2\" VALUE=\"ON\">LED2</label><br>\
    <INPUT TYPE=\"submit\" VALUE=\"Update IO\"></FORM></p>" );
                      
                      strcat( cDynamicPage, bufor );
             /* ... Finally the page footer. */
                            strcat( cDynamicPage, webHTML_END );
                       
             /* Write out the dynamically generated page. */
             netconn_write(pxNetCon, cDynamicPage, (u16_t)strlen( cDynamicPage ), NETCONN_COPY );
                            bufor = NULL;
                            }
          }
            netbuf_delete( pxRxBuffer );
       }
       netconn_close( pxNetCon );
    }
    /*------------------------------------------------------------*/

    void vlwIPInit( void )
    {
        /* Initialize lwIP and its interface layer. */
       sys_init();
       mem_init();                        
       memp_init();
       pbuf_init();
       netif_init();
       ip_init();
       tcpip_init( NULL, NULL );
    }
    /*------------------------------------------------------------*/

    void vBasicWEBServer( void *pvParameters )
    {
    struct netconn *pxHTTPListener, *pxNewConnection;
    struct ip_addr xIpAddr, xNetMast, xGateway;
    extern err_t ethernetif_init( struct netif *netif );
    static struct netif EMAC_if;

       /* Parameters are not used - suppress compiler error. */
       ( void ) pvParameters;


       /* Create and configure the EMAC interface. */
       IP4_ADDR(&xIpAddr,emacIPADDR0,emacIPADDR1,emacIPADDR2,emacIPADDR3);
       IP4_ADDR(&xNetMast,emacNET_MASK0,emacNET_MASK1,emacNET_MASK2,emacNET_MASK3);
       IP4_ADDR(&xGateway,emacGATEWAY_ADDR0,emacGATEWAY_ADDR1,emacGATEWAY_ADDR2,emacGATEWAY_ADDR3);
       netif_add(&EMAC_if, &xIpAddr, &xNetMast, &xGateway, NULL, ethernetif_init, tcpip_input);

       /* make it the default interface */
        netif_set_default(&EMAC_if);

       /* bring it up */
        netif_set_up(&EMAC_if);
       
       /* Create a new tcp connection handle */

        pxHTTPListener = netconn_new( NETCONN_TCP );
       netconn_bind(pxHTTPListener, NULL, webHTTP_PORT );
       netconn_listen( pxHTTPListener );

       /* Loop forever */
       for( ;; )
       {
          /* Wait for connection. */
          pxNewConnection = netconn_accept(pxHTTPListener);

          if(pxNewConnection != NULL)
          {
             /* Service connection. */
             vProcessConnection( pxNewConnection );
             while( netconn_delete( pxNewConnection ) != ERR_OK )
             {
                vTaskDelay( webSHORT_DELAY );
             }
          }
       }
    }


    Jak powinno wyglądać odbieranie danych z bufora, żeby pojawiły się tam dane wysłane z formularza? Podejrzewam, że to kwestia zdefiniowania zmiennej odpowiedniego typu, albo użycia odpowiedniej funkcji do skopiowania bufora.
    Zdefiniowałem zmienną bufor, do której przepisałem dane.
    Z góry dziękuję za wszelką pomoc.

    Pozdrawiam
    Diego

    Dodano po 1 [godziny] 57 [minuty]:


    EDIT:
    Oryginalnie demo było pod inną płytkę ewaluacyjną. Program jest przystosowany do innego układu PHY: DM9161.
    W płycie Olimexu znajduje się PHY: KS8721.
    W swoim programie zakomentowałem część sprawdzającą PHY ID w pliku SAM7_EMAC.c. Czy może to być przyczyną niewłaściwego działania programu?

    0 11
  • #2 30 Wrz 2008 13:08
    fantom
    Poziom 31  

    Po prostu musisz sparsowac ten bufor z POST-em i odczytac tylko zawartosc danych przeslanych z klienta. Jesli nie ma takich gotowych funkcji w tym przykladzie to musisz ja napisac sam tzn znajdz w buforze string LED1 i zaczynajac od tego sparsuj wyslane dane. Nie widze tu zadnych problemow.

    0
  • #3 30 Wrz 2008 13:14
    Freddie Chopin
    Specjalista - Mikrokontrolery
  • #4 30 Wrz 2008 13:39
    don diego
    Poziom 32  

    Z parsowaniem nie ma problemów, ale po prostu w odebranym buforze nie pojawiają się takie dane jak powinny. Jeśli na przykład wyszukuję w buforze "Content-Length:", to je znajduje, ale jak szukam LED1, to już nie. Nie wiem skąd wynikają te problemy.
    Co dziwniejsze, gdy odpalam stronkę na laptopie łączącym się przez WiFi, to po Content-Length są jakieś dane, ale niepoprawne. Na przykład, gdy odświeżam stronę, to w buforze pojawiają się dane z poprzednich formularzy. Gdy łączę się przez kabel, to pojawia się tylko długość danych w Content-Length, ale nie ma żadnych danych.

    Content-Length: 0 jest prawidłowy, ale nie powinno być wtedy żadnych danych. Tak jakby zostawały gdzieś dane z poprzednich transmisji.

    Dodano po 22 [minuty]:

    Znalazłem potencjalną solucję tutaj; http://www.utasker.com/forum/index.php?topic=161.0
    Sprawdzę wieczorem, czy działa.

    0
  • #5 30 Wrz 2008 13:43
    fantom
    Poziom 31  

    Moze bufor nie jest czyszczony.

    0
  • #6 30 Wrz 2008 13:47
    don diego
    Poziom 32  

    No właśnie tak podejrzewam. Nie jest czyszczony, albo w którymś momencie jest źle definiowana jego długość.

    0
  • Pomocny post
    #7 30 Wrz 2008 13:49
    fantom
    Poziom 31  

    don diego napisał:
    No właśnie tak podejrzewam. Nie jest czyszczony, albo w którymś momencie jest źle definiowana jego długość.


    Tak sobie pomyslalem ze jak robisz strcat (strcpy) to moze ci nie skopiowac wszystkiego bo jak sie natknie na 0 (NULL) to konczy kopiowanie. Moze tu jest pies pogrzebany ? Sprobuj skorzystac z memcpy i length-a.

    0
  • #8 30 Wrz 2008 13:59
    don diego
    Poziom 32  

    Ok, sprawdzę po powrocie z pracy i dam znać.

    Edit:
    Po odebraniu formularza z metodą POST zrobiłem od razu wyświetlanie zawartości bufora i wygląda na to, że dane są tracone już na początku, czyli przy operacji:

    Code:
          netbuf_data( pxRxBuffer, ( void * ) &pcRxString, &usLength);   

    albo przy:
    Code:
    pxRxBuffer = netconn_recv( pxNetCon );

    Próbowałem użyć funkcji memcpy do kopiowania bufora, ale program się wtedy zawiesza.

    Jeśli na początku warunku dla POST dam coś takiego:
    Code:
    if( !strncmp( pcRxString, "POST", 4 ) )
    
                     {
                     pxRxBuffer = netconn_recv( pxNetCon );
                     netbuf_data( pxRxBuffer, ( void * ) &bufor, &usLength );

    to otrzymuję jakby pozostałą część bufora, czyli na przykład LED2=ON itp.
    Wniosek z tego, że najprawdopodobniej funkcja wyłuskująca dane nie działa poprawnie.
    Ma ktoś jakiś pomysł, jak to rozwiązać?

    netbuf_data wygląda tak:
    Code:
    netbuf_data(struct netbuf *buf, void **dataptr, u16_t *len)
    
    {
      if (buf->ptr == NULL) {
        return ERR_BUF;
      }
      *dataptr = buf->ptr->payload;
      *len = buf->ptr->len;
      return ERR_OK;
    }

    0
  • Pomocny post
    #9 01 Paź 2008 08:55
    fantom
    Poziom 31  

    Znalazlem taki oto przyklad stosowania tego stacka:

    Code:

    Void example_function(struct netconn *conn)
    {
    struct netbuf *buf;
    /* receive data until the other host closes
    the connection */
    while((buf = netconn_recv(conn)) != NULL) {
    do_something(buf);
    }
    /* the connection has now been closed by the
    other end, so we close our end */
    netconn_close(conn);
    }


    Na twoim miejscu zainstalowalem bym jakiegos sniffera do ethernetu (np: ethereal-a) i podejrzal traffic z przegladarki. Byc moze dane dane przechodza posegmentowane (jak to TCP ma w zwyczaju) i nie wystarczy odebrac jednej ramki tylko kilka az do zamkniecia polaczenia TCP.

    0
  • #10 01 Paź 2008 09:36
    don diego
    Poziom 32  

    Dzięki. Wieczorem sprawdzę.

    Zainstalowałem sobie program Wireshark i chyba faktycznie dane z formularza są wysyłane w innej ramce, niż reszta.

    Jedna ramka kończy się na Content-Length: <długość danych>, a w kolejnej wysłanej ramce są dane, na przykład LED1=OFF.

    Spróbuję to rozgryźć:)
    ---------------------------------------------------------------------------------------------
    Obszedłem problem używając metody GET w formularzach (podziękowania dla kolegi _Matik_ za podpowiedź), ale jeśli ktoś ma doświadczenie w obsłudze połączeń wielopakietowych i chciałby się nim podzielić, to będę wdzięczny:)
    Teraz dane pojawiają się w pasku adresu i jest to troszkę nieestetyczne.

    0
  • #11 20 Sty 2009 21:03
    don diego
    Poziom 32  

    Witam ponownie.
    Serwer www jako tako działa, teraz chciałbym na drugiej płytce (płytka Olimexu SAM7-EX256) zaimplementować klienta TCP. Czy ktoś może posiada procedury realizujące taką funkcję na stosie lwIP? Jak powinno wyglądać prawidłowe nawiązywanie połączenia?
    Modyfikuję serwer z przykładów FreeRTOS'a. Moja funkcja wygląda następująco (używam CrossWorksa):

    Code:
    void vlwIPInit( void )
    
    {
        /* Initialize lwIP and its interface layer. */
       sys_init();
       mem_init();                        
       memp_init();
       pbuf_init();
       netif_init();
       ip_init();
       tcpip_init( NULL, NULL );
    }
    /*------------------------------------------------------------*/

    void vBasicWEBServer( void *pvParameters )
    {
    struct netconn *pxHTTPSender, *pxNewConnection;
    struct ip_addr xIpAddr,xHostIpAddr, xNetMast, xGateway;
    extern err_t ethernetif_init( struct netif *netif );
    static struct netif EMAC_if;
    char getText[]="GET /menu/menu?LED1=OFF HTTP/1.1\r\nHost: 192.168.1.133\r\nUser-Agent: Mozilla/5.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322; .NET CLR 1.0.3705)\r\n Host: http://192.168.1.133/menu\r\nConnection: Keep-Alive\r\n\r\n";
    //zamiast gettext char query[] = "Rzadanie strony www";

       /* Parameters are not used - suppress compiler error. */
       ( void ) pvParameters;


       /* Create and configure the EMAC interface. */
       IP4_ADDR(&xIpAddr,emacIPADDR0,emacIPADDR1,emacIPADDR2,emacIPADDR3);
       IP4_ADDR(&xNetMast,emacNET_MASK0,emacNET_MASK1,emacNET_MASK2,emacNET_MASK3);
       IP4_ADDR(&xGateway,emacGATEWAY_ADDR0,emacGATEWAY_ADDR1,emacGATEWAY_ADDR2,emacGATEWAY_ADDR3);
       netif_add(&EMAC_if, &xIpAddr, &xNetMast, &xGateway, NULL, ethernetif_init, tcpip_input);

            IP4_ADDR(&xHostIpAddr,192,168,1,133);

       /* make it the default interface */
        netif_set_default(&EMAC_if);

       /* bring it up */
        netif_set_up(&EMAC_if);
       
       /* Create a new tcp connection handle */

        pxHTTPSender = netconn_new( NETCONN_TCP );
       netconn_bind(pxHTTPSender, NULL, webHTTP_PORT );
            netconn_connect(pxHTTPSender, &xHostIpAddr, webHTTP_PORT );

            netconn_write(pxHTTPSender, getText, sizeof(getText), NETCONN_NOCOPY);
            struct netbuf *buf;
            /* receive data until the other host closes
            the connection */
            while((buf = netconn_recv(pxHTTPSender)) != NULL) {
            //do_something(buf);
            LCDPutStr( buf, 32, 10, LARGE, BLACK, RED); //wyswietlanie
            }
            /* the connection has now been closed by the
            other end, so we close our end */
            netconn_close(pxHTTPSender);
    }

    Czy sam sposób postępowania jest odpowiedni? 192.168.1.133 to adres mojego serwera w sieci lokalnej.

    EDIT:
    Trochę zmieniłem funkcję na podstawie manuala do lwIP, ale nadal nie ma żadnej reakcji. Będę wdzięczny za jakąś podpowiedź.

    Pozdrawiam
    don diego

    0
  • #12 01 Lut 2009 00:29
    don diego
    Poziom 32  

    Problem pozostał nierozwiązany, ale z powodu obronienia pracy musiałem oddać wszystkie zabawki z ARMami:)

    Pozdro

    0