From ab0053e1713fae08821e96b89759c8d5b0b0cdf0 Mon Sep 17 00:00:00 2001 From: patacongo Date: Wed, 16 Mar 2011 01:37:40 +0000 Subject: [PATCH] Fix SLIP bug git-svn-id: https://nuttx.svn.sourceforge.net/svnroot/nuttx/trunk@3385 7fd9a85b-ad96-42d3-883c-3090e2eb8679 --- .../olimex-lpc1766stk/slip-httpd/defconfig | 4 +- nuttx/drivers/net/slip.c | 265 +++++++----------- nuttx/include/net/uip/uip-tcp.h | 13 +- 3 files changed, 115 insertions(+), 167 deletions(-) diff --git a/nuttx/configs/olimex-lpc1766stk/slip-httpd/defconfig b/nuttx/configs/olimex-lpc1766stk/slip-httpd/defconfig index e0b8278c1..dced6af18 100755 --- a/nuttx/configs/olimex-lpc1766stk/slip-httpd/defconfig +++ b/nuttx/configs/olimex-lpc1766stk/slip-httpd/defconfig @@ -346,9 +346,9 @@ CONFIG_SEM_NNESTPRIO=0 CONFIG_FDCLONE_DISABLE=n CONFIG_FDCLONE_STDIO=n CONFIG_SDCLONE_DISABLE=n -CONFIG_SCHED_WORKQUEUE=y +CONFIG_SCHED_WORKQUEUE=n CONFIG_SCHED_WORKPRIORITY=50 -CONFIG_SCHED_WORKPERIOD=(100*1000) +CONFIG_SCHED_WORKPERIOD=(50*1000) CONFIG_SCHED_WORKSTACKSIZE=2048 CONFIG_SIG_SIGWORK=4 diff --git a/nuttx/drivers/net/slip.c b/nuttx/drivers/net/slip.c index 461a9035a..94baab575 100644 --- a/nuttx/drivers/net/slip.c +++ b/nuttx/drivers/net/slip.c @@ -51,13 +51,11 @@ #include #include #include -#include #include #include #include #include -#include #include #include @@ -79,10 +77,6 @@ # error "UIP_LLH_LEN must be set to zero" #endif -#ifndef CONFIG_SCHED_WORKQUEUE -# warning "CONFIG_SCHED_WORKQUEUE must be set" -#endif - #ifndef CONFIG_NET_NOINTS # warning "CONFIG_NET_NOINTS must be set" #endif @@ -109,6 +103,14 @@ # warning "CONFIG_NET_BUFSIZE == 296 is optimal" #endif +/* CONFIG_SLIP_NINTERFACES determines the number of physical interfaces + * that will be supported. + */ + +#ifndef CONFIG_SLIP_NINTERFACES +# define CONFIG_SLIP_NINTERFACES 1 +#endif + /* SLIP special character codes *******************************************/ #define SLIP_END 0300 /* Indicates end of packet */ @@ -118,23 +120,11 @@ /* General driver definitions **********************************************/ -/* CONFIG_SLIP_NINTERFACES determines the number of physical interfaces - * that will be supported. - */ +/* TX poll delay = 1 second = 1000000 microseconds. */ -#ifndef CONFIG_SLIP_NINTERFACES -# define CONFIG_SLIP_NINTERFACES 1 -#endif - -/* TX poll deley = 1 seconds. CLK_TCK is the number of clock ticks per second */ - -#define SLIP_WDDELAY (1*CLK_TCK) +#define SLIP_WDDELAY (1*1000000) #define SLIP_POLLHSEC (1*2) -/* TX timeout = 1 minute */ - -#define SLIP_TXTIMEOUT (60*CLK_TCK) - /* Statistics helper */ #ifdef CONFIG_NET_STATISTICS @@ -163,13 +153,12 @@ struct slip_statistics_s struct slip_driver_s { - bool bifup; /* true:ifup false:ifdown */ - WDOG_ID txpoll; /* TX poll timer */ - FILE *stream; /* The contained serial stream */ - pid_t pid; /* Receiver thread ID */ + volatile bool bifup; /* true:ifup false:ifdown */ + int fd; /* TTY file descriptor */ + pid_t rxpid; /* Receiver thread ID */ + pid_t txpid; /* Transmitter thread ID */ sem_t waitsem; /* Mutually exclusive access to uIP */ uint16_t rxlen; /* The number of bytes in rxbuf */ - struct work_s txwork; /* Scheduled TX work */ /* Driver statistics */ @@ -206,7 +195,7 @@ static void slip_write(FAR struct slip_driver_s *priv, const uint8_t *buffer, in static void slip_putc(FAR struct slip_driver_s *priv, int ch); static int slip_transmit(FAR struct slip_driver_s *priv); static int slip_uiptxpoll(struct uip_driver_s *dev); -static void slip_txworker(FAR void *arg); +static void slip_txtask(int argc, char *argv[]); /* Packet receiver task */ @@ -214,10 +203,6 @@ static int slip_getc(FAR struct slip_driver_s *priv); static inline void slip_receive(FAR struct slip_driver_s *priv); static int slip_rxtask(int argc, char *argv[]); -/* Watchdog timer expirations */ - -static void slip_polltimer(int argc, uint32_t arg, ...); - /* NuttX callback functions */ static int slip_ifup(struct uip_driver_s *dev); @@ -268,15 +253,11 @@ static void slip_semtake(FAR struct slip_driver_s *priv) static inline void slip_write(FAR struct slip_driver_s *priv, const uint8_t *buffer, int len) { - int remaining = len; + /* Handle the case where the write is awakened by a signal */ - /* Signals will be received on the worker thread. In this case, fwrite - * may return with fewer then len bytes written. - */ - - while (remaining > 0) + while (write(priv->fd, buffer, len) < 0) { - remaining -= fwrite(&buffer[len - remaining], 1, remaining, priv->stream); + DEBUGASSERT(errno == EINTR); } } @@ -294,17 +275,8 @@ static inline void slip_write(FAR struct slip_driver_s *priv, static inline void slip_putc(FAR struct slip_driver_s *priv, int ch) { - int ret; - - /* putc will return ch unless an error occurs (included being awakened - * a signal on the worker thread). Then it will return EOF. - */ - - do - { - ret = putc(ch, priv->stream); - } - while (ret != ch); + uint8_t buffer = (uint8_t)ch; + slip_write(priv, &buffer, 1); } /**************************************************************************** @@ -361,7 +333,7 @@ static int slip_transmit(FAR struct slip_driver_s *priv) esc = SLIP_ESC_END; goto escape; - /* if it's the same code as an ESC character, we send a special two + /* If it's the same code as an ESC character, we send a special two * character code so as not to make the receiver think we sent an * ESC */ @@ -414,10 +386,6 @@ static int slip_transmit(FAR struct slip_driver_s *priv) /* And send the END token */ slip_putc(priv, SLIP_END); - - /* Finally, flush everything to the host */ - - fflush(priv->stream); return OK; } @@ -464,10 +432,10 @@ static int slip_uiptxpoll(struct uip_driver_s *dev) } /**************************************************************************** - * Function: slip_txworker + * Function: slip_txtask * * Description: - * Polling and transmission is performed on the worker thread. + * Polling and transmission is performed on tx thread. * * Parameters: * arg - Reference to the NuttX driver state structure @@ -477,26 +445,53 @@ static int slip_uiptxpoll(struct uip_driver_s *dev) * ****************************************************************************/ -static void slip_txworker(FAR void *arg) +static void slip_txtask(int argc, char *argv[]) { - FAR struct slip_driver_s *priv = (FAR struct slip_driver_s *)arg; + FAR struct slip_driver_s *priv; + unsigned int index = *(argv[1]) - '0'; uip_lock_t flags; - DEBUGASSERT(priv != NULL); + ndbg("index: %d\n", index); + DEBUGASSERT(index < CONFIG_SLIP_NINTERFACES); - /* Get exclusive access to uIP (if it it is already being used slip_rxtask, - * then we have to wait). + /* Get our private data structure instance and wake up the waiting + * initialization logic. */ - slip_semtake(priv); - - /* Poll uIP for new XMIT data. */ - - flags = uip_lock(); - priv->dev.d_buf = priv->txbuf; - (void)uip_timer(&priv->dev, slip_uiptxpoll, SLIP_POLLHSEC); - uip_unlock(flags); + priv = &g_slip[index]; slip_semgive(priv); + + /* Loop forever */ + + for (;;) + { + /* Wait for the timeout to expire (or until we are signaled by by */ + + usleep(SLIP_WDDELAY); + + /* Is the interface up? */ + + if (priv->bifup) + { + /* Get exclusive access to uIP (if it it is already being used + * slip_rxtask, then we have to wait). + */ + + slip_semtake(priv); + + /* Poll uIP for new XMIT data. BUG: We really need to calculate + * the number of hsecs! When we are awakened by slip_txavail, the + * number will be smaller; when we have to wait for the semaphore + * (above), it may be larger. + */ + + flags = uip_lock(); + priv->dev.d_buf = priv->txbuf; + (void)uip_timer(&priv->dev, slip_uiptxpoll, SLIP_POLLHSEC); + uip_unlock(flags); + slip_semgive(priv); + } + } } /**************************************************************************** @@ -515,19 +510,14 @@ static void slip_txworker(FAR void *arg) static inline int slip_getc(FAR struct slip_driver_s *priv) { - int ret; + uint8_t ch; - /* It is not expected that getc will be awakened by signals on the - * slip_rxtask thread. But just in case... - */ - - do + while (read(priv->fd, &ch, 1) < 0) { - ret = getc(priv->stream); + DEBUGASSERT(errno == EINTR); } - while (ret == EOF); - return ret; + return (int)ch; } /**************************************************************************** @@ -655,14 +645,11 @@ static int slip_rxtask(int argc, char *argv[]) DEBUGASSERT(index < CONFIG_SLIP_NINTERFACES); /* Get our private data structure instance and wake up the waiting - * initialization logic. The first slip_semgive() wakes up the wainter - * initializer; the second raises the count to 1 so that the semaphore - * can now be used as a mutex for mutually exclusive access to uIP. + * initialization logic. */ priv = &g_slip[index]; slip_semgive(priv); - slip_semgive(priv); /* Loop forever */ @@ -673,6 +660,13 @@ static int slip_rxtask(int argc, char *argv[]) nvdbg("Waiting...\n"); ch = slip_getc(priv); + /* Ignore any input that we receive before the interface is up. */ + + if (!priv->bifup) + { + continue; + } + /* We have something... * * END characters may appear at packet boundaries BEFORE as well as @@ -741,47 +735,6 @@ static int slip_rxtask(int argc, char *argv[]) return OK; } -/**************************************************************************** - * Function: slip_polltimer - * - * Description: - * Periodic timer handler. Called from the timer interrupt handler. - * - * Parameters: - * argc - The number of available arguments - * arg - The first argument - * - * Returned Value: - * None - * - * Assumptions: - * Global interrupts are disabled by the watchdog logic. - * - ****************************************************************************/ - -static void slip_polltimer(int argc, uint32_t arg, ...) -{ - FAR struct slip_driver_s *priv = (FAR struct slip_driver_s *)arg; - int ret; - - /* Perform the poll on the worker thread (if the work structure is available). - * We should not access standard I/O from an interrupt handler. - */ - - if (priv->txwork.worker == NULL) - { - ret = work_queue(&priv->txwork, slip_txworker, priv, 0); - if (ret != OK) - { - ndbg("Failed to schedule work: %d\n", ret); - } - } - - /* Setup the watchdog poll timer again */ - - (void)wd_start(priv->txpoll, SLIP_WDDELAY, slip_polltimer, 1, arg); -} - /**************************************************************************** * Function: slip_ifup * @@ -807,10 +760,6 @@ static int slip_ifup(struct uip_driver_s *dev) dev->d_ipaddr & 0xff, (dev->d_ipaddr >> 8) & 0xff, (dev->d_ipaddr >> 16) & 0xff, dev->d_ipaddr >> 24 ); - /* Set and activate a timer process */ - - (void)wd_start(priv->txpoll, SLIP_WDDELAY, slip_polltimer, 1, (uint32_t)priv); - /* Mark the interface up */ priv->bifup = true; @@ -836,20 +785,10 @@ static int slip_ifup(struct uip_driver_s *dev) static int slip_ifdown(struct uip_driver_s *dev) { FAR struct slip_driver_s *priv = (FAR struct slip_driver_s *)dev->d_private; - irqstate_t flags; - - /* Disable the interrupts */ - - flags = irqsave(); - - /* Cancel the TX poll timer and TX timeout timers */ - - wd_cancel(priv->txpoll); /* Mark the device "down" */ priv->bifup = false; - irqrestore(flags); return OK; } @@ -872,26 +811,17 @@ static int slip_ifdown(struct uip_driver_s *dev) static int slip_txavail(struct uip_driver_s *dev) { FAR struct slip_driver_s *priv = (FAR struct slip_driver_s *)dev->d_private; - int ret = OK; - /* Ignore the notification if the interface is not yet up OR if the worker - * action is already queued. - */ + /* Ignore the notification if the interface is not yet up */ - if (priv->bifup && priv->txwork.worker == NULL) + if (priv->bifup) { - /* Perform a poll on the worker thread. We cannot access standard I/O - * from an interrupt handler. - */ + /* Wake up the TX polling thread */ - ret = work_queue(&priv->txwork, slip_txworker, priv, 0); - if (ret != OK) - { - ndbg("Failed to schedule work: %d\n", ret); - } + kill(priv->txpid, SIGALRM); } - return ret; + return OK; } /**************************************************************************** @@ -999,10 +929,10 @@ int slip_initialize(int intf, const char *devname) /* Open the device */ - priv->stream = fopen(devname, "rw"); - if (priv->stream == NULL) + priv->fd = open(devname, O_RDWR, 0666); + if (priv->fd < 0) { - ndbg("ERROR: Failed to fdopen %s: %d\n", devname, errno); + ndbg("ERROR: Failed to open %s: %d\n", devname, errno); return -errno; } @@ -1023,13 +953,13 @@ int slip_initialize(int intf, const char *devname) argv[1] = NULL; #ifndef CONFIG_CUSTOM_STACK - priv->pid = task_create("usbhost", CONFIG_SLIP_DEFPRIO, + priv->rxpid = task_create("rxslip", CONFIG_SLIP_DEFPRIO, CONFIG_SLIP_STACKSIZE, (main_t)slip_rxtask, argv); #else - priv->pid = task_create("usbhost", CONFIG_SLIP_DEFPRIO, + priv->rxpid = task_create("rxslip", CONFIG_SLIP_DEFPRIO, (main_t)slip_rxtask, argv); #endif - if (priv->pid < 0) + if (priv->rxpid < 0) { ndbg("ERROR: Failed to start receiver task\n"); return -errno; @@ -1039,9 +969,28 @@ int slip_initialize(int intf, const char *devname) slip_semtake(priv); - /* Create a watchdog for timing polling for and timing of transmisstions */ + /* Start the SLIP transmitter task */ - priv->txpoll = wd_create(); /* Create periodic poll timer */ +#ifndef CONFIG_CUSTOM_STACK + priv->txpid = task_create("txslip", CONFIG_SLIP_DEFPRIO, + CONFIG_SLIP_STACKSIZE, (main_t)slip_txtask, argv); +#else + priv->txpid = task_create("txslip", CONFIG_SLIP_DEFPRIO, + (main_t)slip_txtask, argv); +#endif + if (priv->txpid < 0) + { + ndbg("ERROR: Failed to start receiver task\n"); + return -errno; + } + + /* Wait and make sure that the transmit task is started. */ + + slip_semtake(priv); + + /* Bump the semaphore count so that it can now be used as a mutex */ + + slip_semgive(priv); /* Register the device with the OS so that socket IOCTLs can be performed */ diff --git a/nuttx/include/net/uip/uip-tcp.h b/nuttx/include/net/uip/uip-tcp.h index ee525c854..2fcf7390c 100644 --- a/nuttx/include/net/uip/uip-tcp.h +++ b/nuttx/include/net/uip/uip-tcp.h @@ -430,8 +430,8 @@ extern int uip_backlogdelete(FAR struct uip_conn *conn, FAR struct uip_conn *blc /* Restart the current connection, if is has previously been stopped * with uip_stop(). * - * This function will open the receiver's window again so that we - * start receiving data for the current connection. + * This function will open the receiver's window again so that we start + * receiving data for the current connection. */ #define uip_restart(conn,f) \ @@ -446,13 +446,12 @@ extern int uip_backlogdelete(FAR struct uip_conn *conn, FAR struct uip_conn *blc #define uip_initialmss(conn) ((conn)->initialmss) -/* Get the current maxium segment size that can be sent on the current +/* Get the current maximum segment size that can be sent on the current * connection. * - * The current maxiumum segment size that can be sent on the - * connection is computed from the receiver's window and the MSS of - * the connection (which also is available by calling - * uip_initialmss()). + * The current maxiumum segment size that can be sent on the connection is + * computed from the receiver's window and the MSS of the connection (which + * also is available by calling uip_initialmss()). */ #define uip_mss(conn) ((conn)->mss)