From 75bd97b922e76b2a71e343ea36d4b8a8d0527fad Mon Sep 17 00:00:00 2001 From: Wen Ping Teh Date: Thu, 28 Nov 2024 23:26:09 +0000 Subject: [PATCH 1/4] mod/system_coordinator: Add initial module This patch adds the system coordinator module to the power management framework. The system coordinator is responsible for managing each phase of power management. Each phase is an API call to a module. The phase API and time are configurable elements. Coordinator calls the next phase after the phase timer alarm elapses. The order of the phases follows the element order. A cycle timer alarm periodically notifies the coordinator to call all the phases again. The cycle time is configurable and must be more than the sum of all phase time. Signed-off-by: Wen Ping Teh --- module/CMakeLists.txt | 1 + module/system_coordinator/CMakeLists.txt | 16 + module/system_coordinator/Module.cmake | 9 + .../include/mod_system_coordinator.h | 86 +++++ .../src/mod_system_coordinator.c | 312 ++++++++++++++++++ 5 files changed, 424 insertions(+) create mode 100644 module/system_coordinator/CMakeLists.txt create mode 100644 module/system_coordinator/Module.cmake create mode 100644 module/system_coordinator/include/mod_system_coordinator.h create mode 100644 module/system_coordinator/src/mod_system_coordinator.c diff --git a/module/CMakeLists.txt b/module/CMakeLists.txt index 7bf9460cf..1dea7a541 100644 --- a/module/CMakeLists.txt +++ b/module/CMakeLists.txt @@ -95,6 +95,7 @@ list(APPEND SCP_MODULE_PATHS "${CMAKE_CURRENT_SOURCE_DIR}/sp805") list(APPEND SCP_MODULE_PATHS "${CMAKE_CURRENT_SOURCE_DIR}/ssc") list(APPEND SCP_MODULE_PATHS "${CMAKE_CURRENT_SOURCE_DIR}/statistics") list(APPEND SCP_MODULE_PATHS "${CMAKE_CURRENT_SOURCE_DIR}/stdio") +list(APPEND SCP_MODULE_PATHS "${CMAKE_CURRENT_SOURCE_DIR}/system_coordinator") list(APPEND SCP_MODULE_PATHS "${CMAKE_CURRENT_SOURCE_DIR}/system_info") list(APPEND SCP_MODULE_PATHS "${CMAKE_CURRENT_SOURCE_DIR}/system_pll") list(APPEND SCP_MODULE_PATHS "${CMAKE_CURRENT_SOURCE_DIR}/system_power") diff --git a/module/system_coordinator/CMakeLists.txt b/module/system_coordinator/CMakeLists.txt new file mode 100644 index 000000000..270eb8b6f --- /dev/null +++ b/module/system_coordinator/CMakeLists.txt @@ -0,0 +1,16 @@ +# +# Arm SCP/MCP Software +# Copyright (c) 2024, Arm Limited and Contributors. All rights reserved. +# +# SPDX-License-Identifier: BSD-3-Clause +# + +add_library(${SCP_MODULE_TARGET} SCP_MODULE) + +target_include_directories(${SCP_MODULE_TARGET} + PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/include") + +target_sources(${SCP_MODULE_TARGET} + PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/src/mod_system_coordinator.c") + +target_link_libraries(${SCP_MODULE_TARGET} PRIVATE module-timer) diff --git a/module/system_coordinator/Module.cmake b/module/system_coordinator/Module.cmake new file mode 100644 index 000000000..01ab18be3 --- /dev/null +++ b/module/system_coordinator/Module.cmake @@ -0,0 +1,9 @@ +# +# Arm SCP/MCP Software +# Copyright (c) 2024, Arm Limited and Contributors. All rights reserved. +# +# SPDX-License-Identifier: BSD-3-Clause +# + +set(SCP_MODULE "system-coordinator") +set(SCP_MODULE_TARGET "module-system-coordinator") diff --git a/module/system_coordinator/include/mod_system_coordinator.h b/module/system_coordinator/include/mod_system_coordinator.h new file mode 100644 index 000000000..b8c300c40 --- /dev/null +++ b/module/system_coordinator/include/mod_system_coordinator.h @@ -0,0 +1,86 @@ +/* + * Arm SCP/MCP Software + * Copyright (c) 2024, Arm Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef MOD_SYSTEM_COORDINATOR_H +#define MOD_SYSTEM_COORDINATOR_H + +#include + +/*! + * \addtogroup GroupModules Modules + * \{ + */ + +/*! + * \defgroup GroupSystemCoordinator System Coordinator + * \{ + */ + +/*! + * \brief System Coordinator Phase API + * + * \details API interface for System Coordinator to call each phase. + */ +struct mod_system_coordinator_phase_api { + /*! + * \brief API interface to phase module + * + * \retval ::FWK_SUCCESS The operation succeeded. + * \retval ::Standard framework status codes. + */ + int (*phase_handler)(void); +}; + +/*! + * \brief System Coordinator phase config + */ +struct mod_system_coordinator_phase_config { + /*! + * ID of the phase module. + */ + const fwk_id_t module_id; + + /*! + * ID of the phase API. + */ + const fwk_id_t api_id; + + /*! + * \brief Phase time in microseconds + */ + uint32_t phase_us; +}; + +/*! + * \brief System Coordinator module configuration + */ +struct mod_system_coordinator_config { + /*! + * \brief Identifier of alarm for System Coordinator cycle + */ + fwk_id_t cycle_alarm_id; + + /*! + * \brief Identifier of alarm for System Coordinator phase + */ + fwk_id_t phase_alarm_id; + + /*! + * \brief Cycle time in microseconds + */ + uint32_t cycle_us; +}; + +/*! + * \} + */ + +/*! + * \} + */ + +#endif /* MOD_SYSTEM_COORDINATOR_H */ diff --git a/module/system_coordinator/src/mod_system_coordinator.c b/module/system_coordinator/src/mod_system_coordinator.c new file mode 100644 index 000000000..bda1b7636 --- /dev/null +++ b/module/system_coordinator/src/mod_system_coordinator.c @@ -0,0 +1,312 @@ +/* + * Arm SCP/MCP Software + * Copyright (c) 2024, Arm Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include "mod_system_coordinator.h" + +#include + +#include +#include +#include +#include +#include +#include + +#include + +#define MOD_NAME "[SYS_COORDINATOR] " +#define FIRST_PHASE_INDEX 0 + +enum mod_system_coordinator_event_idx { + MOD_SYSTEM_COORDINATOR_EVENT_IDX_PHASE, + MOD_SYSTEM_COORDINATOR_EVENT_IDX_COUNT, +}; + +/* Phase context */ +struct mod_system_coordinator_phase_ctx { + /* Phase configuration */ + const struct mod_system_coordinator_phase_config *phase_config; + + /* Phase API */ + struct mod_system_coordinator_phase_api *phase_api; +}; + +/* Module context */ +struct mod_system_coordinator_ctx { + /* System Coordinator configuration */ + const struct mod_system_coordinator_config *config; + + /* Phase context */ + struct mod_system_coordinator_phase_ctx *phase_ctx; + + /* Cycle alarm API */ + const struct mod_timer_alarm_api *cycle_alarm_api; + + /* Phase alarm API */ + const struct mod_timer_alarm_api *phase_alarm_api; + + /* Total phase count */ + uint32_t phase_count; +}; + +static const fwk_id_t mod_system_coordinator_event_phase = FWK_ID_EVENT_INIT( + FWK_MODULE_IDX_SYSTEM_COORDINATOR, + MOD_SYSTEM_COORDINATOR_EVENT_IDX_PHASE); + +static struct mod_system_coordinator_ctx system_coordinator_ctx; + +static int send_phase_event(uint32_t phase_idx) +{ + int status; + + struct fwk_event phase_event = { + .source_id = FWK_ID_MODULE(FWK_MODULE_IDX_SYSTEM_COORDINATOR), + .target_id = fwk_id_build_element_id( + fwk_module_id_system_coordinator, phase_idx), + .id = mod_system_coordinator_event_phase, + }; + + status = fwk_put_event(&phase_event); + if (status != FWK_SUCCESS) { + FWK_LOG_ERR( + MOD_NAME "%s@%" PRIu32 " status=%" PRIu32 ", phase_idx=%" PRIu32 "", + __func__, + __LINE__, + status, + phase_idx); + } + + return status; +} + +/* + * Alarm callback + */ + +static void system_coordinator_cycle_alarm_callback(uintptr_t param) +{ + send_phase_event(FIRST_PHASE_INDEX); +} + +static void system_coordinator_phase_alarm_callback(uintptr_t param) +{ + uint32_t phase_index = (uint32_t)param; + + send_phase_event(phase_index); +} + +static int start_timer_for_next_phase( + const struct mod_system_coordinator_phase_ctx *phase_ctx, + const uint32_t *phase_idx) +{ + return system_coordinator_ctx.phase_alarm_api->start( + system_coordinator_ctx.config->phase_alarm_id, + phase_ctx->phase_config->phase_us, + MOD_TIMER_ALARM_TYPE_ONCE, + system_coordinator_phase_alarm_callback, + (uintptr_t)*phase_idx); + + return FWK_SUCCESS; +} + +static int process_current_phase(uint32_t phase_idx) +{ + int status; + uint32_t next_phase_idx; + struct mod_system_coordinator_phase_ctx *phase_ctx; + + if (phase_idx >= system_coordinator_ctx.phase_count) { + return FWK_E_RANGE; + } + + next_phase_idx = phase_idx + 1; + phase_ctx = &system_coordinator_ctx.phase_ctx[phase_idx]; + + if (phase_ctx->phase_config->phase_us == 0) { + /* Send event to process next phase if current phase timer is 0 */ + status = send_phase_event(next_phase_idx); + } else if (phase_idx < (system_coordinator_ctx.phase_count - 1)) { + /* + * Start timer for next phase. Timer will be skip if the phase is the + * last phase or the phase time value is 0. + */ + status = start_timer_for_next_phase(phase_ctx, &next_phase_idx); + } + + if (status != FWK_SUCCESS) { + return status; + } + + /* Call phase API */ + phase_ctx->phase_api->phase_handler(); + + return FWK_SUCCESS; +} + +/* + * Framework handlers + */ + +static int system_coordinator_init( + fwk_id_t module_id, + unsigned int element_count, + const void *data) +{ + if ((data == NULL) || (element_count == 0U)) { + return FWK_E_PARAM; + } + + system_coordinator_ctx.phase_count = element_count; + system_coordinator_ctx.phase_ctx = fwk_mm_calloc( + element_count, sizeof(struct mod_system_coordinator_phase_ctx)); + system_coordinator_ctx.config = + (const struct mod_system_coordinator_config *)data; + + return FWK_SUCCESS; +} + +static int system_coordinator_element_init( + fwk_id_t element_id, + unsigned int sub_element_count, + const void *data) +{ + if (data == NULL) { + return FWK_E_PARAM; + } + + uint32_t idx; + + idx = fwk_id_get_element_idx(element_id); + if (idx >= system_coordinator_ctx.phase_count) { + return FWK_E_PARAM; + } + + system_coordinator_ctx.phase_ctx[idx].phase_config = + (const struct mod_system_coordinator_phase_config *)data; + + return FWK_SUCCESS; +} + +static int system_coordinator_post_init(fwk_id_t module_id) +{ + uint32_t total_phase_time = 0; + + /* Sum of all phase time is not allowed to be more than cycle time */ + for (uint32_t i = 0; i < system_coordinator_ctx.phase_count; i++) { + total_phase_time += + system_coordinator_ctx.phase_ctx[i].phase_config->phase_us; + } + + if (total_phase_time > system_coordinator_ctx.config->cycle_us) { + return FWK_E_SUPPORT; + } + + return FWK_SUCCESS; +} + +static int system_coordinator_bind(fwk_id_t id, unsigned int round) +{ + int status = FWK_E_INIT; + uint32_t phase_idx; + struct mod_system_coordinator_phase_ctx *phase_ctx; + + /* Only bind in first round of calls. */ + if (round > 0) { + return FWK_SUCCESS; + } + + if (fwk_module_is_valid_module_id(id)) { + /* Cycle alarm */ + status = fwk_module_bind( + system_coordinator_ctx.config->cycle_alarm_id, + MOD_TIMER_API_ID_ALARM, + &system_coordinator_ctx.cycle_alarm_api); + if (status != FWK_SUCCESS) { + FWK_LOG_ERR(MOD_NAME "Error binding to cycle alarm API"); + return status; + } + + /* Phase alarm */ + status = fwk_module_bind( + system_coordinator_ctx.config->phase_alarm_id, + MOD_TIMER_API_ID_ALARM, + &system_coordinator_ctx.phase_alarm_api); + if (status != FWK_SUCCESS) { + FWK_LOG_ERR(MOD_NAME "Error binding to phase alarm API"); + } + } else if (fwk_module_is_valid_element_id(id)) { + phase_idx = fwk_id_get_element_idx(id); + phase_ctx = &system_coordinator_ctx.phase_ctx[phase_idx]; + status = fwk_module_bind( + phase_ctx->phase_config->module_id, + phase_ctx->phase_config->api_id, + &phase_ctx->phase_api); + if (status != FWK_SUCCESS) { + FWK_LOG_ERR( + MOD_NAME "Error binding to phase[%" PRIu32 "] API", phase_idx); + } + } + + return status; +} + +static int system_coordinator_start(fwk_id_t id) +{ + int status; + + if (!fwk_id_is_type(id, FWK_ID_TYPE_MODULE)) { + return FWK_SUCCESS; + } + + /* Start cycle timer */ + status = system_coordinator_ctx.cycle_alarm_api->start( + system_coordinator_ctx.config->cycle_alarm_id, + system_coordinator_ctx.config->cycle_us, + MOD_TIMER_ALARM_TYPE_PERIODIC, + system_coordinator_cycle_alarm_callback, + (uintptr_t)NULL); + if (status != FWK_SUCCESS) { + return status; + } + + /* Start first phase */ + status = process_current_phase(FIRST_PHASE_INDEX); + + return status; +} + +static int system_coordinator_process_event( + const struct fwk_event *event, + struct fwk_event *resp_event) +{ + uint32_t phase_idx; + + phase_idx = fwk_id_get_element_idx(event->target_id); + + /* + * Event from cycle and phase timer callback. Both timer callback send the + * same event. Cycle callback will process the first phase while phase + * callback process the current phase. + */ + if (fwk_id_is_equal(event->id, mod_system_coordinator_event_phase)) { + return process_current_phase(phase_idx); + } + + return FWK_E_PARAM; +} + +/* Module definition */ +const struct fwk_module module_system_coordinator = { + .type = FWK_MODULE_TYPE_SERVICE, + .event_count = (unsigned int)MOD_SYSTEM_COORDINATOR_EVENT_IDX_COUNT, + .init = system_coordinator_init, + .element_init = system_coordinator_element_init, + .post_init = system_coordinator_post_init, + .bind = system_coordinator_bind, + .start = system_coordinator_start, + .process_event = system_coordinator_process_event, +}; -- GitLab From 9749fddc3d967c59256c2accba61319144132214 Mon Sep 17 00:00:00 2001 From: Wen Ping Teh Date: Thu, 28 Nov 2024 23:47:18 +0000 Subject: [PATCH 2/4] mod/system_coordinator/test: Add unit test Add unit test for system coordinator module. Create mock phase and alarm API for the unit test. Signed-off-by: Wen Ping Teh --- module/system_coordinator/test/CMakeLists.txt | 24 ++ .../test/config_system_coordinator.h | 63 +++ .../system_coordinator/test/fwk_module_idx.h | 25 ++ .../test/mocks/.clang-format | 4 + .../mocks/Mockmod_system_coordinator_extra.c | 359 ++++++++++++++++++ .../mocks/Mockmod_system_coordinator_extra.h | 67 ++++ .../test/mod_system_coordinator_extra.h | 27 ++ .../test/mod_system_coordinator_unit_test.c | 343 +++++++++++++++++ unit_test/CMakeLists.txt | 1 + 9 files changed, 913 insertions(+) create mode 100644 module/system_coordinator/test/CMakeLists.txt create mode 100644 module/system_coordinator/test/config_system_coordinator.h create mode 100644 module/system_coordinator/test/fwk_module_idx.h create mode 100644 module/system_coordinator/test/mocks/.clang-format create mode 100644 module/system_coordinator/test/mocks/Mockmod_system_coordinator_extra.c create mode 100644 module/system_coordinator/test/mocks/Mockmod_system_coordinator_extra.h create mode 100644 module/system_coordinator/test/mod_system_coordinator_extra.h create mode 100644 module/system_coordinator/test/mod_system_coordinator_unit_test.c diff --git a/module/system_coordinator/test/CMakeLists.txt b/module/system_coordinator/test/CMakeLists.txt new file mode 100644 index 000000000..630108997 --- /dev/null +++ b/module/system_coordinator/test/CMakeLists.txt @@ -0,0 +1,24 @@ +# +# Arm SCP/MCP Software +# Copyright (c) 2024, Arm Limited and Contributors. All rights reserved. +# +# SPDX-License-Identifier: BSD-3-Clause +# + +set(TEST_SRC mod_system_coordinator) +set(TEST_FILE mod_system_coordinator) + +set(UNIT_TEST_TARGET mod_${TEST_MODULE}_unit_test) + +set(MODULE_SRC ${MODULE_ROOT}/${TEST_MODULE}/src) +set(MODULE_INC ${MODULE_ROOT}/${TEST_MODULE}/include) +list(APPEND OTHER_MODULE_INC ${MODULE_ROOT}/timer/include) +set(MODULE_UT_SRC ${CMAKE_CURRENT_LIST_DIR}) +set(MODULE_UT_INC ${CMAKE_CURRENT_LIST_DIR}) +set(MODULE_UT_MOCK_SRC ${CMAKE_CURRENT_LIST_DIR}/mocks) + +list(APPEND MOCK_REPLACEMENTS fwk_core) +list(APPEND MOCK_REPLACEMENTS fwk_mm) +list(APPEND MOCK_REPLACEMENTS fwk_module) + +include(${SCP_ROOT}/unit_test/module_common.cmake) diff --git a/module/system_coordinator/test/config_system_coordinator.h b/module/system_coordinator/test/config_system_coordinator.h new file mode 100644 index 000000000..caacd1fb2 --- /dev/null +++ b/module/system_coordinator/test/config_system_coordinator.h @@ -0,0 +1,63 @@ +/* + * Arm SCP/MCP Software + * Copyright (c) 2024, Arm Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include + +#include +#include +#include + +enum phase_idx { + SYS_COOR_PHASE_ONE, + SYS_COOR_PHASE_TWO, + SYS_COOR_PHASE_THREE, + SYS_COOR_PHASE_COUNT, +}; + +#define PHASE_ONE_TIME 2000 +#define PHASE_TWO_TIME 0 +#define PHASE_THREE_TIME 3000 +#define COORDINATOR_CYCLE_TIME 10000 + +static const struct fwk_element phase_config[] = { + [SYS_COOR_PHASE_ONE] = { + .name = "PHASE_ONE", + .data = &(const struct mod_system_coordinator_phase_config) { + .module_id = FWK_ID_MODULE_INIT(FWK_MODULE_IDX_PHASE_ONE), + .api_id = FWK_ID_API_INIT(FWK_MODULE_IDX_PHASE_ONE, 0), + .phase_us = PHASE_ONE_TIME, + }, + }, + [SYS_COOR_PHASE_TWO] = { + .name = "PHASE_TWO", + .data = &(const struct mod_system_coordinator_phase_config) { + .module_id = FWK_ID_MODULE_INIT(FWK_MODULE_IDX_PHASE_TWO), + .api_id = FWK_ID_API_INIT(FWK_MODULE_IDX_PHASE_TWO, 0), + .phase_us = PHASE_TWO_TIME, + }, + }, + [SYS_COOR_PHASE_THREE] = { + .name = "PHASE_THREE", + .data = &(const struct mod_system_coordinator_phase_config) { + .module_id = FWK_ID_MODULE_INIT(FWK_MODULE_IDX_PHASE_THREE), + .api_id = FWK_ID_API_INIT(FWK_MODULE_IDX_PHASE_THREE, 0), + .phase_us = PHASE_THREE_TIME, + }, + }, + [SYS_COOR_PHASE_COUNT] = { 0 }, +}; + +struct mod_system_coordinator_config system_coordinator_config = { + .cycle_alarm_id = FWK_ID_SUB_ELEMENT_INIT(FWK_MODULE_IDX_TIMER, 0, 0), + .phase_alarm_id = FWK_ID_SUB_ELEMENT_INIT(FWK_MODULE_IDX_TIMER, 0, 0), + .cycle_us = COORDINATOR_CYCLE_TIME +}; + +struct fwk_module_config module_config = { + .data = &system_coordinator_config, + .elements = FWK_MODULE_STATIC_ELEMENTS_PTR(phase_config), +}; diff --git a/module/system_coordinator/test/fwk_module_idx.h b/module/system_coordinator/test/fwk_module_idx.h new file mode 100644 index 000000000..2e3cb4e3e --- /dev/null +++ b/module/system_coordinator/test/fwk_module_idx.h @@ -0,0 +1,25 @@ +/* + * Arm SCP/MCP Software + * Copyright (c) 2024, Arm Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef TEST_FWK_MODULE_MODULE_IDX_H +#define TEST_FWK_MODULE_MODULE_IDX_H + +#include + +enum fwk_module_idx { + FWK_MODULE_IDX_SYSTEM_COORDINATOR, + FWK_MODULE_IDX_TIMER, + FWK_MODULE_IDX_PHASE_ONE, + FWK_MODULE_IDX_PHASE_TWO, + FWK_MODULE_IDX_PHASE_THREE, + FWK_MODULE_IDX_COUNT, +}; + +static const fwk_id_t fwk_module_id_system_coordinator = + FWK_ID_MODULE_INIT(FWK_MODULE_IDX_SYSTEM_COORDINATOR); + +#endif /* TEST_FWK_MODULE_MODULE_IDX_H */ diff --git a/module/system_coordinator/test/mocks/.clang-format b/module/system_coordinator/test/mocks/.clang-format new file mode 100644 index 000000000..eeca2395f --- /dev/null +++ b/module/system_coordinator/test/mocks/.clang-format @@ -0,0 +1,4 @@ +{ + "DisableFormat": true, + "SortIncludes": false, +} diff --git a/module/system_coordinator/test/mocks/Mockmod_system_coordinator_extra.c b/module/system_coordinator/test/mocks/Mockmod_system_coordinator_extra.c new file mode 100644 index 000000000..c73f462ee --- /dev/null +++ b/module/system_coordinator/test/mocks/Mockmod_system_coordinator_extra.c @@ -0,0 +1,359 @@ +/* AUTOGENERATED FILE. DO NOT EDIT. */ +#include +#include +#include +#include "cmock.h" +#include "Mockmod_system_coordinator_extra.h" + +static const char* CMockString_alarm_id = "alarm_id"; +static const char* CMockString_callback = "callback"; +static const char* CMockString_microseconds = "microseconds"; +static const char* CMockString_param = "param"; +static const char* CMockString_phase_api_stub = "phase_api_stub"; +static const char* CMockString_start_alarm_api = "start_alarm_api"; +static const char* CMockString_type = "type"; + +typedef struct _CMOCK_phase_api_stub_CALL_INSTANCE +{ + UNITY_LINE_TYPE LineNumber; + char ExpectAnyArgsBool; + int ReturnVal; + +} CMOCK_phase_api_stub_CALL_INSTANCE; + +typedef struct _CMOCK_start_alarm_api_CALL_INSTANCE +{ + UNITY_LINE_TYPE LineNumber; + char ExpectAnyArgsBool; + int ReturnVal; + fwk_id_t Expected_alarm_id; + unsigned int Expected_microseconds; + enum mod_timer_alarm_type Expected_type; + cmock_mod_system_coordinator_extra_func_ptr1 Expected_callback; + uintptr_t Expected_param; + char IgnoreArg_alarm_id; + char IgnoreArg_microseconds; + char IgnoreArg_type; + char IgnoreArg_callback; + char IgnoreArg_param; + +} CMOCK_start_alarm_api_CALL_INSTANCE; + +static struct Mockmod_system_coordinator_extraInstance +{ + char phase_api_stub_IgnoreBool; + int phase_api_stub_FinalReturn; + char phase_api_stub_CallbackBool; + CMOCK_phase_api_stub_CALLBACK phase_api_stub_CallbackFunctionPointer; + int phase_api_stub_CallbackCalls; + CMOCK_MEM_INDEX_TYPE phase_api_stub_CallInstance; + char start_alarm_api_IgnoreBool; + int start_alarm_api_FinalReturn; + char start_alarm_api_CallbackBool; + CMOCK_start_alarm_api_CALLBACK start_alarm_api_CallbackFunctionPointer; + int start_alarm_api_CallbackCalls; + CMOCK_MEM_INDEX_TYPE start_alarm_api_CallInstance; +} Mock; + +extern jmp_buf AbortFrame; + +void Mockmod_system_coordinator_extra_Verify(void) +{ + UNITY_LINE_TYPE cmock_line = TEST_LINE_NUM; + CMOCK_MEM_INDEX_TYPE call_instance; + call_instance = Mock.phase_api_stub_CallInstance; + if (Mock.phase_api_stub_IgnoreBool) + call_instance = CMOCK_GUTS_NONE; + if (CMOCK_GUTS_NONE != call_instance) + { + UNITY_SET_DETAIL(CMockString_phase_api_stub); + UNITY_TEST_FAIL(cmock_line, CMockStringCalledLess); + } + if (Mock.phase_api_stub_CallbackFunctionPointer != NULL) + { + call_instance = CMOCK_GUTS_NONE; + (void)call_instance; + } + call_instance = Mock.start_alarm_api_CallInstance; + if (Mock.start_alarm_api_IgnoreBool) + call_instance = CMOCK_GUTS_NONE; + if (CMOCK_GUTS_NONE != call_instance) + { + UNITY_SET_DETAIL(CMockString_start_alarm_api); + UNITY_TEST_FAIL(cmock_line, CMockStringCalledLess); + } + if (Mock.start_alarm_api_CallbackFunctionPointer != NULL) + { + call_instance = CMOCK_GUTS_NONE; + (void)call_instance; + } +} + +void Mockmod_system_coordinator_extra_Init(void) +{ + Mockmod_system_coordinator_extra_Destroy(); +} + +void Mockmod_system_coordinator_extra_Destroy(void) +{ + CMock_Guts_MemFreeAll(); + memset(&Mock, 0, sizeof(Mock)); +} + +int phase_api_stub(void) +{ + UNITY_LINE_TYPE cmock_line = TEST_LINE_NUM; + CMOCK_phase_api_stub_CALL_INSTANCE* cmock_call_instance; + UNITY_SET_DETAIL(CMockString_phase_api_stub); + cmock_call_instance = (CMOCK_phase_api_stub_CALL_INSTANCE*)CMock_Guts_GetAddressFor(Mock.phase_api_stub_CallInstance); + Mock.phase_api_stub_CallInstance = CMock_Guts_MemNext(Mock.phase_api_stub_CallInstance); + if (Mock.phase_api_stub_IgnoreBool) + { + UNITY_CLR_DETAILS(); + if (cmock_call_instance == NULL) + return Mock.phase_api_stub_FinalReturn; + Mock.phase_api_stub_FinalReturn = cmock_call_instance->ReturnVal; + return cmock_call_instance->ReturnVal; + } + if (!Mock.phase_api_stub_CallbackBool && + Mock.phase_api_stub_CallbackFunctionPointer != NULL) + { + int cmock_cb_ret = Mock.phase_api_stub_CallbackFunctionPointer(Mock.phase_api_stub_CallbackCalls++); + UNITY_CLR_DETAILS(); + return cmock_cb_ret; + } + UNITY_TEST_ASSERT_NOT_NULL(cmock_call_instance, cmock_line, CMockStringCalledMore); + cmock_line = cmock_call_instance->LineNumber; + if (Mock.phase_api_stub_CallbackFunctionPointer != NULL) + { + cmock_call_instance->ReturnVal = Mock.phase_api_stub_CallbackFunctionPointer(Mock.phase_api_stub_CallbackCalls++); + } + UNITY_CLR_DETAILS(); + return cmock_call_instance->ReturnVal; +} + +void phase_api_stub_CMockIgnoreAndReturn(UNITY_LINE_TYPE cmock_line, int cmock_to_return) +{ + CMOCK_MEM_INDEX_TYPE cmock_guts_index = CMock_Guts_MemNew(sizeof(CMOCK_phase_api_stub_CALL_INSTANCE)); + CMOCK_phase_api_stub_CALL_INSTANCE* cmock_call_instance = (CMOCK_phase_api_stub_CALL_INSTANCE*)CMock_Guts_GetAddressFor(cmock_guts_index); + UNITY_TEST_ASSERT_NOT_NULL(cmock_call_instance, cmock_line, CMockStringOutOfMemory); + memset(cmock_call_instance, 0, sizeof(*cmock_call_instance)); + Mock.phase_api_stub_CallInstance = CMock_Guts_MemChain(Mock.phase_api_stub_CallInstance, cmock_guts_index); + Mock.phase_api_stub_IgnoreBool = (char)0; + cmock_call_instance->LineNumber = cmock_line; + cmock_call_instance->ExpectAnyArgsBool = (char)0; + cmock_call_instance->ReturnVal = cmock_to_return; + Mock.phase_api_stub_IgnoreBool = (char)1; +} + +void phase_api_stub_CMockStopIgnore(void) +{ + if(Mock.phase_api_stub_IgnoreBool) + Mock.phase_api_stub_CallInstance = CMock_Guts_MemNext(Mock.phase_api_stub_CallInstance); + Mock.phase_api_stub_IgnoreBool = (char)0; +} + +void phase_api_stub_CMockExpectAndReturn(UNITY_LINE_TYPE cmock_line, int cmock_to_return) +{ + CMOCK_MEM_INDEX_TYPE cmock_guts_index = CMock_Guts_MemNew(sizeof(CMOCK_phase_api_stub_CALL_INSTANCE)); + CMOCK_phase_api_stub_CALL_INSTANCE* cmock_call_instance = (CMOCK_phase_api_stub_CALL_INSTANCE*)CMock_Guts_GetAddressFor(cmock_guts_index); + UNITY_TEST_ASSERT_NOT_NULL(cmock_call_instance, cmock_line, CMockStringOutOfMemory); + memset(cmock_call_instance, 0, sizeof(*cmock_call_instance)); + Mock.phase_api_stub_CallInstance = CMock_Guts_MemChain(Mock.phase_api_stub_CallInstance, cmock_guts_index); + Mock.phase_api_stub_IgnoreBool = (char)0; + cmock_call_instance->LineNumber = cmock_line; + cmock_call_instance->ExpectAnyArgsBool = (char)0; + cmock_call_instance->ReturnVal = cmock_to_return; +} + +void phase_api_stub_AddCallback(CMOCK_phase_api_stub_CALLBACK Callback) +{ + Mock.phase_api_stub_IgnoreBool = (char)0; + Mock.phase_api_stub_CallbackBool = (char)1; + Mock.phase_api_stub_CallbackFunctionPointer = Callback; +} + +void phase_api_stub_Stub(CMOCK_phase_api_stub_CALLBACK Callback) +{ + Mock.phase_api_stub_IgnoreBool = (char)0; + Mock.phase_api_stub_CallbackBool = (char)0; + Mock.phase_api_stub_CallbackFunctionPointer = Callback; +} + +int start_alarm_api(fwk_id_t alarm_id, unsigned int microseconds, enum mod_timer_alarm_type type, cmock_mod_system_coordinator_extra_func_ptr1 callback, uintptr_t param) +{ + UNITY_LINE_TYPE cmock_line = TEST_LINE_NUM; + CMOCK_start_alarm_api_CALL_INSTANCE* cmock_call_instance; + UNITY_SET_DETAIL(CMockString_start_alarm_api); + cmock_call_instance = (CMOCK_start_alarm_api_CALL_INSTANCE*)CMock_Guts_GetAddressFor(Mock.start_alarm_api_CallInstance); + Mock.start_alarm_api_CallInstance = CMock_Guts_MemNext(Mock.start_alarm_api_CallInstance); + if (Mock.start_alarm_api_IgnoreBool) + { + UNITY_CLR_DETAILS(); + if (cmock_call_instance == NULL) + return Mock.start_alarm_api_FinalReturn; + Mock.start_alarm_api_FinalReturn = cmock_call_instance->ReturnVal; + return cmock_call_instance->ReturnVal; + } + if (!Mock.start_alarm_api_CallbackBool && + Mock.start_alarm_api_CallbackFunctionPointer != NULL) + { + int cmock_cb_ret = Mock.start_alarm_api_CallbackFunctionPointer(alarm_id, microseconds, type, callback, param, Mock.start_alarm_api_CallbackCalls++); + UNITY_CLR_DETAILS(); + return cmock_cb_ret; + } + UNITY_TEST_ASSERT_NOT_NULL(cmock_call_instance, cmock_line, CMockStringCalledMore); + cmock_line = cmock_call_instance->LineNumber; + if (!cmock_call_instance->ExpectAnyArgsBool) + { + if (!cmock_call_instance->IgnoreArg_alarm_id) + { + UNITY_SET_DETAILS(CMockString_start_alarm_api,CMockString_alarm_id); + UNITY_TEST_ASSERT_EQUAL_MEMORY((void*)(&cmock_call_instance->Expected_alarm_id), (void*)(&alarm_id), sizeof(fwk_id_t), cmock_line, CMockStringMismatch); + } + if (!cmock_call_instance->IgnoreArg_microseconds) + { + UNITY_SET_DETAILS(CMockString_start_alarm_api,CMockString_microseconds); + UNITY_TEST_ASSERT_EQUAL_HEX32(cmock_call_instance->Expected_microseconds, microseconds, cmock_line, CMockStringMismatch); + } + if (!cmock_call_instance->IgnoreArg_type) + { + UNITY_SET_DETAILS(CMockString_start_alarm_api,CMockString_type); + UNITY_TEST_ASSERT_EQUAL_MEMORY((void*)(&cmock_call_instance->Expected_type), (void*)(&type), sizeof(enum mod_timer_alarm_type), cmock_line, CMockStringMismatch); + } + if (!cmock_call_instance->IgnoreArg_callback) + { + UNITY_SET_DETAILS(CMockString_start_alarm_api,CMockString_callback); + UNITY_TEST_ASSERT_EQUAL_PTR(cmock_call_instance->Expected_callback, callback, cmock_line, CMockStringMismatch); + } + if (!cmock_call_instance->IgnoreArg_param) + { + UNITY_SET_DETAILS(CMockString_start_alarm_api,CMockString_param); + UNITY_TEST_ASSERT_EQUAL_MEMORY((void*)(&cmock_call_instance->Expected_param), (void*)(¶m), sizeof(uintptr_t), cmock_line, CMockStringMismatch); + } + } + if (Mock.start_alarm_api_CallbackFunctionPointer != NULL) + { + cmock_call_instance->ReturnVal = Mock.start_alarm_api_CallbackFunctionPointer(alarm_id, microseconds, type, callback, param, Mock.start_alarm_api_CallbackCalls++); + } + UNITY_CLR_DETAILS(); + return cmock_call_instance->ReturnVal; +} + +void CMockExpectParameters_start_alarm_api(CMOCK_start_alarm_api_CALL_INSTANCE* cmock_call_instance, fwk_id_t alarm_id, unsigned int microseconds, enum mod_timer_alarm_type type, cmock_mod_system_coordinator_extra_func_ptr1 callback, uintptr_t param); +void CMockExpectParameters_start_alarm_api(CMOCK_start_alarm_api_CALL_INSTANCE* cmock_call_instance, fwk_id_t alarm_id, unsigned int microseconds, enum mod_timer_alarm_type type, cmock_mod_system_coordinator_extra_func_ptr1 callback, uintptr_t param) +{ + memcpy((void*)(&cmock_call_instance->Expected_alarm_id), (void*)(&alarm_id), + sizeof(fwk_id_t[sizeof(alarm_id) == sizeof(fwk_id_t) ? 1 : -1])); /* add fwk_id_t to :treat_as_array if this causes an error */ + cmock_call_instance->IgnoreArg_alarm_id = 0; + cmock_call_instance->Expected_microseconds = microseconds; + cmock_call_instance->IgnoreArg_microseconds = 0; + memcpy((void*)(&cmock_call_instance->Expected_type), (void*)(&type), + sizeof(enum mod_timer_alarm_type[sizeof(type) == sizeof(enum mod_timer_alarm_type) ? 1 : -1])); /* add enum mod_timer_alarm_type to :treat_as_array if this causes an error */ + cmock_call_instance->IgnoreArg_type = 0; + memcpy((void*)(&cmock_call_instance->Expected_callback), (void*)(&callback), + sizeof(cmock_mod_system_coordinator_extra_func_ptr1[sizeof(callback) == sizeof(cmock_mod_system_coordinator_extra_func_ptr1) ? 1 : -1])); /* add cmock_mod_system_coordinator_extra_func_ptr1 to :treat_as_array if this causes an error */ + cmock_call_instance->IgnoreArg_callback = 0; + memcpy((void*)(&cmock_call_instance->Expected_param), (void*)(¶m), + sizeof(uintptr_t[sizeof(param) == sizeof(uintptr_t) ? 1 : -1])); /* add uintptr_t to :treat_as_array if this causes an error */ + cmock_call_instance->IgnoreArg_param = 0; +} + +void start_alarm_api_CMockIgnoreAndReturn(UNITY_LINE_TYPE cmock_line, int cmock_to_return) +{ + CMOCK_MEM_INDEX_TYPE cmock_guts_index = CMock_Guts_MemNew(sizeof(CMOCK_start_alarm_api_CALL_INSTANCE)); + CMOCK_start_alarm_api_CALL_INSTANCE* cmock_call_instance = (CMOCK_start_alarm_api_CALL_INSTANCE*)CMock_Guts_GetAddressFor(cmock_guts_index); + UNITY_TEST_ASSERT_NOT_NULL(cmock_call_instance, cmock_line, CMockStringOutOfMemory); + memset(cmock_call_instance, 0, sizeof(*cmock_call_instance)); + Mock.start_alarm_api_CallInstance = CMock_Guts_MemChain(Mock.start_alarm_api_CallInstance, cmock_guts_index); + Mock.start_alarm_api_IgnoreBool = (char)0; + cmock_call_instance->LineNumber = cmock_line; + cmock_call_instance->ExpectAnyArgsBool = (char)0; + cmock_call_instance->ReturnVal = cmock_to_return; + Mock.start_alarm_api_IgnoreBool = (char)1; +} + +void start_alarm_api_CMockStopIgnore(void) +{ + if(Mock.start_alarm_api_IgnoreBool) + Mock.start_alarm_api_CallInstance = CMock_Guts_MemNext(Mock.start_alarm_api_CallInstance); + Mock.start_alarm_api_IgnoreBool = (char)0; +} + +void start_alarm_api_CMockExpectAnyArgsAndReturn(UNITY_LINE_TYPE cmock_line, int cmock_to_return) +{ + CMOCK_MEM_INDEX_TYPE cmock_guts_index = CMock_Guts_MemNew(sizeof(CMOCK_start_alarm_api_CALL_INSTANCE)); + CMOCK_start_alarm_api_CALL_INSTANCE* cmock_call_instance = (CMOCK_start_alarm_api_CALL_INSTANCE*)CMock_Guts_GetAddressFor(cmock_guts_index); + UNITY_TEST_ASSERT_NOT_NULL(cmock_call_instance, cmock_line, CMockStringOutOfMemory); + memset(cmock_call_instance, 0, sizeof(*cmock_call_instance)); + Mock.start_alarm_api_CallInstance = CMock_Guts_MemChain(Mock.start_alarm_api_CallInstance, cmock_guts_index); + Mock.start_alarm_api_IgnoreBool = (char)0; + cmock_call_instance->LineNumber = cmock_line; + cmock_call_instance->ExpectAnyArgsBool = (char)0; + cmock_call_instance->ReturnVal = cmock_to_return; + cmock_call_instance->ExpectAnyArgsBool = (char)1; +} + +void start_alarm_api_CMockExpectAndReturn(UNITY_LINE_TYPE cmock_line, fwk_id_t alarm_id, unsigned int microseconds, enum mod_timer_alarm_type type, cmock_mod_system_coordinator_extra_func_ptr1 callback, uintptr_t param, int cmock_to_return) +{ + CMOCK_MEM_INDEX_TYPE cmock_guts_index = CMock_Guts_MemNew(sizeof(CMOCK_start_alarm_api_CALL_INSTANCE)); + CMOCK_start_alarm_api_CALL_INSTANCE* cmock_call_instance = (CMOCK_start_alarm_api_CALL_INSTANCE*)CMock_Guts_GetAddressFor(cmock_guts_index); + UNITY_TEST_ASSERT_NOT_NULL(cmock_call_instance, cmock_line, CMockStringOutOfMemory); + memset(cmock_call_instance, 0, sizeof(*cmock_call_instance)); + Mock.start_alarm_api_CallInstance = CMock_Guts_MemChain(Mock.start_alarm_api_CallInstance, cmock_guts_index); + Mock.start_alarm_api_IgnoreBool = (char)0; + cmock_call_instance->LineNumber = cmock_line; + cmock_call_instance->ExpectAnyArgsBool = (char)0; + CMockExpectParameters_start_alarm_api(cmock_call_instance, alarm_id, microseconds, type, callback, param); + cmock_call_instance->ReturnVal = cmock_to_return; +} + +void start_alarm_api_AddCallback(CMOCK_start_alarm_api_CALLBACK Callback) +{ + Mock.start_alarm_api_IgnoreBool = (char)0; + Mock.start_alarm_api_CallbackBool = (char)1; + Mock.start_alarm_api_CallbackFunctionPointer = Callback; +} + +void start_alarm_api_Stub(CMOCK_start_alarm_api_CALLBACK Callback) +{ + Mock.start_alarm_api_IgnoreBool = (char)0; + Mock.start_alarm_api_CallbackBool = (char)0; + Mock.start_alarm_api_CallbackFunctionPointer = Callback; +} + +void start_alarm_api_CMockIgnoreArg_alarm_id(UNITY_LINE_TYPE cmock_line) +{ + CMOCK_start_alarm_api_CALL_INSTANCE* cmock_call_instance = (CMOCK_start_alarm_api_CALL_INSTANCE*)CMock_Guts_GetAddressFor(CMock_Guts_MemEndOfChain(Mock.start_alarm_api_CallInstance)); + UNITY_TEST_ASSERT_NOT_NULL(cmock_call_instance, cmock_line, CMockStringIgnPreExp); + cmock_call_instance->IgnoreArg_alarm_id = 1; +} + +void start_alarm_api_CMockIgnoreArg_microseconds(UNITY_LINE_TYPE cmock_line) +{ + CMOCK_start_alarm_api_CALL_INSTANCE* cmock_call_instance = (CMOCK_start_alarm_api_CALL_INSTANCE*)CMock_Guts_GetAddressFor(CMock_Guts_MemEndOfChain(Mock.start_alarm_api_CallInstance)); + UNITY_TEST_ASSERT_NOT_NULL(cmock_call_instance, cmock_line, CMockStringIgnPreExp); + cmock_call_instance->IgnoreArg_microseconds = 1; +} + +void start_alarm_api_CMockIgnoreArg_type(UNITY_LINE_TYPE cmock_line) +{ + CMOCK_start_alarm_api_CALL_INSTANCE* cmock_call_instance = (CMOCK_start_alarm_api_CALL_INSTANCE*)CMock_Guts_GetAddressFor(CMock_Guts_MemEndOfChain(Mock.start_alarm_api_CallInstance)); + UNITY_TEST_ASSERT_NOT_NULL(cmock_call_instance, cmock_line, CMockStringIgnPreExp); + cmock_call_instance->IgnoreArg_type = 1; +} + +void start_alarm_api_CMockIgnoreArg_callback(UNITY_LINE_TYPE cmock_line) +{ + CMOCK_start_alarm_api_CALL_INSTANCE* cmock_call_instance = (CMOCK_start_alarm_api_CALL_INSTANCE*)CMock_Guts_GetAddressFor(CMock_Guts_MemEndOfChain(Mock.start_alarm_api_CallInstance)); + UNITY_TEST_ASSERT_NOT_NULL(cmock_call_instance, cmock_line, CMockStringIgnPreExp); + cmock_call_instance->IgnoreArg_callback = 1; +} + +void start_alarm_api_CMockIgnoreArg_param(UNITY_LINE_TYPE cmock_line) +{ + CMOCK_start_alarm_api_CALL_INSTANCE* cmock_call_instance = (CMOCK_start_alarm_api_CALL_INSTANCE*)CMock_Guts_GetAddressFor(CMock_Guts_MemEndOfChain(Mock.start_alarm_api_CallInstance)); + UNITY_TEST_ASSERT_NOT_NULL(cmock_call_instance, cmock_line, CMockStringIgnPreExp); + cmock_call_instance->IgnoreArg_param = 1; +} + diff --git a/module/system_coordinator/test/mocks/Mockmod_system_coordinator_extra.h b/module/system_coordinator/test/mocks/Mockmod_system_coordinator_extra.h new file mode 100644 index 000000000..d1970b227 --- /dev/null +++ b/module/system_coordinator/test/mocks/Mockmod_system_coordinator_extra.h @@ -0,0 +1,67 @@ +/* AUTOGENERATED FILE. DO NOT EDIT. */ +#ifndef _MOCKMOD_SYSTEM_COORDINATOR_EXTRA_H +#define _MOCKMOD_SYSTEM_COORDINATOR_EXTRA_H + +#include "unity.h" +#include "mod_system_coordinator_extra.h" + +/* Ignore the following warnings, since we are copying code */ +#if defined(__GNUC__) && !defined(__ICC) && !defined(__TMS470__) +#if __GNUC__ > 4 || (__GNUC__ == 4 && (__GNUC_MINOR__ > 6 || (__GNUC_MINOR__ == 6 && __GNUC_PATCHLEVEL__ > 0))) +#pragma GCC diagnostic push +#endif +#if !defined(__clang__) +#pragma GCC diagnostic ignored "-Wpragmas" +#endif +#pragma GCC diagnostic ignored "-Wunknown-pragmas" +#pragma GCC diagnostic ignored "-Wduplicate-decl-specifier" +#endif + +void Mockmod_system_coordinator_extra_Init(void); +void Mockmod_system_coordinator_extra_Destroy(void); +void Mockmod_system_coordinator_extra_Verify(void); + + +typedef void(*cmock_mod_system_coordinator_extra_func_ptr1)(uintptr_t param); + + +#define phase_api_stub_IgnoreAndReturn(cmock_retval) phase_api_stub_CMockIgnoreAndReturn(__LINE__, cmock_retval) +void phase_api_stub_CMockIgnoreAndReturn(UNITY_LINE_TYPE cmock_line, int cmock_to_return); +#define phase_api_stub_StopIgnore() phase_api_stub_CMockStopIgnore() +void phase_api_stub_CMockStopIgnore(void); +#define phase_api_stub_ExpectAndReturn(cmock_retval) phase_api_stub_CMockExpectAndReturn(__LINE__, cmock_retval) +void phase_api_stub_CMockExpectAndReturn(UNITY_LINE_TYPE cmock_line, int cmock_to_return); +typedef int (* CMOCK_phase_api_stub_CALLBACK)(int cmock_num_calls); +void phase_api_stub_AddCallback(CMOCK_phase_api_stub_CALLBACK Callback); +void phase_api_stub_Stub(CMOCK_phase_api_stub_CALLBACK Callback); +#define phase_api_stub_StubWithCallback phase_api_stub_Stub +#define start_alarm_api_IgnoreAndReturn(cmock_retval) start_alarm_api_CMockIgnoreAndReturn(__LINE__, cmock_retval) +void start_alarm_api_CMockIgnoreAndReturn(UNITY_LINE_TYPE cmock_line, int cmock_to_return); +#define start_alarm_api_StopIgnore() start_alarm_api_CMockStopIgnore() +void start_alarm_api_CMockStopIgnore(void); +#define start_alarm_api_ExpectAnyArgsAndReturn(cmock_retval) start_alarm_api_CMockExpectAnyArgsAndReturn(__LINE__, cmock_retval) +void start_alarm_api_CMockExpectAnyArgsAndReturn(UNITY_LINE_TYPE cmock_line, int cmock_to_return); +#define start_alarm_api_ExpectAndReturn(alarm_id, microseconds, type, callback, param, cmock_retval) start_alarm_api_CMockExpectAndReturn(__LINE__, alarm_id, microseconds, type, callback, param, cmock_retval) +void start_alarm_api_CMockExpectAndReturn(UNITY_LINE_TYPE cmock_line, fwk_id_t alarm_id, unsigned int microseconds, enum mod_timer_alarm_type type, cmock_mod_system_coordinator_extra_func_ptr1 callback, uintptr_t param, int cmock_to_return); +typedef int (* CMOCK_start_alarm_api_CALLBACK)(fwk_id_t alarm_id, unsigned int microseconds, enum mod_timer_alarm_type type, cmock_mod_system_coordinator_extra_func_ptr1 callback, uintptr_t param, int cmock_num_calls); +void start_alarm_api_AddCallback(CMOCK_start_alarm_api_CALLBACK Callback); +void start_alarm_api_Stub(CMOCK_start_alarm_api_CALLBACK Callback); +#define start_alarm_api_StubWithCallback start_alarm_api_Stub +#define start_alarm_api_IgnoreArg_alarm_id() start_alarm_api_CMockIgnoreArg_alarm_id(__LINE__) +void start_alarm_api_CMockIgnoreArg_alarm_id(UNITY_LINE_TYPE cmock_line); +#define start_alarm_api_IgnoreArg_microseconds() start_alarm_api_CMockIgnoreArg_microseconds(__LINE__) +void start_alarm_api_CMockIgnoreArg_microseconds(UNITY_LINE_TYPE cmock_line); +#define start_alarm_api_IgnoreArg_type() start_alarm_api_CMockIgnoreArg_type(__LINE__) +void start_alarm_api_CMockIgnoreArg_type(UNITY_LINE_TYPE cmock_line); +#define start_alarm_api_IgnoreArg_callback() start_alarm_api_CMockIgnoreArg_callback(__LINE__) +void start_alarm_api_CMockIgnoreArg_callback(UNITY_LINE_TYPE cmock_line); +#define start_alarm_api_IgnoreArg_param() start_alarm_api_CMockIgnoreArg_param(__LINE__) +void start_alarm_api_CMockIgnoreArg_param(UNITY_LINE_TYPE cmock_line); + +#if defined(__GNUC__) && !defined(__ICC) && !defined(__TMS470__) +#if __GNUC__ > 4 || (__GNUC__ == 4 && (__GNUC_MINOR__ > 6 || (__GNUC_MINOR__ == 6 && __GNUC_PATCHLEVEL__ > 0))) +#pragma GCC diagnostic pop +#endif +#endif + +#endif diff --git a/module/system_coordinator/test/mod_system_coordinator_extra.h b/module/system_coordinator/test/mod_system_coordinator_extra.h new file mode 100644 index 000000000..86dcd3e1a --- /dev/null +++ b/module/system_coordinator/test/mod_system_coordinator_extra.h @@ -0,0 +1,27 @@ +/* + * Arm SCP/MCP Software + * Copyright (c) 2024, Arm Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + * + * Description: + * System Coordinator unit test support. + */ + +#ifndef MOD_SYSTEM_COORDINATOR_EXTRA_H +#define MOD_SYSTEM_COORDINATOR_EXTRA_H + +#include + +#include + +int phase_api_stub(void); + +int start_alarm_api( + fwk_id_t alarm_id, + unsigned int microseconds, + enum mod_timer_alarm_type type, + void (*callback)(uintptr_t param), + uintptr_t param); + +#endif /* MOD_SYSTEM_COORDINATOR_EXTRA_H */ diff --git a/module/system_coordinator/test/mod_system_coordinator_unit_test.c b/module/system_coordinator/test/mod_system_coordinator_unit_test.c new file mode 100644 index 000000000..5f2726bc8 --- /dev/null +++ b/module/system_coordinator/test/mod_system_coordinator_unit_test.c @@ -0,0 +1,343 @@ +/* + * Arm SCP/MCP Software + * Copyright (c) 2024, Arm Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include "config_system_coordinator.h" +#include "scp_unity.h" +#include "unity.h" + +#include +#include +#include +#include + +#include + +#include + +#include UNIT_TEST_SRC + +#define MOD_SYSTEM_COORDINATOR_ID \ + FWK_ID_MODULE(FWK_MODULE_IDX_SYSTEM_COORDINATOR) + +/* Runtime allocated variables */ + +struct mod_system_coordinator_phase_ctx phase[SYS_COOR_PHASE_COUNT]; +struct mod_system_coordinator_phase_api phase_api = { + .phase_handler = &phase_api_stub, +}; + +struct mod_timer_alarm_api alarm_api_driver = { + .start = start_alarm_api, +}; + +void setUp(void) +{ + struct mod_system_coordinator_phase_ctx *ctx; + + memset(&system_coordinator_ctx, 0, sizeof(system_coordinator_ctx)); + + system_coordinator_ctx.config = module_config.data; + system_coordinator_ctx.phase_ctx = phase; + system_coordinator_ctx.cycle_alarm_api = &alarm_api_driver; + system_coordinator_ctx.phase_alarm_api = &alarm_api_driver; + system_coordinator_ctx.phase_count = SYS_COOR_PHASE_COUNT; + + /* Initialise each phase */ + for (int i = 0; i < SYS_COOR_PHASE_COUNT; i++) { + ctx = &system_coordinator_ctx.phase_ctx[i]; + ctx->phase_config = + (struct mod_system_coordinator_phase_config *)phase_config[i].data; + ctx->phase_api = &phase_api; + } +} + +void tearDown(void) +{ + Mockmod_system_coordinator_extra_Verify(); + Mockmod_system_coordinator_extra_Destroy(); + Mockfwk_mm_Verify(); + Mockfwk_mm_Destroy(); + Mockfwk_module_Verify(); + Mockfwk_module_Destroy(); +} + +void utest_process_current_phase_phase_count_invalid(void) +{ + int status = FWK_E_INIT; + + status = process_current_phase(SYS_COOR_PHASE_COUNT); + + TEST_ASSERT_EQUAL(FWK_E_RANGE, status); +} + +void utest_process_current_phase_call_phase(void) +{ + int status = FWK_E_INIT; + + start_alarm_api_ExpectAndReturn( + system_coordinator_ctx.config->phase_alarm_id, + system_coordinator_ctx.phase_ctx[SYS_COOR_PHASE_ONE] + .phase_config->phase_us, + MOD_TIMER_ALARM_TYPE_ONCE, + system_coordinator_phase_alarm_callback, + SYS_COOR_PHASE_TWO, + FWK_SUCCESS); + + phase_api_stub_ExpectAndReturn(FWK_SUCCESS); + + status = process_current_phase(SYS_COOR_PHASE_ONE); + + TEST_ASSERT_EQUAL(FWK_SUCCESS, status); +} + +void utest_process_current_phase_alarm_error(void) +{ + int status = FWK_E_INIT; + + start_alarm_api_ExpectAnyArgsAndReturn(FWK_E_PARAM); + + status = process_current_phase(SYS_COOR_PHASE_ONE); + + TEST_ASSERT_EQUAL(FWK_E_PARAM, status); +} + +void utest_process_current_phase_last_phase(void) +{ + int status = FWK_E_INIT; + + phase_api_stub_ExpectAndReturn(FWK_SUCCESS); + + status = process_current_phase(SYS_COOR_PHASE_COUNT - 1); + + TEST_ASSERT_EQUAL(FWK_SUCCESS, status); +} + +void utest_process_current_phase_phase_time_zero(void) +{ + int status = FWK_E_INIT; + + phase_api_stub_ExpectAndReturn(FWK_SUCCESS); + __fwk_put_event_ExpectAnyArgsAndReturn(FWK_SUCCESS); + + status = process_current_phase(SYS_COOR_PHASE_TWO); + + TEST_ASSERT_EQUAL(FWK_SUCCESS, status); +} + +void utest_system_coordinator_init_zero_element(void) +{ + int status = FWK_E_INIT; + unsigned int elem_count = 0; + + status = system_coordinator_init( + fwk_module_id_system_coordinator, elem_count, NULL); + TEST_ASSERT_EQUAL(FWK_E_PARAM, status); +} + +void utest_system_coordinator_init_success(void) +{ + int status = FWK_E_INIT; + size_t elem_count = SYS_COOR_PHASE_COUNT; + struct mod_system_coordinator_phase_ctx phase[SYS_COOR_PHASE_COUNT]; + + /* Reset system_coordinator_ctx to let init() initialise the context */ + memset(&system_coordinator_ctx, 0, sizeof(system_coordinator_ctx)); + + fwk_mm_calloc_ExpectAndReturn( + elem_count, sizeof(struct mod_system_coordinator_phase_ctx), phase); + + status = system_coordinator_init( + fwk_module_id_system_coordinator, elem_count, module_config.data); + TEST_ASSERT_EQUAL(elem_count, system_coordinator_ctx.phase_count); + TEST_ASSERT_EQUAL_PTR(phase, system_coordinator_ctx.phase_ctx); + TEST_ASSERT_EQUAL_PTR(module_config.data, system_coordinator_ctx.config); + TEST_ASSERT_EQUAL_PTR( + COORDINATOR_CYCLE_TIME, system_coordinator_ctx.config->cycle_us); + TEST_ASSERT_EQUAL(FWK_SUCCESS, status); +} + +void utest_system_coordinator_element_init_element_count_invalid(void) +{ + int status = FWK_E_INIT; + unsigned int sub_element_count = 0; + fwk_id_t element_id; + + element_id = + FWK_ID_ELEMENT(FWK_MODULE_IDX_SYSTEM_COORDINATOR, SYS_COOR_PHASE_COUNT); + + status = + system_coordinator_element_init(element_id, sub_element_count, NULL); + TEST_ASSERT_EQUAL(FWK_E_PARAM, status); +} + +void utest_system_coordinator_element_init_success(void) +{ + int status = FWK_E_INIT; + unsigned int sub_element_count = 0; + fwk_id_t element_id; + + system_coordinator_ctx.phase_ctx->phase_config = NULL; + + /* Loop all phases */ + for (int i = 0; i < SYS_COOR_PHASE_COUNT; i++) { + element_id = FWK_ID_ELEMENT(FWK_MODULE_IDX_SYSTEM_COORDINATOR, i); + status = system_coordinator_element_init( + element_id, sub_element_count, phase_config[i].data); + TEST_ASSERT_EQUAL_PTR( + phase_config[i].data, + system_coordinator_ctx.phase_ctx[i].phase_config); + TEST_ASSERT_EQUAL(FWK_SUCCESS, status); + } +} + +void utest_system_coordinator_post_init_total_phase_more_than_cycle_time(void) +{ + int status = FWK_E_INIT; + struct mod_system_coordinator_phase_config fake_phase_time = { + .phase_us = COORDINATOR_CYCLE_TIME, + }; + + /* Replace phase one time with a bigger value like cycle time */ + system_coordinator_ctx.phase_ctx[0].phase_config = &fake_phase_time; + + status = system_coordinator_post_init(fwk_module_id_system_coordinator); + TEST_ASSERT_EQUAL(FWK_E_SUPPORT, status); +} + +void utest_system_coordinator_post_init_total_phase_less_than_cycle_time(void) +{ + int status = FWK_E_INIT; + + status = system_coordinator_post_init(fwk_module_id_system_coordinator); + TEST_ASSERT_EQUAL(FWK_SUCCESS, status); +} + +void utest_system_coordinator_bind_module_success(void) +{ + int status = FWK_E_INIT; + unsigned int round = 0; + + fwk_module_is_valid_module_id_ExpectAndReturn( + fwk_module_id_system_coordinator, true); + fwk_module_bind_ExpectAndReturn( + system_coordinator_ctx.config->cycle_alarm_id, + MOD_TIMER_API_ID_ALARM, + &system_coordinator_ctx.cycle_alarm_api, + FWK_SUCCESS); + + fwk_module_bind_ExpectAndReturn( + system_coordinator_ctx.config->phase_alarm_id, + MOD_TIMER_API_ID_ALARM, + &system_coordinator_ctx.phase_alarm_api, + FWK_SUCCESS); + + status = system_coordinator_bind(fwk_module_id_system_coordinator, round); + TEST_ASSERT_EQUAL(FWK_SUCCESS, status); +} + +void utest_system_coordinator_bind_element_success(void) +{ + int status = FWK_E_INIT; + unsigned int round = 0; + fwk_id_t element_id = FWK_ID_ELEMENT_INIT( + FWK_MODULE_IDX_SYSTEM_COORDINATOR, SYS_COOR_PHASE_ONE); + struct mod_system_coordinator_phase_config *cfg = + (struct mod_system_coordinator_phase_config *) + phase_config[SYS_COOR_PHASE_ONE] + .data; + + fwk_module_is_valid_module_id_ExpectAndReturn(element_id, false); + fwk_module_is_valid_element_id_ExpectAndReturn(element_id, true); + fwk_module_bind_ExpectAndReturn( + cfg->module_id, + cfg->api_id, + &system_coordinator_ctx.phase_ctx[SYS_COOR_PHASE_ONE].phase_api, + FWK_SUCCESS); + + status = system_coordinator_bind(element_id, round); + TEST_ASSERT_EQUAL(FWK_SUCCESS, status); +} + +void utest_system_coordinator_start_success(void) +{ + int status = FWK_E_INIT; + + start_alarm_api_ExpectAndReturn( + system_coordinator_ctx.config->cycle_alarm_id, + system_coordinator_ctx.config->cycle_us, + MOD_TIMER_ALARM_TYPE_PERIODIC, + system_coordinator_cycle_alarm_callback, + 0, + FWK_SUCCESS); + + start_alarm_api_ExpectAndReturn( + system_coordinator_ctx.config->phase_alarm_id, + system_coordinator_ctx.phase_ctx[SYS_COOR_PHASE_ONE] + .phase_config->phase_us, + MOD_TIMER_ALARM_TYPE_ONCE, + system_coordinator_phase_alarm_callback, + SYS_COOR_PHASE_TWO, + FWK_SUCCESS); + + phase_api_stub_ExpectAndReturn(FWK_SUCCESS); + + status = system_coordinator_start(fwk_module_id_system_coordinator); + + TEST_ASSERT_EQUAL(FWK_SUCCESS, status); +} + +void utest_system_coordinator_process_event_event_not_found(void) +{ + int status = FWK_E_INIT; + struct fwk_event event; + + event.target_id = + FWK_ID_ELEMENT(FWK_MODULE_IDX_SYSTEM_COORDINATOR, SYS_COOR_PHASE_ONE); + /* Set incorrect event index*/ + event.id = FWK_ID_EVENT( + FWK_MODULE_IDX_SYSTEM_COORDINATOR, + MOD_SYSTEM_COORDINATOR_EVENT_IDX_COUNT); + + status = system_coordinator_process_event(&event, NULL); + TEST_ASSERT_EQUAL(FWK_E_PARAM, status); +} + +int system_coordinator_test_main(void) +{ + UNITY_BEGIN(); + + RUN_TEST(utest_process_current_phase_phase_count_invalid); + RUN_TEST(utest_process_current_phase_call_phase); + RUN_TEST(utest_process_current_phase_alarm_error); + RUN_TEST(utest_process_current_phase_last_phase); + RUN_TEST(utest_process_current_phase_phase_time_zero); + + RUN_TEST(utest_system_coordinator_init_zero_element); + RUN_TEST(utest_system_coordinator_init_success); + + RUN_TEST(utest_system_coordinator_element_init_element_count_invalid); + RUN_TEST(utest_system_coordinator_element_init_success); + + RUN_TEST( + utest_system_coordinator_post_init_total_phase_more_than_cycle_time); + RUN_TEST( + utest_system_coordinator_post_init_total_phase_less_than_cycle_time); + + RUN_TEST(utest_system_coordinator_bind_module_success); + RUN_TEST(utest_system_coordinator_bind_element_success); + + RUN_TEST(utest_system_coordinator_start_success); + + RUN_TEST(utest_system_coordinator_process_event_event_not_found); + + return UNITY_END(); +} + +int main(void) +{ + return system_coordinator_test_main(); +} diff --git a/unit_test/CMakeLists.txt b/unit_test/CMakeLists.txt index 0d7e546b5..99cb3b4cb 100644 --- a/unit_test/CMakeLists.txt +++ b/unit_test/CMakeLists.txt @@ -143,6 +143,7 @@ list(APPEND UNIT_MODULE sensor) list(APPEND UNIT_MODULE sensor_smcf_drv) list(APPEND UNIT_MODULE smcf) list(APPEND UNIT_MODULE spmi) +list(APPEND UNIT_MODULE system_coordinator) list(APPEND UNIT_MODULE thermal_mgmt) list(APPEND UNIT_MODULE thermal_power_estimator) list(APPEND UNIT_MODULE traffic_cop) -- GitLab From 008e1c7124c698d6efdeba5fa5ff128b4fd476e9 Mon Sep 17 00:00:00 2001 From: Wen Ping Teh Date: Thu, 28 Nov 2024 22:59:46 +0000 Subject: [PATCH 3/4] mod/system_coordinator: Check cycle count to avoid outdated phase call Added cycle count to phase event parameters to ensure the coordinator does not call an outdated phase when a new cycle has begun. This prevents issues where a phase takes longer to complete than the configured phase time or when there are too many events in the queue, causing delays. The cycle count is incremented with each cycle alarm elapsed. Only events with the current cycle count will be processed and their phase API called. Events with a mismatched cycle count will be discarded. Signed-off-by: Wen Ping Teh --- .../src/mod_system_coordinator.c | 82 ++++++---- .../test/mod_system_coordinator_unit_test.c | 140 +++++++++++++++--- 2 files changed, 171 insertions(+), 51 deletions(-) diff --git a/module/system_coordinator/src/mod_system_coordinator.c b/module/system_coordinator/src/mod_system_coordinator.c index bda1b7636..405b2ac53 100644 --- a/module/system_coordinator/src/mod_system_coordinator.c +++ b/module/system_coordinator/src/mod_system_coordinator.c @@ -26,6 +26,15 @@ enum mod_system_coordinator_event_idx { MOD_SYSTEM_COORDINATOR_EVENT_IDX_COUNT, }; +/* Event parameter for EVENT_IDX_PHASE */ +struct phase_event_params { + /* The phase index of the API to be call in process_event() */ + unsigned int phase_idx; + + /* The cycle count which the phase originate */ + uint32_t cycle_count; +}; + /* Phase context */ struct mod_system_coordinator_phase_ctx { /* Phase configuration */ @@ -51,6 +60,9 @@ struct mod_system_coordinator_ctx { /* Total phase count */ uint32_t phase_count; + + /* Cycle count */ + uint32_t cycle_count; }; static const fwk_id_t mod_system_coordinator_event_phase = FWK_ID_EVENT_INIT( @@ -59,17 +71,18 @@ static const fwk_id_t mod_system_coordinator_event_phase = FWK_ID_EVENT_INIT( static struct mod_system_coordinator_ctx system_coordinator_ctx; -static int send_phase_event(uint32_t phase_idx) +static int send_phase_event(struct phase_event_params *params) { int status; - struct fwk_event phase_event = { .source_id = FWK_ID_MODULE(FWK_MODULE_IDX_SYSTEM_COORDINATOR), - .target_id = fwk_id_build_element_id( - fwk_module_id_system_coordinator, phase_idx), + .target_id = FWK_ID_MODULE(FWK_MODULE_IDX_SYSTEM_COORDINATOR), .id = mod_system_coordinator_event_phase, }; + struct phase_event_params *evt_params = + (struct phase_event_params *)&phase_event.params; + *evt_params = *params; status = fwk_put_event(&phase_event); if (status != FWK_SUCCESS) { FWK_LOG_ERR( @@ -77,7 +90,7 @@ static int send_phase_event(uint32_t phase_idx) __func__, __LINE__, status, - phase_idx); + params->phase_idx); } return status; @@ -89,52 +102,62 @@ static int send_phase_event(uint32_t phase_idx) static void system_coordinator_cycle_alarm_callback(uintptr_t param) { - send_phase_event(FIRST_PHASE_INDEX); + uint32_t *cycle_count = &system_coordinator_ctx.cycle_count; + struct phase_event_params first_phase_params = { 0 }; + + (*cycle_count)++; + + first_phase_params.phase_idx = FIRST_PHASE_INDEX; + first_phase_params.cycle_count = *cycle_count; + + send_phase_event(&first_phase_params); } static void system_coordinator_phase_alarm_callback(uintptr_t param) { - uint32_t phase_index = (uint32_t)param; - - send_phase_event(phase_index); + send_phase_event((struct phase_event_params *)param); } static int start_timer_for_next_phase( const struct mod_system_coordinator_phase_ctx *phase_ctx, - const uint32_t *phase_idx) + const struct phase_event_params *evt_params) { return system_coordinator_ctx.phase_alarm_api->start( system_coordinator_ctx.config->phase_alarm_id, phase_ctx->phase_config->phase_us, MOD_TIMER_ALARM_TYPE_ONCE, system_coordinator_phase_alarm_callback, - (uintptr_t)*phase_idx); - - return FWK_SUCCESS; + (uintptr_t)evt_params); } -static int process_current_phase(uint32_t phase_idx) +static int process_current_phase(const struct phase_event_params *params) { - int status; - uint32_t next_phase_idx; + int status = FWK_SUCCESS; + struct phase_event_params next_phase_params = { 0 }; struct mod_system_coordinator_phase_ctx *phase_ctx; - if (phase_idx >= system_coordinator_ctx.phase_count) { + if (params->phase_idx >= system_coordinator_ctx.phase_count) { return FWK_E_RANGE; } - next_phase_idx = phase_idx + 1; - phase_ctx = &system_coordinator_ctx.phase_ctx[phase_idx]; + if (params->cycle_count != system_coordinator_ctx.cycle_count) { + FWK_LOG_ERR(MOD_NAME "Cycle count mismatch"); + return FWK_E_STATE; + } + + phase_ctx = &system_coordinator_ctx.phase_ctx[params->phase_idx]; + next_phase_params.phase_idx = params->phase_idx + 1; + next_phase_params.cycle_count = params->cycle_count; if (phase_ctx->phase_config->phase_us == 0) { /* Send event to process next phase if current phase timer is 0 */ - status = send_phase_event(next_phase_idx); - } else if (phase_idx < (system_coordinator_ctx.phase_count - 1)) { + status = send_phase_event(&next_phase_params); + } else if (params->phase_idx < (system_coordinator_ctx.phase_count - 1)) { /* * Start timer for next phase. Timer will be skip if the phase is the * last phase or the phase time value is 0. */ - status = start_timer_for_next_phase(phase_ctx, &next_phase_idx); + status = start_timer_for_next_phase(phase_ctx, &next_phase_params); } if (status != FWK_SUCCESS) { @@ -257,11 +280,14 @@ static int system_coordinator_bind(fwk_id_t id, unsigned int round) static int system_coordinator_start(fwk_id_t id) { int status; + struct phase_event_params params; if (!fwk_id_is_type(id, FWK_ID_TYPE_MODULE)) { return FWK_SUCCESS; } + system_coordinator_ctx.cycle_count = 0; + /* Start cycle timer */ status = system_coordinator_ctx.cycle_alarm_api->start( system_coordinator_ctx.config->cycle_alarm_id, @@ -273,8 +299,11 @@ static int system_coordinator_start(fwk_id_t id) return status; } + params.cycle_count = system_coordinator_ctx.cycle_count; + params.phase_idx = FIRST_PHASE_INDEX; + /* Start first phase */ - status = process_current_phase(FIRST_PHASE_INDEX); + status = process_current_phase(¶ms); return status; } @@ -283,9 +312,7 @@ static int system_coordinator_process_event( const struct fwk_event *event, struct fwk_event *resp_event) { - uint32_t phase_idx; - - phase_idx = fwk_id_get_element_idx(event->target_id); + struct phase_event_params *params; /* * Event from cycle and phase timer callback. Both timer callback send the @@ -293,7 +320,8 @@ static int system_coordinator_process_event( * callback process the current phase. */ if (fwk_id_is_equal(event->id, mod_system_coordinator_event_phase)) { - return process_current_phase(phase_idx); + params = (struct phase_event_params *)event->params; + return process_current_phase(params); } return FWK_E_PARAM; diff --git a/module/system_coordinator/test/mod_system_coordinator_unit_test.c b/module/system_coordinator/test/mod_system_coordinator_unit_test.c index 5f2726bc8..2e89adbd6 100644 --- a/module/system_coordinator/test/mod_system_coordinator_unit_test.c +++ b/module/system_coordinator/test/mod_system_coordinator_unit_test.c @@ -20,6 +20,7 @@ #include UNIT_TEST_SRC +#define CYCLE_COUNT 100 #define MOD_SYSTEM_COORDINATOR_ID \ FWK_ID_MODULE(FWK_MODULE_IDX_SYSTEM_COORDINATOR) @@ -45,6 +46,7 @@ void setUp(void) system_coordinator_ctx.cycle_alarm_api = &alarm_api_driver; system_coordinator_ctx.phase_alarm_api = &alarm_api_driver; system_coordinator_ctx.phase_count = SYS_COOR_PHASE_COUNT; + system_coordinator_ctx.cycle_count = CYCLE_COUNT; /* Initialise each phase */ for (int i = 0; i < SYS_COOR_PHASE_COUNT; i++) { @@ -65,31 +67,101 @@ void tearDown(void) Mockfwk_module_Destroy(); } +int start_alarm_callback( + fwk_id_t alarm_id, + unsigned int microseconds, + enum mod_timer_alarm_type type, + cmock_mod_system_coordinator_extra_func_ptr1 callback, + uintptr_t param, + int cmock_num_calls) +{ + struct phase_event_params *evt_params = (struct phase_event_params *)param; + + TEST_ASSERT_EQUAL(SYS_COOR_PHASE_TWO, evt_params->phase_idx); + + return FWK_SUCCESS; +} + +void utest_cycle_alarm_callback_cycle_increment(void) +{ + struct fwk_event event = { + .source_id = FWK_ID_MODULE(FWK_MODULE_IDX_SYSTEM_COORDINATOR), + .target_id = FWK_ID_MODULE(FWK_MODULE_IDX_SYSTEM_COORDINATOR), + .id = mod_system_coordinator_event_phase, + }; + struct phase_event_params *evt_params = + (struct phase_event_params *)event.params; + + evt_params->phase_idx = SYS_COOR_PHASE_ONE; + evt_params->cycle_count = CYCLE_COUNT + 1; + + __fwk_put_event_ExpectAndReturn(&event, FWK_SUCCESS); + + system_coordinator_cycle_alarm_callback((uintptr_t)NULL); + + TEST_ASSERT_EQUAL(CYCLE_COUNT + 1, system_coordinator_ctx.cycle_count); +} + +void utest_cycle_alarm_callback_cycle_count_wraparound(void) +{ + struct fwk_event event = { + .source_id = FWK_ID_MODULE(FWK_MODULE_IDX_SYSTEM_COORDINATOR), + .target_id = FWK_ID_MODULE(FWK_MODULE_IDX_SYSTEM_COORDINATOR), + .id = mod_system_coordinator_event_phase, + }; + struct phase_event_params *evt_params = + (struct phase_event_params *)event.params; + + system_coordinator_ctx.cycle_count = UINT32_MAX; + evt_params->phase_idx = SYS_COOR_PHASE_ONE; + evt_params->cycle_count = 0; + + __fwk_put_event_ExpectAndReturn(&event, FWK_SUCCESS); + + system_coordinator_cycle_alarm_callback((uintptr_t)NULL); + + TEST_ASSERT_EQUAL(0, system_coordinator_ctx.cycle_count); +} + void utest_process_current_phase_phase_count_invalid(void) { int status = FWK_E_INIT; + struct phase_event_params params = { + .phase_idx = SYS_COOR_PHASE_COUNT, + .cycle_count = CYCLE_COUNT, + }; - status = process_current_phase(SYS_COOR_PHASE_COUNT); + status = process_current_phase(¶ms); TEST_ASSERT_EQUAL(FWK_E_RANGE, status); } -void utest_process_current_phase_call_phase(void) +void utest_process_current_phase_cycle_count_mismatch(void) { int status = FWK_E_INIT; + struct phase_event_params params = { + .phase_idx = SYS_COOR_PHASE_ONE, + .cycle_count = CYCLE_COUNT - 1, + }; - start_alarm_api_ExpectAndReturn( - system_coordinator_ctx.config->phase_alarm_id, - system_coordinator_ctx.phase_ctx[SYS_COOR_PHASE_ONE] - .phase_config->phase_us, - MOD_TIMER_ALARM_TYPE_ONCE, - system_coordinator_phase_alarm_callback, - SYS_COOR_PHASE_TWO, - FWK_SUCCESS); + status = process_current_phase(¶ms); + + TEST_ASSERT_EQUAL(FWK_E_STATE, status); +} + +void utest_process_current_phase_start_phase_timer(void) +{ + int status = FWK_E_INIT; + struct phase_event_params params = { + .phase_idx = SYS_COOR_PHASE_ONE, + .cycle_count = CYCLE_COUNT, + }; + + start_alarm_api_StubWithCallback(start_alarm_callback); phase_api_stub_ExpectAndReturn(FWK_SUCCESS); - status = process_current_phase(SYS_COOR_PHASE_ONE); + status = process_current_phase(¶ms); TEST_ASSERT_EQUAL(FWK_SUCCESS, status); } @@ -97,10 +169,14 @@ void utest_process_current_phase_call_phase(void) void utest_process_current_phase_alarm_error(void) { int status = FWK_E_INIT; + struct phase_event_params params = { + .phase_idx = SYS_COOR_PHASE_ONE, + .cycle_count = CYCLE_COUNT, + }; start_alarm_api_ExpectAnyArgsAndReturn(FWK_E_PARAM); - status = process_current_phase(SYS_COOR_PHASE_ONE); + status = process_current_phase(¶ms); TEST_ASSERT_EQUAL(FWK_E_PARAM, status); } @@ -108,10 +184,14 @@ void utest_process_current_phase_alarm_error(void) void utest_process_current_phase_last_phase(void) { int status = FWK_E_INIT; + struct phase_event_params params = { + .phase_idx = SYS_COOR_PHASE_COUNT - 1, + .cycle_count = CYCLE_COUNT, + }; phase_api_stub_ExpectAndReturn(FWK_SUCCESS); - status = process_current_phase(SYS_COOR_PHASE_COUNT - 1); + status = process_current_phase(¶ms); TEST_ASSERT_EQUAL(FWK_SUCCESS, status); } @@ -119,11 +199,25 @@ void utest_process_current_phase_last_phase(void) void utest_process_current_phase_phase_time_zero(void) { int status = FWK_E_INIT; + struct phase_event_params params = { + .phase_idx = SYS_COOR_PHASE_TWO, + .cycle_count = CYCLE_COUNT, + }; + struct fwk_event event = { + .source_id = FWK_ID_MODULE(FWK_MODULE_IDX_SYSTEM_COORDINATOR), + .target_id = FWK_ID_MODULE(FWK_MODULE_IDX_SYSTEM_COORDINATOR), + .id = mod_system_coordinator_event_phase, + }; + struct phase_event_params *evt_params = + (struct phase_event_params *)event.params; + + evt_params->phase_idx = SYS_COOR_PHASE_THREE; + evt_params->cycle_count = CYCLE_COUNT; phase_api_stub_ExpectAndReturn(FWK_SUCCESS); - __fwk_put_event_ExpectAnyArgsAndReturn(FWK_SUCCESS); + __fwk_put_event_ExpectAndReturn(&event, FWK_SUCCESS); - status = process_current_phase(SYS_COOR_PHASE_TWO); + status = process_current_phase(¶ms); TEST_ASSERT_EQUAL(FWK_SUCCESS, status); } @@ -274,20 +368,14 @@ void utest_system_coordinator_start_success(void) 0, FWK_SUCCESS); - start_alarm_api_ExpectAndReturn( - system_coordinator_ctx.config->phase_alarm_id, - system_coordinator_ctx.phase_ctx[SYS_COOR_PHASE_ONE] - .phase_config->phase_us, - MOD_TIMER_ALARM_TYPE_ONCE, - system_coordinator_phase_alarm_callback, - SYS_COOR_PHASE_TWO, - FWK_SUCCESS); + start_alarm_api_ExpectAnyArgsAndReturn(FWK_SUCCESS); phase_api_stub_ExpectAndReturn(FWK_SUCCESS); status = system_coordinator_start(fwk_module_id_system_coordinator); TEST_ASSERT_EQUAL(FWK_SUCCESS, status); + TEST_ASSERT_EQUAL(0, system_coordinator_ctx.cycle_count); } void utest_system_coordinator_process_event_event_not_found(void) @@ -310,8 +398,12 @@ int system_coordinator_test_main(void) { UNITY_BEGIN(); + RUN_TEST(utest_cycle_alarm_callback_cycle_increment); + RUN_TEST(utest_cycle_alarm_callback_cycle_count_wraparound); + RUN_TEST(utest_process_current_phase_phase_count_invalid); - RUN_TEST(utest_process_current_phase_call_phase); + RUN_TEST(utest_process_current_phase_cycle_count_mismatch); + RUN_TEST(utest_process_current_phase_start_phase_timer); RUN_TEST(utest_process_current_phase_alarm_error); RUN_TEST(utest_process_current_phase_last_phase); RUN_TEST(utest_process_current_phase_phase_time_zero); -- GitLab From 8b3238f79b7281962322ede9cd52f0730f4073a2 Mon Sep 17 00:00:00 2001 From: Wen Ping Teh Date: Mon, 2 Dec 2024 15:07:27 +0000 Subject: [PATCH 4/4] mod/system_coordinator: Add document for system coordinator Add system coordinator documentation that describe module overview and operation. Signed-off-by: Wen Ping Teh --- .../doc/system_coordinator.md | 61 +++++++++++++++++++ 1 file changed, 61 insertions(+) create mode 100644 module/system_coordinator/doc/system_coordinator.md diff --git a/module/system_coordinator/doc/system_coordinator.md b/module/system_coordinator/doc/system_coordinator.md new file mode 100644 index 000000000..2ecb7df47 --- /dev/null +++ b/module/system_coordinator/doc/system_coordinator.md @@ -0,0 +1,61 @@ +\ingroup GroupModules Modules +\defgroup GroupSystemCoordinator System Coordinator + +# Coordinator + +Copyright (c) 2024, Arm Limited and Contributors. All rights reserved. + +## Overview + +System coordinator is a module that manages the power management system. +The system coordinator is responsible for managing each phase of the power +management. + +Each phase is an API call to a module. The phase API and time are configurable +elements. Coordinator calls the next phase after the phase timer alarm elapses. +The order of the phases follows the element order. + +The phase's API shall be in this format for system coordinator to call: + + int phase_handler(void); + +A cycle timer alarm periodically notifies the coordinator to call all the phases +again. The cycle time is the sum of all the phase time.The cycle time is +configurable and must be more than the sum of all phase time. + +If a phase timer from the previous cycle elapses when a new cycle has begun, +the coordinator will discard that phase. Only phases from the current +cycle will be processed. For example, assuming there are three phases A, B and C +and two cycles 1 and 2, the sequence are A1->B1->A2->C1->B2->C2. C1 will be +discarded because A2 signifies cycle 2 had begun and only phases from cycle 2 +will be processed. + +## Phases + +The timing diagram below illustrates the phases in a cycle. Although this +diagram depicts only three phases, the coordinator is capable of calling +multiple phases. + +``` +[Cycle time] |<----------------x---------------->|<----------------x---------------->| + | | | +[Phase time] |<----a---->|<----b---->|<----c---->|<----a---->|<----b---->|<----c---->| + | | | | | | | + | | | | | | | + +-------+ +-------+ +-------+ +-------+ +-------+ +-------+ | +[Module] | Mod 1 | | Mod 2 | | Mod 3 | | Mod 1 | | Mod 2 | | Mod 3 | | + +-------+---+-------+---+-------+---+-------+---+-------+---+-------+---+ +``` + +Phase Time (*a* and *b*): Configurable values used by the phase timer to trigger +the next phase. If a phase time is set to 0, the phase timer will be skipped, +and an event will be immediately sent to initiate the next phase. + +Last Phase Time (*c*): Configurable value representing the duration of the last +phase. Since it is the final phase in the cycle, it does not trigger any further +phase transitions. Its value is used to ensure that the sum of all phase times +does not exceed the configured cycle time + +Cycle Time (*x*): configurable value representing the total duration of the +periodic cycle. The cycle time must be greater than the sum of all phase times: +$x>a+b+c$ -- GitLab