1use super::*;
14use crate::{ffi, ATTR_BUF_SIZE};
15use std::{
16 any::TypeId,
17 collections::HashMap,
18 ffi::CString,
19 mem::{self, size_of, size_of_val},
20 os::raw::{c_char, c_int, c_longlong, c_uint, c_void},
21};
22
23#[derive(Debug, Clone, Copy, PartialEq, Eq)]
25pub enum Direction {
26 Input,
28 Output,
30}
31
32#[allow(missing_docs)]
34#[repr(u32)]
35#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
36pub enum ChannelType {
37 Voltage = ffi::iio_chan_type_IIO_VOLTAGE,
38 Current = ffi::iio_chan_type_IIO_CURRENT,
39 Power = ffi::iio_chan_type_IIO_POWER,
40 Accel = ffi::iio_chan_type_IIO_ACCEL,
41 AnglVel = ffi::iio_chan_type_IIO_ANGL_VEL,
42 Magn = ffi::iio_chan_type_IIO_MAGN,
43 Light = ffi::iio_chan_type_IIO_LIGHT,
44 Intensity = ffi::iio_chan_type_IIO_INTENSITY,
45 Proximity = ffi::iio_chan_type_IIO_PROXIMITY,
46 Temp = ffi::iio_chan_type_IIO_TEMP,
47 Incli = ffi::iio_chan_type_IIO_INCLI,
48 Rot = ffi::iio_chan_type_IIO_ROT,
49 Angl = ffi::iio_chan_type_IIO_ANGL,
50 Timestamp = ffi::iio_chan_type_IIO_TIMESTAMP,
51 Capacitance = ffi::iio_chan_type_IIO_CAPACITANCE,
52 AltVoltage = ffi::iio_chan_type_IIO_ALTVOLTAGE,
53 Cct = ffi::iio_chan_type_IIO_CCT,
54 Pressure = ffi::iio_chan_type_IIO_PRESSURE,
55 HumidityRelative = ffi::iio_chan_type_IIO_HUMIDITYRELATIVE,
56 Activity = ffi::iio_chan_type_IIO_ACTIVITY,
57 Steps = ffi::iio_chan_type_IIO_STEPS,
58 Energy = ffi::iio_chan_type_IIO_ENERGY,
59 Distance = ffi::iio_chan_type_IIO_DISTANCE,
60 Velocity = ffi::iio_chan_type_IIO_VELOCITY,
61 Concentration = ffi::iio_chan_type_IIO_CONCENTRATION,
62 Resistance = ffi::iio_chan_type_IIO_RESISTANCE,
63 Ph = ffi::iio_chan_type_IIO_PH,
64 UvIndex = ffi::iio_chan_type_IIO_UVINDEX,
65 ElectricalConductivity = ffi::iio_chan_type_IIO_ELECTRICALCONDUCTIVITY,
66 Count = ffi::iio_chan_type_IIO_COUNT,
67 Index = ffi::iio_chan_type_IIO_INDEX,
68 Gravity = ffi::iio_chan_type_IIO_GRAVITY,
69 Unknown = ffi::iio_chan_type_IIO_CHAN_TYPE_UNKNOWN,
70}
71
72impl From<u32> for ChannelType {
73 fn from(val: u32) -> ChannelType {
74 use ChannelType::*;
75
76 match val {
77 ffi::iio_chan_type_IIO_VOLTAGE => Voltage,
78 ffi::iio_chan_type_IIO_CURRENT => Current,
79 ffi::iio_chan_type_IIO_POWER => Power,
80 ffi::iio_chan_type_IIO_ACCEL => Accel,
81 ffi::iio_chan_type_IIO_ANGL_VEL => AnglVel,
82 ffi::iio_chan_type_IIO_MAGN => Magn,
83 ffi::iio_chan_type_IIO_LIGHT => Light,
84 ffi::iio_chan_type_IIO_INTENSITY => Intensity,
85 ffi::iio_chan_type_IIO_PROXIMITY => Proximity,
86 ffi::iio_chan_type_IIO_TEMP => Temp,
87 ffi::iio_chan_type_IIO_INCLI => Incli,
88 ffi::iio_chan_type_IIO_ROT => Rot,
89 ffi::iio_chan_type_IIO_ANGL => Angl,
90 ffi::iio_chan_type_IIO_TIMESTAMP => Timestamp,
91 ffi::iio_chan_type_IIO_CAPACITANCE => Capacitance,
92 ffi::iio_chan_type_IIO_ALTVOLTAGE => AltVoltage,
93 ffi::iio_chan_type_IIO_CCT => Cct,
94 ffi::iio_chan_type_IIO_PRESSURE => Pressure,
95 ffi::iio_chan_type_IIO_HUMIDITYRELATIVE => HumidityRelative,
96 ffi::iio_chan_type_IIO_ACTIVITY => Activity,
97 ffi::iio_chan_type_IIO_STEPS => Steps,
98 ffi::iio_chan_type_IIO_ENERGY => Energy,
99 ffi::iio_chan_type_IIO_DISTANCE => Distance,
100 ffi::iio_chan_type_IIO_VELOCITY => Velocity,
101 ffi::iio_chan_type_IIO_CONCENTRATION => Concentration,
102 ffi::iio_chan_type_IIO_RESISTANCE => Resistance,
103 ffi::iio_chan_type_IIO_PH => Ph,
104 ffi::iio_chan_type_IIO_UVINDEX => UvIndex,
105 ffi::iio_chan_type_IIO_ELECTRICALCONDUCTIVITY => ElectricalConductivity,
106 ffi::iio_chan_type_IIO_COUNT => Count,
107 ffi::iio_chan_type_IIO_INDEX => Index,
108 ffi::iio_chan_type_IIO_GRAVITY => Gravity,
109 _ => Unknown,
110 }
111 }
112}
113
114#[derive(Debug, Copy, Clone)]
116pub struct DataFormat {
117 data_fmt: ffi::iio_data_format,
119}
120
121impl DataFormat {
122 fn new(data_fmt: ffi::iio_data_format) -> Self {
124 Self { data_fmt }
125 }
126
127 pub fn length(&self) -> u32 {
129 u32::from(self.data_fmt.length)
130 }
131
132 pub fn bits(&self) -> u32 {
134 u32::from(self.data_fmt.bits)
135 }
136
137 pub fn shift(&self) -> u32 {
139 u32::from(self.data_fmt.shift)
140 }
141
142 pub fn is_signed(&self) -> bool {
144 self.data_fmt.is_signed
145 }
146
147 pub fn is_fully_defined(&self) -> bool {
149 self.data_fmt.is_fully_defined
150 }
151
152 pub fn is_big_endian(&self) -> bool {
154 self.data_fmt.is_be
155 }
156
157 pub fn with_scale(&self) -> bool {
159 self.data_fmt.with_scale
160 }
161
162 pub fn scale(&self) -> f64 {
164 self.data_fmt.scale
165 }
166
167 pub fn repeat(&self) -> u32 {
169 u32::from(self.data_fmt.repeat)
170 }
171
172 pub fn byte_length(&self) -> usize {
174 let nbytes = (self.length() / 8) * self.repeat();
175 nbytes as usize
176 }
177
178 pub fn type_of(&self) -> Option<TypeId> {
183 let nbytes = self.byte_length();
184
185 if self.is_signed() {
186 match nbytes {
187 1 => Some(TypeId::of::<i8>()),
188 2 => Some(TypeId::of::<i16>()),
189 4 => Some(TypeId::of::<i32>()),
190 8 => Some(TypeId::of::<i64>()),
191 _ => None,
192 }
193 }
194 else {
195 match nbytes {
196 1 => Some(TypeId::of::<u8>()),
197 2 => Some(TypeId::of::<u16>()),
198 4 => Some(TypeId::of::<u32>()),
199 8 => Some(TypeId::of::<u64>()),
200 _ => None,
201 }
202 }
203 }
204}
205
206#[derive(Debug, Clone)]
208pub struct Channel {
209 pub(crate) chan: *mut ffi::iio_channel,
211 #[allow(dead_code)]
212 pub(crate) ctx: Context,
214}
215
216impl Channel {
217 pub fn name(&self) -> Option<String> {
219 let pstr = unsafe { ffi::iio_channel_get_name(self.chan) };
220 cstring_opt(pstr)
221 }
222
223 pub fn id(&self) -> Option<String> {
225 let pstr = unsafe { ffi::iio_channel_get_id(self.chan) };
226 cstring_opt(pstr)
227 }
228
229 #[inline]
231 pub fn is_output(&self) -> bool {
232 unsafe { ffi::iio_channel_is_output(self.chan) }
233 }
234
235 #[inline]
237 pub fn is_input(&self) -> bool {
238 !self.is_output()
239 }
240
241 pub fn direction(&self) -> Direction {
243 match self.is_output() {
244 true => Direction::Output,
245 false => Direction::Input,
246 }
247 }
248
249 pub fn is_scan_element(&self) -> bool {
255 unsafe { ffi::iio_channel_is_scan_element(self.chan) }
256 }
257
258 pub fn index(&self) -> Result<usize> {
260 let ret = unsafe { ffi::iio_channel_get_index(self.chan) };
261 sys_result(ret as i32, ret as usize)
262 }
263
264 pub fn has_attrs(&self) -> bool {
266 unsafe { ffi::iio_channel_get_attrs_count(self.chan) > 0 }
267 }
268
269 pub fn num_attrs(&self) -> usize {
271 let n = unsafe { ffi::iio_channel_get_attrs_count(self.chan) };
272 n as usize
273 }
274
275 pub fn has_attr(&self, attr: &str) -> bool {
277 let attr = cstring_or_bail_false!(attr);
278 unsafe { !ffi::iio_channel_find_attr(self.chan, attr.as_ptr()).is_null() }
279 }
280
281 pub fn get_attr(&self, idx: usize) -> Result<String> {
283 let pstr = unsafe { ffi::iio_channel_get_attr(self.chan, idx as c_uint) };
284 cstring_opt(pstr).ok_or(Error::InvalidIndex)
285 }
286
287 pub fn find_attr(&self, name: &str) -> Option<String> {
289 let cname = cstring_or_bail!(name);
290 let pstr = unsafe { ffi::iio_channel_find_attr(self.chan, cname.as_ptr()) };
291 cstring_opt(pstr)
292 }
293
294 pub fn attr_read<T: FromAttribute>(&self, attr: &str) -> Result<T> {
298 let sval = self.attr_read_str(attr)?;
299 T::from_attr(&sval)
300 }
301
302 pub fn attr_read_str(&self, attr: &str) -> Result<String> {
306 let mut buf = vec![0 as c_char; ATTR_BUF_SIZE];
307 let attr = CString::new(attr)?;
308 let ret = unsafe {
309 ffi::iio_channel_attr_read(self.chan, attr.as_ptr(), buf.as_mut_ptr(), buf.len())
310 };
311 sys_result(ret as i32, ())?;
312 let s = unsafe {
313 CStr::from_ptr(buf.as_ptr())
314 .to_str()
315 .map_err(|_| Error::StringConversionError)?
316 };
317 Ok(s.into())
318 }
319
320 pub fn attr_read_bool(&self, attr: &str) -> Result<bool> {
323 let mut val: bool = false;
324 let attr = CString::new(attr)?;
325 let ret = unsafe { ffi::iio_channel_attr_read_bool(self.chan, attr.as_ptr(), &mut val) };
326 sys_result(ret, val)
327 }
328
329 pub fn attr_read_int(&self, attr: &str) -> Result<i64> {
333 let mut val: c_longlong = 0;
334 let attr = CString::new(attr)?;
335 let ret =
336 unsafe { ffi::iio_channel_attr_read_longlong(self.chan, attr.as_ptr(), &mut val) };
337 sys_result(ret, val as i64)
338 }
339
340 pub fn attr_read_float(&self, attr: &str) -> Result<f64> {
344 let mut val: f64 = 0.0;
345 let attr = CString::new(attr)?;
346 let ret = unsafe { ffi::iio_channel_attr_read_double(self.chan, attr.as_ptr(), &mut val) };
347 sys_result(ret, val)
348 }
349
350 unsafe extern "C" fn attr_read_all_cb(
353 _chan: *mut ffi::iio_channel,
354 attr: *const c_char,
355 val: *const c_char,
356 _len: usize,
357 pmap: *mut c_void,
358 ) -> c_int {
359 if attr.is_null() || val.is_null() || pmap.is_null() {
360 return -1;
361 }
362
363 let attr = CStr::from_ptr(attr).to_string_lossy().to_string();
364 let val = CStr::from_ptr(val).to_string_lossy().to_string();
366 let map: &mut HashMap<String, String> = &mut *pmap.cast();
367 map.insert(attr, val);
368 0
369 }
370
371 pub fn attr_read_all(&self) -> Result<HashMap<String, String>> {
375 let mut map = HashMap::new();
376 let pmap = (&mut map as *mut HashMap<_, _>).cast();
377 let ret = unsafe {
378 ffi::iio_channel_attr_read_all(self.chan, Some(Channel::attr_read_all_cb), pmap)
379 };
380 sys_result(ret, map)
381 }
382
383 pub fn attr_write<T: ToAttribute>(&self, attr: &str, val: T) -> Result<()> {
388 let sval = T::to_attr(&val)?;
389 self.attr_write_str(attr, &sval)
390 }
391
392 pub fn attr_write_str(&self, attr: &str, val: &str) -> Result<()> {
397 let attr = CString::new(attr)?;
398 let sval = CString::new(val)?;
399 let ret = unsafe { ffi::iio_channel_attr_write(self.chan, attr.as_ptr(), sval.as_ptr()) };
400 sys_result(ret as i32, ())
401 }
402
403 pub fn attr_write_bool(&self, attr: &str, val: bool) -> Result<()> {
408 let attr = CString::new(attr)?;
409 let ret = unsafe { ffi::iio_channel_attr_write_bool(self.chan, attr.as_ptr(), val) };
410 sys_result(ret, ())
411 }
412
413 pub fn attr_write_int(&self, attr: &str, val: i64) -> Result<()> {
418 let attr = CString::new(attr)?;
419 let ret = unsafe { ffi::iio_channel_attr_write_longlong(self.chan, attr.as_ptr(), val) };
420 sys_result(ret, ())
421 }
422
423 pub fn attr_write_float(&self, attr: &str, val: f64) -> Result<()> {
428 let attr = CString::new(attr)?;
429 let ret = unsafe { ffi::iio_channel_attr_write_double(self.chan, attr.as_ptr(), val) };
430 sys_result(ret, ())
431 }
432
433 pub fn attrs(&self) -> AttrIterator<'_> {
435 AttrIterator { chan: self, idx: 0 }
436 }
437
438 pub fn enable(&self) {
443 unsafe { ffi::iio_channel_enable(self.chan) };
444 }
445
446 pub fn disable(&self) {
448 unsafe { ffi::iio_channel_disable(self.chan) };
449 }
450
451 pub fn is_enabled(&self) -> bool {
453 unsafe { ffi::iio_channel_is_enabled(self.chan) }
454 }
455
456 pub fn data_format(&self) -> DataFormat {
460 unsafe {
461 let pfmt = ffi::iio_channel_get_data_format(self.chan);
462 DataFormat::new(*pfmt)
463 }
464 }
465
466 pub fn type_of(&self) -> Option<TypeId> {
471 let dfmt = self.data_format();
472 dfmt.type_of()
473 }
474
475 pub fn channel_type(&self) -> ChannelType {
477 unsafe {
479 let n = ffi::iio_channel_get_type(self.chan);
480 mem::transmute(n)
481 }
482 }
483
484 pub fn convert<T>(&self, val: T) -> T
490 where
491 T: Copy + 'static,
492 {
493 let mut retval = val;
494 if self.type_of() == Some(TypeId::of::<T>()) {
495 unsafe {
496 ffi::iio_channel_convert(
497 self.chan,
498 (&mut retval as *mut T).cast(),
499 (&val as *const T).cast(),
500 );
501 }
502 }
503 retval
504 }
505
506 pub fn convert_inverse<T>(&self, val: T) -> T
512 where
513 T: Copy + 'static,
514 {
515 let mut retval = val;
516 if self.type_of() == Some(TypeId::of::<T>()) {
517 unsafe {
518 ffi::iio_channel_convert_inverse(
519 self.chan,
520 (&mut retval as *mut T).cast(),
521 (&val as *const T).cast(),
522 );
523 }
524 }
525 retval
526 }
527
528 pub fn read<T>(&self, buf: &Buffer) -> Result<Vec<T>>
530 where
531 T: Default + Copy + 'static,
532 {
533 if self.type_of() != Some(TypeId::of::<T>()) {
534 return Err(Error::WrongDataType);
535 }
536
537 let n = buf.capacity();
538 let sz_item = size_of::<T>();
539 let sz_in = n * sz_item;
540
541 let mut v = vec![T::default(); n];
542 let sz = unsafe { ffi::iio_channel_read(self.chan, buf.buf, v.as_mut_ptr().cast(), sz_in) };
543
544 if sz > sz_in {
545 return Err(Error::BadReturnSize); }
547
548 if sz < sz_in {
549 v.truncate(sz / sz_item);
550 }
551 Ok(v)
552 }
553
554 pub fn read_raw<T>(&self, buf: &Buffer) -> Result<Vec<T>>
556 where
557 T: Default + Copy + 'static,
558 {
559 if self.type_of() != Some(TypeId::of::<T>()) {
560 return Err(Error::WrongDataType);
561 }
562
563 let n = buf.capacity();
564 let sz_item = size_of::<T>();
565 let sz_in = n * sz_item;
566
567 let mut v = vec![T::default(); n];
568 let sz =
569 unsafe { ffi::iio_channel_read_raw(self.chan, buf.buf, v.as_mut_ptr().cast(), sz_in) };
570
571 if sz > sz_in {
572 return Err(Error::BadReturnSize); }
574
575 if sz < sz_in {
576 v.truncate(sz / sz_item);
577 }
578 Ok(v)
579 }
580
581 pub fn write<T>(&self, buf: &Buffer, data: &[T]) -> Result<usize>
584 where
585 T: Default + Copy + 'static,
586 {
587 if self.type_of() != Some(TypeId::of::<T>()) {
588 return Err(Error::WrongDataType);
589 }
590
591 let sz_item = size_of::<T>();
592 let sz_in = size_of_val(data);
593
594 let sz = unsafe { ffi::iio_channel_write(self.chan, buf.buf, data.as_ptr().cast(), sz_in) };
595
596 Ok(sz / sz_item)
597 }
598
599 pub fn write_raw<T>(&self, buf: &Buffer, data: &[T]) -> Result<usize>
602 where
603 T: Default + Copy + 'static,
604 {
605 if self.type_of() != Some(TypeId::of::<T>()) {
606 return Err(Error::WrongDataType);
607 }
608
609 let sz_item = size_of::<T>();
610 let sz_in = size_of_val(data);
611
612 let sz = unsafe { ffi::iio_channel_write(self.chan, buf.buf, data.as_ptr().cast(), sz_in) };
613
614 Ok(sz / sz_item)
615 }
616}
617
618impl PartialEq for Channel {
619 fn eq(&self, other: &Self) -> bool {
622 self.chan == other.chan
623 }
624}
625
626#[derive(Debug)]
628pub struct AttrIterator<'a> {
629 chan: &'a Channel,
631 idx: usize,
633}
634
635impl Iterator for AttrIterator<'_> {
636 type Item = String;
637
638 fn next(&mut self) -> Option<Self::Item> {
640 match self.chan.get_attr(self.idx) {
641 Ok(name) => {
642 self.idx += 1;
643 Some(name)
644 }
645 Err(_) => None,
646 }
647 }
648}
649
650#[cfg(test)]
658mod tests {
659 use super::*;
660
661 const DEV_ID: &str = "dummydev";
662
663 #[test]
665 fn default_context() {
666 let ctx = Context::new().unwrap();
667 let dev = ctx.find_device(DEV_ID).unwrap();
668
669 let idx_chan = dev.get_channel(0).unwrap();
670 let id = idx_chan.id().unwrap();
671 let dir = idx_chan.direction();
672
673 let id_chan = dev.find_channel(&id, dir).unwrap();
674 assert_eq!(id_chan, idx_chan);
675 }
676}