Adam Green / Mbed 2 deprecated WeatherStation

Dependencies:   FatFileSystem mbed WeatherMeters SDFileSystem

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers main.cpp Source File

main.cpp

00001 /* Copyright 2012 Adam Green (http://mbed.org/users/AdamGreen/)
00002 
00003    Licensed under the Apache License, Version 2.0 (the "License");
00004    you may not use this file except in compliance with the License.
00005    You may obtain a copy of the License at
00006 
00007        http://www.apache.org/licenses/LICENSE-2.0
00008 
00009    Unless required by applicable law or agreed to in writing, software
00010    distributed under the License is distributed on an "AS IS" BASIS,
00011    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00012    See the License for the specific language governing permissions and
00013    limitations under the License.
00014 */
00015 /* Provides a simple web interface to these weather meters from Sparkfun:
00016     http://www.sparkfun.com/products/8942
00017 */
00018 #include <stdarg.h>
00019 #include <mbed.h>
00020 #include "SDFileSystem.h"
00021 #include "network.h"
00022 #include "HTTPServer.h"
00023 #include "debug.h"
00024 #include "homepage.h"
00025 #include "WeatherMeters.h"
00026 
00027 
00028 // Name of this sample
00029 #define APPLICATION_NAME "WindMeter"
00030 
00031 // Set to appropriate "#.#.#.#" string for static IP addresses or
00032 // set to NULL for DHCP to be used instead.
00033 #define HTTP_STATIC_IP_ADDRESS      "192.168.0.127"
00034 #define HTTP_STATIC_SUBNET_MASK     "255.255.255.0"
00035 #define HTTP_STATIC_GATEWAY_ADDRESS "192.168.0.1"
00036 
00037 // Name of this device to be use with DHCP server.
00038 #define HTTP_HOST_NAME   "WindMeter"
00039 
00040 // Port to which the HTTP server is to be bound.  The well known port number
00041 // for HTTP is 80.
00042 #define HTTP_PORT       80
00043 
00044 // String used to identify this sample HTTP server to the client.
00045 #define HTTP_SERVER_NAME "lwIPHTTPServer/1.0"
00046 
00047 // Root name of filesystem to be used for HTTP server sample.
00048 #define ROOT_FILESYSTEM_NAME "SD/webfs"
00049 
00050 // Where the SHttpServer structure containing the HTTP_BUFFER_POOL should be
00051 // placed in the device's memory.
00052 #define HTTP_MEM_POSITION __attribute((section("AHBSRAM0"),aligned))
00053 
00054 // Utility macro to determine the element count of an array.
00055 #define ARRAYSIZE(X) (sizeof(X)/sizeof(X[0]))
00056 
00057 
00058 
00059 // GET request handler context which bases HTML on printf() substituion.
00060 class CPrintfGetRequestHandlerContext : public IHTTPRequestHandlerContext
00061 {
00062 public:
00063     // Constructors / Destructors
00064     CPrintfGetRequestHandlerContext(const char* pStatusLine,
00065                                     size_t      StatusLineSize,
00066                                     const char* pHeaders, 
00067                                     size_t      HeaderSize)
00068     {
00069         m_pContent = NULL;
00070         m_pCurrent = NULL;
00071         m_ContentSize = 0;
00072         m_pStatusLine = pStatusLine;
00073         m_StatusLineSize = StatusLineSize;
00074         m_pHeaders = pHeaders;
00075         m_HeaderSize = HeaderSize;
00076     }
00077     ~CPrintfGetRequestHandlerContext()
00078     {
00079         free(m_pContent);
00080         m_pContent = NULL;
00081         m_pCurrent = NULL;
00082         m_pHeaders = NULL;
00083         m_pStatusLine = NULL;
00084         m_ContentSize = 0;
00085         m_HeaderSize = 0;
00086         m_StatusLineSize = 0;
00087     }
00088 
00089     int printf(const char* pFormat, ...)
00090     {
00091         va_list ArgList;
00092         int     RequiredBufferSize;
00093 
00094         // Only expect this to be called once.
00095         assert ( NULL == m_pContent && 0 == m_ContentSize );
00096         
00097         // How big does the HTML content buffer need to be?
00098         va_start(ArgList, pFormat);
00099         RequiredBufferSize = vsnprintf(NULL, 0, pFormat, ArgList);
00100         va_end(ArgList);
00101         
00102         // Check for error.
00103         if (RequiredBufferSize < 0)
00104         {
00105             return RequiredBufferSize;
00106         }
00107         
00108         // Allow space for the NULL terminator.
00109         RequiredBufferSize++;
00110         
00111         // Attempt to allocate a buffer of adequate size.
00112         m_pContent = (char*)malloc(RequiredBufferSize);
00113         if (!m_pContent)
00114         {
00115             return -1;
00116         }
00117         m_ContentSize = RequiredBufferSize;
00118         m_pCurrent = m_pContent;
00119         
00120         // Place the HTML content into the newly allocated buffer.
00121         va_start(ArgList, pFormat);
00122         RequiredBufferSize = vsnprintf(m_pContent, m_ContentSize, pFormat, ArgList);
00123         va_end(ArgList);
00124         
00125         // Make sure that nothing has changed out from underneath us.
00126         assert ( (int)m_ContentSize == RequiredBufferSize+1 );
00127         
00128         return RequiredBufferSize + 1;
00129     }
00130     
00131     // IHTTPRequestHandlerContext interface methods.
00132     virtual int  BeginRequestHeaders()
00133     {
00134         // Ignore request headers.
00135         return 0;
00136     }
00137     virtual void WriteRequestHeader(const char* pHeaderName, 
00138                                     const char* pHeaderValue)
00139     {
00140         // Unused parameters.
00141         (void)pHeaderName;
00142         (void)pHeaderValue;
00143         
00144         assert ( FALSE );
00145     }
00146     
00147     virtual void EndRequestHeaders()
00148     {
00149         assert ( FALSE );
00150     }
00151     
00152     virtual int BeginRequestContent(size_t ContentSize)
00153     {
00154         // Ignore request content body.
00155         (void)ContentSize;
00156         return 0;
00157     }
00158     
00159     virtual void WriteRequestContentBlock(const void* pBlockBuffer, 
00160                                           size_t BlockBufferSize)
00161     {
00162         (void)pBlockBuffer;
00163         (void)BlockBufferSize;
00164         assert ( FALSE );
00165     }
00166     
00167     virtual void EndRequestContent()
00168     {
00169         assert ( FALSE );
00170     }
00171     
00172     virtual const char* GetStatusLine(size_t* pStatusLineLength)
00173     {
00174         *pStatusLineLength = m_StatusLineSize;
00175         return m_pStatusLine;
00176     }
00177     
00178     virtual const char* GetResponseHeaders(size_t* pResponseHeaderLength)
00179     {
00180         *pResponseHeaderLength = m_HeaderSize;
00181         return m_pHeaders;
00182     }
00183     
00184     virtual int BeginResponseContent()
00185     {
00186         assert (m_pContent);
00187         
00188         // We have data to be sent back to client.
00189         m_pCurrent = m_pContent;
00190         return 1;
00191     }
00192     
00193     virtual size_t ReadResponseContentBlock(char*  pBuffer,
00194                                             size_t BytesToRead)
00195     {
00196         size_t BytesAlreadyRead = m_pCurrent - m_pContent;
00197         size_t BytesLeft = m_ContentSize - BytesAlreadyRead;
00198         
00199         if (BytesToRead > BytesLeft)
00200         {
00201             BytesToRead = BytesLeft;
00202         }
00203         
00204         memcpy(pBuffer, m_pCurrent, BytesToRead);
00205         m_pCurrent += BytesToRead;
00206         
00207         return BytesToRead;
00208     }
00209     
00210     virtual void EndResponseContent()
00211     {
00212     }
00213     
00214     virtual void Release()
00215     {
00216         delete this;
00217     }
00218 
00219 protected:
00220     char*       m_pContent;
00221     const char* m_pCurrent;
00222     const char* m_pStatusLine;
00223     const char* m_pHeaders;
00224     size_t      m_ContentSize;
00225     size_t      m_StatusLineSize;
00226     size_t      m_HeaderSize;
00227 };
00228 
00229 
00230 // Request handler context which pulls content from file handle.
00231 class CFileRequestHandlerContext : public IHTTPRequestHandlerContext
00232 {
00233 public:
00234     // Constructors / Destructors
00235     CFileRequestHandlerContext(FILE*       pFile, 
00236                                const char* pStatusLine,
00237                                size_t      StatusLineSize,
00238                                const char* pHeaders, 
00239                                size_t      HeaderSize)
00240     {
00241         m_pFile = pFile;
00242         m_pStatusLine = pStatusLine;
00243         m_StatusLineSize = StatusLineSize;
00244         m_pHeaders = pHeaders;
00245         m_HeaderSize = HeaderSize;
00246     }
00247     ~CFileRequestHandlerContext()
00248     {
00249         // Make sure that file handle isn't being leaked.
00250         assert ( !m_pFile );
00251         m_pHeaders = NULL;
00252         m_pStatusLine = NULL;
00253         m_HeaderSize = 0;
00254         m_StatusLineSize = 0;
00255     }
00256     
00257     // IHTTPRequestHandlerContext interface methods.
00258     virtual int  BeginRequestHeaders()
00259     {
00260         // Ignore request headers.
00261         return 0;
00262     }
00263     virtual void WriteRequestHeader(const char* pHeaderName, 
00264                                     const char* pHeaderValue)
00265     {
00266         (void)pHeaderName;
00267         (void)pHeaderValue;
00268         assert ( FALSE );
00269     }
00270     
00271     virtual void EndRequestHeaders()
00272     {
00273         assert ( FALSE );
00274     }
00275     
00276     virtual int BeginRequestContent(size_t ContentSize)
00277     {
00278         // Ignore request content body.
00279         (void)ContentSize;
00280         return 0;
00281     }
00282     
00283     virtual void WriteRequestContentBlock(const void* pBlockBuffer, 
00284                                           size_t BlockBufferSize)
00285     {
00286         (void)pBlockBuffer;
00287         (void)BlockBufferSize;
00288         assert ( FALSE );
00289     }
00290     
00291     virtual void EndRequestContent()
00292     {
00293         assert ( FALSE );
00294     }
00295     
00296     virtual const char* GetStatusLine(size_t* pStatusLineLength)
00297     {
00298         *pStatusLineLength = m_StatusLineSize;
00299         return m_pStatusLine;
00300     }
00301     
00302     virtual const char* GetResponseHeaders(size_t* pResponseHeaderLength)
00303     {
00304         *pResponseHeaderLength = m_HeaderSize;
00305         return m_pHeaders;
00306     }
00307     
00308     virtual int BeginResponseContent()
00309     {
00310         assert (m_pFile);
00311         
00312         // We have data to be sent back to client.
00313         return 1;
00314     }
00315     
00316     virtual size_t ReadResponseContentBlock(char*  pBuffer,
00317                                             size_t BytesToRead)
00318     {
00319         return fread(pBuffer, 1, BytesToRead, m_pFile);
00320     }
00321     
00322     virtual void EndResponseContent()
00323     {
00324         if (m_pFile)
00325         {
00326             fclose(m_pFile);
00327             m_pFile = NULL;
00328         }
00329     }
00330     
00331     virtual void Release()
00332     {
00333         EndResponseContent();
00334         delete this;
00335     }
00336 
00337 protected:
00338     FILE*       m_pFile;
00339     const char* m_pStatusLine;
00340     const char* m_pHeaders;
00341     size_t      m_StatusLineSize;
00342     size_t      m_HeaderSize;
00343 };
00344 
00345 
00346 // Class to test application request handler overrides.
00347 class CWindMeterRequestHandler : public IHTTPRequestHandler
00348 {
00349 public:
00350     // Constructors/Destructors
00351     CWindMeterRequestHandler();
00352     
00353     // IHTTPRequestHandler interface methods.
00354     virtual IHTTPRequestHandlerContext* HandleGetRequest(const char* pURI);
00355     virtual IHTTPRequestHandlerContext* HandleHeadRequest(const char* pURI);
00356     virtual IHTTPRequestHandlerContext* HandlePostRequest(const char* pURI);
00357     virtual IHTTPRequestHandlerContext* HandleBadRequest(const char* pRequest);
00358     
00359 protected:
00360     IHTTPRequestHandlerContext* HandleRequest(const char* pURI);
00361     void MinuteTickerISR();
00362     
00363     CWeatherMeters  m_WeatherMeters;
00364     Ticker          m_MinuteTicker;
00365 };
00366 
00367 
00368 CWindMeterRequestHandler::CWindMeterRequestHandler()
00369     : m_WeatherMeters(p9, p10, p15)
00370 {
00371     m_MinuteTicker.attach_us<CWindMeterRequestHandler>(this, &CWindMeterRequestHandler::MinuteTickerISR, 60000000);
00372 }
00373 
00374 
00375 void CWindMeterRequestHandler::MinuteTickerISR()
00376 {
00377     CWeatherMeters::SMeasurements   Measurements;
00378     
00379     m_WeatherMeters.GetMeasurements(&Measurements);
00380 }
00381 
00382 
00383 IHTTPRequestHandlerContext* CWindMeterRequestHandler::HandleGetRequest(const char* pURI)
00384 {
00385     return HandleRequest(pURI);
00386 }
00387 
00388 IHTTPRequestHandlerContext* CWindMeterRequestHandler::HandleHeadRequest(const char* pURI)
00389 {
00390     return HandleRequest(pURI);
00391 }
00392 
00393 IHTTPRequestHandlerContext* CWindMeterRequestHandler::HandleRequest(const char* pURI)
00394 {
00395     // Generate content for root home page.
00396     if (0 == strcmp(pURI, "/"))
00397     {
00398         CWeatherMeters::SMeasurements Measurements;
00399         
00400         CPrintfGetRequestHandlerContext* pContext = new CPrintfGetRequestHandlerContext(g_OkStatusLine,
00401                                                                                         sizeof(g_OkStatusLine)-1,
00402                                                                                         g_HTMLHeaders,
00403                                                                                         sizeof(g_HTMLHeaders)-1);
00404         if (!pContext)
00405         {
00406             return NULL;
00407         }
00408         
00409         m_WeatherMeters.GetMeasurements(&Measurements);
00410         pContext->printf(g_HomePageHTML, 
00411                          Measurements.WindSpeed, 
00412                          Measurements.MaximumWindSpeed, 
00413                          Measurements.WindDirectionString,
00414                          Measurements.Rainfall,
00415                          "? minutes");
00416         
00417         return pContext;
00418     }
00419     
00420     return NULL;
00421 }
00422 
00423 IHTTPRequestHandlerContext* CWindMeterRequestHandler::HandlePostRequest(const char* pURI)
00424 {
00425     if (0 == strcmp(pURI, "/reset.html"))
00426     {
00427         FILE* pFile;
00428         
00429         m_WeatherMeters.Reset();
00430 
00431         pFile = fopen("/" ROOT_FILESYSTEM_NAME "/reset.html", "r");
00432         if (pFile)
00433         {
00434             static const char StatusLine[] = "HTTP/1.0 200 OK\r\n";
00435             static const char Headers[] = "Content-type: text/html\r\n";
00436                                             
00437             CFileRequestHandlerContext* pRequestHandlerContext = new CFileRequestHandlerContext(pFile,
00438                                                                                                 StatusLine,
00439                                                                                                 sizeof(StatusLine)-1,
00440                                                                                                 Headers,
00441                                                                                                 sizeof(Headers)-1);
00442             if (!pRequestHandlerContext)
00443             {
00444                 fclose(pFile);
00445             }
00446             
00447             return pRequestHandlerContext;
00448         }
00449     }
00450     
00451     return NULL;
00452 }
00453 
00454 IHTTPRequestHandlerContext* CWindMeterRequestHandler::HandleBadRequest(const char* pRequest)
00455 {
00456     // Unused parameters.
00457     (void)pRequest;
00458     
00459     return NULL;
00460 }
00461 
00462 
00463 
00464 int main() 
00465 {
00466     int                                     Result = 1;
00467     DigitalOut                              ProgressLED(LED1);
00468     Timer                                   BlinkTimer;
00469     static SNetwork                         Network;
00470     static HTTP_MEM_POSITION CHTTPServer    HTTPServer;
00471     static CWindMeterRequestHandler         WindMeterRequestHandler;
00472     
00473     printf("\r\n" APPLICATION_NAME "\r\n");
00474     
00475     // Create the SD based file system.
00476     static SDFileSystem sd(p5, p6, p7, p8, "SD");
00477 
00478     // Initialize the ethernet driver and lwIP network stack.
00479     Result = SNetwork_Init(&Network, 
00480                            HTTP_STATIC_IP_ADDRESS, 
00481                            HTTP_STATIC_SUBNET_MASK,
00482                            HTTP_STATIC_GATEWAY_ADDRESS,
00483                            HTTP_HOST_NAME);
00484     if (Result)
00485     {
00486         error("Failed to initialize network.\r\n");
00487     }
00488     
00489     // Register test request handler for handling HTTP requests.
00490     HTTPServer.AttachRequestHandler(&WindMeterRequestHandler);
00491 
00492     // Setup a HTTP server to listen on port 80.
00493     Result = HTTPServer.Bind(ROOT_FILESYSTEM_NAME, HTTP_SERVER_NAME, HTTP_PORT);
00494     if (Result)
00495     {
00496         error("Failed to initialize for receiving HTTP requests.\r\n");
00497     }
00498                 
00499     // Enter the main application loop.
00500     BlinkTimer.start();
00501     while(1) 
00502     {
00503         // Allow the network stack to do its thing.  It will callback into the
00504         // application callbacks as necessary to complete the actual work
00505         // required for a simple HTTP server implementation.
00506         SNetwork_Poll(&Network);
00507         
00508         // Blink the progress LED once each half second to let user know that
00509         // we haven't hung.
00510         if (BlinkTimer.read_ms() > 500)
00511         {
00512             BlinkTimer.reset();
00513             ProgressLED = !ProgressLED;
00514         }
00515     }
00516 }
00517 
00518