Webserver controller with url trimming for value controls

Dependencies:   LCD_DISCO_F746NG BSP_DISCO_F746NG

main.cpp

Committer:
hudakz
Date:
2018-10-30
Revision:
8:47b0cb4b5b7d
Parent:
7:02a0635aeeac
Child:
9:161bed13b17e

File content as of revision 8:47b0cb4b5b7d:

#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
 
EthernetInterface*  net;

TCPServer           server;
TCPSocket           clientSocket;
SocketAddress       clientAddress;
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: ";
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;
//};
 
/**
 * @brief   Analyses the received URL
 * @note    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.....
 * @param   url URL string
 * @retval -1 invalid password
 *         -2 no command given but password valid
 *         -3 just refresh page
 *          0 switch off
 *          1 switch on
 */
int8_t analyseURL(string& url) {
    if(url.substr(5, PASSWORD.size()) != PASSWORD)
        return(-1);
 
    uint8_t pos = 5 + PASSWORD.size();
 
    if(url.substr(pos, 1) == " ")
        return(-2);
 
    if(url.substr(pos++, 1) != "/")
        return(-1);
 
    string  cmd(url.substr(pos, 5));
 
    if(cmd == "?sw=0")
        return(0);
 
    if(cmd == "?sw=1")
        return(1);
 
    return(-3);
}
 
/**
 * @brief
 * @note
 * @param
 * @retval
 */
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];
 
    //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";
 
    if(status == ON) {
        httpContent += "<a href=\"./?sw=0\" class=\"switch\"> ";
        httpContent += "<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>";
 
    return httpContent;
}
 
/**
 * @brief
 * @note
 * @param
 * @retval
 */
void sendHTTP(TCPSocket& 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.send((char*)webpage.c_str(), webpage.length());
    printf("HTTP sent.\n\r");
}
 
/**
 * @brief
 * @note
 * @param
 * @retval
 */
int main(void) {
    printf("Starting\r\n");
    
    //net = NetworkInterface::get_default_instance();
    
    net = new EthernetInterface();

    if (!net) {
        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();
    if (r != 0) {
        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());
 
    /* Open the server on ethernet stack */
    server.open(net);
 
    /* Bind the HTTP port (TCP 80) to the server */
    server.bind(ip, 80);
 
    /* 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);
 
        string  received(receiveBuf);
 
        if(received.substr(0, 3) != "GET") {
            httpHeader = HTTP_OK;
            httpContent = "<h1>200 OK</h1>";
            sendHTTP(clientSocket, httpHeader, httpContent);
            continue;
        }
 
        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));
            continue;
        }
 
        if(cmd == -1) {
            httpHeader = UNAUTHORIZED;
            httpContent = "<h1>401 Unauthorized</h1>";
            sendHTTP(clientSocket, httpHeader, httpContent);
            continue;
        }
 
        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));
    }
}