Skip to content

Ceedling Temperature Sensor Project

An imagined temperature sensor accessory with ADC, timer, and USART subsystems — firmware organized in embedded C layers.

This example project illustrates:

  • CMock mocks for isolating hardware and peripheral modules under test
  • Custom Unity assertions for project-specific data types, defined in test/support/
  • Subdirectory test organization with ADC tests grouped in their own subfolder
  • Integration tests alongside unit tests (TestTimerIntegrated.c, TestUsartIntegrated.c)
  • Per-file symbol definitions via the :defines matcher section in project.yml
  • Per-file compiler flags via the :flags section in project.yml
  • Test preprocessor enabled for all files (:use_test_preprocessor: :all)
  • Optional add-ons via mixins:
    • gcov plugin coverage reporting
    • Custom assertion activation for more detailed failure messages.

This project implements the Model-Conductor-Hardware design pattern:

  • Model modules manage state and logic
  • Hardware modules abstract hardware interfaces
  • Conductors link the two together and service them

Mocks generated by CMock isolate each components for unit testing, and example integration tests demonstrate exercising cross-module and integrated behavior.

This project is test-suite only (no release build).


Project Structure

temp_sensor/
├── project.yml              # Ceedling configuration
├── mixin/                   # Optional add-on configuration
│   ├── add_gcov.yml         # Enables gcov coverage collection and reporting
│   └── add_unity_helper.yml # Enables custom assertions for project-specific types
├── src/
│   ├── Main.c/.h            # Application entry point
│   ├── Executor.c/.h        # Task execution loop
│   ├── TaskScheduler.c/.h   # Cooperative task scheduler
│   ├── Model.c/.h           # Application data model
│   ├── TemperatureFilter.c/.h
│   ├── Adc*.c/.h            # ADC conductor, hardware, and model layers
│   ├── Timer*.c/.h          # Timer conductor, hardware, and model layers
│   ├── Usart*.c/.h          # USART conductor, hardware, and model layers
│   ├── IntrinsicsWrapper.c/.h
│   ├── Types.h              # Shared type definitions
│   └── calculators/         # Calculation utilities
│       ├── TemperatureCalculator.c/.h
│       └── UsartBaudRateRegisterCalculator.c/.h
└── test/
    ├── Test*.c              # Unit and integration tests
    ├── adc/                 # ADC subsystem tests
    │   └── TestAdc*.c
    └── support/             # Custom assertion helpers (not executed as tests)
        ├── UnityHelper.c    # More assertion failure details than the default comparison
        └── UnityHelper.h

Running the Tests

Run all unit and integration tests:

ceedling test:all

Run a single test file:

ceedling test:TestAdcConductor
ceedling test:TestTimerIntegrated

Run all tests matching a pattern:

ceedling test:pattern[Adc]
ceedling test:pattern[Integrated]

Optional Mixins

Coverage with gcov

Collect and report test coverage (requires gcov and gcovr):

ceedling gcov:all --mixin=mixin/add_gcov.yml

Custom Unity assertions

The project defines a custom assertion for EXAMPLE_STRUCT_T in test/support/UnityHelper.h. It is conditionally compiled and activated by the add_unity_helper mixin, which adds the required define and registers the helper with CMock:

ceedling test:all --mixin=mixin/add_unity_helper.yml