#![no_std]
#![cfg_attr(feature = "nightly_docs", feature(doc_auto_cfg))]
#![doc = document_features::document_features!()]
use core::fmt::Write;
#[cfg(feature = "static")]
mod statics {
use super::*;
#[cfg(feature = "saul")]
riot_wrappers::static_command!(
static_saul,
"saul.rs",
"interact with sensors and actuators using SAUL via Rust",
saul
);
#[cfg(feature = "ztimer")]
riot_wrappers::static_command!(static_sleep, "sleep", "Pause the shell prompt", sleep);
riot_wrappers::static_command!(static_ps, "ps.rs", "List the processes", ps);
pub fn ps<'a>(w: &mut impl Write, _args: impl IntoIterator<Item = &'a str>) {
super::ps(w)
}
}
#[cfg(feature = "shell")]
pub fn all() -> impl riot_wrappers::shell::CommandList {
use riot_wrappers::shell;
let r = shell::new();
#[cfg(not(feature = "static"))]
let r = r.and(
c"ps.rs",
c"List the processes",
|stdio: &mut _, _args: shell::Args| ps(stdio),
);
#[cfg(not(feature = "static"))]
#[cfg(feature = "ztimer")]
let r = r.and(
c"sleep",
c"Pause the shell prompt",
|stdio: &mut _, args: shell::Args| sleep(stdio, args),
);
#[cfg(not(feature = "static"))]
#[cfg(feature = "saul")]
let r = r.and(
c"saul.rs",
c"interact with sensors and actuators using SAUL via Rust",
|stdio: &mut _, args: shell::Args| saul(stdio, args),
);
r
}
pub fn ps(w: &mut impl Write) {
use riot_wrappers::thread;
for i in thread::KernelPID::all_pids() {
let i_number: riot_sys::kernel_pid_t = i.into();
let stats = i.stack_stats();
if let Err(thread::StackStatsError::NoSuchThread) = stats {
continue;
}
if let Ok(stats) = stats {
writeln!(
w,
"{:>3} ({:<16}): pri {:>2}. {:>6}/{:>6} ({:>3}%). {:.16?}.",
i_number,
i.get_name().unwrap_or("(unnamed)"),
i.priority().expect("Thread exists"),
stats.used(),
stats.size(),
100 * stats.used() / stats.size(),
i.status()
)
.unwrap();
} else {
writeln!(
w,
"{:>3}: pri {:>2}. {:.16?}.",
i_number,
i.priority().expect("Thread exists"),
i.status()
)
.unwrap();
}
}
}
#[cfg(feature = "ztimer")]
pub fn sleep<'a>(w: &mut impl Write, args: impl IntoIterator<Item = &'a str>) {
let mut args = args.into_iter();
let commandname = args
.next()
.expect("How was this started without an argv[0]?");
let time: Option<u32> = args.next().map(|t| t.parse().ok()).flatten();
let time = match (time, args.next()) {
(Some(t), None) => t,
_ => {
writeln!(w, "Usage: {} seconds", commandname).unwrap();
return;
}
};
let msec_clock = riot_wrappers::ztimer::Clock::msec();
msec_clock.sleep_extended(core::time::Duration::new(time.into(), 0));
}
#[cfg(feature = "saul")]
pub fn saul<'a, A>(w: &mut impl Write, args: A)
where
A: IntoIterator<Item = &'a str>,
<A as IntoIterator>::IntoIter: ExactSizeIterator,
{
use riot_wrappers::saul::RegistryEntry;
let mut args = args.into_iter();
let commandname = args
.next()
.expect("How was this started without an argv[0]?");
fn reg_from_arg(arg: Option<&str>) -> Result<(usize, RegistryEntry), &'static str> {
let n = arg
.ok_or("Missing index")?
.parse()
.map_err(|_| "Index: Not a number")?;
Ok((n, RegistryEntry::nth(n).ok_or("No such entry")?))
}
fn enumerate(w: &mut impl Write) {
let mut all = RegistryEntry::all().enumerate().peekable();
writeln!(
w,
"{}",
match all.peek() {
Some(_) => " ID Class Name",
None => "No devices found",
}
)
.unwrap();
for (id, item) in all {
writeln!(
w,
"{:3} {:12} {}",
id,
item.type_()
.map(|c| c.name().unwrap_or("(unnamed)"))
.unwrap_or("(undefined)"),
item.name().unwrap_or("(unnamed)")
)
.unwrap();
}
}
fn read(w: &mut impl Write, id: usize, entry: RegistryEntry) {
let named_entry = entry.name().unwrap_or("(unnamed)");
if let Ok(phydat) = entry.read() {
writeln!(w, "Reading from {} ({}): {}", id, named_entry, phydat).unwrap();
} else {
writeln!(w, "Read error from {} ({})", id, named_entry).unwrap();
}
}
fn write<'a>(
w: &mut impl Write,
mut args: impl ExactSizeIterator<Item = &'a str>,
) -> Result<(), &'static str> {
let (n, entry) = reg_from_arg(args.next())?;
if args.len() > 3 {
return Err("Too many parameters");
}
let args: Result<heapless::Vec<i16, 3>, _> = args
.map(|x| x.parse().map_err(|_| "Bad numeric argument"))
.collect();
let phydat = riot_wrappers::saul::Phydat::new(&args?, None, 0);
writeln!(w, "Writing to {}: {}", n, phydat).unwrap();
entry.write(phydat).map_err(|_| "Write failed")
}
let result = match args.next() {
None => Ok(enumerate(w)),
Some("read") => match (args.next(), args.len()) {
(Some("all"), 0) => {
for (id, item) in RegistryEntry::all().enumerate() {
read(w, id, item);
}
Ok(())
}
(Some(x), 0) => reg_from_arg(Some(x)).map(|(n, entry)| read(w, n, entry)),
_ => Err("Wrong number of arguments"),
},
Some("write") => write(w, args),
_ => Err("No such subcommand"),
};
if let Err(e) = result {
writeln!(
w,
"Error: {}\nUsage: {} [read {{all|idx}}|write idx val1 [val2] [val3]]",
e, commandname
)
.unwrap();
}
}