use crate::ffi::*;
use crate::{Result, RtError};
use core::{any::Any, ptr::NonNull};
#[cfg(feature = "alloc")]
use crate::{cstr::RtName, Box};
use cty::c_void;
mod io;
#[cfg(feature = "io")]
pub use io::*;
mod cmd;
pub use cmd::*;
pub type DeviceType = rt_device_class_type;
bitflags! {
pub struct OpenFlag: u16 {
const CLOSE = RT_DEVICE_OFLAG_CLOSE as u16;
const RDONLY = RT_DEVICE_OFLAG_RDONLY as u16;
const WRONLY = RT_DEVICE_OFLAG_WRONLY as u16;
const RDWR = RT_DEVICE_OFLAG_RDWR as u16;
const OPEN = RT_DEVICE_OFLAG_OPEN as u16;
const STREAM = RT_DEVICE_FLAG_STREAM as u16;
const INT_RX = RT_DEVICE_FLAG_INT_RX as u16;
const DMA_RX = RT_DEVICE_FLAG_DMA_RX as u16;
const INT_TX = RT_DEVICE_FLAG_INT_TX as u16;
const DMA_TX = RT_DEVICE_FLAG_DMA_TX as u16;
}
}
bitflags! {
pub struct RegisterFlag: u16 {
const RDONLY = RT_DEVICE_FLAG_RDONLY as u16;
const WRONLY = RT_DEVICE_FLAG_WRONLY as u16;
const RDWR = RT_DEVICE_FLAG_RDWR as u16;
const REMOVABLE = RT_DEVICE_FLAG_REMOVABLE as u16;
const STANDALONE = RT_DEVICE_FLAG_STANDALONE as u16;
const SUSPENDED = RT_DEVICE_FLAG_SUSPENDED as u16;
const STREAM = RT_DEVICE_FLAG_STREAM as u16;
const INT_RX = RT_DEVICE_FLAG_INT_RX as u16;
const DMA_RX = RT_DEVICE_FLAG_DMA_RX as u16;
const INT_TX = RT_DEVICE_FLAG_INT_TX as u16;
const DMA_TX = RT_DEVICE_FLAG_DMA_TX as u16;
}
}
#[derive(Debug)]
#[repr(transparent)]
pub struct Device {
raw: rt_device_t,
}
pub trait DeviceOps: Any + Send + Sync {
fn init(&mut self, device: &mut Device) -> Result<()>;
fn open(&mut self, device: &mut Device, oflag: OpenFlag) -> Result<()>;
fn close(&mut self, device: &mut Device) -> Result<()>;
fn read(
&mut self,
device: &mut Device,
pos: usize,
buffer: &mut [u8],
size: usize,
) -> Result<usize>;
fn write(
&mut self,
device: &mut Device,
pos: usize,
buffer: &[u8],
size: usize,
) -> Result<usize>;
fn control(&mut self, device: &mut Device, cmd: i32, args: *mut c_void) -> Result<()>;
#[inline]
fn get_block_size(&self) -> usize {
1
}
}
unsafe extern "C" fn init_wrapper(dev: rt_device_t) -> rt_err_t {
let device = NonNull::new(dev).expect("Null device ptr");
let mut userdata: NonNull<Box<dyn DeviceOps>> =
NonNull::new(device.as_ref().user_data.cast()).expect("Null device userdata");
if let Err(err) = userdata.as_mut().init(&mut Device {
raw: device.as_ptr(),
}) {
err.to_code()
} else {
0
}
}
unsafe extern "C" fn open_wrapper(dev: rt_device_t, oflag: u16) -> rt_err_t {
let device = NonNull::new(dev).expect("Null device ptr");
let mut userdata: NonNull<Box<dyn DeviceOps>> =
NonNull::new(device.as_ref().user_data.cast()).expect("Null device userdata");
if let Err(err) = userdata.as_mut().open(
&mut Device {
raw: device.as_ptr(),
},
OpenFlag::from_bits_truncate(oflag),
) {
err.to_code()
} else {
0
}
}
unsafe extern "C" fn close_wrapper(dev: rt_device_t) -> rt_err_t {
let device = NonNull::new(dev).expect("Null device ptr");
let mut userdata: NonNull<Box<dyn DeviceOps>> =
NonNull::new(device.as_ref().user_data.cast()).expect("Null device userdata");
if let Err(err) = userdata.as_mut().close(&mut Device {
raw: device.as_ptr(),
}) {
err.to_code()
} else {
0
}
}
unsafe extern "C" fn read_wrapper(
dev: rt_device_t,
pos: rt_off_t,
buffer: *mut cty::c_void,
size: rt_size_t,
) -> rt_size_t {
let block_size = size as usize;
let device = NonNull::new(dev).expect("Null device ptr");
let mut userdata: NonNull<Box<dyn DeviceOps>> =
NonNull::new(device.as_ref().user_data.cast()).expect("Null device userdata");
let size = block_size * userdata.as_ref().get_block_size();
match userdata.as_mut().read(
&mut Device {
raw: device.as_ptr(),
},
(pos as usize) * block_size,
core::slice::from_raw_parts_mut(buffer.cast(), size),
block_size,
) {
Ok(r) => r as rt_size_t,
Err(err) => {
rt_set_errno(err.to_code());
0
}
}
}
unsafe extern "C" fn write_wrapper(
dev: rt_device_t,
pos: rt_off_t,
buffer: *const cty::c_void,
size: rt_size_t,
) -> rt_size_t {
let block_size = size as usize;
let device = NonNull::new(dev).expect("Null device ptr");
let mut userdata: NonNull<Box<dyn DeviceOps>> =
NonNull::new(device.as_ref().user_data.cast()).expect("Null device userdata");
let size = block_size * userdata.as_ref().get_block_size();
match userdata.as_mut().write(
&mut Device {
raw: device.as_ptr(),
},
(pos as usize) * block_size,
core::slice::from_raw_parts(buffer.cast(), size),
block_size,
) {
Ok(r) => r as rt_size_t,
Err(err) => {
rt_set_errno(err.to_code());
0
}
}
}
unsafe extern "C" fn control_wrapper(
dev: rt_device_t,
cmd: cty::c_int,
args: *mut cty::c_void,
) -> rt_err_t {
let device = NonNull::new(dev).expect("Null device ptr");
let mut userdata: NonNull<Box<dyn DeviceOps>> =
NonNull::new(device.as_ref().user_data.cast()).expect("Null device userdata");
if let Err(err) = userdata.as_mut().control(
&mut Device {
raw: device.as_ptr(),
},
cmd,
args,
) {
err.to_code()
} else {
0
}
}
impl Device {
#[inline]
pub unsafe fn create_uninit(type0: DeviceType, attach_size: usize) -> Result<Self> {
NonNull::new(rt_device_create(type0.0 as i32, attach_size as i32))
.map(|raw| Self { raw: raw.as_ptr() })
.ok_or(RtError::Error)
}
#[cfg(feature = "alloc")]
pub fn create<O>(type0: DeviceType) -> Result<Self>
where
O: DeviceOps + Default,
{
let device = unsafe { rt_device_create(type0.0 as i32, 0) };
let mut device: NonNull<rt_device> = NonNull::new(device).ok_or(RtError::Error)?;
let userdata: Box<Box<dyn DeviceOps>> = Box::new(Box::new(O::default()));
unsafe {
let device = device.as_mut();
device.user_data = Box::into_raw(userdata).cast();
device.init = Some(init_wrapper);
device.open = Some(open_wrapper);
device.close = Some(close_wrapper);
device.read = Some(read_wrapper);
device.write = Some(write_wrapper);
device.control = Some(control_wrapper)
}
Ok(Self {
raw: device.as_ptr(),
})
}
pub unsafe fn destroy(self) {
if let Some(userdata) = NonNull::new(self.raw)
.and_then(|dev| NonNull::<Box<dyn DeviceOps>>::new(dev.as_ref().user_data.cast()))
{
drop(userdata.as_ptr().read());
rt_device_destroy(self.raw);
}
}
#[inline]
pub fn register(&self, name: &str, flags: RegisterFlag) -> Result<()> {
let name = RtName::from(name);
let err = unsafe { rt_device_register(self.raw, name.into(), flags.bits()) };
RtError::from_code_none(err, ())
}
#[inline]
pub fn unregister(&self) -> Result<()> {
let err = unsafe { rt_device_unregister(self.raw) };
RtError::from_code_none(err, ())
}
#[inline]
pub fn find(name: &str) -> Result<Self> {
let name = RtName::from(name);
let res = unsafe { rt_device_find(name.into()) };
if res.is_null() {
Ok(Self { raw: res })
} else {
Err(RtError::Error)
}
}
#[inline]
pub fn init(&mut self) -> Result<()> {
let err = unsafe { rt_device_init(self.raw) };
RtError::from_code_none(err, ())
}
#[inline]
pub fn open(&mut self, oflag: OpenFlag) -> Result<()> {
let err = unsafe { rt_device_open(self.raw, oflag.bits()) };
RtError::from_code_none(err, ())
}
#[inline]
pub fn close(&mut self) -> Result<()> {
let err = unsafe { rt_device_close(self.raw) };
RtError::from_code_none(err, ())
}
#[inline]
pub unsafe fn read(&mut self, pos: usize, buffer: &mut [u8], size: usize) -> Result<usize> {
let res = rt_device_read(
self.raw,
pos as rt_off_t,
buffer.as_mut_ptr().cast(),
size as rt_size_t,
);
RtError::from_code_none(rt_get_errno(), res as usize)
}
#[inline]
pub unsafe fn write(&mut self, pos: usize, buffer: &[u8], size: usize) -> Result<usize> {
let res = rt_device_write(
self.raw,
pos as rt_off_t,
buffer.as_ptr().cast(),
size as rt_size_t,
);
RtError::from_code_none(rt_get_errno(), res as usize)
}
#[inline]
pub fn control<R>(&mut self, cmd: &mut dyn DeviceCommand<Return = R>) -> Result<()> {
let err = unsafe { rt_device_control(self.raw, cmd.get_cmd(), cmd.get_arg()) };
RtError::from_code_none(err, ())
}
#[inline]
pub fn get_device_type(&self) -> DeviceType {
unsafe { (*self.raw).type_ }
}
}