Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions config/dataflow.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2405,6 +2405,23 @@ message-processing:
display-units: 'Bar'
gs:
conversion: 'gs_2p_float:f32'
- name: 'BatteryTemp'
can:
bus: range
id-range-first: 0x900
id-range-last: 0x913
datapoint-conversion:
datapoints:
name: 'BatteryTemp'
datapoint-size-bytes: 1
datapoint-type: 'u8'
can-conversion: 'decode_temperature:u8->f32'
display-units: '°C'
critical: false
store:
default: 0
gs:
conversion: 'gs_2p_float:f32'

commands:
- name: 'SendHashes'
Expand Down
2 changes: 1 addition & 1 deletion crates/lib/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ fn main() -> Result<()> {
let mut content = String::from("//@generated\n");

let df = std::fs::read_to_string(DATAFLOW_PATH)?;
let df = goose_utils::dataflow::parse_from(&df);
let df = goose_utils::dataflow::parse_from(&df)?;

// content.push_str(&check_config(DATAFLOW_PATH, )?);
content.push_str(&hash_config(CONFIG_PATH)?);
Expand Down
2 changes: 1 addition & 1 deletion gs/station/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ fn main() -> Result<()> {
content.push_str(&configure_gs(&config));
content.push_str(&configure_gs_ips(&config.gs.ips, config.gs.port));
let df = fs::read_to_string(DATAFLOW_PATH)?;
let df = goose_utils::dataflow::parse_from(&df);
let df = goose_utils::dataflow::parse_from(&df)?;
let dt = goose_utils::dataflow::collect_data_types(&df);
let dt = generate_data_types_from_config(&dt, true)?;
content.push_str(&dt);
Expand Down
5 changes: 3 additions & 2 deletions util/src/bin/output_gs_frontend.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
fn main() {
fn main() -> anyhow::Result<()> {
let df_path = std::env::args().nth(1).expect("No dataflow file provided");
let df = std::fs::read_to_string(df_path).expect("Failed to read dataflow file");
let df = goose_utils::dataflow::parse_from(&df);
let df = goose_utils::dataflow::parse_from(&df)?;

let output = goose_utils::dataflow::output_gs_frontend_code(&df);
println!("{}", output);
Ok(())
}
3 changes: 2 additions & 1 deletion util/src/bin/output_levi_beckhoff_code.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
fn main() {
fn main() -> anyhow::Result<()> {
let df_path = std::env::args().nth(1).expect("No dataflow file provided");
let df = std::fs::read_to_string(df_path).expect("Failed to read dataflow file");
let df = goose_utils::dataflow::parse_from(&df);

let output = goose_utils::dataflow::make_levi_beckhoff_code(&df);
println!("{}", output);
Ok(())
}
137 changes: 117 additions & 20 deletions util/src/dataflow.rs
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,21 @@ pub struct MessageProcessingSpec {
pub can: CanSpec,
pub fsm: Option<FsmSpec>,
pub datapoint_conversion: Vec<DatapointConversionSpec>,
pub datapoints: Option<DatapointRangeConversionSpec>,
}

#[derive(Debug, serde::Deserialize)]
#[serde(rename_all = "kebab-case")]
pub struct DatapointRangeConversionSpec {
pub name: String,
pub datapoint_size_bytes: u8,
pub datapoint_type: Ty,
pub can_conversion: CanConversionSpec,
pub display_units: String,
pub critical: bool,
pub limits: Option<LimitsSpec>,
pub gs: DatapointConversionGsSpec,
pub store: Option<StoreInfo>,
}

#[derive(serde::Deserialize, Debug)]
Expand All @@ -145,6 +160,11 @@ pub enum CanSpec {
#[serde(flatten)]
comes_from_levi: Option<Can2ComesFromLevi>,
},
#[serde(rename_all = "kebab-case")]
Range {
id_range_first: u16,
id_range_last: u16,
},
}

/// for auto-generation of the code for the levi Beckhoff pc.
Expand All @@ -169,7 +189,6 @@ pub struct DatapointConversionSpec {
pub display_units: Option<String>,
pub limits: Option<LimitsSpec>,
pub gs: DatapointConversionGsSpec,
pub severity: Option<String>,
#[serde(rename = "beckhoff")]
pub comes_from_levi_info: Option<DatapointComesFromLeviInfo>,
}
Expand Down Expand Up @@ -424,6 +443,39 @@ fn make_procedures(df: &DataflowSpec) -> String {
code
}

fn make_datapoint_parser_range(spec: &MessageProcessingSpec, can_index: usize) -> String {
let mut code = String::new();
if let Some(dpc) = &spec.datapoints {
let mut byte_index = 0;
let mut counter = 0;
loop {
writeln!(&mut code, "let d = data[{byte_index}];").unwrap();

writeln!(&mut code, "let c = {}(d);", dpc.can_conversion.proc_name).unwrap();

writeln!(
&mut code,
"f(Datapoint::new(
Datatype::{}{}_{},
dump_{}(c),
embassy_time::Instant::now().as_ticks(),
)).await;",
dpc.name, can_index, counter, dpc.gs.conversion.procedure_suffix
)
.unwrap();

byte_index += dpc.datapoint_size_bytes;
counter += 1;
match byte_index {
0..8 => {},
8 => break,
_ => panic!("Invalid size for datapoint {}{}_{}", dpc.name, can_index, counter),
}
}
}
code
}

fn make_datapoint_parser(spec: &MessageProcessingSpec) -> String {
let mut code = String::new();
for dpc in &spec.datapoint_conversion {
Expand Down Expand Up @@ -476,6 +528,24 @@ pub fn collect_data_types(df: &DataflowSpec) -> crate::datatypes::Config {
store: dpc.datapoint.store.clone(),
});
}
if let Some(datapoints) = &mp.datapoints {
if let CanSpec::Range { id_range_first, id_range_last } = mp.can {
for (can_index, _can_id) in (id_range_first..=id_range_last).enumerate() {
for datatype_index in 0..8 / datapoints.datapoint_size_bytes {
data_types.Datatype.push(crate::datatypes::Datatype {
id: id_range_last + can_index as u16 * datatype_index as u16 + 1,
name: format!("{}{}_{}", &mp.name, can_index, datatype_index),
lower: datapoints.limits.as_ref().map(|l| l.lower).unwrap_or(Limit::No), // TODO: Check
upper: datapoints.limits.as_ref().map(|l| l.upper).unwrap_or(Limit::No),
critical: datapoints.critical,
display_units: Some(datapoints.display_units.clone()),
priority: None,
store: datapoints.store.clone(),
});
}
}
}
}
}
for sd in &df.standard_datapoints {
data_types.Datatype.push(crate::datatypes::Datatype {
Expand Down Expand Up @@ -623,6 +693,9 @@ fn apply_trim_8(data: [u8; 8], ctxt: &str) -> [u8; 0] {
);
}
},
_ => {
// I don't think the ranges should be converted to fsm events
},
}
}
}
Expand Down Expand Up @@ -681,27 +754,54 @@ fn apply_trim_8(data: [u8; 8], ctxt: &str) -> [u8; 0] {

writeln!(&mut code, "pub async fn parse_datapoints_can_2<F, Fut>(id: u32, data: &[u8], mut f: F) where F: FnMut(Datapoint) -> Fut, Fut: Future<Output=()> {{ {proc} match id {{").unwrap();
for mp in &df.message_processing {
if let CanSpec::Can2 { id, .. } = mp.can {
writeln!(
&mut code,
"{id} => {{
match mp.can {
CanSpec::Can2 { id, .. } => {
writeln!(
&mut code,
"\t{id} => {{
"
)
.unwrap();
)
.unwrap();

code.push_str(&make_datapoint_parser(mp));
code.push_str(&make_datapoint_parser(mp));

writeln!(
&mut code,
"}}
writeln!(
&mut code,
"}}
"
)
.unwrap();
)
.unwrap();
},
CanSpec::Range { id_range_first, id_range_last } => {
for (can_index, id) in (id_range_first..=id_range_last).enumerate() {
writeln!(
&mut code,
"\t{id} => {{
"
)
.unwrap();

code.push_str(&make_datapoint_parser_range(mp, can_index));

//TODO: Finish this (just take the same method and apply it to all datapoints in a for loop.
// Use index + mp.name to get the datapoint and index % 8 for the getter,
// use datapoint size to iterate over them. They will also have the same procedures for
// decoding, and use the same time stamp embassy_time::Instant::now().as_ticks()

writeln!(
&mut code,
"}}
"
)
.unwrap();
}
},
_ => {},
}
}
writeln!(&mut code, "_ => {{}}}}}}").unwrap();

writeln!(&mut code, "pub fn match_can_to_datatypes(id: u32) -> [Datatype; 8] {{ match id {{")
writeln!(&mut code, "pub fn match_can_id_to_datatypes(id: u32) -> [Datatype; 8] {{ match id {{")
.unwrap();
for mp in &df.message_processing {
if let CanSpec::Can2 { id, .. } = mp.can {
Expand Down Expand Up @@ -731,7 +831,7 @@ fn apply_trim_8(data: [u8; 8], ctxt: &str) -> [u8; 0] {
"_ => [{}Datatype::DefaultDatatype],}}}}",
"Datatype::DefaultDatatype, ".repeat(7)
)
.unwrap();
.unwrap();

let mut can1commands = vec![];
let mut can2commands = vec![];
Expand Down Expand Up @@ -994,10 +1094,7 @@ END_IF
)
}

pub fn make_logging_pcb_code(_df: &DataflowSpec) -> String {
// TODO
String::new()
}
pub fn make_logging_pcb_code(_df: &DataflowSpec) -> String { String::new() }

pub fn make_gs_code(df: &DataflowSpec) -> String {
let mut code = String::new();
Expand Down Expand Up @@ -1138,4 +1235,4 @@ export const NamedDatatypeValues = ["#
code
}

pub fn parse_from(data: &str) -> DataflowSpec { serde_yaml::from_str(data).unwrap() }
pub fn parse_from(data: &str) -> anyhow::Result<DataflowSpec> { Ok(serde_yaml::from_str(data)?) }