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
Diff: nfuncs.cpp
- 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