|
diff --git a/Makefile.unix b/Makefile.unix
index 220740c5bd3..d816947a38e 100644
--- a/Makefile.unix
+++ b/Makefile.unix
@@ -498,7 +498,7 @@ do_qconfig: dirlinks apps_preconfig
qconfig: do_qconfig clean_context
-gconfig: dirlinks apps_preconfig
+do_gconfig: dirlinks apps_preconfig
$(Q) APPSDIR=${CONFIG_APPS_DIR} kconfig-gconf Kconfig
gconfig: do_gconfig clean_context
diff --git a/README.txt b/README.txt
index 59648d01f4c..5d3721f4c50 100644
--- a/README.txt
+++ b/README.txt
@@ -464,9 +464,9 @@ Notes about Header Files
Certain header files, such as setjmp.h, stdarg.h, and math.h, may still
be needed from your toolchain and your compiler may not, however, be able
- to find these if you compile NuttX without using standard header file.
- If that is the case, one solution is to copy those header file from
- your toolchain into the NuttX include directory.
+ to find these if you compile NuttX without using standard header files
+ (ie., with -nostdinc). If that is the case, one solution is to copy
+ those header file from your toolchain into the NuttX include directory.
Duplicated Header Files.
diff --git a/arch/arm/include/stm32/chip.h b/arch/arm/include/stm32/chip.h
index 0844c5a09fb..df921df4b89 100644
--- a/arch/arm/include/stm32/chip.h
+++ b/arch/arm/include/stm32/chip.h
@@ -64,12 +64,16 @@
* STM32L15XCX -- 48-pins
* STM32L15XRX -- 64-pins
* STM32L15XVX -- 100-pins
+ * STM32L15XZX -- 144-pins
*
* STM32L15XX6 -- 32KB FLASH, 10KB SRAM, 4KB EEPROM
* STM32L15XX8 -- 64KB FLASH, 10KB SRAM, 4KB EEPROM
* STM32L15XXB -- 128KB FLASH, 16KB SRAM, 4KB EEPROM
*
* STM32L15XXC -- 256KB FLASH, 32KB SRAM, 8KB EEPROM (medium+ density)
+ *
+ * STM32L16XXD -- 384KB FLASH, 48KB SRAM, 12KB EEPROM (high density)
+ * STM32L16XXE -- 512KB FLASH, 80KB SRAM, 16KB EEPROM (high density)
*/
#if defined(CONFIG_ARCH_CHIP_STM32L151C6) || defined(CONFIG_ARCH_CHIP_STM32L151C8) || \
@@ -320,7 +324,7 @@
#elif defined(CONFIG_ARCH_CHIP_STM32L152RC)
# define CONFIG_STM32_STM32L15XX 1 /* STM32L151xx and STM32L152xx family */
-# define CONFIG_STM32_ENERGYLITE 1 /* STM32L EnergyLite vamily */
+# define CONFIG_STM32_ENERGYLITE 1 /* STM32L EnergyLite family */
# undef CONFIG_STM32_STM32F10XX /* STM32F10xxx family */
# undef CONFIG_STM32_LOWDENSITY /* STM32F100x, STM32F101x, STM32F102x and STM32F103x w/ 16/32 Kbytes
* and STM32L15xxx */
@@ -331,6 +335,7 @@
# undef CONFIG_STM32_CONNECTIVITYLINE /* STM32F105x and STM32F107x */
# undef CONFIG_STM32_STM32F20XX /* STM32F205x and STM32F207x */
# undef CONFIG_STM32_STM32F30XX /* STM32F30xxx family */
+# undef CONFIG_STM32_STM32F33XX /* STM32F33xxx family */
# undef CONFIG_STM32_STM32F40XX /* STM32F405xx and STM32407xx families */
# define STM32_NFSMC 0 /* No FSMC */
# define STM32_NATIM 0 /* No advanced timers */
@@ -358,17 +363,18 @@
#elif defined(CONFIG_ARCH_CHIP_STM32L162ZD)
# define CONFIG_STM32_STM32L15XX 1 /* STM32L151xx and STM32L152xx family */
-# define CONFIG_STM32_ENERGYLITE 1 /* STM32L EnergyLite vamily */
+# define CONFIG_STM32_ENERGYLITE 1 /* STM32L EnergyLite family */
# undef CONFIG_STM32_STM32F10XX /* STM32F10xxx family */
# undef CONFIG_STM32_LOWDENSITY /* STM32F100x, STM32F101x, STM32F102x and STM32F103x w/ 16/32 Kbytes
* and STM32L15xxx */
# undef CONFIG_STM32_MEDIUMDENSITY /* STM32F100x, STM32F101x, STM32F102x and STM32F103x w/ 64/128 Kbytes */
# undef CONFIG_STM32_MEDIUMPLUSDENSITY /* STM32L15xxC w/ 32/256 Kbytes */
-# define CONFIG_STM32_HIGHDENSITY 1 /* STM32F100x, STM32F101x, and STM32F103x w/ 256/512 Kbytes, STM32L16x w/ 48/384 Kbytes. */
+# define CONFIG_STM32_HIGHDENSITY 1 /* STM32L16xD w/ 48/384 Kbytes. */
# undef CONFIG_STM32_VALUELINE /* STM32F100x */
# undef CONFIG_STM32_CONNECTIVITYLINE /* STM32F105x and STM32F107x */
# undef CONFIG_STM32_STM32F20XX /* STM32F205x and STM32F207x */
# undef CONFIG_STM32_STM32F30XX /* STM32F30xxx family */
+# undef CONFIG_STM32_STM32F33XX /* STM32F33xxx family */
# undef CONFIG_STM32_STM32F40XX /* STM32F405xx and STM32407xx families */
# define STM32_NFSMC 1 /* FSMC */
# define STM32_NATIM 0 /* No advanced timers */
@@ -395,6 +401,48 @@
# define STM32_NRNG 0 /* No random number generator (RNG) */
# define STM32_NDCMI 0 /* No digital camera interface (DCMI) */
+#elif defined(CONFIG_ARCH_CHIP_STM32L162VE)
+# define CONFIG_STM32_STM32L15XX 1 /* STM32L151xx and STM32L152xx family */
+# define CONFIG_STM32_ENERGYLITE 1 /* STM32L EnergyLite family */
+# undef CONFIG_STM32_STM32F10XX /* STM32F10xxx family */
+# undef CONFIG_STM32_LOWDENSITY /* STM32F100x, STM32F101x, STM32F102x and STM32F103x w/ 16/32 Kbytes
+ * and STM32L15xxx */
+# undef CONFIG_STM32_MEDIUMDENSITY /* STM32F100x, STM32F101x, STM32F102x and STM32F103x w/ 64/128 Kbytes */
+# undef CONFIG_STM32_MEDIUMPLUSDENSITY /* STM32L15xxC w/ 32/256 Kbytes */
+# define CONFIG_STM32_HIGHDENSITY 1 /* STM32L16xE w/ 80/512 Kbytes. */
+# undef CONFIG_STM32_VALUELINE /* STM32F100x */
+# undef CONFIG_STM32_CONNECTIVITYLINE /* STM32F105x and STM32F107x */
+# undef CONFIG_STM32_STM32F20XX /* STM32F205x and STM32F207x */
+# undef CONFIG_STM32_STM32F30XX /* STM32F30xxx family */
+# undef CONFIG_STM32_STM32F33XX /* STM32F33xxx family */
+# undef CONFIG_STM32_STM32F40XX /* STM32F405xx and STM32407xx families */
+# define STM32_NFSMC 0 /* No FSMC */
+# define STM32_NATIM 0 /* No advanced timers */
+# define STM32_NGTIM 4 /* 16-bit general timers TIM2-4 with DMA
+ * 32-bit general timer TIM5 with DMA */
+# define STM32_NGTIMNDMA 3 /* 16-bit general timers TIM9-11 without DMA */
+# define STM32_NBTIM 2 /* 2 basic timers: TIM6, TIM7 with DMA */
+# define STM32_NDMA 2 /* DMA1, 12-channels */
+# define STM32_NSPI 3 /* SPI1-3 */
+# define STM32_NI2S 2 /* I2S1-2, overlapping with SPI2-3 */
+# define STM32_NUSART 5 /* USART1-3, UART4-5 */
+# define STM32_NI2C 2 /* I2C1-2 */
+# define STM32_NCAN 0 /* No CAN */
+# define STM32_NSDIO 0 /* No SDIO */
+# define STM32_NLCD 1 /* LCD 4x44, 8x40*/
+# define STM32_NUSBOTG 1 /* USB OTG FS/HS (only USB 2.0 device) */
+# define STM32_NGPIO 83 /* GPIOA-G,H */
+
+# define STM32_NADC 1 /* ADC1, up to 40-channels (medium+ and high density). See for more information RM0038 Reference manual */
+# define STM32_NDAC 1 /* DAC 1, 2 channels. See for more information RM0038 Reference manual */
+ /* (2) Comparators */
+# define STM32_NCAPSENSE 23 /* Capacitive sensing channels */
+# define STM32_NCRC 1 /* CRC */
+# define STM32_NETHERNET 0 /* No ethernet */
+# define STM32_NRNG 0 /* No random number generator (RNG) */
+# define STM32_NDCMI 0 /* No digital camera interface (DCMI) */
+
+
/* STM32 F100 Value Line ************************************************************/
#elif defined(CONFIG_ARCH_CHIP_STM32F100C8) || defined(CONFIG_ARCH_CHIP_STM32F100CB) \
@@ -562,7 +610,7 @@
#elif defined(CONFIG_ARCH_CHIP_STM32F102CB)
# undef CONFIG_STM32_STM32L15XX /* STM32L151xx and STM32L152xx family */
-# undef CONFIG_STM32_ENERGYLITE /* STM32L EnergyLite vamily */
+# undef CONFIG_STM32_ENERGYLITE /* STM32L EnergyLite family */
# define CONFIG_STM32_STM32F10XX 1 /* STM32F10xx family */
# undef CONFIG_STM32_LOWDENSITY /* STM32F100x, STM32F101x, STM32F102x and STM32F103x w/ 16/32 Kbytes */
# define CONFIG_STM32_MEDIUMDENSITY 1 /* STM32F100x, STM32F101x, STM32F102x and STM32F103x w/ 64/128 Kbytes */
@@ -1129,7 +1177,7 @@
#elif defined(CONFIG_ARCH_CHIP_STM32F302K6) || defined(CONFIG_ARCH_CHIP_STM32F302K8)
# undef CONFIG_STM32_STM32L15XX /* STM32L151xx and STM32L152xx family */
-# undef CONFIG_STM32_ENERGYLITE /* STM32L EnergyLite vamily */
+# undef CONFIG_STM32_ENERGYLITE /* STM32L EnergyLite family */
# undef CONFIG_STM32_STM32F10XX /* STM32F10xxx family */
# undef CONFIG_STM32_LOWDENSITY /* STM32F100x, STM32F101x, STM32F102x and STM32F103x w/ 16/32 Kbytes */
# undef CONFIG_STM32_MEDIUMDENSITY /* STM32F100x, STM32F101x, STM32F102x and STM32F103x w/ 64/128 Kbytes */
@@ -1668,7 +1716,7 @@
#elif defined(CONFIG_ARCH_CHIP_STM32F373C8) || defined(CONFIG_ARCH_CHIP_STM32F373CB) || defined(CONFIG_ARCH_CHIP_STM32F373CC)
# undef CONFIG_STM32_STM32L15XX /* STM32L151xx and STM32L152xx family */
-# undef CONFIG_STM32_ENERGYLITE /* STM32L EnergyLite vamily */
+# undef CONFIG_STM32_ENERGYLITE /* STM32L EnergyLite family */
# undef CONFIG_STM32_STM32F10XX /* STM32F10xxx family */
# undef CONFIG_STM32_LOWDENSITY /* STM32F100x, STM32F101x, STM32F102x and STM32F103x w/ 16/32 Kbytes */
# undef CONFIG_STM32_MEDIUMDENSITY /* STM32F100x, STM32F101x, STM32F102x and STM32F103x w/ 64/128 Kbytes */
diff --git a/arch/arm/src/stm32/chip/stm32_flash.h b/arch/arm/src/stm32/chip/stm32_flash.h
index 6bc1085bd18..13c966c05c2 100644
--- a/arch/arm/src/stm32/chip/stm32_flash.h
+++ b/arch/arm/src/stm32/chip/stm32_flash.h
@@ -59,16 +59,33 @@
#if defined(CONFIG_STM32_FLASH_CONFIG_DEFAULT)
# if defined(CONFIG_STM32_STM32L15XX)
+# if defined(CONFIG_STM32_HIGHDENSITY)
-/* The STM32 L15xx/L16xx can support up to 384KB of FLASH. (In reality, supported
- * L15xx parts have no more than 128KB). The program memory block is divided into
- * 96 sectors of 4 Kbytes each, and each sector is further split up into 16 pages of
- * 256 bytes each. The sector is the write protection granularity. In total, the
+/* Different STM32L1xxx MCU version are now called by different 'categories' instead
+ * of 'densities'. Cat.5 MCU can have up to 512KB of FLASH. STM32L1xxx also have
+ * data EEPROM, up to 16KB.
+ */
+
+# define STM32_FLASH_NPAGES 2048
+# define STM32_FLASH_PAGESIZE 256
+# else
+
+/* The STM32 (< Cat.5) L15xx/L16xx can support up to 384KB of FLASH. (In reality, most
+ * supported L15xx parts have no more than 128KB). The program memory block is divided
+ * into 96 sectors of 4 Kbytes each, and each sector is further split up into 16 pages
+ * of 256 bytes each. The sector is the write protection granularity. In total, the
* program memory block contains 1536 pages.
*/
-# define STM32_FLASH_NPAGES 1536
-# define STM32_FLASH_PAGESIZE 256
+# define STM32_FLASH_NPAGES 1536
+# define STM32_FLASH_PAGESIZE 256
+# endif
+
+ /* Maximum EEPROM size on Cat.5 MCU. TODO: this should be in chip config. */
+
+# ifndef STM32_EEPROM_SIZE
+# define STM32_EEPROM_SIZE (16 * 1024)
+# endif
# elif defined(CONFIG_STM32_LOWDENSITY)
# define STM32_FLASH_NPAGES 32
@@ -201,27 +218,40 @@
# elif defined(CONFIG_STM32_FLASH_CONFIG_I)
# endif
# endif
-#endif
+#endif /* !defined(CONFIG_STM32_FLASH_CONFIG_DEFAULT) */
#ifdef STM32_FLASH_PAGESIZE
# define STM32_FLASH_SIZE (STM32_FLASH_NPAGES * STM32_FLASH_PAGESIZE)
-#endif /* def STM32_FLASH_PAGESIZE */
+#endif
/* Register Offsets *****************************************************************/
-#define STM32_FLASH_ACR_OFFSET 0x0000
-#define STM32_FLASH_KEYR_OFFSET 0x0004
-#define STM32_FLASH_OPTKEYR_OFFSET 0x0008
-#define STM32_FLASH_SR_OFFSET 0x000c
-#define STM32_FLASH_CR_OFFSET 0x0010
-
-#if defined(CONFIG_STM32_STM32F10XX) || defined(CONFIG_STM32_STM32F30XX) || \
- defined(CONFIG_STM32_STM32F33XX) || defined(CONFIG_STM32_STM32F37XX)
-# define STM32_FLASH_AR_OFFSET 0x0014
-# define STM32_FLASH_OBR_OFFSET 0x001c
-# define STM32_FLASH_WRPR_OFFSET 0x0020
-#elif defined(CONFIG_STM32_STM32F20XX) || defined(CONFIG_STM32_STM32F40XX)
-# define STM32_FLASH_OPTCR_OFFSET 0x0014
+#define STM32_FLASH_ACR_OFFSET 0x0000
+#if defined(CONFIG_STM32_STM32L15XX)
+# define STM32_FLASH_PECR_OFFSET 0x0004
+# define STM32_FLASH_PDKEYR_OFFSET 0x0008
+# define STM32_FLASH_PEKEYR_OFFSET 0x000c
+# define STM32_FLASH_PRGKEYR_OFFSET 0x0010
+# define STM32_FLASH_OPTKEYR_OFFSET 0x0014
+# define STM32_FLASH_SR_OFFSET 0x0018
+# define STM32_FLASH_OBR_OFFSET 0x001c
+# define STM32_FLASH_WRPR1_OFFSET 0x0020
+# define STM32_FLASH_WRPR2_OFFSET 0x0080
+# define STM32_FLASH_WRPR3_OFFSET 0x0084
+# define STM32_FLASH_WRPR4_OFFSET 0x0088
+#else
+# define STM32_FLASH_KEYR_OFFSET 0x0004
+# define STM32_FLASH_OPTKEYR_OFFSET 0x0008
+# define STM32_FLASH_SR_OFFSET 0x000c
+# define STM32_FLASH_CR_OFFSET 0x0010
+# if defined(CONFIG_STM32_STM32F10XX) || defined(CONFIG_STM32_STM32F30XX) || \
+ defined(CONFIG_STM32_STM32F33XX) || defined(CONFIG_STM32_STM32F37XX)
+# define STM32_FLASH_AR_OFFSET 0x0014
+# define STM32_FLASH_OBR_OFFSET 0x001c
+# define STM32_FLASH_WRPR_OFFSET 0x0020
+# elif defined(CONFIG_STM32_STM32F20XX) || defined(CONFIG_STM32_STM32F40XX)
+# define STM32_FLASH_OPTCR_OFFSET 0x0014
+# endif
#endif
#if defined(CONFIG_STM32_STM32F427) || defined(CONFIG_STM32_STM32F429)
@@ -230,22 +260,36 @@
/* Register Addresses ***************************************************************/
-#define STM32_FLASH_ACR (STM32_FLASHIF_BASE+STM32_FLASH_ACR_OFFSET)
-#define STM32_FLASH_KEYR (STM32_FLASHIF_BASE+STM32_FLASH_KEYR_OFFSET)
-#define STM32_FLASH_OPTKEYR (STM32_FLASHIF_BASE+STM32_FLASH_OPTKEYR_OFFSET)
-#define STM32_FLASH_SR (STM32_FLASHIF_BASE+STM32_FLASH_SR_OFFSET)
-#define STM32_FLASH_CR (STM32_FLASHIF_BASE+STM32_FLASH_CR_OFFSET)
+#define STM32_FLASH_ACR (STM32_FLASHIF_BASE+STM32_FLASH_ACR_OFFSET)
+#if defined(CONFIG_STM32_STM32L15XX)
+# define STM32_FLASH_PECR (STM32_FLASHIF_BASE+STM32_FLASH_PECR_OFFSET)
+# define STM32_FLASH_PDKEYR (STM32_FLASHIF_BASE+STM32_FLASH_PDKEYR_OFFSET)
+# define STM32_FLASH_PEKEYR (STM32_FLASHIF_BASE+STM32_FLASH_PEKEYR_OFFSET)
+# define STM32_FLASH_PRGKEYR (STM32_FLASHIF_BASE+STM32_FLASH_PRGKEYR_OFFSET)
+# define STM32_FLASH_OPTKEYR (STM32_FLASHIF_BASE+STM32_FLASH_OPTKEYR_OFFSET)
+# define STM32_FLASH_SR (STM32_FLASHIF_BASE+STM32_FLASH_SR_OFFSET)
+# define STM32_FLASH_OBR (STM32_FLASHIF_BASE+STM32_FLASH_OBR_OFFSET)
+# define STM32_FLASH_WRPR1 (STM32_FLASHIF_BASE+STM32_FLASH_WRPR1_OFFSET)
+# define STM32_FLASH_WRPR2 (STM32_FLASHIF_BASE+STM32_FLASH_WRPR2_OFFSET)
+# define STM32_FLASH_WRPR3 (STM32_FLASHIF_BASE+STM32_FLASH_WRPR3_OFFSET)
+# define STM32_FLASH_WRPR4 (STM32_FLASHIF_BASE+STM32_FLASH_WRPR4_OFFSET)
+#else
+# define STM32_FLASH_KEYR (STM32_FLASHIF_BASE+STM32_FLASH_KEYR_OFFSET)
+# define STM32_FLASH_OPTKEYR (STM32_FLASHIF_BASE+STM32_FLASH_OPTKEYR_OFFSET)
+# define STM32_FLASH_SR (STM32_FLASHIF_BASE+STM32_FLASH_SR_OFFSET)
+# define STM32_FLASH_CR (STM32_FLASHIF_BASE+STM32_FLASH_CR_OFFSET)
-#if defined(CONFIG_STM32_STM32F10XX) || defined(CONFIG_STM32_STM32F30XX) || \
- defined(CONFIG_STM32_STM32F33XX) || defined(CONFIG_STM32_STM32F37XX)
-# define STM32_FLASH_AR (STM32_FLASHIF_BASE+STM32_FLASH_AR_OFFSET)
-# define STM32_FLASH_OBR (STM32_FLASHIF_BASE+STM32_FLASH_OBR_OFFSET)
-# define STM32_FLASH_WRPR (STM32_FLASHIF_BASE+STM32_FLASH_WRPR_OFFSET)
-#elif defined(CONFIG_STM32_STM32F20XX) || defined(CONFIG_STM32_STM32F40XX)
-# define STM32_FLASH_OPTCR (STM32_FLASHIF_BASE+STM32_FLASH_OPTCR_OFFSET)
-#endif
-#if defined(CONFIG_STM32_STM32F427) || defined(CONFIG_STM32_STM32F429)
-# define STM32_FLASH_OPTCR1 (STM32_FLASHIF_BASE+STM32_FLASH_OPTCR1_OFFSET)
+# if defined(CONFIG_STM32_STM32F10XX) || defined(CONFIG_STM32_STM32F30XX) || \
+ defined(CONFIG_STM32_STM32F33XX) || defined(CONFIG_STM32_STM32F37XX)
+# define STM32_FLASH_AR (STM32_FLASHIF_BASE+STM32_FLASH_AR_OFFSET)
+# define STM32_FLASH_OBR (STM32_FLASHIF_BASE+STM32_FLASH_OBR_OFFSET)
+# define STM32_FLASH_WRPR (STM32_FLASHIF_BASE+STM32_FLASH_WRPR_OFFSET)
+# elif defined(CONFIG_STM32_STM32F20XX) || defined(CONFIG_STM32_STM32F40XX)
+# define STM32_FLASH_OPTCR (STM32_FLASHIF_BASE+STM32_FLASH_OPTCR_OFFSET)
+# endif
+# if defined(CONFIG_STM32_STM32F427) || defined(CONFIG_STM32_STM32F429)
+# define STM32_FLASH_OPTCR1 (STM32_FLASHIF_BASE+STM32_FLASH_OPTCR1_OFFSET)
+# endif
#endif
/* Register Bitfield Definitions ****************************************************/
@@ -303,6 +347,34 @@
# define FLASH_SR_PGPERR (1 << 6) /* Bit 6: Programming parallelism error */
# define FLASH_SR_PGSERR (1 << 7) /* Bit 7: Programming sequence error */
# define FLASH_SR_BSY (1 << 16) /* Bit 16: Busy */
+#elif defined(CONFIG_STM32_STM32L15XX)
+# define FLASH_SR_BSY (1 << 0) /* Bit 0: Busy */
+# define FLASH_SR_EOP (1 << 1) /* Bit 1: End of operation */
+# define FLASH_SR_ENDHV (1 << 2) /* Bit 2: End of high voltage */
+# define FLASH_SR_READY (1 << 3) /* Bit 3: Flash memory module ready after low power mode */
+# define FLASH_SR_WRPERR (1 << 8) /* Bit 8: Write protection error */
+# define FLASH_SR_PGAERR (1 << 9) /* Bit 9: Programming alignment error */
+# define FLASH_SR_SIZERR (1 << 10) /* Bit 10: Size error */
+# define FLASH_SR_OPTVERR (1 << 11) /* Bit 11: Option validity error */
+# define FLASH_SR_OPTVERRUSR (1 << 12) /* Bit 12: Option UserValidity Error */
+# define FLASH_SR_RDERR (1 << 13) /* Bit 13: Read protected error */
+#endif
+
+/* Program/Erase Control Register (PECR) */
+
+#if defined(CONFIG_STM32_STM32L15XX)
+# define FLASH_PECR_PELOCK (1 << 0) /* Bit 0: PECR and data EEPROM lock */
+# define FLASH_PECR_PRGLOCK (1 << 1) /* Bit 1: Program memory lock */
+# define FLASH_PECR_OPTLOCK (1 << 2) /* Bit 2: Option bytes block lock */
+# define FLASH_PECR_PROG (1 << 3) /* Bit 3: Program memory selection */
+# define FLASH_PECR_DATA (1 << 4) /* Bit 4: Data EEPROM selection */
+# define FLASH_PECR_FTDW (1 << 8) /* Bit 8: Fixed time data write for Byte, Half Word and Word programming */
+# define FLASH_PECR_ERASE (1 << 9) /* Bit 9: Page or Double Word erase mode */
+# define FLASH_PECR_FPRG (1 << 10) /* Bit 10: Half Page/Double Word programming mode */
+# define FLASH_PECR_PARALLBANK (1 << 15) /* Bit 15: Parallel bank mode */
+# define FLASH_PECR_EOPIE (1 << 16) /* Bit 16: End of programming interrupt enable */
+# define FLASH_PECR_ERRIE (1 << 17) /* Bit 17: Error interrupt enable */
+# define FLASH_PECR_OBL_LAUNCH (1 << 18) /* Bit 18: Launch the option byte loading */
#endif
/* Flash Control Register (CR) */
@@ -380,7 +452,6 @@
# define FLASH_OPTCR1_BFB2_SHIFT (4) /* Bits 4: Dual-bank Boot option byte */
# define FLASH_OPTCR1_BFB2_MASK (1 << FLASH_OPTCR_NWRP_SHIFT)
-
#endif
#if defined(CONFIG_STM32_STM32F446)
diff --git a/arch/arm/src/stm32/chip/stm32f40xxx_pinmap.h b/arch/arm/src/stm32/chip/stm32f40xxx_pinmap.h
index 82fb74a4481..d44c664edbf 100644
--- a/arch/arm/src/stm32/chip/stm32f40xxx_pinmap.h
+++ b/arch/arm/src/stm32/chip/stm32f40xxx_pinmap.h
@@ -424,6 +424,10 @@
#define GPIO_I2C3_SCL_2 (GPIO_ALT|GPIO_AF4|GPIO_SPEED_50MHz|GPIO_OPENDRAIN|GPIO_PORTH|GPIO_PIN7)
#define GPIO_I2C3_SDA_1 (GPIO_ALT|GPIO_AF4|GPIO_SPEED_50MHz|GPIO_OPENDRAIN|GPIO_PORTC|GPIO_PIN9)
#define GPIO_I2C3_SDA_2 (GPIO_ALT|GPIO_AF4|GPIO_SPEED_50MHz|GPIO_OPENDRAIN|GPIO_PORTH|GPIO_PIN8)
+#if defined(CONFIG_STM32_STM32F411)
+# define GPIO_I2C3_SDA_3 (GPIO_ALT|GPIO_AF9|GPIO_SPEED_50MHz|GPIO_OPENDRAIN|GPIO_PORTB|GPIO_PIN4)
+# define GPIO_I2C3_SDA_4 (GPIO_ALT|GPIO_AF9|GPIO_SPEED_50MHz|GPIO_OPENDRAIN|GPIO_PORTB|GPIO_PIN8)
+#endif
#define GPIO_I2C3_SMBA_1 (GPIO_ALT|GPIO_AF4|GPIO_SPEED_50MHz|GPIO_PUSHPULL|GPIO_PORTA|GPIO_PIN9)
#define GPIO_I2C3_SMBA_2 (GPIO_ALT|GPIO_AF4|GPIO_SPEED_50MHz|GPIO_PUSHPULL|GPIO_PORTH|GPIO_PIN9)
#if defined(CONFIG_STM32_STM32F446)
diff --git a/arch/arm/src/stm32/stm32_eth.c b/arch/arm/src/stm32/stm32_eth.c
index 7703a9a745e..b17077fd54d 100644
--- a/arch/arm/src/stm32/stm32_eth.c
+++ b/arch/arm/src/stm32/stm32_eth.c
@@ -90,9 +90,7 @@
# error "Logic to support multiple Ethernet interfaces is incomplete"
#endif
-/* If processing is not done at the interrupt level, then work queue support
- * is required.
- */
+/* Work queue support is required. */
#if !defined(CONFIG_SCHED_WORKQUEUE)
# error Work queue support is required
diff --git a/arch/arm/src/stm32/stm32_flash.c b/arch/arm/src/stm32/stm32_flash.c
index fb1e1cac220..1dae18724c5 100644
--- a/arch/arm/src/stm32/stm32_flash.c
+++ b/arch/arm/src/stm32/stm32_flash.c
@@ -59,10 +59,10 @@
#include "up_arch.h"
-/* Only for the STM32F[1|3|4]0xx family for now */
+/* Only for the STM32F[1|3|4]0xx family and STM32L15xx (EEPROM only) for now */
#if defined(CONFIG_STM32_STM32F10XX) || defined(CONFIG_STM32_STM32F30XX) || \
- defined (CONFIG_STM32_STM32F40XX)
+ defined (CONFIG_STM32_STM32F40XX) || defined(CONFIG_STM32_STM32L15XX)
#if defined(CONFIG_STM32_FLASH_CONFIG_DEFAULT) && \
(defined(CONFIG_STM32_STM32F20XX) || defined(CONFIG_STM32_STM32F40XX))
@@ -73,15 +73,25 @@
* Pre-processor Definitions
************************************************************************************/
-#define FLASH_KEY1 0x45670123
-#define FLASH_KEY2 0xCDEF89AB
+#if defined(CONFIG_STM32_STM32L15XX)
+# define FLASH_KEY1 0x8C9DAEBF
+# define FLASH_KEY2 0x13141516
+#else
+# define FLASH_KEY1 0x45670123
+# define FLASH_KEY2 0xCDEF89AB
+#endif
#if defined(CONFIG_STM32_STM32F10XX) || defined(CONFIG_STM32_STM32F30XX)
-#define FLASH_CR_PAGE_ERASE FLASH_CR_PER
-#define FLASH_SR_WRITE_PROTECTION_ERROR FLASH_SR_WRPRT_ERR
+# define FLASH_CR_PAGE_ERASE FLASH_CR_PER
+# define FLASH_SR_WRITE_PROTECTION_ERROR FLASH_SR_WRPRT_ERR
#elif defined(CONFIG_STM32_STM32F40XX)
-#define FLASH_CR_PAGE_ERASE FLASH_CR_SER
-#define FLASH_SR_WRITE_PROTECTION_ERROR FLASH_SR_WRPERR
+# define FLASH_CR_PAGE_ERASE FLASH_CR_SER
+# define FLASH_SR_WRITE_PROTECTION_ERROR FLASH_SR_WRPERR
+#endif
+
+#if defined(CONFIG_STM32_STM32L15XX)
+# define EEPROM_KEY1 0x89ABCDEF
+# define EEPROM_KEY2 0x02030405
#endif
/************************************************************************************
@@ -107,6 +117,8 @@ static inline void sem_unlock(void)
sem_post(&g_sem);
}
+#if !defined(CONFIG_STM32_STM32L15XX)
+
static void flash_unlock(void)
{
while (getreg32(STM32_FLASH_SR) & FLASH_SR_BSY)
@@ -128,6 +140,8 @@ static void flash_lock(void)
modifyreg32(STM32_FLASH_CR, 0, FLASH_CR_LOCK);
}
+#endif /* !defined(CONFIG_STM32_STM32L15XX) */
+
#if defined(CONFIG_STM32_FLASH_WORKAROUND_DATA_CACHE_CORRUPTION_ON_RWW)
static void data_cache_disable(void)
{
@@ -146,6 +160,183 @@ static void data_cache_enable(void)
}
#endif /* defined(CONFIG_STM32_FLASH_WORKAROUND_DATA_CACHE_CORRUPTION_ON_RWW) */
+#if defined(CONFIG_STM32_STM32L15XX)
+
+static void stm32_eeprom_unlock(void)
+{
+ while (getreg32(STM32_FLASH_SR) & FLASH_SR_BSY)
+ {
+ up_waste();
+ }
+
+ if (getreg32(STM32_FLASH_PECR) & FLASH_PECR_PELOCK)
+ {
+ /* Unlock sequence */
+
+ putreg32(EEPROM_KEY1, STM32_FLASH_PEKEYR);
+ putreg32(EEPROM_KEY2, STM32_FLASH_PEKEYR);
+ }
+}
+
+static void stm32_eeprom_lock(void)
+{
+ modifyreg32(STM32_FLASH_PECR, 0, FLASH_PECR_PELOCK);
+}
+
+static void flash_unlock(void)
+{
+ if (getreg32(STM32_FLASH_PECR) & FLASH_PECR_PRGLOCK)
+ {
+ stm32_eeprom_unlock();
+
+ /* Unlock sequence */
+
+ putreg32(FLASH_KEY1, STM32_FLASH_PRGKEYR);
+ putreg32(FLASH_KEY2, STM32_FLASH_PRGKEYR);
+ }
+}
+
+static void flash_lock(void)
+{
+ modifyreg32(STM32_FLASH_PECR, 0, FLASH_PECR_PRGLOCK);
+ stm32_eeprom_lock();
+}
+
+static ssize_t stm32_eeprom_erase_write(size_t addr, const void *buf,
+ size_t buflen)
+{
+ const char *cbuf = buf;
+ size_t i;
+
+ if (buflen == 0)
+ {
+ return 0;
+ }
+
+ /* Check for valid address range */
+
+ if (addr >= STM32_EEPROM_BASE)
+ {
+ addr -= STM32_EEPROM_BASE;
+ }
+
+ if (addr >= STM32_EEPROM_SIZE)
+ {
+ return -EINVAL;
+ }
+
+ /* TODO: Voltage range must be range 1 or 2. Erase/program not allowed in
+ * range 3.
+ */
+
+ stm32_eeprom_unlock();
+
+ /* Clear pending status flags. */
+
+ putreg32(FLASH_SR_WRPERR | FLASH_SR_PGAERR |
+ FLASH_SR_SIZERR | FLASH_SR_OPTVERR |
+ FLASH_SR_OPTVERRUSR | FLASH_SR_RDERR, STM32_FLASH_SR);
+
+ /* Enable automatic erasing (by disabling 'fixed time' programming). */
+
+ modifyreg32(STM32_FLASH_PECR, FLASH_PECR_FTDW, 0);
+
+ /* Write buffer to EEPROM data memory. */
+
+ addr += STM32_EEPROM_BASE;
+ i = 0;
+ while (i < buflen)
+ {
+ uint32_t writeval;
+ size_t left = buflen - i;
+
+ if ((addr & 0x03) == 0x00 && left >= 4)
+ {
+ /* Read/erase/write word */
+
+ writeval = cbuf ? *(uint32_t *)cbuf : 0;
+ putreg32(writeval, addr);
+ }
+ else if ((addr & 0x01) == 0x00 && left >= 2)
+ {
+ /* Read/erase/write half-word */
+
+ writeval = cbuf ? *(uint16_t *)cbuf : 0;
+ putreg16(writeval, addr);
+ }
+ else
+ {
+ /* Read/erase/write byte */
+
+ writeval = cbuf ? *(uint8_t *)cbuf : 0;
+ putreg8(writeval, addr);
+ }
+
+ /* ... and wait to complete. */
+
+ while (getreg32(STM32_FLASH_SR) & FLASH_SR_BSY)
+ {
+ up_waste();
+ }
+
+ /* Verify */
+
+ /* We do not check Options Byte invalid flags FLASH_SR_OPTVERR
+ * and FLASH_SR_OPTVERRUSR for EEPROM erase/write. They are unrelated
+ * and STM32L standard library does not check for these either.
+ */
+
+ if (getreg32(STM32_FLASH_SR) & (FLASH_SR_WRPERR | FLASH_SR_PGAERR |
+ FLASH_SR_SIZERR | FLASH_SR_RDERR))
+ {
+ stm32_eeprom_lock();
+ return -EROFS;
+ }
+
+ if ((addr & 0x03) == 0x00 && left >= 4)
+ {
+ if (getreg32(addr) != writeval)
+ {
+ stm32_eeprom_lock();
+ return -EIO;
+ }
+
+ addr += 4;
+ i += 4;
+ cbuf += !!(cbuf) * 4;
+ }
+ else if ((addr & 0x01) == 0x00 && left >= 2)
+ {
+ if (getreg16(addr) != writeval)
+ {
+ stm32_eeprom_lock();
+ return -EIO;
+ }
+
+ addr += 2;
+ i += 2;
+ cbuf += !!(cbuf) * 2;
+ }
+ else
+ {
+ if (getreg8(addr) != writeval)
+ {
+ stm32_eeprom_lock();
+ return -EIO;
+ }
+
+ addr += 1;
+ i += 1;
+ cbuf += !!(cbuf) * 1;
+ }
+ }
+
+ stm32_eeprom_lock();
+ return buflen;
+}
+
+#endif /* defined(CONFIG_STM32_STM32L15XX) */
+
/************************************************************************************
* Public Functions
************************************************************************************/
@@ -164,6 +355,35 @@ void stm32_flash_lock(void)
sem_unlock();
}
+#if defined(CONFIG_STM32_STM32L15XX)
+
+size_t stm32_eeprom_size(void)
+{
+ return STM32_EEPROM_SIZE;
+}
+
+size_t stm32_eeprom_getaddress(void)
+{
+ return STM32_EEPROM_BASE;
+}
+
+ssize_t stm32_eeprom_write(size_t addr, const void *buf, size_t buflen)
+{
+ if (!buf)
+ {
+ return -EINVAL;
+ }
+
+ return stm32_eeprom_erase_write(addr, buf, buflen);
+}
+
+ssize_t stm32_eeprom_erase(size_t addr, size_t eraselen)
+{
+ return stm32_eeprom_erase_write(addr, NULL, eraselen);
+}
+
+#endif /* defined(CONFIG_STM32_STM32L15XX) */
+
#if defined(CONFIG_STM32_STM32F10XX) || defined(CONFIG_STM32_STM32F30XX)
size_t up_progmem_pagesize(size_t page)
{
@@ -260,6 +480,8 @@ size_t up_progmem_getaddress(size_t page)
#endif /* def CONFIG_STM32_STM32F40XX */
+#if !defined(CONFIG_STM32_STM32L15XX)
+
size_t up_progmem_npages(void)
{
return STM32_FLASH_NPAGES;
@@ -271,14 +493,14 @@ bool up_progmem_isuniform(void)
return true;
#else
return false;
-#endif /* def STM32_FLASH_PAGESIZE */
+#endif
}
ssize_t up_progmem_erasepage(size_t page)
{
#if defined(CONFIG_STM32_STM32F10XX) || defined(CONFIG_STM32_STM32F30XX)
size_t page_address;
-#endif /* defined(CONFIG_STM32_STM32F10XX) || defined(CONFIG_STM32_STM32F30XX) */
+#endif
if (page >= STM32_FLASH_NPAGES)
{
@@ -438,5 +660,7 @@ ssize_t up_progmem_write(size_t addr, const void *buf, size_t count)
return written;
}
+#endif /* !defined(CONFIG_STM32_STM32L15XX) */
+
#endif /* defined(CONFIG_STM32_STM32F10XX) || defined(CONFIG_STM32_STM32F30XX) || \
- defined (CONFIG_STM32_STM32F40XX) */
+ defined(CONFIG_STM32_STM32F40XX) || defined(CONFIG_STM32_STM32L15XX) */
diff --git a/arch/arm/src/stm32/stm32_flash.h b/arch/arm/src/stm32/stm32_flash.h
index 10c5cc189ed..6da1b0b7034 100644
--- a/arch/arm/src/stm32/stm32_flash.h
+++ b/arch/arm/src/stm32/stm32_flash.h
@@ -46,4 +46,60 @@
#include "chip.h"
#include "chip/stm32_flash.h"
+/************************************************************************************
+ * Public Function Prototypes
+ ************************************************************************************/
+
+/************************************************************************************
+ * Name: stm32_eeprom_size
+ *
+ * Description:
+ * Get EEPROM data memory size
+ *
+ * Returns:
+ * Length of EEPROM memory region
+ *
+ ************************************************************************************/
+
+size_t stm32_eeprom_size(void);
+
+/************************************************************************************
+ * Name: stm32_eeprom_getaddress
+ *
+ * Description:
+ * Get EEPROM data memory address
+ *
+ * Returns:
+ * Address of EEPROM memory region
+ *
+ ************************************************************************************/
+
+size_t stm32_eeprom_getaddress(void);
+
+/************************************************************************************
+ * Name: stm32_eeprom_write
+ *
+ * Description:
+ * Write buffer to EEPROM data memory address
+ *
+ * Returns:
+ * Number of written bytes or error code.
+ *
+ ************************************************************************************/
+
+ssize_t stm32_eeprom_write(size_t addr, const void *buf, size_t buflen);
+
+/************************************************************************************
+ * Name: stm32_eeprom_erase
+ *
+ * Description:
+ * Erase memory on EEPROM data memory address
+ *
+ * Returns:
+ * Number of erased bytes or error code.
+ *
+ ************************************************************************************/
+
+ssize_t stm32_eeprom_erase(size_t addr, size_t eraselen);
+
#endif /* __ARCH_ARM_SRC_STM32_STM32_FLASH_H */
diff --git a/arch/arm/src/stm32/stm32_iwdg.c b/arch/arm/src/stm32/stm32_iwdg.c
index 1cdf8e47bc0..64495b71ab9 100644
--- a/arch/arm/src/stm32/stm32_iwdg.c
+++ b/arch/arm/src/stm32/stm32_iwdg.c
@@ -634,8 +634,8 @@ static int stm32_settimeout(FAR struct watchdog_lowerhalf_s *lower,
* Name: stm32_iwdginitialize
*
* Description:
- * Initialize the IWDG watchdog time. The watchdog timer is initialized and
- * registers as 'devpath. The initial state of the watchdog time is
+ * Initialize the IWDG watchdog timer. The watchdog timer is initialized and
+ * registers as 'devpath'. The initial state of the watchdog timer is
* disabled.
*
* Input Parameters:
@@ -665,7 +665,7 @@ void stm32_iwdginitialize(FAR const char *devpath, uint32_t lsifreq)
priv->started = false;
/* Make sure that the LSI oscillator is enabled. NOTE: The LSI oscillator
- * is enabled here but is not disabled by this file (because this file does
+ * is enabled here but is not disabled by this file, because this file does
* not know the global usage of the oscillator. Any clock management
* logic (say, as part of a power management scheme) needs handle other
* LSI controls outside of this file.
@@ -685,9 +685,9 @@ void stm32_iwdginitialize(FAR const char *devpath, uint32_t lsifreq)
(void)watchdog_register(devpath, (FAR struct watchdog_lowerhalf_s *)priv);
- /* When the microcontroller enters debug mode (Cortex™-M4F core halted),
+ /* When the microcontroller enters debug mode (Cortex-M4F core halted),
* the IWDG counter either continues to work normally or stops, depending
- * on DBG_WIDG_STOP configuration bit in DBG module.
+ * on DBG_IWDG_STOP configuration bit in DBG module.
*/
#if defined(CONFIG_STM32_JTAG_FULL_ENABLE) || \
@@ -695,7 +695,7 @@ void stm32_iwdginitialize(FAR const char *devpath, uint32_t lsifreq)
defined(CONFIG_STM32_JTAG_SW_ENABLE)
{
#if defined(CONFIG_STM32_STM32F20XX) || defined(CONFIG_STM32_STM32F30XX) || \
- defined(CONFIG_STM32_STM32F40XX)
+ defined(CONFIG_STM32_STM32F40XX) || defined(CONFIG_STM32_STM32L15XX)
uint32_t cr = getreg32(STM32_DBGMCU_APB1_FZ);
cr |= DBGMCU_APB1_IWDGSTOP;
putreg32(cr, STM32_DBGMCU_APB1_FZ);
diff --git a/arch/arm/src/stm32/stm32_wwdg.c b/arch/arm/src/stm32/stm32_wwdg.c
index a299de8c991..c0cb34f1f71 100644
--- a/arch/arm/src/stm32/stm32_wwdg.c
+++ b/arch/arm/src/stm32/stm32_wwdg.c
@@ -734,8 +734,8 @@ static int stm32_ioctl(FAR struct watchdog_lowerhalf_s *lower, int cmd,
* Name: stm32_wwdginitialize
*
* Description:
- * Initialize the WWDG watchdog time. The watchdog timer is initialized and
- * registers as 'devpath. The initial state of the watchdog time is
+ * Initialize the WWDG watchdog timer. The watchdog timer is initialized and
+ * registers as 'devpath'. The initial state of the watchdog timer is
* disabled.
*
* Input Parameters:
@@ -753,7 +753,7 @@ void stm32_wwdginitialize(FAR const char *devpath)
wdinfo("Entry: devpath=%s\n", devpath);
- /* NOTE we assume that clocking to the IWDG has already been provided by
+ /* NOTE we assume that clocking to the WWDG has already been provided by
* the RCC initialization logic.
*/
@@ -780,7 +780,7 @@ void stm32_wwdginitialize(FAR const char *devpath)
(void)watchdog_register(devpath, (FAR struct watchdog_lowerhalf_s *)priv);
- /* When the microcontroller enters debug mode (Cortex�-M4F core halted),
+ /* When the microcontroller enters debug mode (Cortex-M core halted),
* the WWDG counter either continues to work normally or stops, depending
* on DBG_WWDG_STOP configuration bit in DBG module.
*/
@@ -790,7 +790,7 @@ void stm32_wwdginitialize(FAR const char *devpath)
defined(CONFIG_STM32_JTAG_SW_ENABLE)
{
#if defined(CONFIG_STM32_STM32F20XX) || defined(CONFIG_STM32_STM32F30XX) || \
- defined(CONFIG_STM32_STM32F40XX)
+ defined(CONFIG_STM32_STM32F40XX) || defined(CONFIG_STM32_STM32L15XX)
uint32_t cr = getreg32(STM32_DBGMCU_APB1_FZ);
cr |= DBGMCU_APB1_WWDGSTOP;
putreg32(cr, STM32_DBGMCU_APB1_FZ);
diff --git a/arch/arm/src/stm32/stm32l15xxx_rcc.c b/arch/arm/src/stm32/stm32l15xxx_rcc.c
index 51a163d99a1..2624fade10d 100644
--- a/arch/arm/src/stm32/stm32l15xxx_rcc.c
+++ b/arch/arm/src/stm32/stm32l15xxx_rcc.c
@@ -524,6 +524,8 @@ static void stm32_stdclockconfig(void)
#if defined(CONFIG_RTC_HSECLOCK) || defined(CONFIG_LCD_HSECLOCK)
uint16_t pwrcr;
#endif
+ uint32_t pwr_vos;
+ bool flash_1ws;
/* Enable PWR clock from APB1 to give access to PWR_CR register */
@@ -537,12 +539,39 @@ static void stm32_stdclockconfig(void)
* Range 1: PLLVCO up to 96MHz in range 1 (1.8V)
* Range 2: PLLVCO up to 48MHz in range 2 (1.5V) (default)
* Range 3: PLLVCO up to 24MHz in range 3 (1.2V)
+ *
+ * Range 1: SYSCLK up to 32Mhz
+ * Range 2: SYSCLK up to 16Mhz
+ * Range 3: SYSCLK up to 4.2Mhz
+ *
+ * Range 1: Flash 1WS if SYSCLK > 16Mhz
+ * Range 2: Flash 1WS if SYSCLK > 8Mhz
+ * Range 3: Flash 1WS if SYSCLK > 2.1Mhz
*/
-#if STM32_PLL_FREQUENCY > 48000000
- stm32_pwr_setvos(PWR_CR_VOS_SCALE_1);
+ pwr_vos = PWR_CR_VOS_SCALE_2;
+ flash_1ws = false;
+
+#ifdef STM32_PLL_FREQUENCY
+ if (STM32_PLL_FREQUENCY > 48000000)
+ {
+ pwr_vos = PWR_CR_VOS_SCALE_1;
+ }
#endif
+ if (STM32_SYSCLK_FREQUENCY > 16000000)
+ {
+ pwr_vos = PWR_CR_VOS_SCALE_1;
+ }
+
+ if ((pwr_vos == PWR_CR_VOS_SCALE_1 && STM32_SYSCLK_FREQUENCY > 16000000) ||
+ (pwr_vos == PWR_CR_VOS_SCALE_2 && STM32_SYSCLK_FREQUENCY > 8000000))
+ {
+ flash_1ws = true;
+ }
+
+ stm32_pwr_setvos(pwr_vos);
+
#if defined(CONFIG_RTC_HSECLOCK) || defined(CONFIG_LCD_HSECLOCK)
/* If RTC / LCD selects HSE as clock source, the RTC prescaler
* needs to be set before HSEON bit is set.
@@ -579,12 +608,11 @@ static void stm32_stdclockconfig(void)
#endif
- /* Enable the source clock for the PLL (via HSE or HSI), HSE, and HSI.
- * NOTE that only PLL, HSE, or HSI are supported for the system clock
- * in this implementation
- */
+ /* Enable the source clock for the PLL (via HSE or HSI), HSE, and HSI. */
+
+#if (STM32_SYSCLK_SW == RCC_CFGR_SW_HSE) || \
+ ((STM32_SYSCLK_SW == RCC_CFGR_SW_PLL) && (STM32_CFGR_PLLSRC == RCC_CFGR_PLLSRC))
-#if (STM32_CFGR_PLLSRC == RCC_CFGR_PLLSRC) || (STM32_SYSCLK_SW == RCC_CFGR_SW_HSE)
/* The PLL is using the HSE, or the HSE is the system clock. In either
* case, we need to enable HSE clocking.
*/
@@ -599,7 +627,9 @@ static void stm32_stdclockconfig(void)
return;
}
-#elif (STM32_CFGR_PLLSRC == 0) || (STM32_SYSCLK_SW == RCC_CFGR_SW_HSI)
+#elif (STM32_SYSCLK_SW == RCC_CFGR_SW_HSI) || \
+ ((STM32_SYSCLK_SW == RCC_CFGR_SW_PLL) && STM32_CFGR_PLLSRC == 0)
+
/* The PLL is using the HSI, or the HSI is the system clock. In either
* case, we need to enable HSI clocking.
*/
@@ -616,6 +646,8 @@ static void stm32_stdclockconfig(void)
#endif
+#if (STM32_SYSCLK_SW != RCC_CFGR_SW_MSI)
+
/* Increasing the CPU frequency (in the same voltage range):
*
* After reset, the used clock is the MSI (2 MHz) with 0 WS configured in the
@@ -643,7 +675,15 @@ static void stm32_stdclockconfig(void)
regval |= FLASH_ACR_ACC64; /* 64-bit access mode */
putreg32(regval, STM32_FLASH_ACR);
- regval |= FLASH_ACR_LATENCY; /* One wait state */
+ if (flash_1ws)
+ {
+ regval |= FLASH_ACR_LATENCY; /* One wait state */
+ }
+ else
+ {
+ regval &= ~FLASH_ACR_LATENCY; /* Zero wait state */
+ }
+
putreg32(regval, STM32_FLASH_ACR);
/* Enable FLASH prefetch */
@@ -651,6 +691,8 @@ static void stm32_stdclockconfig(void)
regval |= FLASH_ACR_PRFTEN;
putreg32(regval, STM32_FLASH_ACR);
+#endif /* STM32_SYSCLK_SW != RCC_CFGR_SW_MSI */
+
/* Set the HCLK source/divider */
regval = getreg32(STM32_RCC_CFGR);
diff --git a/arch/arm/src/stm32f7/Kconfig b/arch/arm/src/stm32f7/Kconfig
index ff7dfe80cfd..e727aef24aa 100644
--- a/arch/arm/src/stm32f7/Kconfig
+++ b/arch/arm/src/stm32f7/Kconfig
@@ -1823,7 +1823,7 @@ config STM32F7_HAVE_RTC_COUNTER
config STM32F7_HAVE_RTC_SUBSECONDS
bool
- default n
+ default y
config RTC_MAGIC_REG
int "The BKP register used to store/check the Magic value to determine if RTC is set already"
diff --git a/arch/arm/src/stm32f7/Make.defs b/arch/arm/src/stm32f7/Make.defs
index 8baa4fbf135..06a190f463f 100644
--- a/arch/arm/src/stm32f7/Make.defs
+++ b/arch/arm/src/stm32f7/Make.defs
@@ -149,6 +149,10 @@ ifeq ($(filter y,$(CONFIG_STM32F7_IWDG) $(CONFIG_STM32F7_RTC_LSICLOCK)),y)
CHIP_CSRCS += stm32_lsi.c
endif
+ifeq ($(CONFIG_STM32F7_RTC_LSECLOCK),y)
+CHIP_CSRCS += stm32_lse.c
+endif
+
ifeq ($(CONFIG_STM32F7_I2C),y)
CHIP_CSRCS += stm32_i2c.c
endif
diff --git a/arch/arm/src/stm32f7/stm32_exti_pwr.c b/arch/arm/src/stm32f7/stm32_exti_pwr.c
index 09d064e930e..3c4f2d07a3b 100644
--- a/arch/arm/src/stm32f7/stm32_exti_pwr.c
+++ b/arch/arm/src/stm32f7/stm32_exti_pwr.c
@@ -129,7 +129,7 @@ static int stm32_exti_pvd_isr(int irq, void *context, void *arg)
****************************************************************************/
int stm32_exti_pvd(bool risingedge, bool fallingedge, bool event,
- xcpt_t func, void *arg);
+ xcpt_t func, void *arg)
{
/* Get the previous GPIO IRQ handler; Save the new IRQ handler. */
diff --git a/net/sixlowpan/sixlowpan_sniffer.c b/arch/arm/src/stm32f7/stm32_lse.c
similarity index 69%
rename from net/sixlowpan/sixlowpan_sniffer.c
rename to arch/arm/src/stm32f7/stm32_lse.c
index 32a2e3121e1..162630060b9 100644
--- a/net/sixlowpan/sixlowpan_sniffer.c
+++ b/arch/arm/src/stm32f7/stm32_lse.c
@@ -1,8 +1,9 @@
/****************************************************************************
- * net/sixlowpan/sixlowpan_sniffer.c
+ * arch/arm/src/stm32f7/stm32_lse.c
*
* Copyright (C) 2017 Gregory Nutt. All rights reserved.
- * Author: Gregory Nutt
+ * Authors: Gregory Nutt
+ * David Sidrane
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -39,43 +40,47 @@
#include
-#include "nuttx/net/net.h"
-#include "nuttx/net/sixlowpan.h"
+#include "up_arch.h"
-#include "sixlowpan/sixlowpan_internal.h"
-
-#ifdef CONFIG_NET_6LOWPAN_SNIFFER
+#include "stm32_rcc.h"
+#include "stm32_pwr.h"
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
- * Function: sixlowpan_set_sniffer
+ * Name: stm32_rcc_enablelse
*
* Description:
- * Configure to use an architecture-specific sniffer to enable tracing of
- * IP.
- *
- * Input parameters:
- * sniffer - A reference to the new sniffer to be used. This may
- * be a NULL value to disable the sniffer.
- *
- * Returned Value:
- * None
+ * Enable the External Low-Speed (LSE) oscillator.
*
****************************************************************************/
-void sixlowpan_set_sniffer(FAR struct sixlowpan_rime_sniffer_s *sniffer)
+void stm32_rcc_enablelse(void)
{
- /* Make sure that the sniffer is not in use */
+ uint32_t regval;
- net_lock();
+ /* The LSE is in the RTC domain and write access is denied to this domain
+ * after reset, you have to enable write access using DBP bit in the PWR CR
+ * register before to configuring the LSE.
+ */
- /* Then instantiate the new sniffer */
+ stm32_pwr_enablebkp(true);
- g_sixlowpan_sniffer = sniffer;
- net_unlock();
+ /* Enable the External Low-Speed (LSE) oscillator by setting the LSEON bit
+ * the RCC BDCR register.
+ */
+
+ regval = getreg32(STM32_RCC_BDCR);
+ regval |= RCC_BDCR_LSEON;
+ putreg32(regval,STM32_RCC_BDCR);
+
+ /* Wait for the LSE clock to be ready */
+
+ while (((regval = getreg32(STM32_RCC_BDCR)) & RCC_BDCR_LSERDY) == 0);
+
+ /* Disable backup domain access if it was disabled on entry */
+
+ stm32_pwr_enablebkp(false);
}
-
-#endif /* CONFIG_NET_6LOWPAN_SNIFFER */
diff --git a/arch/arm/src/stm32f7/stm32_lsi.c b/arch/arm/src/stm32f7/stm32_lsi.c
index 46e96163727..636662721b5 100644
--- a/arch/arm/src/stm32f7/stm32_lsi.c
+++ b/arch/arm/src/stm32f7/stm32_lsi.c
@@ -1,5 +1,5 @@
/****************************************************************************
- * arch/arm/src/stm32f/stm32_lsi.c
+ * arch/arm/src/stm32f7/stm32_lsi.c
*
* Copyright (C) 2012, 2015-2016 Gregory Nutt. All rights reserved.
* Authors: Gregory Nutt
diff --git a/arch/arm/src/stm32f7/stm32_rtc.c b/arch/arm/src/stm32f7/stm32_rtc.c
index 8a21ec41fea..2840fac8a5d 100644
--- a/arch/arm/src/stm32f7/stm32_rtc.c
+++ b/arch/arm/src/stm32f7/stm32_rtc.c
@@ -196,7 +196,7 @@ static void rtc_dumpregs(FAR const char *msg)
rtcinfo(" TSDR: %08x\n", getreg32(STM32_RTC_TSDR));
rtcinfo(" TSSSR: %08x\n", getreg32(STM32_RTC_TSSSR));
rtcinfo(" CALR: %08x\n", getreg32(STM32_RTC_CALR));
- rtcinfo(" TAFCR: %08x\n", getreg32(STM32_RTC_TAFCR));
+ rtcinfo(" TAMPCR: %08x\n", getreg32(STM32_RTC_TAMPCR));
rtcinfo("ALRMASSR: %08x\n", getreg32(STM32_RTC_ALRMASSR));
rtcinfo("ALRMBSSR: %08x\n", getreg32(STM32_RTC_ALRMBSSR));
rtcinfo("MAGICREG: %08x\n", getreg32(RTC_MAGIC_REG));
@@ -227,7 +227,8 @@ static void rtc_dumpregs(FAR const char *msg)
****************************************************************************/
#ifdef CONFIG_DEBUG_RTC_INFO
-static void rtc_dumptime(FAR const struct tm *tp, FAR const char *msg)
+static void rtc_dumptime(FAR const struct tm *tp, FAR const uint32_t *usecs,
+ FAR const char *msg)
{
rtcinfo("%s:\n", msg);
rtcinfo(" tm_sec: %08x\n", tp->tm_sec);
@@ -236,9 +237,14 @@ static void rtc_dumptime(FAR const struct tm *tp, FAR const char *msg)
rtcinfo(" tm_mday: %08x\n", tp->tm_mday);
rtcinfo(" tm_mon: %08x\n", tp->tm_mon);
rtcinfo(" tm_year: %08x\n", tp->tm_year);
+
+ if (usecs != NULL)
+ {
+ rtcinfo(" usecs: %08x\n", (unsigned int)*usecs);
+ }
}
#else
-# define rtc_dumptime(tp, msg)
+# define rtc_dumptime(tp, usecs, msg)
#endif
/****************************************************************************
@@ -1069,34 +1075,48 @@ int up_rtc_initialize(void)
*
****************************************************************************/
-#ifdef CONFIG_STM32_HAVE_RTC_SUBSECONDS
+#ifdef CONFIG_STM32F7_HAVE_RTC_SUBSECONDS
int stm32_rtc_getdatetime_with_subseconds(FAR struct tm *tp, FAR long *nsec)
#else
int up_rtc_getdatetime(FAR struct tm *tp)
#endif
{
-#ifdef CONFIG_STM32_HAVE_RTC_SUBSECONDS
- uint32_t ssr;
-#endif
uint32_t dr;
uint32_t tr;
uint32_t tmp;
+#ifdef CONFIG_STM32F7_HAVE_RTC_SUBSECONDS
+ uint32_t ssr;
+ uint32_t prediv_s;
+ uint32_t usecs;
+#endif
/* Sample the data time registers. There is a race condition here... If
* we sample the time just before midnight on December 31, the date could
- * be wrong because the day rolled over while were sampling.
+ * be wrong because the day rolled over while were sampling. Thus loop for
+ * checking overflow here is needed. There is a race condition with
+ * subseconds too. If we sample TR register just before second rolling
+ * and subseconds are read at wrong second, we get wrong time.
*/
do
{
dr = getreg32(STM32_RTC_DR);
tr = getreg32(STM32_RTC_TR);
-#ifdef CONFIG_STM32_HAVE_RTC_SUBSECONDS
+#ifdef CONFIG_STM32F7_HAVE_RTC_SUBSECONDS
ssr = getreg32(STM32_RTC_SSR);
+ tmp = getreg32(STM32_RTC_TR);
+ if (tmp != tr)
+ {
+ continue;
+ }
#endif
tmp = getreg32(STM32_RTC_DR);
+ if (tmp == dr)
+ {
+ break;
+ }
}
- while (tmp != dr);
+ while (1);
rtc_dumpregs("Reading Time");
@@ -1141,31 +1161,31 @@ int up_rtc_getdatetime(FAR struct tm *tp)
tp->tm_isdst = 0
#endif
-#ifdef CONFIG_STM32_HAVE_RTC_SUBSECONDS
+#ifdef CONFIG_STM32F7_HAVE_RTC_SUBSECONDS
/* Return RTC sub-seconds if no configured and if a non-NULL value
* of nsec has been provided to receive the sub-second value.
*/
- if (nsec)
+ prediv_s = getreg32(STM32_RTC_PRER) & RTC_PRER_PREDIV_S_MASK;
+ prediv_s >>= RTC_PRER_PREDIV_S_SHIFT;
+
+ ssr &= RTC_SSR_MASK;
+
+ /* Maximum prediv_s is 0x7fff, thus we can multiply by 100000 and
+ * still fit 32-bit unsigned integer.
+ */
+
+ usecs = (((prediv_s - ssr) * 100000) / (prediv_s + 1)) * 10;
+ if (nsec != NULL)
{
- uint32_t prediv_s;
- uint32_t usecs;
-
- prediv_s = getreg32(STM32_RTC_PRER) & RTC_PRER_PREDIV_S_MASK;
- prediv_s >>= RTC_PRER_PREDIV_S_SHIFT;
-
- ssr &= RTC_SSR_MASK;
-
- /* Maximum prediv_s is 0x7fff, thus we can multiply by 100000 and
- * still fit 32-bit unsigned integer.
- */
-
- usecs = (((prediv_s - ssr) * 100000) / (prediv_s + 1)) * 10;
*nsec = usecs * 1000;
}
-#endif /* CONFIG_STM32_HAVE_RTC_SUBSECONDS */
- rtc_dumptime((FAR const struct tm *)tp, "Returning");
+ rtc_dumptime((FAR const struct tm *)tp, &usecs, "Returning");
+#else /* CONFIG_STM32_HAVE_RTC_SUBSECONDS */
+ rtc_dumptime((FAR const struct tm *)tp, NULL, "Returning");
+#endif
+
return OK;
}
@@ -1192,7 +1212,7 @@ int up_rtc_getdatetime(FAR struct tm *tp)
*
****************************************************************************/
-#ifdef CONFIG_STM32_HAVE_RTC_SUBSECONDS
+#ifdef CONFIG_STM32F7_HAVE_RTC_SUBSECONDS
int up_rtc_getdatetime(FAR struct tm *tp)
{
return stm32_rtc_getdatetime_with_subseconds(tp, NULL);
@@ -1221,7 +1241,7 @@ int stm32_rtc_setdatetime(FAR const struct tm *tp)
uint32_t dr;
int ret;
- rtc_dumptime(tp, "Setting time");
+ rtc_dumptime(tp, NULL, "Setting time");
/* Then write the broken out values to the RTC */
@@ -1337,7 +1357,7 @@ int stm32_rtc_setalarm(FAR struct alm_setalarm_s *alminfo)
/* REVISIT: Should test that the time is in the future */
- rtc_dumptime(&alminfo->as_time, "New alarm time");
+ rtc_dumptime(&alminfo->as_time, NULL, "New alarm time");
/* Break out the values to the HW alarm register format. The values in
* all STM32 fields match the fields of struct tm in this case. Notice
diff --git a/arch/arm/src/stm32f7/stm32_sdmmc.c b/arch/arm/src/stm32f7/stm32_sdmmc.c
index 2249dc87c3b..9225312bd1b 100644
--- a/arch/arm/src/stm32f7/stm32_sdmmc.c
+++ b/arch/arm/src/stm32f7/stm32_sdmmc.c
@@ -1510,7 +1510,7 @@ static int stm32_sdmmc_rdyinterrupt(int irq, void *context, void *arg)
*
****************************************************************************/
-static int stm32_sdmmc_interrupt(int irq, void *context, void *arg);
+static int stm32_sdmmc_interrupt(int irq, void *context, void *arg)
{
struct stm32_dev_s *priv =(struct stm32_dev_s *)arg;
uint32_t enabled;
diff --git a/arch/arm/src/stm32f7/stm32_serial.c b/arch/arm/src/stm32f7/stm32_serial.c
index 77138526dd6..b839aad8f44 100644
--- a/arch/arm/src/stm32f7/stm32_serial.c
+++ b/arch/arm/src/stm32f7/stm32_serial.c
@@ -1,8 +1,9 @@
/****************************************************************************
* arch/arm/src/stm32f7/stm32_serial.c
*
- * Copyright (C) 2015-2016 Gregory Nutt. All rights reserved.
- * Author: Gregory Nutt
+ * Copyright (C) 2015-2017 Gregory Nutt. All rights reserved.
+ * Authors: Gregory Nutt
+ * David Sidrane
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -189,16 +190,6 @@
CONFIG_USART_DMAPRIO | \
DMA_SCR_PBURST_SINGLE | \
DMA_SCR_MBURST_SINGLE)
-# ifdef CONFIG_SERIAL_IFLOWCONTROL
-# define SERIAL_DMA_IFLOW_CONTROL_WORD \
- (DMA_SCR_DIR_P2M | \
- DMA_SCR_MINC | \
- DMA_SCR_PSIZE_8BITS | \
- DMA_SCR_MSIZE_8BITS | \
- CONFIG_USART_DMAPRIO | \
- DMA_SCR_PBURST_SINGLE | \
- DMA_SCR_MBURST_SINGLE)
-# endif
#endif /* SERIAL_HAVE_DMA */
/* Power management definitions */
@@ -286,8 +277,7 @@ struct up_dev_s
#ifdef SERIAL_HAVE_DMA
DMA_HANDLE rxdma; /* currently-open receive DMA stream */
bool rxenable; /* DMA-based reception en/disable */
- uint16_t rxdmain; /* Next byte in the DMA where hardware will write */
- uint16_t rxdmaout; /* Next byte in the DMA buffer to be read */
+ uint32_t rxdmanext; /* Next byte in the DMA buffer to be read */
char *const rxfifo; /* Receive DMA buffer */
#endif
@@ -1139,7 +1129,22 @@ static void up_set_format(struct uart_dev_s *dev)
uint32_t regval;
uint32_t usartdiv8;
uint32_t cr1;
+ uint32_t cr1_ue;
uint32_t brr;
+ irqstate_t flags;
+
+ flags = enter_critical_section();
+
+ /* Get the original state of UE */
+
+ cr1 = up_serialin(priv, STM32_USART_CR1_OFFSET);
+ cr1_ue = cr1 & USART_CR1_UE;
+ cr1 &= ~USART_CR1_UE;
+
+ /* Disable UE as the format bits and baud rate registers can not be
+ * updated while UE = 1 */
+
+ up_serialout(priv, STM32_USART_CR1_OFFSET, cr1);
/* In case of oversampling by 8, the equation is:
*
@@ -1159,7 +1164,6 @@ static void up_set_format(struct uart_dev_s *dev)
/* Use oversamply by 8 only if the divisor is small. But what is small? */
- cr1 = up_serialin(priv, STM32_USART_CR1_OFFSET);
if (usartdiv8 > 100)
{
/* Use usartdiv16 */
@@ -1188,30 +1192,44 @@ static void up_set_format(struct uart_dev_s *dev)
/* Configure parity mode */
- regval = up_serialin(priv, STM32_USART_CR1_OFFSET);
- regval &= ~(USART_CR1_PCE | USART_CR1_PS | USART_CR1_M0);
+ cr1 &= ~(USART_CR1_PCE | USART_CR1_PS | USART_CR1_M0 | USART_CR1_M1);
if (priv->parity == 1) /* Odd parity */
{
- regval |= (USART_CR1_PCE | USART_CR1_PS);
+ cr1 |= (USART_CR1_PCE | USART_CR1_PS);
}
else if (priv->parity == 2) /* Even parity */
{
- regval |= USART_CR1_PCE;
+ cr1 |= USART_CR1_PCE;
}
- /* Configure word length (Default: 8-bits) */
+ /* Configure word length (parity uses one of configured bits)
+ *
+ * Default: 1 start, 8 data (no parity), n stop, OR
+ * 1 start, 7 data + parity, n stop
+ */
- if (priv->bits == 7)
+ if (priv->bits == 9 || (priv->bits == 8 && priv->parity != 0))
{
- regval |= USART_CR1_M1;
+ /* Select: 1 start, 8 data + parity, n stop, OR
+ * 1 start, 9 data (no parity), n stop.
+ */
+
+ cr1 |= USART_CR1_M0;
}
- else if (priv->bits == 9)
+ else if (priv->bits == 7 && priv->parity == 0)
{
- regval |= USART_CR1_M0;
+ /* Select: 1 start, 7 data (no parity), n stop, OR
+ */
+
+ cr1 |= USART_CR1_M1;
}
- up_serialout(priv, STM32_USART_CR1_OFFSET, regval);
+ /* Else Select: 1 start, 7 data + parity, n stop, OR
+ * 1 start, 8 data (no parity), n stop.
+ */
+
+ up_serialout(priv, STM32_USART_CR1_OFFSET, cr1);
/* Configure STOP bits */
@@ -1230,7 +1248,8 @@ static void up_set_format(struct uart_dev_s *dev)
regval = up_serialin(priv, STM32_USART_CR3_OFFSET);
regval &= ~(USART_CR3_CTSE | USART_CR3_RTSE);
-#if defined(CONFIG_SERIAL_IFLOWCONTROL) && !defined(CONFIG_STM32F7_FLOWCONTROL_BROKEN)
+#if defined(CONFIG_SERIAL_IFLOWCONTROL) && \
+ !defined(CONFIG_STM32F7_FLOWCONTROL_BROKEN)
if (priv->iflow && (priv->rts_gpio != 0))
{
regval |= USART_CR3_RTSE;
@@ -1245,6 +1264,8 @@ static void up_set_format(struct uart_dev_s *dev)
#endif
up_serialout(priv, STM32_USART_CR3_OFFSET, regval);
+ up_serialout(priv, STM32_USART_CR1_OFFSET, cr1 | cr1_ue);
+ leave_critical_section(flags);
}
#endif /* CONFIG_SUPPRESS_UART_CONFIG */
@@ -1473,35 +1494,19 @@ static int up_dma_setup(struct uart_dev_s *dev)
priv->rxdma = stm32_dmachannel(priv->rxdma_channel);
-#ifdef CONFIG_SERIAL_IFLOWCONTROL
- if (priv->iflow)
- {
- /* Configure for non-circular DMA reception into the RX FIFO */
+ /* Configure for circular DMA reception into the RX FIFO */
- stm32_dmasetup(priv->rxdma,
- priv->usartbase + STM32_USART_RDR_OFFSET,
- (uint32_t)priv->rxfifo,
- RXDMA_BUFFER_SIZE,
- SERIAL_DMA_IFLOW_CONTROL_WORD);
- }
- else
-#endif
- {
- /* Configure for circular DMA reception into the RX FIFO */
-
- stm32_dmasetup(priv->rxdma,
- priv->usartbase + STM32_USART_RDR_OFFSET,
- (uint32_t)priv->rxfifo,
- RXDMA_BUFFER_SIZE,
- SERIAL_DMA_CONTROL_WORD);
- }
+ stm32_dmasetup(priv->rxdma,
+ priv->usartbase + STM32_USART_RDR_OFFSET,
+ (uint32_t)priv->rxfifo,
+ RXDMA_BUFFER_SIZE,
+ SERIAL_DMA_CONTROL_WORD);
/* Reset our DMA shadow pointer to match the address just
* programmed above.
*/
- priv->rxdmaout = 0;
- priv->rxdmain = 0;
+ priv->rxdmanext = 0;
/* Enable receive DMA for the UART */
@@ -1509,26 +1514,12 @@ static int up_dma_setup(struct uart_dev_s *dev)
regval |= USART_CR3_DMAR;
up_serialout(priv, STM32_USART_CR3_OFFSET, regval);
-#ifdef CONFIG_SERIAL_IFLOWCONTROL
- if (priv->iflow)
- {
- /* Start the DMA channel, and arrange for callbacks at the full point
- * in the FIFO. After buffer gets full, hardware flow-control kicks
- * in and DMA transfer is stopped.
- */
+ /* Start the DMA channel, and arrange for callbacks at the half and
+ * full points in the FIFO. This ensures that we have half a FIFO
+ * worth of time to claim bytes before they are overwritten.
+ */
- stm32_dmastart(priv->rxdma, up_dma_rxcallback, (void *)priv, false);
- }
- else
-#endif
- {
- /* Start the DMA channel, and arrange for callbacks at the half and
- * full points in the FIFO. This ensures that we have half a FIFO
- * worth of time to claim bytes before they are overwritten.
- */
-
- stm32_dmastart(priv->rxdma, up_dma_rxcallback, (void *)priv, true);
- }
+ stm32_dmastart(priv->rxdma, up_dma_rxcallback, (void *)priv, true);
return OK;
}
@@ -2226,49 +2217,27 @@ static bool up_rxflowcontrol(struct uart_dev_s *dev,
static int up_dma_receive(struct uart_dev_s *dev, unsigned int *status)
{
struct up_dev_s *priv = (struct up_dev_s *)dev->priv;
- uint32_t rxdmain;
int c = 0;
/* If additional bytes have been added to the DMA buffer, then we will need
* to invalidate the DMA buffer before reading the byte.
*/
- rxdmain = up_dma_nextrx(priv);
- if (rxdmain != priv->rxdmain)
+ if (up_dma_nextrx(priv) != priv->rxdmanext)
{
/* Invalidate the DMA buffer */
arch_invalidate_dcache((uintptr_t)priv->rxfifo,
(uintptr_t)priv->rxfifo + RXDMA_BUFFER_SIZE - 1);
- /* Since DMA is ongoing, there are lots of race conditions here. We
- * just have to hope that the rxdmaout stays well ahead of rxdmain.
- */
+ /* Now read from the DMA buffer */
- priv->rxdmain = rxdmain;
- }
+ c = priv->rxfifo[priv->rxdmanext];
- /* Now check if there are any bytes to read from the DMA buffer */
-
- if (rxdmain != priv->rxdmaout)
- {
- c = priv->rxfifo[priv->rxdmaout];
-
- priv->rxdmaout++;
- if (priv->rxdmaout == RXDMA_BUFFER_SIZE)
+ priv->rxdmanext++;
+ if (priv->rxdmanext == RXDMA_BUFFER_SIZE)
{
-#ifdef CONFIG_SERIAL_IFLOWCONTROL
- if (priv->iflow)
- {
- /* RX DMA buffer full. RX paused, RTS line pulled up to prevent
- * more input data from other end.
- */
- }
- else
-#endif
- {
- priv->rxdmaout = 0;
- }
+ priv->rxdmanext = 0;
}
}
@@ -2276,41 +2245,6 @@ static int up_dma_receive(struct uart_dev_s *dev, unsigned int *status)
}
#endif
-/****************************************************************************
- * Name: up_dma_reenable
- *
- * Description:
- * Call to re-enable RX DMA.
- *
- ****************************************************************************/
-
-#if defined(SERIAL_HAVE_DMA) && defined(CONFIG_SERIAL_IFLOWCONTROL)
-static void up_dma_reenable(struct up_dev_s *priv)
-{
- /* Configure for non-circular DMA reception into the RX FIFO */
-
- stm32_dmasetup(priv->rxdma,
- priv->usartbase + STM32_USART_RDR_OFFSET,
- (uint32_t)priv->rxfifo,
- RXDMA_BUFFER_SIZE,
- SERIAL_DMA_IFLOW_CONTROL_WORD);
-
- /* Reset our DMA shadow pointer to match the address just programmed
- * above.
- */
-
- priv->rxdmaout = 0;
- priv->rxdmain = 0;
-
- /* Start the DMA channel, and arrange for callbacks at the full point in
- * the FIFO. After buffer gets full, hardware flow-control kicks in and
- * DMA transfer is stopped.
- */
-
- stm32_dmastart(priv->rxdma, up_dma_rxcallback, (void *)priv, false);
-}
-#endif
-
/****************************************************************************
* Name: up_dma_rxint
*
@@ -2333,15 +2267,6 @@ static void up_dma_rxint(struct uart_dev_s *dev, bool enable)
*/
priv->rxenable = enable;
-
-#ifdef CONFIG_SERIAL_IFLOWCONTROL
- if (priv->iflow && priv->rxenable && (priv->rxdmaout == RXDMA_BUFFER_SIZE))
- {
- /* Re-enable RX DMA. */
-
- up_dma_reenable(priv);
- }
-#endif
}
#endif
@@ -2362,7 +2287,7 @@ static bool up_dma_rxavailable(struct uart_dev_s *dev)
* do not match, then there are bytes to be received.
*/
- return (up_dma_nextrx(priv) != priv->rxdmaout);
+ return (up_dma_nextrx(priv) != priv->rxdmanext);
}
#endif
@@ -2486,16 +2411,6 @@ static void up_dma_rxcallback(DMA_HANDLE handle, uint8_t status, void *arg)
if (priv->rxenable && up_dma_rxavailable(&priv->dev))
{
uart_recvchars(&priv->dev);
-
-#ifdef CONFIG_SERIAL_IFLOWCONTROL
- if (priv->iflow && priv->rxenable &&
- (priv->rxdmaout == RXDMA_BUFFER_SIZE))
- {
- /* Re-enable RX DMA. */
-
- up_dma_reenable(priv);
- }
-#endif
}
}
#endif
diff --git a/arch/sim/Kconfig b/arch/sim/Kconfig
index 5168c7796eb..5bf46951542 100644
--- a/arch/sim/Kconfig
+++ b/arch/sim/Kconfig
@@ -100,10 +100,19 @@ config SIM_WALLTIME
correct for the system timer tick rate. With this definition in the configuration,
sleep() behavior is more or less normal.
+config SIM_NETDEV
+ bool "Simulated Network Device"
+ default y
+ depends on NET
+ ---help---
+ Build in support for a simulated network device using a TAP device on Linux or
+ WPCAP on Windows.
+
if HOST_LINUX
choice
prompt "Simulation Network Type"
default SIM_NET_HOST_ROUTE
+ depends on SIM_NETDEV
config SIM_NET_HOST_ROUTE
bool "Use local host route"
diff --git a/arch/sim/src/Makefile b/arch/sim/src/Makefile
index 540c1c6fc87..5668604ce57 100644
--- a/arch/sim/src/Makefile
+++ b/arch/sim/src/Makefile
@@ -119,6 +119,7 @@ ifeq ($(CONFIG_ARCH_ROMGETC),y)
CSRCS += up_romgetc.c
endif
+ifeq ($(CONFIG_SIM_NETDEV),y)
ifeq ($(CONFIG_NET_ETHERNET),y)
CSRCS += up_netdriver.c
HOSTCFLAGS += -DNETDEV_BUFSIZE=$(CONFIG_NET_ETH_MTU)
@@ -131,11 +132,12 @@ endif
ifeq ($(CONFIG_SIM_NET_HOST_ROUTE),y)
HOSTCFLAGS += -DCONFIG_SIM_NET_HOST_ROUTE
endif
-else
+else # HOSTOS != Cygwin
HOSTSRCS += up_wpcap.c up_netdev.c
DRVLIB = /lib/w32api/libws2_32.a /lib/w32api/libiphlpapi.a
-endif
-endif
+endif # HOSTOS != Cygwin
+endif # CONFIG_NET_ETHERNET
+endif # CONFIG_SIM_NETDEV
ifeq ($(CONFIG_SMP),y)
HOSTCFLAGS += -DCONFIG_SMP=1 -DCONFIG_SMP_NCPUS=$(CONFIG_SMP_NCPUS)
diff --git a/arch/sim/src/up_idle.c b/arch/sim/src/up_idle.c
index 1912bf755cc..05067a7c7ce 100644
--- a/arch/sim/src/up_idle.c
+++ b/arch/sim/src/up_idle.c
@@ -142,7 +142,7 @@ void up_idle(void)
}
#endif
-#ifdef CONFIG_NET_ETHERNET
+#if defined(CONFIG_NET_ETHERNET) && defined(CONFIG_SIM_NETDEV)
/* Run the network if enabled */
netdriver_loop();
diff --git a/arch/sim/src/up_initialize.c b/arch/sim/src/up_initialize.c
index ada5bb33ba0..fa8468196e0 100644
--- a/arch/sim/src/up_initialize.c
+++ b/arch/sim/src/up_initialize.c
@@ -270,7 +270,7 @@ void up_initialize(void)
up_registerblockdevice(); /* Our FAT ramdisk at /dev/ram0 */
#endif
-#ifdef CONFIG_NET_ETHERNET
+#if defined(CONFIG_NET_ETHERNET) && defined(CONFIG_SIM_NETDEV)
netdriver_init(); /* Our "real" network driver */
#endif
diff --git a/arch/sim/src/up_netdriver.c b/arch/sim/src/up_netdriver.c
index d9c12ae3397..bb37ec9fcc7 100644
--- a/arch/sim/src/up_netdriver.c
+++ b/arch/sim/src/up_netdriver.c
@@ -209,7 +209,7 @@ void netdriver_loop(void)
{
pkt_input(&g_sim_dev);
}
-#endif
+#endif /* CONFIG_NET_PKT */
/* We only accept IP packets of the configured type and ARP packets */
@@ -253,7 +253,7 @@ void netdriver_loop(void)
}
}
else
-#endif
+#endif /* CONFIG_NET_IPv4 */
#ifdef CONFIG_NET_IPv6
if (eth->type == HTONS(ETHTYPE_IP6) && is_ours)
{
@@ -283,7 +283,7 @@ void netdriver_loop(void)
{
neighbor_out(&g_sim_dev);
}
-#endif
+#endif /* CONFIG_NET_IPv6 */
/* And send the packet */
@@ -291,7 +291,7 @@ void netdriver_loop(void)
}
}
else
-#endif
+#endif/* CONFIG_NET_IPv6 */
#ifdef CONFIG_NET_ARP
if (eth->type == htons(ETHTYPE_ARP))
{
@@ -307,7 +307,11 @@ void netdriver_loop(void)
netdev_send(g_sim_dev.d_buf, g_sim_dev.d_len);
}
}
+ else
#endif
+ {
+ nwarn("WARNING: Unsupported Ethernet type %u\n", eth->type)
+ }
}
}
diff --git a/configs/sim/README.txt b/configs/sim/README.txt
index e3712b11f91..7fa886b5bda 100644
--- a/configs/sim/README.txt
+++ b/configs/sim/README.txt
@@ -807,6 +807,12 @@ pashello
Configures to use apps/examples/pashello.
+sixlowpan
+
+ This configuration was intended only for unit-level testing of the
+ 6loWPAN stack. It enables networking with 6loWPAN support and uses
+ only a IEEE802.15.4 MAC loopback network device to supported testing.
+
touchscreen
This configuration uses the simple touchscreen test at
diff --git a/configs/sim/nettest/defconfig b/configs/sim/nettest/defconfig
index 14b60be76ef..2c94b1e3a66 100644
--- a/configs/sim/nettest/defconfig
+++ b/configs/sim/nettest/defconfig
@@ -77,6 +77,7 @@ CONFIG_HOST_X86_64=y
CONFIG_SIM_X8664_SYSTEMV=y
# CONFIG_SIM_X8664_MICROSOFT is not set
# CONFIG_SIM_WALLTIME is not set
+CONFIG_SIM_NETDEV=y
CONFIG_SIM_NET_HOST_ROUTE=y
# CONFIG_SIM_NET_BRIDGE is not set
# CONFIG_SIM_FRAMEBUFFER is not set
@@ -203,6 +204,8 @@ CONFIG_MAX_TASKS=64
#
# CONFIG_PTHREAD_MUTEX_TYPES is not set
CONFIG_PTHREAD_MUTEX_ROBUST=y
+# CONFIG_PTHREAD_MUTEX_UNSAFE is not set
+# CONFIG_PTHREAD_MUTEX_BOTH is not set
CONFIG_NPTHREAD_KEYS=4
# CONFIG_PTHREAD_CLEANUP is not set
# CONFIG_CANCELLATION_POINTS is not set
@@ -368,6 +371,7 @@ CONFIG_SERIAL_CONSOLE=y
# CONFIG_PSEUDOTERM is not set
# CONFIG_USBDEV is not set
# CONFIG_USBHOST is not set
+# CONFIG_USBMISC is not set
# CONFIG_HAVE_USBTRACE is not set
# CONFIG_DRIVERS_WIRELESS is not set
# CONFIG_DRIVERS_CONTACTLESS is not set
@@ -408,10 +412,12 @@ CONFIG_NET_GUARDSIZE=2
CONFIG_NET_ETHERNET=y
# CONFIG_NET_LOOPBACK is not set
# CONFIG_NET_TUN is not set
+# CONFIG_NET_USRSOCK is not set
#
# Network Device Operations
#
+# CONFIG_NETDEV_IOCTL is not set
# CONFIG_NETDEV_PHY_IOCTL is not set
#
@@ -442,6 +448,7 @@ CONFIG_NET_SOCKOPTS=y
# TCP/IP Networking
#
CONFIG_NET_TCP=y
+# CONFIG_NET_TCP_NO_STACK is not set
# CONFIG_NET_TCPURGDATA is not set
CONFIG_NET_TCP_CONNS=40
CONFIG_NET_MAX_LISTENPORTS=40
@@ -456,6 +463,7 @@ CONFIG_NET_TCP_RECVDELAY=0
# UDP Networking
#
# CONFIG_NET_UDP is not set
+# CONFIG_NET_UDP_NO_STACK is not set
#
# ICMP Networking Support
@@ -484,6 +492,10 @@ CONFIG_NET_IOB=y
CONFIG_IOB_NBUFFERS=24
CONFIG_IOB_BUFSIZE=196
CONFIG_IOB_NCHAINS=8
+
+#
+# User-space networking stack API
+#
# CONFIG_NET_ARCH_INCR32 is not set
# CONFIG_NET_ARCH_CHKSUM is not set
CONFIG_NET_STATISTICS=y
@@ -717,7 +729,6 @@ CONFIG_EXAMPLES_NETTEST_IPADDR=0xc0a80080
CONFIG_EXAMPLES_NETTEST_DRIPADDR=0xc0a80001
CONFIG_EXAMPLES_NETTEST_NETMASK=0xffffff00
CONFIG_EXAMPLES_NETTEST_CLIENTIP=0xc0a8006a
-# CONFIG_EXAMPLES_NRF24L01TERM is not set
# CONFIG_EXAMPLES_NSH is not set
# CONFIG_EXAMPLES_NULL is not set
# CONFIG_EXAMPLES_NX is not set
@@ -748,6 +759,7 @@ CONFIG_EXAMPLES_NETTEST_CLIENTIP=0xc0a8006a
# CONFIG_EXAMPLES_WATCHDOG is not set
# CONFIG_EXAMPLES_WEBSERVER is not set
# CONFIG_EXAMPLES_WGET is not set
+# CONFIG_EXAMPLES_XBC_TEST is not set
#
# File System Utilities
diff --git a/configs/sim/sixlowpan/Make.defs b/configs/sim/sixlowpan/Make.defs
new file mode 100644
index 00000000000..f2a79385754
--- /dev/null
+++ b/configs/sim/sixlowpan/Make.defs
@@ -0,0 +1,128 @@
+############################################################################
+# configs/sim/sixlowpan/Make.defs
+#
+# Copyright (C) 2017 Gregory Nutt. All rights reserved.
+# Author: Gregory Nutt
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in
+# the documentation and/or other materials provided with the
+# distribution.
+# 3. Neither the name NuttX nor the names of its contributors may be
+# used to endorse or promote products derived from this software
+# without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+# OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+# POSSIBILITY OF SUCH DAMAGE.
+#
+############################################################################
+
+include ${TOPDIR}/.config
+include ${TOPDIR}/tools/Config.mk
+
+HOSTOS = ${shell uname -o 2>/dev/null || echo "Other"}
+
+ifeq ($(CONFIG_DEBUG_SYMBOLS),y)
+ ARCHOPTIMIZATION = -g
+endif
+
+ifneq ($(CONFIG_DEBUG_NOOPT),y)
+ ARCHOPTIMIZATION += -O2
+endif
+
+ARCHCPUFLAGS = -fno-builtin
+ARCHCPUFLAGSXX = -fno-builtin -fno-exceptions -fcheck-new -fno-rtti
+ARCHPICFLAGS = -fpic
+ARCHWARNINGS = -Wall -Wstrict-prototypes -Wshadow -Wundef
+ARCHWARNINGSXX = -Wall -Wshadow -Wundef
+ARCHDEFINES =
+ARCHINCLUDES = -I. -isystem $(TOPDIR)/include
+ARCHINCLUDESXX = -I. -isystem $(TOPDIR)/include -isystem $(TOPDIR)/include/cxx
+ARCHSCRIPT =
+
+ifeq ($(CONFIG_SIM_M32),y)
+ ARCHCPUFLAGS += -m32
+ ARCHCPUFLAGSXX += -m32
+endif
+
+CROSSDEV =
+CC = $(CROSSDEV)gcc
+CXX = $(CROSSDEV)g++
+CPP = $(CROSSDEV)gcc -E
+LD = $(CROSSDEV)ld
+AR = $(CROSSDEV)ar rcs
+NM = $(CROSSDEV)nm
+OBJCOPY = $(CROSSDEV)objcopy
+OBJDUMP = $(CROSSDEV)objdump
+
+CFLAGS = $(ARCHWARNINGS) $(ARCHOPTIMIZATION) \
+ $(ARCHCPUFLAGS) $(ARCHINCLUDES) $(ARCHDEFINES) $(EXTRADEFINES) -pipe
+CXXFLAGS = $(ARCHWARNINGSXX) $(ARCHOPTIMIZATION) \
+ $(ARCHCPUFLAGSXX) $(ARCHINCLUDESXX) $(ARCHDEFINES) $(EXTRADEFINES) -pipe
+CPPFLAGS = $(ARCHINCLUDES) $(ARCHDEFINES) $(EXTRADEFINES)
+AFLAGS = $(CFLAGS) -D__ASSEMBLY__
+
+
+# ELF module definitions
+
+CELFFLAGS = $(CFLAGS)
+CXXELFFLAGS = $(CXXFLAGS)
+
+LDELFFLAGS = -r -e main
+ifeq ($(WINTOOL),y)
+ LDELFFLAGS += -T "${shell cygpath -w $(TOPDIR)/configs/$(CONFIG_ARCH_BOARD)/scripts/gnu-elf.ld}"
+else
+ LDELFFLAGS += -T $(TOPDIR)/configs/$(CONFIG_ARCH_BOARD)/scripts/gnu-elf.ld
+endif
+
+
+ASMEXT = .S
+OBJEXT = .o
+LIBEXT = .a
+
+ifeq ($(HOSTOS),Cygwin)
+ EXEEXT = .exe
+else
+ EXEEXT =
+endif
+
+LDLINKFLAGS = $(ARCHSCRIPT) # Link flags used with $(LD)
+CCLINKFLAGS = $(ARCHSCRIPT) # Link flags used with $(CC)
+LDFLAGS = $(ARCHSCRIPT) # For backward compatibility, same as CCLINKFLAGS
+
+ifeq ($(CONFIG_DEBUG_SYMBOLS),y)
+ LDLINKFLAGS += -g
+ CCLINKFLAGS += -g
+ LDFLAGS += -g
+endif
+
+ifeq ($(CONFIG_SIM_M32),y)
+ LDLINKFLAGS += -melf_i386
+ CCLINKFLAGS += -m32
+ LDFLAGS += -m32
+endif
+
+
+MKDEP = $(TOPDIR)/tools/mkdeps$(HOSTEXEEXT)
+
+HOSTCC = gcc
+HOSTINCLUDES = -I.
+HOSTCFLAGS = $(ARCHWARNINGS) $(ARCHOPTIMIZATION) \
+ $(ARCHCPUFLAGS) $(HOSTINCLUDES) $(ARCHDEFINES) $(EXTRADEFINES) -pipe
+HOSTLDFLAGS =
diff --git a/configs/sim/sixlowpan/defconfig b/configs/sim/sixlowpan/defconfig
new file mode 100644
index 00000000000..8a5d9f766d8
--- /dev/null
+++ b/configs/sim/sixlowpan/defconfig
@@ -0,0 +1,1175 @@
+#
+# Automatically generated file; DO NOT EDIT.
+# Nuttx/ Configuration
+#
+
+#
+# Build Setup
+#
+CONFIG_EXPERIMENTAL=y
+# CONFIG_DEFAULT_SMALL is not set
+# CONFIG_HOST_LINUX is not set
+# CONFIG_HOST_OSX is not set
+CONFIG_HOST_WINDOWS=y
+# CONFIG_HOST_OTHER is not set
+CONFIG_TOOLCHAIN_WINDOWS=y
+# CONFIG_WINDOWS_NATIVE is not set
+CONFIG_WINDOWS_CYGWIN=y
+# CONFIG_WINDOWS_UBUNTU is not set
+# CONFIG_WINDOWS_MSYS is not set
+# CONFIG_WINDOWS_OTHER is not set
+
+#
+# Build Configuration
+#
+# CONFIG_APPS_DIR="../apps"
+CONFIG_BUILD_FLAT=y
+# CONFIG_BUILD_2PASS is not set
+
+#
+# Binary Output Formats
+#
+# CONFIG_RRLOAD_BINARY is not set
+# CONFIG_INTELHEX_BINARY is not set
+# CONFIG_MOTOROLA_SREC is not set
+CONFIG_RAW_BINARY=y
+# CONFIG_UBOOT_UIMAGE is not set
+
+#
+# Customize Header Files
+#
+# CONFIG_ARCH_STDINT_H is not set
+# CONFIG_ARCH_STDBOOL_H is not set
+# CONFIG_ARCH_MATH_H is not set
+# CONFIG_ARCH_FLOAT_H is not set
+# CONFIG_ARCH_STDARG_H is not set
+# CONFIG_ARCH_DEBUG_H is not set
+
+#
+# Debug Options
+#
+CONFIG_DEBUG_ALERT=y
+# CONFIG_DEBUG_FEATURES is not set
+# CONFIG_ARCH_HAVE_STACKCHECK is not set
+# CONFIG_ARCH_HAVE_HEAPCHECK is not set
+CONFIG_DEBUG_SYMBOLS=y
+# CONFIG_ARCH_HAVE_CUSTOMOPT is not set
+CONFIG_DEBUG_NOOPT=y
+# CONFIG_DEBUG_FULLOPT is not set
+
+#
+# System Type
+#
+# CONFIG_ARCH_ARM is not set
+# CONFIG_ARCH_AVR is not set
+# CONFIG_ARCH_HC is not set
+# CONFIG_ARCH_MIPS is not set
+# CONFIG_ARCH_MISOC is not set
+# CONFIG_ARCH_RENESAS is not set
+# CONFIG_ARCH_RISCV is not set
+CONFIG_ARCH_SIM=y
+# CONFIG_ARCH_X86 is not set
+# CONFIG_ARCH_XTENSA is not set
+# CONFIG_ARCH_Z16 is not set
+# CONFIG_ARCH_Z80 is not set
+CONFIG_ARCH="sim"
+
+#
+# Simulation Configuration Options
+#
+CONFIG_HOST_X86_64=y
+# CONFIG_HOST_X86 is not set
+# CONFIG_SIM_M32 is not set
+# CONFIG_SIM_CYGWIN_DECORATED is not set
+# CONFIG_SIM_X8664_SYSTEMV is not set
+CONFIG_SIM_X8664_MICROSOFT=y
+# CONFIG_SIM_WALLTIME is not set
+# CONFIG_SIM_NETDEV is not set
+# CONFIG_SIM_FRAMEBUFFER is not set
+# CONFIG_SIM_SPIFLASH is not set
+# CONFIG_SIM_QSPIFLASH is not set
+
+#
+# Architecture Options
+#
+# CONFIG_ARCH_NOINTC is not set
+# CONFIG_ARCH_VECNOTIRQ is not set
+# CONFIG_ARCH_DMA is not set
+# CONFIG_ARCH_HAVE_IRQPRIO is not set
+# CONFIG_ARCH_L2CACHE is not set
+# CONFIG_ARCH_HAVE_COHERENT_DCACHE is not set
+# CONFIG_ARCH_HAVE_ADDRENV is not set
+# CONFIG_ARCH_NEED_ADDRENV_MAPPING is not set
+CONFIG_ARCH_HAVE_MULTICPU=y
+# CONFIG_ARCH_HAVE_VFORK is not set
+# CONFIG_ARCH_HAVE_MMU is not set
+# CONFIG_ARCH_HAVE_MPU is not set
+# CONFIG_ARCH_NAND_HWECC is not set
+# CONFIG_ARCH_HAVE_EXTCLK is not set
+CONFIG_ARCH_HAVE_POWEROFF=y
+# CONFIG_ARCH_HAVE_RESET is not set
+CONFIG_ARCH_STACKDUMP=y
+# CONFIG_ENDIAN_BIG is not set
+# CONFIG_ARCH_IDLE_CUSTOM is not set
+# CONFIG_ARCH_HAVE_RAMFUNCS is not set
+# CONFIG_ARCH_HAVE_RAMVECTORS is not set
+# CONFIG_ARCH_MINIMAL_VECTORTABLE is not set
+
+#
+# Board Settings
+#
+CONFIG_BOARD_LOOPSPERMSEC=51262
+# CONFIG_ARCH_CALIBRATION is not set
+
+#
+# Interrupt options
+#
+# CONFIG_ARCH_HAVE_INTERRUPTSTACK is not set
+# CONFIG_ARCH_HAVE_HIPRI_INTERRUPT is not set
+
+#
+# Boot options
+#
+# CONFIG_BOOT_RUNFROMEXTSRAM is not set
+CONFIG_BOOT_RUNFROMFLASH=y
+# CONFIG_BOOT_RUNFROMISRAM is not set
+# CONFIG_BOOT_RUNFROMSDRAM is not set
+# CONFIG_BOOT_COPYTORAM is not set
+
+#
+# Boot Memory Configuration
+#
+CONFIG_RAM_START=0x20400000
+CONFIG_RAM_SIZE=393216
+# CONFIG_ARCH_HAVE_SDRAM is not set
+
+#
+# Board Selection
+#
+CONFIG_ARCH_BOARD_SIM=y
+# CONFIG_ARCH_BOARD_CUSTOM is not set
+CONFIG_ARCH_BOARD="sim"
+
+#
+# Common Board Options
+#
+
+#
+# Board-Specific Options
+#
+# CONFIG_BOARD_CRASHDUMP is not set
+CONFIG_LIB_BOARDCTL=y
+CONFIG_BOARDCTL_POWEROFF=y
+# CONFIG_BOARDCTL_UNIQUEID is not set
+# CONFIG_BOARDCTL_TSCTEST is not set
+# CONFIG_BOARDCTL_GRAPHICS is not set
+# CONFIG_BOARDCTL_IOCTL is not set
+
+#
+# RTOS Features
+#
+CONFIG_DISABLE_OS_API=y
+# CONFIG_DISABLE_POSIX_TIMERS is not set
+# CONFIG_DISABLE_PTHREAD is not set
+# CONFIG_DISABLE_SIGNALS is not set
+# CONFIG_DISABLE_MQUEUE is not set
+# CONFIG_DISABLE_ENVIRON is not set
+
+#
+# Clocks and Timers
+#
+CONFIG_ARCH_HAVE_TICKLESS=y
+# CONFIG_SCHED_TICKLESS is not set
+CONFIG_USEC_PER_TICK=10000
+# CONFIG_SYSTEM_TIME64 is not set
+# CONFIG_CLOCK_MONOTONIC is not set
+# CONFIG_ARCH_HAVE_TIMEKEEPING is not set
+# CONFIG_JULIAN_TIME is not set
+CONFIG_START_YEAR=2014
+CONFIG_START_MONTH=3
+CONFIG_START_DAY=10
+CONFIG_MAX_WDOGPARMS=2
+CONFIG_PREALLOC_WDOGS=32
+CONFIG_WDOG_INTRESERVE=4
+CONFIG_PREALLOC_TIMERS=4
+
+#
+# Tasks and Scheduling
+#
+# CONFIG_SPINLOCK is not set
+# CONFIG_SMP is not set
+# CONFIG_INIT_NONE is not set
+CONFIG_INIT_ENTRYPOINT=y
+# CONFIG_INIT_FILEPATH is not set
+CONFIG_USER_ENTRYPOINT="nsh_main"
+CONFIG_RR_INTERVAL=200
+# CONFIG_SCHED_SPORADIC is not set
+CONFIG_TASK_NAME_SIZE=31
+CONFIG_MAX_TASKS=16
+# CONFIG_SCHED_HAVE_PARENT is not set
+CONFIG_SCHED_WAITPID=y
+
+#
+# Pthread Options
+#
+# CONFIG_PTHREAD_MUTEX_TYPES is not set
+CONFIG_PTHREAD_MUTEX_ROBUST=y
+# CONFIG_PTHREAD_MUTEX_UNSAFE is not set
+# CONFIG_PTHREAD_MUTEX_BOTH is not set
+CONFIG_NPTHREAD_KEYS=4
+# CONFIG_PTHREAD_CLEANUP is not set
+# CONFIG_CANCELLATION_POINTS is not set
+
+#
+# Performance Monitoring
+#
+# CONFIG_SCHED_CPULOAD is not set
+# CONFIG_SCHED_INSTRUMENTATION is not set
+
+#
+# Files and I/O
+#
+CONFIG_DEV_CONSOLE=y
+# CONFIG_FDCLONE_DISABLE is not set
+# CONFIG_FDCLONE_STDIO is not set
+CONFIG_SDCLONE_DISABLE=y
+CONFIG_NFILE_DESCRIPTORS=8
+CONFIG_NFILE_STREAMS=8
+CONFIG_NAME_MAX=32
+# CONFIG_PRIORITY_INHERITANCE is not set
+
+#
+# RTOS hooks
+#
+# CONFIG_BOARD_INITIALIZE is not set
+# CONFIG_SCHED_STARTHOOK is not set
+# CONFIG_SCHED_ATEXIT is not set
+# CONFIG_SCHED_ONEXIT is not set
+# CONFIG_SIG_EVTHREAD is not set
+
+#
+# Signal Numbers
+#
+CONFIG_SIG_SIGUSR1=1
+CONFIG_SIG_SIGUSR2=2
+CONFIG_SIG_SIGALARM=3
+CONFIG_SIG_SIGCONDTIMEDOUT=16
+CONFIG_SIG_SIGWORK=17
+
+#
+# POSIX Message Queue Options
+#
+CONFIG_PREALLOC_MQ_MSGS=4
+CONFIG_MQ_MAXMSGSIZE=32
+# CONFIG_MODULE is not set
+
+#
+# Work queue support
+#
+CONFIG_SCHED_WORKQUEUE=y
+CONFIG_SCHED_HPWORK=y
+CONFIG_SCHED_HPWORKPRIORITY=224
+CONFIG_SCHED_HPWORKPERIOD=50000
+CONFIG_SCHED_HPWORKSTACKSIZE=4096
+# CONFIG_SCHED_LPWORK is not set
+
+#
+# Stack and heap information
+#
+CONFIG_IDLETHREAD_STACKSIZE=4096
+CONFIG_USERMAIN_STACKSIZE=8192
+CONFIG_PTHREAD_STACK_MIN=256
+CONFIG_PTHREAD_STACK_DEFAULT=4096
+# CONFIG_LIB_SYSCALL is not set
+
+#
+# Device Drivers
+#
+CONFIG_DISABLE_POLL=y
+CONFIG_DEV_NULL=y
+# CONFIG_DEV_ZERO is not set
+# CONFIG_DEV_URANDOM is not set
+# CONFIG_DEV_LOOP is not set
+
+#
+# Buffering
+#
+# CONFIG_DRVR_WRITEBUFFER is not set
+# CONFIG_DRVR_READAHEAD is not set
+# CONFIG_RAMDISK is not set
+# CONFIG_CAN is not set
+# CONFIG_ARCH_HAVE_PWM_PULSECOUNT is not set
+# CONFIG_ARCH_HAVE_PWM_MULTICHAN is not set
+# CONFIG_PWM is not set
+# CONFIG_ARCH_HAVE_I2CRESET is not set
+CONFIG_I2C=y
+# CONFIG_I2C_SLAVE is not set
+# CONFIG_I2C_POLLED is not set
+# CONFIG_I2C_TRACE is not set
+CONFIG_I2C_DRIVER=y
+# CONFIG_ARCH_HAVE_SPI_CRCGENERATION is not set
+# CONFIG_ARCH_HAVE_SPI_CS_CONTROL is not set
+# CONFIG_ARCH_HAVE_SPI_BITORDER is not set
+CONFIG_SPI=y
+# CONFIG_SPI_SLAVE is not set
+CONFIG_SPI_EXCHANGE=y
+# CONFIG_SPI_CMDDATA is not set
+# CONFIG_SPI_CALLBACK is not set
+# CONFIG_SPI_HWFEATURES is not set
+# CONFIG_SPI_CS_DELAY_CONTROL is not set
+# CONFIG_SPI_DRIVER is not set
+# CONFIG_SPI_BITBANG is not set
+# CONFIG_I2S is not set
+
+#
+# Timer Driver Support
+#
+# CONFIG_TIMER is not set
+# CONFIG_ONESHOT is not set
+# CONFIG_RTC is not set
+# CONFIG_WATCHDOG is not set
+# CONFIG_TIMERS_CS2100CP is not set
+# CONFIG_ANALOG is not set
+# CONFIG_AUDIO_DEVICES is not set
+# CONFIG_VIDEO_DEVICES is not set
+# CONFIG_BCH is not set
+# CONFIG_INPUT is not set
+
+#
+# IO Expander/GPIO Support
+#
+# CONFIG_IOEXPANDER is not set
+# CONFIG_DEV_GPIO is not set
+
+#
+# LCD Driver Support
+#
+# CONFIG_LCD is not set
+# CONFIG_SLCD is not set
+
+#
+# LED Support
+#
+# CONFIG_RGBLED is not set
+# CONFIG_PCA9635PW is not set
+# CONFIG_NCP5623C is not set
+CONFIG_MMCSD=y
+CONFIG_MMCSD_NSLOTS=1
+# CONFIG_MMCSD_READONLY is not set
+CONFIG_MMCSD_MULTIBLOCK_DISABLE=y
+# CONFIG_MMCSD_MMCSUPPORT is not set
+CONFIG_MMCSD_HAVECARDDETECT=y
+# CONFIG_MMCSD_SPI is not set
+# CONFIG_ARCH_HAVE_SDIO is not set
+# CONFIG_SDIO_DMA is not set
+# CONFIG_ARCH_HAVE_SDIOWAIT_WRCOMPLETE is not set
+# CONFIG_MODEM is not set
+CONFIG_MTD=y
+
+#
+# MTD Configuration
+#
+# CONFIG_MTD_PARTITION is not set
+# CONFIG_MTD_SECT512 is not set
+# CONFIG_MTD_BYTE_WRITE is not set
+# CONFIG_MTD_PROGMEM is not set
+CONFIG_MTD_CONFIG=y
+# CONFIG_MTD_CONFIG_RAM_CONSOLIDATE is not set
+CONFIG_MTD_CONFIG_ERASEDVALUE=0xff
+
+#
+# MTD Device Drivers
+#
+# CONFIG_MTD_NAND is not set
+# CONFIG_RAMMTD is not set
+# CONFIG_FILEMTD is not set
+CONFIG_MTD_AT24XX=y
+# CONFIG_AT24XX_MULTI is not set
+CONFIG_AT24XX_SIZE=2
+CONFIG_AT24XX_ADDR=0x57
+CONFIG_AT24XX_EXTENDED=y
+CONFIG_AT24XX_EXTSIZE=160
+CONFIG_AT24XX_FREQUENCY=100000
+CONFIG_MTD_AT25=y
+CONFIG_AT25_SPIMODE=0
+CONFIG_AT25_SPIFREQUENCY=20000000
+# CONFIG_MTD_AT45DB is not set
+# CONFIG_MTD_IS25XP is not set
+# CONFIG_MTD_M25P is not set
+# CONFIG_MTD_MX25L is not set
+# CONFIG_MTD_S25FL1 is not set
+# CONFIG_MTD_N25QXXX is not set
+# CONFIG_MTD_SMART is not set
+# CONFIG_MTD_RAMTRON is not set
+# CONFIG_MTD_SST25 is not set
+# CONFIG_MTD_SST25XX is not set
+# CONFIG_MTD_SST26 is not set
+# CONFIG_MTD_SST39FV is not set
+# CONFIG_MTD_W25 is not set
+# CONFIG_EEPROM is not set
+CONFIG_NETDEVICES=y
+
+#
+# General Ethernet MAC Driver Options
+#
+# CONFIG_NETDEV_LOOPBACK is not set
+CONFIG_NETDEV_TELNET=y
+CONFIG_TELNET_RXBUFFER_SIZE=256
+CONFIG_TELNET_TXBUFFER_SIZE=256
+CONFIG_NETDEV_MULTINIC=y
+CONFIG_ARCH_HAVE_NETDEV_STATISTICS=y
+CONFIG_NETDEV_STATISTICS=y
+# CONFIG_NETDEV_LATEINIT is not set
+
+#
+# External Ethernet MAC Device Support
+#
+# CONFIG_NET_DM90x0 is not set
+# CONFIG_NET_CS89x0 is not set
+# CONFIG_ENC28J60 is not set
+# CONFIG_ENCX24J600 is not set
+# CONFIG_NET_SLIP is not set
+# CONFIG_NET_FTMAC100 is not set
+# CONFIG_PIPES is not set
+# CONFIG_PM is not set
+# CONFIG_POWER is not set
+# CONFIG_SENSORS is not set
+CONFIG_SERIAL=y
+# CONFIG_DEV_LOWCONSOLE is not set
+# CONFIG_SERIAL_REMOVABLE is not set
+CONFIG_SERIAL_CONSOLE=y
+# CONFIG_16550_UART is not set
+# CONFIG_UART_SERIALDRIVER is not set
+# CONFIG_UART0_SERIALDRIVER is not set
+# CONFIG_UART1_SERIALDRIVER is not set
+# CONFIG_UART2_SERIALDRIVER is not set
+# CONFIG_UART3_SERIALDRIVER is not set
+# CONFIG_UART4_SERIALDRIVER is not set
+# CONFIG_UART5_SERIALDRIVER is not set
+# CONFIG_UART6_SERIALDRIVER is not set
+# CONFIG_UART7_SERIALDRIVER is not set
+# CONFIG_UART8_SERIALDRIVER is not set
+# CONFIG_SCI0_SERIALDRIVER is not set
+# CONFIG_SCI1_SERIALDRIVER is not set
+# CONFIG_USART0_SERIALDRIVER is not set
+# CONFIG_USART1_SERIALDRIVER is not set
+# CONFIG_USART2_SERIALDRIVER is not set
+# CONFIG_USART3_SERIALDRIVER is not set
+# CONFIG_USART4_SERIALDRIVER is not set
+# CONFIG_USART5_SERIALDRIVER is not set
+# CONFIG_USART6_SERIALDRIVER is not set
+# CONFIG_USART7_SERIALDRIVER is not set
+# CONFIG_USART8_SERIALDRIVER is not set
+# CONFIG_OTHER_UART_SERIALDRIVER is not set
+# CONFIG_MCU_SERIAL is not set
+CONFIG_STANDARD_SERIAL=y
+# CONFIG_SERIAL_IFLOWCONTROL is not set
+# CONFIG_SERIAL_OFLOWCONTROL is not set
+# CONFIG_SERIAL_DMA is not set
+# CONFIG_ARCH_HAVE_SERIAL_TERMIOS is not set
+# CONFIG_PSEUDOTERM is not set
+# CONFIG_USBDEV is not set
+# CONFIG_USBHOST is not set
+# CONFIG_USBMISC is not set
+# CONFIG_HAVE_USBTRACE is not set
+# CONFIG_DRIVERS_WIRELESS is not set
+# CONFIG_DRIVERS_CONTACTLESS is not set
+
+#
+# System Logging
+#
+# CONFIG_ARCH_SYSLOG is not set
+# CONFIG_RAMLOG is not set
+# CONFIG_SYSLOG_INTBUFFER is not set
+# CONFIG_SYSLOG_TIMESTAMP is not set
+CONFIG_SYSLOG_SERIAL_CONSOLE=y
+# CONFIG_SYSLOG_CHAR is not set
+CONFIG_SYSLOG_CONSOLE=y
+# CONFIG_SYSLOG_NONE is not set
+# CONFIG_SYSLOG_FILE is not set
+# CONFIG_SYSLOG_CHARDEV is not set
+
+#
+# Networking Support
+#
+CONFIG_ARCH_HAVE_NET=y
+# CONFIG_ARCH_HAVE_PHY is not set
+CONFIG_NET=y
+# CONFIG_NET_PROMISCUOUS is not set
+
+#
+# Driver buffer configuration
+#
+CONFIG_NET_GUARDSIZE=2
+
+#
+# Data link support
+#
+# CONFIG_NET_MULTILINK is not set
+# CONFIG_NET_USER_DEVFMT is not set
+# CONFIG_NET_ETHERNET is not set
+CONFIG_NET_6LOWPAN=y
+# CONFIG_NET_LOOPBACK is not set
+# CONFIG_NET_TUN is not set
+# CONFIG_NET_USRSOCK is not set
+
+#
+# Network Device Operations
+#
+CONFIG_NETDEV_IOCTL=y
+CONFIG_NETDEV_PHY_IOCTL=y
+
+#
+# Internet Protocol Selection
+#
+# CONFIG_NET_IPv4 is not set
+CONFIG_NET_IPv6=y
+CONFIG_NET_IPv6_NCONF_ENTRIES=8
+CONFIG_NET_6LOWPAN_FRAG=y
+CONFIG_NET_6LOWPAN_FRAMELEN=127
+# CONFIG_NET_6LOWPAN_COMPRESSION_IPv6 is not set
+# CONFIG_NET_6LOWPAN_COMPRESSION_HC1 is not set
+CONFIG_NET_6LOWPAN_COMPRESSION_HC06=y
+CONFIG_NET_6LOWPAN_COMPRESSION_THRESHOLD=63
+CONFIG_NET_6LOWPAN_MAXADDRCONTEXT=1
+CONFIG_NET_6LOWPAN_MAXADDRCONTEXT_PREFIX_0_0=0xaa
+CONFIG_NET_6LOWPAN_MAXADDRCONTEXT_PREFIX_0_1=0xaa
+# CONFIG_NET_6LOWPAN_MAXADDRCONTEXT_PREINIT_1 is not set
+CONFIG_NET_6LOWPAN_RIMEADDR_SIZE=2
+CONFIG_NET_6LOWPAN_MAXAGE=20
+CONFIG_NET_6LOWPAN_MAX_MACTRANSMITS=4
+CONFIG_NET_6LOWPAN_MAXPAYLOAD=102
+CONFIG_NET_6LOWPAN_MTU=1294
+CONFIG_NET_6LOWPAN_TCP_RECVWNDO=102
+
+#
+# Socket Support
+#
+CONFIG_NSOCKET_DESCRIPTORS=8
+CONFIG_NET_NACTIVESOCKETS=16
+CONFIG_NET_SOCKOPTS=y
+# CONFIG_NET_SOLINGER is not set
+
+#
+# Raw Socket Support
+#
+# CONFIG_NET_PKT is not set
+
+#
+# Unix Domain Socket Support
+#
+# CONFIG_NET_LOCAL is not set
+
+#
+# TCP/IP Networking
+#
+CONFIG_NET_TCP=y
+# CONFIG_NET_TCP_NO_STACK is not set
+# CONFIG_NET_TCPURGDATA is not set
+# CONFIG_NET_TCP_REASSEMBLY is not set
+CONFIG_NET_TCP_CONNS=8
+CONFIG_NET_MAX_LISTENPORTS=20
+CONFIG_NET_TCP_READAHEAD=y
+CONFIG_NET_TCP_WRITE_BUFFERS=y
+CONFIG_NET_TCP_NWRBCHAINS=8
+CONFIG_NET_TCP_RECVDELAY=0
+CONFIG_NET_TCPBACKLOG=y
+# CONFIG_NET_SENDFILE is not set
+
+#
+# UDP Networking
+#
+CONFIG_NET_UDP=y
+# CONFIG_NET_UDP_NO_STACK is not set
+# CONFIG_NET_UDP_CHECKSUMS is not set
+CONFIG_NET_UDP_CONNS=8
+CONFIG_NET_BROADCAST=y
+# CONFIG_NET_RXAVAIL is not set
+CONFIG_NET_UDP_READAHEAD=y
+
+#
+# ICMPv6 Networking Support
+#
+# CONFIG_NET_ICMPv6 is not set
+
+#
+# IGMPv2 Client Support
+#
+# CONFIG_NET_IGMP is not set
+
+#
+# ARP Configuration
+#
+
+#
+# Network I/O Buffer Support
+#
+CONFIG_NET_IOB=y
+CONFIG_IOB_NBUFFERS=36
+CONFIG_IOB_BUFSIZE=196
+CONFIG_IOB_NCHAINS=8
+CONFIG_IOB_THROTTLE=8
+
+#
+# User-space networking stack API
+#
+# CONFIG_NET_ARCH_INCR32 is not set
+# CONFIG_NET_ARCH_CHKSUM is not set
+CONFIG_NET_STATISTICS=y
+
+#
+# Routing Table Configuration
+#
+# CONFIG_NET_ROUTE is not set
+CONFIG_NET_HOSTNAME="SAMV71-XULT"
+
+#
+# Crypto API
+#
+# CONFIG_CRYPTO is not set
+
+#
+# File Systems
+#
+
+#
+# File system configuration
+#
+# CONFIG_DISABLE_MOUNTPOINT is not set
+# CONFIG_FS_AUTOMOUNTER is not set
+# CONFIG_DISABLE_PSEUDOFS_OPERATIONS is not set
+# CONFIG_PSEUDOFS_SOFTLINKS is not set
+CONFIG_FS_READABLE=y
+CONFIG_FS_WRITABLE=y
+# CONFIG_FS_NAMED_SEMAPHORES is not set
+CONFIG_FS_MQUEUE_MPATH="/var/mqueue"
+# CONFIG_FS_RAMMAP is not set
+CONFIG_FS_FAT=y
+CONFIG_FAT_LCNAMES=y
+CONFIG_FAT_LFN=y
+CONFIG_FAT_MAXFNAME=32
+# CONFIG_FS_FATTIME is not set
+# CONFIG_FAT_FORCE_INDIRECT is not set
+# CONFIG_FAT_DMAMEMORY is not set
+# CONFIG_FAT_DIRECT_RETRY is not set
+# CONFIG_FS_NXFFS is not set
+# CONFIG_FS_ROMFS is not set
+# CONFIG_FS_TMPFS is not set
+# CONFIG_FS_SMARTFS is not set
+# CONFIG_FS_BINFS is not set
+CONFIG_FS_PROCFS=y
+# CONFIG_FS_PROCFS_REGISTER is not set
+
+#
+# Exclude individual procfs entries
+#
+# CONFIG_FS_PROCFS_EXCLUDE_PROCESS is not set
+# CONFIG_FS_PROCFS_EXCLUDE_UPTIME is not set
+# CONFIG_FS_PROCFS_EXCLUDE_MOUNTS is not set
+# CONFIG_FS_PROCFS_EXCLUDE_NET is not set
+# CONFIG_FS_PROCFS_EXCLUDE_MTD is not set
+# CONFIG_FS_UNIONFS is not set
+# CONFIG_FS_HOSTFS is not set
+
+#
+# Graphics Support
+#
+# CONFIG_NX is not set
+
+#
+# Memory Management
+#
+# CONFIG_MM_SMALL is not set
+CONFIG_MM_REGIONS=1
+# CONFIG_ARCH_HAVE_HEAP2 is not set
+# CONFIG_GRAN is not set
+
+#
+# Audio Support
+#
+# CONFIG_AUDIO is not set
+
+#
+# Wireless Support
+#
+CONFIG_WIRELESS=y
+CONFIG_WIRELESS_IEEE802154=y
+CONFIG_IEEE802154_LOOPBACK=y
+CONFIG_IEEE802154_LOOPBACK_HPWORK=y
+
+#
+# Binary Loader
+#
+# CONFIG_BINFMT_DISABLE is not set
+# CONFIG_BINFMT_EXEPATH is not set
+# CONFIG_NXFLAT is not set
+# CONFIG_ELF is not set
+CONFIG_BUILTIN=y
+# CONFIG_PIC is not set
+# CONFIG_SYMTAB_ORDEREDBYNAME is not set
+
+#
+# Library Routines
+#
+
+#
+# Standard C Library Options
+#
+
+#
+# Standard C I/O
+#
+# CONFIG_STDIO_DISABLE_BUFFERING is not set
+CONFIG_STDIO_BUFFER_SIZE=64
+CONFIG_STDIO_LINEBUFFER=y
+CONFIG_NUNGET_CHARS=2
+# CONFIG_NOPRINTF_FIELDWIDTH is not set
+# CONFIG_LIBC_FLOATINGPOINT is not set
+CONFIG_LIBC_LONG_LONG=y
+# CONFIG_LIBC_SCANSET is not set
+# CONFIG_EOL_IS_CR is not set
+# CONFIG_EOL_IS_LF is not set
+# CONFIG_EOL_IS_BOTH_CRLF is not set
+CONFIG_EOL_IS_EITHER_CRLF=y
+# CONFIG_MEMCPY_VIK is not set
+# CONFIG_LIBM is not set
+
+#
+# Architecture-Specific Support
+#
+CONFIG_ARCH_LOWPUTC=y
+# CONFIG_ARCH_ROMGETC is not set
+# CONFIG_LIBC_ARCH_MEMCPY is not set
+# CONFIG_LIBC_ARCH_MEMCMP is not set
+# CONFIG_LIBC_ARCH_MEMMOVE is not set
+# CONFIG_LIBC_ARCH_MEMSET is not set
+# CONFIG_LIBC_ARCH_STRCHR is not set
+# CONFIG_LIBC_ARCH_STRCMP is not set
+# CONFIG_LIBC_ARCH_STRCPY is not set
+# CONFIG_LIBC_ARCH_STRNCPY is not set
+# CONFIG_LIBC_ARCH_STRLEN is not set
+# CONFIG_LIBC_ARCH_STRNLEN is not set
+# CONFIG_LIBC_ARCH_ELF is not set
+
+#
+# stdlib Options
+#
+CONFIG_LIB_RAND_ORDER=1
+CONFIG_LIB_HOMEDIR="/"
+CONFIG_LIBC_TMPDIR="/tmp"
+CONFIG_LIBC_MAX_TMPFILE=32
+
+#
+# Program Execution Options
+#
+# CONFIG_LIBC_EXECFUNCS is not set
+CONFIG_POSIX_SPAWN_PROXY_STACKSIZE=2048
+CONFIG_TASK_SPAWN_DEFAULT_STACKSIZE=4096
+
+#
+# errno Decode Support
+#
+# CONFIG_LIBC_STRERROR is not set
+# CONFIG_LIBC_PERROR_STDOUT is not set
+
+#
+# memcpy/memset Options
+#
+# CONFIG_MEMSET_OPTSPEED is not set
+# CONFIG_LIBC_DLLFCN is not set
+# CONFIG_LIBC_MODLIB is not set
+# CONFIG_LIBC_WCHAR is not set
+# CONFIG_LIBC_LOCALE is not set
+
+#
+# Time/Time Zone Support
+#
+# CONFIG_LIBC_LOCALTIME is not set
+# CONFIG_TIME_EXTENDED is not set
+CONFIG_ARCH_HAVE_TLS=y
+
+#
+# Thread Local Storage (TLS)
+#
+# CONFIG_TLS is not set
+
+#
+# Network-Related Options
+#
+# CONFIG_LIBC_IPv4_ADDRCONV is not set
+CONFIG_LIBC_NETDB=y
+
+#
+# NETDB Support
+#
+# CONFIG_NETDB_HOSTFILE is not set
+CONFIG_NETDB_DNSCLIENT=y
+CONFIG_NETDB_DNSCLIENT_ENTRIES=8
+CONFIG_NETDB_DNSCLIENT_NAMESIZE=32
+CONFIG_NETDB_DNSCLIENT_LIFESEC=3600
+CONFIG_NETDB_DNSCLIENT_MAXRESPONSE=96
+# CONFIG_NETDB_RESOLVCONF is not set
+# CONFIG_NETDB_DNSSERVER_NOADDR is not set
+CONFIG_NETDB_DNSSERVER_IPv6=y
+CONFIG_NETDB_DNSSERVER_IPv6ADDR_1=0xfc00
+CONFIG_NETDB_DNSSERVER_IPv6ADDR_2=0x0000
+CONFIG_NETDB_DNSSERVER_IPv6ADDR_3=0x0000
+CONFIG_NETDB_DNSSERVER_IPv6ADDR_4=0x0000
+CONFIG_NETDB_DNSSERVER_IPv6ADDR_5=0x0000
+CONFIG_NETDB_DNSSERVER_IPv6ADDR_6=0x0000
+CONFIG_NETDB_DNSSERVER_IPv6ADDR_7=0x0000
+CONFIG_NETDB_DNSSERVER_IPv6ADDR_8=0x0001
+# CONFIG_LIBC_IOCTL_VARIADIC is not set
+CONFIG_LIB_SENDFILE_BUFSIZE=512
+
+#
+# Non-standard Library Support
+#
+# CONFIG_LIB_CRC64_FAST is not set
+# CONFIG_LIB_KBDCODEC is not set
+# CONFIG_LIB_SLCDCODEC is not set
+# CONFIG_LIB_HEX2BIN is not set
+
+#
+# Basic CXX Support
+#
+# CONFIG_C99_BOOL8 is not set
+# CONFIG_HAVE_CXX is not set
+
+#
+# Application Configuration
+#
+
+#
+# Built-In Applications
+#
+CONFIG_BUILTIN_PROXY_STACKSIZE=2048
+
+#
+# CAN Utilities
+#
+
+#
+# Examples
+#
+# CONFIG_EXAMPLES_CCTYPE is not set
+# CONFIG_EXAMPLES_CHAT is not set
+# CONFIG_EXAMPLES_CONFIGDATA is not set
+# CONFIG_EXAMPLES_DHCPD is not set
+# CONFIG_EXAMPLES_DISCOVER is not set
+# CONFIG_EXAMPLES_ELF is not set
+# CONFIG_EXAMPLES_FSTEST is not set
+# CONFIG_EXAMPLES_FTPC is not set
+# CONFIG_EXAMPLES_FTPD is not set
+# CONFIG_EXAMPLES_HELLO is not set
+# CONFIG_EXAMPLES_HIDKBD is not set
+# CONFIG_EXAMPLES_IGMP is not set
+# CONFIG_EXAMPLES_JSON is not set
+# CONFIG_EXAMPLES_KEYPADTEST is not set
+# CONFIG_EXAMPLES_MEDIA is not set
+# CONFIG_EXAMPLES_MM is not set
+# CONFIG_EXAMPLES_MODBUS is not set
+# CONFIG_EXAMPLES_MOUNT is not set
+CONFIG_EXAMPLES_NETTEST=y
+CONFIG_EXAMPLES_NETTEST_STACKSIZE=4096
+CONFIG_EXAMPLES_NETTEST_PRIORITY=100
+CONFIG_EXAMPLES_NETTEST_LOOPBACK=y
+CONFIG_EXAMPLES_NETTEST_SERVER_STACKSIZE=4096
+CONFIG_EXAMPLES_NETTEST_SERVER_PRIORITY=100
+# CONFIG_EXAMPLES_NETTEST_PERFORMANCE is not set
+CONFIG_EXAMPLES_NETTEST_IPv6=y
+
+#
+# Target IPv6 address
+#
+#
+# Client IPv6 address
+#
+CONFIG_EXAMPLES_NETTEST_CLIENTIPv6ADDR_1=0xfe80
+CONFIG_EXAMPLES_NETTEST_CLIENTIPv6ADDR_2=0x0000
+CONFIG_EXAMPLES_NETTEST_CLIENTIPv6ADDR_3=0x0000
+CONFIG_EXAMPLES_NETTEST_CLIENTIPv6ADDR_4=0x0000
+CONFIG_EXAMPLES_NETTEST_CLIENTIPv6ADDR_5=0x0000
+CONFIG_EXAMPLES_NETTEST_CLIENTIPv6ADDR_6=0x00ff
+CONFIG_EXAMPLES_NETTEST_CLIENTIPv6ADDR_7=0xfe00
+CONFIG_EXAMPLES_NETTEST_CLIENTIPv6ADDR_8=0x1034
+CONFIG_EXAMPLES_NSH=y
+# CONFIG_EXAMPLES_NULL is not set
+# CONFIG_EXAMPLES_NX is not set
+# CONFIG_EXAMPLES_NXFFS is not set
+# CONFIG_EXAMPLES_NXHELLO is not set
+# CONFIG_EXAMPLES_NXIMAGE is not set
+# CONFIG_EXAMPLES_NXLINES is not set
+# CONFIG_EXAMPLES_NXTERM is not set
+# CONFIG_EXAMPLES_NXTEXT is not set
+# CONFIG_EXAMPLES_OSTEST is not set
+# CONFIG_EXAMPLES_PCA9635 is not set
+# CONFIG_EXAMPLES_POSIXSPAWN is not set
+# CONFIG_EXAMPLES_PPPD is not set
+# CONFIG_EXAMPLES_RFID_READUID is not set
+# CONFIG_EXAMPLES_RGBLED is not set
+# CONFIG_EXAMPLES_SENDMAIL is not set
+# CONFIG_EXAMPLES_SERIALBLASTER is not set
+# CONFIG_EXAMPLES_SERIALRX is not set
+# CONFIG_EXAMPLES_SERLOOP is not set
+# CONFIG_EXAMPLES_SLCD is not set
+# CONFIG_EXAMPLES_SMART is not set
+# CONFIG_EXAMPLES_SMART_TEST is not set
+# CONFIG_EXAMPLES_SMP is not set
+# CONFIG_EXAMPLES_STAT is not set
+# CONFIG_EXAMPLES_TCPECHO is not set
+# CONFIG_EXAMPLES_TELNETD is not set
+# CONFIG_EXAMPLES_TIFF is not set
+# CONFIG_EXAMPLES_TOUCHSCREEN is not set
+# CONFIG_EXAMPLES_UDP is not set
+# CONFIG_EXAMPLES_UDPBLASTER is not set
+# CONFIG_EXAMPLES_USBSERIAL is not set
+# CONFIG_EXAMPLES_WATCHDOG is not set
+# CONFIG_EXAMPLES_WEBSERVER is not set
+# CONFIG_EXAMPLES_XBC_TEST is not set
+
+#
+# File System Utilities
+#
+# CONFIG_FSUTILS_FLASH_ERASEALL is not set
+# CONFIG_FSUTILS_INIFILE is not set
+# CONFIG_FSUTILS_PASSWD is not set
+
+#
+# GPS Utilities
+#
+# CONFIG_GPSUTILS_MINMEA_LIB is not set
+
+#
+# Graphics Support
+#
+# CONFIG_TIFF is not set
+# CONFIG_GRAPHICS_TRAVELER is not set
+
+#
+# Interpreters
+#
+# CONFIG_INTERPRETERS_BAS is not set
+# CONFIG_INTERPRETERS_FICL is not set
+# CONFIG_INTERPRETERS_MICROPYTHON is not set
+# CONFIG_INTERPRETERS_MINIBASIC is not set
+# CONFIG_INTERPRETERS_PCODE is not set
+
+#
+# FreeModBus
+#
+# CONFIG_MODBUS is not set
+
+#
+# Network Utilities
+#
+# CONFIG_NETUTILS_CODECS is not set
+# CONFIG_NETUTILS_DISCOVER is not set
+# CONFIG_NETUTILS_ESP8266 is not set
+# CONFIG_NETUTILS_FTPC is not set
+# CONFIG_NETUTILS_JSON is not set
+CONFIG_NETUTILS_NETLIB=y
+# CONFIG_NETUTILS_NTPCLIENT is not set
+# CONFIG_NETUTILS_PPPD is not set
+# CONFIG_NETUTILS_SMTP is not set
+# CONFIG_NETUTILS_TELNETD is not set
+# CONFIG_NETUTILS_TFTPC is not set
+# CONFIG_NETUTILS_WEBCLIENT is not set
+# CONFIG_NETUTILS_WEBSERVER is not set
+# CONFIG_NETUTILS_XMLRPC is not set
+
+#
+# NSH Library
+#
+CONFIG_NSH_LIBRARY=y
+# CONFIG_NSH_MOTD is not set
+
+#
+# Command Line Configuration
+#
+CONFIG_NSH_READLINE=y
+# CONFIG_NSH_CLE is not set
+CONFIG_NSH_LINELEN=64
+# CONFIG_NSH_DISABLE_SEMICOLON is not set
+CONFIG_NSH_CMDPARMS=y
+CONFIG_NSH_MAXARGUMENTS=6
+CONFIG_NSH_ARGCAT=y
+CONFIG_NSH_NESTDEPTH=3
+# CONFIG_NSH_DISABLEBG is not set
+CONFIG_NSH_BUILTIN_APPS=y
+
+#
+# Disable Individual commands
+#
+# CONFIG_NSH_DISABLE_ADDROUTE is not set
+# CONFIG_NSH_DISABLE_BASENAME is not set
+# CONFIG_NSH_DISABLE_CAT is not set
+# CONFIG_NSH_DISABLE_CD is not set
+# CONFIG_NSH_DISABLE_CP is not set
+# CONFIG_NSH_DISABLE_CMP is not set
+CONFIG_NSH_DISABLE_DATE=y
+# CONFIG_NSH_DISABLE_DD is not set
+# CONFIG_NSH_DISABLE_DF is not set
+# CONFIG_NSH_DISABLE_DELROUTE is not set
+# CONFIG_NSH_DISABLE_DIRNAME is not set
+# CONFIG_NSH_DISABLE_ECHO is not set
+# CONFIG_NSH_DISABLE_EXEC is not set
+# CONFIG_NSH_DISABLE_EXIT is not set
+# CONFIG_NSH_DISABLE_FREE is not set
+# CONFIG_NSH_DISABLE_GET is not set
+# CONFIG_NSH_DISABLE_HELP is not set
+# CONFIG_NSH_DISABLE_HEXDUMP is not set
+# CONFIG_NSH_DISABLE_IFCONFIG is not set
+# CONFIG_NSH_DISABLE_IFUPDOWN is not set
+# CONFIG_NSH_DISABLE_KILL is not set
+# CONFIG_NSH_DISABLE_LOSETUP is not set
+CONFIG_NSH_DISABLE_LOSMART=y
+# CONFIG_NSH_DISABLE_LS is not set
+# CONFIG_NSH_DISABLE_MB is not set
+# CONFIG_NSH_DISABLE_MKDIR is not set
+# CONFIG_NSH_DISABLE_MKFATFS is not set
+# CONFIG_NSH_DISABLE_MKRD is not set
+# CONFIG_NSH_DISABLE_MH is not set
+# CONFIG_NSH_DISABLE_MOUNT is not set
+# CONFIG_NSH_DISABLE_MV is not set
+# CONFIG_NSH_DISABLE_MW is not set
+# CONFIG_NSH_DISABLE_NSLOOKUP is not set
+# CONFIG_NSH_DISABLE_POWEROFF is not set
+CONFIG_NSH_DISABLE_PRINTF=y
+# CONFIG_NSH_DISABLE_PS is not set
+# CONFIG_NSH_DISABLE_PUT is not set
+# CONFIG_NSH_DISABLE_PWD is not set
+# CONFIG_NSH_DISABLE_RM is not set
+# CONFIG_NSH_DISABLE_RMDIR is not set
+# CONFIG_NSH_DISABLE_SET is not set
+# CONFIG_NSH_DISABLE_SH is not set
+CONFIG_NSH_DISABLE_SHUTDOWN=y
+# CONFIG_NSH_DISABLE_SLEEP is not set
+# CONFIG_NSH_DISABLE_TIME is not set
+# CONFIG_NSH_DISABLE_TEST is not set
+# CONFIG_NSH_DISABLE_UMOUNT is not set
+# CONFIG_NSH_DISABLE_UNAME is not set
+# CONFIG_NSH_DISABLE_UNSET is not set
+# CONFIG_NSH_DISABLE_USLEEP is not set
+# CONFIG_NSH_DISABLE_WGET is not set
+# CONFIG_NSH_DISABLE_XD is not set
+CONFIG_NSH_MMCSDMINOR=0
+CONFIG_NSH_MMCSDSLOTNO=0
+
+#
+# Configure Command Options
+#
+# CONFIG_NSH_CMDOPT_DF_H is not set
+# CONFIG_NSH_CMDOPT_DD_STATS is not set
+CONFIG_NSH_CODECS_BUFSIZE=128
+CONFIG_NSH_CMDOPT_HEXDUMP=y
+CONFIG_NSH_PROC_MOUNTPOINT="/proc"
+CONFIG_NSH_FILEIOSIZE=512
+
+#
+# Scripting Support
+#
+# CONFIG_NSH_DISABLESCRIPT is not set
+# CONFIG_NSH_DISABLE_ITEF is not set
+# CONFIG_NSH_DISABLE_LOOPS is not set
+
+#
+# Console Configuration
+#
+CONFIG_NSH_CONSOLE=y
+# CONFIG_NSH_ALTCONDEV is not set
+CONFIG_NSH_ARCHINIT=y
+
+#
+# Networking Configuration
+#
+CONFIG_NSH_NETINIT=y
+# CONFIG_NSH_NETINIT_THREAD is not set
+
+#
+# IP Address Configuration
+#
+
+#
+# Target IPv6 address
+#
+CONFIG_NSH_IPv6ADDR_1=0xfe80
+CONFIG_NSH_IPv6ADDR_2=0x0000
+CONFIG_NSH_IPv6ADDR_3=0x0000
+CONFIG_NSH_IPv6ADDR_4=0x0000
+CONFIG_NSH_IPv6ADDR_5=0x0000
+CONFIG_NSH_IPv6ADDR_6=0x00ff
+CONFIG_NSH_IPv6ADDR_7=0xfe00
+CONFIG_NSH_IPv6ADDR_8=0xa9cd
+
+#
+# Router IPv6 address
+#
+CONFIG_NSH_DRIPv6ADDR_1=0xfe80
+CONFIG_NSH_DRIPv6ADDR_2=0x0000
+CONFIG_NSH_DRIPv6ADDR_3=0x0000
+CONFIG_NSH_DRIPv6ADDR_4=0x0000
+CONFIG_NSH_DRIPv6ADDR_5=0x0000
+CONFIG_NSH_DRIPv6ADDR_6=0x00ff
+CONFIG_NSH_DRIPv6ADDR_7=0xfe00
+CONFIG_NSH_DRIPv6ADDR_8=0x1034
+
+#
+# IPv6 Network mask
+#
+CONFIG_NSH_IPv6NETMASK_1=0xffff
+CONFIG_NSH_IPv6NETMASK_2=0xffff
+CONFIG_NSH_IPv6NETMASK_3=0xffff
+CONFIG_NSH_IPv6NETMASK_4=0xffff
+CONFIG_NSH_IPv6NETMASK_5=0xffff
+CONFIG_NSH_IPv6NETMASK_6=0xffff
+CONFIG_NSH_IPv6NETMASK_7=0xffff
+CONFIG_NSH_IPv6NETMASK_8=0x0000
+# CONFIG_NSH_DNS is not set
+CONFIG_NSH_NOMAC=y
+CONFIG_NSH_SWMAC=y
+CONFIG_NSH_MACADDR=0xabcd
+CONFIG_NSH_MAX_ROUNDTRIP=20
+# CONFIG_NSH_LOGIN is not set
+# CONFIG_NSH_CONSOLE_LOGIN is not set
+
+#
+# NxWidgets/NxWM
+#
+
+#
+# Platform-specific Support
+#
+# CONFIG_PLATFORM_CONFIGDATA is not set
+
+#
+# System Libraries and NSH Add-Ons
+#
+# CONFIG_SYSTEM_CLE is not set
+# CONFIG_SYSTEM_CUTERM is not set
+# CONFIG_SYSTEM_FLASH_ERASEALL is not set
+# CONFIG_SYSTEM_FREE is not set
+# CONFIG_SYSTEM_HEX2BIN is not set
+# CONFIG_SYSTEM_HEXED is not set
+CONFIG_SYSTEM_I2CTOOL=y
+CONFIG_I2CTOOL_MINBUS=0
+CONFIG_I2CTOOL_MAXBUS=0
+CONFIG_I2CTOOL_MINADDR=0x03
+CONFIG_I2CTOOL_MAXADDR=0x77
+CONFIG_I2CTOOL_MAXREGADDR=0xff
+CONFIG_I2CTOOL_DEFFREQ=400000
+# CONFIG_SYSTEM_INSTALL is not set
+# CONFIG_SYSTEM_MDIO is not set
+# CONFIG_SYSTEM_NETDB is not set
+# CONFIG_SYSTEM_RAMTEST is not set
+CONFIG_READLINE_HAVE_EXTMATCH=y
+CONFIG_SYSTEM_READLINE=y
+CONFIG_READLINE_ECHO=y
+# CONFIG_READLINE_TABCOMPLETION is not set
+# CONFIG_READLINE_CMD_HISTORY is not set
+# CONFIG_SYSTEM_SUDOKU is not set
+# CONFIG_SYSTEM_SYSTEM is not set
+# CONFIG_SYSTEM_TEE is not set
+# CONFIG_SYSTEM_UBLOXMODEM is not set
+# CONFIG_SYSTEM_VI is not set
+# CONFIG_SYSTEM_ZMODEM is not set
diff --git a/configs/sim/sixlowpan/setenv.sh b/configs/sim/sixlowpan/setenv.sh
new file mode 100644
index 00000000000..65065ccc9bc
--- /dev/null
+++ b/configs/sim/sixlowpan/setenv.sh
@@ -0,0 +1,45 @@
+#!/bin/bash
+# sim/sixlowpan/setenv.sh
+#
+# 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.
+#
+
+if [ "$(basename $0)" = "setenv.sh" ] ; then
+ echo "You must source this script, not run it!" 1>&2
+ exit 1
+fi
+
+if [ -z ${PATH_ORIG} ]; then export PATH_ORIG=${PATH}; fi
+
+#export NUTTX_BIN=
+#export PATH=${NUTTX_BIN}:/sbin:/usr/sbin:${PATH_ORIG}
+
+echo "PATH : ${PATH}"
diff --git a/configs/sim/src/sim_boot.c b/configs/sim/src/sim_boot.c
index 826ca47f90d..6e0be20777f 100644
--- a/configs/sim/src/sim_boot.c
+++ b/configs/sim/src/sim_boot.c
@@ -42,22 +42,6 @@
#include "sim.h"
-/****************************************************************************
- * Pre-processor Definitions
- ****************************************************************************/
-
-/****************************************************************************
- * Private Types
- ****************************************************************************/
-
-/****************************************************************************
- * Private Data
- ****************************************************************************/
-
-/****************************************************************************
- * Private Functions
- ****************************************************************************/
-
/****************************************************************************
* Public Functions
****************************************************************************/
diff --git a/configs/sim/src/sim_bringup.c b/configs/sim/src/sim_bringup.c
index 8f0d85c078e..8dd0f75bdd1 100644
--- a/configs/sim/src/sim_bringup.c
+++ b/configs/sim/src/sim_bringup.c
@@ -47,6 +47,7 @@
#include
#include
#include
+#include
#include "up_internal.h"
#include "sim.h"
@@ -139,5 +140,15 @@ int sim_bringup(void)
}
#endif
+#ifdef CONFIG_IEEE802154_LOOPBACK
+ /* Initialize and register the IEEE802.15.4 MAC network loop device */
+
+ ret = ieee8021514_loopback();
+ if (ret < 0)
+ {
+ _err("ERROR: ieee8021514_loopback() failed: %d\n", ret);
+ }
+#endif
+
return OK;
}
diff --git a/configs/sim/udgram/defconfig b/configs/sim/udgram/defconfig
index 87e97419c1b..aacb9eb00ef 100644
--- a/configs/sim/udgram/defconfig
+++ b/configs/sim/udgram/defconfig
@@ -77,6 +77,7 @@ CONFIG_HOST_X86_64=y
CONFIG_SIM_X8664_SYSTEMV=y
# CONFIG_SIM_X8664_MICROSOFT is not set
CONFIG_SIM_WALLTIME=y
+CONFIG_SIM_NETDEV=y
CONFIG_SIM_NET_HOST_ROUTE=y
# CONFIG_SIM_NET_BRIDGE is not set
# CONFIG_SIM_FRAMEBUFFER is not set
@@ -210,6 +211,8 @@ CONFIG_SCHED_WAITPID=y
#
# CONFIG_PTHREAD_MUTEX_TYPES is not set
CONFIG_PTHREAD_MUTEX_ROBUST=y
+# CONFIG_PTHREAD_MUTEX_UNSAFE is not set
+# CONFIG_PTHREAD_MUTEX_BOTH is not set
CONFIG_NPTHREAD_KEYS=4
# CONFIG_PTHREAD_CLEANUP is not set
# CONFIG_CANCELLATION_POINTS is not set
@@ -380,6 +383,7 @@ CONFIG_SERIAL_CONSOLE=y
# CONFIG_PSEUDOTERM is not set
# CONFIG_USBDEV is not set
# CONFIG_USBHOST is not set
+# CONFIG_USBMISC is not set
# CONFIG_HAVE_USBTRACE is not set
# CONFIG_DRIVERS_WIRELESS is not set
# CONFIG_DRIVERS_CONTACTLESS is not set
@@ -418,10 +422,12 @@ CONFIG_NET_GUARDSIZE=2
# CONFIG_NET_ETHERNET is not set
# CONFIG_NET_LOOPBACK is not set
# CONFIG_NET_TUN is not set
+# CONFIG_NET_USRSOCK is not set
#
# Network Device Operations
#
+# CONFIG_NETDEV_IOCTL is not set
# CONFIG_NETDEV_PHY_IOCTL is not set
#
@@ -453,11 +459,13 @@ CONFIG_NET_LOCAL_DGRAM=y
# TCP/IP Networking
#
# CONFIG_NET_TCP is not set
+# CONFIG_NET_TCP_NO_STACK is not set
#
# UDP Networking
#
# CONFIG_NET_UDP is not set
+# CONFIG_NET_UDP_NO_STACK is not set
#
# IGMPv2 Client Support
@@ -472,6 +480,10 @@ CONFIG_NET_LOCAL_DGRAM=y
# Network I/O Buffer Support
#
# CONFIG_NET_IOB is not set
+
+#
+# User-space networking stack API
+#
# CONFIG_NET_ARCH_INCR32 is not set
# CONFIG_NET_ARCH_CHKSUM is not set
# CONFIG_NET_STATISTICS is not set
@@ -715,7 +727,6 @@ CONFIG_EXAMPLES_HELLO_STACKSIZE=2048
# CONFIG_EXAMPLES_MM is not set
# CONFIG_EXAMPLES_MODBUS is not set
# CONFIG_EXAMPLES_MOUNT is not set
-# CONFIG_EXAMPLES_NRF24L01TERM is not set
CONFIG_EXAMPLES_NSH=y
# CONFIG_EXAMPLES_NULL is not set
# CONFIG_EXAMPLES_NX is not set
@@ -760,6 +771,7 @@ CONFIG_EXAMPLES_UDGRAM_CLIENT_PRIORITY=100
# CONFIG_EXAMPLES_USTREAM is not set
# CONFIG_EXAMPLES_WATCHDOG is not set
# CONFIG_EXAMPLES_WEBSERVER is not set
+# CONFIG_EXAMPLES_XBC_TEST is not set
#
# File System Utilities
diff --git a/configs/sim/ustream/defconfig b/configs/sim/ustream/defconfig
index 3b4cf6bdd29..43bb73515db 100644
--- a/configs/sim/ustream/defconfig
+++ b/configs/sim/ustream/defconfig
@@ -77,6 +77,7 @@ CONFIG_HOST_X86_64=y
CONFIG_SIM_X8664_SYSTEMV=y
# CONFIG_SIM_X8664_MICROSOFT is not set
CONFIG_SIM_WALLTIME=y
+CONFIG_SIM_NETDEV=y
CONFIG_SIM_NET_HOST_ROUTE=y
# CONFIG_SIM_NET_BRIDGE is not set
# CONFIG_SIM_FRAMEBUFFER is not set
@@ -210,6 +211,8 @@ CONFIG_SCHED_WAITPID=y
#
# CONFIG_PTHREAD_MUTEX_TYPES is not set
CONFIG_PTHREAD_MUTEX_ROBUST=y
+# CONFIG_PTHREAD_MUTEX_UNSAFE is not set
+# CONFIG_PTHREAD_MUTEX_BOTH is not set
CONFIG_NPTHREAD_KEYS=4
# CONFIG_PTHREAD_CLEANUP is not set
# CONFIG_CANCELLATION_POINTS is not set
@@ -380,6 +383,7 @@ CONFIG_SERIAL_CONSOLE=y
# CONFIG_PSEUDOTERM is not set
# CONFIG_USBDEV is not set
# CONFIG_USBHOST is not set
+# CONFIG_USBMISC is not set
# CONFIG_HAVE_USBTRACE is not set
# CONFIG_DRIVERS_WIRELESS is not set
# CONFIG_DRIVERS_CONTACTLESS is not set
@@ -418,10 +422,12 @@ CONFIG_NET_GUARDSIZE=2
# CONFIG_NET_ETHERNET is not set
# CONFIG_NET_LOOPBACK is not set
# CONFIG_NET_TUN is not set
+# CONFIG_NET_USRSOCK is not set
#
# Network Device Operations
#
+# CONFIG_NETDEV_IOCTL is not set
# CONFIG_NETDEV_PHY_IOCTL is not set
#
@@ -453,11 +459,13 @@ CONFIG_NET_LOCAL_STREAM=y
# TCP/IP Networking
#
# CONFIG_NET_TCP is not set
+# CONFIG_NET_TCP_NO_STACK is not set
#
# UDP Networking
#
# CONFIG_NET_UDP is not set
+# CONFIG_NET_UDP_NO_STACK is not set
#
# IGMPv2 Client Support
@@ -472,6 +480,10 @@ CONFIG_NET_LOCAL_STREAM=y
# Network I/O Buffer Support
#
# CONFIG_NET_IOB is not set
+
+#
+# User-space networking stack API
+#
# CONFIG_NET_ARCH_INCR32 is not set
# CONFIG_NET_ARCH_CHKSUM is not set
# CONFIG_NET_STATISTICS is not set
@@ -715,7 +727,6 @@ CONFIG_EXAMPLES_HELLO_STACKSIZE=2048
# CONFIG_EXAMPLES_MM is not set
# CONFIG_EXAMPLES_MODBUS is not set
# CONFIG_EXAMPLES_MOUNT is not set
-# CONFIG_EXAMPLES_NRF24L01TERM is not set
CONFIG_EXAMPLES_NSH=y
# CONFIG_EXAMPLES_NULL is not set
# CONFIG_EXAMPLES_NX is not set
@@ -755,6 +766,7 @@ CONFIG_EXAMPLES_USTREAM_ADDR="/dev/fifo"
# CONFIG_EXAMPLES_USTREAM_USE_POLL is not set
# CONFIG_EXAMPLES_WATCHDOG is not set
# CONFIG_EXAMPLES_WEBSERVER is not set
+# CONFIG_EXAMPLES_XBC_TEST is not set
#
# File System Utilities
diff --git a/crypto/random_pool.c b/crypto/random_pool.c
index fed59bd727f..7fd761be003 100644
--- a/crypto/random_pool.c
+++ b/crypto/random_pool.c
@@ -367,7 +367,7 @@ static void rng_buf_internal(FAR void *bytes, size_t nbytes)
static void rng_init(void)
{
- crypinfo("Initializing RNG\n");
+ cryptinfo("Initializing RNG\n");
memset(&g_rng, 0, sizeof(struct rng_s));
sem_init(&g_rng.rd_sem, 0, 1);
diff --git a/drivers/Kconfig b/drivers/Kconfig
index 511d63c5f6c..d7bc2653746 100644
--- a/drivers/Kconfig
+++ b/drivers/Kconfig
@@ -552,6 +552,16 @@ if USBHOST
source drivers/usbhost/Kconfig
endif # USBHOST
+menuconfig USBMISC
+ bool "USB Miscellaneous drivers"
+ default n
+ ---help---
+ USB Miscellaneous drivers.
+
+if USBMISC
+source drivers/usbmisc/Kconfig
+endif # USBMISC
+
config HAVE_USBTRACE
bool
default n
diff --git a/drivers/Makefile b/drivers/Makefile
index 94f027afbbf..5946cc123a7 100644
--- a/drivers/Makefile
+++ b/drivers/Makefile
@@ -72,6 +72,7 @@ include syslog$(DELIM)Make.defs
include timers$(DELIM)Make.defs
include usbdev$(DELIM)Make.defs
include usbhost$(DELIM)Make.defs
+include usbmisc$(DELIM)Make.defs
include usbmonitor$(DELIM)Make.defs
include video$(DELIM)Make.defs
include wireless$(DELIM)Make.defs
diff --git a/drivers/input/button_upper.c b/drivers/input/button_upper.c
index b4432cbad35..f5486752fc5 100644
--- a/drivers/input/button_upper.c
+++ b/drivers/input/button_upper.c
@@ -158,8 +158,8 @@ static const struct file_operations btn_fops =
btn_open, /* open */
btn_close, /* close */
btn_read, /* read */
- 0, /* write */
- 0, /* seek */
+ NULL, /* write */
+ NULL, /* seek */
btn_ioctl /* ioctl */
#ifndef CONFIG_DISABLE_POLL
, btn_poll /* poll */
diff --git a/drivers/net/skeleton.c b/drivers/net/skeleton.c
index b33c46e6e09..d354ab8130b 100644
--- a/drivers/net/skeleton.c
+++ b/drivers/net/skeleton.c
@@ -437,8 +437,8 @@ static void skel_receive(FAR struct skel_driver_s *priv)
skel_transmit(priv);
}
}
-#endif
else
+#endif
{
NETDEV_RXDROPPED(&priv->sk_dev);
}
diff --git a/drivers/sensors/Kconfig b/drivers/sensors/Kconfig
index 5871c18b815..b5fc76cb419 100644
--- a/drivers/sensors/Kconfig
+++ b/drivers/sensors/Kconfig
@@ -33,11 +33,11 @@ config BMP180
Enable driver support for the Bosch BMP180 barometer sensor.
config HTS221
- bool "ST HTS221 humidity sensor"
+ bool "STMicro HTS221 humidity sensor"
default n
select I2C
---help---
- Enable driver support for the ST HTS221 humidity sensor.
+ Enable driver support for the STMicro HTS221 humidity sensor.
if HTS221
@@ -56,11 +56,11 @@ config HTS221_NPOLLWAITERS
endif # HTS221
config SENSORS_L3GD20
- bool "ST L3GD20 Gyroscope Sensor support"
+ bool "STMicro L3GD20 Gyroscope Sensor support"
default n
select SPI
---help---
- Enable driver support for the ST L3GD20 gyroscope sensor.
+ Enable driver support for the STMicro L3GD20 gyroscope sensor.
config SENSOR_KXTJ9
bool "Kionix KXTJ9 Accelerometer support"
@@ -75,15 +75,44 @@ config SENSOR_KXTJ9_I2C_BUS_SPEED
endif # SENSOR_KXTJ9
+config LIS2DH
+ bool "STMicro LIS2DH device support"
+ default n
+ select I2C
+ ---help---
+ Enable driver support for the STMicro LIS2DH accelerometer
+
+if LIS2DH
+
+config DEBUG_LIS2DH
+ bool "Debug support for the LIS2DH"
+ default n
+ ---help---
+ Enables debug features for the LIS2DH
+
+config LIS2DH_NPOLLWAITERS
+ int "Number of waiters to poll"
+ default 2
+ ---help---
+ Maximum number of threads that can be waiting on poll()
+
+config LIS2DH_DRIVER_SELFTEST
+ bool "Enable selftest in LIS2DH driver"
+ default n
+ ---help---
+ Enable selftest in LIS2DH driver
+
+endif # LIS2DH
+
config LIS3DSH
- bool "STMicro LIS3DSH 3-Axis acclerometer support"
+ bool "STMicro LIS3DSH 3-Axis accelerometer support"
default n
select SPI
---help---
- Enable driver support for the STMicro LIS3DSH 3-Axis acclerometer.
+ Enable driver support for the STMicro LIS3DSH 3-Axis accelerometer.
config LIS331DL
- bool "ST LIS331DL device support"
+ bool "STMicro LIS331DL device support"
default n
select I2C
@@ -106,6 +135,23 @@ config LSM9DS1_I2C_FREQUENCY
range 1 400000
depends on SN_LSM9DS1
+config LPS25H
+ bool "STMicro LPS25H pressure sensor"
+ default n
+ select I2C
+ ---help---
+ Enable driver support for the STMicro LPS25H barometer sensor.
+
+if LPS25H
+
+config DEBUG_LPS25H
+ bool "Debug support for the LPS25H"
+ default n
+ ---help---
+ Enables debug features for the LPS25H
+
+endif # LPS25H
+
config MB7040
bool "MaxBotix MB7040 Sonar support"
default n
@@ -209,7 +255,7 @@ endif # SENSORS_ADXL345
config MAX31855
bool "Maxim MAX31855 Driver"
default n
- select SPI
+ select SPI
---help---
Enables support for the MAX31855 driver
@@ -229,7 +275,7 @@ config LIS3MDL
default n
select SPI
---help---
- Enable driver support for the ST LIS3MDL 3-axis magnetometer.
+ Enable driver support for the STMicro LIS3MDL 3-axis magnetometer.
config LM75
bool "STMicro LM-75 Temperature Sensor support"
diff --git a/drivers/sensors/Make.defs b/drivers/sensors/Make.defs
index d0bb9fa650f..7a5d5a0bba0 100644
--- a/drivers/sensors/Make.defs
+++ b/drivers/sensors/Make.defs
@@ -1,7 +1,7 @@
############################################################################
# drivers/sensors/Make.defs
#
-# Copyright (C) 2011-2012, 2015-2016 Gregory Nutt. All rights reserved.
+# Copyright (C) 2011-2012, 2015-2017 Gregory Nutt. All rights reserved.
# Author: Gregory Nutt
#
# Redistribution and use in source and binary forms, with or without
@@ -53,6 +53,10 @@ ifeq ($(CONFIG_SENSOR_KXTJ9),y)
CSRCS += kxtj9.c
endif
+ifeq ($(CONFIG_LIS2DH),y)
+ CSRCS += lis2dh.c
+endif
+
ifeq ($(CONFIG_LIS3DSH),y)
CSRCS += lis3dsh.c
endif
@@ -65,6 +69,10 @@ ifeq ($(CONFIG_SN_LSM9DS1),y)
CSRCS += lsm9ds1.c
endif
+ifeq ($(CONFIG_LPS25H),y)
+ CSRCS += lps25h.c
+endif
+
ifeq ($(CONFIG_ADXL345_I2C),y)
CSRCS += adxl345_i2c.c
endif
diff --git a/drivers/sensors/hts221.c b/drivers/sensors/hts221.c
index 4dc9c0d2dd1..59c5790ad58 100644
--- a/drivers/sensors/hts221.c
+++ b/drivers/sensors/hts221.c
@@ -174,13 +174,11 @@ static const struct file_operations g_humidityops =
#endif
};
-static struct hts221_dev_s *g_humid_data;
-
/****************************************************************************
* Private Functions
****************************************************************************/
-static int hts221_do_transfer(FAR struct hts221_dev_s *dev,
+static int hts221_do_transfer(FAR struct hts221_dev_s *priv,
FAR struct i2c_msg_s *msgv,
size_t nmsg)
{
@@ -189,7 +187,7 @@ static int hts221_do_transfer(FAR struct hts221_dev_s *dev,
for (retries = 0; retries < HTS221_I2C_RETRIES; retries++)
{
- ret = I2C_TRANSFER(dev->i2c, msgv, nmsg);
+ ret = I2C_TRANSFER(priv->i2c, msgv, nmsg);
if (ret >= 0)
{
return 0;
@@ -203,7 +201,7 @@ static int hts221_do_transfer(FAR struct hts221_dev_s *dev,
break;
}
- ret = up_i2creset(dev->i2c);
+ ret = up_i2creset(priv->i2c);
if (ret < 0)
{
hts221_dbg("up_i2creset failed: %d\n", ret);
@@ -217,51 +215,51 @@ static int hts221_do_transfer(FAR struct hts221_dev_s *dev,
return ret;
}
-static int32_t hts221_write_reg8(FAR struct hts221_dev_s *dev,
+static int32_t hts221_write_reg8(FAR struct hts221_dev_s *priv,
const uint8_t *command)
{
struct i2c_msg_s msgv[2] =
{
{
- .addr = dev->addr,
+ .addr = priv->addr,
.flags = 0,
.buffer = (FAR void *)&command[0],
.length = 1
},
{
- .addr = dev->addr,
+ .addr = priv->addr,
.flags = I2C_M_NORESTART,
.buffer = (FAR void *)&command[1],
.length = 1
}
};
- return hts221_do_transfer(dev, msgv, 2);
+ return hts221_do_transfer(priv, msgv, 2);
}
-static int hts221_read_reg(FAR struct hts221_dev_s *dev,
+static int hts221_read_reg(FAR struct hts221_dev_s *priv,
FAR const uint8_t *command, FAR uint8_t *value)
{
struct i2c_msg_s msgv[2] =
{
{
- .addr = dev->addr,
+ .addr = priv->addr,
.flags = 0,
.buffer = (FAR void *)command,
.length = 1
},
{
- .addr = dev->addr,
+ .addr = priv->addr,
.flags = I2C_M_READ,
.buffer = value,
.length = 1
}
};
- return hts221_do_transfer(dev, msgv, 2);
+ return hts221_do_transfer(priv, msgv, 2);
}
-static int hts221_get_id(FAR struct hts221_dev_s *priv, uint8_t * value)
+static int hts221_get_id(FAR struct hts221_dev_s *priv, uint8_t *value)
{
int ret = OK;
uint8_t cmd = HTS221_WHO_AM_I;
@@ -362,7 +360,7 @@ static int hts221_config_ctrl_reg2(FAR struct hts221_dev_s *priv,
}
static int hts221_config_ctrl_reg1(FAR struct hts221_dev_s *priv,
- FAR hts221_settings_t * settings)
+ FAR hts221_settings_t *settings)
{
int ret = OK;
uint8_t regval = 0;
@@ -420,7 +418,7 @@ static int hts221_power_on_off(FAR struct hts221_dev_s *priv, bool on)
}
static int hts221_config(FAR struct hts221_dev_s *priv,
- FAR hts221_settings_t * cfgr)
+ FAR hts221_settings_t *cfgr)
{
int ret = OK;
@@ -477,7 +475,7 @@ static int hts221_start_conversion(FAR struct hts221_dev_s *priv)
}
static int hts221_check_status(FAR struct hts221_dev_s *priv,
- FAR hts221_status_t * status)
+ FAR hts221_status_t *status)
{
int ret = OK;
uint8_t addr = HTS221_STATUS_REG;
@@ -498,7 +496,7 @@ static int hts221_check_status(FAR struct hts221_dev_s *priv,
}
static int hts221_read_raw_data(FAR struct hts221_dev_s *priv,
- FAR hts221_raw_data_t * data)
+ FAR hts221_raw_data_t *data)
{
int ret = OK;
uint8_t addr_humid_low = HTS221_HUM_OUT_L;
@@ -1069,13 +1067,14 @@ out:
static int hts221_int_handler(int irq, FAR void *context, FAR void *arg)
{
- if (!g_humid_data)
- return OK;
+ FAR struct hts221_dev_s *priv = (FAR struct hts221_dev_s *)arg;
- g_humid_data->int_pending = true;
+ DEBUGASSERT(priv != NULL);
+
+ priv->int_pending = true;
hts221_dbg("Hts221 interrupt\n");
#ifndef CONFIG_DISABLE_POLL
- hts221_notify(g_humid_data);
+ hts221_notify(priv);
#endif
return OK;
@@ -1095,7 +1094,6 @@ int hts221_register(FAR const char *devpath, FAR struct i2c_master_s *i2c,
return -ENOMEM;
}
- g_humid_data = priv;
priv->addr = addr;
priv->i2c = i2c;
priv->config = config;
@@ -1125,7 +1123,7 @@ int hts221_register(FAR const char *devpath, FAR struct i2c_master_s *i2c,
priv->config->irq_clear(priv->config);
}
- priv->config->irq_attach(priv->config, hts221_int_handler);
+ priv->config->irq_attach(priv->config, hts221_int_handler, priv);
priv->config->irq_enable(priv->config, false);
return OK;
}
diff --git a/drivers/sensors/lis2dh.c b/drivers/sensors/lis2dh.c
new file mode 100644
index 00000000000..b24aa782e36
--- /dev/null
+++ b/drivers/sensors/lis2dh.c
@@ -0,0 +1,2040 @@
+/****************************************************************************
+ * drivers/sensors/lis2dh.c
+ * LIS2DH accelerometer driver
+ *
+ * Copyright (C) 2014-2017 Haltian Ltd. All rights reserved.
+ * Authors: Timo Voutilainen
+ * Jussi Kivilinna
+ * Juha Niskanen
+ *
+ * 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
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+#ifdef CONFIG_DEBUG_LIS2DH
+# define lis2dh_dbg(x, ...) _info(x, ##__VA_ARGS__)
+#else
+# define lis2dh_dbg(x, ...) sninfo(x, ##__VA_ARGS__)
+#endif
+
+#ifdef CONFIG_LIS2DH_DRIVER_SELFTEST
+# define LSB_AT_10BIT_RESOLUTION 4
+# define LSB_AT_12BIT_RESOLUTION 1
+# define SELFTEST_BUF_SIZE 5
+# define SELFTEST_MAX_READ_ATTEMPTS 200
+# define SELFTEST_ABS_DIFF_MIN_10BIT 17
+# define SELFTEST_ABS_DIFF_MAX_10_BIT 360
+# define SELFTEST_ABS_DIFF_MIN_12BIT (LSB_AT_10BIT_RESOLUTION * SELFTEST_ABS_DIFF_MIN_10BIT)
+# define SELFTEST_ABS_DIFF_MAX_12BIT (LSB_AT_10BIT_RESOLUTION * SELFTEST_ABS_DIFF_MAX_10_BIT)
+# define SELFTEST_0 0
+# define SELFTEST_1 1
+#endif
+
+/* Miscellaneous macros */
+
+#define LIS2DH_I2C_RETRIES 10
+#define LIS2DH_COUNT_INTS
+
+/****************************************************************************
+ * Private Data Types
+ ****************************************************************************/
+
+enum interrupts
+{
+ LIS2DH_INT1 = 1,
+ LIS2DH_INT2 = 2
+};
+
+struct lis2dh_dev_s
+{
+ FAR struct i2c_master_s *i2c; /* I2C interface */
+ uint8_t addr; /* I2C address */
+ FAR struct lis2dh_config_s *config; /* Platform specific configuration */
+ struct lis2dh_setup *setup; /* User defined device operation mode setup */
+ struct lis2dh_vector_s vector_data; /* Latest read data read from lis2dh */
+ int scale; /* Full scale in milliG */
+ sem_t devsem; /* Manages exclusive access to this structure */
+ bool fifo_used; /* LIS2DH configured to use FIFO */
+ bool fifo_stopped;/* FIFO got full and has stopped. */
+#ifdef LIS2DH_COUNT_INTS
+ volatile int16_t int_pending; /* Interrupt received but data not read, yet */
+#else
+ volatile bool int_pending; /* Interrupt received but data not read, yet */
+#endif
+#ifndef CONFIG_DISABLE_POLL
+ struct pollfd *fds[CONFIG_LIS2DH_NPOLLWAITERS];
+#endif
+};
+
+/****************************************************************************
+ * Private Function prototypes
+ ****************************************************************************/
+
+static int lis2dh_open(FAR struct file *filep);
+static int lis2dh_close(FAR struct file *filep);
+static ssize_t lis2dh_read(FAR struct file *, FAR char *, size_t);
+static ssize_t lis2dh_write(FAR struct file *filep,
+ FAR const char *buffer, size_t buflen);
+static int lis2dh_ioctl(FAR struct file *filep, int cmd,
+ unsigned long arg);
+static int lis2dh_access(FAR struct lis2dh_dev_s *dev,
+ uint8_t subaddr, FAR uint8_t *buf, int length);
+static int lis2dh_get_reading(FAR struct lis2dh_dev_s *dev,
+ FAR struct lis2dh_vector_s *res, bool force_read);
+static int lis2dh_powerdown(FAR struct lis2dh_dev_s *dev);
+static int lis2dh_reboot(FAR struct lis2dh_dev_s *dev);
+static int lis2dh_poll(FAR struct file *filep,
+ FAR struct pollfd *fds, bool setup);
+static void lis2dh_notify(FAR struct lis2dh_dev_s *priv);
+static int lis2dh_int_handler(int irq, FAR void *context,
+ FAR void *arg);
+static int lis2dh_setup(FAR struct lis2dh_dev_s *dev,
+ FAR struct lis2dh_setup *new_setup);
+static inline int16_t lis2dh_raw_to_mg(uint8_t raw_hibyte,
+ uint8_t raw_lobyte, int scale);
+static int lis2dh_read_temp(FAR struct lis2dh_dev_s *dev,
+ FAR int16_t *temper);
+static int lis2dh_clear_interrupts(FAR struct lis2dh_dev_s *priv,
+ uint8_t interrupts);
+static unsigned int lis2dh_get_fifo_readings(FAR struct lis2dh_dev_s *priv,
+ FAR struct lis2dh_result *res, unsigned int readcount,
+ FAR int *perr);
+#ifdef CONFIG_LIS2DH_DRIVER_SELFTEST
+static int lis2dh_handle_selftest(FAR struct lis2dh_dev_s *priv);
+static int16_t lis2dh_raw_convert_to_12bit(uint8_t raw_hibyte,
+ uint8_t raw_lobyte);
+static FAR const struct lis2dh_vector_s *
+ lis2dh_get_raw_readings(FAR struct lis2dh_dev_s *dev,
+ FAR int *err);
+#endif
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+static const struct file_operations g_lis2dhops =
+{
+ lis2dh_open, /* open */
+ lis2dh_close, /* close */
+ lis2dh_read, /* read */
+ lis2dh_write, /* write */
+ NULL, /* seek */
+ lis2dh_ioctl /* ioctl */
+#ifndef CONFIG_DISABLE_POLL
+ , lis2dh_poll /* poll */
+#endif
+#ifndef CONFIG_DISABLE_PSEUDOFS_OPERATIONS
+ , NULL /* unlink */
+#endif
+};
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+static int lis2dh_who_am_i(FAR struct lis2dh_dev_s *dev, uint8_t *id)
+{
+ int ret;
+
+ ret = lis2dh_access(dev, ST_LIS2DH_WHOAMI_REG, id, 1);
+ if (ret < 0)
+ {
+ lis2dh_dbg("Cannot read who am i value\n");
+ return -EIO;
+ }
+
+ return ret;
+}
+
+/****************************************************************************
+ * Name: lis2dh_open
+ *
+ * Description:
+ * This function is called whenever the LIS2DH device is opened.
+ *
+ ****************************************************************************/
+
+static int lis2dh_open(FAR struct file *filep)
+{
+ FAR struct inode *inode = filep->f_inode;
+ FAR struct lis2dh_dev_s *priv = inode->i_private;
+ uint8_t regval;
+ int ret = OK;
+
+ /* Probe device */
+
+ if (lis2dh_access(priv, ST_LIS2DH_WHOAMI_REG, ®val, 1) > 0)
+ {
+ /* Check chip identification, in the future several more compatible parts
+ * may be added here.
+ */
+
+ if (regval == ST_LIS2DH_WHOAMI_VALUE)
+ {
+ priv->config->irq_enable(priv->config, true);
+ /* Normal exit point */
+ ret = lis2dh_clear_interrupts(priv, LIS2DH_INT1 | LIS2DH_INT2);
+ return ret;
+ }
+
+ /* Otherwise, we mark an invalid device found at given address */
+
+ ret = -ENODEV;
+ }
+ else
+ {
+ /* No response at given address is marked as */
+
+ ret = -EFAULT;
+ }
+
+ /* Error exit */
+
+ return ret;
+}
+
+/****************************************************************************
+ * Name: lis2dh_close
+ *
+ * Description:
+ * This routine is called when the LIS2DH device is closed.
+ *
+ ****************************************************************************/
+
+static int lis2dh_close(FAR struct file *filep)
+{
+ FAR struct inode *inode = filep->f_inode;
+ FAR struct lis2dh_dev_s *priv = inode->i_private;
+
+ priv->config->irq_enable(priv->config, false);
+ return lis2dh_powerdown(priv);
+}
+
+/****************************************************************************
+ * Name: lis2dh_fifo_start
+ *
+ * Description:
+ * This function restarts FIFO reading.
+ *
+ ****************************************************************************/
+
+static int lis2dh_fifo_start(FAR struct lis2dh_dev_s *priv)
+{
+ uint8_t buf;
+ int err = OK;
+
+ buf = 0x00 | priv->setup->trigger_selection |
+ priv->setup->fifo_trigger_threshold;
+ if (lis2dh_access(priv, ST_LIS2DH_FIFO_CTRL_REG, &buf, -1) != 1)
+ {
+ lis2dh_dbg("lis2dh: Failed to write FIFO control register\n");
+ err = -EIO;
+ }
+ else
+ {
+ buf = priv->setup->fifo_mode | priv->setup->trigger_selection |
+ priv->setup->fifo_trigger_threshold;
+ if (lis2dh_access(priv, ST_LIS2DH_FIFO_CTRL_REG, &buf, -1) != 1)
+ {
+ lis2dh_dbg("lis2dh: Failed to write FIFO control register\n");
+ err = -EIO;
+ }
+ else
+ {
+ priv->fifo_stopped = false;
+
+ lis2dh_dbg("lis2dh: FIFO restarted\n");
+ }
+ }
+
+ return err;
+}
+
+/****************************************************************************
+ * Name: lis2dh_read
+ *
+ * Description:
+ * This routine is called when the LIS2DH device is read.
+ *
+ ****************************************************************************/
+
+static ssize_t lis2dh_read(FAR struct file *filep, FAR char *buffer,
+ size_t buflen)
+{
+ FAR struct inode *inode = filep->f_inode;
+ FAR struct lis2dh_dev_s *priv = inode->i_private;
+ FAR struct lis2dh_result *ptr;
+ int readcount = (buflen - sizeof(struct lis2dh_res_header)) / sizeof(struct lis2dh_vector_s);
+ uint8_t buf;
+ uint8_t int1_src = 0;
+ uint8_t int2_src = 0;
+ irqstate_t flags;
+ int err;
+
+ if (buflen < sizeof(struct lis2dh_result) ||
+ (buflen - sizeof(struct lis2dh_res_header)) % sizeof(struct lis2dh_vector_s) != 0)
+ {
+ lis2dh_dbg("lis2dh: Illegal amount of bytes to read: %d\n", buflen);
+ return -EINVAL;
+ }
+
+ err = sem_wait(&priv->devsem);
+ if (err < 0)
+ {
+ return -EINTR;
+ }
+
+ /* Do not allow read() if no SNIOC_WRITESETUP first. */
+
+ if (!priv->setup)
+ {
+ lis2dh_dbg("lis2dh: Read from unconfigured device\n");
+ return -EINVAL;
+ }
+
+ flags = enter_critical_section();
+#ifdef LIS2DH_COUNT_INTS
+ if (priv->int_pending > 0)
+ {
+ priv->int_pending--;
+ }
+
+ DEBUGASSERT(priv->int_pending >= 0 && priv->int_pending < 10);
+#else
+ priv->int_pending = false;
+#endif
+ leave_critical_section(flags);
+
+ /* Set pointer to first measurement data */
+
+ ptr = (FAR struct lis2dh_result *)buffer;
+ ptr->header.meas_count = 0;
+
+ if (!priv->fifo_used)
+ {
+ /* FIFO not used, read only one sample. */
+
+ if (readcount > 0)
+ {
+ err = lis2dh_get_reading(priv, &ptr->measurements[0], true);
+ if (err < 0)
+ {
+ lis2dh_dbg("lis2dh: Failed to read xyz\n");
+ }
+ else
+ {
+ ptr->header.meas_count = 1;
+ }
+ }
+ }
+ else /* FIFO modes */
+ {
+ uint8_t fifo_mode = priv->setup->fifo_mode & ST_LIS2DH_FIFOCR_MODE_MASK;
+ bool fifo_empty = false;
+ uint8_t fifo_num_samples;
+
+ ptr->header.meas_count = 0;
+
+ do
+ {
+ /* Check if FIFO needs to be restarted after being read empty.
+ * We need to read SRC_REG before reading measurement, as reading
+ * sample from FIFO clears OVRN_FIFO flag.
+ */
+
+ if (lis2dh_access(priv, ST_LIS2DH_FIFO_SRC_REG, &buf, 1) != 1)
+ {
+ lis2dh_dbg("lis2dh: Failed to read FIFO source register\n");
+ return -EIO;
+ }
+
+ if (fifo_mode != LIS2DH_STREAM_MODE)
+ {
+ /* FIFO is full and has stopped. */
+
+ priv->fifo_stopped |= !!(buf & ST_LIS2DH_FIFOSR_OVRN_FIFO);
+ }
+
+ if (buf & ST_LIS2DH_FIFOSR_OVRN_FIFO)
+ {
+ lis2dh_dbg("lis2dh: FIFO overrun\n");
+ }
+
+ if (buf & ST_LIS2DH_FIFOSR_EMPTY)
+ {
+ lis2dh_dbg("lis2dh: FIFO empty\n");
+
+ fifo_empty = true;
+
+ if (fifo_mode != LIS2DH_STREAM_MODE)
+ {
+ priv->fifo_stopped = true;
+ }
+
+ /* FIFO is empty, skip reading. */
+
+ break;
+ }
+
+ /* How many samples available in FIFO? */
+
+ fifo_num_samples = (buf & ST_LIS2DH_FIFOSR_NUM_SAMP_MASK) + 1;
+
+ if (fifo_num_samples > (readcount - ptr->header.meas_count))
+ {
+ fifo_num_samples = (readcount - ptr->header.meas_count);
+ }
+
+ ptr->header.meas_count +=
+ lis2dh_get_fifo_readings(priv, ptr, fifo_num_samples, &err);
+ }
+ while (!fifo_empty && ptr->header.meas_count < readcount);
+
+ if (!fifo_empty && fifo_mode != LIS2DH_TRIGGER_MODE)
+ {
+ /* FIFO was not read empty, more data available. */
+
+ flags = enter_critical_section();
+
+#ifdef LIS2DH_COUNT_INTS
+ priv->int_pending++;
+#else
+ priv->int_pending = true;
+#endif
+
+#ifndef CONFIG_DISABLE_POLL
+ lis2dh_notify(priv);
+#endif
+
+ leave_critical_section(flags);
+ }
+ else if (fifo_mode != LIS2DH_STREAM_MODE && priv->fifo_stopped)
+ {
+ /* FIFO is empty and has stopped by overrun event. Reset FIFO for
+ * further reading.
+ */
+
+ err = lis2dh_fifo_start(priv);
+ }
+ }
+
+ /* Make sure interrupt will get cleared (by reading this register) in case of
+ * latched configuration.
+ */
+
+ buf = 0;
+ if (lis2dh_access(priv, ST_LIS2DH_INT1_SRC_REG, &buf, 1) != 1)
+ {
+ lis2dh_dbg("lis2dh: Failed to read INT1_SRC_REG\n");
+ err = -EIO;
+ }
+ if (buf & ST_LIS2DH_INT_SR_ACTIVE)
+ {
+ /* Interrupt has happened */
+
+ int1_src = buf;
+ ptr->header.int1_occurred = true;
+ }
+ else
+ {
+ ptr->header.int1_occurred = false;
+ }
+
+ /* Make sure interrupt will get cleared (by reading this register) in case of
+ * latched configuration.
+ */
+
+ buf = 0;
+ if (lis2dh_access(priv, ST_LIS2DH_INT2_SRC_REG, &buf, 1) != 1)
+ {
+ lis2dh_dbg("lis2dh: Failed to read INT2_SRC_REG\n");
+ err = -EIO;
+ }
+ if (buf & ST_LIS2DH_INT_SR_ACTIVE)
+ {
+ /* Interrupt has happened */
+
+ int2_src = buf;
+ ptr->header.int2_occurred = true;
+ }
+ else
+ {
+ ptr->header.int2_occurred = false;
+ }
+ ptr->header.int1_source = int1_src;
+ ptr->header.int2_source = int2_src;
+
+ sem_post(&priv->devsem);
+
+ /* 'err' was just for debugging, we do return partial reads here. */
+
+ return sizeof(ptr->header) +
+ ptr->header.meas_count * sizeof(struct lis2dh_vector_s);
+}
+
+/****************************************************************************
+ * Name: lis2dh_write
+ * Description:
+ * This routine is called when the LIS2DH device is written to.
+ ****************************************************************************/
+
+static ssize_t lis2dh_write(FAR struct file *filep, FAR const char *buffer,
+ size_t buflen)
+{
+ DEBUGASSERT(filep != NULL && buffer != NULL && buflen > 0);
+
+ return -ENOSYS;
+}
+
+/****************************************************************************
+ * Name: lis2dh_ioctl
+ *
+ * Description:
+ * This routine is called when ioctl function call
+ * for the LIS2DH device is done.
+ *
+ ****************************************************************************/
+
+static int lis2dh_ioctl(FAR struct file *filep, int cmd, unsigned long arg)
+{
+ FAR struct inode *inode = filep->f_inode;
+ FAR struct lis2dh_dev_s *priv = inode->i_private;
+ int ret;
+ uint8_t buf;
+
+ DEBUGASSERT(filep != NULL);
+
+ ret = sem_wait(&priv->devsem);
+ if (ret < 0)
+ {
+ return -EINTR;
+ }
+
+ ret = OK;
+ switch (cmd)
+ {
+ case SNIOC_WRITESETUP:
+ {
+ /* Write to the configuration registers. Arg: uint8_t value */
+
+ ret = lis2dh_setup(priv, (struct lis2dh_setup *)arg);
+ lis2dh_dbg("lis2dh: conf: %02x ret: %d\n", *(uint8_t*)arg, ret);
+
+ /* Make sure interrupt will get cleared (by reading this register) in
+ * case of latched configuration.
+ */
+
+ lis2dh_clear_interrupts(priv, LIS2DH_INT1 | LIS2DH_INT2);
+ }
+ break;
+
+ case SNIOC_WRITE_INT1THRESHOLD:
+ {
+ buf = (uint8_t)arg;
+
+ if (lis2dh_access(priv, ST_LIS2DH_INT1_THS_REG, &buf, -1) != 1)
+ {
+ lis2dh_dbg("lis2dh: Failed to write INT1_THS_REG\n");
+ ret = -EIO;
+ }
+
+ lis2dh_clear_interrupts(priv, LIS2DH_INT2);
+ }
+ break;
+
+ case SNIOC_WRITE_INT2THRESHOLD:
+ {
+ buf = (uint8_t)arg;
+
+ if (lis2dh_access(priv, ST_LIS2DH_INT2_THS_REG, &buf, -1) != 1)
+ {
+ lis2dh_dbg("lis2dh: Failed to write INT2_THS_REG\n");
+ ret = -EIO;
+ }
+
+ lis2dh_clear_interrupts(priv, LIS2DH_INT2);
+ }
+ break;
+
+ case SNIOC_RESET_HPFILTER:
+ {
+ /* Read reference register to reset/recalib DC offset for HP filter */
+
+ if (lis2dh_access(priv, ST_LIS2DH_REFERENCE_REG, &buf, 1) != 1)
+ {
+ lis2dh_dbg("lis2dh: Failed to write reference register\n");
+ ret = -EIO;
+ }
+
+ lis2dh_clear_interrupts(priv, LIS2DH_INT2);
+ }
+ break;
+
+ case SNIOC_START_SELFTEST:
+#ifdef CONFIG_LIS2DH_DRIVER_SELFTEST
+ {
+ priv->config->irq_enable(priv->config, false);
+ lis2dh_clear_interrupts(priv, LIS2DH_INT1 | LIS2DH_INT2);
+ ret = lis2dh_handle_selftest(priv);
+ priv->config->irq_enable(priv->config, true);
+ }
+#else
+ {
+ ret = -EINVAL;
+ }
+#endif
+ break;
+
+ case SNIOC_READ_TEMP:
+ {
+ ret = lis2dh_read_temp(priv, (int16_t *)arg);
+ }
+ break;
+
+ case SNIOC_WHO_AM_I:
+ {
+ ret = lis2dh_who_am_i(priv, (uint8_t *)arg);
+ }
+ break;
+
+ default:
+ {
+ lis2dh_dbg("lis2dh: Unrecognized cmd: %d\n", cmd);
+ ret = -ENOTTY;
+ }
+ break;
+ }
+
+ sem_post(&priv->devsem);
+ return ret;
+}
+
+/****************************************************************************
+ * Name: lis2dh_poll
+ *
+ * Description:
+ * This routine is called during LIS2DH device poll
+ *
+ ****************************************************************************/
+
+#ifndef CONFIG_DISABLE_POLL
+static int lis2dh_poll(FAR struct file *filep, FAR struct pollfd *fds,
+ bool setup)
+{
+ FAR struct inode *inode;
+ FAR struct lis2dh_dev_s *priv;
+ int ret = OK;
+ int i;
+
+ DEBUGASSERT(filep && fds);
+ inode = filep->f_inode;
+
+ DEBUGASSERT(inode && inode->i_private);
+ priv = (FAR struct lis2dh_dev_s *)inode->i_private;
+
+ ret = sem_wait(&priv->devsem);
+ if (ret < 0)
+ {
+ return -EINTR;
+ }
+
+ if (setup)
+ {
+ /* Ignore waits that do not include POLLIN */
+
+ if ((fds->events & POLLIN) == 0)
+ {
+ ret = -EDEADLK;
+ goto out;
+ }
+
+ /* This is a request to set up the poll. Find an available
+ * slot for the poll structure reference
+ */
+
+ for (i = 0; i < CONFIG_LIS2DH_NPOLLWAITERS; i++)
+ {
+ /* Find an available slot */
+
+ if (!priv->fds[i])
+ {
+ /* Bind the poll structure and this slot */
+
+ priv->fds[i] = fds;
+ fds->priv = &priv->fds[i];
+ break;
+ }
+ }
+
+ if (i >= CONFIG_LIS2DH_NPOLLWAITERS)
+ {
+ fds->priv = NULL;
+ ret = -EBUSY;
+ goto out;
+ }
+
+ if (priv->int_pending)
+ {
+ lis2dh_notify(priv);
+ }
+ }
+ else if (fds->priv)
+ {
+ /* This is a request to tear down the poll. */
+
+ struct pollfd **slot = (struct pollfd **)fds->priv;
+ DEBUGASSERT(slot != NULL);
+
+ /* Remove all memory of the poll setup */
+
+ *slot = NULL;
+ fds->priv = NULL;
+ }
+
+out:
+ sem_post(&priv->devsem);
+ return ret;
+}
+
+static void lis2dh_notify(FAR struct lis2dh_dev_s *priv)
+{
+ DEBUGASSERT(priv != NULL);
+
+ int i;
+
+ /* If there are threads waiting on poll() for LIS2DH data to become available,
+ * then wake them up now. NOTE: we wake up all waiting threads because we
+ * do not know that they are going to do. If they all try to read the data,
+ * then some make end up blocking after all.
+ */
+
+ for (i = 0; i < CONFIG_LIS2DH_NPOLLWAITERS; i++)
+ {
+ struct pollfd *fds = priv->fds[i];
+ if (fds)
+ {
+ fds->revents |= POLLIN;
+ lis2dh_dbg("lis2dh: Report events: %02x\n", fds->revents);
+ sem_post(fds->sem);
+ }
+ }
+}
+#endif /* !CONFIG_DISABLE_POLL */
+
+/****************************************************************************
+ * Name: lis2dh_callback
+ *
+ * Description:
+ * lis2dh interrupt handler
+ *
+ ****************************************************************************/
+
+static int lis2dh_int_handler(int irq, FAR void *context, FAR void *arg)
+{
+ FAR struct lis2dh_dev_s *priv = (FAR struct lis2dh_dev_s *)arg;
+ irqstate_t flags;
+
+ DEBUGASSERT(priv != NULL);
+
+ flags = enter_critical_section();
+
+#ifdef LIS2DH_COUNT_INTS
+ priv->int_pending++;
+#else
+ priv->int_pending = true;
+#endif
+
+#ifndef CONFIG_DISABLE_POLL
+ lis2dh_notify(priv);
+#endif
+
+ leave_critical_section(flags);
+
+ return OK;
+}
+
+#ifdef CONFIG_LIS2DH_DRIVER_SELFTEST
+/****************************************************************************
+ * Name: lis2dh_clear_registers
+ *
+ * Description:
+ * Clear lis2dh registers
+ *
+ * Input Parameters:
+ * priv - pointer to LIS2DH Private Structure
+ *
+ * Returned Value:
+ * Returns OK in case of success, otherwise ERROR
+ *
+ ****************************************************************************/
+
+static int lis2dh_clear_registers(FAR struct lis2dh_dev_s *priv)
+{
+ uint8_t i, buf = 0;
+
+ DEBUGASSERT(priv);
+
+ for (i = ST_LIS2DH_TEMP_CFG_REG; i <= ST_LIS2DH_ACT_DUR_REG; i++)
+ {
+ /* Skip read only registers */
+
+ if ((i <= 0x1e) || (i >= 0x27 && i <= 0x2d) || (i == 0x2f) || (i == 0x31))
+ {
+ continue;
+ }
+
+ if (lis2dh_access(priv, i, &buf, -1) != 1)
+ {
+ lis2dh_dbg("lis2dh: Failed to clear register 0x%02x\n", i);
+ return ERROR;
+ }
+ }
+
+ return OK;
+}
+
+/****************************************************************************
+ * Name: lis2dh_write_register
+ *
+ * Description:
+ * Clear lis2dh registers
+ *
+ * Input Parameters:
+ * priv - pointer to LIS2DH Private Structure
+ * reg - target register
+ * value - value to write
+ *
+ * Returned Value:
+ * Returns OK in case of success, otherwise ERROR
+ *
+ ****************************************************************************/
+
+static int lis2dh_write_register(FAR struct lis2dh_dev_s *priv, uint8_t reg,
+ uint8_t value)
+{
+ DEBUGASSERT(priv);
+
+ if (lis2dh_access(priv, reg, &value, -1) != 1)
+ {
+ lis2dh_dbg("lis2dh: Failed to write %d to register 0x%02x\n",
+ value, reg);
+ return ERROR;
+ }
+ return OK;
+}
+
+/****************************************************************************
+ * Name: lis2dh_read_register
+ *
+ * Description:
+ * read lis2dh register
+ *
+ * Input Parameters:
+ * priv - pointer to LIS2DH Private Structure
+ * reg - register to read
+ *
+ * Returned Value:
+ * Returns positive register value in case of success, otherwise ERROR ( < 0)
+ ****************************************************************************/
+
+static int lis2dh_read_register(FAR struct lis2dh_dev_s *priv, uint8_t reg)
+{
+ uint8_t buf;
+
+ DEBUGASSERT(priv);
+
+ if (lis2dh_access(priv, reg, &buf, sizeof(buf)) == sizeof(buf))
+ {
+ return buf;
+ }
+
+ return ERROR;
+}
+
+/****************************************************************************
+ * Name: lis2dh_handle_selftest
+ *
+ * Description:
+ * Handle selftest. Note, that after running selftest lis2dh is left in
+ * shutdown mode without valid setup. Therefore SNIOC_WRITESETUP must be
+ * sent again to proceed with normal operations.
+ *
+ ****************************************************************************/
+
+static int lis2dh_handle_selftest(FAR struct lis2dh_dev_s *priv)
+{
+ const struct lis2dh_vector_s *results;
+ uint8_t i;
+ uint8_t j;
+ uint8_t buf;
+ int16_t avg_x_no_st = 0;
+ int16_t avg_y_no_st = 0;
+ int16_t avg_z_no_st = 0;
+ int16_t avg_x_with_st = 0;
+ int16_t avg_y_with_st = 0;
+ int16_t avg_z_with_st = 0;
+ int16_t abs_st_x_value;
+ int16_t abs_st_y_value;
+ int16_t abs_st_z_value;
+ int ret = OK;
+ int err = OK;
+
+ DEBUGASSERT(priv);
+
+ lis2dh_powerdown(priv);
+
+ if (lis2dh_clear_registers(priv) != OK)
+ {
+ ret = -EIO;
+ goto out;
+ }
+
+ /* Set the control register (23h) to ±2g FS, normal mode with BDU (Block
+ * Data Update) and HR (High Resolution) bits enabled.
+ */
+
+ if (lis2dh_write_register(priv, ST_LIS2DH_CTRL_REG4, 0x88) != OK)
+ {
+ lis2dh_dbg("lis2dh: Failed to write CTRL4 REG for selftest\n");
+ ret = -EIO;
+ goto out;
+ }
+
+ /* Set the control register (20h) to 50Hz ODR (Output Data Rate) with
+ * X/Y/Z axis enabled.
+ */
+
+ if (lis2dh_write_register(priv, ST_LIS2DH_CTRL_REG1, 0x47) != OK)
+ {
+ lis2dh_dbg("lis2dh: Failed to write CTRL1 REG for selftest\n");
+ ret = -EIO;
+ goto out;
+ }
+
+ /* Dummy reads so that values have stabilized */
+
+ for (i = 0; i < 20; i++)
+ {
+ if (lis2dh_get_raw_readings(priv, &err) == NULL)
+ {
+ ret = -EIO;
+ goto out;
+ }
+ }
+
+ for (i = 0; i < SELFTEST_BUF_SIZE; i++)
+ {
+ results = lis2dh_get_raw_readings(priv, &err);
+ if (results == NULL)
+ {
+ ret = -EIO;
+ goto out;
+ }
+
+ avg_x_no_st += results->x;
+ avg_y_no_st += results->y;
+ avg_z_no_st += results->z;
+ }
+
+ avg_x_no_st = avg_x_no_st / SELFTEST_BUF_SIZE;
+ avg_y_no_st = avg_y_no_st / SELFTEST_BUF_SIZE;
+ avg_z_no_st = avg_z_no_st / SELFTEST_BUF_SIZE;
+
+ for (i = SELFTEST_0; i <= SELFTEST_1; i++)
+ {
+ avg_x_with_st = 0;
+ avg_y_with_st = 0;
+ avg_z_with_st = 0;
+
+ /* Enable self-test 0 or 1 at +/-2g FS with BDU and HR bits enabled. */
+
+ buf = (i == SELFTEST_0) ? 0x8a : 0x8c;
+
+ if (lis2dh_write_register(priv, ST_LIS2DH_CTRL_REG4, buf) != OK)
+ {
+ lis2dh_dbg("lis2dh: Failed to write CTRL4 REG for selftest\n");
+ ret = -EIO;
+ goto out;
+ }
+
+ /* Dummy reads so that values have stabilized */
+
+ for (i = 0; i < 10; i++)
+ {
+ if (lis2dh_get_raw_readings(priv, &err) == NULL)
+ {
+ ret = -EIO;
+ goto out;
+ }
+ }
+
+ for (j = 0; j < SELFTEST_BUF_SIZE; j++)
+ {
+ results = lis2dh_get_raw_readings(priv, &err);
+ if (results == NULL)
+ {
+ ret = -EIO;
+ goto out;
+ }
+
+ avg_x_with_st += results->x;
+ avg_y_with_st += results->y;
+ avg_z_with_st += results->z;
+ }
+
+ avg_x_with_st = avg_x_with_st / SELFTEST_BUF_SIZE;
+ avg_y_with_st = avg_y_with_st / SELFTEST_BUF_SIZE;
+ avg_z_with_st = avg_z_with_st / SELFTEST_BUF_SIZE;
+
+ abs_st_x_value = abs(avg_x_with_st - avg_x_no_st);
+ abs_st_y_value = abs(avg_y_with_st - avg_y_no_st);
+ abs_st_z_value = abs(avg_z_with_st - avg_z_no_st);
+
+ dbg ("ST %d, ABSX: %d, ABSY: %d, ABSZ: %d\n",
+ i, abs_st_x_value, abs_st_y_value, abs_st_z_value);
+
+ if (abs_st_x_value < SELFTEST_ABS_DIFF_MIN_12BIT ||
+ abs_st_x_value > SELFTEST_ABS_DIFF_MAX_12BIT ||
+ abs_st_y_value < SELFTEST_ABS_DIFF_MIN_12BIT ||
+ abs_st_y_value > SELFTEST_ABS_DIFF_MAX_12BIT ||
+ abs_st_z_value < SELFTEST_ABS_DIFF_MIN_12BIT ||
+ abs_st_z_value > SELFTEST_ABS_DIFF_MAX_12BIT)
+ {
+ dbg("Selftest %d fail! Limits (%d <= value <= %d). "
+ "Results: x: %d, y: %d, z: %d ",
+ i,
+ SELFTEST_ABS_DIFF_MIN_12BIT, SELFTEST_ABS_DIFF_MAX_12BIT,
+ abs_st_x_value, abs_st_y_value, abs_st_z_value);
+ ret = -ERANGE;
+ goto out;
+ }
+ }
+
+ /* Verify INT1 and INT2 lines */
+
+ if (lis2dh_clear_registers(priv) != OK)
+ {
+ ret = -EIO;
+ goto out;
+ }
+
+ /* Both INT lines should be low */
+
+ if (priv->config->read_int1_pin() != 0)
+ {
+ dbg("INT1 line is HIGH - expected LOW\n");
+ ret = -ENXIO;
+ goto out;
+ }
+
+ if (priv->config->read_int2_pin)
+ {
+ if (priv->config->read_int2_pin() != 0)
+ {
+ dbg("INT2 line is HIGH - expected LOW\n");
+ ret = -ENODEV;
+ goto out;
+ }
+ }
+
+ /* 400Hz ODR all axes enabled
+ FIFO overrun & DATA READY on INT1
+ FIFO enabled and INT1 & INT2 latched
+ FIFO mode, INT1 , THS 0
+ OR combination, all events enabled */
+
+ if ((lis2dh_write_register(priv, ST_LIS2DH_CTRL_REG1, 0x77) != OK) ||
+ (lis2dh_write_register(priv, ST_LIS2DH_CTRL_REG3, 0x12) != OK) ||
+ (lis2dh_write_register(priv, ST_LIS2DH_CTRL_REG5, 0x4a) != OK) ||
+ (lis2dh_write_register(priv, ST_LIS2DH_FIFO_CTRL_REG, 0x40) != OK) ||
+ (lis2dh_write_register(priv, ST_LIS2DH_INT1_CFG_REG, 0x3f) != OK))
+ {
+ dbg("Writing registers for INT line check failed\n");
+ ret = -EIO;
+ goto out;
+ }
+
+ /* Clear INT1 & INT2 */
+
+ if ((lis2dh_read_register(priv, ST_LIS2DH_INT1_SRC_REG) == ERROR) ||
+ (lis2dh_read_register(priv, ST_LIS2DH_INT2_SRC_REG) == ERROR))
+ {
+ dbg("Failed to clear INT1 / INT2 registers\n");
+ ret = -EIO;
+ goto out;
+ }
+
+ usleep(20000);
+
+ /* Now INT1 should have been latched high and INT2 should be still low */
+
+ if (priv->config->read_int1_pin() != 1)
+ {
+ dbg("INT1 line is LOW - expected HIGH\n");
+ ret = -ENXIO;
+ goto out;
+ }
+
+ if (priv->config->read_int2_pin)
+ {
+ if (priv->config->read_int2_pin() != 0)
+ {
+ dbg("INT2 line is HIGH - expected LOW\n");
+ ret = -ENODEV;
+ goto out;
+ }
+
+ /* Enable interupt 1 on INT2 pin */
+
+ if (lis2dh_write_register(priv, ST_LIS2DH_CTRL_REG6, 0x40) != OK)
+ {
+ dbg("Failed to enable interrupt 1 on INT2 pin");
+ ret = -EIO;
+ goto out;
+ }
+
+ usleep(20000);
+
+ if (priv->config->read_int2_pin() != 1)
+ {
+ dbg("INT2 line is LOW - expected HIGH\n");
+ ret = -ENODEV;
+ goto out;
+ }
+ }
+
+out:
+ (void)lis2dh_clear_registers(priv);
+ lis2dh_powerdown(priv);
+
+ return ret;
+}
+
+/****************************************************************************
+ * Name: lis2dh_raw_to_mg
+ *
+ * Description:
+ * Convert raw acceleration value to mg
+ *
+ * Input Parameters:
+ * raw_hibyte - Hi byte of raw data
+ * raw_lobyte - Lo byte of raw data
+ *
+ * Returned Value:
+ * Returns acceleration value in mg
+ ****************************************************************************/
+
+static int16_t lis2dh_raw_convert_to_12bit(uint8_t raw_hibyte,
+ uint8_t raw_lobyte)
+{
+ int16_t value;
+
+ value = (raw_hibyte << 8) | raw_lobyte;
+ value = value >> 4;
+
+ value &= 0xfff;
+ if (value & 0x800)
+ {
+ value = ~value;
+ value &= 0xfff;
+ value += 1;
+ value = -value;
+ }
+
+ return value;
+}
+
+/****************************************************************************
+ * Name: lis2dh_data_available
+ *
+ * Description:
+ * Check if new data is available to read
+ *
+ * Input Parameters:
+ * dev - pointer to LIS2DH Private Structure
+ *
+ * Returned Value:
+ * Return true if new data is available. Otherwise returns false
+ *
+ ****************************************************************************/
+
+static bool lis2dh_data_available(FAR struct lis2dh_dev_s *dev)
+{
+ uint8_t retval;
+
+ DEBUGASSERT(dev);
+
+ if (lis2dh_access(dev, ST_LIS2DH_STATUS_REG, &retval,
+ sizeof(retval)) == sizeof(retval))
+ {
+ return ((retval & ST_LIS2DH_SR_ZYXDA) != 0);
+ }
+ return false;
+}
+
+/****************************************************************************
+ * Name: lis2dh_get_raw_readings
+ *
+ * Description:
+ * Read X, Y, Z - acceleration values from chip
+ *
+ * Input Parameters:
+ * dev - pointer to LIS2DH Private Structure
+ *
+ * Returned Value:
+ * Returns acceleration vectors (High resolution = 12bit values) on
+ * success, NULL otherwise.
+ *
+ ****************************************************************************/
+
+static FAR const struct lis2dh_vector_s *
+ lis2dh_get_raw_readings(FAR struct lis2dh_dev_s *dev, int *err)
+{
+ uint8_t retval[6];
+ uint8_t retries_left = SELFTEST_MAX_READ_ATTEMPTS;
+
+ DEBUGASSERT(dev);
+
+ *err = 0;
+
+ while (--retries_left > 0)
+ {
+ usleep(20000);
+ if (lis2dh_data_available(dev))
+ {
+ if (lis2dh_access(dev, ST_LIS2DH_OUT_X_L_REG, retval,
+ sizeof(retval)) == sizeof(retval))
+ {
+ dev->vector_data.x = lis2dh_raw_convert_to_12bit(retval[1], retval[0]);
+ dev->vector_data.y = lis2dh_raw_convert_to_12bit(retval[3], retval[2]);
+ dev->vector_data.z = lis2dh_raw_convert_to_12bit(retval[5], retval[4]);
+ return &dev->vector_data;
+ }
+
+ return NULL;
+ }
+ }
+
+ return NULL;
+}
+#endif /* CONFIG_LIS2DH_DRIVER_SELFTEST */
+
+/****************************************************************************
+ * Name: lis2dh_clear_interrupts
+ *
+ * Description:
+ * Clear interrupts from LIS2DH chip
+ *
+ ****************************************************************************/
+
+static int lis2dh_clear_interrupts(FAR struct lis2dh_dev_s *priv,
+ uint8_t interrupts)
+{
+ uint8_t buf;
+ int ret = OK;
+
+ if (interrupts & LIS2DH_INT1)
+ {
+ /* Make sure interrupt will get cleared (by reading this register) in
+ * case of latched configuration.
+ */
+
+ if (lis2dh_access(priv, ST_LIS2DH_INT1_SRC_REG, &buf, 1) != 1)
+ {
+ lis2dh_dbg("lis2dh: Failed to read INT1_SRC_REG\n");
+ ret = -EIO;
+ }
+ }
+
+ if (interrupts & LIS2DH_INT2)
+ {
+ /* Make sure interrupt will get cleared (by reading this register) in
+ * case of latched configuration.
+ */
+
+ if (lis2dh_access(priv, ST_LIS2DH_INT2_SRC_REG, &buf, 1) != 1)
+ {
+ lis2dh_dbg("lis2dh: Failed to read INT2_SRC_REG\n");
+ ret = -EIO;
+ }
+ }
+
+ return ret;
+}
+
+/****************************************************************************
+ * Name: lis2dh_get_reading
+ *
+ * Description:
+ * Read X, Y, Z - acceleration value from chip
+ *
+ * Input Parameters:
+ * dev - pointer to LIS2DH Private Structure
+ * force_read - Read even if new data is not available (old data)
+ *
+ * Returned Value:
+ * Returns OK if success, negative error code otherwise
+ *
+ ****************************************************************************/
+
+static int lis2dh_get_reading(FAR struct lis2dh_dev_s *dev,
+ FAR struct lis2dh_vector_s *res,
+ bool force_read)
+{
+ int scale = dev->scale;
+ uint8_t retval[7];
+ int16_t x;
+ int16_t y;
+ int16_t z;
+
+ if (lis2dh_access(dev, ST_LIS2DH_STATUS_REG, retval, 7) == 7)
+ {
+ /* If result is not yet ready, return NULL */
+
+ if (!force_read && !(retval[0] & ST_LIS2DH_SR_ZYXDA))
+ {
+ lis2dh_dbg("lis2dh: Results were not ready\n");
+ return -EAGAIN;
+ }
+
+ /* Add something to entropy pool. */
+
+ add_sensor_randomness((((uint32_t)retval[6] << 25) |
+ ((uint32_t)retval[6] >> 7)) ^
+ ((uint32_t)retval[5] << 20) ^
+ ((uint32_t)retval[4] << 15) ^
+ ((uint32_t)retval[3] << 10) ^
+ ((uint32_t)retval[2] << 5) ^
+ ((uint32_t)retval[1] << 0));
+
+ x = lis2dh_raw_to_mg(retval[2], retval[1], scale);
+ y = lis2dh_raw_to_mg(retval[4], retval[3], scale);
+ z = lis2dh_raw_to_mg(retval[6], retval[5], scale);
+
+ if (dev->setup->xy_axis_fixup)
+ {
+ res->x = y;
+ res->y = -x;
+ }
+ else
+ {
+ res->x = x;
+ res->y = y;
+ }
+
+ res->z = z;
+ return OK;
+ }
+
+ return -EIO;
+}
+
+/****************************************************************************
+ * Name: lis2dh_get_fifo_readings
+ *
+ * Description:
+ * Bulk read from FIFO
+ *
+ ****************************************************************************/
+
+static unsigned int lis2dh_get_fifo_readings(FAR struct lis2dh_dev_s *priv,
+ FAR struct lis2dh_result *res,
+ unsigned int readcount,
+ FAR int *perr)
+{
+ int scale = priv->scale;
+ union
+ {
+ uint8_t raw[6];
+ struct lis2dh_vector_s sample;
+ } *buf = (void *)&res->measurements[res->header.meas_count];
+ bool xy_axis_fixup = priv->setup->xy_axis_fixup;
+ size_t buflen = readcount * 6;
+ int16_t x;
+ int16_t y;
+ int16_t z;
+ unsigned int i;
+
+ if (readcount == 0)
+ {
+ return 0;
+ }
+
+ if (lis2dh_access(priv, ST_LIS2DH_OUT_X_L_REG, (void *)buf, buflen) != buflen)
+ {
+ lis2dh_dbg("lis2dh: Failed to read FIFO (%d bytes, %d samples)\n",
+ buflen, readcount);
+ *perr = -EIO;
+ return 0;
+ }
+
+ /* Add something to entropy pool. */
+
+ up_rngaddentropy(RND_SRC_SENSOR, (void *)buf, buflen / 4);
+
+ /* Convert raw values to mG */
+
+ for (i = 0; i < readcount; i++)
+ {
+ x = lis2dh_raw_to_mg(buf[i].raw[1], buf[i].raw[0], scale);
+ y = lis2dh_raw_to_mg(buf[i].raw[3], buf[i].raw[2], scale);
+ z = lis2dh_raw_to_mg(buf[i].raw[5], buf[i].raw[4], scale);
+
+ if (xy_axis_fixup)
+ {
+ buf[i].sample.x = y;
+ buf[i].sample.y = -x;
+ }
+ else
+ {
+ buf[i].sample.x = x;
+ buf[i].sample.y = y;
+ }
+
+ buf[i].sample.z = z;
+ }
+
+ return readcount;
+}
+
+/****************************************************************************
+ * Name: lis2dh_raw_to_mg
+ *
+ * Description:
+ * Convert raw acceleration value to mg
+ *
+ * Input Parameters:
+ * raw_hibyte - Hi byte of raw data
+ * raw_lobyte - Lo byte of raw data
+ * scale - full scale in milliG
+ *
+ * Returned Value:
+ * Returns acceleration value in mg
+ *
+ ****************************************************************************/
+
+static inline int16_t lis2dh_raw_to_mg(uint8_t raw_hibyte, uint8_t raw_lobyte,
+ int scale)
+{
+ int16_t value;
+
+ /* Value is signed integer, range INT16_MIN..INT16_MAX. */
+
+ value = (raw_hibyte << 8) | raw_lobyte;
+
+ /* Scale to mg, INT16_MIN..INT16_MAX => -scale..scale */
+
+ return (int32_t)value * scale / INT16_MAX;
+}
+
+/****************************************************************************
+ * Name: lis2dh_read_temp
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ * Returned Value:
+ *
+ ****************************************************************************/
+
+static int lis2dh_read_temp(FAR struct lis2dh_dev_s *dev, FAR int16_t *temper)
+{
+ int ret;
+ uint8_t buf[2] = { 0 };
+
+ ret = lis2dh_access(dev, ST_LIS2DH_OUT_TEMP_L_REG, buf, 2);
+ if (ret < 0)
+ {
+ lis2dh_dbg("Cannot read temperature\n");
+ return -EIO;
+ }
+
+ *temper = buf[0] | ((int16_t)buf[1] << 8);
+
+ return OK;
+}
+
+/****************************************************************************
+ * LIS2DH Access with range check
+ *
+ * Description:
+ * Read or write data via I2C
+ *
+ * Input Parameters:
+ * dev LIS2DH Private Structure
+ * subaddr LIS2DH Sub Address
+ * buf Pointer to buffer, either for read or write access
+ * length When >0 it denotes read access, when <0 it denotes write access
+ * of -length
+ *
+ * Returned Value:
+ * Returns actual length of data on success or negated errno.
+ *
+ ****************************************************************************/
+
+static int lis2dh_access(FAR struct lis2dh_dev_s *dev, uint8_t subaddr,
+ FAR uint8_t *buf, int length)
+{
+ uint16_t flags = 0;
+ int retval;
+ int retries;
+
+ DEBUGASSERT(dev != NULL && buf != NULL && length != 0);
+
+ if (length > 0)
+ {
+ flags = I2C_M_READ;
+ }
+ else
+ {
+ flags = I2C_M_NORESTART;
+ length = -length;
+ }
+
+ /* Check valid address ranges and set auto address increment flag */
+
+ if (subaddr == ST_LIS2DH_STATUS_AUX_REG)
+ {
+ if (length > 1)
+ {
+ length = 1;
+ }
+ }
+ else if (subaddr >= ST_LIS2DH_OUT_TEMP_L_REG && subaddr < 0x10)
+ {
+ if (length > (0x10 - subaddr))
+ {
+ length = 0x10 - subaddr;
+ }
+ }
+
+ else if (subaddr >= ST_LIS2DH_TEMP_CFG_REG && subaddr <= ST_LIS2DH_ACT_DUR_REG)
+ {
+ if (subaddr == ST_LIS2DH_OUT_X_L_REG)
+ {
+ /* FIFO bulk read, length maximum 6*32 = 192 bytes. */
+ if (length > 6 * 32)
+ {
+ length = 6 * 32;
+ }
+ }
+ else
+ {
+ if (length > (ST_LIS2DH_ACT_DUR_REG + 1 - subaddr))
+ {
+ length = ST_LIS2DH_ACT_DUR_REG + 1 - subaddr;
+ }
+ }
+ }
+ else
+ {
+ return -EFAULT;
+ }
+
+ if (length > 1)
+ {
+ subaddr |= 0x80;
+ }
+
+ for (retries = 0; retries < LIS2DH_I2C_RETRIES; retries++)
+ {
+ /* Create message and send */
+
+ struct i2c_msg_s msgv[2] =
+ {
+ {
+ .addr = dev->addr,
+ .flags = 0,
+ .buffer = &subaddr,
+ .length = 1
+ },
+ {
+ .addr = dev->addr,
+ .flags = flags,
+ .buffer = buf,
+ .length = length
+ }
+ };
+
+ retval = I2C_TRANSFER(dev->i2c, msgv, 2);
+ if (retval == OK)
+ {
+ return length;
+ }
+ else
+ {
+ /* Some error. Try to reset I2C bus and keep trying. */
+#ifdef CONFIG_I2C_RESET
+ int ret = up_i2creset(dev->i2c);
+ if (ret < 0)
+ {
+ lis2dh_dbg("up_i2creset failed: %d\n", ret);
+ return ret;
+ }
+#endif
+ continue;
+ }
+ }
+
+ lis2dh_dbg("failed, error: %d\n", retval);
+ return retval;
+}
+
+/****************************************************************************
+ * Name: lis2dh_reboot
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ * Returned Value:
+ *
+ ****************************************************************************/
+
+static int lis2dh_reboot(FAR struct lis2dh_dev_s *dev)
+{
+ struct timespec start, curr;
+ int32_t diff_msec;
+ uint8_t value;
+
+ (void)clock_gettime(CLOCK_MONOTONIC, &start);
+
+ /* Reboot to reset chip. */
+
+ value = ST_LIS2DH_CR5_BOOT;
+ if (lis2dh_access(dev, ST_LIS2DH_CTRL_REG5, &value, -1) != 1)
+ {
+ return -EIO;
+ }
+
+ /* Reboot is completed when reboot bit is cleared. */
+
+ do
+ {
+ value = 0;
+ if (lis2dh_access(dev, ST_LIS2DH_CTRL_REG5, &value, 1) != 1)
+ {
+ return -EIO;
+ }
+
+ if (!(value & ST_LIS2DH_CR5_BOOT))
+ {
+ break;
+ }
+
+ (void)clock_gettime(CLOCK_MONOTONIC, &curr);
+
+ diff_msec = (curr.tv_sec - start.tv_sec) * 1000;
+ diff_msec += (curr.tv_nsec - start.tv_nsec) / (1000 * 1000);
+
+ if (diff_msec > 100)
+ {
+ return -ETIMEDOUT;
+ }
+
+ usleep(1);
+ }
+ while (true);
+
+ /* Reboot completed, chip is now in power-down state. */
+
+ return OK;
+}
+
+/****************************************************************************
+ * Name: lis2dh_powerdown
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ * Returned Value:
+ *
+ ****************************************************************************/
+
+static int lis2dh_powerdown(FAR struct lis2dh_dev_s * dev)
+{
+ uint8_t buf = 0;
+ int ret = OK;
+
+ if (lis2dh_access(dev, ST_LIS2DH_CTRL_REG1, &buf, -1) != 1)
+ {
+ lis2dh_dbg("Failed to clear CTRL_REG1\n");
+ ret = -EIO;
+ }
+
+ return ret;
+}
+
+/****************************************************************************
+ * LIS2DH Setup
+ *
+ * Description:
+ * Apply new register setup
+ *
+ * Input Parameters:
+ * dev - pointer to LIS2DH Private Structure
+ * new_setup - pointer to new setup data to be configured
+ *
+ * Returned Value:
+ * Returns OK on success, ERROR otherwise.
+ *
+ ****************************************************************************/
+
+static int lis2dh_setup(FAR struct lis2dh_dev_s * dev,
+ FAR struct lis2dh_setup *new_setup)
+{
+ uint8_t value;
+
+ dev->setup = new_setup;
+
+ /* Clear old configuration. On first boot after power-loss, reboot bit does
+ * not get cleared, and lis2dh_reboot() times out. Anyway, chip accepts
+ * new configuration and functions correctly. */
+
+ (void)lis2dh_reboot(dev);
+
+ /* TEMP_CFG_REG */
+
+ value = dev->setup->temp_enable ? (0x3 << 6): 0;
+ if (lis2dh_access(dev, ST_LIS2DH_TEMP_CFG_REG, &value, -1) != 1)
+ {
+ goto error;
+ }
+
+ /* CTRL_REG2 */
+
+ value = dev->setup->hpmode | dev->setup->hpcf | dev->setup->fds |
+ dev->setup->hpclick | dev->setup->hpis2 | dev->setup->hpis1;
+ if (lis2dh_access(dev, ST_LIS2DH_CTRL_REG2, &value, -1) != 1)
+ {
+ goto error;
+ }
+
+ /* CTRL_REG3 */
+
+ value = dev->setup->int1_click_enable | dev->setup->int1_aoi_enable |
+ dev->setup->int2_aoi_enable | dev->setup->int1_drdy_enable |
+ dev->setup->int2_drdy_enable | dev->setup->int_wtm_enable |
+ dev->setup->int_overrun_enable;
+ if (lis2dh_access(dev, ST_LIS2DH_CTRL_REG3, &value, -1) != 1)
+ {
+ goto error;
+ }
+
+ /* CTRL_REG4 */
+
+ value = dev->setup->bdu | dev->setup->endian | dev->setup->fullscale |
+ dev->setup->high_resolution_enable | dev->setup->selftest |
+ dev->setup->spi_mode;
+ if (lis2dh_access(dev, ST_LIS2DH_CTRL_REG4, &value, -1) != 1)
+ {
+ goto error;
+ }
+
+ /* CTRL_REG5 */
+
+ value = dev->setup->reboot | dev->setup->fifo_enable | dev->setup->int1_latch |
+ dev->setup->int1_4d_enable | dev->setup->int2_latch |
+ dev->setup->int2_4d_enable;
+ if (lis2dh_access(dev, ST_LIS2DH_CTRL_REG5, &value, -1) != 1)
+ {
+ goto error;
+ }
+
+ /* CTRL_REG6 */
+
+ value = dev->setup->int2_click_enable | dev->setup->int_enable |
+ dev->setup->boot_int1_enable | dev->setup->high_low_active;
+ if (lis2dh_access(dev, ST_LIS2DH_CTRL_REG6, &value, -1) != 1)
+ {
+ goto error;
+ }
+
+ /* REFERENCE */
+
+ value = dev->setup->reference;
+ if (lis2dh_access(dev, ST_LIS2DH_REFERENCE_REG, &value, -1) != 1)
+ {
+ goto error;
+ }
+
+ /* FIFO_CTRL_REG */
+
+ value = dev->setup->fifo_mode | dev->setup->trigger_selection |
+ dev->setup->fifo_trigger_threshold;
+ if (lis2dh_access(dev, ST_LIS2DH_FIFO_CTRL_REG, &value, -1) != 1)
+ {
+ goto error;
+ }
+
+ /* INT1_CFG */
+
+ value = dev->setup->int1_interrupt_mode | dev->setup->int1_enable_6d | dev->setup->int1_int_z_high_enable |
+ dev->setup->int1_int_z_low_enable | dev->setup->int1_int_y_high_enable |
+ dev->setup->int1_int_y_low_enable | dev->setup->int1_int_x_high_enable |
+ dev->setup->int1_int_x_low_enable;
+ if (lis2dh_access(dev, ST_LIS2DH_INT1_CFG_REG, &value, -1) != 1)
+ {
+ goto error;
+ }
+
+ /* INT1_THS */
+
+ value = dev->setup->int1_int_threshold;
+ if (lis2dh_access(dev, ST_LIS2DH_INT1_THS_REG, &value, -1) != 1)
+ {
+ goto error;
+ }
+
+ /* INT1_DURATION */
+
+ value = dev->setup->int1_int_duration;
+ if (lis2dh_access(dev, ST_LIS2DH_INT1_DUR_REG, &value, -1) != 1)
+ {
+ goto error;
+ }
+
+ /* INT2_CFG */
+
+ value = dev->setup->int2_interrupt_mode | dev->setup->int2_enable_6d | dev->setup->int2_int_z_high_enable |
+ dev->setup->int2_int_z_low_enable | dev->setup->int2_int_y_high_enable |
+ dev->setup->int2_int_y_low_enable | dev->setup->int2_int_x_high_enable |
+ dev->setup->int2_int_x_low_enable;
+ if (lis2dh_access(dev, ST_LIS2DH_INT2_CFG_REG, &value, -1) != 1)
+ {
+ goto error;
+ }
+
+ /* INT2_THS */
+
+ value = dev->setup->int2_int_threshold;
+ if (lis2dh_access(dev, ST_LIS2DH_INT2_THS_REG, &value, -1) != 1)
+ {
+ goto error;
+ }
+
+ /* INT2_DURATION */
+
+ value = dev->setup->int2_int_duration;
+ if (lis2dh_access(dev, ST_LIS2DH_INT2_DUR_REG, &value, -1) != 1)
+ {
+ goto error;
+ }
+
+ /* CLICK_CFG */
+
+ value = dev->setup->z_double_click_enable | dev->setup->z_single_click_enable |
+ dev->setup->y_double_click_enable | dev->setup->y_single_click_enable |
+ dev->setup->x_double_click_enable | dev->setup->x_single_click_enable;
+ if (lis2dh_access(dev, ST_LIS2DH_CLICK_CFG_REG, &value, -1) != 1)
+ {
+ goto error;
+ }
+
+ /* CLICK_THS */
+
+ value = dev->setup->click_threshold;
+ if (lis2dh_access(dev, ST_LIS2DH_CLICK_THS_REG, &value, -1) != 1)
+ {
+ goto error;
+ }
+
+ /* TIME_LIMIT */
+
+ value = dev->setup->click_time_limit;
+ if (lis2dh_access(dev, ST_LIS2DH_TIME_LIMIT_REG, &value, -1) != 1)
+ {
+ goto error;
+ }
+
+ /* TIME_LATENCY */
+
+ value = dev->setup->click_time_latency;
+ if (lis2dh_access(dev, ST_LIS2DH_TIME_LATENCY_REG, &value, -1) != 1)
+ {
+ goto error;
+ }
+
+ /* TIME_WINDOW */
+
+ value = dev->setup->click_time_window;
+ if (lis2dh_access(dev, ST_LIS2DH_TIME_WINDOW_REG, &value, -1) != 1)
+ {
+ goto error;
+ }
+
+ /* CTRL_REG1 */
+
+ value = dev->setup->data_rate | dev->setup->low_power_mode_enable |
+ dev->setup->zen | dev->setup->yen | dev->setup->xen;
+ if (lis2dh_access(dev, ST_LIS2DH_CTRL_REG1, &value, -1) != 1)
+ {
+ goto error;
+ }
+
+ switch (dev->setup->fullscale & 0x30)
+ {
+ default:
+ case ST_LIS2DH_CR4_FULL_SCALE_2G:
+ dev->scale = 2000;
+ break;
+
+ case ST_LIS2DH_CR4_FULL_SCALE_4G:
+ dev->scale = 4000;
+ break;
+
+ case ST_LIS2DH_CR4_FULL_SCALE_8G:
+ dev->scale = 8000;
+ break;
+
+ case ST_LIS2DH_CR4_FULL_SCALE_16G:
+ dev->scale = 16000;
+ break;
+ }
+
+ if (dev->setup->fifo_enable)
+ {
+ dev->fifo_used = true;
+
+ if (lis2dh_fifo_start(dev) < 0)
+ {
+ goto error;
+ }
+ }
+ else
+ {
+ dev->fifo_used = false;
+ }
+
+ return OK;
+
+error:
+
+ /* Setup failed - power down */
+
+ lis2dh_powerdown(dev);
+ return -EIO;
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: lis2dh_register
+ *
+ * Description:
+ * Register the LIS2DH character device as 'devpath'
+ *
+ * Input Parameters:
+ * devpath - The full path to the driver to register. E.g., "/dev/acc0"
+ * i2c - An instance of the I2C interface to use to communicate with LIS2DH
+ * addr - The I2C address of the LIS2DH. The base I2C address of the LIS2DH
+ * is 0x18. Bit 0 can be controlled via SA0 pad - when connected to
+ * voltage supply the address is 0x19.
+ * config - Pointer to LIS2DH configuration
+ *
+ * Returned Value:
+ * Zero (OK) on success; a negated errno value on failure.
+ *
+ ****************************************************************************/
+
+int lis2dh_register(FAR const char *devpath, FAR struct i2c_master_s *i2c,
+ uint8_t addr, FAR struct lis2dh_config_s *config)
+{
+ FAR struct lis2dh_dev_s *priv;
+ int ret;
+
+ DEBUGASSERT(devpath != NULL && i2c != NULL && config != NULL);
+
+ priv = (FAR struct lis2dh_dev_s *)kmm_zalloc(sizeof(struct lis2dh_dev_s));
+ if (!priv)
+ {
+ lis2dh_dbg("lis2dh: Failed to allocate instance\n");
+ return -ENOMEM;
+ }
+
+ sem_init(&priv->devsem, 0, 1);
+
+ priv->fifo_used = false;
+#ifdef LIS2DH_COUNT_INTS
+ priv->int_pending = 0;
+#else
+ priv->int_pending = false;
+#endif
+
+ priv->i2c = i2c;
+ priv->addr = addr;
+ priv->config = config;
+
+ ret = register_driver(devpath, &g_lis2dhops, 0666, priv);
+ if (ret < 0)
+ {
+ lis2dh_dbg("lis2dh: Failed to register driver: %d\n", ret);
+ goto errout_with_priv;
+ }
+
+ if (priv->config->irq_clear)
+ {
+ priv->config->irq_clear(config);
+ }
+ priv->config->irq_attach(config, lis2dh_int_handler, priv);
+ priv->config->irq_enable(config, false);
+ return OK;
+
+errout_with_priv:
+ sem_destroy(&priv->devsem);
+ kmm_free(priv);
+
+ return ret;
+}
diff --git a/drivers/sensors/lps25h.c b/drivers/sensors/lps25h.c
new file mode 100644
index 00000000000..3ebba982857
--- /dev/null
+++ b/drivers/sensors/lps25h.c
@@ -0,0 +1,793 @@
+/****************************************************************************
+ * drivers/sensors/lps25h.c
+ *
+ * Copyright (C) 2014-2017 Haltian Ltd. All rights reserved.
+ *
+ * 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
+
+/****************************************************************************
+ * Pre-Processor Definitions
+ ****************************************************************************/
+
+#ifdef CONFIG_DEBUG_LPS25H
+# define lps25h_dbg(x, ...) _info(x, ##__VA_ARGS__)
+#else
+# define lps25h_dbg(x, ...) sninfo(x, ##__VA_ARGS__)
+#endif
+
+#define LPS25H_PRESSURE_INTERNAL_DIVIDER 4096
+
+/* 'AN4450 - Hardware and software guidelines for use of LPS25H pressure
+ * sensors' - '6.2 One-shot mode conversion time estimation' gives estimates
+ * for conversion times:
+ *
+ * Typical conversion time ≈ 62*(Pavg+Tavg) + 975 μs
+ * ex: Tavg = 64; Pavg = 512; Typ. conversation time ≈ 36.7 ms (compatible with
+ * ODT=25 Hz)
+ * ex: Tavg = 32; Pavg = 128; Typ. conversation time ≈ 10.9 ms
+ * The formula is accurate within +/- 3% at room temperature
+ *
+ * Set timeout to 2 * max.conversation time (2*36.7*1.03 = 76 ms).
+ */
+
+#define LPS25H_RETRY_TIMEOUT_MSECS 76
+#define LPS25H_MAX_RETRIES 5
+
+#define LPS25H_I2C_RETRIES 10
+
+/* Registers */
+
+#define LPS25H_REF_P_XL 0x08
+#define LPS25H_REF_P_L 0x09
+#define LPS25H_REF_P_H 0x0a
+#define LPS25H_WHO_AM_I 0x0f
+#define LPS25H_RES_CONF 0x10
+#define LPS25H_CTRL_REG1 0x20
+#define LPS25H_CTRL_REG2 0x21
+#define LPS25H_CTRL_REG3 0x22
+#define LPS25H_CTRL_REG4 0x23
+#define LPS25H_INT_CFG 0x24
+#define LPS25H_INT_SOURCE 0x25
+#define LPS25H_STATUS_REG 0x27
+#define LPS25H_PRESS_POUT_XL 0x28
+#define LPS25H_PRESS_OUT_L 0x29
+#define LPS25H_PRESS_OUT_H 0x2a
+#define LPS25H_TEMP_OUT_L 0x2b
+#define LPS25H_TEMP_OUT_H 0x2c
+#define LPS25H_FIFO_CTRL 0x2e
+#define LPS25H_FIFO_STATUS 0x2f
+#define LPS25H_THS_P_L 0x30
+#define LPS25H_THS_P_H 0x31
+#define LPS25H_RPDS_L 0x39
+#define LPS25H_RPDS_H 0x3a
+
+/* Bits in registers */
+
+#define LPS25H_AUTO_ZERO (1 << 2)
+#define LPS25H_BDU (1 << 2)
+#define LPS25H_DIFF_EN (1 << 3)
+#define LPS25H_FIFO_EN (1 << 6)
+#define LPS25H_WTM_EN (1 << 5)
+#define LPS25H_FIFO_MEAN_DEC (1 << 4)
+#define LPS25H_PD (1 << 7)
+#define LPS25H_ONE_SHOT (1 << 0)
+#define LPS25H_INT_H_L (1 << 7)
+#define LPS25H_PP_OD (1 << 6)
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+struct lps25h_dev_s
+{
+ struct i2c_master_s *i2c;
+ uint8_t addr;
+ bool irqenabled;
+ volatile bool int_pending;
+ sem_t devsem;
+ sem_t waitsem;
+ lps25h_config_t *config;
+};
+
+enum LPS25H_RES_CONF_AVG_PRES
+{
+ PRES_AVG_8 = 0,
+ PRES_AVG_32,
+ PRES_AVG_128,
+ PRES_AVG_512
+};
+
+enum LPS25H_RES_CONF_AVG_TEMP
+{
+ TEMP_AVG_8 = 0,
+ TEMP_AVG_16,
+ TEMP_AVG_32,
+ TEMP_AVG_64
+};
+
+enum LPS25H_CTRL_REG1_ODR
+{
+ CTRL_REG1_ODR_ONE_SHOT = 0,
+ CTRL_REG1_ODR_1Hz,
+ CTRL_REG1_ODR_7Hz,
+ CTRL_REG1_ODR_12_5Hz,
+ CTRL_REG1_ODR_25Hz
+};
+
+enum LPS25H_CTRL_REG4_P1
+{
+ P1_DRDY = 0x1,
+ P1_OVERRUN = 0x02,
+ P1_WTM = 0x04,
+ P1_EMPTY = 0x08
+};
+
+enum LPS25H_FIFO_CTRL_MODE
+{
+ BYPASS_MODE = 0x0,
+ FIFO_STOP_WHEN_FULL,
+ STREAM_NEWEST_IN_FIFO,
+ STREAM_DEASSERTED,
+ BYPASS_DEASSERTED_STREAM,
+ FIFO_MEAN = 0x06,
+ BYPASS_DEASSERTED_FIFO
+};
+
+enum LPS25H_FIFO_CTRL_WTM
+{
+ SAMPLE_2 = 0x01,
+ SAMPLE_4 = 0x03,
+ SAMPLE_8 = 0x07,
+ SAMPLE_16 = 0x0f,
+ SAMPLE_32 = 0x1f
+};
+
+enum LPS25H_INT_CFG_OP
+{
+ PH_E = 0x1,
+ PL_E = 0x2,
+ LIR = 0x4
+};
+
+/************************************************************************************
+ * Private Function Prototypes
+ ************************************************************************************/
+
+static int lps25h_open(FAR struct file *filep);
+static int lps25h_close(FAR struct file *filep);
+static ssize_t lps25h_read(FAR struct file *filep, FAR char *buffer,
+ size_t buflen);
+static ssize_t lps25h_write(FAR struct file *filep, FAR const char *buffer,
+ size_t buflen);
+static int lps25h_ioctl(FAR struct file *filep, int cmd, unsigned long arg);
+
+static int lps25h_configure_dev(FAR struct lps25h_dev_s *dev);
+static int lps25h_read_pressure(FAR struct lps25h_dev_s *dev,
+ FAR lps25h_pressure_data_t *pres);
+static int lps25h_read_temper(FAR struct lps25h_dev_s *dev,
+ FAR lps25h_temper_data_t *temper);
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+static const struct file_operations g_lps25hops =
+{
+ lps25h_open, /* open */
+ lps25h_close, /* close */
+ lps25h_read, /* read */
+ lps25h_write, /* write */
+ NULL, /* seek */
+ lps25h_ioctl /* ioctl */
+#ifndef CONFIG_DISABLE_POLL
+ , NULL /* poll */
+#endif
+#ifndef CONFIG_DISABLE_PSEUDOFS_OPERATIONS
+ , NULL /* unlink */
+ #endif
+};
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+static int lps25h_do_transfer(FAR struct lps25h_dev_s *dev,
+ FAR struct i2c_msg_s *msgv,
+ size_t nmsg)
+{
+ int ret = -EIO;
+ int retries;
+
+ for (retries = 0; retries < LPS25H_I2C_RETRIES; retries++)
+ {
+ ret = I2C_TRANSFER(dev->i2c, msgv, nmsg);
+ if (ret >= 0)
+ {
+ return 0;
+ }
+ else
+ {
+ /* Some error. Try to reset I2C bus and keep trying. */
+#ifdef CONFIG_I2C_RESET
+ if (retries == LPS25H_I2C_RETRIES - 1)
+ {
+ break;
+ }
+
+ ret = up_i2creset(dev->i2c);
+ if (ret < 0)
+ {
+ lps25h_dbg("up_i2creset failed: %d\n", ret);
+ return ret;
+ }
+#endif
+ }
+ }
+
+ lps25h_dbg("xfer failed: %d\n", ret);
+ return ret;
+}
+
+static int lps25h_write_reg8(struct lps25h_dev_s *dev, uint8_t reg_addr,
+ const uint8_t value)
+{
+ struct i2c_msg_s msgv[2] =
+ {
+ {
+ .addr = dev->addr,
+ .flags = 0,
+ .buffer = ®_addr,
+ .length = 1
+ },
+ {
+ .addr = dev->addr,
+ .flags = I2C_M_NORESTART,
+ .buffer = (void *)&value,
+ .length = 1
+ }
+ };
+
+ return lps25h_do_transfer(dev, msgv, 2);
+}
+
+static int lps25h_read_reg8(FAR struct lps25h_dev_s *dev,
+ FAR uint8_t *reg_addr,
+ FAR uint8_t *value)
+{
+ struct i2c_msg_s msgv[2] =
+ {
+ {
+ .addr = dev->addr,
+ .flags = 0,
+ .buffer = reg_addr,
+ .length = 1
+ },
+ {
+ .addr = dev->addr,
+ .flags = I2C_M_READ,
+ .buffer = value,
+ .length = 1
+ }
+ };
+
+ return lps25h_do_transfer(dev, msgv, 2);
+}
+
+static int lps25h_power_on_off(FAR struct lps25h_dev_s *dev, bool on)
+{
+ int ret;
+ uint8_t value;
+
+ value = on ? LPS25H_PD : 0;
+ ret = lps25h_write_reg8(dev, LPS25H_CTRL_REG1, value);
+ return ret;
+}
+
+static int lps25h_open(FAR struct file *filep)
+{
+ FAR struct inode *inode = filep->f_inode;
+ FAR struct lps25h_dev_s *dev = inode->i_private;
+ uint8_t value = 0;
+ uint8_t addr = LPS25H_WHO_AM_I;
+ int32_t ret;
+
+ while (sem_wait(&dev->devsem) != 0)
+ {
+ assert(errno == EINTR);
+ }
+
+ dev->config->set_power(dev->config, true);
+ ret = lps25h_read_reg8(dev, &addr, &value);
+ if (ret < 0)
+ {
+ lps25h_dbg("Cannot read device's ID\n");
+ dev->config->set_power(dev->config, false);
+ goto out;
+ }
+
+ lps25h_dbg("WHO_AM_I: 0x%2x\n", value);
+
+ dev->config->irq_enable(dev->config, true);
+ dev->irqenabled = true;
+
+out:
+ sem_post(&dev->devsem);
+ return ret;
+}
+
+static int lps25h_close(FAR struct file *filep)
+{
+ FAR struct inode *inode = filep->f_inode;
+ FAR struct lps25h_dev_s *dev = inode->i_private;
+ int ret;
+
+ while (sem_wait(&dev->devsem) != 0)
+ {
+ assert(errno == EINTR);
+ }
+
+ dev->config->irq_enable(dev->config, false);
+ dev->irqenabled = false;
+ ret = lps25h_power_on_off(dev, false);
+ dev->config->set_power(dev->config, false);
+ lps25h_dbg("CLOSED\n");
+
+ sem_post(&dev->devsem);
+ return ret;
+}
+
+static ssize_t lps25h_read(FAR struct file *filep, FAR char *buffer,
+ size_t buflen)
+{
+ FAR struct inode *inode = filep->f_inode;
+ FAR struct lps25h_dev_s *dev = inode->i_private;
+ int ret;
+ ssize_t length = 0;
+ lps25h_pressure_data_t data;
+
+ while (sem_wait(&dev->devsem) != 0)
+ {
+ assert(errno == EINTR);
+ }
+
+ ret = lps25h_configure_dev(dev);
+ if (ret < 0)
+ {
+ lps25h_dbg("cannot configure sensor: %d\n", ret);
+ goto out;
+ }
+
+ ret = lps25h_read_pressure(dev, &data);
+ if (ret < 0)
+ {
+ lps25h_dbg("cannot read data: %d\n", ret);
+ }
+ else
+ {
+ /* This interface is mainly intended for easy debugging in nsh. */
+
+ length = snprintf(buffer, buflen, "%u\n", data.pressure_Pa);
+ if (length > buflen)
+ {
+ length = buflen;
+ }
+ }
+
+out:
+ sem_post(&dev->devsem);
+ return length;
+}
+
+static ssize_t lps25h_write(FAR struct file *filep, FAR const char *buffer,
+ size_t buflen)
+{
+ ssize_t length = 0;
+
+ return length;
+}
+
+static void lps25h_notify(FAR struct lps25h_dev_s *dev)
+{
+ DEBUGASSERT(dev != NULL);
+
+ dev->int_pending = true;
+ sem_post(&dev->waitsem);
+}
+
+static int lps25h_int_handler(int irq, FAR void *context, FAR void *arg)
+{
+ FAR struct lps25h_dev_s *dev = (FAR struct lps25h_dev_s *)arg;
+
+ DEBUGASSERT(dev != NULL);
+
+ lps25h_notify(dev);
+ lps25h_dbg("lps25h interrupt\n");
+ return OK;
+}
+
+static int lps25h_configure_dev(FAR struct lps25h_dev_s *dev)
+{
+ int ret = 0;
+
+ ret = lps25h_power_on_off(dev, false);
+ if (ret < 0)
+ {
+ return ret;
+ }
+
+ /* Enable FIFO */
+
+ ret = lps25h_write_reg8(dev, LPS25H_CTRL_REG2, LPS25H_FIFO_EN);
+ if (ret < 0)
+ {
+ return ret;
+ }
+
+ ret = lps25h_write_reg8(dev, LPS25H_FIFO_CTRL, (BYPASS_MODE << 5));
+ if (ret < 0)
+ {
+ return ret;
+ }
+
+ ret = lps25h_write_reg8(dev, LPS25H_CTRL_REG4, P1_DRDY);
+ if (ret < 0)
+ {
+ return ret;
+ }
+
+ /* Write CTRL_REG1 to turn device on */
+
+ ret = lps25h_write_reg8(dev, LPS25H_CTRL_REG1,
+ LPS25H_PD | (CTRL_REG1_ODR_1Hz << 4));
+
+ return ret;
+}
+
+static int lps25h_one_shot(FAR struct lps25h_dev_s *dev)
+{
+ int ret = ERROR;
+ int retries;
+ struct timespec abstime;
+ irqstate_t flags;
+
+ if (!dev->irqenabled)
+ {
+ lps25h_dbg("IRQ disabled!\n");
+ }
+
+ /* Retry one-shot measurement multiple times. */
+
+ for (retries = 0; retries < LPS25H_MAX_RETRIES; retries++)
+ {
+ /* Power off so we start from a known state. */
+
+ ret = lps25h_power_on_off(dev, false);
+ if (ret < 0)
+ {
+ return ret;
+ }
+
+ /* Initiate a one shot mode measurement */
+
+ ret = lps25h_write_reg8(dev, LPS25H_CTRL_REG2, LPS25H_ONE_SHOT);
+ if (ret < 0)
+ {
+ return ret;
+ }
+
+ /* Power on to start measurement. */
+
+ ret = lps25h_power_on_off(dev, true);
+ if (ret < 0)
+ {
+ return ret;
+ }
+
+ (void)clock_gettime(CLOCK_REALTIME, &abstime);
+ abstime.tv_sec += (LPS25H_RETRY_TIMEOUT_MSECS / 1000);
+ abstime.tv_nsec += (LPS25H_RETRY_TIMEOUT_MSECS % 1000) * 1000 * 1000;
+ while (abstime.tv_nsec >= (1000 * 1000 * 1000))
+ {
+ abstime.tv_sec++;
+ abstime.tv_nsec -= 1000 * 1000 * 1000;
+ }
+
+ while ((ret = sem_timedwait(&dev->waitsem, &abstime)) != 0)
+ {
+ int err = errno;
+ if (err == EINTR)
+ {
+ continue;
+ }
+ else if (err == ETIMEDOUT)
+ {
+ uint8_t reg = LPS25H_CTRL_REG2;
+ uint8_t value;
+
+ /* In 'AN4450 - Hardware and software guidelines for use of
+ * LPS25H pressure sensors' - '4.3 One-shot mode measurement
+ * sequence', one-shot mode example is given where interrupt line
+ * is not used, but CTRL_REG2 is polled until ONE_SHOT bit is
+ * unset (as it is self-clearing). Check ONE_SHOT bit status here
+ * to see if we just missed interrupt.
+ */
+
+ ret = lps25h_read_reg8(dev, ®, &value);
+ if (ret < 0)
+ {
+ break;
+ }
+
+ if ((value & LPS25H_ONE_SHOT) == 0)
+ {
+ /* One-shot completed. */
+
+ ret = OK;
+ break;
+ }
+ }
+ else
+ {
+ /* Some unknown mystery error */
+
+ DEBUGASSERT(false);
+ return -err;
+ }
+ }
+
+ if (ret == OK)
+ {
+ break;
+ }
+
+ lps25h_dbg("Retrying one-shot measurement: retries=%d\n", retries);
+ }
+
+ if (ret != OK)
+ {
+ return -ETIMEDOUT;
+ }
+
+ flags = enter_critical_section();
+ dev->int_pending = false;
+ leave_critical_section(flags);
+
+ return ret;
+}
+
+static int lps25h_read_pressure(FAR struct lps25h_dev_s *dev,
+ FAR lps25h_pressure_data_t *pres)
+{
+ int ret;
+ uint8_t pres_addr_h = LPS25H_PRESS_OUT_H;
+ uint8_t pres_addr_l = LPS25H_PRESS_OUT_L;
+ uint8_t pres_addr_xl = LPS25H_PRESS_POUT_XL;
+ uint8_t pres_value_h = 0;
+ uint8_t pres_value_l = 0;
+ uint8_t pres_value_xl = 0;
+ int32_t pres_res = 0;
+
+ ret = lps25h_one_shot(dev);
+ if (ret < 0)
+ {
+ return ret;
+ }
+
+ ret = lps25h_read_reg8(dev, &pres_addr_h, &pres_value_h);
+ if (ret < 0)
+ {
+ return ret;
+ }
+
+ ret = lps25h_read_reg8(dev, &pres_addr_l, &pres_value_l);
+ if (ret < 0)
+ {
+ return ret;
+ }
+
+ ret = lps25h_read_reg8(dev, &pres_addr_xl, &pres_value_xl);
+ if (ret < 0)
+ {
+ return ret;
+ }
+
+ pres_res = ((int32_t) pres_value_h << 16) |
+ ((int16_t) pres_value_l << 8) |
+ pres_value_xl;
+
+ /* Add to entropy pool. */
+
+ add_sensor_randomness(pres_res);
+
+ /* Convert to more usable format. */
+
+ pres->pressure_int_hP = pres_res / LPS25H_PRESSURE_INTERNAL_DIVIDER;
+ pres->pressure_Pa = (uint64_t)pres_res * 100000 / LPS25H_PRESSURE_INTERNAL_DIVIDER;
+ pres->raw_data = pres_res;
+ lps25h_dbg("Pressure: %u Pa\n", pres->pressure_Pa);
+
+ return ret;
+}
+
+static int lps25h_read_temper(FAR struct lps25h_dev_s *dev,
+ FAR lps25h_temper_data_t *temper)
+{
+ int ret;
+ uint8_t temper_addr_h = LPS25H_TEMP_OUT_H;
+ uint8_t temper_addr_l = LPS25H_TEMP_OUT_L;
+ uint8_t temper_value_h = 0;
+ uint8_t temper_value_l = 0;
+ int32_t temper_res;
+ int16_t raw_data;
+
+ ret = lps25h_read_reg8(dev, &temper_addr_h, &temper_value_h);
+ if (ret < 0)
+ {
+ return ret;
+ }
+
+ ret = lps25h_read_reg8(dev, &temper_addr_l, &temper_value_l);
+ if (ret < 0)
+ {
+ return ret;
+ }
+
+ raw_data = (temper_value_h << 8) | temper_value_l;
+
+ /* Add to entropy pool. */
+
+ add_sensor_randomness(raw_data);
+
+ /* T(â°C) = 42.5 + (raw / 480)
+ * =>
+ * T(â°C) * scale = (425 * 48 + raw) * scale / 480;
+ */
+
+ temper_res = (425 * 48 + raw_data);
+ temper_res *= LPS25H_TEMPER_DIVIDER;
+ temper_res /= 480;
+
+ temper->int_temper = temper_res;
+ temper->raw_data = raw_data;
+ lps25h_dbg("Temperature: %d\n", temper_res);
+
+ return ret;
+}
+
+static int lps25h_who_am_i(struct lps25h_dev_s *dev,
+ lps25h_who_am_i_data * who_am_i_data)
+{
+ uint8_t who_addr = LPS25H_WHO_AM_I;
+ return lps25h_read_reg8(dev, &who_addr, &who_am_i_data->who_am_i);
+}
+
+static int lps25h_ioctl(FAR struct file *filep, int cmd, unsigned long arg)
+{
+ FAR struct inode *inode = filep->f_inode;
+ FAR struct lps25h_dev_s *dev = inode->i_private;
+ int ret = 0;
+
+ while (sem_wait(&dev->devsem) != 0)
+ {
+ assert(errno == EINTR);
+ }
+
+ switch (cmd)
+ {
+ case SNIOC_CFGR:
+ ret = lps25h_configure_dev(dev);
+ break;
+
+ case SNIOC_PRESSURE_OUT:
+ ret = lps25h_read_pressure(dev, (lps25h_pressure_data_t *) arg);
+ break;
+
+ case SNIOC_TEMPERATURE_OUT:
+ /* NOTE: call SNIOC_PRESSURE_OUT before this one,
+ * or results are bogus.
+ */
+
+ ret = lps25h_read_temper(dev, (lps25h_temper_data_t *) arg);
+ break;
+
+ case SNIOC_SENSOR_OFF:
+ ret = lps25h_power_on_off(dev, false);
+ break;
+
+ case SNIOC_GET_DEV_ID:
+ ret = lps25h_who_am_i(dev, (lps25h_who_am_i_data *) arg);
+ break;
+
+ default:
+ ret = -EINVAL;
+ break;
+ }
+
+ sem_post(&dev->devsem);
+ return ret;
+}
+
+int lps25h_register(FAR const char *devpath, FAR struct i2c_master_s *i2c,
+ uint8_t addr, FAR lps25h_config_t *config)
+{
+ int ret = 0;
+ FAR struct lps25h_dev_s *dev;
+
+ dev = (struct lps25h_dev_s *)kmm_zalloc(sizeof(struct lps25h_dev_s));
+ if (!dev)
+ {
+ lps25h_dbg("Memory cannot be allocated for LPS25H sensor\n");
+ return -ENOMEM;
+ }
+
+ sem_init(&dev->devsem, 0, 1);
+ sem_init(&dev->waitsem, 0, 0);
+
+ dev->addr = addr;
+ dev->i2c = i2c;
+ dev->config = config;
+
+ if (dev->config->irq_clear)
+ {
+ dev->config->irq_clear(dev->config);
+ }
+
+ ret = register_driver(devpath, &g_lps25hops, 0666, dev);
+
+ lps25h_dbg("Registered with %d\n", ret);
+
+ if (ret < 0)
+ {
+ kmm_free(dev);
+ lps25h_dbg("Error occurred during the driver registering\n");
+ return ERROR;
+ }
+
+ dev->config->irq_attach(config, lps25h_int_handler, dev);
+ dev->config->irq_enable(config, false);
+ dev->irqenabled = false;
+ return OK;
+}
diff --git a/drivers/usbmisc/Kconfig b/drivers/usbmisc/Kconfig
new file mode 100644
index 00000000000..68bd619ee3a
--- /dev/null
+++ b/drivers/usbmisc/Kconfig
@@ -0,0 +1,29 @@
+#
+# For a description of the syntax of this configuration file,
+# see misc/tools/kconfig-language.txt.
+#
+
+comment "USB Miscellaneous drivers"
+
+config FUSB301
+ bool "Fairchild FUSB301 USB type-C controller support"
+ default n
+ select I2C
+ ---help---
+ Enable device driver for Fairchild USB type-C controller
+
+if FUSB301
+
+config DEBUG_FUSB301
+ bool "Enable debug support for the FUSB301"
+ default n
+ ---help---
+ Enables debug support for the FUSB301
+
+config FUSB301_NPOLLWAITERS
+ int "Number of waiters to poll"
+ default 2
+ ---help---
+ Maximum number of threads that can be waiting on poll()
+
+endif
diff --git a/drivers/usbmisc/Make.defs b/drivers/usbmisc/Make.defs
new file mode 100644
index 00000000000..fd9dd6af37e
--- /dev/null
+++ b/drivers/usbmisc/Make.defs
@@ -0,0 +1,49 @@
+############################################################################
+# drivers/usbmisc/Make.defs
+#
+# Copyright (C) 2017 Gregory Nutt. All rights reserved.
+# Author: Gregory Nutt
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in
+# the documentation and/or other materials provided with the
+# distribution.
+# 3. Neither the name NuttX nor the names of its contributors may be
+# used to endorse or promote products derived from this software
+# without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+# OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+# POSSIBILITY OF SUCH DAMAGE.
+#
+############################################################################
+
+ifeq ($(CONFIG_USBMISC),y)
+
+# Include USB miscellaneous drivers
+
+ifeq ($(CONFIG_FUSB301),y)
+ CSRCS += fusb301.c
+endif
+
+# Include USB miscellaneous build support
+
+DEPPATH += --dep-path usbmisc
+VPATH += :usbmisc
+CFLAGS += ${shell $(INCDIR) $(INCDIROPT) "$(CC)" $(TOPDIR)$(DELIM)drivers$(DELIM)usbmisc}
+endif
diff --git a/drivers/usbmisc/fusb301.c b/drivers/usbmisc/fusb301.c
new file mode 100644
index 00000000000..c3627fd909d
--- /dev/null
+++ b/drivers/usbmisc/fusb301.c
@@ -0,0 +1,855 @@
+/****************************************************************************
+ * drivers/usbmisc/fusb301.c
+ *
+ * FUSB301 USB-C controller driver
+ *
+ * Copyright (C) 2016-2017 Haltian Ltd. All rights reserved.
+ * Authors: Harri Luhtala
+ *
+ * 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
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+#ifdef CONFIG_DEBUG_FUSB301
+# define fusb301_err(x, ...) _err(x, ##__VA_ARGS__)
+# define fusb301_info(x, ...) _info(x, ##__VA_ARGS__)
+#else
+# define fusb301_err(x, ...) uerr(x, ##__VA_ARGS__)
+# define fusb301_info(x, ...) uinfo(x, ##__VA_ARGS__)
+#endif
+
+/* Other macros */
+
+#define FUSB301_I2C_RETRIES 10
+
+/****************************************************************************
+ * Private Data Types
+ ****************************************************************************/
+
+struct fusb301_dev_s
+{
+ FAR struct i2c_master_s *i2c; /* I2C interface */
+ uint8_t addr; /* I2C address */
+ volatile bool int_pending; /* Interrupt received but handled */
+ sem_t devsem; /* Manages exclusive access */
+ FAR struct fusb301_config_s *config; /* Platform specific configuration */
+#ifndef CONFIG_DISABLE_POLL
+ FAR struct pollfd *fds[CONFIG_FUSB301_NPOLLWAITERS];
+#endif
+};
+
+/****************************************************************************
+ * Private Function prototypes
+ ****************************************************************************/
+
+static int fusb301_open(FAR struct file *filep);
+static int fusb301_close(FAR struct file *filep);
+static ssize_t fusb301_read(FAR struct file *, FAR char *, size_t);
+static ssize_t fusb301_write(FAR struct file *filep, FAR const char *buffer,
+ size_t buflen);
+static int fusb301_ioctl(FAR struct file *filep, int cmd, unsigned long arg);
+#ifndef CONFIG_DISABLE_POLL
+static int fusb301_poll(FAR struct file *filep, FAR struct pollfd *fds,
+ bool setup);
+static void fusb301_notify(FAR struct fusb301_dev_s *priv);
+#endif
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+static const struct file_operations g_fusb301ops =
+{
+ fusb301_open, /* open */
+ fusb301_close, /* close */
+ fusb301_read, /* read */
+ fusb301_write, /* write */
+ NULL, /* seek */
+ fusb301_ioctl /* ioctl */
+#ifndef CONFIG_DISABLE_POLL
+ , fusb301_poll /* poll */
+#endif
+#ifndef CONFIG_DISABLE_PSEUDOFS_OPERATIONS
+ , NULL /* unlink */
+ #endif
+};
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: fusb301_getreg
+ *
+ * Description:
+ * Read from an 8-bit FUSB301 register
+ *
+ * Input Parameters:
+ * priv - pointer to FUSB301 Private Structure
+ * reg - register to read
+ *
+ * Returned Value:
+ * Returns positive register value in case of success, otherwise ERROR
+ ****************************************************************************/
+
+static int fusb301_getreg(FAR struct fusb301_dev_s *priv, uint8_t reg)
+{
+ int ret = -EIO;
+ int retries;
+ uint8_t regval;
+ struct i2c_msg_s msg[2];
+
+ DEBUGASSERT(priv);
+
+ msg[0].addr = priv->addr;
+ msg[0].flags = 0;
+ msg[0].buffer = ®
+ msg[0].length = 1;
+
+ msg[1].addr = priv->addr;
+ msg[1].flags = I2C_M_READ;
+ msg[1].buffer = ®val;
+ msg[1].length = 1;
+
+ /* Perform the transfer */
+
+ for (retries = 0; retries < FUSB301_I2C_RETRIES; retries++)
+ {
+ ret = I2C_TRANSFER(priv->i2c, msg, 2);
+ if (ret == OK)
+ {
+ fusb301_info("reg:%02X, value:%02X\n", reg, regval);
+ return regval;
+ }
+ else
+ {
+ /* Some error. Try to reset I2C bus and keep trying. */
+
+#ifdef CONFIG_I2C_RESET
+ if (retries == FUSB301_I2C_RETRIES - 1)
+ {
+ break;
+ }
+
+ ret = up_i2creset(priv->i2c);
+ if (ret < 0)
+ {
+ fusb301_err("ERROR: up_i2creset failed: %d\n", ret);
+ return ret;
+ }
+#endif
+ }
+ }
+
+ fusb301_info("reg:%02X, error:%d\n", reg, ret);
+ return ret;
+}
+
+/****************************************************************************
+ * Name: fusb301_putreg
+ *
+ * Description:
+ * Write a value to an 8-bit FUSB301 register
+ *
+ * Input Parameters:
+ * priv - pointer to FUSB301 Private Structure
+ * regaddr - register to read
+ * regval - value to be written
+ *
+ * Returned Value:
+ * None
+ ****************************************************************************/
+
+static int fusb301_putreg(FAR struct fusb301_dev_s *priv, uint8_t regaddr,
+ uint8_t regval)
+{
+ int ret = -EIO;
+ int retries;
+ struct i2c_msg_s msg;
+ uint8_t txbuffer[2];
+
+ /* Setup to the data to be transferred (register address and data). */
+
+ txbuffer[0] = regaddr;
+ txbuffer[1] = regval;
+
+ /* Setup 8-bit FUSB301 address write message */
+
+ msg.addr = priv->addr;
+ msg.flags = 0;
+ msg.buffer = txbuffer;
+ msg.length = 2;
+
+ /* Perform the transfer */
+
+ for (retries = 0; retries < FUSB301_I2C_RETRIES; retries++)
+ {
+ ret = I2C_TRANSFER(priv->i2c, &msg, 1);
+ if (ret == OK)
+ {
+ fusb301_info("reg:%02X, value:%02X\n", regaddr, regval);
+
+ return OK;
+ }
+ else
+ {
+ /* Some error. Try to reset I2C bus and keep trying. */
+
+#ifdef CONFIG_I2C_RESET
+ if (retries == FUSB301_I2C_RETRIES - 1)
+ {
+ break;
+ }
+
+ ret = up_i2creset(priv->i2c);
+ if (ret < 0)
+ {
+ fusb301_err("ERROR: up_i2creset failed: %d\n", ret);
+ return ret;
+ }
+#endif
+ }
+ }
+
+ fusb301_err("ERROR: failed reg:%02X, value:%02X, error:%d\n",
+ regaddr, regval, ret);
+ return ret;
+}
+
+/****************************************************************************
+ * Name: fusb301_read_device_id
+ *
+ * Description:
+ * Read device version and revision IDs
+ *
+ ****************************************************************************/
+
+static int fusb301_read_device_id(FAR struct fusb301_dev_s * priv,
+ FAR uint8_t * arg)
+{
+ int ret;
+
+ ret = fusb301_getreg(priv, FUSB301_DEV_ID_REG);
+ if (ret < 0)
+ {
+ fusb301_err("ERROR: Failed to read device ID\n");
+ return -EIO;
+ }
+
+ *arg = ret;
+ return OK;
+}
+
+/****************************************************************************
+ * Name: fusb301_clear_interrupts
+ *
+ * Description:
+ * Clear interrupts from FUSB301 chip
+ *
+ ****************************************************************************/
+
+static int fusb301_clear_interrupts(FAR struct fusb301_dev_s *priv)
+{
+ int ret = OK;
+
+ ret = fusb301_getreg(priv, FUSB301_INTERRUPT_REG);
+ if (ret < 0)
+ {
+ fusb301_err("ERROR: Failed to clear interrupts\n");
+ return -EIO;
+ }
+
+ return ret;
+}
+
+/****************************************************************************
+ * Name: fusb301_setup
+ *
+ * Description:
+ * Setup FUSB301 chip
+ *
+ ****************************************************************************/
+
+static int fusb301_setup(FAR struct fusb301_dev_s *priv,
+ struct fusb301_setup_s *setup)
+{
+ int ret = OK;
+
+ fusb301_info("drp_tgl:%02X, host_curr:%02X, global_int:%X, mask:%02X\n",
+ setup->drp_toggle_timing, setup->host_current, setup->global_int_mask,
+ setup->int_mask);
+
+ ret = fusb301_putreg(priv, FUSB301_CONTROL_REG, setup->drp_toggle_timing |
+ setup->host_current | setup->global_int_mask);
+
+ if (ret < 0)
+ {
+ fusb301_err("ERROR: Failed to write control register\n");
+ goto err_out;
+ }
+
+ ret = fusb301_putreg(priv, FUSB301_MASK_REG, setup->int_mask);
+ if (ret < 0)
+ {
+ fusb301_err("ERROR: Failed to write mask register\n");
+ }
+
+err_out:
+ return ret;
+}
+
+/****************************************************************************
+ * Name: fusb301_set_mode
+ *
+ * Description:
+ * Configure supported device modes (sink, source, DRP, accessory)
+ *
+ ****************************************************************************/
+
+static int fusb301_set_mode(FAR struct fusb301_dev_s *priv,
+ enum fusb301_mode_e mode)
+{
+ int ret = OK;
+
+ if (mode > MODE_DRP_ACC)
+ {
+ return -EINVAL;
+ }
+
+ ret = fusb301_putreg(priv, FUSB301_MODE_REG, mode);
+ if (ret < 0)
+ {
+ fusb301_err("ERROR: Failed to write mode register\n");
+ ret = -EIO;
+ }
+
+ return ret;
+}
+
+/****************************************************************************
+ * Name: fusb301_set_state
+ *
+ * Description:
+ * Force device in specified state
+ *
+ ****************************************************************************/
+
+static int fusb301_set_state(FAR struct fusb301_dev_s *priv,
+ enum fusb301_manual_e state)
+{
+ int ret = OK;
+
+ if (state > MANUAL_UNATT_SNK)
+ {
+ return -EINVAL;
+ }
+
+ ret = fusb301_putreg(priv, FUSB301_MANUAL_REG, state);
+ if (ret < 0)
+ {
+ fusb301_err("ERROR: Failed to write manual register\n");
+ ret = -EIO;
+ }
+
+ return ret;
+}
+
+/****************************************************************************
+ * Name: fusb301_read_status
+ *
+ * Description:
+ * Clear read status register
+ *
+ ****************************************************************************/
+
+static int fusb301_read_status(FAR struct fusb301_dev_s *priv,
+ FAR uint8_t *arg)
+{
+ int ret;
+
+ ret = fusb301_getreg(priv, FUSB301_STATUS_REG);
+ if (ret < 0)
+ {
+ fusb301_err("ERROR: Failed to read status\n");
+ return -EIO;
+ }
+
+ *arg = ret;
+ return OK;
+}
+
+/****************************************************************************
+ * Name: fusb301_read_devtype
+ *
+ * Description:
+ * Read type of attached device
+ *
+ ****************************************************************************/
+
+static int fusb301_read_devtype(FAR struct fusb301_dev_s *priv,
+ FAR uint8_t *arg)
+{
+ int ret;
+
+ ret = fusb301_getreg(priv, FUSB301_TYPE_REG);
+ if (ret < 0)
+ {
+ fusb301_err("ERROR: Failed to read type\n");
+ return -EIO;
+ }
+
+ *arg = ret;
+ return OK;
+}
+
+/****************************************************************************
+ * Name: fusb301_reset
+ *
+ * Description:
+ * Reset FUSB301 HW and clear I2C registers
+ *
+ ****************************************************************************/
+
+static int fusb301_reset(FAR struct fusb301_dev_s *priv)
+{
+ int ret = OK;
+
+ ret = fusb301_putreg(priv, FUSB301_RESET_REG, RESET_SW_RES);
+ if (ret < 0)
+ {
+ fusb301_err("ERROR: Failed to write reset register\n");
+ ret = -EIO;
+ }
+
+ return ret;
+}
+
+/****************************************************************************
+ * Name: fusb301_open
+ *
+ * Description:
+ * This function is called whenever the FUSB301 device is opened.
+ *
+ ****************************************************************************/
+
+static int fusb301_open(FAR struct file *filep)
+{
+ FAR struct inode *inode = filep->f_inode;
+ FAR struct fusb301_dev_s *priv = inode->i_private;
+ int ret = OK;
+
+ /* Probe device */
+
+ ret = fusb301_getreg(priv, FUSB301_DEV_ID_REG);
+ if (ret < 0)
+ {
+ fusb301_err("ERROR: No response at given address 0x%02X\n", priv->addr);
+ ret = -EFAULT;
+ }
+ else
+ {
+ fusb301_info("device id: 0x%02X\n", ret);
+
+ (void)fusb301_clear_interrupts(priv);
+ priv->config->irq_enable(priv->config, true);
+ }
+
+ /* Error exit */
+
+ return ret;
+}
+
+/****************************************************************************
+ * Name: fusb301_close
+ *
+ * Description:
+ * This routine is called when the FUSB301 device is closed.
+ *
+ ****************************************************************************/
+
+static int fusb301_close(FAR struct file *filep)
+{
+ FAR struct inode *inode = filep->f_inode;
+ FAR struct fusb301_dev_s *priv = inode->i_private;
+
+ priv->config->irq_enable(priv->config, false);
+
+ return OK;
+}
+
+/****************************************************************************
+ * Name: fusb301_read
+ * Description:
+ * This routine is called when the FUSB301 device is read.
+ ****************************************************************************/
+
+static ssize_t fusb301_read(FAR struct file *filep, FAR char *buffer, size_t buflen)
+{
+ FAR struct inode *inode = filep->f_inode;
+ FAR struct fusb301_dev_s *priv = inode->i_private;
+ FAR struct fusb301_result_s *ptr;
+ irqstate_t flags;
+ int ret;
+
+ if (buflen < sizeof(struct fusb301_result_s))
+ {
+ return 0;
+ }
+
+ ptr = (struct fusb301_result_s *)buffer;
+
+ ret = sem_wait(&priv->devsem);
+ if (ret < 0)
+ {
+ return -EINTR;
+ }
+
+ flags = enter_critical_section();
+ priv->int_pending = false;
+ leave_critical_section(flags);
+
+ (void)fusb301_clear_interrupts(priv);
+
+ ptr->status = fusb301_getreg(priv, FUSB301_STATUS_REG);
+ ptr->dev_type = fusb301_getreg(priv, FUSB301_TYPE_REG);
+
+ sem_post(&priv->devsem);
+ return sizeof(struct fusb301_result_s);
+}
+
+/****************************************************************************
+ * Name: fusb301_write
+ * Description:
+ * This routine is called when the FUSB301 device is written to.
+ ****************************************************************************/
+
+static ssize_t fusb301_write(FAR struct file *filep, FAR const char *buffer,
+ size_t buflen)
+{
+ ssize_t length = 0;
+
+ return length;
+}
+
+/****************************************************************************
+ * Name: fusb301_ioctl
+ * Description:
+ * This routine is called when ioctl function call is performed for
+ * the FUSB301 device.
+ ****************************************************************************/
+
+static int fusb301_ioctl(FAR struct file *filep, int cmd, unsigned long arg)
+{
+ FAR struct inode *inode = filep->f_inode;
+ FAR struct fusb301_dev_s *priv = inode->i_private;
+ int ret;
+
+ ret = sem_wait(&priv->devsem);
+ if (ret < 0)
+ {
+ return -EINTR;
+ }
+
+ fusb301_info("cmd: 0x%02X, arg:%lu\n", cmd, arg);
+
+ switch (cmd)
+ {
+ case USBCIOC_READ_DEVID:
+ {
+ ret = fusb301_read_device_id(priv, (uint8_t *)arg);
+ }
+ break;
+
+ case USBCIOC_SETUP:
+ {
+ ret = fusb301_setup(priv, (struct fusb301_setup_s *)arg);
+ }
+ break;
+
+ case USBCIOC_SET_MODE:
+ {
+ ret = fusb301_set_mode(priv, (uint8_t)arg);
+ }
+ break;
+
+ case USBCIOC_SET_STATE:
+ {
+ ret = fusb301_set_state(priv, (uint8_t)arg);
+ }
+ break;
+
+ case USBCIOC_READ_STATUS:
+ {
+ ret = fusb301_read_status(priv, (uint8_t *)arg);
+ }
+ break;
+
+ case USBCIOC_READ_DEVTYPE:
+ {
+ ret = fusb301_read_devtype(priv, (uint8_t *)arg);
+ }
+ break;
+
+ case USBCIOC_RESET:
+ {
+ ret = fusb301_reset(priv);
+ }
+ break;
+
+ default:
+ {
+ fusb301_err("ERROR: Unrecognized cmd: %d\n", cmd);
+ ret = -ENOTTY;
+ }
+ break;
+ }
+
+ sem_post(&priv->devsem);
+ return ret;
+}
+
+/****************************************************************************
+ * Name: fusb301_poll
+ * Description:
+ * This routine is called during FUSB301 device poll
+ ****************************************************************************/
+
+#ifndef CONFIG_DISABLE_POLL
+static int fusb301_poll(FAR struct file *filep, FAR struct pollfd *fds, bool setup)
+{
+ FAR struct inode *inode;
+ FAR struct fusb301_dev_s *priv;
+ irqstate_t flags;
+ int ret = OK;
+ int i;
+
+ DEBUGASSERT(filep && fds);
+ inode = filep->f_inode;
+
+ DEBUGASSERT(inode && inode->i_private);
+ priv = (FAR struct fusb301_dev_s *)inode->i_private;
+
+ ret = sem_wait(&priv->devsem);
+ if (ret < 0)
+ {
+ return -EINTR;
+ }
+
+ if (setup)
+ {
+ /* Ignore waits that do not include POLLIN */
+
+ if ((fds->events & POLLIN) == 0)
+ {
+ ret = -EDEADLK;
+ goto out;
+ }
+
+ /* This is a request to set up the poll. Find an available
+ * slot for the poll structure reference.
+ */
+
+ for (i = 0; i < CONFIG_FUSB301_NPOLLWAITERS; i++)
+ {
+ /* Find an available slot */
+
+ if (!priv->fds[i])
+ {
+ /* Bind the poll structure and this slot */
+
+ priv->fds[i] = fds;
+ fds->priv = &priv->fds[i];
+ break;
+ }
+ }
+
+ if (i >= CONFIG_FUSB301_NPOLLWAITERS)
+ {
+ fds->priv = NULL;
+ ret = -EBUSY;
+ goto out;
+ }
+
+ flags = enter_critical_section();
+ if (priv->int_pending)
+ {
+ fusb301_notify(priv);
+ }
+
+ leave_critical_section(flags);
+ }
+ else if (fds->priv)
+ {
+ /* This is a request to tear down the poll. */
+
+ struct pollfd **slot = (struct pollfd **)fds->priv;
+ DEBUGASSERT(slot != NULL);
+
+ /* Remove all memory of the poll setup */
+
+ *slot = NULL;
+ fds->priv = NULL;
+ }
+
+out:
+ sem_post(&priv->devsem);
+ return ret;
+}
+
+/****************************************************************************
+ * Name: fusb301_notify
+ *
+ * Description:
+ * Notify thread about data to be available
+ *
+ ****************************************************************************/
+
+static void fusb301_notify(FAR struct fusb301_dev_s *priv)
+{
+ DEBUGASSERT(priv != NULL);
+
+ int i;
+
+ /* If there are threads waiting on poll() for FUSB301 data to become available,
+ * then wake them up now. NOTE: we wake up all waiting threads because we
+ * do not know that they are going to do. If they all try to read the data,
+ * then some make end up blocking after all.
+ */
+
+ for (i = 0; i < CONFIG_FUSB301_NPOLLWAITERS; i++)
+ {
+ struct pollfd *fds = priv->fds[i];
+ if (fds)
+ {
+ fds->revents |= POLLIN;
+ fusb301_info("Report events: %02x\n", fds->revents);
+ sem_post(fds->sem);
+ }
+ }
+}
+#endif /* !CONFIG_DISABLE_POLL */
+
+/****************************************************************************
+ * Name: fusb301_callback
+ *
+ * Description:
+ * FUSB301 interrupt handler
+ *
+ ****************************************************************************/
+
+static int fusb301_int_handler(int irq, FAR void *context, FAR void *arg)
+{
+ FAR struct fusb301_dev_s *priv = (FAR struct fusb301_dev_s *)arg;
+ irqstate_t flags;
+
+ DEBUGASSERT(priv != NULL);
+
+ flags = enter_critical_section();
+ priv->int_pending = true;
+
+#ifndef CONFIG_DISABLE_POLL
+ fusb301_notify(priv);
+#endif
+ leave_critical_section(flags);
+
+ return OK;
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+int fusb301_register(FAR const char *devpath, FAR struct i2c_master_s *i2c,
+ uint8_t addr, FAR struct fusb301_config_s *config)
+{
+ FAR struct fusb301_dev_s *priv;
+ int ret;
+
+ DEBUGASSERT(devpath != NULL && i2c != NULL && config != NULL);
+
+ /* Initialize the FUSB301 device structure */
+
+ priv = (FAR struct fusb301_dev_s *)kmm_zalloc(sizeof(struct fusb301_dev_s));
+ if (!priv)
+ {
+ fusb301_err("ERROR: Failed to allocate instance\n");
+ return -ENOMEM;
+ }
+
+ /* Initialize device structure semaphore */
+
+ sem_init(&priv->devsem, 0, 1);
+
+ priv->int_pending = false;
+ priv->i2c = i2c;
+ priv->addr = addr;
+ priv->config = config;
+
+ /* Register the character driver */
+
+ ret = register_driver(devpath, &g_fusb301ops, 0666, priv);
+ if (ret < 0)
+ {
+ fusb301_err("ERROR: Failed to register driver: %d\n", ret);
+ goto errout_with_priv;
+ }
+
+ /* Prepare interrupt line and handler. */
+
+ priv->config->irq_clear(config);
+ priv->config->irq_attach(config, fusb301_int_handler, priv);
+ priv->config->irq_enable(config, false);
+
+ return OK;
+
+errout_with_priv:
+ sem_destroy(&priv->devsem);
+ kmm_free(priv);
+
+ return ret;
+}
diff --git a/include/nuttx/fs/ioctl.h b/include/nuttx/fs/ioctl.h
index 5582ccd0fee..86aaefae180 100644
--- a/include/nuttx/fs/ioctl.h
+++ b/include/nuttx/fs/ioctl.h
@@ -86,6 +86,7 @@
#define _SPIBASE (0x2100) /* SPI driver commands */
#define _GPIOBASE (0x2200) /* GPIO driver commands */
#define _CLIOCBASE (0x2300) /* Contactless modules ioctl commands */
+#define _USBCBASE (0x2400) /* USB-C controller ioctl commands */
/* boardctl() commands share the same number space */
@@ -371,19 +372,19 @@
#define _LOOPIOCVALID(c) (_IOC_TYPE(c)==_LOOPBASE)
#define _LOOPIOC(nr) _IOC(_LOOPBASE,nr)
-/* Modem driver ioctl definitions ********************************************/
+/* Modem driver ioctl definitions *******************************************/
/* see nuttx/include/modem/ioctl.h */
#define _MODEMIOCVALID(c) (_IOC_TYPE(c)==_MODEMBASE)
#define _MODEMIOC(nr) _IOC(_MODEMBASE,nr)
-/* I2C driver ioctl definitions **********************************************/
+/* I2C driver ioctl definitions *********************************************/
/* see nuttx/include/i2c/i2c_master.h */
#define _I2CIOCVALID(c) (_IOC_TYPE(c)==_I2CBASE)
#define _I2CIOC(nr) _IOC(_I2CBASE,nr)
-/* SPI driver ioctl definitions **********************************************/
+/* SPI driver ioctl definitions *********************************************/
/* see nuttx/include/spi/spi_transfer.h */
#define _SPIIOCVALID(c) (_IOC_TYPE(c)==_SPIBASE)
@@ -395,12 +396,18 @@
#define _GPIOCVALID(c) (_IOC_TYPE(c)==_GPIOBASE)
#define _GPIOC(nr) _IOC(_GPIOBASE,nr)
-/* Contactless driver ioctl definitions ****************************************/
+/* Contactless driver ioctl definitions *************************************/
/* (see nuttx/include/contactless/ioctl.h */
#define _CLIOCVALID(c) (_IOC_TYPE(c)==_CLIOCBASE)
#define _CLIOC(nr) _IOC(_CLIOCBASE,nr)
+/* USB-C controller driver ioctl definitions ********************************/
+/* (see nuttx/include/usb/xxx.h */
+
+#define _USBCIOCVALID(c) (_IOC_TYPE(c)==_USBCBASE)
+#define _USBCIOC(nr) _IOC(_USBCBASE,nr)
+
/* boardctl() command definitions *******************************************/
#define _BOARDIOCVALID(c) (_IOC_TYPE(c)==_BOARDBASE)
diff --git a/include/nuttx/net/ip.h b/include/nuttx/net/ip.h
index 6a07edd585b..84df3520740 100644
--- a/include/nuttx/net/ip.h
+++ b/include/nuttx/net/ip.h
@@ -483,7 +483,7 @@ EXTERN const net_ipv6addr_t g_ipv6_llnetmask; /* Netmask for local link addres
#endif
/****************************************************************************
- * Function: net_ipv4addr_maskcmp and net_ipv6addr_maskcmp
+ * Name: net_ipv4addr_maskcmp and net_ipv6addr_maskcmp
*
* Description:
* Compare two IP addresses under a netmask. The mask is used to mask
@@ -527,7 +527,86 @@ bool net_ipv6addr_maskcmp(const net_ipv6addr_t addr1,
#endif
/****************************************************************************
- * Function: net_ipaddr_mask
+ * Name: net_ipv6addr_prefixcmp
+ *
+ * Description:
+ * Compare two IPv6 address prefixes.
+ *
+ ****************************************************************************/
+
+#define net_ipv6addr_prefixcmp(addr1, addr2, length) \
+ (memcmp(addr1, addr2, length >> 3) == 0)
+
+/****************************************************************************
+ * Name: net_is_addr_loopback
+ *
+ * Description:
+ * Is Ithe Pv6 address a the loopback address?
+ *
+ ****************************************************************************/
+
+#define net_is_addr_loopback(a) \
+ ((a)[0] == 0 && (a)[1] == 0 && (a)[2] == 0 && (a)[3] == 0 && \
+ (a)[4] == 0 && (a)[5] == 0 && (a)[6] == 0 && (a)[7] == HTONS(0x0001))
+
+/****************************************************************************
+ * Name: net_is_addr_unspecified
+ *
+ * Description:
+ * Is Ithe Pv6 address the unspecified address?
+ *
+ ****************************************************************************/
+
+#define net_is_addr_unspecified(a) \
+ ((a)[0] == 0 && (a)[1] == 0 && (a)[2] == 0 && (a)[3] == 0 && \
+ (a)[4] == 0 && (a)[5] == 0 && (a)[6] == 0 && (a)[7] == 0)
+
+/****************************************************************************
+ * Name: net_is_addr_mcast
+ *
+ * Description:
+ * s address a multicast address? see RFC 3513.
+ *
+ ****************************************************************************/
+
+#define net_is_addr_mcast(a) (((a)[0] & HTONS(0xff00)) == HTONS(0xff00))
+
+/****************************************************************************
+ * Name: net_is_addr_linklocal_allnodes_mcast
+ *
+ * Description:
+ * Is IPv6 address a the link local all-nodes multicast address?
+ *
+ ****************************************************************************/
+
+#define net_is_addr_linklocal_allnodes_mcast(a) \
+ ((a)[0] == HTONS(0xff02) && (a)[1] == 0 && (a)[2] == 0 && (a)[3] == 0 && \
+ (a)[4] == 0 && (a)[5] == 0 && (a)[6] == 0 && (a)[7] == HTONS(0x0001))
+
+/****************************************************************************
+ * Name: net_is_addr_linklocal_allrouters_mcast
+ *
+ * Description:
+ * Is IPv6 address a the link local all-routers multicast address?
+ *
+ ****************************************************************************/
+
+#define net_is_addr_linklocal_allrouters_mcast(a) \
+ ((a)[0] == HTONS(0xff02) && (a)[1] == 0 && (a)[2] == 0 && (a)[3] == 0 && \
+ (a)[4] == 0 && (a)[5] == 0 && (a)[6] == 0 && (a)[7] == HTOS(0x0002))
+
+/****************************************************************************
+ * Name: net_is_addr_linklocal
+ *
+ * Description:
+ * Checks whether the address a is link local.
+ *
+ ****************************************************************************/
+
+#define net_is_addr_linklocal(a) ((a)[0] == HTONS(0xfe80))
+
+/****************************************************************************
+ * Name: net_ipaddr_mask
*
* Description:
* Mask out the network part of an IP address, given the address and
diff --git a/include/nuttx/net/net.h b/include/nuttx/net/net.h
index 337e0a63665..d99c2f584a6 100644
--- a/include/nuttx/net/net.h
+++ b/include/nuttx/net/net.h
@@ -79,7 +79,7 @@ enum net_lltype_e
NET_LL_SLIP, /* Serial Line Internet Protocol (SLIP) */
NET_LL_TUN, /* TUN Virtual Network Device */
NET_LL_IEEE80211, /* IEEE 802.11 */
- NET_LL_IEEE805154 /* IEEE 802.15.4 MAC */
+ NET_LL_IEEE802154 /* IEEE 802.15.4 MAC */
};
/* This defines a bitmap big enough for one bit for each socket option */
diff --git a/include/nuttx/net/netconfig.h b/include/nuttx/net/netconfig.h
index 34561329013..9bbd0e9929c 100644
--- a/include/nuttx/net/netconfig.h
+++ b/include/nuttx/net/netconfig.h
@@ -97,7 +97,7 @@
*
* - Maximum Transfer Unit (MTU)
* - TCP Receive Window size (See TCP configuration options below)
- *
+ *
* A better solution would be to support device-by-device MTU and receive
* window sizes. This minimum support is require to support the optimal
* SLIP MTU of 296 bytes and the standard Ethernet MTU of 1500
@@ -158,19 +158,19 @@
# endif
# ifdef CONFIG_NET_SLIP
-# define _MIN_SLIP_MTU MIN(_MIN_LO_MTU,CONFIG_NET_6LOWPAN_MTU)
-# define _MAX_SLIP_MTU MAX(_MAX_LO_MTU,CONFIG_NET_6LOWPAN_MTU)
+# define _MIN_SLIP_MTU MIN(_MIN_LO_MTU,CONFIG_NET_SLIP_MTU)
+# define _MAX_SLIP_MTU MAX(_MAX_LO_MTU,CONFIG_NET_SLIP_MTU)
# else
# define _MIN_SLIP_MTU _MIN_LO_MTU
# define _MAX_SLIP_MTU _MAX_LO_MTU
# endif
# ifdef CONFIG_NET_6LOWPAN
-# define _MIN_6LOWPAN_MTU MIN(_MIN_LO_MTU,CONFIG_NET_SLIP_MTU)
-# define _MAX_6LOWPAN_MTU MAX(_MAX_LO_MTU,CONFIG_NET_SLIP_MTU)
+# define _MIN_6LOWPAN_MTU MIN(_MIN_SLIP_MTU,CONFIG_NET_6LOWPAN_MTU)
+# define _MAX_6LOWPAN_MTU MAX(_MAX_SLIP_MTU,CONFIG_NET_6LOWPAN_MTU)
# else
-# define _MIN_6LOWPAN_MTU _MIN_LO_MTU
-# define _MAX_6LOWPAN_MTU _MAX_LO_MTU
+# define _MIN_6LOWPAN_MTU _MIN_SLIP_MTU
+# define _MAX_6LOWPAN_MTU _MAX_SLIP_MTU
# endif
# define MIN_NET_DEV_MTU _MIN_6LOWPAN_MTU
@@ -226,6 +226,12 @@
# define MIN_NET_DEV_MTU CONFIG_NET_6LOWPAN_MTU
# define MAX_NET_DEV_MTU CONFIG_NET_6LOWPAN_MTU
+/* For the IEEE802.15.4 MAC device, we will use the packet MTU
+ * (which is probably much larger than the IEEE802.15.4 fram size)
+ */
+
+# define NET_LO_MTU MAX_NET_DEV_MTU
+
#else
/* Perhaps only Unix domain sockets or the loopback device */
@@ -289,47 +295,97 @@
#endif
/* The UDP maximum packet size. This is should not be to set to more
- * than NET_DEV_MTU(d) - NET_LL_HDRLEN(dev) - IPv4UDP_HDRLEN.
+ * than NET_DEV_MTU(d) - NET_LL_HDRLEN(dev) - IPv*_HDRLEN.
+ *
+ * REVISIT: It is unclear to me if the UDP_HDRLEN should subtracted
+ * or not.
*/
-#define UDP_MSS(d,h) (NET_DEV_MTU(d) - NET_LL_HDRLEN(d) - (h))
-
-/* If Ethernet is supported, then it will have the smaller MSS */
-
-#if defined(CONFIG_NET_SLIP)
-# define SLIP_UDP_MSS(h) (CONFIG_NET_SLIP_MTU - (h))
-# define __MIN_UDP_MSS(h) SLIP_UDP_MSS(h)
-#elif defined(CONFIG_NET_LOOPBACK)
-# define LO_UDP_MSS(h) (NET_LO_MTU - (h))
-# define __MIN_UDP_MSS(h) LO_UDP_MSS(h)
-#endif
+#define UDP_MSS(d,h) (NET_DEV_MTU(d) - NET_LL_HDRLEN(d) (h))
#ifdef CONFIG_NET_ETHERNET
-# define ETH_UDP_MSS(h) (CONFIG_NET_ETH_MTU - ETH_HDRLEN - (h))
-# undef __MIN_UDP_MSS
-# define __MIN_UDP_MSS(h) ETH_UDP_MSS(h)
-# define __MAX_UDP_MSS(h) ETH_UDP_MSS(h)
+# define ETH_UDP_MSS(h) (CONFIG_NET_ETH_MTU - ETH_HDRLEN - (h))
+# ifndef CONFIG_NET_MULTILINK
+# define __MIN_UDP_MSS(h) ETH_UDP_MSS(h)
+# define __MAX_UDP_MSS(h) ETH_UDP_MSS(h)
+# endif
#endif
-/* If SLIP is supported, then it will have the larger MSS */
+#ifdef CONFIG_NET_6LOWPAN
+# define IEEE802154_UDP_MSS(h) (CONFIG_NET_6LOWPAN_MAXPAYLOAD - (h))
+# ifndef CONFIG_NET_MULTILINK
+# define __MIN_UDP_MSS(h) IEEE802154_UDP_MSS(h)
+# define __MAX_UDP_MSS(h) IEEE802154_UDP_MSS(h)
+# endif
+#endif
+
+#ifdef CONFIG_NET_LOOPBACK
+# define LO_UDP_MSS(h) (NET_LO_MTU - (h))
+# ifndef CONFIG_NET_MULTILINK
+# define __MIN_UDP_MSS(h) LO_UDP_MSS(h)
+# define __MAX_UDP_MSS(h) LO_UDP_MSS(h)
+# endif
+#endif
#ifdef CONFIG_NET_SLIP
-# undef __MAX_UDP_MSS
-# define __MAX_UDP_MSS(h) SLIP_UDP_MSS(h)
+# define SLIP_UDP_MSS(h) (CONFIG_NET_SLIP_MTU - (h))
+# ifndef CONFIG_NET_MULTILINK
+# define __MIN_UDP_MSS(h) SLIP_UDP_MSS(h)
+# define __MAX_UDP_MSS(h) SLIP_UDP_MSS(h)
+# endif
#endif
-/* If IPv4 is supported, it will have the larger MSS */
+#ifdef CONFIG_NET_MULTILINK
+# ifdef CONFIG_NET_ETHERNET
+# define __MIN_UDP_MSS(h) ETH_UDP_MSS(h)
+# define __MAX_UDP_MSS(h) ETH_UDP_MSS(h)
+# define __ETH_MIN_UDP_MSS(h) ETH_UDP_MSS(h)
+# define __ETH_MAX_UDP_MSS(h) ETH_UDP_MSS(h)
+# else
+# define __ETH_MIN_UDP_MSS(h) INT_MAX
+# define __ETH_MAX_UDP_MSS(h) 0
+# endif
-#ifdef CONFIG_NET_IPv6
-# define UDP_IPv6_MSS(d) UDP_MSS(d,IPv6_HDRLEN)
-# define ETH_IPv6_UDP_MSS ETH_UDP_MSS(IPv6_HDRLEN)
-# define SLIP_IPv6_UDP_MSS SLIP_UDP_MSS(IPv6_HDRLEN)
+# ifdef CONFIG_NET_6LOWPAN
+# undef __MIN_UDP_MSS
+# undef __MIN_UDP_MSS
+# define __MIN_UDP_MSS(h) MIN(IEEE802154_UDP_MSS(h),__ETH_MIN_UDP_MSS(h))
+# define __MAX_UDP_MSS(h) MAX(IEEE802154_UDP_MSS(h),__ETH_MAX_UDP_MSS(h))
+# define __6LOWPAN_MIN_UDP_MSS(h) MIN(IEEE802154_UDP_MSS(h),__ETH_MIN_UDP_MSS(h))
+# define __6LOWPAN_MAX_UDP_MSS(h) MAX(IEEE802154_UDP_MSS(h),__ETH_MAX_UDP_MSS(h))
+# else
+# define __6LOWPAN_MIN_UDP_MSS(h) __ETH_MIN_UDP_MSS(h)
+# define __6LOWPAN_MAX_UDP_MSS(h) __ETH_MAX_UDP_MSS(h)
+# endif
-# define MAX_IPv6_UDP_MSS __MAX_UDP_MSS(IPv6_HDRLEN)
-# define MAX_UDP_MSS __MAX_UDP_MSS(IPv6_HDRLEN)
+# ifdef CONFIG_NET_LOOPBACK
+# undef __MIN_UDP_MSS
+# undef __MIN_UDP_MSS
+# define __MIN_UDP_MSS(h) MIN(LO_UDP_MSS(h),__6LOWPAN_MIN_UDP_MSS(h))
+# define __MAX_UDP_MSS(h) MAX(LO_UDP_MSS(h),__6LOWPAN_MAX_UDP_MSS(h))
+# define __LOOP_MIN_UDP_MSS(h) MIN(LO_UDP_MSS(h),__6LOWPAN_MIN_UDP_MSS(h))
+# define __LOOP_MAX_UDP_MSS(h) MAX(LO_UDP_MSS(h),__6LOWPAN_MAX_UDP_MSS(h))
+# else
+# define __LOOP_MIN_UDP_MSS(h) __6LOWPAN_MIN_UDP_MSS(h)
+# define __LOOP_MAX_UDP_MSS(h) __6LOWPAN_MAX_UDP_MSS(h)
+# endif
+
+# ifdef CONFIG_NET_SLIP
+# undef __MIN_UDP_MSS
+# undef __MIN_UDP_MSS
+# define __MIN_UDP_MSS(h) MIN(SLIP_UDP_MSS(h),__LOOP_MIN_UDP_MSS(h))
+# define __MAX_UDP_MSS(h) MAX(SLIP_UDP_MSS(h),__LOOP_MAX_UDP_MSS(h))
+# define __SLIP_MIN_UDP_MSS(h) MIN(SLIP_UDP_MSS(h),__LOOP_MIN_UDP_MSS(h))
+# define __SLIP_MAX_UDP_MSS(h) MAX(SLIP_UDP_MSS(h),__LOOP_MAX_UDP_MSS(h))
+# else
+# define __SLIP_MIN_UDP_MSS(h) __LOOP_MIN_UDP_MSS(h)
+# define __SLIP_MAX_UDP_MSS(h) __LOOP_MAX_UDP_MSS(h)
+# endif
#endif
-#ifdef CONFIG_NET_IPv4
+/* NOTE: MSS calcuation excludes the UDP_HDRLEN. */
+
+ #ifdef CONFIG_NET_IPv4
# define UDP_IPv4_MSS(d) UDP_MSS(d,IPv4_HDRLEN)
# define ETH_IPv4_UDP_MSS ETH_UDP_MSS(IPv4_HDRLEN)
# define SLIP_IPv4_UDP_MSS SLIP_UDP_MSS(IPv4_HDRLEN)
@@ -416,36 +472,100 @@
* link layer protocols (CONFIG_NET_MULTILINK), each network device
* may support a different UDP MSS value. Here we arbitrarily select
* the minimum MSS for that case.
+ *
+ * REVISIT: It is unclear to me if the TCP_HDRLEN should subtracted
+ * or not.
*/
-#define TCP_MSS(d,h) (NET_DEV_MTU(d) - NET_LL_HDRLEN(d) - TCP_HDRLEN - (h))
-#define LO_TCP_MSS(h) (NET_LO_MTU - (h))
+#define TCP_MSS(d,h) (NET_DEV_MTU(d) - NET_LL_HDRLEN(d) - (h))
+#define LO_TCP_MSS(h) (NET_LO_MTU - (h))
-/* If Ethernet is supported, then it will have the smaller MSS */
-
-#if defined(CONFIG_NET_SLIP)
-# define SLIP_TCP_MSS(h) (CONFIG_NET_SLIP_MTU - (h))
-# define __MIN_TCP_MSS(h) SLIP_TCP_MSS(h)
-#elif defined(CONFIG_NET_LOOPBACK)
-# define LO_TCP_MSS(h) (NET_LO_MTU - (h))
-# define __MIN_TCP_MSS(h) LO_TCP_MSS(h)
-#endif
+/* Get the smallest and largest MSS */
#ifdef CONFIG_NET_ETHERNET
-# define ETH_TCP_MSS(h) (CONFIG_NET_ETH_MTU - ETH_HDRLEN - (h))
-# undef __MIN_TCP_MSS
-# define __MIN_TCP_MSS(h) ETH_TCP_MSS(h)
-# define __MAX_TCP_MSS(h) ETH_TCP_MSS(h)
+# define ETH_TCP_MSS(h) (CONFIG_NET_ETH_MTU - ETH_HDRLEN - (h))
+# ifndef CONFIG_NET_MULTILINK
+# define __MIN_TCP_MSS(h) ETH_TCP_MSS(h)
+# define __MAX_TCP_MSS(h) ETH_TCP_MSS(h)
+# endif
#endif
-/* If SLIP is supported, then it will have the larger MSS */
+#ifdef CONFIG_NET_6LOWPAN
+# define IEEE802154_TCP_MSS(h) CONFIG_NET_6LOWPAN_MAXPAYLOAD
+# ifndef CONFIG_NET_MULTILINK
+# define __MIN_TCP_MSS(h) IEEE802154_TCP_MSS(h)
+# define __MAX_TCP_MSS(h) IEEE802154_TCP_MSS(h)
+# endif
+#endif
+
+#ifdef CONFIG_NET_LOOPBACK
+# define LO_TCP_MSS(h) (NET_LO_MTU - (h))
+# ifndef CONFIG_NET_MULTILINK
+# define __MIN_TCP_MSS(h) LO_TCP_MSS(h)
+# define __MAX_TCP_MSS(h) LO_TCP_MSS(h)
+# endif
+#endif
#ifdef CONFIG_NET_SLIP
-# undef __MAX_TCP_MSS
-# define __MAX_TCP_MSS(h) SLIP_TCP_MSS(h)
+# define SLIP_TCP_MSS(h) (CONFIG_NET_SLIP_MTU - (h))
+# ifndef CONFIG_NET_MULTILINK
+# define __MIN_TCP_MSS(h) SLIP_TCP_MSS(h)
+# define __MAX_TCP_MSS(h) SLIP_TCP_MSS(h)
+# endif
#endif
-/* If IPv4 is support, it will have the larger MSS */
+#ifdef CONFIG_NET_MULTILINK
+
+# ifdef CONFIG_NET_ETHERNET
+# define __MIN_TCP_MSS(h) ETH_TCP_MSS(h)
+# define __MAX_TCP_MSS(h) ETH_TCP_MSS(h)
+# define __ETH_MIN_TCP_MSS(h) ETH_TCP_MSS(h)
+# define __ETH_MAX_TCP_MSS(h) ETH_TCP_MSS(h)
+# else
+# define __ETH_MIN_TCP_MSS(h) INT_MAX
+# define __ETH_MAX_TCP_MSS(h) 0
+# endif
+
+# ifdef CONFIG_NET_6LOWPAN
+# undef __MIN_TCP_MSS
+# undef __MAX_TCP_MSS
+# define __MIN_TCP_MSS(h) MIN(IEEE802154_TCP_MSS(h),__ETH_MIN_TCP_MSS(h))
+# define __MAX_TCP_MSS(h) MAX(IEEE802154_TCP_MSS(h),__ETH_MAX_TCP_MSS(h))
+# define __6LOWPAN_MIN_TCP_MSS(h) MIN(IEEE802154_TCP_MSS(h),__ETH_MIN_TCP_MSS(h))
+# define __6LOWPAN_MAX_TCP_MSS(h) MAX(IEEE802154_TCP_MSS(h),__ETH_MAX_TCP_MSS(h))
+# else
+# define __6LOWPAN_MIN_TCP_MSS(h) __ETH_MIN_TCP_MSS(h)
+# define __6LOWPAN_MAX_TCP_MSS(h) __ETH_MAX_TCP_MSS(h)
+# endif
+
+# ifdef CONFIG_NET_LOOPBACK
+# undef __MIN_TCP_MSS
+# undef __MAX_TCP_MSS
+# define __MIN_TCP_MSS(h) MIN(LO_TCP_MSS(h),__6LOWPAN_MIN_TCP_MSS(h))
+# define __MAX_TCP_MSS(h) MAX(LO_TCP_MSS(h),__6LOWPAN_MAX_TCP_MSS(h))
+# define __LOOP_MIN_TCP_MSS(h) MIN(LO_TCP_MSS(h),__6LOWPAN_MIN_TCP_MSS(h))
+# define __LOOP_MAX_TCP_MSS(h) MAX(LO_TCP_MSS(h),__6LOWPAN_MAX_TCP_MSS(h))
+# else
+# define __LOOP_MIN_TCP_MSS(h) _6LOWPAN_MIN_TCP_MSS(h)
+# define __LOOP_MAX_TCP_MSS(h) __6LOWPAN_MAX_TCP_MSS(h)
+# endif
+
+# ifdef CONFIG_NET_SLIP
+# undef __MIN_TCP_MSS
+# undef __MAX_TCP_MSS
+# define __MIN_TCP_MSS(h) MIN(SLIP_TCP_MSS(h),__LOOP_MIN_TCP_MSS(h))
+# define __MAX_TCP_MSS(h) MAX(SLIP_TCP_MSS(h),__LOOP_MAX_TCP_MSS(h))
+# define __SLIP_MIN_TCP_MSS(h) MIN(SLIP_TCP_MSS(h),__LOOP_MIN_TCP_MSS(h))
+# define __SLIP_MAX_TCP_MSS(h) MAX(SLIP_TCP_MSS(h),__LOOP_MAX_TCP_MSS(h))
+# else
+# define __SLIP_MIN_TCP_MSS(h) __LOOP_MIN_TCP_MSS(h)
+# define __SLIP_MAX_TCP_MSS(h) __LOOP_MAX_TCP_MSS(h)
+# endif
+#endif
+
+/* If IPv4 is supported, it will have the larger MSS.
+ * NOTE: MSS calcuation excludes the TCP_HDRLEN.
+ */
#ifdef CONFIG_NET_IPv6
# define TCP_IPv6_MSS(d) TCP_MSS(d,IPv6_HDRLEN)
@@ -547,6 +667,18 @@
# define CONFIG_NET_ARP_MAXAGE 120
#endif
+/* Usrsock configuration options */
+
+/* The maximum amount of concurrent usrsock connections, Default: 6 */
+
+#ifndef CONFIG_NET_USRSOCK_CONNS
+# ifdef CONFIG_NET_USRSOCK
+# define CONFIG_NET_USRSOCK_CONNS 6
+# else
+# define CONFIG_NET_USRSOCK_CONNS 0
+# endif
+#endif
+
/* General configuration options */
/* Delay after receive to catch a following packet. No delay should be
diff --git a/include/nuttx/net/netdev.h b/include/nuttx/net/netdev.h
index 72bddc067cc..12b71840d72 100644
--- a/include/nuttx/net/netdev.h
+++ b/include/nuttx/net/netdev.h
@@ -419,7 +419,8 @@ int ipv6_input(FAR struct net_driver_s *dev);
#endif
#ifdef CONFIG_NET_6LOWPAN
-int sixlowpan_input(FAR struct net_driver_s *dev);
+struct ieee802154_driver_s; /* See sixlowpan.h */
+int sixlowpan_input(FAR struct ieee802154_driver_s *ieee);
#endif
/****************************************************************************
diff --git a/include/nuttx/net/sixlowpan.h b/include/nuttx/net/sixlowpan.h
index 7463763bff5..0211d17ce6f 100644
--- a/include/nuttx/net/sixlowpan.h
+++ b/include/nuttx/net/sixlowpan.h
@@ -42,8 +42,8 @@
*
****************************************************************************/
-#ifndef __INCLUDE_NUTTX_NET_SIXLOWOAN_H
-#define __INCLUDE_NUTTX_NET_SIXLOWOAN_H
+#ifndef __INCLUDE_NUTTX_NET_SIXLOWPAN_H
+#define __INCLUDE_NUTTX_NET_SIXLOWPAN_H
/****************************************************************************
* Included Files
@@ -53,8 +53,12 @@
#include
+#include
+#include
#include
+#ifdef CONFIG_NET_6LOWPAN
+
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
@@ -62,17 +66,21 @@
/* Min and Max compressible UDP ports - HC06 */
#define SIXLOWPAN_UDP_4_BIT_PORT_MIN 0xf0b0
-#define SIXLOWPAN_UDP_4_BIT_PORT_MAX 0xf0bf /* F0B0 + 15 */
-#define SIXLOWPAN_UDP_8_BIT_PORT_MIN 0xF000
-#define SIXLOWPAN_UDP_8_BIT_PORT_MAX 0xf0ff /* F000 + 255 */
+#define SIXLOWPAN_UDP_4_BIT_PORT_MAX 0xf0bf /* f0b0 + 15 */
+#define SIXLOWPAN_UDP_8_BIT_PORT_MIN 0xf000
+#define SIXLOWPAN_UDP_8_BIT_PORT_MAX 0xf0ff /* f000 + 255 */
/* 6lowpan dispatches */
#define SIXLOWPAN_DISPATCH_IPV6 0x41 /* 01000001 = 65 */
#define SIXLOWPAN_DISPATCH_HC1 0x42 /* 01000010 = 66 */
-#define SIXLOWPAN_DISPATCH_IPHC 0x60 /* 011xxxxx = ... */
+
+#define SIXLOWPAN_DISPATCH_IPHC 0x60 /* 011xxxxx */
+#define SIXLOWPAN_DISPATCH_IPHC_MASK 0xe0 /* 11100000 */
+
#define SIXLOWPAN_DISPATCH_FRAG1 0xc0 /* 11000xxx */
#define SIXLOWPAN_DISPATCH_FRAGN 0xe0 /* 11100xxx */
+#define SIXLOWPAN_DISPATCH_FRAG_MASK 0xf1 /* 11111000 */
/* HC1 encoding */
@@ -86,38 +94,40 @@
/* IPHC encoding
*
- * Values of fields within the IPHC encoding first byte (C stands for
- * compressed and I for inline)
+ * Values of fields within the IPHC encoding first byte
+ * (Using MS-to-LS bit numbering of the draft RFC)
*/
-
-#define SIXLOWPAN_IPHC_FL_C 0x10
-#define SIXLOWPAN_IPHC_TC_C 0x08
-#define SIXLOWPAN_IPHC_NH_C 0x04
-#define SIXLOWPAN_IPHC_TTL_1 0x01
-#define SIXLOWPAN_IPHC_TTL_64 0x02
-#define SIXLOWPAN_IPHC_TTL_255 0x03
-#define SIXLOWPAN_IPHC_TTL_I 0x00
-
+ /* Bits 0-2: 011 */
+#define SIXLOWPAN_IPHC_TC_MASK 0x18 /* Bits 3-4: Traffic Class, Flow Label */
+# define SIXLOWPAN_IPHC_TC_00 0x00 /* ECN+DSCP+4-bit Pad+Flow Label (4 bytes) */
+# define SIXLOWPAN_IPHC_TC_01 0x08 /* ECN+2-bit Pad+ Flow Label (3 bytes), DSCP is elided. */
+# define SIXLOWPAN_IPHC_TC_10 0x10 /* ECN+DSCP (1 byte), Flow Label is elided */
+# define SIXLOWPAN_IPHC_TC_11 0x11 /* Traffic Class and Flow Label are elided */
+#define SIXLOWPAN_IPHC_NH 0x04 /* Bit 5: Next Header Compressed */
+#define SIXLOWPAN_IPHC_HLIM_MASK 0x03 /* Bits 6-7: Hop Limit */
+# define SIXLOWPAN_IPHC_HLIM_INLINE 0x00 /* Carried in-line */
+# define SIXLOWPAN_IPHC_HLIM_1 0x01 /* Compressed hop limit of 1 */
+# define SIXLOWPAN_IPHC_HLIM_64 0x02 /* Compressed hop limit of 64 */
+# define SIXLOWPAN_IPHC_HLIM_255 0x03 /* Compressed hop limit of 255 */
/* Values of fields within the IPHC encoding second byte */
-#define SIXLOWPAN_IPHC_CID 0x80
-
-#define SIXLOWPAN_IPHC_SAC 0x40
-#define SIXLOWPAN_IPHC_SAM_00 0x00
-#define SIXLOWPAN_IPHC_SAM_01 0x10
-#define SIXLOWPAN_IPHC_SAM_10 0x20
-#define SIXLOWPAN_IPHC_SAM_11 0x30
+#define SIXLOWPAN_IPHC_CID 0x80 /* Bit 8: Context identifier extension */
+#define SIXLOWPAN_IPHC_SAC 0x40 /* Bit 9: Source address compression */
+#define SIXLOWPAN_IPHC_SAM_MASK 0x30 /* Bits 10-11: Source address mode */
+# define SIXLOWPAN_IPHC_SAM_128 0x00 /* 128-bits */
+# define SIXLOWPAN_IPHC_SAM_64 0x10 /* 64-bits */
+# define SIXLOWPAN_IPHC_SAM_16 0x20 /* 16-bits */
+# define SIXLOWPAN_IPHC_SAM_0 0x30 /* 0-bits */
+#define SIXLOWPAN_IPHC_M 0x08 /* Bit 12: Multicast compression */
+#define SIXLOWPAN_IPHC_DAC 0x04 /* Bit 13: Destination address compression */
+#define SIXLOWPAN_IPHC_DAM_MASK 0x03 /* Bits 14-15: Destination address mode */
+# define SIXLOWPAN_IPHC_DAM_128 0x00 /* 128-bits */
+# define SIXLOWPAN_IPHC_DAM_64 0x01 /* 64-bits */
+# define SIXLOWPAN_IPHC_DAM_16 0x02 /* 16-bits */
+# define SIXLOWPAN_IPHC_DAM_0 0x03 /* 0-bits */
#define SIXLOWPAN_IPHC_SAM_BIT 4
-
-#define SIXLOWPAN_IPHC_M 0x08
-#define SIXLOWPAN_IPHC_DAC 0x04
-#define SIXLOWPAN_IPHC_DAM_00 0x00
-#define SIXLOWPAN_IPHC_DAM_01 0x01
-#define SIXLOWPAN_IPHC_DAM_10 0x02
-#define SIXLOWPAN_IPHC_DAM_11 0x03
-
#define SIXLOWPAN_IPHC_DAM_BIT 0
/* Link local context number */
@@ -155,139 +165,67 @@
#define SIXLOWPAN_FRAG1_HDR_LEN 4
#define SIXLOWPAN_FRAGN_HDR_LEN 5
-/* Address compressibility test macros */
-
-/* Check whether we can compress the IID in address 'a' to 16 bits. This is
- * used for unicast addresses only, and is true if the address is on the
- * format ::0000:00ff:fe00:XXXX
- *
- * NOTE: we currently assume 64-bits prefixes
- */
-
-#define SIXLOWPAN_IS_IID_16BIT_COMPRESSABLE(a) \
- ((((a)->u16[4]) == 0) && \
- // (((a)->u8[10]) == 0)&& \
- (((a)->u8[11]) == 0xff)&& \
- (((a)->u8[12]) == 0xfe)&& \
- (((a)->u8[13]) == 0))
-
-/* Check whether the 9-bit group-id of the compressed multicast address is
- * known. It is true if the 9-bit group is the all nodes or all routers
- * group. Parameter 'a' is typed uint8_t *
- */
-
-#define SIXLOWPAN_IS_MCASTADDR_DECOMPRESSABLE(a) \
- (((*a & 0x01) == 0) && \
- ((*(a + 1) == 0x01) || (*(a + 1) == 0x02)))
-
-/* Check whether the 112-bit group-id of the multicast address is mappable
- * to a 9-bit group-id. It is true if the group is the all nodes or all
- * routers group.
- */
-
-#define SIXLOWPAN_IS_MCASTADDR_COMPRESSABLE(a) \
- ((((a)->u16[1]) == 0) && \
- (((a)->u16[2]) == 0) && \
- (((a)->u16[3]) == 0) && \
- (((a)->u16[4]) == 0) && \
- (((a)->u16[5]) == 0) && \
- (((a)->u16[6]) == 0) && \
- (((a)->u8[14]) == 0) && \
- ((((a)->u8[15]) == 1) || (((a)->u8[15]) == 2)))
-
-/* FFXX::00XX:XXXX:XXXX */
-
-#define SIXLOWPAN_IS_MCASTADDR_COMPRESSABLE48(a) \
- ((((a)->u16[1]) == 0) && \
- (((a)->u16[2]) == 0) && \
- (((a)->u16[3]) == 0) && \
- (((a)->u16[4]) == 0) && \
- (((a)->u8[10]) == 0))
-
-/* FFXX::00XX:XXXX */
-
-#define SIXLOWPAN_IS_MCASTADDR_COMPRESSABLE32(a) \
- ((((a)->u16[1]) == 0) && \
- (((a)->u16[2]) == 0) && \
- (((a)->u16[3]) == 0) && \
- (((a)->u16[4]) == 0) && \
- (((a)->u16[5]) == 0) && \
- (((a)->u8[12]) == 0))
-
-/* FF02::00XX */
-
-#define SIXLOWPAN_IS_MCASTADDR_COMPRESSABLE8(a) \
- ((((a)->u8[1]) == 2) && \
- (((a)->u16[1]) == 0) && \
- (((a)->u16[2]) == 0) && \
- (((a)->u16[3]) == 0) && \
- (((a)->u16[4]) == 0) && \
- (((a)->u16[5]) == 0) && \
- (((a)->u16[6]) == 0) && \
- (((a)->u8[14]) == 0))
-
/* This maximum size of an IEEE802.15.4 frame. Certain, non-standard
* devices may exceed this value, however.
*/
#define SIXLOWPAN_MAC_STDFRAME 127
-/* Packet buffer Definitions */
+/* Frame buffer helper macros.
+ *
+ * The IEEE802.15.4 MAC driver structures includes a list of IOB
+ * structures, i_framelist, containing frames to be sent by the driver or
+ * that were received by the driver. The IOB structure is defined in
+ * include/nuttx/net/iob.h. The length of data in the IOB is provided by
+ * the io_len field of the IOB structure.
+ *
+ * NOTE that IOBs must be configured such that CONFIG_IOB_BUFSIZE >=
+ * CONFIG_NET_6LOWPAN_FRAMELEN
+ *
+ * 1. On a TX poll, the IEEE802.15.4 MAC driver should provide its driver
+ * structure with i_framelist set to NULL. At the conclusion of the
+ * poll, if there are frames to be sent, they will have been added to
+ * the i_framelist. The non-empty frame list is the indication that
+ * there is data to be sent.
+ *
+ * The IEEE802.15.4 may use the FRAME_IOB_EMPTY() macro to determine
+ * if there there frames to be sent. If so, it should remove each
+ * frame from the frame list using the FRAME_IOB_REMOVE() macro and send
+ * it. That macro will return NULL when all of the frames have been
+ * sent.
+ *
+ * After sending each frame, the driver must return the IOB to the pool
+ * of free IOBs using the FROM_IOB_FREE() macro.
+ */
-#define PACKETBUF_HDR_SIZE 48
-#define PACKETBUF_ATTR_PACKET_TYPE_DATA 0
-#define PACKETBUF_ATTR_PACKET_TYPE_ACK 1
-#define PACKETBUF_ATTR_PACKET_TYPE_STREAM 2
-#define PACKETBUF_ATTR_PACKET_TYPE_STREAM_END 3
-#define PACKETBUF_ATTR_PACKET_TYPE_TIMESTAMP 4
+#define FRAME_IOB_EMPTY(ieee) ((ieee)->i_framelist == NULL)
+#define FRAME_IOB_REMOVE(ieee, iob) \
+ do \
+ { \
+ (iob) = (ieee)->i_framelist; \
+ (ieee)->i_framelist = (iob)->io_flink; \
+ (iob)->io_flink = NULL; \
+ } \
+ while (0)
+#define FRAME_IOB_FREE(iob) iob_free(iob)
-/* Packet buffer attributes (indices into i_pktattr) */
+/* 2. When receiving data, the IEEE802.15.4 MAC driver should receive the
+ * frame data directly into the payload area of an IOB structure. That
+ * IOB structure may be obtained using the FRAME_IOB_ALLOC() macro. The
+ * single frame should be added to the frame list using FRAME_IOB_ADD()
+ * (it will be a list of length one) . The MAC driver should then inform
+ * the network of the by calling sixlowpan_input().
+ */
-#define PACKETBUF_ATTR_NONE 0
-
-/* Scope 0 attributes: used only on the local node. */
-
-#define PACKETBUF_ATTR_CHANNEL 1
-#define PACKETBUF_ATTR_NETWORK_ID 2
-#define PACKETBUF_ATTR_LINK_QUALITY 3
-#define PACKETBUF_ATTR_RSSI 4
-#define PACKETBUF_ATTR_TIMESTAMP 5
-#define PACKETBUF_ATTR_RADIO_TXPOWER 6
-#define PACKETBUF_ATTR_LISTEN_TIME 7
-#define PACKETBUF_ATTR_TRANSMIT_TIME 8
-#define PACKETBUF_ATTR_MAX_MAC_TRANSMISSIONS 9
-#define PACKETBUF_ATTR_MAC_SEQNO 10
-#define PACKETBUF_ATTR_MAC_ACK 11
-
-/* Scope 1 attributes: used between two neighbors only. */
-
-#define PACKETBUF_ATTR_RELIABLE 12
-#define PACKETBUF_ATTR_PACKET_ID 13
-#define PACKETBUF_ATTR_PACKET_TYPE 14
-#define PACKETBUF_ATTR_REXMIT 15
-#define PACKETBUF_ATTR_MAX_REXMIT 16
-#define PACKETBUF_ATTR_NUM_REXMIT 17
-#define PACKETBUF_ATTR_PENDING 18
-
-/* Scope 2 attributes: used between end-to-end nodes. */
-
-#define PACKETBUF_ATTR_HOPS 11
-#define PACKETBUF_ATTR_TTL 20
-#define PACKETBUF_ATTR_EPACKET_ID 21
-#define PACKETBUF_ATTR_EPACKET_TYPE 22
-#define PACKETBUF_ATTR_ERELIABLE 23
-
-#define PACKETBUF_NUM_ATTRS 24
-
- /* Addresses (indices into i_pktaddr) */
-
-#define PACKETBUF_ADDR_SENDER 0
-#define PACKETBUF_ADDR_RECEIVER 1
-#define PACKETBUF_ADDR_ESENDER 2
-#define PACKETBUF_ADDR_ERECEIVER 3
-
-#define PACKETBUF_NUM_ADDRS 4
+#define FRAME_IOB_ALLOC() iob_alloc(false)
+#define FRAME_IOB_ADD(ieee, iob) \
+ do \
+ { \
+ (iob)->io_flink = (ieee)->i_framelist; \
+ (ieee)->i_framelist = (iob); \
+ } \
+ while (0)
/****************************************************************************
* Public Types
@@ -305,18 +243,20 @@ struct rimeaddr_s
* difference is that fragmentation must be supported.
*
* The IEEE802.15.4 MAC does not use the d_buf packet buffer directly.
- * Rather, it uses a smaller frame buffer, i_frame.
+ * Rather, it uses a list smaller frame buffers, i_framelist.
*
- * - The packet fragment data is provided to the i_frame buffer each time
- * that the IEEE802.15.4 MAC needs to send more data. The length of
- * the frame is provided in i_frame.
+ * - The packet fragment data is provided to an IOB in the i_framelist
+ * buffer each time that the IEEE802.15.4 MAC needs to send more data.
+ * The length of the frame is provided in the io_len field of the IOB.
*
- * In this case, the d_buf holds the packet data yet to be sent; d_len
- * holds the size of entire packet.
+ * In this case, the d_buf is not used at all and, if fact, may be
+ * NULL.
*
* - Received frames are provided by IEEE802.15.4 MAC to the network
- * via i_frame with length i_framelen for reassembly in d_buf; d_len
- * will hold the size of the reassembled packet.
+ * via and IOB in i_framelist with length io_len for reassembly in
+ * d_buf; d_len will hold the size of the reassembled packet.
+ *
+ * In this case, a d_buf of size CONFIG_NET_6LOWPAN_MTU must be provided.
*
* This is accomplished by "inheriting" the standard 'struct net_driver_s'
* and appending the frame buffer as well as other metadata needed to
@@ -328,36 +268,51 @@ struct rimeaddr_s
* this structure. In general, all fields must be set to NULL. In
* addtion:
*
- * 1) i_panid must be set to identify the network. It may be set to 0xfff
+ * 1. i_panid must be set to identify the network. It may be set to 0xfff
* if the device is not associated.
- * 2) i_dsn must be set to a random value. After that, it will be managed
+ *
+ * 2. i_dsn must be set to a random value. After that, it will be managed
* by the network.
- * 3) i_nodeaddr must be set after the MAC is assigned an address.
- * 4) On network TX poll operations, the IEEE802.15.4 MAC needs to provide
- * the i_frame buffer with size greater than or equal to
- * CONFIG_NET_6LOWPAN_FRAMELEN. No dev.d_buf need be provided in this
- * case. The entire is TX is performed using only the i_frame buffer.
- * 5) On network input RX oprations, both buffers must be provided. The size
- * of the i_frame buffer is, again, greater than or equal to
- * CONFIG_NET_6LOWPAN_FRAMELEN. The larger dev.d_buf must have a size
- * of at least the advertised MTU of the protocol, CONFIG_NET_6LOWPAN_MTU.
- * If fragmentation is enabled, then the logical packet size may be
- * significantly larger than the size of the frame buffer. The dev.d_buf
- * is used for de-compressing each frame and reassembling any fragmented
- * packets to create the full input packet that is provided to the
- * application.
*
- * Frame Organization:
+ * 3. i_nodeaddr must be set after the MAC is assigned an address.
*
- * Content Offset
- * +------------------+ 0
- * | Frame Header |
- * +------------------+ i_dataoffset
- * | Procotol Headers |
- * | Data Payload |
- * +------------------+ i_framelen
- * | Unused |
- * +------------------+ CONFIG_NET_6LOWPAN_FRAMELEN
+ * 4. On a TX poll, the IEEE802.15.4 MAC driver should provide its driver
+ * structure with i_framelist set to NULL. At the conclusion of the
+ * poll, if there are frames to be sent, they will have been added to
+ * the i_framelist. The non-empty frame list at the conclusion of the
+ * TX poll is the indication that is data to be sent.
+ *
+ * The IEEE802.15.4 may use the FRAME_IOB_EMPTY() macro to determine
+ * if there there frames to be sent. If so, it should remove each
+ * frame from the frame list using the FRAME_IOB_REMOVE() macro and send
+ * it. That macro will return NULL when all of the frames have been
+ * sent.
+ *
+ * After sending each frame, the driver must return the IOB to the pool
+ * of free IOBs using the FROM_IOB_FREE() macro.
+ *
+ * 5. When receiving data both buffers must be provided:
+ *
+ * The IEEE802.15.4 MAC driver should receive the frame data directly
+ * into the payload area of an IOB structure. That IOB structure may be
+ * obtained using the FRAME_IOB_ALLOC() macro. The single frame should
+ * be added to the frame list using FRAME_IOB_ADD() (it will be a list of
+ * length one).
+ *
+ * The larger dev.d_buf must have a size of at least the advertised MTU
+ * of the protocol, CONFIG_NET_6LOWPAN_MTU. If fragmentation is enabled,
+ * then the logical packet size may be significantly larger than the
+ * size of the frame buffer. The dev.d_buf is used for de-compressing
+ * each frame and reassembling any fragmented packets to create the full
+ * input packet that is provided to the application.
+ *
+ * The MAC driver should then inform the network of the by calling
+ * sixlowpan_input().
+ *
+ * Normally, the network will free the IOB and will nullify the frame
+ * list. But ss a complexity, the result of receiving a frame may be
+ * that the network may respond provide an outgoing frames in the
+ * frame list.
*/
struct ieee802154_driver_s
@@ -370,32 +325,23 @@ struct ieee802154_driver_s
/* IEEE802.15.4 MAC-specific definitions follow. */
- /* The i_frame array is used to hold outgoing frame. When the
- * IEEE802.15.4 device polls for new data, the outgoing frame containing
- * the next fragment is placed in i_frame.
+ /* The i_framelist is used to hold a outgoing frames contained in IOB
+ * structures. When the IEEE802.15.4 device polls for new TX data, the
+ * outgoing frame(s) containing the packet fragments are placed in IOBs
+ * and queued in i_framelist.
*
- * The network will handle only a single outgong frame at a time. The
- * IEEE802.15.4 MAC driver design may be concurrently sending and
- * requesting new framesusing break-off fram buffers. That frame buffer
- * management must be controlled by the IEEE802.15.4 MAC driver.
+ * The i_framelist is similary used to hold incoming frames in IOB
+ * structures. The IEEE802.15.4 MAC driver must receive frames in an IOB,
+ * place the IOB in the i_framelist, and call sixlowpan_input().
*
- * Driver provided frame buffers should of size CONFIG_NET_6LOWPAN_FRAMELEN
- * and should be 16-bit aligned.
+ * The IEEE802.15.4 MAC driver design may be concurrently sending and
+ * requesting new frames using lists of IOBs. That IOB frame buffer
+ * management must be managed by the IEEE802.15.4 MAC driver.
*/
- FAR uint8_t *i_frame;
-
- /* The length of valid data in the i_frame buffer.
- *
- * When the network device driver calls the network input function,
- * i_framelen should be set to zero. If there is frame to be sent
- * by the network, i_framelen will be set to indicate the size of
- * frame to be sent. The value zero means that there is no frame
- * to be sent.
- */
-
- uint16_t i_framelen;
+ FAR struct iob_s *i_framelist;
+ /* Driver Configuration ***************************************************/
/* i_panid. The PAN ID is 16-bit number that identifies the network. It
* must be unique to differentiate a network. All the nodes in the same
* network should have the same PAN ID. This value must be provided to
@@ -421,71 +367,48 @@ struct ieee802154_driver_s
uint8_t i_dsn;
- /* The following fields are device-specific metadata used by the 6loWPAN
- * stack and should not be modified by the IEEE802.15.4 MAC network drvier.
+#if CONFIG_NET_6LOWPAN_FRAG
+ /* Fragmentation Support *************************************************/
+ /* Fragmentation is handled frame by frame and requires that certain
+ * state information be retained from frame to frame.
*/
- /* A pointer to the rime buffer.
- *
- * We initialize it to the beginning of the rime buffer, then access
- * different fields by updating the offset ieee->i_rime_hdrlen.
+ /* i_dgramtag. Datagram tag to be put in the header of the set of
+ * fragments. It is used by the recipient to match fragments of the
+ * same payload.
*/
- FAR uint8_t *i_rimeptr;
+ uint16_t i_dgramtag;
- /* i_uncomp_hdrlen is the length of the headers before compression (if HC2
- * is used this includes the UDP header in addition to the IP header).
+ /* i_pktlen. The total length of the IPv6 packet to be re-assembled in
+ * d_buf.
*/
- uint8_t i_uncomp_hdrlen;
+ uint16_t i_pktlen;
- /* i_rime_hdrlen is the total length of (the processed) 6lowpan headers
- * (fragment headers, IPV6 or HC1, HC2, and HC1 and HC2 non compressed
- * fields).
+ /* The current accumulated length of the packet being received in d_buf.
+ * Included IPv6 and protocol headers.
*/
- uint8_t i_rime_hdrlen;
+ uint16_t i_accumlen;
- /* Offset first available byte for the payload after header region. */
-
- uint8_t i_dataoffset;
-
- /* Packet buffer metadata: Attributes and addresses */
-
- uint16_t i_pktattrs[PACKETBUF_NUM_ATTRS];
- struct rimeaddr_s i_pktaddrs[PACKETBUF_NUM_ADDRS];
-};
-
-/* The structure of a next header compressor. This compressor is provided
- * by architecture-specific logic outside of the network stack.
- *
- * TODO: needs more parameters when compressing extension headers, etc.
- */
-
-struct sixlowpan_nhcompressor_s
-{
- CODE int (*is_compressable)(uint8_t next_header);
-
- /* Compress next header (TCP/UDP, etc) - ptr points to next header to
- * compress.
+ /* i_reasstag. Each frame in the reassembly has a tag. That tag must
+ * match the reassembly tag in the fragments being merged.
*/
- CODE int (*compress)(FAR uint8_t *compressed, FAR uint8_t *uncompressed_len);
+ uint16_t i_reasstag;
- /* Uncompress next header (TCP/UDP, etc) - ptr points to next header to
- * uncompress.
+ /* The source MAC address of the fragments being merged */
+
+ struct rimeaddr_s i_fragsrc;
+
+ /* That time at which reassembly was started. If the elapsed time
+ * exceeds CONFIG_NET_6LOWPAN_MAXAGE, then the reassembly will
+ * be cancelled.
*/
- CODE int (*uncompress)(FAR uint8_t *compressed, FAR uint8_t *lowpanbuf,
- FAR uint8_t *uncompressed_len);
-};
-
-/* RIME sniffer callbacks */
-
-struct sixlowpan_rime_sniffer_s
-{
- CODE void (*input)(void);
- CODE void (*output)(int mac_status);
+ systime_t i_time;
+#endif /* CONFIG_NET_6LOWPAN_FRAG */
};
/****************************************************************************
@@ -493,40 +416,59 @@ struct sixlowpan_rime_sniffer_s
****************************************************************************/
/****************************************************************************
- * Function: sixlowpan_set_compressor
+ * Name: sixlowpan_input
*
* Description:
- * Configure to use the architecture-specific compressor.
+ * Process an incoming 6loWPAN frame.
*
- * Input parameters:
- * compressor - A reference to the new compressor to be used. This may
- * be a NULL value to disable the compressor.
+ * This function is called when the device driver has received a 6loWPAN
+ * frame from the network. The frame from the device driver must be
+ * provided in a IOB present in the i_framelist: The frame data is in the
+ * IOB io_data[] buffer and the length of the frame is in the IOB io_len
+ * field. Only a single IOB is expected in the i_framelist. This incoming
+ * data will be processed one frame at a time.
+ *
+ * An non-NULL d_buf of size CONFIG_NET_6LOWPAN_MTU must also be provided.
+ * The frame will be decompressed and placed in the d_buf. Fragmented
+ * packets will also be reassembled in the d_buf as they are received
+ * (meaning for the driver, that two packet buffers are required: One for
+ * reassembly of RX packets and one used for TX polling).
+ *
+ * After each frame is processed into d_buf, the IOB is removed and
+ * deallocated. i_framelist will be nullified. If reassembly is
+ * incomplete, this function will return to called with i_framelist
+ * equal to NULL. The partially reassembled packet must be preserved by
+ * the IEEE802.15.4 MAC and provided again when the next frame is
+ * received.
+ *
+ * When the packet in the d_buf is fully reassembled, it will be provided
+ * to the network as with any other received packet. d_len will be set
+ * the the length of the uncompressed, reassembled packet.
+ *
+ * After the network processes the packet, d_len will be set to zero.
+ * Network logic may also decide to send a response to the packet. In
+ * that case, the outgoing network packet will be placed in d_buf the
+ * d_buf and d_len will be set to a non-zero value. That case is handled
+ * by this function.
+ *
+ * If that case occurs, the packet will be converted to a list of
+ * compressed and possibly fragmented frames in i_framelist as with other
+ * TX operations.
+ *
+ * So from the standpoint of the IEEE802.15.4 MAC driver, there are two
+ * possible results: (1) i_framelist is NULL meaning that the frame
+ * was fully processed and freed, or (2) i_framelist is non-NULL meaning
+ * that there are outgoing frame(s) to be sent.
+ *
+ * Input Parameters:
+ * ieee - The IEEE802.15.4 MAC network driver interface.
*
* Returned Value:
- * None
+ * Ok is returned on success; Othewise a negated errno value is returned.
*
****************************************************************************/
-void sixlowpan_set_compressor(FAR struct sixlowpan_nhcompressor_s *compressor);
+int sixlowpan_input(FAR struct ieee802154_driver_s *ieee);
-/****************************************************************************
- * Function: sixlowpan_set_sniffer
- *
- * Description:
- * Configure to use an architecture-specific sniffer to enable tracing of
- * IP.
- *
- * Input parameters:
- * sniffer - A reference to the new sniffer to be used. This may
- * be a NULL value to disable the sniffer.
- *
- * Returned Value:
- * None
- *
- ****************************************************************************/
-
-#ifdef CONFIG_NET_6LOWPAN_SNIFFER
-void sixlowpan_set_sniffer(FAR struct sixlowpan_rime_sniffer_s *sniffer);
-#endif
-
-#endif /* __INCLUDE_NUTTX_NET_SIXLOWOAN_H */
+#endif /* CONFIG_NET_6LOWPAN */
+#endif /* __INCLUDE_NUTTX_NET_SIXLOWPAN_H */
diff --git a/include/nuttx/net/usrsock.h b/include/nuttx/net/usrsock.h
new file mode 100644
index 00000000000..3ca990d44e3
--- /dev/null
+++ b/include/nuttx/net/usrsock.h
@@ -0,0 +1,233 @@
+/****************************************************************************
+ * include/nuttx/net/usrsock.h
+ *
+ * Copyright (C) 2015, 2017 Haltian Ltd. All rights reserved.
+ * Author: Jussi Kivilinna
+ *
+ * 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_NET_USRSOCK_H
+#define __INCLUDE_NUTTX_NET_USRSOCK_H
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include
+
+#include
+#include
+
+#include
+#include
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/* Event message flags */
+
+#define USRSOCK_EVENT_ABORT (1 << 0)
+#define USRSOCK_EVENT_SENDTO_READY (1 << 1)
+#define USRSOCK_EVENT_RECVFROM_AVAIL (1 << 2)
+#define USRSOCK_EVENT_REMOTE_CLOSED (1 << 3)
+
+/* Response message flags */
+
+#define USRSOCK_MESSAGE_FLAG_REQ_IN_PROGRESS (1 << 0)
+#define USRSOCK_MESSAGE_FLAG_EVENT (1 << 1)
+
+#define USRSOCK_MESSAGE_IS_EVENT(flags) \
+ (!!((flags) & USRSOCK_MESSAGE_FLAG_EVENT))
+#define USRSOCK_MESSAGE_IS_REQ_RESPONSE(flags) \
+ (!USRSOCK_MESSAGE_IS_EVENT(flags))
+
+#define USRSOCK_MESSAGE_REQ_IN_PROGRESS(flags) \
+ (!!((flags) & USRSOCK_MESSAGE_FLAG_REQ_IN_PROGRESS))
+#define USRSOCK_MESSAGE_REQ_COMPLETED(flags) \
+ (!USRSOCK_MESSAGE_REQ_IN_PROGRESS(flags))
+
+/****************************************************************************
+ * Public Types
+ ****************************************************************************/
+
+/* Request types */
+
+enum usrsock_request_types_e
+{
+ USRSOCK_REQUEST_SOCKET = 0,
+ USRSOCK_REQUEST_CLOSE,
+ USRSOCK_REQUEST_CONNECT,
+ USRSOCK_REQUEST_SENDTO,
+ USRSOCK_REQUEST_RECVFROM,
+ USRSOCK_REQUEST_SETSOCKOPT,
+ USRSOCK_REQUEST_GETSOCKOPT,
+ USRSOCK_REQUEST_GETSOCKNAME,
+ USRSOCK_REQUEST_BIND,
+ USRSOCK_REQUEST__MAX
+};
+
+/* Response/event message types */
+
+enum usrsock_message_types_e
+{
+ USRSOCK_MESSAGE_RESPONSE_ACK = 0,
+ USRSOCK_MESSAGE_RESPONSE_DATA_ACK,
+ USRSOCK_MESSAGE_SOCKET_EVENT,
+};
+
+/* Request structures (kernel => /dev/usrsock => daemon) */
+
+begin_packed_struct struct usrsock_request_common_s
+{
+ int8_t reqid;
+ uint8_t xid;
+} end_packed_struct;
+
+begin_packed_struct struct usrsock_request_socket_s
+{
+ struct usrsock_request_common_s head;
+
+ int16_t domain;
+ int16_t type;
+ int16_t protocol;
+} end_packed_struct;
+
+begin_packed_struct struct usrsock_request_close_s
+{
+ struct usrsock_request_common_s head;
+
+ int16_t usockid;
+} end_packed_struct;
+
+begin_packed_struct struct usrsock_request_bind_s
+{
+ struct usrsock_request_common_s head;
+
+ int16_t usockid;
+ uint16_t addrlen;
+} end_packed_struct;
+
+begin_packed_struct struct usrsock_request_connect_s
+{
+ struct usrsock_request_common_s head;
+
+ int16_t usockid;
+ uint16_t addrlen;
+} end_packed_struct;
+
+begin_packed_struct struct usrsock_request_sendto_s
+{
+ struct usrsock_request_common_s head;
+
+ int16_t usockid;
+ uint16_t addrlen;
+ uint16_t buflen;
+} end_packed_struct;
+
+begin_packed_struct struct usrsock_request_recvfrom_s
+{
+ struct usrsock_request_common_s head;
+
+ int16_t usockid;
+ uint16_t max_buflen;
+ uint16_t max_addrlen;
+} end_packed_struct;
+
+begin_packed_struct struct usrsock_request_setsockopt_s
+{
+ struct usrsock_request_common_s head;
+
+ int16_t usockid;
+ int16_t level;
+ int16_t option;
+ uint16_t valuelen;
+} end_packed_struct;
+
+begin_packed_struct struct usrsock_request_getsockopt_s
+{
+ struct usrsock_request_common_s head;
+
+ int16_t usockid;
+ int16_t level;
+ int16_t option;
+ uint16_t max_valuelen;
+} end_packed_struct;
+
+begin_packed_struct struct usrsock_request_getsockname_s
+{
+ struct usrsock_request_common_s head;
+
+ int16_t usockid;
+ uint16_t max_addrlen;
+} end_packed_struct;
+
+/* Response/event message structures (kernel <= /dev/usrsock <= daemon) */
+
+begin_packed_struct struct usrsock_message_common_s
+{
+ int8_t msgid;
+ int8_t flags;
+} end_packed_struct;
+
+/* Request acknowledgment/completion message */
+
+begin_packed_struct struct usrsock_message_req_ack_s
+{
+ struct usrsock_message_common_s head;
+
+ uint8_t xid;
+ int32_t result;
+} end_packed_struct;
+
+/* Request acknowledgment/completion message */
+
+begin_packed_struct struct usrsock_message_datareq_ack_s
+{
+ struct usrsock_message_req_ack_s reqack;
+
+ /* head.result => positive buflen, negative error-code. */
+
+ uint16_t valuelen; /* length of value returned after buffer */
+ uint16_t valuelen_nontrunc; /* actual non-truncated length of value at
+ * daemon-sïde. */
+} end_packed_struct;
+
+/* Socket event message */
+
+begin_packed_struct struct usrsock_message_socket_event_s
+{
+ struct usrsock_message_common_s head;
+
+ int16_t usockid;
+ uint16_t events;
+} end_packed_struct;
+
+#endif /* __INCLUDE_NUTTX_NET_USRSOCK_H */
diff --git a/include/nuttx/sensors/hts221.h b/include/nuttx/sensors/hts221.h
index 47142c3f82d..1b9ddc56251 100644
--- a/include/nuttx/sensors/hts221.h
+++ b/include/nuttx/sensors/hts221.h
@@ -117,10 +117,11 @@ typedef struct hts221_settings_s
typedef struct hts221_config_s
{
int irq;
- CODE int (*irq_attach)(FAR struct hts221_config_s * state, xcpt_t isr);
- CODE void (*irq_enable)(FAR const struct hts221_config_s * state,
+ CODE int (*irq_attach)(FAR struct hts221_config_s * state, xcpt_t isr,
+ FAR void *arg);
+ CODE void (*irq_enable)(FAR const struct hts221_config_s *state,
bool enable);
- CODE void (*irq_clear)(FAR const struct hts221_config_s * state);
+ CODE void (*irq_clear)(FAR const struct hts221_config_s *state);
CODE int (*set_power)(FAR const struct hts221_config_s *state, bool on);
} hts221_config_t;
diff --git a/include/nuttx/sensors/ioctl.h b/include/nuttx/sensors/ioctl.h
index 231c2056012..18b414773fe 100644
--- a/include/nuttx/sensors/ioctl.h
+++ b/include/nuttx/sensors/ioctl.h
@@ -125,4 +125,22 @@
#define SNIOC_READ_CONVERT_DATA _SNIOC(0x002f)
#define SNIOC_DUMP_REGS _SNIOC(0x0030)
+/* IOCTL commands unique to the LPS25H */
+
+#define SNIOC_GET_DEV_ID _SNIOC(0x0031)
+#define SNIOC_CFGR _SNIOC(0x0032)
+#define SNIOC_TEMPERATURE_OUT _SNIOC(0x0033)
+#define SNIOC_PRESSURE_OUT _SNIOC(0x0034)
+#define SNIOC_SENSOR_OFF _SNIOC(0x0035)
+
+/* IOCTL commands unique to the LIS2DH */
+
+#define SNIOC_WRITESETUP _SNIOC(0x0036) /* Arg: uint8_t value */
+#define SNIOC_WRITE_INT1THRESHOLD _SNIOC(0x0037) /* Arg: uint8_t value */
+#define SNIOC_WRITE_INT2THRESHOLD _SNIOC(0x0038) /* Arg: uint8_t value */
+#define SNIOC_RESET_HPFILTER _SNIOC(0x0039) /* Arg: uint8_t value */
+#define SNIOC_START_SELFTEST _SNIOC(0x003a) /* Arg: uint8_t value */
+#define SNIOC_WHO_AM_I _SNIOC(0x003b)
+#define SNIOC_READ_TEMP _SNIOC(0x003c) /* Arg: int16_t value */
+
#endif /* __INCLUDE_NUTTX_SENSORS_IOCTL_H */
diff --git a/include/nuttx/sensors/lis2dh.h b/include/nuttx/sensors/lis2dh.h
new file mode 100644
index 00000000000..bede2795c23
--- /dev/null
+++ b/include/nuttx/sensors/lis2dh.h
@@ -0,0 +1,445 @@
+/****************************************************************************
+ * include/nuttx/sensors/lis2dh.h
+ * LIS2DH accelerometer driver
+ *
+ * Copyright (C) 2014-2017 Haltian Ltd. All rights reserved.
+ * Authors: Timo Voutilainen
+ *
+ * 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_SENSORS_LIS2DH_H
+#define __INCLUDE_NUTTX_SENSORS_LIS2DH_H
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include
+
+/****************************************************************************
+ * Pre-Processor Declarations
+ ****************************************************************************/
+
+#undef EXTERN
+#if defined(__cplusplus)
+#define EXTERN extern "C"
+extern "C"
+{
+#else
+#define EXTERN extern
+#endif
+
+#define ST_LIS2DH_WHOAMI_VALUE 0x33 /* Valid WHOAMI register value */
+
+/* LIS2DH Internal Registers **********************************************/
+
+#define ST_LIS2DH_WHOAMI_REG 0x0f /* WHOAMI register */
+
+#define ST_LIS2DH_STATUS_AUX_REG 0x07 /* Temperature status */
+#define ST_LIS2DH_OUT_TEMP_L_REG 0x0c /* Temperature data */
+#define ST_LIS2DH_OUT_TEMP_H_REG 0x0d /* Temperature data */
+
+#define ST_LIS2DH_TEMP_CFG_REG 0x1f
+
+#define ST_LIS2DH_CTRL_REG1 0x20
+
+/* CR1 ODR 4 MSBs (XXXX---) */
+
+#define ST_LIS2DH_CR1_ODR_PWR_DWN 0x00
+#define ST_LIS2DH_CR1_ODR_1HZ 0x10 /* HR / Normal / Low Power */
+#define ST_LIS2DH_CR1_ODR_10HZ 0x20 /* HR / Normal / Low Power */
+#define ST_LIS2DH_CR1_ODR_25HZ 0x30 /* HR / Normal / Low Power */
+#define ST_LIS2DH_CR1_ODR_50HZ 0x40 /* HR / Normal / Low Power */
+#define ST_LIS2DH_CR1_ODR_100HZ 0x50 /* HR / Normal / Low Power */
+#define ST_LIS2DH_CR1_ODR_200HZ 0x60 /* HR / Normal / Low Power */
+#define ST_LIS2DH_CR1_ODR_400HZ 0x70 /* HR / Normal / Low Power */
+#define ST_LIS2DH_CR1_ODR_1620HZ 0x80 /* Low Power */
+#define ST_LIS2DH_CR1_ODR_1344_5376HZ 0x90 /* HR / Normal: 1344Hz, Low power: 5376Hz*/
+#define ST_LIS2DH_CR1_LOWP_ENABLE 0x08 /* Low power mode enable */
+#define ST_LIS2DH_CR1_ZEN 0x04 /* Z-Axis Enable */
+#define ST_LIS2DH_CR1_YEN 0x02 /* Y-Axis Enable */
+#define ST_LIS2DH_CR1_XEN 0x01 /* X-Axis Enable */
+
+#define ST_LIS2DH_CTRL_REG2 0x21
+
+/* HPM1 .... HP FILT_MODE (XX------) */
+
+#define ST_LIS2DH_CR2_HPFILT_M_NORM 0x00 /* Normal mode (reset reading REFERENCE/DATACAPTURE (26h) register) */
+#define ST_LIS2DH_CR2_HPFILT_M_REFSIG 0x40 /* Reference signal for filtering */
+#define ST_LIS2DH_CR2_HPFILT_M_NORM2 0x80 /* Normal mode */
+#define ST_LIS2DH_CR2_HPFILT_M_AUTOR 0xc0 /* Autoreset on interrupt event */
+#define ST_LIS2DH_CR2_FDS 0x08
+
+/* HPIS1 HPFILT ENABLE for INT1 (-------X) */
+
+#define ST_LIS2DH_CR2_HPENABLED_INT1 0x01 /* HP filter enabled for INT1 */
+
+/* HPIS2 HPFILT ENABLE for INT2 (------X-) */
+
+#define ST_LIS2DH_CR2_HPENABLED_INT2 0x02 /* HP filter enabled for INT2 */
+
+#define ST_LIS2DH_CTRL_REG3 0x22
+
+/* I1_AOI1 ENABLE for INT2 (-X------) */
+
+#define ST_LIS2DH_CR3_I1_AOI1_ENABLED 0x40 /* AOI1 interrupt on INT1 pin. */
+#define ST_LIS2DH_CR3_I1_AOI2_ENABLED 0x20 /* AOI2 interrupt on INT1 pin. */
+#define ST_LIS2DH_CR3_I1_DRDY1 0x10 /* DRDY1 interrupt on INT1 pin. */
+#define ST_LIS2DH_CR3_I1_DRDY2 0x08 /* DRDY2 interrupt on INT1 pin. */
+#define ST_LIS2DH_CR3_I1_WTM 0x04 /* FIFO Watermark interrupt on INT1 pin. */
+#define ST_LIS2DH_CR3_I1_OVERRUN 0x02 /* FIFO Overrun interrupt on INT1 pin. */
+
+#define ST_LIS2DH_CTRL_REG4 0x23
+
+/* BDU ... Block Data Update (X-------) */
+
+#define ST_LIS2DH_CR4_BDU_CONT 0x00 /* Continuous update (Default) */
+#define ST_LIS2DH_CR4_BDU_UPD_ON_READ 0x80 /* Output registers not updated until MSB and LSB have been read */
+#define ST_LIS2DH_CR4_FULL_SCALE_2G 0x0
+#define ST_LIS2DH_CR4_FULL_SCALE_4G 0x10
+#define ST_LIS2DH_CR4_FULL_SCALE_8G 0x20
+#define ST_LIS2DH_CR4_FULL_SCALE_16G 0x30
+
+/* HR .. Operation mode selector (----X---) */
+
+#define ST_LIS2DH_CR4_HR_ENABLED 0x08 /* See section 2.6.3 in datasheet */
+
+#define ST_LIS2DH_CTRL_REG5 0x24
+#define ST_LIS2DH_CR5_BOOT 0x80
+#define ST_LIS2DH_CR5_FIFO_EN 0x40
+#define ST_LIS2DH_CR5_LIR_INT1 0x08
+#define ST_LIS2DH_CR5_D4D_INT1 0x04
+#define ST_LIS2DH_CR5_LIR_INT2 0x02
+#define ST_LIS2DH_CR5_D4D_INT2 0x01
+
+#define ST_LIS2DH_CTRL_REG6 0x25
+#define ST_LIS2DH_REFERENCE_REG 0x26
+
+#define ST_LIS2DH_STATUS_REG 0x27 /* Status Register */
+#define ST_LIS2DH_SR_ZYXOR 0x80 /* OR'ed X,Y and Z data over-run */
+#define ST_LIS2DH_SR_ZOR 0x40 /* individual data over-run ... */
+#define ST_LIS2DH_SR_YOR 0x20
+#define ST_LIS2DH_SR_XOR 0x10
+#define ST_LIS2DH_SR_ZYXDA 0x08 /* OR'ed X,Y and Z data available */
+#define ST_LIS2DH_SR_ZDA 0x04 /* individual data available ... */
+#define ST_LIS2DH_SR_YDA 0x02
+#define ST_LIS2DH_SR_XDA 0x01
+
+#define ST_LIS2DH_OUT_X_L_REG 0x28
+#define ST_LIS2DH_OUT_X_H_REG 0x29
+#define ST_LIS2DH_OUT_Y_L_REG 0x2a
+#define ST_LIS2DH_OUT_Y_H_REG 0x2b
+#define ST_LIS2DH_OUT_Z_L_REG 0x2c
+#define ST_LIS2DH_OUT_Z_H_REG 0x2d
+
+#define ST_LIS2DH_FIFO_CTRL_REG 0x2e
+#define ST_LIS2DH_FIFOCR_THRESHOLD_MASK 0x1f
+#define ST_LIS2DH_FIFOCR_THRESHOLD(x) ((x) & ST_LIS2DH_FIFOCR_THRESHOLD_MASK)
+#define ST_LIS2DH_FIFOCR_INT1 0x00
+#define ST_LIS2DH_FIFOCR_INT2 0x20
+#define ST_LIS2DH_FIFOCR_MODE_MASK 0xc0
+
+#define ST_LIS2DH_FIFO_SRC_REG 0x2f
+#define ST_LIS2DH_FIFOSR_NUM_SAMP_MASK 0x1f
+#define ST_LIS2DH_FIFOSR_EMPTY 0x20
+#define ST_LIS2DH_FIFOSR_OVRN_FIFO 0x40
+#define ST_LIS2DH_FIFOSR_WTM 0x80
+
+#define ST_LIS2DH_INT1_CFG_REG 0x30
+#define ST_LIS2DH_INT_CFG_AOI 0x80
+#define ST_LIS2DH_INT_CFG_6D 0x40
+#define ST_LIS2DH_INT_CFG_ZHIE 0x20
+#define ST_LIS2DH_INT_CFG_ZLIE 0x10
+#define ST_LIS2DH_INT_CFG_YHIE 0x08
+#define ST_LIS2DH_INT_CFG_YLIE 0x04
+#define ST_LIS2DH_INT_CFG_XHIE 0x02
+#define ST_LIS2DH_INT_CFG_XLIE 0x01
+
+#define ST_LIS2DH_INT1_SRC_REG 0x31
+#define ST_LIS2DH_INT_SR_XLOW 0x01
+#define ST_LIS2DH_INT_SR_XHIGH 0x02
+#define ST_LIS2DH_INT_SR_YLOW 0x04
+#define ST_LIS2DH_INT_SR_YHIGH 0x08
+#define ST_LIS2DH_INT_SR_ZLOW 0x10
+#define ST_LIS2DH_INT_SR_ZHIGH 0x20
+#define ST_LIS2DH_INT_SR_ACTIVE 0x40
+
+#define ST_LIS2DH_INT1_THS_REG 0x32 /* 7-bit value for threshold */
+
+#define ST_LIS2DH_INT1_DUR_REG 0x33 /* 7-bit value for duration */
+
+#define ST_LIS2DH_INT2_CFG_REG 0x34
+
+#define ST_LIS2DH_INT2_SRC_REG 0x35
+
+#define ST_LIS2DH_INT2_THS_REG 0x36 /* 7-bit value for threshold */
+
+#define ST_LIS2DH_INT2_DUR_REG 0x37 /* 7-bit value for duration */
+
+#define ST_LIS2DH_CLICK_CFG_REG 0x38
+
+#define ST_LIS2DH_CLICK_SRC_REG 0x39
+
+#define ST_LIS2DH_CLICK_THS_REG 0x3a
+
+#define ST_LIS2DH_TIME_LIMIT_REG 0x3b
+
+#define ST_LIS2DH_TIME_LATENCY_REG 0x3c
+
+#define ST_LIS2DH_TIME_WINDOW_REG 0x3d
+
+#define ST_LIS2DH_ACT_DUR_REG 0x3f
+
+/************************************************************************************
+ * Public Types
+ ************************************************************************************/
+
+enum lis2dh_ouput_data_rate
+{
+ LIS2DH_ODR_POWER_DOWN = 0x00,
+ LIS2DH_ODR_1HZ = 0x10,
+ LIS2DH_ODR_10HZ = 0x20,
+ LIS2DH_ODR_25HZ = 0x30,
+ LIS2DH_ODR_50HZ = 0x40,
+ LIS2DH_ODR_100HZ = 0x50,
+ LIS2DH_ODR_200HZ = 0x60,
+ LIS2DH_ODR_400HZ = 0x70,
+ LIS2DH_ODR_1620HZ = 0x80,
+ LIS2DH_ODR_5376HZ = 0x90,
+};
+
+enum lis2dh_high_pass_filter_mode
+{
+ LIS2DH_REFERENCE_SIGNAL = 0x40,
+ LIS2DH_NORMAL_MODE = 0x80,
+ LIS2DH_AUTORESET_ON_INTERRUPT = 0xc0,
+};
+
+enum lis2dh_scale_range
+{
+ LIS2DH_RANGE_2G = 0x00,
+ LIS2DH_RANGE_4G = 0x10,
+ LIS2DH_RANGE_8G = 0x20,
+ LIS2DH_RANGE_16G = 0x30,
+};
+
+enum lis2dh_self_test
+{
+ LIS2DH_NORMAL = 0x00,
+ LIS2DH_SELF_TEST0 = 0x02,
+ LIS2DH_SELF_TEST1 = 0x04,
+};
+
+enum lis2dh_fifo_mode
+{
+ LIS2DH_BYPASS_MODE = 0x00,
+ LIS2DH_FIFO_MODE = 0x40,
+ LIS2DH_STREAM_MODE = 0x80,
+ LIS2DH_TRIGGER_MODE = 0xc0,
+};
+
+enum lis2dh_interrupt_mode
+{
+ LIS2DH_OR_COMBINATION = 0x00,
+ LIS2DH_6D_MOVEMENT = 0x40,
+ LIS2DH_AND_COMBINATION = 0x80,
+ LIS2DH_6D_POSITION = 0xc0,
+};
+
+struct lis2dh_vector_s
+{
+ int16_t x, y, z;
+} packed_struct;
+
+struct lis2dh_res_header
+{
+ uint8_t meas_count;
+ bool int1_occurred;
+ uint8_t int1_source;
+ bool int2_occurred;
+ uint8_t int2_source;
+} packed_struct;
+
+struct lis2dh_result
+{
+ struct lis2dh_res_header header;
+ struct lis2dh_vector_s measurements[0];
+} packed_struct;
+
+struct lis2dh_setup
+{
+ bool temp_enable:1;
+ bool xy_axis_fixup:1;
+
+ uint8_t data_rate;
+ uint8_t low_power_mode_enable;
+ uint8_t zen;
+ uint8_t yen;
+ uint8_t xen;
+
+ uint8_t hpmode;
+ uint8_t hpcf;
+ uint8_t fds;
+ uint8_t hpclick;
+ uint8_t hpis2;
+ uint8_t hpis1;
+
+ uint8_t int1_click_enable;
+ uint8_t int1_aoi_enable;
+ uint8_t int2_aoi_enable;
+ uint8_t int1_drdy_enable;
+ uint8_t int2_drdy_enable;
+ uint8_t int_wtm_enable;
+ uint8_t int_overrun_enable;
+
+ uint8_t bdu;
+ uint8_t endian;
+ uint8_t fullscale;
+ uint8_t high_resolution_enable;
+ uint8_t selftest;
+ uint8_t spi_mode;
+
+ uint8_t reboot;
+ uint8_t fifo_enable;
+ uint8_t int1_latch;
+ uint8_t int1_4d_enable;
+ uint8_t int2_latch;
+ uint8_t int2_4d_enable;
+
+ uint8_t int2_click_enable;
+ uint8_t int_enable;
+ uint8_t boot_int1_enable;
+ uint8_t high_low_active;
+
+ uint8_t reference;
+
+ uint8_t fifo_mode;
+ uint8_t trigger_selection;
+ uint8_t fifo_trigger_threshold;
+
+ uint8_t int1_interrupt_mode;
+ uint8_t int1_enable_6d;
+ uint8_t int1_int_z_high_enable;
+ uint8_t int1_int_z_low_enable;
+ uint8_t int1_int_y_high_enable;
+ uint8_t int1_int_y_low_enable;
+ uint8_t int1_int_x_high_enable;
+ uint8_t int1_int_x_low_enable;
+ uint8_t int1_int_threshold;
+ uint8_t int1_int_duration;
+
+ uint8_t int2_interrupt_mode;
+ uint8_t int2_enable_6d;
+ uint8_t int2_int_z_high_enable;
+ uint8_t int2_int_z_low_enable;
+ uint8_t int2_int_y_high_enable;
+ uint8_t int2_int_y_low_enable;
+ uint8_t int2_int_x_high_enable;
+ uint8_t int2_int_x_low_enable;
+ uint8_t int2_int_threshold;
+ uint8_t int2_int_duration;
+
+ uint8_t z_double_click_enable;
+ uint8_t z_single_click_enable;
+ uint8_t y_double_click_enable;
+ uint8_t y_single_click_enable;
+ uint8_t x_double_click_enable;
+ uint8_t x_single_click_enable;
+
+ uint8_t click_threshold;
+ uint8_t click_time_limit;
+ uint8_t click_time_latency;
+ uint8_t click_time_window;
+};
+
+struct lis2dh_config_s
+{
+ /* Device characterization */
+
+ int irq; /* IRQ number received by interrupt handler. */
+
+ /* IRQ/GPIO access callbacks. These operations all hidden behind
+ * callbacks to isolate the lis2dh driver from differences in GPIO
+ * interrupt handling by varying boards and MCUs.
+ *
+ * irq_attach - Attach the lis2dh interrupt handler to the GPIO interrupt
+ * irq_enable - Enable or disable the GPIO interrupt
+ * clear_irq - Acknowledge/clear any pending GPIO interrupt
+ *
+ */
+
+ CODE int (*irq_attach)(FAR struct lis2dh_config_s *state, xcpt_t isr, FAR void *arg);
+ CODE void (*irq_enable)(FAR const struct lis2dh_config_s *state, bool enable);
+ CODE void (*irq_clear)(FAR const struct lis2dh_config_s *state);
+ CODE bool (*read_int1_pin)(void);
+ CODE bool (*read_int2_pin)(void);
+};
+
+struct lis2dh_raw_data_s
+{
+ uint16_t out_x;
+ uint16_t out_y;
+ uint16_t out_z;
+} packed_struct;
+
+typedef struct lis2dh_raw_data_s lis2dh_raw_data_t;
+
+/****************************************************************************
+ * Public Function Prototypes
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: lis2dh_register
+ *
+ * Description:
+ * Register the LIS2DH character device as 'devpath'
+ *
+ * Input Parameters:
+ * devpath - The full path to the driver to register. E.g., "/dev/acc0"
+ * i2c - An instance of the I2C interface to use to communicate with LIS2DH
+ * addr - The I2C address of the LIS2DH. The base I2C address of the LIS2DH
+ * is 0x18. Bit 0 can be controlled via SA0 pad - when connected to
+ * voltage supply the address is 0x19.
+ * config - Pointer to LIS2DH configuration
+ *
+ * Returned Value:
+ * Zero (OK) on success; a negated errno value on failure.
+ *
+ ****************************************************************************/
+
+int lis2dh_register(FAR const char *devpath, FAR struct i2c_master_s *i2c,
+ uint8_t addr, FAR struct lis2dh_config_s *config);
+
+#undef EXTERN
+#if defined(__cplusplus)
+}
+#endif
+
+#endif /* __INCLUDE_NUTTX_SENSORS_LIS2DH_H */
diff --git a/include/nuttx/sensors/lps25h.h b/include/nuttx/sensors/lps25h.h
new file mode 100644
index 00000000000..6f30d61cfc4
--- /dev/null
+++ b/include/nuttx/sensors/lps25h.h
@@ -0,0 +1,105 @@
+/****************************************************************************
+ * include/nuttx/sensors/lps25h.h
+ *
+ * Copyright (C) 2014, 2017 Haltian Ltd. All rights reserved.
+ *
+ * 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_NUTT_SENSORS_LPS25H_H
+#define __INCLUDE_NUTT_SENSORS_LPS25H_H
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+#define LPS25H_TEMPER_DIVIDER 1000
+
+#define LPS25H_VALID_WHO_AM_I 0xbd
+
+/****************************************************************************
+ * Public Types
+ ****************************************************************************/
+
+typedef struct lps25h_temper_data_s
+{
+ int32_t int_temper; /* int_temper value must be divided by
+ * LPS25H_TEMPER_DIVIDER in your app code */
+ int16_t raw_data;
+} lps25h_temper_data_t;
+
+typedef struct lps25h_pressure_data_s
+{
+ uint32_t pressure_int_hP;
+ uint32_t pressure_Pa;
+ uint32_t raw_data;
+} lps25h_pressure_data_t;
+
+typedef struct lps25h_who_am_i_data
+{
+ uint8_t who_am_i;
+} lps25h_who_am_i_data;
+
+typedef struct lps25h_config_s
+{
+ /* Device characterization */
+
+ int irq; /* IRQ number received by interrupt handler. */
+
+ /* IRQ/GPIO access callbacks. These operations all hidden behind callbacks
+ * to isolate the driver from differences in GPIO interrupt handling
+ * by varying boards and MCUs.
+ * irq_attach - Attach the interrupt handler to the GPIO interrupt
+ * irq_enable - Enable or disable the GPIO
+ * irq_clear - Acknowledge/clear any pending GPIO interrupt
+ * set_power - Ask board to turn on regulator
+ */
+
+ CODE int (*irq_attach)(FAR struct lps25h_config_s *state, xcpt_t isr,
+ FAR void *arg);
+ CODE void (*irq_enable)(FAR const struct lps25h_config_s *state,
+ bool enable);
+ CODE void (*irq_clear)(FAR const struct lps25h_config_s *state);
+ CODE int (*set_power)(FAR const struct lps25h_config_s *state, bool on);
+} lps25h_config_t;
+
+/****************************************************************************
+ * Public Function Prototypes
+ ****************************************************************************/
+
+int lps25h_register(FAR const char *devpath, FAR struct i2c_master_s *i2c,
+ uint8_t addr, FAR lps25h_config_t *config);
+
+#endif /* __INCLUDE_NUTT_SENSORS_LPS25H_H */
diff --git a/include/nuttx/usb/fusb301.h b/include/nuttx/usb/fusb301.h
new file mode 100644
index 00000000000..deecff2b752
--- /dev/null
+++ b/include/nuttx/usb/fusb301.h
@@ -0,0 +1,243 @@
+/****************************************************************************
+ * include/nuttx/usb/fusb301.h
+ * FUSB301 USB type-C controller driver
+ *
+ * Copyright (C) 2016-2017 Haltian Ltd. All rights reserved.
+ * Authors: Harri Luhtala
+ *
+ * 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_USB_FUSB301_H
+#define __INCLUDE_NUTTX_USB_FUSB301_H
+
+#include
+
+/************************************************************************************
+ * Pre-Processor Declarations
+ ************************************************************************************/
+
+#undef EXTERN
+#if defined(__cplusplus)
+#define EXTERN extern "C"
+extern "C"
+{
+#else
+#define EXTERN extern
+#endif
+
+/************************************************************************************
+ * Pre-processor Definitions
+ ************************************************************************************/
+
+/* IOCTL Commands ***********************************************************/
+
+#define USBCIOC_READ_DEVID _USBCIOC(0x0001) /* Arg: uint8_t* pointer */
+#define USBCIOC_SETUP _USBCIOC(0x0002) /* Arg: uint8_t* pointer */
+#define USBCIOC_SET_MODE _USBCIOC(0x0003) /* Arg: uint8_t value */
+#define USBCIOC_SET_STATE _USBCIOC(0x0004) /* Arg: uint8_t value */
+#define USBCIOC_READ_STATUS _USBCIOC(0x0005) /* Arg: uint8_t* pointer*/
+#define USBCIOC_READ_DEVTYPE _USBCIOC(0x0006) /* Arg: uint8_t* pointer*/
+#define USBCIOC_RESET _USBCIOC(0x0007) /* Arg: None */
+
+/************************************************************************************
+ * Public Types
+ ************************************************************************************/
+
+enum fusb301_reg_address_e
+{
+ FUSB301_DEV_ID_REG = 0x01,
+ FUSB301_MODE_REG,
+ FUSB301_CONTROL_REG,
+ FUSB301_MANUAL_REG,
+ FUSB301_RESET_REG,
+ FUSB301_MASK_REG = 0x10,
+ FUSB301_STATUS_REG,
+ FUSB301_TYPE_REG,
+ FUSB301_INTERRUPT_REG
+};
+
+/* Device ID - 0x01 */
+
+enum fusb301_devid_mask_e
+{
+ DEV_ID_REVISION_MASK = 0x0F,
+ DEV_ID_VERSION_MASK = 0xF0
+};
+
+#define DEV_ID_VER_A 0x10
+#define DEV_ID_REV_C 0x02
+
+/* Modes - 0x02 */
+
+enum fusb301_mode_e
+{
+ MODE_SRC = (1 << 0),
+ MODE_SRC_ACC = (1 << 1),
+ MODE_SNK = (1 << 2),
+ MODE_SNK_ACC = (1 << 3),
+ MODE_DRP = (1 << 4),
+ MODE_DRP_ACC = (1 << 5)
+};
+
+/* Control - 0x03 */
+
+enum fusb301_control_e
+{
+ CONTROL_INT_ENABLE = (0 << 0),
+ CONTROL_INT_DISABLE = (1 << 0),
+ CONTROL_CUR_DISABLED = (0 << 1),
+ CONTROL_CUR_DEFAULT = (1 << 1),
+ CONTROL_CUR_1500 = (2 << 1),
+ CONTROL_CUR_3000 = (3 << 1),
+ CONTROL_TGL_35_15MS = (0 << 4),
+ CONTROL_TGL_30_20MS = (1 << 4),
+ CONTROL_TGL_25_25MS = (2 << 4),
+ CONTROL_TGL_20_30MS = (3 << 4)
+};
+
+/* Manual - 0x04 */
+
+enum fusb301_manual_e
+{
+ MANUAL_ERROR_REC = (1 << 0),
+ MANUAL_DISABLED = (1 << 1),
+ MANUAL_UNATT_SRC = (1 << 2),
+ MANUAL_UNATT_SNK = (1 << 3)
+};
+
+/* Reset - 0x05 */
+
+enum fusb301_reset_e
+{
+ RESET_SW_RES = (1 << 0)
+};
+
+/* Interrupt mask - 0x10 */
+
+enum fusb301_int_mask_e
+{
+ INT_MASK_ATTACK = (1 << 0),
+ INT_MASK_DETACH = (1 << 1),
+ INT_MASK_BC_LVL = (1 << 2),
+ INT_MASK_ACC_CH = (1 << 3)
+};
+
+/* Status - 0x11 */
+
+enum fusb301_status_e
+{
+ STATUS_ATTACH = (1 << 0),
+ STATUS_BC_SINK_UNATT = (0 << 1),
+ STATUS_BC_SINK_DEF = (1 << 1),
+ STATUS_BC_SINK_1500 = (2 << 1),
+ STATUS_BC_SINK_3000 = (3 << 1),
+ STATUS_VBUS_OK = (1 << 3),
+ STATUS_CC_NO_CONN = (0 << 4),
+ STATUS_CC_1 = (1 << 4),
+ STATUS_CC_2 = (2 << 4),
+ STATUS_CC_FAULT = (3 << 4)
+};
+
+/* Type - 0x12 */
+
+enum fusb301_type_e
+{
+ TYPE_AUDIOACC = (1 << 0),
+ TYPE_DEBUGACC = (1 << 1),
+ TYPE_SOURCE = (1 << 3),
+ TYPE_SINK = (1 << 4)
+};
+
+/* Interrupt - 0x13 */
+
+enum fusb301_interrupt_e
+{
+ INTERRUPT_ATTACH = (1 << 0),
+ INTERRUPT_DETACH = (1 << 1),
+ INTERRUPT_BC_LVL = (1 << 2),
+ INTERRUPT_ACC_CH = (1 << 3)
+};
+
+struct fusb301_result_s
+{
+ uint8_t status;
+ uint8_t dev_type;
+};
+
+struct fusb301_setup_s
+{
+ uint8_t drp_toggle_timing;
+ uint8_t host_current;
+ uint8_t int_mask;
+ bool global_int_mask;
+};
+
+struct fusb301_config_s
+{
+ /* Device characterization */
+
+ int irq;
+
+ CODE int (*irq_attach)(FAR struct fusb301_config_s *state, xcpt_t isr,
+ FAR void *arg);
+ CODE void (*irq_enable)(FAR struct fusb301_config_s *state, bool enable);
+ CODE void (*irq_clear)(FAR struct fusb301_config_s *state);
+};
+
+/************************************************************************************
+ * Public Function Prototypes
+ ************************************************************************************/
+
+/****************************************************************************
+ * Name: fusb301_register
+ *
+ * Description:
+ * Register the FUSB301 character device as 'devpath'
+ *
+ * Input Parameters:
+ * devpath - The full path to the driver to register. E.g., "/dev/usbc0"
+ * i2c - An instance of the I2C interface to use to communicate with FUSB301
+ * addr - The I2C address of the FUSB301. The I2C address of the FUSB301 is 0x25.
+ * config - Pointer to FUSB301 configuration
+ *
+ * Returned Value:
+ * Zero (OK) on success; a negated errno value on failure.
+ *
+ ****************************************************************************/
+
+int fusb301_register(FAR const char *devpath, FAR struct i2c_master_s *i2c,
+ uint8_t addr, FAR struct fusb301_config_s *config);
+
+#undef EXTERN
+#if defined(__cplusplus)
+}
+#endif
+
+#endif /* __INCLUDE_NUTTX_USB_FUSB301_H */
diff --git a/net/sixlowpan/sixlowpan_compressor.c b/include/nuttx/wireless/ieee802154/ieee802154_loopback.h
similarity index 74%
rename from net/sixlowpan/sixlowpan_compressor.c
rename to include/nuttx/wireless/ieee802154/ieee802154_loopback.h
index 837bad77602..d1952df24f3 100644
--- a/net/sixlowpan/sixlowpan_compressor.c
+++ b/include/nuttx/wireless/ieee802154/ieee802154_loopback.h
@@ -1,9 +1,12 @@
/****************************************************************************
- * net/sixlowpan/sixlowpan_compressor.c
+ * include/nuttx/net/ieee802154.h
*
- * Copyright (C) 2017 Gregory Nutt. All rights reserved.
+ * Copyright (C) 2016 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt
*
+ * Includes some definitions that a compatible with the LGPL GNU C Library
+ * header file of the same name.
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@@ -33,48 +36,38 @@
*
****************************************************************************/
+#ifndef __INCLUDE_NUTTX_WIRELESS_IEEE802154_IEEE802154_LOOPBACK_H
+#define __INCLUDE_NUTTX_WIRELESS_IEEE802154_IEEE802154_LOOPBACK_H
+
/****************************************************************************
* Included Files
****************************************************************************/
#include
-#include "nuttx/net/net.h"
-#include "nuttx/net/sixlowpan.h"
-
-#include "sixlowpan/sixlowpan_internal.h"
-
-#ifdef CONFIG_NET_6LOWPAN
+#ifdef CONFIG_IEEE802154_LOOPBACK
/****************************************************************************
- * Public Functions
+ * Public Function Prototypes
****************************************************************************/
/****************************************************************************
- * Function: sixlowpan_set_compressor
+ * Function: ieee8021514_loopback
*
* Description:
- * Configure to use the architecture-specific compressor.
+ * Initialize and register the Ieee802.15.4 MAC loopback network driver.
*
- * Input parameters:
- * compressor - A reference to the new compressor to be used. This may
- * be a NULL value to disable the compressor.
+ * Parameters:
+ * None
*
* Returned Value:
- * None
+ * OK on success; Negated errno on failure.
+ *
+ * Assumptions:
*
****************************************************************************/
-void sixlowpan_set_compressor(FAR struct sixlowpan_nhcompressor_s *compressor)
-{
- /* Make sure that the compressor is not in use */
+int ieee8021514_loopback(void);
- net_lock();
-
- /* Then instantiate the new compressor */
-
- g_sixlowpan_compressor = compressor;
- net_unlock();
-}
-
-#endif /* CONFIG_NET_6LOWPAN */
+#endif /* CONFIG_IEEE802154_LOOPBACK */
+#endif /* __INCLUDE_NUTTX_WIRELESS_IEEE802154_IEEE802154_LOOPBACK_H */
diff --git a/libc/netdb/lib_dnscache.c b/libc/netdb/lib_dnscache.c
index 5a95dc9b1b5..30cfdcd577f 100644
--- a/libc/netdb/lib_dnscache.c
+++ b/libc/netdb/lib_dnscache.c
@@ -268,8 +268,8 @@ int dns_find_answer(FAR const char *hostname, FAR struct sockaddr *addr,
/* We have a match. Return the resolved host address */
#ifdef CONFIG_NET_IPv4
- if (entry->addr.addr.sa_family == AF_INET)
#ifdef CONFIG_NET_IPv6
+ if (entry->addr.addr.sa_family == AF_INET)
#endif
{
inlen = sizeof(struct sockaddr_in);
@@ -277,8 +277,8 @@ int dns_find_answer(FAR const char *hostname, FAR struct sockaddr *addr,
#endif
#ifdef CONFIG_NET_IPv6
- else
#ifdef CONFIG_NET_IPv4
+ else
#endif
{
inlen = sizeof(struct sockaddr_in6);
diff --git a/libc/netdb/lib_dnsinit.c b/libc/netdb/lib_dnsinit.c
index 04b490a1675..b6e0f8d0e03 100644
--- a/libc/netdb/lib_dnsinit.c
+++ b/libc/netdb/lib_dnsinit.c
@@ -39,6 +39,7 @@
#include
+#include
#include
#include
#include
diff --git a/net/Kconfig b/net/Kconfig
index 2741c678169..da5eab15d2c 100644
--- a/net/Kconfig
+++ b/net/Kconfig
@@ -123,28 +123,37 @@ config NET_USER_DEVFMT
config NET_ETHERNET
bool "Ethernet support"
- default y if !NET_SLIP
- default n if NET_SLIP
- select NETDEV_MULTINIC if NET_LOOPBACK || NET_SLIP || NET_TUN
- select NET_MULTILINK if NET_LOOPBACK || NET_SLIP || NET_TUN
+ default y
+ select NETDEV_MULTINIC if NET_6LOWPAN || NET_LOOPBACK || NET_SLIP || NET_TUN
+ select NET_MULTILINK if NET_6LOWPAN || NET_LOOPBACK || NET_SLIP || NET_TUN
---help---
If NET_SLIP is not selected, then Ethernet will be used (there is
no need to define anything special in the configuration file to use
Ethernet -- it is the default).
+config NET_6LOWPAN
+ bool "IEEE 802.15.4 6LoWPAN support"
+ default n
+ select NETDEV_MULTINIC if NET_ETHERNET || NET_LOOPBACK || NET_SLIP || NET_TUN
+ select NET_MULTILINK if NET_ETHERNET || NET_LOOPBACK || NET_SLIP || NET_TUN
+ depends on EXPERIMENTAL && NET_IPv6
+ ---help---
+ Enable support for IEEE 802.15.4 Low power Wireless Personal Area
+ Networking (6LoWPAN).
+
config NET_LOOPBACK
bool "Local loopback"
default n
- select NETDEV_MULTINIC if NET_ETHERNET || NET_SLIP || NET_TUN
- select NET_MULTILINK if NET_ETHERNET || NET_SLIP || NET_TUN
+ select NETDEV_MULTINIC if NET_ETHERNET || NET_6LOWPAN || NET_SLIP || NET_TUN
+ select NET_MULTILINK if NET_ETHERNET || NET_6LOWPAN || NET_SLIP || NET_TUN
---help---
Add support for the local network loopback device, lo.
config NET_SLIP
bool "SLIP support"
default n
- select NETDEV_MULTINIC if NET_ETHERNET || NET_LOOPBACK || NET_TUN
- select NET_MULTILINK if NET_ETHERNET || NET_LOOPBACK || NET_TUN
+ select NETDEV_MULTINIC if NET_ETHERNET || NET_6LOWPAN || NET_LOOPBACK || NET_TUN
+ select NET_MULTILINK if NET_ETHERNET || NET_6LOWPAN || NET_LOOPBACK || NET_TUN
---help---
Enables building of the SLIP driver. SLIP requires
at least one IP protocol selected.
@@ -190,8 +199,8 @@ endif # NET_SLIP
config NET_TUN
bool "TUN Virtual Network Device support"
default n
- select NETDEV_MULTINIC if NET_ETHERNET || NET_LOOPBACK || NET_SLIP
- select NET_MULTILINK if NET_ETHERNET || NET_LOOPBACK || NET_SLIP
+ select NETDEV_MULTINIC if NET_ETHERNET || NET_6LOWPAN || NET_LOOPBACK || NET_SLIP
+ select NET_MULTILINK if NET_ETHERNET || NET_6LOWPAN || NET_LOOPBACK || NET_SLIP
select ARCH_HAVE_NETDEV_STATISTICS
if NET_TUN
@@ -236,6 +245,23 @@ config TUN_LPWORK
endchoice # Work queue
endif # NET_TUN
+config NET_USRSOCK
+ bool "User-space networking stack API"
+ default n
+ ---help---
+ Enable or disable user-space networking stack support.
+
+ User-space networking stack API allows user-space daemon to
+ provide TCP/IP stack implementation for NuttX network.
+
+ Main use for this is to allow use and integration of
+ HW-provided TCP/IP stacks for NuttX.
+
+ For example, user-space daemon can translate /dev/usrsock API
+ requests to HW TCP/IP API requests while rest of the user-space
+ can access standard socket API, with socket descriptors that
+ can be used with NuttX system calls.
+
endmenu # Data link support
source "net/netdev/Kconfig"
@@ -271,6 +297,7 @@ source "net/arp/Kconfig"
source "net/loopback/Kconfig"
source "net/iob/Kconfig"
source "net/procfs/Kconfig"
+source "net/usrsock/Kconfig"
source "net/utils/Kconfig"
config NET_STATISTICS
diff --git a/net/Makefile b/net/Makefile
index 6898bad40e1..cd6979a4145 100644
--- a/net/Makefile
+++ b/net/Makefile
@@ -72,6 +72,7 @@ include devif/Make.defs
include loopback/Make.defs
include route/Make.defs
include procfs/Make.defs
+include usrsock/Make.defs
include utils/Make.defs
endif
diff --git a/net/README.txt b/net/README.txt
index 0f93c075813..e87a0889b51 100644
--- a/net/README.txt
+++ b/net/README.txt
@@ -22,21 +22,25 @@ Directory Structure
+- route - Routing table support
+- tcp - Transmission Control Protocol
+- udp - User Datagram Protocol
+ +- usrsock - User socket API for user-space networking stack
`- utils - Miscellaneous utility functions
- +----------------------------------------------------------------+
- | Application layer |
- +----------------------------------------------------------------+
- +----------------------------------------------------------------+
- | Socket layer (socket/) |
- +----------------------------------------------------------------+
- +------------++--------------------------------------------------+
- | Network || Protocol stacks (arp, ipv6, icmp, pkt, tcp, udp) |
- | Device |+--------------------------------------------------+
- | Interface |+------------------------------------++------------+
- | (netdev/) || Network Device Interface (devif/) || Utilities |
- +------------++------------------------------------++------------+
- +----------------------------------------------------------------+
- | Network Device Drivers |
- +----------------------------------------------------------------+
+ +-------------------------------------------------------------------++------------------------+
+ | Application layer || usrsock daemon |
+ +-------------------------------------------------------------------++------------------------+
+ +-------------------------------------------------------------------++----------------+ +-----+
+ | Socket layer (socket/) || /dev/usrsock | | |
+ +-------------------------------------------------------------------++----------------+ | |
+ +------------++--------------------------------------------------++-------------------+ | |
+ | Network || Protocol stacks (arp, ipv6, icmp, pkt, tcp, udp) || usrsock/ | | |
+ | Device |+--------------------------------------------------++-------------------+ | |
+ | Interface |+------------------------------------++---------------------------------+ | |
+ | (netdev/) || Network Device Interface (devif/) || Utilities | | |
+ +------------++------------------------------------++---------------------------------+ | |
+ +----------------------------------------------------------------+ | |
+ | Network Device Drivers | | HAL |
+ +----------------------------------------------------------------+ +-----+
+ +----------------------------------------------------------------+ +--------------------------+
+ | Networking Hardware | | Hardware TCP/IP Stack |
+ +----------------------------------------------------------------+ +--------------------------+
\ No newline at end of file
diff --git a/net/devif/devif.h b/net/devif/devif.h
index bca09878968..28135f4d30f 100644
--- a/net/devif/devif.h
+++ b/net/devif/devif.h
@@ -1,7 +1,7 @@
/****************************************************************************
* net/devif/devif.h
*
- * Copyright (C) 2007-2009, 2013-2016 Gregory Nutt. All rights reserved.
+ * Copyright (C) 2007-2009, 2013-2017 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt
*
* This logic was leveraged from uIP which also has a BSD-style license:
@@ -170,11 +170,13 @@
#define TCP_NEWDATA (1 << 1)
#define UDP_NEWDATA TCP_NEWDATA
#define PKT_NEWDATA TCP_NEWDATA
+#define WPAN_NEWDATA TCP_NEWDATA
#define TCP_SNDACK (1 << 2)
#define TCP_REXMIT (1 << 3)
#define TCP_POLL (1 << 4)
#define UDP_POLL TCP_POLL
#define PKT_POLL TCP_POLL
+#define WPAN_POLL TCP_POLL
#define TCP_BACKLOG (1 << 5)
#define TCP_CLOSE (1 << 6)
#define TCP_ABORT (1 << 7)
@@ -234,12 +236,17 @@
*/
struct net_driver_s; /* Forward reference */
+
+typedef CODE uint16_t (*devif_callback_event_t)(FAR struct net_driver_s *dev,
+ FAR void *pvconn,
+ FAR void *pvpriv,
+ uint16_t flags);
+
struct devif_callback_s
{
FAR struct devif_callback_s *nxtconn;
FAR struct devif_callback_s *nxtdev;
- uint16_t (*event)(FAR struct net_driver_s *dev, FAR void *pvconn,
- FAR void *pvpriv, uint16_t flags);
+ FAR devif_callback_event_t event;
FAR void *priv;
uint16_t flags;
};
diff --git a/net/devif/devif_poll.c b/net/devif/devif_poll.c
index 928b779fb38..235c58bcf28 100644
--- a/net/devif/devif_poll.c
+++ b/net/devif/devif_poll.c
@@ -45,6 +45,7 @@
#include
#include
#include
+#include
#include "devif/devif.h"
#include "arp/arp.h"
@@ -55,6 +56,21 @@
#include "icmp/icmp.h"
#include "icmpv6/icmpv6.h"
#include "igmp/igmp.h"
+#include "sixlowpan/sixlowpan.h"
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+enum devif_packet_type
+{
+ DEVIF_PKT = 0,
+ DEVIF_ICMP,
+ DEVIF_IGMP,
+ DEVIF_TCP,
+ DEVIF_UDP,
+ DEVIF_ICMP6
+};
/****************************************************************************
* Public Data
@@ -68,6 +84,78 @@ systime_t g_polltime;
* Private Functions
****************************************************************************/
+/****************************************************************************
+ * Function: devif_packet_conversion
+ *
+ * Description:
+ * Generic output conversion hook. Only needed for IEEE802.15.4 for now
+ * is a point where support for other conversions may be provided.
+ *
+ * TCP output comes through three different mechansims. Either from:
+ *
+ * 1. TCP socket output. For the case of TCP output to an
+ * IEEE802.15.4, the TCP output is caught in the socket
+ * send()/sendto() logic and and redirected to 6loWPAN logic.
+ * 2. TCP output from the TCP state machine. That will occur
+ * during TCP packet processing by the TCP state meachine.
+ * 3. TCP output resulting from TX or timer polling
+ *
+ * Cases 2 is handled here. Logic here detected if (1) an attempt
+ * to return with d_len > 0 and (2) that the device is an
+ * IEEE802.15.4 MAC network driver. Under those conditions, 6loWPAN
+ * logic will be called to create the IEEE80215.4 frames.
+ *
+ * Assumptions:
+ * The network is locked.
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_NET_6LOWPAN
+static void devif_packet_conversion(FAR struct net_driver_s *dev,
+ enum devif_packet_type pkttype)
+{
+#ifdef CONFIG_NET_MULTILINK
+ /* Handle the case where multiple link layer protocols are supported */
+
+ if (dev->d_len > 0 && dev->d_lltype == NET_LL_IEEE802154)
+#else
+ if (dev->d_len > 0)
+#endif
+ {
+ if (pkttype == DEVIF_TCP)
+ {
+ FAR struct ipv6_hdr_s *ipv6 = (FAR struct ipv6_hdr_s *)dev->d_buf;
+
+ /* This packet came from a response to TCP polling and is directed
+ * to an IEEE802.15.4 device using 6loWPAN. Verify that the outgoing
+ * packet is IPv6 with TCP protocol.
+ */
+
+ if (ipv6->vtc == IPv6_VERSION && ipv6->proto == IP_PROTO_TCP)
+ {
+ /* Let 6loWPAN convert IPv6 TCP output into IEEE802.15.4 frames. */
+
+ sixlowpan_tcp_send(dev);
+ }
+ else
+ {
+ nerr("ERROR: IPv6 version or protocol error. Packet dropped\n");
+ nerr(" IP version: %02x proocol: %u\n",
+ ipv6->vtc, ipv6->proto);
+ }
+ }
+ else
+ {
+ nerr("ERROR: Non-TCP packet dropped. Packet type: %u\n", pkttype);
+ }
+
+ dev->d_len = 0;
+ }
+}
+#else
+# define devif_packet_conversion(dev,pkttype)
+#endif /* CONFIG_NET_6LOWPAN */
+
/****************************************************************************
* Function: devif_poll_pkt_connections
*
@@ -95,6 +183,10 @@ static int devif_poll_pkt_connections(FAR struct net_driver_s *dev,
pkt_poll(dev, pkt_conn);
+ /* Perform any necessary conversions on outgoing packets */
+
+ devif_packet_conversion(dev, DEVIF_PKT);
+
/* Call back into the driver */
bstop = callback(dev);
@@ -120,6 +212,10 @@ static inline int devif_poll_icmp(FAR struct net_driver_s *dev,
icmp_poll(dev);
+ /* Perform any necessary conversions on outgoing packets */
+
+ devif_packet_conversion(dev, DEVIF_ICMP);
+
/* Call back into the driver */
return callback(dev);
@@ -142,6 +238,10 @@ static inline int devif_poll_icmpv6(FAR struct net_driver_s *dev,
icmpv6_poll(dev);
+ /* Perform any necessary conversions on outgoing packets */
+
+ devif_packet_conversion(dev, DEVIF_ICMP6);
+
/* Call back into the driver */
return callback(dev);
@@ -168,6 +268,10 @@ static inline int devif_poll_igmp(FAR struct net_driver_s *dev,
igmp_poll(dev);
+ /* Perform any necessary conversions on outgoing packets */
+
+ devif_packet_conversion(dev, DEVIF_IGMP);
+
/* Call back into the driver */
return callback(dev);
@@ -186,7 +290,7 @@ static inline int devif_poll_igmp(FAR struct net_driver_s *dev,
*
****************************************************************************/
-#ifdef CONFIG_NET_UDP
+#ifdef NET_UDP_HAVE_STACK
static int devif_poll_udp_connections(FAR struct net_driver_s *dev,
devif_poll_callback_t callback)
{
@@ -201,6 +305,10 @@ static int devif_poll_udp_connections(FAR struct net_driver_s *dev,
udp_poll(dev, conn);
+ /* Perform any necessary conversions on outgoing packets */
+
+ devif_packet_conversion(dev, DEVIF_UDP);
+
/* Call back into the driver */
bstop = callback(dev);
@@ -208,7 +316,7 @@ static int devif_poll_udp_connections(FAR struct net_driver_s *dev,
return bstop;
}
-#endif /* CONFIG_NET_UDP */
+#endif /* NET_UDP_HAVE_STACK */
/****************************************************************************
* Function: devif_poll_tcp_connections
@@ -222,7 +330,7 @@ static int devif_poll_udp_connections(FAR struct net_driver_s *dev,
*
****************************************************************************/
-#ifdef CONFIG_NET_TCP
+#ifdef NET_TCP_HAVE_STACK
static inline int devif_poll_tcp_connections(FAR struct net_driver_s *dev,
devif_poll_callback_t callback)
{
@@ -237,6 +345,10 @@ static inline int devif_poll_tcp_connections(FAR struct net_driver_s *dev,
tcp_poll(dev, conn);
+ /* Perform any necessary conversions on outgoing packets */
+
+ devif_packet_conversion(dev, DEVIF_TCP);
+
/* Call back into the driver */
bstop = callback(dev);
@@ -261,7 +373,7 @@ static inline int devif_poll_tcp_connections(FAR struct net_driver_s *dev,
*
****************************************************************************/
-#ifdef CONFIG_NET_TCP
+#ifdef NET_TCP_HAVE_STACK
static inline int devif_poll_tcp_timer(FAR struct net_driver_s *dev,
devif_poll_callback_t callback,
int hsec)
@@ -277,6 +389,10 @@ static inline int devif_poll_tcp_timer(FAR struct net_driver_s *dev,
tcp_timer(dev, conn, hsec);
+ /* Perform any necessary conversions on outgoing packets */
+
+ devif_packet_conversion(dev, DEVIF_TCP);
+
/* Call back into the driver */
bstop = callback(dev);
@@ -349,7 +465,7 @@ int devif_poll(FAR struct net_driver_s *dev, devif_poll_callback_t callback)
if (!bstop)
#endif
-#ifdef CONFIG_NET_TCP
+#ifdef NET_TCP_HAVE_STACK
{
/* Traverse all of the active TCP connections and perform the poll
* action.
@@ -360,7 +476,7 @@ int devif_poll(FAR struct net_driver_s *dev, devif_poll_callback_t callback)
if (!bstop)
#endif
-#ifdef CONFIG_NET_UDP
+#ifdef NET_UDP_HAVE_STACK
{
/* Traverse all of the allocated UDP connections and perform
* the poll action
@@ -467,7 +583,7 @@ int devif_timer(FAR struct net_driver_s *dev, devif_poll_callback_t callback)
neighbor_periodic(hsec);
#endif
-#ifdef CONFIG_NET_TCP
+#ifdef NET_TCP_HAVE_STACK
/* Traverse all of the active TCP connections and perform the
* timer action.
*/
diff --git a/net/devif/ipv4_input.c b/net/devif/ipv4_input.c
index 5a773b1ef8d..faa23ad547d 100644
--- a/net/devif/ipv4_input.c
+++ b/net/devif/ipv4_input.c
@@ -391,7 +391,7 @@ int ipv4_input(FAR struct net_driver_s *dev)
#endif /* CONFIG_NET_TCP_REASSEMBLY */
}
-#if defined(CONFIG_NET_BROADCAST) && defined(CONFIG_NET_UDP)
+#if defined(CONFIG_NET_BROADCAST) && defined(NET_UDP_HAVE_STACK)
/* If IP broadcast support is configured, we check for a broadcast
* UDP packet, which may be destined to us (even if there is no IP
* address yet assigned to the device as is the case when we are
@@ -459,13 +459,13 @@ int ipv4_input(FAR struct net_driver_s *dev)
switch (pbuf->proto)
{
-#ifdef CONFIG_NET_TCP
+#ifdef NET_TCP_HAVE_STACK
case IP_PROTO_TCP: /* TCP input */
tcp_ipv4_input(dev);
break;
#endif
-#ifdef CONFIG_NET_UDP
+#ifdef NET_UDP_HAVE_STACK
case IP_PROTO_UDP: /* UDP input */
udp_ipv4_input(dev);
break;
diff --git a/net/devif/ipv6_input.c b/net/devif/ipv6_input.c
index 08166306798..24be107a47d 100644
--- a/net/devif/ipv6_input.c
+++ b/net/devif/ipv6_input.c
@@ -95,6 +95,7 @@
#include "neighbor/neighbor.h"
#include "tcp/tcp.h"
#include "udp/udp.h"
+#include "sixlowpan/sixlowpan.h"
#include "pkt/pkt.h"
#include "icmpv6/icmpv6.h"
@@ -197,7 +198,7 @@ int ipv6_input(FAR struct net_driver_s *dev)
* negotiating over DHCP for an address).
*/
-#if defined(CONFIG_NET_BROADCAST) && defined(CONFIG_NET_UDP)
+#if defined(CONFIG_NET_BROADCAST) && defined(NET_UDP_HAVE_STACK)
if (ipv6->proto == IP_PROTO_UDP &&
net_ipv6addr_cmp(ipv6->destipaddr, g_ipv6_alloneaddr))
{
@@ -253,14 +254,52 @@ int ipv6_input(FAR struct net_driver_s *dev)
switch (ipv6->proto)
{
-#ifdef CONFIG_NET_TCP
+#ifdef NET_TCP_HAVE_STACK
case IP_PROTO_TCP: /* TCP input */
- tcp_ipv6_input(dev);
- break;
-#endif
+ /* Forward the IPv6 TCP packet */
-#ifdef CONFIG_NET_UDP
+ tcp_ipv6_input(dev);
+
+#ifdef CONFIG_NET_6LOWPAN
+ /* TCP output comes through three different mechansims. Either from:
+ *
+ * 1. TCP socket output. For the case of TCP output to an
+ * IEEE802.15.4, the TCP output is caught in the socket
+ * send()/sendto() logic and and redirected to 6loWPAN logic.
+ * 2. TCP output from the TCP state machine. That will occur
+ * during TCP packet processing by the TCP state meachine.
+ * 3. TCP output resulting from TX or timer polling
+ *
+ * Cases 2 is handled here. Logic here detected if (1) an attempt
+ * to return with d_len > 0 and (2) that the device is an
+ * IEEE802.15.4 MAC network driver. Under those conditions, 6loWPAN
+ * logic will be called to create the IEEE80215.4 frames.
+ */
+
+#ifdef CONFIG_NET_MULTILINK
+ /* Handle the case where multiple link layer protocols are supported */
+
+ if (dev->d_len > 0 && dev->d_lltype == CONFIG_NET_6LOWPAN)
+#else
+ if (dev->d_len > 0)
+#endif
+ {
+ /* Let 6loWPAN handle the TCP output */
+
+ sixlowpan_tcp_send(dev);
+
+ /* Drop the packet in the d_buf */
+
+ goto drop;
+ }
+#endif /* CONFIG_NET_6LOWPAN */
+ break;
+#endif /* NET_TCP_HAVE_STACK */
+
+#ifdef NET_UDP_HAVE_STACK
case IP_PROTO_UDP: /* UDP input */
+ /* Forward the IPv6 UDP packet */
+
udp_ipv6_input(dev);
break;
#endif
@@ -269,6 +308,8 @@ int ipv6_input(FAR struct net_driver_s *dev)
#ifdef CONFIG_NET_ICMPv6
case IP_PROTO_ICMP6: /* ICMP6 input */
+ /* Forward the ICMPv6 packet */
+
icmpv6_input(dev);
break;
#endif
diff --git a/net/neighbor/Make.defs b/net/neighbor/Make.defs
index cf13cbb732a..7f6b56244ec 100644
--- a/net/neighbor/Make.defs
+++ b/net/neighbor/Make.defs
@@ -39,7 +39,16 @@ ifeq ($(CONFIG_NET_IPv6),y)
NET_CSRCS += neighbor_initialize.c neighbor_add.c neighbor_lookup.c
NET_CSRCS += neighbor_update.c neighbor_periodic.c neighbor_findentry.c
-NET_CSRCS += neighbor_out.c
+
+# Link layer specific support
+
+ifeq ($(CONFIG_NET_ETHERNET),y)
+NET_CSRCS += neighbor_ethernet_out.c
+endif
+
+ifeq ($(CONFIG_NET_6LOWPAN),y)
+# NET_CSRCS += neighbor_6lowpan_out.c
+endif
# Include utility build support
diff --git a/net/neighbor/neighbor_out.c b/net/neighbor/neighbor_ethernet_out.c
similarity index 98%
rename from net/neighbor/neighbor_out.c
rename to net/neighbor/neighbor_ethernet_out.c
index 4725a90ea27..ddd9a3a5ffd 100644
--- a/net/neighbor/neighbor_out.c
+++ b/net/neighbor/neighbor_ethernet_out.c
@@ -1,7 +1,7 @@
/****************************************************************************
- * net/neighbor/neighbor_out.c
+ * net/neighbor/neighbor_ethernet_out.c
*
- * Copyright (C) 2015 Gregory Nutt. All rights reserved.
+ * Copyright (C) 2015, 2017 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt
*
* Redistribution and use in source and binary forms, with or without
diff --git a/net/net_initialize.c b/net/net_initialize.c
index 988faf6b547..3edbd6849b2 100644
--- a/net/net_initialize.c
+++ b/net/net_initialize.c
@@ -57,6 +57,7 @@
#include "local/local.h"
#include "igmp/igmp.h"
#include "route/route.h"
+#include "usrsock/usrsock.h"
#include "utils/utils.h"
/****************************************************************************
@@ -130,7 +131,7 @@ void net_setup(void)
local_initialize();
#endif
-#ifdef CONFIG_NET_TCP
+#ifdef NET_TCP_HAVE_STACK
/* Initialize the listening port structures */
tcp_listen_initialize();
@@ -146,7 +147,7 @@ void net_setup(void)
#endif
#endif /* CONFIG_NET_TCP */
-#ifdef CONFIG_NET_UDP
+#ifdef NET_UDP_HAVE_STACK
/* Initialize the UDP connection structures */
udp_initialize();
@@ -163,6 +164,12 @@ void net_setup(void)
net_initroute();
#endif
+
+#ifdef CONFIG_NET_USRSOCK
+ /* Initialize the user-space socket API */
+
+ usrsock_initialize();
+#endif
}
/****************************************************************************
diff --git a/net/procfs/netdev_statistics.c b/net/procfs/netdev_statistics.c
index 80154c91faa..d7673507b73 100644
--- a/net/procfs/netdev_statistics.c
+++ b/net/procfs/netdev_statistics.c
@@ -1,7 +1,7 @@
/****************************************************************************
* net/procfs/netdev_statistics.c
*
- * Copyright (C) 2015 Gregory Nutt. All rights reserved.
+ * Copyright (C) 2015, 2017 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt
*
* Redistribution and use in source and binary forms, with or without
@@ -47,6 +47,7 @@
#include
#include
+#include
#include "netdev/netdev.h"
#include "utils/utils.h"
@@ -106,6 +107,9 @@ static const linegen_t g_linegen[] =
static int netprocfs_linklayer(FAR struct netprocfs_file_s *netfile)
{
FAR struct net_driver_s *dev;
+#ifdef CONFIG_NET_6LOWPAN
+ FAR struct ieee802154_driver_s *ieee;
+#endif
FAR const char *status;
int len = 0;
@@ -142,6 +146,30 @@ static int netprocfs_linklayer(FAR struct netprocfs_file_s *netfile)
break;
#endif
+#ifdef CONFIG_NET_6LOWPAN
+ case NET_LL_IEEE802154:
+ {
+ ieee = (FAR struct ieee802154_driver_s *)dev;
+
+#if CONFIG_NET_6LOWPAN_RIMEADDR_SIZE == 2
+ len += snprintf(&netfile->line[len], NET_LINELEN - len,
+ "%s\tLink encap:6loWPAN HWaddr %02x:%02x",
+ dev->d_ifname,
+ ieee->i_nodeaddr.u8[0], ieee->i_nodeaddr.u8[1]);
+#else /* CONFIG_NET_6LOWPAN_RIMEADDR_SIZE == 8 */
+ len += snprintf(&netfile->line[len], NET_LINELEN - len,
+ "%s\tLink encap:6loWPAN HWaddr "
+ "%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x",
+ dev->d_ifname,
+ ieee->i_nodeaddr.u8[0], ieee->i_nodeaddr.u8[1],
+ ieee->i_nodeaddr.u8[2], ieee->i_nodeaddr.u8[3],
+ ieee->i_nodeaddr.u8[4], ieee->i_nodeaddr.u8[5],
+ ieee->i_nodeaddr.u8[6], ieee->i_nodeaddr.u8[7]);
+#endif
+ }
+ break;
+#endif
+
#ifdef CONFIG_NET_LOOPBACK
case NET_LL_LOOPBACK:
len += snprintf(&netfile->line[len], NET_LINELEN - len,
@@ -184,6 +212,26 @@ static int netprocfs_linklayer(FAR struct netprocfs_file_s *netfile)
"%s\tLink encap:Ethernet HWaddr %s at %s\n",
dev->d_ifname, ether_ntoa(&dev->d_mac), status);
+#elif defined(CONFIG_NET_6LOWPAN)
+ ieee = (FAR struct ieee802154_driver_s *)dev;
+
+#if CONFIG_NET_6LOWPAN_RIMEADDR_SIZE == 2
+ len += snprintf(&netfile->line[len], NET_LINELEN - len,
+ "%s\tLink encap:6loWPAN HWaddr %02x:%02x at %s",
+ dev->d_ifname,
+ ieee->i_nodeaddr.u8[0], ieee->i_nodeaddr.u8[1],
+ status);
+#else /* CONFIG_NET_6LOWPAN_RIMEADDR_SIZE == 8 */
+ len += snprintf(&netfile->line[len], NET_LINELEN - len,
+ "%s\tLink encap:6loWPAN HWaddr "
+ "%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x at %s",
+ dev->d_ifname,
+ ieee->i_nodeaddr.u8[0], ieee->i_nodeaddr.u8[1],
+ ieee->i_nodeaddr.u8[2], ieee->i_nodeaddr.u8[3],
+ ieee->i_nodeaddr.u8[4], ieee->i_nodeaddr.u8[5],
+ ieee->i_nodeaddr.u8[6], ieee->i_nodeaddr.u8[7],
+ status);
+#endif
#elif defined(CONFIG_NET_LOOPBACK)
len += snprintf(&netfile->line[len], NET_LINELEN - len,
"%s\tLink encap:Local Loopback at %s\n",
diff --git a/net/sixlowpan/Kconfig b/net/sixlowpan/Kconfig
index 406a5e8d34d..02d17a42f1c 100644
--- a/net/sixlowpan/Kconfig
+++ b/net/sixlowpan/Kconfig
@@ -3,15 +3,8 @@
# see the file kconfig-language.txt in the NuttX tools repository.
#
-menuconfig NET_6LOWPAN
- bool "IEEE 802.15.4 6LoWPAN support"
- default n
- depends on EXPERIMENTAL && NET_IPv6
- ---help---
- Enable support for IEEE 802.15.4 Low power Wireless Personal Area
- Networking (6LoWPAN).
-
-if NET_6LOWPAN
+menu "6LoWPAN Configuration"
+ depends on NET_6LOWPAN
config NET_6LOWPAN_FRAG
bool "6loWPAN Fragmentation"
@@ -59,6 +52,17 @@ config NET_6LOWPAN_COMPRESSION_THRESHOLD
CONFIG_NET_6LOWPAN_COMPRESSION_THRESHOLD sets a lower threshold for
when packets should not be compressed.
+config NET_6LOWPAN_MINPORT
+ hex "Minimum port nubmer"
+ default 0xf0b0
+ depends on NET_6LOWPAN_COMPRESSION_HC1
+ ---help---
+ HC1 compression of UDP headersis feasible only if both src and dest
+ ports are between CONFIG_NET_6LOWPAN_MINPORT and
+ CONFIG_NET_6LOWPAN_MINPORT + 15, inclusive.
+
+ All nodes must agree on the value of CONFIG_NET_6LOWPAN_MINPORT
+
if NET_6LOWPAN_COMPRESSION_HC06
config NET_6LOWPAN_MAXADDRCONTEXT
@@ -140,7 +144,8 @@ config NET_6LOWPAN_MAXAGE
int "Packet reassembly timeout"
default 20
---help---
- Timeout for packet reassembly at the 6lowpan layer (should be < 60s)
+ Timeout for packet reassembly at the 6lowpan layer in units of
+ seconds (should be < 60s)
config NET_6LOWPAN_MAX_MACTRANSMITS
int "Max MAC transmissions"
@@ -186,10 +191,13 @@ config NET_6LOWPAN_TCP_RECVWNDO
the application is slow to process incoming data, or high (32768
bytes) if the application processes data quickly.
-config NET_6LOWPAN_SNIFFER
+config NET_6LOWPAN_DUMPBUFFER
+ bool "Enable dumping of buffer data"
default n
+ depends on DEBUG_NET_INFO
---help---
- Enable use use an architecture-specific sniffer to support tracing
- of IP.
+ Enable dumping of all packet and frame buffers coming into and out
+ of the 6loWPAN logic. This will generate a large volume of data if
+ selected.
-endif # NET_6LOWPAN
+endmenu # 6LoWPAN Configuration
diff --git a/net/sixlowpan/Make.defs b/net/sixlowpan/Make.defs
index e0370185e68..d1faae0eacc 100644
--- a/net/sixlowpan/Make.defs
+++ b/net/sixlowpan/Make.defs
@@ -1,7 +1,7 @@
############################################################################
# net/sixlowpan/Make.defs
#
-# Copyright (C) 2016 Gregory Nutt. All rights reserved.
+# Copyright (C) 2017 Gregory Nutt. All rights reserved.
# Author: Gregory Nutt
#
# Redistribution and use in source and binary forms, with or without
@@ -41,7 +41,7 @@ ifeq ($(CONFIG_NET_6LOWPAN),y)
NET_CSRCS += sixlowpan_initialize.c sixlowpan_globals.c sixlowpan_utils.c
NET_CSRCS += sixlowpan_input.c sixlowpan_send.c sixlowpan_framer.c
-NET_CSRCS += sixlowpan_compressor.c
+NET_CSRCS += sixlowpan_framelist.c
ifeq ($(CONFIG_NET_TCP),y)
NET_CSRCS += sixlowpan_tcpsend.c
@@ -59,10 +59,6 @@ ifeq ($(CONFIG_NET_6LOWPAN_COMPRESSION_HC06),y)
NET_CSRCS += sixlowpan_hc06.c
endif
-ifeq ($(CONFIG_NET_6LOWPAN_SNIFFER),y)
-NET_CSRCS += sixlowpan_sniffer.c
-endif
-
# Include the sixlowpan directory in the build
DEPPATH += --dep-path sixlowpan
diff --git a/net/sixlowpan/sixlowpan.h b/net/sixlowpan/sixlowpan.h
index d3660cb2ceb..05ce9496c9c 100644
--- a/net/sixlowpan/sixlowpan.h
+++ b/net/sixlowpan/sixlowpan.h
@@ -53,7 +53,9 @@
* Public Function Prototypes
****************************************************************************/
-struct socket; /* Forward reference */
+struct net_driver_s; /* Forward reference */
+struct socket; /* Forward reference */
+struct sockaddr; /* Forward reference */
/****************************************************************************
* Name: sixlowpan_initialize
@@ -104,6 +106,38 @@ ssize_t psock_6lowpan_tcp_send(FAR struct socket *psock, FAR const void *buf,
size_t len);
#endif
+/****************************************************************************
+ * Function: sixlowpan_tcp_send
+ *
+ * Description:
+ * TCP output comes through three different mechansims. Either from:
+ *
+ * 1. TCP socket output. For the case of TCP output to an
+ * IEEE802.15.4, the TCP output is caught in the socket
+ * send()/sendto() logic and and redirected to psock_6lowpan_tcp_send().
+ * 2. TCP output from the TCP state machine. That will occur
+ * during TCP packet processing by the TCP state meachine.
+ * 3. TCP output resulting from TX or timer polling
+ *
+ * Cases 2 and 3 will be handled here. Logic in ipv6_tcp_input(),
+ * devif_poll(), and devif_timer() detect if (1) an attempt to return with
+ * d_len > 0 and (2) that the device is an IEEE802.15.4 MAC network
+ * driver. Under those conditions, this function will be called to create
+ * the IEEE80215.4 frames.
+ *
+ * Parameters:
+ * dev - An instance of nework device state structure
+ *
+ * Returned Value:
+ * None
+ *
+ * Assumptions:
+ * Called with the network locked.
+ *
+ ****************************************************************************/
+
+void sixlowpan_tcp_send(FAR struct net_driver_s *dev);
+
/****************************************************************************
* Function: psock_6lowpan_udp_send
*
@@ -132,5 +166,39 @@ ssize_t psock_6lowpan_udp_send(FAR struct socket *psock, FAR const void *buf,
size_t len);
#endif
+/****************************************************************************
+ * Function: psock_6lowpan_udp_sendto
+ *
+ * Description:
+ * If sendto() is used on a connection-mode (SOCK_STREAM, SOCK_SEQPACKET)
+ * socket, the parameters to and 'tolen' are ignored (and the error EISCONN
+ * may be returned when they are not NULL and 0), and the error ENOTCONN is
+ * returned when the socket was not actually connected.
+ *
+ * Parameters:
+ * psock A pointer to a NuttX-specific, internal socket structure
+ * buf Data to send
+ * len Length of data to send
+ * flags Send flags
+ * to Address of recipient
+ * tolen The length of the address structure
+ *
+ * Returned Value:
+ * On success, returns the number of characters sent. On error,
+ * -1 is returned, and errno is set appropriately. Returned error
+ * number must be consistent with definition of errors reported by
+ * sendto().
+ *
+ * Assumptions:
+ * Called with the network locked.
+ *
+ ****************************************************************************/
+
+ssize_t psock_6lowpan_udp_sendto(FAR struct socket *psock,
+ FAR const void *buf,
+ size_t len, int flags,
+ FAR const struct sockaddr *to,
+ socklen_t tolen);
+
#endif /* CONFIG_NET_6LOWPAN */
#endif /* _NET_SIXLOWPAN_SIXLOWPAN_H */
diff --git a/net/sixlowpan/sixlowpan_framelist.c b/net/sixlowpan/sixlowpan_framelist.c
new file mode 100644
index 00000000000..bd4dd2e8eb6
--- /dev/null
+++ b/net/sixlowpan/sixlowpan_framelist.c
@@ -0,0 +1,477 @@
+/****************************************************************************
+ * net/sixlowpan/sixlowpan_framelist.c
+ *
+ * Copyright (C) 2017 Gregory Nutt. All rights reserved.
+ * Author: Gregory Nutt
+ *
+ * Parts of this file derive from Contiki:
+ *
+ * Copyright (c) 2008, Swedish Institute of Computer Science.
+ * All rights reserved.
+ * Authors: Adam Dunkels
+ * Nicolas Tsiftes
+ * Niclas Finne
+ * Mathilde Durvy
+ * Julien Abeille
+ * Joakim Eriksson
+ * Joel Hoglund
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the Institute nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include
+
+#include
+#include
+#include
+#include
+
+#include
+
+#include "sixlowpan/sixlowpan_internal.h"
+
+#ifdef CONFIG_NET_6LOWPAN
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/* Configuration ************************************************************/
+
+/* A single IOB must be big enough to hold a full frame */
+
+#if CONFIG_IOB_BUFSIZE < CONFIG_NET_6LOWPAN_FRAMELEN
+# error IOBs must be large enough to hold full IEEE802.14.5 frame
+#endif
+
+/* There must be at least enough IOBs to hold the full MTU. Probably still
+ * won't work unless there are a few more.
+ */
+
+#if CONFIG_NET_6LOWPAN_MTU > (CONFIG_IOB_BUFSIZE * CONFIG_IOB_NBUFFERS)
+# error Not enough IOBs to hold one full IEEE802.14.5 packet
+#endif
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: sixlowpan_compress_ipv6hdr
+ *
+ * Description:
+ * IPv6 dispatch "compression" function. Packets "Compression" when only
+ * IPv6 dispatch is used
+ *
+ * There is no compression in this case, all fields are sent
+ * inline. We just add the IPv6 dispatch byte before the packet.
+ *
+ * 0 1 2 3
+ * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | IPv6 Dsp | IPv6 header and payload ...
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ *
+ * Input Parameters:
+ * ieee - Pointer to IEEE802.15.4 MAC driver structure.
+ * destip - Pointer to the IPv6 header to "compress"
+ * fptr - Pointer to the beginning of the frame under construction
+ *
+ * Returned Value:
+ * None
+ *
+ ****************************************************************************/
+
+static void sixlowpan_compress_ipv6hdr(FAR struct ieee802154_driver_s *ieee,
+ FAR const struct ipv6_hdr_s *destip,
+ FAR uint8_t *fptr)
+{
+ /* Indicate the IPv6 dispatch and length */
+
+ fptr[g_frame_hdrlen] = SIXLOWPAN_DISPATCH_IPV6;
+ g_frame_hdrlen += SIXLOWPAN_IPV6_HDR_LEN;
+
+ /* Copy the IPv6 header and adjust pointers */
+
+ memcpy(&fptr[g_frame_hdrlen] , destip, IPv6_HDRLEN);
+ g_frame_hdrlen += IPv6_HDRLEN;
+ g_uncomp_hdrlen += IPv6_HDRLEN;
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: sixlowpan_queue_frames
+ *
+ * Description:
+ * Process an outgoing UDP or TCP packet. This function is called from
+ * send interrupt logic when a TX poll is received. It formats the
+ * list of frames to be sent by the IEEE802.15.4 MAC driver.
+ *
+ * The payload data is in the caller 'buf' and is of length 'buflen'.
+ * Compressed headers will be added and if necessary the packet is
+ * fragmented. The resulting packet/fragments are put in ieee->i_framelist
+ * and the entire list of frames will be delivered to the 802.15.4 MAC via
+ * ieee->i_framelist.
+ *
+ * Input Parameters:
+ * ieee - The IEEE802.15.4 MAC driver instance
+ * ipv6hdr - IPv6 header followed by TCP or UDP header.
+ * buf - Beginning of the packet packet to send (with IPv6 + protocol
+ * headers)
+ * buflen - Length of data to send (include IPv6 and protocol headers)
+ * destmac - The IEEE802.15.4 MAC address of the destination
+ *
+ * Returned Value:
+ * Ok is returned on success; Othewise a negated errno value is returned.
+ * This function is expected to fail if the driver is not an IEEE802.15.4
+ * MAC network driver. In that case, the UDP/TCP will fall back to normal
+ * IPv4/IPv6 formatting.
+ *
+ * Assumptions:
+ * Called with the network locked.
+ *
+ ****************************************************************************/
+
+int sixlowpan_queue_frames(FAR struct ieee802154_driver_s *ieee,
+ FAR const struct ipv6_hdr_s *destip,
+ FAR const void *buf, size_t buflen,
+ FAR const struct rimeaddr_s *destmac)
+{
+ FAR struct iob_s *iob;
+ FAR uint8_t *fptr;
+ int framer_hdrlen;
+ struct rimeaddr_s bcastmac;
+#ifdef CONFIG_NET_6LOWPAN_FRAG
+ uint16_t outlen = 0;
+#endif
+
+ /* Initialize global data. Locking the network guarantees that we have
+ * exclusive use of the global values for intermediate calculations.
+ */
+
+ g_uncomp_hdrlen = 0;
+ g_frame_hdrlen = 0;
+
+ /* Reset rime buffer, packet buffer metatadata */
+
+ memset(g_pktattrs, 0, PACKETBUF_NUM_ATTRS * sizeof(uint16_t));
+ memset(g_pktaddrs, 0, PACKETBUF_NUM_ADDRS * sizeof(struct rimeaddr_s));
+
+ g_pktattrs[PACKETBUF_ATTR_MAX_MAC_TRANSMISSIONS] =
+ CONFIG_NET_6LOWPAN_MAX_MACTRANSMITS;
+
+ /* Set stream mode for all TCP packets, except FIN packets. */
+
+ if (destip->proto == IP_PROTO_TCP)
+ {
+ FAR const struct tcp_hdr_s *tcp =
+ &((FAR const struct ipv6tcp_hdr_s *)destip)->tcp;
+
+ if ((tcp->flags & TCP_FIN) == 0 &&
+ (tcp->flags & TCP_CTL) != TCP_ACK)
+ {
+ g_pktattrs[PACKETBUF_ATTR_PACKET_TYPE] = PACKETBUF_ATTR_PACKET_TYPE_STREAM;
+ }
+ else if ((tcp->flags & TCP_FIN) == TCP_FIN)
+ {
+ g_pktattrs[PACKETBUF_ATTR_PACKET_TYPE] = PACKETBUF_ATTR_PACKET_TYPE_STREAM_END;
+ }
+ }
+
+ /* The destination address will be tagged to each outbound packet. If the
+ * argument destmac is NULL, we are sending a broadcast packet.
+ */
+
+ if (destmac == NULL)
+ {
+ memset(&bcastmac, 0, sizeof(struct rimeaddr_s));
+ destmac = &bcastmac;
+ }
+
+ /* Pre-allocate the IOB to hold frame or the first fragment, waiting if
+ * necessary.
+ */
+
+ iob = iob_alloc(false);
+ DEBUGASSERT(iob != NULL);
+
+ /* Initialize the IOB */
+
+ iob->io_flink = NULL;
+ iob->io_len = 0;
+ iob->io_offset = 0;
+ iob->io_pktlen = 0;
+ fptr = iob->io_data;
+
+ ninfo("Sending packet length %d\n", buflen);
+
+ /* Pre-calculate frame header length. */
+
+ framer_hdrlen = sixlowpan_send_hdrlen(ieee, ieee->i_panid);
+ if (framer_hdrlen < 0)
+ {
+ /* Failed to determine the size of the header failed. */
+
+ nerr("ERROR: sixlowpan_send_hdrlen() failed: %d\n", framer_hdrlen);
+ return framer_hdrlen;
+ }
+
+ g_frame_hdrlen = framer_hdrlen;
+
+#ifndef CONFIG_NET_6LOWPAN_COMPRESSION_IPv6
+ if (buflen >= CONFIG_NET_6LOWPAN_COMPRESSION_THRESHOLD)
+ {
+ /* Try to compress the headers */
+
+#if defined(CONFIG_NET_6LOWPAN_COMPRESSION_HC1)
+ sixlowpan_compresshdr_hc1(ieee, destip, destmac, fptr);
+#elif defined(CONFIG_NET_6LOWPAN_COMPRESSION_HC06)
+ sixlowpan_compresshdr_hc06(ieee, destip, destmac, fptr);
+#else
+# error No compression specified
+#endif
+ }
+ else
+#endif /* !CONFIG_NET_6LOWPAN_COMPRESSION_IPv6 */
+ {
+ /* Small.. use IPv6 dispatch (no compression) */
+
+ sixlowpan_compress_ipv6hdr(ieee, destip, fptr);
+ }
+
+ ninfo("Header of length %d\n", g_frame_hdrlen);
+
+ rimeaddr_copy(&g_pktaddrs[PACKETBUF_ADDR_RECEIVER], destmac);
+
+ /* Check if we need to fragment the packet into several frames */
+
+ if ((int)buflen - (int)g_uncomp_hdrlen >
+ (int)CONFIG_NET_6LOWPAN_MAXPAYLOAD - framer_hdrlen -
+ (int)g_frame_hdrlen)
+ {
+#ifdef CONFIG_NET_6LOWPAN_FRAG
+ /* ieee->i_framelist will hold the generated frames; frames will be
+ * added at qtail.
+ */
+
+ FAR struct iob_s *qtail;
+ int verify;
+
+ /* The outbound IPv6 packet is too large to fit into a single 15.4
+ * packet, so we fragment it into multiple packets and send them.
+ * The first fragment contains frag1 dispatch, then
+ * IPv6/HC1/HC06/HC_UDP dispatchs/headers.
+ * The following fragments contain only the fragn dispatch.
+ */
+
+ ninfo("Fragmentation sending packet length %d\n", buflen);
+
+ /* Create 1st Fragment */
+ /* Add the frame header using the pre-allocated IOB. */
+
+ verify = sixlowpan_framecreate(ieee, iob, ieee->i_panid);
+ DEBUGASSERT(verify == framer_hdrlen);
+ UNUSED(verify);
+
+ /* Move HC1/HC06/IPv6 header */
+
+ memmove(fptr + SIXLOWPAN_FRAG1_HDR_LEN, fptr, g_frame_hdrlen);
+
+ /* Setup up the fragment header.
+ *
+ * The fragment header contains three fields: Datagram size, datagram
+ * tag and datagram offset:
+ *
+ * 1. Datagram size describes the total (un-fragmented) payload.
+ * 2. Datagram tag identifies the set of fragments and is used to
+ * match fragments of the same payload.
+ * 3. Datagram offset identifies the fragment’s offset within the un-
+ * fragmented payload.
+ *
+ * The fragment header length is 4 bytes for the first header and 5
+ * bytes for all subsequent headers.
+ */
+
+ PUTINT16(fptr, RIME_FRAG_DISPATCH_SIZE,
+ ((SIXLOWPAN_DISPATCH_FRAG1 << 8) | buflen));
+ PUTINT16(fptr, RIME_FRAG_TAG, ieee->i_dgramtag);
+ ieee->i_dgramtag++;
+
+ /* Copy payload and enqueue */
+
+ g_frame_hdrlen += SIXLOWPAN_FRAG1_HDR_LEN;
+ g_rime_payloadlen =
+ (CONFIG_NET_6LOWPAN_MAXPAYLOAD - framer_hdrlen - g_frame_hdrlen) & 0xf8;
+
+ memcpy(fptr + g_frame_hdrlen,
+ (FAR uint8_t *)destip + g_uncomp_hdrlen, g_rime_payloadlen);
+ iob->io_len += g_rime_payloadlen + g_frame_hdrlen;
+
+ /* Set outlen to what we already sent from the IP payload */
+
+ outlen = g_rime_payloadlen + g_uncomp_hdrlen;
+
+ ninfo("First fragment: length %d, tag %d\n",
+ g_rime_payloadlen, ieee->i_dgramtag);
+ sixlowpan_dumpbuffer("Outgoing frame",
+ (FAR const uint8_t *)iob->io_data, iob->io_len);
+
+ /* Add the first frame to the IOB queue */
+
+ ieee->i_framelist = iob;
+ qtail = iob;
+
+ /* Keep track of the total amount of data queue */
+
+ iob->io_pktlen = iob->io_len;
+
+ /* Create following fragments */
+
+ g_frame_hdrlen = SIXLOWPAN_FRAGN_HDR_LEN;
+
+ while (outlen < buflen)
+ {
+ /* Allocate an IOB to hold the next fragment, waiting if
+ * necessary.
+ */
+
+ iob = iob_alloc(false);
+ DEBUGASSERT(iob != NULL);
+
+ /* Initialize the IOB */
+
+ iob->io_flink = NULL;
+ iob->io_len = 0;
+ iob->io_offset = 0;
+ iob->io_pktlen = 0;
+ fptr = iob->io_data;
+
+ /* Add the frame header */
+
+ verify = sixlowpan_framecreate(ieee, iob, ieee->i_panid);
+ DEBUGASSERT(verify == framer_hdrlen);
+ UNUSED(verify);
+
+ /* Move HC1/HC06/IPv6 header */
+
+ memmove(fptr + SIXLOWPAN_FRAGN_HDR_LEN, fptr, g_frame_hdrlen);
+
+ /* Setup up the fragment header */
+
+ PUTINT16(fptr, RIME_FRAG_DISPATCH_SIZE,
+ ((SIXLOWPAN_DISPATCH_FRAGN << 8) | buflen));
+ PUTINT16(fptr, RIME_FRAG_TAG, ieee->i_dgramtag);
+ fptr[RIME_FRAG_OFFSET] = outlen >> 3;
+
+ /* Copy payload and enqueue */
+
+ if (buflen - outlen < g_rime_payloadlen)
+ {
+ /* Last fragment */
+
+ g_rime_payloadlen = buflen - outlen;
+ }
+ else
+ {
+ g_rime_payloadlen =
+ (CONFIG_NET_6LOWPAN_MAXPAYLOAD - framer_hdrlen - g_frame_hdrlen) & 0xf8;
+ }
+
+ memcpy(fptr + g_frame_hdrlen, (FAR uint8_t *)destip + outlen,
+ g_rime_payloadlen);
+ iob->io_len = g_rime_payloadlen + g_frame_hdrlen;
+
+ /* Set outlen to what we already sent from the IP payload */
+
+ outlen += (g_rime_payloadlen + g_uncomp_hdrlen);
+
+ ninfo("sixlowpan output: fragment offset %d, length %d, tag %d\n",
+ outlen >> 3, g_rime_payloadlen, ieee->i_dgramtag);
+ sixlowpan_dumpbuffer("Outgoing frame",
+ (FAR const uint8_t *)iob->io_data,
+ iob->io_len);
+
+ /* Add the next frame to the tail of the IOB queue */
+
+ qtail->io_flink = iob;
+
+ /* Keep track of the total amount of data queue */
+
+ ieee->i_framelist->io_pktlen += iob->io_len;
+ }
+#else
+ nerr("ERROR: Packet too large: %d\n", buflen);
+ nerr(" Cannot to be sent without fragmentation support\n");
+ nerr(" dropping packet\n");
+
+ return -E2BIG;
+#endif
+ }
+ else
+ {
+ int verify;
+
+ /* The packet does not need to be fragmented just copy the "payload"
+ * and send in one frame.
+ */
+
+ /* Add the frame header to the preallocated IOB. */
+
+ verify = sixlowpan_framecreate(ieee, iob, ieee->i_panid);
+ DEBUGASSERT(verify == framer_hdrlen);
+ UNUSED(verify);
+
+ /* Copy the payload and queue */
+
+ memcpy(fptr + g_frame_hdrlen, (FAR uint8_t *)destip + g_uncomp_hdrlen,
+ buflen - g_uncomp_hdrlen);
+ iob->io_len = buflen - g_uncomp_hdrlen + g_frame_hdrlen;
+
+ ninfo("Non-fragmented: length %d\n", iob->io_len);
+ sixlowpan_dumpbuffer("Outgoing frame",
+ (FAR const uint8_t *)iob->io_data, iob->io_len);
+
+ /* Add the first frame to the IOB queue */
+
+ ieee->i_framelist = iob;
+
+ /* Keep track of the total amount of data queue */
+
+ iob->io_pktlen = iob->io_len;
+ }
+
+ return OK;
+}
+
+#endif /* CONFIG_NET_6LOWPAN */
diff --git a/net/sixlowpan/sixlowpan_framer.c b/net/sixlowpan/sixlowpan_framer.c
index 2b528dea10d..b0953db648c 100644
--- a/net/sixlowpan/sixlowpan_framer.c
+++ b/net/sixlowpan/sixlowpan_framer.c
@@ -55,7 +55,6 @@
#include
#include "nuttx/net/net.h"
-#include "nuttx/net/sixlowpan.h"
#include "sixlowpan/sixlowpan_internal.h"
@@ -277,9 +276,10 @@ static int sixlowpan_802154_hdrlen(FAR struct frame802154_s *finfo)
*
* Input parameters:
* ieee - A reference IEEE802.15.4 MAC network device structure.
- * params - Where to put the parmeters
+ * iob - The IOB in which to create the frame.
* dest_panid - PAN ID of the destination. May be 0xffff if the destination
* is not associated.
+ * params - Where to put the parmeters
*
* Returned Value:
* None.
@@ -287,33 +287,28 @@ static int sixlowpan_802154_hdrlen(FAR struct frame802154_s *finfo)
****************************************************************************/
static void sixlowpan_setup_params(FAR struct ieee802154_driver_s *ieee,
- FAR struct frame802154_s *params,
- uint16_t dest_panid)
+ uint16_t dest_panid,
+ FAR struct frame802154_s *params)
{
bool rcvrnull;
/* Initialize all prameters to all zero */
- memset(¶ms, 0, sizeof(params));
-
- /* Reset to an empty frame */
-
- ieee->i_framelen = 0;
- ieee->i_dataoffset = 0;
+ memset(params, 0, sizeof(params));
/* Build the FCF (Only non-zero elements need to be initialized). */
params->fcf.frame_type = FRAME802154_DATAFRAME;
- params->fcf.frame_pending = ieee->i_pktattrs[PACKETBUF_ATTR_PENDING];
+ params->fcf.frame_pending = g_pktattrs[PACKETBUF_ATTR_PENDING];
/* If the output address is NULL in the Rime buf, then it is broadcast
* on the 802.15.4 network.
*/
- rcvrnull = sixlowpan_addrnull(ieee->i_pktaddrs[PACKETBUF_ADDR_RECEIVER].u8);
+ rcvrnull = sixlowpan_addrnull(g_pktaddrs[PACKETBUF_ADDR_RECEIVER].u8);
if (rcvrnull)
{
- params->fcf.ack_required = ieee->i_pktattrs[PACKETBUF_ATTR_MAC_ACK];
+ params->fcf.ack_required = g_pktattrs[PACKETBUF_ATTR_MAC_ACK];
}
/* Insert IEEE 802.15.4 (2003) version bit. */
@@ -322,14 +317,14 @@ static void sixlowpan_setup_params(FAR struct ieee802154_driver_s *ieee,
/* Increment and set the data sequence number. */
- if (ieee->i_pktattrs[PACKETBUF_ATTR_MAC_SEQNO] != 0)
+ if (g_pktattrs[PACKETBUF_ATTR_MAC_SEQNO] != 0)
{
- params->seq = ieee->i_pktattrs[PACKETBUF_ATTR_MAC_SEQNO];
+ params->seq = g_pktattrs[PACKETBUF_ATTR_MAC_SEQNO];
}
else
{
params->seq = ieee->i_dsn++;
- ieee->i_pktattrs[PACKETBUF_ATTR_MAC_SEQNO] = params->seq;
+ g_pktattrs[PACKETBUF_ATTR_MAC_SEQNO] = params->seq;
}
/* Complete the addressing fields. */
@@ -355,7 +350,7 @@ static void sixlowpan_setup_params(FAR struct ieee802154_driver_s *ieee,
/* Copy the destination address */
rimeaddr_copy((struct rimeaddr_s *)¶ms->dest_addr,
- ieee->i_pktaddrs[PACKETBUF_ADDR_RECEIVER].u8);
+ g_pktaddrs[PACKETBUF_ADDR_RECEIVER].u8);
/* Use short address mode if so configured */
@@ -369,11 +364,6 @@ static void sixlowpan_setup_params(FAR struct ieee802154_driver_s *ieee,
/* Set the source address to the node address assigned to the device */
rimeaddr_copy((struct rimeaddr_s *)¶ms->src_addr, &ieee->i_nodeaddr.u8);
-
- /* Configure the payload address and length */
-
- params->payload = FRAME_DATA_START(ieee);
- params->payload_len = FRAME_DATA_SIZE(ieee);
}
/****************************************************************************
@@ -381,7 +371,7 @@ static void sixlowpan_setup_params(FAR struct ieee802154_driver_s *ieee,
****************************************************************************/
/****************************************************************************
- * Function: sixlowpan_hdrlen
+ * Function: sixlowpan_send_hdrlen
*
* Description:
* This function is before the first frame has been sent in order to
@@ -399,14 +389,14 @@ static void sixlowpan_setup_params(FAR struct ieee802154_driver_s *ieee,
*
****************************************************************************/
-int sixlowpan_hdrlen(FAR struct ieee802154_driver_s *ieee,
- uint16_t dest_panid)
+int sixlowpan_send_hdrlen(FAR struct ieee802154_driver_s *ieee,
+ uint16_t dest_panid)
{
struct frame802154_s params;
/* Set up the frame parameters */
- sixlowpan_setup_params(ieee, ¶ms, dest_panid);
+ sixlowpan_setup_params(ieee, dest_panid, ¶ms);
/* Return the length of the header */
@@ -425,7 +415,7 @@ int sixlowpan_hdrlen(FAR struct ieee802154_driver_s *ieee,
* the frame to send.
* buf - Pointer to the buffer to use for the frame.
* buflen - The length of the buffer to use for the frame.
- * finfo - I that specifies the frame to send.
+ * finfo - Specifies the frame to send.
*
* Returned Value:
* The length of the frame header or 0 if there was insufficient space in
@@ -451,18 +441,18 @@ int sixlowpan_802154_framecreate(FAR struct frame802154_s *finfo,
return 0;
}
- /* OK, now we have field lengths. Time to actually construct
- * the outgoing frame, and store it in the provided buffer
+ /* OK, now we have field lengths. Time to actually construct the outgoing
+ * frame, and store it in the provided buffer
*/
- buf[0] = (finfo->fcf.frame_type & 7) |
- ((finfo->fcf.security_enabled & 1) << 3) |
- ((finfo->fcf.frame_pending & 1) << 4) |
- ((finfo->fcf.ack_required & 1) << 5) |
- ((finfo->fcf.panid_compression & 1) << 6);
- buf[1] = ((finfo->fcf.dest_addr_mode & 3) << 2) |
- ((finfo->fcf.frame_version & 3) << 4) |
- ((finfo->fcf.src_addr_mode & 3) << 6);
+ buf[0] = ((finfo->fcf.frame_type & 7) << FRAME802154_FRAMETYPE_SHIFT) |
+ ((finfo->fcf.security_enabled & 1) << FRAME802154_SECENABLED_SHIFT) |
+ ((finfo->fcf.frame_pending & 1) << FRAME802154_FRAMEPENDING_SHIFT) |
+ ((finfo->fcf.ack_required & 1) << FRAME802154_ACKREQUEST_SHIFT) |
+ ((finfo->fcf.panid_compression & 1) << FRAME802154_PANIDCOMP_SHIFT);
+ buf[1] = ((finfo->fcf.dest_addr_mode & 3) << FRAME802154_DSTADDR_SHIFT) |
+ ((finfo->fcf.frame_version & 3) << FRAME802154_VERSION_SHIFT) |
+ ((finfo->fcf.src_addr_mode & 3) << FRAME802154_SRCADDR_SHIFT);
/* Sequence number */
@@ -481,7 +471,7 @@ int sixlowpan_802154_framecreate(FAR struct frame802154_s *finfo,
for (i = flen.dest_addr_len; i > 0; i--)
{
- buf[pos++] = finfo->dest_addr[i - 1];
+ buf[pos++] = finfo->dest_addr[i - 1];
}
/* Source PAN ID */
@@ -516,11 +506,14 @@ int sixlowpan_802154_framecreate(FAR struct frame802154_s *finfo,
* Function: sixlowpan_framecreate
*
* Description:
- * This function is called after the IEEE802.15.4 MAC driver polls for
- * TX data. It creates the IEEE802.15.4 header in the frame buffer.
+ * This function is called after eiether (1) the IEEE802.15.4 MAC driver
+ * polls for TX data or (2) after the IEEE802.15.4 MAC driver provides an
+ * in frame and the network responds with an outgoing packet. It creates
+ * the IEEE802.15.4 header in the frame buffer.
*
* Input parameters:
* ieee - A reference IEEE802.15.4 MAC network device structure.
+ * iob - The IOB in which to create the frame.
* dest_panid - PAN ID of the destination. May be 0xffff if the destination
* is not associated.
*
@@ -531,36 +524,25 @@ int sixlowpan_802154_framecreate(FAR struct frame802154_s *finfo,
****************************************************************************/
int sixlowpan_framecreate(FAR struct ieee802154_driver_s *ieee,
- uint16_t dest_panid)
+ FAR struct iob_s *iob, uint16_t dest_panid)
{
struct frame802154_s params;
- int len;
- int ret;
+ int hdrlen;
/* Set up the frame parameters */
- sixlowpan_setup_params(ieee, ¶ms, dest_panid);
+ sixlowpan_setup_params(ieee, dest_panid, ¶ms);
/* Get the length of the header */
- len = sixlowpan_802154_hdrlen(¶ms);
-
- /* Allocate space for the header in the frame buffer */
-
- ret = sixlowpan_frame_hdralloc(ieee, len);
- if (ret < 0)
- {
- wlerr("ERROR: Header too large: %u\n", len);
- return ret;
- }
+ hdrlen = sixlowpan_802154_hdrlen(¶ms);
/* Then create the frame */
- sixlowpan_802154_framecreate(¶ms, FRAME_HDR_START(ieee), len);
+ sixlowpan_802154_framecreate(¶ms, iob->io_data, hdrlen);
- wlinfo("Frame type: %02x Data len: %d %u (%u)\n",
- params.fcf.frame_type, len, FRAME_DATA_SIZE(ieee),
- FRAME_SIZE(ieee));
+ wlinfo("Frame type: %02x hdrlen: %d\n",
+ params.fcf.frame_type, hdrlen);
#if CONFIG_NET_6LOWPAN_RIMEADDR_SIZE == 2
wlinfo("Dest address: %02x:%02x\n",
params.dest_addr[0], params.dest_addr[1]);
@@ -571,7 +553,7 @@ int sixlowpan_framecreate(FAR struct ieee802154_driver_s *ieee,
params.dest_addr[6], params.dest_addr[7]);
#endif
- return len;
+ return hdrlen;
}
#endif /* CONFIG_NET_6LOWPAN */
diff --git a/net/sixlowpan/sixlowpan_globals.c b/net/sixlowpan/sixlowpan_globals.c
index 4be92354dd0..8f48ade9f2f 100644
--- a/net/sixlowpan/sixlowpan_globals.c
+++ b/net/sixlowpan/sixlowpan_globals.c
@@ -39,8 +39,6 @@
#include
-#include "nuttx/net/sixlowpan.h"
-
#include "sixlowpan/sixlowpan_internal.h"
#ifdef CONFIG_NET_6LOWPAN
@@ -49,14 +47,38 @@
* Public Data
****************************************************************************/
-/* A pointer to the optional, architecture-specific compressor */
+/* The following data values are used to hold intermediate settings while
+ * processing IEEE802.15.4 frames. These globals are shared with incoming
+ * and outgoing frame processing and possibly with mutliple IEEE802.15.4 MAC
+ * devices. The network lock provides exclusive use of these globals
+ * during that processing
+ */
-FAR struct sixlowpan_nhcompressor_s *g_sixlowpan_compressor;
+/* The length of the payload in the Rime buffer.
+ *
+ * The payload is what comes after the compressed or uncompressed headers
+ * (can be the IP payload if the IP header only is compressed or the UDP
+ * payload if the UDP header is also compressed)
+ */
-#ifdef CONFIG_NET_6LOWPAN_SNIFFER
-/* A pointer to the optional, architecture-specific sniffer */
+uint8_t g_rime_payloadlen;
-FAR struct sixlowpan_rime_sniffer_s *g_sixlowpan_sniffer;
-#endif
+/* g_uncomp_hdrlen is the length of the headers before compression (if HC2
+ * is used this includes the UDP header in addition to the IP header).
+ */
+
+uint8_t g_uncomp_hdrlen;
+
+/* g_frame_hdrlen is the total length of (the processed) 6lowpan headers
+ * (fragment headers, IPV6 or HC1, HC2, and HC1 and HC2 non compressed
+ * fields).
+ */
+
+uint8_t g_frame_hdrlen;
+
+/* Packet buffer metadata: Attributes and addresses */
+
+uint16_t g_pktattrs[PACKETBUF_NUM_ATTRS];
+struct rimeaddr_s g_pktaddrs[PACKETBUF_NUM_ADDRS];
#endif /* CONFIG_NET_6LOWPAN */
diff --git a/net/sixlowpan/sixlowpan_hc06.c b/net/sixlowpan/sixlowpan_hc06.c
index 534cb1adbf5..9e51f88c17b 100644
--- a/net/sixlowpan/sixlowpan_hc06.c
+++ b/net/sixlowpan/sixlowpan_hc06.c
@@ -18,7 +18,7 @@
* Joel Hoglund
*
* Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
+ * modification, are permitted provided that the following c/onditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
@@ -58,13 +58,26 @@
#include
+#include
+#include
+
#include
-#include
+#include
#include "sixlowpan/sixlowpan_internal.h"
#ifdef CONFIG_NET_6LOWPAN_COMPRESSION_HC06
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+#define IPv6BUF(ieee) \
+ ((FAR struct ipv6_hdr_s *)((ieee)->i_dev.d_buf))
+#define UDPIPv6BUF(ieee) \
+ ((FAR struct udp_hdr_s *)&((ieee)->i_dev.d_buf[IPv6_HDRLEN]))
+
/****************************************************************************
* Private Types
****************************************************************************/
@@ -84,7 +97,12 @@ struct sixlowpan_addrcontext_s
* Private Data
****************************************************************************/
-/* HC06 specific variables */
+/* HC06 specific variables **************************************************/
+/* Use of global variables simplifies the logic and is safe in the multi-
+ * device environment because access is serialized via the network lock.
+ *
+ * But note that state may NOT be preserved from packet-to-packet.
+ */
#if CONFIG_NET_6LOWPAN_MAXADDRCONTEXT > 0
/* Addresses contexts for IPHC. */
@@ -93,6 +111,222 @@ static struct sixlowpan_addrcontext_s
g_hc06_addrcontexts[CONFIG_NET_6LOWPAN_MAXADDRCONTEXT];
#endif
+/* Pointer to the byte where to write next inline field. */
+
+static FAR uint8_t *g_hc06ptr;
+
+/* Constant Data ************************************************************/
+/* Uncompression of linklocal
+ *
+ * 0 -> 16 bytes from packet
+ * 1 -> 2 bytes from prefix - bunch of zeroes and 8 from packet
+ * 2 -> 2 bytes from prefix - 0000::00ff:fe00:XXXX from packet
+ * 3 -> 2 bytes from prefix - infer 8 bytes from MAC address
+ *
+ * NOTE: => the uncompress function does change 0xf to 0x10
+ * NOTE: 0x00 => no-autoconfig => unspecified
+ */
+
+static const uint8_t g_unc_llconf[] = { 0x0f, 0x28, 0x22, 0x20 };
+
+/* Uncompression of ctx-based
+ *
+ * 0 -> 0 bits from packet [unspecified / reserved]
+ * 1 -> 8 bytes from prefix - bunch of zeroes and 8 from packet
+ * 2 -> 8 bytes from prefix - 0000::00ff:fe00:XXXX + 2 from packet
+ * 3 -> 8 bytes from prefix - infer 8 bytes from MAC address
+ */
+
+static const uint8_t g_unc_ctxconf[] = { 0x00, 0x88, 0x82, 0x80 };
+
+/* Uncompression of ctx-based
+ *
+ * 0 -> 0 bits from packet
+ * 1 -> 2 bytes from prefix - bunch of zeroes 5 from packet
+ * 2 -> 2 bytes from prefix - zeroes + 3 from packet
+ * 3 -> 2 bytes from prefix - infer 1 bytes from MAC address
+ */
+
+static const uint8_t g_unc_mxconf[] = { 0x0f, 0x25, 0x23, 0x21 };
+
+/* Link local prefix */
+
+static const uint8_t g_llprefix[] = { 0xfe, 0x80 };
+
+/* TTL uncompression values */
+
+static const uint8_t g_ttl_values[] = { 0, 1, 64, 255 };
+
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: find_addrcontext_bynumber
+ *
+ * Description:
+ * Find the address context with the given number.
+ *
+ ****************************************************************************/
+
+static FAR struct sixlowpan_addrcontext_s *
+ find_addrcontext_bynumber(uint8_t number)
+{
+ /* Remove code to avoid warnings and save flash if no address context is
+ * used.
+ */
+
+#if CONFIG_NET_6LOWPAN_MAXADDRCONTEXT > 0
+ int i;
+
+ for (i = 0; i < CONFIG_NET_6LOWPAN_MAXADDRCONTEXT; i++)
+ {
+ if ((g_hc06_addrcontexts[i].used == 1) &&
+ g_hc06_addrcontexts[i].number == number)
+ {
+ return &g_hc06_addrcontexts[i];
+ }
+ }
+#endif /* CONFIG_NET_6LOWPAN_MAXADDRCONTEXT > 0 */
+
+ return NULL;
+}
+
+/****************************************************************************
+ * Name: find_addrcontext_bynumber
+ *
+ * Description:
+ * Find the address context corresponding to the prefix ipaddr.
+ *
+ ****************************************************************************/
+
+static FAR struct sixlowpan_addrcontext_s *
+ find_addrcontext_byprefix(FAR const net_ipv6addr_t ipaddr)
+{
+#if CONFIG_NET_6LOWPAN_MAXADDRCONTEXT > 0
+ int i;
+
+ /* Remove code to avoid warnings and save flash if no address context is used */
+
+ for (i = 0; i < CONFIG_NET_6LOWPAN_MAXADDRCONTEXT; i++)
+ {
+ if ((g_hc06_addrcontexts[i].used == 1) &&
+ net_ipv6addr_prefixcmp(&g_hc06_addrcontexts[i].prefix, ipaddr, 64))
+ {
+ return &g_hc06_addrcontexts[i];
+ }
+ }
+#endif /* CONFIG_NET_6LOWPAN_MAXADDRCONTEXT > 0 */
+
+ return NULL;
+}
+
+/****************************************************************************
+ * Name: uncompress_addr
+ *
+ * Description:
+ * Uncompress addresses based on a prefix and a postfix with zeroes in
+ * between. If the postfix is zero in length it will use the link address
+ * to configure the IP address (autoconf style).
+ *
+ * prefpost takes a byte where the first nibble specify prefix count
+ * and the second postfix count (NOTE: 15/0xf => 16 bytes copy).
+ *
+ ****************************************************************************/
+
+static uint8_t compress_addr_64(FAR const net_ipv6addr_t ipaddr,
+ FAR const struct rimeaddr_s *macaddr,
+ uint8_t bitpos)
+{
+ ninfo("ipaddr=%p macaddr=%p bitpos=%u g_hc06ptr=%p\n",
+ ipaddr, macaddr, bitpos, g_hc06ptr);
+
+ if (sixlowpan_ismacbased(ipaddr, macaddr))
+ {
+ return 3 << bitpos; /* 0-bits */
+ }
+ else if (SIXLOWPAN_IS_IID_16BIT_COMPRESSABLE(ipaddr))
+ {
+ /* Compress IID to 16 bits: xxxx:xxxx:xxxx:xxxx:0000:00ff:fe00:XXXX */
+
+ memcpy(g_hc06ptr, &ipaddr[7], 2);
+ g_hc06ptr += 2;
+ return 2 << bitpos; /* 16-bits */
+ }
+ else
+ {
+ /* Do not compress IID: xxxx:xxxx:xxxx:xxxx:IID:IID:IID:IID */
+
+ memcpy(g_hc06ptr, &ipaddr[4], 8);
+ g_hc06ptr += 8;
+ return 1 << bitpos; /* 64-bits */
+ }
+}
+
+/****************************************************************************
+ * Name: uncompress_addr
+ *
+ * Description:
+ * Uncompress addresses based on a prefix and a postfix with zeroes in
+ * between. If the postfix is zero in length it will use the link address
+ * to configure the IP address (autoconf style).
+ *
+ * prefpost takes a byte where the first nibble specify prefix count
+ * and the second postfix count (NOTE: 15/0xf => 16 bytes copy).
+ *
+ ****************************************************************************/
+
+static void uncompress_addr(FAR net_ipv6addr_t ipaddr, uint8_t const prefix[],
+ uint8_t prefpost, FAR struct rimeaddr_s *macaddr)
+{
+ uint8_t prefcount = prefpost >> 4;
+ uint8_t postcount = prefpost & 0x0f;
+
+ /* Full nibble 15 => 16 */
+
+ prefcount = prefcount == 15 ? 16 : prefcount;
+ postcount = postcount == 15 ? 16 : postcount;
+
+ if (prefcount > 0)
+ {
+ memcpy(ipaddr, prefix, prefcount);
+ }
+
+ if (prefcount + postcount < 16)
+ {
+ FAR uint8_t *iptr = (FAR uint8_t *)&ipaddr[0];
+
+ memset(&iptr[prefcount], 0, 16 - (prefcount + postcount));
+ }
+
+ if (postcount > 0)
+ {
+ FAR uint8_t *iptr = (FAR uint8_t *)&ipaddr[0];
+
+ memcpy(&iptr[16 - postcount], g_hc06ptr, postcount);
+ if (postcount == 2 && prefcount < 11)
+ {
+ /* 16 bits uncompression => 0000:00ff:fe00:XXXX */
+
+ iptr[11] = 0xff;
+ iptr[12] = 0xfe;
+ }
+
+ g_hc06ptr += postcount;
+ }
+ else if (prefcount > 0)
+ {
+ /* No IID based configuration if no prefix and no data => unspec */
+
+ sixlowpan_ipfromrime(macaddr, ipaddr);
+ }
+
+ ninfo("Uncompressing %d + %d => %04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x\n",
+ prefcount, postcount, ipaddr[0], ipaddr[2], ipaddr[3], ipaddr[5],
+ ipaddr[5], ipaddr[6], ipaddr[7]);
+}
+
/****************************************************************************
* Public Functions
****************************************************************************/
@@ -169,14 +403,13 @@ void sixlowpan_hc06_initialize(void)
}
/****************************************************************************
- * Name: sixlowpan_hc06_initialize
+ * Name: sixlowpan_compresshdr_hc06
*
* Description:
* Compress IP/UDP header
*
* This function is called by the 6lowpan code to create a compressed
- * 6lowpan packet in the packetbuf buffer from a full IPv6 packet in the
- * uip_buf buffer.
+ * 6lowpan packet in the frame buffer from a full IPv6 packet.
*
* HC-06 (draft-ietf-6lowpan-hc, version 6)
* http://tools.ietf.org/html/draft-ietf-6lowpan-hc-06
@@ -198,27 +431,398 @@ void sixlowpan_hc06_initialize(void)
* | L4 data ... |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
*
- * NOTE: The g_addr_context number 00 is reserved for the link local prefix.
- * For unicast addresses, if we cannot compress the prefix, we neither
- * compress the IID.
+ * NOTE: The address context number 00 is reserved for the link local
+ * prefix. For unicast addresses, if we cannot compress the prefix, we
+ * neither compress the IID.
*
* Input Parameters:
- * dev - A reference to the IEE802.15.4 network device state
- * destaddr - L2 destination address, needed to compress IP dest
+ * ieee - A reference to the IEE802.15.4 network device state
+ * ipv6 - The IPv6 header to be compressed
+ * destmac - L2 destination address, needed to compress the IP
+ * destination field
+ * fptr - Pointer to frame data payload.
*
* Returned Value:
* None
*
****************************************************************************/
-void sixlowpan_compresshdr_hc06(FAR struct net_driver_s *dev,
- FAR struct rimeaddr_s *destaddr)
+void sixlowpan_compresshdr_hc06(FAR struct ieee802154_driver_s *ieee,
+ FAR const struct ipv6_hdr_s *ipv6,
+ FAR const struct rimeaddr_s *destmac,
+ FAR uint8_t *fptr)
{
- /* REVISIT: To be provided */
+ FAR uint8_t *iphc = fptr + g_frame_hdrlen;
+ FAR struct sixlowpan_addrcontext_s *addrcontext;
+ uint8_t iphc0;
+ uint8_t iphc1;
+ uint8_t tmp;
+
+ ninfo("fptr=%p g_frame_hdrlen=%u iphc=%p\n", fptr, g_frame_hdrlen, iphc);
+
+ /* As we copy some bit-length fields, in the IPHC encoding bytes,
+ * we sometimes use |=
+ * If the field is 0, and the current bit value in memory is 1,
+ * this does not work. We therefore reset the IPHC encoding here
+ */
+
+ iphc0 = SIXLOWPAN_DISPATCH_IPHC;
+ iphc1 = 0;
+ iphc[2] = 0; /* Might not be used - but needs to be cleared */
+
+ /* Point to just after the two IPHC bytes we have committed to */
+
+ g_hc06ptr = iphc + 2;
+
+ /* Address handling needs to be made first since it might cause an extra
+ * byte with [ SCI | DCI ]
+ */
+
+ /* Check if dest address context exists (for allocating third byte)
+ *
+ * TODO: fix this so that it remembers the looked up values for avoiding two
+ * lookups - or set the lookup values immediately
+ */
+
+ if (find_addrcontext_byprefix(ipv6->destipaddr) != NULL ||
+ find_addrcontext_byprefix(ipv6->srcipaddr) != NULL)
+ {
+ /* set address context flag and increase g_hc06ptr */
+
+ ninfo("Decompressing dest or src ipaddr. Setting CID\n");
+ iphc1 |= SIXLOWPAN_IPHC_CID;
+ g_hc06ptr++;
+ }
+
+ /* Traffic class, flow label
+ *
+ * If flow label is 0, compress it. If traffic class is 0, compress it
+ * We have to process both in the same time as the offset of traffic class
+ * depends on the presence of version and flow label
+ */
+
+ /* hc06 format of tc is ECN | DSCP , original is DSCP | ECN */
+
+ tmp = (ipv6->vtc << 4) | (ipv6->tcf >> 4);
+ tmp = ((tmp & 0x03) << 6) | (tmp >> 2);
+
+ if (((ipv6->tcf & 0x0f) == 0) && (ipv6->flow == 0))
+ {
+ /* Flow label can be compressed */
+
+ iphc0 |= SIXLOWPAN_IPHC_TC_10;
+ if (((ipv6->vtc & 0x0f) == 0) && ((ipv6->tcf & 0xf0) == 0))
+ {
+ /* Compress (elide) all */
+
+ iphc0 |= SIXLOWPAN_IPHC_TC_01;
+ }
+ else
+ {
+ /* Compress only the flow label */
+
+ *g_hc06ptr = tmp;
+ g_hc06ptr += 1;
+ }
+ }
+ else
+ {
+ /* Flow label cannot be compressed */
+
+ if (((ipv6->vtc & 0x0f) == 0) && ((ipv6->tcf & 0xf0) == 0))
+ {
+ /* Compress only traffic class */
+
+ iphc0 |= SIXLOWPAN_IPHC_TC_01;
+ *g_hc06ptr = (tmp & 0xc0) | (ipv6->tcf & 0x0f);
+ memcpy(g_hc06ptr + 1, &ipv6->flow, 2);
+ g_hc06ptr += 3;
+ }
+ else
+ {
+ /* Compress nothing */
+
+ memcpy(g_hc06ptr, &ipv6->vtc, 4);
+
+ /* But replace the top byte with the new ECN | DSCP format */
+
+ *g_hc06ptr = tmp;
+ g_hc06ptr += 4;
+ }
+ }
+
+ /* Note that the payload length is always compressed */
+
+ /* Next header. We compress it if UDP */
+
+#if CONFIG_NET_UDP || UIP_CONF_ROUTER
+ if (ipv6->proto == IP_PROTO_UDP)
+ {
+ iphc0 |= SIXLOWPAN_IPHC_NH;
+ }
+#endif /* CONFIG_NET_UDP */
+
+ if ((iphc0 & SIXLOWPAN_IPHC_NH) == 0)
+ {
+ *g_hc06ptr = ipv6->proto;
+ g_hc06ptr += 1;
+ }
+
+ /* Hop limit
+ *
+ * if 1: compress, encoding is 01
+ * if 64: compress, encoding is 10
+ * if 255: compress, encoding is 11
+ * else do not compress
+ */
+
+ switch (ipv6->ttl)
+ {
+ case 1:
+ iphc0 |= SIXLOWPAN_IPHC_HLIM_1;
+ break;
+
+ case 64:
+ iphc0 |= SIXLOWPAN_IPHC_HLIM_64;
+ break;
+
+ case 255:
+ iphc0 |= SIXLOWPAN_IPHC_HLIM_255;
+ break;
+
+ default:
+ *g_hc06ptr = ipv6->ttl;
+ g_hc06ptr += 1;
+ break;
+ }
+
+ /* Source address - cannot be multicast */
+
+ if (net_is_addr_unspecified(ipv6->srcipaddr))
+ {
+ ninfo("Compressing unspecified. Setting SAC\n");
+
+ iphc1 |= SIXLOWPAN_IPHC_SAC;
+ iphc1 |= SIXLOWPAN_IPHC_SAM_128;
+ }
+ else if ((addrcontext = find_addrcontext_byprefix(ipv6->srcipaddr)) != NULL)
+ {
+ /* Elide the prefix - indicate by CID and set address context + SAC */
+
+ ninfo("Compressing src with address context. Setting CID and SAC context: %d\n",
+ addrcontext->number);
+
+ iphc1 |= SIXLOWPAN_IPHC_CID | SIXLOWPAN_IPHC_SAC;
+ iphc[2] |= addrcontext->number << 4;
+
+ /* Compression compare with this nodes address (source) */
+
+ iphc1 |= compress_addr_64(ipv6->srcipaddr, &ieee->i_nodeaddr,
+ SIXLOWPAN_IPHC_SAM_BIT);
+ }
+
+ /* No address context found for this address */
+
+ else if (net_is_addr_linklocal(ipv6->srcipaddr) &&
+ ipv6->destipaddr[1] == 0 && ipv6->destipaddr[2] == 0 &&
+ ipv6->destipaddr[3] == 0)
+ {
+ iphc1 |= compress_addr_64(ipv6->srcipaddr, &ieee->i_nodeaddr,
+ SIXLOWPAN_IPHC_SAM_BIT);
+ }
+ else
+ {
+ /* Send the full address => SAC = 0, SAM = 00 */
+
+ iphc1 |= SIXLOWPAN_IPHC_SAM_128; /* 128-bits */
+ memcpy(g_hc06ptr, ipv6->srcipaddr, 16);
+ g_hc06ptr += 16;
+ }
+
+ /* Destination address */
+
+ if (net_is_addr_mcast(ipv6->destipaddr))
+ {
+ /* Address is multicast, try to compress */
+
+ iphc1 |= SIXLOWPAN_IPHC_M;
+ if (SIXLOWPAN_IS_MCASTADDR_COMPRESSABLE8(ipv6->destipaddr))
+ {
+ iphc1 |= SIXLOWPAN_IPHC_DAM_0;
+
+ /* Use last byte */
+
+ *g_hc06ptr = ipv6->destipaddr[7] & 0x00ff;
+ g_hc06ptr += 1;
+ }
+ else if (SIXLOWPAN_IS_MCASTADDR_COMPRESSABLE32(ipv6->destipaddr))
+ {
+ FAR uint8_t *iptr = (FAR uint8_t *)ipv6->destipaddr;
+
+ iphc1 |= SIXLOWPAN_IPHC_DAM_16;
+
+ /* Second byte + the last three */
+
+ *g_hc06ptr = iptr[1];
+ memcpy(g_hc06ptr + 1, &iptr[13], 3);
+ g_hc06ptr += 4;
+ }
+ else if (SIXLOWPAN_IS_MCASTADDR_COMPRESSABLE48(ipv6->destipaddr))
+ {
+ FAR uint8_t *iptr = (FAR uint8_t *)ipv6->destipaddr;
+
+ iphc1 |= SIXLOWPAN_IPHC_DAM_64;
+
+ /* Second byte + the last five */
+
+ *g_hc06ptr = iptr[1];
+ memcpy(g_hc06ptr + 1, &iptr[11], 5);
+ g_hc06ptr += 6;
+ }
+ else
+ {
+ iphc1 |= SIXLOWPAN_IPHC_DAM_128;
+
+ /* Full address */
+
+ memcpy(g_hc06ptr, ipv6->destipaddr, 16);
+ g_hc06ptr += 16;
+ }
+ }
+ else
+ {
+ /* Address is unicast, try to compress */
+
+ if ((addrcontext = find_addrcontext_byprefix(ipv6->destipaddr)) != NULL)
+ {
+ /* Elide the prefix */
+
+ iphc1 |= SIXLOWPAN_IPHC_DAC;
+ iphc[2] |= addrcontext->number;
+
+ /* Compession compare with link adress (destination) */
+
+ iphc1 |= compress_addr_64(ipv6->destipaddr, destmac,
+ SIXLOWPAN_IPHC_DAM_BIT);
+
+ /* No address context found for this address */
+ }
+ else if (net_is_addr_linklocal(ipv6->destipaddr) &&
+ ipv6->destipaddr[1] == 0 && ipv6->destipaddr[2] == 0 &&
+ ipv6->destipaddr[3] == 0)
+ {
+ iphc1 |= compress_addr_64(ipv6->destipaddr, destmac,
+ SIXLOWPAN_IPHC_DAM_BIT);
+ }
+ else
+ {
+ /* Send the full address */
+
+ iphc1 |= SIXLOWPAN_IPHC_DAM_128; /* 128-bits */
+ memcpy(g_hc06ptr, ipv6->destipaddr, 16);
+ g_hc06ptr += 16;
+ }
+ }
+
+ g_uncomp_hdrlen = IPv6_HDRLEN;
+
+#if CONFIG_NET_UDP
+ /* UDP header compression */
+
+ if (ipv6->proto == IP_PROTO_UDP)
+ {
+ FAR struct udp_hdr_s *udp = UDPIPv6BUF(ieee);
+
+ ninfo("Uncompressed UDP ports on send side: %x, %x\n",
+ ntohs(udp->srcport), ntohs(udp->destport));
+
+ /* Mask out the last 4 bits can be used as a mask */
+
+ if (((ntohs(udp->srcport) & 0xfff0) == SIXLOWPAN_UDP_4_BIT_PORT_MIN) &&
+ ((ntohs(udp->destport) & 0xfff0) == SIXLOWPAN_UDP_4_BIT_PORT_MIN))
+ {
+ /* We can compress 12 bits of both source and dest */
+
+ *g_hc06ptr = SIXLOWPAN_NHC_UDP_CS_P_11;
+
+ ninfo("Remove 12b of both source & dest with prefix 0xfob\n");
+
+ *(g_hc06ptr + 1) =
+ (uint8_t)((ntohs(udp->srcport) - SIXLOWPAN_UDP_4_BIT_PORT_MIN) << 4) +
+ (uint8_t)((ntohs(udp->destport) - SIXLOWPAN_UDP_4_BIT_PORT_MIN));
+
+ g_hc06ptr += 2;
+ }
+ else if ((ntohs(udp->destport) & 0xff00) ==
+ SIXLOWPAN_UDP_8_BIT_PORT_MIN)
+ {
+ /* We can compress 8 bits of dest, leave source. */
+
+ *g_hc06ptr = SIXLOWPAN_NHC_UDP_CS_P_01;
+
+ ninfo("Leave source, remove 8 bits of dest with prefix 0xF0\n");
+
+ memcpy(g_hc06ptr + 1, &udp->srcport, 2);
+ *(g_hc06ptr + 3) =
+ (uint8_t) ((ntohs(udp->destport) -
+ SIXLOWPAN_UDP_8_BIT_PORT_MIN));
+ g_hc06ptr += 4;
+ }
+ else if ((ntohs(udp->srcport) & 0xff00) ==
+ SIXLOWPAN_UDP_8_BIT_PORT_MIN)
+ {
+ /* We can compress 8 bits of src, leave dest. Copy compressed port */
+
+ *g_hc06ptr = SIXLOWPAN_NHC_UDP_CS_P_10;
+
+ ninfo("Remove 8 bits of source with prefix 0xF0, leave dest. hch: %u\n",
+ *g_hc06ptr);
+
+ *(g_hc06ptr + 1) =
+ (uint8_t)((ntohs(udp->srcport) - SIXLOWPAN_UDP_8_BIT_PORT_MIN));
+
+ memcpy(g_hc06ptr + 2, &udp->destport, 2);
+ g_hc06ptr += 4;
+ }
+ else
+ {
+ /* we cannot compress. Copy uncompressed ports, full checksum */
+
+ *g_hc06ptr = SIXLOWPAN_NHC_UDP_CS_P_00;
+
+ nwarn("WARNING: Cannot compress headers\n");
+
+ memcpy(g_hc06ptr + 1, &udp->srcport, 4);
+ g_hc06ptr += 5;
+ }
+
+ /* Always inline the checksum */
+
+ if (1)
+ {
+ memcpy(g_hc06ptr, &udp->udpchksum, 2);
+ g_hc06ptr += 2;
+ }
+
+ g_uncomp_hdrlen += UDP_HDRLEN;
+ }
+#endif /* CONFIG_NET_UDP */
+
+ /* Before the g_frame_hdrlen operation */
+
+ iphc[0] = iphc0;
+ iphc[1] = iphc1;
+
+ g_frame_hdrlen = g_hc06ptr - fptr;
+
+ ninfo("fptr=%p g_frame_hdrlen=%u iphc=%02x:%02x:%02x g_hc06ptr=%p\n",
+ fptr, g_frame_hdrlen, iphc[0], iphc[1], iphc[2], g_hc06ptr);
+
+ return;
}
/****************************************************************************
- * Name: sixlowpan_hc06_initialize
+ * Name: sixlowpan_uncompresshdr_hc06
*
* Description:
* Uncompress HC06 (i.e., IPHC and LOWPAN_UDP) headers and put them in
@@ -227,25 +831,373 @@ void sixlowpan_compresshdr_hc06(FAR struct net_driver_s *dev,
* This function is called by the input function when the dispatch is HC06.
* We process the packet in the rime buffer, uncompress the header fields,
* and copy the result in the sixlowpan buffer. At the end of the
- * decompression, g_rime_hdrlen and g_uncompressed_hdrlen are set to the
+ * decompression, g_frame_hdrlen and g_uncompressed_hdrlen are set to the
* appropriate values
*
* Input Parmeters:
- * dev - A reference to the IEE802.15.4 network device state
- * iplen - Equal to 0 if the packet is not a fragment (IP length is then
- * inferred from the L2 length), non 0 if the packet is a 1st
- * fragment.
+ * ieee - A reference to the IEE802.15.4 network device state
+ * iplen - Equal to 0 if the packet is not a fragment (IP length is then
+ * inferred from the L2 length), non 0 if the packet is a first
+ * fragment.
+ * iob - Pointer to the IOB containing the received frame.
+ * payptr - Pointer to the frame data payload.
*
* Returned Value:
* None
*
****************************************************************************/
-void sixlowpan_uncompresshdr_hc06(FAR struct net_driver_s *dev,
- uint16_t iplen)
+void sixlowpan_uncompresshdr_hc06(FAR struct ieee802154_driver_s *ieee,
+ uint16_t iplen, FAR struct iob_s *iob,
+ FAR uint8_t *payptr)
{
- /* REVISIT: To be provided */
+ FAR struct ipv6_hdr_s *ipv6 = IPv6BUF(ieee);
+ FAR uint8_t *iphc;
+ uint8_t iphc0;
+ uint8_t iphc1;
+ uint8_t tmp;
+
+ /* payptr points to IPHC. At least two byte will be used for the encoding. */
+
+ iphc = payptr;
+ iphc0 = iphc[0];
+ iphc1 = iphc[1];
+
+ /* g_hc96ptr points to just after the 2-byte minimum IPHC */
+
+ g_hc06ptr = payptr + 2;
+
+ ninfo("payptr=%p g_frame_hdrlen=%u iphc=%02x:%02x:%02x g_hc06ptr=%p\n",
+ payptr, g_frame_hdrlen, iphc[0], iphc[1], iphc[2], g_hc06ptr);
+
+ /* Another if the CID flag is set */
+
+ if ((iphc1 & SIXLOWPAN_IPHC_CID) != 0)
+ {
+ ninfo("CID flag set. Increase header by one\n");
+ g_hc06ptr++;
+ }
+
+ /* Traffic class and flow label */
+
+ if ((iphc0 & SIXLOWPAN_IPHC_TC_10) == 0)
+ {
+ /* Flow label are carried inline */
+
+ if ((iphc0 & SIXLOWPAN_IPHC_TC_01) == 0)
+ {
+ /* Traffic class is carried inline */
+
+ memcpy(&ipv6->tcf, g_hc06ptr + 1, 3);
+ tmp = *g_hc06ptr;
+ g_hc06ptr += 4;
+
+ /* hc06 format of tc is ECN | DSCP , original is DSCP | ECN */
+ /* set version, pick highest DSCP bits and set in vtc */
+
+ ipv6->vtc = 0x60 | ((tmp >> 2) & 0x0f);
+
+ /* ECN rolled down two steps + lowest DSCP bits at top two bits */
+
+ ipv6->tcf = ((tmp >> 2) & 0x30) | (tmp << 6) | (ipv6->tcf & 0x0f);
+ }
+ else
+ {
+ /* Traffic class is compressed (set version and no TC) */
+
+ ipv6->vtc = 0x60;
+
+ /* Highest flow label bits + ECN bits */
+
+ ipv6->tcf = (*g_hc06ptr & 0x0f) | ((*g_hc06ptr >> 2) & 0x30);
+ memcpy(&ipv6->flow, g_hc06ptr + 1, 2);
+ g_hc06ptr += 3;
+ }
+ }
+ else
+ {
+ /* Version is always 6! */
+ /* Version and flow label are compressed */
+
+ if ((iphc0 & SIXLOWPAN_IPHC_TC_01) == 0)
+ {
+ /* Traffic class is inline */
+
+ ipv6->vtc = 0x60 | ((*g_hc06ptr >> 2) & 0x0f);
+ ipv6->tcf = ((*g_hc06ptr << 6) & 0xC0) | ((*g_hc06ptr >> 2) & 0x30);
+ ipv6->flow = 0;
+ g_hc06ptr += 1;
+ }
+ else
+ {
+ /* Traffic class is compressed */
+
+ ipv6->vtc = 0x60;
+ ipv6->tcf = 0;
+ ipv6->flow = 0;
+ }
+ }
+
+ /* Next Header */
+
+ if ((iphc0 & SIXLOWPAN_IPHC_NH) == 0)
+ {
+ /* Next header is carried inline */
+
+ ipv6->proto = *g_hc06ptr;
+ ninfo("Next header inline: %d\n", ipv6->proto);
+ g_hc06ptr += 1;
+ }
+
+ /* Hop limit */
+
+ if ((iphc0 & SIXLOWPAN_IPHC_HLIM_MASK) != SIXLOWPAN_IPHC_HLIM_INLINE)
+ {
+ ipv6->ttl = g_ttl_values[iphc0 & SIXLOWPAN_IPHC_HLIM_MASK];
+ }
+ else
+ {
+ ipv6->ttl = *g_hc06ptr;
+ g_hc06ptr += 1;
+ }
+
+ /* Put the source address compression mode SAM in the tmp var */
+
+ tmp = ((iphc1 & SIXLOWPAN_IPHC_SAM_MASK) >> SIXLOWPAN_IPHC_SAM_BIT) & 0x03;
+
+ /* Address context based compression */
+
+ if ((iphc1 & SIXLOWPAN_IPHC_SAC) != 0)
+ {
+ FAR struct sixlowpan_addrcontext_s *addrcontext;
+ uint8_t sci = (iphc1 & SIXLOWPAN_IPHC_CID) ? iphc[2] >> 4 : 0;
+
+ /* Source address - check address context != NULL only if SAM bits are != 0 */
+
+ if (tmp != 0)
+ {
+ addrcontext = find_addrcontext_bynumber(sci);
+ if (addrcontext == NULL)
+ {
+ nerr("ERROR: Address context not found\n");
+ return;
+ }
+ }
+
+ /* If tmp == 0 we do not have a Address context and therefore no prefix */
+
+ uncompress_addr(ipv6->srcipaddr,
+ tmp != 0 ? addrcontext->prefix : NULL, g_unc_ctxconf[tmp],
+ (FAR struct rimeaddr_s *)&g_pktaddrs[PACKETBUF_ADDR_SENDER]);
+ }
+ else
+ {
+ /* No compression and link local */
+
+ uncompress_addr(ipv6->srcipaddr, g_llprefix, g_unc_llconf[tmp],
+ (FAR struct rimeaddr_s *)&g_pktaddrs[PACKETBUF_ADDR_SENDER]);
+ }
+
+ /* Destination address */
+ /* Put the destination address compression mode into tmp */
+
+ tmp = ((iphc1 & SIXLOWPAN_IPHC_DAM_MASK) >> SIXLOWPAN_IPHC_DAM_BIT) & 0x03;
+
+ /* Multicast compression */
+
+ if ((iphc1 & SIXLOWPAN_IPHC_M) != 0)
+ {
+ /* Address context based multicast compression */
+
+ if ((iphc1 & SIXLOWPAN_IPHC_DAC) != 0)
+ {
+ /* TODO: implement this */
+ }
+ else
+ {
+ /* Non-address context based multicast compression
+ *
+ * DAM 00: 128 bits
+ * DAM 01: 48 bits FFXX::00XX:XXXX:XXXX
+ * DAM 0: 32 bits FFXX::00XX:XXXX
+ * DAM 11: 8 bits FF02::00XX
+ */
+
+ uint8_t prefix[] = { 0xff, 0x02 };
+ if (tmp > 0 && tmp < 3)
+ {
+ prefix[1] = *g_hc06ptr;
+ g_hc06ptr++;
+ }
+
+ uncompress_addr(ipv6->destipaddr, prefix, g_unc_mxconf[tmp], NULL);
+ }
+ }
+ else
+ {
+ /* no multicast */
+ /* Context based */
+
+ if ((iphc1 & SIXLOWPAN_IPHC_DAC) != 0)
+ {
+ FAR struct sixlowpan_addrcontext_s *addrcontext;
+ uint8_t dci = ((iphc1 & SIXLOWPAN_IPHC_CID) != 0) ? iphc[2] & 0x0f : 0;
+
+ addrcontext = find_addrcontext_bynumber(dci);
+
+ /* All valid cases below need the address context! */
+
+ if (addrcontext == NULL)
+ {
+ ninfo("ERROR: Address context not found\n");
+ return;
+ }
+
+ uncompress_addr(ipv6->destipaddr, addrcontext->prefix, g_unc_ctxconf[tmp],
+ (FAR struct rimeaddr_s *)&g_pktaddrs[PACKETBUF_ADDR_RECEIVER]);
+ }
+ else
+ {
+ /* Not address context based => link local M = 0, DAC = 0 - same as SAC */
+
+ uncompress_addr(ipv6->destipaddr, g_llprefix, g_unc_llconf[tmp],
+ (FAR struct rimeaddr_s *)&g_pktaddrs[PACKETBUF_ADDR_RECEIVER]);
+ }
+ }
+
+ g_uncomp_hdrlen += IPv6_HDRLEN;
+
+ /* Next header processing - continued */
+
+ if ((iphc0 & SIXLOWPAN_IPHC_NH) != 0)
+ {
+ FAR struct udp_hdr_s *udp = UDPIPv6BUF(ieee);
+
+ /* The next header is compressed, NHC is following */
+
+ if ((*g_hc06ptr & SIXLOWPAN_NHC_UDP_MASK) == SIXLOWPAN_NHC_UDP_ID)
+ {
+ uint8_t checksum_compressed;
+
+ ipv6->proto = IP_PROTO_UDP;
+ checksum_compressed = *g_hc06ptr & SIXLOWPAN_NHC_UDP_CHECKSUMC;
+
+ ninfo("Incoming header value: %i\n", *g_hc06ptr);
+
+ switch (*g_hc06ptr & SIXLOWPAN_NHC_UDP_CS_P_11)
+ {
+ case SIXLOWPAN_NHC_UDP_CS_P_00:
+ /* 1 byte for NHC, 4 byte for ports, 2 bytes chksum */
+
+ memcpy(&udp->srcport, g_hc06ptr + 1, 2);
+ memcpy(&udp->destport, g_hc06ptr + 3, 2);
+
+ ninfo("Uncompressed UDP ports (ptr+5): %x, %x\n",
+ htons(udp->srcport), htons(udp->destport));
+
+ g_hc06ptr += 5;
+ break;
+
+ case SIXLOWPAN_NHC_UDP_CS_P_01:
+ /* 1 byte for NHC + source 16bit inline, dest = 0xF0 + 8 bit
+ * inline
+ */
+
+ ninfo("Decompressing destination\n");
+
+ memcpy(&udp->srcport, g_hc06ptr + 1, 2);
+ udp->destport =
+ htons(SIXLOWPAN_UDP_8_BIT_PORT_MIN + (*(g_hc06ptr + 3)));
+
+ ninfo("Uncompressed UDP ports (ptr+4): %x, %x\n",
+ htons(udp->srcport), htons(udp->destport));
+
+ g_hc06ptr += 4;
+ break;
+
+ case SIXLOWPAN_NHC_UDP_CS_P_10:
+ /* 1 byte for NHC + source = 0xF0 + 8bit inline, dest = 16 bit
+ * inline
+ */
+
+ ninfo("Decompressing source\n");
+
+ udp->srcport =
+ htons(SIXLOWPAN_UDP_8_BIT_PORT_MIN + (*(g_hc06ptr + 1)));
+ memcpy(&udp->destport, g_hc06ptr + 2, 2);
+
+ ninfo("Uncompressed UDP ports (ptr+4): %x, %x\n",
+ htons(udp->srcport), htons(udp->destport));
+
+ g_hc06ptr += 4;
+ break;
+
+ case SIXLOWPAN_NHC_UDP_CS_P_11:
+ /* 1 byte for NHC, 1 byte for ports */
+
+ udp->srcport =
+ htons(SIXLOWPAN_UDP_4_BIT_PORT_MIN +
+ (*(g_hc06ptr + 1) >> 4));
+ udp->destport =
+ htons(SIXLOWPAN_UDP_4_BIT_PORT_MIN +
+ ((*(g_hc06ptr + 1)) & 0x0f));
+
+ ninfo("Uncompressed UDP ports (ptr+2): %x, %x\n",
+ htons(udp->srcport), htons(udp->destport));
+
+ g_hc06ptr += 2;
+ break;
+
+ default:
+ nerr("ERROR: Error unsupported UDP compression\n");
+ return;
+ }
+
+ if (!checksum_compressed)
+ {
+ /* Has_checksum, default */
+
+ memcpy(&udp->udpchksum, g_hc06ptr, 2);
+ g_hc06ptr += 2;
+
+ ninfo("Checksum included\n");
+ }
+ else
+ {
+ nwarn("WARNING: checksum *NOT* included\n");
+ }
+
+ g_uncomp_hdrlen += UDP_HDRLEN;
+ }
+ }
+
+ g_frame_hdrlen = g_hc06ptr - payptr;
+
+ /* IP length field. */
+
+ if (iplen == 0)
+ {
+ /* This is not a fragmented packet */
+
+ ipv6->len[0] = 0;
+ ipv6->len[1] = iob->io_len - g_frame_hdrlen + g_uncomp_hdrlen -
+ IPv6_HDRLEN;
+ }
+ else
+ {
+ /* This is a first fragment */
+
+ ipv6->len[0] = (iplen - IPv6_HDRLEN) >> 8;
+ ipv6->len[1] = (iplen - IPv6_HDRLEN) & 0x00ff;
+ }
+
+ /* Length field in UDP header */
+
+ if (ipv6->proto == IP_PROTO_UDP)
+ {
+ FAR struct udp_hdr_s *udp = UDPIPv6BUF(ieee);
+ memcpy(&udp->udplen, &ipv6->len[0], 2);
+ }
}
-
#endif /* CONFIG_NET_6LOWPAN_COMPRESSION_HC06 */
diff --git a/net/sixlowpan/sixlowpan_hc1.c b/net/sixlowpan/sixlowpan_hc1.c
index 245a7465c2c..a7040d5bcb3 100644
--- a/net/sixlowpan/sixlowpan_hc1.c
+++ b/net/sixlowpan/sixlowpan_hc1.c
@@ -48,11 +48,24 @@
#include
+#include
+#include
+#include
+
#include
#include "sixlowpan/sixlowpan_internal.h"
#ifdef CONFIG_NET_6LOWPAN_COMPRESSION_HC1
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/* Buffer access helpers */
+
+#define IPv6BUF(dev) ((FAR struct ipv6_hdr_s *)((dev)->d_buf))
+#define UDPIPv6BUF(dev) ((FAR struct udp_hdr_s *)&(dev)->d_buf[IPv6_HDRLEN])
+
/****************************************************************************
* Public Functions
****************************************************************************/
@@ -102,19 +115,127 @@
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
*
* Input Parmeters:
- * dev - A reference to the IEE802.15.4 network device state
- * destaddr - L2 destination address, needed to compress the IP
- * destination field
+ * ieee - A reference to the IEE802.15.4 network device state
+ * ipv6 - The IPv6 header to be compressed
+ * destmac - L2 destination address, needed to compress the IP
+ * destination field
+ * fptr - Pointer to frame to be compressed.
*
* Returned Value:
* None
*
****************************************************************************/
-void sixlowpan_compresshdr_hc1(FAR struct net_driver_s *dev,
- FAR struct rimeaddr_s *destaddr)
+void sixlowpan_compresshdr_hc1(FAR struct ieee802154_driver_s *ieee,
+ FAR const struct ipv6_hdr_s *ipv6,
+ FAR const struct rimeaddr_s *destmac,
+ FAR uint8_t *fptr)
{
-/* REVISIT: To be provided */
+ FAR uint8_t *hc1 = fptr + g_frame_hdrlen;
+
+ /* Check if all the assumptions for full compression are valid */
+
+ if (ipv6->vtc != 0x60 || ipv6->tcf != 0 || ipv6->flow != 0 ||
+ !sixlowpan_islinklocal(ipv6->srcipaddr) ||
+ !sixlowpan_ismacbased(ipv6->srcipaddr, &ieee->i_nodeaddr) ||
+ !sixlowpan_islinklocal(ipv6->destipaddr) ||
+ !sixlowpan_ismacbased(ipv6->destipaddr, destmac) ||
+ (ipv6->proto != IP_PROTO_ICMP6 && ipv6->proto != IP_PROTO_UDP &&
+ ipv6->proto != IP_PROTO_TCP))
+ {
+ /* IPV6 DISPATCH
+ * Something cannot be compressed, use IPV6 DISPATCH, compress
+ * nothing, copy IPv6 header in rime buffer
+ */
+
+ /* IPv6 dispatch header (1 byte) */
+
+ hc1[RIME_HC1_DISPATCH] = SIXLOWPAN_DISPATCH_IPV6;
+ g_frame_hdrlen += SIXLOWPAN_IPV6_HDR_LEN;
+
+ memcpy(fptr + g_frame_hdrlen, ipv6, IPv6_HDRLEN);
+ g_frame_hdrlen += IPv6_HDRLEN;
+ g_uncomp_hdrlen += IPv6_HDRLEN;
+ }
+ else
+ {
+ /* HC1 DISPATCH maximum compresssion:
+ * All fields in the IP header but Hop Limit are elided. If next
+ * header is UDP, we compress UDP header using HC2
+ */
+
+ hc1[RIME_HC1_DISPATCH] = SIXLOWPAN_DISPATCH_HC1;
+ g_uncomp_hdrlen += IPv6_HDRLEN;
+ switch (ipv6->proto)
+ {
+ case IP_PROTO_ICMP6:
+ /* HC1 encoding and ttl */
+
+ hc1[RIME_HC1_ENCODING] = 0xfc;
+ hc1[RIME_HC1_TTL] = ipv6->ttl;
+ g_frame_hdrlen += SIXLOWPAN_HC1_HDR_LEN;
+ break;
+
+#if CONFIG_NET_TCP
+ case IP_PROTO_TCP:
+ /* HC1 encoding and ttl */
+
+ hc1[RIME_HC1_ENCODING] = 0xfe;
+ hc1[RIME_HC1_TTL] = ipv6->ttl;
+ g_frame_hdrlen += SIXLOWPAN_HC1_HDR_LEN;
+ break;
+#endif /* CONFIG_NET_TCP */
+
+#if CONFIG_NET_UDP
+ case IP_PROTO_UDP:
+ {
+ FAR struct udp_hdr_s *udp = UDPIPv6BUF(&ieee->i_dev);
+
+ /* Try to compress UDP header (we do only full compression).
+ * This is feasible if both src and dest ports are between
+ * CONFIG_NET_6LOWPAN_MINPORT and CONFIG_NET_6LOWPAN_MINPORT +
+ * 15
+ */
+
+ ninfo("local/remote port %u/%u\n", udp->srcport, udp->destport);
+
+ if (htons(udp->srcport) >= CONFIG_NET_6LOWPAN_MINPORT &&
+ htons(udp->srcport) < (CONFIG_NET_6LOWPAN_MINPORT + 16) &&
+ htons(udp->destport) >= CONFIG_NET_6LOWPAN_MINPORT &&
+ htons(udp->destport) < (CONFIG_NET_6LOWPAN_MINPORT + 16))
+ {
+ FAR uint8_t *hcudp = fptr + g_frame_hdrlen;
+
+ /* HC1 encoding */
+
+ hcudp[RIME_HC1_HC_UDP_HC1_ENCODING] = 0xfb;
+
+ /* HC_UDP encoding, ttl, src and dest ports, checksum */
+
+ hcudp[RIME_HC1_HC_UDP_UDP_ENCODING] = 0xe0;
+ hcudp[RIME_HC1_HC_UDP_TTL] = ipv6->ttl;
+ hcudp[RIME_HC1_HC_UDP_PORTS] =
+ (uint8_t)((htons(udp->srcport) - CONFIG_NET_6LOWPAN_MINPORT) << 4) +
+ (uint8_t)((htons(udp->destport) - CONFIG_NET_6LOWPAN_MINPORT));
+
+ memcpy(&hcudp[RIME_HC1_HC_UDP_CHKSUM], &udp->udpchksum, 2);
+
+ g_frame_hdrlen += SIXLOWPAN_HC1_HC_UDP_HDR_LEN;
+ g_uncomp_hdrlen += UDP_HDRLEN;
+ }
+ else
+ {
+ /* HC1 encoding and ttl */
+
+ hc1[RIME_HC1_ENCODING] = 0xfa;
+ hc1[RIME_HC1_TTL] = ipv6->ttl;
+ g_frame_hdrlen += SIXLOWPAN_HC1_HDR_LEN;
+ }
+ }
+ break;
+#endif /* CONFIG_NET_UDP */
+ }
+ }
}
/****************************************************************************
@@ -126,24 +247,140 @@ void sixlowpan_compresshdr_hc1(FAR struct net_driver_s *dev,
* This function is called by the input function when the dispatch is
* HC1. It processes the packet in the rime buffer, uncompresses the
* header fields, and copies the result in the sixlowpan buffer. At the
- * end of the decompression, g_rime_hdrlen and uncompressed_hdr_len
+ * end of the decompression, g_frame_hdrlen and uncompressed_hdr_len
* are set to the appropriate values
*
* Input Parameters:
- * dev - A reference to the IEE802.15.4 network device state
- * iplen - Equal to 0 if the packet is not a fragment (IP length is then
- * inferred from the L2 length), non 0 if the packet is a 1st
- * fragment.
+ * ieee - A reference to the IEE802.15.4 network device state
+ * iplen - Equal to 0 if the packet is not a fragment (IP length is then
+ * inferred from the L2 length), non 0 if the packet is a 1st
+ * fragment.
+ * iob - Pointer to the IOB containing the received frame.
+ * payptr - Pointer to the frame data payload.
*
* Returned Value:
- * None
+ * Zero (OK) is returned on success, on failure a negater errno value is
+ * returned.
*
****************************************************************************/
-void sixlowpan_uncompresshdr_hc1(FAR struct net_driver_s *dev,
- uint16_t iplen)
+int sixlowpan_uncompresshdr_hc1(FAR struct ieee802154_driver_s *ieee,
+ uint16_t iplen, FAR struct iob_s *iob,
+ FAR uint8_t *payptr)
{
-/* REVISIT: To be provided */
+ FAR struct ipv6_hdr_s *ipv6 = IPv6BUF(&ieee->i_dev);
+ FAR uint8_t *hc1 = payptr + g_frame_hdrlen;
+
+ /* Format the IPv6 header in the device d_buf */
+ /* Set version, traffic clase, and flow label */
+
+ ipv6->vtc = 0x60; /* Bits 0-3: version, bits 4-7: traffic class (MS) */
+ ipv6->tcf = 0; /* Bits 0-3: traffic class (LS), 4-bits: flow label (MS) */
+ ipv6->flow = 0; /* 16-bit flow label (LS) */
+
+ /* Use stateless auto-configuration to set source and destination IP
+ * addresses.
+ */
+
+ sixlowpan_ipfromrime(&g_pktaddrs[PACKETBUF_ADDR_SENDER],
+ ipv6->srcipaddr);
+ sixlowpan_ipfromrime(&g_pktaddrs[PACKETBUF_ADDR_RECEIVER],
+ ipv6->destipaddr);
+ g_uncomp_hdrlen += IPv6_HDRLEN;
+
+ /* len[], proto, and ttl depend on the encoding */
+
+ switch (hc1[RIME_HC1_ENCODING] & 0x06)
+ {
+ case SIXLOWPAN_HC1_NH_ICMP6:
+ ipv6->proto = IP_PROTO_ICMP6;
+ ipv6->ttl = hc1[RIME_HC1_TTL];
+ g_frame_hdrlen += SIXLOWPAN_HC1_HDR_LEN;
+ break;
+
+#if CONFIG_NET_TCP
+ case SIXLOWPAN_HC1_NH_TCP:
+ ipv6->proto = IP_PROTO_TCP;
+ ipv6->ttl = hc1[RIME_HC1_TTL];
+ g_frame_hdrlen += SIXLOWPAN_HC1_HDR_LEN;
+ break;
+#endif /* CONFIG_NET_TCP */
+
+#if CONFIG_NET_UDP
+ case SIXLOWPAN_HC1_NH_UDP:
+ {
+ FAR struct udp_hdr_s *udp = UDPIPv6BUF(&ieee->i_dev);
+ FAR uint8_t *hcudp = payptr + g_frame_hdrlen;
+
+ ipv6->proto = IP_PROTO_UDP;
+ if ((hcudp[RIME_HC1_HC_UDP_HC1_ENCODING] & 0x01) != 0)
+ {
+ /* UDP header is compressed with HC_UDP */
+
+ if (hcudp[RIME_HC1_HC_UDP_UDP_ENCODING] !=
+ SIXLOWPAN_HC_UDP_ALL_C)
+ {
+ nwarn("WARNING: sixlowpan (uncompress_hdr), packet not supported");
+ return -EOPNOTSUPP;
+ }
+
+ /* IP TTL */
+
+ ipv6->ttl = hcudp[RIME_HC1_HC_UDP_TTL];
+
+ /* UDP ports, len, checksum */
+
+ udp->srcport =
+ htons(CONFIG_NET_6LOWPAN_MINPORT + (hcudp[RIME_HC1_HC_UDP_PORTS] >> 4));
+ udp->destport =
+ htons(CONFIG_NET_6LOWPAN_MINPORT + (hcudp[RIME_HC1_HC_UDP_PORTS] & 0x0F));
+
+ memcpy(&udp->udpchksum, &hcudp[RIME_HC1_HC_UDP_CHKSUM], 2);
+
+ g_uncomp_hdrlen += UDP_HDRLEN;
+ g_frame_hdrlen += SIXLOWPAN_HC1_HC_UDP_HDR_LEN;
+ }
+ else
+ {
+ g_frame_hdrlen += SIXLOWPAN_HC1_HDR_LEN;
+ }
+ }
+ break;
+#endif /* CONFIG_NET_UDP */
+
+ default:
+ return -EPROTONOSUPPORT;
+ }
+
+ /* IP length field. */
+
+ if (iplen == 0)
+ {
+ /* This is not a fragmented packet */
+
+ ipv6->len[0] = 0;
+ ipv6->len[1] = iob->io_len - g_frame_hdrlen + g_uncomp_hdrlen -
+ IPv6_HDRLEN;
+ }
+ else
+ {
+ /* This is a 1st fragment */
+
+ ipv6->len[0] = (iplen - IPv6_HDRLEN) >> 8;
+ ipv6->len[1] = (iplen - IPv6_HDRLEN) & 0x00FF;
+ }
+
+#if CONFIG_NET_UDP
+ /* Length field in UDP header */
+
+ if (ipv6->proto == IP_PROTO_UDP)
+ {
+ FAR struct udp_hdr_s *udp = UDPIPv6BUF(&ieee->i_dev);
+ memcpy(&udp->udplen, &ipv6->len[0], 2);
+ }
+#endif
+
+ return OK;
}
#endif /* CONFIG_NET_6LOWPAN_COMPRESSION_HC1 */
diff --git a/net/sixlowpan/sixlowpan_input.c b/net/sixlowpan/sixlowpan_input.c
index ce520f8e5e3..03a78f3684e 100644
--- a/net/sixlowpan/sixlowpan_input.c
+++ b/net/sixlowpan/sixlowpan_input.c
@@ -1,35 +1,45 @@
/****************************************************************************
* net/sixlowpan/sixlowpan_input.c
+ * 6loWPAN implementation (RFC4944 and draft-ietf-6loWPAN-hc-06)
*
- * Copyright (C) 2017 Gregory Nutt. All rights reserved.
+ * Copyright (C) 2017, Gregory Nutt, all rights reserved
* Author: Gregory Nutt
*
+ * Derives in large part from Contiki:
+ *
+ * Copyright (c) 2008, Swedish Institute of Computer Science.
+ * All rights reserved.
+ * Authors: Adam Dunkels
+ * Nicolas Tsiftes
+ * Niclas Finne
+ * Mathilde Durvy
+ * Julien Abeille
+ * Joakim Eriksson
+ * Joel Hoglund
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
- *
* 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
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the Institute nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
* 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.
+ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
*
****************************************************************************/
@@ -39,44 +49,571 @@
#include
+#include
+#include
#include
+#include
+
+#ifdef CONFIG_NET_6LOWPAN_FRAG
+# include "nuttx/clock.h"
+#endif
#include "nuttx/net/netdev.h"
+#include "nuttx/net/ip.h"
+#include "nuttx/net/sixlowpan.h"
+
+#ifdef CONFIG_NET_PKT
+# include "pkt/pkt.h"
+#endif
+
#include "sixlowpan/sixlowpan_internal.h"
#ifdef CONFIG_NET_6LOWPAN
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/* Success return values from sixlowpan_frame_process */
+
+#define INPUT_PARTIAL 0 /* Frame processed successful, packet incomplete */
+#define INPUT_COMPLETE 1 /* Frame processed successful, packet complete */
+
+/* Re-assembly timeout in clock ticks */
+
+#define NET_6LOWPAN_TIMEOUT SEC2TICK(CONFIG_NET_6LOWPAN_MAXAGE)
+
+/* Buffer access helpers */
+
+#define IPv6BUF(dev) ((FAR struct ipv6_hdr_s *)((dev)->d_buf))
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: sixlowpan_recv_hdrlen
+ *
+ * Description:
+ * Get the length of the IEEE802.15.4 header on the received frame.
+ *
+ * Input Parameters:
+ * ieee - The IEEE802.15.4 MAC network driver interface.
+ * iob - The IOB containing the frame.
+ *
+ * Returned Value:
+ * Ok is returned on success; Othewise a negated errno value is returned.
+ *
+ * Assumptions:
+ * Network is locked
+ *
+ ****************************************************************************/
+
+int sixlowpan_recv_hdrlen(FAR const uint8_t *fptr)
+{
+ uint16_t hdrlen;
+ uint8_t addrmode;
+
+ /* Minimum header: 2 byte FCF + 1 byte sequence number */
+
+ hdrlen = 3;
+
+ /* Account for destination address size */
+
+ addrmode = (fptr[1] & FRAME802154_DSTADDR_MASK) >> FRAME802154_DSTADDR_SHIFT;
+ if (addrmode == FRAME802154_SHORTADDRMODE)
+ {
+ /* 2 byte dest PAN + 2 byte dest short address */
+
+ hdrlen += 4;
+ }
+ else if (addrmode == FRAME802154_LONGADDRMODE)
+ {
+ /* 2 byte dest PAN + 6 byte dest long address */
+
+ hdrlen += 10;
+ }
+ else if (addrmode != FRAME802154_NOADDR)
+ {
+ nwarn("WARNING: Unrecognized address mode\n");
+
+ return -ENOSYS;
+ }
+ else if ((fptr[0] & (1 << FRAME802154_PANIDCOMP_SHIFT)) != 0)
+ {
+ nwarn("WARNING: PAN compression, but no destination address\n");
+
+ return -EINVAL;
+ }
+
+ /* Account for source address size */
+
+ addrmode = (fptr[1] & FRAME802154_SRCADDR_MASK) >> FRAME802154_SRCADDR_SHIFT;
+ if (addrmode == FRAME802154_NOADDR)
+ {
+ return hdrlen;
+ }
+ else
+ {
+ if ((fptr[0] & (1 << FRAME802154_PANIDCOMP_SHIFT)) == 0)
+ {
+ hdrlen += 2;
+ }
+
+ /* Add the length of the source address */
+
+ if (addrmode == FRAME802154_SHORTADDRMODE)
+ {
+ return hdrlen + 2;
+ }
+ else if (addrmode == FRAME802154_LONGADDRMODE)
+ {
+ return hdrlen + 8;
+ }
+ }
+
+ return 0;
+}
+
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
- * Function: sixlowpan_isbroadcast
+ * Name: sixlowpan_frame_process
*
* Description:
- * Return the address length associated with a 2-bit address mode
+ * Process an incoming 6loWPAN frame in 'iob'.
*
- * Input parameters:
- * addrmode - The address mode
+ * If its a FRAG1 or a non-fragmented frame we first uncompress the IP
+ * header. The 6loWPAN payload and possibly the uncompressed IP header
+ * are then copied into d_buf. An indication is returned if the packet
+ * in d_buf is complete (i.e., non-fragmented frame or and the last
+ * FRAGN frame).
+ *
+ * NOTE: We do not check for overlapping sixlowpan fragments (that is a
+ * SHALL in the RFC 4944 and should never happen)
+ *
+ * Input Parameters:
+ * ieee - The IEEE802.15.4 MAC network driver interface.
+ * iob - The IOB containing the frame.
*
* Returned Value:
- * The address length associated with the address mode.
+ * Ok is returned on success; Othewise a negated errno value is returned.
+ *
+ * Assumptions:
+ * Network is locked
*
****************************************************************************/
-static bool sixlowpan_isbroadcast(uint8_t mode, FAR uint8_t *addr)
+static int sixlowpan_frame_process(FAR struct ieee802154_driver_s *ieee,
+ FAR struct iob_s *iob)
{
- int i = ((mode == FRAME802154_SHORTADDRMODE) ? 2 : 8);
+ FAR uint8_t *payptr; /* Pointer to the frame payload */
+ FAR uint8_t *hc1; /* Convenience pointer to HC1 data */
- while (i-- > 0)
+ uint16_t fragsize = 0; /* Size of the IP packet (read from fragment) */
+ uint8_t fragoffset = 0; /* Offset of the fragment in the IP packet */
+ int reqsize; /* Required buffer size */
+ int hdrsize; /* Size of the IEEE802.15.4 header */
+
+#ifdef CONFIG_NET_6LOWPAN_FRAG
+ bool isfrag = false;
+ bool isfirstfrag = false;
+ bool islastfrag = false;
+ uint16_t fragtag = 0; /* Tag of the fragment */
+ systime_t elapsed; /* Elapsed time */
+#endif /* CONFIG_NET_6LOWPAN_FRAG */
+
+ /* Get a pointer to the payload following the IEEE802.15.4 frame header. */
+
+ hdrsize = sixlowpan_recv_hdrlen(iob->io_data);
+ if (hdrsize < 0)
{
- if (addr[i] != 0xff)
+ nwarn("Invalid IEEE802.15.2 header: %d\n", hdrsize);
+ return hdrsize;
+ }
+
+ /* Initialize global data. Locking the network guarantees that we have
+ * exclusive use of the global values for intermediate calculations.
+ */
+
+ g_uncomp_hdrlen = 0;
+ g_frame_hdrlen = hdrsize;
+
+ /* Payload starts after the IEEE802.15.4 header */
+
+ payptr = &iob->io_data[hdrsize];
+
+#ifdef CONFIG_NET_6LOWPAN_FRAG
+ /* Since we don't support the mesh and broadcast header, the first header
+ * we look for is the fragmentation header
+ */
+
+ switch ((GETINT16(payptr, RIME_FRAG_DISPATCH_SIZE) & 0xf800) >> 8)
+ {
+ /* First fragment of new reassembly */
+
+ case SIXLOWPAN_DISPATCH_FRAG1:
+ {
+ /* Set up for the reassembly */
+
+ fragoffset = 0;
+ fragsize = GETINT16(payptr, RIME_FRAG_DISPATCH_SIZE) & 0x07ff;
+ fragtag = GETINT16(payptr, RIME_FRAG_TAG);
+
+ ninfo("FRAG1: size %d, tag %d, offset %d\n",
+ fragsize, fragtag, fragoffset);
+
+ g_frame_hdrlen += SIXLOWPAN_FRAG1_HDR_LEN;
+
+ /* Indicate the first fragment of the reassembly */
+
+ isfirstfrag = true;
+ isfrag = true;
+ }
+ break;
+
+ case SIXLOWPAN_DISPATCH_FRAGN:
+ {
+ /* Set offset, tag, size. Offset is in units of 8 bytes. */
+
+ fragoffset = payptr[RIME_FRAG_OFFSET];
+ fragtag = GETINT16(payptr, RIME_FRAG_TAG);
+ fragsize = GETINT16(payptr, RIME_FRAG_DISPATCH_SIZE) & 0x07ff;
+
+ ninfo("FRAGN: size %d, tag %d, offset %d\n",
+ fragsize, fragtag, fragoffset);
+
+ g_frame_hdrlen += SIXLOWPAN_FRAGN_HDR_LEN;
+
+ ninfo("FRAGN: i_accumlen %d g_rime_payloadlen %d fragsize %d\n",
+ ieee->i_accumlen, iob->io_len - g_frame_hdrlen, fragsize);
+
+ /* Indicate that this frame is a another fragment for reassembly */
+
+ isfrag = true;
+
+ /* Check if it is the last fragement to be processed.
+ *
+ * If this is the last fragment, we may shave off any extrenous
+ * bytes at the end. We must be liberal in what we accept.
+ */
+
+ if (ieee->i_accumlen + iob->io_len - g_frame_hdrlen >= fragsize)
+ {
+ islastfrag = true;
+ }
+ }
+ break;
+
+ /* Not a fragment */
+
+ default:
+ break;
+ }
+
+ /* Check if we are currently reassembling a packet */
+
+ if (ieee->i_accumlen > 0)
+ {
+ /* If reassembly timed out, cancel it */
+
+ elapsed = clock_systimer() - ieee->i_time;
+ if (elapsed > NET_6LOWPAN_TIMEOUT)
{
- return false;
+ nwarn("WARNING: Reassembly timed out\n");
+ ieee->i_pktlen = 0;
+ ieee->i_accumlen = 0;
+ }
+
+ /* In this case what we expect is that the next frame will hold the
+ * next FRAGN of the sequence. We have to handle a few exeptional
+ * cases that we need to handle:
+ *
+ * 1. If we are currently reassembling a packet, but have just received
+ * the first fragment of another packet. We can either ignore it and
+ * hope to receive the rest of the under-reassembly packet fragments,
+ * or we can discard the previous packet altogether, and start
+ * reassembling the new packet. Here we discard the previous packet,
+ * and start reassembling the new packet.
+ * 2. The new frame is not a fragment. We should be able to handle this
+ * case, but we cannot because that would require two packet buffers.
+ * It could be handled with a more extensive design.
+ * 3. The fragment came from a different sender. What would this mean?
+ *
+ */
+
+ else if (!isfrag)
+ {
+ /* Discard the partially assembled packet */
+
+ nwarn("WARNING: Non-fragment frame received during reassembly\n");
+ ieee->i_pktlen = 0;
+ ieee->i_accumlen = 0;
+ }
+
+ /* It is a fragment of some kind. Drop any zero length fragments */
+
+ else if (fragsize == 0)
+ {
+ nwarn("WARNING: Dropping zero-length 6loWPAN fragment\n");
+ return INPUT_PARTIAL;
+ }
+
+ /* A non-zero, first fragement received while we are in the middle of
+ * rassembly. Discard the partially assembled packet and start over.
+ */
+
+ else if (isfirstfrag)
+ {
+ nwarn("WARNING: First fragment frame received during reassembly\n");
+ ieee->i_pktlen = 0;
+ ieee->i_accumlen = 0;
+ }
+
+ /* Verify that this fragment is part of that reassembly sequence */
+
+ else if (fragsize != ieee->i_pktlen || ieee->i_reasstag != fragtag ||
+ !rimeaddr_cmp(&ieee->i_fragsrc, &g_pktaddrs[PACKETBUF_ADDR_SENDER]))
+ {
+ /* The packet is a fragment that does not belong to the packet
+ * being reassembled or the packet is not a fragment.
+ */
+
+ nwarn("WARNING: Dropping 6loWPAN packet that is not a fragment of "
+ "the packet currently being reassembled\n");
+ return INPUT_PARTIAL;
+ }
+ else
+ {
+ /* Looks good. We are currently processing a reassembling sequence
+ * and we recieved a valid FRAGN fragment. Skip the header
+ * compression dispatch logic.
+ */
+
+ goto copypayload;
}
}
- return true;
+ /* There is no reassembly in progress. Check if we received a fragment */
+
+ else if (isfrag)
+ {
+ /* Another case that we have to handle is if a FRAGN fragment of a
+ * reassembly is received, but we are not currently reassembling a
+ * packet. I think we have no choice but to drop the packet in this
+ * case.
+ */
+
+ if (!isfirstfrag)
+ {
+ nwarn("WARNING: FRAGN 6loWPAN fragment while not reassembling\n");
+ return OK;
+ }
+
+ /* Start reassembly if we received a non-zero length, first fragment */
+
+ if (fragsize > 0)
+ {
+ /* Drop the packet if it cannot fit into the d_buf */
+
+ if (fragsize > CONFIG_NET_6LOWPAN_MTU)
+ {
+ nwarn("WARNING: Reassembled packet size exeeds CONFIG_NET_6LOWPAN_MTU\n");
+ return OK;
+ }
+
+ /* Set up for the reassembly */
+
+ ieee->i_pktlen = fragsize;
+ ieee->i_reasstag = fragtag;
+ ieee->i_time = clock_systimer();
+
+ ninfo("Starting reassembly: i_pktlen %d, i_pktlen %d\n",
+ ieee->i_pktlen, ieee->i_reasstag);
+
+ rimeaddr_copy(&ieee->i_fragsrc, &g_pktaddrs[PACKETBUF_ADDR_SENDER]);
+ }
+ }
+#endif /* CONFIG_NET_6LOWPAN_FRAG */
+
+ /* Process next dispatch and headers */
+
+ hc1 = &iob->io_data[g_frame_hdrlen];
+
+#ifdef CONFIG_NET_6LOWPAN_COMPRESSION_HC06
+ if ((hc1[RIME_HC1_DISPATCH] & SIXLOWPAN_DISPATCH_IPHC_MASK) == SIXLOWPAN_DISPATCH_IPHC)
+ {
+ ninfo("IPHC Dispatch\n");
+ sixlowpan_uncompresshdr_hc06(ieee, fragsize, iob, payptr);
+ }
+ else
+#endif /* CONFIG_NET_6LOWPAN_COMPRESSION_HC06 */
+
+#ifdef CONFIG_NET_6LOWPAN_COMPRESSION_HC1
+ if (hc1[RIME_HC1_DISPATCH] == SIXLOWPAN_DISPATCH_HC1)
+ {
+ ninfo("HC1 Dispatch\n");
+ sixlowpan_uncompresshdr_hc1(ieee, fragsize, iob, payptr);
+ }
+ else
+#endif /* CONFIG_NET_6LOWPAN_COMPRESSION_HC1 */
+
+ if (hc1[RIME_HC1_DISPATCH] == SIXLOWPAN_DISPATCH_IPV6)
+ {
+ ninfo("IPV6 Dispatch\n");
+ g_frame_hdrlen += SIXLOWPAN_IPV6_HDR_LEN;
+
+ /* Put uncompressed IP header in d_buf. */
+
+ memcpy(ieee->i_dev.d_buf, payptr + g_frame_hdrlen, IPv6_HDRLEN);
+
+ /* Update g_uncomp_hdrlen and g_frame_hdrlen. */
+
+ g_frame_hdrlen += IPv6_HDRLEN;
+ g_uncomp_hdrlen += IPv6_HDRLEN;
+ }
+ else
+ {
+ /* Unknown or unsupported header */
+
+ nwarn("WARNING unknown dispatch: %u\n", hc1[RIME_HC1_DISPATCH]);
+ return OK;
+ }
+
+#ifdef CONFIG_NET_6LOWPAN_FRAG
+copypayload:
+#endif /* CONFIG_NET_6LOWPAN_FRAG */
+
+ /* Copy "payload" from the rime buffer to the IEEE802.15.4 MAC driver's
+ * d_buf. If this frame is a first fragment or not part of a fragmented
+ * packet, we have already copied the compressed headers, g_uncomp_hdrlen
+ * and g_frame_hdrlen are non-zerio, fragoffset is.
+ */
+
+ g_rime_payloadlen = iob->io_len - g_frame_hdrlen;
+ if (g_rime_payloadlen > CONFIG_NET_6LOWPAN_MTU)
+ {
+ nwarn("WARNING: Packet dropped due to payload (%u) > packet buffer (%u)\n",
+ g_rime_payloadlen, CONFIG_NET_6LOWPAN_MTU);
+ return OK;
+ }
+
+ /* Sanity-check size of incoming packet to avoid buffer overflow */
+
+ reqsize = g_uncomp_hdrlen + (uint16_t) (fragoffset << 3) + g_rime_payloadlen;
+ if (reqsize > CONFIG_NET_6LOWPAN_MTU)
+ {
+ ninfo("Required buffer size: %d+%d+%d=%d Available: %d\n",
+ g_uncomp_hdrlen, (int)(fragoffset << 3), g_rime_payloadlen,
+ reqsize, CONFIG_NET_6LOWPAN_MTU);
+ return -ENOMEM;
+ }
+
+ memcpy((FAR uint8_t *)ieee->i_dev.d_buf + g_uncomp_hdrlen +
+ (int)(fragoffset << 3), payptr + g_frame_hdrlen,
+ g_rime_payloadlen);
+
+#ifdef CONFIG_NET_6LOWPAN_FRAG
+ /* Update ieee->i_accumlen if the frame is a fragment, ieee->i_pktlen
+ * otherwise.
+ */
+
+ if (isfrag)
+ {
+ /* Add the size of the header only for the first fragment. */
+
+ if (isfirstfrag)
+ {
+ ieee->i_accumlen += g_uncomp_hdrlen;
+ }
+
+ /* For the last fragment, we are OK if there is extraneous bytes at the
+ * end of the packet.
+ */
+
+ if (islastfrag)
+ {
+ ieee->i_accumlen = fragsize;
+ }
+ else
+ {
+ ieee->i_accumlen += g_rime_payloadlen;
+ }
+
+ ninfo("i_accumlen %d, g_rime_payloadlen %d\n",
+ ieee->i_accumlen, g_rime_payloadlen);
+ }
+ else
+ {
+ ieee->i_pktlen = g_rime_payloadlen + g_uncomp_hdrlen;
+ }
+
+ /* If we have a full IP packet in sixlowpan_buf, deliver it to
+ * the IP stack
+ */
+
+ ninfo("sixlowpan_init i_accumlen %d, ieee->i_pktlen %d\n",
+ ieee->i_accumlen, ieee->i_pktlen);
+
+ if (ieee->i_accumlen == 0 || ieee->i_accumlen == ieee->i_pktlen)
+ {
+ ninfo("IP packet ready (length %d)\n", ieee->i_pktlen);
+
+ ieee->i_dev.d_len = ieee->i_pktlen;
+ ieee->i_pktlen = 0;
+ ieee->i_accumlen = 0;
+ return INPUT_COMPLETE;
+ }
+
+ return INPUT_PARTIAL;
+#else
+ /* Deliver the packet to the IP stack */
+
+ ieee->i_dev.d_len = g_rime_payloadlen + g_uncomp_hdrlen;
+ return INPUT_COMPLETE;
+#endif /* CONFIG_NET_6LOWPAN_FRAG */
+}
+
+/****************************************************************************
+ * Function: sixlowpan_dispatch
+ *
+ * Description:
+ * Inject the packet in d_buf into the network for normal packet processing.
+ *
+ * Parameters:
+ * ieee - The IEEE802.15.4 MAC network driver interface.
+ *
+ * Returned Value:
+ * None
+ *
+ ****************************************************************************/
+
+static int sixlowpan_dispatch(FAR struct ieee802154_driver_s *ieee)
+{
+ sixlowpan_dumpbuffer("Incoming packet",
+ (FAR const uint8_t *)IPv6BUF(&ieee->i_dev),
+ ieee->i_dev.d_len);
+
+#ifdef CONFIG_NET_PKT
+ /* When packet sockets are enabled, feed the frame into the packet tap */
+
+ ninfo("Packet tap\n");
+ pkt_input(&ieee->i_dev);
+#endif
+
+ /* We only accept IPv6 packets. */
+
+ ninfo("Iv6 packet dispatch\n");
+ NETDEV_RXIPV6(&ieee->i_dev);
+
+ /* Give the IPv6 packet to the network layer. NOTE: If there is a
+ * problem with IPv6 header, it will be silently dropped and d_len will
+ * be set to zero. Oddly, ipv6_input() will return OK in this case.
+ */
+
+ return ipv6_input(&ieee->i_dev);
}
/****************************************************************************
@@ -87,30 +624,163 @@ static bool sixlowpan_isbroadcast(uint8_t mode, FAR uint8_t *addr)
* Name: sixlowpan_input
*
* Description:
- * Process an incoming IP packet.
+ * Process an incoming 6loWPAN frame.
*
* This function is called when the device driver has received a 6loWPAN
- * packet from the network. The packet from the device driver must be
- * present in the d_buf buffer, and the length of the packet should be
- * placed in the d_len field.
+ * frame from the network. The frame from the device driver must be
+ * provided in a IOB present in the i_framelist: The frame data is in the
+ * IOB io_data[] buffer and the length of the frame is in the IOB io_len
+ * field. Only a single IOB is expected in the i_framelist. This incoming
+ * data will be processed one frame at a time.
*
- * When the function returns, there may be an outbound packet placed
- * in the d_buf packet buffer. If so, the d_len field is set to
- * the length of the packet. If no packet is to be sent out, the
- * d_len field is set to 0.
+ * An non-NULL d_buf of size CONFIG_NET_6LOWPAN_MTU must also be provided.
+ * The frame will be decompressed and placed in the d_buf. Fragmented
+ * packets will also be reassembled in the d_buf as they are received
+ * (meaning for the driver, that two packet buffers are required: One for
+ * reassembly of RX packets and one used for TX polling).
+ *
+ * After each frame is processed into d_buf, the IOB is removed and
+ * deallocated. i_framelist will be nullified. If reassembly is
+ * incomplete, this function will return to called with i_framelist
+ * equal to NULL. The partially reassembled packet must be preserved by
+ * the IEEE802.15.4 MAC and provided again when the next frame is
+ * received.
+ *
+ * When the packet in the d_buf is fully reassembled, it will be provided
+ * to the network as with any other received packet. d_len will be set
+ * the the length of the uncompressed, reassembled packet.
+ *
+ * After the network processes the packet, d_len will be set to zero.
+ * Network logic may also decide to send a response to the packet. In
+ * that case, the outgoing network packet will be placed in d_buf the
+ * d_buf and d_len will be set to a non-zero value. That case is handled
+ * by this function.
+ *
+ * If that case occurs, the packet will be converted to a list of
+ * compressed and possibly fragmented frames in i_framelist as with other
+ * TX operations.
+ *
+ * So from the standpoint of the IEEE802.15.4 MAC driver, there are two
+ * possible results: (1) i_framelist is NULL meaning that the frame
+ * was fully processed and freed, or (2) i_framelist is non-NULL meaning
+ * that there are outgoing frame(s) to be sent.
*
* Input Parameters:
- * dev - The IEEE802.15.4 MAC network driver interface.
+ * ieee - The IEEE802.15.4 MAC network driver interface.
*
* Returned Value:
* Ok is returned on success; Othewise a negated errno value is returned.
*
****************************************************************************/
-int sixlowpan_input(FAR struct net_driver_s *dev)
+int sixlowpan_input(FAR struct ieee802154_driver_s *ieee)
{
- /* REVISIT: To be provided */
- return -ENOSYS;
+ int ret = -EINVAL;
+
+ DEBUGASSERT(ieee != NULL && !FRAME_IOB_EMPTY(ieee));
+
+ /* Verify that an IOB is provided in the device structure */
+
+ while (!FRAME_IOB_EMPTY(ieee))
+ {
+ FAR struct iob_s *iob;
+
+ /* Remove the IOB containing the frame from the device structure */
+
+ FRAME_IOB_REMOVE(ieee, iob);
+ DEBUGASSERT(iob != NULL);
+
+ sixlowpan_dumpbuffer("Incoming frame",
+ (FAR const uint8_t *)iob->io_data, iob->io_len);
+
+ /* Process the frame, decompressing it into the packet buffer */
+
+ ret = sixlowpan_frame_process(ieee, iob);
+
+ /* Was the frame successfully processed? Is the packet in d_buf fully
+ * reassembled?
+ */
+
+ if (ret == INPUT_COMPLETE)
+ {
+ /* Inject the uncompressed, reassembled packet into the network */
+
+ ret = sixlowpan_dispatch(ieee);
+ if (ret >= 0)
+ {
+ /* Check if this resulted in a request to send an outgoing
+ * packet.
+ */
+
+ if (ieee->i_dev.d_len > 0)
+ {
+ FAR struct ipv6_hdr_s *ipv6hdr;
+ FAR uint8_t *buffer;
+ struct rimeaddr_s destmac;
+ size_t hdrlen;
+ size_t buflen;
+
+ /* The IPv6 header followed by TCP or UDP headers should
+ * lie at the beginning of d_buf since there is no link
+ * layer protocol header.
+ */
+
+ ipv6hdr = (FAR struct ipv6_hdr_s *)(ieee->i_dev.d_buf);
+
+ /* Get the Rime MAC address of the destination. This
+ * assumes an encoding of the MAC address in the IPv6
+ * address.
+ */
+
+ sixlowpan_rimefromip(ipv6hdr->destipaddr, &destmac);
+
+ /* The data payload should follow the IPv6 header plus
+ * the protocol header.
+ */
+
+ if (ipv6hdr->proto != IP_PROTO_TCP)
+ {
+ hdrlen = IPv6_HDRLEN + TCP_HDRLEN;
+ }
+ else if (ipv6hdr->proto != IP_PROTO_UDP)
+ {
+ hdrlen = IPv6_HDRLEN + UDP_HDRLEN;
+ }
+ else if (ipv6hdr->proto != IP_PROTO_ICMP6)
+ {
+ hdrlen = IPv6_HDRLEN + ICMPv6_HDRLEN;
+ }
+ else
+ {
+ nwarn("WARNING: Unsupported protoype: %u\n",
+ ipv6hdr->proto);
+ ret = -EPROTO;
+ goto drop;
+ }
+
+ if (hdrlen < ieee->i_dev.d_len)
+ {
+ nwarn("WARNING: Packet to small: Have %u need >%u\n",
+ ieee->i_dev.d_len, hdrlen);
+ ret = -ENOBUFS;
+ goto drop;
+ }
+
+ /* Convert the outgoing packet into a frame list. */
+
+ buffer = ieee->i_dev.d_buf + hdrlen;
+ buflen = ieee->i_dev.d_len - hdrlen;
+
+ ret = sixlowpan_queue_frames(ieee, ipv6hdr, buffer, buflen,
+ &destmac);
+drop:
+ ieee->i_dev.d_len = 0;
+ }
+ }
+ }
+ }
+
+ return ret;
}
#endif /* CONFIG_NET_6LOWPAN */
diff --git a/net/sixlowpan/sixlowpan_internal.h b/net/sixlowpan/sixlowpan_internal.h
index 6828c141285..8f3e52dfd39 100644
--- a/net/sixlowpan/sixlowpan_internal.h
+++ b/net/sixlowpan/sixlowpan_internal.h
@@ -63,6 +63,7 @@
#include
#include
#include
+#include
#ifdef CONFIG_NET_6LOWPAN
@@ -81,57 +82,221 @@
#define rimeaddr_cmp(addr1,addr2) \
(memcmp(addr1, addr2, CONFIG_NET_6LOWPAN_RIMEADDR_SIZE) == 0)
-/* Frame buffer helpers */
+/* Pointers in the Rime buffer */
-#define FRAME_RESET(ieee) \
- do \
- { \
- (ieee)->i_dataoffset = 0; \
- (ieee)->i_framelen = 0; \
- } \
- while (0)
+/* Fragment header.
+ *
+ * The fragment header is used when the payload is too large to fit in a
+ * single IEEE 802.15.4 frame. The fragment header contains three fields:
+ * Datagram size, datagram tag and datagram offset.
+ *
+ * 1. Datagram size describes the total (un-fragmented) payload.
+ * 2. Datagram tag identifies the set of fragments and is used to match
+ * fragments of the same payload.
+ * 3. Datagram offset identifies the fragment’s offset within the un-
+ * fragmented payload.
+ *
+ * The fragment header length is 4 bytes for the first header and 5
+ * bytes for all subsequent headers.
+ */
-#define FRAME_HDR_START(ieee) \
- ((ieee)->i_frame)
-#define FRAME_HDR_SIZE(ieee) \
- ((ieee)->i_dataoffset)
+#define RIME_FRAG_DISPATCH_SIZE 0 /* 16 bit */
+#define RIME_FRAG_TAG 2 /* 16 bit */
+#define RIME_FRAG_OFFSET 4 /* 8 bit */
-#define FRAME_DATA_START(ieee) \
- ((FAR uint8_t *)((ieee)->i_frame) + (ieee)->i_dataoffset)
-#define FRAME_DATA_SIZE(ieee) \
- ((ieee)->i_framelen - (ieee)->i_dataoffset)
+/* Define the Rime buffer as a byte array */
-#define FRAME_REMAINING(ieee) \
- (CONFIG_NET_6LOWPAN_FRAMELEN - (ieee)->i_framelen)
-#define FRAME_SIZE(ieee) \
- ((ieee)->i_framelen)
+#define RIME_HC1_DISPATCH 0 /* 8 bit */
+#define RIME_HC1_ENCODING 1 /* 8 bit */
+#define RIME_HC1_TTL 2 /* 8 bit */
+
+#define RIME_HC1_HC_UDP_DISPATCH 0 /* 8 bit */
+#define RIME_HC1_HC_UDP_HC1_ENCODING 1 /* 8 bit */
+#define RIME_HC1_HC_UDP_UDP_ENCODING 2 /* 8 bit */
+#define RIME_HC1_HC_UDP_TTL 3 /* 8 bit */
+#define RIME_HC1_HC_UDP_PORTS 4 /* 8 bit */
+#define RIME_HC1_HC_UDP_CHKSUM 5 /* 16 bit */
/* These are some definitions of element values used in the FCF. See the
* IEEE802.15.4 spec for details.
*/
-#define FRAME802154_BEACONFRAME 0x00
-#define FRAME802154_DATAFRAME 0x01
-#define FRAME802154_ACKFRAME 0x02
-#define FRAME802154_CMDFRAME 0x03
+#define FRAME802154_FRAMETYPE_SHIFT (0) /* Bits 0-2: Frame type */
+#define FRAME802154_FRAMETYPE_MASK (7 << FRAME802154_FRAMETYPE_SHIFT)
+#define FRAME802154_SECENABLED_SHIFT (3) /* Bit 3: Security enabled */
+#define FRAME802154_FRAMEPENDING_SHIFT (4) /* Bit 4: Frame pending */
+#define FRAME802154_ACKREQUEST_SHIFT (5) /* Bit 5: ACK request */
+#define FRAME802154_PANIDCOMP_SHIFT (6) /* Bit 6: PANID compression */
+ /* Bits 7-9: Reserved */
+#define FRAME802154_DSTADDR_SHIFT (2) /* Bits 10-11: Dest address mode */
+#define FRAME802154_DSTADDR_MASK (3 << FRAME802154_DSTADDR_SHIFT)
+#define FRAME802154_VERSION_SHIFT (4) /* Bit 12-13: Frame version */
+#define FRAME802154_VERSION_MASK (3 << FRAME802154_VERSION_SHIFT)
+#define FRAME802154_SRCADDR_SHIFT (6) /* Bits 14-15: Source address mode */
+#define FRAME802154_SRCADDR_MASK (3 << FRAME802154_SRCADDR_SHIFT)
-#define FRAME802154_BEACONREQ 0x07
+/* Unshifted values for use in struct frame802154_fcf_s */
-#define FRAME802154_IEEERESERVED 0x00
-#define FRAME802154_NOADDR 0x00 /* Only valid for ACK or Beacon frames */
-#define FRAME802154_SHORTADDRMODE 0x02
-#define FRAME802154_LONGADDRMODE 0x03
+#define FRAME802154_BEACONFRAME (0)
+#define FRAME802154_DATAFRAME (1)
+#define FRAME802154_ACKFRAME (2)
+#define FRAME802154_CMDFRAME (3)
+
+#define FRAME802154_BEACONREQ (7)
+
+#define FRAME802154_IEEERESERVED (0)
+#define FRAME802154_NOADDR (0) /* Only valid for ACK or Beacon frames */
+#define FRAME802154_SHORTADDRMODE (2)
+#define FRAME802154_LONGADDRMODE (3)
#define FRAME802154_NOBEACONS 0x0f
#define FRAME802154_BROADCASTADDR 0xffff
#define FRAME802154_BROADCASTPANDID 0xffff
-#define FRAME802154_IEEE802154_2003 0x00
-#define FRAME802154_IEEE802154_2006 0x01
+#define FRAME802154_IEEE802154_2003 (0)
+#define FRAME802154_IEEE802154_2006 (1)
-#define FRAME802154_SECURITY_LEVEL_NONE 0
-#define FRAME802154_SECURITY_LEVEL_128 3
+#define FRAME802154_SECURITY_LEVEL_NONE (0)
+#define FRAME802154_SECURITY_LEVEL_128 (3)
+
+/* Packet buffer Definitions */
+
+#define PACKETBUF_ATTR_PACKET_TYPE_DATA 0
+#define PACKETBUF_ATTR_PACKET_TYPE_ACK 1
+#define PACKETBUF_ATTR_PACKET_TYPE_STREAM 2
+#define PACKETBUF_ATTR_PACKET_TYPE_STREAM_END 3
+#define PACKETBUF_ATTR_PACKET_TYPE_TIMESTAMP 4
+
+/* Packet buffer attributes (indices into i_pktattr) */
+
+#define PACKETBUF_ATTR_NONE 0
+
+/* Scope 0 attributes: used only on the local node. */
+
+#define PACKETBUF_ATTR_CHANNEL 1
+#define PACKETBUF_ATTR_NETWORK_ID 2
+#define PACKETBUF_ATTR_LINK_QUALITY 3
+#define PACKETBUF_ATTR_RSSI 4
+#define PACKETBUF_ATTR_TIMESTAMP 5
+#define PACKETBUF_ATTR_RADIO_TXPOWER 6
+#define PACKETBUF_ATTR_LISTEN_TIME 7
+#define PACKETBUF_ATTR_TRANSMIT_TIME 8
+#define PACKETBUF_ATTR_MAX_MAC_TRANSMISSIONS 9
+#define PACKETBUF_ATTR_MAC_SEQNO 10
+#define PACKETBUF_ATTR_MAC_ACK 11
+
+/* Scope 1 attributes: used between two neighbors only. */
+
+#define PACKETBUF_ATTR_RELIABLE 12
+#define PACKETBUF_ATTR_PACKET_ID 13
+#define PACKETBUF_ATTR_PACKET_TYPE 14
+#define PACKETBUF_ATTR_REXMIT 15
+#define PACKETBUF_ATTR_MAX_REXMIT 16
+#define PACKETBUF_ATTR_NUM_REXMIT 17
+#define PACKETBUF_ATTR_PENDING 18
+
+/* Scope 2 attributes: used between end-to-end nodes. */
+
+#define PACKETBUF_ATTR_HOPS 11
+#define PACKETBUF_ATTR_TTL 20
+#define PACKETBUF_ATTR_EPACKET_ID 21
+#define PACKETBUF_ATTR_EPACKET_TYPE 22
+#define PACKETBUF_ATTR_ERELIABLE 23
+
+#define PACKETBUF_NUM_ATTRS 24
+
+/* Addresses (indices into i_pktaddr) */
+
+#define PACKETBUF_ADDR_SENDER 0
+#define PACKETBUF_ADDR_RECEIVER 1
+#define PACKETBUF_ADDR_ESENDER 2
+#define PACKETBUF_ADDR_ERECEIVER 3
+
+#define PACKETBUF_NUM_ADDRS 4
+
+/* Address compressibility test macros **************************************/
+
+/* Check whether we can compress the IID in address 'a' to 16 bits. This is
+ * used for unicast addresses only, and is true if the address is on the
+ * format ::0000:00ff:fe00:XXXX
+ *
+ * NOTE: we currently assume 64-bits prefixes
+ */
+
+/* Check whether we can compress the IID in address 'a' to 16 bits. This is
+ * used for unicast addresses only, and is true if the address is on the
+ * format ::0000:00ff:fe00:XXXX.
+ *
+ * NOTE: we currently assume 64-bits prefixes. Big-endian, network order is
+ * assumed.
+ */
+
+#define SIXLOWPAN_IS_IID_16BIT_COMPRESSABLE(a) \
+ ((((a)[4]) == 0x0000) && (((a)[5]) == HTONS(0x00ff)) && \
+ (((a)[6]) == 0xfe00))
+
+/* Check whether the 9-bit group-id of the compressed multicast address is
+ * known. It is true if the 9-bit group is the all nodes or all routers
+ * group. Parameter 'a' is typed uint8_t *
+ */
+
+#define SIXLOWPAN_IS_MCASTADDR_DECOMPRESSABLE(a) \
+ (((*a & 0x01) == 0) && \
+ ((*(a + 1) == 0x01) || (*(a + 1) == 0x02)))
+
+/* Check whether the 112-bit group-id of the multicast address is mappable
+ * to a 9-bit group-id. It is true if the group is the all nodes or all
+ * routers group:
+ *
+ * XXXX:0000:0000:0000:0000:0000:0000:0001 All nodes address
+ * XXXX:0000:0000:0000:0000:0000:0000:0002 All routers address
+ */
+
+#define SIXLOWPAN_IS_MCASTADDR_COMPRESSABLE(a) \
+ ((a)[1] == 0 && (a)[2] == 0 && (a)[3] == 0 && \
+ (a)[4] == 0 && (a)[5] == 0 && (a)[6] == 0 && \
+ ((a)[7] == HTONS(0x0001) || (a)[7] == HTONS(0x0002)))
+
+/* FFXX:0000:0000:0000:0000:00XX:XXXX:XXXX */
+
+#define SIXLOWPAN_IS_MCASTADDR_COMPRESSABLE48(a) \
+ ((a)[1] == 0 && (a)[2] == 0 && (a)[3] == 0 && \
+ (a)[4] == 0 && (((a)[5] & HTONS(0xff00)) == 0))
+
+/* FFXX:0000:0000:0000:0000:0000:00XX:XXXX */
+
+#define SIXLOWPAN_IS_MCASTADDR_COMPRESSABLE32(a) \
+ ((a)[1] == 0 && (a)[2] == 0 && (a)[3] == 0 && \
+ (a)[4] == 0 && (a)[5] == 0 && ((a)[6] & HTONS(0xff00)) == 0)
+
+/* FF02:0000:0000:0000:0000:0000:0000:00XX */
+
+#define SIXLOWPAN_IS_MCASTADDR_COMPRESSABLE8(a) \
+ ((((a)[0] & HTONS(0x00ff)) == HTONS(0x0002)) && \
+ (a)[1] == 0 && (a)[2] == 0 && (a)[3] == 0 && \
+ (a)[4] == 0 && (a)[5] == 0 && (a)[6] == 0 && \
+ (((a)[7] & HTONS(0xff00)) == 0x0000))
+
+/* General helper macros ****************************************************/
+
+#define GETINT16(ptr,index) \
+ ((((uint16_t)((ptr)[index])) << 8) | ((uint16_t)(((ptr)[(index) + 1]))))
+#define PUTINT16(ptr,index,value) \
+ do \
+ { \
+ (ptr)[index] = ((uint16_t)(value) >> 8) & 0xff; \
+ (ptr)[index + 1] = (uint16_t)(value) & 0xff; \
+ } \
+ while(0)
+
+/* Debug ********************************************************************/
+
+#ifdef CONFIG_NET_6LOWPAN_DUMPBUFFER
+# define sixlowpan_dumpbuffer(m,b,s) ninfodumpbuffer(m,b,s)
+#else
+# define sixlowpan_dumpbuffer(m,b,s)
+#endif
/****************************************************************************
* Public Types
@@ -223,25 +388,53 @@ struct frame802154_s
uint16_t src_pid; /* Source PAN ID */
uint8_t src_addr[8]; /* Source address */
struct frame802154_aux_hdr_s aux_hdr; /* Aux security header */
- uint8_t *payload; /* Pointer to 802.15.4 frame payload */
- uint8_t payload_len; /* Length of payload field */
};
/****************************************************************************
* Public Data
****************************************************************************/
-/* A pointer to the optional, architecture-specific compressor */
+/* The following data values are used to hold intermediate settings while
+ * processing IEEE802.15.4 frames. These globals are shared with incoming
+ * and outgoing frame processing and possibly with mutliple IEEE802.15.4 MAC
+ * devices. The network lock provides exclusive use of these globals
+ * during that processing
+ */
-struct sixlowpan_nhcompressor_s; /* Foward reference */
-extern FAR struct sixlowpan_nhcompressor_s *g_sixlowpan_compressor;
+/* A pointer to the rime buffer.
+ *
+ * We initialize it to the beginning of the rime buffer, then access
+ * different fields by updating the offset ieee->g_frame_hdrlen.
+ */
-#ifdef CONFIG_NET_6LOWPAN_SNIFFER
-/* Rime Sniffer support for one single listener to enable trace of IP */
+extern FAR uint8_t *g_rimeptr;
-struct sixlowpan_rime_sniffer_s; /* Foward reference */
-extern FAR struct sixlowpan_rime_sniffer_s *g_sixlowpan_sniffer;
-#endif
+/* The length of the payload in the Rime buffer.
+ *
+ * The payload is what comes after the compressed or uncompressed headers
+ * (can be the IP payload if the IP header only is compressed or the UDP
+ * payload if the UDP header is also compressed)
+ */
+
+extern uint8_t g_rime_payloadlen;
+
+/* g_uncomp_hdrlen is the length of the headers before compression (if HC2
+ * is used this includes the UDP header in addition to the IP header).
+ */
+
+extern uint8_t g_uncomp_hdrlen;
+
+/* g_frame_hdrlen is the total length of (the processed) 6lowpan headers
+ * (fragment headers, IPV6 or HC1, HC2, and HC1 and HC2 non compressed
+ * fields).
+ */
+
+extern uint8_t g_frame_hdrlen;
+
+/* Packet buffer metadata: Attributes and addresses */
+
+extern uint16_t g_pktattrs[PACKETBUF_NUM_ATTRS];
+extern struct rimeaddr_s g_pktaddrs[PACKETBUF_NUM_ADDRS];
/****************************************************************************
* Public Types
@@ -253,7 +446,9 @@ extern FAR struct sixlowpan_rime_sniffer_s *g_sixlowpan_sniffer;
struct net_driver_s; /* Forward reference */
struct ieee802154_driver_s; /* Forward reference */
+struct ipv6_hdr_s; /* Forward reference */
struct rimeaddr_s; /* Forward reference */
+struct iob_s; /* Forward reference */
/****************************************************************************
* Name: sixlowpan_send
@@ -263,19 +458,19 @@ struct rimeaddr_s; /* Forward reference */
* it to be sent on an 802.15.4 network using 6lowpan. Called from common
* UDP/TCP send logic.
*
- * The payload data is in the caller 'buf' and is of length 'len'.
- * Compressed headers will be added and if necessary the packet is
- * fragmented. The resulting packet/fragments are put in dev->d_buf and
- * the first frame will be delivered to the 802.15.4 MAC. via ieee->i_frame.
- *
- * Input Parmeters:
+ * The payload data is in the caller 'buf' and is of length 'buflen'.
+ * Compressed headers will be added and if necessary the packet is
+ * fragmented. The resulting packet/fragments are put in ieee->i_framelist
+ * and the entire list of frames will be delivered to the 802.15.4 MAC via
+ * ieee->i_framelist.
*
* Input Parameters:
- * dev - The IEEE802.15.4 MAC network driver interface.
- * ipv6 - IPv6 plus TCP or UDP headers.
- * buf - Data to send
- * len - Length of data to send
- * raddr - The MAC address of the destination
+ * dev - The IEEE802.15.4 MAC network driver interface.
+ * destip - IPv6 plus TCP or UDP headers.
+ * buf - Data to send
+ * buflen - Length of data to send
+ * raddr - The MAC address of the destination
+ * timeout - Send timeout in deciseconds
*
* Returned Value:
* Ok is returned on success; Othewise a negated errno value is returned.
@@ -289,11 +484,12 @@ struct rimeaddr_s; /* Forward reference */
****************************************************************************/
int sixlowpan_send(FAR struct net_driver_s *dev,
- FAR const struct ipv6_hdr_s *ipv6, FAR const void *buf,
- size_t len, FAR const struct rimeaddr_s *raddr);
+ FAR const struct ipv6_hdr_s *destip, FAR const void *buf,
+ size_t buflen, FAR const struct rimeaddr_s *raddr,
+ uint16_t timeout);
/****************************************************************************
- * Function: sixlowpan_hdrlen
+ * Function: sixlowpan_send_hdrlen
*
* Description:
* This function is before the first frame has been sent in order to
@@ -311,7 +507,7 @@ int sixlowpan_send(FAR struct net_driver_s *dev,
*
****************************************************************************/
-int sixlowpan_hdrlen(FAR struct ieee802154_driver_s *ieee,
+int sixlowpan_send_hdrlen(FAR struct ieee802154_driver_s *ieee,
uint16_t dest_panid);
/****************************************************************************
@@ -323,6 +519,7 @@ int sixlowpan_hdrlen(FAR struct ieee802154_driver_s *ieee,
*
* Input parameters:
* ieee - A reference IEEE802.15.4 MAC network device structure.
+ * iob - The IOB in which to create the frame.
* dest_panid - PAN ID of the destination. May be 0xffff if the destination
* is not associated.
*
@@ -333,7 +530,45 @@ int sixlowpan_hdrlen(FAR struct ieee802154_driver_s *ieee,
****************************************************************************/
int sixlowpan_framecreate(FAR struct ieee802154_driver_s *ieee,
- uint16_t dest_panid);
+ FAR struct iob_s *iob, uint16_t dest_panid);
+
+/****************************************************************************
+ * Name: sixlowpan_queue_frames
+ *
+ * Description:
+ * Process an outgoing UDP or TCP packet. This function is called from
+ * send interrupt logic when a TX poll is received. It formates the
+ * list of frames to be sent by the IEEE802.15.4 MAC driver.
+ *
+ * The payload data is in the caller 'buf' and is of length 'buflen'.
+ * Compressed headers will be added and if necessary the packet is
+ * fragmented. The resulting packet/fragments are put in ieee->i_framelist
+ * and the entire list of frames will be delivered to the 802.15.4 MAC via
+ * ieee->i_framelist.
+ *
+ * Input Parameters:
+ * ieee - The IEEE802.15.4 MAC driver instance
+ * ipv6hdr - IPv6 header followed by TCP or UDP header.
+ * buf - Beginning of the packet packet to send (with IPv6 + protocol
+ * headers)
+ * buflen - Length of data to send (include IPv6 and protocol headers)
+ * destmac - The IEEE802.15.4 MAC address of the destination
+ *
+ * Returned Value:
+ * Ok is returned on success; Othewise a negated errno value is returned.
+ * This function is expected to fail if the driver is not an IEEE802.15.4
+ * MAC network driver. In that case, the UDP/TCP will fall back to normal
+ * IPv4/IPv6 formatting.
+ *
+ * Assumptions:
+ * Called with the network locked.
+ *
+ ****************************************************************************/
+
+int sixlowpan_queue_frames(FAR struct ieee802154_driver_s *ieee,
+ FAR const struct ipv6_hdr_s *ipv6hdr,
+ FAR const void *buf, size_t buflen,
+ FAR const struct rimeaddr_s *destmac);
/****************************************************************************
* Name: sixlowpan_hc06_initialize
@@ -359,7 +594,7 @@ void sixlowpan_hc06_initialize(void);
#endif
/****************************************************************************
- * Name: sixlowpan_hc06_initialize
+ * Name: sixlowpan_compresshdr_hc06
*
* Description:
* Compress IP/UDP header
@@ -375,8 +610,11 @@ void sixlowpan_hc06_initialize(void);
* compression
*
* Input Parameters:
- * dev - A reference to the IEE802.15.4 network device state
- * destaddr - L2 destination address, needed to compress IP dest
+ * ieee - A reference to the IEE802.15.4 network device state
+ * ipv6 - The IPv6 header to be compressed
+ * destmac - L2 destination address, needed to compress the IP
+ * destination field
+ * fptr - Pointer to frame to be compressed.
*
* Returned Value:
* None
@@ -384,12 +622,14 @@ void sixlowpan_hc06_initialize(void);
****************************************************************************/
#ifdef CONFIG_NET_6LOWPAN_COMPRESSION_HC06
-void sixlowpan_compresshdr_hc06(FAR struct net_driver_s *dev,
- FAR struct rimeaddr_s *destaddr);
+void sixlowpan_compresshdr_hc06(FAR struct ieee802154_driver_s *ieee,
+ FAR const struct ipv6_hdr_s *ipv6,
+ FAR const struct rimeaddr_s *destmac,
+ FAR uint8_t *fptr);
#endif
/****************************************************************************
- * Name: sixlowpan_hc06_initialize
+ * Name: sixlowpan_uncompresshdr_hc06
*
* Description:
* Uncompress HC06 (i.e., IPHC and LOWPAN_UDP) headers and put them in
@@ -398,14 +638,16 @@ void sixlowpan_compresshdr_hc06(FAR struct net_driver_s *dev,
* This function is called by the input function when the dispatch is HC06.
* We process the packet in the rime buffer, uncompress the header fields,
* and copy the result in the sixlowpan buffer. At the end of the
- * decompression, g_rime_hdrlen and g_uncompressed_hdrlen are set to the
+ * decompression, g_frame_hdrlen and g_uncompressed_hdrlen are set to the
* appropriate values
*
* Input Parmeters:
- * dev - A reference to the IEE802.15.4 network device state
- * iplen - Equal to 0 if the packet is not a fragment (IP length is then
- * inferred from the L2 length), non 0 if the packet is a 1st
- * fragment.
+ * ieee - A reference to the IEE802.15.4 network device state
+ * iplen - Equal to 0 if the packet is not a fragment (IP length is then
+ * inferred from the L2 length), non 0 if the packet is a first
+ * fragment.
+ * iob - Pointer to the IOB containing the received frame.
+ * payptr - Pointer to the frame data payload.
*
* Returned Value:
* None
@@ -413,8 +655,9 @@ void sixlowpan_compresshdr_hc06(FAR struct net_driver_s *dev,
****************************************************************************/
#ifdef CONFIG_NET_6LOWPAN_COMPRESSION_HC06
-void sixlowpan_uncompresshdr_hc06(FAR struct net_driver_s *dev,
- uint16_t iplen);
+void sixlowpan_uncompresshdr_hc06(FAR struct ieee802154_driver_s *ieee,
+ uint16_t iplen, FAR struct iob_s *iob,
+ FAR uint8_t *payptr);
#endif
/****************************************************************************
@@ -428,9 +671,11 @@ void sixlowpan_uncompresshdr_hc06(FAR struct net_driver_s *dev,
* uip_buf buffer.
*
* Input Parmeters:
- * dev - A reference to the IEE802.15.4 network device state
- * destaddr - L2 destination address, needed to compress the IP
- * destination field
+ * ieee - A reference to the IEE802.15.4 network device state
+ * ipv6 - The IPv6 header to be compressed
+ * destmac - L2 destination address, needed to compress the IP
+ * destination field
+ * fptr - Pointer to frame to be compressed.
*
* Returned Value:
* None
@@ -438,8 +683,10 @@ void sixlowpan_uncompresshdr_hc06(FAR struct net_driver_s *dev,
****************************************************************************/
#ifdef CONFIG_NET_6LOWPAN_COMPRESSION_HC1
-void sixlowpan_compresshdr_hc1(FAR struct net_driver_s *dev,
- FAR struct rimeaddr_s *destaddr);
+void sixlowpan_compresshdr_hc1(FAR struct ieee802154_driver_s *ieee,
+ FAR const struct ipv6_hdr_s *ipv6,
+ FAR const struct rimeaddr_s *destmac,
+ FAR uint8_t *fptr);
#endif
/****************************************************************************
@@ -451,14 +698,16 @@ void sixlowpan_compresshdr_hc1(FAR struct net_driver_s *dev,
* This function is called by the input function when the dispatch is
* HC1. It processes the packet in the rime buffer, uncompresses the
* header fields, and copies the result in the sixlowpan buffer. At the
- * end of the decompression, g_rime_hdrlen and uncompressed_hdr_len
+ * end of the decompression, g_frame_hdrlen and uncompressed_hdr_len
* are set to the appropriate values
*
* Input Parameters:
- * dev - A reference to the IEE802.15.4 network device state
+ * ieee - A reference to the IEE802.15.4 network device state
* iplen - Equal to 0 if the packet is not a fragment (IP length is then
- * inferred from the L2 length), non 0 if the packet is a 1st
+ * inferred from the L2 length), non 0 if the packet is a first
* fragment.
+ * iob - Pointer to the IOB containing the received frame.
+ * payptr - Pointer to the frame data payload.
*
* Returned Value:
* None
@@ -466,20 +715,40 @@ void sixlowpan_compresshdr_hc1(FAR struct net_driver_s *dev,
****************************************************************************/
#ifdef CONFIG_NET_6LOWPAN_COMPRESSION_HC1
-void sixlowpan_uncompresshdr_hc1(FAR struct net_driver_s *dev,
- uint16_t ip_len);
+int sixlowpan_uncompresshdr_hc1(FAR struct ieee802154_driver_s *ieee,
+ uint16_t ip_len, FAR struct iob_s *iob,
+ FAR uint8_t *payptr);
#endif
/****************************************************************************
- * Name: sixlowpan_frame_hdralloc
+ * Name: sixlowpan_islinklocal, sixlowpan_ipfromrime, sixlowpan_rimefromip,
+ * and sixlowpan_ismacbased
*
* Description:
- * Allocate space for a header within the frame buffer (i_frame).
+ * sixlowpan_ipfromrime: Create a link local IPv6 address from a rime
+ * address.
+ *
+ * sixlowpan_rimefromip: Extract the rime address from a link local IPv6
+ * address.
+ *
+ * sixlowpan_islinklocal and sixlowpan_ismacbased will return true for
+ * address created in this fashion.
+ *
+ * 128 112 96 80 64 48 32 16
+ * ---- ---- ---- ---- ---- ---- ---- ----
+ * fe80 0000 0000 0000 xxxx 0000 0000 0000 2-byte Rime address (VALID?)
+ * fe80 0000 0000 0000 xxxx xxxx xxxx xxxx 8-byte Rime address
*
****************************************************************************/
-int sixlowpan_frame_hdralloc(FAR struct ieee802154_driver_s *ieee,
- int size);
+#define sixlowpan_islinklocal(ipaddr) ((ipaddr)[0] == NTOHS(0xfe80))
+
+void sixlowpan_ipfromrime(FAR const struct rimeaddr_s *rime,
+ net_ipv6addr_t ipaddr);
+void sixlowpan_rimefromip(const net_ipv6addr_t ipaddr,
+ FAR struct rimeaddr_s *rime);
+bool sixlowpan_ismacbased(const net_ipv6addr_t ipaddr,
+ FAR const struct rimeaddr_s *rime);
#endif /* CONFIG_NET_6LOWPAN */
#endif /* _NET_SIXLOWPAN_SIXLOWPAN_INTERNAL_H */
diff --git a/net/sixlowpan/sixlowpan_send.c b/net/sixlowpan/sixlowpan_send.c
index 9a7b0095cdb..98cc577f5f5 100644
--- a/net/sixlowpan/sixlowpan_send.c
+++ b/net/sixlowpan/sixlowpan_send.c
@@ -4,18 +4,6 @@
* Copyright (C) 2017 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt
*
- * Parts of this file derive from Contiki:
- *
- * Copyright (c) 2008, Swedish Institute of Computer Science.
- * All rights reserved.
- * Authors: Adam Dunkels
- * Nicolas Tsiftes
- * Niclas Finne
- * Mathilde Durvy
- * Julien Abeille
- * Joakim Eriksson
- * Joel Hoglund
- *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@@ -23,23 +11,25 @@
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the Institute nor the names of its contributors
- * may be used to endorse or promote products derived from this software
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * 3. Neither the name NuttX nor the names of its contributors may be
+ * used to endorse or promote products derived from this software
* without specific prior written permission.
*
- * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
*
****************************************************************************/
@@ -49,160 +39,182 @@
#include
-#include
+#include
#include
#include
#include
-#include "nuttx/net/netdev.h"
-#include "nuttx/net/ip.h"
-#include "nuttx/net/tcp.h"
-#include "nuttx/net/udp.h"
-#include "nuttx/net/icmpv6.h"
-#include "nuttx/net/sixlowpan.h"
+#include
+#include
+#include
#include "netdev/netdev.h"
-#include "socket/socket.h"
-#include "tcp/tcp.h"
-#include "udp/udp.h"
+#include "devif/devif.h"
+
#include "sixlowpan/sixlowpan_internal.h"
#ifdef CONFIG_NET_6LOWPAN
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/* These are temporary stubs. Something like this would be needed to
+ * monitor the health of a IPv6 neighbor.
+ */
+
+#define neighbor_reachable(dev)
+#define neighbor_notreachable(dev)
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+/* This is the state data provided to the send interrupt logic. No actions
+ * can be taken until the until we receive the TX poll, then we can call
+ * sixlowpan_queue_frames() with this data strurcture.
+ */
+
+struct sixlowpan_send_s
+{
+ FAR struct devif_callback_s *s_cb; /* Reference to callback instance */
+ sem_t s_waitsem; /* Supports waiting for driver events */
+ int s_result; /* The result of the transfer */
+ uint16_t s_timeout; /* Send timeout in deciseconds */
+ systime_t s_time; /* Last send time for determining timeout */
+ FAR const struct ipv6_hdr_s *s_ipv6hdr; /* IPv6 header, followed by UDP or TCP header. */
+ FAR const struct rimeaddr_s *s_destmac; /* Destination MAC address */
+ FAR const void *s_buf; /* Data to send */
+ size_t s_len; /* Length of data in buf */
+};
+
/****************************************************************************
* Private Functions
****************************************************************************/
/****************************************************************************
- * Name: sixlowpan_set_pktattrs
+ * Function: send_timeout
*
* Description:
- * Setup some packet buffer attributes
+ * Check for send timeout.
*
* Input Parameters:
- * ieee - Pointer to IEEE802.15.4 MAC driver structure.
- * ipv6 - Pointer to the IPv6 header to "compress"
+ * sinfo - Send state structure reference
*
* Returned Value:
- * None
+ * TRUE:timeout FALSE:no timeout
+ *
+ * Assumptions:
+ * The network is locked
*
****************************************************************************/
-static void sixlowpan_set_pktattrs(FAR struct ieee802154_driver_s *ieee,
- FAR const struct ipv6_hdr_s *ipv6)
+static inline bool send_timeout(FAR struct sixlowpan_send_s *sinfo)
{
- int attr = 0;
-
- /* Set protocol in NETWORK_ID */
-
- ieee->i_pktattrs[PACKETBUF_ATTR_NETWORK_ID] = ipv6->proto;
-
- /* Assign values to the channel attribute (port or type + code) */
-
- if (ipv6->proto == IP_PROTO_UDP)
- {
- FAR struct udp_hdr_s *udp = &((FAR struct ipv6udp_hdr_s *)ipv6)->udp;
-
- attr = udp->srcport;
- if (udp->destport < attr)
- {
- attr = udp->destport;
- }
- }
- else if (ipv6->proto == IP_PROTO_TCP)
- {
- FAR struct tcp_hdr_s *tcp = &((FAR struct ipv6tcp_hdr_s *)ipv6)->tcp;
-
- attr = tcp->srcport;
- if (tcp->destport < attr)
- {
- attr = tcp->destport;
- }
- }
- else if (ipv6->proto == IP_PROTO_ICMP6)
- {
- FAR struct icmpv6_iphdr_s *icmp = &((FAR struct ipv6icmp_hdr_s *)ipv6)->icmp;
-
- attr = icmp->type << 8 | icmp->code;
- }
-
- ieee->i_pktattrs[PACKETBUF_ATTR_CHANNEL] = attr;
-}
-
-/****************************************************************************
- * Name: sixlowpan_compress_ipv6hdr
- *
- * Description:
- * IPv6 dispatch "compression" function. Packets "Compression" when only
- * IPv6 dispatch is used
- *
- * There is no compression in this case, all fields are sent
- * inline. We just add the IPv6 dispatch byte before the packet.
- *
- * 0 1 2 3
- * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
- * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- * | IPv6 Dsp | IPv6 header and payload ...
- * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- *
- * Input Parameters:
- * ieee - Pointer to IEEE802.15.4 MAC driver structure.
- * ipv6 - Pointer to the IPv6 header to "compress"
- *
- * Returned Value:
- * None
- *
- ****************************************************************************/
-
-static void sixlowpan_compress_ipv6hdr(FAR struct ieee802154_driver_s *ieee,
- FAR const struct ipv6_hdr_s *ipv6)
-{
- /* Indicate the IPv6 dispatch and length */
-
- *ieee->i_rimeptr = SIXLOWPAN_DISPATCH_IPV6;
- ieee->i_rime_hdrlen += SIXLOWPAN_IPV6_HDR_LEN;
-
- /* Copy the IPv6 header and adjust pointers */
-
- memcpy(ieee->i_rimeptr + ieee->i_rime_hdrlen, ipv6, IPv6_HDRLEN);
- ieee->i_rime_hdrlen += IPv6_HDRLEN;
- ieee->i_uncomp_hdrlen += IPv6_HDRLEN;
-}
-
-/****************************************************************************
- * Name: sixlowpan_send_frame
- *
- * Description:
- * Send one frame when the IEEE802.15.4 MAC device next polls.
- *
- * Input Parameters:
- * ieee - Pointer to IEEE802.15.4 MAC driver structure.
- * ipv6 - Pointer to the IPv6 header to "compress"
- *
- * Returned Value:
- * None
- *
- ****************************************************************************/
-
-static int sixlowpan_send_frame(FAR struct ieee802154_driver_s *ieee)
-{
- /* Prepare the frame */
-#warning Missing logic
- /* Set up for the TX poll */
- /* When polled, then we need to call sixlowpan_framecreate() to create the
- * frame and copy the payload data into the frame.
+ /* Check for a timeout. Zero means none and, in that case, we will let
+ * the send wait forever.
*/
-#if 0 /* Just some notes of what needs to be done in interrupt handler */
- framer_hdrlen = sixlowpan_createframe(ieee, ieee->i_panid);
- memcpy(ieee->i_rimeptr + ieee->i_rime_hdrlen, (uint8_t *)ipv6 + ieee->i_uncomp_hdrlen, len - ieee->i_uncomp_hdrlen);
- dev->i_framelen = len - ieee->i_uncomp_hdrlen + ieee->i_rime_hdrlen;
-#endif
-#warning Missing logic
- /* Notify the IEEE802.14.5 MAC driver that we have data to be sent */
-#warning Missing logic
- /* Wait for the transfer to complete */
-#warning Missing logic
- return -ENOSYS;
+
+ if (sinfo->s_timeout != 0)
+ {
+ /* Check if the configured timeout has elapsed */
+
+ systime_t timeo_ticks = DSEC2TICK(sinfo->s_timeout);
+ systime_t elapsed = clock_systimer() - sinfo->s_time;
+
+ if (elapsed >= timeo_ticks)
+ {
+ return true;
+ }
+ }
+
+ /* No timeout */
+
+ return false;
+}
+
+/****************************************************************************
+ * Function: send_interrupt
+ *
+ * Description:
+ * This function is called from the interrupt level to perform the actual
+ * send operation when polled by the lower, device interfacing layer.
+ *
+ * Parameters:
+ * dev - The structure of the network driver that caused the interrupt
+ * conn - The connection structure associated with the socket
+ * flags - Set of events describing why the callback was invoked
+ *
+ * Returned Value:
+ * None
+ *
+ * Assumptions:
+ * The network is locked.
+ *
+ ****************************************************************************/
+
+static uint16_t send_interrupt(FAR struct net_driver_s *dev,
+ FAR void *pvconn,
+ FAR void *pvpriv, uint16_t flags)
+{
+ FAR struct sixlowpan_send_s *sinfo = (FAR struct sixlowpan_send_s *)pvpriv;
+
+ ninfo("flags: %04x: %d\n", flags);
+
+ /* Check if the IEEE802.15.4 went down */
+
+ if ((flags & NETDEV_DOWN) != 0)
+ {
+ ninfo("Device is down\n");
+ sinfo->s_result = -ENOTCONN;
+ goto end_wait;
+ }
+
+ /* Check for a poll for TX data. */
+
+ if ((flags & WPAN_NEWDATA) == 0)
+ {
+ DEBUGASSERT((flags & WPAN_POLL) != 0);
+
+ /* Transfer the frame listto the IEEE802.15.4 MAC device */
+
+ sinfo->s_result =
+ sixlowpan_queue_frames((FAR struct ieee802154_driver_s *)dev,
+ sinfo->s_ipv6hdr, sinfo->s_buf, sinfo->s_len,
+ sinfo->s_destmac);
+
+ flags &= ~WPAN_POLL;
+ neighbor_reachable(dev);
+ goto end_wait;
+ }
+
+ /* Check for a timeout. */
+
+ if (send_timeout(sinfo))
+ {
+ /* Yes.. report the timeout */
+
+ nwarn("WARNING: SEND timeout\n");
+ sinfo->s_result = -ETIMEDOUT;
+ neighbor_notreachable(dev);
+ goto end_wait;
+ }
+
+ /* Continue waiting */
+
+ return flags;
+
+end_wait:
+ /* Do not allow any further callbacks */
+
+ sinfo->s_cb->flags = 0;
+ sinfo->s_cb->priv = NULL;
+ sinfo->s_cb->event = NULL;
+
+ /* Wake up the waiting thread */
+
+ sem_post(&sinfo->s_waitsem);
+ return flags;
}
/****************************************************************************
@@ -217,19 +229,19 @@ static int sixlowpan_send_frame(FAR struct ieee802154_driver_s *ieee)
* it to be sent on an 802.15.4 network using 6lowpan. Called from common
* UDP/TCP send logic.
*
- * The payload data is in the caller 'buf' and is of length 'len'.
- * Compressed headers will be added and if necessary the packet is
- * fragmented. The resulting packet/fragments are put in dev->d_buf and
- * the first frame will be delivered to the 802.15.4 MAC. via ieee->i_frame.
- *
- * Input Parmeters:
+ * The payload data is in the caller 'buf' and is of length 'len'.
+ * Compressed headers will be added and if necessary the packet is
+ * fragmented. The resulting packet/fragments are put in ieee->i_framelist
+ * and the entire list of frames will be delivered to the 802.15.4 MAC via
+ * ieee->i_framelist.
*
* Input Parameters:
- * dev - The IEEE802.15.4 MAC network driver interface.
- * ipv6 - IPv6 plus TCP or UDP headers.
- * buf - Data to send
- * len - Length of data to send
- * raddr - The IEEE802.15.4 MAC address of the destination
+ * dev - The IEEE802.15.4 MAC network driver interface.
+ * ipv6hdr - IPv6 header followed by TCP or UDP header.
+ * buf - Data to send
+ * len - Length of data to send
+ * destmac - The IEEE802.15.4 MAC address of the destination
+ * timeout - Send timeout in deciseconds
*
* Returned Value:
* Ok is returned on success; Othewise a negated errno value is returned.
@@ -243,200 +255,71 @@ static int sixlowpan_send_frame(FAR struct ieee802154_driver_s *ieee)
****************************************************************************/
int sixlowpan_send(FAR struct net_driver_s *dev,
- FAR const struct ipv6_hdr_s *ipv6, FAR const void *buf,
- size_t len, FAR const struct rimeaddr_s *raddr)
+ FAR const struct ipv6_hdr_s *ipv6hdr, FAR const void *buf,
+ size_t len, FAR const struct rimeaddr_s *destmac,
+ uint16_t timeout)
{
- FAR struct ieee802154_driver_s *ieee = (FAR struct ieee802154_driver_s *)dev;
+ struct sixlowpan_send_s sinfo;
- int framer_hdrlen; /* Framer header length */
- struct rimeaddr_s dest; /* The MAC address of the destination of the packet */
- uint16_t outlen = 0; /* Number of bytes processed. */
+ /* Initialize the send state structure */
- /* Initialize device-specific data */
+ sem_init(&sinfo.s_waitsem, 0, 0);
+ (void)sem_setprotocol(&sinfo.s_waitsem, SEM_PRIO_NONE);
- FRAME_RESET(ieee);
- ieee->i_uncomp_hdrlen = 0;
- ieee->i_rime_hdrlen = 0;
- /* REVISIT: Do I need this rimeptr? */
- ieee->i_rimeptr = &dev->d_buf[PACKETBUF_HDR_SIZE];
+ sinfo.s_result = -EBUSY;
+ sinfo.s_timeout = timeout;
+ sinfo.s_time = clock_systimer();
+ sinfo.s_ipv6hdr = ipv6hdr;
+ sinfo.s_destmac = destmac;
+ sinfo.s_buf = buf;
+ sinfo.s_len = len;
- /* Reset rime buffer, packet buffer metatadata */
-
- memset(ieee->i_pktattrs, 0, PACKETBUF_NUM_ATTRS * sizeof(uint16_t));
- memset(ieee->i_pktaddrs, 0, PACKETBUF_NUM_ADDRS * sizeof(struct rimeaddr_s));
-
- ieee->i_pktattrs[PACKETBUF_ATTR_MAX_MAC_TRANSMISSIONS] =
- CONFIG_NET_6LOWPAN_MAX_MACTRANSMITS;
-
-#ifdef CONFIG_NET_6LOWPAN_SNIFFER
- if (g_sixlowpan_sniffer != NULL)
+ net_lock();
+ if (len > 0)
{
- /* Reset rime buffer, packet buffer metatadata */
+ /* Allocate resources to receive a callback.
+ *
+ * The second parameter is NULL meaning that we can get only
+ * device related events, no connect-related events.
+ */
- memset(ieee->i_pktattrs, 0, PACKETBUF_NUM_ATTRS * sizeof(uint16_t));
- memset(ieee->i_pktaddrs, 0, PACKETBUF_NUM_ADDRS * sizeof(struct rimeaddr_s));
-
- ieee->i_pktattrs[PACKETBUF_ATTR_MAX_MAC_TRANSMISSIONS] =
- CONFIG_NET_6LOWPAN_MAX_MACTRANSMITS;
-
- /* Call the attribution when the callback comes, but set attributes here */
-
- sixlowpan_set_pktattrs(ieee, ipv6);
- }
-#endif
-
- /* Reset rime buffer, packet buffer metatadata */
-
- memset(ieee->i_pktattrs, 0, PACKETBUF_NUM_ATTRS * sizeof(uint16_t));
- memset(ieee->i_pktaddrs, 0, PACKETBUF_NUM_ADDRS * sizeof(struct rimeaddr_s));
-
- ieee->i_pktattrs[PACKETBUF_ATTR_MAX_MAC_TRANSMISSIONS] =
- CONFIG_NET_6LOWPAN_MAX_MACTRANSMITS;
-
- /* Set stream mode for all TCP packets, except FIN packets. */
-
- if (ipv6->proto == IP_PROTO_TCP)
- {
- FAR const struct tcp_hdr_s *tcp = &((FAR const struct ipv6tcp_hdr_s *)ipv6)->tcp;
-
- if ((tcp->flags & TCP_FIN) == 0 &&
- (tcp->flags & TCP_CTL) != TCP_ACK)
+ sinfo.s_cb = devif_callback_alloc(dev, NULL);
+ if (sinfo.s_cb != NULL)
{
- ieee->i_pktattrs[PACKETBUF_ATTR_PACKET_TYPE] = PACKETBUF_ATTR_PACKET_TYPE_STREAM;
- }
- else if ((tcp->flags & TCP_FIN) == TCP_FIN)
- {
- ieee->i_pktattrs[PACKETBUF_ATTR_PACKET_TYPE] = PACKETBUF_ATTR_PACKET_TYPE_STREAM_END;
+ int ret;
+
+ /* Set up the callback in the connection */
+
+ sinfo.s_cb->flags = (NETDEV_DOWN | WPAN_POLL);
+ sinfo.s_cb->priv = (FAR void *)&sinfo;
+ sinfo.s_cb->event = send_interrupt;
+
+ /* Notify the the IEEE802.15.4 MAC that we have data to send. */
+
+ netdev_txnotify_dev(dev);
+
+ /* Wait for the send to complete or an error to occur: NOTES: (1)
+ * net_lockedwait will also terminate if a signal is received, (2) interrupts
+ * may be disabled! They will be re-enabled while the task sleeps and
+ * automatically re-enabled when the task restarts.
+ */
+
+ ret = net_lockedwait(&sinfo.s_waitsem);
+ if (ret < 0)
+ {
+ sinfo.s_result = -get_errno();
+ }
+
+ /* Make sure that no further interrupts are processed */
+
+ devif_dev_callback_free(dev, sinfo.s_cb);
}
}
- /* The destination address will be tagged to each outbound packet. If the
- * argument raddr is NULL, we are sending a broadcast packet.
- */
+ sem_destroy(&sinfo.s_waitsem);
+ net_unlock();
- if (raddr == NULL)
- {
- memset(&dest, 0, sizeof(struct rimeaddr_s));
- }
- else
- {
- rimeaddr_copy(&dest, (FAR const struct rimeaddr_s *)raddr);
- }
-
- ninfo("Sending packet len %d\n", len);
-
-#ifndef CONFIG_NET_6LOWPAN_COMPRESSION_IPv6
- if (len >= CONFIG_NET_6LOWPAN_COMPRESSION_THRESHOLD)
- {
- /* Try to compress the headers */
-
-#if defined(CONFIG_NET_6LOWPAN_COMPRESSION_HC1)
- sixlowpan_compresshdr_hc1(dev, &dest);
-#elif defined(CONFIG_NET_6LOWPAN_COMPRESSION_HC06)
- sixlowpan_compresshdr_hc06(dev, &dest);
-#else
-# error No compression specified
-#endif
- }
- else
-#endif /* !CONFIG_NET_6LOWPAN_COMPRESSION_IPv6 */
- {
- /* Small.. use IPv6 dispatch (no compression) */
-
- sixlowpan_compress_ipv6hdr(ieee, ipv6);
- }
-
- ninfo("Header of len %d\n", ieee->i_rime_hdrlen);
-
- rimeaddr_copy(&ieee->i_pktaddrs[PACKETBUF_ADDR_RECEIVER], &dest);
-
- /* Pre-calculate frame header length. */
-
- framer_hdrlen = sixlowpan_hdrlen(ieee, ieee->i_panid);
- if (framer_hdrlen < 0)
- {
- /* Failed to determine the size of the header failed. */
-
- nerr("ERROR: sixlowpan_framecreate() failed: %d\n", framer_hdrlen);
- return framer_hdrlen;
- }
-
- /* Check if we need to fragment the packet into several frames */
-
- if ((int)len - (int)ieee->i_uncomp_hdrlen >
- (int)CONFIG_NET_6LOWPAN_MAXPAYLOAD - framer_hdrlen -
- (int)ieee->i_rime_hdrlen)
- {
-#if CONFIG_NET_6LOWPAN_FRAG
- /* The outbound IPv6 packet is too large to fit into a single 15.4
- * packet, so we fragment it into multiple packets and send them.
- * The first fragment contains frag1 dispatch, then
- * IPv6/HC1/HC06/HC_UDP dispatchs/headers.
- * The following fragments contain only the fragn dispatch.
- */
-
- ninfo("Fragmentation sending packet len %d\n", len);
-
- /* Create 1st Fragment */
-# warning Missing logic
-
- /* Move HC1/HC06/IPv6 header */
-# warning Missing logic
-
- /* FRAG1 dispatch + header
- * Note that the length is in units of 8 bytes
- */
-# warning Missing logic
-
- /* Copy payload and send */
-# warning Missing logic
-
- /* Check TX result. */
-# warning Missing logic
-
- /* Set outlen to what we already sent from the IP payload */
-# warning Missing logic
-
- /* Create following fragments
- * Datagram tag is already in the buffer, we need to set the
- * FRAGN dispatch and for each fragment, the offset
- */
-# warning Missing logic
-
- while (outlen < len)
- {
- /* Copy payload and send */
-# warning Missing logic
-
- ninfo("sixlowpan output: fragment offset %d, len %d, tag %d\n",
- outlen >> 3, g_rime_payloadlen, g_mytag);
-
-# warning Missing logic
- sixlowpan_send_frame(ieee);
-
- /* Check tx result. */
-# warning Missing logic
- }
-
- return -ENOSYS;
-#else
- nerr("ERROR: Packet too large: %d\n", len);
- nerr(" Cannot to be sent without fragmentation support\n");
- nerr(" dropping packet\n");
-
- return -E2BIG;
-#endif
- }
- else
- {
- /* The packet does not need to be fragmented just copy the "payload"
- * and send in one frame.
- */
-
- return sixlowpan_send_frame(ieee);
- }
-
- return -ENOSYS;
+ return (sinfo.s_result < 0 ? sinfo.s_result : len);
}
#endif /* CONFIG_NET_6LOWPAN */
diff --git a/net/sixlowpan/sixlowpan_tcpsend.c b/net/sixlowpan/sixlowpan_tcpsend.c
index 9928bc3d115..1ad8068a317 100644
--- a/net/sixlowpan/sixlowpan_tcpsend.c
+++ b/net/sixlowpan/sixlowpan_tcpsend.c
@@ -39,21 +39,92 @@
#include
+#include
#include
#include
#include
#include "nuttx/net/netdev.h"
-#include "nuttx/net/tcp.h"
-#include "nuttx/net/sixlowpan.h"
+#include "nuttx/net/netstats.h"
#include "netdev/netdev.h"
#include "socket/socket.h"
#include "tcp/tcp.h"
+#include "utils/utils.h"
#include "sixlowpan/sixlowpan_internal.h"
#if defined(CONFIG_NET_6LOWPAN) && defined(CONFIG_NET_TCP)
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/* Buffer access helpers */
+
+#define IPv6BUF(dev) ((FAR struct ipv6_hdr_s *)((dev)->d_buf))
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: sixlowpan_tcp_chksum
+ *
+ * Description:
+ * Perform the checksum calcaultion over the IPv6, protocol headers, and
+ * data payload as necessary.
+ *
+ * Input Parameters:
+ * ipv6tcp - A reference to a structure containing the IPv6 and TCP headers.
+ * buf - The beginning of the payload data
+ * buflen - The length of the payload data.
+ *
+ * Returned Value:
+ * The calculated checksum
+ *
+ ****************************************************************************/
+
+static uint16_t sixlowpan_tcp_chksum(FAR struct ipv6tcp_hdr_s *ipv6tcp,
+ FAR const uint8_t *buf, uint16_t buflen)
+{
+ uint16_t upperlen;
+ uint16_t sum;
+
+ /* The length reported in the IPv6 header is the length of the payload
+ * that follows the header.
+ */
+
+ upperlen = ((uint16_t)ipv6tcp->ipv6.len[0] << 8) + ipv6tcp->ipv6.len[1];
+
+ /* Verify some minimal assumptions */
+
+ if (upperlen > CONFIG_NET_6LOWPAN_MTU)
+ {
+ return 0;
+ }
+
+ /* The checksum is calculated starting with a pseudo-header of IPv6 header
+ * fields according to the IPv6 standard, which consists of the source
+ * and destination addresses, the packet length and the next header field.
+ */
+
+ sum = upperlen + ipv6tcp->ipv6.proto;
+
+ /* Sum IP source and destination addresses. */
+
+ sum = chksum(sum, (FAR uint8_t *)ipv6tcp->ipv6.srcipaddr,
+ 2 * sizeof(net_ipv6addr_t));
+
+ /* Sum the TCP header */
+
+ sum = chksum(sum, (FAR uint8_t *)&ipv6tcp->tcp, TCP_HDRLEN);
+
+ /* Sum payload data. */
+
+ sum = chksum(sum, buf, buflen);
+ return (sum == 0) ? 0xffff : htons(sum);
+}
+
/****************************************************************************
* Public Functions
****************************************************************************/
@@ -68,7 +139,7 @@
* Parameters:
* psock - An instance of the internal socket structure.
* buf - Data to send
- * len - Length of data to send
+ * bulen - Length of data to send
*
* Returned Value:
* On success, returns the number of characters sent. On error,
@@ -82,14 +153,19 @@
****************************************************************************/
ssize_t psock_6lowpan_tcp_send(FAR struct socket *psock, FAR const void *buf,
- size_t len)
+ size_t buflen)
{
FAR struct tcp_conn_s *conn;
FAR struct net_driver_s *dev;
struct ipv6tcp_hdr_s ipv6tcp;
- struct rimeaddr_s dest;
+ struct rimeaddr_s destmac;
+ uint16_t timeout;
+ uint16_t iplen;
int ret;
+ ninfo("buflen %lu\n", (unsigned long)buflen);
+ sixlowpan_dumpbuffer("Outgoing TCP payload", buf, buflen);
+
DEBUGASSERT(psock != NULL && psock->s_crefs > 0);
DEBUGASSERT(psock->s_type == SOCK_STREAM);
@@ -114,7 +190,7 @@ ssize_t psock_6lowpan_tcp_send(FAR struct socket *psock, FAR const void *buf,
conn = (FAR struct tcp_conn_s *)psock->s_conn;
DEBUGASSERT(conn != NULL);
-#if defined(CONFIG_NET_IPv4) && defined(CONFIG_NET_IPv6)
+#ifdef CONFIG_NET_IPv4
/* Ignore if not IPv6 domain */
if (conn->domain != PF_INET6)
@@ -128,14 +204,22 @@ ssize_t psock_6lowpan_tcp_send(FAR struct socket *psock, FAR const void *buf,
#ifdef CONFIG_NETDEV_MULTINIC
dev = netdev_findby_ipv6addr(conn->u.ipv6.laddr, conn->u.ipv6.raddr);
- if (dev == NULL || dev->d_lltype != NET_LL_IEEE805154)
+#ifdef CONFIG_NETDEV_MULTILINK
+ if (dev == NULL || dev->d_lltype != NET_LL_IEEE802154)
+#else
+ if (dev == NULL)
+#endif
{
nwarn("WARNING: Not routable or not IEEE802.15.4 MAC\n");
return (ssize_t)-ENETUNREACH;
}
#else
dev = netdev_findby_ipv6addr(conn->u.ipv6.raddr);
+#ifdef CONFIG_NETDEV_MULTILINK
+ if (dev == NULL || dev->d_lltype != NET_LL_IEEE802154)
+#else
if (dev == NULL)
+#endif
{
nwarn("WARNING: Not routable\n");
return (ssize_t)-ENETUNREACH;
@@ -154,27 +238,186 @@ ssize_t psock_6lowpan_tcp_send(FAR struct socket *psock, FAR const void *buf,
#endif
/* Initialize the IPv6/TCP headers */
-#warning Missing logic
+
+ /* Initialize the IPv6/UDP headers */
+
+ ipv6tcp.ipv6.vtc = 0x60;
+ ipv6tcp.ipv6.tcf = 0x00;
+ ipv6tcp.ipv6.flow = 0x00;
+ ipv6tcp.ipv6.proto = IP_PROTO_TCP;
+ ipv6tcp.ipv6.ttl = IP_TTL;
+
+ /* The IPv6 header length field does not include the size of IPv6 IP
+ * header.
+ */
+
+ iplen = buflen + TCP_HDRLEN;
+ ipv6tcp.ipv6.len[0] = (iplen >> 8);
+ ipv6tcp.ipv6.len[1] = (iplen & 0xff);
+
+ /* Copy the source and destination addresses */
+
+ net_ipv6addr_hdrcopy(ipv6tcp.ipv6.srcipaddr, conn->u.ipv6.laddr);
+ net_ipv6addr_hdrcopy(ipv6tcp.ipv6.destipaddr, conn->u.ipv6.raddr);
+
+ ninfo("IPv6 length: %d\n",
+ ((int)ipv6tcp.ipv6.len[0] << 8) + ipv6tcp.ipv6.len[1]);
+
+#ifdef CONFIG_NET_STATISTICS
+ g_netstats.ipv6.sent++;
+#endif
+
+ /* Initialize the TCP header */
+
+ ipv6tcp.tcp.srcport = conn->lport; /* Local port */
+ ipv6tcp.tcp.destport = conn->rport; /* Connected remote port */
+
+ memcpy(ipv6tcp.tcp.ackno, conn->rcvseq, 4); /* ACK number */
+ memcpy(ipv6tcp.tcp.seqno, conn->sndseq, 4); /* Sequence number */
+
+ ipv6tcp.tcp.tcpoffset = (TCP_HDRLEN / 4) << 4; /* No optdata */
+ ipv6tcp.tcp.urgp[0] = 0; /* No urgent data */
+ ipv6tcp.tcp.urgp[1] = 0;
+
+ /* Set the TCP window */
+
+ if (conn->tcpstateflags & TCP_STOPPED)
+ {
+ /* If the connection has issued TCP_STOPPED, we advertise a zero
+ * window so that the remote host will stop sending data.
+ */
+
+ ipv6tcp.tcp.wnd[0] = 0;
+ ipv6tcp.tcp.wnd[1] = 0;
+ }
+ else
+ {
+ ipv6tcp.tcp.wnd[0] = ((NET_DEV_RCVWNDO(dev)) >> 8);
+ ipv6tcp.tcp.wnd[1] = ((NET_DEV_RCVWNDO(dev)) & 0xff);
+ }
+
+ /* Calculate TCP checksum. */
+
+ ipv6tcp.tcp.tcpchksum = 0;
+ ipv6tcp.tcp.tcpchksum = ~sixlowpan_tcp_chksum(&ipv6tcp, buf, buflen);
+
+ ninfo("Outgoing TCP packet length: %d bytes\n", iplen + IPv6_HDRLEN);
+
+#ifdef CONFIG_NET_STATISTICS
+ g_netstats.tcp.sent++;
+#endif
/* Set the socket state to sending */
psock->s_flags = _SS_SETSTATE(psock->s_flags, _SF_SEND);
- /* Get the Rime MAC address of the destination */
-#warning Missing logic
+ /* Get the Rime MAC address of the destination This assumes an encoding
+ * of the MAC address in the IPv6 address.
+ */
+
+ sixlowpan_rimefromip(conn->u.ipv6.raddr, &destmac);
/* If routable, then call sixlowpan_send() to format and send the 6loWPAN
* packet.
*/
+#ifdef CONFIG_NET_SOCKOPTS
+ timeout = psock->s_sndtimeo;
+#else
+ timeout = 0;
+#endif
+
ret = sixlowpan_send(dev, (FAR const struct ipv6_hdr_s *)&ipv6tcp,
- buf, len, &dest);
+ buf, buflen, &destmac, timeout);
if (ret < 0)
{
nerr("ERROR: sixlowpan_send() failed: %d\n", ret);
}
+ /* Set the socket state to idle */
+
+ psock->s_flags = _SS_SETSTATE(psock->s_flags, _SF_IDLE);
return ret;
}
+/****************************************************************************
+ * Function: sixlowpan_tcp_send
+ *
+ * Description:
+ * TCP output comes through three different mechansims. Either from:
+ *
+ * 1. TCP socket output. For the case of TCP output to an
+ * IEEE802.15.4, the TCP output is caught in the socket
+ * send()/sendto() logic and and redirected to psock_6lowpan_tcp_send().
+ * 2. TCP output from the TCP state machine. That will occur
+ * during TCP packet processing by the TCP state meachine.
+ * 3. TCP output resulting from TX or timer polling
+ *
+ * Cases 2 and 3 will be handled here. Logic in ipv6_tcp_input(),
+ * devif_poll(), and devif_timer() detect if (1) an attempt to return with
+ * d_len > 0 and (2) that the device is an IEEE802.15.4 MAC network
+ * driver. Under those conditions, this function will be called to create
+ * the IEEE80215.4 frames.
+ *
+ * Parameters:
+ * dev - An instance of nework device state structure
+ *
+ * Returned Value:
+ * None
+ *
+ * Assumptions:
+ * Called with the network locked.
+ *
+ ****************************************************************************/
+
+void sixlowpan_tcp_send(FAR struct net_driver_s *dev)
+{
+ DEBUGASSERT(dev != NULL && dev->d_len > 0);
+
+ /* Double check */
+
+ ninfo("d_len %u\n", dev->d_len);
+ sixlowpan_dumpbuffer("Outgoing TCP packet",
+ (FAR const uint8_t *)IPv6BUF(dev), dev->d_len);
+
+ if (dev != NULL && dev->d_len > 0)
+ {
+ FAR struct ipv6_hdr_s *ipv6hdr;
+
+ /* The IPv6 header followed by a TCP headers should lie at the
+ * beginning of d_buf since there is no link layer protocol header
+ * and the TCP state machine should only response with TCP packets.
+ */
+
+ ipv6hdr = (FAR struct ipv6_hdr_s *)(dev->d_buf);
+
+ /* The TCP data payload should follow the IPv6 header plus the
+ * protocol header.
+ */
+
+ if (ipv6hdr->proto != IP_PROTO_TCP)
+ {
+ nwarn("WARNING: Expected TCP protoype: %u\n", ipv6hdr->proto);
+ }
+ else
+ {
+ struct rimeaddr_s destmac;
+
+ /* Get the Rime MAC address of the destination. This assumes an
+ * encoding of the MAC address in the IPv6 address.
+ */
+
+ sixlowpan_rimefromip(ipv6hdr->destipaddr, &destmac);
+
+ /* Convert the outgoing packet into a frame list. */
+
+ (void)sixlowpan_queue_frames(
+ (FAR struct ieee802154_driver_s *)dev, ipv6hdr,
+ dev->d_buf, dev->d_len, &destmac);
+ }
+ }
+
+ dev->d_len = 0;
+}
+
#endif /* CONFIG_NET_6LOWPAN && CONFIG_NET_TCP */
diff --git a/net/sixlowpan/sixlowpan_udpsend.c b/net/sixlowpan/sixlowpan_udpsend.c
index 9946516e009..717df424a27 100644
--- a/net/sixlowpan/sixlowpan_udpsend.c
+++ b/net/sixlowpan/sixlowpan_udpsend.c
@@ -39,25 +39,295 @@
#include
+#include
+#include
#include
#include
#include
#include "nuttx/net/netdev.h"
-#include "nuttx/net/udp.h"
-#include "nuttx/net/sixlowpan.h"
+#include "nuttx/net/netstats.h"
#include "netdev/netdev.h"
#include "socket/socket.h"
#include "udp/udp.h"
+#include "utils/utils.h"
#include "sixlowpan/sixlowpan_internal.h"
#if defined(CONFIG_NET_6LOWPAN) && defined(CONFIG_NET_UDP)
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: sixlowpan_udp_chksum
+ *
+ * Description:
+ * Perform the checksum calcaultion over the IPv6, protocol headers, and
+ * data payload as necessary.
+ *
+ * Input Parameters:
+ * ipv6udp - A reference to a structure containing the IPv6 and UDP headers.
+ * buf - The beginning of the payload data
+ * buflen - The length of the payload data.
+ *
+ * Returned Value:
+ * The calculated checksum
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_NET_UDP_CHECKSUMS
+static uint16_t sixlowpan_udp_chksum(FAR struct ipv6udp_hdr_s *ipv6udp,
+ FAR const uint8_t *buf, uint16_t buflen)
+{
+ uint16_t upperlen;
+ uint16_t sum;
+
+ /* The length reported in the IPv6 header is the length of the payload
+ * that follows the header.
+ */
+
+ upperlen = ((uint16_t)ipv6udp->ipv6.len[0] << 8) + ipv6udp->ipv6.len[1];
+
+ /* Verify some minimal assumptions */
+
+ if (upperlen > CONFIG_NET_6LOWPAN_MTU)
+ {
+ return 0;
+ }
+
+ /* The checksum is calculated starting with a pseudo-header of IPv6 header
+ * fields according to the IPv6 standard, which consists of the source
+ * and destination addresses, the packet length and the next header field.
+ */
+
+ sum = upperlen + ipv6udp->ipv6.proto;
+
+ /* Sum IP source and destination addresses. */
+
+ sum = chksum(sum, (FAR uint8_t *)ipv6udp->ipv6.srcipaddr,
+ 2 * sizeof(net_ipv6addr_t));
+
+ /* Sum the UDP header */
+
+ sum = chksum(sum, (FAR uint8_t *)&ipv6udp->udp, UDP_HDRLEN);
+
+ /* Sum payload data. */
+
+ sum = chksum(sum, buf, buflen);
+ return (sum == 0) ? 0xffff : htons(sum);
+}
+#endif
+
/****************************************************************************
* Public Functions
****************************************************************************/
+/****************************************************************************
+ * Function: psock_6lowpan_udp_sendto
+ *
+ * Description:
+ * If sendto() is used on a connection-mode (SOCK_STREAM, SOCK_SEQPACKET)
+ * socket, the parameters to and 'tolen' are ignored (and the error EISCONN
+ * may be returned when they are not NULL and 0), and the error ENOTCONN is
+ * returned when the socket was not actually connected.
+ *
+ * Parameters:
+ * psock A pointer to a NuttX-specific, internal socket structure
+ * buf Data to send
+ * buflen Length of data to send
+ * flags Send flags
+ * to Address of recipient
+ * tolen The length of the address structure
+ *
+ * Returned Value:
+ * On success, returns the number of characters sent. On error,
+ * -1 is returned, and errno is set appropriately. Returned error
+ * number must be consistent with definition of errors reported by
+ * sendto().
+ *
+ * Assumptions:
+ * Called with the network locked.
+ *
+ ****************************************************************************/
+
+ssize_t psock_6lowpan_udp_sendto(FAR struct socket *psock,
+ FAR const void *buf,
+ size_t buflen, int flags,
+ FAR const struct sockaddr *to,
+ socklen_t tolen)
+{
+ FAR struct sockaddr_in6 *to6 = (FAR struct sockaddr_in6 *)to;
+ FAR struct udp_conn_s *conn;
+ FAR struct net_driver_s *dev;
+ struct ipv6udp_hdr_s ipv6udp;
+ struct rimeaddr_s destmac;
+ uint16_t iplen;
+ uint16_t timeout;
+ int ret;
+
+ ninfo("buflen %lu\n", (unsigned long)buflen);
+
+ DEBUGASSERT(psock != NULL && psock->s_crefs > 0 && to != NULL);
+ DEBUGASSERT(psock->s_type == SOCK_DGRAM);
+
+ sixlowpan_dumpbuffer("Outgoing UDP payload", buf, buflen);
+
+ if (psock == NULL || to == NULL)
+ {
+ return (ssize_t)-EINVAL;
+ }
+
+ /* Make sure that this is a datagram valid socket */
+
+ if (psock->s_crefs <= 0 || psock->s_type != SOCK_DGRAM)
+ {
+ nerr("ERROR: Invalid socket\n");
+ return (ssize_t)-EBADF;
+ }
+
+ /* Make sure that the destination address is valid */
+
+ if (to6->sin6_family != AF_INET6 || tolen < sizeof(struct sockaddr_in6))
+ {
+ nerr("ERROR: Invalid destination address\n");
+ return (ssize_t)-EAFNOSUPPORT;
+ }
+
+ /* Get the underlying UDP "connection" structure */
+
+ conn = (FAR struct udp_conn_s *)psock->s_conn;
+ DEBUGASSERT(conn != NULL);
+
+ /* Ignore if not IPv6 domain */
+
+ if (conn->domain != PF_INET6)
+ {
+ nwarn("WARNING: Not IPv6\n");
+ return (ssize_t)-EPROTOTYPE;
+ }
+
+ /* Route outgoing message to the correct device */
+
+#ifdef CONFIG_NETDEV_MULTINIC
+ dev = netdev_findby_ipv6addr(conn->u.ipv6.laddr,
+ to6->sin6_addr.in6_u.u6_addr16);
+#ifdef CONFIG_NETDEV_MULTILINK
+ if (dev == NULL || dev->d_lltype != NET_LL_IEEE802154)
+#else
+ if (dev == NULL)
+#endif
+ {
+ nwarn("WARNING: Not routable or not IEEE802.15.4 MAC\n");
+ return (ssize_t)-ENETUNREACH;
+ }
+#else
+ dev = netdev_findby_ipv6addr(to6->sin6_addr.in6_u.u6_addr16);
+#ifdef CONFIG_NETDEV_MULTILINK
+ if (dev == NULL || dev->d_lltype != NET_LL_IEEE802154)
+#else
+ if (dev == NULL)
+#endif
+ {
+ nwarn("WARNING: Not routable\n");
+ return (ssize_t)-ENETUNREACH;
+ }
+#endif
+
+#ifdef CONFIG_NET_ICMPv6_NEIGHBOR
+ /* Make sure that the IP address mapping is in the Neighbor Table */
+
+ ret = icmpv6_neighbor(to6->sin6_addr.in6_u.u6_addr16);
+ if (ret < 0)
+ {
+ nerr("ERROR: Not reachable\n");
+ return (ssize_t)-ENETUNREACH;
+ }
+#endif
+
+ /* Initialize the IPv6/UDP headers */
+
+ ipv6udp.ipv6.vtc = 0x60;
+ ipv6udp.ipv6.tcf = 0x00;
+ ipv6udp.ipv6.flow = 0x00;
+ ipv6udp.ipv6.proto = IP_PROTO_UDP;
+ ipv6udp.ipv6.ttl = conn->ttl;
+
+ /* The IPv6 header length field does not include the size of IPv6 IP
+ * header.
+ */
+
+ iplen = buflen + UDP_HDRLEN;
+ ipv6udp.ipv6.len[0] = (iplen >> 8);
+ ipv6udp.ipv6.len[1] = (iplen & 0xff);
+
+ /* Copy the source and destination addresses */
+
+ net_ipv6addr_hdrcopy(ipv6udp.ipv6.srcipaddr, to6->sin6_addr.in6_u.u6_addr16);
+ net_ipv6addr_hdrcopy(ipv6udp.ipv6.destipaddr, conn->u.ipv6.raddr);
+
+ ninfo("IPv6 length: %d\n",
+ ((int)ipv6udp.ipv6.len[0] << 8) + ipv6udp.ipv6.len[1]);
+
+#ifdef CONFIG_NET_STATISTICS
+ g_netstats.ipv6.sent++;
+#endif
+
+ /* Initialize the UDP header */
+
+ ipv6udp.udp.srcport = conn->lport;
+ ipv6udp.udp.destport = to6->sin6_port;
+ ipv6udp.udp.udplen = htons(iplen);
+ ipv6udp.udp.udpchksum = 0;
+
+#ifdef CONFIG_NET_UDP_CHECKSUMS
+ ipv6udp.udp.udpchksum = ~sixlowpan_udp_chksum(ipv6udp, buf, buflen);
+ if (ipv6udp.udp.udpchksum == 0)
+ {
+ ipv6udp.udp.udpchksum = 0xffff;
+ }
+#endif /* CONFIG_NET_UDP_CHECKSUMS */
+
+ ninfo("Outgoing UDP packet length: %d\n", iplen + IPv6_HDRLEN);
+
+#ifdef CONFIG_NET_STATISTICS
+ g_netstats.udp.sent++;
+#endif
+
+ /* Set the socket state to sending */
+
+ psock->s_flags = _SS_SETSTATE(psock->s_flags, _SF_SEND);
+
+ /* Get the Rime MAC address of the destination This assumes an encoding
+ * of the MAC address in the IPv6 address.
+ */
+
+ sixlowpan_rimefromip(to6->sin6_addr.in6_u.u6_addr16, &destmac);
+
+ /* If routable, then call sixlowpan_send() to format and send the 6loWPAN
+ * packet.
+ */
+
+#ifdef CONFIG_NET_SOCKOPTS
+ timeout = psock->s_sndtimeo;
+#else
+ timeout = 0;
+#endif
+
+ ret = sixlowpan_send(dev, (FAR const struct ipv6_hdr_s *)&ipv6udp,
+ buf, buflen, &destmac, timeout);
+ if (ret < 0)
+ {
+ nerr("ERROR: sixlowpan_send() failed: %d\n", ret);
+ }
+
+ /* Set the socket state to idle */
+
+ psock->s_flags = _SS_SETSTATE(psock->s_flags, _SF_IDLE);
+ return ret;
+}
+
/****************************************************************************
* Function: psock_6lowpan_udp_send
*
@@ -66,15 +336,14 @@
* sockets.
*
* Parameters:
- * psock - An instance of the internal socket structure.
- * buf - Data to send
- * len - Length of data to send
+ * psock - An instance of the internal socket structure.
+ * buf - Data to send
+ * buflen - Length of data to send
*
* Returned Value:
* On success, returns the number of characters sent. On error,
* -1 is returned, and errno is set appropriately. Returned error numbers
- * must be consistent with definition of errors reported by send() or
- * sendto().
+ * must be consistent with definition of errors reported by send().
*
* Assumptions:
* Called with the network locked.
@@ -82,17 +351,18 @@
****************************************************************************/
ssize_t psock_6lowpan_udp_send(FAR struct socket *psock, FAR const void *buf,
- size_t len)
+ size_t buflen)
{
FAR struct udp_conn_s *conn;
- FAR struct net_driver_s *dev;
- struct ipv6udp_hdr_s ipv6udp;
- struct rimeaddr_s dest;
- int ret;
+ struct sockaddr_in6 to;
+
+ ninfo("buflen %lu\n", (unsigned long)buflen);
DEBUGASSERT(psock != NULL && psock->s_crefs > 0);
DEBUGASSERT(psock->s_type == SOCK_DGRAM);
+ sixlowpan_dumpbuffer("Outgoing UDP payload", buf, buflen);
+
/* Make sure that this is a valid socket */
if (psock != NULL || psock->s_crefs <= 0)
@@ -115,7 +385,6 @@ ssize_t psock_6lowpan_udp_send(FAR struct socket *psock, FAR const void *buf,
conn = (FAR struct udp_conn_s *)psock->s_conn;
DEBUGASSERT(conn != NULL);
-#if defined(CONFIG_NET_IPv4) && defined(CONFIG_NET_IPv6)
/* Ignore if not IPv6 domain */
if (conn->domain != PF_INET6)
@@ -123,59 +392,16 @@ ssize_t psock_6lowpan_udp_send(FAR struct socket *psock, FAR const void *buf,
nwarn("WARNING: Not IPv6\n");
return (ssize_t)-EPROTOTYPE;
}
-#endif
- /* Route outgoing message to the correct device */
+ /* Create the 'to' address */
-#ifdef CONFIG_NETDEV_MULTINIC
- dev = netdev_findby_ipv6addr(conn->u.ipv6.laddr, conn->u.ipv6.raddr);
- if (dev == NULL || dev->d_lltype != NET_LL_IEEE805154)
- {
- nwarn("WARNING: Not routable or not IEEE802.15.4 MAC\n");
- return (ssize_t)-ENETUNREACH;
- }
-#else
- dev = netdev_findby_ipv6addr(conn->u.ipv6.raddr);
- if (dev == NULL)
- {
- nwarn("WARNING: Not routable\n");
- return (ssize_t)-ENETUNREACH;
- }
-#endif
+ to.sin6_family = AF_INET6;
+ to.sin6_port = conn->rport; /* Already network order */
+ memcpy(to.sin6_addr.in6_u.u6_addr16, conn->u.ipv6.raddr, 16);
-#ifdef CONFIG_NET_ICMPv6_NEIGHBOR
- /* Make sure that the IP address mapping is in the Neighbor Table */
-
- ret = icmpv6_neighbor(conn->u.ipv6.raddr);
- if (ret < 0)
- {
- nerr("ERROR: Not reachable\n");
- return (ssize_t)-ENETUNREACH;
- }
-#endif
-
- /* Initialize the IPv6/UDP headers */
-#warning Missing logic
-
- /* Set the socket state to sending */
-
- psock->s_flags = _SS_SETSTATE(psock->s_flags, _SF_SEND);
-
- /* Get the Rime MAC address of the destination */
-#warning Missing logic
-
- /* If routable, then call sixlowpan_send() to format and send the 6loWPAN
- * packet.
- */
-
- ret = sixlowpan_send(dev, (FAR const struct ipv6_hdr_s *)&ipv6udp,
- buf, len, &dest);
- if (ret < 0)
- {
- nerr("ERROR: sixlowpan_send() failed: %d\n", ret);
- }
-
- return ret;
+ return psock_6lowpan_udp_sendto(psock, buf, buflen, 0,
+ (FAR const struct sockaddr *)&to,
+ sizeof(struct sockaddr_in6));
}
#endif /* CONFIG_NET_6LOWPAN && CONFIG_NET_UDP */
diff --git a/net/sixlowpan/sixlowpan_utils.c b/net/sixlowpan/sixlowpan_utils.c
index f00eaeae4c3..fc322ec38e1 100644
--- a/net/sixlowpan/sixlowpan_utils.c
+++ b/net/sixlowpan/sixlowpan_utils.c
@@ -44,18 +44,6 @@
* SUCH DAMAGE.
*
****************************************************************************/
-/* Frame Organization:
- *
- * Content Offset
- * +------------------+ 0
- * | Frame Header |
- * +------------------+ i_dataoffset
- * | Procotol Headers |
- * | Data Payload |
- * +------------------+ i_framelen
- * | Unused |
- * +------------------+ CONFIG_NET_6LOWPAN_FRAMELEN
- */
/****************************************************************************
* Included Files
@@ -64,9 +52,10 @@
#include
#include
+#include
#include
-#include "nuttx/net/sixlowpan.h"
+#include
#include "sixlowpan/sixlowpan_internal.h"
@@ -77,24 +66,94 @@
****************************************************************************/
/****************************************************************************
- * Name: sixlowpan_frame_hdralloc
+ * Name: sixlowpan_ipfromrime
*
* Description:
- * Allocate space for a header within the packet buffer (dev->d_buf).
+ * Create a link local IPv6 address from a rime address:
+ *
+ * 128 112 96 80 64 48 32 16
+ * ---- ---- ---- ---- ---- ---- ---- ----
+ * fe80 0000 0000 0000 0000 00ff fe00 xxxx 2-byte Rime address IEEE 48-bit MAC
+ * fe80 0000 0000 0000 xxxx xxxx xxxx xxxx 8-byte Rime address IEEE EUI-64
*
****************************************************************************/
-int sixlowpan_frame_hdralloc(FAR struct ieee802154_driver_s *ieee,
- int size)
+void sixlowpan_ipfromrime(FAR const struct rimeaddr_s *rime,
+ net_ipv6addr_t ipaddr)
{
- if (size <= FRAME_REMAINING(ieee))
- {
- ieee->i_dataoffset += size;
- ieee->i_framelen += size;
- return OK;
- }
+ /* We consider only links with IEEE EUI-64 identifier or IEEE 48-bit MAC
+ * addresses.
+ */
- return -ENOMEM;
+ memset(ipaddr, 0, sizeof(net_ipv6addr_t));
+ ipaddr[0] = HTONS(0xfe80);
+
+#if CONFIG_NET_6LOWPAN_RIMEADDR_SIZE == 2
+ ipaddr[5] = HTONS(0x00ff);
+ ipaddr[6] = HTONS(0xfe00);
+ memcpy(&ipaddr[7], rime, CONFIG_NET_6LOWPAN_RIMEADDR_SIZE);
+ ipaddr[7] ^= HTONS(0x0200);
+#else
+ memcpy(&ipaddr[4], rime, CONFIG_NET_6LOWPAN_RIMEADDR_SIZE);
+ ipaddr[4] ^= HTONS(0x0200);
+#endif
+}
+
+/****************************************************************************
+ * Name: sixlowpan_rimefromip
+ *
+ * Description:
+ * Extract the rime address from a link local IPv6 address:
+ *
+ * 128 112 96 80 64 48 32 16
+ * ---- ---- ---- ---- ---- ---- ---- ----
+ * fe80 0000 0000 0000 0000 00ff fe00 xxxx 2-byte Rime address IEEE 48-bit MAC
+ * fe80 0000 0000 0000 xxxx xxxx xxxx xxxx 8-byte Rime address IEEE EUI-64
+ *
+ ****************************************************************************/
+
+void sixlowpan_rimefromip(const net_ipv6addr_t ipaddr,
+ FAR struct rimeaddr_s *rime)
+{
+ /* REVISIT: See notes about 2 byte addresses in sixlowpan_ipfromrime() */
+
+ DEBUGASSERT(ipaddr[0] == HTONS(0xfe80));
+
+#if CONFIG_NET_6LOWPAN_RIMEADDR_SIZE == 2
+ memcpy(rime, &ipaddr[7], CONFIG_NET_6LOWPAN_RIMEADDR_SIZE);
+#else
+ memcpy(rime, &ipaddr[4], CONFIG_NET_6LOWPAN_RIMEADDR_SIZE);
+#endif
+ rime->u8[0] ^= 0x02;
+}
+
+/****************************************************************************
+ * Name: sixlowpan_ismacbased
+ *
+ * Description:
+ * Check if the MAC address is encoded in the IP address:
+ *
+ * 128 112 96 80 64 48 32 16
+ * ---- ---- ---- ---- ---- ---- ---- ----
+ * fe80 0000 0000 0000 0000 00ff fe00 xxxx 2-byte Rime address IEEE 48-bit MAC
+ * fe80 0000 0000 0000 xxxx xxxx xxxx xxxx 8-byte Rime address IEEE EUI-64
+ *
+ ****************************************************************************/
+
+bool sixlowpan_ismacbased(const net_ipv6addr_t ipaddr,
+ FAR const struct rimeaddr_s *rime)
+{
+ FAR const uint8_t *rimeptr = rime->u8;
+
+#if CONFIG_NET_6LOWPAN_RIMEADDR_SIZE == 2
+ return (ipaddr[5] == HTONS(0x00ff) && ipaddr[6] == HTONS(0xfe00) &&
+ ipaddr[7] == htons((GETINT16(rimeptr, 0) ^ 0x0200)));
+#else /* CONFIG_NET_6LOWPAN_RIMEADDR_SIZE == 8 */
+ return (ipaddr[4] == htons((GETINT16(rimeptr, 0) ^ 0x0200)) &&
+ ipaddr[5] == GETINT16(rimeptr, 2) &&
+ ipaddr[6] == GETINT16(rimeptr, 4) &&
+ ipaddr[7] == GETINT16(rimeptr, 6));
+#endif
}
#endif /* CONFIG_NET_6LOWPAN */
diff --git a/net/socket/Make.defs b/net/socket/Make.defs
index cfb6233bd1f..6f433cd97a8 100644
--- a/net/socket/Make.defs
+++ b/net/socket/Make.defs
@@ -42,7 +42,10 @@ SOCK_CSRCS += net_dupsd2.c net_clone.c net_poll.c net_vfcntl.c
# TCP/IP support
ifeq ($(CONFIG_NET_TCP),y)
-SOCK_CSRCS += listen.c accept.c net_monitor.c
+SOCK_CSRCS += listen.c accept.c
+ifneq ($(CONFIG_NET_TCP_NO_STACK),y)
+SOCK_CSRCS += net_monitor.c
+endif
# Local Unix domain support
diff --git a/net/socket/accept.c b/net/socket/accept.c
index 4bf35dc7f21..b4db581dbad 100644
--- a/net/socket/accept.c
+++ b/net/socket/accept.c
@@ -54,6 +54,7 @@
#include "tcp/tcp.h"
#include "local/local.h"
#include "socket/socket.h"
+#include "usrsock/usrsock.h"
/****************************************************************************
* Public Functions
@@ -129,7 +130,9 @@ int psock_accept(FAR struct socket *psock, FAR struct sockaddr *addr,
FAR socklen_t *addrlen, FAR struct socket *newsock)
{
int errcode;
+#if defined(NET_TCP_HAVE_STACK) || defined(CONFIG_NET_LOCAL_STREAM)
int ret;
+#endif
DEBUGASSERT(psock != NULL);
@@ -141,6 +144,13 @@ int psock_accept(FAR struct socket *psock, FAR struct sockaddr *addr,
if (psock->s_type != SOCK_STREAM)
{
+#ifdef CONFIG_NET_USRSOCK
+ if (psock->s_type == SOCK_USRSOCK_TYPE)
+ {
+#warning "Missing logic"
+ }
+#endif
+
errcode = EOPNOTSUPP;
goto errout;
}
@@ -238,6 +248,7 @@ int psock_accept(FAR struct socket *psock, FAR struct sockaddr *addr,
else
#endif
{
+#ifdef NET_TCP_HAVE_STACK
/* Perform the local accept operation (with the network locked) */
net_lock();
@@ -267,6 +278,10 @@ int psock_accept(FAR struct socket *psock, FAR struct sockaddr *addr,
}
net_unlock();
+#else
+ errcode = EOPNOTSUPP;
+ goto errout;
+#endif /* NET_TCP_HAVE_STACK */
}
#endif /* CONFIG_NET_TCP */
@@ -278,8 +293,10 @@ int psock_accept(FAR struct socket *psock, FAR struct sockaddr *addr,
leave_cancellation_point();
return OK;
+#ifdef NET_TCP_HAVE_STACK
errout_after_accept:
psock_close(newsock);
+#endif
errout:
set_errno(errcode);
diff --git a/net/socket/bind.c b/net/socket/bind.c
index 1197460ce79..8ffc1274e8b 100644
--- a/net/socket/bind.c
+++ b/net/socket/bind.c
@@ -46,6 +46,7 @@
#include
#include
#include
+#include
#ifdef CONFIG_NET_PKT
# include
@@ -60,6 +61,7 @@
#include "udp/udp.h"
#include "pkt/pkt.h"
#include "local/local.h"
+#include "usrsock/usrsock.h"
/****************************************************************************
* Private Functions
@@ -212,6 +214,20 @@ int psock_bind(FAR struct socket *psock, const struct sockaddr *addr,
switch (psock->s_type)
{
+#ifdef CONFIG_NET_USRSOCK
+ case SOCK_USRSOCK_TYPE:
+ {
+ FAR struct usrsock_conn_s *conn = psock->s_conn;
+
+ DEBUGASSERT(conn);
+
+ /* Perform the usrsock bind operation */
+
+ ret = usrsock_bind(conn, addr, addrlen);
+ }
+ break;
+#endif
+
#ifdef CONFIG_NET_PKT
case SOCK_RAW:
ret = pkt_bind(psock->s_conn, lladdr);
@@ -243,9 +259,13 @@ int psock_bind(FAR struct socket *psock, const struct sockaddr *addr,
else
#endif
{
+#ifdef NET_TCP_HAVE_STACK
/* Bind the TCP/IP connection structure */
ret = tcp_bind(psock->s_conn, addr);
+#else
+ ret = -ENOSYS;
+#endif
}
#endif /* CONFIG_NET_TCP */
@@ -284,9 +304,13 @@ int psock_bind(FAR struct socket *psock, const struct sockaddr *addr,
else
#endif
{
+#ifdef NET_UDP_HAVE_STACK
/* Bind the UDPP/IP connection structure */
ret = udp_bind(psock->s_conn, addr);
+#else
+ ret = -ENOSYS;
+#endif
}
#endif /* CONFIG_NET_UDP */
diff --git a/net/socket/connect.c b/net/socket/connect.c
index 6a0140ea55a..dd3ee97e096 100644
--- a/net/socket/connect.c
+++ b/net/socket/connect.c
@@ -62,12 +62,13 @@
#include "udp/udp.h"
#include "local/local.h"
#include "socket/socket.h"
+#include "usrsock/usrsock.h"
/****************************************************************************
* Private Types
****************************************************************************/
-#ifdef CONFIG_NET_TCP
+#ifdef NET_TCP_HAVE_STACK
struct tcp_connect_s
{
FAR struct tcp_conn_s *tc_conn; /* Reference to TCP connection structure */
@@ -82,7 +83,7 @@ struct tcp_connect_s
* Private Function Prototypes
****************************************************************************/
-#ifdef CONFIG_NET_TCP
+#ifdef NET_TCP_HAVE_STACK
static inline int psock_setup_callbacks(FAR struct socket *psock,
FAR struct tcp_connect_s *pstate);
static void psock_teardown_callbacks(FAR struct tcp_connect_s *pstate,
@@ -92,7 +93,7 @@ static uint16_t psock_connect_interrupt(FAR struct net_driver_s *dev,
uint16_t flags);
static inline int psock_tcp_connect(FAR struct socket *psock,
FAR const struct sockaddr *addr);
-#endif /* CONFIG_NET_TCP */
+#endif /* NET_TCP_HAVE_STACK */
/****************************************************************************
* Private Functions
@@ -101,7 +102,7 @@ static inline int psock_tcp_connect(FAR struct socket *psock,
* Name: psock_setup_callbacks
****************************************************************************/
-#ifdef CONFIG_NET_TCP
+#ifdef NET_TCP_HAVE_STACK
static inline int psock_setup_callbacks(FAR struct socket *psock,
FAR struct tcp_connect_s *pstate)
{
@@ -137,13 +138,13 @@ static inline int psock_setup_callbacks(FAR struct socket *psock,
return ret;
}
-#endif /* CONFIG_NET_TCP */
+#endif /* NET_TCP_HAVE_STACK */
/****************************************************************************
* Name: psock_teardown_callbacks
****************************************************************************/
-#ifdef CONFIG_NET_TCP
+#ifdef NET_TCP_HAVE_STACK
static void psock_teardown_callbacks(FAR struct tcp_connect_s *pstate,
int status)
{
@@ -165,7 +166,7 @@ static void psock_teardown_callbacks(FAR struct tcp_connect_s *pstate,
net_stopmonitor(conn);
}
}
-#endif /* CONFIG_NET_TCP */
+#endif /* NET_TCP_HAVE_STACK */
/****************************************************************************
* Name: psock_connect_interrupt
@@ -187,7 +188,7 @@ static void psock_teardown_callbacks(FAR struct tcp_connect_s *pstate,
*
****************************************************************************/
-#ifdef CONFIG_NET_TCP
+#ifdef NET_TCP_HAVE_STACK
static uint16_t psock_connect_interrupt(FAR struct net_driver_s *dev,
FAR void *pvconn, FAR void *pvpriv,
uint16_t flags)
@@ -299,7 +300,7 @@ static uint16_t psock_connect_interrupt(FAR struct net_driver_s *dev,
else
#endif
{
- pstate->tc_conn->mss = TCP_IPv4_INITIAL_MSS(dev);
+ pstate->tc_conn->mss = TCP_IPv6_INITIAL_MSS(dev);
}
#endif /* CONFIG_NET_IPv6 */
@@ -322,7 +323,7 @@ static uint16_t psock_connect_interrupt(FAR struct net_driver_s *dev,
return flags;
}
-#endif /* CONFIG_NET_TCP */
+#endif /* NET_TCP_HAVE_STACK */
/****************************************************************************
* Name: psock_tcp_connect
@@ -342,7 +343,7 @@ static uint16_t psock_connect_interrupt(FAR struct net_driver_s *dev,
*
****************************************************************************/
-#ifdef CONFIG_NET_TCP
+#ifdef NET_TCP_HAVE_STACK
static inline int psock_tcp_connect(FAR struct socket *psock,
FAR const struct sockaddr *addr)
{
@@ -434,7 +435,7 @@ static inline int psock_tcp_connect(FAR struct socket *psock,
net_unlock();
return ret;
}
-#endif /* CONFIG_NET_TCP */
+#endif /* NET_TCP_HAVE_STACK */
/****************************************************************************
* Public Functions
@@ -512,7 +513,8 @@ int psock_connect(FAR struct socket *psock, FAR const struct sockaddr *addr,
socklen_t addrlen)
{
FAR const struct sockaddr_in *inaddr = (FAR const struct sockaddr_in *)addr;
-#if defined(CONFIG_NET_TCP) || defined(CONFIG_NET_UDP) || defined(CONFIG_NET_LOCAL)
+#if defined(CONFIG_NET_TCP) || defined(CONFIG_NET_UDP) || \
+ defined(CONFIG_NET_LOCAL) || defined(CONFIG_NET_USRSOCK)
int ret;
#endif
int errcode;
@@ -570,6 +572,13 @@ int psock_connect(FAR struct socket *psock, FAR const struct sockaddr *addr,
#endif
default:
+#ifdef CONFIG_NET_USRSOCK
+ if (psock->s_type == SOCK_USRSOCK_TYPE)
+ {
+ break;
+ }
+#endif
+
DEBUGPANIC();
errcode = EAFNOSUPPORT;
goto errout;
@@ -608,9 +617,13 @@ int psock_connect(FAR struct socket *psock, FAR const struct sockaddr *addr,
else
#endif
{
+#ifdef NET_TCP_HAVE_STACK
/* Connect the TCP/IP socket */
ret = psock_tcp_connect(psock, addr);
+#else
+ ret = -ENOSYS;
+#endif
}
#endif /* CONFIG_NET_TCP */
@@ -642,6 +655,7 @@ int psock_connect(FAR struct socket *psock, FAR const struct sockaddr *addr,
else
#endif
{
+#ifdef NET_UDP_HAVE_STACK
ret = udp_connect(psock->s_conn, addr);
if (ret < 0 || addr == NULL)
{
@@ -651,6 +665,9 @@ int psock_connect(FAR struct socket *psock, FAR const struct sockaddr *addr,
{
psock->s_flags |= _SF_CONNECTED;
}
+#else
+ ret = -ENOSYS;
+#endif
}
#endif /* CONFIG_NET_UDP */
@@ -663,6 +680,19 @@ int psock_connect(FAR struct socket *psock, FAR const struct sockaddr *addr,
break;
#endif /* CONFIG_NET_UDP || CONFIG_NET_LOCAL_DGRAM */
+#ifdef CONFIG_NET_USRSOCK
+ case SOCK_USRSOCK_TYPE:
+ {
+ ret = usrsock_connect(psock, addr, addrlen);
+ if (ret < 0)
+ {
+ errcode = -ret;
+ goto errout;
+ }
+ }
+ break;
+#endif /* CONFIG_NET_USRSOCK */
+
default:
errcode = EBADF;
goto errout;
diff --git a/net/socket/getsockname.c b/net/socket/getsockname.c
index 7bf87c29d12..703136e0d9e 100644
--- a/net/socket/getsockname.c
+++ b/net/socket/getsockname.c
@@ -44,6 +44,7 @@
#include
#include
+#include
#include
#include
@@ -54,6 +55,7 @@
#include "tcp/tcp.h"
#include "udp/udp.h"
#include "socket/socket.h"
+#include "usrsock/usrsock.h"
#ifdef CONFIG_NET
@@ -92,7 +94,7 @@ int ipv4_getsockname(FAR struct socket *psock, FAR struct sockaddr *addr,
FAR socklen_t *addrlen)
{
FAR struct net_driver_s *dev;
-#if defined(CONFIG_NET_TCP) || defined(CONFIG_NET_UDP)
+#if defined(NET_TCP_HAVE_STACK) || defined(NET_UDP_HAVE_STACK)
FAR struct sockaddr_in *outaddr = (FAR struct sockaddr_in *)addr;
#endif
#ifdef CONFIG_NETDEV_MULTINIC
@@ -116,7 +118,7 @@ int ipv4_getsockname(FAR struct socket *psock, FAR struct sockaddr *addr,
switch (psock->s_type)
{
-#ifdef CONFIG_NET_TCP
+#ifdef NET_TCP_HAVE_STACK
case SOCK_STREAM:
{
FAR struct tcp_conn_s *tcp_conn = (FAR struct tcp_conn_s *)psock->s_conn;
@@ -129,7 +131,7 @@ int ipv4_getsockname(FAR struct socket *psock, FAR struct sockaddr *addr,
break;
#endif
-#ifdef CONFIG_NET_UDP
+#ifdef NET_UDP_HAVE_STACK
case SOCK_DGRAM:
{
FAR struct udp_conn_s *udp_conn = (FAR struct udp_conn_s *)psock->s_conn;
@@ -171,7 +173,7 @@ int ipv4_getsockname(FAR struct socket *psock, FAR struct sockaddr *addr,
/* Set the address family and the IP address */
-#if defined(CONFIG_NET_TCP) || defined(CONFIG_NET_UDP)
+#if defined(NET_TCP_HAVE_STACK) || defined(NET_UDP_HAVE_STACK)
outaddr->sin_family = AF_INET;
outaddr->sin_addr.s_addr = dev->d_ipaddr;
*addrlen = sizeof(struct sockaddr_in);
@@ -215,7 +217,7 @@ int ipv6_getsockname(FAR struct socket *psock, FAR struct sockaddr *addr,
FAR socklen_t *addrlen)
{
FAR struct net_driver_s *dev;
-#if defined(CONFIG_NET_TCP) || defined(CONFIG_NET_UDP)
+#if defined(NET_TCP_HAVE_STACK) || defined(NET_UDP_HAVE_STACK)
FAR struct sockaddr_in6 *outaddr = (FAR struct sockaddr_in6 *)addr;
#endif
#ifdef CONFIG_NETDEV_MULTINIC
@@ -239,7 +241,7 @@ int ipv6_getsockname(FAR struct socket *psock, FAR struct sockaddr *addr,
switch (psock->s_type)
{
-#ifdef CONFIG_NET_TCP
+#ifdef NET_TCP_HAVE_STACK
case SOCK_STREAM:
{
FAR struct tcp_conn_s *tcp_conn = (FAR struct tcp_conn_s *)psock->s_conn;
@@ -252,7 +254,7 @@ int ipv6_getsockname(FAR struct socket *psock, FAR struct sockaddr *addr,
break;
#endif
-#ifdef CONFIG_NET_UDP
+#ifdef NET_UDP_HAVE_STACK
case SOCK_DGRAM:
{
FAR struct udp_conn_s *udp_conn = (FAR struct udp_conn_s *)psock->s_conn;
@@ -294,7 +296,7 @@ int ipv6_getsockname(FAR struct socket *psock, FAR struct sockaddr *addr,
/* Set the address family and the IP address */
-#if defined(CONFIG_NET_TCP) || defined(CONFIG_NET_UDP)
+#if defined(NET_TCP_HAVE_STACK) || defined(NET_UDP_HAVE_STACK)
outaddr->sin6_family = AF_INET6;
memcpy(outaddr->sin6_addr.in6_u.u6_addr8, dev->d_ipv6addr, 16);
*addrlen = sizeof(struct sockaddr_in6);
@@ -371,6 +373,26 @@ int getsockname(int sockfd, FAR struct sockaddr *addr, FAR socklen_t *addrlen)
}
#endif
+#ifdef CONFIG_NET_USRSOCK
+ if (psock->s_type == SOCK_USRSOCK_TYPE)
+ {
+ FAR struct usrsock_conn_s *conn = psock->s_conn;
+
+ DEBUGASSERT(conn);
+
+ /* Handle usrsock getsockname */
+
+ ret = usrsock_getsockname(conn, addr, addrlen);
+ if (ret < 0)
+ {
+ errcode = -ret;
+ goto errout;
+ }
+
+ return OK;
+ }
+#endif
+
/* Handle by address domain */
switch (psock->s_domain)
diff --git a/net/socket/getsockopt.c b/net/socket/getsockopt.c
index 5072f02067c..ab15d511aaf 100644
--- a/net/socket/getsockopt.c
+++ b/net/socket/getsockopt.c
@@ -43,9 +43,12 @@
#include
#include
#include
+#include
+#include
#include
#include "socket/socket.h"
+#include "usrsock/usrsock.h"
#include "utils/utils.h"
/****************************************************************************
@@ -106,6 +109,40 @@ int psock_getsockopt(FAR struct socket *psock, int level, int option,
goto errout;
}
+#ifdef CONFIG_NET_USRSOCK
+ if (psock->s_type == SOCK_USRSOCK_TYPE)
+ {
+ FAR struct usrsock_conn_s *conn = psock->s_conn;
+ int ret;
+
+ DEBUGASSERT(conn);
+
+ /* Some of the socket options are handled from this function. */
+
+ switch (option)
+ {
+ case SO_TYPE: /* Type can be read from NuttX psock structure. */
+ case SO_RCVTIMEO: /* Rx timeouts can be handled at NuttX side, thus
+ * simplify daemon implementation. */
+ case SO_SNDTIMEO: /* Rx timeouts can be handled at NuttX side, thus
+ * simplify daemon implementation. */
+ break;
+
+ default: /* Other options are passed to usrsock daemon. */
+ {
+ ret = usrsock_getsockopt(conn, level, option, value, value_len);
+ if (ret < 0)
+ {
+ errcode = -ret;
+ goto errout;
+ }
+
+ return OK;
+ }
+ }
+ }
+#endif
+
/* Process the option */
switch (option)
@@ -159,6 +196,20 @@ int psock_getsockopt(FAR struct socket *psock, int level, int option,
goto errout;
}
+#ifdef CONFIG_NET_USRSOCK
+ if (psock->s_type == SOCK_USRSOCK_TYPE)
+ {
+ FAR struct usrsock_conn_s *conn = psock->s_conn;
+
+ /* Return the actual socket type */
+
+ *(int*)value = conn->type;
+ *value_len = sizeof(int);
+
+ break;
+ }
+#endif
+
/* Return the socket type */
*(FAR int *)value = psock->s_type;
diff --git a/net/socket/listen.c b/net/socket/listen.c
index 0d91ccb5867..3b0189d019d 100644
--- a/net/socket/listen.c
+++ b/net/socket/listen.c
@@ -48,6 +48,7 @@
#include "tcp/tcp.h"
#include "local/local.h"
#include "socket/socket.h"
+#include "usrsock/usrsock.h"
/****************************************************************************
* Public Functions
@@ -92,6 +93,13 @@ int psock_listen(FAR struct socket *psock, int backlog)
if (psock->s_type != SOCK_STREAM || !psock->s_conn)
{
+#ifdef CONFIG_NET_USRSOCK
+ if (psock->s_type == SOCK_USRSOCK_TYPE)
+ {
+#warning "Missing logic"
+ }
+#endif
+
errcode = EOPNOTSUPP;
goto errout;
}
@@ -118,6 +126,7 @@ int psock_listen(FAR struct socket *psock, int backlog)
else
#endif
{
+#ifdef NET_TCP_HAVE_STACK
FAR struct tcp_conn_s *conn =
(FAR struct tcp_conn_s *)psock->s_conn;
@@ -143,6 +152,10 @@ int psock_listen(FAR struct socket *psock, int backlog)
*/
tcp_listen(conn);
+#else
+ errcode = EOPNOTSUPP;
+ goto errout;
+#endif /* NET_TCP_HAVE_STACK */
}
#endif /* CONFIG_NET_TCP */
diff --git a/net/socket/net_clone.c b/net/socket/net_clone.c
index 5398c614fdf..83a7c5150c4 100644
--- a/net/socket/net_clone.c
+++ b/net/socket/net_clone.c
@@ -51,6 +51,7 @@
#include "tcp/tcp.h"
#include "udp/udp.h"
#include "socket/socket.h"
+#include "usrsock/usrsock.h"
/****************************************************************************
* Public Functions
@@ -96,7 +97,7 @@ int net_clone(FAR struct socket *psock1, FAR struct socket *psock2)
DEBUGASSERT(psock2->s_conn);
psock2->s_crefs = 1; /* One reference on the new socket itself */
-#ifdef CONFIG_NET_TCP
+#ifdef NET_TCP_HAVE_STACK
if (psock2->s_type == SOCK_STREAM)
{
FAR struct tcp_conn_s *conn = psock2->s_conn;
@@ -105,7 +106,7 @@ int net_clone(FAR struct socket *psock1, FAR struct socket *psock2)
}
else
#endif
-#ifdef CONFIG_NET_UDP
+#ifdef NET_UDP_HAVE_STACK
if (psock2->s_type == SOCK_DGRAM)
{
FAR struct udp_conn_s *conn = psock2->s_conn;
@@ -113,6 +114,15 @@ int net_clone(FAR struct socket *psock1, FAR struct socket *psock2)
conn->crefs++;
}
else
+#endif
+#ifdef CONFIG_NET_USRSOCK
+ if (psock2->s_type == SOCK_USRSOCK_TYPE)
+ {
+ FAR struct usrsock_conn_s *conn = psock2->s_conn;
+ DEBUGASSERT(conn->crefs > 0 && conn->crefs < 255);
+ conn->crefs++;
+ }
+ else
#endif
{
nerr("ERROR: Unsupported type: %d\n", psock2->s_type);
diff --git a/net/socket/net_close.c b/net/socket/net_close.c
index ba0fb85dc1d..6bbc01b725f 100644
--- a/net/socket/net_close.c
+++ b/net/socket/net_close.c
@@ -67,12 +67,13 @@
#include "pkt/pkt.h"
#include "local/local.h"
#include "socket/socket.h"
+#include "usrsock/usrsock.h"
/****************************************************************************
* Private Types
****************************************************************************/
-#ifdef CONFIG_NET_TCP
+#ifdef NET_TCP_HAVE_STACK
struct tcp_close_s
{
FAR struct devif_callback_s *cl_cb; /* Reference to TCP callback instance */
@@ -106,7 +107,7 @@ struct tcp_close_s
*
****************************************************************************/
-#if defined(CONFIG_NET_TCP) && defined(CONFIG_NET_SOLINGER)
+#if defined(NET_TCP_HAVE_STACK) && defined(CONFIG_NET_SOLINGER)
static inline int close_timeout(FAR struct tcp_close_s *pstate)
{
FAR struct socket *psock = 0;
@@ -132,7 +133,7 @@ static inline int close_timeout(FAR struct tcp_close_s *pstate)
return FALSE;
}
-#endif /* CONFIG_NET_SOCKOPTS && CONFIG_NET_SOLINGER */
+#endif /* NET_TCP_HAVE_STACK && CONFIG_NET_SOLINGER */
/****************************************************************************
* Function: netclose_interrupt
@@ -151,7 +152,7 @@ static inline int close_timeout(FAR struct tcp_close_s *pstate)
*
****************************************************************************/
-#ifdef CONFIG_NET_TCP
+#ifdef NET_TCP_HAVE_STACK
static uint16_t netclose_interrupt(FAR struct net_driver_s *dev,
FAR void *pvconn, FAR void *pvpriv,
uint16_t flags)
@@ -256,7 +257,7 @@ end_wait:
return 0;
#endif
}
-#endif /* CONFIG_NET_TCP */
+#endif /* NET_TCP_HAVE_STACK */
/****************************************************************************
* Function: netclose_txnotify
@@ -274,7 +275,7 @@ end_wait:
*
****************************************************************************/
-#ifdef CONFIG_NET_TCP
+#ifdef NET_TCP_HAVE_STACK
static inline void netclose_txnotify(FAR struct socket *psock,
FAR struct tcp_conn_s *conn)
{
@@ -313,7 +314,7 @@ static inline void netclose_txnotify(FAR struct socket *psock,
}
#endif /* CONFIG_NET_IPv6 */
}
-#endif /* CONFIG_NET_TCP */
+#endif /* NET_TCP_HAVE_STACK */
/****************************************************************************
* Function: netclose_disconnect
@@ -332,7 +333,7 @@ static inline void netclose_txnotify(FAR struct socket *psock,
*
****************************************************************************/
-#ifdef CONFIG_NET_TCP
+#ifdef NET_TCP_HAVE_STACK
static inline int netclose_disconnect(FAR struct socket *psock)
{
struct tcp_close_s state;
@@ -451,7 +452,7 @@ static inline int netclose_disconnect(FAR struct socket *psock)
net_unlock();
return ret;
}
-#endif /* CONFIG_NET_TCP */
+#endif /* NET_TCP_HAVE_STACK */
/****************************************************************************
* Function: local_close
@@ -557,6 +558,7 @@ int psock_close(FAR struct socket *psock)
else
#endif
{
+#ifdef NET_TCP_HAVE_STACK
FAR struct tcp_conn_s *conn = psock->s_conn;
/* Is this the last reference to the connection structure
@@ -592,6 +594,7 @@ int psock_close(FAR struct socket *psock)
conn->crefs--;
}
+#endif /* NET_TCP_HAVE_STACK */
}
#endif /* CONFIG_NET_TCP || CONFIG_NET_LOCAL_STREAM */
}
@@ -617,6 +620,7 @@ int psock_close(FAR struct socket *psock)
else
#endif
{
+#ifdef NET_UDP_HAVE_STACK
FAR struct udp_conn_s *conn = psock->s_conn;
/* Is this the last reference to the connection structure
@@ -636,6 +640,7 @@ int psock_close(FAR struct socket *psock)
conn->crefs--;
}
+#endif /* NET_UDP_HAVE_STACK */
}
#endif /* CONFIG_NET_UDP || CONFIG_NET_LOCAL_DGRAM */
}
@@ -668,6 +673,44 @@ int psock_close(FAR struct socket *psock)
break;
#endif
+#ifdef CONFIG_NET_USRSOCK
+ case SOCK_USRSOCK_TYPE:
+ {
+ FAR struct usrsock_conn_s *conn = psock->s_conn;
+
+ /* Is this the last reference to the connection structure (there
+ * could be more if the socket was dup'ed).
+ */
+
+ if (conn->crefs <= 1)
+ {
+ /* Yes... inform user-space daemon of socket close. */
+
+ errcode = usrsock_close(conn);
+
+ /* Free the connection structure */
+
+ conn->crefs = 0;
+ usrsock_free(psock->s_conn);
+
+ if (errcode < 0)
+ {
+ /* Return with error code, but free resources. */
+
+ errcode = -errcode;
+ goto errout_with_psock;
+ }
+ }
+ else
+ {
+ /* No.. Just decrement the reference count */
+
+ conn->crefs--;
+ }
+ }
+ break;
+#endif
+
default:
errcode = EBADF;
goto errout;
@@ -679,7 +722,7 @@ int psock_close(FAR struct socket *psock)
sock_release(psock);
return OK;
-#ifdef CONFIG_NET_TCP
+#if defined(NET_TCP_HAVE_STACK) || defined(CONFIG_NET_USRSOCK)
errout_with_psock:
sock_release(psock);
#endif
diff --git a/net/socket/net_monitor.c b/net/socket/net_monitor.c
index cee6a13cd94..d44a6fe5152 100644
--- a/net/socket/net_monitor.c
+++ b/net/socket/net_monitor.c
@@ -50,6 +50,8 @@
#include "tcp/tcp.h"
#include "socket/socket.h"
+#ifdef NET_TCP_HAVE_STACK
+
/****************************************************************************
* Private Function Prototypes
****************************************************************************/
@@ -345,4 +347,6 @@ void net_lostconnection(FAR struct socket *psock, uint16_t flags)
net_unlock();
}
+#endif /* NET_TCP_HAVE_STACK */
+
#endif /* CONFIG_NET && CONFIG_NET_TCP */
diff --git a/net/socket/net_poll.c b/net/socket/net_poll.c
index e534e9d0220..0fe2b23db15 100644
--- a/net/socket/net_poll.c
+++ b/net/socket/net_poll.c
@@ -45,6 +45,7 @@
#include "udp/udp.h"
#include "local/local.h"
#include "socket/socket.h"
+#include "usrsock/usrsock.h"
#if defined(CONFIG_NET) && !defined(CONFIG_DISABLE_POLL)
@@ -57,7 +58,8 @@
*/
#undef HAVE_NET_POLL
-#if defined(HAVE_TCP_POLL) || defined(HAVE_UDP_POLL) || defined(HAVE_LOCAL_POLL)
+#if defined(HAVE_TCP_POLL) || defined(HAVE_UDP_POLL) || \
+ defined(HAVE_LOCAL_POLL) || defined(CONFIG_NET_USRSOCK)
# define HAVE_NET_POLL 1
#endif
@@ -233,6 +235,15 @@ int psock_poll(FAR struct socket *psock, FAR struct pollfd *fds, bool setup)
#else
int ret;
+#ifdef CONFIG_NET_USRSOCK
+ if (psock->s_type == SOCK_USRSOCK_TYPE)
+ {
+ /* Perform usrsock setup/teardown. */
+
+ return usrsock_poll(psock, fds, setup);
+ }
+#endif
+
/* Check if we are setting up or tearing down the poll */
if (setup)
diff --git a/net/socket/net_sendfile.c b/net/socket/net_sendfile.c
index 617bce53972..81f527abe76 100644
--- a/net/socket/net_sendfile.c
+++ b/net/socket/net_sendfile.c
@@ -72,6 +72,8 @@
#include "tcp/tcp.h"
#include "socket/socket.h"
+#ifdef NET_TCP_HAVE_STACK
+
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
@@ -615,6 +617,21 @@ ssize_t net_sendfile(int outfd, struct file *infile, off_t *offset,
goto errout;
}
+#ifdef CONFIG_NET_USRSOCK
+ /* If this is a usrsock socket, use generic sendfile implementation. */
+
+ if (psock->s_type == SOCK_USRSOCK_TYPE)
+ {
+ int infd;
+
+ list = sched_getfiles();
+ DEBUGASSERT(list != NULL);
+
+ infd = infile - list->fl_files;
+ return lib_sendfile(outfd, infd, offset, count);
+ }
+#endif /* CONFIG_NET_USRSOCK */
+
/* If this is an un-connected socket, then return ENOTCONN */
if (psock->s_type != SOCK_STREAM || !_SS_ISCONNECTED(psock->s_flags))
@@ -776,4 +793,6 @@ errout:
}
}
+#endif /* NET_TCP_HAVE_STACK */
+
#endif /* CONFIG_NET && CONFIG_NET_TCP */
diff --git a/net/socket/net_timeo.c b/net/socket/net_timeo.c
index 47099d205d5..81b7123a312 100644
--- a/net/socket/net_timeo.c
+++ b/net/socket/net_timeo.c
@@ -78,6 +78,7 @@ int net_timeo(systime_t start_time, socktimeo_t timeo)
{
return TRUE;
}
+
return FALSE;
}
diff --git a/net/socket/net_vfcntl.c b/net/socket/net_vfcntl.c
index b260edb5b0a..79df78379bc 100644
--- a/net/socket/net_vfcntl.c
+++ b/net/socket/net_vfcntl.c
@@ -49,6 +49,7 @@
#include
#include
#include "socket/socket.h"
+#include "usrsock/usrsock.h"
#if defined(CONFIG_NET) && CONFIG_NSOCKET_DESCRIPTORS > 0
@@ -164,6 +165,13 @@ int net_vfcntl(int sockfd, int cmd, va_list ap)
ret |= O_NONBLOCK;
}
#endif /* CONFIG_NET_LOCAL || CONFIG_NET_TCP_READAHEAD || CONFIG_NET_UDP_READAHEAD */
+
+#ifdef CONFIG_NET_USRSOCK
+ if (psock->s_type == SOCK_USRSOCK_TYPE && _SS_ISNONBLOCK(psock->s_flags))
+ {
+ ret |= O_NONBLOCK;
+ }
+#endif
}
break;
@@ -178,7 +186,7 @@ int net_vfcntl(int sockfd, int cmd, va_list ap)
{
#if defined(CONFIG_NET_LOCAL) || defined(CONFIG_NET_TCP_READAHEAD) || \
- defined(CONFIG_NET_UDP_READAHEAD)
+ defined(CONFIG_NET_UDP_READAHEAD) || defined(CONFIG_NET_USRSOCK)
/* Non-blocking is the only configurable option. And it applies
* only Unix domain sockets and to read operations on TCP/IP
* and UDP/IP sockets when read-ahead is enabled.
@@ -213,7 +221,22 @@ int net_vfcntl(int sockfd, int cmd, va_list ap)
}
else
#endif
-#endif /* CONFIG_NET_LOCAL || CONFIG_NET_TCP_READAHEAD || CONFIG_NET_UDP_READAHEAD */
+#if defined(CONFIG_NET_USRSOCK)
+ if (psock->s_type == SOCK_USRSOCK_TYPE) /* usrsock socket */
+ {
+ if ((mode & O_NONBLOCK) != 0)
+ {
+ psock->s_flags |= _SF_NONBLOCK;
+ }
+ else
+ {
+ psock->s_flags &= ~_SF_NONBLOCK;
+ }
+ }
+ else
+#endif
+#endif /* CONFIG_NET_LOCAL || CONFIG_NET_TCP_READAHEAD ||
+ CONFIG_NET_UDP_READAHEAD || CONFIG_NET_USRSOCK */
{
nerr("ERROR: Non-blocking not supported for this socket\n");
}
diff --git a/net/socket/recvfrom.c b/net/socket/recvfrom.c
index 64789b06720..fc713375cbd 100644
--- a/net/socket/recvfrom.c
+++ b/net/socket/recvfrom.c
@@ -72,6 +72,7 @@
#include "pkt/pkt.h"
#include "local/local.h"
#include "socket/socket.h"
+#include "usrsock/usrsock.h"
/****************************************************************************
* Pre-processor Definitions
@@ -90,7 +91,8 @@
* Private Types
****************************************************************************/
-#if defined(CONFIG_NET_UDP) || defined(CONFIG_NET_TCP) || defined(CONFIG_NET_PKT)
+#if defined(NET_UDP_HAVE_STACK) || defined(NET_TCP_HAVE_STACK) \
+ || defined(CONFIG_NET_PKT)
struct recvfrom_s
{
FAR struct socket *rf_sock; /* The parent socket structure */
@@ -106,7 +108,7 @@ struct recvfrom_s
ssize_t rf_recvlen; /* The received length */
int rf_result; /* Success:OK, failure:negated errno */
};
-#endif /* CONFIG_NET_UDP || CONFIG_NET_TCP */
+#endif /* NET_UDP_HAVE_STACK || NET_TCP_HAVE_STACK */
/****************************************************************************
* Private Functions
@@ -129,7 +131,8 @@ struct recvfrom_s
*
****************************************************************************/
-#if defined(CONFIG_NET_UDP) || defined(CONFIG_NET_TCP) || defined(CONFIG_NET_PKT)
+#if defined(NET_UDP_HAVE_STACK) || defined(NET_TCP_HAVE_STACK) \
+ || defined(CONFIG_NET_PKT)
static inline void recvfrom_add_recvlen(FAR struct recvfrom_s *pstate,
size_t recvlen)
@@ -143,7 +146,7 @@ static inline void recvfrom_add_recvlen(FAR struct recvfrom_s *pstate,
pstate->rf_buffer += recvlen;
pstate->rf_buflen -= recvlen;
}
-#endif /* CONFIG_NET_UDP || CONFIG_NET_TCP || CONFIG_NET_PKT */
+#endif /* NET_UDP_HAVE_STACK || NET_TCP_HAVE_STACK || CONFIG_NET_PKT */
/****************************************************************************
* Function: recvfrom_newdata
@@ -163,7 +166,7 @@ static inline void recvfrom_add_recvlen(FAR struct recvfrom_s *pstate,
*
****************************************************************************/
-#if defined(CONFIG_NET_UDP) || defined(CONFIG_NET_TCP)
+#if defined(NET_UDP_HAVE_STACK) || defined(NET_TCP_HAVE_STACK)
static size_t recvfrom_newdata(FAR struct net_driver_s *dev,
FAR struct recvfrom_s *pstate)
{
@@ -191,7 +194,7 @@ static size_t recvfrom_newdata(FAR struct net_driver_s *dev,
return recvlen;
}
-#endif /* CONFIG_NET_UDP || CONFIG_NET_TCP */
+#endif /* NET_UDP_HAVE_STACK || NET_TCP_HAVE_STACK */
/****************************************************************************
* Function: recvfrom_newpktdata
@@ -255,7 +258,7 @@ static void recvfrom_newpktdata(FAR struct net_driver_s *dev,
*
****************************************************************************/
-#ifdef CONFIG_NET_TCP
+#ifdef NET_TCP_HAVE_STACK
static inline void recvfrom_newtcpdata(FAR struct net_driver_s *dev,
FAR struct recvfrom_s *pstate)
{
@@ -307,7 +310,7 @@ static inline void recvfrom_newtcpdata(FAR struct net_driver_s *dev,
dev->d_len = 0;
}
-#endif /* CONFIG_NET_TCP */
+#endif /* NET_TCP_HAVE_STACK */
/****************************************************************************
* Function: recvfrom_newudpdata
@@ -327,7 +330,7 @@ static inline void recvfrom_newtcpdata(FAR struct net_driver_s *dev,
*
****************************************************************************/
-#ifdef CONFIG_NET_UDP
+#ifdef NET_UDP_HAVE_STACK
static inline void recvfrom_newudpdata(FAR struct net_driver_s *dev,
FAR struct recvfrom_s *pstate)
{
@@ -339,7 +342,7 @@ static inline void recvfrom_newudpdata(FAR struct net_driver_s *dev,
dev->d_len = 0;
}
-#endif /* CONFIG_NET_TCP */
+#endif /* NET_UDP_HAVE_STACK */
/****************************************************************************
* Function: recvfrom_tcpreadahead
@@ -359,7 +362,7 @@ static inline void recvfrom_newudpdata(FAR struct net_driver_s *dev,
*
****************************************************************************/
-#if defined(CONFIG_NET_TCP) && defined(CONFIG_NET_TCP_READAHEAD)
+#if defined(NET_TCP_HAVE_STACK) && defined(CONFIG_NET_TCP_READAHEAD)
static inline void recvfrom_tcpreadahead(struct recvfrom_s *pstate)
{
FAR struct tcp_conn_s *conn = (FAR struct tcp_conn_s *)pstate->rf_sock->s_conn;
@@ -419,9 +422,9 @@ static inline void recvfrom_tcpreadahead(struct recvfrom_s *pstate)
}
}
}
-#endif /* CONFIG_NET_UDP || CONFIG_NET_TCP */
+#endif /* NET_TCP_HAVE_STACK && CONFIG_NET_TCP_READAHEAD */
-#if defined(CONFIG_NET_UDP) && defined(CONFIG_NET_UDP_READAHEAD)
+#if defined(NET_UDP_HAVE_STACK) && defined(CONFIG_NET_UDP_READAHEAD)
static inline void recvfrom_udpreadahead(struct recvfrom_s *pstate)
{
@@ -526,7 +529,7 @@ out:
*
****************************************************************************/
-#if defined(CONFIG_NET_UDP) || defined(CONFIG_NET_TCP)
+#if defined(NET_UDP_HAVE_STACK) || defined(NET_TCP_HAVE_STACK)
#ifdef CONFIG_NET_SOCKOPTS
static int recvfrom_timeout(struct recvfrom_s *pstate)
{
@@ -581,7 +584,7 @@ static int recvfrom_timeout(struct recvfrom_s *pstate)
return FALSE;
}
#endif /* CONFIG_NET_SOCKOPTS */
-#endif /* CONFIG_NET_UDP || CONFIG_NET_TCP */
+#endif /* NET_UDP_HAVE_STACK || NET_TCP_HAVE_STACK */
/****************************************************************************
* Function: recvfrom_pktsender
@@ -684,7 +687,7 @@ static uint16_t recvfrom_pktinterrupt(FAR struct net_driver_s *dev,
*
****************************************************************************/
-#ifdef CONFIG_NET_TCP
+#ifdef NET_TCP_HAVE_STACK
static inline void recvfrom_tcpsender(FAR struct net_driver_s *dev,
FAR struct recvfrom_s *pstate)
{
@@ -735,7 +738,7 @@ static inline void recvfrom_tcpsender(FAR struct net_driver_s *dev,
}
#endif /* CONFIG_NET_IPv4 */
}
-#endif /* CONFIG_NET_TCP */
+#endif /* NET_TCP_HAVE_STACK */
/****************************************************************************
* Function: recvfrom_tcpinterrupt
@@ -757,7 +760,7 @@ static inline void recvfrom_tcpsender(FAR struct net_driver_s *dev,
*
****************************************************************************/
-#ifdef CONFIG_NET_TCP
+#ifdef NET_TCP_HAVE_STACK
static uint16_t recvfrom_tcpinterrupt(FAR struct net_driver_s *dev,
FAR void *pvconn, FAR void *pvpriv,
uint16_t flags)
@@ -958,7 +961,7 @@ static uint16_t recvfrom_tcpinterrupt(FAR struct net_driver_s *dev,
return flags;
}
-#endif /* CONFIG_NET_TCP */
+#endif /* NET_TCP_HAVE_STACK */
/****************************************************************************
* Function: recvfrom_udpsender
@@ -978,7 +981,7 @@ static uint16_t recvfrom_tcpinterrupt(FAR struct net_driver_s *dev,
*
****************************************************************************/
-#ifdef CONFIG_NET_UDP
+#ifdef NET_UDP_HAVE_STACK
static inline void recvfrom_udpsender(struct net_driver_s *dev, struct recvfrom_s *pstate)
{
/* Get the family from the packet type, IP address from the IP header, and
@@ -1059,7 +1062,7 @@ static inline void recvfrom_udpsender(struct net_driver_s *dev, struct recvfrom_
}
#endif /* CONFIG_NET_IPv4 */
}
-#endif /* CONFIG_NET_UDP */
+#endif /* NET_UDP_HAVE_STACK */
/****************************************************************************
* Function: recvfrom_udp_terminate
@@ -1076,7 +1079,7 @@ static inline void recvfrom_udpsender(struct net_driver_s *dev, struct recvfrom_
*
****************************************************************************/
-#ifdef CONFIG_NET_UDP
+#ifdef NET_UDP_HAVE_STACK
static void recvfrom_udp_terminate(FAR struct recvfrom_s *pstate, int result)
{
/* Don't allow any further UDP call backs. */
@@ -1095,7 +1098,7 @@ static void recvfrom_udp_terminate(FAR struct recvfrom_s *pstate, int result)
sem_post(&pstate->rf_sem);
}
-#endif /* CONFIG_NET_UDP */
+#endif /* NET_UDP_HAVE_STACK */
/****************************************************************************
* Function: recvfrom_udp_interrupt
@@ -1117,7 +1120,7 @@ static void recvfrom_udp_terminate(FAR struct recvfrom_s *pstate, int result)
*
****************************************************************************/
-#ifdef CONFIG_NET_UDP
+#ifdef NET_UDP_HAVE_STACK
static uint16_t recvfrom_udp_interrupt(FAR struct net_driver_s *dev,
FAR void *pvconn, FAR void *pvpriv,
uint16_t flags)
@@ -1189,7 +1192,7 @@ static uint16_t recvfrom_udp_interrupt(FAR struct net_driver_s *dev,
return flags;
}
-#endif /* CONFIG_NET_UDP */
+#endif /* NET_UDP_HAVE_STACK */
/****************************************************************************
* Function: recvfrom_init
@@ -1210,7 +1213,8 @@ static uint16_t recvfrom_udp_interrupt(FAR struct net_driver_s *dev,
*
****************************************************************************/
-#if defined(CONFIG_NET_UDP) || defined(CONFIG_NET_TCP) || defined(CONFIG_NET_PKT)
+#if defined(NET_UDP_HAVE_STACK) || defined(NET_TCP_HAVE_STACK) \
+ || defined(CONFIG_NET_PKT)
static void recvfrom_init(FAR struct socket *psock, FAR void *buf,
size_t len, FAR struct sockaddr *infrom,
FAR socklen_t *fromlen,
@@ -1246,7 +1250,7 @@ static void recvfrom_init(FAR struct socket *psock, FAR void *buf,
#define recvfrom_uninit(s) sem_destroy(&(s)->rf_sem)
-#endif /* CONFIG_NET_UDP || CONFIG_NET_TCP */
+#endif /* NET_UDP_HAVE_STACK || NET_TCP_HAVE_STACK */
/****************************************************************************
* Function: recvfrom_result
@@ -1265,7 +1269,8 @@ static void recvfrom_init(FAR struct socket *psock, FAR void *buf,
*
****************************************************************************/
-#if defined(CONFIG_NET_UDP) || defined(CONFIG_NET_TCP) || defined(CONFIG_NET_PKT)
+#if defined(NET_UDP_HAVE_STACK) || defined(NET_TCP_HAVE_STACK) \
+ || defined(CONFIG_NET_PKT)
static ssize_t recvfrom_result(int result, struct recvfrom_s *pstate)
{
int save_errno = get_errno(); /* In case something we do changes it */
@@ -1294,7 +1299,7 @@ static ssize_t recvfrom_result(int result, struct recvfrom_s *pstate)
return pstate->rf_recvlen;
}
-#endif /* CONFIG_NET_UDP || CONFIG_NET_TCP */
+#endif /* NET_UDP_HAVE_STACK || NET_TCP_HAVE_STACK */
/****************************************************************************
* Function: recvfromo_pkt_rxnotify
@@ -1334,7 +1339,7 @@ static void recvfromo_pkt_rxnotify(FAR struct pkt_conn_s *conn)
*
****************************************************************************/
-#ifdef CONFIG_NET_UDP
+#ifdef NET_UDP_HAVE_STACK
static inline void recvfrom_udp_rxnotify(FAR struct socket *psock,
FAR struct udp_conn_s *conn)
{
@@ -1373,7 +1378,7 @@ static inline void recvfrom_udp_rxnotify(FAR struct socket *psock,
}
#endif /* CONFIG_NET_IPv6 */
}
-#endif /* CONFIG_NET_UDP */
+#endif /* NET_UDP_HAVE_STACK */
/****************************************************************************
* Function: pkt_recvfrom
@@ -1489,7 +1494,7 @@ errout_with_state:
*
****************************************************************************/
-#ifdef CONFIG_NET_UDP
+#ifdef NET_UDP_HAVE_STACK
static ssize_t udp_recvfrom(FAR struct socket *psock, FAR void *buf, size_t len,
FAR struct sockaddr *from, FAR socklen_t *fromlen)
{
@@ -1607,7 +1612,7 @@ errout_with_state:
recvfrom_uninit(&state);
return ret;
}
-#endif /* CONFIG_NET_UDP */
+#endif /* NET_UDP_HAVE_STACK */
/****************************************************************************
* Function: tcp_recvfrom
@@ -1629,7 +1634,7 @@ errout_with_state:
*
****************************************************************************/
-#ifdef CONFIG_NET_TCP
+#ifdef NET_TCP_HAVE_STACK
static ssize_t tcp_recvfrom(FAR struct socket *psock, FAR void *buf, size_t len,
FAR struct sockaddr *from, FAR socklen_t *fromlen)
{
@@ -1785,7 +1790,7 @@ static ssize_t tcp_recvfrom(FAR struct socket *psock, FAR void *buf, size_t len,
recvfrom_uninit(&state);
return (ssize_t)ret;
}
-#endif /* CONFIG_NET_TCP */
+#endif /* NET_TCP_HAVE_STACK */
/****************************************************************************
* Public Functions
@@ -1880,6 +1885,22 @@ ssize_t psock_recvfrom(FAR struct socket *psock, FAR void *buf, size_t len,
goto errout;
}
+#ifdef CONFIG_NET_USRSOCK
+ if (psock->s_type == SOCK_USRSOCK_TYPE)
+ {
+ /* Perform the usrsock recvfrom operation */
+
+ ret = usrsock_recvfrom(psock, buf, len, from, fromlen);
+ if (ret < 0)
+ {
+ errcode = -ret;
+ goto errout;
+ }
+
+ return ret;
+ }
+#endif
+
/* If a 'from' address has been provided, verify that it is large
* enough to hold this address family.
*/
@@ -1964,7 +1985,11 @@ ssize_t psock_recvfrom(FAR struct socket *psock, FAR void *buf, size_t len,
else
#endif
{
+#ifdef NET_TCP_HAVE_STACK
ret = tcp_recvfrom(psock, buf, len, from, fromlen);
+#else
+ ret = -ENOSYS;
+#endif
}
#endif /* CONFIG_NET_TCP */
}
@@ -1989,7 +2014,11 @@ ssize_t psock_recvfrom(FAR struct socket *psock, FAR void *buf, size_t len,
else
#endif
{
+#ifdef NET_UDP_HAVE_STACK
ret = udp_recvfrom(psock, buf, len, from, fromlen);
+#else
+ ret = -ENOSYS;
+#endif
}
#endif /* CONFIG_NET_UDP */
}
diff --git a/net/socket/send.c b/net/socket/send.c
index fd37860a1a1..340e4caa62b 100644
--- a/net/socket/send.c
+++ b/net/socket/send.c
@@ -1,7 +1,7 @@
/****************************************************************************
* net/socket/send.c
*
- * Copyright (C) 2007-2014, 2016 Gregory Nutt. All rights reserved.
+ * Copyright (C) 2007-2014, 2016-2017 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt
*
* Redistribution and use in source and binary forms, with or without
@@ -51,6 +51,7 @@
#include "sixlowpan/sixlowpan.h"
#include "local/local.h"
#include "socket/socket.h"
+#include "usrsock/usrsock.h"
/****************************************************************************
* Public Functions
@@ -123,7 +124,7 @@
ssize_t psock_send(FAR struct socket *psock, FAR const void *buf, size_t len,
int flags)
{
- int ret;
+ ssize_t ret;
/* Treat as a cancellation point */
@@ -165,20 +166,18 @@ ssize_t psock_send(FAR struct socket *psock, FAR const void *buf, size_t len,
ret = psock_6lowpan_tcp_send(psock, buf, len);
-#ifdef CONFIG_NETDEV_MULTINIC
+#if defined(CONFIG_NETDEV_MULTINIC) && defined(NET_TCP_HAVE_STACK)
if (ret < 0)
{
- /* UDP/IP packet send */
+ /* TCP/IP packet send */
ret = psock_tcp_send(psock, buf, len);
}
-
-#endif /* CONFIG_NETDEV_MULTINIC */
-#else /* CONFIG_NET_6LOWPAN */
-
- /* Only TCP/IP packet send */
-
+#endif /* CONFIG_NETDEV_MULTINIC && NET_TCP_HAVE_STACK */
+#elif defined(NET_TCP_HAVE_STACK)
ret = psock_tcp_send(psock, buf, len);
+#else
+ ret = -ENOSYS;
#endif /* CONFIG_NET_6LOWPAN */
}
#endif /* CONFIG_NET_TCP */
@@ -205,25 +204,25 @@ ssize_t psock_send(FAR struct socket *psock, FAR const void *buf, size_t len,
else
#endif
{
-#ifdef CONFIG_NET_6LOWPAN
+#if defined(CONFIG_NET_6LOWPAN)
/* Try 6loWPAN UDP packet send */
ret = psock_6lowpan_udp_send(psock, buf, len);
-#ifdef CONFIG_NETDEV_MULTINIC
+#if defined(CONFIG_NETDEV_MULTINIC) && defined(NET_UDP_HAVE_STACK)
if (ret < 0)
{
/* UDP/IP packet send */
ret = psock_udp_send(psock, buf, len);
}
-
-#endif /* CONFIG_NETDEV_MULTINIC */
-#else /* CONFIG_NET_6LOWPAN */
-
+#endif /* CONFIG_NETDEV_MULTINIC && NET_UDP_HAVE_STACK */
+#elif defined(NET_UDP_HAVE_STACK)
/* Only UDP/IP packet send */
ret = psock_udp_send(psock, buf, len);
+#else
+ ret = -ENOSYS;
#endif /* CONFIG_NET_6LOWPAN */
}
#endif /* CONFIG_NET_UDP */
@@ -231,6 +230,14 @@ ssize_t psock_send(FAR struct socket *psock, FAR const void *buf, size_t len,
break;
#endif /* CONFIG_NET_UDP */
+#ifdef CONFIG_NET_USRSOCK
+ case SOCK_USRSOCK_TYPE:
+ {
+ ret = usrsock_sendto(psock, buf, len, NULL, 0);
+ }
+ break;
+#endif /*CONFIG_NET_USRSOCK*/
+
default:
{
/* EDESTADDRREQ. Signifies that the socket is not connection-mode
@@ -243,6 +250,11 @@ ssize_t psock_send(FAR struct socket *psock, FAR const void *buf, size_t len,
}
leave_cancellation_point();
+ if (ret < 0)
+ {
+ set_errno(-ret);
+ ret = ERROR;
+ }
return ret;
}
diff --git a/net/socket/sendto.c b/net/socket/sendto.c
index db51b73c79a..4c2798cd6ca 100644
--- a/net/socket/sendto.c
+++ b/net/socket/sendto.c
@@ -49,8 +49,10 @@
#include
#include "udp/udp.h"
+#include "sixlowpan/sixlowpan.h"
#include "local/local.h"
#include "socket/socket.h"
+#include "usrsock/usrsock.h"
/****************************************************************************
* Public Functions
@@ -126,7 +128,8 @@ ssize_t psock_sendto(FAR struct socket *psock, FAR const void *buf,
socklen_t tolen)
{
socklen_t minlen;
-#if defined(CONFIG_NET_UDP) || defined(CONFIG_NET_LOCAL_DGRAM)
+#if defined(CONFIG_NET_UDP) || defined(CONFIG_NET_LOCAL_DGRAM) || \
+ defined(CONFIG_NET_USRSOCK)
ssize_t nsent;
#endif
int errcode;
@@ -137,7 +140,8 @@ ssize_t psock_sendto(FAR struct socket *psock, FAR const void *buf,
if (!to || !tolen)
{
-#if defined(CONFIG_NET_TCP) || defined(CONFIG_NET_LOCAL_STREAM)
+#if defined(CONFIG_NET_TCP) || defined(CONFIG_NET_LOCAL_STREAM) || \
+ defined(CONFIG_NET_USRSOCK)
return psock_send(psock, buf, len, flags);
#else
nerr("ERROR: No 'to' address\n");
@@ -146,6 +150,22 @@ ssize_t psock_sendto(FAR struct socket *psock, FAR const void *buf,
#endif
}
+#ifdef CONFIG_NET_USRSOCK
+ if (psock->s_type == SOCK_USRSOCK_TYPE)
+ {
+ /* Perform the usrsock sendto operation */
+
+ nsent = usrsock_sendto(psock, buf, len, to, tolen);
+ if (nsent < 0)
+ {
+ errcode = -nsent;
+ goto errout;
+ }
+
+ return nsent;
+ }
+#endif
+
/* Verify that a valid address has been provided */
switch (to->sa_family)
@@ -218,7 +238,24 @@ ssize_t psock_sendto(FAR struct socket *psock, FAR const void *buf,
else
#endif
{
+#if defined(CONFIG_NET_6LOWPAN)
+ /* Try 6loWPAN UDP packet sendto() */
+
+ nsent = psock_6lowpan_udp_sendto(psock, buf, len, flags, to, tolen);
+
+#if defined(CONFIG_NETDEV_MULTINIC) && defined(NET_UDP_HAVE_STACK)
+ if (nsent < 0)
+ {
+ /* UDP/IP packet sendto */
+
+ nsent = psock_udp_sendto(psock, buf, len, flags, to, tolen);
+ }
+#endif /* CONFIG_NETDEV_MULTINIC && NET_UDP_HAVE_STACK */
+#elif defined(NET_UDP_HAVE_STACK)
nsent = psock_udp_sendto(psock, buf, len, flags, to, tolen);
+#else
+ nsent = -ENOSYS;
+#endif /* CONFIG_NET_6LOWPAN */
}
#endif /* CONFIG_NET_UDP */
diff --git a/net/socket/setsockopt.c b/net/socket/setsockopt.c
index cdcd8d2e851..fd41045f3e3 100644
--- a/net/socket/setsockopt.c
+++ b/net/socket/setsockopt.c
@@ -45,11 +45,14 @@
#include
#include
#include
+#include
+#include
#include
#include
#include "socket/socket.h"
+#include "usrsock/usrsock.h"
#include "utils/utils.h"
/****************************************************************************
@@ -115,6 +118,39 @@ int psock_setsockopt(FAR struct socket *psock, int level, int option,
goto errout;
}
+#ifdef CONFIG_NET_USRSOCK
+ if (psock->s_type == SOCK_USRSOCK_TYPE)
+ {
+ FAR struct usrsock_conn_s *conn = psock->s_conn;
+ int ret;
+
+ DEBUGASSERT(conn);
+
+ /* Some of the socket options are handled from this function. */
+
+ switch (option)
+ {
+ case SO_RCVTIMEO: /* Rx timeouts can be handled at NuttX side, thus
+ * simplify daemon implementation. */
+ case SO_SNDTIMEO: /* Rx timeouts can be handled at NuttX side, thus
+ * simplify daemon implementation. */
+ break;
+
+ default: /* Other options are passed to usrsock daemon. */
+ {
+ ret = usrsock_setsockopt(conn, level, option, value, value_len);
+ if (ret < 0)
+ {
+ errcode = -ret;
+ goto errout;
+ }
+
+ return OK;
+ }
+ }
+ }
+#endif
+
/* Process the option */
switch (option)
diff --git a/net/socket/socket.c b/net/socket/socket.c
index 56f6ddfe9c2..04d595a8315 100644
--- a/net/socket/socket.c
+++ b/net/socket/socket.c
@@ -52,6 +52,7 @@
#include "udp/udp.h"
#include "pkt/pkt.h"
#include "local/local.h"
+#include "usrsock/usrsock.h"
/****************************************************************************
* Private Functions
@@ -65,7 +66,7 @@
*
****************************************************************************/
-#ifdef CONFIG_NET_TCP
+#ifdef NET_TCP_HAVE_STACK
static int psock_tcp_alloc(FAR struct socket *psock)
{
/* Allocate the TCP connection structure */
@@ -90,7 +91,7 @@ static int psock_tcp_alloc(FAR struct socket *psock)
psock->s_conn = conn;
return OK;
}
-#endif /* CONFIG_NET_TCP */
+#endif /* NET_TCP_HAVE_STACK */
/****************************************************************************
* Name: psock_udp_alloc
@@ -100,7 +101,7 @@ static int psock_tcp_alloc(FAR struct socket *psock)
*
****************************************************************************/
-#ifdef CONFIG_NET_UDP
+#ifdef NET_UDP_HAVE_STACK
static int psock_udp_alloc(FAR struct socket *psock)
{
/* Allocate the UDP connection structure */
@@ -125,7 +126,7 @@ static int psock_udp_alloc(FAR struct socket *psock)
psock->s_conn = conn;
return OK;
}
-#endif /* CONFIG_NET_UDP */
+#endif /* NET_UDP_HAVE_STACK */
/****************************************************************************
* Name: psock_pkt_alloc
@@ -250,6 +251,47 @@ int psock_socket(int domain, int type, int protocol, FAR struct socket *psock)
int ret;
int errcode;
+#ifdef CONFIG_NET_USRSOCK
+ switch (domain)
+ {
+ default:
+ break;
+
+ case PF_INET:
+ case PF_INET6:
+ {
+#ifndef CONFIG_NET_USRSOCK_UDP
+ if (type == SOCK_DGRAM)
+ break;
+#endif
+#ifndef CONFIG_NET_USRSOCK_TCP
+ if (type == SOCK_STREAM)
+ break;
+#endif
+ psock->s_type = 0;
+ psock->s_conn = NULL;
+
+ ret = usrsock_socket(domain, type, protocol, psock);
+ if (ret >= 0)
+ {
+ /* Successfully handled and opened by usrsock daemon. */
+
+ return OK;
+ }
+ else if (ret == -ENETDOWN)
+ {
+ /* Net down means that usrsock daemon is not running.
+ * Attempt to open socket with kernel networking stack. */
+ }
+ else
+ {
+ errcode = -ret;
+ goto errout;
+ }
+ }
+ }
+#endif /* CONFIG_NET_USRSOCK */
+
/* Only PF_INET, PF_INET6 or PF_PACKET domains supported */
switch (domain)
@@ -400,9 +442,13 @@ int psock_socket(int domain, int type, int protocol, FAR struct socket *psock)
if (ipdomain)
#endif
{
+#ifdef NET_TCP_HAVE_STACK
/* Allocate and attach the TCP connection structure */
ret = psock_tcp_alloc(psock);
+#else
+ ret = -ENETDOWN;
+#endif
}
#endif /* CONFIG_NET_TCP */
@@ -438,9 +484,13 @@ int psock_socket(int domain, int type, int protocol, FAR struct socket *psock)
if (ipdomain)
#endif
{
+#ifdef NET_UDP_HAVE_STACK
/* Allocate and attach the UDP connection structure */
ret = psock_udp_alloc(psock);
+#else
+ ret = -ENETDOWN;
+#endif
}
#endif /* CONFIG_NET_UDP */
diff --git a/net/socket/socket.h b/net/socket/socket.h
index e9bfa161db3..4141cf7477d 100644
--- a/net/socket/socket.h
+++ b/net/socket/socket.h
@@ -49,6 +49,7 @@
#include
#include
+#include "tcp/tcp.h"
/****************************************************************************
* Pre-processor Definitions
@@ -152,7 +153,7 @@ extern "C"
* Public Function Prototypes
****************************************************************************/
-#ifdef CONFIG_NET_TCP
+#ifdef NET_TCP_HAVE_STACK
struct tcp_conn_s; /* Forward reference */
#endif
@@ -243,7 +244,7 @@ FAR struct socket *sockfd_socket(int sockfd);
*
****************************************************************************/
-#ifdef CONFIG_NET_TCP
+#ifdef NET_TCP_HAVE_STACK
int net_startmonitor(FAR struct socket *psock);
#endif
@@ -265,7 +266,7 @@ int net_startmonitor(FAR struct socket *psock);
*
****************************************************************************/
-#ifdef CONFIG_NET_TCP
+#ifdef NET_TCP_HAVE_STACK
void net_stopmonitor(FAR struct tcp_conn_s *conn);
#endif
@@ -287,7 +288,7 @@ void net_stopmonitor(FAR struct tcp_conn_s *conn);
*
****************************************************************************/
-#ifdef CONFIG_NET_TCP
+#ifdef NET_TCP_HAVE_STACK
void net_lostconnection(FAR struct socket *psock, uint16_t flags);
#endif
diff --git a/net/tcp/Kconfig b/net/tcp/Kconfig
index 59fa04d018b..8ac6aab1288 100644
--- a/net/tcp/Kconfig
+++ b/net/tcp/Kconfig
@@ -9,9 +9,16 @@ config NET_TCP
bool "TCP/IP Networking"
default n
---help---
- TCP support on or off
+ Enable or disable TCP networking support.
-if NET_TCP
+config NET_TCP_NO_STACK
+ bool "Disable TCP/IP Stack"
+ default n
+ select NET_TCP
+ ---help---
+ Build without TCP/IP stack even if TCP networking support enabled.
+
+if NET_TCP && !NET_TCP_NO_STACK
config NET_TCPURGDATA
bool "Urgent data"
@@ -184,5 +191,5 @@ config NET_SENDFILE
Support larger, higher performance sendfile() for transferring
files out a TCP connection.
-endif # NET_TCP
+endif # NET_TCP && !NET_TCP_NO_STACK
endmenu # TCP/IP Networking
diff --git a/net/tcp/Make.defs b/net/tcp/Make.defs
index 520e601f4c1..29b6167a65f 100644
--- a/net/tcp/Make.defs
+++ b/net/tcp/Make.defs
@@ -36,6 +36,7 @@
# TCP/IP source files
ifeq ($(CONFIG_NET_TCP),y)
+ifneq ($(CONFIG_NET_TCP_NO_STACK),y)
# Socket layer
@@ -73,4 +74,5 @@ endif
DEPPATH += --dep-path tcp
VPATH += :tcp
+endif # !CONFIG_NET_TCP_NO_STACK
endif # CONFIG_NET_TCP
diff --git a/net/tcp/tcp.h b/net/tcp/tcp.h
index c53475d75a4..f2a5115e53a 100644
--- a/net/tcp/tcp.h
+++ b/net/tcp/tcp.h
@@ -48,11 +48,14 @@
#include
#include
-#ifdef CONFIG_NET_TCP
+#if defined(CONFIG_NET_TCP) && !defined(CONFIG_NET_TCP_NO_STACK)
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
+
+#define NET_TCP_HAVE_STACK 1
+
/* Conditions for support TCP poll/select operations */
#if !defined(CONFIG_DISABLE_POLL) && CONFIG_NSOCKET_DESCRIPTORS > 0 && \
@@ -1306,5 +1309,5 @@ int tcp_pollteardown(FAR struct socket *psock, FAR struct pollfd *fds);
}
#endif
-#endif /* CONFIG_NET_TCP */
+#endif /* CONFIG_NET_TCP && !CONFIG_NET_TCP_NO_STACK */
#endif /* _NET_TCP_TCP_H */
diff --git a/net/tcp/tcp_devpoll.c b/net/tcp/tcp_devpoll.c
index 6a7f16c513b..d292d464738 100644
--- a/net/tcp/tcp_devpoll.c
+++ b/net/tcp/tcp_devpoll.c
@@ -46,6 +46,7 @@
#if defined(CONFIG_NET) && defined(CONFIG_NET_TCP)
#include
+#include
#include
#include
diff --git a/net/tcp/tcp_finddev.c b/net/tcp/tcp_finddev.c
index ef6ae8f0d25..e3cf0b32884 100644
--- a/net/tcp/tcp_finddev.c
+++ b/net/tcp/tcp_finddev.c
@@ -250,7 +250,6 @@ int tcp_local_ipv6_device(FAR struct tcp_conn_s *conn)
#else
return tcp_find_ipv6_device(conn, NULL);
#endif
-
}
#endif /* CONFIG_NET_IPv6 */
diff --git a/net/tcp/tcp_input.c b/net/tcp/tcp_input.c
index 184dfebb01c..1918bd34924 100644
--- a/net/tcp/tcp_input.c
+++ b/net/tcp/tcp_input.c
@@ -2,7 +2,7 @@
* net/tcp/tcp_input.c
* Handling incoming TCP input
*
- * Copyright (C) 2007-2014 Gregory Nutt. All rights reserved.
+ * Copyright (C) 2007-2014, 2017 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt
*
* Adapted for NuttX from logic in uIP which also has a BSD-like license:
diff --git a/net/tcp/tcp_send_unbuffered.c b/net/tcp/tcp_send_unbuffered.c
index 6c3688d85ad..5a2ccc98c42 100644
--- a/net/tcp/tcp_send_unbuffered.c
+++ b/net/tcp/tcp_send_unbuffered.c
@@ -129,7 +129,7 @@ struct send_s
* TRUE:timeout FALSE:no timeout
*
* Assumptions:
- * Running at the interrupt level
+ * The network is locked.
*
****************************************************************************/
@@ -139,7 +139,7 @@ static inline int send_timeout(FAR struct send_s *pstate)
FAR struct socket *psock;
/* Check for a timeout configured via setsockopts(SO_SNDTIMEO).
- * If none... we well let the send wait forever.
+ * If none... we will let the send wait forever.
*/
psock = pstate->snd_sock;
@@ -173,7 +173,7 @@ static inline int send_timeout(FAR struct send_s *pstate)
* None
*
* Assumptions:
- * Running at the interrupt level
+ * The network is locked.
*
****************************************************************************/
@@ -224,7 +224,7 @@ static inline void tcpsend_ipselect(FAR struct net_driver_s *dev,
* None
*
* Assumptions:
- * Running at the interrupt level
+ * The network is locked.
*
****************************************************************************/
@@ -278,7 +278,7 @@ static inline bool psock_send_addrchck(FAR struct tcp_conn_s *conn)
* None
*
* Assumptions:
- * Running at the interrupt level
+ * The network is locked.
*
****************************************************************************/
@@ -708,8 +708,6 @@ static inline void send_txnotify(FAR struct socket *psock,
* In this case the process will also receive a SIGPIPE unless
* MSG_NOSIGNAL is set.
*
- * Assumptions:
- *
****************************************************************************/
ssize_t psock_tcp_send(FAR struct socket *psock,
diff --git a/net/tcp/tcp_timer.c b/net/tcp/tcp_timer.c
index eeabb0910c4..245e849ec67 100644
--- a/net/tcp/tcp_timer.c
+++ b/net/tcp/tcp_timer.c
@@ -46,6 +46,7 @@
#if defined(CONFIG_NET) && defined(CONFIG_NET_TCP)
#include
+#include
#include
#include
diff --git a/net/udp/Kconfig b/net/udp/Kconfig
index a32f34534db..2c8e85d70b4 100644
--- a/net/udp/Kconfig
+++ b/net/udp/Kconfig
@@ -12,7 +12,14 @@ config NET_UDP
---help---
Enable or disable UDP networking support.
-if NET_UDP
+config NET_UDP_NO_STACK
+ bool "Disable UDP/IP Stack"
+ default n
+ select NET_UDP
+ ---help---
+ Build without UDP/IP stack even if UDP networking support enabled.
+
+if NET_UDP && !NET_UDP_NO_STACK
config NET_UDP_CHECKSUMS
bool "UDP checksums"
@@ -55,5 +62,5 @@ config NET_UDP_READAHEAD
default y
select NET_IOB
-endif # NET_UDP
+endif # NET_UDP && !NET_UDP_NO_STACK
endmenu # UDP Networking
diff --git a/net/udp/Make.defs b/net/udp/Make.defs
index 76c72b33ab0..4b3992911df 100644
--- a/net/udp/Make.defs
+++ b/net/udp/Make.defs
@@ -36,6 +36,7 @@
# UDP source files
ifeq ($(CONFIG_NET_UDP),y)
+ifneq ($(CONFIG_NET_UDP_NO_STACK),y)
# Socket layer
@@ -57,4 +58,5 @@ NET_CSRCS += udp_callback.c udp_ipselect.c
DEPPATH += --dep-path udp
VPATH += :udp
+endif # !CONFIG_NET_UDP_NO_STACK
endif # CONFIG_NET_UDP
diff --git a/net/udp/udp.h b/net/udp/udp.h
index f8584bff0b9..1aac4a83280 100644
--- a/net/udp/udp.h
+++ b/net/udp/udp.h
@@ -51,11 +51,14 @@
# include
#endif
-#ifdef CONFIG_NET_UDP
+#if defined(CONFIG_NET_UDP) && !defined(CONFIG_NET_UDP_NO_STACK)
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
+
+#define NET_UDP_HAVE_STACK 1
+
/* Conditions for support UDP poll/select operations */
#if !defined(CONFIG_DISABLE_POLL) && CONFIG_NSOCKET_DESCRIPTORS > 0 && \
@@ -510,5 +513,5 @@ int udp_pollteardown(FAR struct socket *psock, FAR struct pollfd *fds);
}
#endif
-#endif /* CONFIG_NET_UDP */
+#endif /* CONFIG_NET_UDP && !CONFIG_NET_UDP_NO_STACK */
#endif /* __NET_UDP_UDP_H */
diff --git a/net/usrsock/Kconfig b/net/usrsock/Kconfig
new file mode 100644
index 00000000000..677200cb678
--- /dev/null
+++ b/net/usrsock/Kconfig
@@ -0,0 +1,39 @@
+#
+# For a description of the syntax of this configuration file,
+# see misc/tools/kconfig-language.txt.
+#
+
+menu "User-space networking stack API"
+
+config NET_USRSOCK
+ bool "User-space networking stack API"
+ default n
+ depends on NET
+ ---help---
+ Enable or disable user-space networking stack support.
+
+if NET_USRSOCK
+
+config NET_USRSOCK_CONNS
+ int "Number of usrsock connections"
+ default 6
+ ---help---
+ Maximum number of usrsock connections (all tasks).
+
+ Note: Usrsock daemon can impose additional restrictions for
+ maximum number of concurrent connections supported.
+
+config NET_USRSOCK_UDP
+ bool "User-space daemon provides UDP sockets"
+ default n
+ select NET_UDP
+ ---help---
+
+config NET_USRSOCK_TCP
+ bool "User-space daemon provides TCP sockets"
+ default n
+ select NET_TCP
+ ---help---
+
+endif # NET_USRSOCK
+endmenu # User-space networking stack API
diff --git a/net/usrsock/Make.defs b/net/usrsock/Make.defs
new file mode 100644
index 00000000000..2aa069b077f
--- /dev/null
+++ b/net/usrsock/Make.defs
@@ -0,0 +1,51 @@
+############################################################################
+# net/usrsock/Make.defs
+#
+# Copyright (C) 2015, 2017 Haltian Ltd. All rights reserved.
+# Author: Jussi Kivilinna
+#
+# 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.
+#
+############################################################################
+
+# User Socket source files
+
+ifeq ($(CONFIG_NET_USRSOCK),y)
+
+NET_CSRCS += usrsock_close.c usrsock_conn.c usrsock_bind.c usrsock_connect.c
+NET_CSRCS += usrsock_dev.c
+NET_CSRCS += usrsock_event.c usrsock_getsockname.c usrsock_getsockopt.c
+NET_CSRCS += usrsock_poll.c usrsock_recvfrom.c usrsock_sendto.c
+NET_CSRCS += usrsock_setsockopt.c usrsock_socket.c
+
+# Include User Socket build support
+
+DEPPATH += --dep-path usrsock
+VPATH += :usrsock
+
+endif # CONFIG_NET_USRSOCK
diff --git a/net/usrsock/usrsock.h b/net/usrsock/usrsock.h
new file mode 100644
index 00000000000..55d92187e28
--- /dev/null
+++ b/net/usrsock/usrsock.h
@@ -0,0 +1,553 @@
+/****************************************************************************
+ * net/usrsock/usrsock.h
+ *
+ * Copyright (C) 2015, 2017 Haltian Ltd. All rights reserved.
+ * Author: Jussi Kivilinna
+ *
+ * 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 __NET_USRSOCK_USRSOCK_H
+#define __NET_USRSOCK_USRSOCK_H
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include
+
+#ifdef CONFIG_NET_USRSOCK
+
+#include
+#include
+#include
+
+#include "devif/devif.h"
+#include "socket/socket.h"
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+#ifndef ARRAY_SIZE
+# define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
+#endif
+
+/* Internal socket type/domain for marking usrsock sockets */
+
+#define SOCK_USRSOCK_TYPE 0x7f
+#define PF_USRSOCK_DOMAIN 0x7f
+
+/* Internal event flags */
+
+#define USRSOCK_EVENT_REQ_COMPLETE (1 << 14)
+#define USRSOCK_EVENT_CONNECT_RESP (1 << 15)
+#define USRSOCK_EVENT_INTERNAL_MASK 0xf000U
+
+/****************************************************************************
+ * Public Type Definitions
+ ****************************************************************************/
+
+struct usrsockdev_s;
+
+enum usrsock_conn_state_e
+{
+ USRSOCK_CONN_STATE_UNINITIALIZED = 0,
+ USRSOCK_CONN_STATE_ABORTED,
+ USRSOCK_CONN_STATE_READY,
+ USRSOCK_CONN_STATE_CONNECTING,
+};
+
+struct iovec
+{
+ FAR void *iov_base; /* Starting address */
+ size_t iov_len; /* Number of bytes to transfer */
+};
+
+struct usrsock_conn_s
+{
+ dq_entry_t node; /* Supports a doubly linked list */
+ uint8_t crefs; /* Reference counts on this instance */
+
+ enum usrsock_conn_state_e state; /* State of kernel<->daemon link for conn */
+ bool connected; /* Socket has been connected */
+ int8_t type; /* Socket type (SOCK_STREAM, etc) */
+ int16_t usockid; /* Connection number used for kernel<->daemon */
+ uint16_t flags; /* Socket state flags */
+ struct usrsockdev_s *dev; /* Device node used for this conn */
+
+ struct
+ {
+ uint8_t xid; /* Expected message exchange id */
+ bool inprogress; /* Request was received but daemon is still processing */
+ uint16_t valuelen; /* Length of value from daemon */
+ uint16_t valuelen_nontrunc; /* Actual length of value at daemon */
+ int result; /* Result for request */
+
+ struct
+ {
+ FAR struct iovec *iov; /* Data request input buffers */
+ int iovcnt; /* Number of input buffers */
+ size_t total; /* Total length of buffers */
+ size_t pos; /* Writer position on input buffer */
+ } datain;
+ } resp;
+
+ /* Defines the list of usrsock callbacks */
+
+ FAR struct devif_callback_s *list;
+};
+
+struct usrsock_reqstate_s
+{
+ FAR struct usrsock_conn_s *conn; /* Reference to connection structure */
+ FAR struct devif_callback_s *cb; /* Reference to callback instance */
+ sem_t recvsem; /* Semaphore signals recv completion */
+ int result; /* OK on success, otherwise a negated errno. */
+ bool completed;
+};
+
+struct usrsock_data_reqstate_s
+{
+ struct usrsock_reqstate_s reqstate;
+ uint16_t valuelen;
+ uint16_t valuelen_nontrunc;
+};
+
+/****************************************************************************
+ * Public Data
+ ****************************************************************************/
+
+#ifdef __cplusplus
+# define EXTERN extern "C"
+extern "C"
+{
+#else
+# define EXTERN extern
+#endif
+
+/****************************************************************************
+ * Public Function Prototypes
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: usrsock_initialize()
+ *
+ * Description:
+ * Initialize the User Socket connection structures. Called once and only
+ * from the networking layer.
+ *
+ ****************************************************************************/
+
+void usrsock_initialize(void);
+
+/****************************************************************************
+ * Name: usrsock_alloc()
+ *
+ * Description:
+ * Allocate a new, uninitialized usrsock connection structure. This is
+ * normally something done by the implementation of the socket() API
+ *
+ ****************************************************************************/
+
+FAR struct usrsock_conn_s *usrsock_alloc(void);
+
+/****************************************************************************
+ * Name: usrsock_free()
+ *
+ * Description:
+ * Free a usrsock connection structure that is no longer in use. This should
+ * be done by the implementation of close().
+ *
+ ****************************************************************************/
+
+void usrsock_free(FAR struct usrsock_conn_s *conn);
+
+/****************************************************************************
+ * Name: usrsock_nextconn()
+ *
+ * Description:
+ * Traverse the list of allocated usrsock connections
+ *
+ * Assumptions:
+ * This function is called from usrsock device logic.
+ *
+ ****************************************************************************/
+
+FAR struct usrsock_conn_s *usrsock_nextconn(FAR struct usrsock_conn_s *conn);
+
+/****************************************************************************
+ * Name: usrsock_connidx()
+ ****************************************************************************/
+
+int usrsock_connidx(FAR struct usrsock_conn_s *conn);
+
+/****************************************************************************
+ * Name: usrsock_active()
+ *
+ * Description:
+ * Find a connection structure that is the appropriate
+ * connection for usrsock
+ *
+ * Assumptions:
+ *
+ ****************************************************************************/
+
+FAR struct usrsock_conn_s *usrsock_active(int16_t usockid);
+
+/****************************************************************************
+ * Name: usrsock_setup_request_callback()
+ ****************************************************************************/
+
+int usrsock_setup_request_callback(FAR struct usrsock_conn_s *conn,
+ FAR struct usrsock_reqstate_s *pstate,
+ FAR devif_callback_event_t event,
+ uint16_t flags);
+
+/****************************************************************************
+ * Name: usrsock_setup_data_request_callback()
+ ****************************************************************************/
+
+int usrsock_setup_data_request_callback(FAR struct usrsock_conn_s *conn,
+ FAR struct usrsock_data_reqstate_s *pstate,
+ FAR devif_callback_event_t event,
+ uint16_t flags);
+
+/****************************************************************************
+ * Name: usrsock_teardown_request_callback()
+ ****************************************************************************/
+
+void usrsock_teardown_request_callback(FAR struct usrsock_reqstate_s *pstate);
+
+/****************************************************************************
+ * Name: usrsock_teardown_data_request_callback()
+ ****************************************************************************/
+
+#define usrsock_teardown_data_request_callback(datastate) \
+ usrsock_teardown_request_callback(&(datastate)->reqstate)
+
+/****************************************************************************
+ * Name: usrsock_event
+ *
+ * Description:
+ * Handler for received connection events
+ *
+ ****************************************************************************/
+
+int usrsock_event(FAR struct usrsock_conn_s *conn, uint16_t events);
+
+/****************************************************************************
+ * Name: usrsockdev_do_request
+ ****************************************************************************/
+
+int usrsockdev_do_request(FAR struct usrsock_conn_s *conn,
+ FAR struct iovec *iov, unsigned int iovcnt);
+
+/****************************************************************************
+ * Name: usrsockdev_register
+ *
+ * Description:
+ * Register /dev/usrsock
+ *
+ ****************************************************************************/
+
+void usrsockdev_register(void);
+
+/****************************************************************************
+ * Name: usrsock_socket
+ *
+ * Description:
+ * socket() creates an endpoint for communication and returns a socket
+ * structure.
+ *
+ * Input Parameters:
+ * domain (see sys/socket.h)
+ * type (see sys/socket.h)
+ * protocol (see sys/socket.h)
+ * psock A pointer to a user allocated socket structure to be initialized.
+ *
+ * Returned Value:
+ * 0 on success; negative error-code on error
+ *
+ * EACCES
+ * Permission to create a socket of the specified type and/or protocol
+ * is denied.
+ * EAFNOSUPPORT
+ * The implementation does not support the specified address family.
+ * EINVAL
+ * Unknown protocol, or protocol family not available.
+ * EMFILE
+ * Process file table overflow.
+ * ENFILE
+ * The system limit on the total number of open files has been reached.
+ * ENOBUFS or ENOMEM
+ * Insufficient memory is available. The socket cannot be created until
+ * sufficient resources are freed.
+ * EPROTONOSUPPORT
+ * The protocol type or the specified protocol is not supported within
+ * this domain.
+ *
+ * Assumptions:
+ *
+ ****************************************************************************/
+
+int usrsock_socket(int domain, int type, int protocol, FAR struct socket *psock);
+
+/****************************************************************************
+ * Name: usrsock_close
+ *
+ * Description:
+ * Performs the close operation on a usrsock connection instance
+ *
+ * Input Parameters:
+ * conn usrsock connection instance
+ *
+ * Returned Value:
+ * 0 on success; -1 on error with errno set appropriately.
+ *
+ * Assumptions:
+ *
+ ****************************************************************************/
+
+int usrsock_close(FAR struct usrsock_conn_s *conn);
+
+/****************************************************************************
+ * Name: usrsock_bind
+ *
+ * Description:
+ * usrsock_bind() gives the socket 'conn' the local address 'addr'. 'addr'
+ * is 'addrlen' bytes long. Traditionally, this is called "assigning a name
+ * to a socket." When a socket is created with socket, it exists in a name
+ * space (address family) but has no name assigned.
+ *
+ * Input Parameters:
+ * conn usrsock socket connection structure
+ * addr Socket local address
+ * addrlen Length of 'addr'
+ *
+ * Returned Value:
+ * 0 on success; -1 on error with errno set appropriately
+ *
+ * EACCES
+ * The address is protected, and the user is not the superuser.
+ * EADDRINUSE
+ * The given address is already in use.
+ * EINVAL
+ * The socket is already bound to an address.
+ * ENOTSOCK
+ * psock is a descriptor for a file, not a socket.
+ *
+ * Assumptions:
+ *
+ ****************************************************************************/
+
+int usrsock_bind(FAR struct usrsock_conn_s *conn,
+ FAR const struct sockaddr *addr,
+ socklen_t addrlen);
+
+/****************************************************************************
+ * Name: usrsock_connect
+ *
+ * Description:
+ * Perform a usrsock connection
+ *
+ * Input Parameters:
+ * psock A reference to the socket structure of the socket to be connected
+ * addr The address of the remote server to connect to
+ * addrlen Length of address buffer
+ *
+ * Returned Value:
+ * None
+ *
+ * Assumptions:
+ *
+ ****************************************************************************/
+
+int usrsock_connect(FAR struct socket *psock,
+ FAR const struct sockaddr *addr, socklen_t addrlen);
+
+/****************************************************************************
+ * Name: usrsock_poll
+ *
+ * Description:
+ * The standard poll() operation redirects operations on socket descriptors
+ * to this function.
+ *
+ * Input Parameters:
+ * psock - An instance of the internal socket structure.
+ * fds - The structure describing the events to be monitored.
+ * setup - true: Setup up the poll; false: Teardown the poll
+ *
+ * Returned Value:
+ * 0: Success; Negated errno on failure
+ *
+ ****************************************************************************/
+
+#ifndef CONFIG_DISABLE_POLL
+int usrsock_poll(FAR struct socket *psock, FAR struct pollfd *fds, bool setup);
+#endif
+
+/****************************************************************************
+ * Name: usrsock_sendto
+ *
+ * Description:
+ * If sendto() is used on a connection-mode (SOCK_STREAM, SOCK_SEQPACKET)
+ * socket, the parameters to and 'tolen' are ignored (and the error EISCONN
+ * may be returned when they are not NULL and 0), and the error ENOTCONN is
+ * returned when the socket was not actually connected.
+ *
+ * Input Parameters:
+ * psock A reference to the socket structure of the socket to be connected
+ * buf Data to send
+ * len Length of data to send
+ * to Address of recipient
+ * tolen The length of the address structure
+ *
+ * Returned Value:
+ * None
+ *
+ * Assumptions:
+ *
+ ****************************************************************************/
+
+ssize_t usrsock_sendto(FAR struct socket *psock, FAR const void *buf,
+ size_t len, FAR const struct sockaddr *to,
+ socklen_t tolen);
+
+/****************************************************************************
+ * Name: usrsock_recvfrom
+ *
+ * Description:
+ * recvfrom() receives messages from a socket, and may be used to receive
+ * data on a socket whether or not it is connection-oriented.
+ *
+ * If from is not NULL, and the underlying protocol provides the source
+ * address, this source address is filled in. The argument fromlen
+ * initialized to the size of the buffer associated with from, and modified
+ * on return to indicate the actual size of the address stored there.
+ *
+ * Input Parameters:
+ * psock A pointer to a NuttX-specific, internal socket structure
+ * buf Buffer to receive data
+ * len Length of buffer
+ * flags Receive flags
+ * from Address of source (may be NULL)
+ * fromlen The length of the address structure
+ *
+ ****************************************************************************/
+
+ssize_t usrsock_recvfrom(FAR struct socket *psock, FAR void *buf, size_t len,
+ FAR struct sockaddr *from, FAR socklen_t *fromlen);
+
+/****************************************************************************
+ * Name: usrsock_getsockopt
+ *
+ * Description:
+ * getsockopt() retrieve thse value for the option specified by the
+ * 'option' argument for the socket specified by the 'psock' argument. If
+ * the size of the option value is greater than 'value_len', the value
+ * stored in the object pointed to by the 'value' argument will be silently
+ * truncated. Otherwise, the length pointed to by the 'value_len' argument
+ * will be modified to indicate the actual length of the'value'.
+ *
+ * The 'level' argument specifies the protocol level of the option. To
+ * retrieve options at the socket level, specify the level argument as
+ * SOL_SOCKET.
+ *
+ * See a complete list of values for the 'option' argument.
+ *
+ * Input Parameters:
+ * conn usrsock socket connection structure
+ * level Protocol level to set the option
+ * option identifies the option to get
+ * value Points to the argument value
+ * value_len The length of the argument value
+ *
+ ****************************************************************************/
+
+int usrsock_getsockopt(FAR struct usrsock_conn_s *conn, int level, int option,
+ FAR void *value, FAR socklen_t *value_len);
+
+/****************************************************************************
+ * Name: usrsock_setsockopt
+ *
+ * Description:
+ * psock_setsockopt() sets the option specified by the 'option' argument,
+ * at the protocol level specified by the 'level' argument, to the value
+ * pointed to by the 'value' argument for the socket on the 'psock' argument.
+ *
+ * The 'level' argument specifies the protocol level of the option. To set
+ * options at the socket level, specify the level argument as SOL_SOCKET.
+ *
+ * See a complete list of values for the 'option' argument.
+ *
+ * Input Parameters:
+ * conn usrsock socket connection structure
+ * level Protocol level to set the option
+ * option identifies the option to set
+ * value Points to the argument value
+ * value_len The length of the argument value
+ *
+ ****************************************************************************/
+
+int usrsock_setsockopt(FAR struct usrsock_conn_s *conn, int level, int option,
+ FAR const void *value, FAR socklen_t value_len);
+
+/****************************************************************************
+ * Name: usrsock_getsockname
+ *
+ * Description:
+ * The getsockname() function retrieves the locally-bound name of the
+ * specified socket, stores this address in the sockaddr structure pointed
+ * to by the 'addr' argument, and stores the length of this address in the
+ * object pointed to by the 'addrlen' argument.
+ *
+ * If the actual length of the address is greater than the length of the
+ * supplied sockaddr structure, the stored address will be truncated.
+ *
+ * If the socket has not been bound to a local name, the value stored in
+ * the object pointed to by address is unspecified.
+ *
+ * Input Parameters:
+ * conn usrsock socket connection structure
+ * addr sockaddr structure to receive data [out]
+ * addrlen Length of sockaddr structure [in/out]
+ *
+ ****************************************************************************/
+
+int usrsock_getsockname(FAR struct usrsock_conn_s *conn,
+ FAR struct sockaddr *addr, FAR socklen_t *addrlen);
+
+#undef EXTERN
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* CONFIG_NET_USRSOCK */
+#endif /* __NET_USRSOCK_USRSOCK_H */
diff --git a/net/usrsock/usrsock_bind.c b/net/usrsock/usrsock_bind.c
new file mode 100644
index 00000000000..8ce21f07623
--- /dev/null
+++ b/net/usrsock/usrsock_bind.c
@@ -0,0 +1,221 @@
+/****************************************************************************
+ * net/usrsock/usrsock_bind.c
+ *
+ * Copyright (C) 2015-2017 Haltian Ltd. All rights reserved.
+ * Author: Jussi Kivilinna
+ *
+ * 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
+#if defined(CONFIG_NET) && defined(CONFIG_NET_USRSOCK)
+
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include
+
+#include
+#include
+#include
+#include
+
+#include "socket/socket.h"
+#include "usrsock/usrsock.h"
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+static uint16_t bind_event(FAR struct net_driver_s *dev, FAR void *pvconn,
+ FAR void *pvpriv, uint16_t flags)
+{
+ FAR struct usrsock_reqstate_s *pstate = pvpriv;
+ FAR struct usrsock_conn_s *conn = pvconn;
+
+ if (flags & USRSOCK_EVENT_ABORT)
+ {
+ ninfo("socket aborted.\n");
+
+ pstate->result = -ECONNABORTED;
+
+ /* Stop further callbacks */
+
+ pstate->cb->flags = 0;
+ pstate->cb->priv = NULL;
+ pstate->cb->event = NULL;
+
+ /* Wake up the waiting thread */
+
+ sem_post(&pstate->recvsem);
+ }
+ else if (flags & USRSOCK_EVENT_REQ_COMPLETE)
+ {
+ ninfo("request completed.\n");
+
+ pstate->result = conn->resp.result;
+
+ /* Stop further callbacks */
+
+ pstate->cb->flags = 0;
+ pstate->cb->priv = NULL;
+ pstate->cb->event = NULL;
+
+ /* Wake up the waiting thread */
+
+ sem_post(&pstate->recvsem);
+ }
+
+ return flags;
+}
+
+/****************************************************************************
+ * Name: do_bind_request
+ ****************************************************************************/
+
+static int do_bind_request(FAR struct usrsock_conn_s *conn,
+ FAR const struct sockaddr *addr,
+ socklen_t addrlen)
+{
+ struct usrsock_request_bind_s req = {};
+ struct iovec bufs[2];
+
+ /* Prepare request for daemon to read. */
+
+ req.head.reqid = USRSOCK_REQUEST_BIND;
+ req.usockid = conn->usockid;
+ req.addrlen = addrlen;
+
+ bufs[0].iov_base = (FAR void *)&req;
+ bufs[0].iov_len = sizeof(req);
+ bufs[1].iov_base = (FAR void *)addr;
+ bufs[1].iov_len = req.addrlen;
+
+ return usrsockdev_do_request(conn, bufs, ARRAY_SIZE(bufs));
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: usrsock_bind
+ *
+ * Description:
+ * usrsock_bind() gives the socket 'conn' the local address 'addr'. 'addr'
+ * is 'addrlen' bytes long. Traditionally, this is called "assigning a name
+ * to a socket." When a socket is created with socket, it exists in a name
+ * space (address family) but has no name assigned.
+ *
+ * Parameters:
+ * conn usrsock socket connection structure
+ * addr Socket local address
+ * addrlen Length of 'addr'
+ *
+ * Returned Value:
+ * 0 on success; -1 on error with errno set appropriately
+ *
+ * EACCES
+ * The address is protected, and the user is not the superuser.
+ * EADDRINUSE
+ * The given address is already in use.
+ * EINVAL
+ * The socket is already bound to an address.
+ * ENOTSOCK
+ * psock is a descriptor for a file, not a socket.
+ *
+ * Assumptions:
+ *
+ ****************************************************************************/
+
+int usrsock_bind(FAR struct usrsock_conn_s *conn,
+ FAR const struct sockaddr *addr,
+ socklen_t addrlen)
+{
+ struct usrsock_reqstate_s state = {};
+ ssize_t ret;
+
+ DEBUGASSERT(conn);
+
+ net_lock();
+
+ if (conn->state == USRSOCK_CONN_STATE_UNINITIALIZED ||
+ conn->state == USRSOCK_CONN_STATE_ABORTED)
+ {
+ /* Invalid state or closed by daemon. */
+
+ ninfo("usockid=%d; connect() with uninitialized usrsock.\n",
+ conn->usockid);
+
+ ret = (conn->state == USRSOCK_CONN_STATE_ABORTED) ? -EPIPE : -ECONNRESET;
+ goto errout_unlock;
+ }
+
+ /* Set up event callback for usrsock. */
+
+ ret = usrsock_setup_request_callback(conn, &state, bind_event,
+ USRSOCK_EVENT_ABORT |
+ USRSOCK_EVENT_REQ_COMPLETE);
+ if (ret < 0)
+ {
+ nwarn("usrsock_setup_request_callback failed: %d\n", ret);
+ goto errout_unlock;
+ }
+
+ /* Request user-space daemon to close socket. */
+
+ ret = do_bind_request(conn, addr, addrlen);
+ if (ret >= 0)
+ {
+ /* Wait for completion of request. */
+
+ while (net_lockedwait(&state.recvsem) != OK)
+ {
+ DEBUGASSERT(*get_errno_ptr() == EINTR);
+ }
+
+ ret = state.result;
+ }
+
+ usrsock_teardown_request_callback(&state);
+
+errout_unlock:
+ net_unlock();
+ return ret;
+}
+
+#endif /* CONFIG_NET && CONFIG_NET_USRSOCK */
diff --git a/net/usrsock/usrsock_close.c b/net/usrsock/usrsock_close.c
new file mode 100644
index 00000000000..bb6f052732f
--- /dev/null
+++ b/net/usrsock/usrsock_close.c
@@ -0,0 +1,205 @@
+/****************************************************************************
+ * net/usrsock/usrsock_close.c
+ *
+ * Copyright (C) 2015, 2017 Haltian Ltd. All rights reserved.
+ * Author: Jussi Kivilinna
+ *
+ * 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
+#if defined(CONFIG_NET) && defined(CONFIG_NET_USRSOCK)
+
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include
+
+#include
+#include
+#include
+
+#include "usrsock/usrsock.h"
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+static uint16_t close_event(FAR struct net_driver_s *dev, FAR void *pvconn,
+ FAR void *pvpriv, uint16_t flags)
+{
+ FAR struct usrsock_reqstate_s *pstate = pvpriv;
+ FAR struct usrsock_conn_s *conn = pvconn;
+
+ if (flags & USRSOCK_EVENT_ABORT)
+ {
+ ninfo("socket aborted.\n");
+
+ conn->state = USRSOCK_CONN_STATE_ABORTED;
+ pstate->result = -ECONNABORTED;
+
+ /* Stop further callbacks */
+
+ pstate->cb->flags = 0;
+ pstate->cb->priv = NULL;
+ pstate->cb->event = NULL;
+
+ /* Wake up the waiting thread */
+
+ sem_post(&pstate->recvsem);
+ }
+ else if (flags & USRSOCK_EVENT_REQ_COMPLETE)
+ {
+ ninfo("request completed.\n");
+
+ pstate->result = conn->resp.result;
+
+ /* Stop further callbacks */
+
+ pstate->cb->flags = 0;
+ pstate->cb->priv = NULL;
+ pstate->cb->event = NULL;
+
+ /* Wake up the waiting thread */
+
+ sem_post(&pstate->recvsem);
+ }
+
+ return flags;
+}
+
+/****************************************************************************
+ * Name: do_close_request
+ ****************************************************************************/
+
+static int do_close_request(FAR struct usrsock_conn_s *conn)
+{
+ struct usrsock_request_close_s req = {};
+ struct iovec bufs[1];
+
+ /* Prepare request for daemon to read. */
+
+ req.head.reqid = USRSOCK_REQUEST_CLOSE;
+ req.usockid = conn->usockid;
+
+ bufs[0].iov_base = (FAR void *)&req;
+ bufs[0].iov_len = sizeof(req);
+
+ return usrsockdev_do_request(conn, bufs, ARRAY_SIZE(bufs));
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Function: usrsock_close
+ *
+ * Description:
+ *
+ ****************************************************************************/
+
+int usrsock_close(FAR struct usrsock_conn_s *conn)
+{
+ struct usrsock_reqstate_s state = {};
+ int ret;
+
+ net_lock();
+
+ if (conn->state == USRSOCK_CONN_STATE_UNINITIALIZED ||
+ conn->state == USRSOCK_CONN_STATE_ABORTED)
+ {
+ /* Already closed? */
+
+ ninfo("usockid=%d; already closed.\n", conn->usockid);
+
+ ret = OK;
+ goto close_out;
+ }
+
+ /* Set up event callback for usrsock. */
+
+ ret = usrsock_setup_request_callback(conn, &state, close_event,
+ USRSOCK_EVENT_ABORT |
+ USRSOCK_EVENT_REQ_COMPLETE);
+ if (ret < 0)
+ {
+ nwarn("usrsock_setup_request_callback failed: %d\n", ret);
+ goto errout;
+ }
+
+ /* Request user-space daemon to close socket. */
+
+ ret = do_close_request(conn);
+ if (ret < 0)
+ {
+ ret = OK; /* Error? return OK for close. */
+ }
+ else
+ {
+ /* Wait for completion of request. */
+
+ while (net_lockedwait(&state.recvsem) != OK)
+ {
+ DEBUGASSERT(*get_errno_ptr() == EINTR);
+ }
+
+ ret = state.result;
+ if (ret < 0)
+ {
+ /* TODO: Error handling for close? Mark closed anyway? There is not
+ * much we can do if this happens.
+ */
+ ninfo("user-space daemon reported error %d for usockid=%d\n",
+ state.result, conn->usockid);
+
+ ret = OK;
+ }
+ }
+
+ usrsock_teardown_request_callback(&state);
+
+close_out:
+ conn->state = USRSOCK_CONN_STATE_UNINITIALIZED;
+ conn->usockid = -1;
+
+errout:
+ net_unlock();
+ return ret;
+}
+
+#endif /* CONFIG_NET && CONFIG_NET_USRSOCK */
diff --git a/net/usrsock/usrsock_conn.c b/net/usrsock/usrsock_conn.c
new file mode 100644
index 00000000000..0b022762467
--- /dev/null
+++ b/net/usrsock/usrsock_conn.c
@@ -0,0 +1,347 @@
+/****************************************************************************
+ * net/usrsock/usrsock_conn.c
+ *
+ * Copyright (C) 2015, 2017 Haltian Ltd. All rights reserved.
+ * Author: Jussi Kivilinna
+ *
+ * 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
+#if defined(CONFIG_NET) && defined(CONFIG_NET_USRSOCK)
+
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include
+
+#include
+#include
+
+#include "usrsock/usrsock.h"
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+/* The array containing all usrsock connections. */
+
+struct usrsock_conn_s g_usrsock_connections[CONFIG_NET_USRSOCK_CONNS];
+
+/* A list of all free usrsock connections */
+
+static dq_queue_t g_free_usrsock_connections;
+static sem_t g_free_sem;
+
+/* A list of all allocated usrsock connections */
+
+static dq_queue_t g_active_usrsock_connections;
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: _usrsock_semtake() and _usrsock_semgive()
+ *
+ * Description:
+ * Take/give semaphore
+ *
+ ****************************************************************************/
+
+static void _usrsock_semtake(FAR sem_t *sem)
+{
+ /* Take the semaphore (perhaps waiting) */
+
+ while (net_lockedwait(sem) != 0)
+ {
+ /* The only case that an error should occur here is if
+ * the wait was awakened by a signal.
+ */
+
+ DEBUGASSERT(*get_errno_ptr() == EINTR);
+ }
+}
+
+static void _usrsock_semgive(FAR sem_t *sem)
+{
+ (void)sem_post(sem);
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: usrsock_alloc()
+ *
+ * Description:
+ * Allocate a new, uninitialized usrsock connection structure. This is
+ * normally something done by the implementation of the socket() API
+ *
+ ****************************************************************************/
+
+FAR struct usrsock_conn_s *usrsock_alloc(void)
+{
+ FAR struct usrsock_conn_s *conn;
+
+ /* The free list is only accessed from user, non-interrupt level and
+ * is protected by a semaphore (that behaves like a mutex).
+ */
+
+ _usrsock_semtake(&g_free_sem);
+ conn = (FAR struct usrsock_conn_s *)dq_remfirst(&g_free_usrsock_connections);
+ if (conn)
+ {
+ /* Make sure that the connection is marked as uninitialized */
+
+ memset(conn, 0, sizeof(*conn));
+ conn->dev = NULL;
+ conn->usockid = -1;
+ conn->state = USRSOCK_CONN_STATE_UNINITIALIZED;
+ conn->list = NULL;
+ conn->connected = false;
+
+ /* Enqueue the connection into the active list */
+
+ dq_addlast(&conn->node, &g_active_usrsock_connections);
+ }
+
+ _usrsock_semgive(&g_free_sem);
+ return conn;
+}
+
+/****************************************************************************
+ * Name: usrsock_free()
+ *
+ * Description:
+ * Free a usrsock connection structure that is no longer in use. This should
+ * be done by the implementation of close().
+ *
+ ****************************************************************************/
+
+void usrsock_free(FAR struct usrsock_conn_s *conn)
+{
+ /* The free list is only accessed from user, non-interrupt level and
+ * is protected by a semaphore (that behaves like a mutex).
+ */
+
+ DEBUGASSERT(conn->crefs == 0);
+
+ _usrsock_semtake(&g_free_sem);
+
+ /* Remove the connection from the active list */
+
+ dq_rem(&conn->node, &g_active_usrsock_connections);
+
+ /* Reset structure */
+
+ memset(conn, 0, sizeof(*conn));
+ conn->dev = NULL;
+ conn->usockid = -1;
+ conn->state = USRSOCK_CONN_STATE_UNINITIALIZED;
+ conn->list = NULL;
+
+ /* Free the connection */
+
+ dq_addlast(&conn->node, &g_free_usrsock_connections);
+ _usrsock_semgive(&g_free_sem);
+}
+
+/****************************************************************************
+ * Name: usrsock_nextconn()
+ *
+ * Description:
+ * Traverse the list of allocated usrsock connections
+ *
+ * Assumptions:
+ * This function is called from usrsock device logic.
+ *
+ ****************************************************************************/
+
+FAR struct usrsock_conn_s *usrsock_nextconn(FAR struct usrsock_conn_s *conn)
+{
+ if (!conn)
+ {
+ return (FAR struct usrsock_conn_s *)g_active_usrsock_connections.head;
+ }
+ else
+ {
+ return (FAR struct usrsock_conn_s *)conn->node.flink;
+ }
+}
+
+/****************************************************************************
+ * Name: usrsock_connidx()
+ ****************************************************************************/
+
+int usrsock_connidx(FAR struct usrsock_conn_s *conn)
+{
+ int idx = conn - g_usrsock_connections;
+
+ DEBUGASSERT(idx >= 0);
+ DEBUGASSERT(idx < ARRAY_SIZE(g_usrsock_connections));
+
+ return idx;
+}
+
+/****************************************************************************
+ * Name: usrsock_active()
+ *
+ * Description:
+ * Find a connection structure that is the appropriate
+ * connection for usrsock
+ *
+ * Assumptions:
+ *
+ ****************************************************************************/
+
+FAR struct usrsock_conn_s *usrsock_active(int16_t usockid)
+{
+ FAR struct usrsock_conn_s *conn = NULL;
+
+ while ((conn = usrsock_nextconn(conn)) != NULL)
+ {
+ if (conn->usockid == usockid)
+ return conn;
+ }
+
+ return NULL;
+}
+
+/****************************************************************************
+ * Name: usrsock_setup_request_callback()
+ ****************************************************************************/
+
+int usrsock_setup_request_callback(FAR struct usrsock_conn_s *conn,
+ FAR struct usrsock_reqstate_s *pstate,
+ FAR devif_callback_event_t event,
+ uint16_t flags)
+{
+ int ret = -EBUSY;
+
+ (void)sem_init(&pstate->recvsem, 0, 0);
+ pstate->conn = conn;
+ pstate->result = -EAGAIN;
+ pstate->completed = false;
+
+ /* Set up the callback in the connection */
+
+ pstate->cb = devif_callback_alloc(NULL, &conn->list);
+ if (pstate->cb)
+ {
+ /* Set up the connection "interrupt" handler */
+
+ pstate->cb->flags = flags;
+ pstate->cb->priv = (FAR void *)pstate;
+ pstate->cb->event = event;
+
+ ret = OK;
+ }
+
+ return ret;
+}
+
+/****************************************************************************
+ * Name: usrsock_setup_data_request_callback()
+ ****************************************************************************/
+
+int usrsock_setup_data_request_callback(FAR struct usrsock_conn_s *conn,
+ FAR struct usrsock_data_reqstate_s *pstate,
+ FAR devif_callback_event_t event,
+ uint16_t flags)
+{
+ pstate->valuelen = 0;
+ pstate->valuelen_nontrunc = 0;
+ return usrsock_setup_request_callback(conn, &pstate->reqstate, event, flags);
+}
+
+/****************************************************************************
+ * Name: usrsock_teardown_request_callback()
+ ****************************************************************************/
+
+void usrsock_teardown_request_callback(FAR struct usrsock_reqstate_s *pstate)
+{
+ FAR struct usrsock_conn_s *conn = pstate->conn;
+
+ /* Make sure that no further events are processed */
+
+ devif_conn_callback_free(NULL, pstate->cb, &conn->list);
+
+ pstate->cb = NULL;
+}
+
+/****************************************************************************
+ * Name: usrsock_initialize()
+ *
+ * Description:
+ * Initialize the User Socket connection structures. Called once and only
+ * from the networking layer.
+ *
+ ****************************************************************************/
+
+void usrsock_initialize(void)
+{
+ int i;
+
+ /* Initialize the queues */
+
+ dq_init(&g_free_usrsock_connections);
+ dq_init(&g_active_usrsock_connections);
+ sem_init(&g_free_sem, 0, 1);
+
+ for (i = 0; i < CONFIG_NET_USRSOCK_CONNS; i++)
+ {
+ FAR struct usrsock_conn_s *conn = &g_usrsock_connections[i];
+
+ /* Mark the connection closed and move it to the free list */
+
+ memset(conn, 0, sizeof(*conn));
+ conn->dev = NULL;
+ conn->usockid = -1;
+ conn->state = USRSOCK_CONN_STATE_UNINITIALIZED;
+ conn->list = NULL;
+ conn->flags = 0;
+ dq_addlast(&conn->node, &g_free_usrsock_connections);
+ }
+
+ /* Register /dev/usrsock character device. */
+
+ usrsockdev_register();
+}
+
+#endif /* CONFIG_NET && CONFIG_NET_USRSOCK */
diff --git a/net/usrsock/usrsock_connect.c b/net/usrsock/usrsock_connect.c
new file mode 100644
index 00000000000..45ed8c1dd64
--- /dev/null
+++ b/net/usrsock/usrsock_connect.c
@@ -0,0 +1,257 @@
+/****************************************************************************
+ * net/usrsock/usrsock_connect.c
+ *
+ * Copyright (C) 2015, 2017 Haltian Ltd. All rights reserved.
+ * Author: Jussi Kivilinna
+ *
+ * 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
+#if defined(CONFIG_NET) && defined(CONFIG_NET_USRSOCK)
+
+#include |