diff options
author | patacongo <patacongo@42af7a65-404d-4744-a932-0658087f49c3> | 2012-09-17 23:02:58 +0000 |
---|---|---|
committer | patacongo <patacongo@42af7a65-404d-4744-a932-0658087f49c3> | 2012-09-17 23:02:58 +0000 |
commit | 68e8befbc94818cc60bbfd4fb3f8f556e76ecba2 (patch) | |
tree | 73190e5163186ab1028a6b26ef5b3794bc6910ba | |
parent | 14f445102e0b861845ccd53a5d6777a25bc75c7e (diff) | |
download | nuttx-68e8befbc94818cc60bbfd4fb3f8f556e76ecba2.tar.gz nuttx-68e8befbc94818cc60bbfd4fb3f8f556e76ecba2.tar.bz2 nuttx-68e8befbc94818cc60bbfd4fb3f8f556e76ecba2.zip |
Fix ENC28J60 Tx transmit (still a receive problem); Add HTTP 408 logic from Kate
git-svn-id: svn://svn.code.sf.net/p/nuttx/code/trunk@5158 42af7a65-404d-4744-a932-0658087f49c3
-rw-r--r-- | apps/ChangeLog.txt | 7 | ||||
-rw-r--r-- | apps/netutils/webserver/Kconfig | 18 | ||||
-rw-r--r-- | apps/netutils/webserver/httpd.c | 68 | ||||
-rw-r--r-- | nuttx/arch/arm/src/stm32/stm32_i2c.c | 6 | ||||
-rw-r--r-- | nuttx/drivers/net/Kconfig | 9 | ||||
-rw-r--r-- | nuttx/drivers/net/enc28j60.c | 96 | ||||
-rw-r--r-- | nuttx/lib/misc/lib_sendfile.c | 2 |
7 files changed, 177 insertions, 29 deletions
diff --git a/apps/ChangeLog.txt b/apps/ChangeLog.txt index 070a78430..e09809915 100644 --- a/apps/ChangeLog.txt +++ b/apps/ChangeLog.txt @@ -332,6 +332,7 @@ * apps/netutils/uip_listenon.c: Logic in uip_server.c that creates the listening socket was moved to this new file to support re-use. Contributed by Kate. - * apps/netutils/webserver/httpd.c: The option CONFIG_NETUTILS_HTTPD_SINGLETHREAD - can now be used to limit the server to a single thread. From Kate. - + * apps/netutils/webserver/httpd.c: The option CONFIG_NETUTILS_HTTPD_SINGLECONNECT + can now be used to limit the server to a single thread. Option + CONFIG_NETUTILS_HTTPD_TIMEOUT can be used to generate HTTP 408 errors. + Both from Kate. diff --git a/apps/netutils/webserver/Kconfig b/apps/netutils/webserver/Kconfig index e64fcdb73..b4c76a33f 100644 --- a/apps/netutils/webserver/Kconfig +++ b/apps/netutils/webserver/Kconfig @@ -13,8 +13,8 @@ config NETUTILS_WEBSERVER if NETUTILS_WEBSERVER -config NETUTILS_HTTPD_SINGLETHREAD - bool "Single Threded" +config NETUTILS_HTTPD_SINGLECONNECT + bool "Single Connection" default n if !DISABLE_PTHREAD default y if DISABLE_PTHREAD ---help--- @@ -22,9 +22,9 @@ config NETUTILS_HTTPD_SINGLETHREAD for each connection. This can, however, use a lot of stack space if there are many connections and that can be a problem is RAM is limited. If this option is selected, then a single thread will - service all HTTP requests. TCP_BACKLOG would be a good idea - in this case. - + service all HTTP requests and, in this case, only a single connection + at a time is supported at a time. + config NETUTILS_HTTPD_SCRIPT_DISABLE bool "Disable %! scripting" default y if NETUTILS_HTTPD_SENDFILE @@ -65,6 +65,14 @@ config NETUTILS_HTTPD_SERVERHEADER_DISABLE ---help--- This option, if selected, will elide the Server\: header +config NETUTILS_HTTPD_TIMEOUT + int "Receive Timeout (sec)" + default 0 + ---help--- + Receive timeout setting (in seconds). A timeout value of zero + disables the timeout. An HTTP 408 error is generated if the timeout + expires. + choice prompt "File Transfer Method" default NETUTILS_HTTPD_CLASSIC diff --git a/apps/netutils/webserver/httpd.c b/apps/netutils/webserver/httpd.c index bb70e34a1..9d78a38ca 100644 --- a/apps/netutils/webserver/httpd.c +++ b/apps/netutils/webserver/httpd.c @@ -57,7 +57,7 @@ #include <errno.h> #include <debug.h> -#ifndef CONFIG_NETUTILS_HTTPD_SINGLETHREAD +#ifndef CONFIG_NETUTILS_HTTPD_SINGLECONNECT # include <pthread.h> #endif @@ -92,6 +92,14 @@ # define CONFIG_NETUTILS_HTTPD_PATH "/mnt" #endif +/* The correct way to disable receive timeout errors is by setting the + * timeout to zero. + */ + +#ifndef CONFIG_NETUTILS_HTTPD_TIMEOUT +# define CONFIG_NETUTILS_HTTPD_TIMEOUT 0 +#endif + /**************************************************************************** * Private Data ****************************************************************************/ @@ -116,6 +124,9 @@ static const char g_httpextensionjpg[] = ".jpg"; static const char g_httpextensionjs[] = ".js"; static const char g_http404path[] = "/404.html"; +#if CONFIG_NETUTILS_HTTPD_TIMEOUT > 0 +static const char g_http408path[] = "/408.html"; +#endif #ifndef CONFIG_NETUTILS_HTTPD_SCRIPT_DISABLE static const char g_httpindexpath[] = "/index.shtml"; #else @@ -138,6 +149,15 @@ static const char g_httpheader404[] = #endif "Connection: close\r\n"; +#if CONFIG_NETUTILS_HTTPD_TIMEOUT > 0 +static const char g_httpheader408[] = + "HTTP/1.0 408 Request timed out\r\n" +#ifndef CONFIG_NETUTILS_HTTPD_SERVERHEADER_DISABLE + "Server: uIP/1.0 http://www.sics.se/~adam/uip/\r\n" +#endif + "Connection: close\r\n"; +#endif + /**************************************************************************** * Private Functions ****************************************************************************/ @@ -507,6 +527,28 @@ static inline int httpd_cmd(struct httpd_state *pstate) /* Get the next HTTP command. We will handle only GET */ recvlen = recv(pstate->ht_sockfd, pstate->ht_buffer, HTTPD_IOBUFFER_SIZE, 0); +#if CONFIG_NETUTILS_HTTPD_TIMEOUT > 0 + if (recvlen < 0 && errno == EWOULDBLOCK) + { + ndbg("[%d] recv timeout\n"); + strncpy(pstate->ht_filename, g_httpindexpath, strlen(g_httpindexpath)); + + memcpy(pstate->ht_filename, g_http408path, strlen(g_http408path)); + if (httpd_open(g_http408path, &pstate->ht_file) != OK) + { + return ERROR; + } + + if (send_headers(pstate, g_httpheader408, strlen(g_httpheader408)) == OK) + { +#ifdef CONFIG_NETUTILS_HTTPD_SENDFILE + return httpd_sendfile_send(pstate->ht_sockfd, &pstate->ht_file); +#else + return httpd_addchunk(pstate, pstate->ht_file.data, pstate->ht_file.len); +#endif + } + } +#endif if (recvlen < 0) { ndbg("[%d] recv failed: %d\n", pstate->ht_sockfd, errno); @@ -598,7 +640,7 @@ static void *httpd_handler(void *arg) return NULL; } -#ifdef CONFIG_NETUTILS_HTTPD_SINGLETHREAD +#ifdef CONFIG_NETUTILS_HTTPD_SINGLECONNECT static void single_server(uint16_t portno, pthread_startroutine_t handler, int stacksize) { struct sockaddr_in myaddr; @@ -608,11 +650,14 @@ static void single_server(uint16_t portno, pthread_startroutine_t handler, int s #ifdef CONFIG_NET_HAVE_SOLINGER struct linger ling; #endif +#if CONFIG_NETUTILS_HTTPD_TIMEOUT > 0 + struct timeval tv; +#endif listensd = uip_listenon(portno); if (listensd < 0) { - return ERROR; + return; } /* Begin serving connections */ @@ -643,12 +688,25 @@ static void single_server(uint16_t portno, pthread_startroutine_t handler, int s } #endif +#if CONFIG_NETUTILS_HTTPD_TIMEOUT > 0 + /* Set up a receive timeout */ + + tv.tv_sec = CONFIG_NETUTILS_HTTPD_TIMEOUT; + tv.tv_usec = 0; + if (setsockopt(acceptsd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(struct timeval)) < 0) + { + close(acceptsd); + ndbg("setsockopt SO_RCVTIMEO failure: %d\n", errno); + break;; + } +#endif + /* Handle the request. This blocks until complete. */ (void) httpd_handler((void*)acceptsd); } - return ERROR; + return; } #endif @@ -668,7 +726,7 @@ int httpd_listen(void) { /* Execute httpd_handler on each connection to port 80 */ -#ifdef CONFIG_NETUTILS_HTTPD_SINGLETHREAD +#ifdef CONFIG_NETUTILS_HTTPD_SINGLECONNECT single_server(HTONS(80), httpd_handler, CONFIG_NETUTILS_HTTPDSTACKSIZE); #else uip_server(HTONS(80), httpd_handler, CONFIG_NETUTILS_HTTPDSTACKSIZE); diff --git a/nuttx/arch/arm/src/stm32/stm32_i2c.c b/nuttx/arch/arm/src/stm32/stm32_i2c.c index bd3031b2d..2d1c365cd 100644 --- a/nuttx/arch/arm/src/stm32/stm32_i2c.c +++ b/nuttx/arch/arm/src/stm32/stm32_i2c.c @@ -116,8 +116,10 @@ /* Interrupt wait time timeout in system timer ticks */ -#define CONFIG_STM32_I2CTIMEOTICKS \ - (SEC2TICK(CONFIG_STM32_I2CTIMEOSEC) + MSEC2TICK(CONFIG_STM32_I2CTIMEOMS)) +#ifndef CONFIG_STM32_I2CTIMEOTICKS +# define CONFIG_STM32_I2CTIMEOTICKS \ + (SEC2TICK(CONFIG_STM32_I2CTIMEOSEC) + MSEC2TICK(CONFIG_STM32_I2CTIMEOMS)) +#endif #ifndef CONFIG_STM32_I2C_DYNTIMEO_STARTSTOP # define CONFIG_STM32_I2C_DYNTIMEO_STARTSTOP TICK2USEC(CONFIG_STM32_I2CTIMEOTICKS) diff --git a/nuttx/drivers/net/Kconfig b/nuttx/drivers/net/Kconfig index a42d35fea..d8878ecaf 100644 --- a/nuttx/drivers/net/Kconfig +++ b/nuttx/drivers/net/Kconfig @@ -70,8 +70,15 @@ config ENC28J60_DUMPPACKET If selected, the ENC28J60 driver will dump the contents of each packet to the console. +config ENC28J60_REGDEBUG + bool "Register-Level Debug" + default n + depends on DEBUG && DEBUG_NET + ---help--- + Enable very low-level register access debug. Depends on DEBUG and DEBUG_NET. + endif - + config NET_E1000 bool "E1000 support" default n diff --git a/nuttx/drivers/net/enc28j60.c b/nuttx/drivers/net/enc28j60.c index bb79910b3..bf6d89537 100644 --- a/nuttx/drivers/net/enc28j60.c +++ b/nuttx/drivers/net/enc28j60.c @@ -128,6 +128,12 @@ # warrning "CONFIG_NET_NOINTS should be set" #endif +/* Low-level register debug */ + +#if !defined(CONFIG_DEBUG) || !defined(CONFIG_DEBUG_NET) +# undef CONFIG_ENC28J60_REGDEBUG +#endif + /* Timing *******************************************************************/ /* TX poll deley = 1 seconds. CLK_TCK is the number of clock ticks per second */ @@ -169,6 +175,20 @@ #define BUF ((struct uip_eth_hdr *)priv->dev.d_buf) +/* Debug ********************************************************************/ + +#ifdef CONFIG_ENC28J60_REGDEBUG +# define enc_wrdump(a,v) lib_lowprintf("ENC28J60: %02x<-%02x\n", a, v); +# define enc_rddump(a,v) lib_lowprintf("ENC28J60: %02x->%02x\n", a, v); +# define enc_cmddump(c) lib_lowprintf("ENC28J60: CMD: %02x\n", c); +# define enc_bmdump(c,b,s) lib_lowprintf("ENC28J60: CMD: %02x buffer: %p length: %d\n", c,b,s); +#else +# define enc_wrdump(a,v) +# define enc_rddump(a,v) +# define enc_cmddump(c) +# define enc_bmdump(c,b,s) +#endif + /**************************************************************************** * Private Types ****************************************************************************/ @@ -264,7 +284,7 @@ static int enc_waitbreg(FAR struct enc_driver_s *priv, uint8_t ctrlreg, static void enc_rdbuffer(FAR struct enc_driver_s *priv, FAR uint8_t *buffer, size_t buflen); -static void enc_wrbuffer(FAR struct enc_driver_s *priv, +static inline void enc_wrbuffer(FAR struct enc_driver_s *priv, FAR const uint8_t *buffer, size_t buflen); /* PHY register access */ @@ -498,6 +518,8 @@ static uint8_t enc_rdgreg2(FAR struct enc_driver_s *priv, uint8_t cmd) /* De-select ENC28J60 chip */ enc_deselect(priv); + + enc_rddump(cmd, rddata); return rddata; } @@ -539,6 +561,7 @@ static void enc_wrgreg2(FAR struct enc_driver_s *priv, uint8_t cmd, /* De-select ENC28J60 chip. */ enc_deselect(priv); + enc_wrdump(cmd, wrdata); } /**************************************************************************** @@ -592,6 +615,7 @@ static inline void enc_src(FAR struct enc_driver_s *priv) /* De-select ENC28J60 chip. */ enc_deselect(priv); + enc_cmddump(ENC_SRC); } /**************************************************************************** @@ -688,6 +712,7 @@ static uint8_t enc_rdbreg(FAR struct enc_driver_s *priv, uint8_t ctrlreg) /* De-select ENC28J60 chip */ enc_deselect(priv); + enc_rddump(ENC_RCR | GETADDR(ctrlreg), rddata); return rddata; } @@ -734,6 +759,7 @@ static void enc_wrbreg(FAR struct enc_driver_s *priv, uint8_t ctrlreg, /* De-select ENC28J60 chip. */ enc_deselect(priv); + enc_wrdump(ENC_WCR | GETADDR(ctrlreg), wrdata); } /**************************************************************************** @@ -816,6 +842,7 @@ static void enc_rdbuffer(FAR struct enc_driver_s *priv, FAR uint8_t *buffer, /* De-select ENC28J60 chip. */ enc_deselect(priv); + enc_bmdump(ENC_WBM, buffer, buflen); } /**************************************************************************** @@ -837,26 +864,68 @@ static void enc_rdbuffer(FAR struct enc_driver_s *priv, FAR uint8_t *buffer, * ****************************************************************************/ -static void enc_wrbuffer(FAR struct enc_driver_s *priv, - FAR const uint8_t *buffer, size_t buflen) +static inline void enc_wrbuffer(FAR struct enc_driver_s *priv, + FAR const uint8_t *buffer, size_t buflen) { DEBUGASSERT(priv && priv->spi); - /* Select ENC28J60 chip */ + /* Select ENC28J60 chip + * + * "The WBM command is started by lowering the CS pin. ..." + */ enc_select(priv); - /* Send the write buffer memory command (ignoring the response) */ + /* Send the write buffer memory command (ignoring the response) + * + * "...The [3-bit]WBM opcode should then be sent to the ENC28J60, + * followed by the 5-bit constant, 1Ah." + */ (void)SPI_SEND(priv->spi, ENC_WBM); - /* Then send the buffer */ + /* "...the ENC28J60 requires a single per packet control byte to + * precede the packet for transmission." + * + * POVERRIDE: Per Packet Override bit (Not set): + * 1 = The values of PCRCEN, PPADEN and PHUGEEN will override the + * configuration defined by MACON3. + * 0 = The values in MACON3 will be used to determine how the packet + * will be transmitted + * PCRCEN: Per Packet CRC Enable bit (Set, but won't be used because + * POVERRIDE is zero). + * PPADEN: Per Packet Padding Enable bit (Set, but won't be used because + * POVERRIDE is zero). + * PHUGEEN: Per Packet Huge Frame Enable bit (Set, but won't be used + * because POVERRIDE is zero). + */ + + (void)SPI_SEND(priv->spi, + (PKTCTRL_PCRCEN | PKTCTRL_PPADEN | PKTCTRL_PHUGEEN)); + + /* Then send the buffer + * + * "... After the WBM command and constant are sent, the data to + * be stored in the memory pointed to by EWRPT should be shifted + * out MSb first to the ENC28J60. After 8 data bits are received, + * the Write Pointer will automatically increment if AUTOINC is + * set. The host controller can continue to provide clocks on the + * SCK pin and send data on the SI pin, without raising CS, to + * keep writing to the memory. In this manner, with AUTOINC + * enabled, it is possible to continuously write sequential bytes + * to the buffer memory without any extra SPI command + * overhead. + */ SPI_SNDBLOCK(priv->spi, buffer, buflen); - /* De-select ENC28J60 chip. */ + /* De-select ENC28J60 chip + * + * "The WBM command is terminated by bringing up the CS pin. ..." + */ enc_deselect(priv); + enc_bmdump(ENC_WBM, buffer, buflen); } /**************************************************************************** @@ -984,6 +1053,11 @@ static int enc_transmit(FAR struct enc_driver_s *priv) enc_dumppacket("Transmit Packet", priv->dev.d_buf, priv->dev.d_len); + /* Set transmit buffer start (is this necessary?). */ + + enc_wrbreg(priv, ENC_ETXSTL, PKTMEM_TX_START & 0xff); + enc_wrbreg(priv, ENC_ETXSTH, PKTMEM_TX_START >> 8); + /* Reset the write pointer to start of transmit buffer */ enc_wrbreg(priv, ENC_EWRPTL, PKTMEM_TX_START & 0xff); @@ -995,11 +1069,9 @@ static int enc_transmit(FAR struct enc_driver_s *priv) enc_wrbreg(priv, ENC_ETXNDL, txend & 0xff); enc_wrbreg(priv, ENC_ETXNDH, txend >> 8); - /* Write the per-packet control byte into the transmit buffer */ - - enc_wrgreg(priv, ENC_WBM, 0x00); - - /* Copy the packet itself into the transmit buffer */ + /* Send the WBM command and copy the packet itself into the transmit + * buffer at the position of the EWRPT register. + */ enc_wrbuffer(priv, priv->dev.d_buf, priv->dev.d_len); diff --git a/nuttx/lib/misc/lib_sendfile.c b/nuttx/lib/misc/lib_sendfile.c index e4b53d8c8..a82eb325e 100644 --- a/nuttx/lib/misc/lib_sendfile.c +++ b/nuttx/lib/misc/lib_sendfile.c @@ -294,4 +294,4 @@ ssize_t sendfile(int outfd, int infd, off_t *offset, size_t count) return ntransferred; } -#endif /* CONFIG_NSOCKET_DESCRIPTORS > 0 || CONFIG_NFILE_DESCRIPTORS > 0 */
\ No newline at end of file +#endif /* CONFIG_NSOCKET_DESCRIPTORS > 0 || CONFIG_NFILE_DESCRIPTORS > 0 */ |