Tiny HTTP server controlling a DigitalOutput.

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers main.cpp Source File

main.cpp

00001 #include "mbed.h"
00002 #include "EthernetInterface.h"
00003 #include "TCPSocket.h"
00004 #include <stdio.h>
00005 #include <string>
00006 
00007 DigitalOut led(PA_6);
00008 
00009 FileHandle* mbed::mbed_override_console(int)
00010 {
00011     static BufferedSerial   arch_max_serial1(PA_9, PA_10, 9600);
00012     return &arch_max_serial1;
00013 }
00014 
00015 #define PORT    80
00016 /* */
00017 EthernetInterface*  net;
00018 TCPSocket           server;
00019 TCPSocket*          client;
00020 char                httpBuf[1500];
00021 char                httpHeader[256];
00022 const int           OFF = 0;
00023 const int           ON = 1;
00024 const char          PASSWORD[] = "secret";  // Change as you like
00025 DigitalOut          output(LED1);
00026 float               roomTemp = 21.8;        // A temperature sensor output
00027 
00028 FileHandle* mbed_override_console(int)
00029 {
00030     static BufferedSerial   arch_max_serial1(PA_9, PA_10, 9600);
00031     return &arch_max_serial1;
00032 }
00033 
00034 /**
00035  * @brief   Analyses the received URL
00036  * @note    The string passed to this function will look like this:
00037  *          GET /password HTTP/1.....
00038  *          GET /password/ HTTP/1.....
00039  *          GET /password/?sw=1 HTTP/1.....
00040  *          GET /password/?sw=0 HTTP/1.....
00041  * @param   url URL string
00042  * @retval -1 invalid password
00043  *         -2 no command given but password valid
00044  *         -3 just refresh page
00045  *          0 switch off
00046  *          1 switch on
00047  */
00048 int8_t analyseURL(char* url)
00049 {
00050     if (strlen(url) < (5 + strlen(PASSWORD) + 1))
00051         return(-1);
00052 
00053     //if (url.substr(5, PASSWORD.size()) != PASSWORD)
00054     if (strncmp(url + 5, PASSWORD, strlen(PASSWORD)) != 0)
00055         return(-1);
00056 
00057     uint8_t pos = 5 + strlen(PASSWORD);
00058 
00059     //if (url.substr(pos, 1) != "/")
00060 
00061     if (*(url + pos) != '/')
00062         return(-1);
00063 
00064     //if (url.substr(pos++, 1) == " ")
00065     if (*(url + pos++) == ' ')
00066         return(-2);
00067 
00068     //string  cmd(url.substr(pos, 5));
00069     *(url + pos + 5) = '\0';    // terminate the cmd string
00070     char*   cmd = ((url + pos));
00071     if (strcmp(cmd, "?sw=0") == 0)
00072         return(0);
00073     if (strcmp(cmd, "?sw=1") == 0)
00074         return(1);
00075     return(-3);
00076 }
00077 
00078 /**
00079  * @brief
00080  * @note
00081  * @param
00082  * @retval
00083  */
00084 char* movedPermanently(uint8_t flag)
00085 {
00086     memset(httpBuf, 0, sizeof(httpBuf));
00087     if (flag == 1) {
00088         strcpy(httpBuf, "/");
00089         strcat(httpBuf, PASSWORD);
00090         strcat(httpBuf, "/");
00091     }
00092 
00093     strcat(httpBuf, "<h1>301 Moved Permanently</h1>\r\n");
00094     return(httpBuf);
00095 }
00096 
00097 /**
00098  * @brief
00099  * @note
00100  * @param
00101  * @retval
00102  */
00103 char* showWebPage(int status)
00104 {
00105     char    roomTempStr[10] = { };
00106 
00107     //roomTemp = ds1820.read();
00108 
00109     sprintf(roomTempStr, "%3.1f", roomTemp);
00110     memset(httpBuf, 0, sizeof(httpBuf));
00111 
00112     /*$off*/
00113     strcat
00114     (
00115         httpBuf,
00116         "<head>"
00117             "<meta charset=\"utf-8\">"
00118             "<meta name=\"viewport\" content=\" initial-scale=1.0; maximum-scale=1.0; minimum-scale=1.0; user-scalable=0;\"/>"
00119             "<title>Smart Home</title>"
00120             "<link href='http://fonts.googleapis.com/css?family=Droid+Sans&v1' rel='stylesheet' type='text/css'>"
00121             "<style>"
00122             ".switch {"
00123                 "position: relative;"
00124                 "display: inline-block;"
00125                 "width: 60px;"
00126                 "height: 34px;"
00127             "}"
00128             ".switch input {display:none;}"
00129             ".slider {"
00130                 "position: absolute;"
00131                 "cursor: pointer;"
00132                 "top: 0;"
00133                 "left: 0;"
00134                 "right: 0;"
00135                 "bottom: 0;"
00136                 "border-radius: 34px;"
00137                 "background-color: #ccc;"
00138                 "-webkit-transition: .4s;"
00139                 "transition: .4s;"
00140             "}"
00141             ".slider:before {"
00142                 "position: absolute;"
00143                 "content: \"\";"
00144                 "height: 26px;"
00145                 "width: 26px;"
00146                 "left: 4px;"
00147                 "bottom: 4px;"
00148                 "border-radius: 50%;"
00149                 "background-color: white;"
00150                 "-webkit-transition: .4s;"
00151                 "transition: .4s;"
00152             "}"
00153             "input:checked + .slider {"
00154                 "background-color: #8ce196;"
00155             "}"
00156             "input:focus + .slider {"
00157                 "box-shadow: 0 0 1px #8ce196;"
00158             "}"
00159             "input:checked + .slider:before {"
00160                 "-webkit-transform: translateX(26px);"
00161                 "-ms-transform: translateX(26px);"
00162                 "transform: translateX(26px);"
00163             "}"
00164             "</style>"
00165         "</head>"
00166 
00167         "<body>"
00168             "<h2><a href=\".\" title=\"Click to refresh the page\">Smart Home</a></h2>"
00169             "<pre>Temperature:\t"
00170     );
00171     strcat(httpBuf, roomTempStr);
00172     strcat(httpBuf, "&deg;C</pre>");
00173     strcat
00174     (
00175        httpBuf,
00176        "<pre>Heating:\t"
00177     );
00178     if(status == ON) {
00179        strcat
00180        (
00181            httpBuf,
00182            "<a href=\"./?sw=0\" class=\"switch\"> "
00183            "<input type=\"checkbox\" checked>"
00184        );
00185     }
00186     else {
00187        strcat
00188        (
00189            httpBuf,
00190            "<a href=\"./?sw=1\" class=\"switch\"> "
00191            "<input type=\"checkbox\">"
00192        );
00193     }
00194     strcat
00195     (
00196        httpBuf,
00197            "<div class=\"slider\"></div>"
00198            "</a>"
00199            "</pre>"
00200            "<hr>"
00201            "<pre>2017 ARMmbed</pre>"
00202        "</body>"
00203     );
00204     /*$on*/
00205     return httpBuf;
00206 }
00207 
00208 /**
00209  * @brief
00210  * @note
00211  * @param
00212  * @retval
00213  */
00214 void sendHTTP(TCPSocket* client, char* header, char* content)
00215 {
00216     char    content_length[10] = { };
00217     sprintf(content_length, "%u\r\n", strlen(content));
00218     strcat(header, "\r\nContent-Type: text/html\r\n");
00219     strcat(header, "Content-Length: ");
00220     strcat(header, content_length);
00221     strcat(header, "Pragma: no-cache\r\n");
00222     strcat(header, "Connection: About to close\r\n\r\n");
00223 
00224     char    c = content[0];
00225     memmove(httpBuf + strlen(header), httpBuf, strlen(content));    // make room for the header
00226     strcpy(httpBuf, header);                                        // copy the header on front of the content
00227     httpBuf[strlen(header)] = c;
00228     client->send((uint8_t*)httpBuf, strlen(httpBuf));
00229 }
00230 
00231 /**
00232  * @brief
00233  * @note
00234  * @param
00235  * @retval
00236  */
00237 int main()
00238 {
00239     printf("starting\r\n");
00240 
00241     net = new EthernetInterface();
00242 
00243     //net->set_network("192.168.1.181","255.255.255.0","192.168.1.1");  // use static IP address, netmask, gateway
00244     if (!net) {
00245         printf("Error! No network inteface found.\n");
00246         return 0;
00247     }
00248 
00249     //net->set_network (IP, NETMASK, GATEWAY);  // include this for using static IP address
00250     nsapi_size_or_error_t   r = net->connect();
00251     if (r != NSAPI_ERROR_OK) {
00252         printf("Error! net->connect() returned: %d\n", r);
00253         return r;
00254     }
00255 
00256     // Show the network address
00257     SocketAddress   addr;
00258     net->get_ip_address(&addr);
00259     printf("IP address: %s\n", addr.get_ip_address() ? addr.get_ip_address() : "None");
00260     net->get_netmask(&addr);
00261     printf("Netmask: %s\n", addr.get_ip_address() ? addr.get_ip_address() : "None");
00262     net->get_gateway(&addr);
00263     printf("Gateway: %s\n", addr.get_ip_address() ? addr.get_ip_address() : "None");
00264 
00265     /* Open the server on ethernet stack */
00266     server.open(net);
00267 
00268     /* Bind the HTTP port (TCP 80) to the server */
00269     server.bind(PORT);
00270 
00271     /* Listen for clients */
00272     server.listen();
00273 
00274     //listening for http GET request
00275     while (true) {
00276         printf("=========================================\r\n");
00277         printf("Ready to serve clients.\r\n");
00278         net->get_ip_address(&addr);
00279         printf("Usage: Type http:\/\/%s\/%s\/ into your web browser and hit ENTER\r\n", addr.get_ip_address(), PASSWORD);
00280         client = server.accept();
00281         if (client) {
00282             client->getpeername(&addr);
00283             printf("Connection succeeded!\n\rIP: %s\n\r", addr.get_ip_address());
00284             client->recv(httpBuf, 1500);
00285             if (strncmp(httpBuf, "GET", 3) != 0) {
00286                 strcpy(httpHeader, "HTTP/1.0 200 OK");
00287                 strcpy(httpBuf, "<h1>200 OK</h1>");
00288                 sendHTTP(client, httpHeader, httpBuf);
00289             }
00290             else
00291             if ((strncmp(httpBuf, "GET", 3) == 0) && (strncmp(httpBuf + 3, " / ", 3 == 0))) {
00292                 strcpy(httpHeader, "HTTP/1.0 200 OK");
00293                 strcpy(httpBuf, "<p>Usage: http://host_or_ip/password</p>\r\n");
00294                 sendHTTP(client, httpHeader, httpBuf);
00295             }
00296             else {
00297                 int cmd = analyseURL(httpBuf);
00298                 switch (cmd) {
00299                     case -3:
00300                         // update webpage
00301                         strcpy(httpHeader, "HTTP/1.0 200 OK");
00302                         sendHTTP(client, httpHeader, showWebPage(output));
00303                         break;
00304 
00305                     case -2:
00306                         // redirect to the right base url
00307                         strcpy(httpHeader, "HTTP/1.0 301 Moved Permanently\r\nLocation: ");
00308                         sendHTTP(client, httpHeader, movedPermanently(1));
00309                         break;
00310 
00311                     case -1:
00312                         strcpy(httpHeader, "HTTP/1.0 401 Unauthorized");
00313                         strcpy(httpBuf, "<h1>401 Unauthorized</h1>");
00314                         sendHTTP(client, httpHeader, httpBuf);
00315                         break;
00316 
00317                     case 0:
00318                         output = OFF;   // output off
00319                         strcpy(httpHeader, "HTTP/1.0 200 OK");
00320                         sendHTTP(client, httpHeader, showWebPage(output));
00321                         break;
00322 
00323                     case 1:
00324                         output = ON;    // output on
00325                         strcpy(httpHeader, "HTTP/1.0 200 OK");
00326                         sendHTTP(client, httpHeader, showWebPage(output));
00327                         break;
00328                 }
00329             }
00330 
00331             client->close();
00332         }
00333     }
00334 }