Skip to content

Commit

Permalink
Added documentations
Browse files Browse the repository at this point in the history
  • Loading branch information
gbin committed Jun 22, 2024
1 parent c70eaeb commit 35e0929
Show file tree
Hide file tree
Showing 7 changed files with 75 additions and 24 deletions.
24 changes: 17 additions & 7 deletions copper/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,13 @@ pub type NodeId = u32;
pub type NodeInstanceConfig = HashMap<String, Value>;
pub type Edge = (NodeId, NodeId, String);

// The confifuration Serialization format is as follows:
// (
// tasks : [ (id: "toto", type: "zorglub::MyType", config: {...}),
// (id: "titi", type: "zorglub::MyType2", config: {...})]
// cnx : [ (src: "toto", dst: "titi", msg: "zorglub::MyMsgType"),...]
// )

#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct Value(RonValue);

Expand Down Expand Up @@ -96,6 +103,8 @@ impl From<Value> for String {
}
}

/// A node in the configuration graph.
/// A node represents a Task in the system Graph.
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct Node {
id: String,
Expand Down Expand Up @@ -165,17 +174,16 @@ impl Node {
}
}

// Serialization format
// (
// tasks : [ (id: "toto", type: "zorglub::MyType", config: {...}),
// (id: "titi", type: "zorglub::MyType2", config: {...})]
// cnx : [ (src: "toto", dst: "titi", msg: "zorglub::MyMsgType"),...]
// )

/// This represent a conenction between 2 tasks (nodes) in the configuration graph.
#[derive(Serialize, Deserialize, Debug)]
pub struct Cnx {
/// Source node id.
src: String,

// Destination node id.
dst: String,

/// Message type exchanged betwee src and dst.
msg: String,
}

Expand All @@ -185,6 +193,7 @@ pub struct CuConfig {
pub graph: StableDiGraph<Node, String, NodeId>,
}

/// The config is a list of tasks and their connections.
#[derive(Serialize, Deserialize, Default)]
struct CuConfigRepresentation {
tasks: Vec<Node>,
Expand Down Expand Up @@ -344,6 +353,7 @@ impl CuConfig {
}
}

/// Read a copper configuration from a file.
pub fn read_configuration(config_filename: &str) -> CuResult<CuConfig> {
let config_content = read_to_string(config_filename).map_err(|e| {
CuError::from(format!(
Expand Down
35 changes: 24 additions & 11 deletions copper/src/curuntime.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,21 @@ use crate::copperlist::CuListsManager;
use crate::CuResult;
use petgraph::prelude::*;

// CT is a tuple of all the tasks
// CL is the type of the copper list
/// This is the main structure that will be injected as a member of the Application struct.
/// CT is the tuple of all the tasks in order of execution.
/// CL is the type of the copper list, representing the input/output messages for all the tasks.
pub struct CuRuntime<CT, CL: Sized + PartialEq, const NBCL: usize> {
/// The tuple of all the tasks in order of execution.
pub task_instances: CT,

/// Copper lists hold in order all the input/output messages for all the tasks.
pub copper_lists: CuListsManager<CL, NBCL>,

/// The base clock the runtime will be using to record time.
pub clock: RobotClock,
}

/// To be able to share the clock we make the runtime a clock provider.:w
impl<CT, CL: Sized + PartialEq, const NBCL: usize> ClockProvider for CuRuntime<CT, CL, NBCL> {
fn get_clock(&self) -> RobotClock {
self.clock.clone()
Expand All @@ -39,28 +46,32 @@ impl<CT, CL: Sized + PartialEq, const NBCL: usize> CuRuntime<CT, CL, NBCL> {
}
}

/// Copper tasks can be of 3 types:
/// - Source: only producing output messages (usually used for drivers)
/// - Regular: processing input messages and producing output messages, more like compute nodes.
/// - Sink: only consuming input messages (usually used for actuators)
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub enum CuTaskType {
Source,
Sink,
Regular,
Sink,
}

/// Steps give:
/// NodeId: node id of the task to execute
/// Node: node instance
/// CuTaskType: type of the task
/// Option<String>: input message type
/// u32: index in the culist of the input message
/// Option<String>: output message type
/// u32: index in the culist of the output message
/// This structure represents a step in the execution plan.
pub struct CuExecutionStep {
/// NodeId: node id of the task to execute
pub node_id: NodeId,
/// Node: node instance
pub node: Node,
/// CuTaskType: type of the task
pub task_type: CuTaskType,
/// Option<String>: input message type
pub input_msg_type: Option<String>,
/// u32: index in the culist of the input message
pub culist_input_index: Option<u32>,
/// Option<String>: output message type
pub output_msg_type: Option<String>,
/// u32: index in the culist of the output message
pub culist_output_index: Option<u32>,
}

Expand All @@ -73,6 +84,8 @@ fn find_output_index_from_nodeid(node_id: NodeId, steps: &Vec<CuExecutionStep>)
None
}

/// This is the main heuristics to compute an execution plan at compilation time.
/// TODO: Make that heuristic plugable.
pub fn compute_runtime_plan(config: &CuConfig) -> CuResult<Vec<CuExecutionStep>> {
let mut next_culist_output_index = 0u32;

Expand Down
7 changes: 7 additions & 0 deletions copper/src/cutask.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,12 @@ pub trait CuMsgPayload: Default + Serialize + for<'a> Deserialize<'a> + Sized {}
// Also anything that follows this contract can be a payload (blanket implementation)
impl<T> CuMsgPayload for T where T: Default + Serialize + for<'a> Deserialize<'a> + Sized {}

/// CuMsgMetadata is a structure that contains metadata common to all CuMsgs.
#[derive(Debug, PartialEq, Default)]
pub struct CuMsgMetadata {
/// The time before the process method is called.
pub before_process: OptionCuTime,
/// The time after the process method is called.
pub after_process: OptionCuTime,
}

Expand All @@ -29,12 +32,16 @@ impl Display for CuMsgMetadata {
}
}

/// CuMsg is the envelope holding the msg payload and the metadata between tasks.
#[derive(Debug, PartialEq)]
pub struct CuMsg<T>
where
T: CuMsgPayload,
{
/// This payload is the actual data exchanged between tasks.
pub payload: T,

/// This metadata is the data that is common to all messages.
pub metadata: CuMsgMetadata,
}

Expand Down
4 changes: 3 additions & 1 deletion copper/src/serde/arrays.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
use std::fmt;
use std::marker::PhantomData;

use serde::{Deserialize, Deserializer, Serialize, Serializer};
use serde::de::{self, SeqAccess, Visitor};
use serde::ser::SerializeSeq;
use serde::{Deserialize, Deserializer, Serialize, Serializer};

/// Serialize a fixed 2D array.
pub fn serialize<S, T, const WIDTH: usize, const HEIGHT: usize>(
array: &[[T; WIDTH]; HEIGHT],
serializer: S,
Expand All @@ -22,6 +23,7 @@ where
seq.end()
}

/// Deserialize a fixed 2D array.
pub fn deserialize<'de, D, T, const WIDTH: usize, const HEIGHT: usize>(
deserializer: D,
) -> Result<[[T; WIDTH]; HEIGHT], D::Error>
Expand Down
9 changes: 9 additions & 0 deletions copper_datalogger/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,19 +24,23 @@ const MAIN_MAGIC: [u8; 4] = [0xB4, 0xA5, 0x50, 0xFF];

const SECTION_MAGIC: [u8; 2] = [0xFA, 0x57];

/// The main header of the datalogger.
#[derive(dEncode, dDecode)]
struct MainHeader {
magic: [u8; 4],
first_section_offset: u16, // This is to align with a page at write time.
}

/// Each concurrent sublogger is tracked through a section header.
/// The entry type is used to identify the type of data in the section.
#[derive(dEncode, dDecode)]
struct SectionHeader {
magic: [u8; 2],
entry_type: DataLogType,
section_size: u32, // offset of section_magic + section_size -> should be the index of the next section_magic
}

/// A wrapper around a memory mapped file to write to.
struct MmapStream {
entry_type: DataLogType,
parent_logger: Arc<Mutex<DataLoggerWrite>>,
Expand Down Expand Up @@ -105,6 +109,7 @@ impl Drop for MmapStream {
}
}

/// Create a new stream to write to the datalogger.
pub fn stream_write(
logger: Arc<Mutex<DataLoggerWrite>>,
entry_type: DataLogType,
Expand All @@ -124,11 +129,13 @@ pub fn stream_write(

const DEFAULT_LOGGER_SIZE: usize = 1024 * 1024 * 1024; // 1GB

/// Holder of the read or write side of the datalogger.
pub enum DataLogger {
Read(DataLoggerRead),
Write(DataLoggerWrite),
}

/// Use this builder to create a new DataLogger.
pub struct DataLoggerBuilder {
file_path: Option<PathBuf>,
preallocated_size: Option<usize>,
Expand Down Expand Up @@ -235,12 +242,14 @@ impl DataLoggerBuilder {
}
}

/// A read side of the datalogger.
pub struct DataLoggerRead {
file: File,
mmap_buffer: Mmap,
reading_position: usize,
}

/// A write side of the datalogger.
pub struct DataLoggerWrite {
file: File,
mmap_buffer: MmapMut,
Expand Down
17 changes: 13 additions & 4 deletions copper_derive/src/format.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
use std::process::Command;
use std::io::Write;
use std::process::Command;

use syntect::easy::HighlightLines;
use syntect::highlighting::{Theme, Color, ThemeSet, Style};
use syntect::highlighting::{Color, Style, Theme, ThemeSet};
use syntect::parsing::SyntaxSet;
use syntect::util::{as_24_bit_terminal_escaped, LinesWithEndings};

/// A utility method to ease up the debugging of the macro generated code by formatting it with rustfmt.
pub(crate) fn rustfmt_generated_code(code: String) -> String {
let mut rustfmt = Command::new("rustfmt")
.arg("--emit")
Expand All @@ -17,7 +18,9 @@ pub(crate) fn rustfmt_generated_code(code: String) -> String {

{
let stdin = rustfmt.stdin.as_mut().expect("Failed to open stdin");
stdin.write_all(code.as_bytes()).expect("Failed to write to stdin");
stdin
.write_all(code.as_bytes())
.expect("Failed to write to stdin");
}

let output = rustfmt.wait_with_output().expect("Failed to read stdout");
Expand All @@ -26,10 +29,16 @@ pub(crate) fn rustfmt_generated_code(code: String) -> String {

fn create_black_theme() -> Theme {
let mut theme = ThemeSet::load_defaults().themes["base16-ocean.dark"].clone();
theme.settings.background = Some(Color { r: 0, g: 0, b: 0, a: 255 });
theme.settings.background = Some(Color {
r: 0,
g: 0,
b: 0,
a: 255,
});
theme
}

/// A utility method to ease up the debugging of the macro generated code by highlighting it.
pub(crate) fn highlight_rust_code(code: String) -> String {
let ps = SyntaxSet::load_defaults_newlines();
let syntax = ps.find_syntax_by_extension("rs").unwrap();
Expand Down
3 changes: 2 additions & 1 deletion copper_derive/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,8 @@ fn int2index(i: u32) -> syn::Index {
syn::Index::from(i as usize)
}

// Parses the CopperRuntime attribute like #[copper_runtime(config = "path")]
/// Adds #[copper_runtime(config = "path")] to your application struct to generate the runtime.
/// This will add a "runtime" field to your struct and implement the "new" and "run" methods.
#[proc_macro_attribute]
pub fn copper_runtime(args: TokenStream, input: TokenStream) -> TokenStream {
println!("[entry]");
Expand Down

0 comments on commit 35e0929

Please sign in to comment.