gpiocdev_uapi/v2.rs
1// SPDX-FileCopyrightText: 2021 Kent Gibson <warthog618@gmail.com>
2//
3// SPDX-License-Identifier: Apache-2.0 OR MIT
4
5use bitflags::bitflags;
6use std::fmt;
7use std::fs::File;
8use std::os::unix::prelude::{AsRawFd, FromRawFd};
9
10// common to ABI v1 and v2.
11pub use super::common::*;
12
13#[repr(u8)]
14enum Ioctl {
15 GetLineInfo = 5,
16 WatchLineInfo = 6,
17 GetLine = 7,
18 SetLineConfig = 0xD,
19 GetLineValues = 0xE,
20 SetLineValues = 0xF,
21}
22
23bitflags! {
24 /// Flags indicating the configuration of a line.
25 #[derive(Clone, Copy, Debug, Default, Eq, Hash, PartialEq)]
26 pub struct LineFlags: u64 {
27 /// The line is in use and is not available for request.
28 const USED = 1;
29
30 /// The line active state corresponds to a physical low.
31 const ACTIVE_LOW = 2;
32
33 /// The line is an input.
34 const INPUT = 4;
35
36 /// The line is an output.
37 const OUTPUT = 8;
38
39 /// The line detects rising (*inactive* to *active*) edges.
40 const EDGE_RISING = 16;
41
42 /// The line detects falling (*active* to *inactive*) edges.
43 const EDGE_FALLING = 32;
44
45 /// The line is an open drain output.
46 const OPEN_DRAIN = 64;
47
48 /// The line is an open source output.
49 const OPEN_SOURCE = 128;
50
51 /// The line has pull-up bias enabled.
52 const BIAS_PULL_UP = 256;
53
54 /// The line has pull-down bias enabled.
55 const BIAS_PULL_DOWN = 512;
56
57 /// The line has bias disabled.
58 const BIAS_DISABLED = 1024;
59
60 /// The line events contain **CLOCK_REALTIME** timestamps.
61 const EVENT_CLOCK_REALTIME = 2048;
62
63 /// The line events contain **HTE** timestamps.
64 const EVENT_CLOCK_HTE = 4096;
65 }
66}
67
68/// Values of GPIO lines.
69///
70/// Bits in the bitmaps correspond to the index into [`LineRequest.offsets`].
71/// The first requested line, `offsets[0]`, is bit 0.
72///
73/// [`LineRequest.offsets`]: struct@LineRequest
74#[repr(C)]
75#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
76pub struct LineValues {
77 /// The value of the lines, set to 1 for *active* and 0 for *inactive*.
78 pub bits: u64,
79
80 /// The lines in a request to access, set to 1 to access and 0 to ignore.
81 pub mask: u64,
82}
83
84impl LineValues {
85 /// Create values from a slice.
86 ///
87 /// The values are in the same order as [`LineRequest.offsets`].
88 ///
89 /// [`LineRequest.offsets`]: struct@LineRequest
90 pub fn from_slice(s: &[bool]) -> Self {
91 let mut lv: LineValues = Default::default();
92 for (idx, val) in s.iter().enumerate() {
93 lv.set(idx, *val);
94 }
95 lv
96 }
97
98 /// Copy values from an iterable list - in order of requested offsets.
99 pub fn copy_from_slice(&mut self, s: &[bool]) {
100 let extent = std::cmp::min(64usize, s.len());
101 for (i, v) in s.iter().enumerate().take(extent) {
102 self.set(i, *v);
103 }
104 }
105
106 /// Return the value of a line.
107 ///
108 /// Note that the [`LineValues`] need to be populated via a call to [`get_line_values`]
109 /// to get values from the underlying hardware.
110 ///
111 /// Fails if the line of interest is not set in the mask.
112 ///
113 /// * `idx` - The index into the [`LineRequest.offsets`] for the line of interest.
114 ///
115 /// [`LineRequest.offsets`]: struct@LineRequest
116 #[inline]
117 pub fn get(&self, idx: usize) -> Option<bool> {
118 debug_assert!(idx < 64);
119 let mask = 0x01 << idx;
120 if self.mask & mask == 0 {
121 return None;
122 }
123 Some(self.bits & mask != 0)
124 }
125
126 /// Set the value of a line.
127 ///
128 /// Note that the values are not applied to hardware until passed to [`set_line_values`].
129 ///
130 /// * `idx` - The index into the [`LineRequest.offsets`] for the line of interest.
131 /// * `active` - The logical state of the line to be set.
132 ///
133 /// [`LineRequest.offsets`]: struct@LineRequest
134 #[inline]
135 pub fn set(&mut self, idx: usize, active: bool) {
136 debug_assert!(idx < 64);
137 let mask = 0x01 << idx;
138 self.mask |= mask;
139 if active {
140 self.bits |= mask;
141 } else {
142 self.bits &= !mask;
143 }
144 }
145
146 /// Clear the mask bit for a line.
147 ///
148 /// The line will be ignored in subsequent calls to [`get_line_values`] and
149 /// [`set_line_values`].
150 ///
151 /// * `idx` - The index into the [`LineRequest.offsets`] for the line of interest.
152 ///
153 /// [`LineRequest.offsets`]: struct@LineRequest
154 #[inline]
155 pub fn unset_mask(&mut self, idx: usize) {
156 debug_assert!(idx < 64);
157 let mask = 0x01 << idx;
158 self.mask &= !mask;
159 }
160}
161
162/// Read values of requested lines.
163///
164/// * `lf` - The request file returned by [`get_line`].
165/// * `lv` - The line values to be populated.
166#[inline]
167pub fn get_line_values(lf: &File, lv: &mut LineValues) -> Result<()> {
168 // SAFETY: returned struct contains raw byte arrays and bitfields that are safe to decode.
169 match unsafe { libc::ioctl(lf.as_raw_fd(), iorw!(Ioctl::GetLineValues, LineValues), lv) } {
170 0 => Ok(()),
171 _ => Err(Error::from_errno()),
172 }
173}
174
175/// Set values of requested output lines.
176///
177/// Note that requesting a set on an input line is an error.
178///
179/// * `lf` - The request file returned by [`get_line`].
180/// * `lv` - The line values to be set.
181#[inline]
182pub fn set_line_values(lf: &File, lv: &LineValues) -> Result<()> {
183 // SAFETY: lv is not modified.
184 match unsafe { libc::ioctl(lf.as_raw_fd(), iorw!(Ioctl::SetLineValues, LineValues), lv) } {
185 0 => Ok(()),
186 _ => Err(Error::from_errno()),
187 }
188}
189
190/// An identifier for which field of the [`LineAttributeValueUnion`] is in use.
191#[repr(u32)]
192#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
193pub enum LineAttributeKind {
194 /// The attribute is *inactive* - no fields are in use.
195 #[default]
196 Unused = 0,
197
198 /// The flags field is in use.
199 Flags = 1,
200
201 /// The values field is in use.
202 Values = 2,
203
204 /// The debounce_period_us field is in use.
205 Debounce = 3,
206}
207
208impl TryFrom<u32> for LineAttributeKind {
209 type Error = ();
210
211 fn try_from(v: u32) -> std::result::Result<Self, Self::Error> {
212 use LineAttributeKind::*;
213 Ok(match v {
214 0 => Unused,
215 1 => Flags,
216 2 => Values,
217 3 => Debounce,
218 _ => return Err(()),
219 })
220 }
221}
222
223/// A configurable attribute of a line.
224#[repr(C)]
225#[derive(Clone, Copy, Default)]
226pub struct LineAttribute {
227 /// The type of attribute stored in `value` (LineAttributeKind).
228 pub kind: u32,
229
230 /// Reserved for future use and must be zero filled.
231 #[doc(hidden)]
232 pub padding: Padding<1>,
233
234 /// The attribute value.
235 pub value: LineAttributeValueUnion,
236}
237
238impl LineAttribute {
239 /// Set the attribute as debounce period.
240 pub fn set_debounce_period_us(&mut self, debounce_period_us: u32) {
241 self.kind = LineAttributeKind::Debounce as u32;
242 self.value.debounce_period_us = debounce_period_us;
243 }
244
245 /// Set the attribute as flags.
246 pub fn set_flags(&mut self, flags: LineFlags) {
247 self.kind = LineAttributeKind::Flags as u32;
248 self.value.flags = flags;
249 }
250
251 /// Set the attribute as output values.
252 pub fn set_values(&mut self, values: u64) {
253 self.kind = LineAttributeKind::Values as u32;
254 self.value.values = values;
255 }
256
257 /// Get the contained value.
258 ///
259 /// Converts the unsafe kind/union into a safe enum.
260 pub fn to_value(&self) -> Option<LineAttributeValue> {
261 // SAFETY: checks kind before accessing union
262 unsafe {
263 Some(match self.kind {
264 1 => LineAttributeValue::Flags(self.value.flags),
265 2 => LineAttributeValue::Values(self.value.values),
266 3 => LineAttributeValue::DebouncePeriod(self.value.debounce_period_us),
267 _ => return None,
268 })
269 }
270 }
271}
272
273impl fmt::Debug for LineAttribute {
274 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
275 // SAFETY: checks kind before accessing union
276 unsafe {
277 match self.kind {
278 0 => write!(f, "unused"),
279 1 => write!(f, "flags: {:?}", self.value.flags),
280 2 => {
281 write!(f, "values: {:08x}", self.value.values)
282 }
283 3 => {
284 write!(f, "debounce_period_us: {}", self.value.debounce_period_us)
285 }
286 _ => write!(f, "unknown attr kind {}", self.kind),
287 }
288 }
289 }
290}
291
292impl PartialEq for LineAttribute {
293 fn eq(&self, other: &Self) -> bool {
294 if self.kind != other.kind {
295 return false;
296 }
297 // SAFETY: checks kind before accessing union
298 unsafe {
299 match self.kind {
300 0 => true,
301 1 => self.value.flags == other.value.flags,
302 2 => self.value.values == other.value.values,
303 3 => self.value.debounce_period_us == other.value.debounce_period_us,
304 _ => false,
305 }
306 }
307 }
308}
309impl Eq for LineAttribute {}
310
311/// The value of a particular line attribute.
312#[repr(C)]
313#[derive(Clone, Copy)]
314pub union LineAttributeValueUnion {
315 /// The line configuration flags.
316 pub flags: LineFlags,
317
318 /// The values to which the lines will be set, with each bit number
319 /// corresponding to the index into [`LineRequest.offsets`].
320 ///
321 /// [`LineRequest.offsets`]: struct@LineRequest
322 pub values: u64,
323
324 /// The debounce period, in microseconds.
325 pub debounce_period_us: u32,
326}
327
328impl Default for LineAttributeValueUnion {
329 fn default() -> Self {
330 LineAttributeValueUnion {
331 flags: Default::default(),
332 }
333 }
334}
335
336/// The attribute value contained within a [`LineAttribute`].
337#[derive(Clone, Copy, Debug, Eq, PartialEq)]
338pub enum LineAttributeValue {
339 /// The debounce period in microseconds.
340 DebouncePeriod(u32),
341
342 /// The configuration flags.
343 Flags(LineFlags),
344
345 /// The line values.
346 Values(u64),
347}
348
349/// A configuration attribute associated with one or more of the requested lines.
350#[repr(C)]
351#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
352pub struct LineConfigAttribute {
353 /// The configurable attribute.
354 pub attr: LineAttribute,
355
356 /// The lines to which the attribute applies, with each bit number corresponding
357 /// to the index into [`LineRequest.offsets`].
358 ///
359 /// [`LineRequest.offsets`]: struct@LineRequest
360 pub mask: u64,
361}
362
363/// The set of additional configuration attributes for a line request.
364///
365/// [`LineConfig.num_attrs`] specifies the number of entries in use.
366///
367/// Any attribute should only be associated with a particular line once.
368/// If an attribute is associated with a line multiple times then the
369/// first occurrence (i.e. lowest index) has precedence.
370///
371/// [`LineConfig.num_attrs`]: struct@LineConfig
372#[repr(C)]
373#[derive(Clone, Debug, Default)]
374pub struct LineConfigAttributes(pub [LineConfigAttribute; NUM_ATTRS_MAX]);
375
376/// Configuration for a set of requested lines.
377#[repr(C)]
378#[derive(Clone, Debug, Default)]
379pub struct LineConfig {
380 /// Flags for the GPIO lines. This is the default for all requested lines but
381 /// may be overridden for particular lines using `attrs`.
382 pub flags: LineFlags,
383
384 /// The number of attributes active in `attrs`.
385 pub num_attrs: u32,
386
387 /// Reserved for future use and must be zero filled.
388 #[doc(hidden)]
389 pub padding: Padding<5>,
390
391 /// The configuration attributes associated with the requested lines.
392 ///
393 /// The number of active attributes in the array is specified by `num_attrs`.
394 pub attrs: LineConfigAttributes,
395}
396
397impl LineConfig {
398 /// The nth attribute in the attrs
399 #[inline]
400 pub fn attr(&self, idx: usize) -> &LineConfigAttribute {
401 &self.attrs.0[idx]
402 }
403
404 /// The nth attribute in the attrs
405 #[inline]
406 pub fn attr_mut(&mut self, idx: usize) -> &mut LineConfigAttribute {
407 &mut self.attrs.0[idx]
408 }
409
410 /// Add a debounce attribute to the config.
411 pub fn add_debounce(&mut self, period: u32, mask: u64) {
412 let lca = &mut self.attrs.0[self.num_attrs as usize];
413 lca.mask = mask;
414 lca.attr.set_debounce_period_us(period);
415 self.num_attrs += 1;
416 }
417
418 /// Add a flags attribute to the config.
419 pub fn add_flags(&mut self, lf: LineFlags, mask: u64) {
420 let lca = &mut self.attrs.0[self.num_attrs as usize];
421 lca.mask = mask;
422 lca.attr.set_flags(lf);
423 self.num_attrs += 1;
424 }
425
426 /// Add a line values attribute to the config.
427 pub fn add_values(&mut self, values: &LineValues) {
428 let lca = &mut self.attrs.0[self.num_attrs as usize];
429 lca.mask = values.mask;
430 lca.attr.set_values(values.bits);
431 self.num_attrs += 1;
432 }
433}
434
435/// Update the configuration of an existing line request.
436///
437/// * `lf` - The request file returned by [`get_line`].
438/// * `lc` - The configuration to be applied.
439#[inline]
440pub fn set_line_config(lf: &File, lc: LineConfig) -> Result<()> {
441 // SAFETY: lc is consumed.
442 unsafe {
443 match libc::ioctl(lf.as_raw_fd(), iorw!(Ioctl::SetLineConfig, LineConfig), &lc) {
444 0 => Ok(()),
445 _ => Err(Error::from_errno()),
446 }
447 }
448}
449
450/// Information about a request for GPIO lines.
451#[repr(C)]
452#[derive(Clone, Debug, Default)]
453pub struct LineRequest {
454 /// An array of requested lines, identified by offset on the associated GPIO chip.
455 pub offsets: Offsets,
456
457 /// The requested consumer label for the selected GPIO lines such as
458 /// "*my-bitbanged-relay*".
459 pub consumer: Name,
460
461 /// The requested configuration for the lines.
462 pub config: LineConfig,
463
464 /// The number of lines requested in this request.
465 /// i.e. the number of valid elements in `offsets`.
466 ///
467 /// Set to 1 to request a single line.
468 pub num_lines: u32,
469
470 /// A suggested minimum number of line events that the kernel should buffer.
471 ///
472 /// This is only relevant if edge detection is enabled in the configuration.
473 ///
474 /// Note that this is only a suggested value and the kernel may allocate a
475 /// larger buffer or cap the size of the buffer.
476 /// If this field is zero then the buffer size defaults to a minimum of `num_lines*16`.
477 pub event_buffer_size: u32,
478
479 /// Reserved for future use and must be zero filled.
480 #[doc(hidden)]
481 pub padding: Padding<5>,
482
483 /// This field is only present for the underlying ioctl call and is only used internally.
484 #[doc(hidden)]
485 pub fd: i32,
486}
487
488/// Request a line or set of lines for exclusive access.
489///
490/// * `cf` - The open gpiochip device file.
491/// * `lr` - The line request.
492#[inline]
493pub fn get_line(cf: &File, mut lr: LineRequest) -> Result<File> {
494 // SAFETY: lr is consumed and the returned file is drawn from the returned fd.
495 unsafe {
496 match libc::ioctl(cf.as_raw_fd(), iorw!(Ioctl::GetLine, LineRequest), &mut lr) {
497 0 => Ok(File::from_raw_fd(lr.fd)),
498 _ => Err(Error::from_errno()),
499 }
500 }
501}
502
503/// The set of potential configuration attributes for a line.
504///
505/// [`LineInfo.num_attrs`] specifies the number of entries in use.
506///
507/// [`LineInfo.num_attrs`]: struct@LineInfo
508#[repr(C)]
509#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
510pub struct LineAttributes(pub [LineAttribute; NUM_ATTRS_MAX]);
511
512/// The capacity of [`LineAttributes`] and [`LineConfigAttributes`] arrays.
513pub const NUM_ATTRS_MAX: usize = 10;
514
515/// Information about a certain GPIO line.
516#[repr(C)]
517#[derive(Clone, Debug, Default, Eq, PartialEq)]
518pub struct LineInfo {
519 /// The name of this GPIO line, such as the output pin of the line on the chip,
520 /// a rail or a pin header name on a board, as specified by the GPIO chip.
521 ///
522 /// May be empty.
523 pub name: Name,
524
525 /// A functional name for the consumer of this GPIO line as set by whatever is using it.
526 ///
527 /// Will be empty if there is no current user.
528 /// May also be empty if the consumer requests doesn't set this up.
529 pub consumer: Name,
530
531 /// The local offset on this GPIO chip.
532 pub offset: Offset,
533
534 /// The number of attributes active in `attrs`.
535 pub num_attrs: u32,
536
537 /// The configuration flags for this GPIO line.
538 pub flags: LineFlags,
539
540 /// Additional configuration attributes associated with the line.
541 ///
542 /// The number of active attributes in the array is specified by `num_attrs`.
543 pub attrs: LineAttributes,
544
545 /// Reserved for future use.
546 #[doc(hidden)]
547 pub padding: Padding<4>,
548}
549
550impl LineInfo {
551 /// The nth attribute in the attrs
552 #[inline]
553 pub fn attr(&self, idx: usize) -> &LineAttribute {
554 &self.attrs.0[idx]
555 }
556 /// The nth attribute in the attrs
557 #[inline]
558 pub fn attr_mut(&mut self, idx: usize) -> &mut LineAttribute {
559 &mut self.attrs.0[idx]
560 }
561}
562
563/// Get the publicly available information for a line.
564///
565/// This does not include the line value.
566/// The line must be requested to access the value.
567///
568/// * `cf` - The open gpiochip device file.
569/// * `offset` - The offset of the line.
570#[inline]
571pub fn get_line_info(cf: &File, offset: Offset) -> Result<LineInfo> {
572 let mut li = LineInfo {
573 offset,
574 ..Default::default()
575 };
576 // SAFETY: returned struct contains raw byte arrays and bitfields that are safe to decode.
577 match unsafe { libc::ioctl(cf.as_raw_fd(), iorw!(Ioctl::GetLineInfo, LineInfo), &mut li) } {
578 0 => Ok(li),
579 _ => Err(Error::from_errno()),
580 }
581}
582
583/// Add a watch on changes to the [`LineInfo`] for a line.
584///
585/// Returns the current state of that information.
586///
587/// This does not include the line value.
588/// The line must be requested to access the value.
589///
590/// * `cf` - The open gpiochip device file.
591/// * `offset` - The offset of the line to watch.
592#[inline]
593pub fn watch_line_info(cf: &File, offset: Offset) -> Result<LineInfo> {
594 let mut li = LineInfo {
595 offset,
596 ..Default::default()
597 };
598 // SAFETY: returned struct contains raw byte arrays and bitfields that are safe to decode.
599 match unsafe {
600 libc::ioctl(
601 cf.as_raw_fd(),
602 iorw!(Ioctl::WatchLineInfo, LineInfo),
603 &mut li,
604 )
605 } {
606 0 => Ok(li),
607 _ => Err(Error::from_errno()),
608 }
609}
610
611/// An event indicating a change to the info for a line.
612#[repr(C)]
613#[derive(Clone, Debug, Eq, PartialEq)]
614pub struct LineInfoChangeEvent {
615 /// The new line info.
616 pub info: LineInfo,
617
618 /// The best estimate of time of event occurrence, in nanoseconds.
619 pub timestamp_ns: u64,
620
621 /// The trigger for the change (LineInfoChangeKind)
622 pub kind: u32,
623
624 /// Reserved for future use.
625 #[doc(hidden)]
626 pub padding: Padding<5>,
627}
628
629impl LineInfoChangeEvent {
630 /// Read an info change event from a buffer.
631 ///
632 /// The buffer is assumed to have been populated by a read of the chip File,
633 /// so the content is initialised.
634 pub fn from_slice(d: &[u64]) -> Result<&LineInfoChangeEvent> {
635 debug_assert!(std::mem::size_of::<LineInfoChangeEvent>() % 8 == 0);
636 let len = d.len() * 8;
637 if len < std::mem::size_of::<LineInfoChangeEvent>() {
638 return Err(Error::from(UnderReadError::new(
639 "LineInfoChangeEvent",
640 std::mem::size_of::<LineInfoChangeEvent>(),
641 len,
642 )));
643 }
644 // SAFETY: returned struct contains raw byte arrays and bitfields that are safe to decode.
645 let ice = unsafe { &*(d as *const [u64] as *const LineInfoChangeEvent) };
646 Ok(ice)
647 }
648
649 /// The number of u64 words required to store a LineInfoChangeEvent.
650 pub fn u64_size() -> usize {
651 std::mem::size_of::<LineInfoChangeEvent>() / 8
652 }
653}
654
655/// Information about an edge event on a requested line.
656#[repr(C)]
657#[derive(Clone, Debug, Eq, PartialEq)]
658pub struct LineEdgeEvent {
659 /// The best estimate of time of event occurrence, in nanoseconds.
660 ///
661 /// By default the timestamp is read from **CLOCK_MONOTONIC** and is
662 /// intended to allow the accurate measurement of the time between events.
663 /// It does not provide the wall-clock time.
664 ///
665 /// If the [`LineFlags::EVENT_CLOCK_REALTIME`] flag is set then the
666 /// timestamp is read from **CLOCK_REALTIME**.
667 pub timestamp_ns: u64,
668
669 /// The event trigger identifier (LineEdgeEventKind)
670 pub kind: u32,
671
672 /// The offset of the line that triggered the event.
673 pub offset: Offset,
674
675 /// The sequence number for this event in the sequence of events for all
676 /// the lines in this line request.
677 pub seqno: u32,
678
679 /// The sequence number for this event in the sequence of events on this
680 /// particular line.
681 pub line_seqno: u32,
682
683 /// Reserved for future use.
684 #[doc(hidden)]
685 pub padding: Padding<6>,
686}
687
688impl LineEdgeEvent {
689 /// Read an edge event from a buffer.
690 ///
691 /// The buffer is assumed to have been populated by a read of the line request File,
692 /// so the content is initialised.
693 #[inline]
694 pub fn from_slice(d: &[u64]) -> Result<&LineEdgeEvent> {
695 debug_assert!(std::mem::size_of::<LineEdgeEvent>() % 8 == 0);
696 let len = d.len() * 8;
697 if len < std::mem::size_of::<LineEdgeEvent>() {
698 return Err(Error::from(UnderReadError::new(
699 "LineEdgeEvent",
700 std::mem::size_of::<LineEdgeEvent>(),
701 len,
702 )));
703 }
704 // SAFETY: returned struct contains raw byte arrays and bitfields that are safe to decode.
705 let le = unsafe { &*(d as *const [u64] as *const LineEdgeEvent) };
706 Ok(le)
707 }
708
709 /// The number of u64 words required to store a LineEdgeEvent.
710 pub fn u64_size() -> usize {
711 std::mem::size_of::<LineEdgeEvent>() / 8
712 }
713}
714
715#[cfg(test)]
716mod tests {
717 use super::*;
718
719 mod line_attribute {
720 use super::LineAttribute;
721
722 #[test]
723 fn size() {
724 assert_eq!(
725 std::mem::size_of::<LineAttribute>(),
726 16usize,
727 concat!("Size of: ", stringify!(LineAttribute))
728 );
729 }
730 }
731
732 mod line_attribute_value_union {
733 use super::LineAttributeValueUnion;
734
735 #[test]
736 fn size() {
737 assert_eq!(
738 std::mem::size_of::<LineAttributeValueUnion>(),
739 8usize,
740 concat!("Size of: ", stringify!(LineAttributeValueUnion))
741 );
742 }
743 }
744
745 mod line_config_attribute {
746 use super::LineConfigAttribute;
747
748 #[test]
749 fn line_config_attribute() {
750 assert_eq!(
751 std::mem::size_of::<LineConfigAttribute>(),
752 24usize,
753 concat!("Size of: ", stringify!(LineConfigAttribute))
754 );
755 }
756 }
757
758 mod line_config {
759 use super::LineConfig;
760
761 #[test]
762 fn line_config() {
763 assert_eq!(
764 std::mem::size_of::<LineConfig>(),
765 272usize,
766 concat!("Size of: ", stringify!(LineConfig))
767 );
768 }
769 }
770
771 mod line_request {
772 use super::LineRequest;
773
774 #[test]
775 fn line_request() {
776 assert_eq!(
777 std::mem::size_of::<LineRequest>(),
778 592usize,
779 concat!("Size of: ", stringify!(LineRequest))
780 );
781 }
782 }
783
784 mod line_values {
785 use super::LineValues;
786
787 #[test]
788 fn get() {
789 let mut a = LineValues::default();
790 for idx in [0, 2] {
791 let mask = 0x1 << idx;
792 assert_eq!(a.bits & mask, 0, "idx: {idx}");
793 assert!(a.get(idx).is_none(), "idx: {idx}");
794
795 a.mask |= mask;
796 assert!(!a.get(idx).unwrap(), "idx: {idx}");
797
798 a.bits |= mask;
799 assert!(a.get(idx).unwrap(), "idx: {idx}");
800 }
801 }
802
803 #[test]
804 fn set() {
805 let mut a = LineValues::default();
806 for idx in [0, 2] {
807 let mask = 0x1 << idx;
808 a.set(idx, false);
809 assert_eq!(a.mask & mask, mask, "idx: {idx}");
810 assert_eq!(a.bits & mask, 0, "idx: {idx}");
811
812 a.set(idx, true);
813 assert_eq!(a.mask & mask, mask, "idx: {idx}");
814 assert_eq!(a.bits & mask, mask, "idx: {idx}");
815 }
816 }
817
818 #[test]
819 fn unset_mask() {
820 let mut a = LineValues {
821 mask: 0x7f,
822 ..Default::default()
823 };
824 assert_eq!(a.mask & 0x01, 0x01);
825 a.unset_mask(0);
826 assert_eq!(a.mask & 0x01, 0);
827
828 assert_eq!(a.mask & 0x08, 0x08);
829 a.unset_mask(3);
830 assert_eq!(a.mask & 0x08, 0);
831
832 assert_eq!(a.mask & 0x20, 0x20);
833 a.unset_mask(5);
834 assert_eq!(a.mask & 0x20, 0);
835 }
836
837 #[test]
838 fn size() {
839 assert_eq!(
840 std::mem::size_of::<LineValues>(),
841 16usize,
842 concat!("Size of: ", stringify!(LineValues))
843 );
844 }
845 }
846
847 mod line_info {
848 use super::LineInfo;
849
850 #[test]
851 fn size() {
852 assert_eq!(
853 std::mem::size_of::<LineInfo>(),
854 256usize,
855 concat!("Size of: ", stringify!(LineInfo))
856 );
857 }
858 }
859
860 mod line_info_changed {
861 use super::LineInfoChangeEvent;
862
863 #[test]
864 fn size() {
865 assert_eq!(
866 std::mem::size_of::<LineInfoChangeEvent>(),
867 288usize,
868 concat!("Size of: ", stringify!(LineInfoChangeEvent))
869 );
870 }
871 }
872
873 mod line_event {
874 use super::LineEdgeEvent;
875
876 #[test]
877 fn size() {
878 assert_eq!(
879 std::mem::size_of::<LineEdgeEvent>(),
880 48usize,
881 concat!("Size of: ", stringify!(LineEdgeEvent))
882 );
883 }
884 }
885}