Andrew Boyson / Mbed 2 deprecated iot

Dependencies:   mbed

Files at this revision

API Documentation at this revision

Comitter:
andrewboyson
Date:
Fri Apr 15 09:03:54 2016 +0000
Parent:
0:09f915e6f9f6
Child:
2:06fa34661f19
Commit message:
Streamed the log in chunks to allow the send buffer to be reduced. That in turn allowed the log buffer to be increased.; Added content type text/html to http responses.

Changed in this revision

at.cpp Show annotated file Show diff for this revision Revisions of this file
log.cpp Show annotated file Show diff for this revision Revisions of this file
server.cpp Show annotated file Show diff for this revision Revisions of this file
wifi.cpp Show annotated file Show diff for this revision Revisions of this file
--- a/at.cpp	Wed Apr 13 09:21:02 2016 +0000
+++ b/at.cpp	Fri Apr 15 09:03:54 2016 +0000
@@ -185,6 +185,7 @@
             LogCrLf("Esp timed out");
             break;
         case ESP_OVERFLOW:
+            if (wait_for == WAIT_FOR_ESP_READY) break; //Ignore overflows from the esp's 450 byte boot message
             finishAndReset(AT_LINE_OVERFLOW);
             LogCrLf("Esp buffer overflow");
             break;
--- a/log.cpp	Wed Apr 13 09:21:02 2016 +0000
+++ b/log.cpp	Fri Apr 15 09:03:54 2016 +0000
@@ -6,7 +6,7 @@
 
 LocalFileSystem local("local");
 
-#define BUFFER_LENGTH 512
+#define BUFFER_LENGTH 2048
 static char buffer[BUFFER_LENGTH];
 static char* pPush; //Initialised in init
 static char* pPull; //Initialised in init
--- a/server.cpp	Wed Apr 13 09:21:02 2016 +0000
+++ b/server.cpp	Fri Apr 15 09:03:54 2016 +0000
@@ -4,11 +4,20 @@
 #include  "log.h"
 #include "time.h"
 #include "wifi.h"
-#define BUFFER_SIZE 1024
+#define RECV_BUFFER_SIZE 1024
+#define SEND_BUFFER_SIZE  256
 #define SERVER_PORT 80
 
-static char recvbuffer[BUFFER_SIZE];
-static char sendbuffer[BUFFER_SIZE];
+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
 
 void ServerInit(void) //Make sure this is only called after any other ids are reserved.
 {
@@ -17,84 +26,299 @@
         if (!EspIpdReserved[id])
         {
             EspIpdBuffer[id] = recvbuffer;
-            EspIpdBufferLen[id] = BUFFER_SIZE;
+            EspIpdBufferLen[id] = RECV_BUFFER_SIZE;
+        }
+        whatToSendToId[id] = 0;
+        lineToSendToId[id] = 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(
+            "<form action='/' method='get'>\r\n"
+            "<input type='hidden' name='ledonoff'>\r\n");
+            lineToSendToId[id] += 1;
+            break;
+        case 3:
+            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 4:
+            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;
     }
 }
-int ServerStatus = AT_NONE;
-int ServerMain(void)
+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;
 
-    if (!AtBusy() && WifiStarted() && ServerStatus != AT_SUCCESS) AtStartServer(SERVER_PORT, &ServerStatus);
-        
-    static int needToSendId = -1;
-    static int needToCloseId  = -1;
+    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
     
-    if (EspDataAvailable == ESP_AVAILABLE && !EspIpdReserved[EspIpdId])
+
+    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
     {
-        needToSendId = EspIpdId;
-        char method[10];
-        char url[20];
-        char file[20];
-        char query[20];
-        sscanf(recvbuffer, "%s %s ", method, url);
-        sscanf(url, "%[^?]?%s", file, query);
-        if (strcmp(file, "/favicon.ico") == 0)
-            strcpy(sendbuffer, "HTTP/1.0 404 Not Found\r\n\r\n");
-        else if (strcmp(file, "/log") == 0)
+        *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)
         {
-            strcpy(sendbuffer, "HTTP/1.0 200 OK\r\n");
-            strcat(sendbuffer, "\r\n");
-            strcat(sendbuffer, "<html>\r\n");
-            strcat(sendbuffer, "<body>\r\n");
-            strcat(sendbuffer, "<code><pre>");
-            LogEnumerateStart();
-            char* p = sendbuffer;
-            while(*p) p++; //Move to the end of string
-            while (1)
-            {
-                int c = LogEnumerate();
-                if (c == EOF) break;
-                *p++ = c;
-            }
-            *p = 0; //Add back the end of string
-            strcat(sendbuffer, "</pre></code>");
-            strcat(sendbuffer, "</body>\r\n");
-            strcat(sendbuffer, "</html>\r\n");
+             if (compare(pQuery, lenQuery, "ledonoff=&led=on")) Led1 = 1;
+             if (compare(pQuery, lenQuery, "ledonoff="       )) Led1 = 0;
         }
-        else
+        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)
         {
-            if (strcmp(query, "ledonoff=&led=on") == 0) Led1 = 1;
-            if (strcmp(query, "ledonoff="       ) == 0) Led1 = 0;
-            strcpy(sendbuffer, "HTTP/1.0 200 OK\r\n");
-            strcat(sendbuffer, "\r\n");
-            strcat(sendbuffer, "<html>\r\n");
-            strcat(sendbuffer, "<body>\r\n");
-            strcat(sendbuffer, "<form action='/' method='get'>\r\n");
-            strcat(sendbuffer, "<input type='hidden' name='ledonoff'>\r\n");
-            if (Led1) strcat(sendbuffer, "Led <input type='checkbox' name='led' value='on' checked='checked'>\r\n");
-            else      strcat(sendbuffer, "Led <input type='checkbox' name='led' value='on'>\r\n");
-            strcat(sendbuffer, "<input type='submit' value='Set'><br/>\r\n");
-            strcat(sendbuffer, "</form>\r\n");
-            strcat(sendbuffer, "</body>\r\n");
-            strcat(sendbuffer, "</html>\r\n");
-//            sprintf(sendbuffer, "Received a %s request for %s and query %s\r\n", method, file, query);
+            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;
         }
     }
 
-    if (!AtBusy() && needToSendId >= 0)
-    {
-        AtSendData(needToSendId, strlen(sendbuffer), sendbuffer, NULL);
-        needToCloseId = needToSendId;
-        needToSendId = -1;
-    }
+    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;
     
-    if (!AtBusy() && needToCloseId >= 0)
-    {
-        AtClose(needToCloseId, NULL);
-        needToCloseId = -1;
-    }
-    
+    //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;
 }
\ No newline at end of file
--- a/wifi.cpp	Wed Apr 13 09:21:02 2016 +0000
+++ b/wifi.cpp	Fri Apr 15 09:03:54 2016 +0000
@@ -142,7 +142,6 @@
             }
             break;
         case AM_STARTED:
-            LogEnable(false);
             return 0;
         default:
             LogF("Unknown \'am\' %d", am);