Integration Guidelines

Informative

How a Chiisai HAL driver is packaged, configured, and wired into a project — the integrator’s view. The binding rules behind these guidelines live in the Requirements.

Package layout

Each module package follows a common directory structure. Only the <Mip> folder may be extended with further sub-folders (next to the three standard ones);

Documentation, Generator, and Implementation are leaf folders that contain files only, with no nested sub-folders:

<InstallDir>
└─ <Mip>                   # extra sub-folders may be added here, next to the three below
   ├─ Documentation        the module's specification / documentation files   # files only — no sub-folders
   ├─ Generator            generator scripts and template files               # files only — no sub-folders
   └─ Implementation       implementation sources                             # files only — no sub-folders

Normative: CHI-GEN-MUST-06.

Modules with and without an upper-layer stack

Whether a module has an upper-layer interface stack is fixed by its specification, and it determines both where the driver’s general types header comes from and who implements the functions the driver reports events through (the layering view is in Architecture and Layering):

With an upper-layer stack

Without an upper-layer stack

Modules

Can, Lin, Mem, Wdg

I2c, Mcu, Port, Spi, Uart

General types header

<Ma>If_DriverTypes.h, published by the interface stack

<Ma>_DriverTypes.h, published by the module itself

Events reported through

<Ma>If_On<Event>, declared in <Ma>If.h and implemented by the stack

<Mip>_Callout_On<Event> callouts, declared in <Mip>.h and implemented by the integrator

Integrator writes

code above the interface stack

the user code blocks in <Mip>_Callout_Stubs.c

        flowchart LR
    subgraph withstack["Module with an upper-layer stack"]
        direction TB
        Driver1["Chiisai HAL driver (&lt;Mip&gt;)"]
        IfTypes["&lt;Ma&gt;If_DriverTypes.h<br/>from the upper-layer stack<br/>(CanIf / LinIf / …)"]
        IfFns["&lt;Ma&gt;If_On* implemented<br/>by the stack"]
        Driver1 -->|"includes"| IfTypes
        Driver1 -->|"reports through"| IfFns
    end
    subgraph nostack["Module without an upper-layer stack"]
        direction TB
        Driver2["Chiisai HAL driver (&lt;Mip&gt;)"]
        MaTypes["&lt;Ma&gt;_DriverTypes.h<br/>published by the module"]
        Callouts["&lt;Mip&gt;_Callout_On* implemented by<br/>the integrator in &lt;Mip&gt;_Callout_Stubs.c"]
        Driver2 -->|"includes"| MaTypes
        Driver2 -->|"reports through"| Callouts
    end
    

Where a driver’s general types header comes from, and who implements the functions it reports through. A module with an upper-layer stack (left) gets both from that stack; a module without one (right) publishes its own types header and declares callouts that the integrator implements in the generated stub file.

Connecting your components via the callout file

For a module without an upper-layer stack, the module generator emits <Mip>_Callout_Stubs.c: one default, empty implementation of every callout the active configuration enables. This is the file an integrator edits — it is the seam between the driver and the integrator’s own components.

  • Fill in the user code blocks. Each callout body contains a user code block delimited by USERBLOCK markers naming that callout. Put your code inside the markers and leave the markers themselves untouched — the generator finds your code by them.

  • What survives regeneration. Everything inside a user code block, including the block for your own #include directives. Anything you write outside the blocks is generator-owned and will be replaced.

  • Callouts you have not configured. These are still emitted, but excluded from compilation (inside #if 0), so code you wrote for a callout is not lost if you disable and later re-enable the corresponding event.

  • What you must not do. Do not rename the file, move a callout out of it, or edit the marker comments; and do not rely on a callout being reached from a particular context — a callout may be invoked from an interrupt or from the module’s PollFunction depending on configuration, so keep the body short and re-entrancy-safe as documented for that callout.

The complete file skeleton, annotated, is in The Callout Stub File. Each module’s own callouts and their exact contract are listed in that module’s API reference.

Normative: CHI-GEN-MUST-14, CHI-GEN-MUST-15, CHI-GEN-MUST-16.

Dependency management

  • A driver imports only the headers required for its functionality and exports only what other modules need — keep the coupling surface small.

  • Only the general types header is exempt from the per-file include-guard rule; every other header carries a guard named after the file.

  • A driver includes its own header so the toolchain can check declarations against definitions.

Configuration and build flow

A driver is configured through a configuration model, not by hand-editing generated code. Each module ships:

  • a configuration-model definition (the <Mip>Model root, with a general section and a config_set section);

  • a generator script and templates that turn a validated configuration into the driver’s configuration sources.

Configuration naming follows a fixed style — UpperCamelCase for model classes, snake_case for properties, SNAKE_CASE for enumeration values — and vendor-specific properties are prefixed ext_ so they are clearly separable from the standardized set. The detailed model and the per-module property tables are in each module’s configuration reference (for the CAN example, see Configuration Reference).

Normative: CHI-GEN-MUST-12.

Interrupts and critical sections

  • Interrupt handlers are defined with the common ISR() macro rather than a raw, compiler-specific handler signature, so handler definitions stay portable across toolchains.

  • Where a driver needs exclusive access to shared state, it brackets the region with the common <Mip>_EnterCriticalSection / <Mip>_ExitCriticalSection services, which the integrator supplies. A driver keeps these regions as short as possible.

The exact signatures of the ISR() macro, the critical-section services, the logging service (LogM_Report), and the shared types are defined in the Reference and referenced from each module.

Normative: CHI-GEN-MUST-10, CHI-GEN-MUST-11.