diff --git a/configs/clicker2-stm32/Kconfig b/configs/clicker2-stm32/Kconfig index 694b9f3582..cd52c627d0 100644 --- a/configs/clicker2-stm32/Kconfig +++ b/configs/clicker2-stm32/Kconfig @@ -42,4 +42,27 @@ config CLICKER2_STM32_MRF24J40LH_VERBOSE ---help--- Enable verbose syslog for MRF24J40 lowerhalf +config CLICKER2_STM32_MB1_XBEE + bool "mikroBUS1 XBee radio" + default n + depends on IEEE802154_XBEE + select CLICKER2_STM32_MB1_SPI + ---help--- + Enable support for XBee radio on mikroBUS1 + +config CLICKER2_STM32_MB2_XBEE + bool "mikroBUS2 XBee radio" + default n + depends on IEEE802154_XBEE + select CLICKER2_STM32_MB2_SPI + ---help--- + Enable support for XBee on mikroBUS2 + +config CLICKER2_STM32_XBEELH_VERBOSE + bool "Verbose XBee lowerhalf" + default n + depends on IEEE802154_XBEE && DEBUG_WIRELESS_INFO + ---help--- + Enable verbose syslog for XBee lowerhalf + endif # ARCH_BOARD_CLICKER2_STM32 diff --git a/configs/clicker2-stm32/src/Makefile b/configs/clicker2-stm32/src/Makefile index 3980c3ac7d..f8fe311573 100644 --- a/configs/clicker2-stm32/src/Makefile +++ b/configs/clicker2-stm32/src/Makefile @@ -60,6 +60,10 @@ ifeq ($(CONFIG_IEEE802154_MRF24J40),y) CSRCS += stm32_mrf24j40.c endif +ifeq ($(CONFIG_IEEE802154_XBEE),y) +CSRCS += stm32_xbee.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 cf9f3613aa..6251a50e30 100644 --- a/configs/clicker2-stm32/src/clicker2-stm32.h +++ b/configs/clicker2-stm32/src/clicker2-stm32.h @@ -215,6 +215,12 @@ #define GPIO_MB2_RST (GPIO_OUTPUT|GPIO_PUSHPULL|GPIO_SPEED_50MHz|\ GPIO_OUTPUT_CLEAR|GPIO_PORTE|GPIO_PIN13) +#define GPIO_MB1_XBEE_RST (GPIO_OUTPUT|GPIO_OPENDRAIN|GPIO_SPEED_50MHz|\ + GPIO_OUTPUT_CLEAR|GPIO_PORTE|GPIO_PIN7) + +#define GPIO_MB2_XBEE_RST (GPIO_OUTPUT|GPIO_OPENDRAIN|GPIO_SPEED_50MHz|\ + GPIO_OUTPUT_CLEAR|GPIO_PORTE|GPIO_PIN13) + /* Interrupts * * mikroBUS1 Interrupt: PE10-MB1_INT @@ -227,6 +233,9 @@ #define GPIO_MB1_INT (GPIO_INPUT|GPIO_PULLUP|GPIO_EXTI|GPIO_PORTE|GPIO_PIN10) #define GPIO_MB2_INT (GPIO_INPUT|GPIO_PULLUP|GPIO_EXTI|GPIO_PORTE|GPIO_PIN14) +#define GPIO_MB1_XBEE_INT (GPIO_INPUT|GPIO_FLOAT|GPIO_EXTI|GPIO_PORTE|GPIO_PIN10) +#define GPIO_MB2_XBEE_INT (GPIO_INPUT|GPIO_FLOAT|GPIO_EXTI|GPIO_PORTE|GPIO_PIN14) + #ifndef __ASSEMBLY__ /************************************************************************************ @@ -313,5 +322,21 @@ int stm32_can_setup(void); int stm32_mrf24j40_initialize(void); #endif +/**************************************************************************** + * Name: stm32_xbee_initialize + * + * Description: + * Initialize the XBee 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_XBEE) || defined(CONFIG_CLICKER2_STM32_MB2_XBEE) +int stm32_xbee_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 b7adf9dcc1..ce2cb4a601 100644 --- a/configs/clicker2-stm32/src/stm32_bringup.c +++ b/configs/clicker2-stm32/src/stm32_bringup.c @@ -163,6 +163,16 @@ int stm32_bringup(void) } #endif +#if defined(CONFIG_CLICKER2_STM32_MB1_XBEE) || defined(CONFIG_CLICKER2_STM32_MB2_XBEE) + /* Configure XBee wireless */ + + ret = stm32_xbee_initialize(); + if (ret < 0) + { + syslog(LOG_ERR, "ERROR: stm32_xbee_initialize() failed: %d\n", ret); + } +#endif + #ifdef CONFIG_BUTTONS /* Register the BUTTON driver */ diff --git a/configs/clicker2-stm32/src/stm32_spi.c b/configs/clicker2-stm32/src/stm32_spi.c index c56ade201a..319a2ae7ac 100644 --- a/configs/clicker2-stm32/src/stm32_spi.c +++ b/configs/clicker2-stm32/src/stm32_spi.c @@ -144,6 +144,13 @@ void stm32_spi3select(FAR struct spi_dev_s *dev, uint32_t devid, bool selected) stm32_gpiowrite(GPIO_MB1_CS, !selected); break; +#endif +#ifdef CONFIG_IEEE802154_XBEE + case SPIDEV_IEEE802154(0): + /* Set the GPIO low to select and high to de-select */ + + stm32_gpiowrite(GPIO_MB1_CS, !selected); + break; #endif default: break; diff --git a/configs/clicker2-stm32/src/stm32_xbee.c b/configs/clicker2-stm32/src/stm32_xbee.c new file mode 100644 index 0000000000..2b868a7131 --- /dev/null +++ b/configs/clicker2-stm32/src/stm32_xbee.c @@ -0,0 +1,347 @@ +/**************************************************************************** + * configs/clicker2-stm32/src/stm32_xbee.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 "stm32_gpio.h" +#include "stm32_exti.h" +#include "stm32_spi.h" + +#include "clicker2-stm32.h" + +#ifdef CONFIG_IEEE802154_XBEE + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#ifndef CONFIG_DRIVERS_WIRELESS +# error Wireless support requires CONFIG_DRIVERS_WIRELESS +#endif + +#if !defined(CONFIG_CLICKER2_STM32_MB1_XBEE) && \ + !defined(CONFIG_CLICKER2_STM32_MB2_XBEE) +# error Only the Mikroe XBee board is supported +#endif + +#ifdef CONFIG_CLICKER2_STM32_MB1_XBEE +# ifndef CONFIG_STM32_SPI3 +# error Mikroe XBee on mikroBUS1 requires CONFIG_STM32_SPI3 +# endif +#endif + +#ifdef CONFIG_CLICKER2_STM32_MB2_XBEE +# ifndef CONFIG_STM32_SPI2 +# error Mikroe XBee on mikroBUS1 requires CONFIG_STM32_SPI2 +# endif +#endif + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +struct stm32_priv_s +{ + struct xbee_lower_s dev; + xcpt_t handler; + FAR void *arg; + uint32_t rstcfg; + uint32_t attncfg; + uint8_t spidev; +}; + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +/* IRQ/GPIO access callbacks. These operations all hidden behind + * callbacks to isolate the XBee 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. + * + * reset - Reset the XBee using the reset pin + * attn_attach - Attach the XBee interrupt handler to the GPIO + * interrupt (ATTN) + * attn_enable - Enable or disable the GPIO interrupt + * attn_poll - Poll the current state of the GPIO interrupt (ATTN) + */ + +static void stm32_reset(FAR const struct xbee_lower_s *lower); +static int stm32_attach_attn(FAR const struct xbee_lower_s *lower, + xcpt_t handler, FAR void *arg); +static void stm32_enable_attn(FAR const struct xbee_lower_s *lower, bool state); +static bool stm32_poll_attn(FAR const struct xbee_lower_s *lower); +static int stm32_xbee_devsetup(FAR struct stm32_priv_s *priv); + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/* A reference to a structure of this type must be passed to the XBee + * driver. This structure provides information about the configuration + * of the XBee 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_XBEE +static struct stm32_priv_s g_xbee_mb1_priv = +{ + .dev.reset = stm32_reset, + .dev.attach = stm32_attach_attn, + .dev.enable = stm32_enable_attn, + .dev.poll = stm32_poll_attn, + .handler = NULL, + .arg = NULL, + .rstcfg = GPIO_MB1_XBEE_RST, + .attncfg = GPIO_MB1_XBEE_INT, + .spidev = 3, +}; +#endif + +#ifdef CONFIG_CLICKER2_STM32_MB2_XBEE +static struct stm32_priv_s g_xbee_mb2_priv = +{ + .dev.reset = stm32_reset, + .dev.attach = stm32_attach_attn, + .dev.enable = stm32_enable_attn, + .dev.poll = stm32_poll_attn, + .handler = NULL, + .arg = NULL, + .rstcfg = GPIO_MB2_XBEE_RST, + .attncfg = GPIO_MB2_XBEE_INT, + .spidev = 2, +}; +#endif + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/* IRQ/GPIO access callbacks. These operations all hidden behind + * callbacks to isolate the XBee 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. + * + * reset - Reset the XBee using the reset pin + * attn_attach - Attach the XBee interrupt handler to the GPIO + * interrupt (ATTN) + * attn_enable - Enable or disable the GPIO interrupt + * attn_poll - Poll the current state of the GPIO interrupt (ATTN) + */ + +static void stm32_reset(FAR const struct xbee_lower_s *lower) +{ + FAR struct stm32_priv_s *priv = (FAR struct stm32_priv_s *)lower; + + DEBUGASSERT(priv != NULL); + + /* Hold reset line low for min. 200ns */ + + stm32_gpiowrite(priv->rstcfg, false); + up_udelay(1); + stm32_gpiowrite(priv->rstcfg, true); + + up_mdelay(100); +} + +static int stm32_attach_attn(FAR const struct xbee_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_attn(FAR const struct xbee_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)); + +#ifdef CONFIG_CLICKER2_STM32_XBEELH_VERBOSE + wlinfo("state:%d\n", (int)state); +#endif + + /* Attach and enable, or detach and disable */ + + if (state) + { + (void)stm32_gpiosetevent(priv->attncfg, false, true, true, + priv->handler, priv->arg); + } + else + { + (void)stm32_gpiosetevent(priv->attncfg, false, false, false, + NULL, NULL); + } +} + +static bool stm32_poll_attn(FAR const struct xbee_lower_s *lower) +{ + FAR struct stm32_priv_s *priv = (FAR struct stm32_priv_s *)lower; + + return !stm32_gpioread(priv->attncfg); +} + +/**************************************************************************** + * Name: stm32_xbee_devsetup + * + * Description: + * Initialize one the XBee 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_xbee_devsetup(FAR struct stm32_priv_s *priv) +{ + FAR struct spi_dev_s *spi; + XBEEHANDLE xbee; + int ret; + + /* Configure the Reset and Attention pins */ + + stm32_configgpio(priv->rstcfg); + stm32_configgpio(priv->attncfg); + + /* 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 XBee device */ + + xbee = xbee_init(spi, &priv->dev); + if (xbee == NULL) + { + wlerr("ERROR: Failed to initialize XBee driver%d\n", priv->dev); + return -ENODEV; + } + + /* Register the XBee netdev providing it the XBee MAC layer to interface with */ + + ret = xbee_netdev_register(xbee); + if (ret < 0) + { + wlerr("ERROR: Failed to register the XBee MAC network driver wpan%d: %d\n", + 0, ret); + return ret; + } + + return OK; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: stm32_xbee_initialize + * + * Description: + * Initialize the XBee device. + * + * Returned Value: + * Zero is returned on success. Otherwise, a negated errno value is + * returned to indicate the nature of the failure. + * + ****************************************************************************/ + +int stm32_xbee_initialize(void) +{ + int ret; + +#ifdef CONFIG_CLICKER2_STM32_MB1_XBEE + wlinfo("Configuring XBee in mikroBUS1\n"); + + ret = stm32_xbee_devsetup(&g_xbee_mb1_priv); + if (ret < 0) + { + wlerr("ERROR: Failed to initialize XBee on mikroBUS1: %d\n", ret); + } +#endif + +#ifdef CONFIG_CLICKER2_STM32_MB2_XBEE + wlinfo("Configuring XBee in mikroBUS2\n"); + + ret = stm32_xbee_devsetup(&g_xbee_mb2_priv); + if (ret < 0) + { + wlerr("ERROR: Failed to initialize XBee on mikroBUS2: %d\n", ret); + } +#endif + + UNUSED(ret); + return OK; +} +#endif /* CONFIG_IEEE802154_XBEE */ diff --git a/configs/clicker2-stm32/xbee-6lowpan/defconfig b/configs/clicker2-stm32/xbee-6lowpan/defconfig new file mode 100644 index 0000000000..3d86d08f25 --- /dev/null +++ b/configs/clicker2-stm32/xbee-6lowpan/defconfig @@ -0,0 +1,120 @@ +CONFIG_ARCH="arm" +CONFIG_ARCH_BOARD="clicker2-stm32" +CONFIG_ARCH_BOARD_CLICKER2_STM32=y +CONFIG_ARCH_BUTTONS=y +CONFIG_ARCH_CHIP_STM32F407VG=y +CONFIG_ARCH_CHIP_STM32=y +CONFIG_ARCH_IRQBUTTONS=y +CONFIG_ARCH_STACKDUMP=y +CONFIG_BOARDCTL_USBDEVCTRL=y +CONFIG_BOARD_INITIALIZE=y +CONFIG_BOARD_LOOPSPERMSEC=16717 +CONFIG_BUILTIN=y +CONFIG_CDCACM_CONSOLE=y +CONFIG_CDCACM_RXBUFSIZE=256 +CONFIG_CDCACM_TXBUFSIZE=256 +CONFIG_CDCACM=y +CONFIG_CLICKER2_STM32_MB1_XBEE=y +# CONFIG_DEV_CONSOLE is not set +CONFIG_DRIVERS_IEEE802154=y +CONFIG_DRIVERS_WIRELESS=y +CONFIG_EXAMPLES_NETTEST_DEVNAME="wpan0" +CONFIG_EXAMPLES_NETTEST_SERVERIPv6ADDR_1=0xfe80 +CONFIG_EXAMPLES_NETTEST_SERVERIPv6ADDR_6=0x00ff +CONFIG_EXAMPLES_NETTEST_SERVERIPv6ADDR_7=0xfe00 +CONFIG_EXAMPLES_NETTEST_SERVERIPv6ADDR_8=0x0800 +CONFIG_EXAMPLES_NETTEST_SERVER_PORTNO=61616 +CONFIG_EXAMPLES_NETTEST_TARGET2=y +CONFIG_EXAMPLES_NETTEST=y +CONFIG_EXAMPLES_NSH_CXXINITIALIZE=y +CONFIG_EXAMPLES_NSH=y +CONFIG_EXAMPLES_UDP_CLIENT_PORTNO=61617 +CONFIG_EXAMPLES_UDP_DEVNAME="wpan0" +CONFIG_EXAMPLES_UDP_SERVERIPv6ADDR_1=0xfe80 +CONFIG_EXAMPLES_UDP_SERVERIPv6ADDR_6=0x00ff +CONFIG_EXAMPLES_UDP_SERVERIPv6ADDR_7=0xfe00 +CONFIG_EXAMPLES_UDP_SERVERIPv6ADDR_8=0x0d00 +CONFIG_EXAMPLES_UDP_SERVER_PORTNO=61616 +CONFIG_EXAMPLES_UDP_TARGET2=y +CONFIG_EXAMPLES_UDP=y +CONFIG_FAT_LCNAMES=y +CONFIG_FAT_LFN=y +CONFIG_FS_FAT=y +CONFIG_FS_PROCFS=y +CONFIG_HAVE_CXXINITIALIZE=y +CONFIG_HAVE_CXX=y +CONFIG_IEEE802154_I8SAK=y +CONFIG_IEEE802154_IND_PREALLOC=32 +CONFIG_IEEE802154_MACDEV=y +CONFIG_IEEE802154_NETDEV=y +CONFIG_IEEE802154_XBEE=y +CONFIG_INTELHEX_BINARY=y +CONFIG_IOB_BUFSIZE=128 +CONFIG_IOB_NBUFFERS=32 +CONFIG_IOB_NCHAINS=16 +CONFIG_MAC802154_NNOTIF=48 +CONFIG_MAC802154_NTXDESC=32 +CONFIG_MAX_TASKS=16 +CONFIG_MAX_WDOGPARMS=2 +CONFIG_NET_6LOWPAN=y +CONFIG_NET_BROADCAST=y +CONFIG_NETDEVICES=y +CONFIG_NETDEV_LATEINIT=y +CONFIG_NETDEV_STATISTICS=y +CONFIG_NETDEV_WIRELESS_IOCTL=y +# CONFIG_NET_ETHERNET is not set +CONFIG_NET_HOSTNAME="XBee" +# CONFIG_NET_IPv4 is not set +CONFIG_NET_IPv6=y +CONFIG_NET_SOCKOPTS=y +CONFIG_NET_STATISTICS=y +CONFIG_NET_TCPBACKLOG=y +CONFIG_NET_TCP_WRITE_BUFFERS=y +CONFIG_NET_TCP=y +CONFIG_NET_UDP=y +CONFIG_NETUTILS_TELNETD=y +CONFIG_NET=y +CONFIG_NFILE_DESCRIPTORS=8 +CONFIG_NFILE_STREAMS=8 +CONFIG_NSH_ARCHINIT=y +CONFIG_NSH_BUILTIN_APPS=y +# CONFIG_NSH_CMDOPT_DF_H is not set +CONFIG_NSH_DISABLE_GET=y +CONFIG_NSH_DISABLE_PUT=y +# CONFIG_NSH_DISABLE_TELNETD is not set +CONFIG_NSH_DISABLE_WGET=y +CONFIG_NSH_FILEIOSIZE=512 +CONFIG_NSH_LINELEN=64 +CONFIG_NSH_NETLOCAL=y +CONFIG_NSH_NOMAC=y +CONFIG_NSH_READLINE=y +CONFIG_PREALLOC_MQ_MSGS=4 +CONFIG_PREALLOC_TIMERS=4 +CONFIG_PREALLOC_WDOGS=16 +CONFIG_RAMLOG_BUFSIZE=8192 +CONFIG_RAMLOG_SYSLOG=y +CONFIG_RAMLOG=y +CONFIG_RAM_SIZE=131072 +CONFIG_RAM_START=0x20000000 +CONFIG_RAW_BINARY=y +CONFIG_RR_INTERVAL=200 +CONFIG_SCHED_HPWORKPERIOD=50000 +CONFIG_SCHED_HPWORKPRIORITY=192 +CONFIG_SCHED_HPWORK=y +CONFIG_SCHED_LPWORKPRIORITY=160 +CONFIG_SCHED_LPWORK=y +CONFIG_SCHED_WAITPID=y +CONFIG_SDCLONE_DISABLE=y +CONFIG_STANDARD_SERIAL=y +CONFIG_START_YEAR=2013 +CONFIG_STM32_CCMEXCLUDE=y +CONFIG_STM32_DISABLE_IDLE_SLEEP_DURING_DEBUG=y +CONFIG_STM32_JTAG_SW_ENABLE=y +CONFIG_STM32_OTGFS=y +CONFIG_STM32_PWR=y +CONFIG_SYSTEM_TELNET_CLIENT=y +CONFIG_TASK_NAME_SIZE=32 +CONFIG_USBDEV=y +CONFIG_USER_ENTRYPOINT="nsh_main" +CONFIG_WIRELESS_IEEE802154=y +CONFIG_WIRELESS=y diff --git a/configs/same70-xplained/src/sam_bringup.c b/configs/same70-xplained/src/sam_bringup.c index 91c191914e..459d1d6118 100644 --- a/configs/same70-xplained/src/sam_bringup.c +++ b/configs/same70-xplained/src/sam_bringup.c @@ -339,6 +339,16 @@ int sam_bringup(void) } #endif +#ifdef HAVE_XBEE + /* Configure XBee */ + + ret = sam_xbee_initialize(); + if (ret < 0) + { + syslog(LOG_ERR, "ERROR: sam_xbee_initialize() failed: %d\n", ret); + } +#endif + #ifdef HAVE_ELF /* Initialize the ELF binary loader */ diff --git a/configs/same70-xplained/src/sam_xbee.c b/configs/same70-xplained/src/sam_xbee.c new file mode 100644 index 0000000000..9f2d8b8d9f --- /dev/null +++ b/configs/same70-xplained/src/sam_xbee.c @@ -0,0 +1,310 @@ +/**************************************************************************** + * configs/same70-xplained/src/sam_xbee.c + * + * Copyright (C) 2017 Verge Inc, All rights reserver + * 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 "sam_gpio.h" +#include "sam_spi.h" + +#include "same70-xplained.h" + +#ifdef HAVE_XBEE + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#ifndef CONFIG_DRIVERS_WIRELESS +# error Wireless support requires CONFIG_DRIVERS_WIRELESS +#endif + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +struct sam_priv_s +{ + struct xbee_lower_s dev; + uint32_t attncfg; + uint32_t rstcfg; + uint8_t irq; + uint8_t spidev; +}; + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +/* IRQ/GPIO access callbacks. These operations all hidden behind callbacks + * to isolate the XBee driver from differences in GPIO interrupt handling + * varying boards and MCUs. + * + * sam_reset - Reset the XBee + * irq_attach - Attach the XBee ATTN handler to the GPIO interrupt + * irq_enable - Enable or disable the GPIO interrupt + */ + +static int sam_reset(FAR const struct xbee_lower_s *lower); +static int sam_attach_irq(FAR const struct xbee_lower_s *lower, + xcpt_t handler, FAR void *arg); +static void sam_enable_irq(FAR const struct xbee_lower_s *lower, + bool state); +static int sam_xbee_devsetup(FAR struct sam_priv_s *priv); + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/* A reference to a structure of this type must be passed to the XBee + * driver. This structure provides information about the configuration + * of the XBee 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_SAME70XPLAINED_MB1_XBEE +static struct sam_priv_s g_xbee_mb1_priv = +{ + .dev.attach = sam_attach_irq, + .dev.enable = sam_enable_irq, + .intcfg = CLICK_MB1_INTR, + .rstcfg = CLICK_MB1_RESET, + .irq = IRQ_MB1, + .csno = MB1_CSNO, +}; +#endif + +#ifdef CONFIG_SAME70XPLAINED_MB2_XBEE +static struct sam_priv_s g_xbee_mb2_priv = +{ + .dev.attach = sam_attach_irq, + .dev.enable = sam_enable_irq, + .intcfg = CLICK_MB2_INTR, + .rstcfg = CLICK_MB2_RESET, + .irq = IRQ_MB2, + .spidev = MB2_CSNO, +}; +#endif + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +static int sam_reset(FAR const struct xbee_lower_s *lower) +{ + FAR struct sam_priv_s *priv = (FAR struct sam_priv_s *)lower; + + DEBUGASSERT(priv != NULL); + + /* Reset pulse */ + + sam_gpiowrite(priv->rstcfg, true); + sam_gpiowrite(priv->rstcfg, false); + + /* Wait minimum 1.5 ms to allow Xbee a proper boot-up sequence */ + /* TODO: Update time according to datasheet */ + + usleep(1500); + return OK; +} + +static int sam_attach_irq(FAR const struct xbee_lower_s *lower, + xcpt_t handler, FAR void *arg) +{ + FAR struct sam_priv_s *priv = (FAR struct sam_priv_s *)lower; + int ret; + + DEBUGASSERT(priv != NULL); + + ret = irq_attach(priv->irq, handler, arg); + if (ret < 0) + { + wlerr("ERROR: Failed to attach XBee interrupt: %d\n", ret); + } + + return ret; +} + +static void sam_enable_irq(FAR const struct xbee_lower_s *lower, + bool state) +{ + FAR struct sam_priv_s *priv = (FAR struct sam_priv_s *)lower; + static bool enabled; + irqstate_t flags; + + /* The caller should not attempt to enable interrupts if the handler + * has not yet been 'attached' + */ + + DEBUGASSERT(priv != NULL); + wlinfo("state: %d irq: %u\n", (int)state, priv->irq); + + /* Has the interrupt state changed */ + + flags = enter_critical_section(); + if (state != enabled) + { + /* Enable or disable interrupts */ + + if (state) + { + wlinfo("Enabling\n"); + sam_gpioirqenable(priv->irq); + enabled = true; + } + else + { + wlinfo("Disabling\n"); + sam_gpioirqdisable(priv->irq); + enabled = false; + } + } + + leave_critical_section(flags); +} + +/**************************************************************************** + * Name: sam_xbee_devsetup + * + * Description: + * Initialize one the XBee 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 sam_xbee_devsetup(FAR struct sam_priv_s *priv) +{ + FAR struct xbee_mac_s *xbee; + FAR struct spi_dev_s *spi; + int ret; + + sam_configgpio(priv->rstcfg); + sam_configgpio(priv->attncfg); + sam_gpioirq(priv->attncfg); + + /* Initialize the SPI bus and get an instance of the SPI interface */ + + spi = sam_spibus_initialize(priv->csno); + if (spi == NULL) + { + wlerr("ERROR: Failed to initialize SPI bus %d\n", priv->csno); + return -ENODEV; + } + + /* Initialize and register the SPI XBee device */ + + xbee = xbee_init(spi, &priv->dev); + if (xbee == NULL) + { + wlerr("ERROR: Failed to initialize XBee radio\n"); + return -ENODEV; + } + + ret = xbee_netdev_register(xbee); + if (ret < 0) + { + wlerr("ERROR: Failed to register the XBee MAC network driver wpan%d: %d\n", + 0, ret); + return ret; + } + + return OK; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: sam_xbee_initialize + * + * Description: + * Initialize the XBee device. + * + * Returned Value: + * Zero is returned on success. Otherwise, a negated errno value is + * returned to indicate the nature of the failure. + * + ****************************************************************************/ + +int sam_xbee_initialize(void) +{ + int ret; + +#ifdef CONFIG_SAME70XPLAINED_MB1_XBEE + wlinfo("Configuring BEE in mikroBUS1\n"); + + ret = sam_xbee_devsetup(&g_xbee_mb1_priv); + if (ret < 0) + { + wlerr("ERROR: Failed to initialize XBee on mikroBUS1: %d\n", ret); + } +#endif + +#ifdef CONFIG_SAME70XPLAINED_MB2_XBEE + wlinfo("Configuring XBee in mikroBUS2\n"); + + ret = sam_xbee_devsetup(&g_xbee_mb2_priv); + if (ret < 0) + { + wlerr("ERROR: Failed to initialize XBee on mikroBUS2: %d\n", ret); + } +#endif + + UNUSED(ret); + return OK; +} +#endif /* HAVE_XBEE */ diff --git a/configs/same70-xplained/src/same70-xplained.h b/configs/same70-xplained/src/same70-xplained.h index 5f9d52fc01..009eef7cb5 100644 --- a/configs/same70-xplained/src/same70-xplained.h +++ b/configs/same70-xplained/src/same70-xplained.h @@ -64,6 +64,7 @@ #define HAVE_PROGMEM_CHARDEV 1 #define HAVE_I2CTOOL 1 #define HAVE_MRF24J40 1 +#define HAVE_XBEE 1 /* HSMCI */ /* Can't support MMC/SD if the card interface is not enabled */ @@ -230,6 +231,29 @@ # undef HAVE_MRF24J40 #endif +/* Check if the XBee is supported in this configuration */ + +#ifndef CONFIG_IEEE802154_XBEE +# undef HAVE_XBEE +#endif + +#ifndef CONFIG_SAME70XPLAINED_CLICKSHIELD +# undef HAVE_XBEE +#endif + +#if !defined(CONFIG_SAME70XPLAINED_MB1_XBEE) && !defined(CONFIG_SAME70XPLAINED_MB2_XBEE) && \ + !defined(CONFIG_SAME70XPLAINED_MB3_XBEE) +# undef HAVE_XBEE +#endif + +#ifndef CONFIG_SAMV7_SPI0_MASTER +# undef HAVE_XBEE +#endif + +#ifndef CONFIG_SAMV7_GPIOA_IRQ +# undef HAVE_XBEE +#endif + /* SAME70-XPLD GPIO Pin Definitions *************************************************/ /* Ethernet MAC. diff --git a/drivers/wireless/ieee802154/Kconfig b/drivers/wireless/ieee802154/Kconfig index df4a1796a0..d4c15be45c 100644 --- a/drivers/wireless/ieee802154/Kconfig +++ b/drivers/wireless/ieee802154/Kconfig @@ -22,4 +22,12 @@ config IEEE802154_AT86RF233 source drivers/wireless/ieee802154/at86rf23x/Kconfig +config IEEE802154_XBEE + bool "XBee IEEE 802.15.4 Radio (w/ MAC)" + default n + ---help--- + This selection enables support for the XBee Radio device. + +source drivers/wireless/ieee802154/xbee/Kconfig + endif # DRIVERS_IEEE802154 diff --git a/drivers/wireless/ieee802154/Make.defs b/drivers/wireless/ieee802154/Make.defs index 2aa926dbe0..cd898cd666 100644 --- a/drivers/wireless/ieee802154/Make.defs +++ b/drivers/wireless/ieee802154/Make.defs @@ -43,6 +43,7 @@ ifeq ($(CONFIG_DRIVERS_IEEE802154),y) include wireless$(DELIM)ieee802154$(DELIM)mrf24j40$(DELIM)Make.defs include wireless$(DELIM)ieee802154$(DELIM)at86rf23x$(DELIM)Make.defs +include wireless$(DELIM)ieee802154$(DELIM)xbee$(DELIM)Make.defs # Include common IEEE 802.15.4 build support diff --git a/drivers/wireless/ieee802154/xbee/Kconfig b/drivers/wireless/ieee802154/xbee/Kconfig new file mode 100644 index 0000000000..5b28d40b63 --- /dev/null +++ b/drivers/wireless/ieee802154/xbee/Kconfig @@ -0,0 +1,77 @@ +# +# For a description of the syntax of this configuration file, +# see the file kconfig-language.txt in the NuttX tools repository. +# + +if IEEE802154_XBEE + +config IEEE802154_XBEE_FREQUENCY + int "SPI Frequency for XBee Radio" + default 2000000 + ---help--- + SPI SLCK frequency in Hz + +config XBEE_NETDEV_RECVRPRIO + int "Priority of frame receiver registerd with the MAC layer" + default 1 + ---help--- + When the MAC layer receives an incoming data frame, it passes the frame + to registered receivers, in order of receiver priority, until one of the + receivers claim the frame. + + An example case would be when 6LoWPAN and the MAC character driver are + enabled. Both have receivers registered with the MAC. The 6LoWPAN layer + should get assigned a higher priority than the character driver. In this + case, the 6LoWPAN receiver will receive the frame first. If the frame is + a 6LoWPAN frame, it will claim the frame and the MAC will not pass the + frame to any additional receivers. If it does not claim the frame, the + MAC layer will call the next highest priority receiver, in this case, + the MAC character driver (which should always be lowest priority since + it is a "catch-all" type receiver). + +choice + prompt "Work queue" + default XBEE_NETDEV_LPWORK if SCHED_LPWORK + default XBEE_NETDEV_HPWORK if !SCHED_LPWORK && SCHED_HPWORK + depends on SCHED_WORKQUEUE + ---help--- + Work queue support is required to use the XBee MAC network + driver. + + WARNING!! The IEEE802.15.4 network device must never run on the same + work queue as does the IEEE 802.15.4 MAC. That configuration will + cause deadlocks: The network logic may be blocked on the work queue + waiting on resources that can only be freed by the MAC logic but the + MAC is unable to run because the work queue is blocked. The + recommended configuration is: Network on the LP work queue; MAC on HP + work queue. Blocking on the HP work queue is a very bad thing in + any case. + +config XBEE_NETDEV_HPWORK + bool "High priority" + depends on SCHED_HPWORK + +config XBEE_NETDEV_LPWORK + bool "Low priority" + depends on SCHED_LPWORK + +endchoice # Work queue + +config XBEE_NNOTIF + int "Number or notification structures" + default 3 + ---help--- + Configured number of notification strucures Default: 3 + + When various MAC management events occur, the MAC notifies the registered + receiver with an allocated notification structure indicating the event. The + events are primitives such as Association Indication etc. + +config XBEE_LOCK_VERBOSE + bool "Verbose logging related to XBee driver lock management" + default n + depends on DEBUG_WIRELESS_INFO + ---help--- + Enable verbose logging of XBee lock management. Default: false + +endif # IEEE802154_XBEE diff --git a/drivers/wireless/ieee802154/xbee/Make.defs b/drivers/wireless/ieee802154/xbee/Make.defs new file mode 100644 index 0000000000..241b6bc322 --- /dev/null +++ b/drivers/wireless/ieee802154/xbee/Make.defs @@ -0,0 +1,48 @@ +############################################################################ +# drivers/ieee802154/xbee/Make.defs +# +# 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. +# +############################################################################ + +ifeq ($(CONFIG_IEEE802154_XBEE),y) + +# Include XBee files into the build + +CSRCS += xbee_dataind.c xbee_ioctl.c xbee_mac.c xbee_netdev.c xbee_notif.c xbee.c + +# Include XBee build support + +DEPPATH += --dep-path wireless$(DELIM)ieee802154$(DELIM)xbee +VPATH += :wireless$(DELIM)ieee802154$(DELIM)xbee +CFLAGS += ${shell $(INCDIR) $(INCDIROPT) "$(CC)" $(TOPDIR)$(DELIM)drivers$(DELIM)wireless$(DELIM)ieee802154$(DELIM)xbee} + +endif # CONFIG_IEEE802154_XBEE diff --git a/drivers/wireless/ieee802154/xbee/xbee.c b/drivers/wireless/ieee802154/xbee/xbee.c new file mode 100644 index 0000000000..2e547e9fe5 --- /dev/null +++ b/drivers/wireless/ieee802154/xbee/xbee.c @@ -0,0 +1,1477 @@ +/**************************************************************************** + * drivers/wireless/xbee/drivers/xbee.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 + * + 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 "xbee.h" +#include "xbee_mac.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +static int xbee_interrupt(int irq, FAR void *context, FAR void *arg); +static void xbee_attnworker(FAR void *arg); +static bool xbee_validate_apiframe(uint8_t frametype, uint16_t framelen); +static bool xbee_verify_checksum(FAR const struct iob_s *iob); +static void xbee_process_apiframes(FAR struct xbee_priv_s *priv, + FAR struct iob_s *iob); +static void xbee_process_txstatus(FAR struct xbee_priv_s *priv, uint8_t frameid, + uint8_t status); +static void xbee_process_rxframe(FAR struct xbee_priv_s *priv, + FAR struct iob_s *frame, + enum ieee802154_addrmode_e addrmode); + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: xbee_interrupt + * + * Description: + * Hardware interrupt handler + * + * Parameters: + * irq - Number of the IRQ that generated the interrupt + * context - Interrupt register state save info (architecture-specific) + * + * Returned Value: + * OK on success + * + * Assumptions: + * + ****************************************************************************/ + +static int xbee_interrupt(int irq, FAR void *context, FAR void *arg) +{ + FAR struct xbee_priv_s *priv = (FAR struct xbee_priv_s *)arg; + + DEBUGASSERT(priv != NULL); + + priv->attn_latched = true; + + /* 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. + */ + + if (work_available(&priv->attnwork)) + { + return work_queue(HPWORK, &priv->attnwork, xbee_attnworker, (FAR void *)priv, 0); + } + + return OK; +} + +/**************************************************************************** + * Name: xbee_attnworker + * + * Description: + * Perform interrupt handling (Attention) logic outside of the interrupt handler + * (on the work queue thread). + * + * Parameters: + * arg - The reference to the driver structure (cast to void*) + * + * Returned Value: + * None + * + * Assumptions: + * + ****************************************************************************/ + +static void xbee_attnworker(FAR void *arg) +{ + FAR struct xbee_priv_s *priv = (FAR struct xbee_priv_s *)arg; + FAR struct iob_s *iobhead = NULL; + FAR struct iob_s *iob = NULL; + FAR struct iob_s *previob = NULL; + uint16_t rxframelen; + + DEBUGASSERT(priv); + DEBUGASSERT(priv->spi); + + /* NOTE: There is a helpful side-effect to trying to get the SPI Lock here + * even when there is a write going on. That is, if the SPI write are on a + * thread with lower priority, trying to get the lock here should boost the + * priority of that thread, helping move along the low-level driver work + * that really should be happening in a high priority way anyway. + */ + + SPI_LOCK(priv->spi, 1); + SPI_SETBITS(priv->spi, 8); + SPI_SETMODE(priv->spi, SPIDEV_MODE0); + SPI_SETFREQUENCY(priv->spi, CONFIG_IEEE802154_XBEE_FREQUENCY); + + /* Assert CS */ + + SPI_SELECT(priv->spi, SPIDEV_IEEE802154(0), true); + + /* Check to make sure all the data hasn't already been clocked in and + * we just need to process it. + */ + + if (priv->attn_latched && !priv->lower->poll(priv->lower)) + { + priv->attn_latched = false; + } + + /* Allocate an IOB for the incoming data. */ + + iob = iob_alloc(false); + iob->io_flink = NULL; + iob->io_len = 0; + iob->io_offset = 0; + iob->io_pktlen = 0; + + /* Keep a reference to the first IOB. If we need to allocate more than + * one to hold each API frame, then we will still have this reference to + * the head of the list + */ + + iobhead = iob; + + if (priv->attn_latched) + { + while (priv->lower->poll(priv->lower)) + { + DEBUGASSERT(iob->io_len <= CONFIG_IOB_BUFSIZE); + + SPI_RECVBLOCK(priv->spi, &iob->io_data[iob->io_len], 1); + + switch (iob->io_len) + { + case XBEE_APIFRAMEINDEX_STARTBYTE: + { + if (iob->io_data[iob->io_len] == XBEE_STARTBYTE) + { + iob->io_len++; + } + } + break; + case XBEE_APIFRAMEINDEX_LENGTHMSB: + { + rxframelen = iob->io_data[iob->io_len++] << 8; + } + break; + case XBEE_APIFRAMEINDEX_LENGTHLSB: + { + rxframelen |= iob->io_data[iob->io_len++]; + rxframelen += XBEE_APIFRAME_OVERHEAD; + } + break; + case XBEE_APIFRAMEINDEX_TYPE: + { + /* Check that the length and frame type make sense together */ + + if (!xbee_validate_apiframe(iob->io_data[iob->io_len], + rxframelen - XBEE_APIFRAME_OVERHEAD)) + { + wlwarn("invalid length on incoming API frame. Dropping!\n"); + iob->io_len = 0; + } + else + { + iob->io_len++; + } + } + break; + default: + { + if (iob->io_len == rxframelen - 1) + { + iob->io_len++; + if (xbee_verify_checksum(iob)) + { + /* This API frame is complete. Allocate a new IOB + * and link it to the existing one. When we are all + * finished we will pass this IOB list along for + * processing. + */ + + iob->io_flink = iob_alloc(false); + iob = iob->io_flink; + + iob->io_flink = NULL; + iob->io_len = 0; + iob->io_offset = 0; + iob->io_pktlen = 0; + } + else + { + wlwarn("invalid checksum on incoming API frame. Dropping!\n"); + iob->io_len = 0; + } + } + else + { + iob->io_len++; + } + } + break; + } + } + + priv->attn_latched = false; + } + + /* The last IOB in the list (or the only one) may be able to be freed since + * it may not have any valid data. If it contains some data, but not a whole + * API frame, something is wrong, so we just warn the user and drop the + * data. If the data was valid, the ATTN line should have stayed asserted + * until all the data was clocked in. So if we don't have a full frame, + * we can only drop it. + */ + + if (iob->io_len < XBEE_APIFRAME_OVERHEAD || iob->io_len != rxframelen) + { + if (iobhead == iob) + { + iobhead = NULL; + } + else + { + previob = iobhead; + while (previob->io_flink != iob) + { + previob = previob->io_flink; + } + previob->io_flink = NULL; + } + + if (iob->io_len > 0) + { + wlwarn("Partial API frame clocked in. Dropping!\n"); + } + + iob_free(iob); + } + + if (iobhead != NULL) + { + if (priv->rx_apiframes == NULL) + { + priv->rx_apiframes = iobhead; + } + else + { + iob = priv->rx_apiframes; + while (iob->io_flink != NULL) + { + iob = iob->io_flink; + } + + iob->io_flink = iobhead; + } + } + + /* Before unlocking the SPI bus, we "detach" the IOB list from the private + * struct and keep a copy. When the SPI bus becomes free, more data can + * be clocked in from an SPI write. By detaching the IOB list, we can process + * the incoming data without holding up the SPI bus + */ + + iobhead = priv->rx_apiframes; + priv->rx_apiframes = NULL; + + /* De-assert CS */ + + SPI_SELECT(priv->spi, SPIDEV_IEEE802154(0), false); + + /* Relinquish control of the SPI Bus */ + + SPI_LOCK(priv->spi, 0); + + if (iobhead != NULL) + { + xbee_process_apiframes(priv, iobhead); + } +} + +/**************************************************************************** + * Name: xbee_validate_apiframe + * + * Description: + * Verifies that the API frame type is known and that the length makes + * sense for that frame type. + * + * Parameters: + * frame - pointer to the frame data + * datalen - The size of the data section of the frame. This is the value + * included as the second and third byte of the frame. + * + * Returns: + * true - Frame type is known and length is logical + * false - Frame type is unknown or length is invalid for frame type + * + ****************************************************************************/ + +static bool xbee_validate_apiframe(uint8_t frametype, uint16_t datalen) +{ + switch (frametype) + { + case XBEE_APIFRAME_MODEMSTATUS: + { + if (datalen != 2) + { + return false; + } + } + break; + case XBEE_APIFRAME_ATRESPONSE: + { + return true; + } + break; + case XBEE_APIFRAME_TXSTATUS: + { + if (datalen != 3) + { + return false; + } + } + break; + case XBEE_APIFRAME_RX_EADDR: + { + if (datalen < 14) + { + return false; + } + } + break; + case XBEE_APIFRAME_RX_SADDR: + { + if (datalen < 8) + { + return false; + } + } + break; + default: + { + return false; + } + break; + } + + return true; +} + +/**************************************************************************** + * Name: xbee_verify_checksum + * + * Description: + * Verifies API frame checksum. + * + * Parameters: + * frame - pointer to the frame data + * framelen - size of the overall frame. NOT the data length field + * + * Returns: + * true - Checksum is valid + * false - Checksum is invalid + * + ****************************************************************************/ + +static bool xbee_verify_checksum(FAR const struct iob_s *iob) +{ + int i; + uint8_t checksum = 0; + + DEBUGASSERT(iob->io_len > XBEE_APIFRAME_OVERHEAD); + + /* Skip the start byte and frame length, but include the checksum */ + + for (i = 3; i < iob->io_len; i++) + { + checksum += iob->io_data[i]; + } + + if (checksum != 0xFF) + { + wlwarn("Invalid checksum\n"); + return false; + } + + return true; +} + +/**************************************************************************** + * Name: xbee_process_apiframes + * + * Description: + * Processes a list of complete API frames. + * + * Assumptions: + * Frame has already been validated using frame type and frame length and + * the checksum has also been verified. + * + ****************************************************************************/ + +static void xbee_process_apiframes(FAR struct xbee_priv_s *priv, + FAR struct iob_s *framelist) +{ + FAR struct ieee802154_notif_s *notif; + FAR struct iob_s *frame; + FAR struct iob_s *nextframe; + FAR char *command; + + DEBUGASSERT(framelist != NULL); + + frame = framelist; + + /* At the end of each iteration, frame is set to the next frame in the list + * and the IOB is freed. If the IOB is not supposed to be freed, per the + * API frame type, the logic must update the frame to the next frame in the + * list and use continue to skip freeing the IOB. + */ + + while (frame) + { + /* Skip over start byte and length */ + + frame->io_offset += XBEE_APIFRAMEINDEX_TYPE; + + switch (frame->io_data[frame->io_offset++]) + { + case XBEE_APIFRAME_MODEMSTATUS: + { + wlinfo("Modem Status: %d\n", frame->io_data[frame->io_offset++]); + } + break; + case XBEE_APIFRAME_ATRESPONSE: + { + frame->io_offset++; /* Skip over frame index */ + + command = (FAR char *)&frame->io_data[frame->io_offset]; + frame->io_offset += 2; + + wlinfo("AT Repsonse Recevied: %.*s\n", 2, command); + + /* Make sure the command status is OK=0 */ + + if (frame->io_data[frame->io_offset]) + { + wlwarn("AT Command Error: %d\n", + frame->io_data[frame->io_offset]); + } + else + { + frame->io_offset++; + + if (memcmp(command, "ID", 2) == 0) + { + priv->addr.panid[1] = frame->io_data[frame->io_offset++]; + priv->addr.panid[0] = frame->io_data[frame->io_offset++]; + + xbee_notify_respwaiter(priv, XBEE_RESP_AT_NETWORKID); + } + else if (memcmp(command, "SH", 2) == 0) + { + priv->addr.eaddr[7] = frame->io_data[frame->io_offset++]; + priv->addr.eaddr[6] = frame->io_data[frame->io_offset++]; + priv->addr.eaddr[5] = frame->io_data[frame->io_offset++]; + priv->addr.eaddr[4] = frame->io_data[frame->io_offset++]; + + xbee_notify_respwaiter(priv, XBEE_RESP_AT_SERIALHIGH); + } + else if (memcmp(command, "SL", 2) == 0) + { + priv->addr.eaddr[3] = frame->io_data[frame->io_offset++]; + priv->addr.eaddr[2] = frame->io_data[frame->io_offset++]; + priv->addr.eaddr[1] = frame->io_data[frame->io_offset++]; + priv->addr.eaddr[0] = frame->io_data[frame->io_offset++]; + + xbee_notify_respwaiter(priv, XBEE_RESP_AT_SERIALLOW); + } + else if (memcmp(command, "MY", 2) == 0) + { + priv->addr.saddr[1] = frame->io_data[frame->io_offset++]; + priv->addr.saddr[0] = frame->io_data[frame->io_offset++]; + + xbee_notify_respwaiter(priv, XBEE_RESP_AT_SOURCEADDR); + } + else if (memcmp(command, "CH", 2) == 0) + { + priv->chan = frame->io_data[frame->io_offset++]; + xbee_notify_respwaiter(priv, XBEE_RESP_AT_CHAN); + } + else if (memcmp(command, "VR", 2) == 0) + { + priv->firmwareversion = frame->io_data[frame->io_offset++] << 8; + priv->firmwareversion |= frame->io_data[frame->io_offset++]; + + xbee_notify_respwaiter(priv, XBEE_RESP_AT_FIRMWAREVERSION); + } + else if (memcmp(command, "AI", 2) == 0) + { + wlinfo("Association Indication: %d\n", + frame->io_data[frame->io_offset]); + + /* 0xFF = No assocication status determined yet. */ + + if (frame->io_data[frame->io_offset] != 0xFF && + frame->io_data[frame->io_offset] != 0x13) + { + wd_cancel(priv->assocwd); + + xbee_lock(priv, false); + xbee_notif_alloc(priv, ¬if, false); + xbee_unlock(priv); + + notif->notiftype = IEEE802154_NOTIFY_CONF_ASSOC; + + if (frame->io_data[frame->io_offset] == 0) + { + notif->u.assocconf.status = IEEE802154_STATUS_SUCCESS; + } + else + { + notif->u.assocconf.status = IEEE802154_STATUS_FAILURE; + } + + xbee_notify(priv, notif); + } + } + else if (memcmp(command, "A1", 2) == 0) + { + wlinfo("Endpoint Association: %d\n", + frame->io_data[frame->io_offset]); + } + else if (memcmp(command, "A2", 2) == 0) + { + wlinfo("Coordinator Association: %d\n", + frame->io_data[frame->io_offset]); + } + else if (memcmp(command, "CE", 2) == 0) + { + wlinfo("Coordinator Enable: %d\n", + frame->io_data[frame->io_offset]); + } + else if (memcmp(command, "SP", 2) == 0) + { + wlinfo("Sleep Period: %dsec\n", + frame->io_data[frame->io_offset]/100); + } + else + { + wlwarn("Unhandled AT Response: %.*s\n", 2, command); + } + } + } + break; + case XBEE_APIFRAME_TXSTATUS: + { + xbee_process_txstatus(priv, frame->io_data[frame->io_offset], + frame->io_data[frame->io_offset + 1]); + } + break; + case XBEE_APIFRAME_RX_EADDR: + { + nextframe = frame->io_flink; + xbee_process_rxframe(priv, frame, IEEE802154_ADDRMODE_EXTENDED); + frame = nextframe; + + /* xbee_process_rxframe takes care of freeing the IOB or passing + * it along to the next highest layer */ + + continue; + } + break; + case XBEE_APIFRAME_RX_SADDR: + { + nextframe = frame->io_flink; + xbee_process_rxframe(priv, frame, IEEE802154_ADDRMODE_SHORT); + frame = nextframe; + + /* xbee_process_rxframe takes care of freeing the IOB or passing + * it along to the next highest layer */ + + continue; + } + break; + default: + { + /* This really should never happen since xbee_validateframe should + * have caught it. + */ + + wlwarn("Unknown frame type: %d\n", frame[XBEE_APIFRAMEINDEX_TYPE]); + } + break; + } + + nextframe = frame->io_flink; + iob_free(frame); + frame = nextframe; + } +} + +/**************************************************************************** + * Name: xbee_process_rxframe + * + * Description: + * Process an incoming RX frame. + * + ****************************************************************************/ + +static void xbee_process_rxframe(FAR struct xbee_priv_s *priv, + FAR struct iob_s *frame, + enum ieee802154_addrmode_e addrmode) +{ + FAR struct ieee802154_data_ind_s *dataind; + FAR struct xbee_maccb_s *cb; + int ret; + + xbee_lock(priv, false); + xbee_dataind_alloc(priv, &dataind, false); + xbee_unlock(priv); + + dataind->frame = frame; + + /* The XBee does not give us information about how the device was addressed. + * It only indicates the source mode. Therefore, we use the src address mode + * as the destination address mode, unless the short address is set to + * IEEE802154_SADDR_BCAST or IEEE802154_SADDR_UNSPEC + */ + + memcpy(&dataind->dest, &priv->addr, sizeof(struct ieee802154_addr_s)); + + if (addrmode == IEEE802154_ADDRMODE_EXTENDED) + { + dataind->dest.mode = IEEE802154_ADDRMODE_EXTENDED; + dataind->src.mode = IEEE802154_ADDRMODE_EXTENDED; + dataind->src.eaddr[7] = frame->io_data[frame->io_offset++]; + dataind->src.eaddr[6] = frame->io_data[frame->io_offset++]; + dataind->src.eaddr[5] = frame->io_data[frame->io_offset++]; + dataind->src.eaddr[4] = frame->io_data[frame->io_offset++]; + dataind->src.eaddr[3] = frame->io_data[frame->io_offset++]; + dataind->src.eaddr[2] = frame->io_data[frame->io_offset++]; + dataind->src.eaddr[1] = frame->io_data[frame->io_offset++]; + dataind->src.eaddr[0] = frame->io_data[frame->io_offset++]; + } + else + { + if (priv->addr.saddr == IEEE802154_SADDR_BCAST || + priv->addr.saddr == IEEE802154_SADDR_UNSPEC) + { + dataind->dest.mode = IEEE802154_ADDRMODE_EXTENDED; + } + else + { + dataind->dest.mode = IEEE802154_ADDRMODE_SHORT; + } + + dataind->src.mode = IEEE802154_ADDRMODE_SHORT; + dataind->src.saddr[1] = frame->io_data[frame->io_offset++]; + dataind->src.saddr[0] = frame->io_data[frame->io_offset++]; + } + + dataind->rssi = frame->io_data[frame->io_offset++]; + + frame->io_offset++; /* Skip options byte */ + + frame->io_len--; /* Remove the checksum */ + + /* If there are registered MCPS callback receivers registered, + * then forward the frame in priority order. If there are no + * registered receivers or if none of the receivers accept the + * data frame then drop the frame. + */ + + for (cb = priv->cb; cb != NULL; cb = cb->flink) + { + /* Does this MAC client want frames? */ + + if (cb->rxframe != NULL) + { + /* Yes.. Offer this frame to the receiver */ + + ret = cb->rxframe(cb, dataind); + if (ret >= 0) + { + /* The receiver accepted and disposed of the frame and + * its metadata. We are done. + */ + + return; + } + } + } + + xbee_dataind_free((XBEEHANDLE)priv, dataind); + iob_free(frame); +} + +/**************************************************************************** + * Name: xbee_process_txstatus + * + * Description: + * Process an incoming TX status message. This searches the list of pending + * tx requests and notifies the + * + ****************************************************************************/ + +static void xbee_process_txstatus(FAR struct xbee_priv_s *priv, uint8_t frameid, + uint8_t status) +{ + FAR struct ieee802154_notif_s *notif; + + xbee_lock(priv, false); + xbee_notif_alloc(priv, ¬if, false); + xbee_unlock(priv); + + notif->notiftype = IEEE802154_NOTIFY_CONF_DATA; + + switch (status) + { + case 0x00: + notif->u.dataconf.status = IEEE802154_STATUS_SUCCESS; + break; + case 0x01: + case 0x21: + notif->u.dataconf.status = IEEE802154_STATUS_NO_ACK; + break; + case 0x02: + notif->u.dataconf.status = IEEE802154_STATUS_CHANNEL_ACCESS_FAILURE; + break; + default: + notif->u.dataconf.status = IEEE802154_STATUS_FAILURE; + break; + } + + wlinfo("TX done. Frame ID: %d Status: 0x%02X\n", frameid, status); + + xbee_notify(priv, notif); +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: xbee_init + * + * Description: + * Initialize an XBee driver. The XBee 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 XBee + * lower - The MCU-specific interrupt used to control low-level MCU + * functions (i.e., XBee GPIO interrupts). + * + * Returned Value: + * OK on success; Negated errno on failure. + * + * Assumptions: + * + ****************************************************************************/ + +XBEEHANDLE xbee_init(FAR struct spi_dev_s *spi, + FAR const struct xbee_lower_s *lower) +{ + FAR struct xbee_priv_s *priv; + + /* Allocate object */ + + priv = (FAR struct xbee_priv_s *) kmm_zalloc(sizeof(struct xbee_priv_s)); + if (priv == NULL) + { + wlinfo("Failed allocation xbee_priv_s structure\n"); + return NULL; + } + + /* Attach irq */ + + if (lower->attach(lower, xbee_interrupt, priv) != OK) + { + wlinfo("Failed to attach IRQ with XBee lower half\n"); + kmm_free(priv); + return NULL; + } + + /* Allow exclusive access to the struct */ + + sem_init(&priv->exclsem, 0, 1); + + /* Initialize the data indication and notifcation allocation pools */ + + xbee_notifpool_init(priv); + xbee_dataindpool_init(priv); + + sq_init(&priv->waiter_queue); + + priv->assocwd = wd_create(); + + priv->lower = lower; + priv->spi = spi; + + priv->frameid = 0; /* Frame ID should never be 0, but it is incremented + * in xbee_next_frameid before being used so it will be 1 */ + + /* Reset the XBee */ + + priv->lower->reset(priv->lower); + + /* Enable interrupts */ + + priv->lower->enable(priv->lower, true); + + /* Trigger a dummy query without waiting to tell the XBee to operate in SPI + * mode. By default the XBee uses the UART interface. It switches automatically + * when a valid SPI frame is received. + */ + + xbee_at_query(priv, "VR"); + + return (XBEEHANDLE)priv; +} + +/**************************************************************************** + * Name: xbee_send_apiframe + * + * Description: + * Write an api frame over SPI + * + ****************************************************************************/ + +void xbee_send_apiframe(FAR struct xbee_priv_s *priv, + FAR const uint8_t *frame, uint16_t framelen) +{ + FAR struct iob_s *iob; + FAR struct iob_s *previob; + FAR struct iob_s *iobhead; + uint16_t rxframelen; + int i; + + /* Get access to SPI bus, set relevant settings */ + + SPI_LOCK(priv->spi, 1); + SPI_SETBITS(priv->spi, 8); + SPI_SETMODE(priv->spi, SPIDEV_MODE0); + SPI_SETFREQUENCY(priv->spi, CONFIG_IEEE802154_XBEE_FREQUENCY); + + /* Assert CS */ + + SPI_SELECT(priv->spi, SPIDEV_IEEE802154(0), true); + + /* Allocate an IOB for the incoming data. The XBee supports full-duplex + * SPI communication. This means that the MISO data can become valid at any + * time. This requires us to process incoming MISO data to see if it is valid. + */ + + iob = iob_alloc(false); + iob->io_flink = NULL; + iob->io_len = 0; + iob->io_offset = 0; + iob->io_pktlen = 0; + + /* Keep a reference to the first IOB. If we need to allocate more than + * one to hold each API frame, then we will still have this reference to the + * head of the list + */ + + iobhead = iob; + + i = 0; + while (i < framelen || priv->lower->poll(priv->lower)) + { + if (i < framelen) + { + iob->io_data[iob->io_len] = SPI_SEND(priv->spi, frame[i++]); + } + else + { + SPI_RECVBLOCK(priv->spi, &iob->io_data[iob->io_len], 1); + } + + /* attn_latched should be set true immediately from the interrupt. Any + * data prior to that can be completely ignored. + */ + + if (priv->attn_latched) + { + DEBUGASSERT(iob->io_len <= CONFIG_IOB_BUFSIZE); + + switch (iob->io_len) + { + case XBEE_APIFRAMEINDEX_STARTBYTE: + { + if (iob->io_data[iob->io_len] == XBEE_STARTBYTE) + { + iob->io_len++; + } + } + break; + case XBEE_APIFRAMEINDEX_LENGTHMSB: + { + rxframelen = iob->io_data[iob->io_len++] << 8; + } + break; + case XBEE_APIFRAMEINDEX_LENGTHLSB: + { + rxframelen |= iob->io_data[iob->io_len++]; + rxframelen += XBEE_APIFRAME_OVERHEAD; + } + break; + case XBEE_APIFRAMEINDEX_TYPE: + { + /* Check that the length and frame type make sense together */ + + if (!xbee_validate_apiframe(iob->io_data[iob->io_len], + rxframelen - XBEE_APIFRAME_OVERHEAD)) + { + wlwarn("invalid length on incoming API frame. Dropping!\n"); + iob->io_len = 0; + } + else + { + iob->io_len++; + } + } + break; + default: + { + if (iob->io_len == rxframelen - 1) + { + iob->io_len++; + if (xbee_verify_checksum(iob)) + { + /* This API frame is complete. Allocate a new IOB + * and link it to the existing one. When we are all + * finished we will pass this IOB list along for + * processing. + */ + + iob->io_flink = iob_alloc(false); + iob = iob->io_flink; + + iob->io_flink = NULL; + iob->io_len = 0; + iob->io_offset = 0; + iob->io_pktlen = 0; + } + else + { + wlwarn("invalid checksum on incoming API frame. Dropping!\n"); + iob->io_len = 0; + } + } + else + { + iob->io_len++; + } + } + break; + } + } + } + + /* The last IOB in the list (or the only one) may be able to be freed since + * it may not have any valid data. If it contains some data, but not a whole + * API frame, something is wrong, so we just warn the user and drop the + * data. If the data was valid, the ATTN line should have stayed asserted + * until all the data was clocked in. So if we don't have a full frame, + * we can only drop it. + */ + + if (iob->io_len < XBEE_APIFRAME_OVERHEAD || iob->io_len != rxframelen) + { + if (iobhead == iob) + { + iobhead = NULL; + } + else + { + previob = iobhead; + while (previob->io_flink != iob) + { + previob = previob->io_flink; + } + previob->io_flink = NULL; + } + + if (iob->io_len > 0) + { + wlwarn("Partial API frame clocked in. Dropping!\n"); + } + + iob_free(iob); + } + + if (iobhead != NULL) + { + if (priv->rx_apiframes == NULL) + { + priv->rx_apiframes = iobhead; + } + else + { + iob = priv->rx_apiframes; + while (iob->io_flink != NULL) + { + iob = iob->io_flink; + } + + iob->io_flink = iobhead; + } + } + + /* De-assert CS */ + + SPI_SELECT(priv->spi, SPIDEV_IEEE802154(0), false); + + /* Relinquish control of the SPI Bus */ + + SPI_LOCK(priv->spi,0); +} + +/**************************************************************************** + * Name: xbee_at_query + * + * Description: + * Helper function to query a AT Command value. + * + ****************************************************************************/ + +void xbee_at_query(FAR struct xbee_priv_s *priv, FAR const char *atcommand) +{ + uint8_t frame[8]; + + frame[0] = XBEE_STARTBYTE; + frame[1] = 0; + frame[2] = 4; + frame[3] = XBEE_APIFRAME_ATCOMMMAND; + frame[4] = 1; + frame[5] = *atcommand; + frame[6] = *(atcommand + 1); + + xbee_insert_checksum(frame, 8); + + xbee_send_apiframe(priv, frame, 8); +} + +/**************************************************************************** + * Name: xbee_query_firmwareversion + * + * Description: + * Sends API frame with AT command request in order to get the firmware version + * from the device. + * + ****************************************************************************/ + +void xbee_query_firmwareversion(FAR struct xbee_priv_s *priv) +{ + struct xbee_respwaiter_s respwaiter; + + respwaiter.resp_id = XBEE_RESP_AT_FIRMWAREVERSION; + sem_init(&respwaiter.sem, 0, 0); + sem_setprotocol(&respwaiter.sem, SEM_PRIO_NONE); + + xbee_register_respwaiter(priv, &respwaiter); + xbee_at_query(priv, "VR"); + + sem_wait(&respwaiter.sem); + + xbee_unregister_respwaiter(priv, &respwaiter); + + sem_destroy(&respwaiter.sem); +} + +/**************************************************************************** + * Name: xbee_query_panid + * + * Description: + * Sends API frame with AT command request in order to get the PAN ID + * (Network ID) from the device. + * + ****************************************************************************/ + +void xbee_query_panid(FAR struct xbee_priv_s *priv) +{ + struct xbee_respwaiter_s respwaiter; + + respwaiter.resp_id = XBEE_RESP_AT_NETWORKID; + sem_init(&respwaiter.sem, 0, 0); + sem_setprotocol(&respwaiter.sem, SEM_PRIO_NONE); + + xbee_register_respwaiter(priv, &respwaiter); + xbee_at_query(priv, "ID"); + + sem_wait(&respwaiter.sem); + + xbee_unregister_respwaiter(priv, &respwaiter); + + sem_destroy(&respwaiter.sem); +} + +/**************************************************************************** + * Name: xbee_query_eaddr + * + * Description: + * Sends API frame with AT command request in order to get the IEEE 802.15.4 + * Extended Address. (Serial Number) from the device. + * + ****************************************************************************/ + +void xbee_query_eaddr(FAR struct xbee_priv_s *priv) +{ + struct xbee_respwaiter_s respwaiter; + + respwaiter.resp_id = XBEE_RESP_AT_SERIALHIGH; + sem_init(&respwaiter.sem, 0, 0); + sem_setprotocol(&respwaiter.sem, SEM_PRIO_NONE); + + xbee_register_respwaiter(priv, &respwaiter); + xbee_at_query(priv, "SH"); + + sem_wait(&respwaiter.sem); + + respwaiter.resp_id = XBEE_RESP_AT_SERIALLOW; + xbee_at_query(priv, "SL"); + + sem_wait(&respwaiter.sem); + + xbee_unregister_respwaiter(priv, &respwaiter); + sem_destroy(&respwaiter.sem); +} + +/**************************************************************************** + * Name: xbee_query_saddr + * + * Description: + * Sends API frame with AT command request in order to get the + * Short Address. (Source Address (MY)) from the device. + * + ****************************************************************************/ + +void xbee_query_saddr(FAR struct xbee_priv_s *priv) +{ + struct xbee_respwaiter_s respwaiter; + + respwaiter.resp_id = XBEE_RESP_AT_SOURCEADDR; + sem_init(&respwaiter.sem, 0, 0); + sem_setprotocol(&respwaiter.sem, SEM_PRIO_NONE); + + xbee_register_respwaiter(priv, &respwaiter); + xbee_at_query(priv, "MY"); + + sem_wait(&respwaiter.sem); + + xbee_unregister_respwaiter(priv, &respwaiter); + + sem_destroy(&respwaiter.sem); +} + +/**************************************************************************** + * Name: xbee_query_chan + * + * Description: + * Sends API frame with AT command request in order to get the RF Channel + * (Operating Channel) from the device. + * + ****************************************************************************/ + +void xbee_query_chan(FAR struct xbee_priv_s *priv) +{ + struct xbee_respwaiter_s respwaiter; + + respwaiter.resp_id = XBEE_RESP_AT_CHAN; + sem_init(&respwaiter.sem, 0, 0); + sem_setprotocol(&respwaiter.sem, SEM_PRIO_NONE); + + xbee_register_respwaiter(priv, &respwaiter); + xbee_at_query(priv, "CH"); + + sem_wait(&respwaiter.sem); + + xbee_unregister_respwaiter(priv, &respwaiter); + + sem_destroy(&respwaiter.sem); +} + +/**************************************************************************** + * Name: xbee_set_panid + * + * Description: + * Sends API frame with AT command request in order to set the PAN ID + * (Network ID) of the device. + * + ****************************************************************************/ + +void xbee_set_panid(FAR struct xbee_priv_s *priv, FAR const uint8_t *panid) +{ + uint8_t frame[10]; + + IEEE802154_PANIDCOPY(priv->addr.panid, panid); + + frame[0] = XBEE_STARTBYTE; + frame[1] = 0; + frame[2] = 6; + frame[3] = XBEE_APIFRAME_ATCOMMMAND; + frame[4] = 0; + frame[5] = 'I'; + frame[6] = 'D'; + frame[7] = *(panid + 1); + frame[8] = *(panid); + + xbee_insert_checksum(frame, 10); + + xbee_send_apiframe(priv, frame, 10); +} + +/**************************************************************************** + * Name: xbee_set_saddr + * + * Description: + * Sends API frame with AT command request in order to set the Short Address + * (Source Address (MY)) of the device + * + ****************************************************************************/ + +void xbee_set_saddr(FAR struct xbee_priv_s *priv, FAR const uint8_t *saddr) +{ + uint8_t frame[10]; + + IEEE802154_SADDRCOPY(priv->addr.saddr, saddr); + + frame[0] = XBEE_STARTBYTE; + frame[1] = 0; + frame[2] = 6; + frame[3] = XBEE_APIFRAME_ATCOMMMAND; + frame[4] = 0; + frame[5] = 'M'; + frame[6] = 'Y'; + frame[7] = *(saddr + 1); + frame[8] = *(saddr); + + xbee_insert_checksum(frame, 10); + + xbee_send_apiframe(priv, frame, 10); +} + +/**************************************************************************** + * Name: xbee_set_chan + * + * Description: + * Sends API frame with AT command request in order to set the RF channel + * (Operatin Channel) of the device. + * + ****************************************************************************/ + +void xbee_set_chan(FAR struct xbee_priv_s *priv, uint8_t chan) +{ + uint8_t frame[9]; + + priv->chan = chan; + + frame[0] = XBEE_STARTBYTE; + frame[1] = 0; + frame[2] = 5; + frame[3] = XBEE_APIFRAME_ATCOMMMAND; + frame[4] = 0; + frame[5] = 'C'; + frame[6] = 'H'; + frame[7] = chan; + + xbee_insert_checksum(frame, 9); + + xbee_send_apiframe(priv, frame, 9); +} + +/**************************************************************************** + * Name: xbee_set_epassocflags + * + * Description: + * Set flags in 'A1' command register to determine how endpoint behaves + * with regards to association. + * + ****************************************************************************/ + +void xbee_set_epassocflags(FAR struct xbee_priv_s *priv, uint8_t flags) +{ + uint8_t frame[9]; + + frame[0] = XBEE_STARTBYTE; + frame[1] = 0; + frame[2] = 5; + frame[3] = XBEE_APIFRAME_ATCOMMMAND; + frame[4] = 0; + frame[5] = 'A'; + frame[6] = '1'; + frame[7] = flags; + + xbee_insert_checksum(frame, 9); + + xbee_send_apiframe(priv, frame, 9); +} + +/**************************************************************************** + * Name: xbee_set_coordassocflags + * + * Description: + * Set flags in 'A2' command register to determine how coordinator behaves + * with regards to association. + * + ****************************************************************************/ + +void xbee_set_coordassocflags(FAR struct xbee_priv_s *priv, uint8_t flags) +{ + uint8_t frame[9]; + + frame[0] = XBEE_STARTBYTE; + frame[1] = 0; + frame[2] = 5; + frame[3] = XBEE_APIFRAME_ATCOMMMAND; + frame[4] = 0; + frame[5] = 'A'; + frame[6] = '2'; + frame[7] = flags; + + xbee_insert_checksum(frame, 9); + + xbee_send_apiframe(priv, frame, 9); +} + +/**************************************************************************** + * Name: xbee_set_sleepperiod + * + * Description: + * Set Cyclic Sleep Period using 'SP' AT command. + * + ****************************************************************************/ + +void xbee_set_sleepperiod(FAR struct xbee_priv_s *priv, uint16_t period) +{ + uint8_t frame[10]; + + frame[0] = XBEE_STARTBYTE; + frame[1] = 0; + frame[2] = 6; + frame[3] = XBEE_APIFRAME_ATCOMMMAND; + frame[4] = 0; + frame[5] = 'S'; + frame[6] = 'P'; + frame[7] = period >> 8; + frame[8] = period; + + xbee_insert_checksum(frame, 10); + + xbee_send_apiframe(priv, frame, 10); +} + +/**************************************************************************** + * Name: xbee_enable_coord + * + * Description: + * Enables/Disables coordinator mode using 'CE' command + * + ****************************************************************************/ + +void xbee_enable_coord(FAR struct xbee_priv_s *priv, bool enable) +{ + uint8_t frame[9]; + + frame[0] = XBEE_STARTBYTE; + frame[1] = 0; + frame[2] = 5; + frame[3] = XBEE_APIFRAME_ATCOMMMAND; + frame[4] = 0; + frame[5] = 'C'; + frame[6] = 'E'; + frame[7] = enable; + + xbee_insert_checksum(frame, 9); + + xbee_send_apiframe(priv, frame, 9); +} + +/**************************************************************************** + * Name: xbee_regdump + * + * Description: + * Perform a series of queries updating struct and printing settings to SYSLOG. + * + ****************************************************************************/ + +void xbee_regdump(FAR struct xbee_priv_s *priv) +{ + xbee_query_firmwareversion(priv); + + wlinfo("XBee Firmware Version: %04x\n", priv->firmwareversion); + + xbee_at_query(priv, "CE"); + xbee_at_query(priv, "A1"); + xbee_at_query(priv, "A2"); + xbee_at_query(priv, "SP"); +} diff --git a/drivers/wireless/ieee802154/xbee/xbee.h b/drivers/wireless/ieee802154/xbee/xbee.h new file mode 100644 index 0000000000..9d54ab3877 --- /dev/null +++ b/drivers/wireless/ieee802154/xbee/xbee.h @@ -0,0 +1,581 @@ +/**************************************************************************** + * drivers/wireless/ieee802154/xbee/xbee.h + * + * Copyright (C) 2017 Verge Inc. All rights reserved. + * Author: Anthony Merlino + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +#ifndef __DRIVERS_WIRELESS_IEEE802154_XBEE_H +#define __DRIVERS_WIRELESS_IEEE802154_XBEE_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include +#include + +#include +#include + +#include + +#include "xbee_notif.h" +#include "xbee_dataind.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* Configuration *************************************************************/ + +#ifndef CONFIG_SCHED_HPWORK +# error High priority work queue required in this driver +#endif + +#ifndef CONFIG_IEEE802154_XBEE_FREQUENCY +# define CONFIG_IEEE802154_XBEE_FREQUENCY 2000000 +#endif + +#ifndef CONFIG_SPI_EXCHANGE +# error CONFIG_SPI_EXCHANGE required for this driver +#endif + +#if !defined(CONFIG_XBEE_NNOTIF) || CONFIG_XBEE_NNOTIF <= 0 +# undef CONFIG_XBEE_NNOTIF +# define CONFIG_XBEE_NNOTIF 6 +#endif + +#if !defined(CONFIG_XBEE_NDATAIND) || CONFIG_XBEE_NDATAIND <= 0 +# undef CONFIG_XBEE_NDATAIND +# define CONFIG_XBEE_NDATAIND 8 +#endif + +#define XBEE_APIFRAME_MODEMSTATUS 0x8A +#define XBEE_APIFRAME_ATCOMMMAND 0x08 +#define XBEE_APIFRAME_ATCOMMMANDQUEUED 0x09 +#define XBEE_APIFRAME_ATRESPONSE 0x88 +#define XBEE_APIFRAME_REMOTEREQUEST 0x17 +#define XBEE_APIFRAME_REMOTERESPONSE 0x97 +#define XBEE_APIFRAME_TXREQ_EADDR 0x00 +#define XBEE_APIFRAME_TXREQ_SADDR 0x01 +#define XBEE_APIFRAME_TXSTATUS 0x89 +#define XBEE_APIFRAME_RX_EADDR 0x80 +#define XBEE_APIFRAME_RX_SADDR 0x81 +#define XBEE_APIFRAME_RXIO_EADDR 0x82 +#define XBEE_APIFRAME_RXIO_SADDR 0x83 + +#define XBEE_EPASSOCFLAGS_PANID_REASSIGN 1 +#define XBEE_EPASSOCFLAGS_CHAN_REASSIGN 2 +#define XBEE_EPASSOCFLAGS_AUTOASSOC 4 +#define XBEE_EPASSOCFLAGS_POLLONWAKE 8 + +#define XBEE_COORDASSOCFLAGS_PANID_REASSIGN 1 +#define XBEE_COORDASSOCFLAGS_CHAN_REASSIGN 2 +#define XBEE_COORDASSOCFLAGS_ALLOWASSOC 4 + +/* Size of read buffer active for all of the transaction. i.e. must be big enough + * to handle full transmit and receive. + */ + +#define XBEE_RXBUF_SIZE 256 + +#define XBEE_STARTBYTE 0x7E + +#define XBEE_APIFRAME_OVERHEAD 4 + +#define XBEE_APIFRAMEINDEX_STARTBYTE 0 +#define XBEE_APIFRAMEINDEX_LENGTHMSB 1 +#define XBEE_APIFRAMEINDEX_LENGTHLSB 2 +#define XBEE_APIFRAMEINDEX_TYPE 3 + +/**************************************************************************** + * Public Types + ****************************************************************************/ + +/* Enumeration of Modem Status values */ + +enum xbee_modemstatus_e +{ + XBEE_MODEMSTATUS_HARDRESET = 0, + XBEE_MODEMSTATUS_WATCHDOGRESET, + XBEE_MODEMSTATUS_ASSOCIATED, + XBEE_MODEMSTATUS_NONETWORK, + XBEE_MODEMSTATUS_COORD, + XBEE_MODEMSTATUS_VOLTAGETOOHIGH, +}; + +enum xbee_response_e +{ + XBEE_RESP_MODEMSTATUS, + XBEE_RESP_AT_FIRMWAREVERSION, + XBEE_RESP_AT_HARDWAREVERSION, + XBEE_RESP_AT_NETWORKID, + XBEE_RESP_AT_SERIALHIGH, + XBEE_RESP_AT_SERIALLOW, + XBEE_RESP_AT_SOURCEADDR, + XBEE_RESP_AT_CHAN, + + /* Skip some allow for new AT commands */ +}; + +struct xbee_respwaiter_s +{ + FAR struct xbee_respwaiter_s *flink; + sem_t sem; + enum xbee_response_e resp_id; +}; + +/* An XBee device instance */ + +struct xbee_priv_s +{ + /* Low-level MCU-specific support */ + + FAR const struct xbee_lower_s *lower; + FAR struct spi_dev_s *spi; /* Saved SPI interface instance */ + + FAR struct xbee_maccb_s *cb; /* Head of a list of XBee MAC callbacks */ + + FAR struct iob_s *rx_apiframes; /* List of incoming API frames to process */ + + struct work_s attnwork; /* For deferring interrupt work to work queue */ + sem_t exclsem; /* Exclusive access to this struct */ + + WDOG_ID assocwd; /* Association watchdog */ + struct work_s assocwork; /* For polling for association status */ + + volatile bool attn_latched; /* Latched state of ATTN */ + + sq_queue_t waiter_queue; /* List of response waiters */ + + sq_queue_t tx_queue; /* List of pending TX requests */ + uint8_t frameid; /* For differentiating AT request/response */ + + uint16_t firmwareversion; + + /************* Fields related to addressing and coordinator *****************/ + + /* Holds all address information (Extended, Short, and PAN ID) for the MAC. */ + + struct ieee802154_addr_s addr; + + struct ieee802154_pandesc_s pandesc; + + /******************* Fields related to notifications ************************/ + + /* Pre-allocated notifications to be passed to the registered callback. These + * need to be freed by the application using xbee_xxxxnotif_free when + * the callee layer is finished with it's use. + */ + + FAR struct xbee_notif_s *notif_free; + struct xbee_notif_s notif_pool[CONFIG_XBEE_NNOTIF]; + sem_t notif_sem; + uint8_t nclients; + + /******************* Fields related to data indications *********************/ + + /* Pre-allocated notifications to be passed to the registered callback. These + * need to be freed by the application using xbee_dataind_free when + * the callee layer is finished with it's use. + */ + + FAR struct xbee_dataind_s *dataind_free; + struct xbee_dataind_s dataind_pool[CONFIG_XBEE_NDATAIND]; + sem_t dataind_sem; + + /****************** Uncategorized MAC PIB attributes ***********************/ + + /* What type of device is this node acting as */ + + enum ieee802154_devmode_e devmode : 2; + + /****************** PHY attributes ***********************/ + + uint8_t chan; +}; + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +/**************************************************************************** + * Inline Functions + ****************************************************************************/ + +#define xbee_givesem(s) sem_post(s) + +static inline int xbee_takesem(sem_t *sem, bool allowinterrupt) +{ + int ret; + do + { + /* Take a count from the semaphore, possibly waiting */ + + ret = sem_wait(sem); + if (ret < 0) + { + /* EINTR is the only error that we expect */ + + DEBUGASSERT(get_errno() == EINTR); + + if (allowinterrupt) + { + return -EINTR; + } + } + } + while (ret != OK); + + return OK; +} + +#ifdef CONFIG_XBEE_LOCK_VERBOSE +#define xbee_unlock(dev) \ + xbee_givesem(&dev->exclsem); \ + wlinfo("MAC unlocked\n"); +#else +#define xbee_unlock(dev) \ + xbee_givesem(&dev->exclsem); +#endif + +#define xbee_lock(dev, allowinterrupt) \ + xbee_lockpriv(dev, allowinterrupt, __FUNCTION__) + +static inline int xbee_lockpriv(FAR struct xbee_priv_s *dev, + bool allowinterrupt, FAR const char *funcname) +{ + int ret; + +#ifdef CONFIG_XBEE_LOCK_VERBOSE + wlinfo("Locking MAC: %s\n", funcname); +#endif + ret = xbee_takesem(&dev->exclsem, allowinterrupt); + if (ret < 0) + { + wlwarn("Failed to lock MAC\n"); + } + else + { +#ifdef CONFIG_XBEE_LOCK_VERBOSE + wlinfo("MAC locked\n"); +#endif + } + + return ret; +} + +/**************************************************************************** + * Name: xbee_register_respwaiter + * + * Description: + * Register a respone waiter + * + ****************************************************************************/ + +static inline void xbee_register_respwaiter(FAR struct xbee_priv_s *priv, + FAR struct xbee_respwaiter_s *waiter) +{ + sq_addlast((sq_entry_t *)waiter, &priv->waiter_queue); +} + +/**************************************************************************** + * Name: xbee_unregister_respwaiter + * + * Description: + * Unregister a respone waiter + * + ****************************************************************************/ + +static inline void xbee_unregister_respwaiter(FAR struct xbee_priv_s *priv, + FAR struct xbee_respwaiter_s *waiter) +{ + sq_rem((sq_entry_t *)waiter, &priv->waiter_queue); +} + +/**************************************************************************** + * Name: xbee_notify_respwaiter + * + * Description: + * Check to see if there are any respwaiters waiting for this response type. + * If so, signal them. + * + ****************************************************************************/ + +static inline void xbee_notify_respwaiter(FAR struct xbee_priv_s *priv, + enum xbee_response_e resp_id) +{ + FAR struct xbee_respwaiter_s *waiter; + + waiter = (FAR struct xbee_respwaiter_s *)sq_peek(&priv->waiter_queue); + + while (waiter != NULL) + { + if (waiter->resp_id == resp_id) + { + sem_post(&waiter->sem); + } + + waiter = (FAR struct xbee_respwaiter_s *)sq_next((FAR sq_entry_t *)waiter); + } +} + +/**************************************************************************** + * Name: xbee_next_frameid + * + * Description: + * Increment the frame id. This is used to coordinate TX requests with subsequent + * TX status frames received by the XBee device. We must skip value 0 since + * that value is to tell the XBee not to provide a status response. + * + ****************************************************************************/ + +static inline uint8_t xbee_next_frameid(FAR struct xbee_priv_s *priv) +{ + priv->frameid++; + if (priv->frameid == 0) + { + priv->frameid = 1; + } + + return priv->frameid; +} + +/**************************************************************************** + * Name: xbee_insert_checksum + * + * Description: + * Insert checksum into outbound API frame. + * + * Parameters: + * frame - pointer to the frame data + * framelen - size of the overall frame. NOT the data length field + * + ****************************************************************************/ + +static inline void xbee_insert_checksum(FAR uint8_t *frame, uint16_t framelen) +{ + int i; + uint8_t checksum = 0; + + DEBUGASSERT(framelen > XBEE_APIFRAME_OVERHEAD); + + /* Skip the start byte and frame length */ + + for (i = 3; i < framelen - 1; i++) + { + checksum += frame[i]; + } + + frame[framelen - 1] = 0xFF - checksum; +} + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +/**************************************************************************** + * Name: xbee_send_apiframe + * + * Description: + * Write an api frame over SPI + * + ****************************************************************************/ + +void xbee_send_apiframe(FAR struct xbee_priv_s *priv, + FAR const uint8_t *frame, uint16_t framelen); + +/**************************************************************************** + * Name: xbee_at_query + * + * Description: + * Helper function to query a AT Command value. + * + ****************************************************************************/ + +void xbee_at_query(FAR struct xbee_priv_s *priv, FAR const char *atcommand); + +/**************************************************************************** + * Name: xbee_query_firmwareversion + * + * Description: + * Sends API frame with AT command request in order to get the firmware version + * from the device. + * + ****************************************************************************/ + +void xbee_query_firmwareversion(FAR struct xbee_priv_s *priv); + +/**************************************************************************** + * Name: xbee_query_panid + * + * Description: + * Sends API frame with AT command request in order to get the PAN ID + * (Network ID) from the device. + * + ****************************************************************************/ + +void xbee_query_panid(FAR struct xbee_priv_s *priv); + +/**************************************************************************** + * Name: xbee_query_eaddr + * + * Description: + * Sends API frame with AT command request in order to get the IEEE 802.15.4 + * Extended Address. (Serial Number) from the device. + * + ****************************************************************************/ + +void xbee_query_eaddr(FAR struct xbee_priv_s *priv); + +/**************************************************************************** + * Name: xbee_query_saddr + * + * Description: + * Sends API frame with AT command request in order to get the + * Short Address. (Source Address (MY)) from the device. + * + ****************************************************************************/ + +void xbee_query_saddr(FAR struct xbee_priv_s *priv); + +/**************************************************************************** + * Name: xbee_query_chan + * + * Description: + * Sends API frame with AT command request in order to get the RF Channel + * (Operating Channel) from the device. + * + ****************************************************************************/ + +void xbee_query_chan(FAR struct xbee_priv_s *priv); + +/**************************************************************************** + * Name: xbee_query_assoc + * + * Description: + * Sends API frame with AT command request in order to get the association + * status (Association Indication) of the device + * + ****************************************************************************/ + +void xbee_query_assoc(FAR struct xbee_priv_s *priv); + +/**************************************************************************** + * Name: xbee_set_panid + * + * Description: + * Sends API frame with AT command request in order to set the PAN ID + * (Network ID) of the device. + * + ****************************************************************************/ + +void xbee_set_panid(FAR struct xbee_priv_s *priv, FAR const uint8_t *panid); + +/**************************************************************************** + * Name: xbee_set_saddr + * + * Description: + * Sends API frame with AT command request in order to set the Short Address + * (Source Address (MY)) of the device + * + ****************************************************************************/ + +void xbee_set_saddr(FAR struct xbee_priv_s *priv, FAR const uint8_t *saddr); + +/**************************************************************************** + * Name: xbee_set_chan + * + * Description: + * Sends API frame with AT command request in order to set the RF channel + * (Operatin Channel) of the device. + * + ****************************************************************************/ + +void xbee_set_chan(FAR struct xbee_priv_s *priv, uint8_t chan); + +/**************************************************************************** + * Name: xbee_set_epassocflags + * + * Description: + * Set flags in 'A1' command register to determine how endpoint behaves + * with regards to association. + * + ****************************************************************************/ + +void xbee_set_epassocflags(FAR struct xbee_priv_s *priv, uint8_t flags); + +/**************************************************************************** + * Name: xbee_set_coordassocflags + * + * Description: + * Set flags in 'AT' command register to determine how coordinator behaves + * with regards to association. + * + ****************************************************************************/ + +void xbee_set_coordassocflags(FAR struct xbee_priv_s *priv, uint8_t flags); + +/**************************************************************************** + * Name: xbee_set_sleepperiod + * + * Description: + * Set Cyclic Sleep Period using 'SP' AT command. + * + ****************************************************************************/ + +void xbee_set_sleepperiod(FAR struct xbee_priv_s *priv, uint16_t period); + +/**************************************************************************** + * Name: xbee_enable_coord + * + * Description: + * Enables/Disables coordinator mode using 'CE' command + * + ****************************************************************************/ + +void xbee_enable_coord(FAR struct xbee_priv_s *priv, bool enable); + +/**************************************************************************** + * Name: xbee_regdump + * + * Description: + * Perform a series of queries updating struct and printing settings to SYSLOG. + * + ****************************************************************************/ + +void xbee_regdump(FAR struct xbee_priv_s *priv); + +#endif /* __DRIVERS_WIRELESS_IEEE802154_XBEE_H */ diff --git a/drivers/wireless/ieee802154/xbee/xbee_dataind.c b/drivers/wireless/ieee802154/xbee/xbee_dataind.c new file mode 100644 index 0000000000..fe2c155263 --- /dev/null +++ b/drivers/wireless/ieee802154/xbee/xbee_dataind.c @@ -0,0 +1,202 @@ +/**************************************************************************** + * drivers/wireless/ieee802154/xbee/xbee_dataind.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 "xbee.h" +#include "xbee_mac.h" +#include "xbee_notif.h" + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: xbee_dataind_free + * + * Description: + * When the XBee driver calls the registered rxframe function, it passes a + * reference to a ieee802154_data_ind_s structure. This structure needs to be + * freed after the handler is done using it. + * + ****************************************************************************/ + +void xbee_dataind_free(XBEEHANDLE xbee, FAR struct ieee802154_data_ind_s *dataind) +{ + FAR struct xbee_priv_s *priv = (FAR struct xbee_priv_s *)xbee; + FAR struct xbee_dataind_s *privind = (FAR struct xbee_dataind_s *)dataind; + + xbee_lock(priv, false); + + privind->flink = priv->dataind_free; + priv->dataind_free = privind; + + xbee_givesem(&priv->dataind_sem); + + xbee_unlock(priv); +} + +/**************************************************************************** + * Name: xbee_datatindpool_init + * + * Description: + * This function initializes the data indication structure pool. It allows the + * XBee driver to pass received frames with meta data to the callee, where they + * can free them when the calle is done using them, saving copying the data + * when passing. + * + ****************************************************************************/ + +void xbee_dataindpool_init(FAR struct xbee_priv_s *priv) +{ + FAR struct xbee_dataind_s *pool = priv->dataind_pool; + int remaining = CONFIG_XBEE_NDATAIND; + + priv->dataind_free = NULL; + while (remaining > 0) + { + FAR struct xbee_dataind_s *dataind = pool; + + /* Add the next meta data structure from the pool to the list of + * general structures. + */ + + dataind->flink = priv->dataind_free; + priv->dataind_free = dataind; + + /* Set up for the next structure from the pool */ + + pool++; + remaining--; + } + + sem_init(&priv->dataind_sem, 0, CONFIG_XBEE_NDATAIND); +} + +/**************************************************************************** + * Name: xbee_dataind_alloc + * + * Description: + * This function allocates a free data indication structure from the free list + * to be used for passing to the registered rxframe callback. The callee software + * is responsible for freeing the data indication structure after it is done using + * it via xbee_data_ind_sfree. + * + * Assumptions: + * priv XBee struct is locked when calling. + * + * Notes: + * If any of the semaphore waits inside this function get interrupted, the + * function will release the MAC layer. If this function returns -EINTR, the + * calling code should NOT release the MAC semaphore. + * + ****************************************************************************/ + +int xbee_dataind_alloc(FAR struct xbee_priv_s *priv, + FAR struct ieee802154_data_ind_s **dataind, + bool allow_interrupt) +{ + int ret; + FAR struct xbee_dataind_s *privind; + + /* Try and take a count from the semaphore. If this succeeds, we have + * "reserved" the structure, but still need to unlink it from the free list. + * The MAC is already locked, so there shouldn't be any other conflicting calls + */ + + ret = sem_trywait(&priv->dataind_sem); + + if (ret == OK) + { + privind = priv->dataind_free; + priv->dataind_free = privind->flink; + } + else + { + wlinfo("waiting for dataind to be free\n"); + + /* Unlock XBee driver so that other work can be done to free a data indication */ + + xbee_unlock(priv); + + /* Take a count from the indication semaphore, waiting if necessary. We + * only return from here with an error if we are allowing interruptions + * and we received a signal */ + + ret = xbee_takesem(&priv->dataind_sem, allow_interrupt); + if (ret < 0) + { + /* MAC sem is already released */ + + return -EINTR; + } + + /* If we've taken a count from the semaphore, we have "reserved" the struct + * but now we need to pop it off of the free list. We need to re-lock the + * MAC in order to ensure this happens correctly. + */ + + ret = xbee_lock(priv, allow_interrupt); + if (ret < 0) + { + xbee_givesem(&priv->dataind_sem); + return -EINTR; + } + + /* We can now safely unlink the next free structure from the free list */ + + privind = priv->dataind_free; + priv->dataind_free = privind->flink; + + wlinfo("dataind allocated\n"); + } + + *dataind = (FAR struct ieee802154_data_ind_s *)privind; + + return OK; +} diff --git a/drivers/wireless/ieee802154/xbee/xbee_dataind.h b/drivers/wireless/ieee802154/xbee/xbee_dataind.h new file mode 100644 index 0000000000..074f646f76 --- /dev/null +++ b/drivers/wireless/ieee802154/xbee/xbee_dataind.h @@ -0,0 +1,77 @@ +/**************************************************************************** + * drivers/wireless/ieee802154/xbee/xbee_dataind.h + * + * Copyright (C) 2017 Verge Inc. All rights reserved. + * + * Author: Anthony Merlino + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +#ifndef __DRIVERS_WIRELESS_IEEE802154_XBEE_DATAIND_H +#define __DRIVERS_WIRELESS_IEEE802154_XBEE_DATAIND_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include + +#include + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/* Extend the public ieee802154_data_ind_s to include a private forward link to + * support a list to handle allocation + */ + +struct xbee_dataind_s +{ + struct ieee802154_data_ind_s pub; /* Publically visible structure */ + FAR struct xbee_dataind_s *flink; /* Supports a singly linked list */ +}; + +/**************************************************************************** + * Function Prototypes + ****************************************************************************/ + +struct xbee_priv_s; /* Forward Reference */ + +void xbee_dataindpool_init(FAR struct xbee_priv_s *priv); + +int xbee_dataind_alloc(FAR struct xbee_priv_s *priv, + FAR struct ieee802154_data_ind_s **dataind, + bool allow_interrupt); + +#endif /* __DRIVERS_WIRELESS_IEEE802154_XBEE_DATAIND_H */ \ No newline at end of file diff --git a/drivers/wireless/ieee802154/xbee/xbee_ioctl.c b/drivers/wireless/ieee802154/xbee/xbee_ioctl.c new file mode 100644 index 0000000000..0f744a417b --- /dev/null +++ b/drivers/wireless/ieee802154/xbee/xbee_ioctl.c @@ -0,0 +1,179 @@ +/**************************************************************************** + * drivers/wireless/xbee/drivers/xbee_ioctl.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 + * + 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 + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: xbee_ioctl + * + * Description: + * Handle MAC and radio IOCTL commands directed to the MAC. + * + * Parameters: + * mac - Reference to the XBee driver state structure + * cmd - The IOCTL command + * arg - The argument for the IOCTL command + * + * Returned Value: + * OK on success; Negated errno on failure. + * + ****************************************************************************/ + +int xbee_ioctl(XBEEHANDLE xbee, int cmd, unsigned long arg) +{ + int ret = -EINVAL; + + FAR union ieee802154_macarg_u *macarg = + (FAR union ieee802154_macarg_u *)((uintptr_t)arg); + + DEBUGASSERT(xbee != 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_GET_REQUEST: + { + ret = xbee_req_get(xbee, macarg->getreq.attr, + &macarg->getreq.attrval); + } + break; + case MAC802154IOC_MLME_SET_REQUEST: + { + ret = xbee_req_set(xbee, macarg->setreq.attr, + &macarg->setreq.attrval); + } + break; + case MAC802154IOC_MLME_START_REQUEST: + { + ret = xbee_req_start(xbee, &macarg->startreq); + } + break; + case MAC802154IOC_MLME_ASSOC_REQUEST: + { + ret = xbee_req_associate(xbee, &macarg->assocreq); + } + break; + case MAC802154IOC_MLME_RESET_REQUEST: + { + ret = xbee_req_reset(xbee, macarg->resetreq.resetattr); + } + break; +#if 0 + case MAC802154IOC_MLME_ASSOC_RESPONSE: + { + ret = xbee_resp_associate(xbee, &macarg->assocresp); + } + break; + case MAC802154IOC_MLME_DISASSOC_REQUEST: + { + ret = xbee_req_disassociate(xbee, &macarg->disassocreq); + } + break; + + case MAC802154IOC_MLME_RXENABLE_REQUEST: + { + ret = xbee_req_rxenable(xbee, &macarg->rxenabreq); + } + break; + case MAC802154IOC_MLME_SCAN_REQUEST: + { + ret = xbee_req_scan(xbee, &macarg->scanreq); + } + break; + + + case MAC802154IOC_MLME_POLL_REQUEST: + { + ret = xbee_req_poll(xbee, &macarg->pollreq); + } + break; +#endif + default: + wlerr("ERROR: Unrecognized cmd: %d\n", cmd); + ret = -ENOTTY; + break; + } + } + return ret; +} diff --git a/drivers/wireless/ieee802154/xbee/xbee_mac.c b/drivers/wireless/ieee802154/xbee/xbee_mac.c new file mode 100644 index 0000000000..b4e092e22e --- /dev/null +++ b/drivers/wireless/ieee802154/xbee/xbee_mac.c @@ -0,0 +1,601 @@ +/**************************************************************************** + * drivers/wireless/xbee/drivers/xbee_mac.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 "xbee.h" +#include "xbee_mac.h" + +#include +#include + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#define XBEE_ASSOC_POLLDELAY 100 + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +static void xbee_assoctimer(int argc, uint32_t arg, ...); +static void xbee_assocworker(FAR void *arg); + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: xbee_assoctimer + * + * Description: + * This function is used to schedule * an associatioin indication poll. When + * association first gets triggered, a watchdog timer is started. This function + * is called when it expires. The watchdog timer is scheduled again until + * the association is either successful or fails. + * + * Parameters: + * argc - The number of available arguments + * arg - The first argument + * + * Returned Value: + * None + * + * Assumptions: + * + ****************************************************************************/ + +static void xbee_assoctimer(int argc, uint32_t arg, ...) +{ + FAR struct xbee_priv_s *priv = (FAR struct xbee_priv_s *)arg; + int ret; + + /* In complex environments, we cannot do SPI transfers from the timout + * 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(priv && work_available(&priv->assocwork)); + + /* Notice that poll watchdog is not active so further poll timeouts can + * occur until we restart the poll timeout watchdog. + */ + + ret = work_queue(HPWORK, &priv->assocwork, xbee_assocworker, (FAR void *)priv, 0); + (void)ret; + DEBUGASSERT(ret == OK); +} + +/**************************************************************************** + * Name: xbee_assocworker + * + * Description: + * Poll the device for the assosciation status. This function is indirectly + * scheduled rom xbee_req_associate in order to poll the device for association + * progress. + * + * Parameters: + * arg - The reference to the driver structure (cast to void*) + * + * Returned Value: + * None + * + * Assumptions: + * + ****************************************************************************/ + +static void xbee_assocworker(FAR void *arg) +{ + FAR struct xbee_priv_s *priv = (FAR struct xbee_priv_s *)arg; + + xbee_at_query(priv, "AI"); + + (void)wd_start(priv->assocwd, XBEE_ASSOC_POLLDELAY, xbee_assoctimer, 1, (wdparm_t)arg); +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: xbee_bind + * + * Description: + * Bind the MAC callback table to the XBee driver. + * + * Parameters: + * xbee - Reference to the XBee driver structure + * cb - MAC callback operations + * + * Returned Value: + * OK on success; Negated errno on failure. + * + ****************************************************************************/ + +int xbee_bind(XBEEHANDLE xbee, FAR struct xbee_maccb_s *cb) +{ + FAR struct xbee_priv_s *priv = (FAR struct xbee_priv_s *)xbee; + FAR struct xbee_maccb_s *next; + FAR struct xbee_maccb_s *prev; + + /* Add the MAC client callback structure to the list of MAC callbacks in + * priority order. + * + * Search the list to find the location to insert the new instance. + * The list is maintained in descending priority order. + */ + + for (prev = NULL, next = priv->cb; + (next != NULL && cb->prio <= next->prio); + prev = next, next = next->flink); + + /* Add the instance to the spot found in the list. Check if the instance + * goes at the head of the list. + */ + + if (prev == NULL) + { + cb->flink = priv->cb; /* May be NULL */ + priv->cb = cb; + } + + /* No.. the instance goes between prev and next */ + + else + { + cb->flink = next; /* May be NULL */ + prev->flink = cb; + } + + /* Keep track of the number of clients requesting notification */ + + if (cb->notify != NULL) + { + priv->nclients++; + } + + return OK; +} + +/**************************************************************************** + * Name: xbee_get_mhrlen + * + * Description: + * Calculate the MAC header length given the frame meta-data. For the XBee, + * we use the header to store the entire API frame for the TX request. The + * size we need is fixed based on the address mode we are using as it changes + * which API frame we need to issue. + * + ****************************************************************************/ + +int xbee_get_mhrlen(XBEEHANDLE xbee, FAR const struct ieee802154_frame_meta_s *meta) +{ + int ret = 9; /* Smallest possible header size */ + + /* We assume that the XBee is configured with application header on but + * encryption not on. + */ + + ret += 2; + + if (meta->srcmode == IEEE802154_ADDRMODE_EXTENDED) + { + ret += 6; + } + + if (meta->destaddr.mode == IEEE802154_ADDRMODE_EXTENDED) + { + ret += 6; + } + + return ret; +} + +/**************************************************************************** + * Name: xbee_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. + * + ****************************************************************************/ + +int xbee_req_data(XBEEHANDLE xbee, + FAR const struct ieee802154_frame_meta_s *meta, + FAR struct iob_s *frame) +{ + FAR struct xbee_priv_s *priv = (FAR struct xbee_priv_s *)xbee; + int index; + uint16_t apiframelen; + uint8_t frametype; + + int prevoffs = frame->io_offset; + + /* Figure out how much room we need to place the API frame header */ + + if (meta->destaddr.mode == IEEE802154_ADDRMODE_EXTENDED) + { + DEBUGASSERT(frame->io_offset >= 14); + frame->io_offset -= 14; + frametype = XBEE_APIFRAME_TXREQ_EADDR; + } + else if (meta->destaddr.mode == IEEE802154_ADDRMODE_SHORT) + { + DEBUGASSERT(frame->io_offset >= 8); + frame->io_offset -= 8; + frametype = XBEE_APIFRAME_TXREQ_SADDR; + } + else + { + return -EINVAL; + } + + index = frame->io_offset; + apiframelen = (frame->io_len - frame->io_offset - 3); + + frame->io_data[index++] = XBEE_STARTBYTE; + frame->io_data[index++] = ((apiframelen >> 8) & 0xFF); + frame->io_data[index++] = (apiframelen & 0xFF); + frame->io_data[index++] = frametype; + frame->io_data[index++] = xbee_next_frameid(priv); + + if (meta->destaddr.mode == IEEE802154_ADDRMODE_EXTENDED) + { + frame->io_data[index++] = meta->destaddr.eaddr[7]; + frame->io_data[index++] = meta->destaddr.eaddr[6]; + frame->io_data[index++] = meta->destaddr.eaddr[5]; + frame->io_data[index++] = meta->destaddr.eaddr[4]; + frame->io_data[index++] = meta->destaddr.eaddr[3]; + frame->io_data[index++] = meta->destaddr.eaddr[2]; + frame->io_data[index++] = meta->destaddr.eaddr[1]; + frame->io_data[index++] = meta->destaddr.eaddr[0]; + } + else + { + frame->io_data[index++] = meta->destaddr.saddr[1]; + frame->io_data[index++] = meta->destaddr.saddr[0]; + } + + frame->io_data[index++] = 0; /* Options byte. Currently we do not support anything here */ + + DEBUGASSERT(index == prevoffs); + + /* Increment io_len by 1 to account for checksum */ + + frame->io_len++; + xbee_insert_checksum(&frame->io_data[frame->io_offset], + (frame->io_len - frame->io_offset)); + + xbee_send_apiframe(priv, &frame->io_data[frame->io_offset], + (frame->io_len - frame->io_offset)); + + iob_free(frame); + return OK; +} + +/**************************************************************************** + * Name: xbee_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 xbee_req_get(XBEEHANDLE xbee, enum ieee802154_attr_e attr, + FAR union ieee802154_attr_u *attrval) +{ + FAR struct xbee_priv_s *priv = (FAR struct xbee_priv_s *)xbee; + int ret = IEEE802154_STATUS_SUCCESS; + + switch (attr) + { + case IEEE802154_ATTR_MAC_PANID: + { + xbee_query_panid(priv); + IEEE802154_PANIDCOPY(attrval->mac.panid, priv->addr.panid); + } + break; + + case IEEE802154_ATTR_MAC_SADDR: + { + xbee_query_saddr(priv); + IEEE802154_SADDRCOPY(attrval->mac.saddr, priv->addr.saddr); + } + break; + + case IEEE802154_ATTR_MAC_EADDR: + { + xbee_query_eaddr(priv); + IEEE802154_EADDRCOPY(attrval->mac.eaddr, priv->addr.eaddr); + } + break; + + case IEEE802154_ATTR_MAC_COORD_SADDR: + { + IEEE802154_SADDRCOPY(attrval->mac.coordsaddr, priv->pandesc.coordaddr.saddr); + } + break; + + case IEEE802154_ATTR_MAC_COORD_EADDR: + { + IEEE802154_EADDRCOPY(attrval->mac.coordeaddr, priv->pandesc.coordaddr.eaddr); + } + break; + + case IEEE802154_ATTR_MAC_DEVMODE: + { + attrval->mac.devmode = priv->devmode; + } + break; + + case IEEE802154_ATTR_PHY_CHAN: + { + xbee_query_chan(priv); + attrval->phy.chan = priv->chan; + } + break; + + case IEEE802154_ATTR_RADIO_REGDUMP: + { + xbee_regdump(priv); + } + break; + + default: + { + wlwarn("Unsupported attribute\n"); + ret = IEEE802154_STATUS_UNSUPPORTED_ATTRIBUTE; + } + break; + } + + return ret; +} + +/**************************************************************************** + * Name: xbee_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 xbee_req_set(XBEEHANDLE xbee, enum ieee802154_attr_e attr, + FAR const union ieee802154_attr_u *attrval) +{ + FAR struct xbee_priv_s *priv = (FAR struct xbee_priv_s *)xbee; + int ret = IEEE802154_STATUS_SUCCESS; + + switch (attr) + { + case IEEE802154_ATTR_MAC_PANID: + { + xbee_set_panid(priv, attrval->mac.panid); + } + break; + case IEEE802154_ATTR_MAC_EADDR: + { + ret = IEEE802154_STATUS_DENIED; + } + break; + case IEEE802154_ATTR_MAC_SADDR: + { + xbee_set_saddr(priv, attrval->mac.saddr); + } + break; + case IEEE802154_ATTR_PHY_CHAN: + { + xbee_set_chan(priv, attrval->phy.chan); + } + break; + case IEEE802154_ATTR_MAC_ASSOCIATION_PERMIT: + { + if (attrval->mac.assocpermit) + { + xbee_set_coordassocflags(priv, XBEE_COORDASSOCFLAGS_ALLOWASSOC); + } + else + { + xbee_set_coordassocflags(priv, 0); + } + } + break; +#if 0 + case IEEE802154_ATTR_MAC_COORD_SADDR: + { + xbee_set_coordsaddr(priv, attrval->mac.coordsaddr); + } + break; + case IEEE802154_ATTR_MAC_COORD_EADDR: + { + xbee_set_coordeaddr(priv, attrval->mac.coordeaddr); + } + break; + case IEEE802154_ATTR_MAC_RESPONSE_WAIT_TIME: + { + priv->resp_waittime = attrval->mac.resp_waittime; + } + case IEEE802154_ATTR_MAC_RX_ON_WHEN_IDLE: + { + xbee_setrxonidle(priv, attrval->mac.rxonidle); + } +#endif + default: + { + wlwarn("Unsupported attribute\n"); + ret = IEEE802154_STATUS_UNSUPPORTED_ATTRIBUTE; + } + break; + } + + return ret; +} + +/**************************************************************************** + * Name: xbee_req_start + * + * Description: + * The MLME-START.request primitive makes a request for the device to start + * acting as a coordinator. The XBee modules do not support beacon-enabled + * networking! + * + ****************************************************************************/ + +int xbee_req_start(XBEEHANDLE xbee, FAR struct ieee802154_start_req_s *req) +{ + FAR struct xbee_priv_s *priv = (FAR struct xbee_priv_s *)xbee; + + if (req->beaconorder != 15) + { + wlwarn("xbee: beacon-enabled networks not supported\n"); + return -EINVAL; + } + + xbee_set_panid(priv, req->panid); + xbee_set_chan(priv, req->chan); + + xbee_enable_coord(priv, true); + xbee_set_sleepperiod(priv, 0); + + return OK; +} + +/**************************************************************************** + * Name: xbee_req_associate + * + * Description: + * The MLME-ASSOCIATE.request primitive allows a device to request an + * association with a coordinator. + * + * On receipt of the MLME-ASSOCIATE.request primitive, the MLME of an + * unassociated device first updates the appropriate PHY and MAC PIB + * attributes, as described in 5.1.3.1, and then generates an association + * request command, as defined in 5.3.1 [1] pg.80 + * + ****************************************************************************/ + +int xbee_req_associate(XBEEHANDLE xbee, FAR struct ieee802154_assoc_req_s *req) +{ + FAR struct xbee_priv_s *priv = (FAR struct xbee_priv_s *)xbee; + + if (req->coordaddr.mode == IEEE802154_ADDRMODE_NONE) + { + return -EINVAL; + } + + xbee_enable_coord(priv, false); + + xbee_set_panid(priv, req->coordaddr.panid); + xbee_set_chan(priv, req->chan); + + xbee_set_epassocflags(priv, XBEE_EPASSOCFLAGS_AUTOASSOC); + + /* In order to track the association status, we must poll the device for + * an update. + */ + + return wd_start(priv->assocwd, XBEE_ASSOC_POLLDELAY, xbee_assoctimer, 1, (wdparm_t)priv); +} + +/**************************************************************************** + * Name: xbee_req_reset + * + * Description: + * The MLME-RESET.request primitive allows the next higher layer to request + * that the MLME performs a reset operation. + * + * Input Parameters: + * xbee - Handle to the XBee instance + * resetattr - Whether or not to reset the MAC PIB attributes to defaults + * + ****************************************************************************/ + +int xbee_req_reset(XBEEHANDLE xbee, bool resetattr) +{ + FAR struct xbee_priv_s *priv = (FAR struct xbee_priv_s *)xbee; + + /* Reset the XBee radio */ + + priv->lower->reset(priv->lower); + + if (resetattr) + { + xbee_set_panid(priv, IEEE802154_PANID_UNSPEC); + xbee_set_saddr(priv, IEEE802154_SADDR_UNSPEC); + xbee_enable_coord(priv, false); + xbee_set_epassocflags(priv, 0); + xbee_set_coordassocflags(priv, 0); + } + + return OK; +} diff --git a/drivers/wireless/ieee802154/xbee/xbee_mac.h b/drivers/wireless/ieee802154/xbee/xbee_mac.h new file mode 100644 index 0000000000..6da504f117 --- /dev/null +++ b/drivers/wireless/ieee802154/xbee/xbee_mac.h @@ -0,0 +1,262 @@ +/**************************************************************************** + * drivers/wireless/ieee802154/xbee/xbee_mac.h + * + * Copyright (C) 2017 Verge Inc. All rights reserved. + * Author: Anthony Merlino + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +#ifndef __DRIVERS_WIRELESS_IEEE802154_XBEE_MAC_H +#define __DRIVERS_WIRELESS_IEEE802154_XBEE_MAC_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include +#include + +#include +#include + +#include +#include + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/**************************************************************************** + * Public Types + ****************************************************************************/ + +/* 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 xbee_maccb_s +{ + FAR struct xbee_maccb_s *flink; /* Implements a singly linked list */ + uint8_t prio; /* RX frame callback priority */ + + /* Callback methods */ + + CODE void (*notify)(FAR struct xbee_maccb_s *maccb, + FAR struct ieee802154_notif_s *notif); + CODE int (*rxframe)(FAR struct xbee_maccb_s *maccb, + FAR struct ieee802154_data_ind_s *ind); +}; + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +/**************************************************************************** + * Inline Functions + ****************************************************************************/ + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + + /**************************************************************************** + * Name: xbee_bind + * + * Description: + * Bind the XBee callback table to the MAC state. + * + * Parameters: + * xbee - Reference to the XBee driver state structure + * cb - XBee callback operations + * + * Returned Value: + * OK on success; Negated errno on failure. + * + ****************************************************************************/ + +int xbee_bind(XBEEHANDLE xbee, FAR struct xbee_maccb_s *cb); + +/**************************************************************************** + * Name: xbee_ioctl + * + * Description: + * Handle MAC and radio IOCTL commands directed to the XBee device. + * + * Parameters: + * mac - Reference to the Xbee driver state structure + * cmd - The IOCTL command + * arg - The argument for the IOCTL command + * + * Returned Value: + * OK on success; Negated errno on failure. + * + ****************************************************************************/ + +int xbee_ioctl(XBEEHANDLE xbee, int cmd, unsigned long arg); + +/**************************************************************************** + * MAC Interface Operations + ****************************************************************************/ + +/**************************************************************************** + * Name: xbee_get_mhrlen + * + * Description: + * Calculate the MAC header length given the frame meta-data. For the XBee, + * we use the header to store the entire API frame for the TX request. The + * size we need is fixed based on the address mode we are using as it changes + * which API frame we need to issue. + * + ****************************************************************************/ + +int xbee_get_mhrlen(XBEEHANDLE xbee, FAR const struct ieee802154_frame_meta_s *meta); + +/**************************************************************************** + * Name: xbee_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 xbee_maccb_s->conf_data callback. + * + ****************************************************************************/ + +int xbee_req_data(XBEEHANDLE xbee, FAR const struct ieee802154_frame_meta_s *meta, + FAR struct iob_s *frame); + +/**************************************************************************** + * Name: xbee_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 xbee_req_get(XBEEHANDLE xbee, enum ieee802154_attr_e attr, + FAR union ieee802154_attr_u *attrval); + +/**************************************************************************** + * Name: xbee_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 xbee_req_set(XBEEHANDLE xbee, enum ieee802154_attr_e attr, + FAR const union ieee802154_attr_u *attrval); + +/**************************************************************************** + * Name: xbee_req_start + * + * Description: + * The MLME-START.request primitive makes a request for the device to start + * acting as a coordinator. The XBee modules do not support beacon-enabled + * networking! + * + ****************************************************************************/ + +int xbee_req_start(XBEEHANDLE xbee, FAR struct ieee802154_start_req_s *req); + +/**************************************************************************** + * Name: xbee_req_associate + * + * Description: + * The MLME-ASSOCIATE.request primitive allows a device to request an + * association with a coordinator. + * + * On receipt of the MLME-ASSOCIATE.request primitive, the MLME of an + * unassociated device first updates the appropriate PHY and MAC PIB + * attributes, as described in 5.1.3.1, and then generates an association + * request command, as defined in 5.3.1 [1] pg.80 + * + ****************************************************************************/ + +int xbee_req_associate(XBEEHANDLE xbee, FAR struct ieee802154_assoc_req_s *req); + +/**************************************************************************** + * Name: xbee_req_reset + * + * Description: + * The MLME-RESET.request primitive allows the next higher layer to request + * that the MLME performs a reset operation. + * + * Input Parameters: + * xbee - Handle to the XBee instance + * resetattr - Whether or not to reset the MAC PIB attributes to defaults + * + ****************************************************************************/ + +int xbee_req_reset(XBEEHANDLE xbee, bool resetattr); + +/**************************************************************************** + * Name: xbee_notif_free + * + * Description: + * When the XBee driver calls the registered callback, it passes a reference + * to a ieee802154_notif_s structure. This structure needs to be freed + * after the callback handler is done using it. + * + ****************************************************************************/ + +void xbee_notif_free(XBEEHANDLE mac, FAR struct ieee802154_notif_s *notif); + +/**************************************************************************** + * Name: xbee_dataind_free + * + * Description: + * When the XBee driver calls the registered callback, it passes a reference + * to a ieee802154_data_ind_s structure. This structure needs to be freed + * after the callback handler is done using it. + * + ****************************************************************************/ + +void xbee_dataind_free(XBEEHANDLE mac, FAR struct ieee802154_data_ind_s *dataind); + +#endif /* __DRIVERS_WIRELESS_IEEE802154_XBEE_MAC_H */ diff --git a/drivers/wireless/ieee802154/xbee/xbee_netdev.c b/drivers/wireless/ieee802154/xbee/xbee_netdev.c new file mode 100644 index 0000000000..7e0b30ce14 --- /dev/null +++ b/drivers/wireless/ieee802154/xbee/xbee_netdev.c @@ -0,0 +1,1521 @@ +/**************************************************************************** + * drivers/wireless/xbee/drivers/xbee_netdev.c + * + * Copyright (C) 2017 Verge Inc. All rights reserved. + * Author: Anthony Merlino + * + * References: + * + * wireless/ieee802154/xbee_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 +#include +#include + +#include "xbee_mac.h" + +#if defined(CONFIG_NET_6LOWPAN) || defined(CONFIG_NET_IEEE802154) + +/**************************************************************************** + * 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_XBEE_NETDEV_HPWORK) +# define XBEENET_WORK HPWORK +# elif defined(CONFIG_XBEE_NETDEV_LPWORK) +# define XBEENET_WORK LPWORK +# else +# error Neither CONFIG_XBEE_NETDEV_HPWORK nor CONFIG_XBEE_NETDEV_LPWORK defined +# endif +#endif + +/* Preferred address size */ + +#ifdef CONFIG_NET_6LOWPAN_EXTENDEDADDR +# define XBEENET_ADDRSIZE IEEE802154_EADDRSIZE +#else +# define XBEENET_ADDRSIZE IEEE802154_SADDRSIZE +#endif + +/* Frame size */ + +#if defined(CONFIG_NET_IEEE802154_FRAMELEN) +# define XBEENET_FRAMELEN CONFIG_NET_IEEE802154_FRAMELEN +#else +# define XBEENET_FRAMELEN IEEE802154_MAX_PHY_PACKET_SIZE +#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 xbeenet_callback_s +{ + /* This holds the information visible to the MAC layer */ + + struct xbee_maccb_s mc_cb; /* Interface understood by the MAC layer */ + FAR struct xbeenet_driver_s *mc_priv; /* Our priv data */ +}; + +/* The xbeenet_driver_s encapsulates all state information for a single + * IEEE802.15.4 MAC interface. + */ + +struct xbeenet_driver_s +{ + /* This holds the information visible to the NuttX network */ + + struct radio_driver_s xd_dev; /* Interface understood by the network */ + /* Cast compatible with struct xbeenet_driver_s */ + + /* For internal use by this driver */ + + sem_t xd_exclsem; /* Exclusive access to struct */ + struct xbeenet_callback_s xd_cb; /* Callback information */ + XBEEHANDLE xd_mac; /* Contained XBee MAC interface */ + bool xd_bifup; /* true:ifup false:ifdown */ + WDOG_ID xd_txpoll; /* TX poll timer */ + struct work_s xd_pollwork; /* Defer poll work to the work queue */ + + /* Hold a list of events */ + + bool xd_enableevents : 1; /* Are events enabled? */ + bool xd_eventpending : 1; /* Is there a get event using the semaphore? */ + sem_t xd_eventsem; /* Signaling semaphore for waiting get event */ + FAR struct ieee802154_notif_s *xd_eventhead; + FAR struct ieee802154_notif_s *xd_eventtail; + +#ifndef CONFIG_DISABLE_SIGNALS + /* MAC Service notification information */ + + bool xd_notify_registered; + uint8_t xd_notify_signo; + pid_t xd_notify_pid; +#endif +}; + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +/* Utility functions ********************************************************/ + +static int xbeenet_set_ipaddress(FAR struct net_driver_s *dev); +static inline void xbeenet_netmask(FAR struct net_driver_s *dev); + +static inline void xbeenet_pushevent(FAR struct xbeenet_driver_s *priv, + FAR struct ieee802154_notif_s *notif); +static inline FAR struct ieee802154_notif_s * + xbeenet_popevent(FAR struct xbeenet_driver_s *priv); + + +/* IEE802.15.4 MAC callback functions ***************************************/ + +static void xbeenet_notify(FAR struct xbee_maccb_s *maccb, + FAR struct ieee802154_notif_s *notif); +static int xbeenet_rxframe(FAR struct xbee_maccb_s *maccb, + FAR struct ieee802154_data_ind_s *ind); + +/* Asynchronous event indications, replied to synchronously with responses. + * (none are implemented). + */ + +/* Network interface support ************************************************/ +/* Common TX logic */ + +static int xbeenet_txpoll_callback(FAR struct net_driver_s *dev); +static void xbeenet_txpoll_work(FAR void *arg); +static void xbeenet_txpoll_expiry(int argc, wdparm_t arg, ...); + +/* IOCTL support */ + +#ifdef CONFIG_NET_STARPOINT +#ifdef CONFIG_NET_6LOWPAN_EXTENDEDADDR +static int xbeenet_coord_eaddr(FAR struct radio_driver_s *radio, + FAR uint8_t *eaddr); +#else +static int xbeenet_coord_saddr(FAR struct radio_driver_s *radio, + FAR uint8_t *saddr); +#endif +#endif + +/* NuttX callback functions */ + +static int xbeenet_ifup(FAR struct net_driver_s *dev); +static int xbeenet_ifdown(FAR struct net_driver_s *dev); + +static void xbeenet_txavail_work(FAR void *arg); +static int xbeenet_txavail(FAR struct net_driver_s *dev); + +#ifdef CONFIG_NET_IGMP +static int xbeenet_addmac(FAR struct net_driver_s *dev, + FAR const uint8_t *mac); +static int xbeenet_rmmac(FAR struct net_driver_s *dev, + FAR const uint8_t *mac); +#endif +#ifdef CONFIG_NETDEV_IOCTL +static int xbeenet_ioctl(FAR struct net_driver_s *dev, int cmd, + unsigned long arg); +#endif +static int xbeenet_get_mhrlen(FAR struct radio_driver_s *netdev, + FAR const void *meta); +static int xbeenet_req_data(FAR struct radio_driver_s *netdev, + FAR const void *meta, FAR struct iob_s *framelist); +static int xbeenet_properties(FAR struct radio_driver_s *netdev, + FAR struct radiodev_properties_s *properties); + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +#ifdef CONFIG_NET_6LOWPAN +static struct sixlowpan_reassbuf_s g_iobuffer; +#endif + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** +* Name: xbeenet_set_ipaddress +* +* Description: +* Advertise the MAC and IPv6 address for this node. +* +* Creates a MAC-based IP address from the IEEE 802.15.14 short or extended +* address assigned to the node. +* +* 128 112 96 80 64 48 32 16 +* ---- ---- ---- ---- ---- ---- ---- ---- +* 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 +* +****************************************************************************/ + +static int xbeenet_set_ipaddress(FAR struct net_driver_s *dev) +{ + FAR struct xbeenet_driver_s *priv; + union ieee802154_macarg_u arg; + int ret; + +#ifdef CONFIG_NET_6LOWPAN_EXTENDEDADDR + uint8_t *eaddr; + + DEBUGASSERT(dev != NULL && dev->d_private != NULL); + priv = (FAR struct xbeenet_driver_s *)dev->d_private; + + /* Get the eaddr from the MAC */ + + arg.getreq.attr = IEEE802154_ATTR_MAC_EADDR; + ret = xbee_ioctl(priv->xd_mac, MAC802154IOC_MLME_GET_REQUEST, + (unsigned long)((uintptr_t)&arg)); + if (ret < 0) + { + wlerr("ERROR: MAC802154IOC_MLME_GET_REQUEST failed: %d\n", ret); + return ret; + } + else + { + /* Set the MAC address as the eaddr */ + + eaddr = arg.getreq.attrval.mac.eaddr; + IEEE802154_EADDRCOPY(dev->d_mac.radio.nv_addr, eaddr); + dev->d_mac.radio.nv_addrlen = IEEE802154_EADDRSIZE; + +#ifdef CONFIG_NET_IPv6 + /* Set the IP address based on the eaddr */ + + dev->d_ipv6addr[0] = HTONS(0xfe80); + dev->d_ipv6addr[1] = 0; + dev->d_ipv6addr[2] = 0; + dev->d_ipv6addr[3] = 0; + dev->d_ipv6addr[4] = (uint16_t)eaddr[0] << 8 | (uint16_t)eaddr[1]; + dev->d_ipv6addr[5] = (uint16_t)eaddr[2] << 8 | (uint16_t)eaddr[3]; + dev->d_ipv6addr[6] = (uint16_t)eaddr[4] << 8 | (uint16_t)eaddr[5]; + dev->d_ipv6addr[7] = (uint16_t)eaddr[6] << 8 | (uint16_t)eaddr[7]; + dev->d_ipv6addr[4] ^= 0x200; +#endif + return OK; + } + +#else + uint8_t *saddr; + + DEBUGASSERT(dev != NULL && dev->d_private != NULL); + priv = (FAR struct xbeenet_driver_s *)dev->d_private; + + /* Get the saddr from the MAC */ + + arg.getreq.attr = IEEE802154_ATTR_MAC_SADDR; + ret = xbee_ioctl(priv->xd_mac, MAC802154IOC_MLME_GET_REQUEST, + (unsigned long)((uintptr_t)&arg)); + if (ret < 0) + { + wlerr("ERROR: MAC802154IOC_MLME_GET_REQUEST failed: %d\n", ret); + return ret; + } + else + { + /* Set the MAC address as the saddr */ + + saddr = arg.getreq.attrval.mac.saddr; + IEEE802154_SADDRCOPY(dev->d_mac.radio.nv_addr, saddr); + dev->d_mac.radio.nv_addrlen = IEEE802154_SADDRSIZE; + +#ifdef CONFIG_NET_IPv6 + /* Set the IP address based on the saddr */ + + dev->d_ipv6addr[0] = HTONS(0xfe80); + dev->d_ipv6addr[1] = 0; + dev->d_ipv6addr[2] = 0; + dev->d_ipv6addr[3] = 0; + dev->d_ipv6addr[4] = 0; + dev->d_ipv6addr[5] = HTONS(0x00ff); + dev->d_ipv6addr[6] = HTONS(0xfe00); + dev->d_ipv6addr[7] = (uint16_t)saddr[0] << 8 | (uint16_t)saddr[1]; + dev->d_ipv6addr[7] ^= 0x200; +#endif + return OK; + } +#endif +} + +/**************************************************************************** + * Name: xbeenet_netmask + * + * Description: + * Create a netmask of a MAC-based IP address which may be based on either + * the IEEE 802.15.14 short or extended address of the MAC. + * + * 128 112 96 80 64 48 32 16 + * ---- ---- ---- ---- ---- ---- ---- ---- + * 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 + * + ****************************************************************************/ + +static inline void xbeenet_netmask(FAR struct net_driver_s *dev) +{ +#ifdef CONFIG_NET_IPv6 + dev->d_ipv6netmask[0] = 0xffff; + dev->d_ipv6netmask[1] = 0xffff; + dev->d_ipv6netmask[2] = 0xffff; + dev->d_ipv6netmask[3] = 0xffff; +#ifdef CONFIG_NET_6LOWPAN_EXTENDEDADDR + dev->d_ipv6netmask[4] = 0; + dev->d_ipv6netmask[5] = 0; + dev->d_ipv6netmask[6] = 0; + dev->d_ipv6netmask[7] = 0; +#else + dev->d_ipv6netmask[4] = 0xffff; + dev->d_ipv6netmask[5] = 0xffff; + dev->d_ipv6netmask[6] = 0xffff; + dev->d_ipv6netmask[7] = 0; +#endif +#endif +} + +/**************************************************************************** + * Name: xbeenet_pushevent + * + * Description: + * Push event onto the event queue + * + * Assumptions: + * Called with the device struct locked. + * + ****************************************************************************/ + +static inline void xbeenet_pushevent(FAR struct xbeenet_driver_s *priv, + FAR struct ieee802154_notif_s *notif) +{ + notif->flink = NULL; + if (!priv->xd_eventhead) + { + priv->xd_eventhead = notif; + priv->xd_eventtail = notif; + } + else + { + priv->xd_eventtail->flink = notif; + priv->xd_eventtail = notif; + } +} + +/**************************************************************************** + * Name: xbeenet_popevent + * + * Description: + * Pop an event off of the event queue + * + * Assumptions: + * Called with the device struct locked. + * + ****************************************************************************/ + +static inline FAR struct ieee802154_notif_s * + xbeenet_popevent(FAR struct xbeenet_driver_s *priv) +{ + FAR struct ieee802154_notif_s *notif = priv->xd_eventhead; + + if (notif) + { + priv->xd_eventhead = notif->flink; + if (!priv->xd_eventhead) + { + priv->xd_eventhead = NULL; + } + + notif->flink = NULL; + } + + return notif; +} + +/**************************************************************************** + * Name: xbeenet_notify + * + * Description: + * + ****************************************************************************/ + +static void xbeenet_notify(FAR struct xbee_maccb_s *maccb, + FAR struct ieee802154_notif_s *notif) +{ + FAR struct xbeenet_callback_s *cb = + (FAR struct xbeenet_callback_s *)maccb; + FAR struct xbeenet_driver_s *priv; + + DEBUGASSERT(cb != NULL && cb->mc_priv != NULL); + priv = cb->mc_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 (sem_wait(&priv->xd_exclsem) < 0); + + /* If there is a registered notification receiver, queue the event and signal + * the receiver. Events should be popped from the queue from the application + * at a reasonable rate in order for the MAC layer to be able to allocate new + * notifications. + */ + + if (priv->xd_enableevents) + { + xbeenet_pushevent(priv, notif); + + /* Check if there is a read waiting for data */ + + if (priv->xd_eventpending) + { + /* Wake the thread waiting for the data transmission */ + + priv->xd_eventpending = false; + sem_post(&priv->xd_eventsem); + } + +#ifndef CONFIG_DISABLE_SIGNALS + if (priv->xd_notify_registered) + { +#ifdef CONFIG_CAN_PASS_STRUCTS + union sigval value; + value.sival_int = (int)notif->notiftype; + (void)sigqueue(priv->xd_notify_pid, priv->xd_notify_signo, value); +#else + (void)sigqueue(priv->xd_notify_pid, priv->xd_notify_signo, + (FAR void *)notif->notiftype); +#endif + } +#endif + } + else + { + /* Just free the event if the driver is closed and there isn't a registered + * signal number. + */ + + xbee_notif_free(priv->xd_mac, notif); + } + + sem_post(&priv->xd_exclsem); +} + +/**************************************************************************** + * Name: xbeenet_rxframe + * + * Description: + * Handle received frames forward by the XBee MAC. + * + * Returned Value: + * Zero (OK) is returned on success; a negated errno value is returned on + * any failure. On success, the ind and its contained iob will be freed. + * The ind will be intact if this function returns a failure. + * + ****************************************************************************/ + +static int xbeenet_rxframe(FAR struct xbee_maccb_s *maccb, + FAR struct ieee802154_data_ind_s *ind) +{ + FAR struct xbeenet_callback_s *cb = + (FAR struct xbeenet_callback_s *)maccb; + FAR struct xbeenet_driver_s *priv; + FAR struct iob_s *iob; + int ret; + + DEBUGASSERT(cb != NULL && cb->mc_priv != NULL); + priv = cb->mc_priv; + + /* Ignore the frame if the network is not up */ + + if (!priv->xd_bifup) + { + wlwarn("WARNING: Dropped... Network is down\n"); + return -ENETDOWN; + } + + /* Peek the IOB contained the frame in the struct ieee802154_data_ind_s */ + + DEBUGASSERT(priv != NULL && ind != NULL && ind->frame != NULL); + iob = ind->frame; + + /* Remove the IOB containing the frame. */ + + ind->frame = NULL; + + /* Transfer the frame to the network logic */ + +#ifdef CONFIG_NET_IEEE802154 + /* Invoke the PF_IEEE802154 tap first. If the frame matches + * with a connected PF_IEEE802145 socket, it will take the + * frame and return success. + */ + + ret = ieee802154_input(&priv->xd_dev, iob, (FAR void *)ind); + if (ret < 0) +#endif +#ifdef CONFIG_NET_6LOWPAN + { + /* If the frame is not a 6LoWPAN frame, then return an error. The + * first byte following the MAC head at the io_offset should be a + * valid IPHC header. + */ + + if ((iob->io_data[iob->io_offset] & SIXLOWPAN_DISPATCH_NALP_MASK) == + SIXLOWPAN_DISPATCH_NALP) + { + wlwarn("WARNING: Dropped... Not a 6LoWPAN frame: %02x\n", + iob->io_data[iob->io_offset]); + ret = -EINVAL; + } + else + { + /* Make sure the our single packet buffer is attached */ + + priv->xd_dev.r_dev.d_buf = g_iobuffer.rb_buf; + + /* And give the packet to 6LoWPAN */ + + ret = sixlowpan_input(&priv->xd_dev, iob, (FAR void *)ind); + } + } + + if (ret < 0) +#endif + { + ind->frame = iob; + return ret; + } + + /* Increment statistics */ + + NETDEV_RXPACKETS(&priv->xd_dev.r_dev); + NETDEV_RXIPV6(&priv->xd_dev.r_dev); + + /* sixlowpan_input() will free the IOB, but we must free the struct + * ieee802154_data_ind_s container here. + */ + + xbee_dataind_free(priv->xd_mac, ind); + return OK; +} + +/**************************************************************************** + * Name: xbeenet_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 xbeenet_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: xbeenet_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 xbeenet_txpoll_work(FAR void *arg) +{ + FAR struct xbeenet_driver_s *priv = (FAR struct xbeenet_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(); + +#ifdef CONFIG_NET_6LOWPAN + /* Make sure the our single packet buffer is attached */ + + priv->xd_dev.r_dev.d_buf = g_iobuffer.rb_buf; +#endif + + /* Then perform the poll */ + + (void)devif_timer(&priv->xd_dev.r_dev, xbeenet_txpoll_callback); + + /* Setup the watchdog poll timer again */ + + (void)wd_start(priv->xd_txpoll, TXPOLL_WDDELAY, xbeenet_txpoll_expiry, 1, + (wdparm_t)priv); + net_unlock(); +} + +/**************************************************************************** + * Name: xbeenet_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 xbeenet_txpoll_expiry(int argc, wdparm_t arg, ...) +{ + FAR struct xbeenet_driver_s *priv = (FAR struct xbeenet_driver_s *)arg; + + /* Schedule to perform the interrupt processing on the worker thread. */ + + work_queue(XBEENET_WORK, &priv->xd_pollwork, xbeenet_txpoll_work, priv, 0); +} + +/**************************************************************************** + * Name: xbeenet_coord_eaddr + * + * Description: + * Get the extended address of the PAN coordinator. + * + * Input parameters: + * radio - Reference to a radio network driver state instance. + * eaddr - The location in which to return the extended address. + * + * Returned Value: + * Zero (OK) on success; a negated errno value on failure. + * + ****************************************************************************/ + +#if defined(CONFIG_NET_STARPOINT) && defined(CONFIG_NET_6LOWPAN_EXTENDEDADDR) +static int xbeenet_coord_eaddr(FAR struct radio_driver_s *radio, + FAR uint8_t *eaddr) +{ + FAR struct xbeenet_driver_s *priv = (FAR struct xbeenet_driver_s *)radio; + union ieee802154_macarg_u arg; + int ret; + + arg.getreq.attr = IEEE802154_ATTR_MAC_COORD_EADDR ; + ret = xbee_ioctl(priv->xd_mac, MAC802154IOC_MLME_GET_REQUEST, + (unsigned long)((uintptr_t)&arg)); + if (ret < 0) + { + nerr("ERROR: MAC802154IOC_MLME_GET_REQUEST failed: %d\n", ret); + return ret; + } + + IEEE802154_EADDRCOPY(eaddr, arg.getreq.attrval.mac.eaddr); + return OK; +} +#endif + +/**************************************************************************** + * Name: xbeenet_coord_saddr + * + * Description: + * Get the short address of the PAN coordinator. + * + * Input parameters: + * radio - Reference to a radio network driver state instance. + * saddr - The location in which to return the short address. + * + * Returned Value: + * Zero (OK) on success; a negated errno value on failure. + * + ****************************************************************************/ + +#if defined(CONFIG_NET_STARPOINT) && !defined(CONFIG_NET_6LOWPAN_EXTENDEDADDR) +static int xbeenet_coord_saddr(FAR struct radio_driver_s *radio, + FAR uint8_t *saddr) +{ + FAR struct xbeenet_driver_s *priv = (FAR struct xbeenet_driver_s *)radio; + union ieee802154_macarg_u arg; + int ret; + + arg.getreq.attr = IEEE802154_ATTR_MAC_COORD_SADDR ; + ret = xbee_ioctl(priv->xd_mac, MAC802154IOC_MLME_GET_REQUEST, + (unsigned long)((uintptr_t)&arg)); + if (ret < 0) + { + nerr("ERROR: MAC802154IOC_MLME_GET_REQUEST failed: %d\n", ret); + return ret; + } + + IEEE802154_SADDRCOPY(saddr, arg.getreq.attrval.mac.saddr); + return OK; +} +#endif + +/**************************************************************************** + * Name: xbeenet_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 xbeenet_ifup(FAR struct net_driver_s *dev) +{ + FAR struct xbeenet_driver_s *priv = + (FAR struct xbeenet_driver_s *)dev->d_private; + int ret; + + /* Set the IP address based on the addressing assigned to the node */ + + ret = xbeenet_set_ipaddress(dev); + if (ret >= 0) + { +#ifdef CONFIG_NET_IPv6 + wlinfo("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]); + +#ifdef CONFIG_NET_6LOWPAN_EXTENDEDADDR + wlinfo(" Node: %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n", + dev->d_mac.radio.nv_addr[0], dev->d_mac.radio.nv_addr[1], + dev->d_mac.radio.nv_addr[2], dev->d_mac.radio.nv_addr[3], + dev->d_mac.radio.nv_addr[4], dev->d_mac.radio.nv_addr[5], + dev->d_mac.radio.nv_addr[6], dev->d_mac.radio.nv_addr[7]); +#else + wlinfo(" Node: %02x:%02x\n", + dev->d_mac.radio.nv_addr[0], dev->d_mac.radio.nv_addr[1]); +#endif +#else + if (dev->d_mac.radio.nv_addrlen == 8) + { + ninfo("Bringing up: Node: %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x PANID=%02x:%02x\n", + dev->d_mac.radio.nv_addr[0], dev->d_mac.radio.nv_addr[1], + dev->d_mac.radio.nv_addr[2], dev->d_mac.radio.nv_addr[3], + dev->d_mac.radio.nv_addr[4], dev->d_mac.radio.nv_addr[5], + dev->d_mac.radio.nv_addr[6], dev->d_mac.radio.nv_addr[7], + priv->lo_panid[0], priv->lo_panid[1]); + } + else if (dev->d_mac.radio.nv_addrlen == 2) + { + ninfo("Bringing up: Node: %02x:%02x PANID=%02x:%02x\n", + dev->d_mac.radio.nv_addr[0], dev->d_mac.radio.nv_addr[1], + priv->lo_panid[0], priv->lo_panid[1]); + } + else + { + nerr("ERROR: No address assigned\n"); + } +#endif + + /* Set and activate a timer process */ + + (void)wd_start(priv->xd_txpoll, TXPOLL_WDDELAY, xbeenet_txpoll_expiry, + 1, (wdparm_t)priv); + + /* The interface is now up */ + + priv->xd_bifup = true; + ret = OK; + } + + return ret; +} + +/**************************************************************************** + * Name: xbeenet_ifdown + * + * Description: + * NuttX Callback: Stop the interface. + * + * Parameters: + * dev - Reference to the NuttX driver state structure + * + * Returned Value: + * None + * + * Assumptions: + * + ****************************************************************************/ + +static int xbeenet_ifdown(FAR struct net_driver_s *dev) +{ + FAR struct xbeenet_driver_s *priv = (FAR struct xbeenet_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->xd_txpoll); + + /* TODO: Put the xbee driver in its reset, non-operational state. This should be + * a known configuration that will guarantee the xbeenet_ifup() always + * successfully brings the interface back up. + */ + + /* Mark the device "down" */ + + priv->xd_bifup = false; + leave_critical_section(flags); + return OK; +} + +/**************************************************************************** + * Name: xbeenet_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 xbeenet_txavail_work(FAR void *arg) +{ + FAR struct xbeenet_driver_s *priv = (FAR struct xbeenet_driver_s *)arg; + + wlinfo("ifup=%u\n", priv->xd_bifup); + + /* 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->xd_bifup) + { +#ifdef CONFIG_NET_6LOWPAN + /* Make sure the our single packet buffer is attached */ + + priv->xd_dev.r_dev.d_buf = g_iobuffer.rb_buf; +#endif + + /* Then poll the network for new XMIT data */ + + (void)devif_poll(&priv->xd_dev.r_dev, xbeenet_txpoll_callback); + } + + net_unlock(); +} + +/**************************************************************************** + * Name: xbeenet_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 xbeenet_txavail(FAR struct net_driver_s *dev) +{ + FAR struct xbeenet_driver_s *priv = (FAR struct xbeenet_driver_s *)dev->d_private; + + wlinfo("Available=%u\n", work_available(&priv->xd_pollwork)); + + /* 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->xd_pollwork)) + { + /* Schedule to serialize the poll on the worker thread. */ + + work_queue(XBEENET_WORK, &priv->xd_pollwork, xbeenet_txavail_work, priv, 0); + } + + return OK; +} + +/**************************************************************************** + * Name: xbeenet_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: + * + ****************************************************************************/ + +#ifdef CONFIG_NET_IGMP +static int xbeenet_addmac(FAR struct net_driver_s *dev, FAR const uint8_t *mac) +{ + FAR struct xbeenet_driver_s *priv = (FAR struct xbeenet_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: xbeenet_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 xbeenet_rmmac(FAR struct net_driver_s *dev, FAR const uint8_t *mac) +{ + FAR struct xbeenet_driver_s *priv = (FAR struct xbeenet_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: xbeenet_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 xbeenet_ioctl(FAR struct net_driver_s *dev, int cmd, + unsigned long arg) +{ + FAR struct xbeenet_driver_s *priv = (FAR struct xbeenet_driver_s *)dev->d_private; + int ret = -EINVAL; + + ret = sem_wait(&priv->xd_exclsem); + if (ret < 0) + { + wlerr("ERROR: sem_wait failed: %d\n", ret); + return ret; + } + + /* 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); + + switch (cmd) + { + #ifndef CONFIG_DISABLE_SIGNALS + /* Command: MAC802154IOC_NOTIFY_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 + * xbeenet_notify_s + * Return: Zero (OK) on success. Minus one will be returned on + * failure with the errno value set appropriately. + */ + + case MAC802154IOC_NOTIFY_REGISTER: + { + /* Save the notification events */ + + priv->xd_notify_signo = netmac->u.signo; + priv->xd_notify_pid = getpid(); + priv->xd_notify_registered = true; + ret = OK; + } + break; + #endif + case MAC802154IOC_GET_EVENT: + { + FAR struct ieee802154_notif_s *notif; + + while (1) + { + /* Try popping an event off the queue */ + + notif = xbeenet_popevent(priv); + + /* If there was an event to pop off, copy it into the user + * data and free it from the MAC layer's memory. + */ + + if (notif != NULL) + { + memcpy(&netmac->u, notif, sizeof(struct ieee802154_notif_s)); + + /* Free the notification */ + + xbee_notif_free(priv->xd_mac, notif); + ret = OK; + break; + } + + /* There can only be one getevent pending at a time */ + + if (priv->xd_eventpending) + { + ret = -EAGAIN; + break; + } + + priv->xd_eventpending = true; + sem_post(&priv->xd_exclsem); + + /* Wait to be signaled when an event is queued */ + + if (sem_wait(&priv->xd_eventsem) < 0) + { + DEBUGASSERT(errno == EINTR); + priv->xd_eventpending = false; + return -EINTR; + } + + /* Get exclusive access again, then loop back around and try and + * pop an event off the queue + */ + + ret = sem_wait(&priv->xd_exclsem); + if (ret < 0) + { + wlerr("ERROR: sem_wait failed: %d\n", ret); + return ret; + } + } + } + break; + case MAC802154IOC_ENABLE_EVENTS: + { + priv->xd_enableevents = netmac->u.enable; + ret = OK; + } + break; + default: + { + ret = xbee_ioctl(priv->xd_mac, cmd, macarg); + } + break; + } + } + } + + /* Okay, we have no idea what this command is.. just give to the + * XBee MAC layer without modification. + */ + + else + { + ret = xbee_ioctl(priv->xd_mac, cmd, arg); + } + + sem_post(&priv->xd_exclsem); + return ret; + +} +#endif + +/**************************************************************************** + * Name: xbeemac_get_mhrlen + * + * Description + * Calculate the MAC header length given the frame meta-data. + * + * Input parameters: + * netdev - The network device that will mediate the MAC interface + * meta - Obfuscated metadata structure needed to create the radio + * MAC header + * + * Returned Value: + * A non-negative MAC headeer length is returned on success; a negated + * errno value is returned on any failure. + * + * Assumptions: + * Called from network logic running on the low-priority worker thread. + * + ****************************************************************************/ + +static int xbeenet_get_mhrlen(FAR struct radio_driver_s *netdev, + FAR const void *meta) +{ + FAR struct xbeenet_driver_s *priv = + (FAR struct xbeenet_driver_s *)netdev; + FAR const struct ieee802154_frame_meta_s *pktmeta = + (FAR const struct ieee802154_frame_meta_s *)meta; + + DEBUGASSERT(priv != NULL && priv->xd_mac != NULL && pktmeta != NULL); + return xbee_get_mhrlen(priv->xd_mac, pktmeta); +} + +/**************************************************************************** + * Name: xbeenet_req_data + * + * Description: + * Requests the transfer of a list of frames to the XBee MAC. + * + * Input parameters: + * netdev - The networkd device that will mediate the MAC interface + * meta - Obfuscated metadata structure needed to create the radio + * 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 xbeenet_req_data(FAR struct radio_driver_s *netdev, + FAR const void *meta, FAR struct iob_s *framelist) +{ + FAR struct xbeenet_driver_s *priv = + (FAR struct xbeenet_driver_s *)netdev; + FAR const struct ieee802154_frame_meta_s *framemeta = + (FAR const struct ieee802154_frame_meta_s *)meta; + FAR struct iob_s *iob; + int ret; + + wlinfo("Received framelist\n"); + + DEBUGASSERT(priv != NULL && framemeta != 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->xd_dev.r_dev); + + /* Remove the IOB from the queue */ + + framelist = iob->io_flink; + iob->io_flink = NULL; + + ret = xbee_req_data(priv->xd_mac, framemeta, iob); + if (ret < 0) + { + wlerr("ERROR: xbeemac_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); + } + + NETDEV_TXERRORS(&priv->xd_dev.r_dev); + return ret; + } + + NETDEV_TXDONE(&priv->xd_dev.r_dev); + } + + return OK; +} + +/**************************************************************************** + * Name: xbeenet_properties + * + * Description: + * Different packet radios may have different properties. If there are + * multiple packet radios, then those properties have to be queried at + * run time. This information is provided to the 6LoWPAN network via the + * following structure. + * + * Input parameters: + * netdev - The network device to be queried + * properties - Location where radio properities will be returned. + * + * Returned Value: + * Zero (OK) returned on success; a negated errno value is returned on + * any failure. + * + ****************************************************************************/ + +static int xbeenet_properties(FAR struct radio_driver_s *netdev, + FAR struct radiodev_properties_s *properties) +{ + DEBUGASSERT(netdev != NULL && properties != NULL); + memset(properties, 0, sizeof(struct radiodev_properties_s)); + + /* General */ + + properties->sp_addrlen = XBEENET_ADDRSIZE; /* Length of an address */ + properties->sp_framelen = XBEENET_FRAMELEN; /* Fixed frame length */ + + /* Multicast address (uses broadcast address) + * + * For meshes (only) a multicast address candetermined by the first 3 bits + * of a short address (RFC 4944): + * + * 0xxxxxxx xxxxxxxx: Unicast address + * 100xxxxx xxxxxxxx: Multicast address + * 101xxxxx xxxxxxxx: Reserved + * 110xxxxx xxxxxxxx: Reserved + * 111xxxxx xxxxxxxx: Reserved + * + * Otherwise, Multicast is implemented with the broadcast address + * (qualified by the destination PANID). + */ + + properties->sp_mcast.nv_addrlen = NET_6LOWPAN_SADDRSIZE; + memset(properties->sp_mcast.nv_addr, 0xff, RADIO_MAX_ADDRLEN); + + /* Broadcast address */ + + properties->sp_bcast.nv_addrlen = NET_6LOWPAN_SADDRSIZE; + memset(properties->sp_mcast.nv_addr, 0xff, RADIO_MAX_ADDRLEN); + +#ifdef CONFIG_NET_STARPOINT + /* Star hub node address. + * + * If this node is a "point" in a star topology, then the hub node + * MAC address is the address of the hub/PAN coordinator. + */ + +#ifdef CONFIG_NET_6LOWPAN_EXTENDEDADDR + (void)xbeenet_coord_eaddr(netdev, properties->sp_hubnode.nv_addr); + properties->sp_hubnode.nv_addrlen = NET_6LOWPAN_EADDRSIZE; +#else + (void)xbeenet_coord_saddr(netdev, properties->sp_hubnode.nv_addr); + properties->sp_hubnode.nv_addrlen = NET_6LOWPAN_SADDRSIZE; +#endif +#endif + + return OK; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: xbee_netdev_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 xbee_netdev_register(XBEEHANDLE xbee) +{ + FAR struct xbeenet_driver_s *priv; + FAR struct radio_driver_s *radio; + FAR struct net_driver_s *dev; + FAR struct xbee_maccb_s *maccb; + int ret; + + DEBUGASSERT(xbee != NULL); + + /* Get the interface structure associated with this interface number. */ + + priv = (FAR struct xbeenet_driver_s *) + kmm_zalloc(sizeof(struct xbeenet_driver_s)); + + if (priv == NULL) + { + nerr("ERROR: Failed to allocate the device structure\n"); + return -ENOMEM; + } + + /* Initialize the driver structure */ + + radio = &priv->xd_dev; + dev = &radio->r_dev; + dev->d_ifup = xbeenet_ifup; /* I/F up (new IP address) callback */ + dev->d_ifdown = xbeenet_ifdown; /* I/F down callback */ + dev->d_txavail = xbeenet_txavail; /* New TX data callback */ +#ifdef CONFIG_NET_IGMP + dev->d_addmac = xbeenet_addmac; /* Add multicast MAC address */ + dev->d_rmmac = xbeenet_rmmac; /* Remove multicast MAC address */ +#endif + #ifdef CONFIG_NETDEV_IOCTL + dev->d_ioctl = xbeenet_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->xd_mac = xbee; /* Save the MAC interface instance */ + priv->xd_txpoll = wd_create(); /* Create periodic poll timer */ + + /* Setup a locking semaphore for exclusive device driver access */ + + sem_init(&priv->xd_exclsem, 0, 1); + + DEBUGASSERT(priv->xd_txpoll != NULL); + + /* Set the network mask. */ + + xbeenet_netmask(dev); + + /* Initialize the Network frame-related callbacks */ + + radio->r_get_mhrlen = xbeenet_get_mhrlen; /* Get MAC header length */ + radio->r_req_data = xbeenet_req_data; /* Enqueue frame for transmission */ + radio->r_properties = xbeenet_properties; /* Return radio properies */ + + /* Initialize fields related to MAC event handling */ + + priv->xd_eventpending = false; + sem_init(&priv->xd_eventsem, 0, 0); + sem_setprotocol(&priv->xd_eventsem, SEM_PRIO_NONE); + + priv->xd_eventhead = NULL; + priv->xd_eventtail = NULL; + + priv->xd_enableevents = false; + priv->xd_notify_registered = false; + + /* Initialize the XBee MAC callbacks */ + + priv->xd_cb.mc_priv = priv; + + maccb = &priv->xd_cb.mc_cb; + maccb->flink = NULL; + maccb->prio = CONFIG_XBEE_NETDEV_RECVRPRIO; + maccb->notify = xbeenet_notify; + maccb->rxframe = xbeenet_rxframe; + + /* Bind the callback structure */ + + ret = xbee_bind(xbee, maccb); + if (ret < 0) + { + nerr("ERROR: Failed to bind the XBee MAC callbacks: %d\n", ret); + + /* Release wdog timers */ + + wd_delete(priv->xd_txpoll); + + /* Free memory and return the error */ + + kmm_free(priv); + return ret; + } + + /* Put the interface in the down state. */ + + xbeenet_ifdown(dev); + + /* Register the device with the OS so that socket IOCTLs can be performed */ + + (void)netdev_register(&priv->xd_dev.r_dev, NET_LL_IEEE802154); + return OK; +} + +#endif /* CONFIG_NET_6LOWPAN */ diff --git a/drivers/wireless/ieee802154/xbee/xbee_notif.c b/drivers/wireless/ieee802154/xbee/xbee_notif.c new file mode 100644 index 0000000000..a59a1e3a20 --- /dev/null +++ b/drivers/wireless/ieee802154/xbee/xbee_notif.c @@ -0,0 +1,283 @@ +/**************************************************************************** + * drivers/wireless/ieee802154/xbee/xbee_notif.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 "xbee.h" +#include "xbee_mac.h" +#include "xbee_notif.h" + +#include +#include + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: xbee_notif_free + * + * Description: + * When the XBee driver calls the registered callback, it passes a reference + * to a ieee802154_notif_s structure. This structure needs to be freed + * after the callback handler is done using it. + * + ****************************************************************************/ + +void xbee_notif_free(XBEEHANDLE xbee, FAR struct ieee802154_notif_s *notif) +{ + FAR struct xbee_priv_s *priv = (FAR struct xbee_priv_s *)xbee; + + /* Lock the MAC */ + + xbee_lock(priv, false); + + /* Call the internal helper function to free the notification */ + + xbee_notif_free_locked(priv, notif); + + /* Unlock the MAC */ + + xbee_unlock(priv) +} + +/**************************************************************************** + * Internal MAC Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: xbee_notifpool_init + * + * Description: + * This function initializes the notification structure pool. It allows the + * XBee driver to pass notifications and for the callee to free them when they + * are done using them, saving copying the data when passing. + * + ****************************************************************************/ + +void xbee_notifpool_init(FAR struct xbee_priv_s *priv) +{ + FAR struct xbee_notif_s *pool = priv->notif_pool; + int remaining = CONFIG_XBEE_NNOTIF; + + priv->notif_free = NULL; + while (remaining > 0) + { + FAR struct xbee_notif_s *notif = pool; + + /* Add the next meta data structure from the pool to the list of + * general structures. + */ + + notif->flink = priv->notif_free; + priv->notif_free = notif; + + /* Set up for the next structure from the pool */ + + pool++; + remaining--; + } + + sem_init(&priv->notif_sem, 0, CONFIG_XBEE_NNOTIF); +} + +/**************************************************************************** + * Name: xbee_notif_alloc + * + * Description: + * This function allocates a free notification structure from the free list + * to be used for passing to the registered notify callback. The callee software + * is responsible for freeing the notification structure after it is done using + * it via xbee_notif_free. + * + * Assumptions: + * priv XBee struct is locked when calling. + * + * Notes: + * If any of the semaphore waits inside this function get interrupted, the + * function will release the MAC layer. If this function returns -EINTR, the + * calling code should NOT release the MAC semaphore. + * + ****************************************************************************/ + +int xbee_notif_alloc(FAR struct xbee_priv_s *priv, + FAR struct ieee802154_notif_s **notif, + bool allow_interrupt) +{ + int ret; + FAR struct xbee_notif_s *privnotif; + + /* Try and take a count from the semaphore. If this succeeds, we have + * "reserved" the structure, but still need to unlink it from the free list. + * The MAC is already locked, so there shouldn't be any other conflicting calls + */ + + ret = sem_trywait(&priv->notif_sem); + + if (ret == OK) + { + privnotif = priv->notif_free; + priv->notif_free = privnotif->flink; + privnotif->nclients = 0; + } + else + { + /* Unlock XBee driver so that other work can be done to free a notification */ + + xbee_unlock(priv) + + /* Take a count from the notification semaphore, waiting if necessary. We + * only return from here with an error if we are allowing interruptions + * and we received a signal */ + + ret = xbee_takesem(&priv->notif_sem, allow_interrupt); + if (ret < 0) + { + /* MAC sem is already released */ + + return -EINTR; + } + + /* If we've taken a count from the semaphore, we have "reserved" the struct + * but now we need to pop it off of the free list. We need to re-lock the + * MAC in order to ensure this happens correctly. + */ + + ret = xbee_lock(priv, allow_interrupt); + if (ret < 0) + { + xbee_givesem(&priv->notif_sem); + return -EINTR; + } + + /* We can now safely unlink the next free structure from the free list */ + + privnotif = priv->notif_free; + priv->notif_free = privnotif->flink; + privnotif->nclients = 0; + } + + *notif = (FAR struct ieee802154_notif_s *)privnotif; + + return OK; +} + +/**************************************************************************** + * Name: xbee_notif_free_locked + * + * Description: + * When the XBee driver calls the registered callback, it passes a reference + * to a ieee802154_notif_s structure. This structure needs to be freed + * after the callback handler is done using it. + * + * Internal version that already has XBee driver locked + * + ****************************************************************************/ + +void xbee_notif_free_locked(FAR struct xbee_priv_s * priv, + FAR struct ieee802154_notif_s *notif) +{ + FAR struct xbee_notif_s *privnotif = + (FAR struct xbee_notif_s *)notif; + + /* We know how many clients have registered for notifications. Each must + * call xbee_notif_free() before we can release the notification + * resource. + */ + + if (privnotif->nclients < 2) + { + /* This is the free from the last notification */ + + privnotif->flink = priv->notif_free; + priv->notif_free = privnotif; + privnotif->nclients = 0; + + xbee_givesem(&priv->notif_sem); + } + else + { + /* More calls are expected. Decrement the count of expected calls + * and preserve the notification resources. + */ + + privnotif->nclients--; + } +} + +/**************************************************************************** + * Name: xbee_notify + * + * Description: + * Notify every register XBee MAC client. + * + ****************************************************************************/ + +void xbee_notify(FAR struct xbee_priv_s *priv, + FAR struct ieee802154_notif_s *notif) +{ + FAR struct xbee_maccb_s *cb; + FAR struct xbee_notif_s *privnotif = (FAR struct xbee_notif_s *)notif; + + /* Set the notification count so that the notification resources will be + * preserved until the final notification. + */ + + privnotif->nclients = priv->nclients; + + /* Try to notify every registered XBee MAC client */ + + for (cb = priv->cb; cb != NULL; cb = cb->flink) + { + /* Does this client want notifications? */ + + if (cb->notify != NULL) + { + /* Yes.. Notify */ + + cb->notify(cb, notif); + } + } +} diff --git a/drivers/wireless/ieee802154/xbee/xbee_notif.h b/drivers/wireless/ieee802154/xbee/xbee_notif.h new file mode 100644 index 0000000000..4a55b03dd0 --- /dev/null +++ b/drivers/wireless/ieee802154/xbee/xbee_notif.h @@ -0,0 +1,84 @@ +/**************************************************************************** + * drivers/wireless/ieee802154/xbee/xbee_notif.h + * + * Copyright (C) 2017 Verge Inc. All rights reserved. + * + * Author: Anthony Merlino + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +#ifndef __DRIVERS_WIRELESS_IEEE802154_XBEE_NOTIF_H +#define __DRIVERS_WIRELESS_IEEE802154_XBEE_NOTIF_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include + +#include + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/* Extend the public ieee802154_notif_s to include a private forward link to + * support a list to handle allocation + */ + +struct xbee_notif_s +{ + struct ieee802154_notif_s pub; /* Publically visible structure */ + FAR struct xbee_notif_s *flink; /* Supports a singly linked list */ + uint8_t nclients; +}; + +/**************************************************************************** + * Function Prototypes + ****************************************************************************/ + +struct xbee_priv_s; /* Forward Reference */ + +void xbee_notifpool_init(FAR struct xbee_priv_s *priv); + +int xbee_notif_alloc(FAR struct xbee_priv_s *priv, + FAR struct ieee802154_notif_s **notif, + bool allow_interrupt); + +void xbee_notify(FAR struct xbee_priv_s *priv, + FAR struct ieee802154_notif_s *notif); + +void xbee_notif_free_locked(FAR struct xbee_priv_s * priv, + FAR struct ieee802154_notif_s *notif); + +#endif /* __DRIVERS_WIRELESS_IEEE802154_XBEE_NOTIF_H */ \ No newline at end of file diff --git a/include/nuttx/wireless/ieee802154/xbee.h b/include/nuttx/wireless/ieee802154/xbee.h new file mode 100644 index 0000000000..9a1ae8cc9c --- /dev/null +++ b/include/nuttx/wireless/ieee802154/xbee.h @@ -0,0 +1,135 @@ +/**************************************************************************** + * include/nuttx/wireless/ieee802154/xbee.h + * + * Copyright (C) 2017 Verge Inc. All rights reserved. + * Author: Anthony Merlino + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +#ifndef __INCLUDE_NUTTX_WIRELESS_IEEE802154_XBEE_H +#define __INCLUDE_NUTTX_WIRELESS_IEEE802154_XBEE_H + +/**************************************************************************** + * Included files + ****************************************************************************/ + +#include +#include +#include + +/**************************************************************************** + * Public Types + ****************************************************************************/ + +/* The XBee provides interrupts (ATTN) to the MCU via a GPIO pin. The + * following structure provides an MCU-independent mechanism for controlling + * the XBee GPIO interrupt. + * + * The XBee interrupt is active low. + */ + +struct xbee_lower_s +{ + void (*reset)(FAR const struct xbee_lower_s *lower); + int (*attach)(FAR const struct xbee_lower_s *lower, xcpt_t handler, + FAR void *arg); + void (*enable)(FAR const struct xbee_lower_s *lower, bool state); + bool (*poll)(FAR const struct xbee_lower_s *lower); +}; + +/* This is an opaque reference to the XBee's internal private state. It is + * returned by xbee_init() when it is created. It may then be used + * at other interfaces in order to interact with the XBee MAC. + */ + +typedef FAR void *XBEEHANDLE; + +#ifdef __cplusplus +#define EXTERN extern "C" +extern "C" +{ +#else +#define EXTERN extern +#endif + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +/**************************************************************************** + * Name: xbee_init + * + * Description: + * Initialize an XBee driver. The XBee 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 XBee + * lower - The MCU-specific interrupt used to control low-level MCU + * functions (i.e., XBee GPIO interrupts). + * devno - If more than one XBee is supported, then this is the + * zero based number that identifies the XBee; + * + * Returned Value: + * OK on success; Negated errno on failure. + * + * Assumptions: + * + ****************************************************************************/ + +struct spi_dev_s; /* Forward reference */ +XBEEHANDLE xbee_init(FAR struct spi_dev_s *spi, + FAR const struct xbee_lower_s *lower); + +/**************************************************************************** + * Name: xbee_netdev_register + * + * Description: + * Register XBee network device. The network device is what binds the XBee MAC + * to the network layer (6LoWPAN, PF_IEEE802154). + * + * Parameters: + * xbee - A reference to the XBee Mac driver + * + * Returned Value: + * OK on success; Negated errno on failure. + * + * Assumptions: + * + ****************************************************************************/ + +int xbee_netdev_register(XBEEHANDLE xbee); + +#undef EXTERN +#ifdef __cplusplus +} +#endif + +#endif /* __INCLUDE_NUTTX_WIRELESS_IEEE802154_XBEE_H */