cgi.c

来自「针对AVR单片机开发的嵌入式操作系统」· C语言 代码 · 共 721 行 · 第 1/2 页

C
721
字号
/*
 * 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/
 *
 */

#include <string.h>
#include <stdio.h>
#include <io.h>

#include <dev/spidigio.h>
#include <pro/httpd.h>

#include "db_shift.h"
#include "webport.h"

/*!
 * \file cgi.c
 * \brief CGI Callbacks.
 */

/*!
 * \addtogroup xgCGI
 */
/*@{*/

static u_char spi_ni = 255;     /*!< \brief Number of detected opto inputs. */
static u_char spi_no = 255;     /*!< \brief Number of detected relays. */
static u_long relay_status;     /*!< \brief Relays status. */
static u_char relay_known;      /*!< \brief Equals zero as long as the relay status is unknown. */

/*!
 * \brief Print HTML code for a row of LEDs.
 *
 * The resulting HTML code will present a row of LEDs. The color and
 * the lit state of each LED is determined by three bit values. The
 * required images are expected in the URL root of the urom flash
 * filesystem:
 *
 * - r0.gif Red LED not lit. Will be displayed if the corresponding
 *          bit in the direction mask is set and the input and output
 *          bits are both not set.
 * - r1.gif Red LED lit. Will be displayed if the corresponding
 *          bit in the direction mask is set and the input and output
 *          bits are both set.
 * - g0.gif Green LED not lit. Will be displayed if the corresponding
 *          bit in the direction mask and the input value are both not set.
 * - g1.gif Green LED lit. Will be displayed if the corresponding
 *          bit in the direction mask is not set and the input bit is set.
 * - y0.gif Yellow LED not lit. Will be displayed if the corresponding
 *          bit in the direction mask is set, the output bit is set
 *          but the input bit is not set.
 * - y1.gif Yellow LED lit. Will be displayed if the corresponding
 *          bit in the direction mask is set, the output bit is not set
 *          but the input bit is set.
 *
 * All LED images must be of the same size, 28 x 28 pixels.
 *
 * \param stream HTML code is printed to this stream device.
 * \param num    The number of LEDs to print.
 * \param desc   If not equal zero, bits are processed in descending order.
 * \param ival   Input bit values.
 * \param oval   Output bit values.
 * \param dir    Data direction mask. Any bit set to one represents an output.
 */
static void HtmlLedRow(FILE * stream, u_char num, u_char desc, u_long ival, u_long oval, u_long dir)
{
    u_char i;
    u_long mask;

    for (i = 0; i < num; i++) {
        if (desc)
            mask = 1UL << (num - i - 1);
        else
            mask = 1UL << i;
        fputs("<td><img src=\"/", stream);
        if (dir & mask) {
            if (oval & mask) {
                if (ival & mask)
                    fputs("r1", stream);
                else
                    fputs("y0", stream);
            } else {
                if (ival & mask)
                    fputs("y1", stream);
                else
                    fputs("r0", stream);
            }
        } else {
            if (ival & mask) {
                fputs("g1", stream);
            } else {
                fputs("g0", stream);
            }
        }
        fputs(".gif\" width=\"28\" heigth=\"28\"></td>\r\n", stream);
    }
}

/*!
 * \brief Print HTML code for a row of checkboxes.
 *
 * The resulting HTML code will present a row of checkboxes. 
 *
 * \param stream HTML code is printed to this stream device.
 * \param num    The number of checkboxes to print.
 * \param desc   If not equal zero, bits are processed in descending order.
 * \param name   Identifier of the checkboxes.
 * \param check  The checkbox will be checked if the corresponding bit is set.
 * \param enable The checkbox will be created only, ff the corresponding bit 
 *               in this bitmask is set.
 */
static void HtmlCheckboxRow(FILE * stream, u_char num, u_char desc, u_char * name, u_long check, u_long enable)
{
    u_char i;
    u_long mask;
    for (i = 0; i < num; i++) {
        if (desc)
            mask = 1UL << (num - i - 1);
        else
            mask = 1UL << i;
        if (enable & mask) {
            fputs("<td><input type=\"checkbox\" name=\"", stream);
            fprintf(stream, "%s\" value=\"%u\" ", name, num - i - 1);
            if (check & mask)
                fputs(" checked=\"checked\"", stream);
            fputs("></td>\r\n", stream);
        } else
            fputs("<td></td>\r\n", stream);
    }
}


/*!
 * \brief Print HTML code for a separator row.
 *
 * The resulting HTML code will present a black row. 
 *
 * \param stream HTML code is printed to this stream device.
 * \param width  Separator width in columns.
 * \param height Separator width in pixels.
 */
static void HtmlSeparatorRow(FILE * stream, u_char width, u_char height)
{
    fprintf(stream, "<tr bgcolor=\"#000000\"><td colspan=\"%u\" "       /* */
            "height=\"%u\"></td></tr>", width, height);
}

/*!
 * \brief Print HTML code to display a single I/O port.
 *
 * The resulting HTML code will present a row of LEDs and two rows of
 * checkboxes. While the LEDs show the current port status, the checkboxes
 * may be used to modify the port output and the data direction register.
 *
 * See HtmlLedRow() for further details about how LEDs are displayed.
 * The checkboxes are created by calling HtmlCheckboxRow().
 *
 * \param stream HTML code is printed to this stream device.
 * \param name   Port identifier, typically 'A' for Port A, 'B' for port B etc.
 * \param pin    Contents of the PIN register.
 * \param port   Contents of the PORT register.
 * \param ddr    Contents of the data direction register.
 * \param enable If a bit is not set in this bit mask, then the corresponding
 *               checkboxes are not created and the port bits and data direction
 *               can't be modified.
 */
static void HtmlInOutPortRow(FILE * stream, char name, u_char pin, u_char port, u_char ddr, u_char enable)
{
    char ditem[3] = { 'D', 'X', 0 };
    char pitem[3] = { 'P', 'X', 0 };

    ditem[1] = name;
    pitem[1] = name;
    fputs("<tr><th rowspan=\"4\">", stream);
    fprintf(stream, "%c", name);
    fputs("</th><td>Status</td>", stream);
    HtmlLedRow(stream, 8, 1, pin, port, ddr);
    fputs("</tr>\r\n<tr><td>Output</td>", stream);
    HtmlCheckboxRow(stream, 8, 1, ditem, ddr, enable);
    fputs("</tr>\r\n<tr><td>Pull up</td>", stream);
    HtmlCheckboxRow(stream, 8, 1, pitem, port, enable);
    fputs("</tr>\r\n", stream);
}

/*!
 * \brief Process request parameters for CPU port control.
 *
 * Parse the CGI query and perform the corresponding action:
 *
 * - Dx=y will set bit y in the data direction register of port x.
 * - Px=y will set bit y in the port output register of port x.
 *
 * All other bits are switched off.
 *
 * \param query CGI query string.
 */
static void ProcessCgiPortRequest(REQUEST * req)
{
    u_char ddrb = 0;
    u_char portb = 0;
    u_char ddrd = 0;
    u_char portd = 0;
    u_char ddre = 0;
    u_char porte = 0;
    int mods = 0;
    int i;
    int pcount = NutHttpGetParameterCount(req);
    char *name;
    char *value;

    for (i = 0; i < pcount; i++) {
        name = NutHttpGetParameterName(req, i);
        value = NutHttpGetParameterValue(req, i);
        if (strcmp(name, "DB") == 0) {
            ddrb |= BV(*value - '0');
            mods++;
        } else if (strcmp(name, "PB") == 0) {
            portb |= BV(*value - '0');
            mods++;
        } else if (strcmp(name, "DD") == 0) {
            ddrd |= BV(*value - '0');
            mods++;
        } else if (strcmp(name, "PD") == 0) {
            portd |= BV(*value - '0');
            mods++;
        } else if (strcmp(name, "DE") == 0) {
            ddre |= BV(*value - '0');
            ddre &= ~_BV(5);
            mods++;
        } else if (strcmp(name, "PE") == 0) {
            porte |= BV(*value - '0');
            porte &= ~_BV(5);
            mods++;
        }
    }
    if (mods) {
        outb(DDRB, ddrb);
        outb(PORTB, portb);
        outb(DDRD, ddrd);
        outb(PORTD, portd);
        outb(DDRE, ddre);
        outb(PORTE, porte);
    }
}

/*!
 * \brief Process request parameters for relay output control.
 *
 * Parse the CGI query and switch the corresponding relays.
 * 'S=y' will switch on relay y. All other relays are switched off.
 *
 * Note, that before calling this function is called for the first time,
 * the status of the relays is unknown.
 *
 * \param query CGI query string.
 */
static void ProcessCgiRelayRequest(char *query)
{
    u_char *item = query;
    u_char *val;

    relay_status = 0;
    for (;;) {
        if ((val = strchr(item, '=')) == 0)
            break;
        *val++ = 0;
        if (item[0] == 'S')
            relay_status |= 1UL << (7 - (*val - '0'));
        if ((item = strchr(val, '&')) == 0)
            break;
        item++;
    }
    SpiDigitalSet(spi_no, relay_status);
    relay_known = 1;
}

/*!
 * \brief CGI callback function to control the CPU ports.
 *
 * Creates HTML code to show the status of CPU ports B, D, E and F
 * plus a HTML form to modify the port and data direction registers 
 * of ports B, D and E by checkboxes. 
 *
 * The resulting HTML code is send back to the browser. If the submit
 * button is clicked on this page, this function will be called again
 * to process the checkboxes.
 *
 * \image html cport.gif
 *
 *
 *
 * This function is called by the HTTP module when a browser requests
 * a CGI function, for which this routine has been registered via
 * NutRegisterCgi().
 *
 * \param stream Stream of the HTTP connection.
 * \param req    Pointer to the CGI REQUEST structure. Detailed information
 *               is available in the Nut/OS API documentation.
 *
 * \return 0 on success or -1 in case of any failure.
 */
int CpuPortControl(FILE * stream, REQUEST * req)
{
    static prog_char head[] = "<html>"  /* */
        "<head>"                /* */
        "<meta http-equiv=\"expires\" content=\"0\">"   /* */
        "<title>Ethernut CPU Port Control</title>"      /* */
        "</head>"               /* */
        "<body bgcolor=\"#C7D0D9\"><a href=\"/\">"      /* */
        "<img src=\"/enmini.gif\" border=\"0\" width=\"70\" height=\"17\">"     /* */
        "</a><div align=\"center\">";
    static prog_char thdr[] = "<form action=\"" PORT_CONTROL_CGI        /* */
        "\" enctype=\"text/plain\">"    /* */
        "<table border=\"1\" cellspacing=\"0\">\r\n"    /* */
        "<thead><tr><th rowspan=\"2\"> PORT </th>"      /* */
        "<th rowspan=\"2\"> Type </th>" /* */
        "<th colspan=\"8\">Bit</th></tr>"       /* */
        "<tr><th>7</th><th>6</th><th>5</th><th>4</th><th>3</th>"        /* */
        "<th>2</th><th>1</th><th>0</th></tr>"   /* */
        "</thead><tfoot>\r\n";
    static prog_char foot[] = "</tfoot></table><br>"    /* */
        " <input type=\"submit\" value=\" Set \"> "     /* */
        " <input type=\"reset\" value=\" Cancel \"> "   /* */
        "</form>\r\n</div></body>\r\n</html>";

    NutHttpSendHeaderTop(stream, req, 200, "Ok");
    NutHttpSendHeaderBot(stream, "text/html", -1);

    fputs_P(head, stream);
    if (req->req_url)
        ProcessCgiPortRequest(req);

    fputs_P(thdr, stream);

⌨️ 快捷键说明

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