Main Page | Modules | File List | Related Pages

cgi.c

00001 /*
00002  * Copyright (C) 2002 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. All advertising materials mentioning features or use of this
00014  *    software must display the following acknowledgement:
00015  *
00016  *    This product includes software developed by egnite Software GmbH
00017  *    and its contributors.
00018  *
00019  * THIS SOFTWARE IS PROVIDED BY EGNITE SOFTWARE GMBH AND CONTRIBUTORS
00020  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
00021  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
00022  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL EGNITE
00023  * SOFTWARE GMBH OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
00024  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
00025  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
00026  * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
00027  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
00028  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
00029  * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
00030  * SUCH DAMAGE.
00031  *
00032  * For additional information see http://www.ethernut.de/
00033  *
00034  */
00035 
00036 #include <string.h>
00037 #include <stdio.h>
00038 #include <io.h>
00039 
00040 #include <dev/spidigio.h>
00041 #include <pro/httpd.h>
00042 
00043 #include "webport.h"
00044 
00045 /*!
00046  * \addtogroup xgCGI
00047  */
00048 /*@{*/
00049 
00050 static u_char spi_ni = 255;     /*!< \brief Number of detected opto inputs. */
00051 static u_char spi_no = 255;     /*!< \brief Number of detected relays. */
00052 static u_long relay_status;     /*!< \brief Relays status. */
00053 static u_char relay_known;      /*!< \brief Equals zero as long as the relay status is unknown. */
00054 
00055 /*!
00056  * \brief Print HTML code for a row of LEDs.
00057  *
00058  * The resulting HTML code will present a row of LEDs. The color and
00059  * the lit state of each LED is determined by three bit values. The
00060  * required images are expected in the URL root of the urom flash
00061  * filesystem:
00062  *
00063  * - r0.gif Red LED not lit. Will be displayed if the corresponding
00064  *          bit in the direction mask is set and the input and output
00065  *          bits are both not set.
00066  * - r1.gif Red LED lit. Will be displayed if the corresponding
00067  *          bit in the direction mask is set and the input and output
00068  *          bits are both set.
00069  * - g0.gif Green LED not lit. Will be displayed if the corresponding
00070  *          bit in the direction mask and the input value are both not set.
00071  * - g1.gif Green LED lit. Will be displayed if the corresponding
00072  *          bit in the direction mask is not set and the input bit is set.
00073  * - y0.gif Yellow LED not lit. Will be displayed if the corresponding
00074  *          bit in the direction mask is set, the output bit is set
00075  *          but the input bit is not set.
00076  * - y1.gif Yellow LED lit. Will be displayed if the corresponding
00077  *          bit in the direction mask is set, the output bit is not set
00078  *          but the input bit is set.
00079  *
00080  * All LED images must be of the same size, 28 x 28 pixels.
00081  *
00082  * \param stream HTML code is printed to this stream device.
00083  * \param num    The number of LEDs to print.
00084  * \param desc   If not equal zero, bits are processed in descending order.
00085  * \param ival   Input bit values.
00086  * \param oval   Output bit values.
00087  * \param dir    Data direction mask. Any bit set to one represents an output.
00088  */
00089 static void HtmlLedRow(FILE *stream, u_char num, u_char desc, u_long ival, u_long oval, u_long dir)
00090 {
00091     u_char i;
00092     u_long mask;
00093 
00094     for(i = 0; i < num; i++) {
00095         if(desc)
00096             mask = 1UL << (num - i - 1);
00097         else
00098             mask = 1UL << i;
00099         fputs("<td><img src=\"/", stream);
00100         if(dir & mask) {
00101             if(oval & mask) {
00102                 if(ival & mask) 
00103                     fputs("r1", stream);
00104                 else 
00105                     fputs("y0", stream);
00106             }
00107             else {
00108                 if(ival & mask)
00109                     fputs("y1", stream);
00110                 else
00111                     fputs("r0", stream);
00112             }
00113         }
00114         else {
00115             if(ival & mask) {
00116                 fputs("g1", stream);
00117             }
00118             else {
00119                 fputs("g0", stream);
00120             }
00121         }
00122         fputs(".gif\" width=\"28\" heigth=\"28\"></td>\r\n", stream);
00123     }
00124 }
00125 
00126 /*!
00127  * \brief Print HTML code for a row of checkboxes.
00128  *
00129  * The resulting HTML code will present a row of checkboxes. 
00130  *
00131  * \param stream HTML code is printed to this stream device.
00132  * \param num    The number of checkboxes to print.
00133  * \param desc   If not equal zero, bits are processed in descending order.
00134  * \param name   Identifier of the checkboxes.
00135  * \param check  The checkbox will be checked if the corresponding bit is set.
00136  * \param enable The checkbox will be created only, ff the corresponding bit 
00137  *               in this bitmask is set.
00138  */
00139 static void HtmlCheckboxRow(FILE *stream, u_char num, u_char desc, u_char *name, u_long check, u_long enable)
00140 {
00141     u_char i;
00142     u_long mask;
00143 
00144     for(i = 0; i < num; i++) {
00145         if(desc)
00146             mask = 1UL << (num - i - 1);
00147         else
00148             mask = 1UL << i;
00149         if(enable & mask) {
00150             fputs("<td><input type=\"checkbox\" name=\"", stream);
00151             fprintf(stream, "%s\" value=\"%u\" ", name, num - i - 1);
00152             if(check & mask) 
00153                 fputs(" checked=\"checked\"", stream);
00154             fputs("></td>\r\n", stream);
00155         }
00156         else
00157             fputs("<td></td>\r\n", stream);
00158     }
00159 }
00160 
00161 
00162 /*!
00163  * \brief Print HTML code for a separator row.
00164  *
00165  * The resulting HTML code will present a black row. 
00166  *
00167  * \param stream HTML code is printed to this stream device.
00168  * \param width  Separator width in columns.
00169  * \param height Separator width in pixels.
00170  */
00171 static void HtmlSeparatorRow(FILE *stream, u_char width, u_char height)
00172 {
00173     fprintf(stream, "<tr bgcolor=\"#000000\"><td colspan=\"%u\" "
00174                            "height=\"%u\"></td></tr>", width, height);
00175 }
00176 
00177 /*!
00178  * \brief Print HTML code to display a single I/O port.
00179  *
00180  * The resulting HTML code will present a row of LEDs and two rows of
00181  * checkboxes. While the LEDs show the current port status, the checkboxes
00182  * may be used to modify the port output and the data direction register.
00183  *
00184  * See HtmlLedRow() for further details about how LEDs are displayed.
00185  * The checkboxes are created by calling HtmlCheckboxRow().
00186  *
00187  * \param stream HTML code is printed to this stream device.
00188  * \param name   Port identifier, typically 'A' for Port A, 'B' for port B etc.
00189  * \param pin    Contents of the PIN register.
00190  * \param port   Contents of the PORT register.
00191  * \param ddr    Contents of the data direction register.
00192  * \param enable If a bit is not set in this bit mask, then the corresponding
00193  *               checkboxes are not created and the port bits and data direction
00194  *               can't be modified.
00195  */
00196 static void HtmlInOutPortRow(FILE *stream, char name, u_char pin, u_char port, u_char ddr, u_char enable)
00197 {
00198     char ditem[3] = { 'D', 'X', 0 };
00199     char pitem[3] = { 'P', 'X', 0 };
00200 
00201     ditem[1] = name;
00202     pitem[1] = name;
00203     fputs("<tr><th rowspan=\"4\">", stream);
00204     fprintf(stream, "%c", name);
00205     fputs("</th><td>Status</td>", stream);
00206     HtmlLedRow(stream, 8, 1, pin, port, ddr);
00207     fputs("</tr>\r\n<tr><td>Output</td>", stream);
00208     HtmlCheckboxRow(stream, 8, 1, ditem, ddr, enable);
00209     fputs("</tr>\r\n<tr><td>Pull up</td>", stream);
00210     HtmlCheckboxRow(stream, 8, 1, pitem, port, enable);
00211     fputs("</tr>\r\n", stream);
00212 }
00213 
00214 /*!
00215  * \brief Process request parameters for CPU port control.
00216  *
00217  * Parse the CGI query and perform the corresponding action:
00218  *
00219  * - Dx=y will set bit y in the data direction register of port x.
00220  * - Px=y will set bit y in the port output register of port x.
00221  *
00222  * All other bits are switched off.
00223  *
00224  * \param query CGI query string.
00225  */
00226 static void ProcessCgiPortRequest(char *query)
00227 {
00228     u_char *item = query;
00229     u_char *val;
00230     u_char ddrb = 0;
00231     u_char portb = 0;
00232     u_char ddrd = 0;
00233     u_char portd = 0;
00234     u_char ddre = 0;
00235     u_char porte = 0;
00236     
00237     for(;;) {
00238         printf("[%s]", item);
00239         if((val = strchr(item, '=')) == 0)
00240             break;
00241         *val++ = 0;
00242         if(strcmp(item, "DB") == 0)
00243             ddrb |= BV(*val - '0'); 
00244         else if(strcmp(item, "PB") == 0)
00245             portb |= BV(*val - '0'); 
00246         else if(strcmp(item, "DD") == 0)
00247             ddrd |= BV(*val - '0'); 
00248         else if(strcmp(item, "PD") == 0)
00249             portd |= BV(*val - '0'); 
00250         else if(strcmp(item, "DE") == 0)
00251             ddre |= BV(*val - '0'); 
00252         else if(strcmp(item, "PE") == 0)
00253             porte |= BV(*val - '0');
00254         if((item = strchr(val, '&')) == 0)
00255             break;
00256         item++;
00257     }
00258     outp(ddrb, DDRB);
00259     outp(portb, PORTB);
00260     outp(ddrd, DDRD);
00261     outp(portd, PORTD);
00262     outp(ddre, DDRE);
00263     outp(porte, PORTE);
00264 }
00265 
00266 /*!
00267  * \brief Process request parameters for relay output control.
00268  *
00269  * Parse the CGI query and switch the corresponding relays.
00270  * 'S=y' will switch on relay y. All other relays are switched off.
00271  *
00272  * Note, that before calling this function is called for the first time,
00273  * the status of the relays is unknown.
00274  *
00275  * \param query CGI query string.
00276  */
00277 static void ProcessCgiRelayRequest(char *query)
00278 {
00279     u_char *item = query;
00280     u_char *val;
00281     
00282     relay_status = 0;
00283     for(;;) {
00284         if((val = strchr(item, '=')) == 0)
00285             break;
00286         *val++ = 0;
00287         if(item[0] == 'S')
00288             relay_status |= 1UL << (*val - '0');
00289         if((item = strchr(val, '&')) == 0)
00290             break;
00291         item++;
00292     }
00293     SpiDigitalSet(spi_no, relay_status);
00294     relay_known = 1;
00295 }
00296 
00297 /*!
00298  * \brief CGI callback function to control the CPU ports.
00299  *
00300  * Creates HTML code to show the status of CPU ports B, D, E and F
00301  * plus a HTML form to modify the port and data direction registers 
00302  * of ports B, D and E by checkboxes. 
00303  *
00304  * The resulting HTML code is send back to the browser. If the submit
00305  * button is clicked on this page, this function will be called again
00306  * to process the checkboxes.
00307  *
00308  * \image html cport.gif
00309  *
00310  * This function is called by the HTTP module when a browser requests
00311  * a CGI function, for which this routine has been registered via
00312  * NutRegisterCgi().
00313  *
00314  * \param stream Stream of the HTTP connection.
00315  * \param req    Pointer to the CGI ::REQUEST structure.
00316  *
00317  * \return 0 on success or -1 in case of any failure.
00318  */
00319 int CpuPortControl(FILE *stream, REQUEST *req)
00320 {
00321     static prog_char head[] = "<html>"
00322                        "<head>"
00323                        "<meta http-equiv=\"expires\" content=\"0\">"
00324                        "<title>Ethernut CPU Port Control</title>"
00325                        "</head>"
00326                        "<body bgcolor=\"#C7D0D9\"><a href=\"/\">"
00327                        "<img src=\"/enmini.gif\" border=\"0\" width=\"70\" height=\"17\">"
00328                        "</a><div align=\"center\">";
00329     static prog_char thdr[] = "<form action=\"" PORT_CONTROL_CGI
00330                               "\" enctype=\"text/plain\">"
00331                               "<table border=\"1\" cellspacing=\"0\">\r\n"
00332                               "<thead><tr><th rowspan=\"2\"> PORT </th>"
00333                               "<th rowspan=\"2\"> Type </th>"
00334                               "<th colspan=\"8\">Bit</th></tr>"
00335                               "<tr><th>7</th><th>6</th><th>5</th><th>4</th><th>3</th>"
00336                               "<th>2</th><th>1</th><th>0</th></tr>"
00337                               "</thead><tfoot>\r\n";
00338     static prog_char foot[] = "</tfoot></table><br>"
00339                               " <input type=\"submit\" value=\" Set \"> "
00340                               " <input type=\"reset\" value=\" Cancel \"> "
00341                               "</form>\r\n</div></body>\r\n</html>";
00342 
00343     NutHttpSendHeaderTop(stream, req, 200, "Ok");
00344     NutHttpSendHeaderBot(stream, "text/html", -1);
00345 
00346     fputs_P(head, stream);
00347     if(req->req_query)
00348         ProcessCgiPortRequest(req->req_query);
00349 
00350     fputs_P(thdr, stream);
00351  
00352     HtmlInOutPortRow(stream, 'B', inp(PINB), inp(PORTB), inp(DDRB), 0xFF);
00353     HtmlSeparatorRow(stream, 10, 5);
00354     HtmlInOutPortRow(stream, 'D', inp(PIND), inp(PORTD), inp(DDRD), 0xFF);
00355     HtmlSeparatorRow(stream, 10, 5);
00356     HtmlInOutPortRow(stream, 'E', inp(PINE), inp(PORTE), inp(DDRE), 0xDC);
00357     HtmlSeparatorRow(stream, 10, 5);
00358 
00359     fputs("<tr><th>F</th><td>Status</td>", stream);
00360     HtmlLedRow(stream, 8, 1, inp(PINF), inp(PINF), 0);
00361     fputs("</tr>\r\n", stream);
00362 
00363     fputs_P(foot, stream);
00364     fflush(stream);
00365     return 0;
00366 }
00367 
00368 
00369 /*!
00370  * \brief CGI callback function to display the status of the CPU ports.
00371  *
00372  * Creates HTML code to show the status of CPU ports B, D, E and F.
00373  * The page will be automatically refreshed once a second.
00374  *
00375  * \image html sport.gif
00376  *
00377  * This function is called by the HTTP module when a browser requests
00378  * a CGI function, for which this routine has been registered via
00379  * NutRegisterCgi().
00380  *
00381  * \param stream Stream device of the HTTP connection.
00382  * \param req      Pointer to the CGI ::REQUEST structure.
00383  *
00384  * \return 0 on success or -1 in case of any failure.
00385  */
00386 int CpuPortStatus(FILE *stream, REQUEST *req)
00387 {
00388     static prog_char head[] = "<html>"
00389                        "<head>"
00390                        "<meta http-equiv=\"refresh\" content=\"1; URL=" PORT_STATUS_CGI "\">"
00391                        "<title>Ethernut CPU Port Status</title>"
00392                        "</head>"
00393                        "<body bgcolor=\"#C7D0D9\"><a href=\"/\">"
00394                        "<img src=\"/enmini.gif\" border=\"0\" width=\"70\" height=\"17\">"
00395                        "</a><div align=\"center\">"
00396                        "<table border=\"1\" cellspacing=\"0\">\r\n"
00397                        "<thead><tr><th rowspan=\"2\"> PORT </th>"
00398                        "<th colspan=\"8\">Bit</th></tr>"
00399                        "<tr><th>7</th><th>6</th><th>5</th><th>4</th><th>3</th>"
00400                        "<th>2</th><th>1</th><th>0</th></tr>"
00401                        "</thead><tfoot>\r\n";
00402 
00403     NutHttpSendHeaderTop(stream, req, 200, "Ok");
00404     NutHttpSendHeaderBot(stream, "text/html", -1);
00405 
00406     fputs_P(head, stream);
00407 
00408     fputs("<tr><th>B</th>", stream);
00409     HtmlLedRow(stream, 8, 1, inp(PINB), inp(PORTB), inp(DDRB));
00410     fputs("</tr>\r\n", stream);
00411 
00412     fputs("<tr><th>D</th>", stream);
00413     HtmlLedRow(stream, 8, 1, inp(PIND), inp(PORTD), inp(DDRD));
00414     fputs("</tr>\r\n", stream);
00415 
00416     fputs("<tr><th>E</th>", stream);
00417     HtmlLedRow(stream, 8, 1, inp(PINE), inp(PORTE), inp(DDRE));
00418     fputs("</tr>\r\n", stream);
00419 
00420     fputs("<tr><th>F</th>", stream);
00421     HtmlLedRow(stream, 8, 1, inp(PINF), inp(PINF), 0);
00422     fputs("</tr>\r\n", stream);
00423 
00424     fputs("</tfoot></table><br>"
00425                                     "</div></body>\r\n</html>", stream);
00426     fflush(stream);
00427     return 0;
00428 }
00429 
00430 
00431 /*!
00432  * \brief CGI callback function to control a SPI relay output board.
00433  *
00434  * Creates HTML code to show the status of any attached SPI relay 
00435  * output board plus a HTML form to modify the current relay status
00436  * via checkboxes.
00437  *
00438  * The resulting HTML code is send back to the browser. If the submit
00439  * button is clicked on this page, this function will be called again
00440  * to process the checkboxes and display the updated status.
00441  *
00442  * \image html relay.gif
00443  *
00444  * This function is called by the HTTP module when a browser requests
00445  * a CGI function, for which this routine has been registered via
00446  * NutRegisterCgi().
00447  *
00448  * \param stream Stream device of the HTTP connection.
00449  * \param req      Pointer to the CGI ::REQUEST structure.
00450  *
00451  * \return 0 on success or -1 in case of any failure.
00452  */
00453 int SpiRelayControl(FILE *stream, REQUEST *req)
00454 {
00455     u_char i;
00456     static prog_char head[] = "<html>"
00457                        "<head>"
00458                        "<meta http-equiv=\"expires\" content=\"0\">"
00459                        "<title>Ethernut SPI Relay Output</title>"
00460                        "</head>"
00461                        "<body bgcolor=\"#C7D0D9\"><a href=\"/\">"
00462                        "<img src=\"/enmini.gif\" border=\"0\" width=\"70\" height=\"17\">"
00463                        "</a><div align=\"center\">";
00464     static prog_char foot[] = "</tfoot></table><br>"
00465                        " <input type=\"submit\" value=\" Set \"> "
00466                        " <input type=\"reset\" value=\" Cancel \"> "
00467                        "</form>\r\n";
00468 
00469     if(spi_no == 255)
00470         SpiDigitalInit(&spi_ni, &spi_no);
00471 
00472     NutHttpSendHeaderTop(stream, req, 200, "Ok");
00473     NutHttpSendHeaderBot(stream, "text/html", -1);
00474 
00475     fputs_P(head, stream);
00476 
00477     if(spi_no) {
00478         if(req->req_query) 
00479             ProcessCgiRelayRequest(req->req_query);
00480 
00481         fputs("<form action=\"" RELAY_CONTROL_CGI "\" enctype=\"text/plain\">"
00482                                         "<table border=\"1\" cellspacing=\"0\">\r\n"
00483                                         "<thead><tr><th> </th><th colspan=\"", stream);
00484         fprintf(stream, "%u", spi_no);
00485         fputs("\">Relay</th></tr><tr><td> </td>", stream);
00486         for(i = 1; i <= spi_no; i++)
00487             fprintf(stream, "<th>%u</th>", i);
00488         fputs("</tr></thead><tfoot>\r\n", stream);
00489 
00490         fputs("<tr><td> </td>", stream);
00491         if(relay_known)
00492             HtmlLedRow(stream, spi_no, 0, relay_status, relay_status, 0xFFFFFFFF);
00493         else
00494             HtmlLedRow(stream, spi_no, 0, relay_status, ~relay_status, 0xFFFFFFFF);
00495         fputs("</tr>\r\n", stream);
00496 
00497         fputs("<tr><td>On</td>", stream);
00498         HtmlCheckboxRow(stream, spi_no, 0, "S", relay_status, 0xFFFFFFFF);
00499         fputs("</tr>\r\n", stream);
00500 
00501         fputs_P(foot, stream);
00502     }
00503     else
00504         fputs("No SPI Output", stream);
00505     fputs("</div></body>\r\n</html>", stream);
00506     fflush(stream);
00507     return 0;
00508 }
00509 
00510 /*!
00511  * \brief CGI callback function to control a SPI input board.
00512  *
00513  * Creates HTML code to show the status of the optically isolated inputs
00514  * of an attached SPI input board. The page will be automatically refreshed 
00515  * once a second.
00516  *
00517  * \image html opto.gif
00518  *
00519  * This function is called by the HTTP module when a browser requests
00520  * a CGI function, for which this routine has been registered via
00521  * NutRegisterCgi().
00522  *
00523  * \param stream Stream device of the HTTP connection.
00524  * \param req      Pointer to the CGI ::REQUEST structure.
00525  *
00526  * \return 0 on success or -1 in case of any failure.
00527  */
00528 int SpiOptoStatus(FILE *stream, REQUEST *req)
00529 {
00530     u_long status;
00531     u_char i;
00532     static prog_char title[] = "<title>Ethernut SPI Isolated Input</title>"
00533                         "</head><body bgcolor=\"#C7D0D9\"><a href=\"/\">"
00534                         "<img src=\"/enmini.gif\" border=\"0\" width=\"70\" height=\"17\">"
00535                         "</a><div align=\"center\">";
00536 
00537     if(spi_ni == 255)
00538         SpiDigitalInit(&spi_ni, &spi_no);
00539 
00540     NutHttpSendHeaderTop(stream, req, 200, "Ok");
00541     NutHttpSendHeaderBot(stream, "text/html", -1);
00542 
00543     fputs("<html><head>", stream);
00544     if(spi_ni)
00545         fputs("<meta http-equiv=\"refresh\" content=\"1; URL=" OPTO_STATUS_CGI "\">", stream);
00546     fputs_P(title, stream);
00547     if(spi_ni) {
00548         fputs("<table border=\"1\" cellspacing=\"0\">\r\n"
00549                                         "<thead><tr><th colspan=\"", stream);
00550         fprintf(stream, "%u", spi_ni);
00551         fputs("\">Input</th></tr><tr>", stream);
00552         for(i = 1; i <= spi_ni; i++)
00553             fprintf(stream, "<th>%u</th>", i);
00554         fputs("</tr></thead><tfoot><tr>\r\n", stream);
00555         status = SpiDigitalGet(spi_ni);
00556         HtmlLedRow(stream, spi_ni, 0, status, status, 0);
00557         fputs("</tfoot></table><br>", stream);
00558     }
00559     else
00560         fputs("No SPI Input", stream);
00561     fputs("</div></body>\r\n</html>", stream);
00562     fflush(stream);
00563     return 0;
00564 }
00565 
00566 
00567 
00568 /*@}*/

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