From be97a6ed9e98ec8b4c1b3a297a460819162c2614 Mon Sep 17 00:00:00 2001 From: Leandro Belli Date: Tue, 10 Sep 2024 12:03:05 +0100 Subject: [PATCH 1/2] module/thermal_power_estimator: add module This patch introduces a new module called `Thermal Power Estimator` that determines the maximum allocatable power based on temperature input. The module integrates with sensor and PID controller to dynamically estimate the maximum power budget. Signed-off-by: Leandro Belli --- module/thermal_power_estimator/CMakeLists.txt | 19 + module/thermal_power_estimator/Module.cmake | 9 + .../include/mod_thermal_power_estimator.h | 62 +++ .../src/mod_thermal_power_estimator.c | 249 +++++++++ .../test/CMakeLists.txt | 27 + .../test/fwk_module_idx.h | 33 ++ .../test/mocks/.clang-format | 4 + .../Mockmod_thermal_power_estimator_extra.c | 456 +++++++++++++++++ .../Mockmod_thermal_power_estimator_extra.h | 80 +++ .../test/mod_thermal_power_estimator_extra.h | 18 + .../mod_thermal_power_estimator_unit_test.c | 477 ++++++++++++++++++ unit_test/CMakeLists.txt | 1 + 12 files changed, 1435 insertions(+) create mode 100644 module/thermal_power_estimator/CMakeLists.txt create mode 100644 module/thermal_power_estimator/Module.cmake create mode 100644 module/thermal_power_estimator/include/mod_thermal_power_estimator.h create mode 100644 module/thermal_power_estimator/src/mod_thermal_power_estimator.c create mode 100644 module/thermal_power_estimator/test/CMakeLists.txt create mode 100644 module/thermal_power_estimator/test/fwk_module_idx.h create mode 100644 module/thermal_power_estimator/test/mocks/.clang-format create mode 100644 module/thermal_power_estimator/test/mocks/Mockmod_thermal_power_estimator_extra.c create mode 100644 module/thermal_power_estimator/test/mocks/Mockmod_thermal_power_estimator_extra.h create mode 100644 module/thermal_power_estimator/test/mod_thermal_power_estimator_extra.h create mode 100644 module/thermal_power_estimator/test/mod_thermal_power_estimator_unit_test.c diff --git a/module/thermal_power_estimator/CMakeLists.txt b/module/thermal_power_estimator/CMakeLists.txt new file mode 100644 index 000000000..94037b4b1 --- /dev/null +++ b/module/thermal_power_estimator/CMakeLists.txt @@ -0,0 +1,19 @@ +# +# 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_include_directories(${SCP_MODULE_TARGET} + PUBLIC "${CMAKE_SOURCE_DIR}/interface/power_management") + +target_sources(${SCP_MODULE_TARGET} + PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/src/mod_thermal_power_estimator.c") + +target_link_libraries(${SCP_MODULE_TARGET} PRIVATE module-sensor) diff --git a/module/thermal_power_estimator/Module.cmake b/module/thermal_power_estimator/Module.cmake new file mode 100644 index 000000000..cda56dd57 --- /dev/null +++ b/module/thermal_power_estimator/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 "thermal-power-estimator") +set(SCP_MODULE_TARGET "thermal-power-estimator") diff --git a/module/thermal_power_estimator/include/mod_thermal_power_estimator.h b/module/thermal_power_estimator/include/mod_thermal_power_estimator.h new file mode 100644 index 000000000..33848c2d2 --- /dev/null +++ b/module/thermal_power_estimator/include/mod_thermal_power_estimator.h @@ -0,0 +1,62 @@ +/* + * Arm SCP/MCP Software + * Copyright (c) 2024, Arm Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef MOD_THERMAL_POWER_ESTIMATOR_H +#define MOD_THERMAL_POWER_ESTIMATOR_H + +#include +#include +#include + +#include + +/*! + * \ingroup GroupModules + * \defgroup GroupThermalPowerEstimator Thermal Power Estimator + * + * \details Module for estimating maximum power of a platform based + * on thermal input. + * + * \{ + */ + +/*! + * \brief Thermal Power Estimator device configuration. + */ +struct mod_thermal_power_estimator_dev_config { + /*! The thermal design power (TDP) for all the devices being controlled. */ + uint32_t tdp; + + /*! Temperature sensor identifier. */ + fwk_id_t sensor_id; + + /*! Temperature sensor API identifier. */ + fwk_id_t sensor_api_id; + + /*! PID controller identifier. */ + fwk_id_t pid_controller_id; + + /*! PID controller API identifier. */ + fwk_id_t pid_controller_api_id; +}; + +/*! + * \brief API indices. + */ +enum mod_thermal_power_estimator_api_idx { + /*! Index for limit API. */ + MOD_THERMAL_POWER_ESTIMATOR_API_IDX_POWER_MANAGEMENT, + + /*! Number of defined APIs. */ + MOD_THERMAL_POWER_ESTIMATOR_API_IDX_COUNT, +}; + +/*! + * \} + */ + +#endif /* MOD_THERMAL_POWER_ESTIMATOR_H */ diff --git a/module/thermal_power_estimator/src/mod_thermal_power_estimator.c b/module/thermal_power_estimator/src/mod_thermal_power_estimator.c new file mode 100644 index 000000000..8988bfdd2 --- /dev/null +++ b/module/thermal_power_estimator/src/mod_thermal_power_estimator.c @@ -0,0 +1,249 @@ +/* + * Arm SCP/MCP Software + * Copyright (c) 2024, Arm Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + * + * Description: + * Thermal Power estimator. + * This module only probes the temperature and calculates the power budget. + */ + +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include + +#include +#include + +#define MOD_NAME "[TPE]" + +/* Device Context */ +struct mod_thermal_power_estimator_dev_ctx { + /* Thermal device configuration */ + struct mod_thermal_power_estimator_dev_config *config; + + /* Sensor data */ + struct mod_sensor_data sensor_data; + + /* Current temperature */ + uint32_t cur_temp; + + /* Sensor API */ + const struct mod_sensor_api *sensor_api; + + /* PID Controller API */ + const struct mod_pid_controller_api *pid_ctrl_api; +}; + +/* Module Context */ +struct mod_thermal_power_estimator_ctx { + /* Table of thermal domains */ + struct mod_thermal_power_estimator_dev_ctx *dev_ctx_table; + + /* Number of thermal domains */ + unsigned int dev_ctx_count; +}; + +struct mod_thermal_power_estimator_ctx mod_ctx; + +/* + * Helper functions. + */ + +static inline struct mod_thermal_power_estimator_dev_ctx *get_dev_ctx( + fwk_id_t dev_id) +{ + return &mod_ctx.dev_ctx_table[fwk_id_get_element_idx(dev_id)]; +} + +static int read_temperature(struct mod_thermal_power_estimator_dev_ctx *dev_ctx) +{ + int status; + + status = dev_ctx->sensor_api->get_data( + dev_ctx->config->sensor_id, &dev_ctx->sensor_data); + if (status == FWK_PENDING) { + FWK_LOG_ERR(MOD_NAME "delayed sensor response is not supported"); + return FWK_E_SUPPORT; + } else if (status != FWK_SUCCESS) { + return status; + } + + dev_ctx->cur_temp = (uint32_t)dev_ctx->sensor_data.value; + + return status; +} + +static inline int thermal_allocatable_power_calculate( + struct mod_thermal_power_estimator_dev_ctx *dev_ctx, + int64_t pid_output, + uint32_t *allocatable_power) +{ + int64_t output = pid_output + (int64_t)dev_ctx->config->tdp; + + if (output >= UINT32_MAX) { + FWK_LOG_ERR(MOD_NAME "Allocatable power is out of range > UINT32_MAX"); + return FWK_E_DATA; + } + + *allocatable_power = (uint32_t)FWK_MAX(output, 0); + + return FWK_SUCCESS; +} + +/* + * API functions. + */ + +static int thermal_power_estimator_get_limit(fwk_id_t id, uint32_t *power_limit) +{ + struct mod_thermal_power_estimator_dev_ctx *dev_ctx; + int64_t pid_output; + int status; + + fwk_assert(power_limit != NULL); + + dev_ctx = get_dev_ctx(id); + fwk_assert(dev_ctx != NULL); + + status = read_temperature(dev_ctx); + if (status != FWK_SUCCESS) { + return status; + } + + status = dev_ctx->pid_ctrl_api->update( + dev_ctx->config->pid_controller_id, dev_ctx->cur_temp, &pid_output); + if (status != FWK_SUCCESS) { + return status; + } + + status = + thermal_allocatable_power_calculate(dev_ctx, pid_output, power_limit); + if (status != FWK_SUCCESS) { + return status; + } + + return FWK_SUCCESS; +} + +static int thermal_power_estimator_set_limit(fwk_id_t id, uint32_t power_limit) +{ + FWK_LOG_INFO(MOD_NAME "set_limit() is not supported"); + + return FWK_E_SUPPORT; +} + +static struct interface_power_management_api thermal_power_estimator_api = { + .get_limit = thermal_power_estimator_get_limit, + .set_limit = thermal_power_estimator_set_limit, +}; + +/* + * Framework handler functions. + */ + +static int thermal_power_estimator_init( + fwk_id_t module_id, + unsigned int element_count, + const void *data) +{ + mod_ctx.dev_ctx_table = fwk_mm_calloc( + element_count, sizeof(struct mod_thermal_power_estimator_dev_ctx)); + mod_ctx.dev_ctx_count = element_count; + + return FWK_SUCCESS; +} + +static int thermal_power_estimator_dev_init( + fwk_id_t element_id, + unsigned int sub_element_count, + const void *data) +{ + struct mod_thermal_power_estimator_dev_ctx *dev_ctx; + + fwk_assert(data != NULL); + + dev_ctx = get_dev_ctx(element_id); + dev_ctx->config = (struct mod_thermal_power_estimator_dev_config *)data; + + return FWK_SUCCESS; +} + +static int thermal_power_estimator_bind(fwk_id_t id, unsigned int round) +{ + int status; + struct mod_thermal_power_estimator_dev_ctx *dev_ctx; + + if (round > 0) { + return FWK_SUCCESS; + } + + if (fwk_id_is_type(id, FWK_ID_TYPE_MODULE)) { + return FWK_SUCCESS; + } + + dev_ctx = get_dev_ctx(id); + fwk_assert(dev_ctx != NULL); + + /* Bind to sensor */ + status = fwk_module_bind( + dev_ctx->config->sensor_id, + dev_ctx->config->sensor_api_id, + &dev_ctx->sensor_api); + if (status != FWK_SUCCESS) { + return FWK_E_PANIC; + } + + /* Bind to PID Controller */ + status = fwk_module_bind( + dev_ctx->config->pid_controller_id, + dev_ctx->config->pid_controller_api_id, + &dev_ctx->pid_ctrl_api); + + return status; +} + +static int thermal_power_estimator_process_bind_request( + fwk_id_t source_id, + fwk_id_t target_id, + fwk_id_t api_id, + const void **api) +{ + enum mod_thermal_power_estimator_api_idx api_idx; + int status; + + api_idx = + (enum mod_thermal_power_estimator_api_idx)fwk_id_get_api_idx(api_id); + switch (api_idx) { + case MOD_THERMAL_POWER_ESTIMATOR_API_IDX_POWER_MANAGEMENT: + *api = &thermal_power_estimator_api; + status = FWK_SUCCESS; + break; + + default: + status = FWK_E_PARAM; + break; + } + + return status; +} + +const struct fwk_module module_thermal_power_estimator = { + .type = FWK_MODULE_TYPE_SERVICE, + .api_count = (unsigned int)MOD_THERMAL_POWER_ESTIMATOR_API_IDX_COUNT, + .event_count = (unsigned int)0, + .init = thermal_power_estimator_init, + .element_init = thermal_power_estimator_dev_init, + .bind = thermal_power_estimator_bind, + .process_bind_request = thermal_power_estimator_process_bind_request, +}; diff --git a/module/thermal_power_estimator/test/CMakeLists.txt b/module/thermal_power_estimator/test/CMakeLists.txt new file mode 100644 index 000000000..e96950e0f --- /dev/null +++ b/module/thermal_power_estimator/test/CMakeLists.txt @@ -0,0 +1,27 @@ +# +# Arm SCP/MCP Software +# Copyright (c) 2024, Arm Limited and Contributors. All rights reserved. +# +# SPDX-License-Identifier: BSD-3-Clause +# + +set(TEST_SRC mod_thermal_power_estimator) +set(TEST_FILE mod_thermal_power_estimator) + +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}/pid_controller/include) +list(APPEND OTHER_MODULE_INC ${MODULE_ROOT}/sensor/include) +list(APPEND OTHER_MODULE_INC ${SCP_ROOT}/interface/power_management) +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_module) +list(APPEND MOCK_REPLACEMENTS fwk_mm) +list(APPEND MOCK_REPLACEMENTS fwk_id) +list(APPEND MOCK_REPLACEMENTS fwk_core) + +include(${SCP_ROOT}/unit_test/module_common.cmake) diff --git a/module/thermal_power_estimator/test/fwk_module_idx.h b/module/thermal_power_estimator/test/fwk_module_idx.h new file mode 100644 index 000000000..a877598c3 --- /dev/null +++ b/module/thermal_power_estimator/test/fwk_module_idx.h @@ -0,0 +1,33 @@ +/* + * 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_THERMAL_POWER_ESTIMATOR, + FWK_MODULE_IDX_PID_CONTROLLER, + FWK_MODULE_IDX_SENSOR, + FWK_MODULE_IDX_FAKE, + FWK_MODULE_IDX_COUNT, +}; + +static const fwk_id_t fwk_module_id_thermal_power_estimator = + FWK_ID_MODULE_INIT(FWK_MODULE_IDX_THERMAL_POWER_ESTIMATOR); + +static const fwk_id_t fwk_module_id_pid_controller = + FWK_ID_MODULE_INIT(FWK_MODULE_IDX_PID_CONTROLLER); + +static const fwk_id_t fwk_module_id_sensor = + FWK_ID_MODULE_INIT(FWK_MODULE_IDX_SENSOR); + +static const fwk_id_t fwk_module_id_fake = + FWK_ID_MODULE_INIT(FWK_MODULE_IDX_FAKE); + +#endif /* TEST_FWK_MODULE_MODULE_IDX_H */ diff --git a/module/thermal_power_estimator/test/mocks/.clang-format b/module/thermal_power_estimator/test/mocks/.clang-format new file mode 100644 index 000000000..eeca2395f --- /dev/null +++ b/module/thermal_power_estimator/test/mocks/.clang-format @@ -0,0 +1,4 @@ +{ + "DisableFormat": true, + "SortIncludes": false, +} diff --git a/module/thermal_power_estimator/test/mocks/Mockmod_thermal_power_estimator_extra.c b/module/thermal_power_estimator/test/mocks/Mockmod_thermal_power_estimator_extra.c new file mode 100644 index 000000000..9209df41a --- /dev/null +++ b/module/thermal_power_estimator/test/mocks/Mockmod_thermal_power_estimator_extra.c @@ -0,0 +1,456 @@ +/* AUTOGENERATED FILE. DO NOT EDIT. */ +#include +#include +#include +#include "cmock.h" +#include "Mockmod_thermal_power_estimator_extra.h" + +static const char* CMockString_data = "data"; +static const char* CMockString_id = "id"; +static const char* CMockString_input = "input"; +static const char* CMockString_mod_pid_controller_update = "mod_pid_controller_update"; +static const char* CMockString_mod_sensor_get_data = "mod_sensor_get_data"; +static const char* CMockString_output = "output"; + +typedef struct _CMOCK_mod_pid_controller_update_CALL_INSTANCE +{ + UNITY_LINE_TYPE LineNumber; + char ExpectAnyArgsBool; + int ReturnVal; + fwk_id_t Expected_id; + int64_t Expected_input; + int64_t* Expected_output; + int Expected_output_Depth; + char ReturnThruPtr_output_Used; + int64_t* ReturnThruPtr_output_Val; + size_t ReturnThruPtr_output_Size; + char IgnoreArg_id; + char IgnoreArg_input; + char IgnoreArg_output; + +} CMOCK_mod_pid_controller_update_CALL_INSTANCE; + +typedef struct _CMOCK_mod_sensor_get_data_CALL_INSTANCE +{ + UNITY_LINE_TYPE LineNumber; + char ExpectAnyArgsBool; + int ReturnVal; + fwk_id_t Expected_id; + struct mod_sensor_data* Expected_data; + int Expected_data_Depth; + char ReturnThruPtr_data_Used; + struct mod_sensor_data* ReturnThruPtr_data_Val; + size_t ReturnThruPtr_data_Size; + char IgnoreArg_id; + char IgnoreArg_data; + +} CMOCK_mod_sensor_get_data_CALL_INSTANCE; + +static struct Mockmod_thermal_power_estimator_extraInstance +{ + char mod_pid_controller_update_IgnoreBool; + int mod_pid_controller_update_FinalReturn; + char mod_pid_controller_update_CallbackBool; + CMOCK_mod_pid_controller_update_CALLBACK mod_pid_controller_update_CallbackFunctionPointer; + int mod_pid_controller_update_CallbackCalls; + CMOCK_MEM_INDEX_TYPE mod_pid_controller_update_CallInstance; + char mod_sensor_get_data_IgnoreBool; + int mod_sensor_get_data_FinalReturn; + char mod_sensor_get_data_CallbackBool; + CMOCK_mod_sensor_get_data_CALLBACK mod_sensor_get_data_CallbackFunctionPointer; + int mod_sensor_get_data_CallbackCalls; + CMOCK_MEM_INDEX_TYPE mod_sensor_get_data_CallInstance; +} Mock; + +extern jmp_buf AbortFrame; + +void Mockmod_thermal_power_estimator_extra_Verify(void) +{ + UNITY_LINE_TYPE cmock_line = TEST_LINE_NUM; + CMOCK_MEM_INDEX_TYPE call_instance; + call_instance = Mock.mod_pid_controller_update_CallInstance; + if (Mock.mod_pid_controller_update_IgnoreBool) + call_instance = CMOCK_GUTS_NONE; + if (CMOCK_GUTS_NONE != call_instance) + { + UNITY_SET_DETAIL(CMockString_mod_pid_controller_update); + UNITY_TEST_FAIL(cmock_line, CMockStringCalledLess); + } + if (Mock.mod_pid_controller_update_CallbackFunctionPointer != NULL) + { + call_instance = CMOCK_GUTS_NONE; + (void)call_instance; + } + call_instance = Mock.mod_sensor_get_data_CallInstance; + if (Mock.mod_sensor_get_data_IgnoreBool) + call_instance = CMOCK_GUTS_NONE; + if (CMOCK_GUTS_NONE != call_instance) + { + UNITY_SET_DETAIL(CMockString_mod_sensor_get_data); + UNITY_TEST_FAIL(cmock_line, CMockStringCalledLess); + } + if (Mock.mod_sensor_get_data_CallbackFunctionPointer != NULL) + { + call_instance = CMOCK_GUTS_NONE; + (void)call_instance; + } +} + +void Mockmod_thermal_power_estimator_extra_Init(void) +{ + Mockmod_thermal_power_estimator_extra_Destroy(); +} + +void Mockmod_thermal_power_estimator_extra_Destroy(void) +{ + CMock_Guts_MemFreeAll(); + memset(&Mock, 0, sizeof(Mock)); +} + +int mod_pid_controller_update(fwk_id_t id, int64_t input, int64_t* output) +{ + UNITY_LINE_TYPE cmock_line = TEST_LINE_NUM; + CMOCK_mod_pid_controller_update_CALL_INSTANCE* cmock_call_instance; + UNITY_SET_DETAIL(CMockString_mod_pid_controller_update); + cmock_call_instance = (CMOCK_mod_pid_controller_update_CALL_INSTANCE*)CMock_Guts_GetAddressFor(Mock.mod_pid_controller_update_CallInstance); + Mock.mod_pid_controller_update_CallInstance = CMock_Guts_MemNext(Mock.mod_pid_controller_update_CallInstance); + if (Mock.mod_pid_controller_update_IgnoreBool) + { + UNITY_CLR_DETAILS(); + if (cmock_call_instance == NULL) + return Mock.mod_pid_controller_update_FinalReturn; + Mock.mod_pid_controller_update_FinalReturn = cmock_call_instance->ReturnVal; + return cmock_call_instance->ReturnVal; + } + if (!Mock.mod_pid_controller_update_CallbackBool && + Mock.mod_pid_controller_update_CallbackFunctionPointer != NULL) + { + int cmock_cb_ret = Mock.mod_pid_controller_update_CallbackFunctionPointer(id, input, output, Mock.mod_pid_controller_update_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_id) + { + UNITY_SET_DETAILS(CMockString_mod_pid_controller_update,CMockString_id); + UNITY_TEST_ASSERT_EQUAL_MEMORY((void*)(&cmock_call_instance->Expected_id), (void*)(&id), sizeof(fwk_id_t), cmock_line, CMockStringMismatch); + } + if (!cmock_call_instance->IgnoreArg_input) + { + UNITY_SET_DETAILS(CMockString_mod_pid_controller_update,CMockString_input); + UNITY_TEST_ASSERT_EQUAL_MEMORY((void*)(&cmock_call_instance->Expected_input), (void*)(&input), sizeof(int64_t), cmock_line, CMockStringMismatch); + } + if (!cmock_call_instance->IgnoreArg_output) + { + UNITY_SET_DETAILS(CMockString_mod_pid_controller_update,CMockString_output); + if (cmock_call_instance->Expected_output == NULL) + { UNITY_TEST_ASSERT_NULL(output, cmock_line, CMockStringExpNULL); } + else + { UNITY_TEST_ASSERT_EQUAL_MEMORY_ARRAY((void*)(cmock_call_instance->Expected_output), (void*)(output), sizeof(int64_t), cmock_call_instance->Expected_output_Depth, cmock_line, CMockStringMismatch); } + } + } + if (Mock.mod_pid_controller_update_CallbackFunctionPointer != NULL) + { + cmock_call_instance->ReturnVal = Mock.mod_pid_controller_update_CallbackFunctionPointer(id, input, output, Mock.mod_pid_controller_update_CallbackCalls++); + } + if (cmock_call_instance->ReturnThruPtr_output_Used) + { + UNITY_TEST_ASSERT_NOT_NULL(output, cmock_line, CMockStringPtrIsNULL); + memcpy((void*)output, (void*)cmock_call_instance->ReturnThruPtr_output_Val, + cmock_call_instance->ReturnThruPtr_output_Size); + } + UNITY_CLR_DETAILS(); + return cmock_call_instance->ReturnVal; +} + +void CMockExpectParameters_mod_pid_controller_update(CMOCK_mod_pid_controller_update_CALL_INSTANCE* cmock_call_instance, fwk_id_t id, int64_t input, int64_t* output, int output_Depth); +void CMockExpectParameters_mod_pid_controller_update(CMOCK_mod_pid_controller_update_CALL_INSTANCE* cmock_call_instance, fwk_id_t id, int64_t input, int64_t* output, int output_Depth) +{ + memcpy((void*)(&cmock_call_instance->Expected_id), (void*)(&id), + sizeof(fwk_id_t[sizeof(id) == sizeof(fwk_id_t) ? 1 : -1])); /* add fwk_id_t to :treat_as_array if this causes an error */ + cmock_call_instance->IgnoreArg_id = 0; + memcpy((void*)(&cmock_call_instance->Expected_input), (void*)(&input), + sizeof(int64_t[sizeof(input) == sizeof(int64_t) ? 1 : -1])); /* add int64_t to :treat_as_array if this causes an error */ + cmock_call_instance->IgnoreArg_input = 0; + cmock_call_instance->Expected_output = output; + cmock_call_instance->Expected_output_Depth = output_Depth; + cmock_call_instance->IgnoreArg_output = 0; + cmock_call_instance->ReturnThruPtr_output_Used = 0; +} + +void mod_pid_controller_update_CMockIgnoreAndReturn(UNITY_LINE_TYPE cmock_line, int cmock_to_return) +{ + CMOCK_MEM_INDEX_TYPE cmock_guts_index = CMock_Guts_MemNew(sizeof(CMOCK_mod_pid_controller_update_CALL_INSTANCE)); + CMOCK_mod_pid_controller_update_CALL_INSTANCE* cmock_call_instance = (CMOCK_mod_pid_controller_update_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.mod_pid_controller_update_CallInstance = CMock_Guts_MemChain(Mock.mod_pid_controller_update_CallInstance, cmock_guts_index); + Mock.mod_pid_controller_update_IgnoreBool = (char)0; + cmock_call_instance->LineNumber = cmock_line; + cmock_call_instance->ExpectAnyArgsBool = (char)0; + cmock_call_instance->ReturnVal = cmock_to_return; + Mock.mod_pid_controller_update_IgnoreBool = (char)1; +} + +void mod_pid_controller_update_CMockStopIgnore(void) +{ + if(Mock.mod_pid_controller_update_IgnoreBool) + Mock.mod_pid_controller_update_CallInstance = CMock_Guts_MemNext(Mock.mod_pid_controller_update_CallInstance); + Mock.mod_pid_controller_update_IgnoreBool = (char)0; +} + +void mod_pid_controller_update_CMockExpectAnyArgsAndReturn(UNITY_LINE_TYPE cmock_line, int cmock_to_return) +{ + CMOCK_MEM_INDEX_TYPE cmock_guts_index = CMock_Guts_MemNew(sizeof(CMOCK_mod_pid_controller_update_CALL_INSTANCE)); + CMOCK_mod_pid_controller_update_CALL_INSTANCE* cmock_call_instance = (CMOCK_mod_pid_controller_update_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.mod_pid_controller_update_CallInstance = CMock_Guts_MemChain(Mock.mod_pid_controller_update_CallInstance, cmock_guts_index); + Mock.mod_pid_controller_update_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 mod_pid_controller_update_CMockExpectAndReturn(UNITY_LINE_TYPE cmock_line, fwk_id_t id, int64_t input, int64_t* output, int cmock_to_return) +{ + CMOCK_MEM_INDEX_TYPE cmock_guts_index = CMock_Guts_MemNew(sizeof(CMOCK_mod_pid_controller_update_CALL_INSTANCE)); + CMOCK_mod_pid_controller_update_CALL_INSTANCE* cmock_call_instance = (CMOCK_mod_pid_controller_update_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.mod_pid_controller_update_CallInstance = CMock_Guts_MemChain(Mock.mod_pid_controller_update_CallInstance, cmock_guts_index); + Mock.mod_pid_controller_update_IgnoreBool = (char)0; + cmock_call_instance->LineNumber = cmock_line; + cmock_call_instance->ExpectAnyArgsBool = (char)0; + CMockExpectParameters_mod_pid_controller_update(cmock_call_instance, id, input, output, 1); + cmock_call_instance->ReturnVal = cmock_to_return; +} + +void mod_pid_controller_update_AddCallback(CMOCK_mod_pid_controller_update_CALLBACK Callback) +{ + Mock.mod_pid_controller_update_IgnoreBool = (char)0; + Mock.mod_pid_controller_update_CallbackBool = (char)1; + Mock.mod_pid_controller_update_CallbackFunctionPointer = Callback; +} + +void mod_pid_controller_update_Stub(CMOCK_mod_pid_controller_update_CALLBACK Callback) +{ + Mock.mod_pid_controller_update_IgnoreBool = (char)0; + Mock.mod_pid_controller_update_CallbackBool = (char)0; + Mock.mod_pid_controller_update_CallbackFunctionPointer = Callback; +} + +void mod_pid_controller_update_CMockExpectWithArrayAndReturn(UNITY_LINE_TYPE cmock_line, fwk_id_t id, int64_t input, int64_t* output, int output_Depth, int cmock_to_return) +{ + CMOCK_MEM_INDEX_TYPE cmock_guts_index = CMock_Guts_MemNew(sizeof(CMOCK_mod_pid_controller_update_CALL_INSTANCE)); + CMOCK_mod_pid_controller_update_CALL_INSTANCE* cmock_call_instance = (CMOCK_mod_pid_controller_update_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.mod_pid_controller_update_CallInstance = CMock_Guts_MemChain(Mock.mod_pid_controller_update_CallInstance, cmock_guts_index); + Mock.mod_pid_controller_update_IgnoreBool = (char)0; + cmock_call_instance->LineNumber = cmock_line; + cmock_call_instance->ExpectAnyArgsBool = (char)0; + CMockExpectParameters_mod_pid_controller_update(cmock_call_instance, id, input, output, output_Depth); + cmock_call_instance->ReturnVal = cmock_to_return; +} + +void mod_pid_controller_update_CMockReturnMemThruPtr_output(UNITY_LINE_TYPE cmock_line, int64_t* output, size_t cmock_size) +{ + CMOCK_mod_pid_controller_update_CALL_INSTANCE* cmock_call_instance = (CMOCK_mod_pid_controller_update_CALL_INSTANCE*)CMock_Guts_GetAddressFor(CMock_Guts_MemEndOfChain(Mock.mod_pid_controller_update_CallInstance)); + UNITY_TEST_ASSERT_NOT_NULL(cmock_call_instance, cmock_line, CMockStringPtrPreExp); + cmock_call_instance->ReturnThruPtr_output_Used = 1; + cmock_call_instance->ReturnThruPtr_output_Val = output; + cmock_call_instance->ReturnThruPtr_output_Size = cmock_size; +} + +void mod_pid_controller_update_CMockIgnoreArg_id(UNITY_LINE_TYPE cmock_line) +{ + CMOCK_mod_pid_controller_update_CALL_INSTANCE* cmock_call_instance = (CMOCK_mod_pid_controller_update_CALL_INSTANCE*)CMock_Guts_GetAddressFor(CMock_Guts_MemEndOfChain(Mock.mod_pid_controller_update_CallInstance)); + UNITY_TEST_ASSERT_NOT_NULL(cmock_call_instance, cmock_line, CMockStringIgnPreExp); + cmock_call_instance->IgnoreArg_id = 1; +} + +void mod_pid_controller_update_CMockIgnoreArg_input(UNITY_LINE_TYPE cmock_line) +{ + CMOCK_mod_pid_controller_update_CALL_INSTANCE* cmock_call_instance = (CMOCK_mod_pid_controller_update_CALL_INSTANCE*)CMock_Guts_GetAddressFor(CMock_Guts_MemEndOfChain(Mock.mod_pid_controller_update_CallInstance)); + UNITY_TEST_ASSERT_NOT_NULL(cmock_call_instance, cmock_line, CMockStringIgnPreExp); + cmock_call_instance->IgnoreArg_input = 1; +} + +void mod_pid_controller_update_CMockIgnoreArg_output(UNITY_LINE_TYPE cmock_line) +{ + CMOCK_mod_pid_controller_update_CALL_INSTANCE* cmock_call_instance = (CMOCK_mod_pid_controller_update_CALL_INSTANCE*)CMock_Guts_GetAddressFor(CMock_Guts_MemEndOfChain(Mock.mod_pid_controller_update_CallInstance)); + UNITY_TEST_ASSERT_NOT_NULL(cmock_call_instance, cmock_line, CMockStringIgnPreExp); + cmock_call_instance->IgnoreArg_output = 1; +} + +int mod_sensor_get_data(fwk_id_t id, struct mod_sensor_data* data) +{ + UNITY_LINE_TYPE cmock_line = TEST_LINE_NUM; + CMOCK_mod_sensor_get_data_CALL_INSTANCE* cmock_call_instance; + UNITY_SET_DETAIL(CMockString_mod_sensor_get_data); + cmock_call_instance = (CMOCK_mod_sensor_get_data_CALL_INSTANCE*)CMock_Guts_GetAddressFor(Mock.mod_sensor_get_data_CallInstance); + Mock.mod_sensor_get_data_CallInstance = CMock_Guts_MemNext(Mock.mod_sensor_get_data_CallInstance); + if (Mock.mod_sensor_get_data_IgnoreBool) + { + UNITY_CLR_DETAILS(); + if (cmock_call_instance == NULL) + return Mock.mod_sensor_get_data_FinalReturn; + Mock.mod_sensor_get_data_FinalReturn = cmock_call_instance->ReturnVal; + return cmock_call_instance->ReturnVal; + } + if (!Mock.mod_sensor_get_data_CallbackBool && + Mock.mod_sensor_get_data_CallbackFunctionPointer != NULL) + { + int cmock_cb_ret = Mock.mod_sensor_get_data_CallbackFunctionPointer(id, data, Mock.mod_sensor_get_data_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_id) + { + UNITY_SET_DETAILS(CMockString_mod_sensor_get_data,CMockString_id); + UNITY_TEST_ASSERT_EQUAL_MEMORY((void*)(&cmock_call_instance->Expected_id), (void*)(&id), sizeof(fwk_id_t), cmock_line, CMockStringMismatch); + } + if (!cmock_call_instance->IgnoreArg_data) + { + UNITY_SET_DETAILS(CMockString_mod_sensor_get_data,CMockString_data); + if (cmock_call_instance->Expected_data == NULL) + { UNITY_TEST_ASSERT_NULL(data, cmock_line, CMockStringExpNULL); } + else + { UNITY_TEST_ASSERT_EQUAL_MEMORY_ARRAY((void*)(cmock_call_instance->Expected_data), (void*)(data), sizeof(struct mod_sensor_data), cmock_call_instance->Expected_data_Depth, cmock_line, CMockStringMismatch); } + } + } + if (Mock.mod_sensor_get_data_CallbackFunctionPointer != NULL) + { + cmock_call_instance->ReturnVal = Mock.mod_sensor_get_data_CallbackFunctionPointer(id, data, Mock.mod_sensor_get_data_CallbackCalls++); + } + if (cmock_call_instance->ReturnThruPtr_data_Used) + { + UNITY_TEST_ASSERT_NOT_NULL(data, cmock_line, CMockStringPtrIsNULL); + memcpy((void*)data, (void*)cmock_call_instance->ReturnThruPtr_data_Val, + cmock_call_instance->ReturnThruPtr_data_Size); + } + UNITY_CLR_DETAILS(); + return cmock_call_instance->ReturnVal; +} + +void CMockExpectParameters_mod_sensor_get_data(CMOCK_mod_sensor_get_data_CALL_INSTANCE* cmock_call_instance, fwk_id_t id, struct mod_sensor_data* data, int data_Depth); +void CMockExpectParameters_mod_sensor_get_data(CMOCK_mod_sensor_get_data_CALL_INSTANCE* cmock_call_instance, fwk_id_t id, struct mod_sensor_data* data, int data_Depth) +{ + memcpy((void*)(&cmock_call_instance->Expected_id), (void*)(&id), + sizeof(fwk_id_t[sizeof(id) == sizeof(fwk_id_t) ? 1 : -1])); /* add fwk_id_t to :treat_as_array if this causes an error */ + cmock_call_instance->IgnoreArg_id = 0; + cmock_call_instance->Expected_data = data; + cmock_call_instance->Expected_data_Depth = data_Depth; + cmock_call_instance->IgnoreArg_data = 0; + cmock_call_instance->ReturnThruPtr_data_Used = 0; +} + +void mod_sensor_get_data_CMockIgnoreAndReturn(UNITY_LINE_TYPE cmock_line, int cmock_to_return) +{ + CMOCK_MEM_INDEX_TYPE cmock_guts_index = CMock_Guts_MemNew(sizeof(CMOCK_mod_sensor_get_data_CALL_INSTANCE)); + CMOCK_mod_sensor_get_data_CALL_INSTANCE* cmock_call_instance = (CMOCK_mod_sensor_get_data_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.mod_sensor_get_data_CallInstance = CMock_Guts_MemChain(Mock.mod_sensor_get_data_CallInstance, cmock_guts_index); + Mock.mod_sensor_get_data_IgnoreBool = (char)0; + cmock_call_instance->LineNumber = cmock_line; + cmock_call_instance->ExpectAnyArgsBool = (char)0; + cmock_call_instance->ReturnVal = cmock_to_return; + Mock.mod_sensor_get_data_IgnoreBool = (char)1; +} + +void mod_sensor_get_data_CMockStopIgnore(void) +{ + if(Mock.mod_sensor_get_data_IgnoreBool) + Mock.mod_sensor_get_data_CallInstance = CMock_Guts_MemNext(Mock.mod_sensor_get_data_CallInstance); + Mock.mod_sensor_get_data_IgnoreBool = (char)0; +} + +void mod_sensor_get_data_CMockExpectAnyArgsAndReturn(UNITY_LINE_TYPE cmock_line, int cmock_to_return) +{ + CMOCK_MEM_INDEX_TYPE cmock_guts_index = CMock_Guts_MemNew(sizeof(CMOCK_mod_sensor_get_data_CALL_INSTANCE)); + CMOCK_mod_sensor_get_data_CALL_INSTANCE* cmock_call_instance = (CMOCK_mod_sensor_get_data_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.mod_sensor_get_data_CallInstance = CMock_Guts_MemChain(Mock.mod_sensor_get_data_CallInstance, cmock_guts_index); + Mock.mod_sensor_get_data_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 mod_sensor_get_data_CMockExpectAndReturn(UNITY_LINE_TYPE cmock_line, fwk_id_t id, struct mod_sensor_data* data, int cmock_to_return) +{ + CMOCK_MEM_INDEX_TYPE cmock_guts_index = CMock_Guts_MemNew(sizeof(CMOCK_mod_sensor_get_data_CALL_INSTANCE)); + CMOCK_mod_sensor_get_data_CALL_INSTANCE* cmock_call_instance = (CMOCK_mod_sensor_get_data_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.mod_sensor_get_data_CallInstance = CMock_Guts_MemChain(Mock.mod_sensor_get_data_CallInstance, cmock_guts_index); + Mock.mod_sensor_get_data_IgnoreBool = (char)0; + cmock_call_instance->LineNumber = cmock_line; + cmock_call_instance->ExpectAnyArgsBool = (char)0; + CMockExpectParameters_mod_sensor_get_data(cmock_call_instance, id, data, 1); + cmock_call_instance->ReturnVal = cmock_to_return; +} + +void mod_sensor_get_data_AddCallback(CMOCK_mod_sensor_get_data_CALLBACK Callback) +{ + Mock.mod_sensor_get_data_IgnoreBool = (char)0; + Mock.mod_sensor_get_data_CallbackBool = (char)1; + Mock.mod_sensor_get_data_CallbackFunctionPointer = Callback; +} + +void mod_sensor_get_data_Stub(CMOCK_mod_sensor_get_data_CALLBACK Callback) +{ + Mock.mod_sensor_get_data_IgnoreBool = (char)0; + Mock.mod_sensor_get_data_CallbackBool = (char)0; + Mock.mod_sensor_get_data_CallbackFunctionPointer = Callback; +} + +void mod_sensor_get_data_CMockExpectWithArrayAndReturn(UNITY_LINE_TYPE cmock_line, fwk_id_t id, struct mod_sensor_data* data, int data_Depth, int cmock_to_return) +{ + CMOCK_MEM_INDEX_TYPE cmock_guts_index = CMock_Guts_MemNew(sizeof(CMOCK_mod_sensor_get_data_CALL_INSTANCE)); + CMOCK_mod_sensor_get_data_CALL_INSTANCE* cmock_call_instance = (CMOCK_mod_sensor_get_data_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.mod_sensor_get_data_CallInstance = CMock_Guts_MemChain(Mock.mod_sensor_get_data_CallInstance, cmock_guts_index); + Mock.mod_sensor_get_data_IgnoreBool = (char)0; + cmock_call_instance->LineNumber = cmock_line; + cmock_call_instance->ExpectAnyArgsBool = (char)0; + CMockExpectParameters_mod_sensor_get_data(cmock_call_instance, id, data, data_Depth); + cmock_call_instance->ReturnVal = cmock_to_return; +} + +void mod_sensor_get_data_CMockReturnMemThruPtr_data(UNITY_LINE_TYPE cmock_line, struct mod_sensor_data* data, size_t cmock_size) +{ + CMOCK_mod_sensor_get_data_CALL_INSTANCE* cmock_call_instance = (CMOCK_mod_sensor_get_data_CALL_INSTANCE*)CMock_Guts_GetAddressFor(CMock_Guts_MemEndOfChain(Mock.mod_sensor_get_data_CallInstance)); + UNITY_TEST_ASSERT_NOT_NULL(cmock_call_instance, cmock_line, CMockStringPtrPreExp); + cmock_call_instance->ReturnThruPtr_data_Used = 1; + cmock_call_instance->ReturnThruPtr_data_Val = data; + cmock_call_instance->ReturnThruPtr_data_Size = cmock_size; +} + +void mod_sensor_get_data_CMockIgnoreArg_id(UNITY_LINE_TYPE cmock_line) +{ + CMOCK_mod_sensor_get_data_CALL_INSTANCE* cmock_call_instance = (CMOCK_mod_sensor_get_data_CALL_INSTANCE*)CMock_Guts_GetAddressFor(CMock_Guts_MemEndOfChain(Mock.mod_sensor_get_data_CallInstance)); + UNITY_TEST_ASSERT_NOT_NULL(cmock_call_instance, cmock_line, CMockStringIgnPreExp); + cmock_call_instance->IgnoreArg_id = 1; +} + +void mod_sensor_get_data_CMockIgnoreArg_data(UNITY_LINE_TYPE cmock_line) +{ + CMOCK_mod_sensor_get_data_CALL_INSTANCE* cmock_call_instance = (CMOCK_mod_sensor_get_data_CALL_INSTANCE*)CMock_Guts_GetAddressFor(CMock_Guts_MemEndOfChain(Mock.mod_sensor_get_data_CallInstance)); + UNITY_TEST_ASSERT_NOT_NULL(cmock_call_instance, cmock_line, CMockStringIgnPreExp); + cmock_call_instance->IgnoreArg_data = 1; +} + diff --git a/module/thermal_power_estimator/test/mocks/Mockmod_thermal_power_estimator_extra.h b/module/thermal_power_estimator/test/mocks/Mockmod_thermal_power_estimator_extra.h new file mode 100644 index 000000000..601dcbbb3 --- /dev/null +++ b/module/thermal_power_estimator/test/mocks/Mockmod_thermal_power_estimator_extra.h @@ -0,0 +1,80 @@ +/* AUTOGENERATED FILE. DO NOT EDIT. */ +#ifndef _MOCKMOD_THERMAL_POWER_ESTIMATOR_EXTRA_H +#define _MOCKMOD_THERMAL_POWER_ESTIMATOR_EXTRA_H + +#include "unity.h" +#include "mod_thermal_power_estimator_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_thermal_power_estimator_extra_Init(void); +void Mockmod_thermal_power_estimator_extra_Destroy(void); +void Mockmod_thermal_power_estimator_extra_Verify(void); + + + + +#define mod_pid_controller_update_IgnoreAndReturn(cmock_retval) mod_pid_controller_update_CMockIgnoreAndReturn(__LINE__, cmock_retval) +void mod_pid_controller_update_CMockIgnoreAndReturn(UNITY_LINE_TYPE cmock_line, int cmock_to_return); +#define mod_pid_controller_update_StopIgnore() mod_pid_controller_update_CMockStopIgnore() +void mod_pid_controller_update_CMockStopIgnore(void); +#define mod_pid_controller_update_ExpectAnyArgsAndReturn(cmock_retval) mod_pid_controller_update_CMockExpectAnyArgsAndReturn(__LINE__, cmock_retval) +void mod_pid_controller_update_CMockExpectAnyArgsAndReturn(UNITY_LINE_TYPE cmock_line, int cmock_to_return); +#define mod_pid_controller_update_ExpectAndReturn(id, input, output, cmock_retval) mod_pid_controller_update_CMockExpectAndReturn(__LINE__, id, input, output, cmock_retval) +void mod_pid_controller_update_CMockExpectAndReturn(UNITY_LINE_TYPE cmock_line, fwk_id_t id, int64_t input, int64_t* output, int cmock_to_return); +typedef int (* CMOCK_mod_pid_controller_update_CALLBACK)(fwk_id_t id, int64_t input, int64_t* output, int cmock_num_calls); +void mod_pid_controller_update_AddCallback(CMOCK_mod_pid_controller_update_CALLBACK Callback); +void mod_pid_controller_update_Stub(CMOCK_mod_pid_controller_update_CALLBACK Callback); +#define mod_pid_controller_update_StubWithCallback mod_pid_controller_update_Stub +#define mod_pid_controller_update_ExpectWithArrayAndReturn(id, input, output, output_Depth, cmock_retval) mod_pid_controller_update_CMockExpectWithArrayAndReturn(__LINE__, id, input, output, output_Depth, cmock_retval) +void mod_pid_controller_update_CMockExpectWithArrayAndReturn(UNITY_LINE_TYPE cmock_line, fwk_id_t id, int64_t input, int64_t* output, int output_Depth, int cmock_to_return); +#define mod_pid_controller_update_ReturnThruPtr_output(output) mod_pid_controller_update_CMockReturnMemThruPtr_output(__LINE__, output, sizeof(int64_t)) +#define mod_pid_controller_update_ReturnArrayThruPtr_output(output, cmock_len) mod_pid_controller_update_CMockReturnMemThruPtr_output(__LINE__, output, cmock_len * sizeof(*output)) +#define mod_pid_controller_update_ReturnMemThruPtr_output(output, cmock_size) mod_pid_controller_update_CMockReturnMemThruPtr_output(__LINE__, output, cmock_size) +void mod_pid_controller_update_CMockReturnMemThruPtr_output(UNITY_LINE_TYPE cmock_line, int64_t* output, size_t cmock_size); +#define mod_pid_controller_update_IgnoreArg_id() mod_pid_controller_update_CMockIgnoreArg_id(__LINE__) +void mod_pid_controller_update_CMockIgnoreArg_id(UNITY_LINE_TYPE cmock_line); +#define mod_pid_controller_update_IgnoreArg_input() mod_pid_controller_update_CMockIgnoreArg_input(__LINE__) +void mod_pid_controller_update_CMockIgnoreArg_input(UNITY_LINE_TYPE cmock_line); +#define mod_pid_controller_update_IgnoreArg_output() mod_pid_controller_update_CMockIgnoreArg_output(__LINE__) +void mod_pid_controller_update_CMockIgnoreArg_output(UNITY_LINE_TYPE cmock_line); +#define mod_sensor_get_data_IgnoreAndReturn(cmock_retval) mod_sensor_get_data_CMockIgnoreAndReturn(__LINE__, cmock_retval) +void mod_sensor_get_data_CMockIgnoreAndReturn(UNITY_LINE_TYPE cmock_line, int cmock_to_return); +#define mod_sensor_get_data_StopIgnore() mod_sensor_get_data_CMockStopIgnore() +void mod_sensor_get_data_CMockStopIgnore(void); +#define mod_sensor_get_data_ExpectAnyArgsAndReturn(cmock_retval) mod_sensor_get_data_CMockExpectAnyArgsAndReturn(__LINE__, cmock_retval) +void mod_sensor_get_data_CMockExpectAnyArgsAndReturn(UNITY_LINE_TYPE cmock_line, int cmock_to_return); +#define mod_sensor_get_data_ExpectAndReturn(id, data, cmock_retval) mod_sensor_get_data_CMockExpectAndReturn(__LINE__, id, data, cmock_retval) +void mod_sensor_get_data_CMockExpectAndReturn(UNITY_LINE_TYPE cmock_line, fwk_id_t id, struct mod_sensor_data* data, int cmock_to_return); +typedef int (* CMOCK_mod_sensor_get_data_CALLBACK)(fwk_id_t id, struct mod_sensor_data* data, int cmock_num_calls); +void mod_sensor_get_data_AddCallback(CMOCK_mod_sensor_get_data_CALLBACK Callback); +void mod_sensor_get_data_Stub(CMOCK_mod_sensor_get_data_CALLBACK Callback); +#define mod_sensor_get_data_StubWithCallback mod_sensor_get_data_Stub +#define mod_sensor_get_data_ExpectWithArrayAndReturn(id, data, data_Depth, cmock_retval) mod_sensor_get_data_CMockExpectWithArrayAndReturn(__LINE__, id, data, data_Depth, cmock_retval) +void mod_sensor_get_data_CMockExpectWithArrayAndReturn(UNITY_LINE_TYPE cmock_line, fwk_id_t id, struct mod_sensor_data* data, int data_Depth, int cmock_to_return); +#define mod_sensor_get_data_ReturnThruPtr_data(data) mod_sensor_get_data_CMockReturnMemThruPtr_data(__LINE__, data, sizeof(struct mod_sensor_data)) +#define mod_sensor_get_data_ReturnArrayThruPtr_data(data, cmock_len) mod_sensor_get_data_CMockReturnMemThruPtr_data(__LINE__, data, cmock_len * sizeof(*data)) +#define mod_sensor_get_data_ReturnMemThruPtr_data(data, cmock_size) mod_sensor_get_data_CMockReturnMemThruPtr_data(__LINE__, data, cmock_size) +void mod_sensor_get_data_CMockReturnMemThruPtr_data(UNITY_LINE_TYPE cmock_line, struct mod_sensor_data* data, size_t cmock_size); +#define mod_sensor_get_data_IgnoreArg_id() mod_sensor_get_data_CMockIgnoreArg_id(__LINE__) +void mod_sensor_get_data_CMockIgnoreArg_id(UNITY_LINE_TYPE cmock_line); +#define mod_sensor_get_data_IgnoreArg_data() mod_sensor_get_data_CMockIgnoreArg_data(__LINE__) +void mod_sensor_get_data_CMockIgnoreArg_data(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/thermal_power_estimator/test/mod_thermal_power_estimator_extra.h b/module/thermal_power_estimator/test/mod_thermal_power_estimator_extra.h new file mode 100644 index 000000000..d18b1b9f3 --- /dev/null +++ b/module/thermal_power_estimator/test/mod_thermal_power_estimator_extra.h @@ -0,0 +1,18 @@ +/* + * Arm SCP/MCP Software + * Copyright (c) 2024, Arm Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + * + * Description: + * Thermal Power Estimator unit test support. + */ + +#include +#include + +/*! PID Controller update */ +int mod_pid_controller_update(fwk_id_t id, int64_t input, int64_t *output); + +/*! Read sensor data. */ +int mod_sensor_get_data(fwk_id_t id, struct mod_sensor_data *data); diff --git a/module/thermal_power_estimator/test/mod_thermal_power_estimator_unit_test.c b/module/thermal_power_estimator/test/mod_thermal_power_estimator_unit_test.c new file mode 100644 index 000000000..6c0009000 --- /dev/null +++ b/module/thermal_power_estimator/test/mod_thermal_power_estimator_unit_test.c @@ -0,0 +1,477 @@ +/* + * Arm SCP/MCP Software + * Copyright (c) 2024, Arm Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include "scp_unity.h" +#include "unity.h" + +#include +#include +#include +#include +#include + +#include UNIT_TEST_SRC + +enum mod_thermal_power_estimator_elem_id { + THERMAL_POWER_ESTIMATOR_FAKE_ELEM_IDX_0, + THERMAL_POWER_ESTIMATOR_FAKE_ELEM_IDX_COUNT, +}; + +static void thermal_power_estimator_init_one_element( + struct mod_thermal_power_estimator_dev_ctx *mock_dev_ctx, + struct mod_thermal_power_estimator_dev_config *mock_config) +{ + mod_ctx.dev_ctx_count = THERMAL_POWER_ESTIMATOR_FAKE_ELEM_IDX_COUNT; + mod_ctx.dev_ctx_table = mock_dev_ctx; + mock_dev_ctx->config = mock_config; +} + +struct mod_sensor_api mock_sensor_api = { + .get_data = mod_sensor_get_data, +}; + +struct mod_pid_controller_api mock_pid_controller_api = { + .update = mod_pid_controller_update, +}; + +void setUp(void) +{ +} + +void tearDown(void) +{ +} + +/* Test thermal power estimator module initialization */ +static void test_thermal_power_estimator_init_success(void) +{ + struct mod_thermal_power_estimator_dev_ctx + return_table[THERMAL_POWER_ESTIMATOR_FAKE_ELEM_IDX_COUNT]; + unsigned int element_count = THERMAL_POWER_ESTIMATOR_FAKE_ELEM_IDX_COUNT; + int status; + + fwk_mm_calloc_ExpectAndReturn( + element_count, + sizeof(struct mod_thermal_power_estimator_dev_ctx), + (void *)&return_table); + + status = thermal_power_estimator_init( + fwk_module_id_thermal_power_estimator, element_count, NULL); + + TEST_ASSERT_EQUAL(FWK_SUCCESS, status); + TEST_ASSERT_EQUAL_PTR(&return_table, mod_ctx.dev_ctx_table); + TEST_ASSERT_EQUAL(element_count, mod_ctx.dev_ctx_count); +} + +static void test_thermal_power_estimator_dev_init_success(void) +{ + fwk_id_t element_id = FWK_ID_ELEMENT_INIT( + FWK_MODULE_IDX_THERMAL_POWER_ESTIMATOR, + THERMAL_POWER_ESTIMATOR_FAKE_ELEM_IDX_0); + struct mod_thermal_power_estimator_dev_ctx mock_dev_ctx; + struct mod_thermal_power_estimator_dev_config mock_config = { .tdp = 100 }; + unsigned int unused = 0; + int status; + + thermal_power_estimator_init_one_element(&mock_dev_ctx, &mock_config); + fwk_id_get_element_idx_ExpectAndReturn( + element_id, THERMAL_POWER_ESTIMATOR_FAKE_ELEM_IDX_0); + + status = thermal_power_estimator_dev_init( + element_id, unused, (const void *)&mock_config); + + TEST_ASSERT_EQUAL(FWK_SUCCESS, status); + TEST_ASSERT_EQUAL_PTR(&mock_config, mock_dev_ctx.config); +} + +static void test_thermal_power_estimator_bind_success(void) +{ + fwk_id_t element_id = FWK_ID_ELEMENT_INIT( + FWK_MODULE_IDX_THERMAL_POWER_ESTIMATOR, + THERMAL_POWER_ESTIMATOR_FAKE_ELEM_IDX_0); + struct mod_thermal_power_estimator_dev_ctx mock_dev_ctx; + struct mod_thermal_power_estimator_dev_config mock_config = { + .sensor_id = FWK_ID_ELEMENT_INIT(FWK_MODULE_IDX_SENSOR, 0), + .sensor_api_id = FWK_ID_API_INIT(FWK_MODULE_IDX_SENSOR, 0), + .pid_controller_id = + FWK_ID_ELEMENT_INIT(FWK_MODULE_IDX_PID_CONTROLLER, 0), + .pid_controller_api_id = + FWK_ID_API_INIT(FWK_MODULE_IDX_PID_CONTROLLER, 0) + }; + unsigned int round; + int status; + + round = 1; + status = thermal_power_estimator_bind(element_id, round); + TEST_ASSERT_EQUAL(FWK_SUCCESS, status); + + round = 0; + fwk_id_is_type_ExpectAnyArgsAndReturn(true); + status = thermal_power_estimator_bind(element_id, round); + TEST_ASSERT_EQUAL(FWK_SUCCESS, status); + + round = 0; + thermal_power_estimator_init_one_element(&mock_dev_ctx, &mock_config); + fwk_id_is_type_ExpectAnyArgsAndReturn(false); + fwk_id_get_element_idx_ExpectAndReturn( + element_id, THERMAL_POWER_ESTIMATOR_FAKE_ELEM_IDX_0); + + fwk_module_bind_ExpectAndReturn( + mock_config.sensor_id, + mock_config.sensor_api_id, + &mock_dev_ctx.sensor_api, + FWK_SUCCESS); + fwk_module_bind_ExpectAndReturn( + mock_config.pid_controller_id, + mock_config.pid_controller_api_id, + &mock_dev_ctx.pid_ctrl_api, + FWK_SUCCESS); + + status = thermal_power_estimator_bind(element_id, round); + TEST_ASSERT_EQUAL(FWK_SUCCESS, status); +} + +static void test_thermal_power_estimator_bind_sensor_bind_fail(void) +{ + fwk_id_t element_id = FWK_ID_ELEMENT_INIT( + FWK_MODULE_IDX_THERMAL_POWER_ESTIMATOR, + THERMAL_POWER_ESTIMATOR_FAKE_ELEM_IDX_0); + struct mod_thermal_power_estimator_dev_ctx mock_dev_ctx; + struct mod_thermal_power_estimator_dev_config mock_config; + unsigned int round; + int status; + + round = 0; + thermal_power_estimator_init_one_element(&mock_dev_ctx, &mock_config); + fwk_id_get_element_idx_ExpectAndReturn( + element_id, THERMAL_POWER_ESTIMATOR_FAKE_ELEM_IDX_0); + fwk_id_is_type_ExpectAnyArgsAndReturn(false); + + fwk_module_bind_ExpectAnyArgsAndReturn(FWK_E_HANDLER); + status = thermal_power_estimator_bind(element_id, round); + TEST_ASSERT_EQUAL(FWK_E_PANIC, status); +} + +static void test_thermal_power_estimator_process_bind_request_success(void) +{ + fwk_id_t source_id = FWK_ID_ELEMENT_INIT(FWK_MODULE_IDX_FAKE, 0); + fwk_id_t target_id = FWK_ID_ELEMENT_INIT( + FWK_MODULE_IDX_THERMAL_POWER_ESTIMATOR, + THERMAL_POWER_ESTIMATOR_FAKE_ELEM_IDX_0); + fwk_id_t api_id = FWK_ID_API_INIT( + FWK_MODULE_IDX_THERMAL_POWER_ESTIMATOR, + MOD_THERMAL_POWER_ESTIMATOR_API_IDX_POWER_MANAGEMENT); + const void *api = NULL; + int status; + + fwk_id_get_api_idx_ExpectAndReturn( + api_id, MOD_THERMAL_POWER_ESTIMATOR_API_IDX_POWER_MANAGEMENT); + + status = thermal_power_estimator_process_bind_request( + source_id, target_id, api_id, &api); + + TEST_ASSERT_EQUAL(FWK_SUCCESS, status); + TEST_ASSERT_EQUAL_PTR(&thermal_power_estimator_api, api); +} + +static void test_thermal_power_estimator_process_bind_request_invalid_api(void) +{ + fwk_id_t source_id = FWK_ID_ELEMENT_INIT(FWK_MODULE_IDX_FAKE, 0); + fwk_id_t target_id = FWK_ID_ELEMENT_INIT( + FWK_MODULE_IDX_THERMAL_POWER_ESTIMATOR, + THERMAL_POWER_ESTIMATOR_FAKE_ELEM_IDX_0); + fwk_id_t api_id = FWK_ID_API_INIT( + FWK_MODULE_IDX_THERMAL_POWER_ESTIMATOR, + MOD_THERMAL_POWER_ESTIMATOR_API_IDX_COUNT); + const void *api = NULL; + int status; + + fwk_id_get_api_idx_ExpectAndReturn( + api_id, MOD_THERMAL_POWER_ESTIMATOR_API_IDX_COUNT); + + status = thermal_power_estimator_process_bind_request( + source_id, target_id, api_id, &api); + + TEST_ASSERT_EQUAL(FWK_E_PARAM, status); + TEST_ASSERT_NULL(api); +} + +static void test_read_temperature_success(void) +{ + struct mod_thermal_power_estimator_dev_ctx mock_dev_ctx = { + .sensor_api = &mock_sensor_api, + }; + struct mod_thermal_power_estimator_dev_config mock_config = { + .sensor_id = FWK_ID_ELEMENT_INIT(FWK_MODULE_IDX_SENSOR, 0), + }; + int status; + + thermal_power_estimator_init_one_element(&mock_dev_ctx, &mock_config); + + mod_sensor_get_data_ExpectAndReturn( + mock_config.sensor_id, &mock_dev_ctx.sensor_data, FWK_SUCCESS); + + status = read_temperature(&mock_dev_ctx); + + TEST_ASSERT_EQUAL(FWK_SUCCESS, status); +} + +static void test_read_temperature_fail_pending(void) +{ + struct mod_thermal_power_estimator_dev_ctx mock_dev_ctx = { + .sensor_api = &mock_sensor_api, + }; + struct mod_thermal_power_estimator_dev_config mock_config = { + .sensor_id = FWK_ID_ELEMENT_INIT(FWK_MODULE_IDX_SENSOR, 0), + }; + int status; + + thermal_power_estimator_init_one_element(&mock_dev_ctx, &mock_config); + + mod_sensor_get_data_ExpectAndReturn( + mock_config.sensor_id, &mock_dev_ctx.sensor_data, FWK_PENDING); + + status = read_temperature(&mock_dev_ctx); + + TEST_ASSERT_EQUAL(FWK_E_SUPPORT, status); +} + +static void test_read_temperature_fail_generic(void) +{ + struct mod_thermal_power_estimator_dev_ctx mock_dev_ctx = { + .sensor_api = &mock_sensor_api, + }; + struct mod_thermal_power_estimator_dev_config mock_config = { + .sensor_id = FWK_ID_ELEMENT_INIT(FWK_MODULE_IDX_SENSOR, 0), + }; + int status; + + thermal_power_estimator_init_one_element(&mock_dev_ctx, &mock_config); + + mod_sensor_get_data_ExpectAndReturn( + mock_config.sensor_id, &mock_dev_ctx.sensor_data, FWK_E_SUPPORT); + + status = read_temperature(&mock_dev_ctx); + + TEST_ASSERT_EQUAL(FWK_E_SUPPORT, status); +} + +static void test_thermal_allocatable_power_calculate_positive_output(void) +{ + struct mod_thermal_power_estimator_dev_ctx mock_dev_ctx = { 0 }; + struct mod_thermal_power_estimator_dev_config mock_config = { + .tdp = 100, + }; + int64_t pid_output = 50; + uint32_t allocatable_power; + int status; + + thermal_power_estimator_init_one_element(&mock_dev_ctx, &mock_config); + + status = thermal_allocatable_power_calculate( + &mock_dev_ctx, pid_output, &allocatable_power); + + TEST_ASSERT_EQUAL(FWK_SUCCESS, status); + TEST_ASSERT_EQUAL(150, allocatable_power); +} + +static void test_thermal_allocatable_power_calculate_negative_output(void) +{ + struct mod_thermal_power_estimator_dev_ctx mock_dev_ctx = { 0 }; + struct mod_thermal_power_estimator_dev_config mock_config = { + .tdp = 100, + }; + int64_t pid_output = -150; + uint32_t allocatable_power; + int status; + + thermal_power_estimator_init_one_element(&mock_dev_ctx, &mock_config); + + status = thermal_allocatable_power_calculate( + &mock_dev_ctx, pid_output, &allocatable_power); + + TEST_ASSERT_EQUAL(FWK_SUCCESS, status); + TEST_ASSERT_EQUAL(0, allocatable_power); +} + +static void test_thermal_allocatable_power_calculate_zero_output(void) +{ + struct mod_thermal_power_estimator_dev_ctx mock_dev_ctx = { 0 }; + struct mod_thermal_power_estimator_dev_config mock_config = { + .tdp = 100, + }; + int64_t pid_output = -100; + uint32_t allocatable_power; + int status; + + thermal_power_estimator_init_one_element(&mock_dev_ctx, &mock_config); + + status = thermal_allocatable_power_calculate( + &mock_dev_ctx, pid_output, &allocatable_power); + + TEST_ASSERT_EQUAL(FWK_SUCCESS, status); + TEST_ASSERT_EQUAL(0, allocatable_power); +} + +static void test_thermal_allocatable_power_calculate_over_max(void) +{ + struct mod_thermal_power_estimator_dev_ctx mock_dev_ctx = { 0 }; + struct mod_thermal_power_estimator_dev_config mock_config = { + .tdp = 100, + }; + int64_t pid_output = UINT32_MAX; + uint32_t allocatable_power = 123; + uint32_t expected_allocatable_power = 123; + int status; + + thermal_power_estimator_init_one_element(&mock_dev_ctx, &mock_config); + + status = thermal_allocatable_power_calculate( + &mock_dev_ctx, pid_output, &allocatable_power); + + TEST_ASSERT_EQUAL(FWK_E_DATA, status); + TEST_ASSERT_EQUAL(expected_allocatable_power, allocatable_power); +} + +void test_thermal_power_estimator_get_limit_success(void) +{ + fwk_id_t element_id = FWK_ID_ELEMENT_INIT( + FWK_MODULE_IDX_THERMAL_POWER_ESTIMATOR, + THERMAL_POWER_ESTIMATOR_FAKE_ELEM_IDX_0); + struct mod_thermal_power_estimator_dev_ctx mock_dev_ctx = { + .sensor_api = &mock_sensor_api, + .pid_ctrl_api = &mock_pid_controller_api, + }; + struct mod_thermal_power_estimator_dev_config mock_config = { + .pid_controller_id = + FWK_ID_ELEMENT_INIT(FWK_MODULE_IDX_PID_CONTROLLER, 0), + .tdp = 0, + }; + int64_t pid_output = 100; + uint32_t power_limit = 0; + int status; + + thermal_power_estimator_init_one_element(&mock_dev_ctx, &mock_config); + fwk_id_get_element_idx_ExpectAndReturn( + element_id, THERMAL_POWER_ESTIMATOR_FAKE_ELEM_IDX_0); + + mod_sensor_get_data_ExpectAndReturn( + mock_config.sensor_id, &mock_dev_ctx.sensor_data, FWK_SUCCESS); + + /* Simulate PID controller update success */ + mod_pid_controller_update_ExpectAnyArgsAndReturn(FWK_SUCCESS); + mod_pid_controller_update_ReturnThruPtr_output(&pid_output); + + status = thermal_power_estimator_get_limit(element_id, &power_limit); + + TEST_ASSERT_EQUAL(FWK_SUCCESS, status); + TEST_ASSERT_EQUAL(pid_output, power_limit); +} + +static void test_thermal_power_estimator_get_limit_sensor_fail(void) +{ + fwk_id_t element_id = FWK_ID_ELEMENT_INIT( + FWK_MODULE_IDX_THERMAL_POWER_ESTIMATOR, + THERMAL_POWER_ESTIMATOR_FAKE_ELEM_IDX_0); + struct mod_thermal_power_estimator_dev_ctx mock_dev_ctx = { + .sensor_api = &mock_sensor_api, + }; + struct mod_thermal_power_estimator_dev_config mock_config = { 0 }; + uint32_t power_limit = 123, expected_power_limit = 123; + int status; + + thermal_power_estimator_init_one_element(&mock_dev_ctx, &mock_config); + fwk_id_get_element_idx_ExpectAndReturn( + element_id, THERMAL_POWER_ESTIMATOR_FAKE_ELEM_IDX_0); + + mod_sensor_get_data_ExpectAndReturn( + mock_config.sensor_id, &mock_dev_ctx.sensor_data, FWK_E_DEVICE); + + status = thermal_power_estimator_get_limit(element_id, &power_limit); + + TEST_ASSERT_EQUAL(FWK_E_DEVICE, status); + TEST_ASSERT_EQUAL(expected_power_limit, power_limit); +} + +static void test_thermal_power_estimator_get_limit_pid_fail(void) +{ + fwk_id_t element_id = FWK_ID_ELEMENT_INIT( + FWK_MODULE_IDX_THERMAL_POWER_ESTIMATOR, + THERMAL_POWER_ESTIMATOR_FAKE_ELEM_IDX_0); + struct mod_thermal_power_estimator_dev_ctx mock_dev_ctx = { + .sensor_api = &mock_sensor_api, + .pid_ctrl_api = &mock_pid_controller_api, + }; + struct mod_thermal_power_estimator_dev_config mock_config = { + .pid_controller_id = + FWK_ID_ELEMENT_INIT(FWK_MODULE_IDX_PID_CONTROLLER, 0), + .tdp = 0, + }; + int64_t pid_output = 100; + uint32_t power_limit = 0; + int status; + + thermal_power_estimator_init_one_element(&mock_dev_ctx, &mock_config); + fwk_id_get_element_idx_ExpectAndReturn( + element_id, THERMAL_POWER_ESTIMATOR_FAKE_ELEM_IDX_0); + + mod_sensor_get_data_ExpectAndReturn( + mock_config.sensor_id, &mock_dev_ctx.sensor_data, FWK_SUCCESS); + + /* Simulate PID controller update success */ + mod_pid_controller_update_ExpectAnyArgsAndReturn(FWK_E_DEVICE); + + status = thermal_power_estimator_get_limit(element_id, &power_limit); + + TEST_ASSERT_EQUAL(FWK_E_DEVICE, status); + TEST_ASSERT_NOT_EQUAL(pid_output, power_limit); +} + +static void test_thermal_power_estimator_set_limit(void) +{ + fwk_id_t element_id = FWK_ID_ELEMENT_INIT( + FWK_MODULE_IDX_THERMAL_POWER_ESTIMATOR, + THERMAL_POWER_ESTIMATOR_FAKE_ELEM_IDX_0); + uint32_t power_limit = 0; + int status; + + status = thermal_power_estimator_set_limit(element_id, power_limit); + + TEST_ASSERT_EQUAL(FWK_E_SUPPORT, status); +} + +int mod_thermal_power_estimator_test_main(void) +{ + UNITY_BEGIN(); + + RUN_TEST(test_thermal_power_estimator_init_success); + RUN_TEST(test_thermal_power_estimator_dev_init_success); + RUN_TEST(test_thermal_power_estimator_bind_success); + RUN_TEST(test_thermal_power_estimator_bind_sensor_bind_fail); + RUN_TEST(test_thermal_power_estimator_process_bind_request_success); + RUN_TEST(test_thermal_power_estimator_process_bind_request_invalid_api); + RUN_TEST(test_read_temperature_success); + RUN_TEST(test_read_temperature_fail_pending); + RUN_TEST(test_read_temperature_fail_generic); + RUN_TEST(test_thermal_allocatable_power_calculate_positive_output); + RUN_TEST(test_thermal_allocatable_power_calculate_negative_output); + RUN_TEST(test_thermal_allocatable_power_calculate_zero_output); + RUN_TEST(test_thermal_allocatable_power_calculate_over_max); + RUN_TEST(test_thermal_power_estimator_get_limit_success); + RUN_TEST(test_thermal_power_estimator_get_limit_sensor_fail); + RUN_TEST(test_thermal_power_estimator_get_limit_pid_fail); + RUN_TEST(test_thermal_power_estimator_set_limit); + + return UNITY_END(); +} + +#if !defined(TEST_ON_TARGET) +int main(void) +{ + return mod_thermal_power_estimator_test_main(); +} +#endif diff --git a/unit_test/CMakeLists.txt b/unit_test/CMakeLists.txt index 4730e1778..c49b96092 100644 --- a/unit_test/CMakeLists.txt +++ b/unit_test/CMakeLists.txt @@ -143,6 +143,7 @@ list(APPEND UNIT_MODULE sensor_smcf_drv) list(APPEND UNIT_MODULE smcf) list(APPEND UNIT_MODULE spmi) list(APPEND UNIT_MODULE thermal_mgmt) +list(APPEND UNIT_MODULE thermal_power_estimator) list(APPEND UNIT_MODULE traffic_cop) list(APPEND UNIT_MODULE transport) list(APPEND UNIT_MODULE xr77128) -- GitLab From c30203748d159cd03111a556127649754f657833 Mon Sep 17 00:00:00 2001 From: Leandro Belli Date: Fri, 20 Dec 2024 13:15:19 +0000 Subject: [PATCH 2/2] module/thermal_power_estimator: add documentations This patchs adds a documentation explaining the functionallity of the module and how it is integrated with the Metrics analyzer. Signed-off-by: Leandro Belli --- .../doc/thermal_power_estimator.md | 53 +++++++++++++++++++ 1 file changed, 53 insertions(+) create mode 100644 module/thermal_power_estimator/doc/thermal_power_estimator.md diff --git a/module/thermal_power_estimator/doc/thermal_power_estimator.md b/module/thermal_power_estimator/doc/thermal_power_estimator.md new file mode 100644 index 000000000..d2984bc80 --- /dev/null +++ b/module/thermal_power_estimator/doc/thermal_power_estimator.md @@ -0,0 +1,53 @@ +\ingroup GroupModules Modules +\defgroup GroupThermal Thermal Management + +# Thermal Management Architecture + +Copyright (c) 2024, Arm Limited. All rights reserved. + + +## Overview + +The Thermal Power Estimator is a module designed to compute the maximum +allocatable power for a platform based on thermal conditions. It forms part of +the Metrics pipeline framework and interacts with other components to provide +accurate power estimation leveraging temperature data and PID control feedback. + +## Features + +- **Thermal-Aware Power Estimation**: Utilizes thermal input from sensors and + PID feedback to estimate maximum permissible power. +- PID Integration: Interfaces with a separate PID controller module for + closed-loop feedback. +- Metrics Analyzer Integration: Acts as a power limit provider for the Metrics + Analyzer service. + +## Architecture diagram + + Thermal Design + Current temp Power (TDP) + | | + | | + | | + v v + +-+-+ +----------+ +-+-+ + | +---->+ PID Ctrl +------>+ +-------> Maximum allocatable power + +-+-+ +----------+ +---+ + ^ + | + | + | + Control temp + + +## Algorithm + +The Thermal Power Estimator is typically deployed as part of a broader power +management strategy. The following sequence describes its operation within +the Metrics Analyzer framework: + +1. The module retrieves the current temperature from the sensor. +2. PID control feedback is fetched to determine power adjustments. +3. Computes and provides the maximum allocatable power based on the above + inputs. +4. Supplies the computed power limit to the Metrics Analyzer. -- GitLab