From ff8b3cc2886ca2b1da0b7e4311127410158ba9c1 Mon Sep 17 00:00:00 2001 From: maniacbug Date: Mon, 2 Jan 2012 07:09:58 -0800 Subject: [PATCH 01/15] Created new 'telnet_server' example, based on uip_hello_world --- examples/telnet_server/Jamfile | 224 +++++++++++++++++++++++ examples/telnet_server/printf.h | 37 ++++ examples/telnet_server/telnet_server.pde | 105 +++++++++++ 3 files changed, 366 insertions(+) create mode 100644 examples/telnet_server/Jamfile create mode 100644 examples/telnet_server/printf.h create mode 100644 examples/telnet_server/telnet_server.pde diff --git a/examples/telnet_server/Jamfile b/examples/telnet_server/Jamfile new file mode 100644 index 0000000..9f7a3bd --- /dev/null +++ b/examples/telnet_server/Jamfile @@ -0,0 +1,224 @@ +# (1) Project Information + +PROJECT_LIBS = SPI NanodeUIP NanodeUNIO ; +PROJECT_DIRS = $(PWD) ; + +# (2) Board Information + +UPLOAD_PROTOCOL ?= arduino ; +UPLOAD_SPEED ?= 57600 ; +MCU ?= atmega328p ; +F_CPU ?= 16000000 ; +CORE ?= arduino ; +VARIANT ?= standard ; +ARDUINO_VERSION ?= 100 ; + +# (3) USB Ports + +PORTS = p4 p6 p9 u0 u1 u2 ; +PORT_p6 = /dev/tty.usbserial-A600eHIs ; +PORT_p4 = /dev/tty.usbserial-A40081RP ; +PORT_p9 = /dev/tty.usbserial-A9007LmI ; +PORT_u0 = /dev/ttyUSB0 ; +PORT_u1 = /dev/ttyUSB1 ; +PORT_u2 = /dev/ttyUSB2 ; + +# (4) Location of AVR tools +# +# This configuration assumes using avr-tools that were obtained separate from the Arduino +# distribution. + +if $(OS) = MACOSX +{ + AVR_BIN = /usr/local/avrtools/bin ; + AVR_ETC = /usr/local/avrtools/etc ; + AVR_INCLUDE = /usr/local/avrtools/include ; +} +else +{ + AVR_BIN = /usr/bin ; + AVR_INCLUDE = /usr/lib/avr/include ; + AVR_ETC = /etc ; +} + +# (5) Directories where Arduino core and libraries are located + +ARDUINO_DIR ?= /opt/Arduino ; +ARDUINO_CORE = $(ARDUINO_DIR)/hardware/arduino/cores/$(CORE) $(ARDUINO_DIR)/hardware/arduino/variants/$(VARIANT) ; +ARDUINO_LIB = $(ARDUINO_DIR)/libraries ; +SKETCH_LIB = $(HOME)/Source/Arduino/libraries ; + +# +# -------------------------------------------------- +# Below this line usually never needs to be modified +# + +# Tool locations + +CC = $(AVR_BIN)/avr-gcc ; +C++ = $(AVR_BIN)/avr-g++ ; +LINK = $(AVR_BIN)/avr-gcc ; +AR = $(AVR_BIN)/avr-ar rcs ; +RANLIB = ; +OBJCOPY = $(AVR_BIN)/avr-objcopy ; +AVRDUDE = $(AVR_BIN)/avrdude ; + +# Flags + +DEFINES += F_CPU=$(F_CPU)L ARDUINO=$(ARDUINO_VERSION) VERSION_H ; +OPTIM = -Os ; +CCFLAGS = -Wall -Wextra -Wno-strict-aliasing -mmcu=$(MCU) -ffunction-sections -fdata-sections ; +C++FLAGS = $(CCFLAGS) -fno-exceptions -fno-strict-aliasing ; +LINKFLAGS = $(OPTIM) -lm -Wl,--gc-sections -mmcu=$(MCU) ; +AVRDUDEFLAGS = -V -F -D -C $(AVR_ETC)/avrdude.conf -p $(MCU) -c $(UPLOAD_PROTOCOL) -b $(UPLOAD_SPEED) ; + +# Search everywhere for headers + +HDRS = $(PROJECT_DIRS) $(AVR_INCLUDE) $(ARDUINO_CORE) $(ARDUINO_LIB)/$(PROJECT_LIBS) $(ARDUINO_LIB)/$(PROJECT_LIBS)/utility $(SKETCH_LIB)/$(PROJECT_LIBS) ; + +# Output locations + +LOCATE_TARGET = $(F_CPU) ; +LOCATE_SOURCE = $(F_CPU) ; + +# +# Custom rules +# + +rule GitVersion +{ + Always $(<) ; + Depends all : $(<) ; +} + +actions GitVersion +{ + echo "const char program_version[] = \"\\" > $(<) + git log -1 --pretty=format:%h >> $(<) + echo "\";" >> $(<) +} + +GitVersion version.h ; + +rule Pde +{ + Depends $(<) : $(>) ; + MakeLocate $(<) : $(LOCATE_SOURCE) ; + Clean clean : $(<) ; +} + +if ( $(ARDUINO_VERSION) < 100 ) +{ + ARDUINO_H = WProgram.h ; +} +else +{ + ARDUINO_H = Arduino.h ; +} + +actions Pde +{ + echo "#include <$(ARDUINO_H)>" > $(<) + echo "#line 1 \"$(>)\"" >> $(<) + cat $(>) >> $(<) +} + +rule C++Pde +{ + local _CPP = $(>:B).cpp ; + Pde $(_CPP) : $(>) ; + C++ $(<) : $(_CPP) ; +} + +rule UserObject +{ + switch $(>:S) + { + case .ino : C++Pde $(<) : $(>) ; + case .pde : C++Pde $(<) : $(>) ; + } +} + +rule Objects +{ + local _i ; + + for _i in [ FGristFiles $(<) ] + { + local _b = $(_i:B)$(SUFOBJ) ; + local _o = $(_b:G=$(SOURCE_GRIST:E)) ; + Object $(_o) : $(_i) ; + Depends obj : $(_o) ; + } +} + +actions Link bind NEEDLIBS +{ + $(LINK) $(LINKFLAGS) -o $(<) $(UNDEFS) $(NEEDLIBS) $(LINKLIBS) $(>) +} + +rule Library +{ + LibraryFromObjects $(<) : $(>:B)$(SUFOBJ) ; + Objects $(>) ; +} + +rule Main +{ + MainFromObjects $(<) : $(>:B)$(SUFOBJ) ; + Objects $(>) ; +} + +rule Hex +{ + Depends $(<) : $(>) ; + MakeLocate $(<) : $(LOCATE_TARGET) ; + Depends hex : $(<) ; + Clean clean : $(<) ; +} + +actions Hex +{ + $(OBJCOPY) -O ihex -R .eeprom $(>) $(<) +} + +rule Upload +{ + Depends $(1) : $(2) ; + Depends $(2) : $(3) ; + NotFile $(1) ; + Always $(1) ; + Always $(2) ; + UploadAction $(2) : $(3) ; +} + +actions UploadAction +{ + $(AVRDUDE) $(AVRDUDEFLAGS) -P $(<) $(AVRDUDE_WRITE_FLASH) -U flash:w:$(>):i +} + +rule Arduino +{ + LINKFLAGS on $(<) = $(LINKFLAGS) -Wl,-Map=$(LOCATE_TARGET)/$(<:B).map ; + #LinkLibraries $(<) : core libs ; + Main $(<) : $(>) ; + Hex $(<:B).hex : $(<) ; + for _p in $(PORTS) + { + Upload $(_p) : $(PORT_$(_p)) : $(<:B).hex ; + } +} + +# +# Targets +# + +# Grab everything from the core directory +#Library core : [ GLOB $(ARDUINO_CORE) : *.c *.cpp ] ; + +# Grab everything from libraries. To avoid this "grab everything" behaviour, you +# can specify specific modules to pick up in PROJECT_MODULES +#Library libs : [ GLOB $(ARDUINO_LIB)/$(PROJECT_LIBS) $(ARDUINO_LIB)/$(PROJECT_LIBS)/utility $(SKETCH_LIB)/$(PROJECT_LIBS) : *.cpp *.c ] ; + +# Main output executable +Arduino $(PWD:B).elf : $(PROJECT_MODULES) [ GLOB $(ARDUINO_CORE) : *.c *.cpp ] [ GLOB $(ARDUINO_LIB)/$(PROJECT_LIBS) $(ARDUINO_LIB)/$(PROJECT_LIBS)/utility $(SKETCH_LIB)/$(PROJECT_LIBS) : *.cpp *.c ] [ GLOB $(PROJECT_DIRS) : *.c *.cpp *.pde *.ino ] ; diff --git a/examples/telnet_server/printf.h b/examples/telnet_server/printf.h new file mode 100644 index 0000000..b2efd56 --- /dev/null +++ b/examples/telnet_server/printf.h @@ -0,0 +1,37 @@ +/* + Copyright (C) 2011 J. Coliz + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + version 2 as published by the Free Software Foundation. + */ + +/** + * @file printf.h + * + * Setup necessary to direct stdout to the Arduino Serial library, which + * enables 'printf' + */ + +#ifndef __PRINTF_H__ +#define __PRINTF_H__ + +#ifdef ARDUINO + +int serial_putc( char c, FILE * ) +{ + Serial.write( c ); + + return c; +} + +void printf_begin(void) +{ + fdevopen( &serial_putc, 0 ); +} + +#else +#error This example is only for use on Arduino. +#endif // ARDUINO + +#endif // __PRINTF_H__ diff --git a/examples/telnet_server/telnet_server.pde b/examples/telnet_server/telnet_server.pde new file mode 100644 index 0000000..dcb1f50 --- /dev/null +++ b/examples/telnet_server/telnet_server.pde @@ -0,0 +1,105 @@ +#include +#include +#include +#include "printf.h" + +struct hello_world_state { + struct psock p; + byte inputbuffer[20]; + char name[20]; + char quest[20]; +}; +UIPASSERT(sizeof(struct hello_world_state)<=TCP_APP_STATE_SIZE) + +/* This function defines what the "hello world" application does + once a connection has been established. It doesn't have to + deal with setting up the connection. */ +static int hello_world_connection(struct hello_world_state *s) +{ + PSOCK_BEGIN(&s->p); + + PSOCK_SEND_STR(&s->p, "Hello. What is your name?\n>>> "); + PSOCK_READTO(&s->p, '\n'); + /* The input buffer is an array of bytes received from the + network. It's not a string. We cheekily cast it to a string + here on the assumption that we're receiving plain ASCII and + not UTF8 or anything more fancy... */ + s->inputbuffer[PSOCK_DATALEN(&s->p)]=0; + strncpy(s->name, (const char *)s->inputbuffer, sizeof(s->name)); + PSOCK_SEND_STR(&s->p, "What is your quest?\n>>> "); + PSOCK_READTO(&s->p, '\n'); + s->inputbuffer[PSOCK_DATALEN(&s->p)]=0; + strncpy(s->quest, (const char *)s->inputbuffer, sizeof(s->quest)); + PSOCK_SEND_STR(&s->p, "Hello "); + PSOCK_SEND_STR(&s->p, s->name); + PSOCK_SEND_STR(&s->p, "Your quest is: "); + PSOCK_SEND_STR(&s->p, s->quest); + PSOCK_CLOSE(&s->p); + + PSOCK_END(&s->p); +} + +/* This function deals with all incoming events for the "hello + world" application, including dealing with new connections. */ +static void hello_world_appcall(void) +{ + struct hello_world_state *s = (struct hello_world_state *)&(uip_conn->appstate); + + /* + * If a new connection was just established, we should initialize + * the protosocket in our application's state structure. + */ + if(uip_connected()) { + PSOCK_INIT(&s->p, s->inputbuffer, sizeof(s->inputbuffer)-1); + } + + /* + * We run the protosocket function that actually handles the + * communication. We pass it a pointer to the application state + * of the current connection. + */ + hello_world_connection(s); +} + +static void resolv_found(char *name,uint16_t *addr) { + char buf[30]=": addr="; + Serial.print(name); + uip.format_ipaddr(buf+7,addr); + Serial.println(buf); +} + +void dhcp_status(int s,const uint16_t *dnsaddr) { + char buf[20]="IP:"; + if (s==DHCP_STATUS_OK) { + resolv_conf(dnsaddr); + uip.get_ip_addr_str(buf+3); + Serial.println(buf); + uip.query_name("www.greenend.org.uk"); + // Start the "hello world" app defined earlier + uip_listen(HTONS(1000),hello_world_appcall); + } +} + +void setup() { + char buf[20]; + byte macaddr[6]; + NanodeUNIO unio(NANODE_MAC_DEVICE); + + Serial.begin(38400); + printf_begin(); + printf_P(PSTR(__FILE__"\r\n")); + + unio.read(macaddr,NANODE_MAC_ADDRESS,6); + uip.init(macaddr); + uip.get_mac_str(buf); + Serial.println(buf); + uip.wait_for_link(); + nanode_log_P(PSTR("Link is up")); + uip.init_resolv(resolv_found); + uip.start_dhcp(dhcp_status); + nanode_log_P(PSTR("setup() done")); +} + +void loop() { + uip.poll(); +} From 34ab4bd661ce2337eec042ddb824f88c95dbb9c0 Mon Sep 17 00:00:00 2001 From: maniacbug Date: Mon, 2 Jan 2012 07:23:12 -0800 Subject: [PATCH 02/15] Imported needed files from uIP. Compiles, doesn't run yet --- examples/telnet_server/memb.c | 104 ++++++++ examples/telnet_server/memb.h | 142 +++++++++++ examples/telnet_server/shell.cpp | 291 +++++++++++++++++++++++ examples/telnet_server/shell.h | 105 ++++++++ examples/telnet_server/telnet.cpp | 381 ++++++++++++++++++++++++++++++ examples/telnet_server/telnetd.h | 59 +++++ 6 files changed, 1082 insertions(+) create mode 100644 examples/telnet_server/memb.c create mode 100644 examples/telnet_server/memb.h create mode 100644 examples/telnet_server/shell.cpp create mode 100644 examples/telnet_server/shell.h create mode 100644 examples/telnet_server/telnet.cpp create mode 100644 examples/telnet_server/telnetd.h diff --git a/examples/telnet_server/memb.c b/examples/telnet_server/memb.c new file mode 100644 index 0000000..777b52f --- /dev/null +++ b/examples/telnet_server/memb.c @@ -0,0 +1,104 @@ +/* + * Copyright (c) 2004, Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * This file is part of the uIP TCP/IP stack + * + * Author: Adam Dunkels + * + * $Id: memb.c,v 1.1 2006/06/12 08:21:43 adam Exp $ + */ + +/** + * \addtogroup memb + * @{ + */ + + /** + * \file + * Memory block allocation routines. + * \author Adam Dunkels + */ +#include + +#include "memb.h" + +/*---------------------------------------------------------------------------*/ +void +memb_init(struct memb_blocks *m) +{ + memset(m->count, 0, m->num); + memset(m->mem, 0, m->size * m->num); +} +/*---------------------------------------------------------------------------*/ +void * +memb_alloc(struct memb_blocks *m) +{ + int i; + + for(i = 0; i < m->num; ++i) { + if(m->count[i] == 0) { + /* If this block was unused, we increase the reference count to + indicate that it now is used and return a pointer to the + memory block. */ + ++(m->count[i]); + return (void *)((char *)m->mem + (i * m->size)); + } + } + + /* No free block was found, so we return NULL to indicate failure to + allocate block. */ + return NULL; +} +/*---------------------------------------------------------------------------*/ +char +memb_free(struct memb_blocks *m, void *ptr) +{ + int i; + char *ptr2; + + /* Walk through the list of blocks and try to find the block to + which the pointer "ptr" points to. */ + ptr2 = (char *)m->mem; + for(i = 0; i < m->num; ++i) { + + if(ptr2 == (char *)ptr) { + /* We've found to block to which "ptr" points so we decrease the + reference count and return the new value of it. */ + if(m->count[i] > 0) { + /* Make sure that we don't deallocate free memory. */ + --(m->count[i]); + } + return m->count[i]; + } + ptr2 += m->size; + } + return -1; +} +/*---------------------------------------------------------------------------*/ + +/** @} */ diff --git a/examples/telnet_server/memb.h b/examples/telnet_server/memb.h new file mode 100644 index 0000000..b725ebe --- /dev/null +++ b/examples/telnet_server/memb.h @@ -0,0 +1,142 @@ +/* + * Copyright (c) 2004, Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * This file is part of the uIP TCP/IP stack + * + * Author: Adam Dunkels + * + * $Id: memb.h,v 1.1 2006/06/12 08:21:43 adam Exp $ + */ + +/** + * \defgroup memb Memory block management functions + * + * The memory block allocation routines provide a simple yet powerful + * set of functions for managing a set of memory blocks of fixed + * size. A set of memory blocks is statically declared with the + * MEMB() macro. Memory blocks are allocated from the declared + * memory by the memb_alloc() function, and are deallocated with the + * memb_free() function. + * + * \note Because of namespace clashes only one MEMB() can be + * declared per C module, and the name scope of a MEMB() memory + * block is local to each C module. + * + * The following example shows how to declare and use a memory block + * called "cmem" which has 8 chunks of memory with each memory chunk + * being 20 bytes large. + * + * @{ + */ + + +/** + * \file + * Memory block allocation routines. + * \author + * Adam Dunkels + * + */ + +#ifndef __MEMB_H__ +#define __MEMB_H__ + +/* + * Here we define a C preprocessing macro for concatenating to + * strings. We need use two macros in order to allow concatenation of + * two #defined macros. + */ +#define MEMB_CONCAT2(s1, s2) s1##s2 +#define MEMB_CONCAT(s1, s2) MEMB_CONCAT2(s1, s2) + +/** + * Declare a memory block. + * + * This macro is used to staticall declare a block of memory that can + * be used by the block allocation functions. The macro statically + * declares a C array with a size that matches the specified number of + * blocks and their individual sizes. + * + * Example: + \code +MEMB(connections, sizeof(struct connection), 16); + \endcode + * + * \param name The name of the memory block (later used with + * memb_init(), memb_alloc() and memb_free()). + * + * \param size The size of each memory chunk, in bytes. + * + * \param num The total number of memory chunks in the block. + * + */ +#define MEMB(name, structure, num) \ + static char MEMB_CONCAT(name,_memb_count)[num]; \ + static structure MEMB_CONCAT(name,_memb_mem)[num]; \ + static struct memb_blocks name = {sizeof(structure), num, \ + MEMB_CONCAT(name,_memb_count), \ + (void *)MEMB_CONCAT(name,_memb_mem)} + +struct memb_blocks { + unsigned short size; + unsigned short num; + char *count; + void *mem; +}; + +/** + * Initialize a memory block that was declared with MEMB(). + * + * \param m A memory block previosly declared with MEMB(). + */ +void memb_init(struct memb_blocks *m); + +/** + * Allocate a memory block from a block of memory declared with MEMB(). + * + * \param m A memory block previosly declared with MEMB(). + */ +void *memb_alloc(struct memb_blocks *m); + +/** + * Deallocate a memory block from a memory block previously declared + * with MEMB(). + * + * \param m m A memory block previosly declared with MEMB(). + * + * \param ptr A pointer to the memory block that is to be deallocated. + * + * \return The new reference count for the memory block (should be 0 + * if successfully deallocated) or -1 if the pointer "ptr" did not + * point to a legal memory block. + */ +char memb_free(struct memb_blocks *m, void *ptr); + +/** @} */ + +#endif /* __MEMB_H__ */ diff --git a/examples/telnet_server/shell.cpp b/examples/telnet_server/shell.cpp new file mode 100644 index 0000000..a3165ba --- /dev/null +++ b/examples/telnet_server/shell.cpp @@ -0,0 +1,291 @@ + /* + * Copyright (c) 2003, Adam Dunkels. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This file is part of the uIP TCP/IP stack. + * + * $Id: shell.c,v 1.1 2006/06/07 09:43:54 adam Exp $ + * + */ +#include +#include "Arduino.h" +#include "NanodeUIP.h" +#include "shell.h" + + +struct ptentry { + char *commandstr; + void (* pfunc)(char *str); +}; + +#ifndef SHELL_PROMPT +#define SHELL_PROMPT "NanodeUIP> " +#endif + +/*---------------------------------------------------------------------------*/ +static void +parse(register char *str, struct ptentry *t) +{ + struct ptentry *p; + for(p = t; p->commandstr != NULL; ++p) { + if(strncmp(p->commandstr, str, strlen(p->commandstr)) == 0) { + break; + } + } + + p->pfunc(str); +} +/*---------------------------------------------------------------------------*/ +#if 0 // inttostr not used anywhere +static void +inttostr(register char *str, unsigned int i) +{ + str[0] = '0' + i / 100; + if(str[0] == '0') { + str[0] = ' '; + } + str[1] = '0' + (i / 10) % 10; + if(str[0] == ' ' && str[1] == '0') { + str[1] = ' '; + } + str[2] = '0' + i % 10; + str[3] = ' '; + str[4] = 0; +} +#endif // inttostr not used anywhere + +#ifdef TELNETD_TIME_CMD +static void +settime(char *str) +{ + uint8_t timestore_write[8] = {0x00,0x38,0x10,0x10,0x11,0x04,0x10,0}; + send_time_to_rtc(timestore_write); + shell_output("time set", ""); +} +/*---------------------------------------------------------------------------*/ +static void +isotime(char *str) +{ + uint8_t timestore_read[7]; + uint8_t iso_timestore[16]; + + read_time(timestore_read); + iso_time(timestore_read, iso_timestore); +/* iso_timestore[0] = 'a' + timestore_read[0]; + iso_timestore[1] = 'a' + timestore_read[1]; + iso_timestore[2] = 'a' + timestore_read[2]; + iso_timestore[3] = 'a' + timestore_read[3]; + iso_timestore[4] = '\0'; +*/ + shell_output(iso_timestore, ""); +} +#endif + +extern char* __brkval; +extern char __heap_start; +extern int errno; + +/*---------------------------------------------------------------------------*/ +static void +show_memory(char *str) +{ + char buf[25]; + sprintf_P(buf,PSTR("SP = 0x%x"),SP); + shell_output(buf,""); + sprintf_P(buf,PSTR("__brkval = %p"),__brkval?__brkval:&__heap_start); + shell_output(buf,""); + sprintf_P(buf,PSTR("Free memory = %u bytes"),SP-(__brkval?(uint16_t)__brkval:(uint16_t)&__heap_start)); + shell_output(buf,""); +} + +/*---------------------------------------------------------------------------*/ +#ifdef NETWORK_CMD +#define DSTR_BUF 25 +static void +shell_network(char *str) +{ + char *pos = str + sizeof("network"); + uint8_t is_error = 0; + char dstr[DSTR_BUF]; + + + if (strncmp_P(pos, PSTR("set "), 4) == 0) + { + pos += 4; + if (strncmp_P(pos, PSTR("ip "), 3) == 0) + { + pos += 3; + is_error = net_conf_set_ip_string(pos); + } + else if (strncmp_P(pos, PSTR("gw "), 3) == 0) + { + pos += 3; + is_error = net_conf_set_gw_string(pos); + } + else if (strncmp_P(pos, PSTR("nm "), 3) == 0) + { + pos += 3; + is_error = net_conf_set_nm_string(pos); + } + else if (strncmp_P(pos, PSTR("dhcp "), 5) == 0) + { + pos += 5; + is_error = net_conf_set_dhcpc_string(pos); + } + else + { + shell_output("unknown set operation: ", pos); + } + } + else if (strncmp_P(pos, PSTR("show"), 4) == 0) + { + pos += 5; + net_conf_get_mac_string(dstr, DSTR_BUF); + shell_output("MAC: ", dstr); + net_conf_get_ip_string(dstr, DSTR_BUF); + shell_output("IP: ", dstr); + net_conf_get_nm_string(dstr, DSTR_BUF); + shell_output("NM: ", dstr); + net_conf_get_gw_string(dstr, DSTR_BUF); + shell_output("GW: ", dstr); + } + else if (strncmp_P(pos, PSTR("load"), 4) == 0) + { + net_conf_load(); + } + else if (strncmp_P(pos, PSTR("save"), 4) == 0) + { + net_conf_save(); + } + else + { + shell_output_P(PSTR("options: show, set, load, save"),PSTR("")); + } +} +#endif + + +#ifdef UDPDS_CMD +static void +shell_udpds(char *str) +{ + char *pos = str + sizeof("udpds"); + + if (strncmp_P(pos, PSTR("set "), 4) == 0) + { + } + else if (strncmp_P(pos, PSTR("show"), 4) == 0) + { + } + else if (strncmp_P(pos, PSTR("enable"), 6) == 0) + { + + } + else if (strncmp_P(pos, PSTR("disable"), 7) == 0) + { + } +} +#endif + +/*---------------------------------------------------------------------------*/ +static void +help(char *str) +{ + // TEXT HERE CAN ONLY BE 40 chars / output! based on telnetd.h + shell_output_P(PSTR("Available commands:"), PSTR("")); +#ifdef TELNETD_TIME_CMD + shell_output_P(PSTR("isotime - sys time, iso format"), PSTR("")); + shell_output_P(PSTR("settime - set sys time"), PSTR("")); + shell_output_P(PSTR("gettime - get sys time"), PSTR("")); + shell_output_P(PSTR("rtcisotime - show RTC time, iso format"), PSTR("")); + shell_output_P(PSTR("rtcsettime - set the current RTC time"), PSTR("")); + shell_output_P(PSTR("rtcgettime - get the current RTC time"), PSTR("")); + shell_output_P(PSTR("rtctosys - copy RTC time to sys"), PSTR("")); + shell_output_P(PSTR("systortc - copy sys time to RTC"), PSTR("")); +#endif +#ifdef NETWORK_CMD + shell_output_P(PSTR("network - get/set network settings"), PSTR("")); +#endif +#ifdef UDPDS_CMD + shell_output_P(PSTR("udpds - set/enable/disable"),PSTR("")); +#endif +// shell_output("stats - show network statistics", ""); +// shell_output("conn - show TCP connections", ""); + shell_output_P(PSTR("help, ? - show help"), PSTR("")); + shell_output_P(PSTR("exit - exit shell"), PSTR("")); + shell_output_P(PSTR("mem - show memory"), PSTR("")); +} +/*---------------------------------------------------------------------------*/ +static void +unknown(char *str) +{ + if(strlen(str) > 0) { + shell_output("Unknown command: ", str); + *str = 0; + } +} +/*---------------------------------------------------------------------------*/ +static struct ptentry parsetab[] = + {{"stats", help}, + {"conn", help}, + {"help", help}, + {"exit", shell_quit}, + {"?", help}, + {"mem", show_memory}, +#ifdef TELNETD_TIME_CMD + {"time", isotime}, + {"settime", settime}, +#endif +#ifdef NETWORK_CMD + {"network", shell_network}, +#endif +#ifdef UDPDS_CMD + {"udpds", shell_udpds}, +#endif + /* Default action */ + {NULL, unknown}}; +/*---------------------------------------------------------------------------*/ +void +shell_init(void) +{ +} +/*---------------------------------------------------------------------------*/ +void +shell_start(void) +{ + shell_output_P(PSTR("uIP command shell"), PSTR("")); + shell_output_P(PSTR("Type '?' and return for help"), PSTR("")); + shell_prompt(SHELL_PROMPT); +} +/*---------------------------------------------------------------------------*/ +void +shell_input(char *cmd) +{ + parse(cmd, parsetab); + shell_prompt(SHELL_PROMPT); +} +/*---------------------------------------------------------------------------*/ diff --git a/examples/telnet_server/shell.h b/examples/telnet_server/shell.h new file mode 100644 index 0000000..40a0318 --- /dev/null +++ b/examples/telnet_server/shell.h @@ -0,0 +1,105 @@ +/** + * \file + * Interface for the Contiki shell. + * \author Adam Dunkels + * + * Some of the functions declared in this file must be implemented as + * a shell back-end in the architecture specific files of a Contiki + * port. + */ + + +/* + * Copyright (c) 2003, Adam Dunkels. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This file is part of the Contiki desktop OS. + * + * $Id: shell.h,v 1.1 2006/06/07 09:43:54 adam Exp $ + * + */ +#ifndef __SHELL_H__ +#define __SHELL_H__ + +/** + * Initialize the shell. + * + * Called when the shell front-end process starts. This function may + * be used to start listening for signals. + */ +void shell_init(void); + +/** + * Start the shell back-end. + * + * Called by the front-end when a new shell is started. + */ +void shell_start(void); + +/** + * Process a shell command. + * + * This function will be called by the shell GUI / telnet server whan + * a command has been entered that should be processed by the shell + * back-end. + * + * \param command The command to be processed. + */ +void shell_input(char *command); + +/** + * Quit the shell. + * + */ +void shell_quit(char *); + + +/** + * Print a string to the shell window. + * + * This function is implemented by the shell GUI / telnet server and + * can be called by the shell back-end to output a string in the + * shell window. The string is automatically appended with a linebreak. + * + * \param str1 The first half of the string to be output. + * \param str2 The second half of the string to be output. + */ +void shell_output(char *str1, char *str2); +void shell_output_P(PGM_P str1, PGM_P str2); + +/** + * Print a prompt to the shell window. + * + * This function can be used by the shell back-end to print out a + * prompt to the shell window. + * + * \param prompt The prompt to be printed. + * + */ +void shell_prompt(char *prompt); + +#endif /* __SHELL_H__ */ diff --git a/examples/telnet_server/telnet.cpp b/examples/telnet_server/telnet.cpp new file mode 100644 index 0000000..d851f33 --- /dev/null +++ b/examples/telnet_server/telnet.cpp @@ -0,0 +1,381 @@ +/* + * Copyright (c) 2003, Adam Dunkels. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This file is part of the uIP TCP/IP stack + * + * $Id: telnetd.c,v 1.2 2006/06/07 09:43:54 adam Exp $ + * + */ + +#include "NanodeUIP.h" +#include "Arduino.h" +#include "telnetd.h" +#include "shell.h" +extern "C" +{ +#include "memb.h" +} + +#include + +#define ISO_nl 0x0a +#define ISO_cr 0x0d + +struct telnetd_line { + char line[TELNETD_CONF_LINELEN]; +}; +MEMB(linemem, struct telnetd_line, TELNETD_CONF_NUMLINES); + +#define STATE_NORMAL 0 +#define STATE_IAC 1 +#define STATE_WILL 2 +#define STATE_WONT 3 +#define STATE_DO 4 +#define STATE_DONT 5 +#define STATE_CLOSE 6 + +static struct telnetd_state s; + +#define TELNET_IAC 255 +#define TELNET_WILL 251 +#define TELNET_WONT 252 +#define TELNET_DO 253 +#define TELNET_DONT 254 +/*---------------------------------------------------------------------------*/ +static char * +alloc_line(void) +{ + return reinterpret_cast(memb_alloc(&linemem)); +} +/*---------------------------------------------------------------------------*/ +static void +dealloc_line(char *line) +{ + memb_free(&linemem, line); +} +/*---------------------------------------------------------------------------*/ +void +shell_quit(char *) +{ + s.state = STATE_CLOSE; +} +/*---------------------------------------------------------------------------*/ +static void +sendline(char *line) +{ + static unsigned int i; + + for(i = 0; i < TELNETD_CONF_NUMLINES; ++i) { + if(s.lines[i] == NULL) { + s.lines[i] = line; + break; + } + } + if(i == TELNETD_CONF_NUMLINES) { + dealloc_line(line); + } +} +/*---------------------------------------------------------------------------*/ +void +shell_prompt(char *str) +{ + char *line; + line = alloc_line(); + if(line != NULL) { + strncpy(line, str, TELNETD_CONF_LINELEN); + /* petsciiconv_toascii(line, TELNETD_CONF_LINELEN);*/ + sendline(line); + } +} +/*---------------------------------------------------------------------------*/ +void +shell_output(char *str1, char *str2) +{ + static unsigned len; + char *line; + + line = alloc_line(); + if(line != NULL) { + len = strlen(str1); + strncpy(line, str1, TELNETD_CONF_LINELEN); + if(len < TELNETD_CONF_LINELEN) { + strncpy(line + len, str2, TELNETD_CONF_LINELEN - len); + } + len = strlen(line); + if(len < TELNETD_CONF_LINELEN - 2) { + line[len] = ISO_cr; + line[len+1] = ISO_nl; + line[len+2] = 0; + } + /* petsciiconv_toascii(line, TELNETD_CONF_LINELEN);*/ + sendline(line); + } +} +/*---------------------------------------------------------------------------*/ +void +shell_output_P(PGM_P str1, PGM_P str2) +{ + static unsigned len; + char *line; + + line = alloc_line(); + if(line != NULL) { + len = strlen_P(str1); + strncpy_P(line, str1, TELNETD_CONF_LINELEN); + if(len < TELNETD_CONF_LINELEN) { + strncpy_P(line + len, str2, TELNETD_CONF_LINELEN - len); + } + len = strlen(line); + if(len < TELNETD_CONF_LINELEN - 2) { + line[len] = ISO_cr; + line[len+1] = ISO_nl; + line[len+2] = 0; + } + /* petsciiconv_toascii(line, TELNETD_CONF_LINELEN);*/ + sendline(line); + } +} +/*---------------------------------------------------------------------------*/ +void +telnetd_init(void) +{ + uip_listen(HTONS(23),telnetd_appcall); + memb_init(&linemem); + shell_init(); +} +/*---------------------------------------------------------------------------*/ +static void +acked(void) +{ + static unsigned int i; + + while(s.numsent > 0) { + dealloc_line(s.lines[0]); + for(i = 1; i < TELNETD_CONF_NUMLINES; ++i) { + s.lines[i - 1] = s.lines[i]; + } + s.lines[TELNETD_CONF_NUMLINES - 1] = NULL; + --s.numsent; + } +} +/*---------------------------------------------------------------------------*/ +static void +senddata(void) +{ + static char *bufptr, *lineptr; + static int buflen, linelen; + + bufptr = reinterpret_cast(uip_appdata); + buflen = 0; + for(s.numsent = 0; s.numsent < TELNETD_CONF_NUMLINES && + s.lines[s.numsent] != NULL ; ++s.numsent) { + lineptr = s.lines[s.numsent]; + linelen = strlen(lineptr); + if(linelen > TELNETD_CONF_LINELEN) { + linelen = TELNETD_CONF_LINELEN; + } + if(buflen + linelen < uip_mss()) { + memcpy(bufptr, lineptr, linelen); + bufptr += linelen; + buflen += linelen; + } else { + break; + } + } + uip_send(uip_appdata, buflen); +} +/*---------------------------------------------------------------------------*/ +static void +closed(void) +{ + static unsigned int i; + + for(i = 0; i < TELNETD_CONF_NUMLINES; ++i) { + if(s.lines[i] != NULL) { + dealloc_line(s.lines[i]); + } + } +} +/*---------------------------------------------------------------------------*/ +static void +get_char(u8_t c) +{ + if(c == ISO_cr) { + return; + } + + s.buf[(int)s.bufptr] = c; + if(s.buf[(int)s.bufptr] == ISO_nl || + s.bufptr == sizeof(s.buf) - 1) { + if(s.bufptr > 0) { + s.buf[(int)s.bufptr] = 0; + /* petsciiconv_topetscii(s.buf, TELNETD_CONF_LINELEN);*/ + } + if((s.bufptr + 1) < sizeof(s.buf)) { + s.buf[(int)s.bufptr +1] = 0; + } + shell_input(s.buf); + s.bufptr = 0; + } else { + ++s.bufptr; + } +} +/*---------------------------------------------------------------------------*/ +static void +sendopt(u8_t option, u8_t value) +{ + char *line; + line = alloc_line(); + if(line != NULL) { + line[0] = TELNET_IAC; + line[1] = option; + line[2] = value; + line[3] = 0; + sendline(line); + } +} +/*---------------------------------------------------------------------------*/ +static void +newdata(void) +{ + u16_t len; + u8_t c; + char *dataptr; + + + len = uip_datalen(); + dataptr = (char *)uip_appdata; + + while(len > 0 && s.bufptr < sizeof(s.buf)) { + c = *dataptr; + ++dataptr; + --len; + switch(s.state) { + case STATE_IAC: + if(c == TELNET_IAC) { + get_char(c); + s.state = STATE_NORMAL; + } else { + switch(c) { + case TELNET_WILL: + s.state = STATE_WILL; + break; + case TELNET_WONT: + s.state = STATE_WONT; + break; + case TELNET_DO: + s.state = STATE_DO; + break; + case TELNET_DONT: + s.state = STATE_DONT; + break; + default: + s.state = STATE_NORMAL; + break; + } + } + break; + case STATE_WILL: + /* Reply with a DONT */ + sendopt(TELNET_DONT, c); + s.state = STATE_NORMAL; + break; + + case STATE_WONT: + /* Reply with a DONT */ + sendopt(TELNET_DONT, c); + s.state = STATE_NORMAL; + break; + case STATE_DO: + /* Reply with a WONT */ + sendopt(TELNET_WONT, c); + s.state = STATE_NORMAL; + break; + case STATE_DONT: + /* Reply with a WONT */ + sendopt(TELNET_WONT, c); + s.state = STATE_NORMAL; + break; + case STATE_NORMAL: + if(c == TELNET_IAC) { + s.state = STATE_IAC; + } else { + get_char(c); + } + break; + } + + + } + +} +/*---------------------------------------------------------------------------*/ +void +telnetd_appcall(void) +{ + static unsigned int i; + if(uip_connected()) { + /* tcp_markconn(uip_conn, &s);*/ + for(i = 0; i < TELNETD_CONF_NUMLINES; ++i) { + s.lines[i] = NULL; + } + s.bufptr = 0; + s.state = STATE_NORMAL; + + shell_start(); + } + + if(s.state == STATE_CLOSE) { + s.state = STATE_NORMAL; + uip_close(); + return; + } + + if(uip_closed() || + uip_aborted() || + uip_timedout()) { + closed(); + } + + if(uip_acked()) { + acked(); + } + + if(uip_newdata()) { + newdata(); + } + + if(uip_rexmit() || + uip_newdata() || + uip_acked() || + uip_connected() || + uip_poll()) { + senddata(); + } +} +/*---------------------------------------------------------------------------*/ diff --git a/examples/telnet_server/telnetd.h b/examples/telnet_server/telnetd.h new file mode 100644 index 0000000..e083705 --- /dev/null +++ b/examples/telnet_server/telnetd.h @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2003, Adam Dunkels. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * 3. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This file is part of the uIP TCP/IP stack + * + * $Id: telnetd.h,v 1.2 2006/06/07 09:43:54 adam Exp $ + * + */ +#ifndef __TELNETD_H__ +#define __TELNETD_H__ + +#include "uipopt.h" + +void telnetd_appcall(void); +void telnetd_init(void); + +#ifndef TELNETD_CONF_LINELEN +#define TELNETD_CONF_LINELEN 40 +#endif +#ifndef TELNETD_CONF_NUMLINES +// orig value #define TELNETD_CONF_NUMLINES 16 +#define TELNETD_CONF_NUMLINES 8 +#endif + +struct telnetd_state { + char *lines[TELNETD_CONF_NUMLINES]; + char buf[TELNETD_CONF_LINELEN]; + u8_t bufptr; + u8_t numsent; + u8_t state; +}; + +#endif /* __TELNETD_H__ */ From ede15a4c9c530d84d316c266ca2fbf1424b50d7f Mon Sep 17 00:00:00 2001 From: maniacbug Date: Mon, 2 Jan 2012 07:37:01 -0800 Subject: [PATCH 03/15] Sketch is really now telnet server, not hello world server --- examples/telnet_server/telnet_server.pde | 77 ++---------------------- 1 file changed, 6 insertions(+), 71 deletions(-) diff --git a/examples/telnet_server/telnet_server.pde b/examples/telnet_server/telnet_server.pde index dcb1f50..565442d 100644 --- a/examples/telnet_server/telnet_server.pde +++ b/examples/telnet_server/telnet_server.pde @@ -1,82 +1,17 @@ #include #include #include +#include "telnetd.h" #include "printf.h" -struct hello_world_state { - struct psock p; - byte inputbuffer[20]; - char name[20]; - char quest[20]; -}; -UIPASSERT(sizeof(struct hello_world_state)<=TCP_APP_STATE_SIZE) - -/* This function defines what the "hello world" application does - once a connection has been established. It doesn't have to - deal with setting up the connection. */ -static int hello_world_connection(struct hello_world_state *s) -{ - PSOCK_BEGIN(&s->p); - - PSOCK_SEND_STR(&s->p, "Hello. What is your name?\n>>> "); - PSOCK_READTO(&s->p, '\n'); - /* The input buffer is an array of bytes received from the - network. It's not a string. We cheekily cast it to a string - here on the assumption that we're receiving plain ASCII and - not UTF8 or anything more fancy... */ - s->inputbuffer[PSOCK_DATALEN(&s->p)]=0; - strncpy(s->name, (const char *)s->inputbuffer, sizeof(s->name)); - PSOCK_SEND_STR(&s->p, "What is your quest?\n>>> "); - PSOCK_READTO(&s->p, '\n'); - s->inputbuffer[PSOCK_DATALEN(&s->p)]=0; - strncpy(s->quest, (const char *)s->inputbuffer, sizeof(s->quest)); - PSOCK_SEND_STR(&s->p, "Hello "); - PSOCK_SEND_STR(&s->p, s->name); - PSOCK_SEND_STR(&s->p, "Your quest is: "); - PSOCK_SEND_STR(&s->p, s->quest); - PSOCK_CLOSE(&s->p); - - PSOCK_END(&s->p); -} - -/* This function deals with all incoming events for the "hello - world" application, including dealing with new connections. */ -static void hello_world_appcall(void) -{ - struct hello_world_state *s = (struct hello_world_state *)&(uip_conn->appstate); - - /* - * If a new connection was just established, we should initialize - * the protosocket in our application's state structure. - */ - if(uip_connected()) { - PSOCK_INIT(&s->p, s->inputbuffer, sizeof(s->inputbuffer)-1); - } - - /* - * We run the protosocket function that actually handles the - * communication. We pass it a pointer to the application state - * of the current connection. - */ - hello_world_connection(s); -} - -static void resolv_found(char *name,uint16_t *addr) { - char buf[30]=": addr="; - Serial.print(name); - uip.format_ipaddr(buf+7,addr); - Serial.println(buf); -} - -void dhcp_status(int s,const uint16_t *dnsaddr) { +void dhcp_status(int s,const uint16_t *) { char buf[20]="IP:"; if (s==DHCP_STATUS_OK) { - resolv_conf(dnsaddr); uip.get_ip_addr_str(buf+3); Serial.println(buf); - uip.query_name("www.greenend.org.uk"); - // Start the "hello world" app defined earlier - uip_listen(HTONS(1000),hello_world_appcall); + + nanode_log_P(PSTR("Bringing up telnet server...")); + telnetd_init(); } } @@ -95,7 +30,6 @@ void setup() { Serial.println(buf); uip.wait_for_link(); nanode_log_P(PSTR("Link is up")); - uip.init_resolv(resolv_found); uip.start_dhcp(dhcp_status); nanode_log_P(PSTR("setup() done")); } @@ -103,3 +37,4 @@ void setup() { void loop() { uip.poll(); } +// vim:cin:ai:sts=2 sw=2 ft=cpp From 5ef605df4dec0b81c3c607c5c1e1d9dadd68a999 Mon Sep 17 00:00:00 2001 From: maniacbug Date: Mon, 2 Jan 2012 07:37:18 -0800 Subject: [PATCH 04/15] vim modelines --- examples/telnet_server/shell.cpp | 1 + examples/telnet_server/shell.h | 1 + examples/telnet_server/telnet.cpp | 2 ++ examples/telnet_server/telnetd.h | 1 + 4 files changed, 5 insertions(+) diff --git a/examples/telnet_server/shell.cpp b/examples/telnet_server/shell.cpp index a3165ba..ef67418 100644 --- a/examples/telnet_server/shell.cpp +++ b/examples/telnet_server/shell.cpp @@ -289,3 +289,4 @@ shell_input(char *cmd) shell_prompt(SHELL_PROMPT); } /*---------------------------------------------------------------------------*/ +// vim:cin:ai:sts=2 sw=2 ft=cpp diff --git a/examples/telnet_server/shell.h b/examples/telnet_server/shell.h index 40a0318..a2af470 100644 --- a/examples/telnet_server/shell.h +++ b/examples/telnet_server/shell.h @@ -103,3 +103,4 @@ void shell_output_P(PGM_P str1, PGM_P str2); void shell_prompt(char *prompt); #endif /* __SHELL_H__ */ +// vim:cin:ai:sts=2 sw=2 ft=cpp diff --git a/examples/telnet_server/telnet.cpp b/examples/telnet_server/telnet.cpp index d851f33..a7be640 100644 --- a/examples/telnet_server/telnet.cpp +++ b/examples/telnet_server/telnet.cpp @@ -59,6 +59,7 @@ MEMB(linemem, struct telnetd_line, TELNETD_CONF_NUMLINES); #define STATE_DONT 5 #define STATE_CLOSE 6 +// Static state is wasting space. Should use the connection state. static struct telnetd_state s; #define TELNET_IAC 255 @@ -379,3 +380,4 @@ telnetd_appcall(void) } } /*---------------------------------------------------------------------------*/ +// vim:cin:ai:sts=2 sw=2 ft=cpp diff --git a/examples/telnet_server/telnetd.h b/examples/telnet_server/telnetd.h index e083705..5f055ca 100644 --- a/examples/telnet_server/telnetd.h +++ b/examples/telnet_server/telnetd.h @@ -57,3 +57,4 @@ struct telnetd_state { }; #endif /* __TELNETD_H__ */ +// vim:cin:ai:sts=2 sw=2 ft=cpp From dc1938832979323e98f044c103659d382f44e578 Mon Sep 17 00:00:00 2001 From: maniacbug Date: Mon, 2 Jan 2012 07:52:31 -0800 Subject: [PATCH 05/15] Cleanups --- examples/telnet_server/shell.cpp | 187 ++---------------------------- examples/telnet_server/shell.h | 2 +- examples/telnet_server/telnet.cpp | 6 +- 3 files changed, 16 insertions(+), 179 deletions(-) diff --git a/examples/telnet_server/shell.cpp b/examples/telnet_server/shell.cpp index ef67418..3ab847a 100644 --- a/examples/telnet_server/shell.cpp +++ b/examples/telnet_server/shell.cpp @@ -38,7 +38,7 @@ struct ptentry { - char *commandstr; + const char *commandstr; void (* pfunc)(char *str); }; @@ -59,51 +59,6 @@ parse(register char *str, struct ptentry *t) p->pfunc(str); } -/*---------------------------------------------------------------------------*/ -#if 0 // inttostr not used anywhere -static void -inttostr(register char *str, unsigned int i) -{ - str[0] = '0' + i / 100; - if(str[0] == '0') { - str[0] = ' '; - } - str[1] = '0' + (i / 10) % 10; - if(str[0] == ' ' && str[1] == '0') { - str[1] = ' '; - } - str[2] = '0' + i % 10; - str[3] = ' '; - str[4] = 0; -} -#endif // inttostr not used anywhere - -#ifdef TELNETD_TIME_CMD -static void -settime(char *str) -{ - uint8_t timestore_write[8] = {0x00,0x38,0x10,0x10,0x11,0x04,0x10,0}; - send_time_to_rtc(timestore_write); - shell_output("time set", ""); -} -/*---------------------------------------------------------------------------*/ -static void -isotime(char *str) -{ - uint8_t timestore_read[7]; - uint8_t iso_timestore[16]; - - read_time(timestore_read); - iso_time(timestore_read, iso_timestore); -/* iso_timestore[0] = 'a' + timestore_read[0]; - iso_timestore[1] = 'a' + timestore_read[1]; - iso_timestore[2] = 'a' + timestore_read[2]; - iso_timestore[3] = 'a' + timestore_read[3]; - iso_timestore[4] = '\0'; -*/ - shell_output(iso_timestore, ""); -} -#endif extern char* __brkval; extern char __heap_start; @@ -113,131 +68,24 @@ extern int errno; static void show_memory(char *str) { - char buf[25]; - sprintf_P(buf,PSTR("SP = 0x%x"),SP); - shell_output(buf,""); - sprintf_P(buf,PSTR("__brkval = %p"),__brkval?__brkval:&__heap_start); - shell_output(buf,""); - sprintf_P(buf,PSTR("Free memory = %u bytes"),SP-(__brkval?(uint16_t)__brkval:(uint16_t)&__heap_start)); - shell_output(buf,""); + char buf[25]; + sprintf_P(buf,PSTR("SP = 0x%x"),SP); + shell_output(buf,NULL); + sprintf_P(buf,PSTR("__brkval = %p"),__brkval?__brkval:&__heap_start); + shell_output(buf,NULL); + sprintf_P(buf,PSTR("Free memory = %u bytes"),SP-(__brkval?(uint16_t)__brkval:(uint16_t)&__heap_start)); + shell_output(buf,NULL); } -/*---------------------------------------------------------------------------*/ -#ifdef NETWORK_CMD -#define DSTR_BUF 25 -static void -shell_network(char *str) -{ - char *pos = str + sizeof("network"); - uint8_t is_error = 0; - char dstr[DSTR_BUF]; - - - if (strncmp_P(pos, PSTR("set "), 4) == 0) - { - pos += 4; - if (strncmp_P(pos, PSTR("ip "), 3) == 0) - { - pos += 3; - is_error = net_conf_set_ip_string(pos); - } - else if (strncmp_P(pos, PSTR("gw "), 3) == 0) - { - pos += 3; - is_error = net_conf_set_gw_string(pos); - } - else if (strncmp_P(pos, PSTR("nm "), 3) == 0) - { - pos += 3; - is_error = net_conf_set_nm_string(pos); - } - else if (strncmp_P(pos, PSTR("dhcp "), 5) == 0) - { - pos += 5; - is_error = net_conf_set_dhcpc_string(pos); - } - else - { - shell_output("unknown set operation: ", pos); - } - } - else if (strncmp_P(pos, PSTR("show"), 4) == 0) - { - pos += 5; - net_conf_get_mac_string(dstr, DSTR_BUF); - shell_output("MAC: ", dstr); - net_conf_get_ip_string(dstr, DSTR_BUF); - shell_output("IP: ", dstr); - net_conf_get_nm_string(dstr, DSTR_BUF); - shell_output("NM: ", dstr); - net_conf_get_gw_string(dstr, DSTR_BUF); - shell_output("GW: ", dstr); - } - else if (strncmp_P(pos, PSTR("load"), 4) == 0) - { - net_conf_load(); - } - else if (strncmp_P(pos, PSTR("save"), 4) == 0) - { - net_conf_save(); - } - else - { - shell_output_P(PSTR("options: show, set, load, save"),PSTR("")); - } -} -#endif - - -#ifdef UDPDS_CMD -static void -shell_udpds(char *str) -{ - char *pos = str + sizeof("udpds"); - - if (strncmp_P(pos, PSTR("set "), 4) == 0) - { - } - else if (strncmp_P(pos, PSTR("show"), 4) == 0) - { - } - else if (strncmp_P(pos, PSTR("enable"), 6) == 0) - { - - } - else if (strncmp_P(pos, PSTR("disable"), 7) == 0) - { - } -} -#endif - /*---------------------------------------------------------------------------*/ static void help(char *str) { // TEXT HERE CAN ONLY BE 40 chars / output! based on telnetd.h - shell_output_P(PSTR("Available commands:"), PSTR("")); -#ifdef TELNETD_TIME_CMD - shell_output_P(PSTR("isotime - sys time, iso format"), PSTR("")); - shell_output_P(PSTR("settime - set sys time"), PSTR("")); - shell_output_P(PSTR("gettime - get sys time"), PSTR("")); - shell_output_P(PSTR("rtcisotime - show RTC time, iso format"), PSTR("")); - shell_output_P(PSTR("rtcsettime - set the current RTC time"), PSTR("")); - shell_output_P(PSTR("rtcgettime - get the current RTC time"), PSTR("")); - shell_output_P(PSTR("rtctosys - copy RTC time to sys"), PSTR("")); - shell_output_P(PSTR("systortc - copy sys time to RTC"), PSTR("")); -#endif -#ifdef NETWORK_CMD - shell_output_P(PSTR("network - get/set network settings"), PSTR("")); -#endif -#ifdef UDPDS_CMD - shell_output_P(PSTR("udpds - set/enable/disable"),PSTR("")); -#endif -// shell_output("stats - show network statistics", ""); -// shell_output("conn - show TCP connections", ""); - shell_output_P(PSTR("help, ? - show help"), PSTR("")); - shell_output_P(PSTR("exit - exit shell"), PSTR("")); - shell_output_P(PSTR("mem - show memory"), PSTR("")); + shell_output_P(PSTR("Available commands:"), NULL); + shell_output_P(PSTR("help, ? - show help"), NULL); + shell_output_P(PSTR("exit - exit shell"), NULL); + shell_output_P(PSTR("mem - show memory"), NULL); } /*---------------------------------------------------------------------------*/ static void @@ -256,17 +104,6 @@ static struct ptentry parsetab[] = {"exit", shell_quit}, {"?", help}, {"mem", show_memory}, -#ifdef TELNETD_TIME_CMD - {"time", isotime}, - {"settime", settime}, -#endif -#ifdef NETWORK_CMD - {"network", shell_network}, -#endif -#ifdef UDPDS_CMD - {"udpds", shell_udpds}, -#endif - /* Default action */ {NULL, unknown}}; /*---------------------------------------------------------------------------*/ void diff --git a/examples/telnet_server/shell.h b/examples/telnet_server/shell.h index a2af470..3d4c18e 100644 --- a/examples/telnet_server/shell.h +++ b/examples/telnet_server/shell.h @@ -88,7 +88,7 @@ void shell_quit(char *); * \param str1 The first half of the string to be output. * \param str2 The second half of the string to be output. */ -void shell_output(char *str1, char *str2); +void shell_output(const char *str1, const char *str2); void shell_output_P(PGM_P str1, PGM_P str2); /** diff --git a/examples/telnet_server/telnet.cpp b/examples/telnet_server/telnet.cpp index a7be640..5aa85c3 100644 --- a/examples/telnet_server/telnet.cpp +++ b/examples/telnet_server/telnet.cpp @@ -115,7 +115,7 @@ shell_prompt(char *str) } /*---------------------------------------------------------------------------*/ void -shell_output(char *str1, char *str2) +shell_output(const char *str1, const char *str2) { static unsigned len; char *line; @@ -124,7 +124,7 @@ shell_output(char *str1, char *str2) if(line != NULL) { len = strlen(str1); strncpy(line, str1, TELNETD_CONF_LINELEN); - if(len < TELNETD_CONF_LINELEN) { + if(str2 && len < TELNETD_CONF_LINELEN) { strncpy(line + len, str2, TELNETD_CONF_LINELEN - len); } len = strlen(line); @@ -148,7 +148,7 @@ shell_output_P(PGM_P str1, PGM_P str2) if(line != NULL) { len = strlen_P(str1); strncpy_P(line, str1, TELNETD_CONF_LINELEN); - if(len < TELNETD_CONF_LINELEN) { + if(str2 && len < TELNETD_CONF_LINELEN) { strncpy_P(line + len, str2, TELNETD_CONF_LINELEN - len); } len = strlen(line); From 775a2c10ca69d5c93714a538d88ce94519cd7742 Mon Sep 17 00:00:00 2001 From: maniacbug Date: Mon, 2 Jan 2012 15:29:48 -0800 Subject: [PATCH 06/15] Move shell command strings into progmem --- examples/telnet_server/shell.cpp | 44 ++++++++++++++++++------------- examples/telnet_server/shell.h | 2 +- examples/telnet_server/telnet.cpp | 2 +- 3 files changed, 27 insertions(+), 21 deletions(-) diff --git a/examples/telnet_server/shell.cpp b/examples/telnet_server/shell.cpp index 3ab847a..5d8af73 100644 --- a/examples/telnet_server/shell.cpp +++ b/examples/telnet_server/shell.cpp @@ -36,10 +36,9 @@ #include "NanodeUIP.h" #include "shell.h" - struct ptentry { - const char *commandstr; - void (* pfunc)(char *str); + PGM_P commandstr; + void (* pfunc)(const char *str); }; #ifndef SHELL_PROMPT @@ -47,12 +46,12 @@ struct ptentry { #endif /*---------------------------------------------------------------------------*/ -static void -parse(register char *str, struct ptentry *t) +void +parse(const register char *str, struct ptentry *t) { struct ptentry *p; for(p = t; p->commandstr != NULL; ++p) { - if(strncmp(p->commandstr, str, strlen(p->commandstr)) == 0) { + if(strncmp_P(str, p->commandstr, strlen_P(p->commandstr)) == 0) { break; } } @@ -66,7 +65,7 @@ extern int errno; /*---------------------------------------------------------------------------*/ static void -show_memory(char *str) +show_memory(const char *str) { char buf[25]; sprintf_P(buf,PSTR("SP = 0x%x"),SP); @@ -79,7 +78,7 @@ show_memory(char *str) /*---------------------------------------------------------------------------*/ static void -help(char *str) +help(const char *) { // TEXT HERE CAN ONLY BE 40 chars / output! based on telnetd.h shell_output_P(PSTR("Available commands:"), NULL); @@ -89,22 +88,29 @@ help(char *str) } /*---------------------------------------------------------------------------*/ static void -unknown(char *str) +unknown_command(const char *str) { if(strlen(str) > 0) { shell_output("Unknown command: ", str); - *str = 0; } } /*---------------------------------------------------------------------------*/ + +const char stats_str_p[] PROGMEM = "stats"; +const char conn_str_p[] PROGMEM = "conn"; +const char help_str_p[] PROGMEM = "help"; +const char exit_str_p[] PROGMEM = "exit"; +const char q_str_p[] PROGMEM = "?"; +const char mem_str_p[] PROGMEM = "mem"; + static struct ptentry parsetab[] = - {{"stats", help}, - {"conn", help}, - {"help", help}, - {"exit", shell_quit}, - {"?", help}, - {"mem", show_memory}, - {NULL, unknown}}; + {{stats_str_p, help}, + {conn_str_p, help}, + {help_str_p, help}, + {exit_str_p, shell_quit}, + {q_str_p, help}, + {mem_str_p, show_memory}, + {NULL, unknown_command}}; /*---------------------------------------------------------------------------*/ void shell_init(void) @@ -114,8 +120,8 @@ shell_init(void) void shell_start(void) { - shell_output_P(PSTR("uIP command shell"), PSTR("")); - shell_output_P(PSTR("Type '?' and return for help"), PSTR("")); + shell_output_P(PSTR("uIP command shell"), NULL); + shell_output_P(PSTR("Type '?' and return for help"), NULL); shell_prompt(SHELL_PROMPT); } /*---------------------------------------------------------------------------*/ diff --git a/examples/telnet_server/shell.h b/examples/telnet_server/shell.h index 3d4c18e..d0c4b5b 100644 --- a/examples/telnet_server/shell.h +++ b/examples/telnet_server/shell.h @@ -75,7 +75,7 @@ void shell_input(char *command); * Quit the shell. * */ -void shell_quit(char *); +void shell_quit(const char *); /** diff --git a/examples/telnet_server/telnet.cpp b/examples/telnet_server/telnet.cpp index 5aa85c3..4094495 100644 --- a/examples/telnet_server/telnet.cpp +++ b/examples/telnet_server/telnet.cpp @@ -81,7 +81,7 @@ dealloc_line(char *line) } /*---------------------------------------------------------------------------*/ void -shell_quit(char *) +shell_quit(const char *) { s.state = STATE_CLOSE; } From be7f70dac642002d549a21081870b55524de9def Mon Sep 17 00:00:00 2001 From: maniacbug Date: Mon, 2 Jan 2012 15:35:57 -0800 Subject: [PATCH 07/15] Move parsetab into progmem --- examples/telnet_server/shell.cpp | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/examples/telnet_server/shell.cpp b/examples/telnet_server/shell.cpp index 5d8af73..006b5c8 100644 --- a/examples/telnet_server/shell.cpp +++ b/examples/telnet_server/shell.cpp @@ -49,14 +49,25 @@ struct ptentry { void parse(const register char *str, struct ptentry *t) { - struct ptentry *p; - for(p = t; p->commandstr != NULL; ++p) { - if(strncmp_P(str, p->commandstr, strlen_P(p->commandstr)) == 0) { + // RAM space to copy an entry down from progmem + struct ptentry entry; + + // Copy down the first entry + memcpy_P(&entry,t,sizeof(entry)); + + // Keep looking at entries until the commandstr is empty + while ( entry.commandstr != NULL ) + { + // If the command matches + if(strncmp_P(str, entry.commandstr, strlen_P(entry.commandstr)) == 0) { + // We've found our goal, stop! break; } + // Copy down the next entry + memcpy_P(&entry,++t,sizeof(entry)); } - p->pfunc(str); + entry.pfunc(str); } extern char* __brkval; @@ -103,7 +114,7 @@ const char exit_str_p[] PROGMEM = "exit"; const char q_str_p[] PROGMEM = "?"; const char mem_str_p[] PROGMEM = "mem"; -static struct ptentry parsetab[] = +static struct ptentry parsetab[] PROGMEM = {{stats_str_p, help}, {conn_str_p, help}, {help_str_p, help}, From 12ac347892ec38c8fb045bbee8addf4daa361c7f Mon Sep 17 00:00:00 2001 From: maniacbug Date: Mon, 2 Jan 2012 15:39:07 -0800 Subject: [PATCH 08/15] Add shell_output_P_1st() so we can use progmem even when only one of the shell output lines is in progmem --- examples/telnet_server/shell.cpp | 2 +- examples/telnet_server/shell.h | 1 + examples/telnet_server/telnet.cpp | 24 ++++++++++++++++++++++++ 3 files changed, 26 insertions(+), 1 deletion(-) diff --git a/examples/telnet_server/shell.cpp b/examples/telnet_server/shell.cpp index 006b5c8..99a72d7 100644 --- a/examples/telnet_server/shell.cpp +++ b/examples/telnet_server/shell.cpp @@ -102,7 +102,7 @@ static void unknown_command(const char *str) { if(strlen(str) > 0) { - shell_output("Unknown command: ", str); + shell_output_P_1st(PSTR("Unknown command: "), str); } } /*---------------------------------------------------------------------------*/ diff --git a/examples/telnet_server/shell.h b/examples/telnet_server/shell.h index d0c4b5b..56d26e6 100644 --- a/examples/telnet_server/shell.h +++ b/examples/telnet_server/shell.h @@ -90,6 +90,7 @@ void shell_quit(const char *); */ void shell_output(const char *str1, const char *str2); void shell_output_P(PGM_P str1, PGM_P str2); +void shell_output_P_1st(PGM_P str1, const char* str2); /** * Print a prompt to the shell window. diff --git a/examples/telnet_server/telnet.cpp b/examples/telnet_server/telnet.cpp index 4094495..3d11b26 100644 --- a/examples/telnet_server/telnet.cpp +++ b/examples/telnet_server/telnet.cpp @@ -163,6 +163,30 @@ shell_output_P(PGM_P str1, PGM_P str2) } /*---------------------------------------------------------------------------*/ void +shell_output_P_1st(PGM_P str1, const char* str2) +{ + static unsigned len; + char *line; + + line = alloc_line(); + if(line != NULL) { + len = strlen_P(str1); + strncpy_P(line, str1, TELNETD_CONF_LINELEN); + if(str2 && len < TELNETD_CONF_LINELEN) { + strncpy(line + len, str2, TELNETD_CONF_LINELEN - len); + } + len = strlen(line); + if(len < TELNETD_CONF_LINELEN - 2) { + line[len] = ISO_cr; + line[len+1] = ISO_nl; + line[len+2] = 0; + } + /* petsciiconv_toascii(line, TELNETD_CONF_LINELEN);*/ + sendline(line); + } +} +/*---------------------------------------------------------------------------*/ +void telnetd_init(void) { uip_listen(HTONS(23),telnetd_appcall); From b2379167a070bd1901ba09366d3b1d8f3cbd6808 Mon Sep 17 00:00:00 2001 From: maniacbug Date: Mon, 2 Jan 2012 15:41:15 -0800 Subject: [PATCH 09/15] Moved shell prompt to progmem --- examples/telnet_server/shell.cpp | 4 ++-- examples/telnet_server/shell.h | 3 ++- examples/telnet_server/telnet.cpp | 14 +++++++++++++- 3 files changed, 17 insertions(+), 4 deletions(-) diff --git a/examples/telnet_server/shell.cpp b/examples/telnet_server/shell.cpp index 99a72d7..5f13cef 100644 --- a/examples/telnet_server/shell.cpp +++ b/examples/telnet_server/shell.cpp @@ -133,14 +133,14 @@ shell_start(void) { shell_output_P(PSTR("uIP command shell"), NULL); shell_output_P(PSTR("Type '?' and return for help"), NULL); - shell_prompt(SHELL_PROMPT); + shell_prompt_P(PSTR(SHELL_PROMPT)); } /*---------------------------------------------------------------------------*/ void shell_input(char *cmd) { parse(cmd, parsetab); - shell_prompt(SHELL_PROMPT); + shell_prompt_P(PSTR(SHELL_PROMPT)); } /*---------------------------------------------------------------------------*/ // vim:cin:ai:sts=2 sw=2 ft=cpp diff --git a/examples/telnet_server/shell.h b/examples/telnet_server/shell.h index 56d26e6..4c2b6db 100644 --- a/examples/telnet_server/shell.h +++ b/examples/telnet_server/shell.h @@ -101,7 +101,8 @@ void shell_output_P_1st(PGM_P str1, const char* str2); * \param prompt The prompt to be printed. * */ -void shell_prompt(char *prompt); +void shell_prompt(const char *prompt); +void shell_prompt_P(PGM_P prompt); #endif /* __SHELL_H__ */ // vim:cin:ai:sts=2 sw=2 ft=cpp diff --git a/examples/telnet_server/telnet.cpp b/examples/telnet_server/telnet.cpp index 3d11b26..728c76c 100644 --- a/examples/telnet_server/telnet.cpp +++ b/examples/telnet_server/telnet.cpp @@ -103,7 +103,7 @@ sendline(char *line) } /*---------------------------------------------------------------------------*/ void -shell_prompt(char *str) +shell_prompt(const char *str) { char *line; line = alloc_line(); @@ -115,6 +115,18 @@ shell_prompt(char *str) } /*---------------------------------------------------------------------------*/ void +shell_prompt_P(PGM_P str) +{ + char *line; + line = alloc_line(); + if(line != NULL) { + strncpy_P(line, str, TELNETD_CONF_LINELEN); + /* petsciiconv_toascii(line, TELNETD_CONF_LINELEN);*/ + sendline(line); + } +} +/*---------------------------------------------------------------------------*/ +void shell_output(const char *str1, const char *str2) { static unsigned len; From cfb06ce4eafcb9b7109e1f55914bd4bc72a926d7 Mon Sep 17 00:00:00 2001 From: maniacbug Date: Mon, 2 Jan 2012 15:43:46 -0800 Subject: [PATCH 10/15] Move NanodeUIP sprintf's into progmem --- NanodeUIP.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/NanodeUIP.cpp b/NanodeUIP.cpp index aec8343..2f498a5 100644 --- a/NanodeUIP.cpp +++ b/NanodeUIP.cpp @@ -93,14 +93,14 @@ void NanodeUIP::set_nameserver_addr(byte a, byte b, byte c, byte d) { // Requires a buffer of at least 18 bytes to format into void NanodeUIP::get_mac_str(char *buf) { - sprintf(buf,"%02X:%02X:%02X:%02X:%02X:%02X", + sprintf_P(buf,PSTR("%02X:%02X:%02X:%02X:%02X:%02X"), uip_ethaddr.addr[0], uip_ethaddr.addr[1], uip_ethaddr.addr[2], uip_ethaddr.addr[3], uip_ethaddr.addr[4], uip_ethaddr.addr[5]); } // Requires a buffer of at least 16 bytes to format into void NanodeUIP::format_ipaddr(char *buf,uint16_t *addr) { - sprintf(buf,"%d.%d.%d.%d",addr[0]&0xff,addr[0]>>8, + sprintf_P(buf,PSTR("%d.%d.%d.%d"),addr[0]&0xff,addr[0]>>8, addr[1]&0xff,addr[1]>>8); } From 5d42a0947b94fcb7fe41d4382ee00be61c5ec359 Mon Sep 17 00:00:00 2001 From: maniacbug Date: Mon, 2 Jan 2012 16:07:28 -0800 Subject: [PATCH 11/15] Added an 'expect' file to test the functionality of the telnet server. --- examples/telnet_server/test.ex | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 examples/telnet_server/test.ex diff --git a/examples/telnet_server/test.ex b/examples/telnet_server/test.ex new file mode 100644 index 0000000..caa886c --- /dev/null +++ b/examples/telnet_server/test.ex @@ -0,0 +1,14 @@ +#!/usr/bin/expect + +spawn telnet 192.168.1.118 +expect "NanodeUIP>" +send "mem\r" +expect "NanodeUIP>" +send "help\r" +expect "NanodeUIP>" +send "garbage\r" +expect "NanodeUIP>" +send "exit\r" +expect "NanodeUIP>" + + From 2d21b444bd3a8a3e97f44d4f04664815c290285d Mon Sep 17 00:00:00 2001 From: maniacbug Date: Sun, 1 Jan 2012 20:03:20 -0800 Subject: [PATCH 12/15] Add progmem logging --- NanodeUIP.cpp | 7 ++++++- NanodeUIP.h | 3 +++ platform.cpp | 5 +++++ uip.cpp | 5 +++-- uipopt.h | 2 ++ 5 files changed, 19 insertions(+), 3 deletions(-) diff --git a/NanodeUIP.cpp b/NanodeUIP.cpp index 2f498a5..4e77df8 100644 --- a/NanodeUIP.cpp +++ b/NanodeUIP.cpp @@ -1,5 +1,7 @@ #include "NanodeUIP.h" +#include +#include #include #include "uip.h" @@ -8,12 +10,15 @@ #include "dhcpc.h" #include "resolv.h" -void nanode_log(char *msg); void nanode_log(char *msg) { Serial.println(msg); } +void nanode_log_P(PGM_P msg) { + printf_P(PSTR("%lu: %S\r\n"),millis(),msg); +} + void dhcpc_configured(const struct dhcpc_state *s) { uip_sethostaddr(s->ipaddr); uip_setnetmask(s->netmask); diff --git a/NanodeUIP.h b/NanodeUIP.h index 5d424b7..a0f9526 100644 --- a/NanodeUIP.h +++ b/NanodeUIP.h @@ -6,11 +6,14 @@ #else #include // Arduino 0022 #endif +#include #include "uip.h" #include "timer.h" extern void resolv_conf(const uint16_t *dnsserver); +extern void nanode_log(char *msg); +extern void nanode_log_P(PGM_P msg); #define DHCP_STATUS_OK 1 #define DHCP_STATUS_DOWN 0 diff --git a/platform.cpp b/platform.cpp index 197c9e0..c2e328d 100644 --- a/platform.cpp +++ b/platform.cpp @@ -1,3 +1,4 @@ +#include #include "clock.h" #include "uip-conf.h" @@ -14,7 +15,11 @@ clock_time_t clock_time(void) { void nullproc(void) {} extern void nanode_log(char *msg); +extern void nanode_log_P(PGM_P msg); void uip_log(char *msg) { nanode_log(msg); } +void uip_log_P(PGM_P msg) { + nanode_log_P(msg); +} diff --git a/uip.cpp b/uip.cpp index fe39330..8e577a9 100644 --- a/uip.cpp +++ b/uip.cpp @@ -240,9 +240,10 @@ struct uip_stats uip_stat; #endif /* UIP_STATISTICS == 1 */ #if UIP_LOGGING == 1 +#include #include -void uip_log(char *msg); -#define UIP_LOG(m) uip_log(m) +void uip_log_P(PGM_P msg); +#define UIP_LOG(m) uip_log_P(PSTR(m)) #else #define UIP_LOG(m) #endif /* UIP_LOGGING == 1 */ diff --git a/uipopt.h b/uipopt.h index b1ef8e5..07343ed 100644 --- a/uipopt.h +++ b/uipopt.h @@ -67,6 +67,7 @@ #define UIP_BIG_ENDIAN 1234 #endif /* UIP_BIG_ENDIAN */ +#include #include "uip-conf.h" /*------------------------------------------------------------------------------*/ @@ -432,6 +433,7 @@ * is called by uIP whenever a log message is generated. */ void uip_log(char *msg); +void uip_log_P(PGM_P msg); /** * The link level header length. From c712582073d32647ac0e98862b934044e94a2a28 Mon Sep 17 00:00:00 2001 From: maniacbug Date: Mon, 2 Jan 2012 21:04:55 -0800 Subject: [PATCH 13/15] Move telnet app state into connection app state --- examples/telnet_server/telnet.cpp | 90 ++++++++++++++++--------------- 1 file changed, 46 insertions(+), 44 deletions(-) diff --git a/examples/telnet_server/telnet.cpp b/examples/telnet_server/telnet.cpp index 728c76c..12b1160 100644 --- a/examples/telnet_server/telnet.cpp +++ b/examples/telnet_server/telnet.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, Adam Dunkels. + * Copyright (c) 2003, Adam Dunkelps-> * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -60,7 +60,7 @@ MEMB(linemem, struct telnetd_line, TELNETD_CONF_NUMLINES); #define STATE_CLOSE 6 // Static state is wasting space. Should use the connection state. -static struct telnetd_state s; +static struct telnetd_state* ps; #define TELNET_IAC 255 #define TELNET_WILL 251 @@ -83,7 +83,7 @@ dealloc_line(char *line) void shell_quit(const char *) { - s.state = STATE_CLOSE; + ps->state = STATE_CLOSE; } /*---------------------------------------------------------------------------*/ static void @@ -92,8 +92,8 @@ sendline(char *line) static unsigned int i; for(i = 0; i < TELNETD_CONF_NUMLINES; ++i) { - if(s.lines[i] == NULL) { - s.lines[i] = line; + if(ps->lines[i] == NULL) { + ps->lines[i] = line; break; } } @@ -211,13 +211,13 @@ acked(void) { static unsigned int i; - while(s.numsent > 0) { - dealloc_line(s.lines[0]); + while(ps->numsent > 0) { + dealloc_line(ps->lines[0]); for(i = 1; i < TELNETD_CONF_NUMLINES; ++i) { - s.lines[i - 1] = s.lines[i]; + ps->lines[i - 1] = ps->lines[i]; } - s.lines[TELNETD_CONF_NUMLINES - 1] = NULL; - --s.numsent; + ps->lines[TELNETD_CONF_NUMLINES - 1] = NULL; + --ps->numsent; } } /*---------------------------------------------------------------------------*/ @@ -229,9 +229,9 @@ senddata(void) bufptr = reinterpret_cast(uip_appdata); buflen = 0; - for(s.numsent = 0; s.numsent < TELNETD_CONF_NUMLINES && - s.lines[s.numsent] != NULL ; ++s.numsent) { - lineptr = s.lines[s.numsent]; + for(ps->numsent = 0; ps->numsent < TELNETD_CONF_NUMLINES && + ps->lines[ps->numsent] != NULL ; ++ps->numsent) { + lineptr = ps->lines[ps->numsent]; linelen = strlen(lineptr); if(linelen > TELNETD_CONF_LINELEN) { linelen = TELNETD_CONF_LINELEN; @@ -253,8 +253,8 @@ closed(void) static unsigned int i; for(i = 0; i < TELNETD_CONF_NUMLINES; ++i) { - if(s.lines[i] != NULL) { - dealloc_line(s.lines[i]); + if(ps->lines[i] != NULL) { + dealloc_line(ps->lines[i]); } } } @@ -266,20 +266,20 @@ get_char(u8_t c) return; } - s.buf[(int)s.bufptr] = c; - if(s.buf[(int)s.bufptr] == ISO_nl || - s.bufptr == sizeof(s.buf) - 1) { - if(s.bufptr > 0) { - s.buf[(int)s.bufptr] = 0; - /* petsciiconv_topetscii(s.buf, TELNETD_CONF_LINELEN);*/ + ps->buf[(int)ps->bufptr] = c; + if(ps->buf[(int)ps->bufptr] == ISO_nl || + ps->bufptr == sizeof(ps->buf) - 1) { + if(ps->bufptr > 0) { + ps->buf[(int)ps->bufptr] = 0; + /* petsciiconv_topetscii(ps->buf, TELNETD_CONF_LINELEN);*/ } - if((s.bufptr + 1) < sizeof(s.buf)) { - s.buf[(int)s.bufptr +1] = 0; + if((ps->bufptr + 1) < sizeof(ps->buf)) { + ps->buf[(int)ps->bufptr +1] = 0; } - shell_input(s.buf); - s.bufptr = 0; + shell_input(ps->buf); + ps->bufptr = 0; } else { - ++s.bufptr; + ++ps->bufptr; } } /*---------------------------------------------------------------------------*/ @@ -308,31 +308,31 @@ newdata(void) len = uip_datalen(); dataptr = (char *)uip_appdata; - while(len > 0 && s.bufptr < sizeof(s.buf)) { + while(len > 0 && ps->bufptr < sizeof(ps->buf)) { c = *dataptr; ++dataptr; --len; - switch(s.state) { + switch(ps->state) { case STATE_IAC: if(c == TELNET_IAC) { get_char(c); - s.state = STATE_NORMAL; + ps->state = STATE_NORMAL; } else { switch(c) { case TELNET_WILL: - s.state = STATE_WILL; + ps->state = STATE_WILL; break; case TELNET_WONT: - s.state = STATE_WONT; + ps->state = STATE_WONT; break; case TELNET_DO: - s.state = STATE_DO; + ps->state = STATE_DO; break; case TELNET_DONT: - s.state = STATE_DONT; + ps->state = STATE_DONT; break; default: - s.state = STATE_NORMAL; + ps->state = STATE_NORMAL; break; } } @@ -340,27 +340,27 @@ newdata(void) case STATE_WILL: /* Reply with a DONT */ sendopt(TELNET_DONT, c); - s.state = STATE_NORMAL; + ps->state = STATE_NORMAL; break; case STATE_WONT: /* Reply with a DONT */ sendopt(TELNET_DONT, c); - s.state = STATE_NORMAL; + ps->state = STATE_NORMAL; break; case STATE_DO: /* Reply with a WONT */ sendopt(TELNET_WONT, c); - s.state = STATE_NORMAL; + ps->state = STATE_NORMAL; break; case STATE_DONT: /* Reply with a WONT */ sendopt(TELNET_WONT, c); - s.state = STATE_NORMAL; + ps->state = STATE_NORMAL; break; case STATE_NORMAL: if(c == TELNET_IAC) { - s.state = STATE_IAC; + ps->state = STATE_IAC; } else { get_char(c); } @@ -375,20 +375,21 @@ newdata(void) void telnetd_appcall(void) { + ps = reinterpret_cast(&(uip_conn->appstate)); static unsigned int i; if(uip_connected()) { /* tcp_markconn(uip_conn, &s);*/ for(i = 0; i < TELNETD_CONF_NUMLINES; ++i) { - s.lines[i] = NULL; + ps->lines[i] = NULL; } - s.bufptr = 0; - s.state = STATE_NORMAL; + ps->bufptr = 0; + ps->state = STATE_NORMAL; shell_start(); } - if(s.state == STATE_CLOSE) { - s.state = STATE_NORMAL; + if(ps->state == STATE_CLOSE) { + ps->state = STATE_NORMAL; uip_close(); return; } @@ -414,6 +415,7 @@ telnetd_appcall(void) uip_poll()) { senddata(); } + ps = NULL; } /*---------------------------------------------------------------------------*/ // vim:cin:ai:sts=2 sw=2 ft=cpp From 38322bda6673187195e5990dfae8c04593fb01d1 Mon Sep 17 00:00:00 2001 From: maniacbug Date: Mon, 2 Jan 2012 21:42:33 -0800 Subject: [PATCH 14/15] Move static app state AND line memory into connection app state. Reduces memory and allows multiple concurrent telnet connections. --- examples/telnet_server/shell.cpp | 2 +- examples/telnet_server/telnet.cpp | 21 ++++++++------------- examples/telnet_server/telnetd.h | 17 +++++++++++++++-- 3 files changed, 24 insertions(+), 16 deletions(-) diff --git a/examples/telnet_server/shell.cpp b/examples/telnet_server/shell.cpp index 5f13cef..1a4de98 100644 --- a/examples/telnet_server/shell.cpp +++ b/examples/telnet_server/shell.cpp @@ -91,7 +91,7 @@ show_memory(const char *str) static void help(const char *) { - // TEXT HERE CAN ONLY BE 40 chars / output! based on telnetd.h + // TEXT HERE CAN ONLY BE 30 chars / output! based on telnetd.h shell_output_P(PSTR("Available commands:"), NULL); shell_output_P(PSTR("help, ? - show help"), NULL); shell_output_P(PSTR("exit - exit shell"), NULL); diff --git a/examples/telnet_server/telnet.cpp b/examples/telnet_server/telnet.cpp index 12b1160..1e0742a 100644 --- a/examples/telnet_server/telnet.cpp +++ b/examples/telnet_server/telnet.cpp @@ -36,21 +36,12 @@ #include "Arduino.h" #include "telnetd.h" #include "shell.h" -extern "C" -{ -#include "memb.h" -} #include #define ISO_nl 0x0a #define ISO_cr 0x0d -struct telnetd_line { - char line[TELNETD_CONF_LINELEN]; -}; -MEMB(linemem, struct telnetd_line, TELNETD_CONF_NUMLINES); - #define STATE_NORMAL 0 #define STATE_IAC 1 #define STATE_WILL 2 @@ -59,7 +50,6 @@ MEMB(linemem, struct telnetd_line, TELNETD_CONF_NUMLINES); #define STATE_DONT 5 #define STATE_CLOSE 6 -// Static state is wasting space. Should use the connection state. static struct telnetd_state* ps; #define TELNET_IAC 255 @@ -71,13 +61,13 @@ static struct telnetd_state* ps; static char * alloc_line(void) { - return reinterpret_cast(memb_alloc(&linemem)); + return reinterpret_cast(memb_alloc(&(ps->linemem))); } /*---------------------------------------------------------------------------*/ static void dealloc_line(char *line) { - memb_free(&linemem, line); + memb_free(&(ps->linemem), line); } /*---------------------------------------------------------------------------*/ void @@ -202,7 +192,6 @@ void telnetd_init(void) { uip_listen(HTONS(23),telnetd_appcall); - memb_init(&linemem); shell_init(); } /*---------------------------------------------------------------------------*/ @@ -385,6 +374,12 @@ telnetd_appcall(void) ps->bufptr = 0; ps->state = STATE_NORMAL; + ps->linemem.size = sizeof(telnetd_line); + ps->linemem.num = TELNETD_CONF_NUMLINES; + ps->linemem.count = ps->linemem_memb_count; + ps->linemem.mem = ps->linemem_memb_mem; + memb_init(&(ps->linemem)); + shell_start(); } diff --git a/examples/telnet_server/telnetd.h b/examples/telnet_server/telnetd.h index 5f055ca..8a8fa7b 100644 --- a/examples/telnet_server/telnetd.h +++ b/examples/telnet_server/telnetd.h @@ -36,24 +36,37 @@ #define __TELNETD_H__ #include "uipopt.h" +extern "C" +{ +#include "memb.h" +} void telnetd_appcall(void); void telnetd_init(void); +// Be sure to adjust TCP_APP_STATE_SIZE if you change any of these! #ifndef TELNETD_CONF_LINELEN -#define TELNETD_CONF_LINELEN 40 +#define TELNETD_CONF_LINELEN 30 #endif #ifndef TELNETD_CONF_NUMLINES // orig value #define TELNETD_CONF_NUMLINES 16 -#define TELNETD_CONF_NUMLINES 8 +#define TELNETD_CONF_NUMLINES 5 #endif +struct telnetd_line { + char line[TELNETD_CONF_LINELEN]; +}; + struct telnetd_state { char *lines[TELNETD_CONF_NUMLINES]; char buf[TELNETD_CONF_LINELEN]; u8_t bufptr; u8_t numsent; u8_t state; + + char linemem_memb_count[TELNETD_CONF_NUMLINES]; + telnetd_line linemem_memb_mem[TELNETD_CONF_NUMLINES]; + memb_blocks linemem; }; #endif /* __TELNETD_H__ */ From 46788c082104c3ad4ba3560e583e489b650b9466 Mon Sep 17 00:00:00 2001 From: maniacbug Date: Mon, 2 Jan 2012 21:47:36 -0800 Subject: [PATCH 15/15] Larger app data size to accomodate telnet --- uip-conf.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/uip-conf.h b/uip-conf.h index 9ba773c..a387bae 100644 --- a/uip-conf.h +++ b/uip-conf.h @@ -137,7 +137,7 @@ typedef unsigned short uip_stats_t; /*#include "webclient.h"*/ /* XXX must figure out a better way of doing this! */ -#define TCP_APP_STATE_SIZE 150 +#define TCP_APP_STATE_SIZE 220 typedef void tcp_appcall_fn(void); typedef void udp_appcall_fn(void);