Copper Application Overview¶
This page shows a minimal Copper application: a task graph definition in RON and the Rust code that implements a simple task and runtime.
Task graph (RON)¶
(
tasks: [
(
id: "src",
type: "FlippingSource",
),
(
id: "gpio",
type: "cu_rp_gpio::RPGpio",
config: {
"pin": 4,
},
),
],
cnx: [
(src: "src", dst: "gpio", msg: "cu_rp_gpio::RPGpioMsg"),
],
)
Runtime and task implementation (Rust)¶
use std::path::PathBuf;
use cu29::prelude::*;
#[copper_runtime(config = "copperconfig.ron")]
struct MyApplication {}
pub struct FlippingSource {
state: bool,
}
impl CuSrcTask for FlippingSource {
type Output<'m> = output_msg!(RPGpioPayload);
fn new(config: Option<&copper::config::ComponentConfig>) -> CuResult<Self>
where
Self: Sized,
{
Ok(Self { state: true })
}
fn process(&mut self, clock: &RobotClock, output: &mut Self::Output<'_>) -> CuResult<()> {
self.state = !self.state;
output.set_payload(RPGpioPayload {
on: self.state,
creation: Some(clock.now()).into(),
actuation: Some(clock.now()).into(),
});
Ok(())
}
}
fn main() {
let logger_path = "/tmp/mylogfile.copper";
debug!("Creating application... ");
let mut application = MyApplication::builder()
.with_log_path(logger_path, Some(10 * 1024 * 1024))
.expect("Failed to setup logger.")
.build()
.expect("Failed to create runtime.");
debug!("Running... starting clock: {}.", application.clock().now());
application.run().expect("Failed to run application.");
debug!("End of program: {}.", application.clock().now());
}
Experimental self-describing logs¶
Enable cu29/self-describing-logs and use the ordinary application builder.
During construction, before resource initialization, Copper serializes native
encoding descriptions for every compiled mission and saves one compressed catalog
in static log metadata. Matching appended runs reuse it. The catalog and application
metadata survive byte-addressed rollover; data sections identify their run,
instance and mission, so surviving CopperLists remain decodable after startup
markers rotate out.
The producer supports no_std and uses bounded memory for startup compression.
Native payload encoding retains its existing recording pass. Host readers enable
cu29/decode-catalog for allocated value trees. Use the standalone CLI's catalog,
extract-copperlists and fsck --deep commands, or its Python API, to inspect logs.
Expose the feature in your application's Cargo.toml:
[features]
self-describing-logs = ["cu29/self-describing-logs"]
Record with cargo run --features self-describing-logs. From a Copper checkout,
inspect the resulting log with:
just logextract logs/app.copper catalog
just logextract logs/app.copper extract-copperlists --export-format jsonl
just logextract logs/app.copper fsck --deep
For a deeper explanation of task lifecycle hooks and scheduling, see Task Lifecycle.