⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 httpserv.c

📁 qt91上实现的mp3播放机,支持sam9260,参考用
💻 C
字号:
/*
 * Copyright (C) 2001-2007 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/
 *
 */

/*!
 * \file httpserv.c
 * \brief HTTP interface.
 *
 * \verbatim
 *
 * $Log$
 *
 * \endverbatim
 */

#ifndef MY_FSDEV
#define MY_FSDEV        devUrom
#endif

#ifdef MY_FSDEV_NAME
#define MY_HTTPROOT     MY_FSDEV_NAME ":/" 
#endif

#include <cfg/os.h>
#include <cfg/memory.h>

#include <stdlib.h>
#include <string.h>
#include <io.h>
#include <fcntl.h>
#include <time.h>

#include <dev/board.h>
#include <dev/urom.h>

#include <sys/thread.h>
#include <sys/timer.h>
#include <sys/heap.h>
#include <sys/socket.h>

#include <pro/httpd.h>

#include "tlv320dac.h"
#include "httpserv.h"

#ifndef HTTPD_THREAD_STACK
#define HTTPD_THREAD_STACK  2048
#endif

#ifdef USE_HTTPSERVER

/*! \brief Dummy gain.
 *
 * Used to determine volume field that had been left empty.
 * We can't use zero.
 */
#define EMPTY_GAIN  999

extern void *__heap_start;
extern void *__etext;

int h_timevalid; 

static char *html_mt = "text/html";

/*!
 * \brief Radio Info CGI.
 *
 * Dynamically creates a page that displays our current status.
 * It will be automatically refreshed every 10 seconds. Thus, 
 * let's keep it simple
 */
static int CgiInfo(FILE * stream, REQUEST * req)
{
    /* These useful API calls create a HTTP response for us. */
    NutHttpSendHeaderTop(stream, req, 200, "Ok");
    NutHttpSendHeaderBot(stream, html_mt, -1);

    /* Send HTML header. */
    fputs("<HTML><HEAD><TITLE>Internet Radio Information</TITLE>" /* */
          "<meta http-equiv=\"refresh\" content=\"10; URL=info.cgi\">" /* */
          "</HEAD><BODY>\r\n" /* */
          "<h1>Internet Radio Status</h1>" /* */
          , stream);

    /* If we received date and time from a time server, display it. */
    if (h_timevalid) {
        time_t now = time(0);
        struct _tm *lot = localtime(&now);
        fprintf(stream, "Date = %02u.%02u.%u<br>\r\n", lot->tm_mday, lot->tm_mon + 1, 1900 + lot->tm_year);
        fprintf(stream, "Time = %02u:%02u:%02u<br>\r\n", lot->tm_hour, lot->tm_min, lot->tm_sec);
    }
    /* Display our clock settings. */
    fprintf(stream, "<br>CPU Clock = %lu kHz<br>\r\n", NutGetCpuClock() / 1000);
    fprintf(stream, "Master Clock = %lu kHz<br>\r\n", At91GetMasterClock() / 1000);
    /* Display our memory usage. */
    fprintf(stream, "<br>Code size incl. Web Content = %u kBytes<br>\r\n", ((u_int)(&__etext) - NUTMEM_START) / 1024);
    fprintf(stream, "Static data size = %u kBytes<br>\r\n", (u_int)(&__heap_start - &__etext) / 1024);
    fprintf(stream, "Total memory used = %u kBytes<br>\r\n", (u_int)(NUTMEM_SIZE - NutHeapAvailable()) / 1024);
    fflush(stream);

    if (radio.rc_sip == NULL) {
        fputs("<br><br><b>No station connected<br>\r\n", stream);
    }
    else {
        fprintf(stream, "<h2>Radio Station</h2>\r\n");
        fprintf(stream, "Name = %s<br>\r\n", radio.rc_sip->si_name);
        fprintf(stream, "Genre = %s<br>\r\n", radio.rc_sip->si_genre);
        fprintf(stream, "Bitrate = %u kBit<br>\r\n", radio.rc_sip->si_bitrate);
        fflush(stream);
        if (radio.rc_rip) {
            SHOUTCASTINFO *sci = (SHOUTCASTINFO *) radio.rc_rip->ri_bcast;
            fprintf(stream, "<h2>SHOUTcast Stream</h2>\r\n");
            fprintf(stream, "Buffer contents = %u Bytes<br>\r\n", radio.rc_rip->ri_avail);
            if (sci) {
                fprintf(stream, "Title = %s<br>\r\n", sci->sci_metatitle);
                fprintf(stream, "URL = %s<br>\r\n", sci->sci_metaurl);
            }
            fprintf(stream, "Metadata interval = %lu Bytes<br>\r\n", sci->sci_metaint);
            fflush(stream);
            if (radio.rc_pip) {
                MP3PLAYERINFO *mpi = (MP3PLAYERINFO *) radio.rc_pip->pi_bcast;
                if (mpi) {
                    fprintf(stream, "<h2>MP3 Decoder</h2>\r\n");
                    fprintf(stream, "Layer = %d<br>\r\n", mpi->mpi_frameinfo.layer);
                    fprintf(stream, "Version = %d<br>\r\n", mpi->mpi_frameinfo.version);
                    fprintf(stream, "Bitrate = %d<br>\r\n", mpi->mpi_frameinfo.bitrate);
                    fprintf(stream, "Channels = %d<br>\r\n", mpi->mpi_frameinfo.nChans);
                    fprintf(stream, "Sample rate = %d<br>\r\n", mpi->mpi_frameinfo.samprate);
                    fprintf(stream, "Bits per sample = %d<br>\r\n", mpi->mpi_frameinfo.bitsPerSample);
                    fflush(stream);
                }
            }
        }
    }

    fputs("<BR><BR><a href=\"/index.html\">BACK</a>", stream);

    /* Send HTML footer and flush output buffer. */
    fputs("</BODY></HTML>", stream);
    fflush(stream);

    return 0;
}

/*
 * CGI Radio Control
 */
int CgiControl(FILE * stream, REQUEST * req)
{
    int lvol = EMPTY_GAIN;
    int rvol = EMPTY_GAIN;
    int stop = 0;

    NutHttpSendHeaderTop(stream, req, 200, "Ok");
    NutHttpSendHeaderBot(stream, html_mt, -1);

    /* Send HTML header. */
    fputs("<HTML><BODY><BR><H1>Control Result</H1><BR><BR>", stream);
    fflush(stream);

    if (req->req_query) {
        char *name;
        char *value;
        int i;
        int count;

        count = NutHttpGetParameterCount(req);
        /* Extract count parameters. */
        for (i = 0; i < count; i++) {
            name = NutHttpGetParameterName(req, i);
            value = NutHttpGetParameterValue(req, i);

            /* Send the parameters back to the client. */
            //fprintf(stream, "%s = '%s'<BR>\r\n", name, value);
            if (strcmp(name, "lvol") == 0 && value[0]) {
                lvol = atoi(value);
            }
            else if (strcmp(name, "rvol") == 0 && value[0]) {
                rvol = atoi(value);
            }
            else if (strcmp(name, "stream") == 0 && value[0]) {
                stop = 1;
            }
        }

        /* Handle volume changes. User needs to fill one channel only 
           in order to set both. */
        if (rvol == EMPTY_GAIN) {
            rvol = lvol;
        }
        else if (lvol == EMPTY_GAIN) {
            lvol = rvol;
        }
        if (lvol != EMPTY_GAIN) {
            Tlv320DacSetVolume(lvol, rvol);
            fprintf(stream, "Volume set to %d/%d dB<BR>.\r\n", lvol, rvol);
        }

        /* Handle station re-connect. */
        if (stop) {
            if (radio.rc_rip) {
                ReceiverStop(radio.rc_rip);
                fprintf(stream, "Stream stopped.<BR>\r\n");
            }
            if (radio.rc_pip) {
                PlayerStop(radio.rc_pip);
                fprintf(stream, "Player stopped.<BR>\r\n");
            }
        }
    }

    fputs("<BR><BR><p><a href=\"/index.html\">BACK</a></BODY></HTML></p>", stream);
    fflush(stream);

    return 0;
}

/*! \fn Service(void *arg)
 * \brief HTTP service thread.
 *
 * The endless loop in this thread waits for a client connect,
 * processes the HTTP request and disconnects. Nut/Net doesn't
 * support a server backlog. If one client has established a
 * connection, further connect attempts will be rejected.
 * Typically browsers open more than one connection in order
 * to load images concurrently. So we run this routine by
 * several threads.
 *
 */
THREAD(Service, arg)
{
    TCPSOCKET *sock;
    FILE *stream;
    u_char id = (u_char) ((uptr_t) arg);

    /*
     * Now loop endless for connections.
     */
    for (;;) {

        /*
         * Create a socket.
         */
        if ((sock = NutTcpCreateSocket()) == 0) {
            printf("[%u] Creating socket failed\n", id);
            NutSleep(5000);
            continue;
        }

        /*
         * Listen on port 80. This call will block until we get a connection
         * from a client.
         */
        NutTcpAccept(sock, 80);

        /*
         * Wait until at least 8 kByte of free RAM is available. This will
         * keep the client connected in low memory situations.
         */
        while (NutHeapAvailable() < 8192) {
            printf("[%u] Low mem\n", id);
            NutSleep(1000);
        }

        /*
         * Associate a stream with the socket so we can use standard I/O calls.
         */
        if ((stream = _fdopen((int) ((uptr_t) sock), "r+b")) == 0) {
            printf("[%u] Creating stream device failed\n", id);
        } else {
            /*
             * This API call saves us a lot of work. It will parse the
             * client's HTTP request, send any requested file from the
             * registered file system or handle CGI requests by calling
             * our registered CGI routine.
             */
            NutHttpProcessRequest(stream);

            /*
             * Destroy the virtual stream device.
             */
            fclose(stream);
        }

        /*
         * Close our socket.
         */
        NutTcpCloseSocket(sock);
    }
}

/*!
 * \brief HTTP Server Start.
 */
int HttpServerStart(void)
{
    int i;

    /*
     * Register our device for the file system.
     */
    NutRegisterDevice(&MY_FSDEV, 0, 0);

#ifdef MY_HTTPROOT
    /* Register root path. */
    printf("Registering HTTP root '" MY_HTTPROOT "'...");
    if (NutRegisterHttpRoot(MY_HTTPROOT)) {
        puts("failed");
        for (;;);
    }
    puts("OK");
#endif

    /*
     * Register our CGIs.
     */
    NutRegisterCgi("info.cgi", CgiInfo);
    NutRegisterCgi("control.cgi", CgiControl);

    /*
     * Protect the admin directory with user and password.
     */
    NutRegisterAuth("admin", "admin:lemta");

    /*
     * Start four server threads.
     */
    for (i = 1; i <= 4; i++) {
        char *thname = "httpd0";

        thname[5] = '0' + i;
        NutThreadCreate(thname, Service, (void *) (uptr_t) i, HTTPD_THREAD_STACK);
    }
    return 0;
}

#endif /* USE_HTTPSERVER */

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -