diff --git a/drivers/wireless/ieee802154/mrf24j40/mrf24j40.c b/drivers/wireless/ieee802154/mrf24j40/mrf24j40.c index 73bd5c8a1e9..02e0103c190 100644 --- a/drivers/wireless/ieee802154/mrf24j40/mrf24j40.c +++ b/drivers/wireless/ieee802154/mrf24j40/mrf24j40.c @@ -467,6 +467,7 @@ FAR struct ieee802154_radio_s * dev->radio.txnotify = mrf24j40_txnotify; dev->radio.txdelayed = mrf24j40_txdelayed; dev->radio.rxenable = mrf24j40_rxenable; + dev->radio.energydetect = mrf24j40_energydetect; dev->radio.beaconstart = mrf24j40_beaconstart; dev->radio.beaconupdate = mrf24j40_beaconupdate; dev->radio.beaconstop = mrf24j40_beaconstop; diff --git a/drivers/wireless/ieee802154/mrf24j40/mrf24j40_radif.c b/drivers/wireless/ieee802154/mrf24j40/mrf24j40_radif.c index d460100e42b..c6f2a431d80 100644 --- a/drivers/wireless/ieee802154/mrf24j40/mrf24j40_radif.c +++ b/drivers/wireless/ieee802154/mrf24j40/mrf24j40_radif.c @@ -426,6 +426,11 @@ int mrf24j40_rxenable(FAR struct ieee802154_radio_s *radio, bool enable) return OK; } +int mrf24j40_energydetect(FAR struct ieee802154_radio_s *radio, uint32_t nsymbols) +{ + return -ENOTTY; +} + int mrf24j40_reset(FAR struct ieee802154_radio_s *radio) { FAR struct mrf24j40_radio_s *dev = (FAR struct mrf24j40_radio_s *)radio; diff --git a/drivers/wireless/ieee802154/mrf24j40/mrf24j40_radif.h b/drivers/wireless/ieee802154/mrf24j40/mrf24j40_radif.h index 8d5fe07d094..0c288736029 100644 --- a/drivers/wireless/ieee802154/mrf24j40/mrf24j40_radif.h +++ b/drivers/wireless/ieee802154/mrf24j40/mrf24j40_radif.h @@ -57,6 +57,8 @@ int mrf24j40_txdelayed(FAR struct ieee802154_radio_s *radio, int mrf24j40_rxenable(FAR struct ieee802154_radio_s *radio, bool enable); +int mrf24j40_energydetect(FAR struct ieee802154_radio_s *radio, uint32_t nsymbols); + int mrf24j40_beaconstart(FAR struct ieee802154_radio_s *radio, FAR const struct ieee802154_superframespec_s *sfspec, FAR struct ieee802154_beaconframe_s *beacon); diff --git a/include/nuttx/wireless/ieee802154/ieee802154_mac.h b/include/nuttx/wireless/ieee802154/ieee802154_mac.h index 813f9b235cb..e272a90b24c 100644 --- a/include/nuttx/wireless/ieee802154/ieee802154_mac.h +++ b/include/nuttx/wireless/ieee802154/ieee802154_mac.h @@ -1425,11 +1425,14 @@ struct ieee802154_scan_conf_s enum ieee802154_status_e status; enum ieee802154_scantype_e type; uint8_t chpage; - uint8_t unscanned[15]; + + uint8_t chlist[15]; /* Used for both scanned channels (ED) and unscanned + * channels (Active/Passive) */ uint8_t numunscanned; - uint8_t numdesc; + struct ieee802154_pandesc_s pandescs[MAC802154_NPANDESC]; - uint8_t edlist[MAC802154_NPANDESC]; + uint8_t edlist[15]; + uint8_t numresults; }; /***************************************************************************** diff --git a/include/nuttx/wireless/ieee802154/ieee802154_radio.h b/include/nuttx/wireless/ieee802154/ieee802154_radio.h index eb6f9123362..89051d84924 100644 --- a/include/nuttx/wireless/ieee802154/ieee802154_radio.h +++ b/include/nuttx/wireless/ieee802154/ieee802154_radio.h @@ -118,6 +118,8 @@ struct ieee802154_radiocb_s FAR struct ieee802154_data_ind_s *ind); CODE void (*sfevent) (FAR const struct ieee802154_radiocb_s *radiocb, enum ieee802154_sfevent_e sfevent); + CODE void (*edresult) (FAR const struct ieee802154_radiocb_s *radiocb, + uint8_t edval); }; struct ieee802154_radio_s @@ -136,6 +138,8 @@ struct ieee802154_radio_s FAR struct ieee802154_txdesc_s *txdesc, uint32_t symboldelay); CODE int (*rxenable) (FAR struct ieee802154_radio_s *radio, bool enable); + CODE int (*energydetect) (FAR struct ieee802154_radio_s *radio, + uint32_t symboldelay); 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 09b055417f4..e781a22f005 100644 --- a/wireless/ieee802154/mac802154.c +++ b/wireless/ieee802154/mac802154.c @@ -88,6 +88,9 @@ static void mac802154_rxframe(FAR const struct ieee802154_radiocb_s *radiocb, FAR struct ieee802154_data_ind_s *ind); static void mac802154_rxframe_worker(FAR void *arg); +static void mac802154_edresult(FAR const struct ieee802154_radiocb_s *radiocb, + uint8_t edval); + static void mac802154_sfevent(FAR const struct ieee802154_radiocb_s *radiocb, enum ieee802154_sfevent_e sfevent); @@ -1635,6 +1638,45 @@ static void mac802154_rxdatareq(FAR struct ieee802154_privmac_s *priv, priv->radio->txdelayed(priv->radio, txdesc, 0); } +/**************************************************************************** + * Name: mac802154_edresult + * + * Description: + * Called from the radio driver through the callback struct. This + * function is called when the radio has finished an energy detect operation. + * This is triggered by a SCAN.request primitive with ScanType set to Energy + * Detect (ED) + * + ****************************************************************************/ + +static void mac802154_edresult(FAR const struct ieee802154_radiocb_s *radiocb, + uint8_t edval) +{ + FAR struct mac802154_radiocb_s *cb = + (FAR struct mac802154_radiocb_s *)radiocb; + FAR struct ieee802154_privmac_s *priv; + + DEBUGASSERT(cb != NULL && cb->priv != NULL); + priv = cb->priv; + + /* Get exclusive access to the driver structure. We don't care about any + * signals so if we see one, just go back to trying to get access again. + */ + + mac802154_lock(priv, false); + + /* If we are actively performing a scan operation, notify the scan handler */ + + if (priv->curr_op == MAC802154_OP_SCAN) + { + mac802154_edscan_onresult(priv, edval); + } + + /* Relinquish control of the private structure */ + + mac802154_unlock(priv); +} + static void mac802154_sfevent(FAR const struct ieee802154_radiocb_s *radiocb, enum ieee802154_sfevent_e sfevent) { @@ -2125,6 +2167,7 @@ MACHANDLE mac802154_create(FAR struct ieee802154_radio_s *radiodev) radiocb->txdone = mac802154_txdone; radiocb->rxframe = mac802154_rxframe; radiocb->sfevent = mac802154_sfevent; + radiocb->edresult = mac802154_edresult; /* Bind our callback structure */ diff --git a/wireless/ieee802154/mac802154_internal.h b/wireless/ieee802154/mac802154_internal.h index 2677fa5c140..dcdb62776ce 100644 --- a/wireless/ieee802154/mac802154_internal.h +++ b/wireless/ieee802154/mac802154_internal.h @@ -150,9 +150,8 @@ struct ieee802154_privmac_s /******************* Fields related to SCAN operation ***********************/ - /* List of PAN descriptors to track during scan procedures */ - uint8_t scanindex; + uint8_t edlist[15]; uint8_t npandesc; struct ieee802154_pandesc_s pandescs[MAC802154_NPANDESC]; uint8_t panidbeforescan[IEEE802154_PANIDSIZE]; diff --git a/wireless/ieee802154/mac802154_scan.c b/wireless/ieee802154/mac802154_scan.c index 1c131dc7d67..0b7f5766ffe 100644 --- a/wireless/ieee802154/mac802154_scan.c +++ b/wireless/ieee802154/mac802154_scan.c @@ -124,11 +124,13 @@ int mac802154_req_scan(MACHANDLE mac, FAR struct ieee802154_scan_req_s *req) priv->scanindex = 0; priv->npandesc = 0; + priv->scansymdur = IEEE802154_BASE_SUPERFRAME_DURATION * ((1 << req->duration) + 1); + switch (req->type) { case IEEE802154_SCANTYPE_PASSIVE: { - wlinfo("MLME: Starting Passive scan\n"); + wlinfo("MLME: Starting Passive Scan\n"); /* Set the channel to the first channel in the list */ @@ -154,9 +156,6 @@ int mac802154_req_scan(MACHANDLE mac, FAR struct ieee802154_scan_req_s *req) */ mac802154_rxenable(priv); - - priv->scansymdur = IEEE802154_BASE_SUPERFRAME_DURATION * - ((1 << req->duration) + 1); mac802154_timerstart(priv, priv->scansymdur, mac802154_scantimeout); } break; @@ -168,8 +167,15 @@ int mac802154_req_scan(MACHANDLE mac, FAR struct ieee802154_scan_req_s *req) break; case IEEE802154_SCANTYPE_ED: { - ret = -ENOTTY; - goto errout_with_sem; + wlinfo("MLME: Starting Energy Scan\n"); + + /* Set the channel to the first channel in the list, and trigger an + * energy detect operation with the radio layer. + */ + + mac802154_setchpage(priv, req->chpage); + mac802154_setchannel(priv, req->channels[priv->scanindex]); + priv->radio->energydetect(priv->radio, priv->scansymdur); } break; case IEEE802154_SCANTYPE_ORPHAN: @@ -213,33 +219,105 @@ void mac802154_scanfinish(FAR struct ieee802154_privmac_s *priv, scanconf->type = priv->currscan.type; scanconf->chpage = priv->currscan.chpage; - /* Copy in the channels that did not get scanned */ - - if (priv->scanindex != priv->currscan.numchan) + if (priv->currscan.type == IEEE802154_SCANTYPE_ED) { - scanconf->numunscanned = priv->currscan.numchan - priv->scanindex; - memcpy(scanconf->unscanned, &priv->currscan.channels[priv->scanindex], - scanconf->numunscanned); + /* "The list of energy measurements, one for each channel searched during an + * ED scan. This parameter is null for active, passive, and orphan scans." [1] + */ + + memcpy(scanconf->edlist, priv->edlist, sizeof(scanconf->edlist)); + memcpy(scanconf->chlist, priv->currscan.channels, sizeof(scanconf->chlist)); + scanconf->numresults = priv->currscan.numchan; } - /* Copy the PAN descriptors into the primitive */ + else + { + /* "A list of the channels given in the request which were not scanned. This + * parameter is not valid for ED scans." [1] + */ - memcpy(scanconf->pandescs, priv->pandescs, - sizeof(struct ieee802154_pandesc_s) * priv->npandesc); + scanconf->numunscanned = priv->currscan.numchan - priv->scanindex; + if (scanconf->numunscanned) + { + memcpy(scanconf->chlist, &priv->currscan.channels[priv->scanindex], + scanconf->numunscanned); + } + + /* "The list of PAN descriptors, one for each beacon found during an active or + * passive scan if macAutoRequest is set to TRUE. This parameter is null for + * ED and orphan scans or when macAutoRequest is set to FALSE during an + * active or passive scan." [1] + */ + + if (priv->currscan.type != IEEE802154_SCANTYPE_ORPHAN && priv->autoreq) + { + memcpy(scanconf->pandescs, priv->pandescs, + sizeof(struct ieee802154_pandesc_s) * priv->npandesc); + scanconf->numresults = priv->npandesc; + } + + if (priv->currscan.type == IEEE802154_SCANTYPE_PASSIVE) + { + /* Reset the PAN ID to the setting before the scan started */ + + mac802154_setpanid(priv, priv->panidbeforescan); + } + } - scanconf->numdesc = priv->npandesc; scanconf->status = status; - /* Reset the PAN ID to the setting before the scan started */ - - mac802154_setpanid(priv, priv->panidbeforescan); - priv->curr_op = MAC802154_OP_NONE; mac802154_givesem(&priv->opsem); mac802154_notify(priv, primitive); } +/**************************************************************************** + * Name: mac802154_edscan_onresult + * + * Description: + * Function indirectly called from the radio layer via the radiocb edresult() + * call. + * + * Assumptions: + * Called with the priv mac struct locked + * + ****************************************************************************/ + +void mac802154_edscan_onresult(FAR struct ieee802154_privmac_s *priv, uint8_t edval) +{ + DEBUGASSERT(priv->curr_op == MAC802154_OP_SCAN && + priv->currscan.type == IEEE802154_SCANTYPE_ED); + + /* Copy the energy value into our local list */ + + priv->edlist[priv->scanindex] = edval; + + /* If we got here it means we are done scanning that channel */ + + priv->scanindex++; + + /* Check to see if this was the last channel to scan */ + + if (priv->scanindex == priv->currscan.numchan) + { + mac802154_scanfinish(priv, IEEE802154_STATUS_SUCCESS); + return; + } + + /* Continue on with the next channel in the list */ + + mac802154_setchannel(priv, priv->currscan.channels[priv->scanindex]); + + /* ...after switching to the channel for a passive scan, the device + * shall enable its receiver for at most + * [aBaseSuperframeDuration × (2 * n + 1)], + * where n is the value of the ScanDuration parameter. [1] pg. 25 + */ + + priv->radio->energydetect(priv->radio, priv->scansymdur); +} + /**************************************************************************** * Private Functions ****************************************************************************/ diff --git a/wireless/ieee802154/mac802154_scan.h b/wireless/ieee802154/mac802154_scan.h index 985d0953d51..703e670a65f 100644 --- a/wireless/ieee802154/mac802154_scan.h +++ b/wireless/ieee802154/mac802154_scan.h @@ -60,6 +60,8 @@ struct ieee802154_privmac_s; /* Forward Reference */ +void mac802154_edscan_onresult(FAR struct ieee802154_privmac_s *priv, uint8_t edval); + void mac802154_scanfinish(FAR struct ieee802154_privmac_s *priv, enum ieee802154_status_e status);