From 8ecf80b5c46a1e99e87dbed3a2189985b3138b6c Mon Sep 17 00:00:00 2001 From: Martin Budden Date: Tue, 7 Feb 2017 10:04:18 +0000 Subject: [PATCH] Added time unit test --- src/main/build/atomic.h | 13 ++++++ src/main/drivers/system.c | 19 +++++++-- src/test/Makefile | 23 +++++++++++ src/test/unit/platform.h | 14 +++++++ src/test/unit/time_unittest.cc | 72 ++++++++++++++++++++++++++++++++++ 5 files changed, 138 insertions(+), 3 deletions(-) create mode 100644 src/test/unit/time_unittest.cc diff --git a/src/main/build/atomic.h b/src/main/build/atomic.h index fc4944f302..393ec5ab84 100644 --- a/src/main/build/atomic.h +++ b/src/main/build/atomic.h @@ -20,6 +20,12 @@ // only set_BASEPRI is implemented in device library. It does always create memory barrier // missing versions are implemented here +#ifdef UNIT_TEST +static inline void __set_BASEPRI(uint32_t basePri) {(void)basePri;} +static inline void __set_BASEPRI_MAX(uint32_t basePri) {(void)basePri;} +static inline void __set_BASEPRI_nb(uint32_t basePri) {(void)basePri;} +static inline void __set_BASEPRI_MAX_nb(uint32_t basePri) {(void)basePri;} +#else // set BASEPRI and BASEPRI_MAX register, but do not create memory barrier __attribute__( ( always_inline ) ) static inline void __set_BASEPRI_nb(uint32_t basePri) { @@ -30,6 +36,7 @@ __attribute__( ( always_inline ) ) static inline void __set_BASEPRI_MAX_nb(uint3 { __ASM volatile ("\tMSR basepri_max, %0\n" : : "r" (basePri) ); } +#endif // UNIT_TEST // cleanup BASEPRI restore function, with global memory barrier static inline void __basepriRestoreMem(uint8_t *val) @@ -59,6 +66,10 @@ static inline uint8_t __basepriSetRetVal(uint8_t prio) // Run block with elevated BASEPRI (using BASEPRI_MAX), restoring BASEPRI on exit. All exit paths are handled // Full memory barrier is placed at start and exit of block +#ifdef UNIT_TEST +#define ATOMIC_BLOCK(prio) {} +#define ATOMIC_BLOCK_NB(prio) {} +#else #define ATOMIC_BLOCK(prio) for ( uint8_t __basepri_save __attribute__((__cleanup__(__basepriRestoreMem))) = __get_BASEPRI(), \ __ToDo = __basepriSetMemRetVal(prio); __ToDo ; __ToDo = 0 ) @@ -71,6 +82,8 @@ static inline uint8_t __basepriSetRetVal(uint8_t prio) #define ATOMIC_BLOCK_NB(prio) for ( uint8_t __basepri_save __attribute__((__cleanup__(__basepriRestore))) = __get_BASEPRI(), \ __ToDo = __basepriSetRetVal(prio); __ToDo ; __ToDo = 0 ) \ +#endif // UNIT_TEST + // ATOMIC_BARRIER // Create memory barrier // - at the beginning (all data must be reread from memory) diff --git a/src/main/drivers/system.c b/src/main/drivers/system.c index e9f7865b1d..1319dea750 100644 --- a/src/main/drivers/system.c +++ b/src/main/drivers/system.c @@ -25,6 +25,7 @@ #include "sound_beeper.h" #include "nvic.h" #include "build/atomic.h" +#include "build/build_config.h" #include "system.h" @@ -48,12 +49,13 @@ void registerExtiCallbackHandler(IRQn_Type irqn, extiCallbackHandlerFunc *fn) } // cycles per microsecond -static timeUs_t usTicks = 0; +STATIC_UNIT_TESTED timeUs_t usTicks = 0; // current uptime for 1kHz systick timer. will rollover after 49 days. hopefully we won't care. -static volatile timeMs_t sysTickUptime = 0; +STATIC_UNIT_TESTED volatile timeMs_t sysTickUptime = 0; // cached value of RCC->CSR uint32_t cachedRccCsrValue; +#ifndef UNIT_TEST void cycleCounterInit(void) { #if defined(USE_HAL_DRIVER) @@ -69,6 +71,7 @@ void cycleCounterInit(void) CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk; DWT->CTRL |= DWT_CTRL_CYCCNTENA_Msk; } +#endif // UNIT_TEST // SysTick @@ -89,8 +92,12 @@ void SysTick_Handler(void) uint32_t ticks(void) { +#ifdef UNIT_TEST + return 0; +#else CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk; return DWT->CYCCNT; +#endif } timeDelta_t ticks_diff_us(uint32_t begin, uint32_t end) @@ -98,7 +105,7 @@ timeDelta_t ticks_diff_us(uint32_t begin, uint32_t end) return (end - begin) / usTicks; } -// Return system uptime in microseconds (rollover in 70minutes) +// Return system uptime in microseconds timeUs_t microsISR(void) { register uint32_t ms, pending, cycle_cnt; @@ -132,9 +139,11 @@ timeUs_t micros(void) // Call microsISR() in interrupt and elevated (non-zero) BASEPRI context +#ifndef UNIT_TEST if ((SCB->ICSR & SCB_ICSR_VECTACTIVE_Msk) || (__get_BASEPRI())) { return microsISR(); } +#endif do { ms = sysTickUptime; @@ -199,6 +208,9 @@ void delay(timeMs_t ms) void failureMode(failureMode_e mode) { +#ifdef UNIT_TEST + (void)mode; +#else int codeRepeatsRemaining = 10; int codeFlashesRemaining; int shortFlashesRemaining; @@ -239,4 +251,5 @@ void failureMode(failureMode_e mode) #else systemResetToBootloader(); #endif +#endif //UNIT_TEST } diff --git a/src/test/Makefile b/src/test/Makefile index 9a14a52c25..509e65d274 100644 --- a/src/test/Makefile +++ b/src/test/Makefile @@ -630,6 +630,29 @@ $(OBJECT_DIR)/sensor_gyro_unittest : \ $(CXX) $(CXX_FLAGS) $^ -o $(OBJECT_DIR)/$@ +$(OBJECT_DIR)/drivers/system.o : \ + $(USER_DIR)/drivers/system.c \ + $(USER_DIR)/drivers/system.h \ + $(GTEST_HEADERS) + + @mkdir -p $(dir $@) + $(CC) $(C_FLAGS) $(TEST_CFLAGS) -c $(USER_DIR)/drivers/system.c -o $@ + +$(OBJECT_DIR)/time_unittest.o : \ + $(TEST_DIR)/time_unittest.cc \ + $(USER_DIR)/drivers/system.h \ + $(GTEST_HEADERS) + + @mkdir -p $(dir $@) + $(CXX) $(CXX_FLAGS) $(TEST_CFLAGS) -c $(TEST_DIR)/time_unittest.cc -o $@ + +$(OBJECT_DIR)/time_unittest : \ + $(OBJECT_DIR)/drivers/system.o \ + $(OBJECT_DIR)/time_unittest.o \ + $(OBJECT_DIR)/gtest_main.a + + $(CXX) $(CXX_FLAGS) $^ -o $(OBJECT_DIR)/$@ + test: $(TESTS:%=test-%) diff --git a/src/test/unit/platform.h b/src/test/unit/platform.h index 50d5eec89c..6b5d64ac6c 100644 --- a/src/test/unit/platform.h +++ b/src/test/unit/platform.h @@ -55,6 +55,20 @@ uint8_t DMA_GetFlagStatus(uint32_t); void DMA_Cmd(DMA_Channel_TypeDef*, FunctionalState ); void DMA_ClearFlag(uint32_t); +typedef struct +{ + uint32_t CTRL; /*!< Offset: 0x000 (R/W) SysTick Control and Status Register */ + uint32_t LOAD; /*!< Offset: 0x004 (R/W) SysTick Reload Value Register */ + uint32_t VAL; /*!< Offset: 0x008 (R/W) SysTick Current Value Register */ + uint32_t CALIB; /*!< Offset: 0x00C (R/ ) SysTick Calibration Register */ +} SysTick_Type; + +#define SysTick_CTRL_COUNTFLAG_Pos 16 /*!< SysTick CTRL: COUNTFLAG Position */ +#define SysTick_CTRL_COUNTFLAG_Msk (1UL << SysTick_CTRL_COUNTFLAG_Pos) /*!< SysTick CTRL: COUNTFLAG Mask */ + +extern SysTick_Type *SysTick; + + #define WS2811_DMA_TC_FLAG 1 #define WS2811_DMA_HANDLER_IDENTIFER 0 diff --git a/src/test/unit/time_unittest.cc b/src/test/unit/time_unittest.cc new file mode 100644 index 0000000000..2c9f819f2a --- /dev/null +++ b/src/test/unit/time_unittest.cc @@ -0,0 +1,72 @@ +/* + * This file is part of Cleanflight. + * + * Cleanflight is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Cleanflight is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Cleanflight. If not, see . + */ + +#include +#include + +#include + +extern "C" { + #include "common/time.h" + #include "drivers/system.h" + extern timeUs_t usTicks; + extern volatile timeMs_t sysTickUptime; +} + +#include "unittest_macros.h" +#include "gtest/gtest.h" + +SysTick_Type SysTickValue; +SysTick_Type *SysTick = &SysTickValue; + +TEST(TimeUnittest, TestMillis) +{ + sysTickUptime = 0; + EXPECT_EQ(0, millis()); + sysTickUptime = 1; + EXPECT_EQ(1, millis()); +} + +TEST(TimeUnittest, TestMicros) +{ + usTicks = 168; + SysTick->VAL = 1000 * usTicks; + sysTickUptime = 0; + EXPECT_EQ(0, micros()); + sysTickUptime = 1; + EXPECT_EQ(1000, micros()); + // ULONG_MAX = 4294967295 + sysTickUptime = 429496; // ULONG_MAX / 1000; + EXPECT_EQ(429496000, micros()); + sysTickUptime = 429497; + EXPECT_EQ(429497000, micros()); + sysTickUptime = 500000; + EXPECT_EQ(500000000, micros()); + + sysTickUptime = 0; + SysTick->VAL = 0; + EXPECT_EQ(1000, micros()); + sysTickUptime = 1; + EXPECT_EQ(2000, micros()); + // ULONG_MAX = 4294967295 + sysTickUptime = 429496; // ULONG_MAX / 1000; + EXPECT_EQ(429497000, micros()); + sysTickUptime = 429497; + EXPECT_EQ(429498000, micros()); + sysTickUptime = 500000; + EXPECT_EQ(500001000, micros()); +}