MMEx with SPI Slave to allow legacy devices to communicate with modern media such as USB, SD cards, the internet and all of the mbed\'s other interfaces

Dependencies:   NetServices MSCUsbHost mbed TMP102 SDFileSystem

Revision:
0:67a55a82ce06
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/nfuncs.cpp	Sun Feb 27 18:54:40 2011 +0000
@@ -0,0 +1,382 @@
+/* MMEx for MBED - Network Command processing
+ * Copyright (c) 2011 MK
+ *
+ * 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 nfuncs.cpp
+  \brief Commands starting with N for Networking commands
+*/
+
+#include "nfuncs.h"
+
+EthernetNetIf *eth;
+HTTPClient http;
+HTTPResult result;
+HTTPServer *server;
+bool completed = false;
+
+/**
+ *  Global variable to indicate if network is running
+ */
+bool network_enabled = false;
+
+/**
+ *  Global variable to indicate if HTTP Server is running
+ */
+bool httpserver_enabled = false; 
+ 
+/**
+ *  Poll the network (must be called periodically while server is active)
+ */
+void netpoll() 
+{
+  if (network_enabled) {
+    _led3 = 1;
+    Net::poll();
+    _led3 = 0;
+  }
+}
+
+/** main entry for parsing C-commands
+ *
+ */
+void parse_N() {
+  // process parameters
+  DBG_msg("parse_N", inbuf);
+  err_num = noerror;
+ 
+  wipesp(inbuf);                    // remove all spaces from string
+
+  if (inbuf[1] != NULL) {
+    switch (inbuf[1]) {
+      case ninit    : do_ninit();
+                      break;
+      case nstop    : do_nstop();
+                      break;
+      case ntime    : do_ntime();
+                      break;                    
+      case nget     : do_nget();
+                      break;      
+      case nhttp    : do_nhttp();
+                      break;                                        
+      default       : do_ndefault();    // command not recognized
+                      break;
+    }
+  } else { do_ndefault(); }
+}
+            
+/** initialize the network interface
+ *
+ *  syntax: NI
+ */
+void do_ninit() {
+  char * hostname;
+  char * ipnums;
+  char s[50];
+  char ips[4][25];
+
+  DBG_msg("do_ninit", "Network initialisation\n");
+  
+  EthernetErr ethErr;
+
+  // check for alternate hostname in parameters
+  hostname = new char [param[par_H_].size() + 1];     // Host parameter
+  strcpy (hostname, param[par_H_].c_str());
+  if (hostname == NULL) hostname = MMEx_Hostname;
+  
+  // check for DCHP or not
+  // Parameter J is the fixed IP address in the following format:
+  //   ip netmask gateway dns
+  // each ip address is in the format x.y.z.t, separated by spaces
+  // When Param J is empty, DHCP will be used
+  ipnums =  new char [param[par_J_].size() + 1];     // Host parameter
+  strcpy (ipnums, param[par_J_].c_str());  
+  
+  
+  if (param[par_J_].size()< 10) {
+    DBG_msg("do_ninit", "DHCP config"); 
+    // DHCP chosen, initialize network
+    eth = new EthernetNetIf(hostname);
+    
+    // eth->setup();
+  } else {
+    // process fixed IP adresses
+    DBG_msg("do_ninit", "fixed IP"); 
+    DBG_msg("IP adresses", ipnums); 
+    
+    IpAddr *ipparam[4];
+    sscanf(ipnums, "%s %s %s %s", ips[0], ips[1], ips[2], ips[3]);
+    DBG_msg("IP number", ips[0]);
+    DBG_msg("netmask  ", ips[1]);
+    DBG_msg("gateway  ", ips[2]);
+    DBG_msg("dns      ", ips[3]);
+    
+    for ( int i = 0; i < 4; ++i ) {   
+      int ip1, ip2, ip3, ip4;
+      sscanf(ips[i], "%d.%d.%d.%d", &ip1, &ip2, &ip3, &ip4);
+      ipparam[i] = new IpAddr(ip1, ip2, ip3, ip4);
+    }      
+    // Setup IP with given adresses
+    eth = new EthernetNetIf(*ipparam[0],*ipparam[1],*ipparam[2],*ipparam[3]);
+    // eth->setup();
+  }
+  
+  int count = 0;
+  do {
+      DBG_int("do_ninit setup", ++count);
+      ethErr = eth->setup();
+      if (ethErr) DBG_int("do_ninit timeout", ethErr);
+  } while ((ethErr != ETH_OK) && (count < 5));   
+     
+  if (ethErr == ETH_OK) {
+    // connection worked 
+    network_enabled = true;
+    mldl.attach(&netpoll);  
+    DBG_msg("do_ninit", "Connected OK\n");
+    const char* hwAddr = eth->getHwAddr();
+    sprintf(s, "%02x:%02x:%02x:%02x:%02x:%02x",
+               hwAddr[0], hwAddr[1], hwAddr[2], hwAddr[3], hwAddr[4], hwAddr[5]);
+    DBG_msg("ninit MAC addr", s);   
+    param[par_M_].assign(s);             // set MAC address
+
+    IpAddr ethIp = eth->getIp();
+    sprintf(s, "%d.%d.%d.%d", ethIp[0], ethIp[1], ethIp[2], ethIp[3]);
+    upstring(s);    
+    DBG_msg("ninit MAC addr", s);
+    param[par_I_].assign(s);            // set MAC address 
+    
+    sprintf(s, "%s", eth->getHostname());
+    DBG_msg("ninit Hostname", s);
+    param[par_H_].assign(s);            // set Hostname
+  } else {
+    // in case initialization did not work
+    network_enabled = false;
+    DBG_msg("ninit", "network timout");
+    send_error(err_net_timeout);
+  }
+}
+
+/** stop the network interface
+ *
+ *  syntax: NS
+ */
+void do_nstop() {
+  DBG_msg("do_nstop", inbuf);
+  mldl.attach(NULL);  
+  delete eth;
+  network_enabled = false;
+}      
+      
+/** get network time
+ *
+ *  syntax: NT
+ *  URL of NTP server must be in parameter U
+ */
+void do_ntime() {
+  char s[255];  // for intermediate results
+  char s1[255]; // for intermediate results
+  time_t ctTime;
+  NTPClient ntp;
+  DBG_msg("do_ntime", inbuf);
+  
+  ctTime = time(NULL);         // current system time
+  sprintf(s, "%d %s", ctTime, ctime(&ctTime));
+  DBG_msg("MMEx time", s);
+  strcpy(s, param[par_U_].c_str());    // URL from parameter U
+  
+  Host server(IpAddr(), 123, s);
+  NTPResult r =  ntp.setTime(server);
+  if (r == NTP_OK) {
+    // time set
+    ctTime = time(NULL);
+    sprintf(s1, "%d %s", ctTime, ctime(&ctTime));
+    DBG_msg("MMEx time", s1);
+  } else {
+    // error in setting the time    
+    send_error(err_net_NTP);
+  }
+}         
+
+
+void request_callback(HTTPResult r) {
+  result = r;
+  completed = true;
+}
+
+/** get file through HTTP Stream
+ *
+ *  syntax: NG
+ *  URL of must be in parameter U, %n may be used for filename
+ */
+void do_nget() {
+
+  HTTPStream stream;
+  char Buf[512 + 1] = {0};
+  char s[255];    // for temp storage
+  int pnum, pos, count;
+  char * cstr;
+  int rdata, i;
+  bool go = true;
+  bool stopread = false;
+  int numbytes = 0;
+  
+  DBG_msg("do_nget", inbuf);
+  
+  completed = false;
+  
+  count = 0;
+  // next chars on the commandline is the number of bytes to read
+  if (inbuf[2] == NULL) {
+    // no value on the command line
+    numbytes = 0;
+  } else {
+    // now process line
+    for (i = 2; ((inbuf[i] >='0') && (inbuf[i] <= '9')); i++ ) {
+      numbytes = 10 * numbytes + (inbuf[i] - '0');
+    }
+  }
+  DBG_int("do_nget bytes:", numbytes);
+  
+  stream.readNext((byte*)Buf, 512);   //Point to buffer for the first read  
+  strcpy(s, param[par_U_].c_str());   // URL from parameter U
+    
+  // check for a % sign in s
+  pos = 0;
+  while ((s[pos] != NULL) && (s[pos] != c_percent)) pos++;  
+  if ((s[pos] != NULL) && ((pnum = getpnum(s[pos + 1])) >= 0)) {
+    // found and valid parameter, now insert
+    cstr = new char [param[pnum].size() + 1];
+    strcpy (cstr, param[pnum].c_str());
+    DBG_msg("param", cstr);
+    DBG_int("pos", pos);
+    remchar(s, pos, 2);           // remove %n, works better for insert
+    DBG_msg("do_nget", s); 
+    insertstr(s, cstr, pos);  // insert
+    DBG_msg("do_nget", s); 
+    delete[] cstr;
+  }
+    
+  HTTPResult r = http.get(s, &stream, request_callback);      // try to get the data
+  
+  // this is the main loop for reading the file
+  while((!completed)) {
+    Net::poll(); // polls the Networking stack
+    if(stream.readable()) {     
+      rdata = stream.readLen();  // number of bytes read   
+      DBG_int("rdata", rdata);   
+      Buf[stream.readLen()] = 0;  //Transform this buffer in zero-terminated char* string
+      
+      // now send data to our transmit buffer
+      i = 0;
+      while (go && (i < rdata)) {
+        DBG_chr("rd", Buf[i]);
+        mldl.tx_addp(Buf[i]);
+        i++;
+        count++;
+        // now check if we have to stop?    
+        if (!mldl.rx_empty()) {
+          stopread = (mldl.rxx_read(data_mode) < 0);   // intentional stop of read 
+          DBG_msg("do_nget", "forced stop");       
+        } 
+        go = !((count == numbytes) || stopread);
+      }
+      
+      //Buffer has been read, now we can put more data in it
+      stream.readNext((byte*)Buf, 512); 
+    }
+  }
+  
+  // we are done with the required number of bytes or found EOF
+  if (!stopread && (count != numbytes)) {
+    // real EOF found, so terminate by sending EOF
+    mldl.tx_add(c_escape);
+    mldl.tx_add(c_eof); 
+    DBG_int("do_nget: EOF at byte ", count);
+  }      
+      
+  if (stopread) {
+    DBG_msg("do_nget", "forced stop read received");
+    mldl.flush_tx();    // empty transmit buffer
+  }  
+    
+  DBG_int("do_nget: end read at byte ", count);
+}
+
+/** HTTP Server commands
+ *
+ * syntax: NHI[medium]: initialise and start HTTP Server
+ * [medium] = S, U or L for the filesystem to be used
+ * default filesystem is "/local"
+ * \n NHS: stop HTTP Server
+ *
+ */  
+void do_nhttp() {
+  char c;
+  char medium[10];
+  
+  DBG_msg("do_nhttp", inbuf);
+  
+  c = inbuf[3];            // [medium]
+  switch (c) {
+    case f_sdcard : strcpy(medium, rt_sd);    // "/sd"
+                    break;                   
+    case f_local  : strcpy(medium, rt_local); // "/local"
+                    break;                      
+    case f_usb    : strcpy(medium, rt_usb);   //  "/usb"
+                    break;                                            
+    default       : strcpy(medium, "/local"); // default
+                    break;    
+  } 
+
+  if (inbuf[2] == ninit) {
+    // HTTP server initialize
+    DBG_msg("HTTP Init", medium);
+    if (!network_enabled) do_ninit();
+    server = new HTTPServer;
+    FSHandler::mount(medium, "/" );
+    server->addHandler<FSHandler>("/");
+    server->addHandler<RPCHandler>("/rpc");
+    server->addHandler<SimpleHandler>("/simple");
+    server->bind(80);
+    httpserver_enabled = true; 
+    DBG_msg( "HTTP server", "started" );          
+    return;
+  }
+  
+  if (inbuf[2] == nstop) {    
+    // HTTP Server stop
+    delete server;
+    httpserver_enabled = false;
+    DBG_msg( "HTTP server", "stopped" );
+    return;
+  }
+ 
+  do_ndefault();
+}
+             
+/** send error message, command not recognized
+ *
+ */                              
+void do_ndefault() {
+  // command not recognized
+  DBG_msg("do_ndefault", inbuf);
+  send_error(err_notrecognized); 
+}
\ No newline at end of file