pub mod basic;
use alloc::vec::Vec;
use core::str;
use crate::{Node, ResponseToken, TransferHandler};
use canadensis_core::time::{milliseconds, Instant};
use canadensis_core::transfer::ServiceTransfer;
use canadensis_core::transport::{Receiver, Transport};
use canadensis_data_types::uavcan::register::access_1_0::{self, AccessRequest, AccessResponse};
use canadensis_data_types::uavcan::register::list_1_0::{self, ListRequest, ListResponse};
use canadensis_data_types::uavcan::register::name_1_0::Name;
use canadensis_data_types::uavcan::register::value_1_0::Value;
use canadensis_data_types::uavcan::time::synchronized_timestamp_1_0::SynchronizedTimestamp;
use canadensis_encoding::Deserialize;
pub use canadensis_derive_register_block::RegisterBlock;
pub trait RegisterBlock {
fn register_by_index(&self, index: usize) -> Option<&dyn Register>;
fn register_by_index_mut(&mut self, index: usize) -> Option<&mut dyn Register>;
fn register_by_name_mut(&mut self, name: &str) -> Option<&mut dyn Register>;
}
#[derive(Debug, Clone)]
pub struct Access {
pub mutable: bool,
pub persistent: bool,
}
pub trait Register {
fn name(&self) -> &str;
fn access(&self) -> Access;
fn read(&self) -> Value;
fn write(&mut self, value: &Value) -> Result<(), WriteError>;
}
#[derive(Debug)]
pub enum WriteError {
Type,
}
pub struct RegisterHandler<B> {
block: B,
}
impl<B> RegisterHandler<B>
where
B: RegisterBlock,
{
pub fn new(block: B) -> Self {
RegisterHandler { block }
}
pub fn subscribe_requests<N>(
node: &mut N,
) -> Result<(), <N::Receiver as Receiver<N::Instant>>::Error>
where
N: Node,
{
node.subscribe_request(access_1_0::SERVICE, 515, milliseconds(1000))?;
node.subscribe_request(list_1_0::SERVICE, 2, milliseconds(0))?;
Ok(())
}
pub fn block(&self) -> &B {
&self.block
}
pub fn block_mut(&mut self) -> &mut B {
&mut self.block
}
fn handle_access_request(&mut self, request: &AccessRequest) -> AccessResponse {
match str::from_utf8(&request.name.name) {
Ok(register_name) => {
log::debug!("Handling access request for {}", register_name);
if let Some(register) = self.block.register_by_name_mut(register_name) {
register_handle_access(register, request)
} else {
AccessResponse {
timestamp: SynchronizedTimestamp { microsecond: 0 },
mutable: false,
persistent: false,
value: Value::Empty(
canadensis_data_types::uavcan::primitive::empty_1_0::Empty {},
),
}
}
}
Err(_) => {
AccessResponse {
timestamp: SynchronizedTimestamp { microsecond: 0 },
mutable: false,
persistent: false,
value: Value::Empty(
canadensis_data_types::uavcan::primitive::empty_1_0::Empty {},
),
}
}
}
}
fn handle_list_request(&mut self, request: &ListRequest) -> ListResponse {
log::debug!("Handling register list request, index {}", {
request.index
});
match self.block.register_by_index(request.index.into()) {
Some(register) => {
let name = register.name().as_bytes();
let name = if name.len() <= 256 {
name
} else {
&name[..256]
};
ListResponse {
name: Name {
name: heapless::Vec::from_slice(name).expect("Incorrect name length"),
},
}
}
None => {
ListResponse {
name: Name {
name: heapless::Vec::new(),
},
}
}
}
}
}
fn register_handle_access(register: &mut dyn Register, request: &AccessRequest) -> AccessResponse {
let access = register.access();
if access.mutable
&& !matches!(
request.value,
Value::Empty(canadensis_data_types::uavcan::primitive::empty_1_0::Empty {})
)
{
let _ = register.write(&request.value);
}
AccessResponse {
timestamp: SynchronizedTimestamp { microsecond: 0 },
mutable: access.mutable,
persistent: access.persistent,
value: register.read(),
}
}
impl<I, B, T> TransferHandler<I, T> for RegisterHandler<B>
where
I: Instant,
B: RegisterBlock,
T: Transport,
{
fn handle_request<N: Node<Instant = I, Transport = T>>(
&mut self,
node: &mut N,
token: ResponseToken<T>,
transfer: &ServiceTransfer<Vec<u8>, I, T>,
) -> bool {
match transfer.header.service {
access_1_0::SERVICE => {
if let Ok(request) = AccessRequest::deserialize_from_bytes(&transfer.payload) {
let response = self.handle_access_request(&request);
let status = node.send_response(token, milliseconds(1000), &response);
if status.is_err() {
log::warn!("Out of memory when sending register access response");
}
true
} else {
false
}
}
list_1_0::SERVICE => {
if let Ok(request) = ListRequest::deserialize_from_bytes(&transfer.payload) {
let response = self.handle_list_request(&request);
let status = node.send_response(token, milliseconds(1000), &response);
if status.is_err() {
log::warn!("Out of memory when sending register list response");
}
true
} else {
false
}
}
_ => false,
}
}
}