diff --git a/arch/arm/src/stm32l4/Kconfig b/arch/arm/src/stm32l4/Kconfig index 7599a7933a..ae7c0403c6 100644 --- a/arch/arm/src/stm32l4/Kconfig +++ b/arch/arm/src/stm32l4/Kconfig @@ -3249,7 +3249,9 @@ config STM32L4_DAC1_TIMER config STM32L4_DAC1_TIMER_FREQUENCY int "DAC1 timer frequency" - default 0 + default 100 + ---help--- + DAC1 output frequency. Default: 100Hz endif @@ -3272,7 +3274,9 @@ config STM32L4_DAC2_TIMER config STM32L4_DAC2_TIMER_FREQUENCY int "DAC2 timer frequency" - default 0 + default 100 + ---help--- + DAC2 output frequency. Default: 100Hz endif diff --git a/arch/arm/src/stm32l4/stm32l4_adc.h b/arch/arm/src/stm32l4/stm32l4_adc.h index 7d3ae6ceac..39f7d665b6 100644 --- a/arch/arm/src/stm32l4/stm32l4_adc.h +++ b/arch/arm/src/stm32l4/stm32l4_adc.h @@ -177,7 +177,7 @@ #elif defined(CONFIG_STM32L4_TIM15_ADC1) # define ADC1_HAVE_TIMER 1 # define ADC1_TIMER_BASE STM32L4_TIM15_BASE -# define ADC1_TIMER_PCLK_FREQUENCY STM32L4_APB1_TIM15_CLKIN +# define ADC1_TIMER_PCLK_FREQUENCY STM32L4_APB2_TIM15_CLKIN #else # undef ADC1_HAVE_TIMER #endif @@ -219,7 +219,7 @@ #elif defined(CONFIG_STM32L4_TIM15_ADC2) # define ADC2_HAVE_TIMER 1 # define ADC2_TIMER_BASE STM32L4_TIM15_BASE -# define ADC2_TIMER_PCLK_FREQUENCY STM32L4_APB1_TIM15_CLKIN +# define ADC2_TIMER_PCLK_FREQUENCY STM32L4_APB2_TIM15_CLKIN #else # undef ADC2_HAVE_TIMER #endif @@ -261,7 +261,7 @@ #elif defined(CONFIG_STM32L4_TIM15_ADC3) # define ADC3_HAVE_TIMER 1 # define ADC3_TIMER_BASE STM32L4_TIM15_BASE -# define ADC3_TIMER_PCLK_FREQUENCY STM32L4_APB1_TIM15_CLKIN +# define ADC3_TIMER_PCLK_FREQUENCY STM32L4_APB2_TIM15_CLKIN #else # undef ADC3_HAVE_TIMER #endif diff --git a/arch/arm/src/stm32l4/stm32l4_dac.c b/arch/arm/src/stm32l4/stm32l4_dac.c index a984d773c8..90971aa042 100644 --- a/arch/arm/src/stm32l4/stm32l4_dac.c +++ b/arch/arm/src/stm32l4/stm32l4_dac.c @@ -103,11 +103,12 @@ #ifdef CONFIG_STM32L4_DAC1_DMA # if !defined(CONFIG_STM32L4_DAC1_TIMER) -# warning "A timer number must be specificed in CONFIG_STM32L4_DAC1_TIMER" +# warning "A timer number must be specified in CONFIG_STM32L4_DAC1_TIMER" # undef CONFIG_STM32L4_DAC1_DMA # undef CONFIG_STM32L4_DAC1_TIMER_FREQUENCY -# elif !defined(CONFIG_STM32L4_DAC1_TIMER_FREQUENCY) -# warning "A timer frequency must be specificed in CONFIG_STM32L4_DAC1_TIMER_FREQUENCY" +# elif !defined(CONFIG_STM32L4_DAC1_TIMER_FREQUENCY) || \ + (CONFIG_STM32L4_DAC1_TIMER_FREQUENCY < 1) +# warning "A timer frequency (>0) must be specified in CONFIG_STM32L4_DAC1_TIMER_FREQUENCY" # undef CONFIG_STM32L4_DAC1_DMA # undef CONFIG_STM32L4_DAC1_TIMER # endif @@ -115,11 +116,12 @@ #ifdef CONFIG_STM32L4_DAC2_DMA # if !defined(CONFIG_STM32L4_DAC2_TIMER) -# warning "A timer number must be specificed in CONFIG_STM32L4_DAC2_TIMER" +# warning "A timer number must be specified in CONFIG_STM32L4_DAC2_TIMER" # undef CONFIG_STM32L4_DAC2_DMA # undef CONFIG_STM32L4_DAC2_TIMER_FREQUENCY -# elif !defined(CONFIG_STM32L4_DAC2_TIMER_FREQUENCY) -# warning "A timer frequency must be specificed in CONFIG_STM32L4_DAC2_TIMER_FREQUENCY" +# elif !defined(CONFIG_STM32L4_DAC2_TIMER_FREQUENCY) || \ + (CONFIG_STM32L4_DAC2_TIMER_FREQUENCY < 1) +# warning "A timer frequency (>0) must be specified in CONFIG_STM32L4_DAC2_TIMER_FREQUENCY" # undef CONFIG_STM32L4_DAC2_DMA # undef CONFIG_STM32L4_DAC2_TIMER # endif @@ -269,7 +271,7 @@ #endif /* Calculate timer divider values based upon DACn_TIMER_PCLK_FREQUENCY and - * CONFIG_STM32_DACn_TIMER_FREQUENCY. + * CONFIG_STM32L4_DACn_TIMER_FREQUENCY. */ #warning "Missing Logic" @@ -312,6 +314,7 @@ struct stm32_chan_s DMA_HANDLE dma; /* Allocated DMA channel */ uint32_t tbase; /* Timer base address */ uint32_t tfrequency; /* Timer frequency */ + int result; /* DMA result */ uint16_t dmabuffer[CONFIG_STM32L4_DAC_DMA_BUFFER_SIZE]; /* DMA transfer buffer */ #endif }; @@ -323,9 +326,10 @@ struct stm32_chan_s /* DAC Register access */ #ifdef HAVE_DMA -static uint32_t tim_getreg(FAR struct stm32_chan_s *chan, int offset); -static void tim_putreg(FAR struct stm32_chan_s *chan, int offset, - uint32_t value); +static inline void tim_putreg(FAR struct stm32_chan_s *chan, int offset, + uint32_t value); +static inline void tim_modifyreg(FAR struct stm32_chan_s *chan, int offset, + uint32_t clearbits, uint32_t setbits); #endif /* DAC methods */ @@ -457,7 +461,7 @@ static struct stm32_dac_s g_dacblock; * Modify the contents of the DAC control register. * * Input Parameters: - * priv - Driver state instance + * chan - A reference to the DAC channel state data * clearbits - Bits in the control register to be cleared * setbits - Bits in the control register to be set * @@ -484,28 +488,6 @@ static inline void stm32l4_dac_modify_cr(FAR struct stm32_chan_s *chan, modifyreg32(chan->cr, clearbits << shift, setbits << shift); } -/**************************************************************************** - * Name: tim_getreg - * - * Description: - * Read the value of an DMA timer register. - * - * Input Parameters: - * chan - A reference to the DAC block status - * offset - The offset to the register to read - * - * Returned Value: - * The current contents of the specified register - * - ****************************************************************************/ - -#ifdef HAVE_DMA -static uint32_t tim_getreg(FAR struct stm32_chan_s *chan, int offset) -{ - return getreg32(chan->tbase + offset); -} -#endif - /**************************************************************************** * Name: tim_putreg * @@ -513,7 +495,7 @@ static uint32_t tim_getreg(FAR struct stm32_chan_s *chan, int offset) * Read the value of an DMA timer register. * * Input Parameters: - * chan - A reference to the DAC block status + * chan - A reference to the DAC channel state data * offset - The offset to the register to read * * Returned Value: @@ -522,8 +504,8 @@ static uint32_t tim_getreg(FAR struct stm32_chan_s *chan, int offset) ****************************************************************************/ #ifdef HAVE_DMA -static void tim_putreg(FAR struct stm32_chan_s *chan, int offset, - uint32_t value) +static inline void tim_putreg(FAR struct stm32_chan_s *chan, int offset, + uint32_t value) { putreg32(value, chan->tbase + offset); } @@ -536,7 +518,7 @@ static void tim_putreg(FAR struct stm32_chan_s *chan, int offset, * Modify the value of an DMA timer register. * * Input Parameters: - * priv - Driver state instance + * chan - A reference to the DAC channel state data * offset - The timer register offset * clearbits - Bits in the control register to be cleared * setbits - Bits in the control register to be set @@ -547,8 +529,8 @@ static void tim_putreg(FAR struct stm32_chan_s *chan, int offset, ****************************************************************************/ #ifdef HAVE_DMA -static void tim_modifyreg(FAR struct stm32_chan_s *chan, int offset, - uint32_t clearbits, uint32_t setbits) +static inline void tim_modifyreg(FAR struct stm32_chan_s *chan, int offset, + uint32_t clearbits, uint32_t setbits) { modifyreg32(chan->tbase + offset, clearbits, setbits); } @@ -659,6 +641,48 @@ static void dac_txint(FAR struct dac_dev_s *dev, bool enable) #ifdef HAVE_DMA static void dac_dmatxcallback(DMA_HANDLE handle, uint8_t isr, FAR void *arg) { + struct stm32_chan_s *chan = (struct stm32_chan_s *)arg; + struct dac_dev_s *dev; + + DEBUGASSERT(chan); + +#ifdef CONFIG_STM32L4_DAC1 + if (chan->intf == 0) + { + dev = &g_dac1dev; + } +#if STM32L4_NDAC > 1 + else if (chan->intf == 1) + { + dev = &g_dac2dev; + } +#endif + else +#endif /* CONFIG_STM32L4_DAC1 */ +#ifdef CONFIG_STM32L4_DAC2 + if (chan->intf == 2) + { + dev = &g_dac3dev; + } + else +#endif + { + DEBUGPANIC(); + } + + DEBUGASSERT(dev->ad_priv == chan); + + /* Report the result of the transfer only if the TX callback has not already + * reported an error. + */ + + if (chan->result == -EBUSY) + { + /* Save the result of the transfer if no error was previously reported. */ + + chan->result = (isr & DMA_CHAN_TEIF_BIT) ? -EIO : OK; + dac_txdone(dev); + } } #endif @@ -705,8 +729,9 @@ static int dac_send(FAR struct dac_dev_s *dev, FAR struct dac_msg_s *msg) stm32l4_dmasetup(chan->dma, chan->dro, (uint32_t)chan->dmabuffer, CONFIG_STM32L4_DAC_DMA_BUFFER_SIZE, DAC_DMA_CONTROL_WORD); - /* Enable DMA */ + /* Start the DMA */ + chan->result = -EBUSY; stm32l4_dmastart(chan->dma, dac_dmatxcallback, chan, false); /* Enable DMA for DAC Channel */ @@ -777,7 +802,7 @@ static int dac_timinit(FAR struct stm32_chan_s *chan) * counter mode (up). */ - /* Enable the timer. At most, two of the following cases (pluse the + /* Enable the timer. At most, two of the following cases (plus the * default) will be enabled */ @@ -1004,6 +1029,7 @@ static int dac_chaninit(FAR struct stm32_chan_s *chan) if (ret < 0) { aerr("ERROR: Failed to initialize the DMA timer: %d\n", ret); + stm32l4_dmafree(chan->dma); return ret; } } diff --git a/arch/arm/src/stm32l4/stm32l4_pwm.c b/arch/arm/src/stm32l4/stm32l4_pwm.c index c0879f676c..cff3431197 100644 --- a/arch/arm/src/stm32l4/stm32l4_pwm.c +++ b/arch/arm/src/stm32l4/stm32l4_pwm.c @@ -548,7 +548,7 @@ static struct stm32l4_pwmtimer_s g_pwm15dev = .irq = STM32L4_IRQ_TIM15, #endif .base = STM32L4_TIM15_BASE, - .pclk = STM32L4_APB1_TIM15_CLKIN, + .pclk = STM32L4_APB2_TIM15_CLKIN, }; #endif @@ -574,7 +574,7 @@ static struct stm32l4_pwmtimer_s g_pwm16dev = .irq = STM32L4_IRQ_TIM16, #endif .base = STM32L4_TIM16_BASE, - .pclk = STM32L4_APB1_TIM16_CLKIN, + .pclk = STM32L4_APB2_TIM16_CLKIN, }; #endif @@ -600,7 +600,7 @@ static struct stm32l4_pwmtimer_s g_pwm17dev = .irq = STM32L4_IRQ_TIM17, #endif .base = STM32L4_TIM17_BASE, - .pclk = STM32L4_APB1_TIM17_CLKIN, + .pclk = STM32L4_APB2_TIM17_CLKIN, }; #endif diff --git a/arch/arm/src/stm32l4/stm32l4x3xx_rcc.c b/arch/arm/src/stm32l4/stm32l4x3xx_rcc.c index b54cde4f99..42cea67c5b 100644 --- a/arch/arm/src/stm32l4/stm32l4x3xx_rcc.c +++ b/arch/arm/src/stm32l4/stm32l4x3xx_rcc.c @@ -435,8 +435,10 @@ static inline void rcc_enableapb2(void) regval = getreg32(STM32L4_RCC_APB2ENR); -#ifdef CONFIG_STM32L4_SYSCFG - /* System configuration controller clock enable */ +#if defined(CONFIG_STM32L4_SYSCFG) || defined(CONFIG_STM32L4_COMP) + /* System configuration controller, comparators, and voltage reference buffer + * clock enable + */ regval |= RCC_APB2ENR_SYSCFGEN; #endif diff --git a/arch/arm/src/stm32l4/stm32l4x5xx_rcc.c b/arch/arm/src/stm32l4/stm32l4x5xx_rcc.c index 66c31fd387..6a877e62af 100644 --- a/arch/arm/src/stm32l4/stm32l4x5xx_rcc.c +++ b/arch/arm/src/stm32l4/stm32l4x5xx_rcc.c @@ -446,8 +446,10 @@ static inline void rcc_enableapb2(void) regval = getreg32(STM32L4_RCC_APB2ENR); -#ifdef CONFIG_STM32L4_SYSCFG - /* System configuration controller clock enable */ +#if defined(CONFIG_STM32L4_SYSCFG) || defined(CONFIG_STM32L4_COMP) + /* System configuration controller, comparators, and voltage reference buffer + * clock enable + */ regval |= RCC_APB2ENR_SYSCFGEN; #endif diff --git a/arch/arm/src/stm32l4/stm32l4x6xx_rcc.c b/arch/arm/src/stm32l4/stm32l4x6xx_rcc.c index 32562bbdbc..dc2fecea77 100644 --- a/arch/arm/src/stm32l4/stm32l4x6xx_rcc.c +++ b/arch/arm/src/stm32l4/stm32l4x6xx_rcc.c @@ -491,8 +491,10 @@ static inline void rcc_enableapb2(void) regval = getreg32(STM32L4_RCC_APB2ENR); -#ifdef CONFIG_STM32L4_SYSCFG - /* System configuration controller clock enable */ +#if defined(CONFIG_STM32L4_SYSCFG) || defined(CONFIG_STM32L4_COMP) + /* System configuration controller, comparators, and voltage reference buffer + * clock enable + */ regval |= RCC_APB2ENR_SYSCFGEN; #endif diff --git a/arch/sim/Kconfig b/arch/sim/Kconfig index df46ddab30..f025acf965 100644 --- a/arch/sim/Kconfig +++ b/arch/sim/Kconfig @@ -16,6 +16,9 @@ config HOST_X86_64 config HOST_X86 bool "x86" +config HOST_ARM + bool "arm" + endchoice # Host CPU Type config SIM_M32 diff --git a/arch/sim/include/irq.h b/arch/sim/include/irq.h index ae95625ace..fe29b4c634 100644 --- a/arch/sim/include/irq.h +++ b/arch/sim/include/irq.h @@ -57,10 +57,12 @@ /* Storage order: %rbx, %rsp, %rbp, %r12, %r13, %r14, %r15, %rip */ # define XCPTCONTEXT_REGS 8 -#else +#elif defined(CONFIG_HOST_X86) || defined(CONFIG_SIM_M32) /* Storage order: %ebx, %esi, %edi, %ebp, sp, and return PC */ # define XCPTCONTEXT_REGS 6 +#elif defined(CONFIG_HOST_ARM) +# define XCPTCONTEXT_REGS 16 #endif /**************************************************************************** diff --git a/arch/sim/src/Makefile b/arch/sim/src/Makefile index e57b914c8e..031ebacc7b 100644 --- a/arch/sim/src/Makefile +++ b/arch/sim/src/Makefile @@ -47,10 +47,16 @@ ifeq ($(CONFIG_SIM_M32),y) else ASRCS += up_setjmp64.S endif -else +endif + +ifeq ($(CONFIG_HOST_X86_64),y) ASRCS += up_setjmp32.S endif +ifeq ($(CONFIG_HOST_ARM),y) + ASRCS += up_setjmp_arm.S +endif + AOBJS = $(ASRCS:.S=$(OBJEXT)) CSRCS = up_initialize.c up_idle.c up_interruptcontext.c up_initialstate.c diff --git a/arch/sim/src/up_internal.h b/arch/sim/src/up_internal.h index ef5263f2d6..71f41facd9 100644 --- a/arch/sim/src/up_internal.h +++ b/arch/sim/src/up_internal.h @@ -132,7 +132,7 @@ # define JB_SP JB_RSP # define JB_PC JB_RSI -#else +#elif defined(CONFIG_HOST_X86) || defined(CONFIG_SIM_M32) /* Storage order: %ebx, $esi, %edi, %ebp, sp, and return PC */ # ifdef __ASSEMBLY__ @@ -152,7 +152,10 @@ # define JB_PC (5) # endif /* __ASSEMBLY__ */ -#endif /* CONFIG_HOST_X86_64 && !CONFIG_SIM_M32 */ +#elif defined(CONFIG_HOST_ARM) +# define JB_SP 8 +# define JB_PC 9 +#endif /* Simulated Heap Definitions **********************************************/ /* Size of the simulated heap */ diff --git a/arch/sim/src/up_setjmp_arm.S b/arch/sim/src/up_setjmp_arm.S new file mode 100644 index 0000000000..444458c25f --- /dev/null +++ b/arch/sim/src/up_setjmp_arm.S @@ -0,0 +1,103 @@ +/**************************************************************************** + * arch/sim/src/up_setjmp_arm.h + * + * Copyright (C) 2017 Gregory Nutt. All rights reserved. + * Author: Nickolay Semyonov (RPI) + * + * Extracted from the MUSL C-library. The MUSL C library has a compatible + * MIT license and is released here under the NuttX 3-clause BSD license: + * + * 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. + * + ****************************************************************************/ + +.syntax unified +.global up_setjmp +.type up_setjmp,%function +up_setjmp: + mov ip,r0 + stmia ip!,{v1,v2,v3,v4,v5,v6,sl,fp} + mov r2,sp + stmia ip!,{r2,lr} + mov r0,#0 + +#if 0 + adr r1,1f + ldr r2,1f + ldr r1,[r1,r2] + + tst r1,#0x260 + beq 3f + tst r1,#0x20 + beq 2f + stc p2, cr4, [ip], #48 +2: tst r1,#0x40 + beq 2f + .fpu vfp + vstmia ip!, {d8-d15} + .fpu softvfp + .eabi_attribute 10, 0 + .eabi_attribute 27, 0 +2: tst r1,#0x200 + beq 3f + stcl p1, cr10, [ip], #8 + stcl p1, cr11, [ip], #8 + stcl p1, cr12, [ip], #8 + stcl p1, cr13, [ip], #8 + stcl p1, cr14, [ip], #8 + stcl p1, cr15, [ip], #8 +#endif +3: bx lr + +.syntax unified +.global up_longjmp +.type up_longjmp,%function +up_longjmp: + mov ip,r0 + movs r0,r1 + moveq r0,#1 + ldmia ip!, {v1,v2,v3,v4,v5,v6,sl,fp} + ldmia ip!, {r2,lr} + mov sp,r2 + +#if 0 + .fpu vfp + vldmia ip!, {d8-d15} + .fpu softvfp + .eabi_attribute 10, 0 + .eabi_attribute 27, 0 +2: tst r1,#0x200 + beq 3f + ldcl p1, cr10, [ip], #8 + ldcl p1, cr11, [ip], #8 + ldcl p1, cr12, [ip], #8 + ldcl p1, cr13, [ip], #8 + ldcl p1, cr14, [ip], #8 + ldcl p1, cr15, [ip], #8 +#endif +3: bx lr diff --git a/configs/arduino-due/README.txt b/configs/arduino-due/README.txt index a5065b6805..f85dc97b2c 100644 --- a/configs/arduino-due/README.txt +++ b/configs/arduino-due/README.txt @@ -2,8 +2,15 @@ README ^^^^^^ This README discusses issues unique to NuttX configurations for the - Arduino DUE board featuring the Atmel ATSAM3X8E MCU running at 84 - MHz. + Arduino DUE board featuring the Atmel ATSAM3X8E MCU running at 84 MHz. + + NOTE: If found that newer Arduino Due board differ from the older boards + mine: Mine has the 32.768 slow clock crystal and associated caps installed. + the newer boards do not. This can cause a hang in the SAM startup code + where it waits for the slow crystal input to lock on. + + Options: (1) Solder a 32.768 KHz crystal and associated caps on board or, + (2) disable the function sam_setupsupc() in sam_clockconfig.c Supported Shields ----------------- diff --git a/configs/arduino-due/include/board.h b/configs/arduino-due/include/board.h index 8f3bd90e9c..fb1df9ea1a 100644 --- a/configs/arduino-due/include/board.h +++ b/configs/arduino-due/include/board.h @@ -58,7 +58,7 @@ /* After power-on reset, the SAM3X device is running on a 4MHz internal RC. These * definitions will configure clocking * - * MAINOSC: Frequency = 12MHz (crysta) + * MAINOSC: Frequency = 12MHz (crystal) * PLLA: PLL Divider = 1, Multiplier = 14 to generate PLLACK = 168MHz * Master Clock (MCK): Source = PLLACK, Prescalar = 1 to generate MCK = 84MHz * CPU clock: 84MHz diff --git a/configs/b-l475e-iot01a/README.txt b/configs/b-l475e-iot01a/README.txt index 63c9744736..84310d6b6f 100644 --- a/configs/b-l475e-iot01a/README.txt +++ b/configs/b-l475e-iot01a/README.txt @@ -610,7 +610,17 @@ Configuration sub-directories unnecessarily busy. There is some prototype code to do just this in the driver, but does not seem to work. - 2017-08-24: There is only a single buffer for reassemblying larger - packets. This could be an important issue for the hub configuration + 2017-08-26: There was only a single buffer for reassemblying larger + packets. This could be a problem issue for the hub configuration which really needs the capability concurrently reassemble multiple - incoming streams. + incoming streams. The design was extended to support multiple + reassembly buffers. + + Initial testing shows the same basic behavior as noted before: + The UDP test works and TCP test (usually) works. There are, + however, are errors in reported by the hub in the TCP test. + Occassionally the test will hang when ther server echoes the data + back to the client. These errors are presumably the result of ACKs + from the receiver colliding with frames from the sender. + + Needs more investigation. diff --git a/configs/clicker2-stm32/README.txt b/configs/clicker2-stm32/README.txt index b44c5f9767..0f430595df 100644 --- a/configs/clicker2-stm32/README.txt +++ b/configs/clicker2-stm32/README.txt @@ -671,6 +671,7 @@ Configurations two star endpoints via the hub, the frames are correctly directed to the hub. However, they are not being forwarded to the other endpoint. + 2017-06-30: The failure to forward is understood: When the star endpoint sent the IPv6 destination address, the HC06 compression logic elided the address -- meaning that it could be reconstructed @@ -686,13 +687,16 @@ Configurations some additional fixes for byte ordering in 16-bit and 64-bit compressed IPv6 addresses, then all tests are working as expected: TCP, UDP, Telnet. + 2017-08-05: It looks like I have lost one of my Clicker2-STM32 boards. This means that I will not be able to do any regression testing as changes are made to the radio interfaces and 6LoWPAN :( - 2017-08-24: There is only a single buffer for reassemblying larger - packets. This could be an important issue for the hub configuration + + 2017-08-26: There was only a single buffer for reassemblying larger + packets. This could be a problem issue for the hub configuration which really needs the capability concurrently reassemble multiple - incoming streams. + incoming streams. The design was extended to support multiple + reassembly buffers but have not yet been verified on this platform. nsh: diff --git a/configs/nucleo-l432kc/include/nucleo-l432kc.h b/configs/nucleo-l432kc/include/nucleo-l432kc.h index bc2052a2ce..36d22c39ec 100644 --- a/configs/nucleo-l432kc/include/nucleo-l432kc.h +++ b/configs/nucleo-l432kc/include/nucleo-l432kc.h @@ -203,7 +203,8 @@ */ /* prescaler common to all PLL inputs; will be 1 (XXX source is implicitly - as per comment above HSI) */ + * as per comment above HSI) + */ #define STM32L4_PLLCFG_PLLM RCC_PLLCFG_PLLM(1) @@ -292,11 +293,12 @@ /* REVISIT : this can be configured */ #define STM32L4_APB2_TIM1_CLKIN (2*STM32L4_PCLK2_FREQUENCY) -#define STM32L4_APB2_TIM8_CLKIN (2*STM32L4_PCLK2_FREQUENCY) +#define STM32L4_APB2_TIM15_CLKIN (2*STM32L4_PCLK2_FREQUENCY) +#define STM32L4_APB2_TIM16_CLKIN (2*STM32L4_PCLK2_FREQUENCY) /* Timer Frequencies, if APBx is set to 1, frequency is same to APBx * otherwise frequency is 2xAPBx. - * Note: TIM1,8 are on APB2, others on APB1 + * Note: TIM1,15,16 are on APB2, others on APB1 */ /* REVISIT : this can be configured */ @@ -379,7 +381,8 @@ #define STM32L4_PCLK2_FREQUENCY (STM32L4_HCLK_FREQUENCY/1) #define STM32L4_APB2_TIM1_CLKIN (2*STM32L4_PCLK2_FREQUENCY) -#define STM32L4_APB2_TIM8_CLKIN (2*STM32L4_PCLK2_FREQUENCY) +#define STM32L4_APB2_TIM15_CLKIN (2*STM32L4_PCLK2_FREQUENCY) +#define STM32L4_APB2_TIM16_CLKIN (2*STM32L4_PCLK2_FREQUENCY) #elif defined(MSI_CLOCK_CONFIG) @@ -459,13 +462,14 @@ #define STM32L4_PCLK2_FREQUENCY (STM32L4_HCLK_FREQUENCY/1) #define STM32L4_APB2_TIM1_CLKIN (2*STM32L4_PCLK2_FREQUENCY) -#define STM32L4_APB2_TIM8_CLKIN (2*STM32L4_PCLK2_FREQUENCY) +#define STM32L4_APB2_TIM15_CLKIN (2*STM32L4_PCLK2_FREQUENCY) +#define STM32L4_APB2_TIM16_CLKIN (2*STM32L4_PCLK2_FREQUENCY) #endif /* Timer Frequencies, if APBx is set to 1, frequency is same to APBx * otherwise frequency is 2xAPBx. - * Note: TIM1,8,15,16,17 are on APB2, others on APB1 + * Note: TIM1,15,16 are on APB2, others on APB1 */ #define BOARD_TIM1_FREQUENCY STM32L4_HCLK_FREQUENCY @@ -475,10 +479,8 @@ #define BOARD_TIM5_FREQUENCY (STM32L4_HCLK_FREQUENCY / 2) #define BOARD_TIM6_FREQUENCY (STM32L4_HCLK_FREQUENCY / 2) #define BOARD_TIM7_FREQUENCY (STM32L4_HCLK_FREQUENCY / 2) -#define BOARD_TIM8_FREQUENCY STM32L4_HCLK_FREQUENCY #define BOARD_TIM15_FREQUENCY STM32L4_HCLK_FREQUENCY #define BOARD_TIM16_FREQUENCY STM32L4_HCLK_FREQUENCY -#define BOARD_TIM17_FREQUENCY STM32L4_HCLK_FREQUENCY #define BOARD_LPTIM1_FREQUENCY (STM32L4_HCLK_FREQUENCY / 2) #define BOARD_LPTIM2_FREQUENCY (STM32L4_HCLK_FREQUENCY / 2) diff --git a/configs/nucleo-l452re/include/nucleo-l452re.h b/configs/nucleo-l452re/include/nucleo-l452re.h index 1f63c441e3..87d03e5bbe 100644 --- a/configs/nucleo-l452re/include/nucleo-l452re.h +++ b/configs/nucleo-l452re/include/nucleo-l452re.h @@ -292,11 +292,12 @@ /* REVISIT : this can be configured */ #define STM32L4_APB2_TIM1_CLKIN (2*STM32L4_PCLK2_FREQUENCY) -#define STM32L4_APB2_TIM8_CLKIN (2*STM32L4_PCLK2_FREQUENCY) +#define STM32L4_APB2_TIM15_CLKIN (2*STM32L4_PCLK2_FREQUENCY) +#define STM32L4_APB2_TIM16_CLKIN (2*STM32L4_PCLK2_FREQUENCY) /* Timer Frequencies, if APBx is set to 1, frequency is same to APBx * otherwise frequency is 2xAPBx. - * Note: TIM1,8 are on APB2, others on APB1 + * Note: TIM1,15,16 are on APB2, others on APB1 */ /* REVISIT : this can be configured */ @@ -379,7 +380,8 @@ #define STM32L4_PCLK2_FREQUENCY (STM32L4_HCLK_FREQUENCY/1) #define STM32L4_APB2_TIM1_CLKIN (2*STM32L4_PCLK2_FREQUENCY) -#define STM32L4_APB2_TIM8_CLKIN (2*STM32L4_PCLK2_FREQUENCY) +#define STM32L4_APB2_TIM15_CLKIN (2*STM32L4_PCLK2_FREQUENCY) +#define STM32L4_APB2_TIM16_CLKIN (2*STM32L4_PCLK2_FREQUENCY) #elif defined(MSI_CLOCK_CONFIG) @@ -459,13 +461,14 @@ #define STM32L4_PCLK2_FREQUENCY (STM32L4_HCLK_FREQUENCY/1) #define STM32L4_APB2_TIM1_CLKIN (2*STM32L4_PCLK2_FREQUENCY) -#define STM32L4_APB2_TIM8_CLKIN (2*STM32L4_PCLK2_FREQUENCY) +#define STM32L4_APB2_TIM15_CLKIN (2*STM32L4_PCLK2_FREQUENCY) +#define STM32L4_APB2_TIM16_CLKIN (2*STM32L4_PCLK2_FREQUENCY) #endif /* Timer Frequencies, if APBx is set to 1, frequency is same to APBx * otherwise frequency is 2xAPBx. - * Note: TIM1,8,15,16,17 are on APB2, others on APB1 + * Note: TIM1,15,16 are on APB2, others on APB1 */ #define BOARD_TIM1_FREQUENCY STM32L4_HCLK_FREQUENCY @@ -475,10 +478,8 @@ #define BOARD_TIM5_FREQUENCY (STM32L4_HCLK_FREQUENCY / 2) #define BOARD_TIM6_FREQUENCY (STM32L4_HCLK_FREQUENCY / 2) #define BOARD_TIM7_FREQUENCY (STM32L4_HCLK_FREQUENCY / 2) -#define BOARD_TIM8_FREQUENCY STM32L4_HCLK_FREQUENCY #define BOARD_TIM15_FREQUENCY STM32L4_HCLK_FREQUENCY #define BOARD_TIM16_FREQUENCY STM32L4_HCLK_FREQUENCY -#define BOARD_TIM17_FREQUENCY STM32L4_HCLK_FREQUENCY #define BOARD_LPTIM1_FREQUENCY (STM32L4_HCLK_FREQUENCY / 2) #define BOARD_LPTIM2_FREQUENCY (STM32L4_HCLK_FREQUENCY / 2) diff --git a/configs/nucleo-l452re/src/stm32_bringup.c b/configs/nucleo-l452re/src/stm32_bringup.c index b50fe95827..1280168612 100644 --- a/configs/nucleo-l452re/src/stm32_bringup.c +++ b/configs/nucleo-l452re/src/stm32_bringup.c @@ -49,7 +49,7 @@ #include "nucleo-l452re.h" /**************************************************************************** - * Pre-processor Defintiionis + * Pre-processor Definitions ****************************************************************************/ #undef HAVE_I2C_DRIVER diff --git a/configs/nucleo-l476rg/include/nucleo-l476rg.h b/configs/nucleo-l476rg/include/nucleo-l476rg.h index 67a9f46cae..a43d3395ae 100644 --- a/configs/nucleo-l476rg/include/nucleo-l476rg.h +++ b/configs/nucleo-l476rg/include/nucleo-l476rg.h @@ -293,10 +293,13 @@ #define STM32L4_APB2_TIM1_CLKIN (2*STM32L4_PCLK2_FREQUENCY) #define STM32L4_APB2_TIM8_CLKIN (2*STM32L4_PCLK2_FREQUENCY) +#define STM32L4_APB2_TIM15_CLKIN (2*STM32L4_PCLK2_FREQUENCY) +#define STM32L4_APB2_TIM16_CLKIN (2*STM32L4_PCLK2_FREQUENCY) +#define STM32L4_APB2_TIM17_CLKIN (2*STM32L4_PCLK2_FREQUENCY) /* Timer Frequencies, if APBx is set to 1, frequency is same to APBx * otherwise frequency is 2xAPBx. - * Note: TIM1,8 are on APB2, others on APB1 + * Note: TIM1,8,15,16,17 are on APB2, others on APB1 */ /* REVISIT : this can be configured */ @@ -380,6 +383,9 @@ #define STM32L4_APB2_TIM1_CLKIN (2*STM32L4_PCLK2_FREQUENCY) #define STM32L4_APB2_TIM8_CLKIN (2*STM32L4_PCLK2_FREQUENCY) +#define STM32L4_APB2_TIM15_CLKIN (2*STM32L4_PCLK2_FREQUENCY) +#define STM32L4_APB2_TIM16_CLKIN (2*STM32L4_PCLK2_FREQUENCY) +#define STM32L4_APB2_TIM17_CLKIN (2*STM32L4_PCLK2_FREQUENCY) #elif defined(MSI_CLOCK_CONFIG) @@ -460,6 +466,9 @@ #define STM32L4_APB2_TIM1_CLKIN (2*STM32L4_PCLK2_FREQUENCY) #define STM32L4_APB2_TIM8_CLKIN (2*STM32L4_PCLK2_FREQUENCY) +#define STM32L4_APB2_TIM15_CLKIN (2*STM32L4_PCLK2_FREQUENCY) +#define STM32L4_APB2_TIM16_CLKIN (2*STM32L4_PCLK2_FREQUENCY) +#define STM32L4_APB2_TIM17_CLKIN (2*STM32L4_PCLK2_FREQUENCY) #endif diff --git a/configs/nucleo-l496zg/include/board.h b/configs/nucleo-l496zg/include/board.h index 87f69f92d9..8657c22734 100644 --- a/configs/nucleo-l496zg/include/board.h +++ b/configs/nucleo-l496zg/include/board.h @@ -178,10 +178,13 @@ #define STM32L4_APB2_TIM1_CLKIN (2*STM32L4_PCLK2_FREQUENCY) #define STM32L4_APB2_TIM8_CLKIN (2*STM32L4_PCLK2_FREQUENCY) +#define STM32L4_APB2_TIM15_CLKIN (2*STM32L4_PCLK2_FREQUENCY) +#define STM32L4_APB2_TIM16_CLKIN (2*STM32L4_PCLK2_FREQUENCY) +#define STM32L4_APB2_TIM17_CLKIN (2*STM32L4_PCLK2_FREQUENCY) /* Timer Frequencies, if APBx is set to 1, frequency is same to APBx * otherwise frequency is 2xAPBx. - * Note: TIM1,8 are on APB2, others on APB1 + * Note: TIM1,8,15,16,17 are on APB2, others on APB1 */ /* REVISIT : this can be configured */ @@ -361,9 +364,9 @@ /* DMA channels *************************************************************/ /* ADC */ -#define ADC1_DMA_CHAN DMAMAP_ADC1_1 -#define ADC2_DMA_CHAN DMAMAP_ADC2_1 -#define ADC3_DMA_CHAN DMAMAP_ADC3_1 +#define ADC1_DMA_CHAN DMACHAN_ADC1_1 +#define ADC2_DMA_CHAN DMACHAN_ADC2_1 +#define ADC3_DMA_CHAN DMACHAN_ADC3_1 /* SPI * diff --git a/configs/same70-xplained/README.txt b/configs/same70-xplained/README.txt index 4841cab264..2252fc7b94 100644 --- a/configs/same70-xplained/README.txt +++ b/configs/same70-xplained/README.txt @@ -997,7 +997,7 @@ Tickless OS will have an error of 0.6% and will have inaccuracies that will effect the time due to long term error build-up. - Using the slow clock clock input, the Tickless support is functional, + Using the slow clock input, the Tickless support is functional, however, there are inaccuracies in delays. For example, nsh> sleep 10 @@ -1318,7 +1318,7 @@ Configuration sub-directories mrf24j40-starhub - This configuration implement a hub node in a 6LoWPAN start network. + This configuration implements a hub node in a 6LoWPAN start network. It is intended for the us the mrf24j40-starpoint configuration with the clicker2-stm32 configurations. Essentially, the SAME70 Xplained plays the roll of the hub in the configuration and the clicker2-stm32 @@ -1383,10 +1383,11 @@ Configuration sub-directories No significant functional testing has yet been performed. - 2017-08-24: There is only a single buffer for reassemblying larger - packets. This could be an important issue for the hub configuration + 2017-08-26: There was only a single buffer for reassemblying larger + packets. This could be a problem issue for the hub configuration which really needs the capability concurrently reassemble multiple - incoming streams. + incoming streams. The design was extended to support multiple + reassembly buffers but have not yet been verified on this platform. netnsh: diff --git a/configs/samv71-xult/README.txt b/configs/samv71-xult/README.txt index c58270a001..204271892d 100644 --- a/configs/samv71-xult/README.txt +++ b/configs/samv71-xult/README.txt @@ -1956,10 +1956,11 @@ Configuration sub-directories The SPI signals look clean on the board and the MRF24J40 seems fully functional. - 2017-08-24: There is only a single buffer for reassemblying larger - packets. This could be an important issue for the hub configuration + 2017-08-26: There was only a single buffer for reassemblying larger + packets. This could be a problem issue for the hub configuration which really needs the capability concurrently reassemble multiple - incoming streams. + incoming streams. The design was extended to support multiple + reassembly buffers but additional testing is needed. mxtxplnd: diff --git a/drivers/power/Kconfig b/drivers/power/Kconfig index ca02bd12d2..8d9bb1be89 100644 --- a/drivers/power/Kconfig +++ b/drivers/power/Kconfig @@ -292,6 +292,25 @@ config BQ2425X ---help--- The BQ24250/BQ24251 are battery charger for lithium-ion batteries. +config BQ2429X + bool "BQ2429X Battery charger support" + default n + select I2C + select I2C_BQ2429X + depends on BATTERY_CHARGER + ---help--- + The BQ24296/BQ24297/BQ24296M are battery charger for lithium-ion batteries. + +if BQ2429X + +config DEBUG_BQ2429X + bool "BQ2429X Debug Features" + default n + ---help--- + Enable BQ2429X battery management debug features. + +endif # BQ2429X + config BATTERY_GAUGE bool "Battery Fuel Gauge support" default n @@ -312,6 +331,10 @@ config I2C_BQ2425X bool default y if BQ2425X +config I2C_BQ2429X + bool + default y if BQ2429X + config I2C_MAX1704X bool default y if MAX1704X diff --git a/drivers/power/Make.defs b/drivers/power/Make.defs index d566bdf533..8fb6a638a0 100644 --- a/drivers/power/Make.defs +++ b/drivers/power/Make.defs @@ -80,6 +80,12 @@ ifeq ($(CONFIG_I2C_BQ2425X),y) CSRCS += bq2425x.c endif +# Add the BQ2429x I2C-based battery charger driver + +ifeq ($(CONFIG_I2C_BQ2429X),y) +CSRCS += bq2429x.c +endif + endif # Include power support in the build diff --git a/drivers/power/battery_charger.c b/drivers/power/battery_charger.c index 4b489799f8..811254e190 100644 --- a/drivers/power/battery_charger.c +++ b/drivers/power/battery_charger.c @@ -160,7 +160,7 @@ static int bat_charger_ioctl(FAR struct file *filep, int cmd, FAR struct battery_charger_dev_s *dev = inode->i_private; int ret; - /* Inforce mutually exclusive access to the battery driver */ + /* Enforce mutually exclusive access to the battery driver */ ret = sem_wait(&dev->batsem); if (ret < 0) @@ -168,7 +168,7 @@ static int bat_charger_ioctl(FAR struct file *filep, int cmd, return -errno; /* Probably EINTR */ } - /* Procss the IOCTL command */ + /* Process the IOCTL command */ ret = -EINVAL; /* Assume a bad argument */ switch (cmd) @@ -239,6 +239,16 @@ static int bat_charger_ioctl(FAR struct file *filep, int cmd, } break; + case BATIOC_OPERATE: + { + FAR int *ptr = (FAR int *)((uintptr_t)arg); + if (ptr) + { + ret = dev->ops->operate(dev, (uintptr_t)arg); + } + } + break; + default: _err("ERROR: Unrecognized cmd: %d\n", cmd); ret = -ENOTTY; diff --git a/drivers/power/bq2425x.c b/drivers/power/bq2425x.c index 039baf01a3..7e6e7dbd72 100644 --- a/drivers/power/bq2425x.c +++ b/drivers/power/bq2425x.c @@ -134,6 +134,7 @@ static int bq2425x_online(struct battery_charger_dev_s *dev, bool *status); static int bq2425x_voltage(struct battery_charger_dev_s *dev, int value); static int bq2425x_current(struct battery_charger_dev_s *dev, int value); static int bq2425x_input_current(struct battery_charger_dev_s *dev, int value); +static int bq2425x_operate(struct battery_charger_dev_s *dev, uintptr_t param); /**************************************************************************** * Private Data @@ -146,7 +147,8 @@ static const struct battery_charger_operations_s g_bq2425xops = bq2425x_online, bq2425x_voltage, bq2425x_current, - bq2425x_input_current + bq2425x_input_current, + bq2425x_operate }; /**************************************************************************** @@ -728,6 +730,19 @@ static int bq2425x_input_current(struct battery_charger_dev_s *dev, int value) return OK; } +/**************************************************************************** + * Name: bq2425x_operate + * + * Description: + * Do miscellaneous battery ioctl() + * + ****************************************************************************/ + +static int bq2425x_operate(struct battery_charger_dev_s *dev, uintptr_t param) +{ + return -ENOSYS; +} + /**************************************************************************** * Public Functions ****************************************************************************/ diff --git a/drivers/power/bq2429x.c b/drivers/power/bq2429x.c new file mode 100644 index 0000000000..675a6eccd7 --- /dev/null +++ b/drivers/power/bq2429x.c @@ -0,0 +1,1262 @@ +/**************************************************************************** + * drivers/power/bq2429x.c + * Lower half driver for BQ2429x battery charger + * + * Copyright (C) 2017 Neil Hancock. All rights reserved. + * + * Copyright (C) 2017 Haltian Ltd. All rights reserved. + * Author: Juha Niskanen + * + * Copyright (C) 2016 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. + * + ****************************************************************************/ + +/* The BQ24296M/BQ24296 are Li-Ion Battery management + * with Power-Path Management + * and USB OTG +5V boost. + * + * BQ charger with OTG boost and not DSBGA listed below + * BQ24190/24192 compared as similar + * BQ24259 + * BQ24295 + * BQ24195 Boost2A/PMID Chg4A5 SolarPwr + * BQ24195L Boost1A/PMID Chg2A5 SolarPwr + * BQ24296 + * BQ24296M Achg=0.1-3A, Vout=4.55 to 5.0V Current Limit 1.5A + * BQ24297 + * BQ24298 + * BQ25601 I2C - to 13.5 Vin + * BQ25606 No I2C control + * BQ25890H + * BQ25892 + * BQ25895 + * BQ25896 I2C 14V + */ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +/* This driver requires: + * + * CONFIG_BATTERY_CHARGER - Upper half battery driver support + * CONFIG_I2C - I2C support + * CONFIG_I2C_BQ2429X - And the driver must be explictly selected. + */ + +#if defined(CONFIG_BATTERY_CHARGER) && defined(CONFIG_I2C) && \ + defined(CONFIG_I2C_BQ2429X) + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* Debug ********************************************************************/ + +#ifdef CONFIG_DEBUG_BQ2429X +# define baterr _err +# define batdbg _info +# define batinfo _info +#else +# ifdef CONFIG_CPP_HAVE_VARARGS +# define baterr(x...) +# define batdbg(x...) +# define batinfo(x...) +# else +# define baterr (void) +# define batdbg (void) +# define batinfo(void) +# endif +#endif + +/**************************************************************************** + * Private + ****************************************************************************/ + +struct bq2429x_dev_s +{ + /* The common part of the battery driver visible to the upper-half driver */ + + FAR const struct battery_charger_operations_s *ops; /* Battery operations */ + sem_t batsem; /* Enforce mutually exclusive access */ + + /* Data fields specific to the lower half BQ2429X driver follow */ + + FAR struct i2c_master_s *i2c; /* I2C interface */ + uint8_t addr; /* I2C address */ + uint32_t frequency; /* I2C frequency */ +}; + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ +/* I2C support */ + +static int bq2429x_getreg8(FAR struct bq2429x_dev_s *priv, uint8_t regaddr, + FAR uint8_t *val, int num); +static int bq2429x_putreg8(FAR struct bq2429x_dev_s *priv, uint8_t regaddr, + uint8_t regval); + +static int bq2429x_reset(FAR struct bq2429x_dev_s *priv); +static int bq2429x_watchdog(FAR struct bq2429x_dev_s *priv, bool enable); +static int bq2429x_sysoff(FAR struct bq2429x_dev_s *priv); +static int bq2429x_en_term(FAR struct bq2429x_dev_s *priv, bool state); +static int bq2429x_en_hiz(FAR struct bq2429x_dev_s *priv, bool state); +static int bq2429x_en_stat(FAR struct bq2429x_dev_s *priv, bool state); +static int bq2429x_setboost_otg_config(FAR struct bq2429x_dev_s *priv, + bool state); +static int bq2429x_powersupply(FAR struct bq2429x_dev_s *priv, int current); +static inline int bq2429x_setvolt(FAR struct bq2429x_dev_s *priv, + int volts); +static inline int bq2429x_setcurr(FAR struct bq2429x_dev_s *priv, + int req_current); + +/* Battery driver lower half methods */ + +static int bq2429x_state(FAR struct battery_charger_dev_s *dev, + FAR int *status); +static int bq2429x_health(FAR struct battery_charger_dev_s *dev, + FAR int *health); +static int bq2429x_online(FAR struct battery_charger_dev_s *dev, + FAR bool *status); +static int bq2429x_voltage(FAR struct battery_charger_dev_s *dev, + int value); +static int bq2429x_current(FAR struct battery_charger_dev_s *dev, + int value); +static int bq2429x_input_current(FAR struct battery_charger_dev_s *dev, + int value); +static int bq2429x_operate(FAR struct battery_charger_dev_s *dev, + uintptr_t param); + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +static const struct battery_charger_operations_s g_bq2429xops = +{ + bq2429x_state, + bq2429x_health, + bq2429x_online, + bq2429x_voltage, + bq2429x_current, + bq2429x_input_current, + bq2429x_operate, +}; + +#ifdef CONFIG_DEBUG_BQ2429X +static int bq2429x_dump_regs(FAR struct bq2429x_dev_s *priv); +# define bq2429x_dump_regs(priv) bq2429x_dump_regs(priv) +#else +# define bq2429x_dump_regs(priv) +#endif + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: bq2429x_getreg8 + * + * Description: + * Read a 8-bit value from a BQ2429x register pair. + * + * START ACK ACK + * REPEATED-START ACK Data0 ACK Data1 NO-ACK STOP + * + ****************************************************************************/ + +static int bq2429x_getreg8(FAR struct bq2429x_dev_s *priv, uint8_t regaddr, + FAR uint8_t *regval, int num_char) +{ + struct i2c_config_s config; + int ret; + + /* Set up the I2C configuration */ + + config.frequency = priv->frequency; + config.address = priv->addr; + config.addrlen = 7; + + /* Write the register address */ + + ret = i2c_write(priv->i2c, &config, ®addr, 1); + if (ret < 0) + { + baterr("ERROR: i2c_write failed: %d\n", ret); + return ret; + } + + /* Restart and read 8-bit values from the register */ + + ret = i2c_read(priv->i2c, &config, regval, num_char); + if (ret < 0) + { + baterr("ERROR: i2c_read failed: %d\n", ret); + return ret; + } + + return OK; +} + +/**************************************************************************** + * Name: bq2429x_putreg8 + * + * Description: + * Write a 8-bit value to a BQ2429x register pair. + * + * START ACK ACK Data0 ACK Data1 ACK STOP + * + ****************************************************************************/ + +static int bq2429x_putreg8(FAR struct bq2429x_dev_s *priv, uint8_t regaddr, + uint8_t regval) +{ + struct i2c_config_s config; + uint8_t buffer[2]; + + /* Set up the I2C configuration */ + + config.frequency = priv->frequency; + config.address = priv->addr; + config.addrlen = 7; + + batdbg("addr: %02x regval: %08x\n", regaddr, regval); + + /* Set up a message to send */ + + buffer[0] = regaddr; + buffer[1] = regval; + + /* Write the register address followed by the data (no RESTART) */ + + return i2c_write(priv->i2c, &config, buffer, 2); +} + +#ifdef CONFIG_DEBUG_BQ2429X +static int (bq2429x_dump_regs) (FAR struct bq2429x_dev_s * priv) +{ + int ret; + uint8_t value = 0; + + ret = bq2429x_getreg8(priv, BQ2429X_REG00, &value, 1); + batdbg("REG#0: 0x%08X\n", value); + ret |= bq2429x_getreg8(priv, BQ2429X_REG01, &value, 1); + batdbg("REG#1: 0x%08X\n", value); + ret |= bq2429x_getreg8(priv, BQ2429X_REG02, &value, 1); + batdbg("REG#2: 0x%08X\n", value); + ret |= bq2429x_getreg8(priv, BQ2429X_REG03, &value, 1); + batdbg("REG#3: 0x%08X\n", value); + ret |= bq2429x_getreg8(priv, BQ2429X_REG04, &value, 1); + batdbg("REG#4: 0x%08X\n", value); + ret |= bq2429x_getreg8(priv, BQ2429X_REG05, &value, 1); + batdbg("REG#5: 0x%08X\n", value); + ret |= bq2429x_getreg8(priv, BQ2429X_REG06, &value, 1); + batdbg("REG#6: 0x%08X\n", value); + ret |= bq2429x_getreg8(priv, BQ2429X_REG07, &value, 1); + batdbg("REG#7: 0x%08X\n", value); + ret |= bq2429x_getreg8(priv, BQ2429X_REG08, &value, 1); + batdbg("REG#8: 0x%08X\n", value); + + /* Not reading fault register. */ + + ret |= bq2429x_getreg8(priv, BQ2429X_REG0A, &value, 1); + batdbg("REG#10: 0x%08X\n", value); + + return ret; +} +#endif + +/**************************************************************************** + * Name: bq2429x_reset + * + * Description: + * Reset the BQ2429x + * + ****************************************************************************/ + +static int bq2429x_reset(FAR struct bq2429x_dev_s *priv) +{ + int ret; + uint8_t regval; + + /* Read current register value */ + + ret = bq2429x_getreg8(priv, BQ2429X_REG01, ®val, 1); + if (ret < 0) + { + baterr("ERROR: Error reading from BQ2429X! Error = %d\n", ret); + return ret; + } + + /* Send reset command */ + + regval |= BQ2429XR1_REG_RESET; + ret = bq2429x_putreg8(priv, BQ2429X_REG01, regval); + if (ret < 0) + { + baterr("ERROR: Error writing to BQ2429X! Error = %d\n", ret); + return ret; + } + + /* Wait a little bit to clear registers */ + + usleep(500); + +#if 0 + /* There is a BUG in BQ2429X the RESET bit is always read as 1 */ + + regval &= ~(BQ2429X_RESET); + ret = bq2429x_putreg8(priv, BQ2429X_REG01, regval); + if (ret < 0) + { + baterr("ERROR: Error writing to BQ2429X! Error = %d\n", ret); + return ret; + } +#endif + + return OK; +} + +/**************************************************************************** + * Name: bq2429x_watchdog + * + * Description: + * Enable/Disable the BQ2429x watchdog + * + ****************************************************************************/ + +static int bq2429x_watchdog(FAR struct bq2429x_dev_s *priv, bool enable) +{ + int ret; + uint8_t regval; + + ret = bq2429x_getreg8(priv, BQ2429X_REG05, ®val, 1); + if (ret < 0) + { + baterr("ERROR: Error reading from BQ2429X! Error = %d\n", ret); + return ret; + } + + if (enable) + { + /* Hw Default is 40Sec so use that for time being */ + + regval &= ~(BQ2429XR5_WATCHDOG_MASK); + regval |= BQ2429XR5_WATCHDOG_040Sec; + } + else + { + /* 0 is disable */ + + regval &= ~(BQ2429XR5_WATCHDOG_MASK); + } + + ret = bq2429x_putreg8(priv, BQ2429X_REG05, regval); + if (ret < 0) + { + baterr("ERROR: Error writing to BQ2429X! Error = %d\n", ret); + return ret; + } + + return OK; +} + +/**************************************************************************** + * Name: bq2429x_sysoff + * + * Description: + * Turn the internal battery FET off in order to reduce the leakage from + * the BAT pin. Note that this disconnects the battery from the system. + * + ****************************************************************************/ + +static int bq2429x_sysoff(FAR struct bq2429x_dev_s *priv) +{ + int ret; + uint8_t value = 0; + + ret = bq2429x_getreg8(priv, BQ2429X_REG07, &value, 1); + batdbg("REG7 read value: 0x%08X\n", value); + value |= BQ2429XR7_BATFET_DISABLE; + ret |= bq2429x_putreg8(priv, BQ2429X_REG07, value); + + return ret; +} + +/**************************************************************************** + * Name: bq2429x_en_term + * + * Description: + * Enable charger termination. When termination is disabled, there are no + * indications of the charger terminating (i.e. STAT pin or STAT registers). + * + ****************************************************************************/ + +static int bq2429x_en_term(FAR struct bq2429x_dev_s *priv, bool state) +{ + uint8_t regval; + int ret; + + ret = bq2429x_getreg8(priv, BQ2429X_REG05, ®val, 1); + if (ret < 0) + { + baterr("ERROR: Error reading from BQ2429X REG5! Error = %d\n", ret); + return ret; + } + + batdbg("en_term: REG05 %02X EN_TERM=%d\n", + regval, !!(regval & BQ2429XR5_EN_TERM)); + + /* Clear previous and set new value */ + + if (state) + { + regval |= BQ2429XR5_EN_TERM; + } + else + { + regval &= ~BQ2429XR5_EN_TERM; + } + + ret = bq2429x_putreg8(priv, BQ2429X_REG05, regval); + if (ret < 0) + { + baterr("ERROR: Error writing to BQ2429XR5! Error = %d\n", ret); + return ret; + } + + return OK; +} + +/**************************************************************************** + * Name: bq2429x_en_hiz + * + * Description: + * Enable high-impedance mode. Sets the charger IC into low power standby mode. + * + ****************************************************************************/ + +static int bq2429x_en_hiz(FAR struct bq2429x_dev_s *priv, bool state) +{ + uint8_t regval; + int ret; + + ret = bq2429x_getreg8(priv, BQ2429X_REG00, ®val, 1); + if (ret < 0) + { + baterr("ERROR: Error reading from BQ2429X REG0! Error = %d\n", ret); + return ret; + } + + batdbg("en_hiz: REG00 %02X EN_HIZ=%d\n", + regval, !!(regval & BQ2429XR1_EN_HIZ)); + + /* Clear previous and set new value */ + + if (state) + { + regval |= BQ2429XR1_EN_HIZ; + } + else + { + regval &= ~BQ2429XR1_EN_HIZ; + } + + ret = bq2429x_putreg8(priv, BQ2429X_REG00, regval); + if (ret < 0) + { + baterr("ERROR: Error writing to BQ2429XR0! Error = %d\n", ret); + return ret; + } + + return OK; +} + +/**************************************************************************** + * Name: bq2429x_en_stat + * + * Description: + * Enable interrupts. + * + ****************************************************************************/ + +static int bq2429x_en_stat(FAR struct bq2429x_dev_s *priv, bool state) +{ + uint8_t regval; + int ret; + + ret = bq2429x_getreg8(priv, BQ2429X_REG07, ®val, 1); + if (ret < 0) + { + baterr("ERROR: Error reading from BQ2429X REG7! Error = %d\n", ret); + return ret; + } + + batdbg("int stat: REG07 %02X INT_MASK1=%d INT_MASK0=%d\n", regval, + !!(regval & BQ2429XR7_INT_MASK1), !!(regval & BQ2429XR7_INT_MASK0)); + + /* We always set or clear both interrupts together. */ + + if (state) + { + regval |= (BQ2429XR7_INT_MASK0 | BQ2429XR7_INT_MASK1); + } + else + { + regval &= ~(BQ2429XR7_INT_MASK0 | BQ2429XR7_INT_MASK1); + } + + ret = bq2429x_putreg8(priv, BQ2429X_REG07, regval); + if (ret < 0) + { + baterr("ERROR: Error writing to BQ2429XR7! Error = %d\n", ret); + return ret; + } + + return OK; +} + +/**************************************************************************** + * Name: bq2429x_setboost_otg_config + * + * Description: + * Set the device boost mode. + * + ****************************************************************************/ + +static int bq2429x_setboost_otg_config(FAR struct bq2429x_dev_s *priv, + bool state) +{ + uint8_t regval; + int ret; + + ret = bq2429x_getreg8(priv, BQ2429X_REG01, ®val, 1); + if (ret < 0) + { + baterr("ERROR: Error reading from BQ2429X! Error = %d\n", ret); + return ret; + } + + /* Clear previous current and set new value */ + + if (state) + { + /* Set to Boost disable Charge */ + + regval = BQ2429XR1_OTG_CONFIG | (regval & ~BQ2429XR1_CHG_CONFIG); + } + else + { + /* Set to Charge disable Boost */ + + regval = BQ2429XR1_CHG_CONFIG | (regval & ~BQ2429XR1_OTG_CONFIG); + } + + ret = bq2429x_putreg8(priv, BQ2429X_REG01, regval); + if (ret < 0) + { + baterr("ERROR: Error writing to BQ2429X! Error = %d\n", ret); + return ret; + } + +#define BST_CONFIG_MASK (BQ2429XR1_CHG_CONFIG | BQ2429XR1_OTG_CONFIG) + batdbg("otg_config: REG01 %02X Boost=%d\n", regval, + ((BQ2429XR1_OTG_CONFIG == (regval & BST_CONFIG_MASK)) ? 1 : 0)); + + return OK; +} + +/**************************************************************************** + * Name: bq2429x_state + * + * Description: + * Return the current battery management state + * + ****************************************************************************/ + +static int bq2429x_state(FAR struct battery_charger_dev_s *dev, + FAR int *status) +{ + FAR struct bq2429x_dev_s *priv = (FAR struct bq2429x_dev_s *)dev; + uint8_t regval; + bool isfault = false; + int ret; + + ret = bq2429x_getreg8(priv, BQ2429X_REG08, ®val, 1); + if (ret < 0) + { + *status = BATTERY_UNKNOWN; + return ret; + } + + if (regval & BQ2429XR8_DPM_STAT) + { + isfault = true; + batinfo("DPM detected!\n"); + } + + if (!(regval & BQ2429XR8_PG_STAT)) + { + isfault = true; + batinfo("Power is not good!\n"); + } + + if (regval & BQ2429XR8_THERM_STAT) + { + isfault = true; + batinfo("Thermal regulation!\n"); + } + + if (regval & BQ2429XR8_VSYS_STAT) + { + isfault = true; + batinfo("VSYSMIN regulation! Battery is too low!\n"); + } + + regval &= BQ2429XR8_CHRG_STAT_MASK; + + /* TODO: should we check REG09 faults here as well? */ + + if (isfault) + { + *status = BATTERY_FAULT; + } + + /* Is the charging done? */ + + else if (regval == BQ2429XR8_CHRG_STAT_DONE) + { + *status = BATTERY_FULL; + } + + /* Is the charging in progress? */ + + else if (regval == BQ2429XR8_CHRG_STAT_PRECHG || + regval == BQ2429XR8_CHRG_STAT_FASTCHG) + { + *status = BATTERY_CHARGING; + } + + /* Is the charging ready? */ + + else if (regval == BQ2429XR8_CHRG_STAT_NONE) + { + *status = BATTERY_IDLE; + } + + return OK; +} + +/**************************************************************************** + * Name: bq2429x_health + * + * Description: + * Return the current battery health state + * + * Note: if more than one fault happened the user needs to call this ioctl + * again to read a new fault, repeat until receive a BATTERY_HEALTH_GOOD. + * + ****************************************************************************/ + +static int bq2429x_health(FAR struct battery_charger_dev_s *dev, + FAR int *health) +{ + FAR struct bq2429x_dev_s *priv = (FAR struct bq2429x_dev_s *)dev; + uint8_t regval; + int ret; + + ret = bq2429x_getreg8(priv, BQ2429X_REG09, ®val, 1); + if (ret < 0) + { + *health = BATTERY_HEALTH_UNKNOWN; + return ret; + } + + switch (regval & BQ2429XR9_CHRG_FAULT_MASK) + { + case BQ2429XR9_CHRG_FAULT_TIMER: + *health = BATTERY_HEALTH_SAFE_TMR_EXP; + batinfo("battery safety timer expiration!\n"); + return OK; + + case BQ2429XR9_CHRG_FAULT_INPUT: + *health = BATTERY_HEALTH_DISCONNECTED; + batinfo("input disconnect/fault!\n"); + return OK; + + case BQ2429XR9_CHRG_FAULT_THERMAL: + *health = BATTERY_HEALTH_OVERHEAT; + batinfo("thermal shutdown!\n"); + return OK; + + case BQ2429XR9_CHRG_FAULT_NORMAL: + *health = BATTERY_HEALTH_GOOD; + break; /* No return, check for other faults */ + + default: + DEBUGASSERT(false); + *health = BATTERY_HEALTH_UNKNOWN; + return OK; + } + + if (regval & BQ2429XR9_BAT_FAULT) + { + *health = BATTERY_HEALTH_OVERVOLTAGE; + batinfo("battery OVP!\n"); + } + else if (regval & BQ2429XR9_NTC_FAULT2_HOT) + { + *health = BATTERY_HEALTH_OVERHEAT; + batinfo("NTC hot!\n"); + } + else if (regval & BQ2429XR9_NTC_FAULT1_COLD) + { + *health = BATTERY_HEALTH_COLD; + batinfo("NTC cold!\n"); + } + else if (regval & BQ2429XR9_WATCHDOG_FAULT) + { + *health = BATTERY_HEALTH_WD_TMR_EXP; + batinfo("watchdog expiration!\n"); + } + else if (regval & BQ2429XR9_OTG_FAULT) + { + *health = BATTERY_HEALTH_UNSPEC_FAIL; + batinfo("VBUS overload or OVP!\n"); + } + + return OK; +} + +/**************************************************************************** + * Name: bq2429x_online + * + * Description: + * Return true if the battery is online + * + ****************************************************************************/ + +static int bq2429x_online(FAR struct battery_charger_dev_s *dev, + FAR bool *status) +{ + FAR struct bq2429x_dev_s *priv = (FAR struct bq2429x_dev_s *)dev; + uint8_t regval; + int ret; + + ret = bq2429x_getreg8(priv, BQ2429X_REG00, ®val, 1); + if (ret < 0) + { + *status = false; + return ret; + } + + if (regval & BQ2429XR1_EN_HIZ) + { + /* Device is HIGH IMPEDANCE battery offline */ + + *status = false; + } + else + { + *status = true; + } + + return OK; +} + +/**************************************************************************** + * Name: bq2429x_powersupply + * + * Description: + * Set the Power Supply Current Limit. + * + ****************************************************************************/ + +static int bq2429x_powersupply(FAR struct bq2429x_dev_s *priv, int current) +{ + uint8_t regval, idx; + int ret; + + switch (current) + { + case 100: + idx = BQ2429XR0_INLIM_0100mA; + break; + + case 150: + idx = BQ2429XR0_INLIM_0150mA; + break; + + case 500: + idx = BQ2429XR0_INLIM_0500mA; + break; + + case 900: + idx = BQ2429XR0_INLIM_0900mA; + break; + + case 1000: + idx = BQ2429XR0_INLIM_1000mA; + break; + + case 1500: + idx = BQ2429XR0_INLIM_1500mA; + break; + + case 2000: + idx = BQ2429XR0_INLIM_2000mA; + break; + + case 3000: + idx = BQ2429XR0_INLIM_3000mA; + break; + + default: + baterr("ERROR: Current not supported, setting default to 100mA.!\n"); + idx = BQ2429XR0_INLIM_0100mA; + break; + } + + /* Read current register */ + + ret = bq2429x_getreg8(priv, BQ2429X_REG00, ®val, 1); + if (ret < 0) + { + baterr("ERROR: Error reading from BQ2429X! Error = %d\n", ret); + return ret; + } + + /* Clear previous current and set new value */ + + regval &= ~(BQ2429XR0_INLIM_MASK); + regval |= idx; + + ret = bq2429x_putreg8(priv, BQ2429X_REG00, regval); + if (ret < 0) + { + baterr("ERROR: Error writing to BQ2429X! Error = %d\n", ret); + return ret; + } + + return OK; +} + +/**************************************************************************** + * Name: bq2429x_setvolt + * + * Description: + * Set the voltage level to charge the battery. Voltage value in mV. + * + ****************************************************************************/ + +static inline int bq2429x_setvolt(FAR struct bq2429x_dev_s *priv, int req_volts) +{ + uint8_t regval; + int ret, idx; + + /* Verify if voltage is in the acceptable range */ + + if (req_volts < BQ2429X_VOLTCHG_MIN || req_volts > BQ2429X_VOLTCHG_MAX) + { + baterr("ERROR: Voltage %d mV is out of range.\n", req_volts); + return -EINVAL; + } + + ret = bq2429x_getreg8(priv, BQ2429X_REG04, ®val, 1); + if (ret < 0) + { + baterr("ERROR: Error reading from BQ2429X! Error = %d\n", ret); + return ret; + } + + /* Charge Voltage starts at _MIN and increases in steps of 16mV */ + + idx = req_volts - BQ2429X_VOLTCHG_MIN; + idx = idx / 16; + + /* Clear previous voltage */ + + regval &= ~(BQ2429XR4_VREG_MASK); + regval |= (idx << BQ2429XR4_VREG_SHIFT); + + ret = bq2429x_putreg8(priv, BQ2429X_REG04, regval); + if (ret < 0) + { + baterr("ERROR: Error writing to BQ2429X! Error = %d\n", ret); + return ret; + } + + return OK; +} + +/**************************************************************************** + * Name: bq2429x_setcurr + * + * Description: + * Set the current to charge the battery. Current value in mA. + * + ****************************************************************************/ + +static inline int bq2429x_setcurr(FAR struct bq2429x_dev_s *priv, + int req_current) +{ + uint8_t regval; + int ret, idx; + + /* Verify if voltage is in the acceptable range */ + + if (req_current < BQ2429X_CURRCHG_MIN || req_current > BQ2429X_CURRCHG_MAX) + { + baterr("ERROR: Current %d mA is out of range.\n", req_current); + return -EINVAL; + } + + ret = bq2429x_getreg8(priv, BQ2429X_REG02, ®val, 1); + if (ret < 0) + { + baterr("ERROR: Error reading from BQ2429X! Error = %d\n", ret); + return ret; + } + + /* Current starts at _MIN mV and increases in steps of 64mA */ + + idx = req_current - BQ2429X_CURRCHG_MIN; + idx = idx / 64; + + /* Clear previous current and set new value */ + + regval &= ~(BQ2429XR2_ICHG_MASK); + regval |= (idx << BQ2429XR2_ICHG_SHIFT); + + ret = bq2429x_putreg8(priv, BQ2429X_REG02, regval); + if (ret < 0) + { + baterr("ERROR: Error writing to BQ2429X! Error = %d\n", ret); + return ret; + } + + return OK; +} + +/**************************************************************************** + * Name: bq2429x_voltage + * + * Description: + * Set battery charger voltage + * + ****************************************************************************/ + +static int bq2429x_voltage(FAR struct battery_charger_dev_s *dev, int value) +{ + FAR struct bq2429x_dev_s *priv = (FAR struct bq2429x_dev_s *)dev; + int ret; + + /* Set voltage to battery charger */ + + ret = bq2429x_setvolt(priv, value); + if (ret < 0) + { + baterr("ERROR: Error setting voltage to BQ2429X! Error = %d\n", ret); + return ret; + } + + return OK; +} + +/**************************************************************************** + * Name: bq2429x_current + * + * Description: + * Set the battery charger current rate for charging + ****************************************************************************/ + +static int bq2429x_current(FAR struct battery_charger_dev_s *dev, int value) +{ + FAR struct bq2429x_dev_s *priv = (FAR struct bq2429x_dev_s *)dev; + int ret; + + /* Set current to battery charger */ + + ret = bq2429x_setcurr(priv, value); + if (ret < 0) + { + baterr("ERROR: Error setting current to BQ2429X! Error = %d\n", ret); + return ret; + } + + return OK; +} + +/**************************************************************************** + * Name: bq2429x_input_current + * + * Description: + * Set the power-supply input current limit + * + ****************************************************************************/ + +static int bq2429x_input_current(FAR struct battery_charger_dev_s *dev, + int value) +{ + FAR struct bq2429x_dev_s *priv = (FAR struct bq2429x_dev_s *)dev; + int ret; + + ret = bq2429x_powersupply(priv, value); + if (ret < 0) + { + baterr("ERROR: Failed to set BQ2429x power supply input limit: %d\n", + ret); + return ret; + } + + return OK; +} + +/**************************************************************************** + * Name: bq2429x_operate + * + * Description: + * Do miscellaneous battery ioctl(). + * + * Set the battery charger current rate for charging + * REG00 EN_HIZ + * REG01 BOOST + * REG01 CHARGE + * REG02[1] BCOLD + * REG02[1] FORCE_20PCT + * REG05[1] EN_TERM Charging Termination Enable + * REG05[2] WATCHDOG I2C Watchdog Setting 5-20Hrs default 12Hrs + * REG05[1] EN_TIMER Charging safety timer + * REG05[2] CHG_TIMER Fast Charge Timer Setting + * TREG[2] Thermal Regulation Threshold + * REG07[1] DPDM_EN Force DPDM detection when VBUS poower is present + * REG07[1] TMR2X_EN Safety Timer Slowed during DPM or thermal regulation + * REG07[1] BATFET_Disable Turnon off BATFET (Q4) + * REG07[1] INT_MASK1 - Allow INT on CHRG_FAULT Default: 1 Allow + * REG07[1] INT_MASK0 - Allow INT on BAT_FAULT Default: 1 Allow + * + * _provision + * REG00[3] InputCurrent Limit 100mA 3000mA with PSEL + * REG01[1] BOOST_LIM 1A/1.5A Default:1.5A + * REG02[1] ICHG Fast Charge Current Limit, 512-3008mA Default 2048mA + * REG03[4] IPRECHG Pre-charge current Limit 128-2048mA Default: 128mA + * REG03[3] ITERM Termination Current Limit 128-1024mA Default: 256mA + * + * also System output voltage + * REG00[4] VINDPM 3.88-5.08V Default:4.36V + * REG01[3] Min Sys Voltage Range3.0-3.7V + * REG04[6] Charge Voltage Limit 3504-4400mV Default: 4208mV + * REG04[1] Battery Recharge Threhold 100/300mV Default 100mV + * REG06[4] BOOSTV - Boost Voltage 4550-5510mV Default 4998mV + * REG06[2] BHOT Boost Mode Termperature Monitor + * + ****************************************************************************/ + +static int bq2429x_operate(FAR struct battery_charger_dev_s *dev, + uintptr_t param) +{ + FAR struct bq2429x_dev_s *priv = (FAR struct bq2429x_dev_s *)dev; + struct batio_operate_msg_s *msg = (struct batio_operate_msg_s *)param; + int op, value; + int ret = OK; + + bq2429x_dump_regs(priv); + +#if 0 + static bool wdg_disabled = 0; + + /* Tickle watchdog periodically or disable */ + + if (!wdg_disabled) + { + wdg_disabled = true; + bq2429x_reset(priv); + + ret = bq2429x_watchdog(priv, false); /* Disable */ + if (ret < 0) + { + baterr("ERROR: Failed to disable BQ2429x watchdog: %d\n", ret); + return ret; + } + } +#endif + + op = msg->operate_type; + value = (int)msg->u32; + switch (op) + { + case BATIO_OPRTN_BOOST: + ret = bq2429x_setboost_otg_config(priv, true); + break; + + case BATIO_OPRTN_CHARGE: + ret = bq2429x_setboost_otg_config(priv, false); + break; + + case BATIO_OPRTN_EN_TERM: + ret = bq2429x_en_term(priv, (bool)value); + break; + + case BATIO_OPRTN_HIZ: + ret = bq2429x_en_hiz(priv, (bool)value); + + /* Also need to set to 100mA USB host and if the battery above Vbatgd? */ + + break; + + case BATIO_OPRTN_SYSOFF: + ret = bq2429x_sysoff(priv); + break; + + case BATIO_OPRTN_RESET: + ret = bq2429x_reset(priv); + break; + + case BATIO_OPRTN_WDOG: + ret = bq2429x_watchdog(priv, (bool)value); + break; + + default: + baterr("Unsupported opt: 0x%X\n", op); + ret = -EINVAL; + break; + } + + return ret; +} + +/**************************************************************************** + * Name: bq2429x_initialize + * + * Description: + * Initialize the BQ2429x battery driver and return an instance of the + * lower-half interface that may be used with battery_charger_register(). + * + * This driver requires: + * + * CONFIG_BATTERY_CHARGER - Upper half battery driver support + * CONFIG_I2C - I2C support + * CONFIG_I2C_BQ2429X - And the driver must be explictly selected. + * + * Input Parameters: + * i2c - An instance of the I2C interface to use to communicate with + * the BQ2429x + * addr - The I2C address of the BQ2429x (Better be 0x6B). + * frequency - The I2C frequency + * current - The input current our power-supply can offer to charger + * + * Returned Value: + * A pointer to the initialized lower-half driver instance. A NULL pointer + * is returned on a failure to initialize the BQ2429x lower half. + * + ****************************************************************************/ + +FAR struct battery_charger_dev_s * + bq2429x_initialize(FAR struct i2c_master_s *i2c, uint8_t addr, + uint32_t frequency, int current) +{ + FAR struct bq2429x_dev_s *priv; + int ret; + + /* Initialize the BQ2429x device structure */ + + priv = (FAR struct bq2429x_dev_s *)kmm_zalloc(sizeof(struct bq2429x_dev_s)); + if (priv) + { + /* Initialize the BQ2429x device structure */ + + sem_init(&priv->batsem, 0, 1); + priv->ops = &g_bq2429xops; + priv->i2c = i2c; + priv->addr = addr; + priv->frequency = frequency; + + /* Reset the BQ2429x */ + + ret = bq2429x_reset(priv); + if (ret < 0) + { + baterr("ERROR: Failed to reset the BQ2429x: %d\n", ret); + kmm_free(priv); + return NULL; + } + + /* Disable watchdog otherwise BQ2429x returns to StandAlone mode */ + + ret = bq2429x_watchdog(priv, false); + if (ret < 0) + { + baterr("ERROR: Failed to disable BQ2429x watchdog: %d\n", ret); + kmm_free(priv); + return NULL; + } + + /* Define the current that our power supply can offer to the charger. */ + + ret = bq2429x_powersupply(priv, current); + if (ret < 0) + { + baterr("ERROR: Failed to set BQ2429x power supply input limit: %d\n", ret); + kmm_free(priv); + return NULL; + } + + /* Disable all interrupts. */ + + ret = bq2429x_en_stat(priv, false); + if (ret < 0) + { + baterr("ERROR: Failed to disable BQ2429x interrupts: %d\n", ret); + kmm_free(priv); + return NULL; + } + } + + return (FAR struct battery_charger_dev_s *)priv; +} + +#endif /* CONFIG_BATTERY_CHARGER && CONFIG_I2C && CONFIG_I2C_BQ2429X */ diff --git a/drivers/wireless/spirit/drivers/spirit_netdev.c b/drivers/wireless/spirit/drivers/spirit_netdev.c index d5760b58c9..bd2abf9f1a 100644 --- a/drivers/wireless/spirit/drivers/spirit_netdev.c +++ b/drivers/wireless/spirit/drivers/spirit_netdev.c @@ -127,6 +127,7 @@ #include #include #include +#include #include #include @@ -363,6 +364,12 @@ int spirit_hw_initialize(FAR struct spirit_driver_s *dev, * Private Data ****************************************************************************/ +#ifdef CONFIG_NET_6LOWPAN +/* One single packet buffer */ + +static struct sixlowpan_reassbuf_s g_iobuffer; +#endif + /* Spirit radio initialization */ static const struct radio_init_s g_radio_init = @@ -1043,6 +1050,11 @@ static void spirit_receive_work(FAR void *arg) iob = pktmeta->pm_iob; pktmeta->pm_iob = NULL; + /* Make sure the our single packet buffer is attached */ + + priv->radio.r_dev.d_buf = g_iobuffer.rb_buf; + priv->radio.r_dev.d_len = 0; + /* Send the next frame to the network */ wlinfo("Send frame %p to the network: Offset=%u Length=%u\n", @@ -1137,7 +1149,7 @@ static void spirit_interrupt_work(FAR void *arg) #ifdef CONFIG_SPIRIT_FIFOS irqstatus.IRQ_RX_FIFO_ALMOST_FULL = 0; - /* Discard any RX buffer that might have been allocated */ + /* Discard any packet buffer that might have been allocated */ if (priv->rxbuffer != NULL) { @@ -1281,7 +1293,12 @@ static void spirit_interrupt_work(FAR void *arg) if (priv->state != DRIVER_STATE_RECEIVING) { - DEBUGASSERT(priv->state == DRIVER_STATE_IDLE); + /* As a race condition, the TX state, but overriden by concurrent + * RX activity? This assertion here *does* fire: + * + * DEBUGASSERT(priv->state == DRIVER_STATE_IDLE); + */ + priv->state = DRIVER_STATE_RECEIVING; } @@ -1320,7 +1337,7 @@ static void spirit_interrupt_work(FAR void *arg) irqstatus.IRQ_RX_FIFO_ALMOST_FULL = 0; - /* There should be a RX buffer that was allocated when the data sync + /* There should be a packet buffer that was allocated when the data sync * interrupt was processed. */ @@ -1473,7 +1490,7 @@ static void spirit_interrupt_work(FAR void *arg) wlinfo("RX FIFO almost full\n"); - /* There should be a RX buffer that was allocated when the data sync + /* There should be a packet buffer that was allocated when the data sync * interrupt was processed. */ @@ -1571,7 +1588,7 @@ static void spirit_interrupt_work(FAR void *arg) */ #ifdef CONFIG_SPIRIT_FIFOS - /* Discard any RX buffer that might have been allocated */ + /* Discard any packet buffer that might have been allocated */ if (priv->rxbuffer != NULL) { @@ -1752,6 +1769,12 @@ static void spirit_txpoll_work(FAR void *arg) net_lock(); +#ifdef CONFIG_NET_6LOWPAN + /* Make sure the our single packet buffer is attached */ + + priv->radio.r_dev.d_buf = g_iobuffer.rb_buf; +#endif + /* Do nothing if the network is not yet UP */ if (!priv->ifup) @@ -2752,7 +2775,6 @@ int spirit_netdev_initialize(FAR struct spi_dev_s *spi, FAR struct spirit_driver_s *priv; FAR struct radio_driver_s *radio; FAR struct net_driver_s *dev; - FAR uint8_t *pktbuf; int ret; /* Allocate a driver state structure instance */ @@ -2764,16 +2786,6 @@ int spirit_netdev_initialize(FAR struct spi_dev_s *spi, return -ENOMEM; } - /* Allocate a packet buffer */ - - pktbuf = (uint8_t *)kmm_zalloc(CONFIG_NET_6LOWPAN_MTU + CONFIG_NET_GUARDSIZE); - if (priv == NULL) - { - wlerr("ERROR: Failed to allocate a packet buffer\n"); - ret = -ENOMEM; - goto errout_with_alloc; - } - /* Attach the interface, lower driver, and devops */ priv->lower = lower; @@ -2798,7 +2810,6 @@ int spirit_netdev_initialize(FAR struct spi_dev_s *spi, /* Initialize the common network device fields */ dev = &radio->r_dev; - dev->d_buf = pktbuf; /* Single packet buffer */ dev->d_ifup = spirit_ifup; /* I/F up (new IP address) callback */ dev->d_ifdown = spirit_ifdown; /* I/F down callback */ dev->d_txavail = spirit_txavail; /* New TX data callback */ @@ -2839,7 +2850,7 @@ int spirit_netdev_initialize(FAR struct spi_dev_s *spi, if (ret < 0) { wlerr("ERROR: Failed to attach interrupt: %d\n", ret); - goto errout_with_pktbuf; + goto errout_with_alloc; } /* Enable Radio IRQ */ @@ -2850,11 +2861,6 @@ int spirit_netdev_initialize(FAR struct spi_dev_s *spi, errout_with_attach: (void)lower->attach(lower, NULL, NULL); -errout_with_pktbuf: -#if 0 - kmm_free(pktbuf); -#endif - errout_with_alloc: kmm_free(priv); return ret; diff --git a/fs/Kconfig b/fs/Kconfig index 05ab5daea9..cb9963187c 100644 --- a/fs/Kconfig +++ b/fs/Kconfig @@ -13,6 +13,7 @@ config FS_AUTOMOUNTER bool "Auto-mounter" default n depends on !DISABLE_MOUNTPOINT + select SCHED_LPWORK ---help--- The automounter provides an OS-internal mechanism for automatically mounting and unmounting removable media as the media is inserted and diff --git a/include/nuttx/net/radiodev.h b/include/nuttx/net/radiodev.h index c796cb2d5e..71c43c1adf 100644 --- a/include/nuttx/net/radiodev.h +++ b/include/nuttx/net/radiodev.h @@ -42,8 +42,6 @@ #include -#include -#include #include #if defined(CONFIG_NET_6LOWPAN) || defined(CONFIG_NET_IEEE802154) @@ -76,22 +74,37 @@ struct radiodev_properties_s * The radio network driver does not use the d_buf packet buffer directly. * Rather, it uses a list smaller frame buffers. * - * - The packet fragment data is provided in an IOB in the via the + * - Outgoing frame data is provided in an IOB in the via the * r_req_data() interface method each time that the radio needs to * send more data. The length of the frame is provided in the io_len * field of the IOB. * - * In this case, the d_buf is not used at all and, if fact, may be - * NULL. + * Outgoing frames are generated when the radio network driver calls + * the devif_poll(), devif_timer(), sixlowpan_input(), or + * ieee802154_input() interfaces. In each case, the radio driver must + * provide a working buffer in the d_buf pointer. A special form of + * the packet buffer must be used, struct sixlowpan_reassbuf_s. This + * special for includes appended data for managing reassembly of packets. * * - Received frames are provided by radio network driver to the network * via an IOB parameter in the sixlowpan_input() pr ieee802154_input() * interface. The length of the frame is io_len. * - * - 6LoWPAN frames and will be uncompressed and possibly reassembled in - * the d_buf; d_len will hold the size of the reassembled packet. + * Again, the radio network driver must provide an instance of struct + * sixlowpan_reassbuf_s as the packet buffer in the d_buf field. This + * driver-provided data will only be used if the the receive frames are + * not fragmented. * - * In this case, a d_buf of size CONFIG_NET_6LOWPAN_MTU must be provided. + * - Received 6LoWPAN frames and will be uncompressed and possibly + * reassembled in resassembled the d_buf; d_len will hold the size of + * the reassembled packet. + * + * For fagemented frames, d_buf provided by radio driver will not be + * used. 6LoWPAN must handle mutliple reassemblies from different + * sources simultaneously. To support this, 6LoWPAN will allocate a + * unique reassembly buffer for each active reassembly, based on the + * reassembly tag and source radio address. These reassembly buffers + * are managed entirely by the 6LoWPAN layer. * * This is accomplished by "inheriting" the standard 'struct net_driver_s' * and appending the frame buffer as well as other metadata needed to @@ -103,8 +116,9 @@ struct radiodev_properties_s * structure. In general, all fields must be set to NULL. In addition: * * 1. On a TX poll, the radio network driver should provide its driver - * structure. During the course of the poll, the networking layer may - * generate outgoing frames. These frames will by provided to the MAC + * structure along is (single) reassemby buffer provided at d_buf. + * During the course of the poll, the networking layer may generate + * outgoing frames. These frames will by provided to the radio network * driver via the req_data() method. * * After sending each frame through the radio, the MAC driver must @@ -117,16 +131,17 @@ struct radiodev_properties_s * payload area of an IOB frame structure. That IOB structure may be * obtained using the iob_alloc() function. * - * For 6LoWPAN, the larger dev.d_buf must have a size of at least the - * advertised MTU of the protocol, CONFIG_NET_6LOWPAN_MTU, plus - * CONFIG_NET_GUARDSIZE. If fragmentation is enabled, then the logical - * packet size may be significantly larger than the size of the frame - * buffer. The dev.d_buf is used for de-compressing each frame and - * reassembling any fragmented packets to create the full input packet - * that is provided to the application. + * For 6LoWPAN, fragmented packets will be reassembled using allocated + * reassembly buffers that are managed by the 6LoWPAN layer. The radio + * driver must still provide its (single) reassembly buffer in d_buf; + * that buffer is still used for the case where the packet is not + * fragmented into many frames. In either case, the packet buffer will + * have a size of advertised MTU of the protocol, CONFIG_NET_6LOWPAN_MTU, + * plus CONFIG_NET_GUARDSIZE and some additional overhead for reassembly + * state data. * - * The MAC driver should then inform the network of the reciptor of a - * frame by calling sixlowpan_input() or ieee802154_input(). That + * The radio network driver should then inform the network of the recipt + * of a frame by calling sixlowpan_input() or ieee802154_input(). That * single frame (or, perhaps, list of frames) should be provided as * second argument of that call. * @@ -167,65 +182,6 @@ struct radio_driver_s uint8_t r_msdu_handle; #endif -#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. - */ - - /* r_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. - * - * This is the sender's copy of the tag. It is incremented after each - * fragmented packet is sent so that it will be unique to that - * sequence fragmentation. Its value is then persistent, the values of - * other fragmentation variables are valid on during a single - * fragmentation sequence (while r_accumlen > 0) - */ - - uint16_t r_dgramtag; - - /* r_reasstag. Each frame in the reassembly has a tag. That tag must - * match the reassembly tag in the fragments being merged. - * - * This is the same tag as r_dgramtag but is saved on the receiving - * side to match all of the fragments of the packet. - */ - - uint16_t r_reasstag; - - /* r_pktlen. The total length of the IPv6 packet to be re-assembled in - * d_buf. Used to determine when the re-assembly is complete. - */ - - uint16_t r_pktlen; - - /* The current accumulated length of the packet being received in d_buf. - * Included IPv6 and protocol headers. Currently used only to determine - * there is a fragmentation sequence in progress. - */ - - uint16_t r_accumlen; - - /* r_boffset. Offset to the beginning of data in d_buf. As each fragment - * is received, data is placed at an appriate offset added to this. - */ - - uint16_t r_boffset; - - /* The source MAC address of the fragments being merged */ - - struct netdev_varaddr_s r_fragsrc; - - /* That time at which reassembly was started. If the elapsed time - * exceeds CONFIG_NET_6LOWPAN_MAXAGE, then the reassembly will - * be cancelled. - */ - - systime_t r_time; -#endif /* CONFIG_NET_6LOWPAN_FRAG */ - /* MAC network driver callback functions **********************************/ /************************************************************************** * Name: r_get_mhrlen diff --git a/include/nuttx/net/sixlowpan.h b/include/nuttx/net/sixlowpan.h index 4eab7cc48a..839e19b1fb 100644 --- a/include/nuttx/net/sixlowpan.h +++ b/include/nuttx/net/sixlowpan.h @@ -53,6 +53,10 @@ #include #include +#include + +#include +#include #ifdef CONFIG_NET_6LOWPAN @@ -337,6 +341,99 @@ (a)[4] == 0 && (a)[5] == 0 && (a)[6] == 0 && \ (((a)[7] & HTONS(0xff00)) == 0x0000)) +/**************************************************************************** + * Public Types + ****************************************************************************/ + +/* Fragmentation Support + * + * This structure defines the reassembly buffer. NOTE: The packet buffer + * is needed even in the case where reassembly is disabled. + */ + +struct sixlowpan_reassbuf_s +{ + /* This is the externally visible packet buffer. This is assigned + * to the driver's d_buf field when the reassembly is complete and + * provides the full reassembly packet to the network. + */ + + uint8_t rb_buf[CONFIG_NET_6LOWPAN_MTU + CONFIG_NET_GUARDSIZE]; + + /* Memory pool used to allocate this reassembly buffer */ + + uint8_t rb_pool; + + /* True if the reassemby buffer is active (set to false when reassembly is + * complete). + */ + + bool rb_active; + + /* Supports a singly linked list */ + + FAR struct sixlowpan_reassbuf_s *rb_flink; + +#if CONFIG_NET_6LOWPAN_FRAG + /* Fragmentation is handled frame by frame and requires that certain + * state information be retained from frame to frame. That additional + * information follows the externally visible packet buffer. + */ + + /* rb_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. + * + * This is the sender's copy of the tag. It is incremented after each + * fragmented packet is sent so that it will be unique to that + * sequence fragmentation. Its value is then persistent, the values of + * other fragmentation variables are valid on during a single + * fragmentation sequence (while rb_accumlen > 0) + */ + + uint16_t rb_dgramtag; + + /* rb_reasstag. Each frame in the reassembly has a tag. That tag must + * match the reassembly tag in the fragments being merged. + * + * This is the same tag as rb_dgramtag but is saved on the receiving + * side to match all of the fragments of the packet. + */ + + uint16_t rb_reasstag; + + /* rb_pktlen. The total length of the IPv6 packet to be re-assembled in + * d_buf. Used to determine when the re-assembly is complete. + */ + + uint16_t rb_pktlen; + + /* The current accumulated length of the packet being received in d_buf. + * Included IPv6 and protocol headers. Currently used only to determine + * there is a fragmentation sequence in progress. + */ + + uint16_t rb_accumlen; + + /* rb_boffset. Offset to the beginning of data in d_buf. As each fragment + * is received, data is placed at an appriate offset added to this. + */ + + uint16_t rb_boffset; + + /* The source MAC address of the fragments being merged */ + + struct netdev_varaddr_s rb_fragsrc; + + /* That time at which reassembly was started. If the elapsed time + * exceeds CONFIG_NET_6LOWPAN_MAXAGE, then the reassembly will + * be cancelled. + */ + + systime_t rb_time; +#endif /* CONFIG_NET_6LOWPAN_FRAG */ +}; + /**************************************************************************** * Public Function Prototypes ****************************************************************************/ diff --git a/include/nuttx/power/battery_charger.h b/include/nuttx/power/battery_charger.h index 932e3ae37e..997e0fa5c3 100644 --- a/include/nuttx/power/battery_charger.h +++ b/include/nuttx/power/battery_charger.h @@ -60,6 +60,7 @@ * * CONFIG_I2C - I2C support *may* be needed * CONFIG_I2C_BQ2425X - The BQ2425x driver must be explicitly selected. + * CONFIG_I2C_BQ2429X - The BQ2429x driver must be explicitly selected. */ /* IOCTL Commands ***********************************************************/ @@ -84,6 +85,8 @@ * Input value: An int defining the current value. * BATIOC_INPUT_CURRENT - Define the input current limit of power supply. * Input value: An int defining the input current limit value. + * BATIOC_OPERATE - Perform miscellaneous, device-specific charger operation. + * Input value: An uintptr_t that can hold a pointer to struct batio_operate_msg_s. */ /* Special input values for BATIOC_INPUT_CURRENT that may optionally @@ -151,6 +154,10 @@ struct battery_charger_operations_s /* Set the input current limit of power supply */ int (*input_current)(struct battery_charger_dev_s *dev, int value); + + /* Do device specific operation */ + + int (*operate)(struct battery_charger_dev_s *dev, uintptr_t param); }; /* This structure defines the battery driver state structure */ @@ -207,11 +214,11 @@ int battery_charger_register(FAR const char *devpath, * * Description: * Initialize the BQ2425X battery driver and return an instance of the - * lower_half interface that may be used with battery_charger_register(); + * lower-half interface that may be used with battery_charger_register(). * * This driver requires: * - * CONFIG_BATTERY_CHARGER - Upper half battery fuel gauge driver support + * CONFIG_BATTERY_CHARGER - Upper half battery charger driver support * CONFIG_I2C - I2C support * CONFIG_I2C_BQ2425X - And the driver must be explictly selected. * @@ -237,6 +244,55 @@ FAR struct battery_charger_dev_s *bq2425x_initialize(FAR struct i2c_master_s *i2 int current); #endif +/**************************************************************************** + * Name: bq2429x_initialize + * + * Description: + * Initialize the BQ2429X (BQ24series LiIon Charger with USB OTG boost 5V) + * battery driver and return an instance of the lower-half interface that + * may be used with battery_charger_register(). + * + * This is for: + * BQ24296M VQFN24 + * BQ24296 VQFN24 + * BQ24297 + * BQ24298 + * Possibly similar: + * BQ24262 + * BQ24259 + * BQ24292I BQ24295 B + * Possibly the following: + * BQ24260/1/2 Vin-14V + * BQ24190 Vin=17V + * + * This driver requires: + * + * CONFIG_BATTERY_CHARGER - Upper half battery charger driver support + * CONFIG_I2C - I2C support + * CONFIG_I2C_BQ2429X - And the driver must be explictly selected. + * + * Input Parameters: + * i2c - An instance of the I2C interface to use to communicate with + * the BQ2429X + * addr - The I2C address of the BQ2429X (Better be 0x6B). + * frequency - The I2C frequency + * current - The input current our power-supply can offer to charger + * + * Returned Value: + * A pointer to the initialized battery driver instance. A NULL pointer + * is returned on a failure to initialize the BQ2429X lower half. + * + ****************************************************************************/ + +#if defined(CONFIG_I2C) && defined(CONFIG_I2C_BQ2429X) + +struct i2c_master_s; +FAR struct battery_charger_dev_s *bq2429x_initialize(FAR struct i2c_master_s *i2c, + uint8_t addr, + uint32_t frequency, + int current); +#endif + #undef EXTERN #ifdef __cplusplus } diff --git a/include/nuttx/power/battery_ioctl.h b/include/nuttx/power/battery_ioctl.h index 2137a6ffb2..3256f1c87f 100644 --- a/include/nuttx/power/battery_ioctl.h +++ b/include/nuttx/power/battery_ioctl.h @@ -2,7 +2,7 @@ * include/nuttx/power/battery_ioctl.h * NuttX Battery IOCTLs definition * - * 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 @@ -60,5 +60,35 @@ #define BATIOC_CURRENT _BATIOC(0x0005) #define BATIOC_INPUT_CURRENT _BATIOC(0x0006) #define BATIOC_CAPACITY _BATIOC(0x0007) +#define BATIOC_OPERATE _BATIOC(0x0008) + +/**************************************************************************** + * Public Types + ****************************************************************************/ + +struct batio_operate_msg_s +{ + uint8_t operate_type; /* Really enum batio_operate_e */ + union + { + uint32_t u32; + uint8_t u8[8]; + }; +}; + +#if defined(CONFIG_I2C_BQ2429X) +enum batio_operate_e +{ + BATIO_OPRTN_NOP = 0, + BATIO_OPRTN_BOOST, + BATIO_OPRTN_CHARGE, + BATIO_OPRTN_EN_TERM, + BATIO_OPRTN_HIZ, + BATIO_OPRTN_SYSOFF, + BATIO_OPRTN_RESET, + BATIO_OPRTN_WDOG, + BATIO_OPRTN_END +}; +#endif #endif /* __INCLUDE_NUTTX_POWER_BATTERY_IOCTL_H */ diff --git a/include/nuttx/power/bq2429x.h b/include/nuttx/power/bq2429x.h new file mode 100644 index 0000000000..e858ea9325 --- /dev/null +++ b/include/nuttx/power/bq2429x.h @@ -0,0 +1,244 @@ +/**************************************************************************** + * drivers/power/bq2429x.h + * Lower half driver for BQ2429X battery charger + * + * Copyright (C) 2017 Neil Hancock. All rights reserved. + * + * Copyright (C) 2017 Haltian Ltd. All rights reserved. + * Author: 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. + * + ****************************************************************************/ + +#ifndef __DRIVERS_POWER_BQ2429X_H +#define __DRIVERS_POWER_BQ2429X_H + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* Auxiliary Definitions */ + +#define BQ2429X_VOLTCHG_MIN 3504 +#define BQ2429X_VOLTCHG_MAX 4400 + +#define BQ2429X_CURRCHG_MIN 512 +#define BQ2429X_CURRCHG_MAX 3008 + +/* BQ2429X Register Definitions ********************************************/ +#define BQ2429X_REG00 0x00 +#define BQ2429X_REG01 0x01 +#define BQ2429X_REG02 0x02 +#define BQ2429X_REG03 0x03 +#define BQ2429X_REG04 0x04 +#define BQ2429X_REG05 0x05 +#define BQ2429X_REG06 0x06 +#define BQ2429X_REG07 0x07 +#define BQ2429X_REG08 0x08 +#define BQ2429X_REG09 0x09 +#define BQ2429X_REG0A 0x0a + +/* REG00 Input Source Control Register */ + +/* For enabling Device Shutdown for shipping - EN_HIZ=1 until QON pressed*/ +#define BQ2429XR1_EN_HIZ (1 << 7) /* 0 Disable (default) 1 Enable HighZ on battery, powerdown */ + +/* Dynamic Power Management - Indicated in StatusReg DPM_STAT REG08[3] + VINDPM - Input Voltage threshold (a drop below 5V) that triggers DPM + INLIM - Input current threshold that tiggers DPM */ + +#define BQ2429XR0_VINDPM_SHIFT 3 /* VIN DPM Offset 5V? Range*/ +#define BQ2429XR0_VINDPM_MASK (0xf << BQ2429XR0_VINDPM_SHIFT) +# define BQ2429XR0_VINDPM3_080mV (1 << BQ2429XR0_VINDPM_SHIFT) +# define BQ2429XR0_VINDPM2_160mV (2 << BQ2429XR0_VINDPM_SHIFT) +# define BQ2429XR0_VINDPM1_320mV (4 << BQ2429XR0_VINDPM_SHIFT) +# define BQ2429XR0_VINDPM0_640mV (8 << BQ2429XR0_VINDPM_SHIFT) +#define BQ2429XR0_INLIM_SHIFT 0 /* Input Current Limit - lower of I2C & ILIM */ +#define BQ2429XR0_INLIM_MASK (0x7 << BQ2429XR0_INLIM_SHIFT) +# define BQ2429XR0_INLIM_0100mA (0x0 << BQ2429XR0_INLIM_SHIFT) +# define BQ2429XR0_INLIM_0150mA (0x1 << BQ2429XR0_INLIM_SHIFT) +# define BQ2429XR0_INLIM_0500mA (0x2 << BQ2429XR0_INLIM_SHIFT) +# define BQ2429XR0_INLIM_0900mA (0x3 << BQ2429XR0_INLIM_SHIFT) +# define BQ2429XR0_INLIM_1000mA (0x4 << BQ2429XR0_INLIM_SHIFT) +# define BQ2429XR0_INLIM_1500mA (0x5 << BQ2429XR0_INLIM_SHIFT) +# define BQ2429XR0_INLIM_2000mA (0x6 << BQ2429XR0_INLIM_SHIFT) +# define BQ2429XR0_INLIM_3000mA (0x7 << BQ2429XR0_INLIM_SHIFT) + +/* REG01 Power-On Configuration Register */ + +#define BQ2429XR1_REG_RESET (1 << 7) /* Write 1 to Reset all registers to default values */ +#define BQ2429XR1_DOG_RESET (1 << 6) /* Write 1 for watchdog timer reset */ +#define BQ2429XR1_OTG_CONFIG (1 << 5) /* =0 Disable (default) =1 Enable See description */ +#define BQ2429XR1_CHG_CONFIG (1 << 4) /* =0 Disable =1 Enable (default) See description */ +#define BQ2429XR1_SYS_MINV_SHIFT 1 /* Min Sys Voltage Limit. Offset 3.0V Range 3-3.7V */ +#define BQ2429XR1_SYS_MINV_MASK (7 << BQ2429XR1_SYS_MINV_SHIFT) +#define BQ2429XR1_SYS_MINV0_0_1V (1 << BQ2429XR1_SYS_MINV_SHIFT) +#define BQ2429XR1_SYS_MINV0_0_2V (2 << BQ2429XR1_SYS_MINV_SHIFT) +#define BQ2429XR1_SYS_MINV0_0_4V (4 << BQ2429XR1_SYS_MINV_SHIFT) + +#define BQ2429XR2_BOOST_LIM (1 << 0) /* 0=1A, 1=1.5A (default) Vout Boost Current Limit */ + +/* REG02 Charge Current Control */ + +#define BQ2429XR2_ICHG_SHIFT 2 +#define BQ2429XR2_ICHG_MASK (0x3f << BQ2429XR2_ICHG_SHIFT) + +#define BQ2429XR2_BCOLD (1 << 1) /* Boost Mode temperature threshold config for boost disable 0=76% 1=79% */ +#define BQ2429XR2_FORCE_20PCT (1 << 0) /* Charge Configuration Threshold 0=Fast 1=less */ + +/* REG03 Pre-charge Termination Control Register */ + +#define BQ2429XR3_IPRECHG_SHIFT 4 /* Precharge I Limit. Offset 128mA Range 128-2048 mA */ +#define BQ2429XR3_IPRECHG_MASK (0xf << BQ2429XR3_IPRECHG_SHIFT) +#define BQ2429XR3_IPRECHG_0128mA (0x00 << BQ2429XR3_IPRECHG_SHIFT) +#define BQ2429XR3_IPRECHG_0128mA (0x01 << BQ2429XR3_IPRECHG_SHIFT) +#define BQ2429XR3_IPRECHG_0256mA (0x02 << BQ2429XR3_IPRECHG_SHIFT) +#define BQ2429XR3_IPRECHG_0384mA (0x03 << BQ2429XR3_IPRECHG_SHIFT) +#define BQ2429XR3_IPRECHG_0512mA (0x04 << BQ2429XR3_IPRECHG_SHIFT) +#define BQ2429XR3_IPRECHG_0768mA (0x05 << BQ2429XR3_IPRECHG_SHIFT) +#define BQ2429XR3_IPRECHG_0896mA (0x06 << BQ2429XR3_IPRECHG_SHIFT) +#define BQ2429XR3_IPRECHG_1024mA (0x07 << BQ2429XR3_IPRECHG_SHIFT) +#define BQ2429XR3_IPRECHG_1152mA (0x10 << BQ2429XR3_IPRECHG_SHIFT) +#define BQ2429XR3_IPRECHG_1280mA (0x11 << BQ2429XR3_IPRECHG_SHIFT) +#define BQ2429XR3_IPRECHG_1408mA (0x12 << BQ2429XR3_IPRECHG_SHIFT) +#define BQ2429XR3_IPRECHG_1536mA (0x13 << BQ2429XR3_IPRECHG_SHIFT) +#define BQ2429XR3_IPRECHG_1664mA (0x14 << BQ2429XR3_IPRECHG_SHIFT) +#define BQ2429XR3_IPRECHG_1792mA (0x15 << BQ2429XR3_IPRECHG_SHIFT) +#define BQ2429XR3_IPRECHG_1920mA (0x16 << BQ2429XR3_IPRECHG_SHIFT) +#define BQ2429XR3_IPRECHG_2048mA (0x17 << BQ2429XR3_IPRECHG_SHIFT) + +#define BQ2429XR3_ITERM_SHIFT 0 /* Offset 128mA Range 128-2048 mA (128-1024 mA in BQ24296M )*/ +#define BQ2429XR3_ITERM_MASK (0xf << BQ2429XR3_ITERM_SHIFT) +#define BQ2429XR3_ITERM0_128mA (1 << BQ2429XR3_ITERM_SHIFT) +#define BQ2429XR3_ITERM0_256mA (2 << BQ2429XR3_ITERM_SHIFT) +#define BQ2429XR3_ITERM0_512mA (4 << BQ2429XR3_ITERM_SHIFT) +#define BQ2429XR3_ITERM0_1024mA (8 << BQ2429XR3_ITERM_SHIFT) /* Reserved in BQ24296M */ + +/* REG04 Charge Voltage Control Register */ +#define BQ2429XR4_VREG_SHIFT 2 /* Offset 3.504V Range 3.504-4.400V Default 4.208V */ +#define BQ2429XR4_VREG_MASK (0x3f<< BQ2429XR4_VREG_SHIFT) + +#define BQ2429XR4_BATLOWV (1 << 1) /* 0=2.8V 1=3.0V Pre-charge to fast Charge */ +#define BQ2429XR4_VRECHG (1 << 0) /* 0=100mV 1=300mV */ + +/* REG05 Charge Termination Timer Control Register */ + +#define BQ2429XR5_EN_TERM (1 << 7) /* 0=Disable 1=Enable(default) terminate of charge */ +#define BQ2429XR5_RESERVED6 (1 << 6) +#define BQ2429XR5_WATCHDOG_SHIFT 4 /* Watchdog Timer Settings */ +#define BQ2429XR5_WATCHDOG_MASK (3 << BQ2429XR5_WATCHDOG_SHIFT) +# define BQ2429XR5_WATCHDOG_DIS (0 << BQ2429XR5_WATCHDOG_SHIFT) +# define BQ2429XR5_WATCHDOG_040Sec (1 << BQ2429XR5_WATCHDOG_SHIFT) +# define BQ2429XR5_WATCHDOG_080Sec (2 << BQ2429XR5_WATCHDOG_SHIFT) +# define BQ2429XR5_WATCHDOG_160Sec (3 << BQ2429XR5_WATCHDOG_SHIFT) + +#define BQ2429XR5_EN_TIMER (1 << 3) /* 0=Disable 1=Enable(default) */ +/* Fast Charge Timer Settings */ +#define BQ2429XR5_CHG_TIMER_SHIFT 1 +#define BQ2429XR5_CHG_TIMER_MASK (3 << BQ2429XR5_CHG_TIMER_SHIFT) +# define BQ2429XR5_CHG_TIMER_05hrs (0 << BQ2429XR5_CHG_TIMER_SHIFT) +# define BQ2429XR5_CHG_TIMER_08hrs (1 << BQ2429XR5_CHG_TIMER_SHIFT) +# define BQ2429XR5_CHG_TIMER_12hrs (2 << BQ2429XR5_CHG_TIMER_SHIFT) +# define BQ2429XR5_CHG_TIMER_20hrs (3 << BQ2429XR5_CHG_TIMER_SHIFT) +#define BQ2429XR5_RESERVED0 (1 << 0) + +/* REG06 Boost Voltage/Thermal Regulation Control register */ + +#define BQ2429XR6_BOOSTV_SHIFT 4 /* Offset 4.55V Range 4.55-5.51A Dev 4.998V(0111) */ +#define BQ2429XR6_BOOSTV_MASK (0xf << BQ2429XR6_BOOSTV_SHIFT) +# define BQ2429XR6_BOOSTV_064mV (1 << BQ2429XR6_BOOSTV_SHIFT) +# define BQ2429XR6_BOOSTV_128mV (2 << BQ2429XR6_BOOSTV_SHIFT) +# define BQ2429XR6_BOOSTV_256mV (4 << BQ2429XR6_BOOSTV_SHIFT) +# define BQ2429XR6_BOOSTV_512mV (8 << BQ2429XR6_BOOSTV_SHIFT) +#define BQ2429XR6_BHOT_SHIFT 2 /* Boost Mode temp threshold */ +#define BQ2429XR6_BHOT_MASK (3 << BQ2429XR6_BHOT_SHIFT) +# define BQ2429XR6_BHOT_55C (0 << BQ2429XR6_BHOT_SHIFT) +# define BQ2429XR6_BHOT_60C (1 << BQ2429XR6_BHOT_SHIFT) +# define BQ2429XR6_BHOT_65C (2 << BQ2429XR6_BHOT_SHIFT) +# define BQ2429XR6_BHOT_DISABLE (3 << BQ2429XR6_BHOT_SHIFT) +#define BQ2429XR6_TREG_SHIFT 0 /* Thermal Regulation */ +#define BQ2429XR6_TREG_MASK (3 << BQ2429XR6_TREG_SHIFT) +# define BQ2429XR6_TREG_060C (0 << BQ2429XR6_TREG_SHIFT) +# define BQ2429XR6_TREG_080C (1 << BQ2429XR6_TREG_SHIFT) +# define BQ2429XR6_TREG_100C (2 << BQ2429XR6_TREG_SHIFT) +# define BQ2429XR6_TREG_110C (3 << BQ2429XR6_TREG_SHIFT) + +/* REG07 Misc Operation Control Register */ + +#define BQ2429XR7_DPDM_EN (1 << 7) /* 1=Force Detection when VBUS power is present */ +#define BQ2429XR7_TMR2X_EN (1 << 6) /* 1=Safety Timer slowed by 2X during DPM/Thermal regulation */ +#define BQ2429XR7_BATFET_DISABLE (1 << 5) /* 1=BATFET (Q4) turn off */ +#define BQ2429XR7_RESERVED4 (1 << 4) +#define BQ2429XR7_RESERVED3 (1 << 3) +#define BQ2429XR7_RESERVED2 (1 << 2) +#define BQ2429XR7_INT_MASK1 (1 << 1) /* =1 (default) INT on CHRG_FAULT */ +#define BQ2429XR7_INT_MASK0 (1 << 0) /* =1 (default) INT on BAT_FAULT */ + +/* REG08 Systems Status Register */ + +#define BQ2429XR8_VBUS_STAT_SHIFT 6 /* VBUS Connection Type */ +#define BQ2429XR8_VBUS_STAT_MASK (3 << BQ2429XR8_VBUS_STAT_SHIFT) +# define BQ2429XR8_VBUS_STAT_UNKNOWN (0 << BQ2429XR8_VBUS_STAT_SHIFT) +# define BQ2429XR8_VBUS_STAT_USBH (1 << BQ2429XR8_VBUS_STAT_SHIFT) +# define BQ2429XR8_VBUS_STAT_ADAPTER (2 << BQ2429XR8_VBUS_STAT_SHIFT) +# define BQ2429XR8_VBUS_STAT_OTG (3 << BQ2429XR8_VBUS_STAT_SHIFT) +#define BQ2429XR8_CHRG_STAT_SHIFT 4 /* Charging Status */ +#define BQ2429XR8_CHRG_STAT_MASK (3 << BQ2429XR8_CHRG_STAT_SHIFT) +# define BQ2429XR8_CHRG_STAT_NONE (0 << BQ2429XR8_CHRG_STAT_SHIFT) +# define BQ2429XR8_CHRG_STAT_PRECHG (1 << BQ2429XR8_CHRG_STAT_SHIFT) +# define BQ2429XR8_CHRG_STAT_FASTCHG (2 << BQ2429XR8_CHRG_STAT_SHIFT) +# define BQ2429XR8_CHRG_STAT_DONE (3 << BQ2429XR8_CHRG_STAT_SHIFT) +#define BQ2429XR8_DPM_STAT (1 << 3) /* 0= NotDPM 1=VINDPM or INDPM */ +#define BQ2429XR8_PG_STAT (1 << 2) /* 0= Not 1=Power Good */ +#define BQ2429XR8_THERM_STAT (1 << 1) /* 0= Normal 1=In Thermal Regulation */ +#define BQ2429XR8_VSYS_STAT (1 << 0) /* 0= Not 1=In VSYSMIN regulation BAT < VSYSMIN */ + +/* REG09 New Fault Register */ + +#define BQ2429XR9_WATCHDOG_FAULT (1 << 7) /* 1=Watchdog Timer expired */ +#define BQ2429XR9_OTG_FAULT (1 << 6) /* 1=Bus overloaded in OTG, or VBUS OVP or battery low */ +#define BQ2429XR9_CHRG_FAULT_SHIFT 4 /* Charging Status */ +#define BQ2429XR9_CHRG_FAULT_MASK (3 << BQ2429XR9_CHRG_FAULT_SHIFT) +# define BQ2429XR9_CHRG_FAULT_NORMAL (0 << BQ2429XR9_CHRG_FAULT_SHIFT) +# define BQ2429XR9_CHRG_FAULT_INPUT (1 << BQ2429XR9_CHRG_FAULT_SHIFT) +# define BQ2429XR9_CHRG_FAULT_THERMAL (2 << BQ2429XR9_CHRG_FAULT_SHIFT) +# define BQ2429XR9_CHRG_FAULT_TIMER (3 << BQ2429XR9_CHRG_FAULT_SHIFT) +#define BQ2429XR9_BAT_FAULT (1 << 3) /* 1=Battery OVP */ +#define BQ2429XR9_RESERVED2 (1 << 2) + +#define BQ2429XR9_NTC_FAULT1_COLD (1 << 1) /* Cold temperature */ +#define BQ2429XR9_NTC_FAULT2_HOT (1 << 0) /* Hot temperature */ + +/* REG0A Vendor Part Revision Info */ + +#define BQ24296_VENDOR_ID 0x20 /* BQ24296 */ +#define BQ24296M_VENDOR_ID 0x20 /* BQ24296M */ +#define BQ24297_VENDOR_ID 0x60 /* BQ24297 */ + +#endif /* __DRIVERS_POWER_BQ2429X_H */ diff --git a/net/devif/devif_callback.c b/net/devif/devif_callback.c index c88dda744c..419d836869 100644 --- a/net/devif/devif_callback.c +++ b/net/devif/devif_callback.c @@ -447,7 +447,6 @@ uint16_t devif_conn_event(FAR struct net_driver_s *dev, void *pvconn, * beginning of the list (which will be ignored on this pass) */ - ninfo("Call event=%p with flags=%04x\n", list->event, flags); flags = list->event(dev, pvconn, list->priv, flags); } @@ -511,7 +510,6 @@ uint16_t devif_dev_event(FAR struct net_driver_s *dev, void *pvconn, * beginning of the list (which will be ignored on this pass) */ - ninfo("Call event=%p with flags=%04x\n", cb->event, flags); flags = cb->event(dev, pvconn, cb->priv, flags); } diff --git a/net/devif/devif_send.c b/net/devif/devif_send.c index 43c913a97b..11b32e289d 100644 --- a/net/devif/devif_send.c +++ b/net/devif/devif_send.c @@ -67,7 +67,7 @@ void devif_send(struct net_driver_s *dev, const void *buf, int len) { - DEBUGASSERT(dev && len > 0 && len < NET_DEV_MTU(dev)); + DEBUGASSERT(dev != NULL && len > 0 && len < NET_DEV_MTU(dev)); memcpy(dev->d_appdata, buf, len); dev->d_sndlen = len; diff --git a/net/ieee802154/ieee802154_recvfrom.c b/net/ieee802154/ieee802154_recvfrom.c index 1801781634..fe1e557acb 100644 --- a/net/ieee802154/ieee802154_recvfrom.c +++ b/net/ieee802154/ieee802154_recvfrom.c @@ -51,6 +51,7 @@ #include #include +#include #include #include #include diff --git a/net/ipforward/ipfwd_alloc.c b/net/ipforward/ipfwd_alloc.c index 517321a1b8..0db8f337f3 100644 --- a/net/ipforward/ipfwd_alloc.c +++ b/net/ipforward/ipfwd_alloc.c @@ -64,7 +64,7 @@ #endif #if defined(CONFIG_NET_TCP) -# define L3_MAXHDRLEN TCP_MAX_HDRLEN +# define L3_MAXHDRLEN TCP_HDRLEN /* Could be up to TCP_MAX_HDRLEN */ #elif defined(CONFIG_NET_UDP) # define L3_MAXHDRLEN UDP_HDRLEN #elif defined(CONFIG_NET_ICMPv6) diff --git a/net/sixlowpan/Kconfig b/net/sixlowpan/Kconfig index 0a363597bf..a8b76568d1 100644 --- a/net/sixlowpan/Kconfig +++ b/net/sixlowpan/Kconfig @@ -12,6 +12,40 @@ config NET_6LOWPAN_FRAG CONFIG_NET_6LOWPAN_FRAG specifies if 6lowpan fragmentation should be used or not. Fragmentation is on by default. +config NET_6LOWPAN_NREASSBUF + int "Number of preallocated reassembly buffers" + default 2 + depends on NET_6LOWPAN_FRAG + ---help--- + Large IPv6 packets will be fragmented by 6LoWPAN into multiple + frames and reconstitued into a reassembly buffer on the receiving + side. Each concurrent reassembly requires one buffer. Reassembly + buffers are large: The size of the 6LoWPAN MTU plus some overhead + for the reassembly state. + + Some reassembly buffers may be preallocated; some may be allocated + dynamically from the stack. The former require more static memory + usage; the later require additional CPU cycles to perform the + allocation and may effect deterministic behavior. So this is a + trade-off between resources and performance. If the number of pre- + allocated reassembly buffers are exhausted, the reassembly will + continue with dynamically allocated reassembly buffers. + + This behavior can be changed with CONFIG_NET_6LOWPAN_REASS_STATIC + +config NET_6LOWPAN_REASS_STATIC + bool "Static reassembly buffers" + default n + depends on NET_6LOWPAN_FRAG + ---help--- + By default, reassembly buffers may be allocated dynamically from the + stack when all of the statically allocation reassembly buffers are + in use. This will equire additional CPU cycles to perform the + allocation and may effect deterministic behavior. This option may + be selected to suppress all dynamica allocation of reassembly + buffers. In that case, only static reassembly buffers are available; + when those are exhausted, frames that require reassembly will be lost. + config NET_6LOWPAN_FRAMELEN int "Max Radio Frame Size" default 127 diff --git a/net/sixlowpan/Make.defs b/net/sixlowpan/Make.defs index 25cdc8bdd8..654a4e4bcc 100644 --- a/net/sixlowpan/Make.defs +++ b/net/sixlowpan/Make.defs @@ -68,6 +68,10 @@ ifeq ($(CONFIG_NET_6LOWPAN_COMPRESSION_HC06),y) NET_CSRCS += sixlowpan_hc06.c endif +ifeq ($(CONFIG_NET_6LOWPAN_FRAG),y) +NET_CSRCS += sixlowpan_reassbuf.c +endif + # Include the sixlowpan directory in the build DEPPATH += --dep-path sixlowpan diff --git a/net/sixlowpan/sixlowpan_framelist.c b/net/sixlowpan/sixlowpan_framelist.c index 5df2103d4b..8f79bbd791 100644 --- a/net/sixlowpan/sixlowpan_framelist.c +++ b/net/sixlowpan/sixlowpan_framelist.c @@ -54,6 +54,7 @@ #include #include +#include #include #include #include @@ -384,9 +385,9 @@ int sixlowpan_queue_frames(FAR struct radio_driver_s *radio, FAR uint8_t *fptr; int framer_hdrlen; struct netdev_varaddr_s bcastmac; +#ifdef CONFIG_NET_6LOWPAN_FRAG uint16_t pktlen; uint16_t paysize; -#ifdef CONFIG_NET_6LOWPAN_FRAG uint16_t outlen = 0; #endif uint8_t protosize; @@ -505,12 +506,18 @@ int sixlowpan_queue_frames(FAR struct radio_driver_s *radio, * added at qtail. */ + FAR struct sixlowpan_reassbuf_s *reass; FAR struct iob_s *qhead; FAR struct iob_s *qtail; FAR uint8_t *frame1; FAR uint8_t *fragptr; uint16_t frag1_hdrlen; + /* Recover the reassembly buffer from the driver d_buf. */ + + reass = (FAR struct sixlowpan_reassbuf_s *)radio->r_dev.d_buf; + DEBUGASSERT(reass != NULL); + /* 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 @@ -548,7 +555,7 @@ int sixlowpan_queue_frames(FAR struct radio_driver_s *radio, pktlen = buflen + g_uncomp_hdrlen + protosize; PUTHOST16(fragptr, SIXLOWPAN_FRAG_DISPATCH_SIZE, ((SIXLOWPAN_DISPATCH_FRAG1 << 8) | pktlen)); - PUTHOST16(fragptr, SIXLOWPAN_FRAG_TAG, radio->r_dgramtag); + PUTHOST16(fragptr, SIXLOWPAN_FRAG_TAG, reass->rb_dgramtag); g_frame_hdrlen += SIXLOWPAN_FRAG1_HDR_LEN; @@ -575,7 +582,7 @@ int sixlowpan_queue_frames(FAR struct radio_driver_s *radio, outlen = paysize; ninfo("First fragment: length %d, tag %d\n", - paysize, radio->r_dgramtag); + paysize, reass->rb_dgramtag); sixlowpan_dumpbuffer("Outgoing frame", (FAR const uint8_t *)iob->io_data, iob->io_len); @@ -630,7 +637,7 @@ int sixlowpan_queue_frames(FAR struct radio_driver_s *radio, PUTHOST16(fragptr, SIXLOWPAN_FRAG_DISPATCH_SIZE, ((SIXLOWPAN_DISPATCH_FRAGN << 8) | pktlen)); - PUTHOST16(fragptr, SIXLOWPAN_FRAG_TAG, radio->r_dgramtag); + PUTHOST16(fragptr, SIXLOWPAN_FRAG_TAG, reass->rb_dgramtag); fragptr[SIXLOWPAN_FRAG_OFFSET] = outlen >> 3; fragn_hdrlen += SIXLOWPAN_FRAGN_HDR_LEN; @@ -654,8 +661,8 @@ int sixlowpan_queue_frames(FAR struct radio_driver_s *radio, iob->io_len = paysize + fragn_hdrlen; outlen += paysize; - ninfo("Fragment offset=%d, paysize=%d, r_dgramtag=%d\n", - outlen >> 3, paysize, radio->r_dgramtag); + ninfo("Fragment offset=%d, paysize=%d, rb_dgramtag=%d\n", + outlen >> 3, paysize, reass->rb_dgramtag); sixlowpan_dumpbuffer("Outgoing frame", (FAR const uint8_t *)iob->io_data, iob->io_len); @@ -697,7 +704,7 @@ int sixlowpan_queue_frames(FAR struct radio_driver_s *radio, /* Update the datagram TAG value */ - radio->r_dgramtag++; + reass->rb_dgramtag++; #else nerr("ERROR: Packet too large: %d\n", buflen); nerr(" Cannot to be sent without fragmentation support\n"); diff --git a/net/sixlowpan/sixlowpan_hc06.c b/net/sixlowpan/sixlowpan_hc06.c index 85b41a0ff6..deca07733a 100644 --- a/net/sixlowpan/sixlowpan_hc06.c +++ b/net/sixlowpan/sixlowpan_hc06.c @@ -61,6 +61,7 @@ #include #include +#include #include #include #include diff --git a/net/sixlowpan/sixlowpan_hc1.c b/net/sixlowpan/sixlowpan_hc1.c index 4daa4cabb0..77a13a8712 100644 --- a/net/sixlowpan/sixlowpan_hc1.c +++ b/net/sixlowpan/sixlowpan_hc1.c @@ -53,6 +53,7 @@ #include #include +#include #include #include #include "sixlowpan/sixlowpan_internal.h" diff --git a/net/sixlowpan/sixlowpan_initialize.c b/net/sixlowpan/sixlowpan_initialize.c index 99222fc487..8ad5bb9cd4 100644 --- a/net/sixlowpan/sixlowpan_initialize.c +++ b/net/sixlowpan/sixlowpan_initialize.c @@ -69,6 +69,12 @@ void sixlowpan_initialize(void) { +#ifdef CONFIG_NET_6LOWPAN_FRAG + /* Initialize the reassembly buffer allocator */ + + sixlowpan_reass_initialize(); +#endif + #ifdef CONFIG_NET_6LOWPAN_COMPRESSION_HC06 /* Initialize HC06 data data structures */ diff --git a/net/sixlowpan/sixlowpan_input.c b/net/sixlowpan/sixlowpan_input.c index a5d14ed964..3af9ea86e7 100644 --- a/net/sixlowpan/sixlowpan_input.c +++ b/net/sixlowpan/sixlowpan_input.c @@ -54,10 +54,7 @@ #include #include -#ifdef CONFIG_NET_6LOWPAN_FRAG -# include "nuttx/clock.h" -#endif - +#include "nuttx/mm/iob.h" #include "nuttx/net/netdev.h" #include "nuttx/net/radiodev.h" #include "nuttx/net/ip.h" @@ -82,10 +79,6 @@ #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) - /* This is the size of a buffer large enough to hold the largest uncompressed * HC06 or HC1 headers. */ @@ -132,50 +125,6 @@ static uint8_t g_bitbucket[UNCOMP_MAXHDR]; * Private Functions ****************************************************************************/ -/**************************************************************************** - * Name: sixlowpan_compare_fragsrc - * - * Description: - * Check if the fragment that we just received is from the same source as - * the previosly received fragements. - * - * Input Parameters: - * radio - Radio network device driver state instance - * metadata - Characteristics of the newly received frame - * - * Returned Value: - * true if the sources are the same. - * - ****************************************************************************/ - -static bool sixlowpan_compare_fragsrc(FAR struct radio_driver_s *radio, - FAR const void *metadata) -{ - struct netdev_varaddr_s fragsrc; - int ret; - - /* Extract the source address from the 'metadata' */ - - ret = sixlowpan_extract_srcaddr(radio, metadata, &fragsrc); - if (ret < 0) - { - nerr("ERROR: sixlowpan_extract_srcaddr failed: %d\n", ret); - return false; - } - - /* The addresses cannot match if they are not the same size */ - - if (fragsrc.nv_addrlen == radio->r_fragsrc.nv_addrlen) - { - /* The are the same sizer, return the address comparisson */ - - return (memcmp(fragsrc.nv_addr, radio->r_fragsrc.nv_addr, - fragsrc.nv_addrlen) == 0); - } - - return false; -} - /**************************************************************************** * Name: sixlowpan_compress_ipv6hdr * @@ -311,14 +260,15 @@ static int sixlowpan_frame_process(FAR struct radio_driver_s *radio, 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 */ + int ret; #ifdef CONFIG_NET_6LOWPAN_FRAG + FAR struct sixlowpan_reassbuf_s *reass; + struct netdev_varaddr_s fragsrc; FAR uint8_t *fragptr; /* Pointer to the fragmentation header */ bool isfrag = false; bool isfirstfrag = false; uint16_t fragtag = 0; /* Tag of the fragment */ - systime_t elapsed; /* Elapsed time */ - int ret; #endif /* CONFIG_NET_6LOWPAN_FRAG */ /* Get a pointer to the payload following the IEEE802.15.4 frame header(s). @@ -359,166 +309,119 @@ static int sixlowpan_frame_process(FAR struct radio_driver_s *radio, ninfo("FRAG1: fragsize=%d fragtag=%d fragoffset=%d\n", fragsize, fragtag, fragoffset); + /* Drop any zero length fragments */ + + if (fragsize == 0) + { + nwarn("WARNING: Dropping zero-length 6LoWPAN fragment\n"); + return INPUT_PARTIAL; + } + + /* 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 -ENOSPC; + } + + /* Extract the source address from the 'metadata'. */ + + ret = sixlowpan_extract_srcaddr(radio, metadata, &fragsrc); + if (ret < 0) + { + nerr("ERROR: sixlowpan_extract_srcaddr failed: %d\n", ret); + return ret; + } + + /* Allocate a new reassembly buffer */ + + reass = sixlowpan_reass_allocate(fragtag, &fragsrc); + if (reass == NULL) + { + nerr("ERROR: Failed to allocate a reassembly buffer\n"); + return -ENOMEM; + } + + radio->r_dev.d_buf = reass->rb_buf; + radio->r_dev.d_len = 0; + reass->rb_pktlen = fragsize; + /* Indicate the first fragment of the reassembly */ - isfirstfrag = true; - isfrag = true; + bptr = reass->rb_buf; + isfirstfrag = true; + isfrag = true; } break; case SIXLOWPAN_DISPATCH_FRAGN: { - /* Set offset, tag, size. Offset is in units of 8 bytes. */ + /* Get offset, tag, size. Offset is in units of 8 bytes. */ fragoffset = fragptr[SIXLOWPAN_FRAG_OFFSET]; fragtag = GETUINT16(fragptr, SIXLOWPAN_FRAG_TAG); fragsize = GETUINT16(fragptr, SIXLOWPAN_FRAG_DISPATCH_SIZE) & 0x07ff; g_frame_hdrlen += SIXLOWPAN_FRAGN_HDR_LEN; + /* Extract the source address from the 'metadata'. */ + + ret = sixlowpan_extract_srcaddr(radio, metadata, &fragsrc); + if (ret < 0) + { + nerr("ERROR: sixlowpan_extract_srcaddr failed: %d\n", ret); + return ret; + } + + /* Find the existing reassembly buffer with the same tag and source address */ + + reass = sixlowpan_reass_find(fragtag, &fragsrc); + if (reass == NULL) + { + nerr("ERROR: Failed to find a reassembly buffer for tag=%04x\n", + fragtag); + return -ENOENT; + } + + if (fragsize != reass->rb_pktlen) + { + /* The packet is a fragment but its size does not match. */ + + nwarn("WARNING: Dropping 6LoWPAN packet. Bad fragsize: %u vs &u\n", + fragsize, reass->rb_pktlen); + ret = -EPERM; + goto errout_with_reass; + } + + radio->r_dev.d_buf = reass->rb_buf; + radio->r_dev.d_len = 0; + ninfo("FRAGN: fragsize=%d fragtag=%d fragoffset=%d\n", fragsize, fragtag, fragoffset); - ninfo("FRAGN: r_accumlen=%d paysize=%u fragsize=%u\n", - radio->r_accumlen, iob->io_len - g_frame_hdrlen, fragsize); + ninfo("FRAGN: rb_accumlen=%d paysize=%u fragsize=%u\n", + reass->rb_accumlen, iob->io_len - g_frame_hdrlen, fragsize); /* Indicate that this frame is a another fragment for reassembly */ - isfrag = true; + bptr = g_bitbucket; + isfrag = true; } break; /* Not a fragment */ default: + /* We still need a packet buffer. But in this case, the driver should + * have provided one. + */ + + DEBUGASSERT(radio->r_dev.d_buf != NULL); + reass = (FAR struct sixlowpan_reassbuf_s *)radio->r_dev.d_buf; + bptr = reass->rb_buf; break; } - - /* Check if we are currently reassembling a packet */ - - bptr = radio->r_dev.d_buf; - if (radio->r_accumlen > 0) - { - /* If reassembly timed out, cancel it */ - - elapsed = clock_systimer() - radio->r_time; - if (elapsed > NET_6LOWPAN_TIMEOUT) - { - nwarn("WARNING: Reassembly timed out\n"); - radio->r_pktlen = 0; - radio->r_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"); - radio->r_pktlen = 0; - radio->r_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"); - radio->r_pktlen = 0; - radio->r_accumlen = 0; - } - - /* Verify that this fragment is part of that reassembly sequence */ - - else if (fragsize != radio->r_pktlen || radio->r_reasstag != fragtag || - !sixlowpan_compare_fragsrc(radio, metadata)) - { - /* 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 -EPERM; - } - else - { - /* Looks good. We are currently processing a reassembling sequence - * and we recieved a valid FRAGN fragment. Redirect the header - * uncompression to our bitbucket. - */ - - bptr = g_bitbucket; - } - } - - /* 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 -EPERM; - } - - /* 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 -ENOSPC; - } - - radio->r_pktlen = fragsize; - radio->r_reasstag = fragtag; - radio->r_time = clock_systimer(); - - ninfo("Starting reassembly: r_pktlen %u, r_reasstag %d\n", - radio->r_pktlen, radio->r_reasstag); - - /* Extract the source address from the 'metadata'. NOTE that the size - * of the source address may be different than our local, destination - * address. - */ - - ret = sixlowpan_extract_srcaddr(radio, metadata, &radio->r_fragsrc); - if (ret < 0) - { - nerr("ERROR: sixlowpan_extract_srcaddr failed: %d\n", ret); - return ret; - } - } +#else + bptr = radio->r_dev.d_buf; #endif /* CONFIG_NET_6LOWPAN_FRAG */ /* Process next dispatch and headers */ @@ -553,7 +456,8 @@ static int sixlowpan_frame_process(FAR struct radio_driver_s *radio, /* Unknown or unsupported header */ nwarn("WARNING: Unknown dispatch: %u\n", hc1[SIXLOWPAN_HC1_DISPATCH]); - return -ENOSYS; + ret = -ENOSYS; + goto errout_with_reass; } #ifdef CONFIG_NET_6LOWPAN_FRAG @@ -565,7 +469,7 @@ static int sixlowpan_frame_process(FAR struct radio_driver_s *radio, * begin placing the data payload. */ - radio->r_boffset = g_uncomp_hdrlen; + reass->rb_boffset = g_uncomp_hdrlen; } /* No.. is this a subsequent fragment in the same sequence? */ @@ -576,7 +480,7 @@ static int sixlowpan_frame_process(FAR struct radio_driver_s *radio, * we began placing payload data. */ - g_uncomp_hdrlen = radio->r_boffset; + g_uncomp_hdrlen = reass->rb_boffset; } #endif /* CONFIG_NET_6LOWPAN_FRAG */ @@ -591,7 +495,8 @@ static int sixlowpan_frame_process(FAR struct radio_driver_s *radio, { nwarn("WARNING: Packet dropped due to payload (%u) > packet buffer (%u)\n", paysize, CONFIG_NET_6LOWPAN_MTU); - return -ENOSPC; + ret = -ENOSPC; + goto errout_with_reass; } /* Sanity-check size of incoming packet to avoid buffer overflow */ @@ -602,14 +507,15 @@ static int sixlowpan_frame_process(FAR struct radio_driver_s *radio, nwarn("WARNING: Required buffer size: %u+%u+%u=%u Available=%u\n", g_uncomp_hdrlen, (fragoffset << 3), paysize, reqsize, CONFIG_NET_6LOWPAN_MTU); - return -ENOMEM; + ret = -ENOMEM; + goto errout_with_reass; } memcpy(radio->r_dev.d_buf + g_uncomp_hdrlen + (fragoffset << 3), fptr + g_frame_hdrlen, paysize); #ifdef CONFIG_NET_6LOWPAN_FRAG - /* Update radio->r_accumlen if the frame is a fragment, radio->r_pktlen + /* Update reass->rb_accumlen if the frame is a fragment, reass->rb_pktlen * otherwise. */ @@ -621,36 +527,49 @@ static int sixlowpan_frame_process(FAR struct radio_driver_s *radio, * bytes at the end. We must be liberal in what we accept. */ - radio->r_accumlen = g_uncomp_hdrlen + (fragoffset << 3) + paysize; + reass->rb_accumlen = g_uncomp_hdrlen + (fragoffset << 3) + paysize; } else { - radio->r_pktlen = paysize + g_uncomp_hdrlen; + reass->rb_pktlen = paysize + g_uncomp_hdrlen; } /* If we have a full IP packet in sixlowpan_buf, deliver it to * the IP stack */ - ninfo("r_accumlen=%d r_pktlen=%d paysize=%d\n", - radio->r_accumlen, radio->r_pktlen, paysize); + ninfo("rb_accumlen=%d rb_pktlen=%d paysize=%d\n", + reass->rb_accumlen, reass->rb_pktlen, paysize); - if (radio->r_accumlen == 0 || radio->r_accumlen >= radio->r_pktlen) + if (reass->rb_accumlen == 0 || reass->rb_accumlen >= reass->rb_pktlen) { - ninfo("IP packet ready (length %d)\n", radio->r_pktlen); + ninfo("IP packet ready (length %d)\n", reass->rb_pktlen); - radio->r_dev.d_len = radio->r_pktlen; - radio->r_pktlen = 0; - radio->r_accumlen = 0; + radio->r_dev.d_buf = reass->rb_buf; + radio->r_dev.d_len = reass->rb_pktlen; + reass->rb_active = false; + reass->rb_pktlen = 0; + reass->rb_accumlen = 0; return INPUT_COMPLETE; } + radio->r_dev.d_buf = NULL; + radio->r_dev.d_len = 0; return INPUT_PARTIAL; + +errout_with_reass: + sixlowpan_reass_free(reass); + return ret; + #else /* Deliver the packet to the IP stack */ radio->r_dev.d_len = paysize + g_uncomp_hdrlen; return INPUT_COMPLETE; + +errout_with_reass: + return ret; + #endif /* CONFIG_NET_6LOWPAN_FRAG */ } @@ -670,6 +589,11 @@ static int sixlowpan_frame_process(FAR struct radio_driver_s *radio, static int sixlowpan_dispatch(FAR struct radio_driver_s *radio) { +#ifdef CONFIG_NET_6LOWPAN_FRAG + FAR struct sixlowpan_reassbuf_s *reass; +#endif + int ret; + sixlowpan_dumpbuffer("Incoming packet", (FAR const uint8_t *)IPv6BUF(&radio->r_dev), radio->r_dev.d_len); @@ -691,7 +615,17 @@ static int sixlowpan_dispatch(FAR struct radio_driver_s *radio) * be set to zero. Oddly, ipv6_input() will return OK in this case. */ - return ipv6_input(&radio->r_dev); + ret = ipv6_input(&radio->r_dev); + +#ifdef CONFIG_NET_6LOWPAN_FRAG + /* Free the reassemby buffer */ + + reass = (FAR struct sixlowpan_reassbuf_s *)radio->r_dev.d_buf; + DEBUGASSERT(reass != NULL); + sixlowpan_reass_free(reass); +#endif + + return ret; } /**************************************************************************** diff --git a/net/sixlowpan/sixlowpan_internal.h b/net/sixlowpan/sixlowpan_internal.h index a65666880f..af2442a8f3 100644 --- a/net/sixlowpan/sixlowpan_internal.h +++ b/net/sixlowpan/sixlowpan_internal.h @@ -115,8 +115,13 @@ /* Sucessful return values from header compression logic */ -#define COMPRESS_HDR_INLINE 0 /* L2 header not compressed */ -#define COMPRESS_HDR_ELIDED 1 /* L2 header compressed */ +#define COMPRESS_HDR_INLINE 0 /* L2 header not compressed */ +#define COMPRESS_HDR_ELIDED 1 /* L2 header compressed */ + +/* Memory Pools *************************************************************/ + +#define REASS_POOL_PREALLOCATED 0 +#define REASS_POOL_DYNAMIC 1 /* Debug ********************************************************************/ @@ -657,5 +662,107 @@ int sixlowpan_extract_destaddr(FAR struct radio_driver_s *radio, FAR const void *metadata, FAR struct netdev_varaddr_s *destaddr); +/**************************************************************************** + * Name: sixlowpan_reass_initialize + * + * Description: + * This function initializes the reassembly buffer allocator. This + * function must be called early in the initialization sequence before + * any radios begin operation. + * + * Called only once during network initialization. + * + * Inputs: + * None + * + * Return Value: + * None + * + ****************************************************************************/ + +#ifdef CONFIG_NET_6LOWPAN_FRAG +void sixlowpan_reass_initialize(void); +#endif /* CONFIG_NET_6LOWPAN_FRAG */ + +/**************************************************************************** + * Name: sixlowpan_reass_allocate + * + * Description: + * The sixlowpan_reass_allocate function will get a free reassembly buffer + * structure for use by 6LoWPAN. + * + * This function will first attempt to allocate from the g_free_reass + * list. If that the list is empty, then the reassembly buffer structure + * will be allocated from the dynamic memory pool. + * + * Inputs: + * reasstag - The reassembly tag for subsequent lookup. + * fragsrc - The source address of the fragment. + * + * Return Value: + * A reference to the allocated reass structure. All fields used by the + * reasembly logic have been zeroed. On a failure to allocate, NULL is + * returned. + * + * Assumptions: + * The network is locked. + * + ****************************************************************************/ + +#ifdef CONFIG_NET_6LOWPAN_FRAG +FAR struct sixlowpan_reassbuf_s * + sixlowpan_reass_allocate(uint16_t reasstag, + FAR const struct netdev_varaddr_s *fragsrc); +#endif /* CONFIG_NET_6LOWPAN_FRAG */ + +/**************************************************************************** + * Name: sixlowpan_reass_find + * + * Description: + * Find a previously allocated, active reassembly buffer with the specified + * reassembly tag. + * + * Inputs: + * reasstag - The reassembly tag to match. + * fragsrc - The source address of the fragment. + * + * Return Value: + * A reference to the matching reass structure. + * + * Assumptions: + * The network is locked. + * + ****************************************************************************/ + +#ifdef CONFIG_NET_6LOWPAN_FRAG +FAR struct sixlowpan_reassbuf_s * + sixlowpan_reass_find(uint16_t reasstag, + FAR const struct netdev_varaddr_s *fragsrc); +#endif /* CONFIG_NET_6LOWPAN_FRAG */ + +/**************************************************************************** + * Name: sixlowpan_reass_free + * + * Description: + * The sixlowpan_reass_free function will return a reass structure + * to the free list of messages if it was a pre-allocated reass + * structure. If the reass structure was allocated dynamically it will + * be deallocated. + * + * Inputs: + * reass - reass structure to free + * + * Return Value: + * None + * + * Assumptions: + * The network is locked. + * + ****************************************************************************/ + +#ifdef CONFIG_NET_6LOWPAN_FRAG +void sixlowpan_reass_free(FAR struct sixlowpan_reassbuf_s *reass); +#endif /* CONFIG_NET_6LOWPAN_FRAG */ + #endif /* CONFIG_NET_6LOWPAN */ #endif /* _NET_SIXLOWPAN_SIXLOWPAN_INTERNAL_H */ diff --git a/net/sixlowpan/sixlowpan_reassbuf.c b/net/sixlowpan/sixlowpan_reassbuf.c new file mode 100644 index 0000000000..4760488dd6 --- /dev/null +++ b/net/sixlowpan/sixlowpan_reassbuf.c @@ -0,0 +1,458 @@ +/**************************************************************************** + * net/sixlowpan/sixlowpan_reassbuf.c + * + * Copyright (C) 2017 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "sixlowpan_internal.h" + +#ifdef CONFIG_NET_6LOWPAN_FRAG + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* Re-assembly timeout in clock ticks */ + +#define NET_6LOWPAN_TIMEOUT SEC2TICK(CONFIG_NET_6LOWPAN_MAXAGE) + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/* The g_free_reass is a list of reassembly buffer structures that are available for + * general use. The number of messages in this list is a system configuration + * item. Protected only by the network lock. + */ + +static FAR struct sixlowpan_reassbuf_s *g_free_reass; + +/* This is a list of active, allocated reassemby buffers */ + +static FAR struct sixlowpan_reassbuf_s *g_active_reass; + +/* Pool of pre-allocated reassembly buffer stuctures */ + +static struct sixlowpan_reassbuf_s g_metadata_pool[CONFIG_NET_6LOWPAN_NREASSBUF]; + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: sixlowpan_compare_fragsrc + * + * Description: + * Check if the fragment that we just received is from the same source as + * the previosly received fragements. + * + * Input Parameters: + * radio - Radio network device driver state instance + * fragsrc - The source address of the fragment. + * + * Returned Value: + * true if the sources are the same. + * + ****************************************************************************/ + +static bool sixlowpan_compare_fragsrc(FAR struct sixlowpan_reassbuf_s *reass, + FAR const struct netdev_varaddr_s *fragsrc) +{ + /* The addresses cannot match if they are not the same size */ + + if (fragsrc->nv_addrlen == reass->rb_fragsrc.nv_addrlen) + { + /* The are the same size, return the address comparison */ + + return (memcmp(fragsrc->nv_addr, reass->rb_fragsrc.nv_addr, + fragsrc->nv_addrlen) == 0); + } + + return false; +} + +/**************************************************************************** + * Name: sixlowpan_reass_expire + * + * Description: + * Free all expired or inactive reassembly buffers. + * + * Inputs: + * None + * + * Return Value: + * None + * + * Assumptions: + * The network is locked. + * + ****************************************************************************/ + +static void sixlowpan_reass_expire(void) +{ + FAR struct sixlowpan_reassbuf_s *reass; + FAR struct sixlowpan_reassbuf_s *next; + systime_t elapsed; + + /* If reassembly timed out, cancel it */ + + for (reass = g_active_reass; reass != NULL; reass = next) + { + /* Needed if 'reass' is freed */ + + next = reass->rb_flink; + + /* Free any inactive reassembly buffers. This is done because the life + * the reassembly buffer is not cerain. + */ + + if (!reass->rb_active) + { + sixlowpan_reass_free(reass); + } + else + { + /* Get the elpased time of the reassembly */ + + elapsed = clock_systimer() - reass->rb_time; + + /* If the reassembly has expired, then free the reassembly buffer */ + + if (elapsed > NET_6LOWPAN_TIMEOUT) + { + nwarn("WARNING: Reassembly timed out\n"); + sixlowpan_reass_free(reass); + } + } + } +} + +/**************************************************************************** + * Name: sixlowpan_remove_active + * + * Description: + * Remove a reassembly buffer from the active reassembly buffer list. + * + * Inputs: + * reass - The reassembly buffer to be removed. + * + * Return Value: + * None + * + * Assumptions: + * The network is locked. + * + ****************************************************************************/ + +static void sixlowpan_remove_active(FAR struct sixlowpan_reassbuf_s *reass) +{ + FAR struct sixlowpan_reassbuf_s *curr; + FAR struct sixlowpan_reassbuf_s *prev; + + /* Find the reassembly buffer in the list of active reassembly buffers */ + + for (prev = NULL, curr = g_active_reass; + curr != NULL && curr != reass; + prev = curr, curr = curr->rb_flink) + { + } + + /* Did we find it? */ + + if (curr != NULL) + { + /* Yes.. remove it from the active reassembly buffer list */ + + if (prev == NULL) + { + g_active_reass = reass->rb_flink; + } + else + { + prev->rb_flink = reass->rb_flink; + } + } + + reass->rb_flink = NULL; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: sixlowpan_reass_initialize + * + * Description: + * This function initializes the reassembly buffer allocator. This + * function must be called early in the initialization sequence before + * any radios begin operation. + * + * Called only once during network initialization. + * + * Inputs: + * None + * + * Return Value: + * None + * + ****************************************************************************/ + +void sixlowpan_reass_initialize(void) +{ + FAR struct sixlowpan_reassbuf_s *reass; + int i; + + /* Initialize g_free_reass, the list of reassembly buffer structures that are + * available for allocation. + */ + + g_free_reass = NULL; + for (i = 0, reass = g_metadata_pool; + i < CONFIG_NET_6LOWPAN_NREASSBUF; + i++, reass++) + { + /* Add the next meta data structure from the pool to the list of + * general structures. + */ + + reass->rb_flink = g_free_reass; + g_free_reass = reass; + } +} + +/**************************************************************************** + * Name: sixlowpan_reass_allocate + * + * Description: + * The sixlowpan_reass_allocate function will get a free reassembly buffer + * structure for use by 6LoWPAN. + * + * This function will first attempt to allocate from the g_free_reass + * list. If that the list is empty, then the reassembly buffer structure + * will be allocated from the dynamic memory pool. + * + * Inputs: + * reasstag - The reassembly tag for subsequent lookup. + * fragsrc - The source address of the fragment. + * + * Return Value: + * A reference to the allocated reass structure. All fields used by the + * reasembly logic have been zeroed. On a failure to allocate, NULL is + * returned. + * + * Assumptions: + * The network is locked. + * + ****************************************************************************/ + +FAR struct sixlowpan_reassbuf_s * + sixlowpan_reass_allocate(uint16_t reasstag, + FAR const struct netdev_varaddr_s *fragsrc) +{ + FAR struct sixlowpan_reassbuf_s *reass; + uint8_t pool; + + /* First, removed any expired or inactive reassembly buffers. This might + * free up a pre-allocated buffer for this allocation. + */ + + sixlowpan_reass_expire(); + + /* Now, try the free list first */ + + if (g_free_reass != NULL) + { + reass = g_free_reass; + g_free_reass = reass->rb_flink; + pool = REASS_POOL_PREALLOCATED; + } + else + { +#ifdef CONFIG_NET_6LOWPAN_REASS_STATIC + reass = NULL; +#else + /* If we cannot get a reassembly buffer instance from the free list, then we + * will have to allocate one from the kernal memory pool. + */ + + reass = (FAR struct sixlowpan_reassbuf_s *) + kmm_malloc((sizeof (struct sixlowpan_reassbuf_s))); + pool = REASS_POOL_DYNAMIC; +#endif + } + + /* We have successfully allocated memory from some source? */ + + if (reass != NULL) + { + /* Zero and tag the allocated reassembly buffer structure. */ + + memset(reass, 0, sizeof(struct sixlowpan_reassbuf_s)); + memcpy(&reass->rb_fragsrc, fragsrc, sizeof(struct netdev_varaddr_s)); + reass->rb_pool = pool; + reass->rb_active = true; + reass->rb_reasstag = reasstag; + reass->rb_time = clock_systimer(); + + /* Add the reassembly buffer to the list of active reassembly buffers */ + + reass->rb_flink = g_active_reass; + g_active_reass = reass; + } + + return reass; +} + +/**************************************************************************** + * Name: sixlowpan_reass_find + * + * Description: + * Find a previously allocated, active reassembly buffer with the specified + * reassembly tag. + * + * Inputs: + * reasstag - The reassembly tag to match. + * fragsrc - The source address of the fragment. + * + * Return Value: + * A reference to the matching reass structure. + * + * Assumptions: + * The network is locked. + * + ****************************************************************************/ + +FAR struct sixlowpan_reassbuf_s * + sixlowpan_reass_find(uint16_t reasstag, + FAR const struct netdev_varaddr_s *fragsrc) +{ + FAR struct sixlowpan_reassbuf_s *reass; + + /* First, removed any expired or inactive reassembly buffers (we don't want + * to return old reassembly buffer with the same tag) + */ + + sixlowpan_reass_expire(); + + /* Now search for the matching reassembly buffer in the remainng, active + * reassembly buffers. + */ + + for (reass = g_active_reass; reass != NULL; reass = reass->rb_flink) + { + /* In order to be a match, it must have the same reassembly tag as + * well as source address (different sources might use the same + * reassembly tag). + */ + + if (reass->rb_reasstag == reasstag && + sixlowpan_compare_fragsrc(reass, fragsrc)) + { + return reass; + } + } + + /* Not found */ + + return NULL; +} + +/**************************************************************************** + * Name: sixlowpan_reass_free + * + * Description: + * The sixlowpan_reass_free function will return a reass structure + * to the free list of messages if it was a pre-allocated reass + * structure. If the reass structure was allocated dynamically it will + * be deallocated. + * + * Inputs: + * reass - reass structure to free + * + * Return Value: + * None + * + * Assumptions: + * The network is locked. + * + ****************************************************************************/ + +void sixlowpan_reass_free(FAR struct sixlowpan_reassbuf_s *reass) +{ + /* First, remove the reassembly buffer from the list of active reassembly + * buffers. + */ + + sixlowpan_remove_active(reass); + + /* If this is a pre-allocated reassembly buffer structure, then just put it back + * in the free list. + */ + + if (reass->rb_pool == REASS_POOL_PREALLOCATED) + { + reass->rb_flink = g_free_reass; + g_free_reass = reass; + } + else + { +#ifdef CONFIG_NET_6LOWPAN_REASS_STATIC + DEBUGPANIC(); +#else + DEBUGASSERT(reass->rb_pool == REASS_POOL_DYNAMIC); + + /* Otherwise, deallocate it. */ + + sched_kfree(reass); +#endif + } +} + +#endif /* CONFIG_NET_6LOWPAN_FRAG */ diff --git a/net/tcp/tcp_input.c b/net/tcp/tcp_input.c index aefde83fd2..76fecdfd7e 100644 --- a/net/tcp/tcp_input.c +++ b/net/tcp/tcp_input.c @@ -48,6 +48,7 @@ #include #include +#include #include #include @@ -342,9 +343,12 @@ found: #endif /* We must free this TCP connection structure; this connection - * will never be established. + * will never be established. There should only be one reference + * on this connection when we allocated for the connection. */ + DEBUGASSERT(conn->crefs == 1); + conn->crefs = 0; tcp_free(conn); } else diff --git a/wireless/ieee802154/mac802154_loopback.c b/wireless/ieee802154/mac802154_loopback.c index 0c32c4c683..92223cd44d 100644 --- a/wireless/ieee802154/mac802154_loopback.c +++ b/wireless/ieee802154/mac802154_loopback.c @@ -51,6 +51,7 @@ #include #include +#include #include #include #include @@ -137,7 +138,7 @@ struct lo_driver_s static struct lo_driver_s g_loopback; #ifdef CONFIG_NET_6LOWPAN -static uint8_t g_iobuffer[CONFIG_NET_6LOWPAN_MTU + CONFIG_NET_GUARDSIZE]; +static struct sixlowpan_reassbuf_s g_iobuffer; #endif static uint8_t g_eaddr[IEEE802154_EADDRSIZE] = @@ -388,6 +389,12 @@ static int lo_loopback(FAR struct net_driver_s *dev) #endif #ifdef CONFIG_NET_6LOWPAN { + /* Make sure the our single packet buffer is attached */ + + priv->lo_radio.r_dev.d_buf = g_iobuffer.rb_buf; + + /* Then give the frame to 6LoWPAN */ + ret = sixlowpan_input(&priv->lo_radio, iob, (FAR void *)&ind); } #endif @@ -459,6 +466,15 @@ static void lo_poll_work(FAR void *arg) /* Perform the poll */ net_lock(); + +#ifdef CONFIG_NET_6LOWPAN + /* Make sure the our single packet buffer is attached */ + + priv->lo_radio.r_dev.d_buf = g_iobuffer.rb_buf; +#endif + + /* Then perform the poll */ + (void)devif_timer(&priv->lo_radio.r_dev, lo_loopback); /* Setup the watchdog poll timer again */ @@ -634,6 +650,12 @@ static void lo_txavail_work(FAR void *arg) { /* If so, then poll the network for new XMIT data */ +#ifdef CONFIG_NET_6LOWPAN + /* Make sure the our single packet buffer is attached */ + + priv->lo_radio.r_dev.d_buf = g_iobuffer.rb_buf; +#endif + (void)devif_poll(&priv->lo_radio.r_dev, lo_loopback); } @@ -1063,9 +1085,6 @@ int ieee8021514_loopback(void) #endif #ifdef CONFIG_NETDEV_IOCTL dev->d_ioctl = lo_ioctl; /* Handle network IOCTL commands */ -#endif -#ifdef CONFIG_NET_6LOWPAN - dev->d_buf = g_iobuffer; /* Attach the IO buffer */ #endif dev->d_private = (FAR void *)priv; /* Used to recover private state from dev */ diff --git a/wireless/ieee802154/mac802154_netdev.c b/wireless/ieee802154/mac802154_netdev.c index a47b50e75b..5f112ee05e 100644 --- a/wireless/ieee802154/mac802154_netdev.c +++ b/wireless/ieee802154/mac802154_netdev.c @@ -224,6 +224,14 @@ static int macnet_req_data(FAR struct radio_driver_s *netdev, static int macnet_properties(FAR struct radio_driver_s *netdev, FAR struct radiodev_properties_s *properties); +/**************************************************************************** + * Private Data + ****************************************************************************/ + +#ifdef CONFIG_NET_6LOWPAN +static struct sixlowpan_reassbuf_s g_iobuffer; +#endif + /**************************************************************************** * Private Functions ****************************************************************************/ @@ -470,6 +478,12 @@ static int macnet_rxframe(FAR struct mac802154_maccb_s *maccb, } else { + /* Make sure the our single packet buffer is attached */ + + priv->md_dev.r_dev.d_buf = g_iobuffer.rb_buf; + + /* And give the packet to 6LoWPAN */ + ret = sixlowpan_input(&priv->md_dev, iob, (FAR void *)ind); } } @@ -568,7 +582,13 @@ static void macnet_txpoll_work(FAR void *arg) net_lock(); - /* Perform the poll */ +#ifdef CONFIG_NET_6LOWPAN + /* Make sure the our single packet buffer is attached */ + + priv->md_dev.r_dev.d_buf = g_iobuffer.rb_buf; +#endif + + /* Then perform the poll */ (void)devif_timer(&priv->md_dev.r_dev, macnet_txpoll_callback); @@ -836,9 +856,13 @@ static void macnet_txavail_work(FAR void *arg) if (priv->md_bifup) { - /* Check if there is room in the hardware to hold another outgoing packet. */ +#ifdef CONFIG_NET_6LOWPAN + /* Make sure the our single packet buffer is attached */ - /* If so, then poll the network for new XMIT data */ + priv->md_dev.r_dev.d_buf = g_iobuffer.rb_buf; +#endif + + /* Then poll the network for new XMIT data */ (void)devif_poll(&priv->md_dev.r_dev, macnet_txpoll_callback); } @@ -1206,9 +1230,6 @@ int mac802154netdev_register(MACHANDLE mac) FAR struct radio_driver_s *radio; FAR struct net_driver_s *dev; FAR struct mac802154_maccb_s *maccb; -#ifdef CONFIG_NET_6LOWPAN - FAR uint8_t *pktbuf; -#endif int ret; DEBUGASSERT(mac != NULL); @@ -1224,27 +1245,10 @@ int mac802154netdev_register(MACHANDLE mac) return -ENOMEM; } -#ifdef CONFIG_NET_6LOWPAN - /* Allocate a packet buffer (not used by this driver, but needed by the - * upper networking layer) - */ - - pktbuf = (FAR uint8_t *)kmm_malloc(CONFIG_NET_6LOWPAN_MTU + CONFIG_NET_GUARDSIZE); - if (pktbuf == NULL) - { - nerr("ERROR: Failed to allocate the packet buffer\n"); - kmm_free(priv); - return -ENOMEM; - } -#endif - /* Initialize the driver structure */ radio = &priv->md_dev; dev = &radio->r_dev; -#ifdef CONFIG_NET_6LOWPAN - dev->d_buf = pktbuf; /* Single packet buffer */ -#endif dev->d_ifup = macnet_ifup; /* I/F up (new IP address) callback */ dev->d_ifdown = macnet_ifdown; /* I/F down callback */ dev->d_txavail = macnet_txavail; /* New TX data callback */ @@ -1297,9 +1301,6 @@ int mac802154netdev_register(MACHANDLE mac) /* Free memory and return the error */ -#ifdef CONFIG_NET_6LOWPAN - kmm_free(pktbuf); -#endif kmm_free(priv); return ret; } diff --git a/wireless/pktradio/pktradio_loopback.c b/wireless/pktradio/pktradio_loopback.c index f426f7a86b..8b62a2afb1 100644 --- a/wireless/pktradio/pktradio_loopback.c +++ b/wireless/pktradio/pktradio_loopback.c @@ -51,6 +51,7 @@ #include #include +#include #include #include #include @@ -130,7 +131,9 @@ struct lo_driver_s ****************************************************************************/ static struct lo_driver_s g_loopback; -static uint8_t g_iobuffer[CONFIG_NET_6LOWPAN_MTU + CONFIG_NET_GUARDSIZE]; +#ifdef CONFIG_NET_6LOWPAN +static struct sixlowpan_reassbuf_s g_iobuffer; +#endif static uint8_t g_mac_addr[CONFIG_PKTRADIO_ADDRLEN] = { @@ -346,6 +349,10 @@ static int lo_loopback(FAR struct net_driver_s *dev) priv->lo_tail = NULL; } + /* Make sure the our single packet buffer is attached */ + + priv->lo_radio.r_dev.d_buf = g_iobuffer.rb_buf; + /* Return the next frame to the network */ ninfo("Send frame %p to the network: Offset=%u Length=%u\n", @@ -420,6 +427,15 @@ static void lo_poll_work(FAR void *arg) /* Perform the poll */ net_lock(); + +#ifdef CONFIG_NET_6LOWPAN + /* Make sure the our single packet buffer is attached */ + + priv->lo_radio.r_dev.d_buf = g_iobuffer.rb_buf; +#endif + + /* And perform the poll */ + (void)devif_timer(&priv->lo_radio.r_dev, lo_loopback); /* Setup the watchdog poll timer again */ @@ -576,6 +592,13 @@ static void lo_txavail_work(FAR void *arg) if (priv->lo_bifup) { /* If so, then poll the network for new XMIT data */ +#ifdef CONFIG_NET_6LOWPAN + /* Make sure the our single packet buffer is attached */ + + priv->lo_radio.r_dev.d_buf = g_iobuffer.rb_buf; +#endif + + /* Then perform the poll */ (void)devif_poll(&priv->lo_radio.r_dev, lo_loopback); } @@ -1009,7 +1032,6 @@ int pktradio_loopback(void) #ifdef CONFIG_NETDEV_IOCTL dev->d_ioctl = lo_ioctl; /* Handle network IOCTL commands */ #endif - dev->d_buf = g_iobuffer; /* Attach the IO buffer */ dev->d_private = (FAR void *)priv; /* Used to recover private state from dev */ /* Set the network mask and advertise our MAC-based IP address */