webport.c
来自「针对AVR单片机开发的嵌入式操作系统」· C语言 代码 · 共 448 行
C
448 行
/*
* Copyright (C) 2002-2005 by egnite Software GmbH. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holders nor the names of
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY EGNITE SOFTWARE GMBH AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL EGNITE
* SOFTWARE GMBH OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
* THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* For additional information see http://www.ethernut.de/
*/
/*
* $Log$
*/
/*!
* \file webport.c
* \brief Main routines.
*/
/*!
* \addtogroup xgWPDefs
*/
/*@{*/
/*!
* \brief Hard coded MAC address.
*
* The MAC address is used in case the system starts without any
* previously configuration stored in non-volatile memory.
* Typically the non-volatile memory is preloaded by some other
* software, like Basemon. On ATmega128 boards, the 'preserve EEPROM'
* flag should have been set to avoid clearing the EEPROM when the
* part is erased during the upload of a new application.
*/
#define MYMAC 0x00, 0x06, 0x98, 0x00, 0x10, 0x00
/*!
* \brief Hard coded IP address.
*
* The IP address and network mask are used in
* the same case and when there is no DHCP server available in your
* LAN.
*
*/
#define MYIP "192.168.192.100"
/*!
* \brief Hard coded IP mask.
*/
#define MYMASK "255.255.255.0"
/*@}*/
/*
* Some standard C library headers.
*/
#include <string.h>
#include <stdio.h>
#include <io.h>
/*
* Include the proper header file related to our Ethernet hardware.
* Ethernut 1.3 and Charon II use the 10 MBit Realtek RTL8019AS, while
* Ethernut 2 is equipped with the 10/100 MBit LAN91C111, manufactured
* by SMSC.
*/
#ifdef ETHERNUT2
#include <dev/lanc111.h>
#else
#include <dev/nicrtl.h>
#endif
/*
* UROM is a most simple file system to be used for storing web
* contents.
*/
#include <dev/urom.h>
/*
* More Nut/OS header files.
*/
#include <sys/version.h>
#include <sys/confnet.h>
#include <sys/heap.h>
#include <sys/timer.h>
#include <sys/thread.h>
#include <sys/socket.h>
/*
* Basic internet functions.
*/
#include <arpa/inet.h>
/*
* Beside simple TCP/IP routines, Nut/Net offers some higher
* level protocol libraries. We make use of the DHCP client
* and the HTTP helper routines.
*/
#include <pro/dhcp.h>
#include <pro/httpd.h>
#include "webport.h"
/*
* We optionally use an UART for debug output.
*/
#ifdef WP_STATUSOUT
#include <dev/debug.h>
#endif
/*
* For debugging purposes, several routines are available to
* display the thread list, trace TCP packets etc. However,
* this requires to recompile and relink the system with
* NUTDEBUG defined in the compile options.
*/
#ifdef NUTDEBUG
#include <sys/osdebug.h>
#include <net/netdebug.h>
#endif
/*!
* \addtogroup xgWebPort
*/
/*@{*/
/*!
* \brief CPU reset macro.
*
* Start all over on fatal initialization errors.
*
* \note This function currently works on AVR systems only. On other
* architectures an endless loop will be entered.
*/
#if defined(__AVR_ATmega103__) || defined(__AVR_ATmega128__)
#define JUMP_RESET { asm("cli"); asm("call 0"); }
#else
#define JUMP_RESET for(;;)
#endif
/*!
* \brief Process a single HTTP request.
*
* This routine performs the whole cycle of a HTTP request.
*
* - Creating a socket.
* - Listening on the defined port.
* - Processing the request.
* - Closing the socket.
*/
void Service(void)
{
TCPSOCKET *sock; /* TCP socket pointer. */
FILE *stream; /* TCP stream. */
u_long to = 5000;
/*
* Let the Nut/OS library create a TCP socket for us.
*/
if ((sock = NutTcpCreateSocket()) != 0) {
NutTcpSetSockOpt(sock, SO_RCVTIMEO, &to, sizeof(to));
/*
* Listen on the port defined in webport.h. Typically this is
* port 80.
*/
if (NutTcpAccept(sock, HTTP_PORT) == 0) {
/*
* The Nut/OS memory manager dynamically allocates and
* releases SRAM space. In this application most memory is
* used by incoming telegrams and the socket interface. If
* the available space becomes low, we sleep for 200
* milliseconds and try again. This way we will always leave
* some RAM for more important parts of the system.
*
* The watermark is defined in webport.h.
*/
while (NutHeapAvailable() < LOW_MEM_MARK) {
NutSleep(200);
}
/*
* Create a stream from the socket, so we can use stdio.
*/
if ((stream = _fdopen((int) sock, "r+b")) != 0) {
/*
* Process HTTP request. This routine is part of the
* Nut/OS libraries and greatly simplifies our application
* code. It will automatically read requested files from
* the file system and send them to the browser or
* call the proper CGI routines.
*/
NutHttpProcessRequest(stream);
/*
* Close the stream to release its resources.
*/
fclose(stream);
}
}
/*
* Close the socket. If the client didn't close the connection yet,
* it will now be forced to do so.
*/
NutTcpCloseSocket(sock);
}
}
/*! \fn ServiceThread(void *arg)
* \brief Background thread to process HTTP requests.
*
* This thread calls Service() in an endless loop. It can be started more
* than once to support parallel connections.
*/
THREAD(ServiceThread, arg)
{
/*
* Loop endless for connections.
*/
for (;;) {
Service();
}
}
/*!
* \brief Main entry of our application.
*
* Nut/OS automatically calls this entry after initialization.
*
* This routine will do all required initialization, start some
* background threads and then process incoming HTTP requests together
* with the concurrently running background threads.
*/
int main(void)
{
u_char i;
/*
* We may optionally use the serial port for debugging output.
*/
#if defined(WP_STATUSOUT) || defined(NUTDEBUG)
u_long baud = 115200;
/*
* All Nut/OS devices must be registered. This serves two purposes.
* First, it will create a reference to the device driver code, so
* this is linked to the application code. Second, it will initialze
* the hardware.
*
* Nut/OS offers several device drivers for RS232 communication. The
* device devDebug0 is prefered for debug output, because it is not
* only simple, small and fast, but can also used to create output
* from within interrupt routines.
*/
NutRegisterDevice(&devDebug0, 0, 0);
/*
* Now, after the device is registered, it is known to the system
* by its name. We can use a standard C library routine to open it
* as our standard output.
*/
freopen(WP_STATUSOUT, "w", stdout);
/*
* Nut/OS uses _ioctl() to set device specific parameters, like
* the baudrate for serial communication.
*/
_ioctl(_fileno(stdout), UART_SETSPEED, &baud);
/*
* Now we can use the devDebug0 device for standard output. Let's
* print a banner including the Nut/OS version we are running.
*/
printf("\n\nNut/OS %s Webport Daemon\n", NutVersionString());
/*
* If the Nut/OS libraries had been compiled and linked with
* NUTDEBUG defined, we can switch on additional trace output.
*/
#ifdef NUTDEBUG
NutTraceTcp(stdout, 0);
NutTraceOs(stdout, 0);
NutTraceHeap(stdout, 0);
#endif
/*
* During debugging, some delay during startup is quite helpful.
*/
NutSleep(2000);
#endif
/*
* Register the Ethernet controller. Nut/OS supports different
* controllers. We use DEV_ETHER here, which should have been
* defined in one of the include files, which fits our real hardware.
*/
if (NutRegisterDevice(&DEV_ETHER, 0x8300, 5)) {
#ifdef WP_STATUSOUT
puts("Registering NIC failed");
#endif
}
/*
* LAN configuration using values in non-volatile memory or
* DHCP/ARP. We are ready to wait upto 15 seconds for a
* response from the DHCP server. If it fails, use hardcoded
* values.
*
* The whole process is done in three steps.
*
* 1. Call NutDhcpIfConfig() without specifying a MAC address
* will try read all values from non-volatile memory. If
* there are no values available, it will immediately
* return an error.
*
* 2. If step 1 fails, call NutDhcpIfConfig() with a hard coded
* MAC address. The routine will use this MAC address to query
* a DHCP server for its IP configuration. If it succeeds, the
* MAC address and the values received from DHCP will be
* stored in non-volatile memory and used in step 1 during the
* next reboot. Otherwise the call will return an error.
*
* 3. If step 2 fails, call NutNetIfConfig() with hard coded
* MAC address and IP configuration. This fixed values will
* be stored in non-volatile memory and on the next reboot,
* these values will be used in step 1.
*
* Note, that DHCP is only used, if the network configuration
* stored in non-volatile memory doesn't contain a fixed IP
* address. If a fixed value is used once, Nut/OS will store
* it in non-volatile memory and never use DHCP unless this
* fixed values are removed from volatile memory again.
*/
#ifdef WP_STATUSOUT
printf("\nTry stored configuration...");
#endif
if (NutDhcpIfConfig("eth0", 0, 10000)) {
u_char mac[] = { MYMAC };
#ifdef WP_STATUSOUT
printf("failed\nTry DHCP...");
#endif
if (NutDhcpIfConfig("eth0", mac, 10000)) {
#ifdef WP_STATUSOUT
printf("failed\nUse fixed configuration...");
#endif
if (NutNetIfConfig("eth0", mac, inet_addr(MYIP), inet_addr(MYMASK))) {
#ifdef WP_STATUSOUT
puts("failed\nWhere is the NIC?");
#endif
JUMP_RESET;
}
/* If not in a local network, we must also call
NutIpRouteAdd() to configure the routing. */
}
}
#ifdef WP_STATUSOUT
puts("OK");
if (confnet.cdn_cip_addr)
printf("IP addr: %s\n", inet_ntoa(confnet.cdn_cip_addr));
else
printf("IP addr: %s\n", inet_ntoa(confnet.cdn_ip_addr));
printf("IP mask: %s\n", inet_ntoa(confnet.cdn_ip_mask));
printf("IP gate: %s\n", inet_ntoa(confnet.cdn_gateway));
#endif
/*
* Register our device for the file system. If we intend to use
* another file system, we need to register it by calling
* NutRegisterHttpRoot(). If none is registered, the UROM
* file system will be used by default.
*/
NutRegisterDevice(&devUrom, 0, 0);
/*
* Register our CGI routines. This is required to inform the
* HTTP helper routines, which corresponding routine has to
* be called.
*/
if (NutRegisterCgi(PORT_CONTROL_CGI, CpuPortControl))
JUMP_RESET;
if (NutRegisterCgi(PORT_STATUS_CGI, CpuPortStatus))
JUMP_RESET;
if (NutRegisterCgi(RELAY_CONTROL_CGI, SpiRelayControl))
JUMP_RESET;
if (NutRegisterCgi(OPTO_STATUS_CGI, SpiOptoStatus))
JUMP_RESET;
if (NutRegisterCgi(CHARON_CONTROL_CGI, CharonLedControl))
JUMP_RESET;
if (NutRegisterCgi(CHARON_STATUS_CGI, CharonSwitchStatus))
JUMP_RESET;
/*
* Start a defined number of concurrent background threads. The more
* threads we have running, the more connections we can handle
* concurrently. However, each thread occupies some additional RAM.
*/
for (i = 0; i < NUM_HTTP_THREADS - 1; i++) {
/*
* Not really required here, but we give each thread a unique
* name.
*/
char *thname = "httpd0";
thname[5] = '0' + i;
NutThreadCreate(thname, ServiceThread, 0, HTTP_THREAD_STACK);
}
/*
* Finally we use the main thread too for handling HTTP request.
* There's nothing else we can do.
*/
for (;;) {
Service();
}
/*
* This point is never reached. Nut/OS applications are started
* once and continue running forever.
*/
}
/*@}*/
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?