From c171695235a9e7239f48c4c15a0b0b86971ca1f0 Mon Sep 17 00:00:00 2001 From: Marcin Wierzbicki Date: Thu, 19 Dec 2024 10:23:04 +0100 Subject: [PATCH] Remove usage of FreeRTOS timers from asyncFreeRtos Until now for implementing async schedule functions FreeRTOS timers were in use. This led to a huge overhead because most (re)setting of a timer caused two additional task switches (first to high prio timer task and then back to the active task). This new implementation uses only the task notification mechanism for both executing events and scheduling by specifying the next required timeout of the task using the parameter xTicksToWait of function xTaskNotifyWait. Change-Id: Ieaa3ef298c39f2b11eca9c1ed9c2b8bde9dc2290 --- .../freeRtos/mock/include/os/FreeRtosMock.h | 2 +- libs/3rdparty/freeRtos/mock/include/task.h | 2 +- .../freeRtos/mock/src/os/FreeRtosMock.cpp | 4 +- .../include/async/FreeRtosAdapter.h | 11 +- .../asyncFreeRtos/include/async/TaskContext.h | 107 ++--- .../include/async/TaskInitializer.h | 22 +- .../test/gtest/src/async/AsyncTest.cpp | 5 - .../gtest/src/async/FreeRtosAdapterTest.cpp | 15 +- .../test/gtest/src/async/TaskContextTest.cpp | 424 ++++++++++-------- .../gtest/src/async/TaskInitializerTest.cpp | 19 +- .../bsw/asyncImpl/include/async/EventPolicy.h | 6 +- 11 files changed, 300 insertions(+), 317 deletions(-) diff --git a/libs/3rdparty/freeRtos/mock/include/os/FreeRtosMock.h b/libs/3rdparty/freeRtos/mock/include/os/FreeRtosMock.h index 64343ae75a..83d32c3d7f 100644 --- a/libs/3rdparty/freeRtos/mock/include/os/FreeRtosMock.h +++ b/libs/3rdparty/freeRtos/mock/include/os/FreeRtosMock.h @@ -23,7 +23,7 @@ namespace os MOCK_METHOD0(xTaskGetIdleTaskHandle, TaskHandle_t()); MOCK_METHOD3(xTaskNotify, void(TaskHandle_t taskHandle, uint32_t ulValue, eNotifyAction eAction)); MOCK_METHOD4(xTaskNotifyFromISR, void(TaskHandle_t taskHandle, uint32_t ulValue, eNotifyAction eAction, BaseType_t *pxHigherPriorityTaskWoken)); - MOCK_METHOD4(xTaskNotifyWait, void(uint32_t ulBitsToClearOnEntry, uint32_t ulBitsToClearOnExit, uint32_t *pulNotificationValue, TickType_t xTicksToWait)); + MOCK_METHOD4(xTaskNotifyWait, BaseType_t(uint32_t ulBitsToClearOnEntry, uint32_t ulBitsToClearOnExit, uint32_t *pulNotificationValue, TickType_t xTicksToWait)); MOCK_METHOD0(vTaskStartScheduler, void()); MOCK_METHOD1(uxTaskGetTaskNumber, UBaseType_t(TaskHandle_t xTask)); MOCK_METHOD1(uxTaskGetStackHighWaterMark, BaseType_t(TaskHandle_t taskHandle)); diff --git a/libs/3rdparty/freeRtos/mock/include/task.h b/libs/3rdparty/freeRtos/mock/include/task.h index 4c99258ee2..dd5cf484ab 100644 --- a/libs/3rdparty/freeRtos/mock/include/task.h +++ b/libs/3rdparty/freeRtos/mock/include/task.h @@ -11,7 +11,7 @@ TaskHandle_t xTaskCreateStatic(TaskFunction_t pxTaskCode, const char * pcName, c void * pvParameters, UBaseType_t uxPriority, StackType_t * puxStackBuffer, StaticTask_t * pxTaskBuffer); void xTaskNotify(TaskHandle_t taskHandle, uint32_t ulValue, eNotifyAction eAction); void xTaskNotifyFromISR(TaskHandle_t taskHandle, uint32_t ulValue, eNotifyAction eAction, BaseType_t *pxHigherPriorityTaskWoken); -void xTaskNotifyWait(uint32_t ulBitsToClearOnEntry, uint32_t ulBitsToClearOnExit, uint32_t *pulNotificationValue, TickType_t xTicksToWait); +BaseType_t xTaskNotifyWait(uint32_t ulBitsToClearOnEntry, uint32_t ulBitsToClearOnExit, uint32_t *pulNotificationValue, TickType_t xTicksToWait); const char* pcTaskGetName(TaskHandle_t taskHandle); BaseType_t uxTaskGetStackHighWaterMark(TaskHandle_t taskHandle); void vTaskStartScheduler(); diff --git a/libs/3rdparty/freeRtos/mock/src/os/FreeRtosMock.cpp b/libs/3rdparty/freeRtos/mock/src/os/FreeRtosMock.cpp index 282dbd928b..c0cf273581 100644 --- a/libs/3rdparty/freeRtos/mock/src/os/FreeRtosMock.cpp +++ b/libs/3rdparty/freeRtos/mock/src/os/FreeRtosMock.cpp @@ -45,14 +45,14 @@ xTaskNotifyFromISR( taskHandle, ulValue, eAction, pxHigherPriorityTaskWoken); } -void +BaseType_t xTaskNotifyWait( uint32_t ulBitsToClearOnEntry, uint32_t ulBitsToClearOnExit, uint32_t* pulNotificationValue, TickType_t xTicksToWait) { - FreeRtosMock::instance().xTaskNotifyWait( + return FreeRtosMock::instance().xTaskNotifyWait( ulBitsToClearOnEntry, ulBitsToClearOnExit, pulNotificationValue, xTicksToWait); } diff --git a/libs/bsw/asyncFreeRtos/include/async/FreeRtosAdapter.h b/libs/bsw/asyncFreeRtos/include/async/FreeRtosAdapter.h index fe7eb780be..4a16bb9f7c 100644 --- a/libs/bsw/asyncFreeRtos/include/async/FreeRtosAdapter.h +++ b/libs/bsw/asyncFreeRtos/include/async/FreeRtosAdapter.h @@ -237,7 +237,7 @@ class FreeRtosAdapter static void initTask(TaskInitializer& initializer); - static void initTask(ContextType context, char const* name, StaticTimer_t& timer); + static void initTask(ContextType context); static void TaskFunction(void* param); @@ -353,12 +353,12 @@ void FreeRtosAdapter::initTask(TaskInitializer& initializer) } else { - initTask(context, initializer._name, initializer._timer); + initTask(context); TaskContextType& taskContext = _taskContexts[static_cast(context)]; if (context == TASK_IDLE) { _idleTaskInitializer = &initializer; - taskContext.initTask(TASK_IDLE, initializer._taskFunction); + taskContext.initTask(TASK_IDLE, initializer._name, initializer._taskFunction); } else { @@ -374,11 +374,8 @@ void FreeRtosAdapter::initTask(TaskInitializer& initializer) } template -void FreeRtosAdapter::initTask( - ContextType const context, char const* const name, StaticTimer_t& timer) +void FreeRtosAdapter::initTask(ContextType const context) { - TaskContextType& taskContext = _taskContexts[static_cast(context)]; - taskContext.createTimer(timer, name); #ifndef ASYNC_TIMEOUTMANAGER2_DISABLE _timeoutManagers[static_cast(context)].init(context); #endif // ASYNC_TIMEOUTMANAGER2_DISABLE diff --git a/libs/bsw/asyncFreeRtos/include/async/TaskContext.h b/libs/bsw/asyncFreeRtos/include/async/TaskContext.h index 5c571aab6f..70cf5ce7d7 100644 --- a/libs/bsw/asyncFreeRtos/include/async/TaskContext.h +++ b/libs/bsw/asyncFreeRtos/include/async/TaskContext.h @@ -19,7 +19,6 @@ #include #include -#include namespace async { @@ -46,9 +45,10 @@ class TaskContext : public EventDispatcher<2U, LockType> /** * Initializes a task with a specified context and task function. * \param context The context associated with this task. + * \param name The name of this task. * \param taskFunction The function to execute in this task. */ - void initTask(ContextType context, TaskFunctionType taskFunction); + void initTask(ContextType context, char const* const name, TaskFunctionType taskFunction); /** * Sets the FreeRTOS task handle for this context. @@ -73,13 +73,6 @@ class TaskContext : public EventDispatcher<2U, LockType> StackType const& stack, TaskFunctionType taskFunction); - /** - * Creates a FreeRTOS timer. - * \param timer The static timer storage structure. - * \param name The name of the timer. - */ - void createTimer(StaticTimer_t& timer, char const* name); - char const* getName() const; TaskHandle_t getTaskHandle() const; @@ -129,12 +122,6 @@ class TaskContext : public EventDispatcher<2U, LockType> /// Dispatches events while runnable is executing. void dispatchWhileWork(); - /** - * Sets a timeout value in microseconds. - * \param timeInUs The timeout duration in microseconds. - */ - void setTimeout(uint32_t timeInUs); - /** * Retrieves the amount of unused stack space for a specified task. * \param taskHandle The handle of the task. @@ -152,29 +139,28 @@ class TaskContext : public EventDispatcher<2U, LockType> friend class EventPolicy, 0U>; friend class EventPolicy, 1U>; - void setEvents(EventMaskType eventMask); - EventMaskType waitEvents(); - EventMaskType peekEvents(); - -private: - using TimerType = ::timer::Timer; + using ExecuteEventPolicyType = EventPolicy, 0U>; + using TimerEventPolicyType = EventPolicy, 1U>; + using TimerType = ::timer::Timer; static EventMaskType const STOP_EVENT_MASK = static_cast( static_cast(1U) << static_cast(EVENT_COUNT)); static EventMaskType const WAIT_EVENT_MASK = (STOP_EVENT_MASK << 1U) - 1U; + void setEvents(EventMaskType eventMask); + EventMaskType waitEvents(); + EventMaskType peekEvents(); + void handleTimeout(); static void staticTaskFunction(void* param); - static void staticTimerFunction(TimerHandle_t handle); - RunnableExecutor, 0U>, LockType> - _runnableExecutor; + RunnableExecutor _runnableExecutor; TimerType _timer; - EventPolicy, 1U> _timerEventPolicy; + TimerEventPolicyType _timerEventPolicy; TaskFunctionType _taskFunction; TaskHandle_t _taskHandle; - TimerHandle_t _timerHandle; + char const* _name; ContextType _context; }; @@ -184,11 +170,10 @@ class TaskContext : public EventDispatcher<2U, LockType> template inline TaskContext::TaskContext() : _runnableExecutor(*this) -, _timer() , _timerEventPolicy(*this) , _taskFunction() , _taskHandle(nullptr) -, _timerHandle(nullptr) +, _name(nullptr) , _context(CONTEXT_INVALID) { _timerEventPolicy.setEventHandler( @@ -197,9 +182,11 @@ inline TaskContext::TaskContext() } template -void TaskContext::initTask(ContextType const context, TaskFunctionType const taskFunction) +void TaskContext::initTask( + ContextType const context, char const* const name, TaskFunctionType const taskFunction) { _context = context; + _name = name; _taskFunction = taskFunction; } @@ -219,6 +206,7 @@ void TaskContext::createTask( TaskFunctionType const taskFunction) { _context = context; + _name = name; _taskFunction = taskFunction.has_value() ? taskFunction : TaskFunctionType::template create<&TaskContext::defaultTaskFunction>(); @@ -232,17 +220,10 @@ void TaskContext::createTask( &task); } -template -void TaskContext::createTimer(StaticTimer_t& timer, char const* const name) -{ - _timerHandle = xTimerCreateStatic( - name, 1U, static_cast(pdFALSE), this, &staticTimerFunction, &timer); -} - template inline char const* TaskContext::getName() const { - return (_timerHandle != nullptr) ? pcTimerGetName(_timerHandle) : nullptr; + return _name; } template @@ -317,33 +298,35 @@ template inline EventMaskType TaskContext::waitEvents() { EventMaskType eventMask = 0U; - xTaskNotifyWait(0U, WAIT_EVENT_MASK, &eventMask, Binding::WAIT_EVENTS_TICK_COUNT); - return eventMask; + uint32_t ticks = Binding::WAIT_EVENTS_TICK_COUNT; + uint32_t nextDelta; + bool const hasDelta = _timer.getNextDelta(getSystemTimeUs32Bit(), nextDelta); + if (hasDelta) + { + ticks = static_cast((nextDelta + (Config::TICK_IN_US - 1U)) / Config::TICK_IN_US); + } + if (xTaskNotifyWait(0U, WAIT_EVENT_MASK, &eventMask, ticks) != 0) + { + return eventMask; + } + else if (hasDelta) + { + return TimerEventPolicyType::EVENT_MASK; + } + else + { + return 0U; + } } template inline EventMaskType TaskContext::peekEvents() { EventMaskType eventMask = 0U; - xTaskNotifyWait(0U, WAIT_EVENT_MASK, &eventMask, 0U); + (void)xTaskNotifyWait(0U, WAIT_EVENT_MASK, &eventMask, 0U); return eventMask; } -template -void TaskContext::setTimeout(uint32_t const timeInUs) -{ - if (timeInUs > 0U) - { - uint32_t const ticks - = static_cast((timeInUs + (Config::TICK_IN_US - 1U)) / Config::TICK_IN_US); - (void)xTimerChangePeriod(_timerHandle, ticks, 0U); - } - else - { - (void)_timerEventPolicy.setEvent(); - } -} - template void TaskContext::callTaskFunction() { @@ -364,7 +347,6 @@ void TaskContext::dispatch() template inline void TaskContext::stopDispatch() { - _runnableExecutor.shutdown(); setEvents(STOP_EVENT_MASK); } @@ -373,6 +355,7 @@ void TaskContext::dispatchWhileWork() { while (true) { + handleTimeout(); EventMaskType const eventMask = peekEvents(); if (eventMask != 0U) { @@ -402,11 +385,6 @@ template void TaskContext::handleTimeout() { while (_timer.processNextTimeout(getSystemTimeUs32Bit())) {} - uint32_t nextDelta; - if (_timer.getNextDelta(getSystemTimeUs32Bit(), nextDelta)) - { - setTimeout(nextDelta); - } } template @@ -416,13 +394,6 @@ void TaskContext::staticTaskFunction(void* const param) taskContext.callTaskFunction(); } -template -void TaskContext::staticTimerFunction(TimerHandle_t const handle) -{ - TaskContext& taskContext = *reinterpret_cast(pvTimerGetTimerID(handle)); - taskContext._timerEventPolicy.setEvent(); -} - } // namespace async #endif // GUARD_60674D25_51E0_4A73_8CD1_9C6C6138C877 diff --git a/libs/bsw/asyncFreeRtos/include/async/TaskInitializer.h b/libs/bsw/asyncFreeRtos/include/async/TaskInitializer.h index 6eebd05439..9784d94d98 100644 --- a/libs/bsw/asyncFreeRtos/include/async/TaskInitializer.h +++ b/libs/bsw/asyncFreeRtos/include/async/TaskInitializer.h @@ -50,7 +50,6 @@ struct TaskInitializer : public StaticRunnable> using TaskConfigType = typename AdapterType::TaskConfigType; using TaskFunctionType = typename AdapterType::TaskFunctionType; using TaskObjectType = StaticTask_t; - using TimerObjectType = StaticTimer_t; /** * Creates and initializes a task with the specified parameters. @@ -73,7 +72,6 @@ struct TaskInitializer : public StaticRunnable> ContextType context, char const* name, TaskObjectType& task, - TimerObjectType& timer, T& stack, TaskFunctionType taskFunction, TaskConfigType const& config); @@ -83,7 +81,6 @@ struct TaskInitializer : public StaticRunnable> ContextType context, char const* name, TaskObjectType& task, - TimerObjectType& timer, StackSliceType const& stack, TaskFunctionType taskFunction, TaskConfigType const& config); @@ -100,10 +97,6 @@ struct TaskInitializer : public StaticRunnable> /// Reference to the static task object. TaskObjectType& _task; - - /// Reference to the static timer object associated with the task. - TimerObjectType& _timer; - /// The name of the task. char const* _name; @@ -136,7 +129,6 @@ class TaskImpl using TaskConfigType = typename AdapterType::TaskConfigType; using TaskFunctionType = typename AdapterType::TaskFunctionType; using TaskObjectType = StaticTask_t; - using TimerObjectType = StaticTimer_t; TaskImpl(char const* name, TaskFunctionType taskFunction, TaskConfigType const& taskConfig); @@ -146,7 +138,6 @@ class TaskImpl private: Stack _stack; TaskObjectType _task; - TimerObjectType _timer; }; template @@ -158,7 +149,6 @@ class TaskImpl using TaskConfigType = typename AdapterType::TaskConfigType; using TaskFunctionType = typename AdapterType::TaskFunctionType; using TaskObjectType = StaticTask_t; - using TimerObjectType = StaticTimer_t; template TaskImpl( @@ -172,7 +162,6 @@ class TaskImpl private: TaskObjectType _task; - TimerObjectType _timer; }; template @@ -255,7 +244,6 @@ void TaskInitializer::create( ContextType const context, char const* const name, TaskObjectType& task, - TimerObjectType& timer, T& stack, TaskFunctionType const taskFunction, TaskConfigType const& config) @@ -264,8 +252,7 @@ void TaskInitializer::create( ::estd::memory::align(alignof(StackType_t), bytes); StackSliceType const stackSlice = bytes.template reinterpret_as(); estd_assert((stackSlice.size() * sizeof(StackType_t)) >= sizeof(TaskInitializer)); - new (stackSlice.data()) - TaskInitializer(context, name, task, timer, stackSlice, taskFunction, config); + new (stackSlice.data()) TaskInitializer(context, name, task, stackSlice, taskFunction, config); } template @@ -273,14 +260,12 @@ TaskInitializer::TaskInitializer( ContextType const context, char const* const name, TaskObjectType& task, - TimerObjectType& timer, StackSliceType const& stack, TaskFunctionType const taskFunction, TaskConfigType const& config) : _stack(stack) , _taskFunction(taskFunction) , _task(task) -, _timer(timer) , _name(name) , _context(context) , _config(config) @@ -296,8 +281,7 @@ template TaskImpl::TaskImpl( char const* const name, TaskFunctionType const taskFunction, TaskConfigType const& taskConfig) { - TaskInitializer::create( - Context, name, _task, _timer, _stack, taskFunction, taskConfig); + TaskInitializer::create(Context, name, _task, _stack, taskFunction, taskConfig); } template @@ -308,7 +292,7 @@ TaskImpl::TaskImpl( TaskFunctionType const taskFunction, TaskConfigType const& taskConfig) { - TaskInitializer::create(Context, name, _task, _timer, stack, taskFunction, taskConfig); + TaskInitializer::create(Context, name, _task, stack, taskFunction, taskConfig); } template diff --git a/libs/bsw/asyncFreeRtos/test/gtest/src/async/AsyncTest.cpp b/libs/bsw/asyncFreeRtos/test/gtest/src/async/AsyncTest.cpp index 69df090632..59adfccb41 100644 --- a/libs/bsw/asyncFreeRtos/test/gtest/src/async/AsyncTest.cpp +++ b/libs/bsw/asyncFreeRtos/test/gtest/src/async/AsyncTest.cpp @@ -62,7 +62,6 @@ TEST_F(AsyncTest, testExecuteAndScheduleCalls) xTaskCreateStatic( NotNull(), name, 256U / sizeof(StackType_t), NotNull(), 1U, NotNull(), NotNull())) .WillOnce(Return(&taskHandle)); - EXPECT_CALL(_freeRtosMock, xTimerCreateStatic(name, _, 0U, NotNull(), NotNull(), NotNull())); AdapterType::Task<1U, 256U> task(name); AdapterType::init(); { @@ -98,11 +97,7 @@ TEST_F(AsyncTest, testInitIdleTask) AdapterType::IdleTask<384U> idleTask( name, AdapterType::TaskFunctionType::create(*this)); { - uint32_t timerHandle = 13U; - EXPECT_CALL(_freeRtosMock, xTimerCreateStatic(name, _, 0U, NotNull(), NotNull(), NotNull())) - .WillOnce(Return(&timerHandle)); AdapterType::init(); - EXPECT_CALL(_freeRtosMock, pcTimerGetName(&timerHandle)).WillOnce(Return(name)); EXPECT_EQ(name, AdapterType::getTaskName(AdapterType::TASK_IDLE)); } { diff --git a/libs/bsw/asyncFreeRtos/test/gtest/src/async/FreeRtosAdapterTest.cpp b/libs/bsw/asyncFreeRtos/test/gtest/src/async/FreeRtosAdapterTest.cpp index b3eb4837c8..30b77bddf3 100644 --- a/libs/bsw/asyncFreeRtos/test/gtest/src/async/FreeRtosAdapterTest.cpp +++ b/libs/bsw/asyncFreeRtos/test/gtest/src/async/FreeRtosAdapterTest.cpp @@ -57,8 +57,6 @@ TEST_F(FreeRtosAdapterTest, testCreateTask) xTaskCreateStatic( NotNull(), name, 256U / sizeof(StackType_t), NotNull(), 1U, NotNull(), NotNull())) .WillOnce(Return(&taskHandle)); - EXPECT_CALL( - _freeRtosMock, xTimerCreateStatic(name, _, 0U, NotNull(), NotNull(), NotNull())); CutType::init(); } { @@ -68,19 +66,15 @@ TEST_F(FreeRtosAdapterTest, testCreateTask) CutType::TaskFunctionType:: create(*this)); - uint32_t taskHandle = 13U; - uint32_t timerHandle = 14U; + uint32_t taskHandle = 13U; EXPECT_CALL( _freeRtosMock, xTaskCreateStatic( NotNull(), name, 512U / sizeof(StackType_t), NotNull(), 2U, NotNull(), NotNull())) .WillOnce(Return(&taskHandle)); - EXPECT_CALL(_freeRtosMock, xTimerCreateStatic(name, _, 0U, NotNull(), NotNull(), NotNull())) - .WillOnce(Return(&timerHandle)); CutType::init(); { // Test get name - EXPECT_CALL(_freeRtosMock, pcTimerGetName(&timerHandle)).WillOnce(Return(name)); EXPECT_EQ(name, CutType::getTaskName(2U)); } } @@ -106,18 +100,14 @@ TEST_F(FreeRtosAdapterTest, testStackUsage) CutType::TaskFunctionType:: create(*this)); - uint32_t taskHandle = 13U; - uint32_t timerHandle = 14U; + uint32_t taskHandle = 13U; EXPECT_CALL( _freeRtosMock, xTaskCreateStatic( NotNull(), name, 128U / sizeof(StackType_t), NotNull(), 2U, NotNull(), NotNull())) .WillOnce(Return(&taskHandle)); - EXPECT_CALL(_freeRtosMock, xTimerCreateStatic(name, _, 0U, NotNull(), NotNull(), NotNull())) - .WillOnce(Return(&timerHandle)); CutType::init(); { - EXPECT_CALL(_freeRtosMock, pcTimerGetName(&timerHandle)).WillOnce(Return(name)); EXPECT_EQ(name, CutType::getTaskName(2U)); EXPECT_CALL(_freeRtosMock, uxTaskGetStackHighWaterMark(&taskHandle)) @@ -244,7 +234,6 @@ TEST_F(FreeRtosAdapterTest, testExecuteAndScheduleCalls) xTaskCreateStatic( NotNull(), name, 256U / sizeof(StackType_t), NotNull(), 1U, NotNull(), NotNull())) .WillOnce(Return(&taskHandle)); - EXPECT_CALL(_freeRtosMock, xTimerCreateStatic(name, _, 0U, NotNull(), NotNull(), NotNull())); CutType::init(); { EXPECT_CALL(_freeRtosMock, xTaskNotify(&taskHandle, _, eSetBits)); diff --git a/libs/bsw/asyncFreeRtos/test/gtest/src/async/TaskContextTest.cpp b/libs/bsw/asyncFreeRtos/test/gtest/src/async/TaskContextTest.cpp index 6d53e89127..5241d435d6 100644 --- a/libs/bsw/asyncFreeRtos/test/gtest/src/async/TaskContextTest.cpp +++ b/libs/bsw/asyncFreeRtos/test/gtest/src/async/TaskContextTest.cpp @@ -38,7 +38,7 @@ class TestBindingMock : public ::estd::singleton class TaskContextTest : public Test { public: - TaskContextTest() : _name("test"), _taskHandle(10U), _timerHandle(14U) {} + TaskContextTest() : _name("test"), _taskHandle(10U) {} protected: StrictMock<::os::FreeRtosMock> _freeRtosMock; @@ -53,12 +53,12 @@ class TaskContextTest : public Test StackType_t _stack[100]; char const* _name; uint32_t _taskHandle; - uint32_t _timerHandle; }; /** * \req: [BSW_ASFR_39], [BSW_ASFR_52], [BSW_ASFR_54], [BSW_ASFR_57] - * \refs: SMD_asyncFreeRtos_TaskContext, SMD_asyncFreeRtos_TaskContextEventHandling + * \refs: SMD_asyncFreeRtos_TaskContext, SMD_asyncFreeRtos_TaskContextEventHandling, + * SMD_asyncFreeRtos_TaskContextInitialization * \desc: To test task creation and execution */ TEST_F(TaskContextTest, testCreateAndRunTask) @@ -76,17 +76,18 @@ TEST_F(TaskContextTest, testCreateAndRunTask) EXPECT_TRUE(osTaskFunction != 0L); // expect notify wait Sequence seq; + EXPECT_CALL(_systemTimerMock, getSystemTimeUs32Bit()).WillRepeatedly(Return(100000U)); EXPECT_CALL( _freeRtosMock, xTaskNotifyWait(0U, 7U, NotNull(), TestBindingMock::WAIT_EVENTS_TICK_COUNT)) .InSequence(seq) - .WillOnce(SetArgPointee<2>(0U)); + .WillOnce(DoAll(SetArgPointee<2>(0U), Return(false))); // second time do nothing again EXPECT_CALL( _freeRtosMock, xTaskNotifyWait(0U, 7U, NotNull(), TestBindingMock::WAIT_EVENTS_TICK_COUNT)) .InSequence(seq) - .WillOnce(DoAll(SetArgPointee<2>(0U), StopDispatch(&cut))); + .WillOnce(DoAll(SetArgPointee<2>(0U), StopDispatch(&cut), Return(false))); // trigger shutdown on next iteration uint32_t eventMask = 0U; EXPECT_CALL(_bindingMock, getHigherPriorityTaskWokenFunc()) @@ -98,7 +99,7 @@ TEST_F(TaskContextTest, testCreateAndRunTask) _freeRtosMock, xTaskNotifyWait(0U, 7U, NotNull(), TestBindingMock::WAIT_EVENTS_TICK_COUNT)) .InSequence(seq) - .WillOnce(CopyArgPointee2(&eventMask)); + .WillOnce(DoAll(CopyArgPointee2(&eventMask), Return(true))); osTaskFunction(param); Mock::VerifyAndClearExpectations(&_freeRtosMock); } @@ -120,24 +121,6 @@ TEST_F(TaskContextTest, testCreateAndRunTask) } } -/** - * \refs: SMD_asyncFreeRtos_TaskContextInitialization - * \desc: To test timer creation - */ -TEST_F(TaskContextTest, testCreateTimer) -{ - TaskContext cut; - EXPECT_EQ(0L, cut.getName()); - StaticTimer_t timer; - char const* name = "test"; - uint32_t timerHandle = 12U; - EXPECT_CALL(_freeRtosMock, xTimerCreateStatic(name, 1U, 0U, NotNull(), NotNull(), &timer)) - .WillOnce(Return(&timerHandle)); - EXPECT_CALL(_freeRtosMock, pcTimerGetName(&timerHandle)).WillOnce(Return(name)); - cut.createTimer(timer, name); - EXPECT_EQ(name, cut.getName()); -} - /** * \req: [BSW_ASFR_51], [BSW_ASFR_52], [BSW_ASFR_53] * \refs: SMD_asyncFreeRtos_TaskContextAsyncApi @@ -146,9 +129,13 @@ TEST_F(TaskContextTest, testCreateTimer) TEST_F(TaskContextTest, testExecute) { TaskContext cut; + + EXPECT_CALL(_systemTimerMock, getSystemTimeUs32Bit()).WillRepeatedly(Return(100000U)); + + TaskFunction_t* osTaskFunction = 0L; EXPECT_CALL( _freeRtosMock, xTaskCreateStatic(NotNull(), _name, 100, NotNull(), 12U, _stack, &_task)) - .WillOnce(Return(&_taskHandle)); + .WillOnce(DoAll(SaveArg<0>(&osTaskFunction), Return(&_taskHandle))); cut.createTask(1U, _task, _name, 12U, _stack, TaskContext::TaskFunctionType()); { // from task context @@ -162,14 +149,29 @@ TEST_F(TaskContextTest, testExecute) Mock::VerifyAndClearExpectations(&_freeRtosMock); Sequence seq; - EXPECT_CALL(_freeRtosMock, xTaskNotifyWait(0U, 7U, NotNull(), 0U)) + EXPECT_CALL( + _freeRtosMock, + xTaskNotifyWait(0U, 7U, NotNull(), TestBindingMock::WAIT_EVENTS_TICK_COUNT)) .InSequence(seq) - .WillOnce(SetArgPointee<2>(eventMask)); - EXPECT_CALL(_freeRtosMock, xTaskNotifyWait(0U, 7U, NotNull(), 0U)) + .WillOnce(DoAll(SetArgPointee<2>(eventMask), Return(true))); + EXPECT_CALL( + _freeRtosMock, + xTaskNotifyWait(0U, 7U, NotNull(), TestBindingMock::WAIT_EVENTS_TICK_COUNT)) .InSequence(seq) - .WillOnce(SetArgPointee<2>(0U)); + .WillOnce(DoAll(SetArgPointee<2>(0U), StopDispatch(&cut), Return(false))); EXPECT_CALL(_runnableMock1, execute()); - cut.dispatchWhileWork(); + // trigger shutdown on next iteration + EXPECT_CALL(_bindingMock, getHigherPriorityTaskWokenFunc()) + .WillOnce(Return(static_cast(0L))); + EXPECT_CALL(_freeRtosMock, xTaskNotify(&_taskHandle, _, eSetBits)) + .InSequence(seq) + .WillOnce(SaveArg<1>(&eventMask)); + EXPECT_CALL( + _freeRtosMock, + xTaskNotifyWait(0U, 7U, NotNull(), TestBindingMock::WAIT_EVENTS_TICK_COUNT)) + .InSequence(seq) + .WillOnce(DoAll(CopyArgPointee2(&eventMask), Return(true))); + osTaskFunction(&cut); Mock::VerifyAndClearExpectations(&_runnableMock1); } { @@ -186,38 +188,30 @@ TEST_F(TaskContextTest, testExecute) Mock::VerifyAndClearExpectations(&_freeRtosMock); Sequence seq; - EXPECT_CALL(_freeRtosMock, xTaskNotifyWait(0U, 7U, NotNull(), 0U)) + EXPECT_CALL( + _freeRtosMock, + xTaskNotifyWait(0U, 7U, NotNull(), TestBindingMock::WAIT_EVENTS_TICK_COUNT)) .InSequence(seq) - .WillOnce(SetArgPointee<2>(eventMask)); - EXPECT_CALL(_freeRtosMock, xTaskNotifyWait(0U, 7U, NotNull(), 0U)) + .WillOnce(DoAll(SetArgPointee<2>(eventMask), Return(true))); + EXPECT_CALL( + _freeRtosMock, + xTaskNotifyWait(0U, 7U, NotNull(), TestBindingMock::WAIT_EVENTS_TICK_COUNT)) .InSequence(seq) - .WillOnce(SetArgPointee<2>(0U)); + .WillOnce(DoAll(SetArgPointee<2>(0U), StopDispatch(&cut), Return(false))); EXPECT_CALL(_runnableMock1, execute()); - cut.dispatchWhileWork(); - Mock::VerifyAndClearExpectations(&_runnableMock1); - } -} - -/** - * \refs: SMD_asyncFreeRtos_TaskContextAsyncApi - * \desc: To test timeout functionality - */ -TEST_F(TaskContextTest, testSetTimeout) -{ - TaskContext cut; - EXPECT_CALL( - _freeRtosMock, xTaskCreateStatic(NotNull(), _name, 100, NotNull(), 12U, _stack, &_task)) - .WillOnce(Return(&_taskHandle)); - cut.createTask(1U, _task, _name, 12U, _stack, TaskContext::TaskFunctionType()); - { + // trigger shutdown on next iteration EXPECT_CALL(_bindingMock, getHigherPriorityTaskWokenFunc()) .WillOnce(Return(static_cast(0L))); - uint32_t eventMask = 0U; - // set timeout may be called with 0 value and should immediately set event EXPECT_CALL(_freeRtosMock, xTaskNotify(&_taskHandle, _, eSetBits)) + .InSequence(seq) .WillOnce(SaveArg<1>(&eventMask)); - cut.setTimeout(0U); - EXPECT_TRUE(eventMask != 0U); + EXPECT_CALL( + _freeRtosMock, + xTaskNotifyWait(0U, 7U, NotNull(), TestBindingMock::WAIT_EVENTS_TICK_COUNT)) + .InSequence(seq) + .WillOnce(DoAll(CopyArgPointee2(&eventMask), Return(true))); + osTaskFunction(&cut); + Mock::VerifyAndClearExpectations(&_runnableMock1); } } @@ -229,44 +223,16 @@ TEST_F(TaskContextTest, testSetTimeout) TEST_F(TaskContextTest, testSchedule) { TaskContext cut; + TaskFunction_t* osTaskFunction = 0L; EXPECT_CALL( _freeRtosMock, xTaskCreateStatic(NotNull(), _name, 100, NotNull(), 12U, _stack, &_task)) - .WillOnce(Return(&_taskHandle)); + .WillOnce(DoAll(SaveArg<0>(&osTaskFunction), Return(&_taskHandle))); cut.createTask(1U, _task, _name, 12U, _stack, TaskContext::TaskFunctionType()); - void* timerId = 0L; - TimerCallbackFunction_t callbackFunction = 0L; - EXPECT_CALL(_freeRtosMock, xTimerCreateStatic(_name, 1U, 0U, _, NotNull(), &_timer)) - .WillOnce( - DoAll(SaveArg<3>(&timerId), SaveArg<4>(&callbackFunction), Return(&_timerHandle))); - cut.createTimer(_timer, _name); - // now trigger timer the first time - EXPECT_CALL(_freeRtosMock, pvTimerGetTimerID(&_timerHandle)).WillRepeatedly(Return(timerId)); - { - // expect task notify - uint32_t eventMask = 0U; - EXPECT_CALL(_bindingMock, getHigherPriorityTaskWokenFunc()) - .WillOnce(Return(static_cast(0L))); - EXPECT_CALL(_freeRtosMock, xTaskNotify(&_taskHandle, _, eSetBits)) - .WillOnce(SaveArg<1>(&eventMask)); - callbackFunction(&_timerHandle); - // set timer EXPECT_CALL(_systemTimerMock, getSystemTimeUs32Bit()).WillRepeatedly(Return(100000U)); - // dispatch and expect system time. Nothing should happen - Sequence seq; - EXPECT_CALL(_freeRtosMock, xTaskNotifyWait(0U, 7U, NotNull(), 0U)) - .InSequence(seq) - .WillOnce(SetArgPointee<2>(eventMask)); - EXPECT_CALL(_freeRtosMock, xTaskNotifyWait(0U, 7U, NotNull(), 0U)) - .InSequence(seq) - .WillOnce(SetArgPointee<2>(0U)); - cut.dispatchWhileWork(); - } - - { // Schedule first timer. Expect task notify uint32_t eventMask = 0U; EXPECT_CALL(_bindingMock, getHigherPriorityTaskWokenFunc()) @@ -280,50 +246,60 @@ TEST_F(TaskContextTest, testSchedule) // Schedule second timer (to elapse laster). No task notify expected cut.schedule(_runnableMock2, _timeout2, 151U, TimeUnit::MILLISECONDS); + // Cancel the second timer, nothing should happen. + cut.cancel(_timeout2); { - // timer expires too early - EXPECT_CALL(_systemTimerMock, getSystemTimeUs32Bit()).WillRepeatedly(Return(249000U)); + // an event with an active timer will lead to a different timeout + Sequence seq; + EXPECT_CALL(_freeRtosMock, xTaskNotifyWait(0U, 7U, NotNull(), 1500U)) + .InSequence(seq) + .WillOnce(DoAll(SetArgPointee<2>(eventMask), Return(true))); + EXPECT_CALL(_freeRtosMock, xTaskNotifyWait(0U, 7U, NotNull(), 1500U)) + .InSequence(seq) + .WillOnce(DoAll(SetArgPointee<2>(0U), StopDispatch(&cut), Return(false))); + // trigger shutdown on next iteration EXPECT_CALL(_bindingMock, getHigherPriorityTaskWokenFunc()) .WillOnce(Return(static_cast(0L))); EXPECT_CALL(_freeRtosMock, xTaskNotify(&_taskHandle, _, eSetBits)) + .InSequence(seq) .WillOnce(SaveArg<1>(&eventMask)); - callbackFunction(&_timerHandle); - - // Cancel the second timer, nothing should happen. - cut.cancel(_timeout2); + EXPECT_CALL(_freeRtosMock, xTaskNotifyWait(0U, 7U, NotNull(), 1500U)) + .InSequence(seq) + .WillOnce(DoAll(CopyArgPointee2(&eventMask), Return(true))); + osTaskFunction(&cut); + Mock::VerifyAndClearExpectations(&_systemTimerMock); + } + { + // some time has elapsed and OS timer expires a bit too early + // which leads to a new setup of the timer. + // The timer then elapses after second iteration + EXPECT_CALL(_systemTimerMock, getSystemTimeUs32Bit()) + .WillOnce(Return(249000U)) + .WillRepeatedly(Return(250000U)); Sequence seq; - EXPECT_CALL(_freeRtosMock, xTaskNotifyWait(0U, 7U, NotNull(), 0U)) + EXPECT_CALL(_freeRtosMock, xTaskNotifyWait(0U, 7U, NotNull(), 10U)) .InSequence(seq) - .WillOnce(SetArgPointee<2>(eventMask)); - EXPECT_CALL(_freeRtosMock, xTimerChangePeriod(&_timerHandle, 10U, 0U)); - EXPECT_CALL(_freeRtosMock, xTaskNotifyWait(0U, 7U, NotNull(), 0U)) + .WillOnce(DoAll(SetArgPointee<2>(0), Return(false))); + EXPECT_CALL(_runnableMock1, execute()).InSequence(seq); + EXPECT_CALL( + _freeRtosMock, + xTaskNotifyWait(0U, 7U, NotNull(), TestBindingMock::WAIT_EVENTS_TICK_COUNT)) .InSequence(seq) - .WillOnce(SetArgPointee<2>(0U)); - cut.dispatchWhileWork(); - } - - { - // timer expires at correct time + .WillOnce(DoAll(SetArgPointee<2>(0U), StopDispatch(&cut), Return(false))); + // trigger shutdown on next iteration EXPECT_CALL(_bindingMock, getHigherPriorityTaskWokenFunc()) .WillOnce(Return(static_cast(0L))); EXPECT_CALL(_freeRtosMock, xTaskNotify(&_taskHandle, _, eSetBits)) - .WillOnce(SaveArg<1>(&eventMask)); - callbackFunction(&_timerHandle); - - // Expect expired - EXPECT_CALL(_systemTimerMock, getSystemTimeUs32Bit()).WillRepeatedly(Return(250000U)); - - Sequence seq; - EXPECT_CALL(_freeRtosMock, xTaskNotifyWait(0U, 7U, NotNull(), 0U)) .InSequence(seq) - .WillOnce(SetArgPointee<2>(eventMask)); - EXPECT_CALL(_runnableMock1, execute()); - EXPECT_CALL(_freeRtosMock, xTaskNotifyWait(0U, 7U, NotNull(), 0U)) + .WillOnce(SaveArg<1>(&eventMask)); + EXPECT_CALL( + _freeRtosMock, + xTaskNotifyWait(0U, 7U, NotNull(), TestBindingMock::WAIT_EVENTS_TICK_COUNT)) .InSequence(seq) - .WillOnce(SetArgPointee<2>(0U)); - cut.dispatchWhileWork(); + .WillOnce(DoAll(CopyArgPointee2(&eventMask), Return(true))); + osTaskFunction(&cut); } } } @@ -335,125 +311,207 @@ TEST_F(TaskContextTest, testSchedule) TEST_F(TaskContextTest, testScheduleAtFixedRate) { TaskContext cut; + TaskFunction_t* osTaskFunction = 0L; EXPECT_CALL( _freeRtosMock, xTaskCreateStatic(NotNull(), _name, 100, NotNull(), 12U, _stack, &_task)) - .WillOnce(Return(&_taskHandle)); + .WillOnce(DoAll(SaveArg<0>(&osTaskFunction), Return(&_taskHandle))); cut.createTask(1U, _task, _name, 12U, _stack, TaskContext::TaskFunctionType()); - void* timerId = 0L; - TimerCallbackFunction_t callbackFunction = 0L; - EXPECT_CALL(_freeRtosMock, xTimerCreateStatic(_name, 1U, 0U, _, NotNull(), &_timer)) - .WillOnce( - DoAll(SaveArg<3>(&timerId), SaveArg<4>(&callbackFunction), Return(&_timerHandle))); - cut.createTimer(_timer, _name); - // now trigger timer the first time - EXPECT_CALL(_freeRtosMock, pvTimerGetTimerID(&_timerHandle)).WillRepeatedly(Return(timerId)); - { - // expect task notify - uint32_t eventMask = 0U; - EXPECT_CALL(_bindingMock, getHigherPriorityTaskWokenFunc()) - .WillOnce(Return(static_cast(0L))); - EXPECT_CALL(_freeRtosMock, xTaskNotify(&_taskHandle, _, eSetBits)) - .WillOnce(SaveArg<1>(&eventMask)); - callbackFunction(&_timerHandle); - // set timer EXPECT_CALL(_systemTimerMock, getSystemTimeUs32Bit()).WillRepeatedly(Return(100000U)); - // dispatch and expect system time. Nothing should happen - Sequence seq; - EXPECT_CALL(_freeRtosMock, xTaskNotifyWait(0U, 7U, NotNull(), 0U)) - .InSequence(seq) - .WillOnce(SetArgPointee<2>(eventMask)); - EXPECT_CALL(_freeRtosMock, xTaskNotifyWait(0U, 7U, NotNull(), 0U)) - .InSequence(seq) - .WillOnce(SetArgPointee<2>(0U)); - cut.dispatchWhileWork(); - } - - { // Schedule first timer at fixed rate. Expect task notify uint32_t eventMask = 0U; EXPECT_CALL(_bindingMock, getHigherPriorityTaskWokenFunc()) .WillOnce(Return(static_cast(0L))); EXPECT_CALL(_freeRtosMock, xTaskNotify(&_taskHandle, _, eSetBits)) .WillOnce(SaveArg<1>(&eventMask)); - cut.scheduleAtFixedRate(_runnableMock1, _timeout1, 10U, TimeUnit::MILLISECONDS); + cut.scheduleAtFixedRate(_runnableMock1, _timeout1, 20U, TimeUnit::MILLISECONDS); + + // Schedule second timer (to elapse laster). No task notify expected + cut.scheduleAtFixedRate(_runnableMock2, _timeout2, 151U, TimeUnit::MILLISECONDS); + // Cancel the second timer, nothing should happen. + cut.cancel(_timeout2); + Mock::VerifyAndClearExpectations(&_freeRtosMock); { - EXPECT_CALL(_freeRtosMock, pvTimerGetTimerID(&_timerHandle)) - .WillRepeatedly(Return(timerId)); // expect nothing if scheduled again cut.scheduleAtFixedRate(_runnableMock1, _timeout1, 10U, TimeUnit::MILLISECONDS); Mock::VerifyAndClearExpectations(&_freeRtosMock); } { - EXPECT_CALL(_freeRtosMock, pvTimerGetTimerID(&_timerHandle)) - .WillRepeatedly(Return(timerId)); + // the event is received and nothing should happen while no time is elapsed Sequence seq; - EXPECT_CALL(_freeRtosMock, xTaskNotifyWait(0U, 7U, NotNull(), 0U)) + EXPECT_CALL(_freeRtosMock, xTaskNotifyWait(0U, 7U, NotNull(), 200U)) + .InSequence(seq) + .WillOnce(DoAll(SetArgPointee<2>(eventMask), Return(true))); + EXPECT_CALL(_freeRtosMock, xTaskNotifyWait(0U, 7U, NotNull(), 200U)) + .InSequence(seq) + .WillOnce(DoAll(SetArgPointee<2>(0U), StopDispatch(&cut), Return(false))); + // trigger shutdown on next iteration + EXPECT_CALL(_bindingMock, getHigherPriorityTaskWokenFunc()) + .WillOnce(Return(static_cast(0L))); + EXPECT_CALL(_freeRtosMock, xTaskNotify(&_taskHandle, _, eSetBits)) .InSequence(seq) - .WillOnce(SetArgPointee<2>(eventMask)); - EXPECT_CALL(_freeRtosMock, xTimerChangePeriod(&_timerHandle, 100U, 0U)); - EXPECT_CALL(_freeRtosMock, xTaskNotifyWait(0U, 7U, NotNull(), 0U)) + .WillOnce(SaveArg<1>(&eventMask)); + EXPECT_CALL(_freeRtosMock, xTaskNotifyWait(0U, 7U, NotNull(), 200U)) .InSequence(seq) - .WillOnce(SetArgPointee<2>(0U)); - cut.dispatchWhileWork(); + .WillOnce(DoAll(CopyArgPointee2(&eventMask), Return(true))); + osTaskFunction(&cut); Mock::VerifyAndClearExpectations(&_freeRtosMock); } - { - EXPECT_CALL(_freeRtosMock, pvTimerGetTimerID(&_timerHandle)) - .WillRepeatedly(Return(timerId)); - // timer expires at correct time + // time has elapsed and the timer should expire and lead to the next iteration + // with the same timeout + EXPECT_CALL(_systemTimerMock, getSystemTimeUs32Bit()) + .WillOnce(Return(105000U)) + .WillOnce(Return(120000U)) + .WillOnce(Return(120000U)) + .WillOnce(Return(120000U)) + .WillRepeatedly(Return(140000U)); + + Sequence seq; + EXPECT_CALL(_freeRtosMock, xTaskNotifyWait(0U, 7U, NotNull(), 150U)) + .InSequence(seq) + .WillOnce(DoAll(SetArgPointee<2>(0), Return(false))); + EXPECT_CALL(_runnableMock1, execute()).InSequence(seq); + EXPECT_CALL(_freeRtosMock, xTaskNotifyWait(0U, 7U, NotNull(), 200U)) + .InSequence(seq) + .WillOnce(DoAll(SetArgPointee<2>(0), Return(false))); + EXPECT_CALL(_runnableMock1, execute()).InSequence(seq); + EXPECT_CALL(_freeRtosMock, xTaskNotifyWait(0U, 7U, NotNull(), 200U)) + .InSequence(seq) + .WillOnce(DoAll(SetArgPointee<2>(0U), StopDispatch(&cut), Return(false))); + // trigger shutdown on next iteration EXPECT_CALL(_bindingMock, getHigherPriorityTaskWokenFunc()) .WillOnce(Return(static_cast(0L))); EXPECT_CALL(_freeRtosMock, xTaskNotify(&_taskHandle, _, eSetBits)) + .InSequence(seq) .WillOnce(SaveArg<1>(&eventMask)); - callbackFunction(&_timerHandle); + EXPECT_CALL(_freeRtosMock, xTaskNotifyWait(0U, 7U, NotNull(), 200U)) + .InSequence(seq) + .WillOnce(DoAll(CopyArgPointee2(&eventMask), Return(true))); + osTaskFunction(&cut); + } + } +} + +/** + * \refs: SMD_asyncFreeRtos_TaskContextAsyncApi + * \desc: To test task schedule at fixedrate functionality with multiple timers + */ +TEST_F(TaskContextTest, testScheduleAtFixedRateMultipleTimers) +{ + TaskContext cut; + TaskFunction_t* osTaskFunction = 0L; + EXPECT_CALL( + _freeRtosMock, xTaskCreateStatic(NotNull(), _name, 100, NotNull(), 12U, _stack, &_task)) + .WillOnce(DoAll(SaveArg<0>(&osTaskFunction), Return(&_taskHandle))); + cut.createTask(1U, _task, _name, 12U, _stack, TaskContext::TaskFunctionType()); + + { + // set timer + EXPECT_CALL(_systemTimerMock, getSystemTimeUs32Bit()).WillRepeatedly(Return(100000U)); - // Expect expired - EXPECT_CALL(_systemTimerMock, getSystemTimeUs32Bit()).WillRepeatedly(Return(110000U)); + // Schedule first timer at fixed rate. Expect task notify + uint32_t eventMask = 0U; + EXPECT_CALL(_bindingMock, getHigherPriorityTaskWokenFunc()) + .WillOnce(Return(static_cast(0L))); + EXPECT_CALL(_freeRtosMock, xTaskNotify(&_taskHandle, _, eSetBits)) + .WillOnce(SaveArg<1>(&eventMask)); + cut.scheduleAtFixedRate(_runnableMock1, _timeout1, 20U, TimeUnit::MILLISECONDS); + Mock::VerifyAndClearExpectations(&_freeRtosMock); + // Schedule second timer at fixed rate. Expect task notify again because it changes the next + // timeout + EXPECT_CALL(_bindingMock, getHigherPriorityTaskWokenFunc()) + .WillOnce(Return(static_cast(0L))); + EXPECT_CALL(_freeRtosMock, xTaskNotify(&_taskHandle, _, eSetBits)) + .WillOnce(SaveArg<1>(&eventMask)); + cut.scheduleAtFixedRate(_runnableMock2, _timeout2, 12U, TimeUnit::MILLISECONDS); + Mock::VerifyAndClearExpectations(&_freeRtosMock); + { + // the second timer should lead to the right expected timeout Sequence seq; - EXPECT_CALL(_freeRtosMock, xTaskNotifyWait(0U, 7U, NotNull(), 0U)) + EXPECT_CALL(_freeRtosMock, xTaskNotifyWait(0U, 7U, NotNull(), 120U)) + .InSequence(seq) + .WillOnce(DoAll(SetArgPointee<2>(eventMask), Return(true))); + EXPECT_CALL(_freeRtosMock, xTaskNotifyWait(0U, 7U, NotNull(), 120U)) + .InSequence(seq) + .WillOnce(DoAll(SetArgPointee<2>(0U), StopDispatch(&cut), Return(true))); + // trigger shutdown on next iteration + EXPECT_CALL(_bindingMock, getHigherPriorityTaskWokenFunc()) + .WillOnce(Return(static_cast(0L))); + EXPECT_CALL(_freeRtosMock, xTaskNotify(&_taskHandle, _, eSetBits)) .InSequence(seq) - .WillOnce(SetArgPointee<2>(eventMask)); - EXPECT_CALL(_runnableMock1, execute()); - EXPECT_CALL(_freeRtosMock, xTimerChangePeriod(&_timerHandle, 100U, 0U)); - EXPECT_CALL(_freeRtosMock, xTaskNotifyWait(0U, 7U, NotNull(), 0U)) + .WillOnce(SaveArg<1>(&eventMask)); + EXPECT_CALL(_freeRtosMock, xTaskNotifyWait(0U, 7U, NotNull(), 120U)) .InSequence(seq) - .WillOnce(SetArgPointee<2>(0U)); - cut.dispatchWhileWork(); + .WillOnce(DoAll(CopyArgPointee2(&eventMask), Return(true))); + osTaskFunction(&cut); + Mock::VerifyAndClearExpectations(&_freeRtosMock); } } } /** + * \req: [BSW_ASFR_51], [BSW_ASFR_52], [BSW_ASFR_53] * \refs: SMD_asyncFreeRtos_TaskContextAsyncApi - * \desc: To test task schedule at fixedrate functionality with multiple timers + * \desc: To test dispatchWhileWork function to finish on work done */ -TEST_F(TaskContextTest, testScheduleAtFixedRateMultipleTimers) +TEST_F(TaskContextTest, testDispatchWhileWork) { TaskContext cut; - void* timerId = 0L; + TaskFunction_t* osTaskFunction = 0L; + EXPECT_CALL( + _freeRtosMock, xTaskCreateStatic(NotNull(), _name, 100, NotNull(), 12U, _stack, &_task)) + .WillOnce(DoAll(SaveArg<0>(&osTaskFunction), Return(&_taskHandle))); + cut.createTask(1U, _task, _name, 12U, _stack, TaskContext::TaskFunctionType()); - // set timer - EXPECT_CALL(_systemTimerMock, getSystemTimeUs32Bit()).WillRepeatedly(Return(100000U)); + { + // set timer + EXPECT_CALL(_systemTimerMock, getSystemTimeUs32Bit()).WillOnce(Return(100000U)); - EXPECT_CALL(_freeRtosMock, pvTimerGetTimerID(&_timerHandle)).WillRepeatedly(Return(timerId)); - EXPECT_CALL(_bindingMock, getHigherPriorityTaskWokenFunc()) - .WillOnce(Return(static_cast(0L))); - EXPECT_CALL(_freeRtosMock, xTaskNotify(_, _, eSetBits)).Times(1); - cut.scheduleAtFixedRate(_runnableMock1, _timeout1, 10U, TimeUnit::MILLISECONDS); - Mock::VerifyAndClearExpectations(&_freeRtosMock); + // Schedule timer at fixed rate. Expect task notify + uint32_t eventMask1 = 0U; + EXPECT_CALL(_bindingMock, getHigherPriorityTaskWokenFunc()) + .WillOnce(Return(static_cast(0L))); + EXPECT_CALL(_freeRtosMock, xTaskNotify(&_taskHandle, _, eSetBits)) + .WillOnce(SaveArg<1>(&eventMask1)); + cut.schedule(_runnableMock1, _timeout1, 20U, TimeUnit::MILLISECONDS); + Mock::VerifyAndClearExpectations(&_freeRtosMock); + Mock::VerifyAndClearExpectations(&_systemTimerMock); - // another task that expires later - cut.scheduleAtFixedRate(_runnableMock2, _timeout2, 20U, TimeUnit::MILLISECONDS); - Mock::VerifyAndClearExpectations(&_freeRtosMock); + // Execute a task + uint32_t eventMask2 = 0U; + EXPECT_CALL(_bindingMock, getHigherPriorityTaskWokenFunc()) + .WillOnce(Return(static_cast(0L))); + EXPECT_CALL(_freeRtosMock, xTaskNotify(&_taskHandle, _, eSetBits)) + .WillOnce(SaveArg<1>(&eventMask2)); + cut.execute(_runnableMock2); + Mock::VerifyAndClearExpectations(&_bindingMock); + Mock::VerifyAndClearExpectations(&_freeRtosMock); + + // time is running during dispatch + EXPECT_CALL(_systemTimerMock, getSystemTimeUs32Bit()) + .WillOnce(Return(110000U)) + .WillOnce(Return(120000U)) + .WillOnce(Return(120010U)) + .WillOnce(Return(120020U)); + Sequence seq; + EXPECT_CALL(_freeRtosMock, xTaskNotifyWait(0U, 7U, NotNull(), 0U)) + .InSequence(seq) + .WillOnce(DoAll(SetArgPointee<2>((eventMask1 | eventMask2)), Return(true))); + EXPECT_CALL(_runnableMock2, execute()).InSequence(seq); + EXPECT_CALL(_runnableMock1, execute()).InSequence(seq); + EXPECT_CALL(_freeRtosMock, xTaskNotifyWait(0U, 7U, NotNull(), 0U)) + .InSequence(seq) + .WillOnce(Return(false)); + cut.dispatchWhileWork(); + } } /** diff --git a/libs/bsw/asyncFreeRtos/test/gtest/src/async/TaskInitializerTest.cpp b/libs/bsw/asyncFreeRtos/test/gtest/src/async/TaskInitializerTest.cpp index 12d2f091eb..bf90f3a04b 100644 --- a/libs/bsw/asyncFreeRtos/test/gtest/src/async/TaskInitializerTest.cpp +++ b/libs/bsw/asyncFreeRtos/test/gtest/src/async/TaskInitializerTest.cpp @@ -17,7 +17,6 @@ struct AdapterMock : public ::estd::singleton using StackSliceType = ::estd::slice; using TaskFunctionType = ::estd::function; using TaskObjectType = uint32_t*; - using TimerObjectType = uint32_t*; using TaskConfigType = uint32_t; AdapterMock() : ::estd::singleton(*this) {} @@ -39,11 +38,10 @@ struct TaskInitializerData { Cut::StackSliceType _stack; Cut::TaskFunctionType _taskFunction; - Cut::TaskObjectType* _task = nullptr; - Cut::TimerObjectType* _timer = nullptr; - char const* _name = nullptr; - ContextType _context = CONTEXT_INVALID; - Cut::TaskConfigType _config = 0U; + Cut::TaskObjectType* _task = nullptr; + char const* _name = nullptr; + ContextType _context = CONTEXT_INVALID; + Cut::TaskConfigType _config = 0U; }; struct TaskInitializerTest : public Test @@ -61,7 +59,6 @@ ACTION_P(CopyTaskInitializerData, dest) dest->_stack = arg0._stack; dest->_taskFunction = arg0._taskFunction; dest->_task = &arg0._task; - dest->_timer = &arg0._timer; dest->_name = arg0._name; dest->_context = arg0._context; dest->_config = arg0._config; @@ -85,7 +82,6 @@ TEST_F(TaskInitializerTest, testIdleTask) EXPECT_EQ(256, data._stack.size() * sizeof(StackType_t)); EXPECT_EQ(_taskFunction, data._taskFunction); EXPECT_TRUE(data._task != nullptr); - EXPECT_TRUE(data._timer != nullptr); EXPECT_EQ(ContextType(AdapterMock::TASK_IDLE), data._context); EXPECT_EQ(7U, data._config); Mock::VerifyAndClearExpectations(&_adapterMock); @@ -104,7 +100,6 @@ TEST_F(TaskInitializerTest, testIdleTask) EXPECT_EQ(sizeof(stack), data._stack.size() * sizeof(StackType_t)); EXPECT_EQ(_taskFunction, data._taskFunction); EXPECT_TRUE(data._task != nullptr); - EXPECT_TRUE(data._timer != nullptr); EXPECT_EQ(ContextType(AdapterMock::TASK_IDLE), data._context); EXPECT_EQ(7U, data._config); Mock::VerifyAndClearExpectations(&_adapterMock); @@ -129,7 +124,6 @@ TEST_F(TaskInitializerTest, testTimerTask) EXPECT_EQ(512, data._stack.size() * sizeof(StackType_t)); EXPECT_EQ(AdapterMock::TaskFunctionType(), data._taskFunction); EXPECT_TRUE(data._task != nullptr); - EXPECT_TRUE(data._timer != nullptr); EXPECT_EQ(ContextType(AdapterMock::TASK_TIMER), data._context); EXPECT_EQ(9U, data._config); Mock::VerifyAndClearExpectations(&_adapterMock); @@ -148,7 +142,6 @@ TEST_F(TaskInitializerTest, testTimerTask) EXPECT_EQ(sizeof(stack), data._stack.size() * sizeof(StackType_t)); EXPECT_EQ(AdapterMock::TaskFunctionType(), data._taskFunction); EXPECT_TRUE(data._task != nullptr); - EXPECT_TRUE(data._timer != nullptr); EXPECT_EQ(ContextType(AdapterMock::TASK_TIMER), data._context); EXPECT_EQ(8U, data._config); Mock::VerifyAndClearExpectations(&_adapterMock); @@ -173,7 +166,6 @@ TEST_F(TaskInitializerTest, testTask) EXPECT_EQ(512, data._stack.size() * sizeof(StackType_t)); EXPECT_EQ(AdapterMock::TaskFunctionType(), data._taskFunction); EXPECT_TRUE(data._task != nullptr); - EXPECT_TRUE(data._timer != nullptr); EXPECT_EQ(5U, data._context); EXPECT_EQ(9U, data._config); Mock::VerifyAndClearExpectations(&_adapterMock); @@ -192,7 +184,6 @@ TEST_F(TaskInitializerTest, testTask) EXPECT_EQ(sizeof(stack), data._stack.size() * sizeof(StackType_t)); EXPECT_EQ(AdapterMock::TaskFunctionType(), data._taskFunction); EXPECT_TRUE(data._task != nullptr); - EXPECT_TRUE(data._timer != nullptr); EXPECT_EQ(6U, data._context); EXPECT_EQ(8U, data._config); Mock::VerifyAndClearExpectations(&_adapterMock); @@ -209,7 +200,6 @@ TEST_F(TaskInitializerTest, testTask) EXPECT_EQ(512, data._stack.size() * sizeof(StackType_t)); EXPECT_EQ(_taskFunction, data._taskFunction); EXPECT_TRUE(data._task != nullptr); - EXPECT_TRUE(data._timer != nullptr); EXPECT_EQ(5U, data._context); EXPECT_EQ(9U, data._config); Mock::VerifyAndClearExpectations(&_adapterMock); @@ -228,7 +218,6 @@ TEST_F(TaskInitializerTest, testTask) EXPECT_EQ(sizeof(stack), data._stack.size() * sizeof(StackType_t)); EXPECT_EQ(_taskFunction, data._taskFunction); EXPECT_TRUE(data._task != nullptr); - EXPECT_TRUE(data._timer != nullptr); EXPECT_EQ(6U, data._context); EXPECT_EQ(8U, data._config); Mock::VerifyAndClearExpectations(&_adapterMock); diff --git a/libs/bsw/asyncImpl/include/async/EventPolicy.h b/libs/bsw/asyncImpl/include/async/EventPolicy.h index 16823eaabb..bc37837d37 100644 --- a/libs/bsw/asyncImpl/include/async/EventPolicy.h +++ b/libs/bsw/asyncImpl/include/async/EventPolicy.h @@ -24,6 +24,8 @@ class EventPolicy using EventDispatcherType = EventDispatcher; using HandlerFunctionType = typename EventDispatcher::HandlerFunctionType; + static EventMaskType const EVENT_MASK = static_cast(1U << Event); + explicit EventPolicy(EventDispatcher& eventDispatcher); void setEventHandler(HandlerFunctionType handlerFunction); @@ -32,8 +34,6 @@ class EventPolicy void setEvent(); private: - static EventMaskType const _eventMask = static_cast(1U << Event); - EventDispatcher& _eventDispatcher; }; @@ -61,7 +61,7 @@ inline void EventPolicy::removeEventHandler() template inline void EventPolicy::setEvent() { - _eventDispatcher.setEvents(_eventMask); + _eventDispatcher.setEvents(EVENT_MASK); } } // namespace async