Skip to content

feat(vela): complete firmware flash-to-block-device capability - #223

Merged
JusterZhu merged 2 commits into
masterfrom
feat/vela-firmware-flash
May 22, 2026
Merged

feat(vela): complete firmware flash-to-block-device capability#223
JusterZhu merged 2 commits into
masterfrom
feat/vela-firmware-flash

Conversation

@JusterZhu

Copy link
Copy Markdown
Collaborator

Closes #222

Summary

Completes the Vela OTA firmware upgrade capability by adding real block device I/O and wiring the lifecycle Installing phase.

New: vela-flasher crate

  • BlockDeviceWriter: chunked writes, fsync, read-back verification, SHA-256 tracking
  • FpkInstaller: full pipeline from .fpk to flashed device

Refactored: vela-slotmgr SlotManager

  • Generic over SlotProvider trait (was hardcoded to MockSlotProvider)
  • Real write_slot() using BlockDeviceWriter
  • Added device_path(), slot_version(), swap_and_commit()

Wired: vela-lifecycle engine

  • Validating: opens .fpk, runs verify_checksums()
  • Installing: calls FpkInstaller::install() to flash firmware

Fixed: vela-ffi for Rust 2024 edition

  • #[no_mangle] -> #[unsafe(no_mangle)]

- Add vela-flasher crate with BlockDeviceWriter and FpkInstaller
- Refactor vela-slotmgr SlotManager: generic over SlotProvider, real write_slot
- Wire vela-lifecycle Installing phase with actual firmware flashing
- Fix vela-ffi #[no_mangle] -> #[unsafe(no_mangle)] for Rust 2024 edition

Closes #222
Copilot AI review requested due to automatic review settings May 22, 2026 04:01
- Add vela-flasher crate with BlockDeviceWriter and FpkInstaller
- Refactor vela-slotmgr SlotManager: generic over SlotProvider, real write_slot
- Wire vela-lifecycle Installing phase with actual firmware flashing
- Fix vela-ffi #[no_mangle] to #[unsafe(no_mangle)] for Rust 2024 edition

Closes #222
@JusterZhu
JusterZhu merged commit 9389b80 into master May 22, 2026
1 of 4 checks passed
@JusterZhu
JusterZhu deleted the feat/vela-firmware-flash branch May 22, 2026 04:05

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR completes the Vela OTA “Installing” path by introducing a new vela-flasher crate for block-device I/O and wiring it into vela-lifecycle, while refactoring vela-slotmgr to support real device-backed slot writing.

Changes:

  • Added vela-flasher with BlockDeviceWriter and FpkInstaller for flashing .fpk payloads to a device.
  • Refactored vela-slotmgr::SlotManager toward provider-based slot detection and device-path driven writes.
  • Updated vela-lifecycle to validate .fpk bundles and perform real installation writes during the Installing phase.

Reviewed changes

Copilot reviewed 12 out of 12 changed files in this pull request and generated 23 comments.

Show a summary per file
File Description
src/vela/vela-core/crates/vela-slotmgr/src/manager.rs Refactors SlotManager to use a SlotProvider, adds refresh/layout/device helpers, and delegates writes to BlockDeviceWriter.
src/vela/vela-core/crates/vela-slotmgr/src/lib.rs Adds SlotError::FlashError for flasher integration.
src/vela/vela-core/crates/vela-slotmgr/Cargo.toml Adds vela-flasher dependency and enables Tokio runtime feature.
src/vela/vela-core/crates/vela-lifecycle/src/lib.rs Extends lifecycle context/errors for flashing inputs and install reporting.
src/vela/vela-core/crates/vela-lifecycle/src/engine.rs Implements real Validating/Installing logic using FlashPack reader + flasher installer; adds tests.
src/vela/vela-core/crates/vela-lifecycle/Cargo.toml Adds vela-flasher plus new dev-deps for .fpk test building.
src/vela/vela-core/crates/vela-flasher/src/lib.rs Introduces the flasher public API (FlashConfig, FlasherError, exports).
src/vela/vela-core/crates/vela-flasher/src/direct_writer.rs Implements chunked write + fsync + optional read-back verification + SHA tracking; adds tests.
src/vela/vela-core/crates/vela-flasher/src/fpk_installer.rs Implements .fpk install pipeline (verify → decompress → write → hash check); adds tests.
src/vela/vela-core/crates/vela-flasher/Cargo.toml Defines new crate dependencies for flashing and .fpk handling.
src/vela/vela-core/crates/vela-ffi/src/lib.rs Updates #[no_mangle] to Rust 2024’s #[unsafe(no_mangle)].
src/vela/vela-core/Cargo.toml Adds vela-flasher to the workspace.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

//! `vela_flasher::BlockDeviceWriter`, and label management.

use tracing::{debug, instrument};
use tracing::{debug, info, instrument, warn};
Comment on lines +48 to 62
pub struct SlotManager<P: SlotProvider + ?Sized = MockSlotProvider> {
provider: Box<P>,
active: SlotLabel,
/// Cached slot layout, refreshed via `refresh()`.
layout: Option<SlotLayout>,
/// Override for the target device path (for testing).
device_override: Option<String>,
}

impl SlotManager {
/// Create a SlotManager from a mock provider (for testing).
impl SlotManager<MockSlotProvider> {
/// Create a SlotManager backed by a `MockSlotProvider` (for testing).
pub fn with_mock(mock: MockSlotProvider) -> Self {
Self {
provider: Box::new(mock),
active: SlotLabel::Primary,
Comment on lines +93 to +101
pub fn refresh(&mut self) -> SlotResult<()> {
// This is a synchronous wrapper; in production, callers should use
// an async-aware wrapper. We create a single-threaded tokio runtime
// to bridge the async provider trait to sync callers.
let rt = tokio::runtime::Builder::new_current_thread()
.enable_time()
.build()
.map_err(|e| SlotError::DetectionFailed(format!("failed to create runtime: {e}")))?;
let layout = rt.block_on(self.provider.detect_slots())?;
Comment on lines +100 to +108
.map_err(|e| SlotError::DetectionFailed(format!("failed to create runtime: {e}")))?;
let layout = rt.block_on(self.provider.detect_slots())?;
debug!(
primary = %layout.primary.device_path,
alternate = %layout.alternate.device_path,
"Slot layout refreshed"
);
self.layout = Some(layout);
Ok(())
Comment on lines +138 to +145
pub fn swap_and_commit(&mut self) -> SlotResult<()> {
// Persist the swap via the provider
let rt = tokio::runtime::Builder::new_current_thread()
.enable_time()
.build()
.map_err(|e| SlotError::SwapFailed(format!("failed to create runtime: {e}")))?;
rt.block_on(self.provider.swap_slots())?;

Comment on lines +259 to +266
let calls = std::sync::Arc::new(std::sync::Mutex::new(Vec::<(u64, u64)>::new()));
let calls_ref = calls.clone();
let cb: ProgressCallback = Box::new(move |w, t| {
calls_ref.lock().unwrap().push((w, t));
});

let bytes = installer.install(Some(&cb)).unwrap();
assert_eq!(bytes, payload.len() as u64);
use std::sync::Mutex;
use std::io::Write;
use tempfile::NamedTempFile;
use vela_flashpack::header::{FpkHeader, PayloadType};
Comment on lines +144 to +150
// Open and verify the FlashPack
let reader = vela_flashpack::FlashPackReader::open(Path::new(&fpk_path))
.map_err(|e| LifecycleError::InstallError(format!("FPK open failed: {e}")))?;

let _bundle_hash = reader
.verify_checksums()
.map_err(|e| LifecycleError::InstallError(format!("Checksum verification failed: {e}")))?;
Comment on lines +66 to +69
// 2. Verify archive checksums (header + payload)
let _bundle_hash = reader.verify_checksums()?;
info!("FlashPack checksum verification passed");

SwapFailed(String),

#[error("Flash error: {0}")]
FlashError(Box<vela_flasher::FlasherError>),
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

vela: Complete firmware upgrade (flash-to-block-device) capability

2 participants