aquarium_control/relays/
controllino_message.rs

1use crate::relays::actuate_controllino::controllino_constants;
2use std::fmt;
3
4/// Container for message content sent to Controllino
5pub struct ControllinoMessageContent {
6    /// Set by control application with command sent to Controllino
7    pub command: char,
8
9    /// Set by control application with id (e.g., for relay) of an element sent to Controllino
10    pub id: u8,
11
12    /// Unused byte
13    pub reserved1: u8,
14
15    /// Either used to communicate pulse duration in milliseconds to Controllino or
16    /// set by Controllino with data to be sent back to control application
17    pub payload: u16,
18
19    /// Unused byte
20    pub reserved2: char,
21}
22
23impl ControllinoMessageContent {
24    /// Provides a new `ControllinoMessageContent` struct.
25    ///
26    /// This struct serves as a container for the data that will eventually be
27    /// assembled into a full `ControllinoMessage` for serial transmission.
28    /// It initializes the message content with the specified command, ID, and
29    /// pulse duration, setting reserved bytes to zero.
30    ///
31    /// # Arguments
32    /// * `command` - The character representing the command to be sent to Controllino.
33    /// * `id` - The identifier for the relay or digital output relevant to the command.
34    /// * `duration_millis` - The pulse duration in milliseconds, or `0` if not applicable to the command.
35    pub fn new(command: char, id: u8, duration_millis: u16) -> ControllinoMessageContent {
36        ControllinoMessageContent {
37            command,
38            id,
39            reserved1: 0,
40            payload: duration_millis,
41            reserved2: '0',
42        }
43    }
44}
45
46/// Data structure for the message to be sent to Controllino
47#[derive(Debug, PartialEq)]
48pub struct ControllinoMessage {
49    /// represents the raw message transferred via serial port
50    pub data: [u8; controllino_constants::MESSAGE_SIZE],
51}
52
53impl ControllinoMessage {
54    /// Creates a new `ControllinoMessage` from `ControllinoMessageContent`.
55    ///
56    /// This crucial function takes the structured message content, converts its fields
57    /// into a raw 8-byte array (`[u8; 8]`) suitable for serial transmission, and
58    /// **calculates and embeds the necessary checksums** into the data array.
59    /// The resulting `ControllinoMessage` is ready to be sent directly to the Controllino hardware.
60    ///
61    /// # Arguments
62    /// * `content` - The `ControllinoMessageContent` struct containing the command, ID,
63    ///   and payload (e.g., pulse duration) to be packed into the message.
64    ///
65    /// # Returns
66    /// A new `ControllinoMessage` struct with its `data` field populated, including checksums.
67    pub fn new(content: ControllinoMessageContent) -> ControllinoMessage {
68        // transfer content into data structure and calculate checksum
69        let mut data: [u8; controllino_constants::MESSAGE_SIZE] =
70            [0; controllino_constants::MESSAGE_SIZE];
71        data[0] = content.command as u8;
72        data[1] = content.id;
73        data[2] = content.reserved1;
74        data[3] = data[0] ^ data[1] ^ data[2];
75        data[4] = ((content.payload & 0xFF00) >> 8) as u8;
76        data[5] = (content.payload & 0x00FF) as u8;
77        data[6] = content.reserved2 as u8;
78        data[7] = data[4] ^ data[5] ^ data[6];
79
80        ControllinoMessage { data }
81    }
82}
83
84impl fmt::Display for ControllinoMessage {
85    /// Provides output of the struct data for debugging purposes.
86    /// # Arguments
87    /// * `f` - configuration for formatting
88    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
89        write!(
90            f,
91            "ControllinoMessage: [0]={} [1]={} [2]={} [3]={} [4]={} [5]={} [6]={} [7]={}",
92            self.data[0],
93            self.data[1],
94            self.data[2],
95            self.data[3],
96            self.data[4],
97            self.data[5],
98            self.data[6],
99            self.data[7]
100        )
101    }
102}