-
-
Notifications
You must be signed in to change notification settings - Fork 4
Development
This guide covers setting up a development environment, building from source, and contributing to UltraLog.
- Development Setup
- Building
- Project Structure
- Architecture Overview
- Adding New ECU Support
- Code Style
- Testing
- CI/CD
- Contributing
- Rust - Latest stable version
- Git - For version control
- Platform build tools - See below
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
source $HOME/.cargo/env
# Verify installation
rustc --version
cargo --versionLinux (Ubuntu/Debian):
sudo apt-get update
sudo apt-get install -y \
build-essential \
libxcb-render0-dev \
libxcb-shape0-dev \
libxcb-xfixes0-dev \
libxkbcommon-dev \
libssl-dev \
libgtk-3-dev \
libglib2.0-dev \
libatk1.0-dev \
libcairo2-dev \
libpango1.0-dev \
libgdk-pixbuf2.0-devLinux (Fedora):
sudo dnf install -y \
gcc \
libxcb-devel \
libxkbcommon-devel \
openssl-devel \
gtk3-devel \
glib2-devel \
atk-devel \
cairo-devel \
pango-devel \
gdk-pixbuf2-develmacOS:
xcode-select --installWindows:
- Install Visual Studio Build Tools
- Select "Desktop development with C++"
git clone https://github.com/SomethingNew71/UltraLog.git
cd UltraLogFaster compile time, slower runtime, includes debug symbols:
cargo buildSlower compile time, optimized runtime:
cargo build --release# Debug mode
cargo run
# Release mode
cargo run --releasecargo run --bin test_parser -- path/to/logfile.csvUltraLog/
├── src/
│ ├── main.rs # Application entry point
│ ├── lib.rs # Library module exports
│ ├── app.rs # Main UltraLogApp struct (934 lines)
│ │ # - Application state management
│ │ # - File loading pipeline
│ │ # - eframe::App implementation
│ ├── state.rs # Core data types (206 lines)
│ │ # - LoadedFile, SelectedChannel
│ │ # - Color palettes
│ │ # - Loading states
│ ├── units.rs # Unit conversion system (278 lines)
│ ├── normalize.rs # Field name normalization (500 lines)
│ ├── parsers/
│ │ ├── mod.rs # Parser module exports
│ │ ├── types.rs # Core parser traits & enums
│ │ │ # - Log, Channel, Value, Meta
│ │ │ # - Parseable trait
│ │ │ # - EcuType enumeration
│ │ ├── haltech.rs # Haltech CSV parser (547 lines)
│ │ ├── ecumaster.rs # ECUMaster CSV parser (366 lines)
│ │ └── speeduino.rs # Speeduino MLG parser (542 lines)
│ ├── ui/
│ │ ├── mod.rs # UI module exports
│ │ ├── sidebar.rs # File list & view options
│ │ ├── channels.rs # Channel selection panel
│ │ ├── chart.rs # Main chart & LTTB algorithm
│ │ ├── timeline.rs # Playback controls
│ │ ├── menu.rs # Menu bar & units UI
│ │ ├── tab_bar.rs # Chrome-style tabs
│ │ ├── toast.rs # Notification system
│ │ ├── icons.rs # Icon drawing utilities
│ │ ├── export.rs # PNG/PDF export
│ │ ├── normalization_editor.rs # Custom field mapping UI
│ │ ├── scatter_plot.rs # XY scatter visualization
│ │ └── tool_switcher.rs # Tool selection UI
│ └── bin/
│ └── test_parser.rs # CLI parser testing utility
├── assets/
│ ├── icons/ # Platform-specific app icons
│ ├── Outfit-Regular.ttf # Custom font
│ └── Outfit-Bold.ttf # Custom font (bold)
├── exampleLogs/ # Test data
├── .github/
│ └── workflows/
│ ├── ci.yml # CI pipeline
│ └── release.yml # Release automation
├── build.rs # Windows icon embedding
├── Cargo.toml # Project manifest
└── README.md # Documentation
- Core app: 934 lines
- UI modules: ~3,148 lines
- Parsers: ~1,667 lines
- Supporting: ~1,108 lines
- Total: ~6,857 lines
┌─────────────┐ ┌──────────────┐ ┌─────────────┐
│ Log File │───►│ Parser │───►│ Log Struct │
└─────────────┘ └──────────────┘ └─────────────┘
│
▼
┌─────────────┐ ┌──────────────┐ ┌─────────────┐
│ Display │◄───│ LTTB Down- │◄───│ Selected │
│ (egui) │ │ sample │ │ Channels │
└─────────────┘ └──────────────┘ └─────────────┘
UltraLogApp (app.rs)
- Main application state
- Implements
eframe::Apptrait - Manages file loading, tabs, playback
Parsers (parsers/)
- Each ECU format has its own parser
- All implement the
Parseabletrait - Convert ECU-specific data to common
Logstruct
UI Modules (ui/)
- Each UI section is a separate module
- Uses egui's immediate mode paradigm
- Renders from application state each frame
pub struct UltraLogApp {
// Files and tabs
files: Vec<LoadedFile>,
tabs: Vec<Tab>,
active_tab: Option<usize>,
// Playback
cursor_time: Option<f64>,
is_playing: bool,
playback_speed: f64,
// Settings
unit_preferences: UnitPreferences,
color_blind_mode: bool,
field_normalization: bool,
// UI state
loading_state: LoadingState,
downsample_cache: HashMap<...>,
}In src/parsers/types.rs:
#[derive(Debug, Clone, PartialEq)]
pub enum EcuType {
Haltech,
EcuMaster,
Speeduino,
NewEcu, // Add your ECU type
}Create src/parsers/newecu.rs:
use super::types::{Channel, Log, Meta, Parseable, Value};
use anyhow::Result;
pub struct NewEcuParser;
impl Parseable for NewEcuParser {
fn parse(&self, data: &str) -> Result<Log> {
// Parse your ECU format here
let channels = vec![
Channel {
name: "RPM".to_string(),
unit: Some("rpm".to_string()),
..Default::default()
},
// ... more channels
];
let data = vec![
vec![Value::Float(3500.0), /* ... */],
// ... more records
];
let times = vec!["0.000".to_string(), /* ... */];
Ok(Log {
meta: Meta::default(),
channels,
times,
data,
})
}
}In src/parsers/mod.rs:
pub mod newecu;
pub use newecu::NewEcuParser;In src/app.rs, add detection logic in the file loading function:
fn detect_format(content: &str) -> Option<EcuType> {
if content.starts_with("NewECU Header") {
return Some(EcuType::NewEcu);
}
// ... existing detection
}match ecu_type {
EcuType::NewEcu => NewEcuParser.parse(&content),
// ... existing handlers
}In src/normalize.rs, add mappings for your ECU's channel names:
("newecu_rpm", "Engine RPM"),
("newecu_map", "Manifold Pressure"),
// ... more mappingsUse rustfmt for consistent formatting:
cargo fmtUse clippy with warnings as errors:
cargo clippy -- -D warnings-
render_*- UI rendering methods -
start_*- Async operations -
get_*/set_*- Accessors -
SCREAMING_SNAKE_CASE- Constants -
PascalCase- Types and traits -
snake_case- Functions and variables
- Use
anyhowfor parser errors - Use
thiserrorfor custom error types - Show user-friendly errors via toast notifications
cargo testcargo run --bin test_parser -- path/to/logfile.csvThe exampleLogs/ directory contains sample files:
-
haltech/- Haltech CSV samples -
ecumaster/- ECUMaster CSV samples -
speeduino/- Speeduino MLG samples -
rusefi/- rusEFI MLG samples
Runs on every push and pull request:
- Check - Compile check on all platforms
- Test - Run test suite
- Clippy - Lint for issues
- Format - Verify code formatting
Triggered by version tags (v*):
- Build - Create binaries for all platforms
- Release - Create GitHub release with binaries
# Update version in Cargo.toml
# Commit changes
git add .
git commit -m "Release v1.0.0"
# Create and push tag
git tag v1.0.0
git push origin v1.0.0- Fork the repository
- Create a feature branch
- Make your changes
- Test thoroughly
- Submit a pull request
- Keep PRs focused on a single change
- Update documentation if needed
- Add tests for new functionality
- Ensure CI passes
- Write clear commit messages
type: short description
Longer description if needed.
Fixes #123
Types:
-
feat- New feature -
fix- Bug fix -
docs- Documentation -
refactor- Code refactoring -
test- Tests -
chore- Maintenance
- New ECU formats - Add support for more ECUs
- Features - Implement roadmap items
- Bug fixes - Fix reported issues
- Documentation - Improve wiki and comments
- Performance - Optimize parsing or rendering
- Accessibility - Improve accessibility features
- MegaSquirt format support
- AEM format support
- MaxxECU format support
- MoTeC format support
- Link ECU format support
- Data export to CSV/Excel
- Advanced statistical analysis
- Data filtering and smoothing
- Custom formula channels
- Persistent settings storage
- Multi-log comparison tools
Open an issue on GitHub to request features.
- egui - GUI framework
- eframe - egui framework
- egui_plot - Plotting
- serde - Serialization
- anyhow - Error handling
- Getting-Started - User introduction
- Supported-ECU-Formats - Current ECU support
- Troubleshooting - Common issues
Links