Fix ENC28J60 Tx transmit (still a receive problem); Add HTTP 408 logic from Kate

git-svn-id: http://svn.code.sf.net/p/nuttx/code/trunk@5158 42af7a65-404d-4744-a932-0658087f49c3
This commit is contained in:
patacongo
2012-09-17 23:02:58 +00:00
parent 77b8e554f8
commit c3c602f93e
7 changed files with 177 additions and 29 deletions
+4 -3
View File
@@ -332,6 +332,7 @@
* apps/netutils/uip_listenon.c: Logic in uip_server.c that creates * 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. the listening socket was moved to this new file to support re-use.
Contributed by Kate. Contributed by Kate.
* apps/netutils/webserver/httpd.c: The option CONFIG_NETUTILS_HTTPD_SINGLETHREAD * apps/netutils/webserver/httpd.c: The option CONFIG_NETUTILS_HTTPD_SINGLECONNECT
can now be used to limit the server to a single thread. From Kate. 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.
+12 -4
View File
@@ -13,8 +13,8 @@ config NETUTILS_WEBSERVER
if NETUTILS_WEBSERVER if NETUTILS_WEBSERVER
config NETUTILS_HTTPD_SINGLETHREAD config NETUTILS_HTTPD_SINGLECONNECT
bool "Single Threded" bool "Single Connection"
default n if !DISABLE_PTHREAD default n if !DISABLE_PTHREAD
default y if DISABLE_PTHREAD default y if DISABLE_PTHREAD
---help--- ---help---
@@ -22,8 +22,8 @@ config NETUTILS_HTTPD_SINGLETHREAD
for each connection. This can, however, use a lot of stack space 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 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 limited. If this option is selected, then a single thread will
service all HTTP requests. TCP_BACKLOG would be a good idea service all HTTP requests and, in this case, only a single connection
in this case. at a time is supported at a time.
config NETUTILS_HTTPD_SCRIPT_DISABLE config NETUTILS_HTTPD_SCRIPT_DISABLE
bool "Disable %! scripting" bool "Disable %! scripting"
@@ -65,6 +65,14 @@ config NETUTILS_HTTPD_SERVERHEADER_DISABLE
---help--- ---help---
This option, if selected, will elide the Server\: header 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 choice
prompt "File Transfer Method" prompt "File Transfer Method"
default NETUTILS_HTTPD_CLASSIC default NETUTILS_HTTPD_CLASSIC
+63 -5
View File
@@ -57,7 +57,7 @@
#include <errno.h> #include <errno.h>
#include <debug.h> #include <debug.h>
#ifndef CONFIG_NETUTILS_HTTPD_SINGLETHREAD #ifndef CONFIG_NETUTILS_HTTPD_SINGLECONNECT
# include <pthread.h> # include <pthread.h>
#endif #endif
@@ -92,6 +92,14 @@
# define CONFIG_NETUTILS_HTTPD_PATH "/mnt" # define CONFIG_NETUTILS_HTTPD_PATH "/mnt"
#endif #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 * Private Data
****************************************************************************/ ****************************************************************************/
@@ -116,6 +124,9 @@ static const char g_httpextensionjpg[] = ".jpg";
static const char g_httpextensionjs[] = ".js"; static const char g_httpextensionjs[] = ".js";
static const char g_http404path[] = "/404.html"; 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 #ifndef CONFIG_NETUTILS_HTTPD_SCRIPT_DISABLE
static const char g_httpindexpath[] = "/index.shtml"; static const char g_httpindexpath[] = "/index.shtml";
#else #else
@@ -138,6 +149,15 @@ static const char g_httpheader404[] =
#endif #endif
"Connection: close\r\n"; "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 * 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 */ /* Get the next HTTP command. We will handle only GET */
recvlen = recv(pstate->ht_sockfd, pstate->ht_buffer, HTTPD_IOBUFFER_SIZE, 0); 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) if (recvlen < 0)
{ {
ndbg("[%d] recv failed: %d\n", pstate->ht_sockfd, errno); ndbg("[%d] recv failed: %d\n", pstate->ht_sockfd, errno);
@@ -598,7 +640,7 @@ static void *httpd_handler(void *arg)
return NULL; 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) static void single_server(uint16_t portno, pthread_startroutine_t handler, int stacksize)
{ {
struct sockaddr_in myaddr; 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 #ifdef CONFIG_NET_HAVE_SOLINGER
struct linger ling; struct linger ling;
#endif #endif
#if CONFIG_NETUTILS_HTTPD_TIMEOUT > 0
struct timeval tv;
#endif
listensd = uip_listenon(portno); listensd = uip_listenon(portno);
if (listensd < 0) if (listensd < 0)
{ {
return ERROR; return;
} }
/* Begin serving connections */ /* Begin serving connections */
@@ -643,12 +688,25 @@ static void single_server(uint16_t portno, pthread_startroutine_t handler, int s
} }
#endif #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. */ /* Handle the request. This blocks until complete. */
(void) httpd_handler((void*)acceptsd); (void) httpd_handler((void*)acceptsd);
} }
return ERROR; return;
} }
#endif #endif
@@ -668,7 +726,7 @@ int httpd_listen(void)
{ {
/* Execute httpd_handler on each connection to port 80 */ /* 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); single_server(HTONS(80), httpd_handler, CONFIG_NETUTILS_HTTPDSTACKSIZE);
#else #else
uip_server(HTONS(80), httpd_handler, CONFIG_NETUTILS_HTTPDSTACKSIZE); uip_server(HTONS(80), httpd_handler, CONFIG_NETUTILS_HTTPDSTACKSIZE);
+4 -2
View File
@@ -116,8 +116,10 @@
/* Interrupt wait time timeout in system timer ticks */ /* Interrupt wait time timeout in system timer ticks */
#define CONFIG_STM32_I2CTIMEOTICKS \ #ifndef CONFIG_STM32_I2CTIMEOTICKS
(SEC2TICK(CONFIG_STM32_I2CTIMEOSEC) + MSEC2TICK(CONFIG_STM32_I2CTIMEOMS)) # define CONFIG_STM32_I2CTIMEOTICKS \
(SEC2TICK(CONFIG_STM32_I2CTIMEOSEC) + MSEC2TICK(CONFIG_STM32_I2CTIMEOMS))
#endif
#ifndef CONFIG_STM32_I2C_DYNTIMEO_STARTSTOP #ifndef CONFIG_STM32_I2C_DYNTIMEO_STARTSTOP
# define CONFIG_STM32_I2C_DYNTIMEO_STARTSTOP TICK2USEC(CONFIG_STM32_I2CTIMEOTICKS) # define CONFIG_STM32_I2C_DYNTIMEO_STARTSTOP TICK2USEC(CONFIG_STM32_I2CTIMEOTICKS)
+7
View File
@@ -70,6 +70,13 @@ config ENC28J60_DUMPPACKET
If selected, the ENC28J60 driver will dump the contents of each If selected, the ENC28J60 driver will dump the contents of each
packet to the console. 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 endif
config NET_E1000 config NET_E1000
+84 -12
View File
@@ -128,6 +128,12 @@
# warrning "CONFIG_NET_NOINTS should be set" # warrning "CONFIG_NET_NOINTS should be set"
#endif #endif
/* Low-level register debug */
#if !defined(CONFIG_DEBUG) || !defined(CONFIG_DEBUG_NET)
# undef CONFIG_ENC28J60_REGDEBUG
#endif
/* Timing *******************************************************************/ /* Timing *******************************************************************/
/* TX poll deley = 1 seconds. CLK_TCK is the number of clock ticks per second */ /* 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) #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 * 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, static void enc_rdbuffer(FAR struct enc_driver_s *priv, FAR uint8_t *buffer,
size_t buflen); 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); FAR const uint8_t *buffer, size_t buflen);
/* PHY register access */ /* 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 */ /* De-select ENC28J60 chip */
enc_deselect(priv); enc_deselect(priv);
enc_rddump(cmd, rddata);
return rddata; return rddata;
} }
@@ -539,6 +561,7 @@ static void enc_wrgreg2(FAR struct enc_driver_s *priv, uint8_t cmd,
/* De-select ENC28J60 chip. */ /* De-select ENC28J60 chip. */
enc_deselect(priv); 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. */ /* De-select ENC28J60 chip. */
enc_deselect(priv); 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 */ /* De-select ENC28J60 chip */
enc_deselect(priv); enc_deselect(priv);
enc_rddump(ENC_RCR | GETADDR(ctrlreg), rddata);
return rddata; return rddata;
} }
@@ -734,6 +759,7 @@ static void enc_wrbreg(FAR struct enc_driver_s *priv, uint8_t ctrlreg,
/* De-select ENC28J60 chip. */ /* De-select ENC28J60 chip. */
enc_deselect(priv); 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. */ /* De-select ENC28J60 chip. */
enc_deselect(priv); 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, static inline void enc_wrbuffer(FAR struct enc_driver_s *priv,
FAR const uint8_t *buffer, size_t buflen) FAR const uint8_t *buffer, size_t buflen)
{ {
DEBUGASSERT(priv && priv->spi); DEBUGASSERT(priv && priv->spi);
/* Select ENC28J60 chip */ /* Select ENC28J60 chip
*
* "The WBM command is started by lowering the CS pin. ..."
*/
enc_select(priv); 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); (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); 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_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); 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 */ /* Reset the write pointer to start of transmit buffer */
enc_wrbreg(priv, ENC_EWRPTL, PKTMEM_TX_START & 0xff); 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_ETXNDL, txend & 0xff);
enc_wrbreg(priv, ENC_ETXNDH, txend >> 8); enc_wrbreg(priv, ENC_ETXNDH, txend >> 8);
/* Write the per-packet control byte 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_wrgreg(priv, ENC_WBM, 0x00); */
/* Copy the packet itself into the transmit buffer */
enc_wrbuffer(priv, priv->dev.d_buf, priv->dev.d_len); enc_wrbuffer(priv, priv->dev.d_buf, priv->dev.d_len);