diff --git a/Kconfig b/Kconfig index 451b22206d..d2157939e8 100644 --- a/Kconfig +++ b/Kconfig @@ -756,7 +756,7 @@ config DEBUG_WIRELESS default n depends on WIRELESS || DRIVERS_WIRELESS ---help--- - Enable DEBUG_WIRELESS debug features. + Enable wireless debug features. if DEBUG_WIRELESS diff --git a/configs/clicker2-stm32/Kconfig b/configs/clicker2-stm32/Kconfig index 1ca0fbc9ee..9344f015da 100644 --- a/configs/clicker2-stm32/Kconfig +++ b/configs/clicker2-stm32/Kconfig @@ -19,4 +19,20 @@ config CLICKER2_STM32_MB2_SPI ---help--- Enable SPI support on mikroBUS1 (STM32 SPI2) +config CLICKER2_STM32_MB1_BEE + bool "mikroBUS1 MRF24J40 BEE" + default y + depends on IEEE802154_MRF24J40 + select CLICKER2_STM32_MB1_SPI + ---help--- + Enable support for MRF24J40 BEE on mikroBUS1 + +config CLICKER2_STM32_MB2_BEE + bool "mikroBUS2 MRF24J40 BEE" + default n + depends on IEEE802154_MRF24J40 + select CLICKER2_STM32_MB2_SPI + ---help--- + Enable support for MRF24J40 BEE on mikroBUS2 + endif # ARCH_BOARD_CLICKER2_STM32 diff --git a/configs/clicker2-stm32/README.txt b/configs/clicker2-stm32/README.txt index bcc2cc93f6..d2892192e8 100644 --- a/configs/clicker2-stm32/README.txt +++ b/configs/clicker2-stm32/README.txt @@ -304,6 +304,48 @@ Configurations If you do this a lot, you will probably want to invest a little time to develop a tool to automate these steps. + mrf24j40-radio + + This is a version of nsh that was used for testing the MRF24J40 be as a + character device. The most important configuration differences are + summarized below: + + 1. Support for the BEE click and SPI are in enabled in the mikroBUS1 slot: + + CONFIG_CLICKER2_STM32_MB1_BEE=y + CONFIG_CLICKER2_STM32_MB1_SPI=y + + 2. SPI support and STM32 SPI3, in particular, are enabled: + + CONFIG_SPI=y + CONFIG_SPI_EXCHANGE=y + + CONFIG_STM32_SPI=y + CONFIG_STM32_SPI3=y + + 4. Support for the IEEE802.15.4 "upper half" character driver is enabled: + + CONFIG_WIRELESS=y + CONFIG_WIRELESS_IEEE802154=y + CONFIG_IEEE802154_DEV=y + + 5. Support for the lower half MRF24J40 character driver is enabled + + CONFIG_DRIVERS_WIRELESS=y + CONFIG_DRIVERS_IEEE802154=y + CONFIG_IEEE802154_MRF24J40=y + + 6. Support for the test program at apps/ieee802154 is enabled: + + CONFIG_IEEE802154_COMMON=y + CONFIG_IEEE802154_COORD=y + CONFIG_IEEE802154_I8SAK=y + + 7. Initialization hooks are provided to enable the MRF24J40 and to + register the radio character driver. + + CONFIG_NSH_ARCHINIT=y + nsh: Configures the NuttShell (nsh) located at examples/nsh. This diff --git a/configs/clicker2-stm32/mrf24j40-radio/Make.defs b/configs/clicker2-stm32/mrf24j40-radio/Make.defs new file mode 100644 index 0000000000..4aa245f38b --- /dev/null +++ b/configs/clicker2-stm32/mrf24j40-radio/Make.defs @@ -0,0 +1,122 @@ +############################################################################ +# configs/clicker2-stm32/mrf24j40-radio/Make.defs +# +# Copyright (C) 2017 Gregory Nutt. All rights reserved. +# Author: Gregory Nutt +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# 3. Neither the name NuttX nor the names of its contributors may be +# used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS +# OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED +# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# +############################################################################ + +include ${TOPDIR}/.config +include ${TOPDIR}/tools/Config.mk +include ${TOPDIR}/arch/arm/src/armv7-m/Toolchain.defs + +LDSCRIPT = flash.ld + +ifeq ($(WINTOOL),y) + # Windows-native toolchains + DIRLINK = $(TOPDIR)/tools/copydir.sh + DIRUNLINK = $(TOPDIR)/tools/unlink.sh + MKDEP = $(TOPDIR)/tools/mkwindeps.sh + ARCHINCLUDES = -I. -isystem "${shell cygpath -w $(TOPDIR)/include}" + ARCHXXINCLUDES = -I. -isystem "${shell cygpath -w $(TOPDIR)/include}" -isystem "${shell cygpath -w $(TOPDIR)/include/cxx}" + ARCHSCRIPT = -T "${shell cygpath -w $(TOPDIR)/configs/$(CONFIG_ARCH_BOARD)/scripts/$(LDSCRIPT)}" +else + # Linux/Cygwin-native toolchain + MKDEP = $(TOPDIR)/tools/mkdeps$(HOSTEXEEXT) + ARCHINCLUDES = -I. -isystem $(TOPDIR)/include + ARCHXXINCLUDES = -I. -isystem $(TOPDIR)/include -isystem $(TOPDIR)/include/cxx + ARCHSCRIPT = -T$(TOPDIR)/configs/$(CONFIG_ARCH_BOARD)/scripts/$(LDSCRIPT) +endif + +CC = $(CROSSDEV)gcc +CXX = $(CROSSDEV)g++ +CPP = $(CROSSDEV)gcc -E +LD = $(CROSSDEV)ld +AR = $(CROSSDEV)ar rcs +NM = $(CROSSDEV)nm +OBJCOPY = $(CROSSDEV)objcopy +OBJDUMP = $(CROSSDEV)objdump + +ARCHCCVERSION = ${shell $(CC) -v 2>&1 | sed -n '/^gcc version/p' | sed -e 's/^gcc version \([0-9\.]\)/\1/g' -e 's/[-\ ].*//g' -e '1q'} +ARCHCCMAJOR = ${shell echo $(ARCHCCVERSION) | cut -d'.' -f1} + +ifeq ($(CONFIG_DEBUG_SYMBOLS),y) + ARCHOPTIMIZATION = -g +endif + +ifneq ($(CONFIG_DEBUG_NOOPT),y) + ARCHOPTIMIZATION += $(MAXOPTIMIZATION) -fno-strict-aliasing -fno-strength-reduce -fomit-frame-pointer +endif + +ARCHCFLAGS = -fno-builtin +ARCHCXXFLAGS = -fno-builtin -fno-exceptions -fcheck-new -fno-rtti +ARCHWARNINGS = -Wall -Wstrict-prototypes -Wshadow -Wundef +ARCHWARNINGSXX = -Wall -Wshadow -Wundef +ARCHDEFINES = +ARCHPICFLAGS = -fpic -msingle-pic-base -mpic-register=r10 + +CFLAGS = $(ARCHCFLAGS) $(ARCHWARNINGS) $(ARCHOPTIMIZATION) $(ARCHCPUFLAGS) $(ARCHINCLUDES) $(ARCHDEFINES) $(EXTRADEFINES) -pipe +CPICFLAGS = $(ARCHPICFLAGS) $(CFLAGS) +CXXFLAGS = $(ARCHCXXFLAGS) $(ARCHWARNINGSXX) $(ARCHOPTIMIZATION) $(ARCHCPUFLAGS) $(ARCHXXINCLUDES) $(ARCHDEFINES) $(EXTRADEFINES) -pipe +CXXPICFLAGS = $(ARCHPICFLAGS) $(CXXFLAGS) +CPPFLAGS = $(ARCHINCLUDES) $(ARCHDEFINES) $(EXTRADEFINES) +AFLAGS = $(CFLAGS) -D__ASSEMBLY__ + +NXFLATLDFLAGS1 = -r -d -warn-common +NXFLATLDFLAGS2 = $(NXFLATLDFLAGS1) -T$(TOPDIR)/binfmt/libnxflat/gnu-nxflat-gotoff.ld -no-check-sections +LDNXFLATFLAGS = -e main -s 2048 + +# Loadable module definitions + +CMODULEFLAGS = $(CFLAGS) -mlong-calls # --target1-abs + +LDMODULEFLAGS = -r -e module_initialize +ifeq ($(WINTOOL),y) + LDMODULEFLAGS += -T "${shell cygpath -w $(TOPDIR)/libc/modlib/gnu-elf.ld}" +else + LDMODULEFLAGS += -T $(TOPDIR)/libc/modlib/gnu-elf.ld +endif + +ASMEXT = .S +OBJEXT = .o +LIBEXT = .a +EXEEXT = + +ifneq ($(CROSSDEV),arm-nuttx-elf-) + LDFLAGS += -nostartfiles -nodefaultlibs +endif +ifeq ($(CONFIG_DEBUG_SYMBOLS),y) + LDFLAGS += -g +endif + +HOSTCC = gcc +HOSTINCLUDES = -I. +HOSTCFLAGS = -Wall -Wstrict-prototypes -Wshadow -Wundef -g -pipe +HOSTLDFLAGS = diff --git a/configs/clicker2-stm32/mrf24j40-radio/defconfig b/configs/clicker2-stm32/mrf24j40-radio/defconfig new file mode 100644 index 0000000000..33284b022c --- /dev/null +++ b/configs/clicker2-stm32/mrf24j40-radio/defconfig @@ -0,0 +1,1355 @@ +# +# Automatically generated file; DO NOT EDIT. +# Nuttx/ Configuration +# + +# +# Build Setup +# +# CONFIG_EXPERIMENTAL is not set +# CONFIG_DEFAULT_SMALL is not set +CONFIG_HOST_LINUX=y +# CONFIG_HOST_OSX is not set +# CONFIG_HOST_WINDOWS is not set +# CONFIG_HOST_OTHER is not set + +# +# Build Configuration +# +# CONFIG_APPS_DIR="../apps" +CONFIG_BUILD_FLAT=y +# CONFIG_BUILD_2PASS is not set + +# +# Binary Output Formats +# +# CONFIG_RRLOAD_BINARY is not set +CONFIG_INTELHEX_BINARY=y +# CONFIG_MOTOROLA_SREC is not set +CONFIG_RAW_BINARY=y +# CONFIG_UBOOT_UIMAGE is not set + +# +# Customize Header Files +# +# CONFIG_ARCH_STDINT_H is not set +# CONFIG_ARCH_STDBOOL_H is not set +# CONFIG_ARCH_MATH_H is not set +# CONFIG_ARCH_FLOAT_H is not set +# CONFIG_ARCH_STDARG_H is not set +# CONFIG_ARCH_DEBUG_H is not set + +# +# Debug Options +# +CONFIG_DEBUG_ALERT=y +# CONFIG_DEBUG_FEATURES is not set +CONFIG_ARCH_HAVE_STACKCHECK=y +# CONFIG_STACK_COLORATION is not set +CONFIG_ARCH_HAVE_HEAPCHECK=y +# CONFIG_HEAP_COLORATION is not set +# CONFIG_DEBUG_SYMBOLS is not set +CONFIG_ARCH_HAVE_CUSTOMOPT=y +# CONFIG_DEBUG_NOOPT is not set +# CONFIG_DEBUG_CUSTOMOPT is not set +CONFIG_DEBUG_FULLOPT=y + +# +# System Type +# +CONFIG_ARCH_ARM=y +# CONFIG_ARCH_AVR is not set +# CONFIG_ARCH_HC is not set +# CONFIG_ARCH_MIPS is not set +# CONFIG_ARCH_MISOC is not set +# CONFIG_ARCH_RENESAS is not set +# CONFIG_ARCH_RISCV is not set +# CONFIG_ARCH_SIM is not set +# CONFIG_ARCH_X86 is not set +# CONFIG_ARCH_XTENSA is not set +# CONFIG_ARCH_Z16 is not set +# CONFIG_ARCH_Z80 is not set +CONFIG_ARCH="arm" + +# +# ARM Options +# +# CONFIG_ARCH_CHIP_A1X is not set +# CONFIG_ARCH_CHIP_C5471 is not set +# CONFIG_ARCH_CHIP_DM320 is not set +# CONFIG_ARCH_CHIP_EFM32 is not set +# CONFIG_ARCH_CHIP_IMX1 is not set +# CONFIG_ARCH_CHIP_IMX6 is not set +# CONFIG_ARCH_CHIP_KINETIS is not set +# CONFIG_ARCH_CHIP_KL is not set +# CONFIG_ARCH_CHIP_LM is not set +# CONFIG_ARCH_CHIP_TIVA is not set +# CONFIG_ARCH_CHIP_LPC11XX is not set +# CONFIG_ARCH_CHIP_LPC17XX is not set +# CONFIG_ARCH_CHIP_LPC214X is not set +# CONFIG_ARCH_CHIP_LPC2378 is not set +# CONFIG_ARCH_CHIP_LPC31XX is not set +# CONFIG_ARCH_CHIP_LPC43XX is not set +# CONFIG_ARCH_CHIP_MOXART is not set +# CONFIG_ARCH_CHIP_NUC1XX is not set +# CONFIG_ARCH_CHIP_SAMA5 is not set +# CONFIG_ARCH_CHIP_SAMD is not set +# CONFIG_ARCH_CHIP_SAML is not set +# CONFIG_ARCH_CHIP_SAM34 is not set +# CONFIG_ARCH_CHIP_SAMV7 is not set +CONFIG_ARCH_CHIP_STM32=y +# CONFIG_ARCH_CHIP_STM32F7 is not set +# CONFIG_ARCH_CHIP_STM32L4 is not set +# CONFIG_ARCH_CHIP_STR71X is not set +# CONFIG_ARCH_CHIP_TMS570 is not set +# CONFIG_ARCH_CHIP_XMC4 is not set +# CONFIG_ARCH_ARM7TDMI is not set +# CONFIG_ARCH_ARM926EJS is not set +# CONFIG_ARCH_ARM920T is not set +# CONFIG_ARCH_CORTEXM0 is not set +# CONFIG_ARCH_CORTEXM23 is not set +# CONFIG_ARCH_CORTEXM3 is not set +# CONFIG_ARCH_CORTEXM33 is not set +CONFIG_ARCH_CORTEXM4=y +# CONFIG_ARCH_CORTEXM7 is not set +# CONFIG_ARCH_CORTEXA5 is not set +# CONFIG_ARCH_CORTEXA8 is not set +# CONFIG_ARCH_CORTEXA9 is not set +# CONFIG_ARCH_CORTEXR4 is not set +# CONFIG_ARCH_CORTEXR4F is not set +# CONFIG_ARCH_CORTEXR5 is not set +# CONFIG_ARCH_CORTEX5F is not set +# CONFIG_ARCH_CORTEXR7 is not set +# CONFIG_ARCH_CORTEXR7F is not set +CONFIG_ARCH_FAMILY="armv7-m" +CONFIG_ARCH_CHIP="stm32" +# CONFIG_ARM_TOOLCHAIN_IAR is not set +CONFIG_ARM_TOOLCHAIN_GNU=y +# CONFIG_ARMV7M_USEBASEPRI is not set +CONFIG_ARCH_HAVE_CMNVECTOR=y +# CONFIG_ARMV7M_CMNVECTOR is not set +# CONFIG_ARMV7M_LAZYFPU is not set +CONFIG_ARCH_HAVE_FPU=y +# CONFIG_ARCH_HAVE_DPFPU is not set +CONFIG_ARCH_FPU=y +# CONFIG_ARCH_HAVE_TRUSTZONE is not set +CONFIG_ARM_HAVE_MPU_UNIFIED=y +# CONFIG_ARM_MPU is not set + +# +# ARMV7M Configuration Options +# +# CONFIG_ARMV7M_HAVE_ICACHE is not set +# CONFIG_ARMV7M_HAVE_DCACHE is not set +# CONFIG_ARMV7M_HAVE_ITCM is not set +# CONFIG_ARMV7M_HAVE_DTCM is not set +# CONFIG_ARMV7M_TOOLCHAIN_IARL is not set +# CONFIG_ARMV7M_TOOLCHAIN_BUILDROOT is not set +# CONFIG_ARMV7M_TOOLCHAIN_CODEREDL is not set +# CONFIG_ARMV7M_TOOLCHAIN_CODESOURCERYL is not set +CONFIG_ARMV7M_TOOLCHAIN_GNU_EABIL=y +CONFIG_ARMV7M_HAVE_STACKCHECK=y +# CONFIG_ARMV7M_STACKCHECK is not set +# CONFIG_ARMV7M_ITMSYSLOG is not set +# CONFIG_SERIAL_TERMIOS is not set + +# +# STM32 Configuration Options +# +# CONFIG_ARCH_CHIP_STM32L151C6 is not set +# CONFIG_ARCH_CHIP_STM32L151C8 is not set +# CONFIG_ARCH_CHIP_STM32L151CB is not set +# CONFIG_ARCH_CHIP_STM32L151R6 is not set +# CONFIG_ARCH_CHIP_STM32L151R8 is not set +# CONFIG_ARCH_CHIP_STM32L151RB is not set +# CONFIG_ARCH_CHIP_STM32L151V6 is not set +# CONFIG_ARCH_CHIP_STM32L151V8 is not set +# CONFIG_ARCH_CHIP_STM32L151VB is not set +# CONFIG_ARCH_CHIP_STM32L152C6 is not set +# CONFIG_ARCH_CHIP_STM32L152C8 is not set +# CONFIG_ARCH_CHIP_STM32L152CB is not set +# CONFIG_ARCH_CHIP_STM32L152R6 is not set +# CONFIG_ARCH_CHIP_STM32L152R8 is not set +# CONFIG_ARCH_CHIP_STM32L152RB is not set +# CONFIG_ARCH_CHIP_STM32L152V6 is not set +# CONFIG_ARCH_CHIP_STM32L152V8 is not set +# CONFIG_ARCH_CHIP_STM32L152VB is not set +# CONFIG_ARCH_CHIP_STM32L162ZD is not set +# CONFIG_ARCH_CHIP_STM32L162VE is not set +# CONFIG_ARCH_CHIP_STM32F100C8 is not set +# CONFIG_ARCH_CHIP_STM32F100CB is not set +# CONFIG_ARCH_CHIP_STM32F100R8 is not set +# CONFIG_ARCH_CHIP_STM32F100RB is not set +# CONFIG_ARCH_CHIP_STM32F100RC is not set +# CONFIG_ARCH_CHIP_STM32F100RD is not set +# CONFIG_ARCH_CHIP_STM32F100RE is not set +# CONFIG_ARCH_CHIP_STM32F100V8 is not set +# CONFIG_ARCH_CHIP_STM32F100VB is not set +# CONFIG_ARCH_CHIP_STM32F100VC is not set +# CONFIG_ARCH_CHIP_STM32F100VD is not set +# CONFIG_ARCH_CHIP_STM32F100VE is not set +# CONFIG_ARCH_CHIP_STM32F102CB is not set +# CONFIG_ARCH_CHIP_STM32F103T8 is not set +# CONFIG_ARCH_CHIP_STM32F103TB is not set +# CONFIG_ARCH_CHIP_STM32F103C4 is not set +# CONFIG_ARCH_CHIP_STM32F103C8 is not set +# CONFIG_ARCH_CHIP_STM32F103CB is not set +# CONFIG_ARCH_CHIP_STM32F103R8 is not set +# CONFIG_ARCH_CHIP_STM32F103RB is not set +# CONFIG_ARCH_CHIP_STM32F103RC is not set +# CONFIG_ARCH_CHIP_STM32F103RD is not set +# CONFIG_ARCH_CHIP_STM32F103RE is not set +# CONFIG_ARCH_CHIP_STM32F103RG is not set +# CONFIG_ARCH_CHIP_STM32F103V8 is not set +# CONFIG_ARCH_CHIP_STM32F103VB is not set +# CONFIG_ARCH_CHIP_STM32F103VC is not set +# CONFIG_ARCH_CHIP_STM32F103VE is not set +# CONFIG_ARCH_CHIP_STM32F103ZE is not set +# CONFIG_ARCH_CHIP_STM32F105VB is not set +# CONFIG_ARCH_CHIP_STM32F105RB is not set +# CONFIG_ARCH_CHIP_STM32F107VC is not set +# CONFIG_ARCH_CHIP_STM32F205RG is not set +# CONFIG_ARCH_CHIP_STM32F207IG is not set +# CONFIG_ARCH_CHIP_STM32F207ZE is not set +# CONFIG_ARCH_CHIP_STM32F302K6 is not set +# CONFIG_ARCH_CHIP_STM32F302K8 is not set +# CONFIG_ARCH_CHIP_STM32F302CB is not set +# CONFIG_ARCH_CHIP_STM32F302CC is not set +# CONFIG_ARCH_CHIP_STM32F302RB is not set +# CONFIG_ARCH_CHIP_STM32F302RC is not set +# CONFIG_ARCH_CHIP_STM32F302VB is not set +# CONFIG_ARCH_CHIP_STM32F302VC is not set +# CONFIG_ARCH_CHIP_STM32F303K6 is not set +# CONFIG_ARCH_CHIP_STM32F303K8 is not set +# CONFIG_ARCH_CHIP_STM32F303C6 is not set +# CONFIG_ARCH_CHIP_STM32F303C8 is not set +# CONFIG_ARCH_CHIP_STM32F303CB is not set +# CONFIG_ARCH_CHIP_STM32F303CC is not set +# CONFIG_ARCH_CHIP_STM32F303RB is not set +# CONFIG_ARCH_CHIP_STM32F303RC is not set +# CONFIG_ARCH_CHIP_STM32F303RD is not set +# CONFIG_ARCH_CHIP_STM32F303RE is not set +# CONFIG_ARCH_CHIP_STM32F303VB is not set +# CONFIG_ARCH_CHIP_STM32F303VC is not set +# CONFIG_ARCH_CHIP_STM32F334K4 is not set +# CONFIG_ARCH_CHIP_STM32F334K6 is not set +# CONFIG_ARCH_CHIP_STM32F334K8 is not set +# CONFIG_ARCH_CHIP_STM32F334C4 is not set +# CONFIG_ARCH_CHIP_STM32F334C6 is not set +# CONFIG_ARCH_CHIP_STM32F334C8 is not set +# CONFIG_ARCH_CHIP_STM32F334R4 is not set +# CONFIG_ARCH_CHIP_STM32F334R6 is not set +# CONFIG_ARCH_CHIP_STM32F334R8 is not set +# CONFIG_ARCH_CHIP_STM32F372C8 is not set +# CONFIG_ARCH_CHIP_STM32F372R8 is not set +# CONFIG_ARCH_CHIP_STM32F372V8 is not set +# CONFIG_ARCH_CHIP_STM32F372CB is not set +# CONFIG_ARCH_CHIP_STM32F372RB is not set +# CONFIG_ARCH_CHIP_STM32F372VB is not set +# CONFIG_ARCH_CHIP_STM32F372CC is not set +# CONFIG_ARCH_CHIP_STM32F372RC is not set +# CONFIG_ARCH_CHIP_STM32F372VC is not set +# CONFIG_ARCH_CHIP_STM32F373C8 is not set +# CONFIG_ARCH_CHIP_STM32F373R8 is not set +# CONFIG_ARCH_CHIP_STM32F373V8 is not set +# CONFIG_ARCH_CHIP_STM32F373CB is not set +# CONFIG_ARCH_CHIP_STM32F373RB is not set +# CONFIG_ARCH_CHIP_STM32F373VB is not set +# CONFIG_ARCH_CHIP_STM32F373CC is not set +# CONFIG_ARCH_CHIP_STM32F373RC is not set +# CONFIG_ARCH_CHIP_STM32F373VC is not set +# CONFIG_ARCH_CHIP_STM32F401RE is not set +# CONFIG_ARCH_CHIP_STM32F411RE is not set +# CONFIG_ARCH_CHIP_STM32F411VE is not set +# CONFIG_ARCH_CHIP_STM32F405RG is not set +# CONFIG_ARCH_CHIP_STM32F405VG is not set +# CONFIG_ARCH_CHIP_STM32F405ZG is not set +# CONFIG_ARCH_CHIP_STM32F407VE is not set +CONFIG_ARCH_CHIP_STM32F407VG=y +# CONFIG_ARCH_CHIP_STM32F407ZE is not set +# CONFIG_ARCH_CHIP_STM32F407ZG is not set +# CONFIG_ARCH_CHIP_STM32F407IE is not set +# CONFIG_ARCH_CHIP_STM32F407IG is not set +# CONFIG_ARCH_CHIP_STM32F427V is not set +# CONFIG_ARCH_CHIP_STM32F427Z is not set +# CONFIG_ARCH_CHIP_STM32F427I is not set +# CONFIG_ARCH_CHIP_STM32F429V is not set +# CONFIG_ARCH_CHIP_STM32F429Z is not set +# CONFIG_ARCH_CHIP_STM32F429I is not set +# CONFIG_ARCH_CHIP_STM32F429B is not set +# CONFIG_ARCH_CHIP_STM32F429N is not set +# CONFIG_ARCH_CHIP_STM32F446M is not set +# CONFIG_ARCH_CHIP_STM32F446R is not set +# CONFIG_ARCH_CHIP_STM32F446V is not set +# CONFIG_ARCH_CHIP_STM32F446Z is not set +# CONFIG_ARCH_CHIP_STM32F469A is not set +# CONFIG_ARCH_CHIP_STM32F469I is not set +# CONFIG_ARCH_CHIP_STM32F469B is not set +# CONFIG_ARCH_CHIP_STM32F469N is not set +CONFIG_STM32_FLASH_CONFIG_DEFAULT=y +# CONFIG_STM32_FLASH_CONFIG_4 is not set +# CONFIG_STM32_FLASH_CONFIG_6 is not set +# CONFIG_STM32_FLASH_CONFIG_8 is not set +# CONFIG_STM32_FLASH_CONFIG_B is not set +# CONFIG_STM32_FLASH_CONFIG_C is not set +# CONFIG_STM32_FLASH_CONFIG_D is not set +# CONFIG_STM32_FLASH_CONFIG_E is not set +# CONFIG_STM32_FLASH_CONFIG_F is not set +# CONFIG_STM32_FLASH_CONFIG_G is not set +# CONFIG_STM32_FLASH_CONFIG_I is not set +# CONFIG_STM32_STM32L15XX is not set +# CONFIG_STM32_ENERGYLITE is not set +# CONFIG_STM32_STM32F10XX is not set +# CONFIG_STM32_VALUELINE is not set +# CONFIG_STM32_CONNECTIVITYLINE is not set +# CONFIG_STM32_PERFORMANCELINE is not set +# CONFIG_STM32_USBACCESSLINE is not set +# CONFIG_STM32_HIGHDENSITY is not set +# CONFIG_STM32_MEDIUMDENSITY is not set +# CONFIG_STM32_LOWDENSITY is not set +# CONFIG_STM32_STM32F20XX is not set +# CONFIG_STM32_STM32F205 is not set +# CONFIG_STM32_STM32F207 is not set +# CONFIG_STM32_STM32F30XX is not set +# CONFIG_STM32_STM32F302 is not set +# CONFIG_STM32_STM32F303 is not set +# CONFIG_STM32_STM32F33XX is not set +# CONFIG_STM32_STM32F37XX is not set +CONFIG_STM32_STM32F40XX=y +# CONFIG_STM32_STM32F401 is not set +# CONFIG_STM32_STM32F411 is not set +# CONFIG_STM32_STM32F405 is not set +CONFIG_STM32_STM32F407=y +# CONFIG_STM32_STM32F427 is not set +# CONFIG_STM32_STM32F429 is not set +# CONFIG_STM32_STM32F446 is not set +# CONFIG_STM32_STM32F469 is not set +# CONFIG_STM32_DFU is not set + +# +# STM32 Peripheral Support +# +CONFIG_STM32_HAVE_CCM=y +# CONFIG_STM32_HAVE_USBDEV is not set +CONFIG_STM32_HAVE_OTGFS=y +CONFIG_STM32_HAVE_FSMC=y +# CONFIG_STM32_HAVE_HRTIM1 is not set +# CONFIG_STM32_HAVE_LTDC is not set +CONFIG_STM32_HAVE_USART3=y +CONFIG_STM32_HAVE_UART4=y +CONFIG_STM32_HAVE_UART5=y +CONFIG_STM32_HAVE_USART6=y +# CONFIG_STM32_HAVE_UART7 is not set +# CONFIG_STM32_HAVE_UART8 is not set +CONFIG_STM32_HAVE_TIM1=y +CONFIG_STM32_HAVE_TIM2=y +CONFIG_STM32_HAVE_TIM3=y +CONFIG_STM32_HAVE_TIM4=y +CONFIG_STM32_HAVE_TIM5=y +CONFIG_STM32_HAVE_TIM6=y +CONFIG_STM32_HAVE_TIM7=y +CONFIG_STM32_HAVE_TIM8=y +CONFIG_STM32_HAVE_TIM9=y +CONFIG_STM32_HAVE_TIM10=y +CONFIG_STM32_HAVE_TIM11=y +CONFIG_STM32_HAVE_TIM12=y +CONFIG_STM32_HAVE_TIM13=y +CONFIG_STM32_HAVE_TIM14=y +# CONFIG_STM32_HAVE_TIM15 is not set +# CONFIG_STM32_HAVE_TIM16 is not set +# CONFIG_STM32_HAVE_TIM17 is not set +CONFIG_STM32_HAVE_ADC2=y +CONFIG_STM32_HAVE_ADC3=y +# CONFIG_STM32_HAVE_ADC4 is not set +# CONFIG_STM32_HAVE_ADC1_DMA is not set +# CONFIG_STM32_HAVE_ADC2_DMA is not set +# CONFIG_STM32_HAVE_ADC3_DMA is not set +# CONFIG_STM32_HAVE_ADC4_DMA is not set +# CONFIG_STM32_HAVE_SDADC1 is not set +# CONFIG_STM32_HAVE_SDADC2 is not set +# CONFIG_STM32_HAVE_SDADC3 is not set +# CONFIG_STM32_HAVE_SDADC1_DMA is not set +# CONFIG_STM32_HAVE_SDADC2_DMA is not set +# CONFIG_STM32_HAVE_SDADC3_DMA is not set +CONFIG_STM32_HAVE_CAN1=y +CONFIG_STM32_HAVE_CAN2=y +# CONFIG_STM32_HAVE_COMP1 is not set +# CONFIG_STM32_HAVE_COMP2 is not set +# CONFIG_STM32_HAVE_COMP3 is not set +# CONFIG_STM32_HAVE_COMP4 is not set +# CONFIG_STM32_HAVE_COMP5 is not set +# CONFIG_STM32_HAVE_COMP6 is not set +# CONFIG_STM32_HAVE_COMP7 is not set +CONFIG_STM32_HAVE_DAC1=y +CONFIG_STM32_HAVE_DAC2=y +CONFIG_STM32_HAVE_RNG=y +CONFIG_STM32_HAVE_ETHMAC=y +CONFIG_STM32_HAVE_I2C2=y +CONFIG_STM32_HAVE_I2C3=y +CONFIG_STM32_HAVE_SPI2=y +CONFIG_STM32_HAVE_SPI3=y +# CONFIG_STM32_HAVE_SPI4 is not set +# CONFIG_STM32_HAVE_SPI5 is not set +# CONFIG_STM32_HAVE_SPI6 is not set +# CONFIG_STM32_HAVE_SAIPLL is not set +# CONFIG_STM32_HAVE_I2SPLL is not set +# CONFIG_STM32_HAVE_OPAMP1 is not set +# CONFIG_STM32_HAVE_OPAMP2 is not set +# CONFIG_STM32_HAVE_OPAMP3 is not set +# CONFIG_STM32_HAVE_OPAMP4 is not set +# CONFIG_STM32_ADC1 is not set +# CONFIG_STM32_ADC2 is not set +# CONFIG_STM32_ADC3 is not set +# CONFIG_STM32_BKPSRAM is not set +# CONFIG_STM32_CAN1 is not set +# CONFIG_STM32_CAN2 is not set +# CONFIG_STM32_CCMDATARAM is not set +# CONFIG_STM32_CRC is not set +# CONFIG_STM32_CRYP is not set +# CONFIG_STM32_DMA1 is not set +# CONFIG_STM32_DMA2 is not set +# CONFIG_STM32_DAC1 is not set +# CONFIG_STM32_DAC2 is not set +# CONFIG_STM32_DCMI is not set +# CONFIG_STM32_ETHMAC is not set +# CONFIG_STM32_FSMC is not set +# CONFIG_STM32_HASH is not set +# CONFIG_STM32_I2C1 is not set +# CONFIG_STM32_I2C2 is not set +# CONFIG_STM32_I2C3 is not set +# CONFIG_STM32_OPAMP is not set +# CONFIG_STM32_OTGFS is not set +# CONFIG_STM32_OTGHS is not set +CONFIG_STM32_PWR=y +# CONFIG_STM32_RNG is not set +# CONFIG_STM32_SDIO is not set +# CONFIG_STM32_SPI1 is not set +# CONFIG_STM32_SPI2 is not set +CONFIG_STM32_SPI3=y +CONFIG_STM32_SYSCFG=y +# CONFIG_STM32_TIM1 is not set +# CONFIG_STM32_TIM2 is not set +# CONFIG_STM32_TIM3 is not set +# CONFIG_STM32_TIM4 is not set +# CONFIG_STM32_TIM5 is not set +# CONFIG_STM32_TIM6 is not set +# CONFIG_STM32_TIM7 is not set +# CONFIG_STM32_TIM8 is not set +# CONFIG_STM32_TIM9 is not set +# CONFIG_STM32_TIM10 is not set +# CONFIG_STM32_TIM11 is not set +# CONFIG_STM32_TIM12 is not set +# CONFIG_STM32_TIM13 is not set +# CONFIG_STM32_TIM14 is not set +# CONFIG_STM32_USART1 is not set +# CONFIG_STM32_USART2 is not set +CONFIG_STM32_USART3=y +# CONFIG_STM32_UART4 is not set +# CONFIG_STM32_UART5 is not set +# CONFIG_STM32_USART6 is not set +# CONFIG_STM32_IWDG is not set +# CONFIG_STM32_WWDG is not set +CONFIG_STM32_SPI=y +# CONFIG_STM32_NOEXT_VECTORS is not set + +# +# Alternate Pin Mapping +# +# CONFIG_STM32_FLASH_PREFETCH is not set +# CONFIG_STM32_FLASH_WORKAROUND_DATA_CACHE_CORRUPTION_ON_RWW is not set +# CONFIG_STM32_JTAG_DISABLE is not set +# CONFIG_STM32_JTAG_FULL_ENABLE is not set +# CONFIG_STM32_JTAG_NOJNTRST_ENABLE is not set +CONFIG_STM32_JTAG_SW_ENABLE=y +CONFIG_STM32_DISABLE_IDLE_SLEEP_DURING_DEBUG=y +# CONFIG_STM32_FORCEPOWER is not set +# CONFIG_ARCH_BOARD_STM32_CUSTOM_CLOCKCONFIG is not set +CONFIG_STM32_CCMEXCLUDE=y + +# +# Timer Configuration +# +# CONFIG_STM32_ONESHOT is not set +# CONFIG_STM32_FREERUN is not set +# CONFIG_STM32_TIM1_CAP is not set +# CONFIG_STM32_TIM2_CAP is not set +# CONFIG_STM32_TIM3_CAP is not set +# CONFIG_STM32_TIM4_CAP is not set +# CONFIG_STM32_TIM5_CAP is not set +# CONFIG_STM32_TIM8_CAP is not set +# CONFIG_STM32_TIM9_CAP is not set +# CONFIG_STM32_TIM10_CAP is not set +# CONFIG_STM32_TIM11_CAP is not set +# CONFIG_STM32_TIM12_CAP is not set +# CONFIG_STM32_TIM13_CAP is not set +# CONFIG_STM32_TIM14_CAP is not set +CONFIG_STM32_USART=y +CONFIG_STM32_SERIALDRIVER=y + +# +# U[S]ART Configuration +# + +# +# U[S]ART Device Configuration +# +CONFIG_STM32_USART3_SERIALDRIVER=y +# CONFIG_STM32_USART3_1WIREDRIVER is not set +# CONFIG_USART3_RS485 is not set + +# +# Serial Driver Configuration +# +# CONFIG_SERIAL_DISABLE_REORDERING is not set +# CONFIG_STM32_FLOWCONTROL_BROKEN is not set +# CONFIG_STM32_USART_BREAKS is not set +# CONFIG_STM32_USART_SINGLEWIRE is not set + +# +# SPI Configuration +# +# CONFIG_STM32_SPI_INTERRUPTS is not set +# CONFIG_STM32_SPI_DMA is not set +# CONFIG_STM32_HAVE_RTC_COUNTER is not set +# CONFIG_STM32_HAVE_RTC_SUBSECONDS is not set + +# +# USB FS Host Configuration +# + +# +# USB HS Host Configuration +# + +# +# USB Host Debug Configuration +# + +# +# USB Device Configuration +# + +# +# Architecture Options +# +# CONFIG_ARCH_NOINTC is not set +# CONFIG_ARCH_VECNOTIRQ is not set +# CONFIG_ARCH_DMA is not set +CONFIG_ARCH_HAVE_IRQPRIO=y +# CONFIG_ARCH_L2CACHE is not set +# CONFIG_ARCH_HAVE_COHERENT_DCACHE is not set +# CONFIG_ARCH_HAVE_ADDRENV is not set +# CONFIG_ARCH_NEED_ADDRENV_MAPPING is not set +# CONFIG_ARCH_HAVE_MULTICPU is not set +CONFIG_ARCH_HAVE_VFORK=y +# CONFIG_ARCH_HAVE_MMU is not set +CONFIG_ARCH_HAVE_MPU=y +# CONFIG_ARCH_NAND_HWECC is not set +# CONFIG_ARCH_HAVE_EXTCLK is not set +# CONFIG_ARCH_HAVE_POWEROFF is not set +CONFIG_ARCH_HAVE_RESET=y +# CONFIG_ARCH_USE_MPU is not set +# CONFIG_ARCH_IRQPRIO is not set +CONFIG_ARCH_STACKDUMP=y +# CONFIG_ENDIAN_BIG is not set +# CONFIG_ARCH_IDLE_CUSTOM is not set +# CONFIG_ARCH_HAVE_RAMFUNCS is not set +CONFIG_ARCH_HAVE_RAMVECTORS=y +# CONFIG_ARCH_RAMVECTORS is not set +# CONFIG_ARCH_MINIMAL_VECTORTABLE is not set + +# +# Board Settings +# +CONFIG_BOARD_LOOPSPERMSEC=16717 +# CONFIG_ARCH_CALIBRATION is not set + +# +# Interrupt options +# +CONFIG_ARCH_HAVE_INTERRUPTSTACK=y +CONFIG_ARCH_INTERRUPTSTACK=0 +CONFIG_ARCH_HAVE_HIPRI_INTERRUPT=y +# CONFIG_ARCH_HIPRI_INTERRUPT is not set + +# +# Boot options +# +# CONFIG_BOOT_RUNFROMEXTSRAM is not set +CONFIG_BOOT_RUNFROMFLASH=y +# CONFIG_BOOT_RUNFROMISRAM is not set +# CONFIG_BOOT_RUNFROMSDRAM is not set +# CONFIG_BOOT_COPYTORAM is not set + +# +# Boot Memory Configuration +# +CONFIG_RAM_START=0x20000000 +CONFIG_RAM_SIZE=131072 +# CONFIG_ARCH_HAVE_SDRAM is not set + +# +# Board Selection +# +CONFIG_ARCH_BOARD_CLICKER2_STM32=y +# CONFIG_ARCH_BOARD_STM32F4_DISCOVERY is not set +# CONFIG_ARCH_BOARD_MIKROE_STM32F4 is not set +# CONFIG_ARCH_BOARD_CUSTOM is not set +CONFIG_ARCH_BOARD="clicker2-stm32" + +# +# Common Board Options +# +CONFIG_ARCH_HAVE_LEDS=y +CONFIG_ARCH_LEDS=y +CONFIG_ARCH_HAVE_BUTTONS=y +CONFIG_ARCH_BUTTONS=y +CONFIG_ARCH_HAVE_IRQBUTTONS=y +CONFIG_ARCH_IRQBUTTONS=y + +# +# Board-Specific Options +# +CONFIG_CLICKER2_STM32_MB1_SPI=y +# CONFIG_CLICKER2_STM32_MB2_SPI is not set +CONFIG_CLICKER2_STM32_MB1_BEE=y +# CONFIG_CLICKER2_STM32_MB2_BEE is not set +# CONFIG_BOARD_CRASHDUMP is not set +CONFIG_LIB_BOARDCTL=y +# CONFIG_BOARDCTL_RESET is not set +# CONFIG_BOARDCTL_UNIQUEID is not set +# CONFIG_BOARDCTL_TSCTEST is not set +# CONFIG_BOARDCTL_GRAPHICS is not set +# CONFIG_BOARDCTL_IOCTL is not set + +# +# RTOS Features +# +CONFIG_DISABLE_OS_API=y +# CONFIG_DISABLE_POSIX_TIMERS is not set +# CONFIG_DISABLE_PTHREAD is not set +# CONFIG_DISABLE_SIGNALS is not set +# CONFIG_DISABLE_MQUEUE is not set +# CONFIG_DISABLE_ENVIRON is not set + +# +# Clocks and Timers +# +CONFIG_ARCH_HAVE_TICKLESS=y +# CONFIG_SCHED_TICKLESS is not set +CONFIG_USEC_PER_TICK=10000 +# CONFIG_SYSTEM_TIME64 is not set +# CONFIG_CLOCK_MONOTONIC is not set +CONFIG_ARCH_HAVE_TIMEKEEPING=y +# CONFIG_JULIAN_TIME is not set +CONFIG_START_YEAR=2013 +CONFIG_START_MONTH=1 +CONFIG_START_DAY=1 +CONFIG_MAX_WDOGPARMS=2 +CONFIG_PREALLOC_WDOGS=8 +CONFIG_WDOG_INTRESERVE=1 +CONFIG_PREALLOC_TIMERS=4 + +# +# Tasks and Scheduling +# +# CONFIG_SPINLOCK is not set +# CONFIG_INIT_NONE is not set +CONFIG_INIT_ENTRYPOINT=y +# CONFIG_INIT_FILEPATH is not set +CONFIG_USER_ENTRYPOINT="nsh_main" +CONFIG_RR_INTERVAL=200 +# CONFIG_SCHED_SPORADIC is not set +CONFIG_TASK_NAME_SIZE=32 +CONFIG_MAX_TASKS=16 +# CONFIG_SCHED_HAVE_PARENT is not set +CONFIG_SCHED_WAITPID=y + +# +# Pthread Options +# +# CONFIG_PTHREAD_MUTEX_TYPES is not set +CONFIG_PTHREAD_MUTEX_ROBUST=y +# CONFIG_PTHREAD_MUTEX_UNSAFE is not set +# CONFIG_PTHREAD_MUTEX_BOTH is not set +CONFIG_NPTHREAD_KEYS=4 +# CONFIG_PTHREAD_CLEANUP is not set +# CONFIG_CANCELLATION_POINTS is not set + +# +# Performance Monitoring +# +# CONFIG_SCHED_CPULOAD is not set +# CONFIG_SCHED_INSTRUMENTATION is not set + +# +# Files and I/O +# +CONFIG_DEV_CONSOLE=y +# CONFIG_FDCLONE_DISABLE is not set +# CONFIG_FDCLONE_STDIO is not set +CONFIG_SDCLONE_DISABLE=y +CONFIG_NFILE_DESCRIPTORS=8 +CONFIG_NFILE_STREAMS=8 +CONFIG_NAME_MAX=32 +# CONFIG_PRIORITY_INHERITANCE is not set + +# +# RTOS hooks +# +CONFIG_BOARD_INITIALIZE=y +# CONFIG_BOARD_INITTHREAD is not set +# CONFIG_SCHED_STARTHOOK is not set +# CONFIG_SCHED_ATEXIT is not set +# CONFIG_SCHED_ONEXIT is not set +# CONFIG_SIG_EVTHREAD is not set + +# +# Signal Numbers +# +CONFIG_SIG_SIGUSR1=1 +CONFIG_SIG_SIGUSR2=2 +CONFIG_SIG_SIGALARM=3 +CONFIG_SIG_SIGCONDTIMEDOUT=16 +CONFIG_SIG_SIGWORK=17 + +# +# POSIX Message Queue Options +# +CONFIG_PREALLOC_MQ_MSGS=4 +CONFIG_MQ_MAXMSGSIZE=32 +# CONFIG_MODULE is not set + +# +# Work queue support +# +CONFIG_SCHED_WORKQUEUE=y +CONFIG_SCHED_HPWORK=y +CONFIG_SCHED_HPWORKPRIORITY=192 +CONFIG_SCHED_HPWORKPERIOD=50000 +CONFIG_SCHED_HPWORKSTACKSIZE=2048 +# CONFIG_SCHED_LPWORK is not set + +# +# Stack and heap information +# +CONFIG_IDLETHREAD_STACKSIZE=1024 +CONFIG_USERMAIN_STACKSIZE=2048 +CONFIG_PTHREAD_STACK_MIN=256 +CONFIG_PTHREAD_STACK_DEFAULT=2048 +# CONFIG_LIB_SYSCALL is not set + +# +# Device Drivers +# +CONFIG_DISABLE_POLL=y +CONFIG_DEV_NULL=y +# CONFIG_DEV_ZERO is not set +# CONFIG_DEV_URANDOM is not set +# CONFIG_DEV_LOOP is not set + +# +# Buffering +# +# CONFIG_DRVR_WRITEBUFFER is not set +# CONFIG_DRVR_READAHEAD is not set +# CONFIG_RAMDISK is not set +# CONFIG_CAN is not set +# CONFIG_ARCH_HAVE_PWM_PULSECOUNT is not set +# CONFIG_ARCH_HAVE_PWM_MULTICHAN is not set +# CONFIG_PWM is not set +CONFIG_ARCH_HAVE_I2CRESET=y +# CONFIG_I2C is not set +# CONFIG_ARCH_HAVE_SPI_CRCGENERATION is not set +# CONFIG_ARCH_HAVE_SPI_CS_CONTROL is not set +CONFIG_ARCH_HAVE_SPI_BITORDER=y +CONFIG_SPI=y +# CONFIG_SPI_SLAVE is not set +CONFIG_SPI_EXCHANGE=y +# CONFIG_SPI_CMDDATA is not set +# CONFIG_SPI_CALLBACK is not set +# CONFIG_SPI_HWFEATURES is not set +# CONFIG_SPI_BITORDER is not set +# CONFIG_SPI_CS_DELAY_CONTROL is not set +# CONFIG_SPI_DRIVER is not set +# CONFIG_SPI_BITBANG is not set +# CONFIG_I2S is not set + +# +# Timer Driver Support +# +# CONFIG_TIMER is not set +# CONFIG_ONESHOT is not set +# CONFIG_RTC is not set +# CONFIG_WATCHDOG is not set +# CONFIG_ANALOG is not set +# CONFIG_AUDIO_DEVICES is not set +# CONFIG_VIDEO_DEVICES is not set +# CONFIG_BCH is not set +# CONFIG_INPUT is not set + +# +# IO Expander/GPIO Support +# +# CONFIG_IOEXPANDER is not set +# CONFIG_DEV_GPIO is not set + +# +# LCD Driver Support +# +# CONFIG_LCD is not set +# CONFIG_SLCD is not set + +# +# LED Support +# +# CONFIG_USERLED is not set +# CONFIG_RGBLED is not set +# CONFIG_PCA9635PW is not set +# CONFIG_NCP5623C is not set +# CONFIG_MMCSD is not set +# CONFIG_MODEM is not set +# CONFIG_MTD is not set +# CONFIG_EEPROM is not set +# CONFIG_PIPES is not set +# CONFIG_PM is not set +# CONFIG_POWER is not set +# CONFIG_SENSORS is not set +CONFIG_SERIAL=y +# CONFIG_DEV_LOWCONSOLE is not set +# CONFIG_SERIAL_REMOVABLE is not set +CONFIG_SERIAL_CONSOLE=y +# CONFIG_16550_UART is not set +# CONFIG_UART_SERIALDRIVER is not set +# CONFIG_UART0_SERIALDRIVER is not set +# CONFIG_UART1_SERIALDRIVER is not set +# CONFIG_UART2_SERIALDRIVER is not set +# CONFIG_UART3_SERIALDRIVER is not set +# CONFIG_UART4_SERIALDRIVER is not set +# CONFIG_UART5_SERIALDRIVER is not set +# CONFIG_UART6_SERIALDRIVER is not set +# CONFIG_UART7_SERIALDRIVER is not set +# CONFIG_UART8_SERIALDRIVER is not set +# CONFIG_SCI0_SERIALDRIVER is not set +# CONFIG_SCI1_SERIALDRIVER is not set +# CONFIG_USART0_SERIALDRIVER is not set +# CONFIG_USART1_SERIALDRIVER is not set +# CONFIG_USART2_SERIALDRIVER is not set +CONFIG_USART3_SERIALDRIVER=y +# CONFIG_USART4_SERIALDRIVER is not set +# CONFIG_USART5_SERIALDRIVER is not set +# CONFIG_USART6_SERIALDRIVER is not set +# CONFIG_USART7_SERIALDRIVER is not set +# CONFIG_USART8_SERIALDRIVER is not set +# CONFIG_OTHER_UART_SERIALDRIVER is not set +CONFIG_MCU_SERIAL=y +CONFIG_STANDARD_SERIAL=y +# CONFIG_SERIAL_IFLOWCONTROL is not set +# CONFIG_SERIAL_OFLOWCONTROL is not set +# CONFIG_SERIAL_DMA is not set +CONFIG_ARCH_HAVE_SERIAL_TERMIOS=y +CONFIG_USART3_SERIAL_CONSOLE=y +# CONFIG_OTHER_SERIAL_CONSOLE is not set +# CONFIG_NO_SERIAL_CONSOLE is not set + +# +# USART3 Configuration +# +CONFIG_USART3_RXBUFSIZE=256 +CONFIG_USART3_TXBUFSIZE=256 +CONFIG_USART3_BAUD=115200 +CONFIG_USART3_BITS=8 +CONFIG_USART3_PARITY=0 +CONFIG_USART3_2STOP=0 +# CONFIG_USART3_IFLOWCONTROL is not set +# CONFIG_USART3_OFLOWCONTROL is not set +# CONFIG_USART3_DMA is not set +# CONFIG_PSEUDOTERM is not set +# CONFIG_USBDEV is not set +# CONFIG_USBHOST is not set +# CONFIG_USBMISC is not set +# CONFIG_HAVE_USBTRACE is not set +CONFIG_DRIVERS_WIRELESS=y +# CONFIG_WL_CC1101 is not set +# CONFIG_WL_CC3000 is not set +CONFIG_DRIVERS_IEEE802154=y +CONFIG_IEEE802154_MRF24J40=y +# CONFIG_IEEE802154_AT86RF233 is not set +# CONFIG_DRIVERS_IEEE80211 is not set +# CONFIG_WL_NRF24L01 is not set +# CONFIG_DRIVERS_CONTACTLESS is not set + +# +# System Logging +# +# CONFIG_ARCH_SYSLOG is not set +# CONFIG_RAMLOG is not set +# CONFIG_SYSLOG_INTBUFFER is not set +# CONFIG_SYSLOG_TIMESTAMP is not set +CONFIG_SYSLOG_SERIAL_CONSOLE=y +# CONFIG_SYSLOG_CHAR is not set +CONFIG_SYSLOG_CONSOLE=y +# CONFIG_SYSLOG_NONE is not set +# CONFIG_SYSLOG_FILE is not set +# CONFIG_SYSLOG_CHARDEV is not set + +# +# Networking Support +# +# CONFIG_ARCH_HAVE_NET is not set +# CONFIG_ARCH_HAVE_PHY is not set +# CONFIG_NET is not set + +# +# Crypto API +# +# CONFIG_CRYPTO is not set + +# +# File Systems +# + +# +# File system configuration +# +# CONFIG_DISABLE_MOUNTPOINT is not set +# CONFIG_FS_AUTOMOUNTER is not set +# CONFIG_DISABLE_PSEUDOFS_OPERATIONS is not set +# CONFIG_PSEUDOFS_SOFTLINKS is not set +CONFIG_FS_READABLE=y +CONFIG_FS_WRITABLE=y +# CONFIG_FS_NAMED_SEMAPHORES is not set +CONFIG_FS_MQUEUE_MPATH="/var/mqueue" +# CONFIG_FS_RAMMAP is not set +# CONFIG_FS_FAT is not set +# CONFIG_FS_NXFFS is not set +# CONFIG_FS_ROMFS is not set +# CONFIG_FS_TMPFS is not set +# CONFIG_FS_SMARTFS is not set +# CONFIG_FS_BINFS is not set +CONFIG_FS_PROCFS=y +# CONFIG_FS_PROCFS_REGISTER is not set + +# +# Exclude individual procfs entries +# +# CONFIG_FS_PROCFS_EXCLUDE_PROCESS is not set +# CONFIG_FS_PROCFS_EXCLUDE_UPTIME is not set +# CONFIG_FS_PROCFS_EXCLUDE_MOUNTS is not set +# CONFIG_FS_UNIONFS is not set + +# +# Graphics Support +# +# CONFIG_NX is not set + +# +# Memory Management +# +# CONFIG_MM_SMALL is not set +CONFIG_MM_REGIONS=1 +# CONFIG_ARCH_HAVE_HEAP2 is not set +# CONFIG_GRAN is not set + +# +# Audio Support +# +# CONFIG_AUDIO is not set + +# +# Wireless Support +# +CONFIG_WIRELESS=y +CONFIG_WIRELESS_IEEE802154=y +CONFIG_IEEE802154_MAC=y +# CONFIG_IEEE802154_MAC_DEV is not set +CONFIG_IEEE802154_DEV=y + +# +# Binary Loader +# +# CONFIG_BINFMT_DISABLE is not set +# CONFIG_BINFMT_EXEPATH is not set +# CONFIG_NXFLAT is not set +# CONFIG_ELF is not set +CONFIG_BUILTIN=y +# CONFIG_PIC is not set +# CONFIG_SYMTAB_ORDEREDBYNAME is not set + +# +# Library Routines +# + +# +# Standard C Library Options +# + +# +# Standard C I/O +# +# CONFIG_STDIO_DISABLE_BUFFERING is not set +CONFIG_STDIO_BUFFER_SIZE=64 +CONFIG_STDIO_LINEBUFFER=y +CONFIG_NUNGET_CHARS=2 +# CONFIG_NOPRINTF_FIELDWIDTH is not set +# CONFIG_LIBC_FLOATINGPOINT is not set +CONFIG_LIBC_LONG_LONG=y +# CONFIG_LIBC_SCANSET is not set +# CONFIG_EOL_IS_CR is not set +# CONFIG_EOL_IS_LF is not set +# CONFIG_EOL_IS_BOTH_CRLF is not set +CONFIG_EOL_IS_EITHER_CRLF=y +# CONFIG_MEMCPY_VIK is not set +# CONFIG_LIBM is not set + +# +# Architecture-Specific Support +# +CONFIG_ARCH_LOWPUTC=y +# CONFIG_ARCH_ROMGETC is not set +# CONFIG_LIBC_ARCH_MEMCPY is not set +# CONFIG_LIBC_ARCH_MEMCMP is not set +# CONFIG_LIBC_ARCH_MEMMOVE is not set +# CONFIG_LIBC_ARCH_MEMSET is not set +# CONFIG_LIBC_ARCH_STRCHR is not set +# CONFIG_LIBC_ARCH_STRCMP is not set +# CONFIG_LIBC_ARCH_STRCPY is not set +# CONFIG_LIBC_ARCH_STRNCPY is not set +# CONFIG_LIBC_ARCH_STRLEN is not set +# CONFIG_LIBC_ARCH_STRNLEN is not set +# CONFIG_LIBC_ARCH_ELF is not set +# CONFIG_ARMV7M_MEMCPY is not set + +# +# stdlib Options +# +CONFIG_LIB_RAND_ORDER=1 +CONFIG_LIB_HOMEDIR="/" +CONFIG_LIBC_TMPDIR="/tmp" +CONFIG_LIBC_MAX_TMPFILE=32 + +# +# Program Execution Options +# +# CONFIG_LIBC_EXECFUNCS is not set +CONFIG_POSIX_SPAWN_PROXY_STACKSIZE=1024 +CONFIG_TASK_SPAWN_DEFAULT_STACKSIZE=2048 + +# +# errno Decode Support +# +# CONFIG_LIBC_STRERROR is not set +# CONFIG_LIBC_PERROR_STDOUT is not set + +# +# memcpy/memset Options +# +# CONFIG_MEMSET_OPTSPEED is not set +# CONFIG_LIBC_DLLFCN is not set +# CONFIG_LIBC_MODLIB is not set +# CONFIG_LIBC_WCHAR is not set +# CONFIG_LIBC_LOCALE is not set + +# +# Time/Time Zone Support +# +# CONFIG_LIBC_LOCALTIME is not set +# CONFIG_TIME_EXTENDED is not set +CONFIG_ARCH_HAVE_TLS=y + +# +# Thread Local Storage (TLS) +# +# CONFIG_TLS is not set + +# +# Network-Related Options +# +# CONFIG_LIBC_IPv4_ADDRCONV is not set +# CONFIG_LIBC_IPv6_ADDRCONV is not set +# CONFIG_LIBC_NETDB is not set + +# +# NETDB Support +# +# CONFIG_NETDB_HOSTFILE is not set +# CONFIG_LIBC_IOCTL_VARIADIC is not set +CONFIG_LIB_SENDFILE_BUFSIZE=512 + +# +# Non-standard Library Support +# +# CONFIG_LIB_CRC64_FAST is not set +# CONFIG_LIB_KBDCODEC is not set +# CONFIG_LIB_SLCDCODEC is not set +# CONFIG_LIB_HEX2BIN is not set + +# +# Basic CXX Support +# +# CONFIG_C99_BOOL8 is not set +CONFIG_HAVE_CXX=y +CONFIG_HAVE_CXXINITIALIZE=y +# CONFIG_CXX_NEWLONG is not set + +# +# LLVM C++ Library (libcxx) +# +# CONFIG_LIBCXX is not set + +# +# uClibc++ Standard C++ Library +# +# CONFIG_UCLIBCXX is not set + +# +# Application Configuration +# + +# +# Built-In Applications +# +CONFIG_BUILTIN_PROXY_STACKSIZE=1024 + +# +# CAN Utilities +# + +# +# Examples +# +# CONFIG_EXAMPLES_BUTTONS is not set +# CONFIG_EXAMPLES_CCTYPE is not set +# CONFIG_EXAMPLES_CHAT is not set +# CONFIG_EXAMPLES_CONFIGDATA is not set +# CONFIG_EXAMPLES_CXXTEST is not set +# CONFIG_EXAMPLES_DHCPD is not set +# CONFIG_EXAMPLES_ELF is not set +# CONFIG_EXAMPLES_FSTEST is not set +# CONFIG_EXAMPLES_FTPC is not set +# CONFIG_EXAMPLES_FTPD is not set +# CONFIG_EXAMPLES_HELLO is not set +# CONFIG_EXAMPLES_HELLOXX is not set +# CONFIG_EXAMPLES_HIDKBD is not set +# CONFIG_EXAMPLES_IGMP is not set +# CONFIG_EXAMPLES_JSON is not set +# CONFIG_EXAMPLES_KEYPADTEST is not set +# CONFIG_EXAMPLES_MEDIA is not set +# CONFIG_EXAMPLES_MM is not set +# CONFIG_EXAMPLES_MODBUS is not set +# CONFIG_EXAMPLES_MOUNT is not set +# CONFIG_EXAMPLES_NRF24L01TERM is not set +CONFIG_EXAMPLES_NSH=y +CONFIG_EXAMPLES_NSH_CXXINITIALIZE=y +# CONFIG_EXAMPLES_NULL is not set +# CONFIG_EXAMPLES_NX is not set +# CONFIG_EXAMPLES_NXFFS is not set +# CONFIG_EXAMPLES_NXHELLO is not set +# CONFIG_EXAMPLES_NXIMAGE is not set +# CONFIG_EXAMPLES_NXLINES is not set +# CONFIG_EXAMPLES_NXTERM is not set +# CONFIG_EXAMPLES_NXTEXT is not set +# CONFIG_EXAMPLES_OSTEST is not set +# CONFIG_EXAMPLES_PCA9635 is not set +# CONFIG_EXAMPLES_POSIXSPAWN is not set +# CONFIG_EXAMPLES_PPPD is not set +# CONFIG_EXAMPLES_RFID_READUID is not set +# CONFIG_EXAMPLES_RGBLED is not set +# CONFIG_EXAMPLES_SENDMAIL is not set +# CONFIG_EXAMPLES_SERIALBLASTER is not set +# CONFIG_EXAMPLES_SERIALRX is not set +# CONFIG_EXAMPLES_SERLOOP is not set +# CONFIG_EXAMPLES_SLCD is not set +# CONFIG_EXAMPLES_SMART is not set +# CONFIG_EXAMPLES_SMART_TEST is not set +# CONFIG_EXAMPLES_SMP is not set +# CONFIG_EXAMPLES_STAT is not set +# CONFIG_EXAMPLES_TCPECHO is not set +# CONFIG_EXAMPLES_TELNETD is not set +# CONFIG_EXAMPLES_TIFF is not set +# CONFIG_EXAMPLES_TOUCHSCREEN is not set +# CONFIG_EXAMPLES_USBSERIAL is not set +# CONFIG_EXAMPLES_WATCHDOG is not set +# CONFIG_EXAMPLES_WEBSERVER is not set +# CONFIG_EXAMPLES_XBC_TEST is not set + +# +# File System Utilities +# +# CONFIG_FSUTILS_INIFILE is not set +# CONFIG_FSUTILS_PASSWD is not set + +# +# GPS Utilities +# +# CONFIG_GPSUTILS_MINMEA_LIB is not set + +# +# Graphics Support +# +# CONFIG_TIFF is not set +# CONFIG_GRAPHICS_TRAVELER is not set + +# +# Interpreters +# +# CONFIG_INTERPRETERS_BAS is not set +# CONFIG_INTERPRETERS_FICL is not set +# CONFIG_INTERPRETERS_MICROPYTHON is not set +# CONFIG_INTERPRETERS_MINIBASIC is not set +# CONFIG_INTERPRETERS_PCODE is not set + +# +# FreeModBus +# +# CONFIG_MODBUS is not set + +# +# Network Utilities +# +# CONFIG_NETUTILS_CODECS is not set +# CONFIG_NETUTILS_ESP8266 is not set +# CONFIG_NETUTILS_FTPC is not set +# CONFIG_NETUTILS_JSON is not set +# CONFIG_NETUTILS_SMTP is not set + +# +# NSH Library +# +CONFIG_NSH_LIBRARY=y +# CONFIG_NSH_MOTD is not set + +# +# Command Line Configuration +# +CONFIG_NSH_READLINE=y +# CONFIG_NSH_CLE is not set +CONFIG_NSH_LINELEN=64 +# CONFIG_NSH_DISABLE_SEMICOLON is not set +CONFIG_NSH_CMDPARMS=y +CONFIG_NSH_MAXARGUMENTS=6 +CONFIG_NSH_ARGCAT=y +CONFIG_NSH_NESTDEPTH=3 +# CONFIG_NSH_DISABLEBG is not set +CONFIG_NSH_BUILTIN_APPS=y + +# +# Disable Individual commands +# +# CONFIG_NSH_DISABLE_ADDROUTE is not set +# CONFIG_NSH_DISABLE_BASENAME is not set +# CONFIG_NSH_DISABLE_CAT is not set +# CONFIG_NSH_DISABLE_CD is not set +# CONFIG_NSH_DISABLE_CP is not set +# CONFIG_NSH_DISABLE_CMP is not set +CONFIG_NSH_DISABLE_DATE=y +# CONFIG_NSH_DISABLE_DD is not set +# CONFIG_NSH_DISABLE_DF is not set +# CONFIG_NSH_DISABLE_DELROUTE is not set +# CONFIG_NSH_DISABLE_DIRNAME is not set +# CONFIG_NSH_DISABLE_ECHO is not set +# CONFIG_NSH_DISABLE_EXEC is not set +# CONFIG_NSH_DISABLE_EXIT is not set +# CONFIG_NSH_DISABLE_FREE is not set +CONFIG_NSH_DISABLE_GET=y +# CONFIG_NSH_DISABLE_HELP is not set +# CONFIG_NSH_DISABLE_HEXDUMP is not set +# CONFIG_NSH_DISABLE_IFCONFIG is not set +CONFIG_NSH_DISABLE_IFUPDOWN=y +# CONFIG_NSH_DISABLE_KILL is not set +# CONFIG_NSH_DISABLE_LOSETUP is not set +CONFIG_NSH_DISABLE_LOSMART=y +# CONFIG_NSH_DISABLE_LS is not set +# CONFIG_NSH_DISABLE_MB is not set +# CONFIG_NSH_DISABLE_MKDIR is not set +# CONFIG_NSH_DISABLE_MKRD is not set +# CONFIG_NSH_DISABLE_MH is not set +# CONFIG_NSH_DISABLE_MOUNT is not set +# CONFIG_NSH_DISABLE_MV is not set +# CONFIG_NSH_DISABLE_MW is not set +CONFIG_NSH_DISABLE_PRINTF=y +# CONFIG_NSH_DISABLE_PS is not set +CONFIG_NSH_DISABLE_PUT=y +# CONFIG_NSH_DISABLE_PWD is not set +# CONFIG_NSH_DISABLE_RM is not set +# CONFIG_NSH_DISABLE_RMDIR is not set +# CONFIG_NSH_DISABLE_SET is not set +# CONFIG_NSH_DISABLE_SH is not set +# CONFIG_NSH_DISABLE_SLEEP is not set +# CONFIG_NSH_DISABLE_TIME is not set +# CONFIG_NSH_DISABLE_TEST is not set +# CONFIG_NSH_DISABLE_UMOUNT is not set +# CONFIG_NSH_DISABLE_UNAME is not set +# CONFIG_NSH_DISABLE_UNSET is not set +# CONFIG_NSH_DISABLE_USLEEP is not set +CONFIG_NSH_DISABLE_WGET=y +# CONFIG_NSH_DISABLE_XD is not set +CONFIG_NSH_MMCSDMINOR=0 + +# +# Configure Command Options +# +# CONFIG_NSH_CMDOPT_DF_H is not set +# CONFIG_NSH_CMDOPT_DD_STATS is not set +CONFIG_NSH_CODECS_BUFSIZE=128 +CONFIG_NSH_CMDOPT_HEXDUMP=y +CONFIG_NSH_PROC_MOUNTPOINT="/proc" +CONFIG_NSH_FILEIOSIZE=512 + +# +# Scripting Support +# +# CONFIG_NSH_DISABLESCRIPT is not set +# CONFIG_NSH_DISABLE_ITEF is not set +# CONFIG_NSH_DISABLE_LOOPS is not set + +# +# Console Configuration +# +CONFIG_NSH_CONSOLE=y +# CONFIG_NSH_ALTCONDEV is not set +CONFIG_NSH_ARCHINIT=y +# CONFIG_NSH_LOGIN is not set +# CONFIG_NSH_CONSOLE_LOGIN is not set + +# +# NxWidgets/NxWM +# + +# +# Platform-specific Support +# +# CONFIG_PLATFORM_CONFIGDATA is not set + +# +# System Libraries and NSH Add-Ons +# +# CONFIG_SYSTEM_CLE is not set +# CONFIG_SYSTEM_CUTERM is not set +# CONFIG_SYSTEM_FREE is not set +# CONFIG_SYSTEM_HEX2BIN is not set +# CONFIG_SYSTEM_HEXED is not set +# CONFIG_SYSTEM_INSTALL is not set +# CONFIG_SYSTEM_RAMTEST is not set +CONFIG_READLINE_HAVE_EXTMATCH=y +CONFIG_SYSTEM_READLINE=y +CONFIG_READLINE_ECHO=y +# CONFIG_READLINE_TABCOMPLETION is not set +# CONFIG_READLINE_CMD_HISTORY is not set +# CONFIG_SYSTEM_SUDOKU is not set +# CONFIG_SYSTEM_SYSTEM is not set +# CONFIG_SYSTEM_TEE is not set +# CONFIG_SYSTEM_UBLOXMODEM is not set +# CONFIG_SYSTEM_VI is not set +# CONFIG_SYSTEM_ZMODEM is not set + +# +# Wireless Libraries and NSH Add-Ons +# + +# +# IEEE 802.15.4 applications +# +CONFIG_IEEE802154_COMMON=y +CONFIG_IEEE802154_COORD=y +CONFIG_IEEE802154_I8SAK=y diff --git a/configs/clicker2-stm32/src/Makefile b/configs/clicker2-stm32/src/Makefile index bafc45bff1..3980c3ac7d 100644 --- a/configs/clicker2-stm32/src/Makefile +++ b/configs/clicker2-stm32/src/Makefile @@ -56,6 +56,10 @@ ifeq ($(CONFIG_LIB_BOARDCTL),y) CSRCS += stm32_appinit.c endif +ifeq ($(CONFIG_IEEE802154_MRF24J40),y) +CSRCS += stm32_mrf24j40.c +endif + ifeq ($(CONFIG_ADC),y) CSRCS += stm32_adc.c endif diff --git a/configs/clicker2-stm32/src/clicker2-stm32.h b/configs/clicker2-stm32/src/clicker2-stm32.h index 5def0fdce8..7a1867a0b4 100644 --- a/configs/clicker2-stm32/src/clicker2-stm32.h +++ b/configs/clicker2-stm32/src/clicker2-stm32.h @@ -297,5 +297,21 @@ int stm32_adc_setup(void); int stm32_can_setup(void); #endif +/**************************************************************************** + * Name: stm32_mrf24j40_initialize + * + * Description: + * Initialize the MRF24J40 device. + * + * Returned Value: + * Zero is returned on success. Otherwise, a negated errno value is + * returned to indicate the nature of the failure. + * + ****************************************************************************/ + +#if defined(CONFIG_CLICKER2_STM32_MB1_BEE) || defined(CONFIG_CLICKER2_STM32_MB2_BEE) +int stm32_mrf24j40_initialize(void); +#endif + #endif /* __ASSEMBLY__ */ #endif /* __CONFIGS_CLICKER2_STM32_SRC_CLICKER2_H */ diff --git a/configs/clicker2-stm32/src/stm32_bringup.c b/configs/clicker2-stm32/src/stm32_bringup.c index 1dcc276812..b7adf9dcc1 100644 --- a/configs/clicker2-stm32/src/stm32_bringup.c +++ b/configs/clicker2-stm32/src/stm32_bringup.c @@ -153,6 +153,16 @@ int stm32_bringup(void) } #endif +#if defined(CONFIG_CLICKER2_STM32_MB1_BEE) || defined(CONFIG_CLICKER2_STM32_MB2_BEE) + /* Configure MRF24J40 wireless */ + + ret = stm32_mrf24j40_initialize(); + if (ret < 0) + { + syslog(LOG_ERR, "ERROR: stm32_mrf24j40_initialize() failed: %d\n", ret); + } +#endif + #ifdef CONFIG_BUTTONS /* Register the BUTTON driver */ diff --git a/configs/clicker2-stm32/src/stm32_buttons.c b/configs/clicker2-stm32/src/stm32_buttons.c index 00a571c817..5bcd3ba9e9 100644 --- a/configs/clicker2-stm32/src/stm32_buttons.c +++ b/configs/clicker2-stm32/src/stm32_buttons.c @@ -47,6 +47,7 @@ #include #include "stm32_gpio.h" +#include "stm32_exti.h" #include "clicker2-stm32.h" diff --git a/configs/clicker2-stm32/src/stm32_mrf24j40.c b/configs/clicker2-stm32/src/stm32_mrf24j40.c new file mode 100644 index 0000000000..c92b93239b --- /dev/null +++ b/configs/clicker2-stm32/src/stm32_mrf24j40.c @@ -0,0 +1,336 @@ +/**************************************************************************** + * configs/freedom-kl25z/src/stm32_mrf24j40.c + * + * Copyright (C) 2017 Gregory Nutt, All rights reserver + * Author: Gregory Nutt + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "stm32_gpio.h" +#include "stm32_exti.h" +#include "stm32_spi.h" + +#include "clicker2-stm32.h" + +#ifdef CONFIG_IEEE802154_MRF24J40 + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#ifndef CONFIG_DRIVERS_WIRELESS +# error Wireless support requires CONFIG_DRIVERS_WIRELESS +#endif + +#if !defined(CONFIG_CLICKER2_STM32_MB1_BEE) && \ + !defined(CONFIG_CLICKER2_STM32_MB2_BEE) +# error Only the Mikroe BEE board is supported +#endif + +#ifdef CONFIG_CLICKER2_STM32_MB1_BEE +# ifndef CONFIG_STM32_SPI3 +# error Mikroe BEE on mikroBUS1 requires CONFIG_STM32_SPI3 +# endif +#endif + +#ifdef CONFIG_CLICKER2_STM32_MB2_BEE +# ifndef CONFIG_STM32_SPI2 +# error Mikroe BEE on mikroBUS1 requires CONFIG_STM32_SPI2 +# endif +#endif + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +struct stm32_priv_s +{ + struct mrf24j40_lower_s dev; + xcpt_t handler; + FAR void *arg; + uint32_t intcfg; + uint8_t spidev; +}; + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +/* IRQ/GPIO access callbacks. These operations all hidden behind callbacks + * to isolate the MRF24J40 driver from differences in GPIO interrupt handling + * varying boards and MCUs. + * + * irq_attach - Attach the MRF24J40 interrupt handler to the GPIO + interrupt + * irq_enable - Enable or disable the GPIO interrupt + */ + +static int stm32_attach_irq(FAR const struct mrf24j40_lower_s *lower, + xcpt_t handler, FAR void *arg); +static void stm32_enable_irq(FAR const struct mrf24j40_lower_s *lower, + bool state); +static int stm32_mrf24j40_devsetup(FAR struct stm32_priv_s *priv); + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/* A reference to a structure of this type must be passed to the MRF24J40 + * driver. This structure provides information about the configuration + * of the MRF24J40 and provides some board-specific hooks. + * + * Memory for this structure is provided by the caller. It is not copied + * by the driver and is presumed to persist while the driver is active. The + * memory must be writable because, under certain circumstances, the driver + * may modify frequency or X plate resistance values. + */ + +#ifdef CONFIG_CLICKER2_STM32_MB1_BEE +static struct stm32_priv_s g_mrf24j40_mb1_priv = +{ + .dev.attach = stm32_attach_irq, + .dev.enable = stm32_enable_irq, + .handler = NULL, + .intcfg = GPIO_MB1_INT, + .spidev = 3, +}; +#endif + +#ifdef CONFIG_CLICKER2_STM32_MB2_BEE +static struct stm32_priv_s g_mrf24j40_mb2_priv = +{ + .dev.attach = stm32_attach_irq, + .dev.enable = stm32_enable_irq, + .uint32_t = GPIO_MB2_INT, + .spidev = 2, +}; +#endif + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/* IRQ/GPIO access callbacks. These operations all hidden behind + * callbacks to isolate the MRF24J40 driver from differences in GPIO + * interrupt handling by varying boards and MCUs. If possible, + * interrupts should be configured on both rising and falling edges + * so that contact and loss-of-contact events can be detected. + * + * irq_attach - Attach the MRF24J40 interrupt handler to the GPIO + * interrupt + * irq_enable - Enable or disable the GPIO interrupt + */ + +static int stm32_attach_irq(FAR const struct mrf24j40_lower_s *lower, + xcpt_t handler, FAR void *arg) +{ + FAR struct stm32_priv_s *priv = (FAR struct stm32_priv_s *)lower; + + DEBUGASSERT(priv != NULL); + + /* Just save the handler for use when the interrupt is enabled */ + + priv->handler = handler; + priv->arg = arg; + return OK; +} + +static void stm32_enable_irq(FAR const struct mrf24j40_lower_s *lower, + bool state) +{ + FAR struct stm32_priv_s *priv = (FAR struct stm32_priv_s *)lower; + + /* The caller should not attempt to enable interrupts if the handler + * has not yet been 'attached' + */ + + DEBUGASSERT(priv != NULL && (priv->handler != NULL || !state)); + + /* Attach and enable, or detach and disable */ + + wlinfo("state:%d\n", (int)state); + if (state) + { + (void)stm32_gpiosetevent(priv->intcfg, true, true, true, + priv->handler, priv->arg); + } + else + { + (void)stm32_gpiosetevent(priv->intcfg, false, false, false, + NULL, NULL); + } +} + +/**************************************************************************** + * Name: stm32_mrf24j40_devsetup + * + * Description: + * Initialize one the MRF24J40 device in one mikroBUS slot + * + * Returned Value: + * Zero is returned on success. Otherwise, a negated errno value is + * returned to indicate the nature of the failure. + * + ****************************************************************************/ + +static int stm32_mrf24j40_devsetup(FAR struct stm32_priv_s *priv) +{ + FAR struct ieee802154_radio_s *radio; +#ifdef CONFIG_IEEE802154_MAC + MACHANDLE mac; +#endif + FAR struct spi_dev_s *spi; + int ret; + + /* Configure the interrupt pin */ + + stm32_configgpio(priv->intcfg); + + /* Initialize the SPI bus and get an instance of the SPI interface */ + + spi = stm32_spibus_initialize(priv->spidev); + if (spi == NULL) + { + wlerr("ERROR: Failed to initialize SPI bus %d\n", priv->spidev); + return -ENODEV; + } + + /* Initialize and register the SPI MRF24J40 device */ + + radio = mrf24j40_init(spi, &priv->dev); + if (radio == NULL) + { + wlerr("ERROR: Failed to initialize SPI bus %d\n", priv->spidev); + return -ENODEV; + } + +#if defined(CONFIG_IEEE802154_MAC) + /* Create a 802.15.4 MAC device from a 802.15.4 compatible radio device. */ + + mac = mac802154_create(radio); + if (mac == NULL) + { + wlerr("ERROR: Failed to initialize IEEE802.15.4 MAC\n"); + return -ENODEV; + } + +#if defined(CONFIG_IEEE802154_NETDEV) + /* Use the IEEE802.15.4 MAC interface instance to create a 6loWPAN + * network interface by wrapping the MAC intrface instance in a + * network device driver via mac802154dev_register(). + */ + + ret = mac802154netdev_register(mac); + if (ret < 0) + { + wlerr("ERROR: Failed to register the MAC network driver wpan%d: %d\n", + 0, ret); + return ret; + } +#elif defined(CONFIG_IEEE802154_MAC_DEV) + /* If want to call these APIs from userspace, you have to wrap the MAC + * interface in a character device viamac802154dev_register(). + */ + + ret = mac802154dev_register(mac, 0); + if (ret < 0) + { + wlerr("ERROR: Failed to register the MAC character driver /dev/ieee%d: %d\n", + 0, ret); + return ret; + } +#endif + +#endif /* CONFIG_IEEE802154_MAC */ + + return OK; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: stm32_mrf24j40_initialize + * + * Description: + * Initialize the MRF24J40 device. + * + * Returned Value: + * Zero is returned on success. Otherwise, a negated errno value is + * returned to indicate the nature of the failure. + * + ****************************************************************************/ + +int stm32_mrf24j40_initialize(void) +{ + int ret; + +#ifdef CONFIG_CLICKER2_STM32_MB1_BEE + wlinfo("Configuring BEE in mikroBUS1\n"); + + ret = stm32_mrf24j40_devsetup(&g_mrf24j40_mb1_priv); + if (ret < 0) + { + wlerr("ERROR: Failed to initialize BD in mikroBUS1: %d\n", ret); + } +#endif + +#ifdef CONFIG_CLICKER2_STM32_MB2_BEE + wlinfo("Configuring BEE in mikroBUS2\n"); + + ret = stm32_mrf24j40_devsetup(&g_mrf24j40_mb2_priv); + if (ret < 0) + { + wlerr("ERROR: Failed to initialize BD in mikroBUS2: %d\n", ret); + } +#endif + + UNUSED(ret); + return OK; +} +#endif /* CONFIG_IEEE802154_MRF24J40 */ diff --git a/configs/freedom-kl25z/include/kl_cc3000.h b/configs/freedom-kl25z/include/kl_cc3000.h index 117fc57eef..ce252a67a0 100644 --- a/configs/freedom-kl25z/include/kl_cc3000.h +++ b/configs/freedom-kl25z/include/kl_cc3000.h @@ -70,9 +70,8 @@ void WriteWlanEnablePin(uint8_t val); void AssertWlanCS(void); -/* - * Deassert CC3000 CS - */ +/* Deassert CC3000 CS */ + void DeassertWlanCS(void); /* Setup needed pins */ diff --git a/configs/sim/sixlowpan/defconfig b/configs/sim/sixlowpan/defconfig index 5c64eb13e6..f46639d003 100644 --- a/configs/sim/sixlowpan/defconfig +++ b/configs/sim/sixlowpan/defconfig @@ -548,7 +548,7 @@ CONFIG_NET_6LOWPAN_MAXADDRCONTEXT=1 CONFIG_NET_6LOWPAN_MAXADDRCONTEXT_PREFIX_0_0=0xaa CONFIG_NET_6LOWPAN_MAXADDRCONTEXT_PREFIX_0_1=0xaa # CONFIG_NET_6LOWPAN_MAXADDRCONTEXT_PREINIT_1 is not set -# CONFIG_NET_6LOWPAN_RIMEADDR_EXTENDED is not set +# CONFIG_NET_6LOWPAN_EXTENDEDADDR is not set CONFIG_NET_6LOWPAN_MAXAGE=20 CONFIG_NET_6LOWPAN_MAX_MACTRANSMITS=4 CONFIG_NET_6LOWPAN_MTU=1294 diff --git a/drivers/wireless/Kconfig b/drivers/wireless/Kconfig index a3bab81d21..39622d66fd 100644 --- a/drivers/wireless/Kconfig +++ b/drivers/wireless/Kconfig @@ -20,7 +20,6 @@ source drivers/wireless/cc3000/Kconfig menuconfig DRIVERS_IEEE802154 bool "IEEE 802.15.4 Device Support" default n - depends on EXPERIMENTAL ---help--- This directory holds implementations of IEEE802.15.4 device drivers. @@ -29,7 +28,6 @@ source drivers/wireless/ieee802154/Kconfig menuconfig DRIVERS_IEEE80211 bool "IEEE 802.11 Device Support" default n - depends on EXPERIMENTAL ---help--- This directory holds implementations of IEEE802.11 device drivers. diff --git a/drivers/wireless/ieee802154/Kconfig b/drivers/wireless/ieee802154/Kconfig index 93e802323d..d0d8c550ec 100644 --- a/drivers/wireless/ieee802154/Kconfig +++ b/drivers/wireless/ieee802154/Kconfig @@ -11,4 +11,10 @@ config IEEE802154_MRF24J40 ---help--- This selection enables support for the Microchip MRF24J40 device. +config IEEE802154_AT86RF233 + bool "ATMEL RF233 IEEE 802.15.4 transceiver" + default n + ---help--- + This selection enables support for the Atmel RF233 device. + endif # DRIVERS_IEEE802154 diff --git a/drivers/wireless/ieee802154/Make.defs b/drivers/wireless/ieee802154/Make.defs index b0a1406baa..8e0924d67f 100644 --- a/drivers/wireless/ieee802154/Make.defs +++ b/drivers/wireless/ieee802154/Make.defs @@ -45,6 +45,10 @@ ifeq ($(CONFIG_IEEE802154_MRF24J40),y) CSRCS += mrf24j40.c endif +ifeq ($(CONFIG_IEEE802154_AT86RF233),y) + CSRCS += at86rf23x.c +endif + # Include IEEE 802.15.4 build support DEPPATH += --dep-path wireless$(DELIM)ieee802154 diff --git a/drivers/wireless/ieee802154/at86rf23x.c b/drivers/wireless/ieee802154/at86rf23x.c new file mode 100644 index 0000000000..90d99351ba --- /dev/null +++ b/drivers/wireless/ieee802154/at86rf23x.c @@ -0,0 +1,1561 @@ +/**************************************************************************** + * drivers/wireless/ieee802154/at86rf23x.c + * + * Copyright (C) 2016 Matt Poppe. All rights reserved. + * Author: Matt Poppe + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include + +#include + +#include "at86rf23x.h" + +/************************************************************************************ + * Pre-processor Definitions + ************************************************************************************/ + +#ifndef CONFIG_SCHED_HPWORK +# error High priority work queue required in this driver +#endif + +#ifndef CONFIG_SPI_EXCHANGE +# error CONFIG_SPI_EXCHANGE required for this driver +#endif + +#ifndef CONFIG_IEEE802154_at86rf23x_SPIMODE +# define CONFIG_IEEE802154_at86rf23x_SPIMODE SPIDEV_MODE0 +#endif + +#ifndef CONFIG_IEEE802154_at86rf23x_FREQUENCY +# define CONFIG_IEEE802154_at86rf23x_FREQUENCY 1000000 +#endif + +/* Definitions for the device structure */ + +#define AT86RF23X_RXMODE_NORMAL 0 +#define AT86RF23X_RXMODE_PROMISC 1 +#define AT86RF23X_RXMODE_NOCRC 2 +#define AT86RF23X_RXMODE_AUTOACK 3 + +/* Definitions for PA control on high power modules */ + +#define AT86RF23X_PA_AUTO 1 +#define AT86RF23X_PA_ED 2 +#define AT86RF23X_PA_SLEEP 3 + +/************************************************************************************ + * Private Types + ************************************************************************************/ + +/* AT86RF23x device instance + * + * Make sure that struct ieee802154_radio_s remains first. If not it will break the + * code + */ + +struct at86rf23x_dev_s +{ + struct ieee802154_radio_s ieee; /* Public device instance */ + FAR struct spi_dev_s *spi; /* Saved SPI interface instance */ + struct work_s irqwork; /* Interrupt continuation work queue support */ + FAR const struct at86rf23x_lower_s *lower; /* Low-level MCU-specific support */ + uint16_t panid; /* PAN identifier, FFFF = not set */ + uint16_t saddr; /* Short address, FFFF = not set */ + uint8_t eaddr[8]; /* Extended address, FFFFFFFFFFFFFFFF = not set */ + uint8_t channel; /* 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 */ +}; + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +/* Internal operations */ + +static void at86rf23x_lock(FAR struct spi_dev_s *spi); +static void at86rf23x_unlock(FAR struct spi_dev_s *spi); +static void at86rf23x_setreg(FAR struct spi_dev_s *spi, uint32_t addr, + uint8_t val); +static uint8_t at86rf23x_getreg(FAR struct spi_dev_s *spi, uint32_t addr); +static int at86rf23x_writeframe(FAR struct spi_dev_s *spi, FAR uint8_t *frame, + uint8_t len); +static uint8_t at86rf23x_readframe(FAR struct spi_dev_s *spi, + FAR uint8_t *frame_rx); +static int at86rf23x_setTRXstate(FAR struct at86rf23x_dev_s *dev, + uint8_t state, uint8_t force); +static uint8_t at86rf23x_getTRXstate(FAR struct at86rf23x_dev_s *dev); +static int at86rf23x_resetrf(FAR struct at86rf23x_dev_s *dev); +static int at86rf23x_initialize(FAR struct at86rf23x_dev_s *dev); + +static int at86rf23x_regdump(FAR struct at86rf23x_dev_s *dev); +static void at86rf23x_irqwork_rx(FAR struct at86rf23x_dev_s *dev); +static void at86rf23x_irqwork_tx(FAR struct at86rf23x_dev_s *dev); +static void at86rf23x_irqworker(FAR void *arg); +static int at86rf23x_interrupt(int irq, FAR void *context, FAR void *arg); + + +static int at86rf23x_setchannel(FAR struct ieee802154_radio_s *ieee, + uint8_t chan); +static int at86rf23x_getchannel(FAR struct ieee802154_radio_s *ieee, + FAR uint8_t *chan); +static int at86rf23x_setpanid(FAR struct ieee802154_radio_s *ieee, + uint16_t panid); +static int at86rf23x_getpanid(FAR struct ieee802154_radio_s *ieee, + FAR uint16_t *panid); +static int at86rf23x_setsaddr(FAR struct ieee802154_radio_s *ieee, + uint16_t saddr); +static int at86rf23x_getsaddr(FAR struct ieee802154_radio_s *ieee, + FAR uint16_t *saddr); +static int at86rf23x_seteaddr(FAR struct ieee802154_radio_s *ieee, + FAR uint8_t *eaddr); +static int at86rf23x_geteaddr(FAR struct ieee802154_radio_s *ieee, + FAR uint8_t *eaddr); +static int at86rf23x_setpromisc(FAR struct ieee802154_radio_s *ieee, + bool promisc); +static int at86rf23x_getpromisc(FAR struct ieee802154_radio_s *ieee, + FAR bool *promisc); +static int at86rf23x_setdevmode(FAR struct ieee802154_radio_s *ieee, + uint8_t mode); +static int at86rf23x_getdevmode(FAR struct ieee802154_radio_s *ieee, + FAR uint8_t *mode); +static int at86rf23x_settxpower(FAR struct ieee802154_radio_s *ieee, + int32_t txpwr); +static int at86rf23x_gettxpower(FAR struct ieee802154_radio_s *ieee, + FAR int32_t *txpwr); +static int at86rf23x_setcca(FAR struct ieee802154_radio_s *ieee, + FAR struct ieee802154_cca_s *cca); +static int at86rf23x_getcca(FAR struct ieee802154_radio_s *ieee, + FAR struct ieee802154_cca_s *cca); +static int at86rf23x_energydetect(FAR struct ieee802154_radio_s *ieee, + FAR uint8_t *energy); + +/* Driver operations */ + +static int at86rf23x_rxenable(FAR struct ieee802154_radio_s *ieee, + bool state, FAR struct ieee802154_packet_s *packet); +static int at86rf23x_transmit(FAR struct ieee802154_radio_s *ieee, + FAR struct ieee802154_packet_s *packet); + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/* These are pointers to ALL registered at86rf23x devices. + * This table is used during irqs to find the context + * Only one device is supported for now. + * More devices can be supported in the future by lookup them up + * using the IRQ number. See the ENC28J60 or CC3000 drivers for reference. + */ + +static struct at86rf23x_dev_s g_at86rf23x_devices[1]; + +static const struct ieee802154_radioops_s at86rf23x_devops = +{ + .ioctl = at86rf23x_ioctl, + .rxenable = at86rf23x_rxenable, + .transmit = at86rf23x_transmit +}; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: at86rf23x_lock + * + * Description: + * Acquire exclusive access to the shared SPI bus. + * + ****************************************************************************/ + +static void at86rf23x_lock(FAR struct spi_dev_s *spi) +{ + SPI_LOCK(spi, 1); + SPI_SETBITS(spi, 8); + SPI_SETMODE(spi, CONFIG_IEEE802154_at86rf23x_SPIMODE); + SPI_SETFREQUENCY(spi, CONFIG_IEEE802154_at86rf23x_FREQUENCY); +} + +/**************************************************************************** + * Name: at86rf23x_unlock + * + * Description: + * Release exclusive access to the shared SPI bus. + * + ****************************************************************************/ + +static void at86rf23x_unlock(FAR struct spi_dev_s *spi) +{ + SPI_LOCK(spi, 0); +} + +/**************************************************************************** + * Name: at86rf23x_setreg + * + * Description: + * Define the value of an at86rf23x device register + * + ****************************************************************************/ + +static void at86rf23x_setreg(FAR struct spi_dev_s *spi, uint32_t addr, + uint8_t val) +{ + uint8_t reg[2]; + + reg[0] = addr; + reg[0] |= RF23X_SPI_REG_WRITE; + + reg[1] = val; + at86rf23x_lock(spi); + SPI_SELECT(spi, SPIDEV_IEEE802154(0), true); + SPI_SNDBLOCK(spi, reg, 2); + SPI_SELECT(spi, SPIDEV_IEEE802154(0), false); + at86rf23x_unlock(spi); + + wlinfo("0x%02X->r[0x%02X]\n", val, addr); +} + +/**************************************************************************** + * Name: at86rf23x_getreg + * + * Description: + * Return the value of an at86rf23x device register + * + ****************************************************************************/ + +static uint8_t at86rf23x_getreg(FAR struct spi_dev_s *spi, uint32_t addr) +{ + uint8_t reg[2]; + uint8_t val[2]; + + /* Add Read mask to desired register */ + + reg[0] = addr | RF23X_SPI_REG_READ; + + at86rf23x_lock (spi); + + SPI_SELECT(spi, SPIDEV_IEEE802154(0), true); + SPI_EXCHANGE(spi, reg, val, 2); + SPI_SELECT(spi, SPIDEV_IEEE802154(0), false); + + at86rf23x_unlock(spi); + + wlinfo("r[0x%02X]=0x%02X\n",addr,val[1]); + + return val[1]; +} + +/**************************************************************************** + * Name: at86rf23x_setregbits + * + * Description: + * Read the current value of the register. Change only the portion + * of the register we need to change and write the value back to the + * register. + * + ****************************************************************************/ + +static void at86rf23x_setregbits(FAR struct spi_dev_s *spi, uint8_t addr, + uint8_t pos, uint8_t mask, uint8_t val) +{ + uint8_t reg; + + reg = at86rf23x_getreg(spi, addr); + reg = (reg & ~(mask << pos)) | (val << pos); + at86rf23x_setreg(spi, addr, reg); +} + +/**************************************************************************** + * Name: at86rf23x_getregbits + * + * Description: + * Return the value of an section of the at86rf23x device register. + * + ****************************************************************************/ + +static uint8_t at86rf23x_getregbits(FAR struct spi_dev_s *spi, uint8_t addr, + uint8_t pos, uint8_t mask) +{ + uint8_t val; + + val = at86rf23x_getreg(spi, addr); + val = (val >> pos) & mask; + + return val; +} + +/**************************************************************************** + * Name: at86rf23x_writebuffer + * + * Description: + * Write frame to the transmit buffer of the radio. This does not + * initiate the transfer, just write to the buffer. + * + ****************************************************************************/ + +static int at86rf23x_writeframe(FAR struct spi_dev_s *spi, FAR uint8_t *frame, + uint8_t len) +{ +//report_packet(frame_wr, len); + uint8_t reg = RF23X_SPI_FRAME_WRITE; + + at86rf23x_lock(spi); + + SPI_SELECT(spi, SPIDEV_IEEE802154(0), true); + + SPI_SNDBLOCK(spi, ®, 1); + SPI_SNDBLOCK(spi, &frame, len); + + SPI_SELECT(spi, SPIDEV_IEEE802154(0), false); + + at86rf23x_unlock(spi); + + return len; +} + +/**************************************************************************** + * Name: at86rf23x_readframe + * + * Description: + * Read the buffer memory of the radio. This is used when the radio + * indicates a frame has been received. + * + ****************************************************************************/ + +static uint8_t at86rf23x_readframe(FAR struct spi_dev_s *spi, + FAR uint8_t *frame_rx) +{ + uint8_t len, reg; + + reg = RF23X_SPI_FRAME_READ; + + at86rf23x_lock(spi); + SPI_SELECT(spi, SPIDEV_IEEE802154(0), true); + + SPI_SNDBLOCK(spi, ®, 1); + SPI_RECVBLOCK(spi, &len, 1); + SPI_RECVBLOCK(spi, frame_rx, len+3); + + SPI_SELECT(spi, SPIDEV_IEEE802154(0), false); + at86rf23x_unlock(spi); + + return len; +} + +/**************************************************************************** + * Name: at86rf23x_getTRXstate + * + * Description: + * Return the current status of the TRX state machine. + * + ****************************************************************************/ + +static uint8_t at86rf23x_getTRXstate(FAR struct at86rf23x_dev_s *dev) +{ + return at86rf23x_getregbits(dev->spi, RF23X_TRXSTATUS_STATUS); +} + +/**************************************************************************** + * Name: at86rf23x_setTRXstate + * + * Description: + * Set the TRX state machine to the desired state. If the state machine + * cannot move to the desired state an ERROR is returned. If the transistion + * is successful an OK is returned. This is a long running function due to + * waiting for the transistion delay between states. This can be as long as + * 510us. + * + ****************************************************************************/ + +static int at86rf23x_setTRXstate(FAR struct at86rf23x_dev_s *dev, + uint8_t state, uint8_t force) +{ + /* Get the current state of the transceiver */ + + uint8_t status = at86rf23x_getTRXstate(dev); + + int ret = OK; + + /* TODO I don't have every state included verify this will work with SLEEP */ + + if ((status != TRX_STATUS_TRXOFF) && + (status != TRX_STATUS_RXON) && + (status != TRX_STATUS_PLLON) && + (status != TRX_STATUS_RXAACKON) && + (status != TRX_STATUS_TXARETON) && + (status != TRX_STATUS_PON)) + { + wlerr("ERROR: Invalid State\n"); + return ERROR; + } + + int8_t init_status = status; + + /* Start the state change */ + + switch(state) + { + case TRX_CMD_TRXOFF: + if (status == TRX_STATUS_TRXOFF) + { + break; + } + + /* verify in a state that will transfer to TRX_OFF if not check if + * force is required. + */ + + if ((status == TRX_STATUS_RXON) || + (status == TRX_STATUS_PLLON) || + (status == TRX_STATUS_RXAACKON) || + (status == TRX_STATUS_TXARETON)) + { + at86rf23x_setregbits(dev->spi, RF23X_TRXCMD_STATE, TRX_CMD_TRXOFF); + up_udelay(RF23X_TIME_TRANSITION_PLL_ACTIVE); + } + else if (status == TRX_STATUS_PON) + { + at86rf23x_setregbits(dev->spi, RF23X_TRXCMD_STATE, TRX_CMD_TRXOFF); + up_udelay(RF23X_TIME_P_ON_TO_TRXOFF); + } + else if (force) + { + at86rf23x_setregbits(dev->spi, RF23X_TRXCMD_STATE, TRX_CMD_FORCETRXOFF); + up_udelay(RF23X_TIME_FORCE_TRXOFF); + } + + status = at86rf23x_getregbits(dev->spi, RF23X_TRXSTATUS_STATUS); + if (status != TRX_STATUS_TRXOFF) + { + ret = ERROR; + } + + break; + + case TRX_CMD_RX_ON: + if (status == TRX_STATUS_RXON) + { + break; + } + + if (status == TRX_STATUS_TRXOFF) + { + at86rf23x_setregbits(dev->spi, RF23X_TRXCMD_STATE, TRX_CMD_RX_ON); + up_udelay(RF23X_TIME_TRXOFF_TO_PLL); + } + else if ((status == TRX_STATUS_RXAACKON) || + (status == TRX_STATUS_RXON) || + (status == TRX_STATUS_PLLON) || + (status == TRX_STATUS_TXARETON)) + { + at86rf23x_setregbits(dev->spi, RF23X_TRXCMD_STATE, TRX_CMD_RX_ON); + up_udelay(RF23X_TIME_TRANSITION_PLL_ACTIVE); + } + + status = at86rf23x_getregbits(dev->spi, RF23X_TRXSTATUS_STATUS); + if (status != TRX_STATUS_RXON) + { + ret = ERROR; + } + + break; + + /* Transition to PLL_ON */ + + case TRX_CMD_PLL_ON: + if (status == TRX_STATUS_PLLON) + { + break; + } + + if (status == TRX_STATUS_TRXOFF) + { + at86rf23x_setregbits(dev->spi, RF23X_TRXCMD_STATE, TRX_CMD_PLL_ON); + up_udelay(RF23X_TIME_TRXOFF_TO_PLL); + } + else + { + at86rf23x_setregbits(dev->spi, RF23X_TRXCMD_STATE, TRX_CMD_PLL_ON); + up_udelay(RF23X_TIME_TRANSITION_PLL_ACTIVE); + } + + status = at86rf23x_getregbits(dev->spi, RF23X_TRXSTATUS_STATUS); + if (status != TRX_STATUS_PLLON) + { + ret = ERROR; + } + + break; + + case TRX_CMD_RX_AACK_ON: + if (status == TRX_STATUS_RXAACKON) + { + break; + } + + if (status == TRX_STATUS_TRXOFF || status == TRX_STATUS_TXARETON) + { + at86rf23x_setregbits(dev->spi, RF23X_TRXCMD_STATE, TRX_CMD_RX_ON); + + (status == TRX_STATUS_TRXOFF) ? up_udelay(RF23X_TIME_TRXOFF_TO_PLL) : + up_udelay(RF23X_TIME_TRANSITION_PLL_ACTIVE); + } + + status = at86rf23x_getTRXstate(dev); + if ((status == TRX_STATUS_RXON) || (status == TRX_STATUS_PLLON)) + { + at86rf23x_setregbits(dev->spi, RF23X_TRXCMD_STATE, TRX_CMD_RX_AACK_ON); + up_udelay(RF23X_TIME_TRANSITION_PLL_ACTIVE); + } + + status = at86rf23x_getregbits(dev->spi, RF23X_TRXSTATUS_STATUS); + if (status != TRX_STATUS_RXAACKON) + { + ret = ERROR; + } + + break; + + case TRX_STATUS_TXARETON: + if (status == TRX_STATUS_TXARETON) + { + break; + } + + if (status == TRX_STATUS_TRXOFF) + { + at86rf23x_setregbits(dev->spi, RF23X_TRXCMD_STATE, TRX_CMD_RX_ON); + up_udelay(RF23X_TIME_TRXOFF_TO_PLL); + } + + if ((status == TRX_STATUS_RXON) || (status == TRX_STATUS_PLLON)) + { + at86rf23x_setregbits(dev->spi, RF23X_TRXCMD_STATE, TRX_CMD_TX_ARET_ON); + up_udelay(RF23X_TIME_TRANSITION_PLL_ACTIVE); + } + else if (status == TRX_STATUS_RXAACKON) + { + at86rf23x_setregbits(dev->spi, RF23X_TRXCMD_STATE, TRX_CMD_RX_ON); + up_udelay(RF23X_TIME_TRANSITION_PLL_ACTIVE); + + at86rf23x_setregbits(dev->spi, RF23X_TRXCMD_STATE, TRX_CMD_TX_ARET_ON); + up_udelay(RF23X_TIME_TRANSITION_PLL_ACTIVE); + } + + status = at86rf23x_getregbits(dev->spi, RF23X_TRXSTATUS_STATUS); + if (status != TRX_STATUS_TXARETON) + { + ret = ERROR; + } + + break; + + case TRX_STATUS_SLEEP: + at86rf23x_setregbits(dev->spi, RF23X_TRXCMD_STATE, TRX_CMD_FORCETRXOFF); + up_udelay(RF23X_TIME_CMD_FORCE_TRX_OFF); + + dev->lower->slptr(dev->lower, true); + up_udelay(RF23X_TIME_TRXOFF_TO_SLEEP); + + status = at86rf23x_getregbits(dev->spi, RF23X_TRXSTATUS_STATUS); + break; + + default: + wlerr("ERRPR: %s \n", EINVAL_STR); + init_status = 0;/* Placed this here to keep compiler happy when not in debug */ + return -EINVAL; + } + + if (ret == ERROR) + { + wlerr("ERROR: State Transistion Error\n"); + } + + wlinfo("Radio state change state[0x%02x]->state[0x%02x]\n", init_status, status); + return ret; +} + +/**************************************************************************** + * Name: at86rf23x_setchannel + * + * Description: + * Define the current radio channel the device is operating on. + * In the 2.4 GHz, there are 16 channels, each 2 MHz wide, 5 MHz spacing: + * Chan MHz Chan MHz Chan MHz Chan MHz + * 11 2405 15 2425 19 2445 23 2465 + * 12 2410 16 2430 20 2450 24 2470 + * 13 2415 17 2435 21 2455 25 2475 + * 14 2420 18 2440 22 2460 26 2480 + * + * + ****************************************************************************/ + +static int at86rf23x_setchannel(FAR struct ieee802154_radio_s *ieee, + uint8_t chan) +{ + FAR struct at86rf23x_dev_s *dev = (FAR struct at86rf23x_dev_s *)ieee; + uint8_t state; + + /* Validate if chan is a valid channel */ + + if (chan < 11 || chan > 26) + { + wlerr("ERROR: Invalid requested chan: %d\n",chan); + return -EINVAL; + } + + /* Validate we are in an acceptable mode to change the channel */ + + state = at86rf23x_getTRXstate(dev); + + if ((TRX_STATUS_SLEEP == state) || (TRX_STATUS_PON == state)) + { + wlerr("ERROR: Radio in invalid mode [%02x] to set the channel\n", state); + return ERROR; + } + + /* Set the Channel on the transceiver */ + + at86rf23x_setregbits(dev->spi, RF23X_CCA_BITS_CHANNEL, chan); + + /* Set the channel within local device */ + + dev->channel = chan; + + wlinfo("CHANNEL Changed to %d\n", chan); + return OK; +} + +/**************************************************************************** + * Name: at86rf23x_getchannel + * + * 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 + * + * This section assumes that the transceiver is not in SLEEP or P_ON state. + * + * + ****************************************************************************/ + +static int at86rf23x_getchannel(FAR struct ieee802154_radio_s *ieee, + FAR uint8_t *chan) +{ + FAR struct at86rf23x_dev_s *dev = (FAR struct at86rf23x_dev_s *)ieee; + + /* Set the Channel on the transceiver */ + + *chan = at86rf23x_getregbits(dev->spi, RF23X_CCA_BITS_CHANNEL); + + /* Set the channel within local device */ + + dev->channel = *chan; + return OK; +} + +/**************************************************************************** + * Name: at86rf23x_setpanid + * + * Description: + * Define the PAN ID for the network. + * + ****************************************************************************/ + +static int at86rf23x_setpanid(FAR struct ieee802154_radio_s *ieee, + uint16_t panid) +{ + FAR struct at86rf23x_dev_s *dev = (struct at86rf23x_dev_s *)ieee; + uint8_t *pan = (uint8_t *)&panid; + + at86rf23x_setreg(dev->spi, RF23X_REG_PANID0, pan[0]); + at86rf23x_setreg(dev->spi, RF23X_REG_PANID1, pan[1]); + + return OK; +} + +/**************************************************************************** + * Name: at86rf23x_getpanid + * + * Description: + * Define the PAN ID for the network. + * + ****************************************************************************/ + +static int at86rf23x_getpanid(FAR struct ieee802154_radio_s *ieee, + FAR uint16_t *panid) +{ + FAR struct at86rf23x_dev_s *dev = (struct at86rf23x_dev_s *)ieee; + uint8_t *pan = (uint8_t *)panid; + + /* TODO: Check if we need to pay attention to endianness */ + + pan[0] = at86rf23x_getreg(dev->spi, RF23X_REG_PANID0); + pan[1] = at86rf23x_getreg(dev->spi, RF23X_REG_PANID1); + return OK; +} + +/**************************************************************************** + * Name: at86rf23x_setsaddr + * + * Description: + * Define the Short Address for the device. + * + ****************************************************************************/ + +static int at86rf23x_setsaddr(FAR struct ieee802154_radio_s *ieee, + uint16_t saddr) +{ + FAR struct at86rf23x_dev_s *dev = (struct at86rf23x_dev_s *)ieee; + uint8_t *addr = (uint8_t *)&saddr; + + at86rf23x_setreg(dev->spi, RF23X_REG_SADDR0, addr[0]); + at86rf23x_setreg(dev->spi, RF23X_REG_SADDR1, addr[1]); + + return OK; +} + +/**************************************************************************** + * Name: at86rf23x_getsaddr + * + * Description: + * Get the short address of the device. + * + ****************************************************************************/ + +static int at86rf23x_getsaddr(FAR struct ieee802154_radio_s *ieee, + FAR uint16_t *saddr) +{ + FAR struct at86rf23x_dev_s *dev = (struct at86rf23x_dev_s *)ieee; + uint8_t *addr = (uint8_t *)saddr; + + /* TODO: Check if we need to pay attention to endianness */ + + addr[0] = at86rf23x_getreg(dev->spi, RF23X_REG_SADDR0); + addr[1] = at86rf23x_getreg(dev->spi, RF23X_REG_SADDR1); + + return OK; +} + +/**************************************************************************** + * Name: at86rf23x_seteaddr + * + * Description: + * Set the IEEE address of the device. + * + ****************************************************************************/ + +static int at86rf23x_seteaddr(FAR struct ieee802154_radio_s *ieee, + FAR uint8_t *eaddr) +{ + FAR struct at86rf23x_dev_s *dev = (struct at86rf23x_dev_s *)ieee; + + /* TODO: Check if we need to pay attention to endianness */ + + at86rf23x_setreg(dev->spi, RF23X_REG_IEEEADDR0, eaddr[0]); + at86rf23x_setreg(dev->spi, RF23X_REG_IEEEADDR1, eaddr[1]); + at86rf23x_setreg(dev->spi, RF23X_REG_IEEEADDR2, eaddr[2]); + at86rf23x_setreg(dev->spi, RF23X_REG_IEEEADDR3, eaddr[3]); + at86rf23x_setreg(dev->spi, RF23X_REG_IEEEADDR4, eaddr[4]); + at86rf23x_setreg(dev->spi, RF23X_REG_IEEEADDR5, eaddr[5]); + at86rf23x_setreg(dev->spi, RF23X_REG_IEEEADDR6, eaddr[6]); + at86rf23x_setreg(dev->spi, RF23X_REG_IEEEADDR7, eaddr[7]); + + return OK; +} + +/**************************************************************************** + * Name: at86rf23x_geteaddr + * + * Description: + * Get the IEEE address of the device. + * + ****************************************************************************/ + +static int at86rf23x_geteaddr(FAR struct ieee802154_radio_s *ieee, + FAR uint8_t *eaddr) +{ + FAR struct at86rf23x_dev_s *dev = (struct at86rf23x_dev_s *)ieee; + + /* TODO: Check if we need to pay attention to endianness */ + + eaddr[0] = at86rf23x_getreg(dev->spi, RF23X_REG_IEEEADDR0); + eaddr[1] = at86rf23x_getreg(dev->spi, RF23X_REG_IEEEADDR1); + eaddr[2] = at86rf23x_getreg(dev->spi, RF23X_REG_IEEEADDR2); + eaddr[3] = at86rf23x_getreg(dev->spi, RF23X_REG_IEEEADDR3); + eaddr[4] = at86rf23x_getreg(dev->spi, RF23X_REG_IEEEADDR4); + eaddr[5] = at86rf23x_getreg(dev->spi, RF23X_REG_IEEEADDR5); + eaddr[6] = at86rf23x_getreg(dev->spi, RF23X_REG_IEEEADDR6); + eaddr[7] = at86rf23x_getreg(dev->spi, RF23X_REG_IEEEADDR7); + + return OK; +} + +/**************************************************************************** + * Name: at86rf23x_setpromisc + * + * Description: + * enable/disable promiscuous mode. + * + ****************************************************************************/ + +static int at86rf23x_setpromisc(FAR struct ieee802154_radio_s *ieee, + bool promisc) +{ + FAR struct at86rf23x_dev_s *dev = (struct at86rf23x_dev_s *)ieee; + + /* TODO: Check what mode I should be in to activate promiscuous mode: + * This is way to simple of an implementation. Many other things should be set + * and/or checked before we set the device into promiscuous mode + */ + + at86rf23x_setregbits(dev->spi, RF23X_XAHCTRL1_BITS_PROM_MODE, promisc); + return OK; +} + +/**************************************************************************** + * Name: at86rf23x_getpromisc + * + * Description: + * Check if the device is in promiscuous mode. + * + ****************************************************************************/ + +static int at86rf23x_getpromisc(FAR struct ieee802154_radio_s *ieee, + FAR bool *promisc) +{ + FAR struct at86rf23x_dev_s *dev = (struct at86rf23x_dev_s *)ieee; + + *promisc = at86rf23x_getregbits(dev->spi, RF23X_XAHCTRL1_BITS_PROM_MODE); + return OK; +} + +/**************************************************************************** + * Name: at86rf23x_setdevmode + * + * Description: + * Check if the device is in promiscuous mode. + * + ****************************************************************************/ + +static int at86rf23x_setdevmode(FAR struct ieee802154_radio_s *ieee, + uint8_t mode) +{ + FAR struct at86rf23x_dev_s *dev = (struct at86rf23x_dev_s *)ieee; + + /* Define dev mode */ + + if (mode == IEEE802154_MODE_PANCOORD) + { + at86rf23x_setregbits(dev->spi, RF23X_CSMASEED1_IAMCOORD_BITS, 0x01); + } + else if (mode == IEEE802154_MODE_COORD) + { + /* ????? */ + } + else if (mode == IEEE802154_MODE_DEVICE) + { + at86rf23x_setregbits(dev->spi, RF23X_CSMASEED1_IAMCOORD_BITS, 0x00); + } + else + { + return -EINVAL; + } + + dev->devmode = mode; + return OK; +} + +/**************************************************************************** + * Name: at86rf23x_getdevmode + * + * Description: + * get the device mode type of the radio. + * + ****************************************************************************/ + +static int at86rf23x_getdevmode(FAR struct ieee802154_radio_s *ieee, + FAR uint8_t *mode) +{ + FAR struct at86rf23x_dev_s *dev = (struct at86rf23x_dev_s *)ieee; + int val; + + val = at86rf23x_getregbits(dev->spi, RF23X_CSMASEED1_IAMCOORD_BITS); + if (val == 1) + { + *mode = IEEE802154_MODE_PANCOORD; + } + else + { + *mode = IEEE802154_MODE_DEVICE; + } + + return OK; +} + +/**************************************************************************** + * Name: at86rf23x_settxpower + * + * Description: + * set the tx power attenuation or amplification + * + ****************************************************************************/ + +static int at86rf23x_settxpower(FAR struct ieee802154_radio_s *ieee, + int32_t txpwr) +{ + FAR struct at86rf23x_dev_s *dev = (struct at86rf23x_dev_s *)ieee; + + /* TODO: this needs alot of work to make sure all chips can share this function */ + + /* Right now we only set tx power to 0 */ + + at86rf23x_setreg(dev->spi, RF23X_REG_TXPWR, RF23X_TXPWR_0); + return OK; +} + +/**************************************************************************** + * Name: at86rf23x_gettxpower + * + * Description: + * get the tx power attenuation or amplification. + * + ****************************************************************************/ + +static int at86rf23x_gettxpower(FAR struct ieee802154_radio_s *ieee, + FAR int32_t *txpwr) +{ + FAR struct at86rf23x_dev_s *dev = (struct at86rf23x_dev_s *)ieee; + uint8_t reg; + + /* TODO: this needs alot of work to make sure all chips can share this + * function. + */ + + /* Right now we only get negative values */ + + reg = at86rf23x_getreg(dev->spi, RF23X_REG_TXPWR); + switch (reg) + { + case RF23X_TXPWR_POS_4: + *txpwr = 0; + break; + + case RF23X_TXPWR_POS_3_7: + *txpwr = 0; + break; + + case RF23X_TXPWR_POS_3_4: + *txpwr = 0; + break; + + case RF23X_TXPWR_POS_3: + *txpwr = 0; + break; + + case RF23X_TXPWR_POS_2_5: + *txpwr = 0; + break; + + case RF23X_TXPWR_POS_2: + *txpwr = 0; + break; + + case RF23X_TXPWR_POS_1: + *txpwr = 0; + break; + + case RF23X_TXPWR_0: + *txpwr = 0; + break; + + case RF23X_TXPWR_NEG_1: + *txpwr = 1000; + break; + + case RF23X_TXPWR_NEG_2: + *txpwr = 2000; + break; + + case RF23X_TXPWR_NEG_3: + *txpwr = 3000; + break; + + case RF23X_TXPWR_NEG_4: + *txpwr = 4000; + break; + + case RF23X_TXPWR_NEG_6: + *txpwr = 6000; + break; + + case RF23X_TXPWR_NEG_8: + *txpwr = 8000; + break; + + case RF23X_TXPWR_NEG_12: + *txpwr = 12000; + break; + + case RF23X_TXPWR_NEG_17: + *txpwr = 17000; + break; + } + + return OK; +} + +/**************************************************************************** + * Name: at86rf23x_setcca + * + * Description: + * Configures if energy detection is used or carrier sense. The base + * measurement is configured here as well + * + * + ****************************************************************************/ + +static int at86rf23x_setcca(FAR struct ieee802154_radio_s *ieee, + FAR struct ieee802154_cca_s *cca) +{ + FAR struct at86rf23x_dev_s *dev = (struct at86rf23x_dev_s *)ieee; + + /* TODO: This doesn't fit the RF233 completely come back to this */ + + if (!cca->use_ed && !cca->use_cs) + { + return -EINVAL; + } + + if (cca->use_cs && cca->csth > 0x0f) + { + return -EINVAL; + } + + if (cca->use_ed) + { + at86rf23x_setregbits(dev->spi, RF23X_CCA_BITS_MODE, RF23X_CCA_MODE_ED); + } + + if (cca->use_cs) + { + at86rf23x_setregbits(dev->spi, RF23X_CCA_BITS_MODE, RF23X_CCA_MODE_CS); + } + + memcpy(&dev->cca, cca, sizeof(struct ieee802154_cca_s)); + return OK; +} + +/**************************************************************************** + * Name: at86rf23x_getcca + * + * Description: + * Get CCA for ???: TODO: need to implement + * + ****************************************************************************/ + +static int at86rf23x_getcca(FAR struct ieee802154_radio_s *ieee, + FAR struct ieee802154_cca_s *cca) +{ + FAR struct at86rf23x_dev_s *dev = (struct at86rf23x_dev_s *)ieee; + +#warning at86rf23x_getcca not implemented. + + UNUSED(dev); + UNUSED(cca); + + return ERROR; +} + +/**************************************************************************** + * Name: at86rf23x_energydetect + * + * Description: + * Perform energy detection scan. TODO: Need to implement. + * + ****************************************************************************/ + +static int at86rf23x_energydetect(FAR struct ieee802154_radio_s *ieee, + FAR uint8_t *energy) +{ +#warning at86rf23x_energydetect not implemented. + + /* Not yet implemented */ + + return ERROR; +} + +/**************************************************************************** + * Name: at86rf23x_initialize + * + * Description: + * Initialize the radio. + * + ****************************************************************************/ + +int at86rf23x_initialize(FAR struct at86rf23x_dev_s *dev) +{ + uint8_t part; + uint8_t version; + + at86rf23x_resetrf(dev); + + part = at86rf23x_getreg(dev->spi, RF23X_REG_PART); + version = at86rf23x_getreg(dev->spi, RF23X_REG_VERSION); + + wlinfo("Radio part: 0x%02x version: 0x%02x found\n", part, version); + return OK; +} + +/**************************************************************************** + * Name: at86rf23x_resetrf + * + * Description: + * Hard Reset of the radio. The reset also brings the radio into the + * TRX_OFF state. + * + ****************************************************************************/ + +static int at86rf23x_resetrf(FAR struct at86rf23x_dev_s *dev) +{ + FAR const struct at86rf23x_lower_s *lower = dev->lower; + uint8_t trx_status, retry_cnt = 0; + + /* Reset the radio */ + + lower->reset(lower, false); + lower->slptr(lower, false); + + up_udelay(RF23X_TIME_RESET); + lower->reset(lower, true); + + /* Dummy read of IRQ register */ + + at86rf23x_getreg(dev->spi, RF23X_REG_IRQ_STATUS); + + do + { + trx_status = at86rf23x_setTRXstate(dev, TRX_CMD_TRXOFF, true); + + if (retry_cnt == RF23X_MAX_RETRY_RESET_TO_TRX_OFF) + { + wlerr("ERROR: Reset of transceiver failed\n"); + return ERROR; + } + + retry_cnt++; + } + while (trx_status != OK); + + return OK; +} + +/**************************************************************************** + * Name: at86rf23x_rxenable + * + * Description: + * puts the radio into RX mode and brings in the buffer to handle + * RX messages. + * + ****************************************************************************/ + +static int at86rf23x_rxenable(FAR struct ieee802154_radio_s *ieee, bool state, + FAR struct ieee802154_packet_s *packet) +{ + FAR struct at86rf23x_dev_s *dev = (FAR struct at86rf23x_dev_s *)ieee; + + /* Set the radio to the receive state */ + + return at86rf23x_setTRXstate(dev, TRX_CMD_RX_ON, false); + + /* Enable the RX IRQ */ + + /* TODO: + * I am not sure what to do here since the at86rf23x shares the + * irq with the tx finished. Better planning needs to be done on + * my end. + */ + + /* Set buffer to receive next packet */ + + ieee->rxbuf = packet; +} + +/**************************************************************************** + * Name: at86rf23x_interrupt + * + * Description: + * Actual interrupt handler ran inside privileged space. + * + ****************************************************************************/ + +static int at86rf23x_interrupt(int irq, FAR void *context, FAR void *arg) +{ + FAR struct at86rf23x_dev_s *dev = (FAR struct at86rf23x_dev_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, at86rf23x_irqworker, + (FAR void *)dev, 0); +} + +/**************************************************************************** + * Name: at86rf23x_regdump + * + * Description: + * Dumps all the RF23X radios registers from 00 - 2F there are a few other + * registers that don't get dumped but just fore the ease of code I left + * them out. + * + ****************************************************************************/ + +static int at86rf23x_regdump(FAR struct at86rf23x_dev_s *dev) +{ + uint32_t i; + char buf[4+16*3+2+1]; + int len=0; + + printf("RF23X regs:\n"); + + for (i=0;i<0x30;i++) + { + /* First row and every 15 regs */ + + if ((i & 0x0f) == 0) + { + len = sprintf(buf, "%02x: ",i&0xFF); + } + + /* Print the register value */ + + len += sprintf(buf+len, "%02x ", at86rf23x_getreg(dev->spi, i)); + + /* At the end of each 15 regs or end of rf233s regs and actually print + * debug message. + */ + + if ((i&15) == 15 || i == 0x2f) + { + sprintf(buf+len, "\n"); + printf("%s",buf); + } + } + + /* TODO: I have a few more regs that are not consecutive. Will print later */ + + return 0; +} + +/**************************************************************************** + * Name: at86rf23x_irqworker + * + * Description: + * Actual thread to handle the irq outside of privaleged mode. + * + ****************************************************************************/ + +static void at86rf23x_irqworker(FAR void *arg) +{ + FAR struct at86rf23x_dev_s *dev = (FAR struct at86rf23x_dev_s *)arg; + uint8_t irq_status = at86rf23x_getreg(dev->spi, RF23X_REG_IRQ_STATUS); + + wlinfo("IRQ: 0x%02X\n", irq_status); + + if ((irq_status & (1<<3)) != 0) + { + if ((irq_status & (1<<2)) != 0) + { + at86rf23x_irqwork_rx(dev); + } + else + { + at86rf23x_irqwork_tx(dev); + } + } + else + { + wlerr("ERROR: Unknown IRQ Status: %d\n", irq_status); + + /* Re-enable the IRQ even if we don't know how to handle previous + * status. + */ + + dev->lower->enable(dev->lower, true); + } +} + +/**************************************************************************** + * Name: at86rf23x_irqwork_rx + * + * Description: + * Misc/unofficial device controls. + * + ****************************************************************************/ + +static void at86rf23x_irqwork_rx(FAR struct at86rf23x_dev_s *dev) +{ + uint8_t rx_len; + + wlinfo("6LOWPAN:Rx IRQ\n"); + + rx_len = at86rf23x_readframe(dev->spi, dev->ieee.rxbuf->data); + + dev->ieee.rxbuf->len = rx_len; + dev->ieee.rxbuf->lqi = 0; + dev->ieee.rxbuf->rssi = 0; + + sem_post(&dev->ieee.rxsem); + + /* TODO: + * Not to sure yet what I should do here. I will something + * soon. + */ + + /* Re-enable the IRQ */ + + dev->lower->enable(dev->lower, true); +} + +/**************************************************************************** + * Name: at86rf23x_irqwork_tx + * + * Description: + * Misc/unofficial device controls. + * + ****************************************************************************/ + +static void at86rf23x_irqwork_tx(FAR struct at86rf23x_dev_s *dev) +{ + wlinfo("6LOWPAN:Tx IRQ\n"); + + /* TODO: + * There needs to be more here but for now just alert the waiting + * thread. Maybe put it back into Rx mode + */ + + /* Re enable the IRQ */ + + dev->lower->enable(dev->lower, true); + + sem_post(&dev->ieee.txsem); +} + +/**************************************************************************** + * Name: at86rf23x_transmit + * + * Description: + * transmission the packet. Send the packet to the radio and initiate the + * transmit process. Then block the function till we have a successful + * transmission + * + ****************************************************************************/ + +static int at86rf23x_transmit(FAR struct ieee802154_radio_s *ieee, + FAR struct ieee802154_packet_s *packet) +{ + FAR struct at86rf23x_dev_s *dev = (FAR struct at86rf23x_dev_s *)ieee; + + /* TODO: + * A plan needs to be made on when we declare the transmission successful. + * 1. If the packet is sent + * 2. If we receive an ACK. + * 3. Where do we control the retry process? + */ + + if (at86rf23x_setTRXstate(dev, TRX_CMD_PLL_ON, false)) + { + at86rf23x_writeframe(dev->spi, packet->data, packet->len); + } + else + { + wlerr("ERROR: Transmit could not put the radio in a Tx state\n"); + return ERROR; + } + + /* Put the thread that requested transfer to a waiting state */ + + sem_wait(&dev->ieee.txsem); + + /* TODO Verify that I want to stay in the PLL state or if I want to roll + * back to RX_ON. + */ + + return OK; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: at86rf23x_init + * + * Description: + * Return an at86rf23x device for use by other drivers. + * + ****************************************************************************/ + +FAR struct ieee802154_radio_s *at86rf23x_init(FAR struct spi_dev_s *spi, + FAR const struct at86rf23x_lower_s *lower) +{ + FAR struct at86rf23x_dev_s *dev; + struct ieee802154_cca_s cca; + + dev = &g_at86rf23x_devices[0]; + + /* Attach the interface, lower driver, and devops */ + + dev->spi = spi; + dev->lower = lower; + dev->ieee.ops = &at86rf23x_devops; + + /* Attach irq */ + + if (lower->attach(lower, at86rf23x_interrupt, dev) != OK) + { + return NULL; + } + + sem_init(&dev->ieee.rxsem, 0, 0); + sem_init(&dev->ieee.txsem, 0, 0); + + /* Initialize device */ + + at86rf23x_initialize(dev); + + /* Configure the desired IRQs of the devices */ + + at86rf23x_setreg(dev->spi, RF23X_REG_IRQ_MASK, RF23X_IRQ_MASK_DEFAULT); + + /* Turn the PLL to the on state */ + + at86rf23x_setTRXstate(dev, TRX_CMD_PLL_ON, false); + + /* SEED value of the CSMA backoff algorithm. */ + +#ifdef RF23X_ANTENNA_DIVERSITY + /* Use antenna diversity */ + + trx_bit_write(SR_ANT_CTRL, ANTENNA_DEFAULT); + trx_bit_write(SR_PDT_THRES, THRES_ANT_DIV_ENABLE); + trx_bit_write(SR_ANT_DIV_EN, ANT_DIV_ENABLE); + trx_bit_write(SR_ANT_EXT_SW_EN, ANT_EXT_SW_ENABLE); +#endif + +#ifdef RF23X_TIMESTAMP + /* Enable timestamp init code goes here */ + +#endif + +#ifdef RF23X_RF_FRONTEND_CTRL + /* Init front end control code goes here */ + +#endif + + /* Set the channel of the radio */ + + at86rf23x_setchannel(&dev->ieee, 12); + + /* Configure the Pan id */ + + //at86rf23x_setpanid (&dev->ieee, IEEE802154_PAN_DEFAULT); + + /* Configure the Short Addr */ + + //at86rf23x_setsaddr (&dev->ieee, IEEE802154_SADDR_UNSPEC); + + /* Configure the IEEE Addr */ + + //at86rf23x_seteaddr (&dev->ieee, IEEE802154_EADDR_UNSPEC); + + /* Default device params at86rf23x defaults to energy detect only */ + + cca.use_ed = 1; + cca.use_cs = 0; + cca.edth = 0x60; /* CCA mode ED, no carrier sense, recommenced ED + * threshold -69 dBm */ + at86rf23x_setcca(&dev->ieee, &cca); + + /* Put the Device to RX ON Mode */ + //at86rf23x_setTRXstate(dev, TRX_CMD_RX_ON, false); + + /* Enable Radio IRQ */ + + lower->enable(lower, true); + return &dev->ieee; +} diff --git a/drivers/wireless/ieee802154/at86rf23x.h b/drivers/wireless/ieee802154/at86rf23x.h new file mode 100644 index 0000000000..4d64fed0c8 --- /dev/null +++ b/drivers/wireless/ieee802154/at86rf23x.h @@ -0,0 +1,221 @@ +/**************************************************************************** + * drivers/wireless/ieee802154/at86rf23x.c + * + * Copyright (C) 2016 Matt Poppe. All rights reserved. + * Author: Matt Poppe + * + * 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_AT86RF23X_H +#define __DRIVERS_WIRELESS_IEEE802154_AT86RF23X_H + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#define RF23X_SPI_REG_READ 0x80 +#define RF23X_SPI_REG_WRITE 0xc0 +#define RF23X_SPI_FRAME_WRITE 0x60 +#define RF23X_SPI_FRAME_READ 0x20 +#define RF23X_SPI_SRAM_READ 0x00 +#define RF23X_SPI_SRAM_WRITE 0x40 + +/* US Times Constants for the RF233 */ + +#define RF23X_TIME_RESET_BOOT 510 +#define RF23X_TIME_FORCE_TRXOFF 100 +#define RF23X_TIME_P_ON_TO_TRXOFF 510 +#define RF23X_TIME_SLEEP_TO_TRXOFF 1200 +#define RF23X_TIME_RESET 6 +#define RF23X_TIME_ED_MEASUREMENT 140 +#define RF23X_TIME_CCA 140 +#define RF23X_TIME_PLL_LOCK 150 +#define RF23X_TIME_FTN_TUNNING 25 +#define RF23X_TIME_NOCLK_TO_WAKE 6 +#define RF23X_TIME_CMD_FORCE_TRX_OFF 1 +#define RF23X_TIME_TRXOFF_TO_PLL 180 +#define RF23X_TIME_TRANSITION_PLL_ACTIVE 1 +#define RF23X_TIME_TRXOFF_TO_SLEEP 1200 + +#define RF23X_MAX_RETRY_RESET_TO_TRX_OFF 5 + +#define RF23X_REG_TRXSTATUS 0x01 +#define RF23X_REG_TRXSTATE 0x02 +#define RF23X_REG_TRXCTRL0 0x03 +#define RF23X_REG_TRXCTRL1 0x04 +#define RF23X_REG_TXPWR 0x05 +#define RF23X_REG_RSSI 0x06 +#define RF23X_REG_EDLEVEL 0x07 +#define RF23X_REG_CCA 0x08 +#define RF23X_REG_THRES 0x09 +#define RF23X_REG_RXCTRL 0x0a +#define RF23X_REG_SFD 0x0b +#define RF23X_REG_TRXCTRL2 0x0c +#define RF23X_REG_ANT_DIV 0x0d +#define RF23X_REG_IRQ_MASK 0x0e +#define RF23X_REG_IRQ_STATUS 0x0f +#define RF23X_REG_VREG_CTRL 0x10 +#define RF23X_REG_BATMON 0x11 +#define RF23X_REG_XOSC_CTRL 0x12 +#define RF23X_REG_CCCTRL0 0x13 +#define RF23X_REG_CCCTRL1 0x14 +#define RF23X_REG_RXSYN 0x15 +#define RF23X_REG_TRXRPC 0x16 +#define RF23X_REG_XAHCTRL1 0x17 +#define RF23X_REG_FTNCTRL 0x18 +#define RF23X_REG_XAHCTRL2 0x19 +#define RF23X_REG_PLLCF 0x1a +#define RF23X_REG_PLLDCU 0x1b +#define RF23X_REG_PART 0x1c +#define RF23X_REG_VERSION 0x1d +#define RF23X_REG_MANID0 0x1e +#define RF23X_REG_MANID1 0x1f +#define RF23X_REG_SADDR0 0x20 +#define RF23X_REG_SADDR1 0x21 +#define RF23X_REG_PANID0 0x22 +#define RF23X_REG_PANID1 0x23 +#define RF23X_REG_IEEEADDR0 0x24 +#define RF23X_REG_IEEEADDR1 0x25 +#define RF23X_REG_IEEEADDR2 0x26 +#define RF23X_REG_IEEEADDR3 0x27 +#define RF23X_REG_IEEEADDR4 0x28 +#define RF23X_REG_IEEEADDR5 0x29 +#define RF23X_REG_IEEEADDR6 0x2a +#define RF23X_REG_IEEEADDR7 0x2b +#define RF23X_REG_XAHCTRL0 0x2c +#define RF23X_REG_CSMASEED0 0x2d +#define RF23X_REG_CSMASEED1 0x2e +#define RF23X_REG_CSMABE 0x2f +#define RF23X_REG_TSTCTRLDIGI 0x36 +#define RF23X_REG_TSTAGC 0x3c +#define RF23X_REG_SDM 0x3d +#define RF23X_REG_PHYTXTIME 0x3b +#define RF23X_REG_PHYPMUVALUE 0x3b + +#define RF23X_TRXSTATUS_POS 0 +#define RF23X_TRXSTATUS_MASK 0x1f +#define RF23X_TRXSTATUS_STATUS RF23X_REG_TRXSTATUS, RF23X_TRXSTATUS_POS, RF23X_TRXSTATUS_MASK + +#define RF23X_TRXCMD_POS 0 +#define RF23X_TRXCMD_MASK 0x1f +#define RF23X_TRXCMD_STATE RF23X_REG_TRXSTATE, RF23X_TRXCMD_POS, RF23X_TRXCMD_MASK + +#define RF23X_TXPWR_POS_4 0x00 +#define RF23X_TXPWR_POS_3_7 0x01 +#define RF23X_TXPWR_POS_3_4 0x02 +#define RF23X_TXPWR_POS_3 0x03 +#define RF23X_TXPWR_POS_2_5 0x04 +#define RF23X_TXPWR_POS_2 0x05 +#define RF23X_TXPWR_POS_1 0x06 +#define RF23X_TXPWR_0 0x07 +#define RF23X_TXPWR_NEG_1 0x08 +#define RF23X_TXPWR_NEG_2 0x09 +#define RF23X_TXPWR_NEG_3 0x0a +#define RF23X_TXPWR_NEG_4 0x0b +#define RF23X_TXPWR_NEG_6 0x0c +#define RF23X_TXPWR_NEG_8 0x0d +#define RF23X_TXPWR_NEG_12 0x0e +#define RF23X_TXPWR_NEG_17 0x0f + +/* CCA_STATUS */ + +#define RF23X_CCA_MODE_CS_OR_ED 0x00 +#define RF23X_CCA_MODE_ED 0x01 +#define RF23X_CCA_MODE_CS 0x02 +#define RF23X_CCA_MODE_CS_AND_ED 0x03 + +#define RF23X_CCA_CHANNEL_POS 0 +#define RF23X_CCA_CHANNEL_MASK 0x1f +#define RF23X_CCA_BITS_CHANNEL RF23X_REG_CCA, RF23X_CCA_CHANNEL_POS, RF23X_CCA_CHANNEL_MASK +#define RF23X_CCA_MODE_POS 5 +#define RF23X_CCA_MODE_MASK 0x03 +#define RF23X_CCA_BITS_MODE RF23X_REG_CCA, RF23X_CCA_MODE_POS, RF23X_CCA_MODE_MASK + +/* XAH CTRL 1 */ + +#define RF23X_XAHCTRL1_PROM_MODE_POS 1 +#define RF23X_XAHCTRL1_PROM_MODE_MASK 0x01 +#define RF23X_XAHCTRL1_BITS_PROM_MODE RF23X_REG_XAHCTRL1, RF23X_XAHCTRL1_PROM_MODE_POS, RF23X_XAHCTRL1_PROM_MODE_MASK + +/* CSMA SEED 0 */ + +/* CSMA SEED 1 */ + +#define RF23X_CSMASEED1_IAMCOORD_POS 3 +#define RF23X_CSMASEED1_IAMCOORD_MASK 0x1 +#define RF23X_CSMASEED1_IAMCOORD_BITS RF23X_REG_CSMASEED1, RF23X_CSMASEED1_IAMCOORD_POS, RF23X_CSMASEED1_IAMCOORD_MASK + +#define RF23X_CSMASEED1_AACK_DIS_ACK_POS +#define RF23X_CSMASEED1_AACK_SET_PD_POS +#define RF23X_CSMASEED1_AACK_FVN_MODE_POS + +/* TRX Status */ + +#define TRX_STATUS_PON 0x00 +#define TRX_STATUS_BUSYRX 0x01 +#define TRX_STATUS_BUSYTX 0x02 +#define TRX_STATUS_RXON 0x06 +#define TRX_STATUS_TRXOFF 0x08 +#define TRX_STATUS_PLLON 0x09 +#define TRX_STATUS_SLEEP 0x0f +#define TRX_STATUS_DEEPSLEEP 0x10 +#define TRX_STATUS_BUSYRXACK 0x11 +#define TRX_STATUS_BUSYTXARET 0x12 +#define TRX_STATUS_RXAACKON 0x16 +#define TRX_STATUS_TXARETON 0x19 +#define TRX_STATUS_STATEINTRANS 0x1f + +/* TRX Command */ + +#define TRX_CMD_NOP 0x00 +#define TRX_CMD_TX 0x02 +#define TRX_CMD_FORCETRXOFF 0x03 +#define TRX_CMD_FORCE_PLLON 0x04 +#define TRX_CMD_RX_ON 0x06 +#define TRX_CMD_TRXOFF 0x08 +#define TRX_CMD_PLL_ON 0x09 +#define TRX_CMD_PREP_DEEPSLEEP 0x10 +#define TRX_CMD_RX_AACK_ON 0x16 +#define TRX_CMD_TX_ARET_ON 0x19 + +/* IRQ MASK 0x0e */ + +#define RF23X_IRQ_MASK_LOCK_PLL (1 << 0) +#define RF23X_IRQ_MASK_UNLOCK_PLL (1 << 1) +#define RF23X_IRQ_MASK_RX_START (1 << 2) +#define RF23X_IRQ_MASK_TRX_END (1 << 3) +#define RF23X_IRQ_MASK_CCA_ED_DONE (1 << 4) +#define RF23X_IRQ_MASK_AMI (1 << 5) +#define RF23X_IRQ_MASK_TRX_UR (1 << 6) +#define RF23X_IRQ_MASK_BAT_LOW (1 << 7) + +#define RF23X_IRQ_MASK_DEFAULT (RF23X_IRQ_MASK_TRX_END) + +#endif /* __DRIVERS_WIRELESS_IEEE802154_AT86RF23X_H */ diff --git a/drivers/wireless/ieee802154/mrf24j40.c b/drivers/wireless/ieee802154/mrf24j40.c index 41558b9dfa..8283278d3c 100644 --- a/drivers/wireless/ieee802154/mrf24j40.c +++ b/drivers/wireless/ieee802154/mrf24j40.c @@ -2,7 +2,9 @@ * drivers/wireless/ieee802154/mrf24j40.c * * Copyright (C) 2015-2016 Sebastien Lorquet. All rights reserved. + * Copyright (C) 2017 Verge Inc. All rights reserved. * Author: Sebastien Lorquet + * Author: Anthony Merlino * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -55,8 +57,11 @@ #include #include +#include + #include #include +#include #include "mrf24j40.h" @@ -65,7 +70,7 @@ ****************************************************************************/ #ifndef CONFIG_SCHED_HPWORK -#error High priority work queue required in this driver +# error High priority work queue required in this driver #endif #ifndef CONFIG_IEEE802154_MRF24J40_SPIMODE @@ -86,34 +91,65 @@ #define MRF24J40_RXMODE_PROMISC 1 #define MRF24J40_RXMODE_NOCRC 2 +#define MRF24J40_MODE_DEVICE 0 +#define MRF24J40_MODE_COORD 1 +#define MRF24J40_MODE_PANCOORD 2 + /* Definitions for PA control on high power modules */ -#define MRF24J40_PA_AUTO 1 -#define MRF24J40_PA_ED 2 -#define MRF24J40_PA_SLEEP 3 +#define MRF24J40_PA_AUTO 1 +#define MRF24J40_PA_ED 2 +#define MRF24J40_PA_SLEEP 3 + +#define MRF24J40_GTS_SLOTS 2 /**************************************************************************** * Private Types ****************************************************************************/ +struct mrf24j40_txdesc_s +{ + struct ieee802154_txdesc_s pub; + + uint8_t busy : 1; /* Is this txdesc being used */ +}; + /* A MRF24J40 device instance */ -struct mrf24j40_dev_s +struct mrf24j40_radio_s { - struct ieee802154_dev_s ieee; /* The public device instance */ - FAR struct spi_dev_s *spi; /* Saved SPI interface instance */ - struct work_s irqwork; /* Interrupt continuation work queue support */ - FAR const struct mrf24j40_lower_s *lower; /* Low-level MCU-specific support */ + struct ieee802154_radio_s radio; /* The public device instance */ + FAR struct ieee802154_radiocb_s *radiocb; /* Registered callbacks */ - uint16_t panid; /* PAN identifier, FFFF = not set */ - uint16_t saddr; /* short address, FFFF = not set */ - uint8_t eaddr[8]; /* extended address, FFFFFFFFFFFFFFFF = not set */ - uint8_t channel; /* 11 to 26 for the 2.4 GHz band */ - uint8_t devmode; /* device mode: device, coord, pancoord */ - uint8_t paenabled; /* enable usage of PA */ - uint8_t rxmode; /* Reception mode: Main, no CRC, promiscuous */ - int32_t txpower; /* TX power in mBm = dBm/100 */ - struct ieee802154_cca_s cca; /* Clear channel assessement method */ + /* MAC Attributes */ + + bool rxonidle : 1; + + /* Low-level MCU-specific support */ + + FAR const struct mrf24j40_lower_s *lower; + FAR struct spi_dev_s *spi; /* Saved SPI interface instance */ + + struct work_s irqwork; /* For deferring interrupt work to work queue */ + struct work_s pollwork; /* For deferring poll work to the work queue */ + sem_t exclsem; /* Exclusive access to this struct */ + + struct ieee802154_addr_s addr; + + uint8_t channel; /* 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 */ + + /* Buffer Allocations */ + + struct mrf24j40_txdesc_s csma_desc; + FAR struct iob_s *csma_frame; + + struct mrf24j40_txdesc_s gts_desc[MRF24J40_GTS_SLOTS]; + FAR struct iob_s *gts_frame[MRF24J40_GTS_SLOTS]; }; /**************************************************************************** @@ -122,44 +158,90 @@ struct mrf24j40_dev_s /* Internal operations */ -static void mrf24j40_lock (FAR struct spi_dev_s *spi); +static void mrf24j40_spi_lock(FAR struct spi_dev_s *spi); -static void mrf24j40_setreg (FAR struct spi_dev_s *spi, uint32_t addr, uint8_t val); -static uint8_t mrf24j40_getreg (FAR struct spi_dev_s *spi, uint32_t addr); +static void mrf24j40_setreg(FAR struct spi_dev_s *spi, uint32_t addr, + uint8_t val); +static uint8_t mrf24j40_getreg(FAR struct spi_dev_s *spi, uint32_t addr); -static int mrf24j40_resetrfsm (FAR struct mrf24j40_dev_s *dev); -static int mrf24j40_pacontrol (FAR struct mrf24j40_dev_s *dev, int mode); -static int mrf24j40_initialize(FAR struct mrf24j40_dev_s *dev); +static int mrf24j40_resetrfsm(FAR struct mrf24j40_radio_s *dev); +static int mrf24j40_pacontrol(FAR struct mrf24j40_radio_s *dev, int mode); +static int mrf24j40_initialize(FAR struct mrf24j40_radio_s *dev); -static int mrf24j40_setrxmode (FAR struct mrf24j40_dev_s *dev, int mode); -static int mrf24j40_regdump (FAR struct mrf24j40_dev_s *dev); -static void mrf24j40_irqwork_rx(FAR struct mrf24j40_dev_s *dev); -static void mrf24j40_irqwork_tx(FAR struct mrf24j40_dev_s *dev); -static void mrf24j40_irqworker (FAR void *arg); -static int mrf24j40_interrupt (int irq, FAR void *context); +static int mrf24j40_setrxmode(FAR struct mrf24j40_radio_s *dev, int mode); +static int mrf24j40_regdump(FAR struct mrf24j40_radio_s *dev); + +static void mrf24j40_irqwork_rx(FAR struct mrf24j40_radio_s *dev); +static void mrf24j40_irqwork_txnorm(FAR struct mrf24j40_radio_s *dev); +static void mrf24j40_irqwork_txgts(FAR struct mrf24j40_radio_s *dev, + uint8_t gts_num); + +static void mrf24j40_irqworker(FAR void *arg); +static int mrf24j40_interrupt(int irq, FAR void *context, FAR void *arg); + +static void mrf24j40_dopoll_csma(FAR void *arg); +static void mrf24j40_dopoll_gts(FAR void *arg); + +static int mrf24j40_csma_setup(FAR struct mrf24j40_radio_s *dev, + FAR struct iob_s *frame); +static int mrf24j40_gts_setup(FAR struct mrf24j40_radio_s *dev, uint8_t gts, + FAR struct iob_s *frame); +static int mrf24j40_setup_fifo(FAR struct mrf24j40_radio_s *dev, + FAR struct iob_s *frame, uint32_t fifo_addr); + + +static int mrf24j40_setchannel(FAR struct mrf24j40_radio_s *dev, + uint8_t chan); +static int mrf24j40_getchannel(FAR struct mrf24j40_radio_s *dev, + FAR uint8_t *chan); +static int mrf24j40_setpanid(FAR struct mrf24j40_radio_s *dev, + uint16_t panid); +static int mrf24j40_getpanid(FAR struct mrf24j40_radio_s *dev, + FAR uint16_t *panid); +static int mrf24j40_setsaddr(FAR struct mrf24j40_radio_s *dev, + uint16_t saddr); +static int mrf24j40_getsaddr(FAR struct mrf24j40_radio_s *dev, + FAR uint16_t *saddr); +static int mrf24j40_seteaddr(FAR struct mrf24j40_radio_s *dev, + FAR const uint8_t *eaddr); +static int mrf24j40_geteaddr(FAR struct mrf24j40_radio_s *dev, + FAR uint8_t *eaddr); +static int mrf24j40_setpromisc(FAR struct mrf24j40_radio_s *dev, + bool promisc); +static int mrf24j40_getpromisc(FAR struct mrf24j40_radio_s *dev, + FAR bool *promisc); +static int mrf24j40_setdevmode(FAR struct mrf24j40_radio_s *dev, + uint8_t mode); +static int mrf24j40_getdevmode(FAR struct mrf24j40_radio_s *dev, + FAR uint8_t *mode); +static int mrf24j40_settxpower(FAR struct mrf24j40_radio_s *dev, + int32_t txpwr); +static int mrf24j40_gettxpower(FAR struct mrf24j40_radio_s *dev, + FAR int32_t *txpwr); +static int mrf24j40_setcca(FAR struct mrf24j40_radio_s *dev, + FAR struct ieee802154_cca_s *cca); +static int mrf24j40_getcca(FAR struct mrf24j40_radio_s *dev, + FAR struct ieee802154_cca_s *cca); +static int mrf24j40_energydetect(FAR struct mrf24j40_radio_s *dev, + FAR uint8_t *energy); +static int mrf24j40_rxenable(FAR struct mrf24j40_radio_s *dev, bool enable); /* Driver operations */ -static int mrf24j40_setchannel (FAR struct ieee802154_dev_s *ieee, uint8_t chan); -static int mrf24j40_getchannel (FAR struct ieee802154_dev_s *ieee, FAR uint8_t *chan); -static int mrf24j40_setpanid (FAR struct ieee802154_dev_s *ieee, uint16_t panid); -static int mrf24j40_getpanid (FAR struct ieee802154_dev_s *ieee, FAR uint16_t *panid); -static int mrf24j40_setsaddr (FAR struct ieee802154_dev_s *ieee, uint16_t saddr); -static int mrf24j40_getsaddr (FAR struct ieee802154_dev_s *ieee, FAR uint16_t *saddr); -static int mrf24j40_seteaddr (FAR struct ieee802154_dev_s *ieee, FAR uint8_t *eaddr); -static int mrf24j40_geteaddr (FAR struct ieee802154_dev_s *ieee, FAR uint8_t *eaddr); -static int mrf24j40_setpromisc (FAR struct ieee802154_dev_s *ieee, bool promisc); -static int mrf24j40_getpromisc (FAR struct ieee802154_dev_s *ieee, FAR bool *promisc); -static int mrf24j40_setdevmode (FAR struct ieee802154_dev_s *ieee, uint8_t mode); -static int mrf24j40_getdevmode (FAR struct ieee802154_dev_s *ieee, FAR uint8_t *mode); -static int mrf24j40_settxpower (FAR struct ieee802154_dev_s *ieee, int32_t txpwr); -static int mrf24j40_gettxpower (FAR struct ieee802154_dev_s *ieee, FAR int32_t *txpwr); -static int mrf24j40_setcca (FAR struct ieee802154_dev_s *ieee, FAR struct ieee802154_cca_s *cca); -static int mrf24j40_getcca (FAR struct ieee802154_dev_s *ieee, FAR struct ieee802154_cca_s *cca); -static int mrf24j40_ioctl (FAR struct ieee802154_dev_s *ieee, int cmd, unsigned long arg); -static int mrf24j40_energydetect(FAR struct ieee802154_dev_s *ieee, FAR uint8_t *energy); -static int mrf24j40_rxenable (FAR struct ieee802154_dev_s *ieee, bool state, FAR struct ieee802154_packet_s *packet); -static int mrf24j40_transmit (FAR struct ieee802154_dev_s *ieee, FAR struct ieee802154_packet_s *packet); +static int mrf24j40_bind(FAR struct ieee802154_radio_s *radio, + FAR struct ieee802154_radiocb_s *radiocb); +static int mrf24j40_txnotify_csma(FAR struct ieee802154_radio_s *radio); +static int mrf24j40_txnotify_gts(FAR struct ieee802154_radio_s *radio); +static int mrf24j40_get_attr(FAR struct ieee802154_radio_s *radio, + enum ieee802154_pib_attr_e pib_attr, + FAR union ieee802154_attr_val_u *attr_value); +static int mrf24j40_set_attr(FAR struct ieee802154_radio_s *radio, + enum ieee802154_pib_attr_e pib_attr, + FAR const union ieee802154_attr_val_u *attr_value); + +/**************************************************************************** + * Private Data + ****************************************************************************/ /* These are pointers to ALL registered MRF24J40 devices. * This table is used during irqs to find the context @@ -168,55 +250,302 @@ static int mrf24j40_transmit (FAR struct ieee802154_dev_s *ieee, FAR stru * using the IRQ number. See the ENC28J60 or CC3000 drivers for reference. */ -static struct mrf24j40_dev_s g_mrf24j40_devices[1]; - -static const struct ieee802154_devops_s mrf24j40_devops = +static const struct ieee802154_radioops_s mrf24j40_devops = { - mrf24j40_setchannel, mrf24j40_getchannel, - mrf24j40_setpanid , mrf24j40_getpanid, - mrf24j40_setsaddr , mrf24j40_getsaddr, - mrf24j40_seteaddr , mrf24j40_geteaddr, - mrf24j40_setpromisc, mrf24j40_getpromisc, - mrf24j40_setdevmode, mrf24j40_getdevmode, - mrf24j40_settxpower, mrf24j40_gettxpower, - mrf24j40_setcca , mrf24j40_getcca, - mrf24j40_ioctl, - mrf24j40_energydetect, - mrf24j40_rxenable, - mrf24j40_transmit + mrf24j40_bind, + mrf24j40_txnotify_csma, + mrf24j40_txnotify_gts, + mrf24j40_get_attr, + mrf24j40_set_attr }; /**************************************************************************** - * Private Functions + * Radio Interface Functions ****************************************************************************/ -/* Hardware access routines */ +static int mrf24j40_bind(FAR struct ieee802154_radio_s *radio, + FAR struct ieee802154_radiocb_s *radiocb) +{ + FAR struct mrf24j40_radio_s *dev = (FAR struct mrf24j40_radio_s *)radio; + + DEBUGASSERT(dev != NULL); + dev->radiocb = radiocb; + return OK; +} /**************************************************************************** - * Name: mrf24j40_lock + * Function: mrf24j40_txnotify_csma + * + * Description: + * Driver callback invoked when new TX data is available. This is a + * stimulus perform an out-of-cycle poll and, thereby, reduce the TX + * latency. + * + * Parameters: + * radio - Reference to the radio driver state structure + * + * Returned Value: + * None + * + * Assumptions: + * + ****************************************************************************/ + +static int mrf24j40_txnotify_csma(FAR struct ieee802154_radio_s *radio) +{ + FAR struct mrf24j40_radio_s *dev = (FAR struct mrf24j40_radio_s *)radio; + + /* 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->pollwork)) + { + /* Schedule to serialize the poll on the worker thread. */ + + work_queue(HPWORK, &dev->pollwork, mrf24j40_dopoll_csma, dev, 0); + } + + return OK; +} + +/**************************************************************************** + * Function: mrf24j40_txnotify_gts + * + * Description: + * Driver callback invoked when new TX data is available. This is a + * stimulus perform an out-of-cycle poll and, thereby, reduce the TX + * latency. + * + * Parameters: + * radio - Reference to the radio driver state structure + * + * Returned Value: + * None + * + * Assumptions: + * + ****************************************************************************/ + +static int mrf24j40_txnotify_gts(FAR struct ieee802154_radio_s *radio) +{ + FAR struct mrf24j40_radio_s *dev = (FAR struct mrf24j40_radio_s *)radio; + + /* 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->pollwork)) + { + /* Schedule to serialize the poll on the worker thread. */ + + work_queue(HPWORK, &dev->pollwork, mrf24j40_dopoll_gts, dev, 0); + } + + return OK; +} + +static int mrf24j40_get_attr(FAR struct ieee802154_radio_s *radio, + enum ieee802154_pib_attr_e pib_attr, + FAR union ieee802154_attr_val_u *attr_value) +{ + FAR struct mrf24j40_radio_s *dev = (FAR struct mrf24j40_radio_s *)radio; + int ret; + + switch (pib_attr) + { + case IEEE802154_PIB_MAC_EXTENDED_ADDR: + { + memcpy(&attr_value->mac.eaddr[0], &dev->addr.eaddr[0], 8); + ret = IEEE802154_STATUS_SUCCESS; + } + break; + default: + ret = IEEE802154_STATUS_UNSUPPORTED_ATTRIBUTE; + } + return ret; +} + +static int mrf24j40_set_attr(FAR struct ieee802154_radio_s *radio, + enum ieee802154_pib_attr_e pib_attr, + FAR const union ieee802154_attr_val_u *attr_value) +{ + FAR struct mrf24j40_radio_s *dev = (FAR struct mrf24j40_radio_s *)radio; + int ret; + + switch (pib_attr) + { + case IEEE802154_PIB_MAC_EXTENDED_ADDR: + { + mrf24j40_seteaddr(dev, &attr_value->mac.eaddr[0]); + ret = IEEE802154_STATUS_SUCCESS; + } + break; + case IEEE802154_PIB_MAC_PROMISCUOUS_MODE: + { + if (attr_value->mac.promisc_mode) + { + mrf24j40_setrxmode(dev, MRF24J40_RXMODE_PROMISC); + } + else + { + mrf24j40_setrxmode(dev, MRF24J40_RXMODE_NORMAL); + } + + ret = IEEE802154_STATUS_SUCCESS; + } + break; + case IEEE802154_PIB_MAC_RX_ON_WHEN_IDLE: + { + dev->rxonidle = attr_value->mac.rxonidle; + mrf24j40_rxenable(dev, dev->rxonidle); + } + break; + default: + ret = IEEE802154_STATUS_UNSUPPORTED_ATTRIBUTE; + } + return ret; +} + +/**************************************************************************** + * Internal 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_csma), and + * 3. After a TX timeout to restart the sending process + * (mrf24j40_txtimeout_csma). + * + * Parameters: + * radio - Reference to the radio driver state structure + * + * Returned Value: + * None + * + * Assumptions: + * + ****************************************************************************/ + +static void mrf24j40_dopoll_csma(FAR void *arg) +{ + FAR struct mrf24j40_radio_s *dev = (FAR struct mrf24j40_radio_s *)arg; + int len = 0; + + /* Get exclusive access to the driver */ + + while (sem_wait(&dev->exclsem) != 0) { } + + /* If this a CSMA transaction and we have room in the CSMA fifo */ + + if (!dev->csma_desc.busy) + { + /* need to somehow allow for a handle to be passed */ + + len = dev->radiocb->poll_csma(dev->radiocb, &dev->csma_desc.pub, + &dev->csma_frame); + if (len > 0) + { + /* Now the txdesc is in use */ + + dev->csma_desc.busy = 1; + + /* Setup the transaction on the device in the CSMA FIFO */ + + mrf24j40_csma_setup(dev, dev->csma_frame); + } + } + + 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_gts), and + * 3. After a TX timeout to restart the sending process + * (mrf24j40_txtimeout_gts). + * + * Parameters: + * arg - Reference to the radio driver state structure + * + * Returned Value: + * None + * + * Assumptions: + * + ****************************************************************************/ + +static void mrf24j40_dopoll_gts(FAR void *arg) +{ + FAR struct mrf24j40_radio_s *dev = (FAR struct mrf24j40_radio_s *)arg; + int gts = 0; + int len = 0; + + /* Get exclusive access to the driver */ + + while (sem_wait(&dev->exclsem) != 0) { } + + for (gts = 0; gts < MRF24J40_GTS_SLOTS; gts++) + { + if (!dev->gts_desc[gts].busy) + { + len = dev->radiocb->poll_gts(dev->radiocb, &dev->gts_desc[gts].pub, + &dev->gts_frame[0]); + if (len > 0) + { + /* Now the txdesc is in use */ + + dev->gts_desc[gts].busy = 1; + + /* Setup the transaction on the device in the open GTS FIFO */ + + mrf24j40_gts_setup(dev, gts, dev->gts_frame[0]); + } + } + } + + sem_post(&dev->exclsem); +} + +/**************************************************************************** + * Name: mrf24j40_spi_lock * * Description: * Acquire exclusive access to the shared SPI bus. * ****************************************************************************/ -static void mrf24j40_lock(FAR struct spi_dev_s *spi) +static void mrf24j40_spi_lock(FAR struct spi_dev_s *spi) { - SPI_LOCK (spi, 1); - SPI_SETBITS (spi, 8); - SPI_SETMODE (spi, CONFIG_IEEE802154_MRF24J40_SPIMODE); + SPI_LOCK(spi, 1); + SPI_SETBITS(spi, 8); + SPI_SETMODE(spi, CONFIG_IEEE802154_MRF24J40_SPIMODE); SPI_SETFREQUENCY(spi, CONFIG_IEEE802154_MRF24J40_FREQUENCY); } /**************************************************************************** - * Name: mrf24j40_unlock + * Name: mrf24j40_spi_unlock * * Description: * Release exclusive access to the shared SPI bus. * ****************************************************************************/ -static inline void mrf24j40_unlock(FAR struct spi_dev_s *spi) +static inline void mrf24j40_spi_unlock(FAR struct spi_dev_s *spi) { SPI_LOCK(spi,0); } @@ -229,7 +558,8 @@ static inline void mrf24j40_unlock(FAR struct spi_dev_s *spi) * ****************************************************************************/ -static void mrf24j40_setreg(FAR struct spi_dev_s *spi, uint32_t addr, uint8_t val) +static void mrf24j40_setreg(FAR struct spi_dev_s *spi, uint32_t addr, + uint8_t val) { uint8_t buf[3]; int len; @@ -254,11 +584,11 @@ static void mrf24j40_setreg(FAR struct spi_dev_s *spi, uint32_t addr, uint8_t va buf[len++] = val; - mrf24j40_lock(spi); + mrf24j40_spi_lock(spi); SPI_SELECT(spi, SPIDEV_IEEE802154(0), true); SPI_SNDBLOCK(spi, buf, len); SPI_SELECT(spi, SPIDEV_IEEE802154(0), false); - mrf24j40_unlock(spi); + mrf24j40_spi_unlock(spi); } /**************************************************************************** @@ -298,14 +628,14 @@ static uint8_t mrf24j40_getreg(FAR struct spi_dev_s *spi, uint32_t addr) buf[len++] = 0xFF; /* dummy */ - mrf24j40_lock (spi); + 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_unlock(spi); + mrf24j40_spi_unlock(spi); - /*winfo("r[%04X]=%02X\n", addr, rx[len-1]);*/ - return rx[len-1]; + /* wlinfo("r[%04X]=%02X\n", addr, rx[len - 1]); */ + return rx[len - 1]; } /**************************************************************************** @@ -317,7 +647,7 @@ static uint8_t mrf24j40_getreg(FAR struct spi_dev_s *spi, uint32_t addr) * ****************************************************************************/ -static int mrf24j40_resetrfsm(FAR struct mrf24j40_dev_s *dev) +static int mrf24j40_resetrfsm(FAR struct mrf24j40_radio_s *dev) { uint8_t reg; @@ -342,7 +672,7 @@ static int mrf24j40_resetrfsm(FAR struct mrf24j40_dev_s *dev) * GPIO 3: PA power enable (not required on MB) ****************************************************************************/ -static int mrf24j40_pacontrol(FAR struct mrf24j40_dev_s *dev, int mode) +static int mrf24j40_pacontrol(FAR struct mrf24j40_radio_s *dev, int mode) { if (!dev->paenabled) { @@ -384,7 +714,7 @@ static int mrf24j40_pacontrol(FAR struct mrf24j40_dev_s *dev, int mode) * ****************************************************************************/ -static int mrf24j40_initialize(FAR struct mrf24j40_dev_s *dev) +static int mrf24j40_initialize(FAR struct mrf24j40_radio_s *dev) { /* Software reset */ @@ -416,15 +746,16 @@ static int mrf24j40_initialize(FAR struct mrf24j40_dev_s *dev) * ****************************************************************************/ -static int mrf24j40_setrxmode(FAR struct mrf24j40_dev_s *dev, int mode) +static int mrf24j40_setrxmode(FAR struct mrf24j40_radio_s *dev, int mode) { uint8_t reg; + if (mode < MRF24J40_RXMODE_NORMAL || mode > MRF24J40_RXMODE_NOCRC) { return -EINVAL; } - reg = mrf24j40_getreg(dev->spi, MRF24J40_RXMCR); + reg = mrf24j40_getreg(dev->spi, MRF24J40_RXMCR); reg &= ~0x03; reg |= mode; @@ -433,23 +764,23 @@ static int mrf24j40_setrxmode(FAR struct mrf24j40_dev_s *dev, int mode) 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; - winfo("%u\n", (unsigned)mode); + wlinfo("%u\n", (unsigned)mode); return OK; } -/* Publicized driver routines */ - /**************************************************************************** * Name: mrf24j40_setchannel * @@ -464,14 +795,11 @@ static int mrf24j40_setrxmode(FAR struct mrf24j40_dev_s *dev, int mode) * ****************************************************************************/ -static int mrf24j40_setchannel(FAR struct ieee802154_dev_s *ieee, - uint8_t chan) +static int mrf24j40_setchannel(FAR struct mrf24j40_radio_s *dev, uint8_t chan) { - FAR struct mrf24j40_dev_s *dev = (FAR struct mrf24j40_dev_s *)ieee; - - if (chan<11 || chan>26) + if (chan < 11 || chan > 26) { - werr("ERROR: Invalid chan: %d\n",chan); + wlerr("ERROR: Invalid chan: %d\n",chan); return -EINVAL; } @@ -486,7 +814,7 @@ static int mrf24j40_setchannel(FAR struct ieee802154_dev_s *ieee, mrf24j40_resetrfsm(dev); dev->channel = chan; - //winfo("%u\n", (unsigned)chan); + //wlinfo("%u\n", (unsigned)chan); return OK; } @@ -495,15 +823,13 @@ static int mrf24j40_setchannel(FAR struct ieee802154_dev_s *ieee, * Name: mrf24j40_getchannel * * Description: - * Define the current radio channel the device is operating on. + * Get the channel the device is operating on. * ****************************************************************************/ -static int mrf24j40_getchannel(FAR struct ieee802154_dev_s *ieee, +static int mrf24j40_getchannel(FAR struct mrf24j40_radio_s *dev, FAR uint8_t *chan) { - FAR struct mrf24j40_dev_s *dev = (FAR struct mrf24j40_dev_s *)ieee; - *chan = dev->channel; return OK; @@ -517,16 +843,14 @@ static int mrf24j40_getchannel(FAR struct ieee802154_dev_s *ieee, * ****************************************************************************/ -static int mrf24j40_setpanid(FAR struct ieee802154_dev_s *ieee, +static int mrf24j40_setpanid(FAR struct mrf24j40_radio_s *dev, uint16_t panid) { - FAR struct mrf24j40_dev_s *dev = (FAR struct mrf24j40_dev_s *)ieee; - mrf24j40_setreg(dev->spi, MRF24J40_PANIDH, (uint8_t)(panid>>8)); mrf24j40_setreg(dev->spi, MRF24J40_PANIDL, (uint8_t)(panid&0xFF)); - dev->panid = panid; - winfo("%04X\n", (unsigned)panid); + dev->addr.panid = panid; + wlinfo("%04X\n", (unsigned)panid); return OK; } @@ -539,12 +863,10 @@ static int mrf24j40_setpanid(FAR struct ieee802154_dev_s *ieee, * ****************************************************************************/ -static int mrf24j40_getpanid(FAR struct ieee802154_dev_s *ieee, +static int mrf24j40_getpanid(FAR struct mrf24j40_radio_s *dev, FAR uint16_t *panid) { - FAR struct mrf24j40_dev_s *dev = (FAR struct mrf24j40_dev_s *)ieee; - - *panid = dev->panid; + *panid = dev->addr.panid; return OK; } @@ -559,16 +881,14 @@ static int mrf24j40_getpanid(FAR struct ieee802154_dev_s *ieee, * ****************************************************************************/ -static int mrf24j40_setsaddr(FAR struct ieee802154_dev_s *ieee, +static int mrf24j40_setsaddr(FAR struct mrf24j40_radio_s *dev, uint16_t saddr) { - FAR struct mrf24j40_dev_s *dev = (FAR struct mrf24j40_dev_s *)ieee; - mrf24j40_setreg(dev->spi, MRF24J40_SADRH, (uint8_t)(saddr>>8)); mrf24j40_setreg(dev->spi, MRF24J40_SADRL, (uint8_t)(saddr&0xFF)); - dev->saddr = saddr; - winfo("%04X\n", (unsigned)saddr); + dev->addr.saddr = saddr; + wlinfo("%04X\n", (unsigned)saddr); return OK; } @@ -580,12 +900,10 @@ static int mrf24j40_setsaddr(FAR struct ieee802154_dev_s *ieee, * ****************************************************************************/ -static int mrf24j40_getsaddr(FAR struct ieee802154_dev_s *ieee, +static int mrf24j40_getsaddr(FAR struct mrf24j40_radio_s *dev, FAR uint16_t *saddr) { - FAR struct mrf24j40_dev_s *dev = (FAR struct mrf24j40_dev_s *)ieee; - - *saddr = dev->saddr; + *saddr = dev->addr.saddr; return OK; } @@ -599,17 +917,15 @@ static int mrf24j40_getsaddr(FAR struct ieee802154_dev_s *ieee, * ****************************************************************************/ -static int mrf24j40_seteaddr(FAR struct ieee802154_dev_s *ieee, - FAR uint8_t *eaddr) +static int mrf24j40_seteaddr(FAR struct mrf24j40_radio_s *dev, + FAR const uint8_t *eaddr) { - FAR struct mrf24j40_dev_s *dev = (FAR struct mrf24j40_dev_s *)ieee; - int i; - for (i=0; i<8; i++) + for (i = 0; i < 8; i++) { mrf24j40_setreg(dev->spi, MRF24J40_EADR0 + i, eaddr[i]); - dev->eaddr[i] = eaddr[i]; + dev->addr.eaddr[i] = eaddr[i]; } return OK; @@ -623,48 +939,10 @@ static int mrf24j40_seteaddr(FAR struct ieee802154_dev_s *ieee, * ****************************************************************************/ -static int mrf24j40_geteaddr(FAR struct ieee802154_dev_s *ieee, +static int mrf24j40_geteaddr(FAR struct mrf24j40_radio_s *dev, FAR uint8_t *eaddr) { - FAR struct mrf24j40_dev_s *dev = (FAR struct mrf24j40_dev_s *)ieee; - - memcpy(eaddr, dev->eaddr, 8); - - return OK; -} - -/**************************************************************************** - * Name: mrf24j40_setpromisc - * - * Description: - * Set the device into promiscuous mode, e.g do not filter any incoming - * frame. - * - ****************************************************************************/ - -static int mrf24j40_setpromisc(FAR struct ieee802154_dev_s *ieee, - bool promisc) -{ - FAR struct mrf24j40_dev_s *dev = (FAR struct mrf24j40_dev_s *)ieee; - - return mrf24j40_setrxmode(dev, promisc ? MRF24J40_RXMODE_PROMISC : - MRF24J40_RXMODE_NORMAL); -} - -/**************************************************************************** - * Name: mrf24j40_getpromisc - * - * Description: - * Get the device receive mode. - * - ****************************************************************************/ - -static int mrf24j40_getpromisc(FAR struct ieee802154_dev_s *ieee, - FAR bool *promisc) -{ - FAR struct mrf24j40_dev_s *dev = (FAR struct mrf24j40_dev_s *)ieee; - - *promisc = (dev->rxmode == MRF24J40_RXMODE_PROMISC); + memcpy(eaddr, dev->addr.eaddr, 8); return OK; } @@ -677,10 +955,9 @@ static int mrf24j40_getpromisc(FAR struct ieee802154_dev_s *ieee, * ****************************************************************************/ -static int mrf24j40_setdevmode(FAR struct ieee802154_dev_s *ieee, +static int mrf24j40_setdevmode(FAR struct mrf24j40_radio_s *dev, uint8_t mode) { - FAR struct mrf24j40_dev_s *dev = (FAR struct mrf24j40_dev_s *)ieee; int ret = OK; uint8_t reg; @@ -695,29 +972,28 @@ static int mrf24j40_setdevmode(FAR struct ieee802154_dev_s *ieee, reg = mrf24j40_getreg(dev->spi, MRF24J40_RXMCR); - if (mode == IEEE802154_MODE_PANCOORD) + if (mode == MRF24J40_MODE_PANCOORD) { reg |= MRF24J40_RXMCR_PANCOORD; reg &= ~MRF24J40_RXMCR_COORD; } - else if (mode == IEEE802154_MODE_COORD) + else if (mode == MRF24J40_MODE_COORD) { reg |= MRF24J40_RXMCR_COORD; reg &= ~MRF24J40_RXMCR_PANCOORD; } - else if (mode == IEEE802154_MODE_DEVICE) + else if (mode == MRF24J40_MODE_DEVICE) { reg &= ~MRF24J40_RXMCR_PANCOORD; reg &= ~MRF24J40_RXMCR_COORD; } else { - return -EINVAL; + return -EINVAL; } mrf24j40_setreg(dev->spi, MRF24J40_RXMCR, reg); dev->devmode = mode; - return ret; } @@ -729,13 +1005,10 @@ static int mrf24j40_setdevmode(FAR struct ieee802154_dev_s *ieee, * ****************************************************************************/ -static int mrf24j40_getdevmode(FAR struct ieee802154_dev_s *ieee, +static int mrf24j40_getdevmode(FAR struct mrf24j40_radio_s *dev, FAR uint8_t *mode) { - FAR struct mrf24j40_dev_s *dev = (FAR struct mrf24j40_dev_s *)ieee; - *mode = dev->devmode; - return OK; } @@ -749,10 +1022,9 @@ static int mrf24j40_getdevmode(FAR struct ieee802154_dev_s *ieee, * ****************************************************************************/ -static int mrf24j40_settxpower(FAR struct ieee802154_dev_s *ieee, +static int mrf24j40_settxpower(FAR struct mrf24j40_radio_s *dev, int32_t txpwr) { - FAR struct mrf24j40_dev_s *dev = (FAR struct mrf24j40_dev_s *)ieee; uint8_t reg; int save_txpwr = txpwr; @@ -780,21 +1052,43 @@ static int mrf24j40_settxpower(FAR struct ieee802154_dev_s *ieee, return -EINVAL; } - winfo("remaining attenuation: %d mBm\n",txpwr); + 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; break; /* value 0x01 is 0.5 db, not used */ - default: return -EINVAL; + 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); @@ -810,13 +1104,10 @@ static int mrf24j40_settxpower(FAR struct ieee802154_dev_s *ieee, * ****************************************************************************/ -static int mrf24j40_gettxpower(FAR struct ieee802154_dev_s *ieee, +static int mrf24j40_gettxpower(FAR struct mrf24j40_radio_s *dev, FAR int32_t *txpwr) { - FAR struct mrf24j40_dev_s *dev = (FAR struct mrf24j40_dev_s *)ieee; - *txpwr = dev->txpower; - return OK; } @@ -828,10 +1119,9 @@ static int mrf24j40_gettxpower(FAR struct ieee802154_dev_s *ieee, * ****************************************************************************/ -static int mrf24j40_setcca(FAR struct ieee802154_dev_s *ieee, +static int mrf24j40_setcca(FAR struct mrf24j40_radio_s *dev, FAR struct ieee802154_cca_s *cca) { - FAR struct mrf24j40_dev_s *dev = (FAR struct mrf24j40_dev_s *)ieee; uint8_t mode; if (!cca->use_ed && !cca->use_cs) @@ -862,7 +1152,6 @@ static int mrf24j40_setcca(FAR struct ieee802154_dev_s *ieee, mrf24j40_setreg(dev->spi, MRF24J40_BBREG2, mode); memcpy(&dev->cca, cca, sizeof(struct ieee802154_cca_s)); - return OK; } @@ -874,13 +1163,10 @@ static int mrf24j40_setcca(FAR struct ieee802154_dev_s *ieee, * ****************************************************************************/ -static int mrf24j40_getcca(FAR struct ieee802154_dev_s *ieee, +static int mrf24j40_getcca(FAR struct mrf24j40_radio_s *dev, FAR struct ieee802154_cca_s *cca) { - FAR struct mrf24j40_dev_s *dev = (FAR struct mrf24j40_dev_s *)ieee; - memcpy(cca, &dev->cca, sizeof(struct ieee802154_cca_s)); - return OK; } @@ -892,13 +1178,13 @@ static int mrf24j40_getcca(FAR struct ieee802154_dev_s *ieee, * ****************************************************************************/ -static int mrf24j40_regdump(FAR struct mrf24j40_dev_s *dev) +static int mrf24j40_regdump(FAR struct mrf24j40_radio_s *dev) { uint32_t i; char buf[4+16*3+2+1]; - int len=0; + int len = 0; - winfo("Short regs:\n"); + wlinfo("Short regs:\n"); for (i = 0; i < 0x40; i++) { @@ -911,14 +1197,14 @@ static int mrf24j40_regdump(FAR struct mrf24j40_dev_s *dev) if ((i & 15) == 15) { sprintf(buf+len, "\n"); - winfo("%s", buf); + wlinfo("%s", buf); } } - winfo("Long regs:\n"); - for (i=0x80000200;i<0x80000250;i++) + wlinfo("Long regs:\n"); + for (i = 0x80000200; i < 0x80000250; i++) { - if ((i&15)==0) + if ((i & 15) == 0) { len=sprintf(buf, "%02x: ",i&0xFF); } @@ -927,40 +1213,13 @@ static int mrf24j40_regdump(FAR struct mrf24j40_dev_s *dev) if ((i & 15) == 15) { sprintf(buf+len, "\n"); - winfo("%s", buf); + wlinfo("%s", buf); } } return 0; } -/**************************************************************************** - * Name: mrf24j40_ioctl - * - * Description: - * Misc/unofficial device controls. - * - ****************************************************************************/ - -static int mrf24j40_ioctl(FAR struct ieee802154_dev_s *ieee, int cmd, - unsigned long arg) -{ - FAR struct mrf24j40_dev_s *dev = (FAR struct mrf24j40_dev_s *)ieee; - - switch(cmd) - { - case 1000: - return mrf24j40_regdump(dev); - - case 1001: dev->paenabled = (uint8_t)arg; - winfo("PA %sabled\n", arg ? "en" : "dis"); - return OK; - - default: - return -ENOTTY; - } -} - /**************************************************************************** * Name: mrf24j40_energydetect * @@ -969,10 +1228,9 @@ static int mrf24j40_ioctl(FAR struct ieee802154_dev_s *ieee, int cmd, * ****************************************************************************/ -static int mrf24j40_energydetect(FAR struct ieee802154_dev_s *ieee, +static int mrf24j40_energydetect(FAR struct mrf24j40_radio_s *dev, FAR uint8_t *energy) { - FAR struct mrf24j40_dev_s *dev = (FAR struct mrf24j40_dev_s *)ieee; uint8_t reg; /* Manually enable the LNA*/ @@ -1006,32 +1264,22 @@ static int mrf24j40_energydetect(FAR struct ieee802154_dev_s *ieee, /* Back to automatic control */ mrf24j40_pacontrol(dev, MRF24J40_PA_AUTO); - return OK; } -/* Packet exchange */ - /**************************************************************************** - * Name: mrf24j40_transmit + * Name: mrf24j40_csma_setup * * Description: - * Send a regular packet over the air. + * Setup a CSMA transaction in the normal TX FIFO * ****************************************************************************/ -static int mrf24j40_transmit(FAR struct ieee802154_dev_s *ieee, FAR struct ieee802154_packet_s *packet) +static int mrf24j40_csma_setup(FAR struct mrf24j40_radio_s *dev, + FAR struct iob_s *frame) { - FAR struct mrf24j40_dev_s *dev = (FAR struct mrf24j40_dev_s *)ieee; - uint32_t addr; - uint8_t reg; - int ret; - int hlen = 3; /* include frame control and seq number */ - uint8_t fc1, fc2; - - mrf24j40_pacontrol(dev, MRF24J40_PA_AUTO); - - addr = 0x80000000; + uint8_t reg; + int ret; /* Enable tx int */ @@ -1039,57 +1287,9 @@ static int mrf24j40_transmit(FAR struct ieee802154_dev_s *ieee, FAR struct ieee8 reg &= ~MRF24J40_INTCON_TXNIE; mrf24j40_setreg(dev->spi, MRF24J40_INTCON, reg); - /* Analyze frame control to compute header length */ + /* Setup the FIFO */ - fc1 = packet->data[0]; - fc2 = packet->data[1]; - - // winfo("fc1 %02X fc2 %02X\n", fc1,fc2); - - if ((fc2 & IEEE802154_FC2_DADDR) == IEEE802154_DADDR_SHORT) - { - hlen += 2 + 2; /* Destination PAN + shortaddr */ - } - else if ((fc2 & IEEE802154_FC2_DADDR) == IEEE802154_DADDR_EXT) - { - hlen += 2 + 8; /* Destination PAN + extaddr */ - } - - if ((fc2 & IEEE802154_FC2_SADDR) == IEEE802154_SADDR_SHORT) - { - if ((fc1 & IEEE802154_FC1_INTRA) != IEEE802154_INTRA) - { - hlen += 2; /* No PAN compression, source PAN is different from dest PAN */ - } - - hlen += 2; /* Source saddr */ - } - else if ((fc2 & IEEE802154_FC2_SADDR) == IEEE802154_SADDR_EXT) - { - if ((fc1 & IEEE802154_FC1_INTRA) != IEEE802154_INTRA) - { - hlen += 2; /* No PAN compression, source PAN is different from dest PAN */ - } - - hlen += 8; /* Ext saddr */ - } - -// winfo("hlen %d\n",hlen); - - /* Header len, 0, TODO for security modes */ - - mrf24j40_setreg(dev->spi, addr++, hlen); - - /* Frame length */ - - mrf24j40_setreg(dev->spi, addr++, packet->len); - - /* Frame data */ - - for (ret = 0; ret < packet->len; ret++) /* this sets the correct val for ret */ - { - mrf24j40_setreg(dev->spi, addr++, packet->data[ret]); - } + ret = mrf24j40_setup_fifo(dev, frame, MRF24J40_TXNORM_FIFO); /* If the frame control field contains * an acknowledgment request, set the TXNACKREQ bit. @@ -1097,7 +1297,7 @@ static int mrf24j40_transmit(FAR struct ieee802154_dev_s *ieee, FAR struct ieee8 */ reg = MRF24J40_TXNCON_TXNTRIG; - if (fc1 & IEEE802154_FC1_ACKREQ) + if (frame->io_data[0] & IEEE802154_FRAMECTRL_ACKREQ) { reg |= MRF24J40_TXNCON_TXNACKREQ; } @@ -1105,67 +1305,188 @@ static int mrf24j40_transmit(FAR struct ieee802154_dev_s *ieee, FAR struct ieee8 /* Trigger packet emission */ mrf24j40_setreg(dev->spi, MRF24J40_TXNCON, reg); - - /* Suspend calling thread until transmit is complete */ - - return sem_wait(&ieee->txsem); + return ret; } /**************************************************************************** - * Name: mrf24j40_irqwork_tx + * Name: mrf24j40_gts_setup + * + * Description: + * Setup a GTS transaction in one of the GTS FIFOs + * + ****************************************************************************/ + +static int mrf24j40_gts_setup(FAR struct mrf24j40_radio_s *dev, uint8_t fifo, + FAR struct iob_s *frame) +{ + return -ENOTTY; +} + +/**************************************************************************** + * Name: mrf24j40_setup_fifo + * + * Description: + * + ****************************************************************************/ + +static int mrf24j40_setup_fifo(FAR struct mrf24j40_radio_s *dev, + FAR struct iob_s *frame, uint32_t fifo_addr) +{ + int ret; + int hlen = 3; /* Include frame control and seq number */ + uint16_t frame_ctrl; + + /* Analyze frame control to compute header length */ + + frame_ctrl = frame->io_data[0]; + frame_ctrl |= (frame->io_data[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++, frame->io_len); + + /* Frame data */ + + for (ret = 0; ret < frame->io_len; ret++) /* this sets the correct val for ret */ + { + mrf24j40_setreg(dev->spi, fifo_addr++, frame->io_data[ret]); + } + + return ret; +} + +/**************************************************************************** + * Name: mrf24j40_irqwork_txnorm * * Description: * Manage completion of packet transmission. * ****************************************************************************/ -static void mrf24j40_irqwork_tx(FAR struct mrf24j40_dev_s *dev) +static void mrf24j40_irqwork_txnorm(FAR struct mrf24j40_radio_s *dev) { uint8_t txstat; - uint8_t reg; - - txstat = mrf24j40_getreg(dev->spi, MRF24J40_TXSTAT); - - /* 1 means it failed, we want 1 to mean it worked. - * tx_ok = !(tmp & ~(1 << TXNSTAT)); - * retries = tmp >> 6; - * channel_busy = (tmp & (1 << CCAFAIL)); - */ - - //winfo("TXSTAT%02X!\n", txstat); -#warning TODO report errors - UNUSED(txstat); /* Disable tx int */ - reg = mrf24j40_getreg(dev->spi, MRF24J40_INTCON); - reg |= MRF24J40_INTCON_TXNIE; - mrf24j40_setreg(dev->spi, MRF24J40_INTCON, reg); + txstat = mrf24j40_getreg(dev->spi, MRF24J40_INTCON); + txstat |= MRF24J40_INTCON_TXNIE; + mrf24j40_setreg(dev->spi, MRF24J40_INTCON, txstat); - /* Wake up the thread that triggered the transmission */ + /* 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. + */ - sem_post(&dev->ieee.txsem); + txstat = mrf24j40_getreg(dev->spi, MRF24J40_TXSTAT); + dev->csma_desc.pub.status = txstat & MRF24J40_TXSTAT_TXNSTAT; + + /* Inform the next layer of the transmission success/failure */ + + dev->radiocb->txdone(dev->radiocb, &dev->csma_desc.pub); + + /* We are now done with the transaction */ + + dev->csma_desc.busy = 0; + + /* Free the IOB */ + + iob_free(dev->csma_frame); + + mrf24j40_dopoll_csma(dev); } /**************************************************************************** - * Name: mrf24j40_enablerx + * Name: mrf24j40_irqwork_gts * * Description: - * Enable reception of a packet. The interrupt will signal the rx semaphore. + * Manage completion of packet transmission. * ****************************************************************************/ -static int mrf24j40_rxenable(FAR struct ieee802154_dev_s *ieee, bool state, - FAR struct ieee802154_packet_s *packet) +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.pub.status = txstat & MRF24J40_TXSTAT_TXG1STAT; + } + else if (gts == 1) + { + dev->csma_desc.pub.status = txstat & MRF24J40_TXSTAT_TXG2STAT; + } + + /* Inform the next layer of the transmission success/failure */ + + dev->radiocb->txdone(dev->radiocb, &dev->gts_desc[gts].pub); + + /* We are now done with the transaction */ + + dev->gts_desc[gts].busy = 0; + + /* Free the IOB */ + + iob_free(dev->gts_frame[gts]); + + mrf24j40_dopoll_gts(dev); +} + +/**************************************************************************** + * Name: mrf24j40_rxenable + * + * Description: + * Enable/Disable receiver. + * + ****************************************************************************/ + +static int mrf24j40_rxenable(FAR struct mrf24j40_radio_s *dev, bool enable) { - FAR struct mrf24j40_dev_s *dev = (FAR struct mrf24j40_dev_s *)ieee; uint8_t reg; - if (state) + if (enable) { - mrf24j40_pacontrol(dev, MRF24J40_PA_AUTO); - ieee->rxbuf = packet; - /* Enable rx int */ reg = mrf24j40_getreg(dev->spi, MRF24J40_INTCON); @@ -1174,7 +1495,11 @@ static int mrf24j40_rxenable(FAR struct ieee802154_dev_s *ieee, bool state, } else { - ieee->rxbuf = NULL; + /* Disable rx int */ + + reg = mrf24j40_getreg(dev->spi, MRF24J40_INTCON); + reg |= MRF24J40_INTCON_RXIE; + mrf24j40_setreg(dev->spi, MRF24J40_INTCON, reg); } return OK; @@ -1188,42 +1513,60 @@ static int mrf24j40_rxenable(FAR struct ieee802154_dev_s *ieee, bool state, * ****************************************************************************/ -static void mrf24j40_irqwork_rx(FAR struct mrf24j40_dev_s *dev) +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; - /*winfo("!\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 */ + /* Disable packet reception. See pg. 109 of datasheet */ mrf24j40_setreg(dev->spi, MRF24J40_BBREG1, MRF24J40_BBREG1_RXDECINV); - /* Read packet */ + /* Allocate a data_ind to put the frame in */ - addr = 0x80000300; - dev->ieee.rxbuf->len = mrf24j40_getreg(dev->spi, addr++); - /*winfo("len %3d\n", dev->ieee.rxbuf->len);*/ - - for (index = 0; index < dev->ieee.rxbuf->len; index++) + ind = ieee802154_ind_allocate(); + if (ind == NULL) { - dev->ieee.rxbuf->data[index] = mrf24j40_getreg(dev->spi, addr++); + wlerr("ERROR: Unable to allocate data_ind. Discarding frame"); + goto done; } - dev->ieee.rxbuf->lqi = mrf24j40_getreg(dev->spi, addr++); - dev->ieee.rxbuf->rssi = mrf24j40_getreg(dev->spi, addr++); + /* Read packet */ - /* Reduce len by 2, we only receive frames with correct crc, no check required */ + addr = MRF24J40_RXBUF_BASE; - dev->ieee.rxbuf->len -= 2; + ind->frame->io_len= mrf24j40_getreg(dev->spi, addr++); + /* TODO: This needs to be changed. It is inefficient to do the SPI read byte + * by byte */ + + for (index = 0; index < ind->frame->io_len; index++) + { + ind->frame->io_data[index] = mrf24j40_getreg(dev->spi, addr++); + } + + ind->lqi = mrf24j40_getreg(dev->spi, addr++); + ind->rssi = mrf24j40_getreg(dev->spi, addr++); + + /* Reduce len by 2, we only receive frames with correct crc, no check + * required. + */ + + ind->frame->io_len -= 2; + + /* Callback the receiver in the next highest layer */ + + dev->radiocb->rxframe(dev->radiocb, ind); + +done: /* Enable reception of next packet by flushing the fifo. * This is an MRF24J40 errata (no. 1). */ @@ -1234,7 +1577,14 @@ static void mrf24j40_irqwork_rx(FAR struct mrf24j40_dev_s *dev) mrf24j40_setreg(dev->spi, MRF24J40_BBREG1, 0); - sem_post(&dev->ieee.rxsem); + /* Only enable RX interrupt if we are to be listening when IDLE */ + + if (dev->rxonidle) + { + reg = mrf24j40_getreg(dev->spi, MRF24J40_INTCON); + reg &= ~MRF24J40_INTCON_RXIE; + mrf24j40_setreg(dev->spi, MRF24J40_INTCON, reg); + } } /**************************************************************************** @@ -1256,7 +1606,7 @@ static void mrf24j40_irqwork_rx(FAR struct mrf24j40_dev_s *dev) static void mrf24j40_irqworker(FAR void *arg) { - FAR struct mrf24j40_dev_s *dev = (FAR struct mrf24j40_dev_s *)arg; + FAR struct mrf24j40_radio_s *dev = (FAR struct mrf24j40_radio_s *)arg; uint8_t intstat; DEBUGASSERT(dev); @@ -1265,7 +1615,7 @@ static void mrf24j40_irqworker(FAR void *arg) /* Read and store INTSTAT - this clears the register. */ intstat = mrf24j40_getreg(dev->spi, MRF24J40_INTSTAT); -// winfo("INT%02X\n", intstat); + //wlinfo("INT%02X\n", intstat); /* Do work according to the pending interrupts */ @@ -1280,12 +1630,26 @@ static void mrf24j40_irqworker(FAR void *arg) { /* A packet was transmitted or failed*/ - mrf24j40_irqwork_tx(dev); + mrf24j40_irqwork_txnorm(dev); } - /* Re-Enable GPIO interrupts */ + if ((intstat & MRF24J40_INTSTAT_TXG1IF)) + { + /* A packet was transmitted or failed*/ - dev->lower->enable(dev->lower, TRUE); + mrf24j40_irqwork_txgts(dev, 0); + } + + if ((intstat & MRF24J40_INTSTAT_TXG1IF)) + { + /* A packet was transmitted or failed*/ + + mrf24j40_irqwork_txgts(dev, 1); + } + + /* Re-enable GPIO interrupts */ + + dev->lower->enable(dev->lower, true); } /**************************************************************************** @@ -1305,13 +1669,11 @@ static void mrf24j40_irqworker(FAR void *arg) * ****************************************************************************/ -static int mrf24j40_interrupt(int irq, FAR void *context) +static int mrf24j40_interrupt(int irq, FAR void *context, FAR void *arg) { - /* To support multiple devices, - * retrieve the priv structure using the irq number - */ + FAR struct mrf24j40_radio_s *dev = (FAR struct mrf24j40_radio_s *)arg; - register FAR struct mrf24j40_dev_s *dev = &g_mrf24j40_devices[0]; + 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 @@ -1327,7 +1689,7 @@ static int mrf24j40_interrupt(int irq, FAR void *context) * Interrupts are re-enabled in enc_irqworker() when the work is completed. */ - dev->lower->enable(dev->lower, FALSE); + dev->lower->enable(dev->lower, false); return work_queue(HPWORK, &dev->irqwork, mrf24j40_irqworker, (FAR void *)dev, 0); } @@ -1343,26 +1705,21 @@ static int mrf24j40_interrupt(int irq, FAR void *context) * ****************************************************************************/ -FAR struct ieee802154_dev_s *mrf24j40_init(FAR struct spi_dev_s *spi, - FAR const struct mrf24j40_lower_s *lower) +FAR struct ieee802154_radio_s *mrf24j40_init(FAR struct spi_dev_s *spi, + FAR const struct mrf24j40_lower_s *lower) { - FAR struct mrf24j40_dev_s *dev; + FAR struct mrf24j40_radio_s *dev; struct ieee802154_cca_s cca; -#if 0 - dev = kmm_zalloc(sizeof(struct mrf24j40_dev_s)); - - if (!dev) + dev = kmm_zalloc(sizeof(struct mrf24j40_radio_s)); + if (dev == NULL) { return NULL; } -#else - dev = &g_mrf24j40_devices[0]; -#endif /* Attach irq */ - if (lower->attach(lower, mrf24j40_interrupt) != OK) + if (lower->attach(lower, mrf24j40_interrupt, dev) != OK) { #if 0 free(dev); @@ -1370,44 +1727,35 @@ FAR struct ieee802154_dev_s *mrf24j40_init(FAR struct spi_dev_s *spi, return NULL; } - dev->ieee.ops = &mrf24j40_devops; + /* Allow exclusive access to the privmac struct */ - /* Initialize semaphores */ + sem_init(&dev->exclsem, 0, 1); - sem_init(&dev->ieee.rxsem, 0, 0); - sem_init(&dev->ieee.txsem, 0, 0); - - /* These semaphores are all used for signaling and, hence, should - * not have priority inheritance enabled. - */ - - sem_setprotocol(&dev->ieee.rxsem, SEM_PRIO_NONE); - sem_setprotocol(&dev->ieee.txsem, SEM_PRIO_NONE); + dev->radio.ops = &mrf24j40_devops; dev->lower = lower; dev->spi = spi; mrf24j40_initialize(dev); - mrf24j40_setchannel(&dev->ieee, 11); - mrf24j40_setpanid (&dev->ieee, IEEE802154_PAN_DEFAULT); - mrf24j40_setsaddr (&dev->ieee, IEEE802154_SADDR_UNSPEC); - mrf24j40_seteaddr (&dev->ieee, IEEE802154_EADDR_UNSPEC); + mrf24j40_setchannel(dev, 11); + mrf24j40_setpanid (dev, 0xFFFF); + mrf24j40_setsaddr (dev, 0xFFFF); + mrf24j40_seteaddr (dev, (uint8_t*)"\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"); /* 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->ieee, &cca); + mrf24j40_setcca(dev, &cca); mrf24j40_setrxmode(dev, MRF24J40_RXMODE_NORMAL); - mrf24j40_settxpower(&dev->ieee, 0); /*16. Set transmitter power .*/ + mrf24j40_settxpower(dev, 0); /*16. Set transmitter power .*/ mrf24j40_pacontrol(dev, MRF24J40_PA_AUTO); - dev->lower->enable(dev->lower, TRUE); - - return &dev->ieee; + dev->lower->enable(dev->lower, true); + return &dev->radio; } diff --git a/drivers/wireless/ieee802154/mrf24j40.h b/drivers/wireless/ieee802154/mrf24j40.h index de3131e4df..f9a8a35a5d 100644 --- a/drivers/wireless/ieee802154/mrf24j40.h +++ b/drivers/wireless/ieee802154/mrf24j40.h @@ -33,8 +33,8 @@ * ****************************************************************************/ -#ifndef __DRIVERS_IEEE802154_MRF24J40_H -#define __DRIVERS_IEEE802154_MRF24J40_H +#ifndef __DRIVERS_WIRELESS_IEEE802154_MRF24J40_H +#define __DRIVERS_WIRELESS_IEEE802154_MRF24J40_H /* MRF24J40 Registers *******************************************************/ @@ -97,18 +97,27 @@ #define MRF24J40_BBREG6 0x3E #define MRF24J40_CCAEDTH 0x3F -#define MRF24J40_RFCON0 0x80000200 -#define MRF24J40_RFCON1 0x80000201 -#define MRF24J40_RFCON2 0x80000202 -#define MRF24J40_RFCON3 0x80000203 -#define MRF24J40_RFCON5 0x80000205 -#define MRF24J40_RFCON6 0x80000206 -#define MRF24J40_RFCON7 0x80000207 -#define MRF24J40_RFCON8 0x80000208 -#define MRF24J40_SLPCAL0 0x80000209 -#define MRF24J40_SLPCAL1 0x8000020A -#define MRF24J40_SLPCAL2 0x8000020B -#define MRF24J40_RFSTATE 0x8000020F +#define MRF24J40_FIFO_BASE 0x80000000 +#define MRF24J40_LONGREG_BASE 0x80000200 +#define MRF24J40_RXBUF_BASE 0x80000300 + +#define MRF24J40_TXNORM_FIFO (MRF24J40_FIFO_BASE + 0x000) +#define MRF24J40_BEACON_FIFO (MRF24J40_FIFO_BASE + 0x080) +#define MRF24J40_GTS1_FIFO (MRF24J40_FIFO_BASE + 0x100) +#define MRF24J40_GTS2_FIFO (MRF24J40_FIFO_BASE + 0x180) + +#define MRF24J40_RFCON0 (MRF24J40_LONGREG_BASE + 0x00) +#define MRF24J40_RFCON1 (MRF24J40_LONGREG_BASE + 0x01) +#define MRF24J40_RFCON2 (MRF24J40_LONGREG_BASE + 0x02) +#define MRF24J40_RFCON3 (MRF24J40_LONGREG_BASE + 0x03) +#define MRF24J40_RFCON5 (MRF24J40_LONGREG_BASE + 0x05) +#define MRF24J40_RFCON6 (MRF24J40_LONGREG_BASE + 0x06) +#define MRF24J40_RFCON7 (MRF24J40_LONGREG_BASE + 0x07) +#define MRF24J40_RFCON8 (MRF24J40_LONGREG_BASE + 0x08) +#define MRF24J40_SLPCAL0 (MRF24J40_LONGREG_BASE + 0x09) +#define MRF24J40_SLPCAL1 (MRF24J40_LONGREG_BASE + 0x0A) +#define MRF24J40_SLPCAL2 (MRF24J40_LONGREG_BASE + 0x0B) +#define MRF24J40_RFSTATE (MRF24J40_LONGREG_BASE + 0x0F) #define MRF24J40_RSSI 0x80000210 #define MRF24J40_SLPCON0 0x80000211 #define MRF24J40_SLPCON1 0x80000220 @@ -147,26 +156,26 @@ /* INTSTAT bits */ -#define MRF24J40_INTSTAT_SLPIF 0x80 -#define MRF24J40_INTSTAT_WAKEIF 0x40 -#define MRF24J40_INTSTAT_HSYMTMRIF 0x20 -#define MRF24J40_INTSTAT_SECIF 0x10 -#define MRF24J40_INTSTAT_RXIF 0x08 -#define MRF24J40_INTSTAT_TXG2IF 0x04 -#define MRF24J40_INTSTAT_TXG1IF 0x02 -#define MRF24J40_INTSTAT_TXNIF 0x01 +#define MRF24J40_INTSTAT_TXNIF (1 << 0) +#define MRF24J40_INTSTAT_TXG1IF (1 << 1) +#define MRF24J40_INTSTAT_TXG2IF (1 << 2) +#define MRF24J40_INTSTAT_RXIF (1 << 3) +#define MRF24J40_INTSTAT_SECIF (1 << 4) +#define MRF24J40_INTSTAT_HSYMTMRIF (1 << 5) +#define MRF24J40_INTSTAT_WAKEIF (1 << 6) +#define MRF24J40_INTSTAT_SLPIF (1 << 7) /* RXMCR bits */ -#define MRF24J40_RXMCR_PROMI 0x01 /* Enable promisc mode (rx all valid packets) */ -#define MRF24J40_RXMCR_ERRPKT 0x02 /* Do not check CRC */ +#define MRF24J40_RXMCR_PROMI (1 << 0) /* Enable promisc mode (rx all valid packets) */ +#define MRF24J40_RXMCR_ERRPKT 0x02 /* Do not check CRC */ #define MRF24J40_RXMCR_COORD 0x04 /* Enable coordinator mode ??? DIFFERENCE ??? - not used in datasheet! */ -#define MRF24J40_RXMCR_PANCOORD 0x08 /* Enable PAN coordinator mode ??? DIFFERENCE ??? */ +#define MRF24J40_RXMCR_PANCOORD 0x08 /* Enable PAN coordinator mode ??? DIFFERENCE ??? */ #define MRF24J40_RXMCR_NOACKRSP 0x20 /* Enable auto ACK when a packet is rxed */ /* TXMCR bits */ -#define MRF24J40_TXMCR_CSMABF0 0x01 +#define MRF24J40_TXMCR_CSMABF0 (1 << 0) #define MRF24J40_TXMCR_CSMABF1 0x02 #define MRF24J40_TXMCR_CSMABF2 0x04 #define MRF24J40_TXMCR_MACMINBE0 0x08 @@ -184,7 +193,7 @@ #define MRF24J40_INTCON_RXIE 0x08 #define MRF24J40_INTCON_TXG2IE 0x04 #define MRF24J40_INTCON_TXG1IE 0x02 -#define MRF24J40_INTCON_TXNIE 0x01 +#define MRF24J40_INTCON_TXNIE (1 << 0) /* BBREG1 bits */ @@ -197,10 +206,19 @@ /* TXNCON bits */ -#define MRF24J40_TXNCON_TXNTRIG 0x01 /* Trigger packet tx, automatically cleared */ +#define MRF24J40_TXNCON_TXNTRIG (1 << 0) /* Trigger packet tx, automatically cleared */ #define MRF24J40_TXNCON_TXNSECEN 0x02 /* Enable security */ #define MRF24J40_TXNCON_TXNACKREQ 0x04 /* An ACK is requested for this pkt */ #define MRF24J40_TXNCON_INDIRECT 0x08 /* Activate indirect tx bit (for coordinators) */ #define MRF24J40_TXNCON_FPSTAT 0x10 /* Status of the frame pending big in txed acks */ -#endif /* __DRIVERS_IEEE802154_MRF24J40_H */ +/* TXSTAT bits */ + +#define MRF24J40_TXSTAT_TXNSTAT (1 << 0) +#define MRF24J40_TXSTAT_TXG1STAT (1 << 1) +#define MRF24J40_TXSTAT_TXG2STAT (1 << 2) +#define MRF24J40_TXSTAT_CCAFAIL (1 << 5) +#define MRF24J40_TXSTAT_X_SHIFT 6 +#define MRF24J40_TXSTAT_X_MASK (3 << MRF24J40_TXSTAT_X_SHIFT) + +#endif /* __DRIVERS_WIRELESS_IEEE802154_MRF24J40_H */ diff --git a/include/nuttx/fs/ioctl.h b/include/nuttx/fs/ioctl.h index 674eafc1d7..cfcc4507d6 100644 --- a/include/nuttx/fs/ioctl.h +++ b/include/nuttx/fs/ioctl.h @@ -1,7 +1,7 @@ /**************************************************************************** * include/nuttx/fs/ioctl.h * - * Copyright (C) 2008, 2009, 2011-2014 Gregory Nutt. All rights reserved. + * Copyright (C) 2008, 2009, 2011-2014, 2017 Gregory Nutt. All rights reserved. * Author: Gregory Nutt * * Redistribution and use in source and binary forms, with or without @@ -88,6 +88,7 @@ #define _GPIOBASE (0x2300) /* GPIO driver commands */ #define _CLIOCBASE (0x2400) /* Contactless modules ioctl commands */ #define _USBCBASE (0x2500) /* USB-C controller ioctl commands */ +#define _MAC802154BASE (0x2600) /* 802.15.4 MAC ioctl commands */ /* boardctl() commands share the same number space */ @@ -421,6 +422,12 @@ #define _USBCIOCVALID(c) (_IOC_TYPE(c)==_USBCBASE) #define _USBCIOC(nr) _IOC(_USBCBASE,nr) +/* 802.15.4 MAC driver ioctl definitions ************************************/ +/* (see nuttx/include/wireless/ieee802154/ieee802154_mac.h */ + +#define _MAC802154IOCVALID(c) (_IOC_TYPE(c)==_MAC802154BASE) +#define _MAC802154IOC(nr) _IOC(_MAC802154BASE,nr) + /* boardctl() command definitions *******************************************/ #define _BOARDIOCVALID(c) (_IOC_TYPE(c)==_BOARDBASE) diff --git a/include/nuttx/net/ieee802154.h b/include/nuttx/net/ieee802154.h index 6132d3d02b..736141a351 100644 --- a/include/nuttx/net/ieee802154.h +++ b/include/nuttx/net/ieee802154.h @@ -58,61 +58,20 @@ * Pre-processor Definitions ****************************************************************************/ -/* By default, a 2-byte Rime address is used for the IEEE802.15.4 MAC - * device's link layer address. If CONFIG_NET_6LOWPAN_RIMEADDR_EXTENDED - * is selected, then an 8-byte Rime address will be used. +/* By default, a 2-byte short address is used for the IEEE802.15.4 MAC + * device's link layer address. If CONFIG_NET_6LOWPAN_EXTENDEDADDR + * is selected, then an 8-byte extended address will be used. */ -#ifdef CONFIG_NET_6LOWPAN_RIMEADDR_EXTENDED -# define NET_6LOWPAN_RIMEADDR_SIZE 8 +#define NET_6LOWPAN_SADDRSIZE 2 +#define NET_6LOWPAN_EADDRSIZE 8 + +#ifdef CONFIG_NET_6LOWPAN_EXTENDEDADDR +# define NET_6LOWPAN_ADDRSIZE NET_6LOWPAN_EADDRSIZE #else -# define NET_6LOWPAN_RIMEADDR_SIZE 2 +# define NET_6LOWPAN_ADDRSIZE NET_6LOWPAN_SADDRSIZE #endif -/* Frame format definitions *************************************************/ -/* These are some definitions of element values used in the FCF. See the - * IEEE802.15.4 spec for details. - */ - -#define FRAME802154_FRAMETYPE_SHIFT (0) /* Bits 0-2: Frame type */ -#define FRAME802154_FRAMETYPE_MASK (7 << FRAME802154_FRAMETYPE_SHIFT) -#define FRAME802154_SECENABLED_SHIFT (3) /* Bit 3: Security enabled */ -#define FRAME802154_FRAMEPENDING_SHIFT (4) /* Bit 4: Frame pending */ -#define FRAME802154_ACKREQUEST_SHIFT (5) /* Bit 5: ACK request */ -#define FRAME802154_PANIDCOMP_SHIFT (6) /* Bit 6: PANID compression */ - /* Bits 7-9: Reserved */ -#define FRAME802154_DSTADDR_SHIFT (2) /* Bits 10-11: Dest address mode */ -#define FRAME802154_DSTADDR_MASK (3 << FRAME802154_DSTADDR_SHIFT) -#define FRAME802154_VERSION_SHIFT (4) /* Bit 12-13: Frame version */ -#define FRAME802154_VERSION_MASK (3 << FRAME802154_VERSION_SHIFT) -#define FRAME802154_SRCADDR_SHIFT (6) /* Bits 14-15: Source address mode */ -#define FRAME802154_SRCADDR_MASK (3 << FRAME802154_SRCADDR_SHIFT) - -/* Unshifted values for use in struct frame802154_fcf_s */ - -#define FRAME802154_BEACONFRAME (0) -#define FRAME802154_DATAFRAME (1) -#define FRAME802154_ACKFRAME (2) -#define FRAME802154_CMDFRAME (3) - -#define FRAME802154_BEACONREQ (7) - -#define FRAME802154_IEEERESERVED (0) -#define FRAME802154_NOADDR (0) /* Only valid for ACK or Beacon frames */ -#define FRAME802154_SHORTADDRMODE (2) -#define FRAME802154_LONGADDRMODE (3) - -#define FRAME802154_NOBEACONS 0x0f - -#define FRAME802154_BROADCASTADDR 0xffff -#define FRAME802154_BROADCASTPANDID 0xffff - -#define FRAME802154_IEEE802154_2003 (0) -#define FRAME802154_IEEE802154_2006 (1) - -#define FRAME802154_SECURITY_LEVEL_NONE (0) -#define FRAME802154_SECURITY_LEVEL_128 (3) - /* This maximum size of an IEEE802.15.4 frame. Certain, non-standard * devices may exceed this value, however. */ @@ -123,11 +82,35 @@ * Public Types ****************************************************************************/ -/* Rime address representation */ +/* IEEE 802.15.4 address representations */ -struct rimeaddr_s +struct sixlowpan_saddr_s { - uint8_t u8[NET_6LOWPAN_RIMEADDR_SIZE]; + uint8_t u8[NET_6LOWPAN_SADDRSIZE]; +}; + +struct sixlowpan_eaddr_s +{ + uint8_t u8[NET_6LOWPAN_EADDRSIZE]; +}; + +union sixlowpan_anyaddr_u +{ + struct sixlowpan_saddr_s saddr; + struct sixlowpan_eaddr_s eaddr; +}; + +struct sixlowpan_tagaddr_s +{ + bool extended; + union sixlowpan_anyaddr_u u; +}; + +/* Represents the configured address size */ + +struct sixlowpan_addr_s +{ + uint8_t u8[NET_6LOWPAN_ADDRSIZE]; }; /**************************************************************************** diff --git a/include/nuttx/net/netdev.h b/include/nuttx/net/netdev.h index eb84a7774f..782c2e3399 100644 --- a/include/nuttx/net/netdev.h +++ b/include/nuttx/net/netdev.h @@ -224,7 +224,7 @@ struct net_driver_s #ifdef CONFIG_NET_6LOWPAN /* The address assigned to an IEEE 802.15.4 radio. */ - struct rimeaddr_s ieee802154; /* IEEE 802.15.4 Radio address */ + struct sixlowpan_addr_s ieee802154; /* IEEE 802.15.4 Radio address */ #endif } d_mac; #endif @@ -436,8 +436,12 @@ int ipv6_input(FAR struct net_driver_s *dev); #endif #ifdef CONFIG_NET_6LOWPAN -struct ieee802154_driver_s; /* See sixlowpan.h */ -int sixlowpan_input(FAR struct ieee802154_driver_s *ieee); +struct ieee802154_driver_s; /* See sixlowpan.h */ +struct ieee802154_data_ind_s; /* See ieee8021454_mac.h */ +struct iob_s; /* See iob.h */ +int sixlowpan_input(FAR struct ieee802154_driver_s *ieee, + FAR struct iob_s *framelist, + FAR const struct ieee802154_data_ind_s *ind); #endif /**************************************************************************** @@ -513,7 +517,7 @@ int devif_timer(FAR struct net_driver_s *dev, devif_poll_callback_t callback); * * If no Neighbor Table entry is found for the destination IPv6 address, * the packet in the d_buf[] is replaced by an ICMPv6 Neighbor Solict - * request packet for the IPv6 address. The IPv6 packet is dropped and + * request packet for the IPv6 address. The IPv6 packet is dropped and * it is assumed that the higher level protocols (e.g., TCP) eventually * will retransmit the dropped packet. * diff --git a/include/nuttx/net/sixlowpan.h b/include/nuttx/net/sixlowpan.h index 328723b2f8..a99f0e5e67 100644 --- a/include/nuttx/net/sixlowpan.h +++ b/include/nuttx/net/sixlowpan.h @@ -1,6 +1,7 @@ /**************************************************************************** * include/nuttx/net/sixlowpan.h - * Header file for the 6lowpan implementation (RFC4944 and draft-hui-6lowpan-hc-01) + * Header file for the 6lowpan implementation (RFC4944 and + * draft-hui-6lowpan-hc-01) * * Copyright (C) 2017, Gregory Nutt, all rights reserved * Author: Gregory Nutt @@ -81,132 +82,132 @@ * bytes for all subsequent headers. */ -#define RIME_FRAG_DISPATCH_SIZE 0 /* 16 bit */ -#define RIME_FRAG_TAG 2 /* 16 bit */ -#define RIME_FRAG_OFFSET 4 /* 8 bit */ +#define SIXLOWPAN_FRAG_DISPATCH_SIZE 0 /* 16 bit */ +#define SIXLOWPAN_FRAG_TAG 2 /* 16 bit */ +#define SIXLOWPAN_FRAG_OFFSET 4 /* 8 bit */ -/* Define the Rime buffer as a byte array */ +/* Define the frame buffer as a byte array */ -#define RIME_HC1_DISPATCH 0 /* 8 bit */ -#define RIME_HC1_ENCODING 1 /* 8 bit */ -#define RIME_HC1_TTL 2 /* 8 bit */ +#define SIXLOWPAN_HC1_DISPATCH 0 /* 8 bit */ +#define SIXLOWPAN_HC1_ENCODING 1 /* 8 bit */ +#define SIXLOWPAN_HC1_TTL 2 /* 8 bit */ -#define RIME_HC1_HC_UDP_DISPATCH 0 /* 8 bit */ -#define RIME_HC1_HC_UDP_HC1_ENCODING 1 /* 8 bit */ -#define RIME_HC1_HC_UDP_UDP_ENCODING 2 /* 8 bit */ -#define RIME_HC1_HC_UDP_TTL 3 /* 8 bit */ -#define RIME_HC1_HC_UDP_PORTS 4 /* 8 bit */ -#define RIME_HC1_HC_UDP_CHKSUM 5 /* 16 bit */ +#define SIXLOWPAN_HC1_HC_UDP_DISPATCH 0 /* 8 bit */ +#define SIXLOWPAN_HC1_HC_UDP_HC1_ENCODING 1 /* 8 bit */ +#define SIXLOWPAN_HC1_HC_UDP_UDP_ENCODING 2 /* 8 bit */ +#define SIXLOWPAN_HC1_HC_UDP_TTL 3 /* 8 bit */ +#define SIXLOWPAN_HC1_HC_UDP_PORTS 4 /* 8 bit */ +#define SIXLOWPAN_HC1_HC_UDP_CHKSUM 5 /* 16 bit */ /* Min and Max compressible UDP ports - HC06 */ -#define SIXLOWPAN_UDP_4_BIT_PORT_MIN 0xf0b0 -#define SIXLOWPAN_UDP_4_BIT_PORT_MAX 0xf0bf /* f0b0 + 15 */ -#define SIXLOWPAN_UDP_8_BIT_PORT_MIN 0xf000 -#define SIXLOWPAN_UDP_8_BIT_PORT_MAX 0xf0ff /* f000 + 255 */ +#define SIXLOWPAN_UDP_4_BIT_PORT_MIN 0xf0b0 +#define SIXLOWPAN_UDP_4_BIT_PORT_MAX 0xf0bf /* f0b0 + 15 */ +#define SIXLOWPAN_UDP_8_BIT_PORT_MIN 0xf000 +#define SIXLOWPAN_UDP_8_BIT_PORT_MAX 0xf0ff /* f000 + 255 */ /* 6lowpan dispatches */ -#define SIXLOWPAN_DISPATCH_NALP 0x00 /* 00xxxxxx Not a LoWPAN packet */ -#define SIXLOWPAN_DISPATCH_NALP_MASK 0xc0 /* 11000000 */ +#define SIXLOWPAN_DISPATCH_NALP 0x00 /* 00xxxxxx Not a LoWPAN packet */ +#define SIXLOWPAN_DISPATCH_NALP_MASK 0xc0 /* 11000000 */ -#define SIXLOWPAN_DISPATCH_IPV6 0x41 /* 01000001 Uncompressed IPv6 addresses */ -#define SIXLOWPAN_DISPATCH_HC1 0x42 /* 01000010 HC1 Compressed IPv6 header */ -#define SIXLOWPAN_DISPATCH_BC0 0x50 /* 01010000 BC0 Broadcast header */ -#define SIXLOWPAN_DISPATCH_ESC 0x7f /* 01111111 Additional Dispatch octet follows */ +#define SIXLOWPAN_DISPATCH_IPV6 0x41 /* 01000001 Uncompressed IPv6 addresses */ +#define SIXLOWPAN_DISPATCH_HC1 0x42 /* 01000010 HC1 Compressed IPv6 header */ +#define SIXLOWPAN_DISPATCH_BC0 0x50 /* 01010000 BC0 Broadcast header */ +#define SIXLOWPAN_DISPATCH_ESC 0x7f /* 01111111 Additional Dispatch octet follows */ -#define SIXLOWPAN_DISPATCH_IPHC 0x60 /* 011xxxxx IP Header Compression (IPHC)*/ -#define SIXLOWPAN_DISPATCH_IPHC_MASK 0xe0 /* 11100000 */ +#define SIXLOWPAN_DISPATCH_IPHC 0x60 /* 011xxxxx IP Header Compression (IPHC)*/ +#define SIXLOWPAN_DISPATCH_IPHC_MASK 0xe0 /* 11100000 */ -#define SIXLOWPAN_DISPATCH_MESH 0x80 /* 10xxxxxx Mesh routing header */ -#define SIXLOWPAN_DISPATCH_MESH_MASK 0xc0 /* 11000000 */ +#define SIXLOWPAN_DISPATCH_MESH 0x80 /* 10xxxxxx Mesh routing header */ +#define SIXLOWPAN_DISPATCH_MESH_MASK 0xc0 /* 11000000 */ -#define SIXLOWPAN_DISPATCH_FRAG1 0xc0 /* 11000xxx Fragmentation header (first) */ -#define SIXLOWPAN_DISPATCH_FRAGN 0xe0 /* 11100xxx Fragmentation header (subsequent) */ -#define SIXLOWPAN_DISPATCH_FRAG_MASK 0xf8 /* 11111000 */ +#define SIXLOWPAN_DISPATCH_FRAG1 0xc0 /* 11000xxx Fragmentation header (first) */ +#define SIXLOWPAN_DISPATCH_FRAGN 0xe0 /* 11100xxx Fragmentation header (subsequent) */ +#define SIXLOWPAN_DISPATCH_FRAG_MASK 0xf8 /* 11111000 */ /* HC1 encoding */ -#define SIXLOWPAN_HC1_NH_UDP 0x02 -#define SIXLOWPAN_HC1_NH_TCP 0x06 -#define SIXLOWPAN_HC1_NH_ICMP6 0x04 +#define SIXLOWPAN_HC1_NH_UDP 0x02 +#define SIXLOWPAN_HC1_NH_TCP 0x06 +#define SIXLOWPAN_HC1_NH_ICMP6 0x04 /* HC_UDP encoding (works together with HC1) */ -#define SIXLOWPAN_HC_UDP_ALL_C 0xe0 +#define SIXLOWPAN_HC_UDP_ALL_C 0xe0 /* IPHC encoding * * Values of fields within the IPHC encoding first byte * (Using MS-to-LS bit numbering of the draft RFC) */ - /* Bits 0-2: 011 */ -#define SIXLOWPAN_IPHC_TC_MASK 0x18 /* Bits 3-4: Traffic Class, Flow Label */ -# define SIXLOWPAN_IPHC_TC_00 0x00 /* ECN+DSCP+4-bit Pad+Flow Label (4 bytes) */ -# define SIXLOWPAN_IPHC_TC_01 0x08 /* ECN+2-bit Pad+ Flow Label (3 bytes), DSCP is elided. */ -# define SIXLOWPAN_IPHC_TC_10 0x10 /* ECN+DSCP (1 byte), Flow Label is elided */ -# define SIXLOWPAN_IPHC_TC_11 0x11 /* Traffic Class and Flow Label are elided */ -#define SIXLOWPAN_IPHC_NH 0x04 /* Bit 5: Next Header Compressed */ -#define SIXLOWPAN_IPHC_HLIM_MASK 0x03 /* Bits 6-7: Hop Limit */ -# define SIXLOWPAN_IPHC_HLIM_INLINE 0x00 /* Carried in-line */ -# define SIXLOWPAN_IPHC_HLIM_1 0x01 /* Compressed hop limit of 1 */ -# define SIXLOWPAN_IPHC_HLIM_64 0x02 /* Compressed hop limit of 64 */ -# define SIXLOWPAN_IPHC_HLIM_255 0x03 /* Compressed hop limit of 255 */ + /* Bits 0-2: 011 */ +#define SIXLOWPAN_IPHC_TC_MASK 0x18 /* Bits 3-4: Traffic Class, Flow Label */ +# define SIXLOWPAN_IPHC_TC_00 0x00 /* ECN+DSCP+4-bit Pad+Flow Label (4 bytes) */ +# define SIXLOWPAN_IPHC_TC_01 0x08 /* ECN+2-bit Pad+ Flow Label (3 bytes), DSCP is elided. */ +# define SIXLOWPAN_IPHC_TC_10 0x10 /* ECN+DSCP (1 byte), Flow Label is elided */ +# define SIXLOWPAN_IPHC_TC_11 0x11 /* Traffic Class and Flow Label are elided */ +#define SIXLOWPAN_IPHC_NH 0x04 /* Bit 5: Next Header Compressed */ +#define SIXLOWPAN_IPHC_HLIM_MASK 0x03 /* Bits 6-7: Hop Limit */ +# define SIXLOWPAN_IPHC_HLIM_INLINE 0x00 /* Carried in-line */ +# define SIXLOWPAN_IPHC_HLIM_1 0x01 /* Compressed hop limit of 1 */ +# define SIXLOWPAN_IPHC_HLIM_64 0x02 /* Compressed hop limit of 64 */ +# define SIXLOWPAN_IPHC_HLIM_255 0x03 /* Compressed hop limit of 255 */ /* Values of fields within the IPHC encoding second byte */ -#define SIXLOWPAN_IPHC_CID 0x80 /* Bit 8: Context identifier extension */ -#define SIXLOWPAN_IPHC_SAC 0x40 /* Bit 9: Source address compression */ -#define SIXLOWPAN_IPHC_SAM_MASK 0x30 /* Bits 10-11: Source address mode */ -# define SIXLOWPAN_IPHC_SAM_128 0x00 /* 128-bits */ -# define SIXLOWPAN_IPHC_SAM_64 0x10 /* 64-bits */ -# define SIXLOWPAN_IPHC_SAM_16 0x20 /* 16-bits */ -# define SIXLOWPAN_IPHC_SAM_0 0x30 /* 0-bits */ -#define SIXLOWPAN_IPHC_M 0x08 /* Bit 12: Multicast compression */ -#define SIXLOWPAN_IPHC_DAC 0x04 /* Bit 13: Destination address compression */ -#define SIXLOWPAN_IPHC_DAM_MASK 0x03 /* Bits 14-15: Destination address mode */ -# define SIXLOWPAN_IPHC_DAM_128 0x00 /* 128-bits */ -# define SIXLOWPAN_IPHC_DAM_64 0x01 /* 64-bits */ -# define SIXLOWPAN_IPHC_DAM_16 0x02 /* 16-bits */ -# define SIXLOWPAN_IPHC_DAM_0 0x03 /* 0-bits */ +#define SIXLOWPAN_IPHC_CID 0x80 /* Bit 8: Context identifier extension */ +#define SIXLOWPAN_IPHC_SAC 0x40 /* Bit 9: Source address compression */ +#define SIXLOWPAN_IPHC_SAM_MASK 0x30 /* Bits 10-11: Source address mode */ +# define SIXLOWPAN_IPHC_SAM_128 0x00 /* 128-bits */ +# define SIXLOWPAN_IPHC_SAM_64 0x10 /* 64-bits */ +# define SIXLOWPAN_IPHC_SAM_16 0x20 /* 16-bits */ +# define SIXLOWPAN_IPHC_SAM_0 0x30 /* 0-bits */ +#define SIXLOWPAN_IPHC_M 0x08 /* Bit 12: Multicast compression */ +#define SIXLOWPAN_IPHC_DAC 0x04 /* Bit 13: Destination address compression */ +#define SIXLOWPAN_IPHC_DAM_MASK 0x03 /* Bits 14-15: Destination address mode */ +# define SIXLOWPAN_IPHC_DAM_128 0x00 /* 128-bits */ +# define SIXLOWPAN_IPHC_DAM_64 0x01 /* 64-bits */ +# define SIXLOWPAN_IPHC_DAM_16 0x02 /* 16-bits */ +# define SIXLOWPAN_IPHC_DAM_0 0x03 /* 0-bits */ -#define SIXLOWPAN_IPHC_SAM_BIT 4 -#define SIXLOWPAN_IPHC_DAM_BIT 0 +#define SIXLOWPAN_IPHC_SAM_BIT 4 +#define SIXLOWPAN_IPHC_DAM_BIT 0 /* Link local context number */ -#define SIXLOWPAN_IPHC_ADDR_CONTEXT_LL 0 +#define SIXLOWPAN_IPHC_ADDR_CONTEXT_LL 0 /* 16-bit multicast addresses compression */ -#define SIXLOWPAN_IPHC_MCAST_RANGE 0xa0 +#define SIXLOWPAN_IPHC_MCAST_RANGE 0xa0 /* NHC_EXT_HDR */ -#define SIXLOWPAN_NHC_MASK 0xf0 -#define SIXLOWPAN_NHC_EXT_HDR 0xe0 +#define SIXLOWPAN_NHC_MASK 0xf0 +#define SIXLOWPAN_NHC_EXT_HDR 0xe0 /* LOWPAN_UDP encoding (works together with IPHC) */ -#define SIXLOWPAN_NHC_UDP_MASK 0xf8 -#define SIXLOWPAN_NHC_UDP_ID 0xf0 -#define SIXLOWPAN_NHC_UDP_CHECKSUMC 0x04 -#define SIXLOWPAN_NHC_UDP_CHECKSUMI 0x00 +#define SIXLOWPAN_NHC_UDP_MASK 0xf8 +#define SIXLOWPAN_NHC_UDP_ID 0xf0 +#define SIXLOWPAN_NHC_UDP_CHECKSUMC 0x04 +#define SIXLOWPAN_NHC_UDP_CHECKSUMI 0x00 /* Values for port compression, _with checksum_ ie bit 5 set to 0 */ -#define SIXLOWPAN_NHC_UDP_CS_P_00 0xf0 /* All inline */ -#define SIXLOWPAN_NHC_UDP_CS_P_01 0xf1 /* Source 16bit inline, dest = 0xf0 + 8 bit inline */ -#define SIXLOWPAN_NHC_UDP_CS_P_10 0xf2 /* Source = 0xf0 + 8bit inline, dest = 16 bit inline */ -#define SIXLOWPAN_NHC_UDP_CS_P_11 0xf3 /* Source & dest = 0xf0b + 4bit inline */ +#define SIXLOWPAN_NHC_UDP_CS_P_00 0xf0 /* All inline */ +#define SIXLOWPAN_NHC_UDP_CS_P_01 0xf1 /* Source 16bit inline, dest = 0xf0 + 8 bit inline */ +#define SIXLOWPAN_NHC_UDP_CS_P_10 0xf2 /* Source = 0xf0 + 8bit inline, dest = 16 bit inline */ +#define SIXLOWPAN_NHC_UDP_CS_P_11 0xf3 /* Source & dest = 0xf0b + 4bit inline */ /* The 6lowpan "headers" length */ -#define SIXLOWPAN_IPV6_HDR_LEN 1 /* One byte */ -#define SIXLOWPAN_HC1_HDR_LEN 3 -#define SIXLOWPAN_HC1_HC_UDP_HDR_LEN 7 -#define SIXLOWPAN_FRAG1_HDR_LEN 4 -#define SIXLOWPAN_FRAGN_HDR_LEN 5 +#define SIXLOWPAN_IPV6_HDR_LEN 1 /* One byte */ +#define SIXLOWPAN_HC1_HDR_LEN 3 +#define SIXLOWPAN_HC1_HC_UDP_HDR_LEN 7 +#define SIXLOWPAN_FRAG1_HDR_LEN 4 +#define SIXLOWPAN_FRAGN_HDR_LEN 5 /* Address compressibility test macros **************************************/ @@ -227,7 +228,7 @@ #define SIXLOWPAN_IS_IID_16BIT_COMPRESSABLE(a) \ ((((a)[4]) == 0x0000) && (((a)[5]) == HTONS(0x00ff)) && \ - (((a)[6]) == 0xfe00)) + (((a)[6]) == HTONS(0xfe00))) /* Check whether the 9-bit group-id of the compressed multicast address is * known. It is true if the 9-bit group is the all nodes or all routers @@ -271,61 +272,6 @@ (a)[4] == 0 && (a)[5] == 0 && (a)[6] == 0 && \ (((a)[7] & HTONS(0xff00)) == 0x0000)) -/* Frame buffer helper macros ***********************************************/ -/* The IEEE802.15.4 MAC driver structures includes a list of IOB - * structures, i_framelist, containing frames to be sent by the driver or - * that were received by the driver. The IOB structure is defined in - * include/nuttx/drivers/iob.h. The length of data in the IOB is provided by - * the io_len field of the IOB structure. - * - * NOTE that IOBs must be configured such that CONFIG_IOB_BUFSIZE >= - * CONFIG_NET_6LOWPAN_FRAMELEN - * - * 1. On a TX poll, the IEEE802.15.4 MAC driver should provide its driver - * structure with i_framelist set to NULL. At the conclusion of the - * poll, if there are frames to be sent, they will have been added to - * the i_framelist. The non-empty frame list is the indication that - * there is data to be sent. - * - * The IEEE802.15.4 may use the FRAME_IOB_EMPTY() macro to determine - * if there there frames to be sent. If so, it should remove each - * frame from the frame list using the FRAME_IOB_REMOVE() macro and send - * it. That macro will return NULL when all of the frames have been - * sent. - * - * After sending each frame, the driver must return the IOB to the pool - * of free IOBs using the FROM_IOB_FREE() macro. - */ - - -#define FRAME_IOB_EMPTY(ieee) ((ieee)->i_framelist == NULL) -#define FRAME_IOB_REMOVE(ieee, iob) \ - do \ - { \ - (iob) = (ieee)->i_framelist; \ - (ieee)->i_framelist = (iob)->io_flink; \ - (iob)->io_flink = NULL; \ - } \ - while (0) -#define FRAME_IOB_FREE(iob) iob_free(iob) - -/* 2. When receiving data, the IEEE802.15.4 MAC driver should receive the - * frame data directly into the payload area of an IOB structure. That - * IOB structure may be obtained using the FRAME_IOB_ALLOC() macro. The - * single frame should be added to the frame list using FRAME_IOB_ADD() - * (it will be a list of length one) . The MAC driver should then inform - * the network of the by calling sixlowpan_input(). - */ - -#define FRAME_IOB_ALLOC() iob_alloc(false) -#define FRAME_IOB_ADD(ieee, iob) \ - do \ - { \ - (iob)->io_flink = (ieee)->i_framelist; \ - (ieee)->i_framelist = (iob); \ - } \ - while (0) - /**************************************************************************** * Public Types ****************************************************************************/ @@ -335,18 +281,21 @@ * difference is that fragmentation must be supported. * * The IEEE802.15.4 MAC does not use the d_buf packet buffer directly. - * Rather, it uses a list smaller frame buffers, i_framelist. + * Rather, it uses a list smaller frame buffers. * - * - The packet fragment data is provided to an IOB in the i_framelist - * buffer each time that the IEEE802.15.4 MAC needs to send more data. - * The length of the frame is provided in the io_len field of the IOB. + * - The packet fragment data is provided in an IOB in the via the + * i_req_data() interface method each time that the IEEE802.15.4 MAC + * needs to send more data. The length of the frame is provided in the + * io_len field of the IOB. * * In this case, the d_buf is not used at all and, if fact, may be * NULL. * * - Received frames are provided by IEEE802.15.4 MAC to the network - * via and IOB in i_framelist with length io_len for reassembly in - * d_buf; d_len will hold the size of the reassembled packet. + * via an IOB parameter in the sixlowpan_submit() interface. The + * length of the frawme is io_len and will be uncompressed and possibly + * reassembled in the d_buf; d_len will hold the size of the + * reassembled packet. * * In this case, a d_buf of size CONFIG_NET_6LOWPAN_MTU must be provided. * @@ -360,51 +309,42 @@ * this structure. In general, all fields must be set to NULL. In * addtion: * - * 1. i_panid must be set to identify the network. It may be set to 0xfff - * if the device is not associated. + * 1. On a TX poll, the IEEE802.15.4 MAC driver should provide its driver + * structure. During the course of the poll, the networking layer may + * generate outgoing frames. These frames will by provided to the MAC + * driver via the req_data() method. * - * 2. i_dsn must be set to a random value. After that, it will be managed - * by the network. + * After sending each frame through the radio, the MAC driver must + * return the frame to the pool of free IOBs using the iob_free(). * - * 3. On a TX poll, the IEEE802.15.4 MAC driver should provide its driver - * structure with i_framelist set to NULL. At the conclusion of the - * poll, if there are frames to be sent, they will have been added to - * the i_framelist. The non-empty frame list at the conclusion of the - * TX poll is the indication that is data to be sent. - * - * The IEEE802.15.4 may use the FRAME_IOB_EMPTY() macro to determine - * if there there frames to be sent. If so, it should remove each - * frame from the frame list using the FRAME_IOB_REMOVE() macro and send - * it. That macro will return NULL when all of the frames have been - * sent. - * - * After sending each frame, the driver must return the IOB to the pool - * of free IOBs using the FROM_IOB_FREE() macro. - * - * 4. When receiving data both buffers must be provided: + * 2. When receiving data both buffers must be provided: * * The IEEE802.15.4 MAC driver should receive the frame data directly - * into the payload area of an IOB structure. That IOB structure may be - * obtained using the FRAME_IOB_ALLOC() macro. The single frame should - * be added to the frame list using FRAME_IOB_ADD() (it will be a list of - * length one). + * into the payload area of an IOB frame structure. That IOB structure + * may be obtained using the iob_alloc() function. * * The larger dev.d_buf must have a size of at least the advertised MTU - * of the protocol, CONFIG_NET_6LOWPAN_MTU. If fragmentation is enabled, - * then the logical packet size may be significantly larger than the - * size of the frame buffer. The dev.d_buf is used for de-compressing - * each frame and reassembling any fragmented packets to create the full - * input packet that is provided to the application. + * of the protocol, CONFIG_NET_6LOWPAN_MTU, plus CONFIG_NET_GUARDSIZE. + * If fragmentation is enabled, then the logical packet size may be + * significantly larger than the size of the frame buffer. The dev.d_buf + * is used for de-compressing each frame and reassembling any fragmented + * packets to create the full input packet that is provided to the + * application. * * The MAC driver should then inform the network of the by calling - * sixlowpan_input(). + * sixlowpan_input(). That single frame (or, perhaps, list of frames) + * should be provided as second argument of that call. * - * Normally, the network will free the IOB and will nullify the frame - * list. But ss a complexity, the result of receiving a frame may be - * that the network may respond provide an outgoing frames in the - * frame list. + * The network will free the IOB by calling iob_free after it has + * processed the incoming frame. As a complexity, the result of + * receiving a frame may be that the network may respond provide an + * outgoing frames in the via a nested calle to the req_data() method. */ +struct ieee802154_frame_meta_s; /* Forward reference */ +struct ieee802154_data_ind_s; /* Forward reference */ +struct iob_s; /* Forward reference */ + struct ieee802154_driver_s { /* This definitiona must appear first in the structure definition to @@ -415,43 +355,22 @@ struct ieee802154_driver_s /* IEEE802.15.4 MAC-specific definitions follow. */ - /* The i_framelist is used to hold a outgoing frames contained in IOB - * structures. When the IEEE802.15.4 device polls for new TX data, the - * outgoing frame(s) containing the packet fragments are placed in IOBs - * and queued in i_framelist. + /* The msdu_handle is basically an id for the frame. The standard just + * says that the next highest layer should determine it. It is used in + * three places * - * The i_framelist is similary used to hold incoming frames in IOB - * structures. The IEEE802.15.4 MAC driver must receive frames in an IOB, - * place the IOB in the i_framelist, and call sixlowpan_input(). + * 1. When you do that data request + * 2. When the transmission is complete, the conf_data is called with + * that handle so that the user can be notified of the frames success/ + * failure + * 3. For a req_purge, to basically "cancel" the transaction. This is + * often particularly useful on a coordinator that has indirect data + * waiting to be requested from another device * - * The IEEE802.15.4 MAC driver design may be concurrently sending and - * requesting new frames using lists of IOBs. That IOB frame buffer - * management must be managed by the IEEE802.15.4 MAC driver. + * Here is a simple frame counter. */ - FAR struct iob_s *i_framelist; - - /* Driver Configuration ***************************************************/ - /* i_panid. The PAN ID is 16-bit number that identifies the network. It - * must be unique to differentiate a network. All the nodes in the same - * network should have the same PAN ID. This value must be provided to - * the network from the IEEE802.15.4 MAC driver. - * - * If this value is 0xffff, the device is not associated. - */ - - uint16_t i_panid; - - /* i_dsn. The sequence number in the range 0x00-0xff added to the - * transmitted data or MAC command frame. The default is a random value - * within that range. - * - * This field must be initialized to a random number by the IEEE802.15.4 - * MAC driver. It sill be subsequently incremented on each frame by the - * network logic. - */ - - uint8_t i_dsn; + uint8_t i_msdu_handle; #if CONFIG_NET_6LOWPAN_FRAG /* Fragmentation Support *************************************************/ @@ -502,7 +421,7 @@ struct ieee802154_driver_s /* The source MAC address of the fragments being merged */ - struct rimeaddr_s i_fragsrc; + struct sixlowpan_tagaddr_s i_fragsrc; /* That time at which reassembly was started. If the elapsed time * exceeds CONFIG_NET_6LOWPAN_MAXAGE, then the reassembly will @@ -511,6 +430,47 @@ struct ieee802154_driver_s systime_t i_time; #endif /* CONFIG_NET_6LOWPAN_FRAG */ + + /* MAC network driver callback functions **********************************/ + /************************************************************************** + * Name: mac802154_get_mhrlen + * + * Description: + * Calculate the MAC header length given the frame meta-data. + * + * Input parameters: + * netdev - The networkd device that will mediate the MAC interface + * meta - Meta data needed to recreate the MAC header + * + * Returned Value: + * A non-negative MAC headeer length is returned on success; a negated + * errno value is returned on any failure. + * + **************************************************************************/ + + CODE int (*i_get_mhrlen)(FAR struct ieee802154_driver_s *netdev, + FAR const struct ieee802154_frame_meta_s *meta); + + /************************************************************************** + * Name: mac802154_req_data + * + * Description: + * Requests the transfer of a list of frames to the MAC. + * + * Input parameters: + * netdev - The networkd device that will mediate the MAC interface + * meta - Meta data needed to recreate the MAC header + * framelist - Head of a list of frames to be transferred. + * + * Returned Value: + * Zero (OK) returned on success; a negated errno value is returned on + * any failure. + * + **************************************************************************/ + + CODE int (*i_req_data)(FAR struct ieee802154_driver_s *netdev, + FAR const struct ieee802154_frame_meta_s *meta, + FAR struct iob_s *framelist); }; /**************************************************************************** @@ -523,25 +483,32 @@ struct ieee802154_driver_s * Description: * Process an incoming 6loWPAN frame. * - * This function is called when the device driver has received a 6loWPAN - * frame from the network. The frame from the device driver must be - * provided in a IOB present in the i_framelist: The frame data is in the - * IOB io_data[] buffer and the length of the frame is in the IOB io_len - * field. Only a single IOB is expected in the i_framelist. This incoming - * data will be processed one frame at a time. + * This function is called when the device driver has received an + * IEEE802.15.4 frame from the network. The frame from the device + * driver must be provided in by the IOB frame argument of the + * function call: * - * An non-NULL d_buf of size CONFIG_NET_6LOWPAN_MTU must also be provided. - * The frame will be decompressed and placed in the d_buf. Fragmented - * packets will also be reassembled in the d_buf as they are received - * (meaning for the driver, that two packet buffers are required: One for - * reassembly of RX packets and one used for TX polling). + * - The frame data is in the IOB io_data[] buffer, + * - The length of the frame is in the IOB io_len field, and + * - The offset past the IEEE802.15.4 MAC header is provided in the + * io_offset field. * - * After each frame is processed into d_buf, the IOB is removed and - * deallocated. i_framelist will be nullified. If reassembly is - * incomplete, this function will return to called with i_framelist - * equal to NULL. The partially reassembled packet must be preserved by - * the IEEE802.15.4 MAC and provided again when the next frame is - * received. + * The frame argument may refer to a single frame (a list of length one) + * or may it be the head of a list of multiple frames. + * + * - The io_flink field points to the next frame in the list (if enable) + * - The last frame in the list will have io_flink == NULL. + * + * An non-NULL d_buf of size CONFIG_NET_6LOWPAN_MTU + CONFIG_NET_GUARDSIZE + * must also be provided. The frame will be decompressed and placed in + * the d_buf. Fragmented packets will also be reassembled in the d_buf as + * they are received (meaning for the driver, that two packet buffers are + * required: One for reassembly of RX packets and one used for TX polling). + * + * After each frame is processed into d_buf, the IOB is deallocated. If + * reassembly is incomplete, the partially reassembled packet must be + * preserved by the IEEE802.15.4 MAC network drvier sand provided again + * when the next frame is received. * * When the packet in the d_buf is fully reassembled, it will be provided * to the network as with any other received packet. d_len will be set @@ -549,28 +516,31 @@ struct ieee802154_driver_s * * After the network processes the packet, d_len will be set to zero. * Network logic may also decide to send a response to the packet. In - * that case, the outgoing network packet will be placed in d_buf the - * d_buf and d_len will be set to a non-zero value. That case is handled - * by this function. + * that case, the outgoing network packet will be placed in d_buf and + * d_len will be set to a non-zero value. That case is handled by this + * function. * * If that case occurs, the packet will be converted to a list of - * compressed and possibly fragmented frames in i_framelist as with other - * TX operations. - * - * So from the standpoint of the IEEE802.15.4 MAC driver, there are two - * possible results: (1) i_framelist is NULL meaning that the frame - * was fully processed and freed, or (2) i_framelist is non-NULL meaning - * that there are outgoing frame(s) to be sent. + * compressed and possibly fragmented frames and provided to the MAC + * network driver via the req_data() method as with other TX operations. * * Input Parameters: - * ieee - The IEEE802.15.4 MAC network driver interface. + * ieee - The IEEE802.15.4 MAC network driver interface. + * framelist - The head of an incoming list of frames. Normally this + * would be a single frame. A list may be provided if + * appropriate, however. + * ind - Meta data characterizing the received packet. If there are + * multilple frames in the list, this meta data must apply to + * all of the frames! * * Returned Value: * Ok is returned on success; Othewise a negated errno value is returned. * ****************************************************************************/ -int sixlowpan_input(FAR struct ieee802154_driver_s *ieee); +int sixlowpan_input(FAR struct ieee802154_driver_s *ieee, + FAR struct iob_s *framelist, + FAR const struct ieee802154_data_ind_s *ind); #endif /* CONFIG_NET_6LOWPAN */ #endif /* __INCLUDE_NUTTX_NET_SIXLOWPAN_H */ diff --git a/include/nuttx/wireless/ieee802154/at86rf23x.h b/include/nuttx/wireless/ieee802154/at86rf23x.h new file mode 100644 index 0000000000..2cdf6218cf --- /dev/null +++ b/include/nuttx/wireless/ieee802154/at86rf23x.h @@ -0,0 +1,114 @@ +/**************************************************************************** + * include/nuttx/ieee802154/at86rf23x.h + * + * Copyright (C) 2014-2015 Gregory Nutt. All rights reserved. + * Copyright (C) 2014-2015 Sebastien Lorquet. All rights reserved. + * Author: Sebastien Lorquet + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +#ifndef __INCLUDE_NUTTX_IEEE802154_AT86RF23X_H +#define __INCLUDE_NUTTX_IEEE802154_AT86RF23X_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include + +/**************************************************************************** + * Public Types + ****************************************************************************/ + +/* The at86rf23x provides interrupts to the MCU via a GPIO pin. The + * following structure provides an MCU-independent mechanixm for controlling + * the at86rf23x GPIO interrupt. + * + * The at86rf23x interrupt is an active low, *level* interrupt. From Datasheet: + * "Note 1: The INTEDGE polarity defaults to: 0 = Falling Edge. Ensure that + * the interrupt polarity matches the interrupt pin polarity of the host + * microcontroller. + * "Note 2: The INT pin will remain high or low, depending on INTEDGE polarity + * setting, until INTSTAT register is read." + */ + +struct at86rf23x_lower_s +{ + int (*attach)(FAR const struct at86rf23x_lower_s *lower, xcpt_t handler, + FAR void *arg); + void (*enable)(FAR const struct at86rf23x_lower_s *lower, bool state); + void (*slptr)(FAR const struct at86rf23x_lower_s *lower, bool state); + void (*reset)(FAR const struct at86rf23x_lower_s *lower, bool state); +}; + +#ifdef __cplusplus +#define EXTERN extern "C" +extern "C" +{ +#else +#define EXTERN extern +#endif + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +/**************************************************************************** + * Function: at86rf23x_init + * + * Description: + * Initialize the IEEE802.15.4 driver. The at86rf23x device is assumed to be + * in the post-reset state upon entry to this function. + * + * Parameters: + * spi - A reference to the platform's SPI driver for the at86rf23x + * lower - The MCU-specific interrupt used to control low-level MCU + * functions (i.e., at86rf23x GPIO interrupts). + * devno - If more than one at86rf23x is supported, then this is the + * zero based number that identifies the at86rf23x; + * + * Returned Value: + * OK on success; Negated errno on failure. + * + * Assumptions: + * + ****************************************************************************/ + +FAR struct ieee802154_radio_s * + at86rf23x_init(FAR struct spi_dev_s *spi, + FAR const struct at86rf23x_lower_s *lower); + +#undef EXTERN +#ifdef __cplusplus +} +#endif + +#endif /* __INCLUDE_NUTTX_IEEE802154__AT86RF23X_H */ diff --git a/include/nuttx/wireless/ieee802154/ieee802154.h b/include/nuttx/wireless/ieee802154/ieee802154_ioctl.h similarity index 56% rename from include/nuttx/wireless/ieee802154/ieee802154.h rename to include/nuttx/wireless/ieee802154/ieee802154_ioctl.h index 0211940414..5f14f2e2c6 100644 --- a/include/nuttx/wireless/ieee802154/ieee802154.h +++ b/include/nuttx/wireless/ieee802154/ieee802154_ioctl.h @@ -1,11 +1,9 @@ -/**************************************************************************** - * include/nuttx/net/ieee802154.h +/************************************************************************************ + * include/nuttx/wireless/ieee802154/ieee802154_ioctl.h + * IEEE802.15.4 character driver IOCTL commands * - * Copyright (C) 2016 Gregory Nutt. All rights reserved. - * Author: Gregory Nutt - * - * Includes some definitions that a compatible with the LGPL GNU C Library - * header file of the same name. + * Copyright (C) 2017 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -34,29 +32,61 @@ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. * - ****************************************************************************/ + ************************************************************************************/ -#ifndef __INCLUDE_NUTTX_WIRELESS_IEEE802154_IEEE802154_H -#define __INCLUDE_NUTTX_WIRELESS_IEEE802154_IEEE802154_H +/* This file includes common definitions to be used in all wireless character drivers + * (when applicable). + */ -/**************************************************************************** +#ifndef __INCLUDE_NUTTX_WIRELESS_IEEE802154_IEEE802154_IOCTL_H +#define __INCLUDE_NUTTX_WIRELESS_IEEE802154_IEEE802154_IOCTL_H + +/************************************************************************************ * Included Files - ****************************************************************************/ + ************************************************************************************/ #include +#include -#include +#include -/**************************************************************************** - * Public Type Definitions - ****************************************************************************/ +#ifdef CONFIG_WIRELESS_IEEE802154 -/**************************************************************************** - * Public Data - ****************************************************************************/ +/************************************************************************************ + * Pre-processor Definitions + ************************************************************************************/ -/**************************************************************************** - * Public Function Prototypes - ****************************************************************************/ +/* IEEE 802.15.4 Radio Character Driver IOCTL commands ******************************/ +/* None defined */ -#endif /* __INCLUDE_NUTTX_WIRELESS_IEEE802154_IEEE802154_H */ +/* IEEE 802.15.4 MAC Character Driver IOCTL commands ********************************/ + + +#define MAC802154IOC_MCPS_REGISTER _WLCIOC(IEEE802154_FIRST) +#define MAC802154IOC_MLME_REGISTER _WLCIOC(IEEE802154_FIRST+1) + +/************************************************************************************ + * Public Types + ************************************************************************************/ + +struct mac802154dev_notify_s +{ + uint8_t mn_signo; /* Signal number to use in the notification */ +}; + +struct mac802154dev_txframe_s +{ + struct ieee802154_frame_meta_s meta; + FAR uint8_t *payload; + uint16_t length; +}; + +struct mac802154dev_rxframe_s +{ + struct ieee802154_data_ind_s meta; + uint8_t payload[IEEE802154_MAX_MAC_PAYLOAD_SIZE]; + uint16_t length; +}; + +#endif /* CONFIG_WIRELESS_IEEE802154 */ +#endif /* __INCLUDE_NUTTX_WIRELESS_IEEE802154_IEEE802154_IOCTL_H */ diff --git a/include/nuttx/wireless/ieee802154/ieee802154_mac.h b/include/nuttx/wireless/ieee802154/ieee802154_mac.h new file mode 100644 index 0000000000..2c6a846af7 --- /dev/null +++ b/include/nuttx/wireless/ieee802154/ieee802154_mac.h @@ -0,0 +1,1566 @@ +/**************************************************************************** + * include/nuttx/wireless/ieee802154/ieee802154_mac.h + * + * Copyright (C) 2016 Sebastien Lorquet. All rights reserved. + * Copyright (C) 2017 Verge Inc. All rights reserved. + * + * Author: Sebastien Lorquet + * Author: Anthony Merlino + * + * The naming and comments for various fields are taken directly + * from the IEEE 802.15.4 2011 standard. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +#ifndef __INCLUDE_NUTTX_WIRELESS_IEEE802154_IEEE802154_MAC_H +#define __INCLUDE_NUTTX_WIRELESS_IEEE802154_IEEE802154_MAC_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include + +#ifdef CONFIG_NET_6LOWPAN +# include +#endif + +#include + +/**************************************************************************** + * Pre-Processor Definitions + ****************************************************************************/ + +/* Configuration ************************************************************/ +/* None at the moment */ + +/* IEEE 802.15.4 MAC Character Driver IOCTL Commands ************************/ + +/* The IEEE 802.15.4 standard specifies a MLME Service Access Point (SAP) + * including a series of primitives that are used as an interface between + * the MLME and the next highest layer. There are 4 types of primitives: + * + * - Request + * - Indication + * - Response + * - Confirm + * + * Of these, Request and Response primitives are sent from the next highest layer + * to the MLME. Indication and Confirm primitives are used to notify the next + * highest layer of changes or actions that have taken place. + * + * The MAC802154 character driver exposed here provides IOCTL hooks for all + * Request and Response primitives. + */ + +#define MAC802154IOC_MLME_ASSOC_REQUEST _MAC802154IOC(0x0003) +#define MAC802154IOC_MLME_ASSOC_RESPONSE _MAC802154IOC(0x0004) +#define MAC802154IOC_MLME_DISASSOC_REQUEST _MAC802154IOC(0x0005) +#define MAC802154IOC_MLME_GET_REQUEST _MAC802154IOC(0x0006) +#define MAC802154IOC_MLME_GTS_REQUEST _MAC802154IOC(0x0007) +#define MAC802154IOC_MLME_ORPHAN_RESPONSE _MAC802154IOC(0x0008) +#define MAC802154IOC_MLME_RESET_REQUEST _MAC802154IOC(0x0009) +#define MAC802154IOC_MLME_RXENABLE_REQUEST _MAC802154IOC(0x000A) +#define MAC802154IOC_MLME_SCAN_REQUEST _MAC802154IOC(0x000B) +#define MAC802154IOC_MLME_SET_REQUEST _MAC802154IOC(0x000C) +#define MAC802154IOC_MLME_START_REQUEST _MAC802154IOC(0x000D) +#define MAC802154IOC_MLME_SYNC_REQUEST _MAC802154IOC(0x000E) +#define MAC802154IOC_MLME_POLL_REQUEST _MAC802154IOC(0x000F) +#define MAC802154IOC_MLME_DPS_REQUEST _MAC802154IOC(0x0010) +#define MAC802154IOC_MLME_SOUNDING_REQUEST _MAC802154IOC(0x0011) +#define MAC802154IOC_MLME_CALIBRATE_REQUEST _MAC802154IOC(0x0012) + +/* IEEE 802.15.4 MAC Interface **********************************************/ + +/* Frame Type */ + +#define IEEE802154_FRAME_BEACON 0x00 +#define IEEE802154_FRAME_DATA 0x01 +#define IEEE802154_FRAME_ACK 0x02 +#define IEEE802154_FRAME_COMMAND 0x03 + +/* MAC commands */ + +#define IEEE802154_CMD_ASSOC_REQ 0x01 +#define IEEE802154_CMD_ASSOC_RESP 0x02 +#define IEEE802154_CMD_DISASSOC_NOT 0x03 +#define IEEE802154_CMD_DATA_REQ 0x04 +#define IEEE802154_CMD_PANID_CONF_NOT 0x05 +#define IEEE802154_CMD_ORPHAN_NOT 0x06 +#define IEEE802154_CMD_BEACON_REQ 0x07 +#define IEEE802154_CMD_COORD_REALIGN 0x08 +#define IEEE802154_CMD_GTS_REQ 0x09 + +/* Some addresses */ + +#define IEEE802154_PAN_UNSPEC (uint16_t)0xFFFF +#define IEEE802154_SADDR_UNSPEC (uint16_t)0xFFFF +#define IEEE802154_SADDR_BCAST (uint16_t)0xFFFE +#define IEEE802154_EADDR_UNSPEC (uint8_t*)"\xff\xff\xff\xff\xff\xff\xff\xff" + +/* Frame control field masks, 2 bytes + * Seee IEEE 802.15.4/2011 5.2.1.1 page 57 + */ + +#define IEEE802154_FRAMECTRL_FTYPE 0x0007 /* Frame type, bits 0-2 */ +#define IEEE802154_FRAMECTRL_SEC 0x0008 /* Security Enabled, bit 3 */ +#define IEEE802154_FRAMECTRL_PEND 0x0010 /* Frame pending, bit 4 */ +#define IEEE802154_FRAMECTRL_ACKREQ 0x0020 /* Acknowledge request, bit 5 */ +#define IEEE802154_FRAMECTRL_PANIDCOMP 0x0040 /* PAN ID Compression, bit 6 */ +#define IEEE802154_FRAMECTRL_DADDR 0x0C00 /* Dest addressing mode, bits 10-11 */ +#define IEEE802154_FRAMECTRL_VERSION 0x3000 /* Source addressing mode, bits 12-13 */ +#define IEEE802154_FRAMECTRL_SADDR 0xC000 /* Source addressing mode, bits 14-15 */ + +#define IEEE802154_FRAMECTRL_SHIFT_FTYPE 0 /* Frame type, bits 0-2 */ +#define IEEE802154_FRAMECTRL_SHIFT_SEC 3 /* Security Enabled, bit 3 */ +#define IEEE802154_FRAMECTRL_SHIFT_PEND 4 /* Frame pending, bit 4 */ +#define IEEE802154_FRAMECTRL_SHIFT_ACKREQ 5 /* Acknowledge request, bit 5 */ +#define IEEE802154_FRAMECTRL_SHIFT_PANIDCOMP 6 /* PAN ID Compression, bit 6 */ +#define IEEE802154_FRAMECTRL_SHIFT_DADDR 10 /* Dest addressing mode, bits 10-11 */ +#define IEEE802154_FRAMECTRL_SHIFT_VERSION 12 /* Source addressing mode, bits 12-13 */ +#define IEEE802154_FRAMECTRL_SHIFT_SADDR 14 /* Source addressing mode, bits 14-15 */ + +/* IEEE 802.15.4 PHY constants */ + +#define IEEE802154_MAX_PHY_PACKET_SIZE 127 +#define IEEE802154_TURN_AROUND_TIME 12 /*symbol periods*/ + +/* IEEE 802.15.4 MAC constants */ + +#define IEEE802154_BASE_SLOT_DURATION 60 +#define IEEE802154_NUM_SUPERFRAME_SLOTS 16 + +#define IEEE802154_BASE_SUPERFRAME_DURATION \ + (IEEE802154_BASE_SLOT_DURATION * IEEE802154_NUM_SUPERFRAME_SLOTS) + +#define IEEE802154_GTS_DESC_PERSISTENCE_TIME 4 +#define IEEE802154_MAX_BEACON_OVERHEAD 75 + +#define IEEE802154_MAX_BEACON_PAYLOAD_LEN \ + (IEEE802154_MAX_PHY_PACKET_SIZE - IEEE802154_MAX_BEACON_OVERHEAD) + +#define IEEE802154_MAX_LOST_BEACONS 4 +#define IEEE802154_MIN_MPDU_OVERHEAD 9 +#define IEEE802154_MAX_UNSEC_MHR_OVERHEAD 23 +#define IEEE802154_MFR_LENGTH 2 + +#define IEEE802154_MAX_MPDU_UNSEC_OVERHEAD \ + (IEEE802154_MAX_UNSEC_MHR_OVERHEAD + IEEE802154_MFR_LENGTH) + + +#define IEEE802154_MAX_SAFE_MAC_PAYLOAD_SIZE \ + (IEEE802154_MAX_PHY_PACKET_SIZE - IEEE802154_MAX_MPDU_UNSEC_OVERHEAD) + +#define IEEE802154_MAX_MAC_PAYLOAD_SIZE \ + (IEEE802154_MAX_PHY_PACKET_SIZE - IEEE802154_MIN_MPDU_OVERHEAD) + +#define IEEE802154_MAX_SIFS_FRAME_SIZE 18 +#define IEEE802154_MIN_CAP_LENGTH 440 +#define IEEE802154_UNIT_BACKOFF_PERIOD 20 + +/* IEEE 802.15.4 MAC PIB Attribut Defaults */ + +/* Definitions used by IOCTL calls */ + +#define MAX_ORPHAN_ADDR 32 /* REVISIT */ + +// TODO: Add macros + +/**************************************************************************** + * Public Types + ****************************************************************************/ + +/* IEEE 802.15.4 MAC status codes */ + +enum ieee802154_status_e +{ + IEEE802154_STATUS_SUCCESS = 0, + IEEE802154_STATUS_BEACON_LOSS = 0xE0, + IEEE802154_STATUS_CHANNEL_ACCESS_FAILURE, + IEEE802154_STATUS_DENIED, + IEEE802154_STATUS_DISABLE_TRX_FAILURE, + IEEE802154_STATUS_FAILED_SECURITY_CHECK, + IEEE802154_STATUS_FRAME_TOO_LONG, + IEEE802154_STATUS_INVALID_GTS, + IEEE802154_STATUS_INVALID_HANDLE, + IEEE802154_STATUS_INVALID_PARAMETER, + IEEE802154_STATUS_NO_ACK, + IEEE802154_STATUS_NO_BEACON, + IEEE802154_STATUS_NO_DATA, + IEEE802154_STATUS_NO_SHORT_ADDRESS, + IEEE802154_STATUS_OUT_OF_CAP, + IEEE802154_STATUS_PAN_ID_CONFLICT, + IEEE802154_STATUS_REALIGNMENT, + IEEE802154_STATUS_TRANSACTION_EXPIRED, + IEEE802154_STATUS_TRANSACTION_OVERFLOW, + IEEE802154_STATUS_TX_ACTIVE, + IEEE802154_STATUS_UNAVAILABLE_KEY, + IEEE802154_STATUS_UNSUPPORTED_ATTRIBUTE, + IEEE802154_STATUS_FAILED /* This value is not outlined in the standard. It is + * a catch-all for any failures that are not outlined + * in the standard */ +}; + +/* IEEE 802.15.4 PHY/MAC PIB attributes IDs */ + +enum ieee802154_pib_attr_e +{ + /* PHY PIB Attributes */ + + IEEE802154_PIB_PHY_CURRENT_CHANNEL = 0x00, + IEEE802154_PIB_PHY_CHANNELS_SUPPORTED, + IEEE802154_PIB_PHY_TX_POWER_TOLERANCE, + IEEE802154_PIB_PHY_TX_POWER, + IEEE802154_PIB_PHY_CCA_MODE, + IEEE802154_PIB_PHY_CURRENT_PAGE, + IEEE802154_PIB_PHY_MAX_FRAME_DURATION, + IEEE802154_PIB_PHY_SHR_DURATION, + IEEE802154_PIB_PHY_SYM_PER_OCTET, + IEEE802154_PIB_PHY_PREAMBLE_SYM_LEN, + IEEE802154_PIB_PHY_UWB_DATARATES_SUP, + IEEE802154_PIB_PHY_CSS_LOW_DATARATE_SUP, + IEEE802154_PIB_PHY_UWB_COU_PULSES_SUP, + IEEE802154_PIB_PHY_UWB_CS_PULSES_SUP, + IEEE802154_PIB_PHY_UWB_LCP_PULSES_SUP, + IEEE802154_PIB_PHY_UWB_CURR_PULSE_SHAPE, + IEEE802154_PIB_PHY_UWB_COU_PULSE, + IEEE802154_PIB_PHY_UWB_CS_PULSE, + IEEE802154_PIB_PHY_UWB_LCP_WEIGHT1, + IEEE802154_PIB_PHY_UWB_LCP_WEIGHT2, + IEEE802154_PIB_PHY_UWB_LCP_WEIGHT3, + IEEE802154_PIB_PHY_UWB_LCP_WEIGHT4, + IEEE802154_PIB_PHY_UWB_LCP_DELAY2, + IEEE802154_PIB_PHY_UWB_LCP_DELAY3, + IEEE802154_PIB_PHY_UWB_LCP_DELAY4, + IEEE802154_PIB_PHY_RANGING, + IEEE802154_PIB_PHY_RANGING_CRYSTAL_OFFSET, + IEEE802154_PIB_PHY_RANGING_DPS, + IEEE802154_PIB_PHY_CURRENT_CODE, + IEEE802154_PIB_PHY_NATIVE_PRF, + IEEE802154_PIB_PHY_UWB_SCAN_BINS_PER_CHAN, + IEEE802154_PIB_PHY_UWB_INS_PREAMBLE_INTERVAL, + IEEE802154_PIB_PHY_UWB_TX_RMARKER, + IEEE802154_PIB_PHY_UWB_RX_RMARKER, + IEEE802154_PIB_PHY_RFRAME_PROC_TIME, + IEEE802154_PIB_PHY_CCA_DURATION, + + /* MAC PIB Attributes */ + + IEEE802154_PIB_MAC_EXTENDED_ADDR = 0x40, + IEEE802154_PIB_MAC_ACK_WAIT_DUR, + IEEE802154_PIB_MAC_ASSOCIATED_PANCOORD, + IEEE802154_PIB_MAC_ASSOCIATION_PERMIT, + IEEE802154_PIB_MAC_AUTO_REQUEST, + IEEE802154_PIB_MAC_BATT_LIFE_EXT, + IEEE802154_PIB_MAC_BATT_LIFE_EXT_PERIODS, + IEEE802154_PIB_MAC_BEACON_PAYLOAD, + IEEE802154_PIB_MAC_BEACON_PAYLOAD_LEN, + IEEE802154_PIB_MAC_BEACON_ORDER, + IEEE802154_PIB_MAC_BEACON_TX_TIME, + IEEE802154_PIB_MAC_BSN, + IEEE802154_PIB_MAC_COORD_EXT_ADDR, + IEEE802154_PIB_MAC_COORD_SHORT_ADDR, + IEEE802154_PIB_MAC_DSN, + IEEE802154_PIB_MAC_GTS_PERMIT, + IEEE802154_PIB_MAC_MAX_BE, + IEEE802154_PIB_MAC_MAX_CSMA_BACKOFFS, + IEEE802154_PIB_MAC_FRAME_TOTAL_WAIT_TIME, + IEEE802154_PIB_MAC_MAX_FRAME_RETRIES, + IEEE802154_PIB_MAC_MIN_BE, + IEEE802154_PIB_MAC_LIFS_PERIOD, + IEEE802154_PIB_MAC_SIFS_PERIOD, + IEEE802154_PIB_MAC_PAN_ID, + IEEE802154_PIB_MAC_PROMISCUOUS_MODE, + IEEE802154_PIB_MAC_RANGING_SUPPORT, + IEEE802154_PIB_MAC_RESPONSE_WAIT_TIME, + IEEE802154_PIB_MAC_RX_ON_WHEN_IDLE, + IEEE802154_PIB_MAC_SECURITY_ENABLED, + IEEE802154_PIB_MAC_SHORT_ADDRESS, + IEEE802154_PIB_MAC_SUPERFRAME_ORDER, + IEEE802154_PIB_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, + + /* 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, +}; + +#define IEEE802154_EADDR_LEN 8 + +/* IEEE 802.15.4 Device address + * The addresses in ieee802154 have several formats: + * No address : [none] + * Short address + PAN id : PPPP/SSSS + * Extended address + PAN id : PPPP/LLLLLLLLLLLLLLLL + */ + +enum ieee802154_addr_mode_e +{ + IEEE802154_ADDRMODE_NONE = 0, + IEEE802154_ADDRMODE_SHORT = 2, + IEEE802154_ADDRMODE_EXTENDED +}; + +struct ieee802154_addr_s +{ + /* Address mode. Short or Extended */ + + enum ieee802154_addr_mode_e mode; + + uint16_t panid; /* PAN identifier, can be + * IEEE802154_PAN_UNSPEC */ + uint16_t saddr; /* short address */ + uint8_t eaddr[IEEE802154_EADDR_LEN]; /* extended address */ +}; + +#define IEEE802154_ADDRSTRLEN 22 /* (2*2+1+8*2, PPPP/EEEEEEEEEEEEEEEE) */ + +#ifdef CONFIG_IEEE802154_SECURITY +struct ieee802154_security_s +{ + uint8_t level; /* Security level to be used */ + uint8_t key_id_mode; /* Mode used to identify the key to be used */ + uint8_t key_source[8]; /* Originator of the key to be used */ + uint8_t key_index; /* Index of the key to be used */ +}; +#endif + +#ifdef CONFIG_IEEE802154_UWB +enum ieee802154_uwbprf_e +{ + IEEE802154_UWBPRF_OFF = 0, + IEEE802154_UWBPRF_4M, + IEEE802154_UWBPRF_16M, + IEEE802154_UWBPRF_64M +}; + +enum ieee802154_uwb_datarate_e +{ + IEEE802154_UWB_DATARATE_0 = 0, + IEEE802154_UWB_DATARATE_16, + IEEE802154_UWB_DATARATE_64, + IEEE802154_UWB_DATARATE_1024, + IEEE802154_UWB_DATARATE_4096 +}; +#endif + +enum ieee802154_ranging_e +{ + IEEE802154_NON_RANGING = 0, + IEEE802154_ALL_RANGING, + IEEE802154_PHY_HEADER_ONLY +}; + +struct ieee802154_capability_info_s +{ + uint8_t reserved_0 : 1; /* Reserved */ + uint8_t device_type : 1; /* 0=RFD, 1=FFD */ + uint8_t power_source : 1; /* 1=AC, 0=Other */ + uint8_t rx_on_idle : 1; /* 0=Receiver off when idle + * 1=Receiver on when idle */ + uint8_t reserved_45 : 2; /* Reserved */ + uint8_t security : 1; /* 0=disabled, 1=enabled */ + uint8_t allocate_addr : 1; /* 1=Coordinator allocates short address + * 0=otherwise */ +}; + +struct ieee802154_superframe_spec_s +{ + uint16_t beacon_order : 4; /* Transmission interval of beacon */ + uint16_t superframe_order : 4; /* Length of superframe */ + uint16_t final_cap_slot : 4; /* Last slot utilized by CAP */ + uint16_t ble : 1; /* Battery Life Extension (BLE) */ + uint16_t reserved : 1; /* Reserved bit */ + uint16_t pan_coordinator : 1; /* 1 if beacon sent by pan coordinator */ + uint16_t assoc_permit : 1; /* 1 if coordinator is accepting associaton */ +}; + +struct ieee802154_pan_desc_s +{ + /* The coordinator address of the received beacon frame */ + + struct ieee802154_addr_s coord_addr; + + uint8_t channel; /* current channel occupied by the network */ + uint8_t channel_page; /* current channel page occupied by the network */ + + /* The superframe specifications received in the beacon frame */ + + struct ieee802154_superframe_spec_s superframe_spec; + + uint8_t gts_permit; /* 0=No GTS requests allowed + * 1=GTS request allowed */ + uint8_t lqi; /* Link Quality Indication of the beacon */ + uint32_t timestamp; /* Time at which the beacon frame was received + * in symbols */ +}; + +struct ieee802154_pend_addr_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; + struct ieee802154_addr_s addr[7]; /* Array of at most 7 addresses */ +}; + +#ifdef CONFIG_IEEE802154_RANGING +#define IEEE802154_TXDESC_FIELDS \ + uint8_t handle; \ + uint32_t timestamp; \ + uint8_t status; +#else +#define IEEE802154_TXDESC_FIELDS \ + uint8_t handle; \ + uint32_t timestamp; \ + uint8_t status; + bool rng_rcvd; \ + uint32_t rng_counter_start; \ + uint32_t rng_counter_stop; \ + uint32_t rng_tracking_interval; \ + uint32_t rng_offset;\ + uint8_t rng_fom; +#endif + +struct ieee802154_txdesc_s +{ + IEEE802154_TXDESC_FIELDS + + /* TODO: Add slotting information for GTS transactions */ +}; + +struct ieee802154_cca_s +{ + uint8_t use_ed : 1; /* CCA using ED */ + uint8_t use_cs : 1; /* CCA using carrier sense */ + uint8_t edth; /* Energy detection threshold for CCA */ + uint8_t csth; /* Carrier sense threshold for CCA */ +}; + +/* Primitive Support Types ***************************************************/ + +union ieee802154_macattr_u +{ + uint8_t eaddr[IEEE802154_EADDR_LEN]; + uint16_t saddr; + uint16_t panid; + + uint8_t coord_eaddr[IEEE802154_EADDR_LEN]; + uint16_t coord_saddr; + + bool is_assoc; + bool assoc_permit; + bool auto_req; + bool batt_life_ext; + bool gts_permit; + bool promisc_mode; + bool rng_support; + bool resp_wait_time; + bool rxonidle; + bool sec_enabled; + bool timestamp_support; + + uint32_t ack_wait_dur; + uint8_t batt_life_ext_periods; + uint8_t max_csma_backoffs : 3; + uint8_t max_be : 4; + uint8_t min_be : 4; + uint32_t max_frame_wait_time; + uint8_t max_retries; + uint8_t lifs_period; + uint8_t sifs_period; + uint32_t sync_symb_offset : 12; + uint16_t trans_persist_time; + uint32_t tx_ctrl_active_dur; + uint32_t tx_ctrl_pause_dur; + uint32_t tx_total_dur; + + uint8_t beacon_payload[IEEE802154_PIB_MAC_BEACON_PAYLOAD_LEN]; + uint8_t beacon_payload_len; + uint8_t beacon_order; + uint32_t beacon_tx_time : 24; + + uint8_t superframe_order; + + uint8_t bsn; + uint8_t dsn; +}; + +union ieee802154_phyattr_u +{ + uint8_t channel; + int32_t txpwr + /* TODO: Fill this out as we implement supported get/set commands */ +}; + +union ieee802154_secattr_u +{ + /* TODO: Fill this out as we implement supported get/set commands */ +}; + +union ieee802154_attr_val_u +{ + union ieee802154_macattr_u mac; + union ieee802154_phyattr_u phy; + union ieee802154_secattr_u sec; +}; + +struct ieee802154_gts_info_s +{ + uint8_t length : 4; /* Number of SF slots for GTS */ + uint8_t direction : 1; /* 0=transmit-only, 1=receive-only */ + uint8_t type : 1; /* 0=GTS deallocation, 1= GTS allocation */ + uint8_t reserved : 2; +}; + +enum ieee802154_scantype_e +{ + IEEE802154_SCANTYPE_ED, + IEEE802154_SCANTYPE_ACTIVE, + IEEE802154_SCANTYPE_PASSIVE, + IEEE802154_SCANTYPE_ORPHAN +}; + +struct ieee802154_frame_meta_s +{ + enum ieee802154_addr_mode_e src_addr_mode; /* Source Address Mode */ + struct ieee802154_addr_s dest_addr; /* Destination Address */ + + uint8_t msdu_handle; /* Handle assoc. with MSDU */ + + 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; + +#ifdef CONFIG_IEEE802154_SECURITY + /* Security information if enabled */ + + struct ieee802154_security_s security; +#endif + +#ifdef CONFIG_IEEE802154_UWB + /* The UWB Pulse Repetition Frequency to be used for the transmission */ + + enum ieee802154_uwbprf_e uwb_prf; + + /* The UWB preamble symbol repititions + * Should be one of: + * 0, 16, 64, 1024, 4096 + */ + + uint16_t uwb_presym_rep; + + /* The UWB Data Rate to be used for the transmission */ + + enum ieee802154_uwb_datarate_e data_rate; +#endif + + enum ieee802154_ranging_e ranging; +}; + +/* Primitive Semantics *******************************************************/ + +/***************************************************************************** + * Primitive: MCPS-DATA.confirm + * + * Description: + * Reports the results of a request to transfer data to another device. + * + *****************************************************************************/ + +struct ieee802154_data_conf_s +{ + IEEE802154_TXDESC_FIELDS +}; + +/***************************************************************************** + * Primitive: MCPS-DATA.indication + * + * Description: + * Indicates the reception of data from another device. + * + *****************************************************************************/ + +struct ieee802154_data_ind_s +{ + FAR struct ieee802154_data_ind_s *flink; + + FAR struct iob_s *frame; + + struct ieee802154_addr_s src; /* Source addressing information */ + struct ieee802154_addr_s dest; /* Destination addressing infromation */ + uint8_t lqi; /* Link Quality Index */ + uint8_t rssi; /* Non-standard field */ + uint8_t dsn; /* Data Sequence Number */ + uint32_t timestamp; /* Time of received frame */ + +#ifdef CONFIG_IEEE802154_SECURITY + /* Security information if enabled */ + + struct ieee802154_security_s security; +#endif /* CONFIG_IEEE802154_SECURITY */ + +#ifdef CONFIG_IEEE802154_UWB + /* The UWB Pulse Repetition Frequency to be used for the transmission */ + + enum ieee802154_uwbprf_e uwb_prf; + + /* The UWB preamble symbol repititions + * Should be one of: + * 0, 16, 64, 1024, 4096 + */ + + uint16_t uwb_presym_rep; + + /* The UWB Data Rate to be used for the transmission */ + + enum ieee802154_uwb_datarate_e data_rate; +#endif /* CONFIG_IEEE802154_UWB */ + +#ifdef CONFIG_IEEE802154_RANGING + bool rng_rcvd; /* Ranging indicated by MSDU */ + + /* A count of the time units corresponding to an RMARKER at the antenna at + * the beginning of the ranging exchange + */ + + uint32_t rng_counter_start; + + /* A count of the time units corresponding to an RMARKER at the antenna at + * end of the ranging exchange + */ + + uint32_t rng_counter_stop; + + /* A count of the time units in a message exchange over which the tracking + * offset was measured + */ + + uint34_t rng_tracking_interval; + + /* A count of the time units slipped or advanced by the radio tracking + * system over the course of the entire tracking interval + */ + + uint32_t rng_offset; + + /* The Figure of Merit (FoM) characterizing the ranging measurement */ + + uint8_t rng_fom; +#endif /* CONFIG_IEEE802154_RANGING */ +}; + +/***************************************************************************** + * Primitive: MCPS-PURGE.request + * + * Description: + * Allows the next higher layer to purge an MSDU from the transaction queue. + * + *****************************************************************************/ + +struct ieee802154_purge_req_s +{ + uint8_t msdu_handle; /* Handle assoc. with MSDU */ +}; + +/***************************************************************************** + * Primitive: MLME-ASSOCIATE.request + * + * Description: + * Used by a device to request an association with a coordinator. + * + *****************************************************************************/ + +struct ieee802154_assoc_req_s +{ + uint8_t channel; /* Channel number to attempt association */ + uint8_t channel_page; /* Channel page to attempt association */ + + /* Coordinator Address with which to associate */ + + struct ieee802154_addr_s coord_addr; + + /* Capabilities of associating device */ + + struct ieee802154_capability_info_s capabilities; + +#ifdef CONFIG_IEEE802154_SECURITY + /* Security information if enabled */ + + struct ieee802154_security_s security; +#endif +}; + +/***************************************************************************** + * Primitive: MLME-ASSOCIATE.indication + * + * Description: + * Used to indicate the reception of an association request command. + * + *****************************************************************************/ + +struct ieee802154_assoc_ind_s +{ + /* Address of device requesting association. Always in extended mode */ + + struct ieee802154_addr_s dev_addr; + + /* Capabilities of associating device */ + + struct ieee802154_capability_info_s capabilities; + +#ifdef CONFIG_IEEE802154_SECURITY + /* Security information if enabled */ + + struct ieee802154_security_s security; +#endif +}; + +/***************************************************************************** + * Primitive: MLME-ASSOCIATE.response + * + * Description: + * Used to initiate a response to an MLME-ASSOCIATE.indication primitive. + * + *****************************************************************************/ + +struct ieee802154_assoc_resp_s +{ + /* Address of device requesting association. Always in extended mode */ + + struct ieee802154_addr_s dev_addr; + + /* Status of association attempt */ + + enum ieee802154_status_e status; + +#ifdef CONFIG_IEEE802154_SECURITY + /* Security information if enabled */ + + struct ieee802154_security_s security; +#endif +}; + +/***************************************************************************** + * Primitive: MLME-ASSOCIATE.confirm + * + * Description: + * Used to inform the next higher layer of the initiating device whether its + * request to associate was successful or unsuccessful. + * + *****************************************************************************/ + +struct ieee802154_assoc_conf_s +{ + /* Associated device address ALWAYS passed in short address mode. The + * address will be IEEE802154_SADDR_UNSPEC if association was + * unsuccessful. + */ + + struct ieee802154_addr_s dev_addr; + + /* Status of association attempt */ + + enum ieee802154_status_e status; + +#ifdef CONFIG_IEEE802154_SECURITY + /* Security information if enabled */ + + struct ieee802154_security_s security; +#endif +}; + +/***************************************************************************** + * Primitive: MLME-DISASSOCIATE.request + * + * Description: + * Used by an associated device to notify the coordinator of its intent to + * leave the PAN. It is also used by the coordinator to instruct an + * associated device to leave the PAN. + * + *****************************************************************************/ + +struct ieee802154_disassoc_req_s +{ + /* Address of device to send disassociation notification */ + + struct ieee802154_addr_s dev_addr; + + /* Reason for the disassosiation */ + + enum ieee802154_status_e disassoc_reason; + + uint8_t tx_indirect; /* 0=Send Direct, 1=Send Indirect */ + +#ifdef CONFIG_IEEE802154_SECURITY + /* Security information if enabled */ + + struct ieee802154_security_s security; +#endif +}; + +/***************************************************************************** + * Primitive: MLME-DISASSOCIATE.indication + * + * Description: + * Used to indicate the reception of a disassociation notification command. + * + *****************************************************************************/ + +struct ieee802154_disassoc_ind_s +{ + /* Address of device requesting disassociation. Always extended mode */ + + struct ieee802154_addr_s dev_addr; + + /* Reason for the disassosiation */ + + enum ieee802154_status_e disassoc_reason; + +#ifdef CONFIG_IEEE802154_SECURITY + /* Security information if enabled */ + + struct ieee802154_security_s security; +#endif +}; + +/***************************************************************************** + * Primitive: MLME-DISASSOCIATE.confirm + * + * Description: + * Reports the results of an MLME-DISASSOCIATE.request primitive. + * + *****************************************************************************/ + +struct ieee802154_disassoc_conf_s +{ + /* Status of the disassociation attempt */ + + enum ieee802154_status_e status; + + /* Address of device either requesting or being intructed to disassociate */ + + struct ieee802154_addr_s dev_addr; +}; + +/***************************************************************************** + * Primitive: MLME-BEACONNOTIFY.indication + * + * Description: + * Used to send parameters contained within a beacon frame received by the + * MAC sublayer to the next higher layer when either macAutoRequest is set to + * FALSE or when the beacon frame contains one or more octets of payload. The + * primitive also sends a measure of the LQI and the time the beacon frame + * was received. + * + *****************************************************************************/ + +struct ieee802154_beaconnotify_ind_s +{ + uint8_t bsn; /* Beacon sequence number */ + + /* PAN descriptor for the received beacon */ + + struct ieee802154_pan_desc_s pan_desc; + + /* 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]; +}; + +#define SIZEOF_IEEE802154_BEACONNOTIFY_IND_S(n) \ + (sizeof(struct ieee802154_beaconnotify_ind_s) \ + - IEEE802154_MAX_BEACON_PAYLOAD_LEN + (n)) + +/***************************************************************************** + * Primitive: MLME-COMM-STATUS.indication + * + * Description: + * Allows the MLME to indicate a communications status. + * + *****************************************************************************/ + +struct ieee802154_commstatus_ind_s +{ + struct ieee802154_addr_s src_addr; + struct ieee802154_addr_s dest_addr; + enum ieee802154_status_e status; + +#ifdef CONFIG_IEEE802154_SECURITY + /* Security information if enabled */ + + struct ieee802154_security_s security; +#endif +}; + +/***************************************************************************** + * Primitive: MLME-GTS.request + * + * Description: + * Allows a device to send a request to the PAN coordinator to allocate a new + * GTS or to deallocate an existing GTS. This primitive is also used by the + * PAN coordinator to initiate a GTS deallocation. + * + *****************************************************************************/ + +struct ieee802154_gts_req_s +{ + struct ieee802154_gts_info_s gts_info; + +#ifdef CONFIG_IEEE802154_SECURITY + /* Security information if enabled */ + + struct ieee802154_security_s security; +#endif +}; + +/***************************************************************************** + * Primitive: MLME-GTS.confirm + * + * Description: + * Reports the results of a request to allocate a new GTS or to deallocate an + * existing GTS. + * + *****************************************************************************/ + +struct ieee802154_gts_conf_s +{ + struct ieee802154_gts_info_s gts_info; + enum ieee802154_status_e status; +}; + +/***************************************************************************** + * Primitive: MLME-GTS.indication + * + * Description: + * Indicates that a GTS has been allocated or that a previously allocated + * GTS has been deallocated. + * + *****************************************************************************/ + +struct ieee802154_gts_ind_s +{ + uint16_t dev_addr; + struct ieee802154_gts_info_s gts_info; + +#ifdef CONFIG_IEEE802154_SECURITY + /* Security information if enabled */ + + struct ieee802154_security_s security; +#endif +}; + +/***************************************************************************** + * Primitive: MLME-ORPHAN.indication + * + * Description: + * Generated by the MLME of a coordinator and issued to its next higher layer + * on receipt of an orphan notification command. + * + *****************************************************************************/ + +struct ieee802154_orphan_ind_s +{ + uint8_t orphan_addr[8]; + +#ifdef CONFIG_IEEE802154_SECURITY + /* Security information if enabled */ + + struct ieee802154_security_s security; +#endif +}; + +/***************************************************************************** + * Primitive: MLME-ORPHAN.response + * + * Description: + * Allows the next higher layer of a coordinator to respond to the + * MLME-ORPHAN.indication primitive. + * + *****************************************************************************/ + +struct ieee802154_orphan_resp_s +{ + uint8_t orphan_addr[8]; + +#ifdef CONFIG_IEEE802154_SECURITY + /* Security information if enabled */ + + struct ieee802154_security_s security; +#endif +}; + +/***************************************************************************** + * Primitive: MLME-RESET.request + * + * Description: + * Used by the next higher layer to request that the MLME performs a reset + * operation. + * + *****************************************************************************/ + +struct ieee802154_reset_req_s +{ + bool rst_pibattr; +}; + +/***************************************************************************** + * Primitive: MLME-RXENABLE.request + * + * Description: + * Allows the next higher layer to request that the receiver is either + * enabled for a finite period of time or disabled. + * + *****************************************************************************/ + +struct ieee802154_rxenable_req_s +{ + /* Number of symbols measured from the start of the superframe before the + * receiver is to be enabled or disabled. + */ + + uint32_t rxon_time; + + /* Number of symbols for which the receiver is to be enabled */ + + uint32_t rxon_dur; + + uint8_t defer_permit : 1; /* 0=Only attempt operation on current superframe + * 1=Operation can be deferred to next superframe */ + uint8_t rng_rxctrl : 1; /* 0=RANGING_OFF, 1=RANGING_OFF */ +}; + +/***************************************************************************** + * Primitive: MLME-RXENABLE.confirm + * + * Description: + * Reports the results of the attempt to enable or disable the receiver. + * + *****************************************************************************/ + +struct ieee802154_rxenable_conf_s +{ + enum ieee802154_status_e status; +}; + +/***************************************************************************** + * Primitive: MLME-SCAN.request + * + * Description: + * Used to initiate a channel scan over a given list of channels. + * + *****************************************************************************/ + +struct ieee802154_scan_req_s +{ + enum ieee802154_scantype_e type; + uint8_t duration; + uint8_t ch_page; + +#ifdef CONFIG_IEEE802154_SECURITY + /* Security information if enabled */ + + struct ieee802154_security_s security; +#endif + + uint8_t channels[1]; +}; + +#define SIZEOF_IEEE802154_SCAN_REQ_S(n) \ + (sizeof(struct ieee802154_scan_req_s) + (n) - 1) + +/***************************************************************************** + * Primitive: MLME-SCAN.confirm + * + * Description: + * Reports the result of the channel scan request. + * + *****************************************************************************/ + +struct ieee802154_scan_conf_s +{ + enum ieee802154_status_e status; + enum ieee802154_scantype_e type; + uint8_t ch_page; + uint8_t num_channels; + +#warning Figure out how to handle missing primitive semantics. See standard. +}; + +/***************************************************************************** + * Primitive: MLME-GET.request + * + * Description: + * Requests information about a given PIB attribute. + * + *****************************************************************************/ + +struct ieee802154_get_req_s +{ + enum ieee802154_pib_attr_e pib_attr; + union ieee802154_attr_val_u attr_value; +}; + +/***************************************************************************** + * Primitive: MLME-SET.request + * + * Description: + * Attempts to write the given value to the indicated PIB attribute. + * + * NOTE: The standard specifies that confirmation should be indicated via + * the asynchronous MLME-SET.confirm primitve. However, in our implementation + * there is no reason not to synchronously return the status immediately. + * Therefore, we do merge the functionality of the MLME-SET.request and + * MLME-SET.confirm primitives together. + * + *****************************************************************************/ + +struct ieee802154_set_req_s +{ + enum ieee802154_pib_attr_e pib_attr; + union ieee802154_attr_val_u attr_value; +}; + +/***************************************************************************** + * Primitive: MLME-START.request + * + * Description: + * Used by the PAN coordinator to initiate a new PAN or to begin using a new + * superframe configuration. This primitive is also used by a device already + * associated with an existing PAN to begin using a new superframe + * configuration. + * + *****************************************************************************/ + +struct ieee802154_start_req_s +{ + uint16_t pan_id; + uint8_t ch_num; + uint8_t ch_page; + + uint32_t start_time : 24; + uint32_t beacon_order : 8; + + uint8_t sf_order; + + uint8_t pan_coord : 1; + uint8_t batt_life_ext : 1; + uint8_t coord_realign : 1; + +#ifdef CONFIG_IEEE802154_SECURITY + /* Security information if enabled */ + + struct ieee802154_security_s coord_realign; + struct ieee802154_security_s beacon; +#endif +}; + +/***************************************************************************** + * Primitive: MLME-START.confirm + * + * Description: + * Reports the results of the attempt to start using a new superframe + * configuration. + * + *****************************************************************************/ + +struct ieee802154_start_conf_s +{ + enum ieee802154_status_e status; +}; + +/***************************************************************************** + * Primitive: MLME-SYNC.request + * + * Description: + * Requests to synchronize with the coordinator by acquiring and, if + * specified, tracking its beacons. + * + *****************************************************************************/ + +struct ieee802154_sync_req_s +{ + uint8_t ch_num; + uint8_t ch_page; + bool track_beacon; +}; + +/***************************************************************************** + * Primitive: MLME-SYNC-LOSS.indication + * + * Description: + * Indicates the loss of synchronization with a coordinator. + * + *****************************************************************************/ + +struct ieee802154_syncloss_ind_s +{ + enum ieee802154_status_e loss_reason; + uint16_t pan_id; + uint8_t ch_num; + uint8_t ch_page; + +#ifdef CONFIG_IEEE802154_SECURITY + /* Security information if enabled */ + + struct ieee802154_security_s security; +#endif +}; + +/***************************************************************************** + * Primitive: MLME-POLL.request + * + * Description: + * Prompts the device to request data from the coordinator. + * + *****************************************************************************/ + +struct ieee802154_poll_req_s +{ + struct ieee802154_addr_s coord_addr; + +#ifdef CONFIG_IEEE802154_SECURITY + /* Security information if enabled */ + + struct ieee802154_security_s security; +#endif +}; + +/***************************************************************************** + * Primitive: MLME-POLL.confirm + * + * Description: + * Reports the results of a request to poll the coordinator for data. + * + *****************************************************************************/ + +struct ieee802154_poll_conf_s +{ + enum ieee802154_status_e status; +}; + +union ieee802154_mlme_notify_u +{ + 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; +}; + +union ieee802154_mcps_notify_u +{ + struct ieee802154_data_conf_s dataconf; + struct ieee802154_data_ind_s *dataind; +}; + +/* A pointer to this structure is passed as the argument of each IOCTL + * command. + */ + +union ieee802154_macarg_u +{ + struct ieee802154_assoc_req_s assocreq; /* MAC802154IOC_MLME_ASSOC_REQUEST */ + struct ieee802154_assoc_resp_s assocresp; /* MAC802154IOC_MLME_ASSOC_RESPONSE */ + struct ieee802154_disassoc_req_s disassocreq; /* MAC802154IOC_MLME_DISASSOC_REQUEST */ + struct ieee802154_get_req_s getreq; /* MAC802154IOC_MLME_GET_REQUEST */ + struct ieee802154_gts_req_s gtsreq; /* MAC802154IOC_MLME_GTS_REQUEST */ + struct ieee802154_orphan_resp_s orphanresp; /* MAC802154IOC_MLME_ORPHAN_RESPONSE */ + struct ieee802154_reset_req_s resetreq; /* MAC802154IOC_MLME_RESET_REQUEST */ + struct ieee802154_rxenable_req_s rxenabreq; /* MAC802154IOC_MLME_RXENABLE_REQUEST */ + struct ieee802154_scan_req_s scanreq; /* MAC802154IOC_MLME_SCAN_REQUEST */ + struct ieee802154_set_req_s setreq; /* MAC802154IOC_MLME_SET_REQUEST */ + struct ieee802154_start_req_s startreq; /* MAC802154IOC_MLME_START_REQUEST */ + struct ieee802154_sync_req_s syncreq; /* MAC802154IOC_MLME_SYNC_REQUEST */ + struct ieee802154_poll_req_s pollreq; /* MAC802154IOC_MLME_POLL_REQUEST */ + /* To be determined */ /* MAC802154IOC_MLME_DPS_REQUEST */ + /* To be determined */ /* MAC802154IOC_MLME_SOUNDING_REQUEST */ + /* To be determined */ /* MAC802154IOC_MLME_CALIBRATE_REQUEST */ +}; + +#ifdef CONFIG_NET_6LOWPAN +/* For the case of network IOCTLs, the network IOCTL to the MAC network + * driver will include a device name like "wpan0" as the destination of + * the IOCTL command. + */ + +struct ieee802154_netmac_s +{ + char ifr_name[IFNAMSIZ]; /* Interface name, e.g. "wpan0" */ + union ieee802154_macarg_u u; /* Data payload */ +}; +#endif + +/* This is an opaque reference to the MAC's internal private state. It is + * returned by mac802154_create() when it is created. It may then be used + * at other interfaces in order to interact with the MAC. + */ + +typedef FAR void *MACHANDLE; + +/* MAC Service Notifications */ + +enum ieee802154_macnotify_e +{ + /* MCPS Notifications */ + + IEEE802154_NOTIFY_CONF_DATA = 0x00, + IEEE802154_NOTIFY_IND_DATA, + + /* MLME Notifications */ + + IEEE802154_NOTIFY_CONF_ASSOC, + IEEE802154_NOTIFY_CONF_DISASSOC, + IEEE802154_NOTIFY_CONF_GTS, + IEEE802154_NOTIFY_CONF_RESET, + IEEE802154_NOTIFY_CONF_RXENABLE, + IEEE802154_NOTIFY_CONF_SCAN, + IEEE802154_NOTIFY_CONF_START, + IEEE802154_NOTIFY_CONF_POLL, + + IEEE802154_NOTIFY_IND_ASSOC, + IEEE802154_NOTIFY_IND_DISASSOC, + IEEE802154_NOTIFY_IND_BEACONNOTIFY, + IEEE802154_NOTIFY_IND_GTS, + IEEE802154_NOTIFY_IND_ORPHAN, + IEEE802154_NOTIFY_IND_COMMSTATUS, + IEEE802154_NOTIFY_IND_SYNCLOSS +}; + +/* Callback operations to notify the next highest layer of various asynchronous + * events, usually triggered by some previous request or response invoked by the + * upper layer. + */ + +struct ieee802154_maccb_s +{ + CODE void (*mlme_notify)(FAR const struct ieee802154_maccb_s *maccb, + enum ieee802154_macnotify_e notif, + FAR const union ieee802154_mlme_notify_u *arg); + + CODE void (*mcps_notify)(FAR const struct ieee802154_maccb_s *maccb, + enum ieee802154_macnotify_e notif, + FAR const union ieee802154_mcps_notify_u *arg); +}; + +#ifdef __cplusplus +#define EXTERN extern "C" +extern "C" +{ +#else +#define EXTERN extern +#endif + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +struct ieee802154_radio_s; /* Forward reference */ + +/**************************************************************************** + * Name: mac802154_create + * + * Description: + * Create a 802.15.4 MAC device from a 802.15.4 compatible radio device. + * + * The returned MAC structure should be passed to either the next highest + * layer in the network stack, or registered with a mac802154dev character + * or network drivers. In any of these scenarios, the next highest layer + * should register a set of callbacks with the MAC layer by setting the + * mac->cbs member. + * + * NOTE: This API does not create any device accessible to userspace. If you + * want to call these APIs from userspace, you have to wrap your mac in a + * character device via mac802154_device.c. + * + * Input Parameters: + * radiodev - an instance of an IEEE 802.15.4 radio + * + * Returned Value: + * An opaque reference to the MAC state data. + * + ****************************************************************************/ + +MACHANDLE mac802154_create(FAR struct ieee802154_radio_s *radiodev); + +/**************************************************************************** + * Name: mac802154dev_register + * + * Description: + * Register a character driver to access the IEEE 802.15.4 MAC layer from + * user-space + * + * Input Parameters: + * mac - Pointer to the mac layer struct to be registered. + * minor - The device minor number. The IEEE802.15.4 MAC character device + * will be registered as /dev/ieeeN where N is the minor number + * + * Returned Values: + * Zero (OK) is returned on success. Otherwise a negated errno value is + * returned to indicate the nature of the failure. + * + ****************************************************************************/ + +int mac802154dev_register(MACHANDLE mac, int minor); + +/**************************************************************************** + * Name: mac802154netdev_register + * + * Description: + * Register a network driver to access the IEEE 802.15.4 MAC layer from + * a socket using 6loWPAN + * + * Input Parameters: + * mac - Pointer to the mac layer struct to be registered. + * + * Returned Values: + * Zero (OK) is returned on success. Otherwise a negated errno value is + * returned to indicate the nature of the failure. + * + ****************************************************************************/ + +int mac802154netdev_register(MACHANDLE mac); + +/**************************************************************************** + * Name: ieee802154_indpool_initialize + * + * Description: + * This function initializes the meta-data allocator. This function must + * be called early in the initialization sequence before any radios + * begin operation. + * + * Inputs: + * None + * + * Return Value: + * None + * + ****************************************************************************/ + +void ieee802154_indpool_initialize(void); + +/**************************************************************************** + * Name: ieee802154_ind_allocate + * + * Description: + * The ieee802154_ind_allocate function will get a free meta-data + * structure for use by the IEEE 802.15.4 MAC. + * + * Interrupt handling logic will first attempt to allocate from the + * g_indfree list. If that list is empty, it will attempt to allocate + * from its reserve, g_indfree_irq. If that list is empty, then the + * allocation fails (NULL is returned). + * + * Non-interrupt handler logic will attempt to allocate from g_indfree + * list. If that the list is empty, then the meta-data structure will be + * allocated from the dynamic memory pool. + * + * Inputs: + * None + * + * Return Value: + * A reference to the allocated msg structure. All user fields in this + * structure have been zeroed. On a failure to allocate, NULL is + * returned. + * + ****************************************************************************/ + +FAR struct ieee802154_data_ind_s *ieee802154_ind_allocate(void); + +/**************************************************************************** + * Name: ieee802154_ind_free + * + * Description: + * The ieee802154_ind_free function will return a meta-data structure to + * the free pool of messages if it was a pre-allocated meta-data + * structure. If the meta-data structure was allocated dynamically it will + * be deallocated. + * + * Inputs: + * ind - meta-data structure to free + * + * Return Value: + * None + * + ****************************************************************************/ + +void ieee802154_ind_free(FAR struct ieee802154_data_ind_s *ind); + + +#undef EXTERN +#ifdef __cplusplus +} +#endif + +#endif /* __INCLUDE_NUTTX_WIRELESS_IEEE802154_IEEE802154_MAC_H */ diff --git a/include/nuttx/wireless/ieee802154/ieee802154_radio.h b/include/nuttx/wireless/ieee802154/ieee802154_radio.h index c3439feb89..fcbc7ec1b7 100644 --- a/include/nuttx/wireless/ieee802154/ieee802154_radio.h +++ b/include/nuttx/wireless/ieee802154/ieee802154_radio.h @@ -2,7 +2,9 @@ * include/nuttx/wireless/ieee802154/ieee802154_radio.h * * Copyright (C) 2014-2016 Sebastien Lorquet. All rights reserved. + * Copyright (C) 2017 Verge Inc. All rights reserved. * Author: Sebastien Lorquet + * Author: Anthony Merlino * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -33,175 +35,64 @@ * ****************************************************************************/ -#ifndef __INCLUDE_NUTTX_WIRELESS_IEEE802154_IEEE802154_H -#define __INCLUDE_NUTTX_WIRELESS_IEEE802154_IEEE802154_H +#ifndef __INCLUDE_NUTTX_WIRELESS_IEEE802154_IEEE802154_RADIO_H +#define __INCLUDE_NUTTX_WIRELESS_IEEE802154_IEEE802154_RADIO_H /**************************************************************************** * Included Files ****************************************************************************/ #include + #include #include #include +#include + /**************************************************************************** * Pre-Processor Definitions ****************************************************************************/ -/* Configuration ************************************************************/ -/* None at the moment */ - -/* IEEE 802.15.4 MAC Interface **********************************************/ - -/* Frame control field masks, 2 bytes - * Seee IEEE 802.15.4/2003 7.2.1.1 page 112 - */ - -#define IEEE802154_FC1_FTYPE 0x03 /* Frame type, bits 0-2 */ -#define IEEE802154_FC1_SEC 0x08 /* Security Enabled, bit 3 */ -#define IEEE802154_FC1_PEND 0x10 /* Frame pending, bit 4 */ -#define IEEE802154_FC1_ACKREQ 0x20 /* Acknowledge request, bit 5 */ -#define IEEE802154_FC1_INTRA 0x40 /* Intra PAN, bit 6 */ -#define IEEE802154_FC2_DADDR 0x0C /* Dest addressing mode, bits 10-11 */ -#define IEEE802154_FC2_VERSION 0x30 /* Source addressing mode, bits 12-13 */ -#define IEEE802154_FC2_SADDR 0xC0 /* Source addressing mode, bits 14-15 */ - -/* Frame Type */ - -#define IEEE802154_FRAME_BEACON 0x00 -#define IEEE802154_FRAME_DATA 0x01 -#define IEEE802154_FRAME_ACK 0x02 -#define IEEE802154_FRAME_COMMAND 0x03 - -/* Security Enabled */ - -#define IEEE802154_SEC_OFF 0x00 -#define IEEE802154_SEC_ON 0x08 - -/* Flags */ - -#define IEEE802154_PEND 0x10 -#define IEEE802154_ACK_REQ 0x20 -#define IEEE802154_INTRA 0x40 - -/* Dest Addressing modes */ - -#define IEEE802154_DADDR_NONE 0x00 -#define IEEE802154_DADDR_SHORT 0x08 -#define IEEE802154_DADDR_EXT 0x0A - -/* Src Addressing modes */ - -#define IEEE802154_SADDR_NONE 0x00 -#define IEEE802154_SADDR_SHORT 0x80 -#define IEEE802154_SADDR_EXT 0xA0 - -/* Some addresses */ - -#define IEEE802154_PAN_DEFAULT (uint16_t)0xFFFF -#define IEEE802154_SADDR_UNSPEC (uint16_t)0xFFFF -#define IEEE802154_SADDR_BCAST (uint16_t)0xFFFE -#define IEEE802154_EADDR_UNSPEC (uint8_t*)"\xff\xff\xff\xff\xff\xff\xff\xff" - -#define IEEE802154_CMD_ASSOC_REQ 0x01 -#define IEEE802154_CMD_ASSOC_RSP 0x02 -#define IEEE802154_CMD_DIS_NOT 0x03 -#define IEEE802154_CMD_DATA_REQ 0x04 -#define IEEE802154_CMD_PANID_CONF_NOT 0x05 -#define IEEE802154_CMD_ORPHAN_NOT 0x06 -#define IEEE802154_CMD_BEACON_REQ 0x07 -#define IEEE802154_CMD_COORD_REALIGN 0x08 -#define IEEE802154_CMD_GTS_REQ 0x09 - -/* Device modes */ - -#define IEEE802154_MODE_DEVICE 0x00 -#define IEEE802154_MODE_COORD 0x01 /* avail in mrf24j40, but why? */ -#define IEEE802154_MODE_PANCOORD 0x02 /**************************************************************************** * Public Types ****************************************************************************/ -struct ieee802154_packet_s +/* IEEE802.15.4 Radio Interface Operations **********************************/ + +struct ieee802154_radiocb_s { - uint8_t len; - uint8_t data[127]; - uint8_t lqi; - uint8_t rssi; + CODE int (*poll_csma) (FAR const struct ieee802154_radiocb_s *radiocb, + FAR struct ieee802154_txdesc_s *tx_desc, + FAR struct iob_s **frame); + CODE int (*poll_gts) (FAR const struct ieee802154_radiocb_s *radiocb, + FAR struct ieee802154_txdesc_s *tx_desc, + FAR struct iob_s **frame); + CODE void (*txdone) (FAR const struct ieee802154_radiocb_s *radiocb, + FAR const struct ieee802154_txdesc_s *tx_desc); + CODE void (*rxframe) (FAR const struct ieee802154_radiocb_s *radiocb, + FAR struct ieee802154_data_ind_s *ind); }; -struct ieee802154_cca_s +struct ieee802154_radio_s; /* Forward reference */ + +struct ieee802154_radioops_s { - uint8_t use_ed : 1; /* CCA using ED */ - uint8_t use_cs : 1; /* CCA using carrier sense */ - uint8_t edth; /* Energy detection threshold for CCA */ - uint8_t csth; /* Carrier sense threshold for CCA */ + CODE int (*bind) (FAR struct ieee802154_radio_s *radio, + FAR struct ieee802154_radiocb_s *radiocb); + CODE int (*txnotify_csma)(FAR struct ieee802154_radio_s *radio); + CODE int (*txnotify_gts)(FAR struct ieee802154_radio_s *radio); + CODE int (*get_attr) (FAR struct ieee802154_radio_s *radio, + enum ieee802154_pib_attr_e pib_attr, + FAR union ieee802154_attr_val_u *attr_value); + CODE int (*set_attr) (FAR struct ieee802154_radio_s *radio, + enum ieee802154_pib_attr_e pib_attr, + FAR const union ieee802154_attr_val_u *attr_value); }; -struct ieee802154_dev_s; - -struct ieee802154_devops_s +struct ieee802154_radio_s { - CODE int (*setchannel)(FAR struct ieee802154_dev_s *dev, uint8_t channel); - CODE int (*getchannel)(FAR struct ieee802154_dev_s *dev, - FAR uint8_t *channel); - - CODE int (*setpanid)(FAR struct ieee802154_dev_s *dev, uint16_t panid); - CODE int (*getpanid)(FAR struct ieee802154_dev_s *dev, - FAR uint16_t *panid); - - CODE int (*setsaddr)(FAR struct ieee802154_dev_s *dev, uint16_t saddr); - CODE int (*getsaddr)(FAR struct ieee802154_dev_s *dev, - FAR uint16_t *saddr); - - CODE int (*seteaddr)(FAR struct ieee802154_dev_s *dev, - FAR uint8_t *laddr); - CODE int (*geteaddr)(FAR struct ieee802154_dev_s *dev, - FAR uint8_t *laddr); - - CODE int (*setpromisc)(FAR struct ieee802154_dev_s *dev, bool promisc); - CODE int (*getpromisc)(FAR struct ieee802154_dev_s *dev, - FAR bool *promisc); - - CODE int (*setdevmode)(FAR struct ieee802154_dev_s *dev, uint8_t devmode); - CODE int (*getdevmode)(FAR struct ieee802154_dev_s *dev, - FAR uint8_t *devmode); - - CODE int (*settxpower)(FAR struct ieee802154_dev_s *dev, - int32_t txpwr); /* unit = 1 mBm = 1/100 dBm */ - CODE int (*gettxpower)(FAR struct ieee802154_dev_s *dev, - FAR int32_t *txpwr); - - CODE int (*setcca)(FAR struct ieee802154_dev_s *dev, - FAR struct ieee802154_cca_s *cca); - CODE int (*getcca)(FAR struct ieee802154_dev_s *dev, - FAR struct ieee802154_cca_s *cca); - - CODE int (*ioctl)(FAR struct ieee802154_dev_s *ieee, int cmd, - unsigned long arg); - CODE int (*energydetect)(FAR struct ieee802154_dev_s *dev, - FAR uint8_t *energy); - CODE int (*rxenable)(FAR struct ieee802154_dev_s *dev, bool state, - FAR struct ieee802154_packet_s *packet); - CODE int (*transmit)(FAR struct ieee802154_dev_s *dev, - FAR struct ieee802154_packet_s *packet); - - /*TODO beacon/sf order*/ -}; - -struct ieee802154_dev_s -{ - FAR const struct ieee802154_devops_s *ops; - - /* Packet reception management */ - - struct ieee802154_packet_s *rxbuf; - sem_t rxsem; - - /* Packet transmission management */ - - sem_t txsem; + FAR const struct ieee802154_radioops_s *ops; }; #ifdef __cplusplus @@ -221,4 +112,4 @@ extern "C" } #endif -#endif /* __INCLUDE_NUTTX_WIRELESS_IEEE802154_MRF24J40_H */ +#endif /* __INCLUDE_NUTTX_WIRELESS_IEEE802154_IEEE802154_RADIO_H */ diff --git a/include/nuttx/wireless/ieee802154/mrf24j40.h b/include/nuttx/wireless/ieee802154/mrf24j40.h index 878f7d9b45..136c947a48 100644 --- a/include/nuttx/wireless/ieee802154/mrf24j40.h +++ b/include/nuttx/wireless/ieee802154/mrf24j40.h @@ -40,6 +40,8 @@ * Included files ****************************************************************************/ +#include +#include #include /**************************************************************************** @@ -52,18 +54,19 @@ * * The MRF24J40 interrupt is an active low, *level* interrupt. From Datasheet: * "Note 1: The INTEDGE polarity defaults to: - * 0 = Falling Edge. Ensure that the inter- - * rupt polarity matches the interrupt pin - * polarity of the host microcontroller. - * Note 2: The INT pin will remain high or low, - * depending on INTEDGE polarity setting, - * until INTSTAT register is read." + * + * 0 = Falling Edge. Ensure that the interrupt polarity matches the + * interrupt pin polarity of the host microcontroller. + * + * Note 2: The INT pin will remain high or low, depending on INTEDGE + * polarity setting, until INTSTAT register is read." */ struct mrf24j40_lower_s { - int (*attach)(FAR const struct mrf24j40_lower_s *lower, xcpt_t handler); - void (*enable)(FAR const struct mrf24j40_lower_s *lower, int state); + int (*attach)(FAR const struct mrf24j40_lower_s *lower, xcpt_t handler, + FAR void *arg); + void (*enable)(FAR const struct mrf24j40_lower_s *lower, bool state); }; #ifdef __cplusplus @@ -100,8 +103,9 @@ extern "C" ****************************************************************************/ struct spi_dev_s; /* Forward reference */ -FAR struct ieee802154_dev_s *mrf24j40_init(FAR struct spi_dev_s *spi, - FAR const struct mrf24j40_lower_s *lower); +FAR struct ieee802154_radio_s * + mrf24j40_init(FAR struct spi_dev_s *spi, + FAR const struct mrf24j40_lower_s *lower); #undef EXTERN #ifdef __cplusplus diff --git a/include/sys/ioctl.h b/include/sys/ioctl.h index acbcc1d3e6..76abe7f01f 100644 --- a/include/sys/ioctl.h +++ b/include/sys/ioctl.h @@ -63,6 +63,22 @@ # include #endif + +#ifdef CONFIG_WIRELESS_IEEE802154 + +#ifdef CONFIG_IEEE802154_MAC +/* Include ieee802.15.4 MAC IOCTL definitions */ + +# include +#endif + +#ifdef CONFIG_IEEE802154_MAC_DEV +/* Include ieee802.15.4 character driver IOCTL definitions */ + +# include +#endif + +#endif /* CONFIG_WIRELESS_IEEE802154 */ #endif /* CONFIG_NSOCKET_DESCRIPTORS > 0 */ /**************************************************************************** diff --git a/net/Kconfig b/net/Kconfig index 313f7a05f8..c5f7d26117 100644 --- a/net/Kconfig +++ b/net/Kconfig @@ -136,6 +136,7 @@ config NET_6LOWPAN default n select NETDEV_MULTINIC if NET_ETHERNET || NET_LOOPBACK || NET_SLIP || NET_TUN select NET_MULTILINK if NET_ETHERNET || NET_LOOPBACK || NET_SLIP || NET_TUN + select NETDEV_IOCTL depends on EXPERIMENTAL && NET_IPv6 ---help--- Enable support for IEEE 802.15.4 Low power Wireless Personal Area diff --git a/net/netdev/netdev_ioctl.c b/net/netdev/netdev_ioctl.c index 8bb44c82fc..dae8064645 100644 --- a/net/netdev/netdev_ioctl.c +++ b/net/netdev/netdev_ioctl.c @@ -72,6 +72,10 @@ # include #endif +#if defined(CONFIG_NETDEV_IOCTL) && defined(CONFIG_NET_6LOWPAN) +# include +#endif + #include "arp/arp.h" #include "socket/socket.h" #include "netdev/netdev.h" @@ -320,6 +324,67 @@ static void ioctl_set_ipv6addr(FAR net_ipv6addr_t outaddr, } #endif +/**************************************************************************** + * Name: netdev_iee802154_ioctl + * + * Description: + * Perform IEEE802.15.4 network device specific operations. + * + * Parameters: + * psock Socket structure + * dev Ethernet driver device structure + * cmd The ioctl command + * req The argument of the ioctl cmd + * + * Return: + * >=0 on success (positive non-zero values are cmd-specific) + * Negated errno returned on failure. + * + ****************************************************************************/ + +#if defined(CONFIG_NETDEV_IOCTL) && defined(CONFIG_NET_6LOWPAN) +static int netdev_iee802154_ioctl(FAR struct socket *psock, int cmd, + unsigned long arg) +{ + FAR struct net_driver_s *dev; + FAR char *ifname; + int ret = -ENOTTY; + + if (arg != 0ul) + { + if (_MAC802154IOCVALID(cmd)) + { + /* Get the IEEE802.15.4 MAC device to receive the radio IOCTL + * commdand + */ + + FAR struct ieee802154_netmac_s *netmac = + (FAR struct ieee802154_netmac_s *)((uintptr_t)arg); + + ifname = netmac->ifr_name; + } + else + { + /* The IOCTL command is neither */ + + return -ENOTTY; + } + + /* Find the device with this name */ + + dev = netdev_findbyname(ifname); + if (dev != NULL) + { + /* Perform the device IOCTL */ + + ret = dev->d_ioctl(dev, cmd, arg); + } + } + + return ret; +} +#endif + /**************************************************************************** * Name: netdev_wifr_ioctl * @@ -709,7 +774,7 @@ static int netdev_ifr_ioctl(FAR struct socket *psock, int cmd, { req->ifr_hwaddr.sa_family = AF_INETX; memcpy(req->ifr_hwaddr.sa_data, - dev->d_mac.ieee802154.u8, NET_6LOWPAN_RIMEADDR_SIZE); + dev->d_mac.ieee802154.u8, NET_6LOWPAN_ADDRSIZE); } else #endif @@ -747,7 +812,7 @@ static int netdev_ifr_ioctl(FAR struct socket *psock, int cmd, #endif { memcpy(dev->d_mac.ieee802154.u8, - req->ifr_hwaddr.sa_data, NET_6LOWPAN_RIMEADDR_SIZE); + req->ifr_hwaddr.sa_data, NET_6LOWPAN_ADDRSIZE); ret = OK; } else @@ -1192,6 +1257,15 @@ int psock_ioctl(FAR struct socket *psock, int cmd, unsigned long arg) } #endif +#if defined(CONFIG_NETDEV_IOCTL) && defined(CONFIG_NET_6LOWPAN) + /* Check for a IEEE802.15.4 network device command */ + + if (ret == -ENOTTY) + { + ret = netdev_iee802154_ioctl(psock, cmd, arg); + } +#endif + #ifdef CONFIG_NET_IGMP /* Check for address filtering commands */ diff --git a/net/procfs/netdev_statistics.c b/net/procfs/netdev_statistics.c index 5383adfc6a..109f4cdca2 100644 --- a/net/procfs/netdev_statistics.c +++ b/net/procfs/netdev_statistics.c @@ -151,7 +151,7 @@ static int netprocfs_linklayer(FAR struct netprocfs_file_s *netfile) #ifdef CONFIG_NET_6LOWPAN case NET_LL_IEEE802154: { -#ifdef CONFIG_NET_6LOWPAN_RIMEADDR_EXTENDED +#ifdef CONFIG_NET_6LOWPAN_EXTENDEDADDR len += snprintf(&netfile->line[len], NET_LINELEN - len, "%s\tLink encap:6loWPAN HWaddr " "%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x", @@ -213,7 +213,7 @@ static int netprocfs_linklayer(FAR struct netprocfs_file_s *netfile) dev->d_ifname, ether_ntoa(&dev->d_mac.ether), status); #elif defined(CONFIG_NET_6LOWPAN) -#ifdef CONFIG_NET_6LOWPAN_RIMEADDR_EXTENDED +#ifdef CONFIG_NET_6LOWPAN_EXTENDEDADDR len += snprintf(&netfile->line[len], NET_LINELEN - len, "%s\tLink encap:6loWPAN HWaddr " "%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x at %s\n", diff --git a/net/sixlowpan/Kconfig b/net/sixlowpan/Kconfig index 021571fbd0..674eff01f6 100644 --- a/net/sixlowpan/Kconfig +++ b/net/sixlowpan/Kconfig @@ -133,13 +133,13 @@ config NET_6LOWPAN_MAXADDRCONTEXT_PREFIX_2_1 endif # NET_6LOWPAN_MAXADDRCONTEXT_PREINIT_0 endif # NET_6LOWPAN_COMPRESSION_HC06 -config NET_6LOWPAN_RIMEADDR_EXTENDED - bool "Extended Rime address" +config NET_6LOWPAN_EXTENDEDADDR + bool "Extended IEEE 802.15.4 address" default n ---help--- - By default, a 2-byte Rime address is used for the IEEE802.15.4 MAC + By default, a 2-byte short address is used for the IEEE802.15.4 MAC device's link layer address. If this option is selected, then an - 8-byte Rime address will be used. + 8-byte extended address will be used. config NET_6LOWPAN_MAXAGE int "Packet reassembly timeout" @@ -151,6 +151,7 @@ config NET_6LOWPAN_MAXAGE config NET_6LOWPAN_MAX_MACTRANSMITS int "Max MAC transmissions" default 4 + range 1 255 ---help--- CONFIG_NET_6LOWPAN_MAX_MACTRANSMITS specifies how many times the MAC layer should resend packets if no link-layer ACK wasreceived. This diff --git a/net/sixlowpan/README.txt b/net/sixlowpan/README.txt index 5b6b4e298d..9eb848144e 100644 --- a/net/sixlowpan/README.txt +++ b/net/sixlowpan/README.txt @@ -10,12 +10,12 @@ Optimal 6loWPAN Configuration 128 112 96 80 64 48 32 16 ---- ---- ---- ---- ---- ---- ---- ---- - AAAA xxxx xxxx xxxx xxxx 00ff fe00 MMMM 2-byte Rime address IEEE 48-bit MAC - AAAA 0000 0000 0000 NNNN NNNN NNNN NNNN 8-byte Rime address IEEE EUI-64 + AAAA xxxx xxxx xxxx xxxx 00ff fe00 MMMM 2-byte short address IEEE 48-bit MAC + AAAA 0000 0000 0000 NNNN NNNN NNNN NNNN 8-byte extended address IEEE EUI-64 - Where MMM is the 2-byte rime address XORed 0x0200. For example, the MAC + Where MMM is the 2-byte short address XORed 0x0200. For example, the MAC address of 0xabcd would be 0xa9cd. And NNNN NNNN NNNN NNNN is the 8-byte - rime address address XOR 02000 0000 0000 0000. + extended address address XOR 02000 0000 0000 0000. For link-local address, AAAA is 0xfe80 @@ -23,8 +23,8 @@ Optimal 6loWPAN Configuration 128 112 96 80 64 48 32 16 ---- ---- ---- ---- ---- ---- ---- ---- - fe80 0000 0000 0000 0000 00ff fe00 MMMM 2-byte Rime address IEEE 48-bit MAC - fe80 0000 0000 0000 NNNN NNNN NNNN NNNN 8-byte Rime address IEEE EUI-64 + fe80 0000 0000 0000 0000 00ff fe00 MMMM 2-byte short address IEEE 48-bit MAC + fe80 0000 0000 0000 NNNN NNNN NNNN NNNN 8-byte extended address IEEE EUI-64 4. Compressable port numbers in the rangs 0xf0b0-0xf0bf @@ -52,11 +52,11 @@ this is a HC1 compressed first frame of a packet 41 88 2a cefa 3412 cdab ### 9-byte MAC header c50e 000b ### 4-byte FRAG1 header 42 ### SIXLOWPAN_DISPATCH_HC1 - fb ### RIME_HC1_HC_UDP_HC1_ENCODING - e0 ### RIME_HC1_HC_UDP_UDP_ENCODING - 00 ### RIME_HC1_HC_UDP_TTL - 10 ### RIME_HC1_HC_UDP_PORTS - 0000 ### RIME_HC1_HC_UDP_CHKSUM + fb ### SIXLOWPAN_HC1_HC_UDP_HC1_ENCODING + e0 ### SIXLOWPAN_HC1_HC_UDP_UDP_ENCODING + 00 ### SIXLOWPAN_HC1_HC_UDP_TTL + 10 ### SIXLOWPAN_HC1_HC_UDP_PORTS + 0000 ### SIXLOWPAN_HC1_HC_UDP_CHKSUM 104 byte Payload follows: 4f4e452064617920 48656e6e792d7065 6e6e792077617320 7069636b696e6720 @@ -69,11 +69,11 @@ This is the second frame of the same transfer: 41 88 2b cefa 3412 cdab ### 9-byte MAC header e50e 000b 0d ### 5 byte FRAGN header 42 ### SIXLOWPAN_DISPATCH_HC1 - fb ### RIME_HC1_HC_UDP_HC1_ENCODING - e0 ### RIME_HC1_HC_UDP_UDP_ENCODING - 00 ### RIME_HC1_HC_UDP_TTL - 10 ### RIME_HC1_HC_UDP_PORTS - 0000 ### RIME_HC1_HC_UDP_CHKSUM + fb ### SIXLOWPAN_HC1_HC_UDP_HC1_ENCODING + e0 ### SIXLOWPAN_HC1_HC_UDP_UDP_ENCODING + 00 ### SIXLOWPAN_HC1_HC_UDP_TTL + 10 ### SIXLOWPAN_HC1_HC_UDP_PORTS + 0000 ### SIXLOWPAN_HC1_HC_UDP_CHKSUM 104 byte Payload follows: 476f6f646e657373 2067726163696f75 73206d6521272073 6169642048656e6e diff --git a/net/sixlowpan/sixlowpan_framelist.c b/net/sixlowpan/sixlowpan_framelist.c index 9f7a68a1f7..697bec1a81 100644 --- a/net/sixlowpan/sixlowpan_framelist.c +++ b/net/sixlowpan/sixlowpan_framelist.c @@ -55,6 +55,7 @@ #include #include +#include #include "sixlowpan/sixlowpan_internal.h" @@ -77,7 +78,7 @@ */ #if CONFIG_NET_6LOWPAN_MTU > (CONFIG_IOB_BUFSIZE * CONFIG_IOB_NBUFFERS) -# error Not enough IOBs to hold one full IEEE802.14.5 packet +# error Not enough IOBs to hold one full 6LoWPAN packet #endif /**************************************************************************** @@ -183,9 +184,8 @@ static void sixlowpan_compress_ipv6hdr(FAR const struct ipv6_hdr_s *ipv6hdr, * * The payload data is in the caller 'buf' and is of length 'buflen'. * Compressed headers will be added and if necessary the packet is - * fragmented. The resulting packet/fragments are put in ieee->i_framelist - * and the entire list of frames will be delivered to the 802.15.4 MAC via - * ieee->i_framelist. + * fragmented. The resulting packet/fragments are submitted to the MAC + * where they are queue for transfer. * * Input Parameters: * ieee - The IEEE802.15.4 MAC driver instance @@ -209,17 +209,20 @@ static void sixlowpan_compress_ipv6hdr(FAR const struct ipv6_hdr_s *ipv6hdr, int sixlowpan_queue_frames(FAR struct ieee802154_driver_s *ieee, FAR const struct ipv6_hdr_s *destip, FAR const void *buf, size_t buflen, - FAR const struct rimeaddr_s *destmac) + FAR const struct sixlowpan_tagaddr_s *destmac) { + struct packet_metadata_s pktmeta; + struct ieee802154_frame_meta_s meta; FAR struct iob_s *iob; FAR uint8_t *fptr; int framer_hdrlen; - struct rimeaddr_s bcastmac; + struct sixlowpan_tagaddr_s bcastmac; uint16_t pktlen; uint16_t paysize; #ifdef CONFIG_NET_6LOWPAN_FRAG uint16_t outlen = 0; #endif + int ret; /* Initialize global data. Locking the network guarantees that we have * exclusive use of the global values for intermediate calculations. @@ -228,16 +231,14 @@ int sixlowpan_queue_frames(FAR struct ieee802154_driver_s *ieee, g_uncomp_hdrlen = 0; g_frame_hdrlen = 0; - /* Reset rime buffer, packet buffer metatadata */ + /* Reset frame meta data */ - memset(g_pktattrs, 0, PACKETBUF_NUM_ATTRS * sizeof(uint16_t)); - memset(g_pktaddrs, 0, PACKETBUF_NUM_ADDRS * sizeof(struct rimeaddr_s)); - - g_pktattrs[PACKETBUF_ATTR_MAX_MAC_TRANSMISSIONS] = - CONFIG_NET_6LOWPAN_MAX_MACTRANSMITS; + memset(&pktmeta, 0, sizeof(struct packet_metadata_s)); + pktmeta.xmits = CONFIG_NET_6LOWPAN_MAX_MACTRANSMITS; /* Set stream mode for all TCP packets, except FIN packets. */ +#if 0 /* Currently the frame type is always data */ if (destip->proto == IP_PROTO_TCP) { FAR const struct tcp_hdr_s *tcp = @@ -246,13 +247,14 @@ int sixlowpan_queue_frames(FAR struct ieee802154_driver_s *ieee, if ((tcp->flags & TCP_FIN) == 0 && (tcp->flags & TCP_CTL) != TCP_ACK) { - g_pktattrs[PACKETBUF_ATTR_PACKET_TYPE] = PACKETBUF_ATTR_PACKET_TYPE_STREAM; + pktmeta.type = FRAME_ATTR_TYPE_STREAM; } else if ((tcp->flags & TCP_FIN) == TCP_FIN) { - g_pktattrs[PACKETBUF_ATTR_PACKET_TYPE] = PACKETBUF_ATTR_PACKET_TYPE_STREAM_END; + pktmeta.type = FRAME_ATTR_TYPE_STREAM_END; } } +#endif /* The destination address will be tagged to each outbound packet. If the * argument destmac is NULL, we are sending a broadcast packet. @@ -260,7 +262,7 @@ int sixlowpan_queue_frames(FAR struct ieee802154_driver_s *ieee, if (destmac == NULL) { - memset(&bcastmac, 0, sizeof(struct rimeaddr_s)); + memset(&bcastmac, 0, sizeof(struct sixlowpan_tagaddr_s)); destmac = &bcastmac; } @@ -281,24 +283,67 @@ int sixlowpan_queue_frames(FAR struct ieee802154_driver_s *ieee, ninfo("Sending packet length %d\n", buflen); - /* Set the source and destination address */ + /* Set the source and destination address. The source MAC address + * is a fixed size, determined by a configuration setting. The + * destination MAC address many be either short or extended. + */ - rimeaddr_copy(&g_pktaddrs[PACKETBUF_ADDR_SENDER], - &ieee->i_dev.d_mac.ieee802154); - rimeaddr_copy(&g_pktaddrs[PACKETBUF_ADDR_RECEIVER], destmac); +#ifdef CONFIG_NET_6LOWPAN_EXTENDEDADDR + pktmeta.sextended = TRUE; + sixlowpan_eaddrcopy(pktmeta.source.eaddr.u8, + &ieee->i_dev.d_mac.ieee802154); +#else + sixlowpan_saddrcopy(pktmeta.source.saddr.u8, + &ieee->i_dev.d_mac.ieee802154); +#endif + + if (destmac->extended) + { + pktmeta.dextended = TRUE; + sixlowpan_eaddrcopy(pktmeta.dest.eaddr.u8, destmac->u.eaddr.u8); + } + else + { + sixlowpan_saddrcopy(pktmeta.dest.saddr.u8, destmac->u.saddr.u8); + } + + /* Get the destination PAN ID. + * + * REVISIT: For now I am assuming that the source and destination + * PAN IDs are the same. + */ + + pktmeta.dpanid = 0xffff; + (void)sixlowpan_src_panid(ieee, &pktmeta.dpanid); + + /* Based on the collected attributes and addresses, construct the MAC meta + * data structure that we need to interface with the IEEE802.15.4 MAC (we + * will update the MSDU payload size when the IOB has been setup). + */ + + ret = sixlowpan_meta_data(ieee, &pktmeta, &meta, 0); + if (ret < 0) + { + nerr("ERROR: sixlowpan_meta_data() failed: %d\n", ret); + } /* Pre-calculate frame header length. */ - framer_hdrlen = sixlowpan_send_hdrlen(ieee, ieee->i_panid); + framer_hdrlen = sixlowpan_frame_hdrlen(ieee, &meta); if (framer_hdrlen < 0) { /* Failed to determine the size of the header failed. */ - nerr("ERROR: sixlowpan_send_hdrlen() failed: %d\n", framer_hdrlen); + nerr("ERROR: sixlowpan_frame_hdrlen() failed: %d\n", framer_hdrlen); return framer_hdrlen; } - g_frame_hdrlen = framer_hdrlen; + /* This sill be the initial offset into io_data. Valid data begins at + * this offset and must be reflected in io_offset. + */ + + g_frame_hdrlen = framer_hdrlen; + iob->io_offset = framer_hdrlen; #ifndef CONFIG_NET_6LOWPAN_COMPRESSION_IPv6 if (buflen >= CONFIG_NET_6LOWPAN_COMPRESSION_THRESHOLD) @@ -328,15 +373,15 @@ int sixlowpan_queue_frames(FAR struct ieee802154_driver_s *ieee, if (buflen > (CONFIG_NET_6LOWPAN_FRAMELEN - g_frame_hdrlen)) { #ifdef CONFIG_NET_6LOWPAN_FRAG - /* ieee->i_framelist will hold the generated frames; frames will be + /* qhead will hold the generated frame list; frames will be * added at qtail. */ + FAR struct iob_s *qhead; FAR struct iob_s *qtail; FAR uint8_t *frame1; FAR uint8_t *fragptr; uint16_t frag1_hdrlen; - int verify; /* The outbound IPv6 packet is too large to fit into a single 15.4 * packet, so we fragment it into multiple packets and send them. @@ -348,13 +393,6 @@ int sixlowpan_queue_frames(FAR struct ieee802154_driver_s *ieee, ninfo("Sending fragmented packet length %d\n", buflen); /* Create 1st Fragment */ - /* Add the frame header using the pre-allocated IOB using the DSN - * selected by sixlowpan_send_hdrlen(). - */ - - verify = sixlowpan_framecreate(ieee, iob, ieee->i_panid); - DEBUGASSERT(verify == framer_hdrlen); - UNUSED(verify); /* Move HC1/HC06/IPv6 header to make space for the FRAG1 header at the * beginning of the frame. @@ -380,9 +418,9 @@ int sixlowpan_queue_frames(FAR struct ieee802154_driver_s *ieee, */ pktlen = buflen + g_uncomp_hdrlen; - PUTINT16(fragptr, RIME_FRAG_DISPATCH_SIZE, - ((SIXLOWPAN_DISPATCH_FRAG1 << 8) | pktlen)); - PUTINT16(fragptr, RIME_FRAG_TAG, ieee->i_dgramtag); + PUTHOST16(fragptr, SIXLOWPAN_FRAG_DISPATCH_SIZE, + ((SIXLOWPAN_DISPATCH_FRAG1 << 8) | pktlen)); + PUTHOST16(fragptr, SIXLOWPAN_FRAG_TAG, ieee->i_dgramtag); g_frame_hdrlen += SIXLOWPAN_FRAG1_HDR_LEN; @@ -395,8 +433,8 @@ int sixlowpan_queue_frames(FAR struct ieee802154_driver_s *ieee, /* Set outlen to what we already sent from the IP payload */ - iob->io_len = paysize + g_frame_hdrlen; - outlen = paysize; + iob->io_len = paysize + g_frame_hdrlen; + outlen = paysize; ninfo("First fragment: length %d, tag %d\n", paysize, ieee->i_dgramtag); @@ -405,17 +443,17 @@ int sixlowpan_queue_frames(FAR struct ieee802154_driver_s *ieee, /* Add the first frame to the IOB queue */ - ieee->i_framelist = iob; - qtail = iob; + qhead = iob; + qtail = iob; /* Keep track of the total amount of data queue */ - iob->io_pktlen = iob->io_len; + iob->io_pktlen = iob->io_len; /* Create following fragments */ - frame1 = iob->io_data; - frag1_hdrlen = g_frame_hdrlen; + frame1 = iob->io_data; + frag1_hdrlen = g_frame_hdrlen; while (outlen < buflen) { @@ -432,20 +470,10 @@ int sixlowpan_queue_frames(FAR struct ieee802154_driver_s *ieee, iob->io_flink = NULL; iob->io_len = 0; - iob->io_offset = 0; + iob->io_offset = framer_hdrlen; iob->io_pktlen = 0; fptr = iob->io_data; - /* Add a new frame header to the IOB (same as the first but with a - * different DSN). - */ - - g_pktattrs[PACKETBUF_ATTR_MAC_SEQNO] = 0; - - verify = sixlowpan_framecreate(ieee, iob, ieee->i_panid); - DEBUGASSERT(verify == framer_hdrlen); - UNUSED(verify); - /* Copy the HC1/HC06/IPv6 header the frame header from first * frame, into the correct location after the FRAGN header * of subsequent frames. @@ -459,10 +487,10 @@ int sixlowpan_queue_frames(FAR struct ieee802154_driver_s *ieee, /* Setup up the FRAGN header after the frame header. */ - PUTINT16(fragptr, RIME_FRAG_DISPATCH_SIZE, - ((SIXLOWPAN_DISPATCH_FRAGN << 8) | pktlen)); - PUTINT16(fragptr, RIME_FRAG_TAG, ieee->i_dgramtag); - fragptr[RIME_FRAG_OFFSET] = outlen >> 3; + PUTHOST16(fragptr, SIXLOWPAN_FRAG_DISPATCH_SIZE, + ((SIXLOWPAN_DISPATCH_FRAGN << 8) | pktlen)); + PUTHOST16(fragptr, SIXLOWPAN_FRAG_TAG, ieee->i_dgramtag); + fragptr[SIXLOWPAN_FRAG_OFFSET] = outlen >> 3; fragn_hdrlen += SIXLOWPAN_FRAGN_HDR_LEN; @@ -498,7 +526,28 @@ int sixlowpan_queue_frames(FAR struct ieee802154_driver_s *ieee, /* Keep track of the total amount of data queue */ - ieee->i_framelist->io_pktlen += iob->io_len; + qhead->io_pktlen += iob->io_len; + } + + /* Submit all of the fragments to the MAC. We send all frames back- + * to-back like this to minimize any possible condition where some + * frame which is not a fragment from this sequence from intervening. + */ + + for (iob = qhead; iob != NULL; iob = qhead) + { + /* Remove the IOB containing the frame from the list */ + + qhead = iob->io_flink; + iob->io_flink = NULL; + + /* And submit the frame to the MAC */ + + ret = sixlowpan_frame_submit(ieee, &meta, iob); + if (ret < 0) + { + nerr("ERROR: sixlowpan_frame_submit() failed: %d\n", ret); + } } /* Update the datagram TAG value */ @@ -514,34 +563,27 @@ int sixlowpan_queue_frames(FAR struct ieee802154_driver_s *ieee, } else { - int verify; - /* The packet does not need to be fragmented just copy the "payload" * and send in one frame. */ - /* Add the frame header to the preallocated IOB. */ - - verify = sixlowpan_framecreate(ieee, iob, ieee->i_panid); - DEBUGASSERT(verify == framer_hdrlen); - UNUSED(verify); - - /* Copy the payload and queue */ + /* Copy the payload into the frame. */ memcpy(fptr + g_frame_hdrlen, buf, buflen); - iob->io_len = buflen + g_frame_hdrlen; + iob->io_len = buflen + g_frame_hdrlen; + iob->io_pktlen = iob->io_len; ninfo("Non-fragmented: length %d\n", iob->io_len); sixlowpan_dumpbuffer("Outgoing frame", (FAR const uint8_t *)iob->io_data, iob->io_len); - /* Add the first frame to the IOB queue */ + /* And submit the frame to the MAC */ - ieee->i_framelist = iob; - - /* Keep track of the total amount of data queue */ - - iob->io_pktlen = iob->io_len; + ret = sixlowpan_frame_submit(ieee, &meta, iob); + if (ret < 0) + { + nerr("ERROR: sixlowpan_frame_submit() failed: %d\n", ret); + } } return OK; diff --git a/net/sixlowpan/sixlowpan_framer.c b/net/sixlowpan/sixlowpan_framer.c index da52303c6c..d52a5cd30c 100644 --- a/net/sixlowpan/sixlowpan_framer.c +++ b/net/sixlowpan/sixlowpan_framer.c @@ -4,18 +4,6 @@ * Copyright (C) 2017 Gregory Nutt. All rights reserved. * Author: Gregory Nutt * - * Derives from Contiki: - * - * Copyright (c) 2008, Swedish Institute of Computer Science. - * All rights reserved. - * Authors: Adam Dunkels - * Nicolas Tsiftes - * Niclas Finne - * Mathilde Durvy - * Julien Abeille - * Joakim Eriksson - * Joel Hoglund - * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: @@ -23,23 +11,25 @@ * 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 of the Institute nor the names of its contributors - * may be used to endorse or promote products derived from this software + * 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 INSTITUTE 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 INSTITUTE 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. + * 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. * ****************************************************************************/ @@ -52,84 +42,41 @@ #include #include #include +#include #include #include "nuttx/net/net.h" +#include "nuttx/wireless/ieee802154/ieee802154_mac.h" #include "sixlowpan/sixlowpan_internal.h" #ifdef CONFIG_NET_6LOWPAN -/**************************************************************************** - * Private Types - ****************************************************************************/ - -/* Structure that contains the lengths of the various addressing and - * security fields in the 802.15.4 header. - */ - -struct field_length_s -{ - uint8_t dest_pid_len; /* Length (in bytes) of destination PAN ID field */ - uint8_t dest_addr_len; /* Length (in bytes) of destination address field */ - uint8_t src_pid_len; /* Length (in bytes) of source PAN ID field */ - uint8_t src_addr_len; /* Length (in bytes) of source address field */ - uint8_t aux_sec_len; /* Length (in bytes) of aux security header field */ -}; - /**************************************************************************** * Public Functions ****************************************************************************/ /**************************************************************************** - * Name: sixlowpan_addrlen + * Name: sixlowpan_anyaddrnull * * Description: - * Return the address length associated with a 2-bit address mode + * If the destination address is all zero in the MAC header buf, then it is + * broadcast on the 802.15.4 network. * * Input parameters: - * addrmode - The address mode + * addr - The address to check + * addrlen - The length of the address in bytes * * Returned Value: - * The address length associated with the address mode. + * True if the address is all zero. * ****************************************************************************/ -static inline uint8_t sixlowpan_addrlen(uint8_t addrmode) +static bool sixlowpan_anyaddrnull(FAR uint8_t *addr, uint8_t addrlen) { - switch (addrmode) + while (addrlen-- > 0) { - case FRAME802154_SHORTADDRMODE: /* 16-bit address */ - return 2; - case FRAME802154_LONGADDRMODE: /* 64-bit address */ - return 8; - default: - return 0; - } -} - -/**************************************************************************** - * Name: sixlowpan_addrnull - * - * Description: - * If the output address is NULL in the Rime buf, then it is broadcast - * on the 802.15.4 network. - * - * Input parameters: - * addrmode - The address mode - * - * Returned Value: - * The address length associated with the address mode. - * - ****************************************************************************/ - -static bool sixlowpan_addrnull(FAR uint8_t *addr) -{ - int i = NET_6LOWPAN_RIMEADDR_SIZE; - - while (i-- > 0) - { - if (addr[i] != 0x00) + if (addr[addrlen] != 0x00) { return false; } @@ -138,244 +85,44 @@ static bool sixlowpan_addrnull(FAR uint8_t *addr) return true; } - /**************************************************************************** - * Name: sixlowpan_fieldlengths + * Name: sixlowpan_saddrnull * * Description: - * Return the lengths associated fields of the IEEE802.15.4 header. + * If the destination address is all zero in the MAC header buf, then it is + * broadcast on the 802.15.4 network. * * Input parameters: - * finfo - IEEE802.15.4 header info (input) - * flen - Field length info (output) + * eaddr - The short address to check * * Returned Value: - * None + * The address length associated with the address mode. * ****************************************************************************/ -static void sixlowpan_fieldlengths(FAR struct frame802154_s *finfo, - FAR struct field_length_s *flen) +static inline bool sixlowpan_saddrnull(FAR const uint8_t *saddr) { - /* Initialize to all zero */ - - memset(flen, 0, sizeof(struct field_length_s)); - - /* Determine lengths of each field based on fcf and other args */ - - if ((finfo->fcf.dest_addr_mode & 3) != 0) - { - flen->dest_pid_len = 2; - } - - if ((finfo->fcf.src_addr_mode & 3) != 0) - { - flen->src_pid_len = 2; - } - - /* Set PAN ID compression bit if src pan id matches dest pan id. */ - - if ((finfo->fcf.dest_addr_mode & 3) != 0 && - (finfo->fcf.src_addr_mode & 3) != 0 && - finfo->src_pid == finfo->dest_pid) - { - /* Indicate source PANID compression */ - - finfo->fcf.panid_compression = 1; - - /* Compressed header, only do dest pid. - * - * REVISIT: This was commented out in corresponding Contiki logic, but - * is needed to match sixlowpan_recv_hdrlen(). - */ - - flen->src_pid_len = 0; - } - - /* Determine address lengths */ - - flen->dest_addr_len = sixlowpan_addrlen(finfo->fcf.dest_addr_mode & 3); - flen->src_addr_len = sixlowpan_addrlen(finfo->fcf.src_addr_mode & 3); - - /* Aux security header */ - -#if 0 /* TODO Aux security header not yet implemented */ - if ((finfo->fcf.security_enabled & 1) != 0) - { - switch(finfo->aux_hdr.security_control.key_id_mode) - { - case 0: - flen->aux_sec_len = 5; /* Minimum value */ - break; - - case 1: - flen->aux_sec_len = 6; - break; - - case 2: - flen->aux_sec_len = 10; - break; - - case 3: - flen->aux_sec_len = 14; - break; - - default: - break; - } - } -#endif + return sixlowpan_anyaddrnull(saddr, NET_6LOWPAN_SADDRSIZE); } /**************************************************************************** - * Name: sixlowpan_fieldlengths + * Name: sixlowpan_eaddrnull * * Description: - * Return the lengths associated fields of the IEEE802.15.4 header. + * If the destination address is all zero in the MAC header buf, then it is + * broadcast on the 802.15.4 network. * * Input parameters: - * finfo - IEEE802.15.4 header info (input) - * flen - Field length info (output) + * eaddr - The extended address to check * * Returned Value: - * None + * The address length associated with the address mode. * ****************************************************************************/ -static int sixlowpan_flen_hdrlen(FAR const struct field_length_s *flen) +static inline bool sixlowpan_eaddrnull(FAR const uint8_t *eaddr) { - return 3 + flen->dest_pid_len + flen->dest_addr_len + - flen->src_pid_len + flen->src_addr_len + flen->aux_sec_len; -} - -/**************************************************************************** - * Name: sixlowpan_802154_hdrlen - * - * Description: - * Calculates the length of the frame header. This function is meant to - * be called by a higher level function, that interfaces to a MAC. - * - * Input parameters: - * finfo - IEEE802.15.4 header info that specifies the frame to send. - * - * Returned Value: - * The length of the frame header. - * - ****************************************************************************/ - -static int sixlowpan_802154_hdrlen(FAR struct frame802154_s *finfo) -{ - struct field_length_s flen; - - sixlowpan_fieldlengths(finfo, &flen); - return sixlowpan_flen_hdrlen(&flen); -} - -/**************************************************************************** - * Name: sixlowpan_setup_params - * - * Description: - * Configure frame parmeters structure. - * - * Input parameters: - * ieee - A reference IEEE802.15.4 MAC network device structure. - * iob - The IOB in which to create the frame. - * dest_panid - PAN ID of the destination. May be 0xffff if the destination - * is not associated. - * params - Where to put the parmeters - * - * Returned Value: - * None. - * - ****************************************************************************/ - -static void sixlowpan_setup_params(FAR struct ieee802154_driver_s *ieee, - uint16_t dest_panid, - FAR struct frame802154_s *params) -{ - bool rcvrnull; - - /* Initialize all prameters to all zero */ - - memset(params, 0, sizeof(params)); - - /* Build the FCF (Only non-zero elements need to be initialized). */ - - params->fcf.frame_type = FRAME802154_DATAFRAME; - params->fcf.frame_pending = g_pktattrs[PACKETBUF_ATTR_PENDING]; - - /* If the output address is NULL in the Rime buf, then it is broadcast - * on the 802.15.4 network. - */ - - rcvrnull = sixlowpan_addrnull(g_pktaddrs[PACKETBUF_ADDR_RECEIVER].u8); - if (rcvrnull) - { - params->fcf.ack_required = g_pktattrs[PACKETBUF_ATTR_MAC_ACK]; - } - - /* Insert IEEE 802.15.4 (2003) version bit. */ - - params->fcf.frame_version = FRAME802154_IEEE802154_2003; - - /* Increment and set the data sequence number. */ - - if (g_pktattrs[PACKETBUF_ATTR_MAC_SEQNO] != 0) - { - params->seq = g_pktattrs[PACKETBUF_ATTR_MAC_SEQNO] & 0xff; - } - else - { - params->seq = ieee->i_dsn++; - g_pktattrs[PACKETBUF_ATTR_MAC_SEQNO] = params->seq | 0x100; - } - - /* Complete the addressing fields. */ - /* Set the source and destination PAN ID. */ - - params->src_pid = ieee->i_panid; - params->dest_pid = dest_panid; - - /* If the output address is NULL in the Rime buf, then it is broadcast - * on the 802.15.4 network. - */ - - if (rcvrnull) - { - /* Broadcast requires short address mode. */ - - params->fcf.dest_addr_mode = FRAME802154_SHORTADDRMODE; - params->dest_addr[0] = 0xff; - params->dest_addr[1] = 0xff; - } - else - { - /* Copy the destination address */ - - rimeaddr_copy((struct rimeaddr_s *)¶ms->dest_addr, - g_pktaddrs[PACKETBUF_ADDR_RECEIVER].u8); - - /* Use short destination address mode if so configured */ - -#ifdef CONFIG_NET_6LOWPAN_RIMEADDR_EXTENDED - params->fcf.dest_addr_mode = FRAME802154_LONGADDRMODE; -#else - params->fcf.dest_addr_mode = FRAME802154_SHORTADDRMODE; -#endif - } - - /* Set the source address to the node address assigned to the device */ - - rimeaddr_copy((struct rimeaddr_s *)¶ms->src_addr, - &ieee->i_dev.d_mac.ieee802154); - - /* Use short soruce address mode if so configured */ - -#ifdef CONFIG_NET_6LOWPAN_RIMEADDR_EXTENDED - params->fcf.src_addr_mode = FRAME802154_LONGADDRMODE; -#else - params->fcf.src_addr_mode = FRAME802154_SHORTADDRMODE; -#endif + return sixlowpan_anyaddrnull(eaddr, NET_6LOWPAN_EADDRSIZE); } /**************************************************************************** @@ -383,7 +130,115 @@ static void sixlowpan_setup_params(FAR struct ieee802154_driver_s *ieee, ****************************************************************************/ /**************************************************************************** - * Name: sixlowpan_send_hdrlen + * Name: sixlowpan_meta_data + * + * Description: + * Based on the collected attributes and addresses, construct the MAC meta + * data structure that we need to interface with the IEEE802.15.4 MAC. + * + * Input Parameters: + * ieee - IEEE 802.15.4 MAC driver state reference. + * pktmeta - Meta-data specific to the current outgoing frame + * meta - Location to return the corresponding meta data. + * paylen - The size of the data payload to be sent. + * + * Returned Value: + * Ok is returned on success; Othewise a negated errno value is returned. + * + * Assumptions: + * Called with the network locked. + * + ****************************************************************************/ + +int sixlowpan_meta_data(FAR struct ieee802154_driver_s *ieee, + FAR const struct packet_metadata_s *pktmeta, + FAR struct ieee802154_frame_meta_s *meta, + uint16_t paylen) +{ + bool rcvrnull; + + /* Initialize all settings to all zero */ + + memset(meta, 0, sizeof(struct ieee802154_frame_meta_s)); + + /* Source address mode */ + + meta->src_addr_mode = pktmeta->sextended != 0? + IEEE802154_ADDRMODE_EXTENDED : + IEEE802154_ADDRMODE_SHORT; + + /* Check for a broadcast destination address (all zero) */ + + if (pktmeta->dextended != 0) + { + /* Extended destination address mode */ + + rcvrnull = sixlowpan_eaddrnull(pktmeta->dest.eaddr.u8); + } + else + { + /* Short destination address mode */ + + rcvrnull = sixlowpan_saddrnull(pktmeta->dest.saddr.u8); + } + + if (rcvrnull) + { + meta->msdu_flags.ack_tx = TRUE; + } + + /* Destination address */ + + /* If the output address is NULL, then it is broadcast on the 802.15.4 + * network. + */ + + if (rcvrnull) + { + /* Broadcast requires short address mode. */ + + meta->dest_addr.mode = IEEE802154_ADDRMODE_SHORT; + meta->dest_addr.saddr = 0; + } + else if (pktmeta->dextended != 0) + { + /* Extended destination address mode */ + + meta->dest_addr.mode = IEEE802154_ADDRMODE_EXTENDED; + sixlowpan_eaddrcopy(&meta->dest_addr.eaddr, pktmeta->dest.eaddr.u8); + } + else + { + /* Short destination address mode */ + + meta->dest_addr.mode = IEEE802154_ADDRMODE_SHORT; + sixlowpan_saddrcopy(&meta->dest_addr.saddr, pktmeta->dest.saddr.u8); + } + + meta->dest_addr.panid = pktmeta->dpanid; + + /* Handle associated with MSDU. Will increment once per packet, not + * necesarily per frame: The same MSDU handle will be used for each + * fragment of a disassembled packet. + */ + + meta->msdu_handle = ieee->i_msdu_handle++; + +#ifdef CONFIG_IEEE802154_SECURITY +# warning CONFIG_IEEE802154_SECURITY not yet supported +#endif + +#ifdef CONFIG_IEEE802154_UWB +# warning CONFIG_IEEE802154_UWB not yet supported +#endif + + /* Ranging left zero */ + + return OK; +} + +/**************************************************************************** + * Name: sixlowpan_frame_hdrlen * * Description: * This function is before the first frame has been sent in order to @@ -391,9 +246,8 @@ static void sixlowpan_setup_params(FAR struct ieee802154_driver_s *ieee, * buffer is required to make this determination. * * Input parameters: - * ieee - A reference IEEE802.15.4 MAC network device structure. - * dest_panid - PAN ID of the destination. May be 0xffff if the destination - * is not associated. + * ieee - A reference IEEE802.15.4 MAC network device structure. + * meta - Meta data that describes the MAC header * * Returned Value: * The frame header length is returnd on success; otherwise, a negated @@ -401,171 +255,37 @@ static void sixlowpan_setup_params(FAR struct ieee802154_driver_s *ieee, * ****************************************************************************/ -int sixlowpan_send_hdrlen(FAR struct ieee802154_driver_s *ieee, - uint16_t dest_panid) +int sixlowpan_frame_hdrlen(FAR struct ieee802154_driver_s *ieee, + FAR const struct ieee802154_frame_meta_s *meta) { - struct frame802154_s params; - - /* Set up the frame parameters */ - - sixlowpan_setup_params(ieee, dest_panid, ¶ms); - - /* Return the length of the header */ - - return sixlowpan_802154_hdrlen(¶ms); + return ieee->i_get_mhrlen(ieee, meta); } /**************************************************************************** - * Name: sixlowpan_802154_framecreate - * - * Description: - * Creates a frame for transmission over the air. This function is meant - * to be called by a higher level function, that interfaces to a MAC. - * - * Input parameters: - * finfo - Pointer to struct EEE802.15.4 header structure that specifies - * the frame to send. - * buf - Pointer to the buffer to use for the frame. - * buflen - The length of the buffer to use for the frame. - * finfo - Specifies the frame to send. - * - * Returned Value: - * The length of the frame header or 0 if there was insufficient space in - * the buffer for the frame headers. - * - ****************************************************************************/ - -int sixlowpan_802154_framecreate(FAR struct frame802154_s *finfo, - FAR uint8_t *buf, int buflen) -{ - struct field_length_s flen; - uint8_t pos; - int hdrlen; - int i; - - sixlowpan_fieldlengths(finfo, &flen); - - hdrlen = sixlowpan_flen_hdrlen(&flen); - if (hdrlen > buflen) - { - /* Too little space for headers. */ - - return 0; - } - - /* OK, now we have field lengths. Time to actually construct the outgoing - * frame, and store it in the provided buffer - */ - - buf[0] = ((finfo->fcf.frame_type & 7) << FRAME802154_FRAMETYPE_SHIFT) | - ((finfo->fcf.security_enabled & 1) << FRAME802154_SECENABLED_SHIFT) | - ((finfo->fcf.frame_pending & 1) << FRAME802154_FRAMEPENDING_SHIFT) | - ((finfo->fcf.ack_required & 1) << FRAME802154_ACKREQUEST_SHIFT) | - ((finfo->fcf.panid_compression & 1) << FRAME802154_PANIDCOMP_SHIFT); - buf[1] = ((finfo->fcf.dest_addr_mode & 3) << FRAME802154_DSTADDR_SHIFT) | - ((finfo->fcf.frame_version & 3) << FRAME802154_VERSION_SHIFT) | - ((finfo->fcf.src_addr_mode & 3) << FRAME802154_SRCADDR_SHIFT); - - /* Sequence number */ - - buf[2] = finfo->seq; - pos = 3; - - /* Destination PAN ID */ - - if (flen.dest_pid_len == 2) - { - buf[pos++] = finfo->dest_pid & 0xff; - buf[pos++] = (finfo->dest_pid >> 8) & 0xff; - } - - /* Destination address */ - - for (i = flen.dest_addr_len; i > 0; i--) - { - buf[pos++] = finfo->dest_addr[i - 1]; - } - - /* Source PAN ID */ - - if (flen.src_pid_len == 2) - { - buf[pos++] = finfo->src_pid & 0xff; - buf[pos++] = (finfo->src_pid >> 8) & 0xff; - } - - /* Source address */ - - for (i = flen.src_addr_len; i > 0; i--) - { - buf[pos++] = finfo->src_addr[i - 1]; - } - - /* Aux header */ - -#if 0 /* TODO Aux security header not yet implemented */ - if (flen.aux_sec_len) - { - pos += flen.aux_sec_len; - } -#endif - - DEBUGASSERT(pos == hdrlen); - return (int)pos; -} - -/**************************************************************************** - * Name: sixlowpan_framecreate + * Name: sixlowpan_frame_submit * * Description: * This function is called after eiether (1) the IEEE802.15.4 MAC driver - * polls for TX data or (2) after the IEEE802.15.4 MAC driver provides an - * in frame and the network responds with an outgoing packet. It creates - * the IEEE802.15.4 header in the frame buffer. + * polls for TX data or (2) after the IEEE802.15.4 MAC driver provides a + * new incoming frame and the network responds with an outgoing packet. It + * submits any new outgoing frame to the MAC. * * Input parameters: - * ieee - A reference IEEE802.15.4 MAC network device structure. - * iob - The IOB in which to create the frame. - * dest_panid - PAN ID of the destination. May be 0xffff if the destination - * is not associated. + * ieee - A reference IEEE802.15.4 MAC network device structure. + * meta - Meta data that describes the MAC header + * frame - The IOB containing the frame to be submitted. * * Returned Value: - * The frame header length is returnd on success; otherwise, a negated - * errno value is return on failure. + * Zero (OK) is returned on success; otherwise, a negated errno value is + * return on any failure. * ****************************************************************************/ -int sixlowpan_framecreate(FAR struct ieee802154_driver_s *ieee, - FAR struct iob_s *iob, uint16_t dest_panid) +int sixlowpan_frame_submit(FAR struct ieee802154_driver_s *ieee, + FAR const struct ieee802154_frame_meta_s *meta, + FAR struct iob_s *frame) { - struct frame802154_s params; - int hdrlen; - - /* Set up the frame parameters */ - - sixlowpan_setup_params(ieee, dest_panid, ¶ms); - - /* Get the length of the header */ - - hdrlen = sixlowpan_802154_hdrlen(¶ms); - - /* Then create the frame */ - - sixlowpan_802154_framecreate(¶ms, iob->io_data, hdrlen); - - wlinfo("Frame type: %02x hdrlen: %d\n", - params.fcf.frame_type, hdrlen); -#ifdef CONFIG_NET_6LOWPAN_RIMEADDR_EXTENDED - wlinfo("Dest address: %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n", - params.dest_addr[0], params.dest_addr[1], params.dest_addr[2], - params.dest_addr[3], params.dest_addr[4], params.dest_addr[5], - params.dest_addr[6], params.dest_addr[7]); -#else - wlinfo("Dest address: %02x:%02x\n", - params.dest_addr[0], params.dest_addr[1]); -#endif - - return hdrlen; + return ieee->i_req_data(ieee, meta, frame); } #endif /* CONFIG_NET_6LOWPAN */ diff --git a/net/sixlowpan/sixlowpan_globals.c b/net/sixlowpan/sixlowpan_globals.c index aac17f7eb9..6d52082df1 100644 --- a/net/sixlowpan/sixlowpan_globals.c +++ b/net/sixlowpan/sixlowpan_globals.c @@ -67,9 +67,4 @@ uint8_t g_uncomp_hdrlen; uint8_t g_frame_hdrlen; -/* Packet buffer metadata: Attributes and addresses */ - -uint16_t g_pktattrs[PACKETBUF_NUM_ATTRS]; -struct rimeaddr_s g_pktaddrs[PACKETBUF_NUM_ADDRS]; - #endif /* CONFIG_NET_6LOWPAN */ diff --git a/net/sixlowpan/sixlowpan_hc06.c b/net/sixlowpan/sixlowpan_hc06.c index a2ceb53cb6..4de177e0a8 100644 --- a/net/sixlowpan/sixlowpan_hc06.c +++ b/net/sixlowpan/sixlowpan_hc06.c @@ -220,7 +220,7 @@ static FAR struct sixlowpan_addrcontext_s * } /**************************************************************************** - * Name: compress_addr_64 + * Name: comporess_ipaddr, compress_tagaddr, and compress_laddr * * Description: * Uncompress addresses based on a prefix and a postfix with zeroes in @@ -230,20 +230,16 @@ static FAR struct sixlowpan_addrcontext_s * * prefpost takes a byte where the first nibble specify prefix count * and the second postfix count (NOTE: 15/0xf => 16 bytes copy). * + * compress_tagaddr() accepts a remote, variable length, taged MAC address; + * compress_laddr() accepts a local, fixed length MAC address. + * compress_ipaddr() is simply the common logic that does not depend on + * the size of the MAC address. + * ****************************************************************************/ -static uint8_t compress_addr_64(FAR const net_ipv6addr_t ipaddr, - FAR const struct rimeaddr_s *macaddr, - uint8_t bitpos) +static uint8_t compress_ipaddr(FAR const net_ipv6addr_t ipaddr, uint8_t bitpos) { - ninfo("ipaddr=%p macaddr=%p bitpos=%u g_hc06ptr=%p\n", - ipaddr, macaddr, bitpos, g_hc06ptr); - - if (sixlowpan_ismacbased(ipaddr, macaddr)) - { - return 3 << bitpos; /* 0-bits */ - } - else if (SIXLOWPAN_IS_IID_16BIT_COMPRESSABLE(ipaddr)) + if (SIXLOWPAN_IS_IID_16BIT_COMPRESSABLE(ipaddr)) { /* Compress IID to 16 bits: xxxx:xxxx:xxxx:xxxx:0000:00ff:fe00:XXXX */ @@ -261,6 +257,40 @@ static uint8_t compress_addr_64(FAR const net_ipv6addr_t ipaddr, } } +static uint8_t compress_tagaddr(FAR const net_ipv6addr_t ipaddr, + FAR const struct sixlowpan_tagaddr_s *macaddr, + uint8_t bitpos) +{ + ninfo("ipaddr=%p macaddr=%p extended=%u bitpos=%u g_hc06ptr=%p\n", + ipaddr, macaddr, macaddr->extended, bitpos, g_hc06ptr); + + if (sixlowpan_ismacbased(ipaddr, macaddr)) + { + return 3 << bitpos; /* 0-bits */ + } + else + { + return compress_ipaddr(ipaddr, bitpos); + } +} + +static uint8_t compress_laddr(FAR const net_ipv6addr_t ipaddr, + FAR const struct sixlowpan_addr_s *macaddr, + uint8_t bitpos) +{ + ninfo("ipaddr=%p macaddr=%p bitpos=%u g_hc06ptr=%p\n", + ipaddr, macaddr, bitpos, g_hc06ptr); + + if (sixlowpan_isaddrbased(ipaddr, macaddr)) + { + return 3 << bitpos; /* 0-bits */ + } + else + { + return compress_ipaddr(ipaddr, bitpos); + } +} + /**************************************************************************** * Name: uncompress_addr * @@ -275,7 +305,7 @@ static uint8_t compress_addr_64(FAR const net_ipv6addr_t ipaddr, ****************************************************************************/ static void uncompress_addr(FAR net_ipv6addr_t ipaddr, uint8_t const prefix[], - uint8_t prefpost, FAR struct rimeaddr_s *macaddr) + uint8_t prefpost) { uint8_t prefcount = prefpost >> 4; uint8_t postcount = prefpost & 0x0f; @@ -316,7 +346,7 @@ static void uncompress_addr(FAR net_ipv6addr_t ipaddr, uint8_t const prefix[], { /* No IID based configuration if no prefix and no data => unspec */ - sixlowpan_ipfromrime(macaddr, ipaddr); + nwarn("WARNING: No IID based configuration\n"); } ninfo("Uncompressing %d + %d => %04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x\n", @@ -446,7 +476,7 @@ void sixlowpan_hc06_initialize(void) void sixlowpan_compresshdr_hc06(FAR struct ieee802154_driver_s *ieee, FAR const struct ipv6_hdr_s *ipv6, - FAR const struct rimeaddr_s *destmac, + FAR const struct sixlowpan_tagaddr_s *destmac, FAR uint8_t *fptr) { FAR uint8_t *iphc = fptr + g_frame_hdrlen; @@ -614,9 +644,9 @@ void sixlowpan_compresshdr_hc06(FAR struct ieee802154_driver_s *ieee, /* Compression compare with this nodes address (source) */ - iphc1 |= compress_addr_64(ipv6->srcipaddr, - &ieee->i_dev.d_mac.ieee802154, - SIXLOWPAN_IPHC_SAM_BIT); + iphc1 |= compress_laddr(ipv6->srcipaddr, + &ieee->i_dev.d_mac.ieee802154, + SIXLOWPAN_IPHC_SAM_BIT); } /* No address context found for this address */ @@ -625,7 +655,7 @@ void sixlowpan_compresshdr_hc06(FAR struct ieee802154_driver_s *ieee, ipv6->destipaddr[1] == 0 && ipv6->destipaddr[2] == 0 && ipv6->destipaddr[3] == 0) { - iphc1 |= compress_addr_64(ipv6->srcipaddr, + iphc1 |= compress_laddr(ipv6->srcipaddr, &ieee->i_dev.d_mac.ieee802154, SIXLOWPAN_IPHC_SAM_BIT); } @@ -701,7 +731,7 @@ void sixlowpan_compresshdr_hc06(FAR struct ieee802154_driver_s *ieee, /* Compession compare with link adress (destination) */ - iphc1 |= compress_addr_64(ipv6->destipaddr, destmac, + iphc1 |= compress_tagaddr(ipv6->destipaddr, destmac, SIXLOWPAN_IPHC_DAM_BIT); /* No address context found for this address */ @@ -710,7 +740,7 @@ void sixlowpan_compresshdr_hc06(FAR struct ieee802154_driver_s *ieee, ipv6->destipaddr[1] == 0 && ipv6->destipaddr[2] == 0 && ipv6->destipaddr[3] == 0) { - iphc1 |= compress_addr_64(ipv6->destipaddr, destmac, + iphc1 |= compress_tagaddr(ipv6->destipaddr, destmac, SIXLOWPAN_IPHC_DAM_BIT); } else @@ -828,8 +858,8 @@ void sixlowpan_compresshdr_hc06(FAR struct ieee802154_driver_s *ieee, * sixlowpan_buf * * This function is called by the input function when the dispatch is HC06. - * We process the packet in the rime buffer, uncompress the header fields, - * and copy the result in the sixlowpan buffer. At the end of the + * We process the frame in the IOB buffer, uncompress the header fields, + * and copy the result into the driver packet buffer. At the end of the * decompression, g_frame_hdrlen and g_uncompressed_hdrlen are set to the * appropriate values * @@ -983,18 +1013,22 @@ void sixlowpan_uncompresshdr_hc06(uint16_t iplen, FAR struct iob_s *iob, } } - /* If tmp == 0 we do not have a Address context and therefore no prefix */ + /* If tmp == 0 we do not have a address context and therefore no prefix */ + /* REVISIT: Source address may not be the same size as the destination + * address. + */ uncompress_addr(ipv6->srcipaddr, - tmp != 0 ? addrcontext->prefix : NULL, g_unc_ctxconf[tmp], - (FAR struct rimeaddr_s *)&g_pktaddrs[PACKETBUF_ADDR_SENDER]); + tmp != 0 ? addrcontext->prefix : NULL, g_unc_ctxconf[tmp]); } else { /* No compression and link local */ + /* REVISIT: Source address may not be the same size as the destination + * address. + */ - uncompress_addr(ipv6->srcipaddr, g_llprefix, g_unc_llconf[tmp], - (FAR struct rimeaddr_s *)&g_pktaddrs[PACKETBUF_ADDR_SENDER]); + uncompress_addr(ipv6->srcipaddr, g_llprefix, g_unc_llconf[tmp]); } /* Destination address */ @@ -1029,7 +1063,7 @@ void sixlowpan_uncompresshdr_hc06(uint16_t iplen, FAR struct iob_s *iob, g_hc06ptr++; } - uncompress_addr(ipv6->destipaddr, prefix, g_unc_mxconf[tmp], NULL); + uncompress_addr(ipv6->destipaddr, prefix, g_unc_mxconf[tmp]); } } else @@ -1052,15 +1086,13 @@ void sixlowpan_uncompresshdr_hc06(uint16_t iplen, FAR struct iob_s *iob, return; } - uncompress_addr(ipv6->destipaddr, addrcontext->prefix, g_unc_ctxconf[tmp], - (FAR struct rimeaddr_s *)&g_pktaddrs[PACKETBUF_ADDR_RECEIVER]); + uncompress_addr(ipv6->destipaddr, addrcontext->prefix, g_unc_ctxconf[tmp]); } else { /* Not address context based => link local M = 0, DAC = 0 - same as SAC */ - uncompress_addr(ipv6->destipaddr, g_llprefix, g_unc_llconf[tmp], - (FAR struct rimeaddr_s *)&g_pktaddrs[PACKETBUF_ADDR_RECEIVER]); + uncompress_addr(ipv6->destipaddr, g_llprefix, g_unc_llconf[tmp]); } } diff --git a/net/sixlowpan/sixlowpan_hc1.c b/net/sixlowpan/sixlowpan_hc1.c index 3696c4a34f..c6b2f4a137 100644 --- a/net/sixlowpan/sixlowpan_hc1.c +++ b/net/sixlowpan/sixlowpan_hc1.c @@ -120,7 +120,7 @@ void sixlowpan_compresshdr_hc1(FAR struct ieee802154_driver_s *ieee, FAR const struct ipv6_hdr_s *ipv6, - FAR const struct rimeaddr_s *destmac, + FAR const struct sixlowpan_tagaddr_s *destmac, FAR uint8_t *fptr) { FAR uint8_t *hc1 = fptr + g_frame_hdrlen; @@ -129,7 +129,7 @@ void sixlowpan_compresshdr_hc1(FAR struct ieee802154_driver_s *ieee, if (ipv6->vtc != 0x60 || ipv6->tcf != 0 || ipv6->flow != 0 || !sixlowpan_islinklocal(ipv6->srcipaddr) || - !sixlowpan_ismacbased(ipv6->srcipaddr, &ieee->i_dev.d_mac.ieee802154) || + !sixlowpan_isaddrbased(ipv6->srcipaddr, &ieee->i_dev.d_mac.ieee802154) || !sixlowpan_islinklocal(ipv6->destipaddr) || !sixlowpan_ismacbased(ipv6->destipaddr, destmac) || (ipv6->proto != IP_PROTO_ICMP6 && ipv6->proto != IP_PROTO_UDP && @@ -137,12 +137,12 @@ void sixlowpan_compresshdr_hc1(FAR struct ieee802154_driver_s *ieee, { /* IPV6 DISPATCH * Something cannot be compressed, use IPV6 DISPATCH, compress - * nothing, copy IPv6 header in rime buffer + * nothing, copy IPv6 header into the frame buffer */ /* IPv6 dispatch header (1 byte) */ - hc1[RIME_HC1_DISPATCH] = SIXLOWPAN_DISPATCH_IPV6; + hc1[SIXLOWPAN_HC1_DISPATCH] = SIXLOWPAN_DISPATCH_IPV6; g_frame_hdrlen += SIXLOWPAN_IPV6_HDR_LEN; memcpy(fptr + g_frame_hdrlen, ipv6, IPv6_HDRLEN); @@ -156,15 +156,15 @@ void sixlowpan_compresshdr_hc1(FAR struct ieee802154_driver_s *ieee, * header is UDP, we compress UDP header using HC2 */ - hc1[RIME_HC1_DISPATCH] = SIXLOWPAN_DISPATCH_HC1; + hc1[SIXLOWPAN_HC1_DISPATCH] = SIXLOWPAN_DISPATCH_HC1; g_uncomp_hdrlen += IPv6_HDRLEN; switch (ipv6->proto) { case IP_PROTO_ICMP6: /* HC1 encoding and ttl */ - hc1[RIME_HC1_ENCODING] = 0xfc; - hc1[RIME_HC1_TTL] = ipv6->ttl; + hc1[SIXLOWPAN_HC1_ENCODING] = 0xfc; + hc1[SIXLOWPAN_HC1_TTL] = ipv6->ttl; g_frame_hdrlen += SIXLOWPAN_HC1_HDR_LEN; break; @@ -172,8 +172,8 @@ void sixlowpan_compresshdr_hc1(FAR struct ieee802154_driver_s *ieee, case IP_PROTO_TCP: /* HC1 encoding and ttl */ - hc1[RIME_HC1_ENCODING] = 0xfe; - hc1[RIME_HC1_TTL] = ipv6->ttl; + hc1[SIXLOWPAN_HC1_ENCODING] = 0xfe; + hc1[SIXLOWPAN_HC1_TTL] = ipv6->ttl; g_frame_hdrlen += SIXLOWPAN_HC1_HDR_LEN; break; #endif /* CONFIG_NET_TCP */ @@ -201,17 +201,17 @@ void sixlowpan_compresshdr_hc1(FAR struct ieee802154_driver_s *ieee, /* HC1 encoding */ - hcudp[RIME_HC1_HC_UDP_HC1_ENCODING] = 0xfb; + hcudp[SIXLOWPAN_HC1_HC_UDP_HC1_ENCODING] = 0xfb; /* HC_UDP encoding, ttl, src and dest ports, checksum */ - hcudp[RIME_HC1_HC_UDP_UDP_ENCODING] = 0xe0; - hcudp[RIME_HC1_HC_UDP_TTL] = ipv6->ttl; - hcudp[RIME_HC1_HC_UDP_PORTS] = + hcudp[SIXLOWPAN_HC1_HC_UDP_UDP_ENCODING] = 0xe0; + hcudp[SIXLOWPAN_HC1_HC_UDP_TTL] = ipv6->ttl; + hcudp[SIXLOWPAN_HC1_HC_UDP_PORTS] = (uint8_t)((ntohs(udp->srcport) - CONFIG_NET_6LOWPAN_MINPORT) << 4) + (uint8_t)((ntohs(udp->destport) - CONFIG_NET_6LOWPAN_MINPORT)); - memcpy(&hcudp[RIME_HC1_HC_UDP_CHKSUM], &udp->udpchksum, 2); + memcpy(&hcudp[SIXLOWPAN_HC1_HC_UDP_CHKSUM], &udp->udpchksum, 2); g_frame_hdrlen += SIXLOWPAN_HC1_HC_UDP_HDR_LEN; g_uncomp_hdrlen += UDP_HDRLEN; @@ -220,8 +220,8 @@ void sixlowpan_compresshdr_hc1(FAR struct ieee802154_driver_s *ieee, { /* HC1 encoding and ttl */ - hc1[RIME_HC1_ENCODING] = 0xfa; - hc1[RIME_HC1_TTL] = ipv6->ttl; + hc1[SIXLOWPAN_HC1_ENCODING] = 0xfa; + hc1[SIXLOWPAN_HC1_TTL] = ipv6->ttl; g_frame_hdrlen += SIXLOWPAN_HC1_HDR_LEN; } } @@ -238,8 +238,8 @@ void sixlowpan_compresshdr_hc1(FAR struct ieee802154_driver_s *ieee, * Uncompress HC1 (and HC_UDP) headers and put them in sixlowpan_buf * * This function is called by the input function when the dispatch is - * HC1. It processes the packet in the rime buffer, uncompresses the - * header fields, and copies the result in the sixlowpan buffer. At the + * HC1. It processes the frame in the IOB buffer, uncompresses the + * header fields, and copies the result in the packet buffer. At the * end of the decompression, g_frame_hdrlen and uncompressed_hdr_len * are set to the appropriate values * @@ -271,30 +271,22 @@ int sixlowpan_uncompresshdr_hc1(uint16_t iplen, FAR struct iob_s *iob, ipv6->tcf = 0; /* Bits 0-3: traffic class (LS), 4-bits: flow label (MS) */ ipv6->flow = 0; /* 16-bit flow label (LS) */ - /* Use stateless auto-configuration to set source and destination IP - * addresses. - */ - - sixlowpan_ipfromrime(&g_pktaddrs[PACKETBUF_ADDR_SENDER], - ipv6->srcipaddr); - sixlowpan_ipfromrime(&g_pktaddrs[PACKETBUF_ADDR_RECEIVER], - ipv6->destipaddr); g_uncomp_hdrlen += IPv6_HDRLEN; /* len[], proto, and ttl depend on the encoding */ - switch (hc1[RIME_HC1_ENCODING] & 0x06) + switch (hc1[SIXLOWPAN_HC1_ENCODING] & 0x06) { case SIXLOWPAN_HC1_NH_ICMP6: ipv6->proto = IP_PROTO_ICMP6; - ipv6->ttl = hc1[RIME_HC1_TTL]; + ipv6->ttl = hc1[SIXLOWPAN_HC1_TTL]; g_frame_hdrlen += SIXLOWPAN_HC1_HDR_LEN; break; #if CONFIG_NET_TCP case SIXLOWPAN_HC1_NH_TCP: ipv6->proto = IP_PROTO_TCP; - ipv6->ttl = hc1[RIME_HC1_TTL]; + ipv6->ttl = hc1[SIXLOWPAN_HC1_TTL]; g_frame_hdrlen += SIXLOWPAN_HC1_HDR_LEN; break; #endif /* CONFIG_NET_TCP */ @@ -306,11 +298,11 @@ int sixlowpan_uncompresshdr_hc1(uint16_t iplen, FAR struct iob_s *iob, FAR uint8_t *hcudp = fptr + g_frame_hdrlen; ipv6->proto = IP_PROTO_UDP; - if ((hcudp[RIME_HC1_HC_UDP_HC1_ENCODING] & 0x01) != 0) + if ((hcudp[SIXLOWPAN_HC1_HC_UDP_HC1_ENCODING] & 0x01) != 0) { /* UDP header is compressed with HC_UDP */ - if (hcudp[RIME_HC1_HC_UDP_UDP_ENCODING] != + if (hcudp[SIXLOWPAN_HC1_HC_UDP_UDP_ENCODING] != SIXLOWPAN_HC_UDP_ALL_C) { nwarn("WARNING: sixlowpan (uncompress_hdr), packet not supported"); @@ -319,16 +311,16 @@ int sixlowpan_uncompresshdr_hc1(uint16_t iplen, FAR struct iob_s *iob, /* IP TTL */ - ipv6->ttl = hcudp[RIME_HC1_HC_UDP_TTL]; + ipv6->ttl = hcudp[SIXLOWPAN_HC1_HC_UDP_TTL]; /* UDP ports, len, checksum */ udp->srcport = - htons(CONFIG_NET_6LOWPAN_MINPORT + (hcudp[RIME_HC1_HC_UDP_PORTS] >> 4)); + htons(CONFIG_NET_6LOWPAN_MINPORT + (hcudp[SIXLOWPAN_HC1_HC_UDP_PORTS] >> 4)); udp->destport = - htons(CONFIG_NET_6LOWPAN_MINPORT + (hcudp[RIME_HC1_HC_UDP_PORTS] & 0x0F)); + htons(CONFIG_NET_6LOWPAN_MINPORT + (hcudp[SIXLOWPAN_HC1_HC_UDP_PORTS] & 0x0F)); - memcpy(&udp->udpchksum, &hcudp[RIME_HC1_HC_UDP_CHKSUM], 2); + memcpy(&udp->udpchksum, &hcudp[SIXLOWPAN_HC1_HC_UDP_CHKSUM], 2); g_uncomp_hdrlen += UDP_HDRLEN; g_frame_hdrlen += SIXLOWPAN_HC1_HC_UDP_HDR_LEN; diff --git a/net/sixlowpan/sixlowpan_input.c b/net/sixlowpan/sixlowpan_input.c index bccd97677b..9739ab7f61 100644 --- a/net/sixlowpan/sixlowpan_input.c +++ b/net/sixlowpan/sixlowpan_input.c @@ -61,6 +61,7 @@ #include "nuttx/net/netdev.h" #include "nuttx/net/ip.h" #include "nuttx/net/sixlowpan.h" +#include "nuttx/wireless/ieee802154/ieee802154_mac.h" #ifdef CONFIG_NET_PKT # include "pkt/pkt.h" @@ -130,89 +131,52 @@ static uint8_t g_bitbucket[UNCOMP_MAXHDR]; ****************************************************************************/ /**************************************************************************** - * Name: sixlowpan_recv_hdrlen + * Name: sixlowpan_compare_fragsrc * * Description: - * Get the length of the IEEE802.15.4 FCF header on the received frame. + * Check if the fragment that we just received is from the same source as + * the previosly received fragements. * * Input Parameters: - * ieee - The IEEE802.15.4 MAC network driver interface. - * iob - The IOB containing the frame. + * ieee - IEEE 802.15.4 MAC driver state reference + * ind - Characteristics of the newly received frame * * Returned Value: - * Ok is returned on success; Othewise a negated errno value is returned. - * - * Assumptions: - * Network is locked + * true if the sources are the same. * ****************************************************************************/ -int sixlowpan_recv_hdrlen(FAR const uint8_t *fptr) +static bool sixlowpan_compare_fragsrc(FAR struct ieee802154_driver_s *ieee, + FAR const struct ieee802154_data_ind_s *ind) { - uint16_t hdrlen; - uint8_t addrmode; + /* Check for an extended source address */ - /* Minimum header: 2 byte FCF + 1 byte sequence number */ - - hdrlen = 3; - - /* Account for destination address size */ - - addrmode = (fptr[1] & FRAME802154_DSTADDR_MASK) >> FRAME802154_DSTADDR_SHIFT; - if (addrmode == FRAME802154_SHORTADDRMODE) + if (ind->src.mode == IEEE802154_ADDRMODE_EXTENDED) { - /* 2 byte dest PAN + 2 byte dest short address */ + /* Was the first source address also extended? */ - hdrlen += 4; - } - else if (addrmode == FRAME802154_LONGADDRMODE) - { - /* 2 byte dest PAN + 8 byte dest long address */ + if (ieee->i_fragsrc.extended) + { + /* Yes.. perform the extended address comparison */ - hdrlen += 10; - } - else if (addrmode != FRAME802154_NOADDR) - { - nwarn("WARNING: Unrecognized address mode\n"); - - return -ENOSYS; - } - else if ((fptr[0] & (1 << FRAME802154_PANIDCOMP_SHIFT)) != 0) - { - nwarn("WARNING: PAN compression, but no destination address\n"); - - return -EINVAL; - } - - /* Account for source address size */ - - addrmode = (fptr[1] & FRAME802154_SRCADDR_MASK) >> FRAME802154_SRCADDR_SHIFT; - if (addrmode == FRAME802154_NOADDR) - { - return hdrlen; + return sixlowpan_eaddrcmp(ieee->i_fragsrc.u.eaddr.u8, ind->src.eaddr); + } } else { - /* Add source PANID if PANIDs are not compressed */ + /* Short source address. Was the first source address also short? */ - if ((fptr[0] & (1 << FRAME802154_PANIDCOMP_SHIFT)) == 0) + if (!ieee->i_fragsrc.extended) { - hdrlen += 2; - } + /* Yes.. perform the extended short comparison */ - /* Add the length of the source address */ - - if (addrmode == FRAME802154_SHORTADDRMODE) - { - return hdrlen + 2; - } - else if (addrmode == FRAME802154_LONGADDRMODE) - { - return hdrlen + 8; + return sixlowpan_saddrcmp(ieee->i_fragsrc.u.saddr.u8, &ind->src.saddr); } } - return 0; + /* Address are different size and, hence, cannot match */ + + return false; } /**************************************************************************** @@ -245,7 +209,7 @@ static void sixlowpan_uncompress_ipv6hdr(FAR uint8_t *fptr, FAR uint8_t *bptr) { FAR struct ipv6_hdr_s *ipv6 = (FAR struct ipv6_hdr_s *)bptr; uint16_t protosize; - + /* Put uncompressed IPv6 header in d_buf. */ g_frame_hdrlen += SIXLOWPAN_IPV6_HDR_LEN; @@ -321,6 +285,7 @@ static void sixlowpan_uncompress_ipv6hdr(FAR uint8_t *fptr, FAR uint8_t *bptr) * * Input Parameters: * ieee - The IEEE802.15.4 MAC network driver interface. + * ind - Meta data characterizing the received frame. * iob - The IOB containing the frame. * * Returned Value: @@ -332,6 +297,7 @@ static void sixlowpan_uncompress_ipv6hdr(FAR uint8_t *fptr, FAR uint8_t *bptr) ****************************************************************************/ static int sixlowpan_frame_process(FAR struct ieee802154_driver_s *ieee, + FAR const struct ieee802154_data_ind_s *ind, FAR struct iob_s *iob) { FAR uint8_t *fptr; /* Convenience pointer to beginning of the frame */ @@ -355,8 +321,8 @@ static int sixlowpan_frame_process(FAR struct ieee802154_driver_s *ieee, * This size includes both fragmentation and FCF headers. */ - fptr = iob->io_data; - hdrsize = sixlowpan_recv_hdrlen(fptr); + fptr = iob->io_data; /* Frame data is in I/O buffer */ + hdrsize = iob->io_offset; /* Offset past the MAC header */ if (hdrsize < 0) { nwarn("Invalid IEEE802.15.2 header: %d\n", hdrsize); @@ -377,7 +343,7 @@ static int sixlowpan_frame_process(FAR struct ieee802154_driver_s *ieee, */ fragptr = fptr + hdrsize; - switch ((GETINT16(fragptr, RIME_FRAG_DISPATCH_SIZE) & 0xf800) >> 8) + switch ((GETHOST16(fragptr, SIXLOWPAN_FRAG_DISPATCH_SIZE) & 0xf800) >> 8) { /* First fragment of new reassembly */ @@ -385,8 +351,8 @@ static int sixlowpan_frame_process(FAR struct ieee802154_driver_s *ieee, { /* Set up for the reassembly */ - fragsize = GETINT16(fragptr, RIME_FRAG_DISPATCH_SIZE) & 0x07ff; - fragtag = GETINT16(fragptr, RIME_FRAG_TAG); + fragsize = GETHOST16(fragptr, SIXLOWPAN_FRAG_DISPATCH_SIZE) & 0x07ff; + fragtag = GETHOST16(fragptr, SIXLOWPAN_FRAG_TAG); g_frame_hdrlen += SIXLOWPAN_FRAG1_HDR_LEN; ninfo("FRAG1: fragsize=%d fragtag=%d fragoffset=%d\n", @@ -403,9 +369,9 @@ static int sixlowpan_frame_process(FAR struct ieee802154_driver_s *ieee, { /* Set offset, tag, size. Offset is in units of 8 bytes. */ - fragoffset = fragptr[RIME_FRAG_OFFSET]; - fragtag = GETINT16(fragptr, RIME_FRAG_TAG); - fragsize = GETINT16(fragptr, RIME_FRAG_DISPATCH_SIZE) & 0x07ff; + fragoffset = fragptr[SIXLOWPAN_FRAG_OFFSET]; + fragtag = GETHOST16(fragptr, SIXLOWPAN_FRAG_TAG); + fragsize = GETHOST16(fragptr, SIXLOWPAN_FRAG_DISPATCH_SIZE) & 0x07ff; g_frame_hdrlen += SIXLOWPAN_FRAGN_HDR_LEN; ninfo("FRAGN: fragsize=%d fragtag=%d fragoffset=%d\n", @@ -487,8 +453,8 @@ static int sixlowpan_frame_process(FAR struct ieee802154_driver_s *ieee, /* Verify that this fragment is part of that reassembly sequence */ - else if (fragsize != ieee->i_pktlen || ieee->i_reasstag != fragtag || - !rimeaddr_cmp(&ieee->i_fragsrc, &g_pktaddrs[PACKETBUF_ADDR_SENDER])) + else if (fragsize != ieee->i_pktlen || ieee->i_reasstag != fragtag || + !sixlowpan_compare_fragsrc(ieee, ind)) { /* The packet is a fragment that does not belong to the packet * being reassembled or the packet is not a fragment. @@ -540,7 +506,21 @@ static int sixlowpan_frame_process(FAR struct ieee802154_driver_s *ieee, ninfo("Starting reassembly: i_pktlen %u, i_reasstag %d\n", ieee->i_pktlen, ieee->i_reasstag); - rimeaddr_copy(&ieee->i_fragsrc, &g_pktaddrs[PACKETBUF_ADDR_SENDER]); + /* Extract the source address from the 'ind' meta data. NOTE that the + * size of the source address may be different that our local, destination + * address. + */ + + if (ind->src.mode == IEEE802154_ADDRMODE_EXTENDED) + { + ieee->i_fragsrc.extended = true; + sixlowpan_eaddrcopy(ieee->i_fragsrc.u.eaddr.u8, ind->src.eaddr); + } + else + { + memset(&ieee->i_fragsrc, 0, sizeof(struct sixlowpan_tagaddr_s)); + sixlowpan_saddrcopy(ieee->i_fragsrc.u.saddr.u8, &ind->src.saddr); + } } #endif /* CONFIG_NET_6LOWPAN_FRAG */ @@ -549,7 +529,7 @@ static int sixlowpan_frame_process(FAR struct ieee802154_driver_s *ieee, hc1 = fptr + g_frame_hdrlen; #ifdef CONFIG_NET_6LOWPAN_COMPRESSION_HC06 - if ((hc1[RIME_HC1_DISPATCH] & SIXLOWPAN_DISPATCH_IPHC_MASK) == SIXLOWPAN_DISPATCH_IPHC) + if ((hc1[SIXLOWPAN_HC1_DISPATCH] & SIXLOWPAN_DISPATCH_IPHC_MASK) == SIXLOWPAN_DISPATCH_IPHC) { ninfo("IPHC Dispatch\n"); sixlowpan_uncompresshdr_hc06(fragsize, iob, fptr, bptr); @@ -558,7 +538,7 @@ static int sixlowpan_frame_process(FAR struct ieee802154_driver_s *ieee, #endif /* CONFIG_NET_6LOWPAN_COMPRESSION_HC06 */ #ifdef CONFIG_NET_6LOWPAN_COMPRESSION_HC1 - if (hc1[RIME_HC1_DISPATCH] == SIXLOWPAN_DISPATCH_HC1) + if (hc1[SIXLOWPAN_HC1_DISPATCH] == SIXLOWPAN_DISPATCH_HC1) { ninfo("HC1 Dispatch\n"); sixlowpan_uncompresshdr_hc1(fragsize, iob, fptr, bptr); @@ -566,7 +546,7 @@ static int sixlowpan_frame_process(FAR struct ieee802154_driver_s *ieee, else #endif /* CONFIG_NET_6LOWPAN_COMPRESSION_HC1 */ - if (hc1[RIME_HC1_DISPATCH] == SIXLOWPAN_DISPATCH_IPV6) + if (hc1[SIXLOWPAN_HC1_DISPATCH] == SIXLOWPAN_DISPATCH_IPV6) { ninfo("IPv6 Dispatch\n"); sixlowpan_uncompress_ipv6hdr(fptr, bptr); @@ -575,14 +555,13 @@ static int sixlowpan_frame_process(FAR struct ieee802154_driver_s *ieee, { /* Unknown or unsupported header */ - nwarn("WARNING: Unknown dispatch: %u\n", hc1[RIME_HC1_DISPATCH]); + nwarn("WARNING: Unknown dispatch: %u\n", hc1[SIXLOWPAN_HC1_DISPATCH]); return OK; } #ifdef CONFIG_NET_6LOWPAN_FRAG /* Is this the first fragment is a sequence? */ - if (isfirstfrag) { /* Yes.. Remember the offset from the beginning of d_buf where we @@ -603,12 +582,14 @@ static int sixlowpan_frame_process(FAR struct ieee802154_driver_s *ieee, g_uncomp_hdrlen = ieee->i_boffset; } + + #endif /* CONFIG_NET_6LOWPAN_FRAG */ - /* Copy "payload" from the rime buffer to the IEEE802.15.4 MAC driver's - * d_buf. If this frame is a first fragment or not part of a fragmented - * packet, we have already copied the compressed headers, g_uncomp_hdrlen - * and g_frame_hdrlen are non-zerio, fragoffset is. + /* Copy "payload" from the frame buffer to the IEEE802.15.4 MAC driver's + * packet buffer, d_buf. If this frame is a first fragment or not part of + * a fragmented packet, we have already copied the compressed headers, + * g_uncomp_hdrlen and g_frame_hdrlen are non-zerio, fragoffset is. */ paysize = iob->io_len - g_frame_hdrlen; @@ -729,25 +710,32 @@ static int sixlowpan_dispatch(FAR struct ieee802154_driver_s *ieee) * Description: * Process an incoming 6loWPAN frame. * - * This function is called when the device driver has received a 6loWPAN - * frame from the network. The frame from the device driver must be - * provided in a IOB present in the i_framelist: The frame data is in the - * IOB io_data[] buffer and the length of the frame is in the IOB io_len - * field. Only a single IOB is expected in the i_framelist. This incoming - * data will be processed one frame at a time. + * This function is called when the device driver has received an + * IEEE802.15.4 frame from the network. The frame from the device + * driver must be provided in by the IOB frame argument of the + * function call: * - * An non-NULL d_buf of size CONFIG_NET_6LOWPAN_MTU must also be provided. - * The frame will be decompressed and placed in the d_buf. Fragmented - * packets will also be reassembled in the d_buf as they are received - * (meaning for the driver, that two packet buffers are required: One for - * reassembly of RX packets and one used for TX polling). + * - The frame data is in the IOB io_data[] buffer, + * - The length of the frame is in the IOB io_len field, and + * - The offset past the IEEE802.15.4 MAC header is provided in the + * io_offset field. * - * After each frame is processed into d_buf, the IOB is removed and - * deallocated. i_framelist will be nullified. If reassembly is - * incomplete, this function will return to called with i_framelist - * equal to NULL. The partially reassembled packet must be preserved by - * the IEEE802.15.4 MAC and provided again when the next frame is - * received. + * The frame argument may refer to a single frame (a list of length one) + * or may it be the head of a list of multiple frames. + * + * - The io_flink field points to the next frame in the list (if enable) + * - The last frame in the list will have io_flink == NULL. + * + * An non-NULL d_buf of size CONFIG_NET_6LOWPAN_MTU + CONFIG_NET_GUARDSIZE + * must also be provided. The frame will be decompressed and placed in + * the d_buf. Fragmented packets will also be reassembled in the d_buf as + * they are received (meaning for the driver, that two packet buffers are + * required: One for reassembly of RX packets and one used for TX polling). + * + * After each frame is processed into d_buf, the IOB is deallocated. If + * reassembly is incomplete, the partially reassembled packet must be + * preserved by the IEEE802.15.4 MAC network drvier sand provided again + * when the next frame is received. * * When the packet in the d_buf is fully reassembled, it will be provided * to the network as with any other received packet. d_len will be set @@ -755,49 +743,52 @@ static int sixlowpan_dispatch(FAR struct ieee802154_driver_s *ieee) * * After the network processes the packet, d_len will be set to zero. * Network logic may also decide to send a response to the packet. In - * that case, the outgoing network packet will be placed in d_buf the - * d_buf and d_len will be set to a non-zero value. That case is handled - * by this function. + * that case, the outgoing network packet will be placed in d_buf and + * d_len will be set to a non-zero value. That case is handled by this + * function. * * If that case occurs, the packet will be converted to a list of - * compressed and possibly fragmented frames in i_framelist as with other - * TX operations. - * - * So from the standpoint of the IEEE802.15.4 MAC driver, there are two - * possible results: (1) i_framelist is NULL meaning that the frame - * was fully processed and freed, or (2) i_framelist is non-NULL meaning - * that there are outgoing frame(s) to be sent. + * compressed and possibly fragmented frames and provided to the MAC + * network driver via the req_data() method as with other TX operations. * * Input Parameters: - * ieee - The IEEE802.15.4 MAC network driver interface. + * ieee - The IEEE802.15.4 MAC network driver interface. + * framelist - The head of an incoming list of frames. Normally this + * would be a single frame. A list may be provided if + * appropriate, however. + * ind - Meta data characterizing the received frame. If there are + * multilple frames in the list, this meta data must apply to + * all of the frames! * * Returned Value: * Ok is returned on success; Othewise a negated errno value is returned. * ****************************************************************************/ -int sixlowpan_input(FAR struct ieee802154_driver_s *ieee) +int sixlowpan_input(FAR struct ieee802154_driver_s *ieee, + FAR struct iob_s *framelist, + FAR const struct ieee802154_data_ind_s *ind) { int ret = -EINVAL; - DEBUGASSERT(ieee != NULL && !FRAME_IOB_EMPTY(ieee)); + DEBUGASSERT(ieee != NULL && framelist != NULL); - /* Verify that an IOB is provided in the device structure */ + /* Verify that an frame has been provided. */ - while (!FRAME_IOB_EMPTY(ieee)) + while (framelist != NULL) { FAR struct iob_s *iob; /* Remove the IOB containing the frame from the device structure */ - FRAME_IOB_REMOVE(ieee, iob); - DEBUGASSERT(iob != NULL); + iob = framelist; + framelist = iob->io_flink; sixlowpan_dumpbuffer("Incoming frame", iob->io_data, iob->io_len); /* Process the frame, decompressing it into the packet buffer */ - ret = sixlowpan_frame_process(ieee, iob); + ret = sixlowpan_frame_process(ieee, ind, iob); /* Free the IOB the held the consumed frame */ @@ -822,7 +813,7 @@ int sixlowpan_input(FAR struct ieee802154_driver_s *ieee) { FAR struct ipv6_hdr_s *ipv6hdr; FAR uint8_t *buffer; - struct rimeaddr_s destmac; + struct sixlowpan_tagaddr_s destmac; size_t hdrlen; size_t buflen; @@ -833,12 +824,12 @@ int sixlowpan_input(FAR struct ieee802154_driver_s *ieee) ipv6hdr = IPv6BUF(&ieee->i_dev); - /* Get the Rime MAC address of the destination. This - * assumes an encoding of the MAC address in the IPv6 + /* Get the IEEE 802.15.4 MAC address of the destination. + * This assumes an encoding of the MAC address in the IPv6 * address. */ - sixlowpan_rimefromip(ipv6hdr->destipaddr, &destmac); + sixlowpan_addrfromip(ipv6hdr->destipaddr, &destmac); /* The data payload should follow the IPv6 header plus * the protocol header. diff --git a/net/sixlowpan/sixlowpan_internal.h b/net/sixlowpan/sixlowpan_internal.h index a56678c27f..a4dd9b21d0 100644 --- a/net/sixlowpan/sixlowpan_internal.h +++ b/net/sixlowpan/sixlowpan_internal.h @@ -71,79 +71,50 @@ * Pre-processor Definitions ****************************************************************************/ -/* Rime addres macros */ -/* Copy a Rime address */ +/* IEEE 802.15.4 addres macros */ +/* Copy a an IEEE 802.15.4 address */ -#define rimeaddr_copy(dest,src) \ - memcpy(dest, src, NET_6LOWPAN_RIMEADDR_SIZE) +#define sixlowpan_anyaddrcopy(dest,src,len) \ + memcpy(dest, src, len) -/* Compare two Rime addresses */ +#define sixlowpan_saddrcopy(dest,src) \ + sixlowpan_anyaddrcopy(dest,src,NET_6LOWPAN_SADDRSIZE) -#define rimeaddr_cmp(addr1,addr2) \ - (memcmp(addr1, addr2, NET_6LOWPAN_RIMEADDR_SIZE) == 0) +#define sixlowpan_eaddrcopy(dest,src) \ + sixlowpan_anyaddrcopy(dest,src,NET_6LOWPAN_EADDRSIZE) -/* Pointers in the Rime buffer */ +#define sixlowpan_addrcopy(dest,src) \ + sixlowpan_anyaddrcopy(dest,src,NET_6LOWPAN_ADDRSIZE) -/* Packet buffer Definitions */ +/* Compare two IEEE 802.15.4 addresses */ -#define PACKETBUF_ATTR_PACKET_TYPE_DATA 0 -#define PACKETBUF_ATTR_PACKET_TYPE_ACK 1 -#define PACKETBUF_ATTR_PACKET_TYPE_STREAM 2 -#define PACKETBUF_ATTR_PACKET_TYPE_STREAM_END 3 -#define PACKETBUF_ATTR_PACKET_TYPE_TIMESTAMP 4 +#define sixlowpan_anyaddrcmp(addr1,addr2,len) \ + (memcmp(addr1, addr2, len) == 0) -/* Packet buffer attributes (indices into g_pktattrs) */ +#define sixlowpan_saddrcmp(addr1,addr2) \ + sixlowpan_anyaddrcmp(addr1,addr2,NET_6LOWPAN_SADDRSIZE) -#define PACKETBUF_ATTR_NONE 0 +#define sixlowpan_eaddrcmp(addr1,addr2) \ + sixlowpan_anyaddrcmp(addr1,addr2,NET_6LOWPAN_EADDRSIZE) -/* Scope 0 attributes: used only on the local node. */ - -#define PACKETBUF_ATTR_CHANNEL 1 -#define PACKETBUF_ATTR_NETWORK_ID 2 -#define PACKETBUF_ATTR_LINK_QUALITY 3 -#define PACKETBUF_ATTR_RSSI 4 -#define PACKETBUF_ATTR_TIMESTAMP 5 -#define PACKETBUF_ATTR_RADIO_TXPOWER 6 -#define PACKETBUF_ATTR_LISTEN_TIME 7 -#define PACKETBUF_ATTR_TRANSMIT_TIME 8 -#define PACKETBUF_ATTR_MAX_MAC_TRANSMISSIONS 9 -#define PACKETBUF_ATTR_MAC_SEQNO 10 -#define PACKETBUF_ATTR_MAC_ACK 11 - -/* Scope 1 attributes: used between two neighbors only. */ - -#define PACKETBUF_ATTR_RELIABLE 12 -#define PACKETBUF_ATTR_PACKET_ID 13 -#define PACKETBUF_ATTR_PACKET_TYPE 14 -#define PACKETBUF_ATTR_REXMIT 15 -#define PACKETBUF_ATTR_MAX_REXMIT 16 -#define PACKETBUF_ATTR_NUM_REXMIT 17 -#define PACKETBUF_ATTR_PENDING 18 - -/* Scope 2 attributes: used between end-to-end nodes. */ - -#define PACKETBUF_ATTR_HOPS 11 -#define PACKETBUF_ATTR_TTL 20 -#define PACKETBUF_ATTR_EPACKET_ID 21 -#define PACKETBUF_ATTR_EPACKET_TYPE 22 -#define PACKETBUF_ATTR_ERELIABLE 23 - -#define PACKETBUF_NUM_ATTRS 24 - -/* Addresses (indices into g_pktaddrs) */ - -#define PACKETBUF_ADDR_SENDER 0 -#define PACKETBUF_ADDR_RECEIVER 1 -#define PACKETBUF_ADDR_ESENDER 2 -#define PACKETBUF_ADDR_ERECEIVER 3 - -#define PACKETBUF_NUM_ADDRS 4 +#define sixlowpan_addrcmp(addr1,addr2) \ + sixlowpan_anyaddrcmp(addr1,addr2,NET_6LOWPAN_ADDRSIZE) /* General helper macros ****************************************************/ -#define GETINT16(ptr,index) \ +/* GET 16-bit data: source in network order, result in host order */ + +#define GETHOST16(ptr,index) \ ((((uint16_t)((ptr)[index])) << 8) | ((uint16_t)(((ptr)[(index) + 1])))) -#define PUTINT16(ptr,index,value) \ + +/* GET 16-bit data: source in network order, result in network order */ + +#define GETNET16(ptr,index) \ + ((((uint16_t)((ptr)[(index) + 1])) << 8) | ((uint16_t)(((ptr)[index])))) + +/* PUT 16-bit data: source in host order, result in newtwork order */ + +#define PUTHOST16(ptr,index,value) \ do \ { \ (ptr)[index] = ((uint16_t)(value) >> 8) & 0xff; \ @@ -163,7 +134,9 @@ * Public Types ****************************************************************************/ -/* IPv^ TCP/UDP Definitions *************************************************/ +/* IPv6 TCP/UDP/ICMPv6 Definitions ******************************************/ + +#ifdef CONFIG_NET_TCP /* IPv6 + TCP header. Cast compatible based on IPv6 protocol field. */ struct ipv6tcp_hdr_s @@ -171,7 +144,9 @@ struct ipv6tcp_hdr_s struct ipv6_hdr_s ipv6; struct tcp_hdr_s tcp; }; +#endif +#ifdef CONFIG_NET_UDP /* IPv6 + UDP header */ struct ipv6udp_hdr_s @@ -179,7 +154,9 @@ struct ipv6udp_hdr_s struct ipv6_hdr_s ipv6; struct udp_hdr_s udp; }; +#endif +#ifdef CONFIG_NET_ICMPv6 /* IPv6 + ICMPv6 header */ struct ipv6icmp_hdr_s @@ -187,68 +164,28 @@ struct ipv6icmp_hdr_s struct ipv6_hdr_s ipv6; struct icmpv6_iphdr_s icmp; }; +#endif -/* IEEE802.15.4 Frame Definitions *******************************************/ -/* The IEEE 802.15.4 frame has a number of constant/fixed fields that can be - * counted to make frame construction and max payload calculations easier. - * These include: +/* In order to provide a customizable IEEE 802.15.4 MAC header, a structure + * of meta data is passed to the MAC network driver, struct + * ieee802154_frame_meta_s. Many of the settings in this meta data are + * fixed, deterimined by the 6loWPAN configuration. Other settings depend + * on the protocol used in the current packet or on chacteristics of the + * destination node. * - * 1. FCF - 2 bytes - Fixed - * 2. Sequence number - 1 byte - Fixed - * 3. Addressing fields - 4 - 20 bytes - Variable - * 4. Aux security header - 0 - 14 bytes - Variable - * 5. CRC - 2 bytes - Fixed -*/ - -/* Defines the bitfields of the frame control field (FCF). */ - -struct frame802154_fcf_s -{ - uint8_t frame_type; /* 3 bit. Frame type field, see 802.15.4 */ - uint8_t security_enabled; /* 1 bit. True if security is used in this frame */ - uint8_t frame_pending; /* 1 bit. True if sender has more data to send */ - uint8_t ack_required; /* 1 bit. Is an ack frame required? */ - uint8_t panid_compression; /* 1 bit. Is this a compressed header? */ - /* 3 bit. Unused bits */ - uint8_t dest_addr_mode; /* 2 bit. Destination address mode, see 802.15.4 */ - uint8_t frame_version; /* 2 bit. 802.15.4 frame version */ - uint8_t src_addr_mode; /* 2 bit. Source address mode, see 802.15.4 */ -}; - -/* 802.15.4 security control bitfield. See section 7.6.2.2.1 in 802.15.4 - * specification. + * The following structure is used to summarize those per-packet + * customizations and, along, with the fixed configuratin settings, + * determines the full form of that meta data. */ -struct frame802154_scf_s +struct packet_metadata_s { - uint8_t security_level; /* 3 bit. security level */ - uint8_t key_id_mode; /* 2 bit. Key identifier mode */ - uint8_t reserved; /* 3 bit. Reserved bits */ -}; - -/* 802.15.4 Aux security header */ - -struct frame802154_aux_hdr_s -{ - struct frame802154_scf_s security_control; /* Security control bitfield */ - uint32_t frame_counter; /* Frame counter, used for security */ - uint8_t key[9]; /* The key itself, or an index to the key */ -}; - -/* Parameters used by the frame802154_create() function. These parameters - * are used in the 802.15.4 frame header. See the 802.15.4 specification - * for details. - */ - -struct frame802154_s -{ - struct frame802154_fcf_s fcf; /* Frame control field */ - uint8_t seq; /* Sequence number */ - uint16_t dest_pid; /* Destination PAN ID */ - uint8_t dest_addr[8]; /* Destination address */ - uint16_t src_pid; /* Source PAN ID */ - uint8_t src_addr[8]; /* Source address */ - struct frame802154_aux_hdr_s aux_hdr; /* Aux security header */ + uint8_t sextended : 1; /* Extended source address */ + uint8_t dextended : 1; /* Extended destination address */ + uint8_t xmits; /* Max MAC transmisstion */ + uint16_t dpanid; /* Destination PAN ID */ + union sixlowpan_anyaddr_u source; /* Source IEEE 802.15.4 address */ + union sixlowpan_anyaddr_u dest; /* Destination IEEE 802.15.4 address */ }; /**************************************************************************** @@ -262,14 +199,6 @@ struct frame802154_s * during that processing */ -/* A pointer to the rime buffer. - * - * We initialize it to the beginning of the rime buffer, then access - * different fields by updating the offset ieee->g_frame_hdrlen. - */ - -extern FAR uint8_t *g_rimeptr; - /* g_uncomp_hdrlen is the length of the headers before compression (if HC2 * is used this includes the UDP header in addition to the IP header). */ @@ -283,11 +212,6 @@ extern uint8_t g_uncomp_hdrlen; extern uint8_t g_frame_hdrlen; -/* Packet buffer metadata: Attributes and addresses */ - -extern uint16_t g_pktattrs[PACKETBUF_NUM_ATTRS]; -extern struct rimeaddr_s g_pktaddrs[PACKETBUF_NUM_ADDRS]; - /**************************************************************************** * Public Types ****************************************************************************/ @@ -300,7 +224,7 @@ struct net_driver_s; /* Forward reference */ struct ieee802154_driver_s; /* Forward reference */ struct devif_callback_s; /* Forward reference */ struct ipv6_hdr_s; /* Forward reference */ -struct rimeaddr_s; /* Forward reference */ +struct sixlowpan_addr_s; /* Forward reference */ struct iob_s; /* Forward reference */ /**************************************************************************** @@ -313,16 +237,15 @@ struct iob_s; /* Forward reference */ * * The payload data is in the caller 'buf' and is of length 'buflen'. * Compressed headers will be added and if necessary the packet is - * fragmented. The resulting packet/fragments are put in ieee->i_framelist - * and the entire list of frames will be delivered to the 802.15.4 MAC via - * ieee->i_framelist. + * fragmented. The resulting packet/fragments are submitted to the MAC + * via the network driver i_req_data method. * * Input Parameters: * dev - The IEEE802.15.4 MAC network driver interface. * list - Head of callback list for send interrupt * ipv6hdr - IPv6 plus TCP or UDP headers. * buf - Data to send - * buflen - Length of data to send + * len - Length of data to send * raddr - The MAC address of the destination * timeout - Send timeout in deciseconds * @@ -340,11 +263,37 @@ struct iob_s; /* Forward reference */ int sixlowpan_send(FAR struct net_driver_s *dev, FAR struct devif_callback_s **list, FAR const struct ipv6_hdr_s *ipv6hdr, FAR const void *buf, - size_t buflen, FAR const struct rimeaddr_s *raddr, + size_t len, FAR const struct sixlowpan_tagaddr_s *destmac, uint16_t timeout); /**************************************************************************** - * Name: sixlowpan_send_hdrlen + * Name: sixlowpan_meta_data + * + * Description: + * Based on the collected attributes and addresses, construct the MAC meta + * data structure that we need to interface with the IEEE802.15.4 MAC. + * + * Input Parameters: + * ieee - IEEE 802.15.4 MAC driver state reference. + * pktmeta - Meta-data specific to the current outgoing frame + * meta - Location to return the corresponding meta data. + * paylen - The size of the data payload to be sent. + * + * Returned Value: + * Ok is returned on success; Othewise a negated errno value is returned. + * + * Assumptions: + * Called with the network locked. + * + ****************************************************************************/ + +int sixlowpan_meta_data(FAR struct ieee802154_driver_s *ieee, + FAR const struct packet_metadata_s *pktmeta, + FAR struct ieee802154_frame_meta_s *meta, + uint16_t paylen); + +/**************************************************************************** + * Name: sixlowpan_frame_hdrlen * * Description: * This function is before the first frame has been sent in order to @@ -352,9 +301,8 @@ int sixlowpan_send(FAR struct net_driver_s *dev, * buffer is required to make this determination. * * Input parameters: - * ieee - A reference IEEE802.15.4 MAC network device structure. - * dest_panid - PAN ID of the destination. May be 0xffff if the destination - * is not associated. + * ieee - A reference IEEE802.15.4 MAC network device structure. + * meta - Meta data that describes the MAC header * * Returned Value: * The frame header length is returnd on success; otherwise, a negated @@ -362,30 +310,32 @@ int sixlowpan_send(FAR struct net_driver_s *dev, * ****************************************************************************/ -int sixlowpan_send_hdrlen(FAR struct ieee802154_driver_s *ieee, - uint16_t dest_panid); +int sixlowpan_frame_hdrlen(FAR struct ieee802154_driver_s *ieee, + FAR const struct ieee802154_frame_meta_s *meta); /**************************************************************************** - * Name: sixlowpan_framecreate + * Name: sixlowpan_frame_submit * * Description: - * This function is called after the IEEE802.15.4 MAC driver polls for - * TX data. It creates the IEEE802.15.4 header in the frame buffer. + * This function is called after eiether (1) the IEEE802.15.4 MAC driver + * polls for TX data or (2) after the IEEE802.15.4 MAC driver provides a + * new incoming frame and the network responds with an outgoing packet. It + * submits any new outgoing frame to the MAC. * * Input parameters: - * ieee - A reference IEEE802.15.4 MAC network device structure. - * iob - The IOB in which to create the frame. - * dest_panid - PAN ID of the destination. May be 0xffff if the destination - * is not associated. + * ieee - A reference IEEE802.15.4 MAC network device structure. + * meta - Meta data that describes the MAC header + * frame - The IOB containing the frame to be submitted. * * Returned Value: - * The frame header length is returnd on success; otherwise, a negated - * errno value is return on failure. + * Zero (OK) is returned on success; otherwise, a negated errno value is + * return on any failure. * ****************************************************************************/ -int sixlowpan_framecreate(FAR struct ieee802154_driver_s *ieee, - FAR struct iob_s *iob, uint16_t dest_panid); +int sixlowpan_frame_submit(FAR struct ieee802154_driver_s *ieee, + FAR const struct ieee802154_frame_meta_s *meta, + FAR struct iob_s *frame); /**************************************************************************** * Name: sixlowpan_queue_frames @@ -397,9 +347,8 @@ int sixlowpan_framecreate(FAR struct ieee802154_driver_s *ieee, * * The payload data is in the caller 'buf' and is of length 'buflen'. * Compressed headers will be added and if necessary the packet is - * fragmented. The resulting packet/fragments are put in ieee->i_framelist - * and the entire list of frames will be delivered to the 802.15.4 MAC via - * ieee->i_framelist. + * fragmented. The resulting packet/fragments are submitted to the MAC + * via the network driver i_req_data method. * * Input Parameters: * ieee - The IEEE802.15.4 MAC driver instance @@ -423,7 +372,7 @@ int sixlowpan_framecreate(FAR struct ieee802154_driver_s *ieee, int sixlowpan_queue_frames(FAR struct ieee802154_driver_s *ieee, FAR const struct ipv6_hdr_s *ipv6hdr, FAR const void *buf, size_t buflen, - FAR const struct rimeaddr_s *destmac); + FAR const struct sixlowpan_tagaddr_s *destmac); /**************************************************************************** * Name: sixlowpan_hc06_initialize @@ -479,7 +428,7 @@ void sixlowpan_hc06_initialize(void); #ifdef CONFIG_NET_6LOWPAN_COMPRESSION_HC06 void sixlowpan_compresshdr_hc06(FAR struct ieee802154_driver_s *ieee, FAR const struct ipv6_hdr_s *ipv6, - FAR const struct rimeaddr_s *destmac, + FAR const struct sixlowpan_tagaddr_s *destmac, FAR uint8_t *fptr); #endif @@ -491,8 +440,8 @@ void sixlowpan_compresshdr_hc06(FAR struct ieee802154_driver_s *ieee, * sixlowpan_buf * * This function is called by the input function when the dispatch is HC06. - * We process the packet in the rime buffer, uncompress the header fields, - * and copy the result in the sixlowpan buffer. At the end of the + * We process the frame in the IOB buffer, uncompress the header fields, + * and copy the result into the driver packet buffer. At the end of the * decompression, g_frame_hdrlen and g_uncompressed_hdrlen are set to the * appropriate values * @@ -540,7 +489,7 @@ void sixlowpan_uncompresshdr_hc06(uint16_t iplen, FAR struct iob_s *iob, #ifdef CONFIG_NET_6LOWPAN_COMPRESSION_HC1 void sixlowpan_compresshdr_hc1(FAR struct ieee802154_driver_s *ieee, FAR const struct ipv6_hdr_s *ipv6, - FAR const struct rimeaddr_s *destmac, + FAR const struct sixlowpan_tagaddr_s *destmac, FAR uint8_t *fptr); #endif @@ -551,8 +500,8 @@ void sixlowpan_compresshdr_hc1(FAR struct ieee802154_driver_s *ieee, * Uncompress HC1 (and HC_UDP) headers and put them in sixlowpan_buf * * This function is called by the input function when the dispatch is - * HC1. It processes the packet in the rime buffer, uncompresses the - * header fields, and copies the result in the sixlowpan buffer. At the + * HC1. It processes the frame in the IOB buffer, uncompresses the + * header fields, and copies the result in the packet buffer. At the * end of the decompression, g_frame_hdrlen and uncompressed_hdr_len * are set to the appropriate values * @@ -577,34 +526,72 @@ int sixlowpan_uncompresshdr_hc1(uint16_t iplen, FAR struct iob_s *iob, #endif /**************************************************************************** - * Name: sixlowpan_islinklocal, sixlowpan_ipfromrime, sixlowpan_rimefromip, - * and sixlowpan_ismacbased + * Name: sixlowpan_islinklocal, sixlowpan_addrfromip, and + * sixlowpan_ismacbased * * Description: - * sixlowpan_ipfromrime: Create a link local IPv6 address from a rime - * address. + * sixlowpan_addrfromip(): Extract the IEEE 802.15.14 address from a MAC + * based IPv6 address. sixlowpan_addrfromip() is intended to handle a + * tagged address or any size; sixlowpan_saddrfromip() and + * sixlowpan_eaddrfromip() specifically handle short and extended + * addresses. * - * sixlowpan_rimefromip: Extract the rime address from a link local IPv6 - * address. - * - * sixlowpan_islinklocal and sixlowpan_ismacbased will return true for - * address created in this fashion. + * sixlowpan_islinklocal() and sixlowpan_ismacbased() will return true for + * address created in this fashion. sixlowpan_addrfromip() is intended to + * handle a tagged address or any size; sixlowpan_issaddrbased() and + * sixlowpan_iseaddrbased() specifically handle short and extended + * addresses. Local addresses are of a fixed but configurable size and + * sixlowpan_isaddrbased() is for use with such local addresses. * * 128 112 96 80 64 48 32 16 * ---- ---- ---- ---- ---- ---- ---- ---- - * fe80 0000 0000 0000 xxxx 0000 0000 0000 2-byte Rime address (VALID?) - * fe80 0000 0000 0000 xxxx xxxx xxxx xxxx 8-byte Rime address + * fe80 0000 0000 0000 0000 00ff fe00 xxxx 2-byte short address IEEE 48-bit MAC + * fe80 0000 0000 0000 xxxx xxxx xxxx xxxx 8-byte extended address IEEE EUI-64 * ****************************************************************************/ #define sixlowpan_islinklocal(ipaddr) ((ipaddr)[0] == NTOHS(0xfe80)) -void sixlowpan_ipfromrime(FAR const struct rimeaddr_s *rime, - net_ipv6addr_t ipaddr); -void sixlowpan_rimefromip(const net_ipv6addr_t ipaddr, - FAR struct rimeaddr_s *rime); -bool sixlowpan_ismacbased(const net_ipv6addr_t ipaddr, - FAR const struct rimeaddr_s *rime); +void sixlowpan_saddrfromip(const net_ipv6addr_t ipaddr, + FAR struct sixlowpan_saddr_s *saddr); +void sixlowpan_eaddrfromip(const net_ipv6addr_t ipaddr, + FAR struct sixlowpan_eaddr_s *eaddr); +void sixlowpan_addrfromip(const net_ipv6addr_t ipaddr, + FAR struct sixlowpan_tagaddr_s *addr); +bool sixlowpan_issaddrbased(const net_ipv6addr_t ipaddr, + FAR const struct sixlowpan_saddr_s *saddr); +bool sixlowpan_iseaddrbased(const net_ipv6addr_t ipaddr, + FAR const struct sixlowpan_eaddr_s *eaddr); + +#ifdef CONFIG_NET_6LOWPAN_EXTENDEDADDR +# define sixlowpan_isaddrbased(ipaddr,addr) \ + sixlowpan_iseaddrbased(ipaddr,(FAR struct sixlowpan_eaddr_s *)addr) +#else +# define sixlowpan_isaddrbased(ipaddr,addr) \ + sixlowpan_issaddrbased(ipaddr,(FAR struct sixlowpan_saddr_s *)addr) +#endif + +bool sixlowpan_ismacbased(const net_ipv6addr_t ipaddr, + FAR const struct sixlowpan_tagaddr_s *addr); + +/**************************************************************************** + * Name: sixlowpan_src_panid + * + * Description: + * Get the source PAN ID from the IEEE802.15.4 radio. + * + * Input parameters: + * ieee - A reference IEEE802.15.4 MAC network device structure. + * panid - The location in which to return the PAN ID. 0xfff may be + * returned if the device is not associated. + * + * Returned Value: + * Zero (OK) on success; a negated errno value on failure. + * + ****************************************************************************/ + +int sixlowpan_src_panid(FAR struct ieee802154_driver_s *ieee, + FAR uint16_t *panid); #endif /* CONFIG_NET_6LOWPAN */ #endif /* _NET_SIXLOWPAN_SIXLOWPAN_INTERNAL_H */ diff --git a/net/sixlowpan/sixlowpan_send.c b/net/sixlowpan/sixlowpan_send.c index 3ad68554ae..db8337834c 100644 --- a/net/sixlowpan/sixlowpan_send.c +++ b/net/sixlowpan/sixlowpan_send.c @@ -83,7 +83,7 @@ struct sixlowpan_send_s uint16_t s_timeout; /* Send timeout in deciseconds */ systime_t s_time; /* Last send time for determining timeout */ FAR const struct ipv6_hdr_s *s_ipv6hdr; /* IPv6 header, followed by UDP or TCP header. */ - FAR const struct rimeaddr_s *s_destmac; /* Destination MAC address */ + FAR const struct sixlowpan_tagaddr_s *s_destmac; /* Destination MAC address */ FAR const void *s_buf; /* Data to send */ size_t s_len; /* Length of data in buf */ }; @@ -246,11 +246,10 @@ end_wait: * it to be sent on an 802.15.4 network using 6lowpan. Called from common * UDP/TCP send logic. * - * The payload data is in the caller 'buf' and is of length 'len'. + * The payload data is in the caller 'buf' and is of length 'buflen'. * Compressed headers will be added and if necessary the packet is - * fragmented. The resulting packet/fragments are put in ieee->i_framelist - * and the entire list of frames will be delivered to the 802.15.4 MAC via - * ieee->i_framelist. + * fragmented. The resulting packet/fragments are submitted to the MAC + * via the network driver i_req_data method. * * Input Parameters: * dev - The IEEE802.15.4 MAC network driver interface. @@ -275,7 +274,7 @@ end_wait: int sixlowpan_send(FAR struct net_driver_s *dev, FAR struct devif_callback_s **list, FAR const struct ipv6_hdr_s *ipv6hdr, FAR const void *buf, - size_t len, FAR const struct rimeaddr_s *destmac, + size_t len, FAR const struct sixlowpan_tagaddr_s *destmac, uint16_t timeout) { struct sixlowpan_send_s sinfo; diff --git a/net/sixlowpan/sixlowpan_tcpsend.c b/net/sixlowpan/sixlowpan_tcpsend.c index 2bb6c49130..5ae5de0b81 100644 --- a/net/sixlowpan/sixlowpan_tcpsend.c +++ b/net/sixlowpan/sixlowpan_tcpsend.c @@ -164,7 +164,7 @@ ssize_t psock_6lowpan_tcp_send(FAR struct socket *psock, FAR const void *buf, FAR struct tcp_conn_s *conn; FAR struct net_driver_s *dev; struct ipv6tcp_hdr_s ipv6tcp; - struct rimeaddr_s destmac; + struct sixlowpan_tagaddr_s destmac; uint16_t timeout; uint16_t iplen; int ret; @@ -317,11 +317,11 @@ ssize_t psock_6lowpan_tcp_send(FAR struct socket *psock, FAR const void *buf, psock->s_flags = _SS_SETSTATE(psock->s_flags, _SF_SEND); - /* Get the Rime MAC address of the destination This assumes an encoding - * of the MAC address in the IPv6 address. + /* Get the IEEE 802.15.4 MAC address of the destination. This assumes + * an encoding of the MAC address in the IPv6 address. */ - sixlowpan_rimefromip(conn->u.ipv6.raddr, &destmac); + sixlowpan_addrfromip(conn->u.ipv6.raddr, &destmac); /* If routable, then call sixlowpan_send() to format and send the 6loWPAN * packet. @@ -409,16 +409,16 @@ void sixlowpan_tcp_send(FAR struct net_driver_s *dev) } else { - struct rimeaddr_s destmac; + struct sixlowpan_tagaddr_s destmac; FAR uint8_t *buf; uint16_t hdrlen; uint16_t buflen; - /* Get the Rime MAC address of the destination. This assumes an - * encoding of the MAC address in the IPv6 address. + /* Get the IEEE 802.15.4 MAC address of the destination. This + * assumes an encoding of the MAC address in the IPv6 address. */ - sixlowpan_rimefromip(ipv6hdr->ipv6.destipaddr, &destmac); + sixlowpan_addrfromip(ipv6hdr->ipv6.destipaddr, &destmac); /* Get the IPv6 + TCP combined header length. The size of the TCP * header is encoded in the top 4 bits of the tcpoffset field (in diff --git a/net/sixlowpan/sixlowpan_udpsend.c b/net/sixlowpan/sixlowpan_udpsend.c index a29197eec7..7036589e09 100644 --- a/net/sixlowpan/sixlowpan_udpsend.c +++ b/net/sixlowpan/sixlowpan_udpsend.c @@ -162,7 +162,7 @@ ssize_t psock_6lowpan_udp_sendto(FAR struct socket *psock, FAR struct udp_conn_s *conn; FAR struct net_driver_s *dev; struct ipv6udp_hdr_s ipv6udp; - struct rimeaddr_s destmac; + struct sixlowpan_tagaddr_s destmac; uint16_t iplen; uint16_t timeout; int ret; @@ -292,11 +292,11 @@ ssize_t psock_6lowpan_udp_sendto(FAR struct socket *psock, psock->s_flags = _SS_SETSTATE(psock->s_flags, _SF_SEND); - /* Get the Rime MAC address of the destination This assumes an encoding - * of the MAC address in the IPv6 address. + /* Get the IEEE 802.15.4 MAC address of the destination This assumes an + * encoding of the MAC address in the IPv6 address. */ - sixlowpan_rimefromip(to6->sin6_addr.in6_u.u6_addr16, &destmac); + sixlowpan_addrfromip(to6->sin6_addr.in6_u.u6_addr16, &destmac); /* If routable, then call sixlowpan_send() to format and send the 6loWPAN * packet. diff --git a/net/sixlowpan/sixlowpan_utils.c b/net/sixlowpan/sixlowpan_utils.c index dcda6be652..d04ce878c7 100644 --- a/net/sixlowpan/sixlowpan_utils.c +++ b/net/sixlowpan/sixlowpan_utils.c @@ -54,8 +54,10 @@ #include #include #include +#include #include +#include #include "sixlowpan/sixlowpan_internal.h" @@ -66,94 +68,144 @@ ****************************************************************************/ /**************************************************************************** - * Name: sixlowpan_ipfromrime + * Name: sixlowpan_addrfromip * * Description: - * Create a link local IPv6 address from a rime address: + * sixlowpan_addrfromip(): Extract the IEEE 802.15.14 address from a MAC + * based IPv6 address. sixlowpan_addrfromip() is intended to handle a + * tagged address or and size; sixlowpan_saddrfromip() and + * sixlowpan_eaddrfromip() specifically handler short and extended + * addresses. * * 128 112 96 80 64 48 32 16 * ---- ---- ---- ---- ---- ---- ---- ---- - * fe80 0000 0000 0000 0000 00ff fe00 xxxx 2-byte Rime address IEEE 48-bit MAC - * fe80 0000 0000 0000 xxxx xxxx xxxx xxxx 8-byte Rime address IEEE EUI-64 + * xxxx 0000 0000 0000 0000 00ff fe00 xxxx 2-byte short address IEEE 48-bit MAC + * xxxx 0000 0000 0000 xxxx xxxx xxxx xxxx 8-byte extended address IEEE EUI-64 * ****************************************************************************/ -void sixlowpan_ipfromrime(FAR const struct rimeaddr_s *rime, - net_ipv6addr_t ipaddr) +void sixlowpan_saddrfromip(const net_ipv6addr_t ipaddr, + FAR struct sixlowpan_saddr_s *saddr) { - /* We consider only links with IEEE EUI-64 identifier or IEEE 48-bit MAC - * addresses. - */ - - memset(ipaddr, 0, sizeof(net_ipv6addr_t)); - ipaddr[0] = HTONS(0xfe80); - -#ifdef CONFIG_NET_6LOWPAN_RIMEADDR_EXTENDED - memcpy(&ipaddr[4], rime, NET_6LOWPAN_RIMEADDR_SIZE); - ipaddr[4] ^= HTONS(0x0200); -#else - ipaddr[5] = HTONS(0x00ff); - ipaddr[6] = HTONS(0xfe00); - memcpy(&ipaddr[7], rime, NET_6LOWPAN_RIMEADDR_SIZE); - ipaddr[7] ^= HTONS(0x0200); -#endif -} - -/**************************************************************************** - * Name: sixlowpan_rimefromip - * - * Description: - * Extract the rime address from a link local IPv6 address: - * - * 128 112 96 80 64 48 32 16 - * ---- ---- ---- ---- ---- ---- ---- ---- - * fe80 0000 0000 0000 0000 00ff fe00 xxxx 2-byte Rime address IEEE 48-bit MAC - * fe80 0000 0000 0000 xxxx xxxx xxxx xxxx 8-byte Rime address IEEE EUI-64 - * - ****************************************************************************/ - -void sixlowpan_rimefromip(const net_ipv6addr_t ipaddr, - FAR struct rimeaddr_s *rime) -{ - /* REVISIT: See notes about 2 byte addresses in sixlowpan_ipfromrime() */ - DEBUGASSERT(ipaddr[0] == HTONS(0xfe80)); -#ifdef CONFIG_NET_6LOWPAN_RIMEADDR_EXTENDED - memcpy(rime, &ipaddr[4], NET_6LOWPAN_RIMEADDR_SIZE); -#else - memcpy(rime, &ipaddr[7], NET_6LOWPAN_RIMEADDR_SIZE); -#endif - rime->u8[0] ^= 0x02; + memcpy(saddr, &ipaddr[7], NET_6LOWPAN_SADDRSIZE); + saddr->u8[0] ^= 0x02; +} + +void sixlowpan_eaddrfromip(const net_ipv6addr_t ipaddr, + FAR struct sixlowpan_eaddr_s *eaddr) +{ + DEBUGASSERT(ipaddr[0] == HTONS(0xfe80)); + + memcpy(eaddr, &ipaddr[4], NET_6LOWPAN_EADDRSIZE); + eaddr->u8[0] ^= 0x02; +} + +void sixlowpan_addrfromip(const net_ipv6addr_t ipaddr, + FAR struct sixlowpan_tagaddr_s *addr) +{ + DEBUGASSERT(ipaddr[0] == HTONS(0xfe80)); + + if (SIXLOWPAN_IS_IID_16BIT_COMPRESSABLE(ipaddr)) + { + memset(addr, 0, sizeof(struct sixlowpan_tagaddr_s)); + sixlowpan_saddrfromip(ipaddr, &addr->u.saddr); + } + else + { + sixlowpan_eaddrfromip(ipaddr, &addr->u.eaddr); + addr->extended = true; + } } /**************************************************************************** * Name: sixlowpan_ismacbased * * Description: - * Check if the MAC address is encoded in the IP address: + * sixlowpan_ismacbased() will return true for IP addresses formed from + * IEEE802.15.4 MAC addresses. sixlowpan_addrfromip() is intended to + * handle a tagged address or any size; sixlowpan_issaddrbased() and + * sixlowpan_iseaddrbased() specifically handle short and extended + * addresses. Local addresses are of a fixed but configurable size and + * sixlowpan_isaddrbased() is for use with such local addresses. + * * * 128 112 96 80 64 48 32 16 * ---- ---- ---- ---- ---- ---- ---- ---- - * fe80 0000 0000 0000 0000 00ff fe00 xxxx 2-byte Rime address IEEE 48-bit MAC - * fe80 0000 0000 0000 xxxx xxxx xxxx xxxx 8-byte Rime address IEEE EUI-64 + * fe80 0000 0000 0000 0000 00ff fe00 xxxx 2-byte short address IEEE 48-bit MAC + * fe80 0000 0000 0000 xxxx xxxx xxxx xxxx 8-byte extended address IEEE EUI-64 * ****************************************************************************/ -bool sixlowpan_ismacbased(const net_ipv6addr_t ipaddr, - FAR const struct rimeaddr_s *rime) +bool sixlowpan_issaddrbased(const net_ipv6addr_t ipaddr, + FAR const struct sixlowpan_saddr_s *saddr) { - FAR const uint8_t *rimeptr = rime->u8; + FAR const uint8_t *byteptr = saddr->u8; -#ifdef CONFIG_NET_6LOWPAN_RIMEADDR_EXTENDED - return (ipaddr[4] == htons((GETINT16(rimeptr, 0) ^ 0x0200)) && - ipaddr[5] == GETINT16(rimeptr, 2) && - ipaddr[6] == GETINT16(rimeptr, 4) && - ipaddr[7] == GETINT16(rimeptr, 6)); -#else return (ipaddr[5] == HTONS(0x00ff) && ipaddr[6] == HTONS(0xfe00) && - ipaddr[7] == htons((GETINT16(rimeptr, 0) ^ 0x0200))); -#endif + ipaddr[7] == (GETNET16(byteptr, 0) ^ HTONS(0x0200))); +} + +bool sixlowpan_iseaddrbased(const net_ipv6addr_t ipaddr, + FAR const struct sixlowpan_eaddr_s *eaddr) +{ + FAR const uint8_t *byteptr = eaddr->u8; + + return (ipaddr[4] == (GETNET16(byteptr, 0) ^ HTONS(0x0200)) && + ipaddr[5] == GETNET16(byteptr, 2) && + ipaddr[6] == GETNET16(byteptr, 4) && + ipaddr[7] == GETNET16(byteptr, 6)); +} + +bool sixlowpan_ismacbased(const net_ipv6addr_t ipaddr, + FAR const struct sixlowpan_tagaddr_s *addr) +{ + if (addr->extended) + { + return sixlowpan_iseaddrbased(ipaddr, &addr->u.eaddr); + } + else + { + return sixlowpan_issaddrbased(ipaddr, &addr->u.saddr); + } +} + +/**************************************************************************** + * Name: sixlowpan_src_panid + * + * Description: + * Get the source PAN ID from the IEEE802.15.4 MAC layer. + * + * Input parameters: + * ieee - A reference IEEE802.15.4 MAC network device structure. + * panid - The location in which to return the PAN ID. 0xfff may be + * returned if the device is not associated. + * + * Returned Value: + * Zero (OK) on success; a negated errno value on failure. + * + ****************************************************************************/ + +int sixlowpan_src_panid(FAR struct ieee802154_driver_s *ieee, + FAR uint16_t *panid) +{ + FAR struct net_driver_s *dev = &ieee->i_dev; + struct ieee802154_netmac_s arg; + int ret; + + memcpy(arg.ifr_name, ieee->i_dev.d_ifname, IFNAMSIZ); + arg.u.getreq.pib_attr = IEEE802154_PIB_MAC_PAN_ID; + ret = dev->d_ioctl(dev, MAC802154IOC_MLME_GET_REQUEST, + (unsigned long)((uintptr_t)&arg)); + if (ret < 0) + { + wlerr("ERROR: MAC802154IOC_MLME_GET_REQUEST failed: %d\n", ret); + return ret; + } + + *panid = arg.u.getreq.attr_value.mac.panid; + return OK; } #endif /* CONFIG_NET_6LOWPAN */ diff --git a/wireless/Kconfig b/wireless/Kconfig index 440e30a665..75f4ae1289 100644 --- a/wireless/Kconfig +++ b/wireless/Kconfig @@ -6,7 +6,6 @@ config WIRELESS bool "Wireless Support" default n - depends on EXPERIMENTAL ---help--- Enables overall support for Wireless library. diff --git a/wireless/Makefile b/wireless/Makefile index 008d23ff1c..f05d957943 100644 --- a/wireless/Makefile +++ b/wireless/Makefile @@ -52,14 +52,6 @@ VPATH = . include ieee802154$(DELIM)Make.defs -# Include support for various drivers. Each Make.defs file will add its -# files to the source file list, add its DEPPATH info, and will add -# the appropriate paths to the VPATH variable - -ifeq ($(CONFIG_WIRELESS_FORMAT_PCM),y) - CSRCS += pcm_decode.c -endif - AOBJS = $(ASRCS:.S=$(OBJEXT)) COBJS = $(CSRCS:.c=$(OBJEXT)) diff --git a/wireless/ieee802154/Kconfig b/wireless/ieee802154/Kconfig index 228779a5d4..ff64c06d84 100644 --- a/wireless/ieee802154/Kconfig +++ b/wireless/ieee802154/Kconfig @@ -6,19 +6,128 @@ config WIRELESS_IEEE802154 bool "IEEE 802.15.4 Wireless Support" default n - depends on EXPERIMENTAL + select DRIVERS_IOB ---help--- Enables support for the IEEE 802.14.5 Wireless library. if WIRELESS_IEEE802154 +menuconfig IEEE802154_MAC + bool "Generic Media Access Control (MAC) layer for 802.15.4 radios" + default n + depends on WIRELESS_IEEE802154 + ---help--- + Enables a Media Access Controller for any IEEE802.15.4 radio + device. This in turn can be used by higher layer entities + such as 6lowpan. It is not required to use 802.15.4 radios, + but is strongly suggested to ensure exchange of valid frames. + +if IEEE802154_MAC + +config IEEE802154_MAC_DEV + bool "Character driver for IEEE 802.15.4 MAC layer" + default n + depends on IEEE802154_MAC + ---help--- + Enable the device driver to expose the IEEE 802.15.4 MAC layer + access to user space as IOCTLs + +choice + prompt "IEEE 802.15.4 work queue" + default MAC802154_LPWORK if SCHED_LPWORK + default MAC802154_HPWORK if !SCHED_LPWORK && SCHED_HPWORK + depends on SCHED_WORKQUEUE + ---help--- + Work queue support is required to use the IEEE 802.15.4 MAC layer. + If the low priority work queue is available, then it should be used by + the driver. + +config MAC802154_HPWORK + bool "High priority" + depends on SCHED_HPWORK + +config MAC802154_LPWORK + bool "Low priority" + depends on SCHED_LPWORK + +endchoice # Work queue + +config IEEE802154_NTXDESC + int "Number or TX descriptors" + default 3 + ---help--- + Configured number of Tx descriptors. Default: 3 + +endif # IEEE802154_MAC + +config IEEE802154_IND_PREALLOC + int "Number of pre-allocated meta-data structures" + default 20 + ---help--- + This specifies the total number of preallocated meta data structures + must be allocated with each incoming packet. These may be allocated + from either from tasking logic or from interrupt level logic. + +config IEEE802154_IND_IRQRESERVE + int "Rserved pre-allocated meta-data structures" + default 10 + ---help--- + If meta-data structures can be allocated from interrupt handlers, + then this specifies the number of pre-allocatd meta-data structures + that are reserved for for use only by interrupt handlers. This may + be zero to reserve no meta-data structures for interrupt handlers. + In that case, the allocation will fail if tasking logic has + allocated them all. + + Interrupt logic will first attempt to allocate from the general, + pre-allocated structure pool that will contain up to (size + CONFIG_IEEE802154_IND_PREALLOC - CONFIG_IEEE802154_IND_IRQRESERVE) + entries. If that fails, then it will try to take a structure from + the reserve (size CONFIG_IEEE802154_IND_IRQRESERVE). + + Non-interrupt logic will also first attempt to allocate from the + general, pre-allocated structure pool. If that fails, it will + dynamically allocate the meta data structure with an additional cost in performance. + +config IEEE802154_NETDEV + bool "IEEE802154 6loWPAN Network Device" + default n + depends on NET_6LOWPAN && NET_IPv6 + select ARCH_HAVE_NETDEV_STATISTICS + ---help--- + Add support for the IEEE802.15.4 6loWPAN network device built on + the common IEEE802.15.4 MAC. + +if IEEE802154_NETDEV + +choice + prompt "Work queue" + default IEEE802154_NETDEV_LPWORK if SCHED_LPWORK + default IEEE802154_NETDEV_HPWORK if !SCHED_LPWORK && SCHED_HPWORK + depends on SCHED_WORKQUEUE + ---help--- + Work queue support is required to use the IEEE802.15.4 network + driver. If the low priority work queue is available, then it shoul + be used by the loopback driver. + +config IEEE802154_NETDEV_HPWORK + bool "High priority" + depends on SCHED_HPWORK + +config IEEE802154_NETDEV_LPWORK + bool "Low priority" + depends on SCHED_LPWORK + +endchoice # Work queue +endif # IEEE802154_NETDEV + config IEEE802154_LOOPBACK bool "IEEE802154 6loWPAN Loopback" default n depends on NET_6LOWPAN && NET_IPv6 select ARCH_HAVE_NETDEV_STATISTICS ---help--- - Add support for the IEEE802154 6loWPAN Loopback test device. + Add support for the IEEE802.15.4 6loWPAN Loopback test device. if IEEE802154_LOOPBACK diff --git a/wireless/ieee802154/Make.defs b/wireless/ieee802154/Make.defs index 2f5f19967f..73354b2609 100644 --- a/wireless/ieee802154/Make.defs +++ b/wireless/ieee802154/Make.defs @@ -1,7 +1,7 @@ ############################################################################ # wireless/ieee802145/Make.defs # -# Copyright (C) 2016 Gregory Nutt. All rights reserved. +# Copyright (C) 2016-2017 Gregory Nutt. All rights reserved. # Author: Gregory Nutt # # Redistribution and use in source and binary forms, with or without @@ -37,8 +37,26 @@ ifeq ($(CONFIG_WIRELESS_IEEE802154),y) # Include IEEE 802.15.4 support +CSRCS += mac802154_indalloc.c + # Include wireless devices build support +ifeq ($(CONFIG_IEEE802154_MAC),y) +CSRCS += mac802154.c +endif + +ifeq ($(CONFIG_IEEE802154_MAC_DEV),y) +CSRCS += mac802154_device.c +endif + +ifeq ($(CONFIG_IEEE802154_DEV),y) +CSRCS += radio802154_device.c +endif + +ifeq ($(CONFIG_IEEE802154_NETDEV),y) +CSRCS += mac802154_netdev.c +endif + ifeq ($(CONFIG_IEEE802154_LOOPBACK),y) CSRCS += mac802154_loopback.c endif diff --git a/wireless/ieee802154/mac802154.c b/wireless/ieee802154/mac802154.c new file mode 100644 index 0000000000..1da758082c --- /dev/null +++ b/wireless/ieee802154/mac802154.c @@ -0,0 +1,1824 @@ +/**************************************************************************** + * wireless/ieee802154/mac802154.c + * + * Copyright (C) 2016 Sebastien Lorquet. All rights reserved. + * Copyright (C) 2017 Verge Inc. All rights reserved. + * Author: Sebastien Lorquet + * Author: Anthony Merlino + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include +#include +#include +#include + +#include +#include + +#include + +#include +#include + +#include "mac802154.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ +/* Configuration ************************************************************/ +/* If processing is not done at the interrupt level, then work queue support + * is required. + */ + +#if !defined(CONFIG_SCHED_WORKQUEUE) +# error Work queue support is required in this configuration (CONFIG_SCHED_WORKQUEUE) +#else + + /* Use the low priority work queue if possible */ + +# if defined(CONFIG_MAC802154_HPWORK) +# define MAC802154_WORK HPWORK +# elif defined(CONFIG_MAC802154_LPWORK) +# define MAC802154_WORK LPWORK +# else +# error Neither CONFIG_MAC802154_HPWORK nor CONFIG_MAC802154_LPWORK defined +# endif +#endif + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +struct mac802154_txframe_s +{ + /* Supports a singly linked list */ + + FAR struct mac802154_txframe_s *flink; + FAR struct iob_s *frame; + uint8_t msdu_handle; + sem_t sem; +}; + +struct mac802154_unsec_mhr_s +{ + uint8_t length; + union + { + uint16_t frame_control; + uint8_t data[IEEE802154_MAX_UNSEC_MHR_OVERHEAD]; + } u; +}; + +struct mac802154_radiocb_s +{ + struct ieee802154_radiocb_s cb; + FAR struct ieee802154_privmac_s *priv; +}; + +/* The privmac structure holds the internal state of the MAC and is the + * underlying represention of the opaque MACHANDLE. It contains storage for + * the IEEE802.15.4 MIB attributes. + */ + +struct ieee802154_privmac_s +{ + FAR struct ieee802154_radio_s *radio; /* Contained IEEE802.15.4 radio dev */ + FAR const struct ieee802154_maccb_s *cb; /* Contained MAC callbacks */ + FAR struct mac802154_radiocb_s radiocb; /* Interface to bind to radio */ + + sem_t exclsem; /* Support exclusive access */ + + struct work_s tx_work; + struct work_s rx_work; + + /* Support a singly linked list of transactions that will be sent using the + * CSMA algorithm. On a non-beacon enabled PAN, these transactions will be + * sent whenever. On a beacon-enabled PAN, these transactions will be sent + * during the CAP of the Coordinator's superframe. + */ + + FAR struct mac802154_txframe_s *csma_head; + FAR struct mac802154_txframe_s *csma_tail; + + /* Support a singly linked list of transactions that will be sent indirectly. + * This list should only be used by a MAC acting as a coordinator. These + * transactions will stay here until the data is extracted by the destination + * device sending a Data Request MAC command or if too much time passes. This + * list should also be used to populate the address list of the outgoing + * beacon frame. + */ + + FAR struct mac802154_txframe_s *indirect_head; + FAR struct mac802154_txframe_s *indirect_tail; + + uint8_t txdesc_count; + struct ieee802154_txdesc_s txdesc[CONFIG_IEEE802154_NTXDESC]; + + /* Support a singly linked list of frames received */ + FAR struct ieee802154_data_ind_s *dataind_head; + FAR struct ieee802154_data_ind_s *dataind_tail; + + /* MAC PIB attributes, grouped to save memory */ + + /* Holds all address information (Extended, Short, and PAN ID) for the MAC. */ + + struct ieee802154_addr_s addr; + + /* Holds all address information (Extended, Short) for Coordinator */ + + struct ieee802154_addr_s coord_addr; + + /* The maximum number of symbols to wait for an acknowledgement frame to + * arrive following a transmitted data frame. [1] pg. 126 + * + * NOTE: This may be able to be a 16-bit or even an 8-bit number. I wasn't + * sure at the time what the range of reasonable values was. + */ + + uint32_t ack_wait_dur; + + /* The maximum time to wait either for a frame intended as a response to a + * data request frame or for a broadcast frame following a beacon with the + * Frame Pending field set to one. [1] pg. 127 + * + * NOTE: This may be able to be a 16-bit or even an 8-bit number. I wasn't + * sure at the time what the range of reasonable values was. + */ + + uint32_t max_frame_wait_time; + + /* The maximum time (in unit periods) that a transaction is stored by a + * coordinator and indicated in its beacon. + */ + + uint16_t trans_persist_time; + + /* Contents of beacon payload */ + + uint8_t beacon_payload[IEEE802154_MAX_BEACON_PAYLOAD_LEN]; + uint8_t beacon_payload_len; /* Length of beacon payload */ + + uint8_t batt_life_ext_periods; /* # of backoff periods during which rx is + * enabled after the IFS following beacon */ + + uint8_t bsn; /* Seq. num added to tx beacon frame */ + uint8_t dsn; /* Seq. num added to tx data or MAC frame */ + uint8_t max_retries; /* Max # of retries alloed after tx failure */ + + /* The maximum time, in multiples of aBaseSuperframeDuration, a device shall + * wait for a response command frame to be available following a request + * command frame. [1] 128. + */ + + uint8_t resp_wait_time; + + /* The total transmit duration (including PHY header and FCS) specified in + * symbols. [1] pg. 129. + */ + + uint32_t tx_total_dur; + + /* Start of 32-bit bitfield */ + + uint32_t is_assoc : 1; /* Are we associated to the PAN */ + uint32_t assoc_permit : 1; /* Are we allowing assoc. as a coord. */ + uint32_t auto_req : 1; /* Automatically send data req. if addr + * addr is in the beacon frame */ + + uint32_t batt_life_ext : 1; /* Is BLE enabled */ + uint32_t gts_permit : 1; /* Is PAN Coord. accepting GTS reqs. */ + uint32_t promisc_mode : 1; /* Is promiscuous mode on? */ + uint32_t rng_support : 1; /* Does MAC sublayer support ranging */ + uint32_t rx_when_idle : 1; /* Recvr. on during idle periods */ + uint32_t sec_enabled : 1; /* Does MAC sublayer have security en. */ + + uint32_t max_csma_backoffs : 3; /* Max num backoffs for CSMA algorithm + * before declaring ch access failure */ + + uint32_t beacon_order : 4; /* Freq. that beacon is transmitted */ + + uint32_t superframe_order : 4; /* Length of active portion of outgoing + * superframe, including the beacon */ + + /* The offset, measured is symbols, between the symbol boundary at which the + * MLME captures the timestamp of each transmitted and received frame, and + * the onset of the first symbol past the SFD, namely the first symbol of + * the frames [1] pg. 129. + */ + + uint32_t sync_symb_offset : 12; + + /* End of 32-bit bitfield */ + + /* Start of 32-bit bitfield */ + + uint32_t beacon_tx_time : 24; /* Time of last beacon transmit */ + uint32_t min_be : 4; /* Min value of backoff exponent (BE) */ + uint32_t max_be : 4; /* Max value of backoff exponent (BE) */ + + /* End of 32-bit bitfield */ + + /* Start of 32-bit bitfield */ + + uint32_t tx_ctrl_active_dur : 17; /* Duration for which tx is permitted to + * be active */ + uint32_t tx_ctrl_pause_dur : 1; /* Duration after tx before another tx is + * permitted. 0=2000, 1= 10000 */ + uint32_t timestamp_support : 1; /* Does MAC layer supports timestamping */ + uint32_t is_coord : 1; /* Is this device acting as coordinator */ + /* 12-bits remaining */ + + /* End of 32-bit bitfield. */ + + /* TODO: Add Security-related MAC PIB attributes */ +}; + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +static inline int mac802154_takesem(sem_t *sem); +#define mac802154_givesem(s) sem_post(s); + +static void mac802154_txdone_worker(FAR void *arg); +static void mac802154_rxframe_worker(FAR void *arg); + +/* Internal Functions */ + +static int mac802154_defaultmib(FAR struct ieee802154_privmac_s *priv); +static int mac802154_applymib(FAR struct ieee802154_privmac_s *priv); + +/* IEEE 802.15.4 PHY Interface OPs */ + +static int mac802154_poll_csma(FAR const struct ieee802154_radiocb_s *radiocb, + FAR struct ieee802154_txdesc_s *tx_desc, + FAR struct iob_s **frame); + +static int mac802154_poll_gts(FAR const struct ieee802154_radiocb_s *radiocb, + FAR struct ieee802154_txdesc_s *tx_desc, + FAR struct iob_s **frame); + +static void mac802154_txdone(FAR const struct ieee802154_radiocb_s *radiocb, + FAR const struct ieee802154_txdesc_s *tx_desc); + +static void mac802154_rxframe(FAR const struct ieee802154_radiocb_s *radiocb, + FAR struct ieee802154_data_ind_s *ind); + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/* Map between ieee802154_addr_mode_e enum and actual address length */ + +static const uint8_t mac802154_addr_length[4] = {0, 0, 2, 8}; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: mac802154_semtake + * + * Description: + * Acquire the semaphore used for access serialization. + * + ****************************************************************************/ + +static inline int mac802154_takesem(sem_t *sem) +{ + /* Take a count from the semaphore, possibly waiting */ + + if (sem_wait(sem) < 0) + { + /* EINTR is the only error that we expect */ + + int errcode = get_errno(); + DEBUGASSERT(errcode == EINTR); + return -errcode; + } + + return OK; +} + +/**************************************************************************** + * Name: mac802154_push_csma + * + * Description: + * Push a CSMA transaction onto the list + * + ****************************************************************************/ + +static void mac802154_push_csma(FAR struct ieee802154_privmac_s *priv, + FAR struct mac802154_txframe_s *trans) +{ + /* Ensure the transactions forward link is NULL */ + + trans->flink = NULL; + + /* If the tail is not empty, make the transaction pointed to by the tail, + * point to the new transaction */ + + if (priv->csma_tail != NULL) + { + priv->csma_tail->flink = trans; + } + + /* Point the tail at the new transaction */ + + priv->csma_tail = trans; + + /* If the head is NULL, we need to point it at the transaction since there + * is only one transaction in the list at this point */ + + if (priv->csma_head == NULL) + { + priv->csma_head = trans; + } +} + +/**************************************************************************** + * Name: mac802154_pop_csma + * + * Description: + * Pop a CSMA transaction from the list + * + ****************************************************************************/ + +static FAR struct mac802154_txframe_s * + mac802154_pop_csma(FAR struct ieee802154_privmac_s *priv) +{ + FAR struct mac802154_txframe_s *trans; + + if (priv->csma_head == NULL) + { + return NULL; + } + + /* Get the transaction from the head of the list */ + + trans = priv->csma_head; + trans->flink = NULL; + + /* Move the head pointer to the next transaction */ + + priv->csma_head = trans->flink; + + /* If the head is now NULL, the list is empty, so clear the tail too */ + + if (priv->csma_head == NULL) + { + priv->csma_tail = NULL; + } + + return trans; +} + +/**************************************************************************** + * Name: mac802154_push_dataind + * + * Description: + * Push a data indication onto the list to be processed + * + ****************************************************************************/ + +static void mac802154_push_dataind(FAR struct ieee802154_privmac_s *priv, + FAR struct ieee802154_data_ind_s *ind) +{ + /* Ensure the forward link is NULL */ + + ind->flink = NULL; + + /* If the tail is not empty, make the frame pointed to by the tail, + * point to the new data indication */ + + if (priv->dataind_tail != NULL) + { + priv->dataind_tail->flink = ind; + } + + /* Point the tail at the new frame */ + + priv->dataind_tail = ind; + + /* If the head is NULL, we need to point it at the data indication since there + * is only one indication in the list at this point */ + + if (priv->dataind_head == NULL) + { + priv->dataind_head = ind; + } +} + +/**************************************************************************** + * Name: mac802154_pop_dataind + * + * Description: + * Pop a data indication from the list + * + ****************************************************************************/ + +static FAR struct ieee802154_data_ind_s * + mac802154_pop_dataind(FAR struct ieee802154_privmac_s *priv) +{ + FAR struct ieee802154_data_ind_s *ind; + + if (priv->dataind_head == NULL) + { + return NULL; + } + + /* Get the data indication from the head of the list */ + + ind = priv->dataind_head; + ind->flink = NULL; + + /* Move the head pointer to the next data indication */ + + priv->dataind_head = ind->flink; + + /* If the head is now NULL, the list is empty, so clear the tail too */ + + if (priv->dataind_head == NULL) + { + priv->dataind_tail = NULL; + } + + return ind; +} + +/**************************************************************************** + * Name: mac802154_defaultmib + * + * Description: + * Set the MIB to its default values. + * + ****************************************************************************/ + +static int mac802154_defaultmib(FAR struct ieee802154_privmac_s *priv) +{ + priv->is_assoc = false; /* Not associated with a PAN */ + priv->assoc_permit = false; /* Device (if coord) not accepting association */ + priv->auto_req = true; /* Auto send data req if addr. in beacon */ + priv->batt_life_ext = false; /* BLE disabled */ + priv->beacon_payload_len = 0; /* Beacon payload NULL */ + priv->beacon_order = 15; /* Non-beacon enabled network */ + priv->superframe_order = 15; /* Length of active portion of outgoing SF */ + priv->beacon_tx_time = 0; /* Device never sent a beacon */ +#warning Set BSN and DSN to random values! + priv->bsn = 0; + priv->dsn = 0; + priv->gts_permit = true; /* PAN Coord accepting GTS requests */ + priv->min_be = 3; /* Min value of backoff exponent (BE) */ + priv->max_be = 5; /* Max value of backoff exponent (BE) */ + priv->max_csma_backoffs = 4; /* Max # of backoffs before failure */ + priv->max_retries = 3; /* Max # of retries allowed after failure */ + priv->promisc_mode = false; /* Device not in promiscuous mode */ + priv->rng_support = false; /* Ranging not yet supported */ + priv->resp_wait_time = 32; /* 32 SF durations */ + priv->rx_when_idle = false; /* Don't receive while idle */ + priv->sec_enabled = false; /* Security disabled by default */ + priv->tx_total_dur = 0; /* 0 transmit duration */ + + priv->trans_persist_time = 0x01F4; + + + /* Reset the Coordinator address */ + + priv->coord_addr.mode = IEEE802154_ADDRMODE_NONE; + priv->coord_addr.saddr = IEEE802154_SADDR_UNSPEC; + memcpy(&priv->coord_addr.eaddr[0], IEEE802154_EADDR_UNSPEC, + IEEE802154_EADDR_LEN); + + /* Reset the device's address */ + + priv->addr.mode = IEEE802154_ADDRMODE_NONE; + priv->addr.panid = IEEE802154_PAN_UNSPEC; + priv->addr.saddr = IEEE802154_SADDR_UNSPEC; + memcpy(&priv->addr.eaddr[0], IEEE802154_EADDR_UNSPEC, IEEE802154_EADDR_LEN); + + + /* 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 + */ + + return OK; +} + +/**************************************************************************** + * Name: mac802154_applymib + * + * Description: + * Some parts of the MIB must be sent to the radio device. This routine + * calls the radio device routines to store the related parameters in the + * radio driver. It must be called each time a MIB parameter is changed. + * + ****************************************************************************/ + +static int mac802154_applymib(FAR struct ieee802154_privmac_s *priv) +{ + return OK; +} + +/**************************************************************************** + * Name: mac802154_poll_csma + * + * Description: + * Called from the radio driver through the callback struct. This function is + * called when the radio has room for another CSMA transaction. If the MAC + * layer has a CSMA transaction, it copies it into the supplied buffer and + * returns the length. A descriptor is also populated with the transaction. + * + ****************************************************************************/ + +static int mac802154_poll_csma(FAR const struct ieee802154_radiocb_s *radiocb, + FAR struct ieee802154_txdesc_s *tx_desc, + FAR struct iob_s **frame) +{ + FAR struct mac802154_radiocb_s *cb = + (FAR struct mac802154_radiocb_s *)radiocb; + FAR struct ieee802154_privmac_s *priv; + FAR struct mac802154_txframe_s *trans; + + DEBUGASSERT(cb != NULL && cb->priv != NULL); + priv = cb->priv; + + /* Get exclusive access to the driver structure. We don't care about any + * signals so if we see one, just go back to trying to get access again. + */ + + while (mac802154_takesem(&priv->exclsem) != 0); + + /* Check to see if there are any CSMA transactions waiting */ + + trans = mac802154_pop_csma(priv); + mac802154_givesem(&priv->exclsem); + + if (trans != NULL) + { + /* Setup the transmit descriptor */ + + tx_desc->handle = trans->msdu_handle; + + *frame = trans->frame; + + /* Now that we've passed off the data, notify the waiting thread. + * NOTE: The transaction was allocated on the waiting thread's stack so + * it will be automatically deallocated when that thread awakens and + * returns. */ + + sem_post(&trans->sem); + return (trans->frame->io_len); + } + + return 0; +} + +/**************************************************************************** + * Name: mac802154_poll_gts + * + * Description: + * Called from the radio driver through the callback struct. This function is + * called when the radio has room for another GTS transaction. If the MAC + * layer has a GTS transaction, it copies it into the supplied buffer and + * returns the length. A descriptor is also populated with the transaction. + * + ****************************************************************************/ + +static int mac802154_poll_gts(FAR const struct ieee802154_radiocb_s *radiocb, + FAR struct ieee802154_txdesc_s *tx_desc, + FAR struct iob_s **frame) +{ + FAR struct mac802154_radiocb_s *cb = + (FAR struct mac802154_radiocb_s *)radiocb; + FAR struct ieee802154_privmac_s *priv; + FAR struct mac802154_txframe_s *trans; + int ret = 0; + + DEBUGASSERT(cb != NULL && cb->priv != NULL); + priv = cb->priv; + + /* Get exclusive access to the driver structure. We don't care about any + * signals so if we see one, just go back to trying to get access again. + */ + + while (mac802154_takesem(&priv->exclsem) != 0); + +#warning Missing logic. + + mac802154_givesem(&priv->exclsem); + + return 0; +} + +/**************************************************************************** + * Name: mac802154_txdone + * + * Description: + * Called from the radio driver through the callback struct. This function is + * called when the radio has completed a transaction. The txdesc passed gives + * provides information about the completed transaction including the original + * handle provided when the transaction was created and the status of the + * transaction. This function copies the descriptor and schedules work to + * handle the transaction without blocking the radio. + * + ****************************************************************************/ + +static void mac802154_txdone(FAR const struct ieee802154_radiocb_s *radiocb, + FAR const struct ieee802154_txdesc_s *tx_desc) +{ + FAR struct mac802154_radiocb_s *cb = + (FAR struct mac802154_radiocb_s *)radiocb; + FAR struct ieee802154_privmac_s *priv; + + DEBUGASSERT(cb != NULL && cb->priv != NULL); + priv = cb->priv; + + /* Get exclusive access to the driver structure. We don't care about any + * signals so if we see one, just go back to trying to get access again. + */ + + while (mac802154_takesem(&priv->exclsem) != 0); + + /* Check to see if there is an available tx descriptor slot. If there is + * not we simply drop the notification */ + + if (priv->txdesc_count < CONFIG_IEEE802154_NTXDESC) + { + /* Copy the txdesc over and link it into our list */ + + memcpy(&priv->txdesc[priv->txdesc_count++], tx_desc, + sizeof(struct ieee802154_txdesc_s)); + } + else + { + wlinfo("MAC802154: No room for TX Desc.\n"); + } + + mac802154_givesem(&priv->exclsem); + + /* Schedule work with the work queue to process the completion further */ + + if (work_available(&priv->tx_work)) + { + work_queue(MAC802154_WORK, &priv->tx_work, mac802154_txdone_worker, + (FAR void *)priv, 0); + } +} + +/**************************************************************************** + * Name: mac802154_txdone_worker + * + * Description: + * Worker function scheduled from mac802154_txdone. This function pops any + * TX descriptors off of the list and calls the next highest layers callback + * to inform the layer of the completed transaction and the status of it. + * + ****************************************************************************/ + +static void mac802154_txdone_worker(FAR void *arg) +{ + FAR struct ieee802154_privmac_s *priv = + (FAR struct ieee802154_privmac_s *)arg; + int i = 0; + + /* Get exclusive access to the driver structure. We don't care about any + * signals so if we see one, just go back to trying to get access again. + */ + + while (mac802154_takesem(&priv->exclsem) != 0); + + /* For each pending TX descriptor, send an application callback */ + + for (i = 0; i < priv->txdesc_count; i++) + { + priv->cb->mcps_notify(priv->cb, IEEE802154_NOTIFY_CONF_DATA, + (FAR const union ieee802154_mcps_notify_u *) &priv->txdesc[i]); + } + + /* We've handled all the descriptors and no further desc could have been added + * since we have the struct locked */ + + priv->txdesc_count = 0; + + mac802154_givesem(&priv->exclsem); +} + +/**************************************************************************** + * Name: mac802154_rxframe + * + * Description: + * Called from the radio driver through the callback struct. This function is + * called when the radio has received a frame. The frame is passed in an iob, + * so that we can free it when we are done processing. A pointer to the RX + * descriptor is passed along with the iob, but it must be copied here as it + * is allocated directly on the caller's stack. We simply link the frame, + * copy the RX descriptor, and schedule a worker to process the frame later so + * that we do not hold up the radio. + * + ****************************************************************************/ + +static void mac802154_rxframe(FAR const struct ieee802154_radiocb_s *radiocb, + FAR struct ieee802154_data_ind_s *ind) +{ + FAR struct mac802154_radiocb_s *cb = + (FAR struct mac802154_radiocb_s *)radiocb; + FAR struct ieee802154_privmac_s *priv; + + DEBUGASSERT(cb != NULL && cb->priv != NULL); + priv = cb->priv; + + /* Get exclusive access to the driver structure. We don't care about any + * signals so if we see one, just go back to trying to get access again. + */ + + while (mac802154_takesem(&priv->exclsem) != 0); + + /* Push the iob onto the tail of the frame list for processing */ + + mac802154_push_dataind(priv, ind); + + mac802154_givesem(&priv->exclsem); + + /* Schedule work with the work queue to process the completion further */ + + if (work_available(&priv->rx_work)) + { + work_queue(MAC802154_WORK, &priv->rx_work, mac802154_rxframe_worker, + (FAR void *)priv, 0); + } +} + +/**************************************************************************** + * Name: mac802154_rxframe_worker + * + * Description: + * Worker function scheduled from mac802154_rxframe. This function processes + * any frames in the list. Frames intended to be consumed by the MAC layer + * will not produce any callbacks to the next highest layer. Frames intended + * for the application layer will be forwarded to them. + * + ****************************************************************************/ + +static void mac802154_rxframe_worker(FAR void *arg) +{ + FAR struct ieee802154_privmac_s *priv = + (FAR struct ieee802154_privmac_s *)arg; + FAR struct ieee802154_data_ind_s *ind; + union ieee802154_mcps_notify_u mcps_notify; + FAR struct iob_s *frame; + uint16_t *frame_ctrl; + bool panid_comp; + uint8_t ftype; + + while(1) + { + /* Get exclusive access to the driver structure. We don't care about any + * signals so if we see one, just go back to trying to get access again. + */ + + while (mac802154_takesem(&priv->exclsem) != 0); + + /* Push the iob onto the tail of the frame list for processing */ + + ind = mac802154_pop_dataind(priv); + + if (ind == NULL) + { + mac802154_givesem(&priv->exclsem); + break; + } + + /* Once we pop off the indication, we don't need to keep the mac locked */ + + mac802154_givesem(&priv->exclsem); + + /* Get a local copy of the frame to make it easier to access */ + + frame = ind->frame; + + /* Set a local pointer to the frame control then move the offset past + * the frame control field + */ + + frame_ctrl = (uint16_t *)&frame->io_data[frame->io_offset]; + frame->io_offset += 2; + + /* We use the data_ind_s as a container for the frame information even if + * this isn't a data frame + */ + + ind->src.mode = (*frame_ctrl & IEEE802154_FRAMECTRL_SADDR) >> + IEEE802154_FRAMECTRL_SHIFT_SADDR; + + ind->dest.mode = (*frame_ctrl & IEEE802154_FRAMECTRL_DADDR) >> + IEEE802154_FRAMECTRL_SHIFT_DADDR; + + panid_comp = (*frame_ctrl & IEEE802154_FRAMECTRL_PANIDCOMP) >> + IEEE802154_FRAMECTRL_SHIFT_PANIDCOMP; + + ind->dsn = frame->io_data[frame->io_offset++]; + + /* If the destination address is included */ + + if (ind->dest.mode != IEEE802154_ADDRMODE_NONE) + { + /* Get the destination PAN ID */ + + ind->dest.panid = frame->io_data[frame->io_offset]; + frame->io_offset += 2; + + if (ind->dest.mode == IEEE802154_ADDRMODE_SHORT) + { + ind->dest.saddr = frame->io_data[frame->io_offset]; + frame->io_offset += 2; + } + else if (ind->dest.mode == IEEE802154_ADDRMODE_EXTENDED) + { + memcpy(&ind->dest.eaddr[0], &frame->io_data[frame->io_offset], + IEEE802154_EADDR_LEN); + frame->io_offset += 8; + } + } + + if (ind->src.mode != IEEE802154_ADDRMODE_NONE) + { + /* If the source address is included, and the PAN ID compression field + * is set, get the PAN ID from the header. + */ + + if (!panid_comp) + { + ind->src.panid = frame->io_data[frame->io_offset]; + frame->io_offset += 2; + } + + /* If the source address is included, and the PAN ID compression field + * is set, the source PAN ID is the same as the destination PAN ID + */ + + else + { + ind->src.panid = ind->dest.panid; + } + + if (ind->src.mode == IEEE802154_ADDRMODE_SHORT) + { + ind->src.saddr = frame->io_data[frame->io_offset]; + frame->io_offset += 2; + } + else if (ind->src.mode == IEEE802154_ADDRMODE_EXTENDED) + { + memcpy(&ind->src.eaddr[0], &frame->io_data[frame->io_offset], + IEEE802154_EADDR_LEN); + frame->io_offset += 8; + } + } + + ftype = (*frame_ctrl & IEEE802154_FRAMECTRL_FTYPE) >> + IEEE802154_FRAMECTRL_SHIFT_FTYPE; + + if (ftype == IEEE802154_FRAME_DATA) + { + /* If there is a registered MCPS callback receiver registered, send + * the frame, otherwise, throw it out. + */ + + if (priv->cb->mcps_notify != NULL) + { + mcps_notify.dataind = ind; + priv->cb->mcps_notify(priv->cb, IEEE802154_NOTIFY_IND_DATA, + &mcps_notify); + } + else + { + /* Free the data indication struct from the pool */ + + ieee802154_ind_free(ind); + } + } + else if (ftype == IEEE802154_FRAME_COMMAND) + { + + } + else if (ftype == IEEE802154_FRAME_BEACON) + { + + } + else + { + /* The radio layer is responsible for handling all ACKs and retries. If for + * some reason an ACK gets here, just throw it out. + */ + } + } +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: mac802154_create + * + * Description: + * Create a 802.15.4 MAC device from a 802.15.4 compatible radio device. + * + * The returned MAC structure should be passed to either the next highest + * layer in the network stack, or registered with a mac802154dev character + * or network drivers. In any of these scenarios, the next highest layer + * should register a set of callbacks with the MAC layer by setting the + * mac->cbs member. + * + * NOTE: This API does not create any device accessible to userspace. If + * you want to call these APIs from userspace, you have to wrap your mac + * in a character device via mac802154_device.c. + * + * Input Parameters: + * radiodev - an instance of an IEEE 802.15.4 radio + * + * Returned Value: + * An opaque reference to the MAC state data. + * + ****************************************************************************/ + +MACHANDLE mac802154_create(FAR struct ieee802154_radio_s *radiodev) +{ + FAR struct ieee802154_privmac_s *mac; + FAR struct ieee802154_radiocb_s *radiocb; + + /* Allocate object */ + + mac = (FAR struct ieee802154_privmac_s *) + kmm_zalloc(sizeof(struct ieee802154_privmac_s)); + + if (mac == NULL) + { + return NULL; + } + + /* Allow exclusive access to the privmac struct */ + + sem_init(&mac->exclsem, 0, 1); + + /* Initialize fields */ + + mac->radio = radiodev; + + mac802154_defaultmib(mac); + mac802154_applymib(mac); + + /* Initialize the Radio callbacks */ + + mac->radiocb.priv = mac; + + radiocb = &mac->radiocb.cb; + radiocb->poll_csma = mac802154_poll_csma; + radiocb->poll_gts = mac802154_poll_gts; + radiocb->txdone = mac802154_txdone; + radiocb->rxframe = mac802154_rxframe; + + /* Bind our callback structure */ + + radiodev->ops->bind(radiodev, &mac->radiocb.cb); + + /* Initialize our data indication pool */ + + ieee802154_indpool_initialize(); + + return (MACHANDLE)mac; +} + +/**************************************************************************** + * Name: mac802154_bind + * + * Description: + * Bind the MAC callback table to the MAC state. + * + * Parameters: + * mac - Reference to the MAC driver state structure + * cb - MAC callback operations + * + * Returned Value: + * OK on success; Negated errno on failure. + * + ****************************************************************************/ + +int mac802154_bind(MACHANDLE mac, FAR const struct ieee802154_maccb_s *cb) +{ + FAR struct ieee802154_privmac_s *priv = + (FAR struct ieee802154_privmac_s *)mac; + + priv->cb = cb; + return OK; +} + +/**************************************************************************** + * Name: mac802154_ioctl + * + * Description: + * Handle MAC and radio IOCTL commands directed to the MAC. + * + * Parameters: + * mac - Reference to the MAC driver state structure + * cmd - The IOCTL command + * arg - The argument for the IOCTL command + * + * Returned Value: + * OK on success; Negated errno on failure. + * + ****************************************************************************/ + +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); + + /* Check for IOCTLs aimed at the IEEE802.15.4 MAC layer */ + + if (_MAC802154IOCVALID(cmd)) + { + /* Handle the MAC IOCTL command */ + + switch (cmd) + { + case MAC802154IOC_MLME_ASSOC_REQUEST: + { + ret = mac802154_req_associate(mac, &macarg->assocreq); + } + break; + case MAC802154IOC_MLME_ASSOC_RESPONSE: + { + ret = mac802154_resp_associate(mac, &macarg->assocresp); + } + break; + case MAC802154IOC_MLME_DISASSOC_REQUEST: + { + ret = mac802154_req_disassociate(mac, &macarg->disassocreq); + } + break; + case MAC802154IOC_MLME_GET_REQUEST: + { + ret = mac802154_req_get(mac, macarg->getreq.pib_attr, + &macarg->getreq.attr_value); + } + break; + case MAC802154IOC_MLME_GTS_REQUEST: + { + ret = mac802154_req_gts(mac, &macarg->gtsreq); + } + break; + case MAC802154IOC_MLME_ORPHAN_RESPONSE: + { + ret = mac802154_resp_orphan(mac, &macarg->orphanresp); + } + break; + case MAC802154IOC_MLME_RESET_REQUEST: + { + ret = mac802154_req_reset(mac, macarg->resetreq.rst_pibattr); + } + break; + case MAC802154IOC_MLME_RXENABLE_REQUEST: + { + ret = mac802154_req_rxenable(mac, &macarg->rxenabreq); + } + break; + case MAC802154IOC_MLME_SCAN_REQUEST: + { + ret = mac802154_req_scan(mac, &macarg->scanreq); + } + break; + case MAC802154IOC_MLME_SET_REQUEST: + { + ret = mac802154_req_set(mac, macarg->setreq.pib_attr, + &macarg->setreq.attr_value); + } + break; + case MAC802154IOC_MLME_START_REQUEST: + { + ret = mac802154_req_start(mac, &macarg->startreq); + } + break; + case MAC802154IOC_MLME_SYNC_REQUEST: + { + ret = mac802154_req_sync(mac, &macarg->syncreq); + } + break; + case MAC802154IOC_MLME_POLL_REQUEST: + { + ret = mac802154_req_poll(mac, &macarg->pollreq); + } + break; + default: + wlerr("ERROR: Unrecognized cmd: %d\n", cmd); + ret = -ENOTTY; + break; + } + } + return ret; +} + +/**************************************************************************** + * MAC Interface Operations + ****************************************************************************/ + +/**************************************************************************** + * Name: mac802154_get_mhrlen + * + * Description: + * Calculate the MAC header length given the frame meta-data. + * + ****************************************************************************/ + +int mac802154_get_mhrlen(MACHANDLE mac, + FAR const struct ieee802154_frame_meta_s *meta) +{ + FAR struct ieee802154_privmac_s *priv = + (FAR struct ieee802154_privmac_s *)mac; + int ret = 3; /* Always frame control (2 bytes) and seq. num (1 byte) */ + + /* Check to make sure both the dest address and the source address are not set + * to NONE */ + + if (meta->dest_addr.mode == IEEE802154_ADDRMODE_NONE && + meta->src_addr_mode == IEEE802154_ADDRMODE_NONE) + { + return -EINVAL; + } + + /* The source address can only be set to NONE if the device is the PAN coord */ + + if (meta->src_addr_mode == IEEE802154_ADDRMODE_NONE && !priv->is_coord) + { + return -EINVAL; + } + + /* Add the destination address length */ + + ret += mac802154_addr_length[meta->dest_addr.mode]; + + /* Add the source address length */ + + ret += mac802154_addr_length[ meta->src_addr_mode]; + + /* 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->src_addr_mode != IEEE802154_ADDRMODE_NONE && + meta->dest_addr.mode != IEEE802154_ADDRMODE_NONE) + { + /* If the PAN identifiers are identical, the PAN ID Compression field + * shall be set to one, and the source PAN identifier shall be omitted + * from the transmitted frame. [1] pg. 41. + */ + + if (meta->dest_addr.panid == priv->addr.panid) + { + ret += 2; /* 2 bytes for destination PAN ID */ + return ret; + } + } + + /* If we are here, PAN ID compression is off, so include the dest and source + * PAN ID if the respective address is included + */ + + if (meta->src_addr_mode != IEEE802154_ADDRMODE_NONE) + { + ret += 2; /* 2 bytes for source PAN ID */ + } + + if (meta->dest_addr.mode != IEEE802154_ADDRMODE_NONE) + { + ret += 2; /* 2 bytes for destination PAN ID */ + } + + return ret; +} + +/**************************************************************************** + * Name: mac802154_req_data + * + * Description: + * The MCPS-DATA.request primitive requests the transfer of a data SPDU + * (i.e., MSDU) from a local SSCS entity to a single peer SSCS entity. + * Confirmation is returned via the + * struct ieee802154_maccb_s->conf_data callback. + * + ****************************************************************************/ + +int mac802154_req_data(MACHANDLE mac, + FAR const struct ieee802154_frame_meta_s *meta, + FAR struct iob_s *frame) +{ + FAR struct ieee802154_privmac_s *priv = + (FAR struct ieee802154_privmac_s *)mac; + FAR struct mac802154_txframe_s trans; + uint16_t *frame_ctrl; + uint8_t mhr_len = 3; /* Start assuming frame control and seq. num */ + int ret; + + /* Check the required frame size */ + + if (frame->io_len > IEEE802154_MAX_PHY_PACKET_SIZE) + { + return -E2BIG; + } + + /* Cast the first two bytes of the IOB to a uint16_t frame control field */ + + frame_ctrl = (uint16_t *)&frame->io_data[0]; + + /* Ensure we start with a clear frame control field */ + + *frame_ctrl = 0; + + /* Set the frame type to Data */ + + *frame_ctrl |= IEEE802154_FRAME_DATA << IEEE802154_FRAMECTRL_SHIFT_FTYPE; + + /* If the msduLength is greater than aMaxMACSafePayloadSize, the MAC + * sublayer will set the Frame Version to one. [1] pg. 118. + */ + + if ((frame->io_len - frame->io_offset) > IEEE802154_MAX_SAFE_MAC_PAYLOAD_SIZE) + { + *frame_ctrl |= IEEE802154_FRAMECTRL_VERSION; + } + + /* If the TXOptions parameter specifies that an acknowledged transmission + * is required, the AR field will be set appropriately, as described in + * 5.1.6.4 [1] pg. 118. + */ + + *frame_ctrl |= (meta->msdu_flags.ack_tx << 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. + */ + + if (meta->dest_addr.mode != IEEE802154_ADDRMODE_NONE) + { + memcpy(&frame->io_data[mhr_len], &meta->dest_addr.panid, 2); + mhr_len += 2; + + if (meta->dest_addr.mode == IEEE802154_ADDRMODE_SHORT) + { + memcpy(&frame->io_data[mhr_len], &meta->dest_addr.saddr, 2); + mhr_len += 2; + } + else if (meta->dest_addr.mode == IEEE802154_ADDRMODE_EXTENDED) + { + memcpy(&frame->io_data[mhr_len], &meta->dest_addr.eaddr, + IEEE802154_EADDR_LEN); + + mhr_len += IEEE802154_EADDR_LEN; + } + } + + /* Set the destination addr mode inside the frame control field */ + + *frame_ctrl |= (meta->dest_addr.mode << IEEE802154_FRAMECTRL_SHIFT_DADDR); + + /* From this point on, we need exclusive access to the privmac struct */ + + ret = mac802154_takesem(&priv->exclsem); + if (ret < 0) + { + wlerr("ERROR: mac802154_takesem failed: %d\n", ret); + return ret; + } + + /* 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->src_addr_mode != IEEE802154_ADDRMODE_NONE && + meta->dest_addr.mode != IEEE802154_ADDRMODE_NONE) + { + /* If the PAN identifiers are identical, the PAN ID Compression field + * shall be set to one, and the source PAN identifier shall be omitted + * from the transmitted frame. [1] pg. 41. + */ + + if (meta->dest_addr.panid == priv->addr.panid) + { + *frame_ctrl |= IEEE802154_FRAMECTRL_PANIDCOMP; + } + } + + if (meta->src_addr_mode != 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. + */ + + if ((meta->dest_addr.mode == IEEE802154_ADDRMODE_NONE) || + (!(*frame_ctrl & IEEE802154_FRAMECTRL_PANIDCOMP))) + { + memcpy(&frame->io_data[mhr_len], &priv->addr.panid, 2); + mhr_len += 2; + } + + if (meta->src_addr_mode == IEEE802154_ADDRMODE_SHORT) + { + memcpy(&frame->io_data[mhr_len], &priv->addr.saddr, 2); + mhr_len += 2; + } + else if (meta->src_addr_mode == IEEE802154_ADDRMODE_EXTENDED) + { + memcpy(&frame->io_data[mhr_len], &priv->addr.eaddr, + IEEE802154_EADDR_LEN); + + mhr_len += IEEE802154_EADDR_LEN; + } + } + + /* Set the source addr mode inside the frame control field */ + + *frame_ctrl |= (meta->src_addr_mode << 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 + * of the outgoing frame and then increment it by one. [1] pg. 40. + */ + + frame->io_data[2] = priv->dsn++; + + /* The MAC header we just created must never have exceeded where the app + * data starts. This should never happen since the offset should have + * been set via the same logic to calculate the header length as the logic + * here that created the header + */ + + DEBUGASSERT(mhr_len == frame->io_offset); + + frame->io_offset = 0; /* Set the offset to 0 to include the header */ + + /* Setup our transaction */ + + trans.msdu_handle = meta->msdu_handle; + trans.frame = frame; + sem_init(&trans.sem, 0, 1); + + /* If the TxOptions parameter specifies that a GTS transmission is required, + * the MAC sublayer will determine whether it has a valid GTS as described + * 5.1.7.3. If a valid GTS could not be found, the MAC sublayer will discard + * the MSDU. If a valid GTS was found, the MAC sublayer will defer, if + * necessary, until the GTS. If the TxOptions parameter specifies that a GTS + * transmission is not required, the MAC sublayer will transmit the MSDU using + * either slotted CSMA-CA in the CAP for a beacon-enabled PAN or unslotted + * CSMA-CA for a nonbeacon-enabled PAN. Specifying a GTS transmission in the + * TxOptions parameter overrides an indirect transmission request. + * [1] pg. 118. + */ + + if (meta->msdu_flags.gts_tx) + { + /* TODO: Support GTS transmission. This should just change where we link + * the transaction. Instead of going in the CSMA transaction list, it + * should be linked to the GTS' transaction list. We'll need to check if + * the GTS is valid, and then find the GTS, before linking. Note, we also + * don't have to try and kick-off any transmission here. + */ + + return -ENOTSUP; + } + else + { + /* If the TxOptions parameter specifies that an indirect transmission is + * required and this primitive is received by the MAC sublayer of a + * coordinator, the data frame is sent using indirect transmission, as + * described in 5.1.5 and 5.1.6.3. [1] + */ + + if (meta->msdu_flags.indirect_tx) + { + /* If the TxOptions parameter specifies that an indirect transmission + * is required and if the device receiving this primitive is not a + * coordinator, the destination address is not present, or the + * TxOptions parameter also specifies a GTS transmission, the indirect + * transmission option will be ignored. [1] + * + * NOTE: We don't just ignore the parameter. Instead, we throw an + * error, since this really shouldn't be happening. + */ + + if (priv->is_coord && meta->dest_addr.mode != IEEE802154_ADDRMODE_NONE) + { + /* Link the transaction into the indirect_trans list */ + + } + else + { + return -EINVAL; + } + } + else + { + /* Link the transaction into the CSMA transaction list */ + + mac802154_push_csma(priv, &trans); + + /* We no longer need to have the MAC layer locked. */ + + mac802154_givesem(&priv->exclsem); + + /* Notify the radio driver that there is data available */ + + priv->radio->ops->txnotify_csma(priv->radio); + + sem_wait(&trans.sem); + } + } + + sem_destroy(&trans.sem); + return OK; +} + +/**************************************************************************** + * Name: mac802154_req_purge + * + * Description: + * The MCPS-PURGE.request primitive allows the next higher layer to purge + * an MSDU from the transaction queue. Confirmation is returned via + * the struct ieee802154_maccb_s->conf_purge callback. + * + * NOTE: The standard specifies that confirmation should be indicated via + * the asynchronous MLME-PURGE.confirm primitve. However, in our + * implementation we synchronously return the status from the request. + * Therefore, we merge the functionality of the MLME-PURGE.request and + * MLME-PURGE.confirm primitives together. + * + ****************************************************************************/ + +int mac802154_req_purge(MACHANDLE mac, uint8_t msdu_handle) +{ + FAR struct ieee802154_privmac_s *priv = + (FAR struct ieee802154_privmac_s *)mac; + return -ENOTTY; +} + +/**************************************************************************** + * Name: mac802154_req_associate + * + * Description: + * The MLME-ASSOCIATE.request primitive allows a device to request an + * association with a coordinator. Confirmation is returned via the + * struct ieee802154_maccb_s->conf_associate callback. + * + ****************************************************************************/ + +int mac802154_req_associate(MACHANDLE mac, + FAR struct ieee802154_assoc_req_s *req) +{ + FAR struct ieee802154_privmac_s *priv = + (FAR struct ieee802154_privmac_s *)mac; + + /* Set the channel of the PHY layer */ + + /* Set the channel page of the PHY layer */ + + /* Set the macPANId */ + + /* Set either the macCoordExtendedAddress and macCoordShortAddress + * depending on the CoordAddrMode in the primitive. + */ + + if (req->coord_addr.mode == IEEE802154_ADDRMODE_EXTENDED) + { + + } + else if (req->coord_addr.mode == IEEE802154_ADDRMODE_EXTENDED) + { + + } + else + { + return -EINVAL; + } + + return -ENOTTY; +} + +/**************************************************************************** + * Name: mac802154_req_disassociate + * + * Description: + * The MLME-DISASSOCIATE.request primitive is used by an associated device to + * notify the coordinator of its intent to leave the PAN. It is also used by + * the coordinator to instruct an associated device to leave the PAN. + * Confirmation is returned via the + * struct ieee802154_maccb_s->conf_disassociate callback. + * + ****************************************************************************/ + +int mac802154_req_disassociate(MACHANDLE mac, + FAR struct ieee802154_disassoc_req_s *req) +{ + FAR struct ieee802154_privmac_s *priv = + (FAR struct ieee802154_privmac_s *)mac; + return -ENOTTY; +} + + +/**************************************************************************** + * Name: mac802154_req_gts + * + * Description: + * The MLME-GTS.request primitive allows a device to send a request to the PAN + * coordinator to allocate a new GTS or to deallocate an existing GTS. + * Confirmation is returned via the + * struct ieee802154_maccb_s->conf_gts callback. + * + ****************************************************************************/ + +int mac802154_req_gts(MACHANDLE mac, FAR struct ieee802154_gts_req_s *req) +{ + FAR struct ieee802154_privmac_s *priv = + (FAR struct ieee802154_privmac_s *)mac; + return -ENOTTY; +} + +/**************************************************************************** + * Name: mac802154_req_reset + * + * Description: + * The MLME-RESET.request primitive allows the next higher layer to request + * that the MLME performs a reset operation. + * + * NOTE: The standard specifies that confirmation should be provided via + * via the asynchronous MLME-RESET.confirm primitve. However, in our + * implementation we synchronously return the value immediately. Therefore, + * we merge the functionality of the MLME-RESET.request and MLME-RESET.confirm + * primitives together. + * + * Input Parameters: + * mac - Handle to the MAC layer instance + * rst_pibattr - Whether or not to reset the MAC PIB attributes to defaults + * + ****************************************************************************/ + +int mac802154_req_reset(MACHANDLE mac, bool rst_pibattr) +{ + FAR struct ieee802154_privmac_s * priv = + (FAR struct ieee802154_privmac_s *) mac; + return -ENOTTY; +} + +/**************************************************************************** + * Name: mac802154_req_rxenable + * + * Description: + * The MLME-RX-ENABLE.request primitive allows the next higher layer to + * request that the receiver is enable for a finite period of time. + * Confirmation is returned via the + * struct ieee802154_maccb_s->conf_rxenable callback. + * + ****************************************************************************/ + +int mac802154_req_rxenable(MACHANDLE mac, + FAR struct ieee802154_rxenable_req_s *req) +{ + FAR struct ieee802154_privmac_s * priv = + (FAR struct ieee802154_privmac_s *)mac; + return -ENOTTY; +} + +/**************************************************************************** + * Name: mac802154_req_scan + * + * Description: + * The MLME-SCAN.request primitive is used to initiate a channel scan over a + * given list of channels. A device can use a channel scan to measure the + * energy on the channel, search for the coordinator with which it associated, + * or search for all coordinators transmitting beacon frames within the POS of + * the scanning device. Scan results are returned + * via MULTIPLE calls to the struct ieee802154_maccb_s->conf_scan callback. + * This is a difference with the official 802.15.4 specification, implemented + * here to save memory. + * + ****************************************************************************/ + +int mac802154_req_scan(MACHANDLE mac, FAR struct ieee802154_scan_req_s *req) +{ + FAR struct ieee802154_privmac_s *priv = + (FAR struct ieee802154_privmac_s *)mac; + return -ENOTTY; +} + +/**************************************************************************** + * Name: mac802154_req_get + * + * Description: + * The MLME-GET.request primitive requests information about a given PIB + * attribute. + * + * NOTE: The standard specifies that the attribute value should be returned + * via the asynchronous MLME-GET.confirm primitve. However, in our + * implementation, we synchronously return the value immediately.Therefore, we + * merge the functionality of the MLME-GET.request and MLME-GET.confirm + * primitives together. + * + ****************************************************************************/ + +int mac802154_req_get(MACHANDLE mac, enum ieee802154_pib_attr_e pib_attr, + FAR union ieee802154_attr_val_u *attr_value) +{ + FAR struct ieee802154_privmac_s *priv = + (FAR struct ieee802154_privmac_s *)mac; + return -ENOTTY; +} + +/**************************************************************************** + * Name: mac802154_req_set + * + * Description: + * The MLME-SET.request primitive attempts to write the given value to the + * indicated MAC PIB attribute. + * + * NOTE: The standard specifies that confirmation should be indicated via + * the asynchronous MLME-SET.confirm primitve. However, in our implementation + * we synchronously return the status from the request. Therefore, we do merge + * the functionality of the MLME-SET.request and MLME-SET.confirm primitives + * together. + * + ****************************************************************************/ + +int mac802154_req_set(MACHANDLE mac, enum ieee802154_pib_attr_e pib_attr, + FAR const union ieee802154_attr_val_u *attr_value) +{ + FAR struct ieee802154_privmac_s *priv = + (FAR struct ieee802154_privmac_s *)mac; + int ret; + + switch (pib_attr) + { + case IEEE802154_PIB_MAC_EXTENDED_ADDR: + { + /* Set the MAC copy of the address in the table */ + + memcpy(&priv->addr.eaddr[0], &attr_value->mac.eaddr[0], + IEEE802154_EADDR_LEN); + + /* Tell the radio about the attribute */ + + priv->radio->ops->set_attr(priv->radio, pib_attr, attr_value); + + ret = IEEE802154_STATUS_SUCCESS; + } + break; + default: + { + /* The attribute may be handled soley in the radio driver, so pass + * it along. + */ + + ret = priv->radio->ops->set_attr(priv->radio, pib_attr, attr_value); + } + break; + } + return ret; +} + +/**************************************************************************** + * Name: mac802154_req_start + * + * Description: + * The MLME-START.request primitive makes a request for the device to start + * using a new superframe configuration. Confirmation is returned + * via the struct ieee802154_maccb_s->conf_start callback. + * + ****************************************************************************/ + +int mac802154_req_start(MACHANDLE mac, FAR struct ieee802154_start_req_s *req) +{ + FAR struct ieee802154_privmac_s *priv = + (FAR struct ieee802154_privmac_s *)mac; + return -ENOTTY; +} + +/**************************************************************************** + * Name: mac802154_req_sync + * + * Description: + * The MLME-SYNC.request primitive requests to synchronize with the + * coordinator by acquiring and, if specified, tracking its beacons. + * Confirmation is returned via the + * struct ieee802154_maccb_s->int_commstatus callback. TOCHECK. + * + ****************************************************************************/ + +int mac802154_req_sync(MACHANDLE mac, FAR struct ieee802154_sync_req_s *req) +{ + FAR struct ieee802154_privmac_s *priv = + (FAR struct ieee802154_privmac_s *)mac; + return -ENOTTY; +} + +/**************************************************************************** + * Name: mac802154_req_poll + * + * Description: + * The MLME-POLL.request primitive prompts the device to request data from + * the coordinator. Confirmation is returned via the + * struct ieee802154_maccb_s->conf_poll callback, followed by a + * struct ieee802154_maccb_s->ind_data callback. + * + ****************************************************************************/ + +int mac802154_req_poll(MACHANDLE mac, FAR struct ieee802154_poll_req_s *req) +{ + FAR struct ieee802154_privmac_s *priv = + (FAR struct ieee802154_privmac_s *)mac; + return -ENOTTY; +} + +/**************************************************************************** + * Name: mac802154_resp_associate + * + * Description: + * The MLME-ASSOCIATE.response primitive is used to initiate a response to + * an MLME-ASSOCIATE.indication primitive. + * + ****************************************************************************/ + +int mac802154_resp_associate(MACHANDLE mac, + FAR struct ieee802154_assoc_resp_s *resp) +{ + FAR struct ieee802154_privmac_s *priv = + (FAR struct ieee802154_privmac_s *)mac; + return -ENOTTY; +} + +/**************************************************************************** + * Name: mac802154_resp_orphan + * + * Description: + * The MLME-ORPHAN.response primitive allows the next higher layer of a + * coordinator to respond to the MLME-ORPHAN.indication primitive. + * + ****************************************************************************/ + +int mac802154_resp_orphan(MACHANDLE mac, + FAR struct ieee802154_orphan_resp_s *resp) +{ + FAR struct ieee802154_privmac_s *priv = + (FAR struct ieee802154_privmac_s *)mac; + return -ENOTTY; +} + diff --git a/wireless/ieee802154/mac802154.h b/wireless/ieee802154/mac802154.h new file mode 100644 index 0000000000..66fa5495ca --- /dev/null +++ b/wireless/ieee802154/mac802154.h @@ -0,0 +1,345 @@ +/**************************************************************************** + * wireless/ieee802154/mac802154.h + * + * Copyright (C) 2016 Sebastien Lorquet. All rights reserved. + * Copyright (C) 2017 Verge Inc. All rights reserved. + * Copyright (C) 2017 Gregory Nutt. All rights reserved. + * + * Author: Sebastien Lorquet + * Author: Anthony Merlino + * + * The naming and comments for various fields are taken directly + * from the IEEE 802.15.4 2011 standard. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +#ifndef __WIRELESS_IEEE802154__MAC802154_H +#define __WIRELESS_IEEE802154__MAC802154_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include + +#include + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +struct iob_s; /* Forward reference */ + + /**************************************************************************** + * Name: mac802154_bind + * + * Description: + * Bind the MAC callback table to the MAC state. + * + * Parameters: + * mac - Reference to the MAC driver state structure + * cb - MAC callback operations + * + * Returned Value: + * OK on success; Negated errno on failure. + * + ****************************************************************************/ + +int mac802154_bind(MACHANDLE mac, FAR const struct ieee802154_maccb_s *cb); + +/**************************************************************************** + * Name: mac802154_ioctl + * + * Description: + * Handle MAC and radio IOCTL commands directed to the MAC. + * + * Parameters: + * mac - Reference to the MAC driver state structure + * cmd - The IOCTL command + * arg - The argument for the IOCTL command + * + * Returned Value: + * OK on success; Negated errno on failure. + * + ****************************************************************************/ + +int mac802154_ioctl(MACHANDLE mac, int cmd, unsigned long arg); + +/**************************************************************************** + * MAC Interface Operations + ****************************************************************************/ + +/**************************************************************************** + * Name: mac802154_get_mhrlen + * + * Description: + * Calculate the MAC header length given the frame meta-data. + * + ****************************************************************************/ + +int mac802154_get_mhrlen(MACHANDLE mac, + FAR const struct ieee802154_frame_meta_s *meta); + +/**************************************************************************** + * Name: mac802154_req_data + * + * Description: + * The MCPS-DATA.request primitive requests the transfer of a data SPDU + * (i.e., MSDU) from a local SSCS entity to a single peer SSCS entity. + * Confirmation is returned via the + * struct ieee802154_maccb_s->conf_data callback. + * + ****************************************************************************/ + +int mac802154_req_data(MACHANDLE mac, + FAR const struct ieee802154_frame_meta_s *meta, + FAR struct iob_s *frame); + +/**************************************************************************** + * Name: mac802154_req_purge + * + * Description: + * The MCPS-PURGE.request primitive allows the next higher layer to purge + * an MSDU from the transaction queue. Confirmation is returned via + * the struct ieee802154_maccb_s->conf_purge callback. + * + * NOTE: The standard specifies that confirmation should be indicated via + * the asynchronous MLME-PURGE.confirm primitve. However, in our + * implementation we synchronously return the status from the request. + * Therefore, we merge the functionality of the MLME-PURGE.request and + * MLME-PURGE.confirm primitives together. + * + ****************************************************************************/ + +int mac802154_req_purge(MACHANDLE mac, uint8_t msdu_handle); + +/**************************************************************************** + * Name: mac802154_req_associate + * + * Description: + * The MLME-ASSOCIATE.request primitive allows a device to request an + * association with a coordinator. Confirmation is returned via the + * struct ieee802154_maccb_s->conf_associate callback. + * + ****************************************************************************/ + +int mac802154_req_associate(MACHANDLE mac, + FAR struct ieee802154_assoc_req_s *req); + +/**************************************************************************** + * Name: mac802154_req_disassociate + * + * Description: + * The MLME-DISASSOCIATE.request primitive is used by an associated device + * to notify the coordinator of its intent to leave the PAN. It is also + * used by the coordinator to instruct an associated device to leave the + * PAN. + * + * Confirmation is returned via the + * struct ieee802154_maccb_s->conf_disassociate callback. + * + ****************************************************************************/ + +int mac802154_req_disassociate(MACHANDLE mac, + FAR struct ieee802154_disassoc_req_s *req); + +/**************************************************************************** + * Name: mac802154_req_gts + * + * Description: + * The MLME-GTS.request primitive allows a device to send a request to the + * PAN coordinator to allocate a new GTS or to deallocate an existing GTS. + * Confirmation is returned via the + * struct ieee802154_maccb_s->conf_gts callback. + * + ****************************************************************************/ + +int mac802154_req_gts(MACHANDLE mac, FAR struct ieee802154_gts_req_s *req); + +/**************************************************************************** + * Name: mac802154_req_reset + * + * Description: + * The MLME-RESET.request primitive allows the next higher layer to request + * that the MLME performs a reset operation. + * + * NOTE: The standard specifies that confirmation should be provided via + * via the asynchronous MLME-RESET.confirm primitve. However, in our + * implementation we synchronously return the value immediately. Therefore, + * we merge the functionality of the MLME-RESET.request and MLME-RESET.confirm + * primitives together. + * + * Input Parameters: + * mac - Handle to the MAC layer instance + * rst_pibattr - Whether or not to reset the MAC PIB attributes to defaults + * + ****************************************************************************/ + +int mac802154_req_reset(MACHANDLE mac, bool rst_pibattr); + +/**************************************************************************** + * Name: mac802154_req_rxenable + * + * Description: + * The MLME-RX-ENABLE.request primitive allows the next higher layer to + * request that the receiver is enable for a finite period of time. + * Confirmation is returned via the + * struct ieee802154_maccb_s->conf_rxenable callback. + * + ****************************************************************************/ + +int mac802154_req_rxenable(MACHANDLE mac, + FAR struct ieee802154_rxenable_req_s *req); + +/**************************************************************************** + * Name: mac802154_req_scan + * + * Description: + * The MLME-SCAN.request primitive is used to initiate a channel scan over + * a given list of channels. A device can use a channel scan to measure + * the energy on the channel, search for the coordinator with which it + * associated, or search for all coordinators transmitting beacon frames + * within the POS of the scanning device. Scan results are returned + * via MULTIPLE calls to the struct ieee802154_maccb_s->conf_scan + * callback. This is a difference with the official 802.15.4 + * specification, implemented here to save memory. + * + ****************************************************************************/ + +int mac802154_req_scan(MACHANDLE mac, FAR struct ieee802154_scan_req_s *req); + +/**************************************************************************** + * Name: mac802154_req_get + * + * Description: + * The MLME-GET.request primitive requests information about a given PIB + * attribute. + * + * NOTE: The standard specifies that the attribute value should be returned + * via the asynchronous MLME-GET.confirm primitve. However, in our + * implementation, we synchronously return the value immediately.Therefore, we + * merge the functionality of the MLME-GET.request and MLME-GET.confirm + * primitives together. + * + ****************************************************************************/ + +int mac802154_req_get(MACHANDLE mac, enum ieee802154_pib_attr_e pib_attr, + FAR union ieee802154_attr_val_u *attr_value); + +/**************************************************************************** + * Name: mac802154_req_set + * + * Description: + * The MLME-SET.request primitive attempts to write the given value to the + * indicated MAC PIB attribute. + * + * NOTE: The standard specifies that confirmation should be indicated via + * the asynchronous MLME-SET.confirm primitve. However, in our implementation + * we synchronously return the status from the request. Therefore, we do merge + * the functionality of the MLME-SET.request and MLME-SET.confirm primitives + * together. + * + ****************************************************************************/ + +int mac802154_req_set(MACHANDLE mac, enum ieee802154_pib_attr_e pib_attr, + FAR const union ieee802154_attr_val_u *attr_value); + +/**************************************************************************** + * Name: mac802154_req_start + * + * Description: + * The MLME-START.request primitive makes a request for the device to + * start using a new superframe configuration. Confirmation is returned + * via the struct ieee802154_maccb_s->conf_start callback. + * + ****************************************************************************/ + +int mac802154_req_start(MACHANDLE mac, FAR struct ieee802154_start_req_s *req); + +/**************************************************************************** + * Name: mac802154_req_sync + * + * Description: + * The MLME-SYNC.request primitive requests to synchronize with the + * coordinator by acquiring and, if specified, tracking its beacons. + * Confirmation is returned via the + * struct ieee802154_maccb_s->int_commstatus callback. TOCHECK. + * + ****************************************************************************/ + +int mac802154_req_sync(MACHANDLE mac, FAR struct ieee802154_sync_req_s *req); + +/**************************************************************************** + * Name: mac802154_req_poll + * + * Description: + * The MLME-POLL.request primitive prompts the device to request data from + * the coordinator. Confirmation is returned via the + * struct ieee802154_maccb_s->conf_poll callback, followed by a + * struct ieee802154_maccb_s->ind_data callback. + * + ****************************************************************************/ + +int mac802154_req_poll(MACHANDLE mac, FAR struct ieee802154_poll_req_s *req); + +/**************************************************************************** + * Name: mac802154_resp_associate + * + * Description: + * The MLME-ASSOCIATE.response primitive is used to initiate a response to + * an MLME-ASSOCIATE.indication primitive. + * + ****************************************************************************/ + +int mac802154_resp_associate(MACHANDLE mac, + FAR struct ieee802154_assoc_resp_s *resp); + +/**************************************************************************** + * Name: mac802154_resp_orphan + * + * Description: + * The MLME-ORPHAN.response primitive allows the next higher layer of a + * coordinator to respond to the MLME-ORPHAN.indication primitive. + * + ****************************************************************************/ + +int mac802154_resp_orphan(MACHANDLE mac, + FAR struct ieee802154_orphan_resp_s *resp); + + +#undef EXTERN +#ifdef __cplusplus +} +#endif + +#endif /* __WIRELESS_IEEE802154__MAC802154_H */ diff --git a/wireless/ieee802154/mac802154_device.c b/wireless/ieee802154/mac802154_device.c new file mode 100644 index 0000000000..a4eb93b656 --- /dev/null +++ b/wireless/ieee802154/mac802154_device.c @@ -0,0 +1,1017 @@ +/**************************************************************************** + * wireless/ieee802154/mac802154_device.c + * + * Copyright (C) 2017 Verge Inc. All rights reserved. + * Author: Anthony Merlino + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include + +#include +#include + +#include "mac802154.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* Device naming ************************************************************/ + +#define DEVNAME_FMT "/dev/ieee%d" +#define DEVNAME_FMTLEN (9 + 3 + 1) + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/* This structure describes the state of one open mac driver instance */ + +struct mac802154dev_open_s +{ + /* Supports a singly linked list */ + + FAR struct mac802154dev_open_s *md_flink; + + /* The following will be true if we are closing */ + + volatile bool md_closing; +}; + +struct mac802154dev_dwait_s +{ + uint8_t mw_handle; /* The msdu handle identifying the frame */ + sem_t mw_sem; /* The semaphore used to signal the completion */ + int mw_status; /* The success/error of the transaction */ + + /* Supports a singly linked list */ + + FAR struct mac802154dev_dwait_s *mw_flink; +}; + +struct mac802154dev_callback_s +{ + /* This holds the information visible to the MAC layer */ + + struct ieee802154_maccb_s mc_cb; /* Interface understood by the MAC layer */ + FAR struct mac802154_chardevice_s *mc_priv; /* Our priv data */ +}; + +struct mac802154_chardevice_s +{ + MACHANDLE md_mac; /* Saved binding to the mac layer */ + struct mac802154dev_callback_s md_cb; /* Callback information */ + sem_t md_exclsem; /* Exclusive device access */ + + bool readpending; /* Is there a read using the semaphore? */ + sem_t readsem; /* Signaling semaphore for waiting read */ + + /* The following is a singly linked list of open references to the + * MAC device. + */ + + FAR struct mac802154dev_open_s *md_open; + FAR struct mac802154dev_dwait_s *md_dwait; + + /* Hold a list of transactions as a "readahead" buffer */ + + FAR struct ieee802154_data_ind_s *dataind_head; + FAR struct ieee802154_data_ind_s *dataind_tail; + +#ifndef CONFIG_DISABLE_SIGNALS + /* MCPS Service notification information */ + + struct mac802154dev_notify_s md_mcps_notify; + pid_t md_mcps_pid; + + /* MLME Service notification information */ + + struct mac802154dev_notify_s md_mlme_notify; + pid_t md_mlme_pid; +#endif +}; + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + + /* Semaphore helpers */ + +static inline int mac802154dev_takesem(sem_t *sem); +#define mac802154dev_givesem(s) sem_post(s); + +static void mac802154dev_push_dataind(FAR struct mac802154_chardevice_s *dev, + FAR struct ieee802154_data_ind_s *ind); +static FAR struct ieee802154_data_ind_s * + mac802154dev_pop_dataind(FAR struct mac802154_chardevice_s *dev); + + +static void mac802154dev_mlme_notify(FAR const struct ieee802154_maccb_s *maccb, + enum ieee802154_macnotify_e notif, + FAR const union ieee802154_mlme_notify_u *arg); + +static void mac802154dev_mcps_notify(FAR const struct ieee802154_maccb_s *maccb, + enum ieee802154_macnotify_e notif, + FAR const union ieee802154_mcps_notify_u *arg); + +static int mac802154dev_open(FAR struct file *filep); +static int mac802154dev_close(FAR struct file *filep); +static ssize_t mac802154dev_read(FAR struct file *filep, FAR char *buffer, + size_t len); +static ssize_t mac802154dev_write(FAR struct file *filep, + FAR const char *buffer, size_t len); +static int mac802154dev_ioctl(FAR struct file *filep, int cmd, + unsigned long arg); + +/* MAC callback helpers */ + +static void mac802154dev_conf_data(FAR struct mac802154_chardevice_s *dev, + FAR const struct ieee802154_data_conf_s *conf); +static void mac802154dev_ind_data(FAR struct mac802154_chardevice_s *dev, + FAR struct ieee802154_data_ind_s *ind); + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +static const struct file_operations mac802154dev_fops = +{ + mac802154dev_open , /* open */ + mac802154dev_close, /* close */ + mac802154dev_read , /* read */ + mac802154dev_write, /* write */ + NULL, /* seek */ + mac802154dev_ioctl /* ioctl */ +#ifndef CONFIG_DISABLE_POLL + , NULL /* poll */ +#endif +#ifndef CONFIG_DISABLE_PSEUDOFS_OPERATIONS + , NULL /* unlink */ +#endif +}; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: mac802154dev_semtake + * + * Description: + * Acquire the semaphore used for access serialization. + * + ****************************************************************************/ + +static inline int mac802154dev_takesem(sem_t *sem) +{ + /* Take a count from the semaphore, possibly waiting */ + + if (sem_wait(sem) < 0) + { + /* EINTR is the only error that we expect */ + + int errcode = get_errno(); + DEBUGASSERT(errcode == EINTR); + return -errcode; + } + + return OK; +} + +/**************************************************************************** + * Name: mac802154dev_push_dataind + * + * Description: + * Push a data indication onto the list to be processed + * + ****************************************************************************/ + +static void mac802154dev_push_dataind(FAR struct mac802154_chardevice_s *dev, + FAR struct ieee802154_data_ind_s *ind) +{ + /* Ensure the forward link is NULL */ + + ind->flink = NULL; + + /* If the tail is not empty, make the frame pointed to by the tail, + * point to the new data indication */ + + if (dev->dataind_tail != NULL) + { + dev->dataind_tail->flink = ind; + } + + /* Point the tail at the new frame */ + + dev->dataind_tail = ind; + + /* If the head is NULL, we need to point it at the data indication since there + * is only one indication in the list at this point */ + + if (dev->dataind_head == NULL) + { + dev->dataind_head = ind; + } +} + +/**************************************************************************** + * Name: mac802154dev_pop_dataind + * + * Description: + * Pop a data indication from the list + * + ****************************************************************************/ + +static FAR struct ieee802154_data_ind_s * + mac802154dev_pop_dataind(FAR struct mac802154_chardevice_s *dev) +{ + FAR struct ieee802154_data_ind_s *ind; + + if (dev->dataind_head == NULL) + { + return NULL; + } + + /* Get the data indication from the head of the list */ + + ind = dev->dataind_head; + ind->flink = NULL; + + /* Move the head pointer to the next data indication */ + + dev->dataind_head = ind->flink; + + /* If the head is now NULL, the list is empty, so clear the tail too */ + + if (dev->dataind_head == NULL) + { + dev->dataind_tail = NULL; + } + + return ind; +} + +/**************************************************************************** + * Name: mac802154dev_open + * + * Description: + * Open the 802.15.4 MAC character device. + * + ****************************************************************************/ + +static int mac802154dev_open(FAR struct file *filep) +{ + FAR struct inode *inode; + FAR struct mac802154_chardevice_s *dev; + FAR struct mac802154dev_open_s *opriv; + int ret; + + DEBUGASSERT(filep != NULL && filep->f_inode != NULL); + inode = filep->f_inode; + + dev = inode->i_private; + DEBUGASSERT(dev != NULL); + + /* Get exclusive access to the MAC driver data structure */ + + ret = mac802154dev_takesem(&dev->md_exclsem); + if (ret < 0) + { + wlerr("ERROR: mac802154dev_takesem failed: %d\n", ret); + return ret; + } + + /* Allocate a new open struct */ + + opriv = (FAR struct mac802154dev_open_s *) + kmm_zalloc(sizeof(struct mac802154dev_open_s)); + + if (!opriv) + { + wlerr("ERROR: Failed to allocate new open struct\n"); + ret = -ENOMEM; + goto errout_with_sem; + } + + /* Attach the open struct to the device */ + + opriv->md_flink = dev->md_open; + dev->md_open = opriv; + + /* Attach the open struct to the file structure */ + + filep->f_priv = (FAR void *)opriv; + ret = OK; + +errout_with_sem: + mac802154dev_givesem(&dev->md_exclsem); + return ret; +} + +/**************************************************************************** + * Name: mac802154dev_close + * + * Description: + * Close the 802.15.4 MAC character device. + * + ****************************************************************************/ + +static int mac802154dev_close(FAR struct file *filep) +{ + FAR struct inode *inode; + FAR struct mac802154_chardevice_s *dev; + FAR struct mac802154dev_open_s *opriv; + FAR struct mac802154dev_open_s *curr; + FAR struct mac802154dev_open_s *prev; + irqstate_t flags; + bool closing; + int ret; + + DEBUGASSERT(filep && filep->f_priv && filep->f_inode); + opriv = filep->f_priv; + inode = filep->f_inode; + DEBUGASSERT(inode->i_private); + dev = (FAR struct mac802154_chardevice_s *)inode->i_private; + + /* Handle an improbable race conditions with the following atomic test + * and set. + * + * This is actually a pretty feeble attempt to handle this. The + * improbable race condition occurs if two different threads try to + * close the joystick driver at the same time. The rule: don't do + * that! It is feeble because we do not really enforce stale pointer + * detection anyway. + */ + + flags = enter_critical_section(); + closing = opriv->md_closing; + opriv->md_closing = true; + leave_critical_section(flags); + + if (closing) + { + /* Another thread is doing the close */ + + return OK; + } + + /* Get exclusive access to the driver structure */ + + ret = mac802154dev_takesem(&dev->md_exclsem); + if (ret < 0) + { + wlerr("ERROR: mac802154_takesem failed: %d\n", ret); + return ret; + } + + /* Find the open structure in the list of open structures for the device */ + + for (prev = NULL, curr = dev->md_open; + curr && curr != opriv; + prev = curr, curr = curr->md_flink); + + DEBUGASSERT(curr); + if (!curr) + { + wlerr("ERROR: Failed to find open entry\n"); + ret = -ENOENT; + goto errout_with_exclsem; + } + + /* Remove the structure from the device */ + + if (prev) + { + prev->md_flink = opriv->md_flink; + } + else + { + dev->md_open = opriv->md_flink; + } + + /* And free the open structure */ + + kmm_free(opriv); + ret = OK; + +errout_with_exclsem: + mac802154dev_givesem(&dev->md_exclsem); + return ret; +} + +/**************************************************************************** + * Name: mac802154dev_read + * + * Description: + * Return the last received packet. + * + ****************************************************************************/ + +static ssize_t mac802154dev_read(FAR struct file *filep, FAR char *buffer, + size_t len) +{ + FAR struct inode *inode; + FAR struct mac802154_chardevice_s *dev; + FAR struct mac802154dev_rxframe_s *rx; + FAR struct ieee802154_data_ind_s *ind; + int ret; + + DEBUGASSERT(filep && filep->f_inode); + inode = filep->f_inode; + DEBUGASSERT(inode->i_private); + dev = (FAR struct mac802154_chardevice_s *)inode->i_private; + + /* Check to make sure the buffer is the right size for the struct */ + + if (len != sizeof(struct mac802154dev_rxframe_s)) + { + wlerr("ERROR: buffer isn't a mac802154dev_rxframe_s: %lu\n", + (unsigned long)len); + return -EINVAL; + } + + DEBUGASSERT(buffer != NULL); + rx = (FAR struct mac802154dev_rxframe_s *)buffer; + + while (1) + { + /* Get exclusive access to the driver structure */ + + ret = mac802154dev_takesem(&dev->md_exclsem); + if (ret < 0) + { + wlerr("ERROR: mac802154dev_takesem failed: %d\n", ret); + return ret; + } + + /* Try popping a data indication off the list */ + + ind = mac802154dev_pop_dataind(dev); + + /* If the indication is not null, we can exit the loop and copy the data */ + + if (ind != NULL) + { + mac802154dev_givesem(&dev->md_exclsem); + break; + } + + /* If this is a non-blocking call, or if there is another read operation + * already pending, don't block. This driver returns EAGAIN even when + * configured as non-blocking if another read operation is already pending + * This situation should be rare. It will only occur when there are 2 calls + * to read from separate threads and there was no data in the rx list. + */ + + if ((filep->f_oflags & O_NONBLOCK) || dev->readpending) + { + mac802154dev_givesem(&dev->md_exclsem); + return -EAGAIN; + } + + dev->readpending = true; + mac802154dev_givesem(&dev->md_exclsem); + + /* Wait to be signaled when a frame is added to the list */ + + if (sem_wait(&dev->readsem) < 0) + { + DEBUGASSERT(errno == EINTR); + /* Need to get exclusive access again to change the pending bool */ + + ret = mac802154dev_takesem(&dev->md_exclsem); + dev->readpending = false; + mac802154dev_givesem(&dev->md_exclsem); + return -EINTR; + } + + /* Let the loop wrap back around, we will then pop a indication and this + * time, it should have a data indication + */ + } + + rx->length = (ind->frame->io_len - ind->frame->io_offset); + + /* Copy the data from the IOB to the user supplied struct */ + + memcpy(&rx->payload[0], &ind->frame->io_data[ind->frame->io_offset], + rx->length); + + memcpy(&rx->meta, ind, sizeof(struct ieee802154_data_ind_s)); + + /* Zero out the forward link and IOB reference */ + + rx->meta.flink = NULL; + rx->meta.frame = NULL; + + /* Deallocate the data indication */ + + ieee802154_ind_free(ind); + + return OK; +} + +/**************************************************************************** + * Name: mac802154dev_write + * + * Description: + * Send a packet over the IEEE802.15.4 network. + * + ****************************************************************************/ + +static ssize_t mac802154dev_write(FAR struct file *filep, + FAR const char *buffer, size_t len) +{ + FAR struct inode *inode; + FAR struct mac802154_chardevice_s *dev; + FAR struct mac802154dev_txframe_s *tx; + FAR struct iob_s *iob; + struct mac802154dev_dwait_s dwait; + int ret; + + DEBUGASSERT(filep && filep->f_inode); + inode = filep->f_inode; + DEBUGASSERT(inode->i_private); + dev = (FAR struct mac802154_chardevice_s *)inode->i_private; + + /* Check if the struct is write */ + + if (len != sizeof(struct mac802154dev_txframe_s)) + { + wlerr("ERROR: buffer isn't a mac802154dev_txframe_s: %lu\n", + (unsigned long)len); + + return -EINVAL; + } + + DEBUGASSERT(buffer != NULL); + tx = (FAR struct mac802154dev_txframe_s *)buffer; + + /* Allocate an IOB to put the frame in */ + + iob = iob_alloc(false); + DEBUGASSERT(iob != NULL); + + iob->io_flink = NULL; + iob->io_len = 0; + iob->io_offset = 0; + iob->io_pktlen = 0; + + /* Get the MAC header length */ + + ret = mac802154_get_mhrlen(dev->md_mac, &tx->meta); + if (ret < 0) + { + wlerr("ERROR: TX meta-data is invalid"); + return ret; + } + + iob->io_offset = ret; + iob->io_len = iob->io_offset; + + memcpy(&iob->io_data[iob->io_offset], tx->payload, tx->length); + + iob->io_len += tx->length; + + /* If this is a blocking operation, we need to setup a wait struct so we + * can unblock when the packet transmission has finished. If this is a + * non-blocking write, we pass off the data and then move along. Technically + * we stil have to wait for the transaction to get put into the buffer, but we + * won't wait for the transaction to actually finish. */ + + if (!(filep->f_oflags & O_NONBLOCK)) + { + /* Get exclusive access to the driver structure */ + + ret = mac802154dev_takesem(&dev->md_exclsem); + if (ret < 0) + { + wlerr("ERROR: mac802154dev_takesem failed: %d\n", ret); + return ret; + } + + /* Setup the wait struct */ + + dwait.mw_handle = tx->meta.msdu_handle; + + /* Link the wait struct */ + + dwait.mw_flink = dev->md_dwait; + dev->md_dwait = &dwait; + + sem_init(&dwait.mw_sem, 0, 0); + sem_setprotocol(&dwait.mw_sem, SEM_PRIO_NONE); + + mac802154dev_givesem(&dev->md_exclsem); + } + + /* Pass the request to the MAC layer */ + + ret = mac802154_req_data(dev->md_mac, &tx->meta, iob); + + if (ret < 0) + { + wlerr("ERROR: req_data failed %d\n", ret); + return ret; + } + + if (!(filep->f_oflags & O_NONBLOCK)) + { + /* Wait for the DATA.confirm callback to be called for our handle */ + + if (sem_wait(&dwait.mw_sem) < 0) + { + /* This should only happen if the wait was canceled by an signal */ + + sem_destroy(&dwait.mw_sem); + DEBUGASSERT(errno == EINTR); + return -EINTR; + } + + /* The unlinking of the wait struct happens inside the callback. This + * is more efficient since it will already have to find the struct in + * the list in order to perform the sem_post. + */ + + sem_destroy(&dwait.mw_sem); + return dwait.mw_status; + } + + return OK; +} + +/**************************************************************************** + * Name: mac802154dev_ioctl + * + * Description: + * Control the MAC layer via MLME IOCTL commands. + * + ****************************************************************************/ + +static int mac802154dev_ioctl(FAR struct file *filep, int cmd, + unsigned long arg) +{ + FAR struct inode *inode; + FAR struct mac802154_chardevice_s *dev; + int ret; + + DEBUGASSERT(filep != NULL && filep->f_priv != NULL && + filep->f_inode != NULL); + inode = filep->f_inode; + DEBUGASSERT(inode->i_private); + dev = (FAR struct mac802154_chardevice_s *)inode->i_private; + + /* Get exclusive access to the driver structure */ + + ret = mac802154dev_takesem(&dev->md_exclsem); + if (ret < 0) + { + wlerr("ERROR: mac802154dev_takesem failed: %d\n", ret); + return ret; + } + + /* Handle the ioctl command */ + + switch (cmd) + { +#ifndef CONFIG_DISABLE_SIGNALS + /* Command: MAC802154IOC_MLME_REGISTER, MAC802154IOC_MCPS_REGISTER + * Description: Register to receive a signal whenever there is a + * event primitive sent from the MAC layer. + * Argument: A read-only pointer to an instance of struct + * mac802154dev_notify_s + * Return: Zero (OK) on success. Minus one will be returned on + * failure with the errno value set appropriately. + */ + + case MAC802154IOC_MLME_REGISTER: + { + FAR struct mac802154dev_notify_s *notify = + (FAR struct mac802154dev_notify_s *)((uintptr_t)arg); + + if (notify) + { + /* Save the notification events */ + + dev->md_mlme_notify.mn_signo = notify->mn_signo; + dev->md_mlme_pid = getpid(); + + return OK; + } + } + break; + + case MAC802154IOC_MCPS_REGISTER: + { + FAR struct mac802154dev_notify_s *notify = + (FAR struct mac802154dev_notify_s *)((uintptr_t)arg); + + if (notify) + { + /* Save the notification events */ + + dev->md_mcps_notify.mn_signo = notify->mn_signo; + dev->md_mcps_pid = getpid(); + + return OK; + } + } + break; +#endif + default: + { + /* Forward any unrecognized commands to the MAC layer */ + + mac802154_ioctl(dev->md_mac, cmd, arg); + } + + break; + } + + mac802154dev_givesem(&dev->md_exclsem); + return ret; +} + +static void mac802154dev_mlme_notify(FAR const struct ieee802154_maccb_s *maccb, + enum ieee802154_macnotify_e notif, + FAR const union ieee802154_mlme_notify_u *arg) +{ + FAR struct mac802154dev_callback_s *cb = + (FAR struct mac802154dev_callback_s *)maccb; + FAR struct mac802154_chardevice_s *dev; + + DEBUGASSERT(cb != NULL && cb->mc_priv != NULL); + dev = cb->mc_priv; + + switch (notif) + { +#warning Handle MLME notifications + default: + break; + } +} + +static void mac802154dev_mcps_notify(FAR const struct ieee802154_maccb_s *maccb, + enum ieee802154_macnotify_e notif, + FAR const union ieee802154_mcps_notify_u *arg) +{ + FAR struct mac802154dev_callback_s *cb = + (FAR struct mac802154dev_callback_s *)maccb; + FAR struct mac802154_chardevice_s *dev; + + DEBUGASSERT(cb != NULL && cb->mc_priv != NULL); + dev = cb->mc_priv; + + switch (notif) + { + case IEEE802154_NOTIFY_CONF_DATA: + { + mac802154dev_conf_data(dev, &arg->dataconf); + } + break; + case IEEE802154_NOTIFY_IND_DATA: + { + mac802154dev_ind_data(dev, arg->dataind); + } + break; + default: + break; + } +} + +static void mac802154dev_conf_data(FAR struct mac802154_chardevice_s *dev, + FAR const struct ieee802154_data_conf_s *conf) +{ + FAR struct mac802154dev_dwait_s *curr; + FAR struct mac802154dev_dwait_s *prev; + + /* Get exclusive access to the driver structure. We don't care about any + * signals so if we see one, just go back to trying to get access again */ + + while (mac802154dev_takesem(&dev->md_exclsem) != 0); + + /* Search to see if there is a dwait pending for this transaction */ + + for (prev = NULL, curr = dev->md_dwait; + curr && curr->mw_handle != conf->handle; + prev = curr, curr = curr->mw_flink); + + /* If a dwait is found */ + + if (curr) + { + /* Unlink the structure from the list. The struct should be allocated on + * the calling write's stack, so we don't need to worry about deallocating + * here */ + + if (prev) + { + prev->mw_flink = curr->mw_flink; + } + else + { + dev->md_dwait = curr->mw_flink; + } + + /* Copy the transmission status into the dwait struct */ + + curr->mw_status = conf->status; + + /* Wake the thread waiting for the data transmission */ + + sem_post(&curr->mw_sem); + + /* Release the driver */ + + mac802154dev_givesem(&dev->md_exclsem); + } + +#ifndef CONFIG_DISABLE_SIGNALS + /* Send a signal to the registered application */ + +#ifdef CONFIG_CAN_PASS_STRUCTS + /* Copy the status as the signal data to be optionally used by app */ + + union sigval value; + value.sival_int = (int)conf->status; + (void)sigqueue(dev->md_mcps_pid, dev->md_mcps_notify.mn_signo, value); +#else + (void)sigqueue(dev->md_mcps_pid, dev->md_mcps_notify.mn_signo, + value.sival_ptr); +#endif +#endif +} + +static void mac802154dev_ind_data(FAR struct mac802154_chardevice_s *dev, + FAR struct ieee802154_data_ind_s *ind) +{ + /* Get exclusive access to the driver structure. We don't care about any + * signals so if we see one, just go back to trying to get access again */ + + while (mac802154dev_takesem(&dev->md_exclsem) != 0); + + /* Push the indication onto the list */ + + mac802154dev_push_dataind(dev, ind); + + /* Check if there is a read waiting for data */ + + if (dev->readpending) + { + /* Wake the thread waiting for the data transmission */ + + dev->readpending = false; + sem_post(&dev->readsem); + } + + /* Release the driver */ + + mac802154dev_givesem(&dev->md_exclsem); + +#ifndef CONFIG_DISABLE_SIGNALS + /* Send a signal to the registered application */ + +#ifdef CONFIG_CAN_PASS_STRUCTS + /* Copy the status as the signal data to be optionally used by app */ + + union sigval value; + value.sival_int = IEEE802154_STATUS_SUCCESS; + (void)sigqueue(dev->md_mcps_pid, dev->md_mcps_notify.mn_signo, value); +#else + (void)sigqueue(dev->md_mcps_pid, dev->md_mcps_notify.mn_signo, + value.sival_ptr); +#endif +#endif +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: mac802154dev_register + * + * Description: + * Register a character driver to access the IEEE 802.15.4 MAC layer from + * user-space + * + * Input Parameters: + * mac - Pointer to the mac layer struct to be registerd. + * minor - The device minor number. The IEEE802.15.4 MAC character device + * will be registered as /dev/ieeeN where N is the minor number + * + * Returned Values: + * Zero (OK) is returned on success. Otherwise a negated errno value is + * returned to indicate the nature of the failure. + * + ****************************************************************************/ + +int mac802154dev_register(MACHANDLE mac, int minor) +{ + FAR struct mac802154_chardevice_s *dev; + FAR struct ieee802154_maccb_s *maccb; + char devname[DEVNAME_FMTLEN]; + int ret; + + dev = kmm_zalloc(sizeof(struct mac802154_chardevice_s)); + if (!dev) + { + wlerr("ERROR: Failed to allocate device structure\n"); + return -ENOMEM; + } + + /* Initialize the new mac driver instance */ + + dev->md_mac = mac; + sem_init(&dev->md_exclsem, 0, 1); /* Allow the device to be opened once + * before blocking */ + + sem_init(&dev->readsem, 0, 0); + sem_setprotocol(&dev->readsem, SEM_PRIO_NONE); + dev->readpending = false; + + /* Initialize the MAC callbacks */ + + dev->md_cb.mc_priv = dev; + + maccb = &dev->md_cb.mc_cb; + maccb->mlme_notify = mac802154dev_mlme_notify; + maccb->mcps_notify = mac802154dev_mcps_notify; + + /* Bind the callback structure */ + + ret = mac802154_bind(mac, maccb); + if (ret < 0) + { + nerr("ERROR: Failed to bind the MAC callbacks: %d\n", ret); + + /* Free memory and return the error */ + kmm_free(dev); + return ret; + } + + /* Create the character device name */ + + snprintf(devname, DEVNAME_FMTLEN, DEVNAME_FMT, minor); + + /* Register the mac character driver */ + + ret = register_driver(devname, &mac802154dev_fops, 0666, dev); + if (ret < 0) + { + wlerr("ERROR: register_driver failed: %d\n", ret); + goto errout_with_priv; + } + + return OK; + +errout_with_priv: + sem_destroy(&dev->md_exclsem); + kmm_free(dev); + return ret; +} diff --git a/wireless/ieee802154/mac802154_indalloc.c b/wireless/ieee802154/mac802154_indalloc.c new file mode 100644 index 0000000000..5e05c5c09e --- /dev/null +++ b/wireless/ieee802154/mac802154_indalloc.c @@ -0,0 +1,415 @@ +/**************************************************************************** + * wireless/ieee802154_indalloc.c + * + * Copyright (C) 2017 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include + +#include + +#include + +#include + +#include "mac802154.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#if !defined(CONFIG_IEEE802154_IND_PREALLOC) || CONFIG_IEEE802154_IND_PREALLOC < 0 +# undef CONFIG_IEEE802154_IND_PREALLOC +# define CONFIG_IEEE802154_IND_PREALLOC 20 +#endif + +#if !defined(CONFIG_IEEE802154_IND_IRQRESERVE) || CONFIG_IEEE802154_IND_IRQRESERVE < 0 +# undef CONFIG_IEEE802154_IND_IRQRESERVE +# define CONFIG_IEEE802154_IND_IRQRESERVE 10 +#endif + +#if CONFIG_IEEE802154_IND_IRQRESERVE > CONFIG_IEEE802154_IND_PREALLOC +# undef CONFIG_IEEE802154_IND_IRQRESERVE +# define CONFIG_IEEE802154_IND_IRQRESERVE CONFIG_IEEE802154_IND_PREALLOC +#endif + +/* Memory Pools */ + +#define POOL_IND_GENERAL 0 +#define POOL_IND_IRQ 1 +#define POOL_IND_DYNAMIC 2 + +/**************************************************************************** + * Private Data Types + ****************************************************************************/ + +/* Private data type that extends the ieee802154_data_ind_s struct */ + +struct ieee802154_priv_ind_s +{ + /* Must be first member so we can cast to/from */ + + struct ieee802154_data_ind_s pub; + FAR struct ieee802154_priv_ind_s *flink; + uint8_t pool; +}; + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +#if CONFIG_IEEE802154_IND_PREALLOC > 0 +#if CONFIG_IEEE802154_IND_PREALLOC > CONFIG_IEEE802154_IND_IRQRESERVE +/* The g_indfree is a list of meta-data structures that are available for + * general use. The number of messages in this list is a system configuration + * item. + */ + +static struct ieee802154_priv_ind_s *g_indfree; +#endif + +#if CONFIG_IEEE802154_IND_IRQRESERVE > 0 +/* The g_indfree_irq is a list of meta-data structures that are reserved for + * use by only by interrupt handlers. + */ + +static struct ieee802154_priv_ind_s *g_indfree_irq; +#endif + +/* Pool of pre-allocated meta-data stuctures */ + +static struct ieee802154_priv_ind_s g_indpool[CONFIG_IEEE802154_IND_PREALLOC]; +#endif /* CONFIG_IEEE802154_IND_PREALLOC > 0 */ + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: ieee802154_indpool_initialize + * + * Description: + * This function initializes the meta-data allocator. This function must + * be called early in the initialization sequence before any radios + * begin operation. + * + * Inputs: + * None + * + * Return Value: + * None + * + ****************************************************************************/ + +void ieee802154_indpool_initialize(void) +{ +#if CONFIG_IEEE802154_IND_PREALLOC > 0 + FAR struct ieee802154_priv_ind_s *pool = g_indpool; + int remaining = CONFIG_IEEE802154_IND_PREALLOC; + +#if CONFIG_IEEE802154_IND_PREALLOC > CONFIG_IEEE802154_IND_IRQRESERVE + /* Initialize g_indfree, thelist of meta-data structures that are available + * for general use. + */ + + g_indfree = NULL; + while (remaining > CONFIG_IEEE802154_IND_IRQRESERVE) + { + FAR struct ieee802154_priv_ind_s *ind = pool; + + /* Add the next meta data structure from the pool to the list of + * general structures. + */ + + ind->flink = g_indfree; + g_indfree = ind; + + /* Set up for the next structure from the pool */ + + pool++; + remaining--; + } +#endif + +#if CONFIG_IEEE802154_IND_IRQRESERVE > 0 + /* Initialize g_indfree_irq is a list of meta-data structures reserved for + * use by only by interrupt handlers. + */ + + g_indfree_irq = NULL; + while (remaining > 0) + { + FAR struct ieee802154_priv_ind_s *ind = pool; + + /* Add the next meta data structure from the pool to the list of + * general structures. + */ + + ind->flink = g_indfree_irq; + g_indfree_irq = ind; + + /* Set up for the next structure from the pool */ + + pool++; + remaining--; + } +#endif +#endif /* CONFIG_IEEE802154_IND_PREALLOC > 0 */ +} + +/**************************************************************************** + * Name: ieee802154_ind_allocate + * + * Description: + * The ieee802154_ind_allocate function will get a free meta-data + * structure for use by the IEEE 802.15.4 MAC. + * + * Interrupt handling logic will first attempt to allocate from the + * g_indfree list. If that list is empty, it will attempt to allocate + * from its reserve, g_indfree_irq. If that list is empty, then the + * allocation fails (NULL is returned). + * + * Non-interrupt handler logic will attempt to allocate from g_indfree + * list. If that the list is empty, then the meta-data structure will be + * allocated from the dynamic memory pool. + * + * Inputs: + * None + * + * Return Value: + * A reference to the allocated msg structure. All user fields in this + * structure have been zeroed. On a failure to allocate, NULL is + * returned. + * + ****************************************************************************/ + +FAR struct ieee802154_data_ind_s *ieee802154_ind_allocate(void) +{ +#if CONFIG_IEEE802154_IND_PREALLOC > 0 + FAR struct ieee802154_priv_ind_s *ind; + irqstate_t flags; + uint8_t pool; + + /* If we were called from an interrupt handler, then try to get the meta- + * data structure from generally available list of messages. If this fails, + * then try the list of messages reserved for interrupt handlers + */ + + flags = enter_critical_section(); /* Always necessary in SMP mode */ + if (up_interrupt_context()) + { +#if CONFIG_IEEE802154_IND_PREALLOC > CONFIG_IEEE802154_IND_IRQRESERVE + /* Try the general free list */ + + if (g_indfree != NULL) + { + ind = g_indfree; + g_indfree = ind->flink; + + leave_critical_section(flags); + pool = POOL_IND_GENERAL; + } + else +#endif +#if CONFIG_IEEE802154_IND_IRQRESERVE > 0 + /* Try the list list reserved for interrupt handlers */ + + if (g_indfree_irq != NULL) + { + ind = g_indfree_irq; + g_indfree_irq = ind->flink; + + leave_critical_section(flags); + pool = POOL_IND_IRQ; + } + else +#endif + { + leave_critical_section(flags); + return NULL; + } + } + + /* We were not called from an interrupt handler. */ + + else + { +#if CONFIG_IEEE802154_IND_PREALLOC > CONFIG_IEEE802154_IND_IRQRESERVE + /* Try the general free list */ + + if (g_indfree != NULL) + { + ind = g_indfree; + g_indfree = ind->flink; + + leave_critical_section(flags); + pool = POOL_IND_GENERAL; + } + else +#endif + { + /* If we cannot a meta-data structure from the free list, then we + * will have to allocate one from the kernal memory pool. + */ + + leave_critical_section(flags); + ind = (FAR struct ieee802154_priv_ind_s *) + kmm_malloc((sizeof (struct ieee802154_priv_ind_s))); + + /* Check if we allocated the meta-data structure */ + + if (ind != NULL) + { + /* Yes... remember that this meta-data structure was dynamically allocated */ + + pool = POOL_IND_DYNAMIC; + } + } + } + + /* We have successfully allocated memory from some source. + * Zero and tag the alloated meta-data structure. + */ + + ind->pool = pool; + memset(&ind->pub, 0, sizeof(struct ieee802154_data_ind_s)); + + /* Allocate the IOB for the frame */ + + ind->pub.frame = iob_alloc(true); + if (ind->pub.frame == NULL) + { + /* Deallocate the ind */ + + ieee802154_ind_free(&ind->pub); + + return NULL; + } + + ind->pub.frame->io_flink = NULL; + ind->pub.frame->io_len = 0; + ind->pub.frame->io_offset = 0; + ind->pub.frame->io_pktlen = 0; + + return &ind->pub; +#else + return NULL; +#endif +} + +/**************************************************************************** + * Name: ieee802154_ind_free + * + * Description: + * The ieee802154_ind_free function will return a meta-data structure to + * the free pool of messages if it was a pre-allocated meta-data + * structure. If the meta-data structure was allocated dynamically it will + * be deallocated. + * + * Inputs: + * ind - meta-data structure to free + * + * Return Value: + * None + * + ****************************************************************************/ + +void ieee802154_ind_free(FAR struct ieee802154_data_ind_s *ind) +{ +#if CONFIG_IEEE802154_IND_PREALLOC > 0 + irqstate_t flags; + FAR struct ieee802154_priv_ind_s *priv = + (FAR struct ieee802154_priv_ind_s *)ind; + + /* Check if the IOB is not NULL. The only time it should be NULL is if we + * allocated the data_ind, but the IOB allocation failed so we now have to + * free the data_ind but not the IOB. This really should happen rarely if at all. + */ + + if (ind->frame != NULL) + { + iob_free(ind->frame); + } + +#if CONFIG_IEEE802154_IND_PREALLOC > CONFIG_IEEE802154_IND_IRQRESERVE + /* If this is a generally available pre-allocated meta-data structure, + * then just put it back in the free list. + */ + + if (priv->pool == POOL_IND_GENERAL) + { + /* Make sure we avoid concurrent access to the free + * list from interrupt handlers. + */ + + flags = enter_critical_section(); + priv->flink = g_indfree; + g_indfree = priv; + leave_critical_section(flags); + } + else +#endif + +#if CONFIG_IEEE802154_IND_IRQRESERVE > 0 + /* If this is a meta-data structure pre-allocated for interrupts, + * then put it back in the correct free list. + */ + + if (priv->pool == POOL_IND_IRQ) + { + /* Make sure we avoid concurrent access to the free + * list from interrupt handlers. + */ + + flags = enter_critical_section(); + priv->flink = g_indfree_irq; + g_indfree_irq = priv; + leave_critical_section(flags); + } + else +#endif + + { + /* Otherwise, deallocate it. */ + + DEBUGASSERT(priv->pool == POOL_IND_DYNAMIC); + sched_kfree(priv); + } +#endif +} diff --git a/wireless/ieee802154/mac802154_loopback.c b/wireless/ieee802154/mac802154_loopback.c index f914b5db1a..47940329c7 100644 --- a/wireless/ieee802154/mac802154_loopback.c +++ b/wireless/ieee802154/mac802154_loopback.c @@ -56,6 +56,8 @@ #include #include +#include "mac802154.h" + #ifdef CONFIG_IEEE802154_LOOPBACK /**************************************************************************** @@ -80,6 +82,10 @@ #define LO_WDDELAY (1*CLK_TCK) +/* Fake value for MAC header length */ + +#define MAC_HDRLEN 9 + /**************************************************************************** * Private Types ****************************************************************************/ @@ -91,9 +97,12 @@ struct lo_driver_s { bool lo_bifup; /* true:ifup false:ifdown */ - bool lo_txdone; /* One RX packet was looped back */ + bool lo_pending; /* True: TX poll pending */ + uint16_t lo_panid; /* Fake PAN ID for testing */ WDOG_ID lo_polldog; /* TX poll timer */ struct work_s lo_work; /* For deferring poll work to the work queue */ + FAR struct iob_s *lo_head; /* Head of IOBs queued for loopback */ + FAR struct iob_s *lo_tail; /* Tail of IOBs queued for loopback */ /* This holds the information visible to the NuttX network */ @@ -113,29 +122,39 @@ static uint8_t g_iobuffer[CONFIG_NET_6LOWPAN_MTU + CONFIG_NET_GUARDSIZE]; /* Polling logic */ -static int lo_txpoll(FAR struct net_driver_s *dev); +static int lo_loopback(FAR struct net_driver_s *dev); +static void lo_loopback_work(FAR void *arg); static void lo_poll_work(FAR void *arg); static void lo_poll_expiry(int argc, wdparm_t arg, ...); /* NuttX callback functions */ -static int lo_ifup(FAR struct net_driver_s *dev); -static int lo_ifdown(FAR struct net_driver_s *dev); +static int lo_ifup(FAR struct net_driver_s *dev); +static int lo_ifdown(FAR struct net_driver_s *dev); static void lo_txavail_work(FAR void *arg); -static int lo_txavail(FAR struct net_driver_s *dev); +static int lo_txavail(FAR struct net_driver_s *dev); #if defined(CONFIG_NET_IGMP) || defined(CONFIG_NET_ICMPv6) -static int lo_addmac(FAR struct net_driver_s *dev, FAR const uint8_t *mac); +static int lo_addmac(FAR struct net_driver_s *dev, FAR const uint8_t *mac); #ifdef CONFIG_NET_IGMP -static int lo_rmmac(FAR struct net_driver_s *dev, FAR const uint8_t *mac); +static int lo_rmmac(FAR struct net_driver_s *dev, FAR const uint8_t *mac); #endif #endif +#ifdef CONFIG_NETDEV_IOCTL +static int lo_ioctl(FAR struct net_driver_s *dev, int cmd, + unsigned long arg); +#endif +static int lo_get_mhrlen(FAR struct ieee802154_driver_s *netdev, + FAR const struct ieee802154_frame_meta_s *meta); +static int lo_req_data(FAR struct ieee802154_driver_s *netdev, + FAR const struct ieee802154_frame_meta_s *meta, + FAR struct iob_s *framelist); /**************************************************************************** * Private Functions ****************************************************************************/ /**************************************************************************** - * Name: lo_txpoll + * Name: lo_loopback * * Description: * Check if the network has any outgoing packets ready to send. This is @@ -154,71 +173,47 @@ static int lo_rmmac(FAR struct net_driver_s *dev, FAR const uint8_t *mac); * ****************************************************************************/ -static int lo_txpoll(FAR struct net_driver_s *dev) +static int lo_loopback(FAR struct net_driver_s *dev) { FAR struct lo_driver_s *priv = (FAR struct lo_driver_s *)dev->d_private; - FAR struct iob_s *head; - FAR struct iob_s *tail; + struct ieee802154_data_ind_s ind; FAR struct iob_s *iob; int ret; - if (dev->d_len > 0 || priv->lo_ieee.i_framelist != NULL) - { - ninfo("d_len: %u i_framelist: %p\n", - dev->d_len, priv->lo_ieee.i_framelist); + memset(&ind, 0, sizeof(struct ieee802154_data_ind_s)); - /* The only two valid settings are: - * - * 1. Nothing to send: - * dev->d_len == 0 && priv->lo_ieee.i_framelist == NULL - * 2. Outgoing packet has been converted to IEEE802.15.4 frames: - * dev->d_len == 0 && priv->lo_ieee.i_framelist != NULL - */ - - DEBUGASSERT(dev->d_len == 0 && priv->lo_ieee.i_framelist != NULL); - } - - /* Remove the queued IOBs from driver structure */ - - head = priv->lo_ieee.i_framelist; - - /* Find the tail of the IOB queue */ - - for (tail = NULL, iob = head; - iob != NULL; - tail = iob, iob = iob->io_flink); - - /* Loop while there frames to be sent, i.e., while the IOB list is not - * emtpy. Sending, of course, just means relaying back through the network + /* Loop while there framelist to be sent, i.e., while the freme list is not + * emtpy. Sending, of course, just means relaying back through the network * for this driver. */ - while (head != NULL) + while (priv->lo_head != NULL) { + ninfo("Looping frame IOB %p\n", iob); + /* Increment statistics */ NETDEV_RXPACKETS(&priv->lo_ieee.i_dev); /* Remove the IOB from the queue */ - iob = head; - head = iob->io_flink; + iob = priv->lo_head; + priv->lo_head = iob->io_flink; iob->io_flink = NULL; - /* Is the queue now empty? */ + /* Did the framelist become empty? */ - if (head == NULL) + if (priv->lo_head == NULL) { - tail = NULL; + priv->lo_tail = NULL; } /* Return the next frame to the network */ - iob->io_flink = NULL; - priv->lo_ieee.i_framelist = iob; + ninfo("Send frame %p to the network: Offset=%u Length=%u\n", + iob, iob->io_offset, iob->io_len); - ninfo("Send frame %p to the network. Length=%u\n", iob, iob->io_len); - ret = sixlowpan_input(&priv->lo_ieee); + ret = sixlowpan_input(&priv->lo_ieee, iob, &ind); /* Increment statistics */ @@ -230,38 +225,39 @@ static int lo_txpoll(FAR struct net_driver_s *dev) NETDEV_TXERRORS(&priv->lo_ieee.i_dev); NETDEV_ERRORS(&priv->lo_ieee.i_dev); } - - /* What if the network responds with more frames to send? */ - - if (priv->lo_ieee.i_framelist != NULL) - { - /* Append the new list to the tail of the queue */ - - iob = priv->lo_ieee.i_framelist; - priv->lo_ieee.i_framelist = NULL; - - if (tail == NULL) - { - head = iob; - } - else - { - tail->io_flink = iob; - } - - /* Find the new tail of the IOB queue */ - - for (tail = iob, iob = iob->io_flink; - iob != NULL; - tail = iob, iob = iob->io_flink); - } - - priv->lo_txdone = true; } return 0; } +/**************************************************************************** + * Name: lo_loopback_work + * + * Description: + * Perform loopback of received framelist. + * + * Parameters: + * arg - The argument passed when work_queue() as called. + * + * Returned Value: + * OK on success + * + * Assumptions: + * The network is locked + * + ****************************************************************************/ + +static void lo_loopback_work(FAR void *arg) +{ + FAR struct lo_driver_s *priv = (FAR struct lo_driver_s *)arg; + + /* Perform the loopback */ + + net_lock(); + (void)lo_loopback(&priv->lo_ieee.i_dev); + net_unlock(); +} + /**************************************************************************** * Name: lo_poll_work * @@ -286,18 +282,7 @@ static void lo_poll_work(FAR void *arg) /* Perform the poll */ net_lock(); - priv->lo_txdone = false; - (void)devif_timer(&priv->lo_ieee.i_dev, lo_txpoll); - - /* Was something received and looped back? */ - - while (priv->lo_txdone) - { - /* Yes, poll again for more TX data */ - - priv->lo_txdone = false; - (void)devif_poll(&priv->lo_ieee.i_dev, lo_txpoll); - } + (void)devif_timer(&priv->lo_ieee.i_dev, lo_loopback); /* Setup the watchdog poll timer again */ @@ -327,14 +312,18 @@ static void lo_poll_expiry(int argc, wdparm_t arg, ...) { FAR struct lo_driver_s *priv = (FAR struct lo_driver_s *)arg; - if (!work_available(&priv->lo_work)) + if (!work_available(&priv->lo_work) || priv->lo_head != NULL) { nwarn("WARNING: lo_work NOT available\n"); + priv->lo_pending = true; } + else + { + /* Schedule to perform the interrupt processing on the worker thread. */ - /* Schedule to perform the interrupt processing on the worker thread. */ - - work_queue(LPBKWORK, &priv->lo_work, lo_poll_work, priv, 0); + priv->lo_pending = false; + work_queue(LPBKWORK, &priv->lo_work, lo_poll_work, priv, 0); + } } /**************************************************************************** @@ -363,17 +352,17 @@ static int lo_ifup(FAR struct net_driver_s *dev) dev->d_ipv6addr[3], dev->d_ipv6addr[4], dev->d_ipv6addr[5], dev->d_ipv6addr[6], dev->d_ipv6addr[7]); -#ifdef CONFIG_NET_6LOWPAN_RIMEADDR_EXTENDED +#ifdef CONFIG_NET_6LOWPAN_EXTENDEDADDR ninfo(" Node: %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x PANID=%04x\n", dev->d_mac.ieee802154.u8[0], dev->d_mac.ieee802154.u8[1], dev->d_mac.ieee802154.u8[2], dev->d_mac.ieee802154.u8[3], dev->d_mac.ieee802154.u8[4], dev->d_mac.ieee802154.u8[5], dev->d_mac.ieee802154.u8[6], dev->d_mac.ieee802154.u8[7], - priv->lo_ieee.i_panid); + priv->lo_panid); #else ninfo(" Node: %02x:%02x PANID=%04x\n", dev->d_mac.ieee802154.u8[0], dev->d_mac.ieee802154.u8[1], - priv->lo_ieee.i_panid); + priv->lo_panid); #endif /* Set and activate a timer process */ @@ -438,21 +427,16 @@ static void lo_txavail_work(FAR void *arg) { FAR struct lo_driver_s *priv = (FAR struct lo_driver_s *)arg; - ninfo("IP up: %u\n", priv->lo_bifup); + ninfo("TX available work. IP up: %u\n", priv->lo_bifup); /* Ignore the notification if the interface is not yet up */ net_lock(); if (priv->lo_bifup) { - do - { - /* If so, then poll the network for new XMIT data */ + /* If so, then poll the network for new XMIT data */ - priv->lo_txdone = false; - (void)devif_poll(&priv->lo_ieee.i_dev, lo_txpoll); - } - while (priv->lo_txdone); + (void)devif_poll(&priv->lo_ieee.i_dev, lo_loopback); } net_unlock(); @@ -484,14 +468,20 @@ static int lo_txavail(FAR struct net_driver_s *dev) ninfo("Available: %u\n", work_available(&priv->lo_work)); /* 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. + * pending actions and we will have to ignore the Tx availability + * action. */ - if (work_available(&priv->lo_work)) + if (!work_available(&priv->lo_work) || priv->lo_head != NULL) { - /* Schedule to serialize the poll on the worker thread. */ + nwarn("WARNING: lo_work NOT available\n"); + priv->lo_pending = true; + } + else + { + /* Schedule to perform the interrupt processing on the worker thread. */ + priv->lo_pending = false; work_queue(LPBKWORK, &priv->lo_work, lo_txavail_work, priv, 0); } @@ -519,7 +509,7 @@ static int lo_txavail(FAR struct net_driver_s *dev) #if defined(CONFIG_NET_IGMP) || defined(CONFIG_NET_ICMPv6) static int lo_addmac(FAR struct net_driver_s *dev, FAR const uint8_t *mac) { -#ifdef CONFIG_NET_6LOWPAN_RIMEADDR_EXTENDED +#ifdef CONFIG_NET_6LOWPAN_EXTENDEDADDR ninfo("MAC: %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5], mac[6], mac[7]); #else @@ -554,7 +544,7 @@ static int lo_addmac(FAR struct net_driver_s *dev, FAR const uint8_t *mac) #ifdef CONFIG_NET_IGMP static int lo_rmmac(FAR struct net_driver_s *dev, FAR const uint8_t *mac) { -#ifdef CONFIG_NET_6LOWPAN_RIMEADDR_EXTENDED +#ifdef CONFIG_NET_6LOWPAN_EXTENDEDADDR ninfo("MAC: %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5], mac[6], mac[7]); #else @@ -568,6 +558,138 @@ static int lo_rmmac(FAR struct net_driver_s *dev, FAR const uint8_t *mac) } #endif +/**************************************************************************** + * Name: macnet_ioctl + * + * Description: + * Handle network IOCTL commands directed to this device. + * + * Parameters: + * dev - Reference to the NuttX driver state structure + * cmd - The IOCTL command + * arg - The argument for the IOCTL command + * + * Returned Value: + * OK on success; Negated errno on failure. + * + * Assumptions: + * + ****************************************************************************/ + +#ifdef CONFIG_NETDEV_IOCTL +static int lo_ioctl(FAR struct net_driver_s *dev, int cmd, + unsigned long arg) +{ +#if 0 + FAR struct lo_driver_s *priv = (FAR struct lo_driver_s *)dev->d_private; + + /* Check for IOCTLs aimed at the IEEE802.15.4 MAC layer */ + + if (_MAC802154IOCVALID(cmd)) + { + FAR struct ieee802154_netmac_s *netmac = + (FAR struct ieee802154_netmac_s *)arg; + } + else +#endif + { + /* Not a valid IEEE 802.15.4 MAC IOCTL command */ + + return -ENOTTY; + } +} +#endif + +/**************************************************************************** + * Name: lo_get_mhrlen + * + * Description: + * Calculate the MAC header length given the frame meta-data. + * + * Input parameters: + * netdev - The networkd device that will mediate the MAC interface + * meta - Meta data needed to recreate the MAC header + * + * Returned Value: + * A non-negative MAC headeer length is returned on success; a negated + * errno value is returned on any failure. + * + ****************************************************************************/ + +static int lo_get_mhrlen(FAR struct ieee802154_driver_s *netdev, + FAR const struct ieee802154_frame_meta_s *meta) +{ + return MAC_HDRLEN; +} + +/**************************************************************************** + * Name: lo_req_data + * + * Description: + * Requests the transfer of a list of frames to the MAC. + * + * Input parameters: + * netdev - The networkd device that will mediate the MAC interface + * meta - Meta data needed to recreate the MAC header + * framelist - Head of a list of frames to be transferred. + * + * Returned Value: + * Zero (OK) returned on success; a negated errno value is returned on + * any failure. + * + ****************************************************************************/ + +static int lo_req_data(FAR struct ieee802154_driver_s *netdev, + FAR const struct ieee802154_frame_meta_s *meta, + FAR struct iob_s *framelist) +{ + FAR struct lo_driver_s *priv; + FAR struct iob_s *iob; + + DEBUGASSERT(netdev != NULL && netdev->i_dev.d_private != NULL && + framelist != NULL); + priv = (FAR struct lo_driver_s *)netdev->i_dev.d_private; + + /* Add the incoming list of framelist to queue of framelist to loopback */ + + for (iob = framelist; iob != NULL; iob = framelist) + { + /* Increment statistics */ + + NETDEV_RXPACKETS(&priv->lo_ieee.i_dev); + + /* Remove the IOB from the queue */ + + framelist = iob->io_flink; + iob->io_flink = NULL; + + ninfo("Queuing frame IOB %p\n", iob); + + /* Just zero the MAC header for test purposes */ + + DEBUGASSERT(iob->io_offset == MAC_HDRLEN); + memset(iob->io_data, 0, MAC_HDRLEN); + + /* Add the IOB to the tail of the queue of framelist to be looped back */ + + if (priv->lo_tail == NULL) + { + priv->lo_head = iob; + } + else + { + priv->lo_tail->io_flink = iob; + } + + priv->lo_tail = iob; + } + + /* Schedule to serialize the poll on the worker thread. */ + + work_queue(LPBKWORK, &priv->lo_work, lo_loopback_work, priv, 0); + return OK; +} + /**************************************************************************** * Public Functions ****************************************************************************/ @@ -590,7 +712,8 @@ static int lo_rmmac(FAR struct net_driver_s *dev, FAR const uint8_t *mac) int ieee8021514_loopback(void) { - FAR struct lo_driver_s *priv; + FAR struct lo_driver_s *priv; + FAR struct ieee802154_driver_s *ieee; FAR struct net_driver_s *dev; ninfo("Initializing\n"); @@ -603,26 +726,31 @@ int ieee8021514_loopback(void) memset(priv, 0, sizeof(struct lo_driver_s)); - dev = &priv->lo_ieee.i_dev; - dev->d_ifup = lo_ifup; /* I/F up (new IP address) callback */ - dev->d_ifdown = lo_ifdown; /* I/F down callback */ - dev->d_txavail = lo_txavail; /* New TX data callback */ + ieee = &priv->lo_ieee; + dev = &ieee->i_dev; + dev->d_ifup = lo_ifup; /* I/F up (new IP address) callback */ + dev->d_ifdown = lo_ifdown; /* I/F down callback */ + dev->d_txavail = lo_txavail; /* New TX data callback */ #ifdef CONFIG_NET_IGMP - dev->d_addmac = lo_addmac; /* Add multicast MAC address */ - dev->d_rmmac = lo_rmmac; /* Remove multicast MAC address */ + dev->d_addmac = lo_addmac; /* Add multicast MAC address */ + dev->d_rmmac = lo_rmmac; /* Remove multicast MAC address */ #endif - dev->d_buf = g_iobuffer; /* Attach the IO buffer */ - dev->d_private = (FAR void *)priv; /* Used to recover private state from dev */ +#ifdef CONFIG_NETDEV_IOCTL + dev->d_ioctl = lo_ioctl; /* Handle network IOCTL commands */ +#endif + dev->d_buf = g_iobuffer; /* Attach the IO buffer */ + dev->d_private = (FAR void *)priv; /* Used to recover private state from dev */ + + /* Initialize the Network frame-related callbacks */ + + ieee->i_get_mhrlen = lo_get_mhrlen; /* Get MAC header length */ + ieee->i_req_data = lo_req_data; /* Enqueue frame for transmission */ /* Create a watchdog for timing polling for and timing of transmissions */ - priv->lo_polldog = wd_create(); /* Create periodic poll timer */ + priv->lo_polldog = wd_create(); /* Create periodic poll timer */ - /* Initialize the DSN to a "random" value */ - - priv->lo_ieee.i_dsn = 42; - - /* Register the loopabck device with the OS so that socket IOCTLs can b + /* Register the loopabck device with the OS so that socket IOCTLs can be * performed. */ diff --git a/wireless/ieee802154/mac802154_netdev.c b/wireless/ieee802154/mac802154_netdev.c new file mode 100644 index 0000000000..f510cf7f5d --- /dev/null +++ b/wireless/ieee802154/mac802154_netdev.c @@ -0,0 +1,1138 @@ +/**************************************************************************** + * wireless/ieee802154/mac802154_netdev.c + * + * Copyright (C) 2017 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "mac802154.h" + +#ifdef CONFIG_NET_6LOWPAN + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* If processing is not done at the interrupt level, then work queue support + * is required. + */ + +#if !defined(CONFIG_SCHED_WORKQUEUE) +# error Work queue support is required in this configuration (CONFIG_SCHED_WORKQUEUE) +#else + + /* Use the selected work queue */ + +# if defined(CONFIG_IEEE802154_NETDEV_HPWORK) +# define WPANWORK HPWORK +# elif defined(CONFIG_IEEE802154_NETDEV_LPWORK) +# define WPANWORK LPWORK +# else +# error Neither CONFIG_IEEE802154_NETDEV_HPWORK nor CONFIG_IEEE802154_NETDEV_LPWORK defined +# endif +#endif + +/* CONFIG_IEEE802154_NETDEV_NINTERFACES determines the number of physical interfaces + * that will be supported. + */ + +#ifndef CONFIG_IEEE802154_NETDEV_NINTERFACES +# define CONFIG_IEEE802154_NETDEV_NINTERFACES 1 +#endif + +/* TX poll delay = 1 seconds. CLK_TCK is the number of clock ticks per second */ + +#define TXPOLL_WDDELAY (1*CLK_TCK) + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/* This is our private version of the MAC callback stucture */ + +struct macnet_callback_s +{ + /* This holds the information visible to the MAC layer */ + + struct ieee802154_maccb_s mc_cb; /* Interface understood by the MAC layer */ + FAR struct macnet_driver_s *mc_priv; /* Our priv data */ +}; + +/* The macnet_driver_s encapsulates all state information for a single + * IEEE802.15.4 MAC interface. + */ + +struct macnet_driver_s +{ + /* This holds the information visible to the NuttX network */ + + struct ieee802154_driver_s md_dev; /* Interface understood by the network */ + + /* For internal use by this driver */ + + struct macnet_callback_s md_cb; /* Callback information */ + MACHANDLE md_mac; /* Contained MAC interface */ + bool md_bifup; /* true:ifup false:ifdown */ + WDOG_ID md_txpoll; /* TX poll timer */ + struct work_s md_pollwork; /* Defer poll work to the work queue */ +}; + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +/* IEE802.15.4 MAC callback functions ***************************************/ + +static void macnet_mlme_notify(FAR const struct ieee802154_maccb_s *maccb, + enum ieee802154_macnotify_e notif, + FAR const union ieee802154_mlme_notify_u *arg); +static void macnet_mcps_notify(FAR const struct ieee802154_maccb_s *maccb, + enum ieee802154_macnotify_e notif, + FAR const union ieee802154_mcps_notify_u *arg); + +/* Asynchronous confirmations to requests */ + +static void macnet_conf_data(FAR struct macnet_driver_s *priv, + FAR const struct ieee802154_data_conf_s *conf); +static void macnet_conf_associate(FAR struct macnet_driver_s *priv, + FAR struct ieee802154_assoc_conf_s *conf); +static void macnet_conf_disassociate(FAR struct macnet_driver_s *priv, + FAR struct ieee802154_disassoc_conf_s *conf); +static void macnet_conf_gts(FAR struct macnet_driver_s *priv, + FAR struct ieee802154_gts_conf_s *conf); +static void macnet_conf_rxenable(FAR struct macnet_driver_s *priv, + FAR struct ieee802154_rxenable_conf_s *conf); +static void macnet_conf_scan(FAR struct macnet_driver_s *priv, + FAR struct ieee802154_scan_conf_s *conf); +static void macnet_conf_start(FAR struct macnet_driver_s *priv, + FAR struct ieee802154_start_conf_s *conf); +static void macnet_conf_poll(FAR struct macnet_driver_s *priv, + FAR struct ieee802154_poll_conf_s *conf); + + /* Asynchronous event indications, replied to synchronously with responses */ + +static void macnet_ind_data(FAR struct macnet_driver_s *priv, + FAR struct ieee802154_data_ind_s *conf); +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_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, + FAR struct ieee802154_orphan_ind_s *conf); +static void macnet_ind_commstatus(FAR struct macnet_driver_s *priv, + FAR struct ieee802154_commstatus_ind_s *conf); +static void macnet_ind_syncloss(FAR struct macnet_driver_s *priv, + FAR struct ieee802154_syncloss_ind_s *conf); + +/* Network interface support ************************************************/ +/* Common TX logic */ + +static int macnet_txpoll_callback(FAR struct net_driver_s *dev); +static void macnet_txpoll_work(FAR void *arg); +static void macnet_txpoll_expiry(int argc, wdparm_t arg, ...); + +/* NuttX callback functions */ + +static int macnet_ifup(FAR struct net_driver_s *dev); +static int macnet_ifdown(FAR struct net_driver_s *dev); + +static void macnet_txavail_work(FAR void *arg); +static int macnet_txavail(FAR struct net_driver_s *dev); + +#if defined(CONFIG_NET_IGMP) || defined(CONFIG_NET_ICMPv6) +static int macnet_addmac(FAR struct net_driver_s *dev, + FAR const uint8_t *mac); +#ifdef CONFIG_NET_IGMP +static int macnet_rmmac(FAR struct net_driver_s *dev, + FAR const uint8_t *mac); +#endif +#endif +#ifdef CONFIG_NETDEV_IOCTL +static int macnet_ioctl(FAR struct net_driver_s *dev, int cmd, + unsigned long arg); +#endif +static int macnet_get_mhrlen(FAR struct ieee802154_driver_s *netdev, + FAR const struct ieee802154_frame_meta_s *meta); +static int macnet_req_data(FAR struct ieee802154_driver_s *netdev, + FAR const struct ieee802154_frame_meta_s *meta, + FAR struct iob_s *framelist); + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: macnet_mlme_notify + * + * Description: + * + ****************************************************************************/ + +static void macnet_mlme_notify(FAR const struct ieee802154_maccb_s *maccb, + enum ieee802154_macnotify_e notif, + FAR const union ieee802154_mlme_notify_u *arg) +{ + FAR struct macnet_callback_s *cb = + (FAR struct macnet_callback_s *)maccb; + FAR struct macnet_driver_s *priv; + + DEBUGASSERT(cb != NULL && cb->mc_priv != NULL); + priv = cb->mc_priv; + + switch (notif) + { + + default: + break; + } +} + +/**************************************************************************** + * Name: macnet_mcps_notify + * + * Description: + * + ****************************************************************************/ + +static void macnet_mcps_notify(FAR const struct ieee802154_maccb_s *maccb, + enum ieee802154_macnotify_e notif, + FAR const union ieee802154_mcps_notify_u *arg) +{ + FAR struct macnet_callback_s *cb = + (FAR struct macnet_callback_s *)maccb; + FAR struct macnet_driver_s *priv; + + DEBUGASSERT(cb != NULL && cb->mc_priv != NULL); + priv = cb->mc_priv; + + switch (notif) + { + case IEEE802154_NOTIFY_CONF_DATA: + { + macnet_conf_data(priv, &arg->dataconf); + } + break; + + case IEEE802154_NOTIFY_IND_DATA: + { + macnet_ind_data(priv, arg->dataind); + } + break; + + default: + break; + } +} + +/**************************************************************************** + * Name: macnet_conf_data + * + * Description: + * Data frame was received by remote device + * + ****************************************************************************/ + +static void macnet_conf_data(FAR struct macnet_driver_s *priv, + FAR const struct ieee802154_data_conf_s *conf) +{ + +} + +/**************************************************************************** + * Name: macnet_conf_associate + * + * Description: + * Association request completed + * + ****************************************************************************/ + +static void macnet_conf_associate(FAR struct macnet_driver_s *priv, + FAR struct ieee802154_assoc_conf_s *conf) +{ + +} + +/**************************************************************************** + * Name: macnet_conf_disassociate + * + * Description: + * Disassociation request completed + * + ****************************************************************************/ + +static void macnet_conf_disassociate(FAR struct macnet_driver_s *priv, + FAR struct ieee802154_disassoc_conf_s *conf) +{ + +} + +/**************************************************************************** + * Name: macnet_conf_gts + * + * Description: + * GTS management completed + * + ****************************************************************************/ + +static void macnet_conf_gts(FAR struct macnet_driver_s *priv, + FAR struct ieee802154_gts_conf_s *conf) +{ + +} + +/**************************************************************************** + * Name: macnet_conf_rxenable + * + * Description: + * + ****************************************************************************/ + +static void macnet_conf_rxenable(FAR struct macnet_driver_s *priv, + FAR struct ieee802154_rxenable_conf_s *conf) +{ + +} + +/**************************************************************************** + * Name: macnet_conf_scan + * + * Description: + * + ****************************************************************************/ + +static void macnet_conf_scan(FAR struct macnet_driver_s *priv, + FAR struct ieee802154_scan_conf_s *conf) +{ + +} + +/**************************************************************************** + * Name: macnet_conf_start + * + * Description: + * + ****************************************************************************/ + +static void macnet_conf_start(FAR struct macnet_driver_s *priv, + FAR struct ieee802154_start_conf_s *conf) +{ + +} + +/**************************************************************************** + * Name: macnet_conf_poll + * + * Description: + * + ****************************************************************************/ + +static void macnet_conf_poll(FAR struct macnet_driver_s *priv, + FAR struct ieee802154_poll_conf_s *conf) +{ + +} + +/**************************************************************************** + * Name: macnet_ind_data + * + * Description: + * Data frame received + * + ****************************************************************************/ + +static void macnet_ind_data(FAR struct macnet_driver_s *priv, + FAR struct ieee802154_data_ind_s *ind) +{ + FAR struct iob_s *iob; + + /* Extract the IOB containing the frame from the struct ieee802154_data_ind_s */ + + DEBUGASSERT(priv != NULL && ind != NULL && ind->frame != NULL); + iob = ind->frame; + ind->frame = NULL; + + /* Transfer the frame to the network logic */ + + sixlowpan_input(&priv->md_dev, iob, ind); + + /* sixlowpan_input() will free the IOB, but we must free the struct + * ieee802154_data_ind_s container here. + */ + + ieee802154_ind_free(ind); +} + +/**************************************************************************** + * Name: macnet_ind_associate + * + * Description: + * Association request received + * + ****************************************************************************/ + +static void macnet_ind_associate(FAR struct macnet_driver_s *priv, + FAR struct ieee802154_assoc_ind_s *ind) +{ + +} + +/**************************************************************************** + * Name: macnet_ind_disassociate + * + * Description: + * Disassociation request received + * + ****************************************************************************/ + +static void macnet_ind_disassociate(FAR struct macnet_driver_s *priv, + FAR struct ieee802154_disassoc_ind_s *ind) +{ + +} + +/**************************************************************************** + * Name: macnet_ind_beaconnotify + * + * Description: + * Beacon notification + * + ****************************************************************************/ + +static void macnet_ind_beaconnotify(FAR struct macnet_driver_s *priv, + FAR struct ieee802154_beaconnotify_ind_s *ind) +{ + +} + +/**************************************************************************** + * Name: macnet_ind_gts + * + * Description: + * GTS management request received + * + ****************************************************************************/ + +static void macnet_ind_gts(FAR struct macnet_driver_s *priv, + FAR struct ieee802154_gts_ind_s *ind) +{ + +} + +/**************************************************************************** + * Name: macnet_ind_orphan + * + * Description: + * Orphan device detected + * + ****************************************************************************/ + +static void macnet_ind_orphan(FAR struct macnet_driver_s *priv, + FAR struct ieee802154_orphan_ind_s *ind) +{ + +} + +/**************************************************************************** + * Name: macnet_ind_commstatus + * + * Description: + * + ****************************************************************************/ + +static void macnet_ind_commstatus(FAR struct macnet_driver_s *priv, + FAR struct ieee802154_commstatus_ind_s *ind) +{ + +} + +/**************************************************************************** + * Name: macnet_ind_syncloss + * + * Description: + * + ****************************************************************************/ + +static void macnet_ind_syncloss(FAR struct macnet_driver_s *priv, + FAR struct ieee802154_syncloss_ind_s *ind) +{ + +} + +/**************************************************************************** + * Name: macnet_txpoll_callback + * + * Description: + * The transmitter is available, check if the network has any outgoing + * packets ready to send. This is a callback from devif_poll(). + * devif_poll() may be called: + * + * 1. When the preceding TX packet send is complete, + * 2. When the preceding TX packet send timesout and the interface is reset + * 3. During normal TX polling + * + * Parameters: + * dev - Reference to the NuttX driver state structure + * + * Returned Value: + * OK on success; a negated errno on failure + * + * Assumptions: + * The network is locked. + * + ****************************************************************************/ + +static int macnet_txpoll_callback(FAR struct net_driver_s *dev) +{ + /* If zero is returned, the polling will continue until all connections have + * been examined. + */ + + return 0; +} + +/**************************************************************************** + * Name: macnet_txpoll_process + * + * Description: + * Perform the periodic poll. This may be called either from watchdog + * timer logic or from the worker thread, depending upon the configuration. + * + * Parameters: + * priv - Reference to the driver state structure + * + * Returned Value: + * None + * + * Assumptions: + * + ****************************************************************************/ + +static inline void macnet_txpoll_process(FAR struct macnet_driver_s *priv) +{ +} + +/**************************************************************************** + * Name: macnet_txpoll_work + * + * Description: + * Perform periodic polling from the worker thread + * + * Parameters: + * arg - The argument passed when work_queue() as called. + * + * Returned Value: + * OK on success + * + * Assumptions: + * The network is locked. + * + ****************************************************************************/ + +static void macnet_txpoll_work(FAR void *arg) +{ + FAR struct macnet_driver_s *priv = (FAR struct macnet_driver_s *)arg; + + /* Lock the network and serialize driver operations if necessary. + * NOTE: Serialization is only required in the case where the driver work + * is performed on an LP worker thread and where more than one LP worker + * thread has been configured. + */ + + net_lock(); + + /* Perform the poll */ + + (void)devif_timer(&priv->md_dev.i_dev, macnet_txpoll_callback); + + /* Setup the watchdog poll timer again */ + + (void)wd_start(priv->md_txpoll, TXPOLL_WDDELAY, macnet_txpoll_expiry, 1, + (wdparm_t)priv); + net_unlock(); +} + +/**************************************************************************** + * Name: macnet_txpoll_expiry + * + * Description: + * Periodic timer handler. 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 macnet_txpoll_expiry(int argc, wdparm_t arg, ...) +{ + FAR struct macnet_driver_s *priv = (FAR struct macnet_driver_s *)arg; + + /* Schedule to perform the interrupt processing on the worker thread. */ + + work_queue(WPANWORK, &priv->md_pollwork, macnet_txpoll_work, priv, 0); +} + +/**************************************************************************** + * Name: macnet_ifup + * + * Description: + * NuttX Callback: Bring up the IEEE 802.15.4 interface when an IP address + * is provided + * + * Parameters: + * dev - Reference to the NuttX driver state structure + * + * Returned Value: + * None + * + * Assumptions: + * + ****************************************************************************/ + +static int macnet_ifup(FAR struct net_driver_s *dev) +{ + FAR struct macnet_driver_s *priv = (FAR struct macnet_driver_s *)dev->d_private; + +#ifdef CONFIG_NET_IPv4 + ninfo("Bringing up: %d.%d.%d.%d\n", + dev->d_ipaddr & 0xff, (dev->d_ipaddr >> 8) & 0xff, + (dev->d_ipaddr >> 16) & 0xff, dev->d_ipaddr >> 24); +#endif +#ifdef CONFIG_NET_IPv6 + ninfo("Bringing up: %04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x\n", + dev->d_ipv6addr[0], dev->d_ipv6addr[1], dev->d_ipv6addr[2], + dev->d_ipv6addr[3], dev->d_ipv6addr[4], dev->d_ipv6addr[5], + dev->d_ipv6addr[6], dev->d_ipv6addr[7]); +#endif + + /* Initialize PHYs, the IEEE 802.15.4 interface, and setup up IEEE 802.15.4 interrupts */ +#warning Missing logic + + /* Setup up address filtering */ + + /* Set and activate a timer process */ + + (void)wd_start(priv->md_txpoll, TXPOLL_WDDELAY, macnet_txpoll_expiry, 1, + (wdparm_t)priv); + + /* Enable the IEEE 802.15.4 radio */ + + priv->md_bifup = true; + return OK; +} + +/**************************************************************************** + * Name: macnet_ifdown + * + * Description: + * NuttX Callback: Stop the interface. + * + * Parameters: + * dev - Reference to the NuttX driver state structure + * + * Returned Value: + * None + * + * Assumptions: + * + ****************************************************************************/ + +static int macnet_ifdown(FAR struct net_driver_s *dev) +{ + FAR struct macnet_driver_s *priv = (FAR struct macnet_driver_s *)dev->d_private; + irqstate_t flags; + + /* Disable interruption */ + + flags = enter_critical_section(); + + /* Cancel the TX poll timer and TX timeout timers */ + + wd_cancel(priv->md_txpoll); + + /* Put the EMAC in its reset, non-operational state. This should be + * a known configuration that will guarantee the macnet_ifup() always + * successfully brings the interface back up. + */ + + /* Mark the device "down" */ + + priv->md_bifup = false; + leave_critical_section(flags); + return OK; +} + +/**************************************************************************** + * Name: macnet_txavail_work + * + * Description: + * Perform an out-of-cycle poll on the worker thread. + * + * Parameters: + * arg - Reference to the NuttX driver state structure (cast to void*) + * + * Returned Value: + * None + * + * Assumptions: + * Called on the higher priority worker thread. + * + ****************************************************************************/ + +static void macnet_txavail_work(FAR void *arg) +{ + FAR struct macnet_driver_s *priv = (FAR struct macnet_driver_s *)arg; + + /* Lock the network and serialize driver operations if necessary. + * NOTE: Serialization is only required in the case where the driver work + * is performed on an LP worker thread and where more than one LP worker + * thread has been configured. + */ + + net_lock(); + + /* Ignore the notification if the interface is not yet up */ + + if (priv->md_bifup) + { + /* Check if there is room in the hardware to hold another outgoing packet. */ + + /* If so, then poll the network for new XMIT data */ + + (void)devif_poll(&priv->md_dev.i_dev, macnet_txpoll_callback); + } + + net_unlock(); +} + +/**************************************************************************** + * Name: macnet_txavail + * + * 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: + * dev - Reference to the NuttX driver state structure + * + * Returned Value: + * None + * + * Assumptions: + * Called in normal user mode + * + ****************************************************************************/ + +static int macnet_txavail(FAR struct net_driver_s *dev) +{ + FAR struct macnet_driver_s *priv = (FAR struct macnet_driver_s *)dev->d_private; + + /* 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(&priv->md_pollwork)) + { + /* Schedule to serialize the poll on the worker thread. */ + + work_queue(WPANWORK, &priv->md_pollwork, macnet_txavail_work, priv, 0); + } + + return OK; +} + +/**************************************************************************** + * Name: macnet_addmac + * + * Description: + * NuttX Callback: Add the specified MAC address to the hardware multicast + * address filtering + * + * Parameters: + * dev - Reference to the NuttX driver state structure + * mac - The MAC address to be added + * + * Returned Value: + * None + * + * Assumptions: + * + ****************************************************************************/ + +#if defined(CONFIG_NET_IGMP) || defined(CONFIG_NET_ICMPv6) +static int macnet_addmac(FAR struct net_driver_s *dev, FAR const uint8_t *mac) +{ + FAR struct macnet_driver_s *priv = (FAR struct macnet_driver_s *)dev->d_private; + + /* Add the MAC address to the hardware multicast routing table. Not used + * with IEEE 802.15.4 radios. + */ + + return -ENOSYS; +} +#endif + +/**************************************************************************** + * Name: macnet_rmmac + * + * Description: + * NuttX Callback: Remove the specified MAC address from the hardware multicast + * address filtering + * + * Parameters: + * dev - Reference to the NuttX driver state structure + * mac - The MAC address to be removed + * + * Returned Value: + * None + * + * Assumptions: + * + ****************************************************************************/ + +#ifdef CONFIG_NET_IGMP +static int macnet_rmmac(FAR struct net_driver_s *dev, FAR const uint8_t *mac) +{ + FAR struct macnet_driver_s *priv = (FAR struct macnet_driver_s *)dev->d_private; + + /* Remove the MAC address from the hardware multicast routing table Not used + * with IEEE 802.15.4 radios. + */ + + return -ENOSYS; +} +#endif + +/**************************************************************************** + * Name: macnet_ioctl + * + * Description: + * Handle network IOCTL commands directed to this device. + * + * Parameters: + * dev - Reference to the NuttX driver state structure + * cmd - The IOCTL command + * arg - The argument for the IOCTL command + * + * Returned Value: + * OK on success; Negated errno on failure. + * + * Assumptions: + * + ****************************************************************************/ + +#ifdef CONFIG_NETDEV_IOCTL +static int macnet_ioctl(FAR struct net_driver_s *dev, int cmd, + unsigned long arg) +{ + FAR struct macnet_driver_s *priv = (FAR struct macnet_driver_s *)dev->d_private; + int ret = -EINVAL; + + /* Check for IOCTLs aimed at the IEEE802.15.4 MAC layer */ + + if (_MAC802154IOCVALID(cmd)) + { + FAR struct ieee802154_netmac_s *netmac = + (FAR struct ieee802154_netmac_s *)arg; + + if (netmac != NULL) + { + unsigned long macarg = (unsigned int)((uintptr_t)&netmac->u); + ret = mac802154_ioctl(priv->md_mac, cmd, macarg); + + } + } + + /* Okay, we have no idea what this command is.. just give to the + * IEEE802.15.4 MAC layer without modification. + */ + + else + { + ret = mac802154_ioctl(priv->md_mac, cmd, arg); + } + + return ret; +} +#endif + +/**************************************************************************** + * Name: macnet_get_mhrlen + * + * Description: + * Calculate the MAC header length given the frame meta-data. + * + * Input parameters: + * netdev - The networkd device that will mediate the MAC interface + * meta - Meta data needed to recreate the MAC header + * + * Returned Value: + * A non-negative MAC headeer length is returned on success; a negated + * errno value is returned on any failure. + * + ****************************************************************************/ + +static int macnet_get_mhrlen(FAR struct ieee802154_driver_s *netdev, + FAR const struct ieee802154_frame_meta_s *meta) +{ + FAR struct macnet_driver_s *priv; + + DEBUGASSERT(netdev != NULL && netdev->i_dev.d_private != NULL && meta != NULL); + priv = (FAR struct macnet_driver_s *)netdev->i_dev.d_private; + + return mac802154_get_mhrlen(priv->md_mac, meta); +} + +/**************************************************************************** + * Name: macnet_req_data + * + * Description: + * Requests the transfer of a list of frames to the MAC. + * + * Input parameters: + * netdev - The networkd device that will mediate the MAC interface + * meta - Meta data needed to recreate the MAC header + * framelist - Head of a list of frames to be transferred. + * + * Returned Value: + * Zero (OK) returned on success; a negated errno value is returned on + * any failure. + * + ****************************************************************************/ + +static int macnet_req_data(FAR struct ieee802154_driver_s *netdev, + FAR const struct ieee802154_frame_meta_s *meta, + FAR struct iob_s *framelist) +{ + FAR struct macnet_driver_s *priv; + FAR struct iob_s *iob; + int ret; + + DEBUGASSERT(netdev != NULL && netdev->i_dev.d_private != NULL); + priv = (FAR struct macnet_driver_s *)netdev->i_dev.d_private; + + DEBUGASSERT(meta != NULL && framelist != NULL); + + /* Add the incoming list of frames to the MAC's outgoing queue */ + + for (iob = framelist; iob != NULL; iob = framelist) + { + /* Increment statistics */ + + NETDEV_TXPACKETS(&priv->md_dev.i_dev); + + /* Remove the IOB from the queue */ + + framelist = iob->io_flink; + iob->io_flink = NULL; + + /* Transfer the frame to the MAC */ + + ret = mac802154_req_data(priv->md_mac, meta, iob); + if (ret < 0) + { + wlerr("ERROR: mac802154_req_data failed: %d\n", ret); + + iob_free(iob); + for (iob = framelist; iob != NULL; iob = framelist) + { + /* Remove the IOB from the queue and free */ + + framelist = iob->io_flink; + iob_free(iob); + } + + return ret; + } + } + + return OK; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: mac802154netdev_register + * + * Description: + * Register a network driver to access the IEEE 802.15.4 MAC layer from + * a socket using 6loWPAN + * + * Input Parameters: + * mac - Pointer to the mac layer struct to be registered. + * + * Returned Values: + * Zero (OK) is returned on success. Otherwise a negated errno value is + * returned to indicate the nature of the failure. + * + ****************************************************************************/ + +int mac802154netdev_register(MACHANDLE mac) +{ + FAR struct macnet_driver_s *priv; + FAR struct ieee802154_driver_s *ieee; + FAR struct net_driver_s *dev; + FAR struct ieee802154_maccb_s *maccb; + FAR uint8_t *pktbuf; + int ret; + + DEBUGASSERT(mac != NULL); + + /* Get the interface structure associated with this interface number. */ + + priv = (FAR struct macnet_driver_s *) + kmm_zalloc(sizeof(struct macnet_driver_s)); + + if (priv == NULL) + { + nerr("ERROR: Failed to allocate the device structure\n"); + return -ENOMEM; + } + + /* Allocate a packet buffer (not used by this driver, but need by the + * upper networking layer) + */ + + pktbuf = (FAR uint8_t *)kmm_malloc(CONFIG_NET_6LOWPAN_MTU + CONFIG_NET_GUARDSIZE); + if (pktbuf == NULL) + { + nerr("ERROR: Failed to allocate the packet buffer\n"); + kmm_free(priv); + return -ENOMEM; + } + + /* Initialize the driver structure */ + + ieee = &priv->md_dev; + dev = &ieee->i_dev; + dev->d_buf = pktbuf; /* Single packet buffer */ + dev->d_ifup = macnet_ifup; /* I/F up (new IP address) callback */ + dev->d_ifdown = macnet_ifdown; /* I/F down callback */ + dev->d_txavail = macnet_txavail; /* New TX data callback */ +#ifdef CONFIG_NET_IGMP + dev->d_addmac = macnet_addmac; /* Add multicast MAC address */ + dev->d_rmmac = macnet_rmmac; /* Remove multicast MAC address */ +#endif + #ifdef CONFIG_NETDEV_IOCTL + dev->d_ioctl = macnet_ioctl; /* Handle network IOCTL commands */ +#endif + dev->d_private = (FAR void *)priv; /* Used to recover private state from dev */ + + /* Create a watchdog for timing polling for and timing of transmisstions */ + + priv->md_mac = mac; /* Save the MAC interface instance */ + priv->md_txpoll = wd_create(); /* Create periodic poll timer */ + + DEBUGASSERT(priv->md_txpoll != NULL); + + /* Initialize the Network frame-related callbacks */ + + ieee->i_get_mhrlen = macnet_get_mhrlen; /* Get MAC header length */ + ieee->i_req_data = macnet_req_data; /* Enqueue frame for transmission */ + + /* Initialize the MAC callbacks */ + + priv->md_cb.mc_priv = priv; + + maccb = &priv->md_cb.mc_cb; + maccb->mlme_notify = macnet_mlme_notify; + maccb->mcps_notify = macnet_mcps_notify; + + /* Bind the callback structure */ + + ret = mac802154_bind(mac, maccb); + if (ret < 0) + { + nerr("ERROR: Failed to bind the MAC callbacks: %d\n", ret); + + /* Release wdog timers */ + + wd_delete(priv->md_txpoll); + + /* Free memory and return the error */ + + kmm_free(pktbuf); + kmm_free(priv); + return ret; + } + + /* Put the interface in the down state. */ + + macnet_ifdown(dev); + + /* Register the device with the OS so that socket IOCTLs can be performed */ + + (void)netdev_register(&priv->md_dev.i_dev, NET_LL_IEEE802154); + return OK; +} + +#endif /* CONFIG_NET && CONFIG_NET_skeleton */