Revision 1.5 2005/11/22 09:14:13 haraldkipp Replaced specific device names by generalized macros.
Revision 1.4 2005/04/30 16:42:41 chaac Fixed bug in handling of NUTDEBUG. Added include for cfg/os.h. If NUTDEBUG is defined in NutConf, it will make effect where it is used.
Revision 1.3 2005/04/19 08:55:29 haraldkipp Description updated
Revision 1.2 2003/11/04 17:46:52 haraldkipp Adapted to Ethernut 2
Revision 1.1 2003/08/05 18:59:05 haraldkipp Release 3.3 update
Revision 1.8 2003/02/04 16:24:35 harald Adapted to version 3
Revision 1.7 2002/06/26 17:29:06 harald First pre-release with 2.4 stack
Revision 1.6 2002/06/12 10:59:05 harald *** empty log message ***
Revision 1.5 2002/06/04 19:12:55 harald *** empty log message ***
Revision 1.4 2002/05/08 16:02:32 harald First Imagecraft compilation
Simple TCP server.
Program Ethernut with tcps.hex and enter
on a command prompt, replacing x.x.x.x with the IP address of your ethernut board. Enter help for a list of available commands.
00001 /* 00002 * Copyright (C) 2001-2005 by egnite Software GmbH. All rights reserved. 00003 * 00004 * Redistribution and use in source and binary forms, with or without 00005 * modification, are permitted provided that the following conditions 00006 * are met: 00007 * 00008 * 1. Redistributions of source code must retain the above copyright 00009 * notice, this list of conditions and the following disclaimer. 00010 * 2. Redistributions in binary form must reproduce the above copyright 00011 * notice, this list of conditions and the following disclaimer in the 00012 * documentation and/or other materials provided with the distribution. 00013 * 3. Neither the name of the copyright holders nor the names of 00014 * contributors may be used to endorse or promote products derived 00015 * from this software without specific prior written permission. 00016 * 00017 * THIS SOFTWARE IS PROVIDED BY EGNITE SOFTWARE GMBH AND CONTRIBUTORS 00018 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 00019 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 00020 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL EGNITE 00021 * SOFTWARE GMBH OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 00022 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 00023 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS 00024 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 00025 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 00026 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 00027 * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 00028 * SUCH DAMAGE. 00029 * 00030 * For additional information see http://www.ethernut.de/ 00031 * 00032 */ 00033 00086 #include <cfg/os.h> 00087 #include <string.h> 00088 #include <stdio.h> 00089 #include <io.h> 00090 00091 #include <dev/board.h> 00092 00093 #include <sys/version.h> 00094 #include <sys/heap.h> 00095 #include <sys/thread.h> 00096 #include <sys/timer.h> 00097 #include <sys/socket.h> 00098 00099 #include <arpa/inet.h> 00100 #include <pro/dhcp.h> 00101 00102 #ifdef NUTDEBUG 00103 #include <sys/osdebug.h> 00104 #include <net/netdebug.h> 00105 #endif 00106 00107 #include <sys/confnet.h> 00108 00109 static char buff[128]; 00110 00111 /* 00112 * To save RAM, we store large strings in program space. With AVRGCC we 00113 * would be able to use the PSTR() macro and put the text directly in 00114 * the statement that uses it. But ICCAVR doesn't support anything like 00115 * this. Sigh. 00116 */ 00117 #if defined(__IMAGECRAFT__) 00118 #define CC_STRING "ICCAVR" 00119 #elif defined(__GNUC__) 00120 #define CC_STRING "AVRGCC" 00121 #else 00122 #define CC_STRING "Compiler unknown" 00123 #endif 00124 00125 prog_char vbanner_P[] = "\n\nTCP Server Sample - Nut/OS %s - " CC_STRING "\n"; 00126 prog_char banner_P[] = "200 Welcome to tcps. Type help to get help.\r\n"; 00127 prog_char help_P[] = "400 List of commands follows\r\n" 00128 "m[emory]\tQueries number of RAM bytes free.\r\n" 00129 "t[hreads]\tLists all created threads.\r\n" 00130 "ti[mers]\tLists all running timers.\r\n" "q[uit]\t\tTerminates connection.\r\n" ".\r\n"; 00131 prog_char thread_intro_P[] = "220 List of threads with name,state,prio,stack,mem,timeout follows\r\n"; 00132 prog_char timer_intro_P[] = "221 List of timers with ticks left and interval follows\r\n"; 00133 prog_char mem_fmt_P[] = "210 %u bytes RAM free\r\n"; 00134 00135 /* 00136 * Process client requests. 00137 */ 00138 void ProcessRequests(FILE * stream) 00139 { 00140 int got; 00141 char *cp; 00142 00143 /* 00144 * Send a welcome banner. 00145 */ 00146 fputs_P(banner_P, stream); 00147 for (;;) { 00148 00149 /* 00150 * Flush output and read a line. 00151 */ 00152 fflush(stream); 00153 if (fgets(buff, sizeof(buff), stream) == 0) 00154 break; 00155 00156 /* 00157 * Chop off EOL. 00158 */ 00159 if ((cp = strchr(buff, '\r')) != 0) 00160 *cp = 0; 00161 if ((cp = strchr(buff, '\n')) != 0) 00162 *cp = 0; 00163 00164 /* 00165 * Ignore blank lines. 00166 */ 00167 got = strlen(buff); 00168 if (got == 0) 00169 continue; 00170 00171 /* 00172 * Memory info. 00173 */ 00174 if (strncmp(buff, "memory", got) == 0) { 00175 fprintf_P(stream, mem_fmt_P, (u_int)NutHeapAvailable()); 00176 continue; 00177 } 00178 00179 /* 00180 * List threads. 00181 */ 00182 if (strncmp(buff, "threads", got) == 0) { 00183 NUTTHREADINFO *tdp; 00184 NUTTIMERINFO *tnp; 00185 00186 fputs_P(thread_intro_P, stream); 00187 for (tdp = nutThreadList; tdp; tdp = tdp->td_next) { 00188 fputs(tdp->td_name, stream); 00189 switch (tdp->td_state) { 00190 case TDS_TERM: 00191 fputs("\tTerm\t", stream); 00192 break; 00193 case TDS_RUNNING: 00194 fputs("\tRun\t", stream); 00195 break; 00196 case TDS_READY: 00197 fputs("\tReady\t", stream); 00198 break; 00199 case TDS_SLEEP: 00200 fputs("\tSleep\t", stream); 00201 break; 00202 } 00203 fprintf(stream, "%u\t%u", tdp->td_priority, (u_int) tdp->td_sp - (u_int) tdp->td_memory); 00204 if (*((u_long *) tdp->td_memory) != DEADBEEF) 00205 fputs("\tCorrupted\t", stream); 00206 else 00207 fputs("\tOK\t", stream); 00208 00209 if ((tnp = (NUTTIMERINFO *) tdp->td_timer) != 0) 00210 fprintf(stream, "%lu\r\n", tnp->tn_ticks_left); 00211 else 00212 fputs("None\r\n", stream); 00213 } 00214 fputs(".\r\n", stream); 00215 continue; 00216 } 00217 00218 /* 00219 * List timers. 00220 */ 00221 if (strncmp("timers", buff, got) == 0) { 00222 NUTTIMERINFO *tnp; 00223 00224 fputs_P(timer_intro_P, stream); 00225 for (tnp = nutTimerList; tnp; tnp = tnp->tn_next) { 00226 fprintf(stream, "%lu\t", tnp->tn_ticks_left); 00227 if (tnp->tn_ticks) 00228 fprintf(stream, "%lu\r\n", tnp->tn_ticks); 00229 else 00230 fputs("Oneshot\r\n", stream); 00231 } 00232 fputs(".\r\n", stream); 00233 continue; 00234 } 00235 00236 /* 00237 * Quit connection. 00238 */ 00239 if (strncmp("quit", buff, got) == 0) { 00240 break; 00241 } 00242 00243 /* 00244 * Display help text on any unknown command. 00245 */ 00246 fputs_P(help_P, stream); 00247 } 00248 } 00249 00250 /* 00251 * Main application routine. 00252 * 00253 * Nut/OS automatically calls this entry after initialization. 00254 */ 00255 int main(void) 00256 { 00257 TCPSOCKET *sock; 00258 FILE *stream; 00259 u_long baud = 115200; 00260 u_char mac[6] = { 0x00, 0x06, 0x98, 0x00, 0x00, 0x55 }; 00261 00262 /* 00263 * Register all devices used in our application. 00264 */ 00265 NutRegisterDevice(&DEV_DEBUG, 0, 0); 00266 NutRegisterDevice(&DEV_ETHER, 0x8300, 5); 00267 00268 /* 00269 * Assign stdout to the UART device. 00270 */ 00271 freopen(DEV_DEBUG_NAME, "w", stdout); 00272 _ioctl(_fileno(stdout), UART_SETSPEED, &baud); 00273 printf_P(vbanner_P, NutVersionString()); 00274 #ifdef NUTDEBUG 00275 NutTraceTcp(stdout, 1); 00276 NutTraceOs(stdout, 0); 00277 NutTraceHeap(stdout, 0); 00278 NutTracePPP(stdout, 0); 00279 #endif 00280 00281 NutNetLoadConfig(DEV_ETHER_NAME); 00282 memcpy(confnet.cdn_mac, mac, 6); 00283 NutNetSaveConfig(); 00284 00285 /* 00286 * Setup the ethernet device. Try DHCP first. If this is 00287 * the first time boot with empty EEPROM and no DHCP server 00288 * was found, use hardcoded values. 00289 */ 00290 printf("Configure eth0..."); 00291 if (NutDhcpIfConfig("eth0", 0, 60000)) { 00292 printf("initial boot..."); 00293 if (NutDhcpIfConfig("eth0", mac, 60000)) { 00294 u_long ip_addr = inet_addr("192.168.192.100"); 00295 u_long ip_mask = inet_addr("255.255.255.0"); 00296 00297 printf("no DHCP..."); 00298 NutNetIfConfig("eth0", mac, ip_addr, ip_mask); 00299 /* If not in a local network, we must also call 00300 NutIpRouteAdd() to configure the routing. */ 00301 } 00302 } 00303 puts("OK"); 00304 printf("IP: %s\n", inet_ntoa(confnet.cdn_ip_addr)); 00305 00306 /* 00307 * Now loop endless for connections. 00308 */ 00309 for (;;) { 00310 /* 00311 * Create a socket. 00312 */ 00313 if ((sock = NutTcpCreateSocket()) != 0) { 00314 /* 00315 * Listen on port 23. If we return, we got a client. 00316 */ 00317 printf("Waiting for a telnet client..."); 00318 if (NutTcpAccept(sock, 23) == 0) { 00319 puts("connected"); 00320 00321 /* 00322 * Open a stream and associate it with the socket, so 00323 * we can use standard I/O. Note, that socket streams 00324 * currently do support text mode. 00325 */ 00326 if ((stream = _fdopen((int) sock, "r+b")) != 0) { 00327 /* 00328 * Process client requests. 00329 */ 00330 ProcessRequests(stream); 00331 puts("Disconnected"); 00332 00333 /* 00334 * Close the stream. 00335 */ 00336 fclose(stream); 00337 } else 00338 puts("Assigning a stream failed"); 00339 } else 00340 puts("failed"); 00341 00342 /* 00343 * Close our socket. 00344 */ 00345 NutTcpCloseSocket(sock); 00346 } 00347 } 00348 return 0; 00349 }