This application requires the PNUT file system, which is not available on Ethernut 1.x or Charon II.
00001 /* 00002 * Copyright (C) 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 00068 #include <stdio.h> 00069 #include <fcntl.h> 00070 #include <io.h> 00071 00072 #include <dev/board.h> 00073 #include <dev/lanc111.h> 00074 #include <dev/debug.h> 00075 #include <dev/pnut.h> 00076 #include <dev/nplmmc.h> 00077 #include <dev/sbimmc.h> 00078 #include <dev/spimmc_at91.h> 00079 #include <dev/at91_mci.h> 00080 #include <dev/x12rtc.h> 00081 #include <fs/phatfs.h> 00082 00083 #include <sys/confnet.h> 00084 #include <sys/version.h> 00085 #include <sys/heap.h> 00086 #include <sys/thread.h> 00087 #include <sys/socket.h> 00088 00089 #include <arpa/inet.h> 00090 #include <netinet/tcp.h> 00091 #include <net/route.h> 00092 #include <pro/dhcp.h> 00093 #include <pro/ftpd.h> 00094 #include <pro/wins.h> 00095 #include <pro/sntp.h> 00096 #include <pro/discover.h> 00097 00098 /* Determine the compiler. */ 00099 #if defined(__IMAGECRAFT__) 00100 #if defined(__AVR__) 00101 #define CC_STRING "ICCAVR" 00102 #else 00103 #define CC_STRING "ICC" 00104 #endif 00105 #elif defined(__GNUC__) 00106 #if defined(__AVR__) 00107 #define CC_STRING "AVRGCC" 00108 #elif defined(__arm__) 00109 #define CC_STRING "ARMGCC" 00110 #else 00111 #define CC_STRING "GCC" 00112 #endif 00113 #else 00114 #define CC_STRING "Compiler unknown" 00115 #endif 00116 00126 /* 00127 * Baudrate for debug output. 00128 */ 00129 #ifndef DBG_BAUDRATE 00130 #define DBG_BAUDRATE 115200 00131 #endif 00132 00133 /* 00134 * Wether we should use DHCP. 00135 */ 00136 #define USE_DHCP 00137 00138 /* 00139 * Wether we should run a discovery responder. 00140 */ 00141 #if defined(__arm__) 00142 #define USE_DISCOVERY 00143 #endif 00144 00145 /* 00146 * Unique MAC address of the Ethernut Board. 00147 * 00148 * Ignored if EEPROM contains a valid configuration. 00149 */ 00150 #define MY_MAC { 0x00, 0x06, 0x98, 0x30, 0x00, 0x35 } 00151 00152 /* 00153 * Unique IP address of the Ethernut Board. 00154 * 00155 * Ignored if DHCP is used. 00156 */ 00157 #define MY_IPADDR "192.168.192.35" 00158 00159 /* 00160 * IP network mask of the Ethernut Board. 00161 * 00162 * Ignored if DHCP is used. 00163 */ 00164 #define MY_IPMASK "255.255.255.0" 00165 00166 /* 00167 * Gateway IP address for the Ethernut Board. 00168 * 00169 * Ignored if DHCP is used. 00170 */ 00171 #define MY_IPGATE "192.168.192.1" 00172 00173 /* 00174 * NetBIOS name. 00175 * 00176 * Use a symbolic name with Win32 Explorer. 00177 */ 00178 //#define MY_WINSNAME "ETHERNUT" 00179 00180 /* 00181 * FTP port number. 00182 */ 00183 #define FTP_PORTNUM 21 00184 00185 /* 00186 * FTP timeout. 00187 * 00188 * The server will terminate the session, if no new command is received 00189 * within the specified number of milliseconds. 00190 */ 00191 #define FTPD_TIMEOUT 600000 00192 00193 /* 00194 * TCP buffer size. 00195 */ 00196 #define TCPIP_BUFSIZ 5840 00197 00198 /* 00199 * Maximum segment size. 00200 * 00201 * Choose 536 up to 1460. Note, that segment sizes above 536 may result 00202 * in fragmented packets. Remember, that Ethernut doesn't support TCP 00203 * fragmentation. 00204 */ 00205 #define TCPIP_MSS 1460 00206 00207 #if defined(ETHERNUT3) 00208 00209 /* Ethernut 3 file system. */ 00210 #define FSDEV devPhat0 00211 #define FSDEV_NAME "PHAT0" 00212 00213 /* Ethernut 3 block device interface. */ 00214 #define BLKDEV devNplMmc0 00215 #define BLKDEV_NAME "MMC0" 00216 00217 #elif defined(AT91SAM7X_EK) 00218 00219 /* SAM7X-EK file system. */ 00220 #define FSDEV devPhat0 00221 #define FSDEV_NAME "PHAT0" 00222 00223 /* SAM7X-EK block device interface. */ 00224 #define BLKDEV devAt91SpiMmc0 00225 #define BLKDEV_NAME "MMC0" 00226 00227 #elif defined(AT91SAM9260_EK) 00228 00229 /* SAM9260-EK file system. */ 00230 #define FSDEV devPhat0 00231 #define FSDEV_NAME "PHAT0" 00232 00233 /* SAM9260-EK block device interface. */ 00234 #define BLKDEV devAt91Mci0 00235 #define BLKDEV_NAME "MCI0" 00236 00237 #elif defined(ETHERNUT2) 00238 00239 /* 00240 * Ethernut 2 File system 00241 */ 00242 #define FSDEV devPnut 00243 #define FSDEV_NAME "PNUT" 00244 00245 #else 00246 00247 #define FSDEV_NAME "NONE" 00248 00249 #endif 00250 00252 #define MYTZ -1 00253 00255 #define MYTIMED "130.149.17.21" 00256 00257 #ifdef ETHERNUT3 00258 00259 #define X12RTC_DEV 00260 #endif 00261 00262 /* 00263 * FTP service. 00264 * 00265 * This function waits for client connect, processes the FTP request 00266 * and disconnects. Nut/Net doesn't support a server backlog. If one 00267 * client has established a connection, further connect attempts will 00268 * be rejected. 00269 * 00270 * Some FTP clients, like the Win32 Explorer, open more than one 00271 * connection for background processing. So we run this routine by 00272 * several threads. 00273 */ 00274 void FtpService(void) 00275 { 00276 TCPSOCKET *sock; 00277 00278 /* 00279 * Create a socket. 00280 */ 00281 if ((sock = NutTcpCreateSocket()) != 0) { 00282 00283 /* 00284 * Set specified socket options. 00285 */ 00286 #ifdef TCPIP_MSS 00287 { 00288 u_short mss = TCPIP_MSS; 00289 NutTcpSetSockOpt(sock, TCP_MAXSEG, &mss, sizeof(mss)); 00290 } 00291 #endif 00292 #ifdef FTPD_TIMEOUT 00293 { 00294 u_long tmo = FTPD_TIMEOUT; 00295 NutTcpSetSockOpt(sock, SO_RCVTIMEO, &tmo, sizeof(tmo)); 00296 } 00297 #endif 00298 #ifdef TCPIP_BUFSIZ 00299 { 00300 u_short siz = TCPIP_BUFSIZ; 00301 NutTcpSetSockOpt(sock, SO_RCVBUF, &siz, sizeof(siz)); 00302 } 00303 #endif 00304 00305 /* 00306 * Listen on our port. If we return, we got a client. 00307 */ 00308 printf("\nWaiting for an FTP client..."); 00309 if (NutTcpAccept(sock, FTP_PORTNUM) == 0) { 00310 printf("%s connected, %u bytes free\n", inet_ntoa(sock->so_remote_addr), (u_int)NutHeapAvailable()); 00311 NutFtpServerSession(sock); 00312 printf("%s disconnected, %u bytes free\n", inet_ntoa(sock->so_remote_addr), (u_int)NutHeapAvailable()); 00313 } else { 00314 puts("Accept failed"); 00315 } 00316 00317 /* 00318 * Close our socket. 00319 */ 00320 NutTcpCloseSocket(sock); 00321 } 00322 } 00323 00324 /* 00325 * FTP service thread. 00326 */ 00327 THREAD(FtpThread, arg) 00328 { 00329 /* Loop endless for connections. */ 00330 for (;;) { 00331 FtpService(); 00332 } 00333 } 00334 00335 /* 00336 * Assign stdout to the UART device. 00337 */ 00338 void InitDebugDevice(void) 00339 { 00340 u_long baud = DBG_BAUDRATE; 00341 00342 NutRegisterDevice(&DEV_DEBUG, 0, 0); 00343 freopen(DEV_DEBUG_NAME, "w", stdout); 00344 _ioctl(_fileno(stdout), UART_SETSPEED, &baud); 00345 } 00346 00347 /* 00348 * Setup the ethernet device. Try DHCP first. If this is 00349 * the first time boot with empty EEPROM and no DHCP server 00350 * was found, use hardcoded values. 00351 */ 00352 int InitEthernetDevice(void) 00353 { 00354 u_long ip_addr = inet_addr(MY_IPADDR); 00355 u_long ip_mask = inet_addr(MY_IPMASK); 00356 u_long ip_gate = inet_addr(MY_IPGATE); 00357 u_char mac[6] = MY_MAC; 00358 00359 if (NutRegisterDevice(&DEV_ETHER, 0x8300, 5)) { 00360 puts("No Ethernet Device"); 00361 return -1; 00362 } 00363 00364 printf("Configure %s...", DEV_ETHER_NAME); 00365 #ifdef USE_DHCP 00366 if (NutDhcpIfConfig(DEV_ETHER_NAME, 0, 60000) == 0) { 00367 puts("OK"); 00368 return 0; 00369 } 00370 printf("initial boot..."); 00371 if (NutDhcpIfConfig(DEV_ETHER_NAME, mac, 60000) == 0) { 00372 puts("OK"); 00373 return 0; 00374 } 00375 #endif 00376 printf("No DHCP..."); 00377 NutNetIfConfig(DEV_ETHER_NAME, mac, ip_addr, ip_mask); 00378 /* Without DHCP we had to set the default gateway manually.*/ 00379 if(ip_gate) { 00380 printf("hard coded gate..."); 00381 NutIpRouteAdd(0, 0, ip_gate, &DEV_ETHER); 00382 } 00383 puts("OK"); 00384 00385 return 0; 00386 } 00387 00388 /* 00389 * Query a time server and optionally update the hardware clock. 00390 */ 00391 static int QueryTimeServer(void) 00392 { 00393 int rc = -1; 00394 00395 #ifdef MYTIMED 00396 { 00397 time_t now; 00398 u_long timeserver = inet_addr(MYTIMED); 00399 00400 /* Query network time service and set the system time. */ 00401 printf("Query time from %s...", MYTIMED); 00402 if(NutSNTPGetTime(×erver, &now) == 0) { 00403 puts("OK"); 00404 rc = 0; 00405 stime(&now); 00406 #ifdef X12RTC_DEV 00407 /* If RTC hardware is available, update it. */ 00408 { 00409 struct _tm *gmt = gmtime(&now); 00410 00411 if (X12RtcSetClock(gmt)) { 00412 puts("RTC update failed"); 00413 } 00414 } 00415 #endif 00416 } 00417 else { 00418 puts("failed"); 00419 } 00420 } 00421 #endif 00422 00423 return rc; 00424 } 00425 00426 /* 00427 * Try to get initial date and time from the hardware clock or a time server. 00428 */ 00429 static int InitTimeAndDate(void) 00430 { 00431 int rc = -1; 00432 00433 /* Set the local time zone. */ 00434 _timezone = MYTZ * 60L * 60L; 00435 00436 #ifdef X12RTC_DEV 00437 /* Query RTC hardware if available. */ 00438 { 00439 u_long rs; 00440 00441 /* Query the status. If it fails, we do not have an RTC. */ 00442 if (X12RtcGetStatus(&rs)) { 00443 puts("No hardware RTC"); 00444 rc = QueryTimeServer(); 00445 } 00446 else { 00447 /* RTC hardware seems to be available. Check for power failure. */ 00448 //rs = RTC_STATUS_PF; 00449 if ((rs & RTC_STATUS_PF) == RTC_STATUS_PF) { 00450 puts("RTC power fail detected"); 00451 rc = QueryTimeServer(); 00452 } 00453 00454 /* RTC hardware status is fine, update our system clock. */ 00455 else { 00456 struct _tm gmt; 00457 00458 /* Assume that RTC is running at GMT. */ 00459 if (X12RtcGetClock(&gmt) == 0) { 00460 time_t now = _mkgmtime(&gmt); 00461 00462 if (now != -1) { 00463 stime(&now); 00464 rc = 0; 00465 } 00466 } 00467 } 00468 } 00469 } 00470 #else 00471 /* No hardware RTC, query the time server if available. */ 00472 rc = QueryTimeServer(); 00473 #endif 00474 return rc; 00475 } 00476 00477 /* 00478 * Main application routine. 00479 * 00480 * Nut/OS automatically calls this entry after initialization. 00481 */ 00482 int main(void) 00483 { 00484 int volid; 00485 u_long ipgate; 00486 00487 /* Initialize a debug output device and print a banner. */ 00488 InitDebugDevice(); 00489 printf("\n\nFTP Server Sample - Nut/OS %s - " CC_STRING "\n", NutVersionString()); 00490 00491 /* Initialize the Ethernet device and print our IP address. */ 00492 if (InitEthernetDevice()) { 00493 for(;;); 00494 } 00495 printf("IP Addr: %s\n", inet_ntoa(confnet.cdn_ip_addr)); 00496 printf("IP Mask: %s\n", inet_ntoa(confnet.cdn_ip_mask)); 00497 NutIpRouteQuery(0, &ipgate); 00498 printf("IP Gate: %s\n", inet_ntoa(ipgate)); 00499 00500 #ifdef USE_DISCOVERY 00501 /* Register a discovery responder. */ 00502 printf("Start Responder..."); 00503 if (NutRegisterDiscovery((u_long)-1, 0, DISF_INITAL_ANN)) { 00504 puts("failed"); 00505 } 00506 else { 00507 puts("OK"); 00508 } 00509 #endif 00510 00511 /* Initialize system clock and calendar. */ 00512 if (InitTimeAndDate() == 0) { 00513 time_t now = time(0); 00514 struct _tm *lot = localtime(&now); 00515 printf("Date: %02u.%02u.%u\n", lot->tm_mday, lot->tm_mon + 1, 1900 + lot->tm_year); 00516 printf("Time: %02u:%02u:%02u\n", lot->tm_hour, lot->tm_min, lot->tm_sec); 00517 } 00518 00519 #ifdef FSDEV 00520 /* Initialize the file system. */ 00521 printf("Register file system..."); 00522 if (NutRegisterDevice(&FSDEV, 0, 0)) { 00523 puts("failed"); 00524 for (;;); 00525 } 00526 puts("OK"); 00527 #endif 00528 00529 #ifdef BLKDEV 00530 /* Register block device. */ 00531 printf("Register block device..."); 00532 if (NutRegisterDevice(&BLKDEV, 0, 0)) { 00533 puts("failed"); 00534 for (;;); 00535 } 00536 puts("OK"); 00537 00538 /* Mount partition. */ 00539 printf("Mounting partition..."); 00540 if ((volid = _open(BLKDEV_NAME ":1/" FSDEV_NAME, _O_RDWR | _O_BINARY)) == -1) { 00541 puts("failed"); 00542 for (;;); 00543 } 00544 puts("OK"); 00545 #else 00546 volid = 0; 00547 #endif 00548 00549 /* Register root path. */ 00550 printf("Register FTP root..."); 00551 if (NutRegisterFtpRoot(FSDEV_NAME ":")) { 00552 puts("failed"); 00553 for (;;); 00554 } 00555 puts("OK"); 00556 00557 /* Start two additional server threads. */ 00558 NutThreadCreate("ftpd0", FtpThread, 0, 1640); 00559 NutThreadCreate("ftpd1", FtpThread, 0, 1640); 00560 00561 /* Main server thread. */ 00562 for (;;) { 00563 #ifdef MY_WINSNAME 00564 NutWinsNameQuery(MY_WINSNAME, confnet.cdn_ip_addr); 00565 #endif 00566 FtpService(); 00567 } 00568 return 0; 00569 }