# osp-upgrade-engine **Repository Path**: liudegui/osp-upgrade-engine ## Basic Information - **Project Name**: osp-upgrade-engine - **Description**: 工业级固件升级引擎,基于 newosp 基础设施,适用于 ARM-Linux 嵌入式系统 - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2026-02-17 - **Last Updated**: 2026-02-21 ## Categories & Tags **Categories**: Uncategorized **Tags**: Cpp17, 固件升级, ARM-Linux, 嵌入式, OTA ## README # osp-upgrade-engine > Industrial-grade C++17 firmware upgrade engine: HSM-driven, 3-layer power-loss protection, zero heap allocation [![Build Status](https://gitee.com/liudegui/osp-upgrade-engine/workflows/build/badge.svg)](https://gitee.com/liudegui/osp-upgrade-engine/actions) ## Quick Start ### Overview osp-upgrade-engine is an industrial-grade A/B partition firmware upgrade engine for ARM-Linux embedded systems (LiDAR, robotics, edge computing), designed for resource-constrained environments (32-256 MB RAM). **Key Features**: - **HSM-driven**: 8-stage upgrade flow based on newosp `osp::StateMachine` - **Zero heap allocation**: Stack/static allocation throughout, no dynamic memory in hot path - **3-layer power-loss protection**: raw partition state persistence + U-Boot redundant env + bootcount auto-rollback - **Function pointer table HAL**: Easy to unit test and simulate, no virtual function overhead - **x86 simulation layer**: Full upgrade flow can be verified on dev machine (including power-loss scenarios) - **Compile-time dispatch**: C++17 header-only, no external dependencies, only requires newosp + mbedtls **Design Comparison**: | Dimension | SWUpdate / RAUC | osp-upgrade-engine | |-----------|-----------------|-------------------| | Runtime Dependencies | D-Bus + systemd + GLib | newosp header-only (zero external deps) | | Memory Footprint | ~10-50 MB | < 73 KB | | Process Model | Independent daemon | Embedded in app process | | Power-Loss Protection | update_state file | raw partition + U-Boot redundant env + bootcount | | Suitable For | Yocto/Buildroot | Resource-constrained embedded (32-256MB) | ## Architecture Overview ### Storage Layout ``` eMMC: /dev/mmcblk0 ├── bootloader (p1) - U-Boot SPL + U-Boot (2 MB) ├── env (p2) - U-Boot redundant environment variables (128 KB) ├── recovery (p3) - Minimal recovery system (32 MB) ├── rootfs_a (p4) - Active system partition A (1 GB) ├── rootfs_b (p5) - Active system partition B (1 GB) ├── config (p6) - Persistent configuration (64 MB) ├── data (p7) - User data (remaining) └── upgrade_state (p8) - Upgrade state persistence (64 KB, raw) ``` ### HSM State Machine ``` Idle → Verifying → Writing → Switching → Rebooting → BootVerify → Rollback → Idle ``` 8 states, each transition persisted to raw partition, supporting recovery from power loss at any point. ### Full Upgrade Flow ``` 1. App layer: StartUpgrade("/path/to/fw.osp") 2. Idle: Verify package header (128B, CRC-32 + magic), version/hardware compatibility 3. Verifying: Stream SHA-256 calculation, Ed25519 signature verification 4. Writing: 4KB chunk loop read/write, persist progress every 1MB, final readback verify 5. Switching: Atomic U-Boot env swap for boot partition 6. Rebooting: System reboot 7. (After reboot) BootVerify: New firmware boots, app layer self-check confirmation 8. Rollback: On power loss recovery or self-check failure, rollback to old partition 9. Idle: Upgrade complete, wait for next upgrade ``` ## Technical Highlights ### 1. 3-Layer Power-Loss Protection | Layer | Mechanism | Coverage | |-------|-----------|----------| | 1 | raw partition state record + fsync | 64B record persisted before each state transition | | 2 | U-Boot redundant env + fw_setenv | Boot partition switch atomicity guaranteed by U-Boot | | 3 | bootcount rollback | Auto-rollback to old partition when bootcount > bootlimit | ### 2. 128-Byte Binary Package Header ``` Offset Size Field Description 0 4 magic[4] "OSP\x01" 4 1 header_ver Header format version 5 1 pkg_type 0=full, 1=delta, 2=bootloader 8 4 hw_compat_mask Hardware compatibility bitmask (32 board types) 12 4 fw_version major<<24 | minor<<16 | patch 16 4 min_version Delta upgrade baseline version 20 8 payload_size Payload byte count 28 32 payload_sha256 SHA-256 checksum 60 2 signature_len Ed25519 signature length (64B) 62 62 reserved_1 Reserved for future extensions 124 4 header_crc32 CRC-32 of first 124 bytes ``` No JSON parser needed, fast CRC-32 verification, direct version comparison with `>` operator. ### 3. Function Pointer Table HAL (Zero Virtual Functions) ```cpp struct UpgradeHAL { int32_t (*open_partition)(const char*, int32_t, void*); ssize_t (*write_partition)(int32_t, const void*, uint32_t, void*); ssize_t (*read_partition)(int32_t, void*, uint32_t, void*); int32_t (*fsync_partition)(int32_t, void*); int32_t (*close_partition)(int32_t, void*); bool (*get_env)(const char*, char*, uint32_t, void*); bool (*set_env)(const char*, const char*, void*); void (*reboot_system)(void*); void* ctx; }; ``` Same codebase easily switches between production (POSIX HAL) and simulation (SimHAL), no virtual function overhead. ### 4. SpinOnce Polling Model ```cpp while (!engine.IsIdle()) { engine.SpinOnce(); // Process 4KB chunk RunLidarPipeline(); // Other tasks not blocked } ``` Main loop doesn't create extra threads, upgrade runs within app process. ## Build & Usage ### Dependencies - C++17 compiler (gcc >= 9.0) - CMake 3.14+ - newosp (auto-downloaded via FetchContent) - mbedtls (auto-downloaded via FetchContent) ### Build ```bash mkdir build && cd build cmake .. -DOSP_GITHUB_MIRROR="https://ghfast.top/" \ -DOSP_BUILD_TESTS=ON \ -DOSP_BUILD_EXAMPLES=ON make -j$(nproc) ctest ``` For China mainland, set `OSP_GITHUB_MIRROR` to speed up FetchContent downloads (use ghfast.top or similar mirror). ### Unit Tests ```bash ctest -V ``` Includes: - PackageHeader parsing and CRC-32 verification - HSM state transitions and power-loss recovery - Partition write and readback verification - Ed25519 + HMAC-SHA256 signature verification ### Simulation Examples Full upgrade demo on x86 Linux: ```bash ./demo/demo_full_upgrade # Complete upgrade flow ./demo/demo_power_loss # Power-loss safety tests (5 scenarios) ``` ## API Design ### UpgradeEngine (Facade Class) ```cpp class UpgradeEngine { public: // Initialization UpgradeEngine(UpgradeHAL* hal, uint32_t current_version, uint32_t local_hw_id, const uint8_t* pub_key, const char* state_dev_path) noexcept; // Upgrade control Expected StartUpgrade(const char* pkg_path) noexcept; void CancelUpgrade() noexcept; Expected ConfirmBoot() noexcept; // Polling drive void SpinOnce() noexcept; // State queries const char* GetStateName() const noexcept; uint8_t GetProgress() const noexcept; bool IsIdle() const noexcept; UpgradeError GetLastError() const noexcept; // Power-loss recovery void RecoverFromPersistentState() noexcept; }; ``` ### Application Integration Example ```cpp #include int main() { static const uint8_t kPubKey[32] = { /* Ed25519 public key */ }; UpgradeHAL hal = MakePosixHAL(); UpgradeEngine engine(&hal, MakeVersion(1,0,0), 3, kPubKey, "/dev/mtd5"); // Recovery on startup engine.RecoverFromPersistentState(); // Trigger upgrade engine.StartUpgrade("/mnt/usb/fw_v2.0.0.osp"); // Main loop while (!engine.IsIdle()) { engine.SpinOnce(); RunApplicationLogic(); } if (engine.GetLastError() != UpgradeError::kOk) { // Handle upgrade error } return 0; } ``` ## Documentation - [Design Document](docs/design_upgrade_engine_zh.md) (Chinese) -- Detailed design, storage layout, power-loss safety, U-Boot integration, resource budget - [Article](../embedded-cpp-articles/content/posts/blog/osp_upgrade_engine_design.md) (Chinese) -- Companion article ## Related Projects - [newosp](https://github.com/DeguiLiu/newosp) -- C++17 header-only embedded infrastructure library (HSM, Bus, Watchdog, Process) - [embedded-cpp-articles](https://gitee.com/liudegui/embedded-cpp-articles) -- Embedded C++ articles repository ## License MIT License