diff --git a/configs/clicker2-stm32/Kconfig b/configs/clicker2-stm32/Kconfig index 9344f015da..694b9f3582 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 IEEE802154_MRF24J40 && DEBUG_WIRELESS_INFO + ---help--- + Enable verbose syslog for MRF24J40 lowerhalf + endif # ARCH_BOARD_CLICKER2_STM32 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 diff --git a/configs/clicker2-stm32/scripts/Make.defs b/configs/clicker2-stm32/scripts/Make.defs index d5db3bae9f..db554416f3 100644 --- a/configs/clicker2-stm32/scripts/Make.defs +++ b/configs/clicker2-stm32/scripts/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__ 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/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 99% rename from drivers/wireless/ieee802154/at86rf23x.c rename to drivers/wireless/ieee802154/at86rf23x/at86rf23x.c index 3e4cd0ce11..1fe4250d3a 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 @@ -996,19 +996,20 @@ static int at86rf23x_gettxpower(FAR struct ieee802154_radio_s *ieee, 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: + case RF23X_TXPWR_POS_3_7: + *txpwr =0; + break; + + case RF23X_TXPWR_POS_3_4: *txpwr = 0; break; - case RF23X_TXPWR_POS_3_4: - *txpwr = 0; - break; - - case RF23X_TXPWR_POS_3: + case RF23X_TXPWR_POS_3: *txpwr = 0; break; @@ -1016,23 +1017,23 @@ static int at86rf23x_gettxpower(FAR struct ieee802154_radio_s *ieee, *txpwr = 0; break; - case RF23X_TXPWR_POS_2: + case RF23X_TXPWR_POS_2: *txpwr = 0; break; - case RF23X_TXPWR_POS_1: + 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_NEG_2: + case RF23X_TXPWR_NEG_2: *txpwr = 2000; break; @@ -1071,11 +1072,11 @@ static int at86rf23x_gettxpower(FAR struct ieee802154_radio_s *ieee, * 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) +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; 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.c b/drivers/wireless/ieee802154/mrf24j40.c deleted file mode 100644 index b6259099c1..0000000000 --- a/drivers/wireless/ieee802154/mrf24j40.c +++ /dev/null @@ -1,2227 +0,0 @@ -/**************************************************************************** - * 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_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); - -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_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, - enum ieee802154_attr_e attr, - FAR union ieee802154_attr_u *attrval); -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_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); -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_attrs(FAR struct ieee802154_radio_s *radio) -{ - FAR struct mrf24j40_radio_s *dev = (FAR struct mrf24j40_radio_s *)radio; - - dev->max_frame_waittime = MRF24J40_DEFAULT_MAX_FRAME_WAITTIME; - - return OK; -} - -static int mrf24j40_get_attr(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_set_attr(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_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) -{ - 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; - - 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_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 - * - * 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; - struct ieee802154_cca_s cca; - - 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.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; - dev->radio.sfupdate = mrf24j40_sfupdate; - - 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); - - dev->lower->enable(dev->lower, true); - return &dev->radio; -} 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..446f7ef293 --- /dev/null +++ b/drivers/wireless/ieee802154/mrf24j40/Make.defs @@ -0,0 +1,49 @@ +############################################################################ +# 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_getset.c mrf24j40_interrupt.c mrf24j40_radif.c +CSRCS += mrf24j40_regops.c 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/mrf24j40.c b/drivers/wireless/ieee802154/mrf24j40/mrf24j40.c new file mode 100644 index 0000000000..2d1fc5ffe6 --- /dev/null +++ b/drivers/wireless/ieee802154/mrf24j40/mrf24j40.c @@ -0,0 +1,473 @@ +/**************************************************************************** + * 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 "mrf24j40.h" +#include "mrf24j40_reg.h" +#include "mrf24j40_radif.h" +#include "mrf24j40_getset.h" +#include "mrf24j40_regops.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +#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) +{ + uint8_t reg; + + /* Manually enable the LNA*/ + + mrf24j40_setpamode(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_setpamode(dev, MRF24J40_PA_AUTO); + + return OK; +} +#endif + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * 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: + * + ****************************************************************************/ + +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: + * + ****************************************************************************/ + +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_norm_setup + * + * Description: + * Setup a transaction in the normal TX FIFO + * + ****************************************************************************/ + +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 + * + ****************************************************************************/ + +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 + * + ****************************************************************************/ + +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 + * + ****************************************************************************/ + +void mrf24j40_gts_setup(FAR struct mrf24j40_radio_s *dev, uint8_t fifo, + FAR struct iob_s *frame) +{ + +} + +/**************************************************************************** + * Name: mrf24j40_setup_fifo + * + * Description: + * + ****************************************************************************/ + +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]); + } +} + +/**************************************************************************** + * 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/mrf24j40.h b/drivers/wireless/ieee802154/mrf24j40/mrf24j40.h new file mode 100644 index 0000000000..b07714c429 --- /dev/null +++ b/drivers/wireless/ieee802154/mrf24j40/mrf24j40.h @@ -0,0 +1,227 @@ +/**************************************************************************** + * drivers/wireless/ieee802154/mrf24j40/mrf24j40.h + * + * Copyright (C) 2015-2016 Sebastien Lorquet. All rights reserved. + * Author: Sebastien Lorquet + * + * 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_H +#define __DRIVERS_WIRELESS_IEEE802154_MRF24J40_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include +#include + +#include +#include + +#include +#include + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#define MRF24J40_GTS_SLOTS 2 + +/* 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 + +/* 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 + +/* Clock configuration macros */ + +#define MRF24J40_BEACONINTERVAL_NSEC(beaconorder) \ + (IEEE802154_BASE_SUPERFRAME_DURATION * (1 << beaconorder) * (16 * 1000)) + +#define MRF24J40_SUPERFRAMEDURATION_NSEC(sforder) \ + (IEEE802154_BASE_SUPERFRAME_DURATION * (1 << sforder) * (16 * 1000)) + +/* Configuration *************************************************************/ + +#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 + +/**************************************************************************** + * Public 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 */ + uint32_t slpclkper; /* Sleep clock period (nanoseconds) */ + + /* 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]; +}; + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +/**************************************************************************** + * Inline Functions + ****************************************************************************/ + +/**************************************************************************** + * 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); +} + +/**************************************************************************** + * 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 new file mode 100644 index 0000000000..b3c7406eb3 --- /dev/null +++ b/drivers/wireless/ieee802154/mrf24j40/mrf24j40_getset.c @@ -0,0 +1,499 @@ +/**************************************************************************** + * 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 + +#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 + * + * 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) +{ + uint8_t reg; + + /* 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 OK; +} + +/**************************************************************************** + * 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; +} + +/**************************************************************************** + * 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 new file mode 100644 index 0000000000..f1acb79fee --- /dev/null +++ b/drivers/wireless/ieee802154/mrf24j40/mrf24j40_getset.h @@ -0,0 +1,66 @@ +/**************************************************************************** + * 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); + +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_interrupt.c b/drivers/wireless/ieee802154/mrf24j40/mrf24j40_interrupt.c new file mode 100644 index 0000000000..b3e1c16679 --- /dev/null +++ b/drivers/wireless/ieee802154/mrf24j40/mrf24j40_interrupt.c @@ -0,0 +1,443 @@ +/**************************************************************************** + * 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 + + 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); + wlinfo("Beacon triggered. BSN: 0x%02X\n", dev->bsn-1); + } + } + + /* 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..a6dc0c6e0f --- /dev/null +++ b/drivers/wireless/ieee802154/mrf24j40/mrf24j40_radif.c @@ -0,0 +1,749 @@ +/**************************************************************************** + * 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 + +#include "mrf24j40.h" +#include "mrf24j40_reg.h" +#include "mrf24j40_getset.h" +#include "mrf24j40_regops.h" + +/**************************************************************************** + * 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); +static void mrf24j40_slpclkcal(FAR struct mrf24j40_radio_s *dev); + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +static const uint8_t g_allones[8] = +{ + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF +}; + +/**************************************************************************** + * 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 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); + + if (bo < 15) + { + 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; + } + + wlinfo("MAINCNT: %lu, REMCNT: %lu\n", maincnt, remcnt); + + /* 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); + + /* 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’. + */ + + while (!(mrf24j40_getreg(dev->spi, MRF24J40_SLPCAL2) & + MRF24J40_SLPCAL2_SLPCALRDY)) + { + up_udelay(1); + } + + 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); + + dev->slpclkper = (dev->slpclkper * 50 / 16); +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ +/* 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; +} + +/**************************************************************************** + * 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; + 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_BBREG6 , 0x40); /* 01000000 Append RSSI to rx packets */ + + /* Calibrate the Sleep Clock (SLPCLK) frequency. Refer to Section 3.15.1.2 + * “Sleep Clock Calibration”. + */ + + 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 + * 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 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, (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 */ + + reg = mrf24j40_getreg(dev->spi, MRF24J40_INTCON); + 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); + 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_setpamode(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 = IEEE802154_STATUS_SUCCESS;; + + switch (attr) + { + case IEEE802154_ATTR_MAC_PANID: + { + mrf24j40_setpanid(dev, attrval->mac.panid); + } + break; + + case IEEE802154_ATTR_MAC_SADDR: + { + mrf24j40_setsaddr(dev, attrval->mac.saddr); + } + break; + + case IEEE802154_ATTR_MAC_EADDR: + { + mrf24j40_seteaddr(dev, attrval->mac.eaddr); + } + break; + + case IEEE802154_ATTR_MAC_COORD_SADDR: + { + mrf24j40_setcoordsaddr(dev, attrval->mac.coordsaddr); + } + break; + + case IEEE802154_ATTR_MAC_COORD_EADDR: + { + mrf24j40_setcoordeaddr(dev, attrval->mac.coordeaddr); + } + 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); + } + } + break; + + case IEEE802154_ATTR_PHY_CHAN: + { + mrf24j40_setchannel(dev, attrval->phy.chan); + } + break; + + case IEEE802154_ATTR_MAC_DEVMODE: + { + mrf24j40_setdevmode(dev, attrval->mac.devmode); + } + 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; + + if (dev->devmode == IEEE802154_DEVMODE_ENDPOINT) + { + mrf24j40_setreg(dev->spi, MRF24J40_FRMOFFSET, 0x15); + } + else + { + mrf24j40_setreg(dev->spi, MRF24J40_FRMOFFSET, 0x00); + } + } + 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..8d5fe07d09 --- /dev/null +++ b/drivers/wireless/ieee802154/mrf24j40/mrf24j40_radif.h @@ -0,0 +1,72 @@ +/**************************************************************************** + * 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_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, + 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.h b/drivers/wireless/ieee802154/mrf24j40/mrf24j40_reg.h similarity index 94% rename from drivers/wireless/ieee802154/mrf24j40.h rename to drivers/wireless/ieee802154/mrf24j40/mrf24j40_reg.h index e4e4e8ba5e..a54a006f7b 100644 --- a/drivers/wireless/ieee802154/mrf24j40.h +++ b/drivers/wireless/ieee802154/mrf24j40/mrf24j40_reg.h @@ -1,8 +1,10 @@ /**************************************************************************** - * drivers/wireless/ieee802154/mrf24j40.h + * 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 @@ -33,8 +35,8 @@ * ****************************************************************************/ -#ifndef __DRIVERS_WIRELESS_IEEE802154_MRF24J40_H -#define __DRIVERS_WIRELESS_IEEE802154_MRF24J40_H +#ifndef __DRIVERS_WIRELESS_IEEE802154_MRF24J40_REG_H +#define __DRIVERS_WIRELESS_IEEE802154_MRF24J40_REG_H /* MRF24J40 Registers *******************************************************/ @@ -226,6 +228,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 @@ -265,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 @@ -281,4 +295,8 @@ #define MRF24J40_RXFLUSH_SHIFT_WAKEPAD 5 #define MRF24J40_RXFLUSH_SHIFT_WAKEPOL 6 -#endif /* __DRIVERS_WIRELESS_IEEE802154_MRF24J40_H */ +/* SLPCON1 bits */ + +#define MRF24J40_SLPCON1_CLKOUT_DISABLED 0x20 + +#endif /* __DRIVERS_WIRELESS_IEEE802154_MRF24J40_REG_H */ diff --git a/drivers/wireless/ieee802154/mrf24j40/mrf24j40_regops.c b/drivers/wireless/ieee802154/mrf24j40/mrf24j40_regops.c new file mode 100644 index 0000000000..f6778e9308 --- /dev/null +++ b/drivers/wireless/ieee802154/mrf24j40/mrf24j40_regops.c @@ -0,0 +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; +} 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 diff --git a/include/nuttx/wireless/ieee802154/ieee802154_mac.h b/include/nuttx/wireless/ieee802154/ieee802154_mac.h index b079a32902..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 */ @@ -564,11 +568,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 */ }; @@ -593,19 +596,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,17 +626,16 @@ union ieee802154_macattr_u bool is_assoc; bool assocpermit; - bool auto_req; + bool autoreq; bool batt_life_ext; bool gts_permit; bool promisc_mode; bool rng_support; - bool resp_waittime; bool rxonidle; 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; @@ -656,6 +649,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; @@ -706,17 +700,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 */ @@ -727,7 +721,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: @@ -738,7 +732,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; @@ -1112,7 +1106,7 @@ struct ieee802154_disassoc_conf_s * *****************************************************************************/ -struct ieee802154_beaconnotify_ind_s +struct ieee802154_beacon_ind_s { uint8_t bsn; /* Beacon sequence number */ @@ -1122,20 +1116,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 * @@ -1265,7 +1250,7 @@ struct ieee802154_orphan_resp_s struct ieee802154_reset_req_s { - bool rst_pibattr; + bool resetattr; }; /***************************************************************************** @@ -1538,21 +1523,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/include/nuttx/wireless/ieee802154/ieee802154_radio.h b/include/nuttx/wireless/ieee802154/ieee802154_radio.h index 8f851ffe72..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 purge_time; /* 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 */ }; @@ -119,20 +123,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/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/Kconfig b/wireless/ieee802154/Kconfig index 5b8e379968..c5381c7afd 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/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 diff --git a/wireless/ieee802154/mac802154.c b/wireless/ieee802154/mac802154.c index af5e4523f7..7bc0d6c4c9 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, @@ -184,7 +177,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 +197,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); @@ -236,6 +229,9 @@ int mac802154_txdesc_alloc(FAR struct ieee802154_privmac_s *priv, return -EINTR; } + (*txdesc)->purgetime = 0; + (*txdesc)->retrycount = priv->maxretries; + (*txdesc)->conf = ¬if->u.dataconf; return OK; } @@ -354,9 +350,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 +413,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; @@ -561,7 +559,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 */ @@ -580,8 +578,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); } } @@ -607,7 +605,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) { @@ -622,12 +620,12 @@ 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) + if (clock_systimer() >= txdesc->purgetime) { /* Unlink the transaction */ @@ -636,8 +634,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; @@ -648,10 +646,12 @@ 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; } } + + mac802154_unlock(priv); } /**************************************************************************** @@ -677,7 +677,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) { @@ -692,7 +692,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) { @@ -729,11 +729,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 */ @@ -760,13 +760,12 @@ 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 */ - mac802154_takesem(&priv->exclsem, false); + mac802154_lock(priv, false); while (1) { @@ -781,8 +780,9 @@ 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; + + wlinfo("Tx status: %s\n", IEEE802154_STATUS_STRING[txdesc->conf->status]); switch(txdesc->frametype) { @@ -792,9 +792,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; @@ -857,14 +857,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 +865,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; } @@ -889,7 +876,7 @@ static void mac802154_txdone_worker(FAR void *arg) mac802154_txdesc_free(priv, txdesc); } - mac802154_givesem(&priv->exclsem); + mac802154_unlock(priv) } /**************************************************************************** @@ -920,15 +907,15 @@ 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 */ sq_addlast((FAR sq_entry_t *)ind, &priv->dataind_queue); - wlinfo("frame received\n"); + wlinfo("Frame received\n"); - mac802154_givesem(&priv->exclsem); + mac802154_unlock(priv) /* Schedule work with the work queue to process the completion further */ @@ -966,7 +953,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 */ @@ -974,7 +961,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) { @@ -1100,7 +1087,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"); @@ -1123,7 +1109,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); } @@ -1159,7 +1145,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 @@ -1178,7 +1164,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, @@ -1232,7 +1220,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); @@ -1275,7 +1264,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 */ @@ -1291,7 +1280,7 @@ static void mac802154_rxdataframe(FAR struct ieee802154_privmac_s *priv, notify_with_lock: - mac802154_givesem(&priv->exclsem); + mac802154_unlock(priv) notify_without_lock: @@ -1350,7 +1339,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. @@ -1376,11 +1365,20 @@ 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); priv->beaconupdate = true; - mac802154_givesem(&priv->exclsem); + mac802154_unlock(priv) return; } } @@ -1397,7 +1395,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; } } @@ -1503,7 +1501,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); } @@ -1522,18 +1520,31 @@ 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); - /* Check if there is any reason to update the beacon */ - - if (priv->beaconupdate) + switch (sfevent) { - mac802154_updatebeacon(priv); + case IEEE802154_SFEVENT_ENDOFACTIVE: + { +#ifdef CONFIG_MAC802154_SFEVENT_VERBOSE + wlinfo("End of superframe\n"); +#endif - 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); + mac802154_unlock(priv) } /**************************************************************************** @@ -1543,51 +1554,182 @@ 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); + UNUSED(gtsdirmask); + 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) { @@ -1601,19 +1743,31 @@ 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 */ + 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 + * 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++; @@ -1622,69 +1776,101 @@ 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 - */ + /* Check the superframe structure and update the appropriate attributes. */ - if (numgtsdesc > 0) + if (memcmp(&priv->sfspec, &beacon->pandesc.sfspec, + sizeof(struct ieee802154_superframespec_s)) != 0) { - gtsdirmask = IEEE802154_GETGTSDIRMASK(iob->io_data, iob->io_offset); - iob->io_offset++; + /* Copy in the new superframe spec */ - for (i = 0; i < numgtsdesc; i++) - { - /* For now we just discard the data by skipping over it */ + memcpy(&priv->sfspec, &beacon->pandesc.sfspec, + sizeof(struct ieee802154_superframespec_s)); - iob->io_offset += 3; - } + /* Tell the radio layer about the superframe spec update */ + + priv->radio->sfupdate(priv->radio, &priv->sfspec); } - /* 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. + /* 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. */ - for (i = 0; i < npendsaddr; i++) + if (priv->curr_op == MAC802154_OP_ASSOC && pending_eaddr) { - /* If the short address matches our short address */ + priv->curr_cmd = IEEE802154_CMD_DATA_REQ; + mac802154_txdesc_alloc(priv, &respdesc, false); + mac802154_createdatareq(priv, &priv->pandesc.coordaddr, + IEEE802154_ADDRMODE_EXTENDED, respdesc); - 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; + /* 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); } - - for (i = 0; i < npendeaddr; i++) + else { - /* If the extended address matches our extended address */ - - if (IEEE802154_EADDRCMP(&iob->io_data[iob->io_offset], priv->addr.eaddr)) + if (priv->autoreq || priv->curr_op == MAC802154_OP_POLL) { - /* If we are associating, polling, or if macAutoRequest is TRUE, - * extract the data. + /* 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 ((priv->autoreq) || (priv->curr_op == MAC802154_OP_ASSOC) || - (priv->curr_op == MAC802154_OP_POLL)) + if (beacon->payloadlength > 0) + { + /* Unlock the MAC, notify, then lock again */ + + mac802154_unlock(priv) + mac802154_notify(priv, notif); + mac802154_lock(priv, 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); - mac802154_createdatareq(priv, &priv->pandesc.coordaddr, - IEEE802154_ADDRMODE_EXTENDED, respdesc); - - if (priv->curr_op == MAC802154_OP_ASSOC || - priv->curr_op == MAC802154_OP_POLL) + if (priv->curr_op == MAC802154_OP_POLL) { 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); + 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 */ @@ -1694,146 +1880,39 @@ static void mac802154_rxbeaconframe(FAR struct ieee802154_privmac_s *priv, 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; + } } - iob->io_offset += IEEE802154_EADDRSIZE; - } + 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 + */ - /* TODO: Process incoming beacon payload - * If there is anything left in the frame, process it as the beacon payload - */ + /* Unlock the MAC, notify, then lock again */ - /* Check the superframe structure and update the appropriate attributes. */ - - if (memcmp(&priv->sfspec, &pandesc.sfspec, - sizeof(struct ieee802154_superframespec_s)) != 0) - { - /* Copy in the new superframe spec */ - - memcpy(&priv->sfspec, &pandesc.sfspec, - sizeof(struct ieee802154_superframespec_s)); - - /* Tell the radio layer about the superframe spec update */ - - priv->radio->sfupdate(priv->radio, &pandesc.sfspec); + mac802154_unlock(priv) + mac802154_notify(priv, notif); + mac802154_lock(priv, false); + return; /* Return so that we don't free the notificaiton */ + } } } -} -/**************************************************************************** - * Name: mac802154_symtoticks - * - * Description: - * Helper function for converting symbols to system clock ticks - * - * Assumptions: - * priv MAC struct is locked when calling. - * - ****************************************************************************/ + mac802154_notif_free_locked(priv, notif); + return; -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->get_attr(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); - - work_queue(MAC802154_WORK, &priv->timeout_work, (worker_t)priv->timeout_worker, - priv, 0); +errout: + wlwarn("Received beacon with bad format\n"); + mac802154_notif_free_locked(priv, notif); } /**************************************************************************** @@ -1879,6 +1958,7 @@ MACHANDLE mac802154_create(FAR struct ieee802154_radio_s *radiodev) if (mac == NULL) { + wlinfo("Failed allocation privmac structure\n"); return NULL; } @@ -1890,16 +1970,10 @@ 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; - mac802154_req_reset((MACHANDLE)mac, true); - /* Initialize the Radio callbacks */ mac->radiocb.priv = mac; @@ -1919,6 +1993,8 @@ 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++) @@ -1926,9 +2002,7 @@ MACHANDLE mac802154_create(FAR struct ieee802154_radio_s *radiodev) eaddr[i] = (CONFIG_IEEE802154_DEFAULT_EADDR >> (8 * i)) & 0xFF; } - IEEE802154_EADDRCOPY(mac->addr.eaddr, eaddr); - mac->radio->set_attr(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.h b/wireless/ieee802154/mac802154.h index 90ff021952..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 @@ -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..b72ba08556 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 @@ -86,8 +86,8 @@ 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; if (req->coordaddr.mode == IEEE802154_ADDRMODE_NONE) { @@ -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); @@ -127,27 +127,22 @@ 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); /* 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); + } - /* 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->set_attr(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 */ @@ -165,7 +160,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; } @@ -250,13 +245,67 @@ 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); + mac802154_unlock(priv) return OK; } @@ -351,7 +400,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); @@ -364,7 +413,7 @@ int mac802154_resp_associate(MACHANDLE mac, if (ret < 0) { iob_free(iob); - mac802154_givesem(&priv->exclsem); + mac802154_unlock(priv) return ret; } @@ -377,7 +426,7 @@ int mac802154_resp_associate(MACHANDLE mac, mac802154_setupindirect(priv, txdesc); - mac802154_givesem(&priv->exclsem); + mac802154_unlock(priv) return OK; } @@ -402,10 +451,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) { @@ -433,6 +481,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; @@ -441,9 +490,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 { @@ -467,17 +516,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); @@ -497,13 +562,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 +585,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. @@ -573,9 +633,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 { @@ -587,22 +647,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) + { - /* 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. - */ + /* 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); - privnotif->flink = priv->notif_free; - priv->notif_free = privnotif; - mac802154_givesem(&priv->notif_sem); } } @@ -624,7 +695,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 */ @@ -665,7 +736,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 */ @@ -673,7 +744,7 @@ void mac802154_rx_assocreq(FAR struct ieee802154_privmac_s *priv, return; errout_with_sem: - mac802154_givesem(&priv->exclsem); + mac802154_unlock(priv) return; } @@ -698,6 +769,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; } @@ -707,7 +791,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 */ @@ -720,7 +804,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 @@ -751,15 +835,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_unlock(priv) /* Notify the next highest layer of the association status */ @@ -779,10 +864,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 @@ -796,17 +893,19 @@ 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 */ + priv->curr_op = MAC802154_OP_NONE; priv->cmd_desc = NULL; mac802154_givesem(&priv->opsem); + mac802154_rxdisable(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..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. @@ -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 */ @@ -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 @@ -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_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_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 */ } diff --git a/wireless/ieee802154/mac802154_getset.c b/wireless/ieee802154/mac802154_getset.c index b1c29f7191..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->get_attr(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,54 +159,56 @@ 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 * 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_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_internal.h b/wireless/ieee802154/mac802154_internal.h index aa19f79f60..58301bca5a 100644 --- a/wireless/ieee802154/mac802154_internal.h +++ b/wireless/ieee802154/mac802154_internal.h @@ -1,706 +1,822 @@ -/**************************************************************************** - * 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 -}; - -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 */ - 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 - */ - - 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 ******************/ - - uint8_t bsn; /* Seq. num added to tx beacon frame */ - - /* 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. */ - - /* 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 helper macros ****************************************************/ - -#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; -} - -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; - 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->set_attr(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, - (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->set_attr(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->set_attr(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->set_attr(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->set_attr(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->set_attr(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->set_attr(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, - (FAR const union ieee802154_attr_u *)addr->saddr); -} - -#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, +}; + +/* 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 purge_work; + struct work_s timer_work; + + /****************** Uncategorized MAC PIB attributes ***********************/ + + /* 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); + +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; +} + +#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__) + +static inline int mac802154_lockpriv(FAR struct ieee802154_privmac_s *dev, + bool allowinterrupt, FAR const char *funcname) +{ + int ret; + +#ifdef CONFIG_MAC802154_LOCK_VERBOSE + wlinfo("Locking MAC: %s\n", funcname); +#endif + ret = mac802154_takesem(&dev->exclsem, allowinterrupt); + if (ret < 0) + { + wlwarn("Failed to lock MAC\n"); + } + else + { +#ifdef CONFIG_MAC802154_LOCK_VERBOSE + wlinfo("MAC locked\n"); +#endif + } + + 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_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 + * + * 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) +{ + work_cancel(MAC802154_WORK, &priv->timer_work); + 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); + } + + 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_DEVMODE, + (FAR const union ieee802154_attr_u *)&mode); +} + +#endif /* __WIRELESS_IEEE802154__MAC802154_INTERNAL_H */ diff --git a/wireless/ieee802154/mac802154_ioctl.c b/wireless/ieee802154/mac802154_ioctl.c index 35093f6936..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 */ @@ -124,7 +122,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_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) { } diff --git a/wireless/ieee802154/mac802154_notif.c b/wireless/ieee802154/mac802154_notif.c index bce299c139..0d2727c0e1 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); + mac802154_lock(priv, 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; + /* Unlock the MAC */ - mac802154_givesem(&priv->notif_sem); - } - else - { - /* More calls are expected. Decrement the count of expected calls - * and preserve the notification resources. - */ - - priv->nnotif--; - } - - mac802154_givesem(&priv->exclsem); - return -ENOTTY; + mac802154_unlock(priv) } /**************************************************************************** @@ -184,15 +162,15 @@ 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 { /* 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 @@ -211,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); @@ -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_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_poll.c b/wireless/ieee802154/mac802154_poll.c index e2881a397a..a7d61f4a0d 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 @@ -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; } @@ -152,13 +152,15 @@ 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); /* 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 */ @@ -188,9 +190,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. @@ -223,9 +224,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 { @@ -245,13 +246,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); } } @@ -264,17 +261,29 @@ 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. * 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 */ @@ -284,7 +293,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_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_reset.c b/wireless/ieee802154/mac802154_reset.c index 759a44e31e..a573df21c8 100644 --- a/wireless/ieee802154/mac802154_reset.c +++ b/wireless/ieee802154/mac802154_reset.c @@ -74,40 +74,38 @@ * * 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 */ - 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 */ -#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) */ - 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; @@ -125,35 +123,19 @@ 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; - /* 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; } - - 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 diff --git a/wireless/ieee802154/mac802154_scan.c b/wireless/ieee802154/mac802154_scan.c index d333d72d3c..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 @@ -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 */ @@ -108,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); @@ -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]); @@ -182,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; @@ -201,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; @@ -229,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); } @@ -247,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 */ diff --git a/wireless/ieee802154/mac802154_start.c b/wireless/ieee802154/mac802154_start.c index b3675393e2..c19026d589 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; @@ -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 @@ -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; @@ -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 +} 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; }