Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -34,3 +34,6 @@ obj3/
/.claude/settings.local.json
/CLAUDE.md
**/TestResults/

# cargo build output for manual runs in rust/ (MSBuild builds under obj/)
rust/target/
19 changes: 19 additions & 0 deletions LICENSES/dflog-NOTICE.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
dflog
=====

Mission Planner optionally builds and bundles the dflog native dataflash log
parser (dflog_ffi.dll / libdflog_ffi.so / libdflog_ffi.dylib) from the Rust
sources vendored in the top-level rust/ directory. dflog is first-party code
licensed under GNU GPL version 3, the same license as this application; the
complete GPLv3 text is provided in the top-level LICENSE file.

Canonical source (vendored from):
https://github.com/userepo/MissionPlanner/tree/rust/dflog-core (rust/)

Statically linked third-party Rust crates:

- memmap2 (https://crates.io/crates/memmap2) - MIT OR Apache-2.0; used under
Apache-2.0, whose text is provided in this directory (Apache-2.0.txt).
- The Rust standard library is statically linked and is licensed
MIT OR Apache-2.0 (https://github.com/rust-lang/rust); used under
Apache-2.0 as above.
55 changes: 55 additions & 0 deletions MissionPlanner.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,31 @@
</Content>
</ItemGroup>

<PropertyGroup>
<!-- The native dataflash log parser (rust/) is built from source when a
Rust toolchain is available; without one the app builds normally and
the managed parser is used at runtime. Built under obj/ so manual and
MSBuild-driven cargo runs never dirty the build-identity check. -->
<DflogRustTriple Condition="'$(RuntimeIdentifier)' == 'win-x64'">x86_64-pc-windows-msvc</DflogRustTriple>
<DflogRustTriple Condition="'$(RuntimeIdentifier)' == 'linux-x64'">x86_64-unknown-linux-gnu</DflogRustTriple>
<DflogRustTriple Condition="'$(RuntimeIdentifier)' == 'osx-x64'">x86_64-apple-darwin</DflogRustTriple>
<DflogRustTriple Condition="'$(RuntimeIdentifier)' == 'osx-arm64'">aarch64-apple-darwin</DflogRustTriple>
<DflogNativeDir>$([System.IO.Path]::GetFullPath('$(MSBuildProjectDirectory)/$(BaseIntermediateOutputPath)dflog'))</DflogNativeDir>
<DflogReleaseDir Condition="'$(DflogRustTriple)' != ''">$(DflogNativeDir)/$(DflogRustTriple)/release</DflogReleaseDir>
<DflogReleaseDir Condition="'$(DflogRustTriple)' == ''">$(DflogNativeDir)/release</DflogReleaseDir>
<DflogCargoTargetArg Condition="'$(DflogRustTriple)' != ''"> --target $(DflogRustTriple)</DflogCargoTargetArg>
<DflogLibraryName Condition="'$(RuntimeIdentifier)' == 'win-x64' Or
('$(RuntimeIdentifier)' == '' And
$([MSBuild]::IsOSPlatform('Windows')))">dflog_ffi.dll</DflogLibraryName>
<DflogLibraryName Condition="'$(RuntimeIdentifier)' == 'linux-x64' Or
('$(RuntimeIdentifier)' == '' And
$([MSBuild]::IsOSPlatform('Linux')))">libdflog_ffi.so</DflogLibraryName>
<DflogLibraryName Condition="'$(RuntimeIdentifier)' == 'osx-x64' Or
'$(RuntimeIdentifier)' == 'osx-arm64' Or
('$(RuntimeIdentifier)' == '' And
$([MSBuild]::IsOSPlatform('OSX')))">libdflog_ffi.dylib</DflogLibraryName>
</PropertyGroup>

<ItemGroup>
<ProjectReference Include="ExtLibs/ArduPilot/MissionPlanner.ArduPilot.csproj" />
<ProjectReference Include="ExtLibs/Arduino/Arduino.csproj" />
Expand Down Expand Up @@ -290,6 +315,36 @@
<Exec Command="bash &quot;$(MSBuildProjectDirectory)/build/simpleble/fetch-macos.sh&quot; &quot;$(SimpleBleMacRid)&quot; &quot;$(SimpleBleMacNativeDir)&quot;" />
</Target>

<Target Name="BuildDflogNative"
BeforeTargets="PrepareForBuild"
Condition="'$(DflogLibraryName)' != '' And '$(DesignTimeBuild)' != 'true'">
<Exec Command="cargo --version"
IgnoreExitCode="true"
EchoOff="true"
StandardOutputImportance="low"
StandardErrorImportance="low">
<Output TaskParameter="ExitCode" PropertyName="DflogCargoProbeExitCode" />
</Exec>
<Message Condition="'$(DflogCargoProbeExitCode)' != '0'"
Importance="high"
Text="dflog: cargo not found on PATH; skipping the native log parser build (the managed parser is used at runtime)" />
<Exec Condition="'$(DflogCargoProbeExitCode)' == '0'"
Command="cargo build --release --package dflog-ffi --target-dir &quot;$(DflogNativeDir)&quot;$(DflogCargoTargetArg)"
WorkingDirectory="$(MSBuildProjectDirectory)/rust" />
</Target>

<Target Name="IncludeDflogNativeContent"
BeforeTargets="AssignTargetPaths"
DependsOnTargets="BuildDflogNative"
Condition="'$(DflogLibraryName)' != ''">
<ItemGroup Condition="Exists('$(DflogReleaseDir)/$(DflogLibraryName)')">
<Content Include="$(DflogReleaseDir)/$(DflogLibraryName)" Link="$(DflogLibraryName)">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
</Content>
</ItemGroup>
</Target>

<Target Name="RemoveWindowsNativeBinariesFromNonWindowsPublish"
AfterTargets="ComputeFilesToPublish"
Condition="'$(RuntimeIdentifier)' == 'linux-x64' Or
Expand Down
30 changes: 30 additions & 0 deletions Porting/STATUS.md
Original file line number Diff line number Diff line change
Expand Up @@ -397,6 +397,36 @@ Updated: **2026-09-01**.
Next executable steps are physical simultaneous-input acceptance on UDP 14550/14551 and, before
any later release, an intentional `make bump-local-build` from **2 to 3**.

## Native dataflash log core, phase 1: vendored Rust workspace and build plumbing (branch feature/dflog-native-log-core)

- Vendored the dflog parser core from the upstream fork (userepo/MissionPlanner
`rust/dflog-core` branch, crates 0.7.1) into the top-level `rust/` directory: `dflog-core`
(parser/index/columnar access, bug-for-bug compatible with `DFLogBuffer`/`BinaryLog`) and
`dflog-ffi` (`dflog_ffi` cdylib, C ABI v5, panic-safe boundary), plus the SITL corpus in
`rust/testdata` that the golden characterization tests pin exact values against. The CLI,
Python bindings and fuzz targets stay upstream; parser changes land there first and are
re-vendored. `cargo test` (24+2), `cargo fmt --check` and `cargo clippy --workspace
--all-targets` are clean in this tree.
- `MissionPlanner.csproj` builds the cdylib from source when `cargo` is on the PATH
(`BuildDflogNative` before `PrepareForBuild`, mirroring `FetchMacSimpleBle`): RID-mapped
`--target` triples for win-x64/linux-x64/osx-x64/osx-arm64, host-native build when no RID is
set, output under `obj/dflog/` so neither MSBuild nor manual cargo runs (`rust/target/` now
gitignored) can dirty the build-identity check. Without cargo the build prints one notice and
produces today's app unchanged - the managed parser remains the runtime fallback. The built
library is injected as `Content` before `AssignTargetPaths`, so it flows into output, publish,
and every package payload; verified end to end with a `win-x64` self-contained publish carrying
`dflog_ffi.dll` (191 KB, `strip = true` release profile for the lintian gate).
- No binaries are checked in and no new project files exist: `check-project-artifacts.sh`,
`check-binary-artifacts.sh` and `check-native-surface.sh` all pass unchanged. Third-party
notice added as `LICENSES/dflog-NOTICE.txt` (memmap2 and the Rust standard library,
Apache-2.0; version-free filename since the vendored source re-syncs from upstream). Full C# suite: 1532/1544 locally, the failures being the known
environment-dependent set, unchanged from master.
- Remaining blocker: none for this phase. Next executable step: phase 2 - port `DfLogNative`
P/Invoke bindings into `ExtLibs/Utilities` on the `NativeGdalApi` availability pattern, add the
`DFLogBuffer` native fast paths, and cover them with synthesized-log parity tests that skip
when the native library is absent. CI wiring for the four RIDs (rustup targets on the macOS
runner) is phase 4.

## NV4 parameter-catalog synchronization and Debian handoff

- The Hermes source checkpoint is clean GTU `master == origin/master`
Expand Down
32 changes: 32 additions & 0 deletions rust/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

67 changes: 67 additions & 0 deletions rust/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
[workspace]
resolver = "2"
members = ["crates/dflog-core", "crates/dflog-ffi"]

[workspace.package]
edition = "2021"
license = "GPL-3.0"

# Every crate opts in with `[lints] workspace = true`. Deliberately absent:
# `clippy::pedantic` (its cast lints fight the bug-for-bug parity casts that
# mirror C# semantics), `clippy::cargo`, and `clippy::unwrap_used` (the
# no-panic guarantee is enforced by the upstream fork's fuzz net and the FFI
# catch_unwind barrier instead; production unwraps are infallible patterns).
[workspace.lints.rust]
ambiguous_negative_literals = "warn"
missing_debug_implementations = "warn"
redundant_imports = "warn"
redundant_lifetimes = "warn"
trivial_numeric_casts = "warn"
unsafe_op_in_unsafe_fn = "warn"
unused_lifetimes = "warn"

[workspace.lints.clippy]
complexity = { level = "warn", priority = -1 }
correctness = { level = "warn", priority = -1 }
perf = { level = "warn", priority = -1 }
style = { level = "warn", priority = -1 }
suspicious = { level = "warn", priority = -1 }

# Unfinished-work and process-exit markers may not ship in production code;
# tests keep panics via clippy.toml.
panic = "deny"
todo = "deny"
unimplemented = "deny"
unreachable = "deny"
panic_in_result_fn = "deny"
string_slice = "deny"
exit = "deny"
unchecked_time_subtraction = "deny"

# Selected `restriction` lints for consistency and brevity
allow_attributes_without_reason = "warn"
as_pointer_underscore = "warn"
assertions_on_result_states = "warn"
clone_on_ref_ptr = "warn"
deref_by_slicing = "warn"
disallowed_script_idents = "warn"
empty_drop = "warn"
empty_enum_variants_with_brackets = "warn"
empty_structs_with_brackets = "warn"
fn_to_numeric_cast_any = "warn"
if_then_some_else_none = "warn"
map_err_ignore = "warn"
redundant_type_annotations = "warn"
renamed_function_params = "warn"
semicolon_outside_block = "warn"
undocumented_unsafe_blocks = "warn"
unnecessary_safety_comment = "warn"
unnecessary_safety_doc = "warn"
unneeded_field_pattern = "warn"
unused_result_ok = "warn"

[profile.release]
lto = true
codegen-units = 1
# Debian lintian rejects unstripped shared objects in the package payload
strip = true
31 changes: 31 additions & 0 deletions rust/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# dflog - native dataflash log core

Rust implementation of ArduPilot dataflash (`.bin`) log parsing, vendored
from the upstream fork (userepo/MissionPlanner, `rust/` on branch
`rust/dflog-core`, crates 0.7.1). Two crates:

- `crates/dflog-core` - parser, index scan, typed columnar access, units and
GPS time-base metadata. Behavior is bug-for-bug compatible with the C#
parser in `ExtLibs/Utilities` (`DFLogBuffer`/`BinaryLog`), pinned by the
golden characterization tests over `testdata/`.
- `crates/dflog-ffi` - `dflog_ffi` cdylib exposing a C ABI (ABI version 5)
consumed from `ExtLibs/Utilities` over P/Invoke. Every export catches
panics at the boundary.

The main application builds this workspace automatically when `cargo` is on
the PATH (see the dflog targets in `MissionPlanner.csproj`); without a Rust
toolchain the app builds normally and uses the managed parser. The library is
never checked in - it is compiled per RID into `obj/` and flows into the
publish payload from there.

Local development:

```
cargo test # golden + unit tests (needs testdata/)
cargo fmt --check
cargo clippy --workspace --all-targets
```

The upstream fork carries the wider surface (CLI, Python bindings, fuzz
targets, benchmarks). Changes to the parser core should land there first and
be re-vendored here, keeping crate versions in sync.
7 changes: 7 additions & 0 deletions rust/clippy.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# Test code keeps `unwrap`/`expect`/`panic`: the parity and golden tests
# assert against corpus data, where panicking IS the failure mechanism.
# (Harmless at today's lint levels; keeps tests sanctioned if the
# panic-hygiene lints are ever denied for production code.)
allow-unwrap-in-tests = true
allow-expect-in-tests = true
allow-panic-in-tests = true
12 changes: 12 additions & 0 deletions rust/crates/dflog-core/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
[package]
name = "dflog-core"
version = "0.7.1"
edition.workspace = true
license.workspace = true
description = "ArduPilot dataflash (.bin) log parsing and indexing"

[dependencies]
memmap2 = "0.9.11"

[lints]
workspace = true
Loading
Loading