From 609934530d3740f4e4a068095e9f0cfeb5da8787 Mon Sep 17 00:00:00 2001 From: Anthony Merlino Date: Mon, 26 Jun 2017 00:36:32 -0400 Subject: [PATCH 01/54] ieee802154: Renames mac802154_indalloc to ieee802154_indalloc since the functions are ieee802154 scoped functions --- wireless/ieee802154/Make.defs | 2 +- .../ieee802154/{mac802154_indalloc.c => ieee802154_indalloc.c} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename wireless/ieee802154/{mac802154_indalloc.c => ieee802154_indalloc.c} (100%) diff --git a/wireless/ieee802154/Make.defs b/wireless/ieee802154/Make.defs index 26705a51a7..18b52f2cf7 100644 --- a/wireless/ieee802154/Make.defs +++ b/wireless/ieee802154/Make.defs @@ -37,7 +37,7 @@ ifeq ($(CONFIG_WIRELESS_IEEE802154),y) # Include IEEE 802.15.4 support -CSRCS += mac802154.c mac802154_indalloc.c mac802154_assoc.c mac802154_disassoc.c +CSRCS += ieee802154_indalloc.c mac802154.c mac802154_assoc.c mac802154_disassoc.c CSRCS += mac802154_bind.c mac802154_data.c mac802154_get_mhrlen.c CSRCS += mac802154_getset.c mac802154_gts.c mac802154_ioctl.c CSRCS += mac802154_notif.c mac802154_orphan.c mac802154_poll.c mac802154_purge.c diff --git a/wireless/ieee802154/mac802154_indalloc.c b/wireless/ieee802154/ieee802154_indalloc.c similarity index 100% rename from wireless/ieee802154/mac802154_indalloc.c rename to wireless/ieee802154/ieee802154_indalloc.c From 3a427d35a3b4604be47c250a46da71b941f42525 Mon Sep 17 00:00:00 2001 From: Anthony Merlino Date: Mon, 26 Jun 2017 00:37:46 -0400 Subject: [PATCH 02/54] ieee802154: Blocks out template code that is not complete to avoid warnings --- wireless/ieee802154/mac802154_disassoc.c | 2 ++ wireless/ieee802154/mac802154_gts.c | 2 ++ wireless/ieee802154/mac802154_orphan.c | 2 ++ wireless/ieee802154/mac802154_sync.c | 2 ++ 4 files changed, 8 insertions(+) diff --git a/wireless/ieee802154/mac802154_disassoc.c b/wireless/ieee802154/mac802154_disassoc.c index ab5a745068..3051132e9d 100644 --- a/wireless/ieee802154/mac802154_disassoc.c +++ b/wireless/ieee802154/mac802154_disassoc.c @@ -73,7 +73,9 @@ int mac802154_req_disassociate(MACHANDLE mac, FAR struct ieee802154_disassoc_req_s *req) { +#if 0 FAR struct ieee802154_privmac_s *priv = (FAR struct ieee802154_privmac_s *)mac; +#endif return -ENOTTY; } \ No newline at end of file diff --git a/wireless/ieee802154/mac802154_gts.c b/wireless/ieee802154/mac802154_gts.c index e24e409f81..97140d7403 100644 --- a/wireless/ieee802154/mac802154_gts.c +++ b/wireless/ieee802154/mac802154_gts.c @@ -66,7 +66,9 @@ int mac802154_req_gts(MACHANDLE mac, FAR struct ieee802154_gts_req_s *req) { +#if 0 FAR struct ieee802154_privmac_s *priv = (FAR struct ieee802154_privmac_s *)mac; +#endif return -ENOTTY; } \ No newline at end of file diff --git a/wireless/ieee802154/mac802154_orphan.c b/wireless/ieee802154/mac802154_orphan.c index 9e4a80d4f2..46a14e7e23 100644 --- a/wireless/ieee802154/mac802154_orphan.c +++ b/wireless/ieee802154/mac802154_orphan.c @@ -65,7 +65,9 @@ int mac802154_resp_orphan(MACHANDLE mac, FAR struct ieee802154_orphan_resp_s *resp) { +#if 0 FAR struct ieee802154_privmac_s *priv = (FAR struct ieee802154_privmac_s *)mac; +#endif return -ENOTTY; } diff --git a/wireless/ieee802154/mac802154_sync.c b/wireless/ieee802154/mac802154_sync.c index fed5e452de..2018a55dd3 100644 --- a/wireless/ieee802154/mac802154_sync.c +++ b/wireless/ieee802154/mac802154_sync.c @@ -71,8 +71,10 @@ int mac802154_req_sync(MACHANDLE mac, FAR struct ieee802154_sync_req_s *req) { +#if 0 FAR struct ieee802154_privmac_s *priv = (FAR struct ieee802154_privmac_s *)mac; +#endif return -ENOTTY; } From ce8f2735ea903f3aff11fc765557fa77796d2c92 Mon Sep 17 00:00:00 2001 From: Anthony Merlino Date: Mon, 26 Jun 2017 00:58:41 -0400 Subject: [PATCH 03/54] ieee802154: Improves notification freeing functionality Each notification now has a number of clients. When the last client calls free, the notification is freed back to the pool --- wireless/ieee802154/mac802154.c | 25 ++------ wireless/ieee802154/mac802154.h | 2 +- wireless/ieee802154/mac802154_assoc.c | 27 +++----- wireless/ieee802154/mac802154_notif.c | 90 +++++++++++++++++---------- wireless/ieee802154/mac802154_notif.h | 4 ++ wireless/ieee802154/mac802154_poll.c | 13 ++-- 6 files changed, 78 insertions(+), 83 deletions(-) diff --git a/wireless/ieee802154/mac802154.c b/wireless/ieee802154/mac802154.c index af5e4523f7..072e439d1d 100644 --- a/wireless/ieee802154/mac802154.c +++ b/wireless/ieee802154/mac802154.c @@ -636,8 +636,8 @@ static void mac802154_purge_worker(FAR void *arg) /* Free the IOB, the notification, and the tx descriptor */ iob_free(txdesc->frame); - ((FAR struct mac802154_notif_s *)txdesc->conf)->flink = priv->notif_free; - priv->notif_free = ((FAR struct mac802154_notif_s *)txdesc->conf); + mac802154_notif_free_locked(priv, + (FAR struct ieee802154_notif_s *)txdesc->conf); mac802154_txdesc_free(priv, txdesc); priv->beaconupdate = true; @@ -760,7 +760,6 @@ static void mac802154_txdone_worker(FAR void *arg) (FAR struct ieee802154_privmac_s *)arg; FAR struct ieee802154_txdesc_s *txdesc; FAR struct ieee802154_notif_s *notif; - FAR struct mac802154_notif_s *privnotif; /* Get exclusive access to the driver structure. We don't care about any * signals so don't allow interruptions @@ -781,8 +780,7 @@ static void mac802154_txdone_worker(FAR void *arg) * notification structure to make it easier to use. */ - privnotif = (FAR struct mac802154_notif_s *)txdesc->conf; - notif = &privnotif->pub; + notif =(FAR struct ieee802154_notif_s *)txdesc->conf; switch(txdesc->frametype) { @@ -857,14 +855,7 @@ static void mac802154_txdone_worker(FAR void *arg) break; default: - /* We can deallocate the data conf notification as it is no - * longer needed. We can't use the public function here - * since we already have the MAC locked. - */ - - privnotif->flink = priv->notif_free; - priv->notif_free = privnotif; - priv->nnotif = 0; + mac802154_notif_free_locked(priv, notif); break; } } @@ -872,13 +863,7 @@ static void mac802154_txdone_worker(FAR void *arg) default: { - /* We can deallocate the data conf notification as it is no longer - * needed. We can't use the public function here since we already - * have the MAC locked. - */ - - privnotif->flink = priv->notif_free; - priv->notif_free = privnotif; + mac802154_notif_free_locked(priv, notif); } break; } diff --git a/wireless/ieee802154/mac802154.h b/wireless/ieee802154/mac802154.h index 90ff021952..01762b2c5f 100644 --- a/wireless/ieee802154/mac802154.h +++ b/wireless/ieee802154/mac802154.h @@ -368,7 +368,7 @@ int mac802154_resp_orphan(MACHANDLE mac, * ****************************************************************************/ -int mac802154_notif_free(MACHANDLE mac, +void mac802154_notif_free(MACHANDLE mac, FAR struct ieee802154_notif_s *notif); #undef EXTERN diff --git a/wireless/ieee802154/mac802154_assoc.c b/wireless/ieee802154/mac802154_assoc.c index 2027013b7a..1df36a60ee 100644 --- a/wireless/ieee802154/mac802154_assoc.c +++ b/wireless/ieee802154/mac802154_assoc.c @@ -402,10 +402,9 @@ void mac802154_txdone_assocreq(FAR struct ieee802154_privmac_s *priv, FAR struct ieee802154_txdesc_s *txdesc) { enum ieee802154_status_e status; - FAR struct mac802154_notif_s *privnotif = - (FAR struct mac802154_notif_s *)txdesc->conf; - FAR struct ieee802154_notif_s *notif = &privnotif->pub; FAR struct ieee802154_txdesc_s *respdesc; + FAR struct ieee802154_notif_s *notif = + (FAR struct ieee802154_notif_s *)txdesc->conf; if(txdesc->conf->status != IEEE802154_STATUS_SUCCESS) { @@ -497,13 +496,9 @@ void mac802154_txdone_assocreq(FAR struct ieee802154_privmac_s *priv, (priv->resp_waittime*IEEE802154_BASE_SUPERFRAME_DURATION)); } - /* We can deallocate the data conf notification as it is no longer - * needed. We can't use the public function here since we already - * have the MAC locked. - */ + /* Deallocate the data conf notification as it is no longer needed. */ - privnotif->flink = priv->notif_free; - priv->notif_free = privnotif; + mac802154_notif_free_locked(priv, notif); } } @@ -524,9 +519,8 @@ void mac802154_txdone_datareq_assoc(FAR struct ieee802154_privmac_s *priv, FAR struct ieee802154_txdesc_s *txdesc) { enum ieee802154_status_e status; - FAR struct mac802154_notif_s *privnotif = - (FAR struct mac802154_notif_s *)txdesc->conf; - FAR struct ieee802154_notif_s *notif = &privnotif->pub; + FAR struct ieee802154_notif_s *notif = + (FAR struct ieee802154_notif_s *)txdesc->conf; /* If the data request failed to be sent, notify the next layer * that the association has failed. @@ -595,14 +589,9 @@ void mac802154_txdone_datareq_assoc(FAR struct ieee802154_privmac_s *priv, mac802154_timerstart(priv, priv->max_frame_waittime, mac802154_assoctimeout); - /* We can deallocate the data conf notification as it is no longer - * needed. We can't use the public function here since we already - * have the MAC locked. - */ + /* Deallocate the data conf notification as it is no longer needed. */ - privnotif->flink = priv->notif_free; - priv->notif_free = privnotif; - mac802154_givesem(&priv->notif_sem); + mac802154_notif_free_locked(priv, notif); } } diff --git a/wireless/ieee802154/mac802154_notif.c b/wireless/ieee802154/mac802154_notif.c index bce299c139..059d95624c 100644 --- a/wireless/ieee802154/mac802154_notif.c +++ b/wireless/ieee802154/mac802154_notif.c @@ -69,44 +69,22 @@ * ****************************************************************************/ -int mac802154_notif_free(MACHANDLE mac, - FAR struct ieee802154_notif_s *notif) +void mac802154_notif_free(MACHANDLE mac, FAR struct ieee802154_notif_s *notif) { FAR struct ieee802154_privmac_s *priv = (FAR struct ieee802154_privmac_s *)mac; - FAR struct mac802154_notif_s *privnotif = - (FAR struct mac802154_notif_s *)notif; - /* Get exclusive access to the MAC */ + /* Lock the MAC */ mac802154_takesem(&priv->exclsem, false); - /* We know how many clients have registered for notifications. Each must - * call mac802154_notif_free() before we can release the notification - * resource. - */ + /* Call the internal helper function to free the notification */ - if (priv->nnotif < 2) - { - /* This is the free from the last notification */ + mac802154_notif_free_locked(priv, notif); - privnotif->flink = priv->notif_free; - priv->notif_free = privnotif; - priv->nnotif = 0; - - mac802154_givesem(&priv->notif_sem); - } - else - { - /* More calls are expected. Decrement the count of expected calls - * and preserve the notification resources. - */ - - priv->nnotif--; - } + /* Unlock the MAC */ mac802154_givesem(&priv->exclsem); - return -ENOTTY; } /**************************************************************************** @@ -184,9 +162,9 @@ int mac802154_notif_alloc(FAR struct ieee802154_privmac_s *priv, if (ret == OK) { - privnotif = priv->notif_free; - priv->notif_free = privnotif->flink; - priv->nnotif = 0; + privnotif = priv->notif_free; + priv->notif_free = privnotif->flink; + privnotif->nclients = 0; } else { @@ -220,9 +198,9 @@ int mac802154_notif_alloc(FAR struct ieee802154_privmac_s *priv, /* We can now safely unlink the next free structure from the free list */ - privnotif = priv->notif_free; - priv->notif_free = privnotif->flink; - priv->nnotif = 0; + privnotif = priv->notif_free; + priv->notif_free = privnotif->flink; + privnotif->nclients = 0; } *notif = (FAR struct ieee802154_notif_s *)privnotif; @@ -230,6 +208,49 @@ int mac802154_notif_alloc(FAR struct ieee802154_privmac_s *priv, return OK; } +/**************************************************************************** + * Name: mac802154_notif_free_locked + * + * Description: + * When the MAC calls the registered callback, it passes a reference + * to a mac802154_notify_s structure. This structure needs to be freed + * after the callback handler is done using it. + * + * Internal version that already has MAC locked + * + ****************************************************************************/ + +void mac802154_notif_free_locked(FAR struct ieee802154_privmac_s * priv, + FAR struct ieee802154_notif_s *notif) +{ + FAR struct mac802154_notif_s *privnotif = + (FAR struct mac802154_notif_s *)notif; + + /* We know how many clients have registered for notifications. Each must + * call mac802154_notif_free() before we can release the notification + * resource. + */ + + if (privnotif->nclients < 2) + { + /* This is the free from the last notification */ + + privnotif->flink = priv->notif_free; + priv->notif_free = privnotif; + privnotif->nclients = 0; + + mac802154_givesem(&priv->notif_sem); + } + else + { + /* More calls are expected. Decrement the count of expected calls + * and preserve the notification resources. + */ + + privnotif->nclients--; + } +} + /**************************************************************************** * Name: mac802154_notify * @@ -242,12 +263,13 @@ void mac802154_notify(FAR struct ieee802154_privmac_s *priv, FAR struct ieee802154_notif_s *notif) { FAR struct mac802154_maccb_s *cb; + FAR struct mac802154_notif_s *privnotif = (FAR struct mac802154_notif_s *)notif; /* Set the notification count so that the notification resources will be * preserved until the final notification. */ - priv->nnotif = priv->nclients; + privnotif->nclients = priv->nclients; /* Try to notify every registered MAC client */ diff --git a/wireless/ieee802154/mac802154_notif.h b/wireless/ieee802154/mac802154_notif.h index 3c6bdd3523..886d786c6b 100644 --- a/wireless/ieee802154/mac802154_notif.h +++ b/wireless/ieee802154/mac802154_notif.h @@ -65,6 +65,7 @@ struct mac802154_notif_s { struct ieee802154_notif_s pub; /* Publically visible structure */ FAR struct mac802154_notif_s *flink; /* Supports a singly linked list */ + uint8_t nclients; }; /**************************************************************************** @@ -82,4 +83,7 @@ int mac802154_notif_alloc(FAR struct ieee802154_privmac_s *priv, void mac802154_notify(FAR struct ieee802154_privmac_s *priv, FAR struct ieee802154_notif_s *notif); +void mac802154_notif_free_locked(FAR struct ieee802154_privmac_s * priv, + FAR struct ieee802154_notif_s *notif); + #endif /* __WIRELESS_IEEE802154__MAC802154_NOTIF_H */ \ No newline at end of file diff --git a/wireless/ieee802154/mac802154_poll.c b/wireless/ieee802154/mac802154_poll.c index e2881a397a..368f8baac2 100644 --- a/wireless/ieee802154/mac802154_poll.c +++ b/wireless/ieee802154/mac802154_poll.c @@ -188,9 +188,8 @@ void mac802154_txdone_datareq_poll(FAR struct ieee802154_privmac_s *priv, FAR struct ieee802154_txdesc_s *txdesc) { enum ieee802154_status_e status; - FAR struct mac802154_notif_s *privnotif = - (FAR struct mac802154_notif_s *)txdesc->conf; - FAR struct ieee802154_notif_s *notif = &privnotif->pub; + FAR struct ieee802154_notif_s *notif = + (FAR struct ieee802154_notif_s *)txdesc->conf; /* If the data request failed to be sent, notify the next layer * that the poll has failed. @@ -245,13 +244,9 @@ void mac802154_txdone_datareq_poll(FAR struct ieee802154_privmac_s *priv, mac802154_timerstart(priv, priv->max_frame_waittime, mac802154_polltimeout); - /* We can deallocate the data conf notification as it is no longer - * needed. We can't use the public function here since we already - * have the MAC locked. - */ + /* Deallocate the data conf notification as it is no longer needed. */ - privnotif->flink = priv->notif_free; - priv->notif_free = privnotif; + mac802154_notif_free_locked(priv, notif); } } From 4349538f922a9dc87837d54c9781b20a2b097eb8 Mon Sep 17 00:00:00 2001 From: Anthony Merlino Date: Mon, 26 Jun 2017 01:27:08 -0400 Subject: [PATCH 04/54] ieee802154: Blocks out a few more sections of template code to avoid warnings --- wireless/ieee802154/mac802154_purge.c | 2 ++ wireless/ieee802154/mac802154_rxenable.c | 2 ++ 2 files changed, 4 insertions(+) diff --git a/wireless/ieee802154/mac802154_purge.c b/wireless/ieee802154/mac802154_purge.c index 6073c61f8c..d32843166d 100644 --- a/wireless/ieee802154/mac802154_purge.c +++ b/wireless/ieee802154/mac802154_purge.c @@ -76,8 +76,10 @@ int mac802154_req_purge(MACHANDLE mac, uint8_t msdu_handle) { +#if 0 FAR struct ieee802154_privmac_s *priv = (FAR struct ieee802154_privmac_s *)mac; +#endif return -ENOTTY; } diff --git a/wireless/ieee802154/mac802154_rxenable.c b/wireless/ieee802154/mac802154_rxenable.c index 683d130e75..1f38689c30 100644 --- a/wireless/ieee802154/mac802154_rxenable.c +++ b/wireless/ieee802154/mac802154_rxenable.c @@ -72,7 +72,9 @@ int mac802154_req_rxenable(MACHANDLE mac, FAR struct ieee802154_rxenable_req_s *req) { +#if 0 FAR struct ieee802154_privmac_s * priv = (FAR struct ieee802154_privmac_s *)mac; +#endif return -ENOTTY; } \ No newline at end of file From 6b17d5ccc97abd949dfcbf52098151ac67537edc Mon Sep 17 00:00:00 2001 From: Anthony Merlino Date: Mon, 26 Jun 2017 01:31:01 -0400 Subject: [PATCH 05/54] ieee802154: Minor changes to align closer with coding standard --- drivers/wireless/ieee802154/mrf24j40.c | 173 +++++++++--------- .../wireless/ieee802154/ieee802154_radio.h | 16 +- wireless/ieee802154/mac802154.c | 4 +- wireless/ieee802154/mac802154_assoc.c | 6 +- wireless/ieee802154/mac802154_getset.c | 4 +- wireless/ieee802154/mac802154_internal.h | 19 +- wireless/ieee802154/mac802154_reset.c | 4 +- wireless/ieee802154/mac802154_scan.c | 4 + wireless/ieee802154/mac802154_start.c | 4 +- 9 files changed, 114 insertions(+), 120 deletions(-) diff --git a/drivers/wireless/ieee802154/mrf24j40.c b/drivers/wireless/ieee802154/mrf24j40.c index b6259099c1..084b59cd2d 100644 --- a/drivers/wireless/ieee802154/mrf24j40.c +++ b/drivers/wireless/ieee802154/mrf24j40.c @@ -201,7 +201,6 @@ static uint8_t mrf24j40_getreg(FAR struct spi_dev_s *spi, uint32_t addr); static int mrf24j40_resetrfsm(FAR struct mrf24j40_radio_s *dev); static int mrf24j40_pacontrol(FAR struct mrf24j40_radio_s *dev, int mode); -static int mrf24j40_initialize(FAR struct mrf24j40_radio_s *dev); static int mrf24j40_setrxmode(FAR struct mrf24j40_radio_s *dev, int mode); static int mrf24j40_regdump(FAR struct mrf24j40_radio_s *dev); @@ -252,20 +251,18 @@ static void mrf24j40_mactimer(FAR struct mrf24j40_radio_s *dev, int numsymbols); static int mrf24j40_bind(FAR struct ieee802154_radio_s *radio, FAR struct ieee802154_radiocb_s *radiocb); -static int mrf24j40_txnotify(FAR struct ieee802154_radio_s *radio, bool gts); -static int mrf24j40_txdelayed(FAR struct ieee802154_radio_s *radio, - FAR struct ieee802154_txdesc_s *txdesc, - uint32_t symboldelay); -static int mrf24j40_reset_attrs(FAR struct ieee802154_radio_s *radio); -static int mrf24j40_get_attr(FAR struct ieee802154_radio_s *radio, +static int mrf24j40_reset(FAR struct ieee802154_radio_s *radio); +static int mrf24j40_getattr(FAR struct ieee802154_radio_s *radio, enum ieee802154_attr_e attr, FAR union ieee802154_attr_u *attrval); -static int mrf24j40_set_attr(FAR struct ieee802154_radio_s *radio, +static int mrf24j40_setattr(FAR struct ieee802154_radio_s *radio, enum ieee802154_attr_e attr, FAR const union ieee802154_attr_u *attrval); +static int mrf24j40_txnotify(FAR struct ieee802154_radio_s *radio, bool gts); +static int mrf24j40_txdelayed(FAR struct ieee802154_radio_s *radio, + FAR struct ieee802154_txdesc_s *txdesc, + uint32_t symboldelay); static int mrf24j40_rxenable(FAR struct ieee802154_radio_s *dev, bool enable); -static int mrf24j40_req_rxenable(FAR struct ieee802154_radio_s *radio, - FAR struct ieee802154_rxenable_req_s *req); static int mrf24j40_beaconstart(FAR struct ieee802154_radio_s *radio, FAR const struct ieee802154_superframespec_s *sfspec, FAR struct ieee802154_beaconframe_s *beacon); @@ -437,18 +434,69 @@ static int mrf24j40_txdelayed(FAR struct ieee802154_radio_s *radio, return OK; } -static int mrf24j40_reset_attrs(FAR struct ieee802154_radio_s *radio) +static int mrf24j40_reset(FAR struct ieee802154_radio_s *radio) { FAR struct mrf24j40_radio_s *dev = (FAR struct mrf24j40_radio_s *)radio; + struct ieee802154_cca_s cca; + + /* Software reset */ + + mrf24j40_setreg(dev->spi, MRF24J40_SOFTRST , 0x07); /* 00000111 Reset */ + while(mrf24j40_getreg(dev->spi, MRF24J40_SOFTRST) & 0x07); + + /* Apply recommended settings */ + + mrf24j40_setreg(dev->spi, MRF24J40_PACON2 , 0x98); /* 10011000 Enable FIFO (default), TXONTS=6 (recommended), TXONT<8:7>=0 */ + mrf24j40_setreg(dev->spi, MRF24J40_TXSTBL , 0x95); /* 10010101 set the SIFS period. RFSTBL=9, MSIFS=5, aMinSIFSPeriod=14 (min 12) */ + mrf24j40_setreg(dev->spi, MRF24J40_TXPEND , 0x7C); /* 01111100 set the LIFS period, MLIFS=1Fh=31 aMinLIFSPeriod=40 (min 40) */ + mrf24j40_setreg(dev->spi, MRF24J40_TXTIME , 0x30); /* 00110000 set the turnaround time, TURNTIME=3 aTurnAroundTime=12 */ + mrf24j40_setreg(dev->spi, MRF24J40_RFCON1 , 0x02); /* 00000010 VCO optimization, recommended value */ + mrf24j40_setreg(dev->spi, MRF24J40_RFCON2 , 0x80); /* 10000000 Enable PLL */ + mrf24j40_setreg(dev->spi, MRF24J40_RFCON6 , 0x90); /* 10010000 TX filter enable, fast 20M recovery, No bat monitor*/ + mrf24j40_setreg(dev->spi, MRF24J40_RFCON7 , 0x80); /* 10000000 Sleep clock on internal 100 kHz */ + mrf24j40_setreg(dev->spi, MRF24J40_RFCON8 , 0x10); /* 00010000 VCO control bit, as recommended */ + mrf24j40_setreg(dev->spi, MRF24J40_SLPCON1, 0x01); /* 00000001 no CLKOUT, default divisor */ + mrf24j40_setreg(dev->spi, MRF24J40_BBREG6 , 0x40); /* 01000000 Append RSSI to rx packets */ + + /* Set this in reset since it can exist for all device modes. See pg 101 */ + + mrf24j40_setreg(dev->spi, MRF24J40_FRMOFFSET, 0x15); + + mrf24j40_setchannel(dev, 11); + mrf24j40_setpanid(dev, g_allones); + mrf24j40_setsaddr(dev, g_allones); + mrf24j40_seteaddr(dev, g_allones); dev->max_frame_waittime = MRF24J40_DEFAULT_MAX_FRAME_WAITTIME; + /* Default device params */ + + cca.use_ed = 1; + cca.use_cs = 0; + cca.edth = 0x60; /* CCA mode ED, no carrier sense, recommenced ED threshold -69 dBm */ + mrf24j40_setcca(dev, &cca); + + mrf24j40_setrxmode(dev, MRF24J40_RXMODE_NORMAL); + + mrf24j40_settxpower(dev, 0); /*16. Set transmitter power .*/ + + mrf24j40_pacontrol(dev, MRF24J40_PA_AUTO); + + dev->rxenabled = false; + + /* For now, we want to always just have the frame pending bit set when + * acknowledging a Data Request command. The standard says that the coordinator + * can do this if it needs time to figure out whether it has data or not + */ + + mrf24j40_setreg(dev->spi, MRF24J40_ACKTMOUT, 0x39 | MRF24J40_ACKTMOUT_DRPACK); + return OK; } -static int mrf24j40_get_attr(FAR struct ieee802154_radio_s *radio, - enum ieee802154_attr_e attr, - FAR union ieee802154_attr_u *attrval) +static int mrf24j40_getattr(FAR struct ieee802154_radio_s *radio, + enum ieee802154_attr_e attr, + FAR union ieee802154_attr_u *attrval) { FAR struct mrf24j40_radio_s *dev = (FAR struct mrf24j40_radio_s *)radio; int ret; @@ -489,9 +537,9 @@ static int mrf24j40_get_attr(FAR struct ieee802154_radio_s *radio, return ret; } -static int mrf24j40_set_attr(FAR struct ieee802154_radio_s *radio, - enum ieee802154_attr_e attr, - FAR const union ieee802154_attr_u *attrval) +static int mrf24j40_setattr(FAR struct ieee802154_radio_s *radio, + enum ieee802154_attr_e attr, + FAR const union ieee802154_attr_u *attrval) { FAR struct mrf24j40_radio_s *dev = (FAR struct mrf24j40_radio_s *)radio; int ret; @@ -567,16 +615,9 @@ static int mrf24j40_set_attr(FAR struct ieee802154_radio_s *radio, ret = IEEE802154_STATUS_UNSUPPORTED_ATTRIBUTE; break; } - return ret; } -static int mrf24j40_req_rxenable(FAR struct ieee802154_radio_s *radio, - FAR struct ieee802154_rxenable_req_s *req) -{ - return -ENOTTY; -} - static int mrf24j40_beaconstart(FAR struct ieee802154_radio_s *radio, FAR const struct ieee802154_superframespec_s *sfspec, FAR struct ieee802154_beaconframe_s *beacon) @@ -727,6 +768,21 @@ static int mrf24j40_sfupdate(FAR struct ieee802154_radio_s *radio, FAR struct mrf24j40_radio_s *dev = (FAR struct mrf24j40_radio_s *)radio; int reg; + /* If we are operating on a beacon-enabled network, use slotted CSMA */ + + if (sfspec->beaconorder < 15) + { + reg = mrf24j40_getreg(dev->spi, MRF24J40_TXMCR); + reg |= MRF24J40_TXMCR_SLOTTED; + mrf24j40_setreg(dev->spi, MRF24J40_TXMCR, reg); + } + else + { + reg = mrf24j40_getreg(dev->spi, MRF24J40_TXMCR); + reg &= ~MRF24J40_TXMCR_SLOTTED; + mrf24j40_setreg(dev->spi, MRF24J40_TXMCR, reg); + } + reg = mrf24j40_getreg(dev->spi, MRF24J40_RXMCR); if (sfspec->pancoord) @@ -1080,38 +1136,6 @@ static int mrf24j40_pacontrol(FAR struct mrf24j40_radio_s *dev, int mode) return OK; } -/**************************************************************************** - * Name: mrf24j40_initialize - * - * Description: - * Reset the device and put in in order of operation - * - ****************************************************************************/ - -static int mrf24j40_initialize(FAR struct mrf24j40_radio_s *dev) -{ - /* Software reset */ - - mrf24j40_setreg(dev->spi, MRF24J40_SOFTRST , 0x07); /* 00000111 Reset */ - while(mrf24j40_getreg(dev->spi, MRF24J40_SOFTRST) & 0x07); - - /* Apply recommended settings */ - - mrf24j40_setreg(dev->spi, MRF24J40_PACON2 , 0x98); /* 10011000 Enable FIFO (default), TXONTS=6 (recommended), TXONT<8:7>=0 */ - mrf24j40_setreg(dev->spi, MRF24J40_TXSTBL , 0x95); /* 10010101 set the SIFS period. RFSTBL=9, MSIFS=5, aMinSIFSPeriod=14 (min 12) */ - mrf24j40_setreg(dev->spi, MRF24J40_TXPEND , 0x7C); /* 01111100 set the LIFS period, MLIFS=1Fh=31 aMinLIFSPeriod=40 (min 40) */ - mrf24j40_setreg(dev->spi, MRF24J40_TXTIME , 0x30); /* 00110000 set the turnaround time, TURNTIME=3 aTurnAroundTime=12 */ - mrf24j40_setreg(dev->spi, MRF24J40_RFCON1 , 0x02); /* 00000010 VCO optimization, recommended value */ - mrf24j40_setreg(dev->spi, MRF24J40_RFCON2 , 0x80); /* 10000000 Enable PLL */ - mrf24j40_setreg(dev->spi, MRF24J40_RFCON6 , 0x90); /* 10010000 TX filter enable, fast 20M recovery, No bat monitor*/ - mrf24j40_setreg(dev->spi, MRF24J40_RFCON7 , 0x80); /* 10000000 Sleep clock on internal 100 kHz */ - mrf24j40_setreg(dev->spi, MRF24J40_RFCON8 , 0x10); /* 00010000 VCO control bit, as recommended */ - mrf24j40_setreg(dev->spi, MRF24J40_SLPCON1, 0x01); /* 00000001 no CLKOUT, default divisor */ - mrf24j40_setreg(dev->spi, MRF24J40_BBREG6 , 0x40); /* 01000000 Append RSSI to rx packets */ - - return OK; -} - /**************************************************************************** * Name: mrf24j40_setrxmode * @@ -2155,7 +2179,6 @@ FAR struct ieee802154_radio_s *mrf24j40_init(FAR struct spi_dev_s *spi, FAR const struct mrf24j40_lower_s *lower) { FAR struct mrf24j40_radio_s *dev; - struct ieee802154_cca_s cca; dev = kmm_zalloc(sizeof(struct mrf24j40_radio_s)); if (dev == NULL) @@ -2178,13 +2201,12 @@ FAR struct ieee802154_radio_s *mrf24j40_init(FAR struct spi_dev_s *spi, sem_init(&dev->exclsem, 0, 1); dev->radio.bind = mrf24j40_bind; + dev->radio.reset = mrf24j40_reset; + dev->radio.getattr = mrf24j40_getattr; + dev->radio.setattr = mrf24j40_setattr; dev->radio.txnotify = mrf24j40_txnotify; dev->radio.txdelayed = mrf24j40_txdelayed; - dev->radio.reset_attrs = mrf24j40_reset_attrs; - dev->radio.get_attr = mrf24j40_get_attr; - dev->radio.set_attr = mrf24j40_set_attr; dev->radio.rxenable = mrf24j40_rxenable; - dev->radio.req_rxenable = mrf24j40_req_rxenable; dev->radio.beaconstart = mrf24j40_beaconstart; dev->radio.beaconupdate = mrf24j40_beaconupdate; dev->radio.beaconstop = mrf24j40_beaconstop; @@ -2193,34 +2215,7 @@ FAR struct ieee802154_radio_s *mrf24j40_init(FAR struct spi_dev_s *spi, dev->lower = lower; dev->spi = spi; - - dev->rxenabled = false; - mrf24j40_initialize(dev); - - mrf24j40_setchannel(dev, 11); - mrf24j40_setpanid(dev, g_allones); - mrf24j40_setsaddr(dev, g_allones); - mrf24j40_seteaddr(dev, g_allones); - - /* Default device params */ - - cca.use_ed = 1; - cca.use_cs = 0; - cca.edth = 0x60; /* CCA mode ED, no carrier sense, recommenced ED threshold -69 dBm */ - mrf24j40_setcca(dev, &cca); - - mrf24j40_setrxmode(dev, MRF24J40_RXMODE_NORMAL); - - mrf24j40_settxpower(dev, 0); /*16. Set transmitter power .*/ - - mrf24j40_pacontrol(dev, MRF24J40_PA_AUTO); - - /* For now, we want to always just have the frame pending bit set when - * acknowledging a Data Request command. The standard says that the coordinator - * can do this if it needs time to figure out whether it has data or not - */ - - mrf24j40_setreg(dev->spi, MRF24J40_ACKTMOUT, 0x39 | MRF24J40_ACKTMOUT_DRPACK); + mrf24j40_reset(&dev->radio); dev->lower->enable(dev->lower, true); return &dev->radio; diff --git a/include/nuttx/wireless/ieee802154/ieee802154_radio.h b/include/nuttx/wireless/ieee802154/ieee802154_radio.h index 8f851ffe72..b6e802e0ea 100644 --- a/include/nuttx/wireless/ieee802154/ieee802154_radio.h +++ b/include/nuttx/wireless/ieee802154/ieee802154_radio.h @@ -119,20 +119,18 @@ struct ieee802154_radio_s { CODE int (*bind) (FAR struct ieee802154_radio_s *radio, FAR struct ieee802154_radiocb_s *radiocb); + CODE int (*reset) (FAR struct ieee802154_radio_s *radio); + CODE int (*getattr) (FAR struct ieee802154_radio_s *radio, + enum ieee802154_attr_e , + FAR union ieee802154_attr_u *attrval); + CODE int (*setattr) (FAR struct ieee802154_radio_s *radio, + enum ieee802154_attr_e , + FAR const union ieee802154_attr_u *attrval); CODE int (*txnotify)(FAR struct ieee802154_radio_s *radio, bool gts); CODE int (*txdelayed)(FAR struct ieee802154_radio_s *radio, FAR struct ieee802154_txdesc_s *txdesc, uint32_t symboldelay); - CODE int (*reset_attrs) (FAR struct ieee802154_radio_s *radio); - CODE int (*get_attr) (FAR struct ieee802154_radio_s *radio, - enum ieee802154_attr_e , - FAR union ieee802154_attr_u *attrval); - CODE int (*set_attr) (FAR struct ieee802154_radio_s *radio, - enum ieee802154_attr_e , - FAR const union ieee802154_attr_u *attrval); CODE int (*rxenable) (FAR struct ieee802154_radio_s *radio, bool enable); - CODE int (*req_rxenable)(FAR struct ieee802154_radio_s *radio, - FAR struct ieee802154_rxenable_req_s *req); CODE int (*beaconstart)(FAR struct ieee802154_radio_s *radio, FAR const struct ieee802154_superframespec_s *sfspec, FAR struct ieee802154_beaconframe_s *beacon); diff --git a/wireless/ieee802154/mac802154.c b/wireless/ieee802154/mac802154.c index 072e439d1d..7e0935025c 100644 --- a/wireless/ieee802154/mac802154.c +++ b/wireless/ieee802154/mac802154.c @@ -1726,7 +1726,7 @@ static uint32_t mac802154_symtoticks(FAR struct ieee802154_privmac_s *priv, * get overall times. */ - priv->radio->get_attr(priv->radio, IEEE802154_ATTR_PHY_SYMBOL_DURATION, + priv->radio->getattr(priv->radio, IEEE802154_ATTR_PHY_SYMBOL_DURATION, &attrval); /* After this step, ret represents microseconds */ @@ -1912,7 +1912,7 @@ MACHANDLE mac802154_create(FAR struct ieee802154_radio_s *radiodev) } IEEE802154_EADDRCOPY(mac->addr.eaddr, eaddr); - mac->radio->set_attr(mac->radio, IEEE802154_ATTR_MAC_EADDR, + mac->radio->setattr(mac->radio, IEEE802154_ATTR_MAC_EADDR, (union ieee802154_attr_u *)&eaddr[0]); return (MACHANDLE)mac; diff --git a/wireless/ieee802154/mac802154_assoc.c b/wireless/ieee802154/mac802154_assoc.c index 1df36a60ee..ff198b7e9b 100644 --- a/wireless/ieee802154/mac802154_assoc.c +++ b/wireless/ieee802154/mac802154_assoc.c @@ -127,8 +127,6 @@ int mac802154_req_associate(MACHANDLE mac, mac802154_setcoordaddr(priv, &req->coordaddr); - /* TODO: Need to send coordinator address to radio layer */ - /* Copy the coordinator PAN ID to our PAN ID */ mac802154_setpanid(priv, req->coordaddr.panid); @@ -146,7 +144,7 @@ int mac802154_req_associate(MACHANDLE mac, */ rxonidle = req->capabilities.rxonidle; - priv->radio->set_attr(priv->radio, IEEE802154_ATTR_MAC_RX_ON_WHEN_IDLE, + priv->radio->setattr(priv->radio, IEEE802154_ATTR_MAC_RX_ON_WHEN_IDLE, (FAR const union ieee802154_attr_u *)&rxonidle); /* Allocate an IOB to put the frame in */ @@ -709,7 +707,7 @@ void mac802154_rx_assocresp(FAR struct ieee802154_privmac_s *priv, /* Inform the radio of the address change */ - priv->radio->set_attr(priv->radio, IEEE802154_ATTR_MAC_SADDR, + priv->radio->setattr(priv->radio, IEEE802154_ATTR_MAC_SADDR, (FAR union ieee802154_attr_u *)priv->addr.saddr); /* A Short Address field value equal to 0xfffe shall indicate that the device diff --git a/wireless/ieee802154/mac802154_getset.c b/wireless/ieee802154/mac802154_getset.c index b1c29f7191..1a43125cb6 100644 --- a/wireless/ieee802154/mac802154_getset.c +++ b/wireless/ieee802154/mac802154_getset.c @@ -106,7 +106,7 @@ int mac802154_req_get(MACHANDLE mac, enum ieee802154_attr_e attr, * it along. */ - ret = priv->radio->get_attr(priv->radio, attr, attrval); + ret = priv->radio->getattr(priv->radio, attr, attrval); break; } @@ -180,7 +180,7 @@ int mac802154_req_set(MACHANDLE mac, enum ieee802154_attr_e attr, * it along. */ - ret = priv->radio->set_attr(priv->radio, attr, attrval); + ret = priv->radio->setattr(priv->radio, attr, attrval); } break; } diff --git a/wireless/ieee802154/mac802154_internal.h b/wireless/ieee802154/mac802154_internal.h index aa19f79f60..be3cb8ebcd 100644 --- a/wireless/ieee802154/mac802154_internal.h +++ b/wireless/ieee802154/mac802154_internal.h @@ -156,7 +156,6 @@ struct ieee802154_privmac_s sem_t exclsem; /* Support exclusive access */ uint8_t nclients; /* Number of notification clients */ - uint8_t nnotif; /* Number of remaining notifications */ /* Only support a single command at any given time. As of now I see no * condition where you need to have more than one command frame simultaneously @@ -642,14 +641,14 @@ static inline void mac802154_rxdisable(FAR struct ieee802154_privmac_s *priv) static inline void mac802154_setchannel(FAR struct ieee802154_privmac_s *priv, uint8_t channel) { - priv->radio->set_attr(priv->radio, IEEE802154_ATTR_PHY_CHAN, + priv->radio->setattr(priv->radio, IEEE802154_ATTR_PHY_CHAN, (FAR const union ieee802154_attr_u *)&channel); } static inline void mac802154_setchpage(FAR struct ieee802154_privmac_s *priv, uint8_t chpage) { - priv->radio->set_attr(priv->radio, IEEE802154_ATTR_PHY_CURRENT_PAGE, + priv->radio->setattr(priv->radio, IEEE802154_ATTR_PHY_CURRENT_PAGE, (FAR const union ieee802154_attr_u *)&chpage); } @@ -657,7 +656,7 @@ static inline void mac802154_setpanid(FAR struct ieee802154_privmac_s *priv, const uint8_t *panid) { IEEE802154_PANIDCOPY(priv->addr.panid, panid); - priv->radio->set_attr(priv->radio, IEEE802154_ATTR_MAC_PANID, + priv->radio->setattr(priv->radio, IEEE802154_ATTR_MAC_PANID, (FAR const union ieee802154_attr_u *)panid); } @@ -665,7 +664,7 @@ static inline void mac802154_setsaddr(FAR struct ieee802154_privmac_s *priv, const uint8_t *saddr) { IEEE802154_SADDRCOPY(priv->addr.saddr, saddr); - priv->radio->set_attr(priv->radio, IEEE802154_ATTR_MAC_SADDR, + priv->radio->setattr(priv->radio, IEEE802154_ATTR_MAC_SADDR, (FAR const union ieee802154_attr_u *)saddr); } @@ -673,7 +672,7 @@ static inline void mac802154_seteaddr(FAR struct ieee802154_privmac_s *priv, const uint8_t *eaddr) { IEEE802154_EADDRCOPY(priv->addr.eaddr, eaddr); - priv->radio->set_attr(priv->radio, IEEE802154_ATTR_MAC_EADDR, + priv->radio->setattr(priv->radio, IEEE802154_ATTR_MAC_EADDR, (FAR const union ieee802154_attr_u *)eaddr); } @@ -681,7 +680,7 @@ static inline void mac802154_setcoordsaddr(FAR struct ieee802154_privmac_s *priv const uint8_t *saddr) { IEEE802154_SADDRCOPY(priv->pandesc.coordaddr.saddr, saddr); - priv->radio->set_attr(priv->radio, IEEE802154_ATTR_MAC_COORD_SADDR, + priv->radio->setattr(priv->radio, IEEE802154_ATTR_MAC_COORD_SADDR, (FAR const union ieee802154_attr_u *)saddr); } @@ -689,7 +688,7 @@ static inline void mac802154_setcoordeaddr(FAR struct ieee802154_privmac_s *priv const uint8_t *eaddr) { IEEE802154_EADDRCOPY(priv->pandesc.coordaddr.eaddr, eaddr); - priv->radio->set_attr(priv->radio, IEEE802154_ATTR_MAC_COORD_EADDR, + priv->radio->setattr(priv->radio, IEEE802154_ATTR_MAC_COORD_EADDR, (FAR const union ieee802154_attr_u *)eaddr); } @@ -697,9 +696,9 @@ static inline void mac802154_setcoordaddr(FAR struct ieee802154_privmac_s *priv, FAR const struct ieee802154_addr_s *addr) { memcpy(&priv->pandesc.coordaddr, addr, sizeof(struct ieee802154_addr_s)); - priv->radio->set_attr(priv->radio, IEEE802154_ATTR_MAC_COORD_EADDR, + priv->radio->setattr(priv->radio, IEEE802154_ATTR_MAC_COORD_EADDR, (FAR const union ieee802154_attr_u *)addr->eaddr); - priv->radio->set_attr(priv->radio, IEEE802154_ATTR_MAC_COORD_SADDR, + priv->radio->setattr(priv->radio, IEEE802154_ATTR_MAC_COORD_SADDR, (FAR const union ieee802154_attr_u *)addr->saddr); } diff --git a/wireless/ieee802154/mac802154_reset.c b/wireless/ieee802154/mac802154_reset.c index 759a44e31e..870a4bbe1b 100644 --- a/wireless/ieee802154/mac802154_reset.c +++ b/wireless/ieee802154/mac802154_reset.c @@ -125,14 +125,14 @@ int mac802154_req_reset(MACHANDLE mac, bool rst_pibattr) IEEE802154_SADDRCOPY(priv->addr.saddr, &IEEE802154_SADDR_UNSPEC); IEEE802154_EADDRCOPY(priv->addr.eaddr, &IEEE802154_EADDR_UNSPEC); - priv->radio->reset_attrs(priv->radio); + priv->radio->reset(priv->radio); /* The radio is in control of certain attributes, but we keep a mirror * for easy access. Copy in the radio's values now that they've been * reset. */ - priv->radio->get_attr(priv->radio, IEEE802154_ATTR_MAC_MAX_FRAME_WAITTIME, + priv->radio->getattr(priv->radio, IEEE802154_ATTR_MAC_MAX_FRAME_WAITTIME, &attr); priv->max_frame_waittime = attr.mac.max_frame_waittime; diff --git a/wireless/ieee802154/mac802154_scan.c b/wireless/ieee802154/mac802154_scan.c index d333d72d3c..819ac141f8 100644 --- a/wireless/ieee802154/mac802154_scan.c +++ b/wireless/ieee802154/mac802154_scan.c @@ -93,6 +93,8 @@ int mac802154_req_scan(MACHANDLE mac, FAR struct ieee802154_scan_req_s *req) goto errout; } + wlinfo("MLME: SCAN.request received\n"); + /* Need to get access to the ops semaphore since operations are serial. This * must be done before locking the MAC so that we don't hold the MAC */ @@ -126,6 +128,8 @@ int mac802154_req_scan(MACHANDLE mac, FAR struct ieee802154_scan_req_s *req) { case IEEE802154_SCANTYPE_PASSIVE: { + wlinfo("MLME: Starting Passive scan\n"); + /* Set the channel to the first channel in the list */ mac802154_setchannel(priv, req->channels[priv->scanindex]); diff --git a/wireless/ieee802154/mac802154_start.c b/wireless/ieee802154/mac802154_start.c index b3675393e2..5a9c4379ea 100644 --- a/wireless/ieee802154/mac802154_start.c +++ b/wireless/ieee802154/mac802154_start.c @@ -101,9 +101,9 @@ int mac802154_req_start(MACHANDLE mac, FAR struct ieee802154_start_req_s *req) /* Tell the radio layer to set the channel number and channel page */ - priv->radio->set_attr(priv->radio, IEEE802154_ATTR_PHY_CHAN, + priv->radio->setattr(priv->radio, IEEE802154_ATTR_PHY_CHAN, (FAR const union ieee802154_attr_u *)&req->chan); - priv->radio->set_attr(priv->radio, IEEE802154_ATTR_PHY_CURRENT_PAGE, + priv->radio->setattr(priv->radio, IEEE802154_ATTR_PHY_CURRENT_PAGE, (FAR const union ieee802154_attr_u *)&req->chpage); /* The address used in the Source Address field of the beacon frame shall From b981ced4d4723c1545e9a5f06fbd610312d588d1 Mon Sep 17 00:00:00 2001 From: Anthony Merlino Date: Tue, 27 Jun 2017 22:01:40 -0400 Subject: [PATCH 06/54] ieee802154: Finishes beacon association functionality --- drivers/wireless/ieee802154/mrf24j40.c | 4454 +++++++++-------- .../wireless/ieee802154/ieee802154_mac.h | 62 +- wireless/ieee802154/mac802154.c | 389 +- wireless/ieee802154/mac802154_assoc.c | 63 +- wireless/ieee802154/mac802154_netdev.c | 10 +- 5 files changed, 2590 insertions(+), 2388 deletions(-) diff --git a/drivers/wireless/ieee802154/mrf24j40.c b/drivers/wireless/ieee802154/mrf24j40.c index 084b59cd2d..538d140861 100644 --- a/drivers/wireless/ieee802154/mrf24j40.c +++ b/drivers/wireless/ieee802154/mrf24j40.c @@ -1,2222 +1,2232 @@ -/**************************************************************************** - * drivers/wireless/ieee802154/mrf24j40.c - * - * Copyright (C) 2015-2016 Sebastien Lorquet. All rights reserved. - * Copyright (C) 2017 Verge Inc. All rights reserved. - * Author: Sebastien Lorquet - * Author: Anthony Merlino - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * 3. Neither the name NuttX nor the names of its contributors may be - * used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS - * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED - * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - ****************************************************************************/ - -/**************************************************************************** - * Included Files - ****************************************************************************/ - -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -#include - -#include -#include -#include - -#include "mrf24j40.h" - -/**************************************************************************** - * Pre-processor Definitions - ****************************************************************************/ - -#ifndef CONFIG_SCHED_HPWORK -# error High priority work queue required in this driver -#endif - -#ifndef CONFIG_IEEE802154_MRF24J40_SPIMODE -# define CONFIG_IEEE802154_MRF24J40_SPIMODE SPIDEV_MODE0 -#endif - -#ifndef CONFIG_IEEE802154_MRF24J40_FREQUENCY -# define CONFIG_IEEE802154_MRF24J40_FREQUENCY 8000000 -#endif - -#ifndef CONFIG_SPI_EXCHANGE -# error CONFIG_SPI_EXCHANGE required for this driver -#endif - -/* Definitions for the device structure */ - -#define MRF24J40_RXMODE_NORMAL 0 -#define MRF24J40_RXMODE_PROMISC 1 -#define MRF24J40_RXMODE_NOCRC 2 - -#define MRF24J40_MODE_DEVICE 0 -#define MRF24J40_MODE_COORD 1 -#define MRF24J40_MODE_PANCOORD 2 - -/* Definitions for PA control on high power modules */ - -#define MRF24J40_PA_AUTO 1 -#define MRF24J40_PA_ED 2 -#define MRF24J40_PA_SLEEP 3 - -#define MRF24J40_GTS_SLOTS 2 - -/* Clock configuration macros */ - -#define MRF24J40_SLPCLKPER_100KHZ ((1000 * 1000 * 1000)/100000) /* 10ns */ -#define MRF24J40_SLPCLKPER_32KHZ ((1000 * 1000 * 1000)/32000) /* 31.25ns */ - -#define MRF24J40_BEACONINTERVAL_NSEC(beaconorder) \ - (IEEE802154_BASE_SUPERFRAME_DURATION * (1 << beaconorder) * (16 *1000)) - -/* For now I am just setting the REMCNT to the maximum while staying in multiples - * of 10000 (100khz period) */ - -#define MRF24J40_REMCNT 60000 -#define MRF24J40_REMCNT_NSEC (MRF24J40_REMCNT * 50) - -#define MRF24J40_MAINCNT(bo, clkper) \ - ((MRF24J40_BEACONINTERVAL_NSEC(bo) - MRF24J40_REMCNT_NSEC) / \ - clkper) - -/* Formula for calculating default macMaxFrameWaitTime is on pg. 130 - * - * For PHYs other than CSS and UWB, the attribute phyMaxFrameDuration is given by: - * - * phyMaxFrameDuration = phySHRDuration + - * ceiling([aMaxPHYPacketSize + 1] x phySymbolsPerOctet) - * - * where ceiling() is a function that returns the smallest integer value greater - * than or equal to its argument value. [1] pg. 158 -*/ - -#define MRF24J40_DEFAULT_MAX_FRAME_WAITTIME 1824 - -#define MRF24J40_SYMBOL_DURATION_PS 16000000 - -/**************************************************************************** - * Private Types - ****************************************************************************/ - -/* A MRF24J40 device instance */ - -struct mrf24j40_radio_s -{ - struct ieee802154_radio_s radio; /* The public device instance */ - FAR struct ieee802154_radiocb_s *radiocb; /* Registered callbacks */ - - /* MAC Attributes */ - - bool rxonidle : 1; - - /* Low-level MCU-specific support */ - - FAR const struct mrf24j40_lower_s *lower; - FAR struct spi_dev_s *spi; /* Saved SPI interface instance */ - - struct work_s irqwork; /* For deferring interrupt work to work queue */ - struct work_s csma_pollwork; /* For deferring poll work to the work queue */ - struct work_s gts_pollwork; /* For deferring poll work to the work queue */ - - sem_t exclsem; /* Exclusive access to this struct */ - - struct ieee802154_addr_s addr; - - uint8_t chan; /* 11 to 26 for the 2.4 GHz band */ - uint8_t devmode; /* device mode: device, coord, pancoord */ - uint8_t paenabled; /* enable usage of PA */ - uint8_t rxmode; /* Reception mode: Main, no CRC, promiscuous */ - int32_t txpower; /* TX power in mBm = dBm/100 */ - struct ieee802154_cca_s cca; /* Clear channel assessement method */ - - /* MAC PIB attributes */ - - uint32_t max_frame_waittime; - - struct ieee802154_txdesc_s *txdelayed_desc; - struct ieee802154_txdesc_s *csma_desc; - bool txdelayed_busy : 1; - bool csma_busy : 1; - bool reschedule_csma : 1; - - bool rxenabled : 1; - - struct ieee802154_txdesc_s *gts_desc[MRF24J40_GTS_SLOTS]; - bool gts_busy[MRF24J40_GTS_SLOTS]; -}; - -/**************************************************************************** - * Private Function Prototypes - ****************************************************************************/ - -/* Internal operations */ - -static void mrf24j40_spi_lock(FAR struct spi_dev_s *spi); - -static void mrf24j40_setreg(FAR struct spi_dev_s *spi, uint32_t addr, - uint8_t val); -static uint8_t mrf24j40_getreg(FAR struct spi_dev_s *spi, uint32_t addr); - -static int mrf24j40_resetrfsm(FAR struct mrf24j40_radio_s *dev); -static int mrf24j40_pacontrol(FAR struct mrf24j40_radio_s *dev, int mode); - -static int mrf24j40_setrxmode(FAR struct mrf24j40_radio_s *dev, int mode); -static int mrf24j40_regdump(FAR struct mrf24j40_radio_s *dev); - -static void mrf24j40_irqwork_rx(FAR struct mrf24j40_radio_s *dev); -static void mrf24j40_irqwork_txnorm(FAR struct mrf24j40_radio_s *dev); -static void mrf24j40_irqwork_txgts(FAR struct mrf24j40_radio_s *dev, - uint8_t gts_num); - -static void mrf24j40_irqworker(FAR void *arg); -static int mrf24j40_interrupt(int irq, FAR void *context, FAR void *arg); - -static void mrf24j40_dopoll_csma(FAR void *arg); -static void mrf24j40_dopoll_gts(FAR void *arg); - -static void mrf24j40_norm_setup(FAR struct mrf24j40_radio_s *dev, - FAR struct iob_s *frame, bool csma); -static void mrf24j40_gts_setup(FAR struct mrf24j40_radio_s *dev, uint8_t gts, - FAR struct iob_s *frame); -static void mrf24j40_setup_fifo(FAR struct mrf24j40_radio_s *dev, - FAR const uint8_t *buf, uint8_t length, uint32_t fifo_addr); - -static inline void mrf24j40_norm_trigger(FAR struct mrf24j40_radio_s *dev); - -static int mrf24j40_setchannel(FAR struct mrf24j40_radio_s *dev, - uint8_t chan); -static int mrf24j40_setpanid(FAR struct mrf24j40_radio_s *dev, - FAR const uint8_t *panid); -static int mrf24j40_setsaddr(FAR struct mrf24j40_radio_s *dev, - FAR const uint8_t *saddr); -static int mrf24j40_seteaddr(FAR struct mrf24j40_radio_s *dev, - FAR const uint8_t *eaddr); -static int mrf24j40_setcoordsaddr(FAR struct mrf24j40_radio_s *dev, - FAR const uint8_t *saddr); -static int mrf24j40_setcoordeaddr(FAR struct mrf24j40_radio_s *dev, - FAR const uint8_t *eaddr); -static int mrf24j40_setdevmode(FAR struct mrf24j40_radio_s *dev, - uint8_t mode); -static int mrf24j40_settxpower(FAR struct mrf24j40_radio_s *dev, - int32_t txpwr); -static int mrf24j40_setcca(FAR struct mrf24j40_radio_s *dev, - FAR struct ieee802154_cca_s *cca); -static int mrf24j40_energydetect(FAR struct mrf24j40_radio_s *dev, - FAR uint8_t *energy); -static void mrf24j40_mactimer(FAR struct mrf24j40_radio_s *dev, int numsymbols); - -/* Driver operations */ - -static int mrf24j40_bind(FAR struct ieee802154_radio_s *radio, - FAR struct ieee802154_radiocb_s *radiocb); -static int mrf24j40_reset(FAR struct ieee802154_radio_s *radio); -static int mrf24j40_getattr(FAR struct ieee802154_radio_s *radio, - enum ieee802154_attr_e attr, - FAR union ieee802154_attr_u *attrval); -static int mrf24j40_setattr(FAR struct ieee802154_radio_s *radio, - enum ieee802154_attr_e attr, - FAR const union ieee802154_attr_u *attrval); -static int mrf24j40_txnotify(FAR struct ieee802154_radio_s *radio, bool gts); -static int mrf24j40_txdelayed(FAR struct ieee802154_radio_s *radio, - FAR struct ieee802154_txdesc_s *txdesc, - uint32_t symboldelay); -static int mrf24j40_rxenable(FAR struct ieee802154_radio_s *dev, bool enable); -static int mrf24j40_beaconstart(FAR struct ieee802154_radio_s *radio, - FAR const struct ieee802154_superframespec_s *sfspec, - FAR struct ieee802154_beaconframe_s *beacon); -static int mrf24j40_beaconupdate(FAR struct ieee802154_radio_s *radio, - FAR struct ieee802154_beaconframe_s *beacon); -static int mrf24j40_beaconstop(FAR struct ieee802154_radio_s *radio); -static int mrf24j40_sfupdate(FAR struct ieee802154_radio_s *radio, - FAR const struct ieee802154_superframespec_s *sfspec); - -/**************************************************************************** - * Private Data - ****************************************************************************/ - -static const uint8_t g_allones[8] = -{ - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF -}; - -/**************************************************************************** - * Radio Interface Functions - ****************************************************************************/ - -static int mrf24j40_bind(FAR struct ieee802154_radio_s *radio, - FAR struct ieee802154_radiocb_s *radiocb) -{ - FAR struct mrf24j40_radio_s *dev = (FAR struct mrf24j40_radio_s *)radio; - - DEBUGASSERT(dev != NULL); - dev->radiocb = radiocb; - return OK; -} - -/**************************************************************************** - * Function: mrf24j40_txnotify - * - * Description: - * Driver callback invoked when new TX data is available. This is a - * stimulus perform an out-of-cycle poll and, thereby, reduce the TX - * latency. - * - * Parameters: - * radio - Reference to the radio driver state structure - * - * Returned Value: - * None - * - * Assumptions: - * - ****************************************************************************/ - -static int mrf24j40_txnotify(FAR struct ieee802154_radio_s *radio, bool gts) -{ - FAR struct mrf24j40_radio_s *dev = (FAR struct mrf24j40_radio_s *)radio; - - if (gts) - { - /* Is our single work structure available? It may not be if there are - * pending interrupt actions and we will have to ignore the Tx - * availability action. - */ - - if (work_available(&dev->gts_pollwork)) - { - /* Schedule to serialize the poll on the worker thread. */ - - work_queue(HPWORK, &dev->gts_pollwork, mrf24j40_dopoll_gts, dev, 0); - } - } - else - { - /* Is our single work structure available? It may not be if there are - * pending interrupt actions and we will have to ignore the Tx - * availability action. - */ - - if (work_available(&dev->csma_pollwork)) - { - /* Schedule to serialize the poll on the worker thread. */ - - work_queue(HPWORK, &dev->csma_pollwork, mrf24j40_dopoll_csma, dev, 0); - } - } - - return OK; -} - -/**************************************************************************** - * Function: mrf24j40_txdelayed - * - * Description: - * Transmit a packet without regard to supeframe structure after a certain - * number of symbols. This function is used to send Data Request responses. - * It can also be used to send data immediately if the delay is set to 0. - * - * Parameters: - * radio - Reference to the radio driver state structure - * - * Returned Value: - * None - * - * Assumptions: - * - ****************************************************************************/ - -static int mrf24j40_txdelayed(FAR struct ieee802154_radio_s *radio, - FAR struct ieee802154_txdesc_s *txdesc, - uint32_t symboldelay) -{ - FAR struct mrf24j40_radio_s *dev = (FAR struct mrf24j40_radio_s *)radio; - uint8_t reg; - - /* Get exclusive access to the radio device */ - - if (sem_wait(&dev->exclsem) != 0) - { - return -EINTR; - } - - /* There should never be more than one of these transactions at once. */ - - DEBUGASSERT(!dev->txdelayed_busy); - - dev->txdelayed_desc = txdesc; - dev->txdelayed_busy = true; - - /* Disable the TX norm interrupt and clear it */ - - reg = mrf24j40_getreg(dev->spi, MRF24J40_INTCON); - reg |= MRF24J40_INTCON_TXNIE; - mrf24j40_setreg(dev->spi, MRF24J40_INTCON, reg); - - /* If after disabling the interrupt, the irqworker is not scheduled, there - * are no interrupts to worry about. However, if there is work scheduled, - * we need to process it before going any further. - */ - - if (!work_available(&dev->irqwork)) - { - work_cancel(HPWORK, &dev->irqwork); - sem_post(&dev->exclsem); - mrf24j40_irqworker((FAR void *)dev); - - /* Get exclusive access to the radio device */ - - if (sem_wait(&dev->exclsem) != 0) - { - return -EINTR; - } - } - - if (dev->csma_busy) - { - dev->reschedule_csma = true; - } - - mrf24j40_norm_setup(dev, txdesc->frame, false); - - if (symboldelay == 0) - { - mrf24j40_norm_trigger(dev); - } - else - { - mrf24j40_mactimer(dev, symboldelay); - } - - sem_post(&dev->exclsem); - - return OK; -} - -static int mrf24j40_reset(FAR struct ieee802154_radio_s *radio) -{ - FAR struct mrf24j40_radio_s *dev = (FAR struct mrf24j40_radio_s *)radio; - struct ieee802154_cca_s cca; - - /* Software reset */ - - mrf24j40_setreg(dev->spi, MRF24J40_SOFTRST , 0x07); /* 00000111 Reset */ - while(mrf24j40_getreg(dev->spi, MRF24J40_SOFTRST) & 0x07); - - /* Apply recommended settings */ - - mrf24j40_setreg(dev->spi, MRF24J40_PACON2 , 0x98); /* 10011000 Enable FIFO (default), TXONTS=6 (recommended), TXONT<8:7>=0 */ - mrf24j40_setreg(dev->spi, MRF24J40_TXSTBL , 0x95); /* 10010101 set the SIFS period. RFSTBL=9, MSIFS=5, aMinSIFSPeriod=14 (min 12) */ - mrf24j40_setreg(dev->spi, MRF24J40_TXPEND , 0x7C); /* 01111100 set the LIFS period, MLIFS=1Fh=31 aMinLIFSPeriod=40 (min 40) */ - mrf24j40_setreg(dev->spi, MRF24J40_TXTIME , 0x30); /* 00110000 set the turnaround time, TURNTIME=3 aTurnAroundTime=12 */ - mrf24j40_setreg(dev->spi, MRF24J40_RFCON1 , 0x02); /* 00000010 VCO optimization, recommended value */ - mrf24j40_setreg(dev->spi, MRF24J40_RFCON2 , 0x80); /* 10000000 Enable PLL */ - mrf24j40_setreg(dev->spi, MRF24J40_RFCON6 , 0x90); /* 10010000 TX filter enable, fast 20M recovery, No bat monitor*/ - mrf24j40_setreg(dev->spi, MRF24J40_RFCON7 , 0x80); /* 10000000 Sleep clock on internal 100 kHz */ - mrf24j40_setreg(dev->spi, MRF24J40_RFCON8 , 0x10); /* 00010000 VCO control bit, as recommended */ - mrf24j40_setreg(dev->spi, MRF24J40_SLPCON1, 0x01); /* 00000001 no CLKOUT, default divisor */ - mrf24j40_setreg(dev->spi, MRF24J40_BBREG6 , 0x40); /* 01000000 Append RSSI to rx packets */ - - /* Set this in reset since it can exist for all device modes. See pg 101 */ - - mrf24j40_setreg(dev->spi, MRF24J40_FRMOFFSET, 0x15); - - mrf24j40_setchannel(dev, 11); - mrf24j40_setpanid(dev, g_allones); - mrf24j40_setsaddr(dev, g_allones); - mrf24j40_seteaddr(dev, g_allones); - - dev->max_frame_waittime = MRF24J40_DEFAULT_MAX_FRAME_WAITTIME; - - /* Default device params */ - - cca.use_ed = 1; - cca.use_cs = 0; - cca.edth = 0x60; /* CCA mode ED, no carrier sense, recommenced ED threshold -69 dBm */ - mrf24j40_setcca(dev, &cca); - - mrf24j40_setrxmode(dev, MRF24J40_RXMODE_NORMAL); - - mrf24j40_settxpower(dev, 0); /*16. Set transmitter power .*/ - - mrf24j40_pacontrol(dev, MRF24J40_PA_AUTO); - - dev->rxenabled = false; - - /* For now, we want to always just have the frame pending bit set when - * acknowledging a Data Request command. The standard says that the coordinator - * can do this if it needs time to figure out whether it has data or not - */ - - mrf24j40_setreg(dev->spi, MRF24J40_ACKTMOUT, 0x39 | MRF24J40_ACKTMOUT_DRPACK); - - return OK; -} - -static int mrf24j40_getattr(FAR struct ieee802154_radio_s *radio, - enum ieee802154_attr_e attr, - FAR union ieee802154_attr_u *attrval) -{ - FAR struct mrf24j40_radio_s *dev = (FAR struct mrf24j40_radio_s *)radio; - int ret; - - switch (attr) - { - case IEEE802154_ATTR_MAC_EADDR: - { - memcpy(&attrval->mac.eaddr[0], &dev->addr.eaddr[0], 8); - ret = IEEE802154_STATUS_SUCCESS; - } - break; - - case IEEE802154_ATTR_MAC_MAX_FRAME_WAITTIME: - { - attrval->mac.max_frame_waittime = dev->max_frame_waittime; - ret = IEEE802154_STATUS_SUCCESS; - } - break; - - case IEEE802154_ATTR_PHY_SYMBOL_DURATION: - { - attrval->phy.symdur_picosec = MRF24J40_SYMBOL_DURATION_PS; - ret = IEEE802154_STATUS_SUCCESS; - } - break; - - case IEEE802154_ATTR_PHY_CHAN: - { - attrval->phy.chan = dev->chan; - ret = IEEE802154_STATUS_SUCCESS; - } - - default: - ret = IEEE802154_STATUS_UNSUPPORTED_ATTRIBUTE; - } - - return ret; -} - -static int mrf24j40_setattr(FAR struct ieee802154_radio_s *radio, - enum ieee802154_attr_e attr, - FAR const union ieee802154_attr_u *attrval) -{ - FAR struct mrf24j40_radio_s *dev = (FAR struct mrf24j40_radio_s *)radio; - int ret; - - switch (attr) - { - case IEEE802154_ATTR_MAC_PANID: - { - mrf24j40_setpanid(dev, attrval->mac.panid); - ret = IEEE802154_STATUS_SUCCESS; - } - break; - - case IEEE802154_ATTR_MAC_SADDR: - { - mrf24j40_setsaddr(dev, attrval->mac.saddr); - ret = IEEE802154_STATUS_SUCCESS; - } - break; - - case IEEE802154_ATTR_MAC_EADDR: - { - mrf24j40_seteaddr(dev, attrval->mac.eaddr); - ret = IEEE802154_STATUS_SUCCESS; - } - break; - - case IEEE802154_ATTR_MAC_COORD_SADDR: - { - mrf24j40_setcoordsaddr(dev, attrval->mac.coordsaddr); - ret = IEEE802154_STATUS_SUCCESS; - } - break; - - case IEEE802154_ATTR_MAC_COORD_EADDR: - { - mrf24j40_setcoordeaddr(dev, attrval->mac.coordeaddr); - ret = IEEE802154_STATUS_SUCCESS; - } - break; - - case IEEE802154_ATTR_MAC_PROMISCUOUS_MODE: - { - if (attrval->mac.promisc_mode) - { - mrf24j40_setrxmode(dev, MRF24J40_RXMODE_PROMISC); - } - else - { - mrf24j40_setrxmode(dev, MRF24J40_RXMODE_NORMAL); - } - - ret = IEEE802154_STATUS_SUCCESS; - } - break; - - case IEEE802154_ATTR_MAC_RX_ON_WHEN_IDLE: - { - dev->rxonidle = attrval->mac.rxonidle; - mrf24j40_rxenable(radio, dev->rxonidle); - ret = IEEE802154_STATUS_SUCCESS; - } - break; - - case IEEE802154_ATTR_PHY_CHAN: - { - mrf24j40_setchannel(dev, attrval->phy.chan); - ret = IEEE802154_STATUS_SUCCESS; - } - break; - - default: - ret = IEEE802154_STATUS_UNSUPPORTED_ATTRIBUTE; - break; - } - return ret; -} - -static int mrf24j40_beaconstart(FAR struct ieee802154_radio_s *radio, - FAR const struct ieee802154_superframespec_s *sfspec, - FAR struct ieee802154_beaconframe_s *beacon) -{ - FAR struct mrf24j40_radio_s *dev = (FAR struct mrf24j40_radio_s *)radio; - uint32_t maincnt = 0; - uint32_t slpcal = 0; - int reg; - - if (sfspec->pancoord) - { - /* Set the PANCOORD (RXMCR 0x00<3>) bit = 1to configure as PAN coordinator */ - - reg = mrf24j40_getreg(dev->spi, MRF24J40_RXMCR); - reg |= MRF24J40_RXMCR_PANCOORD; - mrf24j40_setreg(dev->spi, MRF24J40_RXMCR, reg); - - /* Set the SLOTTED (TXMCR 0x11<5>) bit = 1 to use Slotted CSMA-CA mode */ - - reg = mrf24j40_getreg(dev->spi, MRF24J40_TXMCR); - reg |= MRF24J40_TXMCR_SLOTTED; - mrf24j40_setreg(dev->spi, MRF24J40_TXMCR, reg); - - /* Load the beacon frame into the TXBFIFO (0x080-0x0FF). */ - - mrf24j40_setup_fifo(dev, beacon->bf_data, beacon->bf_len, MRF24J40_BEACON_FIFO); - - /* Set the TXBMSK (TXBCON1 0x25<7>) bit = 1 to mask the beacon interrupt - * mask - */ - - reg = mrf24j40_getreg(dev->spi, MRF24J40_TXBCON1); - reg |= MRF24J40_TXBCON1_TXBMSK; - mrf24j40_setreg(dev->spi, MRF24J40_TXBCON1, reg); - - /* Set INTL (WAKECON 0x22<5:0>) value to 0x03. */ - - reg = mrf24j40_getreg(dev->spi, MRF24J40_WAKECON); - reg &= ~MRF24J40_WAKECON_INTL; - reg |= 0x03 & MRF24J40_WAKECON_INTL; - mrf24j40_setreg(dev->spi, MRF24J40_WAKECON, reg); - - /* Program the CAP end slot (ESLOTG1 0x13<3:0>) value. */ - - reg = mrf24j40_getreg(dev->spi, MRF24J40_ESLOTG1); - reg &= ~MRF24J40_ESLOTG1_CAP; - reg |= sfspec->final_capslot & MRF24J40_ESLOTG1_CAP; - mrf24j40_setreg(dev->spi, MRF24J40_ESLOTG1, reg); - - /* TODO: Add GTS related code. See pg 100 of datasheet */ - - /* Calibrate the Sleep Clock (SLPCLK) frequency. Refer to Section 3.15.1.2 - * “Sleep Clock Calibration”. - */ - - /* If the Sleep Clock Selection, SLPCLKSEL (0x207<7:6), is the internal - * oscillator (100 kHz), set SLPCLKDIV to a minimum value of 0x01. - */ - - mrf24j40_setreg(dev->spi, MRF24J40_SLPCON1, 0x01); - - /* Select the source of SLPCLK (internal 100kHz) */ - - mrf24j40_setreg(dev->spi, MRF24J40_RFCON7, MRF24J40_RFCON7_SEL_100KHZ); - - /* Begin calibration by setting the SLPCALEN bit (SLPCAL2 0x20B<4>) to - * ‘1’. Sixteen samples of the SLPCLK are counted and stored in the - * SLPCAL register. No need to mask, this is the only writable bit - */ - - mrf24j40_setreg(dev->spi, MRF24J40_SLPCAL2, MRF24J40_SLPCAL2_SLPCALEN); - - /* Calibration is complete when the SLPCALRDY bit (SLPCAL2 0x20B<7>) is - * set to ‘1’. - */ - - while (!(mrf24j40_getreg(dev->spi, MRF24J40_SLPCAL2) & - MRF24J40_SLPCAL2_SLPCALRDY)) - { - usleep(1); - } - - slpcal = mrf24j40_getreg(dev->spi, MRF24J40_SLPCAL0); - slpcal |= (mrf24j40_getreg(dev->spi, MRF24J40_SLPCAL1) << 8); - slpcal |= ((mrf24j40_getreg(dev->spi, MRF24J40_SLPCAL2) << 16) & 0x0F); - - /* Set WAKECNT (SLPACK 0x35<6:0>) value = 0x5F to set the main oscillator - * (20 MHz) start-up timer value. - */ - - mrf24j40_setreg(dev->spi, MRF24J40_SLPACK, 0x5F); - - /* Program the Beacon Interval into the Main Counter, MAINCNT (0x229<1:0>, - * 0x228, 0x227, 0x226), and Remain Counter, REMCNT (0x225, 0x224), - * according to BO and SO values. Refer to Section 3.15.1.3 “Sleep Mode - * Counters” - */ - - mrf24j40_setreg(dev->spi, MRF24J40_REMCNTL, (MRF24J40_REMCNT & 0xFF)); - mrf24j40_setreg(dev->spi, MRF24J40_REMCNTH, ((MRF24J40_REMCNT >> 8) & 0xFF)); - - maincnt = MRF24J40_MAINCNT(sfspec->beaconorder, (slpcal * 50 / 16)); - - mrf24j40_setreg(dev->spi, MRF24J40_MAINCNT0, (maincnt & 0xFF)); - mrf24j40_setreg(dev->spi, MRF24J40_MAINCNT1, ((maincnt >> 8) & 0xFF)); - mrf24j40_setreg(dev->spi, MRF24J40_MAINCNT2, ((maincnt >> 16) & 0xFF)); - mrf24j40_setreg(dev->spi, MRF24J40_MAINCNT3, ((maincnt >> 24) & 0x03)); - - /* Enable the SLPIF and WAKEIF flags */ - - reg = mrf24j40_getreg(dev->spi, MRF24J40_INTCON); - reg &= ~(MRF24J40_INTCON_SLPIE | MRF24J40_INTCON_WAKEIE); - mrf24j40_setreg(dev->spi, MRF24J40_INTCON, reg); - - /* Configure the BO (ORDER 0x10<7:4>) and SO (ORDER 0x10<3:0>) values. - * After configuring BO and SO, the beacon frame will be sent immediately. - */ - - mrf24j40_setreg(dev->spi, MRF24J40_ORDER, - ((sfspec->beaconorder << 4) & 0xF0) | (sfspec->sforder & 0x0F)); - } - else - { - return -ENOTTY; - } - - return OK; -} - -static int mrf24j40_beaconupdate(FAR struct ieee802154_radio_s *radio, - FAR struct ieee802154_beaconframe_s *beacon) -{ - FAR struct mrf24j40_radio_s *dev = (FAR struct mrf24j40_radio_s *)radio; - - mrf24j40_setup_fifo(dev, beacon->bf_data, beacon->bf_len, MRF24J40_BEACON_FIFO); - - return OK; -} - -static int mrf24j40_beaconstop(FAR struct ieee802154_radio_s *radio) -{ - return -ENOTTY; -} - -static int mrf24j40_sfupdate(FAR struct ieee802154_radio_s *radio, - FAR const struct ieee802154_superframespec_s *sfspec) -{ - FAR struct mrf24j40_radio_s *dev = (FAR struct mrf24j40_radio_s *)radio; - int reg; - - /* If we are operating on a beacon-enabled network, use slotted CSMA */ - - if (sfspec->beaconorder < 15) - { - reg = mrf24j40_getreg(dev->spi, MRF24J40_TXMCR); - reg |= MRF24J40_TXMCR_SLOTTED; - mrf24j40_setreg(dev->spi, MRF24J40_TXMCR, reg); - } - else - { - reg = mrf24j40_getreg(dev->spi, MRF24J40_TXMCR); - reg &= ~MRF24J40_TXMCR_SLOTTED; - mrf24j40_setreg(dev->spi, MRF24J40_TXMCR, reg); - } - - reg = mrf24j40_getreg(dev->spi, MRF24J40_RXMCR); - - if (sfspec->pancoord) - { - reg |= MRF24J40_RXMCR_PANCOORD; - } - else - { - reg &= ~MRF24J40_RXMCR_PANCOORD; - } - mrf24j40_setreg(dev->spi, MRF24J40_RXMCR, reg); - - /* Program the CAP end slot (ESLOTG1 0x13<3:0>) value. */ - - reg = mrf24j40_getreg(dev->spi, MRF24J40_ESLOTG1); - reg &= ~MRF24J40_ESLOTG1_CAP; - reg |= sfspec->final_capslot & MRF24J40_ESLOTG1_CAP; - mrf24j40_setreg(dev->spi, MRF24J40_ESLOTG1, reg); - - /* Configure the BO (ORDER 0x10<7:4>) and SO (ORDER 0x10<3:0>) values. - * After configuring BO and SO, the beacon frame will be sent immediately. - */ - - mrf24j40_setreg(dev->spi, MRF24J40_ORDER, - ((sfspec->beaconorder << 4) & 0xF0) | (sfspec->sforder & 0x0F)); - - return OK; -} - -/**************************************************************************** - * Internal Functions - ****************************************************************************/ - -static void mrf24j40_mactimer(FAR struct mrf24j40_radio_s *dev, int numsymbols) -{ - uint16_t nhalfsym; - uint8_t reg; - - nhalfsym = (numsymbols << 1); - - /* Disable the interrupt, clear the timer count */ - - reg = mrf24j40_getreg(dev->spi, MRF24J40_INTCON); - reg |= MRF24J40_INTCON_HSYMTMRIE; - mrf24j40_setreg(dev->spi, MRF24J40_INTCON, reg); - - mrf24j40_setreg(dev->spi, MRF24J40_HSYMTMRL, 0x00); - mrf24j40_setreg(dev->spi, MRF24J40_HSYMTMRH, 0x00); - - reg &= ~MRF24J40_INTCON_HSYMTMRIE; - mrf24j40_setreg(dev->spi, MRF24J40_INTCON, reg); - - /* Set the timer count and enable interrupts */ - - reg = (nhalfsym & 0xFF); - mrf24j40_setreg(dev->spi, MRF24J40_HSYMTMRL, reg); - - reg = (nhalfsym >> 8) & 0xFF; - mrf24j40_setreg(dev->spi, MRF24J40_HSYMTMRH, reg); -} - -/**************************************************************************** - * Function: mrf24j40_dopoll_csma - * - * Description: - * This function is called in order to preform an out-of-sequence TX poll. - * This is done: - * - * 1. After completion of a transmission (mrf24j40_txdone_csma), - * 2. When new TX data is available (mrf24j40_txnotify), and - * 3. After a TX timeout to restart the sending process - * (mrf24j40_txtimeout_csma). - * - * Parameters: - * radio - Reference to the radio driver state structure - * - * Returned Value: - * None - * - * Assumptions: - * - ****************************************************************************/ - -static void mrf24j40_dopoll_csma(FAR void *arg) -{ - FAR struct mrf24j40_radio_s *dev = (FAR struct mrf24j40_radio_s *)arg; - int len = 0; - - /* Get exclusive access to the driver */ - - while (sem_wait(&dev->exclsem) != 0) { } - - /* If this a CSMA transaction and we have room in the CSMA fifo */ - - if (!dev->csma_busy) - { - len = dev->radiocb->poll(dev->radiocb, false, &dev->csma_desc); - - if (len > 0) - { - /* Now the txdesc is in use */ - - dev->csma_busy = 1; - - /* Setup the transaction on the device in the CSMA FIFO */ - - mrf24j40_norm_setup(dev, dev->csma_desc->frame, true); - mrf24j40_norm_trigger(dev); - } - } - - sem_post(&dev->exclsem); -} - -/**************************************************************************** - * Function: mrf24j40_dopoll_gts - * - * Description: - * This function is called in order to preform an out-of-sequence TX poll. - * This is done: - * - * 1. After completion of a transmission (mrf24j40_txdone_gts), - * 2. When new TX data is available (mrf24j40_txnotify), and - * 3. After a TX timeout to restart the sending process - * (mrf24j40_txtimeout_gts). - * - * Parameters: - * arg - Reference to the radio driver state structure - * - * Returned Value: - * None - * - * Assumptions: - * - ****************************************************************************/ - -static void mrf24j40_dopoll_gts(FAR void *arg) -{ - FAR struct mrf24j40_radio_s *dev = (FAR struct mrf24j40_radio_s *)arg; - int gts = 0; - int len = 0; - - /* Get exclusive access to the driver */ - - while (sem_wait(&dev->exclsem) != 0) { } - - for (gts = 0; gts < MRF24J40_GTS_SLOTS; gts++) - { - if (!dev->gts_busy[gts]) - { - len = dev->radiocb->poll(dev->radiocb, true, &dev->gts_desc[gts]); - - if (len > 0) - { - /* Now the txdesc is in use */ - - dev->gts_busy[gts]= 1; - - /* Setup the transaction on the device in the open GTS FIFO */ - - mrf24j40_gts_setup(dev, gts, dev->gts_desc[gts]->frame); - } - } - } - - sem_post(&dev->exclsem); -} - -/**************************************************************************** - * Name: mrf24j40_spi_lock - * - * Description: - * Acquire exclusive access to the shared SPI bus. - * - ****************************************************************************/ - -static void mrf24j40_spi_lock(FAR struct spi_dev_s *spi) -{ - SPI_LOCK(spi, 1); - SPI_SETBITS(spi, 8); - SPI_SETMODE(spi, CONFIG_IEEE802154_MRF24J40_SPIMODE); - SPI_SETFREQUENCY(spi, CONFIG_IEEE802154_MRF24J40_FREQUENCY); -} - -/**************************************************************************** - * Name: mrf24j40_spi_unlock - * - * Description: - * Release exclusive access to the shared SPI bus. - * - ****************************************************************************/ - -static inline void mrf24j40_spi_unlock(FAR struct spi_dev_s *spi) -{ - SPI_LOCK(spi,0); -} - -/**************************************************************************** - * Name: mrf24j40_setreg - * - * Description: - * Define the value of an MRF24J40 device register - * - ****************************************************************************/ - -static void mrf24j40_setreg(FAR struct spi_dev_s *spi, uint32_t addr, - uint8_t val) -{ - uint8_t buf[3]; - int len; - - if (!(addr&0x80000000)) - { - addr &= 0x3F; /* 6-bit address */ - addr <<= 1; - addr |= 0x01; /* writing */ - buf[0] = addr; - len = 1; - } - else - { - addr &= 0x3FF; /* 10-bit address */ - addr <<= 5; - addr |= 0x8010; /* writing long */ - buf[0] = (addr >> 8); - buf[1] = (addr & 0xFF); - len = 2; - } - - buf[len++] = val; - - mrf24j40_spi_lock(spi); - SPI_SELECT(spi, SPIDEV_IEEE802154(0), true); - SPI_SNDBLOCK(spi, buf, len); - SPI_SELECT(spi, SPIDEV_IEEE802154(0), false); - mrf24j40_spi_unlock(spi); -} - -/**************************************************************************** - * Name: mrf24j40_getreg - * - * Description: - * Return the value of an MRF24J40 device register* - * - ****************************************************************************/ - -static uint8_t mrf24j40_getreg(FAR struct spi_dev_s *spi, uint32_t addr) -{ - uint8_t buf[3]; - uint8_t rx[3]; - int len; - - if (!(addr&0x80000000)) - { - /* 6-bit address */ - - addr &= 0x3F; - addr <<= 1; - buf[0] = addr; - len = 1; - } - else - { - /* 10-bit address */ - - addr &= 0x3FF; - addr <<= 5; - addr |= 0x8000; - buf[0] = (addr >> 8); - buf[1] = (addr & 0xFF); - len = 2; - } - - buf[len++] = 0xFF; /* dummy */ - - mrf24j40_spi_lock (spi); - SPI_SELECT (spi, SPIDEV_IEEE802154(0), true); - SPI_EXCHANGE (spi, buf, rx, len); - SPI_SELECT (spi, SPIDEV_IEEE802154(0), false); - mrf24j40_spi_unlock(spi); - - /* wlinfo("r[%04X]=%02X\n", addr, rx[len - 1]); */ - return rx[len - 1]; -} - -/**************************************************************************** - * Name: mrf24j40_resetrfsm - * - * Description: - * Reset the RF state machine. Required at boot, after channel change, - * and probably after PA settings. - * - ****************************************************************************/ - -static int mrf24j40_resetrfsm(FAR struct mrf24j40_radio_s *dev) -{ - uint8_t reg; - - reg = mrf24j40_getreg(dev->spi, MRF24J40_RFCTL); - reg |= 0x04; - mrf24j40_setreg(dev->spi, MRF24J40_RFCTL, reg); - - reg &= ~0x04; - mrf24j40_setreg(dev->spi, MRF24J40_RFCTL, reg); - up_udelay(200); - - return OK; -} - -/**************************************************************************** - * Name: mrf24j40_pacontrol - * - * Description: - * Control the external LNA/PA on the MRF24J40MB/MC/MD/ME modules - * GPIO 1: PA enable - * GPIO 2: LNA enable - * GPIO 3: PA power enable (not required on MB) - ****************************************************************************/ - -static int mrf24j40_pacontrol(FAR struct mrf24j40_radio_s *dev, int mode) -{ - if (!dev->paenabled) - { - return OK; - } - - if (mode == MRF24J40_PA_AUTO) - { - mrf24j40_setreg(dev->spi, MRF24J40_TRISGPIO, 0x08); - mrf24j40_setreg(dev->spi, MRF24J40_GPIO , 0x08); - mrf24j40_setreg(dev->spi, MRF24J40_TESTMODE, 0x0F); - } - else if (mode == MRF24J40_PA_ED) - { - mrf24j40_setreg(dev->spi, MRF24J40_TESTMODE, 0x08); - mrf24j40_setreg(dev->spi, MRF24J40_TRISGPIO, 0x0F); - mrf24j40_setreg(dev->spi, MRF24J40_GPIO , 0x0C); - } - else if (mode == MRF24J40_PA_SLEEP) - { - mrf24j40_setreg(dev->spi, MRF24J40_TESTMODE, 0x08); - mrf24j40_setreg(dev->spi, MRF24J40_TRISGPIO, 0x0F); - mrf24j40_setreg(dev->spi, MRF24J40_GPIO , 0x00); - } - else - { - return -EINVAL; - } - - mrf24j40_resetrfsm(dev); - return OK; -} - -/**************************************************************************** - * Name: mrf24j40_setrxmode - * - * Description: - * Set the RX mode (normal, promiscuous, no CRC) - * - ****************************************************************************/ - -static int mrf24j40_setrxmode(FAR struct mrf24j40_radio_s *dev, int mode) -{ - uint8_t reg; - - if (mode < MRF24J40_RXMODE_NORMAL || mode > MRF24J40_RXMODE_NOCRC) - { - return -EINVAL; - } - - reg = mrf24j40_getreg(dev->spi, MRF24J40_RXMCR); - reg &= ~0x03; - reg |= mode; - - /* Set mode options */ - - if (mode != MRF24J40_RXMODE_NORMAL) - { - /* Promisc and error modes: Disable auto ACK */ - - reg |= MRF24J40_RXMCR_NOACKRSP; - } - else - { - /* Normal mode : enable auto-ACK */ - - reg &= ~MRF24J40_RXMCR_NOACKRSP; - } - - mrf24j40_setreg(dev->spi, MRF24J40_RXMCR, reg); - - dev->rxmode = mode; - wlinfo("%u\n", (unsigned)mode); - return OK; -} - -/**************************************************************************** - * Name: mrf24j40_setchannel - * - * Description: - * Define the current radio channel the device is operating on. - * In the 2.4 GHz, there are 16 channels, each 2 MHz wide, 5 MHz spacing: - * Chan MHz Chan MHz Chan MHz Chan MHz - * 11 2405 15 2425 19 2445 23 2465 - * 12 2410 16 2430 20 2450 24 2470 - * 13 2415 17 2435 21 2455 25 2475 - * 14 2420 18 2440 22 2460 26 2480 - * - ****************************************************************************/ - -static int mrf24j40_setchannel(FAR struct mrf24j40_radio_s *dev, uint8_t chan) -{ - if (chan < 11 || chan > 26) - { - wlerr("ERROR: Invalid chan: %d\n",chan); - return -EINVAL; - } - - /* 15. Set channel – See Section 3.4 “Channel Selection”. */ - - mrf24j40_setreg(dev->spi, MRF24J40_RFCON0, (chan - 11) << 4 | 0x03); - - /* 17. RFCTL (0x36) = 0x04 – Reset RF state machine. - * 18. RFCTL (0x36) = 0x00. - */ - - mrf24j40_resetrfsm(dev); - - dev->chan = chan; - wlinfo("%u\n", (unsigned)chan); - - return OK; -} - -/**************************************************************************** - * Name: mrf24j40_setpanid - * - * Description: - * Define the PAN ID the device is operating on. - * - ****************************************************************************/ - -static int mrf24j40_setpanid(FAR struct mrf24j40_radio_s *dev, - FAR const uint8_t *panid) -{ - mrf24j40_setreg(dev->spi, MRF24J40_PANIDL, panid[0]); - mrf24j40_setreg(dev->spi, MRF24J40_PANIDH, panid[1]); - - IEEE802154_PANIDCOPY(dev->addr.panid, panid); - wlinfo("%02X:%02X\n", panid[1], panid[0]); - - return OK; -} - -/**************************************************************************** - * Name: mrf24j40_setsaddr - * - * Description: - * Define the device short address. The following addresses are special: - * FFFEh : Broadcast - * FFFFh : Unspecified - * - ****************************************************************************/ - -static int mrf24j40_setsaddr(FAR struct mrf24j40_radio_s *dev, - FAR const uint8_t *saddr) -{ - mrf24j40_setreg(dev->spi, MRF24J40_SADRL, saddr[0]); - mrf24j40_setreg(dev->spi, MRF24J40_SADRH, saddr[1]); - - IEEE802154_SADDRCOPY(dev->addr.saddr, saddr); - - wlinfo("%02X:%02X\n", saddr[1], saddr[0]); - return OK; -} - -/**************************************************************************** - * Name: mrf24j40_seteaddr - * - * Description: - * Define the device extended address. The following addresses are special: - * FFFFFFFFFFFFFFFFh : Unspecified - * - ****************************************************************************/ - -static int mrf24j40_seteaddr(FAR struct mrf24j40_radio_s *dev, - FAR const uint8_t *eaddr) -{ - int i; - - for (i = 0; i < 8; i++) - { - mrf24j40_setreg(dev->spi, MRF24J40_EADR0 + i, eaddr[i]); - dev->addr.eaddr[i] = eaddr[i]; - } - - return OK; -} - -/**************************************************************************** - * Name: mrf24j40_setcoordsaddr - * - * Description: - * Define the coordinator short address. The following addresses are special: - * FFFEh : Broadcast - * FFFFh : Unspecified - * - ****************************************************************************/ - -static int mrf24j40_setcoordsaddr(FAR struct mrf24j40_radio_s *dev, - FAR const uint8_t *saddr) -{ - mrf24j40_setreg(dev->spi, MRF24J40_ASSOSADR0, saddr[0]); - mrf24j40_setreg(dev->spi, MRF24J40_ASSOSADR1, saddr[1]); - - IEEE802154_SADDRCOPY(dev->addr.saddr, saddr); - - wlinfo("%02X:%02X\n", saddr[1], saddr[0]); - return OK; -} - -/**************************************************************************** - * Name: mrf24j40_setcoordeaddr - * - * Description: - * Define the coordinator extended address. The following addresses are special: - * FFFFFFFFFFFFFFFFh : Unspecified - * - ****************************************************************************/ - -static int mrf24j40_setcoordeaddr(FAR struct mrf24j40_radio_s *dev, - FAR const uint8_t *eaddr) -{ - int i; - - for (i = 0; i < 8; i++) - { - mrf24j40_setreg(dev->spi, MRF24J40_ASSOEADR0 + i, eaddr[i]); - dev->addr.eaddr[i] = eaddr[i]; - } - - return OK; -} - -/**************************************************************************** - * Name: mrf24j40_setdevmode - * - * Description: - * Define the device behaviour: normal end device or coordinator - * - ****************************************************************************/ - -static int mrf24j40_setdevmode(FAR struct mrf24j40_radio_s *dev, - uint8_t mode) -{ - int ret = OK; - uint8_t reg; - - /* Disable slotted mode until I decide to implement slotted mode */ - - reg = mrf24j40_getreg(dev->spi, MRF24J40_TXMCR); - reg &= ~MRF24J40_TXMCR_SLOTTED; - mrf24j40_setreg(dev->spi, MRF24J40_TXMCR, reg); - mrf24j40_setreg(dev->spi, MRF24J40_ORDER, 0xFF); - - /* Define dev mode */ - - reg = mrf24j40_getreg(dev->spi, MRF24J40_RXMCR); - - if (mode == MRF24J40_MODE_PANCOORD) - { - reg |= MRF24J40_RXMCR_PANCOORD; - reg &= ~MRF24J40_RXMCR_COORD; - } - else if (mode == MRF24J40_MODE_COORD) - { - reg |= MRF24J40_RXMCR_COORD; - reg &= ~MRF24J40_RXMCR_PANCOORD; - } - else if (mode == MRF24J40_MODE_DEVICE) - { - reg &= ~MRF24J40_RXMCR_PANCOORD; - reg &= ~MRF24J40_RXMCR_COORD; - } - else - { - return -EINVAL; - } - - mrf24j40_setreg(dev->spi, MRF24J40_RXMCR, reg); - dev->devmode = mode; - return ret; -} - -/**************************************************************************** - * Name: mrf24j40_settxpower - * - * Description: - * Define the transmit power. Value is passed in mBm, it is rounded to - * the nearest value. Some MRF modules have a power amplifier, this routine - * does not care about this. We only change the CHIP output power. - * - ****************************************************************************/ - -static int mrf24j40_settxpower(FAR struct mrf24j40_radio_s *dev, - int32_t txpwr) -{ - uint8_t reg; - int save_txpwr = txpwr; - - if (txpwr <= -3000 && txpwr > -3630) - { - reg = 0xC0; - txpwr += 3000; - } - else if (txpwr <= -2000) - { - reg = 0x80; - txpwr += 2000; - } - else if (txpwr <= -1000) - { - reg = 0x40; - txpwr += 1000; - } - else if (txpwr <= 0) - { - reg = 0x00; - } - else - { - return -EINVAL; - } - - wlinfo("remaining attenuation: %d mBm\n",txpwr); - - switch(txpwr/100) - { - case -9: - case -8: - case -7: - case -6: - reg |= 0x07; - break; - - case -5: - reg |= 0x06; - break; - - case -4: - reg |= 0x05; - break; - - case -3: - reg |= 0x04; - break; - - case -2: - reg |= 0x03; - break; - - case -1: - reg |= 0x02; - break; - - case 0: - reg |= 0x00; /* value 0x01 is 0.5 db, not used */ - break; - - default: - return -EINVAL; - } - - mrf24j40_setreg(dev->spi, MRF24J40_RFCON3, reg); - dev->txpower = save_txpwr; - return OK; -} - -/**************************************************************************** - * Name: mrf24j40_setcca - * - * Description: - * Define the Clear Channel Assessement method. - * - ****************************************************************************/ - -static int mrf24j40_setcca(FAR struct mrf24j40_radio_s *dev, - FAR struct ieee802154_cca_s *cca) -{ - uint8_t mode; - - if (!cca->use_ed && !cca->use_cs) - { - return -EINVAL; - } - - if (cca->use_cs && cca->csth > 0x0f) - { - return -EINVAL; - } - - mode = mrf24j40_getreg(dev->spi, MRF24J40_BBREG2); - mode &= 0x03; - - if (cca->use_ed) - { - mode |= MRF24J40_BBREG2_CCAMODE_ED; - mrf24j40_setreg(dev->spi, MRF24J40_CCAEDTH, cca->edth); - } - - if (cca->use_cs) - { - mode |= MRF24J40_BBREG2_CCAMODE_CS; - mode |= cca->csth << 2; - } - - mrf24j40_setreg(dev->spi, MRF24J40_BBREG2, mode); - - memcpy(&dev->cca, cca, sizeof(struct ieee802154_cca_s)); - return OK; -} - -/**************************************************************************** - * Name: mrf24j40_regdump - * - * Description: - * Display the value of all registers. - * - ****************************************************************************/ - -static int mrf24j40_regdump(FAR struct mrf24j40_radio_s *dev) -{ - uint32_t i; - char buf[4+16*3+2+1]; - int len = 0; - - wlinfo("Short regs:\n"); - - for (i = 0; i < 0x40; i++) - { - if ((i & 15) == 0) - { - len=sprintf(buf, "%02x: ",i&0xFF); - } - - len += sprintf(buf+len, "%02x ", mrf24j40_getreg(dev->spi, i)); - if ((i & 15) == 15) - { - sprintf(buf+len, "\n"); - wlinfo("%s", buf); - } - } - - wlinfo("Long regs:\n"); - for (i = 0x80000200; i < 0x80000250; i++) - { - if ((i & 15) == 0) - { - len=sprintf(buf, "%02x: ",i&0xFF); - } - - len += sprintf(buf+len, "%02x ", mrf24j40_getreg(dev->spi, i)); - if ((i & 15) == 15) - { - sprintf(buf+len, "\n"); - wlinfo("%s", buf); - } - } - - return 0; -} - -/**************************************************************************** - * Name: mrf24j40_energydetect - * - * Description: - * Measure the RSSI level for the current channel. - * - ****************************************************************************/ - -static int mrf24j40_energydetect(FAR struct mrf24j40_radio_s *dev, - FAR uint8_t *energy) -{ - uint8_t reg; - - /* Manually enable the LNA*/ - - mrf24j40_pacontrol(dev, MRF24J40_PA_ED); - - /* Set RSSI average duration to 8 symbols */ - - reg = mrf24j40_getreg(dev->spi, MRF24J40_TXBCON1); - reg |= 0x30; - mrf24j40_setreg(dev->spi, MRF24J40_TXBCON1, reg); - - /* 1. Set RSSIMODE1 0x3E<7> – Initiate RSSI calculation. */ - - mrf24j40_setreg(dev->spi, MRF24J40_BBREG6, 0x80); - - /* 2. Wait until RSSIRDY 0x3E<0> is set to ‘1’ – RSSI calculation is - * complete. - */ - - while(!(mrf24j40_getreg(dev->spi, MRF24J40_BBREG6) & 0x01)); - - /* 3. Read RSSI 0x210<7:0> – The RSSI register contains the averaged RSSI - * received power level for 8 symbol periods. - */ - - *energy = mrf24j40_getreg(dev->spi, MRF24J40_RSSI); - - mrf24j40_setreg(dev->spi, MRF24J40_BBREG6, 0x40); - - /* Back to automatic control */ - - mrf24j40_pacontrol(dev, MRF24J40_PA_AUTO); - return OK; -} - -/**************************************************************************** - * Name: mrf24j40_norm_setup - * - * Description: - * Setup a transaction in the normal TX FIFO - * - ****************************************************************************/ - -static void mrf24j40_norm_setup(FAR struct mrf24j40_radio_s *dev, - FAR struct iob_s *frame, bool csma) -{ - uint8_t reg; - - /* Enable tx int */ - - reg = mrf24j40_getreg(dev->spi, MRF24J40_INTCON); - reg &= ~MRF24J40_INTCON_TXNIE; - mrf24j40_setreg(dev->spi, MRF24J40_INTCON, reg); - - /* Enable/Disable CSMA mode */ - - reg = mrf24j40_getreg(dev->spi, MRF24J40_TXMCR); - - if (csma) - { - reg &= ~MRF24J40_TXMCR_NOCSMA; - } - else - { - reg |= MRF24J40_TXMCR_NOCSMA; - } - - mrf24j40_setreg(dev->spi, MRF24J40_TXMCR, reg); - - /* Setup the FIFO */ - - mrf24j40_setup_fifo(dev, frame->io_data, frame->io_len, MRF24J40_TXNORM_FIFO); - - /* If the frame control field contains an acknowledgment request, set the - * TXNACKREQ bit. See IEEE 802.15.4/2003 7.2.1.1 page 112 for info. - */ - - reg = mrf24j40_getreg(dev->spi, MRF24J40_TXNCON); - - if (frame->io_data[0] & IEEE802154_FRAMECTRL_ACKREQ) - { - reg |= MRF24J40_TXNCON_TXNACKREQ; - } - else - { - reg &= ~MRF24J40_TXNCON_TXNACKREQ; - } - - mrf24j40_setreg(dev->spi, MRF24J40_TXNCON, reg); -} - -/**************************************************************************** - * Name: mrf24j40_norm_trigger - * - * Description: - * Trigger the normal TX FIFO - * - ****************************************************************************/ - -static inline void mrf24j40_norm_trigger(FAR struct mrf24j40_radio_s *dev) -{ - uint8_t reg; - - reg = mrf24j40_getreg(dev->spi, MRF24J40_TXNCON); - - reg |= MRF24J40_TXNCON_TXNTRIG; - - mrf24j40_setreg(dev->spi, MRF24J40_TXNCON, reg); -} - -/**************************************************************************** - * Name: mrf24j40_gts_setup - * - * Description: - * Setup a GTS transaction in one of the GTS FIFOs - * - ****************************************************************************/ - -static void mrf24j40_gts_setup(FAR struct mrf24j40_radio_s *dev, uint8_t fifo, - FAR struct iob_s *frame) -{ - -} - -/**************************************************************************** - * Name: mrf24j40_setup_fifo - * - * Description: - * - ****************************************************************************/ - -static void mrf24j40_setup_fifo(FAR struct mrf24j40_radio_s *dev, - FAR const uint8_t *buf, uint8_t length, - uint32_t fifo_addr) -{ - int hlen = 3; /* Include frame control and seq number */ - int i; - uint16_t frame_ctrl; - - /* Analyze frame control to compute header length */ - - frame_ctrl = buf[0]; - frame_ctrl |= (buf[1] << 8); - - if ((frame_ctrl & IEEE802154_FRAMECTRL_DADDR)== IEEE802154_ADDRMODE_SHORT) - { - hlen += 2 + 2; /* Destination PAN + shortaddr */ - } - else if ((frame_ctrl & IEEE802154_FRAMECTRL_DADDR) == IEEE802154_ADDRMODE_EXTENDED) - { - hlen += 2 + 8; /* Destination PAN + extaddr */ - } - - if (!(frame_ctrl & IEEE802154_FRAMECTRL_PANIDCOMP)) - { - hlen += 2; /* No PAN compression, source PAN is different from dest PAN */ - } - - if ((frame_ctrl & IEEE802154_FRAMECTRL_SADDR)== IEEE802154_ADDRMODE_SHORT) - { - hlen += 2; /* Source saddr */ - } - else if ((frame_ctrl & IEEE802154_FRAMECTRL_SADDR) == IEEE802154_ADDRMODE_EXTENDED) - { - hlen += 8; /* Ext saddr */ - } - - /* Header len, 0, TODO for security modes */ - - mrf24j40_setreg(dev->spi, fifo_addr++, hlen); - - /* Frame length */ - - mrf24j40_setreg(dev->spi, fifo_addr++, length); - - /* Frame data */ - - for (i = 0; i < length; i++) - { - mrf24j40_setreg(dev->spi, fifo_addr++, buf[i]); - } -} - -/**************************************************************************** - * Name: mrf24j40_irqwork_txnorm - * - * Description: - * Manage completion of packet transmission. - * - ****************************************************************************/ - -static void mrf24j40_irqwork_txnorm(FAR struct mrf24j40_radio_s *dev) -{ - uint8_t reg; - enum ieee802154_status_e status; - bool framepending; - - /* Disable tx int */ - - reg = mrf24j40_getreg(dev->spi, MRF24J40_INTCON); - reg |= MRF24J40_INTCON_TXNIE; - mrf24j40_setreg(dev->spi, MRF24J40_INTCON, reg); - - /* Get the status from the device and copy the status into the tx desc. - * The status for the normal FIFO is represented with bit TXNSTAT where - * 0=success, 1= failure. - */ - - reg = mrf24j40_getreg(dev->spi, MRF24J40_TXSTAT); - - /* TXNSTAT = 0: Transmission was successful - * TXNSTAT = 1: Transmission failed, retry count exceeded - */ - - if (reg & MRF24J40_TXSTAT_TXNSTAT) - { - /* The number of retries of the most recent transmission is contained in the - * TXNRETRY (TXSTAT 0x24<7:6>) bits. The CCAFAIL (TXSTAT 0x24<5>) bit = 1 - * indicates if the failed transmission was due to the channel busy - * (CSMA-CA timed out). - */ - - if (reg & MRF24J40_TXSTAT_CCAFAIL) - { - status = IEEE802154_STATUS_CHANNEL_ACCESS_FAILURE; - } - else - { - status = IEEE802154_STATUS_NO_ACK; - } - } - else - { - status = IEEE802154_STATUS_SUCCESS; - } - - framepending = (mrf24j40_getreg(dev->spi, MRF24J40_TXNCON) & - MRF24J40_TXNCON_FPSTAT); - - if (dev->txdelayed_busy) - { - /* Inform the next layer of the transmission success/failure */ - - dev->txdelayed_desc->conf->status = status; - dev->txdelayed_desc->framepending = framepending; - dev->radiocb->txdone(dev->radiocb, dev->txdelayed_desc); - - dev->txdelayed_busy = false; - - if (dev->reschedule_csma) - { - mrf24j40_norm_setup(dev, dev->csma_desc->frame, true); - mrf24j40_norm_trigger(dev); - dev->reschedule_csma = false; - } - } - else - { - /* Inform the next layer of the transmission success/failure */ - - dev->csma_desc->conf->status = status; - dev->csma_desc->framepending = framepending; - dev->radiocb->txdone(dev->radiocb, dev->csma_desc); - - /* We are now done with the transaction */ - - dev->csma_busy = 0; - - /* Must unlock the radio before calling poll */ - - sem_post(&dev->exclsem); - mrf24j40_dopoll_csma(dev); - while (sem_wait(&dev->exclsem) != 0) { } - } -} - -/**************************************************************************** - * Name: mrf24j40_irqwork_gts - * - * Description: - * Manage completion of packet transmission. - * - ****************************************************************************/ - -static void mrf24j40_irqwork_txgts(FAR struct mrf24j40_radio_s *dev, - uint8_t gts) -{ - uint8_t txstat; - - /* Disable tx int */ - - txstat = mrf24j40_getreg(dev->spi, MRF24J40_INTCON); - txstat |= MRF24J40_INTCON_TXNIE; - mrf24j40_setreg(dev->spi, MRF24J40_INTCON, txstat); - - /* Get the status from the device and copy the status into the tx desc. - * The status for the normal FIFO is represented with bit TXNSTAT where - * 0=success, 1= failure. - */ - - txstat = mrf24j40_getreg(dev->spi, MRF24J40_TXSTAT); - - if (gts == 0) - { - dev->csma_desc->conf->status = txstat & MRF24J40_TXSTAT_TXG1STAT; - } - else if (gts == 1) - { - dev->csma_desc->conf->status = txstat & MRF24J40_TXSTAT_TXG2STAT; - } - - /* Inform the next layer of the transmission success/failure */ - - dev->radiocb->txdone(dev->radiocb, dev->gts_desc[gts]); - - /* We are now done with the transaction */ - - dev->gts_busy[gts]= 0; - - mrf24j40_dopoll_gts(dev); -} - -/**************************************************************************** - * Name: mrf24j40_rxenable - * - * Description: - * Enable/Disable receiver. - * - ****************************************************************************/ - -static int mrf24j40_rxenable(FAR struct ieee802154_radio_s *radio, bool enable) -{ - FAR struct mrf24j40_radio_s *dev = (FAR struct mrf24j40_radio_s *)radio; - uint8_t reg; - - dev->rxenabled = enable; - - - if (enable) - { - /* Disable packet reception. See pg. 109 of datasheet */ - - mrf24j40_setreg(dev->spi, MRF24J40_BBREG1, MRF24J40_BBREG1_RXDECINV); - - /* Enable rx int */ - - reg = mrf24j40_getreg(dev->spi, MRF24J40_INTCON); - reg &= ~MRF24J40_INTCON_RXIE; - mrf24j40_setreg(dev->spi, MRF24J40_INTCON, reg); - - /* Purge the RX buffer */ - - reg = mrf24j40_getreg(dev->spi, MRF24J40_RXFLUSH); - reg |= MRF24J40_RXFLUSH_RXFLUSH; - mrf24j40_setreg(dev->spi, MRF24J40_RXFLUSH, reg); - - /* Re-enable packet reception. See pg. 109 of datasheet */ - - mrf24j40_setreg(dev->spi, MRF24J40_BBREG1, 0); - } - else - { - /* Disable rx int */ - - reg = mrf24j40_getreg(dev->spi, MRF24J40_INTCON); - reg |= MRF24J40_INTCON_RXIE; - mrf24j40_setreg(dev->spi, MRF24J40_INTCON, reg); - } - - return OK; -} - -/**************************************************************************** - * Name: mrf24j40_irqwork_rx - * - * Description: - * Manage packet reception. - * - ****************************************************************************/ - -static void mrf24j40_irqwork_rx(FAR struct mrf24j40_radio_s *dev) -{ - FAR struct ieee802154_data_ind_s *ind; - uint32_t addr; - uint32_t index; - uint8_t reg; - - wlinfo("RX interrupt\n"); - - /* Disable rx int */ - - reg = mrf24j40_getreg(dev->spi, MRF24J40_INTCON); - reg |= MRF24J40_INTCON_RXIE; - mrf24j40_setreg(dev->spi, MRF24J40_INTCON, reg); - - /* Disable packet reception. See pg. 109 of datasheet */ - - mrf24j40_setreg(dev->spi, MRF24J40_BBREG1, MRF24J40_BBREG1_RXDECINV); - - /* Allocate a data_ind to put the frame in */ - - ind = ieee802154_ind_allocate(); - if (ind == NULL) - { - wlerr("ERROR: Unable to allocate data_ind. Discarding frame\n"); - goto done; - } - - /* Read packet */ - - addr = MRF24J40_RXBUF_BASE; - - ind->frame->io_len = mrf24j40_getreg(dev->spi, addr++); - - /* TODO: This needs to be changed. It is inefficient to do the SPI read byte - * by byte */ - - for (index = 0; index < ind->frame->io_len; index++) - { - ind->frame->io_data[index] = mrf24j40_getreg(dev->spi, addr++); - } - - ind->lqi = mrf24j40_getreg(dev->spi, addr++); - ind->rssi = mrf24j40_getreg(dev->spi, addr++); - - /* Reduce len by 2, we only receive frames with correct crc, no check - * required. - */ - - ind->frame->io_len -= 2; - - /* Callback the receiver in the next highest layer */ - - dev->radiocb->rxframe(dev->radiocb, ind); - -done: - /* Enable reception of next packet by flushing the fifo. - * This is an MRF24J40 errata (no. 1). - */ - - mrf24j40_setreg(dev->spi, MRF24J40_RXFLUSH, 1); - - /* Only enable RX interrupt if we are to be listening when IDLE */ - - if (dev->rxenabled) - { - /* Enable packet reception */ - - mrf24j40_setreg(dev->spi, MRF24J40_BBREG1, 0); - - reg = mrf24j40_getreg(dev->spi, MRF24J40_INTCON); - reg &= ~MRF24J40_INTCON_RXIE; - mrf24j40_setreg(dev->spi, MRF24J40_INTCON, reg); - } -} - -/**************************************************************************** - * Name: mrf24j40_irqworker - * - * Description: - * Perform interrupt handling logic outside of the interrupt handler (on - * the work queue thread). - * - * Parameters: - * arg - The reference to the driver structure (cast to void*) - * - * Returned Value: - * None - * - * Assumptions: - * - ****************************************************************************/ - -static void mrf24j40_irqworker(FAR void *arg) -{ - FAR struct mrf24j40_radio_s *dev = (FAR struct mrf24j40_radio_s *)arg; - uint8_t intstat; - uint8_t reg; - - DEBUGASSERT(dev); - DEBUGASSERT(dev->spi); - - /* Get exclusive access to the driver */ - - while (sem_wait(&dev->exclsem) != 0) { } - - /* Read and store INTSTAT - this clears the register. */ - - intstat = mrf24j40_getreg(dev->spi, MRF24J40_INTSTAT); - - /* Do work according to the pending interrupts */ - - if ((intstat & MRF24J40_INTSTAT_HSYMTMRIF)) - { - /* As of now the only use for the MAC timer is for delayed transactions. - * Therefore, all we do here is trigger the TX norm FIFO - */ - - mrf24j40_norm_trigger(dev); - - /* Timers are one-shot, so disable the interrupt */ - - reg = mrf24j40_getreg(dev->spi, MRF24J40_INTCON); - reg |= MRF24J40_INTCON_HSYMTMRIE; - mrf24j40_setreg(dev->spi, MRF24J40_INTCON, reg); - } - - if ((intstat & MRF24J40_INTSTAT_RXIF) && dev->rxenabled) - { - /* A packet was received, retrieve it */ - - mrf24j40_irqwork_rx(dev); - } - - if ((intstat & MRF24J40_INTSTAT_TXNIF)) - { - /* A packet was transmitted or failed*/ - - mrf24j40_irqwork_txnorm(dev); - } - - if ((intstat & MRF24J40_INTSTAT_TXG1IF)) - { - /* A packet was transmitted or failed*/ - - mrf24j40_irqwork_txgts(dev, 0); - } - - if ((intstat & MRF24J40_INTSTAT_TXG1IF)) - { - /* A packet was transmitted or failed*/ - - mrf24j40_irqwork_txgts(dev, 1); - } - - if ((intstat & MRF24J40_INTSTAT_SLPIF)) - { - dev->radiocb->sfevent(dev->radiocb, IEEE802154_SFEVENT_ENDOFACTIVE); - - /* Acknowledge the alert and put the device to sleep */ - - reg = mrf24j40_getreg(dev->spi, MRF24J40_SLPACK); - reg |= MRF24J40_SLPACK_SLPACK; - mrf24j40_setreg(dev->spi, MRF24J40_SLPACK, reg); - } - - /* Unlock the radio device */ - - sem_post(&dev->exclsem); - - /* Re-enable GPIO interrupts */ - - dev->lower->enable(dev->lower, true); -} - -/**************************************************************************** - * Name: mrf24j40_interrupt - * - * Description: - * Hardware interrupt handler - * - * Parameters: - * irq - Number of the IRQ that generated the interrupt - * context - Interrupt register state save info (architecture-specific) - * - * Returned Value: - * OK on success - * - * Assumptions: - * - ****************************************************************************/ - -static int mrf24j40_interrupt(int irq, FAR void *context, FAR void *arg) -{ - FAR struct mrf24j40_radio_s *dev = (FAR struct mrf24j40_radio_s *)arg; - - DEBUGASSERT(dev != NULL); - - /* In complex environments, we cannot do SPI transfers from the interrupt - * handler because semaphores are probably used to lock the SPI bus. In - * this case, we will defer processing to the worker thread. This is also - * much kinder in the use of system resources and is, therefore, probably - * a good thing to do in any event. - */ - - DEBUGASSERT(work_available(&dev->irqwork)); - - /* Notice that further GPIO interrupts are disabled until the work is - * actually performed. This is to prevent overrun of the worker thread. - * Interrupts are re-enabled in enc_irqworker() when the work is completed. - */ - - dev->lower->enable(dev->lower, false); - return work_queue(HPWORK, &dev->irqwork, mrf24j40_irqworker, (FAR void *)dev, 0); -} - -/**************************************************************************** - * Public Functions - ****************************************************************************/ - -/**************************************************************************** - * Name: mrf24j40_init - * - * Description: - * Return an mrf24j40 device for use by other drivers. - * - ****************************************************************************/ - -FAR struct ieee802154_radio_s *mrf24j40_init(FAR struct spi_dev_s *spi, - FAR const struct mrf24j40_lower_s *lower) -{ - FAR struct mrf24j40_radio_s *dev; - - dev = kmm_zalloc(sizeof(struct mrf24j40_radio_s)); - if (dev == NULL) - { - return NULL; - } - - /* Attach irq */ - - if (lower->attach(lower, mrf24j40_interrupt, dev) != OK) - { -#if 0 - free(dev); -#endif - return NULL; - } - - /* Allow exclusive access to the privmac struct */ - - sem_init(&dev->exclsem, 0, 1); - - dev->radio.bind = mrf24j40_bind; - dev->radio.reset = mrf24j40_reset; - dev->radio.getattr = mrf24j40_getattr; - dev->radio.setattr = mrf24j40_setattr; - dev->radio.txnotify = mrf24j40_txnotify; - dev->radio.txdelayed = mrf24j40_txdelayed; - dev->radio.rxenable = mrf24j40_rxenable; - dev->radio.beaconstart = mrf24j40_beaconstart; - dev->radio.beaconupdate = mrf24j40_beaconupdate; - dev->radio.beaconstop = mrf24j40_beaconstop; - dev->radio.sfupdate = mrf24j40_sfupdate; - - dev->lower = lower; - dev->spi = spi; - - mrf24j40_reset(&dev->radio); - - dev->lower->enable(dev->lower, true); - return &dev->radio; -} +/**************************************************************************** + * drivers/wireless/ieee802154/mrf24j40.c + * + * Copyright (C) 2015-2016 Sebastien Lorquet. All rights reserved. + * Copyright (C) 2017 Verge Inc. All rights reserved. + * Author: Sebastien Lorquet + * Author: Anthony Merlino + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include + +#include "mrf24j40.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#ifndef CONFIG_SCHED_HPWORK +# error High priority work queue required in this driver +#endif + +#ifndef CONFIG_IEEE802154_MRF24J40_SPIMODE +# define CONFIG_IEEE802154_MRF24J40_SPIMODE SPIDEV_MODE0 +#endif + +#ifndef CONFIG_IEEE802154_MRF24J40_FREQUENCY +# define CONFIG_IEEE802154_MRF24J40_FREQUENCY 8000000 +#endif + +#ifndef CONFIG_SPI_EXCHANGE +# error CONFIG_SPI_EXCHANGE required for this driver +#endif + +/* Definitions for the device structure */ + +#define MRF24J40_RXMODE_NORMAL 0 +#define MRF24J40_RXMODE_PROMISC 1 +#define MRF24J40_RXMODE_NOCRC 2 + +#define MRF24J40_MODE_DEVICE 0 +#define MRF24J40_MODE_COORD 1 +#define MRF24J40_MODE_PANCOORD 2 + +/* Definitions for PA control on high power modules */ + +#define MRF24J40_PA_AUTO 1 +#define MRF24J40_PA_ED 2 +#define MRF24J40_PA_SLEEP 3 + +#define MRF24J40_GTS_SLOTS 2 + +/* Clock configuration macros */ + +#define MRF24J40_SLPCLKPER_100KHZ ((1000 * 1000 * 1000)/100000) /* 10ns */ +#define MRF24J40_SLPCLKPER_32KHZ ((1000 * 1000 * 1000)/32000) /* 31.25ns */ + +#define MRF24J40_BEACONINTERVAL_NSEC(beaconorder) \ + (IEEE802154_BASE_SUPERFRAME_DURATION * (1 << beaconorder) * (16 *1000)) + +/* For now I am just setting the REMCNT to the maximum while staying in multiples + * of 10000 (100khz period) */ + +#define MRF24J40_REMCNT 60000 +#define MRF24J40_REMCNT_NSEC (MRF24J40_REMCNT * 50) + +#define MRF24J40_MAINCNT(bo, clkper) \ + ((MRF24J40_BEACONINTERVAL_NSEC(bo) - MRF24J40_REMCNT_NSEC) / \ + clkper) + +/* Formula for calculating default macMaxFrameWaitTime is on pg. 130 + * + * For PHYs other than CSS and UWB, the attribute phyMaxFrameDuration is given by: + * + * phyMaxFrameDuration = phySHRDuration + + * ceiling([aMaxPHYPacketSize + 1] x phySymbolsPerOctet) + * + * where ceiling() is a function that returns the smallest integer value greater + * than or equal to its argument value. [1] pg. 158 +*/ + +#define MRF24J40_DEFAULT_MAX_FRAME_WAITTIME 1824 + +#define MRF24J40_SYMBOL_DURATION_PS 16000000 + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/* A MRF24J40 device instance */ + +struct mrf24j40_radio_s +{ + struct ieee802154_radio_s radio; /* The public device instance */ + FAR struct ieee802154_radiocb_s *radiocb; /* Registered callbacks */ + + /* MAC Attributes */ + + bool rxonidle : 1; + + /* Low-level MCU-specific support */ + + FAR const struct mrf24j40_lower_s *lower; + FAR struct spi_dev_s *spi; /* Saved SPI interface instance */ + + struct work_s irqwork; /* For deferring interrupt work to work queue */ + struct work_s csma_pollwork; /* For deferring poll work to the work queue */ + struct work_s gts_pollwork; /* For deferring poll work to the work queue */ + + sem_t exclsem; /* Exclusive access to this struct */ + + struct ieee802154_addr_s addr; + + uint8_t chan; /* 11 to 26 for the 2.4 GHz band */ + uint8_t devmode; /* device mode: device, coord, pancoord */ + uint8_t paenabled; /* enable usage of PA */ + uint8_t rxmode; /* Reception mode: Main, no CRC, promiscuous */ + int32_t txpower; /* TX power in mBm = dBm/100 */ + struct ieee802154_cca_s cca; /* Clear channel assessement method */ + + /* MAC PIB attributes */ + + uint32_t max_frame_waittime; + + struct ieee802154_txdesc_s *txdelayed_desc; + struct ieee802154_txdesc_s *csma_desc; + bool txdelayed_busy : 1; + bool csma_busy : 1; + bool reschedule_csma : 1; + + bool rxenabled : 1; + + struct ieee802154_txdesc_s *gts_desc[MRF24J40_GTS_SLOTS]; + bool gts_busy[MRF24J40_GTS_SLOTS]; +}; + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +/* Internal operations */ + +static void mrf24j40_spi_lock(FAR struct spi_dev_s *spi); + +static void mrf24j40_setreg(FAR struct spi_dev_s *spi, uint32_t addr, + uint8_t val); +static uint8_t mrf24j40_getreg(FAR struct spi_dev_s *spi, uint32_t addr); + +static int mrf24j40_resetrfsm(FAR struct mrf24j40_radio_s *dev); +static void mrf24j40_setorder(FAR struct mrf24j40_radio_s *dev, uint8_t bo, + uint8_t so); +static int mrf24j40_pacontrol(FAR struct mrf24j40_radio_s *dev, int mode); + +static int mrf24j40_setrxmode(FAR struct mrf24j40_radio_s *dev, int mode); +static int mrf24j40_regdump(FAR struct mrf24j40_radio_s *dev); + +static void mrf24j40_irqwork_rx(FAR struct mrf24j40_radio_s *dev); +static void mrf24j40_irqwork_txnorm(FAR struct mrf24j40_radio_s *dev); +static void mrf24j40_irqwork_txgts(FAR struct mrf24j40_radio_s *dev, + uint8_t gts_num); + +static void mrf24j40_irqworker(FAR void *arg); +static int mrf24j40_interrupt(int irq, FAR void *context, FAR void *arg); + +static void mrf24j40_dopoll_csma(FAR void *arg); +static void mrf24j40_dopoll_gts(FAR void *arg); + +static void mrf24j40_norm_setup(FAR struct mrf24j40_radio_s *dev, + FAR struct iob_s *frame, bool csma); +static void mrf24j40_gts_setup(FAR struct mrf24j40_radio_s *dev, uint8_t gts, + FAR struct iob_s *frame); +static void mrf24j40_setup_fifo(FAR struct mrf24j40_radio_s *dev, + FAR const uint8_t *buf, uint8_t length, uint32_t fifo_addr); + +static inline void mrf24j40_norm_trigger(FAR struct mrf24j40_radio_s *dev); + +static int mrf24j40_setchannel(FAR struct mrf24j40_radio_s *dev, + uint8_t chan); +static int mrf24j40_setpanid(FAR struct mrf24j40_radio_s *dev, + FAR const uint8_t *panid); +static int mrf24j40_setsaddr(FAR struct mrf24j40_radio_s *dev, + FAR const uint8_t *saddr); +static int mrf24j40_seteaddr(FAR struct mrf24j40_radio_s *dev, + FAR const uint8_t *eaddr); +static int mrf24j40_setcoordsaddr(FAR struct mrf24j40_radio_s *dev, + FAR const uint8_t *saddr); +static int mrf24j40_setcoordeaddr(FAR struct mrf24j40_radio_s *dev, + FAR const uint8_t *eaddr); +static int mrf24j40_setdevmode(FAR struct mrf24j40_radio_s *dev, + uint8_t mode); +static int mrf24j40_settxpower(FAR struct mrf24j40_radio_s *dev, + int32_t txpwr); +static int mrf24j40_setcca(FAR struct mrf24j40_radio_s *dev, + FAR struct ieee802154_cca_s *cca); +static int mrf24j40_energydetect(FAR struct mrf24j40_radio_s *dev, + FAR uint8_t *energy); +static void mrf24j40_mactimer(FAR struct mrf24j40_radio_s *dev, int numsymbols); + +/* Driver operations */ + +static int mrf24j40_bind(FAR struct ieee802154_radio_s *radio, + FAR struct ieee802154_radiocb_s *radiocb); +static int mrf24j40_reset(FAR struct ieee802154_radio_s *radio); +static int mrf24j40_getattr(FAR struct ieee802154_radio_s *radio, + enum ieee802154_attr_e attr, + FAR union ieee802154_attr_u *attrval); +static int mrf24j40_setattr(FAR struct ieee802154_radio_s *radio, + enum ieee802154_attr_e attr, + FAR const union ieee802154_attr_u *attrval); +static int mrf24j40_txnotify(FAR struct ieee802154_radio_s *radio, bool gts); +static int mrf24j40_txdelayed(FAR struct ieee802154_radio_s *radio, + FAR struct ieee802154_txdesc_s *txdesc, + uint32_t symboldelay); +static int mrf24j40_rxenable(FAR struct ieee802154_radio_s *dev, bool enable); +static int mrf24j40_beaconstart(FAR struct ieee802154_radio_s *radio, + FAR const struct ieee802154_superframespec_s *sfspec, + FAR struct ieee802154_beaconframe_s *beacon); +static int mrf24j40_beaconupdate(FAR struct ieee802154_radio_s *radio, + FAR struct ieee802154_beaconframe_s *beacon); +static int mrf24j40_beaconstop(FAR struct ieee802154_radio_s *radio); +static int mrf24j40_sfupdate(FAR struct ieee802154_radio_s *radio, + FAR const struct ieee802154_superframespec_s *sfspec); + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +static const uint8_t g_allones[8] = +{ + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF +}; + +/**************************************************************************** + * Radio Interface Functions + ****************************************************************************/ + +static int mrf24j40_bind(FAR struct ieee802154_radio_s *radio, + FAR struct ieee802154_radiocb_s *radiocb) +{ + FAR struct mrf24j40_radio_s *dev = (FAR struct mrf24j40_radio_s *)radio; + + DEBUGASSERT(dev != NULL); + dev->radiocb = radiocb; + return OK; +} + +/**************************************************************************** + * Function: mrf24j40_txnotify + * + * Description: + * Driver callback invoked when new TX data is available. This is a + * stimulus perform an out-of-cycle poll and, thereby, reduce the TX + * latency. + * + * Parameters: + * radio - Reference to the radio driver state structure + * + * Returned Value: + * None + * + * Assumptions: + * + ****************************************************************************/ + +static int mrf24j40_txnotify(FAR struct ieee802154_radio_s *radio, bool gts) +{ + FAR struct mrf24j40_radio_s *dev = (FAR struct mrf24j40_radio_s *)radio; + + if (gts) + { + /* Is our single work structure available? It may not be if there are + * pending interrupt actions and we will have to ignore the Tx + * availability action. + */ + + if (work_available(&dev->gts_pollwork)) + { + /* Schedule to serialize the poll on the worker thread. */ + + work_queue(HPWORK, &dev->gts_pollwork, mrf24j40_dopoll_gts, dev, 0); + } + } + else + { + /* Is our single work structure available? It may not be if there are + * pending interrupt actions and we will have to ignore the Tx + * availability action. + */ + + if (work_available(&dev->csma_pollwork)) + { + /* Schedule to serialize the poll on the worker thread. */ + + work_queue(HPWORK, &dev->csma_pollwork, mrf24j40_dopoll_csma, dev, 0); + } + } + + return OK; +} + +/**************************************************************************** + * Function: mrf24j40_txdelayed + * + * Description: + * Transmit a packet without regard to supeframe structure after a certain + * number of symbols. This function is used to send Data Request responses. + * It can also be used to send data immediately if the delay is set to 0. + * + * Parameters: + * radio - Reference to the radio driver state structure + * + * Returned Value: + * None + * + * Assumptions: + * + ****************************************************************************/ + +static int mrf24j40_txdelayed(FAR struct ieee802154_radio_s *radio, + FAR struct ieee802154_txdesc_s *txdesc, + uint32_t symboldelay) +{ + FAR struct mrf24j40_radio_s *dev = (FAR struct mrf24j40_radio_s *)radio; + uint8_t reg; + + /* Get exclusive access to the radio device */ + + if (sem_wait(&dev->exclsem) != 0) + { + return -EINTR; + } + + /* There should never be more than one of these transactions at once. */ + + DEBUGASSERT(!dev->txdelayed_busy); + + dev->txdelayed_desc = txdesc; + dev->txdelayed_busy = true; + + /* Disable the TX norm interrupt and clear it */ + + reg = mrf24j40_getreg(dev->spi, MRF24J40_INTCON); + reg |= MRF24J40_INTCON_TXNIE; + mrf24j40_setreg(dev->spi, MRF24J40_INTCON, reg); + + /* If after disabling the interrupt, the irqworker is not scheduled, there + * are no interrupts to worry about. However, if there is work scheduled, + * we need to process it before going any further. + */ + + if (!work_available(&dev->irqwork)) + { + work_cancel(HPWORK, &dev->irqwork); + sem_post(&dev->exclsem); + mrf24j40_irqworker((FAR void *)dev); + + /* Get exclusive access to the radio device */ + + if (sem_wait(&dev->exclsem) != 0) + { + return -EINTR; + } + } + + if (dev->csma_busy) + { + dev->reschedule_csma = true; + } + + mrf24j40_norm_setup(dev, txdesc->frame, false); + + if (symboldelay == 0) + { + mrf24j40_norm_trigger(dev); + } + else + { + mrf24j40_mactimer(dev, symboldelay); + } + + sem_post(&dev->exclsem); + + return OK; +} + +static int mrf24j40_reset(FAR struct ieee802154_radio_s *radio) +{ + FAR struct mrf24j40_radio_s *dev = (FAR struct mrf24j40_radio_s *)radio; + struct ieee802154_cca_s cca; + int reg; + + /* Software reset */ + + mrf24j40_setreg(dev->spi, MRF24J40_SOFTRST , 0x07); /* 00000111 Reset */ + while(mrf24j40_getreg(dev->spi, MRF24J40_SOFTRST) & 0x07); + + /* Apply recommended settings */ + + mrf24j40_setreg(dev->spi, MRF24J40_PACON2 , 0x98); /* 10011000 Enable FIFO (default), TXONTS=6 (recommended), TXONT<8:7>=0 */ + mrf24j40_setreg(dev->spi, MRF24J40_TXSTBL , 0x95); /* 10010101 set the SIFS period. RFSTBL=9, MSIFS=5, aMinSIFSPeriod=14 (min 12) */ + mrf24j40_setreg(dev->spi, MRF24J40_TXPEND , 0x7C); /* 01111100 set the LIFS period, MLIFS=1Fh=31 aMinLIFSPeriod=40 (min 40) */ + mrf24j40_setreg(dev->spi, MRF24J40_TXTIME , 0x30); /* 00110000 set the turnaround time, TURNTIME=3 aTurnAroundTime=12 */ + mrf24j40_setreg(dev->spi, MRF24J40_RFCON1 , 0x02); /* 00000010 VCO optimization, recommended value */ + mrf24j40_setreg(dev->spi, MRF24J40_RFCON2 , 0x80); /* 10000000 Enable PLL */ + mrf24j40_setreg(dev->spi, MRF24J40_RFCON6 , 0x90); /* 10010000 TX filter enable, fast 20M recovery, No bat monitor*/ + mrf24j40_setreg(dev->spi, MRF24J40_RFCON7 , 0x80); /* 10000000 Sleep clock on internal 100 kHz */ + mrf24j40_setreg(dev->spi, MRF24J40_RFCON8 , 0x10); /* 00010000 VCO control bit, as recommended */ + mrf24j40_setreg(dev->spi, MRF24J40_SLPCON1, 0x01); /* 00000001 no CLKOUT, default divisor */ + mrf24j40_setreg(dev->spi, MRF24J40_BBREG6 , 0x40); /* 01000000 Append RSSI to rx packets */ + + /* Set this in reset since it can exist for all device modes. See pg 101 */ + + mrf24j40_setreg(dev->spi, MRF24J40_FRMOFFSET, 0x15); + + /* For now, we want to always just have the frame pending bit set when + * acknowledging a Data Request command. The standard says that the coordinator + * can do this if it needs time to figure out whether it has data or not + */ + + mrf24j40_setreg(dev->spi, MRF24J40_ACKTMOUT, 0x39 | MRF24J40_ACKTMOUT_DRPACK); + + /* Set WAKECNT (SLPACK 0x35<6:0>) value = 0x5F to set the main oscillator + * (20 MHz) start-up timer value. + */ + + mrf24j40_setreg(dev->spi, MRF24J40_SLPACK, 0x5F); + + /* Enable the SLPIF and WAKEIF flags */ + + reg = mrf24j40_getreg(dev->spi, MRF24J40_INTCON); + reg &= ~(MRF24J40_INTCON_SLPIE | MRF24J40_INTCON_WAKEIE); + mrf24j40_setreg(dev->spi, MRF24J40_INTCON, reg); + + dev->rxenabled = false; + + mrf24j40_setchannel(dev, 11); + mrf24j40_setpanid(dev, g_allones); + mrf24j40_setsaddr(dev, g_allones); + mrf24j40_seteaddr(dev, g_allones); + + dev->max_frame_waittime = MRF24J40_DEFAULT_MAX_FRAME_WAITTIME; + + /* Default device params */ + + cca.use_ed = 1; + cca.use_cs = 0; + cca.edth = 0x60; /* CCA mode ED, no carrier sense, recommenced ED threshold -69 dBm */ + mrf24j40_setcca(dev, &cca); + + mrf24j40_setrxmode(dev, MRF24J40_RXMODE_NORMAL); + + mrf24j40_settxpower(dev, 0); /*16. Set transmitter power .*/ + + mrf24j40_pacontrol(dev, MRF24J40_PA_AUTO); + + return OK; +} + +static int mrf24j40_getattr(FAR struct ieee802154_radio_s *radio, + enum ieee802154_attr_e attr, + FAR union ieee802154_attr_u *attrval) +{ + FAR struct mrf24j40_radio_s *dev = (FAR struct mrf24j40_radio_s *)radio; + int ret; + + switch (attr) + { + case IEEE802154_ATTR_MAC_EADDR: + { + memcpy(&attrval->mac.eaddr[0], &dev->addr.eaddr[0], 8); + ret = IEEE802154_STATUS_SUCCESS; + } + break; + + case IEEE802154_ATTR_MAC_MAX_FRAME_WAITTIME: + { + attrval->mac.max_frame_waittime = dev->max_frame_waittime; + ret = IEEE802154_STATUS_SUCCESS; + } + break; + + case IEEE802154_ATTR_PHY_SYMBOL_DURATION: + { + attrval->phy.symdur_picosec = MRF24J40_SYMBOL_DURATION_PS; + ret = IEEE802154_STATUS_SUCCESS; + } + break; + + case IEEE802154_ATTR_PHY_CHAN: + { + attrval->phy.chan = dev->chan; + ret = IEEE802154_STATUS_SUCCESS; + } + + default: + ret = IEEE802154_STATUS_UNSUPPORTED_ATTRIBUTE; + } + + return ret; +} + +static int mrf24j40_setattr(FAR struct ieee802154_radio_s *radio, + enum ieee802154_attr_e attr, + FAR const union ieee802154_attr_u *attrval) +{ + FAR struct mrf24j40_radio_s *dev = (FAR struct mrf24j40_radio_s *)radio; + int ret; + + switch (attr) + { + case IEEE802154_ATTR_MAC_PANID: + { + mrf24j40_setpanid(dev, attrval->mac.panid); + ret = IEEE802154_STATUS_SUCCESS; + } + break; + + case IEEE802154_ATTR_MAC_SADDR: + { + mrf24j40_setsaddr(dev, attrval->mac.saddr); + ret = IEEE802154_STATUS_SUCCESS; + } + break; + + case IEEE802154_ATTR_MAC_EADDR: + { + mrf24j40_seteaddr(dev, attrval->mac.eaddr); + ret = IEEE802154_STATUS_SUCCESS; + } + break; + + case IEEE802154_ATTR_MAC_COORD_SADDR: + { + mrf24j40_setcoordsaddr(dev, attrval->mac.coordsaddr); + ret = IEEE802154_STATUS_SUCCESS; + } + break; + + case IEEE802154_ATTR_MAC_COORD_EADDR: + { + mrf24j40_setcoordeaddr(dev, attrval->mac.coordeaddr); + ret = IEEE802154_STATUS_SUCCESS; + } + break; + + case IEEE802154_ATTR_MAC_PROMISCUOUS_MODE: + { + if (attrval->mac.promisc_mode) + { + mrf24j40_setrxmode(dev, MRF24J40_RXMODE_PROMISC); + } + else + { + mrf24j40_setrxmode(dev, MRF24J40_RXMODE_NORMAL); + } + + ret = IEEE802154_STATUS_SUCCESS; + } + break; + + case IEEE802154_ATTR_MAC_RX_ON_WHEN_IDLE: + { + dev->rxonidle = attrval->mac.rxonidle; + mrf24j40_rxenable(radio, dev->rxonidle); + ret = IEEE802154_STATUS_SUCCESS; + } + break; + + case IEEE802154_ATTR_PHY_CHAN: + { + mrf24j40_setchannel(dev, attrval->phy.chan); + ret = IEEE802154_STATUS_SUCCESS; + } + break; + + default: + ret = IEEE802154_STATUS_UNSUPPORTED_ATTRIBUTE; + break; + } + return ret; +} + +static int mrf24j40_beaconstart(FAR struct ieee802154_radio_s *radio, + FAR const struct ieee802154_superframespec_s *sfspec, + FAR struct ieee802154_beaconframe_s *beacon) +{ + FAR struct mrf24j40_radio_s *dev = (FAR struct mrf24j40_radio_s *)radio; + int reg; + + if (sfspec->pancoord) + { + /* Set the PANCOORD (RXMCR 0x00<3>) bit = 1to configure as PAN coordinator */ + + reg = mrf24j40_getreg(dev->spi, MRF24J40_RXMCR); + reg |= MRF24J40_RXMCR_PANCOORD; + mrf24j40_setreg(dev->spi, MRF24J40_RXMCR, reg); + + /* Set the SLOTTED (TXMCR 0x11<5>) bit = 1 to use Slotted CSMA-CA mode */ + + reg = mrf24j40_getreg(dev->spi, MRF24J40_TXMCR); + reg |= MRF24J40_TXMCR_SLOTTED; + mrf24j40_setreg(dev->spi, MRF24J40_TXMCR, reg); + + /* Load the beacon frame into the TXBFIFO (0x080-0x0FF). */ + + mrf24j40_setup_fifo(dev, beacon->bf_data, beacon->bf_len, MRF24J40_BEACON_FIFO); + + /* Set the TXBMSK (TXBCON1 0x25<7>) bit = 1 to mask the beacon interrupt + * mask + */ + + reg = mrf24j40_getreg(dev->spi, MRF24J40_TXBCON1); + reg |= MRF24J40_TXBCON1_TXBMSK; + mrf24j40_setreg(dev->spi, MRF24J40_TXBCON1, reg); + + /* Set INTL (WAKECON 0x22<5:0>) value to 0x03. */ + + reg = mrf24j40_getreg(dev->spi, MRF24J40_WAKECON); + reg &= ~MRF24J40_WAKECON_INTL; + reg |= 0x03 & MRF24J40_WAKECON_INTL; + mrf24j40_setreg(dev->spi, MRF24J40_WAKECON, reg); + + /* Program the CAP end slot (ESLOTG1 0x13<3:0>) value. */ + + reg = mrf24j40_getreg(dev->spi, MRF24J40_ESLOTG1); + reg &= ~MRF24J40_ESLOTG1_CAP; + reg |= sfspec->final_capslot & MRF24J40_ESLOTG1_CAP; + mrf24j40_setreg(dev->spi, MRF24J40_ESLOTG1, reg); + + /* TODO: Add GTS related code. See pg 100 of datasheet */ + + + mrf24j40_setorder(dev, sfspec->beaconorder, sfspec->sforder); + } + else + { + return -ENOTTY; + } + + return OK; +} + +static int mrf24j40_beaconupdate(FAR struct ieee802154_radio_s *radio, + FAR struct ieee802154_beaconframe_s *beacon) +{ + FAR struct mrf24j40_radio_s *dev = (FAR struct mrf24j40_radio_s *)radio; + + mrf24j40_setup_fifo(dev, beacon->bf_data, beacon->bf_len, MRF24J40_BEACON_FIFO); + + return OK; +} + +static int mrf24j40_beaconstop(FAR struct ieee802154_radio_s *radio) +{ + return -ENOTTY; +} + +static int mrf24j40_sfupdate(FAR struct ieee802154_radio_s *radio, + FAR const struct ieee802154_superframespec_s *sfspec) +{ + FAR struct mrf24j40_radio_s *dev = (FAR struct mrf24j40_radio_s *)radio; + int reg; + + /* If we are operating on a beacon-enabled network, use slotted CSMA */ + + reg = mrf24j40_getreg(dev->spi, MRF24J40_TXMCR); + if (sfspec->beaconorder < 15) + { + reg |= MRF24J40_TXMCR_SLOTTED; + } + else + { + reg &= ~MRF24J40_TXMCR_SLOTTED; + } + mrf24j40_setreg(dev->spi, MRF24J40_TXMCR, reg); + + mrf24j40_setorder(dev, sfspec->beaconorder, sfspec->sforder); + + /* Program the CAP end slot (ESLOTG1 0x13<3:0>) value. */ + + reg = mrf24j40_getreg(dev->spi, MRF24J40_ESLOTG1); + reg &= ~MRF24J40_ESLOTG1_CAP; + reg |= sfspec->final_capslot & MRF24J40_ESLOTG1_CAP; + mrf24j40_setreg(dev->spi, MRF24J40_ESLOTG1, reg); + + return OK; +} + +/**************************************************************************** + * Internal Functions + ****************************************************************************/ + +static void mrf24j40_mactimer(FAR struct mrf24j40_radio_s *dev, int numsymbols) +{ + uint16_t nhalfsym; + uint8_t reg; + + nhalfsym = (numsymbols << 1); + + /* Disable the interrupt, clear the timer count */ + + reg = mrf24j40_getreg(dev->spi, MRF24J40_INTCON); + reg |= MRF24J40_INTCON_HSYMTMRIE; + mrf24j40_setreg(dev->spi, MRF24J40_INTCON, reg); + + mrf24j40_setreg(dev->spi, MRF24J40_HSYMTMRL, 0x00); + mrf24j40_setreg(dev->spi, MRF24J40_HSYMTMRH, 0x00); + + reg &= ~MRF24J40_INTCON_HSYMTMRIE; + mrf24j40_setreg(dev->spi, MRF24J40_INTCON, reg); + + /* Set the timer count and enable interrupts */ + + reg = (nhalfsym & 0xFF); + mrf24j40_setreg(dev->spi, MRF24J40_HSYMTMRL, reg); + + reg = (nhalfsym >> 8) & 0xFF; + mrf24j40_setreg(dev->spi, MRF24J40_HSYMTMRH, reg); +} + +/**************************************************************************** + * Function: mrf24j40_dopoll_csma + * + * Description: + * This function is called in order to preform an out-of-sequence TX poll. + * This is done: + * + * 1. After completion of a transmission (mrf24j40_txdone_csma), + * 2. When new TX data is available (mrf24j40_txnotify), and + * 3. After a TX timeout to restart the sending process + * (mrf24j40_txtimeout_csma). + * + * Parameters: + * radio - Reference to the radio driver state structure + * + * Returned Value: + * None + * + * Assumptions: + * + ****************************************************************************/ + +static void mrf24j40_dopoll_csma(FAR void *arg) +{ + FAR struct mrf24j40_radio_s *dev = (FAR struct mrf24j40_radio_s *)arg; + int len = 0; + + /* Get exclusive access to the driver */ + + while (sem_wait(&dev->exclsem) != 0) { } + + /* If this a CSMA transaction and we have room in the CSMA fifo */ + + if (!dev->csma_busy) + { + wlinfo("polling for frame\n"); + len = dev->radiocb->poll(dev->radiocb, false, &dev->csma_desc); + + if (len > 0) + { + wlinfo("frame received. frame length: %d\n", len); + + /* Now the txdesc is in use */ + + dev->csma_busy = 1; + + /* Setup the transaction on the device in the CSMA FIFO */ + + mrf24j40_norm_setup(dev, dev->csma_desc->frame, true); + mrf24j40_norm_trigger(dev); + } + else + { + wlinfo("no frames\n"); + } + } + + sem_post(&dev->exclsem); +} + +/**************************************************************************** + * Function: mrf24j40_dopoll_gts + * + * Description: + * This function is called in order to preform an out-of-sequence TX poll. + * This is done: + * + * 1. After completion of a transmission (mrf24j40_txdone_gts), + * 2. When new TX data is available (mrf24j40_txnotify), and + * 3. After a TX timeout to restart the sending process + * (mrf24j40_txtimeout_gts). + * + * Parameters: + * arg - Reference to the radio driver state structure + * + * Returned Value: + * None + * + * Assumptions: + * + ****************************************************************************/ + +static void mrf24j40_dopoll_gts(FAR void *arg) +{ + FAR struct mrf24j40_radio_s *dev = (FAR struct mrf24j40_radio_s *)arg; + int gts = 0; + int len = 0; + + /* Get exclusive access to the driver */ + + while (sem_wait(&dev->exclsem) != 0) { } + + for (gts = 0; gts < MRF24J40_GTS_SLOTS; gts++) + { + if (!dev->gts_busy[gts]) + { + len = dev->radiocb->poll(dev->radiocb, true, &dev->gts_desc[gts]); + + if (len > 0) + { + /* Now the txdesc is in use */ + + dev->gts_busy[gts]= 1; + + /* Setup the transaction on the device in the open GTS FIFO */ + + mrf24j40_gts_setup(dev, gts, dev->gts_desc[gts]->frame); + } + } + } + + sem_post(&dev->exclsem); +} + +/**************************************************************************** + * Name: mrf24j40_spi_lock + * + * Description: + * Acquire exclusive access to the shared SPI bus. + * + ****************************************************************************/ + +static void mrf24j40_spi_lock(FAR struct spi_dev_s *spi) +{ + SPI_LOCK(spi, 1); + SPI_SETBITS(spi, 8); + SPI_SETMODE(spi, CONFIG_IEEE802154_MRF24J40_SPIMODE); + SPI_SETFREQUENCY(spi, CONFIG_IEEE802154_MRF24J40_FREQUENCY); +} + +/**************************************************************************** + * Name: mrf24j40_spi_unlock + * + * Description: + * Release exclusive access to the shared SPI bus. + * + ****************************************************************************/ + +static inline void mrf24j40_spi_unlock(FAR struct spi_dev_s *spi) +{ + SPI_LOCK(spi,0); +} + +/**************************************************************************** + * Name: mrf24j40_setreg + * + * Description: + * Define the value of an MRF24J40 device register + * + ****************************************************************************/ + +static void mrf24j40_setreg(FAR struct spi_dev_s *spi, uint32_t addr, + uint8_t val) +{ + uint8_t buf[3]; + int len; + + if (!(addr&0x80000000)) + { + addr &= 0x3F; /* 6-bit address */ + addr <<= 1; + addr |= 0x01; /* writing */ + buf[0] = addr; + len = 1; + } + else + { + addr &= 0x3FF; /* 10-bit address */ + addr <<= 5; + addr |= 0x8010; /* writing long */ + buf[0] = (addr >> 8); + buf[1] = (addr & 0xFF); + len = 2; + } + + buf[len++] = val; + + mrf24j40_spi_lock(spi); + SPI_SELECT(spi, SPIDEV_IEEE802154(0), true); + SPI_SNDBLOCK(spi, buf, len); + SPI_SELECT(spi, SPIDEV_IEEE802154(0), false); + mrf24j40_spi_unlock(spi); +} + +/**************************************************************************** + * Name: mrf24j40_getreg + * + * Description: + * Return the value of an MRF24J40 device register* + * + ****************************************************************************/ + +static uint8_t mrf24j40_getreg(FAR struct spi_dev_s *spi, uint32_t addr) +{ + uint8_t buf[3]; + uint8_t rx[3]; + int len; + + if (!(addr&0x80000000)) + { + /* 6-bit address */ + + addr &= 0x3F; + addr <<= 1; + buf[0] = addr; + len = 1; + } + else + { + /* 10-bit address */ + + addr &= 0x3FF; + addr <<= 5; + addr |= 0x8000; + buf[0] = (addr >> 8); + buf[1] = (addr & 0xFF); + len = 2; + } + + buf[len++] = 0xFF; /* dummy */ + + mrf24j40_spi_lock (spi); + SPI_SELECT (spi, SPIDEV_IEEE802154(0), true); + SPI_EXCHANGE (spi, buf, rx, len); + SPI_SELECT (spi, SPIDEV_IEEE802154(0), false); + mrf24j40_spi_unlock(spi); + + /* wlinfo("r[%04X]=%02X\n", addr, rx[len - 1]); */ + return rx[len - 1]; +} + +/**************************************************************************** + * Name: mrf24j40_resetrfsm + * + * Description: + * Reset the RF state machine. Required at boot, after channel change, + * and probably after PA settings. + * + ****************************************************************************/ + +static int mrf24j40_resetrfsm(FAR struct mrf24j40_radio_s *dev) +{ + uint8_t reg; + + reg = mrf24j40_getreg(dev->spi, MRF24J40_RFCTL); + reg |= 0x04; + mrf24j40_setreg(dev->spi, MRF24J40_RFCTL, reg); + + reg &= ~0x04; + mrf24j40_setreg(dev->spi, MRF24J40_RFCTL, reg); + up_udelay(200); + + return OK; +} + +/**************************************************************************** + * Name: mrf24j40_setorder + * + * Description: + * Configures the timers and sets the ORDER register + ****************************************************************************/ + +static void mrf24j40_setorder(FAR struct mrf24j40_radio_s *dev, uint8_t bo, + uint8_t so) +{ + uint32_t maincnt = 0; + uint32_t slpcal = 0; + + /* Calibrate the Sleep Clock (SLPCLK) frequency. Refer to Section 3.15.1.2 + * “Sleep Clock Calibration”. + */ + + /* If the Sleep Clock Selection, SLPCLKSEL (0x207<7:6), is the internal + * oscillator (100 kHz), set SLPCLKDIV to a minimum value of 0x01. + */ + + mrf24j40_setreg(dev->spi, MRF24J40_SLPCON1, 0x01); + + /* Select the source of SLPCLK (internal 100kHz) */ + + mrf24j40_setreg(dev->spi, MRF24J40_RFCON7, MRF24J40_RFCON7_SEL_100KHZ); + + /* Begin calibration by setting the SLPCALEN bit (SLPCAL2 0x20B<4>) to + * ‘1’. Sixteen samples of the SLPCLK are counted and stored in the + * SLPCAL register. No need to mask, this is the only writable bit + */ + + mrf24j40_setreg(dev->spi, MRF24J40_SLPCAL2, MRF24J40_SLPCAL2_SLPCALEN); + + /* Calibration is complete when the SLPCALRDY bit (SLPCAL2 0x20B<7>) is + * set to ‘1’. + */ + + while (!(mrf24j40_getreg(dev->spi, MRF24J40_SLPCAL2) & + MRF24J40_SLPCAL2_SLPCALRDY)) + { + usleep(1); + } + + slpcal = mrf24j40_getreg(dev->spi, MRF24J40_SLPCAL0); + slpcal |= (mrf24j40_getreg(dev->spi, MRF24J40_SLPCAL1) << 8); + slpcal |= ((mrf24j40_getreg(dev->spi, MRF24J40_SLPCAL2) << 16) & 0x0F); + + /* Program the Beacon Interval into the Main Counter, MAINCNT (0x229<1:0>, + * 0x228, 0x227, 0x226), and Remain Counter, REMCNT (0x225, 0x224), + * according to BO and SO values. Refer to Section 3.15.1.3 “Sleep Mode + * Counters” + */ + + + mrf24j40_setreg(dev->spi, MRF24J40_REMCNTL, (MRF24J40_REMCNT & 0xFF)); + mrf24j40_setreg(dev->spi, MRF24J40_REMCNTH, ((MRF24J40_REMCNT >> 8) & 0xFF)); + + maincnt = MRF24J40_MAINCNT(bo, (slpcal * 50 / 16)); + + mrf24j40_setreg(dev->spi, MRF24J40_MAINCNT0, (maincnt & 0xFF)); + mrf24j40_setreg(dev->spi, MRF24J40_MAINCNT1, ((maincnt >> 8) & 0xFF)); + mrf24j40_setreg(dev->spi, MRF24J40_MAINCNT2, ((maincnt >> 16) & 0xFF)); + mrf24j40_setreg(dev->spi, MRF24J40_MAINCNT3, ((maincnt >> 24) & 0x03)); + + /* Configure the BO (ORDER 0x10<7:4>) and SO (ORDER 0x10<3:0>) values. + * After configuring BO and SO, the beacon frame will be sent immediately. + */ + + mrf24j40_setreg(dev->spi, MRF24J40_ORDER, ((bo << 4) & 0xF0) | (so & 0x0F)); +} + +/**************************************************************************** + * Name: mrf24j40_pacontrol + * + * Description: + * Control the external LNA/PA on the MRF24J40MB/MC/MD/ME modules + * GPIO 1: PA enable + * GPIO 2: LNA enable + * GPIO 3: PA power enable (not required on MB) + ****************************************************************************/ + +static int mrf24j40_pacontrol(FAR struct mrf24j40_radio_s *dev, int mode) +{ + if (!dev->paenabled) + { + return OK; + } + + if (mode == MRF24J40_PA_AUTO) + { + mrf24j40_setreg(dev->spi, MRF24J40_TRISGPIO, 0x08); + mrf24j40_setreg(dev->spi, MRF24J40_GPIO , 0x08); + mrf24j40_setreg(dev->spi, MRF24J40_TESTMODE, 0x0F); + } + else if (mode == MRF24J40_PA_ED) + { + mrf24j40_setreg(dev->spi, MRF24J40_TESTMODE, 0x08); + mrf24j40_setreg(dev->spi, MRF24J40_TRISGPIO, 0x0F); + mrf24j40_setreg(dev->spi, MRF24J40_GPIO , 0x0C); + } + else if (mode == MRF24J40_PA_SLEEP) + { + mrf24j40_setreg(dev->spi, MRF24J40_TESTMODE, 0x08); + mrf24j40_setreg(dev->spi, MRF24J40_TRISGPIO, 0x0F); + mrf24j40_setreg(dev->spi, MRF24J40_GPIO , 0x00); + } + else + { + return -EINVAL; + } + + mrf24j40_resetrfsm(dev); + return OK; +} + +/**************************************************************************** + * Name: mrf24j40_setrxmode + * + * Description: + * Set the RX mode (normal, promiscuous, no CRC) + * + ****************************************************************************/ + +static int mrf24j40_setrxmode(FAR struct mrf24j40_radio_s *dev, int mode) +{ + uint8_t reg; + + if (mode < MRF24J40_RXMODE_NORMAL || mode > MRF24J40_RXMODE_NOCRC) + { + return -EINVAL; + } + + reg = mrf24j40_getreg(dev->spi, MRF24J40_RXMCR); + reg &= ~0x03; + reg |= mode; + + /* Set mode options */ + + if (mode != MRF24J40_RXMODE_NORMAL) + { + /* Promisc and error modes: Disable auto ACK */ + + reg |= MRF24J40_RXMCR_NOACKRSP; + } + else + { + /* Normal mode : enable auto-ACK */ + + reg &= ~MRF24J40_RXMCR_NOACKRSP; + } + + mrf24j40_setreg(dev->spi, MRF24J40_RXMCR, reg); + + dev->rxmode = mode; + wlinfo("%u\n", (unsigned)mode); + return OK; +} + +/**************************************************************************** + * Name: mrf24j40_setchannel + * + * Description: + * Define the current radio channel the device is operating on. + * In the 2.4 GHz, there are 16 channels, each 2 MHz wide, 5 MHz spacing: + * Chan MHz Chan MHz Chan MHz Chan MHz + * 11 2405 15 2425 19 2445 23 2465 + * 12 2410 16 2430 20 2450 24 2470 + * 13 2415 17 2435 21 2455 25 2475 + * 14 2420 18 2440 22 2460 26 2480 + * + ****************************************************************************/ + +static int mrf24j40_setchannel(FAR struct mrf24j40_radio_s *dev, uint8_t chan) +{ + if (chan < 11 || chan > 26) + { + wlerr("ERROR: Invalid chan: %d\n",chan); + return -EINVAL; + } + + /* 15. Set channel – See Section 3.4 “Channel Selection”. */ + + mrf24j40_setreg(dev->spi, MRF24J40_RFCON0, (chan - 11) << 4 | 0x03); + + /* 17. RFCTL (0x36) = 0x04 – Reset RF state machine. + * 18. RFCTL (0x36) = 0x00. + */ + + mrf24j40_resetrfsm(dev); + + dev->chan = chan; + wlinfo("%u\n", (unsigned)chan); + + return OK; +} + +/**************************************************************************** + * Name: mrf24j40_setpanid + * + * Description: + * Define the PAN ID the device is operating on. + * + ****************************************************************************/ + +static int mrf24j40_setpanid(FAR struct mrf24j40_radio_s *dev, + FAR const uint8_t *panid) +{ + mrf24j40_setreg(dev->spi, MRF24J40_PANIDL, panid[0]); + mrf24j40_setreg(dev->spi, MRF24J40_PANIDH, panid[1]); + + IEEE802154_PANIDCOPY(dev->addr.panid, panid); + wlinfo("%02X:%02X\n", panid[0], panid[1]); + + return OK; +} + +/**************************************************************************** + * Name: mrf24j40_setsaddr + * + * Description: + * Define the device short address. The following addresses are special: + * FFFEh : Broadcast + * FFFFh : Unspecified + * + ****************************************************************************/ + +static int mrf24j40_setsaddr(FAR struct mrf24j40_radio_s *dev, + FAR const uint8_t *saddr) +{ + mrf24j40_setreg(dev->spi, MRF24J40_SADRL, saddr[0]); + mrf24j40_setreg(dev->spi, MRF24J40_SADRH, saddr[1]); + + IEEE802154_SADDRCOPY(dev->addr.saddr, saddr); + + wlinfo("%02X:%02X\n", saddr[0], saddr[1]); + return OK; +} + +/**************************************************************************** + * Name: mrf24j40_seteaddr + * + * Description: + * Define the device extended address. The following addresses are special: + * FFFFFFFFFFFFFFFFh : Unspecified + * + ****************************************************************************/ + +static int mrf24j40_seteaddr(FAR struct mrf24j40_radio_s *dev, + FAR const uint8_t *eaddr) +{ + int i; + + for (i = 0; i < 8; i++) + { + mrf24j40_setreg(dev->spi, MRF24J40_EADR0 + i, eaddr[i]); + dev->addr.eaddr[i] = eaddr[i]; + } + wlinfo("%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X\n", eaddr[0], eaddr[1], + eaddr[2], eaddr[3], eaddr[4], eaddr[5], eaddr[6], eaddr[7]); + + return OK; +} + +/**************************************************************************** + * Name: mrf24j40_setcoordsaddr + * + * Description: + * Define the coordinator short address. The following addresses are special: + * FFFEh : Broadcast + * FFFFh : Unspecified + * + ****************************************************************************/ + +static int mrf24j40_setcoordsaddr(FAR struct mrf24j40_radio_s *dev, + FAR const uint8_t *saddr) +{ + mrf24j40_setreg(dev->spi, MRF24J40_ASSOSADR0, saddr[0]); + mrf24j40_setreg(dev->spi, MRF24J40_ASSOSADR1, saddr[1]); + + IEEE802154_SADDRCOPY(dev->addr.saddr, saddr); + + wlinfo("%02X:%02X\n", saddr[0], saddr[1]); + return OK; +} + +/**************************************************************************** + * Name: mrf24j40_setcoordeaddr + * + * Description: + * Define the coordinator extended address. The following addresses are special: + * FFFFFFFFFFFFFFFFh : Unspecified + * + ****************************************************************************/ + +static int mrf24j40_setcoordeaddr(FAR struct mrf24j40_radio_s *dev, + FAR const uint8_t *eaddr) +{ + int i; + + for (i = 0; i < 8; i++) + { + mrf24j40_setreg(dev->spi, MRF24J40_ASSOEADR0 + i, eaddr[i]); + dev->addr.eaddr[i] = eaddr[i]; + } + + wlinfo("%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X\n", eaddr[0], eaddr[1], + eaddr[2], eaddr[3], eaddr[4], eaddr[5], eaddr[6], eaddr[7]); + return OK; +} + +/**************************************************************************** + * Name: mrf24j40_setdevmode + * + * Description: + * Define the device behaviour: normal end device or coordinator + * + ****************************************************************************/ + +static int mrf24j40_setdevmode(FAR struct mrf24j40_radio_s *dev, + uint8_t mode) +{ + int ret = OK; + uint8_t reg; + + /* Disable slotted mode until I decide to implement slotted mode */ + + reg = mrf24j40_getreg(dev->spi, MRF24J40_TXMCR); + reg &= ~MRF24J40_TXMCR_SLOTTED; + mrf24j40_setreg(dev->spi, MRF24J40_TXMCR, reg); + mrf24j40_setreg(dev->spi, MRF24J40_ORDER, 0xFF); + + /* Define dev mode */ + + reg = mrf24j40_getreg(dev->spi, MRF24J40_RXMCR); + + if (mode == MRF24J40_MODE_PANCOORD) + { + reg |= MRF24J40_RXMCR_PANCOORD; + reg &= ~MRF24J40_RXMCR_COORD; + } + else if (mode == MRF24J40_MODE_COORD) + { + reg |= MRF24J40_RXMCR_COORD; + reg &= ~MRF24J40_RXMCR_PANCOORD; + } + else if (mode == MRF24J40_MODE_DEVICE) + { + reg &= ~MRF24J40_RXMCR_PANCOORD; + reg &= ~MRF24J40_RXMCR_COORD; + } + else + { + return -EINVAL; + } + + mrf24j40_setreg(dev->spi, MRF24J40_RXMCR, reg); + dev->devmode = mode; + return ret; +} + +/**************************************************************************** + * Name: mrf24j40_settxpower + * + * Description: + * Define the transmit power. Value is passed in mBm, it is rounded to + * the nearest value. Some MRF modules have a power amplifier, this routine + * does not care about this. We only change the CHIP output power. + * + ****************************************************************************/ + +static int mrf24j40_settxpower(FAR struct mrf24j40_radio_s *dev, + int32_t txpwr) +{ + uint8_t reg; + int save_txpwr = txpwr; + + if (txpwr <= -3000 && txpwr > -3630) + { + reg = 0xC0; + txpwr += 3000; + } + else if (txpwr <= -2000) + { + reg = 0x80; + txpwr += 2000; + } + else if (txpwr <= -1000) + { + reg = 0x40; + txpwr += 1000; + } + else if (txpwr <= 0) + { + reg = 0x00; + } + else + { + return -EINVAL; + } + + wlinfo("remaining attenuation: %d mBm\n",txpwr); + + switch(txpwr/100) + { + case -9: + case -8: + case -7: + case -6: + reg |= 0x07; + break; + + case -5: + reg |= 0x06; + break; + + case -4: + reg |= 0x05; + break; + + case -3: + reg |= 0x04; + break; + + case -2: + reg |= 0x03; + break; + + case -1: + reg |= 0x02; + break; + + case 0: + reg |= 0x00; /* value 0x01 is 0.5 db, not used */ + break; + + default: + return -EINVAL; + } + + mrf24j40_setreg(dev->spi, MRF24J40_RFCON3, reg); + dev->txpower = save_txpwr; + return OK; +} + +/**************************************************************************** + * Name: mrf24j40_setcca + * + * Description: + * Define the Clear Channel Assessement method. + * + ****************************************************************************/ + +static int mrf24j40_setcca(FAR struct mrf24j40_radio_s *dev, + FAR struct ieee802154_cca_s *cca) +{ + uint8_t mode; + + if (!cca->use_ed && !cca->use_cs) + { + return -EINVAL; + } + + if (cca->use_cs && cca->csth > 0x0f) + { + return -EINVAL; + } + + mode = mrf24j40_getreg(dev->spi, MRF24J40_BBREG2); + mode &= 0x03; + + if (cca->use_ed) + { + mode |= MRF24J40_BBREG2_CCAMODE_ED; + mrf24j40_setreg(dev->spi, MRF24J40_CCAEDTH, cca->edth); + } + + if (cca->use_cs) + { + mode |= MRF24J40_BBREG2_CCAMODE_CS; + mode |= cca->csth << 2; + } + + mrf24j40_setreg(dev->spi, MRF24J40_BBREG2, mode); + + memcpy(&dev->cca, cca, sizeof(struct ieee802154_cca_s)); + return OK; +} + +/**************************************************************************** + * Name: mrf24j40_regdump + * + * Description: + * Display the value of all registers. + * + ****************************************************************************/ + +static int mrf24j40_regdump(FAR struct mrf24j40_radio_s *dev) +{ + uint32_t i; + char buf[4+16*3+2+1]; + int len = 0; + + wlinfo("Short regs:\n"); + + for (i = 0; i < 0x40; i++) + { + if ((i & 15) == 0) + { + len=sprintf(buf, "%02x: ",i&0xFF); + } + + len += sprintf(buf+len, "%02x ", mrf24j40_getreg(dev->spi, i)); + if ((i & 15) == 15) + { + sprintf(buf+len, "\n"); + wlinfo("%s", buf); + } + } + + wlinfo("Long regs:\n"); + for (i = 0x80000200; i < 0x80000250; i++) + { + if ((i & 15) == 0) + { + len=sprintf(buf, "%02x: ",i&0xFF); + } + + len += sprintf(buf+len, "%02x ", mrf24j40_getreg(dev->spi, i)); + if ((i & 15) == 15) + { + sprintf(buf+len, "\n"); + wlinfo("%s", buf); + } + } + + return 0; +} + +/**************************************************************************** + * Name: mrf24j40_energydetect + * + * Description: + * Measure the RSSI level for the current channel. + * + ****************************************************************************/ + +static int mrf24j40_energydetect(FAR struct mrf24j40_radio_s *dev, + FAR uint8_t *energy) +{ + uint8_t reg; + + /* Manually enable the LNA*/ + + mrf24j40_pacontrol(dev, MRF24J40_PA_ED); + + /* Set RSSI average duration to 8 symbols */ + + reg = mrf24j40_getreg(dev->spi, MRF24J40_TXBCON1); + reg |= 0x30; + mrf24j40_setreg(dev->spi, MRF24J40_TXBCON1, reg); + + /* 1. Set RSSIMODE1 0x3E<7> – Initiate RSSI calculation. */ + + mrf24j40_setreg(dev->spi, MRF24J40_BBREG6, 0x80); + + /* 2. Wait until RSSIRDY 0x3E<0> is set to ‘1’ – RSSI calculation is + * complete. + */ + + while(!(mrf24j40_getreg(dev->spi, MRF24J40_BBREG6) & 0x01)); + + /* 3. Read RSSI 0x210<7:0> – The RSSI register contains the averaged RSSI + * received power level for 8 symbol periods. + */ + + *energy = mrf24j40_getreg(dev->spi, MRF24J40_RSSI); + + mrf24j40_setreg(dev->spi, MRF24J40_BBREG6, 0x40); + + /* Back to automatic control */ + + mrf24j40_pacontrol(dev, MRF24J40_PA_AUTO); + return OK; +} + +/**************************************************************************** + * Name: mrf24j40_norm_setup + * + * Description: + * Setup a transaction in the normal TX FIFO + * + ****************************************************************************/ + +static void mrf24j40_norm_setup(FAR struct mrf24j40_radio_s *dev, + FAR struct iob_s *frame, bool csma) +{ + uint8_t reg; + + /* Enable tx int */ + + reg = mrf24j40_getreg(dev->spi, MRF24J40_INTCON); + reg &= ~MRF24J40_INTCON_TXNIE; + mrf24j40_setreg(dev->spi, MRF24J40_INTCON, reg); + + /* Enable/Disable CSMA mode */ + + reg = mrf24j40_getreg(dev->spi, MRF24J40_TXMCR); + + if (csma) + { + reg &= ~MRF24J40_TXMCR_NOCSMA; + } + else + { + reg |= MRF24J40_TXMCR_NOCSMA; + } + + mrf24j40_setreg(dev->spi, MRF24J40_TXMCR, reg); + + /* Setup the FIFO */ + + mrf24j40_setup_fifo(dev, frame->io_data, frame->io_len, MRF24J40_TXNORM_FIFO); + + /* If the frame control field contains an acknowledgment request, set the + * TXNACKREQ bit. See IEEE 802.15.4/2003 7.2.1.1 page 112 for info. + */ + + reg = mrf24j40_getreg(dev->spi, MRF24J40_TXNCON); + + if (frame->io_data[0] & IEEE802154_FRAMECTRL_ACKREQ) + { + reg |= MRF24J40_TXNCON_TXNACKREQ; + } + else + { + reg &= ~MRF24J40_TXNCON_TXNACKREQ; + } + + mrf24j40_setreg(dev->spi, MRF24J40_TXNCON, reg); +} + +/**************************************************************************** + * Name: mrf24j40_norm_trigger + * + * Description: + * Trigger the normal TX FIFO + * + ****************************************************************************/ + +static inline void mrf24j40_norm_trigger(FAR struct mrf24j40_radio_s *dev) +{ + uint8_t reg; + + reg = mrf24j40_getreg(dev->spi, MRF24J40_TXNCON); + + reg |= MRF24J40_TXNCON_TXNTRIG; + + mrf24j40_setreg(dev->spi, MRF24J40_TXNCON, reg); +} + +/**************************************************************************** + * Name: mrf24j40_gts_setup + * + * Description: + * Setup a GTS transaction in one of the GTS FIFOs + * + ****************************************************************************/ + +static void mrf24j40_gts_setup(FAR struct mrf24j40_radio_s *dev, uint8_t fifo, + FAR struct iob_s *frame) +{ + +} + +/**************************************************************************** + * Name: mrf24j40_setup_fifo + * + * Description: + * + ****************************************************************************/ + +static void mrf24j40_setup_fifo(FAR struct mrf24j40_radio_s *dev, + FAR const uint8_t *buf, uint8_t length, + uint32_t fifo_addr) +{ + int hlen = 3; /* Include frame control and seq number */ + int i; + uint16_t frame_ctrl; + + /* Analyze frame control to compute header length */ + + frame_ctrl = buf[0]; + frame_ctrl |= (buf[1] << 8); + + if ((frame_ctrl & IEEE802154_FRAMECTRL_DADDR)== IEEE802154_ADDRMODE_SHORT) + { + hlen += 2 + 2; /* Destination PAN + shortaddr */ + } + else if ((frame_ctrl & IEEE802154_FRAMECTRL_DADDR) == IEEE802154_ADDRMODE_EXTENDED) + { + hlen += 2 + 8; /* Destination PAN + extaddr */ + } + + if (!(frame_ctrl & IEEE802154_FRAMECTRL_PANIDCOMP)) + { + hlen += 2; /* No PAN compression, source PAN is different from dest PAN */ + } + + if ((frame_ctrl & IEEE802154_FRAMECTRL_SADDR)== IEEE802154_ADDRMODE_SHORT) + { + hlen += 2; /* Source saddr */ + } + else if ((frame_ctrl & IEEE802154_FRAMECTRL_SADDR) == IEEE802154_ADDRMODE_EXTENDED) + { + hlen += 8; /* Ext saddr */ + } + + /* Header len, 0, TODO for security modes */ + + mrf24j40_setreg(dev->spi, fifo_addr++, hlen); + + /* Frame length */ + + mrf24j40_setreg(dev->spi, fifo_addr++, length); + + /* Frame data */ + + for (i = 0; i < length; i++) + { + mrf24j40_setreg(dev->spi, fifo_addr++, buf[i]); + } +} + +/**************************************************************************** + * Name: mrf24j40_irqwork_txnorm + * + * Description: + * Manage completion of packet transmission. + * + ****************************************************************************/ + +static void mrf24j40_irqwork_txnorm(FAR struct mrf24j40_radio_s *dev) +{ + uint8_t reg; + enum ieee802154_status_e status; + bool framepending; + + /* Disable tx int */ + + reg = mrf24j40_getreg(dev->spi, MRF24J40_INTCON); + reg |= MRF24J40_INTCON_TXNIE; + mrf24j40_setreg(dev->spi, MRF24J40_INTCON, reg); + + /* Get the status from the device and copy the status into the tx desc. + * The status for the normal FIFO is represented with bit TXNSTAT where + * 0=success, 1= failure. + */ + + reg = mrf24j40_getreg(dev->spi, MRF24J40_TXSTAT); + + /* TXNSTAT = 0: Transmission was successful + * TXNSTAT = 1: Transmission failed, retry count exceeded + */ + + if (reg & MRF24J40_TXSTAT_TXNSTAT) + { + /* The number of retries of the most recent transmission is contained in the + * TXNRETRY (TXSTAT 0x24<7:6>) bits. The CCAFAIL (TXSTAT 0x24<5>) bit = 1 + * indicates if the failed transmission was due to the channel busy + * (CSMA-CA timed out). + */ + + if (reg & MRF24J40_TXSTAT_CCAFAIL) + { + status = IEEE802154_STATUS_CHANNEL_ACCESS_FAILURE; + } + else + { + status = IEEE802154_STATUS_NO_ACK; + } + } + else + { + status = IEEE802154_STATUS_SUCCESS; + } + + framepending = (mrf24j40_getreg(dev->spi, MRF24J40_TXNCON) & + MRF24J40_TXNCON_FPSTAT); + + if (dev->txdelayed_busy) + { + /* Inform the next layer of the transmission success/failure */ + + dev->txdelayed_desc->conf->status = status; + dev->txdelayed_desc->framepending = framepending; + dev->radiocb->txdone(dev->radiocb, dev->txdelayed_desc); + + dev->txdelayed_busy = false; + + if (dev->reschedule_csma) + { + mrf24j40_norm_setup(dev, dev->csma_desc->frame, true); + mrf24j40_norm_trigger(dev); + dev->reschedule_csma = false; + } + } + else + { + /* Inform the next layer of the transmission success/failure */ + + dev->csma_desc->conf->status = status; + dev->csma_desc->framepending = framepending; + dev->radiocb->txdone(dev->radiocb, dev->csma_desc); + + /* We are now done with the transaction */ + + dev->csma_busy = 0; + + /* Must unlock the radio before calling poll */ + + sem_post(&dev->exclsem); + mrf24j40_dopoll_csma(dev); + while (sem_wait(&dev->exclsem) != 0) { } + } +} + +/**************************************************************************** + * Name: mrf24j40_irqwork_gts + * + * Description: + * Manage completion of packet transmission. + * + ****************************************************************************/ + +static void mrf24j40_irqwork_txgts(FAR struct mrf24j40_radio_s *dev, + uint8_t gts) +{ + uint8_t txstat; + + /* Disable tx int */ + + txstat = mrf24j40_getreg(dev->spi, MRF24J40_INTCON); + txstat |= MRF24J40_INTCON_TXNIE; + mrf24j40_setreg(dev->spi, MRF24J40_INTCON, txstat); + + /* Get the status from the device and copy the status into the tx desc. + * The status for the normal FIFO is represented with bit TXNSTAT where + * 0=success, 1= failure. + */ + + txstat = mrf24j40_getreg(dev->spi, MRF24J40_TXSTAT); + + if (gts == 0) + { + dev->csma_desc->conf->status = txstat & MRF24J40_TXSTAT_TXG1STAT; + } + else if (gts == 1) + { + dev->csma_desc->conf->status = txstat & MRF24J40_TXSTAT_TXG2STAT; + } + + /* Inform the next layer of the transmission success/failure */ + + dev->radiocb->txdone(dev->radiocb, dev->gts_desc[gts]); + + /* We are now done with the transaction */ + + dev->gts_busy[gts]= 0; + + mrf24j40_dopoll_gts(dev); +} + +/**************************************************************************** + * Name: mrf24j40_rxenable + * + * Description: + * Enable/Disable receiver. + * + ****************************************************************************/ + +static int mrf24j40_rxenable(FAR struct ieee802154_radio_s *radio, bool enable) +{ + FAR struct mrf24j40_radio_s *dev = (FAR struct mrf24j40_radio_s *)radio; + uint8_t reg; + + dev->rxenabled = enable; + + + if (enable) + { + /* Disable packet reception. See pg. 109 of datasheet */ + + mrf24j40_setreg(dev->spi, MRF24J40_BBREG1, MRF24J40_BBREG1_RXDECINV); + + /* Enable rx int */ + + reg = mrf24j40_getreg(dev->spi, MRF24J40_INTCON); + reg &= ~MRF24J40_INTCON_RXIE; + mrf24j40_setreg(dev->spi, MRF24J40_INTCON, reg); + + /* Purge the RX buffer */ + + reg = mrf24j40_getreg(dev->spi, MRF24J40_RXFLUSH); + reg |= MRF24J40_RXFLUSH_RXFLUSH; + mrf24j40_setreg(dev->spi, MRF24J40_RXFLUSH, reg); + + /* Re-enable packet reception. See pg. 109 of datasheet */ + + mrf24j40_setreg(dev->spi, MRF24J40_BBREG1, 0); + } + else + { + /* Disable rx int */ + + reg = mrf24j40_getreg(dev->spi, MRF24J40_INTCON); + reg |= MRF24J40_INTCON_RXIE; + mrf24j40_setreg(dev->spi, MRF24J40_INTCON, reg); + } + + return OK; +} + +/**************************************************************************** + * Name: mrf24j40_irqwork_rx + * + * Description: + * Manage packet reception. + * + ****************************************************************************/ + +static void mrf24j40_irqwork_rx(FAR struct mrf24j40_radio_s *dev) +{ + FAR struct ieee802154_data_ind_s *ind; + uint32_t addr; + uint32_t index; + uint8_t reg; + + wlinfo("RX interrupt\n"); + + /* Disable rx int */ + + reg = mrf24j40_getreg(dev->spi, MRF24J40_INTCON); + reg |= MRF24J40_INTCON_RXIE; + mrf24j40_setreg(dev->spi, MRF24J40_INTCON, reg); + + /* Disable packet reception. See pg. 109 of datasheet */ + + mrf24j40_setreg(dev->spi, MRF24J40_BBREG1, MRF24J40_BBREG1_RXDECINV); + + /* Allocate a data_ind to put the frame in */ + + ind = ieee802154_ind_allocate(); + if (ind == NULL) + { + wlerr("ERROR: Unable to allocate data_ind. Discarding frame\n"); + goto done; + } + + /* Read packet */ + + addr = MRF24J40_RXBUF_BASE; + + ind->frame->io_len = mrf24j40_getreg(dev->spi, addr++); + + /* TODO: This needs to be changed. It is inefficient to do the SPI read byte + * by byte */ + + for (index = 0; index < ind->frame->io_len; index++) + { + ind->frame->io_data[index] = mrf24j40_getreg(dev->spi, addr++); + } + + ind->lqi = mrf24j40_getreg(dev->spi, addr++); + ind->rssi = mrf24j40_getreg(dev->spi, addr++); + + /* Reduce len by 2, we only receive frames with correct crc, no check + * required. + */ + + ind->frame->io_len -= 2; + + /* Callback the receiver in the next highest layer */ + + dev->radiocb->rxframe(dev->radiocb, ind); + +done: + /* Enable reception of next packet by flushing the fifo. + * This is an MRF24J40 errata (no. 1). + */ + + mrf24j40_setreg(dev->spi, MRF24J40_RXFLUSH, 1); + + /* Only enable RX interrupt if we are to be listening when IDLE */ + + if (dev->rxenabled) + { + /* Enable packet reception */ + + mrf24j40_setreg(dev->spi, MRF24J40_BBREG1, 0); + + reg = mrf24j40_getreg(dev->spi, MRF24J40_INTCON); + reg &= ~MRF24J40_INTCON_RXIE; + mrf24j40_setreg(dev->spi, MRF24J40_INTCON, reg); + } +} + +/**************************************************************************** + * Name: mrf24j40_irqworker + * + * Description: + * Perform interrupt handling logic outside of the interrupt handler (on + * the work queue thread). + * + * Parameters: + * arg - The reference to the driver structure (cast to void*) + * + * Returned Value: + * None + * + * Assumptions: + * + ****************************************************************************/ + +static void mrf24j40_irqworker(FAR void *arg) +{ + FAR struct mrf24j40_radio_s *dev = (FAR struct mrf24j40_radio_s *)arg; + uint8_t intstat; + uint8_t reg; + + DEBUGASSERT(dev); + DEBUGASSERT(dev->spi); + + /* Get exclusive access to the driver */ + + while (sem_wait(&dev->exclsem) != 0) { } + + /* Read and store INTSTAT - this clears the register. */ + + intstat = mrf24j40_getreg(dev->spi, MRF24J40_INTSTAT); + + /* Do work according to the pending interrupts */ + + if ((intstat & MRF24J40_INTSTAT_HSYMTMRIF)) + { + /* As of now the only use for the MAC timer is for delayed transactions. + * Therefore, all we do here is trigger the TX norm FIFO + */ + + mrf24j40_norm_trigger(dev); + + /* Timers are one-shot, so disable the interrupt */ + + reg = mrf24j40_getreg(dev->spi, MRF24J40_INTCON); + reg |= MRF24J40_INTCON_HSYMTMRIE; + mrf24j40_setreg(dev->spi, MRF24J40_INTCON, reg); + } + + if ((intstat & MRF24J40_INTSTAT_RXIF) && dev->rxenabled) + { + /* A packet was received, retrieve it */ + + mrf24j40_irqwork_rx(dev); + } + + if ((intstat & MRF24J40_INTSTAT_TXNIF)) + { + /* A packet was transmitted or failed*/ + + mrf24j40_irqwork_txnorm(dev); + } + + if ((intstat & MRF24J40_INTSTAT_TXG1IF)) + { + /* A packet was transmitted or failed*/ + + mrf24j40_irqwork_txgts(dev, 0); + } + + if ((intstat & MRF24J40_INTSTAT_TXG1IF)) + { + /* A packet was transmitted or failed*/ + + mrf24j40_irqwork_txgts(dev, 1); + } + + if ((intstat & MRF24J40_INTSTAT_SLPIF)) + { + dev->radiocb->sfevent(dev->radiocb, IEEE802154_SFEVENT_ENDOFACTIVE); + + /* Acknowledge the alert and put the device to sleep */ + + reg = mrf24j40_getreg(dev->spi, MRF24J40_SLPACK); + reg |= MRF24J40_SLPACK_SLPACK; + mrf24j40_setreg(dev->spi, MRF24J40_SLPACK, reg); + } + + /* Unlock the radio device */ + + sem_post(&dev->exclsem); + + /* Re-enable GPIO interrupts */ + + dev->lower->enable(dev->lower, true); +} + +/**************************************************************************** + * Name: mrf24j40_interrupt + * + * Description: + * Hardware interrupt handler + * + * Parameters: + * irq - Number of the IRQ that generated the interrupt + * context - Interrupt register state save info (architecture-specific) + * + * Returned Value: + * OK on success + * + * Assumptions: + * + ****************************************************************************/ + +static int mrf24j40_interrupt(int irq, FAR void *context, FAR void *arg) +{ + FAR struct mrf24j40_radio_s *dev = (FAR struct mrf24j40_radio_s *)arg; + + DEBUGASSERT(dev != NULL); + + /* In complex environments, we cannot do SPI transfers from the interrupt + * handler because semaphores are probably used to lock the SPI bus. In + * this case, we will defer processing to the worker thread. This is also + * much kinder in the use of system resources and is, therefore, probably + * a good thing to do in any event. + */ + + DEBUGASSERT(work_available(&dev->irqwork)); + + /* Notice that further GPIO interrupts are disabled until the work is + * actually performed. This is to prevent overrun of the worker thread. + * Interrupts are re-enabled in enc_irqworker() when the work is completed. + */ + + dev->lower->enable(dev->lower, false); + return work_queue(HPWORK, &dev->irqwork, mrf24j40_irqworker, (FAR void *)dev, 0); +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: mrf24j40_init + * + * Description: + * Return an mrf24j40 device for use by other drivers. + * + ****************************************************************************/ + +FAR struct ieee802154_radio_s *mrf24j40_init(FAR struct spi_dev_s *spi, + FAR const struct mrf24j40_lower_s *lower) +{ + FAR struct mrf24j40_radio_s *dev; + + dev = kmm_zalloc(sizeof(struct mrf24j40_radio_s)); + if (dev == NULL) + { + return NULL; + } + + /* Attach irq */ + + if (lower->attach(lower, mrf24j40_interrupt, dev) != OK) + { +#if 0 + free(dev); +#endif + return NULL; + } + + /* Allow exclusive access to the privmac struct */ + + sem_init(&dev->exclsem, 0, 1); + + dev->radio.bind = mrf24j40_bind; + dev->radio.reset = mrf24j40_reset; + dev->radio.getattr = mrf24j40_getattr; + dev->radio.setattr = mrf24j40_setattr; + dev->radio.txnotify = mrf24j40_txnotify; + dev->radio.txdelayed = mrf24j40_txdelayed; + dev->radio.rxenable = mrf24j40_rxenable; + dev->radio.beaconstart = mrf24j40_beaconstart; + dev->radio.beaconupdate = mrf24j40_beaconupdate; + dev->radio.beaconstop = mrf24j40_beaconstop; + dev->radio.sfupdate = mrf24j40_sfupdate; + + dev->lower = lower; + dev->spi = spi; + + mrf24j40_reset(&dev->radio); + + dev->lower->enable(dev->lower, true); + return &dev->radio; +} diff --git a/include/nuttx/wireless/ieee802154/ieee802154_mac.h b/include/nuttx/wireless/ieee802154/ieee802154_mac.h index b079a32902..11b1d96d81 100644 --- a/include/nuttx/wireless/ieee802154/ieee802154_mac.h +++ b/include/nuttx/wireless/ieee802154/ieee802154_mac.h @@ -593,19 +593,10 @@ struct ieee802154_pandesc_s * in symbols */ }; -struct ieee802154_pend_addr_s +struct ieee802154_pendaddr_s { - union - { - uint8_t pa_spec; - struct - { - uint8_t num_short_addr : 3; /* Number of short addresses pending */ - uint8_t reserved_3 : 1; /* Reserved bit */ - uint8_t num_ext_addr : 3; /* Number of extended addresses pending */ - uint8_t reserved_7 : 1; /* Reserved bit */ - } pa_addr; - } u; + uint8_t nsaddr : 3; /* Number of short addresses pending */ + uint8_t neaddr : 3; /* Number of extended addresses pending */ struct ieee802154_addr_s addr[7]; /* Array of at most 7 addresses */ }; @@ -632,7 +623,7 @@ union ieee802154_macattr_u bool is_assoc; bool assocpermit; - bool auto_req; + bool autoreq; bool batt_life_ext; bool gts_permit; bool promisc_mode; @@ -1112,7 +1103,7 @@ struct ieee802154_disassoc_conf_s * *****************************************************************************/ -struct ieee802154_beaconnotify_ind_s +struct ieee802154_beacon_ind_s { uint8_t bsn; /* Beacon sequence number */ @@ -1122,20 +1113,11 @@ struct ieee802154_beaconnotify_ind_s /* Beacon pending addresses */ - struct ieee802154_pend_addr_s pend_addr; - - uint8_t sdu_length; /* Number of octets contained in the beacon - * payload of the received beacond frame */ - - /* Beacon payload */ - - uint8_t sdu[IEEE802154_MAX_BEACON_PAYLOAD_LEN]; + struct ieee802154_pendaddr_s pendaddr; + uint8_t payloadlength; /* # of octets contained in the beacon payload */ + uint8_t payload[IEEE802154_MAX_BEACON_PAYLOAD_LEN]; }; -#define SIZEOF_IEEE802154_BEACONNOTIFY_IND_S(n) \ - (sizeof(struct ieee802154_beaconnotify_ind_s) \ - - IEEE802154_MAX_BEACON_PAYLOAD_LEN + (n)) - /***************************************************************************** * Primitive: MLME-COMM-STATUS.indication * @@ -1538,21 +1520,21 @@ union ieee802154_notif_u /* MLME Notifications */ - struct ieee802154_assoc_conf_s assocconf; - struct ieee802154_disassoc_conf_s disassocconf; - struct ieee802154_gts_conf_s gtsconf; - struct ieee802154_rxenable_conf_s rxenableconf; - struct ieee802154_scan_conf_s scanconf; - struct ieee802154_start_conf_s startconf; - struct ieee802154_poll_conf_s pollconf; + struct ieee802154_assoc_conf_s assocconf; + struct ieee802154_disassoc_conf_s disassocconf; + struct ieee802154_gts_conf_s gtsconf; + struct ieee802154_rxenable_conf_s rxenableconf; + struct ieee802154_scan_conf_s scanconf; + struct ieee802154_start_conf_s startconf; + struct ieee802154_poll_conf_s pollconf; - struct ieee802154_assoc_ind_s assocind; - struct ieee802154_disassoc_ind_s disassocind; - struct ieee802154_beaconnotify_ind_s beaconnotifyind; - struct ieee802154_gts_ind_s gtsind; - struct ieee802154_orphan_ind_s orphanind; - struct ieee802154_commstatus_ind_s commstatusind; - struct ieee802154_syncloss_ind_s synclossind; + struct ieee802154_assoc_ind_s assocind; + struct ieee802154_disassoc_ind_s disassocind; + struct ieee802154_beacon_ind_s beaconind; + struct ieee802154_gts_ind_s gtsind; + struct ieee802154_orphan_ind_s orphanind; + struct ieee802154_commstatus_ind_s commstatusind; + struct ieee802154_syncloss_ind_s synclossind; }; struct ieee802154_notif_s diff --git a/wireless/ieee802154/mac802154.c b/wireless/ieee802154/mac802154.c index 7e0935025c..5c62aac4c4 100644 --- a/wireless/ieee802154/mac802154.c +++ b/wireless/ieee802154/mac802154.c @@ -1528,51 +1528,181 @@ static void mac802154_sfevent(FAR const struct ieee802154_radiocb_s *radiocb, * Function called from the generic RX Frame worker to parse and handle the * reception of a beacon frame. * + * Assumptions: MAC is locked + * ****************************************************************************/ static void mac802154_rxbeaconframe(FAR struct ieee802154_privmac_s *priv, FAR struct ieee802154_data_ind_s *ind) { - FAR struct iob_s *iob = ind->frame; - struct ieee802154_pandesc_s pandesc; FAR struct ieee802154_txdesc_s *respdesc; - uint8_t numgtsdesc; + FAR struct ieee802154_notif_s *notif; + FAR struct ieee802154_beacon_ind_s *beacon; + FAR struct iob_s *iob = ind->frame; + uint8_t ngtsdesc; uint8_t gtsdirmask; - uint8_t npendsaddr; - uint8_t npendeaddr; + bool pending_saddr = false; + bool pending_eaddr = false; int i; + /* Even though we may not use the notification, we use a notification to + * hold all the parsed beacon information. Freeing the notification is quick, + * so it's worth saving a copy (If you were to parse all the info in locally, + * you would have to copy the data over in the case that you actually need + * to notify the next highest layer) + */ + + mac802154_notif_alloc(priv, ¬if, false); + beacon = ¬if->u.beaconind; + + /* Make sure there is another 2 bytes to process */ + + if (iob->io_len < iob->io_offset + 2) + { + goto errout; + } + /* Copy the coordinator address and channel info into the pan descriptor */ - memcpy(&pandesc.coordaddr, &ind->src, sizeof(struct ieee802154_addr_s)); - pandesc.chan = priv->currscan.channels[priv->scanindex]; - pandesc.chpage = priv->currscan.chpage; - pandesc.lqi = ind->lqi; - pandesc.timestamp = ind->timestamp; + memcpy(&beacon->pandesc.coordaddr, &ind->src, sizeof(struct ieee802154_addr_s)); + beacon->pandesc.chan = priv->currscan.channels[priv->scanindex]; + beacon->pandesc.chpage = priv->currscan.chpage; + beacon->pandesc.lqi = ind->lqi; + beacon->pandesc.timestamp = ind->timestamp; /* Parse the superframe specification field */ - pandesc.sfspec.beaconorder = IEEE802154_GETBEACONORDER(iob->io_data, - iob->io_offset); + beacon->pandesc.sfspec.beaconorder = IEEE802154_GETBEACONORDER(iob->io_data, + iob->io_offset); + + beacon->pandesc.sfspec.sforder = + IEEE802154_GETSFORDER(iob->io_data, iob->io_offset); + + beacon->pandesc.sfspec.final_capslot = + IEEE802154_GETFINCAPSLOT(iob->io_data, iob->io_offset); + + beacon->pandesc.sfspec.ble = + IEEE802154_GETBLE(iob->io_data, iob->io_offset); + + beacon->pandesc.sfspec.pancoord = + IEEE802154_GETPANCOORD(iob->io_data, iob->io_offset); + + beacon->pandesc.sfspec.assocpermit = + IEEE802154_GETASSOCPERMIT(iob->io_data, iob->io_offset); - pandesc.sfspec.sforder = IEEE802154_GETSFORDER(iob->io_data, iob->io_offset); - pandesc.sfspec.final_capslot = IEEE802154_GETFINCAPSLOT(iob->io_data, - iob->io_offset); - pandesc.sfspec.ble = IEEE802154_GETBLE(iob->io_data, iob->io_offset); - pandesc.sfspec.pancoord = IEEE802154_GETPANCOORD(iob->io_data, iob->io_offset); - pandesc.sfspec.assocpermit = IEEE802154_GETASSOCPERMIT(iob->io_data, - iob->io_offset); iob->io_offset += 2; + /* Make sure there is another byte to process (GTS Spec) */ + + if (iob->io_len < iob->io_offset + 1) + { + goto errout; + } + /* Parse the GTS Specification field */ - numgtsdesc = IEEE802154_GETGTSDESCCOUNT(iob->io_data, iob->io_offset); - pandesc.gtspermit = IEEE802154_GETGTSPERMIT(iob->io_data, iob->io_offset); + ngtsdesc = IEEE802154_GETGTSDESCCOUNT(iob->io_data, iob->io_offset); + beacon->pandesc.gtspermit = IEEE802154_GETGTSPERMIT(iob->io_data, iob->io_offset); iob->io_offset++; - /* We only need to parse the rest of the frame if we are not performing a - * scan - */ + /* If there are any GTS descriptors, handle the GTS Dir and GTS List fields */ + + if (ngtsdesc > 0) + { + /* Make sure there is another bytes to process (GTS Direction) */ + + if (iob->io_len < iob->io_offset + 1) + { + goto errout; + } + + gtsdirmask = IEEE802154_GETGTSDIRMASK(iob->io_data, iob->io_offset); + iob->io_offset++; + + /* Make sure there are enough bytes left to represent the GTS List */ + + if (iob->io_len < iob->io_offset + (3 * ngtsdesc)) + { + goto errout; + } + + for (i = 0; i < ngtsdesc; i++) + { + /* For now we just discard the data by skipping over it */ + + iob->io_offset += 3; + } + } + + /* Pending address fields. Min 1 byte, the Pending Address Specification */ + + if (iob->io_len < iob->io_offset + 1) + { + goto errout; + } + + beacon->pendaddr.nsaddr = IEEE802154_GETNPENDSADDR(iob->io_data, iob->io_offset); + beacon->pendaddr.neaddr = IEEE802154_GETNPENDEADDR(iob->io_data, iob->io_offset); + iob->io_offset++; + + /* Make sure there are enough bytes left to represent the address list */ + + if (iob->io_len < (iob->io_offset + + (IEEE802154_SADDRSIZE * beacon->pendaddr.nsaddr) + + (IEEE802154_EADDRSIZE * beacon->pendaddr.neaddr))) + { + goto errout; + } + + /* Copy in the pending addresses */ + + for (i = 0; i < beacon->pendaddr.nsaddr; i++) + { + beacon->pendaddr.addr[i].mode = IEEE802154_ADDRMODE_SHORT; + mac802154_takesaddr(iob, beacon->pendaddr.addr[i].saddr); + + /* Check if the short address matches our short address */ + + if (IEEE802154_SADDRCMP(beacon->pendaddr.addr[i].saddr, priv->addr.saddr)) + { + /* Wait to actually decide how to handle this until we parse + * the rest of the frame + */ + wlinfo("Data pending for us in coord\n"); + pending_saddr = true; + } + } + + for (i = beacon->pendaddr.nsaddr; + i < (beacon->pendaddr.nsaddr + beacon->pendaddr.neaddr); + i++) + { + beacon->pendaddr.addr[i].mode = IEEE802154_ADDRMODE_EXTENDED; + + mac802154_takeeaddr(iob, beacon->pendaddr.addr[i].eaddr); + + /* If the extended address matches our extended address */ + + if (IEEE802154_EADDRCMP(beacon->pendaddr.addr[i].eaddr, priv->addr.eaddr)) + { + /* Wait to actually decide how to handle this until we parse + * the rest of the frame + */ + wlinfo("Data pending for us in coord\n"); + pending_eaddr = true; + } + } + + /* If there is anything left in the frame, process it as the beacon payload */ + + beacon->payloadlength = iob->io_len - iob->io_offset; + + if (beacon->payloadlength > 0) + { + memcpy(beacon->payload, &iob->io_data[iob->io_offset], beacon->payloadlength); + } + + /* At this point, we have extracted all relevant info from the incoming frame */ if (priv->curr_op == MAC802154_OP_SCAN) { @@ -1586,19 +1716,30 @@ static void mac802154_rxbeaconframe(FAR struct ieee802154_privmac_s *priv, } if (memcmp(&ind->src, &priv->pandescs[i].coordaddr, - sizeof(struct ieee802154_addr_s))) + sizeof(struct ieee802154_addr_s)) != 0) { continue; } /* The beacon is the same as another, so discard it */ - return; + goto done; } - + + /* TODO: There is supposed to be different logic for the scanning procedure + * based on the macAutoRequest attribute. Currently, we perform scan + * operations as if macAutoRequest is set to TRUE, without actually checking + * the value. Basically, if macAutoRequest is TRUE, we are supposed to + * round up all of the pandesc results and pass them all up via the + * SCAN.confirm primitive. If macAutoRequest is FALSE, we are supposed + * to notify the next highest layer each time a unique beacon is received + * via the BEACON.notify primitive, and pass a NULLed out list of pandesc + * when SCAN.confirm is sent. + */ + /* Copy the pan desc to the list of pan desc */ - memcpy(&priv->pandescs[priv->npandesc], &pandesc, + memcpy(&priv->pandescs[priv->npandesc], &beacon->pandesc, sizeof(struct ieee802154_pandesc_s)); priv->npandesc++; @@ -1607,101 +1748,116 @@ static void mac802154_rxbeaconframe(FAR struct ieee802154_privmac_s *priv, mac802154_scanfinish(priv, IEEE802154_STATUS_LIMITREACHED); } } + + /* If we are not performing a SCAN operation */ + else { - /* If there are any GTS descriptors, handle the GTS Directions and - * GTS List fields - */ - - if (numgtsdesc > 0) - { - gtsdirmask = IEEE802154_GETGTSDIRMASK(iob->io_data, iob->io_offset); - iob->io_offset++; - - for (i = 0; i < numgtsdesc; i++) - { - /* For now we just discard the data by skipping over it */ - - iob->io_offset += 3; - } - } - - /* Pending address fields. Min 1 byte, the Pending Address Specification */ - - npendsaddr = IEEE802154_GETNPENDSADDR(iob->io_data, iob->io_offset); - npendeaddr = IEEE802154_GETNPENDEADDR(iob->io_data, iob->io_offset); - iob->io_offset++; - - /* The pending address field tells us whether or not there is any data - * pending for us. - */ - - for (i = 0; i < npendsaddr; i++) - { - /* If the short address matches our short address */ - - if (IEEE802154_SADDRCMP(&iob->io_data[iob->io_offset], priv->addr.saddr)) - { - /* TODO: Handle data pending in coordinator for us */ - } - iob->io_offset += IEEE802154_SADDRSIZE; - } - - for (i = 0; i < npendeaddr; i++) - { - /* If the extended address matches our extended address */ - - if (IEEE802154_EADDRCMP(&iob->io_data[iob->io_offset], priv->addr.eaddr)) - { - /* If we are associating, polling, or if macAutoRequest is TRUE, - * extract the data. - */ - - if ((priv->autoreq) || (priv->curr_op == MAC802154_OP_ASSOC) || - (priv->curr_op == MAC802154_OP_POLL)) - { - mac802154_txdesc_alloc(priv, &respdesc, false); - - mac802154_createdatareq(priv, &priv->pandesc.coordaddr, - IEEE802154_ADDRMODE_EXTENDED, respdesc); - - if (priv->curr_op == MAC802154_OP_ASSOC || - priv->curr_op == MAC802154_OP_POLL) - { - priv->curr_cmd = IEEE802154_CMD_DATA_REQ; - } - - /* Link the transaction into the CSMA transaction list */ - - sq_addlast((FAR sq_entry_t *)respdesc, &priv->csma_queue); - - /* Notify the radio driver that there is data available */ - - priv->radio->txnotify(priv->radio, false); - } - } - iob->io_offset += IEEE802154_EADDRSIZE; - } - - /* TODO: Process incoming beacon payload - * If there is anything left in the frame, process it as the beacon payload - */ - /* Check the superframe structure and update the appropriate attributes. */ - if (memcmp(&priv->sfspec, &pandesc.sfspec, - sizeof(struct ieee802154_superframespec_s)) != 0) + if (memcmp(&priv->sfspec, &beacon->pandesc.sfspec, + sizeof(struct ieee802154_superframespec_s)) != 0) { /* Copy in the new superframe spec */ - memcpy(&priv->sfspec, &pandesc.sfspec, - sizeof(struct ieee802154_superframespec_s)); + memcpy(&priv->sfspec, &beacon->pandesc.sfspec, + sizeof(struct ieee802154_superframespec_s)); /* Tell the radio layer about the superframe spec update */ - priv->radio->sfupdate(priv->radio, &pandesc.sfspec); + priv->radio->sfupdate(priv->radio, &priv->sfspec); + } + + /* If we are performing an association and there is data pending for us + * we ignore the autoRequest logic and just extract it. We also don't + * send a BEACON-NOTFIY.indication in this case, not sure if that + * is the right thing to do, can't find anything definitive in standard. + */ + + if (priv->curr_op == MAC802154_OP_ASSOC && pending_eaddr) + { + priv->curr_cmd = IEEE802154_CMD_DATA_REQ; + mac802154_txdesc_alloc(priv, &respdesc, false); + mac802154_createdatareq(priv, &priv->pandesc.coordaddr, + IEEE802154_ADDRMODE_EXTENDED, respdesc); + + /* Link the transaction into the CSMA transaction list */ + + sq_addlast((FAR sq_entry_t *)respdesc, &priv->csma_queue); + + /* Notify the radio driver that there is data available */ + + priv->radio->txnotify(priv->radio, false); + } + else if (!priv->autoreq) + { + /* If a valid beacon frame is received and macAutoRequest is set to FALSE, + * the MLME shall indicate the beacon parameters to the next higher layer + * by issuing the MLME-BEACON-NOTIFY.indication primitive. [1] pg. 38 + */ + + /* Unlock the MAC, notify, then lock again */ + + mac802154_givesem(&priv->exclsem); + mac802154_notify(priv, notif); + mac802154_takesem(&priv->exclsem, false); + return; /* Return so that we don't free the notificaiton */ + } + else + { + /* If a beacon frame is received and macAutoRequest is set to TRUE, the + * MLME shall first issue the MLME- BEACON-NOTIFY.indication primitive if + * the beacon contains any payload. + */ + + if (beacon->payloadlength > 0) + { + /* Unlock the MAC, notify, then lock again */ + + mac802154_givesem(&priv->exclsem); + mac802154_notify(priv, notif); + mac802154_takesem(&priv->exclsem, false); + return; /* Return so that we don't free the notificaiton */ + } + + /* If we have data pending for us, attempt to extract it. If for some + * reason we have data pending under our short address and our + * extended address, let the short address arbitrarily take precedence + */ + + if (pending_saddr | pending_eaddr) + { + mac802154_txdesc_alloc(priv, &respdesc, false); + + if (pending_saddr) + { + mac802154_createdatareq(priv, &priv->pandesc.coordaddr, + IEEE802154_ADDRMODE_SHORT, respdesc); + } + else + { + mac802154_createdatareq(priv, &priv->pandesc.coordaddr, + IEEE802154_ADDRMODE_EXTENDED, respdesc); + } + + /* Link the transaction into the CSMA transaction list */ + + sq_addlast((FAR sq_entry_t *)respdesc, &priv->csma_queue); + + /* Notify the radio driver that there is data available */ + + priv->radio->txnotify(priv->radio, false); + } } } + +done: + mac802154_notif_free_locked(priv, notif); + return; + +errout: + wlwarn("Received beacon with bad format\n"); + mac802154_notif_free_locked(priv, notif); } /**************************************************************************** @@ -1864,6 +2020,7 @@ MACHANDLE mac802154_create(FAR struct ieee802154_radio_s *radiodev) if (mac == NULL) { + wlinfo("Failed allocation privmac structure\n"); return NULL; } @@ -1883,8 +2040,6 @@ MACHANDLE mac802154_create(FAR struct ieee802154_radio_s *radiodev) mac->radio = radiodev; - mac802154_req_reset((MACHANDLE)mac, true); - /* Initialize the Radio callbacks */ mac->radiocb.priv = mac; @@ -1904,16 +2059,16 @@ MACHANDLE mac802154_create(FAR struct ieee802154_radio_s *radiodev) ieee802154_indpool_initialize(); mac802154_resetqueues(mac); + mac802154_req_reset((MACHANDLE)mac, true); + /* Set the default extended address */ for (i = 0; i < IEEE802154_EADDRSIZE; i++) { eaddr[i] = (CONFIG_IEEE802154_DEFAULT_EADDR >> (8 * i)) & 0xFF; } - - IEEE802154_EADDRCOPY(mac->addr.eaddr, eaddr); - mac->radio->setattr(mac->radio, IEEE802154_ATTR_MAC_EADDR, - (union ieee802154_attr_u *)&eaddr[0]); + + mac802154_seteaddr(mac, eaddr); return (MACHANDLE)mac; } diff --git a/wireless/ieee802154/mac802154_assoc.c b/wireless/ieee802154/mac802154_assoc.c index ff198b7e9b..dde6575bf6 100644 --- a/wireless/ieee802154/mac802154_assoc.c +++ b/wireless/ieee802154/mac802154_assoc.c @@ -88,6 +88,7 @@ int mac802154_req_associate(MACHANDLE mac, FAR struct iob_s *iob; bool rxonidle; int ret; + int i; if (req->coordaddr.mode == IEEE802154_ADDRMODE_NONE) { @@ -248,14 +249,68 @@ int mac802154_req_associate(MACHANDLE mac, priv->cmd_desc = txdesc; + /* Search the list of PAN descriptors, that would have been populated by the + * latest scan procedure. If we have seen a beacon from the coordinator that + * we are about to associate with, we can check the beacon order to determine + * whether we can send the command during the CAP. If we haven't received + * a beacon frame from the desired coordinator address, we have to just + * send the frame out immediately. + */ + + for (i = 0; i < priv->npandesc; i++) + { + /* Check to make sure the beacon is from the same channel as the request */ + + if (req->chan != priv->pandescs[i].chan) + { + continue; + } + + if (memcmp(&req->coordaddr, &priv->pandescs[i].coordaddr, + sizeof(struct ieee802154_addr_s)) == 0) + { + wlinfo("Found matching beacon to use for settings\n"); + + /* We have a beacon frame from this coordinator, we can set the + * sfspec and send accordingly. + */ + + /* Copy in the new superframe spec */ + + memcpy(&priv->sfspec, &priv->pandescs[i].sfspec, + sizeof(struct ieee802154_superframespec_s)); + + /* Tell the radio layer about the superframe spec update */ + + priv->radio->sfupdate(priv->radio, &priv->pandescs[i].sfspec); + } + } + + if (priv->sfspec.beaconorder == 15) + { + wlinfo("Transmitting assoc request\n"); + + /* Association Request command gets sent out immediately */ + + priv->radio->txdelayed(priv->radio, txdesc, 0); + } + else + { + wlinfo("Queuing assoc request for CAP\n"); + + /* Link the transaction into the CSMA transaction list */ + + sq_addlast((FAR sq_entry_t *)txdesc, &priv->csma_queue); + + /* Notify the radio driver that there is data available */ + + priv->radio->txnotify(priv->radio, false); + } + /* We no longer need to have the MAC layer locked. */ mac802154_givesem(&priv->exclsem); - /* Association Request command gets sent out immediately */ - - priv->radio->txdelayed(priv->radio, txdesc, 0); - return OK; } diff --git a/wireless/ieee802154/mac802154_netdev.c b/wireless/ieee802154/mac802154_netdev.c index 0f49102c5e..bf0225db7b 100644 --- a/wireless/ieee802154/mac802154_netdev.c +++ b/wireless/ieee802154/mac802154_netdev.c @@ -173,8 +173,8 @@ static void macnet_ind_associate(FAR struct macnet_driver_s *priv, FAR struct ieee802154_assoc_ind_s *conf); static void macnet_ind_disassociate(FAR struct macnet_driver_s *priv, FAR struct ieee802154_disassoc_ind_s *conf); -static void macnet_ind_beaconnotify(FAR struct macnet_driver_s *priv, - FAR struct ieee802154_beaconnotify_ind_s *conf); +static void macnet_ind_beacon(FAR struct macnet_driver_s *priv, + FAR struct ieee802154_beacon_ind_s *conf); static void macnet_ind_gts(FAR struct macnet_driver_s *priv, FAR struct ieee802154_gts_ind_s *conf); static void macnet_ind_orphan(FAR struct macnet_driver_s *priv, @@ -589,15 +589,15 @@ static void macnet_ind_disassociate(FAR struct macnet_driver_s *priv, } /**************************************************************************** - * Name: macnet_ind_beaconnotify + * Name: macnet_ind_beacon * * Description: * Beacon notification * ****************************************************************************/ -static void macnet_ind_beaconnotify(FAR struct macnet_driver_s *priv, - FAR struct ieee802154_beaconnotify_ind_s *ind) +static void macnet_ind_beacon(FAR struct macnet_driver_s *priv, + FAR struct ieee802154_beacon_ind_s *ind) { } From 5ca18999a5ff02f9223ed03c7aa90b117501c471 Mon Sep 17 00:00:00 2001 From: Anthony Merlino Date: Fri, 30 Jun 2017 05:26:32 -0400 Subject: [PATCH 07/54] ieee802154: Random fixes to get beacon-enabled networking more stable --- drivers/wireless/ieee802154/mrf24j40.c | 60 ++++++--- drivers/wireless/ieee802154/mrf24j40.h | 5 + wireless/ieee802154/mac802154.c | 153 ++++++++++++++--------- wireless/ieee802154/mac802154_assoc.c | 89 +++++++++---- wireless/ieee802154/mac802154_getset.c | 84 ++++++++----- wireless/ieee802154/mac802154_internal.h | 38 +++++- wireless/ieee802154/mac802154_reset.c | 2 - 7 files changed, 297 insertions(+), 134 deletions(-) diff --git a/drivers/wireless/ieee802154/mrf24j40.c b/drivers/wireless/ieee802154/mrf24j40.c index 538d140861..92c1ade53c 100644 --- a/drivers/wireless/ieee802154/mrf24j40.c +++ b/drivers/wireless/ieee802154/mrf24j40.c @@ -147,10 +147,6 @@ struct mrf24j40_radio_s struct ieee802154_radio_s radio; /* The public device instance */ FAR struct ieee802154_radiocb_s *radiocb; /* Registered callbacks */ - /* MAC Attributes */ - - bool rxonidle : 1; - /* Low-level MCU-specific support */ FAR const struct mrf24j40_lower_s *lower; @@ -162,6 +158,8 @@ struct mrf24j40_radio_s sem_t exclsem; /* Exclusive access to this struct */ + /* MAC Attributes */ + struct ieee802154_addr_s addr; uint8_t chan; /* 11 to 26 for the 2.4 GHz band */ @@ -183,6 +181,8 @@ struct mrf24j40_radio_s bool rxenabled : 1; + uint8_t bsn; + struct ieee802154_txdesc_s *gts_desc[MRF24J40_GTS_SLOTS]; bool gts_busy[MRF24J40_GTS_SLOTS]; }; @@ -226,6 +226,7 @@ static void mrf24j40_setup_fifo(FAR struct mrf24j40_radio_s *dev, FAR const uint8_t *buf, uint8_t length, uint32_t fifo_addr); static inline void mrf24j40_norm_trigger(FAR struct mrf24j40_radio_s *dev); +static inline void mrf24j40_beacon_trigger(FAR struct mrf24j40_radio_s *dev); static int mrf24j40_setchannel(FAR struct mrf24j40_radio_s *dev, uint8_t chan); @@ -492,6 +493,7 @@ static int mrf24j40_reset(FAR struct ieee802154_radio_s *radio) mrf24j40_seteaddr(dev, g_allones); dev->max_frame_waittime = MRF24J40_DEFAULT_MAX_FRAME_WAITTIME; + dev->bsn = 0; /* Default device params */ @@ -611,14 +613,7 @@ static int mrf24j40_setattr(FAR struct ieee802154_radio_s *radio, } break; - case IEEE802154_ATTR_MAC_RX_ON_WHEN_IDLE: - { - dev->rxonidle = attrval->mac.rxonidle; - mrf24j40_rxenable(radio, dev->rxonidle); - ret = IEEE802154_STATUS_SUCCESS; - } - break; - + case IEEE802154_ATTR_PHY_CHAN: { mrf24j40_setchannel(dev, attrval->phy.chan); @@ -658,6 +653,11 @@ static int mrf24j40_beaconstart(FAR struct ieee802154_radio_s *radio, mrf24j40_setup_fifo(dev, beacon->bf_data, beacon->bf_len, MRF24J40_BEACON_FIFO); + /* The radio layer is responsible for setting the BSN. */ + + dev->bsn = 0; + mrf24j40_setreg(dev->spi, MRF24J40_BEACON_FIFO + 4, dev->bsn++); + /* Set the TXBMSK (TXBCON1 0x25<7>) bit = 1 to mask the beacon interrupt * mask */ @@ -682,7 +682,6 @@ static int mrf24j40_beaconstart(FAR struct ieee802154_radio_s *radio, /* TODO: Add GTS related code. See pg 100 of datasheet */ - mrf24j40_setorder(dev, sfspec->beaconorder, sfspec->sforder); } else @@ -699,6 +698,7 @@ static int mrf24j40_beaconupdate(FAR struct ieee802154_radio_s *radio, FAR struct mrf24j40_radio_s *dev = (FAR struct mrf24j40_radio_s *)radio; mrf24j40_setup_fifo(dev, beacon->bf_data, beacon->bf_len, MRF24J40_BEACON_FIFO); + mrf24j40_beacon_trigger(dev); return OK; } @@ -1687,6 +1687,25 @@ static inline void mrf24j40_norm_trigger(FAR struct mrf24j40_radio_s *dev) mrf24j40_setreg(dev->spi, MRF24J40_TXNCON, reg); } +/**************************************************************************** + * Name: mrf24j40_beacon_trigger + * + * Description: + * Trigger the beacon TX FIFO + * + ****************************************************************************/ + +static inline void mrf24j40_beacon_trigger(FAR struct mrf24j40_radio_s *dev) +{ + uint8_t reg; + + reg = mrf24j40_getreg(dev->spi, MRF24J40_TXBCON0); + + reg |= MRF24J40_TXBCON0_TXBTRIG; + + mrf24j40_setreg(dev->spi, MRF24J40_TXBCON0, reg); +} + /**************************************************************************** * Name: mrf24j40_gts_setup * @@ -1991,9 +2010,6 @@ static void mrf24j40_irqwork_rx(FAR struct mrf24j40_radio_s *dev) ind->frame->io_len = mrf24j40_getreg(dev->spi, addr++); - /* TODO: This needs to be changed. It is inefficient to do the SPI read byte - * by byte */ - for (index = 0; index < ind->frame->io_len; index++) { ind->frame->io_data[index] = mrf24j40_getreg(dev->spi, addr++); @@ -2122,6 +2138,18 @@ static void mrf24j40_irqworker(FAR void *arg) reg |= MRF24J40_SLPACK_SLPACK; mrf24j40_setreg(dev->spi, MRF24J40_SLPACK, reg); } + + if ((intstat & MRF24J40_INTSTAT_WAKEIF)) + { + /* This is right before the beacon, we set the bsn here, since the MAC + * uses the SLPIF (end of active portion of superframe). to make any + * changes to the beacon. This assumes that any changes to the beacon + * be in by the time that this interrupt fires. + */ + + mrf24j40_setreg(dev->spi, MRF24J40_BEACON_FIFO + 4, dev->bsn++); + mrf24j40_beacon_trigger(dev); + } /* Unlock the radio device */ diff --git a/drivers/wireless/ieee802154/mrf24j40.h b/drivers/wireless/ieee802154/mrf24j40.h index e4e4e8ba5e..915669a144 100644 --- a/drivers/wireless/ieee802154/mrf24j40.h +++ b/drivers/wireless/ieee802154/mrf24j40.h @@ -226,6 +226,11 @@ #define MRF24J40_TXSTAT_X_SHIFT 6 #define MRF24J40_TXSTAT_X_MASK (3 << MRF24J40_TXSTAT_X_SHIFT) +/* TXBCON0 bits */ + +#define MRF24J40_TXBCON0_TXBTRIG 0x01 +#define MRF24J40_TXBCON0_TXBSECEN 0x02 + /* TXBCON1 bits */ #define MRF24J40_TXBCON1_RSSINUM 0x30 diff --git a/wireless/ieee802154/mac802154.c b/wireless/ieee802154/mac802154.c index 5c62aac4c4..db7a74c311 100644 --- a/wireless/ieee802154/mac802154.c +++ b/wireless/ieee802154/mac802154.c @@ -354,9 +354,9 @@ void mac802154_createdatareq(FAR struct ieee802154_privmac_s *priv, memcpy(&txdesc->destaddr, &coordaddr, sizeof(struct ieee802154_addr_s)); - /* Copy the IOB reference to the descriptor */ + /* Save a reference of the tx descriptor */ - txdesc->frame = iob; + priv->cmd_desc = txdesc; } /**************************************************************************** @@ -417,9 +417,11 @@ void mac802154_updatebeacon(FAR struct ieee802154_privmac_s *priv) IEEE802154_SETSADDRMODE(beacon->bf_data, 0, priv->addr.mode); IEEE802154_SETVERSION(beacon->bf_data, 0, 1); - /* Copy in and increment the beacon sequence number */ + /* The beacon sequence number has to be taken care of by the radio layer, since + * we only want to update the whole frame when more changes than just the bsn. + */ - beacon->bf_data[beacon->bf_len++] = priv->bsn++; + beacon->bf_len++; IEEE802154_PANIDCOPY(&beacon->bf_data[beacon->bf_len], priv->addr.panid); beacon->bf_len += IEEE802154_PANIDSIZE; @@ -580,8 +582,8 @@ void mac802154_setupindirect(FAR struct ieee802154_privmac_s *priv, if (work_available(&priv->purge_work)) { - //work_queue(MAC802154_WORK, &priv->purge_work, mac802154_purge_worker, - // (FAR void *)priv, ticks); + work_queue(MAC802154_WORK, &priv->purge_work, mac802154_purge_worker, + (FAR void *)priv, ticks); } } @@ -782,6 +784,8 @@ static void mac802154_txdone_worker(FAR void *arg) notif =(FAR struct ieee802154_notif_s *)txdesc->conf; + wlinfo("tx status: %s\n", IEEE802154_STATUS_STRING[txdesc->conf->status]); + switch(txdesc->frametype) { case IEEE802154_FRAME_DATA: @@ -1085,7 +1089,6 @@ static void mac802154_rxframe_worker(FAR void *arg) case IEEE802154_CMD_ORPHAN_NOT: wlinfo("Orphan notif received\n"); break; - break; case IEEE802154_CMD_BEACON_REQ: wlinfo("Beacon request received\n"); @@ -1163,7 +1166,9 @@ static void mac802154_rxdataframe(FAR struct ieee802154_privmac_s *priv, * FIXME: Fix documentation */ - if (priv->curr_op == MAC802154_OP_POLL || priv->curr_op == MAC802154_OP_ASSOC) + if (priv->curr_op == MAC802154_OP_POLL || + priv->curr_op == MAC802154_OP_ASSOC || + priv->curr_op == MAC802154_OP_AUTOEXTRACT) { /* If we are in promiscuous mode, we need to check if the * frame is even for us first. If the address is not ours, @@ -1217,7 +1222,8 @@ static void mac802154_rxdataframe(FAR struct ieee802154_privmac_s *priv, } /* If we've gotten this far, the frame is our extracted data. Cancel the - * timeout */ + * timeout + */ mac802154_timercancel(priv); @@ -1617,6 +1623,7 @@ static void mac802154_rxbeaconframe(FAR struct ieee802154_privmac_s *priv, } gtsdirmask = IEEE802154_GETGTSDIRMASK(iob->io_data, iob->io_offset); + UNUSED(gtsdirmask); iob->io_offset++; /* Make sure there are enough bytes left to represent the GTS List */ @@ -1723,7 +1730,8 @@ static void mac802154_rxbeaconframe(FAR struct ieee802154_privmac_s *priv, /* The beacon is the same as another, so discard it */ - goto done; + mac802154_notif_free_locked(priv, notif); + return; } /* TODO: There is supposed to be different logic for the scanning procedure @@ -1789,29 +1797,82 @@ static void mac802154_rxbeaconframe(FAR struct ieee802154_privmac_s *priv, priv->radio->txnotify(priv->radio, false); } - else if (!priv->autoreq) - { - /* If a valid beacon frame is received and macAutoRequest is set to FALSE, - * the MLME shall indicate the beacon parameters to the next higher layer - * by issuing the MLME-BEACON-NOTIFY.indication primitive. [1] pg. 38 - */ - - /* Unlock the MAC, notify, then lock again */ - - mac802154_givesem(&priv->exclsem); - mac802154_notify(priv, notif); - mac802154_takesem(&priv->exclsem, false); - return; /* Return so that we don't free the notificaiton */ - } else { - /* If a beacon frame is received and macAutoRequest is set to TRUE, the - * MLME shall first issue the MLME- BEACON-NOTIFY.indication primitive if - * the beacon contains any payload. - */ - - if (beacon->payloadlength > 0) + if (priv->autoreq || priv->curr_op == MAC802154_OP_POLL) { + /* If a beacon frame is received and macAutoRequest is set to + * TRUE, the MLME shall first issue the MLME- + * BEACON-NOTIFY.indication primitive if the beacon contains any + * payload. + */ + + if (beacon->payloadlength > 0) + { + /* Unlock the MAC, notify, then lock again */ + + mac802154_givesem(&priv->exclsem); + mac802154_notify(priv, notif); + mac802154_takesem(&priv->exclsem, false); + } + + /* If we have data pending for us, attempt to extract it. If for some + * reason we have data pending under our short address and our + * extended address, let the short address arbitrarily take precedence + */ + + if (pending_saddr | pending_eaddr) + { + mac802154_txdesc_alloc(priv, &respdesc, false); + + if (priv->curr_op == MAC802154_OP_POLL) + { + priv->curr_cmd = IEEE802154_CMD_DATA_REQ; + } + else if (priv->curr_op == MAC802154_OP_NONE) + { + DEBUGASSERT(priv->opsem.semcount == 1); + mac802154_takesem(&priv->opsem, false); + priv->curr_op = MAC802154_OP_AUTOEXTRACT; + priv->curr_cmd = IEEE802154_CMD_DATA_REQ; + } + + if (pending_saddr) + { + mac802154_createdatareq(priv, &priv->pandesc.coordaddr, + IEEE802154_ADDRMODE_SHORT, respdesc); + } + else + { + mac802154_createdatareq(priv, &priv->pandesc.coordaddr, + IEEE802154_ADDRMODE_EXTENDED, respdesc); + } + + /* Link the transaction into the CSMA transaction list */ + + sq_addlast((FAR sq_entry_t *)respdesc, &priv->csma_queue); + + /* Notify the radio driver that there is data available */ + + priv->radio->txnotify(priv->radio, false); + } + + /* If there was a beacon payload, we used the notification, so + * return here to make sure we don't free the notification. + */ + + if (beacon->payloadlength > 0) + { + return; + } + } + else + { + /* If a valid beacon frame is received and macAutoRequest is set to FALSE, + * the MLME shall indicate the beacon parameters to the next higher layer + * by issuing the MLME-BEACON-NOTIFY.indication primitive. [1] pg. 38 + */ + /* Unlock the MAC, notify, then lock again */ mac802154_givesem(&priv->exclsem); @@ -1819,39 +1880,9 @@ static void mac802154_rxbeaconframe(FAR struct ieee802154_privmac_s *priv, mac802154_takesem(&priv->exclsem, false); return; /* Return so that we don't free the notificaiton */ } - - /* If we have data pending for us, attempt to extract it. If for some - * reason we have data pending under our short address and our - * extended address, let the short address arbitrarily take precedence - */ - - if (pending_saddr | pending_eaddr) - { - mac802154_txdesc_alloc(priv, &respdesc, false); - - if (pending_saddr) - { - mac802154_createdatareq(priv, &priv->pandesc.coordaddr, - IEEE802154_ADDRMODE_SHORT, respdesc); - } - else - { - mac802154_createdatareq(priv, &priv->pandesc.coordaddr, - IEEE802154_ADDRMODE_EXTENDED, respdesc); - } - - /* Link the transaction into the CSMA transaction list */ - - sq_addlast((FAR sq_entry_t *)respdesc, &priv->csma_queue); - - /* Notify the radio driver that there is data available */ - - priv->radio->txnotify(priv->radio, false); - } } } -done: mac802154_notif_free_locked(priv, notif); return; @@ -1973,6 +2004,8 @@ static void mac802154_timeout_expiry(int argc, wdparm_t arg, ...) DEBUGASSERT(priv->timeout_worker != NULL); + wlinfo("timer expired\n"); + work_queue(MAC802154_WORK, &priv->timeout_work, (worker_t)priv->timeout_worker, priv, 0); } diff --git a/wireless/ieee802154/mac802154_assoc.c b/wireless/ieee802154/mac802154_assoc.c index dde6575bf6..d25c2dd2d3 100644 --- a/wireless/ieee802154/mac802154_assoc.c +++ b/wireless/ieee802154/mac802154_assoc.c @@ -86,7 +86,6 @@ int mac802154_req_associate(MACHANDLE mac, (FAR struct ieee802154_privmac_s *)mac; FAR struct ieee802154_txdesc_s *txdesc; FAR struct iob_s *iob; - bool rxonidle; int ret; int i; @@ -137,16 +136,7 @@ int mac802154_req_associate(MACHANDLE mac, priv->devmode = (req->capabilities.devtype) ? IEEE802154_DEVMODE_COORD : IEEE802154_DEVMODE_ENDPOINT; - /* Unlike other attributes, we can't simply cast this one since it is a bit - * in a bitfield. Casting it will give us unpredicatble results. Instead - * of creating a ieee802154_attr_u, we use a local bool. Allocating the - * ieee802154_attr_u value would take up more room on the stack since it is - * as large as the largest attribute type. - */ - - rxonidle = req->capabilities.rxonidle; - priv->radio->setattr(priv->radio, IEEE802154_ATTR_MAC_RX_ON_WHEN_IDLE, - (FAR const union ieee802154_attr_u *)&rxonidle); + mac802154_setrxonidle(priv, req->capabilities.rxonidle); /* Allocate an IOB to put the frame in */ @@ -485,6 +475,7 @@ void mac802154_txdone_assocreq(FAR struct ieee802154_privmac_s *priv, IEEE802154_SADDRCOPY(notif->u.assocconf.saddr, &IEEE802154_SADDR_UNSPEC); + /* We are now done the operation, unlock the semaphore */ priv->curr_op = MAC802154_OP_NONE; @@ -519,17 +510,33 @@ void mac802154_txdone_assocreq(FAR struct ieee802154_privmac_s *priv, * to respond. Setup a timeout for macResponseWaitTime so that we * can inform the next highest layer if the association attempt fails * due to NO_DATA. + * + * TODO: The standard defines macResponseWaitTime as: + * The maximum time, in multiples of aBaseSuperframeDuration, a device + * shall wait for a response command frame to be available following a + * request command frame. + * + * However, on beacon-enabled networks, it seems the maximum value + * isn't really that large of a value, AKA: assoc always fails from + * timeout even though everything is working as expected. The definition + * does say after we've sent a data request, which we, haven't sent + * yet, but we do need a timeout for association in general. Not sure + * what the correct answer is. For now, I am going to change the + * way macResponseWaitTime is used with beacon-enabled networks and + * make the timeout (BI * macResponseWaitTime) where BI is Beacon + * Interval = aBaseSuperframeDuration * 2^macBeaconOrder */ + wlinfo("starting timeout timer\n"); mac802154_timerstart(priv, (priv->resp_waittime * - IEEE802154_BASE_SUPERFRAME_DURATION), - mac802154_assoctimeout); + (IEEE802154_BASE_SUPERFRAME_DURATION * (1 << priv->sfspec.beaconorder))), + mac802154_assoctimeout); } else { - /* Make sure the coordinator address mode is not set to none. This shouldn't - * happen since the association request should have set the mode to short or - * extended + /* Make sure the coordinator address mode is not set to none. This + * shouldn't happen since the association request should have set + * the mode to short or extended */ DEBUGASSERT(priv->pandesc.coordaddr.mode != IEEE802154_ADDRMODE_NONE); @@ -634,17 +641,33 @@ void mac802154_txdone_datareq_assoc(FAR struct ieee802154_privmac_s *priv, mac802154_rxenable(priv); - /* Start a timer, if we receive the data frame, we will cancel - * the timer, otherwise it will expire and we will notify the - * next highest layer of the failure. + /* If we are on a beacon-enabled network, we already have the association + * timeout timer scheduled. So we only need to start the timeout timer + * if we are operating on a non-beacon enabled network. + * + * NOTE: This may create a bad side-effect where the receiver is on + * for longer than it needs to be during association. Revisit if power + * is ever an issue. */ - mac802154_timerstart(priv, priv->max_frame_waittime, - mac802154_assoctimeout); + if (priv->sfspec.beaconorder == 15) + { + + /* Start a timer, if we receive the data frame, we will cancel + * the timer, otherwise it will expire and we will notify the + * next highest layer of the failure. + */ + + wlinfo("starting timeout timer\n"); + mac802154_timerstart(priv, priv->max_frame_waittime, + mac802154_assoctimeout); + + } /* Deallocate the data conf notification as it is no longer needed. */ mac802154_notif_free_locked(priv, notif); + } } @@ -740,6 +763,19 @@ void mac802154_rx_assocresp(FAR struct ieee802154_privmac_s *priv, if (priv->curr_op != MAC802154_OP_ASSOC) { + /* This situation can occur in a beacon-enabled network if the association + * request has timed out, but the Coordinator has already queued the + * response. Which means the beacon would contain our address, causing us + * to extract the response. + * + * TODO: What is supposed to happen in this situation. Are we supposed to + * accept the request? Are we supposed to Disassociate with the network + * as a convienience to the PAN Coordinator. So that it does not need + * to waste space holding our information? + */ + + wlinfo("ignoring association response frame\n"); + return; } @@ -793,15 +829,16 @@ void mac802154_rx_assocresp(FAR struct ieee802154_privmac_s *priv, IEEE802154_SADDRCOPY(notif->u.assocconf.saddr, priv->addr.saddr); - /* Unlock the MAC */ - - mac802154_givesem(&priv->exclsem); - /* We are no longer performing the association operation */ priv->curr_op = MAC802154_OP_NONE; priv->cmd_desc = NULL; mac802154_givesem(&priv->opsem); + mac802154_rxdisable(priv); + + /* Unlock the MAC */ + + mac802154_givesem(&priv->exclsem); /* Notify the next highest layer of the association status */ @@ -842,9 +879,11 @@ static void mac802154_assoctimeout(FAR struct ieee802154_privmac_s *priv) mac802154_notif_alloc(priv, ¬if, false); /* We are no longer performing the association operation */ + priv->curr_op = MAC802154_OP_NONE; priv->cmd_desc = NULL; mac802154_givesem(&priv->opsem); + mac802154_rxdisable(priv); /* Release the MAC */ diff --git a/wireless/ieee802154/mac802154_getset.c b/wireless/ieee802154/mac802154_getset.c index 1a43125cb6..d6a9ddf889 100644 --- a/wireless/ieee802154/mac802154_getset.c +++ b/wireless/ieee802154/mac802154_getset.c @@ -84,29 +84,55 @@ int mac802154_req_get(MACHANDLE mac, enum ieee802154_attr_e attr, switch (attr) { case IEEE802154_ATTR_MAC_PANID: - IEEE802154_PANIDCOPY(attrval->mac.panid, priv->addr.panid); + { + IEEE802154_PANIDCOPY(attrval->mac.panid, priv->addr.panid); + } break; - case IEEE802154_ATTR_MAC_SADDR: - IEEE802154_SADDRCOPY(attrval->mac.saddr, priv->addr.saddr); - break; - case IEEE802154_ATTR_MAC_EADDR: - IEEE802154_EADDRCOPY(attrval->mac.eaddr, priv->addr.eaddr); - break; - case IEEE802154_ATTR_MAC_COORD_SADDR: - IEEE802154_SADDRCOPY(attrval->mac.coordsaddr, priv->pandesc.coordaddr.saddr); - break; - case IEEE802154_ATTR_MAC_COORD_EADDR: - IEEE802154_EADDRCOPY(attrval->mac.coordeaddr, priv->pandesc.coordaddr.eaddr); - break; - case IEEE802154_ATTR_MAC_DEVMODE: - attrval->mac.devmode = priv->devmode; - break; - default: - /* The attribute may be handled soley in the radio driver, so pass - * it along. - */ - ret = priv->radio->getattr(priv->radio, attr, attrval); + case IEEE802154_ATTR_MAC_SADDR: + { + IEEE802154_SADDRCOPY(attrval->mac.saddr, priv->addr.saddr); + } + break; + + case IEEE802154_ATTR_MAC_EADDR: + { + IEEE802154_EADDRCOPY(attrval->mac.eaddr, priv->addr.eaddr); + } + break; + + case IEEE802154_ATTR_MAC_COORD_SADDR: + { + IEEE802154_SADDRCOPY(attrval->mac.coordsaddr, priv->pandesc.coordaddr.saddr); + } + break; + + case IEEE802154_ATTR_MAC_COORD_EADDR: + { + IEEE802154_EADDRCOPY(attrval->mac.coordeaddr, priv->pandesc.coordaddr.eaddr); + } + break; + + case IEEE802154_ATTR_MAC_DEVMODE: + { + attrval->mac.devmode = priv->devmode; + } + break; + + case IEEE802154_ATTR_MAC_RESPONSE_WAIT_TIME: + { + attrval->mac.resp_waittime = priv->resp_waittime; + } + break;; + + default: + { + /* The attribute may be handled soley in the radio driver, so pass + * it along. + */ + + ret = priv->radio->getattr(priv->radio, attr, attrval); + } break; } @@ -133,47 +159,49 @@ int mac802154_req_set(MACHANDLE mac, enum ieee802154_attr_e attr, { FAR struct ieee802154_privmac_s *priv = (FAR struct ieee802154_privmac_s *)mac; - int ret; + int ret = IEEE802154_STATUS_SUCCESS; switch (attr) { case IEEE802154_ATTR_MAC_PANID: { mac802154_setpanid(priv, attrval->mac.panid); - ret = IEEE802154_STATUS_SUCCESS; } break; case IEEE802154_ATTR_MAC_SADDR: { mac802154_setsaddr(priv, attrval->mac.saddr); - ret = IEEE802154_STATUS_SUCCESS; } break; case IEEE802154_ATTR_MAC_EADDR: { mac802154_seteaddr(priv, attrval->mac.eaddr); - ret = IEEE802154_STATUS_SUCCESS; } break; case IEEE802154_ATTR_MAC_COORD_SADDR: { mac802154_setcoordsaddr(priv, attrval->mac.coordsaddr); - ret = IEEE802154_STATUS_SUCCESS; } break; case IEEE802154_ATTR_MAC_COORD_EADDR: { mac802154_setcoordeaddr(priv, attrval->mac.coordeaddr); - ret = IEEE802154_STATUS_SUCCESS; } break; case IEEE802154_ATTR_MAC_ASSOCIATION_PERMIT: { priv->sfspec.assocpermit = attrval->mac.assocpermit; priv->beaconupdate = true; - ret = IEEE802154_STATUS_SUCCESS; } break; + case IEEE802154_ATTR_MAC_RESPONSE_WAIT_TIME: + { + priv->resp_waittime = attrval->mac.resp_waittime; + } + case IEEE802154_ATTR_MAC_RX_ON_WHEN_IDLE: + { + mac802154_setrxonidle(priv, attrval->mac.rxonidle); + } default: { /* The attribute may be handled soley in the radio driver, so pass diff --git a/wireless/ieee802154/mac802154_internal.h b/wireless/ieee802154/mac802154_internal.h index be3cb8ebcd..e6b067894c 100644 --- a/wireless/ieee802154/mac802154_internal.h +++ b/wireless/ieee802154/mac802154_internal.h @@ -135,7 +135,8 @@ enum mac802154_operation_e MAC802154_OP_NONE, MAC802154_OP_ASSOC, MAC802154_OP_POLL, - MAC802154_OP_SCAN + MAC802154_OP_SCAN, + MAC802154_OP_AUTOEXTRACT, }; struct ieee802154_privmac_s; /* Forward Reference */ @@ -232,8 +233,6 @@ struct ieee802154_privmac_s /*************** Fields related to beacon-enabled networks ******************/ - uint8_t bsn; /* Seq. num added to tx beacon frame */ - /* Holds attributes pertaining to the superframe specification */ struct ieee802154_superframespec_s sfspec; @@ -357,6 +356,14 @@ struct ieee802154_privmac_s uint8_t maxretries : 3; /* Max # of retries allowed after tx fail */ /* End of 8-bit bitfield. */ + /* Start of 8-bit bitfield */ + + uint8_t rxonidle : 1; /* Receiver on when idle? */ + + /* End of 8-bit bitfield. */ + + + /* TODO: Add Security-related MAC PIB attributes */ }; @@ -608,6 +615,7 @@ static inline int mac802154_timercancel(FAR struct ieee802154_privmac_s *priv) { wd_cancel(priv->timeout); priv->timeout_worker = NULL; + wlinfo("timer cancelled\n"); return OK; } @@ -702,4 +710,28 @@ static inline void mac802154_setcoordaddr(FAR struct ieee802154_privmac_s *priv, (FAR const union ieee802154_attr_u *)addr->saddr); } +static inline void mac802154_setrxonidle(FAR struct ieee802154_privmac_s *priv, + bool rxonidle) +{ + priv->rxonidle = true; + if (priv->rxonidle) + { + mac802154_rxenable(priv); + } + else + { + mac802154_rxdisable(priv); + } + + /* Unlike other attributes, we can't simply cast this one since it is a bit + * in a bitfield. Casting it will give us unpredicatble results. Instead + * of creating a ieee802154_attr_u, we use a local bool. Allocating the + * ieee802154_attr_u value would take up more room on the stack since it is + * as large as the largest attribute type. + */ + + priv->radio->setattr(priv->radio, IEEE802154_ATTR_MAC_RX_ON_WHEN_IDLE, + (FAR const union ieee802154_attr_u *)&rxonidle); +} + #endif /* __WIRELESS_IEEE802154__MAC802154_INTERNAL_H */ diff --git a/wireless/ieee802154/mac802154_reset.c b/wireless/ieee802154/mac802154_reset.c index 870a4bbe1b..79ae258b7d 100644 --- a/wireless/ieee802154/mac802154_reset.c +++ b/wireless/ieee802154/mac802154_reset.c @@ -95,8 +95,6 @@ int mac802154_req_reset(MACHANDLE mac, bool rst_pibattr) priv->sfspec.beaconorder = 15; /* Non-beacon enabled network */ priv->sfspec.sforder = 15; /* Length of active portion of outgoing SF */ priv->beacon_txtime = 0; /* Device never sent a beacon */ -#warning Set BSN and DSN to random values! - priv->bsn = 0; priv->dsn = 0; priv->gtspermit = true; /* PAN Coord accepting GTS requests */ priv->minbe = 3; /* Min value of backoff exponent (BE) */ From 29e028f7ac9d145b55474f2f9a239ec617467b5c Mon Sep 17 00:00:00 2001 From: Anthony Merlino Date: Sat, 1 Jul 2017 17:02:40 -0400 Subject: [PATCH 08/54] ieee802154: Minor renaming to align better with coding guidelines --- include/nuttx/wireless/ieee802154/ieee802154_mac.h | 2 +- wireless/ieee802154/mac802154.h | 4 ++-- wireless/ieee802154/mac802154_ioctl.c | 2 +- wireless/ieee802154/mac802154_reset.c | 6 +++--- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/include/nuttx/wireless/ieee802154/ieee802154_mac.h b/include/nuttx/wireless/ieee802154/ieee802154_mac.h index 11b1d96d81..105f98fae3 100644 --- a/include/nuttx/wireless/ieee802154/ieee802154_mac.h +++ b/include/nuttx/wireless/ieee802154/ieee802154_mac.h @@ -1247,7 +1247,7 @@ struct ieee802154_orphan_resp_s struct ieee802154_reset_req_s { - bool rst_pibattr; + bool resetattr; }; /***************************************************************************** diff --git a/wireless/ieee802154/mac802154.h b/wireless/ieee802154/mac802154.h index 01762b2c5f..d1f3a6b63f 100644 --- a/wireless/ieee802154/mac802154.h +++ b/wireless/ieee802154/mac802154.h @@ -223,11 +223,11 @@ int mac802154_req_gts(MACHANDLE mac, FAR struct ieee802154_gts_req_s *req); * * Input Parameters: * mac - Handle to the MAC layer instance - * rst_pibattr - Whether or not to reset the MAC PIB attributes to defaults + * reset_attr - Whether or not to reset the MAC PIB attributes to defaults * ****************************************************************************/ -int mac802154_req_reset(MACHANDLE mac, bool rst_pibattr); +int mac802154_req_reset(MACHANDLE mac, bool restattr); /**************************************************************************** * Name: mac802154_req_rxenable diff --git a/wireless/ieee802154/mac802154_ioctl.c b/wireless/ieee802154/mac802154_ioctl.c index 35093f6936..20ab2557fd 100644 --- a/wireless/ieee802154/mac802154_ioctl.c +++ b/wireless/ieee802154/mac802154_ioctl.c @@ -124,7 +124,7 @@ int mac802154_ioctl(MACHANDLE mac, int cmd, unsigned long arg) break; case MAC802154IOC_MLME_RESET_REQUEST: { - ret = mac802154_req_reset(mac, macarg->resetreq.rst_pibattr); + ret = mac802154_req_reset(mac, macarg->resetreq.resetattr); } break; case MAC802154IOC_MLME_RXENABLE_REQUEST: diff --git a/wireless/ieee802154/mac802154_reset.c b/wireless/ieee802154/mac802154_reset.c index 79ae258b7d..598275d9e0 100644 --- a/wireless/ieee802154/mac802154_reset.c +++ b/wireless/ieee802154/mac802154_reset.c @@ -74,17 +74,17 @@ * * Input Parameters: * mac - Handle to the MAC layer instance - * rst_pibattr - Whether or not to reset the MAC PIB attributes to defaults + * resetattr - Whether or not to reset the MAC PIB attributes to defaults * ****************************************************************************/ -int mac802154_req_reset(MACHANDLE mac, bool rst_pibattr) +int mac802154_req_reset(MACHANDLE mac, bool resetattr) { FAR struct ieee802154_privmac_s * priv = (FAR struct ieee802154_privmac_s *) mac; union ieee802154_attr_u attr; - if (rst_pibattr) + if (resetattr) { priv->isassoc = false; /* Not associated with a PAN */ priv->trackingbeacon = false; /* Not tracking beacon by default */ From 7d9c4ace3415c4849a453183c80d312f9dbc8676 Mon Sep 17 00:00:00 2001 From: Anthony Merlino Date: Sat, 1 Jul 2017 17:04:02 -0400 Subject: [PATCH 09/54] ieee802154: Cleans up some wireless logging --- drivers/wireless/ieee802154/mrf24j40.c | 11 ++++------- wireless/ieee802154/mac802154.c | 6 +++--- wireless/ieee802154/mac802154_assoc.c | 6 +++--- wireless/ieee802154/mac802154_internal.h | 6 +++--- 4 files changed, 13 insertions(+), 16 deletions(-) diff --git a/drivers/wireless/ieee802154/mrf24j40.c b/drivers/wireless/ieee802154/mrf24j40.c index 92c1ade53c..906109c9b8 100644 --- a/drivers/wireless/ieee802154/mrf24j40.c +++ b/drivers/wireless/ieee802154/mrf24j40.c @@ -806,12 +806,12 @@ static void mrf24j40_dopoll_csma(FAR void *arg) if (!dev->csma_busy) { - wlinfo("polling for frame\n"); + wlinfo("Polling for frame\n"); len = dev->radiocb->poll(dev->radiocb, false, &dev->csma_desc); if (len > 0) { - wlinfo("frame received. frame length: %d\n", len); + wlinfo("Frame received. Frame length: %d\n", len); /* Now the txdesc is in use */ @@ -822,10 +822,6 @@ static void mrf24j40_dopoll_csma(FAR void *arg) mrf24j40_norm_setup(dev, dev->csma_desc->frame, true); mrf24j40_norm_trigger(dev); } - else - { - wlinfo("no frames\n"); - } } sem_post(&dev->exclsem); @@ -1427,7 +1423,7 @@ static int mrf24j40_settxpower(FAR struct mrf24j40_radio_s *dev, return -EINVAL; } - wlinfo("remaining attenuation: %d mBm\n",txpwr); + wlinfo("Remaining attenuation: %d mBm\n",txpwr); switch(txpwr/100) { @@ -2141,6 +2137,7 @@ static void mrf24j40_irqworker(FAR void *arg) if ((intstat & MRF24J40_INTSTAT_WAKEIF)) { + wlinfo("Wake Interrupt\n"); /* This is right before the beacon, we set the bsn here, since the MAC * uses the SLPIF (end of active portion of superframe). to make any * changes to the beacon. This assumes that any changes to the beacon diff --git a/wireless/ieee802154/mac802154.c b/wireless/ieee802154/mac802154.c index db7a74c311..4fdebe1776 100644 --- a/wireless/ieee802154/mac802154.c +++ b/wireless/ieee802154/mac802154.c @@ -784,7 +784,7 @@ static void mac802154_txdone_worker(FAR void *arg) notif =(FAR struct ieee802154_notif_s *)txdesc->conf; - wlinfo("tx status: %s\n", IEEE802154_STATUS_STRING[txdesc->conf->status]); + wlinfo("Tx status: %s\n", IEEE802154_STATUS_STRING[txdesc->conf->status]); switch(txdesc->frametype) { @@ -915,7 +915,7 @@ static void mac802154_rxframe(FAR const struct ieee802154_radiocb_s *radiocb, sq_addlast((FAR sq_entry_t *)ind, &priv->dataind_queue); - wlinfo("frame received\n"); + wlinfo("Frame received\n"); mac802154_givesem(&priv->exclsem); @@ -2004,7 +2004,7 @@ static void mac802154_timeout_expiry(int argc, wdparm_t arg, ...) DEBUGASSERT(priv->timeout_worker != NULL); - wlinfo("timer expired\n"); + wlinfo("Timer expired\n"); work_queue(MAC802154_WORK, &priv->timeout_work, (worker_t)priv->timeout_worker, priv, 0); diff --git a/wireless/ieee802154/mac802154_assoc.c b/wireless/ieee802154/mac802154_assoc.c index d25c2dd2d3..5d22c1d88d 100644 --- a/wireless/ieee802154/mac802154_assoc.c +++ b/wireless/ieee802154/mac802154_assoc.c @@ -527,7 +527,7 @@ void mac802154_txdone_assocreq(FAR struct ieee802154_privmac_s *priv, * Interval = aBaseSuperframeDuration * 2^macBeaconOrder */ - wlinfo("starting timeout timer\n"); + wlinfo("Starting timeout timer\n"); mac802154_timerstart(priv, (priv->resp_waittime * (IEEE802154_BASE_SUPERFRAME_DURATION * (1 << priv->sfspec.beaconorder))), mac802154_assoctimeout); @@ -658,7 +658,7 @@ void mac802154_txdone_datareq_assoc(FAR struct ieee802154_privmac_s *priv, * next highest layer of the failure. */ - wlinfo("starting timeout timer\n"); + wlinfo("Starting timeout timer\n"); mac802154_timerstart(priv, priv->max_frame_waittime, mac802154_assoctimeout); @@ -774,7 +774,7 @@ void mac802154_rx_assocresp(FAR struct ieee802154_privmac_s *priv, * to waste space holding our information? */ - wlinfo("ignoring association response frame\n"); + wlinfo("Ignoring association response frame\n"); return; } diff --git a/wireless/ieee802154/mac802154_internal.h b/wireless/ieee802154/mac802154_internal.h index e6b067894c..d3f86be9dd 100644 --- a/wireless/ieee802154/mac802154_internal.h +++ b/wireless/ieee802154/mac802154_internal.h @@ -615,7 +615,7 @@ static inline int mac802154_timercancel(FAR struct ieee802154_privmac_s *priv) { wd_cancel(priv->timeout); priv->timeout_worker = NULL; - wlinfo("timer cancelled\n"); + wlinfo("Timer cancelled\n"); return OK; } @@ -627,7 +627,7 @@ static inline void mac802154_rxenable(FAR struct ieee802154_privmac_s *priv) if (priv->nrxusers == 1) { - wlinfo("receiver enabled\n"); + wlinfo("Receiver enabled\n"); priv->radio->rxenable(priv->radio, true); } } @@ -640,7 +640,7 @@ static inline void mac802154_rxdisable(FAR struct ieee802154_privmac_s *priv) if (priv->nrxusers == 0) { - wlinfo("receiver disabled\n"); + wlinfo("Receiver disabled\n"); priv->radio->rxenable(priv->radio, true); priv->radio->rxenable(priv->radio, false); } From 06b99588c05cf3223fec4a99354397a50fc48ce2 Mon Sep 17 00:00:00 2001 From: Anthony Merlino Date: Sat, 1 Jul 2017 17:04:44 -0400 Subject: [PATCH 10/54] ieee802154: Fixes resp_waittime field in ieee802154_macattr_u --- include/nuttx/wireless/ieee802154/ieee802154_mac.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/nuttx/wireless/ieee802154/ieee802154_mac.h b/include/nuttx/wireless/ieee802154/ieee802154_mac.h index 105f98fae3..1526ad3f0f 100644 --- a/include/nuttx/wireless/ieee802154/ieee802154_mac.h +++ b/include/nuttx/wireless/ieee802154/ieee802154_mac.h @@ -628,7 +628,6 @@ union ieee802154_macattr_u bool gts_permit; bool promisc_mode; bool rng_support; - bool resp_waittime; bool rxonidle; bool sec_enabled; bool timestamp_support; @@ -647,6 +646,7 @@ union ieee802154_macattr_u uint32_t tx_ctrl_active_dur; uint32_t tx_ctrl_pause_dur; uint32_t tx_total_dur; + uint8_t resp_waittime; uint8_t beacon_payload[IEEE802154_ATTR_MAC_BEACON_PAYLOAD_LEN]; uint8_t beacon_payload_len; From 032deb5f492e8996764fbb91e17b47d78f545502 Mon Sep 17 00:00:00 2001 From: Anthony Merlino Date: Sat, 1 Jul 2017 17:05:09 -0400 Subject: [PATCH 11/54] ieee802154: Supports multiple incoming superframe events --- wireless/ieee802154/mac802154.c | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/wireless/ieee802154/mac802154.c b/wireless/ieee802154/mac802154.c index 4fdebe1776..ff3ffb65be 100644 --- a/wireless/ieee802154/mac802154.c +++ b/wireless/ieee802154/mac802154.c @@ -1515,15 +1515,27 @@ static void mac802154_sfevent(FAR const struct ieee802154_radiocb_s *radiocb, mac802154_takesem(&priv->exclsem, false); - /* Check if there is any reason to update the beacon */ - - if (priv->beaconupdate) + switch (sfevent) { - mac802154_updatebeacon(priv); + case IEEE802154_SFEVENT_ENDOFACTIVE: + { + wlinfo("End of superframe\n"); - priv->radio->beaconupdate(priv->radio, &priv->beaconframe[priv->bf_ind]); + /* Check if there is any reason to update the beacon */ + + if (priv->beaconupdate) + { + mac802154_updatebeacon(priv); + + priv->radio->beaconupdate(priv->radio, &priv->beaconframe[priv->bf_ind]); + } + } + break; + default: + break; } + mac802154_givesem(&priv->exclsem); } From 8c00c9ceef16532d66286831d085ca02c60cf6ba Mon Sep 17 00:00:00 2001 From: Gregory Nutt Date: Sun, 2 Jul 2017 11:33:44 -0600 Subject: [PATCH 12/54] Refresh all mrf24j40 configurations --- configs/clicker2-stm32/mrf24j40-mac/defconfig | 4 ++-- configs/clicker2-stm32/mrf24j40-starhub/defconfig | 13 ++++++++----- configs/clicker2-stm32/mrf24j40-starpoint/defconfig | 12 ++++++++---- 3 files changed, 18 insertions(+), 11 deletions(-) diff --git a/configs/clicker2-stm32/mrf24j40-mac/defconfig b/configs/clicker2-stm32/mrf24j40-mac/defconfig index 7ee79a1d4a..0feb83fa31 100644 --- a/configs/clicker2-stm32/mrf24j40-mac/defconfig +++ b/configs/clicker2-stm32/mrf24j40-mac/defconfig @@ -1168,10 +1168,10 @@ CONFIG_BUILTIN_PROXY_STACKSIZE=1024 CONFIG_EXAMPLES_NSH=y CONFIG_EXAMPLES_NSH_CXXINITIALIZE=y # CONFIG_EXAMPLES_NULL is not set +# CONFIG_EXAMPLES_NX is not set # CONFIG_EXAMPLES_NXFFS is not set # CONFIG_EXAMPLES_NXHELLO is not set # CONFIG_EXAMPLES_NXIMAGE is not set -# CONFIG_EXAMPLES_NX is not set # CONFIG_EXAMPLES_NXLINES is not set # CONFIG_EXAMPLES_NXTERM is not set # CONFIG_EXAMPLES_NXTEXT is not set @@ -1191,7 +1191,6 @@ CONFIG_EXAMPLES_NSH_CXXINITIALIZE=y # CONFIG_EXAMPLES_SMP is not set # CONFIG_EXAMPLES_STAT is not set # CONFIG_EXAMPLES_TCPECHO is not set -# CONFIG_EXAMPLES_TELNETD is not set # CONFIG_EXAMPLES_TIFF is not set # CONFIG_EXAMPLES_TOUCHSCREEN is not set # CONFIG_EXAMPLES_USBSERIAL is not set @@ -1304,6 +1303,7 @@ CONFIG_NSH_DISABLE_PUT=y # CONFIG_NSH_DISABLE_SLEEP is not set # CONFIG_NSH_DISABLE_TIME is not set # CONFIG_NSH_DISABLE_TEST is not set +# CONFIG_NSH_DISABLE_TELNETD is not set # CONFIG_NSH_DISABLE_UMOUNT is not set # CONFIG_NSH_DISABLE_UNAME is not set # CONFIG_NSH_DISABLE_UNSET is not set diff --git a/configs/clicker2-stm32/mrf24j40-starhub/defconfig b/configs/clicker2-stm32/mrf24j40-starhub/defconfig index 45000c97af..b76ba0bfae 100644 --- a/configs/clicker2-stm32/mrf24j40-starhub/defconfig +++ b/configs/clicker2-stm32/mrf24j40-starhub/defconfig @@ -992,11 +992,7 @@ CONFIG_NET_6LOWPAN_MAXAGE=20 CONFIG_NET_6LOWPAN_MAX_MACTRANSMITS=4 CONFIG_NET_6LOWPAN_MTU=1294 CONFIG_NET_6LOWPAN_TCP_RECVWNDO=1220 -CONFIG_NET_HAVE_STAR=y CONFIG_NET_IPFORWARD=y -CONFIG_NET_STAR=y -# CONFIG_NET_STARPOINT is not set -CONFIG_NET_STARHUB=y # # Socket Support @@ -1062,6 +1058,14 @@ CONFIG_NET_UDP_READAHEAD=y # CONFIG_NET_ARCH_INCR32 is not set # CONFIG_NET_ARCH_CHKSUM is not set CONFIG_NET_STATISTICS=y +CONFIG_NET_HAVE_STAR=y + +# +# Network Topologies +# +CONFIG_NET_STAR=y +# CONFIG_NET_STARPOINT is not set +CONFIG_NET_STARHUB=y # # Routing Table Configuration @@ -1365,7 +1369,6 @@ CONFIG_EXAMPLES_NSH_CXXINITIALIZE=y # CONFIG_EXAMPLES_SMP is not set # CONFIG_EXAMPLES_STAT is not set # CONFIG_EXAMPLES_TCPECHO is not set -# CONFIG_EXAMPLES_TELNETD is not set # CONFIG_EXAMPLES_TIFF is not set # CONFIG_EXAMPLES_TOUCHSCREEN is not set # CONFIG_EXAMPLES_UDP is not set diff --git a/configs/clicker2-stm32/mrf24j40-starpoint/defconfig b/configs/clicker2-stm32/mrf24j40-starpoint/defconfig index 99c76b0ead..9034a54f49 100644 --- a/configs/clicker2-stm32/mrf24j40-starpoint/defconfig +++ b/configs/clicker2-stm32/mrf24j40-starpoint/defconfig @@ -992,11 +992,7 @@ CONFIG_NET_6LOWPAN_MAXAGE=20 CONFIG_NET_6LOWPAN_MAX_MACTRANSMITS=4 CONFIG_NET_6LOWPAN_MTU=1294 CONFIG_NET_6LOWPAN_TCP_RECVWNDO=1220 -CONFIG_NET_HAVE_STAR=y # CONFIG_NET_IPFORWARD is not set -CONFIG_NET_STAR=y -CONFIG_NET_STARPOINT=y -# CONFIG_NET_STARHUB is not set # # Socket Support @@ -1062,6 +1058,14 @@ CONFIG_NET_UDP_READAHEAD=y # CONFIG_NET_ARCH_INCR32 is not set # CONFIG_NET_ARCH_CHKSUM is not set CONFIG_NET_STATISTICS=y +CONFIG_NET_HAVE_STAR=y + +# +# Network Topologies +# +CONFIG_NET_STAR=y +CONFIG_NET_STARPOINT=y +# CONFIG_NET_STARHUB is not set # # Routing Table Configuration From d05cf268da7d8514a2ccacfce7ce9752fa8b1172 Mon Sep 17 00:00:00 2001 From: Anthony Merlino Date: Mon, 3 Jul 2017 00:33:17 -0400 Subject: [PATCH 13/54] drivers/wireless/ieee802154: Moved radios to individual sub-directories --- drivers/wireless/ieee802154/Kconfig | 4 + drivers/wireless/ieee802154/Make.defs | 13 +- drivers/wireless/ieee802154/at86rf23x/Kconfig | 8 + .../wireless/ieee802154/at86rf23x/Make.defs | 48 + .../ieee802154/{ => at86rf23x}/at86rf23x.c | 167 +- .../ieee802154/{ => at86rf23x}/at86rf23x.h | 8 +- drivers/wireless/ieee802154/mrf24j40/Kconfig | 8 + .../wireless/ieee802154/mrf24j40/Make.defs | 48 + .../ieee802154/{ => mrf24j40}/mrf24j40.c | 4759 +++++++++-------- .../ieee802154/{ => mrf24j40}/mrf24j40.h | 357 +- 10 files changed, 3118 insertions(+), 2302 deletions(-) create mode 100644 drivers/wireless/ieee802154/at86rf23x/Kconfig create mode 100644 drivers/wireless/ieee802154/at86rf23x/Make.defs rename drivers/wireless/ieee802154/{ => at86rf23x}/at86rf23x.c (98%) rename drivers/wireless/ieee802154/{ => at86rf23x}/at86rf23x.h (97%) create mode 100644 drivers/wireless/ieee802154/mrf24j40/Kconfig create mode 100644 drivers/wireless/ieee802154/mrf24j40/Make.defs rename drivers/wireless/ieee802154/{ => mrf24j40}/mrf24j40.c (96%) rename drivers/wireless/ieee802154/{ => mrf24j40}/mrf24j40.h (94%) diff --git a/drivers/wireless/ieee802154/Kconfig b/drivers/wireless/ieee802154/Kconfig index d0d8c550ec..4a799e4999 100644 --- a/drivers/wireless/ieee802154/Kconfig +++ b/drivers/wireless/ieee802154/Kconfig @@ -11,10 +11,14 @@ config IEEE802154_MRF24J40 ---help--- This selection enables support for the Microchip MRF24J40 device. +source drivers/wireless/ieee802154/mrf24j40/Kconfig + config IEEE802154_AT86RF233 bool "ATMEL RF233 IEEE 802.15.4 transceiver" default n ---help--- This selection enables support for the Atmel RF233 device. +source drivers/wireless/ieee802154/at86rf23x/Kconfig + endif # DRIVERS_IEEE802154 diff --git a/drivers/wireless/ieee802154/Make.defs b/drivers/wireless/ieee802154/Make.defs index 8e0924d67f..2aa926dbe0 100644 --- a/drivers/wireless/ieee802154/Make.defs +++ b/drivers/wireless/ieee802154/Make.defs @@ -1,7 +1,7 @@ ############################################################################ # drivers/ieee802154/Make.defs # -# Copyright (C) 2016 Gregory Nutt. All rights reserved. +# Copyright (C) 2016-2017 Gregory Nutt. All rights reserved. # Author: Gregory Nutt # # Redistribution and use in source and binary forms, with or without @@ -41,15 +41,10 @@ ifeq ($(CONFIG_DRIVERS_IEEE802154),y) # Include IEEE 802.15.4 drivers into the build -ifeq ($(CONFIG_IEEE802154_MRF24J40),y) - CSRCS += mrf24j40.c -endif +include wireless$(DELIM)ieee802154$(DELIM)mrf24j40$(DELIM)Make.defs +include wireless$(DELIM)ieee802154$(DELIM)at86rf23x$(DELIM)Make.defs -ifeq ($(CONFIG_IEEE802154_AT86RF233),y) - CSRCS += at86rf23x.c -endif - -# Include IEEE 802.15.4 build support +# Include common IEEE 802.15.4 build support DEPPATH += --dep-path wireless$(DELIM)ieee802154 VPATH += :wireless$(DELIM)ieee802154 diff --git a/drivers/wireless/ieee802154/at86rf23x/Kconfig b/drivers/wireless/ieee802154/at86rf23x/Kconfig new file mode 100644 index 0000000000..43ac4b882d --- /dev/null +++ b/drivers/wireless/ieee802154/at86rf23x/Kconfig @@ -0,0 +1,8 @@ +# +# For a description of the syntax of this configuration file, +# see the file kconfig-language.txt in the NuttX tools repository. +# + +if IEEE802154_AT86RF233 + +endif # IEEE802154_AT86RF233 diff --git a/drivers/wireless/ieee802154/at86rf23x/Make.defs b/drivers/wireless/ieee802154/at86rf23x/Make.defs new file mode 100644 index 0000000000..876032ddbc --- /dev/null +++ b/drivers/wireless/ieee802154/at86rf23x/Make.defs @@ -0,0 +1,48 @@ +############################################################################ +# drivers/ieee802154/at86rf23x/Make.defs +# +# Copyright (C) 2016-2017 Gregory Nutt. All rights reserved. +# Author: Gregory Nutt +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# 3. Neither the name NuttX nor the names of its contributors may be +# used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS +# OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED +# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# +############################################################################ + +# Include AT86RF23x drivers into the build + +ifeq ($(CONFIG_IEEE802154_AT86RF233),y) + +CSRCS += at86rf23x.c + +# Include AT86RF23x build support + +DEPPATH += --dep-path wireless$(DELIM)ieee802154$(DELIM)at86rf23x +VPATH += :wireless$(DELIM)ieee802154$(DELIM)at86rf23x +CFLAGS += ${shell $(INCDIR) $(INCDIROPT) "$(CC)" $(TOPDIR)$(DELIM)drivers$(DELIM)wireless$(DELIM)ieee802154$(DELIM)at86rf23x} + +endif # CONFIG_IEEE802154_AT86RF233 \ No newline at end of file diff --git a/drivers/wireless/ieee802154/at86rf23x.c b/drivers/wireless/ieee802154/at86rf23x/at86rf23x.c similarity index 98% rename from drivers/wireless/ieee802154/at86rf23x.c rename to drivers/wireless/ieee802154/at86rf23x/at86rf23x.c index 3e4cd0ce11..1d71f3239c 100644 --- a/drivers/wireless/ieee802154/at86rf23x.c +++ b/drivers/wireless/ieee802154/at86rf23x/at86rf23x.c @@ -1,5 +1,5 @@ /**************************************************************************** - * drivers/wireless/ieee802154/at86rf23x.c + * drivers/wireless/ieee802154/at86rf23x/at86rf23x.c * * Copyright (C) 2016 Matt Poppe. All rights reserved. * Author: Matt Poppe @@ -993,115 +993,226 @@ static int at86rf23x_gettxpower(FAR struct ieee802154_radio_s *ieee, /* Right now we only get negative values */ + + + reg = at86rf23x_getreg(dev->spi, RF23X_REG_TXPWR); switch (reg) + { - case RF23X_TXPWR_POS_4: + + + case RF23X_TXPWR_POS_4: + *txpwr = 0; break; - case RF23X_TXPWR_POS_3_7: - *txpwr = 0; + + + + case RF23X_TXPWR_POS_3_7: + *txpwr = +0; break; - case RF23X_TXPWR_POS_3_4: + + + + case RF23X_TXPWR_POS_3_4: *txpwr = 0; + + break; - case RF23X_TXPWR_POS_3: - *txpwr = 0; + + + case RF23X_TXPWR_POS_3: + *txpwr = + 0; + break; - case RF23X_TXPWR_POS_2_5: + + case RF23X_ +TXPWR_POS_2_5: *txpwr = 0; + + break; + case RF23X_TXPWR_POS_2: + + *txpwr = 0; + + + break; + + + + case RF23X_TXPWR_POS_1: + *txpwr = 0; break; - case RF23X_TXPWR_POS_1: - *txpwr = 0; + + + + case RF23X_TXPWR_0: + *txpwr = +0; break; - case RF23X_TXPWR_0: - *txpwr = 0; - break; + + case RF23X_TXPWR_NEG_1: *txpwr = 1000; + break; - case RF23X_TXPWR_NEG_2: + + + case RF23X_TXPWR_NE +G_2: *txpwr = 2000; + + break; + case RF23X_TXPWR_NEG_3: - *txpwr = 3000; + + +*txpwr = 3000; + break; + case RF23X_TXPWR_NEG_4: - *txpwr = 4000; - break; + + +*txpwr = 4000; + +break; + + case RF23X_TXPWR_NEG_6: *txpwr = 6000; + + break; + + case RF23X_TXPWR_NEG_8: *txpwr = 8000; + break; - case RF23X_TXPWR_NEG_12: + + + ca +se RF23X_TXPWR_NEG_12: + *txpwr = 12000; break; + + case RF23X_TXPWR_NEG_17: - *txpwr = 17000; - break; + + *txpwr = 17 +000; + +break; } + + return OK; + } -/**************************************************************************** + + +/**** +************************************************************************ + * Name: at86rf23x_setcca * + * Description: + * Configures if energy detection is used or carrier sense. The base + + * measurement is configured here as well * - * - ****************************************************************************/ -static int at86rf23x_setcca(FAR struct ieee802154_radio_s *ieee, + * + + ************************************************************************* +***/ + + +static + int at86rf23x_setcca(FAR struct ieee802154_radio_s *ieee, + FAR struct ieee802154_cca_s *cca) + { FAR struct at86rf23x_dev_s *dev = (struct at86rf23x_dev_s *)ieee; + + + /* TODO: This doesn't fit the RF233 completely come back to this */ + + if (!cca->use_ed && !cca->use_cs) { + return -EINVAL; + } + + + if (cca->use_cs && cca->csth > 0x0f) { + return -EINVAL; + } + + if (cca->use_ed) - { + + + { + at86rf23x_setregbits(dev->spi, RF23X_CCA_BITS_MODE, RF23X_CCA_MODE_ED); } - if (cca->use_cs) + + + +if (cca->use_cs) { - at86rf23x_setregbits(dev->spi, RF23X_CCA_BITS_MODE, RF23X_CCA_MODE_CS); + + at86rf23x_setregbits(dev->spi, RF23X_CCA_BITS_MODE, RF23X_CCA +_MODE_CS); } - memcpy(&dev->cca, cca, sizeof(struct ieee802154_cca_s)); + + + memcpy(&dev->cca, cca, sizeof(struct ieee802154 +_cca_s)); return OK; } diff --git a/drivers/wireless/ieee802154/at86rf23x.h b/drivers/wireless/ieee802154/at86rf23x/at86rf23x.h similarity index 97% rename from drivers/wireless/ieee802154/at86rf23x.h rename to drivers/wireless/ieee802154/at86rf23x/at86rf23x.h index 4d64fed0c8..3d9700aec6 100644 --- a/drivers/wireless/ieee802154/at86rf23x.h +++ b/drivers/wireless/ieee802154/at86rf23x/at86rf23x.h @@ -1,5 +1,5 @@ /**************************************************************************** - * drivers/wireless/ieee802154/at86rf23x.c + * drivers/wireless/ieee802154/at86rf23x/at86rf23x.h * * Copyright (C) 2016 Matt Poppe. All rights reserved. * Author: Matt Poppe @@ -33,8 +33,8 @@ * ****************************************************************************/ -#ifndef __DRIVERS_WIRELESS_IEEE802154_AT86RF23X_H -#define __DRIVERS_WIRELESS_IEEE802154_AT86RF23X_H +#ifndef __DRIVERS_WIRELESS_IEEE802154_AT86RF23X_AT86RF23X_H +#define __DRIVERS_WIRELESS_IEEE802154_AT86RF23X_AT86RF23X_H /**************************************************************************** * Pre-processor Definitions @@ -218,4 +218,4 @@ #define RF23X_IRQ_MASK_DEFAULT (RF23X_IRQ_MASK_TRX_END) -#endif /* __DRIVERS_WIRELESS_IEEE802154_AT86RF23X_H */ +#endif /* __DRIVERS_WIRELESS_IEEE802154_AT86RF23X_AT86RF23X_H */ diff --git a/drivers/wireless/ieee802154/mrf24j40/Kconfig b/drivers/wireless/ieee802154/mrf24j40/Kconfig new file mode 100644 index 0000000000..851b804a14 --- /dev/null +++ b/drivers/wireless/ieee802154/mrf24j40/Kconfig @@ -0,0 +1,8 @@ +# +# For a description of the syntax of this configuration file, +# see the file kconfig-language.txt in the NuttX tools repository. +# + +if IEEE802154_MRF24J40 + +endif # IEEE802154_MRF24J40 diff --git a/drivers/wireless/ieee802154/mrf24j40/Make.defs b/drivers/wireless/ieee802154/mrf24j40/Make.defs new file mode 100644 index 0000000000..f6871f6ce5 --- /dev/null +++ b/drivers/wireless/ieee802154/mrf24j40/Make.defs @@ -0,0 +1,48 @@ +############################################################################ +# drivers/ieee802154/mrf24j40/Make.defs +# +# Copyright (C) 2016-2017 Gregory Nutt. All rights reserved. +# Author: Gregory Nutt +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# 3. Neither the name NuttX nor the names of its contributors may be +# used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS +# OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED +# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# +############################################################################ + +ifeq ($(CONFIG_IEEE802154_MRF24J40),y) + +# Include MRF24J40 files into the build + +CSRCS += mrf24j40.c + +# Include MRF24J40 build support + +DEPPATH += --dep-path wireless$(DELIM)ieee802154$(DELIM)mrf24j40 +VPATH += :wireless$(DELIM)ieee802154$(DELIM)mrf24j40 +CFLAGS += ${shell $(INCDIR) $(INCDIROPT) "$(CC)" $(TOPDIR)$(DELIM)drivers$(DELIM)wireless$(DELIM)ieee802154$(DELIM)mrf24j40} + +endif # CONFIG_IEEE802154_MRF24J40 \ No newline at end of file diff --git a/drivers/wireless/ieee802154/mrf24j40.c b/drivers/wireless/ieee802154/mrf24j40/mrf24j40.c similarity index 96% rename from drivers/wireless/ieee802154/mrf24j40.c rename to drivers/wireless/ieee802154/mrf24j40/mrf24j40.c index 906109c9b8..94b03990e1 100644 --- a/drivers/wireless/ieee802154/mrf24j40.c +++ b/drivers/wireless/ieee802154/mrf24j40/mrf24j40.c @@ -1,2257 +1,2502 @@ -/**************************************************************************** - * drivers/wireless/ieee802154/mrf24j40.c - * - * Copyright (C) 2015-2016 Sebastien Lorquet. All rights reserved. - * Copyright (C) 2017 Verge Inc. All rights reserved. - * Author: Sebastien Lorquet - * Author: Anthony Merlino - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * 3. Neither the name NuttX nor the names of its contributors may be - * used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS - * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED - * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - ****************************************************************************/ - -/**************************************************************************** - * Included Files - ****************************************************************************/ - -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -#include - -#include -#include -#include - -#include "mrf24j40.h" - -/**************************************************************************** - * Pre-processor Definitions - ****************************************************************************/ - -#ifndef CONFIG_SCHED_HPWORK -# error High priority work queue required in this driver -#endif - -#ifndef CONFIG_IEEE802154_MRF24J40_SPIMODE -# define CONFIG_IEEE802154_MRF24J40_SPIMODE SPIDEV_MODE0 -#endif - -#ifndef CONFIG_IEEE802154_MRF24J40_FREQUENCY -# define CONFIG_IEEE802154_MRF24J40_FREQUENCY 8000000 -#endif - -#ifndef CONFIG_SPI_EXCHANGE -# error CONFIG_SPI_EXCHANGE required for this driver -#endif - -/* Definitions for the device structure */ - -#define MRF24J40_RXMODE_NORMAL 0 -#define MRF24J40_RXMODE_PROMISC 1 -#define MRF24J40_RXMODE_NOCRC 2 - -#define MRF24J40_MODE_DEVICE 0 -#define MRF24J40_MODE_COORD 1 -#define MRF24J40_MODE_PANCOORD 2 - -/* Definitions for PA control on high power modules */ - -#define MRF24J40_PA_AUTO 1 -#define MRF24J40_PA_ED 2 -#define MRF24J40_PA_SLEEP 3 - -#define MRF24J40_GTS_SLOTS 2 - -/* Clock configuration macros */ - -#define MRF24J40_SLPCLKPER_100KHZ ((1000 * 1000 * 1000)/100000) /* 10ns */ -#define MRF24J40_SLPCLKPER_32KHZ ((1000 * 1000 * 1000)/32000) /* 31.25ns */ - -#define MRF24J40_BEACONINTERVAL_NSEC(beaconorder) \ - (IEEE802154_BASE_SUPERFRAME_DURATION * (1 << beaconorder) * (16 *1000)) - -/* For now I am just setting the REMCNT to the maximum while staying in multiples - * of 10000 (100khz period) */ - -#define MRF24J40_REMCNT 60000 -#define MRF24J40_REMCNT_NSEC (MRF24J40_REMCNT * 50) - -#define MRF24J40_MAINCNT(bo, clkper) \ - ((MRF24J40_BEACONINTERVAL_NSEC(bo) - MRF24J40_REMCNT_NSEC) / \ - clkper) - -/* Formula for calculating default macMaxFrameWaitTime is on pg. 130 - * - * For PHYs other than CSS and UWB, the attribute phyMaxFrameDuration is given by: - * - * phyMaxFrameDuration = phySHRDuration + - * ceiling([aMaxPHYPacketSize + 1] x phySymbolsPerOctet) - * - * where ceiling() is a function that returns the smallest integer value greater - * than or equal to its argument value. [1] pg. 158 -*/ - -#define MRF24J40_DEFAULT_MAX_FRAME_WAITTIME 1824 - -#define MRF24J40_SYMBOL_DURATION_PS 16000000 - -/**************************************************************************** - * Private Types - ****************************************************************************/ - -/* A MRF24J40 device instance */ - -struct mrf24j40_radio_s -{ - struct ieee802154_radio_s radio; /* The public device instance */ - FAR struct ieee802154_radiocb_s *radiocb; /* Registered callbacks */ - - /* Low-level MCU-specific support */ - - FAR const struct mrf24j40_lower_s *lower; - FAR struct spi_dev_s *spi; /* Saved SPI interface instance */ - - struct work_s irqwork; /* For deferring interrupt work to work queue */ - struct work_s csma_pollwork; /* For deferring poll work to the work queue */ - struct work_s gts_pollwork; /* For deferring poll work to the work queue */ - - sem_t exclsem; /* Exclusive access to this struct */ - - /* MAC Attributes */ - - struct ieee802154_addr_s addr; - - uint8_t chan; /* 11 to 26 for the 2.4 GHz band */ - uint8_t devmode; /* device mode: device, coord, pancoord */ - uint8_t paenabled; /* enable usage of PA */ - uint8_t rxmode; /* Reception mode: Main, no CRC, promiscuous */ - int32_t txpower; /* TX power in mBm = dBm/100 */ - struct ieee802154_cca_s cca; /* Clear channel assessement method */ - - /* MAC PIB attributes */ - - uint32_t max_frame_waittime; - - struct ieee802154_txdesc_s *txdelayed_desc; - struct ieee802154_txdesc_s *csma_desc; - bool txdelayed_busy : 1; - bool csma_busy : 1; - bool reschedule_csma : 1; - - bool rxenabled : 1; - - uint8_t bsn; - - struct ieee802154_txdesc_s *gts_desc[MRF24J40_GTS_SLOTS]; - bool gts_busy[MRF24J40_GTS_SLOTS]; -}; - -/**************************************************************************** - * Private Function Prototypes - ****************************************************************************/ - -/* Internal operations */ - -static void mrf24j40_spi_lock(FAR struct spi_dev_s *spi); - -static void mrf24j40_setreg(FAR struct spi_dev_s *spi, uint32_t addr, - uint8_t val); -static uint8_t mrf24j40_getreg(FAR struct spi_dev_s *spi, uint32_t addr); - -static int mrf24j40_resetrfsm(FAR struct mrf24j40_radio_s *dev); -static void mrf24j40_setorder(FAR struct mrf24j40_radio_s *dev, uint8_t bo, - uint8_t so); -static int mrf24j40_pacontrol(FAR struct mrf24j40_radio_s *dev, int mode); - -static int mrf24j40_setrxmode(FAR struct mrf24j40_radio_s *dev, int mode); -static int mrf24j40_regdump(FAR struct mrf24j40_radio_s *dev); - -static void mrf24j40_irqwork_rx(FAR struct mrf24j40_radio_s *dev); -static void mrf24j40_irqwork_txnorm(FAR struct mrf24j40_radio_s *dev); -static void mrf24j40_irqwork_txgts(FAR struct mrf24j40_radio_s *dev, - uint8_t gts_num); - -static void mrf24j40_irqworker(FAR void *arg); -static int mrf24j40_interrupt(int irq, FAR void *context, FAR void *arg); - -static void mrf24j40_dopoll_csma(FAR void *arg); -static void mrf24j40_dopoll_gts(FAR void *arg); - -static void mrf24j40_norm_setup(FAR struct mrf24j40_radio_s *dev, - FAR struct iob_s *frame, bool csma); -static void mrf24j40_gts_setup(FAR struct mrf24j40_radio_s *dev, uint8_t gts, - FAR struct iob_s *frame); -static void mrf24j40_setup_fifo(FAR struct mrf24j40_radio_s *dev, - FAR const uint8_t *buf, uint8_t length, uint32_t fifo_addr); - -static inline void mrf24j40_norm_trigger(FAR struct mrf24j40_radio_s *dev); -static inline void mrf24j40_beacon_trigger(FAR struct mrf24j40_radio_s *dev); - -static int mrf24j40_setchannel(FAR struct mrf24j40_radio_s *dev, - uint8_t chan); -static int mrf24j40_setpanid(FAR struct mrf24j40_radio_s *dev, - FAR const uint8_t *panid); -static int mrf24j40_setsaddr(FAR struct mrf24j40_radio_s *dev, - FAR const uint8_t *saddr); -static int mrf24j40_seteaddr(FAR struct mrf24j40_radio_s *dev, - FAR const uint8_t *eaddr); -static int mrf24j40_setcoordsaddr(FAR struct mrf24j40_radio_s *dev, - FAR const uint8_t *saddr); -static int mrf24j40_setcoordeaddr(FAR struct mrf24j40_radio_s *dev, - FAR const uint8_t *eaddr); -static int mrf24j40_setdevmode(FAR struct mrf24j40_radio_s *dev, - uint8_t mode); -static int mrf24j40_settxpower(FAR struct mrf24j40_radio_s *dev, - int32_t txpwr); -static int mrf24j40_setcca(FAR struct mrf24j40_radio_s *dev, - FAR struct ieee802154_cca_s *cca); -static int mrf24j40_energydetect(FAR struct mrf24j40_radio_s *dev, - FAR uint8_t *energy); -static void mrf24j40_mactimer(FAR struct mrf24j40_radio_s *dev, int numsymbols); - -/* Driver operations */ - -static int mrf24j40_bind(FAR struct ieee802154_radio_s *radio, - FAR struct ieee802154_radiocb_s *radiocb); -static int mrf24j40_reset(FAR struct ieee802154_radio_s *radio); -static int mrf24j40_getattr(FAR struct ieee802154_radio_s *radio, - enum ieee802154_attr_e attr, - FAR union ieee802154_attr_u *attrval); -static int mrf24j40_setattr(FAR struct ieee802154_radio_s *radio, - enum ieee802154_attr_e attr, - FAR const union ieee802154_attr_u *attrval); -static int mrf24j40_txnotify(FAR struct ieee802154_radio_s *radio, bool gts); -static int mrf24j40_txdelayed(FAR struct ieee802154_radio_s *radio, - FAR struct ieee802154_txdesc_s *txdesc, - uint32_t symboldelay); -static int mrf24j40_rxenable(FAR struct ieee802154_radio_s *dev, bool enable); -static int mrf24j40_beaconstart(FAR struct ieee802154_radio_s *radio, - FAR const struct ieee802154_superframespec_s *sfspec, - FAR struct ieee802154_beaconframe_s *beacon); -static int mrf24j40_beaconupdate(FAR struct ieee802154_radio_s *radio, - FAR struct ieee802154_beaconframe_s *beacon); -static int mrf24j40_beaconstop(FAR struct ieee802154_radio_s *radio); -static int mrf24j40_sfupdate(FAR struct ieee802154_radio_s *radio, - FAR const struct ieee802154_superframespec_s *sfspec); - -/**************************************************************************** - * Private Data - ****************************************************************************/ - -static const uint8_t g_allones[8] = -{ - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF -}; - -/**************************************************************************** - * Radio Interface Functions - ****************************************************************************/ - -static int mrf24j40_bind(FAR struct ieee802154_radio_s *radio, - FAR struct ieee802154_radiocb_s *radiocb) -{ - FAR struct mrf24j40_radio_s *dev = (FAR struct mrf24j40_radio_s *)radio; - - DEBUGASSERT(dev != NULL); - dev->radiocb = radiocb; - return OK; -} - -/**************************************************************************** - * Function: mrf24j40_txnotify - * - * Description: - * Driver callback invoked when new TX data is available. This is a - * stimulus perform an out-of-cycle poll and, thereby, reduce the TX - * latency. - * - * Parameters: - * radio - Reference to the radio driver state structure - * - * Returned Value: - * None - * - * Assumptions: - * - ****************************************************************************/ - -static int mrf24j40_txnotify(FAR struct ieee802154_radio_s *radio, bool gts) -{ - FAR struct mrf24j40_radio_s *dev = (FAR struct mrf24j40_radio_s *)radio; - - if (gts) - { - /* Is our single work structure available? It may not be if there are - * pending interrupt actions and we will have to ignore the Tx - * availability action. - */ - - if (work_available(&dev->gts_pollwork)) - { - /* Schedule to serialize the poll on the worker thread. */ - - work_queue(HPWORK, &dev->gts_pollwork, mrf24j40_dopoll_gts, dev, 0); - } - } - else - { - /* Is our single work structure available? It may not be if there are - * pending interrupt actions and we will have to ignore the Tx - * availability action. - */ - - if (work_available(&dev->csma_pollwork)) - { - /* Schedule to serialize the poll on the worker thread. */ - - work_queue(HPWORK, &dev->csma_pollwork, mrf24j40_dopoll_csma, dev, 0); - } - } - - return OK; -} - -/**************************************************************************** - * Function: mrf24j40_txdelayed - * - * Description: - * Transmit a packet without regard to supeframe structure after a certain - * number of symbols. This function is used to send Data Request responses. - * It can also be used to send data immediately if the delay is set to 0. - * - * Parameters: - * radio - Reference to the radio driver state structure - * - * Returned Value: - * None - * - * Assumptions: - * - ****************************************************************************/ - -static int mrf24j40_txdelayed(FAR struct ieee802154_radio_s *radio, - FAR struct ieee802154_txdesc_s *txdesc, - uint32_t symboldelay) -{ - FAR struct mrf24j40_radio_s *dev = (FAR struct mrf24j40_radio_s *)radio; - uint8_t reg; - - /* Get exclusive access to the radio device */ - - if (sem_wait(&dev->exclsem) != 0) - { - return -EINTR; - } - - /* There should never be more than one of these transactions at once. */ - - DEBUGASSERT(!dev->txdelayed_busy); - - dev->txdelayed_desc = txdesc; - dev->txdelayed_busy = true; - - /* Disable the TX norm interrupt and clear it */ - - reg = mrf24j40_getreg(dev->spi, MRF24J40_INTCON); - reg |= MRF24J40_INTCON_TXNIE; - mrf24j40_setreg(dev->spi, MRF24J40_INTCON, reg); - - /* If after disabling the interrupt, the irqworker is not scheduled, there - * are no interrupts to worry about. However, if there is work scheduled, - * we need to process it before going any further. - */ - - if (!work_available(&dev->irqwork)) - { - work_cancel(HPWORK, &dev->irqwork); - sem_post(&dev->exclsem); - mrf24j40_irqworker((FAR void *)dev); - - /* Get exclusive access to the radio device */ - - if (sem_wait(&dev->exclsem) != 0) - { - return -EINTR; - } - } - - if (dev->csma_busy) - { - dev->reschedule_csma = true; - } - - mrf24j40_norm_setup(dev, txdesc->frame, false); - - if (symboldelay == 0) - { - mrf24j40_norm_trigger(dev); - } - else - { - mrf24j40_mactimer(dev, symboldelay); - } - - sem_post(&dev->exclsem); - - return OK; -} - -static int mrf24j40_reset(FAR struct ieee802154_radio_s *radio) -{ - FAR struct mrf24j40_radio_s *dev = (FAR struct mrf24j40_radio_s *)radio; - struct ieee802154_cca_s cca; - int reg; - - /* Software reset */ - - mrf24j40_setreg(dev->spi, MRF24J40_SOFTRST , 0x07); /* 00000111 Reset */ - while(mrf24j40_getreg(dev->spi, MRF24J40_SOFTRST) & 0x07); - - /* Apply recommended settings */ - - mrf24j40_setreg(dev->spi, MRF24J40_PACON2 , 0x98); /* 10011000 Enable FIFO (default), TXONTS=6 (recommended), TXONT<8:7>=0 */ - mrf24j40_setreg(dev->spi, MRF24J40_TXSTBL , 0x95); /* 10010101 set the SIFS period. RFSTBL=9, MSIFS=5, aMinSIFSPeriod=14 (min 12) */ - mrf24j40_setreg(dev->spi, MRF24J40_TXPEND , 0x7C); /* 01111100 set the LIFS period, MLIFS=1Fh=31 aMinLIFSPeriod=40 (min 40) */ - mrf24j40_setreg(dev->spi, MRF24J40_TXTIME , 0x30); /* 00110000 set the turnaround time, TURNTIME=3 aTurnAroundTime=12 */ - mrf24j40_setreg(dev->spi, MRF24J40_RFCON1 , 0x02); /* 00000010 VCO optimization, recommended value */ - mrf24j40_setreg(dev->spi, MRF24J40_RFCON2 , 0x80); /* 10000000 Enable PLL */ - mrf24j40_setreg(dev->spi, MRF24J40_RFCON6 , 0x90); /* 10010000 TX filter enable, fast 20M recovery, No bat monitor*/ - mrf24j40_setreg(dev->spi, MRF24J40_RFCON7 , 0x80); /* 10000000 Sleep clock on internal 100 kHz */ - mrf24j40_setreg(dev->spi, MRF24J40_RFCON8 , 0x10); /* 00010000 VCO control bit, as recommended */ - mrf24j40_setreg(dev->spi, MRF24J40_SLPCON1, 0x01); /* 00000001 no CLKOUT, default divisor */ - mrf24j40_setreg(dev->spi, MRF24J40_BBREG6 , 0x40); /* 01000000 Append RSSI to rx packets */ - - /* Set this in reset since it can exist for all device modes. See pg 101 */ - - mrf24j40_setreg(dev->spi, MRF24J40_FRMOFFSET, 0x15); - - /* For now, we want to always just have the frame pending bit set when - * acknowledging a Data Request command. The standard says that the coordinator - * can do this if it needs time to figure out whether it has data or not - */ - - mrf24j40_setreg(dev->spi, MRF24J40_ACKTMOUT, 0x39 | MRF24J40_ACKTMOUT_DRPACK); - - /* Set WAKECNT (SLPACK 0x35<6:0>) value = 0x5F to set the main oscillator - * (20 MHz) start-up timer value. - */ - - mrf24j40_setreg(dev->spi, MRF24J40_SLPACK, 0x5F); - - /* Enable the SLPIF and WAKEIF flags */ - - reg = mrf24j40_getreg(dev->spi, MRF24J40_INTCON); - reg &= ~(MRF24J40_INTCON_SLPIE | MRF24J40_INTCON_WAKEIE); - mrf24j40_setreg(dev->spi, MRF24J40_INTCON, reg); - - dev->rxenabled = false; - - mrf24j40_setchannel(dev, 11); - mrf24j40_setpanid(dev, g_allones); - mrf24j40_setsaddr(dev, g_allones); - mrf24j40_seteaddr(dev, g_allones); - - dev->max_frame_waittime = MRF24J40_DEFAULT_MAX_FRAME_WAITTIME; - dev->bsn = 0; - - /* Default device params */ - - cca.use_ed = 1; - cca.use_cs = 0; - cca.edth = 0x60; /* CCA mode ED, no carrier sense, recommenced ED threshold -69 dBm */ - mrf24j40_setcca(dev, &cca); - - mrf24j40_setrxmode(dev, MRF24J40_RXMODE_NORMAL); - - mrf24j40_settxpower(dev, 0); /*16. Set transmitter power .*/ - - mrf24j40_pacontrol(dev, MRF24J40_PA_AUTO); - - return OK; -} - -static int mrf24j40_getattr(FAR struct ieee802154_radio_s *radio, - enum ieee802154_attr_e attr, - FAR union ieee802154_attr_u *attrval) -{ - FAR struct mrf24j40_radio_s *dev = (FAR struct mrf24j40_radio_s *)radio; - int ret; - - switch (attr) - { - case IEEE802154_ATTR_MAC_EADDR: - { - memcpy(&attrval->mac.eaddr[0], &dev->addr.eaddr[0], 8); - ret = IEEE802154_STATUS_SUCCESS; - } - break; - - case IEEE802154_ATTR_MAC_MAX_FRAME_WAITTIME: - { - attrval->mac.max_frame_waittime = dev->max_frame_waittime; - ret = IEEE802154_STATUS_SUCCESS; - } - break; - - case IEEE802154_ATTR_PHY_SYMBOL_DURATION: - { - attrval->phy.symdur_picosec = MRF24J40_SYMBOL_DURATION_PS; - ret = IEEE802154_STATUS_SUCCESS; - } - break; - - case IEEE802154_ATTR_PHY_CHAN: - { - attrval->phy.chan = dev->chan; - ret = IEEE802154_STATUS_SUCCESS; - } - - default: - ret = IEEE802154_STATUS_UNSUPPORTED_ATTRIBUTE; - } - - return ret; -} - -static int mrf24j40_setattr(FAR struct ieee802154_radio_s *radio, - enum ieee802154_attr_e attr, - FAR const union ieee802154_attr_u *attrval) -{ - FAR struct mrf24j40_radio_s *dev = (FAR struct mrf24j40_radio_s *)radio; - int ret; - - switch (attr) - { - case IEEE802154_ATTR_MAC_PANID: - { - mrf24j40_setpanid(dev, attrval->mac.panid); - ret = IEEE802154_STATUS_SUCCESS; - } - break; - - case IEEE802154_ATTR_MAC_SADDR: - { - mrf24j40_setsaddr(dev, attrval->mac.saddr); - ret = IEEE802154_STATUS_SUCCESS; - } - break; - - case IEEE802154_ATTR_MAC_EADDR: - { - mrf24j40_seteaddr(dev, attrval->mac.eaddr); - ret = IEEE802154_STATUS_SUCCESS; - } - break; - - case IEEE802154_ATTR_MAC_COORD_SADDR: - { - mrf24j40_setcoordsaddr(dev, attrval->mac.coordsaddr); - ret = IEEE802154_STATUS_SUCCESS; - } - break; - - case IEEE802154_ATTR_MAC_COORD_EADDR: - { - mrf24j40_setcoordeaddr(dev, attrval->mac.coordeaddr); - ret = IEEE802154_STATUS_SUCCESS; - } - break; - - case IEEE802154_ATTR_MAC_PROMISCUOUS_MODE: - { - if (attrval->mac.promisc_mode) - { - mrf24j40_setrxmode(dev, MRF24J40_RXMODE_PROMISC); - } - else - { - mrf24j40_setrxmode(dev, MRF24J40_RXMODE_NORMAL); - } - - ret = IEEE802154_STATUS_SUCCESS; - } - break; - - - case IEEE802154_ATTR_PHY_CHAN: - { - mrf24j40_setchannel(dev, attrval->phy.chan); - ret = IEEE802154_STATUS_SUCCESS; - } - break; - - default: - ret = IEEE802154_STATUS_UNSUPPORTED_ATTRIBUTE; - break; - } - return ret; -} - -static int mrf24j40_beaconstart(FAR struct ieee802154_radio_s *radio, - FAR const struct ieee802154_superframespec_s *sfspec, - FAR struct ieee802154_beaconframe_s *beacon) -{ - FAR struct mrf24j40_radio_s *dev = (FAR struct mrf24j40_radio_s *)radio; - int reg; - - if (sfspec->pancoord) - { - /* Set the PANCOORD (RXMCR 0x00<3>) bit = 1to configure as PAN coordinator */ - - reg = mrf24j40_getreg(dev->spi, MRF24J40_RXMCR); - reg |= MRF24J40_RXMCR_PANCOORD; - mrf24j40_setreg(dev->spi, MRF24J40_RXMCR, reg); - - /* Set the SLOTTED (TXMCR 0x11<5>) bit = 1 to use Slotted CSMA-CA mode */ - - reg = mrf24j40_getreg(dev->spi, MRF24J40_TXMCR); - reg |= MRF24J40_TXMCR_SLOTTED; - mrf24j40_setreg(dev->spi, MRF24J40_TXMCR, reg); - - /* Load the beacon frame into the TXBFIFO (0x080-0x0FF). */ - - mrf24j40_setup_fifo(dev, beacon->bf_data, beacon->bf_len, MRF24J40_BEACON_FIFO); - - /* The radio layer is responsible for setting the BSN. */ - - dev->bsn = 0; - mrf24j40_setreg(dev->spi, MRF24J40_BEACON_FIFO + 4, dev->bsn++); - - /* Set the TXBMSK (TXBCON1 0x25<7>) bit = 1 to mask the beacon interrupt - * mask - */ - - reg = mrf24j40_getreg(dev->spi, MRF24J40_TXBCON1); - reg |= MRF24J40_TXBCON1_TXBMSK; - mrf24j40_setreg(dev->spi, MRF24J40_TXBCON1, reg); - - /* Set INTL (WAKECON 0x22<5:0>) value to 0x03. */ - - reg = mrf24j40_getreg(dev->spi, MRF24J40_WAKECON); - reg &= ~MRF24J40_WAKECON_INTL; - reg |= 0x03 & MRF24J40_WAKECON_INTL; - mrf24j40_setreg(dev->spi, MRF24J40_WAKECON, reg); - - /* Program the CAP end slot (ESLOTG1 0x13<3:0>) value. */ - - reg = mrf24j40_getreg(dev->spi, MRF24J40_ESLOTG1); - reg &= ~MRF24J40_ESLOTG1_CAP; - reg |= sfspec->final_capslot & MRF24J40_ESLOTG1_CAP; - mrf24j40_setreg(dev->spi, MRF24J40_ESLOTG1, reg); - - /* TODO: Add GTS related code. See pg 100 of datasheet */ - - mrf24j40_setorder(dev, sfspec->beaconorder, sfspec->sforder); - } - else - { - return -ENOTTY; - } - - return OK; -} - -static int mrf24j40_beaconupdate(FAR struct ieee802154_radio_s *radio, - FAR struct ieee802154_beaconframe_s *beacon) -{ - FAR struct mrf24j40_radio_s *dev = (FAR struct mrf24j40_radio_s *)radio; - - mrf24j40_setup_fifo(dev, beacon->bf_data, beacon->bf_len, MRF24J40_BEACON_FIFO); - mrf24j40_beacon_trigger(dev); - - return OK; -} - -static int mrf24j40_beaconstop(FAR struct ieee802154_radio_s *radio) -{ - return -ENOTTY; -} - -static int mrf24j40_sfupdate(FAR struct ieee802154_radio_s *radio, - FAR const struct ieee802154_superframespec_s *sfspec) -{ - FAR struct mrf24j40_radio_s *dev = (FAR struct mrf24j40_radio_s *)radio; - int reg; - - /* If we are operating on a beacon-enabled network, use slotted CSMA */ - - reg = mrf24j40_getreg(dev->spi, MRF24J40_TXMCR); - if (sfspec->beaconorder < 15) - { - reg |= MRF24J40_TXMCR_SLOTTED; - } - else - { - reg &= ~MRF24J40_TXMCR_SLOTTED; - } - mrf24j40_setreg(dev->spi, MRF24J40_TXMCR, reg); - - mrf24j40_setorder(dev, sfspec->beaconorder, sfspec->sforder); - - /* Program the CAP end slot (ESLOTG1 0x13<3:0>) value. */ - - reg = mrf24j40_getreg(dev->spi, MRF24J40_ESLOTG1); - reg &= ~MRF24J40_ESLOTG1_CAP; - reg |= sfspec->final_capslot & MRF24J40_ESLOTG1_CAP; - mrf24j40_setreg(dev->spi, MRF24J40_ESLOTG1, reg); - - return OK; -} - -/**************************************************************************** - * Internal Functions - ****************************************************************************/ - -static void mrf24j40_mactimer(FAR struct mrf24j40_radio_s *dev, int numsymbols) -{ - uint16_t nhalfsym; - uint8_t reg; - - nhalfsym = (numsymbols << 1); - - /* Disable the interrupt, clear the timer count */ - - reg = mrf24j40_getreg(dev->spi, MRF24J40_INTCON); - reg |= MRF24J40_INTCON_HSYMTMRIE; - mrf24j40_setreg(dev->spi, MRF24J40_INTCON, reg); - - mrf24j40_setreg(dev->spi, MRF24J40_HSYMTMRL, 0x00); - mrf24j40_setreg(dev->spi, MRF24J40_HSYMTMRH, 0x00); - - reg &= ~MRF24J40_INTCON_HSYMTMRIE; - mrf24j40_setreg(dev->spi, MRF24J40_INTCON, reg); - - /* Set the timer count and enable interrupts */ - - reg = (nhalfsym & 0xFF); - mrf24j40_setreg(dev->spi, MRF24J40_HSYMTMRL, reg); - - reg = (nhalfsym >> 8) & 0xFF; - mrf24j40_setreg(dev->spi, MRF24J40_HSYMTMRH, reg); -} - -/**************************************************************************** - * Function: mrf24j40_dopoll_csma - * - * Description: - * This function is called in order to preform an out-of-sequence TX poll. - * This is done: - * - * 1. After completion of a transmission (mrf24j40_txdone_csma), - * 2. When new TX data is available (mrf24j40_txnotify), and - * 3. After a TX timeout to restart the sending process - * (mrf24j40_txtimeout_csma). - * - * Parameters: - * radio - Reference to the radio driver state structure - * - * Returned Value: - * None - * - * Assumptions: - * - ****************************************************************************/ - -static void mrf24j40_dopoll_csma(FAR void *arg) -{ - FAR struct mrf24j40_radio_s *dev = (FAR struct mrf24j40_radio_s *)arg; - int len = 0; - - /* Get exclusive access to the driver */ - - while (sem_wait(&dev->exclsem) != 0) { } - - /* If this a CSMA transaction and we have room in the CSMA fifo */ - - if (!dev->csma_busy) - { - wlinfo("Polling for frame\n"); - len = dev->radiocb->poll(dev->radiocb, false, &dev->csma_desc); - - if (len > 0) - { - wlinfo("Frame received. Frame length: %d\n", len); - - /* Now the txdesc is in use */ - - dev->csma_busy = 1; - - /* Setup the transaction on the device in the CSMA FIFO */ - - mrf24j40_norm_setup(dev, dev->csma_desc->frame, true); - mrf24j40_norm_trigger(dev); - } - } - - sem_post(&dev->exclsem); -} - -/**************************************************************************** - * Function: mrf24j40_dopoll_gts - * - * Description: - * This function is called in order to preform an out-of-sequence TX poll. - * This is done: - * - * 1. After completion of a transmission (mrf24j40_txdone_gts), - * 2. When new TX data is available (mrf24j40_txnotify), and - * 3. After a TX timeout to restart the sending process - * (mrf24j40_txtimeout_gts). - * - * Parameters: - * arg - Reference to the radio driver state structure - * - * Returned Value: - * None - * - * Assumptions: - * - ****************************************************************************/ - -static void mrf24j40_dopoll_gts(FAR void *arg) -{ - FAR struct mrf24j40_radio_s *dev = (FAR struct mrf24j40_radio_s *)arg; - int gts = 0; - int len = 0; - - /* Get exclusive access to the driver */ - - while (sem_wait(&dev->exclsem) != 0) { } - - for (gts = 0; gts < MRF24J40_GTS_SLOTS; gts++) - { - if (!dev->gts_busy[gts]) - { - len = dev->radiocb->poll(dev->radiocb, true, &dev->gts_desc[gts]); - - if (len > 0) - { - /* Now the txdesc is in use */ - - dev->gts_busy[gts]= 1; - - /* Setup the transaction on the device in the open GTS FIFO */ - - mrf24j40_gts_setup(dev, gts, dev->gts_desc[gts]->frame); - } - } - } - - sem_post(&dev->exclsem); -} - -/**************************************************************************** - * Name: mrf24j40_spi_lock - * - * Description: - * Acquire exclusive access to the shared SPI bus. - * - ****************************************************************************/ - -static void mrf24j40_spi_lock(FAR struct spi_dev_s *spi) -{ - SPI_LOCK(spi, 1); - SPI_SETBITS(spi, 8); - SPI_SETMODE(spi, CONFIG_IEEE802154_MRF24J40_SPIMODE); - SPI_SETFREQUENCY(spi, CONFIG_IEEE802154_MRF24J40_FREQUENCY); -} - -/**************************************************************************** - * Name: mrf24j40_spi_unlock - * - * Description: - * Release exclusive access to the shared SPI bus. - * - ****************************************************************************/ - -static inline void mrf24j40_spi_unlock(FAR struct spi_dev_s *spi) -{ - SPI_LOCK(spi,0); -} - -/**************************************************************************** - * Name: mrf24j40_setreg - * - * Description: - * Define the value of an MRF24J40 device register - * - ****************************************************************************/ - -static void mrf24j40_setreg(FAR struct spi_dev_s *spi, uint32_t addr, - uint8_t val) -{ - uint8_t buf[3]; - int len; - - if (!(addr&0x80000000)) - { - addr &= 0x3F; /* 6-bit address */ - addr <<= 1; - addr |= 0x01; /* writing */ - buf[0] = addr; - len = 1; - } - else - { - addr &= 0x3FF; /* 10-bit address */ - addr <<= 5; - addr |= 0x8010; /* writing long */ - buf[0] = (addr >> 8); - buf[1] = (addr & 0xFF); - len = 2; - } - - buf[len++] = val; - - mrf24j40_spi_lock(spi); - SPI_SELECT(spi, SPIDEV_IEEE802154(0), true); - SPI_SNDBLOCK(spi, buf, len); - SPI_SELECT(spi, SPIDEV_IEEE802154(0), false); - mrf24j40_spi_unlock(spi); -} - -/**************************************************************************** - * Name: mrf24j40_getreg - * - * Description: - * Return the value of an MRF24J40 device register* - * - ****************************************************************************/ - -static uint8_t mrf24j40_getreg(FAR struct spi_dev_s *spi, uint32_t addr) -{ - uint8_t buf[3]; - uint8_t rx[3]; - int len; - - if (!(addr&0x80000000)) - { - /* 6-bit address */ - - addr &= 0x3F; - addr <<= 1; - buf[0] = addr; - len = 1; - } - else - { - /* 10-bit address */ - - addr &= 0x3FF; - addr <<= 5; - addr |= 0x8000; - buf[0] = (addr >> 8); - buf[1] = (addr & 0xFF); - len = 2; - } - - buf[len++] = 0xFF; /* dummy */ - - mrf24j40_spi_lock (spi); - SPI_SELECT (spi, SPIDEV_IEEE802154(0), true); - SPI_EXCHANGE (spi, buf, rx, len); - SPI_SELECT (spi, SPIDEV_IEEE802154(0), false); - mrf24j40_spi_unlock(spi); - - /* wlinfo("r[%04X]=%02X\n", addr, rx[len - 1]); */ - return rx[len - 1]; -} - -/**************************************************************************** - * Name: mrf24j40_resetrfsm - * - * Description: - * Reset the RF state machine. Required at boot, after channel change, - * and probably after PA settings. - * - ****************************************************************************/ - -static int mrf24j40_resetrfsm(FAR struct mrf24j40_radio_s *dev) -{ - uint8_t reg; - - reg = mrf24j40_getreg(dev->spi, MRF24J40_RFCTL); - reg |= 0x04; - mrf24j40_setreg(dev->spi, MRF24J40_RFCTL, reg); - - reg &= ~0x04; - mrf24j40_setreg(dev->spi, MRF24J40_RFCTL, reg); - up_udelay(200); - - return OK; -} - -/**************************************************************************** - * Name: mrf24j40_setorder - * - * Description: - * Configures the timers and sets the ORDER register - ****************************************************************************/ - -static void mrf24j40_setorder(FAR struct mrf24j40_radio_s *dev, uint8_t bo, - uint8_t so) -{ - uint32_t maincnt = 0; - uint32_t slpcal = 0; - - /* Calibrate the Sleep Clock (SLPCLK) frequency. Refer to Section 3.15.1.2 - * “Sleep Clock Calibration”. - */ - - /* If the Sleep Clock Selection, SLPCLKSEL (0x207<7:6), is the internal - * oscillator (100 kHz), set SLPCLKDIV to a minimum value of 0x01. - */ - - mrf24j40_setreg(dev->spi, MRF24J40_SLPCON1, 0x01); - - /* Select the source of SLPCLK (internal 100kHz) */ - - mrf24j40_setreg(dev->spi, MRF24J40_RFCON7, MRF24J40_RFCON7_SEL_100KHZ); - - /* Begin calibration by setting the SLPCALEN bit (SLPCAL2 0x20B<4>) to - * ‘1’. Sixteen samples of the SLPCLK are counted and stored in the - * SLPCAL register. No need to mask, this is the only writable bit - */ - - mrf24j40_setreg(dev->spi, MRF24J40_SLPCAL2, MRF24J40_SLPCAL2_SLPCALEN); - - /* Calibration is complete when the SLPCALRDY bit (SLPCAL2 0x20B<7>) is - * set to ‘1’. - */ - - while (!(mrf24j40_getreg(dev->spi, MRF24J40_SLPCAL2) & - MRF24J40_SLPCAL2_SLPCALRDY)) - { - usleep(1); - } - - slpcal = mrf24j40_getreg(dev->spi, MRF24J40_SLPCAL0); - slpcal |= (mrf24j40_getreg(dev->spi, MRF24J40_SLPCAL1) << 8); - slpcal |= ((mrf24j40_getreg(dev->spi, MRF24J40_SLPCAL2) << 16) & 0x0F); - - /* Program the Beacon Interval into the Main Counter, MAINCNT (0x229<1:0>, - * 0x228, 0x227, 0x226), and Remain Counter, REMCNT (0x225, 0x224), - * according to BO and SO values. Refer to Section 3.15.1.3 “Sleep Mode - * Counters” - */ - - - mrf24j40_setreg(dev->spi, MRF24J40_REMCNTL, (MRF24J40_REMCNT & 0xFF)); - mrf24j40_setreg(dev->spi, MRF24J40_REMCNTH, ((MRF24J40_REMCNT >> 8) & 0xFF)); - - maincnt = MRF24J40_MAINCNT(bo, (slpcal * 50 / 16)); - - mrf24j40_setreg(dev->spi, MRF24J40_MAINCNT0, (maincnt & 0xFF)); - mrf24j40_setreg(dev->spi, MRF24J40_MAINCNT1, ((maincnt >> 8) & 0xFF)); - mrf24j40_setreg(dev->spi, MRF24J40_MAINCNT2, ((maincnt >> 16) & 0xFF)); - mrf24j40_setreg(dev->spi, MRF24J40_MAINCNT3, ((maincnt >> 24) & 0x03)); - - /* Configure the BO (ORDER 0x10<7:4>) and SO (ORDER 0x10<3:0>) values. - * After configuring BO and SO, the beacon frame will be sent immediately. - */ - - mrf24j40_setreg(dev->spi, MRF24J40_ORDER, ((bo << 4) & 0xF0) | (so & 0x0F)); -} - -/**************************************************************************** - * Name: mrf24j40_pacontrol - * - * Description: - * Control the external LNA/PA on the MRF24J40MB/MC/MD/ME modules - * GPIO 1: PA enable - * GPIO 2: LNA enable - * GPIO 3: PA power enable (not required on MB) - ****************************************************************************/ - -static int mrf24j40_pacontrol(FAR struct mrf24j40_radio_s *dev, int mode) -{ - if (!dev->paenabled) - { - return OK; - } - - if (mode == MRF24J40_PA_AUTO) - { - mrf24j40_setreg(dev->spi, MRF24J40_TRISGPIO, 0x08); - mrf24j40_setreg(dev->spi, MRF24J40_GPIO , 0x08); - mrf24j40_setreg(dev->spi, MRF24J40_TESTMODE, 0x0F); - } - else if (mode == MRF24J40_PA_ED) - { - mrf24j40_setreg(dev->spi, MRF24J40_TESTMODE, 0x08); - mrf24j40_setreg(dev->spi, MRF24J40_TRISGPIO, 0x0F); - mrf24j40_setreg(dev->spi, MRF24J40_GPIO , 0x0C); - } - else if (mode == MRF24J40_PA_SLEEP) - { - mrf24j40_setreg(dev->spi, MRF24J40_TESTMODE, 0x08); - mrf24j40_setreg(dev->spi, MRF24J40_TRISGPIO, 0x0F); - mrf24j40_setreg(dev->spi, MRF24J40_GPIO , 0x00); - } - else - { - return -EINVAL; - } - - mrf24j40_resetrfsm(dev); - return OK; -} - -/**************************************************************************** - * Name: mrf24j40_setrxmode - * - * Description: - * Set the RX mode (normal, promiscuous, no CRC) - * - ****************************************************************************/ - -static int mrf24j40_setrxmode(FAR struct mrf24j40_radio_s *dev, int mode) -{ - uint8_t reg; - - if (mode < MRF24J40_RXMODE_NORMAL || mode > MRF24J40_RXMODE_NOCRC) - { - return -EINVAL; - } - - reg = mrf24j40_getreg(dev->spi, MRF24J40_RXMCR); - reg &= ~0x03; - reg |= mode; - - /* Set mode options */ - - if (mode != MRF24J40_RXMODE_NORMAL) - { - /* Promisc and error modes: Disable auto ACK */ - - reg |= MRF24J40_RXMCR_NOACKRSP; - } - else - { - /* Normal mode : enable auto-ACK */ - - reg &= ~MRF24J40_RXMCR_NOACKRSP; - } - - mrf24j40_setreg(dev->spi, MRF24J40_RXMCR, reg); - - dev->rxmode = mode; - wlinfo("%u\n", (unsigned)mode); - return OK; -} - -/**************************************************************************** - * Name: mrf24j40_setchannel - * - * Description: - * Define the current radio channel the device is operating on. - * In the 2.4 GHz, there are 16 channels, each 2 MHz wide, 5 MHz spacing: - * Chan MHz Chan MHz Chan MHz Chan MHz - * 11 2405 15 2425 19 2445 23 2465 - * 12 2410 16 2430 20 2450 24 2470 - * 13 2415 17 2435 21 2455 25 2475 - * 14 2420 18 2440 22 2460 26 2480 - * - ****************************************************************************/ - -static int mrf24j40_setchannel(FAR struct mrf24j40_radio_s *dev, uint8_t chan) -{ - if (chan < 11 || chan > 26) - { - wlerr("ERROR: Invalid chan: %d\n",chan); - return -EINVAL; - } - - /* 15. Set channel – See Section 3.4 “Channel Selection”. */ - - mrf24j40_setreg(dev->spi, MRF24J40_RFCON0, (chan - 11) << 4 | 0x03); - - /* 17. RFCTL (0x36) = 0x04 – Reset RF state machine. - * 18. RFCTL (0x36) = 0x00. - */ - - mrf24j40_resetrfsm(dev); - - dev->chan = chan; - wlinfo("%u\n", (unsigned)chan); - - return OK; -} - -/**************************************************************************** - * Name: mrf24j40_setpanid - * - * Description: - * Define the PAN ID the device is operating on. - * - ****************************************************************************/ - -static int mrf24j40_setpanid(FAR struct mrf24j40_radio_s *dev, - FAR const uint8_t *panid) -{ - mrf24j40_setreg(dev->spi, MRF24J40_PANIDL, panid[0]); - mrf24j40_setreg(dev->spi, MRF24J40_PANIDH, panid[1]); - - IEEE802154_PANIDCOPY(dev->addr.panid, panid); - wlinfo("%02X:%02X\n", panid[0], panid[1]); - - return OK; -} - -/**************************************************************************** - * Name: mrf24j40_setsaddr - * - * Description: - * Define the device short address. The following addresses are special: - * FFFEh : Broadcast - * FFFFh : Unspecified - * - ****************************************************************************/ - -static int mrf24j40_setsaddr(FAR struct mrf24j40_radio_s *dev, - FAR const uint8_t *saddr) -{ - mrf24j40_setreg(dev->spi, MRF24J40_SADRL, saddr[0]); - mrf24j40_setreg(dev->spi, MRF24J40_SADRH, saddr[1]); - - IEEE802154_SADDRCOPY(dev->addr.saddr, saddr); - - wlinfo("%02X:%02X\n", saddr[0], saddr[1]); - return OK; -} - -/**************************************************************************** - * Name: mrf24j40_seteaddr - * - * Description: - * Define the device extended address. The following addresses are special: - * FFFFFFFFFFFFFFFFh : Unspecified - * - ****************************************************************************/ - -static int mrf24j40_seteaddr(FAR struct mrf24j40_radio_s *dev, - FAR const uint8_t *eaddr) -{ - int i; - - for (i = 0; i < 8; i++) - { - mrf24j40_setreg(dev->spi, MRF24J40_EADR0 + i, eaddr[i]); - dev->addr.eaddr[i] = eaddr[i]; - } - wlinfo("%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X\n", eaddr[0], eaddr[1], - eaddr[2], eaddr[3], eaddr[4], eaddr[5], eaddr[6], eaddr[7]); - - return OK; -} - -/**************************************************************************** - * Name: mrf24j40_setcoordsaddr - * - * Description: - * Define the coordinator short address. The following addresses are special: - * FFFEh : Broadcast - * FFFFh : Unspecified - * - ****************************************************************************/ - -static int mrf24j40_setcoordsaddr(FAR struct mrf24j40_radio_s *dev, - FAR const uint8_t *saddr) -{ - mrf24j40_setreg(dev->spi, MRF24J40_ASSOSADR0, saddr[0]); - mrf24j40_setreg(dev->spi, MRF24J40_ASSOSADR1, saddr[1]); - - IEEE802154_SADDRCOPY(dev->addr.saddr, saddr); - - wlinfo("%02X:%02X\n", saddr[0], saddr[1]); - return OK; -} - -/**************************************************************************** - * Name: mrf24j40_setcoordeaddr - * - * Description: - * Define the coordinator extended address. The following addresses are special: - * FFFFFFFFFFFFFFFFh : Unspecified - * - ****************************************************************************/ - -static int mrf24j40_setcoordeaddr(FAR struct mrf24j40_radio_s *dev, - FAR const uint8_t *eaddr) -{ - int i; - - for (i = 0; i < 8; i++) - { - mrf24j40_setreg(dev->spi, MRF24J40_ASSOEADR0 + i, eaddr[i]); - dev->addr.eaddr[i] = eaddr[i]; - } - - wlinfo("%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X\n", eaddr[0], eaddr[1], - eaddr[2], eaddr[3], eaddr[4], eaddr[5], eaddr[6], eaddr[7]); - return OK; -} - -/**************************************************************************** - * Name: mrf24j40_setdevmode - * - * Description: - * Define the device behaviour: normal end device or coordinator - * - ****************************************************************************/ - -static int mrf24j40_setdevmode(FAR struct mrf24j40_radio_s *dev, - uint8_t mode) -{ - int ret = OK; - uint8_t reg; - - /* Disable slotted mode until I decide to implement slotted mode */ - - reg = mrf24j40_getreg(dev->spi, MRF24J40_TXMCR); - reg &= ~MRF24J40_TXMCR_SLOTTED; - mrf24j40_setreg(dev->spi, MRF24J40_TXMCR, reg); - mrf24j40_setreg(dev->spi, MRF24J40_ORDER, 0xFF); - - /* Define dev mode */ - - reg = mrf24j40_getreg(dev->spi, MRF24J40_RXMCR); - - if (mode == MRF24J40_MODE_PANCOORD) - { - reg |= MRF24J40_RXMCR_PANCOORD; - reg &= ~MRF24J40_RXMCR_COORD; - } - else if (mode == MRF24J40_MODE_COORD) - { - reg |= MRF24J40_RXMCR_COORD; - reg &= ~MRF24J40_RXMCR_PANCOORD; - } - else if (mode == MRF24J40_MODE_DEVICE) - { - reg &= ~MRF24J40_RXMCR_PANCOORD; - reg &= ~MRF24J40_RXMCR_COORD; - } - else - { - return -EINVAL; - } - - mrf24j40_setreg(dev->spi, MRF24J40_RXMCR, reg); - dev->devmode = mode; - return ret; -} - -/**************************************************************************** - * Name: mrf24j40_settxpower - * - * Description: - * Define the transmit power. Value is passed in mBm, it is rounded to - * the nearest value. Some MRF modules have a power amplifier, this routine - * does not care about this. We only change the CHIP output power. - * - ****************************************************************************/ - -static int mrf24j40_settxpower(FAR struct mrf24j40_radio_s *dev, - int32_t txpwr) -{ - uint8_t reg; - int save_txpwr = txpwr; - - if (txpwr <= -3000 && txpwr > -3630) - { - reg = 0xC0; - txpwr += 3000; - } - else if (txpwr <= -2000) - { - reg = 0x80; - txpwr += 2000; - } - else if (txpwr <= -1000) - { - reg = 0x40; - txpwr += 1000; - } - else if (txpwr <= 0) - { - reg = 0x00; - } - else - { - return -EINVAL; - } - - wlinfo("Remaining attenuation: %d mBm\n",txpwr); - - switch(txpwr/100) - { - case -9: - case -8: - case -7: - case -6: - reg |= 0x07; - break; - - case -5: - reg |= 0x06; - break; - - case -4: - reg |= 0x05; - break; - - case -3: - reg |= 0x04; - break; - - case -2: - reg |= 0x03; - break; - - case -1: - reg |= 0x02; - break; - - case 0: - reg |= 0x00; /* value 0x01 is 0.5 db, not used */ - break; - - default: - return -EINVAL; - } - - mrf24j40_setreg(dev->spi, MRF24J40_RFCON3, reg); - dev->txpower = save_txpwr; - return OK; -} - -/**************************************************************************** - * Name: mrf24j40_setcca - * - * Description: - * Define the Clear Channel Assessement method. - * - ****************************************************************************/ - -static int mrf24j40_setcca(FAR struct mrf24j40_radio_s *dev, - FAR struct ieee802154_cca_s *cca) -{ - uint8_t mode; - - if (!cca->use_ed && !cca->use_cs) - { - return -EINVAL; - } - - if (cca->use_cs && cca->csth > 0x0f) - { - return -EINVAL; - } - - mode = mrf24j40_getreg(dev->spi, MRF24J40_BBREG2); - mode &= 0x03; - - if (cca->use_ed) - { - mode |= MRF24J40_BBREG2_CCAMODE_ED; - mrf24j40_setreg(dev->spi, MRF24J40_CCAEDTH, cca->edth); - } - - if (cca->use_cs) - { - mode |= MRF24J40_BBREG2_CCAMODE_CS; - mode |= cca->csth << 2; - } - - mrf24j40_setreg(dev->spi, MRF24J40_BBREG2, mode); - - memcpy(&dev->cca, cca, sizeof(struct ieee802154_cca_s)); - return OK; -} - -/**************************************************************************** - * Name: mrf24j40_regdump - * - * Description: - * Display the value of all registers. - * - ****************************************************************************/ - -static int mrf24j40_regdump(FAR struct mrf24j40_radio_s *dev) -{ - uint32_t i; - char buf[4+16*3+2+1]; - int len = 0; - - wlinfo("Short regs:\n"); - - for (i = 0; i < 0x40; i++) - { - if ((i & 15) == 0) - { - len=sprintf(buf, "%02x: ",i&0xFF); - } - - len += sprintf(buf+len, "%02x ", mrf24j40_getreg(dev->spi, i)); - if ((i & 15) == 15) - { - sprintf(buf+len, "\n"); - wlinfo("%s", buf); - } - } - - wlinfo("Long regs:\n"); - for (i = 0x80000200; i < 0x80000250; i++) - { - if ((i & 15) == 0) - { - len=sprintf(buf, "%02x: ",i&0xFF); - } - - len += sprintf(buf+len, "%02x ", mrf24j40_getreg(dev->spi, i)); - if ((i & 15) == 15) - { - sprintf(buf+len, "\n"); - wlinfo("%s", buf); - } - } - - return 0; -} - -/**************************************************************************** - * Name: mrf24j40_energydetect - * - * Description: - * Measure the RSSI level for the current channel. - * - ****************************************************************************/ - -static int mrf24j40_energydetect(FAR struct mrf24j40_radio_s *dev, - FAR uint8_t *energy) -{ - uint8_t reg; - - /* Manually enable the LNA*/ - - mrf24j40_pacontrol(dev, MRF24J40_PA_ED); - - /* Set RSSI average duration to 8 symbols */ - - reg = mrf24j40_getreg(dev->spi, MRF24J40_TXBCON1); - reg |= 0x30; - mrf24j40_setreg(dev->spi, MRF24J40_TXBCON1, reg); - - /* 1. Set RSSIMODE1 0x3E<7> – Initiate RSSI calculation. */ - - mrf24j40_setreg(dev->spi, MRF24J40_BBREG6, 0x80); - - /* 2. Wait until RSSIRDY 0x3E<0> is set to ‘1’ – RSSI calculation is - * complete. - */ - - while(!(mrf24j40_getreg(dev->spi, MRF24J40_BBREG6) & 0x01)); - - /* 3. Read RSSI 0x210<7:0> – The RSSI register contains the averaged RSSI - * received power level for 8 symbol periods. - */ - - *energy = mrf24j40_getreg(dev->spi, MRF24J40_RSSI); - - mrf24j40_setreg(dev->spi, MRF24J40_BBREG6, 0x40); - - /* Back to automatic control */ - - mrf24j40_pacontrol(dev, MRF24J40_PA_AUTO); - return OK; -} - -/**************************************************************************** - * Name: mrf24j40_norm_setup - * - * Description: - * Setup a transaction in the normal TX FIFO - * - ****************************************************************************/ - -static void mrf24j40_norm_setup(FAR struct mrf24j40_radio_s *dev, - FAR struct iob_s *frame, bool csma) -{ - uint8_t reg; - - /* Enable tx int */ - - reg = mrf24j40_getreg(dev->spi, MRF24J40_INTCON); - reg &= ~MRF24J40_INTCON_TXNIE; - mrf24j40_setreg(dev->spi, MRF24J40_INTCON, reg); - - /* Enable/Disable CSMA mode */ - - reg = mrf24j40_getreg(dev->spi, MRF24J40_TXMCR); - - if (csma) - { - reg &= ~MRF24J40_TXMCR_NOCSMA; - } - else - { - reg |= MRF24J40_TXMCR_NOCSMA; - } - - mrf24j40_setreg(dev->spi, MRF24J40_TXMCR, reg); - - /* Setup the FIFO */ - - mrf24j40_setup_fifo(dev, frame->io_data, frame->io_len, MRF24J40_TXNORM_FIFO); - - /* If the frame control field contains an acknowledgment request, set the - * TXNACKREQ bit. See IEEE 802.15.4/2003 7.2.1.1 page 112 for info. - */ - - reg = mrf24j40_getreg(dev->spi, MRF24J40_TXNCON); - - if (frame->io_data[0] & IEEE802154_FRAMECTRL_ACKREQ) - { - reg |= MRF24J40_TXNCON_TXNACKREQ; - } - else - { - reg &= ~MRF24J40_TXNCON_TXNACKREQ; - } - - mrf24j40_setreg(dev->spi, MRF24J40_TXNCON, reg); -} - -/**************************************************************************** - * Name: mrf24j40_norm_trigger - * - * Description: - * Trigger the normal TX FIFO - * - ****************************************************************************/ - -static inline void mrf24j40_norm_trigger(FAR struct mrf24j40_radio_s *dev) -{ - uint8_t reg; - - reg = mrf24j40_getreg(dev->spi, MRF24J40_TXNCON); - - reg |= MRF24J40_TXNCON_TXNTRIG; - - mrf24j40_setreg(dev->spi, MRF24J40_TXNCON, reg); -} - -/**************************************************************************** - * Name: mrf24j40_beacon_trigger - * - * Description: - * Trigger the beacon TX FIFO - * - ****************************************************************************/ - -static inline void mrf24j40_beacon_trigger(FAR struct mrf24j40_radio_s *dev) -{ - uint8_t reg; - - reg = mrf24j40_getreg(dev->spi, MRF24J40_TXBCON0); - - reg |= MRF24J40_TXBCON0_TXBTRIG; - - mrf24j40_setreg(dev->spi, MRF24J40_TXBCON0, reg); -} - -/**************************************************************************** - * Name: mrf24j40_gts_setup - * - * Description: - * Setup a GTS transaction in one of the GTS FIFOs - * - ****************************************************************************/ - -static void mrf24j40_gts_setup(FAR struct mrf24j40_radio_s *dev, uint8_t fifo, - FAR struct iob_s *frame) -{ - -} - -/**************************************************************************** - * Name: mrf24j40_setup_fifo - * - * Description: - * - ****************************************************************************/ - -static void mrf24j40_setup_fifo(FAR struct mrf24j40_radio_s *dev, - FAR const uint8_t *buf, uint8_t length, - uint32_t fifo_addr) -{ - int hlen = 3; /* Include frame control and seq number */ - int i; - uint16_t frame_ctrl; - - /* Analyze frame control to compute header length */ - - frame_ctrl = buf[0]; - frame_ctrl |= (buf[1] << 8); - - if ((frame_ctrl & IEEE802154_FRAMECTRL_DADDR)== IEEE802154_ADDRMODE_SHORT) - { - hlen += 2 + 2; /* Destination PAN + shortaddr */ - } - else if ((frame_ctrl & IEEE802154_FRAMECTRL_DADDR) == IEEE802154_ADDRMODE_EXTENDED) - { - hlen += 2 + 8; /* Destination PAN + extaddr */ - } - - if (!(frame_ctrl & IEEE802154_FRAMECTRL_PANIDCOMP)) - { - hlen += 2; /* No PAN compression, source PAN is different from dest PAN */ - } - - if ((frame_ctrl & IEEE802154_FRAMECTRL_SADDR)== IEEE802154_ADDRMODE_SHORT) - { - hlen += 2; /* Source saddr */ - } - else if ((frame_ctrl & IEEE802154_FRAMECTRL_SADDR) == IEEE802154_ADDRMODE_EXTENDED) - { - hlen += 8; /* Ext saddr */ - } - - /* Header len, 0, TODO for security modes */ - - mrf24j40_setreg(dev->spi, fifo_addr++, hlen); - - /* Frame length */ - - mrf24j40_setreg(dev->spi, fifo_addr++, length); - - /* Frame data */ - - for (i = 0; i < length; i++) - { - mrf24j40_setreg(dev->spi, fifo_addr++, buf[i]); - } -} - -/**************************************************************************** - * Name: mrf24j40_irqwork_txnorm - * - * Description: - * Manage completion of packet transmission. - * - ****************************************************************************/ - -static void mrf24j40_irqwork_txnorm(FAR struct mrf24j40_radio_s *dev) -{ - uint8_t reg; - enum ieee802154_status_e status; - bool framepending; - - /* Disable tx int */ - - reg = mrf24j40_getreg(dev->spi, MRF24J40_INTCON); - reg |= MRF24J40_INTCON_TXNIE; - mrf24j40_setreg(dev->spi, MRF24J40_INTCON, reg); - - /* Get the status from the device and copy the status into the tx desc. - * The status for the normal FIFO is represented with bit TXNSTAT where - * 0=success, 1= failure. - */ - - reg = mrf24j40_getreg(dev->spi, MRF24J40_TXSTAT); - - /* TXNSTAT = 0: Transmission was successful - * TXNSTAT = 1: Transmission failed, retry count exceeded - */ - - if (reg & MRF24J40_TXSTAT_TXNSTAT) - { - /* The number of retries of the most recent transmission is contained in the - * TXNRETRY (TXSTAT 0x24<7:6>) bits. The CCAFAIL (TXSTAT 0x24<5>) bit = 1 - * indicates if the failed transmission was due to the channel busy - * (CSMA-CA timed out). - */ - - if (reg & MRF24J40_TXSTAT_CCAFAIL) - { - status = IEEE802154_STATUS_CHANNEL_ACCESS_FAILURE; - } - else - { - status = IEEE802154_STATUS_NO_ACK; - } - } - else - { - status = IEEE802154_STATUS_SUCCESS; - } - - framepending = (mrf24j40_getreg(dev->spi, MRF24J40_TXNCON) & - MRF24J40_TXNCON_FPSTAT); - - if (dev->txdelayed_busy) - { - /* Inform the next layer of the transmission success/failure */ - - dev->txdelayed_desc->conf->status = status; - dev->txdelayed_desc->framepending = framepending; - dev->radiocb->txdone(dev->radiocb, dev->txdelayed_desc); - - dev->txdelayed_busy = false; - - if (dev->reschedule_csma) - { - mrf24j40_norm_setup(dev, dev->csma_desc->frame, true); - mrf24j40_norm_trigger(dev); - dev->reschedule_csma = false; - } - } - else - { - /* Inform the next layer of the transmission success/failure */ - - dev->csma_desc->conf->status = status; - dev->csma_desc->framepending = framepending; - dev->radiocb->txdone(dev->radiocb, dev->csma_desc); - - /* We are now done with the transaction */ - - dev->csma_busy = 0; - - /* Must unlock the radio before calling poll */ - - sem_post(&dev->exclsem); - mrf24j40_dopoll_csma(dev); - while (sem_wait(&dev->exclsem) != 0) { } - } -} - -/**************************************************************************** - * Name: mrf24j40_irqwork_gts - * - * Description: - * Manage completion of packet transmission. - * - ****************************************************************************/ - -static void mrf24j40_irqwork_txgts(FAR struct mrf24j40_radio_s *dev, - uint8_t gts) -{ - uint8_t txstat; - - /* Disable tx int */ - - txstat = mrf24j40_getreg(dev->spi, MRF24J40_INTCON); - txstat |= MRF24J40_INTCON_TXNIE; - mrf24j40_setreg(dev->spi, MRF24J40_INTCON, txstat); - - /* Get the status from the device and copy the status into the tx desc. - * The status for the normal FIFO is represented with bit TXNSTAT where - * 0=success, 1= failure. - */ - - txstat = mrf24j40_getreg(dev->spi, MRF24J40_TXSTAT); - - if (gts == 0) - { - dev->csma_desc->conf->status = txstat & MRF24J40_TXSTAT_TXG1STAT; - } - else if (gts == 1) - { - dev->csma_desc->conf->status = txstat & MRF24J40_TXSTAT_TXG2STAT; - } - - /* Inform the next layer of the transmission success/failure */ - - dev->radiocb->txdone(dev->radiocb, dev->gts_desc[gts]); - - /* We are now done with the transaction */ - - dev->gts_busy[gts]= 0; - - mrf24j40_dopoll_gts(dev); -} - -/**************************************************************************** - * Name: mrf24j40_rxenable - * - * Description: - * Enable/Disable receiver. - * - ****************************************************************************/ - -static int mrf24j40_rxenable(FAR struct ieee802154_radio_s *radio, bool enable) -{ - FAR struct mrf24j40_radio_s *dev = (FAR struct mrf24j40_radio_s *)radio; - uint8_t reg; - - dev->rxenabled = enable; - - - if (enable) - { - /* Disable packet reception. See pg. 109 of datasheet */ - - mrf24j40_setreg(dev->spi, MRF24J40_BBREG1, MRF24J40_BBREG1_RXDECINV); - - /* Enable rx int */ - - reg = mrf24j40_getreg(dev->spi, MRF24J40_INTCON); - reg &= ~MRF24J40_INTCON_RXIE; - mrf24j40_setreg(dev->spi, MRF24J40_INTCON, reg); - - /* Purge the RX buffer */ - - reg = mrf24j40_getreg(dev->spi, MRF24J40_RXFLUSH); - reg |= MRF24J40_RXFLUSH_RXFLUSH; - mrf24j40_setreg(dev->spi, MRF24J40_RXFLUSH, reg); - - /* Re-enable packet reception. See pg. 109 of datasheet */ - - mrf24j40_setreg(dev->spi, MRF24J40_BBREG1, 0); - } - else - { - /* Disable rx int */ - - reg = mrf24j40_getreg(dev->spi, MRF24J40_INTCON); - reg |= MRF24J40_INTCON_RXIE; - mrf24j40_setreg(dev->spi, MRF24J40_INTCON, reg); - } - - return OK; -} - -/**************************************************************************** - * Name: mrf24j40_irqwork_rx - * - * Description: - * Manage packet reception. - * - ****************************************************************************/ - -static void mrf24j40_irqwork_rx(FAR struct mrf24j40_radio_s *dev) -{ - FAR struct ieee802154_data_ind_s *ind; - uint32_t addr; - uint32_t index; - uint8_t reg; - - wlinfo("RX interrupt\n"); - - /* Disable rx int */ - - reg = mrf24j40_getreg(dev->spi, MRF24J40_INTCON); - reg |= MRF24J40_INTCON_RXIE; - mrf24j40_setreg(dev->spi, MRF24J40_INTCON, reg); - - /* Disable packet reception. See pg. 109 of datasheet */ - - mrf24j40_setreg(dev->spi, MRF24J40_BBREG1, MRF24J40_BBREG1_RXDECINV); - - /* Allocate a data_ind to put the frame in */ - - ind = ieee802154_ind_allocate(); - if (ind == NULL) - { - wlerr("ERROR: Unable to allocate data_ind. Discarding frame\n"); - goto done; - } - - /* Read packet */ - - addr = MRF24J40_RXBUF_BASE; - - ind->frame->io_len = mrf24j40_getreg(dev->spi, addr++); - - for (index = 0; index < ind->frame->io_len; index++) - { - ind->frame->io_data[index] = mrf24j40_getreg(dev->spi, addr++); - } - - ind->lqi = mrf24j40_getreg(dev->spi, addr++); - ind->rssi = mrf24j40_getreg(dev->spi, addr++); - - /* Reduce len by 2, we only receive frames with correct crc, no check - * required. - */ - - ind->frame->io_len -= 2; - - /* Callback the receiver in the next highest layer */ - - dev->radiocb->rxframe(dev->radiocb, ind); - -done: - /* Enable reception of next packet by flushing the fifo. - * This is an MRF24J40 errata (no. 1). - */ - - mrf24j40_setreg(dev->spi, MRF24J40_RXFLUSH, 1); - - /* Only enable RX interrupt if we are to be listening when IDLE */ - - if (dev->rxenabled) - { - /* Enable packet reception */ - - mrf24j40_setreg(dev->spi, MRF24J40_BBREG1, 0); - - reg = mrf24j40_getreg(dev->spi, MRF24J40_INTCON); - reg &= ~MRF24J40_INTCON_RXIE; - mrf24j40_setreg(dev->spi, MRF24J40_INTCON, reg); - } -} - -/**************************************************************************** - * Name: mrf24j40_irqworker - * - * Description: - * Perform interrupt handling logic outside of the interrupt handler (on - * the work queue thread). - * - * Parameters: - * arg - The reference to the driver structure (cast to void*) - * - * Returned Value: - * None - * - * Assumptions: - * - ****************************************************************************/ - -static void mrf24j40_irqworker(FAR void *arg) -{ - FAR struct mrf24j40_radio_s *dev = (FAR struct mrf24j40_radio_s *)arg; - uint8_t intstat; - uint8_t reg; - - DEBUGASSERT(dev); - DEBUGASSERT(dev->spi); - - /* Get exclusive access to the driver */ - - while (sem_wait(&dev->exclsem) != 0) { } - - /* Read and store INTSTAT - this clears the register. */ - - intstat = mrf24j40_getreg(dev->spi, MRF24J40_INTSTAT); - - /* Do work according to the pending interrupts */ - - if ((intstat & MRF24J40_INTSTAT_HSYMTMRIF)) - { - /* As of now the only use for the MAC timer is for delayed transactions. - * Therefore, all we do here is trigger the TX norm FIFO - */ - - mrf24j40_norm_trigger(dev); - - /* Timers are one-shot, so disable the interrupt */ - - reg = mrf24j40_getreg(dev->spi, MRF24J40_INTCON); - reg |= MRF24J40_INTCON_HSYMTMRIE; - mrf24j40_setreg(dev->spi, MRF24J40_INTCON, reg); - } - - if ((intstat & MRF24J40_INTSTAT_RXIF) && dev->rxenabled) - { - /* A packet was received, retrieve it */ - - mrf24j40_irqwork_rx(dev); - } - - if ((intstat & MRF24J40_INTSTAT_TXNIF)) - { - /* A packet was transmitted or failed*/ - - mrf24j40_irqwork_txnorm(dev); - } - - if ((intstat & MRF24J40_INTSTAT_TXG1IF)) - { - /* A packet was transmitted or failed*/ - - mrf24j40_irqwork_txgts(dev, 0); - } - - if ((intstat & MRF24J40_INTSTAT_TXG1IF)) - { - /* A packet was transmitted or failed*/ - - mrf24j40_irqwork_txgts(dev, 1); - } - - if ((intstat & MRF24J40_INTSTAT_SLPIF)) - { - dev->radiocb->sfevent(dev->radiocb, IEEE802154_SFEVENT_ENDOFACTIVE); - - /* Acknowledge the alert and put the device to sleep */ - - reg = mrf24j40_getreg(dev->spi, MRF24J40_SLPACK); - reg |= MRF24J40_SLPACK_SLPACK; - mrf24j40_setreg(dev->spi, MRF24J40_SLPACK, reg); - } - - if ((intstat & MRF24J40_INTSTAT_WAKEIF)) - { - wlinfo("Wake Interrupt\n"); - /* This is right before the beacon, we set the bsn here, since the MAC - * uses the SLPIF (end of active portion of superframe). to make any - * changes to the beacon. This assumes that any changes to the beacon - * be in by the time that this interrupt fires. - */ - - mrf24j40_setreg(dev->spi, MRF24J40_BEACON_FIFO + 4, dev->bsn++); - mrf24j40_beacon_trigger(dev); - } - - /* Unlock the radio device */ - - sem_post(&dev->exclsem); - - /* Re-enable GPIO interrupts */ - - dev->lower->enable(dev->lower, true); -} - -/**************************************************************************** - * Name: mrf24j40_interrupt - * - * Description: - * Hardware interrupt handler - * - * Parameters: - * irq - Number of the IRQ that generated the interrupt - * context - Interrupt register state save info (architecture-specific) - * - * Returned Value: - * OK on success - * - * Assumptions: - * - ****************************************************************************/ - -static int mrf24j40_interrupt(int irq, FAR void *context, FAR void *arg) -{ - FAR struct mrf24j40_radio_s *dev = (FAR struct mrf24j40_radio_s *)arg; - - DEBUGASSERT(dev != NULL); - - /* In complex environments, we cannot do SPI transfers from the interrupt - * handler because semaphores are probably used to lock the SPI bus. In - * this case, we will defer processing to the worker thread. This is also - * much kinder in the use of system resources and is, therefore, probably - * a good thing to do in any event. - */ - - DEBUGASSERT(work_available(&dev->irqwork)); - - /* Notice that further GPIO interrupts are disabled until the work is - * actually performed. This is to prevent overrun of the worker thread. - * Interrupts are re-enabled in enc_irqworker() when the work is completed. - */ - - dev->lower->enable(dev->lower, false); - return work_queue(HPWORK, &dev->irqwork, mrf24j40_irqworker, (FAR void *)dev, 0); -} - -/**************************************************************************** - * Public Functions - ****************************************************************************/ - -/**************************************************************************** - * Name: mrf24j40_init - * - * Description: - * Return an mrf24j40 device for use by other drivers. - * - ****************************************************************************/ - -FAR struct ieee802154_radio_s *mrf24j40_init(FAR struct spi_dev_s *spi, - FAR const struct mrf24j40_lower_s *lower) -{ - FAR struct mrf24j40_radio_s *dev; - - dev = kmm_zalloc(sizeof(struct mrf24j40_radio_s)); - if (dev == NULL) - { - return NULL; - } - - /* Attach irq */ - - if (lower->attach(lower, mrf24j40_interrupt, dev) != OK) - { -#if 0 - free(dev); -#endif - return NULL; - } - - /* Allow exclusive access to the privmac struct */ - - sem_init(&dev->exclsem, 0, 1); - - dev->radio.bind = mrf24j40_bind; - dev->radio.reset = mrf24j40_reset; - dev->radio.getattr = mrf24j40_getattr; - dev->radio.setattr = mrf24j40_setattr; - dev->radio.txnotify = mrf24j40_txnotify; - dev->radio.txdelayed = mrf24j40_txdelayed; - dev->radio.rxenable = mrf24j40_rxenable; - dev->radio.beaconstart = mrf24j40_beaconstart; - dev->radio.beaconupdate = mrf24j40_beaconupdate; - dev->radio.beaconstop = mrf24j40_beaconstop; - dev->radio.sfupdate = mrf24j40_sfupdate; - - dev->lower = lower; - dev->spi = spi; - - mrf24j40_reset(&dev->radio); - - dev->lower->enable(dev->lower, true); - return &dev->radio; -} +/**************************************************************************** + * drivers/wireless/ieee802154/mrf24j40/mrf24j40.c + * + * Copyright (C) 2015-2016 Sebastien Lorquet. All rights reserved. + * Copyright (C) 2017 Verge Inc. All rights reserved. + * Author: Sebastien Lorquet + * Author: Anthony Merlino + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include + +#include "mrf24j40.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#ifndef CONFIG_SCHED_HPWORK +# error High priority work queue required in this driver +#endif + +#ifndef CONFIG_IEEE802154_MRF24J40_SPIMODE +# define CONFIG_IEEE802154_MRF24J40_SPIMODE SPIDEV_MODE0 +#endif + +#ifndef CONFIG_IEEE802154_MRF24J40_FREQUENCY +# define CONFIG_IEEE802154_MRF24J40_FREQUENCY 8000000 +#endif + +#ifndef CONFIG_SPI_EXCHANGE +# error CONFIG_SPI_EXCHANGE required for this driver +#endif + +/* Definitions for the device structure */ + +#define MRF24J40_RXMODE_NORMAL 0 +#define MRF24J40_RXMODE_PROMISC 1 +#define MRF24J40_RXMODE_NOCRC 2 + +#define MRF24J40_MODE_DEVICE 0 +#define MRF24J40_MODE_COORD 1 +#define MRF24J40_MODE_PANCOORD 2 + +/* Definitions for PA control on high power modules */ + +#define MRF24J40_PA_AUTO 1 +#define MRF24J40_PA_ED 2 +#define MRF24J40_PA_SLEEP 3 + +#define MRF24J40_GTS_SLOTS 2 + +/* Clock configuration macros */ + +#define MRF24J40_SLPCLKPER_100KHZ ((1000 * 1000 * 1000)/100000) /* 10ns */ +#define MRF24J40_SLPCLKPER_32KHZ ((1000 * 1000 * 1000)/32000) /* 31.25ns */ + +#define MRF24J40_BEACONINTERVAL_NSEC(beaconorder) \ + (IEEE802154_BASE_SUPERFRAME_DURATION * (1 << beaconorder) * (16 *1000)) + +/* For now I am just setting the REMCNT to the maximum while staying in multiples + * of 10000 (100khz period) */ + +#define MRF24J40_REMCNT 60000 +#define MRF24J40_REMCNT_NSEC (MRF24J40_REMCNT * 50) + +#define MRF24J40_MAINCNT(bo, clkper) \ + ((MRF24J40_BEACONINTERVAL_NSEC(bo) - MRF24J40_REMCNT_NSEC) / \ + clkper) + +/* Formula for calculating default macMaxFrameWaitTime is on pg. 130 + * + * For PHYs other than CSS and UWB, the attribute phyMaxFrameDuration is given by: + * + * phyMaxFrameDuration = phySHRDuration + + * ceiling([aMaxPHYPacketSize + 1] x phySymbolsPerOctet) + * + * where ceiling() is a function that returns the smallest integer value greater + * than or equal to its argument value. [1] pg. 158 +*/ + +#define MRF24J40_DEFAULT_MAX_FRAME_WAITTIME 1824 + +#define MRF24J40_SYMBOL_DURATION_PS 16000000 + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/* A MRF24J40 device instance */ + +struct mrf24j40_radio_s +{ + struct ieee802154_radio_s radio; /* The public device instance */ + FAR struct ieee802154_radiocb_s *radiocb; /* Registered callbacks */ + + /* Low-level MCU-specific support */ + + FAR const struct mrf24j40_lower_s *lower; + FAR struct spi_dev_s *spi; /* Saved SPI interface instance */ + + struct work_s irqwork; /* For deferring interrupt work to work queue */ + struct work_s csma_pollwork; /* For deferring poll work to the work queue */ + struct work_s gts_pollwork; /* For deferring poll work to the work queue */ + + sem_t exclsem; /* Exclusive access to this struct */ + + /* MAC Attributes */ + + struct ieee802154_addr_s addr; + + uint8_t chan; /* 11 to 26 for the 2.4 GHz band */ + uint8_t devmode; /* device mode: device, coord, pancoord */ + uint8_t paenabled; /* enable usage of PA */ + uint8_t rxmode; /* Reception mode: Main, no CRC, promiscuous */ + int32_t txpower; /* TX power in mBm = dBm/100 */ + struct ieee802154_cca_s cca; /* Clear channel assessement method */ + + /* MAC PIB attributes */ + + uint32_t max_frame_waittime; + + struct ieee802154_txdesc_s *txdelayed_desc; + struct ieee802154_txdesc_s *csma_desc; + bool txdelayed_busy : 1; + bool csma_busy : 1; + bool reschedule_csma : 1; + + bool rxenabled : 1; + + uint8_t bsn; + + struct ieee802154_txdesc_s *gts_desc[MRF24J40_GTS_SLOTS]; + bool gts_busy[MRF24J40_GTS_SLOTS]; +}; + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +/* Internal operations */ + +static void mrf24j40_spi_lock(FAR struct spi_dev_s *spi); + +static void mrf24j40_setreg(FAR struct spi_dev_s *spi, uint32_t addr, + uint8_t val); +static uint8_t mrf24j40_getreg(FAR struct spi_dev_s *spi, uint32_t addr); + +static int mrf24j40_resetrfsm(FAR struct mrf24j40_radio_s *dev); +static void mrf24j40_setorder(FAR struct mrf24j40_radio_s *dev, uint8_t bo, + uint8_t so); +static int mrf24j40_pacontrol(FAR struct mrf24j40_radio_s *dev, int mode); + +static int mrf24j40_setrxmode(FAR struct mrf24j40_radio_s *dev, int mode); +static int mrf24j40_regdump(FAR struct mrf24j40_radio_s *dev); + +static void mrf24j40_irqwork_rx(FAR struct mrf24j40_radio_s *dev); +static void mrf24j40_irqwork_txnorm(FAR struct mrf24j40_radio_s *dev); +static void mrf24j40_irqwork_txgts(FAR struct mrf24j40_radio_s *dev, + uint8_t gts_num); + +static void mrf24j40_irqworker(FAR void *arg); +static int mrf24j40_interrupt(int irq, FAR void *context, FAR void *arg); + +static void mrf24j40_dopoll_csma(FAR void *arg); +static void mrf24j40_dopoll_gts(FAR void *arg); + +static void mrf24j40_norm_setup(FAR struct mrf24j40_radio_s *dev, + FAR struct iob_s *frame, bool csma); +static void mrf24j40_gts_setup(FAR struct mrf24j40_radio_s *dev, uint8_t gts, + FAR struct iob_s *frame); +static void mrf24j40_setup_fifo(FAR struct mrf24j40_radio_s *dev, + FAR const uint8_t *buf, uint8_t length, uint32_t fifo_addr); + +static inline void mrf24j40_norm_trigger(FAR struct mrf24j40_radio_s *dev); +static inline void mrf24j40_beacon_trigger(FAR struct mrf24j40_radio_s *dev); + +static int mrf24j40_setchannel(FAR struct mrf24j40_radio_s *dev, + uint8_t chan); +static int mrf24j40_setpanid(FAR struct mrf24j40_radio_s *dev, + FAR const uint8_t *panid); +static int mrf24j40_setsaddr(FAR struct mrf24j40_radio_s *dev, + FAR const uint8_t *saddr); +static int mrf24j40_seteaddr(FAR struct mrf24j40_radio_s *dev, + FAR const uint8_t *eaddr); +static int mrf24j40_setcoordsaddr(FAR struct mrf24j40_radio_s *dev, + FAR const uint8_t *saddr); +static int mrf24j40_setcoordeaddr(FAR struct mrf24j40_radio_s *dev, + FAR const uint8_t *eaddr); +static int mrf24j40_setdevmode(FAR struct mrf24j40_radio_s *dev, + uint8_t mode); +static int mrf24j40_settxpower(FAR struct mrf24j40_radio_s *dev, + int32_t txpwr); +static int mrf24j40_setcca(FAR struct mrf24j40_radio_s *dev, + FAR struct ieee802154_cca_s *cca); +static int mrf24j40_energydetect(FAR struct mrf24j40_radio_s *dev, + FAR uint8_t *energy); +static void mrf24j40_mactimer(FAR struct mrf24j40_radio_s *dev, int numsymbols); + +/* Driver operations */ + +static int mrf24j40_bind(FAR struct ieee802154_radio_s *radio, + FAR struct ieee802154_radiocb_s *radiocb); +static int mrf24j40_reset(FAR struct ieee802154_radio_s *radio); +static int mrf24j40_getattr(FAR struct ieee802154_radio_s *radio, + enum ieee802154_attr_e attr, + FAR union ieee802154_attr_u *attrval); +static int mrf24j40_setattr(FAR struct ieee802154_radio_s *radio, + enum ieee802154_attr_e attr, + FAR const union ieee802154_attr_u *attrval); +static int mrf24j40_txnotify(FAR struct ieee802154_radio_s *radio, bool gts); +static int mrf24j40_txdelayed(FAR struct ieee802154_radio_s *radio, + FAR struct ieee802154_txdesc_s *txdesc, + uint32_t symboldelay); +static int mrf24j40_rxenable(FAR struct ieee802154_radio_s *dev, bool enable); +static int mrf24j40_beaconstart(FAR struct ieee802154_radio_s *radio, + FAR const struct ieee802154_superframespec_s *sfspec, + FAR struct ieee802154_beaconframe_s *beacon); +static int mrf24j40_beaconupdate(FAR struct ieee802154_radio_s *radio, + FAR struct ieee802154_beaconframe_s *beacon); +static int mrf24j40_beaconstop(FAR struct ieee802154_radio_s *radio); +static int mrf24j40_sfupdate(FAR struct ieee802154_radio_s *radio, + FAR const struct ieee802154_superframespec_s *sfspec); + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +static const uint8_t g_allones[8] = +{ + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF +}; + +/**************************************************************************** + * Radio Interface Functions + ****************************************************************************/ + +static int mrf24j40_bind(FAR struct ieee802154_radio_s *radio, + FAR struct ieee802154_radiocb_s *radiocb) +{ + FAR struct mrf24j40_radio_s *dev = (FAR struct mrf24j40_radio_s *)radio; + + DEBUGASSERT(dev != NULL); + dev->radiocb = radiocb; + return OK; +} + +/**************************************************************************** + * Function: mrf24j40_txnotify + * + * Description: + * Driver callback invoked when new TX data is available. This is a + * stimulus perform an out-of-cycle poll and, thereby, reduce the TX + * latency. + * + * Parameters: + * radio - Reference to the radio driver state structure + * + * Returned Value: + * None + * + * Assumptions: + * + ****************************************************************************/ + +static int mrf24j40_txnotify(FAR struct ieee802154_radio_s *radio, bool gts) +{ + FAR struct mrf24j40_radio_s *dev = (FAR struct mrf24j40_radio_s *)radio; + + if (gts) + { + /* Is our single work structure available? It may not be if there are + * pending interrupt actions and we will have to ignore the Tx + * availability action. + */ + + if (work_available(&dev->gts_pollwork)) + { + /* Schedule to serialize the poll on the worker thread. */ + + work_queue(HPWORK, &dev->gts_pollwork, mrf24j40_dopoll_gts, dev, 0); + } + } + else + { + /* Is our single work structure available? It may not be if there are + * pending interrupt actions and we will have to ignore the Tx + * availability action. + */ + + if (work_available(&dev->csma_pollwork)) + { + /* Schedule to serialize the poll on the worker thread. */ + + work_queue(HPWORK, &dev->csma_pollwork, mrf24j40_dopoll_csma, dev, 0); + } + } + + return OK; +} + +/**************************************************************************** + * Function: mrf24j40_txdelayed + * + * Description: + * Transmit a packet without regard to supeframe structure after a certain + * number of symbols. This function is used to send Data Request responses. + * It can also be used to send data immediately if the delay is set to 0. + * + * Parameters: + * radio - Reference to the radio driver state structure + * + * Returned Value: + * None + * + * Assumptions: + * + ****************************************************************************/ + +static int mrf24j40_txdelayed(FAR struct ieee802154_radio_s *radio, + FAR struct ieee802154_txdesc_s *txdesc, + uint32_t symboldelay) +{ + FAR struct mrf24j40_radio_s *dev = (FAR struct mrf24j40_radio_s *)radio; + uint8_t reg; + + /* Get exclusive access to the radio device */ + + if (sem_wait(&dev->exclsem) != 0) + { + return -EINTR; + } + + /* There should never be more than one of these transactions at once. */ + + DEBUGASSERT(!dev->txdelayed_busy); + + dev->txdelayed_desc = txdesc; + dev->txdelayed_busy = true; + + /* Disable the TX norm interrupt and clear it */ + + reg = mrf24j40_getreg(dev->spi, MRF24J40_INTCON); + reg |= MRF24J40_INTCON_TXNIE; + mrf24j40_setreg(dev->spi, MRF24J40_INTCON, reg); + + /* If after disabling the interrupt, the irqworker is not scheduled, there + * are no interrupts to worry about. However, if there is work scheduled, + * we need to process it before going any further. + */ + + if (!work_available(&dev->irqwork)) + { + work_cancel(HPWORK, &dev->irqwork); + sem_post(&dev->exclsem); + mrf24j40_irqworker((FAR void *)dev); + + /* Get exclusive access to the radio device */ + + if (sem_wait(&dev->exclsem) != 0) + { + return -EINTR; + } + } + + if (dev->csma_busy) + { + dev->reschedule_csma = true; + } + + mrf24j40_norm_setup(dev, txdesc->frame, false); + + if (symboldelay == 0) + { + mrf24j40_norm_trigger(dev); + } + else + { + mrf24j40_mactimer(dev, symboldelay); + } + + sem_post(&dev->exclsem); + + return OK; +} + +static int mrf24j40_reset(FAR struct ieee802154_radio_s *radio) +{ + FAR struct mrf24j40_radio_s *dev = (FAR struct mrf24j40_radio_s *)radio; + struct ieee802154_cca_s cca; + int reg; + + /* Software reset */ + + mrf24j40_setreg(dev->spi, MRF24J40_SOFTRST , 0x07); /* 00000111 Reset */ + while(mrf24j40_getreg(dev->spi, MRF24J40_SOFTRST) & 0x07); + + /* Apply recommended settings */ + + mrf24j40_setreg(dev->spi, MRF24J40_PACON2 , 0x98); /* 10011000 Enable FIFO (default), TXONTS=6 (recommended), TXONT<8:7>=0 */ + mrf24j40_setreg(dev->spi, MRF24J40_TXSTBL , 0x95); /* 10010101 set the SIFS period. RFSTBL=9, MSIFS=5, aMinSIFSPeriod=14 (min 12) */ + mrf24j40_setreg(dev->spi, MRF24J40_TXPEND , 0x7C); /* 01111100 set the LIFS period, MLIFS=1Fh=31 aMinLIFSPeriod=40 (min 40) */ + mrf24j40_setreg(dev->spi, MRF24J40_TXTIME , 0x30); /* 00110000 set the turnaround time, TURNTIME=3 aTurnAroundTime=12 */ + mrf24j40_setreg(dev->spi, MRF24J40_RFCON1 , 0x02); /* 00000010 VCO optimization, recommended value */ + mrf24j40_setreg(dev->spi, MRF24J40_RFCON2 , 0x80); /* 10000000 Enable PLL */ + mrf24j40_setreg(dev->spi, MRF24J40_RFCON6 , 0x90); /* 10010000 TX filter enable, fast 20M recovery, No bat monitor*/ + mrf24j40_setreg(dev->spi, MRF24J40_RFCON7 , 0x80); /* 10000000 Sleep clock on internal 100 kHz */ + mrf24j40_setreg(dev->spi, MRF24J40_RFCON8 , 0x10); /* 00010000 VCO control bit, as recommended */ + mrf24j40_setreg(dev->spi, MRF24J40_SLPCON1, 0x01); /* 00000001 no CLKOUT, default divisor */ + mrf24j40_setreg(dev->spi, MRF24J40_BBREG6 , 0x40); /* 01000000 Append RSSI to rx packets */ + + /* Set this in reset since it can exist for all device modes. See pg 101 */ + + mrf24j40_setreg(dev->spi, MRF24J40_FRMOFFSET, 0x15); + + /* For now, we want to always just have the frame pending bit set when + * acknowledging a Data Request command. The standard says that the coordinator + * can do this if it needs time to figure out whether it has data or not + */ + + mrf24j40_setreg(dev->spi, MRF24J40_ACKTMOUT, 0x39 | MRF24J40_ACKTMOUT_DRPACK); + + /* Set WAKECNT (SLPACK 0x35<6:0>) value = 0x5F to set the main oscillator + * (20 MHz) start-up timer value. + */ + + mrf24j40_setreg(dev->spi, MRF24J40_SLPACK, 0x5F); + + /* Enable the SLPIF and WAKEIF flags */ + + reg = mrf24j40_getreg(dev->spi, MRF24J40_INTCON); + reg &= ~(MRF24J40_INTCON_SLPIE | MRF24J40_INTCON_WAKEIE); + mrf24j40_setreg(dev->spi, MRF24J40_INTCON, reg); + + dev->rxenabled = false; + + mrf24j40_setchannel(dev, 11); + mrf24j40_setpanid(dev, g_allones); + mrf24j40_setsaddr(dev, g_allones); + mrf24j40_seteaddr(dev, g_allones); + + dev->max_frame_waittime = MRF24J40_DEFAULT_MAX_FRAME_WAITTIME; + dev->bsn = 0; + + /* Default device params */ + + cca.use_ed = 1; + cca.use_cs = 0; + cca.edth = 0x60; /* CCA mode ED, no carrier sense, recommenced ED threshold -69 dBm */ + mrf24j40_setcca(dev, &cca); + + mrf24j40_setrxmode(dev, MRF24J40_RXMODE_NORMAL); + + mrf24j40_settxpower(dev, 0); /*16. Set transmitter power .*/ + + mrf24j40_pacontrol(dev, MRF24J40_PA_AUTO); + + return OK; +} + +static int mrf24j40_getattr(FAR struct ieee802154_radio_s *radio, + enum ieee802154_attr_e attr, + FAR union ieee802154_attr_u *attrval) +{ + FAR struct mrf24j40_radio_s *dev = (FAR struct mrf24j40_radio_s *)radio; + int ret; + + switch (attr) + { + case IEEE802154_ATTR_MAC_EADDR: + { + memcpy(&attrval->mac.eaddr[0], &dev->addr.eaddr[0], 8); + ret = IEEE802154_STATUS_SUCCESS; + } + break; + + case IEEE802154_ATTR_MAC_MAX_FRAME_WAITTIME: + { + attrval->mac.max_frame_waittime = dev->max_frame_waittime; + ret = IEEE802154_STATUS_SUCCESS; + } + break; + + case IEEE802154_ATTR_PHY_SYMBOL_DURATION: + { + attrval->phy.symdur_picosec = MRF24J40_SYMBOL_DURATION_PS; + ret = IEEE802154_STATUS_SUCCESS; + } + break; + + case IEEE802154_ATTR_PHY_CHAN: + { + attrval->phy.chan = dev->chan; + ret = IEEE802154_STATUS_SUCCESS; + } + + default: + ret = IEEE802154_STATUS_UNSUPPORTED_ATTRIBUTE; + } + + return ret; +} + +static int mrf24j40_setattr(FAR struct ieee802154_radio_s *radio, + enum ieee802154_attr_e attr, + FAR const union ieee802154_attr_u *attrval) +{ + FAR struct mrf24j40_radio_s *dev = (FAR struct mrf24j40_radio_s *)radio; + int ret; + + switch (attr) + { + case IEEE802154_ATTR_MAC_PANID: + { + mrf24j40_setpanid(dev, attrval->mac.panid); + ret = IEEE802154_STATUS_SUCCESS; + } + break; + + case IEEE802154_ATTR_MAC_SADDR: + { + mrf24j40_setsaddr(dev, attrval->mac.saddr); + ret = IEEE802154_STATUS_SUCCESS; + } + break; + + case IEEE802154_ATTR_MAC_EADDR: + { + mrf24j40_seteaddr(dev, attrval->mac.eaddr); + ret = IEEE802154_STATUS_SUCCESS; + } + break; + + case IEEE802154_ATTR_MAC_COORD_SADDR: + { + mrf24j40_setcoordsaddr(dev, attrval->mac.coordsaddr); + ret = IEEE802154_STATUS_SUCCESS; + } + break; + + case IEEE802154_ATTR_MAC_COORD_EADDR: + { + mrf24j40_setcoordeaddr(dev, attrval->mac.coordeaddr); + ret = IEEE802154_STATUS_SUCCESS; + } + break; + + case IEEE802154_ATTR_MAC_PROMISCUOUS_MODE: + { + if (attrval->mac.promisc_mode) + { + mrf24j40_setrxmode(dev, MRF24J40_RXMODE_PROMISC); + } + else + { + mrf24j40_setrxmode(dev, MRF24J40_RXMODE_NORMAL); + } + + ret = IEEE802154_STATUS_SUCCESS; + } + break; + + + case IEEE802154_ATTR_PHY_CHAN: + { + mrf24j40_setchannel(dev, attrval->phy.chan); + ret = IEEE802154_STATUS_SUCCESS; + } + break; + + default: + ret = IEEE802154_STATUS_UNSUPPORTED_ATTRIBUTE; + break; + } + return ret; +} + +static int mrf24j40_beaconstart(FAR struct ieee802154_radio_s *radio, + FAR const struct ieee802154_superframespec_s *sfspec, + FAR struct ieee802154_beaconframe_s *beacon) +{ + FAR struct mrf24j40_radio_s *dev = (FAR struct mrf24j40_radio_s *)radio; + int reg; + + if (sfspec->pancoord) + { + /* Set the PANCOORD (RXMCR 0x00<3>) bit = 1to configure as PAN coordinator */ + + reg = mrf24j40_getreg(dev->spi, MRF24J40_RXMCR); + reg |= MRF24J40_RXMCR_PANCOORD; + mrf24j40_setreg(dev->spi, MRF24J40_RXMCR, reg); + + /* Set the SLOTTED (TXMCR 0x11<5>) bit = 1 to use Slotted CSMA-CA mode */ + + reg = mrf24j40_getreg(dev->spi, MRF24J40_TXMCR); + reg |= MRF24J40_TXMCR_SLOTTED; + mrf24j40_setreg(dev->spi, MRF24J40_TXMCR, reg); + + /* Load the beacon frame into the TXBFIFO (0x080-0x0FF). */ + + mrf24j40_setup_fifo(dev, beacon->bf_data, beacon->bf_len, MRF24J40_BEACON_FIFO); + + /* The radio layer is responsible for setting the BSN. */ + + dev->bsn = 0; + mrf24j40_setreg(dev->spi, MRF24J40_BEACON_FIFO + 4, dev->bsn++); + + /* Set the TXBMSK (TXBCON1 0x25<7>) bit = 1 to mask the beacon interrupt + * mask + */ + + reg = mrf24j40_getreg(dev->spi, MRF24J40_TXBCON1); + reg |= MRF24J40_TXBCON1_TXBMSK; + mrf24j40_setreg(dev->spi, MRF24J40_TXBCON1, reg); + + /* Set INTL (WAKECON 0x22<5:0>) value to 0x03. */ + + reg = mrf24j40_getreg(dev->spi, MRF24J40_WAKECON); + reg &= ~MRF24J40_WAKECON_INTL; + reg |= 0x03 & MRF24J40_WAKECON_INTL; + mrf24j40_setreg(dev->spi, MRF24J40_WAKECON, reg); + + /* Program the CAP end slot (ESLOTG1 0x13<3:0>) value. */ + + reg = mrf24j40_getreg(dev->spi, MRF24J40_ESLOTG1); + reg &= ~MRF24J40_ESLOTG1_CAP; + reg |= sfspec->final_capslot & MRF24J40_ESLOTG1_CAP; + mrf24j40_setreg(dev->spi, MRF24J40_ESLOTG1, reg); + + /* TODO: Add GTS related code. See pg 100 of datasheet */ + + mrf24j40_setorder(dev, sfspec->beaconorder, sfspec->sforder); + } + else + { + return -ENOTTY; + } + + return OK; +} + +static int mrf24j40_beaconupdate(FAR struct ieee802154_radio_s *radio, + FAR struct ieee802154_beaconframe_s *beacon) +{ + FAR struct mrf24j40_radio_s *dev = (FAR struct mrf24j40_radio_s *)radio; + + mrf24j40_setup_fifo(dev, beacon->bf_data, beacon->bf_len, MRF24J40_BEACON_FIFO); + mrf24j40_beacon_trigger(dev); + + return OK; +} + +static int mrf24j40_beaconstop(FAR struct ieee802154_radio_s *radio) +{ + return -ENOTTY; +} + +static int mrf24j40_sfupdate(FAR struct ieee802154_radio_s *radio, + FAR const struct ieee802154_superframespec_s *sfspec) +{ + FAR struct mrf24j40_radio_s *dev = (FAR struct mrf24j40_radio_s *)radio; + int reg; + + /* If we are operating on a beacon-enabled network, use slotted CSMA */ + + reg = mrf24j40_getreg(dev->spi, MRF24J40_TXMCR); + if (sfspec->beaconorder < 15) + { + reg |= MRF24J40_TXMCR_SLOTTED; + } + else + { + reg &= ~MRF24J40_TXMCR_SLOTTED; + } + mrf24j40_setreg(dev->spi, MRF24J40_TXMCR, reg); + + mrf24j40_setorder(dev, sfspec->beaconorder, sfspec->sforder); + + /* Program the CAP end slot (ESLOTG1 0x13<3:0>) value. */ + + reg = mrf24j40_getreg(dev->spi, MRF24J40_ESLOTG1); + reg &= ~MRF24J40_ESLOTG1_CAP; + reg |= sfspec->final_capslot & MRF24J40_ESLOTG1_CAP; + mrf24j40_setreg(dev->spi, MRF24J40_ESLOTG1, reg); + + return OK; +} + +/**************************************************************************** + * Internal Functions + ****************************************************************************/ + +static void mrf24j40_mactimer(FAR struct mrf24j40_radio_s *dev, int numsymbols) +{ + uint16_t nhalfsym; + uint8_t reg; + + nhalfsym = (numsymbols << 1); + + /* Disable the interrupt, clear the timer count */ + + reg = mrf24j40_getreg(dev->spi, MRF24J40_INTCON); + reg |= MRF24J40_INTCON_HSYMTMRIE; + mrf24j40_setreg(dev->spi, MRF24J40_INTCON, reg); + + mrf24j40_setreg(dev->spi, MRF24J40_HSYMTMRL, 0x00); + mrf24j40_setreg(dev->spi, MRF24J40_HSYMTMRH, 0x00); + + reg &= ~MRF24J40_INTCON_HSYMTMRIE; + mrf24j40_setreg(dev->spi, MRF24J40_INTCON, reg); + + /* Set the timer count and enable interrupts */ + + reg = (nhalfsym & 0xFF); + mrf24j40_setreg(dev->spi, MRF24J40_HSYMTMRL, reg); + + reg = (nhalfsym >> 8) & 0xFF; + mrf24j40_setreg(dev->spi, MRF24J40_HSYMTMRH, reg); +} + +/**************************************************************************** + * Function: mrf24j40_dopoll_csma + * + * Description: + * This function is called in order to preform an out-of-sequence TX poll. + * This is done: + * + * 1. After completion of a transmission (mrf24j40_txdone_csma), + * 2. When new TX data is available (mrf24j40_txnotify), and + * 3. After a TX timeout to restart the sending process + * (mrf24j40_txtimeout_csma). + * + * Parameters: + * radio - Reference to the radio driver state structure + * + * Returned Value: + * None + * + * Assumptions: + * + ****************************************************************************/ + +static void mrf24j40_dopoll_csma(FAR void *arg) +{ + FAR struct mrf24j40_radio_s *dev = (FAR struct mrf24j40_radio_s *)arg; + int len = 0; + + /* Get exclusive access to the driver */ + + while (sem_wait(&dev->exclsem) != 0) { } + + /* If this a CSMA transaction and we have room in the CSMA fifo */ + + if (!dev->csma_busy) + { + wlinfo("Polling for frame\n"); + len = dev->radiocb->poll(dev->radiocb, false, &dev->csma_desc); + + if (len > 0) + { + wlinfo("Frame received. Frame length: %d\n", len); + + /* Now the txdesc is in use */ + + dev->csma_busy = 1; + + /* Setup the transaction on the device in the CSMA FIFO */ + + mrf24j40_norm_setup(dev, dev->csma_desc->frame, true); + mrf24j40_norm_trigger(dev); + } + } + + sem_post(&dev->exclsem); +} + +/**************************************************************************** + * Function: mrf24j40_dopoll_gts + * + * Description: + * This function is called in order to preform an out-of-sequence TX poll. + * This is done: + * + * 1. After completion of a transmission (mrf24j40_txdone_gts), + * 2. When new TX data is available (mrf24j40_txnotify), and + * 3. After a TX timeout to restart the sending process + * (mrf24j40_txtimeout_gts). + * + * Parameters: + * arg - Reference to the radio driver state structure + * + * Returned Value: + * None + * + * Assumptions: + * + ****************************************************************************/ + +static void mrf24j40_dopoll_gts(FAR void *arg) +{ + FAR struct mrf24j40_radio_s *dev = (FAR struct mrf24j40_radio_s *)arg; + int gts = 0; + int len = 0; + + /* Get exclusive access to the driver */ + + while (sem_wait(&dev->exclsem) != 0) { } + + for (gts = 0; gts < MRF24J40_GTS_SLOTS; gts++) + { + if (!dev->gts_busy[gts]) + { + len = dev->radiocb->poll(dev->radiocb, true, &dev->gts_desc[gts]); + + if (len > 0) + { + /* Now the txdesc is in use */ + + dev->gts_busy[gts]= 1; + + /* Setup the transaction on the device in the open GTS FIFO */ + + mrf24j40_gts_setup(dev, gts, dev->gts_desc[gts]->frame); + } + } + } + + sem_post(&dev->exclsem); +} + +/**************************************************************************** + * Name: mrf24j40_spi_lock + * + * Description: + * Acquire exclusive access to the shared SPI bus. + * + ****************************************************************************/ + +static void mrf24j40_spi_lock(FAR struct spi_dev_s *spi) +{ + SPI_LOCK(spi, 1); + SPI_SETBITS(spi, 8); + SPI_SETMODE(spi, CONFIG_IEEE802154_MRF24J40_SPIMODE); + SPI_SETFREQUENCY(spi, CONFIG_IEEE802154_MRF24J40_FREQUENCY); +} + +/**************************************************************************** + * Name: mrf24j40_spi_unlock + * + * Description: + * Release exclusive access to the shared SPI bus. + * + ****************************************************************************/ + +static inline void mrf24j40_spi_unlock(FAR struct spi_dev_s *spi) +{ + SPI_LOCK(spi,0); +} + +/**************************************************************************** + * Name: mrf24j40_setreg + * + * Description: + * Define the value of an MRF24J40 device register + * + ****************************************************************************/ + +static void mrf24j40_setreg(FAR struct spi_dev_s *spi, uint32_t addr, + uint8_t val) +{ + uint8_t buf[3]; + int len; + + if (!(addr&0x80000000)) + { + addr &= 0x3F; /* 6-bit address */ + addr <<= 1; + addr |= 0x01; /* writing */ + buf[0] = addr; + len = 1; + } + else + { + addr &= 0x3FF; /* 10-bit address */ + addr <<= 5; + addr |= 0x8010; /* writing long */ + buf[0] = (addr >> 8); + buf[1] = (addr & 0xFF); + len = 2; + } + + buf[len++] = val; + + mrf24j40_spi_lock(spi); + SPI_SELECT(spi, SPIDEV_IEEE802154(0), true); + SPI_SNDBLOCK(spi, buf, len); + SPI_SELECT(spi, SPIDEV_IEEE802154(0), false); + mrf24j40_spi_unlock(spi); +} + +/**************************************************************************** + * Name: mrf24j40_getreg + * + * Description: + * Return the value of an MRF24J40 device register* + * + ****************************************************************************/ + +static uint8_t mrf24j40_getreg(FAR struct spi_dev_s *spi, uint32_t addr) +{ + uint8_t buf[3]; + uint8_t rx[3]; + int len; + + if (!(addr&0x80000000)) + { + /* 6-bit address */ + + addr &= 0x3F; + addr <<= 1; + buf[0] = addr; + len = 1; + } + else + { + /* 10-bit address */ + + addr &= 0x3FF; + addr <<= 5; + addr |= 0x8000; + buf[0] = (addr >> 8); + buf[1] = (addr & 0xFF); + len = 2; + } + + buf[len++] = 0xFF; /* dummy */ + + mrf24j40_spi_lock (spi); + SPI_SELECT (spi, SPIDEV_IEEE802154(0), true); + SPI_EXCHANGE (spi, buf, rx, len); + SPI_SELECT (spi, SPIDEV_IEEE802154(0), false); + mrf24j40_spi_unlock(spi); + + /* wlinfo("r[%04X]=%02X\n", addr, rx[len - 1]); */ + return rx[len - 1]; +} + +/**************************************************************************** + * Name: mrf24j40_resetrfsm + * + * Description: + * Reset the RF state machine. Required at boot, after channel change, + * and probably after PA settings. + * + ****************************************************************************/ + +static int mrf24j40_resetrfsm(FAR struct mrf24j40_radio_s *dev) +{ + uint8_t reg; + + reg = mrf24j40_getreg(dev->spi, MRF24J40_RFCTL); + reg |= 0x04; + mrf24j40_setreg(dev->spi, MRF24J40_RFCTL, reg); + + reg &= ~0x04; + mrf24j40_setreg(dev->spi, MRF24J40_RFCTL, reg); + up_udelay(200); + + return OK; +} + +/**************************************************************************** + * Name: mrf24j40_setorder + * + * Description: + * Configures the timers and sets the ORDER register + ****************************************************************************/ + +static void mrf24j40_setorder(FAR struct mrf24j40_radio_s *dev, uint8_t bo, + uint8_t so) +{ + uint32_t maincnt = 0; + uint32_t slpcal = 0; + + /* Calibrate the Sleep Clock (SLPCLK) frequency. Refer to Section 3.15.1.2 + * “Sleep Clock Calibration”. + */ + + /* If the Sleep Clock Selection, SLPCLKSEL (0x207<7:6), is the internal + * oscillator (100 kHz), set SLPCLKDIV to a minimum value of 0x01. + */ + + mrf24j40_setreg(dev->spi, MRF24J40_SLPCON1, 0x01); + + /* Select the source of SLPCLK (internal 100kHz) */ + + mrf24j40_setreg(dev->spi, MRF24J40_RFCON7, MRF24J40_RFCON7_SEL_100KHZ); + + /* Begin calibration by setting the SLPCALEN bit (SLPCAL2 0x20B<4>) to + * ‘1’. Sixteen samples of the SLPCLK are counted and stored in the + * SLPCAL register. No need to mask, this is the only writable bit + */ + + mrf24j40_setreg(dev->spi, MRF24J40_SLPCAL2, MRF24J40_SLPCAL2_SLPCALEN); + + /* Calibration is complete when the SLPCALRDY bit (SLPCAL2 0x20B<7>) is + * set to ‘1’. + */ + + while (!(mrf24j40_getreg(dev->spi, MRF24J40_SLPCAL2) & + MRF24J40_SLPCAL2_SLPCALRDY)) + { + usleep(1); + } + + slpcal = mrf24j40_getreg(dev->spi, MRF24J40_SLPCAL0); + slpcal |= (mrf24j40_getreg(dev->spi, MRF24J40_SLPCAL1) << 8); + slpcal |= ((mrf24j40_getreg(dev->spi, MRF24J40_SLPCAL2) << 16) & 0x0F); + + /* Program the Beacon Interval into the Main Counter, MAINCNT (0x229<1:0>, + * 0x228, 0x227, 0x226), and Remain Counter, REMCNT (0x225, 0x224), + * according to BO and SO values. Refer to Section 3.15.1.3 “Sleep Mode + * Counters” + */ + + + mrf24j40_setreg(dev->spi, MRF24J40_REMCNTL, (MRF24J40_REMCNT & 0xFF)); + mrf24j40_setreg(dev->spi, MRF24J40_REMCNTH, ((MRF24J40_REMCNT >> 8) & 0xFF)); + + maincnt = MRF24J40_MAINCNT(bo, (slpcal * 50 / 16)); + + mrf24j40_setreg(dev->spi, MRF24J40_MAINCNT0, (maincnt & 0xFF)); + mrf24j40_setreg(dev->spi, MRF24J40_MAINCNT1, ((maincnt >> 8) & 0xFF)); + mrf24j40_setreg(dev->spi, MRF24J40_MAINCNT2, ((maincnt >> 16) & 0xFF)); + mrf24j40_setreg(dev->spi, MRF24J40_MAINCNT3, ((maincnt >> 24) & 0x03)); + + /* Configure the BO (ORDER 0x10<7:4>) and SO (ORDER 0x10<3:0>) values. + * After configuring BO and SO, the beacon frame will be sent immediately. + */ + + mrf24j40_setreg(dev->spi, MRF24J40_ORDER, ((bo << 4) & 0xF0) | (so & 0x0F)); +} + +/**************************************************************************** + * Name: mrf24j40_pacontrol + * + * Description: + * Control the external LNA/PA on the MRF24J40MB/MC/MD/ME modules + * GPIO 1: PA enable + * GPIO 2: LNA enable + * GPIO 3: PA power enable (not required on MB) + ****************************************************************************/ + +static int mrf24j40_pacontrol(FAR struct mrf24j40_radio_s *dev, int mode) +{ + if (!dev->paenabled) + { + return OK; + } + + if (mode == MRF24J40_PA_AUTO) + { + mrf24j40_setreg(dev->spi, MRF24J40_TRISGPIO, 0x08); + mrf24j40_setreg(dev->spi, MRF24J40_GPIO , 0x08); + mrf24j40_setreg(dev->spi, MRF24J40_TESTMODE, 0x0F); + } + else if (mode == MRF24J40_PA_ED) + { + mrf24j40_setreg(dev->spi, MRF24J40_TESTMODE, 0x08); + mrf24j40_setreg(dev->spi, MRF24J40_TRISGPIO, 0x0F); + mrf24j40_setreg(dev->spi, MRF24J40_GPIO , 0x0C); + } + else if (mode == MRF24J40_PA_SLEEP) + { + mrf24j40_setreg(dev->spi, MRF24J40_TESTMODE, 0x08); + mrf24j40_setreg(dev->spi, MRF24J40_TRISGPIO, 0x0F); + mrf24j40_setreg(dev->spi, MRF24J40_GPIO , 0x00); + } + else + { + return -EINVAL; + } + + mrf24j40_resetrfsm(dev); + return OK; +} + +/**************************************************************************** + * Name: mrf24j40_setrxmode + * + * Description: + * Set the RX mode (normal, promiscuous, no CRC) + * + ****************************************************************************/ + +static int mrf24j40_setrxmode(FAR struct mrf24j40_radio_s *dev, int mode) +{ + uint8_t reg; + + if (mode < MRF24J40_RXMODE_NORMAL || mode > MRF24J40_RXMODE_NOCRC) + { + return -EINVAL; + } + + reg = mrf24j40_getreg(dev->spi, MRF24J40_RXMCR); + reg &= ~0x03; + reg |= mode; + + /* Set mode options */ + + if (mode != MRF24J40_RXMODE_NORMAL) + { + /* Promisc and error modes: Disable auto ACK */ + + reg |= MRF24J40_RXMCR_NOACKRSP; + } + else + { + /* Normal mode : enable auto-ACK */ + + reg &= ~MRF24J40_RXMCR_NOACKRSP; + } + + mrf24j40_setreg(dev->spi, MRF24J40_RXMCR, reg); + + dev->rxmode = mode; + wlinfo("%u\n", (unsigned)mode); + return OK; +} + +/**************************************************************************** + * Name: mrf24j40_setchannel + * + * Description: + * Define the current radio channel the device is operating on. + * In the 2.4 GHz, there are 16 channels, each 2 MHz wide, 5 MHz spacing: + * Chan MHz Chan MHz Chan MHz Chan MHz + * 11 2405 15 2425 19 2445 23 2465 + * 12 2410 16 2430 20 2450 24 2470 + * 13 2415 17 2435 21 2455 25 2475 + * 14 2420 18 2440 22 2460 26 2480 + * + ****************************************************************************/ + +static int mrf24j40_setchannel(FAR struct mrf24j40_radio_s *dev, uint8_t chan) +{ + if (chan < 11 || chan > 26) + { + wlerr("ERROR: Invalid chan: %d\n",chan); + return -EINVAL; + } + + /* 15. Set channel – See Section 3.4 “Channel Selection”. */ + + mrf24j40_setreg(dev->spi, MRF24J40_RFCON0, (chan - 11) << 4 | 0x03); + + /* 17. RFCTL (0x36) = 0x04 – Reset RF state machine. + * 18. RFCTL (0x36) = 0x00. + */ + + mrf24j40_resetrfsm(dev); + + dev->chan = chan; + wlinfo("%u\n", (unsigned)chan); + + return OK; +} + +/**************************************************************************** + * Name: mrf24j40_setpanid + * + * Description: + * Define the PAN ID the device is operating on. + * + ****************************************************************************/ + +static int mrf24j40_setpanid(FAR struct mrf24j40_radio_s *dev, + FAR const uint8_t *panid) +{ + mrf24j40_setreg(dev->spi, MRF24J40_PANIDL, panid[0]); + mrf24j40_setreg(dev->spi, MRF24J40_PANIDH, panid[1]); + + IEEE802154_PANIDCOPY(dev->addr.panid, panid); + wlinfo("%02X:%02X\n", panid[0], panid[1]); + + return OK; +} + +/**************************************************************************** + * Name: mrf24j40_setsaddr + * + * Description: + * Define the device short address. The following addresses are special: + * FFFEh : Broadcast + * FFFFh : Unspecified + * + ****************************************************************************/ + +static int mrf24j40_setsaddr(FAR struct mrf24j40_radio_s *dev, + FAR const uint8_t *saddr) +{ + mrf24j40_setreg(dev->spi, MRF24J40_SADRL, saddr[0]); + mrf24j40_setreg(dev->spi, MRF24J40_SADRH, saddr[1]); + + IEEE802154_SADDRCOPY(dev->addr.saddr, saddr); + + wlinfo("%02X:%02X\n", saddr[0], saddr[1]); + return OK; +} + +/**************************************************************************** + * Name: mrf24j40_seteaddr + * + * Description: + * Define the device extended address. The following addresses are special: + * FFFFFFFFFFFFFFFFh : Unspecified + * + ****************************************************************************/ + +static int mrf24j40_seteaddr(FAR struct mrf24j40_radio_s *dev, + FAR const uint8_t *eaddr) +{ + int i; + + for (i = 0; i < 8; i++) + { + mrf24j40_setreg(dev->spi, MRF24J40_EADR0 + i, eaddr[i]); + dev->addr.eaddr[i] = eaddr[i]; + } + wlinfo("%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X\n", eaddr[0], eaddr[1], + eaddr[2], eaddr[3], eaddr[4], eaddr[5], eaddr[6], eaddr[7]); + + return OK; +} + +/**************************************************************************** + * Name: mrf24j40_setcoordsaddr + * + * Description: + * Define the coordinator short address. The following addresses are special: + * FFFEh : Broadcast + * FFFFh : Unspecified + * + ****************************************************************************/ + +static int mrf24j40_setcoordsaddr(FAR struct mrf24j40_radio_s *dev, + FAR const uint8_t *saddr) +{ + mrf24j40_setreg(dev->spi, MRF24J40_ASSOSADR0, saddr[0]); + mrf24j40_setreg(dev->spi, MRF24J40_ASSOSADR1, saddr[1]); + + IEEE802154_SADDRCOPY(dev->addr.saddr, saddr); + + wlinfo("%02X:%02X\n", saddr[0], saddr[1]); + return OK; +} + +/**************************************************************************** + * Name: mrf24j40_setcoordeaddr + * + * Description: + * Define the coordinator extended address. The following addresses are special: + * FFFFFFFFFFFFFFFFh : Unspecified + * + ****************************************************************************/ + +static int mrf24j40_setcoordeaddr(FAR struct mrf24j40_radio_s *dev, + FAR const uint8_t *eaddr) +{ + int i; + + for (i = 0; i < 8; i++) + { + mrf24j40_setreg(dev->spi, MRF24J40_ASSOEADR0 + i, eaddr[i]); + dev->addr.eaddr[i] = eaddr[i]; + } + + wlinfo("%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X\n", eaddr[0], eaddr[1], + eaddr[2], eaddr[3], eaddr[4], eaddr[5], eaddr[6], eaddr[7]); + return OK; +} + +/**************************************************************************** + * Name: mrf24j40_setdevmode + * + * Description: + * Define the device behaviour: normal end device or coordinator + * + ****************************************************************************/ + +static int mrf24j40_setdevmode(FAR struct mrf24j40_radio_s *dev, + uint8_t mode) +{ + int ret = OK; + uint8_t reg; + + /* Disable slotted mode until I decide to implement slotted mode */ + + reg = mrf24j40_getreg(dev->spi, MRF24J40_TXMCR); + reg &= ~MRF24J40_TXMCR_SLOTTED; + mrf24j40_setreg(dev->spi, MRF24J40_TXMCR, reg); + mrf24j40_setreg(dev->spi, MRF24J40_ORDER, 0xFF); + + /* Define dev mode */ + + reg = mrf24j40_getreg(dev->spi, MRF24J40_RXMCR); + + if (mode == MRF24J40_MODE_PANCOORD) + { + reg |= MRF24J40_RXMCR_PANCOORD; + reg &= ~MRF24J40_RXMCR_COORD; + } + else if (mode == MRF24J40_MODE_COORD) + { + reg |= MRF24J40_RXMCR_COORD; + reg &= ~MRF24J40_RXMCR_PANCOORD; + } + else if (mode == MRF24J40_MODE_DEVICE) + { + reg &= ~MRF24J40_RXMCR_PANCOORD; + reg &= ~MRF24J40_RXMCR_COORD; + } + else + { + return -EINVAL; + } + + mrf24j40_setreg(dev->spi, MRF24J40_RXMCR, reg); + dev->devmode = mode; + return ret; +} + +/**************************************************************************** + * Name: mrf24j40_settxpower + * + * Description: + * Define the transmit power. Value is passed in mBm, it is rounded to + * the nearest value. Some MRF modules have a power amplifier, this routine + * does not care about this. We only change the CHIP output power. + * + ****************************************************************************/ + +static int mrf24j40_settxpower(FAR struct mrf24j40_radio_s *dev, + int32_t txpwr) +{ + uint8_t reg; + int save_txpwr = txpwr; + + if (txpwr <= -3000 && txpwr > -3630) + { + reg = 0xC0; + txpwr += 3000; + } + else if (txpwr <= -2000) + { + reg = 0x80; + txpwr += 2000; + } + else if (txpwr <= -1000) + { + reg = 0x40; + txpwr += 1000; + } + else if (txpwr <= 0) + { + reg = 0x00; + } + else + { + return -EINVAL; + } + + wlinfo("Remaining attenuation: %d mBm\n",txpwr); + + switch(txpwr/100) + { + case -9: + case -8: + case -7: + case -6: + reg |= 0x07; + break; + + case -5: + reg |= 0x06; + break; + + case -4: + reg |= 0x05; + break; + + case -3: + reg |= 0x04; + break; + + case -2: + reg |= 0x03; + break; + + case -1: + reg |= 0x02; + + break; + + + + case 0: + + reg |= 0x00; /* value 0x01 is 0.5 db, not used */ + + break; + + + + default: + + return -EINVAL; + + } + + + + mrf24j40_setreg(dev->spi, MRF24J40_RFCON3, reg); + + dev->txpower = save_txpwr; + + return OK; + +} + + + +/**************************************************************************** + + * Name: mrf24j40_setcca + + * + + * Description: + + * Define the Clear Channel Assessement method. + + * + + ****************************************************************************/ + + + +static int mrf24j40_setcca(FAR struct mrf24j40_radio_s *dev, + + FAR struct ieee802154_cca_s *cca) + +{ + + uint8_t mode; + + + + if (!cca->use_ed && !cca->use_cs) + + { + + return -EINVAL; + + } + + + + if (cca->use_cs && cca->csth > 0x0f) + + { + + return -EINVAL; + + } + + + + mode = mrf24j40_getreg(dev->spi, MRF24J40_BBREG2); + + mode &= 0x03; + + + + if (cca->use_ed) + + { + + mode |= MRF24J40_BBREG2_CCAMODE_ED; + + mrf24j40_setreg(dev->spi, MRF24J40_CCAEDTH, cca->edth); + + } + + + + if (cca->use_cs) + + { + + mode |= MRF24J40_BBREG2_CCAMODE_CS; + + mode |= cca->csth << 2; + + } + + + + mrf24j40_setreg(dev->spi, MRF24J40_BBREG2, mode); + + + + memcpy(&dev->cca, cca, sizeof(struct ieee802154_cca_s)); + + return OK; + +} + + + +/**************************************************************************** + + * Name: mrf24j40_regdump + + * + + * Description: + + * Display the value of all registers. + + * + + ****************************************************************************/ + + + +static int mrf24j40_regdump(FAR struct mrf24j40_radio_s *dev) + +{ + + uint32_t i; + + char buf[4+16*3+2+1]; + + int len = 0; + + + + wlinfo("Short regs:\n"); + + + + for (i = 0; i < 0x40; i++) + + { + + if ((i & 15) == 0) + + { + + len=sprintf(buf, "%02x: ",i&0xFF); + + } + + + + len += sprintf(buf+len, "%02x ", mrf24j40_getreg(dev->spi, i)); + + if ((i & 15) == 15) + + { + + sprintf(buf+len, "\n"); + + wlinfo("%s", buf); + + } + + } + + + + wlinfo("Long regs:\n"); + + for (i = 0x80000200; i < 0x80000250; i++) + + { + + if ((i & 15) == 0) + + { + + len=sprintf(buf, "%02x: ",i&0xFF); + + } + + + + len += sprintf(buf+len, "%02x ", mrf24j40_getreg(dev->spi, i)); + + if ((i & 15) == 15) + + { + + sprintf(buf+len, "\n"); + + wlinfo("%s", buf); + + } + + } + + + + return 0; + +} + + + +/**************************************************************************** + + * Name: mrf24j40_energydetect + + * + + * Description: + + * Measure the RSSI level for the current channel. + + * + + ****************************************************************************/ + + + +static int mrf24j40_energydetect(FAR struct mrf24j40_radio_s *dev, + + FAR uint8_t *energy) + +{ + + uint8_t reg; + + + + /* Manually enable the LNA*/ + + + + mrf24j40_pacontrol(dev, MRF24J40_PA_ED); + + + + /* Set RSSI average duration to 8 symbols */ + + + + reg = mrf24j40_getreg(dev->spi, MRF24J40_TXBCON1); + + reg |= 0x30; + + mrf24j40_setreg(dev->spi, MRF24J40_TXBCON1, reg); + + + + /* 1. Set RSSIMODE1 0x3E<7> – Initiate RSSI calculation. */ + + + + mrf24j40_setreg(dev->spi, MRF24J40_BBREG6, 0x80); + + + + /* 2. Wait until RSSIRDY 0x3E<0> is set to ‘1’ – RSSI calculation is + + * complete. + + */ + + + + while(!(mrf24j40_getreg(dev->spi, MRF24J40_BBREG6) & 0x01)); + + + + /* 3. Read RSSI 0x210<7:0> – The RSSI register contains the averaged RSSI + + * received power level for 8 symbol periods. + + */ + + + + *energy = mrf24j40_getreg(dev->spi, MRF24J40_RSSI); + + + + mrf24j40_setreg(dev->spi, MRF24J40_BBREG6, 0x40); + + + + /* Back to automatic control */ + + + + mrf24j40_pacontrol(dev, MRF24J40_PA_AUTO); + + return OK; + +} + + + +/**************************************************************************** + + * Name: mrf24j40_norm_setup + + * + + * Description: + + * Setup a transaction in the normal TX FIFO + + * + + ****************************************************************************/ + + + +static void mrf24j40_norm_setup(FAR struct mrf24j40_radio_s *dev, + + FAR struct iob_s *frame, bool csma) + +{ + + uint8_t reg; + + + + /* Enable tx int */ + + + + reg = mrf24j40_getreg(dev->spi, MRF24J40_INTCON); + + reg &= ~MRF24J40_INTCON_TXNIE; + + mrf24j40_setreg(dev->spi, MRF24J40_INTCON, reg); + + + + /* Enable/Disable CSMA mode */ + + + + reg = mrf24j40_getreg(dev->spi, MRF24J40_TXMCR); + + + + if (csma) + + { + + reg &= ~MRF24J40_TXMCR_NOCSMA; + + } + + else + + { + + reg |= MRF24J40_TXMCR_NOCSMA; + + } + + + + mrf24j40_setreg(dev->spi, MRF24J40_TXMCR, reg); + + + + /* Setup the FIFO */ + + + + mrf24j40_setup_fifo(dev, frame->io_data, frame->io_len, MRF24J40_TXNORM_FIFO); + + + + /* If the frame control field contains an acknowledgment request, set the + + * TXNACKREQ bit. See IEEE 802.15.4/2003 7.2.1.1 page 112 for info. + + */ + + + + reg = mrf24j40_getreg(dev->spi, MRF24J40_TXNCON); + + + + if (frame->io_data[0] & IEEE802154_FRAMECTRL_ACKREQ) + + { + + reg |= MRF24J40_TXNCON_TXNACKREQ; + + } + + else + + { + + reg &= ~MRF24J40_TXNCON_TXNACKREQ; + + } + + + + mrf24j40_setreg(dev->spi, MRF24J40_TXNCON, reg); + +} + + + +/**************************************************************************** + + * Name: mrf24j40_norm_trigger + + * + + * Description: + + * Trigger the normal TX FIFO + + * + + ****************************************************************************/ + + + +static inline void mrf24j40_norm_trigger(FAR struct mrf24j40_radio_s *dev) + +{ + + uint8_t reg; + + + + reg = mrf24j40_getreg(dev->spi, MRF24J40_TXNCON); + + + + reg |= MRF24J40_TXNCON_TXNTRIG; + + + + mrf24j40_setreg(dev->spi, MRF24J40_TXNCON, reg); + +} + + + +/**************************************************************************** + + * Name: mrf24j40_beacon_trigger + + * + + * Description: + + * Trigger the beacon TX FIFO + + * + + ****************************************************************************/ + + + +static inline void mrf24j40_beacon_trigger(FAR struct mrf24j40_radio_s *dev) +{ + uint8_t reg; + + reg = mrf24j40_getreg(dev->spi, MRF24J40_TXBCON0); + + reg |= MRF24J40_TXBCON0_TXBTRIG; + + mrf24j40_setreg(dev->spi, MRF24J40_TXBCON0, reg); +} + +/**************************************************************************** + * Name: mrf24j40_gts_setup + * + * Description: + * Setup a GTS transaction in one of the GTS FIFOs + * + ****************************************************************************/ + +static void mrf24j40_gts_setup(FAR struct mrf24j40_radio_s *dev, uint8_t fifo, + FAR struct iob_s *frame) +{ + +} + +/**************************************************************************** + * Name: mrf24j40_setup_fifo + * + * Description: + * + ****************************************************************************/ + +static void mrf24j40_setup_fifo(FAR struct mrf24j40_radio_s *dev, + FAR const uint8_t *buf, uint8_t length, + uint32_t fifo_addr) +{ + + int hlen = 3; /* Include frame control and seq number */ + int i; + uint16_t frame_ctrl; + + /* Analyze frame control to compute header length */ + + frame_ctrl = buf[0]; + frame_ctrl |= (buf[1] << 8); + + if ((frame_ctrl & IEEE802154_FRAMECTRL_DADDR)== IEEE802154_ADDRMODE_SHORT) + { + hlen += 2 + 2; /* Destination PAN + shortaddr */ + } + else if ((frame_ctrl & IEEE802154_FRAMECTRL_DADDR) == IEEE802154_ADDRMODE_EXTENDED) + { + hlen += 2 + 8; /* Destination PAN + extaddr */ + } + + if (!(frame_ctrl & IEEE802154_FRAMECTRL_PANIDCOMP)) + { + hlen += 2; /* No PAN compression, source PAN is different from dest PAN */ + } + + if ((frame_ctrl & IEEE802154_FRAMECTRL_SADDR)== IEEE802154_ADDRMODE_SHORT) + { + hlen += 2; /* Source saddr */ + } + else if ((frame_ctrl & IEEE802154_FRAMECTRL_SADDR) == IEEE802154_ADDRMODE_EXTENDED) + { + hlen += 8; /* Ext saddr */ + } + + /* Header len, 0, TODO for security modes */ + + mrf24j40_setreg(dev->spi, fifo_addr++, hlen); + + + /* Frame length */ + + mrf24j40_setreg(dev->spi, fifo_addr++, length); + + /* Frame data */ + + for (i = 0; i < length; i++) + { + mrf24j40_setreg(dev->spi, fifo_addr++, buf[i]); + } +} + +/**************************************************************************** + * Name: mrf24j40_irqwork_txnorm + * + * Description: + * Manage completion of packet transmission. + * + ****************************************************************************/ + +static void mrf24j40_irqwork_txnorm(FAR struct mrf24j40_radio_s *dev) +{ + uint8_t reg; + enum ieee802154_status_e status; + bool framepending; + + /* Disable tx int */ + + reg = mrf24j40_getreg(dev->spi, MRF24J40_INTCON); + reg |= MRF24J40_INTCON_TXNIE; + mrf24j40_setreg(dev->spi, MRF24J40_INTCON, reg); + + /* Get the status from the device and copy the status into the tx desc. + * The status for the normal FIFO is represented with bit TXNSTAT where + * 0=success, 1= failure. + */ + + reg = mrf24j40_getreg(dev->spi, MRF24J40_TXSTAT); + + /* TXNSTAT = 0: Transmission was successful + * TXNSTAT = 1: Transmission failed, retry count exceeded + */ + + if (reg & MRF24J40_TXSTAT_TXNSTAT) + { + /* The number of retries of the most recent transmission is contained in the + * TXNRETRY (TXSTAT 0x24<7:6>) bits. The CCAFAIL (TXSTAT 0x24<5>) bit = 1 + * indicates if the failed transmission was due to the channel busy + * (CSMA-CA timed out). + */ + + if (reg & MRF24J40_TXSTAT_CCAFAIL) + { + status = IEEE802154_STATUS_CHANNEL_ACCESS_FAILURE; + } + else + { + status = IEEE802154_STATUS_NO_ACK; + } + } + else + { + status = IEEE802154_STATUS_SUCCESS; + } + + framepending = (mrf24j40_getreg(dev->spi, MRF24J40_TXNCON) & + MRF24J40_TXNCON_FPSTAT); + + if (dev->txdelayed_busy) + + { + /* Inform the next layer of the transmission success/failure */ + + dev->txdelayed_desc->conf->status = status; + dev->txdelayed_desc->framepending = framepending; + dev->radiocb->txdone(dev->radiocb, dev->txdelayed_desc); + + dev->txdelayed_busy = false; + + if (dev->reschedule_csma) + { + mrf24j40_norm_setup(dev, dev->csma_desc->frame, true); + mrf24j40_norm_trigger(dev); + dev->reschedule_csma = false; + } + } + else + { + /* Inform the next layer of the transmission success/failure */ + + dev->csma_desc->conf->status = status; + dev->csma_desc->framepending = framepending; + dev->radiocb->txdone(dev->radiocb, dev->csma_desc); + + /* We are now done with the transaction */ + + dev->csma_busy = 0; + + /* Must unlock the radio before calling poll */ + + sem_post(&dev->exclsem); + mrf24j40_dopoll_csma(dev); + while (sem_wait(&dev->exclsem) != 0) { } + } +} + +/**************************************************************************** + * Name: mrf24j40_irqwork_gts + * + * Description: + * Manage completion of packet transmission. + * + ****************************************************************************/ + +static void mrf24j40_irqwork_txgts(FAR struct mrf24j40_radio_s *dev, + uint8_t gts) +{ + uint8_t txstat; + + /* Disable tx int */ + + txstat = mrf24j40_getreg(dev->spi, MRF24J40_INTCON); + txstat |= MRF24J40_INTCON_TXNIE; + mrf24j40_setreg(dev->spi, MRF24J40_INTCON, txstat); + + /* Get the status from the device and copy the status into the tx desc. + * The status for the normal FIFO is represented with bit TXNSTAT where + * 0=success, 1= failure. + */ + + txstat = mrf24j40_getreg(dev->spi, MRF24J40_TXSTAT); + + if (gts == 0) + { + dev->csma_desc->conf->status = txstat & MRF24J40_TXSTAT_TXG1STAT; + } + else if (gts == 1) + { + dev->csma_desc->conf->status = txstat & MRF24J40_TXSTAT_TXG2STAT; + } + + /* Inform the next layer of the transmission success/failure */ + + dev->radiocb->txdone(dev->radiocb, dev->gts_desc[gts]); + + /* We are now done with the transaction */ + + dev->gts_busy[gts]= 0; + + mrf24j40_dopoll_gts(dev); +} + +/**************************************************************************** + * Name: mrf24j40_rxenable + * + * Description: + * Enable/Disable receiver. + * + ****************************************************************************/ + +static int mrf24j40_rxenable(FAR struct ieee802154_radio_s *radio, bool enable) +{ + FAR struct mrf24j40_radio_s *dev = (FAR struct mrf24j40_radio_s *)radio; + uint8_t reg; + + dev->rxenabled = enable; + + + if (enable) + { + /* Disable packet reception. See pg. 109 of datasheet */ + + mrf24j40_setreg(dev->spi, MRF24J40_BBREG1, MRF24J40_BBREG1_RXDECINV); + + /* Enable rx int */ + + reg = mrf24j40_getreg(dev->spi, MRF24J40_INTCON); + reg &= ~MRF24J40_INTCON_RXIE; + mrf24j40_setreg(dev->spi, MRF24J40_INTCON, reg); + + /* Purge the RX buffer */ + + reg = mrf24j40_getreg(dev->spi, MRF24J40_RXFLUSH); + reg |= MRF24J40_RXFLUSH_RXFLUSH; + mrf24j40_setreg(dev->spi, MRF24J40_RXFLUSH, reg); + + /* Re-enable packet reception. See pg. 109 of datasheet */ + + mrf24j40_setreg(dev->spi, MRF24J40_BBREG1, 0); + } + else + { + /* Disable rx int */ + + reg = mrf24j40_getreg(dev->spi, MRF24J40_INTCON); + reg |= MRF24J40_INTCON_RXIE; + mrf24j40_setreg(dev->spi, MRF24J40_INTCON, reg); + } + + return OK; +} + +/**************************************************************************** + * Name: mrf24j40_irqwork_rx + * + * Description: + * Manage packet reception. + * + ****************************************************************************/ + +static void mrf24j40_irqwork_rx(FAR struct mrf24j40_radio_s *dev) + +{ + FAR struct ieee802154_data_ind_s *ind; + uint32_t addr; + uint32_t index; + uint8_t reg; + + wlinfo("RX interrupt\n"); + + /* Disable rx int */ + + reg = mrf24j40_getreg(dev->spi, MRF24J40_INTCON); + reg |= MRF24J40_INTCON_RXIE; + mrf24j40_setreg(dev->spi, MRF24J40_INTCON, reg); + + /* Disable packet reception. See pg. 109 of datasheet */ + + mrf24j40_setreg(dev->spi, MRF24J40_BBREG1, MRF24J40_BBREG1_RXDECINV); + + /* Allocate a data_ind to put the frame in */ + + ind = ieee802154_ind_allocate(); + if (ind == NULL) + { + wlerr("ERROR: Unable to allocate data_ind. Discarding frame\n"); + goto done; + } + + /* Read packet */ + + addr = MRF24J40_RXBUF_BASE; + + ind->frame->io_len = mrf24j40_getreg(dev->spi, addr++); + + for (index = 0; index < ind->frame->io_len; index++) + { + ind->frame->io_data[index] = mrf24j40_getreg(dev->spi, addr++); + } + + ind->lqi = mrf24j40_getreg(dev->spi, addr++); + ind->rssi = mrf24j40_getreg(dev->spi, addr++); + + /* Reduce len by 2, we only receive frames with correct crc, no check + * required. + */ + + ind->frame->io_len -= 2; + + /* Callback the receiver in the next highest layer */ + + dev->radiocb->rxframe(dev->radiocb, ind); + +done: + /* Enable reception of next packet by flushing the fifo. + * This is an MRF24J40 errata (no. 1). + */ + + mrf24j40_setreg(dev->spi, MRF24J40_RXFLUSH, 1); + + /* Only enable RX interrupt if we are to be listening when IDLE */ + + if (dev->rxenabled) + { + /* Enable packet reception */ + + mrf24j40_setreg(dev->spi, MRF24J40_BBREG1, 0); + + reg = mrf24j40_getreg(dev->spi, MRF24J40_INTCON); + reg &= ~MRF24J40_INTCON_RXIE; + mrf24j40_setreg(dev->spi, MRF24J40_INTCON, reg); + } +} + +/**************************************************************************** + * Name: mrf24j40_irqworker + * + * Description: + * Perform interrupt handling logic outside of the interrupt handler (on + * the work queue thread). + * + * Parameters: + * arg - The reference to the driver structure (cast to void*) + * + * Returned Value: + * None + * + * Assumptions: + * + ****************************************************************************/ + +static void mrf24j40_irqworker(FAR void *arg) +{ + FAR struct mrf24j40_radio_s *dev = (FAR struct mrf24j40_radio_s *)arg; + uint8_t intstat; + uint8_t reg; + + DEBUGASSERT(dev); + DEBUGASSERT(dev->spi); + + /* Get exclusive access to the driver */ + + while (sem_wait(&dev->exclsem) != 0) { } + + /* Read and store INTSTAT - this clears the register. */ + + intstat = mrf24j40_getreg(dev->spi, MRF24J40_INTSTAT); + + /* Do work according to the pending interrupts */ + + if ((intstat & MRF24J40_INTSTAT_HSYMTMRIF)) + { + /* As of now the only use for the MAC timer is for delayed transactions. + * Therefore, all we do here is trigger the TX norm FIFO + */ + + mrf24j40_norm_trigger(dev); + + /* Timers are one-shot, so disable the interrupt */ + + reg = mrf24j40_getreg(dev->spi, MRF24J40_INTCON); + reg |= MRF24J40_INTCON_HSYMTMRIE; + mrf24j40_setreg(dev->spi, MRF24J40_INTCON, reg); + } + + if ((intstat & MRF24J40_INTSTAT_RXIF) && dev->rxenabled) + { + /* A packet was received, retrieve it */ + + mrf24j40_irqwork_rx(dev); + } + + if ((intstat & MRF24J40_INTSTAT_TXNIF)) + { + /* A packet was transmitted or failed*/ + + mrf24j40_irqwork_txnorm(dev); + } + + if ((intstat & MRF24J40_INTSTAT_TXG1IF)) + { + /* A packet was transmitted or failed*/ + + mrf24j40_irqwork_txgts(dev, 0); + } + + if ((intstat & MRF24J40_INTSTAT_TXG1IF)) + { + /* A packet was transmitted or failed*/ + + mrf24j40_irqwork_txgts(dev, 1); + } + + if ((intstat & MRF24J40_INTSTAT_SLPIF)) + { + dev->radiocb->sfevent(dev->radiocb, IEEE802154_SFEVENT_ENDOFACTIVE); + + /* Acknowledge the alert and put the device to sleep */ + + reg = mrf24j40_getreg(dev->spi, MRF24J40_SLPACK); + reg |= MRF24J40_SLPACK_SLPACK; + mrf24j40_setreg(dev->spi, MRF24J40_SLPACK, reg); + } + + if ((intstat & MRF24J40_INTSTAT_WAKEIF)) + { + wlinfo("Wake Interrupt\n"); + /* This is right before the beacon, we set the bsn here, since the MAC + * uses the SLPIF (end of active portion of superframe). to make any + * changes to the beacon. This assumes that any changes to the beacon + * be in by the time that this interrupt fires. + */ + + mrf24j40_setreg(dev->spi, MRF24J40_BEACON_FIFO + 4, dev->bsn++); + mrf24j40_beacon_trigger(dev); + } + + /* Unlock the radio device */ + + sem_post(&dev->exclsem); + + /* Re-enable GPIO interrupts */ + + dev->lower->enable(dev->lower, true); +} + +/**************************************************************************** + * Name: mrf24j40_interrupt + * + * Description: + * Hardware interrupt handler + * + * Parameters: + * irq - Number of the IRQ that generated the interrupt + * context - Interrupt register state save info (architecture-specific) + * + * Returned Value: + * OK on success + * + * Assumptions: + * + ****************************************************************************/ + +static int mrf24j40_interrupt(int irq, FAR void *context, FAR void *arg) +{ + FAR struct mrf24j40_radio_s *dev = (FAR struct mrf24j40_radio_s *)arg; + + DEBUGASSERT(dev != NULL); + + /* In complex environments, we cannot do SPI transfers from the interrupt + * handler because semaphores are probably used to lock the SPI bus. In + * this case, we will defer processing to the worker thread. This is also + * much kinder in the use of system resources and is, therefore, probably + * a good thing to do in any event. + */ + + DEBUGASSERT(work_available(&dev->irqwork)); + + /* Notice that further GPIO interrupts are disabled until the work is + * actually performed. This is to prevent overrun of the worker thread. + * Interrupts are re-enabled in enc_irqworker() when the work is completed. + */ + + dev->lower->enable(dev->lower, false); + return work_queue(HPWORK, &dev->irqwork, mrf24j40_irqworker, (FAR void *)dev, 0); +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: mrf24j40_init + * + * Description: + * Return an mrf24j40 device for use by other drivers. + * + ****************************************************************************/ + +FAR struct ieee802154_radio_s *mrf24j40_init(FAR struct spi_dev_s *spi, + FAR const struct mrf24j40_lower_s *lower) +{ + FAR struct mrf24j40_radio_s *dev; + + dev = kmm_zalloc(sizeof(struct mrf24j40_radio_s)); + if (dev == NULL) + { + return NULL; + } + + /* Attach irq */ + + if (lower->attach(lower, mrf24j40_interrupt, dev) != OK) + { +#if 0 + free(dev); +#endif + return NULL; + } + + /* Allow exclusive access to the privmac struct */ + + sem_init(&dev->exclsem, 0, 1); + + dev->radio.bind = mrf24j40_bind; + dev->radio.reset = mrf24j40_reset; + dev->radio.getattr = mrf24j40_getattr; + dev->radio.setattr = mrf24j40_setattr; + dev->radio.txnotify = mrf24j40_txnotify; + dev->radio.txdelayed = mrf24j40_txdelayed; + dev->radio.rxenable = mrf24j40_rxenable; + dev->radio.beaconstart = mrf24j40_beaconstart; + dev->radio.beaconupdate = mrf24j40_beaconupdate; + dev->radio.beaconstop = mrf24j40_beaconstop; + dev->radio.sfupdate = mrf24j40_sfupdate; + + dev->lower = lower; + dev->spi = spi; + + mrf24j40_reset(&dev->radio); + + dev->lower->enable(dev->lower, true); + return &dev->radio; +} + diff --git a/drivers/wireless/ieee802154/mrf24j40.h b/drivers/wireless/ieee802154/mrf24j40/mrf24j40.h similarity index 94% rename from drivers/wireless/ieee802154/mrf24j40.h rename to drivers/wireless/ieee802154/mrf24j40/mrf24j40.h index 915669a144..56b5716d1c 100644 --- a/drivers/wireless/ieee802154/mrf24j40.h +++ b/drivers/wireless/ieee802154/mrf24j40/mrf24j40.h @@ -1,5 +1,5 @@ /**************************************************************************** - * drivers/wireless/ieee802154/mrf24j40.h + * drivers/wireless/ieee802154/mrf24j40/mrf24j40.h * * Copyright (C) 2015-2016 Sebastien Lorquet. All rights reserved. * Author: Sebastien Lorquet @@ -33,8 +33,8 @@ * ****************************************************************************/ -#ifndef __DRIVERS_WIRELESS_IEEE802154_MRF24J40_H -#define __DRIVERS_WIRELESS_IEEE802154_MRF24J40_H +#ifndef __DRIVERS_WIRELESS_IEEE802154_MRF24J40_MRF24J40_H +#define __DRIVERS_WIRELESS_IEEE802154_MRF24J40_MRF24J40_H /* MRF24J40 Registers *******************************************************/ @@ -286,4 +286,353 @@ #define MRF24J40_RXFLUSH_SHIFT_WAKEPAD 5 #define MRF24J40_RXFLUSH_SHIFT_WAKEPOL 6 -#endif /* __DRIVERS_WIRELESS_IEEE802154_MRF24J40_H */ +#endif /* __DRIVERS_WIRELESS_IEEE802154_MRF24J40_MRF24J40_H */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From 053b6e3d9fe3f7af4fbe138e6096f0120c4b6165 Mon Sep 17 00:00:00 2001 From: Gregory Nutt Date: Mon, 3 Jul 2017 10:08:49 -0600 Subject: [PATCH 14/54] Fix dangling white space at the end of lines. --- .../wireless/ieee802154/at86rf23x/at86rf23x.c | 156 ++------ .../wireless/ieee802154/mrf24j40/mrf24j40.c | 18 +- .../wireless/ieee802154/mrf24j40/mrf24j40.h | 348 ------------------ wireless/ieee802154/mac802154.c | 18 +- wireless/ieee802154/mac802154_assoc.c | 4 +- 5 files changed, 43 insertions(+), 501 deletions(-) diff --git a/drivers/wireless/ieee802154/at86rf23x/at86rf23x.c b/drivers/wireless/ieee802154/at86rf23x/at86rf23x.c index 1d71f3239c..1fe4250d3a 100644 --- a/drivers/wireless/ieee802154/at86rf23x/at86rf23x.c +++ b/drivers/wireless/ieee802154/at86rf23x/at86rf23x.c @@ -993,226 +993,116 @@ static int at86rf23x_gettxpower(FAR struct ieee802154_radio_s *ieee, /* Right now we only get negative values */ - - - reg = at86rf23x_getreg(dev->spi, RF23X_REG_TXPWR); switch (reg) - { - - case RF23X_TXPWR_POS_4: *txpwr = 0; break; - - - - case RF23X_TXPWR_POS_3_7: - *txpwr = -0; + case RF23X_TXPWR_POS_3_7: + *txpwr =0; break; - - - - case RF23X_TXPWR_POS_3_4: + case RF23X_TXPWR_POS_3_4: *txpwr = 0; - - break; - - case RF23X_TXPWR_POS_3: - *txpwr = - 0; - + *txpwr = 0; break; - - case RF23X_ -TXPWR_POS_2_5: + case RF23X_TXPWR_POS_2_5: *txpwr = 0; - - break; - - case RF23X_TXPWR_POS_2: - + case RF23X_TXPWR_POS_2: *txpwr = 0; - - break; - - case RF23X_TXPWR_POS_1: - *txpwr = 0; break; - - - - case RF23X_TXPWR_0: - *txpwr = -0; + case RF23X_TXPWR_0: + *txpwr =0; break; - - - - case RF23X_TXPWR_NEG_1: + case RF23X_TXPWR_NEG_1: *txpwr = 1000; - break; - - - case RF23X_TXPWR_NE -G_2: + case RF23X_TXPWR_NEG_2: *txpwr = 2000; - - break; - case RF23X_TXPWR_NEG_3: - - -*txpwr = 3000; - + *txpwr = 3000; break; - case RF23X_TXPWR_NEG_4: - - -*txpwr = 4000; - -break; - - + *txpwr = 4000; + break; case RF23X_TXPWR_NEG_6: *txpwr = 6000; - - break; - - case RF23X_TXPWR_NEG_8: *txpwr = 8000; - break; - - - ca -se RF23X_TXPWR_NEG_12: - + case RF23X_TXPWR_NEG_12: *txpwr = 12000; break; - - case RF23X_TXPWR_NEG_17: - - *txpwr = 17 -000; - -break; + *txpwr = 17000; + break; } - - return OK; - } - - -/**** -************************************************************************ - +/**************************************************************************** * Name: at86rf23x_setcca * - * Description: - * Configures if energy detection is used or carrier sense. The base - - * measurement is configured here as well * - - * - - ************************************************************************* -***/ - + ****************************************************************************/ static int at86rf23x_setcca(FAR struct ieee802154_radio_s *ieee, - - FAR struct ieee802154_cca_s *cca) - + FAR struct ieee802154_cca_s *cca) { FAR struct at86rf23x_dev_s *dev = (struct at86rf23x_dev_s *)ieee; - - - /* TODO: This doesn't fit the RF233 completely come back to this */ - - if (!cca->use_ed && !cca->use_cs) { - return -EINVAL; - } - - - if (cca->use_cs && cca->csth > 0x0f) { - return -EINVAL; - } - - if (cca->use_ed) - - - { - + { at86rf23x_setregbits(dev->spi, RF23X_CCA_BITS_MODE, RF23X_CCA_MODE_ED); } - - - -if (cca->use_cs) + if (cca->use_cs) { - - at86rf23x_setregbits(dev->spi, RF23X_CCA_BITS_MODE, RF23X_CCA -_MODE_CS); + at86rf23x_setregbits(dev->spi, RF23X_CCA_BITS_MODE, RF23X_CCA_MODE_CS); } - - - memcpy(&dev->cca, cca, sizeof(struct ieee802154 -_cca_s)); + memcpy(&dev->cca, cca, sizeof(struct ieee802154_cca_s)); return OK; } diff --git a/drivers/wireless/ieee802154/mrf24j40/mrf24j40.c b/drivers/wireless/ieee802154/mrf24j40/mrf24j40.c index 94b03990e1..5098e96253 100644 --- a/drivers/wireless/ieee802154/mrf24j40/mrf24j40.c +++ b/drivers/wireless/ieee802154/mrf24j40/mrf24j40.c @@ -465,7 +465,7 @@ static int mrf24j40_reset(FAR struct ieee802154_radio_s *radio) /* Set this in reset since it can exist for all device modes. See pg 101 */ mrf24j40_setreg(dev->spi, MRF24J40_FRMOFFSET, 0x15); - + /* For now, we want to always just have the frame pending bit set when * acknowledging a Data Request command. The standard says that the coordinator * can do this if it needs time to figure out whether it has data or not @@ -613,7 +613,7 @@ static int mrf24j40_setattr(FAR struct ieee802154_radio_s *radio, } break; - + case IEEE802154_ATTR_PHY_CHAN: { mrf24j40_setchannel(dev, attrval->phy.chan); @@ -729,7 +729,7 @@ static int mrf24j40_sfupdate(FAR struct ieee802154_radio_s *radio, mrf24j40_setorder(dev, sfspec->beaconorder, sfspec->sforder); - /* Program the CAP end slot (ESLOTG1 0x13<3:0>) value. */ + /* Program the CAP end slot (ESLOTG1 0x13<3:0>) value. */ reg = mrf24j40_getreg(dev->spi, MRF24J40_ESLOTG1); reg &= ~MRF24J40_ESLOTG1_CAP; @@ -1042,7 +1042,7 @@ static void mrf24j40_setorder(FAR struct mrf24j40_radio_s *dev, uint8_t bo, /* If the Sleep Clock Selection, SLPCLKSEL (0x207<7:6), is the internal * oscillator (100 kHz), set SLPCLKDIV to a minimum value of 0x01. */ - + mrf24j40_setreg(dev->spi, MRF24J40_SLPCON1, 0x01); /* Select the source of SLPCLK (internal 100kHz) */ @@ -1059,8 +1059,8 @@ static void mrf24j40_setorder(FAR struct mrf24j40_radio_s *dev, uint8_t bo, /* Calibration is complete when the SLPCALRDY bit (SLPCAL2 0x20B<7>) is * set to ‘1’. */ - - while (!(mrf24j40_getreg(dev->spi, MRF24J40_SLPCAL2) & + + while (!(mrf24j40_getreg(dev->spi, MRF24J40_SLPCAL2) & MRF24J40_SLPCAL2_SLPCALRDY)) { usleep(1); @@ -1073,7 +1073,7 @@ static void mrf24j40_setorder(FAR struct mrf24j40_radio_s *dev, uint8_t bo, /* Program the Beacon Interval into the Main Counter, MAINCNT (0x229<1:0>, * 0x228, 0x227, 0x226), and Remain Counter, REMCNT (0x225, 0x224), * according to BO and SO values. Refer to Section 3.15.1.3 “Sleep Mode - * Counters” + * Counters” */ @@ -2378,14 +2378,14 @@ static void mrf24j40_irqworker(FAR void *arg) reg |= MRF24J40_SLPACK_SLPACK; mrf24j40_setreg(dev->spi, MRF24J40_SLPACK, reg); } - + if ((intstat & MRF24J40_INTSTAT_WAKEIF)) { wlinfo("Wake Interrupt\n"); /* This is right before the beacon, we set the bsn here, since the MAC * uses the SLPIF (end of active portion of superframe). to make any * changes to the beacon. This assumes that any changes to the beacon - * be in by the time that this interrupt fires. + * be in by the time that this interrupt fires. */ mrf24j40_setreg(dev->spi, MRF24J40_BEACON_FIFO + 4, dev->bsn++); diff --git a/drivers/wireless/ieee802154/mrf24j40/mrf24j40.h b/drivers/wireless/ieee802154/mrf24j40/mrf24j40.h index 56b5716d1c..c21c2e9f38 100644 --- a/drivers/wireless/ieee802154/mrf24j40/mrf24j40.h +++ b/drivers/wireless/ieee802154/mrf24j40/mrf24j40.h @@ -288,351 +288,3 @@ #endif /* __DRIVERS_WIRELESS_IEEE802154_MRF24J40_MRF24J40_H */ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/wireless/ieee802154/mac802154.c b/wireless/ieee802154/mac802154.c index ff3ffb65be..09a3ab0274 100644 --- a/wireless/ieee802154/mac802154.c +++ b/wireless/ieee802154/mac802154.c @@ -1569,7 +1569,7 @@ static void mac802154_rxbeaconframe(FAR struct ieee802154_privmac_s *priv, * you would have to copy the data over in the case that you actually need * to notify the next highest layer) */ - + mac802154_notif_alloc(priv, ¬if, false); beacon = ¬if->u.beaconind; @@ -1718,9 +1718,9 @@ static void mac802154_rxbeaconframe(FAR struct ieee802154_privmac_s *priv, if (beacon->payloadlength > 0) { - memcpy(beacon->payload, &iob->io_data[iob->io_offset], beacon->payloadlength); + memcpy(beacon->payload, &iob->io_data[iob->io_offset], beacon->payloadlength); } - + /* At this point, we have extracted all relevant info from the incoming frame */ if (priv->curr_op == MAC802154_OP_SCAN) @@ -1745,7 +1745,7 @@ static void mac802154_rxbeaconframe(FAR struct ieee802154_privmac_s *priv, mac802154_notif_free_locked(priv, notif); return; } - + /* TODO: There is supposed to be different logic for the scanning procedure * based on the macAutoRequest attribute. Currently, we perform scan * operations as if macAutoRequest is set to TRUE, without actually checking @@ -1756,7 +1756,7 @@ static void mac802154_rxbeaconframe(FAR struct ieee802154_privmac_s *priv, * via the BEACON.notify primitive, and pass a NULLed out list of pandesc * when SCAN.confirm is sent. */ - + /* Copy the pan desc to the list of pan desc */ memcpy(&priv->pandescs[priv->npandesc], &beacon->pandesc, @@ -1793,7 +1793,7 @@ static void mac802154_rxbeaconframe(FAR struct ieee802154_privmac_s *priv, * send a BEACON-NOTFIY.indication in this case, not sure if that * is the right thing to do, can't find anything definitive in standard. */ - + if (priv->curr_op == MAC802154_OP_ASSOC && pending_eaddr) { priv->curr_cmd = IEEE802154_CMD_DATA_REQ; @@ -1818,7 +1818,7 @@ static void mac802154_rxbeaconframe(FAR struct ieee802154_privmac_s *priv, * BEACON-NOTIFY.indication primitive if the beacon contains any * payload. */ - + if (beacon->payloadlength > 0) { /* Unlock the MAC, notify, then lock again */ @@ -1872,7 +1872,7 @@ static void mac802154_rxbeaconframe(FAR struct ieee802154_privmac_s *priv, /* If there was a beacon payload, we used the notification, so * return here to make sure we don't free the notification. */ - + if (beacon->payloadlength > 0) { return; @@ -2112,7 +2112,7 @@ MACHANDLE mac802154_create(FAR struct ieee802154_radio_s *radiodev) { eaddr[i] = (CONFIG_IEEE802154_DEFAULT_EADDR >> (8 * i)) & 0xFF; } - + mac802154_seteaddr(mac, eaddr); return (MACHANDLE)mac; diff --git a/wireless/ieee802154/mac802154_assoc.c b/wireless/ieee802154/mac802154_assoc.c index 5d22c1d88d..6f413eafe6 100644 --- a/wireless/ieee802154/mac802154_assoc.c +++ b/wireless/ieee802154/mac802154_assoc.c @@ -246,7 +246,7 @@ int mac802154_req_associate(MACHANDLE mac, * a beacon frame from the desired coordinator address, we have to just * send the frame out immediately. */ - + for (i = 0; i < priv->npandesc; i++) { /* Check to make sure the beacon is from the same channel as the request */ @@ -264,7 +264,7 @@ int mac802154_req_associate(MACHANDLE mac, /* We have a beacon frame from this coordinator, we can set the * sfspec and send accordingly. */ - + /* Copy in the new superframe spec */ memcpy(&priv->sfspec, &priv->pandescs[i].sfspec, From 4cf2d0a6a8eea2cf5318fa271aab7e18be0208fe Mon Sep 17 00:00:00 2001 From: Anthony Merlino Date: Fri, 7 Jul 2017 23:31:13 -0400 Subject: [PATCH 15/54] ieee802154: Changes mac locking/unlocking to aid in debugging --- wireless/ieee802154/mac802154.c | 56 ++++++++++++------------ wireless/ieee802154/mac802154_assoc.c | 34 +++++++------- wireless/ieee802154/mac802154_data.c | 8 ++-- wireless/ieee802154/mac802154_internal.h | 32 ++++++++++++-- wireless/ieee802154/mac802154_notif.c | 8 ++-- wireless/ieee802154/mac802154_poll.c | 14 +++--- wireless/ieee802154/mac802154_scan.c | 10 ++--- wireless/ieee802154/mac802154_start.c | 6 +-- 8 files changed, 96 insertions(+), 72 deletions(-) diff --git a/wireless/ieee802154/mac802154.c b/wireless/ieee802154/mac802154.c index 09a3ab0274..8b401d9ae0 100644 --- a/wireless/ieee802154/mac802154.c +++ b/wireless/ieee802154/mac802154.c @@ -184,7 +184,7 @@ int mac802154_txdesc_alloc(FAR struct ieee802154_privmac_s *priv, { /* Unlock MAC so that other work can be done to free a notification */ - mac802154_givesem(&priv->exclsem); + mac802154_unlock(priv) /* Take a count from the tx desc semaphore, waiting if necessary. We * only return from here with an error if we are allowing interruptions @@ -204,7 +204,7 @@ int mac802154_txdesc_alloc(FAR struct ieee802154_privmac_s *priv, * MAC in order to ensure this happens correctly. */ - ret = mac802154_takesem(&priv->exclsem, allow_interrupt); + ret = mac802154_lock(priv, allow_interrupt); if (ret < 0) { wlwarn("WARNING: mac802154_takesem failed: %d\n", ret); @@ -609,7 +609,7 @@ static void mac802154_purge_worker(FAR void *arg) * signals so don't allow interruptions */ - mac802154_takesem(&priv->exclsem, false); + mac802154_lock(priv, false); while (1) { @@ -679,7 +679,7 @@ static int mac802154_radiopoll(FAR const struct ieee802154_radiocb_s *radiocb, /* Get exclusive access to the driver structure. Ignore any EINTR signals */ - mac802154_takesem(&priv->exclsem, false); + mac802154_lock(priv, false); if (gts) { @@ -694,7 +694,7 @@ static int mac802154_radiopoll(FAR const struct ieee802154_radiocb_s *radiocb, *txdesc = (FAR struct ieee802154_txdesc_s *)sq_remfirst(&priv->csma_queue); } - mac802154_givesem(&priv->exclsem); + mac802154_unlock(priv) if (*txdesc != NULL) { @@ -731,11 +731,11 @@ static void mac802154_txdone(FAR const struct ieee802154_radiocb_s *radiocb, * signals so don't allow interruptions */ - mac802154_takesem(&priv->exclsem, false); + mac802154_lock(priv, false); sq_addlast((FAR sq_entry_t *)txdesc, &priv->txdone_queue); - mac802154_givesem(&priv->exclsem); + mac802154_unlock(priv) /* Schedule work with the work queue to process the completion further */ @@ -767,7 +767,7 @@ static void mac802154_txdone_worker(FAR void *arg) * signals so don't allow interruptions */ - mac802154_takesem(&priv->exclsem, false); + mac802154_lock(priv, false); while (1) { @@ -794,9 +794,9 @@ static void mac802154_txdone_worker(FAR void *arg) /* Release the MAC, call the callback, get exclusive access again */ - mac802154_givesem(&priv->exclsem); + mac802154_unlock(priv) mac802154_notify(priv, notif); - mac802154_takesem(&priv->exclsem, false); + mac802154_lock(priv, false); } break; @@ -878,7 +878,7 @@ static void mac802154_txdone_worker(FAR void *arg) mac802154_txdesc_free(priv, txdesc); } - mac802154_givesem(&priv->exclsem); + mac802154_unlock(priv) } /**************************************************************************** @@ -909,7 +909,7 @@ static void mac802154_rxframe(FAR const struct ieee802154_radiocb_s *radiocb, * signals so if we see one, just go back to trying to get access again. */ - mac802154_takesem(&priv->exclsem, false); + mac802154_lock(priv, false); /* Push the iob onto the tail of the frame list for processing */ @@ -917,7 +917,7 @@ static void mac802154_rxframe(FAR const struct ieee802154_radiocb_s *radiocb, wlinfo("Frame received\n"); - mac802154_givesem(&priv->exclsem); + mac802154_unlock(priv) /* Schedule work with the work queue to process the completion further */ @@ -955,7 +955,7 @@ static void mac802154_rxframe_worker(FAR void *arg) * signals so if we see one, just go back to trying to get access again. */ - mac802154_takesem(&priv->exclsem, false); + mac802154_lock(priv, false); /* Pop the iob from the head of the frame list for processing */ @@ -963,7 +963,7 @@ static void mac802154_rxframe_worker(FAR void *arg) /* Once we pop off the indication, we don't need to keep the mac locked */ - mac802154_givesem(&priv->exclsem); + mac802154_unlock(priv) if (ind == NULL) { @@ -1147,7 +1147,7 @@ static void mac802154_rxdataframe(FAR struct ieee802154_privmac_s *priv, /* Get exclusive access to the MAC */ - mac802154_takesem(&priv->exclsem, false); + mac802154_lock(priv, false); /* If we are currently performing a POLL operation and we've * received a data response, use the addressing information @@ -1266,7 +1266,7 @@ static void mac802154_rxdataframe(FAR struct ieee802154_privmac_s *priv, /* Release the MAC */ - mac802154_givesem(&priv->exclsem); + mac802154_unlock(priv) mac802154_notify(priv, notif); /* If there was data, pass it along */ @@ -1282,7 +1282,7 @@ static void mac802154_rxdataframe(FAR struct ieee802154_privmac_s *priv, notify_with_lock: - mac802154_givesem(&priv->exclsem); + mac802154_unlock(priv) notify_without_lock: @@ -1341,7 +1341,7 @@ static void mac802154_rxdatareq(FAR struct ieee802154_privmac_s *priv, /* Get exclusive access to the MAC */ - mac802154_takesem(&priv->exclsem, false); + mac802154_lock(priv, false); /* Search the list of indirect transactions to see if there are any waiting * for the requesting device. @@ -1371,7 +1371,7 @@ static void mac802154_rxdatareq(FAR struct ieee802154_privmac_s *priv, priv->radio->txdelayed(priv->radio, txdesc, 0); priv->beaconupdate = true; - mac802154_givesem(&priv->exclsem); + mac802154_unlock(priv) return; } } @@ -1388,7 +1388,7 @@ static void mac802154_rxdatareq(FAR struct ieee802154_privmac_s *priv, priv->radio->txdelayed(priv->radio, txdesc, 0); priv->beaconupdate = true; - mac802154_givesem(&priv->exclsem); + mac802154_unlock(priv) return; } } @@ -1494,7 +1494,7 @@ static void mac802154_rxdatareq(FAR struct ieee802154_privmac_s *priv, txdesc->frame = iob; txdesc->frametype = IEEE802154_FRAME_DATA; - mac802154_givesem(&priv->exclsem); + mac802154_unlock(priv) priv->radio->txdelayed(priv->radio, txdesc, 0); } @@ -1513,7 +1513,7 @@ static void mac802154_sfevent(FAR const struct ieee802154_radiocb_s *radiocb, * signals so if we see one, just go back to trying to get access again. */ - mac802154_takesem(&priv->exclsem, false); + mac802154_lock(priv, false); switch (sfevent) { @@ -1536,7 +1536,7 @@ static void mac802154_sfevent(FAR const struct ieee802154_radiocb_s *radiocb, } - mac802154_givesem(&priv->exclsem); + mac802154_unlock(priv) } /**************************************************************************** @@ -1823,9 +1823,9 @@ static void mac802154_rxbeaconframe(FAR struct ieee802154_privmac_s *priv, { /* Unlock the MAC, notify, then lock again */ - mac802154_givesem(&priv->exclsem); + mac802154_unlock(priv) mac802154_notify(priv, notif); - mac802154_takesem(&priv->exclsem, false); + mac802154_lock(priv, false); } /* If we have data pending for us, attempt to extract it. If for some @@ -1887,9 +1887,9 @@ static void mac802154_rxbeaconframe(FAR struct ieee802154_privmac_s *priv, /* Unlock the MAC, notify, then lock again */ - mac802154_givesem(&priv->exclsem); + mac802154_unlock(priv) mac802154_notify(priv, notif); - mac802154_takesem(&priv->exclsem, false); + mac802154_lock(priv, false); return; /* Return so that we don't free the notificaiton */ } } diff --git a/wireless/ieee802154/mac802154_assoc.c b/wireless/ieee802154/mac802154_assoc.c index 6f413eafe6..beaf1c34f6 100644 --- a/wireless/ieee802154/mac802154_assoc.c +++ b/wireless/ieee802154/mac802154_assoc.c @@ -111,7 +111,7 @@ int mac802154_req_associate(MACHANDLE mac, /* Get exclusive access to the MAC */ - ret = mac802154_takesem(&priv->exclsem, true); + ret = mac802154_lock(priv, true); if (ret < 0) { mac802154_givesem(&priv->opsem); @@ -154,7 +154,7 @@ int mac802154_req_associate(MACHANDLE mac, if (ret < 0) { iob_free(iob); - mac802154_givesem(&priv->exclsem); + mac802154_unlock(priv) mac802154_givesem(&priv->opsem); return ret; } @@ -299,7 +299,7 @@ int mac802154_req_associate(MACHANDLE mac, /* We no longer need to have the MAC layer locked. */ - mac802154_givesem(&priv->exclsem); + mac802154_unlock(priv) return OK; } @@ -394,7 +394,7 @@ int mac802154_resp_associate(MACHANDLE mac, /* Get exclusive access to the MAC */ - ret = mac802154_takesem(&priv->exclsem, true); + ret = mac802154_lock(priv, true); if (ret < 0) { iob_free(iob); @@ -407,7 +407,7 @@ int mac802154_resp_associate(MACHANDLE mac, if (ret < 0) { iob_free(iob); - mac802154_givesem(&priv->exclsem); + mac802154_unlock(priv) return ret; } @@ -420,7 +420,7 @@ int mac802154_resp_associate(MACHANDLE mac, mac802154_setupindirect(priv, txdesc); - mac802154_givesem(&priv->exclsem); + mac802154_unlock(priv) return OK; } @@ -484,9 +484,9 @@ void mac802154_txdone_assocreq(FAR struct ieee802154_privmac_s *priv, /* Release the MAC, call the callback, get exclusive access again */ - mac802154_givesem(&priv->exclsem); + mac802154_unlock(priv) mac802154_notify(priv, notif); - mac802154_takesem(&priv->exclsem, false); + mac802154_lock(priv, false); } else { @@ -627,9 +627,9 @@ void mac802154_txdone_datareq_assoc(FAR struct ieee802154_privmac_s *priv, /* Release the MAC, call the callback, get exclusive access again */ - mac802154_givesem(&priv->exclsem); + mac802154_unlock(priv) mac802154_notify(priv, notif); - mac802154_takesem(&priv->exclsem, false); + mac802154_lock(priv, false); } else { @@ -689,7 +689,7 @@ void mac802154_rx_assocreq(FAR struct ieee802154_privmac_s *priv, /* Get exclusive access to the MAC */ - mac802154_takesem(&priv->exclsem, false); + mac802154_lock(priv, false); /* Allocate a notification to pass to the next highest layer */ @@ -730,7 +730,7 @@ void mac802154_rx_assocreq(FAR struct ieee802154_privmac_s *priv, /* Unlock the MAC */ - mac802154_givesem(&priv->exclsem); + mac802154_unlock(priv) /* Notify the next highest layer of the association status */ @@ -738,7 +738,7 @@ void mac802154_rx_assocreq(FAR struct ieee802154_privmac_s *priv, return; errout_with_sem: - mac802154_givesem(&priv->exclsem); + mac802154_unlock(priv) return; } @@ -785,7 +785,7 @@ void mac802154_rx_assocresp(FAR struct ieee802154_privmac_s *priv, /* Get exclusive access to the MAC */ - mac802154_takesem(&priv->exclsem, false); + mac802154_lock(priv, false); /* Allocate a notification to pass to the next highest layer */ @@ -838,7 +838,7 @@ void mac802154_rx_assocresp(FAR struct ieee802154_privmac_s *priv, /* Unlock the MAC */ - mac802154_givesem(&priv->exclsem); + mac802154_unlock(priv) /* Notify the next highest layer of the association status */ @@ -875,7 +875,7 @@ static void mac802154_assoctimeout(FAR struct ieee802154_privmac_s *priv) * Don't allow EINTR to interrupt. */ - mac802154_takesem(&priv->exclsem, false); + mac802154_lock(priv, false); mac802154_notif_alloc(priv, ¬if, false); /* We are no longer performing the association operation */ @@ -887,7 +887,7 @@ static void mac802154_assoctimeout(FAR struct ieee802154_privmac_s *priv) /* Release the MAC */ - mac802154_givesem(&priv->exclsem); + mac802154_unlock(priv) notif->notiftype = IEEE802154_NOTIFY_CONF_ASSOC; notif->u.assocconf.status = IEEE802154_STATUS_NO_DATA; diff --git a/wireless/ieee802154/mac802154_data.c b/wireless/ieee802154/mac802154_data.c index 171751169b..066c4815b8 100644 --- a/wireless/ieee802154/mac802154_data.c +++ b/wireless/ieee802154/mac802154_data.c @@ -147,7 +147,7 @@ int mac802154_req_data(MACHANDLE mac, /* From this point on, we need exclusive access to the privmac struct */ - ret = mac802154_takesem(&priv->exclsem, true); + ret = mac802154_lock(priv, true); if (ret < 0) { /* Should only fail if interrupted by a signal */ @@ -313,7 +313,7 @@ int mac802154_req_data(MACHANDLE mac, memcpy(&txdesc->destaddr, &meta->destaddr, sizeof(struct ieee802154_addr_s)); mac802154_setupindirect(priv, txdesc); - mac802154_givesem(&priv->exclsem); + mac802154_unlock(priv) } else { @@ -329,7 +329,7 @@ int mac802154_req_data(MACHANDLE mac, /* We no longer need to have the MAC layer locked. */ - mac802154_givesem(&priv->exclsem); + mac802154_unlock(priv) /* Notify the radio driver that there is data available */ @@ -346,7 +346,7 @@ errout_with_txdesc: mac802154_txdesc_free(priv, txdesc); errout_with_sem: - mac802154_givesem(&priv->exclsem); + mac802154_unlock(priv) return ret; } diff --git a/wireless/ieee802154/mac802154_internal.h b/wireless/ieee802154/mac802154_internal.h index d3f86be9dd..b31c0f2931 100644 --- a/wireless/ieee802154/mac802154_internal.h +++ b/wireless/ieee802154/mac802154_internal.h @@ -388,8 +388,6 @@ void mac802154_createdatareq(FAR struct ieee802154_privmac_s *priv, void mac802154_updatebeacon(FAR struct ieee802154_privmac_s *priv); - - /**************************************************************************** * Helper Macros/Inline Functions ****************************************************************************/ @@ -564,9 +562,9 @@ void mac802154_updatebeacon(FAR struct ieee802154_privmac_s *priv); ((GETHOST16(ptr, index) & IEEE802154_PENDADDR_NEADDR) >> \ IEEE802154_PENDADDR_SHIFT_NEADDR) -/* General helper macros ****************************************************/ +/* General helpers ****************************************************/ -#define mac802154_givesem(s) sem_post(s); +#define mac802154_givesem(s) sem_post(s) static inline int mac802154_takesem(sem_t *sem, bool allowinterrupt) { @@ -593,6 +591,32 @@ static inline int mac802154_takesem(sem_t *sem, bool allowinterrupt) return OK; } +#define mac802154_unlock(dev) \ + mac802154_givesem(&dev->exclsem); \ + wlinfo("MAC unlocked\n"); + +#define mac802154_lock(dev, allowinterrupt) \ + mac802154_lockpriv(dev, allowinterrupt, __FUNCTION__) + +static inline int mac802154_lockpriv(FAR struct ieee802154_privmac_s *dev, + bool allowinterrupt, FAR const char *funcname) +{ + int ret; + + wlinfo("Locking MAC: %s\n", funcname); + ret = mac802154_takesem(&dev->exclsem, allowinterrupt); + if (ret < 0) + { + wlinfo("Failed to lock MAC\n"); + } + else + { + wlinfo("MAC locked\n"); + } + + return ret; +} + static inline void mac802154_txdesc_free(FAR struct ieee802154_privmac_s *priv, FAR struct ieee802154_txdesc_s *txdesc) { diff --git a/wireless/ieee802154/mac802154_notif.c b/wireless/ieee802154/mac802154_notif.c index 059d95624c..0d2727c0e1 100644 --- a/wireless/ieee802154/mac802154_notif.c +++ b/wireless/ieee802154/mac802154_notif.c @@ -76,7 +76,7 @@ void mac802154_notif_free(MACHANDLE mac, FAR struct ieee802154_notif_s *notif) /* Lock the MAC */ - mac802154_takesem(&priv->exclsem, false); + mac802154_lock(priv, false); /* Call the internal helper function to free the notification */ @@ -84,7 +84,7 @@ void mac802154_notif_free(MACHANDLE mac, FAR struct ieee802154_notif_s *notif) /* Unlock the MAC */ - mac802154_givesem(&priv->exclsem); + mac802154_unlock(priv) } /**************************************************************************** @@ -170,7 +170,7 @@ int mac802154_notif_alloc(FAR struct ieee802154_privmac_s *priv, { /* Unlock MAC so that other work can be done to free a notification */ - mac802154_givesem(&priv->exclsem); + mac802154_unlock(priv) /* Take a count from the notification semaphore, waiting if necessary. We * only return from here with an error if we are allowing interruptions @@ -189,7 +189,7 @@ int mac802154_notif_alloc(FAR struct ieee802154_privmac_s *priv, * MAC in order to ensure this happens correctly. */ - ret = mac802154_takesem(&priv->exclsem, allow_interrupt); + ret = mac802154_lock(priv, allow_interrupt); if (ret < 0) { mac802154_givesem(&priv->notif_sem); diff --git a/wireless/ieee802154/mac802154_poll.c b/wireless/ieee802154/mac802154_poll.c index 368f8baac2..715518e916 100644 --- a/wireless/ieee802154/mac802154_poll.c +++ b/wireless/ieee802154/mac802154_poll.c @@ -106,7 +106,7 @@ int mac802154_req_poll(MACHANDLE mac, FAR struct ieee802154_poll_req_s *req) /* Get exclusive access to the MAC */ - ret = mac802154_takesem(&priv->exclsem, true); + ret = mac802154_lock(priv, true); if (ret < 0) { mac802154_givesem(&priv->opsem); @@ -121,7 +121,7 @@ int mac802154_req_poll(MACHANDLE mac, FAR struct ieee802154_poll_req_s *req) ret = mac802154_txdesc_alloc(priv, &txdesc, true); if (ret < 0) { - mac802154_givesem(&priv->exclsem); + mac802154_unlock(priv) mac802154_givesem(&priv->opsem); return ret; } @@ -158,7 +158,7 @@ int mac802154_req_poll(MACHANDLE mac, FAR struct ieee802154_poll_req_s *req) /* We no longer need to have the MAC layer locked. */ - mac802154_givesem(&priv->exclsem); + mac802154_unlock(priv) /* Notify the radio driver that there is data available */ @@ -222,9 +222,9 @@ void mac802154_txdone_datareq_poll(FAR struct ieee802154_privmac_s *priv, /* Release the MAC, call the callback, get exclusive access again */ - mac802154_givesem(&priv->exclsem); + mac802154_unlock(priv) mac802154_notify(priv, notif); - mac802154_takesem(&priv->exclsem, false); + mac802154_lock(priv, false); } else { @@ -269,7 +269,7 @@ void mac802154_polltimeout(FAR struct ieee802154_privmac_s *priv) * Don't allow EINTR to interrupt. */ - mac802154_takesem(&priv->exclsem, false); + mac802154_lock(priv, false); mac802154_notif_alloc(priv, ¬if, false); /* We are no longer performing the association operation */ @@ -279,7 +279,7 @@ void mac802154_polltimeout(FAR struct ieee802154_privmac_s *priv) /* Release the MAC */ - mac802154_givesem(&priv->exclsem); + mac802154_unlock(priv) notif->notiftype = IEEE802154_NOTIFY_CONF_POLL; notif->u.pollconf.status = IEEE802154_STATUS_NO_DATA; diff --git a/wireless/ieee802154/mac802154_scan.c b/wireless/ieee802154/mac802154_scan.c index 819ac141f8..c24ae0b5f1 100644 --- a/wireless/ieee802154/mac802154_scan.c +++ b/wireless/ieee802154/mac802154_scan.c @@ -110,7 +110,7 @@ int mac802154_req_scan(MACHANDLE mac, FAR struct ieee802154_scan_req_s *req) /* Get exclusive access to the MAC */ - ret = mac802154_takesem(&priv->exclsem, true); + ret = mac802154_lock(priv, true); if (ret < 0) { mac802154_givesem(&priv->opsem); @@ -186,11 +186,11 @@ int mac802154_req_scan(MACHANDLE mac, FAR struct ieee802154_scan_req_s *req) break; } - mac802154_givesem(&priv->exclsem); + mac802154_unlock(priv) return OK; errout_with_sem: - mac802154_givesem(&priv->exclsem); + mac802154_unlock(priv) mac802154_givesem(&priv->opsem); errout: return ret; @@ -205,7 +205,7 @@ void mac802154_scanfinish(FAR struct ieee802154_privmac_s *priv, { FAR struct ieee802154_notif_s * notif; - mac802154_takesem(&priv->exclsem, false); + mac802154_lock(priv, false); mac802154_notif_alloc(priv, ¬if, false); priv->curr_op = MAC802154_OP_NONE; @@ -233,7 +233,7 @@ void mac802154_scanfinish(FAR struct ieee802154_privmac_s *priv, mac802154_setpanid(priv, priv->panidbeforescan); - mac802154_givesem(&priv->exclsem); + mac802154_unlock(priv) mac802154_notify(priv, notif); } diff --git a/wireless/ieee802154/mac802154_start.c b/wireless/ieee802154/mac802154_start.c index 5a9c4379ea..2bab5afd15 100644 --- a/wireless/ieee802154/mac802154_start.c +++ b/wireless/ieee802154/mac802154_start.c @@ -72,7 +72,7 @@ int mac802154_req_start(MACHANDLE mac, FAR struct ieee802154_start_req_s *req) /* Get exclusive access to the MAC */ - ret = mac802154_takesem(&priv->exclsem, true); + ret = mac802154_lock(priv, true); if (ret < 0) { return ret; @@ -194,11 +194,11 @@ int mac802154_req_start(MACHANDLE mac, FAR struct ieee802154_start_req_s *req) } } - mac802154_givesem(&priv->exclsem); + mac802154_unlock(priv) return OK; errout: - mac802154_givesem(&priv->exclsem); + mac802154_unlock(priv) return ret; } \ No newline at end of file From c72eb1b39b94b761b6890ca7488ba80b7e42e224 Mon Sep 17 00:00:00 2001 From: Anthony Merlino Date: Sun, 9 Jul 2017 17:59:22 -0400 Subject: [PATCH 16/54] ieee802154: mac802154_purge_timeout was not unlocking MAC before returning --- wireless/ieee802154/mac802154.c | 23 +++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/wireless/ieee802154/mac802154.c b/wireless/ieee802154/mac802154.c index 8b401d9ae0..7e49793a8b 100644 --- a/wireless/ieee802154/mac802154.c +++ b/wireless/ieee802154/mac802154.c @@ -236,6 +236,10 @@ int mac802154_txdesc_alloc(FAR struct ieee802154_privmac_s *priv, return -EINTR; } + /* Set the purge time to zero */ + + (*txdesc)->purge_time = 0; + (*txdesc)->conf = ¬if->u.dataconf; return OK; } @@ -624,10 +628,10 @@ static void mac802154_purge_worker(FAR void *arg) break; } - /* Should probably check a little ahead and remove the transaction if it is within - * a certain number of clock ticks away. There is no since in scheduling the - * timer to expire in only a few ticks. - */ + /* Should probably check a little ahead and remove the transaction if it is within + * a certain number of clock ticks away. There is no since in scheduling the + * timer to expire in only a few ticks. + */ if (clock_systimer() >= txdesc->purge_time) { @@ -654,6 +658,8 @@ static void mac802154_purge_worker(FAR void *arg) break; } } + + mac802154_unlock(priv); } /**************************************************************************** @@ -1367,6 +1373,15 @@ static void mac802154_rxdatareq(FAR struct ieee802154_privmac_s *priv, sq_rem((FAR sq_entry_t *)txdesc, &priv->indirect_queue); + /* NOTE: We don't do anything with the purge timeout, because + * we really don't need to. As of now, I see no disadvantage + * to just letting the timeout expire, which won't purge the + * transaction since it is no longer on the list, and then it + * will reschedule the next timeout appropriately. The logic + * otherwise may get complicated even though it may save a few + * clock cycles. + */ + /* The addresses match, send the transaction immediately */ priv->radio->txdelayed(priv->radio, txdesc, 0); From c8c31810dce7d21e93648485a1438338315c934b Mon Sep 17 00:00:00 2001 From: Anthony Merlino Date: Sun, 9 Jul 2017 18:38:56 -0400 Subject: [PATCH 17/54] ieee802154: Minor renaming. purge_time -> purgetime --- wireless/ieee802154/mac802154.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/wireless/ieee802154/mac802154.c b/wireless/ieee802154/mac802154.c index 7e49793a8b..3a7989e9d8 100644 --- a/wireless/ieee802154/mac802154.c +++ b/wireless/ieee802154/mac802154.c @@ -238,7 +238,7 @@ int mac802154_txdesc_alloc(FAR struct ieee802154_privmac_s *priv, /* Set the purge time to zero */ - (*txdesc)->purge_time = 0; + (*txdesc)->purgetime = 0; (*txdesc)->conf = ¬if->u.dataconf; return OK; @@ -567,7 +567,7 @@ void mac802154_setupindirect(FAR struct ieee802154_privmac_s *priv, ticks = mac802154_symtoticks(priv, symbols); - txdesc->purge_time = clock_systimer() + ticks; + txdesc->purgetime = clock_systimer() + ticks; /* Make sure the beacon gets updated */ @@ -633,7 +633,7 @@ static void mac802154_purge_worker(FAR void *arg) * timer to expire in only a few ticks. */ - if (clock_systimer() >= txdesc->purge_time) + if (clock_systimer() >= txdesc->purgetime) { /* Unlink the transaction */ @@ -654,7 +654,7 @@ static void mac802154_purge_worker(FAR void *arg) /* Reschedule the transaction for the next timeout */ work_queue(MAC802154_WORK, &priv->purge_work, mac802154_purge_worker, - (FAR void *)priv, txdesc->purge_time - clock_systimer()); + (FAR void *)priv, txdesc->purgetime - clock_systimer()); break; } } From 45473095719dbac911c5a3a4f0f6988d6a4a07b6 Mon Sep 17 00:00:00 2001 From: Gregory Nutt Date: Sun, 9 Jul 2017 16:53:08 -0600 Subject: [PATCH 18/54] Remove carriage return endings and dangling white space at the end of lines --- wireless/ieee802154/mac802154_internal.h | 1522 +++++++++++----------- 1 file changed, 761 insertions(+), 761 deletions(-) diff --git a/wireless/ieee802154/mac802154_internal.h b/wireless/ieee802154/mac802154_internal.h index b31c0f2931..fc097cfbf6 100644 --- a/wireless/ieee802154/mac802154_internal.h +++ b/wireless/ieee802154/mac802154_internal.h @@ -1,761 +1,761 @@ -/**************************************************************************** - * wireless/ieee802154/mac802154_internal.h - * - * Copyright (C) 2016 Sebastien Lorquet. All rights reserved. - * Copyright (C) 2017 Verge Inc. All rights reserved. - * Copyright (C) 2017 Gregory Nutt. All rights reserved. - * - * Author: Sebastien Lorquet - * Author: Anthony Merlino - * - * The naming and comments for various fields are taken directly - * from the IEEE 802.15.4 2011 standard. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * 3. Neither the name NuttX nor the names of its contributors may be - * used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS - * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED - * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - ****************************************************************************/ - -#ifndef __WIRELESS_IEEE802154__MAC802154_INTERNAL_H -#define __WIRELESS_IEEE802154__MAC802154_INTERNAL_H - -/**************************************************************************** - * Included Files - ****************************************************************************/ - -#include - -#include -#include -#include -#include -#include - -#include -#include - -#include "mac802154_notif.h" - -#include -#include - -/**************************************************************************** - * Pre-processor Definitions - ****************************************************************************/ - -/* Configuration ************************************************************/ -/* If processing is not done at the interrupt level, then work queue support - * is required. - */ - -#if !defined(CONFIG_SCHED_WORKQUEUE) -# error Work queue support is required in this configuration (CONFIG_SCHED_WORKQUEUE) -#else - - /* Use the low priority work queue if possible */ - -# if defined(CONFIG_MAC802154_HPWORK) -# define MAC802154_WORK HPWORK -# elif defined(CONFIG_MAC802154_LPWORK) -# define MAC802154_WORK LPWORK -# else -# error Neither CONFIG_MAC802154_HPWORK nor CONFIG_MAC802154_LPWORK defined -# endif -#endif - -#if !defined(CONFIG_MAC802154_NNOTIF) || CONFIG_MAC802154_NNOTIF <= 0 -# undef CONFIG_MAC802154_NNOTIF -# define CONFIG_MAC802154_NNOTIF 6 -#endif - -#if !defined(CONFIG_MAC802154_NTXDESC) || CONFIG_MAC802154_NTXDESC <= 0 -# undef CONFIG_MAC802154_NTXDESC -# define CONFIG_MAC802154_NTXDESC 3 -#endif - -#if CONFIG_MAC802154_NTXDESC > CONFIG_MAC802154_NNOTIF -# error CONFIG_MAC802154_NNOTIF must be greater than CONFIG_MAC802154_NTXDESC -#endif - -#if !defined(CONFIG_IEEE802154_DEFAULT_EADDR) -# define CONFIG_IEEE802154_DEFAULT_EADDR 0xFFFFFFFFFFFFFFFF -#endif - -/**************************************************************************** - * Private Data - ****************************************************************************/ - -/* Map between ieee802154_addrmode_e enum and actual address length */ - -static const uint8_t mac802154_addr_length[4] = {0, 0, 2, 8}; - -/**************************************************************************** - * Private Types - ****************************************************************************/ - -struct mac802154_radiocb_s -{ - struct ieee802154_radiocb_s cb; - FAR struct ieee802154_privmac_s *priv; -}; - -/* Enumeration for representing what operation the MAC layer is currently doing. - * There can only be one command being handled at any given time, but certain - * operations such as association requires more than one command to be sent. - * Therefore, the need to track not only what command is currently active, but - * also, what overall operation the command is apart of is necessary. - */ - -enum mac802154_operation_e -{ - MAC802154_OP_NONE, - MAC802154_OP_ASSOC, - MAC802154_OP_POLL, - MAC802154_OP_SCAN, - MAC802154_OP_AUTOEXTRACT, -}; - -struct ieee802154_privmac_s; /* Forward Reference */ -typedef void (*mac802154_worker_t)(FAR struct ieee802154_privmac_s *priv); - -/* The privmac structure holds the internal state of the MAC and is the - * underlying represention of the opaque MACHANDLE. It contains storage for - * the IEEE802.15.4 MIB attributes. - */ - -struct ieee802154_privmac_s -{ - /*************************** General Fields *********************************/ - - FAR struct ieee802154_radio_s *radio; /* Contained IEEE802.15.4 radio dev */ - FAR struct mac802154_maccb_s *cb; /* Head of a list of MAC callbacks */ - FAR struct mac802154_radiocb_s radiocb; /* Interface to bind to radio */ - - sem_t exclsem; /* Support exclusive access */ - uint8_t nclients; /* Number of notification clients */ - - /* Only support a single command at any given time. As of now I see no - * condition where you need to have more than one command frame simultaneously - */ - - sem_t opsem; /* Exclusive operations */ - - /******************* Fields related to MAC operations ***********************/ - - enum mac802154_operation_e curr_op; /* The current overall operation */ - enum ieee802154_cmdid_e curr_cmd; /* Type of the current cmd */ - FAR struct ieee802154_txdesc_s *cmd_desc; /* TX descriptor for current cmd */ - uint8_t nrxusers; - - /******************* Fields related to SCAN operation ***********************/ - - /* List of PAN descriptors to track during scan procedures */ - - uint8_t scanindex; - uint8_t npandesc; - struct ieee802154_pandesc_s pandescs[MAC802154_NPANDESC]; - uint8_t panidbeforescan[IEEE802154_PANIDSIZE]; - struct ieee802154_scan_req_s currscan; - uint32_t scansymdur; - - /******************* Fields related to notifications ************************/ - - /* Pre-allocated notifications to be passed to the registered callback. These - * need to be freed by the application using mac802154_xxxxnotif_free when - * the callee layer is finished with it's use. - */ - - FAR struct mac802154_notif_s *notif_free; - struct mac802154_notif_s notif_pool[CONFIG_MAC802154_NNOTIF]; - sem_t notif_sem; - - /******************* Tx descriptor queues and pools *************************/ - - struct ieee802154_txdesc_s txdesc_pool[CONFIG_MAC802154_NTXDESC]; - sem_t txdesc_sem; - sq_queue_t txdesc_queue; - sq_queue_t txdone_queue; - - /* 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 - * during the CAP of the Coordinator's superframe. - */ - - sq_queue_t csma_queue; - sq_queue_t gts_queue; - - /* Support a singly linked list of transactions that will be sent indirectly. - * This list should only be used by a MAC acting as a coordinator. These - * transactions will stay here until the data is extracted by the destination - * device sending a Data Request MAC command or if too much time passes. This - * list should also be used to populate the address list of the outgoing - * beacon frame. - */ - - sq_queue_t indirect_queue; - - /* Support a singly linked list of frames received */ - - sq_queue_t dataind_queue; - - /************* Fields related to addressing and coordinator *****************/ - - /* Holds all address information (Extended, Short, and PAN ID) for the MAC. */ - - struct ieee802154_addr_s addr; - - struct ieee802154_pandesc_s pandesc; - - /*************** Fields related to beacon-enabled networks ******************/ - - /* Holds attributes pertaining to the superframe specification */ - - struct ieee802154_superframespec_s sfspec; - - /* We use 2 beacon frame structures so that we can ping-pong between them - * while updating the beacon - */ - - struct ieee802154_beaconframe_s beaconframe[2]; - - /* Contents of beacon payload */ - - uint8_t beaconpayload[IEEE802154_MAX_BEACON_PAYLOAD_LEN]; - uint8_t beaconpayloadlength; - - /****************** Fields related to offloading work ***********************/ - - /* Work structures for offloading aynchronous work */ - - struct work_s tx_work; - struct work_s rx_work; - - struct work_s timeout_work; - WDOG_ID timeout; /* Timeout watchdog */ - mac802154_worker_t timeout_worker; - - struct work_s purge_work; - - /****************** Uncategorized MAC PIB attributes ***********************/ - - /* The maximum number of symbols to wait for an acknowledgement frame to - * arrive following a transmitted data frame. [1] pg. 126 - * - * NOTE: This may be able to be a 16-bit or even an 8-bit number. I wasn't - * sure at the time what the range of reasonable values was. - */ - - uint32_t ack_waitdur; - - /* The maximum time to wait either for a frame intended as a response to a - * data request frame or for a broadcast frame following a beacon with the - * Frame Pending field set to one. [1] pg. 127 - * - * NOTE: This may be able to be a 16-bit or even an 8-bit number. I wasn't - * sure at the time what the range of reasonable values was. - */ - - uint32_t max_frame_waittime; - - /* The maximum time (in unit periods) that a transaction is stored by a - * coordinator and indicated in its beacon. - */ - - uint16_t trans_persisttime; - - uint8_t dsn; /* Seq. num added to tx data or MAC frame */ - - /* The maximum time, in multiples of aBaseSuperframeDuration, a device shall - * wait for a response command frame to be available following a request - * command frame. [1] 128. - */ - - uint8_t resp_waittime; - - /* The total transmit duration (including PHY header and FCS) specified in - * symbols. [1] pg. 129. - */ - - uint32_t tx_totaldur; - - /* Start of 8-bit bitfield */ - - uint32_t trackingbeacon : 1; /* Are we tracking the beacon */ - uint32_t isassoc : 1; /* Are we associated to the PAN */ - uint32_t autoreq : 1; /* Automatically send data req. if addr - * addr is in the beacon frame */ - - uint32_t gtspermit : 1; /* Is PAN Coord. accepting GTS reqs. */ - uint32_t promisc : 1; /* Is promiscuous mode on? */ - uint32_t rngsupport : 1; /* Does MAC sublayer support ranging */ - uint32_t sec_enabled : 1; /* Does MAC sublayer have security en. */ - uint32_t timestamp_support : 1; /* Does MAC layer supports timestamping */ - - /* End of 8-bit bitfield */ - - /* Start of 32-bit bitfield */ - - /* The offset, measured is symbols, between the symbol boundary at which the - * MLME captures the timestamp of each transmitted and received frame, and - * the onset of the first symbol past the SFD, namely the first symbol of - * the frames [1] pg. 129. - */ - - uint32_t sync_symboffset : 12; - - uint32_t txctrl_activedur : 17; /* Duration for which tx is permitted to - * be active */ - uint32_t txctrl_pausedur : 1; /* Duration after tx before another tx is - * permitted. 0=2000, 1= 10000 */ - - /* What type of device is this node acting as */ - - enum ieee802154_devmode_e devmode : 2; - - /* End of 32-bit bitfield */ - - /* Start of 32-bit bitfield */ - - uint32_t beacon_txtime : 24; /* Time of last beacon transmit */ - uint32_t minbe : 4; /* Min value of backoff exponent (BE) */ - uint32_t maxbe : 4; /* Max value of backoff exponent (BE) */ - - /* End of 32-bit bitfield */ - - /* Start of 8-bit bitfield */ - - uint8_t bf_ind : 1; /* Ping-pong index for beacon frame */ - uint8_t beaconupdate : 1; /* Does the beacon frame need to be updated */ - uint8_t max_csmabackoffs : 3; /* Max num backoffs for CSMA algorithm - * before declaring ch access failure */ - uint8_t maxretries : 3; /* Max # of retries allowed after tx fail */ - /* End of 8-bit bitfield. */ - - /* Start of 8-bit bitfield */ - - uint8_t rxonidle : 1; /* Receiver on when idle? */ - - /* End of 8-bit bitfield. */ - - - - /* TODO: Add Security-related MAC PIB attributes */ -}; - -/**************************************************************************** - * Function Prototypes - ****************************************************************************/ - -int mac802154_txdesc_alloc(FAR struct ieee802154_privmac_s *priv, - FAR struct ieee802154_txdesc_s **txdesc, - bool allow_interrupt); - -int mac802154_timerstart(FAR struct ieee802154_privmac_s *priv, - uint32_t numsymbols, mac802154_worker_t); - -void mac802154_setupindirect(FAR struct ieee802154_privmac_s *priv, - FAR struct ieee802154_txdesc_s *txdesc); - -void mac802154_createdatareq(FAR struct ieee802154_privmac_s *priv, - FAR struct ieee802154_addr_s *coordaddr, - enum ieee802154_addrmode_e srcmode, - FAR struct ieee802154_txdesc_s *txdesc); - -void mac802154_updatebeacon(FAR struct ieee802154_privmac_s *priv); - -/**************************************************************************** - * Helper Macros/Inline Functions - ****************************************************************************/ - -#define mac802154_putpanid(iob, panid) \ - do \ - { \ - IEEE802154_PANIDCOPY(&iob->io_data[iob->io_len], panid); \ - iob->io_len += IEEE802154_PANIDSIZE; \ - } \ - while(0) - -#define mac802154_putsaddr(iob, saddr) \ - do \ - { \ - IEEE802154_SADDRCOPY(&iob->io_data[iob->io_len], saddr); \ - iob->io_len += IEEE802154_SADDRSIZE; \ - } \ - while(0) - -#define mac802154_puteaddr(iob, eaddr) \ - do \ - { \ - IEEE802154_EADDRCOPY(&iob->io_data[iob->io_len], eaddr); \ - iob->io_len += IEEE802154_EADDRSIZE; \ - } \ - while(0) - -#define mac802154_takepanid(iob, panid) \ - do \ - { \ - IEEE802154_PANIDCOPY(panid, &iob->io_data[iob->io_offset]); \ - iob->io_offset += IEEE802154_PANIDSIZE; \ - } \ - while(0) - -#define mac802154_takesaddr(iob, saddr) \ - do \ - { \ - IEEE802154_SADDRCOPY(saddr, &iob->io_data[iob->io_offset]); \ - iob->io_offset += IEEE802154_SADDRSIZE; \ - } \ - while(0) - -#define mac802154_takeeaddr(iob, eaddr) \ - do \ - { \ - IEEE802154_EADDRCOPY(eaddr, &iob->io_data[iob->io_offset]); \ - iob->io_offset += IEEE802154_EADDRSIZE; \ - } \ - while(0) - -/* General helper macros ****************************************************/ - -/* GET 16-bit data: source in network order, result in host order */ - -#define GETHOST16(ptr,index) \ - ((((uint16_t)((ptr)[(index) + 1])) << 8) | ((uint16_t)(((ptr)[index])))) - -/* GET 16-bit data: source in network order, result in network order */ - -#define GETNET16(ptr,index) \ - ((((uint16_t)((ptr)[index])) << 8) | ((uint16_t)(((ptr)[(index) + 1])))) - -/* PUT 16-bit data: source in host order, result in network order */ - -#define PUTHOST16(ptr,index,value) \ - do \ - { \ - (ptr)[index] = (uint16_t)(value) & 0xff; \ - (ptr)[index + 1] = ((uint16_t)(value) >> 8) & 0xff; \ - } \ - while(0) - -/* Set bit in 16-bit value: source in host order, result in network order. */ - -#define IEEE802154_SETBITS_U16(ptr,index,value) \ - do \ - { \ - (ptr)[index] |= (uint16_t)(value) & 0xff; \ - (ptr)[index + 1] |= ((uint16_t)(value) >> 8) & 0xff; \ - } \ - while(0) - -/* Helper macros for setting/receiving bits for frame control field */ - -#define IEEE802154_SETFTYPE(ptr, index, ftype) \ - IEEE802154_SETBITS_U16(ptr, index, (ftype << IEEE802154_FRAMECTRL_SHIFT_FTYPE)) - -#define IEEE802154_SETACKREQ(ptr, index) \ - IEEE802154_SETBITS_U16(ptr, index, IEEE802154_FRAMECTRL_ACKREQ) - -#define IEEE802154_SETDADDRMODE(ptr, index, mode) \ - IEEE802154_SETBITS_U16(ptr, index, (mode << IEEE802154_FRAMECTRL_SHIFT_DADDR)) - -#define IEEE802154_SETSADDRMODE(ptr, index, mode) \ - IEEE802154_SETBITS_U16(ptr, index, (mode << IEEE802154_FRAMECTRL_SHIFT_SADDR)) - -#define IEEE802154_SETPANIDCOMP(ptr, index) \ - IEEE802154_SETBITS_U16(ptr, index, IEEE802154_FRAMECTRL_PANIDCOMP) - -#define IEEE802154_SETVERSION(ptr, index, version) \ - IEEE802154_SETBITS_U16(ptr, index, (version << IEEE802154_FRAMECTRL_SHIFT_VERSION)) - -/* Helper macros for setting/receiving bits for superframe specification */ - -#define IEEE802154_SETBEACONORDER(ptr, index, val) \ - IEEE802154_SETBITS_U16(ptr, index, (val << IEEE802154_SFSPEC_SHIFT_BEACONORDER)) - -#define IEEE802154_SETSFORDER(ptr, index, val) \ - IEEE802154_SETBITS_U16(ptr, index, (val << IEEE802154_SFSPEC_SHIFT_SFORDER)) - -#define IEEE802154_SETFINCAPSLOT(ptr, index, val) \ - IEEE802154_SETBITS_U16(ptr, index, (val << IEEE802154_SFSPEC_SHIFT_FINCAPSLOT)) - -#define IEEE802154_SETBLE(ptr, index) \ - IEEE802154_SETBITS_U16(ptr, index, IEEE802154_SFSPEC_BLE) - -#define IEEE802154_SETPANCOORD(ptr, index) \ - IEEE802154_SETBITS_U16(ptr, index, IEEE802154_SFSPEC_PANCOORD) - -#define IEEE802154_SETASSOCPERMIT(ptr, index) \ - IEEE802154_SETBITS_U16(ptr, index, IEEE802154_SFSPEC_ASSOCPERMIT) - -#define IEEE802154_GETBEACONORDER(ptr, index) \ - ((GETHOST16(ptr, index) & IEEE802154_SFSPEC_BEACONORDER) >> \ - IEEE802154_SFSPEC_SHIFT_BEACONORDER) - -#define IEEE802154_GETSFORDER(ptr, index) \ - ((GETHOST16(ptr, index) & IEEE802154_SFSPEC_SFORDER) >> \ - IEEE802154_SFSPEC_SHIFT_SFORDER) - -#define IEEE802154_GETFINCAPSLOT(ptr, index) \ - ((GETHOST16(ptr, index) & IEEE802154_SFSPEC_FINCAPSLOT) >> \ - IEEE802154_SFSPEC_SHIFT_FINCAPSLOT) - -#define IEEE802154_GETBLE(ptr, index) \ - ((GETHOST16(ptr, index) & IEEE802154_SFSPEC_BLE) >> \ - IEEE802154_SFSPEC_SHIFT_BLE) - -#define IEEE802154_GETPANCOORD(ptr, index) \ - ((GETHOST16(ptr, index) & IEEE802154_SFSPEC_PANCOORD) >> \ - IEEE802154_SFSPEC_SHIFT_PANCOORD) - -#define IEEE802154_GETASSOCPERMIT(ptr, index) \ - ((GETHOST16(ptr, index) & IEEE802154_SFSPEC_ASSOCPERMIT) >> \ - IEEE802154_SFSPEC_SHIFT_ASSOCPERMIT) - -/* Helper macros for setting/receiving bits for GTS specification */ - -#define IEEE802154_GETGTSDESCCOUNT(ptr, index) \ - ((GETHOST16(ptr, index) & IEEE802154_GTSSPEC_DESCCOUNT) >> \ - IEEE802154_GTSSPEC_SHIFT_DESCCOUNT) - -#define IEEE802154_GETGTSPERMIT(ptr, index) \ - ((GETHOST16(ptr, index) & IEEE802154_GTSSPEC_PERMIT) >> \ - IEEE802154_GTSSPEC_SHIFT_PERMIT) - -/* Helper macros for setting/receiving bits for GTS Directions */ - -#define IEEE802154_GETGTSDIRMASK(ptr, index) \ - ((GETHOST16(ptr, index) & IEEE802154_GTSDIR_MASK) >> \ - IEEE802154_GTSDIR_SHIFT_MASK) - -/* Helper macros for setting/receiving bits for Pending Address Specification */ - -#define IEEE802154_GETNPENDSADDR(ptr, index) \ - ((GETHOST16(ptr, index) & IEEE802154_PENDADDR_NSADDR) >> \ - IEEE802154_PENDADDR_SHIFT_NSADDR) - -#define IEEE802154_GETNPENDEADDR(ptr, index) \ - ((GETHOST16(ptr, index) & IEEE802154_PENDADDR_NEADDR) >> \ - IEEE802154_PENDADDR_SHIFT_NEADDR) - -/* General helpers ****************************************************/ - -#define mac802154_givesem(s) sem_post(s) - -static inline int mac802154_takesem(sem_t *sem, bool allowinterrupt) -{ - int ret; - do - { - /* Take a count from the semaphore, possibly waiting */ - - ret = sem_wait(sem); - if (ret < 0) - { - /* EINTR is the only error that we expect */ - - DEBUGASSERT(get_errno() == EINTR); - - if (allowinterrupt) - { - return -EINTR; - } - } - } - while (ret != OK); - - return OK; -} - -#define mac802154_unlock(dev) \ - mac802154_givesem(&dev->exclsem); \ - wlinfo("MAC unlocked\n"); - -#define mac802154_lock(dev, allowinterrupt) \ - mac802154_lockpriv(dev, allowinterrupt, __FUNCTION__) - -static inline int mac802154_lockpriv(FAR struct ieee802154_privmac_s *dev, - bool allowinterrupt, FAR const char *funcname) -{ - int ret; - - wlinfo("Locking MAC: %s\n", funcname); - ret = mac802154_takesem(&dev->exclsem, allowinterrupt); - if (ret < 0) - { - wlinfo("Failed to lock MAC\n"); - } - else - { - wlinfo("MAC locked\n"); - } - - return ret; -} - -static inline void mac802154_txdesc_free(FAR struct ieee802154_privmac_s *priv, - FAR struct ieee802154_txdesc_s *txdesc) -{ - sq_addlast((FAR sq_entry_t *)txdesc, &priv->txdesc_queue); - mac802154_givesem(&priv->txdesc_sem); -} - -/**************************************************************************** - * Name: mac802154_timercancel - * - * Description: - * Cancel timer and remove reference to callback function - * - * Assumptions: - * priv MAC struct is locked when calling. - * - ****************************************************************************/ - -static inline int mac802154_timercancel(FAR struct ieee802154_privmac_s *priv) -{ - wd_cancel(priv->timeout); - priv->timeout_worker = NULL; - wlinfo("Timer cancelled\n"); - return OK; -} - -static inline void mac802154_rxenable(FAR struct ieee802154_privmac_s *priv) -{ - priv->nrxusers++; - - /* If this is the first user, actually enable the receiver */ - - if (priv->nrxusers == 1) - { - wlinfo("Receiver enabled\n"); - priv->radio->rxenable(priv->radio, true); - } -} - -static inline void mac802154_rxdisable(FAR struct ieee802154_privmac_s *priv) -{ - priv->nrxusers--; - - /* If this is the first user, actually enable the receiver */ - - if (priv->nrxusers == 0) - { - wlinfo("Receiver disabled\n"); - priv->radio->rxenable(priv->radio, true); - priv->radio->rxenable(priv->radio, false); - } -} - -static inline void mac802154_setchannel(FAR struct ieee802154_privmac_s *priv, - uint8_t channel) -{ - priv->radio->setattr(priv->radio, IEEE802154_ATTR_PHY_CHAN, - (FAR const union ieee802154_attr_u *)&channel); -} - -static inline void mac802154_setchpage(FAR struct ieee802154_privmac_s *priv, - uint8_t chpage) -{ - priv->radio->setattr(priv->radio, IEEE802154_ATTR_PHY_CURRENT_PAGE, - (FAR const union ieee802154_attr_u *)&chpage); -} - -static inline void mac802154_setpanid(FAR struct ieee802154_privmac_s *priv, - const uint8_t *panid) -{ - IEEE802154_PANIDCOPY(priv->addr.panid, panid); - priv->radio->setattr(priv->radio, IEEE802154_ATTR_MAC_PANID, - (FAR const union ieee802154_attr_u *)panid); -} - -static inline void mac802154_setsaddr(FAR struct ieee802154_privmac_s *priv, - const uint8_t *saddr) -{ - IEEE802154_SADDRCOPY(priv->addr.saddr, saddr); - priv->radio->setattr(priv->radio, IEEE802154_ATTR_MAC_SADDR, - (FAR const union ieee802154_attr_u *)saddr); -} - -static inline void mac802154_seteaddr(FAR struct ieee802154_privmac_s *priv, - const uint8_t *eaddr) -{ - IEEE802154_EADDRCOPY(priv->addr.eaddr, eaddr); - priv->radio->setattr(priv->radio, IEEE802154_ATTR_MAC_EADDR, - (FAR const union ieee802154_attr_u *)eaddr); -} - -static inline void mac802154_setcoordsaddr(FAR struct ieee802154_privmac_s *priv, - const uint8_t *saddr) -{ - IEEE802154_SADDRCOPY(priv->pandesc.coordaddr.saddr, saddr); - priv->radio->setattr(priv->radio, IEEE802154_ATTR_MAC_COORD_SADDR, - (FAR const union ieee802154_attr_u *)saddr); -} - -static inline void mac802154_setcoordeaddr(FAR struct ieee802154_privmac_s *priv, - const uint8_t *eaddr) -{ - IEEE802154_EADDRCOPY(priv->pandesc.coordaddr.eaddr, eaddr); - priv->radio->setattr(priv->radio, IEEE802154_ATTR_MAC_COORD_EADDR, - (FAR const union ieee802154_attr_u *)eaddr); -} - -static inline void mac802154_setcoordaddr(FAR struct ieee802154_privmac_s *priv, - FAR const struct ieee802154_addr_s *addr) -{ - memcpy(&priv->pandesc.coordaddr, addr, sizeof(struct ieee802154_addr_s)); - priv->radio->setattr(priv->radio, IEEE802154_ATTR_MAC_COORD_EADDR, - (FAR const union ieee802154_attr_u *)addr->eaddr); - priv->radio->setattr(priv->radio, IEEE802154_ATTR_MAC_COORD_SADDR, - (FAR const union ieee802154_attr_u *)addr->saddr); -} - -static inline void mac802154_setrxonidle(FAR struct ieee802154_privmac_s *priv, - bool rxonidle) -{ - priv->rxonidle = true; - if (priv->rxonidle) - { - mac802154_rxenable(priv); - } - else - { - mac802154_rxdisable(priv); - } - - /* Unlike other attributes, we can't simply cast this one since it is a bit - * in a bitfield. Casting it will give us unpredicatble results. Instead - * of creating a ieee802154_attr_u, we use a local bool. Allocating the - * ieee802154_attr_u value would take up more room on the stack since it is - * as large as the largest attribute type. - */ - - priv->radio->setattr(priv->radio, IEEE802154_ATTR_MAC_RX_ON_WHEN_IDLE, - (FAR const union ieee802154_attr_u *)&rxonidle); -} - -#endif /* __WIRELESS_IEEE802154__MAC802154_INTERNAL_H */ +/**************************************************************************** + * wireless/ieee802154/mac802154_internal.h + * + * Copyright (C) 2016 Sebastien Lorquet. All rights reserved. + * Copyright (C) 2017 Verge Inc. All rights reserved. + * Copyright (C) 2017 Gregory Nutt. All rights reserved. + * + * Author: Sebastien Lorquet + * Author: Anthony Merlino + * + * The naming and comments for various fields are taken directly + * from the IEEE 802.15.4 2011 standard. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +#ifndef __WIRELESS_IEEE802154__MAC802154_INTERNAL_H +#define __WIRELESS_IEEE802154__MAC802154_INTERNAL_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include +#include +#include +#include + +#include +#include + +#include "mac802154_notif.h" + +#include +#include + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* Configuration ************************************************************/ +/* If processing is not done at the interrupt level, then work queue support + * is required. + */ + +#if !defined(CONFIG_SCHED_WORKQUEUE) +# error Work queue support is required in this configuration (CONFIG_SCHED_WORKQUEUE) +#else + + /* Use the low priority work queue if possible */ + +# if defined(CONFIG_MAC802154_HPWORK) +# define MAC802154_WORK HPWORK +# elif defined(CONFIG_MAC802154_LPWORK) +# define MAC802154_WORK LPWORK +# else +# error Neither CONFIG_MAC802154_HPWORK nor CONFIG_MAC802154_LPWORK defined +# endif +#endif + +#if !defined(CONFIG_MAC802154_NNOTIF) || CONFIG_MAC802154_NNOTIF <= 0 +# undef CONFIG_MAC802154_NNOTIF +# define CONFIG_MAC802154_NNOTIF 6 +#endif + +#if !defined(CONFIG_MAC802154_NTXDESC) || CONFIG_MAC802154_NTXDESC <= 0 +# undef CONFIG_MAC802154_NTXDESC +# define CONFIG_MAC802154_NTXDESC 3 +#endif + +#if CONFIG_MAC802154_NTXDESC > CONFIG_MAC802154_NNOTIF +# error CONFIG_MAC802154_NNOTIF must be greater than CONFIG_MAC802154_NTXDESC +#endif + +#if !defined(CONFIG_IEEE802154_DEFAULT_EADDR) +# define CONFIG_IEEE802154_DEFAULT_EADDR 0xFFFFFFFFFFFFFFFF +#endif + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/* Map between ieee802154_addrmode_e enum and actual address length */ + +static const uint8_t mac802154_addr_length[4] = {0, 0, 2, 8}; + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +struct mac802154_radiocb_s +{ + struct ieee802154_radiocb_s cb; + FAR struct ieee802154_privmac_s *priv; +}; + +/* Enumeration for representing what operation the MAC layer is currently doing. + * There can only be one command being handled at any given time, but certain + * operations such as association requires more than one command to be sent. + * Therefore, the need to track not only what command is currently active, but + * also, what overall operation the command is apart of is necessary. + */ + +enum mac802154_operation_e +{ + MAC802154_OP_NONE, + MAC802154_OP_ASSOC, + MAC802154_OP_POLL, + MAC802154_OP_SCAN, + MAC802154_OP_AUTOEXTRACT, +}; + +struct ieee802154_privmac_s; /* Forward Reference */ +typedef void (*mac802154_worker_t)(FAR struct ieee802154_privmac_s *priv); + +/* The privmac structure holds the internal state of the MAC and is the + * underlying represention of the opaque MACHANDLE. It contains storage for + * the IEEE802.15.4 MIB attributes. + */ + +struct ieee802154_privmac_s +{ + /*************************** General Fields *********************************/ + + FAR struct ieee802154_radio_s *radio; /* Contained IEEE802.15.4 radio dev */ + FAR struct mac802154_maccb_s *cb; /* Head of a list of MAC callbacks */ + FAR struct mac802154_radiocb_s radiocb; /* Interface to bind to radio */ + + sem_t exclsem; /* Support exclusive access */ + uint8_t nclients; /* Number of notification clients */ + + /* Only support a single command at any given time. As of now I see no + * condition where you need to have more than one command frame simultaneously + */ + + sem_t opsem; /* Exclusive operations */ + + /******************* Fields related to MAC operations ***********************/ + + enum mac802154_operation_e curr_op; /* The current overall operation */ + enum ieee802154_cmdid_e curr_cmd; /* Type of the current cmd */ + FAR struct ieee802154_txdesc_s *cmd_desc; /* TX descriptor for current cmd */ + uint8_t nrxusers; + + /******************* Fields related to SCAN operation ***********************/ + + /* List of PAN descriptors to track during scan procedures */ + + uint8_t scanindex; + uint8_t npandesc; + struct ieee802154_pandesc_s pandescs[MAC802154_NPANDESC]; + uint8_t panidbeforescan[IEEE802154_PANIDSIZE]; + struct ieee802154_scan_req_s currscan; + uint32_t scansymdur; + + /******************* Fields related to notifications ************************/ + + /* Pre-allocated notifications to be passed to the registered callback. These + * need to be freed by the application using mac802154_xxxxnotif_free when + * the callee layer is finished with it's use. + */ + + FAR struct mac802154_notif_s *notif_free; + struct mac802154_notif_s notif_pool[CONFIG_MAC802154_NNOTIF]; + sem_t notif_sem; + + /******************* Tx descriptor queues and pools *************************/ + + struct ieee802154_txdesc_s txdesc_pool[CONFIG_MAC802154_NTXDESC]; + sem_t txdesc_sem; + sq_queue_t txdesc_queue; + sq_queue_t txdone_queue; + + /* 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 + * during the CAP of the Coordinator's superframe. + */ + + sq_queue_t csma_queue; + sq_queue_t gts_queue; + + /* Support a singly linked list of transactions that will be sent indirectly. + * This list should only be used by a MAC acting as a coordinator. These + * transactions will stay here until the data is extracted by the destination + * device sending a Data Request MAC command or if too much time passes. This + * list should also be used to populate the address list of the outgoing + * beacon frame. + */ + + sq_queue_t indirect_queue; + + /* Support a singly linked list of frames received */ + + sq_queue_t dataind_queue; + + /************* Fields related to addressing and coordinator *****************/ + + /* Holds all address information (Extended, Short, and PAN ID) for the MAC. */ + + struct ieee802154_addr_s addr; + + struct ieee802154_pandesc_s pandesc; + + /*************** Fields related to beacon-enabled networks ******************/ + + /* Holds attributes pertaining to the superframe specification */ + + struct ieee802154_superframespec_s sfspec; + + /* We use 2 beacon frame structures so that we can ping-pong between them + * while updating the beacon + */ + + struct ieee802154_beaconframe_s beaconframe[2]; + + /* Contents of beacon payload */ + + uint8_t beaconpayload[IEEE802154_MAX_BEACON_PAYLOAD_LEN]; + uint8_t beaconpayloadlength; + + /****************** Fields related to offloading work ***********************/ + + /* Work structures for offloading aynchronous work */ + + struct work_s tx_work; + struct work_s rx_work; + + struct work_s timeout_work; + WDOG_ID timeout; /* Timeout watchdog */ + mac802154_worker_t timeout_worker; + + struct work_s purge_work; + + /****************** Uncategorized MAC PIB attributes ***********************/ + + /* The maximum number of symbols to wait for an acknowledgement frame to + * arrive following a transmitted data frame. [1] pg. 126 + * + * NOTE: This may be able to be a 16-bit or even an 8-bit number. I wasn't + * sure at the time what the range of reasonable values was. + */ + + uint32_t ack_waitdur; + + /* The maximum time to wait either for a frame intended as a response to a + * data request frame or for a broadcast frame following a beacon with the + * Frame Pending field set to one. [1] pg. 127 + * + * NOTE: This may be able to be a 16-bit or even an 8-bit number. I wasn't + * sure at the time what the range of reasonable values was. + */ + + uint32_t max_frame_waittime; + + /* The maximum time (in unit periods) that a transaction is stored by a + * coordinator and indicated in its beacon. + */ + + uint16_t trans_persisttime; + + uint8_t dsn; /* Seq. num added to tx data or MAC frame */ + + /* The maximum time, in multiples of aBaseSuperframeDuration, a device shall + * wait for a response command frame to be available following a request + * command frame. [1] 128. + */ + + uint8_t resp_waittime; + + /* The total transmit duration (including PHY header and FCS) specified in + * symbols. [1] pg. 129. + */ + + uint32_t tx_totaldur; + + /* Start of 8-bit bitfield */ + + uint32_t trackingbeacon : 1; /* Are we tracking the beacon */ + uint32_t isassoc : 1; /* Are we associated to the PAN */ + uint32_t autoreq : 1; /* Automatically send data req. if addr + * addr is in the beacon frame */ + + uint32_t gtspermit : 1; /* Is PAN Coord. accepting GTS reqs. */ + uint32_t promisc : 1; /* Is promiscuous mode on? */ + uint32_t rngsupport : 1; /* Does MAC sublayer support ranging */ + uint32_t sec_enabled : 1; /* Does MAC sublayer have security en. */ + uint32_t timestamp_support : 1; /* Does MAC layer supports timestamping */ + + /* End of 8-bit bitfield */ + + /* Start of 32-bit bitfield */ + + /* The offset, measured is symbols, between the symbol boundary at which the + * MLME captures the timestamp of each transmitted and received frame, and + * the onset of the first symbol past the SFD, namely the first symbol of + * the frames [1] pg. 129. + */ + + uint32_t sync_symboffset : 12; + + uint32_t txctrl_activedur : 17; /* Duration for which tx is permitted to + * be active */ + uint32_t txctrl_pausedur : 1; /* Duration after tx before another tx is + * permitted. 0=2000, 1= 10000 */ + + /* What type of device is this node acting as */ + + enum ieee802154_devmode_e devmode : 2; + + /* End of 32-bit bitfield */ + + /* Start of 32-bit bitfield */ + + uint32_t beacon_txtime : 24; /* Time of last beacon transmit */ + uint32_t minbe : 4; /* Min value of backoff exponent (BE) */ + uint32_t maxbe : 4; /* Max value of backoff exponent (BE) */ + + /* End of 32-bit bitfield */ + + /* Start of 8-bit bitfield */ + + uint8_t bf_ind : 1; /* Ping-pong index for beacon frame */ + uint8_t beaconupdate : 1; /* Does the beacon frame need to be updated */ + uint8_t max_csmabackoffs : 3; /* Max num backoffs for CSMA algorithm + * before declaring ch access failure */ + uint8_t maxretries : 3; /* Max # of retries allowed after tx fail */ + /* End of 8-bit bitfield. */ + + /* Start of 8-bit bitfield */ + + uint8_t rxonidle : 1; /* Receiver on when idle? */ + + /* End of 8-bit bitfield. */ + + + + /* TODO: Add Security-related MAC PIB attributes */ +}; + +/**************************************************************************** + * Function Prototypes + ****************************************************************************/ + +int mac802154_txdesc_alloc(FAR struct ieee802154_privmac_s *priv, + FAR struct ieee802154_txdesc_s **txdesc, + bool allow_interrupt); + +int mac802154_timerstart(FAR struct ieee802154_privmac_s *priv, + uint32_t numsymbols, mac802154_worker_t); + +void mac802154_setupindirect(FAR struct ieee802154_privmac_s *priv, + FAR struct ieee802154_txdesc_s *txdesc); + +void mac802154_createdatareq(FAR struct ieee802154_privmac_s *priv, + FAR struct ieee802154_addr_s *coordaddr, + enum ieee802154_addrmode_e srcmode, + FAR struct ieee802154_txdesc_s *txdesc); + +void mac802154_updatebeacon(FAR struct ieee802154_privmac_s *priv); + +/**************************************************************************** + * Helper Macros/Inline Functions + ****************************************************************************/ + +#define mac802154_putpanid(iob, panid) \ + do \ + { \ + IEEE802154_PANIDCOPY(&iob->io_data[iob->io_len], panid); \ + iob->io_len += IEEE802154_PANIDSIZE; \ + } \ + while(0) + +#define mac802154_putsaddr(iob, saddr) \ + do \ + { \ + IEEE802154_SADDRCOPY(&iob->io_data[iob->io_len], saddr); \ + iob->io_len += IEEE802154_SADDRSIZE; \ + } \ + while(0) + +#define mac802154_puteaddr(iob, eaddr) \ + do \ + { \ + IEEE802154_EADDRCOPY(&iob->io_data[iob->io_len], eaddr); \ + iob->io_len += IEEE802154_EADDRSIZE; \ + } \ + while(0) + +#define mac802154_takepanid(iob, panid) \ + do \ + { \ + IEEE802154_PANIDCOPY(panid, &iob->io_data[iob->io_offset]); \ + iob->io_offset += IEEE802154_PANIDSIZE; \ + } \ + while(0) + +#define mac802154_takesaddr(iob, saddr) \ + do \ + { \ + IEEE802154_SADDRCOPY(saddr, &iob->io_data[iob->io_offset]); \ + iob->io_offset += IEEE802154_SADDRSIZE; \ + } \ + while(0) + +#define mac802154_takeeaddr(iob, eaddr) \ + do \ + { \ + IEEE802154_EADDRCOPY(eaddr, &iob->io_data[iob->io_offset]); \ + iob->io_offset += IEEE802154_EADDRSIZE; \ + } \ + while(0) + +/* General helper macros ****************************************************/ + +/* GET 16-bit data: source in network order, result in host order */ + +#define GETHOST16(ptr,index) \ + ((((uint16_t)((ptr)[(index) + 1])) << 8) | ((uint16_t)(((ptr)[index])))) + +/* GET 16-bit data: source in network order, result in network order */ + +#define GETNET16(ptr,index) \ + ((((uint16_t)((ptr)[index])) << 8) | ((uint16_t)(((ptr)[(index) + 1])))) + +/* PUT 16-bit data: source in host order, result in network order */ + +#define PUTHOST16(ptr,index,value) \ + do \ + { \ + (ptr)[index] = (uint16_t)(value) & 0xff; \ + (ptr)[index + 1] = ((uint16_t)(value) >> 8) & 0xff; \ + } \ + while(0) + +/* Set bit in 16-bit value: source in host order, result in network order. */ + +#define IEEE802154_SETBITS_U16(ptr,index,value) \ + do \ + { \ + (ptr)[index] |= (uint16_t)(value) & 0xff; \ + (ptr)[index + 1] |= ((uint16_t)(value) >> 8) & 0xff; \ + } \ + while(0) + +/* Helper macros for setting/receiving bits for frame control field */ + +#define IEEE802154_SETFTYPE(ptr, index, ftype) \ + IEEE802154_SETBITS_U16(ptr, index, (ftype << IEEE802154_FRAMECTRL_SHIFT_FTYPE)) + +#define IEEE802154_SETACKREQ(ptr, index) \ + IEEE802154_SETBITS_U16(ptr, index, IEEE802154_FRAMECTRL_ACKREQ) + +#define IEEE802154_SETDADDRMODE(ptr, index, mode) \ + IEEE802154_SETBITS_U16(ptr, index, (mode << IEEE802154_FRAMECTRL_SHIFT_DADDR)) + +#define IEEE802154_SETSADDRMODE(ptr, index, mode) \ + IEEE802154_SETBITS_U16(ptr, index, (mode << IEEE802154_FRAMECTRL_SHIFT_SADDR)) + +#define IEEE802154_SETPANIDCOMP(ptr, index) \ + IEEE802154_SETBITS_U16(ptr, index, IEEE802154_FRAMECTRL_PANIDCOMP) + +#define IEEE802154_SETVERSION(ptr, index, version) \ + IEEE802154_SETBITS_U16(ptr, index, (version << IEEE802154_FRAMECTRL_SHIFT_VERSION)) + +/* Helper macros for setting/receiving bits for superframe specification */ + +#define IEEE802154_SETBEACONORDER(ptr, index, val) \ + IEEE802154_SETBITS_U16(ptr, index, (val << IEEE802154_SFSPEC_SHIFT_BEACONORDER)) + +#define IEEE802154_SETSFORDER(ptr, index, val) \ + IEEE802154_SETBITS_U16(ptr, index, (val << IEEE802154_SFSPEC_SHIFT_SFORDER)) + +#define IEEE802154_SETFINCAPSLOT(ptr, index, val) \ + IEEE802154_SETBITS_U16(ptr, index, (val << IEEE802154_SFSPEC_SHIFT_FINCAPSLOT)) + +#define IEEE802154_SETBLE(ptr, index) \ + IEEE802154_SETBITS_U16(ptr, index, IEEE802154_SFSPEC_BLE) + +#define IEEE802154_SETPANCOORD(ptr, index) \ + IEEE802154_SETBITS_U16(ptr, index, IEEE802154_SFSPEC_PANCOORD) + +#define IEEE802154_SETASSOCPERMIT(ptr, index) \ + IEEE802154_SETBITS_U16(ptr, index, IEEE802154_SFSPEC_ASSOCPERMIT) + +#define IEEE802154_GETBEACONORDER(ptr, index) \ + ((GETHOST16(ptr, index) & IEEE802154_SFSPEC_BEACONORDER) >> \ + IEEE802154_SFSPEC_SHIFT_BEACONORDER) + +#define IEEE802154_GETSFORDER(ptr, index) \ + ((GETHOST16(ptr, index) & IEEE802154_SFSPEC_SFORDER) >> \ + IEEE802154_SFSPEC_SHIFT_SFORDER) + +#define IEEE802154_GETFINCAPSLOT(ptr, index) \ + ((GETHOST16(ptr, index) & IEEE802154_SFSPEC_FINCAPSLOT) >> \ + IEEE802154_SFSPEC_SHIFT_FINCAPSLOT) + +#define IEEE802154_GETBLE(ptr, index) \ + ((GETHOST16(ptr, index) & IEEE802154_SFSPEC_BLE) >> \ + IEEE802154_SFSPEC_SHIFT_BLE) + +#define IEEE802154_GETPANCOORD(ptr, index) \ + ((GETHOST16(ptr, index) & IEEE802154_SFSPEC_PANCOORD) >> \ + IEEE802154_SFSPEC_SHIFT_PANCOORD) + +#define IEEE802154_GETASSOCPERMIT(ptr, index) \ + ((GETHOST16(ptr, index) & IEEE802154_SFSPEC_ASSOCPERMIT) >> \ + IEEE802154_SFSPEC_SHIFT_ASSOCPERMIT) + +/* Helper macros for setting/receiving bits for GTS specification */ + +#define IEEE802154_GETGTSDESCCOUNT(ptr, index) \ + ((GETHOST16(ptr, index) & IEEE802154_GTSSPEC_DESCCOUNT) >> \ + IEEE802154_GTSSPEC_SHIFT_DESCCOUNT) + +#define IEEE802154_GETGTSPERMIT(ptr, index) \ + ((GETHOST16(ptr, index) & IEEE802154_GTSSPEC_PERMIT) >> \ + IEEE802154_GTSSPEC_SHIFT_PERMIT) + +/* Helper macros for setting/receiving bits for GTS Directions */ + +#define IEEE802154_GETGTSDIRMASK(ptr, index) \ + ((GETHOST16(ptr, index) & IEEE802154_GTSDIR_MASK) >> \ + IEEE802154_GTSDIR_SHIFT_MASK) + +/* Helper macros for setting/receiving bits for Pending Address Specification */ + +#define IEEE802154_GETNPENDSADDR(ptr, index) \ + ((GETHOST16(ptr, index) & IEEE802154_PENDADDR_NSADDR) >> \ + IEEE802154_PENDADDR_SHIFT_NSADDR) + +#define IEEE802154_GETNPENDEADDR(ptr, index) \ + ((GETHOST16(ptr, index) & IEEE802154_PENDADDR_NEADDR) >> \ + IEEE802154_PENDADDR_SHIFT_NEADDR) + +/* General helpers **********************************************************/ + +#define mac802154_givesem(s) sem_post(s) + +static inline int mac802154_takesem(sem_t *sem, bool allowinterrupt) +{ + int ret; + do + { + /* Take a count from the semaphore, possibly waiting */ + + ret = sem_wait(sem); + if (ret < 0) + { + /* EINTR is the only error that we expect */ + + DEBUGASSERT(get_errno() == EINTR); + + if (allowinterrupt) + { + return -EINTR; + } + } + } + while (ret != OK); + + return OK; +} + +#define mac802154_unlock(dev) \ + mac802154_givesem(&dev->exclsem); \ + wlinfo("MAC unlocked\n"); + +#define mac802154_lock(dev, allowinterrupt) \ + mac802154_lockpriv(dev, allowinterrupt, __FUNCTION__) + +static inline int mac802154_lockpriv(FAR struct ieee802154_privmac_s *dev, + bool allowinterrupt, FAR const char *funcname) +{ + int ret; + + wlinfo("Locking MAC: %s\n", funcname); + ret = mac802154_takesem(&dev->exclsem, allowinterrupt); + if (ret < 0) + { + wlinfo("Failed to lock MAC\n"); + } + else + { + wlinfo("MAC locked\n"); + } + + return ret; +} + +static inline void mac802154_txdesc_free(FAR struct ieee802154_privmac_s *priv, + FAR struct ieee802154_txdesc_s *txdesc) +{ + sq_addlast((FAR sq_entry_t *)txdesc, &priv->txdesc_queue); + mac802154_givesem(&priv->txdesc_sem); +} + +/**************************************************************************** + * Name: mac802154_timercancel + * + * Description: + * Cancel timer and remove reference to callback function + * + * Assumptions: + * priv MAC struct is locked when calling. + * + ****************************************************************************/ + +static inline int mac802154_timercancel(FAR struct ieee802154_privmac_s *priv) +{ + wd_cancel(priv->timeout); + priv->timeout_worker = NULL; + wlinfo("Timer cancelled\n"); + return OK; +} + +static inline void mac802154_rxenable(FAR struct ieee802154_privmac_s *priv) +{ + priv->nrxusers++; + + /* If this is the first user, actually enable the receiver */ + + if (priv->nrxusers == 1) + { + wlinfo("Receiver enabled\n"); + priv->radio->rxenable(priv->radio, true); + } +} + +static inline void mac802154_rxdisable(FAR struct ieee802154_privmac_s *priv) +{ + priv->nrxusers--; + + /* If this is the first user, actually enable the receiver */ + + if (priv->nrxusers == 0) + { + wlinfo("Receiver disabled\n"); + priv->radio->rxenable(priv->radio, true); + priv->radio->rxenable(priv->radio, false); + } +} + +static inline void mac802154_setchannel(FAR struct ieee802154_privmac_s *priv, + uint8_t channel) +{ + priv->radio->setattr(priv->radio, IEEE802154_ATTR_PHY_CHAN, + (FAR const union ieee802154_attr_u *)&channel); +} + +static inline void mac802154_setchpage(FAR struct ieee802154_privmac_s *priv, + uint8_t chpage) +{ + priv->radio->setattr(priv->radio, IEEE802154_ATTR_PHY_CURRENT_PAGE, + (FAR const union ieee802154_attr_u *)&chpage); +} + +static inline void mac802154_setpanid(FAR struct ieee802154_privmac_s *priv, + const uint8_t *panid) +{ + IEEE802154_PANIDCOPY(priv->addr.panid, panid); + priv->radio->setattr(priv->radio, IEEE802154_ATTR_MAC_PANID, + (FAR const union ieee802154_attr_u *)panid); +} + +static inline void mac802154_setsaddr(FAR struct ieee802154_privmac_s *priv, + const uint8_t *saddr) +{ + IEEE802154_SADDRCOPY(priv->addr.saddr, saddr); + priv->radio->setattr(priv->radio, IEEE802154_ATTR_MAC_SADDR, + (FAR const union ieee802154_attr_u *)saddr); +} + +static inline void mac802154_seteaddr(FAR struct ieee802154_privmac_s *priv, + const uint8_t *eaddr) +{ + IEEE802154_EADDRCOPY(priv->addr.eaddr, eaddr); + priv->radio->setattr(priv->radio, IEEE802154_ATTR_MAC_EADDR, + (FAR const union ieee802154_attr_u *)eaddr); +} + +static inline void mac802154_setcoordsaddr(FAR struct ieee802154_privmac_s *priv, + const uint8_t *saddr) +{ + IEEE802154_SADDRCOPY(priv->pandesc.coordaddr.saddr, saddr); + priv->radio->setattr(priv->radio, IEEE802154_ATTR_MAC_COORD_SADDR, + (FAR const union ieee802154_attr_u *)saddr); +} + +static inline void mac802154_setcoordeaddr(FAR struct ieee802154_privmac_s *priv, + const uint8_t *eaddr) +{ + IEEE802154_EADDRCOPY(priv->pandesc.coordaddr.eaddr, eaddr); + priv->radio->setattr(priv->radio, IEEE802154_ATTR_MAC_COORD_EADDR, + (FAR const union ieee802154_attr_u *)eaddr); +} + +static inline void mac802154_setcoordaddr(FAR struct ieee802154_privmac_s *priv, + FAR const struct ieee802154_addr_s *addr) +{ + memcpy(&priv->pandesc.coordaddr, addr, sizeof(struct ieee802154_addr_s)); + priv->radio->setattr(priv->radio, IEEE802154_ATTR_MAC_COORD_EADDR, + (FAR const union ieee802154_attr_u *)addr->eaddr); + priv->radio->setattr(priv->radio, IEEE802154_ATTR_MAC_COORD_SADDR, + (FAR const union ieee802154_attr_u *)addr->saddr); +} + +static inline void mac802154_setrxonidle(FAR struct ieee802154_privmac_s *priv, + bool rxonidle) +{ + priv->rxonidle = true; + if (priv->rxonidle) + { + mac802154_rxenable(priv); + } + else + { + mac802154_rxdisable(priv); + } + + /* Unlike other attributes, we can't simply cast this one since it is a bit + * in a bitfield. Casting it will give us unpredicatble results. Instead + * of creating a ieee802154_attr_u, we use a local bool. Allocating the + * ieee802154_attr_u value would take up more room on the stack since it is + * as large as the largest attribute type. + */ + + priv->radio->setattr(priv->radio, IEEE802154_ATTR_MAC_RX_ON_WHEN_IDLE, + (FAR const union ieee802154_attr_u *)&rxonidle); +} + +#endif /* __WIRELESS_IEEE802154__MAC802154_INTERNAL_H */ From 19de3372b700713cbd431c898d2fc42ce9329de7 Mon Sep 17 00:00:00 2001 From: Anthony Merlino Date: Sun, 9 Jul 2017 18:38:56 -0400 Subject: [PATCH 19/54] ieee802154: Minor renaming. purge_time -> purgetime --- include/nuttx/wireless/ieee802154/ieee802154_radio.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/nuttx/wireless/ieee802154/ieee802154_radio.h b/include/nuttx/wireless/ieee802154/ieee802154_radio.h index b6e802e0ea..7617d03685 100644 --- a/include/nuttx/wireless/ieee802154/ieee802154_radio.h +++ b/include/nuttx/wireless/ieee802154/ieee802154_radio.h @@ -84,7 +84,7 @@ struct ieee802154_txdesc_s * control how tx done is handled */ bool framepending; /* Did the ACK have the frame pending bit * bit set */ - uint32_t purge_time; /* Time to purge transaction */ + uint32_t purgetime; /* Time to purge transaction */ /* TODO: Add slotting information for GTS transactions */ }; From 93cdae50fc6ec529eb40f3b813decf3f1fc02a33 Mon Sep 17 00:00:00 2001 From: Anthony Merlino Date: Sun, 9 Jul 2017 23:55:48 -0400 Subject: [PATCH 20/54] ieee802154: Improves internal timer logic to handle work serially Before, the MAC timer used a watchdog to schedule work with the high priority worker queue. However, since everything in the MAC is supposed to be serialized through the use of the high priority work queue, but the timer uses a watchdog, there are some unintended consequences. To simplify, we now use the delayed work feature of the work queue. --- wireless/ieee802154/mac802154.c | 130 ----------------------- wireless/ieee802154/mac802154_assoc.c | 16 ++- wireless/ieee802154/mac802154_internal.h | 86 ++++++++++++--- wireless/ieee802154/mac802154_poll.c | 18 +++- wireless/ieee802154/mac802154_scan.c | 5 +- 5 files changed, 106 insertions(+), 149 deletions(-) diff --git a/wireless/ieee802154/mac802154.c b/wireless/ieee802154/mac802154.c index 3a7989e9d8..cf7ebba212 100644 --- a/wireless/ieee802154/mac802154.c +++ b/wireless/ieee802154/mac802154.c @@ -92,13 +92,6 @@ static void mac802154_sfevent(FAR const struct ieee802154_radiocb_s *radiocb, static void mac802154_purge_worker(FAR void *arg); -/* Watchdog Timeout Functions */ - -static void mac802154_timeout_expiry(int argc, wdparm_t arg, ...); - -static uint32_t mac802154_symtoticks(FAR struct ieee802154_privmac_s *priv, - uint32_t symbols); - static void mac802154_rxdatareq(FAR struct ieee802154_privmac_s *priv, FAR struct ieee802154_data_ind_s *ind); static void mac802154_rxdataframe(FAR struct ieee802154_privmac_s *priv, @@ -1918,125 +1911,6 @@ errout: mac802154_notif_free_locked(priv, notif); } -/**************************************************************************** - * Name: mac802154_symtoticks - * - * Description: - * Helper function for converting symbols to system clock ticks - * - * Assumptions: - * priv MAC struct is locked when calling. - * - ****************************************************************************/ - -static uint32_t mac802154_symtoticks(FAR struct ieee802154_privmac_s *priv, - uint32_t symbols) -{ - union ieee802154_attr_u attrval; - uint32_t ret; - - /* First, get the symbol duration from the radio layer. Symbol duration is - * returned in picoseconds to ensure precision is kept when multiplying to - * get overall times. - */ - - priv->radio->getattr(priv->radio, IEEE802154_ATTR_PHY_SYMBOL_DURATION, - &attrval); - - /* After this step, ret represents microseconds */ - - ret = ((uint64_t)attrval.phy.symdur_picosec * symbols) / (1000 * 1000); - - /* This method should only be used for things that can be late. For instance, - * it's always okay to wait a little longer before disabling your receiver. - * Therefore, we force the tick count to round up. - */ - - if (ret % USEC_PER_TICK == 0) - { - ret = ret/USEC_PER_TICK; - } - else - { - ret = ret/USEC_PER_TICK; - ret++; - } - - return ret; -} - -/**************************************************************************** - * Name: mac802154_timerstart - * - * Description: - * Helper function wrapping the watchdog timer interface. Helps isolate - * different operations from having to worry about work queues and watchdog - * timers. - * - * Assumptions: - * priv MAC struct is locked when calling. - * - ****************************************************************************/ - -int mac802154_timerstart(FAR struct ieee802154_privmac_s *priv, - uint32_t numsymbols, mac802154_worker_t worker) -{ - /* TODO: Add check to make sure timer is not already being used. I'd like to - * design this so that it absolutely never happens */ - - /* Convert the number of symbols to the number of CPU ticks */ - - uint32_t ticks = mac802154_symtoticks(priv, numsymbols); - - /* Save the function pointer to call if the timeout expires */ - - priv->timeout_worker = worker; - - /* Start the watchdog */ - - wd_start(priv->timeout, (int32_t)ticks, mac802154_timeout_expiry, - 1, (wdparm_t)priv); - - return OK; -} - -/**************************************************************************** - * Function: mac802154_timeout_expiry - * - * Description: - * The watchdog timed out. Called from the timer interrupt handler. - * - * Parameters: - * argc - The number of available arguments - * arg - The first argument - * - * Returned Value: - * None - * - * Assumptions: - * Global interrupts are disabled by the watchdog logic. - * - ****************************************************************************/ - -static void mac802154_timeout_expiry(int argc, wdparm_t arg, ...) -{ - FAR struct ieee802154_privmac_s *priv = (FAR struct ieee802154_privmac_s *)arg; - - /* There should never be a case where the timeout is used twice at the same - * time. */ - - DEBUGASSERT(work_available(&priv->timeout_work)); - - /* Check to make sure the function pointer is still valid */ - - DEBUGASSERT(priv->timeout_worker != NULL); - - wlinfo("Timer expired\n"); - - work_queue(MAC802154_WORK, &priv->timeout_work, (worker_t)priv->timeout_worker, - priv, 0); -} - /**************************************************************************** * Public Functions ****************************************************************************/ @@ -2092,10 +1966,6 @@ MACHANDLE mac802154_create(FAR struct ieee802154_radio_s *radiodev) sem_init(&mac->opsem, 0, 1); - /* Setup watchdog for extraction timeout */ - - mac->timeout = wd_create(); - /* Initialize fields */ mac->radio = radiodev; diff --git a/wireless/ieee802154/mac802154_assoc.c b/wireless/ieee802154/mac802154_assoc.c index beaf1c34f6..42ee5c4618 100644 --- a/wireless/ieee802154/mac802154_assoc.c +++ b/wireless/ieee802154/mac802154_assoc.c @@ -58,7 +58,7 @@ * Private Function Prototypes ****************************************************************************/ -static void mac802154_assoctimeout(FAR struct ieee802154_privmac_s *priv); +static void mac802154_assoctimeout(FAR void *arg); /**************************************************************************** * Public MAC Functions @@ -858,10 +858,22 @@ void mac802154_rx_assocresp(FAR struct ieee802154_privmac_s *priv, * ****************************************************************************/ -static void mac802154_assoctimeout(FAR struct ieee802154_privmac_s *priv) +static void mac802154_assoctimeout(FAR void *arg) { + FAR struct ieee802154_privmac_s *priv = (FAR struct ieee802154_privmac_s *)arg; FAR struct ieee802154_notif_s *notif; + /* If there is work scheduled for the rxframe_worker, we want to reschedule + * this work, so that we make sure if the frame we were waiting for was just + * received, we don't timeout + */ + + if (!work_available(&priv->rx_work)) + { + work_queue(MAC802154_WORK, &priv->timer_work, mac802154_assoctimeout, priv, 0); + return; + } + DEBUGASSERT(priv->curr_op == MAC802154_OP_ASSOC); /* If the device does not extract an association response command diff --git a/wireless/ieee802154/mac802154_internal.h b/wireless/ieee802154/mac802154_internal.h index fc097cfbf6..6fcfaaeb8e 100644 --- a/wireless/ieee802154/mac802154_internal.h +++ b/wireless/ieee802154/mac802154_internal.h @@ -139,9 +139,6 @@ enum mac802154_operation_e MAC802154_OP_AUTOEXTRACT, }; -struct ieee802154_privmac_s; /* Forward Reference */ -typedef void (*mac802154_worker_t)(FAR struct ieee802154_privmac_s *priv); - /* The privmac structure holds the internal state of the MAC and is the * underlying represention of the opaque MACHANDLE. It contains storage for * the IEEE802.15.4 MIB attributes. @@ -254,12 +251,8 @@ struct ieee802154_privmac_s struct work_s tx_work; struct work_s rx_work; - - struct work_s timeout_work; - WDOG_ID timeout; /* Timeout watchdog */ - mac802154_worker_t timeout_worker; - struct work_s purge_work; + struct work_s timer_work; /****************** Uncategorized MAC PIB attributes ***********************/ @@ -375,9 +368,6 @@ int mac802154_txdesc_alloc(FAR struct ieee802154_privmac_s *priv, FAR struct ieee802154_txdesc_s **txdesc, bool allow_interrupt); -int mac802154_timerstart(FAR struct ieee802154_privmac_s *priv, - uint32_t numsymbols, mac802154_worker_t); - void mac802154_setupindirect(FAR struct ieee802154_privmac_s *priv, FAR struct ieee802154_txdesc_s *txdesc); @@ -624,6 +614,77 @@ static inline void mac802154_txdesc_free(FAR struct ieee802154_privmac_s *priv, mac802154_givesem(&priv->txdesc_sem); } +/**************************************************************************** + * Name: mac802154_symtoticks + * + * Description: + * Helper function for converting symbols to system clock ticks + * + * Assumptions: + * priv MAC struct is locked when calling. + * + ****************************************************************************/ + +static inline uint32_t mac802154_symtoticks(FAR struct ieee802154_privmac_s *priv, + uint32_t symbols) +{ + union ieee802154_attr_u attrval; + uint32_t ret; + + /* First, get the symbol duration from the radio layer. Symbol duration is + * returned in picoseconds to ensure precision is kept when multiplying to + * get overall times. + */ + + priv->radio->getattr(priv->radio, IEEE802154_ATTR_PHY_SYMBOL_DURATION, + &attrval); + + /* After this step, ret represents microseconds */ + + ret = ((uint64_t)attrval.phy.symdur_picosec * symbols) / (1000 * 1000); + + /* This method should only be used for things that can be late. For instance, + * it's always okay to wait a little longer before disabling your receiver. + * Therefore, we force the tick count to round up. + */ + + if (ret % USEC_PER_TICK == 0) + { + ret = ret/USEC_PER_TICK; + } + else + { + ret = ret/USEC_PER_TICK; + ret++; + } + + return ret; +} + +/**************************************************************************** + * Name: mac802154_timerstart + * + * Description: + * Helper function wrapping the watchdog timer interface. Helps isolate + * different operations from having to worry about work queues and watchdog + * timers. + * + * Assumptions: + * priv MAC struct is locked when calling. + * + ****************************************************************************/ + +static inline void mac802154_timerstart(FAR struct ieee802154_privmac_s *priv, + uint32_t numsymbols, worker_t worker) +{ + DEBUGASSERT(work_available(&priv->timer_work)); + + /* Schedule the work, converting the number of symbols to the number of CPU ticks */ + + work_queue(MAC802154_WORK, &priv->timer_work, worker, priv, + mac802154_symtoticks(priv, numsymbols)); +} + /**************************************************************************** * Name: mac802154_timercancel * @@ -637,8 +698,7 @@ static inline void mac802154_txdesc_free(FAR struct ieee802154_privmac_s *priv, static inline int mac802154_timercancel(FAR struct ieee802154_privmac_s *priv) { - wd_cancel(priv->timeout); - priv->timeout_worker = NULL; + work_cancel(MAC802154_WORK, &priv->timer_work); wlinfo("Timer cancelled\n"); return OK; } diff --git a/wireless/ieee802154/mac802154_poll.c b/wireless/ieee802154/mac802154_poll.c index 715518e916..3271a8f92a 100644 --- a/wireless/ieee802154/mac802154_poll.c +++ b/wireless/ieee802154/mac802154_poll.c @@ -60,7 +60,7 @@ * Private Function Prototypes ****************************************************************************/ -static void mac802154_polltimeout(FAR struct ieee802154_privmac_s *priv); +static void mac802154_polltimeout(FAR void *arg); /**************************************************************************** * Public MAC Functions @@ -152,6 +152,8 @@ int mac802154_req_poll(MACHANDLE mac, FAR struct ieee802154_poll_req_s *req) priv->cmd_desc = txdesc; + wlinfo("Queuing POLL.request in CSMA queue\n"); + /* Link the transaction into the CSMA transaction list */ sq_addlast((FAR sq_entry_t *)txdesc, &priv->csma_queue); @@ -259,10 +261,22 @@ void mac802154_txdone_datareq_poll(FAR struct ieee802154_privmac_s *priv, * ****************************************************************************/ -void mac802154_polltimeout(FAR struct ieee802154_privmac_s *priv) +void mac802154_polltimeout(FAR void *arg) { + FAR struct ieee802154_privmac_s *priv = (FAR struct ieee802154_privmac_s *)arg; FAR struct ieee802154_notif_s *notif; + /* If there is work scheduled for the rxframe_worker, we want to reschedule + * this work, so that we make sure if the frame we were waiting for was just + * received, we don't timeout + */ + + if (!work_available(&priv->rx_work)) + { + work_queue(MAC802154_WORK, &priv->timer_work, mac802154_polltimeout, priv, 0); + return; + } + DEBUGASSERT(priv->curr_op == MAC802154_OP_POLL); /* Allocate a notification struct to pass to the next highest layer. diff --git a/wireless/ieee802154/mac802154_scan.c b/wireless/ieee802154/mac802154_scan.c index c24ae0b5f1..0c6140b192 100644 --- a/wireless/ieee802154/mac802154_scan.c +++ b/wireless/ieee802154/mac802154_scan.c @@ -60,7 +60,7 @@ * Private Function Prototypes ****************************************************************************/ -static void mac802154_scantimeout(FAR struct ieee802154_privmac_s *priv); +static void mac802154_scantimeout(FAR void *arg); /**************************************************************************** * Public MAC Functions @@ -251,8 +251,9 @@ void mac802154_scanfinish(FAR struct ieee802154_privmac_s *priv, * ****************************************************************************/ -static void mac802154_scantimeout(FAR struct ieee802154_privmac_s *priv) +static void mac802154_scantimeout(FAR void *arg) { + FAR struct ieee802154_privmac_s *priv = (FAR struct ieee802154_privmac_s *)arg; DEBUGASSERT(priv->curr_op == MAC802154_OP_SCAN); /* If we got here it means we are done scanning that channel */ From b9a9ba7dd03a57740dd08a0b015582eb13b7aa36 Mon Sep 17 00:00:00 2001 From: Anthony Merlino Date: Sun, 9 Jul 2017 23:57:11 -0400 Subject: [PATCH 21/54] ieee802154: Adds configuration options for verbose logging of certain features, to aid in debugging --- configs/clicker2-stm32/Kconfig | 7 +++++++ configs/clicker2-stm32/src/stm32_mrf24j40.c | 5 ++++- drivers/wireless/ieee802154/mrf24j40/mrf24j40.c | 3 +++ wireless/ieee802154/Kconfig | 14 ++++++++++++++ wireless/ieee802154/mac802154.c | 2 ++ wireless/ieee802154/mac802154_internal.h | 11 ++++++++++- 6 files changed, 40 insertions(+), 2 deletions(-) diff --git a/configs/clicker2-stm32/Kconfig b/configs/clicker2-stm32/Kconfig index 9344f015da..fb4b89d98a 100644 --- a/configs/clicker2-stm32/Kconfig +++ b/configs/clicker2-stm32/Kconfig @@ -35,4 +35,11 @@ config CLICKER2_STM32_MB2_BEE ---help--- Enable support for MRF24J40 BEE on mikroBUS2 +config CLICKER2_STM32_MRF24J40LH_VERBOSE + bool "Verbose MRF24J40 lowerhalf" + default n + depends on DEBUG_WIRELESS_INFO + ---help--- + Enable verbose syslog for MRF24J40 lowerhalf + endif # ARCH_BOARD_CLICKER2_STM32 diff --git a/configs/clicker2-stm32/src/stm32_mrf24j40.c b/configs/clicker2-stm32/src/stm32_mrf24j40.c index d523fd257b..04737b9941 100644 --- a/configs/clicker2-stm32/src/stm32_mrf24j40.c +++ b/configs/clicker2-stm32/src/stm32_mrf24j40.c @@ -193,9 +193,12 @@ static void stm32_enable_irq(FAR const struct mrf24j40_lower_s *lower, DEBUGASSERT(priv != NULL && (priv->handler != NULL || !state)); +#ifdef CONFIG_CLICKER2_STM32_MRF24J40LH_VERBOSE + wlinfo("state:%d\n", (int)state); +#endif + /* Attach and enable, or detach and disable */ - wlinfo("state:%d\n", (int)state); if (state) { (void)stm32_gpiosetevent(priv->intcfg, true, true, true, diff --git a/drivers/wireless/ieee802154/mrf24j40/mrf24j40.c b/drivers/wireless/ieee802154/mrf24j40/mrf24j40.c index 5098e96253..a6780c1fa7 100644 --- a/drivers/wireless/ieee802154/mrf24j40/mrf24j40.c +++ b/drivers/wireless/ieee802154/mrf24j40/mrf24j40.c @@ -2381,7 +2381,10 @@ static void mrf24j40_irqworker(FAR void *arg) if ((intstat & MRF24J40_INTSTAT_WAKEIF)) { +#ifdef CONFIG_MAC802154_SFEVENT_VERBOSE wlinfo("Wake Interrupt\n"); +#endif + /* This is right before the beacon, we set the bsn here, since the MAC * uses the SLPIF (end of active portion of superframe). to make any * changes to the beacon. This assumes that any changes to the beacon diff --git a/wireless/ieee802154/Kconfig b/wireless/ieee802154/Kconfig index f01ae562d7..11e47bed07 100644 --- a/wireless/ieee802154/Kconfig +++ b/wireless/ieee802154/Kconfig @@ -83,6 +83,20 @@ config MAC802154_NPANDESC information for all unique beacons received. This is the number of unique descriptors that can be held before the scan cancels with LIMIT_REACHED. +config MAC802154_SFEVENT_VERBOSE + bool "Verbose logging related to superframe events" + default n + depends on DEBUG_WIRELESS_INFO + ---help--- + Enable verbose logging of superframe events Default: false + +config MAC802154_LOCK_VERBOSE + bool "Verbose logging related to MAC lock management" + default n + depends on DEBUG_WIRELESS_INFO + ---help--- + Enable verbose logging of MAC lock management. Default: false + config IEEE802154_IND_PREALLOC int "Number of pre-allocated meta-data structures" default 20 diff --git a/wireless/ieee802154/mac802154.c b/wireless/ieee802154/mac802154.c index cf7ebba212..d8a4fddc23 100644 --- a/wireless/ieee802154/mac802154.c +++ b/wireless/ieee802154/mac802154.c @@ -1527,7 +1527,9 @@ static void mac802154_sfevent(FAR const struct ieee802154_radiocb_s *radiocb, { case IEEE802154_SFEVENT_ENDOFACTIVE: { +#ifdef CONFIG_MAC802154_SFEVENT_VERBOSE wlinfo("End of superframe\n"); +#endif /* Check if there is any reason to update the beacon */ diff --git a/wireless/ieee802154/mac802154_internal.h b/wireless/ieee802154/mac802154_internal.h index 6fcfaaeb8e..fd1fd77568 100644 --- a/wireless/ieee802154/mac802154_internal.h +++ b/wireless/ieee802154/mac802154_internal.h @@ -581,9 +581,14 @@ static inline int mac802154_takesem(sem_t *sem, bool allowinterrupt) return OK; } +#ifdef CONFIG_MAC802154_LOCK_VERBOSE #define mac802154_unlock(dev) \ mac802154_givesem(&dev->exclsem); \ wlinfo("MAC unlocked\n"); +#else +#define mac802154_unlock(dev) \ + mac802154_givesem(&dev->exclsem); +#endif #define mac802154_lock(dev, allowinterrupt) \ mac802154_lockpriv(dev, allowinterrupt, __FUNCTION__) @@ -593,15 +598,19 @@ static inline int mac802154_lockpriv(FAR struct ieee802154_privmac_s *dev, { int ret; +#ifdef CONFIG_MAC802154_LOCK_VERBOSE wlinfo("Locking MAC: %s\n", funcname); +#endif ret = mac802154_takesem(&dev->exclsem, allowinterrupt); if (ret < 0) { - wlinfo("Failed to lock MAC\n"); + wlwarn("Failed to lock MAC\n"); } else { +#ifdef CONFIG_MAC802154_LOCK_VERBOSE wlinfo("MAC locked\n"); +#endif } return ret; From 0aabea26621fbd6eb4eeeed713ef761057220e57 Mon Sep 17 00:00:00 2001 From: Anthony Merlino Date: Mon, 10 Jul 2017 01:19:13 -0400 Subject: [PATCH 22/54] drivers/wireless/ieee802154/mrf24j40: Fixes odd extra spacing that mysteriously got introduced --- .../wireless/ieee802154/mrf24j40/mrf24j40.c | 238 ------------------ 1 file changed, 238 deletions(-) diff --git a/drivers/wireless/ieee802154/mrf24j40/mrf24j40.c b/drivers/wireless/ieee802154/mrf24j40/mrf24j40.c index a6780c1fa7..665cd1da19 100644 --- a/drivers/wireless/ieee802154/mrf24j40/mrf24j40.c +++ b/drivers/wireless/ieee802154/mrf24j40/mrf24j40.c @@ -1452,485 +1452,247 @@ static int mrf24j40_settxpower(FAR struct mrf24j40_radio_s *dev, case -1: reg |= 0x02; - break; - - case 0: - reg |= 0x00; /* value 0x01 is 0.5 db, not used */ - break; - - default: return -EINVAL; - } - - mrf24j40_setreg(dev->spi, MRF24J40_RFCON3, reg); dev->txpower = save_txpwr; return OK; - } - - /**************************************************************************** - * Name: mrf24j40_setcca - * - * Description: - * Define the Clear Channel Assessement method. - * - ****************************************************************************/ - - static int mrf24j40_setcca(FAR struct mrf24j40_radio_s *dev, - FAR struct ieee802154_cca_s *cca) - { - uint8_t mode; - - if (!cca->use_ed && !cca->use_cs) - { - return -EINVAL; - } - - if (cca->use_cs && cca->csth > 0x0f) - { - return -EINVAL; - } - - mode = mrf24j40_getreg(dev->spi, MRF24J40_BBREG2); - mode &= 0x03; - - if (cca->use_ed) - { - mode |= MRF24J40_BBREG2_CCAMODE_ED; - mrf24j40_setreg(dev->spi, MRF24J40_CCAEDTH, cca->edth); - } - - if (cca->use_cs) - { - mode |= MRF24J40_BBREG2_CCAMODE_CS; - mode |= cca->csth << 2; - } - - mrf24j40_setreg(dev->spi, MRF24J40_BBREG2, mode); - - memcpy(&dev->cca, cca, sizeof(struct ieee802154_cca_s)); - return OK; - } - - /**************************************************************************** - * Name: mrf24j40_regdump - * - * Description: - * Display the value of all registers. - * - ****************************************************************************/ - - static int mrf24j40_regdump(FAR struct mrf24j40_radio_s *dev) - { - uint32_t i; - char buf[4+16*3+2+1]; - int len = 0; - - wlinfo("Short regs:\n"); - - for (i = 0; i < 0x40; i++) - { - if ((i & 15) == 0) - { - len=sprintf(buf, "%02x: ",i&0xFF); - } - - len += sprintf(buf+len, "%02x ", mrf24j40_getreg(dev->spi, i)); - if ((i & 15) == 15) - { - sprintf(buf+len, "\n"); - wlinfo("%s", buf); - } - } - - wlinfo("Long regs:\n"); for (i = 0x80000200; i < 0x80000250; i++) - { - if ((i & 15) == 0) - { - len=sprintf(buf, "%02x: ",i&0xFF); - } - - len += sprintf(buf+len, "%02x ", mrf24j40_getreg(dev->spi, i)); - if ((i & 15) == 15) - { - sprintf(buf+len, "\n"); - wlinfo("%s", buf); - } - } - - return 0; - } - - /**************************************************************************** - * Name: mrf24j40_energydetect - * - * Description: - * Measure the RSSI level for the current channel. - * - ****************************************************************************/ - - static int mrf24j40_energydetect(FAR struct mrf24j40_radio_s *dev, - FAR uint8_t *energy) - { - uint8_t reg; - - /* Manually enable the LNA*/ - - mrf24j40_pacontrol(dev, MRF24J40_PA_ED); - - /* Set RSSI average duration to 8 symbols */ - - reg = mrf24j40_getreg(dev->spi, MRF24J40_TXBCON1); - reg |= 0x30; - mrf24j40_setreg(dev->spi, MRF24J40_TXBCON1, reg); - - /* 1. Set RSSIMODE1 0x3E<7> – Initiate RSSI calculation. */ - - mrf24j40_setreg(dev->spi, MRF24J40_BBREG6, 0x80); - - /* 2. Wait until RSSIRDY 0x3E<0> is set to ‘1’ – RSSI calculation is - * complete. - */ - - while(!(mrf24j40_getreg(dev->spi, MRF24J40_BBREG6) & 0x01)); - - /* 3. Read RSSI 0x210<7:0> – The RSSI register contains the averaged RSSI - * received power level for 8 symbol periods. - */ - - *energy = mrf24j40_getreg(dev->spi, MRF24J40_RSSI); - - - mrf24j40_setreg(dev->spi, MRF24J40_BBREG6, 0x40); - - /* Back to automatic control */ - - mrf24j40_pacontrol(dev, MRF24J40_PA_AUTO); return OK; - } - - /**************************************************************************** - * Name: mrf24j40_norm_setup - * - * Description: - * Setup a transaction in the normal TX FIFO - * - ****************************************************************************/ - - static void mrf24j40_norm_setup(FAR struct mrf24j40_radio_s *dev, - FAR struct iob_s *frame, bool csma) - { - uint8_t reg; - - /* Enable tx int */ - - reg = mrf24j40_getreg(dev->spi, MRF24J40_INTCON); - reg &= ~MRF24J40_INTCON_TXNIE; - mrf24j40_setreg(dev->spi, MRF24J40_INTCON, reg); - - /* Enable/Disable CSMA mode */ - - reg = mrf24j40_getreg(dev->spi, MRF24J40_TXMCR); - - if (csma) - { - reg &= ~MRF24J40_TXMCR_NOCSMA; - } - else - { - reg |= MRF24J40_TXMCR_NOCSMA; - } - - mrf24j40_setreg(dev->spi, MRF24J40_TXMCR, reg); - - /* Setup the FIFO */ - - mrf24j40_setup_fifo(dev, frame->io_data, frame->io_len, MRF24J40_TXNORM_FIFO); - - /* If the frame control field contains an acknowledgment request, set the - * TXNACKREQ bit. See IEEE 802.15.4/2003 7.2.1.1 page 112 for info. - */ - - reg = mrf24j40_getreg(dev->spi, MRF24J40_TXNCON); - - if (frame->io_data[0] & IEEE802154_FRAMECTRL_ACKREQ) - { - reg |= MRF24J40_TXNCON_TXNACKREQ; - } - else - { - reg &= ~MRF24J40_TXNCON_TXNACKREQ; - } - - mrf24j40_setreg(dev->spi, MRF24J40_TXNCON, reg); - } - - /**************************************************************************** - * Name: mrf24j40_norm_trigger - * - * Description: - * Trigger the normal TX FIFO - * - ****************************************************************************/ - - static inline void mrf24j40_norm_trigger(FAR struct mrf24j40_radio_s *dev) - { - uint8_t reg; - - reg = mrf24j40_getreg(dev->spi, MRF24J40_TXNCON); - - - reg |= MRF24J40_TXNCON_TXNTRIG; - - - mrf24j40_setreg(dev->spi, MRF24J40_TXNCON, reg); - } - - /**************************************************************************** - * Name: mrf24j40_beacon_trigger - * - * Description: - * Trigger the beacon TX FIFO - * - ****************************************************************************/ - - static inline void mrf24j40_beacon_trigger(FAR struct mrf24j40_radio_s *dev) { uint8_t reg; From deeb52cedc1d624174a8e9693ad1122e84b1257a Mon Sep 17 00:00:00 2001 From: Anthony Merlino Date: Mon, 10 Jul 2017 01:51:15 -0400 Subject: [PATCH 23/54] drivers/wireless/ieee802154/mrf24j40: Minor timing fix. Matches recommended value in datasheet --- drivers/wireless/ieee802154/mrf24j40/mrf24j40.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/drivers/wireless/ieee802154/mrf24j40/mrf24j40.c b/drivers/wireless/ieee802154/mrf24j40/mrf24j40.c index 665cd1da19..3e66d9f4cf 100644 --- a/drivers/wireless/ieee802154/mrf24j40/mrf24j40.c +++ b/drivers/wireless/ieee802154/mrf24j40/mrf24j40.c @@ -473,11 +473,16 @@ static int mrf24j40_reset(FAR struct ieee802154_radio_s *radio) mrf24j40_setreg(dev->spi, MRF24J40_ACKTMOUT, 0x39 | MRF24J40_ACKTMOUT_DRPACK); - /* Set WAKECNT (SLPACK 0x35<6:0>) value = 0x5F to set the main oscillator + /* Set WAKECNT (SLPACK 0x35<6:0>) value = 0xC8 to set the main oscillator * (20 MHz) start-up timer value. */ - mrf24j40_setreg(dev->spi, MRF24J40_SLPACK, 0x5F); + mrf24j40_setreg(dev->spi, MRF24J40_SLPACK, 0xC8); + + /* Set WAKETIME to recommended value for 100kHz SLPCLK Source */ + + mrf24j40_setreg(dev->spi, MRF24J40_WAKETIMEL, 0xD2); + mrf24j40_setreg(dev->spi, MRF24J40_WAKETIMEH, 0x00); /* Enable the SLPIF and WAKEIF flags */ From 4b7d743f32a728bd78116735103dafe07bbe1741 Mon Sep 17 00:00:00 2001 From: Anthony Merlino Date: Mon, 10 Jul 2017 01:51:39 -0400 Subject: [PATCH 24/54] configs/clicker2-stm32: Adds support for per-function-call stack checking --- configs/clicker2-stm32/mrf24j40-mac/Make.defs | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/configs/clicker2-stm32/mrf24j40-mac/Make.defs b/configs/clicker2-stm32/mrf24j40-mac/Make.defs index ab1e10dc45..da798a6481 100644 --- a/configs/clicker2-stm32/mrf24j40-mac/Make.defs +++ b/configs/clicker2-stm32/mrf24j40-mac/Make.defs @@ -75,6 +75,11 @@ ifneq ($(CONFIG_DEBUG_NOOPT),y) ARCHOPTIMIZATION += $(MAXOPTIMIZATION) -fno-strict-aliasing -fno-strength-reduce -fomit-frame-pointer endif +# enable precise stack overflow tracking +ifeq ($(CONFIG_ARMV7M_STACKCHECK),y) +INSTRUMENTATIONDEFINES = -finstrument-functions -ffixed-r10 +endif + ARCHCFLAGS = -fno-builtin ARCHCXXFLAGS = -fno-builtin -fno-exceptions -fcheck-new -fno-rtti ARCHWARNINGS = -Wall -Wstrict-prototypes -Wshadow -Wundef @@ -82,9 +87,9 @@ ARCHWARNINGSXX = -Wall -Wshadow -Wundef ARCHDEFINES = ARCHPICFLAGS = -fpic -msingle-pic-base -mpic-register=r10 -CFLAGS = $(ARCHCFLAGS) $(ARCHWARNINGS) $(ARCHOPTIMIZATION) $(ARCHCPUFLAGS) $(ARCHINCLUDES) $(ARCHDEFINES) $(EXTRADEFINES) -pipe +CFLAGS = $(ARCHCFLAGS) $(ARCHWARNINGS) $(ARCHOPTIMIZATION) $(ARCHCPUFLAGS) $(ARCHINCLUDES) $(ARCHDEFINES) $(EXTRADEFINES) $(INSTRUMENTATIONDEFINES) -pipe CPICFLAGS = $(ARCHPICFLAGS) $(CFLAGS) -CXXFLAGS = $(ARCHCXXFLAGS) $(ARCHWARNINGSXX) $(ARCHOPTIMIZATION) $(ARCHCPUFLAGS) $(ARCHXXINCLUDES) $(ARCHDEFINES) $(EXTRADEFINES) -pipe +CXXFLAGS = $(ARCHCXXFLAGS) $(ARCHWARNINGSXX) $(ARCHOPTIMIZATION) $(ARCHCPUFLAGS) $(ARCHXXINCLUDES) $(ARCHDEFINES) $(EXTRADEFINES) $(INSTRUMENTATIONDEFINES) -pipe CXXPICFLAGS = $(ARCHPICFLAGS) $(CXXFLAGS) CPPFLAGS = $(ARCHINCLUDES) $(ARCHDEFINES) $(EXTRADEFINES) AFLAGS = $(CFLAGS) -D__ASSEMBLY__ From 28d1db02b8ffe6169db484c1acd2f08173cd4c17 Mon Sep 17 00:00:00 2001 From: Anthony Merlino Date: Mon, 10 Jul 2017 03:10:20 -0400 Subject: [PATCH 25/54] drivers/wireless/ieee802154/mrf24j40: Splits up driver into multiple files to make it easier to navigate --- .../wireless/ieee802154/mrf24j40/Make.defs | 3 +- .../wireless/ieee802154/mrf24j40/mrf24j40.c | 1639 +---------------- .../wireless/ieee802154/mrf24j40/mrf24j40.h | 356 ++-- .../ieee802154/mrf24j40/mrf24j40_getset.c | 425 +++++ .../ieee802154/mrf24j40/mrf24j40_getset.h | 64 + .../ieee802154/mrf24j40/mrf24j40_interrupt.c | 439 +++++ .../ieee802154/mrf24j40/mrf24j40_radif.c | 530 ++++++ .../ieee802154/mrf24j40/mrf24j40_radif.h | 71 + .../ieee802154/mrf24j40/mrf24j40_reg.h | 286 +++ .../ieee802154/mrf24j40/mrf24j40_regops.c | 189 ++ .../ieee802154/mrf24j40/mrf24j40_regops.h | 47 + 11 files changed, 2226 insertions(+), 1823 deletions(-) create mode 100644 drivers/wireless/ieee802154/mrf24j40/mrf24j40_getset.c create mode 100644 drivers/wireless/ieee802154/mrf24j40/mrf24j40_getset.h create mode 100644 drivers/wireless/ieee802154/mrf24j40/mrf24j40_interrupt.c create mode 100644 drivers/wireless/ieee802154/mrf24j40/mrf24j40_radif.c create mode 100644 drivers/wireless/ieee802154/mrf24j40/mrf24j40_radif.h create mode 100644 drivers/wireless/ieee802154/mrf24j40/mrf24j40_reg.h create mode 100644 drivers/wireless/ieee802154/mrf24j40/mrf24j40_regops.c create mode 100644 drivers/wireless/ieee802154/mrf24j40/mrf24j40_regops.h diff --git a/drivers/wireless/ieee802154/mrf24j40/Make.defs b/drivers/wireless/ieee802154/mrf24j40/Make.defs index f6871f6ce5..446f7ef293 100644 --- a/drivers/wireless/ieee802154/mrf24j40/Make.defs +++ b/drivers/wireless/ieee802154/mrf24j40/Make.defs @@ -37,7 +37,8 @@ ifeq ($(CONFIG_IEEE802154_MRF24J40),y) # Include MRF24J40 files into the build -CSRCS += mrf24j40.c +CSRCS += mrf24j40_getset.c mrf24j40_interrupt.c mrf24j40_radif.c +CSRCS += mrf24j40_regops.c mrf24j40.c # Include MRF24J40 build support diff --git a/drivers/wireless/ieee802154/mrf24j40/mrf24j40.c b/drivers/wireless/ieee802154/mrf24j40/mrf24j40.c index 3e66d9f4cf..9dd7e7ddc1 100644 --- a/drivers/wireless/ieee802154/mrf24j40/mrf24j40.c +++ b/drivers/wireless/ieee802154/mrf24j40/mrf24j40.c @@ -54,8 +54,6 @@ #include #include #include -#include -#include #include @@ -64,45 +62,14 @@ #include #include "mrf24j40.h" +#include "mrf24j40_reg.h" +#include "mrf24j40_radif.h" +#include "mrf24j40_regops.h" /**************************************************************************** * Pre-processor Definitions ****************************************************************************/ -#ifndef CONFIG_SCHED_HPWORK -# error High priority work queue required in this driver -#endif - -#ifndef CONFIG_IEEE802154_MRF24J40_SPIMODE -# define CONFIG_IEEE802154_MRF24J40_SPIMODE SPIDEV_MODE0 -#endif - -#ifndef CONFIG_IEEE802154_MRF24J40_FREQUENCY -# define CONFIG_IEEE802154_MRF24J40_FREQUENCY 8000000 -#endif - -#ifndef CONFIG_SPI_EXCHANGE -# error CONFIG_SPI_EXCHANGE required for this driver -#endif - -/* Definitions for the device structure */ - -#define MRF24J40_RXMODE_NORMAL 0 -#define MRF24J40_RXMODE_PROMISC 1 -#define MRF24J40_RXMODE_NOCRC 2 - -#define MRF24J40_MODE_DEVICE 0 -#define MRF24J40_MODE_COORD 1 -#define MRF24J40_MODE_PANCOORD 2 - -/* Definitions for PA control on high power modules */ - -#define MRF24J40_PA_AUTO 1 -#define MRF24J40_PA_ED 2 -#define MRF24J40_PA_SLEEP 3 - -#define MRF24J40_GTS_SLOTS 2 - /* Clock configuration macros */ #define MRF24J40_SLPCLKPER_100KHZ ((1000 * 1000 * 1000)/100000) /* 10ns */ @@ -121,634 +88,11 @@ ((MRF24J40_BEACONINTERVAL_NSEC(bo) - MRF24J40_REMCNT_NSEC) / \ clkper) -/* Formula for calculating default macMaxFrameWaitTime is on pg. 130 - * - * For PHYs other than CSS and UWB, the attribute phyMaxFrameDuration is given by: - * - * phyMaxFrameDuration = phySHRDuration + - * ceiling([aMaxPHYPacketSize + 1] x phySymbolsPerOctet) - * - * where ceiling() is a function that returns the smallest integer value greater - * than or equal to its argument value. [1] pg. 158 -*/ - -#define MRF24J40_DEFAULT_MAX_FRAME_WAITTIME 1824 - -#define MRF24J40_SYMBOL_DURATION_PS 16000000 - -/**************************************************************************** - * Private Types - ****************************************************************************/ - -/* A MRF24J40 device instance */ - -struct mrf24j40_radio_s -{ - struct ieee802154_radio_s radio; /* The public device instance */ - FAR struct ieee802154_radiocb_s *radiocb; /* Registered callbacks */ - - /* Low-level MCU-specific support */ - - FAR const struct mrf24j40_lower_s *lower; - FAR struct spi_dev_s *spi; /* Saved SPI interface instance */ - - struct work_s irqwork; /* For deferring interrupt work to work queue */ - struct work_s csma_pollwork; /* For deferring poll work to the work queue */ - struct work_s gts_pollwork; /* For deferring poll work to the work queue */ - - sem_t exclsem; /* Exclusive access to this struct */ - - /* MAC Attributes */ - - struct ieee802154_addr_s addr; - - uint8_t chan; /* 11 to 26 for the 2.4 GHz band */ - uint8_t devmode; /* device mode: device, coord, pancoord */ - uint8_t paenabled; /* enable usage of PA */ - uint8_t rxmode; /* Reception mode: Main, no CRC, promiscuous */ - int32_t txpower; /* TX power in mBm = dBm/100 */ - struct ieee802154_cca_s cca; /* Clear channel assessement method */ - - /* MAC PIB attributes */ - - uint32_t max_frame_waittime; - - struct ieee802154_txdesc_s *txdelayed_desc; - struct ieee802154_txdesc_s *csma_desc; - bool txdelayed_busy : 1; - bool csma_busy : 1; - bool reschedule_csma : 1; - - bool rxenabled : 1; - - uint8_t bsn; - - struct ieee802154_txdesc_s *gts_desc[MRF24J40_GTS_SLOTS]; - bool gts_busy[MRF24J40_GTS_SLOTS]; -}; - -/**************************************************************************** - * Private Function Prototypes - ****************************************************************************/ - -/* Internal operations */ - -static void mrf24j40_spi_lock(FAR struct spi_dev_s *spi); - -static void mrf24j40_setreg(FAR struct spi_dev_s *spi, uint32_t addr, - uint8_t val); -static uint8_t mrf24j40_getreg(FAR struct spi_dev_s *spi, uint32_t addr); - -static int mrf24j40_resetrfsm(FAR struct mrf24j40_radio_s *dev); -static void mrf24j40_setorder(FAR struct mrf24j40_radio_s *dev, uint8_t bo, - uint8_t so); -static int mrf24j40_pacontrol(FAR struct mrf24j40_radio_s *dev, int mode); - -static int mrf24j40_setrxmode(FAR struct mrf24j40_radio_s *dev, int mode); -static int mrf24j40_regdump(FAR struct mrf24j40_radio_s *dev); - -static void mrf24j40_irqwork_rx(FAR struct mrf24j40_radio_s *dev); -static void mrf24j40_irqwork_txnorm(FAR struct mrf24j40_radio_s *dev); -static void mrf24j40_irqwork_txgts(FAR struct mrf24j40_radio_s *dev, - uint8_t gts_num); - -static void mrf24j40_irqworker(FAR void *arg); -static int mrf24j40_interrupt(int irq, FAR void *context, FAR void *arg); - -static void mrf24j40_dopoll_csma(FAR void *arg); -static void mrf24j40_dopoll_gts(FAR void *arg); - -static void mrf24j40_norm_setup(FAR struct mrf24j40_radio_s *dev, - FAR struct iob_s *frame, bool csma); -static void mrf24j40_gts_setup(FAR struct mrf24j40_radio_s *dev, uint8_t gts, - FAR struct iob_s *frame); -static void mrf24j40_setup_fifo(FAR struct mrf24j40_radio_s *dev, - FAR const uint8_t *buf, uint8_t length, uint32_t fifo_addr); - -static inline void mrf24j40_norm_trigger(FAR struct mrf24j40_radio_s *dev); -static inline void mrf24j40_beacon_trigger(FAR struct mrf24j40_radio_s *dev); - -static int mrf24j40_setchannel(FAR struct mrf24j40_radio_s *dev, - uint8_t chan); -static int mrf24j40_setpanid(FAR struct mrf24j40_radio_s *dev, - FAR const uint8_t *panid); -static int mrf24j40_setsaddr(FAR struct mrf24j40_radio_s *dev, - FAR const uint8_t *saddr); -static int mrf24j40_seteaddr(FAR struct mrf24j40_radio_s *dev, - FAR const uint8_t *eaddr); -static int mrf24j40_setcoordsaddr(FAR struct mrf24j40_radio_s *dev, - FAR const uint8_t *saddr); -static int mrf24j40_setcoordeaddr(FAR struct mrf24j40_radio_s *dev, - FAR const uint8_t *eaddr); -static int mrf24j40_setdevmode(FAR struct mrf24j40_radio_s *dev, - uint8_t mode); -static int mrf24j40_settxpower(FAR struct mrf24j40_radio_s *dev, - int32_t txpwr); -static int mrf24j40_setcca(FAR struct mrf24j40_radio_s *dev, - FAR struct ieee802154_cca_s *cca); -static int mrf24j40_energydetect(FAR struct mrf24j40_radio_s *dev, - FAR uint8_t *energy); -static void mrf24j40_mactimer(FAR struct mrf24j40_radio_s *dev, int numsymbols); - -/* Driver operations */ - -static int mrf24j40_bind(FAR struct ieee802154_radio_s *radio, - FAR struct ieee802154_radiocb_s *radiocb); -static int mrf24j40_reset(FAR struct ieee802154_radio_s *radio); -static int mrf24j40_getattr(FAR struct ieee802154_radio_s *radio, - enum ieee802154_attr_e attr, - FAR union ieee802154_attr_u *attrval); -static int mrf24j40_setattr(FAR struct ieee802154_radio_s *radio, - enum ieee802154_attr_e attr, - FAR const union ieee802154_attr_u *attrval); -static int mrf24j40_txnotify(FAR struct ieee802154_radio_s *radio, bool gts); -static int mrf24j40_txdelayed(FAR struct ieee802154_radio_s *radio, - FAR struct ieee802154_txdesc_s *txdesc, - uint32_t symboldelay); -static int mrf24j40_rxenable(FAR struct ieee802154_radio_s *dev, bool enable); -static int mrf24j40_beaconstart(FAR struct ieee802154_radio_s *radio, - FAR const struct ieee802154_superframespec_s *sfspec, - FAR struct ieee802154_beaconframe_s *beacon); -static int mrf24j40_beaconupdate(FAR struct ieee802154_radio_s *radio, - FAR struct ieee802154_beaconframe_s *beacon); -static int mrf24j40_beaconstop(FAR struct ieee802154_radio_s *radio); -static int mrf24j40_sfupdate(FAR struct ieee802154_radio_s *radio, - FAR const struct ieee802154_superframespec_s *sfspec); - -/**************************************************************************** - * Private Data - ****************************************************************************/ - -static const uint8_t g_allones[8] = -{ - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF -}; - -/**************************************************************************** - * Radio Interface Functions - ****************************************************************************/ - -static int mrf24j40_bind(FAR struct ieee802154_radio_s *radio, - FAR struct ieee802154_radiocb_s *radiocb) -{ - FAR struct mrf24j40_radio_s *dev = (FAR struct mrf24j40_radio_s *)radio; - - DEBUGASSERT(dev != NULL); - dev->radiocb = radiocb; - return OK; -} - -/**************************************************************************** - * Function: mrf24j40_txnotify - * - * Description: - * Driver callback invoked when new TX data is available. This is a - * stimulus perform an out-of-cycle poll and, thereby, reduce the TX - * latency. - * - * Parameters: - * radio - Reference to the radio driver state structure - * - * Returned Value: - * None - * - * Assumptions: - * - ****************************************************************************/ - -static int mrf24j40_txnotify(FAR struct ieee802154_radio_s *radio, bool gts) -{ - FAR struct mrf24j40_radio_s *dev = (FAR struct mrf24j40_radio_s *)radio; - - if (gts) - { - /* Is our single work structure available? It may not be if there are - * pending interrupt actions and we will have to ignore the Tx - * availability action. - */ - - if (work_available(&dev->gts_pollwork)) - { - /* Schedule to serialize the poll on the worker thread. */ - - work_queue(HPWORK, &dev->gts_pollwork, mrf24j40_dopoll_gts, dev, 0); - } - } - else - { - /* Is our single work structure available? It may not be if there are - * pending interrupt actions and we will have to ignore the Tx - * availability action. - */ - - if (work_available(&dev->csma_pollwork)) - { - /* Schedule to serialize the poll on the worker thread. */ - - work_queue(HPWORK, &dev->csma_pollwork, mrf24j40_dopoll_csma, dev, 0); - } - } - - return OK; -} - -/**************************************************************************** - * Function: mrf24j40_txdelayed - * - * Description: - * Transmit a packet without regard to supeframe structure after a certain - * number of symbols. This function is used to send Data Request responses. - * It can also be used to send data immediately if the delay is set to 0. - * - * Parameters: - * radio - Reference to the radio driver state structure - * - * Returned Value: - * None - * - * Assumptions: - * - ****************************************************************************/ - -static int mrf24j40_txdelayed(FAR struct ieee802154_radio_s *radio, - FAR struct ieee802154_txdesc_s *txdesc, - uint32_t symboldelay) -{ - FAR struct mrf24j40_radio_s *dev = (FAR struct mrf24j40_radio_s *)radio; - uint8_t reg; - - /* Get exclusive access to the radio device */ - - if (sem_wait(&dev->exclsem) != 0) - { - return -EINTR; - } - - /* There should never be more than one of these transactions at once. */ - - DEBUGASSERT(!dev->txdelayed_busy); - - dev->txdelayed_desc = txdesc; - dev->txdelayed_busy = true; - - /* Disable the TX norm interrupt and clear it */ - - reg = mrf24j40_getreg(dev->spi, MRF24J40_INTCON); - reg |= MRF24J40_INTCON_TXNIE; - mrf24j40_setreg(dev->spi, MRF24J40_INTCON, reg); - - /* If after disabling the interrupt, the irqworker is not scheduled, there - * are no interrupts to worry about. However, if there is work scheduled, - * we need to process it before going any further. - */ - - if (!work_available(&dev->irqwork)) - { - work_cancel(HPWORK, &dev->irqwork); - sem_post(&dev->exclsem); - mrf24j40_irqworker((FAR void *)dev); - - /* Get exclusive access to the radio device */ - - if (sem_wait(&dev->exclsem) != 0) - { - return -EINTR; - } - } - - if (dev->csma_busy) - { - dev->reschedule_csma = true; - } - - mrf24j40_norm_setup(dev, txdesc->frame, false); - - if (symboldelay == 0) - { - mrf24j40_norm_trigger(dev); - } - else - { - mrf24j40_mactimer(dev, symboldelay); - } - - sem_post(&dev->exclsem); - - return OK; -} - -static int mrf24j40_reset(FAR struct ieee802154_radio_s *radio) -{ - FAR struct mrf24j40_radio_s *dev = (FAR struct mrf24j40_radio_s *)radio; - struct ieee802154_cca_s cca; - int reg; - - /* Software reset */ - - mrf24j40_setreg(dev->spi, MRF24J40_SOFTRST , 0x07); /* 00000111 Reset */ - while(mrf24j40_getreg(dev->spi, MRF24J40_SOFTRST) & 0x07); - - /* Apply recommended settings */ - - mrf24j40_setreg(dev->spi, MRF24J40_PACON2 , 0x98); /* 10011000 Enable FIFO (default), TXONTS=6 (recommended), TXONT<8:7>=0 */ - mrf24j40_setreg(dev->spi, MRF24J40_TXSTBL , 0x95); /* 10010101 set the SIFS period. RFSTBL=9, MSIFS=5, aMinSIFSPeriod=14 (min 12) */ - mrf24j40_setreg(dev->spi, MRF24J40_TXPEND , 0x7C); /* 01111100 set the LIFS period, MLIFS=1Fh=31 aMinLIFSPeriod=40 (min 40) */ - mrf24j40_setreg(dev->spi, MRF24J40_TXTIME , 0x30); /* 00110000 set the turnaround time, TURNTIME=3 aTurnAroundTime=12 */ - mrf24j40_setreg(dev->spi, MRF24J40_RFCON1 , 0x02); /* 00000010 VCO optimization, recommended value */ - mrf24j40_setreg(dev->spi, MRF24J40_RFCON2 , 0x80); /* 10000000 Enable PLL */ - mrf24j40_setreg(dev->spi, MRF24J40_RFCON6 , 0x90); /* 10010000 TX filter enable, fast 20M recovery, No bat monitor*/ - mrf24j40_setreg(dev->spi, MRF24J40_RFCON7 , 0x80); /* 10000000 Sleep clock on internal 100 kHz */ - mrf24j40_setreg(dev->spi, MRF24J40_RFCON8 , 0x10); /* 00010000 VCO control bit, as recommended */ - mrf24j40_setreg(dev->spi, MRF24J40_SLPCON1, 0x01); /* 00000001 no CLKOUT, default divisor */ - mrf24j40_setreg(dev->spi, MRF24J40_BBREG6 , 0x40); /* 01000000 Append RSSI to rx packets */ - - /* Set this in reset since it can exist for all device modes. See pg 101 */ - - mrf24j40_setreg(dev->spi, MRF24J40_FRMOFFSET, 0x15); - - /* For now, we want to always just have the frame pending bit set when - * acknowledging a Data Request command. The standard says that the coordinator - * can do this if it needs time to figure out whether it has data or not - */ - - mrf24j40_setreg(dev->spi, MRF24J40_ACKTMOUT, 0x39 | MRF24J40_ACKTMOUT_DRPACK); - - /* Set WAKECNT (SLPACK 0x35<6:0>) value = 0xC8 to set the main oscillator - * (20 MHz) start-up timer value. - */ - - mrf24j40_setreg(dev->spi, MRF24J40_SLPACK, 0xC8); - - /* Set WAKETIME to recommended value for 100kHz SLPCLK Source */ - - mrf24j40_setreg(dev->spi, MRF24J40_WAKETIMEL, 0xD2); - mrf24j40_setreg(dev->spi, MRF24J40_WAKETIMEH, 0x00); - - /* Enable the SLPIF and WAKEIF flags */ - - reg = mrf24j40_getreg(dev->spi, MRF24J40_INTCON); - reg &= ~(MRF24J40_INTCON_SLPIE | MRF24J40_INTCON_WAKEIE); - mrf24j40_setreg(dev->spi, MRF24J40_INTCON, reg); - - dev->rxenabled = false; - - mrf24j40_setchannel(dev, 11); - mrf24j40_setpanid(dev, g_allones); - mrf24j40_setsaddr(dev, g_allones); - mrf24j40_seteaddr(dev, g_allones); - - dev->max_frame_waittime = MRF24J40_DEFAULT_MAX_FRAME_WAITTIME; - dev->bsn = 0; - - /* Default device params */ - - cca.use_ed = 1; - cca.use_cs = 0; - cca.edth = 0x60; /* CCA mode ED, no carrier sense, recommenced ED threshold -69 dBm */ - mrf24j40_setcca(dev, &cca); - - mrf24j40_setrxmode(dev, MRF24J40_RXMODE_NORMAL); - - mrf24j40_settxpower(dev, 0); /*16. Set transmitter power .*/ - - mrf24j40_pacontrol(dev, MRF24J40_PA_AUTO); - - return OK; -} - -static int mrf24j40_getattr(FAR struct ieee802154_radio_s *radio, - enum ieee802154_attr_e attr, - FAR union ieee802154_attr_u *attrval) -{ - FAR struct mrf24j40_radio_s *dev = (FAR struct mrf24j40_radio_s *)radio; - int ret; - - switch (attr) - { - case IEEE802154_ATTR_MAC_EADDR: - { - memcpy(&attrval->mac.eaddr[0], &dev->addr.eaddr[0], 8); - ret = IEEE802154_STATUS_SUCCESS; - } - break; - - case IEEE802154_ATTR_MAC_MAX_FRAME_WAITTIME: - { - attrval->mac.max_frame_waittime = dev->max_frame_waittime; - ret = IEEE802154_STATUS_SUCCESS; - } - break; - - case IEEE802154_ATTR_PHY_SYMBOL_DURATION: - { - attrval->phy.symdur_picosec = MRF24J40_SYMBOL_DURATION_PS; - ret = IEEE802154_STATUS_SUCCESS; - } - break; - - case IEEE802154_ATTR_PHY_CHAN: - { - attrval->phy.chan = dev->chan; - ret = IEEE802154_STATUS_SUCCESS; - } - - default: - ret = IEEE802154_STATUS_UNSUPPORTED_ATTRIBUTE; - } - - return ret; -} - -static int mrf24j40_setattr(FAR struct ieee802154_radio_s *radio, - enum ieee802154_attr_e attr, - FAR const union ieee802154_attr_u *attrval) -{ - FAR struct mrf24j40_radio_s *dev = (FAR struct mrf24j40_radio_s *)radio; - int ret; - - switch (attr) - { - case IEEE802154_ATTR_MAC_PANID: - { - mrf24j40_setpanid(dev, attrval->mac.panid); - ret = IEEE802154_STATUS_SUCCESS; - } - break; - - case IEEE802154_ATTR_MAC_SADDR: - { - mrf24j40_setsaddr(dev, attrval->mac.saddr); - ret = IEEE802154_STATUS_SUCCESS; - } - break; - - case IEEE802154_ATTR_MAC_EADDR: - { - mrf24j40_seteaddr(dev, attrval->mac.eaddr); - ret = IEEE802154_STATUS_SUCCESS; - } - break; - - case IEEE802154_ATTR_MAC_COORD_SADDR: - { - mrf24j40_setcoordsaddr(dev, attrval->mac.coordsaddr); - ret = IEEE802154_STATUS_SUCCESS; - } - break; - - case IEEE802154_ATTR_MAC_COORD_EADDR: - { - mrf24j40_setcoordeaddr(dev, attrval->mac.coordeaddr); - ret = IEEE802154_STATUS_SUCCESS; - } - break; - - case IEEE802154_ATTR_MAC_PROMISCUOUS_MODE: - { - if (attrval->mac.promisc_mode) - { - mrf24j40_setrxmode(dev, MRF24J40_RXMODE_PROMISC); - } - else - { - mrf24j40_setrxmode(dev, MRF24J40_RXMODE_NORMAL); - } - - ret = IEEE802154_STATUS_SUCCESS; - } - break; - - - case IEEE802154_ATTR_PHY_CHAN: - { - mrf24j40_setchannel(dev, attrval->phy.chan); - ret = IEEE802154_STATUS_SUCCESS; - } - break; - - default: - ret = IEEE802154_STATUS_UNSUPPORTED_ATTRIBUTE; - break; - } - return ret; -} - -static int mrf24j40_beaconstart(FAR struct ieee802154_radio_s *radio, - FAR const struct ieee802154_superframespec_s *sfspec, - FAR struct ieee802154_beaconframe_s *beacon) -{ - FAR struct mrf24j40_radio_s *dev = (FAR struct mrf24j40_radio_s *)radio; - int reg; - - if (sfspec->pancoord) - { - /* Set the PANCOORD (RXMCR 0x00<3>) bit = 1to configure as PAN coordinator */ - - reg = mrf24j40_getreg(dev->spi, MRF24J40_RXMCR); - reg |= MRF24J40_RXMCR_PANCOORD; - mrf24j40_setreg(dev->spi, MRF24J40_RXMCR, reg); - - /* Set the SLOTTED (TXMCR 0x11<5>) bit = 1 to use Slotted CSMA-CA mode */ - - reg = mrf24j40_getreg(dev->spi, MRF24J40_TXMCR); - reg |= MRF24J40_TXMCR_SLOTTED; - mrf24j40_setreg(dev->spi, MRF24J40_TXMCR, reg); - - /* Load the beacon frame into the TXBFIFO (0x080-0x0FF). */ - - mrf24j40_setup_fifo(dev, beacon->bf_data, beacon->bf_len, MRF24J40_BEACON_FIFO); - - /* The radio layer is responsible for setting the BSN. */ - - dev->bsn = 0; - mrf24j40_setreg(dev->spi, MRF24J40_BEACON_FIFO + 4, dev->bsn++); - - /* Set the TXBMSK (TXBCON1 0x25<7>) bit = 1 to mask the beacon interrupt - * mask - */ - - reg = mrf24j40_getreg(dev->spi, MRF24J40_TXBCON1); - reg |= MRF24J40_TXBCON1_TXBMSK; - mrf24j40_setreg(dev->spi, MRF24J40_TXBCON1, reg); - - /* Set INTL (WAKECON 0x22<5:0>) value to 0x03. */ - - reg = mrf24j40_getreg(dev->spi, MRF24J40_WAKECON); - reg &= ~MRF24J40_WAKECON_INTL; - reg |= 0x03 & MRF24J40_WAKECON_INTL; - mrf24j40_setreg(dev->spi, MRF24J40_WAKECON, reg); - - /* Program the CAP end slot (ESLOTG1 0x13<3:0>) value. */ - - reg = mrf24j40_getreg(dev->spi, MRF24J40_ESLOTG1); - reg &= ~MRF24J40_ESLOTG1_CAP; - reg |= sfspec->final_capslot & MRF24J40_ESLOTG1_CAP; - mrf24j40_setreg(dev->spi, MRF24J40_ESLOTG1, reg); - - /* TODO: Add GTS related code. See pg 100 of datasheet */ - - mrf24j40_setorder(dev, sfspec->beaconorder, sfspec->sforder); - } - else - { - return -ENOTTY; - } - - return OK; -} - -static int mrf24j40_beaconupdate(FAR struct ieee802154_radio_s *radio, - FAR struct ieee802154_beaconframe_s *beacon) -{ - FAR struct mrf24j40_radio_s *dev = (FAR struct mrf24j40_radio_s *)radio; - - mrf24j40_setup_fifo(dev, beacon->bf_data, beacon->bf_len, MRF24J40_BEACON_FIFO); - mrf24j40_beacon_trigger(dev); - - return OK; -} - -static int mrf24j40_beaconstop(FAR struct ieee802154_radio_s *radio) -{ - return -ENOTTY; -} - -static int mrf24j40_sfupdate(FAR struct ieee802154_radio_s *radio, - FAR const struct ieee802154_superframespec_s *sfspec) -{ - FAR struct mrf24j40_radio_s *dev = (FAR struct mrf24j40_radio_s *)radio; - int reg; - - /* If we are operating on a beacon-enabled network, use slotted CSMA */ - - reg = mrf24j40_getreg(dev->spi, MRF24J40_TXMCR); - if (sfspec->beaconorder < 15) - { - reg |= MRF24J40_TXMCR_SLOTTED; - } - else - { - reg &= ~MRF24J40_TXMCR_SLOTTED; - } - mrf24j40_setreg(dev->spi, MRF24J40_TXMCR, reg); - - mrf24j40_setorder(dev, sfspec->beaconorder, sfspec->sforder); - - /* Program the CAP end slot (ESLOTG1 0x13<3:0>) value. */ - - reg = mrf24j40_getreg(dev->spi, MRF24J40_ESLOTG1); - reg &= ~MRF24J40_ESLOTG1_CAP; - reg |= sfspec->final_capslot & MRF24J40_ESLOTG1_CAP; - mrf24j40_setreg(dev->spi, MRF24J40_ESLOTG1, reg); - - return OK; -} - /**************************************************************************** * Internal Functions ****************************************************************************/ -static void mrf24j40_mactimer(FAR struct mrf24j40_radio_s *dev, int numsymbols) +void mrf24j40_mactimer(FAR struct mrf24j40_radio_s *dev, int numsymbols) { uint16_t nhalfsym; uint8_t reg; @@ -798,7 +142,7 @@ static void mrf24j40_mactimer(FAR struct mrf24j40_radio_s *dev, int numsymbols) * ****************************************************************************/ -static void mrf24j40_dopoll_csma(FAR void *arg) +void mrf24j40_dopoll_csma(FAR void *arg) { FAR struct mrf24j40_radio_s *dev = (FAR struct mrf24j40_radio_s *)arg; int len = 0; @@ -854,7 +198,7 @@ static void mrf24j40_dopoll_csma(FAR void *arg) * ****************************************************************************/ -static void mrf24j40_dopoll_gts(FAR void *arg) +void mrf24j40_dopoll_gts(FAR void *arg) { FAR struct mrf24j40_radio_s *dev = (FAR struct mrf24j40_radio_s *)arg; int gts = 0; @@ -886,147 +230,6 @@ static void mrf24j40_dopoll_gts(FAR void *arg) sem_post(&dev->exclsem); } -/**************************************************************************** - * Name: mrf24j40_spi_lock - * - * Description: - * Acquire exclusive access to the shared SPI bus. - * - ****************************************************************************/ - -static void mrf24j40_spi_lock(FAR struct spi_dev_s *spi) -{ - SPI_LOCK(spi, 1); - SPI_SETBITS(spi, 8); - SPI_SETMODE(spi, CONFIG_IEEE802154_MRF24J40_SPIMODE); - SPI_SETFREQUENCY(spi, CONFIG_IEEE802154_MRF24J40_FREQUENCY); -} - -/**************************************************************************** - * Name: mrf24j40_spi_unlock - * - * Description: - * Release exclusive access to the shared SPI bus. - * - ****************************************************************************/ - -static inline void mrf24j40_spi_unlock(FAR struct spi_dev_s *spi) -{ - SPI_LOCK(spi,0); -} - -/**************************************************************************** - * Name: mrf24j40_setreg - * - * Description: - * Define the value of an MRF24J40 device register - * - ****************************************************************************/ - -static void mrf24j40_setreg(FAR struct spi_dev_s *spi, uint32_t addr, - uint8_t val) -{ - uint8_t buf[3]; - int len; - - if (!(addr&0x80000000)) - { - addr &= 0x3F; /* 6-bit address */ - addr <<= 1; - addr |= 0x01; /* writing */ - buf[0] = addr; - len = 1; - } - else - { - addr &= 0x3FF; /* 10-bit address */ - addr <<= 5; - addr |= 0x8010; /* writing long */ - buf[0] = (addr >> 8); - buf[1] = (addr & 0xFF); - len = 2; - } - - buf[len++] = val; - - mrf24j40_spi_lock(spi); - SPI_SELECT(spi, SPIDEV_IEEE802154(0), true); - SPI_SNDBLOCK(spi, buf, len); - SPI_SELECT(spi, SPIDEV_IEEE802154(0), false); - mrf24j40_spi_unlock(spi); -} - -/**************************************************************************** - * Name: mrf24j40_getreg - * - * Description: - * Return the value of an MRF24J40 device register* - * - ****************************************************************************/ - -static uint8_t mrf24j40_getreg(FAR struct spi_dev_s *spi, uint32_t addr) -{ - uint8_t buf[3]; - uint8_t rx[3]; - int len; - - if (!(addr&0x80000000)) - { - /* 6-bit address */ - - addr &= 0x3F; - addr <<= 1; - buf[0] = addr; - len = 1; - } - else - { - /* 10-bit address */ - - addr &= 0x3FF; - addr <<= 5; - addr |= 0x8000; - buf[0] = (addr >> 8); - buf[1] = (addr & 0xFF); - len = 2; - } - - buf[len++] = 0xFF; /* dummy */ - - mrf24j40_spi_lock (spi); - SPI_SELECT (spi, SPIDEV_IEEE802154(0), true); - SPI_EXCHANGE (spi, buf, rx, len); - SPI_SELECT (spi, SPIDEV_IEEE802154(0), false); - mrf24j40_spi_unlock(spi); - - /* wlinfo("r[%04X]=%02X\n", addr, rx[len - 1]); */ - return rx[len - 1]; -} - -/**************************************************************************** - * Name: mrf24j40_resetrfsm - * - * Description: - * Reset the RF state machine. Required at boot, after channel change, - * and probably after PA settings. - * - ****************************************************************************/ - -static int mrf24j40_resetrfsm(FAR struct mrf24j40_radio_s *dev) -{ - uint8_t reg; - - reg = mrf24j40_getreg(dev->spi, MRF24J40_RFCTL); - reg |= 0x04; - mrf24j40_setreg(dev->spi, MRF24J40_RFCTL, reg); - - reg &= ~0x04; - mrf24j40_setreg(dev->spi, MRF24J40_RFCTL, reg); - up_udelay(200); - - return OK; -} - /**************************************************************************** * Name: mrf24j40_setorder * @@ -1034,8 +237,7 @@ static int mrf24j40_resetrfsm(FAR struct mrf24j40_radio_s *dev) * Configures the timers and sets the ORDER register ****************************************************************************/ -static void mrf24j40_setorder(FAR struct mrf24j40_radio_s *dev, uint8_t bo, - uint8_t so) +void mrf24j40_setorder(FAR struct mrf24j40_radio_s *dev, uint8_t bo, uint8_t so) { uint32_t maincnt = 0; uint32_t slpcal = 0; @@ -1109,7 +311,7 @@ static void mrf24j40_setorder(FAR struct mrf24j40_radio_s *dev, uint8_t bo, * GPIO 3: PA power enable (not required on MB) ****************************************************************************/ -static int mrf24j40_pacontrol(FAR struct mrf24j40_radio_s *dev, int mode) +int mrf24j40_pacontrol(FAR struct mrf24j40_radio_s *dev, int mode) { if (!dev->paenabled) { @@ -1143,433 +345,6 @@ static int mrf24j40_pacontrol(FAR struct mrf24j40_radio_s *dev, int mode) return OK; } -/**************************************************************************** - * Name: mrf24j40_setrxmode - * - * Description: - * Set the RX mode (normal, promiscuous, no CRC) - * - ****************************************************************************/ - -static int mrf24j40_setrxmode(FAR struct mrf24j40_radio_s *dev, int mode) -{ - uint8_t reg; - - if (mode < MRF24J40_RXMODE_NORMAL || mode > MRF24J40_RXMODE_NOCRC) - { - return -EINVAL; - } - - reg = mrf24j40_getreg(dev->spi, MRF24J40_RXMCR); - reg &= ~0x03; - reg |= mode; - - /* Set mode options */ - - if (mode != MRF24J40_RXMODE_NORMAL) - { - /* Promisc and error modes: Disable auto ACK */ - - reg |= MRF24J40_RXMCR_NOACKRSP; - } - else - { - /* Normal mode : enable auto-ACK */ - - reg &= ~MRF24J40_RXMCR_NOACKRSP; - } - - mrf24j40_setreg(dev->spi, MRF24J40_RXMCR, reg); - - dev->rxmode = mode; - wlinfo("%u\n", (unsigned)mode); - return OK; -} - -/**************************************************************************** - * Name: mrf24j40_setchannel - * - * Description: - * Define the current radio channel the device is operating on. - * In the 2.4 GHz, there are 16 channels, each 2 MHz wide, 5 MHz spacing: - * Chan MHz Chan MHz Chan MHz Chan MHz - * 11 2405 15 2425 19 2445 23 2465 - * 12 2410 16 2430 20 2450 24 2470 - * 13 2415 17 2435 21 2455 25 2475 - * 14 2420 18 2440 22 2460 26 2480 - * - ****************************************************************************/ - -static int mrf24j40_setchannel(FAR struct mrf24j40_radio_s *dev, uint8_t chan) -{ - if (chan < 11 || chan > 26) - { - wlerr("ERROR: Invalid chan: %d\n",chan); - return -EINVAL; - } - - /* 15. Set channel – See Section 3.4 “Channel Selection”. */ - - mrf24j40_setreg(dev->spi, MRF24J40_RFCON0, (chan - 11) << 4 | 0x03); - - /* 17. RFCTL (0x36) = 0x04 – Reset RF state machine. - * 18. RFCTL (0x36) = 0x00. - */ - - mrf24j40_resetrfsm(dev); - - dev->chan = chan; - wlinfo("%u\n", (unsigned)chan); - - return OK; -} - -/**************************************************************************** - * Name: mrf24j40_setpanid - * - * Description: - * Define the PAN ID the device is operating on. - * - ****************************************************************************/ - -static int mrf24j40_setpanid(FAR struct mrf24j40_radio_s *dev, - FAR const uint8_t *panid) -{ - mrf24j40_setreg(dev->spi, MRF24J40_PANIDL, panid[0]); - mrf24j40_setreg(dev->spi, MRF24J40_PANIDH, panid[1]); - - IEEE802154_PANIDCOPY(dev->addr.panid, panid); - wlinfo("%02X:%02X\n", panid[0], panid[1]); - - return OK; -} - -/**************************************************************************** - * Name: mrf24j40_setsaddr - * - * Description: - * Define the device short address. The following addresses are special: - * FFFEh : Broadcast - * FFFFh : Unspecified - * - ****************************************************************************/ - -static int mrf24j40_setsaddr(FAR struct mrf24j40_radio_s *dev, - FAR const uint8_t *saddr) -{ - mrf24j40_setreg(dev->spi, MRF24J40_SADRL, saddr[0]); - mrf24j40_setreg(dev->spi, MRF24J40_SADRH, saddr[1]); - - IEEE802154_SADDRCOPY(dev->addr.saddr, saddr); - - wlinfo("%02X:%02X\n", saddr[0], saddr[1]); - return OK; -} - -/**************************************************************************** - * Name: mrf24j40_seteaddr - * - * Description: - * Define the device extended address. The following addresses are special: - * FFFFFFFFFFFFFFFFh : Unspecified - * - ****************************************************************************/ - -static int mrf24j40_seteaddr(FAR struct mrf24j40_radio_s *dev, - FAR const uint8_t *eaddr) -{ - int i; - - for (i = 0; i < 8; i++) - { - mrf24j40_setreg(dev->spi, MRF24J40_EADR0 + i, eaddr[i]); - dev->addr.eaddr[i] = eaddr[i]; - } - wlinfo("%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X\n", eaddr[0], eaddr[1], - eaddr[2], eaddr[3], eaddr[4], eaddr[5], eaddr[6], eaddr[7]); - - return OK; -} - -/**************************************************************************** - * Name: mrf24j40_setcoordsaddr - * - * Description: - * Define the coordinator short address. The following addresses are special: - * FFFEh : Broadcast - * FFFFh : Unspecified - * - ****************************************************************************/ - -static int mrf24j40_setcoordsaddr(FAR struct mrf24j40_radio_s *dev, - FAR const uint8_t *saddr) -{ - mrf24j40_setreg(dev->spi, MRF24J40_ASSOSADR0, saddr[0]); - mrf24j40_setreg(dev->spi, MRF24J40_ASSOSADR1, saddr[1]); - - IEEE802154_SADDRCOPY(dev->addr.saddr, saddr); - - wlinfo("%02X:%02X\n", saddr[0], saddr[1]); - return OK; -} - -/**************************************************************************** - * Name: mrf24j40_setcoordeaddr - * - * Description: - * Define the coordinator extended address. The following addresses are special: - * FFFFFFFFFFFFFFFFh : Unspecified - * - ****************************************************************************/ - -static int mrf24j40_setcoordeaddr(FAR struct mrf24j40_radio_s *dev, - FAR const uint8_t *eaddr) -{ - int i; - - for (i = 0; i < 8; i++) - { - mrf24j40_setreg(dev->spi, MRF24J40_ASSOEADR0 + i, eaddr[i]); - dev->addr.eaddr[i] = eaddr[i]; - } - - wlinfo("%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X\n", eaddr[0], eaddr[1], - eaddr[2], eaddr[3], eaddr[4], eaddr[5], eaddr[6], eaddr[7]); - return OK; -} - -/**************************************************************************** - * Name: mrf24j40_setdevmode - * - * Description: - * Define the device behaviour: normal end device or coordinator - * - ****************************************************************************/ - -static int mrf24j40_setdevmode(FAR struct mrf24j40_radio_s *dev, - uint8_t mode) -{ - int ret = OK; - uint8_t reg; - - /* Disable slotted mode until I decide to implement slotted mode */ - - reg = mrf24j40_getreg(dev->spi, MRF24J40_TXMCR); - reg &= ~MRF24J40_TXMCR_SLOTTED; - mrf24j40_setreg(dev->spi, MRF24J40_TXMCR, reg); - mrf24j40_setreg(dev->spi, MRF24J40_ORDER, 0xFF); - - /* Define dev mode */ - - reg = mrf24j40_getreg(dev->spi, MRF24J40_RXMCR); - - if (mode == MRF24J40_MODE_PANCOORD) - { - reg |= MRF24J40_RXMCR_PANCOORD; - reg &= ~MRF24J40_RXMCR_COORD; - } - else if (mode == MRF24J40_MODE_COORD) - { - reg |= MRF24J40_RXMCR_COORD; - reg &= ~MRF24J40_RXMCR_PANCOORD; - } - else if (mode == MRF24J40_MODE_DEVICE) - { - reg &= ~MRF24J40_RXMCR_PANCOORD; - reg &= ~MRF24J40_RXMCR_COORD; - } - else - { - return -EINVAL; - } - - mrf24j40_setreg(dev->spi, MRF24J40_RXMCR, reg); - dev->devmode = mode; - return ret; -} - -/**************************************************************************** - * Name: mrf24j40_settxpower - * - * Description: - * Define the transmit power. Value is passed in mBm, it is rounded to - * the nearest value. Some MRF modules have a power amplifier, this routine - * does not care about this. We only change the CHIP output power. - * - ****************************************************************************/ - -static int mrf24j40_settxpower(FAR struct mrf24j40_radio_s *dev, - int32_t txpwr) -{ - uint8_t reg; - int save_txpwr = txpwr; - - if (txpwr <= -3000 && txpwr > -3630) - { - reg = 0xC0; - txpwr += 3000; - } - else if (txpwr <= -2000) - { - reg = 0x80; - txpwr += 2000; - } - else if (txpwr <= -1000) - { - reg = 0x40; - txpwr += 1000; - } - else if (txpwr <= 0) - { - reg = 0x00; - } - else - { - return -EINVAL; - } - - wlinfo("Remaining attenuation: %d mBm\n",txpwr); - - switch(txpwr/100) - { - case -9: - case -8: - case -7: - case -6: - reg |= 0x07; - break; - - case -5: - reg |= 0x06; - break; - - case -4: - reg |= 0x05; - break; - - case -3: - reg |= 0x04; - break; - - case -2: - reg |= 0x03; - break; - - case -1: - reg |= 0x02; - break; - - case 0: - reg |= 0x00; /* value 0x01 is 0.5 db, not used */ - break; - - default: - - return -EINVAL; - } - - mrf24j40_setreg(dev->spi, MRF24J40_RFCON3, reg); - - dev->txpower = save_txpwr; - - return OK; -} - -/**************************************************************************** - * Name: mrf24j40_setcca - * - * Description: - * Define the Clear Channel Assessement method. - * - ****************************************************************************/ - -static int mrf24j40_setcca(FAR struct mrf24j40_radio_s *dev, - FAR struct ieee802154_cca_s *cca) -{ - uint8_t mode; - - if (!cca->use_ed && !cca->use_cs) - { - return -EINVAL; - } - - if (cca->use_cs && cca->csth > 0x0f) - { - return -EINVAL; - } - - mode = mrf24j40_getreg(dev->spi, MRF24J40_BBREG2); - mode &= 0x03; - - if (cca->use_ed) - { - mode |= MRF24J40_BBREG2_CCAMODE_ED; - mrf24j40_setreg(dev->spi, MRF24J40_CCAEDTH, cca->edth); - } - - if (cca->use_cs) - { - mode |= MRF24J40_BBREG2_CCAMODE_CS; - mode |= cca->csth << 2; - } - - mrf24j40_setreg(dev->spi, MRF24J40_BBREG2, mode); - - memcpy(&dev->cca, cca, sizeof(struct ieee802154_cca_s)); - return OK; -} - -/**************************************************************************** - * Name: mrf24j40_regdump - * - * Description: - * Display the value of all registers. - * - ****************************************************************************/ - -static int mrf24j40_regdump(FAR struct mrf24j40_radio_s *dev) -{ - uint32_t i; - char buf[4+16*3+2+1]; - int len = 0; - - wlinfo("Short regs:\n"); - - for (i = 0; i < 0x40; i++) - { - if ((i & 15) == 0) - { - len=sprintf(buf, "%02x: ",i&0xFF); - } - - len += sprintf(buf+len, "%02x ", mrf24j40_getreg(dev->spi, i)); - if ((i & 15) == 15) - { - sprintf(buf+len, "\n"); - wlinfo("%s", buf); - } - } - - wlinfo("Long regs:\n"); - - for (i = 0x80000200; i < 0x80000250; i++) - { - if ((i & 15) == 0) - { - len=sprintf(buf, "%02x: ",i&0xFF); - } - - len += sprintf(buf+len, "%02x ", mrf24j40_getreg(dev->spi, i)); - if ((i & 15) == 15) - { - sprintf(buf+len, "\n"); - wlinfo("%s", buf); - } - } - - return 0; -} - /**************************************************************************** * Name: mrf24j40_energydetect * @@ -1578,8 +353,7 @@ static int mrf24j40_regdump(FAR struct mrf24j40_radio_s *dev) * ****************************************************************************/ -static int mrf24j40_energydetect(FAR struct mrf24j40_radio_s *dev, - FAR uint8_t *energy) +int mrf24j40_energydetect(FAR struct mrf24j40_radio_s *dev, FAR uint8_t *energy) { uint8_t reg; @@ -1625,8 +399,8 @@ static int mrf24j40_energydetect(FAR struct mrf24j40_radio_s *dev, * ****************************************************************************/ -static void mrf24j40_norm_setup(FAR struct mrf24j40_radio_s *dev, - FAR struct iob_s *frame, bool csma) +void mrf24j40_norm_setup(FAR struct mrf24j40_radio_s *dev, + FAR struct iob_s *frame, bool csma) { uint8_t reg; @@ -1681,7 +455,7 @@ static void mrf24j40_norm_setup(FAR struct mrf24j40_radio_s *dev, * ****************************************************************************/ -static inline void mrf24j40_norm_trigger(FAR struct mrf24j40_radio_s *dev) +void mrf24j40_norm_trigger(FAR struct mrf24j40_radio_s *dev) { uint8_t reg; @@ -1698,7 +472,7 @@ static inline void mrf24j40_norm_trigger(FAR struct mrf24j40_radio_s *dev) * ****************************************************************************/ -static inline void mrf24j40_beacon_trigger(FAR struct mrf24j40_radio_s *dev) +void mrf24j40_beacon_trigger(FAR struct mrf24j40_radio_s *dev) { uint8_t reg; @@ -1717,8 +491,8 @@ static inline void mrf24j40_beacon_trigger(FAR struct mrf24j40_radio_s *dev) * ****************************************************************************/ -static void mrf24j40_gts_setup(FAR struct mrf24j40_radio_s *dev, uint8_t fifo, - FAR struct iob_s *frame) +void mrf24j40_gts_setup(FAR struct mrf24j40_radio_s *dev, uint8_t fifo, + FAR struct iob_s *frame) { } @@ -1730,9 +504,8 @@ static void mrf24j40_gts_setup(FAR struct mrf24j40_radio_s *dev, uint8_t fifo, * ****************************************************************************/ -static void mrf24j40_setup_fifo(FAR struct mrf24j40_radio_s *dev, - FAR const uint8_t *buf, uint8_t length, - uint32_t fifo_addr) +void mrf24j40_setup_fifo(FAR struct mrf24j40_radio_s *dev, FAR const uint8_t *buf, + uint8_t length, uint32_t fifo_addr) { int hlen = 3; /* Include frame control and seq number */ @@ -1784,146 +557,6 @@ static void mrf24j40_setup_fifo(FAR struct mrf24j40_radio_s *dev, } } -/**************************************************************************** - * Name: mrf24j40_irqwork_txnorm - * - * Description: - * Manage completion of packet transmission. - * - ****************************************************************************/ - -static void mrf24j40_irqwork_txnorm(FAR struct mrf24j40_radio_s *dev) -{ - uint8_t reg; - enum ieee802154_status_e status; - bool framepending; - - /* Disable tx int */ - - reg = mrf24j40_getreg(dev->spi, MRF24J40_INTCON); - reg |= MRF24J40_INTCON_TXNIE; - mrf24j40_setreg(dev->spi, MRF24J40_INTCON, reg); - - /* Get the status from the device and copy the status into the tx desc. - * The status for the normal FIFO is represented with bit TXNSTAT where - * 0=success, 1= failure. - */ - - reg = mrf24j40_getreg(dev->spi, MRF24J40_TXSTAT); - - /* TXNSTAT = 0: Transmission was successful - * TXNSTAT = 1: Transmission failed, retry count exceeded - */ - - if (reg & MRF24J40_TXSTAT_TXNSTAT) - { - /* The number of retries of the most recent transmission is contained in the - * TXNRETRY (TXSTAT 0x24<7:6>) bits. The CCAFAIL (TXSTAT 0x24<5>) bit = 1 - * indicates if the failed transmission was due to the channel busy - * (CSMA-CA timed out). - */ - - if (reg & MRF24J40_TXSTAT_CCAFAIL) - { - status = IEEE802154_STATUS_CHANNEL_ACCESS_FAILURE; - } - else - { - status = IEEE802154_STATUS_NO_ACK; - } - } - else - { - status = IEEE802154_STATUS_SUCCESS; - } - - framepending = (mrf24j40_getreg(dev->spi, MRF24J40_TXNCON) & - MRF24J40_TXNCON_FPSTAT); - - if (dev->txdelayed_busy) - - { - /* Inform the next layer of the transmission success/failure */ - - dev->txdelayed_desc->conf->status = status; - dev->txdelayed_desc->framepending = framepending; - dev->radiocb->txdone(dev->radiocb, dev->txdelayed_desc); - - dev->txdelayed_busy = false; - - if (dev->reschedule_csma) - { - mrf24j40_norm_setup(dev, dev->csma_desc->frame, true); - mrf24j40_norm_trigger(dev); - dev->reschedule_csma = false; - } - } - else - { - /* Inform the next layer of the transmission success/failure */ - - dev->csma_desc->conf->status = status; - dev->csma_desc->framepending = framepending; - dev->radiocb->txdone(dev->radiocb, dev->csma_desc); - - /* We are now done with the transaction */ - - dev->csma_busy = 0; - - /* Must unlock the radio before calling poll */ - - sem_post(&dev->exclsem); - mrf24j40_dopoll_csma(dev); - while (sem_wait(&dev->exclsem) != 0) { } - } -} - -/**************************************************************************** - * Name: mrf24j40_irqwork_gts - * - * Description: - * Manage completion of packet transmission. - * - ****************************************************************************/ - -static void mrf24j40_irqwork_txgts(FAR struct mrf24j40_radio_s *dev, - uint8_t gts) -{ - uint8_t txstat; - - /* Disable tx int */ - - txstat = mrf24j40_getreg(dev->spi, MRF24J40_INTCON); - txstat |= MRF24J40_INTCON_TXNIE; - mrf24j40_setreg(dev->spi, MRF24J40_INTCON, txstat); - - /* Get the status from the device and copy the status into the tx desc. - * The status for the normal FIFO is represented with bit TXNSTAT where - * 0=success, 1= failure. - */ - - txstat = mrf24j40_getreg(dev->spi, MRF24J40_TXSTAT); - - if (gts == 0) - { - dev->csma_desc->conf->status = txstat & MRF24J40_TXSTAT_TXG1STAT; - } - else if (gts == 1) - { - dev->csma_desc->conf->status = txstat & MRF24J40_TXSTAT_TXG2STAT; - } - - /* Inform the next layer of the transmission success/failure */ - - dev->radiocb->txdone(dev->radiocb, dev->gts_desc[gts]); - - /* We are now done with the transaction */ - - dev->gts_busy[gts]= 0; - - mrf24j40_dopoll_gts(dev); -} - /**************************************************************************** * Name: mrf24j40_rxenable * @@ -1932,7 +565,7 @@ static void mrf24j40_irqwork_txgts(FAR struct mrf24j40_radio_s *dev, * ****************************************************************************/ -static int mrf24j40_rxenable(FAR struct ieee802154_radio_s *radio, bool enable) +int mrf24j40_rxenable(FAR struct ieee802154_radio_s *radio, bool enable) { FAR struct mrf24j40_radio_s *dev = (FAR struct mrf24j40_radio_s *)radio; uint8_t reg; @@ -1975,241 +608,25 @@ static int mrf24j40_rxenable(FAR struct ieee802154_radio_s *radio, bool enable) } /**************************************************************************** - * Name: mrf24j40_irqwork_rx + * Name: mrf24j40_resetrfsm * * Description: - * Manage packet reception. + * Reset the RF state machine. Required at boot, after channel change, + * and probably after PA settings. * ****************************************************************************/ -static void mrf24j40_irqwork_rx(FAR struct mrf24j40_radio_s *dev) - +void mrf24j40_resetrfsm(FAR struct mrf24j40_radio_s *dev) { - FAR struct ieee802154_data_ind_s *ind; - uint32_t addr; - uint32_t index; - uint8_t reg; - - wlinfo("RX interrupt\n"); - - /* Disable rx int */ - - reg = mrf24j40_getreg(dev->spi, MRF24J40_INTCON); - reg |= MRF24J40_INTCON_RXIE; - mrf24j40_setreg(dev->spi, MRF24J40_INTCON, reg); - - /* Disable packet reception. See pg. 109 of datasheet */ - - mrf24j40_setreg(dev->spi, MRF24J40_BBREG1, MRF24J40_BBREG1_RXDECINV); - - /* Allocate a data_ind to put the frame in */ - - ind = ieee802154_ind_allocate(); - if (ind == NULL) - { - wlerr("ERROR: Unable to allocate data_ind. Discarding frame\n"); - goto done; - } - - /* Read packet */ - - addr = MRF24J40_RXBUF_BASE; - - ind->frame->io_len = mrf24j40_getreg(dev->spi, addr++); - - for (index = 0; index < ind->frame->io_len; index++) - { - ind->frame->io_data[index] = mrf24j40_getreg(dev->spi, addr++); - } - - ind->lqi = mrf24j40_getreg(dev->spi, addr++); - ind->rssi = mrf24j40_getreg(dev->spi, addr++); - - /* Reduce len by 2, we only receive frames with correct crc, no check - * required. - */ - - ind->frame->io_len -= 2; - - /* Callback the receiver in the next highest layer */ - - dev->radiocb->rxframe(dev->radiocb, ind); - -done: - /* Enable reception of next packet by flushing the fifo. - * This is an MRF24J40 errata (no. 1). - */ - - mrf24j40_setreg(dev->spi, MRF24J40_RXFLUSH, 1); - - /* Only enable RX interrupt if we are to be listening when IDLE */ - - if (dev->rxenabled) - { - /* Enable packet reception */ - - mrf24j40_setreg(dev->spi, MRF24J40_BBREG1, 0); - - reg = mrf24j40_getreg(dev->spi, MRF24J40_INTCON); - reg &= ~MRF24J40_INTCON_RXIE; - mrf24j40_setreg(dev->spi, MRF24J40_INTCON, reg); - } -} - -/**************************************************************************** - * Name: mrf24j40_irqworker - * - * Description: - * Perform interrupt handling logic outside of the interrupt handler (on - * the work queue thread). - * - * Parameters: - * arg - The reference to the driver structure (cast to void*) - * - * Returned Value: - * None - * - * Assumptions: - * - ****************************************************************************/ - -static void mrf24j40_irqworker(FAR void *arg) -{ - FAR struct mrf24j40_radio_s *dev = (FAR struct mrf24j40_radio_s *)arg; - uint8_t intstat; uint8_t reg; - DEBUGASSERT(dev); - DEBUGASSERT(dev->spi); + reg = mrf24j40_getreg(dev->spi, MRF24J40_RFCTL); + reg |= 0x04; + mrf24j40_setreg(dev->spi, MRF24J40_RFCTL, reg); - /* Get exclusive access to the driver */ - - while (sem_wait(&dev->exclsem) != 0) { } - - /* Read and store INTSTAT - this clears the register. */ - - intstat = mrf24j40_getreg(dev->spi, MRF24J40_INTSTAT); - - /* Do work according to the pending interrupts */ - - if ((intstat & MRF24J40_INTSTAT_HSYMTMRIF)) - { - /* As of now the only use for the MAC timer is for delayed transactions. - * Therefore, all we do here is trigger the TX norm FIFO - */ - - mrf24j40_norm_trigger(dev); - - /* Timers are one-shot, so disable the interrupt */ - - reg = mrf24j40_getreg(dev->spi, MRF24J40_INTCON); - reg |= MRF24J40_INTCON_HSYMTMRIE; - mrf24j40_setreg(dev->spi, MRF24J40_INTCON, reg); - } - - if ((intstat & MRF24J40_INTSTAT_RXIF) && dev->rxenabled) - { - /* A packet was received, retrieve it */ - - mrf24j40_irqwork_rx(dev); - } - - if ((intstat & MRF24J40_INTSTAT_TXNIF)) - { - /* A packet was transmitted or failed*/ - - mrf24j40_irqwork_txnorm(dev); - } - - if ((intstat & MRF24J40_INTSTAT_TXG1IF)) - { - /* A packet was transmitted or failed*/ - - mrf24j40_irqwork_txgts(dev, 0); - } - - if ((intstat & MRF24J40_INTSTAT_TXG1IF)) - { - /* A packet was transmitted or failed*/ - - mrf24j40_irqwork_txgts(dev, 1); - } - - if ((intstat & MRF24J40_INTSTAT_SLPIF)) - { - dev->radiocb->sfevent(dev->radiocb, IEEE802154_SFEVENT_ENDOFACTIVE); - - /* Acknowledge the alert and put the device to sleep */ - - reg = mrf24j40_getreg(dev->spi, MRF24J40_SLPACK); - reg |= MRF24J40_SLPACK_SLPACK; - mrf24j40_setreg(dev->spi, MRF24J40_SLPACK, reg); - } - - if ((intstat & MRF24J40_INTSTAT_WAKEIF)) - { -#ifdef CONFIG_MAC802154_SFEVENT_VERBOSE - wlinfo("Wake Interrupt\n"); -#endif - - /* This is right before the beacon, we set the bsn here, since the MAC - * uses the SLPIF (end of active portion of superframe). to make any - * changes to the beacon. This assumes that any changes to the beacon - * be in by the time that this interrupt fires. - */ - - mrf24j40_setreg(dev->spi, MRF24J40_BEACON_FIFO + 4, dev->bsn++); - mrf24j40_beacon_trigger(dev); - } - - /* Unlock the radio device */ - - sem_post(&dev->exclsem); - - /* Re-enable GPIO interrupts */ - - dev->lower->enable(dev->lower, true); -} - -/**************************************************************************** - * Name: mrf24j40_interrupt - * - * Description: - * Hardware interrupt handler - * - * Parameters: - * irq - Number of the IRQ that generated the interrupt - * context - Interrupt register state save info (architecture-specific) - * - * Returned Value: - * OK on success - * - * Assumptions: - * - ****************************************************************************/ - -static int mrf24j40_interrupt(int irq, FAR void *context, FAR void *arg) -{ - FAR struct mrf24j40_radio_s *dev = (FAR struct mrf24j40_radio_s *)arg; - - DEBUGASSERT(dev != NULL); - - /* In complex environments, we cannot do SPI transfers from the interrupt - * handler because semaphores are probably used to lock the SPI bus. In - * this case, we will defer processing to the worker thread. This is also - * much kinder in the use of system resources and is, therefore, probably - * a good thing to do in any event. - */ - - DEBUGASSERT(work_available(&dev->irqwork)); - - /* Notice that further GPIO interrupts are disabled until the work is - * actually performed. This is to prevent overrun of the worker thread. - * Interrupts are re-enabled in enc_irqworker() when the work is completed. - */ - - dev->lower->enable(dev->lower, false); - return work_queue(HPWORK, &dev->irqwork, mrf24j40_irqworker, (FAR void *)dev, 0); + reg &= ~0x04; + mrf24j40_setreg(dev->spi, MRF24J40_RFCTL, reg); + up_udelay(200); } /**************************************************************************** diff --git a/drivers/wireless/ieee802154/mrf24j40/mrf24j40.h b/drivers/wireless/ieee802154/mrf24j40/mrf24j40.h index c21c2e9f38..1a3c15da09 100644 --- a/drivers/wireless/ieee802154/mrf24j40/mrf24j40.h +++ b/drivers/wireless/ieee802154/mrf24j40/mrf24j40.h @@ -33,258 +33,192 @@ * ****************************************************************************/ -#ifndef __DRIVERS_WIRELESS_IEEE802154_MRF24J40_MRF24J40_H -#define __DRIVERS_WIRELESS_IEEE802154_MRF24J40_MRF24J40_H +#ifndef __DRIVERS_WIRELESS_IEEE802154_MRF24J40_H +#define __DRIVERS_WIRELESS_IEEE802154_MRF24J40_H -/* MRF24J40 Registers *******************************************************/ +/**************************************************************************** + * Included Files + ****************************************************************************/ -#define MRF24J40_RXMCR 0x00 -#define MRF24J40_PANIDL 0x01 -#define MRF24J40_PANIDH 0x02 -#define MRF24J40_SADRL 0x03 -#define MRF24J40_SADRH 0x04 -#define MRF24J40_EADR0 0x05 -#define MRF24J40_EADR1 0x06 -#define MRF24J40_EADR2 0x07 -#define MRF24J40_EADR3 0x08 -#define MRF24J40_EADR4 0x09 -#define MRF24J40_EADR5 0x0A -#define MRF24J40_EADR6 0x0B -#define MRF24J40_EADR7 0x0C -#define MRF24J40_RXFLUSH 0x0D -#define MRF24J40_ORDER 0x10 -#define MRF24J40_TXMCR 0x11 -#define MRF24J40_ACKTMOUT 0x12 -#define MRF24J40_ESLOTG1 0x13 -#define MRF24J40_SYMTICKL 0x14 -#define MRF24J40_SYMTICKH 0x15 -#define MRF24J40_PACON0 0x16 -#define MRF24J40_PACON1 0x17 -#define MRF24J40_PACON2 0x18 -#define MRF24J40_TXBCON0 0x1A -#define MRF24J40_TXNCON 0x1B -#define MRF24J40_TXG1CON 0x1C -#define MRF24J40_TXG2CON 0x1D -#define MRF24J40_ESLOTG23 0x1E -#define MRF24J40_ESLOTG45 0x1F -#define MRF24J40_ESLOTG67 0x20 -#define MRF24J40_TXPEND 0x21 -#define MRF24J40_WAKECON 0x22 -#define MRF24J40_FRMOFFSET 0x23 -#define MRF24J40_TXSTAT 0x24 -#define MRF24J40_TXBCON1 0x25 -#define MRF24J40_GATECLK 0x26 -#define MRF24J40_TXTIME 0x27 -#define MRF24J40_HSYMTMRL 0x28 -#define MRF24J40_HSYMTMRH 0x29 -#define MRF24J40_SOFTRST 0x2A -#define MRF24J40_SECCON0 0x2C -#define MRF24J40_SECCON1 0x2C -#define MRF24J40_TXSTBL 0x2E -#define MRF24J40_RXSR 0x30 -#define MRF24J40_INTSTAT 0x31 -#define MRF24J40_INTCON 0x32 -#define MRF24J40_GPIO 0x33 -#define MRF24J40_TRISGPIO 0x34 -#define MRF24J40_SLPACK 0x35 -#define MRF24J40_RFCTL 0x36 -#define MRF24J40_SECCR2 0x37 -#define MRF24J40_BBREG0 0x38 -#define MRF24J40_BBREG1 0x39 -#define MRF24J40_BBREG2 0x3A -#define MRF24J40_BBREG3 0x3B -#define MRF24J40_BBREG4 0x3C -#define MRF24J40_BBREG6 0x3E -#define MRF24J40_CCAEDTH 0x3F +#include -#define MRF24J40_FIFO_BASE 0x80000000 -#define MRF24J40_LONGREG_BASE 0x80000200 -#define MRF24J40_RXBUF_BASE 0x80000300 +#include +#include +#include -#define MRF24J40_TXNORM_FIFO (MRF24J40_FIFO_BASE + 0x000) -#define MRF24J40_BEACON_FIFO (MRF24J40_FIFO_BASE + 0x080) -#define MRF24J40_GTS1_FIFO (MRF24J40_FIFO_BASE + 0x100) -#define MRF24J40_GTS2_FIFO (MRF24J40_FIFO_BASE + 0x180) +#include +#include -#define MRF24J40_RFCON0 (MRF24J40_LONGREG_BASE + 0x00) -#define MRF24J40_RFCON1 (MRF24J40_LONGREG_BASE + 0x01) -#define MRF24J40_RFCON2 (MRF24J40_LONGREG_BASE + 0x02) -#define MRF24J40_RFCON3 (MRF24J40_LONGREG_BASE + 0x03) -#define MRF24J40_RFCON5 (MRF24J40_LONGREG_BASE + 0x05) -#define MRF24J40_RFCON6 (MRF24J40_LONGREG_BASE + 0x06) -#define MRF24J40_RFCON7 (MRF24J40_LONGREG_BASE + 0x07) -#define MRF24J40_RFCON8 (MRF24J40_LONGREG_BASE + 0x08) -#define MRF24J40_SLPCAL0 (MRF24J40_LONGREG_BASE + 0x09) -#define MRF24J40_SLPCAL1 (MRF24J40_LONGREG_BASE + 0x0A) -#define MRF24J40_SLPCAL2 (MRF24J40_LONGREG_BASE + 0x0B) -#define MRF24J40_RFSTATE (MRF24J40_LONGREG_BASE + 0x0F) -#define MRF24J40_RSSI (MRF24J40_LONGREG_BASE + 0x10) -#define MRF24J40_SLPCON0 (MRF24J40_LONGREG_BASE + 0x11) -#define MRF24J40_SLPCON1 (MRF24J40_LONGREG_BASE + 0x20) -#define MRF24J40_WAKETIMEL (MRF24J40_LONGREG_BASE + 0x22) -#define MRF24J40_WAKETIMEH (MRF24J40_LONGREG_BASE + 0x23) -#define MRF24J40_REMCNTL (MRF24J40_LONGREG_BASE + 0x24) -#define MRF24J40_REMCNTH (MRF24J40_LONGREG_BASE + 0x25) -#define MRF24J40_MAINCNT0 (MRF24J40_LONGREG_BASE + 0x26) -#define MRF24J40_MAINCNT1 (MRF24J40_LONGREG_BASE + 0x27) -#define MRF24J40_MAINCNT2 (MRF24J40_LONGREG_BASE + 0x28) -#define MRF24J40_MAINCNT3 (MRF24J40_LONGREG_BASE + 0x29) -#define MRF24J40_TESTMODE (MRF24J40_LONGREG_BASE + 0x2F) -#define MRF24J40_ASSOEADR0 (MRF24J40_LONGREG_BASE + 0x30) -#define MRF24J40_ASSOEADR1 (MRF24J40_LONGREG_BASE + 0x31) -#define MRF24J40_ASSOEADR2 (MRF24J40_LONGREG_BASE + 0x32) -#define MRF24J40_ASSOEADR3 (MRF24J40_LONGREG_BASE + 0x33) -#define MRF24J40_ASSOEADR4 (MRF24J40_LONGREG_BASE + 0x34) -#define MRF24J40_ASSOEADR5 (MRF24J40_LONGREG_BASE + 0x35) -#define MRF24J40_ASSOEADR6 (MRF24J40_LONGREG_BASE + 0x36) -#define MRF24J40_ASSOEADR7 (MRF24J40_LONGREG_BASE + 0x37) -#define MRF24J40_ASSOSADR0 (MRF24J40_LONGREG_BASE + 0x38) -#define MRF24J40_ASSOSADR1 (MRF24J40_LONGREG_BASE + 0x39) -#define MRF24J40_UPNONCE0 (MRF24J40_LONGREG_BASE + 0x40) -#define MRF24J40_UPNONCE1 (MRF24J40_LONGREG_BASE + 0x41) -#define MRF24J40_UPNONCE2 (MRF24J40_LONGREG_BASE + 0x42) -#define MRF24J40_UPNONCE3 (MRF24J40_LONGREG_BASE + 0x43) -#define MRF24J40_UPNONCE4 (MRF24J40_LONGREG_BASE + 0x44) -#define MRF24J40_UPNONCE5 (MRF24J40_LONGREG_BASE + 0x45) -#define MRF24J40_UPNONCE6 (MRF24J40_LONGREG_BASE + 0x46) -#define MRF24J40_UPNONCE7 (MRF24J40_LONGREG_BASE + 0x47) -#define MRF24J40_UPNONCE8 (MRF24J40_LONGREG_BASE + 0x48) -#define MRF24J40_UPNONCE9 (MRF24J40_LONGREG_BASE + 0x49) -#define MRF24J40_UPNONCE10 (MRF24J40_LONGREG_BASE + 0x4A) -#define MRF24J40_UPNONCE11 (MRF24J40_LONGREG_BASE + 0x4B) -#define MRF24J40_UPNONCE12 (MRF24J40_LONGREG_BASE + 0x4C) +#include +#include -/* INTSTAT bits */ +/* NuttX implementation defines **********************************************/ -#define MRF24J40_INTSTAT_TXNIF (1 << 0) -#define MRF24J40_INTSTAT_TXG1IF (1 << 1) -#define MRF24J40_INTSTAT_TXG2IF (1 << 2) -#define MRF24J40_INTSTAT_RXIF (1 << 3) -#define MRF24J40_INTSTAT_SECIF (1 << 4) -#define MRF24J40_INTSTAT_HSYMTMRIF (1 << 5) -#define MRF24J40_INTSTAT_WAKEIF (1 << 6) -#define MRF24J40_INTSTAT_SLPIF (1 << 7) +#define MRF24J40_GTS_SLOTS 2 -/* RXMCR bits */ +/* Definitions for the device structure */ -#define MRF24J40_RXMCR_PROMI (1 << 0) /* Enable promisc mode (rx all valid packets) */ -#define MRF24J40_RXMCR_ERRPKT 0x02 /* Do not check CRC */ -#define MRF24J40_RXMCR_COORD 0x04 /* Enable coordinator mode ??? DIFFERENCE ??? - not used in datasheet! */ -#define MRF24J40_RXMCR_PANCOORD 0x08 /* Enable PAN coordinator mode ??? DIFFERENCE ??? */ -#define MRF24J40_RXMCR_NOACKRSP 0x20 /* Enable auto ACK when a packet is rxed */ +#define MRF24J40_RXMODE_NORMAL 0 +#define MRF24J40_RXMODE_PROMISC 1 +#define MRF24J40_RXMODE_NOCRC 2 -/* TXMCR bits */ +#define MRF24J40_MODE_DEVICE 0 +#define MRF24J40_MODE_COORD 1 +#define MRF24J40_MODE_PANCOORD 2 -#define MRF24J40_TXMCR_CSMABF0 (1 << 0) -#define MRF24J40_TXMCR_CSMABF1 0x02 -#define MRF24J40_TXMCR_CSMABF2 0x04 -#define MRF24J40_TXMCR_MACMINBE0 0x08 -#define MRF24J40_TXMCR_MACMINBE1 0x10 -#define MRF24J40_TXMCR_SLOTTED 0x20 -#define MRF24J40_TXMCR_BATLIFEXT 0x40 -#define MRF24J40_TXMCR_NOCSMA 0x80 +/* Definitions for PA control on high power modules */ -/* ACKTMOUT bits */ +#define MRF24J40_PA_AUTO 1 +#define MRF24J40_PA_ED 2 +#define MRF24J40_PA_SLEEP 3 -#define MRF24J40_ACKTMOUT_MAWD 0xEF -#define MRF24J40_ACKTMOUT_DRPACK 0x80 +/* Formula for calculating default macMaxFrameWaitTime is on pg. 130 + * + * For PHYs other than CSS and UWB, the attribute phyMaxFrameDuration is given by: + * + * phyMaxFrameDuration = phySHRDuration + + * ceiling([aMaxPHYPacketSize + 1] x phySymbolsPerOctet) + * + * where ceiling() is a function that returns the smallest integer value greater + * than or equal to its argument value. [1] pg. 158 +*/ -/* INTCON bits */ +#define MRF24J40_DEFAULT_MAX_FRAME_WAITTIME 1824 -#define MRF24J40_INTCON_SLPIE 0x80 -#define MRF24J40_INTCON_WAKEIE 0x40 -#define MRF24J40_INTCON_HSYMTMRIE 0x20 -#define MRF24J40_INTCON_SECIE 0x10 -#define MRF24J40_INTCON_RXIE 0x08 -#define MRF24J40_INTCON_TXG2IE 0x04 -#define MRF24J40_INTCON_TXG1IE 0x02 -#define MRF24J40_INTCON_TXNIE (1 << 0) +#define MRF24J40_SYMBOL_DURATION_PS 16000000 -/* BBREG1 bits */ +/* Configuration *************************************************************/ -#define MRF24J40_BBREG1_RXDECINV 0x04 /* Enable/Disable packet reception */ +#ifndef CONFIG_SCHED_HPWORK +# error High priority work queue required in this driver +#endif -/* BBREG2 bits */ +#ifndef CONFIG_IEEE802154_MRF24J40_SPIMODE +# define CONFIG_IEEE802154_MRF24J40_SPIMODE SPIDEV_MODE0 +#endif -#define MRF24J40_BBREG2_CCAMODE_ED 0x80 -#define MRF24J40_BBREG2_CCAMODE_CS 0x40 +#ifndef CONFIG_IEEE802154_MRF24J40_FREQUENCY +# define CONFIG_IEEE802154_MRF24J40_FREQUENCY 8000000 +#endif -/* TXNCON bits */ +#ifndef CONFIG_SPI_EXCHANGE +# error CONFIG_SPI_EXCHANGE required for this driver +#endif -#define MRF24J40_TXNCON_TXNTRIG (1 << 0) /* Trigger packet tx, automatically cleared */ -#define MRF24J40_TXNCON_TXNSECEN 0x02 /* Enable security */ -#define MRF24J40_TXNCON_TXNACKREQ 0x04 /* An ACK is requested for this pkt */ -#define MRF24J40_TXNCON_INDIRECT 0x08 /* Activate indirect tx bit (for coordinators) */ -#define MRF24J40_TXNCON_FPSTAT 0x10 /* Status of the frame pending big in txed acks */ +/**************************************************************************** + * Private Types + ****************************************************************************/ -/* TXSTAT bits */ +/* A MRF24J40 device instance */ -#define MRF24J40_TXSTAT_TXNSTAT (1 << 0) -#define MRF24J40_TXSTAT_TXG1STAT (1 << 1) -#define MRF24J40_TXSTAT_TXG2STAT (1 << 2) -#define MRF24J40_TXSTAT_CCAFAIL (1 << 5) -#define MRF24J40_TXSTAT_X_SHIFT 6 -#define MRF24J40_TXSTAT_X_MASK (3 << MRF24J40_TXSTAT_X_SHIFT) +struct mrf24j40_radio_s +{ + struct ieee802154_radio_s radio; /* The public device instance */ + FAR struct ieee802154_radiocb_s *radiocb; /* Registered callbacks */ -/* TXBCON0 bits */ + /* Low-level MCU-specific support */ -#define MRF24J40_TXBCON0_TXBTRIG 0x01 -#define MRF24J40_TXBCON0_TXBSECEN 0x02 + FAR const struct mrf24j40_lower_s *lower; + FAR struct spi_dev_s *spi; /* Saved SPI interface instance */ -/* TXBCON1 bits */ + struct work_s irqwork; /* For deferring interrupt work to work queue */ + struct work_s csma_pollwork; /* For deferring poll work to the work queue */ + struct work_s gts_pollwork; /* For deferring poll work to the work queue */ -#define MRF24J40_TXBCON1_RSSINUM 0x30 -#define MRF24J40_TXBCON1_NWU_BCN 0x40 -#define MRF24J40_TXBCON1_TXBMSK 0x80 + sem_t exclsem; /* Exclusive access to this struct */ -/* WAKECON bits */ + /* MAC Attributes */ -#define MRF24J40_WAKECON_INTL 0x3F -#define MRF24J40_WAKECON_REGWAKE 0x40 -#define MRF24J40_WAKECON_IMMWAKE 0x80 + struct ieee802154_addr_s addr; -/* WAKECON bits */ + uint8_t chan; /* 11 to 26 for the 2.4 GHz band */ + uint8_t devmode; /* device mode: device, coord, pancoord */ + uint8_t paenabled; /* enable usage of PA */ + uint8_t rxmode; /* Reception mode: Main, no CRC, promiscuous */ + int32_t txpower; /* TX power in mBm = dBm/100 */ + struct ieee802154_cca_s cca; /* Clear channel assessement method */ -#define MRF24J40_WAKECON_INTL 0x3F -#define MRF24J40_WAKECON_REGWAKE 0x40 -#define MRF24J40_WAKECON_IMMWAKE 0x80 + /* MAC PIB attributes */ -/* ESLOTG1 bits */ + uint32_t max_frame_waittime; -#define MRF24J40_ESLOTG1_CAP 0x0F -#define MRF24J40_ESLOTG1_GTS1 0xF0 + struct ieee802154_txdesc_s *txdelayed_desc; + struct ieee802154_txdesc_s *csma_desc; + bool txdelayed_busy : 1; + bool csma_busy : 1; + bool reschedule_csma : 1; -/* SLPCAL2 bits */ + bool rxenabled : 1; -#define MRF24J40_SLPCAL2_SLPCAL 0x0F -#define MRF24J40_SLPCAL2_SLPCALEN 0x10 -#define MRF24J40_SLPCAL2_SLPCALRDY 0x80 + uint8_t bsn; -/* RFCON7 bits */ + struct ieee802154_txdesc_s *gts_desc[MRF24J40_GTS_SLOTS]; + bool gts_busy[MRF24J40_GTS_SLOTS]; +}; -#define MRF24J40_RFCON7_SEL_32KHZ 0x40 -#define MRF24J40_RFCON7_SEL_100KHZ 0x80 +/**************************************************************************** + * Internal Function Prototypes + ****************************************************************************/ -/* SLPACK bits */ +int mrf24j40_interrupt(int irq, FAR void *context, FAR void *arg); +void mrf24j40_irqworker(FAR void *arg); -#define MRF24J40_SLPACK_WAKECNT0_6 0x7F -#define MRF24J40_SLPACK_SLPACK 0x80 +void mrf24j40_dopoll_csma(FAR void *arg); +void mrf24j40_dopoll_gts(FAR void *arg); -/* RXFLUSH bits */ +void mrf24j40_resetrfsm(FAR struct mrf24j40_radio_s *dev); -#define MRF24J40_RXFLUSH_RXFLUSH 0x01 -#define MRF24J40_RXFLUSH_BCNONLY 0x02 -#define MRF24J40_RXFLUSH_DATAONLY 0x04 -#define MRF24J40_RXFLUSH_CMDONLY 0x08 -#define MRF24J40_RXFLUSH_WAKEPAD 0x20 -#define MRF24J40_RXFLUSH_WAKEPOL 0x40 +void mrf24j40_setorder(FAR struct mrf24j40_radio_s *dev, uint8_t bo, uint8_t so); -#define MRF24J40_RXFLUSH_SHIFT_RXFLUSH 0 -#define MRF24J40_RXFLUSH_SHIFT_BCNONLY 1 -#define MRF24J40_RXFLUSH_SHIFT_DATAONLY 2 -#define MRF24J40_RXFLUSH_SHIFT_CMDONLY 3 -#define MRF24J40_RXFLUSH_SHIFT_WAKEPAD 5 -#define MRF24J40_RXFLUSH_SHIFT_WAKEPOL 6 +int mrf24j40_pacontrol(FAR struct mrf24j40_radio_s *dev, int mode); +int mrf24j40_energydetect(FAR struct mrf24j40_radio_s *dev, FAR uint8_t *energy); -#endif /* __DRIVERS_WIRELESS_IEEE802154_MRF24J40_MRF24J40_H */ +int mrf24j40_rxenable(FAR struct ieee802154_radio_s *dev, bool enable); + +void mrf24j40_norm_setup(FAR struct mrf24j40_radio_s *dev, + FAR struct iob_s *frame, bool csma); +void mrf24j40_gts_setup(FAR struct mrf24j40_radio_s *dev, uint8_t gts, + FAR struct iob_s *frame); +void mrf24j40_setup_fifo(FAR struct mrf24j40_radio_s *dev, + FAR const uint8_t *buf, uint8_t length, uint32_t fifo_addr); + +void mrf24j40_norm_trigger(FAR struct mrf24j40_radio_s *dev); +void mrf24j40_beacon_trigger(FAR struct mrf24j40_radio_s *dev); + +void mrf24j40_mactimer(FAR struct mrf24j40_radio_s *dev, int numsymbols); + +/**************************************************************************** + * Internal Helpers + ****************************************************************************/ + +/**************************************************************************** + * Name: mrf24j40_spi_lock + * + * Description: + * Acquire exclusive access to the shared SPI bus. + * + ****************************************************************************/ + +static inline void mrf24j40_spi_lock(FAR struct spi_dev_s *spi) +{ + SPI_LOCK(spi, 1); + SPI_SETBITS(spi, 8); + SPI_SETMODE(spi, CONFIG_IEEE802154_MRF24J40_SPIMODE); + SPI_SETFREQUENCY(spi, CONFIG_IEEE802154_MRF24J40_FREQUENCY); +} + +/**************************************************************************** + * Name: mrf24j40_spi_unlock + * + * Description: + * Release exclusive access to the shared SPI bus. + * + ****************************************************************************/ + +static inline void mrf24j40_spi_unlock(FAR struct spi_dev_s *spi) +{ + SPI_LOCK(spi,0); +} + +#endif /* __DRIVERS_WIRELESS_IEEE802154_MRF24J40_H */ diff --git a/drivers/wireless/ieee802154/mrf24j40/mrf24j40_getset.c b/drivers/wireless/ieee802154/mrf24j40/mrf24j40_getset.c new file mode 100644 index 0000000000..a4b92ad666 --- /dev/null +++ b/drivers/wireless/ieee802154/mrf24j40/mrf24j40_getset.c @@ -0,0 +1,425 @@ +/**************************************************************************** + * drivers/wireless/ieee802154/mrf24j40/mrf24j40_getset.c + * + * Copyright (C) 2015-2016 Sebastien Lorquet. All rights reserved. + * Copyright (C) 2017 Verge Inc. All rights reserved. + * Author: Sebastien Lorquet + * Author: Anthony Merlino + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include +#include + +#include "mrf24j40.h" +#include "mrf24j40_reg.h" +#include "mrf24j40_regops.h" +#include "mrf24j40_getset.h" + +/**************************************************************************** + * Name: mrf24j40_setrxmode + * + * Description: + * Set the RX mode (normal, promiscuous, no CRC) + * + ****************************************************************************/ + +int mrf24j40_setrxmode(FAR struct mrf24j40_radio_s *dev, int mode) +{ + uint8_t reg; + + if (mode < MRF24J40_RXMODE_NORMAL || mode > MRF24J40_RXMODE_NOCRC) + { + return -EINVAL; + } + + reg = mrf24j40_getreg(dev->spi, MRF24J40_RXMCR); + reg &= ~0x03; + reg |= mode; + + /* Set mode options */ + + if (mode != MRF24J40_RXMODE_NORMAL) + { + /* Promisc and error modes: Disable auto ACK */ + + reg |= MRF24J40_RXMCR_NOACKRSP; + } + else + { + /* Normal mode : enable auto-ACK */ + + reg &= ~MRF24J40_RXMCR_NOACKRSP; + } + + mrf24j40_setreg(dev->spi, MRF24J40_RXMCR, reg); + + dev->rxmode = mode; + wlinfo("%u\n", (unsigned)mode); + return OK; +} + +/**************************************************************************** + * Name: mrf24j40_setchannel + * + * Description: + * Define the current radio channel the device is operating on. + * In the 2.4 GHz, there are 16 channels, each 2 MHz wide, 5 MHz spacing: + * Chan MHz Chan MHz Chan MHz Chan MHz + * 11 2405 15 2425 19 2445 23 2465 + * 12 2410 16 2430 20 2450 24 2470 + * 13 2415 17 2435 21 2455 25 2475 + * 14 2420 18 2440 22 2460 26 2480 + * + ****************************************************************************/ + +int mrf24j40_setchannel(FAR struct mrf24j40_radio_s *dev, uint8_t chan) +{ + if (chan < 11 || chan > 26) + { + wlerr("ERROR: Invalid chan: %d\n",chan); + return -EINVAL; + } + + /* 15. Set channel – See Section 3.4 “Channel Selection”. */ + + mrf24j40_setreg(dev->spi, MRF24J40_RFCON0, (chan - 11) << 4 | 0x03); + + /* 17. RFCTL (0x36) = 0x04 – Reset RF state machine. + * 18. RFCTL (0x36) = 0x00. + */ + + mrf24j40_resetrfsm(dev); + + dev->chan = chan; + wlinfo("%u\n", (unsigned)chan); + + return OK; +} + +/**************************************************************************** + * Name: mrf24j40_setpanid + * + * Description: + * Define the PAN ID the device is operating on. + * + ****************************************************************************/ + +int mrf24j40_setpanid(FAR struct mrf24j40_radio_s *dev, + FAR const uint8_t *panid) +{ + mrf24j40_setreg(dev->spi, MRF24J40_PANIDL, panid[0]); + mrf24j40_setreg(dev->spi, MRF24J40_PANIDH, panid[1]); + + IEEE802154_PANIDCOPY(dev->addr.panid, panid); + wlinfo("%02X:%02X\n", panid[0], panid[1]); + + return OK; +} + +/**************************************************************************** + * Name: mrf24j40_setsaddr + * + * Description: + * Define the device short address. The following addresses are special: + * FFFEh : Broadcast + * FFFFh : Unspecified + * + ****************************************************************************/ + +int mrf24j40_setsaddr(FAR struct mrf24j40_radio_s *dev, + FAR const uint8_t *saddr) +{ + mrf24j40_setreg(dev->spi, MRF24J40_SADRL, saddr[0]); + mrf24j40_setreg(dev->spi, MRF24J40_SADRH, saddr[1]); + + IEEE802154_SADDRCOPY(dev->addr.saddr, saddr); + + wlinfo("%02X:%02X\n", saddr[0], saddr[1]); + return OK; +} + +/**************************************************************************** + * Name: mrf24j40_seteaddr + * + * Description: + * Define the device extended address. The following addresses are special: + * FFFFFFFFFFFFFFFFh : Unspecified + * + ****************************************************************************/ + +int mrf24j40_seteaddr(FAR struct mrf24j40_radio_s *dev, + FAR const uint8_t *eaddr) +{ + int i; + + for (i = 0; i < 8; i++) + { + mrf24j40_setreg(dev->spi, MRF24J40_EADR0 + i, eaddr[i]); + dev->addr.eaddr[i] = eaddr[i]; + } + wlinfo("%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X\n", eaddr[0], eaddr[1], + eaddr[2], eaddr[3], eaddr[4], eaddr[5], eaddr[6], eaddr[7]); + + return OK; +} + +/**************************************************************************** + * Name: mrf24j40_setcoordsaddr + * + * Description: + * Define the coordinator short address. The following addresses are special: + * FFFEh : Broadcast + * FFFFh : Unspecified + * + ****************************************************************************/ + +int mrf24j40_setcoordsaddr(FAR struct mrf24j40_radio_s *dev, + FAR const uint8_t *saddr) +{ + mrf24j40_setreg(dev->spi, MRF24J40_ASSOSADR0, saddr[0]); + mrf24j40_setreg(dev->spi, MRF24J40_ASSOSADR1, saddr[1]); + + IEEE802154_SADDRCOPY(dev->addr.saddr, saddr); + + wlinfo("%02X:%02X\n", saddr[0], saddr[1]); + return OK; +} + +/**************************************************************************** + * Name: mrf24j40_setcoordeaddr + * + * Description: + * Define the coordinator extended address. The following addresses are special: + * FFFFFFFFFFFFFFFFh : Unspecified + * + ****************************************************************************/ + +int mrf24j40_setcoordeaddr(FAR struct mrf24j40_radio_s *dev, + FAR const uint8_t *eaddr) +{ + int i; + + for (i = 0; i < 8; i++) + { + mrf24j40_setreg(dev->spi, MRF24J40_ASSOEADR0 + i, eaddr[i]); + dev->addr.eaddr[i] = eaddr[i]; + } + + wlinfo("%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X\n", eaddr[0], eaddr[1], + eaddr[2], eaddr[3], eaddr[4], eaddr[5], eaddr[6], eaddr[7]); + return OK; +} + +/**************************************************************************** + * Name: mrf24j40_setdevmode + * + * Description: + * Define the device behaviour: normal end device or coordinator + * + ****************************************************************************/ + +int mrf24j40_setdevmode(FAR struct mrf24j40_radio_s *dev, + uint8_t mode) +{ + int ret = OK; + uint8_t reg; + + /* Disable slotted mode until I decide to implement slotted mode */ + + reg = mrf24j40_getreg(dev->spi, MRF24J40_TXMCR); + reg &= ~MRF24J40_TXMCR_SLOTTED; + mrf24j40_setreg(dev->spi, MRF24J40_TXMCR, reg); + mrf24j40_setreg(dev->spi, MRF24J40_ORDER, 0xFF); + + /* Define dev mode */ + + reg = mrf24j40_getreg(dev->spi, MRF24J40_RXMCR); + + if (mode == MRF24J40_MODE_PANCOORD) + { + reg |= MRF24J40_RXMCR_PANCOORD; + reg &= ~MRF24J40_RXMCR_COORD; + } + else if (mode == MRF24J40_MODE_COORD) + { + reg |= MRF24J40_RXMCR_COORD; + reg &= ~MRF24J40_RXMCR_PANCOORD; + } + else if (mode == MRF24J40_MODE_DEVICE) + { + reg &= ~MRF24J40_RXMCR_PANCOORD; + reg &= ~MRF24J40_RXMCR_COORD; + } + else + { + return -EINVAL; + } + + mrf24j40_setreg(dev->spi, MRF24J40_RXMCR, reg); + dev->devmode = mode; + return ret; +} + +/**************************************************************************** + * Name: mrf24j40_settxpower + * + * Description: + * Define the transmit power. Value is passed in mBm, it is rounded to + * the nearest value. Some MRF modules have a power amplifier, this routine + * does not care about this. We only change the CHIP output power. + * + ****************************************************************************/ + +int mrf24j40_settxpower(FAR struct mrf24j40_radio_s *dev, + int32_t txpwr) +{ + uint8_t reg; + int save_txpwr = txpwr; + + if (txpwr <= -3000 && txpwr > -3630) + { + reg = 0xC0; + txpwr += 3000; + } + else if (txpwr <= -2000) + { + reg = 0x80; + txpwr += 2000; + } + else if (txpwr <= -1000) + { + reg = 0x40; + txpwr += 1000; + } + else if (txpwr <= 0) + { + reg = 0x00; + } + else + { + return -EINVAL; + } + + wlinfo("Remaining attenuation: %d mBm\n",txpwr); + + switch(txpwr/100) + { + case -9: + case -8: + case -7: + case -6: + reg |= 0x07; + break; + + case -5: + reg |= 0x06; + break; + + case -4: + reg |= 0x05; + break; + + case -3: + reg |= 0x04; + break; + + case -2: + reg |= 0x03; + break; + + case -1: + reg |= 0x02; + break; + + case 0: + reg |= 0x00; /* value 0x01 is 0.5 db, not used */ + break; + + default: + + return -EINVAL; + } + + mrf24j40_setreg(dev->spi, MRF24J40_RFCON3, reg); + + dev->txpower = save_txpwr; + + return OK; +} + +/**************************************************************************** + * Name: mrf24j40_setcca + * + * Description: + * Define the Clear Channel Assessement method. + * + ****************************************************************************/ + +int mrf24j40_setcca(FAR struct mrf24j40_radio_s *dev, + FAR struct ieee802154_cca_s *cca) +{ + uint8_t mode; + + if (!cca->use_ed && !cca->use_cs) + { + return -EINVAL; + } + + if (cca->use_cs && cca->csth > 0x0f) + { + return -EINVAL; + } + + mode = mrf24j40_getreg(dev->spi, MRF24J40_BBREG2); + mode &= 0x03; + + if (cca->use_ed) + { + mode |= MRF24J40_BBREG2_CCAMODE_ED; + mrf24j40_setreg(dev->spi, MRF24J40_CCAEDTH, cca->edth); + } + + if (cca->use_cs) + { + mode |= MRF24J40_BBREG2_CCAMODE_CS; + mode |= cca->csth << 2; + } + + mrf24j40_setreg(dev->spi, MRF24J40_BBREG2, mode); + + memcpy(&dev->cca, cca, sizeof(struct ieee802154_cca_s)); + return OK; +} diff --git a/drivers/wireless/ieee802154/mrf24j40/mrf24j40_getset.h b/drivers/wireless/ieee802154/mrf24j40/mrf24j40_getset.h new file mode 100644 index 0000000000..999ce92875 --- /dev/null +++ b/drivers/wireless/ieee802154/mrf24j40/mrf24j40_getset.h @@ -0,0 +1,64 @@ +/**************************************************************************** + * drivers/wireless/ieee802154/mrf24j40/mrf24j40_getset.h + * + * Copyright (C) 2015-2016 Sebastien Lorquet. All rights reserved. + * Copyright (C) 2017 Verge Inc. All rights reserved. + * Author: Sebastien Lorquet + * Author: Anthony Merlino + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +#ifndef __DRIVERS_WIRELESS_IEEE802154_MRF24J40_GETSET_H +#define __DRIVERS_WIRELESS_IEEE802154_MRF24J40_GETSET_H + +int mrf24j40_setrxmode(FAR struct mrf24j40_radio_s *dev, int mode); + +int mrf24j40_setchannel(FAR struct mrf24j40_radio_s *dev, uint8_t chan); + +int mrf24j40_setpanid(FAR struct mrf24j40_radio_s *dev, FAR const uint8_t *panid); + +int mrf24j40_setsaddr(FAR struct mrf24j40_radio_s *dev, FAR const uint8_t *saddr); + +int mrf24j40_seteaddr(FAR struct mrf24j40_radio_s *dev, FAR const uint8_t *eaddr); + +int mrf24j40_setcoordsaddr(FAR struct mrf24j40_radio_s *dev, + FAR const uint8_t *saddr); + +int mrf24j40_setcoordeaddr(FAR struct mrf24j40_radio_s *dev, + FAR const uint8_t *eaddr); + +int mrf24j40_setdevmode(FAR struct mrf24j40_radio_s *dev, uint8_t mode); + +int mrf24j40_settxpower(FAR struct mrf24j40_radio_s *dev, int32_t txpwr); + +int mrf24j40_setcca(FAR struct mrf24j40_radio_s *dev, + FAR struct ieee802154_cca_s *cca); + +#endif /* __DRIVERS_WIRELESS_IEEE802154_MRF24J40_GETSET_H */ \ No newline at end of file diff --git a/drivers/wireless/ieee802154/mrf24j40/mrf24j40_interrupt.c b/drivers/wireless/ieee802154/mrf24j40/mrf24j40_interrupt.c new file mode 100644 index 0000000000..673aba7c34 --- /dev/null +++ b/drivers/wireless/ieee802154/mrf24j40/mrf24j40_interrupt.c @@ -0,0 +1,439 @@ +/**************************************************************************** + * drivers/wireless/ieee802154/mrf24j40/mrf24j40_interrupt.c + * + * Copyright (C) 2015-2016 Sebastien Lorquet. All rights reserved. + * Copyright (C) 2017 Verge Inc. All rights reserved. + * Author: Sebastien Lorquet + * Author: Anthony Merlino + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include +#include + +#include + +#include + +#include "mrf24j40.h" +#include "mrf24j40_reg.h" +#include "mrf24j40_regops.h" + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +static void mrf24j40_irqwork_rx(FAR struct mrf24j40_radio_s *dev); +static void mrf24j40_irqwork_txnorm(FAR struct mrf24j40_radio_s *dev); +static void mrf24j40_irqwork_txgts(FAR struct mrf24j40_radio_s *dev, + uint8_t gts_num); + +/**************************************************************************** + * Name: mrf24j40_irqwork_txnorm + * + * Description: + * Manage completion of packet transmission. + * + ****************************************************************************/ + +static void mrf24j40_irqwork_txnorm(FAR struct mrf24j40_radio_s *dev) +{ + uint8_t reg; + enum ieee802154_status_e status; + bool framepending; + + /* Disable tx int */ + + reg = mrf24j40_getreg(dev->spi, MRF24J40_INTCON); + reg |= MRF24J40_INTCON_TXNIE; + mrf24j40_setreg(dev->spi, MRF24J40_INTCON, reg); + + /* Get the status from the device and copy the status into the tx desc. + * The status for the normal FIFO is represented with bit TXNSTAT where + * 0=success, 1= failure. + */ + + reg = mrf24j40_getreg(dev->spi, MRF24J40_TXSTAT); + + /* TXNSTAT = 0: Transmission was successful + * TXNSTAT = 1: Transmission failed, retry count exceeded + */ + + if (reg & MRF24J40_TXSTAT_TXNSTAT) + { + /* The number of retries of the most recent transmission is contained in the + * TXNRETRY (TXSTAT 0x24<7:6>) bits. The CCAFAIL (TXSTAT 0x24<5>) bit = 1 + * indicates if the failed transmission was due to the channel busy + * (CSMA-CA timed out). + */ + + if (reg & MRF24J40_TXSTAT_CCAFAIL) + { + status = IEEE802154_STATUS_CHANNEL_ACCESS_FAILURE; + } + else + { + status = IEEE802154_STATUS_NO_ACK; + } + } + else + { + status = IEEE802154_STATUS_SUCCESS; + } + + framepending = (mrf24j40_getreg(dev->spi, MRF24J40_TXNCON) & + MRF24J40_TXNCON_FPSTAT); + + if (dev->txdelayed_busy) + + { + /* Inform the next layer of the transmission success/failure */ + + dev->txdelayed_desc->conf->status = status; + dev->txdelayed_desc->framepending = framepending; + dev->radiocb->txdone(dev->radiocb, dev->txdelayed_desc); + + dev->txdelayed_busy = false; + + if (dev->reschedule_csma) + { + mrf24j40_norm_setup(dev, dev->csma_desc->frame, true); + mrf24j40_norm_trigger(dev); + dev->reschedule_csma = false; + } + } + else + { + /* Inform the next layer of the transmission success/failure */ + + dev->csma_desc->conf->status = status; + dev->csma_desc->framepending = framepending; + dev->radiocb->txdone(dev->radiocb, dev->csma_desc); + + /* We are now done with the transaction */ + + dev->csma_busy = 0; + + /* Must unlock the radio before calling poll */ + + sem_post(&dev->exclsem); + mrf24j40_dopoll_csma(dev); + while (sem_wait(&dev->exclsem) != 0) { } + } +} + +/**************************************************************************** + * Name: mrf24j40_irqwork_gts + * + * Description: + * Manage completion of packet transmission. + * + ****************************************************************************/ + +static void mrf24j40_irqwork_txgts(FAR struct mrf24j40_radio_s *dev, + uint8_t gts) +{ + uint8_t txstat; + + /* Disable tx int */ + + txstat = mrf24j40_getreg(dev->spi, MRF24J40_INTCON); + txstat |= MRF24J40_INTCON_TXNIE; + mrf24j40_setreg(dev->spi, MRF24J40_INTCON, txstat); + + /* Get the status from the device and copy the status into the tx desc. + * The status for the normal FIFO is represented with bit TXNSTAT where + * 0=success, 1= failure. + */ + + txstat = mrf24j40_getreg(dev->spi, MRF24J40_TXSTAT); + + if (gts == 0) + { + dev->csma_desc->conf->status = txstat & MRF24J40_TXSTAT_TXG1STAT; + } + else if (gts == 1) + { + dev->csma_desc->conf->status = txstat & MRF24J40_TXSTAT_TXG2STAT; + } + + /* Inform the next layer of the transmission success/failure */ + + dev->radiocb->txdone(dev->radiocb, dev->gts_desc[gts]); + + /* We are now done with the transaction */ + + dev->gts_busy[gts]= 0; + + mrf24j40_dopoll_gts(dev); +} + +/**************************************************************************** + * Name: mrf24j40_irqwork_rx + * + * Description: + * Manage packet reception. + * + ****************************************************************************/ + +static void mrf24j40_irqwork_rx(FAR struct mrf24j40_radio_s *dev) + +{ + FAR struct ieee802154_data_ind_s *ind; + uint32_t addr; + uint32_t index; + uint8_t reg; + + wlinfo("RX interrupt\n"); + + /* Disable rx int */ + + reg = mrf24j40_getreg(dev->spi, MRF24J40_INTCON); + reg |= MRF24J40_INTCON_RXIE; + mrf24j40_setreg(dev->spi, MRF24J40_INTCON, reg); + + /* Disable packet reception. See pg. 109 of datasheet */ + + mrf24j40_setreg(dev->spi, MRF24J40_BBREG1, MRF24J40_BBREG1_RXDECINV); + + /* Allocate a data_ind to put the frame in */ + + ind = ieee802154_ind_allocate(); + if (ind == NULL) + { + wlerr("ERROR: Unable to allocate data_ind. Discarding frame\n"); + goto done; + } + + /* Read packet */ + + addr = MRF24J40_RXBUF_BASE; + + ind->frame->io_len = mrf24j40_getreg(dev->spi, addr++); + + for (index = 0; index < ind->frame->io_len; index++) + { + ind->frame->io_data[index] = mrf24j40_getreg(dev->spi, addr++); + } + + ind->lqi = mrf24j40_getreg(dev->spi, addr++); + ind->rssi = mrf24j40_getreg(dev->spi, addr++); + + /* Reduce len by 2, we only receive frames with correct crc, no check + * required. + */ + + ind->frame->io_len -= 2; + + /* Callback the receiver in the next highest layer */ + + dev->radiocb->rxframe(dev->radiocb, ind); + +done: + /* Enable reception of next packet by flushing the fifo. + * This is an MRF24J40 errata (no. 1). + */ + + mrf24j40_setreg(dev->spi, MRF24J40_RXFLUSH, 1); + + /* Only enable RX interrupt if we are to be listening when IDLE */ + + if (dev->rxenabled) + { + /* Enable packet reception */ + + mrf24j40_setreg(dev->spi, MRF24J40_BBREG1, 0); + + reg = mrf24j40_getreg(dev->spi, MRF24J40_INTCON); + reg &= ~MRF24J40_INTCON_RXIE; + mrf24j40_setreg(dev->spi, MRF24J40_INTCON, reg); + } +} + +/**************************************************************************** + * Name: mrf24j40_irqworker + * + * Description: + * Perform interrupt handling logic outside of the interrupt handler (on + * the work queue thread). + * + * Parameters: + * arg - The reference to the driver structure (cast to void*) + * + * Returned Value: + * None + * + * Assumptions: + * + ****************************************************************************/ + +void mrf24j40_irqworker(FAR void *arg) +{ + FAR struct mrf24j40_radio_s *dev = (FAR struct mrf24j40_radio_s *)arg; + uint8_t intstat; + uint8_t reg; + + DEBUGASSERT(dev); + DEBUGASSERT(dev->spi); + + /* Get exclusive access to the driver */ + + while (sem_wait(&dev->exclsem) != 0) { } + + /* Read and store INTSTAT - this clears the register. */ + + intstat = mrf24j40_getreg(dev->spi, MRF24J40_INTSTAT); + + /* Do work according to the pending interrupts */ + + if ((intstat & MRF24J40_INTSTAT_HSYMTMRIF)) + { + /* As of now the only use for the MAC timer is for delayed transactions. + * Therefore, all we do here is trigger the TX norm FIFO + */ + + mrf24j40_norm_trigger(dev); + + /* Timers are one-shot, so disable the interrupt */ + + reg = mrf24j40_getreg(dev->spi, MRF24J40_INTCON); + reg |= MRF24J40_INTCON_HSYMTMRIE; + mrf24j40_setreg(dev->spi, MRF24J40_INTCON, reg); + } + + if ((intstat & MRF24J40_INTSTAT_RXIF) && dev->rxenabled) + { + /* A packet was received, retrieve it */ + + mrf24j40_irqwork_rx(dev); + } + + if ((intstat & MRF24J40_INTSTAT_TXNIF)) + { + /* A packet was transmitted or failed*/ + + mrf24j40_irqwork_txnorm(dev); + } + + if ((intstat & MRF24J40_INTSTAT_TXG1IF)) + { + /* A packet was transmitted or failed*/ + + mrf24j40_irqwork_txgts(dev, 0); + } + + if ((intstat & MRF24J40_INTSTAT_TXG1IF)) + { + /* A packet was transmitted or failed*/ + + mrf24j40_irqwork_txgts(dev, 1); + } + + if ((intstat & MRF24J40_INTSTAT_SLPIF)) + { + dev->radiocb->sfevent(dev->radiocb, IEEE802154_SFEVENT_ENDOFACTIVE); + + /* Acknowledge the alert and put the device to sleep */ + + reg = mrf24j40_getreg(dev->spi, MRF24J40_SLPACK); + reg |= MRF24J40_SLPACK_SLPACK; + mrf24j40_setreg(dev->spi, MRF24J40_SLPACK, reg); + } + + if ((intstat & MRF24J40_INTSTAT_WAKEIF)) + { +#ifdef CONFIG_MAC802154_SFEVENT_VERBOSE + wlinfo("Wake Interrupt\n"); +#endif + + /* This is right before the beacon, we set the bsn here, since the MAC + * uses the SLPIF (end of active portion of superframe). to make any + * changes to the beacon. This assumes that any changes to the beacon + * be in by the time that this interrupt fires. + */ + + mrf24j40_setreg(dev->spi, MRF24J40_BEACON_FIFO + 4, dev->bsn++); + mrf24j40_beacon_trigger(dev); + } + + /* Unlock the radio device */ + + sem_post(&dev->exclsem); + + /* Re-enable GPIO interrupts */ + + dev->lower->enable(dev->lower, true); +} + +/**************************************************************************** + * Name: mrf24j40_interrupt + * + * Description: + * Hardware interrupt handler + * + * Parameters: + * irq - Number of the IRQ that generated the interrupt + * context - Interrupt register state save info (architecture-specific) + * + * Returned Value: + * OK on success + * + * Assumptions: + * + ****************************************************************************/ + +int mrf24j40_interrupt(int irq, FAR void *context, FAR void *arg) +{ + FAR struct mrf24j40_radio_s *dev = (FAR struct mrf24j40_radio_s *)arg; + + DEBUGASSERT(dev != NULL); + + /* In complex environments, we cannot do SPI transfers from the interrupt + * handler because semaphores are probably used to lock the SPI bus. In + * this case, we will defer processing to the worker thread. This is also + * much kinder in the use of system resources and is, therefore, probably + * a good thing to do in any event. + */ + + DEBUGASSERT(work_available(&dev->irqwork)); + + /* Notice that further GPIO interrupts are disabled until the work is + * actually performed. This is to prevent overrun of the worker thread. + * Interrupts are re-enabled in enc_irqworker() when the work is completed. + */ + + dev->lower->enable(dev->lower, false); + return work_queue(HPWORK, &dev->irqwork, mrf24j40_irqworker, (FAR void *)dev, 0); +} diff --git a/drivers/wireless/ieee802154/mrf24j40/mrf24j40_radif.c b/drivers/wireless/ieee802154/mrf24j40/mrf24j40_radif.c new file mode 100644 index 0000000000..1f23d2188a --- /dev/null +++ b/drivers/wireless/ieee802154/mrf24j40/mrf24j40_radif.c @@ -0,0 +1,530 @@ +/**************************************************************************** + * drivers/wireless/ieee802154/mrf24j40/mrf24j40_radif.c + * + * Copyright (C) 2015-2016 Sebastien Lorquet. All rights reserved. + * Copyright (C) 2017 Verge Inc. All rights reserved. + * Author: Sebastien Lorquet + * Author: Anthony Merlino + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include +#include + +#include +#include +#include +#include + +#include +#include + +#include "mrf24j40.h" +#include "mrf24j40_reg.h" +#include "mrf24j40_getset.h" +#include "mrf24j40_regops.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +static const uint8_t g_allones[8] = +{ + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF +}; + +/**************************************************************************** + * Radio Interface Functions + ****************************************************************************/ + +int mrf24j40_bind(FAR struct ieee802154_radio_s *radio, + FAR struct ieee802154_radiocb_s *radiocb) +{ + FAR struct mrf24j40_radio_s *dev = (FAR struct mrf24j40_radio_s *)radio; + + DEBUGASSERT(dev != NULL); + dev->radiocb = radiocb; + return OK; +} + +/**************************************************************************** + * Function: mrf24j40_txnotify + * + * Description: + * Driver callback invoked when new TX data is available. This is a + * stimulus perform an out-of-cycle poll and, thereby, reduce the TX + * latency. + * + * Parameters: + * radio - Reference to the radio driver state structure + * + * Returned Value: + * None + * + * Assumptions: + * + ****************************************************************************/ + +int mrf24j40_txnotify(FAR struct ieee802154_radio_s *radio, bool gts) +{ + FAR struct mrf24j40_radio_s *dev = (FAR struct mrf24j40_radio_s *)radio; + + if (gts) + { + /* Is our single work structure available? It may not be if there are + * pending interrupt actions and we will have to ignore the Tx + * availability action. + */ + + if (work_available(&dev->gts_pollwork)) + { + /* Schedule to serialize the poll on the worker thread. */ + + work_queue(HPWORK, &dev->gts_pollwork, mrf24j40_dopoll_gts, dev, 0); + } + } + else + { + /* Is our single work structure available? It may not be if there are + * pending interrupt actions and we will have to ignore the Tx + * availability action. + */ + + if (work_available(&dev->csma_pollwork)) + { + /* Schedule to serialize the poll on the worker thread. */ + + work_queue(HPWORK, &dev->csma_pollwork, mrf24j40_dopoll_csma, dev, 0); + } + } + + return OK; +} + +/**************************************************************************** + * Function: mrf24j40_txdelayed + * + * Description: + * Transmit a packet without regard to supeframe structure after a certain + * number of symbols. This function is used to send Data Request responses. + * It can also be used to send data immediately if the delay is set to 0. + * + * Parameters: + * radio - Reference to the radio driver state structure + * + * Returned Value: + * None + * + * Assumptions: + * + ****************************************************************************/ + +int mrf24j40_txdelayed(FAR struct ieee802154_radio_s *radio, + FAR struct ieee802154_txdesc_s *txdesc, + uint32_t symboldelay) +{ + FAR struct mrf24j40_radio_s *dev = (FAR struct mrf24j40_radio_s *)radio; + uint8_t reg; + + /* Get exclusive access to the radio device */ + + if (sem_wait(&dev->exclsem) != 0) + { + return -EINTR; + } + + /* There should never be more than one of these transactions at once. */ + + DEBUGASSERT(!dev->txdelayed_busy); + + dev->txdelayed_desc = txdesc; + dev->txdelayed_busy = true; + + /* Disable the TX norm interrupt and clear it */ + + reg = mrf24j40_getreg(dev->spi, MRF24J40_INTCON); + reg |= MRF24J40_INTCON_TXNIE; + mrf24j40_setreg(dev->spi, MRF24J40_INTCON, reg); + + /* If after disabling the interrupt, the irqworker is not scheduled, there + * are no interrupts to worry about. However, if there is work scheduled, + * we need to process it before going any further. + * FIXME: I think this could be done cleaner. + */ + + if (!work_available(&dev->irqwork)) + { + sem_post(&dev->exclsem); + mrf24j40_irqworker((FAR void *)dev); + + /* Get exclusive access to the radio device */ + + if (sem_wait(&dev->exclsem) != 0) + { + return -EINTR; + } + } + + if (dev->csma_busy) + { + dev->reschedule_csma = true; + } + + mrf24j40_norm_setup(dev, txdesc->frame, false); + + if (symboldelay == 0) + { + mrf24j40_norm_trigger(dev); + } + else + { + mrf24j40_mactimer(dev, symboldelay); + } + + sem_post(&dev->exclsem); + + return OK; +} + +int mrf24j40_reset(FAR struct ieee802154_radio_s *radio) +{ + FAR struct mrf24j40_radio_s *dev = (FAR struct mrf24j40_radio_s *)radio; + struct ieee802154_cca_s cca; + int reg; + + /* Software reset */ + + mrf24j40_setreg(dev->spi, MRF24J40_SOFTRST , 0x07); /* 00000111 Reset */ + while(mrf24j40_getreg(dev->spi, MRF24J40_SOFTRST) & 0x07); + + /* Apply recommended settings */ + + mrf24j40_setreg(dev->spi, MRF24J40_PACON2 , 0x98); /* 10011000 Enable FIFO (default), TXONTS=6 (recommended), TXONT<8:7>=0 */ + mrf24j40_setreg(dev->spi, MRF24J40_TXSTBL , 0x95); /* 10010101 set the SIFS period. RFSTBL=9, MSIFS=5, aMinSIFSPeriod=14 (min 12) */ + mrf24j40_setreg(dev->spi, MRF24J40_TXPEND , 0x7C); /* 01111100 set the LIFS period, MLIFS=1Fh=31 aMinLIFSPeriod=40 (min 40) */ + mrf24j40_setreg(dev->spi, MRF24J40_TXTIME , 0x30); /* 00110000 set the turnaround time, TURNTIME=3 aTurnAroundTime=12 */ + mrf24j40_setreg(dev->spi, MRF24J40_RFCON1 , 0x02); /* 00000010 VCO optimization, recommended value */ + mrf24j40_setreg(dev->spi, MRF24J40_RFCON2 , 0x80); /* 10000000 Enable PLL */ + mrf24j40_setreg(dev->spi, MRF24J40_RFCON6 , 0x90); /* 10010000 TX filter enable, fast 20M recovery, No bat monitor*/ + mrf24j40_setreg(dev->spi, MRF24J40_RFCON7 , 0x80); /* 10000000 Sleep clock on internal 100 kHz */ + mrf24j40_setreg(dev->spi, MRF24J40_RFCON8 , 0x10); /* 00010000 VCO control bit, as recommended */ + mrf24j40_setreg(dev->spi, MRF24J40_SLPCON1, 0x01); /* 00000001 no CLKOUT, default divisor */ + mrf24j40_setreg(dev->spi, MRF24J40_BBREG6 , 0x40); /* 01000000 Append RSSI to rx packets */ + + /* Set this in reset since it can exist for all device modes. See pg 101 */ + + mrf24j40_setreg(dev->spi, MRF24J40_FRMOFFSET, 0x15); + + /* For now, we want to always just have the frame pending bit set when + * acknowledging a Data Request command. The standard says that the coordinator + * can do this if it needs time to figure out whether it has data or not + */ + + mrf24j40_setreg(dev->spi, MRF24J40_ACKTMOUT, 0x39 | MRF24J40_ACKTMOUT_DRPACK); + + /* Set WAKECNT (SLPACK 0x35<6:0>) value = 0xC8 to set the main oscillator + * (20 MHz) start-up timer value. + */ + + mrf24j40_setreg(dev->spi, MRF24J40_SLPACK, 0xC8); + + /* Set WAKETIME to recommended value for 100kHz SLPCLK Source */ + + mrf24j40_setreg(dev->spi, MRF24J40_WAKETIMEL, 0xD2); + mrf24j40_setreg(dev->spi, MRF24J40_WAKETIMEH, 0x00); + + /* Enable the SLPIF and WAKEIF flags */ + + reg = mrf24j40_getreg(dev->spi, MRF24J40_INTCON); + reg &= ~(MRF24J40_INTCON_SLPIE | MRF24J40_INTCON_WAKEIE); + mrf24j40_setreg(dev->spi, MRF24J40_INTCON, reg); + + dev->rxenabled = false; + + mrf24j40_setchannel(dev, 11); + mrf24j40_setpanid(dev, g_allones); + mrf24j40_setsaddr(dev, g_allones); + mrf24j40_seteaddr(dev, g_allones); + + dev->max_frame_waittime = MRF24J40_DEFAULT_MAX_FRAME_WAITTIME; + dev->bsn = 0; + + /* Default device params */ + + cca.use_ed = 1; + cca.use_cs = 0; + cca.edth = 0x60; /* CCA mode ED, no carrier sense, recommenced ED threshold -69 dBm */ + mrf24j40_setcca(dev, &cca); + + mrf24j40_setrxmode(dev, MRF24J40_RXMODE_NORMAL); + + mrf24j40_settxpower(dev, 0); /*16. Set transmitter power .*/ + + mrf24j40_pacontrol(dev, MRF24J40_PA_AUTO); + + return OK; +} + +int mrf24j40_getattr(FAR struct ieee802154_radio_s *radio, + enum ieee802154_attr_e attr, + FAR union ieee802154_attr_u *attrval) +{ + FAR struct mrf24j40_radio_s *dev = (FAR struct mrf24j40_radio_s *)radio; + int ret; + + switch (attr) + { + case IEEE802154_ATTR_MAC_EADDR: + { + memcpy(&attrval->mac.eaddr[0], &dev->addr.eaddr[0], 8); + ret = IEEE802154_STATUS_SUCCESS; + } + break; + + case IEEE802154_ATTR_MAC_MAX_FRAME_WAITTIME: + { + attrval->mac.max_frame_waittime = dev->max_frame_waittime; + ret = IEEE802154_STATUS_SUCCESS; + } + break; + + case IEEE802154_ATTR_PHY_SYMBOL_DURATION: + { + attrval->phy.symdur_picosec = MRF24J40_SYMBOL_DURATION_PS; + ret = IEEE802154_STATUS_SUCCESS; + } + break; + + case IEEE802154_ATTR_PHY_CHAN: + { + attrval->phy.chan = dev->chan; + ret = IEEE802154_STATUS_SUCCESS; + } + + default: + ret = IEEE802154_STATUS_UNSUPPORTED_ATTRIBUTE; + } + + return ret; +} + +int mrf24j40_setattr(FAR struct ieee802154_radio_s *radio, + enum ieee802154_attr_e attr, + FAR const union ieee802154_attr_u *attrval) +{ + FAR struct mrf24j40_radio_s *dev = (FAR struct mrf24j40_radio_s *)radio; + int ret; + + switch (attr) + { + case IEEE802154_ATTR_MAC_PANID: + { + mrf24j40_setpanid(dev, attrval->mac.panid); + ret = IEEE802154_STATUS_SUCCESS; + } + break; + + case IEEE802154_ATTR_MAC_SADDR: + { + mrf24j40_setsaddr(dev, attrval->mac.saddr); + ret = IEEE802154_STATUS_SUCCESS; + } + break; + + case IEEE802154_ATTR_MAC_EADDR: + { + mrf24j40_seteaddr(dev, attrval->mac.eaddr); + ret = IEEE802154_STATUS_SUCCESS; + } + break; + + case IEEE802154_ATTR_MAC_COORD_SADDR: + { + mrf24j40_setcoordsaddr(dev, attrval->mac.coordsaddr); + ret = IEEE802154_STATUS_SUCCESS; + } + break; + + case IEEE802154_ATTR_MAC_COORD_EADDR: + { + mrf24j40_setcoordeaddr(dev, attrval->mac.coordeaddr); + ret = IEEE802154_STATUS_SUCCESS; + } + break; + + case IEEE802154_ATTR_MAC_PROMISCUOUS_MODE: + { + if (attrval->mac.promisc_mode) + { + mrf24j40_setrxmode(dev, MRF24J40_RXMODE_PROMISC); + } + else + { + mrf24j40_setrxmode(dev, MRF24J40_RXMODE_NORMAL); + } + + ret = IEEE802154_STATUS_SUCCESS; + } + break; + + + case IEEE802154_ATTR_PHY_CHAN: + { + mrf24j40_setchannel(dev, attrval->phy.chan); + ret = IEEE802154_STATUS_SUCCESS; + } + break; + + default: + ret = IEEE802154_STATUS_UNSUPPORTED_ATTRIBUTE; + break; + } + return ret; +} + +int mrf24j40_beaconstart(FAR struct ieee802154_radio_s *radio, + FAR const struct ieee802154_superframespec_s *sfspec, + FAR struct ieee802154_beaconframe_s *beacon) +{ + FAR struct mrf24j40_radio_s *dev = (FAR struct mrf24j40_radio_s *)radio; + int reg; + + if (sfspec->pancoord) + { + /* Set the PANCOORD (RXMCR 0x00<3>) bit = 1to configure as PAN coordinator */ + + reg = mrf24j40_getreg(dev->spi, MRF24J40_RXMCR); + reg |= MRF24J40_RXMCR_PANCOORD; + mrf24j40_setreg(dev->spi, MRF24J40_RXMCR, reg); + + /* Set the SLOTTED (TXMCR 0x11<5>) bit = 1 to use Slotted CSMA-CA mode */ + + reg = mrf24j40_getreg(dev->spi, MRF24J40_TXMCR); + reg |= MRF24J40_TXMCR_SLOTTED; + mrf24j40_setreg(dev->spi, MRF24J40_TXMCR, reg); + + /* Load the beacon frame into the TXBFIFO (0x080-0x0FF). */ + + mrf24j40_setup_fifo(dev, beacon->bf_data, beacon->bf_len, MRF24J40_BEACON_FIFO); + + /* The radio layer is responsible for setting the BSN. */ + + dev->bsn = 0; + mrf24j40_setreg(dev->spi, MRF24J40_BEACON_FIFO + 4, dev->bsn++); + + /* Set the TXBMSK (TXBCON1 0x25<7>) bit = 1 to mask the beacon interrupt + * mask + */ + + reg = mrf24j40_getreg(dev->spi, MRF24J40_TXBCON1); + reg |= MRF24J40_TXBCON1_TXBMSK; + mrf24j40_setreg(dev->spi, MRF24J40_TXBCON1, reg); + + /* Set INTL (WAKECON 0x22<5:0>) value to 0x03. */ + + reg = mrf24j40_getreg(dev->spi, MRF24J40_WAKECON); + reg &= ~MRF24J40_WAKECON_INTL; + reg |= 0x03 & MRF24J40_WAKECON_INTL; + mrf24j40_setreg(dev->spi, MRF24J40_WAKECON, reg); + + /* Program the CAP end slot (ESLOTG1 0x13<3:0>) value. */ + + reg = mrf24j40_getreg(dev->spi, MRF24J40_ESLOTG1); + reg &= ~MRF24J40_ESLOTG1_CAP; + reg |= sfspec->final_capslot & MRF24J40_ESLOTG1_CAP; + mrf24j40_setreg(dev->spi, MRF24J40_ESLOTG1, reg); + + /* TODO: Add GTS related code. See pg 100 of datasheet */ + + mrf24j40_setorder(dev, sfspec->beaconorder, sfspec->sforder); + } + else + { + return -ENOTTY; + } + + return OK; +} + +int mrf24j40_beaconupdate(FAR struct ieee802154_radio_s *radio, + FAR struct ieee802154_beaconframe_s *beacon) +{ + FAR struct mrf24j40_radio_s *dev = (FAR struct mrf24j40_radio_s *)radio; + + mrf24j40_setup_fifo(dev, beacon->bf_data, beacon->bf_len, MRF24J40_BEACON_FIFO); + mrf24j40_beacon_trigger(dev); + + return OK; +} + +int mrf24j40_beaconstop(FAR struct ieee802154_radio_s *radio) +{ + return -ENOTTY; +} + +int mrf24j40_sfupdate(FAR struct ieee802154_radio_s *radio, + FAR const struct ieee802154_superframespec_s *sfspec) +{ + FAR struct mrf24j40_radio_s *dev = (FAR struct mrf24j40_radio_s *)radio; + int reg; + + /* If we are operating on a beacon-enabled network, use slotted CSMA */ + + reg = mrf24j40_getreg(dev->spi, MRF24J40_TXMCR); + if (sfspec->beaconorder < 15) + { + reg |= MRF24J40_TXMCR_SLOTTED; + } + else + { + reg &= ~MRF24J40_TXMCR_SLOTTED; + } + mrf24j40_setreg(dev->spi, MRF24J40_TXMCR, reg); + + mrf24j40_setorder(dev, sfspec->beaconorder, sfspec->sforder); + + /* Program the CAP end slot (ESLOTG1 0x13<3:0>) value. */ + + reg = mrf24j40_getreg(dev->spi, MRF24J40_ESLOTG1); + reg &= ~MRF24J40_ESLOTG1_CAP; + reg |= sfspec->final_capslot & MRF24J40_ESLOTG1_CAP; + mrf24j40_setreg(dev->spi, MRF24J40_ESLOTG1, reg); + + return OK; +} diff --git a/drivers/wireless/ieee802154/mrf24j40/mrf24j40_radif.h b/drivers/wireless/ieee802154/mrf24j40/mrf24j40_radif.h new file mode 100644 index 0000000000..3eb678c603 --- /dev/null +++ b/drivers/wireless/ieee802154/mrf24j40/mrf24j40_radif.h @@ -0,0 +1,71 @@ +/**************************************************************************** + * drivers/wireless/ieee802154/mrf24j40/mrf24j40_radif.h + * + * Copyright (C) 2017 Verge Inc. All rights reserved. + * Author: Anthony Merlino + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +#ifndef __DRIVERS_WIRELESS_IEEE802154_MRF24J40_RADIF_H +#define __DRIVERS_WIRELESS_IEEE802154_MRF24J40_RADIF_H + +int mrf24j40_bind(FAR struct ieee802154_radio_s *radio, + FAR struct ieee802154_radiocb_s *radiocb); + +int mrf24j40_reset(FAR struct ieee802154_radio_s *radio); + +int mrf24j40_getattr(FAR struct ieee802154_radio_s *radio, + enum ieee802154_attr_e attr, + FAR union ieee802154_attr_u *attrval); + +int mrf24j40_setattr(FAR struct ieee802154_radio_s *radio, + enum ieee802154_attr_e attr, + FAR const union ieee802154_attr_u *attrval); + +int mrf24j40_txnotify(FAR struct ieee802154_radio_s *radio, bool gts); + +int mrf24j40_txdelayed(FAR struct ieee802154_radio_s *radio, + FAR struct ieee802154_txdesc_s *txdesc, + uint32_t symboldelay); + + +int mrf24j40_beaconstart(FAR struct ieee802154_radio_s *radio, + FAR const struct ieee802154_superframespec_s *sfspec, + FAR struct ieee802154_beaconframe_s *beacon); + +int mrf24j40_beaconupdate(FAR struct ieee802154_radio_s *radio, + FAR struct ieee802154_beaconframe_s *beacon); + +int mrf24j40_beaconstop(FAR struct ieee802154_radio_s *radio); + +int mrf24j40_sfupdate(FAR struct ieee802154_radio_s *radio, + FAR const struct ieee802154_superframespec_s *sfspec); + +#endif /* __DRIVERS_WIRELESS_IEEE802154_MRF24J40_RADIF_H */ \ No newline at end of file diff --git a/drivers/wireless/ieee802154/mrf24j40/mrf24j40_reg.h b/drivers/wireless/ieee802154/mrf24j40/mrf24j40_reg.h new file mode 100644 index 0000000000..4d45545b27 --- /dev/null +++ b/drivers/wireless/ieee802154/mrf24j40/mrf24j40_reg.h @@ -0,0 +1,286 @@ +/**************************************************************************** + * drivers/wireless/ieee802154/mrf24j40/mrf24j40_reg.h + * + * Copyright (C) 2015-2016 Sebastien Lorquet. All rights reserved. + * Copyright (C) 2017 Verge Inc. All rights reserved. + * Author: Sebastien Lorquet + * Author: Anthony Merlino + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/* MRF24J40 Registers *******************************************************/ + +#define MRF24J40_RXMCR 0x00 +#define MRF24J40_PANIDL 0x01 +#define MRF24J40_PANIDH 0x02 +#define MRF24J40_SADRL 0x03 +#define MRF24J40_SADRH 0x04 +#define MRF24J40_EADR0 0x05 +#define MRF24J40_EADR1 0x06 +#define MRF24J40_EADR2 0x07 +#define MRF24J40_EADR3 0x08 +#define MRF24J40_EADR4 0x09 +#define MRF24J40_EADR5 0x0A +#define MRF24J40_EADR6 0x0B +#define MRF24J40_EADR7 0x0C +#define MRF24J40_RXFLUSH 0x0D +#define MRF24J40_ORDER 0x10 +#define MRF24J40_TXMCR 0x11 +#define MRF24J40_ACKTMOUT 0x12 +#define MRF24J40_ESLOTG1 0x13 +#define MRF24J40_SYMTICKL 0x14 +#define MRF24J40_SYMTICKH 0x15 +#define MRF24J40_PACON0 0x16 +#define MRF24J40_PACON1 0x17 +#define MRF24J40_PACON2 0x18 +#define MRF24J40_TXBCON0 0x1A +#define MRF24J40_TXNCON 0x1B +#define MRF24J40_TXG1CON 0x1C +#define MRF24J40_TXG2CON 0x1D +#define MRF24J40_ESLOTG23 0x1E +#define MRF24J40_ESLOTG45 0x1F +#define MRF24J40_ESLOTG67 0x20 +#define MRF24J40_TXPEND 0x21 +#define MRF24J40_WAKECON 0x22 +#define MRF24J40_FRMOFFSET 0x23 +#define MRF24J40_TXSTAT 0x24 +#define MRF24J40_TXBCON1 0x25 +#define MRF24J40_GATECLK 0x26 +#define MRF24J40_TXTIME 0x27 +#define MRF24J40_HSYMTMRL 0x28 +#define MRF24J40_HSYMTMRH 0x29 +#define MRF24J40_SOFTRST 0x2A +#define MRF24J40_SECCON0 0x2C +#define MRF24J40_SECCON1 0x2C +#define MRF24J40_TXSTBL 0x2E +#define MRF24J40_RXSR 0x30 +#define MRF24J40_INTSTAT 0x31 +#define MRF24J40_INTCON 0x32 +#define MRF24J40_GPIO 0x33 +#define MRF24J40_TRISGPIO 0x34 +#define MRF24J40_SLPACK 0x35 +#define MRF24J40_RFCTL 0x36 +#define MRF24J40_SECCR2 0x37 +#define MRF24J40_BBREG0 0x38 +#define MRF24J40_BBREG1 0x39 +#define MRF24J40_BBREG2 0x3A +#define MRF24J40_BBREG3 0x3B +#define MRF24J40_BBREG4 0x3C +#define MRF24J40_BBREG6 0x3E +#define MRF24J40_CCAEDTH 0x3F + +#define MRF24J40_FIFO_BASE 0x80000000 +#define MRF24J40_LONGREG_BASE 0x80000200 +#define MRF24J40_RXBUF_BASE 0x80000300 + +#define MRF24J40_TXNORM_FIFO (MRF24J40_FIFO_BASE + 0x000) +#define MRF24J40_BEACON_FIFO (MRF24J40_FIFO_BASE + 0x080) +#define MRF24J40_GTS1_FIFO (MRF24J40_FIFO_BASE + 0x100) +#define MRF24J40_GTS2_FIFO (MRF24J40_FIFO_BASE + 0x180) + +#define MRF24J40_RFCON0 (MRF24J40_LONGREG_BASE + 0x00) +#define MRF24J40_RFCON1 (MRF24J40_LONGREG_BASE + 0x01) +#define MRF24J40_RFCON2 (MRF24J40_LONGREG_BASE + 0x02) +#define MRF24J40_RFCON3 (MRF24J40_LONGREG_BASE + 0x03) +#define MRF24J40_RFCON5 (MRF24J40_LONGREG_BASE + 0x05) +#define MRF24J40_RFCON6 (MRF24J40_LONGREG_BASE + 0x06) +#define MRF24J40_RFCON7 (MRF24J40_LONGREG_BASE + 0x07) +#define MRF24J40_RFCON8 (MRF24J40_LONGREG_BASE + 0x08) +#define MRF24J40_SLPCAL0 (MRF24J40_LONGREG_BASE + 0x09) +#define MRF24J40_SLPCAL1 (MRF24J40_LONGREG_BASE + 0x0A) +#define MRF24J40_SLPCAL2 (MRF24J40_LONGREG_BASE + 0x0B) +#define MRF24J40_RFSTATE (MRF24J40_LONGREG_BASE + 0x0F) +#define MRF24J40_RSSI (MRF24J40_LONGREG_BASE + 0x10) +#define MRF24J40_SLPCON0 (MRF24J40_LONGREG_BASE + 0x11) +#define MRF24J40_SLPCON1 (MRF24J40_LONGREG_BASE + 0x20) +#define MRF24J40_WAKETIMEL (MRF24J40_LONGREG_BASE + 0x22) +#define MRF24J40_WAKETIMEH (MRF24J40_LONGREG_BASE + 0x23) +#define MRF24J40_REMCNTL (MRF24J40_LONGREG_BASE + 0x24) +#define MRF24J40_REMCNTH (MRF24J40_LONGREG_BASE + 0x25) +#define MRF24J40_MAINCNT0 (MRF24J40_LONGREG_BASE + 0x26) +#define MRF24J40_MAINCNT1 (MRF24J40_LONGREG_BASE + 0x27) +#define MRF24J40_MAINCNT2 (MRF24J40_LONGREG_BASE + 0x28) +#define MRF24J40_MAINCNT3 (MRF24J40_LONGREG_BASE + 0x29) +#define MRF24J40_TESTMODE (MRF24J40_LONGREG_BASE + 0x2F) +#define MRF24J40_ASSOEADR0 (MRF24J40_LONGREG_BASE + 0x30) +#define MRF24J40_ASSOEADR1 (MRF24J40_LONGREG_BASE + 0x31) +#define MRF24J40_ASSOEADR2 (MRF24J40_LONGREG_BASE + 0x32) +#define MRF24J40_ASSOEADR3 (MRF24J40_LONGREG_BASE + 0x33) +#define MRF24J40_ASSOEADR4 (MRF24J40_LONGREG_BASE + 0x34) +#define MRF24J40_ASSOEADR5 (MRF24J40_LONGREG_BASE + 0x35) +#define MRF24J40_ASSOEADR6 (MRF24J40_LONGREG_BASE + 0x36) +#define MRF24J40_ASSOEADR7 (MRF24J40_LONGREG_BASE + 0x37) +#define MRF24J40_ASSOSADR0 (MRF24J40_LONGREG_BASE + 0x38) +#define MRF24J40_ASSOSADR1 (MRF24J40_LONGREG_BASE + 0x39) +#define MRF24J40_UPNONCE0 (MRF24J40_LONGREG_BASE + 0x40) +#define MRF24J40_UPNONCE1 (MRF24J40_LONGREG_BASE + 0x41) +#define MRF24J40_UPNONCE2 (MRF24J40_LONGREG_BASE + 0x42) +#define MRF24J40_UPNONCE3 (MRF24J40_LONGREG_BASE + 0x43) +#define MRF24J40_UPNONCE4 (MRF24J40_LONGREG_BASE + 0x44) +#define MRF24J40_UPNONCE5 (MRF24J40_LONGREG_BASE + 0x45) +#define MRF24J40_UPNONCE6 (MRF24J40_LONGREG_BASE + 0x46) +#define MRF24J40_UPNONCE7 (MRF24J40_LONGREG_BASE + 0x47) +#define MRF24J40_UPNONCE8 (MRF24J40_LONGREG_BASE + 0x48) +#define MRF24J40_UPNONCE9 (MRF24J40_LONGREG_BASE + 0x49) +#define MRF24J40_UPNONCE10 (MRF24J40_LONGREG_BASE + 0x4A) +#define MRF24J40_UPNONCE11 (MRF24J40_LONGREG_BASE + 0x4B) +#define MRF24J40_UPNONCE12 (MRF24J40_LONGREG_BASE + 0x4C) + +/* INTSTAT bits */ + +#define MRF24J40_INTSTAT_TXNIF (1 << 0) +#define MRF24J40_INTSTAT_TXG1IF (1 << 1) +#define MRF24J40_INTSTAT_TXG2IF (1 << 2) +#define MRF24J40_INTSTAT_RXIF (1 << 3) +#define MRF24J40_INTSTAT_SECIF (1 << 4) +#define MRF24J40_INTSTAT_HSYMTMRIF (1 << 5) +#define MRF24J40_INTSTAT_WAKEIF (1 << 6) +#define MRF24J40_INTSTAT_SLPIF (1 << 7) + +/* RXMCR bits */ + +#define MRF24J40_RXMCR_PROMI (1 << 0) /* Enable promisc mode (rx all valid packets) */ +#define MRF24J40_RXMCR_ERRPKT 0x02 /* Do not check CRC */ +#define MRF24J40_RXMCR_COORD 0x04 /* Enable coordinator mode ??? DIFFERENCE ??? - not used in datasheet! */ +#define MRF24J40_RXMCR_PANCOORD 0x08 /* Enable PAN coordinator mode ??? DIFFERENCE ??? */ +#define MRF24J40_RXMCR_NOACKRSP 0x20 /* Enable auto ACK when a packet is rxed */ + +/* TXMCR bits */ + +#define MRF24J40_TXMCR_CSMABF0 (1 << 0) +#define MRF24J40_TXMCR_CSMABF1 0x02 +#define MRF24J40_TXMCR_CSMABF2 0x04 +#define MRF24J40_TXMCR_MACMINBE0 0x08 +#define MRF24J40_TXMCR_MACMINBE1 0x10 +#define MRF24J40_TXMCR_SLOTTED 0x20 +#define MRF24J40_TXMCR_BATLIFEXT 0x40 +#define MRF24J40_TXMCR_NOCSMA 0x80 + +/* ACKTMOUT bits */ + +#define MRF24J40_ACKTMOUT_MAWD 0xEF +#define MRF24J40_ACKTMOUT_DRPACK 0x80 + +/* INTCON bits */ + +#define MRF24J40_INTCON_SLPIE 0x80 +#define MRF24J40_INTCON_WAKEIE 0x40 +#define MRF24J40_INTCON_HSYMTMRIE 0x20 +#define MRF24J40_INTCON_SECIE 0x10 +#define MRF24J40_INTCON_RXIE 0x08 +#define MRF24J40_INTCON_TXG2IE 0x04 +#define MRF24J40_INTCON_TXG1IE 0x02 +#define MRF24J40_INTCON_TXNIE (1 << 0) + +/* BBREG1 bits */ + +#define MRF24J40_BBREG1_RXDECINV 0x04 /* Enable/Disable packet reception */ + +/* BBREG2 bits */ + +#define MRF24J40_BBREG2_CCAMODE_ED 0x80 +#define MRF24J40_BBREG2_CCAMODE_CS 0x40 + +/* TXNCON bits */ + +#define MRF24J40_TXNCON_TXNTRIG (1 << 0) /* Trigger packet tx, automatically cleared */ +#define MRF24J40_TXNCON_TXNSECEN 0x02 /* Enable security */ +#define MRF24J40_TXNCON_TXNACKREQ 0x04 /* An ACK is requested for this pkt */ +#define MRF24J40_TXNCON_INDIRECT 0x08 /* Activate indirect tx bit (for coordinators) */ +#define MRF24J40_TXNCON_FPSTAT 0x10 /* Status of the frame pending big in txed acks */ + +/* TXSTAT bits */ + +#define MRF24J40_TXSTAT_TXNSTAT (1 << 0) +#define MRF24J40_TXSTAT_TXG1STAT (1 << 1) +#define MRF24J40_TXSTAT_TXG2STAT (1 << 2) +#define MRF24J40_TXSTAT_CCAFAIL (1 << 5) +#define MRF24J40_TXSTAT_X_SHIFT 6 +#define MRF24J40_TXSTAT_X_MASK (3 << MRF24J40_TXSTAT_X_SHIFT) + +/* TXBCON0 bits */ + +#define MRF24J40_TXBCON0_TXBTRIG 0x01 +#define MRF24J40_TXBCON0_TXBSECEN 0x02 + +/* TXBCON1 bits */ + +#define MRF24J40_TXBCON1_RSSINUM 0x30 +#define MRF24J40_TXBCON1_NWU_BCN 0x40 +#define MRF24J40_TXBCON1_TXBMSK 0x80 + +/* WAKECON bits */ + +#define MRF24J40_WAKECON_INTL 0x3F +#define MRF24J40_WAKECON_REGWAKE 0x40 +#define MRF24J40_WAKECON_IMMWAKE 0x80 + +/* WAKECON bits */ + +#define MRF24J40_WAKECON_INTL 0x3F +#define MRF24J40_WAKECON_REGWAKE 0x40 +#define MRF24J40_WAKECON_IMMWAKE 0x80 + +/* ESLOTG1 bits */ + +#define MRF24J40_ESLOTG1_CAP 0x0F +#define MRF24J40_ESLOTG1_GTS1 0xF0 + +/* SLPCAL2 bits */ + +#define MRF24J40_SLPCAL2_SLPCAL 0x0F +#define MRF24J40_SLPCAL2_SLPCALEN 0x10 +#define MRF24J40_SLPCAL2_SLPCALRDY 0x80 + +/* RFCON7 bits */ + +#define MRF24J40_RFCON7_SEL_32KHZ 0x40 +#define MRF24J40_RFCON7_SEL_100KHZ 0x80 + +/* SLPACK bits */ + +#define MRF24J40_SLPACK_WAKECNT0_6 0x7F +#define MRF24J40_SLPACK_SLPACK 0x80 + +/* RXFLUSH bits */ + +#define MRF24J40_RXFLUSH_RXFLUSH 0x01 +#define MRF24J40_RXFLUSH_BCNONLY 0x02 +#define MRF24J40_RXFLUSH_DATAONLY 0x04 +#define MRF24J40_RXFLUSH_CMDONLY 0x08 +#define MRF24J40_RXFLUSH_WAKEPAD 0x20 +#define MRF24J40_RXFLUSH_WAKEPOL 0x40 + +#define MRF24J40_RXFLUSH_SHIFT_RXFLUSH 0 +#define MRF24J40_RXFLUSH_SHIFT_BCNONLY 1 +#define MRF24J40_RXFLUSH_SHIFT_DATAONLY 2 +#define MRF24J40_RXFLUSH_SHIFT_CMDONLY 3 +#define MRF24J40_RXFLUSH_SHIFT_WAKEPAD 5 +#define MRF24J40_RXFLUSH_SHIFT_WAKEPOL 6 diff --git a/drivers/wireless/ieee802154/mrf24j40/mrf24j40_regops.c b/drivers/wireless/ieee802154/mrf24j40/mrf24j40_regops.c new file mode 100644 index 0000000000..16fb2b0fcf --- /dev/null +++ b/drivers/wireless/ieee802154/mrf24j40/mrf24j40_regops.c @@ -0,0 +1,189 @@ +/**************************************************************************** + * drivers/wireless/ieee802154/mrf24j40/mrf24j40_regops.c + + * Copyright (C) 2015-2016 Sebastien Lorquet. All rights reserved. + * Copyright (C) 2017 Verge Inc. All rights reserved. + * Author: Sebastien Lorquet + * Author: Anthony Merlino + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include +#include + +#include "mrf24j40.h" +#include "mrf24j40_regops.h" + +/**************************************************************************** + * Internal Driver Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: mrf24j40_setreg + * + * Description: + * Define the value of an MRF24J40 device register + * + ****************************************************************************/ + +void mrf24j40_setreg(FAR struct spi_dev_s *spi, uint32_t addr, uint8_t val) +{ + uint8_t buf[3]; + int len; + + if (!(addr&0x80000000)) + { + addr &= 0x3F; /* 6-bit address */ + addr <<= 1; + addr |= 0x01; /* writing */ + buf[0] = addr; + len = 1; + } + else + { + addr &= 0x3FF; /* 10-bit address */ + addr <<= 5; + addr |= 0x8010; /* writing long */ + buf[0] = (addr >> 8); + buf[1] = (addr & 0xFF); + len = 2; + } + + buf[len++] = val; + + mrf24j40_spi_lock(spi); + SPI_SELECT(spi, SPIDEV_IEEE802154(0), true); + SPI_SNDBLOCK(spi, buf, len); + SPI_SELECT(spi, SPIDEV_IEEE802154(0), false); + mrf24j40_spi_unlock(spi); +} + +/**************************************************************************** + * Name: mrf24j40_getreg + * + * Description: + * Return the value of an MRF24J40 device register* + * + ****************************************************************************/ + +uint8_t mrf24j40_getreg(FAR struct spi_dev_s *spi, uint32_t addr) +{ + uint8_t buf[3]; + uint8_t rx[3]; + int len; + + if (!(addr&0x80000000)) + { + /* 6-bit address */ + + addr &= 0x3F; + addr <<= 1; + buf[0] = addr; + len = 1; + } + else + { + /* 10-bit address */ + + addr &= 0x3FF; + addr <<= 5; + addr |= 0x8000; + buf[0] = (addr >> 8); + buf[1] = (addr & 0xFF); + len = 2; + } + + buf[len++] = 0xFF; /* dummy */ + + mrf24j40_spi_lock (spi); + SPI_SELECT (spi, SPIDEV_IEEE802154(0), true); + SPI_EXCHANGE (spi, buf, rx, len); + SPI_SELECT (spi, SPIDEV_IEEE802154(0), false); + mrf24j40_spi_unlock(spi); + + /* wlinfo("r[%04X]=%02X\n", addr, rx[len - 1]); */ + return rx[len - 1]; +} + +/**************************************************************************** + * Name: mrf24j40_regdump + * + * Description: + * Display the value of all registers. + * + ****************************************************************************/ + +int mrf24j40_regdump(FAR struct mrf24j40_radio_s *dev) +{ + uint32_t i; + char buf[4+16*3+2+1]; + int len = 0; + + wlinfo("Short regs:\n"); + + for (i = 0; i < 0x40; i++) + { + if ((i & 15) == 0) + { + len=sprintf(buf, "%02x: ",i&0xFF); + } + + len += sprintf(buf+len, "%02x ", mrf24j40_getreg(dev->spi, i)); + if ((i & 15) == 15) + { + sprintf(buf+len, "\n"); + wlinfo("%s", buf); + } + } + + wlinfo("Long regs:\n"); + + for (i = 0x80000200; i < 0x80000250; i++) + { + if ((i & 15) == 0) + { + len=sprintf(buf, "%02x: ",i&0xFF); + } + + len += sprintf(buf+len, "%02x ", mrf24j40_getreg(dev->spi, i)); + if ((i & 15) == 15) + { + sprintf(buf+len, "\n"); + wlinfo("%s", buf); + } + } + + return 0; +} diff --git a/drivers/wireless/ieee802154/mrf24j40/mrf24j40_regops.h b/drivers/wireless/ieee802154/mrf24j40/mrf24j40_regops.h new file mode 100644 index 0000000000..b70cf41762 --- /dev/null +++ b/drivers/wireless/ieee802154/mrf24j40/mrf24j40_regops.h @@ -0,0 +1,47 @@ +/**************************************************************************** + * drivers/wireless/ieee802154/mrf24j40/mrf24j40_regops.h + * + * Copyright (C) 2015-2016 Sebastien Lorquet. All rights reserved. + * Copyright (C) 2017 Verge Inc. All rights reserved. + * Author: Sebastien Lorquet + * Author: Anthony Merlino + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +#ifndef __DRIVERS_WIRELESS_IEEE802154_MRF24J40_REGOPS_H +#define __DRIVERS_WIRELESS_IEEE802154_MRF24J40_REGOPS_H + +void mrf24j40_setreg(FAR struct spi_dev_s *spi, uint32_t addr, uint8_t val); + +uint8_t mrf24j40_getreg(FAR struct spi_dev_s *spi, uint32_t addr); + +int mrf24j40_regdump(FAR struct mrf24j40_radio_s *dev); + +#endif /* __DRIVERS_WIRELESS_IEEE802154_MRF24J40_REGOPS_H */ \ No newline at end of file From bbf37a0db80f0f465062017477c229bf27a36223 Mon Sep 17 00:00:00 2001 From: Anthony Merlino Date: Mon, 10 Jul 2017 12:38:39 -0400 Subject: [PATCH 26/54] drivers/wireless/ieee802154/mrf24j40: Fixes issue with non-beacon enabled mode --- .../wireless/ieee802154/mrf24j40/mrf24j40.c | 22 ++++++++++++++----- .../ieee802154/mrf24j40/mrf24j40_radif.c | 10 --------- 2 files changed, 17 insertions(+), 15 deletions(-) diff --git a/drivers/wireless/ieee802154/mrf24j40/mrf24j40.c b/drivers/wireless/ieee802154/mrf24j40/mrf24j40.c index 9dd7e7ddc1..94e5b7e2df 100644 --- a/drivers/wireless/ieee802154/mrf24j40/mrf24j40.c +++ b/drivers/wireless/ieee802154/mrf24j40/mrf24j40.c @@ -242,6 +242,8 @@ void mrf24j40_setorder(FAR struct mrf24j40_radio_s *dev, uint8_t bo, uint8_t so) uint32_t maincnt = 0; uint32_t slpcal = 0; + wlinfo("bo: %d, so: %d\n", bo, so); + /* Calibrate the Sleep Clock (SLPCLK) frequency. Refer to Section 3.15.1.2 * “Sleep Clock Calibration”. */ @@ -277,12 +279,22 @@ void mrf24j40_setorder(FAR struct mrf24j40_radio_s *dev, uint8_t bo, uint8_t so) slpcal |= (mrf24j40_getreg(dev->spi, MRF24J40_SLPCAL1) << 8); slpcal |= ((mrf24j40_getreg(dev->spi, MRF24J40_SLPCAL2) << 16) & 0x0F); - /* Program the Beacon Interval into the Main Counter, MAINCNT (0x229<1:0>, - * 0x228, 0x227, 0x226), and Remain Counter, REMCNT (0x225, 0x224), - * according to BO and SO values. Refer to Section 3.15.1.3 “Sleep Mode - * Counters” - */ + /* Set WAKECNT (SLPACK 0x35<6:0>) value = 0xC8 to set the main oscillator + * (20 MHz) start-up timer value. + */ + mrf24j40_setreg(dev->spi, MRF24J40_SLPACK, 0xC8); + + /* Set WAKETIME to recommended value for 100kHz SLPCLK Source */ + + mrf24j40_setreg(dev->spi, MRF24J40_WAKETIMEL, 0xD2); + mrf24j40_setreg(dev->spi, MRF24J40_WAKETIMEH, 0x00); + + /* Program the Beacon Interval into the Main Counter, MAINCNT (0x229<1:0>, + * 0x228, 0x227, 0x226), and Remain Counter, REMCNT (0x225, 0x224), + * according to BO and SO values. Refer to Section 3.15.1.3 “Sleep Mode + * Counters” + */ mrf24j40_setreg(dev->spi, MRF24J40_REMCNTL, (MRF24J40_REMCNT & 0xFF)); mrf24j40_setreg(dev->spi, MRF24J40_REMCNTH, ((MRF24J40_REMCNT >> 8) & 0xFF)); diff --git a/drivers/wireless/ieee802154/mrf24j40/mrf24j40_radif.c b/drivers/wireless/ieee802154/mrf24j40/mrf24j40_radif.c index 1f23d2188a..ae6df003f5 100644 --- a/drivers/wireless/ieee802154/mrf24j40/mrf24j40_radif.c +++ b/drivers/wireless/ieee802154/mrf24j40/mrf24j40_radif.c @@ -258,16 +258,6 @@ int mrf24j40_reset(FAR struct ieee802154_radio_s *radio) mrf24j40_setreg(dev->spi, MRF24J40_ACKTMOUT, 0x39 | MRF24J40_ACKTMOUT_DRPACK); - /* Set WAKECNT (SLPACK 0x35<6:0>) value = 0xC8 to set the main oscillator - * (20 MHz) start-up timer value. - */ - - mrf24j40_setreg(dev->spi, MRF24J40_SLPACK, 0xC8); - - /* Set WAKETIME to recommended value for 100kHz SLPCLK Source */ - - mrf24j40_setreg(dev->spi, MRF24J40_WAKETIMEL, 0xD2); - mrf24j40_setreg(dev->spi, MRF24J40_WAKETIMEH, 0x00); /* Enable the SLPIF and WAKEIF flags */ From fce023b1460eca8b8f0d23b178e8d977b01b25ea Mon Sep 17 00:00:00 2001 From: Anthony Merlino Date: Mon, 10 Jul 2017 13:04:27 -0400 Subject: [PATCH 27/54] wireless/ieee802154: Removes trailing whitespace --- wireless/ieee802154/mac802154_assoc.c | 2 +- wireless/ieee802154/mac802154_poll.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/wireless/ieee802154/mac802154_assoc.c b/wireless/ieee802154/mac802154_assoc.c index 42ee5c4618..c5448ca1fb 100644 --- a/wireless/ieee802154/mac802154_assoc.c +++ b/wireless/ieee802154/mac802154_assoc.c @@ -867,7 +867,7 @@ static void mac802154_assoctimeout(FAR void *arg) * this work, so that we make sure if the frame we were waiting for was just * received, we don't timeout */ - + if (!work_available(&priv->rx_work)) { work_queue(MAC802154_WORK, &priv->timer_work, mac802154_assoctimeout, priv, 0); diff --git a/wireless/ieee802154/mac802154_poll.c b/wireless/ieee802154/mac802154_poll.c index 3271a8f92a..a7d61f4a0d 100644 --- a/wireless/ieee802154/mac802154_poll.c +++ b/wireless/ieee802154/mac802154_poll.c @@ -270,7 +270,7 @@ void mac802154_polltimeout(FAR void *arg) * this work, so that we make sure if the frame we were waiting for was just * received, we don't timeout */ - + if (!work_available(&priv->rx_work)) { work_queue(MAC802154_WORK, &priv->timer_work, mac802154_polltimeout, priv, 0); From 6e680bb9670c9233319ec29287af1e8d0c584a76 Mon Sep 17 00:00:00 2001 From: Anthony Merlino Date: Mon, 10 Jul 2017 19:45:29 -0400 Subject: [PATCH 28/54] ieee802154: Fixes warning for unused variable --- wireless/ieee802154/mac802154_ioctl.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/wireless/ieee802154/mac802154_ioctl.c b/wireless/ieee802154/mac802154_ioctl.c index 20ab2557fd..75269b2648 100644 --- a/wireless/ieee802154/mac802154_ioctl.c +++ b/wireless/ieee802154/mac802154_ioctl.c @@ -74,14 +74,12 @@ int mac802154_ioctl(MACHANDLE mac, int cmd, unsigned long arg) { - FAR struct ieee802154_privmac_s *priv = - (FAR struct ieee802154_privmac_s *)mac; int ret = -EINVAL; FAR union ieee802154_macarg_u *macarg = (FAR union ieee802154_macarg_u *)((uintptr_t)arg); - DEBUGASSERT(priv != NULL); + DEBUGASSERT(mac != NULL); /* Check for IOCTLs aimed at the IEEE802.15.4 MAC layer */ From 7ff2f90247de2706549c3ddc33dd57d9dc3727eb Mon Sep 17 00:00:00 2001 From: Anthony Merlino Date: Mon, 10 Jul 2017 19:47:02 -0400 Subject: [PATCH 29/54] configs/clicker2-stm32/mrf24j40-mac: Updates stack size to 2048 to avoid random stack overflows when logging is enabled --- configs/clicker2-stm32/mrf24j40-mac/defconfig | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/configs/clicker2-stm32/mrf24j40-mac/defconfig b/configs/clicker2-stm32/mrf24j40-mac/defconfig index 00e30e6183..109b2bc704 100644 --- a/configs/clicker2-stm32/mrf24j40-mac/defconfig +++ b/configs/clicker2-stm32/mrf24j40-mac/defconfig @@ -1,12 +1,11 @@ -# CONFIG_NSH_CMDOPT_DF_H is not set -CONFIG_ARCH_BOARD_CLICKER2_STM32=y +CONFIG_ARCH="arm" CONFIG_ARCH_BOARD="clicker2-stm32" +CONFIG_ARCH_BOARD_CLICKER2_STM32=y CONFIG_ARCH_BUTTONS=y -CONFIG_ARCH_CHIP_STM32=y CONFIG_ARCH_CHIP_STM32F407VG=y +CONFIG_ARCH_CHIP_STM32=y CONFIG_ARCH_IRQBUTTONS=y CONFIG_ARCH_STACKDUMP=y -CONFIG_ARCH="arm" CONFIG_BOARD_INITIALIZE=y CONFIG_BOARD_LOOPSPERMSEC=16717 CONFIG_BUILTIN=y @@ -17,8 +16,9 @@ CONFIG_EXAMPLES_NSH_CXXINITIALIZE=y CONFIG_EXAMPLES_NSH=y CONFIG_FS_PROCFS=y CONFIG_FS_WRITABLE=y -CONFIG_HAVE_CXX=y CONFIG_HAVE_CXXINITIALIZE=y +CONFIG_HAVE_CXX=y +CONFIG_IDLETHREAD_STACKSIZE=2048 CONFIG_IEEE802154_I8SAK=y CONFIG_IEEE802154_MACDEV=y CONFIG_IEEE802154_MRF24J40=y @@ -30,6 +30,7 @@ CONFIG_NFILE_DESCRIPTORS=8 CONFIG_NFILE_STREAMS=8 CONFIG_NSH_ARCHINIT=y CONFIG_NSH_BUILTIN_APPS=y +# CONFIG_NSH_CMDOPT_DF_H is not set CONFIG_NSH_DISABLE_GET=y CONFIG_NSH_DISABLE_IFUPDOWN=y CONFIG_NSH_DISABLE_PUT=y @@ -44,8 +45,8 @@ CONFIG_RAM_SIZE=131072 CONFIG_RAM_START=0x20000000 CONFIG_RAW_BINARY=y CONFIG_RR_INTERVAL=200 -CONFIG_SCHED_HPWORK=y CONFIG_SCHED_HPWORKPRIORITY=192 +CONFIG_SCHED_HPWORK=y CONFIG_SCHED_WAITPID=y CONFIG_SDCLONE_DISABLE=y CONFIG_START_YEAR=2013 From 35289e6d0e8b57cd354abecbcb98f49d922f3343 Mon Sep 17 00:00:00 2001 From: Anthony Merlino Date: Tue, 11 Jul 2017 12:58:01 -0400 Subject: [PATCH 30/54] ieee802154: Minor reformatting --- drivers/wireless/ieee802154/mrf24j40/mrf24j40_radif.c | 1 - wireless/ieee802154/mac802154_start.c | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/wireless/ieee802154/mrf24j40/mrf24j40_radif.c b/drivers/wireless/ieee802154/mrf24j40/mrf24j40_radif.c index ae6df003f5..eb5b9a2be9 100644 --- a/drivers/wireless/ieee802154/mrf24j40/mrf24j40_radif.c +++ b/drivers/wireless/ieee802154/mrf24j40/mrf24j40_radif.c @@ -258,7 +258,6 @@ int mrf24j40_reset(FAR struct ieee802154_radio_s *radio) mrf24j40_setreg(dev->spi, MRF24J40_ACKTMOUT, 0x39 | MRF24J40_ACKTMOUT_DRPACK); - /* Enable the SLPIF and WAKEIF flags */ reg = mrf24j40_getreg(dev->spi, MRF24J40_INTCON); diff --git a/wireless/ieee802154/mac802154_start.c b/wireless/ieee802154/mac802154_start.c index 2bab5afd15..e5684a39a3 100644 --- a/wireless/ieee802154/mac802154_start.c +++ b/wireless/ieee802154/mac802154_start.c @@ -201,4 +201,4 @@ int mac802154_req_start(MACHANDLE mac, FAR struct ieee802154_start_req_s *req) errout: mac802154_unlock(priv) return ret; -} \ No newline at end of file +} From 0eaf2925cf5b48628d8fbe9c21959e668175b4b1 Mon Sep 17 00:00:00 2001 From: Anthony Merlino Date: Tue, 11 Jul 2017 21:11:52 -0400 Subject: [PATCH 31/54] drivers/wireless/ieee802154/mrf24j40/: Fixes bug causing radio to cease transmitting --- .../wireless/ieee802154/mrf24j40/mrf24j40.c | 11 ----------- .../ieee802154/mrf24j40/mrf24j40_radif.c | 18 ++++++++++++++++++ 2 files changed, 18 insertions(+), 11 deletions(-) diff --git a/drivers/wireless/ieee802154/mrf24j40/mrf24j40.c b/drivers/wireless/ieee802154/mrf24j40/mrf24j40.c index 94e5b7e2df..3cf82f3208 100644 --- a/drivers/wireless/ieee802154/mrf24j40/mrf24j40.c +++ b/drivers/wireless/ieee802154/mrf24j40/mrf24j40.c @@ -279,17 +279,6 @@ void mrf24j40_setorder(FAR struct mrf24j40_radio_s *dev, uint8_t bo, uint8_t so) slpcal |= (mrf24j40_getreg(dev->spi, MRF24J40_SLPCAL1) << 8); slpcal |= ((mrf24j40_getreg(dev->spi, MRF24J40_SLPCAL2) << 16) & 0x0F); - /* Set WAKECNT (SLPACK 0x35<6:0>) value = 0xC8 to set the main oscillator - * (20 MHz) start-up timer value. - */ - - mrf24j40_setreg(dev->spi, MRF24J40_SLPACK, 0xC8); - - /* Set WAKETIME to recommended value for 100kHz SLPCLK Source */ - - mrf24j40_setreg(dev->spi, MRF24J40_WAKETIMEL, 0xD2); - mrf24j40_setreg(dev->spi, MRF24J40_WAKETIMEH, 0x00); - /* Program the Beacon Interval into the Main Counter, MAINCNT (0x229<1:0>, * 0x228, 0x227, 0x226), and Remain Counter, REMCNT (0x225, 0x224), * according to BO and SO values. Refer to Section 3.15.1.3 “Sleep Mode diff --git a/drivers/wireless/ieee802154/mrf24j40/mrf24j40_radif.c b/drivers/wireless/ieee802154/mrf24j40/mrf24j40_radif.c index eb5b9a2be9..9f2aca935f 100644 --- a/drivers/wireless/ieee802154/mrf24j40/mrf24j40_radif.c +++ b/drivers/wireless/ieee802154/mrf24j40/mrf24j40_radif.c @@ -258,6 +258,24 @@ int mrf24j40_reset(FAR struct ieee802154_radio_s *radio) mrf24j40_setreg(dev->spi, MRF24J40_ACKTMOUT, 0x39 | MRF24J40_ACKTMOUT_DRPACK); + /* Set WAKETIME to recommended value for 100kHz SLPCLK Source. + * + * NOTE!!!: The datasheet specifies that WAKETIME > WAKECNT. It appears that + * it is even sensitive to the order in which you set WAKECNT and WAKETIME. + * Meaning, if you set WAKECNT first and it goes higher than WAKETIME, and + * then raise WAKETIME above WAKECNT, the device will not function correctly. + * Therefore, be careful when changing these registers + */ + + mrf24j40_setreg(dev->spi, MRF24J40_WAKETIMEL, 0xD2); + mrf24j40_setreg(dev->spi, MRF24J40_WAKETIMEH, 0x00); + + /* Set WAKECNT (SLPACK 0x35<6:0>) value = 0x5F to set the main oscillator + * (20 MHz) start-up timer value. + */ + + mrf24j40_setreg(dev->spi, MRF24J40_SLPACK, 0x5F); + /* Enable the SLPIF and WAKEIF flags */ reg = mrf24j40_getreg(dev->spi, MRF24J40_INTCON); From 3148e62ca10ef33d6ab4fee49722a859389ae3f7 Mon Sep 17 00:00:00 2001 From: Anthony Merlino Date: Tue, 11 Jul 2017 21:12:50 -0400 Subject: [PATCH 32/54] drivers/wireless/ieee802154/mrf24j40: Aligns better with coding standard after splitting up driver --- .../wireless/ieee802154/mrf24j40/mrf24j40.c | 320 +++--------------- .../wireless/ieee802154/mrf24j40/mrf24j40.h | 76 +++-- .../ieee802154/mrf24j40/mrf24j40_getset.c | 82 +++++ .../ieee802154/mrf24j40/mrf24j40_getset.h | 2 + .../ieee802154/mrf24j40/mrf24j40_radif.c | 179 +++++++++- .../ieee802154/mrf24j40/mrf24j40_radif.h | 1 + 6 files changed, 358 insertions(+), 302 deletions(-) diff --git a/drivers/wireless/ieee802154/mrf24j40/mrf24j40.c b/drivers/wireless/ieee802154/mrf24j40/mrf24j40.c index 3cf82f3208..17f5c6186d 100644 --- a/drivers/wireless/ieee802154/mrf24j40/mrf24j40.c +++ b/drivers/wireless/ieee802154/mrf24j40/mrf24j40.c @@ -50,7 +50,6 @@ #include #include -#include #include #include #include @@ -64,61 +63,78 @@ #include "mrf24j40.h" #include "mrf24j40_reg.h" #include "mrf24j40_radif.h" +#include "mrf24j40_getset.h" #include "mrf24j40_regops.h" /**************************************************************************** * Pre-processor Definitions ****************************************************************************/ -/* Clock configuration macros */ - -#define MRF24J40_SLPCLKPER_100KHZ ((1000 * 1000 * 1000)/100000) /* 10ns */ -#define MRF24J40_SLPCLKPER_32KHZ ((1000 * 1000 * 1000)/32000) /* 31.25ns */ - -#define MRF24J40_BEACONINTERVAL_NSEC(beaconorder) \ - (IEEE802154_BASE_SUPERFRAME_DURATION * (1 << beaconorder) * (16 *1000)) - -/* For now I am just setting the REMCNT to the maximum while staying in multiples - * of 10000 (100khz period) */ - -#define MRF24J40_REMCNT 60000 -#define MRF24J40_REMCNT_NSEC (MRF24J40_REMCNT * 50) - -#define MRF24J40_MAINCNT(bo, clkper) \ - ((MRF24J40_BEACONINTERVAL_NSEC(bo) - MRF24J40_REMCNT_NSEC) / \ - clkper) - /**************************************************************************** - * Internal Functions + * Private Function Prototypes ****************************************************************************/ -void mrf24j40_mactimer(FAR struct mrf24j40_radio_s *dev, int numsymbols) +#if 0 +static int mrf24j40_energydetect(FAR struct mrf24j40_radio_s *dev, + FAR uint8_t *energy); +#endif + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: mrf24j40_energydetect + * + * Description: + * Measure the RSSI level for the current channel. + * + ****************************************************************************/ + +#if 0 +static int mrf24j40_energydetect(FAR struct mrf24j40_radio_s *dev, + FAR uint8_t *energy) { - uint16_t nhalfsym; uint8_t reg; - nhalfsym = (numsymbols << 1); + /* Manually enable the LNA*/ - /* Disable the interrupt, clear the timer count */ + mrf24j40_setpamode(dev, MRF24J40_PA_ED); - reg = mrf24j40_getreg(dev->spi, MRF24J40_INTCON); - reg |= MRF24J40_INTCON_HSYMTMRIE; - mrf24j40_setreg(dev->spi, MRF24J40_INTCON, reg); + /* Set RSSI average duration to 8 symbols */ - mrf24j40_setreg(dev->spi, MRF24J40_HSYMTMRL, 0x00); - mrf24j40_setreg(dev->spi, MRF24J40_HSYMTMRH, 0x00); + reg = mrf24j40_getreg(dev->spi, MRF24J40_TXBCON1); + reg |= 0x30; + mrf24j40_setreg(dev->spi, MRF24J40_TXBCON1, reg); - reg &= ~MRF24J40_INTCON_HSYMTMRIE; - mrf24j40_setreg(dev->spi, MRF24J40_INTCON, reg); + /* 1. Set RSSIMODE1 0x3E<7> – Initiate RSSI calculation. */ - /* Set the timer count and enable interrupts */ + mrf24j40_setreg(dev->spi, MRF24J40_BBREG6, 0x80); - reg = (nhalfsym & 0xFF); - mrf24j40_setreg(dev->spi, MRF24J40_HSYMTMRL, reg); + /* 2. Wait until RSSIRDY 0x3E<0> is set to ‘1’ – RSSI calculation is + * complete. + */ - reg = (nhalfsym >> 8) & 0xFF; - mrf24j40_setreg(dev->spi, MRF24J40_HSYMTMRH, reg); + while(!(mrf24j40_getreg(dev->spi, MRF24J40_BBREG6) & 0x01)); + + /* 3. Read RSSI 0x210<7:0> – The RSSI register contains the averaged RSSI + * received power level for 8 symbol periods. + */ + + *energy = mrf24j40_getreg(dev->spi, MRF24J40_RSSI); + mrf24j40_setreg(dev->spi, MRF24J40_BBREG6, 0x40); + + /* Back to automatic control */ + + mrf24j40_setpamode(dev, MRF24J40_PA_AUTO); + + return OK; } +#endif + +/**************************************************************************** + * Public Functions + ****************************************************************************/ /**************************************************************************** * Function: mrf24j40_dopoll_csma @@ -230,168 +246,6 @@ void mrf24j40_dopoll_gts(FAR void *arg) sem_post(&dev->exclsem); } -/**************************************************************************** - * Name: mrf24j40_setorder - * - * Description: - * Configures the timers and sets the ORDER register - ****************************************************************************/ - -void mrf24j40_setorder(FAR struct mrf24j40_radio_s *dev, uint8_t bo, uint8_t so) -{ - uint32_t maincnt = 0; - uint32_t slpcal = 0; - - wlinfo("bo: %d, so: %d\n", bo, so); - - /* Calibrate the Sleep Clock (SLPCLK) frequency. Refer to Section 3.15.1.2 - * “Sleep Clock Calibration”. - */ - - /* If the Sleep Clock Selection, SLPCLKSEL (0x207<7:6), is the internal - * oscillator (100 kHz), set SLPCLKDIV to a minimum value of 0x01. - */ - - mrf24j40_setreg(dev->spi, MRF24J40_SLPCON1, 0x01); - - /* Select the source of SLPCLK (internal 100kHz) */ - - mrf24j40_setreg(dev->spi, MRF24J40_RFCON7, MRF24J40_RFCON7_SEL_100KHZ); - - /* Begin calibration by setting the SLPCALEN bit (SLPCAL2 0x20B<4>) to - * ‘1’. Sixteen samples of the SLPCLK are counted and stored in the - * SLPCAL register. No need to mask, this is the only writable bit - */ - - mrf24j40_setreg(dev->spi, MRF24J40_SLPCAL2, MRF24J40_SLPCAL2_SLPCALEN); - - /* Calibration is complete when the SLPCALRDY bit (SLPCAL2 0x20B<7>) is - * set to ‘1’. - */ - - while (!(mrf24j40_getreg(dev->spi, MRF24J40_SLPCAL2) & - MRF24J40_SLPCAL2_SLPCALRDY)) - { - usleep(1); - } - - slpcal = mrf24j40_getreg(dev->spi, MRF24J40_SLPCAL0); - slpcal |= (mrf24j40_getreg(dev->spi, MRF24J40_SLPCAL1) << 8); - slpcal |= ((mrf24j40_getreg(dev->spi, MRF24J40_SLPCAL2) << 16) & 0x0F); - - /* Program the Beacon Interval into the Main Counter, MAINCNT (0x229<1:0>, - * 0x228, 0x227, 0x226), and Remain Counter, REMCNT (0x225, 0x224), - * according to BO and SO values. Refer to Section 3.15.1.3 “Sleep Mode - * Counters” - */ - - mrf24j40_setreg(dev->spi, MRF24J40_REMCNTL, (MRF24J40_REMCNT & 0xFF)); - mrf24j40_setreg(dev->spi, MRF24J40_REMCNTH, ((MRF24J40_REMCNT >> 8) & 0xFF)); - - maincnt = MRF24J40_MAINCNT(bo, (slpcal * 50 / 16)); - - mrf24j40_setreg(dev->spi, MRF24J40_MAINCNT0, (maincnt & 0xFF)); - mrf24j40_setreg(dev->spi, MRF24J40_MAINCNT1, ((maincnt >> 8) & 0xFF)); - mrf24j40_setreg(dev->spi, MRF24J40_MAINCNT2, ((maincnt >> 16) & 0xFF)); - mrf24j40_setreg(dev->spi, MRF24J40_MAINCNT3, ((maincnt >> 24) & 0x03)); - - /* Configure the BO (ORDER 0x10<7:4>) and SO (ORDER 0x10<3:0>) values. - * After configuring BO and SO, the beacon frame will be sent immediately. - */ - - mrf24j40_setreg(dev->spi, MRF24J40_ORDER, ((bo << 4) & 0xF0) | (so & 0x0F)); -} - -/**************************************************************************** - * Name: mrf24j40_pacontrol - * - * Description: - * Control the external LNA/PA on the MRF24J40MB/MC/MD/ME modules - * GPIO 1: PA enable - * GPIO 2: LNA enable - * GPIO 3: PA power enable (not required on MB) - ****************************************************************************/ - -int mrf24j40_pacontrol(FAR struct mrf24j40_radio_s *dev, int mode) -{ - if (!dev->paenabled) - { - return OK; - } - - if (mode == MRF24J40_PA_AUTO) - { - mrf24j40_setreg(dev->spi, MRF24J40_TRISGPIO, 0x08); - mrf24j40_setreg(dev->spi, MRF24J40_GPIO , 0x08); - mrf24j40_setreg(dev->spi, MRF24J40_TESTMODE, 0x0F); - } - else if (mode == MRF24J40_PA_ED) - { - mrf24j40_setreg(dev->spi, MRF24J40_TESTMODE, 0x08); - mrf24j40_setreg(dev->spi, MRF24J40_TRISGPIO, 0x0F); - mrf24j40_setreg(dev->spi, MRF24J40_GPIO , 0x0C); - } - else if (mode == MRF24J40_PA_SLEEP) - { - mrf24j40_setreg(dev->spi, MRF24J40_TESTMODE, 0x08); - mrf24j40_setreg(dev->spi, MRF24J40_TRISGPIO, 0x0F); - mrf24j40_setreg(dev->spi, MRF24J40_GPIO , 0x00); - } - else - { - return -EINVAL; - } - - mrf24j40_resetrfsm(dev); - return OK; -} - -/**************************************************************************** - * Name: mrf24j40_energydetect - * - * Description: - * Measure the RSSI level for the current channel. - * - ****************************************************************************/ - -int mrf24j40_energydetect(FAR struct mrf24j40_radio_s *dev, FAR uint8_t *energy) -{ - uint8_t reg; - - /* Manually enable the LNA*/ - - mrf24j40_pacontrol(dev, MRF24J40_PA_ED); - - /* Set RSSI average duration to 8 symbols */ - - reg = mrf24j40_getreg(dev->spi, MRF24J40_TXBCON1); - reg |= 0x30; - mrf24j40_setreg(dev->spi, MRF24J40_TXBCON1, reg); - - /* 1. Set RSSIMODE1 0x3E<7> – Initiate RSSI calculation. */ - - mrf24j40_setreg(dev->spi, MRF24J40_BBREG6, 0x80); - - /* 2. Wait until RSSIRDY 0x3E<0> is set to ‘1’ – RSSI calculation is - * complete. - */ - - while(!(mrf24j40_getreg(dev->spi, MRF24J40_BBREG6) & 0x01)); - - /* 3. Read RSSI 0x210<7:0> – The RSSI register contains the averaged RSSI - * received power level for 8 symbol periods. - */ - - *energy = mrf24j40_getreg(dev->spi, MRF24J40_RSSI); - mrf24j40_setreg(dev->spi, MRF24J40_BBREG6, 0x40); - - /* Back to automatic control */ - - mrf24j40_pacontrol(dev, MRF24J40_PA_AUTO); - - return OK; -} - /**************************************************************************** * Name: mrf24j40_norm_setup * @@ -558,77 +412,7 @@ void mrf24j40_setup_fifo(FAR struct mrf24j40_radio_s *dev, FAR const uint8_t *bu } } -/**************************************************************************** - * Name: mrf24j40_rxenable - * - * Description: - * Enable/Disable receiver. - * - ****************************************************************************/ -int mrf24j40_rxenable(FAR struct ieee802154_radio_s *radio, bool enable) -{ - FAR struct mrf24j40_radio_s *dev = (FAR struct mrf24j40_radio_s *)radio; - uint8_t reg; - - dev->rxenabled = enable; - - - if (enable) - { - /* Disable packet reception. See pg. 109 of datasheet */ - - mrf24j40_setreg(dev->spi, MRF24J40_BBREG1, MRF24J40_BBREG1_RXDECINV); - - /* Enable rx int */ - - reg = mrf24j40_getreg(dev->spi, MRF24J40_INTCON); - reg &= ~MRF24J40_INTCON_RXIE; - mrf24j40_setreg(dev->spi, MRF24J40_INTCON, reg); - - /* Purge the RX buffer */ - - reg = mrf24j40_getreg(dev->spi, MRF24J40_RXFLUSH); - reg |= MRF24J40_RXFLUSH_RXFLUSH; - mrf24j40_setreg(dev->spi, MRF24J40_RXFLUSH, reg); - - /* Re-enable packet reception. See pg. 109 of datasheet */ - - mrf24j40_setreg(dev->spi, MRF24J40_BBREG1, 0); - } - else - { - /* Disable rx int */ - - reg = mrf24j40_getreg(dev->spi, MRF24J40_INTCON); - reg |= MRF24J40_INTCON_RXIE; - mrf24j40_setreg(dev->spi, MRF24J40_INTCON, reg); - } - - return OK; -} - -/**************************************************************************** - * Name: mrf24j40_resetrfsm - * - * Description: - * Reset the RF state machine. Required at boot, after channel change, - * and probably after PA settings. - * - ****************************************************************************/ - -void mrf24j40_resetrfsm(FAR struct mrf24j40_radio_s *dev) -{ - uint8_t reg; - - reg = mrf24j40_getreg(dev->spi, MRF24J40_RFCTL); - reg |= 0x04; - mrf24j40_setreg(dev->spi, MRF24J40_RFCTL, reg); - - reg &= ~0x04; - mrf24j40_setreg(dev->spi, MRF24J40_RFCTL, reg); - up_udelay(200); -} /**************************************************************************** * Public Functions diff --git a/drivers/wireless/ieee802154/mrf24j40/mrf24j40.h b/drivers/wireless/ieee802154/mrf24j40/mrf24j40.h index 1a3c15da09..bbfca37f4f 100644 --- a/drivers/wireless/ieee802154/mrf24j40/mrf24j40.h +++ b/drivers/wireless/ieee802154/mrf24j40/mrf24j40.h @@ -52,7 +52,9 @@ #include #include -/* NuttX implementation defines **********************************************/ +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ #define MRF24J40_GTS_SLOTS 2 @@ -87,6 +89,24 @@ #define MRF24J40_SYMBOL_DURATION_PS 16000000 +/* Clock configuration macros */ + +#define MRF24J40_SLPCLKPER_100KHZ ((1000 * 1000 * 1000)/100000) /* 10ns */ +#define MRF24J40_SLPCLKPER_32KHZ ((1000 * 1000 * 1000)/32000) /* 31.25ns */ + +#define MRF24J40_BEACONINTERVAL_NSEC(beaconorder) \ + (IEEE802154_BASE_SUPERFRAME_DURATION * (1 << beaconorder) * (16 *1000)) + +/* For now I am just setting the REMCNT to the maximum while staying in multiples + * of 10000 (100khz period) */ + +#define MRF24J40_REMCNT 60000 +#define MRF24J40_REMCNT_NSEC (MRF24J40_REMCNT * 50) + +#define MRF24J40_MAINCNT(bo, clkper) \ + ((MRF24J40_BEACONINTERVAL_NSEC(bo) - MRF24J40_REMCNT_NSEC) / \ + clkper) + /* Configuration *************************************************************/ #ifndef CONFIG_SCHED_HPWORK @@ -106,7 +126,7 @@ #endif /**************************************************************************** - * Private Types + * Public Types ****************************************************************************/ /* A MRF24J40 device instance */ @@ -157,38 +177,11 @@ struct mrf24j40_radio_s }; /**************************************************************************** - * Internal Function Prototypes + * Public Data ****************************************************************************/ -int mrf24j40_interrupt(int irq, FAR void *context, FAR void *arg); -void mrf24j40_irqworker(FAR void *arg); - -void mrf24j40_dopoll_csma(FAR void *arg); -void mrf24j40_dopoll_gts(FAR void *arg); - -void mrf24j40_resetrfsm(FAR struct mrf24j40_radio_s *dev); - -void mrf24j40_setorder(FAR struct mrf24j40_radio_s *dev, uint8_t bo, uint8_t so); - -int mrf24j40_pacontrol(FAR struct mrf24j40_radio_s *dev, int mode); -int mrf24j40_energydetect(FAR struct mrf24j40_radio_s *dev, FAR uint8_t *energy); - -int mrf24j40_rxenable(FAR struct ieee802154_radio_s *dev, bool enable); - -void mrf24j40_norm_setup(FAR struct mrf24j40_radio_s *dev, - FAR struct iob_s *frame, bool csma); -void mrf24j40_gts_setup(FAR struct mrf24j40_radio_s *dev, uint8_t gts, - FAR struct iob_s *frame); -void mrf24j40_setup_fifo(FAR struct mrf24j40_radio_s *dev, - FAR const uint8_t *buf, uint8_t length, uint32_t fifo_addr); - -void mrf24j40_norm_trigger(FAR struct mrf24j40_radio_s *dev); -void mrf24j40_beacon_trigger(FAR struct mrf24j40_radio_s *dev); - -void mrf24j40_mactimer(FAR struct mrf24j40_radio_s *dev, int numsymbols); - /**************************************************************************** - * Internal Helpers + * Inline Functions ****************************************************************************/ /**************************************************************************** @@ -220,5 +213,24 @@ static inline void mrf24j40_spi_unlock(FAR struct spi_dev_s *spi) SPI_LOCK(spi,0); } -#endif /* __DRIVERS_WIRELESS_IEEE802154_MRF24J40_H */ +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ +int mrf24j40_interrupt(int irq, FAR void *context, FAR void *arg); +void mrf24j40_irqworker(FAR void *arg); + +void mrf24j40_dopoll_csma(FAR void *arg); +void mrf24j40_dopoll_gts(FAR void *arg); + +void mrf24j40_norm_setup(FAR struct mrf24j40_radio_s *dev, + FAR struct iob_s *frame, bool csma); +void mrf24j40_gts_setup(FAR struct mrf24j40_radio_s *dev, uint8_t gts, + FAR struct iob_s *frame); +void mrf24j40_setup_fifo(FAR struct mrf24j40_radio_s *dev, + FAR const uint8_t *buf, uint8_t length, uint32_t fifo_addr); + +void mrf24j40_norm_trigger(FAR struct mrf24j40_radio_s *dev); +void mrf24j40_beacon_trigger(FAR struct mrf24j40_radio_s *dev); + +#endif /* __DRIVERS_WIRELESS_IEEE802154_MRF24J40_H */ diff --git a/drivers/wireless/ieee802154/mrf24j40/mrf24j40_getset.c b/drivers/wireless/ieee802154/mrf24j40/mrf24j40_getset.c index a4b92ad666..24bf5a644c 100644 --- a/drivers/wireless/ieee802154/mrf24j40/mrf24j40_getset.c +++ b/drivers/wireless/ieee802154/mrf24j40/mrf24j40_getset.c @@ -43,11 +43,49 @@ #include #include +#include + #include "mrf24j40.h" #include "mrf24j40_reg.h" #include "mrf24j40_regops.h" #include "mrf24j40_getset.h" +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +static void mrf24j40_resetrfsm(FAR struct mrf24j40_radio_s *dev); + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: mrf24j40_resetrfsm + * + * Description: + * Reset the RF state machine. Required at boot, after channel change, + * and probably after PA settings. + * + ****************************************************************************/ + +static void mrf24j40_resetrfsm(FAR struct mrf24j40_radio_s *dev) +{ + uint8_t reg; + + reg = mrf24j40_getreg(dev->spi, MRF24J40_RFCTL); + reg |= 0x04; + mrf24j40_setreg(dev->spi, MRF24J40_RFCTL, reg); + + reg &= ~0x04; + mrf24j40_setreg(dev->spi, MRF24J40_RFCTL, reg); + up_udelay(200); +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + /**************************************************************************** * Name: mrf24j40_setrxmode * @@ -423,3 +461,47 @@ int mrf24j40_setcca(FAR struct mrf24j40_radio_s *dev, memcpy(&dev->cca, cca, sizeof(struct ieee802154_cca_s)); return OK; } + +/**************************************************************************** + * Name: mrf24j40_setpamode + * + * Description: + * Control the external LNA/PA on the MRF24J40MB/MC/MD/ME modules + * GPIO 1: PA enable + * GPIO 2: LNA enable + * GPIO 3: PA power enable (not required on MB) + ****************************************************************************/ + +int mrf24j40_setpamode(FAR struct mrf24j40_radio_s *dev, int mode) +{ + if (!dev->paenabled) + { + return OK; + } + + if (mode == MRF24J40_PA_AUTO) + { + mrf24j40_setreg(dev->spi, MRF24J40_TRISGPIO, 0x08); + mrf24j40_setreg(dev->spi, MRF24J40_GPIO , 0x08); + mrf24j40_setreg(dev->spi, MRF24J40_TESTMODE, 0x0F); + } + else if (mode == MRF24J40_PA_ED) + { + mrf24j40_setreg(dev->spi, MRF24J40_TESTMODE, 0x08); + mrf24j40_setreg(dev->spi, MRF24J40_TRISGPIO, 0x0F); + mrf24j40_setreg(dev->spi, MRF24J40_GPIO , 0x0C); + } + else if (mode == MRF24J40_PA_SLEEP) + { + mrf24j40_setreg(dev->spi, MRF24J40_TESTMODE, 0x08); + mrf24j40_setreg(dev->spi, MRF24J40_TRISGPIO, 0x0F); + mrf24j40_setreg(dev->spi, MRF24J40_GPIO , 0x00); + } + else + { + return -EINVAL; + } + + mrf24j40_resetrfsm(dev); + return OK; +} diff --git a/drivers/wireless/ieee802154/mrf24j40/mrf24j40_getset.h b/drivers/wireless/ieee802154/mrf24j40/mrf24j40_getset.h index 999ce92875..f1acb79fee 100644 --- a/drivers/wireless/ieee802154/mrf24j40/mrf24j40_getset.h +++ b/drivers/wireless/ieee802154/mrf24j40/mrf24j40_getset.h @@ -61,4 +61,6 @@ int mrf24j40_settxpower(FAR struct mrf24j40_radio_s *dev, int32_t txpwr); int mrf24j40_setcca(FAR struct mrf24j40_radio_s *dev, FAR struct ieee802154_cca_s *cca); +int mrf24j40_setpamode(FAR struct mrf24j40_radio_s *dev, int mode); + #endif /* __DRIVERS_WIRELESS_IEEE802154_MRF24J40_GETSET_H */ \ No newline at end of file diff --git a/drivers/wireless/ieee802154/mrf24j40/mrf24j40_radif.c b/drivers/wireless/ieee802154/mrf24j40/mrf24j40_radif.c index 9f2aca935f..546984ff1c 100644 --- a/drivers/wireless/ieee802154/mrf24j40/mrf24j40_radif.c +++ b/drivers/wireless/ieee802154/mrf24j40/mrf24j40_radif.c @@ -48,6 +48,8 @@ #include #include +#include + #include #include @@ -60,6 +62,18 @@ * Pre-processor Definitions ****************************************************************************/ +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +static void mrf24j40_mactimer(FAR struct mrf24j40_radio_s *dev, int numsymbols); +static void mrf24j40_setorder(FAR struct mrf24j40_radio_s *dev, uint8_t bo, + uint8_t so); + /**************************************************************************** * Private Data ****************************************************************************/ @@ -70,9 +84,119 @@ static const uint8_t g_allones[8] = }; /**************************************************************************** - * Radio Interface Functions + * Public Data ****************************************************************************/ +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +static void mrf24j40_mactimer(FAR struct mrf24j40_radio_s *dev, int numsymbols) +{ + uint16_t nhalfsym; + uint8_t reg; + + nhalfsym = (numsymbols << 1); + + /* Disable the interrupt, clear the timer count */ + + reg = mrf24j40_getreg(dev->spi, MRF24J40_INTCON); + reg |= MRF24J40_INTCON_HSYMTMRIE; + mrf24j40_setreg(dev->spi, MRF24J40_INTCON, reg); + + mrf24j40_setreg(dev->spi, MRF24J40_HSYMTMRL, 0x00); + mrf24j40_setreg(dev->spi, MRF24J40_HSYMTMRH, 0x00); + + reg &= ~MRF24J40_INTCON_HSYMTMRIE; + mrf24j40_setreg(dev->spi, MRF24J40_INTCON, reg); + + /* Set the timer count and enable interrupts */ + + reg = (nhalfsym & 0xFF); + mrf24j40_setreg(dev->spi, MRF24J40_HSYMTMRL, reg); + + reg = (nhalfsym >> 8) & 0xFF; + mrf24j40_setreg(dev->spi, MRF24J40_HSYMTMRH, reg); +} + +/**************************************************************************** + * Name: mrf24j40_setorder + * + * Description: + * Configures the timers and sets the ORDER register + ****************************************************************************/ + +static void mrf24j40_setorder(FAR struct mrf24j40_radio_s *dev, uint8_t bo, + uint8_t so) +{ + uint32_t maincnt = 0; + uint32_t slpcal = 0; + + wlinfo("bo: %d, so: %d\n", bo, so); + + /* Calibrate the Sleep Clock (SLPCLK) frequency. Refer to Section 3.15.1.2 + * “Sleep Clock Calibration”. + */ + + /* If the Sleep Clock Selection, SLPCLKSEL (0x207<7:6), is the internal + * oscillator (100 kHz), set SLPCLKDIV to a minimum value of 0x01. + */ + + mrf24j40_setreg(dev->spi, MRF24J40_SLPCON1, 0x01); + + /* Select the source of SLPCLK (internal 100kHz) */ + + mrf24j40_setreg(dev->spi, MRF24J40_RFCON7, MRF24J40_RFCON7_SEL_100KHZ); + + /* Begin calibration by setting the SLPCALEN bit (SLPCAL2 0x20B<4>) to + * ‘1’. Sixteen samples of the SLPCLK are counted and stored in the + * SLPCAL register. No need to mask, this is the only writable bit + */ + + mrf24j40_setreg(dev->spi, MRF24J40_SLPCAL2, MRF24J40_SLPCAL2_SLPCALEN); + + /* Calibration is complete when the SLPCALRDY bit (SLPCAL2 0x20B<7>) is + * set to ‘1’. + */ + + while (!(mrf24j40_getreg(dev->spi, MRF24J40_SLPCAL2) & + MRF24J40_SLPCAL2_SLPCALRDY)) + { + up_udelay(1); + } + + slpcal = mrf24j40_getreg(dev->spi, MRF24J40_SLPCAL0); + slpcal |= (mrf24j40_getreg(dev->spi, MRF24J40_SLPCAL1) << 8); + slpcal |= ((mrf24j40_getreg(dev->spi, MRF24J40_SLPCAL2) << 16) & 0x0F); + + /* Program the Beacon Interval into the Main Counter, MAINCNT (0x229<1:0>, + * 0x228, 0x227, 0x226), and Remain Counter, REMCNT (0x225, 0x224), + * according to BO and SO values. Refer to Section 3.15.1.3 “Sleep Mode + * Counters” + */ + + mrf24j40_setreg(dev->spi, MRF24J40_REMCNTL, (MRF24J40_REMCNT & 0xFF)); + mrf24j40_setreg(dev->spi, MRF24J40_REMCNTH, ((MRF24J40_REMCNT >> 8) & 0xFF)); + + maincnt = MRF24J40_MAINCNT(bo, (slpcal * 50 / 16)); + + mrf24j40_setreg(dev->spi, MRF24J40_MAINCNT0, (maincnt & 0xFF)); + mrf24j40_setreg(dev->spi, MRF24J40_MAINCNT1, ((maincnt >> 8) & 0xFF)); + mrf24j40_setreg(dev->spi, MRF24J40_MAINCNT2, ((maincnt >> 16) & 0xFF)); + mrf24j40_setreg(dev->spi, MRF24J40_MAINCNT3, ((maincnt >> 24) & 0x03)); + + /* Configure the BO (ORDER 0x10<7:4>) and SO (ORDER 0x10<3:0>) values. + * After configuring BO and SO, the beacon frame will be sent immediately. + */ + + mrf24j40_setreg(dev->spi, MRF24J40_ORDER, ((bo << 4) & 0xF0) | (so & 0x0F)); +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ +/* Radio Interface Functions ***********************************************/ + int mrf24j40_bind(FAR struct ieee802154_radio_s *radio, FAR struct ieee802154_radiocb_s *radiocb) { @@ -222,6 +346,56 @@ int mrf24j40_txdelayed(FAR struct ieee802154_radio_s *radio, return OK; } +/**************************************************************************** + * Name: mrf24j40_rxenable + * + * Description: + * Enable/Disable receiver. + * + ****************************************************************************/ + +int mrf24j40_rxenable(FAR struct ieee802154_radio_s *radio, bool enable) +{ + FAR struct mrf24j40_radio_s *dev = (FAR struct mrf24j40_radio_s *)radio; + uint8_t reg; + + dev->rxenabled = enable; + + + if (enable) + { + /* Disable packet reception. See pg. 109 of datasheet */ + + mrf24j40_setreg(dev->spi, MRF24J40_BBREG1, MRF24J40_BBREG1_RXDECINV); + + /* Enable rx int */ + + reg = mrf24j40_getreg(dev->spi, MRF24J40_INTCON); + reg &= ~MRF24J40_INTCON_RXIE; + mrf24j40_setreg(dev->spi, MRF24J40_INTCON, reg); + + /* Purge the RX buffer */ + + reg = mrf24j40_getreg(dev->spi, MRF24J40_RXFLUSH); + reg |= MRF24J40_RXFLUSH_RXFLUSH; + mrf24j40_setreg(dev->spi, MRF24J40_RXFLUSH, reg); + + /* Re-enable packet reception. See pg. 109 of datasheet */ + + mrf24j40_setreg(dev->spi, MRF24J40_BBREG1, 0); + } + else + { + /* Disable rx int */ + + reg = mrf24j40_getreg(dev->spi, MRF24J40_INTCON); + reg |= MRF24J40_INTCON_RXIE; + mrf24j40_setreg(dev->spi, MRF24J40_INTCON, reg); + } + + return OK; +} + int mrf24j40_reset(FAR struct ieee802154_radio_s *radio) { FAR struct mrf24j40_radio_s *dev = (FAR struct mrf24j40_radio_s *)radio; @@ -303,7 +477,7 @@ int mrf24j40_reset(FAR struct ieee802154_radio_s *radio) mrf24j40_settxpower(dev, 0); /*16. Set transmitter power .*/ - mrf24j40_pacontrol(dev, MRF24J40_PA_AUTO); + mrf24j40_setpamode(dev, MRF24J40_PA_AUTO); return OK; } @@ -535,3 +709,4 @@ int mrf24j40_sfupdate(FAR struct ieee802154_radio_s *radio, return OK; } + diff --git a/drivers/wireless/ieee802154/mrf24j40/mrf24j40_radif.h b/drivers/wireless/ieee802154/mrf24j40/mrf24j40_radif.h index 3eb678c603..8d5fe07d09 100644 --- a/drivers/wireless/ieee802154/mrf24j40/mrf24j40_radif.h +++ b/drivers/wireless/ieee802154/mrf24j40/mrf24j40_radif.h @@ -55,6 +55,7 @@ int mrf24j40_txdelayed(FAR struct ieee802154_radio_s *radio, FAR struct ieee802154_txdesc_s *txdesc, uint32_t symboldelay); +int mrf24j40_rxenable(FAR struct ieee802154_radio_s *radio, bool enable); int mrf24j40_beaconstart(FAR struct ieee802154_radio_s *radio, FAR const struct ieee802154_superframespec_s *sfspec, From 4ad0f8b68b6382d30923c3c5d5063da357e94dec Mon Sep 17 00:00:00 2001 From: Gregory Nutt Date: Tue, 11 Jul 2017 19:45:22 -0600 Subject: [PATCH 33/54] trivial --- drivers/wireless/ieee802154/mrf24j40/mrf24j40_regops.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/wireless/ieee802154/mrf24j40/mrf24j40_regops.c b/drivers/wireless/ieee802154/mrf24j40/mrf24j40_regops.c index 16fb2b0fcf..a5de5e0d1f 100644 --- a/drivers/wireless/ieee802154/mrf24j40/mrf24j40_regops.c +++ b/drivers/wireless/ieee802154/mrf24j40/mrf24j40_regops.c @@ -1,6 +1,6 @@ /**************************************************************************** * drivers/wireless/ieee802154/mrf24j40/mrf24j40_regops.c - + * * Copyright (C) 2015-2016 Sebastien Lorquet. All rights reserved. * Copyright (C) 2017 Verge Inc. All rights reserved. * Author: Sebastien Lorquet From c3f51dce70ef415139322a1a272f8c9eb8c86aa0 Mon Sep 17 00:00:00 2001 From: Anthony Merlino Date: Tue, 11 Jul 2017 23:41:49 -0400 Subject: [PATCH 34/54] drivers/mrf24j40: Formatting fixes --- .../wireless/ieee802154/mrf24j40/mrf24j40.c | 5 +- .../ieee802154/mrf24j40/mrf24j40_getset.c | 1 + .../ieee802154/mrf24j40/mrf24j40_radif.c | 2 +- .../ieee802154/mrf24j40/mrf24j40_regops.c | 379 +++++++++--------- 4 files changed, 195 insertions(+), 192 deletions(-) diff --git a/drivers/wireless/ieee802154/mrf24j40/mrf24j40.c b/drivers/wireless/ieee802154/mrf24j40/mrf24j40.c index 17f5c6186d..00ebe6cd99 100644 --- a/drivers/wireless/ieee802154/mrf24j40/mrf24j40.c +++ b/drivers/wireless/ieee802154/mrf24j40/mrf24j40.c @@ -40,16 +40,17 @@ ****************************************************************************/ #include + #include #include - -#include #include #include #include #include #include +#include + #include #include #include diff --git a/drivers/wireless/ieee802154/mrf24j40/mrf24j40_getset.c b/drivers/wireless/ieee802154/mrf24j40/mrf24j40_getset.c index 24bf5a644c..c2f7a16be4 100644 --- a/drivers/wireless/ieee802154/mrf24j40/mrf24j40_getset.c +++ b/drivers/wireless/ieee802154/mrf24j40/mrf24j40_getset.c @@ -40,6 +40,7 @@ ****************************************************************************/ #include + #include #include diff --git a/drivers/wireless/ieee802154/mrf24j40/mrf24j40_radif.c b/drivers/wireless/ieee802154/mrf24j40/mrf24j40_radif.c index 546984ff1c..c8cb3cfc4e 100644 --- a/drivers/wireless/ieee802154/mrf24j40/mrf24j40_radif.c +++ b/drivers/wireless/ieee802154/mrf24j40/mrf24j40_radif.c @@ -40,9 +40,9 @@ ****************************************************************************/ #include + #include #include - #include #include #include diff --git a/drivers/wireless/ieee802154/mrf24j40/mrf24j40_regops.c b/drivers/wireless/ieee802154/mrf24j40/mrf24j40_regops.c index a5de5e0d1f..75e507d0b8 100644 --- a/drivers/wireless/ieee802154/mrf24j40/mrf24j40_regops.c +++ b/drivers/wireless/ieee802154/mrf24j40/mrf24j40_regops.c @@ -1,189 +1,190 @@ -/**************************************************************************** - * drivers/wireless/ieee802154/mrf24j40/mrf24j40_regops.c - * - * Copyright (C) 2015-2016 Sebastien Lorquet. All rights reserved. - * Copyright (C) 2017 Verge Inc. All rights reserved. - * Author: Sebastien Lorquet - * Author: Anthony Merlino - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * 3. Neither the name NuttX nor the names of its contributors may be - * used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS - * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED - * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - ****************************************************************************/ - -/**************************************************************************** - * Included Files - ****************************************************************************/ - -#include -#include -#include - -#include "mrf24j40.h" -#include "mrf24j40_regops.h" - -/**************************************************************************** - * Internal Driver Functions - ****************************************************************************/ - -/**************************************************************************** - * Name: mrf24j40_setreg - * - * Description: - * Define the value of an MRF24J40 device register - * - ****************************************************************************/ - -void mrf24j40_setreg(FAR struct spi_dev_s *spi, uint32_t addr, uint8_t val) -{ - uint8_t buf[3]; - int len; - - if (!(addr&0x80000000)) - { - addr &= 0x3F; /* 6-bit address */ - addr <<= 1; - addr |= 0x01; /* writing */ - buf[0] = addr; - len = 1; - } - else - { - addr &= 0x3FF; /* 10-bit address */ - addr <<= 5; - addr |= 0x8010; /* writing long */ - buf[0] = (addr >> 8); - buf[1] = (addr & 0xFF); - len = 2; - } - - buf[len++] = val; - - mrf24j40_spi_lock(spi); - SPI_SELECT(spi, SPIDEV_IEEE802154(0), true); - SPI_SNDBLOCK(spi, buf, len); - SPI_SELECT(spi, SPIDEV_IEEE802154(0), false); - mrf24j40_spi_unlock(spi); -} - -/**************************************************************************** - * Name: mrf24j40_getreg - * - * Description: - * Return the value of an MRF24J40 device register* - * - ****************************************************************************/ - -uint8_t mrf24j40_getreg(FAR struct spi_dev_s *spi, uint32_t addr) -{ - uint8_t buf[3]; - uint8_t rx[3]; - int len; - - if (!(addr&0x80000000)) - { - /* 6-bit address */ - - addr &= 0x3F; - addr <<= 1; - buf[0] = addr; - len = 1; - } - else - { - /* 10-bit address */ - - addr &= 0x3FF; - addr <<= 5; - addr |= 0x8000; - buf[0] = (addr >> 8); - buf[1] = (addr & 0xFF); - len = 2; - } - - buf[len++] = 0xFF; /* dummy */ - - mrf24j40_spi_lock (spi); - SPI_SELECT (spi, SPIDEV_IEEE802154(0), true); - SPI_EXCHANGE (spi, buf, rx, len); - SPI_SELECT (spi, SPIDEV_IEEE802154(0), false); - mrf24j40_spi_unlock(spi); - - /* wlinfo("r[%04X]=%02X\n", addr, rx[len - 1]); */ - return rx[len - 1]; -} - -/**************************************************************************** - * Name: mrf24j40_regdump - * - * Description: - * Display the value of all registers. - * - ****************************************************************************/ - -int mrf24j40_regdump(FAR struct mrf24j40_radio_s *dev) -{ - uint32_t i; - char buf[4+16*3+2+1]; - int len = 0; - - wlinfo("Short regs:\n"); - - for (i = 0; i < 0x40; i++) - { - if ((i & 15) == 0) - { - len=sprintf(buf, "%02x: ",i&0xFF); - } - - len += sprintf(buf+len, "%02x ", mrf24j40_getreg(dev->spi, i)); - if ((i & 15) == 15) - { - sprintf(buf+len, "\n"); - wlinfo("%s", buf); - } - } - - wlinfo("Long regs:\n"); - - for (i = 0x80000200; i < 0x80000250; i++) - { - if ((i & 15) == 0) - { - len=sprintf(buf, "%02x: ",i&0xFF); - } - - len += sprintf(buf+len, "%02x ", mrf24j40_getreg(dev->spi, i)); - if ((i & 15) == 15) - { - sprintf(buf+len, "\n"); - wlinfo("%s", buf); - } - } - - return 0; -} +/**************************************************************************** + * drivers/wireless/ieee802154/mrf24j40/mrf24j40_regops.c + * + * Copyright (C) 2015-2016 Sebastien Lorquet. All rights reserved. + * Copyright (C) 2017 Verge Inc. All rights reserved. + * Author: Sebastien Lorquet + * Author: Anthony Merlino + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include + +#include "mrf24j40.h" +#include "mrf24j40_regops.h" + +/**************************************************************************** + * Internal Driver Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: mrf24j40_setreg + * + * Description: + * Define the value of an MRF24J40 device register + * + ****************************************************************************/ + +void mrf24j40_setreg(FAR struct spi_dev_s *spi, uint32_t addr, uint8_t val) +{ + uint8_t buf[3]; + int len; + + if (!(addr&0x80000000)) + { + addr &= 0x3F; /* 6-bit address */ + addr <<= 1; + addr |= 0x01; /* writing */ + buf[0] = addr; + len = 1; + } + else + { + addr &= 0x3FF; /* 10-bit address */ + addr <<= 5; + addr |= 0x8010; /* writing long */ + buf[0] = (addr >> 8); + buf[1] = (addr & 0xFF); + len = 2; + } + + buf[len++] = val; + + mrf24j40_spi_lock(spi); + SPI_SELECT(spi, SPIDEV_IEEE802154(0), true); + SPI_SNDBLOCK(spi, buf, len); + SPI_SELECT(spi, SPIDEV_IEEE802154(0), false); + mrf24j40_spi_unlock(spi); +} + +/**************************************************************************** + * Name: mrf24j40_getreg + * + * Description: + * Return the value of an MRF24J40 device register* + * + ****************************************************************************/ + +uint8_t mrf24j40_getreg(FAR struct spi_dev_s *spi, uint32_t addr) +{ + uint8_t buf[3]; + uint8_t rx[3]; + int len; + + if (!(addr&0x80000000)) + { + /* 6-bit address */ + + addr &= 0x3F; + addr <<= 1; + buf[0] = addr; + len = 1; + } + else + { + /* 10-bit address */ + + addr &= 0x3FF; + addr <<= 5; + addr |= 0x8000; + buf[0] = (addr >> 8); + buf[1] = (addr & 0xFF); + len = 2; + } + + buf[len++] = 0xFF; /* dummy */ + + mrf24j40_spi_lock (spi); + SPI_SELECT (spi, SPIDEV_IEEE802154(0), true); + SPI_EXCHANGE (spi, buf, rx, len); + SPI_SELECT (spi, SPIDEV_IEEE802154(0), false); + mrf24j40_spi_unlock(spi); + + /* wlinfo("r[%04X]=%02X\n", addr, rx[len - 1]); */ + return rx[len - 1]; +} + +/**************************************************************************** + * Name: mrf24j40_regdump + * + * Description: + * Display the value of all registers. + * + ****************************************************************************/ + +int mrf24j40_regdump(FAR struct mrf24j40_radio_s *dev) +{ + uint32_t i; + char buf[4+16*3+2+1]; + int len = 0; + + wlinfo("Short regs:\n"); + + for (i = 0; i < 0x40; i++) + { + if ((i & 15) == 0) + { + len=sprintf(buf, "%02x: ",i&0xFF); + } + + len += sprintf(buf+len, "%02x ", mrf24j40_getreg(dev->spi, i)); + if ((i & 15) == 15) + { + sprintf(buf+len, "\n"); + wlinfo("%s", buf); + } + } + + wlinfo("Long regs:\n"); + + for (i = 0x80000200; i < 0x80000250; i++) + { + if ((i & 15) == 0) + { + len=sprintf(buf, "%02x: ",i&0xFF); + } + + len += sprintf(buf+len, "%02x ", mrf24j40_getreg(dev->spi, i)); + if ((i & 15) == 15) + { + sprintf(buf+len, "\n"); + wlinfo("%s", buf); + } + } + + return 0; +} From f944a33485a5e7fb768cb52d04a60e6bfbee8eee Mon Sep 17 00:00:00 2001 From: Anthony Merlino Date: Tue, 11 Jul 2017 23:42:30 -0400 Subject: [PATCH 35/54] drivers/mrf24j40: Fixes implicit declaration warning --- drivers/wireless/ieee802154/mrf24j40/mrf24j40_regops.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/wireless/ieee802154/mrf24j40/mrf24j40_regops.c b/drivers/wireless/ieee802154/mrf24j40/mrf24j40_regops.c index 75e507d0b8..2558bde084 100644 --- a/drivers/wireless/ieee802154/mrf24j40/mrf24j40_regops.c +++ b/drivers/wireless/ieee802154/mrf24j40/mrf24j40_regops.c @@ -43,6 +43,7 @@ #include #include +#include #include "mrf24j40.h" #include "mrf24j40_regops.h" From 420db06b37e58a47fa171b9dec2e291896f2848a Mon Sep 17 00:00:00 2001 From: Anthony Merlino Date: Wed, 12 Jul 2017 00:53:04 -0400 Subject: [PATCH 36/54] ieee802154: Notify radio layer of changes in devmode --- wireless/ieee802154/mac802154_assoc.c | 10 ++++++++-- wireless/ieee802154/mac802154_internal.h | 15 ++++++++------- 2 files changed, 16 insertions(+), 9 deletions(-) diff --git a/wireless/ieee802154/mac802154_assoc.c b/wireless/ieee802154/mac802154_assoc.c index c5448ca1fb..b72ba08556 100644 --- a/wireless/ieee802154/mac802154_assoc.c +++ b/wireless/ieee802154/mac802154_assoc.c @@ -133,8 +133,14 @@ int mac802154_req_associate(MACHANDLE mac, /* Copy in the capabilities information bitfield */ - priv->devmode = (req->capabilities.devtype) ? - IEEE802154_DEVMODE_COORD : IEEE802154_DEVMODE_ENDPOINT; + if (req->capabilities.devtype) + { + mac802154_setdevmode(priv, IEEE802154_DEVMODE_COORD); + } + else + { + mac802154_setdevmode(priv, IEEE802154_DEVMODE_ENDPOINT); + } mac802154_setrxonidle(priv, req->capabilities.rxonidle); diff --git a/wireless/ieee802154/mac802154_internal.h b/wireless/ieee802154/mac802154_internal.h index fd1fd77568..8051763598 100644 --- a/wireless/ieee802154/mac802154_internal.h +++ b/wireless/ieee802154/mac802154_internal.h @@ -816,15 +816,16 @@ static inline void mac802154_setrxonidle(FAR struct ieee802154_privmac_s *priv, mac802154_rxdisable(priv); } - /* Unlike other attributes, we can't simply cast this one since it is a bit - * in a bitfield. Casting it will give us unpredicatble results. Instead - * of creating a ieee802154_attr_u, we use a local bool. Allocating the - * ieee802154_attr_u value would take up more room on the stack since it is - * as large as the largest attribute type. - */ - priv->radio->setattr(priv->radio, IEEE802154_ATTR_MAC_RX_ON_WHEN_IDLE, (FAR const union ieee802154_attr_u *)&rxonidle); } +static inline void mac802154_setdevmode(FAR struct ieee802154_privmac_s *priv, + enum ieee802154_devmode_e mode) +{ + priv->devmode = mode; + priv->radio->setattr(priv->radio, IEEE802154_ATTR_MAC_RX_ON_WHEN_IDLE, + (FAR const union ieee802154_attr_u *)&mode); +} + #endif /* __WIRELESS_IEEE802154__MAC802154_INTERNAL_H */ From b1eb796d97b3f72f71af1d392c4d5ff7b85975df Mon Sep 17 00:00:00 2001 From: Anthony Merlino Date: Wed, 12 Jul 2017 00:54:29 -0400 Subject: [PATCH 37/54] drivers/mrf24j40: Hook in setdevmode from newly added radio attribute setting --- .../ieee802154/mrf24j40/mrf24j40_getset.c | 13 ++----------- .../ieee802154/mrf24j40/mrf24j40_radif.c | 18 +++++++----------- 2 files changed, 9 insertions(+), 22 deletions(-) diff --git a/drivers/wireless/ieee802154/mrf24j40/mrf24j40_getset.c b/drivers/wireless/ieee802154/mrf24j40/mrf24j40_getset.c index c2f7a16be4..b3c7406eb3 100644 --- a/drivers/wireless/ieee802154/mrf24j40/mrf24j40_getset.c +++ b/drivers/wireless/ieee802154/mrf24j40/mrf24j40_getset.c @@ -290,19 +290,10 @@ int mrf24j40_setcoordeaddr(FAR struct mrf24j40_radio_s *dev, * ****************************************************************************/ -int mrf24j40_setdevmode(FAR struct mrf24j40_radio_s *dev, - uint8_t mode) +int mrf24j40_setdevmode(FAR struct mrf24j40_radio_s *dev, uint8_t mode) { - int ret = OK; uint8_t reg; - /* Disable slotted mode until I decide to implement slotted mode */ - - reg = mrf24j40_getreg(dev->spi, MRF24J40_TXMCR); - reg &= ~MRF24J40_TXMCR_SLOTTED; - mrf24j40_setreg(dev->spi, MRF24J40_TXMCR, reg); - mrf24j40_setreg(dev->spi, MRF24J40_ORDER, 0xFF); - /* Define dev mode */ reg = mrf24j40_getreg(dev->spi, MRF24J40_RXMCR); @@ -329,7 +320,7 @@ int mrf24j40_setdevmode(FAR struct mrf24j40_radio_s *dev, mrf24j40_setreg(dev->spi, MRF24J40_RXMCR, reg); dev->devmode = mode; - return ret; + return OK; } /**************************************************************************** diff --git a/drivers/wireless/ieee802154/mrf24j40/mrf24j40_radif.c b/drivers/wireless/ieee802154/mrf24j40/mrf24j40_radif.c index c8cb3cfc4e..b4faa5c153 100644 --- a/drivers/wireless/ieee802154/mrf24j40/mrf24j40_radif.c +++ b/drivers/wireless/ieee802154/mrf24j40/mrf24j40_radif.c @@ -530,42 +530,37 @@ int mrf24j40_setattr(FAR struct ieee802154_radio_s *radio, FAR const union ieee802154_attr_u *attrval) { FAR struct mrf24j40_radio_s *dev = (FAR struct mrf24j40_radio_s *)radio; - int ret; + int ret = IEEE802154_STATUS_SUCCESS;; switch (attr) { case IEEE802154_ATTR_MAC_PANID: { mrf24j40_setpanid(dev, attrval->mac.panid); - ret = IEEE802154_STATUS_SUCCESS; } break; case IEEE802154_ATTR_MAC_SADDR: { mrf24j40_setsaddr(dev, attrval->mac.saddr); - ret = IEEE802154_STATUS_SUCCESS; } break; case IEEE802154_ATTR_MAC_EADDR: { mrf24j40_seteaddr(dev, attrval->mac.eaddr); - ret = IEEE802154_STATUS_SUCCESS; } break; case IEEE802154_ATTR_MAC_COORD_SADDR: { mrf24j40_setcoordsaddr(dev, attrval->mac.coordsaddr); - ret = IEEE802154_STATUS_SUCCESS; } break; case IEEE802154_ATTR_MAC_COORD_EADDR: { mrf24j40_setcoordeaddr(dev, attrval->mac.coordeaddr); - ret = IEEE802154_STATUS_SUCCESS; } break; @@ -579,16 +574,18 @@ int mrf24j40_setattr(FAR struct ieee802154_radio_s *radio, { mrf24j40_setrxmode(dev, MRF24J40_RXMODE_NORMAL); } - - ret = IEEE802154_STATUS_SUCCESS; } break; - case IEEE802154_ATTR_PHY_CHAN: { mrf24j40_setchannel(dev, attrval->phy.chan); - ret = IEEE802154_STATUS_SUCCESS; + } + break; + + case IEEE802154_ATTR_MAC_DEVMODE: + { + mrf24j40_setdevmode(dev, attrval->mac.devmode); } break; @@ -709,4 +706,3 @@ int mrf24j40_sfupdate(FAR struct ieee802154_radio_s *radio, return OK; } - From a846459bec1965be7bb2ca0ec7ba4254ad314e96 Mon Sep 17 00:00:00 2001 From: Anthony Merlino Date: Wed, 12 Jul 2017 00:57:55 -0400 Subject: [PATCH 38/54] ieee802154: Minor formatting fixes --- wireless/ieee802154/mac802154_reset.c | 38 +++++++++++++-------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/wireless/ieee802154/mac802154_reset.c b/wireless/ieee802154/mac802154_reset.c index 598275d9e0..1f1025815f 100644 --- a/wireless/ieee802154/mac802154_reset.c +++ b/wireless/ieee802154/mac802154_reset.c @@ -86,26 +86,26 @@ int mac802154_req_reset(MACHANDLE mac, bool resetattr) if (resetattr) { - priv->isassoc = false; /* Not associated with a PAN */ - priv->trackingbeacon = false; /* Not tracking beacon by default */ - priv->sfspec.assocpermit = false; /* Device (if coord) not accepting ssociation */ - priv->autoreq = true; /* Auto send data req if addr. in beacon */ + priv->isassoc = false; /* Not associated with a PAN */ + priv->trackingbeacon = false; /* Not tracking beacon by default */ + priv->sfspec.assocpermit = false; /* Dev (if coord) not accepting assoc */ + priv->autoreq = true; /* Auto send data req if addr in beacon */ priv->sfspec.ble = false; /* BLE disabled */ - priv->beaconpayloadlength = 0; /* Beacon payload NULL */ - priv->sfspec.beaconorder = 15; /* Non-beacon enabled network */ - priv->sfspec.sforder = 15; /* Length of active portion of outgoing SF */ - priv->beacon_txtime = 0; /* Device never sent a beacon */ - priv->dsn = 0; - priv->gtspermit = true; /* PAN Coord accepting GTS requests */ - priv->minbe = 3; /* Min value of backoff exponent (BE) */ - priv->maxbe = 5; /* Max value of backoff exponent (BE) */ - priv->max_csmabackoffs = 4; /* Max # of backoffs before failure */ - priv->maxretries = 3; /* Max # of retries allowed after failure */ - priv->promisc = false; /* Device not in promiscuous mode */ - priv->rngsupport = false; /* Ranging not yet supported */ - priv->resp_waittime = 32; /* 32 SF durations */ - priv->sec_enabled = false; /* Security disabled by default */ - priv->tx_totaldur = 0; /* 0 transmit duration */ + priv->beaconpayloadlength = 0; /* Beacon payload NULL */ + priv->sfspec.beaconorder = 15; /* Non-beacon enabled network */ + priv->sfspec.sforder = 15; /* Length of active portion of outgoing SF */ + priv->beacon_txtime = 0; /* Device never sent a beacon */ + priv->dsn = 0; /* Data sequence number */ + priv->gtspermit = true; /* PAN Coord accepting GTS requests */ + priv->minbe = 3; /* Min value of backoff exponent (BE) */ + priv->maxbe = 5; /* Max value of backoff exponent (BE) */ + priv->max_csmabackoffs = 4; /* Max # of backoffs before failure */ + priv->maxretries = 3; /* Max # of retries allowed after failure */ + priv->promisc = false; /* Device not in promiscuous mode */ + priv->rngsupport = false; /* Ranging not yet supported */ + priv->resp_waittime = 32; /* 32 SF durations */ + priv->sec_enabled = false; /* Security disabled by default */ + priv->tx_totaldur = 0; /* 0 transmit duration */ priv->trans_persisttime = 0x01F4; From e466ade385ad510116ee4e6bf7eacf64e2ddeb20 Mon Sep 17 00:00:00 2001 From: Anthony Merlino Date: Wed, 12 Jul 2017 00:59:38 -0400 Subject: [PATCH 39/54] ieee802154: Set devmode to endpoint on MAC layer reset --- wireless/ieee802154/mac802154_reset.c | 18 +----------------- 1 file changed, 1 insertion(+), 17 deletions(-) diff --git a/wireless/ieee802154/mac802154_reset.c b/wireless/ieee802154/mac802154_reset.c index 1f1025815f..a573df21c8 100644 --- a/wireless/ieee802154/mac802154_reset.c +++ b/wireless/ieee802154/mac802154_reset.c @@ -134,24 +134,8 @@ int mac802154_req_reset(MACHANDLE mac, bool resetattr) &attr); priv->max_frame_waittime = attr.mac.max_frame_waittime; - /* These attributes are effected and determined based on the PHY. Need to - * figure out how to "share" attributes between the radio driver and this - * MAC layer - * - * macAckWaitDuration - * macBattLifeExtPeriods - * macMaxFrameTotalWaitTime - * macLIFSPeriod - * macSIFSPeriod - * macSyncSymbolOffset - * macTimestampSupported - * macTxControlActiveDuration - * macTxControlPauseDuration - * macRxOnWhenIdle - */ + mac802154_setdevmode(priv, IEEE802154_DEVMODE_ENDPOINT); } return OK; } - - From 21bc4175fee79a8a25f3fa19f63d0c908431a1fb Mon Sep 17 00:00:00 2001 From: Anthony Merlino Date: Wed, 12 Jul 2017 14:37:17 -0400 Subject: [PATCH 40/54] drivers/mrf24j40: Adds header guards to mrf24j40_reg.h --- drivers/wireless/ieee802154/mrf24j40/mrf24j40_reg.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/wireless/ieee802154/mrf24j40/mrf24j40_reg.h b/drivers/wireless/ieee802154/mrf24j40/mrf24j40_reg.h index 4d45545b27..1ae1d5b159 100644 --- a/drivers/wireless/ieee802154/mrf24j40/mrf24j40_reg.h +++ b/drivers/wireless/ieee802154/mrf24j40/mrf24j40_reg.h @@ -35,6 +35,9 @@ * ****************************************************************************/ +#ifndef __DRIVERS_WIRELESS_IEEE802154_MRF24J40_REG_H +#define __DRIVERS_WIRELESS_IEEE802154_MRF24J40_REG_H + /* MRF24J40 Registers *******************************************************/ #define MRF24J40_RXMCR 0x00 @@ -284,3 +287,5 @@ #define MRF24J40_RXFLUSH_SHIFT_CMDONLY 3 #define MRF24J40_RXFLUSH_SHIFT_WAKEPAD 5 #define MRF24J40_RXFLUSH_SHIFT_WAKEPOL 6 + +#endif /* __DRIVERS_WIRELESS_IEEE802154_MRF24J40_REG_H */ From 95e797fceb3836ec03204c5766a0dcff6cb274cb Mon Sep 17 00:00:00 2001 From: Anthony Merlino Date: Thu, 13 Jul 2017 03:17:05 -0400 Subject: [PATCH 41/54] ieee802154: Fixes setting devmode logic --- wireless/ieee802154/mac802154.c | 1 - wireless/ieee802154/mac802154_internal.h | 2 +- wireless/ieee802154/mac802154_start.c | 4 ++-- 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/wireless/ieee802154/mac802154.c b/wireless/ieee802154/mac802154.c index d8a4fddc23..5c1e91b2e7 100644 --- a/wireless/ieee802154/mac802154.c +++ b/wireless/ieee802154/mac802154.c @@ -1545,7 +1545,6 @@ static void mac802154_sfevent(FAR const struct ieee802154_radiocb_s *radiocb, break; } - mac802154_unlock(priv) } diff --git a/wireless/ieee802154/mac802154_internal.h b/wireless/ieee802154/mac802154_internal.h index 8051763598..f9cc4f7b89 100644 --- a/wireless/ieee802154/mac802154_internal.h +++ b/wireless/ieee802154/mac802154_internal.h @@ -824,7 +824,7 @@ static inline void mac802154_setdevmode(FAR struct ieee802154_privmac_s *priv, enum ieee802154_devmode_e mode) { priv->devmode = mode; - priv->radio->setattr(priv->radio, IEEE802154_ATTR_MAC_RX_ON_WHEN_IDLE, + priv->radio->setattr(priv->radio, IEEE802154_ATTR_MAC_DEVMODE, (FAR const union ieee802154_attr_u *)&mode); } diff --git a/wireless/ieee802154/mac802154_start.c b/wireless/ieee802154/mac802154_start.c index e5684a39a3..c19026d589 100644 --- a/wireless/ieee802154/mac802154_start.c +++ b/wireless/ieee802154/mac802154_start.c @@ -147,11 +147,11 @@ int mac802154_req_start(MACHANDLE mac, FAR struct ieee802154_start_req_s *req) if (req->pancoord) { - priv->devmode = IEEE802154_DEVMODE_PANCOORD; + mac802154_setdevmode(priv, IEEE802154_DEVMODE_PANCOORD); } else { - priv->devmode = IEEE802154_DEVMODE_COORD; + mac802154_setdevmode(priv, IEEE802154_DEVMODE_COORD); } priv->sfspec.pancoord = req->pancoord; From 350776eca37fafe152c313ceb224d79b228a74f1 Mon Sep 17 00:00:00 2001 From: Anthony Merlino Date: Thu, 13 Jul 2017 03:18:22 -0400 Subject: [PATCH 42/54] drivers/mrf24j40: Fixes issues with sleeping for beacon enabled networking --- .../wireless/ieee802154/mrf24j40/mrf24j40.h | 27 ++-- .../ieee802154/mrf24j40/mrf24j40_interrupt.c | 17 ++- .../ieee802154/mrf24j40/mrf24j40_radif.c | 131 ++++++++++++------ .../ieee802154/mrf24j40/mrf24j40_reg.h | 11 ++ 4 files changed, 115 insertions(+), 71 deletions(-) diff --git a/drivers/wireless/ieee802154/mrf24j40/mrf24j40.h b/drivers/wireless/ieee802154/mrf24j40/mrf24j40.h index bbfca37f4f..b07714c429 100644 --- a/drivers/wireless/ieee802154/mrf24j40/mrf24j40.h +++ b/drivers/wireless/ieee802154/mrf24j40/mrf24j40.h @@ -91,21 +91,11 @@ /* Clock configuration macros */ -#define MRF24J40_SLPCLKPER_100KHZ ((1000 * 1000 * 1000)/100000) /* 10ns */ -#define MRF24J40_SLPCLKPER_32KHZ ((1000 * 1000 * 1000)/32000) /* 31.25ns */ - #define MRF24J40_BEACONINTERVAL_NSEC(beaconorder) \ - (IEEE802154_BASE_SUPERFRAME_DURATION * (1 << beaconorder) * (16 *1000)) + (IEEE802154_BASE_SUPERFRAME_DURATION * (1 << beaconorder) * (16 * 1000)) -/* For now I am just setting the REMCNT to the maximum while staying in multiples - * of 10000 (100khz period) */ - -#define MRF24J40_REMCNT 60000 -#define MRF24J40_REMCNT_NSEC (MRF24J40_REMCNT * 50) - -#define MRF24J40_MAINCNT(bo, clkper) \ - ((MRF24J40_BEACONINTERVAL_NSEC(bo) - MRF24J40_REMCNT_NSEC) / \ - clkper) +#define MRF24J40_SUPERFRAMEDURATION_NSEC(sforder) \ + (IEEE802154_BASE_SUPERFRAME_DURATION * (1 << sforder) * (16 * 1000)) /* Configuration *************************************************************/ @@ -151,12 +141,13 @@ struct mrf24j40_radio_s struct ieee802154_addr_s addr; - uint8_t chan; /* 11 to 26 for the 2.4 GHz band */ - uint8_t devmode; /* device mode: device, coord, pancoord */ - uint8_t paenabled; /* enable usage of PA */ - uint8_t rxmode; /* Reception mode: Main, no CRC, promiscuous */ - int32_t txpower; /* TX power in mBm = dBm/100 */ + uint8_t chan; /* 11 to 26 for the 2.4 GHz band */ + uint8_t devmode; /* device mode: device, coord, pancoord */ + uint8_t paenabled; /* enable usage of PA */ + uint8_t rxmode; /* Reception mode: Main, no CRC, promiscuous */ + int32_t txpower; /* TX power in mBm = dBm/100 */ struct ieee802154_cca_s cca; /* Clear channel assessement method */ + uint32_t slpclkper; /* Sleep clock period (nanoseconds) */ /* MAC PIB attributes */ diff --git a/drivers/wireless/ieee802154/mrf24j40/mrf24j40_interrupt.c b/drivers/wireless/ieee802154/mrf24j40/mrf24j40_interrupt.c index 673aba7c34..9961212b9f 100644 --- a/drivers/wireless/ieee802154/mrf24j40/mrf24j40_interrupt.c +++ b/drivers/wireless/ieee802154/mrf24j40/mrf24j40_interrupt.c @@ -378,14 +378,17 @@ void mrf24j40_irqworker(FAR void *arg) wlinfo("Wake Interrupt\n"); #endif - /* This is right before the beacon, we set the bsn here, since the MAC - * uses the SLPIF (end of active portion of superframe). to make any - * changes to the beacon. This assumes that any changes to the beacon - * be in by the time that this interrupt fires. - */ + if (dev->devmode != IEEE802154_DEVMODE_ENDPOINT) + { + /* This is right before the beacon, we set the bsn here, since the MAC + * uses the SLPIF (end of active portion of superframe). to make any + * changes to the beacon. This assumes that any changes to the beacon + * be in by the time that this interrupt fires. + */ - mrf24j40_setreg(dev->spi, MRF24J40_BEACON_FIFO + 4, dev->bsn++); - mrf24j40_beacon_trigger(dev); + mrf24j40_setreg(dev->spi, MRF24J40_BEACON_FIFO + 4, dev->bsn++); + mrf24j40_beacon_trigger(dev); + } } /* Unlock the radio device */ diff --git a/drivers/wireless/ieee802154/mrf24j40/mrf24j40_radif.c b/drivers/wireless/ieee802154/mrf24j40/mrf24j40_radif.c index b4faa5c153..847ebb5fd4 100644 --- a/drivers/wireless/ieee802154/mrf24j40/mrf24j40_radif.c +++ b/drivers/wireless/ieee802154/mrf24j40/mrf24j40_radif.c @@ -73,6 +73,7 @@ static void mrf24j40_mactimer(FAR struct mrf24j40_radio_s *dev, int numsymbols); static void mrf24j40_setorder(FAR struct mrf24j40_radio_s *dev, uint8_t bo, uint8_t so); +static void mrf24j40_slpclkcal(FAR struct mrf24j40_radio_s *dev); /**************************************************************************** * Private Data @@ -129,67 +130,89 @@ static void mrf24j40_mactimer(FAR struct mrf24j40_radio_s *dev, int numsymbols) static void mrf24j40_setorder(FAR struct mrf24j40_radio_s *dev, uint8_t bo, uint8_t so) { - uint32_t maincnt = 0; - uint32_t slpcal = 0; + uint32_t bi = MRF24J40_BEACONINTERVAL_NSEC(bo); + uint32_t sfduration = MRF24J40_SUPERFRAMEDURATION_NSEC(so); + uint32_t maincnt; + uint32_t remcnt; wlinfo("bo: %d, so: %d\n", bo, so); - /* Calibrate the Sleep Clock (SLPCLK) frequency. Refer to Section 3.15.1.2 - * “Sleep Clock Calibration”. - */ + if (bo < 15) + { + if (dev->devmode == IEEE802154_DEVMODE_ENDPOINT) + { + maincnt = (bi - sfduration) / dev->slpclkper; + remcnt = ((bi - sfduration) - (maincnt * dev->slpclkper)) / 50; + } + else + { + maincnt = bi / dev->slpclkper; + remcnt = bi - (maincnt * dev->slpclkper) / 50; + } - /* If the Sleep Clock Selection, SLPCLKSEL (0x207<7:6), is the internal - * oscillator (100 kHz), set SLPCLKDIV to a minimum value of 0x01. - */ + wlinfo("MAINCNT: %lu, REMCNT: %lu\n", maincnt, remcnt); - mrf24j40_setreg(dev->spi, MRF24J40_SLPCON1, 0x01); + /* Program the Main Counter, MAINCNT (0x229<1:0>, 0x228, 0x227, 0x226), and + * Remain Counter, REMCNT (0x225, 0x224), according to BO and SO values. Refer + * to Section 3.15.1.3 “Sleep Mode * Counters” + */ + + mrf24j40_setreg(dev->spi, MRF24J40_REMCNTL, (remcnt & 0xFF)); + mrf24j40_setreg(dev->spi, MRF24J40_REMCNTH, ((remcnt >> 8) & 0xFF)); + + mrf24j40_setreg(dev->spi, MRF24J40_MAINCNT0, (maincnt & 0xFF)); + mrf24j40_setreg(dev->spi, MRF24J40_MAINCNT1, ((maincnt >> 8) & 0xFF)); + mrf24j40_setreg(dev->spi, MRF24J40_MAINCNT2, ((maincnt >> 16) & 0xFF)); + mrf24j40_setreg(dev->spi, MRF24J40_MAINCNT3, ((maincnt >> 24) & 0x03)); + } + + /* Configure the BO (ORDER 0x10<7:4>) and SO (ORDER 0x10<3:0>) values. + * After configuring BO and SO, the beacon frame will be sent immediately. + */ + + mrf24j40_setreg(dev->spi, MRF24J40_ORDER, ((bo << 4) & 0xF0) | (so & 0x0F)); +} + +static void mrf24j40_slpclkcal(FAR struct mrf24j40_radio_s *dev) +{ + uint8_t reg; /* Select the source of SLPCLK (internal 100kHz) */ mrf24j40_setreg(dev->spi, MRF24J40_RFCON7, MRF24J40_RFCON7_SEL_100KHZ); - /* Begin calibration by setting the SLPCALEN bit (SLPCAL2 0x20B<4>) to - * ‘1’. Sixteen samples of the SLPCLK are counted and stored in the - * SLPCAL register. No need to mask, this is the only writable bit - */ + /* If the Sleep Clock Selection, SLPCLKSEL (0x207<7:6), is the internal + * oscillator (100 kHz), set SLPCLKDIV to a minimum value of 0x01. + */ + + mrf24j40_setreg(dev->spi, MRF24J40_SLPCON1, + 0x01 | MRF24J40_SLPCON1_CLKOUT_DISABLED); + + /* Begin calibration by setting the SLPCALEN bit (SLPCAL2 0x20B<4>) to + * ‘1’. Sixteen samples of the SLPCLK are counted and stored in the + * SLPCAL register. No need to mask, this is the only writable bit + */ mrf24j40_setreg(dev->spi, MRF24J40_SLPCAL2, MRF24J40_SLPCAL2_SLPCALEN); /* Calibration is complete when the SLPCALRDY bit (SLPCAL2 0x20B<7>) is - * set to ‘1’. - */ + * set to ‘1’. + */ while (!(mrf24j40_getreg(dev->spi, MRF24J40_SLPCAL2) & - MRF24J40_SLPCAL2_SLPCALRDY)) + MRF24J40_SLPCAL2_SLPCALRDY)) { up_udelay(1); } - slpcal = mrf24j40_getreg(dev->spi, MRF24J40_SLPCAL0); - slpcal |= (mrf24j40_getreg(dev->spi, MRF24J40_SLPCAL1) << 8); - slpcal |= ((mrf24j40_getreg(dev->spi, MRF24J40_SLPCAL2) << 16) & 0x0F); + reg = mrf24j40_getreg(dev->spi, MRF24J40_SLPCAL0); + dev->slpclkper = reg; + reg = mrf24j40_getreg(dev->spi, MRF24J40_SLPCAL1); + dev->slpclkper |= (reg << 8); + reg = mrf24j40_getreg(dev->spi, MRF24J40_SLPCAL2) & 0x0F; + dev->slpclkper |= (reg << 16); - /* Program the Beacon Interval into the Main Counter, MAINCNT (0x229<1:0>, - * 0x228, 0x227, 0x226), and Remain Counter, REMCNT (0x225, 0x224), - * according to BO and SO values. Refer to Section 3.15.1.3 “Sleep Mode - * Counters” - */ - - mrf24j40_setreg(dev->spi, MRF24J40_REMCNTL, (MRF24J40_REMCNT & 0xFF)); - mrf24j40_setreg(dev->spi, MRF24J40_REMCNTH, ((MRF24J40_REMCNT >> 8) & 0xFF)); - - maincnt = MRF24J40_MAINCNT(bo, (slpcal * 50 / 16)); - - mrf24j40_setreg(dev->spi, MRF24J40_MAINCNT0, (maincnt & 0xFF)); - mrf24j40_setreg(dev->spi, MRF24J40_MAINCNT1, ((maincnt >> 8) & 0xFF)); - mrf24j40_setreg(dev->spi, MRF24J40_MAINCNT2, ((maincnt >> 16) & 0xFF)); - mrf24j40_setreg(dev->spi, MRF24J40_MAINCNT3, ((maincnt >> 24) & 0x03)); - - /* Configure the BO (ORDER 0x10<7:4>) and SO (ORDER 0x10<3:0>) values. - * After configuring BO and SO, the beacon frame will be sent immediately. - */ - - mrf24j40_setreg(dev->spi, MRF24J40_ORDER, ((bo << 4) & 0xF0) | (so & 0x0F)); + dev->slpclkper = (dev->slpclkper * 50 / 16); } /**************************************************************************** @@ -418,12 +441,13 @@ int mrf24j40_reset(FAR struct ieee802154_radio_s *radio) mrf24j40_setreg(dev->spi, MRF24J40_RFCON6 , 0x90); /* 10010000 TX filter enable, fast 20M recovery, No bat monitor*/ mrf24j40_setreg(dev->spi, MRF24J40_RFCON7 , 0x80); /* 10000000 Sleep clock on internal 100 kHz */ mrf24j40_setreg(dev->spi, MRF24J40_RFCON8 , 0x10); /* 00010000 VCO control bit, as recommended */ - mrf24j40_setreg(dev->spi, MRF24J40_SLPCON1, 0x01); /* 00000001 no CLKOUT, default divisor */ mrf24j40_setreg(dev->spi, MRF24J40_BBREG6 , 0x40); /* 01000000 Append RSSI to rx packets */ - /* Set this in reset since it can exist for all device modes. See pg 101 */ + /* Calibrate the Sleep Clock (SLPCLK) frequency. Refer to Section 3.15.1.2 + * “Sleep Clock Calibration”. + */ - mrf24j40_setreg(dev->spi, MRF24J40_FRMOFFSET, 0x15); + mrf24j40_slpclkcal(dev); /* For now, we want to always just have the frame pending bit set when * acknowledging a Data Request command. The standard says that the coordinator @@ -448,7 +472,11 @@ int mrf24j40_reset(FAR struct ieee802154_radio_s *radio) * (20 MHz) start-up timer value. */ - mrf24j40_setreg(dev->spi, MRF24J40_SLPACK, 0x5F); + mrf24j40_setreg(dev->spi, MRF24J40_SLPACK, (0x0C8 & MRF24J40_SLPACK_WAKECNT0_6)); + reg = mrf24j40_getreg(dev->spi, MRF24J40_RFCTL); + reg &= ~MRF24J40_RFCTRL_WAKECNT7_8; + reg |= ((0x0C8 >> 7) & 0x03) << 3; + mrf24j40_setreg(dev->spi, MRF24J40_RFCTL, reg); /* Enable the SLPIF and WAKEIF flags */ @@ -456,6 +484,8 @@ int mrf24j40_reset(FAR struct ieee802154_radio_s *radio) reg &= ~(MRF24J40_INTCON_SLPIE | MRF24J40_INTCON_WAKEIE); mrf24j40_setreg(dev->spi, MRF24J40_INTCON, reg); + mrf24j40_setorder(dev, 15, 15); + dev->rxenabled = false; mrf24j40_setchannel(dev, 11); @@ -483,8 +513,8 @@ int mrf24j40_reset(FAR struct ieee802154_radio_s *radio) } int mrf24j40_getattr(FAR struct ieee802154_radio_s *radio, - enum ieee802154_attr_e attr, - FAR union ieee802154_attr_u *attrval) + enum ieee802154_attr_e attr, + FAR union ieee802154_attr_u *attrval) { FAR struct mrf24j40_radio_s *dev = (FAR struct mrf24j40_radio_s *)radio; int ret; @@ -688,6 +718,15 @@ int mrf24j40_sfupdate(FAR struct ieee802154_radio_s *radio, if (sfspec->beaconorder < 15) { reg |= MRF24J40_TXMCR_SLOTTED; + + if (dev->devmode == IEEE802154_DEVMODE_ENDPOINT) + { + mrf24j40_setreg(dev->spi, MRF24J40_FRMOFFSET, 0x15); + } + else + { + mrf24j40_setreg(dev->spi, MRF24J40_FRMOFFSET, 0x00); + } } else { diff --git a/drivers/wireless/ieee802154/mrf24j40/mrf24j40_reg.h b/drivers/wireless/ieee802154/mrf24j40/mrf24j40_reg.h index 1ae1d5b159..a54a006f7b 100644 --- a/drivers/wireless/ieee802154/mrf24j40/mrf24j40_reg.h +++ b/drivers/wireless/ieee802154/mrf24j40/mrf24j40_reg.h @@ -272,6 +272,13 @@ #define MRF24J40_SLPACK_WAKECNT0_6 0x7F #define MRF24J40_SLPACK_SLPACK 0x80 +/* RFCTL bits */ + +#define MRF24J40_RFCTRL_RFRXMODE 0x01 +#define MRF24J40_RFCTRL_RFTXMODE 0x02 +#define MRF24J40_RFCTRL_RFRST 0x03 +#define MRF24J40_RFCTRL_WAKECNT7_8 0x18 + /* RXFLUSH bits */ #define MRF24J40_RXFLUSH_RXFLUSH 0x01 @@ -288,4 +295,8 @@ #define MRF24J40_RXFLUSH_SHIFT_WAKEPAD 5 #define MRF24J40_RXFLUSH_SHIFT_WAKEPOL 6 +/* SLPCON1 bits */ + +#define MRF24J40_SLPCON1_CLKOUT_DISABLED 0x20 + #endif /* __DRIVERS_WIRELESS_IEEE802154_MRF24J40_REG_H */ From bd821dafcb6934f2e0dba4c7236c0a00ee396a1a Mon Sep 17 00:00:00 2001 From: Anthony Merlino Date: Thu, 13 Jul 2017 03:23:19 -0400 Subject: [PATCH 43/54] drivers/mrf24j40: Fixes line endings in file --- .../ieee802154/mrf24j40/mrf24j40_regops.c | 382 +++++++++--------- 1 file changed, 191 insertions(+), 191 deletions(-) diff --git a/drivers/wireless/ieee802154/mrf24j40/mrf24j40_regops.c b/drivers/wireless/ieee802154/mrf24j40/mrf24j40_regops.c index 2558bde084..f6778e9308 100644 --- a/drivers/wireless/ieee802154/mrf24j40/mrf24j40_regops.c +++ b/drivers/wireless/ieee802154/mrf24j40/mrf24j40_regops.c @@ -1,191 +1,191 @@ -/**************************************************************************** - * drivers/wireless/ieee802154/mrf24j40/mrf24j40_regops.c - * - * Copyright (C) 2015-2016 Sebastien Lorquet. All rights reserved. - * Copyright (C) 2017 Verge Inc. All rights reserved. - * Author: Sebastien Lorquet - * Author: Anthony Merlino - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * 3. Neither the name NuttX nor the names of its contributors may be - * used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS - * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED - * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - ****************************************************************************/ - -/**************************************************************************** - * Included Files - ****************************************************************************/ - -#include - -#include -#include -#include - -#include "mrf24j40.h" -#include "mrf24j40_regops.h" - -/**************************************************************************** - * Internal Driver Functions - ****************************************************************************/ - -/**************************************************************************** - * Name: mrf24j40_setreg - * - * Description: - * Define the value of an MRF24J40 device register - * - ****************************************************************************/ - -void mrf24j40_setreg(FAR struct spi_dev_s *spi, uint32_t addr, uint8_t val) -{ - uint8_t buf[3]; - int len; - - if (!(addr&0x80000000)) - { - addr &= 0x3F; /* 6-bit address */ - addr <<= 1; - addr |= 0x01; /* writing */ - buf[0] = addr; - len = 1; - } - else - { - addr &= 0x3FF; /* 10-bit address */ - addr <<= 5; - addr |= 0x8010; /* writing long */ - buf[0] = (addr >> 8); - buf[1] = (addr & 0xFF); - len = 2; - } - - buf[len++] = val; - - mrf24j40_spi_lock(spi); - SPI_SELECT(spi, SPIDEV_IEEE802154(0), true); - SPI_SNDBLOCK(spi, buf, len); - SPI_SELECT(spi, SPIDEV_IEEE802154(0), false); - mrf24j40_spi_unlock(spi); -} - -/**************************************************************************** - * Name: mrf24j40_getreg - * - * Description: - * Return the value of an MRF24J40 device register* - * - ****************************************************************************/ - -uint8_t mrf24j40_getreg(FAR struct spi_dev_s *spi, uint32_t addr) -{ - uint8_t buf[3]; - uint8_t rx[3]; - int len; - - if (!(addr&0x80000000)) - { - /* 6-bit address */ - - addr &= 0x3F; - addr <<= 1; - buf[0] = addr; - len = 1; - } - else - { - /* 10-bit address */ - - addr &= 0x3FF; - addr <<= 5; - addr |= 0x8000; - buf[0] = (addr >> 8); - buf[1] = (addr & 0xFF); - len = 2; - } - - buf[len++] = 0xFF; /* dummy */ - - mrf24j40_spi_lock (spi); - SPI_SELECT (spi, SPIDEV_IEEE802154(0), true); - SPI_EXCHANGE (spi, buf, rx, len); - SPI_SELECT (spi, SPIDEV_IEEE802154(0), false); - mrf24j40_spi_unlock(spi); - - /* wlinfo("r[%04X]=%02X\n", addr, rx[len - 1]); */ - return rx[len - 1]; -} - -/**************************************************************************** - * Name: mrf24j40_regdump - * - * Description: - * Display the value of all registers. - * - ****************************************************************************/ - -int mrf24j40_regdump(FAR struct mrf24j40_radio_s *dev) -{ - uint32_t i; - char buf[4+16*3+2+1]; - int len = 0; - - wlinfo("Short regs:\n"); - - for (i = 0; i < 0x40; i++) - { - if ((i & 15) == 0) - { - len=sprintf(buf, "%02x: ",i&0xFF); - } - - len += sprintf(buf+len, "%02x ", mrf24j40_getreg(dev->spi, i)); - if ((i & 15) == 15) - { - sprintf(buf+len, "\n"); - wlinfo("%s", buf); - } - } - - wlinfo("Long regs:\n"); - - for (i = 0x80000200; i < 0x80000250; i++) - { - if ((i & 15) == 0) - { - len=sprintf(buf, "%02x: ",i&0xFF); - } - - len += sprintf(buf+len, "%02x ", mrf24j40_getreg(dev->spi, i)); - if ((i & 15) == 15) - { - sprintf(buf+len, "\n"); - wlinfo("%s", buf); - } - } - - return 0; -} +/**************************************************************************** + * drivers/wireless/ieee802154/mrf24j40/mrf24j40_regops.c + * + * Copyright (C) 2015-2016 Sebastien Lorquet. All rights reserved. + * Copyright (C) 2017 Verge Inc. All rights reserved. + * Author: Sebastien Lorquet + * Author: Anthony Merlino + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include +#include + +#include "mrf24j40.h" +#include "mrf24j40_regops.h" + +/**************************************************************************** + * Internal Driver Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: mrf24j40_setreg + * + * Description: + * Define the value of an MRF24J40 device register + * + ****************************************************************************/ + +void mrf24j40_setreg(FAR struct spi_dev_s *spi, uint32_t addr, uint8_t val) +{ + uint8_t buf[3]; + int len; + + if (!(addr&0x80000000)) + { + addr &= 0x3F; /* 6-bit address */ + addr <<= 1; + addr |= 0x01; /* writing */ + buf[0] = addr; + len = 1; + } + else + { + addr &= 0x3FF; /* 10-bit address */ + addr <<= 5; + addr |= 0x8010; /* writing long */ + buf[0] = (addr >> 8); + buf[1] = (addr & 0xFF); + len = 2; + } + + buf[len++] = val; + + mrf24j40_spi_lock(spi); + SPI_SELECT(spi, SPIDEV_IEEE802154(0), true); + SPI_SNDBLOCK(spi, buf, len); + SPI_SELECT(spi, SPIDEV_IEEE802154(0), false); + mrf24j40_spi_unlock(spi); +} + +/**************************************************************************** + * Name: mrf24j40_getreg + * + * Description: + * Return the value of an MRF24J40 device register* + * + ****************************************************************************/ + +uint8_t mrf24j40_getreg(FAR struct spi_dev_s *spi, uint32_t addr) +{ + uint8_t buf[3]; + uint8_t rx[3]; + int len; + + if (!(addr&0x80000000)) + { + /* 6-bit address */ + + addr &= 0x3F; + addr <<= 1; + buf[0] = addr; + len = 1; + } + else + { + /* 10-bit address */ + + addr &= 0x3FF; + addr <<= 5; + addr |= 0x8000; + buf[0] = (addr >> 8); + buf[1] = (addr & 0xFF); + len = 2; + } + + buf[len++] = 0xFF; /* dummy */ + + mrf24j40_spi_lock (spi); + SPI_SELECT (spi, SPIDEV_IEEE802154(0), true); + SPI_EXCHANGE (spi, buf, rx, len); + SPI_SELECT (spi, SPIDEV_IEEE802154(0), false); + mrf24j40_spi_unlock(spi); + + /* wlinfo("r[%04X]=%02X\n", addr, rx[len - 1]); */ + return rx[len - 1]; +} + +/**************************************************************************** + * Name: mrf24j40_regdump + * + * Description: + * Display the value of all registers. + * + ****************************************************************************/ + +int mrf24j40_regdump(FAR struct mrf24j40_radio_s *dev) +{ + uint32_t i; + char buf[4+16*3+2+1]; + int len = 0; + + wlinfo("Short regs:\n"); + + for (i = 0; i < 0x40; i++) + { + if ((i & 15) == 0) + { + len=sprintf(buf, "%02x: ",i&0xFF); + } + + len += sprintf(buf+len, "%02x ", mrf24j40_getreg(dev->spi, i)); + if ((i & 15) == 15) + { + sprintf(buf+len, "\n"); + wlinfo("%s", buf); + } + } + + wlinfo("Long regs:\n"); + + for (i = 0x80000200; i < 0x80000250; i++) + { + if ((i & 15) == 0) + { + len=sprintf(buf, "%02x: ",i&0xFF); + } + + len += sprintf(buf+len, "%02x ", mrf24j40_getreg(dev->spi, i)); + if ((i & 15) == 15) + { + sprintf(buf+len, "\n"); + wlinfo("%s", buf); + } + } + + return 0; +} From 86b690a285d6bf92460aa3cc7b1eb01a27e4e1a4 Mon Sep 17 00:00:00 2001 From: Anthony Merlino Date: Thu, 13 Jul 2017 17:56:31 -0400 Subject: [PATCH 44/54] ieee802154: Fixes issue with association on beacon-enabled networking --- wireless/ieee802154/mac802154.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/wireless/ieee802154/mac802154.c b/wireless/ieee802154/mac802154.c index 5c1e91b2e7..5753f167e3 100644 --- a/wireless/ieee802154/mac802154.c +++ b/wireless/ieee802154/mac802154.c @@ -1850,6 +1850,10 @@ static void mac802154_rxbeaconframe(FAR struct ieee802154_privmac_s *priv, { priv->curr_cmd = IEEE802154_CMD_DATA_REQ; } + else if (priv->curr_op == MAC802154_OP_ASSOC) + { + priv->curr_cmd = IEEE802154_CMD_DATA_REQ; + } else if (priv->curr_op == MAC802154_OP_NONE) { DEBUGASSERT(priv->opsem.semcount == 1); From acc1ecd9a93c45222206f173b98f6290b722da14 Mon Sep 17 00:00:00 2001 From: Anthony Merlino Date: Thu, 13 Jul 2017 17:56:59 -0400 Subject: [PATCH 45/54] drivers/mrf24j40: Fixes math error for calculating sleep count values --- drivers/wireless/ieee802154/mrf24j40/mrf24j40_radif.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/wireless/ieee802154/mrf24j40/mrf24j40_radif.c b/drivers/wireless/ieee802154/mrf24j40/mrf24j40_radif.c index 847ebb5fd4..41b2350d1d 100644 --- a/drivers/wireless/ieee802154/mrf24j40/mrf24j40_radif.c +++ b/drivers/wireless/ieee802154/mrf24j40/mrf24j40_radif.c @@ -147,7 +147,7 @@ static void mrf24j40_setorder(FAR struct mrf24j40_radio_s *dev, uint8_t bo, else { maincnt = bi / dev->slpclkper; - remcnt = bi - (maincnt * dev->slpclkper) / 50; + remcnt = (bi - (maincnt * dev->slpclkper)) / 50; } wlinfo("MAINCNT: %lu, REMCNT: %lu\n", maincnt, remcnt); From 8610723ee6652f004621092b3890e20131eb858c Mon Sep 17 00:00:00 2001 From: Anthony Merlino Date: Thu, 13 Jul 2017 17:57:33 -0400 Subject: [PATCH 46/54] ieee802154: Adds some wlinfo logs for debugging --- drivers/wireless/ieee802154/mrf24j40/mrf24j40_interrupt.c | 1 + drivers/wireless/ieee802154/mrf24j40/mrf24j40_radif.c | 2 ++ wireless/ieee802154/mac802154.c | 2 +- 3 files changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/wireless/ieee802154/mrf24j40/mrf24j40_interrupt.c b/drivers/wireless/ieee802154/mrf24j40/mrf24j40_interrupt.c index 9961212b9f..b3e1c16679 100644 --- a/drivers/wireless/ieee802154/mrf24j40/mrf24j40_interrupt.c +++ b/drivers/wireless/ieee802154/mrf24j40/mrf24j40_interrupt.c @@ -388,6 +388,7 @@ void mrf24j40_irqworker(FAR void *arg) mrf24j40_setreg(dev->spi, MRF24J40_BEACON_FIFO + 4, dev->bsn++); mrf24j40_beacon_trigger(dev); + wlinfo("Beacon triggered. BSN: 0x%02X\n", dev->bsn-1); } } diff --git a/drivers/wireless/ieee802154/mrf24j40/mrf24j40_radif.c b/drivers/wireless/ieee802154/mrf24j40/mrf24j40_radif.c index 41b2350d1d..a6dc0c6e0f 100644 --- a/drivers/wireless/ieee802154/mrf24j40/mrf24j40_radif.c +++ b/drivers/wireless/ieee802154/mrf24j40/mrf24j40_radif.c @@ -141,11 +141,13 @@ static void mrf24j40_setorder(FAR struct mrf24j40_radio_s *dev, uint8_t bo, { if (dev->devmode == IEEE802154_DEVMODE_ENDPOINT) { + wlinfo("Configuring sleep for inactive period\n"); maincnt = (bi - sfduration) / dev->slpclkper; remcnt = ((bi - sfduration) - (maincnt * dev->slpclkper)) / 50; } else { + wlinfo("Configuring sleep for beacon interval\n"); maincnt = bi / dev->slpclkper; remcnt = (bi - (maincnt * dev->slpclkper)) / 50; } diff --git a/wireless/ieee802154/mac802154.c b/wireless/ieee802154/mac802154.c index 5753f167e3..6c93de3f15 100644 --- a/wireless/ieee802154/mac802154.c +++ b/wireless/ieee802154/mac802154.c @@ -1110,7 +1110,7 @@ static void mac802154_rxframe_worker(FAR void *arg) case IEEE802154_FRAME_BEACON: { - wlinfo("Beacon frame received\n"); + wlinfo("Beacon frame received. BSN: 0x%02X\n", ind->dsn); mac802154_rxbeaconframe(priv, ind); ieee802154_ind_free(ind); } From aaa1dd2bbebac3f89340142b796a0d4c3c7f93b9 Mon Sep 17 00:00:00 2001 From: Anthony Merlino Date: Sun, 16 Jul 2017 23:50:27 -0400 Subject: [PATCH 47/54] ieee802154: Renames ack_wait_dur to ack_waitdur and removes it from private mac struct --- include/nuttx/wireless/ieee802154/ieee802154_mac.h | 2 +- wireless/ieee802154/mac802154_internal.h | 9 --------- 2 files changed, 1 insertion(+), 10 deletions(-) diff --git a/include/nuttx/wireless/ieee802154/ieee802154_mac.h b/include/nuttx/wireless/ieee802154/ieee802154_mac.h index 1526ad3f0f..f30ca769cc 100644 --- a/include/nuttx/wireless/ieee802154/ieee802154_mac.h +++ b/include/nuttx/wireless/ieee802154/ieee802154_mac.h @@ -632,7 +632,7 @@ union ieee802154_macattr_u bool sec_enabled; bool timestamp_support; - uint32_t ack_wait_dur; + uint32_t ack_waitdur; uint8_t batt_life_ext_periods; uint8_t max_csma_backoffs : 3; uint8_t max_be : 4; diff --git a/wireless/ieee802154/mac802154_internal.h b/wireless/ieee802154/mac802154_internal.h index f9cc4f7b89..58301bca5a 100644 --- a/wireless/ieee802154/mac802154_internal.h +++ b/wireless/ieee802154/mac802154_internal.h @@ -256,15 +256,6 @@ struct ieee802154_privmac_s /****************** Uncategorized MAC PIB attributes ***********************/ - /* The maximum number of symbols to wait for an acknowledgement frame to - * arrive following a transmitted data frame. [1] pg. 126 - * - * NOTE: This may be able to be a 16-bit or even an 8-bit number. I wasn't - * sure at the time what the range of reasonable values was. - */ - - uint32_t ack_waitdur; - /* The maximum time to wait either for a frame intended as a response to a * data request frame or for a broadcast frame following a beacon with the * Frame Pending field set to one. [1] pg. 127 From c13bd23ed99f03fad76891784f88adf469f4359a Mon Sep 17 00:00:00 2001 From: Anthony Merlino Date: Sun, 16 Jul 2017 23:50:45 -0400 Subject: [PATCH 48/54] drivers/mrf24j40: Trivial whitespace fix --- drivers/wireless/ieee802154/mrf24j40/mrf24j40.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/wireless/ieee802154/mrf24j40/mrf24j40.c b/drivers/wireless/ieee802154/mrf24j40/mrf24j40.c index 00ebe6cd99..2d1fc5ffe6 100644 --- a/drivers/wireless/ieee802154/mrf24j40/mrf24j40.c +++ b/drivers/wireless/ieee802154/mrf24j40/mrf24j40.c @@ -413,8 +413,6 @@ void mrf24j40_setup_fifo(FAR struct mrf24j40_radio_s *dev, FAR const uint8_t *bu } } - - /**************************************************************************** * Public Functions ****************************************************************************/ From 2f89ebeebd548bfc7772ea32156eedd802969467 Mon Sep 17 00:00:00 2001 From: Anthony Merlino Date: Sun, 16 Jul 2017 23:51:15 -0400 Subject: [PATCH 49/54] ieee802154: Adds retry count to tx descriptor --- .../nuttx/wireless/ieee802154/ieee802154_radio.h | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/include/nuttx/wireless/ieee802154/ieee802154_radio.h b/include/nuttx/wireless/ieee802154/ieee802154_radio.h index 7617d03685..d755118812 100644 --- a/include/nuttx/wireless/ieee802154/ieee802154_radio.h +++ b/include/nuttx/wireless/ieee802154/ieee802154_radio.h @@ -80,11 +80,15 @@ struct ieee802154_txdesc_s FAR struct ieee802154_data_conf_s *conf; - enum ieee802154_frametype_e frametype; /* Frame type. Used by MAC layer to - * control how tx done is handled */ - bool framepending; /* Did the ACK have the frame pending bit - * bit set */ - uint32_t purgetime; /* Time to purge transaction */ + /* Frame type. Used by MAC layer to control how tx done is handled */ + + enum ieee802154_frametype_e frametype; + + bool framepending; /* Did the ACK have the frame pending bit set */ + uint32_t purgetime; /* Time to purge transaction */ + uint8_t retrycount; /* Number of remaining retries. Set to macMaxFrameRetries + * when txdescriptor is allocated + */ /* TODO: Add slotting information for GTS transactions */ }; From 31581888462c19230159bac5f7bcc974d00a6369 Mon Sep 17 00:00:00 2001 From: Anthony Merlino Date: Mon, 17 Jul 2017 01:20:01 -0400 Subject: [PATCH 50/54] ieee802154: Renaming of some fields --- .../nuttx/wireless/ieee802154/ieee802154_mac.h | 18 +++++++++--------- net/sixlowpan/sixlowpan_framer.c | 10 +++++----- wireless/ieee802154/mac802154_data.c | 18 +++++++++--------- wireless/ieee802154/mac802154_get_mhrlen.c | 10 +++++----- 4 files changed, 28 insertions(+), 28 deletions(-) diff --git a/include/nuttx/wireless/ieee802154/ieee802154_mac.h b/include/nuttx/wireless/ieee802154/ieee802154_mac.h index f30ca769cc..24ed1388bd 100644 --- a/include/nuttx/wireless/ieee802154/ieee802154_mac.h +++ b/include/nuttx/wireless/ieee802154/ieee802154_mac.h @@ -697,17 +697,17 @@ enum ieee802154_scantype_e struct ieee802154_frame_meta_s { - enum ieee802154_addrmode_e srcaddr_mode; /* Source Address Mode */ - struct ieee802154_addr_s destaddr; /* Destination Address */ + enum ieee802154_addrmode_e srcmode; /* Source Address Mode */ + struct ieee802154_addr_s destaddr; /* Destination Address */ - uint8_t msdu_handle; /* Handle assoc. with MSDU */ + uint8_t handle; /* User-specified handle identifier */ struct { - uint8_t ack_tx : 1; /* Acknowledge TX? */ - uint8_t gts_tx : 1; /* 1=GTS used for TX, 0=CAP used for TX */ - uint8_t indirect_tx : 1; /* Should indirect transmission be used? */ - } msdu_flags; + uint8_t ackreq : 1; + uint8_t usegts : 1; + uint8_t indirect : 1; + } flags; #ifdef CONFIG_IEEE802154_SECURITY /* Security information if enabled */ @@ -718,7 +718,7 @@ struct ieee802154_frame_meta_s #ifdef CONFIG_IEEE802154_UWB /* The UWB Pulse Repetition Frequency to be used for the transmission */ - enum ieee802154_uwbprf_e uwb_prf; + enum ieee802154_uwbprf_e uwbprf; /* The UWB preamble symbol repititions * Should be one of: @@ -729,7 +729,7 @@ struct ieee802154_frame_meta_s /* The UWB Data Rate to be used for the transmission */ - enum ieee802154_uwb_datarate_e data_rate; + enum ieee802154_uwb_datarate_e datarate; #endif enum ieee802154_ranging_e ranging; diff --git a/net/sixlowpan/sixlowpan_framer.c b/net/sixlowpan/sixlowpan_framer.c index 91bff0cf76..4d0d51aeaf 100644 --- a/net/sixlowpan/sixlowpan_framer.c +++ b/net/sixlowpan/sixlowpan_framer.c @@ -163,9 +163,9 @@ int sixlowpan_meta_data(FAR struct ieee802154_driver_s *ieee, /* Source address mode */ - meta->srcaddr_mode = pktmeta->sextended != 0? - IEEE802154_ADDRMODE_EXTENDED : - IEEE802154_ADDRMODE_SHORT; + meta->srcmode = pktmeta->sextended != 0? + IEEE802154_ADDRMODE_EXTENDED : + IEEE802154_ADDRMODE_SHORT; /* Check for a broadcast destination address (all zero) */ @@ -184,7 +184,7 @@ int sixlowpan_meta_data(FAR struct ieee802154_driver_s *ieee, if (rcvrnull) { - meta->msdu_flags.ack_tx = TRUE; + meta->flags.ackreq = TRUE; } /* Destination address */ @@ -223,7 +223,7 @@ int sixlowpan_meta_data(FAR struct ieee802154_driver_s *ieee, * fragment of a disassembled packet. */ - meta->msdu_handle = ieee->i_msdu_handle++; + meta->handle = ieee->i_msdu_handle++; #ifdef CONFIG_IEEE802154_SECURITY # warning CONFIG_IEEE802154_SECURITY not yet supported diff --git a/wireless/ieee802154/mac802154_data.c b/wireless/ieee802154/mac802154_data.c index 066c4815b8..04bac7b7b0 100644 --- a/wireless/ieee802154/mac802154_data.c +++ b/wireless/ieee802154/mac802154_data.c @@ -118,7 +118,7 @@ int mac802154_req_data(MACHANDLE mac, * 5.1.6.4 [1] pg. 118. */ - *frame_ctrl |= (meta->msdu_flags.ack_tx << IEEE802154_FRAMECTRL_SHIFT_ACKREQ); + *frame_ctrl |= (meta->flags.ackreq << IEEE802154_FRAMECTRL_SHIFT_ACKREQ); /* If the destination address is present, copy the PAN ID and one of the * addresses, depending on mode, into the MHR. @@ -161,7 +161,7 @@ int mac802154_req_data(MACHANDLE mac, * [1] pg. 41. */ - if (meta->srcaddr_mode != IEEE802154_ADDRMODE_NONE && + if (meta->srcmode != IEEE802154_ADDRMODE_NONE && meta->destaddr.mode != IEEE802154_ADDRMODE_NONE) { /* If the PAN identifiers are identical, the PAN ID Compression field @@ -175,7 +175,7 @@ int mac802154_req_data(MACHANDLE mac, } } - if (meta->srcaddr_mode != IEEE802154_ADDRMODE_NONE) + if (meta->srcmode != IEEE802154_ADDRMODE_NONE) { /* If the destination address is not included, or if PAN ID Compression * is off, we need to include the Source PAN ID. @@ -188,12 +188,12 @@ int mac802154_req_data(MACHANDLE mac, mhr_len += 2; } - if (meta->srcaddr_mode == IEEE802154_ADDRMODE_SHORT) + if (meta->srcmode == IEEE802154_ADDRMODE_SHORT) { IEEE802154_SADDRCOPY(&frame->io_data[mhr_len], priv->addr.saddr); mhr_len += 2; } - else if (meta->srcaddr_mode == IEEE802154_ADDRMODE_EXTENDED) + else if (meta->srcmode == IEEE802154_ADDRMODE_EXTENDED) { IEEE802154_EADDRCOPY(&frame->io_data[mhr_len], priv->addr.eaddr); mhr_len += IEEE802154_EADDRSIZE; @@ -214,7 +214,7 @@ int mac802154_req_data(MACHANDLE mac, /* Set the source addr mode inside the frame control field */ - *frame_ctrl |= (meta->srcaddr_mode << IEEE802154_FRAMECTRL_SHIFT_SADDR); + *frame_ctrl |= (meta->srcmode << IEEE802154_FRAMECTRL_SHIFT_SADDR); /* Each time a data or a MAC command frame is generated, the MAC sublayer * shall copy the value of macDSN into the Sequence Number field of the MHR @@ -255,7 +255,7 @@ int mac802154_req_data(MACHANDLE mac, /* Then initialize the TX descriptor */ - txdesc->conf->handle = meta->msdu_handle; + txdesc->conf->handle = meta->handle; txdesc->frame = frame; txdesc->frametype = IEEE802154_FRAME_DATA; @@ -271,7 +271,7 @@ int mac802154_req_data(MACHANDLE mac, * [1] pg. 118. */ - if (meta->msdu_flags.gts_tx) + if (meta->flags.usegts) { /* TODO: Support GTS transmission. This should just change where we link * the transaction. Instead of going in the CSMA transaction list, it @@ -291,7 +291,7 @@ int mac802154_req_data(MACHANDLE mac, * described in 5.1.5 and 5.1.6.3. [1] */ - if (meta->msdu_flags.indirect_tx) + if (meta->flags.indirect) { /* If the TxOptions parameter specifies that an indirect transmission * is required and if the device receiving this primitive is not a diff --git a/wireless/ieee802154/mac802154_get_mhrlen.c b/wireless/ieee802154/mac802154_get_mhrlen.c index 3423e1169d..a710e33a82 100644 --- a/wireless/ieee802154/mac802154_get_mhrlen.c +++ b/wireless/ieee802154/mac802154_get_mhrlen.c @@ -76,14 +76,14 @@ int mac802154_get_mhrlen(MACHANDLE mac, * to NONE */ if (meta->destaddr.mode == IEEE802154_ADDRMODE_NONE && - meta->srcaddr_mode == IEEE802154_ADDRMODE_NONE) + meta->srcmode == IEEE802154_ADDRMODE_NONE) { return -EINVAL; } /* The source address can only be set to NONE if the device is the PAN coord */ - if (meta->srcaddr_mode == IEEE802154_ADDRMODE_NONE && + if (meta->srcmode == IEEE802154_ADDRMODE_NONE && priv->devmode != IEEE802154_DEVMODE_PANCOORD) { return -EINVAL; @@ -95,14 +95,14 @@ int mac802154_get_mhrlen(MACHANDLE mac, /* Add the source address length */ - ret += mac802154_addr_length[ meta->srcaddr_mode]; + ret += mac802154_addr_length[ meta->srcmode]; /* If both destination and source addressing information is present, the MAC * sublayer shall compare the destination and source PAN identifiers. * [1] pg. 41. */ - if (meta->srcaddr_mode != IEEE802154_ADDRMODE_NONE && + if (meta->srcmode != IEEE802154_ADDRMODE_NONE && meta->destaddr.mode != IEEE802154_ADDRMODE_NONE) { /* If the PAN identifiers are identical, the PAN ID Compression field @@ -121,7 +121,7 @@ int mac802154_get_mhrlen(MACHANDLE mac, * PAN ID if the respective address is included */ - if (meta->srcaddr_mode != IEEE802154_ADDRMODE_NONE) + if (meta->srcmode != IEEE802154_ADDRMODE_NONE) { ret += 2; /* 2 bytes for source PAN ID */ } From 222fe50d3a5051dcda3c433f24ddc9076637eb97 Mon Sep 17 00:00:00 2001 From: Anthony Merlino Date: Mon, 17 Jul 2017 03:57:28 -0400 Subject: [PATCH 51/54] ieee802154: Trivial --- include/nuttx/wireless/ieee802154/ieee802154_mac.h | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/include/nuttx/wireless/ieee802154/ieee802154_mac.h b/include/nuttx/wireless/ieee802154/ieee802154_mac.h index 24ed1388bd..a1238ba0ad 100644 --- a/include/nuttx/wireless/ieee802154/ieee802154_mac.h +++ b/include/nuttx/wireless/ieee802154/ieee802154_mac.h @@ -564,11 +564,10 @@ struct ieee802154_capability_info_s struct ieee802154_superframespec_s { - uint16_t beaconorder : 4; /* Transmission interval of beacon */ - uint16_t sforder : 4; /* Length of active portion of superframe */ + uint16_t beaconorder : 4; /* Transmission interval of beacon */ + uint16_t sforder : 4; /* Length of active portion of superframe */ uint16_t final_capslot : 4; /* Last slot utilized by CAP */ uint16_t ble : 1; /* Battery Life Extension (BLE) */ - uint16_t reserved : 1; /* Reserved bit */ uint16_t pancoord : 1; /* 1 if beacon sent by pan coordinator */ uint16_t assocpermit : 1; /* 1 if coordinator is accepting associaton */ }; From eaf4c05f27fd790b31f92b7a58509df9ee2cc190 Mon Sep 17 00:00:00 2001 From: Anthony Merlino Date: Tue, 18 Jul 2017 14:01:30 -0400 Subject: [PATCH 52/54] ieee802154: Sets txdesc retrycount to the maxretries MAC attribute when allocated --- wireless/ieee802154/mac802154.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/wireless/ieee802154/mac802154.c b/wireless/ieee802154/mac802154.c index 6c93de3f15..7bc0d6c4c9 100644 --- a/wireless/ieee802154/mac802154.c +++ b/wireless/ieee802154/mac802154.c @@ -229,9 +229,8 @@ int mac802154_txdesc_alloc(FAR struct ieee802154_privmac_s *priv, return -EINTR; } - /* Set the purge time to zero */ - (*txdesc)->purgetime = 0; + (*txdesc)->retrycount = priv->maxretries; (*txdesc)->conf = ¬if->u.dataconf; return OK; From 706bce0eb7da343ef47573ca838e75eb55089059 Mon Sep 17 00:00:00 2001 From: Anthony Merlino Date: Tue, 18 Jul 2017 14:02:13 -0400 Subject: [PATCH 53/54] configs/clicker2-stm32: Fixes Kconfig option dependency --- configs/clicker2-stm32/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configs/clicker2-stm32/Kconfig b/configs/clicker2-stm32/Kconfig index fb4b89d98a..694b9f3582 100644 --- a/configs/clicker2-stm32/Kconfig +++ b/configs/clicker2-stm32/Kconfig @@ -38,7 +38,7 @@ config CLICKER2_STM32_MB2_BEE config CLICKER2_STM32_MRF24J40LH_VERBOSE bool "Verbose MRF24J40 lowerhalf" default n - depends on DEBUG_WIRELESS_INFO + depends on IEEE802154_MRF24J40 && DEBUG_WIRELESS_INFO ---help--- Enable verbose syslog for MRF24J40 lowerhalf From f665c3e506f8d6588330dfd36206f059c29f5354 Mon Sep 17 00:00:00 2001 From: Anthony Merlino Date: Tue, 18 Jul 2017 14:04:58 -0400 Subject: [PATCH 54/54] ieee802154: Adds special attribut that can be used to perform a regdump of the radio --- .../wireless/ieee802154/ieee802154_mac.h | 36 ++++++++++--------- 1 file changed, 20 insertions(+), 16 deletions(-) diff --git a/include/nuttx/wireless/ieee802154/ieee802154_mac.h b/include/nuttx/wireless/ieee802154/ieee802154_mac.h index a1238ba0ad..a3fc7bc618 100644 --- a/include/nuttx/wireless/ieee802154/ieee802154_mac.h +++ b/include/nuttx/wireless/ieee802154/ieee802154_mac.h @@ -423,26 +423,30 @@ enum ieee802154_attr_e IEEE802154_ATTR_MAC_SADDR, IEEE802154_ATTR_MAC_SUPERFRAME_ORDER, IEEE802154_ATTR_MAC_SYNC_SYMBOL_OFFSET, - IEEE802154_PIB_MAC_TIMESTAMP_SUPPORT, - IEEE802154_PIB_MAC_TRANSACTION_PERSIST_TIME, - IEEE802154_PIB_MAC_TX_CTRL_ACTIVE_DUR, - IEEE802154_PIB_MAC_TX_CTRL_PAUSE_DUR, - IEEE802154_PIB_MAC_TX_TOTAL_DUR, + IEEE802154_ATTR_MAC_TIMESTAMP_SUPPORT, + IEEE802154_ATTR_MAC_TRANSACTION_PERSIST_TIME, + IEEE802154_ATTR_MAC_TX_CTRL_ACTIVE_DUR, + IEEE802154_ATTR_MAC_TX_CTRL_PAUSE_DUR, + IEEE802154_ATTR_MAC_TX_TOTAL_DUR, IEEE802154_ATTR_MAC_DEVMODE, /* Non-standard */ /* MAC Security Attributes */ - IEEE802154_PIB_MAC_KEY_TABLE = 0x70, - IEEE802154_PIB_MAC_DEV_TABLE, - IEEE802154_PIB_MAC_SEC_LVL_TABLE, - IEEE802154_PIB_MAC_FRAME_COUNTER, - IEEE802154_PIB_MAC_AUTOREQ_SEC_LVL, - IEEE802154_PIB_MAC_AUTOREQ_KEY_ID_MODE, - IEEE802154_PIB_MAC_AUTOREQ_KEY_SOURCE, - IEEE802154_PIB_MAC_AUTOREQ_KEY_INDEX, - IEEE802154_PIB_MAC_DEFAULT_KEY_SRC, - IEEE802154_PIB_MAC_PANCOORD_EXT_ADDR, - IEEE802154_PIB_MAC_PANCOORD_SHORT_ADDR, + IEEE802154_ATTR_MAC_KEY_TABLE = 0x70, + IEEE802154_ATTR_MAC_DEV_TABLE, + IEEE802154_ATTR_MAC_SEC_LVL_TABLE, + IEEE802154_ATTR_MAC_FRAME_COUNTER, + IEEE802154_ATTR_MAC_AUTOREQ_SEC_LVL, + IEEE802154_ATTR_MAC_AUTOREQ_KEY_ID_MODE, + IEEE802154_ATTR_MAC_AUTOREQ_KEY_SOURCE, + IEEE802154_ATTR_MAC_AUTOREQ_KEY_INDEX, + IEEE802154_ATTR_MAC_DEFAULT_KEY_SRC, + IEEE802154_ATTR_MAC_PANCOORD_EXT_ADDR, + IEEE802154_ATTR_MAC_PANCOORD_SHORT_ADDR, + + /* Special Attributes */ + + IEEE802154_ATTR_RADIO_REGDUMP = 0xF0, }; /* Frame Type */