Misc slip-related fixes
git-svn-id: svn://svn.code.sf.net/p/nuttx/code/trunk@3383 42af7a65-404d-4744-a932-0658087f49c3
This commit is contained in:
parent
53c68bf74e
commit
cc0aee9d2f
@ -817,8 +817,8 @@ Where <subdir> is one of the following:
|
||||
Add -d to get debug output. This will show the interface name.
|
||||
|
||||
NOTE: The -L option is included to suppress use of hardware flow
|
||||
control. This is necessary because I haven't figure out how to
|
||||
use the UART1 hardwar flow control yet.
|
||||
control. This is necessary because I haven't figured out how to
|
||||
use the UART1 hardware flow control yet.
|
||||
|
||||
NOTE: The Linux slip module hard-codes its MTU size to 296. So you
|
||||
might as well set CONFIG_NET_BUFSIZE to 296 as well.
|
||||
|
@ -346,10 +346,10 @@ CONFIG_SEM_NNESTPRIO=0
|
||||
CONFIG_FDCLONE_DISABLE=n
|
||||
CONFIG_FDCLONE_STDIO=n
|
||||
CONFIG_SDCLONE_DISABLE=n
|
||||
CONFIG_SCHED_WORKQUEUE=n
|
||||
CONFIG_SCHED_WORKQUEUE=y
|
||||
CONFIG_SCHED_WORKPRIORITY=50
|
||||
CONFIG_SCHED_WORKPERIOD=(50*1000)
|
||||
CONFIG_SCHED_WORKSTACKSIZE=1024
|
||||
CONFIG_SCHED_WORKPERIOD=(100*1000)
|
||||
CONFIG_SCHED_WORKSTACKSIZE=2048
|
||||
CONFIG_SIG_SIGWORK=4
|
||||
|
||||
#
|
||||
|
@ -57,6 +57,7 @@
|
||||
|
||||
#include <nuttx/irq.h>
|
||||
#include <nuttx/net.h>
|
||||
#include <nuttx/wqueue.h>
|
||||
|
||||
#include <net/uip/uip.h>
|
||||
#include <net/uip/uip-arch.h>
|
||||
@ -78,6 +79,10 @@
|
||||
# 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_MULTIBUFFER
|
||||
# error "Requires CONFIG_NET_MULTIBUFFER"
|
||||
#endif
|
||||
@ -154,12 +159,13 @@ 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 */
|
||||
sem_t waitsem; /* Only used at start-up */
|
||||
uint16_t rxlen; /* The number of bytes in rxbuf */
|
||||
bool bifup; /* true:ifup false:ifdown */
|
||||
WDOG_ID txpoll; /* TX poll timer */
|
||||
FILE *stream; /* The contained serial stream */
|
||||
pid_t pid; /* Receiver 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 */
|
||||
|
||||
@ -192,15 +198,15 @@ static void slip_semtake(FAR struct slip_driver_s *priv);
|
||||
|
||||
/* Common TX logic */
|
||||
|
||||
static inline void slip_write(FAR struct slip_driver_s *priv,
|
||||
const uint8_t *buffer, int len);
|
||||
static inline 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_write(FAR struct slip_driver_s *priv, const uint8_t *buffer, int len);
|
||||
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);
|
||||
|
||||
/* Packet receiver task */
|
||||
|
||||
static inline int slip_getc(FAR struct slip_driver_s *priv);
|
||||
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[]);
|
||||
|
||||
@ -258,12 +264,16 @@ 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)
|
||||
{
|
||||
#if CONFIG_DEBUG
|
||||
size_t nbytes = fwrite(buffer, 1, len, priv->stream);
|
||||
DEBUGASSERT(nbytes == len);
|
||||
#else
|
||||
(void)fwrite(buffer, 1, len, priv->stream);
|
||||
#endif
|
||||
int remaining = len;
|
||||
|
||||
/* Signals will be received on the worker thread. In this case, fwrite
|
||||
* may return with fewer then len bytes written.
|
||||
*/
|
||||
|
||||
while (remaining > 0)
|
||||
{
|
||||
remaining -= fwrite(&buffer[len - remaining], 1, remaining, priv->stream);
|
||||
}
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
@ -280,12 +290,17 @@ static inline void slip_write(FAR struct slip_driver_s *priv,
|
||||
|
||||
static inline void slip_putc(FAR struct slip_driver_s *priv, int ch)
|
||||
{
|
||||
#if 0 // CONFIG_DEBUG
|
||||
int ret = putc(ch, priv->stream);
|
||||
DEBUGASSERT(ret == ch);
|
||||
#else
|
||||
putc(ch, priv->stream);
|
||||
#endif
|
||||
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);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
@ -301,20 +316,15 @@ static inline void slip_putc(FAR struct slip_driver_s *priv, int ch)
|
||||
* Returned Value:
|
||||
* OK on success; a negated errno on failure
|
||||
*
|
||||
* Assumptions:
|
||||
* May or may not be called from an interrupt handler. In either case,
|
||||
* global interrupts are disabled, either explicitly or indirectly through
|
||||
* interrupt handling logic.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static int slip_transmit(FAR struct slip_driver_s *priv)
|
||||
{
|
||||
uint8_t *src;
|
||||
uint8_t *start;
|
||||
uint8_t esc;
|
||||
int remaining;
|
||||
int len;
|
||||
uint8_t esc;
|
||||
int remaining;
|
||||
int len;
|
||||
|
||||
/* Increment statistics */
|
||||
|
||||
@ -332,6 +342,7 @@ static int slip_transmit(FAR struct slip_driver_s *priv)
|
||||
src = priv->dev.d_buf;
|
||||
remaining = priv->dev.d_len;
|
||||
start = src;
|
||||
len = 0;
|
||||
|
||||
while (remaining-- > 0)
|
||||
{
|
||||
@ -395,11 +406,14 @@ static int slip_transmit(FAR struct slip_driver_s *priv)
|
||||
{
|
||||
slip_write(priv, start, len);
|
||||
}
|
||||
fflush(priv->stream);
|
||||
|
||||
/* And send the END token */
|
||||
|
||||
slip_putc(priv, SLIP_END);
|
||||
|
||||
/* Finally, flush everything to the host */
|
||||
|
||||
fflush(priv->stream);
|
||||
return OK;
|
||||
}
|
||||
|
||||
@ -407,11 +421,11 @@ static int slip_transmit(FAR struct slip_driver_s *priv)
|
||||
* Function: slip_uiptxpoll
|
||||
*
|
||||
* Description:
|
||||
* The transmitter is available, check if uIP has any outgoing packets ready
|
||||
* to send. This is a callback from uip_poll(). uip_poll() may be called:
|
||||
* Check if uIP has any outgoing packets ready to send. This is a
|
||||
* callback from uip_poll(). uip_poll() may be called:
|
||||
*
|
||||
* 1. When the preceding TX packet send is complete,
|
||||
* 2. When the preceding TX packet send timesout and the interface is reset
|
||||
* 1. When the preceding TX packet send is complete, or
|
||||
* 2. When the preceding TX packet send times o ]ut and the interface is reset
|
||||
* 3. During normal TX polling
|
||||
*
|
||||
* Parameters:
|
||||
@ -421,9 +435,7 @@ static int slip_transmit(FAR struct slip_driver_s *priv)
|
||||
* OK on success; a negated errno on failure
|
||||
*
|
||||
* Assumptions:
|
||||
* May or may not be called from an interrupt handler. In either case,
|
||||
* global interrupts are disabled, either explicitly or indirectly through
|
||||
* interrupt handling logic.
|
||||
* The initiator of the poll holds the priv->waitsem;
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
@ -447,6 +459,36 @@ static int slip_uiptxpoll(struct uip_driver_s *dev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Function: slip_txworker
|
||||
*
|
||||
* Description:
|
||||
* Polling and transmission is performed on the worker thread.
|
||||
*
|
||||
* Parameters:
|
||||
* arg - Reference to the NuttX driver state structure
|
||||
*
|
||||
* Returned Value:
|
||||
* None
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static void slip_txworker(FAR void *arg)
|
||||
{
|
||||
FAR struct slip_driver_s *priv = (FAR struct slip_driver_s *)arg;
|
||||
DEBUGASSERT(priv != NULL);
|
||||
|
||||
/* Get exclusive access to uIP */
|
||||
|
||||
slip_semtake(priv);
|
||||
|
||||
/* Poll uIP for new XMIT data. uIP expects interrupts to be disabled. */
|
||||
|
||||
priv->dev.d_buf = priv->txbuf;
|
||||
(void)uip_timer(&priv->dev, slip_uiptxpoll, SLIP_POLLHSEC);
|
||||
slip_semgive(priv);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Function: slip_getc
|
||||
*
|
||||
@ -463,8 +505,18 @@ static int slip_uiptxpoll(struct uip_driver_s *dev)
|
||||
|
||||
static inline int slip_getc(FAR struct slip_driver_s *priv)
|
||||
{
|
||||
int ret = getc(priv->stream);
|
||||
DEBUGASSERT(ret != EOF);
|
||||
int ret;
|
||||
|
||||
/* It is not expected that getc will be awakened by signals on the
|
||||
* slip_rxtask thread. But just in case...
|
||||
*/
|
||||
|
||||
do
|
||||
{
|
||||
ret = getc(priv->stream);
|
||||
}
|
||||
while (ret == EOF);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -591,10 +643,15 @@ static int slip_rxtask(int argc, char *argv[])
|
||||
ndbg("index: %d\n", index);
|
||||
DEBUGASSERT(index < CONFIG_SLIP_NINTERFACES);
|
||||
|
||||
/* Get our private data structure instance */
|
||||
/* 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.
|
||||
*/
|
||||
|
||||
priv = &g_slip[index];
|
||||
slip_semgive(priv);
|
||||
slip_semgive(priv);
|
||||
|
||||
/* Loop forever */
|
||||
|
||||
@ -602,24 +659,16 @@ static int slip_rxtask(int argc, char *argv[])
|
||||
{
|
||||
/* Wait for the next character to be available on the input stream. */
|
||||
|
||||
nvdbg("Waiting...\n");
|
||||
ch = slip_getc(priv);
|
||||
|
||||
/* We have something... three interesting cases. First there might
|
||||
* be a read error. Anything other an EINTR would indicate a serious
|
||||
* device-related problem or software bug.
|
||||
*/
|
||||
|
||||
if (ch == EOF)
|
||||
{
|
||||
DEBUGASSERT(errno == EINTR);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* END characters may appear at packet boundaries BEFORE as well as
|
||||
/* We have something...
|
||||
*
|
||||
* END characters may appear at packet boundaries BEFORE as well as
|
||||
* after the beginning of the packet. This is normal and expected.
|
||||
*/
|
||||
|
||||
else if (ch == SLIP_END)
|
||||
if (ch == SLIP_END)
|
||||
{
|
||||
priv->rxlen = 0;
|
||||
}
|
||||
@ -649,11 +698,9 @@ static int slip_rxtask(int argc, char *argv[])
|
||||
|
||||
if (priv->rxlen >= UIP_IPH_LEN)
|
||||
{
|
||||
/* Handle the IP input. Interrupts must be disabled here to
|
||||
* keep the POLL watchdog from firing.
|
||||
*/
|
||||
/* Handle the IP input. Get exclusive access to uIP. */
|
||||
|
||||
irqstate_t flags = irqsave();
|
||||
slip_semtake(priv);
|
||||
priv->dev.d_buf = priv->rxbuf;
|
||||
priv->dev.d_len = priv->rxlen;
|
||||
uip_input(&priv->dev);
|
||||
@ -665,9 +712,9 @@ static int slip_rxtask(int argc, char *argv[])
|
||||
|
||||
if (priv->dev.d_len > 0)
|
||||
{
|
||||
slip_transmit(priv);
|
||||
slip_transmit(priv);
|
||||
}
|
||||
irqrestore(flags);
|
||||
slip_semgive(priv);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -701,11 +748,17 @@ static int slip_rxtask(int argc, char *argv[])
|
||||
static void slip_polltimer(int argc, uint32_t arg, ...)
|
||||
{
|
||||
FAR struct slip_driver_s *priv = (FAR struct slip_driver_s *)arg;
|
||||
int ret;
|
||||
|
||||
/* If so, update TCP timing states and poll uIP for new XMIT data. */
|
||||
/* Perform the poll on the worker thread. We cannot access standard I/O
|
||||
* from an interrupt handler.
|
||||
*/
|
||||
|
||||
priv->dev.d_buf = priv->txbuf;
|
||||
(void)uip_timer(&priv->dev, slip_uiptxpoll, SLIP_POLLHSEC);
|
||||
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 */
|
||||
|
||||
@ -797,34 +850,29 @@ static int slip_ifdown(struct uip_driver_s *dev)
|
||||
* Returned Value:
|
||||
* None
|
||||
*
|
||||
* Assumptions:
|
||||
* Called in normal user mode
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static int slip_txavail(struct uip_driver_s *dev)
|
||||
{
|
||||
FAR struct slip_driver_s *priv = (FAR struct slip_driver_s *)dev->d_private;
|
||||
irqstate_t flags;
|
||||
|
||||
/* Disable interrupts because this function may be called from interrupt
|
||||
* level processing.
|
||||
*/
|
||||
|
||||
flags = irqsave();
|
||||
int ret = OK;
|
||||
|
||||
/* Ignore the notification if the interface is not yet up */
|
||||
|
||||
if (priv->bifup)
|
||||
{
|
||||
/* Poll uIP for new XMIT data */
|
||||
/* Perform a poll on the worker thread. We cannot access standard I/O
|
||||
* from an interrupt handler.
|
||||
*/
|
||||
|
||||
priv->dev.d_buf = priv->txbuf;
|
||||
(void)uip_poll(&priv->dev, slip_uiptxpoll);
|
||||
ret = work_queue(&priv->txwork, slip_txworker, priv, 0);
|
||||
if (ret != OK)
|
||||
{
|
||||
ndbg("Failed to schedule work: %d\n", ret);
|
||||
}
|
||||
}
|
||||
|
||||
irqrestore(flags);
|
||||
return OK;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
@ -957,10 +1005,10 @@ int slip_initialize(int intf, const char *devname)
|
||||
|
||||
#ifndef CONFIG_CUSTOM_STACK
|
||||
priv->pid = task_create("usbhost", CONFIG_SLIP_DEFPRIO,
|
||||
CONFIG_SLIP_STACKSIZE, (main_t)slip_rxtask, argv);
|
||||
CONFIG_SLIP_STACKSIZE, (main_t)slip_rxtask, argv);
|
||||
#else
|
||||
priv->pid = task_create("usbhost", CONFIG_SLIP_DEFPRIO,
|
||||
(main_t)slip_rxtask, argv);
|
||||
(main_t)slip_rxtask, argv);
|
||||
#endif
|
||||
if (priv->pid < 0)
|
||||
{
|
||||
|
@ -59,7 +59,7 @@
|
||||
|
||||
/* Defines the work callback */
|
||||
|
||||
typedef FAR void (*worker_t)(FAR void *arg);
|
||||
typedef void (*worker_t)(FAR void *arg);
|
||||
|
||||
/* Defines one entry in the work queue. The user only needs this structure
|
||||
* in order to declare instances of the work structure. Handling of all
|
||||
|
Loading…
x
Reference in New Issue
Block a user