1use super::*;
14use crate::{ffi, Direction, ATTR_BUF_SIZE};
15use nix::errno::Errno;
16use std::{
17 collections::HashMap,
18 ffi::CString,
19 os::raw::{c_char, c_longlong, c_uint},
20 ptr,
21};
22
23#[derive(Debug, Clone)]
27pub struct Device {
28 pub(crate) dev: *mut ffi::iio_device,
30 pub(crate) ctx: Context,
32}
33
34impl Device {
35 pub fn context(&self) -> Context {
37 self.ctx.clone()
38 }
39
40 pub fn id(&self) -> Option<String> {
42 let pstr = unsafe { ffi::iio_device_get_id(self.dev) };
43 cstring_opt(pstr)
44 }
45
46 pub fn name(&self) -> Option<String> {
48 let pstr = unsafe { ffi::iio_device_get_name(self.dev) };
49 cstring_opt(pstr)
50 }
51
52 #[cfg(not(any(feature = "libiio_v0_19", feature = "libiio_v0_21")))]
54 pub fn label(&self) -> Option<String> {
55 let pstr = unsafe { ffi::iio_device_get_label(self.dev) };
56 cstring_opt(pstr)
57 }
58
59 pub fn is_buffer_capable(&self) -> bool {
62 for chan in self.channels() {
64 if chan.is_scan_element() {
65 return true;
66 }
67 }
68 false
69 }
70
71 pub fn is_trigger(&self) -> bool {
73 unsafe { ffi::iio_device_is_trigger(self.dev) }
74 }
75
76 pub fn set_trigger(&self, trigger: &Self) -> Result<()> {
79 let ret = unsafe { ffi::iio_device_set_trigger(self.dev, trigger.dev) };
80 sys_result(ret, ())
81 }
82
83 pub fn remove_trigger(&self) -> Result<()> {
85 let ret = unsafe { ffi::iio_device_set_trigger(self.dev, ptr::null()) };
86 sys_result(ret, ())
87 }
88
89 pub fn set_num_kernel_buffers(&self, n: u32) -> Result<()> {
91 let ret = unsafe { ffi::iio_device_set_kernel_buffers_count(self.dev, n as c_uint) };
92 sys_result(ret, ())
93 }
94
95 pub fn has_attrs(&self) -> bool {
99 unsafe { ffi::iio_device_get_attrs_count(self.dev) > 0 }
100 }
101
102 pub fn num_attrs(&self) -> usize {
104 unsafe { ffi::iio_device_get_attrs_count(self.dev) as usize }
105 }
106
107 pub fn get_attr(&self, idx: usize) -> Result<String> {
109 let pstr = unsafe { ffi::iio_device_get_attr(self.dev, idx as c_uint) };
110 cstring_opt(pstr).ok_or(Error::InvalidIndex)
111 }
112
113 pub fn find_attr(&self, name: &str) -> Option<String> {
115 let cname = cstring_or_bail!(name);
116 let pstr = unsafe { ffi::iio_device_find_attr(self.dev, cname.as_ptr()) };
117 cstring_opt(pstr)
118 }
119
120 pub fn has_attr(&self, name: &str) -> bool {
122 let cname = cstring_or_bail_false!(name);
123 let pstr = unsafe { ffi::iio_device_find_attr(self.dev, cname.as_ptr()) };
124 !pstr.is_null()
125 }
126
127 pub fn attr_read<T: FromAttribute>(&self, attr: &str) -> Result<T> {
131 let sval = self.attr_read_str(attr)?;
132 T::from_attr(&sval)
133 }
134
135 pub fn attr_read_str(&self, attr: &str) -> Result<String> {
139 let mut buf = vec![0 as c_char; ATTR_BUF_SIZE];
140 let attr = CString::new(attr)?;
141 let ret = unsafe {
142 ffi::iio_device_attr_read(self.dev, attr.as_ptr(), buf.as_mut_ptr(), buf.len())
143 };
144 sys_result(ret as i32, ())?;
145 let s = unsafe {
146 CStr::from_ptr(buf.as_ptr())
147 .to_str()
148 .map_err(|_| Error::StringConversionError)?
149 };
150 Ok(s.into())
151 }
152
153 pub fn attr_read_bool(&self, attr: &str) -> Result<bool> {
157 let mut val: bool = false;
158 let attr = CString::new(attr)?;
159 let ret = unsafe { ffi::iio_device_attr_read_bool(self.dev, attr.as_ptr(), &mut val) };
160 sys_result(ret, val)
161 }
162
163 pub fn attr_read_int(&self, attr: &str) -> Result<i64> {
167 let mut val: c_longlong = 0;
168 let attr = CString::new(attr)?;
169 let ret = unsafe { ffi::iio_device_attr_read_longlong(self.dev, attr.as_ptr(), &mut val) };
170 sys_result(ret, val as i64)
171 }
172
173 pub fn attr_read_float(&self, attr: &str) -> Result<f64> {
177 let mut val: f64 = 0.0;
178 let attr = CString::new(attr)?;
179 let ret = unsafe { ffi::iio_device_attr_read_double(self.dev, attr.as_ptr(), &mut val) };
180 sys_result(ret, val)
181 }
182
183 pub fn attr_read_all(&self) -> Result<HashMap<String, String>> {
187 let mut map = HashMap::new();
188 let pmap = (&mut map as *mut HashMap<_, _>).cast();
189 let ret = unsafe { ffi::iio_device_attr_read_all(self.dev, Some(attr_read_all_cb), pmap) };
190 sys_result(ret, map)
191 }
192
193 pub fn attr_write<T: ToAttribute>(&self, attr: &str, val: T) -> Result<()> {
198 let sval = T::to_attr(&val)?;
199 self.attr_write_str(attr, &sval)
200 }
201
202 pub fn attr_write_str(&self, attr: &str, val: &str) -> Result<()> {
207 let attr = CString::new(attr)?;
208 let val = CString::new(val)?;
209 let ret = unsafe { ffi::iio_device_attr_write(self.dev, attr.as_ptr(), val.as_ptr()) };
210 sys_result(ret as i32, ())
211 }
212
213 pub fn attr_write_bool(&self, attr: &str, val: bool) -> Result<()> {
218 let attr = CString::new(attr)?;
219 let ret = unsafe { ffi::iio_device_attr_write_bool(self.dev, attr.as_ptr(), val) };
220 sys_result(ret, ())
221 }
222
223 pub fn attr_write_int(&self, attr: &str, val: i64) -> Result<()> {
228 let attr = CString::new(attr)?;
229 let ret = unsafe { ffi::iio_device_attr_write_longlong(self.dev, attr.as_ptr(), val) };
230 sys_result(ret, ())
231 }
232
233 pub fn attr_write_float(&self, attr: &str, val: f64) -> Result<()> {
238 let attr = CString::new(attr)?;
239 let ret = unsafe { ffi::iio_device_attr_write_double(self.dev, attr.as_ptr(), val) };
240 sys_result(ret, ())
241 }
242
243 pub fn attributes(&self) -> AttrIterator<'_> {
245 AttrIterator { dev: self, idx: 0 }
246 }
247
248 pub fn num_channels(&self) -> usize {
252 unsafe { ffi::iio_device_get_channels_count(self.dev) as usize }
253 }
254
255 pub fn get_channel(&self, idx: usize) -> Result<Channel> {
257 let chan = unsafe { ffi::iio_device_get_channel(self.dev, idx as c_uint) };
258 if chan.is_null() {
259 Err(Error::InvalidIndex)
260 }
261 else {
262 Ok(Channel {
263 chan,
264 ctx: self.context(),
265 })
266 }
267 }
268
269 pub fn find_channel(&self, name: &str, dir: Direction) -> Option<Channel> {
271 let is_output = dir == Direction::Output;
272 let cname = cstring_or_bail!(name);
273 let chan = unsafe { ffi::iio_device_find_channel(self.dev, cname.as_ptr(), is_output) };
274
275 if chan.is_null() {
276 None
277 }
278 else {
279 Some(Channel {
280 chan,
281 ctx: self.context(),
282 })
283 }
284 }
285
286 #[inline]
288 pub fn find_input_channel(&self, name: &str) -> Option<Channel> {
289 self.find_channel(name, Direction::Input)
290 }
291
292 #[inline]
294 pub fn find_output_channel(&self, name: &str) -> Option<Channel> {
295 self.find_channel(name, Direction::Output)
296 }
297
298 pub fn channels(&self) -> ChannelIterator<'_> {
300 ChannelIterator { dev: self, idx: 0 }
301 }
302
303 pub fn create_buffer(&self, sample_count: usize, cyclic: bool) -> Result<Buffer> {
310 let buf = unsafe { ffi::iio_device_create_buffer(self.dev, sample_count, cyclic) };
311 if buf.is_null() {
312 return Err(Errno::last().into());
313 }
314 Ok(Buffer {
315 buf,
316 cap: sample_count,
317 dev: self.clone(),
318 })
319 }
320
321 pub fn sample_size(&self) -> Result<usize> {
327 let ret = unsafe { ffi::iio_device_get_sample_size(self.dev) };
328 sys_result(ret as i32, ret as usize)
329 }
330
331 pub fn reg_read(&self, addr: u32) -> Result<u32> {
333 let mut val: u32 = 0;
334 let ret = unsafe { ffi::iio_device_reg_read(self.dev, addr, &mut val) };
335 sys_result(ret as i32, val)
336 }
337
338 pub fn reg_write(&self, addr: u32, val: u32) -> Result<()> {
340 let ret = unsafe { ffi::iio_device_reg_write(self.dev, addr, val) };
341 sys_result(ret as i32, ())
342 }
343}
344
345unsafe impl Send for Device {}
347
348impl PartialEq for Device {
349 fn eq(&self, other: &Self) -> bool {
352 self.dev == other.dev
353 }
354}
355
356#[derive(Debug)]
358pub struct ChannelIterator<'a> {
359 dev: &'a Device,
361 idx: usize,
363}
364
365impl Iterator for ChannelIterator<'_> {
366 type Item = Channel;
367
368 fn next(&mut self) -> Option<Self::Item> {
369 match self.dev.get_channel(self.idx) {
370 Ok(chan) => {
371 self.idx += 1;
372 Some(chan)
373 }
374 Err(_) => None,
375 }
376 }
377}
378
379#[derive(Debug)]
381pub struct AttrIterator<'a> {
382 dev: &'a Device,
384 idx: usize,
386}
387
388impl Iterator for AttrIterator<'_> {
389 type Item = String;
390
391 fn next(&mut self) -> Option<Self::Item> {
393 match self.dev.get_attr(self.idx) {
394 Ok(name) => {
395 self.idx += 1;
396 Some(name)
397 }
398 Err(_) => None,
399 }
400 }
401}
402
403#[cfg(test)]
411mod tests {
412 use super::*;
413
414 const DEV_ID: &str = "iio:device0";
415 const DEV_NAME: &str = "dummydev";
416
417 #[test]
419 fn get_device() {
420 let ctx = Context::new().unwrap();
421
422 let id_dev = ctx.find_device(DEV_ID).unwrap();
423 assert_eq!(id_dev.id(), Some(DEV_ID.to_string()));
424
425 let name_dev = ctx.find_device(DEV_NAME).unwrap();
426 assert_eq!(name_dev.name(), Some(DEV_NAME.to_string()));
427
428 let id = name_dev.id().unwrap();
430 let id_dev = ctx.find_device(&id).unwrap();
431 assert_eq!(name_dev.name(), Some(DEV_NAME.to_string()));
432 assert_eq!(name_dev, id_dev);
433 }
434
435 #[test]
437 fn attr_iterator_count() {
438 let ctx = Context::new().unwrap();
439 let dev = ctx.find_device(DEV_ID).unwrap();
440
441 let n = dev.num_attrs();
442 assert!(n != 0);
443 assert!(dev.attributes().count() == n);
444 }
445
446 #[test]
448 fn test_device_send() {
449 use std::thread;
450
451 let ctx = Context::new().unwrap();
452 let dev = ctx.find_device("timer0").unwrap();
453
454 let thr = thread::spawn(move || {
459 let name = dev.name().unwrap();
463 assert_eq!(name, "timer0");
464 });
465 let _ = thr.join();
466 }
467}