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

nfuncs.cpp

Committer:
DeMein
Date:
2011-02-27
Revision:
0:67a55a82ce06

File content as of revision 0:67a55a82ce06:

/* 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); 
}