services: xous-ticktimer: use reply_and_receive_next()

Convert the ticktimer server to use the new
reply_and_receive_next_legacy() call. This is an example of how to use
this API for future projects.

Signed-off-by: Sean Cross <sean@xobs.io>
This commit is contained in:
Sean Cross 2022-12-29 21:06:51 +08:00
parent 0e75b8e479
commit e2bf710939

View file

@ -3,7 +3,7 @@
#![cfg_attr(target_os = "none", no_main)]
use xous_api_ticktimer::*;
#[cfg(feature="timestamp")]
#[cfg(feature = "timestamp")]
mod version;
use std::collections::{BTreeMap, HashMap, HashSet, VecDeque};
@ -62,7 +62,7 @@ impl core::cmp::PartialEq for TimerRequest {
}
}
#[cfg(any(feature="precursor", feature="renode"))]
#[cfg(any(feature = "precursor", feature = "renode"))]
mod implementation {
const TICKS_PER_MS: u64 = 1;
use super::TimerRequest;
@ -284,8 +284,9 @@ mod implementation {
}
}
#[cfg(any(not(target_os = "xous"),
not(any(feature="precursor", feature="renode", not(target_os = "xous")))
#[cfg(any(
not(target_os = "xous"),
not(any(feature = "precursor", feature = "renode", not(target_os = "xous")))
))]
mod implementation {
use crate::RequestKind;
@ -524,14 +525,14 @@ fn main() -> ! {
log::set_max_level(log::LevelFilter::Info);
info!("my PID is {}", xous::process::id());
#[cfg(feature="timestamp")]
#[cfg(feature = "timestamp")]
{
log::info!("****************************************************************");
log::info!("Welcome to Xous {}", version::SEMVER);
log::info!("Built on {}", version::TIMESTAMP);
log::info!("****************************************************************");
}
#[cfg(not(feature="timestamp"))]
#[cfg(not(feature = "timestamp"))]
{
log::info!("****************************************************************");
log::info!("Welcome to Xous");
@ -598,39 +599,65 @@ fn main() -> ! {
let mut mutex_hash: HashMap<Option<xous::PID>, HashMap<usize, VecDeque<xous::MessageSender>>> =
HashMap::new();
let mut msg_opt = None;
let mut return_type = 0;
loop {
#[cfg(feature = "watchdog")]
ticktimer.reset_wdt();
//#[cfg(feature = "watchdog")] // for debugging the watchdog
//ticktimer.check_wdt();
let mut msg = xous::receive_message(ticktimer_server).unwrap();
xous::reply_and_receive_next_legacy(ticktimer_server, &mut msg_opt, &mut return_type)
.unwrap();
let msg = msg_opt.as_mut().unwrap();
log::trace!("msg: {:x?}", msg);
match num_traits::FromPrimitive::from_usize(msg.body.id())
.unwrap_or(api::Opcode::InvalidCall)
{
api::Opcode::ElapsedMs => {
let time = ticktimer.elapsed_ms() as i64;
xous::return_scalar2(
msg.sender,
(time & 0xFFFF_FFFFi64) as usize,
((time >> 32) & 0xFFF_FFFFi64) as usize,
)
.expect("couldn't return time request");
if let Some(scalar) = msg.body.scalar_message_mut() {
let time = ticktimer.elapsed_ms() as i64;
scalar.arg1 = (time & 0xFFFF_FFFFi64) as usize;
scalar.arg2 = ((time >> 32) & 0xFFF_FFFFi64) as usize;
scalar.id = 0;
// API calls expect a `Scalar2` value in response
return_type = 2;
}
}
api::Opcode::SleepMs => {
if let Some(scalar) = msg.body.scalar_message_mut() {
let ms = scalar.arg1 as i64;
let sender = msg.sender;
// Forget the contents of the message, replacing it with `None`. This
// will prevent it from getting dropped, which (under normal circumstances)
// would cause it to be responded to automatically.
//
// The ideal approach here would be to have the struct -- in this case the
// TimerRequest -- keep track of the element itself. That way, it could
// return the value as part of its response routine. However, due to the
// legacy split of `BlockingScalars`, these are allowed to have an explicit
// return path, so we need to forget the original message here to prevent
// it from getting returned early.
//
// (n.b. this auto-response hasn't been enabled yet for Scalar messages,
// but this definitely would need to be done for e.g. Memory messages).
core::mem::forget(msg_opt.take());
// let timeout_queue = timeout_heap.entry(msg.sender.pid()).or_default();
recalculate_sleep(
&mut ticktimer,
&mut sleep_heap,
Some(TimerRequest {
msec: ms,
sender: sender,
kind: RequestKind::Sleep,
data: 0,
}),
);
}
}
api::Opcode::SleepMs => xous::msg_blocking_scalar_unpack!(msg, ms, _, _, _, {
// let timeout_queue = timeout_heap.entry(msg.sender.pid()).or_default();
recalculate_sleep(
&mut ticktimer,
&mut sleep_heap,
Some(TimerRequest {
msec: ms as i64,
sender: msg.sender,
kind: RequestKind::Sleep,
data: 0,
}),
)
}),
api::Opcode::RecalculateSleep => {
// let timeout_queue = timeout_heap.entry(msg.sender.pid()).or_default();
if let Some(args) = msg.body.scalar_message() {
@ -686,28 +713,24 @@ fn main() -> ! {
msg.body.memory_message_mut().unwrap(),
)
};
#[cfg(feature="timestamp")]
#[cfg(feature = "timestamp")]
buf.replace(version::get_version()).unwrap();
#[cfg(not(feature="timestamp"))]
#[cfg(not(feature = "timestamp"))]
{
let v = crate::api::VersionString {
version: xous_ipc::String::from_str("--no-timestamp requested for build")
version: xous_ipc::String::from_str("--no-timestamp requested for build"),
};
buf.replace(v).unwrap();
}
}
api::Opcode::LockMutex => {
let pid = msg.sender.pid();
if !msg.body.is_blocking() {
info!("sender made LockMutex request that was not blocking");
continue;
}
if let Some(scalar) = msg.body.scalar_message() {
if let Some(scalar) = msg.body.scalar_message_mut() {
let ready = mutex_ready_hash.entry(pid).or_default();
// If this item is in the Ready list, return right away without blocking
if ready.remove(&scalar.arg1) {
xous::return_scalar(msg.sender, 0).unwrap();
scalar.id = 0;
continue;
}
@ -719,6 +742,12 @@ fn main() -> ! {
// the message will get a response.
let mutex_entry = awaiting.entry(scalar.arg1).or_default();
mutex_entry.push_back(msg.sender);
// We've saved the `msg.sender` above and will return the lock as part of the mutex
// work thread. Forget the contents of `msg_opt` without running its destructor.
core::mem::forget(msg_opt.take());
} else {
info!("sender made LockMutex request that was not blocking");
}
}
api::Opcode::UnlockMutex => {
@ -745,11 +774,7 @@ fn main() -> ! {
}
api::Opcode::WaitForCondition => {
let pid = msg.sender.pid();
if !msg.body.is_blocking() {
info!("sender made WaitForCondition request that was not blocking");
continue;
}
if let Some(scalar) = msg.body.scalar_message() {
if let Some(scalar) = msg.body.scalar_message_mut() {
let condvar = scalar.arg1;
let timeout = scalar.arg2;
@ -769,8 +794,10 @@ fn main() -> ! {
{
if *excess > 0 {
*excess -= 1;
xous::return_scalar(msg.sender, 0)
.expect("couldn't respond to message");
scalar.id = 0;
// Rust libstd expects a `Scalar1` return type for this call
return_type = 1;
continue;
}
}
@ -798,7 +825,11 @@ fn main() -> ! {
.push_back(msg.sender);
// log::trace!("New waiting senders: {:?}", notify_hash.get(&pid).unwrap().get(&condvar));
continue;
// The message will be responded to as part of the notification hash
// when the condvar is unlocked. Forget the contents of the message
// in order to prevent it from being responded to early.
core::mem::forget(msg_opt.take());
} else {
info!(
"sender made WaitForCondition request that wasn't a BlockingScalar Message"