Spirit Network Device: Fix a deadlock. Also several other design improvements to eliminate corner cases.
This commit is contained in:
parent
d5e7ebed02
commit
8a785c4b66
@ -273,8 +273,9 @@ Configuration sub-directories
|
|||||||
|
|
||||||
This is another version of nsh that is similar to the above 'nsh'
|
This is another version of nsh that is similar to the above 'nsh'
|
||||||
configuration but is focused on testing the Spirit1 integration with
|
configuration but is focused on testing the Spirit1 integration with
|
||||||
the 6LoWPAN network stack. Additional differences
|
the 6LoWPAN network stack. It supports point-to-point, 6LoWPAN
|
||||||
are summarized below:
|
communications between two b-l47e-iot01a boards. Additional differences
|
||||||
|
from the 'nsh" configuration are summarized below:
|
||||||
|
|
||||||
NOTES:
|
NOTES:
|
||||||
|
|
||||||
@ -292,14 +293,19 @@ Configuration sub-directories
|
|||||||
|
|
||||||
nsh> ifconfig wpan0 hw 37
|
nsh> ifconfig wpan0 hw 37
|
||||||
|
|
||||||
Where 37 is address as an example. It should be different in the
|
Where 37 the address is an example. It should be different for
|
||||||
the range 1..ed and ef..fe (ee and ff are the reseerd multicast
|
each radio, but in the the range 1..ed and ef..fe (ee and ff are
|
||||||
and broadcast addresses. Zero is valid but not a good idea).
|
the reserved for multicast and broadcast addresses, respectively.
|
||||||
|
Zero is a valid address but not recommeded).
|
||||||
|
|
||||||
b) Bring each the network up on each board in the WPAN:
|
b) Bring each the network up on each board in the WPAN:
|
||||||
|
|
||||||
nsh> ifup wpan0
|
nsh> ifup wpan0
|
||||||
|
|
||||||
|
You can entry nsh> ifconfig to see if the node address and
|
||||||
|
derived IPv4 are set correctly (the IPv6 address will not be
|
||||||
|
determined until the network is UP).
|
||||||
|
|
||||||
4. examples/udp is enabled. This will allow two Spirit1 nodes to
|
4. examples/udp is enabled. This will allow two Spirit1 nodes to
|
||||||
exchange UDP packets. Basic instructions:
|
exchange UDP packets. Basic instructions:
|
||||||
|
|
||||||
|
@ -124,8 +124,6 @@ int board_button_irq(int id, xcpt_t irqhandler, FAR void *arg)
|
|||||||
{
|
{
|
||||||
int ret = -EINVAL;
|
int ret = -EINVAL;
|
||||||
|
|
||||||
/* The following should be atomic */
|
|
||||||
|
|
||||||
if (id >= MIN_IRQBUTTON && id <= MAX_IRQBUTTON)
|
if (id >= MIN_IRQBUTTON && id <= MAX_IRQBUTTON)
|
||||||
{
|
{
|
||||||
ret = stm32_gpiosetevent(g_buttons[id], true, true, true, irqhandler, arg);
|
ret = stm32_gpiosetevent(g_buttons[id], true, true, true, irqhandler, arg);
|
||||||
|
@ -110,6 +110,11 @@
|
|||||||
|
|
||||||
#define SPIRIT_TXTIMEOUT (60*CLK_TCK)
|
#define SPIRIT_TXTIMEOUT (60*CLK_TCK)
|
||||||
|
|
||||||
|
/* Return values from spirit_transmit() */
|
||||||
|
|
||||||
|
#define SPIRIT_TX_IDLE 0
|
||||||
|
#define SPIRIT_TX_INFLIGHT 1
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
* Private Types
|
* Private Types
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
@ -136,12 +141,14 @@ struct spirit_driver_s
|
|||||||
FAR struct pktradio_metadata_s *txtail; /* Tail of pending TX transfers */
|
FAR struct pktradio_metadata_s *txtail; /* Tail of pending TX transfers */
|
||||||
FAR struct pktradio_metadata_s *rxhead; /* Head of completed RX transfers */
|
FAR struct pktradio_metadata_s *rxhead; /* Head of completed RX transfers */
|
||||||
FAR struct pktradio_metadata_s *rxtail; /* Tail of completed RX transfers */
|
FAR struct pktradio_metadata_s *rxtail; /* Tail of completed RX transfers */
|
||||||
struct work_s hpwork; /* Interrupt continuation work queue support */
|
struct work_s irqwork; /* Interrupt continuation work queue support */
|
||||||
struct work_s lpwork; /* Net poll work queue support */
|
struct work_s txwork; /* TX / Network poll work queue support */
|
||||||
|
struct work_s rxwork; /* RX work queue support */
|
||||||
WDOG_ID txpoll; /* TX poll timer */
|
WDOG_ID txpoll; /* TX poll timer */
|
||||||
WDOG_ID txtimeout; /* TX timeout timer */
|
WDOG_ID txtimeout; /* TX timeout timer */
|
||||||
sem_t exclsem; /* Mutually exclusive access */
|
sem_t exclsem; /* Mutually exclusive access */
|
||||||
bool ifup; /* Spirit is on and interface is up */
|
bool ifup; /* Spirit is on and interface is up */
|
||||||
|
bool needpoll; /* Timer poll needed */
|
||||||
uint8_t state; /* See enum spirit_driver_state_e */
|
uint8_t state; /* See enum spirit_driver_state_e */
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -180,15 +187,13 @@ static int spirit_interrupt(int irq, FAR void *context, FAR void *arg);
|
|||||||
static void spirit_txtimeout_work(FAR void *arg);
|
static void spirit_txtimeout_work(FAR void *arg);
|
||||||
static void spirit_txtimeout_expiry(int argc, wdparm_t arg, ...);
|
static void spirit_txtimeout_expiry(int argc, wdparm_t arg, ...);
|
||||||
|
|
||||||
static void spirit_poll_work(FAR void *arg);
|
static void spirit_txpoll_work(FAR void *arg);
|
||||||
static void spirit_poll_expiry(int argc, wdparm_t arg, ...);
|
static void spirit_txpoll_expiry(int argc, wdparm_t arg, ...);
|
||||||
|
|
||||||
/* NuttX callback functions */
|
/* NuttX callback functions */
|
||||||
|
|
||||||
static int spirit_ifup(FAR struct net_driver_s *dev);
|
static int spirit_ifup(FAR struct net_driver_s *dev);
|
||||||
static int spirit_ifdown(FAR struct net_driver_s *dev);
|
static int spirit_ifdown(FAR struct net_driver_s *dev);
|
||||||
|
|
||||||
static void spirit_txavail_work(FAR void *arg);
|
|
||||||
static int spirit_txavail(FAR struct net_driver_s *dev);
|
static int spirit_txavail(FAR struct net_driver_s *dev);
|
||||||
|
|
||||||
#ifdef CONFIG_NET_IGMP
|
#ifdef CONFIG_NET_IGMP
|
||||||
@ -439,7 +444,9 @@ errout_with_irqdisable:
|
|||||||
* priv - Reference to the driver state structure
|
* priv - Reference to the driver state structure
|
||||||
*
|
*
|
||||||
* Returned Value:
|
* Returned Value:
|
||||||
* OK on success; a negated errno on failure
|
* 0 - on success with nothing to be sent (SPIRIT_TX_IDLE)
|
||||||
|
* 1 - on success if a packet is in-flight (SPIRIT_TX_INFLIGHT)
|
||||||
|
* <0 - a negated errno on failure
|
||||||
*
|
*
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
|
||||||
@ -455,6 +462,8 @@ static int spirit_transmit(FAR struct spirit_driver_s *priv)
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
spirit_lock(priv);
|
spirit_lock(priv);
|
||||||
|
wlinfo("txhead=%p state=%u\n", priv->txhead, priv->state);
|
||||||
|
|
||||||
while (priv->txhead != NULL && priv->state == DRIVER_STATE_IDLE)
|
while (priv->txhead != NULL && priv->state == DRIVER_STATE_IDLE)
|
||||||
{
|
{
|
||||||
/* Remove the contained IOB from the head of the TX queue */
|
/* Remove the contained IOB from the head of the TX queue */
|
||||||
@ -490,6 +499,7 @@ static int spirit_transmit(FAR struct spirit_driver_s *priv)
|
|||||||
ret = spirit_set_readystate(priv);
|
ret = spirit_set_readystate(priv);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
{
|
{
|
||||||
|
wlerr("ERROR: Failed to set READY state: %d\n", ret);
|
||||||
goto errout_with_iob;
|
goto errout_with_iob;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -498,14 +508,18 @@ static int spirit_transmit(FAR struct spirit_driver_s *priv)
|
|||||||
ret = spirit_command(spirit, COMMAND_FLUSHTXFIFO);
|
ret = spirit_command(spirit, COMMAND_FLUSHTXFIFO);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
{
|
{
|
||||||
|
wlerr("ERROR: Failed to flush TX FIFO\n");
|
||||||
goto errout_with_iob;
|
goto errout_with_iob;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Sets the length of the packet to send */
|
/* Sets the length of the packet to send */
|
||||||
|
|
||||||
|
wlinfo("Payload length=%u\n", iob->io_len);
|
||||||
|
|
||||||
ret = spirit_pktbasic_set_payloadlen(spirit, iob->io_len);
|
ret = spirit_pktbasic_set_payloadlen(spirit, iob->io_len);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
{
|
{
|
||||||
|
wlerr("ERROR: Failed to set payload length: %d\n", ret);
|
||||||
goto errout_with_iob;
|
goto errout_with_iob;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -513,19 +527,26 @@ static int spirit_transmit(FAR struct spirit_driver_s *priv)
|
|||||||
/* Set the destination address */
|
/* Set the destination address */
|
||||||
|
|
||||||
DEBUGASSERT(pktmeta->pm_dest.pa_addrlen == 1);
|
DEBUGASSERT(pktmeta->pm_dest.pa_addrlen == 1);
|
||||||
|
wlinfo("txdestaddr=%02x\n", pktmeta->pm_dest.pa_addr[0]);
|
||||||
|
|
||||||
ret = spirit_pktcommon_set_txdestaddr(spirit,
|
ret = spirit_pktcommon_set_txdestaddr(spirit,
|
||||||
pktmeta->pm_dest.pa_addr[0]);
|
pktmeta->pm_dest.pa_addr[0]);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
{
|
{
|
||||||
|
wlerr("ERROR: Failed to set TX destaddr to %02x: %d\n",
|
||||||
|
pktmeta->pm_dest.pa_addr[0], ret);
|
||||||
goto errout_with_iob;
|
goto errout_with_iob;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Enable CSMA */
|
/* Enable CSMA */
|
||||||
|
|
||||||
|
wlinfo("Enable CSMA and send packet\n");
|
||||||
|
|
||||||
ret = spirit_csma_enable(spirit, S_ENABLE);
|
ret = spirit_csma_enable(spirit, S_ENABLE);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
{
|
{
|
||||||
|
wlerr("ERROR: Failed to enable CSMA: %d\n", ret);
|
||||||
goto errout_with_iob;
|
goto errout_with_iob;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -534,15 +555,21 @@ static int spirit_transmit(FAR struct spirit_driver_s *priv)
|
|||||||
ret = spirit_fifo_write(spirit, iob->io_data, iob->io_len);
|
ret = spirit_fifo_write(spirit, iob->io_data, iob->io_len);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
{
|
{
|
||||||
|
wlerr("ERROR: Write to linear FIFO failed: %d\n", ret);
|
||||||
goto errout_with_iob;
|
goto errout_with_iob;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* We can free the IOB now */
|
||||||
|
|
||||||
|
iob_free(iob);
|
||||||
|
|
||||||
/* Put the SPIRIT1 into TX state. This starts the transmission */
|
/* Put the SPIRIT1 into TX state. This starts the transmission */
|
||||||
|
|
||||||
ret = spirit_command(spirit, COMMAND_TX);
|
ret = spirit_command(spirit, COMMAND_TX);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
{
|
{
|
||||||
goto errout_with_iob;
|
wlerr("ERROR: Write to send TX command: %d\n", ret);
|
||||||
|
goto errout_with_lock;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Wait until we have successfully entered the TX state */
|
/* Wait until we have successfully entered the TX state */
|
||||||
@ -551,7 +578,7 @@ static int spirit_transmit(FAR struct spirit_driver_s *priv)
|
|||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
{
|
{
|
||||||
wlerr("ERROR: Failed to go to TX state: %d\n", ret);
|
wlerr("ERROR: Failed to go to TX state: %d\n", ret);
|
||||||
goto errout_with_iob;
|
goto errout_with_lock;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Setup the TX timeout watchdog (perhaps restarting the timer) */
|
/* Setup the TX timeout watchdog (perhaps restarting the timer) */
|
||||||
@ -560,13 +587,20 @@ static int spirit_transmit(FAR struct spirit_driver_s *priv)
|
|||||||
spirit_txtimeout_expiry, 1, (wdparm_t)priv);
|
spirit_txtimeout_expiry, 1, (wdparm_t)priv);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Return 0 or 1, depending upon if the Spirit is IDLE or is in the TX (or
|
||||||
|
* possibly RX) states.
|
||||||
|
*/
|
||||||
|
|
||||||
|
ret = (priv->state == DRIVER_STATE_IDLE) ? SPIRIT_TX_IDLE : SPIRIT_TX_INFLIGHT;
|
||||||
spirit_unlock(priv);
|
spirit_unlock(priv);
|
||||||
return OK;
|
return ret;
|
||||||
|
|
||||||
errout_with_iob:
|
errout_with_iob:
|
||||||
spirit_unlock(priv);
|
|
||||||
NETDEV_RXDROPPED(&priv->radio.r_dev);
|
|
||||||
iob_free(iob);
|
iob_free(iob);
|
||||||
|
|
||||||
|
errout_with_lock:
|
||||||
|
spirit_unlock(priv);
|
||||||
|
NETDEV_TXERRORS(&priv->radio.r_dev);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -574,7 +608,9 @@ errout_with_iob:
|
|||||||
* Name: sprit_transmit_work
|
* Name: sprit_transmit_work
|
||||||
*
|
*
|
||||||
* Description:
|
* Description:
|
||||||
* Send data on the LP work queue.
|
* Send data on the LP work queue. This function scheduled by interrupt
|
||||||
|
* handling logic when a TX transfer completes and, more generally, on
|
||||||
|
* all transitions to the IDLE state.
|
||||||
*
|
*
|
||||||
* Parameters:
|
* Parameters:
|
||||||
* arg - Reference to driver state structure (cast to void *)
|
* arg - Reference to driver state structure (cast to void *)
|
||||||
@ -587,12 +623,25 @@ errout_with_iob:
|
|||||||
static void sprit_transmit_work(FAR void *arg)
|
static void sprit_transmit_work(FAR void *arg)
|
||||||
{
|
{
|
||||||
FAR struct spirit_driver_s *priv = (FAR struct spirit_driver_s *)arg;
|
FAR struct spirit_driver_s *priv = (FAR struct spirit_driver_s *)arg;
|
||||||
|
int ret;
|
||||||
|
|
||||||
DEBUGASSERT(priv != NULL);
|
DEBUGASSERT(priv != NULL);
|
||||||
|
|
||||||
net_lock();
|
/* If the driver is IDLE and there are packets to be sent, then send them
|
||||||
spirit_transmit(priv);
|
* now. This will cause a transition to the DRIVER_STATE_SENDING state.
|
||||||
net_unlock();
|
*/
|
||||||
|
|
||||||
|
ret = spirit_transmit(priv);
|
||||||
|
if (ret < 0)
|
||||||
|
{
|
||||||
|
wlerr("ERROR: spirit_transmit failed: %d\n", ret);
|
||||||
|
}
|
||||||
|
else if (ret == SPIRIT_TX_IDLE)
|
||||||
|
{
|
||||||
|
/* Nothing was sent. Try, instead, to poll for new TX data */
|
||||||
|
|
||||||
|
spirit_txpoll_work(arg);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
@ -618,7 +667,7 @@ static void spirit_schedule_transmit_work(FAR struct spirit_driver_s *priv)
|
|||||||
{
|
{
|
||||||
/* Schedule to perform the TX processing on the worker thread. */
|
/* Schedule to perform the TX processing on the worker thread. */
|
||||||
|
|
||||||
work_queue(LPWORK, &priv->lpwork, sprit_transmit_work, priv, 0);
|
work_queue(LPWORK, &priv->txwork, sprit_transmit_work, priv, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -648,10 +697,23 @@ static void spirit_schedule_transmit_work(FAR struct spirit_driver_s *priv)
|
|||||||
|
|
||||||
static int spirit_txpoll_callback(FAR struct net_driver_s *dev)
|
static int spirit_txpoll_callback(FAR struct net_driver_s *dev)
|
||||||
{
|
{
|
||||||
/* If zero is returned, the polling will continue until all connections have
|
FAR struct spirit_driver_s *priv = (FAR struct spirit_driver_s *)dev->d_private;
|
||||||
* been examined.
|
int ret;
|
||||||
|
|
||||||
|
/* NOTE: It is not necessary to call spirit_transmit because that works
|
||||||
|
* though different mechanism, through a backdoor 6LoWPAN interface. We
|
||||||
|
* call it here only to may sure that it has not stalled for some reason.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
ret = spirit_transmit(priv);
|
||||||
|
|
||||||
|
/* If zero is returned, the polling will continue until all connections have
|
||||||
|
* been examined.
|
||||||
|
*
|
||||||
|
* REVISIT: Should we halt polling if there are packets in flight.
|
||||||
|
*/
|
||||||
|
|
||||||
|
UNUSED(ret);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -756,7 +818,7 @@ static void spirit_schedule_receive_work(FAR struct spirit_driver_s *priv)
|
|||||||
{
|
{
|
||||||
/* Schedule to perform the TX processing on the worker thread. */
|
/* Schedule to perform the TX processing on the worker thread. */
|
||||||
|
|
||||||
work_queue(LPWORK, &priv->lpwork, sprit_receive_work, priv, 0);
|
work_queue(LPWORK, &priv->rxwork, sprit_receive_work, priv, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -822,6 +884,7 @@ static void spirit_interrupt_work(FAR void *arg)
|
|||||||
{
|
{
|
||||||
/* Put the Spirit back in the receiving state */
|
/* Put the Spirit back in the receiving state */
|
||||||
|
|
||||||
|
wlinfo("Data sent\n");
|
||||||
DEBUGVERIFY(spirit_management_rxstrobe(spirit));
|
DEBUGVERIFY(spirit_management_rxstrobe(spirit));
|
||||||
DEBUGVERIFY(spirit_command(spirit, CMD_RX));
|
DEBUGVERIFY(spirit_command(spirit, CMD_RX));
|
||||||
|
|
||||||
@ -842,6 +905,7 @@ static void spirit_interrupt_work(FAR void *arg)
|
|||||||
|
|
||||||
if (irqstatus.IRQ_TX_FIFO_ALMOST_EMPTY != 0)
|
if (irqstatus.IRQ_TX_FIFO_ALMOST_EMPTY != 0)
|
||||||
{
|
{
|
||||||
|
wlinfo("TX FIFO almost empty\n");
|
||||||
#warning Missing logic
|
#warning Missing logic
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@ -850,6 +914,7 @@ static void spirit_interrupt_work(FAR void *arg)
|
|||||||
|
|
||||||
if (irqstatus.IRQ_VALID_SYNC != 0)
|
if (irqstatus.IRQ_VALID_SYNC != 0)
|
||||||
{
|
{
|
||||||
|
wlinfo("Valid sync\n");
|
||||||
DEBUGASSERT(priv->state == DRIVER_STATE_IDLE);
|
DEBUGASSERT(priv->state == DRIVER_STATE_IDLE);
|
||||||
priv->state = DRIVER_STATE_RECEIVING;
|
priv->state = DRIVER_STATE_RECEIVING;
|
||||||
}
|
}
|
||||||
@ -862,6 +927,7 @@ static void spirit_interrupt_work(FAR void *arg)
|
|||||||
FAR struct iob_s *iob;
|
FAR struct iob_s *iob;
|
||||||
uint8_t count;
|
uint8_t count;
|
||||||
|
|
||||||
|
wlinfo("Data ready\n");
|
||||||
NETDEV_RXPACKETS(&priv->radio.r_dev);
|
NETDEV_RXPACKETS(&priv->radio.r_dev);
|
||||||
|
|
||||||
/* Check the packet size */
|
/* Check the packet size */
|
||||||
@ -967,6 +1033,7 @@ static void spirit_interrupt_work(FAR void *arg)
|
|||||||
|
|
||||||
if (irqstatus.IRQ_RX_FIFO_ALMOST_FULL != 0)
|
if (irqstatus.IRQ_RX_FIFO_ALMOST_FULL != 0)
|
||||||
{
|
{
|
||||||
|
wlinfo("RX FIFO almost full\n");
|
||||||
#warning Missing logic
|
#warning Missing logic
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@ -1032,12 +1099,13 @@ static int spirit_interrupt(int irq, FAR void *context, FAR void *arg)
|
|||||||
*
|
*
|
||||||
* Notice that further GPIO interrupts are disabled until the work is
|
* Notice that further GPIO interrupts are disabled until the work is
|
||||||
* actually performed. This is to prevent overrun of the worker thread.
|
* actually performed. This is to prevent overrun of the worker thread.
|
||||||
* Interrupts are re-enabled in enc_irqworker() when the work is completed.
|
* Interrupts are re-enabled in spirit_interrupt_work() when the work is
|
||||||
|
* completed.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
priv->lower->enable(priv->lower, false);
|
priv->lower->enable(priv->lower, false);
|
||||||
|
|
||||||
return work_queue(HPWORK, &priv->hpwork, spirit_interrupt_work,
|
return work_queue(HPWORK, &priv->irqwork, spirit_interrupt_work,
|
||||||
(FAR void *)priv, 0);
|
(FAR void *)priv, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1076,6 +1144,9 @@ static void spirit_txtimeout_work(FAR void *arg)
|
|||||||
|
|
||||||
/* Then reset the hardware */
|
/* Then reset the hardware */
|
||||||
|
|
||||||
|
spirit_ifdown(&priv->radio.r_dev);
|
||||||
|
spirit_ifup(&priv->radio.r_dev);
|
||||||
|
|
||||||
/* Then poll the network for new XMIT data */
|
/* Then poll the network for new XMIT data */
|
||||||
|
|
||||||
(void)devif_poll(&priv->radio.r_dev, spirit_txpoll_callback);
|
(void)devif_poll(&priv->radio.r_dev, spirit_txpoll_callback);
|
||||||
@ -1117,32 +1188,11 @@ static void spirit_txtimeout_expiry(int argc, wdparm_t arg, ...)
|
|||||||
|
|
||||||
/* Schedule to perform the TX timeout processing on the worker thread. */
|
/* Schedule to perform the TX timeout processing on the worker thread. */
|
||||||
|
|
||||||
work_queue(LPWORK, &priv->hpwork, spirit_txtimeout_work, priv, 0);
|
work_queue(LPWORK, &priv->irqwork, spirit_txtimeout_work, priv, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
* Name: spirit_poll_process
|
* Name: spirit_txpoll_work
|
||||||
*
|
|
||||||
* Description:
|
|
||||||
* Perform the periodic poll. This may be called either from watchdog
|
|
||||||
* timer logic or from the worker thread, depending upon the configuration.
|
|
||||||
*
|
|
||||||
* Parameters:
|
|
||||||
* priv - Reference to the driver state structure
|
|
||||||
*
|
|
||||||
* Returned Value:
|
|
||||||
* None
|
|
||||||
*
|
|
||||||
* Assumptions:
|
|
||||||
*
|
|
||||||
****************************************************************************/
|
|
||||||
|
|
||||||
static inline void spirit_poll_process(FAR struct spirit_driver_s *priv)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
/****************************************************************************
|
|
||||||
* Name: spirit_poll_work
|
|
||||||
*
|
*
|
||||||
* Description:
|
* Description:
|
||||||
* Perform periodic polling from the worker thread
|
* Perform periodic polling from the worker thread
|
||||||
@ -1159,7 +1209,7 @@ static inline void spirit_poll_process(FAR struct spirit_driver_s *priv)
|
|||||||
*
|
*
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
|
||||||
static void spirit_poll_work(FAR void *arg)
|
static void spirit_txpoll_work(FAR void *arg)
|
||||||
{
|
{
|
||||||
FAR struct spirit_driver_s *priv = (FAR struct spirit_driver_s *)arg;
|
FAR struct spirit_driver_s *priv = (FAR struct spirit_driver_s *)arg;
|
||||||
|
|
||||||
@ -1171,19 +1221,47 @@ static void spirit_poll_work(FAR void *arg)
|
|||||||
|
|
||||||
net_lock();
|
net_lock();
|
||||||
|
|
||||||
/* Perform the periodic poll */
|
/* Do nothing if the network is not yet UP */
|
||||||
|
|
||||||
(void)devif_timer(&priv->radio.r_dev, spirit_txpoll_callback);
|
if (!priv->ifup)
|
||||||
|
{
|
||||||
|
priv->needpoll = false;
|
||||||
|
}
|
||||||
|
|
||||||
/* Setup the watchdog poll timer again */
|
/* Skip the poll if the Spirit busy in the TX or RX states. In this case,
|
||||||
|
* spirit_transmit_work will run when the state transitions back to IDLE
|
||||||
|
* we will perform the poll at that time.
|
||||||
|
*/
|
||||||
|
|
||||||
|
else if (priv->state == DRIVER_STATE_IDLE)
|
||||||
|
{
|
||||||
|
/* Is a periodic poll needed? */
|
||||||
|
|
||||||
|
if (priv->needpoll)
|
||||||
|
{
|
||||||
|
/* Perform the periodic poll */
|
||||||
|
|
||||||
|
priv->needpoll = false;
|
||||||
|
(void)devif_timer(&priv->radio.r_dev, spirit_txpoll_callback);
|
||||||
|
|
||||||
|
/* Setup the watchdog poll timer again */
|
||||||
|
|
||||||
|
(void)wd_start(priv->txpoll, SPIRIT_WDDELAY, spirit_txpoll_expiry, 1,
|
||||||
|
(wdparm_t)priv);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Perform a normal, asynchronous poll for new TX data */
|
||||||
|
|
||||||
|
(void)devif_poll(&priv->radio.r_dev, spirit_txpoll_callback);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
(void)wd_start(priv->txpoll, SPIRIT_WDDELAY, spirit_poll_expiry, 1,
|
|
||||||
(wdparm_t)priv);
|
|
||||||
net_unlock();
|
net_unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
* Name: spirit_poll_expiry
|
* Name: spirit_txpoll_expiry
|
||||||
*
|
*
|
||||||
* Description:
|
* Description:
|
||||||
* Periodic timer handler. Called from the timer interrupt handler.
|
* Periodic timer handler. Called from the timer interrupt handler.
|
||||||
@ -1200,13 +1278,14 @@ static void spirit_poll_work(FAR void *arg)
|
|||||||
*
|
*
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
|
||||||
static void spirit_poll_expiry(int argc, wdparm_t arg, ...)
|
static void spirit_txpoll_expiry(int argc, wdparm_t arg, ...)
|
||||||
{
|
{
|
||||||
FAR struct spirit_driver_s *priv = (FAR struct spirit_driver_s *)arg;
|
FAR struct spirit_driver_s *priv = (FAR struct spirit_driver_s *)arg;
|
||||||
|
|
||||||
/* Schedule to perform the interrupt processing on the worker thread. */
|
/* Schedule to perform the interrupt processing on the worker thread. */
|
||||||
|
|
||||||
work_queue(LPWORK, &priv->lpwork, spirit_poll_work, priv, 0);
|
priv->needpoll = true;
|
||||||
|
work_queue(LPWORK, &priv->txwork, spirit_txpoll_work, priv, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
@ -1303,7 +1382,7 @@ static int spirit_ifup(FAR struct net_driver_s *dev)
|
|||||||
|
|
||||||
/* Set and activate a timer process */
|
/* Set and activate a timer process */
|
||||||
|
|
||||||
(void)wd_start(priv->txpoll, SPIRIT_WDDELAY, spirit_poll_expiry, 1,
|
(void)wd_start(priv->txpoll, SPIRIT_WDDELAY, spirit_txpoll_expiry, 1,
|
||||||
(wdparm_t)priv);
|
(wdparm_t)priv);
|
||||||
|
|
||||||
/* Enables the interrupts from the SPIRIT1 */
|
/* Enables the interrupts from the SPIRIT1 */
|
||||||
@ -1415,49 +1494,6 @@ static int spirit_ifdown(FAR struct net_driver_s *dev)
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
/****************************************************************************
|
|
||||||
* Name: spirit_txavail_work
|
|
||||||
*
|
|
||||||
* Description:
|
|
||||||
* Perform an out-of-cycle poll on the worker thread.
|
|
||||||
*
|
|
||||||
* Parameters:
|
|
||||||
* arg - Reference to the NuttX driver state structure (cast to void*)
|
|
||||||
*
|
|
||||||
* Returned Value:
|
|
||||||
* None
|
|
||||||
*
|
|
||||||
* Assumptions:
|
|
||||||
* Called on the higher priority worker thread.
|
|
||||||
*
|
|
||||||
****************************************************************************/
|
|
||||||
|
|
||||||
static void spirit_txavail_work(FAR void *arg)
|
|
||||||
{
|
|
||||||
FAR struct spirit_driver_s *priv = (FAR struct spirit_driver_s *)arg;
|
|
||||||
|
|
||||||
/* Lock the network and serialize driver operations if necessary.
|
|
||||||
* NOTE: Serialization is only required in the case where the driver work
|
|
||||||
* is performed on an LP worker thread and where more than one LP worker
|
|
||||||
* thread has been configured.
|
|
||||||
*/
|
|
||||||
|
|
||||||
net_lock();
|
|
||||||
|
|
||||||
/* Ignore the notification if the interface is not yet up */
|
|
||||||
|
|
||||||
if (priv->ifup)
|
|
||||||
{
|
|
||||||
/* Check if there is room in the hardware to hold another outgoing packet. */
|
|
||||||
|
|
||||||
/* If so, then poll the network for new XMIT data */
|
|
||||||
|
|
||||||
(void)devif_poll(&priv->radio.r_dev, spirit_txpoll_callback);
|
|
||||||
}
|
|
||||||
|
|
||||||
net_unlock();
|
|
||||||
}
|
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
* Name: spirit_txavail
|
* Name: spirit_txavail
|
||||||
*
|
*
|
||||||
@ -1487,11 +1523,11 @@ static int spirit_txavail(FAR struct net_driver_s *dev)
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
spirit_lock(priv);
|
spirit_lock(priv);
|
||||||
if (work_available(&priv->lpwork))
|
if (work_available(&priv->txwork))
|
||||||
{
|
{
|
||||||
/* Schedule to serialize the poll on the worker thread. */
|
/* Schedule to serialize the poll on the worker thread. */
|
||||||
|
|
||||||
work_queue(LPWORK, &priv->lpwork, spirit_txavail_work, priv, 0);
|
work_queue(LPWORK, &priv->txwork, spirit_txpoll_work, priv, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
spirit_unlock(priv);
|
spirit_unlock(priv);
|
||||||
@ -1728,11 +1764,11 @@ static int spirit_req_data(FAR struct sixlowpan_driver_s *netdev,
|
|||||||
|
|
||||||
/* Add the incoming list of frames to the MAC's outgoing queue */
|
/* Add the incoming list of frames to the MAC's outgoing queue */
|
||||||
|
|
||||||
spirit_lock(priv);
|
|
||||||
for (iob = framelist; iob != NULL; iob = framelist)
|
for (iob = framelist; iob != NULL; iob = framelist)
|
||||||
{
|
{
|
||||||
/* Increment statistics */
|
/* Increment statistics */
|
||||||
|
|
||||||
|
spirit_lock(priv);
|
||||||
NETDEV_TXPACKETS(&priv->radio.r_dev);
|
NETDEV_TXPACKETS(&priv->radio.r_dev);
|
||||||
|
|
||||||
/* Remove the IOB from the queue */
|
/* Remove the IOB from the queue */
|
||||||
@ -1786,10 +1822,10 @@ static int spirit_req_data(FAR struct sixlowpan_driver_s *netdev,
|
|||||||
* tranmission of the frame in the IOB at the head of the IOB queue.
|
* tranmission of the frame in the IOB at the head of the IOB queue.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
spirit_unlock(priv);
|
||||||
spirit_transmit(priv);
|
spirit_transmit(priv);
|
||||||
}
|
}
|
||||||
|
|
||||||
spirit_unlock(priv);
|
|
||||||
return OK;
|
return OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -416,7 +416,7 @@ int spirit_irq_get_pending(FAR struct spirit_library_s *spirit,
|
|||||||
* Name: spirit_irq_clr_pending
|
* Name: spirit_irq_clr_pending
|
||||||
*
|
*
|
||||||
* Description:
|
* Description:
|
||||||
* Clear the IRQ status registers.
|
* Clear all IRQ status registers.
|
||||||
*
|
*
|
||||||
* Input Parameters:
|
* Input Parameters:
|
||||||
* spirit - Reference to a Spirit library state structure instance
|
* spirit - Reference to a Spirit library state structure instance
|
||||||
|
Loading…
Reference in New Issue
Block a user