summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--apps/ChangeLog.txt7
-rw-r--r--apps/netutils/webserver/Kconfig18
-rw-r--r--apps/netutils/webserver/httpd.c68
-rw-r--r--nuttx/arch/arm/src/stm32/stm32_i2c.c6
-rw-r--r--nuttx/drivers/net/Kconfig9
-rw-r--r--nuttx/drivers/net/enc28j60.c96
-rw-r--r--nuttx/lib/misc/lib_sendfile.c2
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 */