1use crate::ValueError;
2
3#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
4#[repr(u8)]
5pub enum Channel {
6 Ch1 = 0,
7 Ch2,
8 Ch3,
9 Ch4,
10 Ch5,
11 Ch6,
12 Ch7,
13 Ch8,
14 Ch9,
15 Ch10,
16 Ch11,
17 Ch12,
18 Ch13,
19 Ch14,
20 Ch15,
21 Ch16,
22}
23
24impl Channel {
25 pub const ALL: [Channel; 16] = [
26 Channel::Ch1,
27 Channel::Ch2,
28 Channel::Ch3,
29 Channel::Ch4,
30 Channel::Ch5,
31 Channel::Ch6,
32 Channel::Ch7,
33 Channel::Ch8,
34 Channel::Ch9,
35 Channel::Ch10,
36 Channel::Ch11,
37 Channel::Ch12,
38 Channel::Ch13,
39 Channel::Ch14,
40 Channel::Ch15,
41 Channel::Ch16,
42 ];
43
44 pub const fn index(self) -> u8 {
45 self as u8
46 }
47
48 pub const fn number(self) -> u8 {
49 self as u8 + 1
50 }
51
52 pub fn from_index(index: u8) -> Result<Self, ValueError> {
53 Self::ALL
54 .get(index as usize)
55 .copied()
56 .ok_or(ValueError::ChannelIndex(index))
57 }
58
59 pub fn from_number(number: u8) -> Result<Self, ValueError> {
60 number
61 .checked_sub(1)
62 .and_then(|index| Self::from_index(index).ok())
63 .ok_or(ValueError::ChannelNumber(number))
64 }
65}
66
67pub(crate) fn channel_from_nibble(status: u8) -> Channel {
68 Channel::from_index(status & 0x0F).expect("status nibble is always 0..=15")
69}
70
71impl std::fmt::Display for Channel {
72 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
73 write!(f, "{}", self.number())
74 }
75}
76
77#[cfg(test)]
78mod tests {
79 use super::*;
80
81 #[test]
82 fn channel_from_number_roundtrips() {
83 for ch in Channel::ALL {
84 assert_eq!(Channel::from_number(ch.number()), Ok(ch));
85 }
86 assert_eq!(Channel::from_number(1), Ok(Channel::Ch1));
87 assert_eq!(Channel::from_number(16), Ok(Channel::Ch16));
88 }
89
90 #[test]
91 fn channel_from_number_rejects_out_of_range() {
92 assert_eq!(Channel::from_number(0), Err(ValueError::ChannelNumber(0)));
93 assert_eq!(Channel::from_number(17), Err(ValueError::ChannelNumber(17)));
94 assert_eq!(Channel::from_index(16), Err(ValueError::ChannelIndex(16)));
95 }
96}