1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102
//! # Simple Serial
//!
//! This is a basic service that defines some kind of serial port.
//!
//! This module only contains the service definition and client definition,
//! the server must be implemented for the given target platform.
use uuid::Uuid;
use crate::comms::bbq::BidiHandle;
use crate::comms::oneshot::Reusable;
use crate::Kernel;
use crate::registry::{self, known_uuids, Envelope, KernelHandle, RegisteredDriver, ReplyTo};
////////////////////////////////////////////////////////////////////////////////
// Service Definition
////////////////////////////////////////////////////////////////////////////////
pub struct SimpleSerialService;
impl RegisteredDriver for SimpleSerialService {
type Request = Request;
type Response = Response;
type Error = SimpleSerialError;
// TODO(eliza): maybe we should do a v2 of this trait where the `Hello`
// message is `GetPort` and the request/response types are serial frames?
// but we can't do this until services can be bidi pipes instead of req
// channels...
type Hello = ();
type ConnectError = core::convert::Infallible;
const UUID: Uuid = known_uuids::kernel::SIMPLE_SERIAL_PORT;
}
////////////////////////////////////////////////////////////////////////////////
// Message and Error Types
////////////////////////////////////////////////////////////////////////////////
pub enum Request {
GetPort,
}
pub enum Response {
PortHandle { handle: BidiHandle },
}
#[derive(Debug, Eq, PartialEq)]
pub enum SimpleSerialError {
AlreadyAssignedPort,
}
////////////////////////////////////////////////////////////////////////////////
// Client Definition
////////////////////////////////////////////////////////////////////////////////
pub struct SimpleSerialClient {
kprod: KernelHandle<SimpleSerialService>,
rosc: Reusable<Envelope<Result<Response, SimpleSerialError>>>,
}
impl SimpleSerialClient {
pub async fn from_registry(
kernel: &'static Kernel,
) -> Result<Self, registry::ConnectError<SimpleSerialService>> {
let kprod = kernel.registry().connect::<SimpleSerialService>(()).await?;
Ok(SimpleSerialClient {
kprod,
rosc: Reusable::new_async().await,
})
}
pub async fn from_registry_no_retry(
kernel: &'static Kernel,
) -> Result<Self, registry::ConnectError<SimpleSerialService>> {
let kprod = kernel
.registry()
.try_connect::<SimpleSerialService>(())
.await?;
Ok(SimpleSerialClient {
kprod,
rosc: Reusable::new_async().await,
})
}
pub async fn get_port(&mut self) -> Option<BidiHandle> {
self.kprod
.send(
Request::GetPort,
ReplyTo::OneShot(self.rosc.sender().await.ok()?),
)
.await
.ok()?;
let resp = self.rosc.receive().await.ok()?;
let Response::PortHandle { handle } = resp.body.ok()?;
Some(handle)
}
}