From 6ae646603d9be647554a8053d6b22dc44abb16ad Mon Sep 17 00:00:00 2001 From: swateeshrivastava Date: Thu, 27 Dec 2018 15:34:08 +0530 Subject: [PATCH] Unity test cases are added for ocmp_se98a --- firmware/ec/inc/devices/se98a.h | 16 + .../ec/src/devices/ocmp_wrappers/ocmp_se98a.c | 18 +- firmware/ec/test/Makefile | 3 + firmware/ec/test/fake/fake_se98a.c | 54 ++ firmware/ec/test/include/test_se98a.h | 59 ++ firmware/ec/test/stub/stub_se98a.c | 43 ++ firmware/ec/test/suites/Doc/TestCaseList.xlsx | Bin 33889 -> 33547 bytes firmware/ec/test/suites/Test_ocmp_se98a.c | 515 ++++++++++++++++++ 8 files changed, 691 insertions(+), 17 deletions(-) create mode 100644 firmware/ec/test/fake/fake_se98a.c create mode 100644 firmware/ec/test/include/test_se98a.h create mode 100644 firmware/ec/test/stub/stub_se98a.c create mode 100644 firmware/ec/test/suites/Test_ocmp_se98a.c diff --git a/firmware/ec/inc/devices/se98a.h b/firmware/ec/inc/devices/se98a.h index 88bf827774..93b0d53877 100644 --- a/firmware/ec/inc/devices/se98a.h +++ b/firmware/ec/inc/devices/se98a.h @@ -34,6 +34,22 @@ typedef enum { CONF_TEMP_SE98A_CRITICAL_LIMIT_REG } eTempSensor_ConfigParamsId; +typedef enum Se98aStatus { + SE98A_STATUS_TEMPERATURE = 0, +} Se98aStatus; + +typedef enum Se98aConfig { + SE98A_CONFIG_LIM_LOW = 0, + SE98A_CONFIG_LIM_HIGH, + SE98A_CONFIG_LIM_CRIT, +} Se98aConfig; + +typedef enum Se98aAlert { + SE98A_ALERT_LOW = 0, + SE98A_ALERT_HIGH, + SE98A_ALERT_CRITICAL +} Se98aAlert; + typedef void (*SE98A_CallbackFn)(SE98A_Event evt, int8_t temperature, void *context); diff --git a/firmware/ec/src/devices/ocmp_wrappers/ocmp_se98a.c b/firmware/ec/src/devices/ocmp_wrappers/ocmp_se98a.c index 5605f9dc7a..2242d48407 100644 --- a/firmware/ec/src/devices/ocmp_wrappers/ocmp_se98a.c +++ b/firmware/ec/src/devices/ocmp_wrappers/ocmp_se98a.c @@ -12,22 +12,6 @@ #include "helpers/math.h" #include "inc/devices/se98a.h" -typedef enum Se98aStatus { - SE98A_STATUS_TEMPERATURE = 0, -} Se98aStatus; - -typedef enum Se98aConfig { - SE98A_CONFIG_LIM_LOW = 0, - SE98A_CONFIG_LIM_HIGH, - SE98A_CONFIG_LIM_CRIT, -} Se98aConfig; - -typedef enum Se98aAlert { - SE98A_ALERT_LOW = 0, - SE98A_ALERT_HIGH, - SE98A_ALERT_CRITICAL -} Se98aAlert; - static bool _get_status(void *driver, unsigned int param_id, void *return_buf) { switch (param_id) { @@ -121,7 +105,7 @@ static ePostCode _init(void *driver, const void *config, return POST_DEV_CFG_DONE; } const SE98A_Config *se98a_config = config; - for (int i = 0; i < ARRAY_SIZE(se98a_config->limits); ++i) { + for (uint8_t i = 0; i < ARRAY_SIZE(se98a_config->limits); ++i) { if (se98a_set_limit(driver, i + 1, se98a_config->limits[i]) != RETURN_OK) { return POST_DEV_CFG_FAIL; diff --git a/firmware/ec/test/Makefile b/firmware/ec/test/Makefile index e11cb067a6..f66dba06be 100644 --- a/firmware/ec/test/Makefile +++ b/firmware/ec/test/Makefile @@ -166,6 +166,9 @@ $(PATHB)Test_ocmp_ltc4015$(TARGET_EXTENSION): $(STD_FILES) $(TEST_OCMP_LTC4015_S TEST_OCMP_powerSource_SRC=$(OCWARE_ROOT)/src/devices/ocmp_wrappers/ocmp_powerSource.c $(OCWARE_ROOT)/src/devices/powerSource.c $(OCWARE_ROOT)/src/drivers/GpioSX1509.c $(OCWARE_ROOT)/src/devices/sx1509.c $(OCWARE_ROOT)/src/helpers/memory.c $(OCWARE_ROOT)/src/devices/i2cbus.c fake/fake_GPIO.c fake/fake_I2C.c fake/fake_ThreadedISR.c stub/stub_GateMutex.c stub/stub_GateMutex.c $(OCWARE_ROOT)/src/post/post_util.c fake/fake_SX1509_register.c fake/fake_powerSource.c $(OCWARE_ROOT)/platform/oc-sdr/cfg/OC_CONNECT_GBC.c $(PATHB)Test_ocmp_powerSource$(TARGET_EXTENSION): $(STD_FILES) $(TEST_OCMP_powerSource_SRC) $(INC_M) +TEST_OCMP_SE98A_SRC=$(OCWARE_ROOT)/src/devices/ocmp_wrappers/ocmp_se98a.c $(OCWARE_ROOT)/src/devices/se98a.c $(OCWARE_ROOT)/src/devices/i2cbus.c fake/fake_GPIO.c fake/fake_I2C.c fake/fake_ThreadedISR.c stub/stub_GateMutex.c stub/stub_se98a.c $(OCWARE_ROOT)/src/post/post_util.c fake/fake_se98a.c $(OCWARE_ROOT)/platform/oc-sdr/cfg/OC_CONNECT_GBC.c +$(PATHB)Test_ocmp_se98a$(TARGET_EXTENSION): $(STD_FILES) $(TEST_OCMP_SE98A_SRC) $(INC_M) + $(PATHB)%$(TARGET_EXTENSION): $(C_COMPILER) $(CFLAGS) $(INC_DIRS) $(SYMBOLS) $^ -o $@ $(COV_CMDS) diff --git a/firmware/ec/test/fake/fake_se98a.c b/firmware/ec/test/fake/fake_se98a.c new file mode 100644 index 0000000000..dfa3a9e536 --- /dev/null +++ b/firmware/ec/test/fake/fake_se98a.c @@ -0,0 +1,54 @@ +/** + * Copyright (c) 2017-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + */ +#include "include/test_se98a.h" +#include + +OcGpio_Port gbc_io_0 = { + .fn_table = &FakeGpio_fnTable, + .object_data = &(FakeGpio_Obj){}, +}; +SE98A_Dev s_invalid_device = { + .cfg = + { + .dev = + { + .bus = 3, + .slave_addr = 0xFF, + }, + }, +}; + +SE98A_Dev s_invalid_bus = { + .cfg = + { + .dev = + { + .bus = 0xFF, + .slave_addr = 0x1A, + }, + }, +}; +bool SE98A_GpioPins[] = { + [0x05] = OCGPIO_CFG_INPUT, +}; + +uint32_t SE98A_GpioConfig[] = { + [0x05] = OCGPIO_CFG_INPUT, +}; + +uint16_t SE98A_regs[] = { + [SE98A_REG_CAPABILITY] = 0x00, /* Capabilities */ + [SE98A_REG_CONFIG] = 0x00, /* Config */ + [SE98A_REG_HIGH_LIMIT] = 0x00, /* High limit */ + [SE98A_REG_LOW_LIMIT] = 0x00, /* Low limit */ + [SE98A_REG_CRITICAL_LIMIT] = 0x00, /* Critical limit */ + [SE98A_REG_MEASURED_TEMP] = 0x00, /* Measured Temperature */ + [SE98A_REG_MFG_ID] = 0x00, /* MFG ID */ + [SE98A_REG_DEVICE_ID] = 0x00, /* Device ID */ +}; diff --git a/firmware/ec/test/include/test_se98a.h b/firmware/ec/test/include/test_se98a.h new file mode 100644 index 0000000000..bc6b2262e2 --- /dev/null +++ b/firmware/ec/test/include/test_se98a.h @@ -0,0 +1,59 @@ +/** + * Copyright (c) 2017-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + */ +#ifndef _TEST_SE98A_H +#define _TEST_SE98A_H + +#include "common/inc/global/Framework.h" +#include "common/inc/ocmp_wrappers/ocmp_se98a.h" +#include "fake/fake_GPIO.h" +#include "fake/fake_I2C.h" +#include "fake/fake_ThreadedISR.h" +#include "inc/common/byteorder.h" +#include "inc/devices/se98a.h" +#include "src/helpers/math.h" +#include +#include +#include +#include "unity.h" + +/* ======================== Constants & variables =========================== */ +#define AP_COMPONENET 2 +#define GPP_SUBSYSTEM 6 +#define GPP_TEMP_SENS_DEVICE_ID 0 +#define POST_DATA_NULL 0x0000 +#define SE98A_CFG_EOCTL 8 +#define SE98A_DEVICE_ID 0xA102 +#define SE98A_DEFAULT_INIT_VALUE 0 +#define SE98A_EVT_DEFAULT 1 << 3 +#define SE98A_INVALID_DEVICE_ID 0xFACE +#define SE98A_INVALID_MFG_ID 0xABCD +#define SE98A_MFG_ID 0x1131 + +typedef struct Test_AlertData { + bool triggered; + SE98A_Event evt; + int8_t temp; + void *ctx; +} s_alert_data; + +typedef enum SE98ARegs { + SE98A_REG_CAPABILITY = 0, + SE98A_REG_CONFIG, + SE98A_REG_HIGH_LIMIT, + SE98A_REG_LOW_LIMIT, + SE98A_REG_CRITICAL_LIMIT, + SE98A_REG_MEASURED_TEMP, + SE98A_REG_MFG_ID, + SE98A_REG_DEVICE_ID, +} SE98ARegs; + +int16_t ocmp_se98a_set_temp_limit(int8_t tempLimitValue); +int16_t ocmp_se98a_get_temp_value(int16_t statusVal); +uint8_t ocmp_se98a_dev_id(uint16_t devId); +#endif diff --git a/firmware/ec/test/stub/stub_se98a.c b/firmware/ec/test/stub/stub_se98a.c new file mode 100644 index 0000000000..bc0f6cd75a --- /dev/null +++ b/firmware/ec/test/stub/stub_se98a.c @@ -0,0 +1,43 @@ +/** + * Copyright (c) 2017-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + */ +#include "include/test_se98a.h" +#include + +int16_t ocmp_se98a_set_temp_limit(int8_t tempLimitValue) +{ + uint16_t expTempLimit = 0; + expTempLimit = ((int16_t)tempLimitValue & 0x00FF) << 4; + if (tempLimitValue < 0) { + expTempLimit |= 0x1000; + } + return expTempLimit; +} + +int16_t ocmp_se98a_get_temp_value(int16_t statusVal) +{ + int8_t retTempStatus = 0; + int16_t expTempStatus = 0; + int16_t tempTempStatus = statusVal; + + expTempStatus = (tempTempStatus & 0x0FFC); + if (tempTempStatus & 0x1000) { + expTempStatus |= 0xF000; + } + + expTempStatus = round(expTempStatus / 16.0f); + retTempStatus = CONSTRAIN(expTempStatus, INT8_MIN, INT8_MAX); + return retTempStatus; +} + +uint8_t ocmp_se98a_dev_id(uint16_t devId) +{ + uint8_t expDevId = 0; + expDevId = ((uint8_t)((devId) >> 8)); + return expDevId; +} diff --git a/firmware/ec/test/suites/Doc/TestCaseList.xlsx b/firmware/ec/test/suites/Doc/TestCaseList.xlsx index 13b9edd318a06889e57cadeeb37330349c361825..f15c78f0ebfd49c55fbe6f01c35816ac496786b1 100644 GIT binary patch literal 33547 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
    cG%P_%`r^Z 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 Cgl7!^ diff --git a/firmware/ec/test/suites/Test_ocmp_se98a.c b/firmware/ec/test/suites/Test_ocmp_se98a.c new file mode 100644 index 0000000000..6f79b675c3 --- /dev/null +++ b/firmware/ec/test/suites/Test_ocmp_se98a.c @@ -0,0 +1,515 @@ +/** + * Copyright (c) 2017-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + */ +#include "include/test_se98a.h" + +extern bool SE98A_GpioPins[0x05]; +extern const SE98A_Config fact_ap_se98a_ts1_cfg; +extern OcGpio_Port gbc_io_0; +extern SE98A_Dev gbc_gpp_ap_ts1; +extern SE98A_Dev s_invalid_bus; +extern SE98A_Dev s_invalid_device; +extern uint16_t SE98A_regs[SE98A_REG_DEVICE_ID]; +extern uint32_t SE98A_GpioConfig[0x05]; + +/* ============================= Fake Functions ============================= */ +unsigned int s_task_sleep_ticks; +xdc_Void ti_sysbios_knl_Task_sleep__E(xdc_UInt32 nticks) +{ + s_task_sleep_ticks += nticks; +} + +/* ============================= Boilerplate ================================ */ +void suite_setUp(void) +{ + FakeGpio_registerDevSimple(SE98A_GpioPins, SE98A_GpioConfig); + fake_I2C_init(); + fake_I2C_init(); + fake_I2C_registerDevSimple(gbc_gpp_ap_ts1.cfg.dev.bus, + gbc_gpp_ap_ts1.cfg.dev.slave_addr, SE98A_regs, + sizeof(SE98A_regs) + 2, sizeof(SE98A_regs[0]), + sizeof(uint8_t), FAKE_I2C_DEV_BIG_ENDIAN); +} + +void setUp(void) +{ + memset(SE98A_regs, 0, sizeof(SE98A_regs)); + SE98A_regs[SE98A_REG_CAPABILITY] = 0x0037; + SE98A_regs[SE98A_REG_MFG_ID] = SE98A_MFG_ID; + SE98A_regs[SE98A_REG_DEVICE_ID] = SE98A_DEVICE_ID; + + s_task_sleep_ticks = 0; + OcGpio_init(&gbc_io_0); + se98a_init(&gbc_gpp_ap_ts1); +} + +void tearDown(void) +{ +} + +void suite_tearDown(void) +{ + fake_I2C_deinit(); /* This will automatically unregister devices */ +} +/* ================================ Tests =================================== */ +// Parameters are not used as this is just used to test assigning the +// alert_handler right now. +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-parameter" +void OCMP_GenerateAlert(const AlertData *alert_data, unsigned int alert_id, + const void *data) +{ +} +#pragma GCC diagnostic pop +/* ================================ Tests =================================== */ +void test_ocmp_se98a_probe(void) +{ + uint8_t devId = 0; + /* Test with the actual values + * (dev id is hi-byte) + * (1131h = NXP Semiconductors PCI-SIG)*/ + POSTData postData; + SE98A_regs[SE98A_REG_DEVICE_ID] = SE98A_DEVICE_ID; + SE98A_regs[SE98A_REG_MFG_ID] = SE98A_MFG_ID; + TEST_ASSERT_EQUAL(POST_DEV_FOUND, + SE98_fxnTable.cb_probe(&gbc_gpp_ap_ts1, &postData)); + devId = ocmp_se98a_dev_id(SE98A_regs[SE98A_REG_DEVICE_ID]); + TEST_ASSERT_EQUAL(gbc_gpp_ap_ts1.cfg.dev.bus, postData.i2cBus); + TEST_ASSERT_EQUAL_HEX8(gbc_gpp_ap_ts1.cfg.dev.slave_addr, postData.devAddr); + TEST_ASSERT_EQUAL_HEX8(SE98A_MFG_ID, postData.manId); + TEST_ASSERT_EQUAL_HEX16(devId, postData.devId); + + /* Test with an incorrect device ID */ + postData.i2cBus = POST_DATA_NULL; + postData.devAddr = POST_DATA_NULL; + postData.manId = POST_DATA_NULL; + postData.devId = POST_DATA_NULL; + SE98A_regs[SE98A_REG_DEVICE_ID] = SE98A_INVALID_DEVICE_ID; + TEST_ASSERT_EQUAL(POST_DEV_ID_MISMATCH, + SE98_fxnTable.cb_probe(&gbc_gpp_ap_ts1, &postData)); + TEST_ASSERT_EQUAL(POST_DATA_NULL, postData.i2cBus); + TEST_ASSERT_EQUAL_HEX8(POST_DATA_NULL, postData.devAddr); + TEST_ASSERT_EQUAL_HEX8(POST_DATA_NULL, postData.manId); + TEST_ASSERT_EQUAL_HEX8(POST_DATA_NULL, postData.devId); + + /* Test with an incorrect mfg ID */ + SE98A_regs[SE98A_REG_DEVICE_ID] = SE98A_DEVICE_ID; + SE98A_regs[SE98A_REG_MFG_ID] = SE98A_INVALID_MFG_ID; + TEST_ASSERT_EQUAL(POST_DEV_ID_MISMATCH, + SE98_fxnTable.cb_probe(&gbc_gpp_ap_ts1, &postData)); + TEST_ASSERT_EQUAL(POST_DATA_NULL, postData.i2cBus); + TEST_ASSERT_EQUAL_HEX8(POST_DATA_NULL, postData.devAddr); + TEST_ASSERT_EQUAL_HEX8(POST_DATA_NULL, postData.manId); + TEST_ASSERT_EQUAL_HEX8(POST_DATA_NULL, postData.devId); + + /* Test with a missing device */ + TEST_ASSERT_EQUAL(POST_DEV_MISSING, + SE98_fxnTable.cb_probe(&s_invalid_device, &postData)); + TEST_ASSERT_EQUAL(POST_DATA_NULL, postData.i2cBus); + TEST_ASSERT_EQUAL_HEX8(POST_DATA_NULL, postData.devAddr); + TEST_ASSERT_EQUAL_HEX8(POST_DATA_NULL, postData.manId); + TEST_ASSERT_EQUAL_HEX8(POST_DATA_NULL, postData.devId); + + /* Test with a missing bus */ + TEST_ASSERT_EQUAL(POST_DEV_MISSING, + SE98_fxnTable.cb_probe(&s_invalid_bus, &postData)); + TEST_ASSERT_EQUAL(POST_DATA_NULL, postData.i2cBus); + TEST_ASSERT_EQUAL_HEX8(POST_DATA_NULL, postData.devAddr); + TEST_ASSERT_EQUAL_HEX8(POST_DATA_NULL, postData.manId); + TEST_ASSERT_EQUAL_HEX8(POST_DATA_NULL, postData.devId); +} + +void test_ocmp_se98a_init(void) +{ + int16_t expTempLowLimit = 0; + int16_t expTempHighLimit = 0; + int16_t expTempCriticLimit = 0; + + SE98A_regs[SE98A_REG_CONFIG] = SE98A_DEFAULT_INIT_VALUE; + SE98A_regs[SE98A_REG_HIGH_LIMIT] = SE98A_DEFAULT_INIT_VALUE; + SE98A_regs[SE98A_REG_LOW_LIMIT] = SE98A_DEFAULT_INIT_VALUE; + SE98A_regs[SE98A_REG_CRITICAL_LIMIT] = SE98A_DEFAULT_INIT_VALUE; + + AlertData alert_data = { + .subsystem = GPP_SUBSYSTEM, + .componentId = AP_COMPONENET, + .deviceId = GPP_TEMP_SENS_DEVICE_ID, + }; + + /* Init with a pin associated */ + // s_task_sleep_ticks = SE98A_DEFAULT_INIT_VALUE; + TEST_ASSERT_EQUAL(POST_DEV_CFG_DONE, + SE98_fxnTable.cb_init(&gbc_gpp_ap_ts1, + &fact_ap_se98a_ts1_cfg, + &alert_data)); + expTempLowLimit = + ocmp_se98a_set_temp_limit(fact_ap_se98a_ts1_cfg.limits[0]); + expTempHighLimit = + ocmp_se98a_set_temp_limit(fact_ap_se98a_ts1_cfg.limits[1]); + expTempCriticLimit = + ocmp_se98a_set_temp_limit(fact_ap_se98a_ts1_cfg.limits[2]); + + /* Test that the enable alert flag is set */ + TEST_ASSERT_BITS_HIGH(SE98A_CFG_EOCTL, SE98A_regs[SE98A_REG_CONFIG]); + + /* Test temprature values */ + TEST_ASSERT_EQUAL_HEX16(expTempLowLimit, SE98A_regs[SE98A_REG_LOW_LIMIT]); + TEST_ASSERT_EQUAL_HEX16(expTempHighLimit, SE98A_regs[SE98A_REG_HIGH_LIMIT]); + TEST_ASSERT_EQUAL_HEX16(expTempCriticLimit, + SE98A_regs[SE98A_REG_CRITICAL_LIMIT]); + + /* Test with null config */ + SE98A_regs[SE98A_REG_CONFIG] = SE98A_DEFAULT_INIT_VALUE; + SE98A_regs[SE98A_REG_HIGH_LIMIT] = SE98A_DEFAULT_INIT_VALUE; + SE98A_regs[SE98A_REG_LOW_LIMIT] = SE98A_DEFAULT_INIT_VALUE; + SE98A_regs[SE98A_REG_CRITICAL_LIMIT] = SE98A_DEFAULT_INIT_VALUE; + + TEST_ASSERT_EQUAL( + POST_DEV_CFG_DONE, + SE98_fxnTable.cb_init(&gbc_gpp_ap_ts1, NULL, &alert_data)); + + TEST_ASSERT_EQUAL_HEX16(SE98A_DEFAULT_INIT_VALUE, + SE98A_regs[SE98A_REG_LOW_LIMIT]); + TEST_ASSERT_EQUAL_HEX16(SE98A_DEFAULT_INIT_VALUE, + SE98A_regs[SE98A_REG_HIGH_LIMIT]); + TEST_ASSERT_EQUAL_HEX16(SE98A_DEFAULT_INIT_VALUE, + SE98A_regs[SE98A_REG_CRITICAL_LIMIT]); + + /* Test with a missing device */ + TEST_ASSERT_EQUAL( + POST_DEV_CFG_FAIL, + SE98_fxnTable.cb_init(&s_invalid_device, NULL, &alert_data)); + + /* Test with a missing bus */ + TEST_ASSERT_EQUAL(POST_DEV_CFG_FAIL, + SE98_fxnTable.cb_init(&s_invalid_bus, NULL, &alert_data)); +} + +/* Values are used in the below function are taken as per the datasheet*/ +void test_ocmp_se98a_get_status(void) +{ + /* + * [15..13] Trip Status + * [12..5] 8-bit integer part + * [4..1] fractional part + * [0] RFU + */ + int8_t statusTemp = 0; + int8_t expStatusTemp = 0; + Se98aStatus paramId = SE98A_STATUS_TEMPERATURE; + SE98A_regs[SE98A_REG_MEASURED_TEMP] = 0x019C; /* 25.75 */ + TEST_ASSERT_EQUAL(true, SE98_fxnTable.cb_get_status(&gbc_gpp_ap_ts1, + paramId, &statusTemp)); + expStatusTemp = + ocmp_se98a_get_temp_value(SE98A_regs[SE98A_REG_MEASURED_TEMP]); + TEST_ASSERT_EQUAL(expStatusTemp, statusTemp); + + statusTemp = 0; + expStatusTemp = 0; + SE98A_regs[SE98A_REG_MEASURED_TEMP] = 0x1E64; /* -25.75 */ + TEST_ASSERT_EQUAL(true, SE98_fxnTable.cb_get_status(&gbc_gpp_ap_ts1, + paramId, &statusTemp)); + expStatusTemp = + ocmp_se98a_get_temp_value(SE98A_regs[SE98A_REG_MEASURED_TEMP]); + TEST_ASSERT_EQUAL(expStatusTemp, statusTemp); + + statusTemp = 0; + expStatusTemp = 0; + SE98A_regs[SE98A_REG_MEASURED_TEMP] = 0x07C0; + TEST_ASSERT_EQUAL(true, SE98_fxnTable.cb_get_status(&gbc_gpp_ap_ts1, + paramId, &statusTemp)); + expStatusTemp = + ocmp_se98a_get_temp_value(SE98A_regs[SE98A_REG_MEASURED_TEMP]); + TEST_ASSERT_EQUAL(expStatusTemp, statusTemp); + + statusTemp = 0; + expStatusTemp = 0; + SE98A_regs[SE98A_REG_MEASURED_TEMP] = 0x1FF0; + TEST_ASSERT_EQUAL(true, SE98_fxnTable.cb_get_status(&gbc_gpp_ap_ts1, + paramId, &statusTemp)); + expStatusTemp = + ocmp_se98a_get_temp_value(SE98A_regs[SE98A_REG_MEASURED_TEMP]); + TEST_ASSERT_EQUAL(expStatusTemp, statusTemp); + + statusTemp = 0; + expStatusTemp = 0; + SE98A_regs[SE98A_REG_MEASURED_TEMP] = 0x1C90; + TEST_ASSERT_EQUAL(true, SE98_fxnTable.cb_get_status(&gbc_gpp_ap_ts1, + paramId, &statusTemp)); + expStatusTemp = + ocmp_se98a_get_temp_value(SE98A_regs[SE98A_REG_MEASURED_TEMP]); + TEST_ASSERT_EQUAL(expStatusTemp, statusTemp); + + /* The device shouldn't return temperatures larger than 125, so we only + * support int8s - everything else is rounded for now */ + statusTemp = 0; + expStatusTemp = 0; + SE98A_regs[SE98A_REG_MEASURED_TEMP] = 0x17E0; /* -130 */ + TEST_ASSERT_EQUAL(true, SE98_fxnTable.cb_get_status(&gbc_gpp_ap_ts1, + paramId, &statusTemp)); + expStatusTemp = + ocmp_se98a_get_temp_value(SE98A_regs[SE98A_REG_MEASURED_TEMP]); + TEST_ASSERT_EQUAL(expStatusTemp, statusTemp); + + statusTemp = 0; + expStatusTemp = 0; + SE98A_regs[SE98A_REG_MEASURED_TEMP] = 0x0B40; /* 180 */ + TEST_ASSERT_EQUAL(true, SE98_fxnTable.cb_get_status(&gbc_gpp_ap_ts1, + paramId, &statusTemp)); + expStatusTemp = + ocmp_se98a_get_temp_value(SE98A_regs[SE98A_REG_MEASURED_TEMP]); + TEST_ASSERT_EQUAL(expStatusTemp, statusTemp); + + /* Make sure we mask the status/RFU bits out */ + statusTemp = 0; + expStatusTemp = 0; + SE98A_regs[SE98A_REG_MEASURED_TEMP] = 0xFC91; + TEST_ASSERT_EQUAL(true, SE98_fxnTable.cb_get_status(&gbc_gpp_ap_ts1, + paramId, &statusTemp)); + expStatusTemp = + ocmp_se98a_get_temp_value(SE98A_regs[SE98A_REG_MEASURED_TEMP]); + TEST_ASSERT_EQUAL(expStatusTemp, statusTemp); + + /* Test with a missing device */ + statusTemp = 0; + expStatusTemp = 0; + SE98A_regs[SE98A_REG_MEASURED_TEMP] = 0xFC91; + TEST_ASSERT_EQUAL(false, SE98_fxnTable.cb_get_status(&s_invalid_device, + paramId, &statusTemp)); + /* Test with a missing bus*/ + statusTemp = 0; + expStatusTemp = 0; + SE98A_regs[SE98A_REG_MEASURED_TEMP] = 0xFC91; + TEST_ASSERT_EQUAL(false, SE98_fxnTable.cb_get_status(&s_invalid_bus, + paramId, &statusTemp)); + /* Test with a invalid paramid*/ + statusTemp = 0; + expStatusTemp = 0; + SE98A_regs[SE98A_REG_MEASURED_TEMP] = 0xFC91; + TEST_ASSERT_EQUAL( + false, SE98_fxnTable.cb_get_status(&gbc_gpp_ap_ts1, 1, &statusTemp)); +} + +/* Helper to let us run through the various limits we can get */ +static void +test_ocmp_se98a_get_x_limit(eTempSensor_ConfigParamsId limitToConfig, + uint8_t reg_addr) +{ + /* Register map: + * [15..13] RFU + * [12] sign + * [11..4] 9-bit integer part + * [3..2] fractional part (0.5, 0.25) + * [1..0] RFU + */ + int8_t limit = 0; + int16_t expTempLimit = 0; + + SE98A_regs[reg_addr] = 0x0000; + TEST_ASSERT_EQUAL(true, SE98_fxnTable.cb_get_config(&gbc_gpp_ap_ts1, + limitToConfig, &limit)); + expTempLimit = ocmp_se98a_get_temp_value(SE98A_regs[reg_addr]); + TEST_ASSERT_EQUAL(expTempLimit, limit); + + limit = 0; + expTempLimit = 0; + SE98A_regs[reg_addr] = 1 << 4; + TEST_ASSERT_EQUAL(true, SE98_fxnTable.cb_get_config(&gbc_gpp_ap_ts1, + limitToConfig, &limit)); + expTempLimit = ocmp_se98a_get_temp_value(SE98A_regs[reg_addr]); + TEST_ASSERT_EQUAL(expTempLimit, limit); + + limit = 0; + expTempLimit = 0; + SE98A_regs[reg_addr] = 75 << 4; + TEST_ASSERT_EQUAL(true, SE98_fxnTable.cb_get_config(&gbc_gpp_ap_ts1, + limitToConfig, &limit)); + expTempLimit = ocmp_se98a_get_temp_value(SE98A_regs[reg_addr]); + TEST_ASSERT_EQUAL(expTempLimit, limit); + + limit = 0; + expTempLimit = 0; + SE98A_regs[reg_addr] = 0x019C; /* 25.75 */ + TEST_ASSERT_EQUAL(true, SE98_fxnTable.cb_get_config(&gbc_gpp_ap_ts1, + limitToConfig, &limit)); + expTempLimit = ocmp_se98a_get_temp_value(SE98A_regs[reg_addr]); + TEST_ASSERT_EQUAL(expTempLimit, limit); + + limit = 0; + expTempLimit = 0; + SE98A_regs[reg_addr] = 0x1B50; + TEST_ASSERT_EQUAL(true, SE98_fxnTable.cb_get_config(&gbc_gpp_ap_ts1, + limitToConfig, &limit)); + expTempLimit = ocmp_se98a_get_temp_value(SE98A_regs[reg_addr]); + TEST_ASSERT_EQUAL(expTempLimit, limit); + + limit = 0; + expTempLimit = 0; + SE98A_regs[reg_addr] = 0x07F0; + TEST_ASSERT_EQUAL(true, SE98_fxnTable.cb_get_config(&gbc_gpp_ap_ts1, + limitToConfig, &limit)); + expTempLimit = ocmp_se98a_get_temp_value(SE98A_regs[reg_addr]); + TEST_ASSERT_EQUAL(expTempLimit, limit); + + limit = 0; + expTempLimit = 0; + SE98A_regs[reg_addr] = 0x1800; + TEST_ASSERT_EQUAL(true, SE98_fxnTable.cb_get_config(&gbc_gpp_ap_ts1, + limitToConfig, &limit)); + expTempLimit = ocmp_se98a_get_temp_value(SE98A_regs[reg_addr]); + TEST_ASSERT_EQUAL(expTempLimit, limit); + + /* Make sure we mask the RFU bits out */ + limit = 0; + expTempLimit = 0; + SE98A_regs[reg_addr] = 0x07FC; + TEST_ASSERT_EQUAL(true, SE98_fxnTable.cb_get_config(&gbc_gpp_ap_ts1, + limitToConfig, &limit)); + expTempLimit = ocmp_se98a_get_temp_value(SE98A_regs[reg_addr]); + TEST_ASSERT_EQUAL(expTempLimit, limit); + + /* Test with a missing device */ + TEST_ASSERT_EQUAL(false, SE98_fxnTable.cb_get_config( + &s_invalid_device, limitToConfig, &limit)); + + /* Test with a missing bus */ + TEST_ASSERT_EQUAL(false, SE98_fxnTable.cb_get_config( + &s_invalid_bus, limitToConfig, &limit)); + + /* Test with a invalid paramId */ + TEST_ASSERT_EQUAL(false, + SE98_fxnTable.cb_get_config(&gbc_gpp_ap_ts1, 4, &limit)); +} + +void test_ocmp_se98a_temp_sens_get_limit(void) +{ + /* Register: + * SE98A_REG_HIGH_LIM = SE98A_REG_HIGH_LIMIT + * SE98A_REG_LOW_LIM = SE98A_REG_LOW_LIMIT + * SE98A_REG_CRIT_LIM = SE98A_REG_CRITICAL_LIMIT + */ + test_ocmp_se98a_get_x_limit(SE98A_CONFIG_LIM_LOW, SE98A_REG_LOW_LIMIT); + test_ocmp_se98a_get_x_limit(SE98A_CONFIG_LIM_HIGH, SE98A_REG_HIGH_LIMIT); + test_ocmp_se98a_get_x_limit(SE98A_CONFIG_LIM_CRIT, + SE98A_REG_CRITICAL_LIMIT); +} + +/* Helper to let us run through the various limits we can set */ +static void +test_ocmp_se98a_set_x_limit(eTempSensor_ConfigParamsId limitToConfig, + uint8_t reg_addr) +{ + /* Register map: + * [15..13] RFU + * [12] SIGN (2's complement) + * [11..4] Integer part (8 bits) + * [3..2] Fractional part (0.5, 0.25) + * [1..0] RFU + */ + int8_t limit = 0; + int16_t expTempLimit = 0; + + TEST_ASSERT_EQUAL(true, SE98_fxnTable.cb_set_config(&gbc_gpp_ap_ts1, + limitToConfig, &limit)); + expTempLimit = ocmp_se98a_set_temp_limit(limit); + TEST_ASSERT_EQUAL_HEX16(expTempLimit, SE98A_regs[reg_addr]); + + limit = 1; + expTempLimit = 0; + TEST_ASSERT_EQUAL(true, SE98_fxnTable.cb_set_config(&gbc_gpp_ap_ts1, + limitToConfig, &limit)); + expTempLimit = ocmp_se98a_set_temp_limit(limit); + TEST_ASSERT_EQUAL_HEX16(expTempLimit, SE98A_regs[reg_addr]); + + limit = 75; + expTempLimit = 0; + TEST_ASSERT_EQUAL(true, SE98_fxnTable.cb_set_config(&gbc_gpp_ap_ts1, + limitToConfig, &limit)); + expTempLimit = ocmp_se98a_set_temp_limit(limit); + TEST_ASSERT_EQUAL_HEX16(expTempLimit, SE98A_regs[reg_addr]); + + limit = -75; + expTempLimit = 0; + TEST_ASSERT_EQUAL(true, SE98_fxnTable.cb_set_config(&gbc_gpp_ap_ts1, + limitToConfig, &limit)); + expTempLimit = ocmp_se98a_set_temp_limit(limit); + TEST_ASSERT_EQUAL_HEX16(expTempLimit, SE98A_regs[reg_addr]); + + limit = 127; + expTempLimit = 0; + TEST_ASSERT_EQUAL(true, SE98_fxnTable.cb_set_config(&gbc_gpp_ap_ts1, + limitToConfig, &limit)); + expTempLimit = ocmp_se98a_set_temp_limit(limit); + TEST_ASSERT_EQUAL_HEX16(expTempLimit, SE98A_regs[reg_addr]); + + limit = -128; + expTempLimit = 0; + TEST_ASSERT_EQUAL(true, SE98_fxnTable.cb_set_config(&gbc_gpp_ap_ts1, + limitToConfig, &limit)); + expTempLimit = ocmp_se98a_set_temp_limit(limit); + TEST_ASSERT_EQUAL_HEX16(expTempLimit, SE98A_regs[reg_addr]); + + /* Test with a missing device */ + SE98A_regs[reg_addr] = 0x0000; + limit = 20; + expTempLimit = 0; + TEST_ASSERT_EQUAL(false, SE98_fxnTable.cb_set_config( + &s_invalid_device, limitToConfig, &limit)); + /* Test with a missing device */ + SE98A_regs[reg_addr] = 0x0000; + limit = 20; + expTempLimit = 0; + TEST_ASSERT_EQUAL(false, SE98_fxnTable.cb_set_config( + &s_invalid_bus, limitToConfig, &limit)); + + /* Test with a missing device */ + SE98A_regs[reg_addr] = 0x0000; + limit = 20; + expTempLimit = 0; + TEST_ASSERT_EQUAL(false, + SE98_fxnTable.cb_set_config(&gbc_gpp_ap_ts1, 4, &limit)); +} + +void test_ocmp_se98a_temp_sens_set_limit(void) +{ + /* Register: + * SE98A_REG_HIGH_LIM = SE98A_REG_HIGH_LIMIT + * SE98A_REG_LOW_LIM = SE98A_REG_LOW_LIMIT + * SE98A_REG_CRIT_LIM = SE98A_REG_CRITICAL_LIMIT + */ + test_ocmp_se98a_set_x_limit(SE98A_CONFIG_LIM_LOW, SE98A_REG_LOW_LIMIT); + test_ocmp_se98a_set_x_limit(SE98A_CONFIG_LIM_HIGH, SE98A_REG_HIGH_LIMIT); + test_ocmp_se98a_set_x_limit(SE98A_CONFIG_LIM_CRIT, + SE98A_REG_CRITICAL_LIMIT); +} + +void test_ocmp_se98a_alert_handler(void) +{ + int16_t value = 0x0000; + + AlertData alert_data = { + .subsystem = GPP_SUBSYSTEM, + .componentId = AP_COMPONENET, + .deviceId = GPP_TEMP_SENS_DEVICE_ID, + }; + + TEST_ASSERT_EQUAL(POST_DEV_CFG_DONE, + SE98_fxnTable.cb_init(&gbc_gpp_ap_ts1, + &fact_ap_se98a_ts1_cfg, + &alert_data)); + + gbc_gpp_ap_ts1.obj.alert_cb(SE98A_EVT_ACT, value, &alert_data); + gbc_gpp_ap_ts1.obj.alert_cb(SE98A_EVT_AAW, value, &alert_data); + gbc_gpp_ap_ts1.obj.alert_cb(SE98A_EVT_BAW, value, &alert_data); + + /* Test for memory check */ + gbc_gpp_ap_ts1.obj.alert_cb(SE98A_EVT_ACT, value, NULL); + + /* Default case test */ + gbc_gpp_ap_ts1.obj.alert_cb(SE98A_EVT_DEFAULT, value, &alert_data); +}