diff --git a/drivers/wireless/ieee802154/mrf24j40.c b/drivers/wireless/ieee802154/mrf24j40.c index b6e155bd93..1e07d1126b 100644 --- a/drivers/wireless/ieee802154/mrf24j40.c +++ b/drivers/wireless/ieee802154/mrf24j40.c @@ -1520,7 +1520,7 @@ static void mrf24j40_irqwork_txnorm(FAR struct mrf24j40_radio_s *dev) /* Inform the next layer of the transmission success/failure */ - dev->radiocb->txdone_csma(dev->radiocb, &dev->csma_desc.pub); + dev->radiocb->txdone(dev->radiocb, &dev->csma_desc.pub); /* We are now done with the transaction */ @@ -1566,7 +1566,7 @@ static void mrf24j40_irqwork_txgts(FAR struct mrf24j40_radio_s *dev, /* Inform the next layer of the transmission success/failure */ - dev->radiocb->txdone_gts(dev->radiocb, &dev->gts_desc[gts].pub); + dev->radiocb->txdone(dev->radiocb, &dev->gts_desc[gts].pub); /* We are now done with the transaction */ diff --git a/include/nuttx/wireless/ieee802154/ieee802154_radio.h b/include/nuttx/wireless/ieee802154/ieee802154_radio.h index 272d5fdf2c..58748b267a 100644 --- a/include/nuttx/wireless/ieee802154/ieee802154_radio.h +++ b/include/nuttx/wireless/ieee802154/ieee802154_radio.h @@ -180,9 +180,7 @@ struct ieee802154_radiocb_s FAR struct ieee802154_txdesc_s *tx_desc, FAR uint8_t *buf); CODE int (*poll_gts) (FAR struct ieee802154_radiocb_s *radiocb, FAR struct ieee802154_txdesc_s *tx_desc, FAR uint8_t *buf); - CODE int (*txdone_csma) (FAR struct ieee802154_radiocb_s *radiocb, - FAR const struct ieee802154_txdesc_s *tx_desc); - CODE int (*txdone_gts) (FAR struct ieee802154_radiocb_s *radiocb, + CODE int (*txdone) (FAR struct ieee802154_radiocb_s *radiocb, FAR const struct ieee802154_txdesc_s *tx_desc); CODE int (*rx_frame) (FAR struct ieee802154_radiocb_s *radiocb, FAR const struct ieee8021254_rxdesc_s *rx_desc, diff --git a/wireless/ieee802154/mac802154.c b/wireless/ieee802154/mac802154.c index 0977c72b92..51658893c0 100644 --- a/wireless/ieee802154/mac802154.c +++ b/wireless/ieee802154/mac802154.c @@ -105,6 +105,9 @@ struct ieee802154_privmac_s sem_t exclsem; /* Support exclusive access */ + struct work_s tx_work; + struct work_s rx_work; + /* Support a singly linked list of transactions that will be sent using the * CSMA algorithm. On a non-beacon enabled PAN, these transactions will be * sent whenever. On a beacon-enabled PAN, these transactions will be sent @@ -125,6 +128,10 @@ struct ieee802154_privmac_s FAR struct mac802154_trans_s *indirect_head; FAR struct mac802154_trans_s *indirect_tail; + FAR struct ieee802154_txdesc_s *txhead; /* Next TX descriptor to handle */ + FAR struct ieee802154_txdesc_s *txtail; /* Location to push TX descriptor */ + struct ieee802154_txdesc_s txtable[CONFIG_IEEE802154_NTXDESC]; + /* MAC PIB attributes, grouped to save memory */ /* Holds all address information (Extended, Short, and PAN ID) for the MAC. */ @@ -262,6 +269,9 @@ static int mac802154_poll_gts(FAR struct ieee802154_radiocb_s *radiocb, FAR struct ieee802154_txdesc_s *tx_desc, FAR uint8_t *buf); +static int mac802154_txdone(FAR struct ieee802154_radiocb_s *radiocb, + FAR struct ieee802154_txdesc_s *tx_desc); + /**************************************************************************** * Private Data ****************************************************************************/ @@ -325,6 +335,258 @@ static int mac802154_applymib(FAR struct ieee802154_privmac_s *priv) return OK; } +/**************************************************************************** + * Name: mac802154_poll_csma + * + * Description: + * Called from the radio driver through the callback struct. This function is + * called when the radio has room for another CSMA transaction. If the MAC + * layer has a CSMA transaction, it copies it into the supplied buffer and + * returns the length. A descriptor is also populated with the transaction. + * + ****************************************************************************/ + +static int mac802154_poll_csma(FAR struct ieee802154_radiocb_s *radiocb, + FAR struct ieee802154_txdesc_s *tx_desc, + FAR uint8_t *buf) +{ + FAR struct mac802154_radiocb_s *cb = + (FAR struct mac802154_radiocb_s *)radiocb; + FAR struct ieee802154_privmac_s *priv; + FAR struct mac802154_trans_s *trans; + + DEBUGASSERT(cb != NULL && cb->priv != NULL); + priv = cb->priv; + + /* Get exclusive access to the driver structure. We don't care about any + * signals so if we see one, just go back to trying to get access again. + */ + + while (mac802154_takesem(&priv->exclsem) != 0); + + /* Check to see if there are any CSMA transactions waiting */ + + if (priv->csma_head) + { + /* Pop a CSMA transaction off the list */ + + trans = priv->csma_head; + priv->csma_head = priv->csma_head->flink; + + mac802154_givesem(&priv->exclsem); + + /* Setup the transmit descriptor */ + + tx_desc->psdu_handle = trans->msdu_handle; + tx_desc->psdu_length = trans->mhr_len + trans->d_len; + + /* Copy the frame into the buffer */ + + memcpy(&buf[0], trans->mhr_buf, trans->mhr_len); + memcpy(&buf[trans->mhr_len], trans->d_buf, trans->d_len); + + /* Now that we've passed off the data, notify the waiting thread. + * NOTE: The transaction was allocated on the waiting thread's stack so + * it will be automatically deallocated when that thread awakens and + * returns. + */ + + sem_post(&trans->sem); + return tx_desc->psdu_length; + } + + mac802154_givesem(&priv->exclsem); + return 0; +} + +/**************************************************************************** + * Name: mac802154_poll_gts + * + * Description: + * Called from the radio driver through the callback struct. This function is + * called when the radio has room for another GTS transaction. If the MAC + * layer has a GTS transaction, it copies it into the supplied buffer and + * returns the length. A descriptor is also populated with the transaction. + * + ****************************************************************************/ + +static int mac802154_poll_gts(FAR struct ieee802154_radiocb_s *radiocb, + FAR struct ieee802154_txdesc_s *tx_desc, + FAR uint8_t *buf) +{ + FAR struct mac802154_radiocb_s *cb = + (FAR struct mac802154_radiocb_s *)radiocb; + FAR struct ieee802154_privmac_s *priv; + FAR struct mac802154_trans_s *trans; + int ret = 0; + + DEBUGASSERT(cb != NULL && cb->priv != NULL); + priv = cb->priv; + + /* Get exclusive access to the driver structure. We don't care about any + * signals so if we see one, just go back to trying to get access again. + */ + + while (mac802154_takesem(&priv->exclsem) != 0); + +#warning Missing logic. + + mac802154_givesem(&priv->exclsem); + + return 0; +} + +/**************************************************************************** + * Name: mac802154_txdone + * + * Description: + * Called from the radio driver through the callback struct. This function is + * called when the radio has completed a transaction. The txdesc passed gives + * provides information about the completed transaction including the original + * handle provided when the transaction was created and the status of the + * transaction. This function copies the descriptor and schedules work to + * handle the transaction without blocking the radio. + * + ****************************************************************************/ + +static int mac802154_txdone(FAR struct ieee802154_radiocb_s *radiocb, + FAR const struct ieee802154_txdesc_s *tx_desc) +{ + FAR struct mac802154_radiocb_s *cb = + (FAR struct mac802154_radiocb_s *)radiocb; + FAR struct ieee802154_privmac_s *priv; + FAR struct ieee802154_txdesc_s *desc; + int ret = 0; + + DEBUGASSERT(cb != NULL && cb->priv != NULL); + priv = cb->priv; + + /* Get exclusive access to the driver structure. We don't care about any + * signals so if we see one, just go back to trying to get access again. + */ + + while (mac802154_takesem(&priv->exclsem) != 0); + + /* Allocate a tx_desc */ + + desc = kmm_zalloc(sizeof(struct ieee802154_txdesc_s)); + if (desc == NULL) + { + mac802154_givesem(&priv->exclsem); + + return -ENOMEM; + } + + /* Copy the txdesc over and link it into our list */ + + memcpy(desc, tx_desc, sizeof(ieee802154_txdesc_s)); + + /* Link the descriptor */ + +#warning Missing Logic! + + mac802154_givesem(&priv->exclsem); + + /* Schedule work with the work queue to process the completion further */ + + if (work_available(&priv->tx_work)) + { + work_queue(MAC802154_WORK, &priv->tx_work, mac802154_txdone_worker, + (FAR void *)dev, 0); + } +} + +/**************************************************************************** + * Name: mac802154_txdone_worker + * + * Description: + * Worker function scheduled from mac802154_txdone. This function pops any + * TX descriptors off of the list and calls the next highest layers callback + * to inform the layer of the completed transaction and the status of it. + * + ****************************************************************************/ + +static void mac802154_txdone_worker(FAR void *arg) +{ + FAR struct ieee802154_privmanc_s *priv = + (FAR struct ieee802154_privmanc_s *)arg; + + +} + +/**************************************************************************** + * Name: mac802154_rxframe + * + * Description: + * Called from the radio driver through the callback struct. This function is + * called when the radio has received a frame. The frame is passed in an iob, + * so that we can free it when we are done processing. A pointer to the RX + * descriptor is passed along with the iob, but it must be copied here as it + * is allocated directly on the caller's stack. We simply link the frame, + * copy the RX descriptor, and schedule a worker to process the frame later so + * that we do not hold up the radio. + * + ****************************************************************************/ + +static void mac802154_rxframe(FAR struct ieee802154_radiocb_s *radiocb, + FAR struct ieee802154_rxdesc_s *rx_desc, + FAR struct iob_s *frame) +{ + FAR struct mac802154_radiocb_s *cb = + (FAR struct mac802154_radiocb_s *)radiocb; + FAR struct ieee802154_privmac_s *priv; + FAR struct ieee802154_txdesc_s *desc; + int ret = 0; + + DEBUGASSERT(cb != NULL && cb->priv != NULL); + priv = cb->priv; + + /* Get exclusive access to the driver structure. We don't care about any + * signals so if we see one, just go back to trying to get access again. + */ + + while (mac802154_takesem(&priv->exclsem) != 0); + + /* TODO: Copy the frame descriptor to some type of list */ + + /* Push the iob onto the tail of the frame list for processing */ + + priv->rxframes_tail->io_flink = iob; + priv->rxframes_tail = iob; + + mac802154_givesem(&priv->exclsem); + + /* Schedule work with the work queue to process the completion further */ + + if (work_available(&priv->rx_work)) + { + work_queue(MAC802154_WORK, &priv->rx_work, mac802154_rxframe_worker, + (FAR void *)priv, 0); + } +} + +/**************************************************************************** + * Name: mac802154_rxframe_worker + * + * Description: + * Worker function scheduled from mac802154_rxframe. This function processes + * any frames in the list. Frames intended to be consumed by the MAC layer + * will not produce any callbacks to the next highest layer. Frames intended + * for the application layer will be forwarded to them. + * + ****************************************************************************/ + +static void mac802154_rxframe_worker(FAR void *arg) +{ + FAR struct ieee802154_privmac_s *priv = + (FAR struct ieee802154_privmac_s *)arg; + + /* The radio layer is responsible for handling all ACKs and retries. If for + * some reason an ACK gets here, just throw it out */ + +} + + /**************************************************************************** * Public Functions ****************************************************************************/ @@ -379,9 +641,10 @@ MACHANDLE mac802154_create(FAR struct ieee802154_radio_s *radiodev) mac->radiocb.priv = mac; - radiocb = &mac->radiocb.cb; - radiocb->poll_csma = mac802154_poll_csma; - radiocb->poll_gts = mac802154_poll_gts; + radiocb = &mac->radiocb.cb; + radiocb->poll_csma = mac802154_poll_csma; + radiocb->poll_gts = mac802154_poll_gts; + radiocb->txdone = mac802154_txdone; /* Bind our callback structure */ @@ -710,87 +973,6 @@ int mac802154_req_data(MACHANDLE mac, FAR struct ieee802154_data_req_s *req) return OK; } -/* Called from interrupt level or worker thread with interrupts disabled */ - -static int mac802154_poll_csma(FAR struct ieee802154_radiocb_s *radiocb, - FAR struct ieee802154_txdesc_s *tx_desc, - FAR uint8_t *buf) -{ - FAR struct mac802154_radiocb_s *cb = - (FAR struct mac802154_radiocb_s *)radiocb; - FAR struct ieee802154_privmac_s *priv; - FAR struct mac802154_trans_s *trans; - int ret = 0; - - DEBUGASSERT(cb != NULL && cb->priv != NULL); - priv = cb->priv; - - /* Get exclusive access to the driver structure. We don't care about any - * signals so if we see one, just go back to trying to get access again. - */ - - while (mac802154_takesem(&priv->exclsem) != 0); - - /* Check to see if there are any CSMA transactions waiting */ - - if (priv->csma_head) - { - /* Pop a CSMA transaction off the list */ - - trans = priv->csma_head; - priv->csma_head = priv->csma_head->flink; - - /* Setup the transmit descriptor */ - - tx_desc->psdu_handle = trans->msdu_handle; - tx_desc->psdu_length = trans->mhr_len + trans->d_len; - - /* Copy the frame into the buffer */ - - memcpy(&buf[0], trans->mhr_buf, trans->mhr_len); - memcpy(&buf[trans->mhr_len], trans->d_buf, trans->d_len); - - /* Now that we've passed off the data, notify the waiting thread. - * NOTE: The transaction was allocated on the waiting thread's stack so - * it will be automatically deallocated when that thread awakens and - * returns. - */ - - sem_post(&trans->sem); - - ret = tx_desc->psdu_length; - } - - mac802154_givesem(&priv->exclsem); - - return ret; -} - -static int mac802154_poll_gts(FAR struct ieee802154_radiocb_s *radiocb, - FAR struct ieee802154_txdesc_s *tx_desc, - FAR uint8_t *buf) -{ - FAR struct mac802154_radiocb_s *cb = - (FAR struct mac802154_radiocb_s *)radiocb; - FAR struct ieee802154_privmac_s *priv; - FAR struct mac802154_trans_s *trans; - int ret = 0; - - DEBUGASSERT(cb != NULL && cb->priv != NULL); - priv = cb->priv; - - /* Get exclusive access to the driver structure. We don't care about any - * signals so if we see one, just go back to trying to get access again. - */ - - while (mac802154_takesem(&priv->exclsem) != 0); - -#warning Missing logic. - - mac802154_givesem(&priv->exclsem); - - return 0; -} /**************************************************************************** * Name: mac802154_req_purge