Webserver controller with url trimming for value controls

Dependencies:   LCD_DISCO_F746NG BSP_DISCO_F746NG

Revision:
9:161bed13b17e
Parent:
8:47b0cb4b5b7d
Child:
10:f941e0750773
--- a/main.cpp	Tue Oct 30 16:41:15 2018 +0000
+++ b/main.cpp	Mon Jul 01 17:23:49 2019 +0000
@@ -1,317 +1,327 @@
 #include "mbed.h"
 #include "EthernetInterface.h"
-#include "TCPServer.h"
 #include "TCPSocket.h"
 #include <stdio.h>
 #include <string>
- 
-using namespace     std;
- 
-#define IP         "192.168.1.181"
-#define GATEWAY    "192.168.1.1"
-#define NETMASK    "255.255.255.0"
- 
- 
-#define PORT        80
- 
+
+using namespace std;
+
+#define IP      "192.168.1.181"
+#define GATEWAY "192.168.1.1"
+#define NETMASK "255.255.255.0"
+#define PORT    80
+
+Serial              pc(USBTX, USBRX);
 EthernetInterface*  net;
-
-TCPServer           server;
-TCPSocket           clientSocket;
+TCPSocket           server;
+TCPSocket*          clientSocket;
 SocketAddress       clientAddress;
-char                receiveBuf[1024] = { };
- 
+char                receiveBuf[1024];
 const int           OFF = 0;
 const int           ON = 1;
- 
-DigitalOut          sw(LED1);
-float               roomTemp = 21.8;    // A temperature sensor output
- 
-const string        PASSWORD     = "secret";    // change as you like
-const string        HTTP_OK      = "HTTP/1.0 200 OK";
-const string        MOVED_PERM   = "HTTP/1.0 301 Moved Permanently\r\nLocation: ";
+DigitalOut          sw(LED1);               // A digital output to be switched on/off
+float               roomTemp = 21.8;        // A temperature sensor output
+const string        PASSWORD = "secret";    // Change as you like
+const string        HTTP_OK = "HTTP/1.0 200 OK";
+const string        MOVED_PERM = "HTTP/1.0 301 Moved Permanently\r\nLocation: ";
 const string        UNAUTHORIZED = "HTTP/1.0 401 Unauthorized";
-string              httpHeader;     // HTTP header
-string              httpContent;    // HTTP content
- 
-/**
- * @brief   Defines a custom MAC address
- * @note    Uncomment the code below to define a unique MAC address.
- *          Modify the mac array items as needed.
- * @param
- * @retval
- */
-//extern "C" void mbed_mac_address(char* mac) {
-//    mac[0] = 0x00;
-//    mac[1] = 0x01;
-//    mac[2] = 0x02;
-//    mac[3] = 0x03;
-//    mac[4] = 0x04;
-//    mac[5] = 0x05;
-//};
- 
+string              httpHeader;             // HTTP header
+string              httpContent;            // HTTP content
+
 /**
  * @brief   Analyses the received URL
  * @note    The string passed to this function will look like this:
+ *          GET /HTTP/1.....
  *          GET /password HTTP/1.....
  *          GET /password/ HTTP/1.....
  *          GET /password/?sw=1 HTTP/1.....
  *          GET /password/?sw=0 HTTP/1.....
  * @param   url URL string
- * @retval -1 invalid password
+ * @retval -3 just refresh page
  *         -2 no command given but password valid
- *         -3 just refresh page
+ *         -1 invalid password
  *          0 switch off
  *          1 switch on
  */
-int8_t analyseURL(string& url) {
-    if(url.substr(5, PASSWORD.size()) != PASSWORD)
+int8_t analyseURL(string& url)
+{
+    if (url.length() < 5 + PASSWORD.size() + 1)
+        return(-1);
+
+    if (url.substr(5, PASSWORD.size()) != PASSWORD)
         return(-1);
- 
+
     uint8_t pos = 5 + PASSWORD.size();
- 
-    if(url.substr(pos, 1) == " ")
+
+    if (url.substr(pos, 1) != "/")
+        return(-1);
+
+    if (url.substr(pos++, 1) == " ")
         return(-2);
- 
-    if(url.substr(pos++, 1) != "/")
-        return(-1);
- 
+
     string  cmd(url.substr(pos, 5));
- 
-    if(cmd == "?sw=0")
+
+    if (cmd == "?sw=0")
         return(0);
- 
-    if(cmd == "?sw=1")
+
+    if (cmd == "?sw=1")
         return(1);
- 
+
     return(-3);
 }
- 
+
 /**
  * @brief
  * @note
  * @param
  * @retval
  */
-string& movedPermanently(uint8_t flag) {
-    if(flag == 1)
+string& movedPermanently(uint8_t flag)
+{
+    if (flag == 1)
         httpContent = "/" + PASSWORD + "/";
     else
         httpContent = "";
- 
+
     httpContent += "<h1>301 Moved Permanently</h1>\r\n";
- 
+
     return(httpContent);
 }
- 
+
 /**
  * @brief
  * @note
  * @param
  * @retval
  */
-string& showWebPage(uint8_t status) {
-    char roomTempStr[5];
- 
+string& showWebPage(int status)
+{
+    char    roomTempStr[5];
+
     //roomTemp = ds1820.read();
     sprintf(roomTempStr, "%3.1f", roomTemp);
- 
-    // CSS toggle switch
-    httpContent  = "<head>";
-    httpContent += "<style>";
- 
-    httpContent += ".switch {";
-    httpContent += "position: relative;";
-    httpContent += "display: inline-block;";
-    httpContent += "width: 60px;";
-    httpContent += "height: 34px;";
-    httpContent += "}";
- 
-    httpContent += ".switch input {display:none;}";
- 
-    httpContent += ".slider {";
-    httpContent += "position: absolute;";
-    httpContent += "cursor: pointer;";
-    httpContent += "top: 0;";
-    httpContent += "left: 0;";
-    httpContent += "right: 0;";
-    httpContent += "bottom: 0;";
-    httpContent += "border-radius: 34px;";
-    httpContent += "background-color: #ccc;";
-    httpContent += "-webkit-transition: .4s;";
-    httpContent += "transition: .4s;";
-    httpContent += "}";
- 
-    httpContent += ".slider:before {";
-    httpContent += "position: absolute;";
-    httpContent += "content: \"\";";
-    httpContent += "height: 26px;";
-    httpContent += "width: 26px;";
-    httpContent += "left: 4px;";
-    httpContent += "bottom: 4px;";
-    httpContent += "border-radius: 50%;";
-    httpContent += "background-color: white;";
-    httpContent += "-webkit-transition: .4s;";
-    httpContent += "transition: .4s;";
-    httpContent += "}";
- 
-    httpContent += "input:checked + .slider {";
-    httpContent += "background-color: #8ce196;";
-    httpContent += "}";
- 
-    httpContent += "input:focus + .slider {";
-    httpContent += "box-shadow: 0 0 1px #8ce196;";
-    httpContent += "}";
- 
-    httpContent += "input:checked + .slider:before {";
-    httpContent += "-webkit-transform: translateX(26px);";
-    httpContent += "-ms-transform: translateX(26px);";
-    httpContent += "transform: translateX(26px);";
-    httpContent += "}";
- 
-    httpContent += "</style>";
-    httpContent += "</head>";
- 
-    httpContent += "<body>";
-    httpContent += "<h2><a href=\".\" title=\"Click to refresh the page\">Smart Home</a></h2>";
-    httpContent += "<pre>Temperature:\t" + string(roomTempStr) + "&deg;C</pre>";
-    httpContent += "<pre>Heating:\t";
- 
+
+    /*$off*/
+    httpContent  =
+        "<head>"
+        "<meta charset=\"utf-8\">"
+        "<meta name=\"viewport\" content=\" initial-scale=1.0; maximum-scale=1.0; minimum-scale=1.0; user-scalable=0;\"/>"
+        "<title>Smart Home</title>"
+        "<link href='http://fonts.googleapis.com/css?family=Droid+Sans&v1' rel='stylesheet' type='text/css'>"
+        "<style>"
+        ".switch {"
+            "position: relative;"
+            "display: inline-block;"
+            "width: 60px;"
+            "height: 34px;"
+        "}"
+        ".switch input {display:none;}"
+        ".slider {"
+            "position: absolute;"
+            "cursor: pointer;"
+            "top: 0;"
+            "left: 0;"
+            "right: 0;"
+            "bottom: 0;"
+            "border-radius: 34px;"
+            "background-color: #ccc;"
+            "-webkit-transition: .4s;"
+            "transition: .4s;"
+        "}"
+        ".slider:before {"
+            "position: absolute;"
+            "content: \"\";"
+            "height: 26px;"
+            "width: 26px;"
+            "left: 4px;"
+            "bottom: 4px;"
+            "border-radius: 50%;"
+            "background-color: white;"
+            "-webkit-transition: .4s;"
+            "transition: .4s;"
+        "}"
+        "input:checked + .slider {"
+            "background-color: #8ce196;"
+        "}"
+        "input:focus + .slider {"
+            "box-shadow: 0 0 1px #8ce196;"
+        "}"
+        "input:checked + .slider:before {"
+            "-webkit-transform: translateX(26px);"
+            "-ms-transform: translateX(26px);"
+            "transform: translateX(26px);"
+        "}"
+        "</style>"
+        "</head>"
+
+        "<body>"
+        "<h2><a href=\".\" title=\"Click to refresh the page\">Smart Home</a></h2>"
+        "<pre>Temperature:\t" + string(roomTempStr) + "&deg;C</pre>"
+        "<pre>Heating:\t";
+
     if(status == ON) {
-        httpContent += "<a href=\"./?sw=0\" class=\"switch\"> ";
-        httpContent += "<input type=\"checkbox\" checked>";
+        httpContent +=
+            "<a href=\"./?sw=0\" class=\"switch\"> "
+            "<input type=\"checkbox\" checked>";
     }
     else {
-        httpContent += "<a href=\"./?sw=1\" class=\"switch\"> ";
-        httpContent += "<input type=\"checkbox\">";
-   }
- 
-    httpContent += "<div class=\"slider\"></div>";
-    httpContent += "</a></pre>";
-    httpContent += "<hr>";
-    httpContent += "<pre>2017 armMBED</pre>";
-    httpContent += "</body>";
- 
+        httpContent +=
+            "<a href=\"./?sw=1\" class=\"switch\"> "
+            "<input type=\"checkbox\">";
+    }
+
+    httpContent +=
+        "<div class=\"slider\"></div>"
+        "</a>"
+        "</pre>"
+        "<hr>"
+        "<pre>2017 ARMmbed</pre>"
+        "</body>";
+
     return httpContent;
+    /*$on*/
 }
- 
+
 /**
  * @brief
  * @note
  * @param
  * @retval
  */
-void sendHTTP(TCPSocket& client, string& header, string& content) {
+void sendHTTP(TCPSocket& client, string& header, string& content)
+{
+    /*$off*/
     char    content_length[5] = { };
- 
-    header += "\r\nContent-Type: text/html\r\n";
-    header += "Content-Length: ";
+
+    header +=
+        "\r\nContent-Type: text/html\r\n"
+        "Content-Length: ";
     sprintf(content_length, "%d", content.length());
-    header += string(content_length) + "\r\n";
-    header += "Pragma: no-cache\r\n";
-    header += "Connection: About to close\r\n";
-    header += "\r\n";
- 
+    header +=
+        string(content_length) + "\r\n"
+        "Pragma: no-cache\r\n"
+        "Connection: About to close\r\n\r\n";
+
     string  webpage = header + content;
     client.send((char*)webpage.c_str(), webpage.length());
-    printf("HTTP sent.\n\r");
+    pc.printf("HTTP message sent to client.\n\r");
+    /*$on*/
 }
- 
+
 /**
  * @brief
  * @note
  * @param
  * @retval
  */
-int main(void) {
-    printf("Starting\r\n");
-    
-    //net = NetworkInterface::get_default_instance();
-    
+int main(void)
+{
+    pc.printf("Starting.. \r\n\r\n");
+
     net = new EthernetInterface();
 
     if (!net) {
-        printf("Error! No network inteface found.\n");
+        pc.printf("Error! No network inteface found.\n");
         return 0;
     }
 
     //net->set_network (IP, NETMASK, GATEWAY);  // include this for using static IP address
-    
-    nsapi_size_or_error_t r = net->connect();
+    nsapi_size_or_error_t   r = net->connect();
+
     if (r != 0) {
-        printf("Error! net->connect() returned: %d\n", r);
+        pc.printf("Error! net->connect() returned: %d\n", r);
         return r;
     }
 
-   // Show the network address
-    const char *ip = net->get_ip_address();
-    const char *netmask = net->get_netmask();
-    const char *gateway = net->get_gateway();
-    printf("IP address: %s\n", ip ? ip : "None");
-    printf("Netmask: %s\n", netmask ? netmask : "None");
-    printf("Gateway: %s\n", gateway ? gateway : "None");   
-    printf("Usage: Type %s/%s/ into your web browser and hit ENTER\r\n", ip, PASSWORD.c_str());
- 
+    // Show the network address
+    const char*     ip = net->get_ip_address();
+    const char*     netmask = net->get_netmask();
+    const char*     gateway = net->get_gateway();
+    
+    pc.printf("IP address: %s\r\n", ip ? ip : "None");
+    pc.printf("Netmask: %s\r\n", netmask ? netmask : "None");
+    pc.printf("Gateway: %s\r\n\r\n", gateway ? gateway : "None");
+    pc.printf("Usage: Type %s/%s/ into your web browser and hit ENTER\r\n\r\n", ip, PASSWORD.c_str());
+
     /* Open the server on ethernet stack */
     server.open(net);
- 
+
     /* Bind the HTTP port (TCP 80) to the server */
-    server.bind(ip, 80);
- 
+    server.bind(ip, PORT);
+
     /* Can handle 5 simultaneous connections */
     server.listen(5);
- 
+
     //listening for http GET request
-    while(true) {
-        printf("=========================================\r\n");
-        printf("Ready to serve clients.\r\n");
-        server.accept(&clientSocket, &clientAddress);
-        printf("Connection succeeded!\n\rIP: %s\n\r", clientAddress.get_ip_address());
-        clientSocket.recv(receiveBuf, 1023);
-        printf("Recieved Data: %d\n\r\n\r%.*s\n\r", strlen(receiveBuf), strlen(receiveBuf), receiveBuf);
- 
+    while (true) {
+        pc.printf("=========================================\r\n");
+
+        nsapi_error_t   error;
+
+        clientSocket = server.accept(&error);
+        if (error != 0) {
+            pc.printf("Connection failed!\r\n");
+            clientSocket->close();
+            continue;
+        }
+
+        clientSocket->getpeername(&clientAddress);
+        pc.printf("Client with IP address %s connected.\r\n\r\n", clientAddress.get_ip_address());
+        clientSocket->recv(receiveBuf, 1023);
+        pc.printf("Data received:\r\n%s\n\r", receiveBuf);
+
         string  received(receiveBuf);
- 
-        if(received.substr(0, 3) != "GET") {
+
+        if (received.substr(0, 3) != "GET") {
             httpHeader = HTTP_OK;
             httpContent = "<h1>200 OK</h1>";
-            sendHTTP(clientSocket, httpHeader, httpContent);
+            sendHTTP(*clientSocket, httpHeader, httpContent);
+            clientSocket->close();
             continue;
         }
- 
-        if(received.substr(0, 6) == "GET / ") {
+
+        if (received.substr(0, 6) == "GET / ") {
             httpHeader = HTTP_OK;
             httpContent = "<p>Usage: Type http://ip_address/password/ into your web browser and hit ENTER</p>\r\n";
-            sendHTTP(clientSocket, httpHeader, httpContent);
-            continue;
-        }
- 
-        int cmd = analyseURL(received);
- 
-        if(cmd == -2) {
- 
-            // redirect to the right base url
-            httpHeader = MOVED_PERM;
-            sendHTTP(clientSocket, httpHeader, movedPermanently(1));
+            sendHTTP(*clientSocket, httpHeader, httpContent);
+            clientSocket->close();
             continue;
         }
- 
-        if(cmd == -1) {
-            httpHeader = UNAUTHORIZED;
-            httpContent = "<h1>401 Unauthorized</h1>";
-            sendHTTP(clientSocket, httpHeader, httpContent);
-            continue;
+
+        int cmd = analyseURL(received);
+
+        switch (cmd) {
+            case -3:
+                // update webpage
+                httpHeader = HTTP_OK;
+                sendHTTP(*clientSocket, httpHeader, showWebPage(sw));
+                break;
+
+            case -2:
+                // redirect to the right base url
+                httpHeader = MOVED_PERM;
+                sendHTTP(*clientSocket, httpHeader, movedPermanently(1));
+                break;
+
+            case -1:
+                httpHeader = UNAUTHORIZED;
+                httpContent = "<h1>401 Unauthorized</h1>";
+                sendHTTP(*clientSocket, httpHeader, httpContent);
+                break;
+
+            case 0:
+                sw = OFF;   // turn the switch off
+                httpHeader = HTTP_OK;
+                sendHTTP(*clientSocket, httpHeader, showWebPage(sw));
+                break;
+
+            case 1:
+                sw = ON;    // turn the switch on
+                httpHeader = HTTP_OK;
+                sendHTTP(*clientSocket, httpHeader, showWebPage(sw));
+                break;
         }
- 
-        if(cmd == ON) {
-            sw = ON;    // turn the switch on
-        }
- 
-        if(cmd == OFF) {
-            sw = OFF;   // turn the switch off
-        }
- 
-        httpHeader = HTTP_OK;
-        sendHTTP(clientSocket, httpHeader, showWebPage(sw));
+
+        clientSocket->close();
     }
-}
\ No newline at end of file
+}