Jack Hansdampf / Mbed OS WebSwitch_ENC28J60_GSOE

Dependencies:   UIPEthernet_GSOE

main.cpp

Committer:
hudakz
Date:
2020-06-05
Revision:
15:9beb9b99695d
Parent:
14:810ac368dd6e
Child:
18:02264a85fdda

File content as of revision 15:9beb9b99695d:

#include "mbed.h"
#include <string>
#include "UipEthernet.h"
#include "TcpServer.h"
#include "TcpClient.h"

//#define DEBUG
// Static IP address must be unique and compatible with your network.
#define IP      "192.168.1.35"
#define GATEWAY "192.168.1.1"
#define NETMASK "255.255.255.0"
#define PORT    80
const uint8_t   MAC[6] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x06 };
UipEthernet     net(MAC, D11, D12, D13, D10);   // mosi, miso, sck, cs
TcpServer       server;                         // Ethernet server
TcpClient*      client;
char            httpBuf[1500];
char            httpHeader[256];
const int       OFF = 0;
const int       ON = 1;
DigitalOut      output(D3);                     // A digital output to be switched on/off
float           roomTemp = 21.8f;               // A temperature sensor output
const char      PASSWORD[] = "secret";          // Change as you like

/**
 * @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(char* url)
{
    if (strlen(url) < (5 + strlen(PASSWORD) + 1))
        return(-1);

    //if (url.substr(5, PASSWORD.size()) != PASSWORD)
    if (strncmp(url + 5, PASSWORD, strlen(PASSWORD)) != 0)
        return(-1);

    uint8_t pos = 5 + strlen(PASSWORD);

    //if (url.substr(pos, 1) != "/")

    if (*(url + pos) != '/')
        return(-1);

    //if (url.substr(pos++, 1) == " ")
    if (*(url + pos++) == ' ')
        return(-2);

    //string  cmd(url.substr(pos, 5));
    *(url + pos + 5) = '\0';    // terminate the cmd string
    char*   cmd = ((url + pos));
    if (strcmp(cmd, "?sw=0") == 0)
        return(0);
    if (strcmp(cmd, "?sw=1") == 0)
        return(1);
    return(-3);
}

/**
 * @brief
 * @note
 * @param
 * @retval
 */
char* movedPermanently(uint8_t flag)
{
    memset(httpBuf, 0, sizeof(httpBuf));
    if (flag == 1) {
        strcpy(httpBuf, "/");
        strcat(httpBuf, PASSWORD);
        strcat(httpBuf, "/");
    }

    strcat(httpBuf, "<h1>301 Moved Permanently</h1>\r\n");
    return(httpBuf);
}

/**
 * @brief
 * @note
 * @param
 * @retval
 */
char* showWebPage(int status)
{
    char    roomTempStr[10] = { };

    //roomTemp = ds1820.read();

    sprintf(roomTempStr, "%3.1f", roomTemp);
    memset(httpBuf, 0, sizeof(httpBuf));
    /*$off*/
    strcat
    (
        httpBuf,
        "<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"
    );
    strcat(httpBuf, roomTempStr);
    strcat(httpBuf, "&deg;C</pre>");
    strcat
    (
       httpBuf,
       "<pre>Heating:\t"
    );
    if(status == ON) {
       strcat
       (
           httpBuf,
           "<a href=\"./?sw=0\" class=\"switch\"> "
           "<input type=\"checkbox\" checked>"
       );
    }
    else {
       strcat
       (
           httpBuf,
           "<a href=\"./?sw=1\" class=\"switch\"> "
           "<input type=\"checkbox\">"
       );
    }
    strcat
    (
       httpBuf,
           "<div class=\"slider\"></div>"
           "</a>"
           "</pre>"
           "<hr>"
           "<pre>2017 ARMmbed</pre>"
       "</body>"
    );
    /*$on*/
    return httpBuf;
}

/**
 * @brief
 * @note
 * @param
 * @retval
 */
void sendHTTP(TcpClient* client, char* header, char* content)
{
    char    content_length[10] = { };

    sprintf(content_length, "%u\r\n", strlen(content));

    strcat(header, "\r\nContent-Type: text/html\r\n");
    strcat(header, "Content-Length: ");
    strcat(header, content_length);
    strcat(header, "Pragma: no-cache\r\n");
    strcat(header, "Connection: About to close\r\n\r\n");

    char c = content[0];
    memmove(httpBuf + strlen(header), httpBuf, strlen(content)); // make room for the header
    strcpy(httpBuf, header); // copy the header on front of the content
    httpBuf[strlen(header)] = c;
    client->send((uint8_t*)httpBuf, strlen(httpBuf));
}

/**
 * @brief
 * @note
 * @param
 * @retval
 */
int main(void)
{
    printf("Starting ...\r\n");

    //net.set_network(IP, NETMASK, GATEWAY);  // include this for using static IP address
    if (net.connect(30) != 0) {

        // 'connect' timeout in seconds (defaults to 60 sec)
        printf("Unable to connet.\r\n");
        return -1;
    }

    // Show the network address
    SocketAddress   addr;
    net.get_ip_address(&addr);
    printf("IP address: %s\n", addr.get_ip_address() ? addr.get_ip_address() : "None");
    net.get_netmask(&addr);
    printf("Netmask: %s\n", addr.get_ip_address() ? addr.get_ip_address() : "None");
    net.get_gateway(&addr);
    printf("Gateway: %s\n", addr.get_ip_address() ? addr.get_ip_address() : "None");

    /* Open the server on ethernet stack */
    server.open(&net);

    /* Bind the HTTP port (TCP 80) to the server */
    server.bind(PORT);

    /* Can handle 4 simultaneous connections */
    server.listen(4);

    while (true) {
        client = server.accept();
        if (client) {
            switch (client->recv((uint8_t*)httpBuf, client->available())) {
                case 0:
                    printf("recieved buffer is empty.\n\r");
                    break;

                case -1:
                    printf("failed to read data from client.\n\r");
                    break;

                default:
    #ifdef DEBUG
                    printf("Client with IP address %s connected.\r\n\r\n", client->getpeername());
                    printf("Data received:\r\n%s\n\r", receiveBuf);
    #endif
                    if (strncmp(httpBuf, "GET", 3) != 0) {
                        strcpy(httpHeader, "HTTP/1.0 200 OK");
                        strcpy(httpBuf, "<h1>200 OK</h1>");
                        sendHTTP(client, httpHeader, httpBuf);
                    }
                    else
                    if ((strncmp(httpBuf, "GET", 3) == 0) && (strncmp(httpBuf + 3, " / ", 3 == 0))) {
                        strcpy(httpHeader, "HTTP/1.0 200 OK");
                        strcpy(httpBuf, "<p>Usage: http://host_or_ip/password</p>\r\n");
                        sendHTTP(client, httpHeader, httpBuf);
                    }
                    else {
                        int cmd = analyseURL(httpBuf);
                        switch (cmd) {
                            case -3:
                                // update webpage
                                strcpy(httpHeader, "HTTP/1.0 200 OK");
                                sendHTTP(client, httpHeader, showWebPage(output));
                                break;

                            case -2:
                                // redirect to the right base url
                                strcpy(httpHeader, "HTTP/1.0 301 Moved Permanently\r\nLocation: ");
                                sendHTTP(client, httpHeader, movedPermanently(1));
                                break;

                            case -1:
                                strcpy(httpHeader, "HTTP/1.0 401 Unauthorized");
                                strcpy(httpBuf, "<h1>401 Unauthorized</h1>");
                                sendHTTP(client, httpHeader, httpBuf);
                                break;

                            case 0:
                                output = OFF;   // output off
                                strcpy(httpHeader, "HTTP/1.0 200 OK");
                                sendHTTP(client, httpHeader, showWebPage(output));
                                break;

                            case 1:
                                output = ON;    // output on
                                strcpy(httpHeader, "HTTP/1.0 200 OK");
                                sendHTTP(client, httpHeader, showWebPage(output));
                                break;
                        }
                    }
            }

            client->close();
        }
    }
}