Backing up an unused program in case of future need

Dependencies:   mbed

server.cpp

Committer:
andrewboyson
Date:
2016-04-22
Revision:
2:06fa34661f19
Parent:
1:94282484baae
Child:
5:6226f3c566ef

File content as of revision 2:06fa34661f19:

#include  "esp.h"
#include   "at.h"
#include   "io.h"
#include  "log.h"
#include "time.h"
#include "wifi.h"
#define RECV_BUFFER_SIZE 1024
#define SEND_BUFFER_SIZE  256
#define SERVER_PORT 80

static char recvbuffer[RECV_BUFFER_SIZE];
static char sendbuffer[SEND_BUFFER_SIZE];

#define WHAT_NOT_FOUND   0
#define WHAT_BAD_REQUEST 1
#define WHAT_BAD_METHOD  2
#define WHAT_LED         3
#define WHAT_LOG         4
static int whatToSendToId[4];
static int lineToSendToId[4]; //0 == do nothing; -1 == close

int ServerInit(void) //Make sure this is only called after any other ids are reserved.
{
    for (int id = 0; id < 4; id++)
    {
        if (!EspIpdReserved[id])
        {
            EspIpdBuffer[id] = recvbuffer;
            EspIpdBufferLen[id] = RECV_BUFFER_SIZE;
        }
        whatToSendToId[id] = 0;
        lineToSendToId[id] = 0;
    }
    return 0;
}

static int addChunk(int prevlen, char *text)
{
    strncpy(sendbuffer + prevlen, text, SEND_BUFFER_SIZE - prevlen);
    int len = prevlen + strlen(text);
    return len < SEND_BUFFER_SIZE ? len : SEND_BUFFER_SIZE;
}
static int fillChunk(char * text)
{
    strncpy(sendbuffer, text, SEND_BUFFER_SIZE);
    int len = strlen(text);
    return len < SEND_BUFFER_SIZE ? len : SEND_BUFFER_SIZE;
}
static int fillNotFound(int id)
{
    int len = fillChunk("HTTP/1.0 404 Not Found\r\n\r\n");
    lineToSendToId[id] = -1;
    return len;
}
static int fillBadRequest(int id)
{
    int len = fillChunk("HTTP/1.0 400 Bad Request\r\n\r\n");
    lineToSendToId[id] = -1;
    return len;
}
static int fillBadMethod(int id)
{
    int len = fillChunk("HTTP/1.0 405 Method Not Allowed\r\nAllow: GET\r\n\r\n");
    lineToSendToId[id] = -1;
    return len;
}
static int fillLogChunk() //Returns length. If length is less than the buffer size then that was the last chunk to send: that could mean a length of zero.
{
    static int enumerationStarted = false;
    if (!enumerationStarted)
    {
        LogEnumerateStart();
        enumerationStarted = true;
    }
    char* p = sendbuffer;
    while (p < sendbuffer + SEND_BUFFER_SIZE)
    {
        int c = LogEnumerate();
        if (c == EOF)
        {
            enumerationStarted = false;
            break;
        }
        *p++ = c;
    }
    return p - sendbuffer;
}
static char* header = 
            "HTTP/1.0 200 OK\r\n"
            "Content-Type: text/html; charset=ISO-8859-1\r\n"
            "\r\n"
            "<!DOCTYPE html>\r\n"
            "<html>\r\n"
            "<head>\r\n"
            "<title>IoT mbed</title>\r\n"
            "</head>\r\n"
            "<body>\r\n";

static int fillLog(int id)
{
    int len = 0;

    switch (lineToSendToId[id])
    {
        case 1: len = fillChunk(header);                             lineToSendToId[id] += 1; break;
        case 2: len = fillChunk("<code><pre>");                      lineToSendToId[id] += 1; break;
        case 3: len = fillLogChunk();    if (len < SEND_BUFFER_SIZE) lineToSendToId[id] += 1; break; //only increments after the last chunk
        case 4: len = fillChunk(
            "</pre></code>\r\n"
            "</body>\r\n"
            "</html>\r\n");
            lineToSendToId[id] = -1;
            break;
    }
    return len;
}

static int fillLed(int id)
{
    int len;
    switch (lineToSendToId[id])
    {
        case 1:
            len = fillChunk(header);
            lineToSendToId[id] += 1;
            break;
        case 2:
            len = fillChunk("Version: ");
            len = addChunk(len, AtEspVersion);
            len = addChunk(len, "\r\n");
            lineToSendToId[id] += 1;
            break;
        case 3:
            len = fillChunk(
            "<form action='/' method='get'>\r\n"
            "<input type='hidden' name='ledonoff'>\r\n");
            lineToSendToId[id] += 1;
            break;
        case 4:
            len = fillChunk("Led <input type='checkbox' name='led' value='on'");
            if (Led1) len = addChunk(len, " checked='checked'");
            len = addChunk(len, ">\r\n");
            lineToSendToId[id] +=  1;
            break;
        case 5:
            len = fillChunk(
            "<input type='submit' value='Set'><br/>\r\n"
            "</form>\r\n"
            "</body>\r\n"
            "</html>\r\n");
            lineToSendToId[id] = -1;
            break;
    }
    return len;
}
static int fillSendBuffer(int id)
{
    switch(whatToSendToId[id])
    {
        case WHAT_NOT_FOUND:   return fillNotFound(id);
        case WHAT_BAD_REQUEST: return fillBadRequest(id);
        case WHAT_BAD_METHOD:  return fillBadMethod(id);
        case WHAT_LOG:         return fillLog(id);
        case WHAT_LED:         return fillLed(id);
        default:
            LogF("No such 'whatToSendToId' %s", whatToSendToId[id]);
            return -1;
    }
}
static int splitRequest(char** ppMethod, char** ppPath, char** ppQuery, int *pLenMethod, int *pLenPath, int *pLenQuery) //returns 1 if malformed request; 0 if ok
{
    char* p  = recvbuffer;
    char* pE = recvbuffer + RECV_BUFFER_SIZE;
    
    *ppMethod   = NULL;
    *ppPath     = NULL;
    *ppQuery    = NULL;
    *pLenMethod = 0;
    *pLenPath   = 0;
    *pLenQuery  = 0;

    while (*p == ' ')                   //Loop to non space
    {
        if (p == pE)     return -1;
        if (*p < ' ')    return -1;
        if (*p >= 0x7f)  return -1;
        p++;
    }
    *ppMethod = p;                      //Record the start of the method GET or POST
 
    while (*p != ' ')                   //Loop to a space
    {
        if (p == pE)     return -1;
        if (*p < ' ')    return -1;
        if (*p >= 0x7f)  return -1;
        p++;
    }
    *pLenMethod = p - *ppMethod;        //Record the length of the method GET or POST
    

    while (*p == ' ')         //Loop to non space
    {
        if (p == pE)     return -1;
        if (*p < ' ')    return -1;
        if (*p >= 0x7f)  return -1;
        p++;
    }
    *ppPath = p;                        //Record the start of the file part of the url
    
    while (*p != ' ')                   //Loop to space
    {
        if (p == pE)     return -1;
        if (*p < ' ')    return -1;
        if (*p >= 0x7f)  return -1;
        if (*p == '?')  *ppQuery = p + 1;
        p++;
    }

    if (*ppQuery)                       //Calulate length of the file and query parts
    {
        *pLenPath  = *ppQuery - *ppPath - 1;
        *pLenQuery = p - *ppQuery;
    }
    else
    {
        *pLenPath = p - *ppPath;
        *pLenQuery = 0;
    }
    
    return 0;
}
int compare(char* mem, int len, char* str) //Returns true if same and false if not
{
    if (strlen(str) != len) return false;
    if (memcmp(mem, str, len)) return false;
    return true;
}
static int recvMain()
{
    //Wait for data to be available oneshot
    if (EspDataAvailable != ESP_AVAILABLE) return 0;
    
    //Ignore ids that have been reserved elsewhere (ie NTP)
    if (EspIpdReserved[EspIpdId]) return 0;
    
    //Set up the next line to send to be the first
    lineToSendToId[EspIpdId] = 1;
    
    char* pMethod;
    char* pPath;
    char* pQuery;
    int lenMethod;
    int lenQuery;
    int lenPath;
    int r = splitRequest(&pMethod, &pPath, &pQuery, &lenMethod, &lenPath, &lenQuery);
    if (r)
    {
        whatToSendToId[EspIpdId] = WHAT_BAD_REQUEST;
        return 0;
    }

    if (!compare(pMethod, lenMethod, "GET"))
    {
        whatToSendToId[EspIpdId] = WHAT_BAD_METHOD;
        return 0;
    }
    
    if (compare(pPath, lenPath, "/"))
    {
        if (pQuery)
        {
             if (compare(pQuery, lenQuery, "ledonoff=&led=on")) Led1 = 1;
             if (compare(pQuery, lenQuery, "ledonoff="       )) Led1 = 0;
        }
        whatToSendToId[EspIpdId] = WHAT_LED;
        return 0;
    }
    
    if (compare(pPath, lenPath, "/log"))
    {
        whatToSendToId[EspIpdId] = WHAT_LOG;
        return 0;
    }
    
    whatToSendToId[EspIpdId] = WHAT_NOT_FOUND;
    return 0;
}
static int sendMain()
{
    //Do nothing if a command is already in progress
    if (AtBusy()) return 0;
    
    //Send data. Do each id in turn to avoid interleaved calls to fillers like LogEnumerate which are not reentrant.
    for(int id = 0; id < 4; id++)
    {
        if (lineToSendToId[id] > 0)
        {
            int length = fillSendBuffer(id);
            if (length < 0) return -1;
            if (length > 0) AtSendData(id, length, sendbuffer, NULL);
        }
        else if (lineToSendToId[id] < 0)
        {
            AtClose(id, NULL);
            lineToSendToId[id] = 0;
        }
    }

    return 0;
}
int startMain()
{
    //Do nothing if a command is already in progress
    if (AtBusy()) return 0;
    
    //Do nothing until WiFi is running
    if (!WifiStarted()) return 0;
    
    //Start the server if not started
    static int startServerReply = AT_NONE;
    if (startServerReply != AT_SUCCESS) AtStartServer(SERVER_PORT, &startServerReply);
    return 0;
}
int ServerMain()
{
    if (startMain()) return -1;
    if ( recvMain()) return -1;
    if ( sendMain()) return -1;
    
    return 0;
}