diff --git a/drivers/wireless/ieee802154/xbee/xbee.c b/drivers/wireless/ieee802154/xbee/xbee.c index 2f5d048aa9..bf8fa0cfce 100644 --- a/drivers/wireless/ieee802154/xbee/xbee.c +++ b/drivers/wireless/ieee802154/xbee/xbee.c @@ -166,6 +166,21 @@ static void xbee_attnworker(FAR void *arg) DEBUGASSERT(priv); DEBUGASSERT(priv->spi); + /* Allocate an IOB for the incoming data. */ + + iob = iob_alloc(false); + iob->io_flink = NULL; + iob->io_len = 0; + iob->io_offset = 0; + iob->io_pktlen = 0; + + /* Keep a reference to the first IOB. If we need to allocate more than + * one to hold each API frame, then we will still have this reference to + * the head of the list + */ + + iobhead = iob; + /* NOTE: There is a helpful side-effect to trying to get the SPI Lock here * even when there is a write going on. That is, if the SPI write are on a * thread with lower priority, trying to get the lock here should boost the @@ -191,24 +206,9 @@ static void xbee_attnworker(FAR void *arg) priv->attn_latched = false; } - /* Allocate an IOB for the incoming data. */ - - iob = iob_alloc(false); - iob->io_flink = NULL; - iob->io_len = 0; - iob->io_offset = 0; - iob->io_pktlen = 0; - - /* Keep a reference to the first IOB. If we need to allocate more than - * one to hold each API frame, then we will still have this reference to - * the head of the list - */ - - iobhead = iob; - if (priv->attn_latched) { - while (priv->lower->poll(priv->lower)) + while (priv->lower->poll(priv->lower) && iob != NULL) { DEBUGASSERT(iob->io_len <= CONFIG_IOB_BUFSIZE); @@ -264,14 +264,18 @@ static void xbee_attnworker(FAR void *arg) * processing. */ - iob->io_flink = iob_alloc(false); + iob->io_flink = iob_tryalloc(false); iob = iob->io_flink; - iob->io_flink = NULL; - iob->io_len = 0; - iob->io_offset = 0; - iob->io_pktlen = 0; - } + if (iob != NULL) + { + + iob->io_flink = NULL; + iob->io_len = 0; + iob->io_offset = 0; + iob->io_pktlen = 0; + } + } else { wlwarn("invalid checksum on incoming API frame. Dropping!\n"); @@ -287,7 +291,10 @@ static void xbee_attnworker(FAR void *arg) } } - priv->attn_latched = false; + if (!priv->lower->poll(priv->lower)) + { + priv->attn_latched = false; + } } /* The last IOB in the list (or the only one) may be able to be freed since @@ -298,28 +305,31 @@ static void xbee_attnworker(FAR void *arg) * we can only drop it. */ - if (iob->io_len < XBEE_APIFRAME_OVERHEAD || iob->io_len != rxframelen) + if (iob != NULL) { - if (iobhead == iob) + if (iob->io_len < XBEE_APIFRAME_OVERHEAD || iob->io_len != rxframelen) { - iobhead = NULL; - } - else - { - previob = iobhead; - while (previob->io_flink != iob) + if (iobhead == iob) { - previob = previob->io_flink; + iobhead = NULL; + } + else + { + previob = iobhead; + while (previob->io_flink != iob) + { + previob = previob->io_flink; + } + previob->io_flink = NULL; } - previob->io_flink = NULL; - } - if (iob->io_len > 0) - { - wlwarn("Partial API frame clocked in. Dropping!\n"); - } + if (iob->io_len > 0) + { + wlwarn("Partial API frame clocked in. Dropping!\n"); + } - iob_free(iob); + iob_free(iob); + } } if (iobhead != NULL) @@ -665,11 +675,8 @@ static void xbee_process_apiframes(FAR struct xbee_priv_s *priv, break; case XBEE_APIFRAME_TXSTATUS: { - wd_cancel(priv->reqdata_wd); xbee_process_txstatus(priv, frame->io_data[frame->io_offset], frame->io_data[frame->io_offset + 1]); - priv->txdone = true; - nxsem_post(&priv->txdone_sem); } break; case XBEE_APIFRAME_RX_EADDR: @@ -841,6 +848,17 @@ static void xbee_process_txstatus(FAR struct xbee_priv_s *priv, uint8_t frameid, } xbee_notify(priv, primitive); + + /* If this is the frame we are currently waiting on, cancel the timeout, and + * notify the waiting thread that the transmit is done + */ + + if (priv->frameid == frameid) + { + wd_cancel(priv->reqdata_wd); + priv->txdone = true; + nxsem_post(&priv->txdone_sem); + } } /**************************************************************************** @@ -1116,9 +1134,11 @@ void xbee_send_apiframe(FAR struct xbee_priv_s *priv, /* Allocate an IOB for the incoming data. The XBee supports full-duplex * SPI communication. This means that the MISO data can become valid at any * time. This requires us to process incoming MISO data to see if it is valid. + * + * If we can't allocate an IOB, then we have to just drop the incoming data. */ - iob = iob_alloc(false); + iob = iob_tryalloc(false); iob->io_flink = NULL; iob->io_len = 0; iob->io_offset = 0; @@ -1132,11 +1152,18 @@ void xbee_send_apiframe(FAR struct xbee_priv_s *priv, iobhead = iob; i = 0; - while (i < framelen || priv->lower->poll(priv->lower)) + while (i < framelen || (priv->lower->poll(priv->lower) && iob != NULL)) { if (i < framelen) { - iob->io_data[iob->io_len] = SPI_SEND(priv->spi, frame[i++]); + if (iob) + { + iob->io_data[iob->io_len] = SPI_SEND(priv->spi, frame[i++]); + } + else + { + SPI_SEND(priv->spi, frame[i++]); + } } else { @@ -1147,7 +1174,7 @@ void xbee_send_apiframe(FAR struct xbee_priv_s *priv, * data prior to that can be completely ignored. */ - if (priv->attn_latched) + if (priv->attn_latched && iob != NULL) { DEBUGASSERT(iob->io_len <= CONFIG_IOB_BUFSIZE); @@ -1201,14 +1228,17 @@ void xbee_send_apiframe(FAR struct xbee_priv_s *priv, * processing. */ - iob->io_flink = iob_alloc(false); + iob->io_flink = iob_tryalloc(false); iob = iob->io_flink; - iob->io_flink = NULL; - iob->io_len = 0; - iob->io_offset = 0; - iob->io_pktlen = 0; - } + if (iob != NULL) + { + iob->io_flink = NULL; + iob->io_len = 0; + iob->io_offset = 0; + iob->io_pktlen = 0; + } + } else { wlwarn("invalid checksum on incoming API frame. Dropping!\n"); @@ -1233,28 +1263,31 @@ void xbee_send_apiframe(FAR struct xbee_priv_s *priv, * we can only drop it. */ - if (iob->io_len < XBEE_APIFRAME_OVERHEAD || iob->io_len != rxframelen) + if (iob != NULL) { - if (iobhead == iob) + if (iob->io_len < XBEE_APIFRAME_OVERHEAD || iob->io_len != rxframelen) { - iobhead = NULL; - } - else - { - previob = iobhead; - while (previob->io_flink != iob) + if (iobhead == iob) { - previob = previob->io_flink; + iobhead = NULL; + } + else + { + previob = iobhead; + while (previob->io_flink != iob) + { + previob = previob->io_flink; + } + previob->io_flink = NULL; } - previob->io_flink = NULL; - } - if (iob->io_len > 0) - { - wlwarn("Partial API frame clocked in. Dropping!\n"); - } + if (iob->io_len > 0) + { + wlwarn("Partial API frame clocked in. Dropping!\n"); + } - iob_free(iob); + iob_free(iob); + } } if (iobhead != NULL) diff --git a/drivers/wireless/ieee802154/xbee/xbee_mac.c b/drivers/wireless/ieee802154/xbee/xbee_mac.c index a0dbeea818..c423a1968f 100644 --- a/drivers/wireless/ieee802154/xbee/xbee_mac.c +++ b/drivers/wireless/ieee802154/xbee/xbee_mac.c @@ -380,6 +380,20 @@ int xbee_req_data(XBEEHANDLE xbee, /* Wait for a transmit status to be received. Does not necessarily mean success */ while (nxsem_wait(&priv->txdone_sem) < 0); + + /* If the transmit timeout has occured, and there are no IOBs available, + * we may be blocking the context needed to free the IOBs. We cannot receive + * the Tx status because it requires an IOB. Therefore, if we have hit the + * timeout, and there are no IOBs, let's move on assuming the transmit was + * a success + */ + + if (!priv->txdone && iob_navail(false) <= 0) + { + wlwarn("Couldn't confirm TX. No IOBs\n"); + break; + } + } while (!priv->txdone);