diff --git a/drivers/wireless/ieee802154/xbee/xbee.c b/drivers/wireless/ieee802154/xbee/xbee.c index 145a0a25474..33b7485918e 100644 --- a/drivers/wireless/ieee802154/xbee/xbee.c +++ b/drivers/wireless/ieee802154/xbee/xbee.c @@ -643,8 +643,10 @@ 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; @@ -1027,6 +1029,7 @@ XBEEHANDLE xbee_init(FAR struct spi_dev_s *spi, priv->assocwd = wd_create(); priv->atquery_wd = wd_create(); + priv->reqdata_wd = wd_create(); priv->frameid = 0; /* Frame ID should never be 0, but it is incremented * in xbee_next_frameid before being used so it will be 1 */ diff --git a/drivers/wireless/ieee802154/xbee/xbee.h b/drivers/wireless/ieee802154/xbee/xbee.h index 3f0386b7183..e039917d184 100644 --- a/drivers/wireless/ieee802154/xbee/xbee.h +++ b/drivers/wireless/ieee802154/xbee/xbee.h @@ -172,9 +172,11 @@ struct xbee_priv_s char querycmd[2]; /* Stores the pending AT Query command */ bool querydone; /* Used to tell waiting thread query is done*/ WDOG_ID atquery_wd; /* Support AT Query timeout and retry */ + WDOG_ID reqdata_wd; /* Support send timeout and retry */ uint8_t frameid; /* For differentiating AT request/response */ sem_t tx_sem; /* Support a single pending transmit */ sem_t txdone_sem; /* For signalling tx is completed */ + bool txdone; /******************* Fields related to Xbee radio ***************************/ diff --git a/drivers/wireless/ieee802154/xbee/xbee_mac.c b/drivers/wireless/ieee802154/xbee/xbee_mac.c index 03b7b380452..69aa8b8d1b7 100644 --- a/drivers/wireless/ieee802154/xbee/xbee_mac.c +++ b/drivers/wireless/ieee802154/xbee/xbee_mac.c @@ -55,6 +55,7 @@ ****************************************************************************/ #define XBEE_ASSOC_POLLDELAY 100 +#define XBEE_RESPONSE_TIMEOUT 100 /**************************************************************************** * Private Types @@ -149,6 +150,40 @@ static void xbee_assocworker(FAR void *arg) (void)wd_start(priv->assocwd, XBEE_ASSOC_POLLDELAY, xbee_assoctimer, 1, (wdparm_t)arg); } +/**************************************************************************** + * Name: xbee_reqdata_timeout + * + * Description: + * This function runs when a send request has timed out waiting for a response + * from the XBee module. This really should never happen, but if it does, + * handle it gracefully by retrying the query. Although I still think this + * should not happen, it does seem to happen. The XBee seemingly randomly drops + * the request and never sends a response. + * + * Parameters: + * argc - The number of available arguments + * arg - The first argument + * + * Returned Value: + * None + * + * Assumptions: + * + ****************************************************************************/ + +static void xbee_reqdata_timeout(int argc, uint32_t arg, ...) +{ + FAR struct xbee_priv_s *priv = (FAR struct xbee_priv_s *)arg; + + DEBUGASSERT(priv != NULL); + + wlwarn("Send timeout\n"); + + /* Wake the pending reqdata thread so it can retry */ + + nxsem_post(&priv->txdone_sem); +} + /**************************************************************************** * Public Functions ****************************************************************************/ @@ -327,12 +362,25 @@ int xbee_req_data(XBEEHANDLE xbee, xbee_insert_checksum(&frame->io_data[frame->io_offset], (frame->io_len - frame->io_offset)); - xbee_send_apiframe(priv, &frame->io_data[frame->io_offset], - (frame->io_len - frame->io_offset)); + priv->txdone = false; - /* Wait for a transmit status to be received. Does not necessarily mean success */ + do + { + /* Setup a timeout in case the XBee never responds with a tx status */ - while (nxsem_wait(&priv->txdone_sem) < 0); + (void)wd_start(priv->reqdata_wd, XBEE_RESPONSE_TIMEOUT, xbee_reqdata_timeout, + 1, (wdparm_t)priv); + + /* Send the frame */ + + xbee_send_apiframe(priv, &frame->io_data[frame->io_offset], + (frame->io_len - frame->io_offset)); + + /* Wait for a transmit status to be received. Does not necessarily mean success */ + + while (nxsem_wait(&priv->txdone_sem) < 0); + } + while (!priv->txdone); nxsem_post(&priv->tx_sem); iob_free(frame);