LDF Parser
ldfparser is a Python library designed to parse LIN Description Files (LDF), enabling extraction of signal names, frame definitions, and facilitating encoding and decoding of LIN messages. It supports LIN standards 1.3, 2.0, 2.1, and 2.2A. Currently, the library is in a pre-release state, which means that features might undergo changes between minor versions.
Common errors
-
FileNotFoundError: 'non_existent.ldf' doesn't exist
cause The path provided to `ldfparser.parse_ldf` does not point to an accessible LDF file.fixEnsure the LDF file exists at the specified path and that the Python process has read permissions for it. Double-check the file name and directory. -
KeyError: 'Frame_X'
cause Attempted to access a frame (e.g., `ldf.get_unconditional_frame('Frame_X')`) or signal that does not exist or is misspelled in the parsed LDF.fixVerify the exact name of the frame or signal in the LDF file. Use `ldf.frames` or `ldf.signals` to inspect available names or iterate through them. -
AttributeError: 'LinSignal' object has no attribute 'frame'
cause Attempting to access `signal.frame` when the signal is associated with multiple frames, especially after v0.26.0 which introduced `signal.frames`.fixUse `signal.frames` (which is a list of frames) to determine the owners of a signal. Iterate over this list if a signal can belong to multiple frames. For signals with a single frame owner, `signal.frame` will still be populated for backward compatibility. -
ldfparser.parser.LDFParserException: Error parsing LDF file: ...
cause The provided LDF file contains syntax errors or deviations from the LIN standard that the parser cannot handle, leading to a parsing failure.fixReview the LDF file for syntax errors. Validate it with a commercial LDF editor if possible. Consider simplifying the LDF to isolate the problematic section or upgrading `ldfparser` if it's an old version with a known parsing bug.
Warnings
- breaking As of v0.26.0, `signal.frames` is the new way to determine signal owners for compatibility with signals associated with multiple frames. While `signal.frame` is still set if a signal belongs to only one frame, relying on `signal.frame` directly for multi-frame signals is discouraged.
- breaking In v0.26.0, physical values are now rounded to the nearest integer during conversion, rather than always rounded down. This can change the output of decoded signals.
- deprecated Prior to v0.10.0, several functions like `parseLDF`, `parseLDFtoDict`, `parseComments`, and direct attribute access like `LDF.frame(x)` were common. These have been deprecated in favor of snake_case function names (`parse_ldf`) and proper getter methods.
- gotcha The library is in a 'pre-release' state, and features may break between minor versions. This means APIs or internal behaviors can change without a major version increment.
- gotcha Due to known ambiguities or errors in LIN standard documentation, `ldfparser` cannot guarantee parsing correctness for *all* LDF files.
Install
-
pip install ldfparser
Imports
- parse_ldf
from ldfparser import parse_ldf
- LDF
import ldfparser ldf = ldfparser.parse_ldf(path='file.ldf')
Quickstart
import ldfparser
import os
import tempfile
import binascii
# Create a dummy LDF file for demonstration
ldf_content = """
LIN_description_file;
LIN_protocol_version = "2.1";
LIN_language_version = "2.1";
LIN_speed = 19.2 kbps;
Nodes {
Master: MasterNode, 5 ms, 0.1 ms;
Slaves: SlaveNode1;
}
Signals {
EngineRPM: 12, 0, MasterNode, MasterNode;
CoolantTemp: 8, 12, MasterNode, MasterNode;
}
Frames {
EngineFrame: 0x10, 8, MasterNode;
Signals {
EngineRPM, 0;
CoolantTemp, 2;
}
}
Signal_encoding_types {
MotorRPM_encoding:
physical_value,
0, 255, 1, 0, "RPM";
}
Signal_representation {
MotorRPM_encoding: EngineRPM;
}
"""
with tempfile.NamedTemporaryFile(mode='w', delete=False, suffix='.ldf') as temp_ldf_file:
temp_ldf_file.write(ldf_content)
ldf_path = temp_ldf_file.name
try:
# Load LDF
ldf = ldfparser.parse_ldf(path=ldf_path)
print(f"Successfully parsed LDF from: {ldf_path}")
# Get baudrate
print(f"Baudrate: {ldf.get_baudrate()} kbps")
# Get an unconditional frame
frame = ldf.get_unconditional_frame('EngineFrame')
print(f"Frame 'EngineFrame' ID: {frame.frame_id}, Length: {frame.length} bytes")
# Encode signal values
signal_values = {"EngineRPM": 1500, "CoolantTemp": 95}
message = frame.encode(signal_values)
print(f"Encoded message for {signal_values}: 0x{binascii.hexlify(message).decode('utf-8')}")
# Decode message
decoded_values = frame.decode(message)
print(f"Decoded message: {decoded_values}")
except Exception as e:
print(f"An error occurred: {e}")
finally:
# Clean up the temporary LDF file
if os.path.exists(ldf_path):
os.remove(ldf_path)