Skip to content

Resources

Resources are typed runtime objects that tasks and bridges can access without going through the message graph. They are provided by resource bundles and wired by name in copperconfig.ron. Today we primarily use them to expose hardware as a HAL for embedded systems, but the same mechanism works well for "engine services" like memory arenas, thread pools, or reserved subsystems dedicated to specific tasks or bridges.

Concept

  • Bundles own the concrete resources and register them into the runtime at startup.
  • Tasks and bridges declare the bindings they need by name, and the config maps those names to bundle_id.resource_id.
  • Resources can be exclusive (owned by one task) or shared (borrowed or Arc).
  • Bundles can be mission-scoped so the same task code can run against different hardware per mission.

Using resources (most users)

1) Declare the bundles you want in the config. 2) Bind task and bridge resource names to concrete bundle.resource paths. 3) Use the bindings in your task/bridge constructor.

Example copperconfig.ron snippet:

(
    resources: [
        (id: "board", provider: "board_crate::BoardBundle"),
    ],
    tasks: [
        (
            id: "telemetry",
            type: "app::TelemetryTask",
            resources: { bus: "board.telemetry_bus" },
        ),
    ],
    bridges: [
        (
            id: "crsf",
            type: "cu_crsf::CrsfBridge<SerialPort, SerialError>",
            resources: { serial: "board.uart0" },
        ),
    ],
)

The bundle provider defines the resource ids (like uart0 or telemetry_bus), so check the board/component crate docs or the bundle source for the list.

In code, either implement ResourceBindings manually or use the resources! macro for a compact declaration:

use cu29::prelude::*;

resources!({
    bus => Borrowed<TelemetryBus>,
});

impl CuTask for TelemetryTask {
    type Resources<'r> = Resources;
    // ...
    fn new_with(_cfg: Option<&ComponentConfig>, resources: Self::Resources<'_>) -> CuResult<Self> {
        Ok(Self { bus: resources.bus.0 })
    }
}

Notes:

  • Owned<T> means the task takes exclusive ownership (common for peripherals).
  • Borrowed<T> (macro form) or shared Arc<T> means the resource can be reused by multiple consumers.
  • Use missions: [...] on resource entries to scope bundles to specific missions.
  • See Copper Configuration file Reference for the full schema.

Creating or adding resources

1) Define the resource types you want to expose (drivers, pools, arenas, handles). 2) Declare bundle IDs with bundle_resources!. 3) Implement ResourceBundle to construct resources and register them in the ResourceManager. 4) Point your config resources entries at the bundle provider path.

Minimal bundle example:

use cu29::resource::{ResourceBundle, ResourceManager};
use cu29::{CuResult, bundle_resources};
use std::sync::Arc;

pub struct BoardBundle;
bundle_resources!(BoardBundle: Uart0, TelemetryBus);

impl ResourceBundle for BoardBundle {
    fn build(
        bundle: cu29::resource::BundleContext<Self>,
        _config: Option<&cu29::config::ComponentConfig>,
        manager: &mut ResourceManager,
    ) -> CuResult<()> {
        let uart_key = bundle.key(BoardBundleId::Uart0);
        let bus_key = bundle.key(BoardBundleId::TelemetryBus);
        manager.add_owned(uart_key, MyUart::new())?;
        manager.add_shared(bus_key, Arc::new(MyBus::new()))?;
        Ok(())
    }
}

Embedded note: if you need to build resources from handles created in main (for example, HAL peripherals), use ResourceManager::add_bundle_prebuilt to insert them during runtime setup.

Examples

  • https://github.com/copper-project/copper-rs/tree/master/examples/cu_resources_test - End-to-end example with owned vs shared resources, mission-specific bundles, and bridge bindings.
  • https://github.com/copper-project/copper-rs/tree/master/examples/cu_elrs_bdshot_demo - Embedded demo that wires a board resource bundle into tasks and bridges.
  • https://github.com/copper-project/copper-rs/tree/master/examples/cu_flight_controller - Uses the resources! macro to bind board peripherals to tasks.