Skip to content
christoph2Public

About

ASAM ASAP2 Library for Python

Topics

Resources

Code of conduct

Stars

173 stars

Watchers

23 watching

Forks

Latest commit

 

History

1,359 Commits

Folders and files

Repository files navigation

Readme

PyPI Python Versions License: LGPL v3+ Code style: black Ask DeepWiki PDF Manual

pya2l_social.jpg

pyA2L is an ASAM MCD-2MC processing library written in Python.

If you work with ECUs, ASAP2/A2L is the contract that describes what and how to measure or calibrate. pyA2L helps you parse once, inspect and validate programmatically, automate checks, and export back when needed — all from Python.

Contents

  • About ASAM MCD-2 MC (ASAP2)
  • What pyA2L offers
  • Installation
  • Getting Started (Quickstart)
  • Command-line usage
  • Tips
  • Examples
  • Compatibility
  • Project links
  • Contributing
  • Code of Conduct
  • License
  • Changelog / Release notes
  • Acknowledgements

About ASAM MCD-2 MC (ASAP2)

ASAM MCD-2 MC (ASAP2) is the ASAM standard that defines the A2L description format for ECU measurement signals and calibration parameters. In practice, the A2L acts as a contract between ECU software and tools so different vendors can consistently locate data in memory and convert raw values into physical engineering units. Runtime transport (e.g., CCP/XCP) is out of scope of the standard.

For an authoritative overview of the standard, see the ASAM page: https://www.asam.net/standards/detail/mcd-2-mc/

What pyA2L offers

  • Parse .a2l files and persist them as compact, queryable SQLite databases (.a2ldb) to avoid repeated parse costs.
  • Programmatic access to ASAP2 entities via SQLAlchemy ORM models (MODULE, MEASUREMENT, CHARACTERISTIC, AXIS_DESCR, RECORD_LAYOUT, COMPU_METHOD/COMPU_TAB, UNIT, FUNCTION, GROUP, VARIANT_CODING, etc.).
  • Rich inspection helpers in pya2l.api.inspect (e.g., Characteristic, Measurement, AxisDescr, ModPar, ModCommon) to compute shapes, axis info, allocated memory, conversions, and more.
  • Creator API in pya2l.api.create to programmatically build or augment A2L content (PROJECT, MODULE, MEASUREMENT, CHARACTERISTIC, COMPU_METHOD, AXIS_PTS, RECORD_LAYOUT, GROUP, FUNCTION, etc.).
  • Validation utilities (pya2l.api.validate) to check common ASAP2 rules and project-specific consistency.
  • Export .a2ldb content back to A2L text or JSON when needed.
  • Building blocks for automation: reporting, quality gates, CI checks, and integration with CCP/XCP workflows.

Supported ASAP2 version: 1.7.1

Why pyA2L?

  • Parse once, query fast: Avoid repeated parser runs by working from SQLite.
  • Powerful model: Use SQLAlchemy ORM to navigate ASAP2 entities naturally.
  • Beyond parsing: Inspect derived properties, validate consistency, and export back to A2L.
  • Automate: Integrate with CI to enforce quality gates on A2L content.

Design highlights

  • SQLite-backed storage (.a2ldb) with SQLAlchemy models
  • C++ parser (ANTLR4-based) for fast parsing (2.5 MB/s)
  • Adaptive flush strategy automatically tunes performance (10% speedup for large files)
  • High-level inspection helpers in pya2l.api.inspect
  • Creator API in pya2l.api.create for programmatic A2L generation
  • Validator framework in pya2l.api.validate yielding structured diagnostics
  • Export to A2L text or JSON format with complete roundtrip fidelity
  • Optional CLI (a2ldb-imex) for import/export tasks
  • Concurrent access via SQLite WAL mode (multiple readers during export)

Learn more about the standard at the ASAM website: https://www.asam.net/standards/detail/mcd-2-mc/wiki/

Installation

  • Via pip: shell $ pip install pya2ldb IMPORTANT: Package-name is pya2ldb NOT pya2l!!!
  • From Github:

Getting Started (Quickstart)

Parse once, work from SQLite thereafter.

Import a .a2l file and persist it as .a2ldb (SQLite):

from pya2l import import_a2l

session = import_a2l(
    "ASAP2_Demo_V161.a2l",
    # Optional:
    # encoding="utf-8",        # default is latin-1
    # progress_bar=False,      # silence the progress meter
    # loglevel="ERROR",        # also suppresses progress
    # force_overwrite=True,    # overwrite existing .a2ldb without prompting
)
# Creates ASAP2_Demo_V161.a2ldb in the working directory
  • Open an existing .a2ldb without re-parsing:
from pya2l import open_existing

session = open_existing("ASAP2_Demo_V161")  # extension .a2ldb is implied

Or use a context manager so resources are closed deterministically:

from pya2l import open_existing
import pya2l.model as model

with open_existing("ASAP2_Demo_V161") as session:
    measurements = session.query(model.Measurement).limit(5).all()

Query with SQLAlchemy ORM - List all measurements ordered by name with address and data type:

from pya2l import open_existing
import pya2l.model as model

session = open_existing("ASAP2_Demo_V161")
measurements = (
    session.query(model.Measurement)
    .order_by(model.Measurement.name)
    .all()
)
for m in measurements:
    print(f"{m.name:48} {m.datatype:12} 0x{m.ecu_address.address:08x}")

When not using with ... as ..., call session.close() when finished so SQLite WAL data is checkpointed and file handles are released.

High-level inspection helpers - Use convenience wrappers from pya2l.api.inspect to access derived info:

from pya2l import open_existing
from pya2l.api.inspect import Characteristic, Measurement, AxisDescr

session = open_existing("ASAP2_Demo_V161")
ch = Characteristic(session, "ASAM.C.MAP.UBYTE.IDENTICAL")
print("shape:", ch.dim().shape)
print("element size:", ch.fnc_element_size(), "bytes")
print("num axes:", ch.num_axes())

me = Measurement(session, "ASAM.M.SCALAR.UBYTE.IDENTICAL")
print("is virtual:", me.is_virtual())

axis = ch.axisDescription("X")
print("axis info:", axis.axisDescription("X"))

Create A2L content programmatically - Use the Creator API to build or augment A2L databases:

from pya2l import open_create
from pya2l.api.create import (
    ProjectCreator, ModuleCreator, MeasurementCreator,
    CharacteristicCreator, CompuMethodCreator
)

session = open_create("MyProject.a2ldb")

# Create project and module
pc = ProjectCreator(session)
project = pc.create_project("MyProject", "Demo ECU Project")

mc = ModuleCreator(session)
module = mc.create_module("MyModule", "Demo Module", project=project)

# Add a conversion method
cmc = CompuMethodCreator(session)
cm = cmc.create_compu_method(
    "CM_Voltage", "Voltage conversion", "LINEAR",
    "%6.3", "V", module_name="MyModule"
)
cmc.add_coeffs_linear(cm, offset=0.0, factor=0.01)  # y = 0.01*x + 0

# Add a measurement
mec = MeasurementCreator(session)
meas = mec.create_measurement(
    "BatteryVoltage", "Battery voltage in Volts",
    "UWORD", "CM_Voltage", resolution=1, accuracy=0.1,
    lower_limit=0.0, upper_limit=20.0,
    module_name="MyModule"
)
mec.add_ecu_address(meas, 0x1000)

# Add a characteristic (calibration parameter)
cc = CharacteristicCreator(session)
char = cc.create_characteristic(
    "InjectionMap", "Fuel injection map",
    "MAP", 0x2000, "RL_InjMap", 0.0, "CM_Voltage",
    0.0, 100.0, module_name="MyModule"
)

mc.commit()
db.close()

Validate your database

from pya2l import open_existing
from pya2l.api.validate import Validator

session = open_existing("ASAP2_Demo_V161")
vd = Validator(session)
for msg in vd():  # iterate diagnostics
    # msg has fields: type (Level), category (Category), diag_code (Diagnostics), text (str)
    print(msg.type.name, msg.category.name, msg.diag_code.name, "-", msg.text)

Export back to A2L or JSON

from pya2l import export_a2l

# Export to A2L text format
export_a2l("ASAP2_Demo_V161", "exported.a2l")

# Or export to JSON for further processing
from pya2l.imex.json_exporter import export_json
export_json("ASAP2_Demo_V161.a2ldb", "exported.json")

Tips

  • Default import encoding is latin-1; override encoding= if your file differs.
  • Silence the progress meter via progress_bar=False or loglevel="ERROR".
  • Python package name is pya2ldb (not pya2l).
  • See howto for Excel export and other short recipes.

Examples

  • See pya2l/examples for sample A2L files and scripts.
  • The Sphinx docs contain a fuller tutorial and HOWTO guides.

Create API and coverage parity

pyA2L offers a Creator API in pya2l.api.create to programmatically build or augment A2L content. The project’s goal is coverage parity: everything you can query via pya2l.api.inspect is intended to be creatable via pya2l.api.create.

Example: creating common entities

from pya2l import open_create
from pya2l.api.create import ModuleCreator
from pya2l.api.inspect import Module

# Open or create a database
session = open_create("MyProject.a2l")  # or .a2ldb

mc = ModuleCreator(session)
# Create a module
mod = mc.create_module("DEMO", "Demo ECU module")

# Units and conversions
temp_unit = mc.add_unit(mod, name="degC", long_identifier="Celsius",
                        display="°C", type_str="TEMPERATURE")
ct = mc.add_compu_tab(mod, name="TAB_NOINTP_DEMO", long_identifier="Demo Tab",
                      conversion_type="TAB_NOINTP",
                      pairs=[(0, 0.0), (100, 1.0)], default_numeric=0.0)

# Frames and transformers
fr = mc.add_frame(mod, name="FRAME1", long_identifier="Demo frame",
                  scaling_unit=1, rate=10, measurements=["ENGINE_SPEED"])
tr = mc.add_transformer(mod, name="TR1", version="1.0",
                        executable32="tr32.dll", executable64="tr64.dll",
                        timeout=1000, trigger="ON_CHANGE", inverse="NONE",
                        in_objects=["ENGINE_SPEED"], out_objects=["SPEED_PHYS"])

# Typedefs and instances
ts = mc.add_typedef_structure(mod, name="TSig", long_identifier="Signal",
                              size=8)
mc.add_structure_component(ts, name="raw", typedefName="UWORD", addressOffset=0)
inst = mc.add_instance(mod, name="S1", long_identifier="Inst of TSig",
                       type_name="TSig", address=0x1000)

# Verify with inspect helpers
mi = Module(session)
print("#frames:", len(list(mi.frame.query())))
print("#compu tabs:", len(list(mi.compu_tab.query())))

See pya2l/examples/create_quickstart.py for a more complete example.

Command-line usage

A small CLI is provided as a console script named a2ldb-imex:

# Show version (exit 0)
$ a2ldb-imex -V

# Import an A2L (creates .a2ldb next to the input or in CWD with -L)
$ a2ldb-imex -i path/to/file.a2l

# Import with explicit encoding and create DB in current directory
$ a2ldb-imex -i path/to/file.a2l -E latin-1 -L

# Overwrite existing .a2ldb without prompting
$ a2ldb-imex -i path/to/file.a2l -f

# Suppress all output (useful in scripts/CI)
$ a2ldb-imex -i path/to/file.a2l -q

# Export an .a2ldb back to A2L text (stdout by default or -o file)
$ a2ldb-imex -e path/to/file.a2ldb -o exported.a2l

Compatibility

  • Python: 3.10 – 3.14
  • Platforms: Prebuilt wheels are published for selected platforms. From source, Windows/macOS are supported; Linux may require building native extensions.

Project links

Contributing

Contributions are welcome! Please open an issue to discuss significant changes before submitting a PR. See the existing tests under pya2l/tests and examples under pya2l/examples to get started. Contributors should use pre-commit to run formatting and lint checks before committing; see https://pre-commit.com/ for installation and usage.

Code of Conduct

This project follows a Code of Conduct to foster an open and welcoming community. Please read and abide by it when interacting in issues, discussions, and pull requests.

See CODE_OF_CONDUCT for full details.

Changelog / Release notes

See GitHub Releases: https://github.com/christoph2/pyA2L/releases

About

ASAM ASAP2 Library for Python

Topics

Resources

Code of conduct

Stars

173 stars

Watchers

23 watching

Forks

Releases

Sponsor this project

Packages

Used by

Contributors

Languages