first step in unifying the examples: one example folder

One example folder for all examples, including std and embedded examples
This commit is contained in:
Robin Mueller
2026-09-24 19:45:02 +02:00
parent cb6c8b84bb
commit 2ba0ace388
115 changed files with 36 additions and 36 deletions
@@ -0,0 +1,71 @@
use std::time::Duration;
use anyhow::bail;
use clap::Parser;
use cobs::CobsDecoderOwned;
use embedded_client::setup_logger;
use embedded_types::stm32f3;
use spacepackets::{CcsdsPacketCreatorOwned, CcsdsPacketReader, SpHeader};
use tmtc_utils::transport::serial::PacketTransportSerialCobs;
#[derive(Parser, Debug)]
struct Cli {
#[arg(short, long)]
ping: bool,
/// Set frequency in milliseconds.
#[arg(short, long)]
set_led_frequency: Option<u32>,
}
fn main() -> anyhow::Result<()> {
setup_logger().expect("failed to initialize logger");
println!("-- STM32F3 TMTC client --");
let cli = Cli::parse();
let config = embedded_client::Config::new_from_file();
if config.interface.serial_port.is_none() {
bail!("Serial port not specified in configuration file.");
}
let serial_port = config.interface.serial_port.as_ref().unwrap();
let serial = serialport::new(serial_port, 115200)
.open()
.expect("opening serial port failed");
let mut transport = PacketTransportSerialCobs::new(serial, CobsDecoderOwned::new(1024));
if cli.ping {
let tc = create_stm32f3_tc(&embedded_types::stm32f3::Request::Ping);
log::info!(
"Sending ping request with TC ID: {:#010x}",
tc.ccsds_packet_id_and_psc().raw()
);
transport.send(&tc.to_vec()).unwrap();
}
if let Some(freq_ms) = cli.set_led_frequency {
let request = stm32f3::Request::ChangeBlinkFrequency(Duration::from_millis(freq_ms as u64));
let tc = create_stm32f3_tc(&request);
log::info!(
"Sending change blink frequency request {:?} with TC ID: {:#010x}",
request,
tc.ccsds_packet_id_and_psc().raw()
);
transport.send(&tc.to_vec()).unwrap();
}
log::info!("Waiting for response...");
loop {
transport
.receive(|packet: &[u8]| {
let reader = CcsdsPacketReader::new_with_checksum(packet);
log::info!("Received packet: {:?}", reader);
})
.unwrap();
}
}
fn create_stm32f3_tc(request: &stm32f3::Request) -> CcsdsPacketCreatorOwned {
let req_raw = postcard::to_allocvec(&request).unwrap();
let sp_header = SpHeader::new_from_apid(embedded_types::stm32f3::PUS_APID);
CcsdsPacketCreatorOwned::new_tc_with_checksum(sp_header, &req_raw).unwrap()
}
@@ -0,0 +1,95 @@
use std::{net::UdpSocket, time::Duration};
use anyhow::{Context as _, bail};
use clap::Parser;
use embedded_client::setup_logger;
use embedded_types::{TmHeader, stm32h7};
use spacepackets::{CcsdsPacketCreatorOwned, CcsdsPacketReader, SpHeader};
use tmtc_utils::transport::udp::PacketTransportUdp;
#[derive(Parser, Debug)]
struct Cli {
#[arg(short, long)]
ping: bool,
/// Set frequency in milliseconds.
#[arg(short, long)]
set_led_frequency: Option<u32>,
/// UDP address to bind to.
#[arg(short, long)]
udp_addr: Option<std::net::SocketAddr>,
}
fn main() -> anyhow::Result<()> {
setup_logger().expect("failed to initialize logger");
println!("-- STM32H7 TMTC client --");
let cli = Cli::parse();
let config = embedded_client::Config::new_from_file();
let mut udp_addr = cli.udp_addr;
if udp_addr.is_none() {
udp_addr = config.interface.udp_addr;
}
if udp_addr.is_none() {
bail!("UDP address not specified in config.toml or via command line");
}
let udp_addr = udp_addr.unwrap();
log::info!("binding to UDP address: {}", udp_addr);
let local_socket = UdpSocket::bind("0.0.0.0:0").expect("failed to bind UDP socket");
let mut transport = PacketTransportUdp::new(local_socket, udp_addr)
.with_context(|| "crateing UDP transport failed")?;
if cli.ping {
let tc = create_stm32h7_tc(&embedded_types::stm32h7::Request::Ping);
log::info!(
"Sending ping request with TC ID: {:#010x}",
tc.ccsds_packet_id_and_psc().raw()
);
transport.send(&tc.to_vec()).unwrap();
}
if let Some(freq_ms) = cli.set_led_frequency {
let request = stm32h7::Request::ChangeBlinkFrequency(Duration::from_millis(freq_ms as u64));
let tc = create_stm32h7_tc(&request);
log::info!(
"Sending change blink frequency request {:?} with TC ID: {:#010x}",
request,
tc.ccsds_packet_id_and_psc().raw()
);
transport.send(&tc.to_vec()).unwrap();
}
log::info!("Waiting for response...");
loop {
transport
.receive(|packet: &[u8]| {
let reader = CcsdsPacketReader::new_with_checksum(packet);
log::debug!("Received packet: {:?}", reader);
if let Ok(reader) = reader {
let packet_data = reader.packet_data();
let tm_header = postcard::take_from_bytes::<TmHeader>(packet_data);
if let Ok((tm_header, remainder)) = tm_header {
let response = postcard::from_bytes::<stm32h7::Response>(remainder);
if let Ok(response) = response {
log::info!(
"Received TM with header: {:?} and response: {:?}",
tm_header,
response
);
} else {
log::error!("Failed to deserialize response: {:?}", response.err());
}
} else {
log::error!("Failed to deserialize TM header: {:?}", tm_header.err());
}
}
})
.unwrap();
}
}
fn create_stm32h7_tc(request: &stm32h7::Request) -> CcsdsPacketCreatorOwned {
let req_raw = postcard::to_allocvec(&request).unwrap();
let sp_header = SpHeader::new_from_apid(embedded_types::stm32h7::PUS_APID);
CcsdsPacketCreatorOwned::new_tc_with_checksum(sp_header, &req_raw).unwrap()
}
+43
View File
@@ -0,0 +1,43 @@
use std::{fs::File, io::Read as _, net::SocketAddr, path::Path, time::SystemTime};
#[derive(Debug, serde::Deserialize)]
pub struct Config {
pub interface: Interface,
}
#[derive(Debug, serde::Deserialize)]
pub struct Interface {
pub serial_port: Option<String>,
pub udp_addr: Option<SocketAddr>,
}
impl Config {
pub fn new_from_file() -> Self {
let mut config_file =
File::open(Path::new("config.toml")).expect("opening config.toml file failed");
let mut toml_str = String::new();
config_file
.read_to_string(&mut toml_str)
.expect("reading config.toml file failed");
let config: Config = toml::from_str(&toml_str).expect("parsing config.toml file failed");
config
}
}
pub fn setup_logger() -> Result<(), fern::InitError> {
fern::Dispatch::new()
.format(|out, message, record| {
out.finish(format_args!(
"[{} {} {}] {}",
humantime::format_rfc3339_seconds(SystemTime::now()),
record.level(),
record.target(),
message
))
})
.level(log::LevelFilter::Info)
.chain(std::io::stdout())
.chain(fern::log_file("output.log")?)
.apply()?;
Ok(())
}