IonizationChamber/Software/Firmware/UnitTest/test_mcp3425.c

345 wiersze
8.0 KiB
C
Executable File

#include <stdarg.h>
#include <stddef.h>
#include <setjmp.h> // NOLINT(misc-include-cleaner), needed by <cmocka.h>
#include <cmocka.h>
#include <stdint.h>
// Include production code
#include "mcp3425.h"
#include "stm8s_i2c.h"
#include "stm8s_gpio.h"
#include "stm8s.h"
// =============================================================================
// TEST CONFIGURATION
// =============================================================================
/**
* @def I2C_MASTER_ADDRESS
* @brief I2C master address for testing
*/
#define I2C_MASTER_ADDRESS 0x10
// =============================================================================
// MOCK STATE TRACKING
// =============================================================================
/**
* @var i2c_bus_busy
* @brief Tracks I2C bus busy status
*/
static bool i2c_bus_busy = FALSE;
/**
* @var i2c_last_sent_data
* @brief Stores the last byte sent via I2C
*/
static uint8_t i2c_last_sent_data = 0;
#define RECEIVE_DATA_LEN 8
/**
* @var i2c_receive_data
* @brief Buffer for simulated I2C receive data
*/
static uint8_t i2c_receive_data[RECEIVE_DATA_LEN] = {0};
/**
* @var i2c_receive_index
* @brief Index for reading from receive buffer
*/
static uint8_t i2c_receive_index = 0;
/**
* @var i2c_event_status
* @brief Simulates I2C event status register
*/
static uint8_t i2c_event_status = 0;
// =============================================================================
// MOCK FUNCTION IMPLEMENTATIONS
// =============================================================================
/**
* @brief Mock implementation of GPIO_Init
*
* Stub function to satisfy linker requirements.
*
* @param GPIOx GPIO port pointer
* @param GPIO_Pin Pin selection
* @param GPIO_Mode Pin mode configuration
*/
void GPIO_Init(
GPIO_TypeDef * GPIOx,
GPIO_Pin_TypeDef GPIO_Pin,
GPIO_Mode_TypeDef GPIO_Mode)
{
(void)GPIOx;
(void)GPIO_Pin;
(void)GPIO_Mode;
}
/**
* @brief Mock implementation of I2C_DeInit
*
* Resets all I2C mock state variables to default values.
*/
void I2C_DeInit(
void)
{
i2c_bus_busy = FALSE;
i2c_last_sent_data = 0;
i2c_receive_index = 0;
i2c_event_status = 0;
}
/**
* @brief Mock implementation of I2C_Init
*
* Verifies I2C initialization parameters.
*
* @param OutputClockFrequencyHz Desired I2C clock frequency
* @param OwnAddress Master device address
* @param I2C_DutyCycle I2C duty cycle mode
* @param Ack Acknowledge enable/disable
* @param AddMode Addressing mode
* @param InputClockFrequencyMHz Input clock frequency in MHz
*/
void I2C_Init(
uint32_t OutputClockFrequencyHz,
uint16_t OwnAddress,
I2C_DutyCycle_TypeDef I2C_DutyCycle,
I2C_Ack_TypeDef Ack,
I2C_AddMode_TypeDef AddMode,
uint8_t InputClockFrequencyMHz)
{
check_expected(OutputClockFrequencyHz);
check_expected(OwnAddress);
check_expected(I2C_DutyCycle);
check_expected(Ack);
check_expected(AddMode);
check_expected(InputClockFrequencyMHz);
}
/**
* @brief Mock implementation of I2C_Cmd
*
* Verifies I2C enable/disable commands.
*
* @param NewState ENABLE or DISABLE command
*/
void I2C_Cmd(
FunctionalState NewState)
{
check_expected(NewState);
}
/**
* @brief Mock implementation of I2C_GenerateSTART
*
* Simulates START condition generation and updates bus state.
*
* @param NewState ENABLE to generate START condition
*/
void I2C_GenerateSTART(
FunctionalState NewState)
{
if(NewState == ENABLE)
{
i2c_event_status |= I2C_EVENT_MASTER_MODE_SELECT;
i2c_bus_busy = TRUE;
}
}
/**
* @brief Mock implementation of I2C_CheckEvent
*
* Simulates I2C event status checking.
*
* @param I2C_Event Event to check
* @return ErrorStatus SUCCESS if event occurred, ERROR otherwise
*/
ErrorStatus I2C_CheckEvent(
I2C_Event_TypeDef I2C_Event)
{
return (i2c_event_status & I2C_Event) ? SUCCESS : ERROR;
}
/**
* @brief Mock implementation of I2C_Send7bitAddress
*
* Verifies address transmission and simulates address ACK event.
*
* @param Address Slave address to send
* @param Direction Transmission direction (TX/RX)
*/
void I2C_Send7bitAddress(
uint8_t Address,
I2C_Direction_TypeDef Direction)
{
check_expected(Address);
check_expected(Direction);
if(Direction == I2C_DIRECTION_TX)
{
i2c_event_status |= I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED;
}
else
{
i2c_event_status |= I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED;
}
}
/**
* @brief Mock implementation of I2C_SendData
*
* Stores sent data and simulates byte transmission event.
*
* @param Data Byte to send
*/
void I2C_SendData(
uint8_t Data)
{
i2c_last_sent_data = Data;
i2c_event_status |= I2C_EVENT_MASTER_BYTE_TRANSMITTED;
check_expected(Data);
}
/**
* @brief Mock implementation of I2C_GenerateSTOP
*
* Simulates STOP condition generation and resets bus state.
*
* @param NewState ENABLE to generate STOP condition
*/
void I2C_GenerateSTOP(
FunctionalState NewState)
{
if(NewState == ENABLE)
{
i2c_bus_busy = FALSE;
i2c_event_status = 0;
}
}
/**
* @brief Mock implementation of I2C_GetFlagStatus
*
* Simulates I2C flag status checking.
*
* @param I2C_Flag Flag to check
* @return FlagStatus SET if flag is set, RESET otherwise
*/
FlagStatus I2C_GetFlagStatus(
I2C_Flag_TypeDef I2C_Flag)
{
if(I2C_Flag == I2C_FLAG_BUSBUSY)
{
return i2c_bus_busy ? SET : RESET;
}
return RESET;
}
/**
* @brief Mock implementation of I2C_ReceiveData
*
* Simulates data reception from I2C bus.
*
* @return uint8_t Received data byte
*/
uint8_t I2C_ReceiveData(
void)
{
if(i2c_receive_index < sizeof(i2c_receive_data))
{
return i2c_receive_data[i2c_receive_index++];
}
return 0;
}
/**
* @brief Mock implementation of I2C_AcknowledgeConfig
*
* Stub function to satisfy linker requirements.
*
* @param Ack ACK configuration
*/
void I2C_AcknowledgeConfig(
I2C_Ack_TypeDef Ack)
{
(void)Ack;
}
/**
* @brief Mock implementation of CLK_GetClockFreq
*
* Simulates clock frequency retrieval.
*
* @return uint32_t Current clock frequency
*/
uint32_t CLK_GetClockFreq(
void)
{
return (uint32_t)mock(); // Use mock() to return expected value
}
// =============================================================================
// TEST CASES
// =============================================================================
/**
* @brief Tests MCP3425 initialization sequence
*
* Verifies that the MCP3425 initialization:
* 1. Retrieves the correct system clock frequency
* 2. Configures I2C peripheral with correct parameters:
* - 100kHz output clock
* - 7-bit addressing mode
* - Standard duty cycle
* - Acknowledge enabled
* 3. Enables the I2C peripheral
*
* @param state CMocka state object (unused)
*/
static void test_Init_ConfiguresGPIOAndI2C(
void **state)
{
(void)state;
// 1. Set clock frequency expectation
will_return(CLK_GetClockFreq, 16000000); // 16MHz clock
// 2. Set I2C_Init expectations
expect_value(I2C_Init, OutputClockFrequencyHz, 100000);
expect_value(I2C_Init, OwnAddress, I2C_MASTER_ADDRESS);
expect_value(I2C_Init, I2C_DutyCycle, I2C_DUTYCYCLE_2);
expect_value(I2C_Init, Ack, I2C_ACK_CURR);
expect_value(I2C_Init, AddMode, I2C_ADDMODE_7BIT);
expect_value(I2C_Init, InputClockFrequencyMHz, 16); // 16MHz / 1,000,000
// 3. Set I2C_Cmd expectation
expect_value(I2C_Cmd, NewState, ENABLE);
// Execute function under test
mcp3425_init();
}
// =============================================================================
// TEST RUNNER
// =============================================================================
/**
* @brief Test runner entry point
*
* Executes the MCP3425 initialization test:
* 1. Initializes the CMocka test environment
* 2. Runs the I2C configuration test
*
* @return int Number of failed tests (0 if all pass)
*/
int main(
void)
{
const struct CMUnitTest tests[] = {
cmocka_unit_test(test_Init_ConfiguresGPIOAndI2C)
};
return cmocka_run_group_tests(tests, NULL, NULL);
}