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}