1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
use crate::{
    impl_default, impl_message_from_buf, impl_response_ops, impl_var_message_ops, len, std::fmt,
    ChannelValue, ChannelValueList, Error, MessageOps, MessageType, ResponseOps, Result, Vec,
};

pub mod index {
    pub const NUM_CHANNELS: usize = 4;
    pub const CHANNEL_VALUES: usize = NUM_CHANNELS + 1;
}

/// ChannelValueData - Response (0x0A)
///
/// Represents a response to an [ChannelValueDataCommand](crate::ChannelValueDataCommand) message.
#[repr(C)]
#[derive(Clone, Copy, Debug, PartialEq)]
pub struct ChannelValueDataResponse {
    buf: [u8; len::CHANNEL_VALUE_DATA_RESPONSE],
}

impl ChannelValueDataResponse {
    /// Creates a new [ChannelValueDataResponse] message.
    pub fn new() -> Self {
        let mut msg = Self {
            buf: [0u8; len::CHANNEL_VALUE_DATA_RESPONSE],
        };

        msg.init();

        msg
    }

    /// Gets the number of channels.
    pub fn num_channels(&self) -> usize {
        self.buf[index::NUM_CHANNELS].into()
    }

    /// Gets the [ChannelValue] for each channel.
    pub fn channel_values(&self) -> Result<ChannelValueList> {
        self.is_valid()?;

        let channel_values_end = self.channel_values_end();

        Ok(self.buf[index::CHANNEL_VALUES..channel_values_end]
            .iter()
            .map(|&v| ChannelValue::from([v]))
            .collect::<Vec<ChannelValue>>()
            .into())
    }

    fn channel_values_end(&self) -> usize {
        index::CHANNEL_VALUES + self.num_channels()
    }

    /// Gets whether the message contains a valid length and number of channels.
    ///
    /// Because the buffer has variable length, and fields that are multiples of the number of
    /// channels, there are combinations that result in overflowing the total buffer length.
    ///
    /// For example, LEN=255 & NUM_FIELDS=255 obviously overflows the buffer since the first
    /// CHANNEL_VALUES field is NUM_FIELDS*LEN_CHANNEL_VALUE(1) = 255.
    pub fn is_valid(&self) -> Result<()> {
        use crate::message::index as msg_index;

        let end_range = len::HEADER + self.data_len();
        let values_end = self.channel_values_end();

        if (msg_index::DATA..=end_range).contains(&values_end) {
            Ok(())
        } else {
            Err(Error::InvalidDataLength((values_end, end_range)))
        }
    }
}

impl_default!(ChannelValueDataResponse);
impl_message_from_buf!(ChannelValueDataResponse);
impl_var_message_ops!(ChannelValueDataResponse, MessageType::ChannelValueData);
impl_response_ops!(ChannelValueDataResponse);

impl fmt::Display for ChannelValueDataResponse {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self.is_valid() {
            Ok(_) => {
                let stx = self.stx();
                let seqid = self.sequence_id();
                let len = self.data_len();
                let status = self.response_status();
                let num_channels = self.num_channels();
                let channel_values = self.channel_values().unwrap();
                let crc = self.checksum();

                write!(f, "STX: 0x{stx:02x} | SEQID: {seqid} | LEN: 0x{len:02x} | Response status: {status} | Number of channels: {num_channels} | Channel values: {channel_values} | CRC-16: 0x{crc:04x}")
            }
            Err(err) => {
                write!(f, "Invalid ChannelValueDataResponse message: {err}")
            }
        }
    }
}

#[cfg(test)]
mod tests {
    use crate::Result;

    use super::*;

    #[test]
    #[rustfmt::skip]
    fn test_unit_data_response() -> Result<()> {
        use crate::{STX, ResponseStatus};

        let channel_value_data_response_bytes = [
            // STX(0x7f)
            STX,
            // SEQID
            0x80,
            // LEN
            0x06, 
            // OK response
            0xf0,
            // Number of channels
            0x04,
            // Channel values
            0x05, 0x0a, 0x14, 0x32,
            // CRC-16
            0xb8, 0xba,
        ];

        let exp_response = ResponseStatus::Ok;
        let exp_num_channels = 4;
        let exp_channel_values = [
            ChannelValue::from(5),
            ChannelValue::from(10),
            ChannelValue::from(20),
            ChannelValue::from(50),
        ];

        let response = ChannelValueDataResponse::try_from(channel_value_data_response_bytes)?;

        assert_eq!(response.len(), channel_value_data_response_bytes.len());
        assert_eq!(response.data_len(), channel_value_data_response_bytes.len() - len::METADATA);

        assert_eq!(response.response_status(), exp_response);
        assert_eq!(response.num_channels(), exp_num_channels);
        assert_eq!(response.channel_values()?.as_ref(), exp_channel_values.as_ref());

        Ok(())
    }
}