Main Page | Modules | Directories | File List | Globals | Related Pages

webport.c

Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2002-2005 by egnite Software GmbH. All rights reserved.
00003  *
00004  * Redistribution and use in source and binary forms, with or without
00005  * modification, are permitted provided that the following conditions
00006  * are met:
00007  *
00008  * 1. Redistributions of source code must retain the above copyright
00009  *    notice, this list of conditions and the following disclaimer.
00010  * 2. Redistributions in binary form must reproduce the above copyright
00011  *    notice, this list of conditions and the following disclaimer in the
00012  *    documentation and/or other materials provided with the distribution.
00013  * 3. Neither the name of the copyright holders nor the names of
00014  *    contributors may be used to endorse or promote products derived
00015  *    from this software without specific prior written permission.
00016  *
00017  * THIS SOFTWARE IS PROVIDED BY EGNITE SOFTWARE GMBH AND CONTRIBUTORS
00018  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
00019  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
00020  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL EGNITE
00021  * SOFTWARE GMBH OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
00022  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
00023  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
00024  * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
00025  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
00026  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
00027  * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
00028  * SUCH DAMAGE.
00029  *
00030  * For additional information see http://www.ethernut.de/
00031  */
00032 
00033 /*
00034  * $Log$
00035  */
00036 
00037 /*!
00038  * \file webport.c
00039  * \brief Main routines.
00040  */
00041 
00042 /*!
00043  * \addtogroup xgWPDefs
00044  */
00045 /*@{*/
00046 
00047 /*!
00048  * \brief Hard coded MAC address.
00049  *
00050  * The MAC address is used in case the system starts without any 
00051  * previously configuration stored in non-volatile memory.
00052  * Typically the non-volatile memory is preloaded by some other
00053  * software, like Basemon. On ATmega128 boards, the 'preserve EEPROM'
00054  * flag should have been set to avoid clearing the EEPROM when the
00055  * part is erased during the upload of a new application.
00056  */
00057 #define MYMAC   0x00, 0x06, 0x98, 0x00, 0x10, 0x00
00058 
00059 /*!
00060  * \brief Hard coded IP address.
00061  *
00062  * The IP address and network mask are used in
00063  * the same case and when there is no DHCP server available in your
00064  * LAN.
00065  *
00066  */
00067 #define MYIP    "192.168.192.100"
00068 
00069 /*!
00070  * \brief Hard coded IP mask.
00071  */
00072 #define MYMASK  "255.255.255.0"
00073 
00074 /*@}*/
00075 
00076 /*
00077  * Some standard C library headers.
00078  */
00079 #include <string.h>
00080 #include <stdio.h>
00081 #include <io.h>
00082 
00083 /*
00084  * Include the proper header file related to our Ethernet hardware.
00085  * Ethernut 1.3 and Charon II use the 10 MBit Realtek RTL8019AS, while 
00086  * Ethernut 2 is equipped with the 10/100 MBit LAN91C111, manufactured 
00087  * by SMSC.
00088  */
00089 #ifdef ETHERNUT2
00090 #include <dev/lanc111.h>
00091 #else
00092 #include <dev/nicrtl.h>
00093 #endif
00094 
00095 
00096 /*
00097  * UROM is a most simple file system to be used for storing web
00098  * contents.
00099  */
00100 #include <dev/urom.h>
00101 
00102 /*
00103  * More Nut/OS header files.
00104  */
00105 #include <sys/version.h>
00106 #include <sys/confnet.h>
00107 #include <sys/heap.h>
00108 #include <sys/timer.h>
00109 #include <sys/thread.h>
00110 #include <sys/socket.h>
00111 
00112 /*
00113  * Basic internet functions.
00114  */
00115 #include <arpa/inet.h>
00116 
00117 /*
00118  * Beside simple TCP/IP routines, Nut/Net offers some higher
00119  * level protocol libraries. We make use of the DHCP client
00120  * and the HTTP helper routines.
00121  */
00122 #include <pro/dhcp.h>
00123 #include <pro/httpd.h>
00124 
00125 
00126 #include "webport.h"
00127 
00128 /*
00129  * We optionally use an UART for debug output.
00130  */
00131 #ifdef WP_STATUSOUT
00132 #include <dev/debug.h>
00133 #endif
00134 
00135 /*
00136  * For debugging purposes, several routines are available to
00137  * display the thread list, trace TCP packets etc. However,
00138  * this requires to recompile and relink the system with
00139  * NUTDEBUG defined in the compile options.
00140  */
00141 #ifdef NUTDEBUG
00142 #include <sys/osdebug.h>
00143 #include <net/netdebug.h>
00144 #endif
00145 
00146 /*!
00147  * \addtogroup xgWebPort
00148  */
00149 /*@{*/
00150 
00151 /*!
00152  * \brief CPU reset macro.
00153  *
00154  * Start all over on fatal initialization errors.
00155  *
00156  * \note This function currently works on AVR systems only. On other 
00157  *       architectures an endless loop will be entered.
00158  */
00159 #if defined(__AVR_ATmega103__) || defined(__AVR_ATmega128__)
00160 #define JUMP_RESET { asm("cli"); asm("call 0"); }
00161 #else
00162 #define JUMP_RESET for(;;)
00163 #endif
00164 
00165 /*!
00166  * \brief Process a single HTTP request.
00167  *
00168  * This routine performs the whole cycle of a HTTP request.
00169  *
00170  * - Creating a socket.
00171  * - Listening on the defined port.
00172  * - Processing the request.
00173  * - Closing the socket.
00174  */
00175 void Service(void)
00176 {
00177     TCPSOCKET *sock;            /* TCP socket pointer. */
00178     FILE *stream;               /* TCP stream. */
00179     u_long to = 5000;
00180 
00181     /*
00182      * Let the Nut/OS library create a TCP socket for us.
00183      */
00184     if ((sock = NutTcpCreateSocket()) != 0) {
00185 
00186         NutTcpSetSockOpt(sock, SO_RCVTIMEO, &to, sizeof(to));
00187 
00188         /*
00189          * Listen on the port defined in webport.h. Typically this is
00190          * port 80.
00191          */
00192         if (NutTcpAccept(sock, HTTP_PORT) == 0) {
00193             /*
00194              * The Nut/OS memory manager dynamically allocates and 
00195              * releases SRAM space. In this application most memory is 
00196              * used by incoming telegrams and the socket interface. If 
00197              * the available space becomes low, we sleep for 200 
00198              * milliseconds and try again. This way we will always leave 
00199              * some RAM for more important parts of the system.
00200              *
00201              * The watermark is defined in webport.h.
00202              */
00203             while (NutHeapAvailable() < LOW_MEM_MARK) {
00204                 NutSleep(200);
00205             }
00206 
00207             /*
00208              * Create a stream from the socket, so we can use stdio.
00209              */
00210             if ((stream = _fdopen((int) sock, "r+b")) != 0) {
00211                 /*
00212                  * Process HTTP request. This routine is part of the
00213                  * Nut/OS libraries and greatly simplifies our application
00214                  * code. It will automatically read requested files from
00215                  * the file system and send them to the browser or
00216                  * call the proper CGI routines.
00217                  */
00218                 NutHttpProcessRequest(stream);
00219 
00220                 /*
00221                  * Close the stream to release its resources.
00222                  */
00223                 fclose(stream);
00224             }
00225         }
00226 
00227         /*
00228          * Close the socket. If the client didn't close the connection yet,
00229          * it will now be forced to do so.
00230          */
00231         NutTcpCloseSocket(sock);
00232     }
00233 }
00234 
00235 /*! \fn ServiceThread(void *arg)
00236  * \brief Background thread to process HTTP requests.
00237  *
00238  * This thread calls Service() in an endless loop. It can be started more
00239  * than once to support parallel connections.
00240  */
00241 THREAD(ServiceThread, arg)
00242 {
00243     /*
00244      * Loop endless for connections.
00245      */
00246     for (;;) {
00247         Service();
00248     }
00249 }
00250 
00251 /*!
00252  * \brief Main entry of our application.
00253  *
00254  * Nut/OS automatically calls this entry after initialization.
00255  * 
00256  * This routine will do all required initialization, start some
00257  * background threads and then process incoming HTTP requests together 
00258  * with the concurrently running background threads.
00259  */
00260 int main(void)
00261 {
00262     u_char i;
00263 
00264     /*
00265      * We may optionally use the serial port for debugging output.
00266      */
00267 #if defined(WP_STATUSOUT) || defined(NUTDEBUG)
00268     u_long baud = 115200;
00269 
00270     /*
00271      * All Nut/OS devices must be registered. This serves two purposes.
00272      * First, it will create a reference to the device driver code, so
00273      * this is linked to the application code. Second, it will initialze
00274      * the hardware.
00275      *
00276      * Nut/OS offers several device drivers for RS232 communication. The 
00277      * device devDebug0 is prefered for debug output, because it is not
00278      * only simple, small and fast, but can also used to create output
00279      * from within interrupt routines.
00280      */
00281     NutRegisterDevice(&devDebug0, 0, 0);
00282 
00283     /*
00284      * Now, after the device is registered, it is known to the system
00285      * by its name. We can use a standard C library routine to open it
00286      * as our standard output.
00287      */
00288     freopen(WP_STATUSOUT, "w", stdout);
00289 
00290     /*
00291      * Nut/OS uses _ioctl() to set device specific parameters, like
00292      * the baudrate for serial communication.
00293      */
00294     _ioctl(_fileno(stdout), UART_SETSPEED, &baud);
00295 
00296     /*
00297      * Now we can use the devDebug0 device for standard output. Let's
00298      * print a banner including the Nut/OS version we are running.
00299      */
00300     printf("\n\nNut/OS %s Webport Daemon\n", NutVersionString());
00301 
00302     /*
00303      * If the Nut/OS libraries had been compiled and linked with
00304      * NUTDEBUG defined, we can switch on additional trace output.
00305      */
00306 #ifdef NUTDEBUG
00307     NutTraceTcp(stdout, 0);
00308     NutTraceOs(stdout, 0);
00309     NutTraceHeap(stdout, 0);
00310 #endif
00311 
00312     /*
00313      * During debugging, some delay during startup is quite helpful.
00314      */
00315     NutSleep(2000);
00316 #endif
00317 
00318     /*
00319      * Register the Ethernet controller. Nut/OS supports different
00320      * controllers. We use DEV_ETHER here, which should have been 
00321      * defined in one of the include files, which fits our real hardware.
00322      */
00323     if (NutRegisterDevice(&DEV_ETHER, 0x8300, 5)) {
00324 #ifdef WP_STATUSOUT
00325         puts("Registering NIC failed");
00326 #endif
00327     }
00328 
00329     /*
00330      * LAN configuration using values in non-volatile memory or 
00331      * DHCP/ARP. We are ready to wait upto 15 seconds for a 
00332      * response from the DHCP server. If it fails, use hardcoded 
00333      * values.
00334      *
00335      * The whole process is done in three steps.
00336      *
00337      * 1. Call NutDhcpIfConfig() without specifying a MAC address
00338      *    will try read all values from non-volatile memory. If
00339      *    there are no values available, it will immediately
00340      *    return an error.
00341      *
00342      * 2. If step 1 fails, call NutDhcpIfConfig() with a hard coded 
00343      *    MAC address. The routine will use this MAC address to query 
00344      *    a DHCP server for its IP configuration. If it succeeds, the 
00345      *    MAC address and the values received from DHCP will be 
00346      *    stored in non-volatile memory and used in step 1 during the
00347      *    next reboot. Otherwise the call will return an error.
00348      *
00349      * 3. If step 2 fails, call NutNetIfConfig() with hard coded
00350      *    MAC address and IP configuration. This fixed values will
00351      *    be stored in non-volatile memory and on the next reboot,
00352      *    these values will be used in step 1.
00353      *
00354      * Note, that DHCP is only used, if the network configuration
00355      * stored in non-volatile memory doesn't contain a fixed IP
00356      * address. If a fixed value is used once, Nut/OS will store
00357      * it in non-volatile memory and never use DHCP unless this
00358      * fixed values are removed from volatile memory again.
00359      */
00360 #ifdef WP_STATUSOUT
00361     printf("\nTry stored configuration...");
00362 #endif
00363     if (NutDhcpIfConfig("eth0", 0, 10000)) {
00364         u_char mac[] = { MYMAC };
00365 #ifdef WP_STATUSOUT
00366         printf("failed\nTry DHCP...");
00367 #endif
00368         if (NutDhcpIfConfig("eth0", mac, 10000)) {
00369 #ifdef WP_STATUSOUT
00370             printf("failed\nUse fixed configuration...");
00371 #endif
00372             if (NutNetIfConfig("eth0", mac, inet_addr(MYIP), inet_addr(MYMASK))) {
00373 #ifdef WP_STATUSOUT
00374                 puts("failed\nWhere is the NIC?");
00375 #endif
00376                 JUMP_RESET;
00377             }
00378             /* If not in a local network, we must also call 
00379                NutIpRouteAdd() to configure the routing. */
00380         }
00381     }
00382 #ifdef WP_STATUSOUT
00383     puts("OK");
00384     if (confnet.cdn_cip_addr)
00385         printf("IP addr: %s\n", inet_ntoa(confnet.cdn_cip_addr));
00386     else
00387         printf("IP addr: %s\n", inet_ntoa(confnet.cdn_ip_addr));
00388     printf("IP mask: %s\n", inet_ntoa(confnet.cdn_ip_mask));
00389     printf("IP gate: %s\n", inet_ntoa(confnet.cdn_gateway));
00390 #endif
00391 
00392     /*
00393      * Register our device for the file system. If we intend to use 
00394      * another file system, we need to register it by calling
00395      * NutRegisterHttpRoot(). If none is registered, the UROM
00396      * file system will be used by default.
00397      */
00398     NutRegisterDevice(&devUrom, 0, 0);
00399 
00400     /*
00401      * Register our CGI routines. This is required to inform the
00402      * HTTP helper routines, which corresponding routine has to
00403      * be called.
00404      */
00405     if (NutRegisterCgi(PORT_CONTROL_CGI, CpuPortControl))
00406         JUMP_RESET;
00407     if (NutRegisterCgi(PORT_STATUS_CGI, CpuPortStatus))
00408         JUMP_RESET;
00409     if (NutRegisterCgi(RELAY_CONTROL_CGI, SpiRelayControl))
00410         JUMP_RESET;
00411     if (NutRegisterCgi(OPTO_STATUS_CGI, SpiOptoStatus))
00412         JUMP_RESET;
00413     if (NutRegisterCgi(CHARON_CONTROL_CGI, CharonLedControl))
00414         JUMP_RESET;
00415     if (NutRegisterCgi(CHARON_STATUS_CGI, CharonSwitchStatus))
00416         JUMP_RESET;
00417 
00418     /*
00419      * Start a defined number of concurrent background threads. The more 
00420      * threads we have running, the more connections we can handle 
00421      * concurrently. However, each thread occupies some additional RAM.
00422      */
00423     for (i = 0; i < NUM_HTTP_THREADS - 1; i++) {
00424         /*
00425          * Not really required here, but we give each thread a unique
00426          * name.
00427          */
00428         char *thname = "httpd0";
00429         thname[5] = '0' + i;
00430         NutThreadCreate(thname, ServiceThread, 0, HTTP_THREAD_STACK);
00431     }
00432 
00433     /*
00434      * Finally we use the main thread too for handling HTTP request.
00435      * There's nothing else we can do.
00436      */
00437     for (;;) {
00438         Service();
00439     }
00440 
00441     /*
00442      * This point is never reached. Nut/OS applications are started
00443      * once and continue running forever.
00444      */
00445 }
00446 
00447 /*@}*/

© 2002-2004 by egnite Software GmbH - visit http://www.ethernut.de/