use std::collections::HashMap;
use std::ffi::CString;
use std::os::raw::{c_int, c_longlong, c_uint, c_void};
use std::{ptr, str};
use nix::errno::Errno;
use super::*;
use crate::ffi;
pub struct Device {
pub(crate) dev: *mut ffi::iio_device,
pub(crate) ctx: Context,
}
impl Device {
pub fn context(&self) -> Context {
self.ctx.clone()
}
pub fn id(&self) -> Option<String> {
let pstr = unsafe { ffi::iio_device_get_id(self.dev) };
cstring_opt(pstr)
}
pub fn name(&self) -> Option<String> {
let pstr = unsafe { ffi::iio_device_get_name(self.dev) };
cstring_opt(pstr)
}
pub fn is_buffer_capable(&self) -> bool {
for chan in self.channels() {
if chan.is_scan_element() {
return true;
}
}
false
}
pub fn is_trigger(&self) -> bool {
unsafe { ffi::iio_device_is_trigger(self.dev) }
}
pub fn set_trigger(&mut self, trigger: &Device) -> Result<()> {
let ret = unsafe { ffi::iio_device_set_trigger(self.dev, trigger.dev) };
sys_result(ret, ())
}
pub fn remove_trigger(&mut self) -> Result<()> {
let ret = unsafe { ffi::iio_device_set_trigger(self.dev, ptr::null()) };
sys_result(ret, ())
}
pub fn num_attrs(&self) -> usize {
unsafe { ffi::iio_device_get_attrs_count(self.dev) as usize }
}
pub fn get_attr(&self, idx: usize) -> Result<String> {
let pstr = unsafe { ffi::iio_device_get_attr(self.dev, idx as c_uint) };
cstring_opt(pstr).ok_or_else(|| Error::InvalidIndex)
}
pub fn find_attr(&self, name: &str) -> Option<String> {
let cname = cstring_or_bail!(name);
let pstr = unsafe { ffi::iio_device_find_attr(self.dev, cname.as_ptr()) };
cstring_opt(pstr)
}
pub fn has_attr(&self, name: &str) -> bool {
let cname = cstring_or_bail_false!(name);
let pstr = unsafe { ffi::iio_device_find_attr(self.dev, cname.as_ptr()) };
!pstr.is_null()
}
pub fn attr_read_bool(&self, attr: &str) -> Result<bool> {
let mut val: bool = false;
let attr = CString::new(attr)?;
let ret = unsafe { ffi::iio_device_attr_read_bool(self.dev, attr.as_ptr(), &mut val) };
sys_result(ret, val)
}
pub fn attr_read_int(&self, attr: &str) -> Result<i64> {
let mut val: c_longlong = 0;
let attr = CString::new(attr)?;
let ret = unsafe { ffi::iio_device_attr_read_longlong(self.dev, attr.as_ptr(), &mut val) };
sys_result(ret, val as i64)
}
pub fn attr_read_float(&self, attr: &str) -> Result<f64> {
let mut val: f64 = 0.0;
let attr = CString::new(attr)?;
let ret = unsafe { ffi::iio_device_attr_read_double(self.dev, attr.as_ptr(), &mut val) };
sys_result(ret, val)
}
unsafe extern "C" fn attr_read_all_cb(
_chan: *mut ffi::iio_device,
attr: *const c_char,
val: *const c_char,
_len: usize,
pmap: *mut c_void,
) -> c_int {
if attr.is_null() || val.is_null() || pmap.is_null() {
return -1;
}
let attr = CStr::from_ptr(attr).to_string_lossy().to_string();
let val = CStr::from_ptr(val).to_string_lossy().to_string();
let map: &mut HashMap<String, String> = &mut *(pmap as *mut _);
map.insert(attr, val);
0
}
pub fn attr_read_all(&self) -> Result<HashMap<String, String>> {
let mut map = HashMap::new();
let pmap = &mut map as *mut _ as *mut c_void;
let ret = unsafe {
ffi::iio_device_attr_read_all(self.dev, Some(Device::attr_read_all_cb), pmap)
};
sys_result(ret, map)
}
pub fn attr_write_bool(&self, attr: &str, val: bool) -> Result<()> {
let attr = CString::new(attr)?;
let ret = unsafe { ffi::iio_device_attr_write_bool(self.dev, attr.as_ptr(), val) };
sys_result(ret, ())
}
pub fn attr_write_int(&self, attr: &str, val: i64) -> Result<()> {
let attr = CString::new(attr)?;
let ret = unsafe { ffi::iio_device_attr_write_longlong(self.dev, attr.as_ptr(), val) };
sys_result(ret, ())
}
pub fn attr_write_float(&self, attr: &str, val: f64) -> Result<()> {
let attr = CString::new(attr)?;
let ret = unsafe { ffi::iio_device_attr_write_double(self.dev, attr.as_ptr(), val) };
sys_result(ret, ())
}
pub fn attributes(&self) -> AttrIterator {
AttrIterator { dev: self, idx: 0 }
}
pub fn num_channels(&self) -> usize {
unsafe { ffi::iio_device_get_channels_count(self.dev) as usize }
}
pub fn get_channel(&self, idx: usize) -> Result<Channel> {
let chan = unsafe { ffi::iio_device_get_channel(self.dev, idx as c_uint) };
if chan.is_null() {
return Err(Error::InvalidIndex);
}
Ok(Channel {
chan,
ctx: self.context(),
})
}
pub fn find_channel(&self, name: &str, is_output: bool) -> Option<Channel> {
let cname = cstring_or_bail!(name);
let chan = unsafe { ffi::iio_device_find_channel(self.dev, cname.as_ptr(), is_output) };
if chan.is_null() {
None
}
else {
Some(Channel {
chan,
ctx: self.context(),
})
}
}
pub fn channels(&self) -> ChannelIterator {
ChannelIterator { dev: self, idx: 0 }
}
pub fn create_buffer(&self, sample_count: usize, cyclic: bool) -> Result<Buffer> {
let buf = unsafe { ffi::iio_device_create_buffer(self.dev, sample_count, cyclic) };
if buf.is_null() {
return Err(Errno::last().into());
}
Ok(Buffer {
buf,
cap: sample_count,
ctx: self.context(),
})
}
pub fn num_buffer_attrs(&self) -> usize {
unsafe { ffi::iio_device_get_buffer_attrs_count(self.dev) as usize }
}
pub fn get_buffer_attr(&self, idx: usize) -> Result<String> {
let pstr = unsafe { ffi::iio_device_get_buffer_attr(self.dev, idx as c_uint) };
cstring_opt(pstr).ok_or_else(|| Error::InvalidIndex)
}
pub fn find_buffer_attr(&self, name: &str) -> Option<String> {
let cname = cstring_or_bail!(name);
let pstr = unsafe { ffi::iio_device_find_buffer_attr(self.dev, cname.as_ptr()) };
cstring_opt(pstr)
}
pub fn has_buffer_attr(&self, name: &str) -> bool {
let cname = cstring_or_bail_false!(name);
let pstr = unsafe { ffi::iio_device_find_buffer_attr(self.dev, cname.as_ptr()) };
!pstr.is_null()
}
pub fn buffer_attr_read_bool(&self, attr: &str) -> Result<bool> {
let mut val: bool = false;
let attr = CString::new(attr)?;
let ret =
unsafe { ffi::iio_device_buffer_attr_read_bool(self.dev, attr.as_ptr(), &mut val) };
sys_result(ret, val)
}
pub fn buffer_attr_read_int(&self, attr: &str) -> Result<i64> {
let mut val: c_longlong = 0;
let attr = CString::new(attr)?;
let ret =
unsafe { ffi::iio_device_buffer_attr_read_longlong(self.dev, attr.as_ptr(), &mut val) };
sys_result(ret, val as i64)
}
pub fn buffer_attr_read_float(&self, attr: &str) -> Result<f64> {
let mut val: f64 = 0.0;
let attr = CString::new(attr)?;
let ret =
unsafe { ffi::iio_device_buffer_attr_read_double(self.dev, attr.as_ptr(), &mut val) };
sys_result(ret, val)
}
pub fn buffer_attr_read_all(&self) -> Result<HashMap<String, String>> {
let mut map = HashMap::new();
let pmap = &mut map as *mut _ as *mut c_void;
let ret = unsafe {
ffi::iio_device_buffer_attr_read_all(self.dev, Some(Device::attr_read_all_cb), pmap)
};
sys_result(ret, map)
}
pub fn buffer_attr_write_bool(&self, attr: &str, val: bool) -> Result<()> {
let attr = CString::new(attr)?;
let ret = unsafe { ffi::iio_device_buffer_attr_write_bool(self.dev, attr.as_ptr(), val) };
sys_result(ret, ())
}
pub fn buffer_attr_write_int(&self, attr: &str, val: i64) -> Result<()> {
let attr = CString::new(attr)?;
let ret =
unsafe { ffi::iio_device_buffer_attr_write_longlong(self.dev, attr.as_ptr(), val) };
sys_result(ret, ())
}
pub fn buffer_attr_write_float(&self, attr: &str, val: f64) -> Result<()> {
let attr = CString::new(attr)?;
let ret = unsafe { ffi::iio_device_buffer_attr_write_double(self.dev, attr.as_ptr(), val) };
sys_result(ret, ())
}
pub fn buffer_attributes(&self) -> BufferAttrIterator {
BufferAttrIterator { dev: self, idx: 0 }
}
pub fn set_num_kernel_buffers(&self, n: u32) -> Result<()> {
let ret = unsafe { ffi::iio_device_set_kernel_buffers_count(self.dev, n as c_uint) };
sys_result(ret, ())
}
pub fn sample_size(&self) -> Result<usize> {
let ret = unsafe { ffi::iio_device_get_sample_size(self.dev) };
sys_result(ret as i32, ret as usize)
}
pub fn reg_read(&self, addr: u32) -> Result<u32> {
let mut val: u32 = 0;
let ret = unsafe { ffi::iio_device_reg_read(self.dev, addr, &mut val) };
sys_result(ret as i32, val)
}
pub fn reg_write(&self, addr: u32, val: u32) -> Result<()> {
let ret = unsafe { ffi::iio_device_reg_write(self.dev, addr, val) };
sys_result(ret as i32, ())
}
}
impl PartialEq for Device {
fn eq(&self, other: &Device) -> bool {
self.dev == other.dev
}
}
pub struct ChannelIterator<'a> {
dev: &'a Device,
idx: usize,
}
impl<'a> Iterator for ChannelIterator<'a> {
type Item = Channel;
fn next(&mut self) -> Option<Self::Item> {
match self.dev.get_channel(self.idx) {
Ok(chan) => {
self.idx += 1;
Some(chan)
}
Err(_) => None,
}
}
}
pub struct AttrIterator<'a> {
dev: &'a Device,
idx: usize,
}
impl<'a> Iterator for AttrIterator<'a> {
type Item = String;
fn next(&mut self) -> Option<Self::Item> {
match self.dev.get_attr(self.idx) {
Ok(name) => {
self.idx += 1;
Some(name)
}
Err(_) => None,
}
}
}
pub struct BufferAttrIterator<'a> {
dev: &'a Device,
idx: usize,
}
impl<'a> Iterator for BufferAttrIterator<'a> {
type Item = String;
fn next(&mut self) -> Option<Self::Item> {
match self.dev.get_buffer_attr(self.idx) {
Ok(name) => {
self.idx += 1;
Some(name)
}
Err(_) => None,
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn get_device() {
let ctx = Context::new().unwrap();
let dev = ctx.get_device(0);
assert!(dev.is_ok());
let dev = dev.unwrap();
let id = dev.id().unwrap();
assert!(!id.is_empty());
}
#[test]
fn attr_iterator_count() {
let ctx = Context::new().unwrap();
let dev = ctx.get_device(0).unwrap();
let n = dev.num_attrs();
assert!(n != 0);
assert!(dev.attributes().count() == n);
}
}