use core::cell::UnsafeCell;
use core::marker::PhantomData;
use avr_oxide::concurrency::Isolated;
use avr_oxide::devices::internal::StaticShareable;
use avr_oxide::event::{EventSink, EventSource, OxideEvent};
use avr_oxide::hal::generic::twi::{Command, RetryStrategy, TwiAddr, TwiCommandCompleteCallback, TwiError, TwoWireMaster};
use avr_oxide::halt_if_none;
use avr_oxide::private::binaryringq::BinaryRingQ;
use avr_oxide::sync::Mutex;
use avr_oxide::util::{OwnOrBorrow, OwnOrBorrowMut};
pub trait SerialBusClient {
fn write_from(&mut self, buffer: &[u8]) -> Result<(),TwiError>;
fn write_from_multiple(&mut self, buffers: &[&[u8]]) -> Result<(),TwiError>;
fn read_into(&mut self, buffer: &mut [u8]) -> Result<usize,TwiError>;
fn write_then_read(&mut self, command: &[u8], result: &mut [u8]) -> Result<usize,TwiError>;
fn write_multiple_then_read(&mut self, commands: &[&[u8]], result: &mut [u8]) -> Result<usize,TwiError>;
}
pub struct SerialBus<B,S>
where
B: 'static + TwoWireMaster,
S: EventSink
{
bus: Mutex<&'static mut B>,
phantom: PhantomData<S>,
response: UnsafeCell<Option<Result<(Command,usize),TwiError>>>,
waiting_response: UnsafeCell<BinaryRingQ> }
impl<B,S> StaticShareable for SerialBus<B,S>
where
B: 'static + TwoWireMaster,
S: EventSink
{}
pub struct SerialBusClientImpl<'sbc,B,S>
where
B: 'static + TwoWireMaster,
S: EventSink
{
address: TwiAddr,
master: &'sbc SerialBus<B,S>
}
impl<B,S> SerialBus<B,S>
where
B: 'static + TwoWireMaster,
S: EventSink
{
pub fn using_bus(bus: &'static mut B) -> Self {
SerialBus {
bus: Mutex::new(bus),
phantom: PhantomData::default(),
response: UnsafeCell::new(None),
waiting_response: UnsafeCell::new(BinaryRingQ::new())
}
}
pub fn client(&self, address: TwiAddr) -> SerialBusClientImpl<B,S> {
SerialBusClientImpl {
address,
master: self
}
}
fn command_complete(&mut self, isotoken: Isolated, result: Result<(Command,usize),TwiError>){
self.response.get_mut().replace(result);
unsafe {
let waiting_response = &mut *self.waiting_response.get();
let _ = waiting_response.append(isotoken, true);
}
}
fn command_blocking(&self, command: Command) -> Result<(Command,usize),TwiError> {
let mut bus = self.bus.lock();
bus.command(command);
unsafe {
let waiting_response = &mut *self.waiting_response.get();
waiting_response.consume_blocking();
let response = &mut *self.response.get();
halt_if_none!(response.take(), avr_oxide::oserror::OsError::InternalError)
}
}
}
impl<B,S> EventSource for SerialBus<B,S>
where
B: 'static + TwoWireMaster,
S: EventSink
{
fn listen(&'static self) {
let bus = self.bus.lock();
bus.set_command_complete_callback(TwiCommandCompleteCallback::WithData(|isotoken, _src, result, udata|{
let myself = halt_if_none!(udata, avr_oxide::oserror::OsError::InternalError) as *mut SerialBus<B,S>;
unsafe {
(*myself).command_complete(isotoken, result);
}
}, self as *const dyn core::any::Any));
}
fn process_event(&self, _evt: OxideEvent) {
todo!()
}
}
impl<'sbc,B,S> SerialBusClient for SerialBusClientImpl<'sbc,B,S>
where
B: 'static + TwoWireMaster,
S: EventSink
{
fn write_from(&mut self, buffer: &[u8]) -> Result<(),TwiError>{
unsafe {
let command = Command::Write(RetryStrategy::UntilAcknowledged,
self.address,
OwnOrBorrow::Borrow(core::mem::transmute(buffer)));
match self.master.command_blocking(command) {
Ok(_) => Ok(()),
Err(e) => Err(e)
}
}
}
fn write_from_multiple(&mut self, buffers: &[&[u8]]) -> Result<(),TwiError> {
unsafe {
let command = Command::WriteMultiple(RetryStrategy::UntilAcknowledged,
self.address,
core::mem::transmute(buffers));
match self.master.command_blocking(command) {
Ok(_) => Ok(()),
Err(e) => Err(e)
}
}
}
fn read_into(&mut self, buffer: &mut [u8]) -> Result<usize,TwiError>{
unsafe {
let command = Command::Read(RetryStrategy::UntilAcknowledged,
self.address,
OwnOrBorrowMut::Borrow(core::mem::transmute(buffer)));
match self.master.command_blocking(command) {
Ok((_,size)) => Ok(size),
Err(e) => Err(e)
}
}
}
fn write_then_read(&mut self, command: &[u8], result: &mut [u8]) -> Result<usize,TwiError> {
unsafe {
let command = Command::WriteThenRead(RetryStrategy::UntilAcknowledged,
self.address,
OwnOrBorrow::Borrow(core::mem::transmute(command)),
OwnOrBorrowMut::Borrow(core::mem::transmute(result)));
match self.master.command_blocking(command) {
Ok((_,size)) => Ok(size),
Err(e) => Err(e)
}
}
}
fn write_multiple_then_read(&mut self, commands: &[&[u8]], result: &mut [u8]) -> Result<usize, TwiError> {
unsafe {
let command = Command::WriteMultipleThenRead(RetryStrategy::UntilAcknowledged,
self.address,
core::mem::transmute(commands),
OwnOrBorrowMut::Borrow(core::mem::transmute(result)));
match self.master.command_blocking(command) {
Ok((_,size)) => Ok(size),
Err(e) => Err(e)
}
}
}
}