use core::cell::UnsafeCell;
use core::marker::PhantomData;
use avr_oxide::concurrency::Isolated;
use avr_oxide::event::{EventSink, EventSource, OxideEvent};
use avr_oxide::hal::generic::twi::{Command, CommandBuilder, TwiAddr, TwiCommandCompleteCallback, TwiError, TwoWireMaster};
use avr_oxide::{AsStaticRef, OxideResult, panic_if_none};
use avr_oxide::private::binaryringq::BinaryRingQ;
use avr_oxide::sync::Mutex;
use avr_oxide::OxideResult::{Ok,Err};
pub trait SerialBusClient {
fn get_bus_addr(&self) -> TwiAddr;
fn clone_with_bus_addr(&self, addr: TwiAddr) -> Self;
fn write_from(&mut self, buffer: &[u8]) -> OxideResult<(),TwiError>;
fn write_from_multiple(&mut self, buffers: &[&[u8]]) -> OxideResult<(),TwiError>;
fn read_into(&mut self, buffer: &mut [u8]) -> OxideResult<usize,TwiError>;
fn write_then_read(&mut self, command: &[u8], result: &mut [u8]) -> OxideResult<usize,TwiError>;
fn write_multiple_then_read(&mut self, commands: &[&[u8]], result: &mut [u8]) -> OxideResult<usize,TwiError>;
}
pub trait UsesSerialBusClient<BC>
where
BC: SerialBusClient
{
fn using_client(client: BC) -> Self;
}
pub struct SerialBus<S>
where
S: EventSink
{
bus: Mutex<&'static mut dyn TwoWireMaster>,
phantom: PhantomData<S>,
response: UnsafeCell<Option<OxideResult<(Command<'static>, usize),TwiError>>>,
waiting_response: UnsafeCell<BinaryRingQ> }
pub struct SerialBusClientImpl<'sbc,S>
where
S: EventSink
{
builder: CommandBuilder,
master: &'sbc SerialBus<S>
}
impl<S> SerialBus<S>
where
S: EventSink
{
pub fn using_bus(bus: &'static mut dyn TwoWireMaster) -> Self {
SerialBus {
bus: Mutex::new(bus),
phantom: PhantomData::default(),
response: UnsafeCell::new(None),
waiting_response: UnsafeCell::new(BinaryRingQ::new())
}
}
pub fn client<M: AsStaticRef<Self>>(master: M, address: TwiAddr) -> SerialBusClientImpl<'static,S> {
unsafe {
SerialBusClientImpl {
builder: CommandBuilder::new(address),
master: master.as_static_ref()
}
}
}
fn command_complete(&mut self, isotoken: Isolated, result: OxideResult<(Command<'static>, 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<'static>) -> OxideResult<(Command<'static>, 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();
panic_if_none!(response.take(), avr_oxide::oserror::OsError::InternalError)
}
}
}
impl<S> EventSource for SerialBus<S>
where
S: EventSink
{
fn listen(&'static self) {
let bus = self.bus.lock();
bus.set_command_complete_callback(TwiCommandCompleteCallback::WithData(|isotoken, _src, result, udata|{
let myself = panic_if_none!(udata, avr_oxide::oserror::OsError::InternalError) as *mut SerialBus<S>;
unsafe {
(*myself).command_complete(isotoken, result);
}
}, self as *const dyn core::any::Any));
}
fn process_event(&self, _evt: OxideEvent) {
todo!()
}
}
impl<'sbc,S> SerialBusClient for SerialBusClientImpl<'sbc,S>
where
S: EventSink
{
fn get_bus_addr(&self) -> TwiAddr {
self.builder.get_address()
}
fn clone_with_bus_addr(&self, addr: TwiAddr) -> Self {
Self {
builder: self.builder.clone().address(addr),
master: self.master
}
}
fn write_from(&mut self, buffer: &[u8]) -> OxideResult<(),TwiError>{
unsafe {
let buffer : &'static[u8] = core::mem::transmute(buffer);
let command = self.builder.write_cmd(buffer);
self.master.command_blocking(command)?;
Ok(())
}
}
fn write_from_multiple(&mut self, buffers: &[&[u8]]) -> OxideResult<(),TwiError> {
unsafe {
let buffers : &'static[&'static [u8]] = core::mem::transmute(buffers);
let command = self.builder.write_multiple_cmd(buffers);
self.master.command_blocking(command)?;
Ok(())
}
}
fn read_into(&mut self, buffer: &mut [u8]) -> OxideResult<usize,TwiError>{
unsafe {
let buffer : &'static mut [u8] = core::mem::transmute(buffer);
let command = self.builder.read_cmd(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]) -> OxideResult<usize,TwiError> {
unsafe {
let c_buffer : &'static[u8] = core::mem::transmute(command);
let r_buffer : &'static mut [u8] = core::mem::transmute(result);
let command = self.builder.wtr_cmd(c_buffer, r_buffer);
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]) -> OxideResult<usize, TwiError> {
unsafe {
let c_buffers : &'static[&'static [u8]] = core::mem::transmute(commands);
let r_buffer : &'static mut [u8] = core::mem::transmute(result);
let command = self.builder.wmtr_cmd(c_buffers, r_buffer);
match self.master.command_blocking(command) {
Ok((_,size)) => Ok(size),
Err(e) => Err(e)
}
}
}
}