Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Dependencies: FatFileSystem mbed WeatherMeters SDFileSystem
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
Generated on Tue Jul 12 2022 20:48:16 by
 1.7.2
 1.7.2