Example of HTTPServer with additional features: * SNTPClient, DST rules * Link status indication * Local or SDCard-based WebServer * RPC-able class * Static and Dynamic HTML page

Dependencies:   mbed

Revision:
0:886e4b3119ad
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/HTTPLinkStatus.h	Sun Jan 03 07:00:43 2010 +0000
@@ -0,0 +1,185 @@
+// HTTPLinkStatus.h
+// HTTP Server Logger class
+//
+// Provides:
+// 1. ETH port link state monitor 
+//   - lights LED for link
+//   - default: logs link state to stdout;
+//   - default: creates URL file on local filesystem (can be used to open browser to URL address)
+// 2. HTTP activity monitor (does not react to non-http traffic)
+//   - blinks LED for activity / HTTP requests
+//   - optional: log activity to stdout
+//   - optional: log activity to file (file is opened for each log entry, so local file system can still be accessed via USB)
+// 
+
+#ifndef HTTPLINKSTATUS_H
+#define HTTPLINKSTATUS_H
+
+#include "HTTPServer.h"
+
+// FIXME: should we be able to get this from *con?
+extern Ethernet eth;        // eth is defined elsewhere, avoid compiler error.
+
+namespace mbed {
+
+class DigitalOutDelayed : public DigitalOut {
+  public:
+    DigitalOutDelayed(PinName pin, const char* name = NULL) : DigitalOut(pin, name) {}
+    void write(int value, float delay=0.0) {
+      _timeout.detach();
+      if (delay > 0.0) {
+          _delay_value = value;
+          _timeout.attach(this, &DigitalOutDelayed::_write_delayed, delay);
+      } else {
+        DigitalOut::write(value);
+      }
+    }
+    void write_us(int value, unsigned int delay_us=0) {
+      _timeout.detach();
+      if (delay_us > 0) {
+          _delay_value = value;
+          _timeout.attach_us(this, &DigitalOutDelayed::_write_delayed, delay_us);
+      } else {
+        DigitalOut::write(value);
+      }
+    }
+#ifdef MBED_OPERATORS
+    using DigitalOut::operator = ;
+    using DigitalOut::operator int;
+#endif      
+
+  protected:
+    void _write_delayed(void) { DigitalOut::write(_delay_value); }
+    Timeout _timeout;
+    int _delay_value;
+};
+
+}    // namespace mbed
+
+class HTTPLinkStatus : public HTTPHandler {
+  public:
+    HTTPLinkStatus(const char *prefix, PinName link_led=NC, PinName act_led=NC, float poll_t = 0.1, 
+      bool do_urlfile = true, bool do_link_printf = true, bool do_log_printf = false, const char* log_file = NULL
+    ) : 
+      HTTPHandler(prefix),
+      _link_led(link_led),
+      _act_led(act_led),
+      _linkstate(-1),
+      _first(true),
+      _our_ip(0),
+      _do_urlfile(do_urlfile),
+      _do_link_printf(do_link_printf),
+      _do_log_printf(do_log_printf),
+      _log_file(log_file) 
+    {
+      if (poll_t > 0) _ticker.attach(this, &HTTPLinkStatus::_link_poll, poll_t);
+    }
+    HTTPLinkStatus(HTTPServer *server, const char *prefix, PinName link_led=NC, PinName act_led=NC, float poll_t = 0.1,
+      bool do_urlfile = true, bool do_link_printf = true, bool do_log_printf = false, const char* log_file = NULL
+    ) :
+      HTTPHandler(prefix),
+      _link_led(link_led),
+      _act_led(act_led),
+      _linkstate(-1),
+      _first(true),
+      _our_ip(0),
+      _do_urlfile(do_urlfile),
+      _do_link_printf(do_link_printf),
+      _do_log_printf(do_log_printf),
+      _log_file(log_file) 
+    {
+      server->addHandler(this); 
+      if (poll_t > 0) _ticker.attach(this, &HTTPLinkStatus::_link_poll, poll_t);
+    }
+    virtual ~HTTPLinkStatus() {
+      _ticker.detach();    // Needeed?
+    }
+    void set_do_urlfile(bool val) { _do_urlfile = val; }
+    void set_link_stdout(bool val) { _do_link_printf = val; }
+    void set_log_stdout(bool val) { _do_log_printf = val; }
+    void set_log_file(const char *file) {
+      _log_file = file;
+      if (_log_file) {
+        FILE *fp = fopen(_log_file, "a");
+        if (fp) {
+            fprintf(fp, "======== HTTPLinkStatus NEW LOG OPENED ========\r\n");
+            fclose(fp);
+        } else {
+          _log_file = NULL;    // Error opening file. Reset file name so we won't waste our time trying to log to it.
+        }
+      }
+    }
+  private:
+    void _link_poll() {
+        int new_linkstate = eth.link();
+        if (new_linkstate) {
+            // From http://mbed.org/forum/post/909/
+            NetServer *net = NetServer::get();
+            struct ip_addr ip = net->getIPAddr();
+//            struct ip_addr gw = net->getGateway();
+//            struct ip_addr nm = net->getNetmask();
+//            struct ip_addr dns = net->getDNS1();
+            if (ip.addr != _our_ip) {
+                if (!_first &&_do_link_printf) {
+                  printf("IP: %hhu.%hhu.%hhu.%hhu\r\n",
+                   (ip.addr)&0xFF, (ip.addr>>8)&0xFF, (ip.addr>>16)&0xFF, (ip.addr>>24)&0xFF);
+                }
+                _first = false;
+                if (_do_urlfile) {
+                    // Create a link file to our IP.
+                    FILE *fp = fopen("/local/Start.url", "w");  // Create a link to own IP
+                    if (fp) {
+                        fprintf(fp, "[InternetShortcut]\r\nURL=http://%hhu.%hhu.%hhu.%hhu/\r\n",
+                          (ip.addr)&0xFF, (ip.addr>>8)&0xFF, (ip.addr>>16)&0xFF, (ip.addr>>24)&0xFF);
+                        fclose(fp);
+                    }
+                }
+                _our_ip = ip.addr;
+            }
+        }
+        else {
+            if (_do_link_printf && _linkstate != new_linkstate) {
+              printf("IP: <link down>\r\n");
+            }
+        }
+        _link_led  = new_linkstate;
+        _linkstate = new_linkstate;
+    }
+
+    virtual HTTPHandle action(HTTPConnection *con) const {
+      _act_led = 1;
+//      struct ip_addr ip = con->_pcb()->remote_ip;
+      struct ip_addr ip = con->get_remote_ip();    // This requires a patch to TCPConnection.h file in lwip/Core
+      if (_do_log_printf) {
+        printf("HTTPStatus IP: %hhu.%hhu.%hhu.%hhu %s %s\r\n",
+          (ip.addr)&0xFF, (ip.addr>>8)&0xFF, (ip.addr>>16)&0xFF, (ip.addr>>24)&0xFF, 
+          (con->getType() == POST? "POST" : "GET "), con->getURL()
+        );
+      }
+      if (_log_file) {
+        FILE *fp = fopen(_log_file, "a");
+        if (fp) {
+            fprintf(fp, "HTTPStatus IP: %hhu.%hhu.%hhu.%hhu %s %s\r\n",
+              (ip.addr)&0xFF, (ip.addr>>8)&0xFF, (ip.addr>>16)&0xFF, (ip.addr>>24)&0xFF, 
+              (con->getType() == POST? "POST" : "GET "), con->getURL()
+            );
+            fclose(fp);
+        }
+      }
+      _act_led.write(0, 0.050);    // Delayed write
+      return HTTP_AddFields;
+    }
+    
+    DigitalOut _link_led;           // Link status LED
+    mutable DigitalOutDelayed _act_led;    // Link activity LED. Need "mutable" keyword to let it be changed from within action() const function.
+    Ticker _ticker;                 // State polling timer
+    int _linkstate;                 // Last state of eth link
+    bool _first;                    // Avoid duplicate IP report on the very first pass
+    unsigned int _our_ip;           // Our last IP address (used for _do_urlfile)
+    bool _do_urlfile;               // True for creating url (link) to self on local file system /local/Start.url
+    bool _do_link_printf;           // True for printing to stdout 
+    bool _do_log_printf;            // True for printing activity log to stdout 
+    const char *_log_file;          // Optional file for activity logging
+};
+
+#endif