server/
archive.rs

1// SPDX-FileCopyrightText: 2023 Foundation Devices, Inc. <hello@foundation.xyz>
2// SPDX-License-Identifier: GPL-3.0-or-later
3
4use std::any::type_name;
5
6use whence::WhenceExt;
7use xous_ipc::XousValidator;
8
9use crate::{Error, Owned, Server, ServerContext};
10
11/// A [`Archive`] message handler.
12pub trait ArchiveHandler<M>
13where
14    M: Archive,
15    Self: Server,
16{
17    fn handle(&mut self, msg: Owned<M>, sender: xous::PID, context: &mut ServerContext<Self>);
18}
19
20/// A message which can be serialized and deserialized using rkyv, with no response.
21pub trait Archive: crate::ArchiveCodec + crate::MessageId + 'static {}
22
23/// Message handler, used by ServerMessages::messages()
24pub fn handle_archive_message<M, S>(
25    handler: &mut S,
26    raw: xous::MessageEnvelope,
27    context: &mut ServerContext<S>,
28) where
29    M: Archive,
30    S: ArchiveHandler<M>,
31    <M as rkyv::Archive>::Archived: for<'a> rkyv::bytecheck::CheckBytes<XousValidator<'a>>,
32{
33    let pid = raw.sender.pid().unwrap();
34    if let Err(e) = try_handle_archive_message(pid, handler, raw, context) {
35        log::warn!("Archive handle error (PID {pid}) for {}: {e}", type_name::<M>());
36    }
37}
38
39fn try_handle_archive_message<M, S>(
40    pid: xous::PID,
41    handler: &mut S,
42    raw: xous::MessageEnvelope,
43    context: &mut ServerContext<S>,
44) -> whence::Result<(), Error>
45where
46    M: Archive,
47    S: ArchiveHandler<M>,
48    <M as rkyv::Archive>::Archived: for<'a> rkyv::bytecheck::CheckBytes<XousValidator<'a>>,
49{
50    let msg = Owned::new_move(raw).whence()?;
51    handler.handle(msg, pid, context);
52    Ok(())
53}
54
55/// Send a [`Archive`] message.
56/// Blocks if the queue is full.
57/// Cannot be used from an IRQ context.
58pub fn send_archive<M>(cid: xous::CID, msg: M) -> Result<(), xous::Error>
59where
60    M: Archive,
61{
62    xous_ipc::Buffer::into_buf(&msg).map_err(|_| xous::Error::InternalError)?.send(cid, M::ID as u32)?;
63    Ok(())
64}
65
66/// Try to send a [`Archive`] message.
67/// Returns an error if the queue is full
68/// Can be used from an IRQ context.
69pub fn send_archive_nowait<M>(cid: xous::CID, msg: M) -> Result<(), xous::Error>
70where
71    M: Archive,
72{
73    let buf = xous_ipc::Buffer::into_buf(&msg).map_err(|_| xous::Error::InternalError)?;
74    buf.send_nowait(cid, M::ID as u32)?;
75    Ok(())
76}