Merge branch 'beacon802154'

This commit is contained in:
Gregory Nutt 2017-07-20 08:36:13 -06:00
commit 4fde6fc654
50 changed files with 4630 additions and 3593 deletions

View File

@ -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

View File

@ -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

View File

@ -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__

View File

@ -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,

View File

@ -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

View File

@ -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 <gnutt@nuttx.org>
#
# 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

View File

@ -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

View File

@ -0,0 +1,48 @@
############################################################################
# drivers/ieee802154/at86rf23x/Make.defs
#
# Copyright (C) 2016-2017 Gregory Nutt. All rights reserved.
# Author: Gregory Nutt <gnutt@nuttx.org>
#
# 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

View File

@ -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 <matt@poppe.me>
@ -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;

View File

@ -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 <matt@poppe.me>
@ -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 */

File diff suppressed because it is too large Load Diff

View File

@ -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

View File

@ -0,0 +1,49 @@
############################################################################
# drivers/ieee802154/mrf24j40/Make.defs
#
# Copyright (C) 2016-2017 Gregory Nutt. All rights reserved.
# Author: Gregory Nutt <gnutt@nuttx.org>
#
# 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

View File

@ -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 <sebastien@lorquet.fr>
* Author: Anthony Merlino <anthony@vergeaero.com>
*
* 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 <nuttx/config.h>
#include <assert.h>
#include <debug.h>
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <errno.h>
#include <semaphore.h>
#include <sys/types.h>
#include <nuttx/kmalloc.h>
#include <nuttx/wqueue.h>
#include <nuttx/semaphore.h>
#include <nuttx/mm/iob.h>
#include <nuttx/wireless/ieee802154/mrf24j40.h>
#include <nuttx/wireless/ieee802154/ieee802154_radio.h>
#include <nuttx/wireless/ieee802154/ieee802154_mac.h>
#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;
}

View File

@ -0,0 +1,227 @@
/****************************************************************************
* drivers/wireless/ieee802154/mrf24j40/mrf24j40.h
*
* Copyright (C) 2015-2016 Sebastien Lorquet. All rights reserved.
* Author: Sebastien Lorquet <sebastien@lorquet.fr>
*
* 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 <nuttx/config.h>
#include <stdint.h>
#include <stdbool.h>
#include <semaphore.h>
#include <nuttx/wqueue.h>
#include <nuttx/spi/spi.h>
#include <nuttx/wireless/ieee802154/ieee802154_mac.h>
#include <nuttx/wireless/ieee802154/ieee802154_radio.h>
/****************************************************************************
* 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 */

View File

@ -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 <sebastien@lorquet.fr>
* Author: Anthony Merlino <anthony@vergeaero.com>
*
* 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 <nuttx/config.h>
#include <assert.h>
#include <debug.h>
#include <nuttx/arch.h>
#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;
}

View File

@ -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 <sebastien@lorquet.fr>
* Author: Anthony Merlino <anthony@vergeaero.com>
*
* 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 */

View File

@ -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 <sebastien@lorquet.fr>
* Author: Anthony Merlino <anthony@vergeaero.com>
*
* 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 <nuttx/config.h>
#include <assert.h>
#include <debug.h>
#include <nuttx/mm/iob.h>
#include <nuttx/wireless/ieee802154/mrf24j40.h>
#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);
}

View File

@ -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 <sebastien@lorquet.fr>
* Author: Anthony Merlino <anthony@vergeaero.com>
*
* 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 <nuttx/config.h>
#include <assert.h>
#include <debug.h>
#include <stdint.h>
#include <stdbool.h>
#include <string.h>
#include <semaphore.h>
#include <nuttx/arch.h>
#include <nuttx/wireless/ieee802154/ieee802154_radio.h>
#include <nuttx/wireless/ieee802154/ieee802154_mac.h>
#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;
}

View File

@ -0,0 +1,72 @@
/****************************************************************************
* drivers/wireless/ieee802154/mrf24j40/mrf24j40_radif.h
*
* Copyright (C) 2017 Verge Inc. All rights reserved.
* Author: Anthony Merlino <anthony@vergeaero.com>
*
* 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 */

View File

@ -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 <sebastien@lorquet.fr>
* Author: Anthony Merlino <anthony@vergeaero.com>
*
* 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 */

View File

@ -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 <sebastien@lorquet.fr>
* Author: Anthony Merlino <anthony@vergeaero.com>
*
* 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 <nuttx/config.h>
#include <assert.h>
#include <debug.h>
#include <stdio.h>
#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;
}

View File

@ -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 <sebastien@lorquet.fr>
* Author: Anthony Merlino <anthony@vergeaero.com>
*
* 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 */

View File

@ -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

View File

@ -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);

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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 = &notif->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, &notif, false);
beacon = &notif->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;
}

View File

@ -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

View File

@ -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, &notif, 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;

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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 */
}

View File

@ -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;
}

View File

@ -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;
}

File diff suppressed because it is too large Load Diff

View File

@ -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:

View File

@ -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)
{
}

View File

@ -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 */

View File

@ -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 */

View File

@ -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;
}

View File

@ -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, &notif, 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;

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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, &notif, 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 */

View File

@ -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;
}
}

View File

@ -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;
}