Jack Hansdampf / Mbed OS WebSwitch_ENC28J60_GSOE

Dependencies:   UIPEthernet_GSOE

Revision:
10:b47c7921346f
Parent:
5:0ab8292e37da
Child:
11:6c0b20227ca2
--- a/main.cpp	Mon Mar 16 09:43:13 2015 +0000
+++ b/main.cpp	Tue Aug 27 15:03:19 2019 +0000
@@ -1,100 +1,69 @@
-/* 
- * In this project LED1 on the mbed board is switched on/off using a web browser.
- * However, you can easily modify the project to remotely switch on/off any external device.
- * The HTTP server is built from an mbed board and an ENC28J60 board.
- * ENC28J60 is driven by the UIPEthernet library <https://github.com/ntruchsess/arduino_uip>.
- * The example is based on the Tuxgraphics Web Switch <http://www.tuxgraphics.org/>.
- */
-#include <mbed.h>
-#include <UIPEthernet.h>
-#include <UIPServer.h>
-#include <UIPClient.h>
+#include "mbed.h"
 #include <string>
-
-using namespace     std;
+#include "UipEthernet.h"
+#include "TcpServer.h"
+#include "TcpClient.h"
 
-// UIPEthernet is the name of a global instance of UIPEthernetClass.
-// Do not change the name! It is used within the UIPEthernet library.
-#if defined(TARGET_LPC1768)
-UIPEthernetClass    UIPEthernet(p11, p12, p13, p8);         // mosi, miso, sck, cs
-#elif defined(TARGET_LPC1114)
-UIPEthernetClass    UIPEthernet(dp2, dp1, dp6, dp25);       // mosi, miso, sck, cs
-#elif defined(TARGET_LPC11U68)
-UIPEthernetClass    UIPEthernet(P0_9, P0_8, P1_29, P0_2);   // mosi, miso, sck, cs
-#elif defined(TARGET_NUCLEO_F103RB)
-UIPEthernetClass    UIPEthernet(PB_5, PB_4, PB_3, PB_6);    // mosi, miso, sck, cs
-#elif defined(TARGET_NUCLEO_F401RE)
-UIPEthernetClass    UIPEthernet(PB_5, PB_4, PB_3, PB_6);    // mosi, miso, sck, cs
-#elif defined(TARGET_NUCLEO_F411RE)
-UIPEthernetClass    UIPEthernet(PB_5, PB_4, PB_3, PB_6);    // mosi, miso, sck, cs
+using namespace std;
 
-// If your board/plaform is not present yet then uncomment
-// the following two lines and replace TARGET_YOUR_BOARD as appropriate.
-
-//#elif defined(TARGET_YOUR_BOARD)
-//UIPEthernetClass    UIPEthernet(SPI_MOSI, SPI_MISO, SPI_SCK, SPI_CS);   // mosi, miso, sck, cs
-
-#endif
+// To be used when static IP is needed
+#define IP      "192.168.1.35"
+#define GATEWAY "192.168.1.1"
+#define NETMASK "255.255.255.0"
+#define PORT    80
 
-// Note:
-// If it happends that any of the SPI_MOSI, SPI_MISO, SPI_SCK, SPI_CS pins collide with LED1 pin
-// then either use different SPI port (if available on the board) and change the pin names
-// in the constructor UIPEthernet(...) accordingly or instead of using LED1 pin, select
-// a free pin (not used by SPI port) and connect to it an external LED which is connected
-// to a 220 Ohm resitor that is connected to the groud.
-// In the second case remember to replace LED1 in sw(LED1) constructor (see below).
-// MAC number must be unique within the connected network. Modify as appropriate.
-const uint8_t       MY_MAC[6] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x06 };
-
-// IP address must be also unique and compatible with your network. Change as appropriate.
-const IPAddress     MY_IP(192, 168, 1, 181);
-const uint16_t      MY_PORT = 80;           // for HTTP connection
-EthernetServer      myServer = EthernetServer(MY_PORT);
-
-// In this example we are turning on/off LED1.
-DigitalOut          sw(LED1);               // Change LED1 to a pin of your choice.
+// The ENC28J60 chip doesn't have a built-in MAC address.
+// It's up to us to provide one which is unique within the connected network.
+// So modify the one below accordingly.
+const uint8_t   MAC[6] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05 };
+UipEthernet     net(MAC, D11, D12, D13, D10);       // mosi, miso, sck, cs
+TcpServer       server;                             // TCP server running on this mbed device
+TcpClient*      client;                             // TCP client communicating with a HTTP Browser running on a PC or Mobile device
+const int       OFF = 0;
+const int       ON = 1;
+DigitalOut      output(D3);                         // A digital output to be switched on/off
+float           roomTemp = 21.8;                    // A dummy temperature sensor output
+const string    PASSWORD = "secret";                // Change as you like
+string          httpHeader;                         // HTTP header
+string          httpContent;                        // HTTP content
 
-// However, make sure that it does not collide with any of the SPI pins
-// already used in the UIPEthernet(...) constructor above!
-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   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 -3 just refresh page
+ *         -2 no command given but password valid
+ *         -1 invalid password
+ *          0 switch off
+ *          1 switch on
+ */
+int8_t analyseURL(string& url)
+{
+    if (url.length() < 5 + PASSWORD.size() + 1)
+        return(-1);
 
-// analyse the url given
-// return values: -1 invalid password
-//                -2 no command given but password valid
-//                -3 just refresh page
-//                 0 switch off
-//                 1 switch on
-//
-//                The string passed to this function will look like this:
-//                GET /password HTTP/1.....
-//                GET /password/ HTTP/1.....
-//                GET /password/?sw=1 HTTP/1.....
-//                GET /password/?sw=0 HTTP/1.....
-int8_t analyse_get_url(string& str) {
-    if(str.substr(5, PASSWORD.size()) != PASSWORD)
+    if (url.substr(5, PASSWORD.size()) != PASSWORD)
         return(-1);
 
     uint8_t pos = 5 + PASSWORD.size();
 
-    if(str.substr(pos, 1) == " ")
-        return(-2);
-
-    if(str.substr(pos, 1) != "/")
+    if (url.substr(pos, 1) != "/")
         return(-1);
 
-    pos++;
+    if (url.substr(pos++, 1) == " ")
+        return(-2);
 
-    string  cmd(str.substr(pos, 5));
+    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);
@@ -106,8 +75,9 @@
  * @param
  * @retval
  */
-string& moved_perm(uint8_t flag) {
-    if(flag == 1)
+string& movedPermanently(uint8_t flag)
+{
+    if (flag == 1)
         httpContent = "/" + PASSWORD + "/";
     else
         httpContent = "";
@@ -123,43 +93,92 @@
  * @param
  * @retval
  */
-string& view(uint8_t status) {
-    httpContent = "<h2>Web Switch</h2>\r\n";
+string& showWebPage(int status)
+{
+    char    roomTempStr[5];
+
+    //roomTemp = ds1820.read();
+    sprintf(roomTempStr, "%3.1f", roomTemp);
 
-    if(status == 1) {
-        httpContent += "<pre>\r\n  <font color=#FF0000>ON</font>";
-        httpContent += " <a href=\"./?sw=0\">[switch off]</a>\r\n";
+    /*$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\"> "
+            "<input type=\"checkbox\" checked>";
     }
     else {
-        httpContent += "<pre>\r\n  <font color=#00FF00>OFF</font>";
-        httpContent += " <a href=\"./?sw=1\">[switch on]</a>\r\n";
+        httpContent +=
+            "<a href=\"./?sw=1\" class=\"switch\"> "
+            "<input type=\"checkbox\">";
     }
 
-    httpContent += "  <a href=\".\">[refresh status]</a>\r\n";
-    httpContent += "</pre>\r\n";
-    httpContent += "<hr>\r\n";
-    return httpContent;
-}
+    httpContent +=
+        "<div class=\"slider\"></div>"
+        "</a>"
+        "</pre>"
+        "<hr>"
+        "<pre>2017 ARMmbed</pre>"
+        "</body>";
 
-/**
- * @brief
- * @note
- * @param
- * @retval
- */
-void http_send(EthernetClient& client, string& header, string& content) {
-    char    content_length[5] = { };
-
-    header += "\r\nContent-Type: text/html\r\n";
-    header += "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";
-
-    string  webpage = header + content;
-    client.write((uint8_t*)webpage.c_str(), webpage.length());
+    return httpContent;
+    /*$on*/
 }
 
 /**
@@ -168,60 +187,124 @@
  * @param
  * @retval
  */
-int main(void) {
-    UIPEthernet.begin(MY_MAC, MY_IP);
-    myServer.begin();
-    while(1) {
-        EthernetClient  client = myServer.available();
-        if(client) {
-            size_t  size = client.available();
-            if(size > 0) {
+void sendHTTP(TcpClient& client, string& header, string& content)
+{
+    /*$off*/
+    char    content_length[5] = { };
+
+    header +=
+        "\r\nContent-Type: text/html\r\n"
+        "Content-Length: ";
+    sprintf(content_length, "%d", content.length());
+    header +=
+        string(content_length) + "\r\n"
+        "Pragma: no-cache\r\n"
+        "Connection: About to close\r\n\r\n";
+
+    string  webpage = header + content;
+    client.write((uint8_t*)webpage.c_str(), webpage.length());
+    /*$on*/
+}
+
+/**
+ * @brief
+ * @note
+ * @param
+ * @retval
+ */
+int main(void)
+{
+    printf("Starting ...\r\n");
+
+    // IP address must be unique and compatible with your network.
+    //net->set_network(IP, NETMASK, GATEWAY);  // include this for using static IP address
+    net.connect();
+
+    // 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\r\n", ip ? ip : "None");
+    printf("Netmask: %s\r\n", netmask ? netmask : "None");
+    printf("Gateway: %s\r\n\r\n", gateway ? gateway : "None");
+    printf("------------------------------------------------------\r\n");
+    printf("Usage: Type %s/%s/ into your web browser and hit ENTER\r\n\r\n", net.get_ip_address(), PASSWORD.c_str());
+    printf("------------------------------------------------------\r\n");
+
+    /* Open the server on ethernet stack */
+    server.open(&net);
+
+    /* Bind the HTTP port (TCP 80) to the server */
+    server.bind(PORT);
+
+    /* Can handle 5 simultaneous connections */
+    server.listen(5);
+
+    while (1) {
+        client = server.accept();
+
+        if (client) {
+            size_t  size = client->available();
+
+            if (size > 0) {
                 uint8_t*    buf = (uint8_t*)malloc(size);
-                size = client.read(buf, size);
+                size = client->read(buf, size);
+
                 string  received((char*)buf);
                 free(buf);
-                
-                if(received.substr(0, 3) != "GET") {
-                    httpHeader = HTTP_OK;
+
+                if (received.substr(0, 3) != "GET") {
+                    httpHeader = "HTTP/1.0 200 OK";
                     httpContent = "<h1>200 OK</h1>";
-                    http_send(client, httpHeader, httpContent);
-                    continue;
-                }
-
-                if(received.substr(0, 6) == "GET / ") {
-                    httpHeader = HTTP_OK;
-                    httpContent = "<p>Usage: http://host_or_ip/password</p>\r\n";
-                    http_send(client, httpHeader, httpContent);
+                    sendHTTP(*client, httpHeader, httpContent);
+                    client->close();
                     continue;
                 }
 
-                int cmd = analyse_get_url(received);
-
-                if(cmd == -2) {
-                    // redirect to the right base url
-                    httpHeader = MOVED_PERM;
-                    http_send(client, httpHeader, moved_perm(1));
+                if (received.substr(0, 6) == "GET / ") {
+                    httpHeader = "HTTP/1.0 200 OK";
+                    httpContent = "<p>Usage: http://host_or_ip/password</p>\r\n";
+                    sendHTTP(*client, httpHeader, httpContent);
+                    client->close();
                     continue;
                 }
 
-                if(cmd == -1) {
-                    httpHeader = UNAUTHORIZED;
-                    httpContent = "<h1>401 Unauthorized</h1>";
-                    http_send(client, httpHeader, httpContent);
-                    continue;
-                }
+                int cmd = analyseURL(received);
+
+                switch (cmd) {
+                    case -3:
+                        // update webpage
+                        httpHeader = "HTTP/1.0 200 OK";
+                        sendHTTP(*client, httpHeader, showWebPage(output));
+                        break;
+
+                    case -2:
+                        // redirect to the right base url
+                        httpHeader = "HTTP/1.0 301 Moved Permanently\r\nLocation: ";
+                        sendHTTP(*client, httpHeader, movedPermanently(1));
+                        break;
 
-                if(cmd == 1) {
-                    sw = 1; // switch on
-                }
+                    case -1:
+                        httpHeader = "HTTP/1.0 401 Unauthorized";
+                        httpContent = "<h1>401 Unauthorized</h1>";
+                        sendHTTP(*client, httpHeader, httpContent);
+                        break;
 
-                if(cmd == 0) {
-                    sw = 0; // switch off
-                }
+                    case 0:
+                        output = OFF;       // output off
+                        httpHeader = "HTTP/1.0 200 OK";
+                        sendHTTP(*client, httpHeader, showWebPage(output));
+                        break;
 
-                httpHeader = HTTP_OK;
-                http_send(client, httpHeader, view(sw));
+                    case 1:
+                        output = ON;        // output on
+                        httpHeader = "HTTP/1.0 200 OK";
+                        sendHTTP(*client, httpHeader, showWebPage(output));
+                        break;
+                }
             }
+            client->close();
         }
     }
 }