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

HTTPLinkStatus.h

Committer:
iva2k
Date:
2010-01-12
Revision:
2:360fda42fefd
Parent:
0:886e4b3119ad

File content as of revision 2:360fda42fefd:

// 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