Oakrey.Applications.FileParsing.LDF
1.0.0
See the version list below for details.
dotnet add package Oakrey.Applications.FileParsing.LDF --version 1.0.0
NuGet\Install-Package Oakrey.Applications.FileParsing.LDF -Version 1.0.0
<PackageReference Include="Oakrey.Applications.FileParsing.LDF" Version="1.0.0" />
<PackageVersion Include="Oakrey.Applications.FileParsing.LDF" Version="1.0.0" />
<PackageReference Include="Oakrey.Applications.FileParsing.LDF" />
paket add Oakrey.Applications.FileParsing.LDF --version 1.0.0
#r "nuget: Oakrey.Applications.FileParsing.LDF, 1.0.0"
#:package Oakrey.Applications.FileParsing.LDF@1.0.0
#addin nuget:?package=Oakrey.Applications.FileParsing.LDF&version=1.0.0
#tool nuget:?package=Oakrey.Applications.FileParsing.LDF&version=1.0.0
Oakrey.Applications.FileParsing.LDF
A specialized file parsing library for LDF (LIN Description File) files, built on the FileParsing framework. Provides automatic parsing of LDF files into LdfMatrix objects with reactive updates, file browsing integration, and extended file management capabilities for LIN (Local Interconnect Network) automotive applications.
Features
LDF File Parsing
- Automatic Parsing: Parses LDF files using
Oakrey.LDFlibrary - LdfMatrix Support: Returns structured LIN database with frames, signals, and metadata
- Extended Browsing: Integrates with
FileBrowsing.Extendedfor file operations - Template Support: Includes default LDF template for creating new files
File Management Integration
- Create New LDF Files: Create files from customizable templates
- File Browsing: Browse and select LDF files in directories
- Reactive Updates: Observable pattern for file change notifications
- Auto-Load Support: Optionally load LDF files at application startup
LIN Database Access
- Frames: Access LIN frame definitions
- Signals: Work with signal definitions and parameters
- Network Nodes: Retrieve ECU and node information
- Schedules: Access LIN schedule tables
- Attributes: Access extended attributes and metadata
Settings Integration
- Persistent Configuration: Settings automatically saved and restored
- Auto-Load Control: Enable/disable automatic file loading
- Last Selected File: Remembers last opened LDF file
Built on FileParsing Framework
- Extends
FileParsingServiceBase<LdfMatrix> - Inherits all file parsing framework features
- Consistent API with other file parsers (DBC, INI)
Installation
You can install the package via NuGet Package Manager, Package Manager Console or the .NET CLI.
NuGet Package Manager
- Open your project in Visual Studio.
- Navigate to Tools > NuGet Package Manager > Manage NuGet Packages for Solution....
- Search for
Oakrey.Applications.FileParsing.LDFand click Install.
.NET CLI
Run the following command in your terminal:
dotnet add package Oakrey.Applications.FileParsing.LDF
Package Manager Console
Run the following command in your Package Manager Console:
Install-Package Oakrey.Applications.FileParsing.LDF
Prerequisites
This package requires:
- Oakrey.Applications.FileParsing - Base file parsing framework
- Oakrey.Applications.FileBrowsing.Extended - Extended file browsing with templates
- Oakrey.LDF - LDF file parsing library (LdfMatrix)
Usage Examples
Basic Dependency Injection Setup
using Microsoft.Extensions.DependencyInjection;
using Oakrey.Applications.FileBrowsing.Extended;
using Oakrey.Applications.FileParsing.LDF;
using Oakrey.Applications.UserPrompts.Windows;
public class Startup
{
public void ConfigureServices(IServiceCollection services)
{
// Register user prompts (required)
services.AddUserPromptsService();
// Register extended file browsing for LDF files
services.AddSingleton<IFileExtendedBrowsingServiceSettings,
LdfExtendedFileBrowsingServiceSettings>();
services.AddSingleton<IFileBrowsingService, IExtendedFileBrowsingService,
ExtendedFileBrowsingService>();
// Register LDF parsing service settings
services.AddSingleton<ISettingsService<LdfServiceSettings>,
SettingsService<LdfServiceSettings>>();
services.AddSingleton<ILdfServiceSettings, LdfServiceSettings>();
// Register LDF parsing service
services.AddSingleton<ILdfService, LdfService>();
}
}
Creating LDF File Browsing Settings
using Oakrey.Applications.FileBrowsing;
using Oakrey.Applications.FileBrowsing.Extended;
using Oakrey.Applications.Settings;
public class LdfExtendedFileBrowsingServiceSettings
: FileBrowsingServiceSettingsBase, IFileExtendedBrowsingServiceSettings
{
public LdfExtendedFileBrowsingServiceSettings(
ISettingsService<LdfExtendedFileBrowsingServiceSettings> settingsService)
: base(settingsService)
{
}
public override string FileExtension => "ldf";
public override string SearchPattern => "*.ldf";
// Template loaded from external file or defined inline
public string NewFileTemplate
{
get
{
string templatePath = Path.Combine(
AppDomain.CurrentDomain.BaseDirectory,
"ldfNew.txt");
if (File.Exists(templatePath))
{
return File.ReadAllText(templatePath);
}
// Fallback template
return "LIN_description_file;\nLIN_protocol_version = \"2.1\";\n";
}
}
}
Using the LDF Service
using Oakrey.Applications.FileParsing.LDF;
using Oakrey.LDF;
public class LinManager
{
private readonly ILdfService _ldfService;
public LinManager(ILdfService ldfService)
{
_ldfService = ldfService;
// Subscribe to LDF file changes
_ldfService.FileParsed.Subscribe(OnLdfFileParsed);
}
private void OnLdfFileParsed(LdfMatrix? ldfMatrix)
{
if (ldfMatrix != null)
{
Console.WriteLine($"LDF file loaded: {_ldfService.FilePath}");
Console.WriteLine($"Frames: {ldfMatrix.Frames.Count}");
Console.WriteLine($"Nodes: {ldfMatrix.Nodes.Count}");
// Process the LIN database
ProcessLinDatabase(ldfMatrix);
}
else
{
Console.WriteLine("No LDF file loaded");
}
}
public void ProcessLinDatabase(LdfMatrix matrix)
{
// Access LIN frames
foreach (var frame in matrix.Frames)
{
Console.WriteLine($"Frame: {frame.Name} (ID: {frame.Id})");
// Access signals in the frame
foreach (var signal in frame.Signals)
{
Console.WriteLine($" Signal: {signal.Name}");
Console.WriteLine($" Offset: {signal.Offset}");
Console.WriteLine($" Length: {signal.Size} bits");
}
}
// Access LIN nodes
Console.WriteLine("\nNodes:");
foreach (var node in matrix.Nodes)
{
Console.WriteLine($" - {node.Name}");
}
// Access schedules
Console.WriteLine("\nSchedules:");
foreach (var schedule in matrix.Schedules)
{
Console.WriteLine($" Schedule: {schedule.Name}");
}
}
}
Accessing Current LDF Matrix
public class LinDataProcessor
{
private readonly ILdfService _ldfService;
public LinDataProcessor(ILdfService ldfService)
{
_ldfService = ldfService;
}
public void ProcessLinFrame(byte frameId, byte[] data)
{
// Access current LDF matrix
if (_ldfService.Instance == null)
{
Console.WriteLine("No LDF file loaded");
return;
}
var ldfMatrix = _ldfService.Instance;
// Find frame by ID
var frame = ldfMatrix.Frames.FirstOrDefault(f => f.Id == frameId);
if (frame == null)
{
Console.WriteLine($"Frame ID {frameId} not found in LDF");
return;
}
Console.WriteLine($"Processing frame: {frame.Name}");
// Decode signals
foreach (var signal in frame.Signals)
{
double value = DecodeSignal(signal, data);
double physicalValue = value * signal.Factor + signal.Offset;
Console.WriteLine($" {signal.Name}: {physicalValue}");
}
}
private double DecodeSignal(Signal signal, byte[] data)
{
// Implement signal decoding logic
ulong rawValue = 0;
for (int i = 0; i < signal.Size; i++)
{
int bitPos = signal.Offset + i;
int byteIndex = bitPos / 8;
int bitIndex = bitPos % 8;
if (byteIndex < data.Length)
{
if ((data[byteIndex] & (1 << bitIndex)) != 0)
{
rawValue |= (1UL << i);
}
}
}
return rawValue;
}
}
WPF ViewModel Integration
using Oakrey.Applications.FileParsing.LDF;
using System.ComponentModel;
using System.Windows.Input;
using CommunityToolkit.Mvvm.Input;
public class LdfViewModel : INotifyPropertyChanged
{
private readonly ILdfService _ldfService;
private LdfMatrix? _currentMatrix;
public LdfViewModel(ILdfService ldfService)
{
_ldfService = ldfService;
// Subscribe to LDF file changes
_ldfService.FileParsed.Subscribe(OnLdfParsed);
// Initialize with current matrix
_currentMatrix = _ldfService.Instance;
LoadFileCommand = new AsyncRelayCommand<string>(LoadFileAsync);
RefreshCommand = new RelayCommand(Refresh);
}
public LdfMatrix? CurrentMatrix
{
get => _currentMatrix;
set
{
if (_currentMatrix != value)
{
_currentMatrix = value;
OnPropertyChanged(nameof(CurrentMatrix));
OnPropertyChanged(nameof(IsFileLoaded));
OnPropertyChanged(nameof(FrameCount));
OnPropertyChanged(nameof(NodeCount));
}
}
}
public bool IsFileLoaded => _ldfService.IsFilePathCorrect;
public string CurrentFilePath => _ldfService.FilePath;
public int FrameCount => CurrentMatrix?.Frames.Count ?? 0;
public int NodeCount => CurrentMatrix?.Nodes.Count ?? 0;
public List<string> FrameNames =>
CurrentMatrix?.Frames.Select(f => f.Name).ToList() ?? new List<string>();
public IAsyncRelayCommand<string> LoadFileCommand { get; }
public ICommand RefreshCommand { get; }
private void OnLdfParsed(LdfMatrix? matrix)
{
CurrentMatrix = matrix;
OnPropertyChanged(nameof(CurrentFilePath));
}
private async Task LoadFileAsync(string? filePath)
{
if (!string.IsNullOrEmpty(filePath))
{
var fileInfo = new FileInfo(filePath);
await _ldfService.LoadFile(fileInfo);
}
}
private void Refresh()
{
CurrentMatrix = _ldfService.Instance;
}
public event PropertyChangedEventHandler? PropertyChanged;
protected void OnPropertyChanged(string propertyName)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
Manual File Loading
public class LdfFileLoader
{
private readonly ILdfService _ldfService;
public LdfFileLoader(ILdfService ldfService)
{
_ldfService = ldfService;
}
public async Task<LdfMatrix?> LoadLdfFileAsync(string filePath)
{
var fileInfo = new FileInfo(filePath);
if (!fileInfo.Exists)
{
Console.WriteLine($"LDF file not found: {filePath}");
return null;
}
// Manually load the file
var ldfMatrix = await _ldfService.LoadFile(fileInfo);
if (ldfMatrix != null)
{
Console.WriteLine($"Loaded LDF file: {filePath}");
Console.WriteLine($"Frames: {ldfMatrix.Frames.Count}");
Console.WriteLine($"Signals: {ldfMatrix.Frames.Sum(f => f.Signals.Count)}");
return ldfMatrix;
}
return null;
}
public async Task<LdfMatrix?> LoadWithCancellationAsync(
string filePath,
CancellationToken cancellationToken)
{
var fileInfo = new FileInfo(filePath);
try
{
var ldfMatrix = await _ldfService.LoadFile(fileInfo, cancellationToken);
if (ldfMatrix != null && !cancellationToken.IsCancellationRequested)
{
return ldfMatrix;
}
}
catch (OperationCanceledException)
{
Console.WriteLine("Load operation cancelled");
}
return null;
}
}
Pre-Loading at Application Startup
using Oakrey.Applications;
public class ApplicationStartup
{
private readonly ILdfService _ldfService;
public ApplicationStartup(ILdfService ldfService)
{
_ldfService = ldfService;
}
public async Task InitializeAsync(CancellationToken cancellationToken)
{
// Pre-load LDF file if AutoLoad is enabled
if (_ldfService is IPreLoadable preLoadable)
{
await preLoadable.Preload(cancellationToken);
if (_ldfService.Instance != null)
{
Console.WriteLine("LDF file pre-loaded successfully");
Console.WriteLine($"File: {_ldfService.FilePath}");
Console.WriteLine($"Frames: {_ldfService.Instance.Frames.Count}");
}
}
}
}
Working with LIN Frames and Signals
public class LinFrameAnalyzer
{
private readonly ILdfService _ldfService;
public LinFrameAnalyzer(ILdfService ldfService)
{
_ldfService = ldfService;
}
public void AnalyzeFrame(string frameName)
{
if (_ldfService.Instance == null)
{
Console.WriteLine("No LDF file loaded");
return;
}
var frame = _ldfService.Instance.Frames
.FirstOrDefault(f => f.Name == frameName);
if (frame == null)
{
Console.WriteLine($"Frame '{frameName}' not found");
return;
}
Console.WriteLine($"Frame: {frame.Name}");
Console.WriteLine($" Frame ID: {frame.Id}");
Console.WriteLine($" Length: {frame.Length} bytes");
Console.WriteLine($" Publisher: {frame.Publisher}");
Console.WriteLine($" Signals: {frame.Signals.Count}");
Console.WriteLine();
foreach (var signal in frame.Signals)
{
Console.WriteLine($" Signal: {signal.Name}");
Console.WriteLine($" Offset: {signal.Offset} bits");
Console.WriteLine($" Size: {signal.Size} bits");
Console.WriteLine($" Init Value: {signal.InitValue}");
Console.WriteLine($" Publisher: {signal.Publisher}");
Console.WriteLine($" Subscribers: {string.Join(", ", signal.Subscribers)}");
Console.WriteLine();
}
}
public void ListAllFrames()
{
if (_ldfService.Instance == null)
{
Console.WriteLine("No LDF file loaded");
return;
}
Console.WriteLine("LIN Frames:");
Console.WriteLine("ID | Name | Length | Signals | Publisher");
Console.WriteLine("----|---------------------|--------|---------|----------");
foreach (var frame in _ldfService.Instance.Frames.OrderBy(f => f.Id))
{
Console.WriteLine($"{frame.Id,3} | {frame.Name,-19} | {frame.Length,6} | {frame.Signals.Count,7} | {frame.Publisher}");
}
}
public void ListAllNodes()
{
if (_ldfService.Instance == null)
{
Console.WriteLine("No LDF file loaded");
return;
}
Console.WriteLine("Network Nodes:");
foreach (var node in _ldfService.Instance.Nodes)
{
Console.WriteLine($" - {node.Name}");
Console.WriteLine($" Protocol: {node.ProtocolVersion}");
Console.WriteLine($" Configured NAD: {node.ConfiguredNAD}");
}
}
public void ListSchedules()
{
if (_ldfService.Instance == null)
{
Console.WriteLine("No LDF file loaded");
return;
}
Console.WriteLine("LIN Schedules:");
foreach (var schedule in _ldfService.Instance.Schedules)
{
Console.WriteLine($" Schedule: {schedule.Name}");
Console.WriteLine($" Entries: {schedule.Entries.Count}");
foreach (var entry in schedule.Entries)
{
Console.WriteLine($" - {entry.FrameName} @ {entry.Delay}ms");
}
}
}
}
Complete Application Example
using System.Windows;
using Microsoft.Extensions.DependencyInjection;
using Oakrey.Applications.FileBrowsing.Extended;
using Oakrey.Applications.FileParsing.LDF;
using Oakrey.Applications.UserPrompts.Windows;
public partial class App : Application
{
private IServiceProvider _serviceProvider;
protected override void OnStartup(StartupEventArgs e)
{
base.OnStartup(e);
var services = new ServiceCollection();
// Register user prompts
services.AddUserPromptsService();
// Register extended file browsing for LDF files
services.AddSingleton<ISettingsService<LdfExtendedFileBrowsingServiceSettings>,
SettingsService<LdfExtendedFileBrowsingServiceSettings>>();
services.AddSingleton<IFileExtendedBrowsingServiceSettings,
LdfExtendedFileBrowsingServiceSettings>();
services.AddSingleton<IFileBrowsingService, IExtendedFileBrowsingService,
ExtendedFileBrowsingService>();
// Register LDF parsing service
services.AddSingleton<ISettingsService<LdfServiceSettings>,
SettingsService<LdfServiceSettings>>();
services.AddSingleton<ILdfServiceSettings, LdfServiceSettings>();
services.AddSingleton<ILdfService, LdfService>();
// Register application services
services.AddTransient<LinManager>();
services.AddTransient<MainViewModel>();
_serviceProvider = services.BuildServiceProvider();
// Pre-load LDF file
var ldfService = _serviceProvider.GetRequiredService<ILdfService>();
if (ldfService is IPreLoadable preLoadable)
{
Task.Run(() => preLoadable.Preload(CancellationToken.None)).Wait();
}
var mainWindow = new MainWindow
{
DataContext = _serviceProvider.GetRequiredService<MainViewModel>()
};
mainWindow.Show();
}
}
API Reference
ILdfService
Extends IFileParsingService<LdfMatrix>:
| Property | Type | Description |
|---|---|---|
Instance |
LdfMatrix? |
Currently parsed LDF file |
FileParsed |
IObservable<LdfMatrix?> |
Observable for file parse events |
FilePath |
string |
Path of the currently selected file |
IsFilePathCorrect |
bool |
True if file was parsed successfully |
LdfMatrix Structure
From Oakrey.LDF:
| Property | Type | Description |
|---|---|---|
Frames |
List<Frame> |
LIN frame definitions |
Nodes |
List<Node> |
Network nodes (Master/Slaves) |
Schedules |
List<Schedule> |
LIN schedule tables |
ProtocolVersion |
string |
LDF protocol version |
Frame Structure
| Property | Type | Description |
|---|---|---|
Name |
string |
Frame name |
Id |
byte |
Frame identifier (0-63) |
Length |
int |
Data length (1-8 bytes) |
Publisher |
string |
Publishing node |
Signals |
List<Signal> |
Signal definitions |
Signal Structure
| Property | Type | Description |
|---|---|---|
Name |
string |
Signal name |
Offset |
int |
Bit offset in frame |
Size |
int |
Signal size in bits |
InitValue |
int |
Initial value |
Publisher |
string |
Publishing node |
Subscribers |
List<string> |
Subscribing nodes |
ILdfServiceSettings
Extends IAutoLoadServiceSettings:
| Property | Type | Description |
|---|---|---|
AutoLoad |
bool |
Enable automatic loading on startup |
About LIN and LDF Files
LIN (Local Interconnect Network) is a serial network protocol used for communication between components in vehicles. It's typically used for lower-speed, less critical applications compared to CAN bus.
LDF (LIN Description File) is an XML-based file format that describes:
- Network topology and nodes
- Frame definitions and signals
- Signal encodings and physical values
- Schedule tables for frame transmission
- Diagnostic frames and services
LDF files are the LIN equivalent of DBC files for CAN networks.
Features in Detail
Automatic Parsing
- Uses
LdfMatrixfrom Oakrey.LDF - Async parsing for large files
- Full LDF 2.x specification support
Error Handling
- File not found errors shown to user
- Parse errors displayed with user-friendly messages
- Graceful handling of malformed LDF files
Reactive Updates
- Subscribe to
FileParsedobservable - Get notified when files are parsed or selection changes
- Always have access to current LdfMatrix
Integration
- Works seamlessly with FileBrowsing.Extended service
- Automatic reparsing on file selection change
- Persistent settings for last selected file
- Template support for creating new LDF files
When to Use
Use FileParsing.LDF when:
- You need to parse and monitor LDF LIN database files
- You want automatic reloading when files change
- You need reactive updates for LIN database changes
- You want persistent file selection across sessions
- You need integration with file browsing and management UI
- You're developing automotive LIN applications
Use Oakrey.LDF directly when:
- You only need one-time LDF file reading
- You don't need change tracking or observables
- You're working with non-UI scenarios
Requirements
- .NET 10 or higher
- Oakrey.Applications.FileParsing
- Oakrey.Applications.FileBrowsing.Extended
- Oakrey.LDF (LdfMatrix parser)
Project Information
- Author: Oakrey
- Company: Oakrey
- License: MIT
- Repository: Git Repository
- Project URL: Project Website
Contributing
Contributions are welcome! Feel free to open issues or submit pull requests to improve the package.
License
This project is licensed under the MIT License. See the LICENSE file for details.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net10.0-windows7.0 is compatible. |
-
net10.0-windows7.0
- Oakrey.Applications.FileBrowsing.Extended (>= 1.0.1)
- Oakrey.Applications.FileParsing (>= 1.0.1)
- Oakrey.LDF (>= 2.0.0)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.