This version has the index file and data pages on a SD card (512Mbyte) it does not suffer from the autorun problem when directly writtin to the mbed flash memory It makes readings from one solar panel for open and loaded voltages every 'interval' seconds Every readingsPerPage a new web page is created and indexed on a readings web page Activty is shown by the flashing blue led (0.5s) means it is connected and output via the serial over usb port. Data is preserved on subsequent power ups by incrementing file number. PMR 15/9/10 */

Dependencies:   EthernetNetIf NTPClient_NetServices mbed SDFileSystem

Files at this revision

API Documentation at this revision

Comitter:
pmr1
Date:
Sat Sep 18 13:31:41 2010 +0000
Commit message:

Changed in this revision

EthernetNetIf.lib Show annotated file Show diff for this revision Revisions of this file
FATFileSystem.lib Show annotated file Show diff for this revision Revisions of this file
NTPClient.lib Show annotated file Show diff for this revision Revisions of this file
SDFileSystem.lib Show annotated file Show diff for this revision Revisions of this file
mbed.bld Show annotated file Show diff for this revision Revisions of this file
server/HTTPRequestDispatcher.cpp Show annotated file Show diff for this revision Revisions of this file
server/HTTPRequestDispatcher.h Show annotated file Show diff for this revision Revisions of this file
server/HTTPRequestHandler.cpp Show annotated file Show diff for this revision Revisions of this file
server/HTTPRequestHandler.h Show annotated file Show diff for this revision Revisions of this file
server/HTTPServer.cpp Show annotated file Show diff for this revision Revisions of this file
server/HTTPServer.h Show annotated file Show diff for this revision Revisions of this file
server/impl/FSHandler.cpp Show annotated file Show diff for this revision Revisions of this file
server/impl/FSHandler.h Show annotated file Show diff for this revision Revisions of this file
server/impl/RPCHandler.cpp Show annotated file Show diff for this revision Revisions of this file
server/impl/RPCHandler.h Show annotated file Show diff for this revision Revisions of this file
server/impl/SimpleHandler.cpp Show annotated file Show diff for this revision Revisions of this file
server/impl/SimpleHandler.h Show annotated file Show diff for this revision Revisions of this file
solar2.cpp Show annotated file Show diff for this revision Revisions of this file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/EthernetNetIf.lib	Sat Sep 18 13:31:41 2010 +0000
@@ -0,0 +1,1 @@
+http://mbed.org/users/donatien/code/EthernetNetIf/#bc7df6da7589
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/FATFileSystem.lib	Sat Sep 18 13:31:41 2010 +0000
@@ -0,0 +1,1 @@
+http://mbed.org/users/mbed_unsupported/code/fatfilesystem/
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/NTPClient.lib	Sat Sep 18 13:31:41 2010 +0000
@@ -0,0 +1,1 @@
+http://mbed.org/users/donatien/code/NTPClient/#7c3f1199256a
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/SDFileSystem.lib	Sat Sep 18 13:31:41 2010 +0000
@@ -0,0 +1,1 @@
+http://mbed.org/users/simon/code/SDFileSystem/#b1ddfc9a9b25
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed.bld	Sat Sep 18 13:31:41 2010 +0000
@@ -0,0 +1,1 @@
+http://mbed.org/users/mbed_official/code/mbed/builds/9114680c05da
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/server/HTTPRequestDispatcher.cpp	Sat Sep 18 13:31:41 2010 +0000
@@ -0,0 +1,231 @@
+
+/*
+Copyright (c) 2010 Donatien Garnier (donatiengar [at] gmail [dot] com)
+ 
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+ 
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+ 
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+
+#include "core/netservice.h"
+#include "HTTPRequestDispatcher.h"
+#include "HTTPRequestHandler.h"
+#include <string.h>
+
+//#define __DEBUG
+#include "dbg/dbg.h"
+
+HTTPRequestDispatcher::HTTPRequestDispatcher(HTTPServer* pSvr, TCPSocket* pTCPSocket) : NetService(), m_pSvr(pSvr), m_pTCPSocket(pTCPSocket), m_watchdog(), m_closed(false)
+{
+  m_pTCPSocket->setOnEvent(this, &HTTPRequestDispatcher::onTCPSocketEvent);
+  m_watchdog.attach_us<HTTPRequestDispatcher>(this, &HTTPRequestDispatcher::onTimeout, HTTP_REQUEST_TIMEOUT * 1000);
+}
+
+HTTPRequestDispatcher::~HTTPRequestDispatcher()
+{
+  close();
+}
+
+void HTTPRequestDispatcher::dispatchRequest()
+{
+  string path;
+  string meth;
+  HTTP_METH methCode;
+  
+  DBG("Dispatching req\r\n");
+  
+  if( !getRequest(&path, &meth ) )
+  {
+    close();
+    return; //Invalid request
+  }
+  
+  if( !meth.compare("GET") )
+  {
+    methCode = HTTP_GET;
+  }
+  else if( !meth.compare("POST") )
+  {
+    methCode = HTTP_POST;
+  }
+  else if( !meth.compare("HEAD") )
+  {
+    methCode = HTTP_HEAD;
+  }
+  else
+  {
+    close(); //Parse error
+    return;
+  }
+  
+  DBG("Looking for a handler\r\n");
+  
+  map< string, HTTPRequestHandler*(*)(const char*, const char*, TCPSocket*) >::iterator it;
+//  it = m_pSvr->m_lpHandlers.find(rootPath); //We are friends so we can do that
+// NEW CODE START: 
+  int root_len = 0;
+  for (it = m_pSvr->m_lpHandlers.begin(); it != m_pSvr->m_lpHandlers.end(); it++)
+  {
+    DBG("Checking %s...\n", (*it).first.c_str());
+    root_len = (*it).first.length();
+    if ( root_len &&
+      !path.compare( 0, root_len, (*it).first ) && 
+      (path[root_len] == '/' || path[root_len] == '\0'))
+    {
+      DBG("Found (%s)\n", (*it).first.c_str());
+	    // Found!
+	    break;	// for
+	  }
+  }
+// NEW CODE END
+  if((it == m_pSvr->m_lpHandlers.end()) && !(m_pSvr->m_lpHandlers.empty()))
+  {
+    DBG("Using default handler\n");
+    it = m_pSvr->m_lpHandlers.end();
+    it--; //Get the last element
+    if( ! (((*it).first.length() == 0) || !(*it).first.compare("/")) ) //This is not the default handler
+      it = m_pSvr->m_lpHandlers.end();
+    root_len = 0;
+  }
+  if(it == m_pSvr->m_lpHandlers.end())
+  {    
+    DBG("No handler found\n");
+    close(); //No handler found
+    return;
+  }
+  
+  DBG("Handler found.\r\n");
+  
+//HTTPRequestHandler* pHdlr = (*it).second(rootPath.c_str(), subPath.c_str(), m_pTCPSocket);
+//NEW CODE 1 LINE:
+  HTTPRequestHandler* pHdlr = (*it).second((*it).first.c_str(), path.c_str() + root_len, m_pTCPSocket);
+  m_pTCPSocket = NULL; //We don't own it anymore
+  
+  switch(methCode)
+  {
+  case HTTP_GET:
+    pHdlr->doGet();
+    break;
+  case HTTP_POST:
+    pHdlr->doPost();
+    break;
+  case HTTP_HEAD:
+    pHdlr->doHead();
+    break;
+  }
+  
+  DBG("Req handled (or being handled)\r\n");
+  close();
+}
+
+void HTTPRequestDispatcher::close() //Close socket and destroy data
+{
+  if(m_closed)
+    return;
+  m_closed = true; //Prevent recursive calling or calling on an object being destructed by someone else
+  m_watchdog.detach();
+  if(m_pTCPSocket) //m_pTCPSocket Should only be destroyed if ownership not passed to an handler
+  {
+    m_pTCPSocket->resetOnEvent();
+    m_pTCPSocket->close();
+    delete m_pTCPSocket; //This fn might have been called by this socket (through an event), so DO NOT DESTROY IT HERE
+  }
+  NetService::close();
+}
+
+
+void HTTPRequestDispatcher::onTimeout() //Connection has timed out
+{
+  close();
+}
+
+bool HTTPRequestDispatcher::getRequest(string* path, string* meth)
+{
+  char req[128];
+  char c_path[128];
+  char c_meth[128];
+  const int maxLen = 128;
+  char* p = req;
+  //Read Line
+  int ret;
+  int len = 0;
+  for(int i = 0; i < maxLen - 1; i++)
+  {
+    ret = m_pTCPSocket->recv(p, 1);
+    if(!ret)
+    {
+      break;
+    }
+    if( (len > 1) && *(p-1)=='\r' && *p=='\n' )
+    {
+      p--;
+      len-=2;
+      break;
+    }
+    else if( *p=='\n' )
+    {
+      len--;
+      break;    
+    }
+    p++;
+    len++;
+  }
+  *p = 0;
+  
+  DBG("Parsing request : %s\r\n", req);
+  
+  ret = sscanf(req, "%s %s HTTP/%*d.%*d", c_meth, c_path);
+  if(ret !=2)
+    return false;
+    
+  *meth = string(c_meth);
+// NEW CODE (old code removed):
+   *path = string(c_path);
+  return true;
+}
+
+
+
+void HTTPRequestDispatcher::onTCPSocketEvent(TCPSocketEvent e)
+{
+
+  DBG("\r\nEvent %d\r\n", e);
+  
+  if(m_closed)
+  {
+    DBG("\r\nWARN: Discarded\r\n");
+    return;
+  }
+
+  switch(e)
+  {
+  case TCPSOCKET_READABLE:
+    m_watchdog.detach();
+    m_pTCPSocket->resetOnEvent();
+    //Req arrived, dispatch :
+    dispatchRequest();
+    break;
+  case TCPSOCKET_CONTIMEOUT:
+  case TCPSOCKET_CONRST:
+  case TCPSOCKET_CONABRT:
+  case TCPSOCKET_ERROR:
+  case TCPSOCKET_DISCONNECTED:
+    close();
+    break;
+  }
+  
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/server/HTTPRequestDispatcher.h	Sat Sep 18 13:31:41 2010 +0000
@@ -0,0 +1,72 @@
+
+/*
+Copyright (c) 2010 Donatien Garnier (donatiengar [at] gmail [dot] com)
+ 
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+ 
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+ 
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+
+#ifndef HTTP_REQUEST_DISPATCHER_H
+#define HTTP_REQUEST_DISPATCHER_H
+
+class HTTPServer;
+
+#include "api/TCPSocket.h"
+#include "HTTPServer.h"
+#include "core/netservice.h"
+
+#include "mbed.h"
+
+#define HTTP_REQUEST_TIMEOUT 5000
+
+#include <string>
+using std::string;
+
+class HTTPRequestDispatcher : public NetService
+{
+public:
+  HTTPRequestDispatcher(HTTPServer* pSvr, TCPSocket* pTCPSocket);
+  virtual ~HTTPRequestDispatcher();
+  
+private:
+
+  enum HTTP_METH
+  {
+    HTTP_GET,
+    HTTP_POST,
+    HTTP_HEAD
+  };
+  
+  void dispatchRequest();
+  
+  virtual void close(); //Close TCPSocket and destroy data
+  
+  void onTCPSocketEvent(TCPSocketEvent e);
+  
+  void onTimeout(); //Connection has timed out
+
+  bool getRequest(string* path, string* meth);
+  
+  HTTPServer* m_pSvr;
+  TCPSocket* m_pTCPSocket;
+  
+  Timeout m_watchdog;
+  bool m_closed;
+};
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/server/HTTPRequestHandler.cpp	Sat Sep 18 13:31:41 2010 +0000
@@ -0,0 +1,237 @@
+
+/*
+Copyright (c) 2010 Donatien Garnier (donatiengar [at] gmail [dot] com)
+ 
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+ 
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+ 
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+
+#include "core/netservice.h"
+#include "HTTPRequestHandler.h"
+
+#include <string.h>
+
+//#define __DEBUG
+#include "dbg/dbg.h"
+
+#define HTTP_REQUEST_TIMEOUT 5000
+
+HTTPRequestHandler::HTTPRequestHandler(const char* rootPath, const char* path, TCPSocket* pTCPSocket) : NetService(), 
+m_pTCPSocket(pTCPSocket), m_reqHeaders(), m_respHeaders(),
+m_rootPath(rootPath), m_path(path), m_errc(200),
+m_watchdog(), m_timeout(0), m_closed(false), m_headersSent(false) //OK
+{
+  //Read & parse headers
+  readHeaders();
+  m_pTCPSocket->setOnEvent(this, &HTTPRequestHandler::onTCPSocketEvent);
+  setTimeout(HTTP_REQUEST_TIMEOUT);
+}
+
+HTTPRequestHandler::~HTTPRequestHandler()
+{
+  close();
+}
+
+void HTTPRequestHandler::onTimeout() //Connection has timed out
+{
+  close();
+}
+
+void HTTPRequestHandler::close() //Close socket and destroy data
+{
+  if(m_closed)
+    return;
+  m_closed = true; //Prevent recursive calling or calling on an object being destructed by someone else
+  m_watchdog.detach();
+  onClose();
+  m_pTCPSocket->resetOnEvent();
+  m_pTCPSocket->close();
+  delete m_pTCPSocket; //Can safely destroy socket
+  NetService::close();
+}
+
+map<string, string>& HTTPRequestHandler::reqHeaders() //const
+{
+  return m_reqHeaders;
+}
+
+string& HTTPRequestHandler::path() //const
+{
+  return m_path;
+}
+
+int HTTPRequestHandler::dataLen() const
+{
+  map<string,string>::iterator it;
+  it = m_reqHeaders.find("Content-Length");
+  if( it == m_reqHeaders.end() )
+  {
+    return 0;
+  }
+  return atoi((*it).second.c_str()); //return 0 if parse fails, so that's fine
+}
+
+int HTTPRequestHandler::readData(char* buf, int len)
+{
+  return m_pTCPSocket->recv(buf, len);
+}
+
+string& HTTPRequestHandler::rootPath() //const
+{
+  return m_rootPath;
+}
+
+void HTTPRequestHandler::setErrCode(int errc)
+{
+  m_errc = errc;
+}
+
+void HTTPRequestHandler::setContentLen(int len)
+{
+  char len_str[6] = {0};
+  sprintf(len_str, "%d", len);
+  respHeaders()["Content-Length"] = len_str;
+}
+  
+map<string, string>& HTTPRequestHandler::respHeaders()
+{
+  return m_respHeaders;
+}
+
+int HTTPRequestHandler::writeData(const char* buf, int len)
+{
+  if(!m_headersSent)
+  {
+    m_headersSent = true;
+    writeHeaders();
+  }
+  
+  return m_pTCPSocket->send(buf, len);
+}
+
+void HTTPRequestHandler::setTimeout(int ms)
+{
+  m_timeout = 1000*ms;
+  resetTimeout();
+}
+
+void HTTPRequestHandler::resetTimeout()
+{
+  m_watchdog.detach();
+  m_watchdog.attach_us<HTTPRequestHandler>(this, &HTTPRequestHandler::onTimeout, m_timeout);
+}
+
+
+void HTTPRequestHandler::readHeaders()
+{
+  static char line[128];
+  static char key[128];
+  static char value[128];
+  while( readLine(line, 128) > 0) //if == 0, it is an empty line = end of headers
+  {
+    int n = sscanf(line, "%[^:]: %[^\n]", key, value);
+    if ( n == 2 )
+    {
+      DBG("\r\nRead header : %s : %s\r\n", key, value);
+      m_reqHeaders[key] = value;
+    }
+    //TODO: Impl n==1 case (part 2 of previous header)
+  }
+}
+
+void HTTPRequestHandler::writeHeaders() //Called at the first writeData call
+{
+  static char line[128];
+  
+  //Response line
+  sprintf(line, "HTTP/1.1 %d MbedInfo\r\n", m_errc); //Not a violation of the standard not to include the descriptive text
+  m_pTCPSocket->send(line, strlen(line));
+  
+  map<string,string>::iterator it;
+  while( !m_respHeaders.empty() )
+  {
+    it = m_respHeaders.begin();
+    sprintf(line, "%s: %s\r\n", (*it).first.c_str(), (*it).second.c_str() );
+    DBG("\r\n%s", line);
+    m_pTCPSocket->send(line, strlen(line));
+    m_respHeaders.erase(it);
+  }
+  m_pTCPSocket->send("\r\n",2); //End of head
+}
+
+int HTTPRequestHandler::readLine(char* str, int maxLen)
+{
+  int ret;
+  int len = 0;
+  for(int i = 0; i < maxLen - 1; i++)
+  {
+    ret = m_pTCPSocket->recv(str, 1);
+    if(!ret)
+    {
+      break;
+    }
+    if( (len > 1) && *(str-1)=='\r' && *str=='\n' )
+    {
+      str--;
+      len-=2;
+      break;
+    }
+    else if( *str=='\n' )
+    {
+      len--;
+      break;    
+    }
+    str++;
+    len++;
+  }
+  *str = 0;
+  return len;
+}
+
+void HTTPRequestHandler::onTCPSocketEvent(TCPSocketEvent e)
+{
+   
+  DBG("\r\nEvent %d in HTTPRequestHandler\r\n", e);
+
+  if(m_closed)
+  {
+    DBG("\r\nWARN: Discarded\r\n");
+    return;
+  }
+
+  switch(e)
+  {
+  case TCPSOCKET_READABLE:
+    resetTimeout();
+    onReadable();
+    break;
+  case TCPSOCKET_WRITEABLE:
+    resetTimeout();
+    onWriteable();    
+    break;
+  case TCPSOCKET_CONTIMEOUT:
+  case TCPSOCKET_CONRST:
+  case TCPSOCKET_CONABRT:
+  case TCPSOCKET_ERROR:
+  case TCPSOCKET_DISCONNECTED:
+    DBG("\r\nConnection error in handler\r\n");
+    close();
+    break;
+  }
+  
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/server/HTTPRequestHandler.h	Sat Sep 18 13:31:41 2010 +0000
@@ -0,0 +1,101 @@
+
+/*
+Copyright (c) 2010 Donatien Garnier (donatiengar [at] gmail [dot] com)
+ 
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+ 
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+ 
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+
+/**
+HTTP Request Handler header file.
+*/
+
+#ifndef HTTP_REQUEST_HANDLER_H
+#define HTTP_REQUEST_HANDLER_H
+
+#include "api/TCPSocket.h"
+//#include "HTTPServer.h"
+
+#include "mbed.h"
+#include "core/netservice.h"
+
+#include <string>
+using std::string;
+
+#include <map>
+using std::map;
+
+///HTTP Server's generic request handler
+class HTTPRequestHandler : public NetService
+{
+public:
+  ///Instantiated by the HTTP Server
+  HTTPRequestHandler(const char* rootPath, const char* path, TCPSocket* pTCPSocket);
+  virtual ~HTTPRequestHandler();
+
+//protected:
+  virtual void doGet() = 0;
+  virtual void doPost() = 0;
+  virtual void doHead() = 0;
+  
+  virtual void onReadable() = 0; //Data has been read
+  virtual void onWriteable() = 0; //Data has been written & buf is free
+  virtual void onTimeout(); //Connection has timed out
+  virtual void onClose() = 0; //Connection is closing
+  
+  virtual void close(); //Close socket and destroy data
+
+protected:  
+  map<string, string>& reqHeaders() /*const*/;
+  string& path() /*const*/;
+  int dataLen() const;
+  int readData(char* buf, int len);
+  string& rootPath() /*const*/;
+  
+  void setErrCode(int errc);
+  void setContentLen(int len);
+  
+  map<string, string>& respHeaders();
+  int writeData(const char* buf, int len);
+  
+  void setTimeout(int ms);
+  void resetTimeout();
+
+private:
+  void readHeaders(); //Called at instanciation
+  void writeHeaders(); //Called at the first writeData call
+  void onTCPSocketEvent(TCPSocketEvent e);
+   
+  TCPSocket* m_pTCPSocket;
+  map<string, string> m_reqHeaders;
+  map<string, string> m_respHeaders;
+  string m_rootPath;
+  string m_path;
+  int m_errc; //Response code
+  
+  Timeout m_watchdog;
+  int m_timeout;
+  
+  bool m_closed;
+  bool m_headersSent;
+  
+  int readLine(char* str, int maxLen);
+
+};
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/server/HTTPServer.cpp	Sat Sep 18 13:31:41 2010 +0000
@@ -0,0 +1,77 @@
+
+/*
+Copyright (c) 2010 Donatien Garnier (donatiengar [at] gmail [dot] com)
+ 
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+ 
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+ 
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+
+#include "HTTPServer.h"
+
+//#define __DEBUG
+#include "dbg/dbg.h"
+
+HTTPServer::HTTPServer()
+{
+  m_pTCPSocket = new TCPSocket;
+  m_pTCPSocket->setOnEvent(this, &HTTPServer::onTCPSocketEvent);
+}
+
+HTTPServer::~HTTPServer()
+{
+  delete m_pTCPSocket;
+}
+
+void HTTPServer::bind(int port /*= 80*/)
+{
+  Host h(IpAddr(127,0,0,1), port, "localhost");
+  m_pTCPSocket->bind(h);     
+  m_pTCPSocket->listen(); //Listen
+}
+
+#if 0 //Just for clarity
+template<typename T>
+void HTTPServer::addHandler(const char* path)
+{
+  m_lpHandlers[path] = &T::inst;
+  
+}
+#endif
+  
+void HTTPServer::onTCPSocketEvent(TCPSocketEvent e)
+{
+
+  DBG("\r\nHTTPServer::onTCPSocketEvent : Event %d\r\n", e);
+
+  if(e==TCPSOCKET_ACCEPT)
+  {
+    TCPSocket* pTCPSocket;
+    Host client;
+
+    if( !!m_pTCPSocket->accept(&client, &pTCPSocket) )
+    {
+      DBG("\r\nHTTPServer::onTCPSocketEvent : Could not accept connection.\r\n");
+      return; //Error in accept, discard connection
+    }
+    
+    HTTPRequestDispatcher* pDispatcher = new HTTPRequestDispatcher(this, pTCPSocket); //TCPSocket ownership is passed to dispatcher
+    //The dispatcher object will destroy itself when done, or will be destroyed on Server destruction
+   
+  }
+  
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/server/HTTPServer.h	Sat Sep 18 13:31:41 2010 +0000
@@ -0,0 +1,104 @@
+
+/*
+Copyright (c) 2010 Donatien Garnier (donatiengar [at] gmail [dot] com)
+ 
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+ 
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+ 
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+
+/** \file
+HTTP Server header file
+*/
+
+#ifndef HTTP_SERVER_H
+#define HTTP_SERVER_H
+
+class HTTPRequestHandler;
+class HTTPRequestDispatcher;
+
+#include "core/net.h"
+#include "HTTPRequestHandler.h"
+#include "HTTPRequestDispatcher.h"
+
+#include <string>
+using std::string;
+
+#include <map>
+using std::map;
+
+///A simple HTTP server implementation
+/**
+The HTTPServer is composed of:
+- The actual server (HTTPServer)
+- A request dispatcher, instanciated on each request (HTTPRequestDispatcher)
+- Request handlers instanciated by the dispatcher(deriving from HTTPRequestHandler) 
+*/
+class HTTPServer
+{
+public:
+  ///Instantiates the HTTP Server
+  HTTPServer();
+  ~HTTPServer();
+  
+  struct handlersComp //Used to order handlers in the right way
+  {
+    bool operator() (const string& handler1, const string& handler2) const
+    {
+      //The first handler is longer than the second one
+      if (handler1.length() > handler2.length())
+        return true; //Returns true if handler1 is to appear before handler2
+      else if (handler1.length() < handler2.length())
+        return false;
+      else //To avoid the == case, sort now by address
+        return ((&handler1)>(&handler2));
+    }
+  };
+
+  ///Adds a handler
+  /**
+  Appends a handler to the handlers list
+  @param T : class which will be instanciated to serve these requests
+  @param path : requests starting with this path will be served using this handler
+  */
+  template<typename T>
+  void addHandler(const char* path) //Template decl in header
+  { m_lpHandlers[path] = &T::inst; }
+  
+  ///Starts listening
+  /**
+  Binds server to a specific port and starts listening
+  @param port : port on which to listen for incoming connections
+  */
+  void bind(int port = 80);
+  
+private:
+  friend class HTTPRequestDispatcher;
+
+  void onTCPSocketEvent(TCPSocketEvent e);
+  
+  TCPSocket* m_pTCPSocket;
+  map< string, HTTPRequestHandler*(*)(const char*, const char*, TCPSocket*), handlersComp > m_lpHandlers;
+
+};
+
+//Including handlers here for more convenience
+#include "impl/RPCHandler.h"
+#include "impl/FSHandler.h"
+#include "impl/SimpleHandler.h"
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/server/impl/FSHandler.cpp	Sat Sep 18 13:31:41 2010 +0000
@@ -0,0 +1,160 @@
+
+/*
+Copyright (c) 2010 Donatien Garnier (donatiengar [at] gmail [dot] com)
+ 
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+ 
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+ 
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+
+#include "FSHandler.h"
+
+//#define __DEBUG
+#include "dbg/dbg.h"
+
+#define CHUNK_SIZE 128
+
+#define DEFAULT_PAGE "/index.htm"
+
+FSHandler::FSHandler(const char* rootPath, const char* path, TCPSocket* pTCPSocket) : HTTPRequestHandler(rootPath, path, pTCPSocket), m_err404(false)
+{}
+
+FSHandler::~FSHandler()
+{
+  if(m_fp)
+    fclose(m_fp);
+  DBG("\r\nHandler destroyed\r\n");
+}
+
+//static init
+map<string,string> FSHandler::m_lFsPath = map<string,string>();
+
+void FSHandler::mount(const string& fsPath, const string& rootPath)
+{
+  m_lFsPath[rootPath]=fsPath;
+}
+
+void FSHandler::doGet()
+{
+  DBG("\r\nIn FSHandler::doGet() - rootPath=%s, path=%s\r\n", rootPath().c_str(), path().c_str());
+  //FIXME: Translate path to local/path
+  string checkedRootPath = rootPath();
+  if(checkedRootPath.empty())
+    checkedRootPath="/";
+  string filePath = m_lFsPath[checkedRootPath];
+  if (path().size() > 1)
+  {
+    filePath += path();
+  }
+  else
+  {
+    filePath += DEFAULT_PAGE;
+  }
+  
+  DBG("Trying to open %s\n", filePath.c_str());
+
+  m_fp = fopen(filePath.c_str(), "r"); //FIXME: if null, error 404
+  
+  if(!m_fp)
+  {
+    m_err404 = true;
+    setErrCode(404);
+    const char* msg = "File not found.";
+    setContentLen(strlen(msg));
+    respHeaders()["Content-Type"] = "text/html";
+    respHeaders()["Connection"] = "close";
+    writeData(msg,strlen(msg)); //Only send header
+    DBG("\r\nExit FSHandler::doGet() w Error 404\r\n");
+    return;
+  }
+    
+  //Seek EOF to get length
+  fseek(m_fp, 0, SEEK_END);
+  setContentLen( ftell(m_fp) );
+  fseek(m_fp, 0, SEEK_SET); //Goto SOF
+
+  respHeaders()["Connection"] = "close";
+  onWriteable();
+  DBG("\r\nExit SimpleHandler::doGet()\r\n");
+}
+
+void FSHandler::doPost()
+{
+
+}
+
+void FSHandler::doHead()
+{
+
+}
+
+void FSHandler::onReadable() //Data has been read
+{
+
+}
+
+void FSHandler::onWriteable() //Data has been written & buf is free
+{
+  DBG("\r\nFSHandler::onWriteable() event\r\n");
+  if(m_err404)
+  {
+    //Error has been served, now exit
+    close();
+    return;
+  }
+  
+  static char rBuf[CHUNK_SIZE];
+  while(true)
+  {
+    int len = fread(rBuf, 1, CHUNK_SIZE, m_fp);
+    if(len>0)
+    {
+      int writtenLen = writeData(rBuf, len);
+      if(writtenLen < 0) //Socket error
+      {
+        DBG("FSHandler: Socket error %d\n", writtenLen);
+        if(writtenLen == TCPSOCKET_MEM)
+        {
+          fseek(m_fp, -len, SEEK_CUR);
+          return; //Wait for the queued TCP segments to be transmitted
+        }
+        else
+        {
+          //This is a critical error
+          close();
+          return; 
+        }
+      }
+      else if(writtenLen < len) //Short write, socket's buffer is full
+      {
+        fseek(m_fp, writtenLen - len, SEEK_CUR);
+        return;
+      }
+    }
+    else
+    {
+      close(); //Data written, we can close the connection
+      return;
+    }
+  }
+}
+
+void FSHandler::onClose() //Connection is closing
+{
+  if(m_fp)
+    fclose(m_fp);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/server/impl/FSHandler.h	Sat Sep 18 13:31:41 2010 +0000
@@ -0,0 +1,61 @@
+
+/*
+Copyright (c) 2010 Donatien Garnier (donatiengar [at] gmail [dot] com)
+ 
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+ 
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+ 
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+
+#ifndef FS_HANDLER_H
+#define FS_HANDLER_H
+
+#include "../HTTPRequestHandler.h"
+#include "mbed.h"
+
+#include <map>
+using std::map;
+
+#include <string>
+using std::string;
+
+class FSHandler : public HTTPRequestHandler
+{
+public:
+  FSHandler(const char* rootPath, const char* path, TCPSocket* pTCPSocket);
+  virtual ~FSHandler();
+  
+  static void mount(const string& fsPath, const string& rootPath);
+
+//protected:
+  static inline HTTPRequestHandler* inst(const char* rootPath, const char* path, TCPSocket* pTCPSocket) { return new FSHandler(rootPath, path, pTCPSocket); } //if we ever could do static virtual functions, this would be one
+
+  virtual void doGet();
+  virtual void doPost();
+  virtual void doHead();
+  
+  virtual void onReadable(); //Data has been read
+  virtual void onWriteable(); //Data has been written & buf is free
+  virtual void onClose(); //Connection is closing
+  
+private:
+  FILE* m_fp;
+  bool m_err404;
+  static map<string,string> m_lFsPath;
+};
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/server/impl/RPCHandler.cpp	Sat Sep 18 13:31:41 2010 +0000
@@ -0,0 +1,115 @@
+
+/*
+Copyright (c) 2010 Donatien Garnier (donatiengar [at] gmail [dot] com)
+ 
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+ 
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+ 
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+
+#include "RPCHandler.h"
+#include "rpc.h"
+
+//#define __DEBUG
+#include "dbg/dbg.h"
+
+#define RPC_DATA_LEN 128
+
+RPCHandler::RPCHandler(const char* rootPath, const char* path, TCPSocket* pTCPSocket) : HTTPRequestHandler(rootPath, path, pTCPSocket)
+{}
+
+RPCHandler::~RPCHandler()
+{
+  DBG("\r\nHandler destroyed\r\n");
+}
+
+void RPCHandler::doGet()
+{
+  DBG("\r\nIn RPCHandler::doGet()\r\n");
+  char resp[RPC_DATA_LEN] = {0};
+  char req[RPC_DATA_LEN] = {0};
+  
+  DBG("\r\nPath : %s\r\n", path().c_str());
+  DBG("\r\nRoot Path : %s\r\n", rootPath().c_str());
+  
+  //Remove path
+  strncpy(req, path().c_str(), RPC_DATA_LEN-1);
+  DBG("\r\nRPC req : %s\r\n", req);
+  
+  //Remove %20, +, from req
+  cleanReq(req);
+  DBG("\r\nRPC req : %s\r\n", req);
+  
+  //Do RPC Call
+  mbed::rpc(req, resp); //FIXME: Use bool result
+  
+  //Response
+  setContentLen( strlen(resp) );
+  
+  //Make sure that the browser won't cache this request
+  respHeaders()["Cache-control"]="no-cache;no-store";
+ // respHeaders()["Cache-control"]="no-store";
+  respHeaders()["Pragma"]="no-cache";
+  respHeaders()["Expires"]="0";
+  
+  //Write data
+  respHeaders()["Connection"] = "close";
+  writeData(resp, strlen(resp));
+  DBG("\r\nExit RPCHandler::doGet()\r\n");
+}
+
+void RPCHandler::doPost()
+{
+
+}
+
+void RPCHandler::doHead()
+{
+
+}
+
+  
+void RPCHandler::onReadable() //Data has been read
+{
+
+}
+
+void RPCHandler::onWriteable() //Data has been written & buf is free
+{
+  DBG("\r\nRPCHandler::onWriteable() event\r\n");
+  close(); //Data written, we can close the connection
+}
+
+void RPCHandler::onClose() //Connection is closing
+{
+  //Nothing to do
+}
+
+void RPCHandler::cleanReq(char* data)
+{
+  char* p;
+  static const char* lGarbage[2] = {"%20", "+"};
+  for(int i = 0; i < 2; i++)
+  {
+    while( p = strstr(data, lGarbage[i]) )
+    {
+      memset((void*) p, ' ', strlen(lGarbage[i]));
+    }
+  }
+}
+  
+  
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/server/impl/RPCHandler.h	Sat Sep 18 13:31:41 2010 +0000
@@ -0,0 +1,50 @@
+
+/*
+Copyright (c) 2010 Donatien Garnier (donatiengar [at] gmail [dot] com)
+ 
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+ 
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+ 
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+
+#ifndef RPC_HANDLER_H
+#define RPC_HANDLER_H
+
+#include "../HTTPRequestHandler.h"
+
+class RPCHandler : public HTTPRequestHandler
+{
+public:
+  RPCHandler(const char* rootPath, const char* path, TCPSocket* pTCPSocket);
+  virtual ~RPCHandler();
+
+//protected:
+  static inline HTTPRequestHandler* inst(const char* rootPath, const char* path, TCPSocket* pTCPSocket) { return new RPCHandler(rootPath, path, pTCPSocket); } //if we ever could do static virtual functions, this would be one
+
+  virtual void doGet();
+  virtual void doPost();
+  virtual void doHead();
+  
+  virtual void onReadable(); //Data has been read
+  virtual void onWriteable(); //Data has been written & buf is free
+  virtual void onClose(); //Connection is closing
+
+protected:
+  void cleanReq(char* data);
+};
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/server/impl/SimpleHandler.cpp	Sat Sep 18 13:31:41 2010 +0000
@@ -0,0 +1,72 @@
+
+/*
+Copyright (c) 2010 Donatien Garnier (donatiengar [at] gmail [dot] com)
+ 
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+ 
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+ 
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+
+#include "SimpleHandler.h"
+
+//#define __DEBUG
+#include "dbg/dbg.h"
+
+SimpleHandler::SimpleHandler(const char* rootPath, const char* path, TCPSocket* pTCPSocket) : HTTPRequestHandler(rootPath, path, pTCPSocket)
+{}
+
+SimpleHandler::~SimpleHandler()
+{
+  DBG("\r\nHandler destroyed\r\n");
+}
+
+void SimpleHandler::doGet()
+{
+  DBG("\r\nIn SimpleHandler::doGet()\r\n");
+  const char* resp = "Hello world !";
+  setContentLen( strlen(resp) );
+  respHeaders()["Connection"] = "close";
+  writeData(resp, strlen(resp));
+  DBG("\r\nExit SimpleHandler::doGet()\r\n");
+}
+
+void SimpleHandler::doPost()
+{
+
+}
+
+void SimpleHandler::doHead()
+{
+
+}
+
+  
+void SimpleHandler::onReadable() //Data has been read
+{
+
+}
+
+void SimpleHandler::onWriteable() //Data has been written & buf is free
+{
+  DBG("\r\nSimpleHandler::onWriteable() event\r\n");
+  close(); //Data written, we can close the connection
+}
+
+void SimpleHandler::onClose() //Connection is closing
+{
+  //Nothing to do
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/server/impl/SimpleHandler.h	Sat Sep 18 13:31:41 2010 +0000
@@ -0,0 +1,47 @@
+
+/*
+Copyright (c) 2010 Donatien Garnier (donatiengar [at] gmail [dot] com)
+ 
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+ 
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+ 
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+
+#ifndef SIMPLE_HANDLER_H
+#define SIMPLE_HANDLER_H
+
+#include "../HTTPRequestHandler.h"
+
+class SimpleHandler : public HTTPRequestHandler
+{
+public:
+  SimpleHandler(const char* rootPath, const char* path, TCPSocket* pTCPSocket);
+  virtual ~SimpleHandler();
+
+//protected:
+  static inline HTTPRequestHandler* inst(const char* rootPath, const char* path, TCPSocket* pTCPSocket) { return new SimpleHandler(rootPath, path, pTCPSocket); } //if we ever could do static virtual functions, this would be one
+
+  virtual void doGet();
+  virtual void doPost();
+  virtual void doHead();
+  
+  virtual void onReadable(); //Data has been read
+  virtual void onWriteable(); //Data has been written & buf is free
+  virtual void onClose(); //Connection is closing
+};
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/solar2.cpp	Sat Sep 18 13:31:41 2010 +0000
@@ -0,0 +1,278 @@
+/* This version has the index file and data pages on a  SD card (512Mbyte)
+  it does not suffer from the autorun problem when directly writtin to the mbed flash memory
+ It makes readings from one solar panel for open and loaded voltages every 'interval' seconds
+ Every readingsPerPage a new web page is created and indexed on a readings web page
+ Activty is shown by the flashing blue led (0.5s) means it is connected and output via the serial
+ over usb port. 
+ 
+ Data is preserved on subsequent power ups by incrementing file number.
+ 
+ PMR   15/9/10 */
+
+#include "mbed.h"
+#include "EthernetNetIf.h"
+#include "HTTPServer.h"
+#include "NTPClient.h"
+#include "SDFileSystem.h"
+
+
+DigitalOut led1(LED1, "led1");
+DigitalOut led2(LED2, "led2");
+DigitalOut led3(LED3, "led3");
+DigitalOut led4(LED4, "led4");
+
+AnalogIn Voltmeter (p20);
+
+//LocalFileSystem fs("webfs");  // this could be any name
+
+SDFileSystem sd(p5, p6, p7, p8, "sd"); // mosi, miso, sclk, cs, name
+
+EthernetNetIf eth;  
+HTTPServer svr;
+NTPClient ntp;
+
+bool file_exists(const char * filename)
+{
+    if (FILE * file = fopen(filename, "r"))
+    {
+        fclose(file);
+        return true;
+    }
+    return false;
+}
+
+void update_web(time_t ctTime , char *filename, char *filename2)
+ {
+ // updates the readings page, filename with new web file, filename2
+    FILE *fp;
+     char locTime[32];
+      char *ftag;
+      char tempfile[32];
+     fp=NULL;
+    strcpy (tempfile,filename2);     // this prevents corruption of filenam2
+    strtok(tempfile,"d/");  // strip off /sd/
+    ftag=strtok(NULL,"\0");
+     fp=fopen (filename, "a");
+     if (fp !=NULL)
+    {
+      time_t seconds = time(NULL);
+      strftime(locTime,32,"%d/%b/%Y  %H:%M:%S",localtime(&seconds));
+       fprintf(fp, "\n <a href="); fprintf(fp,"%s ",ftag);  fprintf(fp," > readings at %s </a> </br>",locTime);
+        fclose(fp);
+   }  
+ }
+ 
+ char *update_file(char *filename)
+
+  {
+  // check for previous and increnment file number if filename exists
+   int n ;
+    char *ftag;
+    char *ext;
+    char *fn;
+    char filename2[32];
+  
+  
+//    printf(" filename is now0 %s\n",filename);
+   while  (file_exists(filename))
+   {
+   //increment filename
+   // strip off extension
+     n = 0;
+    
+    ext=strstr(filename,".");
+ //   strcpy(tmp,ext);
+ //    printf(" ext %s\n",ext);
+
+    strtok(filename,"d/"); 
+// extract text part of filename and moving pointer to extract the numerical part
+    ftag=strtok(NULL,"0")+1; fn=strtok(NULL,"\0");
+//    printf(" fname %s\n",ftag);
+ //atoi ignores spaces but not characters
+    n=atoi(fn);
+    n=n+1;
+ //  printf("fn %i\n",n);
+ // re-assemble filename
+     strcpy(filename2,"/sd/"); strcpy(fn,"0");
+     strcat(filename2,ftag); strcat(filename2,fn);
+ //    printf(" filename is now1 %s\n",filename2);
+     strcpy(fn,"");
+     sprintf(fn,"%d", n );
+     strcat(filename2,fn); strcat(filename2,".htm");
+ //     printf(" filename is now2 %s\n",filename2);
+     strcpy(filename,filename2); 
+   }
+   
+    return(filename);
+  }
+
+void createVolts(time_t ctTime, char *filename)
+ {
+  
+    FILE *fp = fopen(filename, "a");  // Open local filename
+    // it ignores path and date defaults 1/1/2008 becausse RTC not set
+    // if I call ithe localfilesystem www rather than 'local' it writes and is seen when drive is refreshed
+    
+    fprintf(fp, "<title> Volt meter test page </title>\n");
+    fprintf(fp,"<h1>Volts of the day from port 1</h1>");
+    fprintf(fp," Voc,            Vld,           time </br>");
+//    fprintf(fp, "volts %f V at %s </br>",Voltmeter.read(), ctime(&ctTime));
+    fclose(fp);
+  
+ }
+ 
+ int updateVolts (time_t ctTime , char *filename)
+ {
+ FILE *fp;
+ int ckc,i;
+ int avg=10;
+ float volts;
+  char locTime[32];
+ // check not been displayed
+  fp=NULL;  ckc =0;
+  DigitalOut loadSwitch(p21);
+  Timer tm;
+  loadSwitch=0;  // load off
+  while ( (fp== NULL)  &&  (ckc++ < 20))
+     {
+       fp=fopen (filename, "a");
+     }  
+  if (ckc >19)
+       {
+         return(1);  // if access prevented
+       }    
+       else
+         {
+          time_t seconds = time(NULL);
+          strftime(locTime,32,"%d-%b-%y  %H:%M:%S",localtime(&seconds));
+// output in form of excel .csv
+// oc voltage
+         volts=0;
+         for(i=0; i < avg ; i++) volts= Voltmeter.read();
+         volts = volts /avg; 
+         fprintf(fp, "%f,",volts); 
+// loaded voltage
+         tm.start();
+         loadSwitch =1;
+// after 1 second read the loaded voltage
+         volts=0;
+         while ( tm.read() < 1.0);
+         for(i=0; i < avg; i++) volts= Voltmeter.read();
+         volts = volts /avg;       
+         fprintf(fp, "%f,%s </br>" ,volts,locTime);
+         loadSwitch=0;
+         fclose(fp);
+          return(0);
+          }
+    
+ }
+ 
+ 
+ long int loadTime(void)
+ {
+   time_t ctTime;
+  ctTime = time(NULL); 
+  char locTime[32]; 
+//  printf("Current time is (UTC): %s\n\r", ctime(&ctTime));  
+
+  Host server(IpAddr(), 123, "0.uk.pool.ntp.org");  
+  ntp.setTime(server);
+    
+  ctTime = time(NULL);  
+  set_time (ctTime);  // sets local rtc
+  time_t seconds = time(NULL);
+  strftime(locTime,32, "%I:%M %p\r\n",localtime(&seconds));
+  printf("RTC Time is now (UTC): %s\n\r",locTime );   
+  return (ctTime);
+ }
+
+
+int main() {
+
+  time_t systemTime;
+  Base::add_rpc_class<DigitalOut>();
+  char fname[32];
+  char *fn;
+  int readings =0;
+  const int readingsPerPage = 50;
+  long int now_sec,last_time;
+  const long int interval = 30;  // seconds
+ 
+
+  printf("Setting up...\n");
+  EthernetErr ethErr = eth.setup();
+  if(ethErr)
+  {
+    printf("Error %d in setup.\n", ethErr);
+    return -1;
+  }
+  printf("Setup OK\n");
+  
+//  FSHandler::mount("/webfs", "/files"); //Mount /wwww path on /files web path  - this has no meaning
+  FSHandler::mount("/sd", "/"); //Mount /wwww path on web root path
+ 
+  
+//  svr.addHandler<SimpleHandler>("/");  hard code for Hello world 
+
+  
+  systemTime=loadTime();  
+  
+  printf("System is now (UTC): %s\n\r", ctime(&systemTime)); 
+  Timer tm;
+  tm.start();
+  
+  
+  svr.addHandler<RPCHandler>("/rpc");   // sets up the remote procedure call handler
+  svr.addHandler<FSHandler>("/files");//  this does not see the subdirectory
+  svr.addHandler<FSHandler>("/"); //Default handler
+  svr.bind(80);
+  // assemble file name
+  // examples sprintf(ts_adj, "%02d", Hours);  // %02d includes leading zero
+  //     strncat(ts,ts_adj,2);
+   //Listen indefinitely
+   printf("Listening...\n\r");
+   
+   
+  strcpy(fname,"/sd/volts00.htm");
+  fn = update_file(fname);   // preserve previous data
+  strcpy(fname,fn);
+  createVolts(systemTime,fname);
+  printf(" updated file %s\n\r",fname);
+  update_web(systemTime,"/sd/readings.htm",fname);  // log reading file
+ readings =0;
+ while (true)
+ { 
+ 
+  last_time=0; // seconds
+
+   while(readings < readingsPerPage )
+   {
+    Net::poll();
+    systemTime=time(NULL);
+    time_t seconds =time(NULL);
+    now_sec = seconds;
+     if(tm.read()>0.5)
+      {
+       led1=!led1; //Show that we are alive
+         tm.start();
+      
+       }
+    if (now_sec > (last_time + interval))
+    {
+      if (updateVolts(systemTime,fname)) printf("  %s not updated \n\r", fname); 
+          else printf(" reading %i\n\r",readings);
+        last_time=now_sec;
+        readings++;
+      
+     }
+   }
+  fn = update_file(fname);
+  strcpy(fname,fn);
+  createVolts(systemTime,fname);
+  printf(" updated file %s\n\r",fname);
+  update_web(systemTime,"/sd/readings.htm",fname);
+   readings=0;
+  }
+  return 0;
+
+}
\ No newline at end of file